From 5a20dab343c9c43582f8a2ceeea18132d14674e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Wed, 26 Apr 2017 17:30:09 +0100 Subject: [PATCH 0001/1783] rename LocalNx etc --- bin/bout_4to5 | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100755 bin/bout_4to5 diff --git a/bin/bout_4to5 b/bin/bout_4to5 new file mode 100755 index 0000000000..a6f7156937 --- /dev/null +++ b/bin/bout_4to5 @@ -0,0 +1,17 @@ +#!/bin/bash + +if ! test -e $1 +then + echo "Error: folder or file as argument needed" + echo "usage:" + echo " $0 " + exit 1 +fi + +for d in x y z; do for f in ` find $1 -type f | grep x\$` ; do sed "s/LocalN$d/local_n$d/g" $f -i ; done;done +for d in x y z; do for f in ` find $1 -type f | grep x\$` ; do sed "s/GlobalN$d/global_n$d/g" $f -i ; done;done +for d in x y z; do for f in ` find $1 -type f | grep x\$` ; do sed "s/OffsetN$d/offset_n$d/g" $f -i ; done;done + +#Further changes: + +${d}end should be changed to ${d}end+1 From b2a5172380de0df5e99f9a4ea6a68adfb8d3f729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 22 Feb 2018 16:32:17 +0000 Subject: [PATCH 0002/1783] Work on BOUT++ 4to5 script * Add guard to not call on old version. * Make script more readabile --- bin/bout_4to5 | 53 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/bin/bout_4to5 b/bin/bout_4to5 index a6f7156937..314def92e4 100755 --- a/bin/bout_4to5 +++ b/bin/bout_4to5 @@ -1,17 +1,52 @@ #!/bin/bash +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +version=$($DIR/bout-config --version) +major=$(echo $version|cut -d. -f1) -if ! test -e $1 +if test $major -lt 5 then - echo "Error: folder or file as argument needed" - echo "usage:" - echo " $0 " - exit 1 + echo "The BOUT++ version appears to be $version." + echo "This script is intend to update to BOUT++ 5 - are you sure you want to continue? [y/N]" + read continue + continue=$(echo $continue |tr :lower: :upper:) + if test ".$continue" == .y || test ".$continue" == .yes + then + echo "Continuing at your risk ..." + else + echo "Maybe soon :)" + exit 0 + fi fi -for d in x y z; do for f in ` find $1 -type f | grep x\$` ; do sed "s/LocalN$d/local_n$d/g" $f -i ; done;done -for d in x y z; do for f in ` find $1 -type f | grep x\$` ; do sed "s/GlobalN$d/global_n$d/g" $f -i ; done;done -for d in x y z; do for f in ` find $1 -type f | grep x\$` ; do sed "s/OffsetN$d/offset_n$d/g" $f -i ; done;done +if test $# -eq 0 +then + for dir in src tools examples tests include + do + work="$work $DIR/../$dir" + done +else + echo x + work=$@ +fi + +# Set to true if you don't want to run the script: +false && + printordo=echo || printordo= + +for dir in $work +do + for d in x y z + do + for f in $(find $dir -type f | grep x\$) + do + $printordo sed "s/LocalN$d/local_n$d/g" $f -i + $printordo sed "s/GlobalN$d/global_n$d/g" $f -i + $printordo sed "s/OffsetN$d/offset_n$d/g" $f -i + done + done +done + #Further changes: -${d}end should be changed to ${d}end+1 +#${d}end should be changed to ${d}end+1 From 4f6a3b76917df10cf1805b7ca20649ce64c7957e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Wed, 21 Feb 2018 17:56:59 +0000 Subject: [PATCH 0003/1783] Scripts to update header location --- bin/bout_fix_headerlocation.sh | 30 ++++++++++++++++++++++++++++++ include/gen_compat_headerfiles.sh | 25 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100755 bin/bout_fix_headerlocation.sh create mode 100755 include/gen_compat_headerfiles.sh diff --git a/bin/bout_fix_headerlocation.sh b/bin/bout_fix_headerlocation.sh new file mode 100755 index 0000000000..044cff9ae2 --- /dev/null +++ b/bin/bout_fix_headerlocation.sh @@ -0,0 +1,30 @@ +for d in $@ +do + includes=$(grep "#include" $d -Hr --include=*xx --include=*pp) + for f in boundary_factory.hxx boundary_op.hxx boundary_region.hxx \ + boundary_standard.hxx boutcomm.hxx \ + boutexception.hxx boutmain.hxx bout_types.hxx \ + comm_group.hxx cyclic_reduction.hxx \ + datafile.hxx dataformat.hxx dcomplex.hxx \ + derivs.hxx difops.hxx fft.hxx field2d.hxx \ + field3d.hxx field_data.hxx field_factory.hxx \ + field.hxx fieldperp.hxx globals.hxx \ + gyro_average.hxx initialprofiles.hxx \ + interpolation_factory.hxx interpolation.hxx \ + invert_laplace.hxx invert_parderiv.hxx \ + lapack_routines.hxx mask.hxx msg_stack.hxx \ + multiostream.hxx options.hxx \ + optionsreader.hxx output.hxx \ + parallel_boundary_op.hxx \ + parallel_boundary_region.hxx smoothing.hxx \ + sourcex.hxx stencils.hxx unused.hxx utils.hxx \ + vecops.hxx vector2d.hxx vector3d.hxx where.hxx + do + matched=$(echo "$includes"|grep [^/]$f) + todo=$(echo "$matched"|cut -d: -f1) + for doit in $todo + do + sed -i "s/\([<\"]\)$f/\1bout\/$f/" $doit + done + done +done diff --git a/include/gen_compat_headerfiles.sh b/include/gen_compat_headerfiles.sh new file mode 100755 index 0000000000..6bdba4b5fd --- /dev/null +++ b/include/gen_compat_headerfiles.sh @@ -0,0 +1,25 @@ + +for f in boundary_factory.hxx boundary_op.hxx boundary_region.hxx \ + boundary_standard.hxx boutcomm.hxx \ + boutexception.hxx boutmain.hxx bout_types.hxx \ + comm_group.hxx cyclic_reduction.hxx \ + datafile.hxx dataformat.hxx dcomplex.hxx \ + derivs.hxx difops.hxx fft.hxx field2d.hxx \ + field3d.hxx field_data.hxx field_factory.hxx \ + field.hxx fieldperp.hxx globals.hxx \ + gyro_average.hxx initialprofiles.hxx \ + interpolation_factory.hxx interpolation.hxx \ + invert_laplace.hxx invert_parderiv.hxx \ + lapack_routines.hxx mask.hxx msg_stack.hxx \ + multiostream.hxx options.hxx \ + optionsreader.hxx output.hxx \ + parallel_boundary_op.hxx \ + parallel_boundary_region.hxx smoothing.hxx \ + sourcex.hxx stencils.hxx unused.hxx utils.hxx \ + vecops.hxx vector2d.hxx vector3d.hxx where.hxx +do + mv $f bout -i + echo "#pragma once +#warning <$f> has moved to - this can be fixed with bin/bout_fix_headerlocation.sh +#include \"bout/$f\"" > $f +done From 2992f63a5635282bfab380aa8771d891cce57d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 22 Feb 2018 18:19:55 +0000 Subject: [PATCH 0004/1783] Merge header file changes into 4to5 script * Merge bout_fix_headerlocation.sh * Merge gen_compat_headerfiles.sh * Add check for gen_compat_headerfiles * Add check for git status --- bin/bout_4to5 | 95 +++++++++++++++++++++++++++---- bin/bout_fix_headerlocation.sh | 30 ---------- include/gen_compat_headerfiles.sh | 25 -------- 3 files changed, 85 insertions(+), 65 deletions(-) delete mode 100755 bin/bout_fix_headerlocation.sh delete mode 100755 include/gen_compat_headerfiles.sh diff --git a/bin/bout_4to5 b/bin/bout_4to5 index 314def92e4..33dd7716c8 100755 --- a/bin/bout_4to5 +++ b/bin/bout_4to5 @@ -1,12 +1,10 @@ #!/bin/bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -version=$($DIR/bout-config --version) -major=$(echo $version|cut -d. -f1) -if test $major -lt 5 -then - echo "The BOUT++ version appears to be $version." - echo "This script is intend to update to BOUT++ 5 - are you sure you want to continue? [y/N]" +function maybe_proceed() { + echo $1 + echo "Are you sure you want to continue? [y/N]" + continue=y read continue continue=$(echo $continue |tr :lower: :upper:) if test ".$continue" == .y || test ".$continue" == .yes @@ -16,6 +14,21 @@ then echo "Maybe soon :)" exit 0 fi +} + +version=$($DIR/bout-config --version) +major=$(echo $version|cut -d. -f1) +if test $major -lt 5 +then + maybe_proceed "The BOUT++ version appears to be $version. +This script is intend to update to BOUT++ 5" +fi + +if ! git diff --exit-code &>/dev/null +then + maybe_proceed "Git shows that you have uncommited changes." +else + echo git is clean fi if test $# -eq 0 @@ -29,15 +42,24 @@ else work=$@ fi -# Set to true if you don't want to run the script: -false && - printordo=echo || printordo= +# Set to false if you don't want to run the script: +true && + printordo= || printordo=echo + +# Set to false to be quite +true && + verbose=echo || verbose=\# + +$verbose " Renaiming LocalNx -> local_nx" +$verbose " Renaiming GlobalNx -> global_nx" +$verbose " Renaiming OffsetNx -> offset_nx" for dir in $work do + allmatches=$(grep -EHr 'LocalN|GlobalN|OffsetN' $dir) for d in x y z do - for f in $(find $dir -type f | grep x\$) + for f in $(echo $allmatches|grep 'N$d'|cut -d: -f1|sort -u) do $printordo sed "s/LocalN$d/local_n$d/g" $f -i $printordo sed "s/GlobalN$d/global_n$d/g" $f -i @@ -46,6 +68,59 @@ do done done +headerfilelist="boundary_factory.hxx boundary_op.hxx boundary_region.hxx \ + boundary_standard.hxx boutcomm.hxx \ + boutexception.hxx boutmain.hxx bout_types.hxx \ + comm_group.hxx cyclic_reduction.hxx \ + datafile.hxx dataformat.hxx dcomplex.hxx \ + derivs.hxx difops.hxx fft.hxx field2d.hxx \ + field3d.hxx field_data.hxx field_factory.hxx \ + field.hxx fieldperp.hxx globals.hxx \ + gyro_average.hxx initialprofiles.hxx \ + interpolation_factory.hxx interpolation.hxx \ + invert_laplace.hxx invert_parderiv.hxx \ + lapack_routines.hxx mask.hxx msg_stack.hxx \ + multiostream.hxx options.hxx \ + optionsreader.hxx output.hxx \ + parallel_boundary_op.hxx \ + parallel_boundary_region.hxx smoothing.hxx \ + sourcex.hxx stencils.hxx unused.hxx utils.hxx \ + vecops.hxx vector2d.hxx vector3d.hxx where.hxx + " + +include=$DIR/../include/ +function gen_compat() { + for f in $headerfilelist + do + mv $f bout -i + echo "#pragma once +#warning <$f> has moved to - this can be fixed with bin/bout_fix_headerlocation.sh +#include \"bout/$f\"" > $f + done +} + +if test $(cat $include/boundary_factory.hxx|wc -l) -gt 20 +then + $verbose " Creating compat headerfiles" + (cd $include ; $printordo gen_compat) +else + $verbose " Compat headerfiles seem to be available" +fi + +$verbose " Update files to look for headers in bout/ subfolder" +for dir in $work +do + includes=$(grep "#include" $dir -Hr) + for f in $headerfilelist + do + matched=$(echo "$includes"|grep [^/]$f) + todo=$(echo "$matched"|cut -d: -f1) + for doit in $todo + do + $printordo sed -i "s/\([<\"]\)$f/\1bout\/$f/" $doit + done + done +done #Further changes: diff --git a/bin/bout_fix_headerlocation.sh b/bin/bout_fix_headerlocation.sh deleted file mode 100755 index 044cff9ae2..0000000000 --- a/bin/bout_fix_headerlocation.sh +++ /dev/null @@ -1,30 +0,0 @@ -for d in $@ -do - includes=$(grep "#include" $d -Hr --include=*xx --include=*pp) - for f in boundary_factory.hxx boundary_op.hxx boundary_region.hxx \ - boundary_standard.hxx boutcomm.hxx \ - boutexception.hxx boutmain.hxx bout_types.hxx \ - comm_group.hxx cyclic_reduction.hxx \ - datafile.hxx dataformat.hxx dcomplex.hxx \ - derivs.hxx difops.hxx fft.hxx field2d.hxx \ - field3d.hxx field_data.hxx field_factory.hxx \ - field.hxx fieldperp.hxx globals.hxx \ - gyro_average.hxx initialprofiles.hxx \ - interpolation_factory.hxx interpolation.hxx \ - invert_laplace.hxx invert_parderiv.hxx \ - lapack_routines.hxx mask.hxx msg_stack.hxx \ - multiostream.hxx options.hxx \ - optionsreader.hxx output.hxx \ - parallel_boundary_op.hxx \ - parallel_boundary_region.hxx smoothing.hxx \ - sourcex.hxx stencils.hxx unused.hxx utils.hxx \ - vecops.hxx vector2d.hxx vector3d.hxx where.hxx - do - matched=$(echo "$includes"|grep [^/]$f) - todo=$(echo "$matched"|cut -d: -f1) - for doit in $todo - do - sed -i "s/\([<\"]\)$f/\1bout\/$f/" $doit - done - done -done diff --git a/include/gen_compat_headerfiles.sh b/include/gen_compat_headerfiles.sh deleted file mode 100755 index 6bdba4b5fd..0000000000 --- a/include/gen_compat_headerfiles.sh +++ /dev/null @@ -1,25 +0,0 @@ - -for f in boundary_factory.hxx boundary_op.hxx boundary_region.hxx \ - boundary_standard.hxx boutcomm.hxx \ - boutexception.hxx boutmain.hxx bout_types.hxx \ - comm_group.hxx cyclic_reduction.hxx \ - datafile.hxx dataformat.hxx dcomplex.hxx \ - derivs.hxx difops.hxx fft.hxx field2d.hxx \ - field3d.hxx field_data.hxx field_factory.hxx \ - field.hxx fieldperp.hxx globals.hxx \ - gyro_average.hxx initialprofiles.hxx \ - interpolation_factory.hxx interpolation.hxx \ - invert_laplace.hxx invert_parderiv.hxx \ - lapack_routines.hxx mask.hxx msg_stack.hxx \ - multiostream.hxx options.hxx \ - optionsreader.hxx output.hxx \ - parallel_boundary_op.hxx \ - parallel_boundary_region.hxx smoothing.hxx \ - sourcex.hxx stencils.hxx unused.hxx utils.hxx \ - vecops.hxx vector2d.hxx vector3d.hxx where.hxx -do - mv $f bout -i - echo "#pragma once -#warning <$f> has moved to - this can be fixed with bin/bout_fix_headerlocation.sh -#include \"bout/$f\"" > $f -done From bda0e4c27b756cfa7cf96f74c541369248ebf42b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 6 Apr 2018 17:36:41 +0100 Subject: [PATCH 0005/1783] Enable travis test for 4to5 script New travis test: Run the script, and run the tests afterwards Further add options to the 4to5 script, to allow force-running the script, as needed for testing. Further exit on error (set -e) --- .travis.yml | 3 ++ .travis_script.sh | 13 ++++- bin/bout_4to5 | 120 +++++++++++++++++++++++++++++++++++----------- 3 files changed, 107 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4f9f718696..5f749bb303 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,6 +41,9 @@ matrix: - *default_env - CONFIGURE_OPTIONS='--enable-shared' - SCRIPT_FLAGS="-ut shared" + - env: + - *default_env + - SCRIPT_FLAGS='-uim5' - env: - *default_env - CONFIGURE_OPTIONS='--enable-checks=no --enable-optimize=3 --disable-signal --disable-track --disable-backtrace' diff --git a/.travis_script.sh b/.travis_script.sh index d39f0cf2cc..c88666bf73 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -7,6 +7,7 @@ INTEGRATED=0 MMS=0 TESTS=0 MAIN_TARGET= +UPDATE_SCRIPT=0 usage() { echo "$0 options are: " @@ -16,7 +17,7 @@ usage() { } #Handle input flags -while getopts "cuimt:" arg; +while getopts "cuimt:5" arg; do case $arg in c) ### Run the coverage-post job tasks @@ -37,12 +38,20 @@ do t) ### Set target to build MAIN_TARGET="$OPTARG" ;; - *) ### Show usage message + 5) ### Run the update to version 5 script + UPDATE_SCRIPT=1 + ;; + *) ### Show usage message usage ;; esac done +if test $UPDATE_SCRIPT -gt 0 +then + bin/bout_4to5 -f +fi + export MAKEFLAGS="-j 2 -k" echo "Configuring with $CONFIGURE_OPTIONS" time ./configure $CONFIGURE_OPTIONS MAKEFLAGS="$MAKEFLAGS" diff --git a/bin/bout_4to5 b/bin/bout_4to5 index 33dd7716c8..3573695c3a 100755 --- a/bin/bout_4to5 +++ b/bin/bout_4to5 @@ -1,27 +1,97 @@ #!/bin/bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +VERBOSE=1 +FORCE=0 + +usage() { + echo "$0 options are: " + #Just pull out special comments from this file + grep "\#\#\#" $0 + exit 1 +} + +while getopts "fvqd" arg; +do + case $arg in + f) ### Force mode - run without asking + FORCE=1 + ;; + v) ### Enable verbose mode + VERBOSE=1 + ;; + q) ### Enable quite mode + VERBOSE=0 + ;; + d) ### Debug mode - print everything before doing it + set -v + ;; + *) ### Show usage + usage + ;; + esac +done + +# remove the processed options from the input arguments +shift $((OPTIND-1)) + function maybe_proceed() { echo $1 - echo "Are you sure you want to continue? [y/N]" - continue=y - read continue - continue=$(echo $continue |tr :lower: :upper:) - if test ".$continue" == .y || test ".$continue" == .yes + if test $FORCE -gt 0 then - echo "Continuing at your risk ..." + verbose "Runing in force mode - continuing" else - echo "Maybe soon :)" - exit 0 + echo "Are you sure you want to continue? [y/N]" + continue=y + read continue + continue=$(echo $continue |tr :lower: :upper:) + if test ".$continue" == .y || test ".$continue" == .yes + then + echo "Continuing at your risk ..." + else + echo "Maybe soon :)" + exit 0 + fi + fi +} + +GREP=$(which grep) +# Wrapper for grep to detect errors +function grep () { + ex=0 + $GREP "$@" || ex=$? + if test $ex -eq 2 + then + echo "grep failed for $@" > /dev/stderr + exit 2 fi } -version=$($DIR/bout-config --version) -major=$(echo $version|cut -d. -f1) -if test $major -lt 5 +# Set to false to be quiet +function verbose() { + if test $VERBOSE -gt 0 + then + echo $@ + fi +} + +# If there is any error - we don't want to continue +set -e + +version= + +test -f $DIR/bout-config && version=$($DIR/bout-config --version ) +if test -z $version then - maybe_proceed "The BOUT++ version appears to be $version. + maybe_proceed "The BOUT++ version could not be detected. This script is intend to update to BOUT++ 5" +else + major=$(echo $version|cut -d. -f1) + if test $major -lt 5 + then + maybe_proceed "The BOUT++ version appears to be $version. +This script is intend to update to BOUT++ 5" + fi fi if ! git diff --exit-code &>/dev/null @@ -38,25 +108,21 @@ then work="$work $DIR/../$dir" done else - echo x work=$@ fi +echo $work # Set to false if you don't want to run the script: true && printordo= || printordo=echo -# Set to false to be quite -true && - verbose=echo || verbose=\# - -$verbose " Renaiming LocalNx -> local_nx" -$verbose " Renaiming GlobalNx -> global_nx" -$verbose " Renaiming OffsetNx -> offset_nx" +verbose " Renaming LocalNx -> local_nx" +verbose " Renaming GlobalNx -> global_nx" +verbose " Renaming OffsetNx -> offset_nx" for dir in $work do - allmatches=$(grep -EHr 'LocalN|GlobalN|OffsetN' $dir) + allmatches=$(grep -EHr 'LocalN|GlobalN|OffsetN' $dir ) for d in x y z do for f in $(echo $allmatches|grep 'N$d'|cut -d: -f1|sort -u) @@ -101,20 +167,20 @@ function gen_compat() { if test $(cat $include/boundary_factory.hxx|wc -l) -gt 20 then - $verbose " Creating compat headerfiles" + verbose " Creating compat headerfiles" (cd $include ; $printordo gen_compat) else - $verbose " Compat headerfiles seem to be available" + verbose " Compat headerfiles seem to be available" fi -$verbose " Update files to look for headers in bout/ subfolder" +verbose " Update files to look for headers in bout/ subfolder" for dir in $work do - includes=$(grep "#include" $dir -Hr) + includes=$(grep "#include" $dir -Hr ) for f in $headerfilelist do - matched=$(echo "$includes"|grep [^/]$f) - todo=$(echo "$matched"|cut -d: -f1) + matched=$(echo "$includes"|grep [^/]$f ) + todo=$(echo "$matched"|cut -d: -f1 ) for doit in $todo do $printordo sed -i "s/\([<\"]\)$f/\1bout\/$f/" $doit From 4f400308ff72f9e48d0962a175cb7008aeb72574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 6 Apr 2018 17:38:55 +0100 Subject: [PATCH 0006/1783] Add clang-format to 4to5 change In order to avoid merge conflicts in the future by white-space changes, make sure all code is properly-clang-formated. A test to make sure it stays that way is still required. --- bin/bout_4to5 | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/bin/bout_4to5 b/bin/bout_4to5 index 3573695c3a..ae561ac5ad 100755 --- a/bin/bout_4to5 +++ b/bin/bout_4to5 @@ -188,6 +188,22 @@ do done done + +# clang-format everything +if test $# -eq 0 +then + for dir in $work + do + files=$(find $dir|grep xx\$ ) + if test "$files" + then + verbose " Running clang-format on all files in $dir" + clang-format -i $files + fi + done +fi + + #Further changes: #${d}end should be changed to ${d}end+1 From 9b0f7fc07a64c8f28a0b3c7e63ab7cb750eb8013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 12 Apr 2018 14:49:15 +0100 Subject: [PATCH 0007/1783] Don't declare pass-by-value as const --- include/bout/rkscheme.hxx | 8 ++++---- include/parallel_boundary_region.hxx | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/bout/rkscheme.hxx b/include/bout/rkscheme.hxx index b5fdd51f22..2045b0fec5 100644 --- a/include/bout/rkscheme.hxx +++ b/include/bout/rkscheme.hxx @@ -58,14 +58,14 @@ class RKScheme { //Finish generic initialisation void init(int nlocalIn,int neqIn,bool adaptiveIn,BoutReal atolIn, - const BoutReal rtolIn, Options *options=NULL); + BoutReal rtolIn, Options *options=NULL); //Get the time at given stage BoutReal setCurTime(BoutReal timeIn,BoutReal dt,int curStage); //Get the state vector at given stage virtual void setCurState(const Array &start, Array &out,int curStage, - const BoutReal dt); + BoutReal dt); //Calculate the output state and return the error estimate (if adaptive) virtual BoutReal setOutputStates(const Array &start,BoutReal dt, Array &resultFollow); @@ -111,10 +111,10 @@ class RKScheme { virtual BoutReal getErr(Array &solA, Array &solB); virtual void constructOutput(const Array &start,BoutReal dt, - const int index, Array &sol); + int index, Array &sol); virtual void constructOutputs(const Array &start,BoutReal dt, - const int indexFollow,int indexAlt, + int indexFollow,int indexAlt, Array &solFollow, Array &solAlt); private: diff --git a/include/parallel_boundary_region.hxx b/include/parallel_boundary_region.hxx index b8c520ea6c..69475a0183 100644 --- a/include/parallel_boundary_region.hxx +++ b/include/parallel_boundary_region.hxx @@ -53,8 +53,8 @@ public: /// Add a point to the boundary void add_point(int jx,int jy,int jz, - const BoutReal x,BoutReal y,BoutReal z, - const BoutReal length,BoutReal angle); + BoutReal x,BoutReal y,BoutReal z, + BoutReal length,BoutReal angle); void first(); void next(); From a2793e22f739792d9c4070c6e1d09d7c65ada788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 12 Apr 2018 14:58:07 +0100 Subject: [PATCH 0008/1783] Update relative includes as well --- bin/bout_4to5 | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bin/bout_4to5 b/bin/bout_4to5 index ae561ac5ad..b6e8890a4a 100755 --- a/bin/bout_4to5 +++ b/bin/bout_4to5 @@ -107,8 +107,10 @@ then do work="$work $DIR/../$dir" done + WORK=default else work=$@ + WORK=other fi echo $work @@ -187,6 +189,16 @@ do done done done +if test $WORK == default +then + for f in $DIR/../include/bout/* + do + if test -f $f + then + $printordo sed -i "s|\.\./||" $f + fi + done +fi # clang-format everything From 7329d3cf5dd90e7588a772c2269889bf73a0a3c9 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 5 Sep 2018 15:58:34 +0100 Subject: [PATCH 0009/1783] Adding a class that can be used to invert a generic linear non-singular operator This is a work in progress and relies on PETSc. It has been written according to the PETSc 3.9 api and is unlikely to work with sufficiently old versions currently. Probably easy enough to fix. The class is templated on Field type to define the problem domain. --- include/bout/invert_operator.hxx | 275 +++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 include/bout/invert_operator.hxx diff --git a/include/bout/invert_operator.hxx b/include/bout/invert_operator.hxx new file mode 100644 index 0000000000..94e245f0b8 --- /dev/null +++ b/include/bout/invert_operator.hxx @@ -0,0 +1,275 @@ +/************************************************************************** + * Invert arbitrary global operatorn using PETSc. to invert + * + ************************************************************************** + * Copyright 2018 D. Dickinson + * + * Contact: Ben Dudson, bd512@york.ac.uk + * + * This file is part of BOUT++. + * + * BOUT++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BOUT++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with BOUT++. If not, see . + * + **************************************************************************/ + +template class InvertOperator; + +#ifndef __INVERT_OPERATOR_H__ +#define __INVERT_OPERATOR_H__ + +#ifdef BOUT_HAS_PETSC + +#include +#include +#include +#include + + +#include +#include +#include +#include + + +/// Non-member wrapper that gets a pointer to the parent InvertOperator instance +/// from the Matrix m and uses this to get the actual function to call. +/// Copies data from v1 into a field of type T, calls the function on this and then +/// copies the result into the v2 argument. +template +PetscErrorCode functionWrapper(Mat m, Vec v1, Vec v2){ + InvertOperator *ctx; + auto ierr = MatShellGetContext(m, &ctx); + T tmpField(ctx->localmesh); tmpField.allocate(); + petscVecToField(v1, tmpField); + T tmpField2 = ctx->func(tmpField); + fieldToPetscVec(tmpField2, v2); + return ierr; +} + +/// No-op function to use as a default -- may wish to remove once testing phase complete +template +T identity(const T& in){return in;}; + +template +class InvertOperator { + static_assert(std::is_base_of::value || std::is_base_of::value || std::is_base_of::value, + "InvertOperator must be templated with one of FieldPerp, Field2D or Field3D"); + + public: + + using data_type = T; // What type of field + using function_signature = std::function; // The required signature of the callback function representing the operator + using function_cast = void(*)(void); // Signature that we have to cast the function to for PETSc + + InvertOperator(Options *opt = nullptr, Mesh *localmesh = nullptr) : opt(opt ? opt : Options::getRoot()->getSection("invertOperator")), + localmesh(localmesh ? localmesh : mesh), doneSetup(false) {}; + + ~InvertOperator(){ + +#if CHECK > 1 + output_info<); + T invert(const T &rhs); + + /// With checks enabled provides a convience routine to check that + /// applying the registered function on the calculated inverse gives + /// back the initial values. + bool verify(const T &rhs, BoutReal tol = 1.0e-5){ + TRACE("InvertOperator::verify"); +#if CHECK > 1 + const T result = invert(rhs); + const T applied = func(result); + const BoutReal maxDiff = max(abs(applied-rhs),true); +#if CHECK > 2 + if (maxDiff >= tol) { + output_info << "Maximum difference in verify is "< +PetscErrorCode InvertOperator::setup(function_signature funcIn) { + TRACE("InvertOperator::setup"); + if (doneSetup) { + throw BoutException("Trying to call setup on an InvertOperator instance that has already been setup."); + } + + func = funcIn; + + PetscInt ierr; + + // Hacky way to determine the local size for now + PetscInt nlocal = 0; + { + T tmp(localmesh); + /// @TODO : Replace this with a BOUT_FOR type loop or alternative (T.size()?) + for(const auto &i: tmp){ nlocal++;} + } + + PetscInt nglobal = PETSC_DETERMINE; // Depends on type of T + + /// Create the shell matrix representing the operator to invert + /// Note we currently pass "this" as the Matrix context + ierr = MatCreateShell(BoutComm::get(), nlocal, nlocal, nglobal, nglobal, this, &matOperator); + CHKERRQ(ierr); // Can't call this in constructor as includes a return statement + + /// Create vectors compatible with matrix + ierr = MatCreateVecs(matOperator, &rhs, &lhs); // Older versions may need to use MatGetVecs + CHKERRQ(ierr); + + /// Now register Matrix_multiply operation + // ierr = MatShellSetOperation(matOperator, MATOP_MULT, (function_cast)(identityFunc)); + ierr = MatShellSetOperation(matOperator, MATOP_MULT, (function_cast)(functionWrapper)); + CHKERRQ(ierr); + + /// Now create and setup the linear solver with the matrix + ierr = KSPCreate(BoutComm::get(), &ksp); + CHKERRQ(ierr); + ierr = KSPSetOperators(ksp, matOperator, matOperator); + CHKERRQ(ierr); + + /// Allow options to be set on command line using a --invert_ksp_* prefix. + ierr = KSPSetOptionsPrefix(ksp,"invert_"); + CHKERRQ(ierr); + ierr = KSPSetFromOptions(ksp); + CHKERRQ(ierr); + + /// Do required setup so solve can proceed in invert + ierr = KSPSetUp(ksp); + CHKERRQ(ierr); + + doneSetup = true; +}; + +template +T InvertOperator::invert(const T& rhsField){ + TRACE("InvertOperator::invert"); + + if (!doneSetup) { + throw BoutException("Trying to call invert on an InvertOperator instance that has not been setup."); + } + + ASSERT2(localmesh == rhsField.getMesh()); + + // rhsField to rhs + fieldToPetscVec(rhsField, rhs); + + /// Do the solve with solution stored in lhs + auto ierr = KSPSolve(ksp, rhs, lhs); + CHKERRQ(ierr); + + KSPConvergedReason reason; + ierr = KSPGetConvergedReason( ksp, &reason ); + if(reason <=0 ){ + throw BoutException("KSPSolve failed with reason %d.",reason); + } + +#if CHECK > 3 + output_info << "KSPSolve finished with converged reason : "< +PetscErrorCode fieldToPetscVec(const T& in, Vec out){ + TRACE("fieldToPetscVec"); + + PetscScalar *vecData; + + auto ierr = VecGetArray(out, &vecData); + CHKERRQ(ierr); + + int counter = 0; + + /// @TODO : Replace this with a BOUT_FOR type loop + for(const auto &i: in){ + vecData[counter] = in[i]; + counter++; + } + + ierr = VecRestoreArray(out, &vecData); + CHKERRQ(ierr); +} + +template +PetscErrorCode petscVecToField(const Vec in, T& out){ + TRACE("petscVecToField"); + + const PetscScalar *vecData; + + auto ierr = VecGetArrayRead(in, &vecData); + CHKERRQ(ierr); + + int counter = 0; + + /// @TODO : Replace this with a BOUT_FOR type loop + for(const auto &i: out){ + out[i] = vecData[counter]; + counter++; + } + + ierr = VecRestoreArrayRead(in, &vecData); + CHKERRQ(ierr); +} + +#endif // PETSC +#endif // HEADER GUARD From 6209443634466c8cd286e86608976ab0e5046d88 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 5 Sep 2018 16:01:41 +0100 Subject: [PATCH 0010/1783] Adding a brief example to demonstrate invert_operator usage --- examples/invert_operator/data/BOUT.inp | 4 ++ examples/invert_operator/invert_operator.cxx | 47 ++++++++++++++++++++ examples/invert_operator/makefile | 6 +++ 3 files changed, 57 insertions(+) create mode 100644 examples/invert_operator/data/BOUT.inp create mode 100644 examples/invert_operator/invert_operator.cxx create mode 100644 examples/invert_operator/makefile diff --git a/examples/invert_operator/data/BOUT.inp b/examples/invert_operator/data/BOUT.inp new file mode 100644 index 0000000000..045ed5dd67 --- /dev/null +++ b/examples/invert_operator/data/BOUT.inp @@ -0,0 +1,4 @@ +[mesh] +nx = 20 +ny = 16 +nz = 32 \ No newline at end of file diff --git a/examples/invert_operator/invert_operator.cxx b/examples/invert_operator/invert_operator.cxx new file mode 100644 index 0000000000..9e66b3e3c8 --- /dev/null +++ b/examples/invert_operator/invert_operator.cxx @@ -0,0 +1,47 @@ + +#include +#include +#include + +Field3D minus(const Field3D &input) { return -1.0 * input; }; +Field3D delp(const Field3D &input) { return input + Delp2(input); }; + +class HW : public PhysicsModel { +private: + Field3D n; + class InvertOperator *mySolver; + +protected: + int init(bool restart) { + + SOLVE_FOR(n); + + mySolver = new InvertOperator(); + + mySolver->setup(delp); + + Field3D output = 3.0; + n = -2.0; + output = mySolver->invert(n); + + output_warn << endl; + output_warn << "Max difference is " << max(abs(output - n), true) << endl; + output_warn << endl; + auto pass = mySolver->verify(n) == 0 ? "False" : "True"; + output_warn << "Has test passed ? " << pass << endl; + output_warn << endl; + + return 0; + } + + int rhs(BoutReal time) { + ddt(n) = 0.; + return 0; + } + +public: + ~HW() { delete mySolver; }; +}; + +// Define a main() function +BOUTMAIN(HW); diff --git a/examples/invert_operator/makefile b/examples/invert_operator/makefile new file mode 100644 index 0000000000..80a8da2bbf --- /dev/null +++ b/examples/invert_operator/makefile @@ -0,0 +1,6 @@ + +BOUT_TOP = ../.. + +SOURCEC = invert_operator.cxx + +include $(BOUT_TOP)/make.config From ab456dc5f3d1958e2107c48de848e7accfdb7bdd Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 6 Sep 2018 08:48:53 +0100 Subject: [PATCH 0011/1783] Bug fix to pass test-code-style --- examples/invert_operator/invert_operator.cxx | 8 ++++---- include/bout/invert_operator.hxx | 8 +++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/examples/invert_operator/invert_operator.cxx b/examples/invert_operator/invert_operator.cxx index 9e66b3e3c8..2db032f749 100644 --- a/examples/invert_operator/invert_operator.cxx +++ b/examples/invert_operator/invert_operator.cxx @@ -25,11 +25,11 @@ class HW : public PhysicsModel { output = mySolver->invert(n); output_warn << endl; - output_warn << "Max difference is " << max(abs(output - n), true) << endl; - output_warn << endl; + output_warn << "Max difference is " << max(abs(output - n), true) << std::endl; + output_warn << std::endl; auto pass = mySolver->verify(n) == 0 ? "False" : "True"; - output_warn << "Has test passed ? " << pass << endl; - output_warn << endl; + output_warn << "Has test passed ? " << pass << std::endl; + output_warn << std::endl; return 0; } diff --git a/include/bout/invert_operator.hxx b/include/bout/invert_operator.hxx index 94e245f0b8..52373f022a 100644 --- a/include/bout/invert_operator.hxx +++ b/include/bout/invert_operator.hxx @@ -31,16 +31,14 @@ template class InvertOperator; #ifdef BOUT_HAS_PETSC #include -#include -#include -#include +#include #include #include #include #include - +#include /// Non-member wrapper that gets a pointer to the parent InvertOperator instance /// from the Matrix m and uses this to get the actual function to call. @@ -251,7 +249,7 @@ PetscErrorCode fieldToPetscVec(const T& in, Vec out){ } template -PetscErrorCode petscVecToField(const Vec in, T& out){ +PetscErrorCode petscVecToField(Vec in, T& out){ TRACE("petscVecToField"); const PetscScalar *vecData; From 9c7b82ff78c03d19fc4934a28fa9445aabac93a5 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 6 Sep 2018 23:45:54 +0100 Subject: [PATCH 0012/1783] Making functionWrapper be a static member. Seems to allow localmesh to be made private --- include/bout/invert_operator.hxx | 37 ++++++++++++++------------------ 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/include/bout/invert_operator.hxx b/include/bout/invert_operator.hxx index 52373f022a..7e73696533 100644 --- a/include/bout/invert_operator.hxx +++ b/include/bout/invert_operator.hxx @@ -40,21 +40,6 @@ template class InvertOperator; #include #include -/// Non-member wrapper that gets a pointer to the parent InvertOperator instance -/// from the Matrix m and uses this to get the actual function to call. -/// Copies data from v1 into a field of type T, calls the function on this and then -/// copies the result into the v2 argument. -template -PetscErrorCode functionWrapper(Mat m, Vec v1, Vec v2){ - InvertOperator *ctx; - auto ierr = MatShellGetContext(m, &ctx); - T tmpField(ctx->localmesh); tmpField.allocate(); - petscVecToField(v1, tmpField); - T tmpField2 = ctx->func(tmpField); - fieldToPetscVec(tmpField2, v2); - return ierr; -} - /// No-op function to use as a default -- may wish to remove once testing phase complete template T identity(const T& in){return in;}; @@ -113,11 +98,21 @@ class InvertOperator { return true; #endif }; - - /// Currently has to be public to allow the non-member functionWrapper to - /// create fields on the correct mesh. - Mesh *localmesh; + /// Wrapper that gets a pointer to the parent InvertOperator instance + /// from the Matrix m and uses this to get the actual function to call. + /// Copies data from v1 into a field of type T, calls the function on this and then + /// copies the result into the v2 argument. + static PetscErrorCode functionWrapper(Mat m, Vec v1, Vec v2){ + InvertOperator *ctx; + auto ierr = MatShellGetContext(m, &ctx); + T tmpField(ctx->localmesh); tmpField.allocate(); + petscVecToField(v1, tmpField); + T tmpField2 = ctx->func(tmpField); + fieldToPetscVec(tmpField2, v2); + return ierr; + } + /// The function that represents the operator that we wish to invert function_signature func; @@ -130,7 +125,7 @@ class InvertOperator { // Internal types Options *opt; //Do we need this? - + Mesh *localmesh; //< To ensure we can create T on the right mesh bool doneSetup = false; // To ensure PETSc has been setup @@ -169,7 +164,7 @@ PetscErrorCode InvertOperator::setup(function_signature funcIn) { /// Now register Matrix_multiply operation // ierr = MatShellSetOperation(matOperator, MATOP_MULT, (function_cast)(identityFunc)); - ierr = MatShellSetOperation(matOperator, MATOP_MULT, (function_cast)(functionWrapper)); + ierr = MatShellSetOperation(matOperator, MATOP_MULT, (function_cast)(functionWrapper)); CHKERRQ(ierr); /// Now create and setup the linear solver with the matrix From 0bb35840ae16c298e13d959997142eca4a134047 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 6 Sep 2018 23:47:59 +0100 Subject: [PATCH 0013/1783] Add timing capture/reporting --- examples/invert_operator/invert_operator.cxx | 3 ++- include/bout/invert_operator.hxx | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/examples/invert_operator/invert_operator.cxx b/examples/invert_operator/invert_operator.cxx index 2db032f749..8cd082da27 100644 --- a/examples/invert_operator/invert_operator.cxx +++ b/examples/invert_operator/invert_operator.cxx @@ -9,7 +9,7 @@ Field3D delp(const Field3D &input) { return input + Delp2(input); }; class HW : public PhysicsModel { private: Field3D n; - class InvertOperator *mySolver; + InvertOperator *mySolver; protected: int init(bool restart) { @@ -31,6 +31,7 @@ class HW : public PhysicsModel { output_warn << "Has test passed ? " << pass << std::endl; output_warn << std::endl; + mySolver->reportTime(); return 0; } diff --git a/include/bout/invert_operator.hxx b/include/bout/invert_operator.hxx index 7e73696533..fa7a6af0ff 100644 --- a/include/bout/invert_operator.hxx +++ b/include/bout/invert_operator.hxx @@ -34,6 +34,7 @@ template class InvertOperator; #include +#include #include #include #include @@ -116,6 +117,14 @@ class InvertOperator { /// The function that represents the operator that we wish to invert function_signature func; + static void reportTime(){ + BoutReal time_setup = Timer::resetTime("invert_operator_setup"); + BoutReal time_invert = Timer::resetTime("invert_operator_invert"); + BoutReal time_packing = Timer::resetTime("invert_operator_packing"); + output_info << "InvertOperator timing :: Setup "<< time_setup; + output_info << " , Invert(packing) "<< time_invert << "("; + output_info << time_packing << ")" << endl; + }; private: // PETSc types @@ -134,7 +143,8 @@ class InvertOperator { template PetscErrorCode InvertOperator::setup(function_signature funcIn) { - TRACE("InvertOperator::setup"); + TRACE("InvertOperator::setup"); + Timer timer("invert_operator_setup"); if (doneSetup) { throw BoutException("Trying to call setup on an InvertOperator instance that has already been setup."); } @@ -189,6 +199,7 @@ PetscErrorCode InvertOperator::setup(function_signature funcIn) { template T InvertOperator::invert(const T& rhsField){ TRACE("InvertOperator::invert"); + Timer timer("invert_operator_invert"); if (!doneSetup) { throw BoutException("Trying to call invert on an InvertOperator instance that has not been setup."); @@ -225,6 +236,7 @@ T InvertOperator::invert(const T& rhsField){ template PetscErrorCode fieldToPetscVec(const T& in, Vec out){ TRACE("fieldToPetscVec"); + Timer timer("invert_operator_packing"); PetscScalar *vecData; @@ -246,6 +258,7 @@ PetscErrorCode fieldToPetscVec(const T& in, Vec out){ template PetscErrorCode petscVecToField(Vec in, T& out){ TRACE("petscVecToField"); + Timer timer("invert_operator_packing"); const PetscScalar *vecData; From 24cfa61e107cd0fd4afd0fe5d0aa54b1da021b74 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 09:46:21 +0100 Subject: [PATCH 0014/1783] Provide a simple struct wrapper to represent an operator --- include/bout/invert_operator.hxx | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/include/bout/invert_operator.hxx b/include/bout/invert_operator.hxx index fa7a6af0ff..87e55fd1f8 100644 --- a/include/bout/invert_operator.hxx +++ b/include/bout/invert_operator.hxx @@ -23,24 +23,41 @@ * **************************************************************************/ +#include +#include +#include +#include +#include +#include + template class InvertOperator; #ifndef __INVERT_OPERATOR_H__ #define __INVERT_OPERATOR_H__ +/// Provides a base struct representing a light wrapper +/// around the operator function call `apply`. This is +/// used so that users can derive from this struct to +/// provide member data that can be used in the apply +/// function call. +struct OperatorWrapper { + virtual Field3D apply(const Field3D& input){ + throw BoutException("Invalid Field type 'Field3D' in OperatorWrapper."); + }; + virtual Field2D apply(const Field2D& input){ + throw BoutException("Invalid Field type 'Field2D' in OperatorWrapper."); + }; + virtual FieldPerp apply(const FieldPerp& input){ + throw BoutException("Invalid Field type 'FieldPerp' in OperatorWrapper."); + }; +}; + #ifdef BOUT_HAS_PETSC #include #include -#include -#include -#include -#include -#include -#include - /// No-op function to use as a default -- may wish to remove once testing phase complete template T identity(const T& in){return in;}; From 3e2830e5512f40ce890904588137bcaf6a4cc9ba Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 12:01:55 +0100 Subject: [PATCH 0015/1783] Take advantage of the fact that std::function can take a functor This allows setup to take any one of: * A function with signature `InvertOperator::function_signature` * A struct derived from `OperatorWrapper` * A lambda matching `InvertOperator::function_signature` This provides flexibility to the user -- they can pass a function if no extra data is required or a struct if further information/state is needed etc. --- examples/invert_operator/invert_operator.cxx | 18 +++++++++++++++--- include/bout/invert_operator.hxx | 6 +++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/examples/invert_operator/invert_operator.cxx b/examples/invert_operator/invert_operator.cxx index 8cd082da27..cecc9ecb5b 100644 --- a/examples/invert_operator/invert_operator.cxx +++ b/examples/invert_operator/invert_operator.cxx @@ -10,6 +10,12 @@ class HW : public PhysicsModel { private: Field3D n; InvertOperator *mySolver; + + struct myOp : public OperatorWrapper { + BoutReal factor + Field3D operator()(const Field3D &input) override {return factor*input + Delp2(input); } ; + }; + myOp myDelp; protected: int init(bool restart) { @@ -18,12 +24,18 @@ class HW : public PhysicsModel { mySolver = new InvertOperator(); - mySolver->setup(delp); + // mySolver->setup(delp); + mySolver->setup(myDelp); + // Above could also be: + // mySolver->setup(delp); + // or even a Lambda + // mySolver->setup([](const Field3D &input) { return input + Delp2(input); }); Field3D output = 3.0; n = -2.0; - output = mySolver->invert(n); - + for(int i=0; i<10000; i++){ + output = mySolver->invert(n); + } output_warn << endl; output_warn << "Max difference is " << max(abs(output - n), true) << std::endl; output_warn << std::endl; diff --git a/include/bout/invert_operator.hxx b/include/bout/invert_operator.hxx index 87e55fd1f8..69a4942c1d 100644 --- a/include/bout/invert_operator.hxx +++ b/include/bout/invert_operator.hxx @@ -41,13 +41,13 @@ template class InvertOperator; /// provide member data that can be used in the apply /// function call. struct OperatorWrapper { - virtual Field3D apply(const Field3D& input){ + virtual Field3D operator()(const Field3D& input){ throw BoutException("Invalid Field type 'Field3D' in OperatorWrapper."); }; - virtual Field2D apply(const Field2D& input){ + virtual Field2D operator()(const Field2D& input){ throw BoutException("Invalid Field type 'Field2D' in OperatorWrapper."); }; - virtual FieldPerp apply(const FieldPerp& input){ + virtual FieldPerp operator()(const FieldPerp& input){ throw BoutException("Invalid Field type 'FieldPerp' in OperatorWrapper."); }; }; From 68b69d59a369b07783eeaba94639fe9f2a6f4459 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 16:36:42 +0100 Subject: [PATCH 0016/1783] Adding some comments demonstrating possible behaviour --- examples/invert_operator/invert_operator.cxx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/invert_operator/invert_operator.cxx b/examples/invert_operator/invert_operator.cxx index cecc9ecb5b..adf9d1f40c 100644 --- a/examples/invert_operator/invert_operator.cxx +++ b/examples/invert_operator/invert_operator.cxx @@ -12,8 +12,8 @@ class HW : public PhysicsModel { InvertOperator *mySolver; struct myOp : public OperatorWrapper { - BoutReal factor - Field3D operator()(const Field3D &input) override {return factor*input + Delp2(input); } ; + BoutReal factor=1.; + Field3D operator()(const Field3D &input) override {output<<"Factor is "<setup([](const Field3D &input) { return input + Delp2(input); }); + // Note mySolve takes a copy of the passed functor so updates to the local + // instance won't have any effect, but the function _can_ be changed (currently) + // as it is a public member, so the following should work. + myDelp.factor = 3.0; + mySolver->func = myDelp; Field3D output = 3.0; n = -2.0; for(int i=0; i<10000; i++){ From 1168159ca4b379740d96aaaf98ff195e70b14397 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 16:46:29 +0100 Subject: [PATCH 0017/1783] Add comments and rearrange code --- include/bout/invert_operator.hxx | 220 ++++++++++++++++--------------- 1 file changed, 116 insertions(+), 104 deletions(-) diff --git a/include/bout/invert_operator.hxx b/include/bout/invert_operator.hxx index 69a4942c1d..7d5d64700c 100644 --- a/include/bout/invert_operator.hxx +++ b/include/bout/invert_operator.hxx @@ -68,17 +68,22 @@ class InvertOperator { "InvertOperator must be templated with one of FieldPerp, Field2D or Field3D"); public: + + /// What type of field does the operator take? + using data_type = T; - using data_type = T; // What type of field - using function_signature = std::function; // The required signature of the callback function representing the operator - using function_cast = void(*)(void); // Signature that we have to cast the function to for PETSc - - InvertOperator(Options *opt = nullptr, Mesh *localmesh = nullptr) : opt(opt ? opt : Options::getRoot()->getSection("invertOperator")), - localmesh(localmesh ? localmesh : mesh), doneSetup(false) {}; + /// The signature of the functor that applies the operator. + using function_signature = std::function; + + /// Almost empty constructor -- currently don't actually use Options for anything + InvertOperator(Options *opt = nullptr, Mesh *localmesh = nullptr) : + opt(opt ? opt : Options::getRoot()->getSection("invertOperator")), + localmesh(localmesh ? localmesh : mesh), doneSetup(false) {}; + /// Destructor just has to cleanup the PETSc owned objects. ~InvertOperator(){ -#if CHECK > 1 +#if CHECK > 3 output_info<) { + TRACE("InvertOperator::setup"); + Timer timer("invert_operator_setup"); + if (doneSetup) { + throw BoutException("Trying to call setup on an InvertOperator instance that has already been setup."); + } + + // Take a copy of the functor + func = funcIn; + + PetscInt ierr; - PetscErrorCode setup(function_signature funcIn = identity); - T invert(const T &rhs); + // Hacky way to determine the local size for now + PetscInt nlocal = 0; + { + T tmp(localmesh); + /// @TODO : Replace this with a BOUT_FOR type loop or alternative (T.size()?) + for(const auto &i: tmp){ nlocal++;} + } + + PetscInt nglobal = PETSC_DETERMINE; // Depends on type of T + + /// Create the shell matrix representing the operator to invert + /// Note we currently pass "this" as the Matrix context + ierr = MatCreateShell(BoutComm::get(), nlocal, nlocal, nglobal, nglobal, this, &matOperator); + CHKERRQ(ierr); // Can't call this in constructor as includes a return statement + + /// Create vectors compatible with matrix + ierr = MatCreateVecs(matOperator, &rhs, &lhs); // Older versions may need to use MatGetVecs + CHKERRQ(ierr); + + /// Now register Matrix_multiply operation + ierr = MatShellSetOperation(matOperator, MATOP_MULT, (void(*)(void))(functionWrapper)); + CHKERRQ(ierr); + + /// Now create and setup the linear solver with the matrix + ierr = KSPCreate(BoutComm::get(), &ksp); + CHKERRQ(ierr); + ierr = KSPSetOperators(ksp, matOperator, matOperator); + CHKERRQ(ierr); + + /// Allow options to be set on command line using a --invert_ksp_* prefix. + ierr = KSPSetOptionsPrefix(ksp,"invert_"); + CHKERRQ(ierr); + ierr = KSPSetFromOptions(ksp); + CHKERRQ(ierr); + + /// Do required setup so solve can proceed in invert + ierr = KSPSetUp(ksp); + CHKERRQ(ierr); + + doneSetup = true; + }; + + /// Triggers the solve of A.x = b for x, where b = rhs and A is the matrix representation + /// of the operator we represent. Should probably provide an overload or similar as a + /// way of setting the initial guess. + T invert(const T &rhs) { + TRACE("InvertOperator::invert"); + Timer timer("invert_operator_invert"); + + if (!doneSetup) { + throw BoutException("Trying to call invert on an InvertOperator instance that has not been setup."); + } + + ASSERT2(localmesh == rhsField.getMesh()); + + // rhsField to rhs + fieldToPetscVec(rhsField, rhs); + + /// Do the solve with solution stored in lhs + auto ierr = KSPSolve(ksp, rhs, lhs); + CHKERRQ(ierr); + + KSPConvergedReason reason; + ierr = KSPGetConvergedReason( ksp, &reason ); + if(reason <=0 ){ + throw BoutException("KSPSolve failed with reason %d.",reason); + } + +#if CHECK > 3 + output_info << "KSPSolve finished with converged reason : "< 2 +#if CHECK > 3 if (maxDiff >= tol) { output_info << "Maximum difference in verify is "< -PetscErrorCode InvertOperator::setup(function_signature funcIn) { - TRACE("InvertOperator::setup"); - Timer timer("invert_operator_setup"); - if (doneSetup) { - throw BoutException("Trying to call setup on an InvertOperator instance that has already been setup."); - } - - func = funcIn; - - PetscInt ierr; - - // Hacky way to determine the local size for now - PetscInt nlocal = 0; - { - T tmp(localmesh); - /// @TODO : Replace this with a BOUT_FOR type loop or alternative (T.size()?) - for(const auto &i: tmp){ nlocal++;} - } - - PetscInt nglobal = PETSC_DETERMINE; // Depends on type of T - - /// Create the shell matrix representing the operator to invert - /// Note we currently pass "this" as the Matrix context - ierr = MatCreateShell(BoutComm::get(), nlocal, nlocal, nglobal, nglobal, this, &matOperator); - CHKERRQ(ierr); // Can't call this in constructor as includes a return statement - - /// Create vectors compatible with matrix - ierr = MatCreateVecs(matOperator, &rhs, &lhs); // Older versions may need to use MatGetVecs - CHKERRQ(ierr); - - /// Now register Matrix_multiply operation - // ierr = MatShellSetOperation(matOperator, MATOP_MULT, (function_cast)(identityFunc)); - ierr = MatShellSetOperation(matOperator, MATOP_MULT, (function_cast)(functionWrapper)); - CHKERRQ(ierr); - - /// Now create and setup the linear solver with the matrix - ierr = KSPCreate(BoutComm::get(), &ksp); - CHKERRQ(ierr); - ierr = KSPSetOperators(ksp, matOperator, matOperator); - CHKERRQ(ierr); - - /// Allow options to be set on command line using a --invert_ksp_* prefix. - ierr = KSPSetOptionsPrefix(ksp,"invert_"); - CHKERRQ(ierr); - ierr = KSPSetFromOptions(ksp); - CHKERRQ(ierr); - - /// Do required setup so solve can proceed in invert - ierr = KSPSetUp(ksp); - CHKERRQ(ierr); - - doneSetup = true; -}; - -template -T InvertOperator::invert(const T& rhsField){ - TRACE("InvertOperator::invert"); - Timer timer("invert_operator_invert"); - - if (!doneSetup) { - throw BoutException("Trying to call invert on an InvertOperator instance that has not been setup."); - } - - ASSERT2(localmesh == rhsField.getMesh()); - - // rhsField to rhs - fieldToPetscVec(rhsField, rhs); - - /// Do the solve with solution stored in lhs - auto ierr = KSPSolve(ksp, rhs, lhs); - CHKERRQ(ierr); - - KSPConvergedReason reason; - ierr = KSPGetConvergedReason( ksp, &reason ); - if(reason <=0 ){ - throw BoutException("KSPSolve failed with reason %d.",reason); - } - -#if CHECK > 3 - output_info << "KSPSolve finished with converged reason : "< template PetscErrorCode fieldToPetscVec(const T& in, Vec out){ TRACE("fieldToPetscVec"); @@ -272,6 +283,7 @@ PetscErrorCode fieldToPetscVec(const T& in, Vec out){ CHKERRQ(ierr); } +/// Pack a Field from a PetscVec template PetscErrorCode petscVecToField(Vec in, T& out){ TRACE("petscVecToField"); From 91461d2cfa0955a261b736373be0dfe29472ac0c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 16:47:48 +0100 Subject: [PATCH 0018/1783] Clang-format the invert_operator header --- include/bout/invert_operator.hxx | 174 +++++++++++++++++-------------- 1 file changed, 95 insertions(+), 79 deletions(-) diff --git a/include/bout/invert_operator.hxx b/include/bout/invert_operator.hxx index 7d5d64700c..4532ce9a51 100644 --- a/include/bout/invert_operator.hxx +++ b/include/bout/invert_operator.hxx @@ -30,7 +30,7 @@ #include #include -template class InvertOperator; +template class InvertOperator; #ifndef __INVERT_OPERATOR_H__ #define __INVERT_OPERATOR_H__ @@ -41,13 +41,13 @@ template class InvertOperator; /// provide member data that can be used in the apply /// function call. struct OperatorWrapper { - virtual Field3D operator()(const Field3D& input){ + virtual Field3D operator()(const Field3D &input) { throw BoutException("Invalid Field type 'Field3D' in OperatorWrapper."); }; - virtual Field2D operator()(const Field2D& input){ + virtual Field2D operator()(const Field2D &input) { throw BoutException("Invalid Field type 'Field2D' in OperatorWrapper."); }; - virtual FieldPerp operator()(const FieldPerp& input){ + virtual FieldPerp operator()(const FieldPerp &input) { throw BoutException("Invalid Field type 'FieldPerp' in OperatorWrapper."); }; }; @@ -59,37 +59,36 @@ struct OperatorWrapper { #include /// No-op function to use as a default -- may wish to remove once testing phase complete -template -T identity(const T& in){return in;}; - -template -class InvertOperator { - static_assert(std::is_base_of::value || std::is_base_of::value || std::is_base_of::value, - "InvertOperator must be templated with one of FieldPerp, Field2D or Field3D"); - - public: - +template T identity(const T &in) { return in; }; + +template class InvertOperator { + static_assert( + std::is_base_of::value || std::is_base_of::value || + std::is_base_of::value, + "InvertOperator must be templated with one of FieldPerp, Field2D or Field3D"); + +public: /// What type of field does the operator take? using data_type = T; /// The signature of the functor that applies the operator. - using function_signature = std::function; + using function_signature = std::function; /// Almost empty constructor -- currently don't actually use Options for anything - InvertOperator(Options *opt = nullptr, Mesh *localmesh = nullptr) : - opt(opt ? opt : Options::getRoot()->getSection("invertOperator")), - localmesh(localmesh ? localmesh : mesh), doneSetup(false) {}; + InvertOperator(Options *opt = nullptr, Mesh *localmesh = nullptr) + : opt(opt ? opt : Options::getRoot()->getSection("invertOperator")), + localmesh(localmesh ? localmesh : mesh), doneSetup(false){}; /// Destructor just has to cleanup the PETSc owned objects. - ~InvertOperator(){ - + ~InvertOperator() { + #if CHECK > 3 - output_info<::setup"); Timer timer("invert_operator_setup"); if (doneSetup) { - throw BoutException("Trying to call setup on an InvertOperator instance that has already been setup."); + throw BoutException("Trying to call setup on an InvertOperator instance that has " + "already been setup."); } // Take a copy of the functor func = funcIn; - + PetscInt ierr; - + // Hacky way to determine the local size for now PetscInt nlocal = 0; { T tmp(localmesh); /// @TODO : Replace this with a BOUT_FOR type loop or alternative (T.size()?) - for(const auto &i: tmp){ nlocal++;} + for (const auto &i : tmp) { + nlocal++; + } } - + PetscInt nglobal = PETSC_DETERMINE; // Depends on type of T /// Create the shell matrix representing the operator to invert /// Note we currently pass "this" as the Matrix context - ierr = MatCreateShell(BoutComm::get(), nlocal, nlocal, nglobal, nglobal, this, &matOperator); + ierr = MatCreateShell(BoutComm::get(), nlocal, nlocal, nglobal, nglobal, this, + &matOperator); CHKERRQ(ierr); // Can't call this in constructor as includes a return statement /// Create vectors compatible with matrix - ierr = MatCreateVecs(matOperator, &rhs, &lhs); // Older versions may need to use MatGetVecs + ierr = MatCreateVecs(matOperator, &rhs, + &lhs); // Older versions may need to use MatGetVecs CHKERRQ(ierr); - + /// Now register Matrix_multiply operation - ierr = MatShellSetOperation(matOperator, MATOP_MULT, (void(*)(void))(functionWrapper)); + ierr = + MatShellSetOperation(matOperator, MATOP_MULT, (void (*)(void))(functionWrapper)); CHKERRQ(ierr); /// Now create and setup the linear solver with the matrix ierr = KSPCreate(BoutComm::get(), &ksp); - CHKERRQ(ierr); + CHKERRQ(ierr); ierr = KSPSetOperators(ksp, matOperator, matOperator); CHKERRQ(ierr); /// Allow options to be set on command line using a --invert_ksp_* prefix. - ierr = KSPSetOptionsPrefix(ksp,"invert_"); + ierr = KSPSetOptionsPrefix(ksp, "invert_"); CHKERRQ(ierr); ierr = KSPSetFromOptions(ksp); CHKERRQ(ierr); @@ -153,37 +158,39 @@ class InvertOperator { doneSetup = true; }; - - /// Triggers the solve of A.x = b for x, where b = rhs and A is the matrix representation + + /// Triggers the solve of A.x = b for x, where b = rhs and A is the matrix + /// representation /// of the operator we represent. Should probably provide an overload or similar as a /// way of setting the initial guess. T invert(const T &rhs) { TRACE("InvertOperator::invert"); - Timer timer("invert_operator_invert"); - + Timer timer("invert_operator_invert"); + if (!doneSetup) { - throw BoutException("Trying to call invert on an InvertOperator instance that has not been setup."); + throw BoutException( + "Trying to call invert on an InvertOperator instance that has not been setup."); } ASSERT2(localmesh == rhsField.getMesh()); // rhsField to rhs fieldToPetscVec(rhsField, rhs); - - /// Do the solve with solution stored in lhs + + /// Do the solve with solution stored in lhs auto ierr = KSPSolve(ksp, rhs, lhs); CHKERRQ(ierr); KSPConvergedReason reason; - ierr = KSPGetConvergedReason( ksp, &reason ); - if(reason <=0 ){ - throw BoutException("KSPSolve failed with reason %d.",reason); + ierr = KSPGetConvergedReason(ksp, &reason); + if (reason <= 0) { + throw BoutException("KSPSolve failed with reason %d.", reason); } - + #if CHECK > 3 - output_info << "KSPSolve finished with converged reason : "<::verify"); #if CHECK > 1 const T result = invert(rhs); const T applied = func(result); - const BoutReal maxDiff = max(abs(applied-rhs),true); + const BoutReal maxDiff = max(abs(applied - rhs), true); #if CHECK > 3 if (maxDiff >= tol) { - output_info << "Maximum difference in verify is "< *ctx; auto ierr = MatShellGetContext(m, &ctx); - T tmpField(ctx->localmesh); tmpField.allocate(); + T tmpField(ctx->localmesh); + tmpField.allocate(); petscVecToField(v1, tmpField); T tmpField2 = ctx->func(tmpField); fieldToPetscVec(tmpField2, v2); return ierr; } - + /// The function that represents the operator that we wish to invert function_signature func; /// Reports the time spent in various parts of InvertOperator. Note /// that as the Timer "labels" are not unique to an instance the time /// reported is summed across all different instances. - static void reportTime(){ + static void reportTime() { BoutReal time_setup = Timer::resetTime("invert_operator_setup"); BoutReal time_invert = Timer::resetTime("invert_operator_invert"); BoutReal time_packing = Timer::resetTime("invert_operator_packing"); - output_info << "InvertOperator timing :: Setup "<< time_setup; - output_info << " , Invert(packing) "<< time_invert << "("; + output_info << "InvertOperator timing :: Setup " << time_setup; + output_info << " , Invert(packing) " << time_invert << "("; output_info << time_packing << ")" << endl; }; - - private: + +private: // PETSc objects Mat matOperator; Vec rhs, lhs; KSP ksp; // Internal types - Options *opt; //Do we need this? + Options *opt; // Do we need this? Mesh *localmesh; //< To ensure we can create T on the right mesh bool doneSetup = false; - + // To ensure PETSc has been setup - PetscLib lib; //Do we need this? + PetscLib lib; // Do we need this? }; /// Pack a PetscVec from a Field -template -PetscErrorCode fieldToPetscVec(const T& in, Vec out){ +template PetscErrorCode fieldToPetscVec(const T &in, Vec out) { TRACE("fieldToPetscVec"); Timer timer("invert_operator_packing"); - + PetscScalar *vecData; auto ierr = VecGetArray(out, &vecData); @@ -274,21 +281,20 @@ PetscErrorCode fieldToPetscVec(const T& in, Vec out){ int counter = 0; /// @TODO : Replace this with a BOUT_FOR type loop - for(const auto &i: in){ + for (const auto &i : in) { vecData[counter] = in[i]; counter++; } - + ierr = VecRestoreArray(out, &vecData); - CHKERRQ(ierr); + CHKERRQ(ierr); } /// Pack a Field from a PetscVec -template -PetscErrorCode petscVecToField(Vec in, T& out){ +template PetscErrorCode petscVecToField(Vec in, T &out) { TRACE("petscVecToField"); Timer timer("invert_operator_packing"); - + const PetscScalar *vecData; auto ierr = VecGetArrayRead(in, &vecData); @@ -296,15 +302,25 @@ PetscErrorCode petscVecToField(Vec in, T& out){ int counter = 0; - /// @TODO : Replace this with a BOUT_FOR type loop - for(const auto &i: out){ + /// @TODO : Replace this with a BOUT_FOR type loop + for (const auto &i : out) { out[i] = vecData[counter]; counter++; } - + ierr = VecRestoreArrayRead(in, &vecData); - CHKERRQ(ierr); + CHKERRQ(ierr); } +#else + +template class InvertOperator { +public: + // InvertOperator(){ + // static_assert(0==1, "Can't use InvertOperator when BOUT++ built without PETSc + // support."); + // } +}; + #endif // PETSC #endif // HEADER GUARD From 9b629dbf4861dcdc4c3ea0c51f81fbcdc0de047f Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 17:03:15 +0100 Subject: [PATCH 0019/1783] Make constructor take function rather than setup Provides interface to set the function --- include/bout/invert_operator.hxx | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/include/bout/invert_operator.hxx b/include/bout/invert_operator.hxx index 4532ce9a51..72d90dff64 100644 --- a/include/bout/invert_operator.hxx +++ b/include/bout/invert_operator.hxx @@ -75,9 +75,13 @@ public: using function_signature = std::function; /// Almost empty constructor -- currently don't actually use Options for anything - InvertOperator(Options *opt = nullptr, Mesh *localmesh = nullptr) - : opt(opt ? opt : Options::getRoot()->getSection("invertOperator")), - localmesh(localmesh ? localmesh : mesh), doneSetup(false){}; + InvertOperator(const function_signature &func = identity, Options *opt = nullptr, + Mesh *localmesh = nullptr) + : operatorFunction(func), + opt(opt ? opt : Options::getRoot()->getSection("invertOperator")), + localmesh(localmesh ? localmesh : mesh), doneSetup(false) { + TRACE("InvertOperator::constructor"); + }; /// Destructor just has to cleanup the PETSc owned objects. ~InvertOperator() { @@ -95,21 +99,24 @@ public: VecDestroy(&lhs); }; + /// Allow the user to override the existing function + void setOperatorFunction(const function_signature& func){ + TRACE("InvertOperator::setOperatorFunction"); + operatorFunction = func; + } /// Sets up the PETSc objects required for inverting the operator /// Currently also takes the functor that applies the operator this class /// represents. Not actually required by any of the setup so this should /// probably be moved to a separate place (maybe the constructor). - PetscErrorCode setup(function_signature funcIn = identity) { + PetscErrorCode setup() { TRACE("InvertOperator::setup"); + Timer timer("invert_operator_setup"); if (doneSetup) { throw BoutException("Trying to call setup on an InvertOperator instance that has " "already been setup."); } - // Take a copy of the functor - func = funcIn; - PetscInt ierr; // Hacky way to determine the local size for now From a8120af7dff14b99db155a44963d9f0207c9c218 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 17:03:54 +0100 Subject: [PATCH 0020/1783] Provide an interface to apply the operator Allows the function to be made private --- include/bout/invert_operator.hxx | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/include/bout/invert_operator.hxx b/include/bout/invert_operator.hxx index 72d90dff64..9e4819026c 100644 --- a/include/bout/invert_operator.hxx +++ b/include/bout/invert_operator.hxx @@ -85,7 +85,7 @@ public: /// Destructor just has to cleanup the PETSc owned objects. ~InvertOperator() { - + TRACE("InvertOperator::destructor"); #if CHECK > 3 output_info << endl; output_info << "Destroying KSP object in InvertOperator with properties: " << endl; @@ -104,6 +104,16 @@ public: TRACE("InvertOperator::setOperatorFunction"); operatorFunction = func; } + + /// Provide a way to apply the operator to a Field + T operator()(const T& input) { + TRACE("InvertOperator::operator()"); + return operatorFunction(input); + } + + /// Provide a synonym for applying the operator to a Field + T apply(const T& input){ return operator()(input); } + /// Sets up the PETSc objects required for inverting the operator /// Currently also takes the functor that applies the operator this class /// represents. Not actually required by any of the setup so this should @@ -214,7 +224,7 @@ public: TRACE("InvertOperator::verify"); #if CHECK > 1 const T result = invert(rhs); - const T applied = func(result); + const T applied = operator()(result); const BoutReal maxDiff = max(abs(applied - rhs), true); #if CHECK > 3 if (maxDiff >= tol) { @@ -240,14 +250,11 @@ public: T tmpField(ctx->localmesh); tmpField.allocate(); petscVecToField(v1, tmpField); - T tmpField2 = ctx->func(tmpField); + T tmpField2 = ctx->operator()(tmpField); fieldToPetscVec(tmpField2, v2); return ierr; } - /// The function that represents the operator that we wish to invert - function_signature func; - /// Reports the time spent in various parts of InvertOperator. Note /// that as the Timer "labels" are not unique to an instance the time /// reported is summed across all different instances. @@ -260,6 +267,9 @@ public: output_info << time_packing << ")" << endl; }; + /// The function that represents the operator that we wish to invert + function_signature operatorFunction; + private: // PETSc objects Mat matOperator; From 50be4ab635ef8a8f65484442c9c6a21402c4d456 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 17:04:19 +0100 Subject: [PATCH 0021/1783] Add TRACE macros --- include/bout/invert_operator.hxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/bout/invert_operator.hxx b/include/bout/invert_operator.hxx index 9e4819026c..81c82c6feb 100644 --- a/include/bout/invert_operator.hxx +++ b/include/bout/invert_operator.hxx @@ -245,6 +245,7 @@ public: /// Copies data from v1 into a field of type T, calls the function on this and then /// copies the result into the v2 argument. static PetscErrorCode functionWrapper(Mat m, Vec v1, Vec v2) { + TRACE("InvertOperator::functionWrapper"); InvertOperator *ctx; auto ierr = MatShellGetContext(m, &ctx); T tmpField(ctx->localmesh); @@ -259,6 +260,7 @@ public: /// that as the Timer "labels" are not unique to an instance the time /// reported is summed across all different instances. static void reportTime() { + TRACE("InvertOperator::reportTime"); BoutReal time_setup = Timer::resetTime("invert_operator_setup"); BoutReal time_invert = Timer::resetTime("invert_operator_invert"); BoutReal time_packing = Timer::resetTime("invert_operator_packing"); From c5dd12aa4eb6f20f57b950598fb75312b6c416ee Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 17:04:25 +0100 Subject: [PATCH 0022/1783] Small bug fix --- include/bout/invert_operator.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/invert_operator.hxx b/include/bout/invert_operator.hxx index 81c82c6feb..a27877cefc 100644 --- a/include/bout/invert_operator.hxx +++ b/include/bout/invert_operator.hxx @@ -180,7 +180,7 @@ public: /// representation /// of the operator we represent. Should probably provide an overload or similar as a /// way of setting the initial guess. - T invert(const T &rhs) { + T invert(const T &rhsField) { TRACE("InvertOperator::invert"); Timer timer("invert_operator_invert"); From 394dd96f899a6dab81507a7439f1c1c99249278c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 17:04:35 +0100 Subject: [PATCH 0023/1783] Don't use new in the example --- examples/invert_operator/invert_operator.cxx | 26 +++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/examples/invert_operator/invert_operator.cxx b/examples/invert_operator/invert_operator.cxx index adf9d1f40c..6f8fb9a492 100644 --- a/examples/invert_operator/invert_operator.cxx +++ b/examples/invert_operator/invert_operator.cxx @@ -9,7 +9,6 @@ Field3D delp(const Field3D &input) { return input + Delp2(input); }; class HW : public PhysicsModel { private: Field3D n; - InvertOperator *mySolver; struct myOp : public OperatorWrapper { BoutReal factor=1.; @@ -22,33 +21,37 @@ class HW : public PhysicsModel { SOLVE_FOR(n); - mySolver = new InvertOperator(); - - // mySolver->setup(delp); - mySolver->setup(myDelp); + InvertOperator mySolver(myDelp); // Above could also be: - // mySolver->setup(delp); + // mySolver(delp); // or even a Lambda - // mySolver->setup([](const Field3D &input) { return input + Delp2(input); }); + // mySolver([](const Field3D &input) { return input + Delp2(input); }); + + mySolver.setup(); // Note mySolve takes a copy of the passed functor so updates to the local // instance won't have any effect, but the function _can_ be changed (currently) // as it is a public member, so the following should work. myDelp.factor = 3.0; - mySolver->func = myDelp; + mySolver.setOperatorFunction(myDelp); + Field3D output = 3.0; n = -2.0; for(int i=0; i<10000; i++){ - output = mySolver->invert(n); + // myDelp.factor = i+1; + // mySolver.setOperatorFunction(myDelp); + output = mySolver.invert(n); + // auto pass = mySolver.verify(n) == 0 ? "False" : "True"; + // output_warn << "Has test passed ? " << pass << std::endl; } output_warn << endl; output_warn << "Max difference is " << max(abs(output - n), true) << std::endl; output_warn << std::endl; - auto pass = mySolver->verify(n) == 0 ? "False" : "True"; + auto pass = mySolver.verify(n) == 0 ? "False" : "True"; output_warn << "Has test passed ? " << pass << std::endl; output_warn << std::endl; - mySolver->reportTime(); + mySolver.reportTime(); return 0; } @@ -58,7 +61,6 @@ class HW : public PhysicsModel { } public: - ~HW() { delete mySolver; }; }; // Define a main() function From df06d029d4d77fa2b876427df3486e1422710dad Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 20:11:04 +0100 Subject: [PATCH 0024/1783] Rename InvertOperator to InvertableOperator --- ...t_operator.hxx => invertable_operator.hxx} | 68 +++++++++---------- 1 file changed, 32 insertions(+), 36 deletions(-) rename include/bout/{invert_operator.hxx => invertable_operator.hxx} (83%) diff --git a/include/bout/invert_operator.hxx b/include/bout/invertable_operator.hxx similarity index 83% rename from include/bout/invert_operator.hxx rename to include/bout/invertable_operator.hxx index a27877cefc..45cd854a3e 100644 --- a/include/bout/invert_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -30,10 +30,10 @@ #include #include -template class InvertOperator; +template class InvertableOperator; -#ifndef __INVERT_OPERATOR_H__ -#define __INVERT_OPERATOR_H__ +#ifndef __INVERTABLE_OPERATOR_H__ +#define __INVERTABLE_OPERATOR_H__ /// Provides a base struct representing a light wrapper /// around the operator function call `apply`. This is @@ -61,11 +61,11 @@ struct OperatorWrapper { /// No-op function to use as a default -- may wish to remove once testing phase complete template T identity(const T &in) { return in; }; -template class InvertOperator { +template class InvertableOperator { static_assert( std::is_base_of::value || std::is_base_of::value || std::is_base_of::value, - "InvertOperator must be templated with one of FieldPerp, Field2D or Field3D"); + "InvertableOperator must be templated with one of FieldPerp, Field2D or Field3D"); public: /// What type of field does the operator take? @@ -75,20 +75,20 @@ public: using function_signature = std::function; /// Almost empty constructor -- currently don't actually use Options for anything - InvertOperator(const function_signature &func = identity, Options *opt = nullptr, + InvertableOperator(const function_signature &func = identity, Options *opt = nullptr, Mesh *localmesh = nullptr) : operatorFunction(func), - opt(opt ? opt : Options::getRoot()->getSection("invertOperator")), + opt(opt ? opt : Options::getRoot()->getSection("invertableOperator")), localmesh(localmesh ? localmesh : mesh), doneSetup(false) { - TRACE("InvertOperator::constructor"); + TRACE("InvertableOperator::constructor"); }; /// Destructor just has to cleanup the PETSc owned objects. - ~InvertOperator() { - TRACE("InvertOperator::destructor"); + ~InvertableOperator() { + TRACE("InvertableOperator::destructor"); #if CHECK > 3 output_info << endl; - output_info << "Destroying KSP object in InvertOperator with properties: " << endl; + output_info << "Destroying KSP object in InvertableOperator with properties: " << endl; KSPView(ksp, PETSC_VIEWER_STDOUT_SELF); output_info << endl; #endif @@ -101,13 +101,13 @@ public: /// Allow the user to override the existing function void setOperatorFunction(const function_signature& func){ - TRACE("InvertOperator::setOperatorFunction"); + TRACE("InvertableOperator::setOperatorFunction"); operatorFunction = func; } /// Provide a way to apply the operator to a Field T operator()(const T& input) { - TRACE("InvertOperator::operator()"); + TRACE("InvertableOperator::operator()"); return operatorFunction(input); } @@ -119,11 +119,11 @@ public: /// represents. Not actually required by any of the setup so this should /// probably be moved to a separate place (maybe the constructor). PetscErrorCode setup() { - TRACE("InvertOperator::setup"); + TRACE("InvertableOperator::setup"); - Timer timer("invert_operator_setup"); + Timer timer("invertable_operator_setup"); if (doneSetup) { - throw BoutException("Trying to call setup on an InvertOperator instance that has " + throw BoutException("Trying to call setup on an InvertableOperator instance that has " "already been setup."); } @@ -181,12 +181,12 @@ public: /// of the operator we represent. Should probably provide an overload or similar as a /// way of setting the initial guess. T invert(const T &rhsField) { - TRACE("InvertOperator::invert"); - Timer timer("invert_operator_invert"); + TRACE("InvertableOperator::invert"); + Timer timer("invertable_operator_invert"); if (!doneSetup) { throw BoutException( - "Trying to call invert on an InvertOperator instance that has not been setup."); + "Trying to call invert on an InvertableOperator instance that has not been setup."); } ASSERT2(localmesh == rhsField.getMesh()); @@ -221,7 +221,7 @@ public: /// applying the registered function on the calculated inverse gives /// back the initial values. bool verify(const T &rhs, BoutReal tol = 1.0e-5) { - TRACE("InvertOperator::verify"); + TRACE("InvertableOperator::verify"); #if CHECK > 1 const T result = invert(rhs); const T applied = operator()(result); @@ -240,13 +240,13 @@ public: #endif }; - /// Wrapper that gets a pointer to the parent InvertOperator instance + /// Wrapper that gets a pointer to the parent InvertableOperator instance /// from the Matrix m and uses this to get the actual function to call. /// Copies data from v1 into a field of type T, calls the function on this and then /// copies the result into the v2 argument. static PetscErrorCode functionWrapper(Mat m, Vec v1, Vec v2) { - TRACE("InvertOperator::functionWrapper"); - InvertOperator *ctx; + TRACE("InvertableOperator::functionWrapper"); + InvertableOperator *ctx; auto ierr = MatShellGetContext(m, &ctx); T tmpField(ctx->localmesh); tmpField.allocate(); @@ -256,15 +256,15 @@ public: return ierr; } - /// Reports the time spent in various parts of InvertOperator. Note + /// Reports the time spent in various parts of InvertableOperator. Note /// that as the Timer "labels" are not unique to an instance the time /// reported is summed across all different instances. static void reportTime() { - TRACE("InvertOperator::reportTime"); - BoutReal time_setup = Timer::resetTime("invert_operator_setup"); - BoutReal time_invert = Timer::resetTime("invert_operator_invert"); - BoutReal time_packing = Timer::resetTime("invert_operator_packing"); - output_info << "InvertOperator timing :: Setup " << time_setup; + TRACE("InvertableOperator::reportTime"); + BoutReal time_setup = Timer::resetTime("invertable_operator_setup"); + BoutReal time_invert = Timer::resetTime("invertable_operator_invert"); + BoutReal time_packing = Timer::resetTime("invertable_operator_packing"); + output_info << "InvertableOperator timing :: Setup " << time_setup; output_info << " , Invert(packing) " << time_invert << "("; output_info << time_packing << ")" << endl; }; @@ -290,7 +290,7 @@ private: /// Pack a PetscVec from a Field template PetscErrorCode fieldToPetscVec(const T &in, Vec out) { TRACE("fieldToPetscVec"); - Timer timer("invert_operator_packing"); + Timer timer("invertable_operator_packing"); PetscScalar *vecData; @@ -312,7 +312,7 @@ template PetscErrorCode fieldToPetscVec(const T &in, Vec out) { /// Pack a Field from a PetscVec template PetscErrorCode petscVecToField(Vec in, T &out) { TRACE("petscVecToField"); - Timer timer("invert_operator_packing"); + Timer timer("invertable_operator_packing"); const PetscScalar *vecData; @@ -333,12 +333,8 @@ template PetscErrorCode petscVecToField(Vec in, T &out) { #else -template class InvertOperator { +template class InvertableOperator { public: - // InvertOperator(){ - // static_assert(0==1, "Can't use InvertOperator when BOUT++ built without PETSc - // support."); - // } }; #endif // PETSC From 6fd80b9f0ece474184dcfbe895bf9892ff5dbda8 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 20:12:09 +0100 Subject: [PATCH 0025/1783] Move invert_operator example to invertable_operator --- examples/{invert_operator => invertable_operator}/data/BOUT.inp | 0 .../invertable_operator.cxx} | 0 examples/{invert_operator => invertable_operator}/makefile | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename examples/{invert_operator => invertable_operator}/data/BOUT.inp (100%) rename examples/{invert_operator/invert_operator.cxx => invertable_operator/invertable_operator.cxx} (100%) rename examples/{invert_operator => invertable_operator}/makefile (59%) diff --git a/examples/invert_operator/data/BOUT.inp b/examples/invertable_operator/data/BOUT.inp similarity index 100% rename from examples/invert_operator/data/BOUT.inp rename to examples/invertable_operator/data/BOUT.inp diff --git a/examples/invert_operator/invert_operator.cxx b/examples/invertable_operator/invertable_operator.cxx similarity index 100% rename from examples/invert_operator/invert_operator.cxx rename to examples/invertable_operator/invertable_operator.cxx diff --git a/examples/invert_operator/makefile b/examples/invertable_operator/makefile similarity index 59% rename from examples/invert_operator/makefile rename to examples/invertable_operator/makefile index 80a8da2bbf..f59c90b2a1 100644 --- a/examples/invert_operator/makefile +++ b/examples/invertable_operator/makefile @@ -1,6 +1,6 @@ BOUT_TOP = ../.. -SOURCEC = invert_operator.cxx +SOURCEC = invertable_operator.cxx include $(BOUT_TOP)/make.config From 974bd1364f9fd2466d39036829e1dea10260e8e2 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 20:14:14 +0100 Subject: [PATCH 0026/1783] Update invertable_operator --- examples/invertable_operator/invertable_operator.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/invertable_operator/invertable_operator.cxx b/examples/invertable_operator/invertable_operator.cxx index 6f8fb9a492..0d2e5c8a14 100644 --- a/examples/invertable_operator/invertable_operator.cxx +++ b/examples/invertable_operator/invertable_operator.cxx @@ -1,5 +1,5 @@ -#include +#include #include #include @@ -21,7 +21,7 @@ class HW : public PhysicsModel { SOLVE_FOR(n); - InvertOperator mySolver(myDelp); + InvertableOperator mySolver(myDelp); // Above could also be: // mySolver(delp); // or even a Lambda From a200a5d98b871ed3d30275a7f2e2f36078c9a27e Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Sep 2018 20:22:48 +0100 Subject: [PATCH 0027/1783] Remove OperatorWrapper as not actually needed anymore with functor approach --- .../invertable_operator.cxx | 4 ++-- include/bout/invertable_operator.hxx | 19 +------------------ 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/examples/invertable_operator/invertable_operator.cxx b/examples/invertable_operator/invertable_operator.cxx index 0d2e5c8a14..ba472344b5 100644 --- a/examples/invertable_operator/invertable_operator.cxx +++ b/examples/invertable_operator/invertable_operator.cxx @@ -10,9 +10,9 @@ class HW : public PhysicsModel { private: Field3D n; - struct myOp : public OperatorWrapper { + struct myOp { BoutReal factor=1.; - Field3D operator()(const Field3D &input) override {output<<"Factor is "< class InvertableOperator; #ifndef __INVERTABLE_OPERATOR_H__ #define __INVERTABLE_OPERATOR_H__ -/// Provides a base struct representing a light wrapper -/// around the operator function call `apply`. This is -/// used so that users can derive from this struct to -/// provide member data that can be used in the apply -/// function call. -struct OperatorWrapper { - virtual Field3D operator()(const Field3D &input) { - throw BoutException("Invalid Field type 'Field3D' in OperatorWrapper."); - }; - virtual Field2D operator()(const Field2D &input) { - throw BoutException("Invalid Field type 'Field2D' in OperatorWrapper."); - }; - virtual FieldPerp operator()(const FieldPerp &input) { - throw BoutException("Invalid Field type 'FieldPerp' in OperatorWrapper."); - }; -}; - #ifdef BOUT_HAS_PETSC #include From 3e9ef912024ce08bbf81e12281801a4146ebe410 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Sep 2018 14:35:24 +0100 Subject: [PATCH 0028/1783] Update example input file --- examples/invertable_operator/data/BOUT.inp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/examples/invertable_operator/data/BOUT.inp b/examples/invertable_operator/data/BOUT.inp index 045ed5dd67..c01be865d8 100644 --- a/examples/invertable_operator/data/BOUT.inp +++ b/examples/invertable_operator/data/BOUT.inp @@ -1,4 +1,22 @@ +NOUT=0 + [mesh] nx = 20 ny = 16 -nz = 32 \ No newline at end of file +nz = 16 + +[mesh:ddz] +first = fft +second = fft + +[laplace] +inner_boundary_flags = 0#32#2 +outer_boundary_flags = 0#32#2 + +[all] +bndry_all = none +function = 0. + +[n] +scale = 1.0 +function = sin(z) #gauss(x-0.5)*cos(x*2*pi)*sin(z) \ No newline at end of file From ea7d47f00a38a44b0ff8480fc9a5c2625940cb57 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Sep 2018 14:36:03 +0100 Subject: [PATCH 0029/1783] Restructure invertable_operator example --- .../invertable_operator.cxx | 103 +++++++++++++----- 1 file changed, 77 insertions(+), 26 deletions(-) diff --git a/examples/invertable_operator/invertable_operator.cxx b/examples/invertable_operator/invertable_operator.cxx index ba472344b5..df44bebdad 100644 --- a/examples/invertable_operator/invertable_operator.cxx +++ b/examples/invertable_operator/invertable_operator.cxx @@ -1,14 +1,19 @@ +#include +#include +#include #include #include #include +#include + Field3D minus(const Field3D &input) { return -1.0 * input; }; Field3D delp(const Field3D &input) { return input + Delp2(input); }; class HW : public PhysicsModel { private: - Field3D n; + Field3D n, solutionInv, solutionLap; struct myOp { BoutReal factor=1.; @@ -16,47 +21,93 @@ class HW : public PhysicsModel { }; myOp myDelp; + struct myLaplacian { + Field3D D=1.0, C=1.0, A=0.0; + + // Drop C term for now + Field3D operator()(const Field3D &input) { + TRACE("myLaplacian::operator()"); + Field3D result = A*input + D*Delp2(input); + + // Ensure boundary points are set appropriately as given by the input field. + result.setBoundaryTo(input); + + return result; + }; + }; + + + myLaplacian mm; + InvertableOperator mySolver; + // Above could also be: + // mySolver(delp); + // or even a Lambda + // mySolver([](const Field3D &input) { return input + Delp2(input); }); + + class Laplacian *phiSolverXZ; + + const int nits=1000; + protected: int init(bool restart) { - SOLVE_FOR(n); + SOLVE_FOR(solutionLap); + SOLVE_FOR(solutionInv); - InvertableOperator mySolver(myDelp); - // Above could also be: - // mySolver(delp); - // or even a Lambda - // mySolver([](const Field3D &input) { return input + Delp2(input); }); - - mySolver.setup(); + mm.A=1.0e-1; + mm.D=1.0; // Note mySolve takes a copy of the passed functor so updates to the local // instance won't have any effect, but the function _can_ be changed (currently) - // as it is a public member, so the following should work. - myDelp.factor = 3.0; - mySolver.setOperatorFunction(myDelp); + // through setOperatorFunction + + mySolver.setOperatorFunction(mm); + mySolver.setup(); + + + phiSolverXZ = Laplacian::create(); + phiSolverXZ->setCoefA(mm.A); + phiSolverXZ->setCoefC(1.0); + phiSolverXZ->setCoefD(mm.D); + + n.applyBoundary("dirichlet"); - Field3D output = 3.0; - n = -2.0; - for(int i=0; i<10000; i++){ - // myDelp.factor = i+1; - // mySolver.setOperatorFunction(myDelp); - output = mySolver.invert(n); - // auto pass = mySolver.verify(n) == 0 ? "False" : "True"; - // output_warn << "Has test passed ? " << pass << std::endl; + return 0; + } + + int rhs(BoutReal time) { + ddt(n) = 0.; + ddt(solutionInv) = 0.; + ddt(solutionLap) = 0.; + + try{ + for(int i=0; isolve(n); + } + }catch(BoutException){ + }; + } + + output_warn<<"Max diff undo Invertable is "< Date: Tue, 11 Sep 2018 14:37:13 +0100 Subject: [PATCH 0030/1783] Ensure functions return when expected --- include/bout/invertable_operator.hxx | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 2cabbd0acb..1eb3b35f17 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -157,6 +157,8 @@ public: CHKERRQ(ierr); doneSetup = true; + + return ierr; }; /// Triggers the solve of A.x = b for x, where b = rhs and A is the matrix @@ -203,16 +205,16 @@ public: /// With checks enabled provides a convience routine to check that /// applying the registered function on the calculated inverse gives /// back the initial values. - bool verify(const T &rhs, BoutReal tol = 1.0e-5) { + bool verify(const T &rhsIn, BoutReal tol = 1.0e-5) { TRACE("InvertableOperator::verify"); #if CHECK > 1 - const T result = invert(rhs); + const T result = invert(rhsIn); const T applied = operator()(result); - const BoutReal maxDiff = max(abs(applied - rhs), true); + const BoutReal maxDiff = max(abs(applied - rhsIn), true); #if CHECK > 3 if (maxDiff >= tol) { output_info << "Maximum difference in verify is " << maxDiff << endl; - output_info << "Max rhs is " << max(abs(rhs), true) << endl; + output_info << "Max rhs is " << max(abs(rhsIn), true) << endl; output_info << "Max applied is " << max(abs(applied), true) << endl; output_info << "Max result is " << max(abs(result), true) << endl; }; @@ -247,9 +249,9 @@ public: BoutReal time_setup = Timer::resetTime("invertable_operator_setup"); BoutReal time_invert = Timer::resetTime("invertable_operator_invert"); BoutReal time_packing = Timer::resetTime("invertable_operator_packing"); - output_info << "InvertableOperator timing :: Setup " << time_setup; - output_info << " , Invert(packing) " << time_invert << "("; - output_info << time_packing << ")" << endl; + output_warn << "InvertableOperator timing :: Setup " << time_setup; + output_warn << " , Invert(packing) " << time_invert << "("; + output_warn << time_packing << ")" << endl; }; /// The function that represents the operator that we wish to invert @@ -290,6 +292,8 @@ template PetscErrorCode fieldToPetscVec(const T &in, Vec out) { ierr = VecRestoreArray(out, &vecData); CHKERRQ(ierr); + + return ierr; } /// Pack a Field from a PetscVec @@ -312,6 +316,8 @@ template PetscErrorCode petscVecToField(Vec in, T &out) { ierr = VecRestoreArrayRead(in, &vecData); CHKERRQ(ierr); + + return ierr; } #else From 42ff4475f8ee251c3ac9308e6c0101b0c6e03f6b Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Sep 2018 14:44:55 +0100 Subject: [PATCH 0031/1783] Bug fix add communicates. May want to revisit the need/location for these. --- include/bout/invertable_operator.hxx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 1eb3b35f17..7bf181e6b1 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -208,7 +208,8 @@ public: bool verify(const T &rhsIn, BoutReal tol = 1.0e-5) { TRACE("InvertableOperator::verify"); #if CHECK > 1 - const T result = invert(rhsIn); + T result = invert(rhsIn); + localmesh->communicate(result); const T applied = operator()(result); const BoutReal maxDiff = max(abs(applied - rhsIn), true); #if CHECK > 3 @@ -233,9 +234,16 @@ public: TRACE("InvertableOperator::functionWrapper"); InvertableOperator *ctx; auto ierr = MatShellGetContext(m, &ctx); - T tmpField(ctx->localmesh); - tmpField.allocate(); + T tmpField(ctx->localmesh); tmpField.allocate(); petscVecToField(v1, tmpField); + // Need following communicate if operator() uses guard cells, i.e. differential + // operator. Could delegate to the user function but then need to remove const + // from signature of the function (function_signature) likely involving a copy. + // @TODO : Consider removing the communicate and introduce requirement for user + // function to communicate if required. This would be neater as currently result + // of invert needs explicitly communicating if we want to apply the operator to + // it, for example (e.g. see verify). + ctx->localmesh->communicate(tmpField); T tmpField2 = ctx->operator()(tmpField); fieldToPetscVec(tmpField2, v2); return ierr; From 1929f3ffa8a230b341b23d0746db8ac18b01258c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Sep 2018 14:52:26 +0100 Subject: [PATCH 0032/1783] Add communicate for safety --- examples/invertable_operator/invertable_operator.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/invertable_operator/invertable_operator.cxx b/examples/invertable_operator/invertable_operator.cxx index df44bebdad..f14a5d13a9 100644 --- a/examples/invertable_operator/invertable_operator.cxx +++ b/examples/invertable_operator/invertable_operator.cxx @@ -86,6 +86,8 @@ class HW : public PhysicsModel { } }catch(BoutException){ }; + + mesh->communicate(solutionInv); output_warn << std::endl; auto pass = mySolver.verify(n) == 0 ? "False" : "True"; From 356f209b39585eade12d1873206f108c166c880d Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Sep 2018 14:56:43 +0100 Subject: [PATCH 0033/1783] TO REVERT -- Add Field::getRegion and RGN_NOCORNERS This commit should probably be reverted and a better thought out interface to extracting regions from Fields implemented instead. Also adds RGN_NOCORNERS which should be RGN_NOBNDRY plus the actual boundary cells (not the guard cells) without corner locations. --- include/field2d.hxx | 2 ++ include/field3d.hxx | 2 ++ include/fieldperp.hxx | 2 ++ src/field/field2d.cxx | 4 ++++ src/field/field3d.cxx | 3 +++ src/field/fieldperp.cxx | 4 ++++ src/mesh/mesh.cxx | 41 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 58 insertions(+) diff --git a/include/field2d.hxx b/include/field2d.hxx index 7d10403fa5..975fa28978 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -144,6 +144,8 @@ class Field2D : public Field, public FieldData { */ const IndexRange region(REGION rgn) const override; + const Region& getRegion(const std::string ®ion_name) const; + BoutReal& operator[](const Ind2D &d) { return data[d.ind]; } diff --git a/include/field3d.hxx b/include/field3d.hxx index aefc6a1075..5c38ad84a1 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -326,6 +326,8 @@ class Field3D : public Field, public FieldData { */ const IndexRange region2D(REGION rgn) const; + const Region& getRegion(const std::string ®ion_name) const; + /*! * Direct data access using DataIterator object. * This uses operator(x,y,z) so checks will only be diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 207267fe5a..1cf26f5915 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -89,6 +89,8 @@ class FieldPerp : public Field { const IndexRange region(REGION rgn) const override; + const Region& getRegion(const std::string ®ion_name) const; + /*! * Direct data access using DataIterator indexing */ diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 01ba00134d..b335849b02 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -174,6 +174,10 @@ const IndexRange Field2D::region(REGION rgn) const { }; } +const Region& Field2D::getRegion(const std::string ®ion_name) const { + return fieldmesh->getRegion2D(region_name); +} + // Not in header because we need to access fieldmesh BoutReal& Field2D::operator[](const Ind3D &d) { return operator[](fieldmesh->map3Dto2D(d)); diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index d6168531bf..773e00b947 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -354,6 +354,9 @@ const IndexRange Field3D::region2D(REGION rgn) const { }; } +const Region& Field3D::getRegion(const std::string ®ion_name) const { + return fieldmesh->getRegion3D(region_name); +} /////////////////// ASSIGNMENT //////////////////// Field3D & Field3D::operator=(const Field3D &rhs) { diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index d7f128269f..f5f57a0ba4 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -191,6 +191,10 @@ const IndexRange FieldPerp::region(REGION rgn) const { }; } +const Region& FieldPerp::getRegion(const std::string ®ion_name) const { + return fieldmesh->getRegionPerp(region_name); +} + //////////////// NON-MEMBER FUNCTIONS ////////////////// ////////////// NON-MEMBER OVERLOADED OPERATORS ////////////// diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index baed7a630c..95bb55e647 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -386,6 +386,21 @@ void Mesh::createDefaultRegions(){ addRegion3D("RGN_NOY", Region(0, LocalNx - 1, ystart, yend, 0, LocalNz - 1, LocalNy, LocalNz, maxregionblocksize)); + + // This avoids all guard cells and corners but includes boundaries + Region nocorner3D = getRegion3D("RGN_NOBNDRY"); + if (firstX()) nocorner3D += Region(0,1,ystart, yend, 0, LocalNz -1, + LocalNy, LocalNz, maxregionblocksize); + if (lastX()) nocorner3D += Region(LocalNx - 2,LocalNx - 1,ystart, yend, 0, LocalNz -1, + LocalNy, LocalNz, maxregionblocksize); + if (firstY()) nocorner3D += Region(xstart,xend,0, 1, 0, LocalNz -1, + LocalNy, LocalNz, maxregionblocksize); + if (lastY()) nocorner3D += Region(xstart,xend,LocalNy-2, LocalNy-1, 0, LocalNz -1, + LocalNy, LocalNz, maxregionblocksize); + + nocorner3D.unique(); + addRegion3D("RGN_NOCORNERS", nocorner3D); + //2D regions addRegion2D("RGN_ALL", Region(0, LocalNx - 1, 0, LocalNy - 1, 0, 0, LocalNy, 1, maxregionblocksize)); @@ -396,6 +411,21 @@ void Mesh::createDefaultRegions(){ addRegion2D("RGN_NOY", Region(0, LocalNx - 1, ystart, yend, 0, 0, LocalNy, 1, maxregionblocksize)); + + // This avoids all guard cells and corners but includes boundaries + Region nocorner2D = getRegion2D("RGN_NOBNDRY"); + if (firstX()) nocorner2D += Region(0,1,ystart, yend, 0, 0, + LocalNy, 1, maxregionblocksize); + if (lastX()) nocorner2D += Region(LocalNx - 2,LocalNx - 1,ystart, yend, 0, 0, + LocalNy, 1, maxregionblocksize); + if (firstY()) nocorner2D += Region(xstart,xend,0, 1, 0, 0, + LocalNy, 1, maxregionblocksize); + if (lastY()) nocorner2D += Region(xstart,xend,LocalNy-2, LocalNy-1, 0, 0, + LocalNy, 1, maxregionblocksize); + + nocorner2D.unique(); + addRegion2D("RGN_NOCORNERS", nocorner2D); + // Perp regions addRegionPerp("RGN_ALL", Region(0, LocalNx - 1, 0, 0, 0, LocalNz - 1, 1, LocalNz, maxregionblocksize)); @@ -406,6 +436,17 @@ void Mesh::createDefaultRegions(){ addRegionPerp("RGN_NOY", Region(0, LocalNx - 1, 0, 0, 0, LocalNz - 1, 1, LocalNz, maxregionblocksize)); // Same as ALL + // This avoids all guard cells and corners but includes boundaries + Region nocornerPerp = getRegionPerp("RGN_NOBNDRY"); + if (firstX()) nocornerPerp += Region(0,1,0, 0, 0, LocalNz -1, + 1, LocalNz, maxregionblocksize); + if (lastX()) nocornerPerp += Region(LocalNx - 2,LocalNx - 1,0, 0, 0, LocalNz -1, + 1, LocalNz, maxregionblocksize); + + nocornerPerp.unique(); + addRegionPerp("RGN_NOCORNERS", nocornerPerp); + + // Construct index lookup for 3D-->2D indexLookup3Dto2D = Array(LocalNx*LocalNy*LocalNz); for (const auto &ind3D: getRegion3D("RGN_ALL")){ From 46dc54e8387a664344e02e37a647b629c6d144d4 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Sep 2018 14:58:13 +0100 Subject: [PATCH 0034/1783] Bug fix : introduce further communicate --- include/bout/invertable_operator.hxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 7bf181e6b1..2cb3aaf516 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -245,6 +245,11 @@ public: // it, for example (e.g. see verify). ctx->localmesh->communicate(tmpField); T tmpField2 = ctx->operator()(tmpField); + // This communicate is required in case operator() ends up not setting + // all periodic boundaries correctly (possibly -- need to check?) + // @TODO : Consider need for this communicate. Could communicate at the + // end of the user routine. + ctx->localmesh->communicate(tmpField2); fieldToPetscVec(tmpField2, v2); return ierr; } From 1bc25570327d5f26d25c82b73bc44ff2b25c92a6 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Sep 2018 14:58:28 +0100 Subject: [PATCH 0035/1783] Replace loops over entire field with loops over RGN_NOCORNERS --- include/bout/invertable_operator.hxx | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 2cb3aaf516..4a80a9fa7d 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -116,10 +116,7 @@ public: PetscInt nlocal = 0; { T tmp(localmesh); - /// @TODO : Replace this with a BOUT_FOR type loop or alternative (T.size()?) - for (const auto &i : tmp) { - nlocal++; - } + nlocal = tmp.getRegion("RGN_NOCORNERS").size(); } PetscInt nglobal = PETSC_DETERMINE; // Depends on type of T @@ -297,8 +294,7 @@ template PetscErrorCode fieldToPetscVec(const T &in, Vec out) { int counter = 0; - /// @TODO : Replace this with a BOUT_FOR type loop - for (const auto &i : in) { + BOUT_FOR_SERIAL(i, in.getRegion("RGN_NOCORNERS") ) { vecData[counter] = in[i]; counter++; } @@ -321,8 +317,7 @@ template PetscErrorCode petscVecToField(Vec in, T &out) { int counter = 0; - /// @TODO : Replace this with a BOUT_FOR type loop - for (const auto &i : out) { + BOUT_FOR_SERIAL(i, out.getRegion("RGN_NOCORNERS") ) { out[i] = vecData[counter]; counter++; } From 58e073846e3a86bb58d3ee820160781f4714351c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Sep 2018 08:57:41 +0100 Subject: [PATCH 0036/1783] Provide mechanism for setting preconditioner matrix --- include/bout/invertable_operator.hxx | 58 +++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 4a80a9fa7d..9672c86cfb 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -60,7 +60,7 @@ public: /// Almost empty constructor -- currently don't actually use Options for anything InvertableOperator(const function_signature &func = identity, Options *opt = nullptr, Mesh *localmesh = nullptr) - : operatorFunction(func), + : operatorFunction(func), preconditionerFunction(func), opt(opt ? opt : Options::getRoot()->getSection("invertableOperator")), localmesh(localmesh ? localmesh : mesh), doneSetup(false) { TRACE("InvertableOperator::constructor"); @@ -88,6 +88,12 @@ public: operatorFunction = func; } + /// Allow the user to override the existing preconditioner function + void setPreconditionerFunction(const function_signature& func){ + TRACE("InvertableOperator::setPreconditionerFunction"); + preconditionerFunction = func; + } + /// Provide a way to apply the operator to a Field T operator()(const T& input) { TRACE("InvertableOperator::operator()"); @@ -125,7 +131,7 @@ public: /// Note we currently pass "this" as the Matrix context ierr = MatCreateShell(BoutComm::get(), nlocal, nlocal, nglobal, nglobal, this, &matOperator); - CHKERRQ(ierr); // Can't call this in constructor as includes a return statement + CHKERRQ(ierr); /// Create vectors compatible with matrix ierr = MatCreateVecs(matOperator, &rhs, @@ -137,10 +143,21 @@ public: MatShellSetOperation(matOperator, MATOP_MULT, (void (*)(void))(functionWrapper)); CHKERRQ(ierr); + /// Create the shell matrix representing the operator to invert + /// Note we currently pass "this" as the Matrix context + ierr = MatCreateShell(BoutComm::get(), nlocal, nlocal, nglobal, nglobal, this, + &matPreconditioner); + CHKERRQ(ierr); + + /// Now register Matrix_multiply operation + ierr = + MatShellSetOperation(matPreconditioner, MATOP_MULT, (void (*)(void))(preconditionerWrapper)); + CHKERRQ(ierr); + /// Now create and setup the linear solver with the matrix ierr = KSPCreate(BoutComm::get(), &ksp); CHKERRQ(ierr); - ierr = KSPSetOperators(ksp, matOperator, matOperator); + ierr = KSPSetOperators(ksp, matOperator, matPreconditioner); CHKERRQ(ierr); /// Allow options to be set on command line using a --invert_ksp_* prefix. @@ -251,6 +268,34 @@ public: return ierr; } + /// Wrapper that gets a pointer to the parent InvertableOperator instance + /// from the Matrix m and uses this to get the actual function to call. + /// Copies data from v1 into a field of type T, calls the function on this and then + /// copies the result into the v2 argument. + static PetscErrorCode preconditionerWrapper(Mat m, Vec v1, Vec v2) { + TRACE("InvertableOperator::functionWrapper"); + InvertableOperator *ctx; + auto ierr = MatShellGetContext(m, &ctx); + T tmpField(ctx->localmesh); tmpField.allocate(); + petscVecToField(v1, tmpField); + // Need following communicate if operator() uses guard cells, i.e. differential + // operator. Could delegate to the user function but then need to remove const + // from signature of the function (function_signature) likely involving a copy. + // @TODO : Consider removing the communicate and introduce requirement for user + // function to communicate if required. This would be neater as currently result + // of invert needs explicitly communicating if we want to apply the operator to + // it, for example (e.g. see verify). + ctx->localmesh->communicate(tmpField); + T tmpField2 = ctx->preconditionerFunction(tmpField); + // This communicate is required in case operator() ends up not setting + // all periodic boundaries correctly (possibly -- need to check?) + // @TODO : Consider need for this communicate. Could communicate at the + // end of the user routine. + ctx->localmesh->communicate(tmpField2); + fieldToPetscVec(tmpField2, v2); + return ierr; + } + /// Reports the time spent in various parts of InvertableOperator. Note /// that as the Timer "labels" are not unique to an instance the time /// reported is summed across all different instances. @@ -265,11 +310,14 @@ public: }; /// The function that represents the operator that we wish to invert - function_signature operatorFunction; + function_signature operatorFunction = identity; + + /// The function that represents the preconditioner for the operator that we wish to invert + function_signature preconditionerFunction = identity; private: // PETSc objects - Mat matOperator; + Mat matOperator, matPreconditioner; Vec rhs, lhs; KSP ksp; From 8bf90b65c07e7835153029e38d2b8d5855b9d6d5 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Sep 2018 08:59:40 +0100 Subject: [PATCH 0037/1783] Make setOperatorFunction by default also set the preConditionerFunction --- include/bout/invertable_operator.hxx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 9672c86cfb..267510bce4 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -83,9 +83,15 @@ public: }; /// Allow the user to override the existing function - void setOperatorFunction(const function_signature& func){ - TRACE("InvertableOperator::setOperatorFunction"); + /// Note by default we set the preconditioner function to match this + /// as this is the usual mode of operation. If the user doesn't want to + /// do this they can set alsoSetPreconditioner to false. + void setOperatorFunction(const function_signature& func, bool alsoSetPreconditioner = true){ + TRACE("InvertableOperator::setOperatorFunction"); operatorFunction = func; + if ( alsoSetPreconditioner ) { + preconditionerFunction = func; + } } /// Allow the user to override the existing preconditioner function From 85eb30950810b35bfdb10d252dd85f738341602f Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Sep 2018 09:00:14 +0100 Subject: [PATCH 0038/1783] Report on the time spent in the user callback function --- examples/invertable_operator/invertable_operator.cxx | 1 + include/bout/invertable_operator.hxx | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/invertable_operator/invertable_operator.cxx b/examples/invertable_operator/invertable_operator.cxx index f14a5d13a9..3926068227 100644 --- a/examples/invertable_operator/invertable_operator.cxx +++ b/examples/invertable_operator/invertable_operator.cxx @@ -27,6 +27,7 @@ class HW : public PhysicsModel { // Drop C term for now Field3D operator()(const Field3D &input) { TRACE("myLaplacian::operator()"); + Timer timer("invertable_operator_operate"); Field3D result = A*input + D*Delp2(input); // Ensure boundary points are set appropriately as given by the input field. diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 267510bce4..26dedcf0ce 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -310,9 +310,12 @@ public: BoutReal time_setup = Timer::resetTime("invertable_operator_setup"); BoutReal time_invert = Timer::resetTime("invertable_operator_invert"); BoutReal time_packing = Timer::resetTime("invertable_operator_packing"); + + BoutReal time_operate = Timer::resetTime("invertable_operator_operate"); output_warn << "InvertableOperator timing :: Setup " << time_setup; output_warn << " , Invert(packing) " << time_invert << "("; - output_warn << time_packing << ")" << endl; + output_warn << time_packing << ")" ; + output_warn << " operate :"< Date: Wed, 12 Sep 2018 09:53:46 +0100 Subject: [PATCH 0039/1783] Make sure preconditioner matrix is destroyed. --- include/bout/invertable_operator.hxx | 1 + 1 file changed, 1 insertion(+) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 26dedcf0ce..f717202aa7 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -78,6 +78,7 @@ public: KSPDestroy(&ksp); MatDestroy(&matOperator); + MatDestroy(&matPreconditioner); VecDestroy(&rhs); VecDestroy(&lhs); }; From 8e92083b6fa074542c4697edeea6c4c2bfe8399f Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Sep 2018 14:02:33 +0100 Subject: [PATCH 0040/1783] Clang format InvertableOperator example file --- .../invertable_operator.cxx | 86 ++++++++++++------- 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/examples/invertable_operator/invertable_operator.cxx b/examples/invertable_operator/invertable_operator.cxx index 3926068227..1ad567558f 100644 --- a/examples/invertable_operator/invertable_operator.cxx +++ b/examples/invertable_operator/invertable_operator.cxx @@ -1,9 +1,9 @@ #include #include -#include #include #include +#include #include #include @@ -14,21 +14,44 @@ Field3D delp(const Field3D &input) { return input + Delp2(input); }; class HW : public PhysicsModel { private: Field3D n, solutionInv, solutionLap; - + struct myOp { - BoutReal factor=1.; - Field3D operator()(const Field3D &input) {return factor*input + Delp2(input); } ; + BoutReal factor = 1.; + Field3D operator()(const Field3D &input) { return factor * input + Delp2(input); }; }; myOp myDelp; struct myLaplacian { - Field3D D=1.0, C=1.0, A=0.0; + Field3D D = 1.0, C = 1.0, A = 0.0; + + // Drop C term for now + Field3D operator()(const Field3D &input) { + TRACE("myLaplacian::operator()"); + Timer timer("invertable_operator_operate"); + Field3D result = A * input + D * Delp2(input); + + // Ensure boundary points are set appropriately as given by the input field. + result.setBoundaryTo(input); + + return result; + }; + }; + + struct my3DLaplacian { + Field3D A = 1.0, B = 1.0, C = 0.0, D = 0.0; + bool withDiv = false; // Drop C term for now Field3D operator()(const Field3D &input) { TRACE("myLaplacian::operator()"); - Timer timer("invertable_operator_operate"); - Field3D result = A*input + D*Delp2(input); + Timer timer("invertable_operator_operate"); + Field3D result = A * input + B * Laplace_perp(input); + if (withDiv) { + auto tmp = C * Grad_perp(input); + input.getMesh()->communicate(tmp); + result += Div(tmp); + } + result += D * Laplace(input); // Ensure boundary points are set appropriately as given by the input field. result.setBoundaryTo(input); @@ -37,7 +60,6 @@ class HW : public PhysicsModel { }; }; - myLaplacian mm; InvertableOperator mySolver; // Above could also be: @@ -46,17 +68,17 @@ class HW : public PhysicsModel { // mySolver([](const Field3D &input) { return input + Delp2(input); }); class Laplacian *phiSolverXZ; - - const int nits=1000; - + + const int nits = 10; + protected: int init(bool restart) { SOLVE_FOR(n); SOLVE_FOR(solutionLap); SOLVE_FOR(solutionInv); - mm.A=1.0e-1; - mm.D=1.0; + mm.A = 1.0e-1; + mm.D = 1.0; // Note mySolve takes a copy of the passed functor so updates to the local // instance won't have any effect, but the function _can_ be changed (currently) @@ -65,14 +87,13 @@ class HW : public PhysicsModel { mySolver.setOperatorFunction(mm); mySolver.setup(); - phiSolverXZ = Laplacian::create(); phiSolverXZ->setCoefA(mm.A); phiSolverXZ->setCoefC(1.0); phiSolverXZ->setCoefD(mm.D); n.applyBoundary("dirichlet"); - + return 0; } @@ -81,15 +102,21 @@ class HW : public PhysicsModel { ddt(solutionInv) = 0.; ddt(solutionLap) = 0.; - try{ - for(int i=0; icommunicate(solutionInv); + } + } catch (BoutException) { }; mesh->communicate(solutionInv); - + output_warn << std::endl; auto pass = mySolver.verify(n) == 0 ? "False" : "True"; output_warn << "Has test passed ? " << pass << std::endl; @@ -97,19 +124,20 @@ class HW : public PhysicsModel { { Timer timer("sol_lap"); - try{ - for(int i=0; isolve(n); - } - }catch(BoutException){ + try { + for (int i = 0; i < nits; i++) { + solutionLap = phiSolverXZ->solve(n); + } + } catch (BoutException) { }; } - output_warn<<"Max diff undo Invertable is "< Date: Wed, 12 Sep 2018 14:09:33 +0100 Subject: [PATCH 0041/1783] Catch by ref --- examples/invertable_operator/invertable_operator.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/invertable_operator/invertable_operator.cxx b/examples/invertable_operator/invertable_operator.cxx index 1ad567558f..70dc60e5b1 100644 --- a/examples/invertable_operator/invertable_operator.cxx +++ b/examples/invertable_operator/invertable_operator.cxx @@ -112,7 +112,7 @@ class HW : public PhysicsModel { solutionInv = mySolver.invert(n, solutionInv); // mesh->communicate(solutionInv); } - } catch (BoutException) { + } catch (&BoutException) { }; mesh->communicate(solutionInv); @@ -128,7 +128,7 @@ class HW : public PhysicsModel { for (int i = 0; i < nits; i++) { solutionLap = phiSolverXZ->solve(n); } - } catch (BoutException) { + } catch (&BoutException) { }; } From d2f62d6e817b70380fbdf65bf0a5a20ea640db80 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Sep 2018 14:22:50 +0100 Subject: [PATCH 0042/1783] Provide an interface to invert that allows the user to set the initial guess --- include/bout/invertable_operator.hxx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index f717202aa7..7cb0097153 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -145,6 +145,12 @@ public: &lhs); // Older versions may need to use MatGetVecs CHKERRQ(ierr); + /// Zero out the lhs vector as values used for initial guess + /// in solve step. Don't need to initialise rhs as this is + /// done in the callback function using the passed Field. + ierr = VecSet(lhs, 0.0); + CHKERRQ(ierr); + /// Now register Matrix_multiply operation ierr = MatShellSetOperation(matOperator, MATOP_MULT, (void (*)(void))(functionWrapper)); @@ -182,6 +188,15 @@ public: return ierr; }; + // Pack values into lhs vec before solving. + // This may be the way to set the initial guess + // but suspect it's not as there are KSPGuess objects + // to deal with. + T invert(const T &rhsField, const T &guess) { + fieldToPetscVec(guess, lhs); + return invert(rhsField); + } + /// Triggers the solve of A.x = b for x, where b = rhs and A is the matrix /// representation /// of the operator we represent. Should probably provide an overload or similar as a @@ -201,6 +216,12 @@ public: fieldToPetscVec(rhsField, rhs); /// Do the solve with solution stored in lhs + /// Note: the values in lhs on input are used as the initial guess + /// provided KSPSetInitialGuessNonzero has been called as true (if + /// not then lhs is zeroed on entry). As the results in lhs persist + /// between calls to invert (as a class member rather than local scope) + /// we automatically provide the previous solution as the initial guess + /// for subsequent solves. auto ierr = KSPSolve(ksp, rhs, lhs); CHKERRQ(ierr); From 342049591ba78ddaac1f9ccd90ff3b3b2717bfec Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Sep 2018 14:52:46 +0100 Subject: [PATCH 0043/1783] Correct catch statements --- examples/invertable_operator/invertable_operator.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/invertable_operator/invertable_operator.cxx b/examples/invertable_operator/invertable_operator.cxx index 70dc60e5b1..1b01125e2c 100644 --- a/examples/invertable_operator/invertable_operator.cxx +++ b/examples/invertable_operator/invertable_operator.cxx @@ -112,7 +112,7 @@ class HW : public PhysicsModel { solutionInv = mySolver.invert(n, solutionInv); // mesh->communicate(solutionInv); } - } catch (&BoutException) { + } catch (BoutException &e) { }; mesh->communicate(solutionInv); @@ -128,7 +128,7 @@ class HW : public PhysicsModel { for (int i = 0; i < nits; i++) { solutionLap = phiSolverXZ->solve(n); } - } catch (&BoutException) { + } catch (BoutException &e) { }; } From 8c00419914ade8a34d9889af6dd8f00fafa80b7c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 13 Sep 2018 09:49:02 +0100 Subject: [PATCH 0044/1783] Default to non-zero initial guess --- include/bout/invertable_operator.hxx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 7cb0097153..e89ae8d784 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -173,6 +173,14 @@ public: ierr = KSPSetOperators(ksp, matOperator, matPreconditioner); CHKERRQ(ierr); + /// By default allow a non-zero initial guess as this is probably the + /// most helpful mode of operation. To disable this user can pass + /// `-invert_ksp_initial_guess_nonzero false` on the command line or simply + /// use `result = operator.invert(rhs, 0.0)` which will lead to an initial + /// guess of zero being used. + ierr = KSPSetInitialGuessNonzero(ksp, PETSC_TRUE); + CHKERRQ(ierr); + /// Allow options to be set on command line using a --invert_ksp_* prefix. ierr = KSPSetOptionsPrefix(ksp, "invert_"); CHKERRQ(ierr); From 396d728c9d6c3cacbadf047db74f12202b2559ac Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 13 Sep 2018 10:05:05 +0100 Subject: [PATCH 0045/1783] Add support for earlier PETSc versions (tested with 3.4.5) --- include/bout/invertable_operator.hxx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index e89ae8d784..2b225f77e4 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -141,8 +141,13 @@ public: CHKERRQ(ierr); /// Create vectors compatible with matrix +#if PETSC_VERSION_LT(3,6,0) + ierr = MatGetVecs(matOperator, &rhs, + &lhs); +#else ierr = MatCreateVecs(matOperator, &rhs, - &lhs); // Older versions may need to use MatGetVecs + &lhs); +#endif CHKERRQ(ierr); /// Zero out the lhs vector as values used for initial guess @@ -170,7 +175,16 @@ public: /// Now create and setup the linear solver with the matrix ierr = KSPCreate(BoutComm::get(), &ksp); CHKERRQ(ierr); + +#if PETSC_VERSION_LT(3,5,0) + /// Need to provide a MatStructure flag in versions <3.5. This details if we expect + /// the preconditioner matrix structure to vary between calls to KSPSolve. + /// Safest but slowest option is DIFFERENT_NONZERO_PATTERN but can probably usually + /// use SAME_PRECONDITIONER. + ierr = KSPSetOperators(ksp, matOperator, matPreconditioner, DIFFERENT_NONZERO_PATTERN); +#else ierr = KSPSetOperators(ksp, matOperator, matPreconditioner); +#endif CHKERRQ(ierr); /// By default allow a non-zero initial guess as this is probably the From f7b774e4cb227cc47b06b319980549bb4720dbe5 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 13 Sep 2018 10:18:38 +0100 Subject: [PATCH 0046/1783] Make more InvertableOperator details private --- include/bout/invertable_operator.hxx | 77 ++++++++++++++-------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 2b225f77e4..494c6c186e 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -61,8 +61,8 @@ public: InvertableOperator(const function_signature &func = identity, Options *opt = nullptr, Mesh *localmesh = nullptr) : operatorFunction(func), preconditionerFunction(func), - opt(opt ? opt : Options::getRoot()->getSection("invertableOperator")), - localmesh(localmesh ? localmesh : mesh), doneSetup(false) { + opt(opt ? opt : Options::getRoot()->getSection("invertableOperator")), + localmesh(localmesh ? localmesh : mesh), doneSetup(false) { TRACE("InvertableOperator::constructor"); }; @@ -290,6 +290,43 @@ public: #endif }; + /// Reports the time spent in various parts of InvertableOperator. Note + /// that as the Timer "labels" are not unique to an instance the time + /// reported is summed across all different instances. + static void reportTime() { + TRACE("InvertableOperator::reportTime"); + BoutReal time_setup = Timer::resetTime("invertable_operator_setup"); + BoutReal time_invert = Timer::resetTime("invertable_operator_invert"); + BoutReal time_packing = Timer::resetTime("invertable_operator_packing"); + + BoutReal time_operate = Timer::resetTime("invertable_operator_operate"); + output_warn << "InvertableOperator timing :: Setup " << time_setup; + output_warn << " , Invert(packing) " << time_invert << "("; + output_warn << time_packing << ")" ; + output_warn << " operate :"<; + + /// The function that represents the preconditioner for the operator that we wish to invert + function_signature preconditionerFunction = identity; + + // To ensure PETSc has been setup -- a bit noisy if creating/destroying InvertableOperator, + // maybe this should be static to avoid this but then how do we initialise it? + PetscLib lib; // Do we need this? + /// Wrapper that gets a pointer to the parent InvertableOperator instance /// from the Matrix m and uses this to get the actual function to call. /// Copies data from v1 into a field of type T, calls the function on this and then @@ -345,42 +382,6 @@ public: fieldToPetscVec(tmpField2, v2); return ierr; } - - /// Reports the time spent in various parts of InvertableOperator. Note - /// that as the Timer "labels" are not unique to an instance the time - /// reported is summed across all different instances. - static void reportTime() { - TRACE("InvertableOperator::reportTime"); - BoutReal time_setup = Timer::resetTime("invertable_operator_setup"); - BoutReal time_invert = Timer::resetTime("invertable_operator_invert"); - BoutReal time_packing = Timer::resetTime("invertable_operator_packing"); - - BoutReal time_operate = Timer::resetTime("invertable_operator_operate"); - output_warn << "InvertableOperator timing :: Setup " << time_setup; - output_warn << " , Invert(packing) " << time_invert << "("; - output_warn << time_packing << ")" ; - output_warn << " operate :"<; - - /// The function that represents the preconditioner for the operator that we wish to invert - function_signature preconditionerFunction = identity; - -private: - // PETSc objects - Mat matOperator, matPreconditioner; - Vec rhs, lhs; - KSP ksp; - - // Internal types - Options *opt; // Do we need this? - Mesh *localmesh; //< To ensure we can create T on the right mesh - bool doneSetup = false; - - // To ensure PETSc has been setup - PetscLib lib; // Do we need this? }; /// Pack a PetscVec from a Field From c68762d75e7c34409879480d60e64798da9487ea Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 13 Sep 2018 11:20:06 +0100 Subject: [PATCH 0047/1783] Update RGN_NOCORNERS to avoid adding periodic boundaries --- src/mesh/mesh.cxx | 63 ++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 95bb55e647..552af53dc8 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -388,15 +388,26 @@ void Mesh::createDefaultRegions(){ // This avoids all guard cells and corners but includes boundaries + // Note we probably don't want to include periodic boundaries as these + // are essentially just duplicate points so should be careful here (particularly in y) + // to only include unique points Region nocorner3D = getRegion3D("RGN_NOBNDRY"); - if (firstX()) nocorner3D += Region(0,1,ystart, yend, 0, LocalNz -1, - LocalNy, LocalNz, maxregionblocksize); - if (lastX()) nocorner3D += Region(LocalNx - 2,LocalNx - 1,ystart, yend, 0, LocalNz -1, - LocalNy, LocalNz, maxregionblocksize); - if (firstY()) nocorner3D += Region(xstart,xend,0, 1, 0, LocalNz -1, - LocalNy, LocalNz, maxregionblocksize); - if (lastY()) nocorner3D += Region(xstart,xend,LocalNy-2, LocalNy-1, 0, LocalNz -1, - LocalNy, LocalNz, maxregionblocksize); + if(!periodicX) { + if (firstX()) nocorner3D += Region(0,1,ystart, yend, 0, LocalNz -1, + LocalNy, LocalNz, maxregionblocksize); + if (lastX()) nocorner3D += Region(LocalNx - 2,LocalNx - 1,ystart, yend, 0, LocalNz -1, + LocalNy, LocalNz, maxregionblocksize); + } + if(firstY() or lastY()) { + for(int ix = xstart; ix <= xend; ix++) { + if(not periodicY(ix)) { + if (firstY()) nocorner3D += Region(ix,ix,0, 1, 0, LocalNz -1, + LocalNy, LocalNz, maxregionblocksize); + if (lastY()) nocorner3D += Region(ix,ix,LocalNy-2, LocalNy-1, 0, LocalNz -1, + LocalNy, LocalNz, maxregionblocksize); + } + } + } nocorner3D.unique(); addRegion3D("RGN_NOCORNERS", nocorner3D); @@ -414,15 +425,22 @@ void Mesh::createDefaultRegions(){ // This avoids all guard cells and corners but includes boundaries Region nocorner2D = getRegion2D("RGN_NOBNDRY"); - if (firstX()) nocorner2D += Region(0,1,ystart, yend, 0, 0, - LocalNy, 1, maxregionblocksize); - if (lastX()) nocorner2D += Region(LocalNx - 2,LocalNx - 1,ystart, yend, 0, 0, - LocalNy, 1, maxregionblocksize); - if (firstY()) nocorner2D += Region(xstart,xend,0, 1, 0, 0, - LocalNy, 1, maxregionblocksize); - if (lastY()) nocorner2D += Region(xstart,xend,LocalNy-2, LocalNy-1, 0, 0, - LocalNy, 1, maxregionblocksize); - + if(!periodicX) { + if (firstX()) nocorner2D += Region(0,1,ystart, yend, 0, 0, + LocalNy, 1, maxregionblocksize); + if (lastX()) nocorner2D += Region(LocalNx - 2,LocalNx - 1,ystart, yend, 0, 0, + LocalNy, 1, maxregionblocksize); + } + if(firstY() or lastY()) { + for(int ix = xstart; ix <= xend; ix++) { + if(not periodicY(ix)) { + if (firstY()) nocorner2D += Region(ix,ix,0, 1, 0, 0, + LocalNy, 1, maxregionblocksize); + if (lastY()) nocorner2D += Region(ix,ix,LocalNy-2, LocalNy-1, 0, 0, + LocalNy, 1, maxregionblocksize); + } + } + } nocorner2D.unique(); addRegion2D("RGN_NOCORNERS", nocorner2D); @@ -438,11 +456,12 @@ void Mesh::createDefaultRegions(){ // This avoids all guard cells and corners but includes boundaries Region nocornerPerp = getRegionPerp("RGN_NOBNDRY"); - if (firstX()) nocornerPerp += Region(0,1,0, 0, 0, LocalNz -1, - 1, LocalNz, maxregionblocksize); - if (lastX()) nocornerPerp += Region(LocalNx - 2,LocalNx - 1,0, 0, 0, LocalNz -1, - 1, LocalNz, maxregionblocksize); - + if(!periodicX) { + if (firstX()) nocornerPerp += Region(0,1,0, 0, 0, LocalNz -1, + 1, LocalNz, maxregionblocksize); + if (lastX()) nocornerPerp += Region(LocalNx - 2,LocalNx - 1,0, 0, 0, LocalNz -1, + 1, LocalNz, maxregionblocksize); + } nocornerPerp.unique(); addRegionPerp("RGN_NOCORNERS", nocornerPerp); From fe7974f4973ea7ca35d8acf1ccbb8588fdaa2cd0 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 9 Oct 2018 10:13:38 +0100 Subject: [PATCH 0048/1783] Adding an enum class to represent the three logic directions --- include/bout_types.hxx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 0553159867..6081567139 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -69,6 +69,19 @@ inline const std::string& REGION_STRING(REGION region) { return REGIONtoString.at(region); } +/// To identify particular directions (in index space) +enum class DIRECTION { X = 0, Y = 1, Z = 2 }; + +const std::map DIRECTIONtoString = { + {DIRECTION::X, "X"}, + {DIRECTION::Y, "Y"}, + {DIRECTION::Z, "Z"} +}; + +inline const std::string& DIRECTION_STRING(DIRECTION direction) { + return DIRECTIONtoString.at(direction); +} + /// Boundary condition function typedef BoutReal (*FuncPtr)(BoutReal t, BoutReal x, BoutReal y, BoutReal z); From 7996b8749f45a6f580a48eea38dbfc4a408a6ac8 Mon Sep 17 00:00:00 2001 From: Brendan Shanahan Date: Tue, 9 Oct 2018 13:55:19 +0200 Subject: [PATCH 0049/1783] Add fmod function for inputs, and a test in test-initial --- src/field/field_factory.cxx | 1 + tests/integrated/test-initial/data/BOUT.inp | 3 +++ tests/integrated/test-initial/runtest | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 884c228cd0..3180b50592 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -74,6 +74,7 @@ FieldFactory::FieldFactory(Mesh * localmesh, Options *opt) : fieldmesh(localmesh addGenerator("sqrt", std::make_shared(nullptr)); addGenerator("h", std::make_shared(nullptr)); addGenerator("erf", std::make_shared(nullptr)); + addGenerator("fmod", std::make_shared>(nullptr, nullptr)); addGenerator("min", std::make_shared()); addGenerator("max", std::make_shared()); diff --git a/tests/integrated/test-initial/data/BOUT.inp b/tests/integrated/test-initial/data/BOUT.inp index baffdf7b98..696f30d998 100644 --- a/tests/integrated/test-initial/data/BOUT.inp +++ b/tests/integrated/test-initial/data/BOUT.inp @@ -123,3 +123,6 @@ function = erf(x) [TanhHat] function = TanhHat(x, 0.5, 0.4, 0.3) + +[fmod] +function = fmod(x,.50) diff --git a/tests/integrated/test-initial/runtest b/tests/integrated/test-initial/runtest index d4ffd0dec1..0f5c6c83eb 100755 --- a/tests/integrated/test-initial/runtest +++ b/tests/integrated/test-initial/runtest @@ -120,6 +120,12 @@ def min(*args): current = np.minimum(arg, current) return current +def fmod(x, denominator=1.0): + """ + Modulo operator using fmod convention, (rem in Matlab) + """ + return np.fmod(x, denominator) + # Rename functions to match BOUT++ naming # Mostly just alternative names to numpy functions abs = np.abs From 01b486732e6dd2edd99bb3beb8314e5d63ee3ba0 Mon Sep 17 00:00:00 2001 From: Brendan Shanahan Date: Tue, 9 Oct 2018 15:05:11 +0200 Subject: [PATCH 0050/1783] Add fmod to variable initialisation documenation --- manual/sphinx/user_docs/variable_init.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/manual/sphinx/user_docs/variable_init.rst b/manual/sphinx/user_docs/variable_init.rst index 44f49cb2e5..3c03660bd1 100644 --- a/manual/sphinx/user_docs/variable_init.rst +++ b/manual/sphinx/user_docs/variable_init.rst @@ -170,6 +170,8 @@ expressions. | | :math:`\frac{1}{2}(\tanh[s (x-[c-\frac{w}{2}])]` | | | :math:`- \tanh[s (x-[c+\frac{w}{2}])] )` | +------------------------------------------+------------------------------------------------------+ + | ``fmod(x)`` | The modulo operator, returns floating point remainder| + +------------------------------------------+------------------------------------------------------+ For field-aligned tokamak simulations, the Y direction is along the field and in the core this will have a discontinuity at the twist-shift From 86d1cb331565e22da2906ec4ce205fd18956127e Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 10:03:13 +0100 Subject: [PATCH 0051/1783] Adding DIRECTION enum members to refer to specific Y meanings --- include/bout_types.hxx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 6081567139..ede4239539 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -70,12 +70,15 @@ inline const std::string& REGION_STRING(REGION region) { } /// To identify particular directions (in index space) -enum class DIRECTION { X = 0, Y = 1, Z = 2 }; +enum class DIRECTION { X = 0, Y = 1, Z = 3, YAligned = 4, YOrthogonal = 5 }; const std::map DIRECTIONtoString = { {DIRECTION::X, "X"}, {DIRECTION::Y, "Y"}, - {DIRECTION::Z, "Z"} + {DIRECTION::Z, "Z"}, + {DIRECTION::YAligned, "Y - field aligned"}, + {DIRECTION::YOrthogonal, "Y - orthogonal"} + }; inline const std::string& DIRECTION_STRING(DIRECTION direction) { From 467089a0e284953567520d9ea92df8f048aad728 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 10:05:34 +0100 Subject: [PATCH 0052/1783] Adding templated `minus` and `plus` routines to SpecificInd These are templated on the size of the offset to take and the direction in which to take the offset. --- include/bout/region.hxx | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/include/bout/region.hxx b/include/bout/region.hxx index d11587ef98..453cd7166a 100644 --- a/include/bout/region.hxx +++ b/include/bout/region.hxx @@ -226,6 +226,46 @@ public: int y() const { return (ind / nz) % ny; } int z() const { return (ind % nz); } + /// Templated routine to return index.?p(offset), where `?` is one of {x,y,z} + /// and is determined by the `dir` template argument. The offset corresponds + /// to the `dd` template argument. + template + const inline SpecificInd plus() const{ + switch(dir) { + case(DIRECTION::X): + return xp(dd); + case(DIRECTION::Y): + case(DIRECTION::YAligned): + case(DIRECTION::YOrthogonal): + return yp(dd); + case(DIRECTION::Z): + return zp(dd); +#if CHECK > 2 + default: throw BoutException("Invalid direction passed to SpecificInd.plus"); +#endif + } + } + + /// Templated routine to return index.?m(offset), where `?` is one of {x,y,z} + /// and is determined by the `dir` template argument. The offset corresponds + /// to the `dd` template argument. + template + const inline SpecificInd minus() const{ + switch(dir) { + case(DIRECTION::X): + return xm(dd); + case(DIRECTION::Y): + case(DIRECTION::YAligned): + case(DIRECTION::YOrthogonal): + return ym(dd); + case(DIRECTION::Z): + return zm(dd); +#if CHECK > 2 + default: throw BoutException("Invalid direction passed to SpecificInd.minus"); +#endif + } + } + const inline SpecificInd xp(int dx = 1) const { return {ind + (dx * ny * nz), ny, nz}; } /// The index one point -1 in x const inline SpecificInd xm(int dx = 1) const { return xp(-dx); } From 62ad8baf0583ada1d195be4f47fd45cb434f09c1 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 10:33:52 +0100 Subject: [PATCH 0053/1783] Adding unit tests for SpecificInd `minus` and `plus` --- tests/unit/include/bout/test_region.cxx | 280 ++++++++++++++++++++++++ 1 file changed, 280 insertions(+) diff --git a/tests/unit/include/bout/test_region.cxx b/tests/unit/include/bout/test_region.cxx index 50f37a29a7..85fb04458e 100644 --- a/tests/unit/include/bout/test_region.cxx +++ b/tests/unit/include/bout/test_region.cxx @@ -1829,6 +1829,79 @@ TEST_F(IndexOffsetTest, ZPlusOne) { } } +TEST_F(IndexOffsetTest, XPlusOneGeneric) { + const auto ®ion = mesh->getRegion3D("RGN_ALL"); + + auto index = region.cbegin(); + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_EQ(index->x(), i); + EXPECT_EQ(index->y(), j); + EXPECT_EQ(index->z(), k); + + if (i >= (nx - 1)) { + // skip this point + } else { + EXPECT_EQ((index->plus<1, DIRECTION::X>().x()), i + 1); + EXPECT_EQ((index->plus<1, DIRECTION::X>().y()), j); + EXPECT_EQ((index->plus<1, DIRECTION::X>().z()), k); + } + ++index; + } + } + } +} + +TEST_F(IndexOffsetTest, YPlusOneGeneric) { + const auto ®ion = mesh->getRegion3D("RGN_ALL"); + + auto index = region.cbegin(); + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_EQ(index->x(), i); + EXPECT_EQ(index->y(), j); + EXPECT_EQ(index->z(), k); + + if (j >= (ny - 1)) { +#if CHECK > 3 + EXPECT_THROW(index->yp(), BoutException); +#endif + } else { + EXPECT_EQ((index->plus<1, DIRECTION::Y>().x()), i); + EXPECT_EQ((index->plus<1, DIRECTION::Y>().y()), j + 1); + EXPECT_EQ((index->plus<1, DIRECTION::Y>().z()), k); + } + ++index; + } + } + } +} + +TEST_F(IndexOffsetTest, ZPlusOneGeneric) { + const auto ®ion = mesh->getRegion3D("RGN_ALL"); + + auto index = region.cbegin(); + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_EQ(index->x(), i); + EXPECT_EQ(index->y(), j); + EXPECT_EQ(index->z(), k); + + EXPECT_EQ((index->plus<1, DIRECTION::Z>().x()), i); + EXPECT_EQ((index->plus<1, DIRECTION::Z>().y()), j); + EXPECT_EQ((index->plus<1, DIRECTION::Z>().z()), (k + 1) % nz); + ++index; + } + } + } +} + TEST_F(IndexOffsetTest, XMinusOne) { const auto ®ion = mesh->getRegion3D("RGN_ALL"); @@ -1902,6 +1975,79 @@ TEST_F(IndexOffsetTest, ZMinusOne) { } } +TEST_F(IndexOffsetTest, XMinusOneGeneric) { + const auto ®ion = mesh->getRegion3D("RGN_ALL"); + + auto index = region.cbegin(); + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_EQ(index->x(), i); + EXPECT_EQ(index->y(), j); + EXPECT_EQ(index->z(), k); + + if (i < 1) { + // skip this point + } else { + EXPECT_EQ((index->minus<1, DIRECTION::X>().x()), i - 1); + EXPECT_EQ((index->minus<1, DIRECTION::X>().y()), j); + EXPECT_EQ((index->minus<1, DIRECTION::X>().z()), k); + } + ++index; + } + } + } +} + +TEST_F(IndexOffsetTest, YMinusOneGeneric) { + const auto ®ion = mesh->getRegion3D("RGN_ALL"); + + auto index = region.cbegin(); + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_EQ(index->x(), i); + EXPECT_EQ(index->y(), j); + EXPECT_EQ(index->z(), k); + + if (j < 1) { +#if CHECK > 3 + EXPECT_THROW(index->ym(), BoutException); +#endif + } else { + EXPECT_EQ((index->minus<1, DIRECTION::Y>().x()), i); + EXPECT_EQ((index->minus<1, DIRECTION::Y>().y()), j - 1); + EXPECT_EQ((index->minus<1, DIRECTION::Y>().z()), k); + } + ++index; + } + } + } +} + +TEST_F(IndexOffsetTest, ZMinusOneGeneric) { + const auto ®ion = mesh->getRegion3D("RGN_ALL"); + + auto index = region.cbegin(); + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_EQ(index->x(), i); + EXPECT_EQ(index->y(), j); + EXPECT_EQ(index->z(), k); + + EXPECT_EQ((index->minus<1, DIRECTION::Z>().x()), i); + EXPECT_EQ((index->minus<1, DIRECTION::Z>().y()), j); + EXPECT_EQ((index->minus<1, DIRECTION::Z>().z()), (k - 1 + nz) % nz); + ++index; + } + } + } +} + TEST_F(IndexOffsetTest, XPlusTwo) { const auto ®ion = mesh->getRegion3D("RGN_ALL"); @@ -2225,6 +2371,73 @@ TEST_F(IndexOffsetTest, ZPlusOneInd2D) { } } +TEST_F(IndexOffsetTest, XPlusOneInd2DGeneric) { + const auto ®ion = mesh->getRegion2D("RGN_ALL"); + + auto index = region.cbegin(); + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + EXPECT_EQ(index->x(), i); + EXPECT_EQ(index->y(), j); + EXPECT_EQ(index->z(), 0); + + if (i >= (nx - 1)) { + // skip this point + } else { + EXPECT_EQ((index->plus<1, DIRECTION::X>().x()), i + 1); + EXPECT_EQ((index->plus<1, DIRECTION::X>().y()), j); + EXPECT_EQ((index->plus<1, DIRECTION::X>().z()), 0); + } + ++index; + } + } +} + +TEST_F(IndexOffsetTest, YPlusOneInd2DGeneric) { + const auto ®ion = mesh->getRegion2D("RGN_ALL"); + + auto index = region.cbegin(); + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + EXPECT_EQ(index->x(), i); + EXPECT_EQ(index->y(), j); + EXPECT_EQ(index->z(), 0); + + if (j >= (ny - 1)) { +#if CHECK > 3 + EXPECT_THROW(index->yp(), BoutException); +#endif + } else { + EXPECT_EQ((index->plus<1, DIRECTION::Y>().x()), i); + EXPECT_EQ((index->plus<1, DIRECTION::Y>().y()), j + 1); + EXPECT_EQ((index->plus<1, DIRECTION::Y>().z()), 0); + } + ++index; + } + } +} + +TEST_F(IndexOffsetTest, ZPlusOneInd2DGeneric) { + const auto ®ion = mesh->getRegion2D("RGN_ALL"); + + auto index = region.cbegin(); + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + EXPECT_EQ(index->x(), i); + EXPECT_EQ(index->y(), j); + EXPECT_EQ(index->z(), 0); + + EXPECT_EQ((index->plus<1, DIRECTION::Z>().x()), i); + EXPECT_EQ((index->plus<1, DIRECTION::Z>().y()), j); + EXPECT_EQ((index->plus<1, DIRECTION::Z>().z()), 0); + ++index; + } + } +} + TEST_F(IndexOffsetTest, XMinusOneInd2D) { const auto ®ion = mesh->getRegion2D("RGN_ALL"); @@ -2292,6 +2505,73 @@ TEST_F(IndexOffsetTest, ZMinusOneInd2D) { } } +TEST_F(IndexOffsetTest, XMinusOneInd2DGeneric) { + const auto ®ion = mesh->getRegion2D("RGN_ALL"); + + auto index = region.cbegin(); + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + EXPECT_EQ(index->x(), i); + EXPECT_EQ(index->y(), j); + EXPECT_EQ(index->z(), 0); + + if (i < 1) { + // skip this point + } else { + EXPECT_EQ((index->minus<1, DIRECTION::X>().x()), i - 1); + EXPECT_EQ((index->minus<1, DIRECTION::X>().y()), j); + EXPECT_EQ((index->minus<1, DIRECTION::X>().z()), 0); + } + ++index; + } + } +} + +TEST_F(IndexOffsetTest, YMinusOneInd2DGeneric) { + const auto ®ion = mesh->getRegion2D("RGN_ALL"); + + auto index = region.cbegin(); + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + EXPECT_EQ(index->x(), i); + EXPECT_EQ(index->y(), j); + EXPECT_EQ(index->z(), 0); + + if (j < 1) { +#if CHECK > 3 + EXPECT_THROW(index->ym(), BoutException); +#endif + } else { + EXPECT_EQ((index->minus<1, DIRECTION::Y>().x()), i); + EXPECT_EQ((index->minus<1, DIRECTION::Y>().y()), j - 1); + EXPECT_EQ((index->minus<1, DIRECTION::Y>().z()), 0); + } + ++index; + } + } +} + +TEST_F(IndexOffsetTest, ZMinusOneInd2DGeneric) { + const auto ®ion = mesh->getRegion2D("RGN_ALL"); + + auto index = region.cbegin(); + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + EXPECT_EQ(index->x(), i); + EXPECT_EQ(index->y(), j); + EXPECT_EQ(index->z(), 0); + + EXPECT_EQ((index->minus<1, DIRECTION::Z>().x()), i); + EXPECT_EQ((index->minus<1, DIRECTION::Z>().y()), j); + EXPECT_EQ((index->minus<1, DIRECTION::Z>().z()), 0); + ++index; + } + } +} + TEST_F(IndexOffsetTest, XPlusTwoInd2D) { const auto ®ion = mesh->getRegion2D("RGN_ALL"); From 0220b70211c7f3438ca2485c204a90f3c0271743 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 11:33:37 +0100 Subject: [PATCH 0054/1783] Adding enum class to describe valid staggering combinations in derivatives --- include/bout_types.hxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index ede4239539..65ad7ba5ac 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -85,6 +85,20 @@ inline const std::string& DIRECTION_STRING(DIRECTION direction) { return DIRECTIONtoString.at(direction); } +/// To identify valid staggering combinations +enum class STAGGER { None = 0, C2L = 1, L2C = 2}; + +const std::map STAGGERtoString = { + {STAGGER::None, "No staggering"}, + {STAGGER::C2L, "Centre to Low"}, + {STAGGER::L2C, "Low to Centre"} + +}; + +inline const std::string& STAGGER_STRING(STAGGER stagger) { + return STAGGERtoString.at(stagger); +} + /// Boundary condition function typedef BoutReal (*FuncPtr)(BoutReal t, BoutReal x, BoutReal y, BoutReal z); From e7c2a29d527e36ae24b6163989e7f1c14b38a5c8 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 11:34:12 +0100 Subject: [PATCH 0055/1783] Adding templated routine `populateStencil` which should hopefully be usable to populate any stencil --- include/stencils.hxx | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/include/stencils.hxx b/include/stencils.hxx index 4fe22d63cf..8f5248c302 100644 --- a/include/stencils.hxx +++ b/include/stencils.hxx @@ -37,4 +37,46 @@ struct stencil { BoutReal mm = BoutNaN, m = BoutNaN, c = BoutNaN, p = BoutNaN, pp = BoutNaN; }; + +template +void inline populateStencil(stencil &s, const FieldType& f, const typename FieldType::ind_type i){ + static_assert(NGuard == 1 || NGuard == 2, + "populateStencil currently only supports one or two guard cells" + ); + + switch(stagger) { + case(STAGGER::None): + if (NGuard == 2) s.mm = f[i.template minus<2, direction>()]; + s.m = f[i.template minus<1, direction>()]; + s.c = f[i]; + s.p = f[i.template plus<1, direction>()]; + if (NGuard == 2) s.pp = f[i.template plus<2, direction>()]; + break; + case(STAGGER::C2L): + if (NGuard == 2) s.mm = f[i.template minus<2, direction>()]; + s.m = f[i.template minus<1, direction>()]; + s.c = f[i]; + s.p = s.c; + s.pp = f[i.template plus<1, direction>()]; + break; + case(STAGGER::L2C): + s.mm = f[i.template minus<1, direction>()]; + s.m = f[i]; + s.c = s.m; + s.p = f[i.template plus<1, direction>()]; + if (NGuard == 2) s.pp = f[i.template plus<2, direction>()]; + break; + } + return; +} + +template +stencil inline populateStencil(const FieldType& f, const typename FieldType::ind_type i){ + static_assert(NGuard == 1 || NGuard == 2, + "populateStencil currently only supports one or two guard cells" + ); + stencil s; + populateStencil(s, f, i); + return s; +} #endif /* __STENCILS_H__ */ From 55c863a1e2c0d133bafe1211c5c53e02edb820b1 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 12:08:37 +0100 Subject: [PATCH 0056/1783] Change order of populateStencil template args. Can now use type deduction to avoid need to specify what FieldType is being used. Provides defaults to enable less typing in common uses --- include/stencils.hxx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/stencils.hxx b/include/stencils.hxx index 8f5248c302..24555d2933 100644 --- a/include/stencils.hxx +++ b/include/stencils.hxx @@ -38,22 +38,22 @@ struct stencil { }; -template +template void inline populateStencil(stencil &s, const FieldType& f, const typename FieldType::ind_type i){ - static_assert(NGuard == 1 || NGuard == 2, + static_assert(nGuard == 1 || nGuard == 2, "populateStencil currently only supports one or two guard cells" ); switch(stagger) { case(STAGGER::None): - if (NGuard == 2) s.mm = f[i.template minus<2, direction>()]; + if (nGuard == 2) s.mm = f[i.template minus<2, direction>()]; s.m = f[i.template minus<1, direction>()]; s.c = f[i]; s.p = f[i.template plus<1, direction>()]; - if (NGuard == 2) s.pp = f[i.template plus<2, direction>()]; + if (nGuard == 2) s.pp = f[i.template plus<2, direction>()]; break; case(STAGGER::C2L): - if (NGuard == 2) s.mm = f[i.template minus<2, direction>()]; + if (nGuard == 2) s.mm = f[i.template minus<2, direction>()]; s.m = f[i.template minus<1, direction>()]; s.c = f[i]; s.p = s.c; @@ -64,19 +64,19 @@ void inline populateStencil(stencil &s, const FieldType& f, const typename Field s.m = f[i]; s.c = s.m; s.p = f[i.template plus<1, direction>()]; - if (NGuard == 2) s.pp = f[i.template plus<2, direction>()]; + if (nGuard == 2) s.pp = f[i.template plus<2, direction>()]; break; } return; } -template +template stencil inline populateStencil(const FieldType& f, const typename FieldType::ind_type i){ - static_assert(NGuard == 1 || NGuard == 2, + static_assert(nGuard == 1 || nGuard == 2, "populateStencil currently only supports one or two guard cells" ); stencil s; - populateStencil(s, f, i); + populateStencil(s, f, i); return s; } #endif /* __STENCILS_H__ */ From 216bf244346a286c6a4ee766bb1a01cd14f33939 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 12:10:01 +0100 Subject: [PATCH 0057/1783] Use populateStencil in `applyXdiff` --- src/mesh/index_derivs.cxx | 202 ++++++++++++++++---------------------- 1 file changed, 85 insertions(+), 117 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index d872b70ab4..b8cb1c1110 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -662,64 +662,56 @@ const Field2D Mesh::applyXdiff(const Field2D &var, Mesh::deriv_func func, Field2D result(this); result.allocate(); // Make sure data allocated - + if (this->StaggerGrids && (outloc != inloc)) { // Staggered differencing if (this->xstart > 1) { // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - s.mm = var[i.xmm()]; - s.m = var[i.xm()]; - s.c = var[i]; - s.p = var[i.xp()]; - s.pp = var[i.xpp()]; - - if (outloc == CELL_XLOW) { - // Producing a stencil centred around a lower X value - s.pp = s.p; - s.p = s.c; - } else { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; - } - - result[i] = func(s); - } + if (outloc == CELL_XLOW) { + BOUT_OMP(parallel) + { + stencil s; + BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + populateStencil(s, var, i); + result[i] = func(s); + } + } + } else { + BOUT_OMP(parallel) + { + stencil s; + BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + populateStencil(s, var, i); + result[i] = func(s); + } + } } } else { // Only one guard cell, so no pp or mm values - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - s.m = var[i.xm()]; - s.c = var[i]; - s.p = var[i.xp()]; - - if (outloc == CELL_XLOW) { - // Producing a stencil centred around a lower X value - s.pp = s.p; - s.p = s.c; - } else { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; - } - - result[i] = func(s); - } + if (outloc == CELL_XLOW) { + BOUT_OMP(parallel) + { + stencil s; + BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + populateStencil(s, var, i); + result[i] = func(s); + } + } + } else { + BOUT_OMP(parallel) + { + stencil s; + BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + populateStencil(s, var, i); + result[i] = func(s); + } + } } } - } else { // Non-staggered differencing - if (this->xstart > 1) { // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used @@ -727,12 +719,7 @@ const Field2D Mesh::applyXdiff(const Field2D &var, Mesh::deriv_func func, { stencil s; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - s.mm = var[i.xmm()]; - s.m = var[i.xm()]; - s.c = var[i]; - s.p = var[i.xp()]; - s.pp = var[i.xpp()]; - + populateStencil(s, var, i); result[i] = func(s); } } @@ -742,10 +729,7 @@ const Field2D Mesh::applyXdiff(const Field2D &var, Mesh::deriv_func func, { stencil s; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - s.m = var[i.xm()]; - s.c = var[i]; - s.p = var[i.xp()]; - + populateStencil(s, var, i); result[i] = func(s); } } @@ -794,85 +778,69 @@ const Field3D Mesh::applyXdiff(const Field3D &var, Mesh::deriv_func func, if (this->xstart > 1) { // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - s.mm = var[i.xmm()]; - s.m = var[i.xm()]; - s.c = var[i]; - s.p = var[i.xp()]; - s.pp = var[i.xpp()]; - - if ((inloc == CELL_CENTRE) && (outloc == CELL_XLOW)) { - // Producing a stencil centred around a lower X value - s.pp = s.p; - s.p = s.c; - } else if (inloc == CELL_XLOW) { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; - } - - result[i] = func(s); - } + if (outloc == CELL_XLOW) { + BOUT_OMP(parallel) + { + stencil s; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(s, var, i); + result[i] = func(s); + } + } + } else { + BOUT_OMP(parallel) + { + stencil s; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(s, var, i); + result[i] = func(s); + } + } } } else { // Only one guard cell, so no pp or mm values - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - s.m = var[i.xm()]; - s.c = var[i]; - s.p = var[i.xp()]; - - if (outloc == CELL_XLOW) { - // Producing a stencil centred around a lower X value - s.pp = s.p; - s.p = s.c; - } else if (inloc == CELL_XLOW) { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; - } - - result[i] = func(s); - } + if (outloc == CELL_XLOW) { + BOUT_OMP(parallel) + { + stencil s; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(s, var, i); + result[i] = func(s); + } + } + } else { + BOUT_OMP(parallel) + { + stencil s; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(s, var, i); + result[i] = func(s); + } + } } } - } else { // Non-staggered differencing - if (this->xstart > 1) { // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - s.mm = var[i.xmm()]; - s.m = var[i.xm()]; - s.c = var[i]; - s.p = var[i.xp()]; - s.pp = var[i.xpp()]; - - result[i] = func(s); - } + stencil s; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(s, var, i); + result[i] = func(s); + } } } else { // Only one guard cell, so no pp or mm values BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - s.m = var[i.xm()]; - s.c = var[i]; - s.p = var[i.xp()]; - - result[i] = func(s); - } + stencil s; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(s, var, i); + result[i] = func(s); + } } } } From 08852f212dbcb4b5ddfabfcdfe1597133c029cb3 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 12:39:21 +0100 Subject: [PATCH 0058/1783] Adding `yup` and `ydown` methods to Field2D. These just return a pointer to the parent field. --- include/field2d.hxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/field2d.hxx b/include/field2d.hxx index b261ca8456..29984ff94d 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -113,6 +113,20 @@ class Field2D : public Field, public FieldData { */ int getNz() const override {return 1;}; + Field2D& yup() { + return *this; + } + const Field2D& yup() const { + return *this; + } + + Field2D& ydown() { + return *this; + } + const Field2D& ydown() const { + return *this; + } + // Operators /*! From 87214db4d1936ba1fcf28cc9820671f9c52fe25f Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 12:40:47 +0100 Subject: [PATCH 0059/1783] Adding handling of YOrthogonal in populateStencil This is currently a bit ugly and enforces `nGuard == 1` even for Field2D which could in principle use more than one guard cell. --- include/stencils.hxx | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/include/stencils.hxx b/include/stencils.hxx index 24555d2933..6d98563e35 100644 --- a/include/stencils.hxx +++ b/include/stencils.hxx @@ -43,27 +43,54 @@ void inline populateStencil(stencil &s, const FieldType& f, const typename Field static_assert(nGuard == 1 || nGuard == 2, "populateStencil currently only supports one or two guard cells" ); - + static_assert(direction != DIRECTION::YOrthogonal || nGuard == 1, + "Orthogonal Y currently only supports one guard cell" + ); + switch(stagger) { case(STAGGER::None): if (nGuard == 2) s.mm = f[i.template minus<2, direction>()]; - s.m = f[i.template minus<1, direction>()]; + if (direction == DIRECTION::YOrthogonal) { + s.m = f.ydown()[i.template minus<1, direction>()]; + } else { + s.m = f[i.template minus<1, direction>()]; + } s.c = f[i]; - s.p = f[i.template plus<1, direction>()]; + if (direction == DIRECTION::YOrthogonal) { + s.p = f.yup()[i.template plus<1, direction>()]; + } else { + s.p = f[i.template plus<1, direction>()]; + } if (nGuard == 2) s.pp = f[i.template plus<2, direction>()]; break; case(STAGGER::C2L): if (nGuard == 2) s.mm = f[i.template minus<2, direction>()]; - s.m = f[i.template minus<1, direction>()]; + if (direction == DIRECTION::YOrthogonal) { + s.m = f.ydown()[i.template minus<1, direction>()]; + } else { + s.m = f[i.template minus<1, direction>()]; + } s.c = f[i]; s.p = s.c; - s.pp = f[i.template plus<1, direction>()]; + if (direction == DIRECTION::YOrthogonal) { + s.pp = f.yup()[i.template plus<1, direction>()]; + } else { + s.pp = f[i.template plus<1, direction>()]; + } break; case(STAGGER::L2C): - s.mm = f[i.template minus<1, direction>()]; + if (direction == DIRECTION::YOrthogonal) { + s.mm = f.ydown()[i.template minus<1, direction>()]; + } else { + s.mm = f[i.template minus<1, direction>()]; + } s.m = f[i]; s.c = s.m; - s.p = f[i.template plus<1, direction>()]; + if (direction == DIRECTION::YOrthogonal) { + s.p = f.yup()[i.template plus<1, direction>()]; + } else { + s.p = f[i.template plus<1, direction>()]; + } if (nGuard == 2) s.pp = f[i.template plus<2, direction>()]; break; } @@ -72,9 +99,6 @@ void inline populateStencil(stencil &s, const FieldType& f, const typename Field template stencil inline populateStencil(const FieldType& f, const typename FieldType::ind_type i){ - static_assert(nGuard == 1 || nGuard == 2, - "populateStencil currently only supports one or two guard cells" - ); stencil s; populateStencil(s, f, i); return s; From 21c38dac0c93d1de92153ece183c6c0687bfbbcd Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 12:55:03 +0100 Subject: [PATCH 0060/1783] Make use of applyYdiff in index_derivs --- src/mesh/index_derivs.cxx | 133 ++++++++++++++------------------------ 1 file changed, 47 insertions(+), 86 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index b8cb1c1110..e81449499e 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -888,12 +888,7 @@ const Field2D Mesh::applyYdiff(const Field2D &var, Mesh::deriv_func func, CELL_L { stencil s; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - s.mm = var[i.ymm()]; - s.m = var[i.ym()]; - s.c = var[i]; - s.p = var[i.yp()]; - s.pp = var[i.ypp()]; - + populateStencil(s, var, i); result[i] = func(s); } } @@ -902,10 +897,7 @@ const Field2D Mesh::applyYdiff(const Field2D &var, Mesh::deriv_func func, CELL_L { stencil s; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - s.m = var[i.ym()]; - s.c = var[i]; - s.p = var[i.yp()]; - + populateStencil(s, var, i); result[i] = func(s); } } @@ -953,28 +945,21 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L if (this->StaggerGrids && (outloc != inloc)) { // Staggered differencing - - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - - // Set stencils - s.m = var.ydown()[i.ym()]; - s.c = var[i]; - s.p = var.yup()[i.yp()]; - - if (outloc == CELL_YLOW) { - // Producing a stencil centred around a lower Y value - s.pp = s.p; - s.p = s.c; - } else if (inloc == CELL_YLOW) { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; + if (outloc == CELL_YLOW) { + BOUT_OMP(parallel) { + stencil s; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(s, var, i); + result[i] = func(s); + } + } + } else { + BOUT_OMP(parallel) { + stencil s; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(s, var, i); + result[i] = func(s); } - - result[i] = func(s); } } } else { @@ -984,10 +969,7 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L stencil s; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { // Set stencils - s.m = var.ydown()[i.ym()]; - s.c = var[i]; - s.p = var.yup()[i.yp()]; - + populateStencil(s, var, i); result[i] = func(s); } } @@ -1003,50 +985,40 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L if (this->ystart > 1) { // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - // Set stencils - s.mm = var_fa[i.ymm()]; - s.m = var_fa[i.ym()]; - s.c = var_fa[i]; - s.p = var_fa[i.yp()]; - s.pp = var_fa[i.ypp()]; - - if (outloc == CELL_YLOW) { - // Producing a stencil centred around a lower Y value - s.pp = s.p; - s.p = s.c; - } else if (inloc == CELL_YLOW) { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; + if (outloc == CELL_YLOW) { + BOUT_OMP(parallel) { + stencil s; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(s, var_fa, i); + result[i] = func(s); + } + } + } else { + BOUT_OMP(parallel) { + stencil s; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(s, var_fa, i); + result[i] = func(s); } - - result[i] = func(s); } } } else { // Only one guard cell, so no pp or mm values - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - // Set stencils - s.m = var_fa[i.ym()]; - s.c = var_fa[i]; - s.p = var_fa[i.yp()]; - - if (outloc == CELL_YLOW) { - // Producing a stencil centred around a lower Y value - s.pp = s.p; - s.p = s.c; - } else if (inloc == CELL_YLOW) { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; + if (outloc == CELL_YLOW) { + BOUT_OMP(parallel) { + stencil s; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(s, var_fa, i); + result[i] = func(s); + } + } + } else { + BOUT_OMP(parallel) { + stencil s; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(s, var_fa, i); + result[i] = func(s); } - - result[i] = func(s); } } } @@ -1059,13 +1031,7 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L BOUT_OMP(parallel) { stencil s; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - // Set stencils - s.mm = var_fa[i.ymm()]; - s.m = var_fa[i.ym()]; - s.c = var_fa[i]; - s.p = var_fa[i.yp()]; - s.pp = var_fa[i.ypp()]; - + populateStencil(s, var_fa, i); result[i] = func(s); } } @@ -1074,11 +1040,7 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L BOUT_OMP(parallel) { stencil s; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - // Set stencils - s.m = var_fa[i.ym()]; - s.c = var_fa[i]; - s.p = var_fa[i.yp()]; - + populateStencil(s, var_fa, i); result[i] = func(s); } } @@ -1086,7 +1048,6 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L } // Shift result back - result = this->fromFieldAligned(result); } From 4da80699530e2f713603d9a4eba663e6e6fee18c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 13:01:54 +0100 Subject: [PATCH 0061/1783] Make use of populateStencil in applyZdiff --- src/mesh/index_derivs.cxx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index e81449499e..8bca7f21f3 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -1093,12 +1093,7 @@ const Field3D Mesh::applyZdiff(const Field3D &var, Mesh::deriv_func func, CELL_L { stencil s; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - s.mm = var[i.zmm()]; - s.m = var[i.zm()]; - s.c = var[i]; - s.p = var[i.zp()]; - s.pp = var[i.zpp()]; - + populateStencil(s, var, i); result[i] = func(s); } } From 5ad90dd93f58e05b1eec072ef0fb3fe2e34e08ca Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 14:27:28 +0100 Subject: [PATCH 0062/1783] Make use of populateStencil in indexVDD? routines --- src/mesh/index_derivs.cxx | 275 +++++++++++--------------------------- 1 file changed, 76 insertions(+), 199 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 8bca7f21f3..8634abe5d1 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -1656,12 +1656,7 @@ const Field2D Mesh::indexVDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil s; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - s.mm = f[i.xmm()]; - s.m = f[i.xm()]; - s.c = f[i]; - s.p = f[i.xp()]; - s.pp = f[i.xpp()]; - + populateStencil(s, f, i); result[i] = func(v[i], s); } } @@ -1671,10 +1666,7 @@ const Field2D Mesh::indexVDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil s; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - s.m = f[i.xm()]; - s.c = f[i]; - s.p = f[i.xp()]; - + populateStencil(s, f, i); result[i] = func(v[i], s); } } @@ -1740,17 +1732,8 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fs.mm = f[i.xmm()]; - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - fs.pp = f[i.xpp()]; - - vs.mm = v[i.xm()]; - vs.m = v[i]; - vs.p = v[i.xp()]; - vs.pp = v[i.xpp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -1759,17 +1742,8 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fs.mm = f[i.xmm()]; - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - fs.pp = f[i.xpp()]; - - vs.mm = v[i.xmm()]; - vs.m = v[i.xm()]; - vs.p = v[i]; - vs.pp = v[i.xp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -1781,14 +1755,8 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - - vs.mm = v[i.xm()]; - vs.m = v[i]; - vs.p = v[i.xp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -1797,14 +1765,8 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - - vs.m = v[i.xm()]; - vs.p = v[i]; - vs.pp = v[i.xp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -1826,12 +1788,7 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fs.mm = f[i.xmm()]; - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - fs.pp = f[i.xpp()]; - + populateStencil(fs, f, i); result[i] = func(v[i], fs); } } @@ -1840,10 +1797,7 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - + populateStencil(fs, f, i); result[i] = func(v[i], fs); } } @@ -1916,17 +1870,8 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - fs.mm = f[i.ymm()]; - fs.m = f[i.ym()]; - fs.c = f[i]; - fs.p = f[i.yp()]; - fs.pp = f[i.ypp()]; - - vs.mm = v[i.ym()]; - vs.m = v[i]; - vs.p = v[i.yp()]; - vs.pp = v[i.ypp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -1935,14 +1880,8 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - fs.m = f[i.ym()]; - fs.c = f[i]; - fs.p = f[i.yp()]; - - vs.mm = v[i.ym()]; - vs.m = v[i]; - vs.p = v[i.yp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -1953,17 +1892,8 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - fs.mm = f[i.ymm()]; - fs.m = f[i.ym()]; - fs.c = f[i]; - fs.p = f[i.yp()]; - fs.pp = f[i.ypp()]; - - vs.mm = v[i.ymm()]; - vs.m = v[i.ym()]; - vs.p = v[i]; - vs.pp = v[i.yp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -1972,14 +1902,8 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - fs.m = f[i.ym()]; - fs.c = f[i]; - fs.p = f[i.yp()]; - - vs.m = v[i.ym()]; - vs.p = v[i]; - vs.pp = v[i.yp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -2002,12 +1926,7 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - fs.mm = f[i.ymm()]; - fs.m = f[i.ym()]; - fs.c = f[i]; - fs.p = f[i.yp()]; - fs.pp = f[i.ypp()]; - + populateStencil(fs, f, i); result[i] = func(v[i], fs); } } @@ -2016,10 +1935,7 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - fs.m = f[i.ym()]; - fs.c = f[i]; - fs.p = f[i.yp()]; - + populateStencil(fs, f, i); result[i] = func(v[i], fs); } } @@ -2093,60 +2009,46 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo if (vUseUpDown && fUseUpDown) { // Both v and f have up/down fields - BOUT_OMP(parallel) { - stencil vval, fval; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - vval.m = v.ydown()[i.ym()]; - vval.c = v[i]; - vval.p = v.yup()[i.yp()]; - - fval.m = f.ydown()[i.ym()]; - fval.c = f[i]; - fval.p = f.yup()[i.yp()]; - - // Non-centred stencil - if (inloc == CELL_YLOW) { - // Producing a stencil centred around a lower Y value - vval.pp = vval.p; - vval.p = vval.c; - } else { - // Stencil centred around a cell centre - vval.mm = vval.m; - vval.m = vval.c; + if (inloc == CELL_YLOW) { + BOUT_OMP(parallel) { + stencil vval, fval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f, i); + populateStencil(vval, v, i); + result[i] = func(vval, fval); + } + } + } else { + BOUT_OMP(parallel) { + stencil vval, fval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f, i); + populateStencil(vval, v, i); + result[i] = func(vval, fval); } - result[i] = func(vval, fval); } } } else { // Both must shift to field aligned Field3D v_fa = this->toFieldAligned(v); Field3D f_fa = this->toFieldAligned(f); - BOUT_OMP(parallel) { - stencil vval, fval; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - vval.mm = v_fa[i.ymm()]; - vval.m = v_fa[i.ym()]; - vval.c = v_fa[i]; - vval.p = v_fa[i.yp()]; - vval.pp = v_fa[i.ypp()]; - - fval.mm = f_fa[i.ymm()]; - fval.m = f_fa[i.ym()]; - fval.c = f[i]; - fval.p = f_fa[i.yp()]; - fval.pp = f_fa[i.ypp()]; - - // Non-centred stencil - if (inloc == CELL_YLOW) { - // Producing a stencil centred around a lower Y value - vval.pp = vval.p; - vval.p = vval.c; - } else { - // Stencil centred around a cell centre - vval.mm = vval.m; - vval.m = vval.c; + if (inloc == CELL_YLOW) { + BOUT_OMP(parallel) { + stencil vval, fval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f_fa, i); + populateStencil(vval, v_fa, i); + result[i] = func(vval, fval); + } + } + } else { + BOUT_OMP(parallel) { + stencil vval, fval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f_fa, i); + populateStencil(vval, v_fa, i); + result[i] = func(vval, fval); } - result[i] = func(vval, fval); } } } @@ -2163,15 +2065,10 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo if (f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))) { // f has yup and ydown fields which are distinct - const Field3D f_yup = f.yup(); - const Field3D f_ydown = f.ydown(); BOUT_OMP(parallel) { stencil fs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fs.m = f_ydown[i.ym()]; - fs.c = f[i]; - fs.p = f_yup[i.yp()]; - + populateStencil(fs, f, i); result[i] = func(v[i], fs); } } @@ -2184,12 +2081,7 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fs.mm = f_fa[i.ymm()]; - fs.m = f_fa[i.ym()]; - fs.c = f_fa[i]; - fs.p = f_fa[i.yp()]; - fs.pp = f_fa[i.ypp()]; - + populateStencil(fs, f_fa, i); result[i] = func(v_fa[i], fs); } } @@ -2197,10 +2089,7 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fs.m = f_fa[i.ym()]; - fs.c = f_fa[i]; - fs.p = f_fa[i.yp()]; - + populateStencil(fs, f_fa, i); result[i] = func(v_fa[i], fs); } } @@ -2260,32 +2149,25 @@ const Field3D Mesh::indexVDDZ(const Field3D &v, const Field3D &f, CELL_LOC outlo func = lookupFunc(table, method); } - BOUT_OMP(parallel) { - stencil vval, fval; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fval.mm = f[i.zmm()]; - fval.m = f[i.zm()]; - fval.c = f[i]; - fval.p = f[i.zp()]; - fval.pp = f[i.zpp()]; - - vval.mm = v[i.zmm()]; - vval.m = v[i.zm()]; - vval.c = v[i]; - vval.p = v[i.zp()]; - vval.pp = v[i.zpp()]; - - if (inloc == CELL_ZLOW) { - // Producing a stencil centred around a lower Z value - vval.pp = vval.p; - vval.p = vval.c; - - } else { - // Stencil centred around a cell centre - vval.mm = vval.m; - vval.m = vval.c; + if (inloc == CELL_ZLOW) { + // Producing a stencil centred around a lower Z value + BOUT_OMP(parallel) { + stencil vval, fval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f, i); + populateStencil(vval, v, i); + result[i] = func(vval, fval); + } + } + } else { + // Stencil centred around a cell centre + BOUT_OMP(parallel) { + stencil vval, fval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f, i); + populateStencil(vval, v, i); + result[i] = func(vval, fval); } - result[i] = func(vval, fval); } } } else { @@ -2300,12 +2182,7 @@ const Field3D Mesh::indexVDDZ(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fval; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fval.mm = f[i.zmm()]; - fval.m = f[i.zm()]; - fval.c = f[i]; - fval.p = f[i.zp()]; - fval.pp = f[i.zpp()]; - + populateStencil(fval, f, i); result[i] = func(v[i], fval); } } From 8d4da0743c13f60d53f3b26e2809e556070b2254 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 14:53:32 +0100 Subject: [PATCH 0063/1783] Make use of populateStencil in indexFDD? routines --- src/mesh/index_derivs.cxx | 283 ++++++++++++++------------------------ 1 file changed, 103 insertions(+), 180 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 8634abe5d1..c90e234032 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -2239,18 +2239,8 @@ const Field2D Mesh::indexFDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - fs.mm = f[i.xmm()]; - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - fs.pp = f[i.xpp()]; - - vs.mm = v[i.xmm()]; - vs.m = v[i.xm()]; - vs.c = v[i]; - vs.p = v[i.xp()]; - vs.pp = v[i.xpp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -2259,14 +2249,8 @@ const Field2D Mesh::indexFDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - - vs.m = v[i.xm()]; - vs.c = v[i]; - vs.p = v[i.xp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -2334,18 +2318,8 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { // Location of f always the same as the output - fs.mm = f[i.xmm()]; - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - fs.pp = f[i.xpp()]; - - // Note: Location in diffloc - vs.mm = v[i.xmm()]; - vs.m = v[i.xm()]; - vs.p = v[i]; - vs.pp = v[i.xp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -2355,17 +2329,8 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { // Location of f always the same as the output - fs.mm = f[i.xmm()]; - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - fs.pp = f[i.xpp()]; - - vs.mm = v[i.xm()]; - vs.m = v[i]; - vs.p = v[i.xp()]; - vs.pp = v[i.xpp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -2375,20 +2340,8 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - // Location of f always the same as the output - fs.mm = f[i.xmm()]; - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - fs.pp = f[i.xpp()]; - - // Note: Location in diffloc - vs.mm = v[i.xmm()]; - vs.m = v[i.xm()]; - vs.c = v[i]; - vs.p = v[i.xp()]; - vs.pp = v[i.xpp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -2401,16 +2354,8 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - // Location of f always the same as the output - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - - // Note: Location in diffloc - vs.m = v[i.xm()]; - vs.p = v[i]; - vs.pp = v[i.xp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -2419,15 +2364,8 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - // Location of f always the same as the output - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - - vs.mm = v[i.xm()]; - vs.m = v[i]; - vs.p = v[i.xp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -2437,15 +2375,8 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - // Location of f always the same as the output - fs.m = f[i.xm()]; - fs.c = f[i]; - fs.p = f[i.xp()]; - - vs.m = v[i.xm()]; - vs.c = v[i]; - vs.p = v[i.xp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -2501,18 +2432,8 @@ const Field2D Mesh::indexFDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - fs.mm = f[i.ymm()]; - fs.m = f[i.ym()]; - fs.c = f[i]; - fs.p = f[i.yp()]; - fs.pp = f[i.ypp()]; - - vs.mm = v[i.ymm()]; - vs.m = v[i.ym()]; - vs.c = v[i]; - vs.p = v[i.yp()]; - vs.pp = v[i.ypp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -2522,14 +2443,8 @@ const Field2D Mesh::indexFDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fs, vs; BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - fs.m = f[i.ym()]; - fs.c = f[i]; - fs.p = f[i.yp()]; - - vs.m = v[i.ym()]; - vs.c = v[i]; - vs.p = v[i.yp()]; - + populateStencil(fs, f, i); + populateStencil(vs, v, i); result[i] = func(vs, fs); } } @@ -2603,64 +2518,69 @@ const Field3D Mesh::indexFDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo if (vUseUpDown && fUseUpDown) { // Both v and f have up/down fields - BOUT_OMP(parallel) { - stencil fval, vval; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fval.m = f.ydown()[i.ym()]; - fval.c = f[i]; - fval.p = f.yup()[i.yp()]; - - vval.m = v.ydown()[i.ym()]; - vval.c = v[i]; - vval.p = v.yup()[i.yp()]; - - if (StaggerGrids && (inloc != vloc)) { - // Non-centred stencil - if (inloc == CELL_YLOW) { - // Producing a stencil centred around a lower Y value - vval.pp = vval.p; - vval.p = vval.c; - } else { - // Stencil centred around a cell centre - vval.mm = vval.m; - vval.m = vval.c; + if (StaggerGrids && (inloc != vloc)) { + if (inloc == CELL_YLOW) { + BOUT_OMP(parallel) { + stencil fval, vval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f, i); + populateStencil(vval, v, i); + result[i] = func(vval, fval); } } - result[i] = func(vval, fval); + } else { + BOUT_OMP(parallel) { + stencil fval, vval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f, i); + populateStencil(vval, v, i); + result[i] = func(vval, fval); + } + } + } + } else { + BOUT_OMP(parallel) { + stencil fval, vval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f, i); + populateStencil(vval, v, i); + result[i] = func(vval, fval); + } } } } else { // Both must shift to field aligned Field3D v_fa = this->toFieldAligned(v); Field3D f_fa = this->toFieldAligned(f); - BOUT_OMP(parallel) { - stencil fval, vval; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fval.mm = f_fa[i.ymm()]; - fval.m = f_fa[i.ym()]; - fval.c = f_fa[i]; - fval.p = f_fa[i.yp()]; - fval.pp = f_fa[i.ypp()]; - - vval.mm = v_fa[i.ymm()]; - vval.m = v_fa[i.ym()]; - vval.c = v_fa[i]; - vval.p = v_fa[i.yp()]; - vval.pp = v_fa[i.ypp()]; - - if (StaggerGrids && (inloc != vloc)) { - // Non-centred stencil - if (inloc == CELL_YLOW) { - // Producing a stencil centred around a lower Y value - vval.pp = vval.p; - vval.p = vval.c; - } else { - // Stencil centred around a cell centre - vval.mm = vval.m; - vval.m = vval.c; + if (StaggerGrids && (inloc != vloc)) { + // Non-centred stencil + if (inloc == CELL_YLOW) { + BOUT_OMP(parallel) { + stencil fval, vval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f_fa, i); + populateStencil(vval, v_fa, i); + result[i] = func(vval, fval); } } - result[i] = func(vval, fval); + } else { + BOUT_OMP(parallel) { + stencil fval, vval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f_fa, i); + populateStencil(vval, v_fa, i); + result[i] = func(vval, fval); + } + } + } + } else { + BOUT_OMP(parallel) { + stencil fval, vval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f_fa, i); + populateStencil(vval, v_fa, i); + result[i] = func(vval, fval); + } } } } @@ -2721,37 +2641,40 @@ const Field3D Mesh::indexFDDZ(const Field3D &v, const Field3D &f, CELL_LOC outlo /// Convert REGION enum to a Region string identifier const auto region_str = REGION_STRING(region); - BOUT_OMP(parallel) { - stencil vval, fval; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { - fval.mm = f[i.zmm()]; - fval.m = f[i.zm()]; - fval.c = f[i]; - fval.p = f[i.zp()]; - fval.pp = f[i.zpp()]; - - vval.mm = v[i.zmm()]; - vval.m = v[i.zm()]; - vval.c = v[i]; - vval.p = v[i.zp()]; - vval.pp = v[i.zpp()]; - - if (StaggerGrids && (inloc != vloc)) { - // Non-centred stencil - - if (inloc == CELL_ZLOW) { - // Producing a stencil centred around a lower Z value - vval.pp = vval.p; - vval.p = vval.c; - } else { - // Stencil centred around a cell centre - vval.mm = vval.m; - vval.m = vval.c; + if (StaggerGrids && (inloc != vloc)) { + // Non-centred stencil + + if (inloc == CELL_ZLOW) { + // Producing a stencil centred around a lower Z value + BOUT_OMP(parallel) { + stencil vval, fval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f, i); + populateStencil(vval, v, i); + result[i] = func(vval, fval); + } + } + } else { + BOUT_OMP(parallel) { + stencil vval, fval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f, i); + populateStencil(vval, v, i); + result[i] = func(vval, fval); } } - result[i] = func(vval, fval); + } + } else { + BOUT_OMP(parallel) { + stencil vval, fval; + BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + populateStencil(fval, f, i); + populateStencil(vval, v, i); + result[i] = func(vval, fval); + } } } + result.setLocation(outloc); #if CHECK > 0 From 581d1c2c6f6110ff3383dd4a9ad9928e1191e021 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 11 Oct 2018 16:19:09 +0100 Subject: [PATCH 0064/1783] Provide `getRegion` method on Fields to return the requested Region from fieldmesh --- include/field2d.hxx | 4 ++++ include/field3d.hxx | 4 ++++ include/fieldperp.hxx | 4 ++++ src/field/field2d.cxx | 7 +++++++ src/field/field3d.cxx | 7 +++++++ src/field/fieldperp.cxx | 7 +++++++ 6 files changed, 33 insertions(+) diff --git a/include/field2d.hxx b/include/field2d.hxx index b261ca8456..51e14607ab 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -154,6 +154,10 @@ class Field2D : public Field, public FieldData { */ const IndexRange DEPRECATED(region(REGION rgn)) const override; + /// Return a Region reference to use to iterate over this field + const Region& getRegion(REGION region) const; + const Region& getRegion(const std::string ®ion_name) const; + BoutReal& operator[](const Ind2D &d) { return data[d.ind]; } diff --git a/include/field3d.hxx b/include/field3d.hxx index bd085f7c73..1025f935ab 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -328,6 +328,10 @@ class Field3D : public Field, public FieldData { */ const IndexRange DEPRECATED(region2D(REGION rgn)) const; + /// Return a Region reference to use to iterate over this field + const Region& getRegion(REGION region) const; + const Region& getRegion(const std::string ®ion_name) const; + /*! * Direct data access using DataIterator object. * This uses operator(x,y,z) so checks will only be diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 8fef875e8a..90fdcf03d8 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -91,6 +91,10 @@ class FieldPerp : public Field { const IndexRange DEPRECATED(region(REGION rgn)) const override; + /// Return a Region reference to use to iterate over this field + const Region& getRegion(REGION region) const; + const Region& getRegion(const std::string ®ion_name) const; + /*! * Direct data access using DataIterator indexing */ diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index c7859f1d46..ad44b43a1b 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -179,6 +179,13 @@ const IndexRange Field2D::region(REGION rgn) const { }; } +const Region &Field2D::getRegion(REGION region) const { + return fieldmesh->getRegion2D(REGION_STRING(region)); +}; +const Region &Field2D::getRegion(const std::string ®ion_name) const { + return fieldmesh->getRegion2D(region_name); +}; + void Field2D::setLocation(CELL_LOC new_location) { if (getMesh()->StaggerGrids) { if (new_location == CELL_VSHIFT) { diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index c62900285a..1143eb9fdc 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -355,6 +355,13 @@ const IndexRange Field3D::region2D(REGION rgn) const { }; } +const Region &Field3D::getRegion(REGION region) const { + return fieldmesh->getRegion3D(REGION_STRING(region)); +}; +const Region &Field3D::getRegion(const std::string ®ion_name) const { + return fieldmesh->getRegion3D(region_name); +}; + /////////////////// ASSIGNMENT //////////////////// Field3D & Field3D::operator=(const Field3D &rhs) { diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 856b6c0272..5bd7765e91 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -215,6 +215,13 @@ const IndexRange FieldPerp::region(REGION rgn) const { }; } +const Region &FieldPerp::getRegion(REGION region) const { + return fieldmesh->getRegionPerp(REGION_STRING(region)); +}; +const Region &FieldPerp::getRegion(const std::string ®ion_name) const { + return fieldmesh->getRegionPerp(region_name); +}; + //////////////// NON-MEMBER FUNCTIONS ////////////////// ////////////// NON-MEMBER OVERLOADED OPERATORS ////////////// From 753a3b1a7a341fe4b139ecd2204760ec6ac77e00 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 12 Oct 2018 09:59:38 +0100 Subject: [PATCH 0065/1783] Use `this` rather than `mesh` in Mesh member function --- src/mesh/index_derivs.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index d872b70ab4..7ee18db5d4 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -1341,8 +1341,8 @@ const Field3D Mesh::indexDDZ(const Field3D &f, CELL_LOC outloc, // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro // here, // but should be ok for now. - BOUT_FOR_INNER(i, mesh->getRegion2D(region_str)) { - auto i3D = mesh->ind2Dto3D(i, 0); + BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + auto i3D = this->ind2Dto3D(i, 0); rfft(&f[i3D], ncz, cv.begin()); // Forward FFT for (int jz = 0; jz <= kmax; jz++) { @@ -1598,8 +1598,8 @@ const Field3D Mesh::indexD2DZ2(const Field3D &f, CELL_LOC outloc, // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro // here, // but should be ok for now. - BOUT_FOR_INNER(i, mesh->getRegion2D(region_str)) { - auto i3D = mesh->ind2Dto3D(i, 0); + BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + auto i3D = this->ind2Dto3D(i, 0); rfft(&f[i3D], ncz, cv.begin()); // Forward FFT From db125e1a6441ce7fdfef80b8030cbc36d6ddd07c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 12 Oct 2018 09:59:57 +0100 Subject: [PATCH 0066/1783] Replace `this->getRegion?D(region_str)` with `field->getRegion(region)` in index_derivs. Makes it clearer that the region is associated with iterating over the field. Removes one point of difference between 2D and 3D versions of index_deriv routines. --- src/mesh/index_derivs.cxx | 144 ++++++++++++++------------------------ 1 file changed, 51 insertions(+), 93 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 7ee18db5d4..2c3760e083 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -656,9 +656,6 @@ const Field2D Mesh::applyXdiff(const Field2D &var, Mesh::deriv_func func, tmp.setLocation(var.getLocation()); return tmp; } - - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); Field2D result(this); result.allocate(); // Make sure data allocated @@ -672,7 +669,7 @@ const Field2D Mesh::applyXdiff(const Field2D &var, Mesh::deriv_func func, BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { s.mm = var[i.xmm()]; s.m = var[i.xm()]; s.c = var[i]; @@ -697,7 +694,7 @@ const Field2D Mesh::applyXdiff(const Field2D &var, Mesh::deriv_func func, BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { s.m = var[i.xm()]; s.c = var[i]; s.p = var[i.xp()]; @@ -726,7 +723,7 @@ const Field2D Mesh::applyXdiff(const Field2D &var, Mesh::deriv_func func, BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { s.mm = var[i.xmm()]; s.m = var[i.xm()]; s.c = var[i]; @@ -741,7 +738,7 @@ const Field2D Mesh::applyXdiff(const Field2D &var, Mesh::deriv_func func, BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { s.m = var[i.xm()]; s.c = var[i]; s.p = var[i.xp()]; @@ -782,9 +779,6 @@ const Field3D Mesh::applyXdiff(const Field3D &var, Mesh::deriv_func func, return tmp; } - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - Field3D result(this); result.allocate(); // Make sure data allocated @@ -797,7 +791,7 @@ const Field3D Mesh::applyXdiff(const Field3D &var, Mesh::deriv_func func, BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { s.mm = var[i.xmm()]; s.m = var[i.xm()]; s.c = var[i]; @@ -822,7 +816,7 @@ const Field3D Mesh::applyXdiff(const Field3D &var, Mesh::deriv_func func, BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { s.m = var[i.xm()]; s.c = var[i]; s.p = var[i.xp()]; @@ -851,7 +845,7 @@ const Field3D Mesh::applyXdiff(const Field3D &var, Mesh::deriv_func func, BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { s.mm = var[i.xmm()]; s.m = var[i.xm()]; s.c = var[i]; @@ -866,7 +860,7 @@ const Field3D Mesh::applyXdiff(const Field3D &var, Mesh::deriv_func func, BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { s.m = var[i.xm()]; s.c = var[i]; s.p = var[i.xp()]; @@ -906,9 +900,6 @@ const Field2D Mesh::applyYdiff(const Field2D &var, Mesh::deriv_func func, CELL_L tmp.setLocation(var.getLocation()); return tmp; } - - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); Field2D result(this); result.allocate(); // Make sure data allocated @@ -919,7 +910,7 @@ const Field2D Mesh::applyYdiff(const Field2D &var, Mesh::deriv_func func, CELL_L BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { s.mm = var[i.ymm()]; s.m = var[i.ym()]; s.c = var[i]; @@ -933,7 +924,7 @@ const Field2D Mesh::applyYdiff(const Field2D &var, Mesh::deriv_func func, CELL_L BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { s.m = var[i.ym()]; s.c = var[i]; s.p = var[i.yp()]; @@ -989,7 +980,7 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { // Set stencils s.m = var.ydown()[i.ym()]; @@ -1014,7 +1005,7 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { // Set stencils s.m = var.ydown()[i.ym()]; s.c = var[i]; @@ -1037,7 +1028,7 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L // This allows higher-order methods to be used BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { // Set stencils s.mm = var_fa[i.ymm()]; s.m = var_fa[i.ym()]; @@ -1062,7 +1053,7 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L // Only one guard cell, so no pp or mm values BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { // Set stencils s.m = var_fa[i.ym()]; s.c = var_fa[i]; @@ -1090,7 +1081,7 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L // This allows higher-order methods to be used BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { // Set stencils s.mm = var_fa[i.ymm()]; s.m = var_fa[i.ym()]; @@ -1105,7 +1096,7 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L // Only one guard cell, so no pp or mm values BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { // Set stencils s.m = var_fa[i.ym()]; s.c = var_fa[i]; @@ -1151,9 +1142,6 @@ const Field3D Mesh::applyZdiff(const Field3D &var, Mesh::deriv_func func, CELL_L return tmp; } - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - Field3D result(this); result.allocate(); // Make sure data allocated @@ -1163,7 +1151,7 @@ const Field3D Mesh::applyZdiff(const Field3D &var, Mesh::deriv_func func, CELL_L BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, var.getRegion(region)) { s.mm = var[i.zmm()]; s.m = var[i.zm()]; s.c = var[i]; @@ -1721,9 +1709,6 @@ const Field2D Mesh::indexVDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo ASSERT1(this == f.getMesh()); ASSERT1(this == v.getMesh()); - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - Field2D result(this); result.allocate(); // Make sure data allocated @@ -1731,7 +1716,7 @@ const Field2D Mesh::indexVDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo // Two or more guard cells BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { s.mm = f[i.xmm()]; s.m = f[i.xm()]; s.c = f[i]; @@ -1746,7 +1731,7 @@ const Field2D Mesh::indexVDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo // Only one guard cell BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { s.m = f[i.xm()]; s.c = f[i]; s.p = f[i.xp()]; @@ -1788,9 +1773,6 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo Field3D result(this); result.allocate(); // Make sure data allocated - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - if (StaggerGrids && (vloc != inloc)) { // Staggered grids enabled, and velocity at different location to value @@ -1815,7 +1797,7 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo if (vloc == CELL_XLOW) { BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.mm = f[i.xmm()]; fs.m = f[i.xm()]; fs.c = f[i]; @@ -1834,7 +1816,7 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo } else { BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.mm = f[i.xmm()]; fs.m = f[i.xm()]; fs.c = f[i]; @@ -1856,7 +1838,7 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo if (vloc == CELL_XLOW) { BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.m = f[i.xm()]; fs.c = f[i]; fs.p = f[i.xp()]; @@ -1872,7 +1854,7 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo } else { BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.m = f[i.xm()]; fs.c = f[i]; fs.p = f[i.xp()]; @@ -1901,7 +1883,7 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo // Two or more guard cells BOUT_OMP(parallel) { stencil fs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.mm = f[i.xmm()]; fs.m = f[i.xm()]; fs.c = f[i]; @@ -1915,7 +1897,7 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo // Only one guard cell BOUT_OMP(parallel) { stencil fs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.m = f[i.xm()]; fs.c = f[i]; fs.p = f[i.xp()]; @@ -1966,9 +1948,6 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo ASSERT1(this->ystart > 0); // Must have at least one guard cell - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - if (StaggerGrids && (vloc != inloc)) { // Staggered grids enabled, and velocity at different location to value @@ -1991,7 +1970,7 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo // Two or more guard cells BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.mm = f[i.ymm()]; fs.m = f[i.ym()]; fs.c = f[i]; @@ -2010,7 +1989,7 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo // Only one guard cell BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.m = f[i.ym()]; fs.c = f[i]; fs.p = f[i.yp()]; @@ -2028,7 +2007,7 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo // Two or more guard cells BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.mm = f[i.ymm()]; fs.m = f[i.ym()]; fs.c = f[i]; @@ -2047,7 +2026,7 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo // Only one guard cell BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.m = f[i.ym()]; fs.c = f[i]; fs.p = f[i.yp()]; @@ -2077,7 +2056,7 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo // Two or more guard cells BOUT_OMP(parallel) { stencil fs; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.mm = f[i.ymm()]; fs.m = f[i.ym()]; fs.c = f[i]; @@ -2091,7 +2070,7 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo // Only one guard cell BOUT_OMP(parallel) { stencil fs; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.m = f[i.ym()]; fs.c = f[i]; fs.p = f[i.yp()]; @@ -2140,9 +2119,6 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo ASSERT1(this->ystart > 0); // Need at least one guard cell - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - if (StaggerGrids && (vloc != inloc)) { // Staggered grids enabled, and velocity at different location to value @@ -2171,7 +2147,7 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo // Both v and f have up/down fields BOUT_OMP(parallel) { stencil vval, fval; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { vval.m = v.ydown()[i.ym()]; vval.c = v[i]; vval.p = v.yup()[i.yp()]; @@ -2199,7 +2175,7 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo Field3D f_fa = this->toFieldAligned(f); BOUT_OMP(parallel) { stencil vval, fval; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { vval.mm = v_fa[i.ymm()]; vval.m = v_fa[i.ym()]; vval.c = v_fa[i]; @@ -2243,7 +2219,7 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo const Field3D f_ydown = f.ydown(); BOUT_OMP(parallel) { stencil fs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.m = f_ydown[i.ym()]; fs.c = f[i]; fs.p = f_yup[i.yp()]; @@ -2259,7 +2235,7 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo if (this->ystart > 1) { BOUT_OMP(parallel) { stencil fs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.mm = f_fa[i.ymm()]; fs.m = f_fa[i.ym()]; fs.c = f_fa[i]; @@ -2272,7 +2248,7 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo } else { BOUT_OMP(parallel) { stencil fs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.m = f_fa[i.ym()]; fs.c = f_fa[i]; fs.p = f_fa[i.yp()]; @@ -2318,9 +2294,6 @@ const Field3D Mesh::indexVDDZ(const Field3D &v, const Field3D &f, CELL_LOC outlo Field3D result(this); result.allocate(); // Make sure data allocated - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - if (StaggerGrids && (vloc != inloc)) { // Staggered grids enabled, and velocity at different location to value @@ -2338,7 +2311,7 @@ const Field3D Mesh::indexVDDZ(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil vval, fval; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fval.mm = f[i.zmm()]; fval.m = f[i.zm()]; fval.c = f[i]; @@ -2375,7 +2348,7 @@ const Field3D Mesh::indexVDDZ(const Field3D &v, const Field3D &f, CELL_LOC outlo BOUT_OMP(parallel) { stencil fval; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fval.mm = f[i.zmm()]; fval.m = f[i.zm()]; fval.c = f[i]; @@ -2430,14 +2403,11 @@ const Field2D Mesh::indexFDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo ASSERT1(this == v.getMesh()); ASSERT1(this == f.getMesh()); - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - if (this->xstart > 1) { // Two or more guard cells BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.mm = f[i.xmm()]; fs.m = f[i.xm()]; fs.c = f[i]; @@ -2457,7 +2427,7 @@ const Field2D Mesh::indexFDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo // Only one guard cell BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.m = f[i.xm()]; fs.c = f[i]; fs.p = f[i.xp()]; @@ -2521,9 +2491,6 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo Field3D result(this); result.allocate(); // Make sure data allocated - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - if (this->xstart > 1) { // Two or more guard cells if (StaggerGrids && vloc != inloc) { @@ -2531,7 +2498,7 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo // Producing a stencil centred around a lower X value BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { // Location of f always the same as the output fs.mm = f[i.xmm()]; fs.m = f[i.xm()]; @@ -2552,7 +2519,7 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo // Stencil centred around a cell centre BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { // Location of f always the same as the output fs.mm = f[i.xmm()]; fs.m = f[i.xm()]; @@ -2573,7 +2540,7 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo // Non-staggered, two or more guard cells BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { // Location of f always the same as the output fs.mm = f[i.xmm()]; fs.m = f[i.xm()]; @@ -2599,7 +2566,7 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo // Producing a stencil centred around a lower X value BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { // Location of f always the same as the output fs.m = f[i.xm()]; fs.c = f[i]; @@ -2617,7 +2584,7 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo // Stencil centred around a cell centre BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { // Location of f always the same as the output fs.m = f[i.xm()]; fs.c = f[i]; @@ -2635,7 +2602,7 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo // Non-staggered, one guard cell BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { // Location of f always the same as the output fs.m = f[i.xm()]; fs.c = f[i]; @@ -2692,14 +2659,11 @@ const Field2D Mesh::indexFDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo result.allocate(); // Make sure data allocated result.setLocation(f.getLocation()); - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - if (this->ystart > 1) { // Two or more guard cells BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.mm = f[i.ymm()]; fs.m = f[i.ym()]; fs.c = f[i]; @@ -2720,7 +2684,7 @@ const Field2D Mesh::indexFDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo // Only one guard cell BOUT_OMP(parallel) { stencil fs, vs; - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fs.m = f[i.ym()]; fs.c = f[i]; fs.p = f[i.yp()]; @@ -2797,14 +2761,11 @@ const Field3D Mesh::indexFDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo bool vUseUpDown = (v.hasYupYdown() && ((&v.yup() != &v) || (&v.ydown() != &v))); bool fUseUpDown = (f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - if (vUseUpDown && fUseUpDown) { // Both v and f have up/down fields BOUT_OMP(parallel) { stencil fval, vval; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fval.m = f.ydown()[i.ym()]; fval.c = f[i]; fval.p = f.yup()[i.yp()]; @@ -2834,7 +2795,7 @@ const Field3D Mesh::indexFDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo Field3D f_fa = this->toFieldAligned(f); BOUT_OMP(parallel) { stencil fval, vval; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fval.mm = f_fa[i.ymm()]; fval.m = f_fa[i.ym()]; fval.c = f_fa[i]; @@ -2917,12 +2878,9 @@ const Field3D Mesh::indexFDDZ(const Field3D &v, const Field3D &f, CELL_LOC outlo Field3D result(this); result.allocate(); // Make sure data allocated - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - BOUT_OMP(parallel) { stencil vval, fval; - BOUT_FOR_INNER(i, this->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, f.getRegion(region)) { fval.mm = f[i.zmm()]; fval.m = f[i.zm()]; fval.c = f[i]; From f1bf751dd0d84ba84c1aa4d683c07275dad81fab Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 12 Oct 2018 12:36:25 +0100 Subject: [PATCH 0067/1783] Use Field.getRegion in generated fieldops --- src/field/gen_fieldops.jinja | 12 ++-- src/field/gen_fieldops.py | 2 + src/field/generated_fieldops.cxx | 104 +++++++++++++++---------------- 3 files changed, 62 insertions(+), 56 deletions(-) diff --git a/src/field/gen_fieldops.jinja b/src/field/gen_fieldops.jinja index af3c3afb90..58f07d0796 100644 --- a/src/field/gen_fieldops.jinja +++ b/src/field/gen_fieldops.jinja @@ -22,7 +22,11 @@ checkData({{rhs.name}}); {% if (out == "Field3D") and ((lhs == "Field2D") or (rhs =="Field2D")) %} - {{region_loop}}({{index_var}}, localmesh->getRegion2D({{region_name}})) { + {% if (lhs == "Field2D") %} + {{region_loop}}({{index_var}}, {{lhs.name}}.getRegion({{region_name}})) { + {% else %} + {{region_loop}}({{index_var}}, {{rhs.name}}.getRegion({{region_name}})) { + {% endif %} const auto {{mixed_base_ind}} = localmesh->ind2Dto3D({{index_var}}); {% if (operator == "/") and (rhs == "Field2D") %} const auto tmp = 1.0 / {{rhs.mixed_index}}; @@ -35,7 +39,7 @@ } } {% else %} - {{region_loop}}({{index_var}}, localmesh->getRegion{{out.region_type}}({{region_name}})) { + {{region_loop}}({{index_var}}, {{out.name}}.getRegion({{region_name}})) { {{out.index}} = {{lhs.index}} {{operator}} {{rhs.index}}; } {% endif %} @@ -72,7 +76,7 @@ checkData({{rhs.name}}); {% if (out == "Field3D") and (rhs =="Field2D") %} - {{region_loop}}({{index_var}}, fieldmesh->getRegion2D({{region_name}})) { + {{region_loop}}({{index_var}}, {{rhs.name}}.getRegion({{region_name}})) { const auto {{mixed_base_ind}} = fieldmesh->ind2Dto3D({{index_var}}); {% if (operator == "/") and (rhs == "Field2D") %} const auto tmp = 1.0 / {{rhs.mixed_index}}; @@ -85,7 +89,7 @@ } } {% else %} - {{region_loop}}({{index_var}}, fieldmesh->getRegion{{lhs.region_type}}({{region_name}})) { + {{region_loop}}({{index_var}}, this->getRegion({{region_name}})) { (*this)[{{index_var}}] {{operator}}= {{rhs.index}}; } {% endif %} diff --git a/src/field/gen_fieldops.py b/src/field/gen_fieldops.py index 7fd545a2a3..96fc0bb22e 100755 --- a/src/field/gen_fieldops.py +++ b/src/field/gen_fieldops.py @@ -91,6 +91,8 @@ def __init__(self, field_type, dimensions, name=None, index_var=None, # Name of jz variable self.jz_var = jz_var self.mixed_base_ind_var = mixed_base_ind_var + #Note region_type isn't actually used currently but + #may be useful in future. if self.field_type == "Field3D": self.region_type="3D" elif self.field_type == "Field2D": diff --git a/src/field/generated_fieldops.cxx b/src/field/generated_fieldops.cxx index 0456dbef1f..0aa552060f 100644 --- a/src/field/generated_fieldops.cxx +++ b/src/field/generated_fieldops.cxx @@ -25,7 +25,7 @@ Field3D operator*(const Field3D &lhs, const Field3D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] * rhs[index]; } @@ -55,7 +55,7 @@ Field3D &Field3D::operator*=(const Field3D &rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion3D("RGN_ALL")) { (*this)[index] *= rhs[index]; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= rhs[index]; } checkData(*this); @@ -84,7 +84,7 @@ Field3D operator/(const Field3D &lhs, const Field3D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] / rhs[index]; } @@ -114,7 +114,7 @@ Field3D &Field3D::operator/=(const Field3D &rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion3D("RGN_ALL")) { (*this)[index] /= rhs[index]; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] /= rhs[index]; } checkData(*this); @@ -143,7 +143,7 @@ Field3D operator+(const Field3D &lhs, const Field3D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] + rhs[index]; } @@ -173,7 +173,7 @@ Field3D &Field3D::operator+=(const Field3D &rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion3D("RGN_ALL")) { (*this)[index] += rhs[index]; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] += rhs[index]; } checkData(*this); @@ -202,7 +202,7 @@ Field3D operator-(const Field3D &lhs, const Field3D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] - rhs[index]; } @@ -232,7 +232,7 @@ Field3D &Field3D::operator-=(const Field3D &rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion3D("RGN_ALL")) { (*this)[index] -= rhs[index]; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] -= rhs[index]; } checkData(*this); @@ -261,7 +261,7 @@ Field3D operator*(const Field3D &lhs, const Field2D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, rhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { result[base_ind + jz] = lhs[base_ind + jz] * rhs[index]; @@ -294,7 +294,7 @@ Field3D &Field3D::operator*=(const Field2D &rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, rhs.getRegion("RGN_ALL")) { const auto base_ind = fieldmesh->ind2Dto3D(index); for (int jz = 0; jz < fieldmesh->LocalNz; ++jz) { (*this)[base_ind + jz] *= rhs[index]; @@ -328,7 +328,7 @@ Field3D operator/(const Field3D &lhs, const Field2D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, rhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); const auto tmp = 1.0 / rhs[index]; for (int jz = 0; jz < localmesh->LocalNz; ++jz) { @@ -362,7 +362,7 @@ Field3D &Field3D::operator/=(const Field2D &rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, rhs.getRegion("RGN_ALL")) { const auto base_ind = fieldmesh->ind2Dto3D(index); const auto tmp = 1.0 / rhs[index]; for (int jz = 0; jz < fieldmesh->LocalNz; ++jz) { @@ -397,7 +397,7 @@ Field3D operator+(const Field3D &lhs, const Field2D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, rhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { result[base_ind + jz] = lhs[base_ind + jz] + rhs[index]; @@ -430,7 +430,7 @@ Field3D &Field3D::operator+=(const Field2D &rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, rhs.getRegion("RGN_ALL")) { const auto base_ind = fieldmesh->ind2Dto3D(index); for (int jz = 0; jz < fieldmesh->LocalNz; ++jz) { (*this)[base_ind + jz] += rhs[index]; @@ -464,7 +464,7 @@ Field3D operator-(const Field3D &lhs, const Field2D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, rhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { result[base_ind + jz] = lhs[base_ind + jz] - rhs[index]; @@ -497,7 +497,7 @@ Field3D &Field3D::operator-=(const Field2D &rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, rhs.getRegion("RGN_ALL")) { const auto base_ind = fieldmesh->ind2Dto3D(index); for (int jz = 0; jz < fieldmesh->LocalNz; ++jz) { (*this)[base_ind + jz] -= rhs[index]; @@ -522,7 +522,7 @@ Field3D operator*(const Field3D &lhs, const BoutReal rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion3D("RGN_ALL")) { result[index] = lhs[index] * rhs; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] * rhs; } result.setLocation(lhs.getLocation()); @@ -539,7 +539,7 @@ Field3D &Field3D::operator*=(const BoutReal rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion3D("RGN_ALL")) { (*this)[index] *= rhs; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= rhs; } checkData(*this); @@ -559,7 +559,7 @@ Field3D operator/(const Field3D &lhs, const BoutReal rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion3D("RGN_ALL")) { result[index] = lhs[index] / rhs; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] / rhs; } result.setLocation(lhs.getLocation()); @@ -576,7 +576,7 @@ Field3D &Field3D::operator/=(const BoutReal rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion3D("RGN_ALL")) { (*this)[index] /= rhs; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] /= rhs; } checkData(*this); @@ -596,7 +596,7 @@ Field3D operator+(const Field3D &lhs, const BoutReal rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion3D("RGN_ALL")) { result[index] = lhs[index] + rhs; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] + rhs; } result.setLocation(lhs.getLocation()); @@ -613,7 +613,7 @@ Field3D &Field3D::operator+=(const BoutReal rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion3D("RGN_ALL")) { (*this)[index] += rhs; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] += rhs; } checkData(*this); @@ -633,7 +633,7 @@ Field3D operator-(const Field3D &lhs, const BoutReal rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion3D("RGN_ALL")) { result[index] = lhs[index] - rhs; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] - rhs; } result.setLocation(lhs.getLocation()); @@ -650,7 +650,7 @@ Field3D &Field3D::operator-=(const BoutReal rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion3D("RGN_ALL")) { (*this)[index] -= rhs; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] -= rhs; } checkData(*this); @@ -679,7 +679,7 @@ Field3D operator*(const Field2D &lhs, const Field3D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, lhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { result[base_ind + jz] = lhs[index] * rhs[base_ind + jz]; @@ -711,7 +711,7 @@ Field3D operator/(const Field2D &lhs, const Field3D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, lhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { result[base_ind + jz] = lhs[index] / rhs[base_ind + jz]; @@ -743,7 +743,7 @@ Field3D operator+(const Field2D &lhs, const Field3D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, lhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { result[base_ind + jz] = lhs[index] + rhs[base_ind + jz]; @@ -775,7 +775,7 @@ Field3D operator-(const Field2D &lhs, const Field3D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, lhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { result[base_ind + jz] = lhs[index] - rhs[base_ind + jz]; @@ -807,7 +807,7 @@ Field2D operator*(const Field2D &lhs, const Field2D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] * rhs[index]; } @@ -837,7 +837,7 @@ Field2D &Field2D::operator*=(const Field2D &rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion2D("RGN_ALL")) { (*this)[index] *= rhs[index]; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= rhs[index]; } checkData(*this); @@ -866,7 +866,7 @@ Field2D operator/(const Field2D &lhs, const Field2D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] / rhs[index]; } @@ -896,7 +896,7 @@ Field2D &Field2D::operator/=(const Field2D &rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion2D("RGN_ALL")) { (*this)[index] /= rhs[index]; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] /= rhs[index]; } checkData(*this); @@ -925,7 +925,7 @@ Field2D operator+(const Field2D &lhs, const Field2D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] + rhs[index]; } @@ -955,7 +955,7 @@ Field2D &Field2D::operator+=(const Field2D &rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion2D("RGN_ALL")) { (*this)[index] += rhs[index]; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] += rhs[index]; } checkData(*this); @@ -984,7 +984,7 @@ Field2D operator-(const Field2D &lhs, const Field2D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] - rhs[index]; } @@ -1014,7 +1014,7 @@ Field2D &Field2D::operator-=(const Field2D &rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion2D("RGN_ALL")) { (*this)[index] -= rhs[index]; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] -= rhs[index]; } checkData(*this); @@ -1034,7 +1034,7 @@ Field2D operator*(const Field2D &lhs, const BoutReal rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { result[index] = lhs[index] * rhs; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] * rhs; } result.setLocation(lhs.getLocation()); @@ -1051,7 +1051,7 @@ Field2D &Field2D::operator*=(const BoutReal rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion2D("RGN_ALL")) { (*this)[index] *= rhs; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= rhs; } checkData(*this); @@ -1071,7 +1071,7 @@ Field2D operator/(const Field2D &lhs, const BoutReal rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { result[index] = lhs[index] / rhs; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] / rhs; } result.setLocation(lhs.getLocation()); @@ -1088,7 +1088,7 @@ Field2D &Field2D::operator/=(const BoutReal rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion2D("RGN_ALL")) { (*this)[index] /= rhs; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] /= rhs; } checkData(*this); @@ -1108,7 +1108,7 @@ Field2D operator+(const Field2D &lhs, const BoutReal rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { result[index] = lhs[index] + rhs; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] + rhs; } result.setLocation(lhs.getLocation()); @@ -1125,7 +1125,7 @@ Field2D &Field2D::operator+=(const BoutReal rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion2D("RGN_ALL")) { (*this)[index] += rhs; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] += rhs; } checkData(*this); @@ -1145,7 +1145,7 @@ Field2D operator-(const Field2D &lhs, const BoutReal rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { result[index] = lhs[index] - rhs; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] - rhs; } result.setLocation(lhs.getLocation()); @@ -1162,7 +1162,7 @@ Field2D &Field2D::operator-=(const BoutReal rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, fieldmesh->getRegion2D("RGN_ALL")) { (*this)[index] -= rhs; } + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] -= rhs; } checkData(*this); @@ -1182,7 +1182,7 @@ Field3D operator*(const BoutReal lhs, const Field3D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion3D("RGN_ALL")) { result[index] = lhs * rhs[index]; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs * rhs[index]; } result.setLocation(rhs.getLocation()); @@ -1200,7 +1200,7 @@ Field3D operator/(const BoutReal lhs, const Field3D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion3D("RGN_ALL")) { result[index] = lhs / rhs[index]; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs / rhs[index]; } result.setLocation(rhs.getLocation()); @@ -1218,7 +1218,7 @@ Field3D operator+(const BoutReal lhs, const Field3D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion3D("RGN_ALL")) { result[index] = lhs + rhs[index]; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs + rhs[index]; } result.setLocation(rhs.getLocation()); @@ -1236,7 +1236,7 @@ Field3D operator-(const BoutReal lhs, const Field3D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion3D("RGN_ALL")) { result[index] = lhs - rhs[index]; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs - rhs[index]; } result.setLocation(rhs.getLocation()); @@ -1254,7 +1254,7 @@ Field2D operator*(const BoutReal lhs, const Field2D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { result[index] = lhs * rhs[index]; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs * rhs[index]; } result.setLocation(rhs.getLocation()); @@ -1272,7 +1272,7 @@ Field2D operator/(const BoutReal lhs, const Field2D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { result[index] = lhs / rhs[index]; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs / rhs[index]; } result.setLocation(rhs.getLocation()); @@ -1290,7 +1290,7 @@ Field2D operator+(const BoutReal lhs, const Field2D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { result[index] = lhs + rhs[index]; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs + rhs[index]; } result.setLocation(rhs.getLocation()); @@ -1308,7 +1308,7 @@ Field2D operator-(const BoutReal lhs, const Field2D &rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, localmesh->getRegion2D("RGN_ALL")) { result[index] = lhs - rhs[index]; } + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs - rhs[index]; } result.setLocation(rhs.getLocation()); From 49b59fa0c8d2a58d96d527ad093b0b0a8139bb9a Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 12 Oct 2018 12:49:04 +0100 Subject: [PATCH 0068/1783] Remove mesh->getRegion?? in Field2D --- src/field/field2d.cxx | 52 +++++++++---------------------------------- 1 file changed, 11 insertions(+), 41 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index ad44b43a1b..f71df79bd6 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -270,10 +270,7 @@ Field2D &Field2D::operator=(const BoutReal rhs) { throw BoutException("Field2D: Assignment from non-finite BoutReal\n"); #endif - const Region ®ion_all = fieldmesh->getRegion2D("RGN_ALL"); - BOUT_FOR(i, region_all) { - (*this)[i] = rhs; - } + BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] = rhs; } return *this; } @@ -416,8 +413,7 @@ BoutReal min(const Field2D &f, bool allpe, REGION rgn) { checkData(f); - const Region ®ion = f.getMesh()->getRegion2D(REGION_STRING(rgn)); - + const auto region = f.getRegion(rgn); BoutReal result = f[*region.cbegin()]; BOUT_FOR_OMP(i, region, parallel for reduction(min:result)) { @@ -440,8 +436,7 @@ BoutReal max(const Field2D &f, bool allpe,REGION rgn) { checkData(f); - const Region ®ion = f.getMesh()->getRegion2D(REGION_STRING(rgn)); - + const auto region = f.getRegion(rgn); BoutReal result = f[*region.cbegin()]; BOUT_FOR_OMP(i, region, parallel for reduction(max:result)) { @@ -466,9 +461,7 @@ bool finite(const Field2D &f, REGION rgn) { return false; } - const Region ®ion = f.getMesh()->getRegion2D(REGION_STRING(rgn)); - - BOUT_FOR_SERIAL(i, region) { + BOUT_FOR_SERIAL(i, f.getRegion(rgn)) { if (!::finite(f[i])) { return false; } @@ -504,10 +497,7 @@ bool finite(const Field2D &f, REGION rgn) { /* Define and allocate the output result */ \ Field2D result(f.getMesh()); \ result.allocate(); \ - const Region ®ion = f.getMesh()->getRegion2D(REGION_STRING(rgn)); \ - BOUT_FOR(d, region) { \ - result[d] = func(f[d]); \ - } \ + BOUT_FOR(d, result.getRegion(rgn)) { result[d] = func(f[d]); } \ result.setLocation(f.getLocation()); \ checkData(result); \ return result; \ @@ -539,9 +529,7 @@ const Field2D floor(const Field2D &var, BoutReal f, REGION rgn) { Field2D result = copy(var); - const Region ®ion = var.getMesh()->getRegion2D(REGION_STRING(rgn)); - - BOUT_FOR(d, region) { + BOUT_FOR(d, result.getRegion(rgn)) { if (result[d] < f) { result[d] = f; } @@ -562,11 +550,7 @@ Field2D pow(const Field2D &lhs, const Field2D &rhs, REGION rgn) { Field2D result(lhs.getMesh()); result.allocate(); - const Region ®ion = lhs.getMesh()->getRegion2D(REGION_STRING(rgn)); - - BOUT_FOR(i, region) { - result[i] = ::pow(lhs[i], rhs[i]); - } + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } result.setLocation(lhs.getLocation()); @@ -584,11 +568,7 @@ Field2D pow(const Field2D &lhs, BoutReal rhs, REGION rgn) { Field2D result(lhs.getMesh()); result.allocate(); - const Region ®ion = lhs.getMesh()->getRegion2D(REGION_STRING(rgn)); - - BOUT_FOR(i, region) { - result[i] = ::pow(lhs[i], rhs); - } + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs); } result.setLocation(lhs.getLocation()); @@ -606,11 +586,7 @@ Field2D pow(BoutReal lhs, const Field2D &rhs, REGION rgn) { Field2D result(rhs.getMesh()); result.allocate(); - const Region ®ion = rhs.getMesh()->getRegion2D(REGION_STRING(rgn)); - - BOUT_FOR(i, region) { - result[i] = ::pow(lhs, rhs[i]); - } + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs, rhs[i]); } result.setLocation(rhs.getLocation()); @@ -623,10 +599,8 @@ namespace { // levels and UNUSED parameters #if CHECK > 2 void checkDataIsFiniteOnRegion(const Field2D &f, REGION region) { - const Region &new_region = f.getMesh()->getRegion2D(REGION_STRING(region)); - // Do full checks - BOUT_FOR_SERIAL (i, new_region) { + BOUT_FOR_SERIAL(i, f.getRegion(region)) { if (!::finite(f[i])) { throw BoutException("Field2D: Operation on non-finite data at [%d][%d]\n", i.x(), i.y()); @@ -653,10 +627,6 @@ void checkData(const Field2D &f, REGION region) { void invalidateGuards(Field2D &var) { Mesh *localmesh = var.getMesh(); - const Region ®ion_guards = localmesh->getRegion2D("RGN_GUARDS"); - - BOUT_FOR(i, region_guards) { - var[i] = BoutNaN; - } + BOUT_FOR(i, var.getRegion("RGN_GUARDS")) { var[i] = BoutNaN; } } #endif From 18cfbb7cdfed6623cb58d340e4e99373d754fcf0 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 12 Oct 2018 13:06:03 +0100 Subject: [PATCH 0069/1783] Remove mesh->getRegion?? in Field3D --- src/field/field3d.cxx | 89 +++++++++---------------------------------- 1 file changed, 18 insertions(+), 71 deletions(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 1143eb9fdc..924d240f8b 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -395,12 +395,8 @@ Field3D & Field3D::operator=(const Field2D &rhs) { allocate(); /// Copy data - const Region ®ion_all = fieldmesh->getRegion3D("RGN_ALL"); + BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] = rhs[i]; } - BOUT_FOR(i, region_all) { - (*this)[i] = rhs[i]; - } - /// Only 3D fields have locations for now //location = CELL_CENTRE; @@ -417,11 +413,7 @@ void Field3D::operator=(const FieldPerp &rhs) { allocate(); /// Copy data - const Region ®ion_all = fieldmesh->getRegionPerp("RGN_ALL"); - - BOUT_FOR(i, region_all) { - (*this)(i, rhs.getIndex()) = rhs[i]; - } + BOUT_FOR(i, rhs.getRegion("RGN_ALL")) { (*this)(i, rhs.getIndex()) = rhs[i]; } } Field3D & Field3D::operator=(const BoutReal val) { @@ -431,15 +423,7 @@ Field3D & Field3D::operator=(const BoutReal val) { allocate(); - const Region ®ion_all = fieldmesh->getRegion3D("RGN_ALL"); - - BOUT_FOR(i, region_all) { - (*this)[i] = val; - } - - // Only 3D fields have locations - //location = CELL_CENTRE; - // DON'T RE-SET LOCATION + BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] = val; } return *this; } @@ -726,8 +710,7 @@ Field3D operator-(const Field3D &f) { return -1.0 * f; } FieldPerp result; \ result.allocate(); \ result.setIndex(rhs.getIndex()); \ - const Region ®ion_all = rhs.getMesh()->getRegionPerp("RGN_ALL"); \ - BOUT_FOR(i, region_all) { \ + BOUT_FOR(i, rhs.getRegion("RGN_ALL")) { \ result[i] = lhs(i, rhs.getIndex()) op rhs[i]; \ return result; \ } @@ -743,12 +726,8 @@ Field3D pow(const Field3D &lhs, const Field3D &rhs, REGION rgn) { Field3D result(lhs.getMesh()); result.allocate(); - const Region ®ion = lhs.getMesh()->getRegion3D(REGION_STRING(rgn)); + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } - BOUT_FOR(i, region) { - result[i] = ::pow(lhs[i], rhs[i]); - } - result.setLocation( lhs.getLocation() ); checkData(result); @@ -766,11 +745,7 @@ Field3D pow(const Field3D &lhs, const Field2D &rhs, REGION rgn) { Field3D result(lhs.getMesh()); result.allocate(); - const Region ®ion = lhs.getMesh()->getRegion3D(REGION_STRING(rgn)); - - BOUT_FOR(i, region) { - result[i] = ::pow(lhs[i], rhs[i]); - } + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } result.setLocation( lhs.getLocation() ); @@ -789,9 +764,7 @@ FieldPerp pow(const Field3D &lhs, const FieldPerp &rhs, REGION rgn) { result.allocate(); result.setIndex(rhs.getIndex()); - const Region ®ion = lhs.getMesh()->getRegionPerp(REGION_STRING(rgn)); - - BOUT_FOR(i, region) { + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs(i, rhs.getIndex()), rhs[i]); } @@ -810,12 +783,8 @@ Field3D pow(const Field3D &lhs, BoutReal rhs, REGION rgn) { Field3D result(lhs.getMesh()); result.allocate(); - const Region ®ion = lhs.getMesh()->getRegion3D(REGION_STRING(rgn)); + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs); } - BOUT_FOR(i, region) { - result[i] = ::pow(lhs[i], rhs); - } - result.setLocation( lhs.getLocation() ); checkData(result); @@ -832,12 +801,8 @@ Field3D pow(BoutReal lhs, const Field3D &rhs, REGION rgn) { Field3D result(rhs.getMesh()); result.allocate(); - const Region ®ion = rhs.getMesh()->getRegion3D(REGION_STRING(rgn)); + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs, rhs[i]); } - BOUT_FOR(i, region) { - result[i] = ::pow(lhs, rhs[i]); - } - result.setLocation( rhs.getLocation() ); checkData(result); @@ -849,8 +814,7 @@ BoutReal min(const Field3D &f, bool allpe, REGION rgn) { checkData(f); - const Region ®ion = f.getMesh()->getRegion3D(REGION_STRING(rgn)); - + const auto region = f.getRegion(rgn); BoutReal result = f[*region.cbegin()]; BOUT_FOR_OMP(i, region, parallel for reduction(min:result)) { @@ -872,9 +836,8 @@ BoutReal max(const Field3D &f, bool allpe, REGION rgn) { TRACE("Field3D::Max() %s",allpe? "over all PEs" : ""); checkData(f); - - const Region ®ion = f.getMesh()->getRegion3D(REGION_STRING(rgn)); + const auto region = f.getRegion(rgn); BoutReal result = f[*region.cbegin()]; BOUT_FOR_OMP(i, region, parallel for reduction(max:result)) { @@ -901,9 +864,7 @@ BoutReal mean(const Field3D &f, bool allpe, REGION rgn) { BoutReal result = 0.; int count = 0; - const Region ®ion = f.getMesh()->getRegion3D(REGION_STRING(rgn)); - - BOUT_FOR_OMP(i, region, parallel for reduction(+:result,count)) { + BOUT_FOR_OMP(i, f.getRegion(rgn), parallel for reduction(+:result,count)) { result += f[i]; count += 1; } @@ -946,10 +907,7 @@ BoutReal mean(const Field3D &f, bool allpe, REGION rgn) { /* Define and allocate the output result */ \ Field3D result(f.getMesh()); \ result.allocate(); \ - const Region ®ion = f.getMesh()->getRegion3D(REGION_STRING(rgn)); \ - BOUT_FOR (d, region) { \ - result[d] = func(f[d]); \ - } \ + BOUT_FOR(d, result.getRegion(rgn)) { result[d] = func(f[d]); } \ result.setLocation(f.getLocation()); \ checkData(result); \ return result; \ @@ -1166,9 +1124,7 @@ bool finite(const Field3D &f, REGION rgn) { return false; } - const Region ®ion = f.getMesh()->getRegion3D(REGION_STRING(rgn)); - - BOUT_FOR_SERIAL(i, region) { + BOUT_FOR_SERIAL(i, f.getRegion(rgn)) { if (!finite(f[i])) { return false; } @@ -1183,9 +1139,7 @@ namespace { #if CHECK > 2 void checkDataIsFiniteOnRegion(const Field3D &f, REGION region) { // Do full checks - const Region &new_region = f.getMesh()->getRegion3D(REGION_STRING(region)); - - BOUT_FOR_SERIAL(i, new_region) { + BOUT_FOR_SERIAL(i, f.getRegion(region)) { if (!finite(f[i])) { throw BoutException("Field3D: Operation on non-finite data at [%d][%d][%d]\n", i.x(), i.y(), i.z()); @@ -1216,8 +1170,7 @@ const Field3D floor(const Field3D &var, BoutReal f, REGION rgn) { checkData(var); Field3D result = copy(var); - const Region ®ion = var.getMesh()->getRegion3D(REGION_STRING(rgn)); - BOUT_FOR(d, region) { + BOUT_FOR(d, var.getRegion(rgn)) { if (result[d] < f) { result[d] = f; } @@ -1235,9 +1188,7 @@ Field2D DC(const Field3D &f, REGION rgn) { Field2D result(localmesh); result.allocate(); - const Region ®ion = localmesh->getRegion2D(REGION_STRING(rgn)); - - BOUT_FOR(i, region) { + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = 0.0; for (int k = 0; k < localmesh->LocalNz; k++) { result[i] += f[localmesh->ind2Dto3D(i, k)]; @@ -1253,10 +1204,6 @@ Field2D DC(const Field3D &f, REGION rgn) { void invalidateGuards(Field3D &var) { Mesh *localmesh = var.getMesh(); - const Region ®ion_guards = localmesh->getRegion3D("RGN_GUARDS"); - - BOUT_FOR(i, region_guards) { - var[i] = BoutNaN; - } + BOUT_FOR(i, var.getRegion("RGN_GUARDS")) { var[i] = BoutNaN; } } #endif From 3abefca05d69e745d108ad01bec4a68cf9d8df8d Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 12 Oct 2018 13:35:22 +0100 Subject: [PATCH 0070/1783] Remove mesh->getRegion?? in FieldPerp --- src/field/fieldperp.cxx | 116 +++++++++++----------------------------- 1 file changed, 32 insertions(+), 84 deletions(-) diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 5bd7765e91..5006c8c751 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -96,11 +96,7 @@ FieldPerp & FieldPerp::operator=(const BoutReal rhs) { checkData(rhs); - const Region ®ion_all = fieldmesh->getRegionPerp("RGN_ALL"); - - BOUT_FOR(i, region_all) { - (*this)[i] = rhs; - } + BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] = rhs; } return *this; } @@ -126,15 +122,12 @@ const DataIterator FieldPerp::end() const { * OPERATORS ***************************************************************/ -#define FPERP_OP_FPERP(op, bop, ftype) \ - FieldPerp &FieldPerp::operator op(const ftype &rhs) { \ +#define FPERP_OP_FPERP(op, bop) \ + FieldPerp &FieldPerp::operator op(const FieldPerp &rhs) { \ if (data.unique()) { \ checkData(rhs); \ /* Only reference to the data */ \ - const Region ®ion = fieldmesh->getRegionPerp("RGN_ALL"); \ - BOUT_FOR(i, region) { \ - (*this)[i] op rhs[i]; \ - } \ + BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] op rhs[i]; } \ checkData(*this); \ } else { \ /* Shared with another FieldPerp */ \ @@ -143,10 +136,10 @@ const DataIterator FieldPerp::end() const { return *this; \ } -FPERP_OP_FPERP(+=, +, FieldPerp); -FPERP_OP_FPERP(-=, -, FieldPerp); -FPERP_OP_FPERP(*=, *, FieldPerp); -FPERP_OP_FPERP(/=, /, FieldPerp); +FPERP_OP_FPERP(+=, +); +FPERP_OP_FPERP(-=, -); +FPERP_OP_FPERP(*=, *); +FPERP_OP_FPERP(/=, /); #define FPERP_OP_FIELD(op, bop, ftype) \ FieldPerp &FieldPerp::operator op(const ftype &rhs) { \ @@ -154,10 +147,7 @@ FPERP_OP_FPERP(/=, /, FieldPerp); checkData(*this); \ checkData(rhs); \ /* Only reference to the data */ \ - const Region ®ion = fieldmesh->getRegionPerp("RGN_ALL"); \ - BOUT_FOR(i, region) { \ - (*this)[i] op rhs(i.x(), yindex, i.z()); \ - } \ + BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] op rhs(i.x(), yindex, i.z()); } \ checkData(*this); \ } else { \ /* Shared with another FieldPerp */ \ @@ -183,10 +173,7 @@ FPERP_OP_FIELD(/=, /, Field2D); if (data.unique()) { \ checkData(rhs); \ /* Only reference to the data */ \ - const Region ®ion = fieldmesh->getRegionPerp("RGN_ALL"); \ - BOUT_FOR(i, region) { \ - (*this)[i] op rhs; \ - } \ + BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] op rhs; } \ checkData(*this); \ } else { \ /* Shared with another FieldPerp */ \ @@ -230,26 +217,23 @@ const Region &FieldPerp::getRegion(const std::string ®ion_name) cons FieldPerp operator-(const FieldPerp &f) { return -1.0 * f; } // Operator on FieldPerp and another field -#define FPERP_FPERP_OP_FPERP(op, ftype) \ - const FieldPerp operator op(const FieldPerp &lhs, const ftype &rhs) { \ +#define FPERP_FPERP_OP_FPERP(op) \ + const FieldPerp operator op(const FieldPerp &lhs, const FieldPerp &rhs) { \ checkData(lhs); \ checkData(rhs); \ FieldPerp result(lhs.getMesh()); \ result.allocate(); \ result.setIndex(lhs.getIndex()); \ \ - const Region ®ion = lhs.getMesh()->getRegionPerp("RGN_ALL"); \ - BOUT_FOR(i, region) { \ - result[i] = lhs[i] op rhs[i]; \ - } \ + BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs[i] op rhs[i]; } \ checkData(result); \ return result; \ } -FPERP_FPERP_OP_FPERP(+, FieldPerp); -FPERP_FPERP_OP_FPERP(-, FieldPerp); -FPERP_FPERP_OP_FPERP(*, FieldPerp); -FPERP_FPERP_OP_FPERP(/, FieldPerp); +FPERP_FPERP_OP_FPERP(+); +FPERP_FPERP_OP_FPERP(-); +FPERP_FPERP_OP_FPERP(*); +FPERP_FPERP_OP_FPERP(/); // Operator on FieldPerp and another field #define FPERP_FPERP_OP_FIELD(op, ftype) \ @@ -260,8 +244,7 @@ FPERP_FPERP_OP_FPERP(/, FieldPerp); result.allocate(); \ result.setIndex(lhs.getIndex()); \ \ - const Region ®ion = lhs.getMesh()->getRegionPerp("RGN_ALL"); \ - BOUT_FOR(i, region) { \ + BOUT_FOR(i, result.getRegion("RGN_ALL")) { \ result[i] = lhs[i] op rhs(i.x(), lhs.getIndex(), i.z()); \ } \ checkData(result); \ @@ -289,10 +272,7 @@ FPERP_FPERP_OP_FIELD(/, Field2D); result.allocate(); \ result.setIndex(lhs.getIndex()); \ \ - const Region ®ion = result.getMesh()->getRegionPerp("RGN_ALL"); \ - BOUT_FOR (i, region) { \ - result[i] = lhs[i] op rhs; \ - } \ + BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs[i] op rhs; } \ \ checkData(result); \ return result; \ @@ -311,10 +291,7 @@ FPERP_FPERP_OP_REAL(/); result.allocate(); \ result.setIndex(rhs.getIndex()); \ \ - const Region ®ion = result.getMesh()->getRegionPerp("RGN_ALL"); \ - BOUT_FOR (i, region) { \ - result[i] = lhs op rhs[i]; \ - } \ + BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs op rhs[i]; } \ \ checkData(result); \ return result; \ @@ -353,10 +330,7 @@ FPERP_REAL_OP_FPERP(/); FieldPerp result(f.getMesh()); \ result.allocate(); \ result.setIndex(f.getIndex()); \ - const Region ®ion = f.getMesh()->getRegionPerp(REGION_STRING(rgn)); \ - BOUT_FOR (d, region) { \ - result[d] = func(f[d]); \ - } \ + BOUT_FOR(d, result.getRegion(rgn)) { result[d] = func(f[d]); } \ checkData(result); \ return result; \ } @@ -386,8 +360,7 @@ const FieldPerp floor(const FieldPerp &var, BoutReal f, REGION rgn) { checkData(var); FieldPerp result = copy(var); - const Region ®ion = var.getMesh()->getRegionPerp(REGION_STRING(rgn)); - BOUT_FOR(d, region) { + BOUT_FOR(d, var.getRegion(rgn)) { if (result[d] < f) { result[d] = f; } @@ -407,11 +380,8 @@ const FieldPerp sliceXZ(const Field3D& f, int y) { result.allocate(); result.setIndex(y); - const Region ®ion_all = f.getMesh()->getRegionPerp("RGN_ALL"); - BOUT_FOR(i, region_all) { - result[i] = f(i, y); - } - + BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = f(i, y); } + checkData(result); return result; } @@ -421,8 +391,7 @@ BoutReal min(const FieldPerp &f, bool allpe, REGION rgn) { checkData(f); - const Region ®ion = f.getMesh()->getRegionPerp(REGION_STRING(rgn)); - + const auto region = f.getRegion(rgn); BoutReal result = f[*region.cbegin()]; BOUT_FOR_OMP(i, region, parallel for reduction(min:result)) { @@ -445,8 +414,7 @@ BoutReal max(const FieldPerp &f, bool allpe, REGION rgn) { checkData(f); - const Region ®ion = f.getMesh()->getRegionPerp(REGION_STRING(rgn)); - + const auto region = f.getRegion(rgn); BoutReal result = f[*region.cbegin()]; BOUT_FOR_OMP(i, region, parallel for reduction(max:result)) { @@ -471,9 +439,7 @@ bool finite(const FieldPerp &f, REGION rgn) { return false; } - const Region ®ion = f.getMesh()->getRegionPerp(REGION_STRING(rgn)); - - BOUT_FOR_SERIAL(i, region) { + BOUT_FOR_SERIAL(i, f.getRegion(rgn)) { if (!::finite(f[i])) { return false; } @@ -495,11 +461,7 @@ FieldPerp pow(const FieldPerp &lhs, const FieldPerp &rhs, REGION rgn) { result.allocate(); result.setIndex(lhs.getIndex()); - const Region ®ion = result.getMesh()->getRegionPerp(REGION_STRING(rgn)); - - BOUT_FOR(i, region) { - result[i] = ::pow(lhs[i], rhs[i]); - } + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } checkData(result); return result; @@ -516,11 +478,7 @@ FieldPerp pow(const FieldPerp &lhs, BoutReal rhs, REGION rgn) { result.allocate(); result.setIndex(lhs.getIndex()); - const Region ®ion = result.getMesh()->getRegionPerp(REGION_STRING(rgn)); - - BOUT_FOR(i, region) { - result[i] = ::pow(lhs[i], rhs); - } + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs); } checkData(result); return result; @@ -537,11 +495,7 @@ FieldPerp pow(BoutReal lhs, const FieldPerp &rhs, REGION rgn) { result.allocate(); result.setIndex(rhs.getIndex()); - const Region ®ion = result.getMesh()->getRegionPerp(REGION_STRING(rgn)); - - BOUT_FOR(i, region) { - result[i] = ::pow(lhs, rhs[i]); - } + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs, rhs[i]); } checkData(result); return result; @@ -549,10 +503,8 @@ FieldPerp pow(BoutReal lhs, const FieldPerp &rhs, REGION rgn) { #if CHECK > 2 void checkDataIsFiniteOnRegion(const FieldPerp &f, REGION region) { - const Region &new_region = f.getMesh()->getRegionPerp(REGION_STRING(region)); - // Do full checks - BOUT_FOR_SERIAL(i, new_region) { + BOUT_FOR_SERIAL(i, f.getRegion(region)) { if (!::finite(f[i])) { throw BoutException("FieldPerp: Operation on non-finite data at [%d][%d]\n", i.x(), i.z()); @@ -581,10 +533,6 @@ void checkData(const FieldPerp &f, REGION region) { void invalidateGuards(FieldPerp &var) { Mesh *localmesh = var.getMesh(); - const Region ®ion_guards = localmesh->getRegionPerp("RGN_GUARDS"); - - BOUT_FOR(i, region_guards) { - var[i] = BoutNaN; - } + BOUT_FOR(i, var.getRegion("RGN_GUARDS")) { var[i] = BoutNaN; } } #endif From 2fd68772ee7c5d22c96b1d15ae31d7f7ced32b5f Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 12 Oct 2018 18:59:44 +0100 Subject: [PATCH 0071/1783] Replace mesh->getRegion?D with Field.getRegion in several places --- src/field/field_factory.cxx | 14 ++++++------- src/field/where.cxx | 20 +++++++++---------- .../impls/multigrid/multigrid_laplace.cxx | 9 +++------ src/mesh/difops.cxx | 19 ++++++++---------- src/mesh/fv_ops.cxx | 4 ++-- src/mesh/interpolation.cxx | 16 +++++++-------- src/physics/sourcex.cxx | 14 ++++++------- src/sys/derivs.cxx | 2 +- 8 files changed, 46 insertions(+), 52 deletions(-) diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 3180b50592..939754699e 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -124,7 +124,7 @@ const Field2D FieldFactory::create2D(const string &value, const Options *opt, switch(loc) { case CELL_XLOW: { - BOUT_FOR(i, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal xpos = 0.5 * (localmesh->GlobalX(i.x() - 1) + localmesh->GlobalX(i.x())); result[i] = gen->generate(xpos, TWOPI * localmesh->GlobalY(i.y()), 0.0, // Z @@ -133,7 +133,7 @@ const Field2D FieldFactory::create2D(const string &value, const Options *opt, break; } case CELL_YLOW: { - BOUT_FOR(i, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal ypos = TWOPI * 0.5 * (localmesh->GlobalY(i.y() - 1) + localmesh->GlobalY(i.y())); result[i] = gen->generate(localmesh->GlobalX(i.x()), ypos, @@ -143,7 +143,7 @@ const Field2D FieldFactory::create2D(const string &value, const Options *opt, break; } default: {// CELL_CENTRE or CELL_ZLOW - BOUT_FOR(i, localmesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = gen->generate(localmesh->GlobalX(i.x()), TWOPI * localmesh->GlobalY(i.y()), 0.0, // Z @@ -182,7 +182,7 @@ const Field3D FieldFactory::create3D(const string &value, const Options *opt, switch(loc) { case CELL_XLOW: { - BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal xpos = 0.5 * (localmesh->GlobalX(i.x() - 1) + localmesh->GlobalX(i.x())); result[i] = gen->generate(xpos, TWOPI * localmesh->GlobalY(i.y()), TWOPI * static_cast(i.z()) / @@ -192,7 +192,7 @@ const Field3D FieldFactory::create3D(const string &value, const Options *opt, break; } case CELL_YLOW: { - BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal ypos = TWOPI * 0.5 * (localmesh->GlobalY(i.y() - 1) + localmesh->GlobalY(i.y())); result[i] = gen->generate(localmesh->GlobalX(i.x()), ypos, @@ -203,7 +203,7 @@ const Field3D FieldFactory::create3D(const string &value, const Options *opt, break; } case CELL_ZLOW: { - BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = gen->generate(localmesh->GlobalX(i.x()), TWOPI * localmesh->GlobalY(i.y()), TWOPI * (static_cast(i.z()) - 0.5) / @@ -213,7 +213,7 @@ const Field3D FieldFactory::create3D(const string &value, const Options *opt, break; } default: {// CELL_CENTRE - BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = gen->generate(localmesh->GlobalX(i.x()), TWOPI * localmesh->GlobalY(i.y()), TWOPI * static_cast(i.z()) / diff --git a/src/field/where.cxx b/src/field/where.cxx index 6a003cedf2..4328f7e7e7 100644 --- a/src/field/where.cxx +++ b/src/field/where.cxx @@ -34,7 +34,7 @@ const Field3D where(const Field2D &test, const Field3D >0, const Field3D &le0) Field3D result(testMesh); result.allocate(); - BOUT_FOR(i, testMesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { result[i] = gt0[i]; }else { @@ -49,7 +49,7 @@ const Field3D where(const Field2D &test, const Field3D >0, BoutReal le0) { Field3D result(testMesh); result.allocate(); - BOUT_FOR(i, testMesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { result[i] = gt0[i]; }else { @@ -64,7 +64,7 @@ const Field3D where(const Field2D &test, BoutReal gt0, const Field3D &le0) { Field3D result(testMesh); result.allocate(); - BOUT_FOR(i, testMesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { result[i] = gt0; }else { @@ -80,7 +80,7 @@ const Field3D where(const Field2D &test, const Field3D >0, const Field2D &le0) Field3D result(testMesh); result.allocate(); - BOUT_FOR(i, testMesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { result[i] = gt0[i]; }else { @@ -96,7 +96,7 @@ const Field3D where(const Field2D &test, const Field2D >0, const Field3D &le0) Field3D result(testMesh); result.allocate(); - BOUT_FOR(i, testMesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { result[i] = gt0[i]; }else { @@ -115,7 +115,7 @@ const Field2D where(const Field2D &test, const Field2D >0, const Field2D &le0) Field2D result(testMesh); result.allocate(); - BOUT_FOR(i, testMesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { result[i] = gt0[i]; }else { @@ -131,7 +131,7 @@ const Field2D where(const Field2D &test, const Field2D >0, BoutReal le0) { Field2D result(testMesh); result.allocate(); - BOUT_FOR(i, testMesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { result[i] = gt0[i]; }else { @@ -147,7 +147,7 @@ const Field2D where(const Field2D &test, BoutReal gt0, const Field2D &le0) { Field2D result(testMesh); result.allocate(); - BOUT_FOR(i, testMesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { result[i] = gt0; }else { @@ -163,7 +163,7 @@ const Field2D where(const Field2D &test, BoutReal gt0, BoutReal le0) { Field2D result(test.getMesh()); result.allocate(); - BOUT_FOR(i, testMesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { result[i] = gt0; }else { @@ -182,7 +182,7 @@ const Field3D where(const Field3D &test, BoutReal gt0, const Field3D &le0) { Field3D result(testMesh); result.allocate(); - BOUT_FOR(i, testMesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { result[i] = gt0; }else { diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index 5170c0d031..758064481d 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -427,13 +427,10 @@ BOUT_OMP(for) result.allocate(); result.setIndex(yindex); - #if CHECK>2 +#if CHECK > 2 // Make any unused elements NaN so that user does not try to do calculations with them - const auto ®ion = mesh->getRegionPerp("RGN_ALL"); - BOUT_FOR(i, region) { - result[i] = BoutNaN; - } - #endif + result = BoutNan; +#endif // Copy solution into a FieldPerp to return BOUT_OMP(parallel default(shared) ) BOUT_OMP(for collapse(2)) diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index 8b8ff649ce..dc5e93198a 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -296,7 +296,7 @@ const Field2D Grad_par_CtoL(const Field2D &var) { Coordinates *metric = var.getCoordinates(CELL_YLOW); - BOUT_FOR(i, varMesh->getRegion2D("RGN_NOBNDRY")) { + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { result[i] = (var[i] - var[i.ym()]) / (metric->dy[i] * sqrt(metric->g_22[i])); } @@ -319,14 +319,11 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg bool vUseUpDown = (v.hasYupYdown() && ((&v.yup() != &v) || (&v.ydown() != &v))); bool fUseUpDown = (f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - if (vUseUpDown && fUseUpDown) { // Both v and f have up/down fields BOUT_OMP(parallel) { stencil fval, vval; - BOUT_FOR_INNER(i, vMesh->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, result.getRegion(region)) { vval.m = v.ydown()[i.ym()]; vval.c = v[i]; vval.p = v.yup()[i.yp()]; @@ -352,7 +349,7 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg BOUT_OMP(parallel) { stencil fval, vval; - BOUT_FOR_INNER(i, vMesh->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, result.getRegion(region)) { fval.m = f_fa[i.ym()]; fval.c = f_fa[i]; fval.p = f_fa[i.yp()]; @@ -388,7 +385,7 @@ const Field3D Grad_par_LtoC(const Field3D &var) { Coordinates *metric = var.getCoordinates(CELL_CENTRE); if (var.hasYupYdown()) { - BOUT_FOR(i, varMesh->getRegion3D("RGN_NOBNDRY")) { + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { result[i] = (var.yup()[i.yp()] - var[i]) / (metric->dy[i]*sqrt(metric->g_22[i])); } } else { @@ -396,7 +393,7 @@ const Field3D Grad_par_LtoC(const Field3D &var) { Field3D var_fa = varMesh->toFieldAligned(var); - BOUT_FOR(i, varMesh->getRegion3D("RGN_NOBNDRY")) { + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { result[i] = (var_fa[i.yp()] - var_fa[i]) / (metric->dy[i]*sqrt(metric->g_22[i])); } result = varMesh->fromFieldAligned(result); @@ -413,7 +410,7 @@ const Field2D Grad_par_LtoC(const Field2D &var) { Coordinates *metric = var.getCoordinates(CELL_CENTRE); - BOUT_FOR(i, varMesh->getRegion2D("RGN_NOBNDRY")) { + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { result[i] = (var[i.yp()] - var[i]) / (metric->dy[i] * sqrt(metric->g_22[i])); } @@ -854,7 +851,7 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, const BoutReal fac = 1.0 / (12 * metric->dz); const int ncz = mesh->LocalNz; - BOUT_FOR(j2D, mesh->getRegion2D("RGN_NOBNDRY")) { + BOUT_FOR(j2D, result.getRegion("RGN_NOBNDRY")) { // Get constants for this iteration const BoutReal spacingFactor = fac / metric->dx[j2D]; const int jy = j2D.y(), jx = j2D.x(); @@ -1138,7 +1135,7 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, Field3D f_temp = f; Field3D g_temp = g; - BOUT_FOR(j2D, mesh->getRegion2D("RGN_NOBNDRY")) { + BOUT_FOR(j2D, result.getRegion("RGN_NOBNDRY")) { const BoutReal spacingFactor = partialFactor / metric->dx[j2D]; const int jy = j2D.y(), jx = j2D.x(); const int xm = jx - 1, xp = jx + 1; diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index 75d3debaf5..d613228483 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -146,8 +146,8 @@ namespace FV { } Coordinates *coord = fin.getCoordinates(); - - BOUT_FOR(i, mesh->getRegion3D("RGN_ALL")) { + + BOUT_FOR(i, result.getRegion("RGN_ALL")) { // Calculate flux at upper surface const auto iyp = i.yp(); diff --git a/src/mesh/interpolation.cxx b/src/mesh/interpolation.cxx index b3b9285811..a979df641f 100644 --- a/src/mesh/interpolation.cxx +++ b/src/mesh/interpolation.cxx @@ -91,7 +91,7 @@ const Field3D interp_to(const Field3D &var, CELL_LOC loc, REGION region) { BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, fieldmesh->getRegion3D("RGN_NOBNDRY")) { + BOUT_FOR_INNER(i, result.getRegion("RGN_NOBNDRY")) { // Set stencils s.mm = var[i.xmm()]; s.m = var[i.xm()]; @@ -127,7 +127,7 @@ const Field3D interp_to(const Field3D &var, CELL_LOC loc, REGION region) { "/double-down fields, then we can use this case."); BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, fieldmesh->getRegion3D("RGN_NOBNDRY")) { + BOUT_FOR_INNER(i, result.getRegion("RGN_NOBNDRY")) { // Set stencils s.m = var.ydown()[i.ym()]; s.c = var[i]; @@ -162,7 +162,7 @@ const Field3D interp_to(const Field3D &var, CELL_LOC loc, REGION region) { // This allows higher-order methods to be used BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, fieldmesh->getRegion3D("RGN_NOBNDRY")) { + BOUT_FOR_INNER(i, result.getRegion("RGN_NOBNDRY")) { // Set stencils s.mm = var_fa[i.ymm()]; s.m = var_fa[i.ym()]; @@ -190,7 +190,7 @@ const Field3D interp_to(const Field3D &var, CELL_LOC loc, REGION region) { // stencil for interp, then this will be useful BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, fieldmesh->getRegion3D("RGN_NOBNDRY")) { + BOUT_FOR_INNER(i, result.getRegion("RGN_NOBNDRY")) { // Set stencils s.m = var_fa[i.ym()]; s.c = var_fa[i]; @@ -221,7 +221,7 @@ const Field3D interp_to(const Field3D &var, CELL_LOC loc, REGION region) { BOUT_OMP(parallel) { stencil s; - BOUT_FOR_INNER(i, fieldmesh->getRegion3D(region_str)) { + BOUT_FOR_INNER(i, result.getRegion(region_str)) { s.mm = var[i.zmm()]; s.m = var[i.zm()]; s.c = var[i]; @@ -311,7 +311,7 @@ const Field2D interp_to(const Field2D &var, CELL_LOC loc, REGION region) { case CELL_XLOW: { ASSERT0(fieldmesh->xstart >= 2); // At least 2 boundary cells needed for interpolation in x-direction - BOUT_FOR(i, fieldmesh->getRegion2D("RGN_NOBNDRY")) { + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { // Set stencils s.c = var[i]; @@ -341,7 +341,7 @@ const Field2D interp_to(const Field2D &var, CELL_LOC loc, REGION region) { // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used - BOUT_FOR(i, fieldmesh->getRegion2D("RGN_NOBNDRY")) { + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { // Set stencils s.c = var[i]; s.p = var[i.yp()]; @@ -366,7 +366,7 @@ const Field2D interp_to(const Field2D &var, CELL_LOC loc, REGION region) { // Note: at the moment we cannot reach this case because of the // 'ASSERT0(fieldmesh->ystart >=2)' above, but if we implement a 3-point // stencil for interp, then this will be useful - BOUT_FOR(i, fieldmesh->getRegion2D("RGN_NOBNDRY")) { + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { // Set stencils s.c = var[i]; s.p = var[i.yp()]; diff --git a/src/physics/sourcex.cxx b/src/physics/sourcex.cxx index 4655b94582..45b484961e 100644 --- a/src/physics/sourcex.cxx +++ b/src/physics/sourcex.cxx @@ -21,7 +21,7 @@ const Field2D source_tanhx(const Field2D &UNUSED(f), BoutReal swidth, BoutReal s result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary - BOUT_FOR(i, mesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal lx = mesh->GlobalX(i.x()) - slength; BoutReal dampl = TanH(lx / swidth); result[i] = 0.5 * (1.0 - dampl); @@ -40,7 +40,7 @@ const Field2D source_expx2(const Field2D &UNUSED(f), BoutReal swidth, BoutReal s result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary - BOUT_FOR(i, mesh->getRegion2D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal lx = mesh->GlobalX(i.x()) - slength; BoutReal dampl = exp(-lx * lx / swidth / swidth); result[i] = dampl; @@ -59,7 +59,7 @@ const Field3D sink_tanhx(const Field2D &UNUSED(f0), const Field3D &f, BoutReal s result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary - BOUT_FOR(i, mesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal rlx = 1. - mesh->GlobalX(i.x()) - slength; BoutReal dampr = TanH(rlx / swidth); result[i] = 0.5 * (1.0 - dampr) * f[i]; @@ -79,7 +79,7 @@ const Field3D mask_x(const Field3D &f, bool UNUSED(BoutRealspace)) { result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary - BOUT_FOR(i, mesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal lx = mesh->GlobalX(i.x()); BoutReal dampl = TanH(lx / 40.0); BoutReal dampr = TanH((1. - lx) / 40.0); @@ -102,7 +102,7 @@ const Field3D sink_tanhxl(const Field2D &UNUSED(f0), const Field3D &f, BoutReal result.allocate(); - BOUT_FOR(i, mesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal lx = mesh->GlobalX(i.x()) - slength; BoutReal dampl = TanH(lx / swidth); @@ -122,7 +122,7 @@ const Field3D sink_tanhxr(const Field2D &UNUSED(f0), const Field3D &f, BoutReal Field3D result; result.allocate(); - BOUT_FOR(i, mesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal rlx = 1. - mesh->GlobalX(i.x()) - slength; BoutReal dampr = TanH(rlx / swidth); @@ -147,7 +147,7 @@ const Field3D buff_x(const Field3D &f, bool UNUSED(BoutRealspace)) { const BoutReal deltal = 0.05; const BoutReal deltar = 0.05; - BOUT_FOR(i, mesh->getRegion3D("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal lx = mesh->GlobalX(i.x()); BoutReal rlx = 1. - lx; diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 63e259540f..40dc10d73c 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -345,7 +345,7 @@ const Field3D D2DYDZ(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGI / (coords->dy(i,j) * coords->dz); } // TODO: use region aware implementation - // BOUT_FOR(i, f.getMesh()->getRegion3D(REGION_STRING(region))) { + // BOUT_FOR(i, f.getRegion(region)) { // result[i] = 0.25*( +(f[i.offset(0,1, 1)] - f[i.offset(0,-1, 1)]) // / (coords->dy[i.yp()]) // -(f[i.offset(0,1,-1)] - f[i.offset(0,-1,-1)]) From e74f5b70efa66ad3bbc8d36a05080f57c96be715 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 12 Oct 2018 19:13:12 +0100 Subject: [PATCH 0072/1783] Correct spelling of BoutNaN --- src/invert/laplace/impls/multigrid/multigrid_laplace.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index 758064481d..df3fef956c 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -429,7 +429,7 @@ BOUT_OMP(for) #if CHECK > 2 // Make any unused elements NaN so that user does not try to do calculations with them - result = BoutNan; + result = BoutNaN; #endif // Copy solution into a FieldPerp to return BOUT_OMP(parallel default(shared) ) From 911fdce3f1aa4ce4c963edd44afeef58b732e76f Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 12 Oct 2018 19:55:56 +0100 Subject: [PATCH 0073/1783] Fix multigrid laplace -- can't use operator= to set BoutNaN --- src/invert/laplace/impls/multigrid/multigrid_laplace.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index df3fef956c..49660ffe64 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -429,7 +429,7 @@ BOUT_OMP(for) #if CHECK > 2 // Make any unused elements NaN so that user does not try to do calculations with them - result = BoutNaN; + BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = BoutNaN; } #endif // Copy solution into a FieldPerp to return BOUT_OMP(parallel default(shared) ) From 5dd7cbeeb012673137bf3ddcf541d3a5d4c73fdf Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 13 Oct 2018 00:02:50 +0100 Subject: [PATCH 0074/1783] Save run information to settings file To enable post-processing scripts to easily get things like BOUT++ revision and simulation run time, put in options so they're saved to BOUT.settings. --- src/bout++.cxx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index a81421b58b..b2177ab01b 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -66,7 +66,7 @@ const char DEFAULT_LOG[] = "BOUT.log"; #include #include -#include +#include #include #include @@ -401,6 +401,18 @@ int BoutInitialise(int &argc, char **&argv) { // Get options override from command-line reader->parseCommandLine(options, argc, argv); + // Put some run information in the options. + // This is mainly so it can be easily read in post-processing + auto &runinfo = Options::root()["run"]; + + // Note: have to force value, since may already be set if a previously + // output BOUT.settings file was used as input + runinfo["version"].force(BOUT_VERSION_STRING, ""); + runinfo["revision"].force(REV, ""); + + time_t start_time = time(nullptr); + runinfo["started"].force(ctime(&start_time), ""); + // Save settings if (BoutComm::rank() == 0) { reader->write(options, "%s/%s", data_dir, set_file); @@ -454,6 +466,7 @@ int BoutInitialise(int &argc, char **&argv) { output_error.write("Error encountered during initialisation: %s\n", e.what()); throw; } + return 0; } @@ -479,6 +492,10 @@ int BoutFinalise() { string data_dir; Options::getRoot()->get("datadir", data_dir, "data"); + // Set the end time in the settings file + time_t end_time = time(nullptr); + Options::root()["run"]["finished"].force(ctime(&end_time), ""); + OptionsReader *reader = OptionsReader::getInstance(); std::string settingsfile; OPTION(Options::getRoot(), settingsfile, ""); From c0fa064e9f74e03a359d4c2b66483c61121ea9e7 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 15 Oct 2018 12:48:42 +0100 Subject: [PATCH 0075/1783] Template applyXdiff on Field type to remove duplicated code. Note appropriate type of field for template can be inferred from function signature and hence we don't need to explicitly specify this at the call sites --- include/bout/mesh.hxx | 7 +-- src/mesh/index_derivs.cxx | 113 +++----------------------------------- 2 files changed, 11 insertions(+), 109 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 41ecbd41d0..4a0d1bf273 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -724,11 +724,8 @@ class Mesh { void derivs_init(Options* options); /// Loop over mesh, applying a stencil in the X direction - const Field2D applyXdiff(const Field2D &var, deriv_func func, - CELL_LOC loc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY); - - const Field3D applyXdiff(const Field3D &var, deriv_func func, + template + const T applyXdiff(const T &var, deriv_func func, CELL_LOC loc = CELL_DEFAULT, REGION region = RGN_NOBNDRY); diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 73a0faf773..6c3e0bf2ea 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -639,110 +639,15 @@ void Mesh::derivs_init(Options *options) { *******************************************************************************/ // X derivative - -const Field2D Mesh::applyXdiff(const Field2D &var, Mesh::deriv_func func, +template +const T Mesh::applyXdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, REGION region) { - ASSERT1(this == var.getMesh()); - ASSERT1(var.isAllocated()); - CELL_LOC inloc = var.getLocation(); - if (outloc == CELL_DEFAULT) - outloc = inloc; - // Allowed staggers: - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_XLOW) || - (outloc == CELL_XLOW && inloc == CELL_CENTRE)); - - if (var.getNx() == 1) { - auto tmp = Field2D(0., this); - tmp.setLocation(var.getLocation()); - return tmp; - } + static_assert( + std::is_base_of::value + || std::is_base_of::value, + "applyXdiff only works on Field2D or Field3D input" + ); - Field2D result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - if (this->StaggerGrids && (outloc != inloc)) { - // Staggered differencing - - if (this->xstart > 1) { - // More than one guard cell, so set pp and mm values - // This allows higher-order methods to be used - if (outloc == CELL_XLOW) { - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } - } else { - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } - } - } else { - // Only one guard cell, so no pp or mm values - if (outloc == CELL_XLOW) { - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } - } else { - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } - } - } - } else { - // Non-staggered differencing - if (this->xstart > 1) { - // More than one guard cell, so set pp and mm values - // This allows higher-order methods to be used - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } - } else { - // Only one guard cell, so no pp or mm values - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } - } - } - -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; -#endif - - return result; -} - -const Field3D Mesh::applyXdiff(const Field3D &var, Mesh::deriv_func func, - CELL_LOC outloc, REGION region) { // Check that the mesh is correct ASSERT1(this == var.getMesh()); // Check that the input variable has data @@ -756,12 +661,12 @@ const Field3D Mesh::applyXdiff(const Field3D &var, Mesh::deriv_func func, (outloc == CELL_XLOW && inloc == CELL_CENTRE)); if (var.getNx() == 1) { - auto tmp = Field3D(0., this); + auto tmp = T(0., this); tmp.setLocation(var.getLocation()); return tmp; } - Field3D result(this); + T result(this); result.allocate(); // Make sure data allocated result.setLocation(outloc); From 6b52f667fd4dfa0393858f4ca879248a760a8d36 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 15 Oct 2018 12:51:33 +0100 Subject: [PATCH 0076/1783] Fix output location of shortcut return in applyXdiff --- src/mesh/index_derivs.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 6c3e0bf2ea..0196617a15 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -662,7 +662,7 @@ const T Mesh::applyXdiff(const T &var, Mesh::deriv_func func, if (var.getNx() == 1) { auto tmp = T(0., this); - tmp.setLocation(var.getLocation()); + tmp.setLocation(outloc); return tmp; } From 4707ea42e747343c35af986d80a82b046862dd76 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 15 Oct 2018 14:22:20 +0100 Subject: [PATCH 0077/1783] Add Field2D versions of to/fromFieldAligned --- include/bout/mesh.hxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 4a0d1bf273..14e5425ecc 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -612,10 +612,17 @@ class Mesh { const Field3D toFieldAligned(const Field3D &f) { return getParallelTransform().toFieldAligned(f); } + const Field2D toFieldAligned(const Field2D &f) { + return f; + } + /// Convert back into standard form const Field3D fromFieldAligned(const Field3D &f) { return getParallelTransform().fromFieldAligned(f); } + const Field2D fromFieldAligned(const Field2D &f) { + return f; + } bool canToFromFieldAligned() { return getParallelTransform().canToFromFieldAligned(); From 88bd7a5b77c50ca28d232fc2d8b27cd417922cd1 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 15 Oct 2018 14:23:40 +0100 Subject: [PATCH 0078/1783] Add hasYupDown to Field2D --- include/field2d.hxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/field2d.hxx b/include/field2d.hxx index 5c7ba99d24..a54503c5b1 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -113,6 +113,11 @@ class Field2D : public Field, public FieldData { */ int getNz() const override {return 1;}; + /// Check if this field has yup and ydown fields + bool hasYupYdown() const { + return true; + } + Field2D& yup() { return *this; } From 3edc6e97a8025e788abcee398302d89970e6e9f9 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 15 Oct 2018 14:24:05 +0100 Subject: [PATCH 0079/1783] Template applyYdiff on Field type --- include/bout/mesh.hxx | 7 ++-- src/mesh/index_derivs.cxx | 75 +++++++-------------------------------- 2 files changed, 15 insertions(+), 67 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 14e5425ecc..fe2d288b4a 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -736,11 +736,8 @@ class Mesh { CELL_LOC loc = CELL_DEFAULT, REGION region = RGN_NOBNDRY); - const Field2D applyYdiff(const Field2D &var, deriv_func func, - CELL_LOC loc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY); - - const Field3D applyYdiff(const Field3D &var, deriv_func func, + template + const T applyYdiff(const T &var, deriv_func func, CELL_LOC loc = CELL_DEFAULT, REGION region = RGN_NOBNDRY); diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 0196617a15..d6e459db57 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -752,86 +752,38 @@ const T Mesh::applyXdiff(const T &var, Mesh::deriv_func func, } // Y derivative +template +const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, + REGION region) { -const Field2D Mesh::applyYdiff(const Field2D &var, Mesh::deriv_func func, CELL_LOC outloc, - REGION region) { - ASSERT1(this == var.getMesh()); - // Check that the input variable has data - ASSERT1(var.isAllocated()); - - CELL_LOC inloc = var.getLocation(); - if (outloc == CELL_DEFAULT) - outloc = inloc; - // Allowed staggers: - ASSERT1(outloc == inloc); + static_assert(std::is_base_of::value || std::is_base_of::value, + "applyYdiff only works on Field2D or Field3D input"); - if (var.getNy() == 1) { - auto tmp = Field2D(0., this); - tmp.setLocation(var.getLocation()); - return tmp; - } - - Field2D result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - if (this->ystart > 1) { - // More than one guard cell, so set pp and mm values - // This allows higher-order methods to be used - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } - } else { - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } - } - -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_yup = result.bndry_ydown = false; -#endif - - return result; -} - -const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_LOC outloc, - REGION region) { ASSERT1(this == var.getMesh()); // Check that the input variable has data ASSERT1(var.isAllocated()); + // Cell location of the input field CELL_LOC inloc = var.getLocation(); if (outloc == CELL_DEFAULT) outloc = inloc; + // Allowed staggers: ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_YLOW) || (outloc == CELL_YLOW && inloc == CELL_CENTRE)); if (var.getNy() == 1) { - auto tmp = Field3D(0., this); - tmp.setLocation(var.getLocation()); + auto tmp = T(0., this); + tmp.setLocation(outloc); return tmp; } - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - - Field3D result(this); + T result(this); result.allocate(); // Make sure data allocated result.setLocation(outloc); - if (var.hasYupYdown() && ((&var.yup() != &var) || (&var.ydown() != &var))) { + if (std::is_base_of::value && var.hasYupYdown() && + ((&var.yup() != &var) || (&var.ydown() != &var))) { // Field "var" has distinct yup and ydown fields which // will be used to calculate a derivative along // the magnetic field @@ -869,8 +821,7 @@ const Field3D Mesh::applyYdiff(const Field3D &var, Mesh::deriv_func func, CELL_L } } else { // var has no yup/ydown fields, so we need to shift into field-aligned coordinates - - Field3D var_fa = this->toFieldAligned(var); + T var_fa = this->toFieldAligned(var); if (this->StaggerGrids && (outloc != inloc)) { // Staggered differencing From fefcf87cb53de58dffdcb7d8c010aa5b4815f155 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 15 Oct 2018 15:53:05 +0100 Subject: [PATCH 0080/1783] Template applyZdiff on Field type --- include/bout/mesh.hxx | 3 ++- src/mesh/index_derivs.cxx | 51 ++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index fe2d288b4a..a54c22ea3d 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -741,7 +741,8 @@ class Mesh { CELL_LOC loc = CELL_DEFAULT, REGION region = RGN_NOBNDRY); - const Field3D applyZdiff(const Field3D &var, Mesh::deriv_func func, + template + const T applyZdiff(const T &var, deriv_func func, CELL_LOC loc = CELL_DEFAULT, REGION region = RGN_NOBNDRY); diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index d6e459db57..c82ab6d64d 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -904,30 +904,63 @@ const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, } // Z derivative +template +const T Mesh::applyZdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, + REGION region) { + static_assert(std::is_base_of::value || std::is_base_of::value, + "applyZdiff only works on Field2D or Field3D input"); -const Field3D Mesh::applyZdiff(const Field3D &var, Mesh::deriv_func func, CELL_LOC outloc, - REGION region) { ASSERT1(this == var.getMesh()); // Check that the input variable has data ASSERT1(var.isAllocated()); + CELL_LOC inloc = var.getLocation(); - // Allowed staggers: if (outloc == CELL_DEFAULT) outloc = inloc; - ASSERT1(outloc == inloc); + + // Allowed staggers: + ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_ZLOW) || + (outloc == CELL_ZLOW && inloc == CELL_CENTRE)); if (var.getNz() == 1) { - auto tmp = Field3D(0., this); - tmp.setLocation(var.getLocation()); + auto tmp = T(0., this); + tmp.setLocation(outloc); return tmp; } - Field3D result(this); + T result(this); result.allocate(); // Make sure data allocated result.setLocation(outloc); - // Check that the input variable has data - ASSERT1(var.isAllocated()); + if (this->StaggerGrids && (outloc != inloc)) { + // Staggered differencing + if (outloc == CELL_ZLOW) { + BOUT_OMP(parallel) { + stencil s; + BOUT_FOR_INNER(i, result.getRegion(region)) { + populateStencil(s, var, i); + result[i] = func(s); + } + } + } else { + BOUT_OMP(parallel) { + stencil s; + BOUT_FOR_INNER(i, result.getRegion(region)) { + populateStencil(s, var, i); + result[i] = func(s); + } + } + } + } else { + // Non-staggered differencing + BOUT_OMP(parallel) { + stencil s; + BOUT_FOR_INNER(i, result.getRegion(region)) { + populateStencil(s, var, i); + result[i] = func(s); + } + } + } BOUT_OMP(parallel) { From 00e6d8d4cea20984d867b27c365b0432ae691960 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 15 Oct 2018 15:55:22 +0100 Subject: [PATCH 0081/1783] Small tidy of static_assert --- src/mesh/index_derivs.cxx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index c82ab6d64d..b2bdb88941 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -642,12 +642,10 @@ void Mesh::derivs_init(Options *options) { template const T Mesh::applyXdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, REGION region) { - static_assert( - std::is_base_of::value - || std::is_base_of::value, - "applyXdiff only works on Field2D or Field3D input" - ); - + + static_assert(std::is_base_of::value || std::is_base_of::value, + "applyXdiff only works on Field2D or Field3D input"); + // Check that the mesh is correct ASSERT1(this == var.getMesh()); // Check that the input variable has data From 8d411875122cdd963f8ac462b54384eeff57e749 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 15 Oct 2018 16:41:52 +0100 Subject: [PATCH 0082/1783] Refactor apply?diff routines to reduce number of direction specific statements --- include/bout/mesh.hxx | 5 +++ src/mesh/index_derivs.cxx | 80 +++++++++++++++++++++++++++++---------- 2 files changed, 64 insertions(+), 21 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index a54c22ea3d..2c9f009b5f 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -746,6 +746,11 @@ class Mesh { CELL_LOC loc = CELL_DEFAULT, REGION region = RGN_NOBNDRY); + template + void applyDiffKernel(const T &var, deriv_func func, T &result, + REGION region = RGN_NOBNDRY); + + private: /// Allocates default Coordinates objects std::shared_ptr createDefaultCoordinates(const CELL_LOC location); diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index b2bdb88941..32c34c948c 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -654,11 +654,20 @@ const T Mesh::applyXdiff(const T &var, Mesh::deriv_func func, CELL_LOC inloc = var.getLocation(); if (outloc == CELL_DEFAULT) outloc = inloc; + + // Determine what the non-centre allowed location is for outloc + CELL_LOC allowedStaggerLoc; + allowedStaggerLoc = CELL_XLOW; + // Allowed staggers: - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_XLOW) || - (outloc == CELL_XLOW && inloc == CELL_CENTRE)); + ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == allowedStaggerLoc) || + (outloc == allowedStaggerLoc && inloc == CELL_CENTRE)); - if (var.getNx() == 1) { + int nPoint, nGuard; + nPoint = var.getNx(); + nGuard = xstart; + + if (nPoint == 1) { auto tmp = T(0., this); tmp.setLocation(outloc); return tmp; @@ -671,11 +680,11 @@ const T Mesh::applyXdiff(const T &var, Mesh::deriv_func func, if (this->StaggerGrids && (outloc != inloc)) { // Staggered differencing - if (this->xstart > 1) { + if (nGuard > 1) { // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used - if (outloc == CELL_XLOW) { - BOUT_OMP(parallel) + if (outloc == allowedStaggerLoc) { + BOUT_OMP(parallel) { stencil s; BOUT_FOR_INNER(i, result.getRegion(region)) { @@ -695,8 +704,8 @@ const T Mesh::applyXdiff(const T &var, Mesh::deriv_func func, } } else { // Only one guard cell, so no pp or mm values - if (outloc == CELL_XLOW) { - BOUT_OMP(parallel) + if (outloc == allowedStaggerLoc) { + BOUT_OMP(parallel) { stencil s; BOUT_FOR_INNER(i, result.getRegion(region)) { @@ -717,7 +726,7 @@ const T Mesh::applyXdiff(const T &var, Mesh::deriv_func func, } } else { // Non-staggered differencing - if (this->xstart > 1) { + if (nGuard > 1) { // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used BOUT_OMP(parallel) @@ -766,11 +775,19 @@ const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, if (outloc == CELL_DEFAULT) outloc = inloc; + // Determine what the non-centre allowed location is for outloc + CELL_LOC allowedStaggerLoc; + allowedStaggerLoc = CELL_YLOW; + // Allowed staggers: - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_YLOW) || - (outloc == CELL_YLOW && inloc == CELL_CENTRE)); + ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == allowedStaggerLoc) || + (outloc == allowedStaggerLoc && inloc == CELL_CENTRE)); + + int nPoint, nGuard; + nPoint = var.getNy(); + nGuard = ystart; - if (var.getNy() == 1) { + if (nPoint == 1) { auto tmp = T(0., this); tmp.setLocation(outloc); return tmp; @@ -788,7 +805,7 @@ const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, if (this->StaggerGrids && (outloc != inloc)) { // Staggered differencing - if (outloc == CELL_YLOW) { + if (outloc == allowedStaggerLoc) { BOUT_OMP(parallel) { stencil s; BOUT_FOR_INNER(i, result.getRegion(region)) { @@ -824,10 +841,10 @@ const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, if (this->StaggerGrids && (outloc != inloc)) { // Staggered differencing - if (this->ystart > 1) { + if (nGuard > 1) { // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used - if (outloc == CELL_YLOW) { + if (outloc == allowedStaggerLoc) { BOUT_OMP(parallel) { stencil s; BOUT_FOR_INNER(i, result.getRegion(region)) { @@ -846,7 +863,7 @@ const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, } } else { // Only one guard cell, so no pp or mm values - if (outloc == CELL_YLOW) { + if (outloc == allowedStaggerLoc) { BOUT_OMP(parallel) { stencil s; BOUT_FOR_INNER(i, result.getRegion(region)) { @@ -867,7 +884,7 @@ const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, } else { // Non-staggered differencing - if (this->ystart > 1) { + if (nGuard > 1) { // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used BOUT_OMP(parallel) { @@ -905,6 +922,7 @@ const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, template const T Mesh::applyZdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, REGION region) { + static_assert(std::is_base_of::value || std::is_base_of::value, "applyZdiff only works on Field2D or Field3D input"); @@ -916,11 +934,19 @@ const T Mesh::applyZdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, if (outloc == CELL_DEFAULT) outloc = inloc; + // Determine what the non-centre allowed location is for outloc + CELL_LOC allowedStaggerLoc; + allowedStaggerLoc = CELL_ZLOW; + // Allowed staggers: - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_ZLOW) || - (outloc == CELL_ZLOW && inloc == CELL_CENTRE)); + ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == allowedStaggerLoc) || + (outloc == allowedStaggerLoc && inloc == CELL_CENTRE)); + + int nPoint, nGuard; + nPoint = var.getNz(); + nGuard = 2; - if (var.getNz() == 1) { + if (nPoint == 1) { auto tmp = T(0., this); tmp.setLocation(outloc); return tmp; @@ -932,7 +958,7 @@ const T Mesh::applyZdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, if (this->StaggerGrids && (outloc != inloc)) { // Staggered differencing - if (outloc == CELL_ZLOW) { + if (outloc == allowedStaggerLoc) { BOUT_OMP(parallel) { stencil s; BOUT_FOR_INNER(i, result.getRegion(region)) { @@ -972,6 +998,18 @@ const T Mesh::applyZdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, return result; } +template +void Mesh::applyDiffKernel(const T &var, Mesh::deriv_func func, T &result, + REGION region) { + BOUT_OMP(parallel) { + stencil s; + BOUT_FOR_INNER(i, result.getRegion(region)) { + populateStencil(s, var, i); + result[i] = func(s); + } + } + return; +} /******************************************************************************* * First central derivatives *******************************************************************************/ From 83822e10a61fed4493a8771c9650a0d435c14d5f Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 15 Oct 2018 16:59:06 +0100 Subject: [PATCH 0083/1783] Make use of applyDiffKernel to reduce repeated code in apply?diff --- src/mesh/index_derivs.cxx | 165 +++++--------------------------------- 1 file changed, 21 insertions(+), 144 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 32c34c948c..68c7eb6bbd 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -684,44 +684,16 @@ const T Mesh::applyXdiff(const T &var, Mesh::deriv_func func, // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used if (outloc == allowedStaggerLoc) { - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } + applyDiffKernel(var, func, result, region); } else { - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } + applyDiffKernel(var, func, result, region); } } else { // Only one guard cell, so no pp or mm values if (outloc == allowedStaggerLoc) { - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } + applyDiffKernel(var, func, result, region); } else { - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } + applyDiffKernel(var, func, result, region); } } } else { @@ -729,24 +701,10 @@ const T Mesh::applyXdiff(const T &var, Mesh::deriv_func func, if (nGuard > 1) { // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } + applyDiffKernel(var, func, result, region); } else { // Only one guard cell, so no pp or mm values - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } + applyDiffKernel(var, func, result, region); } } @@ -806,33 +764,16 @@ const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, if (this->StaggerGrids && (outloc != inloc)) { // Staggered differencing if (outloc == allowedStaggerLoc) { - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } + applyDiffKernel(var, func, result, + region); } else { - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } + applyDiffKernel(var, func, result, + region); } } else { // Non-staggered - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, var.getRegion(region)) { - // Set stencils - populateStencil(s, var, i); - result[i] = func(s); - } - } + applyDiffKernel(var, func, result, + region); } } else { // var has no yup/ydown fields, so we need to shift into field-aligned coordinates @@ -840,45 +781,20 @@ const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, if (this->StaggerGrids && (outloc != inloc)) { // Staggered differencing - if (nGuard > 1) { // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used if (outloc == allowedStaggerLoc) { - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var_fa, i); - result[i] = func(s); - } - } + applyDiffKernel(var_fa, func, result, region); } else { - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var_fa, i); - result[i] = func(s); - } - } + applyDiffKernel(var_fa, func, result, region); } } else { // Only one guard cell, so no pp or mm values if (outloc == allowedStaggerLoc) { - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var_fa, i); - result[i] = func(s); - } - } + applyDiffKernel(var_fa, func, result, region); } else { - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var_fa, i); - result[i] = func(s); - } - } + applyDiffKernel(var_fa, func, result, region); } } } else { @@ -887,22 +803,10 @@ const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, if (nGuard > 1) { // More than one guard cell, so set pp and mm values // This allows higher-order methods to be used - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var_fa, i); - result[i] = func(s); - } - } + applyDiffKernel(var_fa, func, result, region); } else { // Only one guard cell, so no pp or mm values - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var_fa, i); - result[i] = func(s); - } - } + applyDiffKernel(var_fa, func, result, region); } } @@ -959,40 +863,13 @@ const T Mesh::applyZdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, if (this->StaggerGrids && (outloc != inloc)) { // Staggered differencing if (outloc == allowedStaggerLoc) { - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } + applyDiffKernel(var, func, result, region); } else { - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } + applyDiffKernel(var, func, result, region); } } else { // Non-staggered differencing - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } - } - - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } + applyDiffKernel(var, func, result, region); } return result; From c66e941a3d369d94bbdb6aada5602a995e6e4cd2 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 15 Oct 2018 17:12:54 +0100 Subject: [PATCH 0084/1783] Remove explicit `this->` from Mesh member functions --- src/mesh/index_derivs.cxx | 124 ++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 58 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 68c7eb6bbd..528ca211d5 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -677,7 +677,7 @@ const T Mesh::applyXdiff(const T &var, Mesh::deriv_func func, result.allocate(); // Make sure data allocated result.setLocation(outloc); - if (this->StaggerGrids && (outloc != inloc)) { + if (StaggerGrids && (outloc != inloc)) { // Staggered differencing if (nGuard > 1) { @@ -708,11 +708,6 @@ const T Mesh::applyXdiff(const T &var, Mesh::deriv_func func, } } -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; -#endif - return result; } @@ -761,7 +756,7 @@ const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, // will be used to calculate a derivative along // the magnetic field - if (this->StaggerGrids && (outloc != inloc)) { + if (StaggerGrids && (outloc != inloc)) { // Staggered differencing if (outloc == allowedStaggerLoc) { applyDiffKernel(var, func, result, @@ -777,9 +772,9 @@ const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, } } else { // var has no yup/ydown fields, so we need to shift into field-aligned coordinates - T var_fa = this->toFieldAligned(var); + T var_fa = toFieldAligned(var); - if (this->StaggerGrids && (outloc != inloc)) { + if (StaggerGrids && (outloc != inloc)) { // Staggered differencing if (nGuard > 1) { // More than one guard cell, so set pp and mm values @@ -811,14 +806,9 @@ const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, } // Shift result back - result = this->fromFieldAligned(result); + result = fromFieldAligned(result); } -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; -#endif - return result; } @@ -860,16 +850,34 @@ const T Mesh::applyZdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, result.allocate(); // Make sure data allocated result.setLocation(outloc); - if (this->StaggerGrids && (outloc != inloc)) { + if (StaggerGrids && (outloc != inloc)) { // Staggered differencing - if (outloc == allowedStaggerLoc) { - applyDiffKernel(var, func, result, region); + if (nGuard > 1) { + // More than one guard cell, so set pp and mm values + // This allows higher-order methods to be used + if (outloc == allowedStaggerLoc) { + applyDiffKernel(var, func, result, region); + } else { + applyDiffKernel(var, func, result, region); + } } else { - applyDiffKernel(var, func, result, region); + // Only one guard cell, so no pp or mm values + if (outloc == allowedStaggerLoc) { + applyDiffKernel(var, func, result, region); + } else { + applyDiffKernel(var, func, result, region); + } } } else { // Non-staggered differencing - applyDiffKernel(var, func, result, region); + if (nGuard > 1) { + // More than one guard cell, so set pp and mm values + // This allows higher-order methods to be used + applyDiffKernel(var, func, result, region); + } else { + // Only one guard cell, so no pp or mm values + applyDiffKernel(var, func, result, region); + } } return result; @@ -905,7 +913,7 @@ const Field3D Mesh::indexDDX(const Field3D &f, CELL_LOC outloc, DIFF_METHOD meth ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_XLOW) || (outloc == CELL_XLOW && inloc == CELL_CENTRE)); - if (this->StaggerGrids && (outloc != inloc)) { + if (StaggerGrids && (outloc != inloc)) { // Shifting in X. Centre -> Xlow, or Xlow -> Centre func = sfDDX; // Set default @@ -943,7 +951,7 @@ const Field3D Mesh::indexDDY(const Field3D &f, CELL_LOC outloc, DIFF_METHOD meth ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_YLOW) || (outloc == CELL_YLOW && inloc == CELL_CENTRE)); - if (this->StaggerGrids && (outloc != inloc)) { + if (StaggerGrids && (outloc != inloc)) { // Shifting in Y. Centre -> Ylow, or Ylow -> Centre func = sfDDY; // Set default table = FirstStagDerivTable; // Set table for others @@ -982,7 +990,7 @@ const Field3D Mesh::indexDDZ(const Field3D &f, CELL_LOC outloc, Field3D result(this); - if (this->StaggerGrids && (outloc != inloc)) { + if (StaggerGrids && (outloc != inloc)) { // Shifting in Z. Centre -> Zlow, or Zlow -> Centre func = sfDDZ; // Set default table = FirstStagDerivTable; // Set table for others @@ -997,7 +1005,7 @@ const Field3D Mesh::indexDDZ(const Field3D &f, CELL_LOC outloc, // Use FFT BoutReal shift = 0.; // Shifting result in Z? - if (this->StaggerGrids && (outloc != inloc)) { + if (StaggerGrids && (outloc != inloc)) { if (outloc == CELL_ZLOW) { // Shifting down - multiply by exp(-0.5*i*k*dz) shift = -1.; @@ -1012,7 +1020,7 @@ const Field3D Mesh::indexDDZ(const Field3D &f, CELL_LOC outloc, result.allocate(); // Make sure data allocated // Calculate how many Z wavenumbers will be removed - const int ncz = this->LocalNz; + const int ncz = LocalNz; int kfilter = static_cast(fft_derivs_filter * ncz / 2); // truncates, rounding down if (kfilter < 0) @@ -1041,8 +1049,8 @@ const Field3D Mesh::indexDDZ(const Field3D &f, CELL_LOC outloc, // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro // here, // but should be ok for now. - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - auto i3D = this->ind2Dto3D(i, 0); + BOUT_FOR_INNER(i, getRegion2D(region_str)) { + auto i3D = ind2Dto3D(i, 0); rfft(&f[i3D], ncz, cv.begin()); // Forward FFT for (int jz = 0; jz <= kmax; jz++) { @@ -1268,7 +1276,7 @@ const Field3D Mesh::indexD2DZ2(const Field3D &f, CELL_LOC outloc, result.allocate(); // Make sure data allocated // No filtering in 2nd derivative method - const int ncz = this->LocalNz; + const int ncz = LocalNz; const int kmax = ncz / 2; // Up to and including this wavenumber index const auto region_str = REGION_STRING(region); @@ -1290,8 +1298,8 @@ const Field3D Mesh::indexD2DZ2(const Field3D &f, CELL_LOC outloc, // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro // here, // but should be ok for now. - BOUT_FOR_INNER(i, this->getRegion2D(region_str)) { - auto i3D = this->ind2Dto3D(i, 0); + BOUT_FOR_INNER(i, getRegion2D(region_str)) { + auto i3D = ind2Dto3D(i, 0); rfft(&f[i3D], ncz, cv.begin()); // Forward FFT @@ -1409,7 +1417,7 @@ const Field2D Mesh::indexVDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo func = lookupFunc(UpwindTable, method); } - ASSERT1(this->xstart > 0); // Need at least one guard cell + ASSERT1(xstart > 0); // Need at least one guard cell ASSERT1(this == f.getMesh()); ASSERT1(this == v.getMesh()); @@ -1417,7 +1425,7 @@ const Field2D Mesh::indexVDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo result.allocate(); // Make sure data allocated result.setLocation(outloc); - if (this->xstart > 1) { + if (xstart > 1) { // Two or more guard cells BOUT_OMP(parallel) { stencil s; @@ -1452,7 +1460,7 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo DIFF_METHOD method, REGION region) { TRACE("Mesh::indexVDDX(Field3D, Field3D)"); - ASSERT1(this->xstart > 0); // Need at least one guard cell + ASSERT1(xstart > 0); // Need at least one guard cell ASSERT1(this == v.getMesh()); ASSERT1(this == f.getMesh()); @@ -1488,7 +1496,7 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo // Note: The velocity stencil contains only (mm, m, p, pp) // v.p is v at +1/2, v.m is at -1/2 relative to the field f - if (this->xstart > 1) { + if (xstart > 1) { // Two or more guard cells if (vloc == CELL_XLOW) { @@ -1546,7 +1554,7 @@ const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo func = lookupFunc(table, method); } - if (this->xstart > 1) { + if (xstart > 1) { // Two or more guard cells BOUT_OMP(parallel) { stencil fs; @@ -1598,12 +1606,12 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo result.allocate(); // Make sure data allocated result.setLocation(outloc); - if (this->LocalNy == 1){ + if (LocalNy == 1) { result=0; return result; } - ASSERT1(this->ystart > 0); // Must have at least one guard cell + ASSERT1(ystart > 0); // Must have at least one guard cell if (StaggerGrids && (vloc != inloc)) { // Staggered grids enabled, and velocity at different location to value @@ -1623,7 +1631,7 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo // Note: vs.c not used for staggered differencing // vs.m is at i-1/2, vs.p is as i+1/2 if (vloc == CELL_YLOW) { - if (this->ystart > 1) { + if (ystart > 1) { // Two or more guard cells BOUT_OMP(parallel) { stencil fs, vs; @@ -1645,7 +1653,7 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo } } } else { - if (this->ystart > 1) { + if (ystart > 1) { // Two or more guard cells BOUT_OMP(parallel) { stencil fs, vs; @@ -1679,7 +1687,7 @@ const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo func = lookupFunc(table, method); } - if (this->ystart > 1) { + if (ystart > 1) { // Two or more guard cells BOUT_OMP(parallel) { stencil fs; @@ -1729,12 +1737,12 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo result.allocate(); // Make sure data allocated result.setLocation(outloc); - if (this->LocalNy == 1){ + if (LocalNy == 1) { result=0; return result; } - ASSERT1(this->ystart > 0); // Need at least one guard cell + ASSERT1(ystart > 0); // Need at least one guard cell if (StaggerGrids && (vloc != inloc)) { // Staggered grids enabled, and velocity at different location to value @@ -1782,8 +1790,8 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo // (even if one of v and f has yup/ydown fields, it doesn't make sense to // multiply them with one in field-aligned and one in non-field-aligned // coordinates) - Field3D v_fa = this->toFieldAligned(v); - Field3D f_fa = this->toFieldAligned(f); + Field3D v_fa = toFieldAligned(v); + Field3D f_fa = toFieldAligned(f); if (inloc == CELL_YLOW) { BOUT_OMP(parallel) { stencil vval, fval; @@ -1804,7 +1812,7 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo } } - result = this->fromFieldAligned(result); + result = fromFieldAligned(result); } } else { // Non-staggered case @@ -1828,10 +1836,10 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo } } else { // Not using yup/ydown fields, so first transform to field-aligned coordinates - Field3D f_fa = this->toFieldAligned(f); - Field3D v_fa = this->toFieldAligned(v); + Field3D f_fa = toFieldAligned(f); + Field3D v_fa = toFieldAligned(v); - if (this->ystart > 1) { + if (ystart > 1) { BOUT_OMP(parallel) { stencil fs; BOUT_FOR_INNER(i, result.getRegion(region)) { @@ -1849,7 +1857,7 @@ const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo } } // Shift result back - result = this->fromFieldAligned(result); + result = fromFieldAligned(result); } } @@ -1954,7 +1962,7 @@ const Field2D Mesh::indexFDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo DIFF_METHOD method, REGION region) { TRACE("Mesh::::indexFDDX(Field2D, Field2D)"); - ASSERT1(this->xstart > 0); // Need at least one guard cell + ASSERT1(xstart > 0); // Need at least one guard cell if (outloc == CELL_DEFAULT) outloc = f.getLocation(); @@ -1980,7 +1988,7 @@ const Field2D Mesh::indexFDDX(const Field2D &v, const Field2D &f, CELL_LOC outlo ASSERT1(this == v.getMesh()); ASSERT1(this == f.getMesh()); - if (this->xstart > 1) { + if (xstart > 1) { // Two or more guard cells BOUT_OMP(parallel) { stencil fs, vs; @@ -2014,7 +2022,7 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo DIFF_METHOD method, REGION region) { TRACE("Mesh::indexFDDX(Field3D, Field3D)"); - ASSERT1(this->xstart > 0); // Need at least one guard cell + ASSERT1(xstart > 0); // Need at least one guard cell CELL_LOC vloc = v.getLocation(); CELL_LOC inloc = f.getLocation(); // Input location @@ -2053,7 +2061,7 @@ const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outlo result.allocate(); // Make sure data allocated result.setLocation(outloc); - if (this->xstart > 1) { + if (xstart > 1) { // Two or more guard cells if (StaggerGrids && vloc != inloc) { if (inloc == CELL_XLOW) { @@ -2141,7 +2149,7 @@ const Field2D Mesh::indexFDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo DIFF_METHOD method, REGION region) { TRACE("Mesh::indexFDDY(Field2D, Field2D)"); - ASSERT1(this->ystart > 0); // Need at least one guard cell + ASSERT1(ystart > 0); // Need at least one guard cell ASSERT1(this == v.getMesh()); ASSERT1(this == f.getMesh()); @@ -2166,7 +2174,7 @@ const Field2D Mesh::indexFDDY(const Field2D &v, const Field2D &f, CELL_LOC outlo result.allocate(); // Make sure data allocated result.setLocation(outloc); - if (this->ystart > 1) { + if (ystart > 1) { // Two or more guard cells BOUT_OMP(parallel) { stencil fs, vs; @@ -2284,8 +2292,8 @@ const Field3D Mesh::indexFDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo // (even if one of v and f has yup/ydown fields, it doesn't make sense to // multiply them with one in field-aligned and one in non-field-aligned // coordinates) - Field3D v_fa = this->toFieldAligned(v); - Field3D f_fa = this->toFieldAligned(f); + Field3D v_fa = toFieldAligned(v); + Field3D f_fa = toFieldAligned(f); if (StaggerGrids && (inloc != vloc)) { // Non-centred stencil if (inloc == CELL_YLOW) { @@ -2318,7 +2326,7 @@ const Field3D Mesh::indexFDDY(const Field3D &v, const Field3D &f, CELL_LOC outlo } } - result = this->fromFieldAligned(result); + result = fromFieldAligned(result); } #if CHECK > 0 From 5d42de4e6ec7d6b40b64abd4b43f75bd15618e8d Mon Sep 17 00:00:00 2001 From: dschwoerer Date: Mon, 15 Oct 2018 17:16:25 +0100 Subject: [PATCH 0085/1783] Add support for enum class * Based on https://stackoverflow.com/a/36440173 - Special case enum class where required - Most generating code is the same as normal enum * Avoid python keyword None: - Add NONE alternative - Only use NONE in python * Fix indentation * Add a few comments --- .../pylib/_boutcore_build/resolve_enum.pxd.in | 143 +++++++++++------- .../_boutcore_build/resolve_enum_inv.pyx.in | 113 ++++++++------ 2 files changed, 158 insertions(+), 98 deletions(-) diff --git a/tools/pylib/_boutcore_build/resolve_enum.pxd.in b/tools/pylib/_boutcore_build/resolve_enum.pxd.in index e953a93676..ac61275487 100644 --- a/tools/pylib/_boutcore_build/resolve_enum.pxd.in +++ b/tools/pylib/_boutcore_build/resolve_enum.pxd.in @@ -1,55 +1,94 @@ +#!/usr/bin/env bash + +# We are trying to parse bout_types, to translate the list of enums to +# a python dictionary. + for file in ../../../include/bout_types.hxx other_enums.hxx do -end=${file##*/} -grep enum $file| \ - while read line -do - what=${line:5} - #echo $what - name=${what%\{*} - tmp=${what#*\{} - enums=${tmp%\}*} - echo "cdef extern from \"$end\":" - echo " cpdef enum ${name}:" - while test "$enums" - do - cur=${enums%%,*} - test "$cur" == "$enums" && enums= - cur=$(echo $cur) - enums=${enums#*,} - shrt=${cur%=*} - shrts+=" $shrt" - echo " $cur," - #echo $enums - done - echo - same=1 - continue=yes - while test $continue - do - same=$((same + 1)) - same_=${shrt::$same} - for shrt in $shrts: - do - if test ${shrt::$same} != $same_ - then - same=$((same - 1)) - continue= - break; - fi - done - done - lower=$(echo ${name}|tr [:upper:] [:lower:]) - echo "cdef inline $name resolve_${lower}(str):" - echo " opts={" - for shrt in $shrts - do - echo " \"$shrt\":$shrt," - echo " \"${shrt:$same}\":$shrt," - done - echo " }" - echo " return opts[str]" - echo - shrts= -done + end=${file##*/} + + # In each file we are checking for enums, and then parse them + grep enum $file| \ + while read line + do + # first remove the start, which is just enum + what=${line:5} + # the name is before { - maybe remove "class " from that + fullname=$(echo ${what%\{*}) + name=${fullname#class } + test "$name" = "$fullname" && class= || class=yes + # between { and } all the enums are listed + tmp=${what#*\{} + enums=${tmp%\}*} + # Split the list of enums, which are separated by "," + # Also doe some parsing, check if a value is assigned, etc + if test $class + then + cat </dev/stderr $cur + shrts+=" $shrt" + test $class && + echo " cdef $name $cur" || + echo " $cur," + #echo $enums + done + echo + same=0 + continue=yes + # check for duplicates - e.g. CENTER = CENTRE + while test $continue + do + same=$((same + 1)) + same_=${shrt::$same} + for shrt in $shrts: + do + if test ${shrt::$same} != $same_ + then + same=$((same - 1)) + continue= + break; + fi + done + done + lower=$(echo ${name}|tr [:upper:] [:lower:]) + echo "cdef inline $name resolve_${lower}(str):" + echo " opts={" + for shrt in $shrts + do + test "$shrt" = None && continue + test $class && res="$shrt" || res="$shrt" + echo &>/dev/stderr "$class - $res" + echo " \"$shrt\":$res," + test $same -gt 1 && + echo " \"${shrt:$same}\":$res," + test $class && + echo " \"${name}_${shrt}\":$res," + done + echo " }" + test $class && + echo " return <$name> opts[str]" || + echo " return opts[str]" + echo + shrts= + done done diff --git a/tools/pylib/_boutcore_build/resolve_enum_inv.pyx.in b/tools/pylib/_boutcore_build/resolve_enum_inv.pyx.in index 6a4ee28fd9..4b2005c905 100644 --- a/tools/pylib/_boutcore_build/resolve_enum_inv.pyx.in +++ b/tools/pylib/_boutcore_build/resolve_enum_inv.pyx.in @@ -1,49 +1,70 @@ +#!/usr/bin/env bash + +# We are trying to parse bout_types, to translate the list of enums to +# a python dictionary. + for file in ../../../include/bout_types.hxx other_enums.hxx do -end=${file##*/} -grep enum $file| \ - while read line -do - what=${line:5} - name=${what%\{*} - tmp=${what#*\{} - enums=${tmp%\}*} - while test "$enums" - do - cur=${enums%%,*} - test "$cur" == "$enums" && enums= - cur=$(echo $cur) - enums=${enums#*,} - shrt=${cur%=*} - shrts+=" $shrt" - done - echo - same=1 - continue=yes - while test $continue - do - same=$((same + 1)) - same_=${shrt::$same} - for shrt in $shrts: - do - if test ${shrt::$same} != $same_ - then - same=$((same - 1)) - continue= - break; - fi - done - done - lower=$(echo ${name}|tr [:upper:] [:lower:]) - echo "def _resolve_inv_${lower}(benum.$name tores):" - echo " opts={" - for shrt in $shrts - do - echo " benum.$shrt:\"${shrt:$same}\"," - done - echo " }" - echo " return opts[tores]" - echo - shrts= -done + end=${file##*/} + + # In each file we are checking for enums, and then parse them + grep enum $file| \ + while read line + do + # first remove the start, which is just enum + what=${line:5} + # the name is before { - maybe remove "class " from that + fullname=$(echo ${what%\{*}) + name=${fullname#class } + test "$name" = "$fullname" && class= || class=yes + # between { and } all the enums are listed + tmp=${what#*\{} + enums=${tmp%\}*} + # Split the list of enums, which are separated by "," + # Also doe some parsing, check if a value is assigned, etc + while test "$enums" + do + cur=${enums%%,*} + test "$cur" == "$enums" && enums= + cur=$(echo $cur) + enums=${enums#*,} + shrt=${cur%=*} + test "$shrt" = None && continue + #test $shrt = "None" && shrt=NONE && cur=${cur/None/NONE} || echo &>/dev/stderr $cur + shrts+=" $shrt" + done + echo + same=0 + continue=yes + # check for duplicates - e.g. CENTER = CENTRE + while test $continue + do + same=$((same + 1)) + same_=${shrt::$same} + for shrt in $shrts: + do + if test ${shrt::$same} != $same_ + then + same=$((same - 1)) + continue= + break; + fi + done + done + lower=$(echo ${name}|tr [:upper:] [:lower:]) + test $class && prefix="" || prefix= + test $class && + echo "def _resolve_inv_${lower}(int tores):" || + echo "def _resolve_inv_${lower}(benum.$name tores):" + echo " opts={" + for shrt in $shrts + do + test "$shrt" = None && continue + echo " $prefix benum.$shrt:\"${shrt:$same}\"," + done + echo " }" + echo " return opts[$prefix tores]" + echo + shrts= + done done From 3772f6d0e61ca488dcb636d2ea4aa0784e5017a0 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 14:13:04 +0100 Subject: [PATCH 0086/1783] Remove dataiterator and associated uses in Fields Still need to fix tests --- include/bout/dataiterator.hxx | 403 ---------------------------------- include/field.hxx | 7 - include/field2d.hxx | 37 ---- include/field3d.hxx | 90 ++------ include/fieldperp.hxx | 25 --- src/field/field2d.cxx | 46 ---- src/field/field3d.cxx | 83 +------ src/field/fieldperp.cxx | 32 --- 8 files changed, 17 insertions(+), 706 deletions(-) delete mode 100644 include/bout/dataiterator.hxx diff --git a/include/bout/dataiterator.hxx b/include/bout/dataiterator.hxx deleted file mode 100644 index 7dc57550e7..0000000000 --- a/include/bout/dataiterator.hxx +++ /dev/null @@ -1,403 +0,0 @@ -/* - - - */ - -#ifndef __DATAITERATOR_H__ -#define __DATAITERATOR_H__ - -#include -#include -#include "unused.hxx" -#include "assert.hxx" -#include "bout/deprecated.hxx" - -#ifdef _OPENMP -#include -inline int DI_spread_work(int num_work, int thread, int max_thread); -#endif - -/*! - * Set of indices - DataIterator is dereferenced into these - */ -struct Indices { - int x; - int y; - int z; -}; - -#define DI_GET_END ((void *) NULL) - -/*! - * Provides range-based iteration over indices. - * If OpenMP is enabled, then this divides work between threads. - * - * This is used mainly to loop over the indices of fields, - * and provides convenient ways to index - * - * Example - * ------- - * - * Start,end values for (x,y,z) can be specified directly: - * - * for(d = DataIterator(xs, xe, ys, ye, zs, ze); !d.done(); ++d) { - * // print index - * output.write("%d,%d,%d\n", d.x, d.y, d.z); - * // Index into a Field3D variable 'f' - * output.write("Value = %e\n", f[d]); - * } - * - * Usually DataIterator is used to loop over fields. Field3D::begin() - * and Field3D::end() return DataIterator objects: - * - * Field3D f(0.0); // Initialise field - * for(const auto &i : f) { // Loop over all indices, including guard cells - * f[i] = i.x; // Indexing using DataIterator - * } - * - */ -class DataIterator - : public std::iterator { -private: - /*! - * This initialises OpenMP threads if enabled, and - * divides iteration index ranges between threads - */ -#ifdef _OPENMP - inline void omp_init(bool end); -#endif -public: - /// Disable null constructor - DataIterator() = delete; - /*! - * Constructor. This sets index ranges. - * If OpenMP is enabled, the index range is divided - * between threads using the omp_init method. - */ - DataIterator(int xs, int xe, - int ys, int ye, - int zs, int ze) : -#ifndef _OPENMP - x(xs), y(ys), z(zs), - // start / end : start and end point of the iterator - xstart(xs), ystart(ys), zstart(zs), - xend(xe), yend(ye), zend(ze), - // Min / Max are the values of the domain we iterate over - xmin(xstart), ymin(ystart), zmin(zstart), - xmax(xend), ymax(yend), zmax(zend), -#else - // In the case of OpenMP each processor has a subset. - // Therefore we initiallise here only the common ones, i.e. the - // total size of the domain, not what this processor is doing - xmin(xs), ymin(ys), zmin(zs), - xmax(xe), ymax(ye), zmax(ze), -#endif - isEnd(false) - { -#ifdef _OPENMP - omp_init(false); -#endif - } - - /*! - * set end(); - * use as DataIterator(int,int,int,int,int,int,DI_GET_END); - */ - DataIterator(int xs, int xe, - int ys, int ye, - int zs, int ze, void* UNUSED(dummy)) : -#ifndef _OPENMP - x(xe), y(ye), z(ze), - xstart(xs), ystart(ys), zstart(zs), - xend(xe), yend(ye), zend(ze), - xmin(xstart), ymin(ystart), zmin(zstart), - xmax(xend), ymax(yend), zmax(zend), -#else - xmin(xs), ymin(ys), zmin(zs), - xmax(xe), ymax(ye), zmax(ze), -#endif - isEnd(true) - { -#ifdef _OPENMP - omp_init(true); -#endif - next(); - } - - /*! - * The index variables, updated during loop - * Should make these private and provide getters? - */ - int x, y, z; - - /// Pre-increment operator. Use this rather than post-increment when possible - DataIterator& operator++() { next(); return *this; } - - /// Post-increment operator - DataIterator operator++(int) { DataIterator tmp(*this); next(); return tmp; } - - /// Pre-decrement operator - DataIterator& operator--() { prev(); return *this; } - - /// Post-decrement operator - DataIterator operator--(int) { DataIterator tmp(*this); prev(); return tmp; } - - /// Comparison operator. Most common use is in for loops - inline bool operator!=(const DataIterator& rhs) const { - if (rhs.isEnd){ - return !this->done(); - } else { - return !(x == rhs.x && y == rhs.y && z == rhs.z); - } - } - - /*! - * Dereference operators - * These are needed because the C++11 for loop - * dereferences the iterator - */ - DataIterator& operator*() { - return *this; - } - - /*! - * Const dereference operator. - * Needed because C++11 for loop dereferences the iterator - */ - const DataIterator& operator*() const { - return *this; - } - - /*! - * Add an offset to the index for general stencils - */ - const inline Indices offset(int dx, int dy, int dz) const { - if (dz>0){ - int zp=z; - for (int j=0;j= 0); - int zp=z; - for (int j=0;j= 0); - int zm=z; - for (;i!= 0;--i) - zm = (zm == zmin ? zmax : zm-1); - return {x, y, zm }; } - // and for 2 cells - const inline Indices xpp() const { return xp(2); } - const inline Indices xmm() const { return xm(2); } - const inline Indices ypp() const { return yp(2); } - const inline Indices ymm() const { return ym(2); } - const inline Indices zpp() const { return zp(2); } - const inline Indices zmm() const { return zm(2); } - - /*! - * Resets DataIterator to the start of the range - */ - void start() { - x = xstart; y = ystart; z = zstart; - } - - /*! - * Sets DataIterator to one index past the end of the range - */ - void end() { - x = xend; y = yend; z = zend; - next(); - } - - /*! - * Checks if finished looping. Is this more efficient than - * using the more idiomatic it != DataIterator::end() ? - */ - bool done() const { -#ifndef _OPENMP - return (x > xend) || (x < xstart); -#else //_OPENMP - return (x == xend && y == yend && z > zend) - || (x == xend && y > yend) - || x > xend || - (x <= xstart && y <= ystart && z < zstart) ; -#endif //_OPENMP - } - -private: - - /// start / end : start and end point of THIS iterator -#ifndef _OPENMP - const int xstart, ystart, zstart; - const int xend, yend, zend; -#else - /// start / end : local to THIS processor - int xstart, ystart, zstart; - int xend, yend, zend; -#endif - /// min / max : size of the domain - /// same for all processors - int xmin, ymin, zmin; - int xmax, ymax, zmax; - - const bool isEnd; - /// Advance to the next index - void next() { - ++z; - if(z > zmax) { - z = zmin; - ++y; - if(y > ymax) { - y = ymin; - ++x; - } - } - } - - /// Rewind to the previous index - void prev() { - --z; - if(z < zmin) { - z = zmax; - --y; - if(y < ymin) { - y = ymax; - --x; - } - } - } -}; - -/*! - * Specifies a range of indices which can be iterated over - * and begin() and end() methods for range-based for loops - * - * Example - * ------- - * - * Index ranges can be defined manually: - * - * IndexRange r(0, 10, 0, 20, 0, 30); - * - * then iterated over using begin() and end() - * - * for( DataIterator i = r.begin(); i != r.end(); i++ ) { - * output.write("%d,%d,%d\n", i.x, i.y, i.z); - * } - * - * or the more convenient range for loop: - * - * for( const auto &i : r ) { - * output.write("%d,%d,%d\n", i.x, i.y, i.z); - * } - * - * A common use for this class is to loop over - * regions of a field: - * - * Field3D f(0.0); - * for( const auto &i : f.region(RGN_NOBNDRY) ) { - * f[i] = 1.0; - * } - * - * where RGN_NOBNDRY specifies a region not including - * boundary/guard cells. - */ -struct IndexRange { - int xstart, xend; - int ystart, yend; - int zstart, zend; - - const DataIterator begin() const { - return DataIterator(xstart, xend, - ystart, yend, - zstart, zend); - } - const DataIterator end() const { - return DataIterator(xstart, xend, - ystart, yend, - zstart, zend, DI_GET_END); - } -}; - -#ifdef _OPENMP -inline int DI_spread_work(int work,int cp,int np){ - int pp=work/np; - int rest=work%np; - int result=pp*cp; - if (rest > cp){ - result +=cp; - } else { - result +=rest; - } - return result; -}; - -inline void DataIterator::omp_init(bool end){ - // In the case of OPENMP we need to calculate the range - int threads=omp_get_num_threads(); - if (threads > 1){ - int ny=ymax-ymin+1; - int nz=zmax-zmin+1; - int work = (xmax-xmin+1)*ny*nz; - int current_thread = omp_get_thread_num(); - int begin_index = DI_spread_work(work,current_thread,threads); - int end_index = DI_spread_work(work,current_thread+1,threads); - --end_index; - zend = (end_index % nz) + zmin; - zstart = (begin_index % nz) + zmin; - end_index /= nz; - begin_index /= nz; - yend = (end_index % ny) + ymin; - ystart = (begin_index % ny) + ymin; - end_index /= ny; - begin_index /= ny; - xend = end_index + xmin; - xstart = begin_index + xmin; - } else { - zstart = zmin; - zend = zmax; - ystart = ymin; - yend = ymax; - xstart = xmin; - xend = xmax; - } - if (!end){ - x=xstart; - y=ystart; - z=zstart; - } else { - x=xend; - y=yend; - z=zend; - } -}; -#endif - -#endif // __DATAITERATOR_H__ diff --git a/include/field.hxx b/include/field.hxx index 07d9c65199..35a574cde4 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -38,8 +38,6 @@ class Field; #include "bout/deprecated.hxx" -#include "bout/dataiterator.hxx" - #include "unused.hxx" class Mesh; @@ -61,9 +59,6 @@ class Field { Field(Mesh * localmesh); virtual ~Field() { } - // Data access - virtual const BoutReal& operator[](const Indices &i) const = 0; - virtual void setLocation(CELL_LOC loc) { if (loc != CELL_CENTRE) throw BoutException("not implemented!"); @@ -129,8 +124,6 @@ class Field { */ virtual int getNz() const; - /// Make region mendatory for all fields - virtual const IndexRange region(REGION rgn) const = 0; protected: Mesh * fieldmesh; mutable Coordinates * fieldCoordinates = nullptr; diff --git a/include/field2d.hxx b/include/field2d.hxx index 51e14607ab..25e19b532b 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -37,8 +37,6 @@ class Field3D; //#include "field3d.hxx" #include "fieldperp.hxx" #include "stencils.hxx" -#include "bout/dataiterator.hxx" - #include "bout/field_visitor.hxx" #include "bout/array.hxx" @@ -142,18 +140,6 @@ class Field2D : public Field, public FieldData { ///////////////////////////////////////////////////////// // Data access - /// Iterator over the Field2D indices - const DataIterator DEPRECATED(iterator() const); - - const DataIterator DEPRECATED(begin()) const; - const DataIterator DEPRECATED(end()) const; - - /*! - * Returns a range of indices which can be iterated over - * Uses the REGION flags in bout_types.hxx - */ - const IndexRange DEPRECATED(region(REGION rgn)) const override; - /// Return a Region reference to use to iterate over this field const Region& getRegion(REGION region) const; const Region& getRegion(const std::string ®ion_name) const; @@ -167,29 +153,6 @@ class Field2D : public Field, public FieldData { BoutReal& operator[](const Ind3D &d); const BoutReal& operator[](const Ind3D &d) const; - /*! - * Direct access to the data array. Since operator() is used - * to implement this, no checks are performed if CHECK <= 2 - */ - inline BoutReal& DEPRECATED(operator[](const DataIterator &d)) { - return operator()(d.x, d.y); - } - - /// Const access to data array - inline const BoutReal& DEPRECATED(operator[](const DataIterator &d)) const { - return operator()(d.x, d.y); - } - - /// Indices are also used as a lightweight way to specify indexing - /// for example DataIterator offsets (xp, xm, yp etc.) return Indices - inline BoutReal& DEPRECATED(operator[](const Indices &i)) { - return operator()(i.x, i.y); - } - /// const Indices data access - inline const BoutReal& DEPRECATED(operator[](const Indices &i)) const override { - return operator()(i.x, i.y); - } - /*! * Access to the underlying data array. * diff --git a/include/field3d.hxx b/include/field3d.hxx index 1025f935ab..61de6a110d 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -33,8 +33,6 @@ class Mesh; // #include "bout/mesh.hxx" #include "stencils.hxx" #include "bout_types.hxx" -#include "bout/dataiterator.hxx" - #include "bout/array.hxx" #include "bout/region.hxx" @@ -113,15 +111,6 @@ class Mesh; // #include "bout/mesh.hxx" `data` now points to `f(0,1,0)` and can be incremented to move in Z. - Indexing can also be done using DataIterator or Indices objects, - defined in bout/dataiterator.hxx: - - Indices i = {0,1,0}; - - f[i] = 1.0; // Equivalent to f(0,1,0) - - This is primarily used to allow convenient iteration over fields - Iteration --------- @@ -279,78 +268,25 @@ class Field3D : public Field, public FieldData { ///////////////////////////////////////////////////////// // Data access - - const DataIterator DEPRECATED(iterator() const); - - /*! - * These begin and end functions are used to iterate over - * the indices of a field. Indices are used rather than - * values since this allows expressions involving multiple fields. - * - * Example - * ------- - * - * Field3D objects f and g can be modified by - * - * for(const auto &i : f) { - * f[i] = 2.*f[i] + g[i]; - * } - * - */ - const DataIterator DEPRECATED(begin()) const; - const DataIterator DEPRECATED(end()) const; - - /*! - * Returns a range of indices which can be iterated over - * Uses the REGION flags in bout_types.hxx - * - * Example - * ------- - * - * This loops over the interior points, not the boundary - * and inside the loop the index is used to calculate the difference - * between the point one index up in x (i.xp()) and one index down - * in x (i.xm()), putting the result into a different field 'g' - * - * for(const auto &i : f.region(RGN_NOBNDRY)) { - * g[i] = f[i.xp()] - f[i.xm()]; - * } - * - */ - const IndexRange DEPRECATED(region(REGION rgn)) const override; - - /*! - * Like Field3D::region(REGION rgn), but returns range - * to iterate over only x-y, not z. - * This is useful in the Fourier transform functions - * which need an explicit loop in z. - * - */ - const IndexRange DEPRECATED(region2D(REGION rgn)) const; /// Return a Region reference to use to iterate over this field + /// + /// Example + /// ------- + /// + /// This loops over the interior points, not the boundary + /// and inside the loop the index is used to calculate the difference + /// between the point one index up in x (i.xp()) and one index down + /// in x (i.xm()), putting the result into a different field 'g' + /// + /// for(const auto &i : f.getRegion(RGN_NOBNDRY)) { + /// g[i] = f[i.xp()] - f[i.xm()]; + /// } + /// const Region& getRegion(REGION region) const; const Region& getRegion(const std::string ®ion_name) const; - /*! - * Direct data access using DataIterator object. - * This uses operator(x,y,z) so checks will only be - * performed if CHECK > 2. - */ - BoutReal& DEPRECATED(operator[](const DataIterator &d)) { - return operator()(d.x, d.y, d.z); - } - const BoutReal& DEPRECATED(operator[](const DataIterator &d)) const { - return operator()(d.x, d.y, d.z); - } - BoutReal& DEPRECATED(operator[](const Indices &i)) { - return operator()(i.x, i.y, i.z); - } - const BoutReal& DEPRECATED(operator[](const Indices &i)) const override { - return operator()(i.x, i.y, i.z); - } - BoutReal& operator[](const Ind3D &d) { return data[d.ind]; } diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 90fdcf03d8..548214a45f 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -30,7 +30,6 @@ class FieldPerp; #include "field.hxx" -#include "bout/dataiterator.hxx" #include "bout/array.hxx" #include "bout/assert.hxx" #include "bout/region.hxx" @@ -83,34 +82,10 @@ class FieldPerp : public Field { FieldPerp &operator=(FieldPerp &&rhs) = default; FieldPerp &operator=(BoutReal rhs); - /*! - * Iterators and data access - */ - const DataIterator DEPRECATED(begin()) const; - const DataIterator DEPRECATED(end()) const; - - const IndexRange DEPRECATED(region(REGION rgn)) const override; - /// Return a Region reference to use to iterate over this field const Region& getRegion(REGION region) const; const Region& getRegion(const std::string ®ion_name) const; - /*! - * Direct data access using DataIterator indexing - */ - inline BoutReal& DEPRECATED(operator[](const DataIterator &d)) { - return operator()(d.x, d.z); - } - inline const BoutReal& DEPRECATED(operator[](const DataIterator &d)) const { - return operator()(d.x, d.z); - } - BoutReal& DEPRECATED(operator[](const Indices &i)) { - return operator()(i.x, i.z); - } - const BoutReal& DEPRECATED(operator[](const Indices &i)) const override{ - return operator()(i.x, i.z); - } - inline BoutReal& operator[](const IndPerp &d) { return data[d.ind]; } diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index ad44b43a1b..a675039078 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -133,52 +133,6 @@ Field2D* Field2D::timeDeriv() { ////////////// Indexing /////////////////// -const DataIterator Field2D::iterator() const { - return DataIterator(0, nx-1, - 0, ny-1, - 0, 0); -} - -const DataIterator Field2D::begin() const { - return DataIterator(0, nx-1, - 0, ny-1, - 0, 0); -} - -const DataIterator Field2D::end() const { - return DataIterator(0, nx-1, - 0, ny-1, - 0, 0, DI_GET_END); -} - -const IndexRange Field2D::region(REGION rgn) const { - switch(rgn) { - case RGN_ALL: { - return IndexRange{0, nx-1, - 0, ny-1, - 0, 0}; - } - case RGN_NOBNDRY: { - return IndexRange{fieldmesh->xstart, fieldmesh->xend, - fieldmesh->ystart, fieldmesh->yend, - 0, 0}; - } - case RGN_NOX: { - return IndexRange{fieldmesh->xstart, fieldmesh->xend, - 0, ny-1, - 0, 0}; - } - case RGN_NOY: { - return IndexRange{0, nx-1, - fieldmesh->ystart, fieldmesh->yend, - 0, 0}; - } - default: { - throw BoutException("Field2D::region() : Requested region not implemented"); - } - }; -} - const Region &Field2D::getRegion(REGION region) const { return fieldmesh->getRegion2D(REGION_STRING(region)); }; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 1143eb9fdc..6e963023e4 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -276,85 +276,6 @@ const BoutReal &Field3D::operator()(const Ind2D &d, int jz) const { return operator[](fieldmesh->ind2Dto3D(d, jz)); } -/*************************************************************** - * OPERATORS - ***************************************************************/ - -const DataIterator Field3D::iterator() const { - return DataIterator(0, nx-1, - 0, ny-1, - 0, nz-1); -} - -const DataIterator Field3D::begin() const { - return DataIterator(0, nx-1, - 0, ny-1, - 0, nz-1); -} - -const DataIterator Field3D::end() const { - // end() iterator should be one past the last element - return DataIterator(0, nx-1, - 0, ny-1, - 0, nz-1,DI_GET_END); -} - -const IndexRange Field3D::region(REGION rgn) const { - switch(rgn) { - case RGN_ALL: { - return IndexRange{0, nx-1, - 0, ny-1, - 0, nz-1}; - } - case RGN_NOBNDRY: { - return IndexRange{fieldmesh->xstart, fieldmesh->xend, - fieldmesh->ystart, fieldmesh->yend, - 0, nz-1}; - } - case RGN_NOX: { - return IndexRange{fieldmesh->xstart, fieldmesh->xend, - 0, ny-1, - 0, nz-1}; - } - case RGN_NOY: { - return IndexRange{0, nx-1, - fieldmesh->ystart, fieldmesh->yend, - 0, nz-1}; - } - default: { - throw BoutException("Field3D::region() : Requested region not implemented"); - } - }; -} - -const IndexRange Field3D::region2D(REGION rgn) const { - switch(rgn) { - case RGN_ALL: { - return IndexRange{0, nx-1, - 0, ny-1, - 0, 0}; - } - case RGN_NOBNDRY: { - return IndexRange{fieldmesh->xstart, fieldmesh->xend, - fieldmesh->ystart, fieldmesh->yend, - 0, 0}; - } - case RGN_NOX: { - return IndexRange{fieldmesh->xstart, fieldmesh->xend, - 0, ny-1, - 0, 0}; - } - case RGN_NOY: { - return IndexRange{0, nx-1, - fieldmesh->ystart, fieldmesh->yend, - 0, 0}; - } - default: { - throw BoutException("Field3D::region() : Requested region not implemented"); - } - }; -} - const Region &Field3D::getRegion(REGION region) const { return fieldmesh->getRegion3D(REGION_STRING(region)); }; @@ -362,6 +283,10 @@ const Region &Field3D::getRegion(const std::string ®ion_name) const { return fieldmesh->getRegion3D(region_name); }; +/*************************************************************** + * OPERATORS + ***************************************************************/ + /////////////////// ASSIGNMENT //////////////////// Field3D & Field3D::operator=(const Field3D &rhs) { diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 5bd7765e91..ad7c2ad8d2 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -105,23 +105,6 @@ FieldPerp & FieldPerp::operator=(const BoutReal rhs) { return *this; } -/*************************************************************** - * ITERATORS - ***************************************************************/ - -const DataIterator FieldPerp::begin() const { - return DataIterator( 0, nx-1, - yindex, yindex, - 0, nz-1); -} - -const DataIterator FieldPerp::end() const { - return DataIterator( 0, nx-1, - yindex, yindex, - 0, nz-1,DI_GET_END); -} - - /*************************************************************** * OPERATORS ***************************************************************/ @@ -200,21 +183,6 @@ FPERP_OP_REAL(-=, -); FPERP_OP_REAL(*=, *); FPERP_OP_REAL(/=, /); -const IndexRange FieldPerp::region(REGION rgn) const { - switch (rgn) { - case RGN_ALL: - case RGN_NOZ: - return IndexRange{0, nx - 1, 0, 0, 0, nz - 1}; - break; - case RGN_NOX: - return IndexRange{getMesh()->xstart, getMesh()->xend, 0, 0, 0, nz - 1}; - break; - default: - throw BoutException("FieldPerp::region() : Requested region not implemented"); - break; - }; -} - const Region &FieldPerp::getRegion(REGION region) const { return fieldmesh->getRegionPerp(REGION_STRING(region)); }; From 4a3ed30c196561ef7b03091ffcd408ae9a8624f5 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 14:20:20 +0100 Subject: [PATCH 0087/1783] Allow fields to be easily used in range based loops --- include/field2d.hxx | 3 +++ include/field3d.hxx | 2 ++ include/fieldperp.hxx | 3 +++ 3 files changed, 8 insertions(+) diff --git a/include/field2d.hxx b/include/field2d.hxx index 25e19b532b..5b491c2660 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -143,6 +143,9 @@ class Field2D : public Field, public FieldData { /// Return a Region reference to use to iterate over this field const Region& getRegion(REGION region) const; const Region& getRegion(const std::string ®ion_name) const; + + Region::RegionIndices::const_iterator begin() const {return std::begin(getRegion("RGN_ALL"));}; + Region::RegionIndices::const_iterator end() const {return std::end(getRegion("RGN_ALL"));}; BoutReal& operator[](const Ind2D &d) { return data[d.ind]; diff --git a/include/field3d.hxx b/include/field3d.hxx index 61de6a110d..ecce03302d 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -286,6 +286,8 @@ class Field3D : public Field, public FieldData { const Region& getRegion(REGION region) const; const Region& getRegion(const std::string ®ion_name) const; + Region::RegionIndices::const_iterator begin() const {return std::begin(getRegion("RGN_ALL"));}; + Region::RegionIndices::const_iterator end() const {return std::end(getRegion("RGN_ALL"));}; BoutReal& operator[](const Ind3D &d) { return data[d.ind]; diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 548214a45f..a587ce0ad9 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -86,6 +86,9 @@ class FieldPerp : public Field { const Region& getRegion(REGION region) const; const Region& getRegion(const std::string ®ion_name) const; + Region::RegionIndices::const_iterator begin() const {return std::begin(getRegion("RGN_ALL"));}; + Region::RegionIndices::const_iterator end() const {return std::end(getRegion("RGN_ALL"));}; + inline BoutReal& operator[](const IndPerp &d) { return data[d.ind]; } From ac51a07a25e9b9e58644c84d699d76129f202883 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 14:51:02 +0100 Subject: [PATCH 0088/1783] Fix the tests --- src/mesh/mesh.cxx | 1 + .../test-interpolate/test_interpolate.cxx | 10 +- .../test_region_iterator.cxx | 10 +- tests/unit/field/test_field2d.cxx | 60 ++-------- tests/unit/field/test_field3d.cxx | 111 ++++++------------ tests/unit/field/test_fieldperp.cxx | 56 ++------- 6 files changed, 67 insertions(+), 181 deletions(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 6a857f57a7..70112cfe91 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -418,6 +418,7 @@ void Mesh::createDefaultRegions(){ maxregionblocksize)); // Same as NOBNDRY addRegionPerp("RGN_NOY", Region(0, LocalNx - 1, 0, 0, 0, LocalNz - 1, 1, LocalNz, maxregionblocksize)); // Same as ALL + addRegionPerp("RGN_NOZ", getRegionPerp("RGN_ALL")); // Currently the same as ALL addRegionPerp("RGN_GUARDS", mask(getRegionPerp("RGN_ALL"), getRegionPerp("RGN_NOBNDRY"))); // Construct index lookup for 3D-->2D diff --git a/tests/integrated/test-interpolate/test_interpolate.cxx b/tests/integrated/test-interpolate/test_interpolate.cxx index a4f6554420..5d0a49d54e 100644 --- a/tests/integrated/test-interpolate/test_interpolate.cxx +++ b/tests/integrated/test-interpolate/test_interpolate.cxx @@ -65,18 +65,18 @@ int main(int argc, char **argv) { for (const auto &index : deltax) { // Get some random displacements - BoutReal dx = index.x + dice(); - BoutReal dz = index.z + dice(); + BoutReal dx = index.x() + dice(); + BoutReal dz = index.z() + dice(); // For the last point, put the displacement inwards // Otherwise we try to interpolate in the guard cells, which doesn't work so well - if (index.x >= mesh->xend) { - dx = index.x - dice(); + if (index.x() >= mesh->xend) { + dx = index.x() - dice(); } deltax[index] = dx; deltaz[index] = dz; // Get the global indices BoutReal x = mesh->GlobalX(dx); - BoutReal y = TWOPI * mesh->GlobalY(index.y); + BoutReal y = TWOPI * mesh->GlobalY(index.y()); BoutReal z = TWOPI * static_cast(dz) / static_cast(mesh->LocalNz); // Generate the analytic solution at the displacements a_solution[index] = a_gen->generate(x, y, z, 0.0); diff --git a/tests/integrated/test-region-iterator/test_region_iterator.cxx b/tests/integrated/test-region-iterator/test_region_iterator.cxx index 346f8b41b6..0ddd07b80b 100644 --- a/tests/integrated/test-region-iterator/test_region_iterator.cxx +++ b/tests/integrated/test-region-iterator/test_region_iterator.cxx @@ -20,19 +20,19 @@ int physics_init(bool restarting) { //Check expected results int nerr=0; - for (const auto &i: a.region(RGN_ALL)){ + for (const auto &i : a.getRegion(RGN_ALL)) { if (a[i] != 3.0) nerr++; } if(nerr != 0 ) throw BoutException("Unexpected values found in 'a', count %d",nerr); nerr=0; - for (const auto &i: b.region(RGN_ALL)){ + for (const auto &i : b.getRegion(RGN_ALL)) { if (b[i] != c[i]) nerr++; } if(nerr != 0 ) throw BoutException("Unexpected values found in 'b', count %d",nerr); Field3D d=1.0, e=1.0, f=2.0; - BOUT_FOR(i, mesh->getRegion3D("RGN_NOBNDRY")) { + BOUT_FOR(i, d.getRegion("RGN_NOBNDRY")) { d[i] = 3.0; e[i] = f[i]; } @@ -41,12 +41,12 @@ int physics_init(bool restarting) { nerr=0; //Expect to find differences just in the boundaries, so work out how many boundary points there area const int nerrExpected = (2*mesh->xstart*mesh->LocalNy + 2*mesh->ystart*(mesh->LocalNx-mesh->xstart*2))*mesh->LocalNz; - for (const auto &i: d.region(RGN_ALL)){ + for (const auto &i : d.getRegion(RGN_ALL)) { if (d[i] != 3.0) nerr++; } if(nerr != nerrExpected ) throw BoutException("Unexpected values found in 'd', count %d",nerr); nerr=0; - for (const auto &i: e.region(RGN_ALL)){ + for (const auto &i : e.getRegion(RGN_ALL)) { if (e[i] != f[i]) nerr++; } if(nerr != nerrExpected ) throw BoutException("Unexpected values found in 'e', count %d",nerr); diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index 2e27894172..1a87816f21 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -256,43 +256,7 @@ TEST_F(Field2DTest, IterateOverWholeField) { for (auto &i : field) { sum += field[i]; if (field[i] == sentinel) { - result_indices.insert({i.x, i.y}); - ++found_sentinels; - } - } - - EXPECT_EQ(found_sentinels, num_sentinels); - EXPECT_EQ(sum, ((nx * ny) - num_sentinels) + (num_sentinels * sentinel)); - EXPECT_TRUE(test_indices == result_indices); -} - -TEST_F(Field2DTest, IterateOverRGN_ALL) { - Field2D field = 1.0; - - const BoutReal sentinel = -99.0; - - // We use a set in case for some reason the iterator doesn't visit - // each point in the order we expect - std::set> test_indices; - test_indices.insert({0, 0}); - test_indices.insert({0, 1}); - test_indices.insert({1, 0}); - test_indices.insert({1, 1}); - const int num_sentinels = test_indices.size(); - - // Assign sentinel value to watch out for to our chosen points - for (auto index : test_indices) { - field(index[0], index[1]) = sentinel; - } - - int found_sentinels = 0; - BoutReal sum = 0.0; - std::set> result_indices; - - for (auto &i : field.region(RGN_ALL)) { - sum += field[i]; - if (field[i] == sentinel) { - result_indices.insert({i.x, i.y}); + result_indices.insert({i.x(), i.y()}); ++found_sentinels; } } @@ -321,7 +285,7 @@ TEST_F(Field2DTest, IterateOverRegionInd2D_RGN_ALL) { BoutReal sum = 0.0; std::set> result_indices; - for (auto &i : field.getMesh()->getRegion2D("RGN_ALL")) { + for (auto &i : field.getRegion("RGN_ALL")) { sum += field[i]; if (field[i] == sentinel) { result_indices.insert({i.x(), i.y()}); @@ -394,10 +358,10 @@ TEST_F(Field2DTest, IterateOverRGN_NOBNDRY) { BoutReal sum = 0.0; std::set> result_indices; - for (auto &i : field.region(RGN_NOBNDRY)) { + for (auto &i : field.getRegion(RGN_NOBNDRY)) { sum += field[i]; if (field[i] == sentinel) { - result_indices.insert({i.x, i.y}); + result_indices.insert({i.x(), i.y()}); ++found_sentinels; } } @@ -435,10 +399,10 @@ TEST_F(Field2DTest, IterateOverRGN_NOX) { BoutReal sum = 0.0; std::set> result_indices; - for (auto &i : field.region(RGN_NOX)) { + for (auto &i : field.getRegion(RGN_NOX)) { sum += field[i]; if (field[i] == sentinel) { - result_indices.insert({i.x, i.y}); + result_indices.insert({i.x(), i.y()}); ++found_sentinels; } } @@ -476,10 +440,10 @@ TEST_F(Field2DTest, IterateOverRGN_NOY) { BoutReal sum = 0.0; std::set> result_indices; - for (auto &i : field.region(RGN_NOY)) { + for (auto &i : field.getRegion(RGN_NOY)) { sum += field[i]; if (field[i] == sentinel) { - result_indices.insert({i.x, i.y}); + result_indices.insert({i.x(), i.y()}); ++found_sentinels; } } @@ -493,7 +457,7 @@ TEST_F(Field2DTest, IterateOverRGN_NOZ) { Field2D field = 1.0; // This is not a valid region for Field2D - EXPECT_THROW(field.region(RGN_NOZ), BoutException); + EXPECT_THROW(field.getRegion(RGN_NOZ), BoutException); } TEST_F(Field2DTest, Indexing) { @@ -656,7 +620,7 @@ TEST_F(Field2DTest, InvalidateGuards) { const int nmesh = nx * ny; int sum = 0; - for (const auto &i : field.region(RGN_ALL)) { + for (const auto &i : field) { field[i] = 0.0; // Reset field value sum++; } @@ -664,7 +628,7 @@ TEST_F(Field2DTest, InvalidateGuards) { // Count the number of non-boundary points sum = 0; - for (const auto &i : field.region(RGN_NOBNDRY)) { + for (const auto &i : field.getRegion(RGN_NOBNDRY)) { field[i] = 0.0; // Reset field value sum++; } @@ -680,7 +644,7 @@ TEST_F(Field2DTest, InvalidateGuards) { EXPECT_NO_THROW(checkData(field(localmesh->xstart, localmesh->ystart))); sum = 0; - for (const auto &i : field.region(RGN_ALL)) { + for (const auto &i : field) { if (!finite(field[i])) sum++; } diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index bb13235d6d..649a3abb1b 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -419,47 +419,7 @@ TEST_F(Field3DTest, IterateOverWholeField) { for (const auto &i : field) { sum += field[i]; if (field[i] == sentinel) { - result_indices.insert({i.x, i.y, i.z}); - ++found_sentinels; - } - } - - EXPECT_EQ(found_sentinels, num_sentinels); - EXPECT_EQ(sum, ((nx * ny * nz) - num_sentinels) + (num_sentinels * sentinel)); - EXPECT_TRUE(test_indices == result_indices); -} - -TEST_F(Field3DTest, IterateOverRGN_ALL) { - Field3D field = 1.0; - - const BoutReal sentinel = -99.0; - - // We use a set in case for some reason the iterator doesn't visit - // each point in the order we expect - std::set> test_indices; - test_indices.insert({0, 0, 0}); - test_indices.insert({0, 0, 1}); - test_indices.insert({0, 1, 0}); - test_indices.insert({1, 0, 0}); - test_indices.insert({0, 1, 1}); - test_indices.insert({1, 0, 1}); - test_indices.insert({1, 1, 0}); - test_indices.insert({1, 1, 1}); - const int num_sentinels = test_indices.size(); - - // Assign sentinel value to watch out for to our chosen points - for (const auto index : test_indices) { - field(index[0], index[1], index[2]) = sentinel; - } - - int found_sentinels = 0; - BoutReal sum = 0.0; - std::set> result_indices; - - for (const auto &i : field.region(RGN_ALL)) { - sum += field[i]; - if (field[i] == sentinel) { - result_indices.insert({i.x, i.y, i.z}); + result_indices.insert({i.x(), i.y(), i.z()}); ++found_sentinels; } } @@ -534,10 +494,10 @@ TEST_F(Field3DTest, IterateOverRGN_NOBNDRY) { BoutReal sum = 0.0; std::set> result_indices; - for (const auto &i : field.region(RGN_NOBNDRY)) { + for (const auto &i : field.getRegion(RGN_NOBNDRY)) { sum += field[i]; if (field[i] == sentinel) { - result_indices.insert({i.x, i.y, i.z}); + result_indices.insert({i.x(), i.y(), i.z()}); ++found_sentinels; } } @@ -582,10 +542,10 @@ TEST_F(Field3DTest, IterateOverRGN_NOX) { BoutReal sum = 0.0; std::set> result_indices; - for (const auto &i : field.region(RGN_NOX)) { + for (const auto &i : field.getRegion(RGN_NOX)) { sum += field[i]; if (field[i] == sentinel) { - result_indices.insert({i.x, i.y, i.z}); + result_indices.insert({i.x(), i.y(), i.z()}); ++found_sentinels; } } @@ -631,10 +591,10 @@ TEST_F(Field3DTest, IterateOverRGN_NOY) { BoutReal sum = 0.0; std::set> result_indices; - for (const auto &i : field.region(RGN_NOY)) { + for (const auto &i : field.getRegion(RGN_NOY)) { sum += field[i]; if (field[i] == sentinel) { - result_indices.insert({i.x, i.y, i.z}); + result_indices.insert({i.x(), i.y(), i.z()}); ++found_sentinels; } } @@ -648,7 +608,7 @@ TEST_F(Field3DTest, IterateOverRGN_NOZ) { Field3D field = 1.0; // This is not a valid region for Field3D - EXPECT_THROW(field.region(RGN_NOZ), BoutException); + EXPECT_THROW(field.getRegion(RGN_NOZ), BoutException); } TEST_F(Field3DTest, IterateOver2DRGN_ALL) { @@ -656,14 +616,14 @@ TEST_F(Field3DTest, IterateOver2DRGN_ALL) { field.allocate(); for (const auto &i : field) { - field[i] = 1.0 + i.z; + field[i] = 1.0 + i.z(); } BoutReal sum = 0.0; - for (const auto &i : field.region2D(RGN_ALL)) { - sum += field[i]; - EXPECT_EQ(field[i], 1.0); - EXPECT_EQ(i.z, 0); + for (const auto &i : field.getMesh()->getRegion2D("RGN_ALL")) { + sum += field(i, 0); + EXPECT_EQ(field(i, 0), 1.0); + EXPECT_EQ(i.z(), 0); } EXPECT_EQ(sum, nx * ny); @@ -674,14 +634,14 @@ TEST_F(Field3DTest, IterateOver2DRGN_NOBNDRY) { field.allocate(); for (const auto &i : field) { - field[i] = 1.0 + i.z; + field[i] = 1.0 + i.z(); } BoutReal sum = 0.0; - for (const auto &i : field.region2D(RGN_NOBNDRY)) { - sum += field[i]; - EXPECT_EQ(field[i], 1.0); - EXPECT_EQ(i.z, 0); + for (const auto &i : field.getMesh()->getRegion2D("RGN_NOBNDRY")) { + sum += field(i, 0); + EXPECT_EQ(field(i, 0), 1.0); + EXPECT_EQ(i.z(), 0); } EXPECT_EQ(sum, nx * ny - 2 * nx - 2 * (ny - 2)); @@ -692,14 +652,14 @@ TEST_F(Field3DTest, IterateOver2DRGN_NOX) { field.allocate(); for (const auto &i : field) { - field[i] = 1.0 + i.z; + field[i] = 1.0 + i.z(); } BoutReal sum = 0.0; - for (const auto &i : field.region2D(RGN_NOX)) { - sum += field[i]; - EXPECT_EQ(field[i], 1.0); - EXPECT_EQ(i.z, 0); + for (const auto &i : field.getMesh()->getRegion2D("RGN_NOX")) { + sum += field(i, 0); + EXPECT_EQ(field(i, 0), 1.0); + EXPECT_EQ(i.z(), 0); } EXPECT_EQ(sum, nx * ny - 2 * ny); @@ -710,24 +670,19 @@ TEST_F(Field3DTest, IterateOver2DRGN_NOY) { field.allocate(); for (const auto &i : field) { - field[i] = 1.0 + i.z; + field[i] = 1.0 + i.z(); } BoutReal sum = 0.0; - for (const auto &i : field.region2D(RGN_NOY)) { - sum += field[i]; - EXPECT_EQ(field[i], 1.0); - EXPECT_EQ(i.z, 0); + for (const auto &i : field.getMesh()->getRegion2D("RGN_NOY")) { + sum += field(i, 0); + EXPECT_EQ(field(i, 0), 1.0); + EXPECT_EQ(i.z(), 0); } EXPECT_EQ(sum, nx * ny - 2 * nx); } -TEST_F(Field3DTest, IterateOver2DRGN_NOZ) { - Field3D field = 1.0; - EXPECT_THROW(field.region2D(RGN_NOZ), BoutException); -} - TEST_F(Field3DTest, Indexing) { Field3D field; @@ -981,7 +936,7 @@ TEST_F(Field3DTest, InvalidateGuards) { const int nmesh = nx * ny * nz; int sum = 0; - for (const auto &i : field.region(RGN_ALL)) { + for (const auto &i : field) { field[i] = 0.0; // Reset field value sum++; } @@ -989,7 +944,7 @@ TEST_F(Field3DTest, InvalidateGuards) { // Count the number of non-boundary points sum = 0; - for (const auto &i : field.region(RGN_NOBNDRY)) { + for (const auto &i : field.getRegion(RGN_NOBNDRY)) { field[i] = 0.0; // Reset field value sum++; } @@ -1005,7 +960,7 @@ TEST_F(Field3DTest, InvalidateGuards) { EXPECT_NO_THROW(checkData(field(localmesh->xstart, localmesh->ystart, 0))); sum = 0; - for (const auto &i : field.region(RGN_ALL)) { + for (const auto &i : field) { if (!finite(field[i])) sum++; } @@ -1079,7 +1034,7 @@ TEST_F(Field3DTest, AssignFromFieldPerp) { field = field2; for (const auto &i : field) { - if (i.y == yindex) { + if (i.y() == yindex) { EXPECT_EQ(field[i], 2.0); } else { EXPECT_EQ(field[i], 1.0); @@ -1952,7 +1907,7 @@ TEST_F(Field3DTest, DC) { field = 1.0; for (const auto& i : field) { - field[i] = i.z; + field[i] = i.z(); } EXPECT_TRUE(IsField2DEqualBoutReal(DC(field), 3.0)); diff --git a/tests/unit/field/test_fieldperp.cxx b/tests/unit/field/test_fieldperp.cxx index ead90cc8c8..3b5291a3f7 100644 --- a/tests/unit/field/test_fieldperp.cxx +++ b/tests/unit/field/test_fieldperp.cxx @@ -60,7 +60,7 @@ TEST_F(FieldPerpTest, Allocate) { EXPECT_TRUE(field.isAllocated()); int counter = 0; - for (const auto &i : field.region(RGN_ALL)) { + for (const auto &i : field) { field[i] = 1.; // Hits Array bounds checking counter++; } @@ -268,7 +268,7 @@ TEST_F(FieldPerpTest, IterateOverWholeField) { for (auto &i : field) { sum += field[i]; if (field[i] == sentinel) { - result_indices.insert({i.x, i.z}); + result_indices.insert({i.x(), i.z()}); ++found_sentinels; } } @@ -302,10 +302,10 @@ TEST_F(FieldPerpTest, IterateOverRGN_ALL) { BoutReal sum = 0.0; std::set> result_indices; - for (auto &i : field.region(RGN_ALL)) { + for (auto &i : field) { sum += field[i]; if (field[i] == sentinel) { - result_indices.insert({i.x, i.z}); + result_indices.insert({i.x(), i.z()}); ++found_sentinels; } } @@ -346,10 +346,10 @@ TEST_F(FieldPerpTest, IterateOverRGN_NOZ) { BoutReal sum = 0.0; std::set> result_indices; - for (auto &i : field.region(RGN_NOZ)) { + for (auto &i : field.getRegion(RGN_NOZ)) { sum += field[i]; if (field[i] == sentinel) { - result_indices.insert({i.x, i.z}); + result_indices.insert({i.x(), i.z()}); ++found_sentinels; } } @@ -388,10 +388,10 @@ TEST_F(FieldPerpTest, IterateOverRGN_NOX) { BoutReal sum = 0.0; std::set> result_indices; - for (auto &i : field.region(RGN_NOX)) { + for (auto &i : field.getRegion(RGN_NOX)) { sum += field[i]; if (field[i] == sentinel) { - result_indices.insert({i.x, i.z}); + result_indices.insert({i.x(), i.z()}); ++found_sentinels; } } @@ -401,20 +401,6 @@ TEST_F(FieldPerpTest, IterateOverRGN_NOX) { EXPECT_TRUE(region_indices == result_indices); } -TEST_F(FieldPerpTest, IterateOverRGN_NOBNDRY) { - FieldPerp field(mesh); - - // This is not a valid region for FieldPerp - EXPECT_THROW(field.region(RGN_NOBNDRY), BoutException); -} - -TEST_F(FieldPerpTest, IterateOverRGN_NOY) { - FieldPerp field(mesh); - - // This is not a valid region for FieldPerp - EXPECT_THROW(field.region(RGN_NOY), BoutException); -} - TEST_F(FieldPerpTest, Indexing) { FieldPerp field; @@ -445,26 +431,6 @@ TEST_F(FieldPerpTest, IndexingAs3D) { EXPECT_DOUBLE_EQ(field(2, 2), 4 + ny - 1); } -TEST_F(FieldPerpTest, IndexingWithIndices) { - FieldPerp field; - - field.allocate(); - - for (int i = 0; i < nx; ++i) { - for (int j = 0; j < nz; ++j) { - field(i, j) = i + j; - } - } - Indices ii{2, -1, 2}; - EXPECT_DOUBLE_EQ(field[ii], 4); -} - -TEST_F(FieldPerpTest, ConstIndexingWithIndices) { - const FieldPerp field = 2.0; - const Indices ii{2, -1, 2}; - EXPECT_DOUBLE_EQ(field[ii], 2.0); -} - TEST_F(FieldPerpTest, IndexingWithIndPerp) { FieldPerp field(0.0); const BoutReal sentinel = 2.0; @@ -646,7 +612,7 @@ TEST_F(FieldPerpTest, InvalidateGuards) { const int nmesh = nx * nz; int sum = 0; - for (const auto &i : field.region(RGN_ALL)) { + for (const auto &i : field) { field[i] = 0.0; // Reset field value sum++; } @@ -654,7 +620,7 @@ TEST_F(FieldPerpTest, InvalidateGuards) { // Count the number of non-boundary points sum = 0; - for (const auto &i : field.region(RGN_NOX)) { + for (const auto &i : field.getRegion(RGN_NOX)) { field[i] = 0.0; // Reset field value sum++; } @@ -670,7 +636,7 @@ TEST_F(FieldPerpTest, InvalidateGuards) { EXPECT_NO_THROW(checkData(field(localmesh->xstart, 0))); sum = 0; - for (const auto &i : field.region(RGN_ALL)) { + for (const auto &i : field) { if (!finite(field[i])) sum++; } From 9b1d8b9a1f55cba2ad182721d3087c5991e368fa Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 14:52:30 +0100 Subject: [PATCH 0089/1783] Remove deprecated DataFile::writeVar --- include/datafile.hxx | 4 ---- src/fileio/datafile.cxx | 15 --------------- 2 files changed, 19 deletions(-) diff --git a/include/datafile.hxx b/include/datafile.hxx index 534759ac34..60322350a7 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -73,10 +73,6 @@ class Datafile { bool write(); ///< Write added variables bool write(const char *filename, ...) const; ///< Opens, writes, closes file - - // Write a variable to the file now - DEPRECATED(bool writeVar(const int &i, const char *name)); - DEPRECATED(bool writeVar(BoutReal r, const char *name)); void setAttribute(const string &varname, const string &attrname, const string &text); void setAttribute(const string &varname, const string &attrname, int value); diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 9cac03bf10..b11636fc33 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -1006,21 +1006,6 @@ bool Datafile::write(const char *format, ...) const { return ret; } -bool Datafile::writeVar(const int &i, const char *name) { - // Should do this a better way... - int *i2 = new int; - *i2 = i; - add(*i2, name); - return true; -} - -bool Datafile::writeVar(BoutReal r, const char *name) { - BoutReal *r2 = new BoutReal; - *r2 = r; - add(*r2, name); - return true; -} - void Datafile::setAttribute(const string &varname, const string &attrname, const string &text) { TRACE("Datafile::setAttribute(string, string, string)"); From 2db6912abdf2b6f9bb8f24b7f7156f00b9c8db32 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 14:53:18 +0100 Subject: [PATCH 0090/1783] Remove deprecated Field::get/setName --- include/field.hxx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index 35a574cde4..3a4025b79b 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -67,13 +67,6 @@ class Field { return CELL_CENTRE; } -#ifdef TRACK - DEPRECATED(std::string getName() const) { return name; } - DEPRECATED(void setName(std::string s)) { name = s; } -#else - DEPRECATED(std::string getName()) const { return ""; } - DEPRECATED(void setName(std::string UNUSED(s))) {} -#endif std::string name; #if CHECK > 0 From 00cdd08fb1702d290bd70abf84e92b3d7b1533a8 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 14:55:20 +0100 Subject: [PATCH 0091/1783] Remove deprecated Field::error --- include/field.hxx | 3 --- src/field/field.cxx | 26 -------------------------- 2 files changed, 29 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index 3a4025b79b..504ddd4898 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -120,9 +120,6 @@ class Field { protected: Mesh * fieldmesh; mutable Coordinates * fieldCoordinates = nullptr; - /// Supplies an error method. Currently just prints and exits, but - /// should do something more cunning... - DEPRECATED(void error(const char *s, ...) const); }; #endif /* __FIELD_H__ */ diff --git a/src/field/field.cxx b/src/field/field.cxx index 365294d8df..dfef4ce140 100644 --- a/src/field/field.cxx +++ b/src/field/field.cxx @@ -82,29 +82,3 @@ int Field::getNz() const{ return getMesh()->LocalNz; }; -/////////////////// PROTECTED //////////////////// - - -// Report an error occurring -void Field::error(const char *s, ...) const { - int buf_len=512; - char * err_buffer=new char[buf_len]; - - if (s == nullptr) { - output_error.write("Unspecified error in field\n"); - } else { - - bout_vsnprintf(err_buffer,buf_len, s); - -#ifdef TRACK - output_error.write("Error in '%s': %s", name.c_str(), err_buffer); -#else - output_error.write("Error in field: %s", err_buffer); -#endif - } - std::string msg="Error in field: "; - msg+=err_buffer; - delete[] err_buffer; - throw BoutException(msg); -} - From 1ab0aeb797c509484106076b7140e8b3c6c0d8b2 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 14:58:08 +0100 Subject: [PATCH 0092/1783] Remove deprecated matrix, r3tensor, i3tensor etc. --- include/utils.hxx | 102 ---------------------------------------------- src/sys/utils.cxx | 61 --------------------------- 2 files changed, 163 deletions(-) diff --git a/include/utils.hxx b/include/utils.hxx index 1a6201b906..2b0052817f 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -35,7 +35,6 @@ #include "bout/array.hxx" #include "bout/assert.hxx" -#include "bout/deprecated.hxx" #include "msg_stack.hxx" #include "unused.hxx" @@ -91,17 +90,6 @@ public: }; return *this; }; - - // To provide backwards compatibility with matrix to be removed - DEPRECATED(T* operator[](size_type i1)) { - ASSERT2(0<=i1 && i1 data; }; -// For backwards compatibility with old matrix -- to be removed -template -DEPRECATED(void free_matrix(Matrix UNUSED(m))); -template -void free_matrix(Matrix UNUSED(m)) {}; - /// Helper class for 3D arrays /// /// Allows bounds checking through `operator()` with CHECK > 1 @@ -259,90 +241,6 @@ template int invert3x3(Matrix &a, BoutReal small = 1.0e-15) { return 0; }; -// Give signature here as not able to mark implementation below as DEPRECATED -template -DEPRECATED(T **matrix(int xsize, int ysize)); - -/*! - * Create a 2D array of \p xsize by \p ysize - * This is allocated as two blocks of data so that - * the values are in a contiguous array. - * - * Note: This returns C-style pointers, and makes - * no effort to manage memory. Prefer other methods - * (like standard containers) over this if possible. - * - * \deprecated - * - * Example - * ------- - * - * BoutReal **m = matrix(nx, ny); - */ -template -T **matrix(int xsize, int ysize) { - long i; - T **m; - - if(xsize == 0) - xsize = 1; - if(ysize == 0) - ysize = 1; - - if((m = new T*[xsize]) == nullptr) - throw BoutException("Error: could not allocate memory:%d\n", xsize); - - if((m[0] = new T[xsize*ysize]) == nullptr) - throw BoutException("Error: could not allocate memory\n"); - - for(i=1;i -DEPRECATED(void free_matrix(T **m)); -/*! - * Free a matrix, assumed to have been allocated using matrix() - * - * @param[in] m The matrix to free - * @deprecated - * - * Example - * ------- - * - * BoutReal **m = matrix(nx, ny); - * ... - * free_matrix(m); - */ -template -void free_matrix(T **m) { - delete[] m[0]; - delete[] m; -} - - -/// Allocate a 3D BoutReal array of size \p nrow x \p ncol \p ndep -/// -/// \deprecated Prefer other methods like standard containers -DEPRECATED(BoutReal ***r3tensor(int nrow, int ncol, int ndep)); - -/// Free a 3D BoutReal array, assumed to have been created by r3tensor -/// -/// \deprecated -DEPRECATED(void free_r3tensor(BoutReal ***m)); - -/// Allocate a 3D int array of size \p nrow x \p ncol \p ndep -/// -/// \deprecated Prefer other methods like standard containers -DEPRECATED(int ***i3tensor(int nrow, int ncol, int ndep)); - -/// Free a 3D int array, assumed to have been created by i3tensor() -/// -/// \deprecated -DEPRECATED(void free_i3tensor(int ***m)); - /*! * Get Random number between 0 and 1 */ diff --git a/src/sys/utils.cxx b/src/sys/utils.cxx index 5ae518caaf..8eef7335e6 100644 --- a/src/sys/utils.cxx +++ b/src/sys/utils.cxx @@ -32,67 +32,6 @@ #include #include #include - -BoutReal ***r3tensor(int nrow, int ncol, int ndep) { - int i,j; - BoutReal ***t; - - /* allocate pointers to pointers to rows */ - t = static_cast(malloc(nrow * sizeof(BoutReal **))); - - /* allocate pointers to rows and set pointers to them */ - t[0] = static_cast(malloc(nrow * ncol * sizeof(BoutReal *))); - - /* allocate rows and set pointers to them */ - t[0][0] = static_cast(malloc(nrow * ncol * ndep * sizeof(BoutReal))); - - for(j=1;j!=ncol;j++) t[0][j]=t[0][j-1]+ndep; - for(i=1;i!=nrow;i++) { - t[i]=t[i-1]+ncol; - t[i][0]=t[i-1][0]+ncol*ndep; - for(j=1;j!=ncol;j++) t[i][j]=t[i][j-1]+ndep; - } - - /* return pointer to array of pointers to rows */ - return t; -} - -void free_r3tensor(BoutReal ***m) { - free(m[0][0]); - free(m[0]); - free(m); -} - -int ***i3tensor(int nrow, int ncol, int ndep) { - int i,j; - int ***t; - - /* allocate pointers to pointers to rows */ - t = static_cast(malloc(nrow * sizeof(int **))); - - /* allocate pointers to rows and set pointers to them */ - t[0] = static_cast(malloc(nrow * ncol * sizeof(int *))); - - /* allocate rows and set pointers to them */ - t[0][0] = static_cast(malloc(nrow * ncol * ndep * sizeof(int))); - - for(j=1;j!=ncol;j++) t[0][j]=t[0][j-1]+ndep; - for(i=1;i!=nrow;i++) { - t[i]=t[i-1]+ncol; - t[i][0]=t[i-1][0]+ncol*ndep; - for(j=1;j!=ncol;j++) t[i][j]=t[i][j-1]+ndep; - } - - /* return pointer to array of pointers to rows */ - return t; -} - -void free_i3tensor(int ***m) { - free(m[0][0]); - free(m[0]); - free(m); -} - /************************************************************************** * String routines **************************************************************************/ From d3b1b6c9eae9802d3d239904d0b45aca6a0fe3c3 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 15:01:45 +0100 Subject: [PATCH 0093/1783] Remove deprecated operator^ in vectors --- include/vector2d.hxx | 11 ----------- include/vector3d.hxx | 15 --------------- src/field/vector2d.cxx | 18 ------------------ src/field/vector3d.cxx | 20 -------------------- 4 files changed, 64 deletions(-) diff --git a/include/vector2d.hxx b/include/vector2d.hxx index 876455dca2..ef0e650bf4 100644 --- a/include/vector2d.hxx +++ b/include/vector2d.hxx @@ -106,10 +106,6 @@ class Vector2D : public FieldData { /// Divide all components by \p rhs Vector2D & operator/=(const Field2D &rhs); - /// Cross-product of two vectors - /// Deprecated: use a=cross(a,b) instead - DEPRECATED(Vector2D & operator^=(const Vector2D &rhs);) - // Binary operators const Vector2D operator+(const Vector2D &rhs) const; ///< Addition @@ -129,13 +125,6 @@ class Vector2D : public FieldData { const Field2D operator*(const Vector2D &rhs) const; ///< Dot product const Field3D operator*(const Vector3D &rhs) const; ///< Dot product - /// Cross product - /// Deprecated: use cross(a,b) instead - DEPRECATED(const Vector2D operator^(const Vector2D &rhs) const;) - /// Cross product - /// Deprecated: use cross(a,b) instead - DEPRECATED(const Vector3D operator^(const Vector3D &rhs) const;) - /*! * Set variable cell location */ diff --git a/include/vector3d.hxx b/include/vector3d.hxx index 5f03dce9d0..b2d41d8c0d 100644 --- a/include/vector3d.hxx +++ b/include/vector3d.hxx @@ -149,13 +149,6 @@ class Vector3D : public FieldData { Vector3D & operator/=(BoutReal rhs); Vector3D & operator/=(const Field2D &rhs); Vector3D & operator/=(const Field3D &rhs); - - /// Cross-product of two vectors - /// Deprecated: use a=cross(a,b) instead - DEPRECATED(Vector3D & operator^=(const Vector3D &rhs);) - /// Cross-product of two vectors - /// Deprecated: use a=cross(a,b) instead - DEPRECATED(Vector3D & operator^=(const Vector2D &rhs);) // Binary operators @@ -176,14 +169,6 @@ class Vector3D : public FieldData { const Field3D operator*(const Vector3D &rhs) const; // Dot product const Field3D operator*(const Vector2D &rhs) const; - /// Cross-product of two vectors - /// Deprecated: use cross(a,b) instead - DEPRECATED(const Vector3D operator^(const Vector3D &rhs) const;) - - /// Cross-product of two vectors - /// Deprecated: use cross(a,b) instead - DEPRECATED(const Vector3D operator^(const Vector2D &rhs) const;) - /*! * Set variable cell location */ diff --git a/src/field/vector2d.cxx b/src/field/vector2d.cxx index 2a931dbbbb..541715b15b 100644 --- a/src/field/vector2d.cxx +++ b/src/field/vector2d.cxx @@ -245,14 +245,6 @@ Vector2D & Vector2D::operator/=(const Field2D &rhs) { return *this; } -///////////////// CROSS PRODUCT ////////////////// - -// cross product implementation in vector3d.cxx -Vector2D & Vector2D::operator^=(const Vector2D &rhs) { - *this = cross(*this, rhs); - return *this; -} - /*************************************************************** * BINARY OPERATORS ***************************************************************/ @@ -363,16 +355,6 @@ const Field3D Vector2D::operator*(const Vector3D &rhs) const { return rhs*(*this); } -///////////////// CROSS PRODUCT ////////////////// - -const Vector2D Vector2D::operator^(const Vector2D &rhs) const { - return cross(*this,rhs); -} - -const Vector3D Vector2D::operator^(const Vector3D &rhs) const { - return cross(*this,rhs); -} - /*************************************************************** * Get/set variable location for staggered meshes ***************************************************************/ diff --git a/src/field/vector3d.cxx b/src/field/vector3d.cxx index 9855e422ed..000e5e0fec 100644 --- a/src/field/vector3d.cxx +++ b/src/field/vector3d.cxx @@ -346,16 +346,6 @@ CROSS(Vector3D, Vector3D, Vector2D); CROSS(Vector3D, Vector2D, Vector3D); CROSS(Vector2D, Vector2D, Vector2D); -Vector3D & Vector3D::operator^=(const Vector3D &rhs) { - *this = cross(*this, rhs); - return *this; -} - -Vector3D & Vector3D::operator^=(const Vector2D &rhs) { - *this = cross(*this, rhs); - return *this; -} - /*************************************************************** * BINARY OPERATORS ***************************************************************/ @@ -491,16 +481,6 @@ const Field3D Vector3D::operator*(const Vector2D &rhs) const return result; } -///////////////// CROSS PRODUCT ////////////////// - -const Vector3D Vector3D::operator^(const Vector3D &rhs) const { - return cross(*this,rhs); -} - -const Vector3D Vector3D::operator^(const Vector2D &rhs) const { - return cross(*this,rhs); -} - /*************************************************************** * Get/set variable location for staggered meshes ***************************************************************/ From 749536d6d99c2c22710727211a1fc0f089b0a958 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 15:03:55 +0100 Subject: [PATCH 0094/1783] Remove deprecated vecops routines --- include/vecops.hxx | 39 --------------------------------------- src/field/vecops.cxx | 22 ---------------------- 2 files changed, 61 deletions(-) diff --git a/include/vecops.hxx b/include/vecops.hxx index ca06def8d2..134e76006f 100644 --- a/include/vecops.hxx +++ b/include/vecops.hxx @@ -44,17 +44,6 @@ const Vector2D Grad(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT); const Vector3D Grad(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT); -/// Gradient of scalar field \p f, returning a covariant vector -/// -/// All locations supported -/// -/// @param[in] f The field to differentiate -/// @param[in] outloc_x The cell location where the X component should be defined -/// @param[in] outloc_y The cell location where the Y component should be defined -/// @param[in] outloc_z The cell location where the Z component should be defined -const Vector3D DEPRECATED(Grad(const Field3D &f, CELL_LOC outloc_x, CELL_LOC outloc_y, - CELL_LOC outloc_z)); - /// Perpendicular gradient of scalar field \p f /// /// outloc must be either CELL_DEFAULT or f.getLocation() --> argument can be removed @@ -68,23 +57,6 @@ const Vector3D DEPRECATED(Grad(const Field3D &f, CELL_LOC outloc_x, CELL_LOC out /// const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT); -/// Perpendicular gradient of scalar field \p f -/// -/// -/// outloc must all be the same and must be either CELL_DEFAULT or f.getLocation() --> arguments can be removed -/// -/// result.x = df/dx - g_12/(JB)^2 df/dy -/// result.y = 0 -/// result.z = df/dz - g_23/(JB)^2 df/dy -/// -/// @param[in] f The field to differentiate -/// @param[in] outloc_x The cell location where the X component should be defined -/// @param[in] outloc_y The cell location where the Y component should be defined -/// @param[in] outloc_z The cell location where the Z component should be defined -/// -const Vector3D DEPRECATED(Grad_perp(const Field3D &f, CELL_LOC outloc_x, - CELL_LOC outloc_y, CELL_LOC outloc_z)); - /// Divergence of a vector \p v, returning a scalar /// /// All locations except `CELL_VSHIFT` supported. Note that if \p v is @@ -115,17 +87,6 @@ const Field3D Div(const Vector3D &v, const Field3D &f); /// const Vector2D Curl(const Vector2D &v); const Vector3D Curl(const Vector3D &v); -inline const Vector2D DEPRECATED(Curl(const Vector2D &v, CELL_LOC UNUSED(outloc))) { - return Curl(v); -} -inline const Vector3D DEPRECATED(Curl(const Vector3D &v, CELL_LOC UNUSED(outloc))) { - return Curl(v); -} -inline const Vector3D DEPRECATED(Curl(const Vector3D &v, CELL_LOC UNUSED(outloc_x), - CELL_LOC UNUSED(outloc_y), - CELL_LOC UNUSED(outloc_z))) { - return Curl(v); -} // Upwinding routines diff --git a/src/field/vecops.cxx b/src/field/vecops.cxx index 3f2644e961..4ebb9fb7e3 100644 --- a/src/field/vecops.cxx +++ b/src/field/vecops.cxx @@ -63,20 +63,6 @@ const Vector2D Grad(const Field2D &f, CELL_LOC outloc) { return result; } -const Vector3D Grad(const Field3D &f, CELL_LOC outloc_x, CELL_LOC outloc_y, - CELL_LOC outloc_z) { - // Note no Vector2D equivalent to this three location overload - TRACE("Grad( Field3D )"); - - ASSERT1((outloc_x == outloc_y && outloc_x == outloc_z) || - (outloc_x == CELL_XLOW && outloc_y == CELL_YLOW && - outloc_z == CELL_ZLOW)); // CELL_VSHIFT - - CELL_LOC outloc = - (outloc_x == outloc_y && outloc_x == outloc_z) ? outloc_x : CELL_VSHIFT; - return Grad(f, outloc); -} - const Vector3D Grad(const Field3D &f, CELL_LOC outloc) { TRACE("Grad( Field3D )"); @@ -106,14 +92,6 @@ const Vector3D Grad(const Field3D &f, CELL_LOC outloc) { return result; } -const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc_x, CELL_LOC outloc_y, - CELL_LOC outloc_z) { - TRACE("Grad_perp( Field3D )"); - ASSERT1(outloc_x == outloc_y && outloc_x == outloc_z); - ASSERT1(outloc_x == CELL_DEFAULT || outloc_x == f.getLocation()); - return Grad_perp(f, outloc_x); -} - const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc) { TRACE("Grad_perp( Field3D )"); From 5a7fc6f99b4e135a5b1f60f7dc2ef21080553952 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 15:05:35 +0100 Subject: [PATCH 0095/1783] Remove deprecated routines from cyclic_reduction --- include/cyclic_reduction.hxx | 58 ------------------------------------ 1 file changed, 58 deletions(-) diff --git a/include/cyclic_reduction.hxx b/include/cyclic_reduction.hxx index 78cac60ca6..c8acb130cf 100644 --- a/include/cyclic_reduction.hxx +++ b/include/cyclic_reduction.hxx @@ -91,31 +91,6 @@ public: /// By default not periodic void setPeriodic(bool p = true) { periodic = p; } - DEPRECATED(void setCoefs(T a[], T b[], T c[])) { - // Set coefficients - setCoefs(1, &a, &b, &c); - } - - DEPRECATED(void setCoefs(int nsys, T **a, T **b, T **c)) { - Matrix aMatrix(nsys, N); - Matrix bMatrix(nsys, N); - Matrix cMatrix(nsys, N); - - // Copy data into matrices - BOUT_OMP(parallel for) - for (int j = 0; j < nsys; ++j) { - for (int i = 0; i < N; ++i) { - aMatrix(j, i) = a[j][i]; - bMatrix(j, i) = b[j][i]; - cMatrix(j, i) = c[j][i]; - } - } - - setCoefs(aMatrix, bMatrix, cMatrix); - // Don't copy ?Matrix back into ? as setCoefs - // doesn't modify these. Could copy out if we really wanted. - } - void setCoefs(Array &a, Array &b, Array &c) { ASSERT2(a.size() == b.size()); ASSERT2(a.size() == c.size()); @@ -163,39 +138,6 @@ public: } } - /// Solve a single triadiagonal system - /// - DEPRECATED(void solve(T rhs[], T x[])) { - // Solving single system - solve(1, &rhs, &x); - } - - /// Solve a set of tridiagonal systems - /// - DEPRECATED(void solve(int nrhs, T **rhs, T **x)) { - Matrix rhsMatrix(nrhs, N); - Matrix xMatrix(nrhs, N); - - // Copy input data into matrix - BOUT_OMP(parallel for) - for (int j = 0; j < nrhs; ++j) { - for (int i = 0; i < N; ++i) { - rhsMatrix(j, i) = rhs[j][i]; - } - } - - // Solve - solve(rhsMatrix, xMatrix); - - // Copy result back into argument - BOUT_OMP(parallel for) - for (int j = 0; j < nrhs; ++j) { - for (int i = 0; i < N; ++i) { - x[j][i] = xMatrix(j, i); - } - } - } - /// Solve a set of tridiagonal systems /// /// @param[in] rhs Array storing Values of the rhs for a single system From babad607332546ccdd3e1a7cb4bbd91a2a6d6589 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 15:06:44 +0100 Subject: [PATCH 0096/1783] Remove deprecated FCI constructors --- src/mesh/parallel/fci.hxx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index 05bd0093d6..293113b91d 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -27,7 +27,6 @@ #define __FCITRANSFORM_H__ #include -#include #include #include #include @@ -46,8 +45,6 @@ class FCIMap { public: /// dir MUST be either +1 or -1 FCIMap(Mesh& mesh, int dir, bool zperiodic); - DEPRECATED(FCIMap(Mesh &mesh, int dir, bool UNUSED(yperiodic), bool zperiodic)) - : FCIMap(mesh, dir, zperiodic) {} int dir; /**< Direction of map */ @@ -68,8 +65,6 @@ public: */ class FCITransform : public ParallelTransform { public: - DEPRECATED(FCITransform(Mesh &mesh, bool UNUSED(yperiodic), bool zperiodic)) - : FCITransform(mesh, zperiodic) {} FCITransform(Mesh &mesh, bool zperiodic = true) : mesh(mesh), forward_map(mesh, +1, zperiodic), backward_map(mesh, -1, zperiodic), zperiodic(zperiodic) {} From af2d4272d20a1cd7265d7a0708015b0e738f2956 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 15:07:41 +0100 Subject: [PATCH 0097/1783] Remove deprecated Mesh::coordinates routine --- include/bout/mesh.hxx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index fcee0e58e3..056294bbe0 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -445,10 +445,6 @@ class Mesh { } } - Coordinates *DEPRECATED(coordinates(const CELL_LOC location = CELL_CENTRE)) { - return getCoordinates(location); - } - // First derivatives in index space // Implemented in src/mesh/index_derivs.hxx From 9f4104a4462ad53e58f583d3a41248b9e5e35d2f Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 15:08:43 +0100 Subject: [PATCH 0098/1783] Remove deprecated Field3D::setBackground --- include/field3d.hxx | 2 -- src/field/field3d.cxx | 4 ---- 2 files changed, 6 deletions(-) diff --git a/include/field3d.hxx b/include/field3d.hxx index ecce03302d..e90ccdc42e 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -36,7 +36,6 @@ class Mesh; // #include "bout/mesh.hxx" #include "bout/array.hxx" #include "bout/region.hxx" -#include "bout/deprecated.hxx" #include "bout/assert.hxx" #include "bout/field_visitor.hxx" @@ -432,7 +431,6 @@ class Field3D : public Field, public FieldData { friend class Vector3D; - DEPRECATED(void setBackground(const Field2D &f2d)); ///< Boundary is applied to the total of this and f2d void applyBoundary(bool init=false) override; void applyBoundary(BoutReal t); void applyBoundary(const string &condition); diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 6e963023e4..7d9dda7cea 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -371,10 +371,6 @@ Field3D & Field3D::operator=(const BoutReal val) { ///////////////////// BOUNDARY CONDITIONS ////////////////// -void Field3D::setBackground(const Field2D &f2d) { - background = &f2d; -} - void Field3D::applyBoundary(bool init) { TRACE("Field3D::applyBoundary()"); From 78ef377a04b201e4f65d62fd6f9bc5d3b942fc9c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 15:13:22 +0100 Subject: [PATCH 0099/1783] Remove deprecated derivs routines --- include/derivs.hxx | 282 +-------------------------------------------- 1 file changed, 1 insertion(+), 281 deletions(-) diff --git a/include/derivs.hxx b/include/derivs.hxx index 463343955e..a0060e71d6 100644 --- a/include/derivs.hxx +++ b/include/derivs.hxx @@ -58,13 +58,6 @@ const Field3D DDX(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match DDX(const Field3D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D DDX(const Field3D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return DDX(f, outloc, method, region); -} - /// Calculate first partial derivative in X /// /// \f$\partial / \partial x\f$ @@ -80,13 +73,6 @@ DEPRECATED(inline const Field3D DDX(const Field3D &f, DIFF_METHOD method, const Field2D DDX(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match DDX(const Field2D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D DDX(const Field2D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return DDX(f, outloc, method, region); -} - /// Calculate first partial derivative in Y /// /// \f$\partial / \partial y\f$ @@ -102,13 +88,6 @@ DEPRECATED(inline const Field2D DDX(const Field2D &f, DIFF_METHOD method, const Field3D DDY(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match DDY(const Field3D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D DDY(const Field3D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return DDY(f, outloc, method, region); -} - /// Calculate first partial derivative in Y /// /// \f$\partial / \partial y\f$ @@ -124,13 +103,6 @@ DEPRECATED(inline const Field3D DDY(const Field3D &f, DIFF_METHOD method, const Field2D DDY(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match DDY(const Field2D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D DDY(const Field2D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return DDY(f, outloc, method, region); -} - /// Calculate first partial derivative in Z /// /// \f$\partial / \partial z\f$ @@ -146,13 +118,6 @@ DEPRECATED(inline const Field2D DDY(const Field2D &f, DIFF_METHOD method, const Field3D DDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match DDZ(const Field3D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D DDZ(const Field3D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return DDZ(f, outloc, method, region); -} - /// Calculate first partial derivative in Z /// /// \f$\partial / \partial z\f$ @@ -167,13 +132,6 @@ DEPRECATED(inline const Field3D DDZ(const Field3D &f, DIFF_METHOD method, /// If not given, defaults to RGN_NOBNDRY const Field2D DDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); - -/// Reorder arguments to match DDZ(const Field2D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D DDZ(const Field2D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return DDZ(f, outloc, method, region); -} ////////// SECOND DERIVATIVES ////////// /// Calculate second partial derivative in X @@ -191,13 +149,6 @@ DEPRECATED(inline const Field2D DDZ(const Field2D &f, DIFF_METHOD method, const Field3D D2DX2(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D2DX2(const Field3D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D D2DX2(const Field3D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D2DX2(f, outloc, method, region); -} - /// Calculate second partial derivative in X /// /// \f$\partial^2 / \partial x^2\f$ @@ -213,13 +164,6 @@ DEPRECATED(inline const Field3D D2DX2(const Field3D &f, DIFF_METHOD method, const Field2D D2DX2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D2DX2(const Field2D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D D2DX2(const Field2D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D2DX2(f, outloc, method, region); -} - /// Calculate second partial derivative in Y /// /// \f$\partial^2 / \partial y^2\f$ @@ -235,13 +179,6 @@ DEPRECATED(inline const Field2D D2DX2(const Field2D &f, DIFF_METHOD method, const Field3D D2DY2(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D2DY2(const Field3D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D D2DY2(const Field3D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D2DY2(f, outloc, method, region); -} - /// Calculate second partial derivative in Y /// /// \f$\partial^2 / \partial y^2\f$ @@ -257,13 +194,6 @@ DEPRECATED(inline const Field3D D2DY2(const Field3D &f, DIFF_METHOD method, const Field2D D2DY2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D2DY2(const Field2D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D D2DY2(const Field2D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D2DY2(f, outloc, method, region); -} - /// Calculate second partial derivative in Z /// /// \f$\partial^2 / \partial z^2\f$ @@ -279,13 +209,6 @@ DEPRECATED(inline const Field2D D2DY2(const Field2D &f, DIFF_METHOD method, const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D2DZ2(const Field3D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D D2DZ2(const Field3D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D2DZ2(f, outloc, method, region); -} - /// Calculate second partial derivative in Z /// /// \f$\partial^2 / \partial z^2\f$ @@ -301,13 +224,7 @@ DEPRECATED(inline const Field3D D2DZ2(const Field3D &f, DIFF_METHOD method, const Field2D D2DZ2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D2DZ2(const Field2D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D D2DZ2(const Field2D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D2DZ2(f, outloc, method, region); -} -////////// FORTH DERIVATIVES ////////// +////////// FOURTH DERIVATIVES ////////// /// Calculate forth partial derivative in X /// @@ -324,13 +241,6 @@ DEPRECATED(inline const Field2D D2DZ2(const Field2D &f, DIFF_METHOD method, const Field3D D4DX4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D4DX4(const Field3D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D D4DX4(const Field3D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D4DX4(f, outloc, method, region); -} - /// Calculate forth partial derivative in X /// /// \f$\partial^4 / \partial x^4\f$ @@ -346,13 +256,6 @@ DEPRECATED(inline const Field3D D4DX4(const Field3D &f, DIFF_METHOD method, const Field2D D4DX4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D4DX4(const Field2D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D D4DX4(const Field2D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D4DX4(f, outloc, method, region); -} - /// Calculate forth partial derivative in Y /// /// \f$\partial^4 / \partial y^4\f$ @@ -368,13 +271,6 @@ DEPRECATED(inline const Field2D D4DX4(const Field2D &f, DIFF_METHOD method, const Field3D D4DY4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D4DY4(const Field3D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D D4DY4(const Field3D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D4DY4(f, outloc, method, region); -} - /// Calculate forth partial derivative in Y /// /// \f$\partial^4 / \partial y^4\f$ @@ -390,13 +286,6 @@ DEPRECATED(inline const Field3D D4DY4(const Field3D &f, DIFF_METHOD method, const Field2D D4DY4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D4DY4(const Field2D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D D4DY4(const Field2D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D4DY4(f, outloc, method, region); -} - /// Calculate forth partial derivative in Z /// /// \f$\partial^4 / \partial z^4\f$ @@ -412,13 +301,6 @@ DEPRECATED(inline const Field2D D4DY4(const Field2D &f, DIFF_METHOD method, const Field3D D4DZ4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D4DZ4(const Field3D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D D4DZ4(const Field3D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D4DZ4(f, outloc, method, region); -} - /// Calculate forth partial derivative in Z /// /// \f$\partial^4 / \partial z^4\f$ @@ -434,14 +316,6 @@ DEPRECATED(inline const Field3D D4DZ4(const Field3D &f, DIFF_METHOD method, const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D4DZ4(const Field2D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D D4DZ4(const Field2D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D4DZ4(f, outloc, method, region); -} -///////// UPWINDING METHODS ///////////// - /// For terms of form v * grad(f) /// /// \f$v \cdot \partial f / \partial x\f$ @@ -458,14 +332,6 @@ DEPRECATED(inline const Field2D D4DZ4(const Field2D &f, DIFF_METHOD method, const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match VDDX(const Field3D &v, const Field3D &f, CELL_LOC, -/// DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D VDDX(const Field3D &v, const Field3D &f, - DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return VDDX(v, f, outloc, method, region); -} - /// For terms of form v * grad(f) /// /// \f$v \cdot \partial f / \partial x\f$ @@ -482,14 +348,6 @@ DEPRECATED(inline const Field3D VDDX(const Field3D &v, const Field3D &f, const Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match VDDX(const Field2D &v, const Field2D &f, CELL_LOC, -/// DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D VDDX(const Field2D &v, const Field2D &f, - DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return VDDX(v, f, outloc, method, region); -} - /// For terms of form v * grad(f) /// /// \f$v \cdot \partial f / \partial y\f$ @@ -506,14 +364,6 @@ DEPRECATED(inline const Field2D VDDX(const Field2D &v, const Field2D &f, const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match VDDY(const Field3D &v, const Field3D &f, CELL_LOC, -/// DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D VDDY(const Field3D &v, const Field3D &f, - DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return VDDY(v, f, outloc, method, region); -} - /// For terms of form v * grad(f) /// /// \f$v \cdot \partial f / \partial y\f$ @@ -530,14 +380,6 @@ DEPRECATED(inline const Field3D VDDY(const Field3D &v, const Field3D &f, const Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match VDDY(const Field2D &v, const Field2D &f, CELL_LOC, -/// DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D VDDY(const Field2D &v, const Field2D &f, - DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return VDDY(v, f, outloc, method, region); -} - /// For terms of form v * grad(f) /// /// \f$v \cdot \partial f / \partial z\f$ @@ -554,14 +396,6 @@ DEPRECATED(inline const Field2D VDDY(const Field2D &v, const Field2D &f, const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match VDDZ(const Field3D &v, const Field3D &f, CELL_LOC, -/// DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D VDDZ(const Field3D &v, const Field3D &f, - DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return VDDZ(v, f, outloc, method, region); -} - /// For terms of form v * grad(f) /// /// \f$v \cdot \partial f / \partial z\f$ @@ -578,15 +412,6 @@ DEPRECATED(inline const Field3D VDDZ(const Field3D &v, const Field3D &f, const Field2D VDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match VDDZ(const Field2D &v, const Field2D &f, CELL_LOC, -/// DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D VDDZ(const Field2D &v, const Field2D &f, - DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return VDDZ(v, f, outloc, method, region); -} -///////// FLUX METHODS ///////////// - /// for terms of form div(v * f) /// /// \f$\partial (v f) / \partial x\f$ @@ -603,14 +428,6 @@ DEPRECATED(inline const Field2D VDDZ(const Field2D &v, const Field2D &f, const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match FDDX(const Field3D &v, const Field3D &f, CELL_LOC, -/// DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D FDDX(const Field3D &v, const Field3D &f, - DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return FDDX(v, f, outloc, method, region); -} - /// for terms of form div(v * f) /// /// \f$\partial (v f) / \partial x\f$ @@ -627,14 +444,6 @@ DEPRECATED(inline const Field3D FDDX(const Field3D &v, const Field3D &f, const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match FDDX(const Field2D &v, const Field2D &f, CELL_LOC, -/// DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D FDDX(const Field2D &v, const Field2D &f, - DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return FDDX(v, f, outloc, method, region); -} - /// for terms of form div(v * f) /// /// \f$\partial (v f) / \partial y\f$ @@ -651,14 +460,6 @@ DEPRECATED(inline const Field2D FDDX(const Field2D &v, const Field2D &f, const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match FDDY(const Field3D &v, const Field3D &f, CELL_LOC, -/// DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D FDDY(const Field3D &v, const Field3D &f, - DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return FDDY(v, f, outloc, method, region); -} - /// for terms of form div(v * f) /// /// \f$\partial (v f) / \partial y\f$ @@ -675,14 +476,6 @@ DEPRECATED(inline const Field3D FDDY(const Field3D &v, const Field3D &f, const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match FDDY(const Field2D &v, const Field2D &f, CELL_LOC, -/// DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D FDDY(const Field2D &v, const Field2D &f, - DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return FDDY(v, f, outloc, method, region); -} - /// for terms of form div(v * f) /// /// \f$\partial (v f) / \partial z\f$ @@ -699,14 +492,6 @@ DEPRECATED(inline const Field2D FDDY(const Field2D &v, const Field2D &f, const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match FDDZ(const Field3D &v, const Field3D &f, CELL_LOC, -/// DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D FDDZ(const Field3D &v, const Field3D &f, - DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return FDDZ(v, f, outloc, method, region); -} - /// for terms of form div(v * f) /// /// \f$\partial (v f) / \partial z\f$ @@ -723,14 +508,6 @@ DEPRECATED(inline const Field3D FDDZ(const Field3D &v, const Field3D &f, const Field2D FDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match FDDZ(const Field2D &v, const Field2D &f, CELL_LOC, -/// DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D FDDZ(const Field2D &v, const Field2D &f, - DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return FDDZ(v, f, outloc, method, region); -} - /// Calculate first partial derivative in Z /// /// \f$\partial / \partial z\f$ @@ -746,13 +523,6 @@ DEPRECATED(inline const Field2D FDDZ(const Field2D &v, const Field2D &f, const Vector3D DDZ(const Vector3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match DDZ(const Vector3D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Vector3D DDZ(const Vector3D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return DDZ(f, outloc, method, region); -} - /// Calculate mixed partial derivative in x and y /// /// \f$\partial^2 / \partial x \partial y\f$ @@ -768,13 +538,6 @@ DEPRECATED(inline const Vector3D DDZ(const Vector3D &f, DIFF_METHOD method, const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D2DXDY(const Field2D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D D2DXDY(const Field2D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D2DXDY(f, outloc, method, region); -} - /// Calculate mixed partial derivative in x and y /// /// \f$\partial^2 / \partial x \partial y\f$ @@ -790,13 +553,6 @@ DEPRECATED(inline const Field2D D2DXDY(const Field2D &f, DIFF_METHOD method, const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D2DXDY(const Field3D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D D2DXDY(const Field3D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D2DXDY(f, outloc, method, region); -} - /// Calculate mixed partial derivative in x and z /// /// \f$\partial^2 / \partial x \partial z\f$ @@ -812,13 +568,6 @@ DEPRECATED(inline const Field3D D2DXDY(const Field3D &f, DIFF_METHOD method, const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D2DXDZ(const Field2D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D D2DXDZ(const Field2D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D2DXDZ(f, outloc, method, region); -} - /// Calculate mixed partial derivative in x and z /// /// \f$\partial^2 / \partial x \partial z\f$ @@ -834,13 +583,6 @@ DEPRECATED(inline const Field2D D2DXDZ(const Field2D &f, DIFF_METHOD method, const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D2DXDZ(const Field3D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D D2DXDZ(const Field3D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D2DXDZ(f, outloc, method, region); -} - /// Calculate mixed partial derivative in y and z /// /// \f$\partial^2 / \partial y \partial z\f$ @@ -856,13 +598,6 @@ DEPRECATED(inline const Field3D D2DXDZ(const Field3D &f, DIFF_METHOD method, const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D2DYDZ(const Field2D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D D2DYDZ(const Field2D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D2DYDZ(f, outloc, method, region); -} - /// Calculate mixed partial derivative in y and z /// /// \f$\partial^2 / \partial y \partial z\f$ @@ -878,13 +613,6 @@ DEPRECATED(inline const Field2D D2DYDZ(const Field2D &f, DIFF_METHOD method, const Field3D D2DYDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match D2DYDZ(const Field3D &f, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const Field3D D2DYDZ(const Field3D &f, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return D2DYDZ(f, outloc, method, region); -} - /// For terms of form v * grad(f) /// /// \f$v \cdot \partial f / \partial z\f$ @@ -901,14 +629,6 @@ DEPRECATED(inline const Field3D D2DYDZ(const Field3D &f, DIFF_METHOD method, const Field2D VDDZ(const Field3D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -/// Reorder arguments to match VDDZ(const Field3D &v, const Field2D &f, CELL_LOC, -/// DIFF_METHOD, REGION) -DEPRECATED(inline const Field2D VDDZ(const Field3D &v, const Field2D &f, - DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return VDDZ(v, f, outloc, method, region); -} - // Deprecated methods // // Calculate first partial derivative in Z From ed677ffcbd00338291198d89b60a4e0bcb5b25de Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 15:14:04 +0100 Subject: [PATCH 0100/1783] Remove include of bout/deprecated where not needed --- include/datafile.hxx | 1 - include/field.hxx | 2 -- 2 files changed, 3 deletions(-) diff --git a/include/datafile.hxx b/include/datafile.hxx index 60322350a7..15ef36a356 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -14,7 +14,6 @@ class Datafile; #ifndef __DATAFILE_H__ #define __DATAFILE_H__ -#include "bout/deprecated.hxx" #include "bout_types.hxx" #include "field2d.hxx" #include "field3d.hxx" diff --git a/include/field.hxx b/include/field.hxx index 504ddd4898..78e44ccd75 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -36,8 +36,6 @@ class Field; #include #include "boutexception.hxx" -#include "bout/deprecated.hxx" - #include "unused.hxx" class Mesh; From 714d3ce83fd2f777dbc2a317c198862cc38aa027 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 15:32:36 +0100 Subject: [PATCH 0101/1783] Remove test for deprecated matrix --- tests/unit/sys/test_utils.cxx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/unit/sys/test_utils.cxx b/tests/unit/sys/test_utils.cxx index 5ff1c238c2..a11b672889 100644 --- a/tests/unit/sys/test_utils.cxx +++ b/tests/unit/sys/test_utils.cxx @@ -3,18 +3,6 @@ #include -// We know stuff might be deprecated, but we still want to test it -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -TEST(OldMatrixTest, CreateAndFree) { - BoutReal **test_matrix = matrix(5, 10); - - EXPECT_NE(nullptr, test_matrix); - - free_matrix(test_matrix); -} -#pragma GCC diagnostic pop - TEST(MatrixTest, DefaultShape) { Matrix matrix; From 4a8ec63eeef47a257cd1da4cd5274a92fd143318 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 17 Oct 2018 15:51:31 +0100 Subject: [PATCH 0102/1783] Attempt to fix boutcore for coordinates->getCoordinates change --- tools/pylib/_boutcore_build/boutcore.pyx.in | 2 +- tools/pylib/_boutcore_build/boutcpp.pxd.in | 2 +- tools/pylib/_boutcore_build/helper.cxx.in | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 6e20f61ae6..63559f9786 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -746,7 +746,7 @@ cdef class Mesh: Get the Coordinates object of this mesh """ if self._coords is None: - self._coords = coordsFromObj(self.cobj.coordinates()) + self._coords = coordsFromObj(self.cobj.getCoordinates()) return self._coords cdef Coordinates coordsFromObj(c.Coordinates * obj): diff --git a/tools/pylib/_boutcore_build/boutcpp.pxd.in b/tools/pylib/_boutcore_build/boutcpp.pxd.in index 49edc12332..de59f4394f 100644 --- a/tools/pylib/_boutcore_build/boutcpp.pxd.in +++ b/tools/pylib/_boutcore_build/boutcpp.pxd.in @@ -60,7 +60,7 @@ cdef extern from "bout/mesh.hxx": int ystart int LocalNx int LocalNy - Coordinates * coordinates() + Coordinates * getCoordinates() cdef extern from "bout/coordinates.hxx": cppclass Coordinates: diff --git a/tools/pylib/_boutcore_build/helper.cxx.in b/tools/pylib/_boutcore_build/helper.cxx.in index b618ae18b4..73d2f46834 100644 --- a/tools/pylib/_boutcore_build/helper.cxx.in +++ b/tools/pylib/_boutcore_build/helper.cxx.in @@ -165,7 +165,7 @@ Mesh * c_get_global_mesh(){ void c_mesh_normalise(Mesh * msh, double norm){ //printf("%g\n",norm); - auto coord = msh->coordinates(); + auto coord = msh->getCoordinates(); coord->dx/=norm; coord->dy/=norm; coord->dz/=norm; From 7e80f5713a66f391744250dc2e3e0d9f916a508a Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 18 Oct 2018 13:30:50 +0100 Subject: [PATCH 0103/1783] Update derivs jinja file to reflect removal of deprecated routines --- include/derivs.hxx.in.jinja | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/derivs.hxx.in.jinja b/include/derivs.hxx.in.jinja index b9660e6dbf..9d26e638a5 100644 --- a/include/derivs.hxx.in.jinja +++ b/include/derivs.hxx.in.jinja @@ -14,10 +14,3 @@ const {{field}} {{DD}}({{in_sig}}, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); - -/// Reorder arguments to match {{DD}}({{in_sig}}, CELL_LOC, DIFF_METHOD, REGION) -DEPRECATED(inline const {{field}} {{DD}}({{in_sig}}, DIFF_METHOD method, - CELL_LOC outloc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY)) { - return {{DD}}({{in_field}}, outloc, method,region); -} From 4927536cf8d3848f41d58d41b491e49f17253c4c Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 19 Oct 2018 11:42:06 +0100 Subject: [PATCH 0104/1783] Add unary operator+ to fields A slight annoyance when testing code: ``` ddt(T) = //A + B ; ``` Commenting out the first term leads to a compiler error, since unary + is not defined. The unary + operator does nothing, but here is defined for `Field2D`, `Field3D` and `FieldPerp` separately. This could perhaps be a template ``` template T operator+(const T& f) {return f;} ``` but I don't know if there could be unexpected side-effects from a general template like that. Maybe `enable_if` could help? --- include/field2d.hxx | 4 ++++ include/field3d.hxx | 4 ++++ include/fieldperp.hxx | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/include/field2d.hxx b/include/field2d.hxx index 51e14607ab..ae03aaea87 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -309,6 +309,10 @@ Field2D operator/(BoutReal lhs, const Field2D &rhs); */ Field2D operator-(const Field2D &f); +/// Unary plus. This does nothing, but is sometimes useful +/// when commenting out code or for clarification. +Field2D operator+(const Field2D &f) { return f; } + // Non-member functions /// Square root of \p f over region \p rgn diff --git a/include/field3d.hxx b/include/field3d.hxx index 1025f935ab..8b18070c00 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -561,6 +561,10 @@ Field3D operator/(BoutReal lhs, const Field3D &rhs); */ Field3D operator-(const Field3D &f); +/// Unary plus. This does nothing, but is sometimes useful +/// when commenting out code or for clarification. +Field3D operator+(const Field3D &f) { return f; } + // Non-member functions /// Calculates the minimum of a field, excluding the boundary/guard diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 90fdcf03d8..cbedaaf70c 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -310,6 +310,10 @@ const FieldPerp operator/(BoutReal lhs, const FieldPerp &rhs); */ FieldPerp operator-(const FieldPerp &f); +/// Unary plus. This does nothing, but is sometimes useful +/// when commenting out code or for clarification. +FieldPerp operator+(const FieldPerp &f) { return f; } + /// Square root const FieldPerp sqrt(const FieldPerp &f, REGION rgn=RGN_ALL); From 5e997aa8e82318f91d584a90403e40ebe287967f Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 19 Oct 2018 14:24:23 +0100 Subject: [PATCH 0105/1783] Adding unary operator+ template Removing operator+ from Field3D, as covered by new template. --- include/field.hxx | 4 ++++ include/field2d.hxx | 6 +----- include/field3d.hxx | 6 ------ include/fieldperp.hxx | 4 ---- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index 07d9c65199..802231bb81 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -139,4 +139,8 @@ class Field { DEPRECATED(void error(const char *s, ...) const); }; +/// Unary + operator. This doesn't do anything +template +T operator+(const T& f) {return f;} + #endif /* __FIELD_H__ */ diff --git a/include/field2d.hxx b/include/field2d.hxx index ae03aaea87..122d6c097e 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -114,7 +114,7 @@ class Field2D : public Field, public FieldData { int getNz() const override {return 1;}; // Operators - + /*! * Assignment from Field2D. After this both fields will * share the same underlying data. To make a true copy, @@ -309,10 +309,6 @@ Field2D operator/(BoutReal lhs, const Field2D &rhs); */ Field2D operator-(const Field2D &f); -/// Unary plus. This does nothing, but is sometimes useful -/// when commenting out code or for clarification. -Field2D operator+(const Field2D &f) { return f; } - // Non-member functions /// Square root of \p f over region \p rgn diff --git a/include/field3d.hxx b/include/field3d.hxx index 8b18070c00..782ee273c2 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -437,8 +437,6 @@ class Field3D : public Field, public FieldData { ///////////////////////////////////////////////////////// // Operators - const Field3D operator+() const {return *this;} - /// Assignment operators ///@{ Field3D & operator=(const Field3D &rhs); @@ -561,10 +559,6 @@ Field3D operator/(BoutReal lhs, const Field3D &rhs); */ Field3D operator-(const Field3D &f); -/// Unary plus. This does nothing, but is sometimes useful -/// when commenting out code or for clarification. -Field3D operator+(const Field3D &f) { return f; } - // Non-member functions /// Calculates the minimum of a field, excluding the boundary/guard diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index cbedaaf70c..90fdcf03d8 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -310,10 +310,6 @@ const FieldPerp operator/(BoutReal lhs, const FieldPerp &rhs); */ FieldPerp operator-(const FieldPerp &f); -/// Unary plus. This does nothing, but is sometimes useful -/// when commenting out code or for clarification. -FieldPerp operator+(const FieldPerp &f) { return f; } - /// Square root const FieldPerp sqrt(const FieldPerp &f, REGION rgn=RGN_ALL); From cad0a030ae6891c069bff4289782ce4be5922f1a Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 19 Oct 2018 15:13:07 +0100 Subject: [PATCH 0106/1783] Remove deprecated DDZ routines --- include/derivs.hxx | 33 --------------------------------- include/derivs.hxx.in.py | 37 ------------------------------------- 2 files changed, 70 deletions(-) diff --git a/include/derivs.hxx b/include/derivs.hxx index a0060e71d6..30a6b86f20 100644 --- a/include/derivs.hxx +++ b/include/derivs.hxx @@ -629,37 +629,4 @@ const Field3D D2DYDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, const Field2D VDDZ(const Field3D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); -// Deprecated methods -// -// Calculate first partial derivative in Z -// -// $\partial / \partial z $ -// -// @param[in] f The field to be differentiated -// @param[in] outloc The cell location where the result is desired. -// If staggered grids is not enabled then this has no effect -// @param[in] method Differencing method to use. This overrides the default -// @param[in] inc_xbndry DEPRECATED: use REGION flags -// Determines whether the derivative should be calculated in -// the X boundaries. This allows mixed operators (e.g. -// D2DXDZ) without additional communication - -inline const Field3D DDZ(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, - bool inc_xbndry) { - return DDZ(f, outloc, method, inc_xbndry ? RGN_NOY : RGN_NOBNDRY); -} - -inline const Field3D DDZ(const Field3D &f, DIFF_METHOD method, CELL_LOC outloc, - bool inc_xbndry) { - return DDZ(f, outloc, method, inc_xbndry ? RGN_NOY : RGN_NOBNDRY); -} - -inline const Field3D DDZ(const Field3D &f, DIFF_METHOD method, bool inc_xbndry) { - return DDZ(f, CELL_DEFAULT, method, inc_xbndry ? RGN_NOY : RGN_NOBNDRY); -} - -inline const Field3D DDZ(const Field3D &f, bool inc_xbndry) { - return DDZ(f, CELL_DEFAULT, DIFF_DEFAULT, inc_xbndry ? RGN_NOY : RGN_NOBNDRY); -} - #endif // __DERIVS_H__ diff --git a/include/derivs.hxx.in.py b/include/derivs.hxx.in.py index ee344c912d..d6b317ee02 100755 --- a/include/derivs.hxx.in.py +++ b/include/derivs.hxx.in.py @@ -115,41 +115,6 @@ def render(self): desc="for terms of form div(v * f)", latex="\partial (v f) / \partial $d_lower")] -deprecated_methods=""" -// Deprecated methods -// -// Calculate first partial derivative in Z -// -// \f$\partial / \partial z\f$ -// -// @param[in] f The field to be differentiated -// @param[in] outloc The cell location where the result is desired. -// If staggered grids is not enabled then this has no effect -// @param[in] method Differencing method to use. This overrides the default -// @param[in] inc_xbndry DEPRECATED: use REGION flags -// Determines whether the derivative should be calculated in -// the X boundaries. This allows mixed operators (e.g. -// D2DXDZ) without additional communication - - -inline const Field3D DDZ(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, bool inc_xbndry) { - return DDZ(f, outloc, method, inc_xbndry ? RGN_NOY : RGN_NOBNDRY); -} - -inline const Field3D DDZ(const Field3D &f, DIFF_METHOD method, CELL_LOC outloc, bool inc_xbndry) { - return DDZ(f, outloc, method, inc_xbndry ? RGN_NOY : RGN_NOBNDRY); -} - -inline const Field3D DDZ(const Field3D &f, DIFF_METHOD method, bool inc_xbndry) { - return DDZ(f, CELL_DEFAULT, method, inc_xbndry ? RGN_NOY : RGN_NOBNDRY); -} - -inline const Field3D DDZ(const Field3D &f, bool inc_xbndry) { - return DDZ(f, CELL_DEFAULT, DIFF_DEFAULT, inc_xbndry ? RGN_NOY : RGN_NOBNDRY); -} - -""" - end_of_file="#endif // __DERIVS_H__" if __name__ == "__main__": @@ -198,6 +163,4 @@ def render(self): cur.in_sig="const Field3D &v, const Field2D &f" cur.render() - print(deprecated_methods) - print(end_of_file) From 0782c164656e75b665356be33c1a7014dcebce15 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 19 Oct 2018 15:27:49 +0100 Subject: [PATCH 0107/1783] Removing deprecated boundaries --- src/mesh/boundary_factory.cxx | 3 - src/mesh/boundary_standard.cxx | 142 --------------------------------- 2 files changed, 145 deletions(-) diff --git a/src/mesh/boundary_factory.cxx b/src/mesh/boundary_factory.cxx index 86a617e2fd..fc56ddae8b 100644 --- a/src/mesh/boundary_factory.cxx +++ b/src/mesh/boundary_factory.cxx @@ -15,14 +15,11 @@ BoundaryFactory *BoundaryFactory::instance = nullptr; BoundaryFactory::BoundaryFactory() { add(new BoundaryDirichlet(), "dirichlet"); add(new BoundaryDirichlet(), "dirichlet_o2"); // Synonym for "dirichlet" - add(new BoundaryDirichlet_2ndOrder(), "dirichlet_2ndorder"); // Deprecated add(new BoundaryDirichlet_O3(), "dirichlet_o3"); add(new BoundaryDirichlet_O4(), "dirichlet_o4"); add(new BoundaryDirichlet_4thOrder(), "dirichlet_4thorder"); add(new BoundaryNeumann(), "neumann"); add(new BoundaryNeumann(), "neumann_O2"); // Synonym for "neumann" - add(new BoundaryNeumann2(), "neumann2"); // Deprecated - add(new BoundaryNeumann_2ndOrder(), "neumann_2ndorder"); // Deprecated add(new BoundaryNeumann_4thOrder(), "neumann_4thorder"); add(new BoundaryNeumann_O4(), "neumann_O4"); add(new BoundaryNeumannPar(), "neumannpar"); diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 44f910d74d..d7a71226a3 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -1398,60 +1398,6 @@ void BoundaryDirichlet_O4::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDirichlet_2ndOrder::clone(BoundaryRegion *region, const list &args) { - output << "WARNING: Use of boundary condition \"dirichlet_2ndorder\" is deprecated!\n"; - output << " Consider using \"dirichlet\" instead\n"; - verifyNumPoints(region,2); - if(!args.empty()) { - // First argument should be a value - val = stringToReal(args.front()); - return new BoundaryDirichlet_2ndOrder(region, val); - } - return new BoundaryDirichlet_2ndOrder(region); -} - -void BoundaryDirichlet_2ndOrder::apply(Field2D &f) { - // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val - // N.B. Only first guard cells (closest to the grid) should ever be used - for(bndry->first(); !bndry->isDone(); bndry->next1d()) { - f(bndry->x,bndry->y) = 8./3.*val - 2.*f(bndry->x-bndry->bx,bndry->y-bndry->by) + 1./3.*f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by); -#ifdef BOUNDARY_CONDITIONS_UPGRADE_EXTRAPOLATE_FOR_2ND_ORDER - f(bndry->x+bndry->bx,bndry->y+bndry->by) = 3.*f(bndry->x,bndry->y) - 3.*f(bndry->x-bndry->bx,bndry->y-bndry->by) + f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by); -#elif defined(CHECK) - f(bndry->x+bndry->bx,bndry->y+bndry->by) = 1.e60; -#endif - } -} - -void BoundaryDirichlet_2ndOrder::apply(Field3D &f) { - // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val - // N.B. Only first guard cells (closest to the grid) should ever be used - for(bndry->first(); !bndry->isDone(); bndry->next1d()) - for(int z=0;zLocalNz;z++) { - f(bndry->x,bndry->y,z) = 8./3.*val - 2.*f(bndry->x-bndry->bx,bndry->y-bndry->by,z) + 1./3.*f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by,z); -#ifdef BOUNDARY_CONDITIONS_UPGRADE_EXTRAPOLATE_FOR_2ND_ORDER - f(bndry->x+bndry->bx,bndry->y+bndry->by,z) = 3.*f(bndry->x,bndry->y,z) - 3.*f(bndry->x-bndry->bx,bndry->y-bndry->by,z) + f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by,z); -#elif defined(CHECK) - f(bndry->x+bndry->bx,bndry->y+bndry->by,z) = 1.e60; -#endif - } -} - -void BoundaryDirichlet_2ndOrder::apply_ddt(Field2D &f) { - Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - (*dt)(bndry->x,bndry->y) = 0.; // Set time derivative to zero -} - -void BoundaryDirichlet_2ndOrder::apply_ddt(Field3D &f) { - Field3D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) - (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero -} - -/////////////////////////////////////////////////////////////// - BoundaryOp* BoundaryDirichlet_4thOrder::clone(BoundaryRegion *region, const list &args) { verifyNumPoints(region,4); if(!args.empty()) { @@ -1591,94 +1537,6 @@ void BoundaryNeumann_NonOrthogonal::apply(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann2::clone(BoundaryRegion *region, const list &args) { - output << "WARNING: Use of boundary condition \"neumann2\" is deprecated!\n"; - output << " Consider using \"neumann\" instead\n"; - verifyNumPoints(region,2); - if(!args.empty()) { - output << "WARNING: Ignoring arguments to BoundaryNeumann2\n"; - } - return new BoundaryNeumann2(region); -} - -void BoundaryNeumann2::apply(Field2D &f) { - // Loop over all elements and use one-sided differences - for(bndry->first(); !bndry->isDone(); bndry->next()) - f(bndry->x, bndry->y) = (4.*f(bndry->x - bndry->bx, bndry->y - bndry->by) - f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by))/3.; -} - -void BoundaryNeumann2::apply(Field3D &f) { - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) - f(bndry->x, bndry->y, z) = (4.*f(bndry->x - bndry->bx, bndry->y - bndry->by, z) - f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by, z))/3.; -} - -/////////////////////////////////////////////////////////////// - -BoundaryOp* BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const list &args) { - output << "WARNING: Use of boundary condition \"neumann_2ndorder\" is deprecated!\n"; - output << " Consider using \"neumann\" instead\n"; -#ifdef BOUNDARY_CONDITIONS_UPGRADE_EXTRAPOLATE_FOR_2ND_ORDER - verifyNumPoints(region,2); -#else - verifyNumPoints(region,1); -#endif - if(!args.empty()) { - // First argument should be a value - val = stringToReal(args.front()); - return new BoundaryNeumann_2ndOrder(region, val); - } - return new BoundaryNeumann_2ndOrder(region); -} - -void BoundaryNeumann_2ndOrder::apply(Field2D &f) { - Coordinates *metric = f.getCoordinates(); - - // Set (at 2nd order) the gradient at the mid-point between the guard cell and the grid cell to be val - // This sets the value of the co-ordinate derivative, i.e. DDX/DDY not Grad_par/Grad_perp.x - // N.B. Only first guard cells (closest to the grid) should ever be used - for(bndry->first(); !bndry->isDone(); bndry->next1d()) { - f(bndry->x,bndry->y) = f(bndry->x-bndry->bx,bndry->y-bndry->by) + val*(bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y)); -#ifdef BOUNDARY_CONDITIONS_UPGRADE_EXTRAPOLATE_FOR_2ND_ORDER - f(bndry->x+bndry->bx,bndry->y+bndry->by) = 3.*f(bndry->x,bndry->y) - 3.*f(bndry->x-bndry->bx,bndry->y-bndry->by) + f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by); -#elif defined(CHECK) - f(bndry->x+bndry->bx,bndry->y+bndry->by) = 1.e60; -#endif - } -} - -void BoundaryNeumann_2ndOrder::apply(Field3D &f) { - Coordinates *metric = f.getCoordinates(); - // Set (at 2nd order) the gradient at the mid-point between the guard cell and the grid cell to be val - // This sets the value of the co-ordinate derivative, i.e. DDX/DDY not Grad_par/Grad_perp.x - // N.B. Only first guard cells (closest to the grid) should ever be used - for(bndry->first(); !bndry->isDone(); bndry->next1d()) - for(int z=0;zLocalNz;z++) { - BoutReal delta = bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y); - f(bndry->x,bndry->y,z) = f(bndry->x-bndry->bx,bndry->y-bndry->by,z) + val*delta; -#ifdef BOUNDARY_CONDITIONS_UPGRADE_EXTRAPOLATE_FOR_2ND_ORDER - f(bndry->x+bndry->bx,bndry->y+bndry->by,z) = 3.*f(bndry->x,bndry->y,z) - 3.*f(bndry->x-bndry->bx,bndry->y-bndry->by,z) + f(bndry->x-2*bndry->bx,bndry->y-2*bndry->by,z); -#elif defined(CHECK) - f(bndry->x+bndry->bx,bndry->y+bndry->by,z) = 1.e60; -#endif - } -} - -void BoundaryNeumann_2ndOrder::apply_ddt(Field2D &f) { - Field2D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - (*dt)(bndry->x,bndry->y) = 0.; // Set time derivative to zero -} - -void BoundaryNeumann_2ndOrder::apply_ddt(Field3D &f) { - Field3D *dt = f.timeDeriv(); - for(bndry->first(); !bndry->isDone(); bndry->next()) - for(int z=0;zLocalNz;z++) - (*dt)(bndry->x,bndry->y,z) = 0.; // Set time derivative to zero -} - -/////////////////////////////////////////////////////////////// - BoundaryOp* BoundaryNeumann::clone(BoundaryRegion *region, const list &args){ verifyNumPoints(region,1); std::shared_ptr newgen = nullptr; From 54737ab1e6e887eb5e604770fbe10d4998642e2c Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 19 Oct 2018 17:25:01 +0100 Subject: [PATCH 0108/1783] Allow escaping of characters in expressions If variables have names which include symbols like + then expressions need to escape the symbols to avoid treating them as arithmetic operators. This can be important when evolving variables with names like "H+" or "He+2". Two mechanisms currently allowed: 1. A backslash (\) escapes the following character, so an expression could include something like "h2\+:density" as a symbol 2. Backquotes escape a sequence of characters, so "`h2+:density`" or "h`2+`:density" could be used. Note that the colon symbol always indicates section, and is not escaped. This is to avoid ambiguity. The options reader therefore checks if keys include `:` and throws if they do. Unit tests added for all these things --- src/sys/expressionparser.cxx | 33 ++++++++++-- src/sys/options/options_ini.cxx | 11 ++-- tests/unit/sys/test_expressionparser.cxx | 66 ++++++++++++++++++++++++ tests/unit/sys/test_optionsreader.cxx | 57 ++++++++++++++++++++ 4 files changed, 159 insertions(+), 8 deletions(-) diff --git a/src/sys/expressionparser.cxx b/src/sys/expressionparser.cxx index 34ecfbd3e9..42225494f9 100644 --- a/src/sys/expressionparser.cxx +++ b/src/sys/expressionparser.cxx @@ -310,17 +310,40 @@ char ExpressionParser::LexInfo::nextToken() { curtok = 0; return 0; } - - if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9_:]* + + if (isalpha(LastChar) || (LastChar == '`')) { // identifier: [a-zA-Z`][a-zA-Z0-9_:\`]* curident.clear(); do { - curident += LastChar; + if (LastChar == '\\') { + // Escape character. Whatever the next character is, include it in the identifier + LastChar = static_cast(ss.get()); + if (LastChar == EOF) { + throw ParseException("Unexpected end of input after \\ character"); + } + + curident += LastChar; + } else if (LastChar == '`') { + // An escaped symbol + // Include all characters until the next ` (backtick) + LastChar = static_cast(ss.get()); // Skip the ` + do { + curident += LastChar; + LastChar = static_cast(ss.get()); + if (LastChar == EOF) { + throw ParseException("Unexpected end of input; expecting ` (backtick)"); + } + } while (LastChar != '`'); + // Final ` will not be added to the symbol + } else { + curident += LastChar; + } LastChar = static_cast(ss.get()); - }while(isalnum(LastChar) || (LastChar == '_') || (LastChar == ':')); + } while (isalnum(LastChar) || (LastChar == '_') || (LastChar == ':') || + (LastChar == '\\') || (LastChar == '`')); curtok = -2; return curtok; } - + // Handle numbers if (isdigit(LastChar) || (LastChar == '.')) { // Number: [0-9.]+ diff --git a/src/sys/options/options_ini.cxx b/src/sys/options/options_ini.cxx index 62eaeca90a..bf4e420c19 100644 --- a/src/sys/options/options_ini.cxx +++ b/src/sys/options/options_ini.cxx @@ -153,8 +153,7 @@ string OptionINI::getNextLine(ifstream &fin) { return line; } -void OptionINI::parse(const string &buffer, string &key, string &value) -{ +void OptionINI::parse(const string &buffer, string &key, string &value) { // A key/value pair, separated by a '=' size_t startpos = buffer.find_first_of('='); @@ -169,8 +168,14 @@ void OptionINI::parse(const string &buffer, string &key, string &value) key = trim(buffer.substr(0, startpos), " \t\r\n\""); value = trim(buffer.substr(startpos+1), " \t\r\n\""); + + if (key.empty()) { + throw BoutException("\tEmpty key\n\tLine: %s", buffer.c_str()); + } - if(key.empty()) throw BoutException("\tEmpty key\n\tLine: %s", buffer.c_str()); + if (key.find(':') != std::string::npos) { + throw BoutException("\tKey must not contain ':' character\n\tLine: %s", buffer.c_str()); + } } void OptionINI::writeSection(const Options *options, std::ofstream &fout) { diff --git a/tests/unit/sys/test_expressionparser.cxx b/tests/unit/sys/test_expressionparser.cxx index 7b7822dd8a..62af1af1ab 100644 --- a/tests/unit/sys/test_expressionparser.cxx +++ b/tests/unit/sys/test_expressionparser.cxx @@ -352,3 +352,69 @@ TEST(ParseExceptionTest, WhatTest) { EXPECT_NE(message.find("test message"), std::string::npos); } } + +TEST_F(ExpressionParserTest, EscapeSymbol) { + auto fieldgen = parser.parseString("`x`"); + EXPECT_EQ(fieldgen->str(), "x"); + + for (auto x : x_array) { + for (auto y : y_array) { + for (auto z : z_array) { + for (auto t : t_array) { + EXPECT_DOUBLE_EQ(fieldgen->generate(x, y, z, t), x); + } + } + } + } +} + +// Backslash can be used to escape a single character +TEST_F(ExpressionParserTest, GeneratorNameEscape) { + parser.addGenerator("one+", std::make_shared()); + + auto fieldgen = parser.parseString("one\\+(x)"); + + for (auto x : x_array) { + for (auto y : y_array) { + for (auto z : z_array) { + for (auto t : t_array) { + EXPECT_DOUBLE_EQ(fieldgen->generate(x, y, z, t), x + 1); + } + } + } + } +} + +// Back-ticks can be used to escape sequences of characters +TEST_F(ExpressionParserTest, GeneratorNameLongEscape) { + parser.addGenerator("++", std::make_shared()); + + auto fieldgen = parser.parseString("`++`(x)"); + + for (auto x : x_array) { + for (auto y : y_array) { + for (auto z : z_array) { + for (auto t : t_array) { + EXPECT_DOUBLE_EQ(fieldgen->generate(x, y, z, t), x + 1); + } + } + } + } +} + +// Back-ticks can be used for part of a symbol +TEST_F(ExpressionParserTest, GeneratorNamePartEscape) { + parser.addGenerator("one+this", std::make_shared()); + + auto fieldgen = parser.parseString("one`+`this(x)"); + + for (auto x : x_array) { + for (auto y : y_array) { + for (auto z : z_array) { + for (auto t : t_array) { + EXPECT_DOUBLE_EQ(fieldgen->generate(x, y, z, t), x + 1); + } + } + } + } +} diff --git a/tests/unit/sys/test_optionsreader.cxx b/tests/unit/sys/test_optionsreader.cxx index 575cfdde7d..af70115eec 100644 --- a/tests/unit/sys/test_optionsreader.cxx +++ b/tests/unit/sys/test_optionsreader.cxx @@ -400,3 +400,60 @@ value = std::string val = opt["value"]; EXPECT_TRUE(val.empty()); } + +TEST_F(OptionsReaderTest, ReadFileEscapedChars) { + const std::string text = R"( +some-value = 3 # Names can contain symbols, but need to be escaped + +[h2+] # Sections can contain symbols +another = 5 +one-more = 2 + +[tests] +test1 = some\-value # Escaping of single characters +test2 = h2\+:another * some\-value # Including in section names +test3 = `some-value` + 1 # Escaping character sequence +test4 = `h2+:one-more` * 2 # Escape sequence including : +test5 = `h2+`:another # Escape only start of sequence +test6 = h2`+`:on`e-`more # Escape sequences in the middle +)"; + + char *filename = std::tmpnam(nullptr); + std::ofstream test_file(filename, std::ios::out); + test_file << text; + test_file.close(); + + OptionsReader reader; + reader.read(Options::getRoot(), filename); + std::remove(filename); + + auto options = Options::root()["tests"]; + + EXPECT_EQ(options["test1"].as(), 3); + EXPECT_EQ(options["test2"].as(), 15); + EXPECT_EQ(options["test3"].as(), 4); + EXPECT_EQ(options["test4"].as(), 4); + EXPECT_EQ(options["test5"].as(), 5); + EXPECT_EQ(options["test6"].as(), 2); +} + +// Variable names must not contain colons, escaped or otherwise +// Sections can contain colons, where they indicate subsections. +// That is tested elsewhere. +TEST_F(OptionsReaderTest, ReadFileVariablesNoColons) { + const std::string text = R"( +some:value = 3 +)"; + + char *filename = std::tmpnam(nullptr); + std::ofstream test_file(filename, std::ios::out); + test_file << text; + test_file.close(); + + OptionsReader reader; + + EXPECT_THROW(reader.read(Options::getRoot(), filename), BoutException); + std::remove(filename); +} + + From 6945c45ff53209a257482bd050c4fdf6764f11eb Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 19 Oct 2018 18:05:23 +0100 Subject: [PATCH 0109/1783] Started manual entry on escaping chars To be continued... --- manual/sphinx/user_docs/bout_options.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index cf852733fa..ccc254198d 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -44,6 +44,10 @@ name in square brackets. yetanother = true # a boolean finally = "some text" # a string +Option names can contain almost any character except ’=’ and ’:’, but +if they contain symbols then these will need to be escaped in +expressions. See below for how this is done. + Subsections can also be used, separated by colons ’:’, e.g. .. code-block:: cfg @@ -85,6 +89,11 @@ number though. Have a look through the examples to see how the options are used. +Special symbols in Option names +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + + Command line options -------------------- From 1e8b916b2a0384b1e6aa377eef412b967524397d Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 19 Oct 2018 22:40:30 +0100 Subject: [PATCH 0110/1783] Short manual secion on escaping Describes how to use variables with symbols in expressions by escaping them using \ or ` methods. --- manual/sphinx/user_docs/bout_options.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index ccc254198d..15c2d0a40a 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -92,7 +92,27 @@ Have a look through the examples to see how the options are used. Special symbols in Option names ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If option names contain symbols such as ``+`` or ``-`` then these symbols need +to be escaped in expressions or they will be treated as arithmetic +operators like addition or subtraction. To escape a single character +``\`` (backslash) can be used, for example ``plasma\-density * 10`` +would read the option ``plasma-density`` and multiply it +by 10 e.g +.. code-block:: cfg + + plasma-density = 1e19 + value = plasma\-density * 10 + +To escape multiple characters, ` (backquote) can be used: + +.. code-block:: cfg + + plasma-density = 1e19 + value = `plasma-density` * 10 + +The character ``:`` cannot be part of an option or section name, as it +is always used to separate sections. Command line options -------------------- From c168717c885a36103f36cbf03392850aef27e614 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 20 Oct 2018 00:26:04 +0100 Subject: [PATCH 0111/1783] Add support for unicode options Symbols in expressions can now have a much wider range of characters, including utf-8. Anything except whitespace and some reserved operators and brackets, which can be escaped if needed. Updated documentation, added tests. --- include/bout/sys/expressionparser.hxx | 9 ++- manual/sphinx/user_docs/bout_options.rst | 19 ++--- src/field/field_factory.cxx | 3 +- src/sys/expressionparser.cxx | 90 ++++++++++++++---------- tests/unit/sys/test_optionsreader.cxx | 26 +++++++ 5 files changed, 97 insertions(+), 50 deletions(-) diff --git a/include/bout/sys/expressionparser.hxx b/include/bout/sys/expressionparser.hxx index 250965940a..6806aaad5c 100644 --- a/include/bout/sys/expressionparser.hxx +++ b/include/bout/sys/expressionparser.hxx @@ -107,13 +107,17 @@ public: /// ^ precedence = 30 /// void addBinaryOp(char sym, FieldGeneratorPtr b, int precedence); - protected: /// This will be called to resolve any unknown symbols virtual FieldGeneratorPtr resolve(std::string &UNUSED(name)) { return nullptr; } /// Parses a given string into a tree of FieldGenerator objects FieldGeneratorPtr parseString(const std::string &input); + + /// Characters which cannot be used in symbols; all other allowed + /// In addition, whitespace cannot be used + /// Adding a binary operator adds its symbol to this string + std::string reserved_chars = "+-*/^[](){}"; private: @@ -123,13 +127,14 @@ private: /// Lexing info, used when splitting input into tokens struct LexInfo { - LexInfo(const std::string &input); + LexInfo(const std::string &input, const std::string &reserved_chars=""); signed char curtok; ///< Current token. -1 for number, -2 for string, 0 for "end of input" double curval; ///< Value if a number std::string curident; ///< Identifier, variable or function name signed char LastChar; ///< The last character read from the string std::stringstream ss; ///< Used to read values from the input string + std::string reserved_chars; ///< Reserved characters, not in symbols char nextToken(); ///< Get the next token in the string }; diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index 15c2d0a40a..275c7e4cab 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -23,7 +23,9 @@ The text input file ``BOUT.inp`` is always in a subdirectory called ``data`` for all examples. The files include comments (starting with either ``;`` or ``#``) and should be fairly self-explanatory. The format is the same as a windows INI file, consisting of ``name = value`` pairs. -Supported value types are: +Any type which can be read from a stream using the ``>>`` operator can +be stored in an option (see later for the implementation details). +Supported value types include: - Integers @@ -41,12 +43,12 @@ name in square brackets. [section1] something = 132 # an integer another = 5.131 # a real value - yetanother = true # a boolean - finally = "some text" # a string + 工作的 = true # a boolean + इनपुट = "some text" # a string -Option names can contain almost any character except ’=’ and ’:’, but -if they contain symbols then these will need to be escaped in -expressions. See below for how this is done. +Option names can contain almost any character except ’=’ and ’:’, including unicode. +If they contain arithmetic symbols (``+-*/^``), brackets (``(){}[]``) or whitespace, +then these will need to be escaped in expressions. See below for how this is done. Subsections can also be used, separated by colons ’:’, e.g. @@ -71,6 +73,7 @@ Variables can even reference other variables: Note that variables can be used before their definition; all variables are first read, and then processed afterwards. +The value ``pi`` is already defined, as is ``π``, and can be used in expressions. All expressions are calculated in floating point and then converted to an integer when read inside BOUT++. The conversion is done by rounding @@ -111,8 +114,8 @@ To escape multiple characters, ` (backquote) can be used: plasma-density = 1e19 value = `plasma-density` * 10 -The character ``:`` cannot be part of an option or section name, as it -is always used to separate sections. +The character ``:`` cannot be part of an option or section name, and cannot be escaped, +as it is always used to separate sections. Command line options -------------------- diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 3180b50592..7340c0a4e5 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -53,7 +53,8 @@ FieldFactory::FieldFactory(Mesh * localmesh, Options *opt) : fieldmesh(localmesh // Useful values addGenerator("pi", std::make_shared(PI)); - + addGenerator("π", std::make_shared(PI)); + // Some standard functions addGenerator("sin", std::make_shared(nullptr)); addGenerator("cos", std::make_shared(nullptr)); diff --git a/src/sys/expressionparser.cxx b/src/sys/expressionparser.cxx index 42225494f9..1c9793171f 100644 --- a/src/sys/expressionparser.cxx +++ b/src/sys/expressionparser.cxx @@ -133,11 +133,13 @@ void ExpressionParser::addGenerator(const string &name, FieldGeneratorPtr g) { void ExpressionParser::addBinaryOp(char sym, FieldGeneratorPtr b, int precedence) { bin_op[sym] = std::make_pair(b, precedence); + // Add to string of reserved characters + reserved_chars += sym; } FieldGeneratorPtr ExpressionParser::parseString(const string &input) { // Allocate a new lexer - LexInfo lex(input); + LexInfo lex(input, reserved_chars); // Parse return parseExpression(lex); @@ -293,17 +295,19 @@ FieldGeneratorPtr ExpressionParser::parseExpression(LexInfo &lex) { ////////////////////////////////////////////////////////// // LexInfo -ExpressionParser::LexInfo::LexInfo(const std::string &input) { +ExpressionParser::LexInfo::LexInfo(const std::string &input, + const std::string &reserved_chars) + : reserved_chars(reserved_chars) { ss.clear(); ss.str(input); // Set the input stream ss.seekg(0, std::ios_base::beg); - + LastChar = static_cast(ss.get()); // First char from stream - nextToken(); // Get first token + nextToken(); // Get first token } char ExpressionParser::LexInfo::nextToken() { - while(isspace(LastChar)) + while (isspace(LastChar)) LastChar = static_cast(ss.get()); if(!ss.good()) { @@ -311,41 +315,7 @@ char ExpressionParser::LexInfo::nextToken() { return 0; } - if (isalpha(LastChar) || (LastChar == '`')) { // identifier: [a-zA-Z`][a-zA-Z0-9_:\`]* - curident.clear(); - do { - if (LastChar == '\\') { - // Escape character. Whatever the next character is, include it in the identifier - LastChar = static_cast(ss.get()); - if (LastChar == EOF) { - throw ParseException("Unexpected end of input after \\ character"); - } - - curident += LastChar; - } else if (LastChar == '`') { - // An escaped symbol - // Include all characters until the next ` (backtick) - LastChar = static_cast(ss.get()); // Skip the ` - do { - curident += LastChar; - LastChar = static_cast(ss.get()); - if (LastChar == EOF) { - throw ParseException("Unexpected end of input; expecting ` (backtick)"); - } - } while (LastChar != '`'); - // Final ` will not be added to the symbol - } else { - curident += LastChar; - } - LastChar = static_cast(ss.get()); - } while (isalnum(LastChar) || (LastChar == '_') || (LastChar == ':') || - (LastChar == '\\') || (LastChar == '`')); - curtok = -2; - return curtok; - } - // Handle numbers - if (isdigit(LastChar) || (LastChar == '.')) { // Number: [0-9.]+ bool gotdecimal = false, gotexponent = false; std::string NumStr; @@ -378,6 +348,48 @@ char ExpressionParser::LexInfo::nextToken() { curtok = -1; return curtok; } + + // Symbols can contain anything else which is not reserved + if ((LastChar == '`') || + (reserved_chars.find(LastChar) == std::string::npos)) { + + curident.clear(); + do { + if (LastChar == '\\') { + // Escape character. + // Whatever the next character is, include it in the identifier + // Note: Even though this only treats one character specially, + // it should still work for utf8 since all chars are + // allowed except reserved_chars and whitespace + LastChar = static_cast(ss.get()); + if (LastChar == EOF) { + throw ParseException("Unexpected end of input after \\ character"); + } + + curident += LastChar; + } else if (LastChar == '`') { + // An escaped symbol + // Include all characters until the next ` (backquote) + LastChar = static_cast(ss.get()); // Skip the ` + do { + curident += LastChar; + LastChar = static_cast(ss.get()); + if (LastChar == EOF) { + throw ParseException("Unexpected end of input; expecting ` (backquote)"); + } + } while (LastChar != '`'); + // Final ` will not be added to the symbol + } else { + curident += LastChar; + } + LastChar = static_cast(ss.get()); + } while ( (LastChar != EOF && + !isspace(LastChar) && + (reserved_chars.find(LastChar) == std::string::npos)) + || (LastChar == '\\') || (LastChar == '`')); + curtok = -2; + return curtok; + } // LastChar is unsigned, explicitly cast curtok = LastChar; diff --git a/tests/unit/sys/test_optionsreader.cxx b/tests/unit/sys/test_optionsreader.cxx index af70115eec..5d6c2952ab 100644 --- a/tests/unit/sys/test_optionsreader.cxx +++ b/tests/unit/sys/test_optionsreader.cxx @@ -456,4 +456,30 @@ some:value = 3 std::remove(filename); } +TEST_F(OptionsReaderTest, ReadUnicodeNames) { + const std::string text = R"( + +α = 1.3 +重要的數字 = 3 + +[tests] +結果 = 重要的數字 + 5 +value = α*(1 + 重要的數字) +twopi = 2 * π # Unicode symbol defined for pi +)"; + char *filename = std::tmpnam(nullptr); + std::ofstream test_file(filename, std::ios::out); + test_file << text; + test_file.close(); + + OptionsReader reader; + reader.read(Options::getRoot(), filename); + std::remove(filename); + + auto options = Options::root()["tests"]; + + EXPECT_EQ(options["結果"].as(), 8); + EXPECT_DOUBLE_EQ(options["value"].as(), 1.3*(1+3)); + EXPECT_DOUBLE_EQ(options["twopi"].as(), 2 * 3.141592653589793); +} From 6f368501c8e24345db02b51bc2bd821ea13ef3b0 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 20 Oct 2018 08:52:32 +0100 Subject: [PATCH 0112/1783] Add , to reserved characters Was being included in the symbol, so functions of two arguments failed. A unit test is added to catch this. Updated documentation --- include/bout/sys/expressionparser.hxx | 2 +- manual/sphinx/user_docs/bout_options.rst | 20 ++++++----- tests/unit/sys/test_expressionparser.cxx | 46 ++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/include/bout/sys/expressionparser.hxx b/include/bout/sys/expressionparser.hxx index 6806aaad5c..e8737c29ab 100644 --- a/include/bout/sys/expressionparser.hxx +++ b/include/bout/sys/expressionparser.hxx @@ -117,7 +117,7 @@ protected: /// Characters which cannot be used in symbols; all other allowed /// In addition, whitespace cannot be used /// Adding a binary operator adds its symbol to this string - std::string reserved_chars = "+-*/^[](){}"; + std::string reserved_chars = "+-*/^[](){},"; private: diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index 275c7e4cab..e3770514b1 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -46,9 +46,10 @@ name in square brackets. 工作的 = true # a boolean इनपुट = "some text" # a string -Option names can contain almost any character except ’=’ and ’:’, including unicode. -If they contain arithmetic symbols (``+-*/^``), brackets (``(){}[]``) or whitespace, -then these will need to be escaped in expressions. See below for how this is done. +Option names can contain almost any character except ’=’ and ’:’, including unicode. +If they start with a number or ``.``, contain arithmetic symbols +(``+-*/^``), brackets (``(){}[]``), whitespace or comma ``,``, then these will need +to be escaped in expressions. See below for how this is done. Subsections can also be used, separated by colons ’:’, e.g. @@ -95,9 +96,10 @@ Have a look through the examples to see how the options are used. Special symbols in Option names ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If option names contain symbols such as ``+`` or ``-`` then these symbols need -to be escaped in expressions or they will be treated as arithmetic -operators like addition or subtraction. To escape a single character +If option names start with numbers or ``.`` or contain symbols such as +``+`` and ``-`` then these symbols need to be escaped in expressions +or they will be treated as arithmetic operators like addition or +subtraction. To escape a single character ``\`` (backslash) can be used, for example ``plasma\-density * 10`` would read the option ``plasma-density`` and multiply it by 10 e.g @@ -105,14 +107,16 @@ by 10 e.g .. code-block:: cfg plasma-density = 1e19 - value = plasma\-density * 10 + 2ndvalue = 10 + value = plasma\-density * \2ndvalue To escape multiple characters, ` (backquote) can be used: .. code-block:: cfg plasma-density = 1e19 - value = `plasma-density` * 10 + 2ndvalue = 10 + value = `plasma-density` * `2ndvalue` The character ``:`` cannot be part of an option or section name, and cannot be escaped, as it is always used to separate sections. diff --git a/tests/unit/sys/test_expressionparser.cxx b/tests/unit/sys/test_expressionparser.cxx index 62af1af1ab..025ad3df4d 100644 --- a/tests/unit/sys/test_expressionparser.cxx +++ b/tests/unit/sys/test_expressionparser.cxx @@ -22,6 +22,35 @@ class ExpressionParserTest : public ::testing::Test { std::vector t_array = {-1., 0., 1., 5., 10., 3.14e8}; }; +/// For testing, a generator function of two inputs +class BinaryGenerator : public FieldGenerator { +public: + BinaryGenerator(std::shared_ptr a = nullptr, + std::shared_ptr b = nullptr) + : a(a), b(b) {} + + std::shared_ptr + clone(const std::list> args) { + if (args.size() != 2) { + throw ParseException( + "Incorrect number of arguments to increment function. Expecting 2, got %d", + args.size()); + } + + return std::make_shared(args.front(), args.back()); + } + + BoutReal generate(BoutReal x, BoutReal y, BoutReal z, BoutReal t) { + return a->generate(x, y, z, t) + b->generate(x, y, z, t); + } + const std::string str() { + return std::string{"add(" + a->str() + ", " + b->str() + ")"}; + } + +private: + std::shared_ptr a, b; +}; + class IncrementGenerator : public FieldGenerator { public: IncrementGenerator(std::shared_ptr gen = nullptr) : gen(gen) {} @@ -418,3 +447,20 @@ TEST_F(ExpressionParserTest, GeneratorNamePartEscape) { } } } + +TEST_F(ExpressionParserTest, AddBinaryGenerator) { + parser.addGenerator("add", std::make_shared()); + + auto fieldgen = parser.parseString("add(x,y)"); + EXPECT_EQ(fieldgen->str(), "add(x, y)"); + + for (auto x : x_array) { + for (auto y : y_array) { + for (auto z : z_array) { + for (auto t : t_array) { + EXPECT_DOUBLE_EQ(fieldgen->generate(x, y, z, t), x + y); + } + } + } + } +} From 8f7307c8c367b7f626ca6d1056c46ed36a3cd1d9 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 20 Oct 2018 21:08:18 +0100 Subject: [PATCH 0113/1783] Enable implicit multiplication in expressions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a number is followed by a symbol or an opening bracket, then a multiplication is assumed. This is a nice (I think) feature of Julia which reduces clutter in large expressions. `3sin(2π*x)` or `3 sin(2 π * x)` are equivalent to `3*sin(2*π*x)`. Added tests and documentation. --- include/bout/sys/expressionparser.hxx | 2 +- manual/sphinx/user_docs/bout_options.rst | 16 ++++++++++ src/sys/expressionparser.cxx | 16 ++++++++++ tests/unit/sys/test_expressionparser.cxx | 40 ++++++++++++++++++++++-- 4 files changed, 71 insertions(+), 3 deletions(-) diff --git a/include/bout/sys/expressionparser.hxx b/include/bout/sys/expressionparser.hxx index e8737c29ab..986120314b 100644 --- a/include/bout/sys/expressionparser.hxx +++ b/include/bout/sys/expressionparser.hxx @@ -129,7 +129,7 @@ private: LexInfo(const std::string &input, const std::string &reserved_chars=""); - signed char curtok; ///< Current token. -1 for number, -2 for string, 0 for "end of input" + signed char curtok = 0; ///< Current token. -1 for number, -2 for string, 0 for "end of input" double curval; ///< Value if a number std::string curident; ///< Identifier, variable or function name signed char LastChar; ///< The last character read from the string diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index e3770514b1..664ab865af 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -76,6 +76,22 @@ Note that variables can be used before their definition; all variables are first read, and then processed afterwards. The value ``pi`` is already defined, as is ``π``, and can be used in expressions. +Uses for expressions include initialising variables +:ref:`_sec-expressions` and input sources, defining grids +:ref:`_sec-gridgen` and MMS convergence tests :ref:`_sec-mms`. + +Expressions can include addition (``+``), subtraction (``-``), +multiplication (``*``), division (``/``) and exponentiation (``^``) +operators, with the usual precedence rules. In addition to ``π``, +expressions can use predefined variables ``x``, ``y``, ``z`` and ``t`` +to refer to the spatial and time coordinates. +A number of functions are defined, listed in table +:numref:`tab-initexprfunc`. One slightly unusual feature is that if a +number comes before a symbol or an opening bracket (``(``) +then a multiplication is assumed: ``2x+3y^2`` is the same as +``2*x + 3*y^2``, which with the usual precedence rules is the same as +``(2*x) + (3*(y^2))``. + All expressions are calculated in floating point and then converted to an integer when read inside BOUT++. The conversion is done by rounding to the nearest integer, but throws an error if the floating point diff --git a/src/sys/expressionparser.cxx b/src/sys/expressionparser.cxx index 1c9793171f..94a4330205 100644 --- a/src/sys/expressionparser.cxx +++ b/src/sys/expressionparser.cxx @@ -352,6 +352,13 @@ char ExpressionParser::LexInfo::nextToken() { // Symbols can contain anything else which is not reserved if ((LastChar == '`') || (reserved_chars.find(LastChar) == std::string::npos)) { + + // Special case: If the last token returned was a number + // then insert a multiplication ("*") + if (curtok == -1) { + curtok = '*'; + return curtok; + } curident.clear(); do { @@ -391,6 +398,15 @@ char ExpressionParser::LexInfo::nextToken() { return curtok; } + if (LastChar == '(') { + // Special case: If the last token returned was a number + // then insert a multiplication ("*") before the opening bracket + if (curtok == -1) { + curtok = '*'; + return curtok; + } + } + // LastChar is unsigned, explicitly cast curtok = LastChar; LastChar = static_cast(ss.get()); diff --git a/tests/unit/sys/test_expressionparser.cxx b/tests/unit/sys/test_expressionparser.cxx index 025ad3df4d..04015de7b1 100644 --- a/tests/unit/sys/test_expressionparser.cxx +++ b/tests/unit/sys/test_expressionparser.cxx @@ -240,8 +240,8 @@ TEST_F(ExpressionParserTest, BadNumbers) { EXPECT_THROW(parser.parseString("1.1.4"), ParseException); EXPECT_THROW(parser.parseString("2.1e4.5."), ParseException); EXPECT_THROW(parser.parseString("3.e8e4"), ParseException); - EXPECT_THROW(parser.parseString("4ee"), ParseException); - EXPECT_THROW(parser.parseString("5G"), ParseException); + EXPECT_THROW(parser.parseString("4()"), ParseException); + EXPECT_THROW(parser.parseString("5_000"), ParseException); } TEST_F(ExpressionParserTest, BadFunctions) { @@ -464,3 +464,39 @@ TEST_F(ExpressionParserTest, AddBinaryGenerator) { } } } + +TEST_F(ExpressionParserTest, ImplicitMultiply) { + + auto fieldgen = parser.parseString("2x + 3y"); + + for (auto x : x_array) { + for (auto y : y_array) { + for (auto z : z_array) { + for (auto t : t_array) { + EXPECT_DOUBLE_EQ(fieldgen->generate(x, y, z, t), 2*x + 3*y); + } + } + } + } +} + +TEST_F(ExpressionParserTest, ImplicitMultiplyBracket) { + + auto fieldgen = parser.parseString("2(x + 3y)"); + + for (auto x : x_array) { + for (auto y : y_array) { + for (auto z : z_array) { + for (auto t : t_array) { + EXPECT_DOUBLE_EQ(fieldgen->generate(x, y, z, t), 2*(x + 3*y)); + } + } + } + } +} + +TEST_F(ExpressionParserTest, BadImplicitMultiply) { + EXPECT_THROW(parser.parseString("x2"), ParseException); + EXPECT_THROW(parser.parseString("(1+x)2"), ParseException); + EXPECT_THROW(parser.parseString("2 2"), ParseException); +} From 667ba1b81bd68be8dac70a71b80b863d8b04463b Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 20 Oct 2018 22:09:07 +0100 Subject: [PATCH 0114/1783] Simple test of gettext for internationalisation Mostly following this introduction tutorial: http://www.labri.fr/perso/fleury/posts/programming/a-quick-gettext-tutorial.html Note: A locale needs to be installed system-wide before it can be used. --- locale/fr/LC_MESSAGES/test.mo | Bin 0 -> 462 bytes locale/fr/LC_MESSAGES/test.po | 24 +++++++++++++++++++++++ tests/integrated/test-i18n/data/BOUT.inp | 8 ++++++++ tests/integrated/test-i18n/makefile | 5 +++++ tests/integrated/test-i18n/test-i18n.cxx | 19 ++++++++++++++++++ 5 files changed, 56 insertions(+) create mode 100644 locale/fr/LC_MESSAGES/test.mo create mode 100644 locale/fr/LC_MESSAGES/test.po create mode 100644 tests/integrated/test-i18n/data/BOUT.inp create mode 100644 tests/integrated/test-i18n/makefile create mode 100644 tests/integrated/test-i18n/test-i18n.cxx diff --git a/locale/fr/LC_MESSAGES/test.mo b/locale/fr/LC_MESSAGES/test.mo new file mode 100644 index 0000000000000000000000000000000000000000..45ba3e9d6fda2d315171baa90c4319c7d26b3a64 GIT binary patch literal 462 zcmZvX&rSj{5XM)dm&S{pJ%4CoO5intY7I7^W4Cj zv3Vkbo;4GUy=*7)6|Kt*De&mL%pj_e=;Pd2FS{5K z*BMnI9&78+*Kc2%?e^BU9A|`9K2U6uj8X-aVdh0IFRadG%h;JyK=akr)yq{_r}Yzp W21KV-5!@M?n8HGiFf){(2>t;1`F?2t literal 0 HcmV?d00001 diff --git a/locale/fr/LC_MESSAGES/test.po b/locale/fr/LC_MESSAGES/test.po new file mode 100644 index 0000000000..66e41e224b --- /dev/null +++ b/locale/fr/LC_MESSAGES/test.po @@ -0,0 +1,24 @@ +# French translations for test-i package. +# Copyright (C) 2018 THE test-i'S COPYRIGHT HOLDER +# This file is distributed under the same license as the test-i package. +# , 2018. +# +msgid "" +msgstr "" +"Project-Id-Version: test-i 18n\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-10-20 21:34+0100\n" +"PO-Revision-Date: 2018-10-20 21:36+0100\n" +"Last-Translator: \n" +"Language-Team: French\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ASCII\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: test-i18n.cxx:13 +#, c-format +msgid "Hello World\n" +msgstr "Bonjour le monde\n" + diff --git a/tests/integrated/test-i18n/data/BOUT.inp b/tests/integrated/test-i18n/data/BOUT.inp new file mode 100644 index 0000000000..4882c631fe --- /dev/null +++ b/tests/integrated/test-i18n/data/BOUT.inp @@ -0,0 +1,8 @@ + +mxg = 0 +myg = 0 +[mesh] + +nx = 1 +ny = 1 +nz = 1 diff --git a/tests/integrated/test-i18n/makefile b/tests/integrated/test-i18n/makefile new file mode 100644 index 0000000000..96868cf602 --- /dev/null +++ b/tests/integrated/test-i18n/makefile @@ -0,0 +1,5 @@ +BOUT_TOP = ../../.. + +SOURCEC = test-i18n.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-i18n/test-i18n.cxx b/tests/integrated/test-i18n/test-i18n.cxx new file mode 100644 index 0000000000..f92866eece --- /dev/null +++ b/tests/integrated/test-i18n/test-i18n.cxx @@ -0,0 +1,19 @@ + +#include "bout.hxx" +#include "bout/sys/gettext.hxx" + +int main(int argc, char**argv) { + // Setting the i18n environment + if (setlocale (LC_ALL, "") == NULL) { + throw BoutException("Failed to set locale"); + } + bindtextdomain ("test", "/home/bd512/BOUT-dev/locale/"); + textdomain ("test"); + + BoutInitialise(argc, argv); + + output.write(_("Hello World\n")); + + BoutFinalise(); + return 0; +} From 5c7f29999373724afca170dc96e4cb6066b7a84d Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 22 Oct 2018 01:08:57 +0100 Subject: [PATCH 0115/1783] Started i18n for BOUT++ library - configure option `--enable-gettext` which defines BOUT_HAS_GETTEXT and BOUT_LOCALE_PATH - Makefile targets `locale-po` and `locale-mo` for updating files - Some strings in `bout++.cxx` and `solver.cxx` marked for translation. For now just French translation (probably bad french). --- configure | 20 ++++++++ configure.ac | 11 +++++ include/bout/sys/gettext.hxx | 18 +++++++ include/output.hxx | 1 + locale/README.md | 9 ++++ locale/fr/libbout.po | 88 ++++++++++++++++++++++++++++++++++ locale/libbout.pot | 93 ++++++++++++++++++++++++++++++++++++ make.config.in | 1 + makefile | 21 ++++++++ src/bout++.cxx | 28 +++++++---- src/solver/solver.cxx | 14 +++--- 11 files changed, 288 insertions(+), 16 deletions(-) create mode 100644 include/bout/sys/gettext.hxx create mode 100644 locale/README.md create mode 100644 locale/fr/libbout.po create mode 100644 locale/libbout.pot diff --git a/configure b/configure index dba763cd86..411e72f362 100755 --- a/configure +++ b/configure @@ -788,6 +788,7 @@ enable_shared enable_openmp with_openmp_schedule enable_pvode_openmp +enable_gettext with_gcov enable_code_coverage with_hdf5 @@ -1443,6 +1444,7 @@ Optional Features: --enable-shared Enable building bout++ into an shared object --enable-openmp Enable building with OpenMP support --enable-pvode-openmp Enable building PVODE with OpenMP support + --enable-gettext Enable localisation (i18n) with gettext --disable-openmp do not use OpenMP --enable-code-coverage Whether to enable code coverage support @@ -2674,6 +2676,13 @@ else enable_pvode_openmp=no fi +# Check whether --enable-gettext was given. +if test "${enable_gettext+set}" = set; then : + enableval=$enable_gettext; +else + enable_gettext=no +fi + @@ -12085,6 +12094,17 @@ fi fi +############################################################# +# Localisation (i18n) with gettext +############################################################# + +if test "$enable_gettext" != "no" ; then : + + # Note: BOUT_LOCALE_PATH is defined in make.config, and may be changed by `make install`. + CXXFLAGS="$CXXFLAGS -DBOUT_HAS_GETTEXT -DBOUT_LOCALE_PATH=\$(BOUT_LOCALE_PATH)" + +fi + ############################################################# # Check environment ############################################################# diff --git a/configure.ac b/configure.ac index 21dd288bbc..b68f1110d3 100644 --- a/configure.ac +++ b/configure.ac @@ -91,6 +91,8 @@ AC_ARG_WITH(openmp_schedule,[AS_HELP_STRING([--with-openmp-schedule=static], [Set OpenMP schedule (default: static)])],,[with_openmp_schedule=static]) AC_ARG_ENABLE(pvode_openmp, [AS_HELP_STRING([--enable-pvode-openmp], [Enable building PVODE with OpenMP support])],,[enable_pvode_openmp=no]) +AC_ARG_ENABLE(gettext, [AS_HELP_STRING([--enable-gettext], + [Enable localisation (i18n) with gettext])],,[enable_gettext=no]) AC_ARG_VAR(EXTRA_INCS,[Extra compile flags]) AC_ARG_VAR(EXTRA_LIBS,[Extra linking flags]) @@ -1130,6 +1132,15 @@ AS_IF([test "$with_pvode" != "no"], [ HAS_PVODE="yes" ]) +############################################################# +# Localisation (i18n) with gettext +############################################################# + +AS_IF([test "$enable_gettext" != "no" ], [ + # Note: BOUT_LOCALE_PATH is defined in make.config, and may be changed by `make install`. + CXXFLAGS="$CXXFLAGS -DBOUT_HAS_GETTEXT -DBOUT_LOCALE_PATH=\$(BOUT_LOCALE_PATH)" +]) + ############################################################# # Check environment ############################################################# diff --git a/include/bout/sys/gettext.hxx b/include/bout/sys/gettext.hxx new file mode 100644 index 0000000000..6baa49b5c7 --- /dev/null +++ b/include/bout/sys/gettext.hxx @@ -0,0 +1,18 @@ +/// Support for i18n using GNU gettext + +#ifndef __BOUT_GETTEXT_H__ +#define __BOUT_GETTEXT_H__ + +#if BOUT_HAS_GETTEXT + +#include +#include + +#define _(string) gettext(string) + +#else + +#define _(string) string + +#endif // BOUT_HAS_GETTEXT +#endif // __BOUT_GETTEXT_H__ diff --git a/include/output.hxx b/include/output.hxx index 69cd35f21d..49dbd28ba8 100644 --- a/include/output.hxx +++ b/include/output.hxx @@ -37,6 +37,7 @@ class Output; #include "bout/assert.hxx" #include "boutexception.hxx" #include "unused.hxx" +#include "bout/sys/gettext.hxx" // for gettext _() macro using std::endl; diff --git a/locale/README.md b/locale/README.md new file mode 100644 index 0000000000..2b764dc871 --- /dev/null +++ b/locale/README.md @@ -0,0 +1,9 @@ + +To start a new translation: + + msginit --input=libbout.pot --locale=fr --output=fr/libbout.po + +Edit the .po file, then convert to a .mo file: +Note: Change the content line to: "Content-Type: text/plain; charset=UTF-8\n" + + msgfmt --output-file=LC_MESSAGES/libbout.mo libbout.po diff --git a/locale/fr/libbout.po b/locale/fr/libbout.po new file mode 100644 index 0000000000..0d3f43d406 --- /dev/null +++ b/locale/fr/libbout.po @@ -0,0 +1,88 @@ +# French translations for BOUT++ package. +# Copyright (C) 2018 THE BOUT++'S COPYRIGHT HOLDER +# This file is distributed under the same license as the BOUT++ package. +# , 2018. +# +msgid "" +msgstr "" +"Project-Id-Version: BOUT++ 4.2.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-10-21 23:23+0100\n" +"PO-Revision-Date: 2018-10-21 22:46+0100\n" +"Last-Translator: \n" +"Language-Team: French\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: src/bout++.cxx:355 +msgid "\tChecking disabled\n" +msgstr "\tVérification désactivée\n" + +#: src/bout++.cxx:353 +#, c-format +msgid "\tChecking enabled, level %d\n" +msgstr "\tVérification activée, niveau %d\n" + +#: src/bout++.cxx:361 +msgid "\tSignal handling disabled\n" +msgstr "\tTraitement du signal désactivé\n" + +#: src/bout++.cxx:359 +msgid "\tSignal handling enabled\n" +msgstr "\tTraitement du signal activé\n" + +#: src/solver/solver.cxx:563 +#, c-format +msgid "\nRun finished at : %s\n" +msgstr "\nL'exécution se termine à %s\n" + +#: src/bout++.cxx:340 +#, c-format +msgid "Code compiled on %s at %s\n\n" +msgstr "Code compilé le %s à %s\n\n" + +#: src/bout++.cxx:246 +#, c-format +msgid "DataDir \"%s\" does not exist or is not accessible\n" +msgstr "Le répertoire de données \"%s\" n'existe pas ou n'est pas accessible\n" + +#: src/bout++.cxx:243 +#, c-format +msgid "DataDir \"%s\" is not a directory\n" +msgstr "\"%s\" n'est pas un répertoire\n" + +#: src/bout++.cxx:414 +#, fuzzy +msgid "Error encountered during initialisation\n" +msgstr "Erreur rencontrée lors de l'initialisation\n" + +#: src/bout++.cxx:459 +#, c-format +msgid "Error encountered during initialisation: %s\n" +msgstr "Erreur rencontrée lors de l'initialisation : %s\n" + +#: src/solver/solver.cxx:526 +msgid "Failed to initialise solver-> Aborting\n" +msgstr "Échec d'initialisation du solutionneur -> Abandonner\n" + +#: src/solver/solver.cxx:564 +msgid "Run time : " +msgstr "Temps d'exécution : " + +#. / Run the solver +#: src/solver/solver.cxx:531 +msgid "Running simulation\n\n" +msgstr "L'exécution commence\n\n" + +#: src/solver/solver.cxx:521 +#, c-format +msgid "Solver running for %d outputs with monitor timestep of %e\n" +msgstr "Le solveur fonctionne pour %d sorties avec un temps de moniteur de %e\n" + +#: src/solver/solver.cxx:519 +#, c-format +msgid "Solver running for %d outputs with output timestep of %e\n" +msgstr "Le solveur fonctionne pour %d sorties avec un pas de sortie de %e\n" diff --git a/locale/libbout.pot b/locale/libbout.pot new file mode 100644 index 0000000000..16f147edb2 --- /dev/null +++ b/locale/libbout.pot @@ -0,0 +1,93 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-10-21 23:23+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/bout++.cxx:355 +msgid "\tChecking disabled\n" +msgstr "" + +#: src/bout++.cxx:353 +#, c-format +msgid "\tChecking enabled, level %d\n" +msgstr "" + +#: src/bout++.cxx:361 +msgid "\tSignal handling disabled\n" +msgstr "" + +#: src/bout++.cxx:359 +msgid "\tSignal handling enabled\n" +msgstr "" + +#: src/solver/solver.cxx:563 +#, c-format +msgid "" +"\n" +"Run finished at : %s\n" +msgstr "" + +#: src/bout++.cxx:340 +#, c-format +msgid "" +"Code compiled on %s at %s\n" +"\n" +msgstr "" + +#: src/bout++.cxx:246 +#, c-format +msgid "DataDir \"%s\" does not exist or is not accessible\n" +msgstr "" + +#: src/bout++.cxx:243 +#, c-format +msgid "DataDir \"%s\" is not a directory\n" +msgstr "" + +#: src/bout++.cxx:414 +msgid "Error encountered during initialisation\n" +msgstr "" + +#: src/bout++.cxx:459 +#, c-format +msgid "Error encountered during initialisation: %s\n" +msgstr "" + +#: src/solver/solver.cxx:526 +msgid "Failed to initialise solver-> Aborting\n" +msgstr "" + +#: src/solver/solver.cxx:564 +msgid "Run time : " +msgstr "" + +#. / Run the solver +#: src/solver/solver.cxx:531 +msgid "" +"Running simulation\n" +"\n" +msgstr "" + +#: src/solver/solver.cxx:521 +#, c-format +msgid "Solver running for %d outputs with monitor timestep of %e\n" +msgstr "" + +#: src/solver/solver.cxx:519 +#, c-format +msgid "Solver running for %d outputs with output timestep of %e\n" +msgstr "" diff --git a/make.config.in b/make.config.in index 3743fc4c53..29789ebb56 100644 --- a/make.config.in +++ b/make.config.in @@ -28,6 +28,7 @@ SLEPC_ARCH ?= @SLEPC_ARCH@ # They are used in the CXXFLAGS variable below rather than hard-coding the directories BOUT_INCLUDE_PATH=$(BOUT_TOP)/include BOUT_LIB_PATH=$(BOUT_TOP)/lib +BOUT_LOCALE_PATH=$(BOUT_TOP)/locale/ BOUT_CONFIG_FILE=$(BOUT_TOP)/make.config # Created this variable so that a user won't overwrite the CXXFLAGS variable diff --git a/makefile b/makefile index 329215f941..479113110e 100644 --- a/makefile +++ b/makefile @@ -68,3 +68,24 @@ build-check-integrated-tests: libfast build-check: build-check-integrated-tests build-check-mms-tests build-check-unit-tests + +###################################################################### +# Internationalisation +###################################################################### + +# Create the template file, combining all source files +locale/libbout.pot: src/bout++.cxx + xgettext --keyword=_ --language=c++ --add-comments --sort-output -o $@ `find src/ -name "*.cxx"` + +# Update a .po file +locale/%/libbout.po: locale/libbout.pot + msgmerge --update $@ $< + +# Update a .mo file +locale/%/LC_MESSAGES/libbout.mo: locale/%/libbout.po + msgfmt --output-file=$@ $< + +locale-po: locale/fr/libbout.po + +locale-mo: locale/fr/LC_MESSAGES/libbout.mo + diff --git a/src/bout++.cxx b/src/bout++.cxx index a81421b58b..9fb3065378 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -141,6 +141,16 @@ int BoutInitialise(int &argc, char **&argv) { set_file = DEFAULT_SET; log_file = DEFAULT_LOG; +#if BOUT_HAS_GETTEXT + // Setting the i18n environment + // Note: LC_ALL here causes problems, perhaps with reading strings + setlocale (LC_MESSAGES, ""); // Language-specific messages + setlocale (LC_CTYPE, ""); // Output utf-8 characters + //bindtextdomain ("libbout", LOCALE_PATH); + bindtextdomain ("libbout", "/home/bd512/BOUT-dev/locale/"); + textdomain ("libbout"); +#endif // BOUT_HAS_GETTEXT + int verbosity=4; /// Check command-line arguments /// NB: "restart" and "append" are now caught by options @@ -235,10 +245,10 @@ int BoutInitialise(int &argc, char **&argv) { struct stat test; if (stat(data_dir, &test) == 0){ if (!S_ISDIR(test.st_mode)){ - throw BoutException("DataDir \"%s\" is not a directory\n",data_dir); + throw BoutException(_("DataDir \"%s\" is not a directory\n"),data_dir); } } else { - throw BoutException("DataDir \"%s\" does not exist or is not accessible\n",data_dir); + throw BoutException(_("DataDir \"%s\" does not exist or is not accessible\n"),data_dir); } // Set options @@ -332,7 +342,7 @@ int BoutInitialise(int &argc, char **&argv) { #ifdef MD5SUM output_progress.write("MD5 checksum: %s\n", CHECKSUM); #endif - output_progress.write("Code compiled on %s at %s\n\n", __DATE__, __TIME__); + output_progress.write(_("Code compiled on %s at %s\n\n"), __DATE__, __TIME__); output_info.write("B.Dudson (University of York), M.Umansky (LLNL) 2007\n"); output_info.write("Based on BOUT by Xueqiao Xu, 1999\n\n"); @@ -345,15 +355,15 @@ int BoutInitialise(int &argc, char **&argv) { output_info.write("Compile-time options:\n"); #if CHECK > 0 - output_info.write("\tChecking enabled, level %d\n", CHECK); + output_info.write(_("\tChecking enabled, level %d\n"), CHECK); #else - output_info.write("\tChecking disabled\n"); + output_info.write(_("\tChecking disabled\n")); #endif #ifdef SIGHANDLE - output_info.write("\tSignal handling enabled\n"); + output_info.write(_("\tSignal handling enabled\n")); #else - output_info.write("\tSignal handling disabled\n"); + output_info.write(_("\tSignal handling disabled\n")); #endif #ifdef NCDF @@ -406,7 +416,7 @@ int BoutInitialise(int &argc, char **&argv) { reader->write(options, "%s/%s", data_dir, set_file); } } catch (BoutException &e) { - output << "Error encountered during initialisation\n"; + output << _("Error encountered during initialisation\n"); output << e.what() << endl; return 1; } @@ -451,7 +461,7 @@ int BoutInitialise(int &argc, char **&argv) { mesh->outputVars(dump); ///< Save mesh configuration into output file }catch(BoutException &e) { - output_error.write("Error encountered during initialisation: %s\n", e.what()); + output_error.write(_("Error encountered during initialisation: %s\n"), e.what()); throw; } return 0; diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 2267c2f06f..f8aa9797e6 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -516,22 +516,22 @@ int Solver::solve(int NOUT, BoutReal TIMESTEP) { } - output_progress.write("Solver running for %d outputs with output timestep of %e\n", NOUT, TIMESTEP); + output_progress.write(_("Solver running for %d outputs with output timestep of %e\n"), NOUT, TIMESTEP); if (freqDefault > 1) - output_progress.write("Solver running for %d outputs with monitor timestep of %e\n", + output_progress.write(_("Solver running for %d outputs with monitor timestep of %e\n"), NOUT/freqDefault, TIMESTEP*freqDefault); // Initialise if (init(NOUT, TIMESTEP)) { - throw BoutException("Failed to initialise solver-> Aborting\n"); + throw BoutException(_("Failed to initialise solver-> Aborting\n")); } initCalled=true; /// Run the solver - output_info.write("Running simulation\n\n"); + output_info.write(_("Running simulation\n\n")); time_t start_time = time(nullptr); - output_progress.write("\nRun started at : %s\n", ctime(&start_time)); + output_progress.write(_("\nRun started at : %s\n"), ctime(&start_time)); Timer timer("run"); // Start timer @@ -560,8 +560,8 @@ int Solver::solve(int NOUT, BoutReal TIMESTEP) { status = run(); time_t end_time = time(nullptr); - output_progress.write("\nRun finished at : %s\n", ctime(&end_time)); - output_progress.write("Run time : "); + output_progress.write(_("\nRun finished at : %s\n"), ctime(&end_time)); + output_progress.write(_("Run time : ")); int dt = end_time - start_time; int i = static_cast(dt / (60. * 60.)); From 0295f58954d54d554ecd8f936e6ee7234b1807d4 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 22 Oct 2018 17:48:16 +0100 Subject: [PATCH 0116/1783] Use BOUT_TOP to get path to locale Previously hard-wired. Needs to be full path, so use `realpath` in `make.config` to get full path to `$(BOUT_TOP)/locale`. --- make.config.in | 2 +- src/bout++.cxx | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/make.config.in b/make.config.in index 29789ebb56..dff8866683 100644 --- a/make.config.in +++ b/make.config.in @@ -28,7 +28,7 @@ SLEPC_ARCH ?= @SLEPC_ARCH@ # They are used in the CXXFLAGS variable below rather than hard-coding the directories BOUT_INCLUDE_PATH=$(BOUT_TOP)/include BOUT_LIB_PATH=$(BOUT_TOP)/lib -BOUT_LOCALE_PATH=$(BOUT_TOP)/locale/ +BOUT_LOCALE_PATH=$(realpath $(BOUT_TOP)/locale/) BOUT_CONFIG_FILE=$(BOUT_TOP)/make.config # Created this variable so that a user won't overwrite the CXXFLAGS variable diff --git a/src/bout++.cxx b/src/bout++.cxx index 9fb3065378..5ee57d8dc1 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -30,6 +30,9 @@ const char DEFAULT_OPT[] = "BOUT.inp"; const char DEFAULT_SET[] = "BOUT.settings"; const char DEFAULT_LOG[] = "BOUT.log"; +#define CMDLINE1_(x) #x +#define CMDLINE(x) CMDLINE1_(x) + // MD5 Checksum passed at compile-time #define CHECKSUM1_(x) #x #define CHECKSUM_(x) CHECKSUM1_(x) @@ -144,10 +147,12 @@ int BoutInitialise(int &argc, char **&argv) { #if BOUT_HAS_GETTEXT // Setting the i18n environment // Note: LC_ALL here causes problems, perhaps with reading strings - setlocale (LC_MESSAGES, ""); // Language-specific messages + if (!setlocale (LC_MESSAGES, "")) { // Language-specific messages + fprintf(stderr, "WARNING: Could not set locale. Try a different LANG setting\n"); + } setlocale (LC_CTYPE, ""); // Output utf-8 characters - //bindtextdomain ("libbout", LOCALE_PATH); - bindtextdomain ("libbout", "/home/bd512/BOUT-dev/locale/"); + bindtextdomain ("libbout", CMDLINE(BOUT_LOCALE_PATH)); + fprintf(stderr, "LOCALE_PATH = '%s'", CMDLINE(BOUT_LOCALE_PATH)); textdomain ("libbout"); #endif // BOUT_HAS_GETTEXT From c908c35ca2b9c5e464ae81d914b4eed1c82c1a58 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 23 Oct 2018 00:11:29 +0100 Subject: [PATCH 0117/1783] add toString(time_t) function Uses std::localtime and std::put_time to convert a time to a string. This avoids messing with ctime directly, and automatically adjusts for locale. --- include/utils.hxx | 8 +++++++- src/solver/solver.cxx | 4 ++-- src/sys/utils.cxx | 13 +++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/include/utils.hxx b/include/utils.hxx index 2b0052817f..8af9ed5bb9 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -41,6 +41,7 @@ #include #include #include +#include #include using std::abs; @@ -337,12 +338,17 @@ char* copy_string(const char* s); * by writing to a stringstream */ template -const string toString(const T& val) { +const std::string toString(const T& val) { std::stringstream ss; ss << val; return ss.str(); } +/// Convert a time stamp to a string +/// This uses std::localtime and std::put_time +template <> +const std::string toString<>(const time_t& time); + /*! * Convert a string to lower case */ diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index f8aa9797e6..b723d5e21c 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -531,7 +531,7 @@ int Solver::solve(int NOUT, BoutReal TIMESTEP) { output_info.write(_("Running simulation\n\n")); time_t start_time = time(nullptr); - output_progress.write(_("\nRun started at : %s\n"), ctime(&start_time)); + output_progress.write(_("\nRun started at : %s\n"), toString(start_time).c_str()); Timer timer("run"); // Start timer @@ -560,7 +560,7 @@ int Solver::solve(int NOUT, BoutReal TIMESTEP) { status = run(); time_t end_time = time(nullptr); - output_progress.write(_("\nRun finished at : %s\n"), ctime(&end_time)); + output_progress.write(_("\nRun finished at : %s\n"), toString(end_time).c_str()); output_progress.write(_("Run time : ")); int dt = end_time - start_time; diff --git a/src/sys/utils.cxx b/src/sys/utils.cxx index 8eef7335e6..26986b48e8 100644 --- a/src/sys/utils.cxx +++ b/src/sys/utils.cxx @@ -32,6 +32,9 @@ #include #include #include +#include +#include + /************************************************************************** * String routines **************************************************************************/ @@ -128,3 +131,13 @@ std::string trimComments(const std::string &s, const std::string &c) { return s.substr(0, s.find_first_of(c)); } +template <> +const std::string toString<>(const time_t& time) { + // Get local time + std::tm tm = *std::localtime(&time); + + std::stringstream ss; + ss << std::put_time(&tm, "%c %Z"); + + return ss.str(); +} From fde75389c0524d1ead3de14c7f60d998b08df58e Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 23 Oct 2018 00:14:53 +0100 Subject: [PATCH 0118/1783] Add chinese (taiwan) locale Partial translation into traditional chinese characters. --- include/options.hxx | 4 +- locale/fr/libbout.po | 56 +++++++++++++++++-------- locale/libbout.pot | 32 ++++++++++----- locale/zh_TW/libbout.po | 90 +++++++++++++++++++++++++++++++++++++++++ makefile | 17 ++++++-- src/sys/options.cxx | 12 +++--- 6 files changed, 172 insertions(+), 39 deletions(-) create mode 100644 locale/zh_TW/libbout.po diff --git a/include/options.hxx b/include/options.hxx index 4df91fc612..65232d2e9b 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -295,7 +295,7 @@ public: assign(def, DEFAULT_SOURCE); value.used = true; // Mark the option as used - output_info << "\tOption " << full_name << " = " << def << " (" << DEFAULT_SOURCE + output_info << _("\tOption ") << full_name << " = " << def << " (" << DEFAULT_SOURCE << ")" << std::endl; return def; } @@ -316,7 +316,7 @@ public: template T withDefault(T def) const { if (!is_value) { // Option not found - output_info << "\tOption " << full_name << " = " << def << " (" << DEFAULT_SOURCE + output_info << _("\tOption ") << full_name << " = " << def << " (" << DEFAULT_SOURCE << ")" << std::endl; return def; } diff --git a/locale/fr/libbout.po b/locale/fr/libbout.po index 0d3f43d406..7501f91717 100644 --- a/locale/fr/libbout.po +++ b/locale/fr/libbout.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: BOUT++ 4.2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-21 23:23+0100\n" +"POT-Creation-Date: 2018-10-22 22:26+0100\n" "PO-Revision-Date: 2018-10-21 22:46+0100\n" "Last-Translator: \n" "Language-Team: French\n" @@ -17,49 +17,66 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: src/bout++.cxx:355 +#: src/bout++.cxx:365 msgid "\tChecking disabled\n" msgstr "\tVérification désactivée\n" -#: src/bout++.cxx:353 +#: src/bout++.cxx:363 #, c-format msgid "\tChecking enabled, level %d\n" msgstr "\tVérification activée, niveau %d\n" -#: src/bout++.cxx:361 +#: src/bout++.cxx:371 msgid "\tSignal handling disabled\n" msgstr "\tTraitement du signal désactivé\n" -#: src/bout++.cxx:359 +#: src/bout++.cxx:369 msgid "\tSignal handling enabled\n" msgstr "\tTraitement du signal activé\n" #: src/solver/solver.cxx:563 #, c-format -msgid "\nRun finished at : %s\n" -msgstr "\nL'exécution se termine à %s\n" +msgid "" +"\n" +"Run finished at : %s\n" +msgstr "" +"\n" +"L'exécution se termine à %s\n" + +#: src/solver/solver.cxx:534 +#, fuzzy, c-format +msgid "" +"\n" +"Run started at : %s\n" +msgstr "" +"\n" +"L'exécution se termine à %s\n" -#: src/bout++.cxx:340 +#: src/bout++.cxx:350 #, c-format -msgid "Code compiled on %s at %s\n\n" -msgstr "Code compilé le %s à %s\n\n" +msgid "" +"Code compiled on %s at %s\n" +"\n" +msgstr "" +"Code compilé le %s à %s\n" +"\n" -#: src/bout++.cxx:246 +#: src/bout++.cxx:256 #, c-format msgid "DataDir \"%s\" does not exist or is not accessible\n" msgstr "Le répertoire de données \"%s\" n'existe pas ou n'est pas accessible\n" -#: src/bout++.cxx:243 +#: src/bout++.cxx:253 #, c-format msgid "DataDir \"%s\" is not a directory\n" msgstr "\"%s\" n'est pas un répertoire\n" -#: src/bout++.cxx:414 +#: src/bout++.cxx:424 #, fuzzy msgid "Error encountered during initialisation\n" msgstr "Erreur rencontrée lors de l'initialisation\n" -#: src/bout++.cxx:459 +#: src/bout++.cxx:469 #, c-format msgid "Error encountered during initialisation: %s\n" msgstr "Erreur rencontrée lors de l'initialisation : %s\n" @@ -74,13 +91,18 @@ msgstr "Temps d'exécution : " #. / Run the solver #: src/solver/solver.cxx:531 -msgid "Running simulation\n\n" -msgstr "L'exécution commence\n\n" +msgid "" +"Running simulation\n" +"\n" +msgstr "" +"L'exécution commence\n" +"\n" #: src/solver/solver.cxx:521 #, c-format msgid "Solver running for %d outputs with monitor timestep of %e\n" -msgstr "Le solveur fonctionne pour %d sorties avec un temps de moniteur de %e\n" +msgstr "" +"Le solveur fonctionne pour %d sorties avec un temps de moniteur de %e\n" #: src/solver/solver.cxx:519 #, c-format diff --git a/locale/libbout.pot b/locale/libbout.pot index 16f147edb2..6ca192dc2f 100644 --- a/locale/libbout.pot +++ b/locale/libbout.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-21 23:23+0100\n" +"POT-Creation-Date: 2018-10-23 00:03+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,20 +17,25 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: src/bout++.cxx:355 +#: src/bout++.cxx:365 msgid "\tChecking disabled\n" msgstr "" -#: src/bout++.cxx:353 +#: src/bout++.cxx:363 #, c-format msgid "\tChecking enabled, level %d\n" msgstr "" -#: src/bout++.cxx:361 +#: src/sys/options.cxx:96 src/sys/options.cxx:136 src/sys/options.cxx:171 +#: src/sys/options.cxx:199 src/sys/options.cxx:220 src/sys/options.cxx:223 +msgid "\tOption " +msgstr "" + +#: src/bout++.cxx:371 msgid "\tSignal handling disabled\n" msgstr "" -#: src/bout++.cxx:359 +#: src/bout++.cxx:369 msgid "\tSignal handling enabled\n" msgstr "" @@ -41,28 +46,35 @@ msgid "" "Run finished at : %s\n" msgstr "" -#: src/bout++.cxx:340 +#: src/solver/solver.cxx:534 +#, c-format +msgid "" +"\n" +"Run started at : %s\n" +msgstr "" + +#: src/bout++.cxx:350 #, c-format msgid "" "Code compiled on %s at %s\n" "\n" msgstr "" -#: src/bout++.cxx:246 +#: src/bout++.cxx:256 #, c-format msgid "DataDir \"%s\" does not exist or is not accessible\n" msgstr "" -#: src/bout++.cxx:243 +#: src/bout++.cxx:253 #, c-format msgid "DataDir \"%s\" is not a directory\n" msgstr "" -#: src/bout++.cxx:414 +#: src/bout++.cxx:424 msgid "Error encountered during initialisation\n" msgstr "" -#: src/bout++.cxx:459 +#: src/bout++.cxx:469 #, c-format msgid "Error encountered during initialisation: %s\n" msgstr "" diff --git a/locale/zh_TW/libbout.po b/locale/zh_TW/libbout.po new file mode 100644 index 0000000000..8ad8df5a0d --- /dev/null +++ b/locale/zh_TW/libbout.po @@ -0,0 +1,90 @@ +# Chinese translations for BOUT++ package. +# Copyright (C) 2018 THE BOUT++'S COPYRIGHT HOLDER +# This file is distributed under the same license as the BOUT++ package. +# , 2018. +# +msgid "" +msgstr "" +"Project-Id-Version: BOUT++ 4.2.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-10-23 00:03+0100\n" +"PO-Revision-Date: 2018-10-22 22:56+0100\n" +"Last-Translator: \n" +"Language-Team: Chinese (traditional)\n" +"Language: zh_TW\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/bout++.cxx:365 +msgid "\tChecking disabled\n" +msgstr "\t測試關掉\n" + +#: src/bout++.cxx:363 +#, c-format +msgid "\tChecking enabled, level %d\n" +msgstr "\t測試打開,级别 %d\n" + +#: src/sys/options.cxx:96 src/sys/options.cxx:136 src/sys/options.cxx:171 +#: src/sys/options.cxx:199 src/sys/options.cxx:220 src/sys/options.cxx:223 +msgid "\tOption " +msgstr "\t選項 " + +#: src/solver/solver.cxx:563 +#, c-format +msgid "" +"\n" +"Run finished at : %s\n" +msgstr "" +"\n" +"计算结束于 %s\n" + +#: src/solver/solver.cxx:534 +#, c-format +msgid "" +"\n" +"Run started at : %s\n" +msgstr "" +"\n" +"计算从 %s 开始\n" + +#: src/bout++.cxx:350 +#, c-format +msgid "" +"Code compiled on %s at %s\n" +"\n" +msgstr "" +"代码于 %s %s 编译\n" +"\n" + +#: src/bout++.cxx:256 +#, c-format +msgid "DataDir \"%s\" does not exist or is not accessible\n" +msgstr "\"%s\" 不存在或不可访问\n" + +#: src/bout++.cxx:253 +#, c-format +msgid "DataDir \"%s\" is not a directory\n" +msgstr "\"%s\" 不是目录\n" + +#: src/bout++.cxx:424 +msgid "Error encountered during initialisation\n" +msgstr "启动时遇到错误\n" + +#: src/bout++.cxx:469 +#, c-format +msgid "Error encountered during initialisation: %s\n" +msgstr "启动时遇到错误 : %s\n" + +#: src/solver/solver.cxx:564 +msgid "Run time : " +msgstr "计算时间" + +#. / Run the solver +#: src/solver/solver.cxx:531 +msgid "" +"Running simulation\n" +"\n" +msgstr "" +"模拟\n" +"\n" diff --git a/makefile b/makefile index 479113110e..0b805a00b8 100644 --- a/makefile +++ b/makefile @@ -85,7 +85,16 @@ locale/%/libbout.po: locale/libbout.pot locale/%/LC_MESSAGES/libbout.mo: locale/%/libbout.po msgfmt --output-file=$@ $< -locale-po: locale/fr/libbout.po - -locale-mo: locale/fr/LC_MESSAGES/libbout.mo - +# Shortcut target for building single language +# Note: invoking make since otherwise the intermediate file is deleted +locale-po-%: + $(MAKE) locale/$*/libbout.po +locale-mo-%: + $(MAKE) locale/$*/LC_MESSAGES/libbout.mo + +# Build all locales +LANGUAGES = fr zh_TW + +.PHONY: locale-po locale-mo +locale-po: $(LANGUAGES:%=locale/%/libbout.po) +locale-mo: $(LANGUAGES:%=locale/%/LC_MESSAGES/libbout.mo) diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 908c5e1ee4..340bf7b5e5 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -93,7 +93,7 @@ void Options::_set(string val, std::string source, bool force) { // Check if current value the same as new value if (value.value != val) { if (force or value.source != source) { - output_warn << "\tOption " << full_name << " = " << value.value << " (" + output_warn << _("\tOption ") << full_name << " = " << value.value << " (" << value.source << ") overwritten with:" << "\n" << "\t\t" << full_name << " = " << val << " (" << source << ")\n"; @@ -133,7 +133,7 @@ template <> std::string Options::as() const { // Mark this option as used value.used = true; - output_info << "\tOption " << full_name << " = " << value.value; + output_info << _("\tOption ") << full_name << " = " << value.value; if (!value.source.empty()) { // Specify the source of the setting output_info << " (" << value.source << ")"; @@ -168,7 +168,7 @@ template <> int Options::as() const { value.used = true; - output_info << "\tOption " << full_name << " = " << val; + output_info << _("\tOption ") << full_name << " = " << val; if (!value.source.empty()) { // Specify the source of the setting output_info << " (" << value.source << ")"; @@ -196,7 +196,7 @@ template <> BoutReal Options::as() const { // Mark this option as used value.used = true; - output_info << "\tOption " << full_name << " = " << val; + output_info << _("\tOption ") << full_name << " = " << val; if (!value.source.empty()) { // Specify the source of the setting output_info << " (" << value.source << ")"; @@ -217,10 +217,10 @@ template <> bool Options::as() const { char c = static_cast(toupper((value.value)[0])); if ((c == 'Y') || (c == 'T') || (c == '1')) { val = true; - output_info << "\tOption " << full_name << " = true"; + output_info << _("\tOption ") << full_name << " = true"; } else if ((c == 'N') || (c == 'F') || (c == '0')) { val = false; - output_info << "\tOption " << full_name << " = false"; + output_info << _("\tOption ") << full_name << " = false"; } else { throw BoutException("\tOption '%s': Boolean expected. Got '%s'\n", full_name.c_str(), value.value.c_str()); From 1bdb30c4263d3bcd612f511884c92bad2695c2f9 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 23 Oct 2018 00:16:00 +0100 Subject: [PATCH 0119/1783] Use std::locale rather than setlocale Sets C++ stream locales in addition to the C functions. Also seems to work where `setlocale(LC_ALL)` failed previously. --- src/bout++.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 5ee57d8dc1..8c8c91c0fd 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -146,14 +146,14 @@ int BoutInitialise(int &argc, char **&argv) { #if BOUT_HAS_GETTEXT // Setting the i18n environment - // Note: LC_ALL here causes problems, perhaps with reading strings - if (!setlocale (LC_MESSAGES, "")) { // Language-specific messages + try { + std::locale::global(std::locale("")); + bindtextdomain ("libbout", CMDLINE(BOUT_LOCALE_PATH)); + textdomain ("libbout"); + fprintf(stderr, "LOCALE_PATH = '%s'", CMDLINE(BOUT_LOCALE_PATH)); + } catch (const std::runtime_error &e) { fprintf(stderr, "WARNING: Could not set locale. Try a different LANG setting\n"); } - setlocale (LC_CTYPE, ""); // Output utf-8 characters - bindtextdomain ("libbout", CMDLINE(BOUT_LOCALE_PATH)); - fprintf(stderr, "LOCALE_PATH = '%s'", CMDLINE(BOUT_LOCALE_PATH)); - textdomain ("libbout"); #endif // BOUT_HAS_GETTEXT int verbosity=4; From cbda3f61ddb404f53972b847bef586eef56f3320 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 23 Oct 2018 10:12:26 +0100 Subject: [PATCH 0120/1783] Fix a few issues - `*.mo` makefile target ensures that `LC_MESSAGES` directory exists, since the directory has no git tracked files. - Add `*.mo` to `.gitignore` so shouldn't be accidentally checked in. - Use `std::setlocale` to set the `LC_NUMERIC` locale to "C". This aspect causes problems with `fr_FR` in reading numbers from strings. - Use `strftime` rather than `put_time` to format dates. Still handles locales, but should be available on older compilers. --- .gitignore | 2 ++ makefile | 2 ++ src/bout++.cxx | 7 ++++++- src/sys/utils.cxx | 15 ++++++++++----- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 5d18f0f0d3..ace943d4ef 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,5 @@ aclocal.m4 bout-coverage/ src/.libfast .*.mk +*.mo + diff --git a/makefile b/makefile index 0b805a00b8..96a5e79ab0 100644 --- a/makefile +++ b/makefile @@ -82,7 +82,9 @@ locale/%/libbout.po: locale/libbout.pot msgmerge --update $@ $< # Update a .mo file +# First ensure that the directory exists locale/%/LC_MESSAGES/libbout.mo: locale/%/libbout.po + @mkdir -p $(@D) msgfmt --output-file=$@ $< # Shortcut target for building single language diff --git a/src/bout++.cxx b/src/bout++.cxx index 8c8c91c0fd..73be8d47cf 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -147,7 +147,12 @@ int BoutInitialise(int &argc, char **&argv) { #if BOUT_HAS_GETTEXT // Setting the i18n environment try { - std::locale::global(std::locale("")); + // Note: Would like to use std::locale::global + // std::locale::global(std::locale("")); + // but the Numeric aspect causes problems parsing input strings + std::setlocale(LC_ALL, ""); + std::setlocale(LC_NUMERIC, "C"); + bindtextdomain ("libbout", CMDLINE(BOUT_LOCALE_PATH)); textdomain ("libbout"); fprintf(stderr, "LOCALE_PATH = '%s'", CMDLINE(BOUT_LOCALE_PATH)); diff --git a/src/sys/utils.cxx b/src/sys/utils.cxx index 26986b48e8..caef6013f5 100644 --- a/src/sys/utils.cxx +++ b/src/sys/utils.cxx @@ -134,10 +134,15 @@ std::string trimComments(const std::string &s, const std::string &c) { template <> const std::string toString<>(const time_t& time) { // Get local time - std::tm tm = *std::localtime(&time); - - std::stringstream ss; - ss << std::put_time(&tm, "%c %Z"); + std::tm *tm = std::localtime(&time); - return ss.str(); + // Note: With GCC >= 5 `put_time` becomes available + // std::stringstream ss; + // ss << std::put_time(tm, "%c %Z"); + // return ss.str(); + + // Older compilers + char buffer[80]; + strftime(buffer, 80, "%Ec %Z", tm); + return std::string(buffer); } From 8f344fcbc3e9bd49abc7f510f6e3eeba8ce26240 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 25 Oct 2018 14:05:51 +0100 Subject: [PATCH 0121/1783] Ensure Zoidberg fieldtracer works correctly with scalar inputs Numpy helpfully has scalar arrays which have no `len()`. Use `numpy.atleast_1d` to both make sure inputs are numpy arrays and that they have at least one dimension This also ensures the output is consistently 3D, although scalar inputs then have a useless y-dimension --- tools/pylib/zoidberg/fieldtracer.py | 17 ++++++++--------- tools/pylib/zoidberg/test_fieldtracer.py | 18 +++++++++--------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/tools/pylib/zoidberg/fieldtracer.py b/tools/pylib/zoidberg/fieldtracer.py index a876bca47e..6b5fcb69ba 100644 --- a/tools/pylib/zoidberg/fieldtracer.py +++ b/tools/pylib/zoidberg/fieldtracer.py @@ -54,12 +54,11 @@ def follow_field_lines(self, x_values, z_values, y_values, rtol=None): """ - if not isinstance(x_values, np.ndarray): - x_values = np.array(x_values) - if not isinstance(y_values, np.ndarray): - y_values = np.array(y_values) - if not isinstance(z_values, np.ndarray): - z_values = np.array(z_values) + # Ensure all inputs are NumPy arrays + x_values = np.atleast_1d(x_values) + y_values = np.atleast_1d(y_values) + z_values = np.atleast_1d(z_values) + if len(y_values) < 2: raise ValueError("There must be at least two elements in y_values") if len(y_values.shape) > 1: @@ -203,9 +202,9 @@ def follow_field_lines(self, x_values, z_values, y_values, rtol=None, eps=None, nsteps = int(nsteps) # Ensure all inputs are NumPy arrays - x_values = np.asfarray(x_values) - y_values = np.asfarray(y_values) - z_values = np.asfarray(z_values) + x_values = np.atleast_1d(x_values) + y_values = np.atleast_1d(y_values) + z_values = np.atleast_1d(z_values) if len(y_values) < 2: raise ValueError("There must be at least two elements in y_values") diff --git a/tools/pylib/zoidberg/test_fieldtracer.py b/tools/pylib/zoidberg/test_fieldtracer.py index e71b102711..8cdac5fdf0 100644 --- a/tools/pylib/zoidberg/test_fieldtracer.py +++ b/tools/pylib/zoidberg/test_fieldtracer.py @@ -10,11 +10,11 @@ def test_slab(): coords = tracer.follow_field_lines( 0.2, 0.3, [1.5, 2.5] ) - assert coords.shape == (2,2) - assert np.allclose(coords[:,0], 0.2) # X coordinate + assert coords.shape == (2,1,2) + assert np.allclose(coords[:,0,0], 0.2) # X coordinate - assert np.allclose(coords[0,1], 0.3) - assert np.allclose(coords[1,1], 0.3 + 0.1/0.5) # Z coordinate + assert np.allclose(coords[0,0,1], 0.3) + assert np.allclose(coords[1,0,1], 0.3 + 0.1/0.5) # Z coordinate coords = tracer.follow_field_lines( [0.2,0.3,0.4], 0.5, [1.0,2.5] ) @@ -31,11 +31,11 @@ def test_FieldTracerReversible_slab(): coords = tracer.follow_field_lines( 0.2, 0.3, [1.5, 2.5] ) - assert coords.shape == (2,2) - assert np.allclose(coords[:,0], 0.2) # X coordinate + assert coords.shape == (2,1,2) + assert np.allclose(coords[:,0,0], 0.2) # X coordinate - assert np.allclose(coords[0,1], 0.3) - assert np.allclose(coords[1,1], 0.3 + 0.1/0.5) # Z coordinate + assert np.allclose(coords[0,0,1], 0.3) + assert np.allclose(coords[1,0,1], 0.3 + 0.1/0.5) # Z coordinate coords = tracer.follow_field_lines( [0.2,0.3,0.4], 0.5, [1.0,2.5] ) @@ -52,5 +52,5 @@ def test_poincare(): nplot=3, revs=5,nover=1) assert y_slices.size == 3 - assert result.shape == (5,y_slices.size, 2) + assert result.shape == (5, y_slices.size, 1, 2) From 602ba81674b10b4d7a89b4be4d513b4419472c5e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 25 Oct 2018 14:08:15 +0100 Subject: [PATCH 0122/1783] Fix some warnings in test_make_maps_straight_stellarator The radius needs to be at least sqrt(2) in order to fully encompass a square with width 1 --- tools/pylib/zoidberg/test_zoidberg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pylib/zoidberg/test_zoidberg.py b/tools/pylib/zoidberg/test_zoidberg.py index b1af481eea..d82c30f0e2 100644 --- a/tools/pylib/zoidberg/test_zoidberg.py +++ b/tools/pylib/zoidberg/test_zoidberg.py @@ -54,7 +54,7 @@ def test_make_maps_straight_stellarator(): nz = 7 # Create magnetic field - magnetic_field = field.StraightStellarator(radius = 1.0) + magnetic_field = field.StraightStellarator(radius = np.sqrt(2.0)) # Create a rectangular grid in (x,y,z) rectangle = grid.rectangular_grid(nx,ny,nz, From f6288c4d5c9ee320fff8801b81a60b1fc8b77f28 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 25 Oct 2018 14:34:33 +0100 Subject: [PATCH 0123/1783] Install and run pytest on Travis --- .travis.yml | 1 + .travis_script.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 70fd3f23ad..40fc35b8d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ addons: - hdf5-tools - python3 - python3-pip + - python3-pytest - python3-numpy - python3-scipy - lcov diff --git a/.travis_script.sh b/.travis_script.sh index e1fca8159c..5fedcbb8a9 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -95,6 +95,7 @@ fi if [[ ${UNIT} == 1 ]] then time make check-unit-tests || exit + time pytest tools/pylib/ || exit fi if [[ ${INTEGRATED} == 1 ]] From 5374e4aa838d923dea9c8ac8355f66dcb206103f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 25 Oct 2018 15:04:47 +0100 Subject: [PATCH 0124/1783] Use the actual name of the pytest binary installed on trusty --- .travis_script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis_script.sh b/.travis_script.sh index 5fedcbb8a9..8d36b051dd 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -95,7 +95,7 @@ fi if [[ ${UNIT} == 1 ]] then time make check-unit-tests || exit - time pytest tools/pylib/ || exit + time py.test-3 tools/pylib/ || exit fi if [[ ${INTEGRATED} == 1 ]] From 540d735f8f651dc73d91c4376938baf9b480887d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 25 Oct 2018 16:18:22 +0100 Subject: [PATCH 0125/1783] Install sympy and upgrade scipy and numpy on Travis --- .pip_install_for_travis.sh | 1 + .travis.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) mode change 100644 => 100755 .pip_install_for_travis.sh diff --git a/.pip_install_for_travis.sh b/.pip_install_for_travis.sh old mode 100644 new mode 100755 index 0b489f1d15..739885ea44 --- a/.pip_install_for_travis.sh +++ b/.pip_install_for_travis.sh @@ -1,6 +1,7 @@ #!/bin/bash export PATH=${HOME}/.local/bin:${PATH} pip3 install --user --upgrade pip setuptools +pip3 install --user --upgrade pip scipy numpy for package in $@ do diff --git a/.travis.yml b/.travis.yml index 40fc35b8d1..457aa7d9fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ matrix: - env: &default_env - CONFIGURE_OPTIONS='--enable-checks=no --enable-optimize=3 --disable-signal --disable-track --disable-backtrace' - SCRIPT_FLAGS='-uim' - - PIP_PACKAGES='netcdf4' + - PIP_PACKAGES='netcdf4 sympy' - addons: apt: sources: From b2d731e60e1a43c7ffd37bd12445d5940cc718d7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 25 Oct 2018 16:51:58 +0100 Subject: [PATCH 0126/1783] Include sympy in all the relevant Travis jobs --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 457aa7d9fb..4b5369cee8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,7 +53,7 @@ matrix: - *default_env - CONFIGURE_OPTIONS='--enable-shared' - SCRIPT_FLAGS="-uim -t python -t shared" - - PIP_PACKAGES='netcdf4 cython' + - PIP_PACKAGES='netcdf4 cython sympy' - env: - *default_env - CONFIGURE_OPTIONS='--enable-openmp' From a6855f20b233f7d5e9d2b25412b2e6f9e936008d Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 25 Oct 2018 17:03:14 +0100 Subject: [PATCH 0127/1783] Add zh_CN, add some strings in boutmesh Now have simplified chinese in zh_CN, and traditional in zh_TW. --- locale/zh_CN/libbout.po | 90 ++++++++++++++++++++++++++++++++ locale/zh_TW/libbout.po | 14 ++--- makefile | 2 +- src/mesh/impls/bout/boutmesh.cxx | 38 +++++++------- 4 files changed, 117 insertions(+), 27 deletions(-) create mode 100644 locale/zh_CN/libbout.po diff --git a/locale/zh_CN/libbout.po b/locale/zh_CN/libbout.po new file mode 100644 index 0000000000..277c2ac448 --- /dev/null +++ b/locale/zh_CN/libbout.po @@ -0,0 +1,90 @@ +# Chinese translations for BOUT++ package. +# Copyright (C) 2018 THE BOUT++'S COPYRIGHT HOLDER +# This file is distributed under the same license as the BOUT++ package. +# , 2018. +# +msgid "" +msgstr "" +"Project-Id-Version: BOUT++ 4.2.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-10-23 00:03+0100\n" +"PO-Revision-Date: 2018-10-22 22:56+0100\n" +"Last-Translator: \n" +"Language-Team: Chinese (simplified)\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/bout++.cxx:365 +msgid "\tChecking disabled\n" +msgstr "\t测试关掉\n" + +#: src/bout++.cxx:363 +#, c-format +msgid "\tChecking enabled, level %d\n" +msgstr "\t测试打开,级别 %d\n" + +#: src/sys/options.cxx:96 src/sys/options.cxx:136 src/sys/options.cxx:171 +#: src/sys/options.cxx:199 src/sys/options.cxx:220 src/sys/options.cxx:223 +msgid "\tOption " +msgstr "\t选项 " + +#: src/solver/solver.cxx:563 +#, c-format +msgid "" +"\n" +"Run finished at : %s\n" +msgstr "" +"\n" +"计算结束于 %s\n" + +#: src/solver/solver.cxx:534 +#, c-format +msgid "" +"\n" +"Run started at : %s\n" +msgstr "" +"\n" +"计算从 %s 开始\n" + +#: src/bout++.cxx:350 +#, c-format +msgid "" +"Code compiled on %s at %s\n" +"\n" +msgstr "" +"代码于 %s %s 编译\n" +"\n" + +#: src/bout++.cxx:256 +#, c-format +msgid "DataDir \"%s\" does not exist or is not accessible\n" +msgstr "\"%s\" 不存在或不可访问\n" + +#: src/bout++.cxx:253 +#, c-format +msgid "DataDir \"%s\" is not a directory\n" +msgstr "\"%s\" 不是目录\n" + +#: src/bout++.cxx:424 +msgid "Error encountered during initialisation\n" +msgstr "启动时遇到错误\n" + +#: src/bout++.cxx:469 +#, c-format +msgid "Error encountered during initialisation: %s\n" +msgstr "启动时遇到错误 : %s\n" + +#: src/solver/solver.cxx:564 +msgid "Run time : " +msgstr "计算时间" + +#. / Run the solver +#: src/solver/solver.cxx:531 +msgid "" +"Running simulation\n" +"\n" +msgstr "" +"模拟\n" +"\n" diff --git a/locale/zh_TW/libbout.po b/locale/zh_TW/libbout.po index 8ad8df5a0d..80e8d3a3cb 100644 --- a/locale/zh_TW/libbout.po +++ b/locale/zh_TW/libbout.po @@ -54,31 +54,31 @@ msgid "" "Code compiled on %s at %s\n" "\n" msgstr "" -"代码于 %s %s 编译\n" +"代碼於 %s %s 编译\n" "\n" #: src/bout++.cxx:256 #, c-format msgid "DataDir \"%s\" does not exist or is not accessible\n" -msgstr "\"%s\" 不存在或不可访问\n" +msgstr "\"%s\" 不存在或不可訪問\n" #: src/bout++.cxx:253 #, c-format msgid "DataDir \"%s\" is not a directory\n" -msgstr "\"%s\" 不是目录\n" +msgstr "\"%s\" 不是目錄\n" #: src/bout++.cxx:424 msgid "Error encountered during initialisation\n" -msgstr "启动时遇到错误\n" +msgstr "啟動時遇到錯誤\n" #: src/bout++.cxx:469 #, c-format msgid "Error encountered during initialisation: %s\n" -msgstr "启动时遇到错误 : %s\n" +msgstr "啟動時遇到錯誤 : %s\n" #: src/solver/solver.cxx:564 msgid "Run time : " -msgstr "计算时间" +msgstr "計算時間" #. / Run the solver #: src/solver/solver.cxx:531 @@ -86,5 +86,5 @@ msgid "" "Running simulation\n" "\n" msgstr "" -"模拟\n" +"模擬\n" "\n" diff --git a/makefile b/makefile index 96a5e79ab0..da332cf410 100644 --- a/makefile +++ b/makefile @@ -95,7 +95,7 @@ locale-mo-%: $(MAKE) locale/$*/LC_MESSAGES/libbout.mo # Build all locales -LANGUAGES = fr zh_TW +LANGUAGES = fr zh_TW zh_CN .PHONY: locale-po locale-mo locale-po: $(LANGUAGES:%=locale/%/libbout.po) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index e4f3c487a0..9df5f340d6 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -88,7 +88,7 @@ BoutMesh::~BoutMesh() { int BoutMesh::load() { TRACE("BoutMesh::load()"); - output_progress << "Loading mesh" << endl; + output_progress << _("Loading mesh") << endl; // Use root level options Options *options = Options::getRoot(); @@ -103,10 +103,10 @@ int BoutMesh::load() { // Grid sizes if (Mesh::get(nx, "nx")) - throw BoutException("Mesh must contain nx"); + throw BoutException(_("Mesh must contain nx")); if (Mesh::get(ny, "ny")) - throw BoutException("Mesh must contain ny"); + throw BoutException(_("Mesh must contain ny")); int MZ; @@ -121,10 +121,10 @@ int BoutMesh::load() { MZ); } } else { - output_info.write("\tRead nz from input grid file\n"); + output_info.write(_("\tRead nz from input grid file\n")); } - output_info << "\tGrid size: " << nx << " x " << ny << " x " << MZ << endl; + output_info << _("\tGrid size: ") << nx << " x " << ny << " x " << MZ << endl; // Get guard cell sizes // Try to read from grid file first, then if not found @@ -140,11 +140,11 @@ int BoutMesh::load() { } ASSERT0(MYG >= 0); - output_info << "\tGuard cells (x,y): " << MXG << ", " << MYG << std::endl; + output_info << _("\tGuard cells (x,y): ") << MXG << ", " << MYG << std::endl; // Check that nx is large enough if (nx <= 2 * MXG) { - throw BoutException("Error: nx must be greater than 2 times MXG (2 * %d)", MXG); + throw BoutException(_("Error: nx must be greater than 2 times MXG (2 * %d)"), MXG); } // Set global grid sizes @@ -153,7 +153,7 @@ int BoutMesh::load() { GlobalNz = MZ; if (2 * MXG >= nx) - throw BoutException("nx must be greater than 2*MXG"); + throw BoutException(_("nx must be greater than 2*MXG")); // separatrix location if (Mesh::get(ixseps1, "ixseps1")) { @@ -231,7 +231,7 @@ int BoutMesh::load() { options->get("NXPE", NXPE, 1); // Decomposition in the radial direction if ((NPES % NXPE) != 0) { throw BoutException( - "Number of processors (%d) not divisible by NPs in x direction (%d)\n", NPES, + _("Number of processors (%d) not divisible by NPs in x direction (%d)\n"), NPES, NXPE); } @@ -381,14 +381,14 @@ int BoutMesh::load() { } if (NXPE < 1) - throw BoutException( - "Could not find a valid value for NXPE. Try a different number of processors."); + throw BoutException(_("Could not find a valid value for NXPE. Try a different " + "number of processors.")); NYPE = NPES / NXPE; output_progress.write( - "\tDomain split (NXPE=%d, NYPE=%d) into domains (localNx=%d, localNy=%d)\n", NXPE, - NYPE, MX / NXPE, ny / NYPE); + _("\tDomain split (NXPE=%d, NYPE=%d) into domains (localNx=%d, localNy=%d)\n"), + NXPE, NYPE, MX / NXPE, ny / NYPE); } /// Get X and Y processor indices @@ -403,7 +403,7 @@ int BoutMesh::load() { /// Split MX points between NXPE processors MXSUB = MX / NXPE; if ((MX % NXPE) != 0) { - throw BoutException("Cannot split %d X points equally between %d processors\n", MX, + throw BoutException(_("Cannot split %d X points equally between %d processors\n"), MX, NXPE); } @@ -412,7 +412,7 @@ int BoutMesh::load() { MYSUB = MY / NYPE; if ((MY % NYPE) != 0) { throw BoutException( - "\tERROR: Cannot split %d Y points equally between %d processors\n", MY, NYPE); + _("\tERROR: Cannot split %d Y points equally between %d processors\n"), MY, NYPE); } /// Get mesh options @@ -824,22 +824,22 @@ int BoutMesh::load() { } if (!boundary.empty()) { - output_info << "Boundary regions in this processor: "; + output_info << _("Boundary regions in this processor: "); for (const auto &bndry : boundary) { output_info << bndry->label << ", "; } output_info << endl; } else { - output_info << "No boundary regions in this processor" << endl; + output_info << _("No boundary regions in this processor") << endl; } - output_info << "Constructing default regions" << endl; + output_info << _("Constructing default regions") << endl; createDefaultRegions(); // Add boundary regions addBoundaryRegions(); - output_info.write("\tdone\n"); + output_info.write(_("\tdone\n")); return 0; } From 40ec05ddc31428fb64d062af9bcbd4f21644d8ef Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 25 Oct 2018 23:56:12 +0100 Subject: [PATCH 0128/1783] Improve config, makefile for NLS `--enable-nls` now uses `AM_GNU_GETTEXT` to check for and enable Natural Language Support. Configure now builds the .mo files so no separate step needed. `makefile` for NLS related things moved to `locale/` --- bin/bout-config.in | 8 + configure | 2934 ++++++++++++++++++++++++++++++++++++++++---- configure.ac | 33 +- locale/libbout.pot | 121 +- locale/makefile | 41 + makefile | 35 +- 6 files changed, 2902 insertions(+), 270 deletions(-) create mode 100644 locale/makefile diff --git a/bin/bout-config.in b/bin/bout-config.in index 517987425f..0cc85012ce 100755 --- a/bin/bout-config.in +++ b/bin/bout-config.in @@ -39,6 +39,7 @@ has_slepc="@HAS_SLEPC@" has_mumps="@HAS_MUMPS@" has_arkode="@HAS_ARKODE@" has_openmp="@HAS_OPENMP@" +has_nls="@HAS_NLS@" petsc_has_sundials="@PETSC_HAS_SUNDIALS@" @@ -75,6 +76,7 @@ Available values for OPTION include: --has-petsc PETSc support --has-slepc SLEPc support --has-mumps MUMPS support + --has-nls Natural Language Support --petsc-has-sundials EOF @@ -111,6 +113,7 @@ all() echo " --has-slepc -> $has_slepc" echo " --has-mumps -> $has_mumps" echo " --has-arkode -> $has_arkode" + echo " --has-nls -> $has_nls" echo echo " --petsc-has-sundials -> $petsc_has_sundials" echo @@ -231,6 +234,11 @@ while test $# -gt 0; do echo $has_openmp ;; + --has-nls) + echo $has_nls + ;; + + --petsc-version) # TODO: Remove in next release # Left in for backwards-compatibility diff --git a/configure b/configure index 411e72f362..3a9cb933dd 100755 --- a/configure +++ b/configure @@ -621,7 +621,9 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='HAS_OPENMP +gt_needs= +ac_subst_vars='HAS_NLS +HAS_OPENMP SLEPC_ARCH SLEPC_DIR SLEPC_MAKE_INCLUDE @@ -651,6 +653,31 @@ BOUT_LIB_PATH CONFIG_LDFLAGS CONFIG_CFLAGS LTLIBOBJS +POSUB +LTLIBINTL +LIBINTL +INTLLIBS +LTLIBICONV +LIBICONV +INTL_MACOSX_LIBS +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +XGETTEXT_EXTRA_OPTIONS +MSGMERGE +XGETTEXT_015 +XGETTEXT +GMSGFMT_015 +MSGFMT_015 +GMSGFMT +MSGFMT +GETTEXT_MACRO_VERSION +USE_NLS SCOREPPATH sundials_config PARALLELHDF5_TYPE @@ -788,11 +815,15 @@ enable_shared enable_openmp with_openmp_schedule enable_pvode_openmp -enable_gettext +enable_nls with_gcov enable_code_coverage with_hdf5 with_parallelhdf5 +with_gnu_ld +enable_rpath +with_libiconv_prefix +with_libintl_prefix ' ac_precious_vars='build_alias host_alias @@ -1417,6 +1448,10 @@ Fine tuning of the installation directories: _ACEOF cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi @@ -1444,9 +1479,11 @@ Optional Features: --enable-shared Enable building bout++ into an shared object --enable-openmp Enable building with OpenMP support --enable-pvode-openmp Enable building PVODE with OpenMP support - --enable-gettext Enable localisation (i18n) with gettext + --enable-nls Enable Natural Language Support with gettext --disable-openmp do not use OpenMP --enable-code-coverage Whether to enable code coverage support + --disable-nls do not use Native Language Support + --disable-rpath do not hardcode runtime library paths Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1470,6 +1507,11 @@ Optional Packages: --with-hdf5=yes/no/PATH location of h5cc for serial HDF5 configuration --with-parallelhdf5=yes/no/PATH location of h5pcc for parallel HDF5 configuration + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib + --without-libiconv-prefix don't search for libiconv in includedir and libdir + --with-libintl-prefix[=DIR] search for libintl in DIR/include and DIR/lib + --without-libintl-prefix don't search for libintl in includedir and libdir Some influential environment variables: EXTRA_INCS Extra compile flags @@ -2413,6 +2455,7 @@ $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi +gt_needs="$gt_needs " # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false @@ -2676,11 +2719,11 @@ else enable_pvode_openmp=no fi -# Check whether --enable-gettext was given. -if test "${enable_gettext+set}" = set; then : - enableval=$enable_gettext; +# Check whether --enable-nls was given. +if test "${enable_nls+set}" = set; then : + enableval=$enable_nls; else - enable_gettext=no + enable_nls=no fi @@ -12098,240 +12141,2424 @@ fi # Localisation (i18n) with gettext ############################################################# -if test "$enable_gettext" != "no" ; then : - - # Note: BOUT_LOCALE_PATH is defined in make.config, and may be changed by `make install`. - CXXFLAGS="$CXXFLAGS -DBOUT_HAS_GETTEXT -DBOUT_LOCALE_PATH=\$(BOUT_LOCALE_PATH)" +HAS_NLS="no" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether NLS is requested" >&5 +$as_echo_n "checking whether NLS is requested... " >&6; } + # Check whether --enable-nls was given. +if test "${enable_nls+set}" = set; then : + enableval=$enable_nls; USE_NLS=$enableval +else + USE_NLS=yes fi -############################################################# -# Check environment -############################################################# - -if test "$CXXINCLUDE" != ""; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 +$as_echo "$USE_NLS" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: ================================================" >&5 -$as_echo "$as_me: ================================================" >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: CXXINCLUDE environment variable set to:" >&5 -$as_echo "$as_me: WARNING: CXXINCLUDE environment variable set to:" >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: $CXXINCLUDE" >&5 -$as_echo "$as_me: $CXXINCLUDE" >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: => This will be added to compile commands" >&5 -$as_echo "$as_me: => This will be added to compile commands" >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: If this is not intended, then run" >&5 -$as_echo "$as_me: If this is not intended, then run" >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: export CXXINCLUDE=''" >&5 -$as_echo "$as_me: export CXXINCLUDE=''" >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: before making BOUT++" >&5 -$as_echo "$as_me: before making BOUT++" >&6;} - { $as_echo "$as_me:${as_lineno-$LINENO}: ================================================" >&5 -$as_echo "$as_me: ================================================" >&6;} -fi -############################################################# -# Gather configuration info for bout-config -############################################################# -EXTRA_INCS="${EXTRA_INCS} ${CPPFLAGS}" + GETTEXT_MACRO_VERSION=0.19 -PREFIX=$PWD -IDLCONFIGPATH=$PWD/tools/idllib -PYTHONCONFIGPATH=$PWD/tools/pylib -HAS_IDA="yes" -if test "$IDALIBS" = "" -then - HAS_IDA="no" -fi -HAS_CVODE="yes" -if test "$CVODELIBS" = "" -then - HAS_CVODE="no" -fi -HAS_ARKODE="yes" -if test "$ARKODELIBS" = "" -then - HAS_ARKODE="no" +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which + # contains only /bin. Note that ksh looks also at the FPATH variable, + # so we have to set that as well for the test. + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + || PATH_SEPARATOR=';' + } fi -HAS_NETCDF="yes" -if test "$NCPATH" = "" -then - HAS_NETCDF="no" +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" fi +rm -f conf$$.file -HAS_PNETCDF="yes" -if test "$PNCPATH" = "" -then - HAS_PNETCDF="no" +# Extract the first word of "msgfmt", so it can be a program name with args. +set dummy msgfmt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_MSGFMT+:} false; then : + $as_echo_n "(cached) " >&6 +else + case "$MSGFMT" in + [\\/]* | ?:[\\/]*) + ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + echo "$as_me: trying $ac_dir/$ac_word..." >&5 + if $ac_dir/$ac_word --statistics /dev/null >&5 2>&1 && + (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + ac_cv_path_MSGFMT="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" + test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT=":" + ;; +esac fi - -HAS_MUMPS="yes" -if test "$MUMPS" = "" -then - HAS_MUMPS="no" +MSGFMT="$ac_cv_path_MSGFMT" +if test "$MSGFMT" != ":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 +$as_echo "$MSGFMT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi -# Only make.config is altered by configure -ac_config_files="$ac_config_files make.config" - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac + # Extract the first word of "gmsgfmt", so it can be a program name with args. +set dummy gmsgfmt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_GMSGFMT+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $GMSGFMT in + [\\/]* | ?:[\\/]*) + ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_GMSGFMT="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done done +IFS=$as_save_IFS - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} - fi + test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT" + ;; +esac +fi +GMSGFMT=$ac_cv_path_GMSGFMT +if test -n "$GMSGFMT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GMSGFMT" >&5 +$as_echo "$GMSGFMT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } fi -rm -f confcache -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' -# Transform confdefs.h into DEFS. -# Protect against shell expansion while executing Makefile rules. -# Protect against Makefile macro expansion. -# -# If the first sed substitution is executed (which looks for macros that -# take arguments), then branch to the quote section. Otherwise, -# look for a macro that doesn't take arguments. -ac_script=' -:mline -/\\$/{ - N - s,\\\n,, - b mline -} -t clear -:clear -s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g -t quote -s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g -t quote -b any -:quote -s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g -s/\[/\\&/g -s/\]/\\&/g -s/\$/$$/g -H -:any -${ - g - s/^\n// - s/\n/ /g - p -} -' -DEFS=`sed -n "$ac_script" confdefs.h` + case `$MSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) MSGFMT_015=: ;; + *) MSGFMT_015=$MSGFMT ;; + esac -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs + case `$GMSGFMT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) GMSGFMT_015=: ;; + *) GMSGFMT_015=$GMSGFMT ;; + esac -LTLIBOBJS=$ac_ltlibobjs -if test -z "${CODE_COVERAGE_ENABLED_TRUE}" && test -z "${CODE_COVERAGE_ENABLED_FALSE}"; then - as_fn_error $? "conditional \"CODE_COVERAGE_ENABLED\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which + # contains only /bin. Note that ksh looks also at the FPATH variable, + # so we have to set that as well for the test. + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + || PATH_SEPARATOR=';' + } fi -: "${CONFIG_STATUS=./config.status}" -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "xgettext", so it can be a program name with args. +set dummy xgettext; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_XGETTEXT+:} false; then : + $as_echo_n "(cached) " >&6 +else + case "$XGETTEXT" in + [\\/]* | ?:[\\/]*) + ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + echo "$as_me: trying $ac_dir/$ac_word..." >&5 + if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >&5 2>&1 && + (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + ac_cv_path_XGETTEXT="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" + test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":" + ;; +esac +fi +XGETTEXT="$ac_cv_path_XGETTEXT" +if test "$XGETTEXT" != ":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XGETTEXT" >&5 +$as_echo "$XGETTEXT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + rm -f messages.po + + case `$XGETTEXT --version | sed 1q | sed -e 's,^[^0-9]*,,'` in + '' | 0.[0-9] | 0.[0-9].* | 0.1[0-4] | 0.1[0-4].*) XGETTEXT_015=: ;; + *) XGETTEXT_015=$XGETTEXT ;; + esac + + + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which + # contains only /bin. Note that ksh looks also at the FPATH variable, + # so we have to set that as well for the test. + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + || PATH_SEPARATOR=';' + } +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "msgmerge", so it can be a program name with args. +set dummy msgmerge; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_MSGMERGE+:} false; then : + $as_echo_n "(cached) " >&6 +else + case "$MSGMERGE" in + [\\/]* | ?:[\\/]*) + ac_cv_path_MSGMERGE="$MSGMERGE" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + echo "$as_me: trying $ac_dir/$ac_word..." >&5 + if $ac_dir/$ac_word --update -q /dev/null /dev/null >&5 2>&1; then + ac_cv_path_MSGMERGE="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" + test -z "$ac_cv_path_MSGMERGE" && ac_cv_path_MSGMERGE=":" + ;; +esac +fi +MSGMERGE="$ac_cv_path_MSGMERGE" +if test "$MSGMERGE" != ":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGMERGE" >&5 +$as_echo "$MSGMERGE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$localedir" || localedir='${datadir}/locale' + + + test -n "${XGETTEXT_EXTRA_OPTIONS+set}" || XGETTEXT_EXTRA_OPTIONS= + + + ac_config_commands="$ac_config_commands po-directories" + + + + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which + # contains only /bin. Note that ksh looks also at the FPATH variable, + # so we have to set that as well for the test. + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ + || PATH_SEPARATOR=';' + } +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo "$ac_prog"| sed 's%\\\\%/%g'` + while echo "$ac_prog" | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${acl_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$acl_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${acl_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$acl_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$acl_cv_prog_gnu_ld + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shared library run path origin" >&5 +$as_echo_n "checking for shared library run path origin... " >&6; } +if ${acl_cv_rpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_rpath" >&5 +$as_echo "$acl_cv_rpath" >&6; } + wl="$acl_cv_wl" + acl_libext="$acl_cv_libext" + acl_shlibext="$acl_cv_shlibext" + acl_libname_spec="$acl_cv_libname_spec" + acl_library_names_spec="$acl_cv_library_names_spec" + acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + acl_hardcode_direct="$acl_cv_hardcode_direct" + acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" + # Check whether --enable-rpath was given. +if test "${enable_rpath+set}" = set; then : + enableval=$enable_rpath; : +else + enable_rpath=yes +fi + + + + + acl_libdirstem=lib + acl_libdirstem2= + case "$host_os" in + solaris*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit host" >&5 +$as_echo_n "checking for 64-bit host... " >&6; } +if ${gl_cv_solaris_64bit+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef _LP64 +sixtyfour bits +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "sixtyfour bits" >/dev/null 2>&1; then : + gl_cv_solaris_64bit=yes +else + gl_cv_solaris_64bit=no +fi +rm -f conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_solaris_64bit" >&5 +$as_echo "$gl_cv_solaris_64bit" >&6; } + if test $gl_cv_solaris_64bit = yes; then + acl_libdirstem=lib/64 + case "$host_cpu" in + sparc*) acl_libdirstem2=lib/sparcv9 ;; + i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; + esac + fi + ;; + *) + searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` + if test -n "$searchpath"; then + acl_save_IFS="${IFS= }"; IFS=":" + for searchdir in $searchpath; do + if test -d "$searchdir"; then + case "$searchdir" in + */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; + */../ | */.. ) + # Better ignore directories of this form. They are misleading. + ;; + *) searchdir=`cd "$searchdir" && pwd` + case "$searchdir" in + */lib64 ) acl_libdirstem=lib64 ;; + esac ;; + esac + fi + done + IFS="$acl_save_IFS" + fi + ;; + esac + test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" + + + + + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libiconv-prefix was given. +if test "${with_libiconv_prefix+set}" = set; then : + withval=$with_libiconv_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + if test "$acl_libdirstem2" != "$acl_libdirstem" \ + && ! test -d "$withval/$acl_libdirstem"; then + additional_libdir="$withval/$acl_libdirstem2" + fi + fi + fi + +fi + + LIBICONV= + LTLIBICONV= + INCICONV= + LIBICONV_PREFIX= + HAVE_LIBICONV= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='iconv ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBICONV="${LIBICONV}${LIBICONV:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + eval libname=\"$acl_libname_spec\" # typically: libname=lib$name + if test -n "$acl_shlibext"; then + shrext=".$acl_shlibext" # typically: shrext=.so + else + shrext= + fi + if test $use_additional = yes; then + dir="$additional_libdir" + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no \ + || test "X$found_dir" = "X/usr/$acl_libdirstem" \ + || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$acl_hardcode_direct" = yes; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir" + fi + if test "$acl_hardcode_minus_L" != no; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }$found_a" + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + if test "$name" = 'iconv'; then + LIBICONV_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + */$acl_libdirstem2 | */$acl_libdirstem2/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` + if test "$name" = 'iconv'; then + LIBICONV_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCICONV="${INCICONV}${INCICONV:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ + && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ + || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBICONV="${LIBICONV}${LIBICONV:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBICONV; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBICONV="${LIBICONV}${LIBICONV:+ }$dep" + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$dep" + ;; + esac + done + fi + else + LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$acl_hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-R$found_dir" + done + fi + + + + + + + +if test "$enable_nls" != "no" ; then : + + # Use macro to test if Natural Language Support (gettext) is available. + # If available sets: + # - USE_NLS to "yes" + # - LIBINTL to the linker options + # - Modifies CPPFLAGS if needed + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFPreferencesCopyAppValue" >&5 +$as_echo_n "checking for CFPreferencesCopyAppValue... " >&6; } +if ${gt_cv_func_CFPreferencesCopyAppValue+:} false; then : + $as_echo_n "(cached) " >&6 +else + gt_save_LIBS="$LIBS" + LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +CFPreferencesCopyAppValue(NULL, NULL) + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gt_cv_func_CFPreferencesCopyAppValue=yes +else + gt_cv_func_CFPreferencesCopyAppValue=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$gt_save_LIBS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFPreferencesCopyAppValue" >&5 +$as_echo "$gt_cv_func_CFPreferencesCopyAppValue" >&6; } + if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then + +$as_echo "#define HAVE_CFPREFERENCESCOPYAPPVALUE 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyCurrent" >&5 +$as_echo_n "checking for CFLocaleCopyCurrent... " >&6; } +if ${gt_cv_func_CFLocaleCopyCurrent+:} false; then : + $as_echo_n "(cached) " >&6 +else + gt_save_LIBS="$LIBS" + LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +CFLocaleCopyCurrent(); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gt_cv_func_CFLocaleCopyCurrent=yes +else + gt_cv_func_CFLocaleCopyCurrent=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$gt_save_LIBS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyCurrent" >&5 +$as_echo "$gt_cv_func_CFLocaleCopyCurrent" >&6; } + if test $gt_cv_func_CFLocaleCopyCurrent = yes; then + +$as_echo "#define HAVE_CFLOCALECOPYCURRENT 1" >>confdefs.h + + fi + INTL_MACOSX_LIBS= + if test $gt_cv_func_CFPreferencesCopyAppValue = yes || test $gt_cv_func_CFLocaleCopyCurrent = yes; then + INTL_MACOSX_LIBS="-Wl,-framework -Wl,CoreFoundation" + fi + + + + + + + LIBINTL= + LTLIBINTL= + POSUB= + + case " $gt_needs " in + *" need-formatstring-macros "*) gt_api_version=3 ;; + *" need-ngettext "*) gt_api_version=2 ;; + *) gt_api_version=1 ;; + esac + gt_func_gnugettext_libc="gt_cv_func_gnugettext${gt_api_version}_libc" + gt_func_gnugettext_libintl="gt_cv_func_gnugettext${gt_api_version}_libintl" + + if test "$USE_NLS" = "yes"; then + gt_use_preinstalled_gnugettext=no + + + if test $gt_api_version -ge 3; then + gt_revision_test_code=' +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +#define __GNU_GETTEXT_SUPPORTED_REVISION(major) ((major) == 0 ? 0 : -1) +#endif +typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; +' + else + gt_revision_test_code= + fi + if test $gt_api_version -ge 2; then + gt_expression_test_code=' + * ngettext ("", "", 0)' + else + gt_expression_test_code= + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libc" >&5 +$as_echo_n "checking for GNU gettext in libc... " >&6; } +if eval \${$gt_func_gnugettext_libc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +extern int _nl_msg_cat_cntr; +extern int *_nl_domain_bindings; +#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_domain_bindings) +#else +#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 +#endif +$gt_revision_test_code + +int +main () +{ + +bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + eval "$gt_func_gnugettext_libc=yes" +else + eval "$gt_func_gnugettext_libc=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$gt_func_gnugettext_libc + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then + + + + + + am_save_CPPFLAGS="$CPPFLAGS" + + for element in $INCICONV; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 +$as_echo_n "checking for iconv... " >&6; } +if ${am_cv_func_iconv+:} false; then : + $as_echo_n "(cached) " >&6 +else + + am_cv_func_iconv="no, consider installing GNU libiconv" + am_cv_lib_iconv=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "$am_cv_func_iconv" != yes; then + am_save_LIBS="$LIBS" + LIBS="$LIBS $LIBICONV" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +int +main () +{ +iconv_t cd = iconv_open("",""); + iconv(cd,NULL,NULL,NULL,NULL); + iconv_close(cd); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + am_cv_lib_iconv=yes + am_cv_func_iconv=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$am_save_LIBS" + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 +$as_echo "$am_cv_func_iconv" >&6; } + if test "$am_cv_func_iconv" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working iconv" >&5 +$as_echo_n "checking for working iconv... " >&6; } +if ${am_cv_func_iconv_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + + am_save_LIBS="$LIBS" + if test $am_cv_lib_iconv = yes; then + LIBS="$LIBS $LIBICONV" + fi + am_cv_func_iconv_works=no + for ac_iconv_const in '' 'const'; do + if test "$cross_compiling" = yes; then : + case "$host_os" in + aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; + *) am_cv_func_iconv_works="guessing yes" ;; + esac +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +#ifndef ICONV_CONST +# define ICONV_CONST $ac_iconv_const +#endif + +int +main () +{ +int result = 0; + /* Test against AIX 5.1 bug: Failures are not distinguishable from successful + returns. */ + { + iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); + if (cd_utf8_to_88591 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\342\202\254"; /* EURO SIGN */ + char buf[10]; + ICONV_CONST char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_utf8_to_88591, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + result |= 1; + iconv_close (cd_utf8_to_88591); + } + } + /* Test against Solaris 10 bug: Failures are not distinguishable from + successful returns. */ + { + iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); + if (cd_ascii_to_88591 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\263"; + char buf[10]; + ICONV_CONST char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_ascii_to_88591, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res == 0) + result |= 2; + iconv_close (cd_ascii_to_88591); + } + } + /* Test against AIX 6.1..7.1 bug: Buffer overrun. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\304"; + static char buf[2] = { (char)0xDE, (char)0xAD }; + ICONV_CONST char *inptr = input; + size_t inbytesleft = 1; + char *outptr = buf; + size_t outbytesleft = 1; + size_t res = iconv (cd_88591_to_utf8, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) + result |= 4; + iconv_close (cd_88591_to_utf8); + } + } +#if 0 /* This bug could be worked around by the caller. */ + /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ + { + iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); + if (cd_88591_to_utf8 != (iconv_t)(-1)) + { + static ICONV_CONST char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; + char buf[50]; + ICONV_CONST char *inptr = input; + size_t inbytesleft = strlen (input); + char *outptr = buf; + size_t outbytesleft = sizeof (buf); + size_t res = iconv (cd_88591_to_utf8, + &inptr, &inbytesleft, + &outptr, &outbytesleft); + if ((int)res > 0) + result |= 8; + iconv_close (cd_88591_to_utf8); + } + } +#endif + /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is + provided. */ + if (/* Try standardized names. */ + iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) + /* Try IRIX, OSF/1 names. */ + && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) + /* Try AIX names. */ + && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) + /* Try HP-UX names. */ + && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) + result |= 16; + return result; + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_run "$LINENO"; then : + am_cv_func_iconv_works=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + test "$am_cv_func_iconv_works" = no || break + done + LIBS="$am_save_LIBS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv_works" >&5 +$as_echo "$am_cv_func_iconv_works" >&6; } + case "$am_cv_func_iconv_works" in + *no) am_func_iconv=no am_cv_lib_iconv=no ;; + *) am_func_iconv=yes ;; + esac + else + am_func_iconv=no am_cv_lib_iconv=no + fi + if test "$am_func_iconv" = yes; then + +$as_echo "#define HAVE_ICONV 1" >>confdefs.h + + fi + if test "$am_cv_lib_iconv" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 +$as_echo_n "checking how to link with libiconv... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 +$as_echo "$LIBICONV" >&6; } + else + CPPFLAGS="$am_save_CPPFLAGS" + LIBICONV= + LTLIBICONV= + fi + + + + + + + + + + + + use_additional=yes + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + +# Check whether --with-libintl-prefix was given. +if test "${with_libintl_prefix+set}" = set; then : + withval=$with_libintl_prefix; + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + else + additional_includedir="$withval/include" + additional_libdir="$withval/$acl_libdirstem" + if test "$acl_libdirstem2" != "$acl_libdirstem" \ + && ! test -d "$withval/$acl_libdirstem"; then + additional_libdir="$withval/$acl_libdirstem2" + fi + fi + fi + +fi + + LIBINTL= + LTLIBINTL= + INCINTL= + LIBINTL_PREFIX= + HAVE_LIBINTL= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='intl ' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIBINTL="${LIBINTL}${LIBINTL:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$value" + else + : + fi + else + found_dir= + found_la= + found_so= + found_a= + eval libname=\"$acl_libname_spec\" # typically: libname=lib$name + if test -n "$acl_shlibext"; then + shrext=".$acl_shlibext" # typically: shrext=.so + else + shrext= + fi + if test $use_additional = yes; then + dir="$additional_libdir" + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIBINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$acl_shlibext"; then + if test -f "$dir/$libname$shrext"; then + found_dir="$dir" + found_so="$dir/$libname$shrext" + else + if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then + ver=`(cd "$dir" && \ + for f in "$libname$shrext".*; do echo "$f"; done \ + | sed -e "s,^$libname$shrext\\\\.,," \ + | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ + | sed 1q ) 2>/dev/null` + if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then + found_dir="$dir" + found_so="$dir/$libname$shrext.$ver" + fi + else + eval library_names=\"$acl_library_names_spec\" + for f in $library_names; do + if test -f "$dir/$f"; then + found_dir="$dir" + found_so="$dir/$f" + break + fi + done + fi + fi + fi + if test "X$found_dir" = "X"; then + if test -f "$dir/$libname.$acl_libext"; then + found_dir="$dir" + found_a="$dir/$libname.$acl_libext" + fi + fi + if test "X$found_dir" != "X"; then + if test -f "$dir/$libname.la"; then + found_la="$dir/$libname.la" + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + if test "$enable_rpath" = no \ + || test "X$found_dir" = "X/usr/$acl_libdirstem" \ + || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" + else + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + if test "$acl_hardcode_direct" = yes; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" + else + if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + haveit= + for x in $LDFLAGS $LIBINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir" + fi + if test "$acl_hardcode_minus_L" != no; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_so" + else + LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + LIBINTL="${LIBINTL}${LIBINTL:+ }$found_a" + else + LIBINTL="${LIBINTL}${LIBINTL:+ }-L$found_dir -l$name" + fi + fi + additional_includedir= + case "$found_dir" in + */$acl_libdirstem | */$acl_libdirstem/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` + if test "$name" = 'intl'; then + LIBINTL_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + */$acl_libdirstem2 | */$acl_libdirstem2/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` + if test "$name" = 'intl'; then + LIBINTL_PREFIX="$basedir" + fi + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INCINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + INCINTL="${INCINTL}${INCINTL:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + if test -n "$found_la"; then + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ + && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ + || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then + if test -n "$GCC"; then + case $host_os in + linux* | gnu* | k*bsd*-gnu) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIBINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LIBINTL="${LIBINTL}${LIBINTL:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIBINTL; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + LIBINTL="${LIBINTL}${LIBINTL:+ }$dep" + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }$dep" + ;; + esac + done + fi + else + LIBINTL="${LIBINTL}${LIBINTL:+ }-l$name" + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$acl_hardcode_libdir_separator"; then + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" + done + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBINTL="${LIBINTL}${LIBINTL:+ }$flag" + else + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$acl_hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIBINTL="${LIBINTL}${LIBINTL:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + for found_dir in $ltrpathdirs; do + LTLIBINTL="${LTLIBINTL}${LTLIBINTL:+ }-R$found_dir" + done + fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libintl" >&5 +$as_echo_n "checking for GNU gettext in libintl... " >&6; } +if eval \${$gt_func_gnugettext_libintl+:} false; then : + $as_echo_n "(cached) " >&6 +else + gt_save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $INCINTL" + gt_save_LIBS="$LIBS" + LIBS="$LIBS $LIBINTL" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *); +#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) +#else +#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 +#endif +$gt_revision_test_code + +int +main () +{ + +bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + eval "$gt_func_gnugettext_libintl=yes" +else + eval "$gt_func_gnugettext_libintl=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" != yes; } && test -n "$LIBICONV"; then + LIBS="$LIBS $LIBICONV" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +extern int _nl_msg_cat_cntr; +extern +#ifdef __cplusplus +"C" +#endif +const char *_nl_expand_alias (const char *); +#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) +#else +#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 +#endif +$gt_revision_test_code + +int +main () +{ + +bindtextdomain ("", ""); +return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + LIBINTL="$LIBINTL $LIBICONV" + LTLIBINTL="$LTLIBINTL $LTLIBICONV" + eval "$gt_func_gnugettext_libintl=yes" + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + fi + CPPFLAGS="$gt_save_CPPFLAGS" + LIBS="$gt_save_LIBS" +fi +eval ac_res=\$$gt_func_gnugettext_libintl + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + fi + + if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ + || { { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; } \ + && test "$PACKAGE" != gettext-runtime \ + && test "$PACKAGE" != gettext-tools; }; then + gt_use_preinstalled_gnugettext=yes + else + LIBINTL= + LTLIBINTL= + INCINTL= + fi + + + + if test -n "$INTL_MACOSX_LIBS"; then + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + LIBINTL="$LIBINTL $INTL_MACOSX_LIBS" + LTLIBINTL="$LTLIBINTL $INTL_MACOSX_LIBS" + fi + fi + + if test "$gt_use_preinstalled_gnugettext" = "yes" \ + || test "$nls_cv_use_gnu_gettext" = "yes"; then + +$as_echo "#define ENABLE_NLS 1" >>confdefs.h + + else + USE_NLS=no + fi + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use NLS" >&5 +$as_echo_n "checking whether to use NLS... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 +$as_echo "$USE_NLS" >&6; } + if test "$USE_NLS" = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking where the gettext function comes from" >&5 +$as_echo_n "checking where the gettext function comes from... " >&6; } + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + gt_source="external libintl" + else + gt_source="libc" + fi + else + gt_source="included intl directory" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gt_source" >&5 +$as_echo "$gt_source" >&6; } + fi + + if test "$USE_NLS" = "yes"; then + + if test "$gt_use_preinstalled_gnugettext" = "yes"; then + if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libintl" >&5 +$as_echo_n "checking how to link with libintl... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBINTL" >&5 +$as_echo "$LIBINTL" >&6; } + + for element in $INCINTL; do + haveit= + for x in $CPPFLAGS; do + + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + eval x=\"$x\" + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" + + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" + fi + done + + fi + + +$as_echo "#define HAVE_GETTEXT 1" >>confdefs.h + + +$as_echo "#define HAVE_DCGETTEXT 1" >>confdefs.h + + fi + + POSUB=po + fi + + + + INTLLIBS="$LIBINTL" + + + + + + + if test "$USE_NLS" = "yes"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: Enabling language support with gettext" >&5 +$as_echo "$as_me: Enabling language support with gettext" >&6;} + + # Turn the .po files into .mo files + $MAKE -C locale | tee -a config-build.log 2>&1 + + # Note: BOUT_LOCALE_PATH is defined in make.config, and may be changed by `make install`. + CXXFLAGS="$CXXFLAGS -DBOUT_HAS_GETTEXT -DBOUT_LOCALE_PATH=\$(BOUT_LOCALE_PATH)" + + EXTRA_LIBS="$EXTRA_LIBS $LIBINTL" + + # Set variable substituted into bout-config + HAS_NLS="yes" + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: Language support with gettext not available" >&5 +$as_echo "$as_me: Language support with gettext not available" >&6;} + +fi + +fi + +############################################################# +# Check environment +############################################################# + +if test "$CXXINCLUDE" != ""; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: ================================================" >&5 +$as_echo "$as_me: ================================================" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: CXXINCLUDE environment variable set to:" >&5 +$as_echo "$as_me: WARNING: CXXINCLUDE environment variable set to:" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: $CXXINCLUDE" >&5 +$as_echo "$as_me: $CXXINCLUDE" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: => This will be added to compile commands" >&5 +$as_echo "$as_me: => This will be added to compile commands" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: If this is not intended, then run" >&5 +$as_echo "$as_me: If this is not intended, then run" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: export CXXINCLUDE=''" >&5 +$as_echo "$as_me: export CXXINCLUDE=''" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: before making BOUT++" >&5 +$as_echo "$as_me: before making BOUT++" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: ================================================" >&5 +$as_echo "$as_me: ================================================" >&6;} + +fi + +############################################################# +# Gather configuration info for bout-config +############################################################# + +EXTRA_INCS="${EXTRA_INCS} ${CPPFLAGS}" + +PREFIX=$PWD +IDLCONFIGPATH=$PWD/tools/idllib +PYTHONCONFIGPATH=$PWD/tools/pylib + +HAS_IDA="yes" +if test "$IDALIBS" = "" +then + HAS_IDA="no" +fi + +HAS_CVODE="yes" +if test "$CVODELIBS" = "" +then + HAS_CVODE="no" +fi + +HAS_ARKODE="yes" +if test "$ARKODELIBS" = "" +then + HAS_ARKODE="no" +fi + +HAS_NETCDF="yes" +if test "$NCPATH" = "" +then + HAS_NETCDF="no" +fi + +HAS_PNETCDF="yes" +if test "$PNCPATH" = "" +then + HAS_PNETCDF="no" +fi + +HAS_MUMPS="yes" +if test "$MUMPS" = "" +then + HAS_MUMPS="no" +fi + +# Only make.config is altered by configure +ac_config_files="$ac_config_files make.config" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${CODE_COVERAGE_ENABLED_TRUE}" && test -z "${CODE_COVERAGE_ENABLED_FALSE}"; then + as_fn_error $? "conditional \"CODE_COVERAGE_ENABLED\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} @@ -12748,6 +14975,7 @@ esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" +config_commands="$ac_config_commands" _ACEOF @@ -12772,6 +15000,9 @@ Usage: $0 [OPTION]... [TAG]... Configuration files: $config_files +Configuration commands: +$config_commands + Report bugs to ." _ACEOF @@ -12883,6 +15114,17 @@ _ASBOX _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +# Capture the value of obsolete ALL_LINGUAS because we need it to compute + # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it + # from automake < 1.5. + eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' + # Capture the value of LINGUAS because we need it to compute CATALOGS. + LINGUAS="${LINGUAS-%UNSET%}" + + _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 @@ -12891,6 +15133,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 for ac_config_target in $ac_config_targets do case $ac_config_target in + "po-directories") CONFIG_COMMANDS="$CONFIG_COMMANDS po-directories" ;; "make.config") CONFIG_FILES="$CONFIG_FILES make.config" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; @@ -12904,6 +15147,7 @@ done # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree @@ -13092,7 +15336,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" -eval set X " :F $CONFIG_FILES " +eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" shift for ac_tag do @@ -13313,9 +15557,129 @@ which seems to be undefined. Please make sure it is defined" >&2;} ;; - + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; esac + + case $ac_file$ac_mode in + "po-directories":C) + for ac_file in $CONFIG_FILES; do + # Support "outfile[:infile[:infile...]]" + case "$ac_file" in + *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + esac + # PO directories have a Makefile.in generated from Makefile.in.in. + case "$ac_file" in */Makefile.in) + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix=/`echo "$ac_dir"|sed 's%^\./%%'` + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + # Treat a directory as a PO directory if and only if it has a + # POTFILES.in file. This allows packages to have multiple PO + # directories under different names or in different locations. + if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then + rm -f "$ac_dir/POTFILES" + test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + gt_tab=`printf '\t'` + cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ${gt_tab}]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" + POMAKEFILEDEPS="POTFILES.in" + # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend + # on $ac_dir but don't depend on user-specified configuration + # parameters. + if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then + # The LINGUAS file contains the set of available languages. + if test -n "$OBSOLETE_ALL_LINGUAS"; then + test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" + fi + ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` + # Hide the ALL_LINGUAS assignment from automake < 1.5. + eval 'ALL_LINGUAS''=$ALL_LINGUAS_' + POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" + else + # The set of available languages was given in configure.in. + # Hide the ALL_LINGUAS assignment from automake < 1.5. + eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' + fi + # Compute POFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) + # Compute UPDATEPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) + # Compute DUMMYPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) + # Compute GMOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) + case "$ac_given_srcdir" in + .) srcdirpre= ;; + *) srcdirpre='$(srcdir)/' ;; + esac + POFILES= + UPDATEPOFILES= + DUMMYPOFILES= + GMOFILES= + for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + done + # CATALOGS depends on both $ac_dir and the user's LINGUAS + # environment variable. + INST_LINGUAS= + if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done + fi + CATALOGS= + if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + done + fi + test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" + for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do + if test -f "$f"; then + case "$f" in + *.orig | *.bak | *~) ;; + *) cat "$f" >> "$ac_dir/Makefile" ;; + esac + fi + done + fi + ;; + esac + done ;; + + esac done # for ac_tag @@ -13403,6 +15767,7 @@ BOUT_INCLUDE_PATH=$PWD/include + ac_config_files="$ac_config_files bin/bout-config" @@ -13976,6 +16341,7 @@ esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" +config_commands="$ac_config_commands" _ACEOF @@ -14000,6 +16366,9 @@ Usage: $0 [OPTION]... [TAG]... Configuration files: $config_files +Configuration commands: +$config_commands + Report bugs to ." _ACEOF @@ -14111,6 +16480,17 @@ _ASBOX _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +# Capture the value of obsolete ALL_LINGUAS because we need it to compute + # POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES, CATALOGS. But hide it + # from automake < 1.5. + eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' + # Capture the value of LINGUAS because we need it to compute CATALOGS. + LINGUAS="${LINGUAS-%UNSET%}" + + _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 @@ -14119,6 +16499,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 for ac_config_target in $ac_config_targets do case $ac_config_target in + "po-directories") CONFIG_COMMANDS="$CONFIG_COMMANDS po-directories" ;; "make.config") CONFIG_FILES="$CONFIG_FILES make.config" ;; "bin/bout-config") CONFIG_FILES="$CONFIG_FILES bin/bout-config" ;; @@ -14133,6 +16514,7 @@ done # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree @@ -14321,7 +16703,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" -eval set X " :F $CONFIG_FILES " +eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" shift for ac_tag do @@ -14542,9 +16924,129 @@ which seems to be undefined. Please make sure it is defined" >&2;} ;; - + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; esac + + case $ac_file$ac_mode in + "po-directories":C) + for ac_file in $CONFIG_FILES; do + # Support "outfile[:infile[:infile...]]" + case "$ac_file" in + *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + esac + # PO directories have a Makefile.in generated from Makefile.in.in. + case "$ac_file" in */Makefile.in) + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix=/`echo "$ac_dir"|sed 's%^\./%%'` + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + # Treat a directory as a PO directory if and only if it has a + # POTFILES.in file. This allows packages to have multiple PO + # directories under different names or in different locations. + if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then + rm -f "$ac_dir/POTFILES" + test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + gt_tab=`printf '\t'` + cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ${gt_tab}]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" + POMAKEFILEDEPS="POTFILES.in" + # ALL_LINGUAS, POFILES, UPDATEPOFILES, DUMMYPOFILES, GMOFILES depend + # on $ac_dir but don't depend on user-specified configuration + # parameters. + if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then + # The LINGUAS file contains the set of available languages. + if test -n "$OBSOLETE_ALL_LINGUAS"; then + test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" + fi + ALL_LINGUAS_=`sed -e "/^#/d" -e "s/#.*//" "$ac_given_srcdir/$ac_dir/LINGUAS"` + # Hide the ALL_LINGUAS assignment from automake < 1.5. + eval 'ALL_LINGUAS''=$ALL_LINGUAS_' + POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" + else + # The set of available languages was given in configure.in. + # Hide the ALL_LINGUAS assignment from automake < 1.5. + eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' + fi + # Compute POFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).po) + # Compute UPDATEPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).po-update) + # Compute DUMMYPOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(lang).nop) + # Compute GMOFILES + # as $(foreach lang, $(ALL_LINGUAS), $(srcdir)/$(lang).gmo) + case "$ac_given_srcdir" in + .) srcdirpre= ;; + *) srcdirpre='$(srcdir)/' ;; + esac + POFILES= + UPDATEPOFILES= + DUMMYPOFILES= + GMOFILES= + for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + done + # CATALOGS depends on both $ac_dir and the user's LINGUAS + # environment variable. + INST_LINGUAS= + if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done + fi + CATALOGS= + if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + done + fi + test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" + for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do + if test -f "$f"; then + case "$f" in + *.orig | *.bak | *~) ;; + *) cat "$f" >> "$ac_dir/Makefile" ;; + esac + fi + done + fi + ;; + esac + done ;; + + esac done # for ac_tag @@ -14618,6 +17120,8 @@ $as_echo "$as_me: Lapack support : $HAS_LAPACK" >&6;} $as_echo "$as_me: Scorep support : $HAS_SCOREP" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: OpenMP support : $HAS_OPENMP (schedule: $OPENMP_SCHEDULE)" >&5 $as_echo "$as_me: OpenMP support : $HAS_OPENMP (schedule: $OPENMP_SCHEDULE)" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Natural language support: $HAS_NLS" >&5 +$as_echo "$as_me: Natural language support: $HAS_NLS" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: " >&5 $as_echo "$as_me: " >&6;} diff --git a/configure.ac b/configure.ac index b68f1110d3..8e75493b7d 100644 --- a/configure.ac +++ b/configure.ac @@ -91,8 +91,8 @@ AC_ARG_WITH(openmp_schedule,[AS_HELP_STRING([--with-openmp-schedule=static], [Set OpenMP schedule (default: static)])],,[with_openmp_schedule=static]) AC_ARG_ENABLE(pvode_openmp, [AS_HELP_STRING([--enable-pvode-openmp], [Enable building PVODE with OpenMP support])],,[enable_pvode_openmp=no]) -AC_ARG_ENABLE(gettext, [AS_HELP_STRING([--enable-gettext], - [Enable localisation (i18n) with gettext])],,[enable_gettext=no]) +AC_ARG_ENABLE(nls, [AS_HELP_STRING([--enable-nls], + [Enable Natural Language Support with gettext])],,[enable_nls=no]) AC_ARG_VAR(EXTRA_INCS,[Extra compile flags]) AC_ARG_VAR(EXTRA_LIBS,[Extra linking flags]) @@ -1136,9 +1136,30 @@ AS_IF([test "$with_pvode" != "no"], [ # Localisation (i18n) with gettext ############################################################# -AS_IF([test "$enable_gettext" != "no" ], [ - # Note: BOUT_LOCALE_PATH is defined in make.config, and may be changed by `make install`. - CXXFLAGS="$CXXFLAGS -DBOUT_HAS_GETTEXT -DBOUT_LOCALE_PATH=\$(BOUT_LOCALE_PATH)" +HAS_NLS="no" +AS_IF([test "$enable_nls" != "no" ], [ + # Use macro to test if Natural Language Support (gettext) is available. + # If available sets: + # - USE_NLS to "yes" + # - LIBINTL to the linker options + # - Modifies CPPFLAGS if needed + AM_GNU_GETTEXT([external]) + AS_IF([test "$USE_NLS" = "yes"], [ + AC_MSG_NOTICE([Enabling language support with gettext]) + + # Turn the .po files into .mo files + $MAKE -C locale | tee -a config-build.log 2>&1 + + # Note: BOUT_LOCALE_PATH is defined in make.config, and may be changed by `make install`. + CXXFLAGS="$CXXFLAGS -DBOUT_HAS_GETTEXT -DBOUT_LOCALE_PATH=\$(BOUT_LOCALE_PATH)" + + EXTRA_LIBS="$EXTRA_LIBS $LIBINTL" + + # Set variable substituted into bout-config + HAS_NLS="yes" + ],[ + AC_MSG_NOTICE([Language support with gettext not available]) + ]) ]) ############################################################# @@ -1257,6 +1278,7 @@ AC_SUBST(SLEPC_MAKE_INCLUDE) AC_SUBST(SLEPC_DIR) AC_SUBST(SLEPC_ARCH) AC_SUBST(HAS_OPENMP) +AC_SUBST(HAS_NLS) AC_CONFIG_FILES([bin/bout-config]) AC_OUTPUT @@ -1282,6 +1304,7 @@ AC_MSG_NOTICE([ MUMPS support : $HAS_MUMPS]) AC_MSG_NOTICE([ Lapack support : $HAS_LAPACK]) AC_MSG_NOTICE([ Scorep support : $HAS_SCOREP]) AC_MSG_NOTICE([ OpenMP support : $HAS_OPENMP (schedule: $OPENMP_SCHEDULE)]) +AC_MSG_NOTICE([ Natural language support: $HAS_NLS]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([-------------------------------]) diff --git a/locale/libbout.pot b/locale/libbout.pot index 6ca192dc2f..e5f2c60474 100644 --- a/locale/libbout.pot +++ b/locale/libbout.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-23 00:03+0100\n" +"POT-Creation-Date: 2018-10-25 23:40+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,89 +17,172 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: src/bout++.cxx:365 +#: ../src/bout++.cxx:370 msgid "\tChecking disabled\n" msgstr "" -#: src/bout++.cxx:363 +#: ../src/bout++.cxx:368 #, c-format msgid "\tChecking enabled, level %d\n" msgstr "" -#: src/sys/options.cxx:96 src/sys/options.cxx:136 src/sys/options.cxx:171 -#: src/sys/options.cxx:199 src/sys/options.cxx:220 src/sys/options.cxx:223 +#: ../src/mesh/impls/bout/boutmesh.cxx:390 +#, c-format +msgid "" +"\tDomain split (NXPE=%d, NYPE=%d) into domains (localNx=%d, localNy=%d)\n" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:415 +#, c-format +msgid "\tERROR: Cannot split %d Y points equally between %d processors\n" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:127 +msgid "\tGrid size: " +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:143 +msgid "\tGuard cells (x,y): " +msgstr "" + +#. Mark the option as used +#. Option not found +#: ../src/sys/options.cxx:96 ../src/sys/options.cxx:136 +#: ../src/sys/options.cxx:171 ../src/sys/options.cxx:199 +#: ../src/sys/options.cxx:220 ../src/sys/options.cxx:223 +#: ../include/options.hxx:298 ../include/options.hxx:319 msgid "\tOption " msgstr "" -#: src/bout++.cxx:371 +#: ../src/mesh/impls/bout/boutmesh.cxx:124 +msgid "\tRead nz from input grid file\n" +msgstr "" + +#: ../src/bout++.cxx:376 msgid "\tSignal handling disabled\n" msgstr "" -#: src/bout++.cxx:369 +#: ../src/bout++.cxx:374 msgid "\tSignal handling enabled\n" msgstr "" -#: src/solver/solver.cxx:563 +#: ../src/mesh/impls/bout/boutmesh.cxx:842 +msgid "\tdone\n" +msgstr "" + +#: ../src/solver/solver.cxx:563 #, c-format msgid "" "\n" "Run finished at : %s\n" msgstr "" -#: src/solver/solver.cxx:534 +#: ../src/solver/solver.cxx:534 #, c-format msgid "" "\n" "Run started at : %s\n" msgstr "" -#: src/bout++.cxx:350 +#: ../src/mesh/impls/bout/boutmesh.cxx:827 +msgid "Boundary regions in this processor: " +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:406 +#, c-format +msgid "Cannot split %d X points equally between %d processors\n" +msgstr "" + +#: ../src/bout++.cxx:355 #, c-format msgid "" "Code compiled on %s at %s\n" "\n" msgstr "" -#: src/bout++.cxx:256 +#: ../src/mesh/impls/bout/boutmesh.cxx:836 +msgid "Constructing default regions" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:384 +msgid "" +"Could not find a valid value for NXPE. Try a different number of processors." +msgstr "" + +#: ../src/bout++.cxx:261 #, c-format msgid "DataDir \"%s\" does not exist or is not accessible\n" msgstr "" -#: src/bout++.cxx:253 +#: ../src/bout++.cxx:258 #, c-format msgid "DataDir \"%s\" is not a directory\n" msgstr "" -#: src/bout++.cxx:424 +#: ../src/bout++.cxx:429 msgid "Error encountered during initialisation\n" msgstr "" -#: src/bout++.cxx:469 +#: ../src/bout++.cxx:474 #, c-format msgid "Error encountered during initialisation: %s\n" msgstr "" -#: src/solver/solver.cxx:526 +#: ../src/mesh/impls/bout/boutmesh.cxx:147 +#, c-format +msgid "Error: nx must be greater than 2 times MXG (2 * %d)" +msgstr "" + +#: ../src/solver/solver.cxx:526 msgid "Failed to initialise solver-> Aborting\n" msgstr "" -#: src/solver/solver.cxx:564 +#: ../tests/integrated/test-i18n/test-i18n.cxx:15 +msgid "Hello World\n" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:91 +msgid "Loading mesh" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:106 +msgid "Mesh must contain nx" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:109 +msgid "Mesh must contain ny" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:833 +msgid "No boundary regions in this processor" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:234 +#, c-format +msgid "Number of processors (%d) not divisible by NPs in x direction (%d)\n" +msgstr "" + +#: ../src/solver/solver.cxx:564 msgid "Run time : " msgstr "" #. / Run the solver -#: src/solver/solver.cxx:531 +#: ../src/solver/solver.cxx:531 msgid "" "Running simulation\n" "\n" msgstr "" -#: src/solver/solver.cxx:521 +#: ../src/solver/solver.cxx:521 #, c-format msgid "Solver running for %d outputs with monitor timestep of %e\n" msgstr "" -#: src/solver/solver.cxx:519 +#: ../src/solver/solver.cxx:519 #, c-format msgid "Solver running for %d outputs with output timestep of %e\n" msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:156 +msgid "nx must be greater than 2*MXG" +msgstr "" diff --git a/locale/makefile b/locale/makefile new file mode 100644 index 0000000000..99d6570c25 --- /dev/null +++ b/locale/makefile @@ -0,0 +1,41 @@ +###################################################################### +# Internationalisation +###################################################################### + +# List of supported locales +LANGUAGES = fr zh_TW zh_CN + +# This target is the most commonly used, to build all the .mo files +.PHONY: locale +locale: $(LANGUAGES:%=%/LC_MESSAGES/libbout.mo) + +# Update all .po files. Note that they will then need manually +# editing to fill in (or delete) missing translations. +.PHONY: po-all +all-po: $(LANGUAGES:%=%/libbout.po) + +# Create the template file, combining all source files +libbout.pot: FORCE + xgettext --keyword=_ --language=c++ --add-comments --sort-output -o $@ `find ../ -name "*.[ch]xx"` + +# Update a .po file +%/libbout.po: libbout.pot + msgmerge --update $@ $< + +# Update a .mo file, ensuring that the directory exists +# Note: Because the .po files must be updated manually, +# don't automatically generate the .po files +%/LC_MESSAGES/libbout.mo: FORCE + @mkdir -p $(@D) + msgfmt --output-file=$@ $*/libbout.po + +# Shortcut target for building single language +# e.g. "make po-fr" +# Note: invoking make since otherwise the intermediate file is deleted +po-%: + $(MAKE) $*/libbout.po +mo-%: + $(MAKE) $*/LC_MESSAGES/libbout.mo + +# Dummy target to force rules to be run +FORCE: diff --git a/makefile b/makefile index da332cf410..12e2fa183f 100644 --- a/makefile +++ b/makefile @@ -69,34 +69,7 @@ build-check-integrated-tests: libfast build-check: build-check-integrated-tests build-check-mms-tests build-check-unit-tests -###################################################################### -# Internationalisation -###################################################################### - -# Create the template file, combining all source files -locale/libbout.pot: src/bout++.cxx - xgettext --keyword=_ --language=c++ --add-comments --sort-output -o $@ `find src/ -name "*.cxx"` - -# Update a .po file -locale/%/libbout.po: locale/libbout.pot - msgmerge --update $@ $< - -# Update a .mo file -# First ensure that the directory exists -locale/%/LC_MESSAGES/libbout.mo: locale/%/libbout.po - @mkdir -p $(@D) - msgfmt --output-file=$@ $< - -# Shortcut target for building single language -# Note: invoking make since otherwise the intermediate file is deleted -locale-po-%: - $(MAKE) locale/$*/libbout.po -locale-mo-%: - $(MAKE) locale/$*/LC_MESSAGES/libbout.mo - -# Build all locales -LANGUAGES = fr zh_TW zh_CN - -.PHONY: locale-po locale-mo -locale-po: $(LANGUAGES:%=locale/%/libbout.po) -locale-mo: $(LANGUAGES:%=locale/%/LC_MESSAGES/libbout.mo) +# Build the .mo files needed for Natural Language Support (gettext) +.PHONY: locale +locale: + $(MAKE) -C locale From 8b11ba96ab14de8c52c64eaed4042224a5a0671b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Oct 2018 14:29:01 +0100 Subject: [PATCH 0129/1783] Cleanly separate BoutException message from backtrace Mixing the backtrace and the message causes problems with tests. Backtrace functionality is still present, but moved into `BoutException::getBacktrace`. BOUTMAIN now calls that instead of `what()` so that physics models still print a backtrace if it is available. --- include/bout/physicsmodel.hxx | 4 +- include/boutexception.hxx | 27 +++++++------ src/sys/boutexception.cxx | 56 ++++++--------------------- tests/unit/sys/test_boutexception.cxx | 32 +++++++++++---- 4 files changed, 55 insertions(+), 64 deletions(-) diff --git a/include/bout/physicsmodel.hxx b/include/bout/physicsmodel.hxx index d41a81890d..6e98ecebbf 100644 --- a/include/bout/physicsmodel.hxx +++ b/include/bout/physicsmodel.hxx @@ -315,9 +315,9 @@ private: delete model; \ delete solver; \ delete bout_monitor; \ - }catch (BoutException &e) { \ + } catch (const BoutException &e) { \ output << "Error encountered\n"; \ - output << e.what() << endl; \ + output << e.getBacktrace() << endl; \ MPI_Abort(BoutComm::get(), 1); \ } \ BoutFinalise(); \ diff --git a/include/boutexception.hxx b/include/boutexception.hxx index 40316f5dd0..029bc4d19a 100644 --- a/include/boutexception.hxx +++ b/include/boutexception.hxx @@ -7,6 +7,7 @@ class BoutException; #include #include +#include "bout/deprecated.hxx" using std::string; /// Throw BoutRhsFail with \p message if any one process has non-zero @@ -16,24 +17,28 @@ void BoutParallelThrowRhsFail(int status, const char* message); class BoutException : public std::exception { public: BoutException(const char *, ...); - BoutException(const std::string&); + BoutException(std::string msg) : message(std::move(msg)) {} ~BoutException() override; - const char* what() const noexcept override; - void Backtrace(); + const char* what() const noexcept override { + return message.c_str(); + } + void DEPRECATED(Backtrace()) {}; + + /// Return the exception message along with the MsgStack and + /// backtrace (if available) + std::string getBacktrace() const; + + const std::string header{"====== Exception thrown ======\n"}; + protected: char *buffer = nullptr; - static const int BUFFER_LEN = 1024; // Length of char buffer for printing + static constexpr int BUFFER_LEN = 1024; // Length of char buffer for printing int buflen; // Length of char buffer for printing - string message; + std::string message; #ifdef BACKTRACE - static const unsigned int TRACE_MAX = 128; - void *trace[TRACE_MAX]; - char **messages; - int trace_size; - mutable std::string _tmp; + static constexpr unsigned int TRACE_MAX = 128; #endif - std::string BacktraceGenerate() const; }; class BoutRhsFail : public BoutException { diff --git a/src/sys/boutexception.cxx b/src/sys/boutexception.cxx index b3f468a291..1416974bb7 100644 --- a/src/sys/boutexception.cxx +++ b/src/sys/boutexception.cxx @@ -29,35 +29,20 @@ BoutException::~BoutException() { } } -void BoutException::Backtrace() { -#if CHECK > 1 - /// Print out the message stack to help debugging - std::string tmp = msg_stack.getDump(); - message += tmp; -#else - message += "Enable checking (configure with --enable-check or set flag -DCHECK > 1) to " - "get a trace\n"; -#endif - +std::string BoutException::getBacktrace() const{ + std::string backtrace_message; #ifdef BACKTRACE - trace_size = backtrace(trace, TRACE_MAX); - messages = backtrace_symbols(trace, trace_size); - -#else // BACKTRACE - message += "Stacktrace not enabled.\n"; -#endif -} + void *trace[TRACE_MAX]; + auto trace_size = backtrace(trace, TRACE_MAX); + auto **messages = backtrace_symbols(trace, trace_size); -std::string BoutException::BacktraceGenerate() const{ - std::string message; -#ifdef BACKTRACE - // skip first stack frame (points here) - message = ("====== Exception path ======\n"); + backtrace_message = "====== Exception path ======\n"; char buf[1024]; + // skip first stack frame (points here) for (int i = 1; i < trace_size; ++i) { snprintf(buf, sizeof(buf) - 1, "[bt] #%d %s\n", i, messages[i]); - message += buf; + backtrace_message += buf; // find first occurence of '(' or ' ' in message[i] and assume // everything before that is the file name. (Don't go beyond 0 though // (string terminator) @@ -93,12 +78,14 @@ std::string BoutException::BacktraceGenerate() const{ } while (retstr != nullptr); int status = pclose(fp); if (status == 0) { - message += buf; + backtrace_message += buf; } } } +#else + backtrace_message = "Stacktrace not enabled.\n"; #endif - return message; + return header + message + "\n" + msg_stack.getDump() + backtrace_message; } /// Common set up for exceptions @@ -126,29 +113,10 @@ std::string BoutException::BacktraceGenerate() const{ delete[] buffer; \ buffer = nullptr; \ } \ - message = "====== Exception thrown ======\n" + message + "\n"; \ - \ - this->Backtrace(); \ } BoutException::BoutException(const char *s, ...) { INIT_EXCEPTION(s); } -BoutException::BoutException(const std::string &msg) { - message = "====== Exception thrown ======\n" + msg + "\n"; - - this->Backtrace(); -} - -const char *BoutException::what() const noexcept{ -#ifdef BACKTRACE - _tmp=message; - _tmp+=BacktraceGenerate(); - return _tmp.c_str(); -#else - return message.c_str(); -#endif -} - BoutRhsFail::BoutRhsFail(const char *s, ...) : BoutException::BoutException(nullptr) { INIT_EXCEPTION(s); } diff --git a/tests/unit/sys/test_boutexception.cxx b/tests/unit/sys/test_boutexception.cxx index 8d34141f15..842870baae 100644 --- a/tests/unit/sys/test_boutexception.cxx +++ b/tests/unit/sys/test_boutexception.cxx @@ -8,21 +8,39 @@ TEST(BoutExceptionTest, ThrowCorrect) { EXPECT_THROW(throw BoutException("test"), BoutException); } -TEST(BoutExceptionTest, WhatTest) { +TEST(BoutExceptionTest, What) { + std::string test_message{"Test message"}; try { - throw BoutException(std::string("Test message")); - } catch (BoutException &e) { - std::string message(e.what()); - EXPECT_NE(message.find("Test message"), std::string::npos); + throw BoutException(test_message); + } catch (const BoutException &e) { + EXPECT_EQ(e.what(), test_message); } try { throw BoutException("%s", "second"); - } catch (BoutException &e) { + } catch (const BoutException &e) { std::string message(e.what()); - EXPECT_NE(message.find("second"), std::string::npos); + EXPECT_EQ(message, "second"); } } + +TEST(BoutExceptionTest, GetBacktrace) { + std::string test_message{"Test message"}; + try { + throw BoutException(test_message); + } catch (const BoutException &e) { + std::string expected{"[bt] #1 ./serial_tests"}; +#ifdef BACKTRACE + // Should be able to find something about backtrace + EXPECT_NE(e.getBacktrace().find(expected), std::string::npos); +#else + // Should *not* be able to find something about backtrace + EXPECT_EQ(e.getBacktrace().find(expected), std::string::npos); +#endif + } +} + + TEST(BoutRhsFailTest, ThrowCorrect) { EXPECT_THROW(throw BoutRhsFail("RHS Fail test"), BoutRhsFail); } From 15f1dd35148714ee5fd316a45a6efcd3db00b0e6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Oct 2018 14:30:00 +0100 Subject: [PATCH 0130/1783] Clear the MsgStack in BoutException destructor If an exception is thrown while a TRACE is active, we won't clear up the msg_stack. We also won't know how many messages to pop, so just clear everything. This should make the unit tests less confusing if something goes wrong --- src/sys/boutexception.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sys/boutexception.cxx b/src/sys/boutexception.cxx index 1416974bb7..280a250c01 100644 --- a/src/sys/boutexception.cxx +++ b/src/sys/boutexception.cxx @@ -27,6 +27,10 @@ BoutException::~BoutException() { delete[] buffer; buffer = nullptr; } + // If an exception is thrown while a TRACE is active, we won't clear + // up the msg_stack. We also won't know how many messages to pop, so + // just clear everything + msg_stack.clear(); } std::string BoutException::getBacktrace() const{ From 2c26d398fb8ee4140c983ea8d712b112a8da68c2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Oct 2018 14:33:28 +0100 Subject: [PATCH 0131/1783] Improve the error message in SolverFactory::create --- include/bout/generic_factory.hxx | 2 +- include/bout/solverfactory.hxx | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/bout/generic_factory.hxx b/include/bout/generic_factory.hxx index cfc031a8eb..324b6f7f39 100644 --- a/include/bout/generic_factory.hxx +++ b/include/bout/generic_factory.hxx @@ -59,7 +59,7 @@ public: if (index != std::end(type_map)) { return index->second(std::forward(args) ...); } - throw BoutException("Could not find %s", name.c_str()); + throw BoutException("Could not find '%s'", name.c_str()); } /// List available types that can be created diff --git a/include/bout/solverfactory.hxx b/include/bout/solverfactory.hxx index 3085da6cb1..9b0041bbbd 100644 --- a/include/bout/solverfactory.hxx +++ b/include/bout/solverfactory.hxx @@ -28,10 +28,14 @@ class SolverFactory : public Factory> { Solver* createSolver(Options *options = nullptr); Solver* createSolver(SolverType &name) { - return create(name, Options::getRoot()->getSection("solver")); + return createSolver(name, Options::getRoot()->getSection("solver")); } Solver* createSolver(SolverType &name, Options *options) { - return create(name, options); + try { + return create(name, options); + } catch (const BoutException &e) { + throw BoutException("Error when trying to create a Solver: %s", e.what()); + } } private: SolverFactory() {} From 95df643149474ccb60c8639d7d8914b3c1c3ec6f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Oct 2018 16:07:15 +0100 Subject: [PATCH 0132/1783] Use auto instead of naming complicated iterator types --- src/field/field_data.cxx | 2 +- src/field/fieldgenerators.cxx | 2 +- src/field/fieldgenerators.hxx | 4 +-- src/mesh/boundary_factory.cxx | 9 +++---- src/mesh/boundary_standard.cxx | 31 ++++++++++++------------ src/solver/impls/imex-bdf2/imex-bdf2.cxx | 4 +-- src/sys/timer.cxx | 2 +- 7 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 6ab19709c7..597846a111 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -85,7 +85,7 @@ void FieldData::addBndryGenerator(FieldGeneratorPtr gen, BndryLoc location) { } FieldGeneratorPtr FieldData::getBndryGenerator(BndryLoc location) { - std::map::iterator it = bndry_generator.find(location); + auto it = bndry_generator.find(location); if(it == bndry_generator.end()) return nullptr; diff --git a/src/field/fieldgenerators.cxx b/src/field/fieldgenerators.cxx index f2d7ecf430..916d3605e5 100644 --- a/src/field/fieldgenerators.cxx +++ b/src/field/fieldgenerators.cxx @@ -253,7 +253,7 @@ FieldGeneratorPtr FieldTanhHat::clone(const list args) { // As lists are not meant to be indexed, we may use an iterator to get the // input arguments instead // Create the iterator - list::const_iterator it = args.begin(); + auto it = args.begin(); // Assign the input arguments to the input of the constructor and advance the // iterator FieldGeneratorPtr xin = *it; diff --git a/src/field/fieldgenerators.hxx b/src/field/fieldgenerators.hxx index 46fe4881b7..e94cb611de 100644 --- a/src/field/fieldgenerators.hxx +++ b/src/field/fieldgenerators.hxx @@ -219,7 +219,7 @@ public: return std::make_shared(args); } BoutReal generate(double x, double y, double z, double t) { - list::iterator it=input.begin(); + auto it = input.begin(); BoutReal result = (*it)->generate(x,y,z,t); for(;it != input.end(); it++) { BoutReal val = (*it)->generate(x,y,z,t); @@ -244,7 +244,7 @@ public: return std::make_shared(args); } BoutReal generate(double x, double y, double z, double t) { - list::iterator it=input.begin(); + auto it = input.begin(); BoutReal result = (*it)->generate(x,y,z,t); for(;it != input.end(); it++) { BoutReal val = (*it)->generate(x,y,z,t); diff --git a/src/mesh/boundary_factory.cxx b/src/mesh/boundary_factory.cxx index 86a617e2fd..bc9db98a84 100644 --- a/src/mesh/boundary_factory.cxx +++ b/src/mesh/boundary_factory.cxx @@ -342,24 +342,21 @@ void BoundaryFactory::addMod(BoundaryModifier* bmod, const char *name) { } BoundaryOp* BoundaryFactory::findBoundaryOp(const string &s) { - map::iterator it; - it = opmap.find(lowercase(s)); + auto it = opmap.find(lowercase(s)); if(it == opmap.end()) return nullptr; return it->second; } BoundaryModifier* BoundaryFactory::findBoundaryMod(const string &s) { - map::iterator it; - it = modmap.find(lowercase(s)); + auto it = modmap.find(lowercase(s)); if(it == modmap.end()) return nullptr; return it->second; } BoundaryOpPar* BoundaryFactory::findBoundaryOpPar(const string &s) { - map::iterator it; - it = par_opmap.find(lowercase(s)); + auto it = par_opmap.find(lowercase(s)); if(it == par_opmap.end()) return nullptr; return it->second; diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 44f910d74d..5d4d2773a1 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -2316,30 +2316,31 @@ void BoundaryNeumannPar::apply(Field3D &f) { BoundaryOp* BoundaryRobin::clone(BoundaryRegion *region, const list &args) { verifyNumPoints(region,1); BoutReal a = 0.5, b = 1.0, g = 0.; - - list::const_iterator it = args.begin(); - - if(it != args.end()) { + + auto it = args.begin(); + + if (it != args.end()) { // First argument is 'a' a = stringToReal(*it); it++; - - if(it != args.end()) { + + if (it != args.end()) { // Second is 'b' b = stringToReal(*it); it++; - - if(it != args.end()) { - // Third is 'g' - g = stringToReal(*it); - it++; - if(it != args.end()) { - output << "WARNING: BoundaryRobin takes maximum of 3 arguments. Ignoring extras\n"; - } + + if (it != args.end()) { + // Third is 'g' + g = stringToReal(*it); + it++; + if (it != args.end()) { + output + << "WARNING: BoundaryRobin takes maximum of 3 arguments. Ignoring extras\n"; + } } } } - + return new BoundaryRobin(region, a, b, g); } diff --git a/src/solver/impls/imex-bdf2/imex-bdf2.cxx b/src/solver/impls/imex-bdf2/imex-bdf2.cxx index 232d08abff..dfb0990319 100644 --- a/src/solver/impls/imex-bdf2/imex-bdf2.cxx +++ b/src/solver/impls/imex-bdf2/imex-bdf2.cxx @@ -1311,7 +1311,7 @@ PetscErrorCode IMEXBDF2::precon(Vec x, Vec f) { template< class Op > void IMEXBDF2::loopVars(BoutReal *u) { // Loop over 2D variables - for(vector< VarStr >::const_iterator it = f2d.begin(); it != f2d.end(); ++it) { + for(auto it = f2d.begin(); it != f2d.end(); ++it) { Op op(it->var, it->F_var); // Initialise the operator if(it->evolve_bndry) { @@ -1355,7 +1355,7 @@ void IMEXBDF2::loopVars(BoutReal *u) { } // Loop over 3D variables - for(vector< VarStr >::const_iterator it = f3d.begin(); it != f3d.end(); ++it) { + for(auto it = f3d.begin(); it != f3d.end(); ++it) { Op op(it->var, it->F_var); // Initialise the operator if(it->evolve_bndry) { // Include boundary regions diff --git a/src/sys/timer.cxx b/src/sys/timer.cxx index c31a826451..80ba127834 100644 --- a/src/sys/timer.cxx +++ b/src/sys/timer.cxx @@ -69,7 +69,7 @@ void Timer::cleanup() { map Timer::info; Timer::timer_info* Timer::getInfo(const std::string &label) { - map::iterator it(info.find(label)); + auto it = info.find(label); if(it == info.end()) { // Not in map, so create it timer_info *t = new timer_info; From 47da759d0109b8431c5c967134162f2cc85deb7c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Oct 2018 16:14:32 +0100 Subject: [PATCH 0133/1783] Remove `using std::string` etc. from headers --- include/boundary_factory.hxx | 24 ++- include/boundary_op.hxx | 6 +- include/boundary_region.hxx | 3 +- include/boundary_standard.hxx | 50 +++--- include/bout/griddata.hxx | 50 +++--- include/bout/mesh.hxx | 22 +-- include/bout/rkscheme.hxx | 6 +- include/bout/solver.hxx | 37 +++-- include/boutexception.hxx | 4 +- include/datafile.hxx | 34 ++-- include/dataformat.hxx | 49 +++--- include/field2d.hxx | 6 +- include/field3d.hxx | 14 +- include/field_data.hxx | 17 +- include/initialprofiles.hxx | 8 +- include/interpolation_factory.hxx | 12 +- include/options.hxx | 2 +- include/parallel_boundary_op.hxx | 10 +- include/parallel_boundary_region.hxx | 4 +- include/utils.hxx | 6 +- include/vector2d.hxx | 4 +- include/vector3d.hxx | 4 +- src/field/field2d.cxx | 4 +- src/field/field3d.cxx | 10 +- src/field/field_data.cxx | 8 +- src/field/field_factory.cxx | 28 ++-- src/field/initialprofiles.cxx | 12 +- src/fileio/datafile.cxx | 152 +++++++++--------- src/fileio/dataformat.cxx | 12 +- src/fileio/impls/emptyformat.hxx | 24 +-- src/fileio/impls/hdf5/h5_format.cxx | 32 ++-- src/fileio/impls/hdf5/h5_format.hxx | 35 ++-- src/fileio/impls/netcdf4/ncxx4.cxx | 48 +++--- src/fileio/impls/netcdf4/ncxx4.hxx | 8 +- .../laplace/impls/petsc/petsc_laplace.cxx | 2 +- src/invert/laplace/laplacefactory.cxx | 2 +- src/invert/laplacexy/laplacexy.cxx | 4 +- .../laplacexz/impls/petsc/laplacexz-petsc.cxx | 6 +- .../laplacexz/impls/petsc/laplacexz-petsc.hxx | 2 +- src/invert/laplacexz/laplacexz.cxx | 2 +- src/invert/parderiv/parderiv_factory.cxx | 2 +- src/mesh/boundary_standard.cxx | 55 +++---- src/mesh/data/gridfromfile.cxx | 32 ++-- src/mesh/data/gridfromoptions.cxx | 14 +- src/mesh/impls/bout/boutmesh.cxx | 8 +- src/mesh/impls/bout/boutmesh.hxx | 21 ++- src/mesh/index_derivs.cxx | 2 +- .../interpolation/interpolation_factory.cxx | 10 +- src/mesh/mesh.cxx | 22 +-- src/mesh/meshfactory.cxx | 8 +- src/mesh/parallel_boundary_op.cxx | 8 +- src/physics/physicsmodel.cxx | 6 +- src/solver/impls/imex-bdf2/imex-bdf2.cxx | 2 +- src/solver/impls/imex-bdf2/imex-bdf2.hxx | 8 +- src/solver/impls/rkgeneric/rkscheme.cxx | 36 ++--- .../impls/rkgeneric/rkschemefactory.cxx | 2 +- src/solver/impls/slepc/slepc.cxx | 8 +- src/solver/solver.cxx | 4 +- src/sys/options.cxx | 10 +- src/sys/options/options_ini.hxx | 2 +- src/sys/optionsreader.cxx | 12 +- src/sys/utils.cxx | 8 +- tests/unit/mesh/test_boutmesh.cxx | 14 +- tests/unit/test_extras.hxx | 6 +- 64 files changed, 519 insertions(+), 544 deletions(-) diff --git a/include/boundary_factory.hxx b/include/boundary_factory.hxx index e4c6a67d55..5bdb11b20e 100644 --- a/include/boundary_factory.hxx +++ b/include/boundary_factory.hxx @@ -11,8 +11,6 @@ class BoundaryFactory; #include #include -using std::string; -using std::map; /// Create BoundaryOp objects on demand /*! @@ -69,18 +67,18 @@ class BoundaryFactory { static void cleanup(); ///< Frees all memory /// Create a boundary operation object - BoundaryOpBase* create(const string &name, BoundaryRegionBase *region); + BoundaryOpBase* create(const std::string &name, BoundaryRegionBase *region); BoundaryOpBase* create(const char* name, BoundaryRegionBase *region); /// Create a boundary object using the options file - BoundaryOpBase* createFromOptions(const string &varname, BoundaryRegionBase *region); + BoundaryOpBase* createFromOptions(const std::string &varname, BoundaryRegionBase *region); BoundaryOpBase* createFromOptions(const char* varname, BoundaryRegionBase *region); /*! * Add available boundary conditions and modifiers * Supply an object, and the name to be used */ - void add(BoundaryOp* bop, const string &name); + void add(BoundaryOp* bop, const std::string &name); /*! * Add a boundary condition. @@ -92,7 +90,7 @@ class BoundaryFactory { /*! * Add a boundary condition modifier */ - void addMod(BoundaryModifier* bmod, const string &name); + void addMod(BoundaryModifier* bmod, const std::string &name); /*! * Note: This method should be removed, as the string method is sufficient @@ -100,7 +98,7 @@ class BoundaryFactory { void addMod(BoundaryModifier* bmod, const char *name); // Parallel boundaries - void add(BoundaryOpPar* bop, const string &name); + void add(BoundaryOpPar* bop, const std::string &name); void add(BoundaryOpPar* bop, const char *name); private: @@ -111,18 +109,18 @@ class BoundaryFactory { static BoundaryFactory* instance; ///< The only instance of this class (Singleton) // Database of available boundary conditions and modifiers - map opmap; - map modmap; + std::map opmap; + std::map modmap; // Parallel boundary conditions - map par_opmap; + std::map par_opmap; // Modifiers to be implemented... // map par_modmap; // Functions to look up operations and modifiers - BoundaryOp* findBoundaryOp(const string &s); - BoundaryModifier* findBoundaryMod(const string &s); + BoundaryOp* findBoundaryOp(const std::string &s); + BoundaryModifier* findBoundaryMod(const std::string &s); // Parallel boundary conditions - BoundaryOpPar* findBoundaryOpPar(const string &s); + BoundaryOpPar* findBoundaryOpPar(const std::string &s); // To be implemented... // BoundaryModifier* findBoundaryMod(const string &s); diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index 5a15fd21ff..1f06675a5c 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -15,8 +15,6 @@ class BoundaryModifier; #include #include #include -using std::string; -using std::list; class BoundaryOpBase { public: @@ -53,7 +51,7 @@ public: ~BoundaryOp() override {} // Note: All methods must implement clone, except for modifiers (see below) - virtual BoundaryOp* clone(BoundaryRegion *UNUSED(region), const list &UNUSED(args)) { + virtual BoundaryOp* clone(BoundaryRegion *UNUSED(region), const std::list &UNUSED(args)) { return nullptr; } @@ -79,7 +77,7 @@ class BoundaryModifier : public BoundaryOp { public: BoundaryModifier() : op(nullptr) {} BoundaryModifier(BoundaryOp *operation) : BoundaryOp(operation->bndry), op(operation) {} - virtual BoundaryOp* cloneMod(BoundaryOp *op, const list &args) = 0; + virtual BoundaryOp* cloneMod(BoundaryOp *op, const std::list &args) = 0; protected: BoundaryOp *op; }; diff --git a/include/boundary_region.hxx b/include/boundary_region.hxx index 0121fc4c64..cc53f1b54e 100644 --- a/include/boundary_region.hxx +++ b/include/boundary_region.hxx @@ -6,7 +6,6 @@ class BoundaryRegion; #include #include -using std::string; class Mesh; extern Mesh* mesh; @@ -33,7 +32,7 @@ public: Mesh* localmesh; ///< Mesh does this boundary region belongs to - string label; ///< Label for this boundary region + std::string label; ///< Label for this boundary region BndryLoc location; ///< Which side of the domain is it on? bool isParallel = false; ///< Is this a parallel boundary? diff --git a/include/boundary_standard.hxx b/include/boundary_standard.hxx index ca9a05fc11..6c6d291df6 100644 --- a/include/boundary_standard.hxx +++ b/include/boundary_standard.hxx @@ -16,7 +16,7 @@ class BoundaryDirichlet_2ndOrder : public BoundaryOp { BoundaryDirichlet_2ndOrder() : val(0.) {} BoundaryDirichlet_2ndOrder(BoutReal setval ): val(setval) {} BoundaryDirichlet_2ndOrder(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region),val(setval) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -35,7 +35,7 @@ class BoundaryDirichlet : public BoundaryOp { BoundaryDirichlet() : gen(nullptr) {} BoundaryDirichlet(BoundaryRegion *region, std::shared_ptr g) : BoundaryOp(region), gen(std::move(g)) {} - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -58,7 +58,7 @@ class BoundaryDirichlet_O3 : public BoundaryOp { BoundaryDirichlet_O3() : gen(nullptr) {} BoundaryDirichlet_O3(BoundaryRegion *region, std::shared_ptr g) : BoundaryOp(region), gen(std::move(g)) {} - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -79,7 +79,7 @@ class BoundaryDirichlet_O4 : public BoundaryOp { BoundaryDirichlet_O4() : gen(nullptr) {} BoundaryDirichlet_O4(BoundaryRegion *region, std::shared_ptr g) : BoundaryOp(region), gen(std::move(g)) {} - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -100,7 +100,7 @@ class BoundaryDirichlet_4thOrder : public BoundaryOp { BoundaryDirichlet_4thOrder() : val(0.) {} BoundaryDirichlet_4thOrder(BoutReal setval ): val(setval) {} BoundaryDirichlet_4thOrder(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region),val(setval) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -119,7 +119,7 @@ class BoundaryNeumann_NonOrthogonal : public BoundaryOp { BoundaryNeumann_NonOrthogonal(): val(0.) {} BoundaryNeumann_NonOrthogonal(BoutReal setval ): val(setval) {} BoundaryNeumann_NonOrthogonal(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region),val(setval) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -133,7 +133,7 @@ class BoundaryNeumann2 : public BoundaryOp { public: BoundaryNeumann2() {} BoundaryNeumann2(BoundaryRegion *region):BoundaryOp(region) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -146,7 +146,7 @@ class BoundaryNeumann_2ndOrder : public BoundaryOp { BoundaryNeumann_2ndOrder() : val(0.) {} BoundaryNeumann_2ndOrder(BoutReal setval ): val(setval) {} BoundaryNeumann_2ndOrder(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region),val(setval) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -165,7 +165,7 @@ class BoundaryNeumann : public BoundaryOp { BoundaryNeumann() : gen(nullptr) {} BoundaryNeumann(BoundaryRegion *region, std::shared_ptr g) : BoundaryOp(region), gen(std::move(g)) {} - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -186,7 +186,7 @@ class BoundaryNeumann_4thOrder : public BoundaryOp { BoundaryNeumann_4thOrder() : val(0.) {} BoundaryNeumann_4thOrder(BoutReal setval ): val(setval) {} BoundaryNeumann_4thOrder(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region),val(setval) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -205,7 +205,7 @@ class BoundaryNeumann_O4 : public BoundaryOp { BoundaryNeumann_O4() : gen(nullptr) {} BoundaryNeumann_O4(BoundaryRegion *region, std::shared_ptr g) : BoundaryOp(region), gen(std::move(g)) {} - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -226,7 +226,7 @@ class BoundaryNeumannPar : public BoundaryOp { public: BoundaryNeumannPar() {} BoundaryNeumannPar(BoundaryRegion *region):BoundaryOp(region) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -238,7 +238,7 @@ class BoundaryRobin : public BoundaryOp { public: BoundaryRobin() : aval(0.), bval(0.), gval(0.) {} BoundaryRobin(BoundaryRegion *region, BoutReal a, BoutReal b, BoutReal g):BoundaryOp(region), aval(a), bval(b), gval(g) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -252,7 +252,7 @@ class BoundaryConstGradient : public BoundaryOp { public: BoundaryConstGradient() {} BoundaryConstGradient(BoundaryRegion *region):BoundaryOp(region) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -264,7 +264,7 @@ class BoundaryZeroLaplace : public BoundaryOp { public: BoundaryZeroLaplace() {} BoundaryZeroLaplace(BoundaryRegion *region):BoundaryOp(region) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -276,7 +276,7 @@ class BoundaryZeroLaplace2 : public BoundaryOp { public: BoundaryZeroLaplace2() {} BoundaryZeroLaplace2(BoundaryRegion *region):BoundaryOp(region) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -288,7 +288,7 @@ class BoundaryConstLaplace : public BoundaryOp { public: BoundaryConstLaplace() {} BoundaryConstLaplace(BoundaryRegion *region):BoundaryOp(region) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -300,7 +300,7 @@ class BoundaryDivCurl : public BoundaryOp { public: BoundaryDivCurl() {} BoundaryDivCurl(BoundaryRegion *region):BoundaryOp(region) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &UNUSED(f)) override { throw BoutException("ERROR: DivCurl boundary only for vectors"); } @@ -315,7 +315,7 @@ class BoundaryFree : public BoundaryOp { BoundaryFree() : val(0.) {apply_to_ddt = true;} BoundaryFree(BoutReal setval): val(setval) {} BoundaryFree(BoundaryRegion *region, BoutReal setval=0.):BoundaryOp(region),val(setval) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -334,7 +334,7 @@ class BoundaryFree_O2 : public BoundaryOp { public: BoundaryFree_O2() {} BoundaryFree_O2(BoundaryRegion *region):BoundaryOp(region) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -349,7 +349,7 @@ class BoundaryFree_O3 : public BoundaryOp { public: BoundaryFree_O3() {} BoundaryFree_O3(BoundaryRegion *region):BoundaryOp(region) { } - BoundaryOp* clone(BoundaryRegion *region, const list &args) override; + BoundaryOp* clone(BoundaryRegion *region, const std::list &args) override; using BoundaryOp::apply; void apply(Field2D &f) override; @@ -370,7 +370,7 @@ class BoundaryRelax : public BoundaryModifier { public: BoundaryRelax() : r(10.) {apply_to_ddt = true;} // Set default rate BoundaryRelax(BoundaryOp *operation, BoutReal rate) : BoundaryModifier(operation) {r = fabs(rate); apply_to_ddt = true;} - BoundaryOp* cloneMod(BoundaryOp *op, const list &args) override; + BoundaryOp* cloneMod(BoundaryOp *op, const std::list &args) override; using BoundaryModifier::apply; void apply(Field2D &f) override {apply(f, 0.);}; @@ -390,7 +390,7 @@ class BoundaryWidth : public BoundaryModifier { public: BoundaryWidth() : width(2) {} BoundaryWidth(BoundaryOp *operation, int wid) : BoundaryModifier(operation), width(wid) {} - BoundaryOp* cloneMod(BoundaryOp *op, const list &args) override; + BoundaryOp* cloneMod(BoundaryOp *op, const std::list &args) override; using BoundaryModifier::apply; void apply(Field2D &f) override {apply(f, 0.);}; @@ -411,7 +411,7 @@ class BoundaryToFieldAligned : public BoundaryModifier { public: BoundaryToFieldAligned(){} BoundaryToFieldAligned(BoundaryOp *operation) : BoundaryModifier(operation){} - BoundaryOp* cloneMod(BoundaryOp *op, const list &args) override; + BoundaryOp* cloneMod(BoundaryOp *op, const std::list &args) override; using BoundaryModifier::apply; void apply(Field2D &f) override {apply(f, 0.);}; @@ -431,7 +431,7 @@ class BoundaryFromFieldAligned : public BoundaryModifier { public: BoundaryFromFieldAligned(){} BoundaryFromFieldAligned(BoundaryOp *operation) : BoundaryModifier(operation){} - BoundaryOp* cloneMod(BoundaryOp *op, const list &args) override; + BoundaryOp* cloneMod(BoundaryOp *op, const std::list &args) override; using BoundaryModifier::apply; void apply(Field2D &f) override {apply(f, 0.);}; diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index afc661303b..42ca1c9f97 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -50,18 +50,18 @@ class GridDataSource { public: virtual ~GridDataSource() {} - virtual bool hasVar(const string &name) = 0; ///< Test if source can supply a variable + virtual bool hasVar(const std::string &name) = 0; ///< Test if source can supply a variable - virtual bool get(Mesh *m, int &ival, const string &name) = 0; ///< Get an integer + virtual bool get(Mesh *m, int &ival, const std::string &name) = 0; ///< Get an integer virtual bool get(Mesh *m, BoutReal &rval, - const string &name) = 0; ///< Get a BoutReal number - virtual bool get(Mesh *m, Field2D &var, const string &name, BoutReal def = 0.0) = 0; - virtual bool get(Mesh *m, Field3D &var, const string &name, BoutReal def = 0.0) = 0; + const std::string &name) = 0; ///< Get a BoutReal number + virtual bool get(Mesh *m, Field2D &var, const std::string &name, BoutReal def = 0.0) = 0; + virtual bool get(Mesh *m, Field3D &var, const std::string &name, BoutReal def = 0.0) = 0; enum Direction { X = 1, Y = 2, Z = 3 }; - virtual bool get(Mesh *m, vector &var, const string &name, int len, int offset = 0, + virtual bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, Direction dir = GridDataSource::X) = 0; - virtual bool get(Mesh *m, vector &var, const string &name, int len, + virtual bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, Direction dir = GridDataSource::X) = 0; }; @@ -73,30 +73,30 @@ public: class GridFile : public GridDataSource { public: GridFile() = delete; - GridFile(std::unique_ptr format, string gridfilename); + GridFile(std::unique_ptr format, std::string gridfilename); ~GridFile() override; - bool hasVar(const string &name) override; + bool hasVar(const std::string &name) override; - bool get(Mesh *m, int &ival, const string &name) override; ///< Get an integer + bool get(Mesh *m, int &ival, const std::string &name) override; ///< Get an integer bool get(Mesh *m, BoutReal &rval, - const string &name) override; ///< Get a BoutReal number - bool get(Mesh *m, Field2D &var, const string &name, BoutReal def = 0.0) override; - bool get(Mesh *m, Field3D &var, const string &name, BoutReal def = 0.0) override; + const std::string &name) override; ///< Get a BoutReal number + bool get(Mesh *m, Field2D &var, const std::string &name, BoutReal def = 0.0) override; + bool get(Mesh *m, Field3D &var, const std::string &name, BoutReal def = 0.0) override; - bool get(Mesh *m, vector &var, const string &name, int len, int offset = 0, + bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, GridDataSource::Direction dir = GridDataSource::X) override; - bool get(Mesh *m, vector &var, const string &name, int len, int offset = 0, + bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, GridDataSource::Direction dir = GridDataSource::X) override; private: std::unique_ptr file; - string filename; + std::string filename; - bool readgrid_3dvar_fft(Mesh *m, const string &name, int yread, int ydest, int ysize, + bool readgrid_3dvar_fft(Mesh *m, const std::string &name, int yread, int ydest, int ysize, int xge, int xlt, Field3D &var); - bool readgrid_3dvar_real(Mesh *m, const string &name, int yread, int ydest, int ysize, + bool readgrid_3dvar_real(Mesh *m, const std::string &name, int yread, int ydest, int ysize, int xge, int xlt, Field3D &var); }; @@ -118,7 +118,7 @@ public: /*! * Checks if the options has a given variable */ - bool hasVar(const string &name) override; + bool hasVar(const std::string &name) override; /*! * Reads integers from options. Uses Options::get to handle @@ -130,7 +130,7 @@ public: * * @return True if option is set, false if ival is default (0) */ - bool get(Mesh *mesh, int &ival, const string &name) override; + bool get(Mesh *mesh, int &ival, const std::string &name) override; /*! * Reads BoutReal from options. Uses Options::get to handle @@ -142,7 +142,7 @@ public: * * @return True if option is set, false if ival is default (0) */ - bool get(Mesh *mesh, BoutReal &rval, const string &name) override; + bool get(Mesh *mesh, BoutReal &rval, const std::string &name) override; /*! * Get a Field2D object by finding the option with the given name, @@ -153,7 +153,7 @@ public: * @param[in] name The name in the options. Not case sensitive * @param[in] def Default value to use if option not found */ - bool get(Mesh *mesh, Field2D &var, const string &name, BoutReal def = 0.0) override; + bool get(Mesh *mesh, Field2D &var, const std::string &name, BoutReal def = 0.0) override; /*! * Get a Field3D object by finding the option with the given name, @@ -164,7 +164,7 @@ public: * @param[in] name The name in the options. Not case sensitive * @param[in] def Default value to use if option not found */ - bool get(Mesh *mesh, Field3D &var, const string &name, BoutReal def = 0.0) override; + bool get(Mesh *mesh, Field3D &var, const std::string &name, BoutReal def = 0.0) override; /*! * Get an array of integers. Currently reads a single @@ -177,7 +177,7 @@ public: * @param[in] offset Not currently used * @param[in] dir The direction (X,Y,Z) of the array */ - bool get(Mesh *mesh, vector &var, const string &name, int len, int offset = 0, + bool get(Mesh *mesh, std::vector &var, const std::string &name, int len, int offset = 0, GridDataSource::Direction dir = GridDataSource::X) override; /*! @@ -193,7 +193,7 @@ public: * dir is X. * @param[in] dir The direction (X,Y,Z) of the array */ - bool get(Mesh *mesh, vector &var, const string &name, int len, int offset = 0, + bool get(Mesh *mesh, std::vector &var, const std::string &name, int len, int offset = 0, GridDataSource::Direction dir = GridDataSource::X) override; private: diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 056294bbe0..0689852816 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -126,7 +126,7 @@ class Mesh { /// @param[in] name The name of the variable to read /// /// @returns zero if successful, non-zero on failure - int get(int &ival, const string &name); + int get(int &ival, const std::string &name); /// Get a BoutReal from the input source /// @@ -134,7 +134,7 @@ class Mesh { /// @param[in] name The name of the variable to read /// /// @returns zero if successful, non-zero on failure - int get(BoutReal &rval, const string &name); + int get(BoutReal &rval, const std::string &name); /// Get a Field2D from the input source /// including communicating guard cells @@ -144,7 +144,7 @@ class Mesh { /// @param[in] def The default value if not found /// /// @returns zero if successful, non-zero on failure - int get(Field2D &var, const string &name, BoutReal def=0.0); + int get(Field2D &var, const std::string &name, BoutReal def=0.0); /// Get a Field3D from the input source /// @@ -154,7 +154,7 @@ class Mesh { /// @param[in] communicate Should the field be communicated to fill guard cells? /// /// @returns zero if successful, non-zero on failure - int get(Field3D &var, const string &name, BoutReal def=0.0, bool communicate=true); + int get(Field3D &var, const std::string &name, BoutReal def=0.0, bool communicate=true); /// Get a Vector2D from the input source. /// If \p var is covariant then this gets three @@ -167,7 +167,7 @@ class Mesh { /// @param[in] name The name of the vector. Individual fields are read based on this name by appending. See above /// /// @returns zero always. - int get(Vector2D &var, const string &name); + int get(Vector2D &var, const std::string &name); /// Get a Vector3D from the input source. /// If \p var is covariant then this gets three @@ -180,10 +180,10 @@ class Mesh { /// @param[in] name The name of the vector. Individual fields are read based on this name by appending. See above /// /// @returns zero always. - int get(Vector3D &var, const string &name); + int get(Vector3D &var, const std::string &name); /// Wrapper for GridDataSource::hasVar - bool sourceHasVar(const string &name); + bool sourceHasVar(const std::string &name); // Communications /*! @@ -387,13 +387,13 @@ class Mesh { // Boundary regions /// Return a vector containing all the boundary regions on this processor - virtual vector getBoundaries() = 0; + virtual std::vector getBoundaries() = 0; /// Add a boundary region to this processor virtual void addBoundary(BoundaryRegion* UNUSED(bndry)) {} /// Get all the parallel (Y) boundaries on this processor - virtual vector getBoundariesPar() = 0; + virtual std::vector getBoundariesPar() = 0; /// Add a parallel(Y) boundary to this processor virtual void addBoundaryPar(BoundaryRegionPar* UNUSED(bndry)) {} @@ -716,10 +716,10 @@ class Mesh { PTptr transform; ///< Handles calculation of yup and ydown /// Read a 1D array of integers - const vector readInts(const string &name, int n); + const std::vector readInts(const std::string &name, int n); /// Calculates the size of a message for a given x and y range - int msg_len(const vector &var_list, int xge, int xlt, int yge, int ylt); + int msg_len(const std::vector &var_list, int xge, int xlt, int yge, int ylt); /// Initialise derivatives void derivs_init(Options* options); diff --git a/include/bout/rkscheme.hxx b/include/bout/rkscheme.hxx index 593de44519..19f8a00a3f 100644 --- a/include/bout/rkscheme.hxx +++ b/include/bout/rkscheme.hxx @@ -41,8 +41,6 @@ class RKScheme; #include #include -using std::string; -using std::setw; #define RKSchemeType const char* #define RKSCHEME_RKF45 "rkf45" @@ -75,7 +73,7 @@ class RKScheme { virtual BoutReal updateTimestep(BoutReal dt,BoutReal err); //Returns the string name for the given scheme - virtual string getType(){return label;}; + virtual std::string getType(){return label;}; //Returns the number of stages for the current scheme int getStageCount(){return numStages;}; @@ -89,7 +87,7 @@ class RKScheme { protected: //Information about scheme bool followHighOrder; //If true the recommended solution is the higher order one. - string label; + std::string label; int numStages; //Number of stages in the scheme int numOrders; //Number of orders in the scheme int order; //Order of scheme diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 0b77c8d333..411011f82e 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -75,7 +75,6 @@ typedef int (*TimestepMonitorFunc)(Solver *solver, BoutReal simtime, BoutReal la #include #include -using std::string; typedef std::string SolverType; #define SOLVERCVODE "cvode" @@ -330,24 +329,24 @@ protected: /// A structure to hold an evolving variable template - struct VarStr { - bool constraint; - T *var; - T *F_var; - T *MMS_err; // Error for MMS - CELL_LOC location; // For fields and vector components - bool covariant; // For vectors - bool evolve_bndry; // Are the boundary regions being evolved? - - string name; // Name of the variable - }; - + struct VarStr { + bool constraint; + T *var; + T *F_var; + T *MMS_err; // Error for MMS + CELL_LOC location; // For fields and vector components + bool covariant; // For vectors + bool evolve_bndry; // Are the boundary regions being evolved? + + std::string name; // Name of the variable + }; + /// Vectors of variables to evolve - vector< VarStr > f2d; - vector< VarStr > f3d; - vector< VarStr > v2d; - vector< VarStr > v3d; - + std::vector> f2d; + std::vector> f3d; + std::vector> v2d; + std::vector> v3d; + bool has_constraints; ///< Can this solver.hxxandle constraints? Set to true if so. bool initialised; ///< Has init been called yet? @@ -406,7 +405,7 @@ private: void loop_vars_op(Ind2D i2d, BoutReal *udata, int &p, SOLVER_VAR_OP op, bool bndry); void loop_vars(BoutReal *udata, SOLVER_VAR_OP op); - bool varAdded(const string &name); // Check if a variable has already been added + bool varAdded(const std::string &name); // Check if a variable has already been added }; #endif // __SOLVER_H__ diff --git a/include/boutexception.hxx b/include/boutexception.hxx index 40316f5dd0..3afa987cab 100644 --- a/include/boutexception.hxx +++ b/include/boutexception.hxx @@ -7,8 +7,6 @@ class BoutException; #include #include -using std::string; - /// Throw BoutRhsFail with \p message if any one process has non-zero /// \p status void BoutParallelThrowRhsFail(int status, const char* message); @@ -25,7 +23,7 @@ protected: char *buffer = nullptr; static const int BUFFER_LEN = 1024; // Length of char buffer for printing int buflen; // Length of char buffer for printing - string message; + std::string message; #ifdef BACKTRACE static const unsigned int TRACE_MAX = 128; void *trace[TRACE_MAX]; diff --git a/include/datafile.hxx b/include/datafile.hxx index 15ef36a356..b15ea76c92 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -73,8 +73,8 @@ class Datafile { bool write(const char *filename, ...) const; ///< Opens, writes, closes file - void setAttribute(const string &varname, const string &attrname, const string &text); - void setAttribute(const string &varname, const string &attrname, int value); + void setAttribute(const std::string &varname, const std::string &attrname, const std::string &text); + void setAttribute(const std::string &varname, const std::string &attrname, int value); private: bool parallel; // Use parallel formats? @@ -106,33 +106,33 @@ class Datafile { struct VarStr { T *ptr; ///< Pointer to the data. ///< Note that this may be a user object, not a copy, so must not be destroyed - string name; ///< Name as it appears in the output file + std::string name; ///< Name as it appears in the output file bool save_repeat; ///< If true, has a time dimension and is saved every time step bool covar; ///< For vectors, true if a covariant vector, false if contravariant }; // one set per variable type - vector< VarStr > int_arr; - vector< VarStr > BoutReal_arr; - vector< VarStr > f2d_arr; - vector< VarStr > f3d_arr; - vector< VarStr > v2d_arr; - vector< VarStr > v3d_arr; + std::vector> int_arr; + std::vector> BoutReal_arr; + std::vector> f2d_arr; + std::vector> f3d_arr; + std::vector> v2d_arr; + std::vector> v3d_arr; - bool read_f2d(const string &name, Field2D *f, bool save_repeat); - bool read_f3d(const string &name, Field3D *f, bool save_repeat); + bool read_f2d(const std::string &name, Field2D *f, bool save_repeat); + bool read_f3d(const std::string &name, Field3D *f, bool save_repeat); - bool write_int(const string &name, int *f, bool save_repeat); - bool write_real(const string &name, BoutReal *f, bool save_repeat); - bool write_f2d(const string &name, Field2D *f, bool save_repeat); - bool write_f3d(const string &name, Field3D *f, bool save_repeat); + bool write_int(const std::string &name, int *f, bool save_repeat); + bool write_real(const std::string &name, BoutReal *f, bool save_repeat); + bool write_f2d(const std::string &name, Field2D *f, bool save_repeat); + bool write_f3d(const std::string &name, Field3D *f, bool save_repeat); /// Check if a variable has already been added - bool varAdded(const string &name); + bool varAdded(const std::string &name); /// Get the pointer to the variable, nullptr if not added /// This is used to check if the same variable is being added - void* varPtr(const string &name); + void* varPtr(const std::string &name); }; /// Write this variable once to the grid file diff --git a/include/dataformat.hxx b/include/dataformat.hxx index 7186cfdf2e..2cfdd4f459 100644 --- a/include/dataformat.hxx +++ b/include/dataformat.hxx @@ -38,10 +38,7 @@ class DataFormat; #include #include -using std::string; - #include -using std::vector; // Can't copy, to control access to file class DataFormat { @@ -49,15 +46,15 @@ class DataFormat { virtual ~DataFormat() { } // File opening routines virtual bool openr(const char *name) = 0; - virtual bool openr(const string &name) { + virtual bool openr(const std::string &name) { return openr(name.c_str()); } - virtual bool openr(const string &base, int mype); + virtual bool openr(const std::string &base, int mype); virtual bool openw(const char *name, bool append=false) = 0; - virtual bool openw(const string &name, bool append=false) { + virtual bool openw(const std::string &name, bool append=false) { return openw(name.c_str(), append); } - virtual bool openw(const string &base, int mype, bool append=false); + virtual bool openw(const std::string &base, int mype, bool append=false); virtual bool is_valid() = 0; @@ -65,8 +62,8 @@ class DataFormat { virtual void flush() = 0; - virtual const vector getSize(const char *var) = 0; - virtual const vector getSize(const string &var) = 0; + virtual const std::vector getSize(const char *var) = 0; + virtual const std::vector getSize(const std::string &var) = 0; // Set the origin for all subsequent calls virtual bool setGlobalOrigin(int x = 0, int y = 0, int z = 0) = 0; @@ -74,34 +71,34 @@ class DataFormat { virtual bool setRecord(int t) = 0; // negative -> latest // Add a variable to the file - virtual bool addVarInt(const string &name, bool repeat) = 0; - virtual bool addVarBoutReal(const string &name, bool repeat) = 0; - virtual bool addVarField2D(const string &name, bool repeat) = 0; - virtual bool addVarField3D(const string &name, bool repeat) = 0; + virtual bool addVarInt(const std::string &name, bool repeat) = 0; + virtual bool addVarBoutReal(const std::string &name, bool repeat) = 0; + virtual bool addVarField2D(const std::string &name, bool repeat) = 0; + virtual bool addVarField3D(const std::string &name, bool repeat) = 0; // Read / Write simple variables up to 3D virtual bool read(int *var, const char *name, int lx = 1, int ly = 0, int lz = 0) = 0; - virtual bool read(int *var, const string &name, int lx = 1, int ly = 0, int lz = 0) = 0; + virtual bool read(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) = 0; virtual bool read(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) = 0; - virtual bool read(BoutReal *var, const string &name, int lx = 1, int ly = 0, int lz = 0) = 0; + virtual bool read(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) = 0; virtual bool write(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) = 0; - virtual bool write(int *var, const string &name, int lx = 0, int ly = 0, int lz = 0) = 0; + virtual bool write(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) = 0; virtual bool write(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) = 0; - virtual bool write(BoutReal *var, const string &name, int lx = 0, int ly = 0, int lz = 0) = 0; + virtual bool write(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) = 0; // Read / Write record-based variables virtual bool read_rec(int *var, const char *name, int lx = 1, int ly = 0, int lz = 0) = 0; - virtual bool read_rec(int *var, const string &name, int lx = 1, int ly = 0, int lz = 0) = 0; + virtual bool read_rec(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) = 0; virtual bool read_rec(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) = 0; - virtual bool read_rec(BoutReal *var, const string &name, int lx = 1, int ly = 0, int lz = 0) = 0; + virtual bool read_rec(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) = 0; virtual bool write_rec(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) = 0; - virtual bool write_rec(int *var, const string &name, int lx = 0, int ly = 0, int lz = 0) = 0; + virtual bool write_rec(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) = 0; virtual bool write_rec(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) = 0; - virtual bool write_rec(BoutReal *var, const string &name, int lx = 0, int ly = 0, int lz = 0) = 0; + virtual bool write_rec(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) = 0; // Optional functions @@ -117,8 +114,8 @@ class DataFormat { /// @param[in] varname Variable name. The variable must already exist /// @param[in] attrname Attribute name /// @param[in] text A string attribute to attach to the variable - virtual void setAttribute(const string &varname, const string &attrname, - const string &text) = 0; + virtual void setAttribute(const std::string &varname, const std::string &attrname, + const std::string &text) = 0; /// Sets an integer attribute /// @@ -128,7 +125,7 @@ class DataFormat { /// @param[in] varname Variable name. The variable must already exist /// @param[in] attrname Attribute name /// @param[in] value A string attribute to attach to the variable - virtual void setAttribute(const string &varname, const string &attrname, + virtual void setAttribute(const std::string &varname, const std::string &attrname, int value) = 0; /// Gets a string attribute /// @@ -141,7 +138,7 @@ class DataFormat { /// Returns /// ------- /// text A string attribute of the variable - virtual bool getAttribute(const string &varname, const string &attrname, std::string &text) = 0; + virtual bool getAttribute(const std::string &varname, const std::string &attrname, std::string &text) = 0; /// Sets an integer attribute /// @@ -154,7 +151,7 @@ class DataFormat { /// Returns /// ------- /// value An int attribute of the variable - virtual bool getAttribute(const string &varname, const string &attrname, int &value) = 0; + virtual bool getAttribute(const std::string &varname, const std::string &attrname, int &value) = 0; }; // For backwards compatability. In formatfactory.cxx diff --git a/include/field2d.hxx b/include/field2d.hxx index 1b9dde93ac..017b6b1ff6 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -230,9 +230,9 @@ class Field2D : public Field, public FieldData { friend class Vector2D; void applyBoundary(bool init=false) override; - void applyBoundary(const string &condition); - void applyBoundary(const char* condition) { applyBoundary(string(condition)); } - void applyBoundary(const string ®ion, const string &condition); + void applyBoundary(const std::string &condition); + void applyBoundary(const char* condition) { applyBoundary(std::string(condition)); } + void applyBoundary(const std::string ®ion, const std::string &condition); void applyTDerivBoundary() override; void setBoundaryTo(const Field2D &f2d); ///< Copy the boundary region diff --git a/include/field3d.hxx b/include/field3d.hxx index e9f090bea6..3c80b3d24f 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -431,18 +431,18 @@ class Field3D : public Field, public FieldData { void applyBoundary(bool init=false) override; void applyBoundary(BoutReal t); - void applyBoundary(const string &condition); - void applyBoundary(const char* condition) { applyBoundary(string(condition)); } - void applyBoundary(const string ®ion, const string &condition); + void applyBoundary(const std::string &condition); + void applyBoundary(const char* condition) { applyBoundary(std::string(condition)); } + void applyBoundary(const std::string ®ion, const std::string &condition); void applyTDerivBoundary() override; void setBoundaryTo(const Field3D &f3d); ///< Copy the boundary region void applyParallelBoundary(); void applyParallelBoundary(BoutReal t); - void applyParallelBoundary(const string &condition); - void applyParallelBoundary(const char* condition) { applyParallelBoundary(string(condition)); } - void applyParallelBoundary(const string ®ion, const string &condition); - void applyParallelBoundary(const string ®ion, const string &condition, Field3D *f); + void applyParallelBoundary(const std::string &condition); + void applyParallelBoundary(const char* condition) { applyParallelBoundary(std::string(condition)); } + void applyParallelBoundary(const std::string ®ion, const std::string &condition); + void applyParallelBoundary(const std::string ®ion, const std::string &condition, Field3D *f); private: /// Boundary - add a 2D field diff --git a/include/field_data.hxx b/include/field_data.hxx index c4fadd4e95..6fa182be2a 100644 --- a/include/field_data.hxx +++ b/include/field_data.hxx @@ -33,21 +33,16 @@ class FieldData; #include "bout_types.hxx" #include "unused.hxx" +#include #include #include -using std::string; +#include // Including the next line leads to compiler errors //#include "boundary_op.hxx" class BoundaryOp; class BoundaryOpPar; -#include -using std::vector; - -#include -using std::map; - #include "boundary_region.hxx" #include "parallel_boundary_region.hxx" @@ -78,8 +73,8 @@ public: virtual void doneComms() { }; // Notifies that communications done // Boundary conditions - void setBoundary(const string &name); ///< Set the boundary conditions - void setBoundary(const string ®ion, BoundaryOp *op); ///< Manually set + void setBoundary(const std::string &name); ///< Set the boundary conditions + void setBoundary(const std::string ®ion, BoundaryOp *op); ///< Manually set void copyBoundary(const FieldData &f); ///< Copy the boundary conditions from another field @@ -92,11 +87,11 @@ public: FieldGeneratorPtr getBndryGenerator(BndryLoc location); protected: - vector bndry_op; ///< Boundary conditions + std::vector bndry_op; ///< Boundary conditions bool boundaryIsCopy; ///< True if bndry_op is a copy bool boundaryIsSet; ///< Set to true when setBoundary called // Parallel boundaries - vector bndry_op_par; ///< Boundary conditions + std::vector bndry_op_par; ///< Boundary conditions std::map bndry_generator; }; diff --git a/include/initialprofiles.hxx b/include/initialprofiles.hxx index 2a4421f60a..fe133b0c2e 100644 --- a/include/initialprofiles.hxx +++ b/include/initialprofiles.hxx @@ -74,7 +74,7 @@ * o vorticity -> cos(y) * */ -void initial_profile(const string &name, Field3D &var); +void initial_profile(const std::string &name, Field3D &var); /*! * Set a Field2D from options @@ -83,7 +83,7 @@ void initial_profile(const string &name, Field3D &var); * * @param[out] var The field which will be set to a value */ -void initial_profile(const string &name, Field2D &var); +void initial_profile(const std::string &name, Field2D &var); /*! * Set a vector to a value. The options used depend @@ -95,7 +95,7 @@ void initial_profile(const string &name, Field2D &var); * If contravariant, then each component will be initialised * by adding "x", "y" and "z" to the name. */ -void initial_profile(const string &name, Vector2D &var); +void initial_profile(const std::string &name, Vector2D &var); /*! * Set a vector to a value. The options used depend @@ -109,6 +109,6 @@ void initial_profile(const string &name, Vector2D &var); * * */ -void initial_profile(const string &name, Vector3D &var); +void initial_profile(const std::string &name, Vector3D &var); #endif // __INITIALPROF_H__ diff --git a/include/interpolation_factory.hxx b/include/interpolation_factory.hxx index 9964d0c8be..60b5b2065f 100644 --- a/include/interpolation_factory.hxx +++ b/include/interpolation_factory.hxx @@ -7,8 +7,6 @@ #include #include -using std::string; - class Mesh; class InterpolationFactory { @@ -25,14 +23,14 @@ private: static InterpolationFactory* instance; /// Database of available interpolations - std::map interp_map; + std::map interp_map; /// Find an interpolation method in the list of available methods /// /// @param name Name of the interpolation method /// /// @return A pointer to the Interpolation object in the map - CreateInterpCallback findInterpolation(const string &name); + CreateInterpCallback findInterpolation(const std::string &name); public: ~InterpolationFactory() {}; @@ -43,7 +41,7 @@ public: static void cleanup(); /// A string representing the default interpolation type - inline string getDefaultInterpType() { return "hermitespline"; } + inline std::string getDefaultInterpType() { return "hermitespline"; } /// Create an interpolation object Interpolation *create(Mesh *mesh) { @@ -61,11 +59,11 @@ public: /// @param mesh A Mesh object to construct the interpolation on /// /// @return A new copy of an Interpolation object - Interpolation *create(const string &name, Options *options = nullptr, + Interpolation *create(const std::string &name, Options *options = nullptr, Mesh *mesh = nullptr); /// Add available interpolations to database - void add(CreateInterpCallback interp, const string &name); + void add(CreateInterpCallback interp, const std::string &name); }; #endif //__INTERP_FACTORY_H__ diff --git a/include/options.hxx b/include/options.hxx index 4df91fc612..f78a1c6969 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -217,7 +217,7 @@ public: /// Force to a value /// Overwrites any existing setting template - void force(T val, const string source = "") { + void force(T val, const std::string source = "") { is_value = false; // Invalidates any existing setting assign(val, source); } diff --git a/include/parallel_boundary_op.hxx b/include/parallel_boundary_op.hxx index 3bd0be5c15..607ae7ee53 100644 --- a/include/parallel_boundary_op.hxx +++ b/include/parallel_boundary_op.hxx @@ -28,7 +28,7 @@ public: ~BoundaryOpPar() override {} // Note: All methods must implement clone, except for modifiers (see below) - virtual BoundaryOpPar* clone(BoundaryRegionPar *UNUSED(region), const list &UNUSED(args)) {return nullptr; } + virtual BoundaryOpPar* clone(BoundaryRegionPar *UNUSED(region), const std::list &UNUSED(args)) {return nullptr; } virtual BoundaryOpPar* clone(BoundaryRegionPar *UNUSED(region), Field3D *UNUSED(f)) {return nullptr; } using BoundaryOpBase::apply; @@ -71,7 +71,7 @@ public: BoundaryOpPar(region, value) {} BoundaryOpPar_dirichlet(BoundaryRegionPar *region, BoutReal value) : BoundaryOpPar(region, value) {} - BoundaryOpPar* clone(BoundaryRegionPar *region, const list &args) override; + BoundaryOpPar* clone(BoundaryRegionPar *region, const std::list &args) override; BoundaryOpPar* clone(BoundaryRegionPar *region, Field3D *f) override; using BoundaryOpPar::apply; @@ -91,7 +91,7 @@ public: BoundaryOpPar(region, value) {} BoundaryOpPar_dirichlet_O3(BoundaryRegionPar *region, BoutReal value) : BoundaryOpPar(region, value) {} - BoundaryOpPar* clone(BoundaryRegionPar *region, const list &args) override; + BoundaryOpPar* clone(BoundaryRegionPar *region, const std::list &args) override; BoundaryOpPar* clone(BoundaryRegionPar *region, Field3D *f) override; using BoundaryOpPar::apply; @@ -111,7 +111,7 @@ public: BoundaryOpPar(region, value) {} BoundaryOpPar_dirichlet_interp(BoundaryRegionPar *region, BoutReal value) : BoundaryOpPar(region, value) {} - BoundaryOpPar* clone(BoundaryRegionPar *region, const list &args) override; + BoundaryOpPar* clone(BoundaryRegionPar *region, const std::list &args) override; BoundaryOpPar* clone(BoundaryRegionPar *region, Field3D *f) override; using BoundaryOpPar::apply; @@ -131,7 +131,7 @@ public: BoundaryOpPar(region, value) {} BoundaryOpPar_neumann(BoundaryRegionPar *region, BoutReal value) : BoundaryOpPar(region, value) {} - BoundaryOpPar* clone(BoundaryRegionPar *region, const list &args) override; + BoundaryOpPar* clone(BoundaryRegionPar *region, const std::list &args) override; BoundaryOpPar* clone(BoundaryRegionPar *region, Field3D *f) override; using BoundaryOpPar::apply; diff --git a/include/parallel_boundary_region.hxx b/include/parallel_boundary_region.hxx index 2025ad9abb..094611b823 100644 --- a/include/parallel_boundary_region.hxx +++ b/include/parallel_boundary_region.hxx @@ -44,10 +44,10 @@ class BoundaryRegionPar : public BoundaryRegionBase { IndicesIter bndry_position; public: - BoundaryRegionPar(const string &name, int dir, Mesh* passmesh) : + BoundaryRegionPar(const std::string &name, int dir, Mesh* passmesh) : BoundaryRegionBase(name, passmesh), dir(dir) { BoundaryRegionBase::isParallel = true;} - BoundaryRegionPar(const string &name, BndryLoc loc,int dir, Mesh* passmesh) : + BoundaryRegionPar(const std::string &name, BndryLoc loc,int dir, Mesh* passmesh) : BoundaryRegionBase(name, loc, passmesh), dir(dir) { BoundaryRegionBase::isParallel = true;} diff --git a/include/utils.hxx b/include/utils.hxx index 2b0052817f..458849baaa 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -337,7 +337,7 @@ char* copy_string(const char* s); * by writing to a stringstream */ template -const string toString(const T& val) { +const std::string toString(const T& val) { std::stringstream ss; ss << val; return ss.str(); @@ -346,12 +346,12 @@ const string toString(const T& val) { /*! * Convert a string to lower case */ -const string lowercase(const string &str); +const std::string lowercase(const std::string &str); /*! * Convert to lower case, except inside quotes (" or ') */ -const string lowercasequote(const string &str); +const std::string lowercasequote(const std::string &str); /*! * Convert a string to a BoutReal diff --git a/include/vector2d.hxx b/include/vector2d.hxx index ef0e650bf4..80040b76a2 100644 --- a/include/vector2d.hxx +++ b/include/vector2d.hxx @@ -145,12 +145,12 @@ class Vector2D : public FieldData { /// Apply boundary condition to all fields void applyBoundary(bool init=false) override; - void applyBoundary(const string &condition) { + void applyBoundary(const std::string &condition) { x.applyBoundary(condition); y.applyBoundary(condition); z.applyBoundary(condition); } - void applyBoundary(const char* condition) { applyBoundary(string(condition)); } + void applyBoundary(const char* condition) { applyBoundary(std::string(condition)); } void applyTDerivBoundary() override; private: diff --git a/include/vector3d.hxx b/include/vector3d.hxx index b2d41d8c0d..38eb25658b 100644 --- a/include/vector3d.hxx +++ b/include/vector3d.hxx @@ -188,12 +188,12 @@ class Vector3D : public FieldData { int BoutRealSize() const override { return 3; } void applyBoundary(bool init=false) override; - void applyBoundary(const string &condition) { + void applyBoundary(const std::string &condition) { x.applyBoundary(condition); y.applyBoundary(condition); z.applyBoundary(condition); } - void applyBoundary(const char* condition) { applyBoundary(string(condition)); } + void applyBoundary(const char* condition) { applyBoundary(std::string(condition)); } void applyTDerivBoundary() override; private: Vector3D *deriv; ///< Time-derivative, can be NULL diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index a675039078..5ea8d2e677 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -252,7 +252,7 @@ void Field2D::applyBoundary(bool init) { bndry->apply(*this); } -void Field2D::applyBoundary(const string &condition) { +void Field2D::applyBoundary(const std::string &condition) { TRACE("Field2D::applyBoundary(condition)"); checkData(*this); @@ -286,7 +286,7 @@ void Field2D::applyBoundary(const string &condition) { } } -void Field2D::applyBoundary(const string ®ion, const string &condition) { +void Field2D::applyBoundary(const std::string ®ion, const std::string &condition) { TRACE("Field2D::applyBoundary(string, string)"); checkData(*this); diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 7d9dda7cea..89adcb510b 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -423,7 +423,7 @@ void Field3D::applyBoundary(BoutReal t) { } } -void Field3D::applyBoundary(const string &condition) { +void Field3D::applyBoundary(const std::string &condition) { TRACE("Field3D::applyBoundary(condition)"); checkData(*this); @@ -450,7 +450,7 @@ void Field3D::applyBoundary(const string &condition) { //Field2D sets the corners to zero here, should we do the same here? } -void Field3D::applyBoundary(const string ®ion, const string &condition) { +void Field3D::applyBoundary(const std::string ®ion, const std::string &condition) { TRACE("Field3D::applyBoundary(string, string)"); checkData(*this); @@ -552,7 +552,7 @@ void Field3D::applyParallelBoundary(BoutReal t) { } } -void Field3D::applyParallelBoundary(const string &condition) { +void Field3D::applyParallelBoundary(const std::string &condition) { TRACE("Field3D::applyParallelBoundary(condition)"); @@ -576,7 +576,7 @@ void Field3D::applyParallelBoundary(const string &condition) { } } -void Field3D::applyParallelBoundary(const string ®ion, const string &condition) { +void Field3D::applyParallelBoundary(const std::string ®ion, const std::string &condition) { TRACE("Field3D::applyParallelBoundary(region, condition)"); @@ -603,7 +603,7 @@ void Field3D::applyParallelBoundary(const string ®ion, const string &conditio } } -void Field3D::applyParallelBoundary(const string ®ion, const string &condition, Field3D *f) { +void Field3D::applyParallelBoundary(const std::string ®ion, const std::string &condition, Field3D *f) { TRACE("Field3D::applyParallelBoundary(region, condition, f)"); diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 597846a111..fa541a30c4 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -18,7 +18,7 @@ FieldData::~FieldData() { } } -void FieldData::setBoundary(const string &name) { +void FieldData::setBoundary(const std::string &name) { /// Get the boundary factory (singleton) BoundaryFactory *bfact = BoundaryFactory::getInstance(); @@ -32,7 +32,7 @@ void FieldData::setBoundary(const string &name) { } /// Get the mesh boundary regions - vector par_reg = mesh->getBoundariesPar(); + std::vector par_reg = mesh->getBoundariesPar(); /// Loop over the mesh parallel boundary regions for(const auto& reg : mesh->getBoundariesPar()) { BoundaryOpPar* op = static_cast(bfact->createFromOptions(name, reg)); @@ -45,9 +45,9 @@ void FieldData::setBoundary(const string &name) { boundaryIsCopy = false; } -void FieldData::setBoundary(const string &UNUSED(region), BoundaryOp *op) { +void FieldData::setBoundary(const std::string &UNUSED(region), BoundaryOp *op) { /// Get the mesh boundary regions - vector reg = mesh->getBoundaries(); + std::vector reg = mesh->getBoundaries(); /// Find the region diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 7340c0a4e5..4b2ed5e343 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -99,7 +99,7 @@ FieldFactory::~FieldFactory() { } -const Field2D FieldFactory::create2D(const string &value, const Options *opt, +const Field2D FieldFactory::create2D(const std::string &value, const Options *opt, Mesh *localmesh, CELL_LOC loc, BoutReal t) { @@ -158,7 +158,7 @@ const Field2D FieldFactory::create2D(const string &value, const Options *opt, return result; } -const Field3D FieldFactory::create3D(const string &value, const Options *opt, +const Field3D FieldFactory::create3D(const std::string &value, const Options *opt, Mesh *localmesh, CELL_LOC loc, BoutReal t) { @@ -235,14 +235,14 @@ const Field3D FieldFactory::create3D(const string &value, const Options *opt, return result; } -const Options* FieldFactory::findOption(const Options *opt, const string &name, string &val) { +const Options* FieldFactory::findOption(const Options *opt, const std::string &name, std::string &val) { // Find an Options object which contains the given name const Options *result = opt; // Check if name contains a section separator ':' size_t pos = name.find(':'); - if(pos == string::npos) { + if(pos == std::string::npos) { // No separator. Try this section, and then go through parents while(!result->isSet(name)) { @@ -257,8 +257,8 @@ const Options* FieldFactory::findOption(const Options *opt, const string &name, result = Options::getRoot(); size_t lastpos = 0; - while(pos != string::npos) { - string sectionname = name.substr(lastpos,pos); + while(pos != std::string::npos) { + std::string sectionname = name.substr(lastpos,pos); if( sectionname.length() > 0 ) { result = result->getSection(sectionname); } @@ -267,7 +267,7 @@ const Options* FieldFactory::findOption(const Options *opt, const string &name, } // Now look for the name in this section - string varname = name.substr(lastpos); + std::string varname = name.substr(lastpos); if(!result->isSet(varname)) { // Not in this section @@ -280,17 +280,17 @@ const Options* FieldFactory::findOption(const Options *opt, const string &name, return result; } -FieldGeneratorPtr FieldFactory::resolve(string &name) { +FieldGeneratorPtr FieldFactory::resolve(std::string &name) { if (options) { // Check if in cache - string key; - if(name.find(':') != string::npos) { + std::string key; + if(name.find(':') != std::string::npos) { // Already has section key = name; }else { key = options->str(); if(key.length() > 0) - key += string(":"); + key += ":"; key += name; } @@ -318,7 +318,7 @@ FieldGeneratorPtr FieldFactory::resolve(string &name) { // Find the option, including traversing sections. // Throws exception if not found - string value; + std::string value; const Options *section = findOption(options, name, value); // Add to lookup list @@ -339,10 +339,10 @@ FieldGeneratorPtr FieldFactory::resolve(string &name) { return nullptr; } -FieldGeneratorPtr FieldFactory::parse(const string &input, const Options *opt) { +FieldGeneratorPtr FieldFactory::parse(const std::string &input, const Options *opt) { // Check if in the cache - string key = string("#") + input; + std::string key = "#" + input; if (opt) key = opt->str() + key; // Include options context in key diff --git a/src/field/initialprofiles.cxx b/src/field/initialprofiles.cxx index ad14f0df50..ff5426cf7d 100644 --- a/src/field/initialprofiles.cxx +++ b/src/field/initialprofiles.cxx @@ -49,7 +49,7 @@ #include #include -void initial_profile(const string &name, Field3D &var) { +void initial_profile(const std::string &name, Field3D &var) { TRACE("initial_profile(string, Field3D)"); Mesh *localmesh = var.getMesh(); @@ -66,7 +66,7 @@ void initial_profile(const string &name, Field3D &var) { FieldFactory f(localmesh); - string function; + std::string function; VAROPTION(varOpts, function, "0.0"); // Create a 3D variable @@ -79,7 +79,7 @@ void initial_profile(const string &name, Field3D &var) { } // For 2D variables almost identical, just no z dependence -void initial_profile(const string &name, Field2D &var) { +void initial_profile(const std::string &name, Field2D &var) { CELL_LOC loc = var.getLocation(); @@ -93,7 +93,7 @@ void initial_profile(const string &name, Field2D &var) { FieldFactory f(localmesh); - string function; + std::string function; VAROPTION(varOpts, function, "0.0"); var = f.create2D(function, varOpts, nullptr, loc); @@ -104,7 +104,7 @@ void initial_profile(const string &name, Field2D &var) { var *= scale; } -void initial_profile(const string &name, Vector2D &var) { +void initial_profile(const std::string &name, Vector2D &var) { if(var.covariant) { initial_profile(name + "_x", var.x); initial_profile(name + "_y", var.y); @@ -116,7 +116,7 @@ void initial_profile(const string &name, Vector2D &var) { } } -void initial_profile(const string &name, Vector3D &var) { +void initial_profile(const std::string &name, Vector3D &var) { if(var.covariant) { initial_profile(name + "_x", var.x); initial_profile(name + "_y", var.y); diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index b11636fc33..e76bb2e378 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -249,26 +249,26 @@ bool Datafile::openw(const char *format, ...) { // 2D vectors for(const auto& var : v2d_arr) { - if (!file->addVarField2D(string(var.name)+string("_x"), var.save_repeat)) { + if (!file->addVarField2D(var.name + "_x", var.save_repeat)) { throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); } - if (!file->addVarField2D(string(var.name)+string("_y"), var.save_repeat)) { + if (!file->addVarField2D(var.name + "_y", var.save_repeat)) { throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); } - if (!file->addVarField2D(string(var.name)+string("_y"), var.save_repeat)) { + if (!file->addVarField2D(var.name + "_y", var.save_repeat)) { throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); } } // 3D vectors for(const auto& var : v3d_arr) { - if (!file->addVarField3D(string(var.name)+string("_x"), var.save_repeat)) { + if (!file->addVarField3D(var.name + "_x", var.save_repeat)) { throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); } - if (!file->addVarField3D(string(var.name)+string("_y"), var.save_repeat)) { + if (!file->addVarField3D(var.name + "_y", var.save_repeat)) { throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); } - if (!file->addVarField3D(string(var.name)+string("_y"), var.save_repeat)) { + if (!file->addVarField3D(var.name + "_y", var.save_repeat)) { throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); } } @@ -351,26 +351,26 @@ bool Datafile::opena(const char *format, ...) { // 2D vectors for(const auto& var : v2d_arr) { - if (!file->addVarField2D(string(var.name)+string("_x"), var.save_repeat)) { + if (!file->addVarField2D(var.name + "_x", var.save_repeat)) { throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); } - if (!file->addVarField2D(string(var.name)+string("_y"), var.save_repeat)) { + if (!file->addVarField2D(var.name + "_y", var.save_repeat)) { throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); } - if (!file->addVarField2D(string(var.name)+string("_y"), var.save_repeat)) { + if (!file->addVarField2D(var.name + "_y", var.save_repeat)) { throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); } } // 3D vectors for(const auto& var : v3d_arr) { - if (!file->addVarField3D(string(var.name)+string("_x"), var.save_repeat)) { + if (!file->addVarField3D(var.name + "_x", var.save_repeat)) { throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); } - if (!file->addVarField3D(string(var.name)+string("_y"), var.save_repeat)) { + if (!file->addVarField3D(var.name + "_y", var.save_repeat)) { throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); } - if (!file->addVarField3D(string(var.name)+string("_y"), var.save_repeat)) { + if (!file->addVarField3D(var.name + "_y", var.save_repeat)) { throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); } } @@ -414,9 +414,9 @@ void Datafile::add(int &i, const char *name, bool save_repeat) { TRACE("DataFile::add(int)"); if (!enabled) return; - if (varAdded(string(name))) { + if (varAdded(name)) { // Check if it's the same variable - if (&i == varPtr(string(name))) { + if (&i == varPtr(name)) { output_warn.write("WARNING: variable '%s' added again to Datafile\n", name); } else { throw BoutException("Variable with name '%s' already added to Datafile", name); @@ -426,7 +426,7 @@ void Datafile::add(int &i, const char *name, bool save_repeat) { VarStr d; d.ptr = &i; - d.name = string(name); + d.name = name; d.save_repeat = save_repeat; d.covar = false; @@ -464,9 +464,9 @@ void Datafile::add(BoutReal &r, const char *name, bool save_repeat) { TRACE("DataFile::add(BoutReal)"); if (!enabled) return; - if (varAdded(string(name))) { + if (varAdded(name)) { // Check if it's the same variable - if (&r == varPtr(string(name))) { + if (&r == varPtr(name)) { output_warn.write("WARNING: variable '%s' added again to Datafile\n", name); } else { throw BoutException("Variable with name '%s' already added to Datafile", name); @@ -476,7 +476,7 @@ void Datafile::add(BoutReal &r, const char *name, bool save_repeat) { VarStr d; d.ptr = &r; - d.name = string(name); + d.name = name; d.save_repeat = save_repeat; d.covar = false; @@ -516,9 +516,9 @@ void Datafile::add(Field2D &f, const char *name, bool save_repeat) { TRACE("DataFile::add(Field2D)"); if (!enabled) return; - if (varAdded(string(name))) { + if (varAdded(name)) { // Check if it's the same variable - if (&f == varPtr(string(name))) { + if (&f == varPtr(name)) { output_warn.write("WARNING: variable '%s' added again to Datafile", name); } else { throw BoutException("Variable with name '%s' already added to Datafile", name); @@ -528,7 +528,7 @@ void Datafile::add(Field2D &f, const char *name, bool save_repeat) { VarStr d; d.ptr = &f; - d.name = string(name); + d.name = name; d.save_repeat = save_repeat; d.covar = false; @@ -568,9 +568,9 @@ void Datafile::add(Field3D &f, const char *name, bool save_repeat) { TRACE("DataFile::add(Field3D)"); if (!enabled) return; - if (varAdded(string(name))) { + if (varAdded(name)) { // Check if it's the same variable - if (&f == varPtr(string(name))) { + if (&f == varPtr(name)) { output_warn.write("WARNING: variable '%s' added again to Datafile\n", name); } else { throw BoutException("Variable with name '%s' already added to Datafile", name); @@ -580,7 +580,7 @@ void Datafile::add(Field3D &f, const char *name, bool save_repeat) { VarStr d; d.ptr = &f; - d.name = string(name); + d.name = name; d.save_repeat = save_repeat; d.covar = false; @@ -620,9 +620,9 @@ void Datafile::add(Vector2D &f, const char *name, bool save_repeat) { TRACE("DataFile::add(Vector2D)"); if (!enabled) return; - if (varAdded(string(name))) { + if (varAdded(name)) { // Check if it's the same variable - if (&f == varPtr(string(name))) { + if (&f == varPtr(name)) { output_warn.write("WARNING: variable '%s' added again to Datafile\n", name); } else { throw BoutException("Variable with name '%s' already added to Datafile", name); @@ -632,7 +632,7 @@ void Datafile::add(Vector2D &f, const char *name, bool save_repeat) { VarStr d; d.ptr = &f; - d.name = string(name); + d.name = name; d.save_repeat = save_repeat; d.covar = f.covariant; @@ -658,13 +658,13 @@ void Datafile::add(Vector2D &f, const char *name, bool save_repeat) { file->setLowPrecision(); // Add variables to file - if (!file->addVarField2D(string(name)+string("_x"), save_repeat)) { + if (!file->addVarField2D(d.name + "_x", save_repeat)) { throw BoutException("Failed to add Vector2D variable %s to Datafile", name); } - if (!file->addVarField2D(string(name)+string("_y"), save_repeat)) { + if (!file->addVarField2D(d.name + "_y", save_repeat)) { throw BoutException("Failed to add Vector2D variable %s to Datafile", name); } - if (!file->addVarField2D(string(name)+string("_z"), save_repeat)) { + if (!file->addVarField2D(d.name + "_z", save_repeat)) { throw BoutException("Failed to add Vector2D variable %s to Datafile", name); } @@ -678,9 +678,9 @@ void Datafile::add(Vector3D &f, const char *name, bool save_repeat) { TRACE("DataFile::add(Vector3D)"); if (!enabled) return; - if (varAdded(string(name))) { + if (varAdded(name)) { // Check if it's the same variable - if (&f == varPtr(string(name))) { + if (&f == varPtr(name)) { output_warn.write("WARNING: variable '%s' added again to Datafile\n", name); } else { throw BoutException("Variable with name '%s' already added to Datafile", name); @@ -690,7 +690,7 @@ void Datafile::add(Vector3D &f, const char *name, bool save_repeat) { VarStr d; d.ptr = &f; - d.name = string(name); + d.name = name; d.save_repeat = save_repeat; d.covar = f.covariant; @@ -716,13 +716,13 @@ void Datafile::add(Vector3D &f, const char *name, bool save_repeat) { file->setLowPrecision(); // Add variables to file - if (!file->addVarField3D(string(name)+string("_x"), save_repeat)) { + if (!file->addVarField3D(d.name + "_x", save_repeat)) { throw BoutException("Failed to add Vector3D variable %s to Datafile", name); } - if (!file->addVarField3D(string(name)+string("_y"), save_repeat)) { + if (!file->addVarField3D(d.name + "_y", save_repeat)) { throw BoutException("Failed to add Vector3D variable %s to Datafile", name); } - if (!file->addVarField3D(string(name)+string("_z"), save_repeat)) { + if (!file->addVarField3D(d.name + "_z", save_repeat)) { throw BoutException("Failed to add Vector3D variable %s to Datafile", name); } @@ -808,13 +808,13 @@ bool Datafile::read() { for(const auto& var : v2d_arr) { if(var.covar) { // Reading covariant vector - read_f2d(var.name+string("_x"), &(var.ptr->x), var.save_repeat); - read_f2d(var.name+string("_y"), &(var.ptr->y), var.save_repeat); - read_f2d(var.name+string("_z"), &(var.ptr->z), var.save_repeat); + read_f2d(var.name + "_x", &(var.ptr->x), var.save_repeat); + read_f2d(var.name + "_y", &(var.ptr->y), var.save_repeat); + read_f2d(var.name + "_z", &(var.ptr->z), var.save_repeat); } else { - read_f2d(var.name+string("x"), &(var.ptr->x), var.save_repeat); - read_f2d(var.name+string("y"), &(var.ptr->y), var.save_repeat); - read_f2d(var.name+string("z"), &(var.ptr->z), var.save_repeat); + read_f2d(var.name + "x", &(var.ptr->x), var.save_repeat); + read_f2d(var.name + "y", &(var.ptr->y), var.save_repeat); + read_f2d(var.name + "z", &(var.ptr->z), var.save_repeat); } var.ptr->covariant = var.covar; @@ -824,13 +824,13 @@ bool Datafile::read() { for(const auto& var : v3d_arr) { if(var.covar) { // Reading covariant vector - read_f3d(var.name+string("_x"), &(var.ptr->x), var.save_repeat); - read_f3d(var.name+string("_y"), &(var.ptr->y), var.save_repeat); - read_f3d(var.name+string("_z"), &(var.ptr->z), var.save_repeat); + read_f3d(var.name + "_x", &(var.ptr->x), var.save_repeat); + read_f3d(var.name + "_y", &(var.ptr->y), var.save_repeat); + read_f3d(var.name + "_z", &(var.ptr->z), var.save_repeat); } else { - read_f3d(var.name+string("x"), &(var.ptr->x), var.save_repeat); - read_f3d(var.name+string("y"), &(var.ptr->y), var.save_repeat); - read_f3d(var.name+string("z"), &(var.ptr->z), var.save_repeat); + read_f3d(var.name + "x", &(var.ptr->x), var.save_repeat); + read_f3d(var.name + "y", &(var.ptr->y), var.save_repeat); + read_f3d(var.name + "z", &(var.ptr->z), var.save_repeat); } var.ptr->covariant = var.covar; @@ -892,22 +892,22 @@ bool Datafile::write() { // 2D vectors for(const auto& var : v2d_arr) { Vector2D v = *(var.ptr); - file->setAttribute(var.name+string("_x"), "cell_location", + file->setAttribute(var.name+"_x", "cell_location", CELL_LOC_STRING(v.x.getLocation())); - file->setAttribute(var.name+string("_y"), "cell_location", + file->setAttribute(var.name+"_y", "cell_location", CELL_LOC_STRING(v.y.getLocation())); - file->setAttribute(var.name+string("_z"), "cell_location", + file->setAttribute(var.name+"_z", "cell_location", CELL_LOC_STRING(v.z.getLocation())); } // 3D vectors for(const auto& var : v3d_arr) { Vector3D v = *(var.ptr); - file->setAttribute(var.name+string("_x"), "cell_location", + file->setAttribute(var.name+"_x", "cell_location", CELL_LOC_STRING(v.x.getLocation())); - file->setAttribute(var.name+string("_y"), "cell_location", + file->setAttribute(var.name+"_y", "cell_location", CELL_LOC_STRING(v.y.getLocation())); - file->setAttribute(var.name+string("_z"), "cell_location", + file->setAttribute(var.name+"_z", "cell_location", CELL_LOC_STRING(v.z.getLocation())); } } @@ -939,17 +939,17 @@ bool Datafile::write() { Vector2D v = *(var.ptr); v.toCovariant(); - write_f2d(var.name+string("_x"), &(v.x), var.save_repeat); - write_f2d(var.name+string("_y"), &(v.y), var.save_repeat); - write_f2d(var.name+string("_z"), &(v.z), var.save_repeat); + write_f2d(var.name+"_x", &(v.x), var.save_repeat); + write_f2d(var.name+"_y", &(v.y), var.save_repeat); + write_f2d(var.name+"_z", &(v.z), var.save_repeat); } else { // Writing contravariant vector Vector2D v = *(var.ptr); v.toContravariant(); - write_f2d(var.name+string("x"), &(v.x), var.save_repeat); - write_f2d(var.name+string("y"), &(v.y), var.save_repeat); - write_f2d(var.name+string("z"), &(v.z), var.save_repeat); + write_f2d(var.name+"x", &(v.x), var.save_repeat); + write_f2d(var.name+"y", &(v.y), var.save_repeat); + write_f2d(var.name+"z", &(v.z), var.save_repeat); } } @@ -960,17 +960,17 @@ bool Datafile::write() { Vector3D v = *(var.ptr); v.toCovariant(); - write_f3d(var.name+string("_x"), &(v.x), var.save_repeat); - write_f3d(var.name+string("_y"), &(v.y), var.save_repeat); - write_f3d(var.name+string("_z"), &(v.z), var.save_repeat); + write_f3d(var.name+"_x", &(v.x), var.save_repeat); + write_f3d(var.name+"_y", &(v.y), var.save_repeat); + write_f3d(var.name+"_z", &(v.z), var.save_repeat); } else { // Writing contravariant vector Vector3D v = *(var.ptr); v.toContravariant(); - write_f3d(var.name+string("x"), &(v.x), var.save_repeat); - write_f3d(var.name+string("y"), &(v.y), var.save_repeat); - write_f3d(var.name+string("z"), &(v.z), var.save_repeat); + write_f3d(var.name+"x", &(v.x), var.save_repeat); + write_f3d(var.name+"y", &(v.y), var.save_repeat); + write_f3d(var.name+"z", &(v.z), var.save_repeat); } } @@ -1006,7 +1006,7 @@ bool Datafile::write(const char *format, ...) const { return ret; } -void Datafile::setAttribute(const string &varname, const string &attrname, const string &text) { +void Datafile::setAttribute(const std::string &varname, const std::string &attrname, const std::string &text) { TRACE("Datafile::setAttribute(string, string, string)"); @@ -1035,7 +1035,7 @@ void Datafile::setAttribute(const string &varname, const string &attrname, const } } -void Datafile::setAttribute(const string &varname, const string &attrname, int value) { +void Datafile::setAttribute(const std::string &varname, const std::string &attrname, int value) { TRACE("Datafile::setAttribute(string, string, int)"); @@ -1066,7 +1066,7 @@ void Datafile::setAttribute(const string &varname, const string &attrname, int v ///////////////////////////////////////////////////////////// -bool Datafile::read_f2d(const string &name, Field2D *f, bool save_repeat) { +bool Datafile::read_f2d(const std::string &name, Field2D *f, bool save_repeat) { f->allocate(); if(save_repeat) { @@ -1094,7 +1094,7 @@ bool Datafile::read_f2d(const string &name, Field2D *f, bool save_repeat) { return true; } -bool Datafile::read_f3d(const string &name, Field3D *f, bool save_repeat) { +bool Datafile::read_f3d(const std::string &name, Field3D *f, bool save_repeat) { f->allocate(); if(save_repeat) { @@ -1128,7 +1128,7 @@ bool Datafile::read_f3d(const string &name, Field3D *f, bool save_repeat) { return true; } -bool Datafile::write_int(const string &name, int *f, bool save_repeat) { +bool Datafile::write_int(const std::string &name, int *f, bool save_repeat) { if(save_repeat) { return file->write_rec(f, name); }else { @@ -1136,7 +1136,7 @@ bool Datafile::write_int(const string &name, int *f, bool save_repeat) { } } -bool Datafile::write_real(const string &name, BoutReal *f, bool save_repeat) { +bool Datafile::write_real(const std::string &name, BoutReal *f, bool save_repeat) { if(save_repeat) { return file->write_rec(f, name); }else { @@ -1144,7 +1144,7 @@ bool Datafile::write_real(const string &name, BoutReal *f, bool save_repeat) { } } -bool Datafile::write_f2d(const string &name, Field2D *f, bool save_repeat) { +bool Datafile::write_f2d(const std::string &name, Field2D *f, bool save_repeat) { if (!f->isAllocated()) { throw BoutException("Datafile::write_f2d: Field2D '%s' is not allocated!", name.c_str()); } @@ -1160,7 +1160,7 @@ bool Datafile::write_f2d(const string &name, Field2D *f, bool save_repeat) { return true; } -bool Datafile::write_f3d(const string &name, Field3D *f, bool save_repeat) { +bool Datafile::write_f3d(const std::string &name, Field3D *f, bool save_repeat) { if (!f->isAllocated()) { throw BoutException("Datafile::write_f3d: Field3D '%s' is not allocated!", name.c_str()); } @@ -1180,7 +1180,7 @@ bool Datafile::write_f3d(const string &name, Field3D *f, bool save_repeat) { } } -bool Datafile::varAdded(const string &name) { +bool Datafile::varAdded(const std::string &name) { for(const auto& var : int_arr ) { if(name == var.name) return true; @@ -1213,7 +1213,7 @@ bool Datafile::varAdded(const string &name) { return false; } -void *Datafile::varPtr(const string &name) { +void *Datafile::varPtr(const std::string &name) { for (const auto &var : int_arr) { if (name == var.name) { return static_cast(var.ptr); diff --git a/src/fileio/dataformat.cxx b/src/fileio/dataformat.cxx index 6cdb899b96..2fa1d9dd0d 100644 --- a/src/fileio/dataformat.cxx +++ b/src/fileio/dataformat.cxx @@ -3,21 +3,21 @@ #include #include -bool DataFormat::openr(const string &name, int mype) { +bool DataFormat::openr(const std::string &name, int mype) { // Split into base name and extension size_t pos = name.find_last_of('.'); - string base(name.substr(0, pos)); - string ext(name.substr(pos+1)); + std::string base(name.substr(0, pos)); + std::string ext(name.substr(pos+1)); // Insert the processor number between base and extension return openr(base + "." + toString(mype) + "." + ext); } -bool DataFormat::openw(const string &name, int mype, bool append) { +bool DataFormat::openw(const std::string &name, int mype, bool append) { // Split into base name and extension size_t pos = name.find_last_of('.'); - string base(name.substr(0, pos)); - string ext(name.substr(pos+1)); + std::string base(name.substr(0, pos)); + std::string ext(name.substr(pos+1)); // Insert the processor number between base and extension return openw(base + "." + toString(mype) + "." + ext, append); diff --git a/src/fileio/impls/emptyformat.hxx b/src/fileio/impls/emptyformat.hxx index baba9d6fbb..e7e93604ba 100644 --- a/src/fileio/impls/emptyformat.hxx +++ b/src/fileio/impls/emptyformat.hxx @@ -36,53 +36,53 @@ class EmptyFormat; class EmptyFormat { EmptyFormat() {throw BoutException("File format not enabled!");} - bool openr(const string &UNUSED(name)) {return false; } - bool openw(const string &UNUSED(name), bool UNUSED(append)) {return false; } + bool openr(const std::string &UNUSED(name)) {return false; } + bool openw(const std::string &UNUSED(name), bool UNUSED(append)) {return false; } bool is_valid() {return false;} void close() {} - const vector getSize(const char *UNUSED(var)) {vector tmp; return tmp;} - const vector getSize(const string &UNUSED(var)) {vector tmp; return tmp;} + const std::vector getSize(const char *UNUSED(var)) {std::vector tmp; return tmp;} + const std::vector getSize(const std::string &UNUSED(var)) {std::vector tmp; return tmp;} bool setOrigin(int UNUSED(x) = 0, int UNUSED(y) = 0, int UNUSED(z) = 0) {return false;} bool setRecord(int UNUSED(t)) {return false;} bool read(int *UNUSED(var), const char *UNUSED(name), int UNUSED(lx) = 1, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} - bool read(int *UNUSED(var), const string &UNUSED(name), int UNUSED(lx) = 1, + bool read(int *UNUSED(var), const std::string &UNUSED(name), int UNUSED(lx) = 1, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} bool read(BoutReal *UNUSED(var), const char *UNUSED(name), int UNUSED(lx) = 1, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} - bool read(BoutReal *UNUSED(var), const string &UNUSED(name), int UNUSED(lx) = 1, + bool read(BoutReal *UNUSED(var), const std::string &UNUSED(name), int UNUSED(lx) = 1, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} bool write(int *UNUSED(var), const char *UNUSED(name), int UNUSED(lx) = 0, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} - bool write(int *UNUSED(var), const string &UNUSED(name), int UNUSED(lx) = 0, + bool write(int *UNUSED(var), const std::string &UNUSED(name), int UNUSED(lx) = 0, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} bool write(BoutReal *UNUSED(var), const char *UNUSED(name), int UNUSED(lx) = 0, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} - bool write(BoutReal *UNUSED(var), const string &UNUSED(name), int UNUSED(lx) = 0, + bool write(BoutReal *UNUSED(var), const std::string &UNUSED(name), int UNUSED(lx) = 0, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} bool read_rec(int *UNUSED(var), const char *UNUSED(name), int UNUSED(lx) = 1, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} - bool read_rec(int *UNUSED(var), const string &UNUSED(name), int UNUSED(lx) = 1, + bool read_rec(int *UNUSED(var), const std::string &UNUSED(name), int UNUSED(lx) = 1, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} bool read_rec(BoutReal *UNUSED(var), const char *UNUSED(name), int UNUSED(lx) = 1, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} - bool read_rec(BoutReal *UNUSED(var), const string &UNUSED(name), int UNUSED(lx) = 1, + bool read_rec(BoutReal *UNUSED(var), const std::string &UNUSED(name), int UNUSED(lx) = 1, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} bool write_rec(int *UNUSED(var), const char *UNUSED(name), int UNUSED(lx) = 0, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} - bool write_rec(int *UNUSED(var), const string &UNUSED(name), int UNUSED(lx) = 0, + bool write_rec(int *UNUSED(var), const std::string &UNUSED(name), int UNUSED(lx) = 0, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} bool write_rec(BoutReal *UNUSED(var), const char *UNUSED(name), int UNUSED(lx) = 0, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} - bool write_rec(BoutReal *UNUSED(var), const string &UNUSED(name), int UNUSED(lx) = 0, + bool write_rec(BoutReal *UNUSED(var), const std::string &UNUSED(name), int UNUSED(lx) = 0, int UNUSED(ly) = 0, int UNUSED(lz) = 0) {return false;} }; diff --git a/src/fileio/impls/hdf5/h5_format.cxx b/src/fileio/impls/hdf5/h5_format.cxx index 378220cfd4..405b32e5ae 100644 --- a/src/fileio/impls/hdf5/h5_format.cxx +++ b/src/fileio/impls/hdf5/h5_format.cxx @@ -169,10 +169,10 @@ void H5Format::flush() { } } -const vector H5Format::getSize(const char *name) { +const std::vector H5Format::getSize(const char *name) { TRACE("H5Format::getSize"); - vector size; + std::vector size; if(!is_valid()) return size; @@ -220,7 +220,7 @@ const vector H5Format::getSize(const char *name) { return size; } -const vector H5Format::getSize(const string &var) { +const std::vector H5Format::getSize(const std::string &var) { return getSize(var.c_str()); } @@ -254,7 +254,7 @@ bool H5Format::setRecord(int t) { } // Add a variable to the file -bool H5Format::addVar(const string &name, bool repeat, hid_t write_hdf5_type, int nd) { +bool H5Format::addVar(const std::string &name, bool repeat, hid_t write_hdf5_type, int nd) { hid_t dataSet = H5Dopen(dataFile, name.c_str(), H5P_DEFAULT); if (dataSet >= 0) { // >=0 means variable already exists, so return. if (H5Dclose(dataSet) < 0) @@ -374,21 +374,21 @@ bool H5Format::addVar(const string &name, bool repeat, hid_t write_hdf5_type, in return true; } -bool H5Format::addVarInt(const string &name, bool repeat) { +bool H5Format::addVarInt(const std::string &name, bool repeat) { return addVar(name, repeat, H5T_NATIVE_INT, 0); } -bool H5Format::addVarBoutReal(const string &name, bool repeat) { +bool H5Format::addVarBoutReal(const std::string &name, bool repeat) { auto h5_float_type = lowPrecision ? H5T_NATIVE_FLOAT : H5T_NATIVE_DOUBLE; return addVar(name, repeat, h5_float_type, 0); } -bool H5Format::addVarField2D(const string &name, bool repeat) { +bool H5Format::addVarField2D(const std::string &name, bool repeat) { auto h5_float_type = lowPrecision ? H5T_NATIVE_FLOAT : H5T_NATIVE_DOUBLE; return addVar(name, repeat, h5_float_type, 2); } -bool H5Format::addVarField3D(const string &name, bool repeat) { +bool H5Format::addVarField3D(const std::string &name, bool repeat) { auto h5_float_type = lowPrecision ? H5T_NATIVE_FLOAT : H5T_NATIVE_DOUBLE; return addVar(name, repeat, h5_float_type, 3); } @@ -397,7 +397,7 @@ bool H5Format::read(int *data, const char *name, int lx, int ly, int lz) { return read(data, H5T_NATIVE_INT, name, lx, ly, lz); } -bool H5Format::read(int *var, const string &name, int lx, int ly, int lz) { +bool H5Format::read(int *var, const std::string &name, int lx, int ly, int lz) { return read(var, name.c_str(), lx, ly, lz); } @@ -405,7 +405,7 @@ bool H5Format::read(BoutReal *data, const char *name, int lx, int ly, int lz) { return read(data, H5T_NATIVE_DOUBLE, name, lx, ly, lz); } -bool H5Format::read(BoutReal *var, const string &name, int lx, int ly, int lz) { +bool H5Format::read(BoutReal *var, const std::string &name, int lx, int ly, int lz) { return read(var, name.c_str(), lx, ly, lz); } @@ -468,7 +468,7 @@ bool H5Format::write(int *data, const char *name, int lx, int ly, int lz) { return write(data, H5T_NATIVE_INT, name, lx, ly, lz); } -bool H5Format::write(int *var, const string &name, int lx, int ly, int lz) { +bool H5Format::write(int *var, const std::string &name, int lx, int ly, int lz) { return write(var, name.c_str(), lx, ly, lz); } @@ -498,7 +498,7 @@ bool H5Format::write(BoutReal *data, const char *name, int lx, int ly, int lz) { } -bool H5Format::write(BoutReal *var, const string &name, int lx, int ly, int lz) { +bool H5Format::write(BoutReal *var, const std::string &name, int lx, int ly, int lz) { return write(var, name.c_str(), lx, ly, lz); } @@ -580,7 +580,7 @@ bool H5Format::read_rec(int *data, const char *name, int lx, int ly, int lz) { return read_rec(data, H5T_NATIVE_INT, name, lx, ly, lz); } -bool H5Format::read_rec(int *var, const string &name, int lx, int ly, int lz) { +bool H5Format::read_rec(int *var, const std::string &name, int lx, int ly, int lz) { return read_rec(var, name.c_str(), lx, ly, lz); } @@ -590,7 +590,7 @@ bool H5Format::read_rec(BoutReal *data, const char *name, int lx, int ly, int lz } -bool H5Format::read_rec(BoutReal *var, const string &name, int lx, int ly, int lz) { +bool H5Format::read_rec(BoutReal *var, const std::string &name, int lx, int ly, int lz) { return read_rec(var, name.c_str(), lx, ly, lz); } @@ -674,7 +674,7 @@ bool H5Format::write_rec(int *data, const char *name, int lx, int ly, int lz) { return write_rec(data, H5T_NATIVE_INT, name, lx, ly, lz); } -bool H5Format::write_rec(int *var, const string &name, int lx, int ly, int lz) { +bool H5Format::write_rec(int *var, const std::string &name, int lx, int ly, int lz) { return write_rec(var, name.c_str(), lx, ly, lz); } @@ -701,7 +701,7 @@ bool H5Format::write_rec(BoutReal *data, const char *name, int lx, int ly, int l return write_rec(data, H5T_NATIVE_DOUBLE, name, lx, ly, lz); } -bool H5Format::write_rec(BoutReal *var, const string &name, int lx, int ly, int lz) { +bool H5Format::write_rec(BoutReal *var, const std::string &name, int lx, int ly, int lz) { return write_rec(var, name.c_str(), lx, ly, lz); } diff --git a/src/fileio/impls/hdf5/h5_format.hxx b/src/fileio/impls/hdf5/h5_format.hxx index bb2fd9e07e..11cd3b8a70 100644 --- a/src/fileio/impls/hdf5/h5_format.hxx +++ b/src/fileio/impls/hdf5/h5_format.hxx @@ -52,14 +52,11 @@ class H5Format; #include #include -using std::string; -using std::map; - class H5Format : public DataFormat { public: H5Format(bool parallel_in = false); H5Format(const char *name, bool parallel_in = false); - H5Format(const string &name, bool parallel_in = false) : H5Format(name.c_str(), parallel_in) {} + H5Format(const std::string &name, bool parallel_in = false) : H5Format(name.c_str(), parallel_in) {} ~H5Format(); using DataFormat::openr; @@ -75,8 +72,8 @@ class H5Format : public DataFormat { const char* filename() { return fname; }; - const vector getSize(const char *var) override; - const vector getSize(const string &var) override; + const std::vector getSize(const char *var) override; + const std::vector getSize(const std::string &var) override; // Set the origin for all subsequent calls bool setGlobalOrigin(int x = 0, int y = 0, int z = 0) override; @@ -84,34 +81,34 @@ class H5Format : public DataFormat { bool setRecord(int t) override; // negative -> latest // Add a variable to the file - bool addVarInt(const string &name, bool repeat) override; - bool addVarBoutReal(const string &name, bool repeat) override; - bool addVarField2D(const string &name, bool repeat) override; - bool addVarField3D(const string &name, bool repeat) override; + bool addVarInt(const std::string &name, bool repeat) override; + bool addVarBoutReal(const std::string &name, bool repeat) override; + bool addVarField2D(const std::string &name, bool repeat) override; + bool addVarField3D(const std::string &name, bool repeat) override; // Read / Write simple variables up to 3D bool read(int *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; - bool read(int *var, const string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool read(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; - bool read(BoutReal *var, const string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool write(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; - bool write(int *var, const string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; bool write(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; - bool write(BoutReal *var, const string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; // Read / Write record-based variables bool read_rec(int *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; - bool read_rec(int *var, const string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read_rec(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool read_rec(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; - bool read_rec(BoutReal *var, const string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read_rec(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool write_rec(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; - bool write_rec(int *var, const string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write_rec(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; - bool write_rec(BoutReal *var, const string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write_rec(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; void setLowPrecision() override { lowPrecision = true; } @@ -140,7 +137,7 @@ class H5Format : public DataFormat { hsize_t chunk_length; - bool addVar(const string &name, bool repeat, hid_t write_hdf5_type, int nd); + bool addVar(const std::string &name, bool repeat, hid_t write_hdf5_type, int nd); bool read(void *var, hid_t hdf5_type, const char *name, int lx = 1, int ly = 0, int lz = 0); bool write(void *var, hid_t mem_hdf5_type, const char *name, int lx = 0, int ly = 0, int lz = 0); bool read_rec(void *var, hid_t hdf5_type, const char *name, int lx = 1, int ly = 0, int lz = 0); diff --git a/src/fileio/impls/netcdf4/ncxx4.cxx b/src/fileio/impls/netcdf4/ncxx4.cxx index 3673e577da..d69bbd31e1 100644 --- a/src/fileio/impls/netcdf4/ncxx4.cxx +++ b/src/fileio/impls/netcdf4/ncxx4.cxx @@ -267,13 +267,13 @@ void Ncxx4::close() { void Ncxx4::flush() { } -const vector Ncxx4::getSize(const char *name) { +const std::vector Ncxx4::getSize(const char *name) { TRACE("Ncxx4::getSize"); #ifdef NCDF_VERBOSE output.write("Ncxx4:: getSize(%s)\n", name); #endif - vector size; + std::vector size; if(!is_valid()) return size; @@ -437,9 +437,9 @@ bool Ncxx4::read(int *data, const char *name, int lx, int ly, int lz) { return false; } - vector start(3); + std::vector start(3); start[0] = x0; start[1] = y0; start[2] = z0; - vector counts(3); + std::vector counts(3); counts[0] = lx; counts[1] = ly; counts[2] = lz; var.getVar(start, counts, data); @@ -469,9 +469,9 @@ bool Ncxx4::read(BoutReal *data, const char *name, int lx, int ly, int lz) { return false; } - vector start(3); + std::vector start(3); start[0] = x0; start[1] = y0; start[2] = z0; - vector counts(3); + std::vector counts(3); counts[0] = lx; counts[1] = ly; counts[2] = lz; var.getVar(start, counts, data); @@ -505,9 +505,9 @@ bool Ncxx4::write(int *data, const char *name, int lx, int ly, int lz) { output.write("Ncxx4:: write { Writing Variable } \n"); #endif - vector start(3); + std::vector start(3); start[0] = x0; start[1] = y0; start[2] = z0; - vector counts(3); + std::vector counts(3); counts[0] = lx; counts[1] = ly; counts[2] = lz; var.putVar(start, counts, data); @@ -541,9 +541,9 @@ bool Ncxx4::write(BoutReal *data, const char *name, int lx, int ly, int lz) { return false; } - vector start(3); + std::vector start(3); start[0] = x0; start[1] = y0; start[2] = z0; - vector counts(3); + std::vector counts(3); counts[0] = lx; counts[1] = ly; counts[2] = lz; if(lowPrecision) { @@ -594,9 +594,9 @@ bool Ncxx4::read_rec(int *data, const char *name, int lx, int ly, int lz) { // NOTE: Probably should do something here to check t0 - vector start(4); + std::vector start(4); start[0] = t0; start[1] = x0; start[2] = y0; start[3] = z0; - vector counts(4); + std::vector counts(4); counts[0] = 1; counts[1] = lx; counts[2] = ly; counts[3] = lz; var.getVar(start, counts, data); @@ -625,9 +625,9 @@ bool Ncxx4::read_rec(BoutReal *data, const char *name, int lx, int ly, int lz) { // NOTE: Probably should do something here to check t0 - vector start(4); + std::vector start(4); start[0] = t0; start[1] = x0; start[2] = y0; start[3] = z0; - vector counts(4); + std::vector counts(4); counts[0] = 1; counts[1] = lx; counts[2] = ly; counts[3] = lz; var.getVar(start, counts, data); @@ -662,9 +662,9 @@ bool Ncxx4::write_rec(int *data, const char *name, int lx, int ly, int lz) { } } - vector start(1); + std::vector start(1); start[0] = rec_nr[name]; - vector counts(1); + std::vector counts(1); counts[0] = 1; #ifdef NCDF_VERBOSE @@ -732,9 +732,9 @@ bool Ncxx4::write_rec(BoutReal *data, const char *name, int lx, int ly, int lz) data[i] = 0.0; } - vector start(4); + std::vector start(4); start[0] = t; start[1] = x0; start[2] = y0; start[3] = z0; - vector counts(4); + std::vector counts(4); counts[0] = 1; counts[1] = lx; counts[2] = ly; counts[3] = lz; // Add the record @@ -806,7 +806,7 @@ bool Ncxx4::getAttribute(const std::string &varname, const std::string &attrname } // Check if attribute exists without throwing exception when it doesn't - map varAtts_list = var.getAtts(); + std::map varAtts_list = var.getAtts(); if (varAtts_list.find(attrname) == varAtts_list.end()) { return false; } else { @@ -826,7 +826,7 @@ bool Ncxx4::getAttribute(const std::string &varname, const std::string &attrname } // Check if attribute exists without throwing exception when it doesn't - map varAtts_list = var.getAtts(); + std::map varAtts_list = var.getAtts(); if (varAtts_list.find(attrname) == varAtts_list.end()) { return false; } else { @@ -842,15 +842,15 @@ bool Ncxx4::getAttribute(const std::string &varname, const std::string &attrname * Private functions ***************************************************************************/ -vector Ncxx4::getDimVec(int nd) { - vector vec(nd); +std::vector Ncxx4::getDimVec(int nd) { + std::vector vec(nd); for(int i=0;i Ncxx4::getRecDimVec(int nd) { - vector vec(nd); +std::vector Ncxx4::getRecDimVec(int nd) { + std::vector vec(nd); for(int i=0;i latest // Add a variable to the file - bool addVarInt(const string &name, bool repeat) override; - bool addVarBoutReal(const string &name, bool repeat) override; - bool addVarField2D(const string &name, bool repeat) override; - bool addVarField3D(const string &name, bool repeat) override; + bool addVarInt(const std::string &name, bool repeat) override; + bool addVarBoutReal(const std::string &name, bool repeat) override; + bool addVarField2D(const std::string &name, bool repeat) override; + bool addVarField3D(const std::string &name, bool repeat) override; // Read / Write simple variables up to 3D diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.cxx b/src/invert/laplace/impls/petsc/petsc_laplace.cxx index 27f01a3161..6429e61887 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.cxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.cxx @@ -275,7 +275,7 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc) : KSPCreate( comm, &ksp ); // Get KSP Solver Type (Generalizes Minimal RESidual is the default) - string type; + std::string type; opts->get("ksptype", ksptype, KSP_GMRES); // Get preconditioner type diff --git a/src/invert/laplace/laplacefactory.cxx b/src/invert/laplace/laplacefactory.cxx index 6a04e6e68e..21db91329c 100644 --- a/src/invert/laplace/laplacefactory.cxx +++ b/src/invert/laplace/laplacefactory.cxx @@ -41,7 +41,7 @@ Laplacian* LaplaceFactory::createLaplacian(Options *options, const CELL_LOC loc) if (options == nullptr) options = Options::getRoot()->getSection("laplace"); - string type; + std::string type; if(mesh->firstX() && mesh->lastX()) { // Can use serial algorithm diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index 6793880b8d..fc046fd7b1 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -236,11 +236,11 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat OPTION(opt, maxits, 100000); // Maximum iterations // Get KSP Solver Type - string ksptype; + std::string ksptype; opt->get("ksptype", ksptype, "gmres"); // Get PC type - string pctype; + std::string pctype; opt->get("pctype", pctype, "none", true); KSPSetType( ksp, ksptype.c_str() ); diff --git a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx index 6095919064..962fe8ad46 100644 --- a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx +++ b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx @@ -130,14 +130,14 @@ LaplaceXZpetsc::LaplaceXZpetsc(Mesh *m, Options *opt, const CELL_LOC loc) OPTION(opt, maxits, 100000); // Maximum iterations // Get KSP Solver Type - string ksptype; + std::string ksptype; opt->get("ksptype", ksptype, "gmres"); // Get PC type - string pctype; + std::string pctype; opt->get("pctype", pctype, "lu", true); - string factor_package; + std::string factor_package; opt->get("factor_package", factor_package, "petsc", true); // Get MPI communicator diff --git a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.hxx b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.hxx index 8120a1922d..6c40e2bac6 100644 --- a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.hxx +++ b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.hxx @@ -71,7 +71,7 @@ private: Mat MatP; ///< Matrix for preconditioner KSP ksp; ///< Krylov Subspace solver context }; - vector slice; + std::vector slice; Vec xs, bs; ///< Solution and RHS vectors diff --git a/src/invert/laplacexz/laplacexz.cxx b/src/invert/laplacexz/laplacexz.cxx index f760e3870b..b3a066105c 100644 --- a/src/invert/laplacexz/laplacexz.cxx +++ b/src/invert/laplacexz/laplacexz.cxx @@ -10,7 +10,7 @@ LaplaceXZ* LaplaceXZ::create(Mesh *m, Options *options, const CELL_LOC loc) { if (options == nullptr) options = Options::getRoot()->getSection("laplacexz"); - string type; + std::string type; options->get("type", type, "cyclic"); if(strcasecmp(type.c_str(), "cyclic") == 0) { diff --git a/src/invert/parderiv/parderiv_factory.cxx b/src/invert/parderiv/parderiv_factory.cxx index 1408dd8960..ee1211b76c 100644 --- a/src/invert/parderiv/parderiv_factory.cxx +++ b/src/invert/parderiv/parderiv_factory.cxx @@ -47,7 +47,7 @@ InvertPar* ParDerivFactory::createInvertPar(const char* type, Options *opt) { } InvertPar* ParDerivFactory::createInvertPar(Options *opts) { - string type; + std::string type; opts->get("type", type, "cyclic"); return createInvertPar(type.c_str(), opts); diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 5d4d2773a1..5c7146ff27 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -31,7 +31,7 @@ void verifyNumPoints(BoundaryRegion *region, int ptsRequired) { #else int ptsAvailGlobal, ptsAvailLocal, ptsAvail; - string side, gridType; + std::string side, gridType; //Initialise var in case of no match and CHECK<=2 ptsAvail = ptsRequired; //Ensures test passes without exception @@ -103,7 +103,7 @@ void verifyNumPoints(BoundaryRegion *region, int ptsRequired) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDirichlet::clone(BoundaryRegion *region, const list &args){ +BoundaryOp* BoundaryDirichlet::clone(BoundaryRegion *region, const std::list &args){ verifyNumPoints(region,1); std::shared_ptr newgen; @@ -556,7 +556,7 @@ void BoundaryDirichlet::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// // New implementation, accurate to higher order -BoundaryOp* BoundaryDirichlet_O3::clone(BoundaryRegion *region, const list &args){ +BoundaryOp* BoundaryDirichlet_O3::clone(BoundaryRegion *region, const std::list &args){ verifyNumPoints(region,2); std::shared_ptr newgen = nullptr; if(!args.empty()) { @@ -971,7 +971,7 @@ void BoundaryDirichlet_O3::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// // Extrapolate to calculate boundary cell to 4th-order -BoundaryOp* BoundaryDirichlet_O4::clone(BoundaryRegion *region, const list &args){ +BoundaryOp* BoundaryDirichlet_O4::clone(BoundaryRegion *region, const std::list &args){ verifyNumPoints(region,3); std::shared_ptr newgen = nullptr; if(!args.empty()) { @@ -1398,7 +1398,7 @@ void BoundaryDirichlet_O4::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDirichlet_2ndOrder::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryDirichlet_2ndOrder::clone(BoundaryRegion *region, const std::list &args) { output << "WARNING: Use of boundary condition \"dirichlet_2ndorder\" is deprecated!\n"; output << " Consider using \"dirichlet\" instead\n"; verifyNumPoints(region,2); @@ -1452,7 +1452,7 @@ void BoundaryDirichlet_2ndOrder::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDirichlet_4thOrder::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryDirichlet_4thOrder::clone(BoundaryRegion *region, const std::list &args) { verifyNumPoints(region,4); if(!args.empty()) { // First argument should be a value @@ -1494,7 +1494,7 @@ void BoundaryDirichlet_4thOrder::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const std::list &args) { verifyNumPoints(region,1); if(!args.empty()) { output << "WARNING: arguments is set to BoundaryNeumann None Zero Gradient\n"; @@ -1591,7 +1591,7 @@ void BoundaryNeumann_NonOrthogonal::apply(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann2::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryNeumann2::clone(BoundaryRegion *region, const std::list &args) { output << "WARNING: Use of boundary condition \"neumann2\" is deprecated!\n"; output << " Consider using \"neumann\" instead\n"; verifyNumPoints(region,2); @@ -1615,7 +1615,7 @@ void BoundaryNeumann2::apply(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryNeumann_2ndOrder::clone(BoundaryRegion *region, const std::list &args) { output << "WARNING: Use of boundary condition \"neumann_2ndorder\" is deprecated!\n"; output << " Consider using \"neumann\" instead\n"; #ifdef BOUNDARY_CONDITIONS_UPGRADE_EXTRAPOLATE_FOR_2ND_ORDER @@ -1679,7 +1679,7 @@ void BoundaryNeumann_2ndOrder::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann::clone(BoundaryRegion *region, const list &args){ +BoundaryOp* BoundaryNeumann::clone(BoundaryRegion *region, const std::list &args){ verifyNumPoints(region,1); std::shared_ptr newgen = nullptr; if(!args.empty()) { @@ -2106,7 +2106,7 @@ void BoundaryNeumann::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann_O4::clone(BoundaryRegion *region, const list &args){ +BoundaryOp* BoundaryNeumann_O4::clone(BoundaryRegion *region, const std::list &args){ std::shared_ptr newgen = nullptr; if(!args.empty()) { // First argument should be an expression @@ -2240,7 +2240,7 @@ void BoundaryNeumann_O4::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumann_4thOrder::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryNeumann_4thOrder::clone(BoundaryRegion *region, const std::list &args) { verifyNumPoints(region,4); if(!args.empty()) { // First argument should be a value @@ -2288,7 +2288,7 @@ void BoundaryNeumann_4thOrder::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryNeumannPar::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryNeumannPar::clone(BoundaryRegion *region, const std::list &args) { verifyNumPoints(region,1); if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryNeumann2\n"; @@ -2313,8 +2313,9 @@ void BoundaryNeumannPar::apply(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryRobin::clone(BoundaryRegion *region, const list &args) { - verifyNumPoints(region,1); +BoundaryOp *BoundaryRobin::clone(BoundaryRegion *region, + const std::list &args) { + verifyNumPoints(region, 1); BoutReal a = 0.5, b = 1.0, g = 0.; auto it = args.begin(); @@ -2389,7 +2390,7 @@ void BoundaryConstGradient::apply(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryConstGradient::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryConstGradient::clone(BoundaryRegion *region, const std::list &args) { verifyNumPoints(region,2); if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryConstGradient\n"; @@ -2399,7 +2400,7 @@ BoundaryOp* BoundaryConstGradient::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryZeroLaplace::clone(BoundaryRegion *region, const std::list &args) { verifyNumPoints(region,2); if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryZeroLaplace\n"; @@ -2485,7 +2486,7 @@ void BoundaryZeroLaplace::apply(Field3D &f) { /////////////////////////////////////////////////////////////// BoundaryOp *BoundaryZeroLaplace2::clone(BoundaryRegion *region, - const list &args) { + const std::list &args) { verifyNumPoints(region, 3); if (!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryZeroLaplace2\n"; @@ -2572,7 +2573,7 @@ void BoundaryZeroLaplace2::apply(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryConstLaplace::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryConstLaplace::clone(BoundaryRegion *region, const std::list &args) { verifyNumPoints(region,2); if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryConstLaplace\n"; @@ -2672,7 +2673,7 @@ void BoundaryConstLaplace::apply(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryDivCurl::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryDivCurl::clone(BoundaryRegion *region, const std::list &args) { if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryDivCurl\n"; } @@ -2749,7 +2750,7 @@ void BoundaryDivCurl::apply(Vector3D &var) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryFree::clone(BoundaryRegion *region, const list &args) { +BoundaryOp* BoundaryFree::clone(BoundaryRegion *region, const std::list &args) { if(!args.empty()) { // First argument should be a value val = stringToReal(args.front()); @@ -2780,7 +2781,7 @@ void BoundaryFree::apply_ddt(Field3D &UNUSED(f)) { // 2nd order extrapolation: -BoundaryOp* BoundaryFree_O2::clone(BoundaryRegion *region, const list &args){ +BoundaryOp* BoundaryFree_O2::clone(BoundaryRegion *region, const std::list &args){ verifyNumPoints(region,2); if(!args.empty()) { output << "WARNING: Ignoring arguments to BoundaryFree\n"; @@ -3018,7 +3019,7 @@ void BoundaryFree_O2::apply_ddt(Field3D &f) { ////////////////////////////////// // Third order extrapolation: ////////////////////////////////// -BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const list &args){ +BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const std::list &args){ verifyNumPoints(region,3); if(!args.empty()) { @@ -3263,7 +3264,7 @@ void BoundaryFree_O3::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryRelax::cloneMod(BoundaryOp *operation, const list &args) { +BoundaryOp* BoundaryRelax::cloneMod(BoundaryOp *operation, const std::list &args) { BoundaryRelax* result = new BoundaryRelax(operation, r); if(!args.empty()) { @@ -3318,7 +3319,7 @@ void BoundaryRelax::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryWidth::cloneMod(BoundaryOp *operation, const list &args) { +BoundaryOp* BoundaryWidth::cloneMod(BoundaryOp *operation, const std::list &args) { BoundaryWidth* result = new BoundaryWidth(operation, width); if(args.empty()) { @@ -3362,7 +3363,7 @@ void BoundaryWidth::apply_ddt(Field3D &f) { } /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryToFieldAligned::cloneMod(BoundaryOp *operation, const list &args) { +BoundaryOp* BoundaryToFieldAligned::cloneMod(BoundaryOp *operation, const std::list &args) { BoundaryToFieldAligned* result = new BoundaryToFieldAligned(operation); if(!args.empty()) { @@ -3405,7 +3406,7 @@ void BoundaryToFieldAligned::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// -BoundaryOp* BoundaryFromFieldAligned::cloneMod(BoundaryOp *operation, const list &args) { +BoundaryOp* BoundaryFromFieldAligned::cloneMod(BoundaryOp *operation, const std::list &args) { BoundaryFromFieldAligned* result = new BoundaryFromFieldAligned(operation); if(!args.empty()) { diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 59fb515271..e9b1c417f8 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -24,7 +24,7 @@ * format Pointer to DataFormat. This will be deleted in * destructor */ -GridFile::GridFile(std::unique_ptr format, string gridfilename) +GridFile::GridFile(std::unique_ptr format, std::string gridfilename) : file(std::move(format)), filename(std::move(gridfilename)) { TRACE("GridFile constructor"); @@ -46,13 +46,13 @@ GridFile::~GridFile() { * Currently this is done by getting the variable's size, * and testing for zero size. */ -bool GridFile::hasVar(const string &name) { +bool GridFile::hasVar(const std::string &name) { if (!file->is_valid()) { return false; } /// Get the size of the variable - vector s = file->getSize(name); + std::vector s = file->getSize(name); /// Test if the variable has zero size return s.size() != 0; @@ -79,7 +79,7 @@ bool GridFile::hasVar(const string &name) { * Boolean. True on success. * */ -bool GridFile::get(Mesh *UNUSED(m), int &ival, const string &name) { +bool GridFile::get(Mesh *UNUSED(m), int &ival, const std::string &name) { Timer timer("io"); TRACE("GridFile::get(int)"); @@ -100,7 +100,7 @@ bool GridFile::get(Mesh *UNUSED(m), int &ival, const string &name) { * * */ -bool GridFile::get(Mesh *UNUSED(m), BoutReal &rval, const string &name) { +bool GridFile::get(Mesh *UNUSED(m), BoutReal &rval, const std::string &name) { Timer timer("io"); TRACE("GridFile::get(BoutReal)"); @@ -121,14 +121,14 @@ bool GridFile::get(Mesh *UNUSED(m), BoutReal &rval, const string &name) { * * Succeeds if the variable in the file is 0-D or 2-D */ -bool GridFile::get(Mesh *m, Field2D &var, const string &name, BoutReal def) { +bool GridFile::get(Mesh *m, Field2D &var, const std::string &name, BoutReal def) { Timer timer("io"); TRACE("GridFile::get(Field2D)"); if (!file->is_valid()) { throw BoutException("Could not read '%s' from file: File cannot be read", name.c_str()); } - vector size = file->getSize(name); + std::vector size = file->getSize(name); switch(size.size()) { case 0: { @@ -179,7 +179,7 @@ bool GridFile::get(Mesh *m, Field2D &var, const string &name, BoutReal def) { ASSERT1((m->LocalNy - (m->yend - m->ystart + 1)) % 2 == 0); ///Global (x,y) dimensions of field - const vector field_dimensions = file->getSize(name); + const std::vector field_dimensions = file->getSize(name); // Number of points to read. int nx_to_read = -1; @@ -237,7 +237,7 @@ bool GridFile::get(Mesh *m, Field2D &var, const string &name, BoutReal def) { * * */ -bool GridFile::get(Mesh *m, Field3D &var, const string &name, BoutReal def) { +bool GridFile::get(Mesh *m, Field3D &var, const std::string &name, BoutReal def) { Timer timer("io"); TRACE("GridFile::get(Field3D)"); @@ -249,7 +249,7 @@ bool GridFile::get(Mesh *m, Field3D &var, const string &name, BoutReal def) { // Check the size of the variable in the file - vector size = file->getSize(name); + std::vector size = file->getSize(name); switch(size.size()) { case 0: { // Variable not found @@ -331,7 +331,7 @@ bool GridFile::get(Mesh *m, Field3D &var, const string &name, BoutReal def) { return true; } -bool GridFile::get(Mesh *UNUSED(m), vector &var, const string &name, +bool GridFile::get(Mesh *UNUSED(m), std::vector &var, const std::string &name, int len, int offset, GridDataSource::Direction UNUSED(dir)) { TRACE("GridFile::get(vector)"); @@ -349,7 +349,7 @@ bool GridFile::get(Mesh *UNUSED(m), vector &var, const string &name, return true; } -bool GridFile::get(Mesh *UNUSED(m), vector &var, const string &name, +bool GridFile::get(Mesh *UNUSED(m), std::vector &var, const std::string &name, int len, int offset, GridDataSource::Direction UNUSED(dir)) { TRACE("GridFile::get(vector)"); @@ -382,7 +382,7 @@ bool GridFile::get(Mesh *UNUSED(m), vector &var, const string &name, with the BoutReal and imaginary parts of each (positive) frequency up to the nyquist frequency. */ -bool GridFile::readgrid_3dvar_fft(Mesh *m, const string &name, +bool GridFile::readgrid_3dvar_fft(Mesh *m, const std::string &name, int yread, int ydest, int ysize, int xge, int xlt, Field3D &var) { /// Check the arguments make sense @@ -391,7 +391,7 @@ bool GridFile::readgrid_3dvar_fft(Mesh *m, const string &name, } /// Check the size of the data - vector size = file->getSize(name); + std::vector size = file->getSize(name); if (size.size() != 3) { output_warn.write("\tWARNING: Number of dimensions of %s incorrect\n", name.c_str()); @@ -472,7 +472,7 @@ bool GridFile::readgrid_3dvar_fft(Mesh *m, const string &name, * Reads a 3D variable directly from the file, without * any processing */ -bool GridFile::readgrid_3dvar_real(Mesh *m, const string &name, +bool GridFile::readgrid_3dvar_real(Mesh *m, const std::string &name, int yread, int ydest, int ysize, int xge, int xlt, Field3D &var) { /// Check the arguments make sense @@ -481,7 +481,7 @@ bool GridFile::readgrid_3dvar_real(Mesh *m, const string &name, } /// Check the size of the data - vector size = file->getSize(name); + std::vector size = file->getSize(name); if (size.size() != 3) { output_warn.write("\tWARNING: Number of dimensions of %s incorrect\n", name.c_str()); diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index a784c105e4..f5e2158b68 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -11,11 +11,11 @@ #include -bool GridFromOptions::hasVar(const string &name) { +bool GridFromOptions::hasVar(const std::string &name) { return options->isSet(name); } -bool GridFromOptions::get(Mesh *UNUSED(m), int &ival, const string &name) { +bool GridFromOptions::get(Mesh *UNUSED(m), int &ival, const std::string &name) { if(!hasVar(name)) { ival = 0; return false; @@ -25,7 +25,7 @@ bool GridFromOptions::get(Mesh *UNUSED(m), int &ival, const string &name) { return true; } -bool GridFromOptions::get(Mesh *UNUSED(m), BoutReal &rval, const string &name) { +bool GridFromOptions::get(Mesh *UNUSED(m), BoutReal &rval, const std::string &name) { if(!hasVar(name)) { rval = 0.0; return false; @@ -42,7 +42,7 @@ bool GridFromOptions::get(Mesh *UNUSED(m), BoutReal &rval, const string &name) { return true; } -bool GridFromOptions::get(Mesh *m, Field2D &var, const string &name, BoutReal def) { +bool GridFromOptions::get(Mesh *m, Field2D &var, const std::string &name, BoutReal def) { if (!hasVar(name)) { output_warn.write("Variable '%s' not in mesh options. Setting to %e\n", name.c_str(), def); var = def; @@ -53,7 +53,7 @@ bool GridFromOptions::get(Mesh *m, Field2D &var, const string &name, BoutReal de return true; } -bool GridFromOptions::get(Mesh *m, Field3D &var, const string &name, BoutReal def) { +bool GridFromOptions::get(Mesh *m, Field3D &var, const std::string &name, BoutReal def) { if(!hasVar(name)) { var = def; return false; @@ -63,7 +63,7 @@ bool GridFromOptions::get(Mesh *m, Field3D &var, const string &name, BoutReal de return true; } -bool GridFromOptions::get(Mesh *m, vector &var, const string &name, int len, +bool GridFromOptions::get(Mesh *m, std::vector &var, const std::string &name, int len, int UNUSED(offset), GridDataSource::Direction UNUSED(dir)) { // Integers not expressions yet @@ -76,7 +76,7 @@ bool GridFromOptions::get(Mesh *m, vector &var, const string &name, int len return true; } -bool GridFromOptions::get(Mesh *m, vector &var, const string &name, int len, +bool GridFromOptions::get(Mesh *m, std::vector &var, const std::string &name, int len, int offset, GridDataSource::Direction dir) { if(!hasVar(name)) { diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index e4f3c487a0..bafee883de 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -1925,7 +1925,7 @@ void BoutMesh::clear_handles() { * Communication utilities ****************************************************************/ -int BoutMesh::pack_data(const vector &var_list, int xge, int xlt, int yge, +int BoutMesh::pack_data(const std::vector &var_list, int xge, int xlt, int yge, int ylt, BoutReal *buffer) { int len = 0; @@ -1958,7 +1958,7 @@ int BoutMesh::pack_data(const vector &var_list, int xge, int xlt, i return (len); } -int BoutMesh::unpack_data(const vector &var_list, int xge, int xlt, int yge, +int BoutMesh::unpack_data(const std::vector &var_list, int xge, int xlt, int yge, int ylt, BoutReal *buffer) { int len = 0; @@ -2379,9 +2379,9 @@ const RangeIterator BoutMesh::iterateBndryUpperY() const { return RangeIterator(xs, xe); } -vector BoutMesh::getBoundaries() { return boundary; } +std::vector BoutMesh::getBoundaries() { return boundary; } -vector BoutMesh::getBoundariesPar() { return par_boundary; } +std::vector BoutMesh::getBoundariesPar() { return par_boundary; } void BoutMesh::addBoundaryPar(BoundaryRegionPar *bndry) { output_info << "Adding new parallel boundary: " << bndry->label << endl; diff --git a/src/mesh/impls/bout/boutmesh.hxx b/src/mesh/impls/bout/boutmesh.hxx index 8b8fb97ee1..6964ebf2dc 100644 --- a/src/mesh/impls/bout/boutmesh.hxx +++ b/src/mesh/impls/bout/boutmesh.hxx @@ -11,9 +11,6 @@ #include #include -using std::list; -using std::vector; - /// Implementation of Mesh (mostly) compatible with BOUT /// /// Topology and communications compatible with BOUT @@ -138,8 +135,8 @@ class BoutMesh : public Mesh { // Boundary regions - vector getBoundaries(); - vector getBoundariesPar(); + std::vector getBoundaries(); + std::vector getBoundariesPar(); void addBoundaryPar(BoundaryRegionPar* bndry); const Field3D smoothSeparatrix(const Field3D &f); @@ -163,7 +160,7 @@ class BoutMesh : public Mesh { int YGLOBAL(BoutReal yloc, BoutReal &yglo) const; private: - string gridname; + std::string gridname; int nx, ny; ///< Size of the grid in the input file int MX, MY; ///< size of the grid excluding boundary regions @@ -182,7 +179,7 @@ class BoutMesh : public Mesh { int ixseps_inner, ixseps_outer, ixseps_upper, ixseps_lower; int ny_inner; - vector ShiftAngle; ///< Angle for twist-shift location + std::vector ShiftAngle; ///< Angle for twist-shift location // Processor number, local <-> global translation int PROC_NUM(int xind, int yind); // (PE_XIND, PE_YIND) -> MYPE @@ -219,8 +216,8 @@ class BoutMesh : public Mesh { void addBoundaryRegions(); ///< Adds 2D and 3D regions for boundaries - vector boundary; // Vector of boundary regions - vector par_boundary; // Vector of parallel boundary regions + std::vector boundary; // Vector of boundary regions + std::vector par_boundary; // Vector of parallel boundary regions ////////////////////////////////////////////////// // Communications @@ -245,7 +242,7 @@ class BoutMesh : public Mesh { void free_handle(CommHandle *h); CommHandle* get_handle(int xlen, int ylen); void clear_handles(); - list comm_list; // List of allocated communication handles + std::list comm_list; // List of allocated communication handles ////////////////////////////////////////////////// // X communicator @@ -264,9 +261,9 @@ class BoutMesh : public Mesh { void post_receive(CommHandle &ch); /// Take data from objects and put into a buffer - int pack_data(const vector &var_list, int xge, int xlt, int yge, int ylt, BoutReal *buffer); + int pack_data(const std::vector &var_list, int xge, int xlt, int yge, int ylt, BoutReal *buffer); /// Copy data from a buffer back into the fields - int unpack_data(const vector &var_list, int xge, int xlt, int yge, int ylt, BoutReal *buffer); + int unpack_data(const std::vector &var_list, int xge, int xlt, int yge, int ylt, BoutReal *buffer); }; #endif // __BOUTMESH_H__ diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index f684cce292..00181318cf 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -558,7 +558,7 @@ void derivs_set(std::vector options, DiffLookup *table, DiffLookup *s bool staggerGrids) { TRACE("derivs_set()"); output_info.write("\t%-12s: ", name.c_str()); - string label = def; + std::string label = def; for (auto &opts : options) { if (opts->isSet(name)) { opts->get(name, label, ""); diff --git a/src/mesh/interpolation/interpolation_factory.cxx b/src/mesh/interpolation/interpolation_factory.cxx index 387a578070..fb57cb1e75 100644 --- a/src/mesh/interpolation/interpolation_factory.cxx +++ b/src/mesh/interpolation/interpolation_factory.cxx @@ -29,14 +29,14 @@ void InterpolationFactory::cleanup() { Interpolation* InterpolationFactory::create(Options *options, Mesh *mesh) { // Get the default interpolation type - string type = getDefaultInterpType(); + std::string type = getDefaultInterpType(); // If no options section passed (e.g. for a variable), then use the // "interpolation" section if (options == nullptr) options = Options::getRoot()->getSection("interpolation"); - string interp_option; + std::string interp_option; options->get("type", interp_option, type); if (!interp_option.empty()) type = interp_option.c_str(); @@ -44,7 +44,7 @@ Interpolation* InterpolationFactory::create(Options *options, Mesh *mesh) { return create(type, options, mesh); } -Interpolation* InterpolationFactory::create(const string &name, Options *options, Mesh *localmesh) { +Interpolation* InterpolationFactory::create(const std::string &name, Options *options, Mesh *localmesh) { // If no options section passed (e.g. for a variable), then use the // "interpolation" section if (options == nullptr) @@ -61,7 +61,7 @@ Interpolation* InterpolationFactory::create(const string &name, Options *options return interp(localmesh); } -void InterpolationFactory::add(CreateInterpCallback interp, const string &name) { +void InterpolationFactory::add(CreateInterpCallback interp, const std::string &name) { if ((findInterpolation(name)) != nullptr) { // error - already exists output << "ERROR: Trying to add an already existing interpolation: " << name << endl; @@ -70,7 +70,7 @@ void InterpolationFactory::add(CreateInterpCallback interp, const string &name) interp_map[lowercase(name)] = interp; } -InterpolationFactory::CreateInterpCallback InterpolationFactory::findInterpolation(const string &name) { +InterpolationFactory::CreateInterpCallback InterpolationFactory::findInterpolation(const std::string &name) { auto interp = interp_map.find(lowercase(name)); if (interp == end(interp_map)) return nullptr; diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 70112cfe91..cc9b39838c 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -49,7 +49,7 @@ Mesh::~Mesh() { **************************************************************************/ /// Get an integer -int Mesh::get(int &ival, const string &name) { +int Mesh::get(int &ival, const std::string &name) { TRACE("Mesh::get(ival, %s)", name.c_str()); if (source == nullptr or !source->get(this, ival, name)) @@ -59,7 +59,7 @@ int Mesh::get(int &ival, const string &name) { } /// A BoutReal number -int Mesh::get(BoutReal &rval, const string &name) { +int Mesh::get(BoutReal &rval, const std::string &name) { TRACE("Mesh::get(rval, %s)", name.c_str()); if (source == nullptr or !source->get(this, rval, name)) @@ -68,7 +68,7 @@ int Mesh::get(BoutReal &rval, const string &name) { return 0; } -int Mesh::get(Field2D &var, const string &name, BoutReal def) { +int Mesh::get(Field2D &var, const std::string &name, BoutReal def) { TRACE("Loading 2D field: Mesh::get(Field2D, %s)", name.c_str()); // Ensure data allocated @@ -86,7 +86,7 @@ int Mesh::get(Field2D &var, const string &name, BoutReal def) { return 0; } -int Mesh::get(Field3D &var, const string &name, BoutReal def, bool communicate) { +int Mesh::get(Field3D &var, const std::string &name, BoutReal def, bool communicate) { TRACE("Loading 3D field: Mesh::get(Field3D, %s)", name.c_str()); // Ensure data allocated @@ -110,7 +110,7 @@ int Mesh::get(Field3D &var, const string &name, BoutReal def, bool communicate) * Data get routines **************************************************************************/ -int Mesh::get(Vector2D &var, const string &name) { +int Mesh::get(Vector2D &var, const std::string &name) { TRACE("Loading 2D vector: Mesh::get(Vector2D, %s)", name.c_str()); if(var.covariant) { @@ -131,7 +131,7 @@ int Mesh::get(Vector2D &var, const string &name) { return 0; } -int Mesh::get(Vector3D &var, const string &name) { +int Mesh::get(Vector3D &var, const std::string &name) { TRACE("Loading 3D vector: Mesh::get(Vector3D, %s)", name.c_str()); if(var.covariant) { @@ -152,7 +152,7 @@ int Mesh::get(Vector3D &var, const string &name) { return 0; } -bool Mesh::sourceHasVar(const string &name) { +bool Mesh::sourceHasVar(const std::string &name) { TRACE("Mesh::sourceHasVar(%s)", name.c_str()); if (source == nullptr) return false; @@ -209,7 +209,7 @@ void Mesh::communicate(FieldPerp &f) { wait(recv[1]); } -int Mesh::msg_len(const vector &var_list, int xge, int xlt, int yge, int ylt) { +int Mesh::msg_len(const std::vector &var_list, int xge, int xlt, int yge, int ylt) { int len = 0; /// Loop over variables @@ -262,7 +262,7 @@ bool Mesh::hasBndryUpperY() { return answer; } -const vector Mesh::readInts(const string &name, int n) { +const std::vector Mesh::readInts(const std::string &name, int n) { TRACE("Mesh::readInts(%s)", name.c_str()); if (source == nullptr) { @@ -270,7 +270,7 @@ const vector Mesh::readInts(const string &name, int n) { name.c_str()); } - vector result; + std::vector result; if(source->hasVar(name)) { if(!source->get(this, result, name, n, 0)) { @@ -287,7 +287,7 @@ const vector Mesh::readInts(const string &name, int n) { void Mesh::setParallelTransform() { - string ptstr; + std::string ptstr; options->get("paralleltransform", ptstr, "identity"); // Convert to lower case for comparison diff --git a/src/mesh/meshfactory.cxx b/src/mesh/meshfactory.cxx index 1c6eb1ef21..0502c9c228 100644 --- a/src/mesh/meshfactory.cxx +++ b/src/mesh/meshfactory.cxx @@ -27,14 +27,14 @@ Mesh* MeshFactory::createMesh(GridDataSource *source, Options *options) { options = Options::getRoot()->getSection("mesh"); if (source == nullptr) { - string grid_name; + std::string grid_name; if(options->isSet("file")) { // Specified mesh file options->get("file", grid_name, ""); output << "\nGetting grid data from file " << grid_name << endl; /// Create a grid file, using specified format if given - string grid_ext; + std::string grid_ext; options->get("format", grid_ext, ""); /// Create a grid file @@ -45,7 +45,7 @@ Mesh* MeshFactory::createMesh(GridDataSource *source, Options *options) { // Get the global option Options::getRoot()->get("grid", grid_name, ""); output << "\nGetting grid data from file " << grid_name << endl; - string grid_ext; + std::string grid_ext; Options::getRoot()->get("format", grid_ext, ""); source = static_cast(new GridFile( @@ -58,7 +58,7 @@ Mesh* MeshFactory::createMesh(GridDataSource *source, Options *options) { } // Get the type of mesh - string type; + std::string type; options->get("type", type, MESH_BOUT); if(!strcasecmp(type.c_str(), MESH_BOUT)) { diff --git a/src/mesh/parallel_boundary_op.cxx b/src/mesh/parallel_boundary_op.cxx index fa120d6516..1fdd82bcaa 100644 --- a/src/mesh/parallel_boundary_op.cxx +++ b/src/mesh/parallel_boundary_op.cxx @@ -63,7 +63,7 @@ BoutReal BoundaryOpPar::getValue(const BoundaryRegionPar &bndry, BoutReal t) { ////////////////////////////////////////// // Dirichlet boundary -BoundaryOpPar* BoundaryOpPar_dirichlet::clone(BoundaryRegionPar *region, const list &args) { +BoundaryOpPar* BoundaryOpPar_dirichlet::clone(BoundaryRegionPar *region, const std::list &args) { if(!args.empty()) { try { real_value = stringToReal(args.front()); @@ -108,7 +108,7 @@ void BoundaryOpPar_dirichlet::apply(Field3D &f, BoutReal t) { ////////////////////////////////////////// // Dirichlet boundary - Third order -BoundaryOpPar* BoundaryOpPar_dirichlet_O3::clone(BoundaryRegionPar *region, const list &args) { +BoundaryOpPar* BoundaryOpPar_dirichlet_O3::clone(BoundaryRegionPar *region, const std::list &args) { if(!args.empty()) { try { real_value = stringToReal(args.front()); @@ -160,7 +160,7 @@ void BoundaryOpPar_dirichlet_O3::apply(Field3D &f, BoutReal t) { ////////////////////////////////////////// // Dirichlet with interpolation -BoundaryOpPar* BoundaryOpPar_dirichlet_interp::clone(BoundaryRegionPar *region, const list &args) { +BoundaryOpPar* BoundaryOpPar_dirichlet_interp::clone(BoundaryRegionPar *region, const std::list &args) { if(!args.empty()) { try { real_value = stringToReal(args.front()); @@ -209,7 +209,7 @@ void BoundaryOpPar_dirichlet_interp::apply(Field3D &f, BoutReal t) { ////////////////////////////////////////// // Neumann boundary -BoundaryOpPar* BoundaryOpPar_neumann::clone(BoundaryRegionPar *region, const list &args) { +BoundaryOpPar* BoundaryOpPar_neumann::clone(BoundaryRegionPar *region, const std::list &args) { if(!args.empty()) { try { real_value = stringToReal(args.front()); diff --git a/src/physics/physicsmodel.cxx b/src/physics/physicsmodel.cxx index 21421dccf4..98c56a329b 100644 --- a/src/physics/physicsmodel.cxx +++ b/src/physics/physicsmodel.cxx @@ -97,8 +97,8 @@ int PhysicsModel::postInit(bool restarting) { // Second argument specifies no time history solver->outputVars(restart, false); - string restart_dir; ///< Directory for restart files - string dump_ext, restart_ext; ///< Dump, Restart file extension + std::string restart_dir; ///< Directory for restart files + std::string dump_ext, restart_ext; ///< Dump, Restart file extension Options *options = Options::getRoot(); if (options->isSet("restartdir")) { @@ -112,7 +112,7 @@ int PhysicsModel::postInit(bool restarting) { options->get("dump_format", dump_ext, "nc"); options->get("restart_format", restart_ext, dump_ext); - string filename = restart_dir + "/BOUT.restart."+restart_ext; + std::string filename = restart_dir + "/BOUT.restart."+restart_ext; if (restarting) { output.write("Loading restart file: %s\n", filename.c_str()); diff --git a/src/solver/impls/imex-bdf2/imex-bdf2.cxx b/src/solver/impls/imex-bdf2/imex-bdf2.cxx index dfb0990319..3a0080ba8c 100644 --- a/src/solver/impls/imex-bdf2/imex-bdf2.cxx +++ b/src/solver/impls/imex-bdf2/imex-bdf2.cxx @@ -739,7 +739,7 @@ int IMEXBDF2::run() { int order = 1; int lastOrder = -1; BoutReal dt = timestep; - vector lastTimesteps = timesteps; + std::vector lastTimesteps = timesteps; BoutReal dtNext = dt; //Timestep to try for next internal iteration //By default use the main snes object. diff --git a/src/solver/impls/imex-bdf2/imex-bdf2.hxx b/src/solver/impls/imex-bdf2/imex-bdf2.hxx index 5343582dc3..0e31ff9d37 100644 --- a/src/solver/impls/imex-bdf2/imex-bdf2.hxx +++ b/src/solver/impls/imex-bdf2/imex-bdf2.hxx @@ -123,7 +123,7 @@ class IMEXBDF2 : public Solver { BoutReal dtMinFatal; ///< If timestep wants to drop below this we abort. Set -ve to deactivate //Scheme coefficients - vector uFac, fFac, gFac; + std::vector uFac, fFac, gFac; BoutReal dtImp; int nlocal, neq; ///< Number of variables on local processor and in total @@ -150,9 +150,9 @@ class IMEXBDF2 : public Solver { // Working memory Array u ; ///< System state at current time - vector> uV; ///< The solution history - vector> fV; ///< The non-stiff solution history - vector timesteps; ///< Timestep history + std::vector> uV; ///< The solution history + std::vector> fV; ///< The non-stiff solution history + std::vector timesteps; ///< Timestep history Array rhs; Array err; diff --git a/src/solver/impls/rkgeneric/rkscheme.cxx b/src/solver/impls/rkgeneric/rkscheme.cxx index 02492d793d..cca8e6a5a4 100644 --- a/src/solver/impls/rkgeneric/rkscheme.cxx +++ b/src/solver/impls/rkgeneric/rkscheme.cxx @@ -206,32 +206,32 @@ void RKScheme::verifyCoeffs(){ output<atol) warn=true; } //Optional warning if(warn){ - output<getSection("solver"); - string scheme; + std::string scheme; options->get("scheme", scheme, ""); if(!scheme.empty()) type = scheme.c_str(); diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index f76bbaa552..60989d1ea5 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -37,7 +37,7 @@ #include #include -string formatEig(BoutReal reEig, BoutReal imEig); +std::string formatEig(BoutReal reEig, BoutReal imEig); //The callback function for the shell matrix-multiply operation //A simple wrapper around the SlepcSolver advanceStep routine @@ -117,8 +117,8 @@ PetscErrorCode stBackTransformWrapper(ST st, PetscInt nEig, PetscScalar *eigr, //Helper function -string formatEig(BoutReal reEig, BoutReal imEig){ - string rePad, imPad; +std::string formatEig(BoutReal reEig, BoutReal imEig){ + std::string rePad, imPad; if(reEig<0){ rePad="-"; @@ -584,7 +584,7 @@ void SlepcSolver::monitor(PetscInt its, PetscInt nconv, PetscScalar eigr[], BoutReal reEigBout, imEigBout; slepcToBout(eigr[nconv],eigi[nconv],reEigBout,imEigBout); - string joinNum, joinNumSlepc; + std::string joinNum, joinNumSlepc; if(imEigBout<0){ joinNum=""; }else{ diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 2267c2f06f..544543a4c6 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -623,7 +623,7 @@ void Solver::outputVars(Datafile &outputfile, bool save_repeat) { if(mms) { // Add an error variable - outputfile.add(*(f.MMS_err), (string("E_")+f.name).c_str(), save_repeat); + outputfile.add(*(f.MMS_err), ("E_" + f.name).c_str(), save_repeat); } } } @@ -1308,7 +1308,7 @@ void Solver::post_rhs(BoutReal UNUSED(t)) { #endif } -bool Solver::varAdded(const string &name) { +bool Solver::varAdded(const std::string &name) { for(const auto& f : f2d) { if(f.name == name) return true; diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 908c5e1ee4..a8dd80d1cb 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -88,7 +88,7 @@ template <> void Options::assign(BoutReal val, const std::string sourc _set(ss.str(), source, false); } -void Options::_set(string val, std::string source, bool force) { +void Options::_set(std::string val, std::string source, bool force) { if (isSet()) { // Check if current value the same as new value if (value.value != val) { @@ -266,8 +266,8 @@ void Options::printUnused() const { void Options::cleanCache() { FieldFactory::get()->cleanCache(); } -std::map Options::values() const { - std::map options; +std::map Options::values() const { + std::map options; for (const auto &it : children) { if (it.second.is_value) { options[it.first] = it.second.value; @@ -276,8 +276,8 @@ std::map Options::values() const { return options; } -std::map Options::subsections() const { - std::map sections; +std::map Options::subsections() const { + std::map sections; for (const auto &it : children) { if (it.second.is_section) { sections[it.first] = &it.second; diff --git a/src/sys/options/options_ini.hxx b/src/sys/options/options_ini.hxx index 7fbb9d9562..1387f054c7 100644 --- a/src/sys/options/options_ini.hxx +++ b/src/sys/options/options_ini.hxx @@ -59,7 +59,7 @@ private: // Helper functions for reading void parse(const std::string &, std::string &, std::string &); - string getNextLine(std::ifstream &fin); + std::string getNextLine(std::ifstream &fin); // Helper functions for writing void writeSection(const Options *options, std::ofstream &fout); diff --git a/src/sys/optionsreader.cxx b/src/sys/optionsreader.cxx index a791e5b10f..6f46ccd1a0 100644 --- a/src/sys/optionsreader.cxx +++ b/src/sys/optionsreader.cxx @@ -78,7 +78,7 @@ void OptionsReader::parseCommandLine(Options *options, int argc, char **argv) { // A key/value pair, separated by a '=' or a switch // and sections separated with an '_' but don't start with a '-' - string buffer; + std::string buffer; // Go through command-line arguments for (int i=1;igetSection(section); } diff --git a/src/sys/utils.cxx b/src/sys/utils.cxx index 8eef7335e6..d48a290e3e 100644 --- a/src/sys/utils.cxx +++ b/src/sys/utils.cxx @@ -51,16 +51,16 @@ char* copy_string(const char* s) { } // Convert a string to lower case -const string lowercase(const string &str) { - string strlow(str); +const std::string lowercase(const std::string &str) { + std::string strlow(str); std::transform(strlow.begin(), strlow.end(), strlow.begin(), ::tolower); return strlow; } // Convert to lowercase, except for inside strings -const string lowercasequote(const string &str) { - string strlow(str); +const std::string lowercasequote(const std::string &str) { + std::string strlow(str); bool quote = false, dquote = false; for (char &i : strlow) { diff --git a/tests/unit/mesh/test_boutmesh.cxx b/tests/unit/mesh/test_boutmesh.cxx index 3510bffacf..3891227e48 100644 --- a/tests/unit/mesh/test_boutmesh.cxx +++ b/tests/unit/mesh/test_boutmesh.cxx @@ -9,27 +9,27 @@ class FakeGridDataSource : public GridDataSource { public: FakeGridDataSource(){}; ~FakeGridDataSource(){}; - bool hasVar(const string &UNUSED(name)) { return false; }; - bool get(Mesh *UNUSED(m), int &UNUSED(ival), const string &UNUSED(name)) { + bool hasVar(const std::string &UNUSED(name)) { return false; }; + bool get(Mesh *UNUSED(m), int &UNUSED(ival), const std::string &UNUSED(name)) { return true; }; - bool get(Mesh *UNUSED(m), BoutReal &UNUSED(rval), const string &UNUSED(name)) { + bool get(Mesh *UNUSED(m), BoutReal &UNUSED(rval), const std::string &UNUSED(name)) { return true; } - bool get(Mesh *UNUSED(m), Field2D &UNUSED(var), const string &UNUSED(name), + bool get(Mesh *UNUSED(m), Field2D &UNUSED(var), const std::string &UNUSED(name), BoutReal UNUSED(def) = 0.0) { return true; } - bool get(Mesh *UNUSED(m), Field3D &UNUSED(var), const string &UNUSED(name), + bool get(Mesh *UNUSED(m), Field3D &UNUSED(var), const std::string &UNUSED(name), BoutReal UNUSED(def) = 0.0) { return true; } - bool get(Mesh *UNUSED(m), vector &UNUSED(var), const string &UNUSED(name), + bool get(Mesh *UNUSED(m), std::vector &UNUSED(var), const std::string &UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, Direction UNUSED(dir) = GridDataSource::X) { return true; } - bool get(Mesh *UNUSED(m), vector &UNUSED(var), const string &UNUSED(name), + bool get(Mesh *UNUSED(m), std::vector &UNUSED(var), const std::string &UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, Direction UNUSED(dir) = GridDataSource::X) { return true; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 6e6c9dc2ad..bc09839a0f 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -145,8 +145,8 @@ public: const RangeIterator iterateBndryUpperOuterY() const { return RangeIterator(); } const RangeIterator iterateBndryUpperInnerY() const { return RangeIterator(); } void addBoundary(BoundaryRegion* region) {boundaries.push_back(region);} - vector getBoundaries() { return boundaries; } - vector getBoundariesPar() { return vector(); } + std::vector getBoundaries() { return boundaries; } + std::vector getBoundariesPar() { return std::vector(); } BoutReal GlobalX(int UNUSED(jx)) const { return 0; } BoutReal GlobalY(int UNUSED(jy)) const { return 0; } BoutReal GlobalX(BoutReal UNUSED(jx)) const { return 0; } @@ -159,7 +159,7 @@ public: derivs_init(opt); } private: - vector boundaries; + std::vector boundaries; }; From 6ede44f37cb8e51ece3307cc6221ad75cf6c2ca8 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Oct 2018 16:15:15 +0100 Subject: [PATCH 0134/1783] Remove some commented out code --- src/mesh/boundary_factory.cxx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/mesh/boundary_factory.cxx b/src/mesh/boundary_factory.cxx index bc9db98a84..ea01569752 100644 --- a/src/mesh/boundary_factory.cxx +++ b/src/mesh/boundary_factory.cxx @@ -150,14 +150,6 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * string s = arg.substr(start, arg.length()); arglist.push_back(trim(s)); - /* - list arglist = strsplit(arg, ','); - for(list::iterator it=arglist.begin(); it != arglist.end(); it++) { - // Trim each argument - (*it) = trim(*it); - } - */ - // Test if func is a modifier BoundaryModifier *mod = findBoundaryMod(func); if (mod != nullptr) { From 7e251a5dab79f0896d347f13c529d9241820f262 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Oct 2018 16:30:10 +0100 Subject: [PATCH 0135/1783] Remove some more `using std::` --- include/utils.hxx | 5 ++- src/field/fieldgenerators.hxx | 52 +++++++++++++-------------- src/fileio/impls/netcdf/nc_format.hxx | 35 +++++++++--------- src/fileio/impls/pnetcdf/pnetcdf.hxx | 29 +++++++-------- src/mesh/boundary_region.cxx | 2 ++ src/solver/impls/arkode/arkode.hxx | 10 +++--- src/solver/impls/cvode/cvode.hxx | 10 +++--- src/solver/impls/ida/ida.hxx | 1 - src/solver/impls/slepc/slepc.hxx | 2 -- 9 files changed, 71 insertions(+), 75 deletions(-) diff --git a/include/utils.hxx b/include/utils.hxx index 458849baaa..daac72713c 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -43,9 +43,6 @@ #include #include -using std::abs; -using std::swap; - /// Helper class for 2D arrays /// /// Allows bounds checking through `operator()` with CHECK > 1 @@ -201,6 +198,8 @@ private: template int invert3x3(Matrix &a, BoutReal small = 1.0e-15) { TRACE("invert3x3"); + using std::abs; + // Calculate the first co-factors T A = a(1, 1) * a(2, 2) - a(1, 2) * a(2, 1); T B = a(1, 2) * a(2, 0) - a(1, 0) * a(2, 2); diff --git a/src/field/fieldgenerators.hxx b/src/field/fieldgenerators.hxx index e94cb611de..1da1cbfc3d 100644 --- a/src/field/fieldgenerators.hxx +++ b/src/field/fieldgenerators.hxx @@ -13,8 +13,6 @@ #include -using std::list; - ////////////////////////////////////////////////////////// // Generators from values @@ -23,7 +21,9 @@ using std::list; class FieldValuePtr : public FieldGenerator { public: FieldValuePtr(BoutReal *val) : ptr(val) {} - FieldGeneratorPtr clone(const list UNUSED(args)) { return std::make_shared(ptr); } + FieldGeneratorPtr clone(const std::list UNUSED(args)) { + return std::make_shared(ptr); + } BoutReal generate(double UNUSED(x), double UNUSED(y), double UNUSED(z), double UNUSED(t)) { return *ptr; } private: BoutReal *ptr; @@ -37,7 +37,7 @@ class FieldSin : public FieldGenerator { public: FieldSin(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const list args); + FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); const std::string str() {return std::string("sin(")+gen->str()+std::string(")");} private: @@ -49,7 +49,7 @@ class FieldCos : public FieldGenerator { public: FieldCos(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const list args); + FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); const std::string str() {return std::string("cos(")+gen->str()+std::string(")");} @@ -63,7 +63,7 @@ template class FieldGenOneArg : public FieldGenerator { ///< Template for single-argument function public: FieldGenOneArg(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const list args) { + FieldGeneratorPtr clone(const std::list args) { if(args.size() != 1) { throw ParseException("Incorrect number of arguments to function. Expecting 1, got %d", args.size()); } @@ -83,7 +83,7 @@ template class FieldGenTwoArg : public FieldGenerator { ///< Template for two-argument function public: FieldGenTwoArg(FieldGeneratorPtr a, FieldGeneratorPtr b) : A(a), B(b) {} - FieldGeneratorPtr clone(const list args) { + FieldGeneratorPtr clone(const std::list args) { if(args.size() != 2) { throw ParseException("Incorrect number of arguments to function. Expecting 2, got %d", args.size()); } @@ -101,7 +101,7 @@ private: class FieldATan : public FieldGenerator { public: FieldATan(FieldGeneratorPtr a, FieldGeneratorPtr b=nullptr) : A(a), B(b) {} - FieldGeneratorPtr clone(const list args) { + FieldGeneratorPtr clone(const std::list args) { if(args.size() == 1) { return std::make_shared(args.front()); }else if(args.size() == 2) { @@ -123,7 +123,7 @@ class FieldSinh : public FieldGenerator { public: FieldSinh(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const list args); + FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); private: FieldGeneratorPtr gen; @@ -134,7 +134,7 @@ class FieldCosh : public FieldGenerator { public: FieldCosh(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const list args); + FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); private: FieldGeneratorPtr gen; @@ -145,7 +145,7 @@ class FieldTanh : public FieldGenerator { public: FieldTanh(FieldGeneratorPtr g=nullptr) : gen(g) {} - FieldGeneratorPtr clone(const list args); + FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); private: FieldGeneratorPtr gen; @@ -156,7 +156,7 @@ class FieldGaussian : public FieldGenerator { public: FieldGaussian(FieldGeneratorPtr xin, FieldGeneratorPtr sin) : X(xin), s(sin) {} - FieldGeneratorPtr clone(const list args); + FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); private: FieldGeneratorPtr X, s; @@ -167,7 +167,7 @@ class FieldAbs : public FieldGenerator { public: FieldAbs(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const list args); + FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); private: FieldGeneratorPtr gen; @@ -178,7 +178,7 @@ class FieldSqrt : public FieldGenerator { public: FieldSqrt(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const list args); + FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); private: FieldGeneratorPtr gen; @@ -189,7 +189,7 @@ class FieldHeaviside : public FieldGenerator { public: FieldHeaviside(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const list args); + FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); const std::string str() {return std::string("H(")+gen->str()+std::string(")");} private: @@ -201,7 +201,7 @@ class FieldErf : public FieldGenerator { public: FieldErf(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const list args); + FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); private: FieldGeneratorPtr gen; @@ -211,8 +211,8 @@ private: class FieldMin : public FieldGenerator { public: FieldMin() {} - FieldMin(const list args) : input(args) {} - FieldGeneratorPtr clone(const list args) { + FieldMin(const std::list args) : input(args) {} + FieldGeneratorPtr clone(const std::list args) { if(args.size() == 0) { throw ParseException("min function must have some inputs"); } @@ -229,15 +229,15 @@ public: return result; } private: - list input; + std::list input; }; /// Maximum class FieldMax : public FieldGenerator { public: FieldMax() {} - FieldMax(const list args) : input(args) {} - FieldGeneratorPtr clone(const list args) { + FieldMax(const std::list args) : input(args) {} + FieldGeneratorPtr clone(const std::list args) { if(args.size() == 0) { throw ParseException("max function must have some inputs"); } @@ -254,7 +254,7 @@ public: return result; } private: - list input; + std::list input; }; /// Generator to round to the nearest integer @@ -262,7 +262,7 @@ class FieldRound : public FieldGenerator { public: FieldRound(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const list args) { + FieldGeneratorPtr clone(const std::list args) { if(args.size() != 1) throw BoutException("round function must have one input"); return std::make_shared(args.front()); @@ -288,7 +288,7 @@ private: class FieldBallooning : public FieldGenerator { public: FieldBallooning(Mesh *m, FieldGeneratorPtr a = nullptr, int n = 3) : mesh(m), arg(a), ball_n(n) {} - FieldGeneratorPtr clone(const list args); + FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); private: Mesh *mesh; @@ -303,7 +303,7 @@ private: class FieldMixmode : public FieldGenerator { public: FieldMixmode(FieldGeneratorPtr a = nullptr, BoutReal seed = 0.5); - FieldGeneratorPtr clone(const list args); + FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); private: /// Generate a random number between 0 and 1 (exclusive) @@ -328,7 +328,7 @@ public: FieldGeneratorPtr steepnessin) : X(xin), width(widthin), center(centerin), steepness(steepnessin) {}; // Clone containing the list of arguments - FieldGeneratorPtr clone(const list args); + FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); private: // The (x,y,z,t) field diff --git a/src/fileio/impls/netcdf/nc_format.hxx b/src/fileio/impls/netcdf/nc_format.hxx index a04557066f..2ac34d2f62 100644 --- a/src/fileio/impls/netcdf/nc_format.hxx +++ b/src/fileio/impls/netcdf/nc_format.hxx @@ -53,14 +53,11 @@ class NcFormat; #include #include -using std::string; -using std::map; - class NcFormat : public DataFormat { public: NcFormat(); NcFormat(const char *name); - NcFormat(const string &name) : NcFormat(name.c_str()) {} + NcFormat(const std::string &name) : NcFormat(name.c_str()) {} ~NcFormat(); using DataFormat::openr; @@ -76,8 +73,8 @@ class NcFormat : public DataFormat { const char* filename() { return fname; }; - const vector getSize(const char *var) override; - const vector getSize(const string &var) override; + const std::vector getSize(const char *var) override; + const std::vector getSize(const std::string &var) override; // Set the origin for all subsequent calls bool setGlobalOrigin(int x = 0, int y = 0, int z = 0) override; @@ -88,34 +85,34 @@ class NcFormat : public DataFormat { bool setRecord(int t) override; // negative -> latest // Add a variable to the file - bool addVarInt(const string &name, bool repeat) override; - bool addVarBoutReal(const string &name, bool repeat) override; - bool addVarField2D(const string &name, bool repeat) override; - bool addVarField3D(const string &name, bool repeat) override; + bool addVarInt(const std::string &name, bool repeat) override; + bool addVarBoutReal(const std::string &name, bool repeat) override; + bool addVarField2D(const std::string &name, bool repeat) override; + bool addVarField3D(const std::string &name, bool repeat) override; // Read / Write simple variables up to 3D bool read(int *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; - bool read(int *var, const string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool read(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; - bool read(BoutReal *var, const string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool write(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; - bool write(int *var, const string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; bool write(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; - bool write(BoutReal *var, const string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; // Read / Write record-based variables bool read_rec(int *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; - bool read_rec(int *var, const string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read_rec(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool read_rec(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; - bool read_rec(BoutReal *var, const string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read_rec(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool write_rec(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; - bool write_rec(int *var, const string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write_rec(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; - bool write_rec(BoutReal *var, const string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write_rec(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; void setLowPrecision() override { lowPrecision = true; } @@ -144,7 +141,7 @@ class NcFormat : public DataFormat { int x0, y0, z0, t0; ///< Data origins - map rec_nr; // Record number for each variable (bit nasty) + std::map rec_nr; // Record number for each variable (bit nasty) int default_rec; // Starting record. Useful when appending to existing file void checkName(const char* name); ///< Check if a name contains invalid characters diff --git a/src/fileio/impls/pnetcdf/pnetcdf.hxx b/src/fileio/impls/pnetcdf/pnetcdf.hxx index 3fa94cbafc..19f23d2917 100644 --- a/src/fileio/impls/pnetcdf/pnetcdf.hxx +++ b/src/fileio/impls/pnetcdf/pnetcdf.hxx @@ -50,21 +50,18 @@ class PncFormat; #include #include -using std::string; -using std::map; - class PncFormat : public DataFormat { public: PncFormat(); PncFormat(const char *name); - PncFormat(const string &name) : PncFormat(name.c_str()) {} + PncFormat(const std::string &name) : PncFormat(name.c_str()) {} ~PncFormat(); bool openr(const char *name) override; - bool openr(const string &name, int mype) {return openr(name);} + bool openr(const std::string &name, int mype) {return openr(name);} bool openw(const char *name, bool append=false) override; - bool openw(const string &name, int mype, bool append=false) {return openw(name, append);} + bool openw(const std::string &name, int mype, bool append=false) {return openw(name, append);} bool is_valid() override { return fname != nullptr; } @@ -75,7 +72,7 @@ class PncFormat : public DataFormat { const char* filename() { return fname; }; const vector getSize(const char *var) override; - const vector getSize(const string &var) override { return getSize(var.c_str()); } + const vector getSize(const std::string &var) override { return getSize(var.c_str()); } // Set the origin for all subsequent calls bool setGlobalOrigin(int x = 0, int y = 0, int z = 0) override; @@ -84,26 +81,26 @@ class PncFormat : public DataFormat { // Read / Write simple variables up to 3D bool read(int *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; - bool read(int *var, const string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool read(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; - bool read(BoutReal *var, const string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool write(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; - bool write(int *var, const string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; bool write(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; - bool write(BoutReal *var, const string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; // Read / Write record-based variables bool read_rec(int *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; - bool read_rec(int *var, const string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read_rec(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool read_rec(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; - bool read_rec(BoutReal *var, const string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read_rec(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool write_rec(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; - bool write_rec(int *var, const string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write_rec(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; - bool write_rec(BoutReal *var, const string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write_rec(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; void setLowPrecision() override { lowPrecision = true; } @@ -126,7 +123,7 @@ class PncFormat : public DataFormat { int x0, y0, z0, t0; ///< Data origins (global offsets) - map rec_nr; // Record number for each variable (bit nasty) + std::map rec_nr; // Record number for each variable (bit nasty) int default_rec; // Starting record. Useful when appending to existing file }; diff --git a/src/mesh/boundary_region.cxx b/src/mesh/boundary_region.cxx index 0ddd615e1d..bee26d439e 100644 --- a/src/mesh/boundary_region.cxx +++ b/src/mesh/boundary_region.cxx @@ -3,6 +3,8 @@ #include #include +using std::swap; + BoundaryRegionXIn::BoundaryRegionXIn(std::string name, int ymin, int ymax, Mesh* passmesh) : BoundaryRegion(name, -1, 0, passmesh), ys(ymin), ye(ymax) { diff --git a/src/solver/impls/arkode/arkode.hxx b/src/solver/impls/arkode/arkode.hxx index 0ec9318301..69f86ec6cd 100644 --- a/src/solver/impls/arkode/arkode.hxx +++ b/src/solver/impls/arkode/arkode.hxx @@ -49,7 +49,6 @@ class ArkodeSolver; #include #include -using std::vector; #include namespace { @@ -89,9 +88,12 @@ class ArkodeSolver : public Solver { BoutReal pre_Wtime; // Time in preconditioner BoutReal pre_ncalls; // Number of calls to preconditioner - - void set_abstol_values(BoutReal* abstolvec_data, vector &f2dtols, vector &f3dtols); - void loop_abstol_values_op(Ind2D i2d, BoutReal* abstolvec_data, int &p, vector &f2dtols, vector &f3dtols, bool bndry); + + void set_abstol_values(BoutReal *abstolvec_data, std::vector &f2dtols, + std::vector &f3dtols); + void loop_abstol_values_op(Ind2D i2d, BoutReal *abstolvec_data, int &p, + std::vector &f2dtols, + std::vector &f3dtols, bool bndry); }; #endif // __ARKODE_SOLVER_H__ diff --git a/src/solver/impls/cvode/cvode.hxx b/src/solver/impls/cvode/cvode.hxx index c03215ef58..4bf8124b39 100644 --- a/src/solver/impls/cvode/cvode.hxx +++ b/src/solver/impls/cvode/cvode.hxx @@ -48,7 +48,6 @@ class CvodeSolver; #include #include -using std::vector; #include namespace { @@ -88,9 +87,12 @@ class CvodeSolver : public Solver { BoutReal pre_Wtime; // Time in preconditioner BoutReal pre_ncalls; // Number of calls to preconditioner - - void set_abstol_values(BoutReal* abstolvec_data, vector &f2dtols, vector &f3dtols); - void loop_abstol_values_op(Ind2D i2d, BoutReal* abstolvec_data, int &p, vector &f2dtols, vector &f3dtols, bool bndry); + + void set_abstol_values(BoutReal *abstolvec_data, std::vector &f2dtols, + std::vector &f3dtols); + void loop_abstol_values_op(Ind2D i2d, BoutReal *abstolvec_data, int &p, + std::vector &f2dtols, + std::vector &f3dtols, bool bndry); }; #endif // __SUNDIAL_SOLVER_H__ diff --git a/src/solver/impls/ida/ida.hxx b/src/solver/impls/ida/ida.hxx index dbb268e2cd..575218f806 100644 --- a/src/solver/impls/ida/ida.hxx +++ b/src/solver/impls/ida/ida.hxx @@ -48,7 +48,6 @@ class IdaSolver; #include #include -using std::vector; #include namespace { diff --git a/src/solver/impls/slepc/slepc.hxx b/src/solver/impls/slepc/slepc.hxx index b272e053d8..b4c8e092ec 100644 --- a/src/solver/impls/slepc/slepc.hxx +++ b/src/solver/impls/slepc/slepc.hxx @@ -55,8 +55,6 @@ namespace { RegisterSolver registersolverslepc("slepc"); } -using std::vector; - class SlepcSolver : public Solver { public: SlepcSolver(Options *options); From a27e9917278a92a836ca88360be553c55d21db71 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Oct 2018 16:34:23 +0100 Subject: [PATCH 0136/1783] Run pytest with integrated tests instead of unit tests --- .travis_script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis_script.sh b/.travis_script.sh index 8d36b051dd..b8595e086e 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -95,12 +95,12 @@ fi if [[ ${UNIT} == 1 ]] then time make check-unit-tests || exit - time py.test-3 tools/pylib/ || exit fi if [[ ${INTEGRATED} == 1 ]] then time make check-integrated-tests || exit + time py.test-3 tools/pylib/ || exit fi if [[ ${MMS} == 1 ]] From 6edafba2335cc3d0aa428844700190989c09e21e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Oct 2018 16:51:27 +0100 Subject: [PATCH 0137/1783] Fix some missing namespaces --- src/field/fieldgenerators.cxx | 26 +++++++++++++------------- src/fileio/impls/netcdf/nc_format.cxx | 3 +++ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/field/fieldgenerators.cxx b/src/field/fieldgenerators.cxx index 916d3605e5..2881917398 100644 --- a/src/field/fieldgenerators.cxx +++ b/src/field/fieldgenerators.cxx @@ -6,7 +6,7 @@ ////////////////////////////////////////////////////////// -FieldGeneratorPtr FieldSin::clone(const list args) { +FieldGeneratorPtr FieldSin::clone(const std::list args) { if(args.size() != 1) { throw ParseException("Incorrect number of arguments to sin function. Expecting 1, got %d", args.size()); } @@ -18,7 +18,7 @@ BoutReal FieldSin::generate(double x, double y, double z, double t) { return sin(gen->generate(x,y,z,t)); } -FieldGeneratorPtr FieldCos::clone(const list args) { +FieldGeneratorPtr FieldCos::clone(const std::list args) { if(args.size() != 1) { throw ParseException("Incorrect number of arguments to cos function. Expecting 1, got %d", args.size()); } @@ -30,7 +30,7 @@ BoutReal FieldCos::generate(double x, double y, double z, double t) { return cos(gen->generate(x,y,z,t)); } -FieldGeneratorPtr FieldSinh::clone(const list args) { +FieldGeneratorPtr FieldSinh::clone(const std::list args) { if(args.size() != 1) { throw ParseException("Incorrect number of arguments to sinh function. Expecting 1, got %d", args.size()); } @@ -42,7 +42,7 @@ BoutReal FieldSinh::generate(double x, double y, double z, double t) { return sinh(gen->generate(x,y,z,t)); } -FieldGeneratorPtr FieldCosh::clone(const list args) { +FieldGeneratorPtr FieldCosh::clone(const std::list args) { if(args.size() != 1) { throw ParseException("Incorrect number of arguments to cosh function. Expecting 1, got %d", args.size()); } @@ -54,7 +54,7 @@ BoutReal FieldCosh::generate(double x, double y, double z, double t) { return cosh(gen->generate(x,y,z,t)); } -FieldGeneratorPtr FieldTanh::clone(const list args) { +FieldGeneratorPtr FieldTanh::clone(const std::list args) { if(args.size() != 1) { throw ParseException("Incorrect number of arguments to tanh function. Expecting 1, got ", args.size()); } @@ -65,7 +65,7 @@ BoutReal FieldTanh::generate(double x, double y, double z, double t) { return tanh(gen->generate(x,y,z,t)); } -FieldGeneratorPtr FieldGaussian::clone(const list args) { +FieldGeneratorPtr FieldGaussian::clone(const std::list args) { if((args.size() < 1) || (args.size() > 2)) { throw ParseException("Incorrect number of arguments to gaussian function. Expecting 1 or 2, got ", args.size()); } @@ -85,7 +85,7 @@ BoutReal FieldGaussian::generate(double x, double y, double z, double t) { return exp(-SQ(X->generate(x,y,z,t)/sigma)/2.) / (sqrt(TWOPI) * sigma); } -FieldGeneratorPtr FieldAbs::clone(const list args) { +FieldGeneratorPtr FieldAbs::clone(const std::list args) { if(args.size() != 1) { throw ParseException("Incorrect number of arguments to abs function. Expecting 1, got %d", args.size()); } @@ -97,7 +97,7 @@ BoutReal FieldAbs::generate(double x, double y, double z, double t) { return fabs(gen->generate(x,y,z,t)); } -FieldGeneratorPtr FieldSqrt::clone(const list args) { +FieldGeneratorPtr FieldSqrt::clone(const std::list args) { if(args.size() != 1) { throw ParseException("Incorrect number of arguments to sqrt function. Expecting 1, got %d", args.size()); } @@ -109,7 +109,7 @@ BoutReal FieldSqrt::generate(double x, double y, double z, double t) { return sqrt(gen->generate(x,y,z,t)); } -FieldGeneratorPtr FieldHeaviside::clone(const list args) { +FieldGeneratorPtr FieldHeaviside::clone(const std::list args) { if(args.size() != 1) { throw ParseException("Incorrect number of arguments to heaviside function. Expecting 1, got %d", args.size()); } @@ -121,7 +121,7 @@ BoutReal FieldHeaviside::generate(double x, double y, double z, double t) { return (gen->generate(x,y,z,t) > 0.0) ? 1.0 : 0.0; } -FieldGeneratorPtr FieldErf::clone(const list args) { +FieldGeneratorPtr FieldErf::clone(const std::list args) { if(args.size() != 1) { throw ParseException("Incorrect number of arguments to erf function. Expecting 1, got %d", args.size()); } @@ -137,7 +137,7 @@ BoutReal FieldErf::generate(double x, double y, double z, double t) { // Ballooning transform // Use a truncated Ballooning transform to enforce periodicity in y and z -FieldGeneratorPtr FieldBallooning::clone(const list args) { +FieldGeneratorPtr FieldBallooning::clone(const std::list args) { int n = ball_n; switch(args.size()) { case 2: { @@ -196,7 +196,7 @@ FieldMixmode::FieldMixmode(FieldGeneratorPtr a, BoutReal seed) : arg(std::move(a phase[i] = PI * (2.*genRand(seed + i) - 1.); } -FieldGeneratorPtr FieldMixmode::clone(const list args) { +FieldGeneratorPtr FieldMixmode::clone(const std::list args) { BoutReal seed = 0.5; switch(args.size()) { case 2: { @@ -245,7 +245,7 @@ BoutReal FieldMixmode::genRand(BoutReal seed) { ////////////////////////////////////////////////////////// // TanhHat -FieldGeneratorPtr FieldTanhHat::clone(const list args) { +FieldGeneratorPtr FieldTanhHat::clone(const std::list args) { if(args.size() != 4) { throw ParseException("Incorrect number of arguments to TanhHat function. Expecting 4, got %d", args.size()); } diff --git a/src/fileio/impls/netcdf/nc_format.cxx b/src/fileio/impls/netcdf/nc_format.cxx index cc5b01598b..98047c9e3f 100644 --- a/src/fileio/impls/netcdf/nc_format.cxx +++ b/src/fileio/impls/netcdf/nc_format.cxx @@ -31,6 +31,9 @@ #include #include +using std::string; +using std::vector; + // Define this to see loads of info messages //#define NCDF_VERBOSE From 3ae67b3889aa132372b536053035743dd4992c23 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Oct 2018 17:50:05 +0100 Subject: [PATCH 0138/1783] Fix even more missing namespaces --- src/solver/impls/arkode/arkode.cxx | 16 +++++++++------- src/solver/impls/cvode/cvode.cxx | 14 +++++++------- tests/integrated/test-invpar/test_invpar.cxx | 2 +- tests/integrated/test-vec/testVec.cxx | 2 +- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index 32420a9cc0..20316aac44 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -156,8 +156,8 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { BoutReal tempabstol; if ((abstolvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) throw BoutException("ERROR: SUNDIALS memory allocation (abstol vector) failed\n"); - vector f2dtols; - vector f3dtols; + std::vector f2dtols; + std::vector f3dtols; BoutReal* abstolvec_data = NV_DATA_P(abstolvec); for (const auto& f2 : f2d) { abstol_options = Options::getRoot()->getSection(f2.name); @@ -706,7 +706,9 @@ static int arkode_jac(N_Vector v, N_Vector Jv, realtype t, N_Vector y, * vector abstol functions **************************************************************************/ -void ArkodeSolver::set_abstol_values(BoutReal* abstolvec_data, vector &f2dtols, vector &f3dtols) { +void ArkodeSolver::set_abstol_values(BoutReal *abstolvec_data, + std::vector &f2dtols, + std::vector &f3dtols) { int p = 0; // Counter for location in abstolvec_data array // All boundaries @@ -721,10 +723,10 @@ void ArkodeSolver::set_abstol_values(BoutReal* abstolvec_data, vector void ArkodeSolver::loop_abstol_values_op(Ind2D UNUSED(i2d), BoutReal *abstolvec_data, int &p, - vector &f2dtols, - vector &f3dtols, bool bndry) { + std::vector &f2dtols, + std::vector &f3dtols, bool bndry) { // Loop over 2D variables - for(vector::size_type i=0; i::size_type i=0; iLocalNz; jz++) { // Loop over 3D variables - for(vector::size_type i=0; i::size_type i=0; i f2dtols; - vector f3dtols; + std::vector f2dtols; + std::vector f3dtols; BoutReal* abstolvec_data = NV_DATA_P(abstolvec); for (const auto& f : f2d) { abstol_options = Options::getRoot()->getSection(f.name); @@ -577,7 +577,7 @@ static int cvode_jac(N_Vector v, N_Vector Jv, realtype t, N_Vector y, N_Vector U * vector abstol functions **************************************************************************/ -void CvodeSolver::set_abstol_values(BoutReal* abstolvec_data, vector &f2dtols, vector &f3dtols) { +void CvodeSolver::set_abstol_values(BoutReal* abstolvec_data, std::vector &f2dtols, std::vector &f3dtols) { int p = 0; // Counter for location in abstolvec_data array // All boundaries @@ -592,10 +592,10 @@ void CvodeSolver::set_abstol_values(BoutReal* abstolvec_data, vector & void CvodeSolver::loop_abstol_values_op(Ind2D UNUSED(i2d), BoutReal *abstolvec_data, int &p, - vector &f2dtols, - vector &f3dtols, bool bndry) { + std::vector &f2dtols, + std::vector &f3dtols, bool bndry) { // Loop over 2D variables - for(vector::size_type i=0; i::size_type i=0; iLocalNz; jz++) { // Loop over 3D variables - for(vector::size_type i=0; i::size_type i=0; iget("acoef", acoef, "1.0"); options->get("bcoef", bcoef, "-1.0"); options->get("input", func, "sin(2*y)"); diff --git a/tests/integrated/test-vec/testVec.cxx b/tests/integrated/test-vec/testVec.cxx index 09173a0e05..ac027bf61f 100644 --- a/tests/integrated/test-vec/testVec.cxx +++ b/tests/integrated/test-vec/testVec.cxx @@ -10,7 +10,7 @@ class VecTest : public PhysicsModel { public: Field3D n; Vector3D gradPerpN; - string ownOpType; + std::string ownOpType; }; From 603d0d7336a136fcbbd69863528ce6b073e2b81a Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 26 Oct 2018 23:46:47 +0100 Subject: [PATCH 0139/1783] Enable NLS by default, improve makefile AM_GETTEXT macro has an option `--disable-nls` to turn off if needed. `locale/makefile` no longer needs to be modified to add more languages. Creating a new language is just `make po-XX`, edit, then `make`. --- configure | 45 ++++++++++++++++----------------------------- configure.ac | 47 +++++++++++++++++++++-------------------------- locale/README.md | 28 +++++++++++++++++++++++----- locale/makefile | 22 ++++++++++++---------- 4 files changed, 72 insertions(+), 70 deletions(-) diff --git a/configure b/configure index 3a9cb933dd..d7205eb1f1 100755 --- a/configure +++ b/configure @@ -815,11 +815,11 @@ enable_shared enable_openmp with_openmp_schedule enable_pvode_openmp -enable_nls with_gcov enable_code_coverage with_hdf5 with_parallelhdf5 +enable_nls with_gnu_ld enable_rpath with_libiconv_prefix @@ -1479,7 +1479,6 @@ Optional Features: --enable-shared Enable building bout++ into an shared object --enable-openmp Enable building with OpenMP support --enable-pvode-openmp Enable building PVODE with OpenMP support - --enable-nls Enable Natural Language Support with gettext --disable-openmp do not use OpenMP --enable-code-coverage Whether to enable code coverage support --disable-nls do not use Native Language Support @@ -2719,13 +2718,6 @@ else enable_pvode_openmp=no fi -# Check whether --enable-nls was given. -if test "${enable_nls+set}" = set; then : - enableval=$enable_nls; -else - enable_nls=no -fi - @@ -12142,6 +12134,11 @@ fi ############################################################# HAS_NLS="no" +# Use macro to test if Natural Language Support (gettext) is available. +# If available sets: +# - USE_NLS to "yes" +# - LIBINTL to the linker options +# - Modifies CPPFLAGS if needed { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether NLS is requested" >&5 $as_echo_n "checking whether NLS is requested... " >&6; } @@ -13208,13 +13205,6 @@ fi -if test "$enable_nls" != "no" ; then : - - # Use macro to test if Natural Language Support (gettext) is available. - # If available sets: - # - USE_NLS to "yes" - # - LIBINTL to the linker options - # - Modifies CPPFLAGS if needed @@ -14307,31 +14297,28 @@ $as_echo "#define HAVE_DCGETTEXT 1" >>confdefs.h - if test "$USE_NLS" = "yes"; then : +if test "$USE_NLS" = "yes"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: Enabling language support with gettext" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: Enabling language support with gettext" >&5 $as_echo "$as_me: Enabling language support with gettext" >&6;} + # Turn the .po files into .mo files + $MAKE -C locale | tee -a config-build.log 2>&1 - # Turn the .po files into .mo files - $MAKE -C locale | tee -a config-build.log 2>&1 - - # Note: BOUT_LOCALE_PATH is defined in make.config, and may be changed by `make install`. - CXXFLAGS="$CXXFLAGS -DBOUT_HAS_GETTEXT -DBOUT_LOCALE_PATH=\$(BOUT_LOCALE_PATH)" + # Note: BOUT_LOCALE_PATH is defined in make.config, and may be changed by `make install`. + CXXFLAGS="$CXXFLAGS -DBOUT_HAS_GETTEXT -DBOUT_LOCALE_PATH=\$(BOUT_LOCALE_PATH)" - EXTRA_LIBS="$EXTRA_LIBS $LIBINTL" + EXTRA_LIBS="$EXTRA_LIBS $LIBINTL" - # Set variable substituted into bout-config - HAS_NLS="yes" + # Set variable substituted into bout-config + HAS_NLS="yes" else - { $as_echo "$as_me:${as_lineno-$LINENO}: Language support with gettext not available" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: Language support with gettext not available" >&5 $as_echo "$as_me: Language support with gettext not available" >&6;} fi -fi - ############################################################# # Check environment ############################################################# diff --git a/configure.ac b/configure.ac index 8e75493b7d..8451b37c3e 100644 --- a/configure.ac +++ b/configure.ac @@ -91,8 +91,6 @@ AC_ARG_WITH(openmp_schedule,[AS_HELP_STRING([--with-openmp-schedule=static], [Set OpenMP schedule (default: static)])],,[with_openmp_schedule=static]) AC_ARG_ENABLE(pvode_openmp, [AS_HELP_STRING([--enable-pvode-openmp], [Enable building PVODE with OpenMP support])],,[enable_pvode_openmp=no]) -AC_ARG_ENABLE(nls, [AS_HELP_STRING([--enable-nls], - [Enable Natural Language Support with gettext])],,[enable_nls=no]) AC_ARG_VAR(EXTRA_INCS,[Extra compile flags]) AC_ARG_VAR(EXTRA_LIBS,[Extra linking flags]) @@ -1137,30 +1135,27 @@ AS_IF([test "$with_pvode" != "no"], [ ############################################################# HAS_NLS="no" -AS_IF([test "$enable_nls" != "no" ], [ - # Use macro to test if Natural Language Support (gettext) is available. - # If available sets: - # - USE_NLS to "yes" - # - LIBINTL to the linker options - # - Modifies CPPFLAGS if needed - AM_GNU_GETTEXT([external]) - AS_IF([test "$USE_NLS" = "yes"], [ - AC_MSG_NOTICE([Enabling language support with gettext]) - - # Turn the .po files into .mo files - $MAKE -C locale | tee -a config-build.log 2>&1 - - # Note: BOUT_LOCALE_PATH is defined in make.config, and may be changed by `make install`. - CXXFLAGS="$CXXFLAGS -DBOUT_HAS_GETTEXT -DBOUT_LOCALE_PATH=\$(BOUT_LOCALE_PATH)" - - EXTRA_LIBS="$EXTRA_LIBS $LIBINTL" - - # Set variable substituted into bout-config - HAS_NLS="yes" - ],[ - AC_MSG_NOTICE([Language support with gettext not available]) - ]) -]) +# Use macro to test if Natural Language Support (gettext) is available. +# If available sets: +# - USE_NLS to "yes" +# - LIBINTL to the linker options +# - Modifies CPPFLAGS if needed +AM_GNU_GETTEXT([external]) +AS_IF([test "$USE_NLS" = "yes"], [ + AC_MSG_NOTICE([Enabling language support with gettext]) + # Turn the .po files into .mo files + $MAKE -C locale | tee -a config-build.log 2>&1 + + # Note: BOUT_LOCALE_PATH is defined in make.config, and may be changed by `make install`. + CXXFLAGS="$CXXFLAGS -DBOUT_HAS_GETTEXT -DBOUT_LOCALE_PATH=\$(BOUT_LOCALE_PATH)" + + EXTRA_LIBS="$EXTRA_LIBS $LIBINTL" + + # Set variable substituted into bout-config + HAS_NLS="yes" +],[ + AC_MSG_NOTICE([Language support with gettext not available]) +]) ############################################################# # Check environment diff --git a/locale/README.md b/locale/README.md index 2b764dc871..4f35c2da08 100644 --- a/locale/README.md +++ b/locale/README.md @@ -1,9 +1,27 @@ +Natural Language Support (NLS) +============================== -To start a new translation: +These are inputs for language support using gettext. - msginit --input=libbout.pot --locale=fr --output=fr/libbout.po + - Template file libbout.pot : Do not edit + This is generated by extracting strings from the BOUT++ source. + - Language files .po which are human-readable. These contain + translations for particular languages, and can be edited. + - Machine readable .mo files. These are created from the .po files. -Edit the .po file, then convert to a .mo file: -Note: Change the content line to: "Content-Type: text/plain; charset=UTF-8\n" +Build all .mo files: + + make + +Update the template (.pot) file: + + make libbout.pot + +Start a new translation: + + make po-XX + +where XX is the language e.g. "de" for German, or a language_country code e.g. "de_DE". +This will update a .po file if it already exists. +Edit the .po file, translating or deleting new entries, then remake the .mo files. - msgfmt --output-file=LC_MESSAGES/libbout.mo libbout.po diff --git a/locale/makefile b/locale/makefile index 99d6570c25..eb9aa71b0b 100644 --- a/locale/makefile +++ b/locale/makefile @@ -2,32 +2,34 @@ # Internationalisation ###################################################################### -# List of supported locales -LANGUAGES = fr zh_TW zh_CN +# Find all .po files and work out the corresponding .mo file name +PO_FILES = $(shell ls */libbout.po) +MO_FILES = $(PO_FILES:%/libbout.po=%/LC_MESSAGES/libbout.mo) # This target is the most commonly used, to build all the .mo files .PHONY: locale -locale: $(LANGUAGES:%=%/LC_MESSAGES/libbout.mo) - -# Update all .po files. Note that they will then need manually -# editing to fill in (or delete) missing translations. -.PHONY: po-all -all-po: $(LANGUAGES:%=%/libbout.po) +locale: $(MO_FILES) # Create the template file, combining all source files libbout.pot: FORCE xgettext --keyword=_ --language=c++ --add-comments --sort-output -o $@ `find ../ -name "*.[ch]xx"` # Update a .po file +# If it doesn't exist then create; if it exists then update +# Note that it will need manually editing to translate or delete new entries %/libbout.po: libbout.pot - msgmerge --update $@ $< + @mkdir -p $(@D) + @if [ -a $@ ]; then echo "Updating " $@; msgmerge --update $@ $< ; else echo "Creating " $@; msginit --input=libbout.pot --locale=$* --output=$@; fi; + @echo "Now edit " $@ " to translate or delete new entries" + @echo "then run 'make' to generate the .mo file" # Update a .mo file, ensuring that the directory exists # Note: Because the .po files must be updated manually, # don't automatically generate the .po files %/LC_MESSAGES/libbout.mo: FORCE @mkdir -p $(@D) - msgfmt --output-file=$@ $*/libbout.po + @echo "Building language: " $* + @msgfmt --output-file=$@ $*/libbout.po # Shortcut target for building single language # e.g. "make po-fr" From 5a0306780352c69aec47959136a1599319c5df5a Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 27 Oct 2018 16:35:23 +0100 Subject: [PATCH 0140/1783] Marking more strings for translation Updating libbout.pot template file --- locale/libbout.pot | 404 ++++++++++++++++++++++++++++++- src/bout++.cxx | 80 +++--- src/mesh/impls/bout/boutmesh.cxx | 8 +- src/mesh/mesh.cxx | 34 +-- src/solver/solver.cxx | 22 +- src/sys/options.cxx | 33 +-- src/sys/options/options_ini.cxx | 6 +- src/sys/optionsreader.cxx | 8 +- 8 files changed, 489 insertions(+), 106 deletions(-) diff --git a/locale/libbout.pot b/locale/libbout.pot index e5f2c60474..19bd580d28 100644 --- a/locale/libbout.pot +++ b/locale/libbout.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-25 23:40+0100\n" +"POT-Creation-Date: 2018-10-27 16:33+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,15 +17,35 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: ../src/bout++.cxx:370 +#: ../src/mesh/impls/bout/boutmesh.cxx:376 +msgid "\t -> Good value\n" +msgstr "" + +#. Loop over all possibilities +#. Processors divide equally +#. Mesh in X divides equally +#. Mesh in Y divides equally +#: ../src/mesh/impls/bout/boutmesh.cxx:311 +#, c-format +msgid "\tCandidate value: %d\n" +msgstr "" + +#: ../src/bout++.cxx:372 msgid "\tChecking disabled\n" msgstr "" -#: ../src/bout++.cxx:368 +#: ../src/bout++.cxx:370 #, c-format msgid "\tChecking enabled, level %d\n" msgstr "" +#. The stringify is needed here as BOUT_FLAGS_STRING may already contain quoted strings +#. which could cause problems (e.g. terminate strings). +#: ../src/bout++.cxx:413 +#, c-format +msgid "\tCompiled with flags : %s\n" +msgstr "" + #: ../src/mesh/impls/bout/boutmesh.cxx:390 #, c-format msgid "" @@ -37,6 +57,18 @@ msgstr "" msgid "\tERROR: Cannot split %d Y points equally between %d processors\n" msgstr "" +#: ../src/sys/options/options_ini.cxx:173 +#, c-format +msgid "" +"\tEmpty key\n" +"\tLine: %s" +msgstr "" + +#: ../src/sys/optionsreader.cxx:140 +#, c-format +msgid "\tEmpty key or value in command line '%s'\n" +msgstr "" + #: ../src/mesh/impls/bout/boutmesh.cxx:127 msgid "\tGrid size: " msgstr "" @@ -45,24 +77,64 @@ msgstr "" msgid "\tGuard cells (x,y): " msgstr "" +#: ../src/sys/optionsreader.cxx:127 +#, c-format +msgid "\tMultiple '=' in command-line argument '%s'\n" +msgstr "" + +#: ../src/bout++.cxx:400 +msgid "\tOpenMP parallelisation disabled\n" +msgstr "" + +#: ../src/bout++.cxx:398 +#, c-format +msgid "\tOpenMP parallelisation enabled, using %d threads\n" +msgstr "" + #. Mark the option as used #. Option not found #: ../src/sys/options.cxx:96 ../src/sys/options.cxx:136 -#: ../src/sys/options.cxx:171 ../src/sys/options.cxx:199 -#: ../src/sys/options.cxx:220 ../src/sys/options.cxx:223 +#: ../src/sys/options.cxx:172 ../src/sys/options.cxx:200 +#: ../src/sys/options.cxx:221 ../src/sys/options.cxx:224 #: ../include/options.hxx:298 ../include/options.hxx:319 msgid "\tOption " msgstr "" +#: ../src/sys/options.cxx:226 +#, c-format +msgid "\tOption '%s': Boolean expected. Got '%s'\n" +msgstr "" + +#: ../src/sys/options/options_ini.cxx:74 +#, c-format +msgid "\tOptions file '%s' not found\n" +msgstr "" + +#: ../src/bout++.cxx:394 +msgid "\tParallel NetCDF support disabled\n" +msgstr "" + +#: ../src/bout++.cxx:392 +msgid "\tParallel NetCDF support enabled\n" +msgstr "" + #: ../src/mesh/impls/bout/boutmesh.cxx:124 msgid "\tRead nz from input grid file\n" msgstr "" -#: ../src/bout++.cxx:376 +#: ../src/mesh/mesh.cxx:124 +msgid "\tReading contravariant vector " +msgstr "" + +#: ../src/mesh/mesh.cxx:117 ../src/mesh/mesh.cxx:138 +msgid "\tReading covariant vector " +msgstr "" + +#: ../src/bout++.cxx:378 msgid "\tSignal handling disabled\n" msgstr "" -#: ../src/bout++.cxx:374 +#: ../src/bout++.cxx:376 msgid "\tSignal handling enabled\n" msgstr "" @@ -70,6 +142,30 @@ msgstr "" msgid "\tdone\n" msgstr "" +#: ../src/bout++.cxx:387 +msgid "\tnetCDF support disabled\n" +msgstr "" + +#: ../src/bout++.cxx:382 +msgid "\tnetCDF support enabled\n" +msgstr "" + +#: ../src/bout++.cxx:385 +msgid "\tnetCDF4 support enabled\n" +msgstr "" + +#: ../src/bout++.cxx:174 +#, c-format +msgid "" +"\n" +" -d \tLook in for input/output files\n" +" -f \tUse OPTIONS given in \n" +" -o \tSave used OPTIONS given to \n" +" -l, --log \tPrint log to \n" +" -v, --verbose\t\tIncrease verbosity\n" +" -q, --quiet\t\tDecrease verbosity\n" +msgstr "" + #: ../src/solver/solver.cxx:563 #, c-format msgid "" @@ -84,6 +180,37 @@ msgid "" "Run started at : %s\n" msgstr "" +#: ../src/bout++.cxx:183 +#, c-format +msgid " -c, --color\t\tColor output using bout-log-color\n" +msgstr "" + +#: ../src/bout++.cxx:186 +#, c-format +msgid "" +" -h, --help\t\tThis message\n" +" restart [append]\tRestart the simulation. If append is specified, append " +"to the existing output files, otherwise overwrite them\n" +" VAR=VALUE\t\tSpecify a VALUE for input parameter VAR\n" +"\n" +"For all possible input parameters, see the user manual and/or the physics " +"model source (e.g. %s.cxx)\n" +msgstr "" + +#: ../src/sys/options.cxx:97 +msgid ") overwritten with:" +msgstr "" + +#: ../src/sys/options.cxx:248 +msgid "All options used\n" +msgstr "" + +#. / Print intro +#: ../src/bout++.cxx:350 +#, c-format +msgid "BOUT++ version %s\n" +msgstr "" + #: ../src/mesh/impls/bout/boutmesh.cxx:827 msgid "Boundary regions in this processor: " msgstr "" @@ -93,13 +220,22 @@ msgstr "" msgid "Cannot split %d X points equally between %d processors\n" msgstr "" -#: ../src/bout++.cxx:355 +#: ../src/bout++.cxx:357 #, c-format msgid "" "Code compiled on %s at %s\n" "\n" msgstr "" +#: ../src/sys/optionsreader.cxx:142 +msgid "Command line" +msgstr "" + +#. / Print compile-time options +#: ../src/bout++.cxx:367 +msgid "Compile-time options:\n" +msgstr "" + #: ../src/mesh/impls/bout/boutmesh.cxx:836 msgid "Constructing default regions" msgstr "" @@ -109,25 +245,80 @@ msgid "" "Could not find a valid value for NXPE. Try a different number of processors." msgstr "" -#: ../src/bout++.cxx:261 +#: ../src/sys/options/options_ini.cxx:132 +#, c-format +msgid "Could not open output file '%s'\n" +msgstr "" + +#. Error reading +#: ../src/mesh/mesh.cxx:278 +#, c-format +msgid "Could not read integer array '%s'\n" +msgstr "" + +#. Failed . Probably not important enough to stop the simulation +#: ../src/bout++.cxx:310 +#, c-format +msgid "Could not run bout-log-color. Make sure it is in your PATH\n" +msgstr "" + +#: ../src/solver/solver.cxx:642 +#, c-format +msgid "Couldn't add Monitor: %g is not a multiple of %g!" +msgstr "" + +#: ../src/mesh/mesh.cxx:349 +#, c-format +msgid "Couldn't find region %s in regionMap2D" +msgstr "" + +#: ../src/mesh/mesh.cxx:341 +#, c-format +msgid "Couldn't find region %s in regionMap3D" +msgstr "" + +#: ../src/mesh/mesh.cxx:357 +#, c-format +msgid "Couldn't find region %s in regionMapPerp" +msgstr "" + +#: ../src/sys/options.cxx:192 +#, c-format +msgid "Couldn't get BoutReal from option %s = '%s'" +msgstr "" + +#: ../src/sys/options.cxx:156 +#, c-format +msgid "Couldn't get integer from option %s = '%s'" +msgstr "" + +#: ../src/bout++.cxx:263 #, c-format msgid "DataDir \"%s\" does not exist or is not accessible\n" msgstr "" -#: ../src/bout++.cxx:258 +#: ../src/bout++.cxx:260 #, c-format msgid "DataDir \"%s\" is not a directory\n" msgstr "" -#: ../src/bout++.cxx:429 +#: ../src/solver/solver.cxx:597 +msgid "ERROR: Solver is already initialised\n" +msgstr "" + +#: ../src/bout++.cxx:431 msgid "Error encountered during initialisation\n" msgstr "" -#: ../src/bout++.cxx:474 +#: ../src/bout++.cxx:476 #, c-format msgid "Error encountered during initialisation: %s\n" msgstr "" +#: ../src/bout++.cxx:510 +msgid "Error whilst writing settings" +msgstr "" + #: ../src/mesh/impls/bout/boutmesh.cxx:147 #, c-format msgid "Error: nx must be greater than 2 times MXG (2 * %d)" @@ -141,6 +332,16 @@ msgstr "" msgid "Hello World\n" msgstr "" +#: ../src/solver/solver.cxx:599 +msgid "Initialising solver\n" +msgstr "" + +#: ../src/bout++.cxx:252 +msgid "" +"Input and output file for settings must be different.\n" +"Provide -o to avoid this issue.\n" +msgstr "" + #: ../src/mesh/impls/bout/boutmesh.cxx:91 msgid "Loading mesh" msgstr "" @@ -153,6 +354,20 @@ msgstr "" msgid "Mesh must contain ny" msgstr "" +#. Not found +#: ../src/mesh/mesh.cxx:282 +#, c-format +msgid "Missing integer array %s\n" +msgstr "" + +#: ../src/solver/solver.cxx:696 +msgid "Monitor signalled to quit" +msgstr "" + +#: ../src/solver/solver.cxx:703 +msgid "Monitor signalled to quit\n" +msgstr "" + #: ../src/mesh/impls/bout/boutmesh.cxx:833 msgid "No boundary regions in this processor" msgstr "" @@ -162,6 +377,60 @@ msgstr "" msgid "Number of processors (%d) not divisible by NPs in x direction (%d)\n" msgstr "" +#. Less than 1 time-step left +#: ../src/bout++.cxx:660 +#, c-format +msgid "Only %e seconds left. Quitting\n" +msgstr "" + +#: ../src/sys/options.cxx:130 ../src/sys/options.cxx:148 +#: ../src/sys/options.cxx:184 ../src/sys/options.cxx:212 +#, c-format +msgid "Option %s has no value" +msgstr "" + +#: ../src/sys/options.cxx:59 +#, c-format +msgid "Option %s is not a section" +msgstr "" + +#. Doesn't exist +#: ../src/sys/options.cxx:70 +#, c-format +msgid "Option %s:%s does not exist" +msgstr "" + +#: ../src/sys/options.cxx:101 +#, c-format +msgid "" +"Options: Setting a value from same source (%s) to new value '%s' - old value " +"was '%s'." +msgstr "" + +#: ../src/bout++.cxx:361 +#, c-format +msgid "" +"Processor number: %d of %d\n" +"\n" +msgstr "" + +#: ../src/mesh/mesh.cxx:376 +msgid "Registered region 2D " +msgstr "" + +#: ../src/mesh/mesh.cxx:367 +msgid "Registered region 3D " +msgstr "" + +#: ../src/mesh/mesh.cxx:385 +msgid "Registered region Perp " +msgstr "" + +#: ../src/bout++.cxx:352 +#, c-format +msgid "Revision: %s\n" +msgstr "" + #: ../src/solver/solver.cxx:564 msgid "Run time : " msgstr "" @@ -173,6 +442,19 @@ msgid "" "\n" msgstr "" +#: ../src/bout++.cxx:621 +msgid "" +"Sim Time | RHS evals | Wall Time | Calc Inv Comm I/O SOLVER\n" +"\n" +msgstr "" + +#: ../src/bout++.cxx:624 +msgid "" +"Sim Time | RHS_e evals | RHS_I evals | Wall Time | Calc Inv " +"Comm I/O SOLVER\n" +"\n" +msgstr "" + #: ../src/solver/solver.cxx:521 #, c-format msgid "Solver running for %d outputs with monitor timestep of %e\n" @@ -183,6 +465,104 @@ msgstr "" msgid "Solver running for %d outputs with output timestep of %e\n" msgstr "" +#: ../src/solver/solver.cxx:648 +#, c-format +msgid "" +"Solver::addMonitor: Cannot reduce timestep (from %g to %g) after init is " +"called!" +msgstr "" + +#: ../src/solver/solver.cxx:1061 +#, c-format +msgid "" +"Time derivative at wrong location - Field is at %s, derivative is at %s for " +"field '%s'\n" +msgstr "" + +#: ../src/solver/solver.cxx:1267 +#, c-format +msgid "Time derivative for variable '%s' not set" +msgstr "" + +#: ../src/mesh/mesh.cxx:373 +#, c-format +msgid "Trying to add an already existing region %s to regionMap2D" +msgstr "" + +#: ../src/mesh/mesh.cxx:364 +#, c-format +msgid "Trying to add an already existing region %s to regionMap3D" +msgstr "" + +#: ../src/mesh/mesh.cxx:382 +#, c-format +msgid "Trying to add an already existing region %s to regionMapPerp" +msgstr "" + +#: ../src/mesh/mesh.cxx:313 +msgid "" +"Unrecognised paralleltransform option.\n" +"Valid choices are 'identity', 'shifted', 'fci'" +msgstr "" + +#: ../src/sys/options.cxx:250 +msgid "Unused options:\n" +msgstr "" + +#: ../src/bout++.cxx:202 +#, c-format +msgid "Usage is %s -d \n" +msgstr "" + +#: ../src/bout++.cxx:211 +#, c-format +msgid "Usage is %s -f \n" +msgstr "" + +#: ../src/bout++.cxx:228 +#, c-format +msgid "Usage is %s -l \n" +msgstr "" + +#: ../src/bout++.cxx:220 +#, c-format +msgid "Usage is %s -o \n" +msgstr "" + +#. Print help message -- note this will be displayed once per processor as we've not started MPI yet. +#: ../src/bout++.cxx:172 +#, c-format +msgid "" +"Usage: %s [-d ] [-f ] [restart [append]] " +"[VAR=VALUE]\n" +msgstr "" + +#: ../src/sys/options.cxx:166 +#, c-format +msgid "Value for option %s = %e is not an integer" +msgstr "" + +#: ../src/solver/solver.cxx:1020 ../src/solver/solver.cxx:1024 +#, c-format +msgid "Variable '%s' not initialised" +msgstr "" + +#. Should be a power of 2 for efficient FFTs +#: ../src/mesh/impls/bout/boutmesh.cxx:119 +msgid "" +"WARNING: Number of toroidal points should be 2^n for efficient FFT " +"performance -- consider changing MZ if using FFTs\n" +msgstr "" + +#: ../src/sys/optionsreader.cxx:60 +msgid "Writing options to file " +msgstr "" + +#. / The source label given to default values +#: ../src/sys/options.cxx:11 +msgid "default" +msgstr "" + #: ../src/mesh/impls/bout/boutmesh.cxx:156 msgid "nx must be greater than 2*MXG" msgstr "" diff --git a/src/bout++.cxx b/src/bout++.cxx index 73be8d47cf..48c8e0c7e7 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -169,24 +169,26 @@ int BoutInitialise(int &argc, char **&argv) { if (string(argv[i]) == "-h" || string(argv[i]) == "--help") { // Print help message -- note this will be displayed once per processor as we've not started MPI yet. - fprintf(stdout, "Usage: %s [-d ] [-f ] [restart [append]] [VAR=VALUE]\n", argv[0]); + fprintf(stdout, _("Usage: %s [-d ] [-f ] [restart [append]] [VAR=VALUE]\n"), argv[0]); fprintf(stdout, - "\n" - " -d \tLook in for input/output files\n" - " -f \tUse OPTIONS given in \n" - " -o \tSave used OPTIONS given to \n" - " -l, --log \tPrint log to \n" - " -v, --verbose\t\tIncrease verbosity\n" - " -q, --quiet\t\tDecrease verbosity\n" + _("\n" + " -d \tLook in for input/output files\n" + " -f \tUse OPTIONS given in \n" + " -o \tSave used OPTIONS given to \n" + " -l, --log \tPrint log to \n" + " -v, --verbose\t\tIncrease verbosity\n" + " -q, --quiet\t\tDecrease verbosity\n")); #ifdef LOGCOLOR - " -c, --color\t\tColor output using bout-log-color\n" + fprintf(stdout, + _(" -c, --color\t\tColor output using bout-log-color\n")); #endif - " -h, --help\t\tThis message\n" - " restart [append]\tRestart the simulation. If append is specified, " - "append to the existing output files, otherwise overwrite them\n" - " VAR=VALUE\t\tSpecify a VALUE for input parameter VAR\n" - "\nFor all possible input parameters, see the user manual and/or the " - "physics model source (e.g. %s.cxx)\n", + fprintf(stdout, + _(" -h, --help\t\tThis message\n" + " restart [append]\tRestart the simulation. If append is specified, " + "append to the existing output files, otherwise overwrite them\n" + " VAR=VALUE\t\tSpecify a VALUE for input parameter VAR\n" + "\nFor all possible input parameters, see the user manual and/or the " + "physics model source (e.g. %s.cxx)\n"), argv[0]); return -1; @@ -197,7 +199,7 @@ int BoutInitialise(int &argc, char **&argv) { if (string(argv[i]) == "-d") { // Set data directory if (i+1 >= argc) { - fprintf(stderr, "Usage is %s -d \n", argv[0]); + fprintf(stderr, _("Usage is %s -d \n"), argv[0]); return 1; } i++; @@ -206,7 +208,7 @@ int BoutInitialise(int &argc, char **&argv) { } else if (string(argv[i]) == "-f") { // Set options file if (i+1 >= argc) { - fprintf(stderr, "Usage is %s -f \n", argv[0]); + fprintf(stderr, _("Usage is %s -f \n"), argv[0]); return 1; } i++; @@ -215,7 +217,7 @@ int BoutInitialise(int &argc, char **&argv) { } else if (string(argv[i]) == "-o") { // Set options file if (i+1 >= argc) { - fprintf(stderr, "Usage is %s -o \n", argv[0]); + fprintf(stderr, _("Usage is %s -o \n"), argv[0]); return 1; } i++; @@ -223,7 +225,7 @@ int BoutInitialise(int &argc, char **&argv) { } else if ((string(argv[i]) == "-l") || (string(argv[i]) == "--log")) { if (i + 1 >= argc) { - fprintf(stderr, "Usage is %s -l \n", argv[0]); + fprintf(stderr, _("Usage is %s -l \n"), argv[0]); return 1; } i++; @@ -247,7 +249,7 @@ int BoutInitialise(int &argc, char **&argv) { } if (std::string(set_file) == std::string(opt_file)){ - throw BoutException("Input and output file for settings must be different.\nProvide -o to avoid this issue.\n"); + throw BoutException(_("Input and output file for settings must be different.\nProvide -o to avoid this issue.\n")); } // Check that data_dir exists. We do not check whether we can write, as it is @@ -305,7 +307,7 @@ int BoutInitialise(int &argc, char **&argv) { } if (!success) { // Failed . Probably not important enough to stop the simulation - fprintf(stderr, "Could not run bout-log-color. Make sure it is in your PATH\n"); + fprintf(stderr, _("Could not run bout-log-color. Make sure it is in your PATH\n")); } } #endif // LOGCOLOR @@ -345,9 +347,9 @@ int BoutInitialise(int &argc, char **&argv) { } /// Print intro - output_progress.write("BOUT++ version %s\n", BOUT_VERSION_STRING); + output_progress.write(_("BOUT++ version %s\n"), BOUT_VERSION_STRING); #ifdef REVISION - output_progress.write("Revision: %s\n", REV); + output_progress.write(_("Revision: %s\n"), REV); #endif #ifdef MD5SUM output_progress.write("MD5 checksum: %s\n", CHECKSUM); @@ -356,13 +358,13 @@ int BoutInitialise(int &argc, char **&argv) { output_info.write("B.Dudson (University of York), M.Umansky (LLNL) 2007\n"); output_info.write("Based on BOUT by Xueqiao Xu, 1999\n\n"); - output_info.write("Processor number: %d of %d\n\n", MYPE, NPES); + output_info.write(_("Processor number: %d of %d\n\n"), MYPE, NPES); output_info.write("pid: %d\n\n",getpid()); /// Print compile-time options - output_info.write("Compile-time options:\n"); + output_info.write(_("Compile-time options:\n")); #if CHECK > 0 output_info.write(_("\tChecking enabled, level %d\n"), CHECK); @@ -377,25 +379,25 @@ int BoutInitialise(int &argc, char **&argv) { #endif #ifdef NCDF - output_info.write("\tnetCDF support enabled\n"); + output_info.write(_("\tnetCDF support enabled\n")); #else #ifdef NCDF4 - output_info.write("\tnetCDF4 support enabled\n"); + output_info.write(_("\tnetCDF4 support enabled\n")); #else - output_info.write("\tnetCDF support disabled\n"); + output_info.write(_("\tnetCDF support disabled\n")); #endif #endif #ifdef PNCDF - output_info.write("\tParallel NetCDF support enabled\n"); + output_info.write(_("\tParallel NetCDF support enabled\n")); #else - output_info.write("\tParallel NetCDF support disabled\n"); + output_info.write(_("\tParallel NetCDF support disabled\n")); #endif #ifdef _OPENMP - output_info.write("\tOpenMP parallelisation enabled, using %d threads\n",omp_get_max_threads()); + output_info.write(_("\tOpenMP parallelisation enabled, using %d threads\n",omp_get_max_threads())); #else - output_info.write("\tOpenMP parallelisation disabled\n"); + output_info.write(_("\tOpenMP parallelisation disabled\n")); #endif #ifdef METRIC3D @@ -408,7 +410,7 @@ int BoutInitialise(int &argc, char **&argv) { //The stringify is needed here as BOUT_FLAGS_STRING may already contain quoted strings //which could cause problems (e.g. terminate strings). - output_info.write("\tCompiled with flags : %s\n",STRINGIFY(BOUT_FLAGS_STRING)); + output_info.write(_("\tCompiled with flags : %s\n"),STRINGIFY(BOUT_FLAGS_STRING)); /// Get the options tree Options *options = Options::getRoot(); @@ -505,7 +507,7 @@ int BoutFinalise() { reader->write(Options::getRoot(), "%s/%s", data_dir.c_str(), settingsfile.c_str()); } } catch (BoutException &e) { - output_error << "Error whilst writing settings" << endl; + output_error << _("Error whilst writing settings") << endl; output_error << e.what() << endl; } @@ -616,11 +618,11 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { /// Print the column header for timing info if (!output_split) { - output_progress.write("Sim Time | RHS evals | Wall Time | Calc Inv Comm I/O " - "SOLVER\n\n"); + output_progress.write(_("Sim Time | RHS evals | Wall Time | Calc Inv Comm " + " I/O SOLVER\n\n")); } else { - output_progress.write("Sim Time | RHS_e evals | RHS_I evals | Wall Time | Calc Inv " - " Comm I/O SOLVER\n\n"); + output_progress.write(_("Sim Time | RHS_e evals | RHS_I evals | Wall Time | " + "Calc Inv Comm I/O SOLVER\n\n")); } } @@ -655,7 +657,7 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { BoutReal t_remain = mpi_start_time + wall_limit - MPI_Wtime(); if (t_remain < wtime) { // Less than 1 time-step left - output_warn.write("Only %e seconds left. Quitting\n", t_remain); + output_warn.write(_("Only %e seconds left. Quitting\n"), t_remain); return 1; // Return an error code to quit } else { diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 9df5f340d6..242e0fadb5 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -116,8 +116,8 @@ int BoutMesh::load() { OPTION(options, MZ, 64); if (!is_pow2(MZ)) { // Should be a power of 2 for efficient FFTs - output_warn.write("WARNING: Number of toroidal points should be 2^n for efficient " - "FFT performance -- consider changing MZ if using FFTs\n", + output_warn.write(_("WARNING: Number of toroidal points should be 2^n for efficient " + "FFT performance -- consider changing MZ if using FFTs\n"), MZ); } } else { @@ -308,7 +308,7 @@ int BoutMesh::load() { (MX % i == 0) && // Mesh in X divides equally (ny % (NPES / i) == 0)) { // Mesh in Y divides equally - output_info.write("\tCandidate value: %d\n", i); + output_info.write(_("\tCandidate value: %d\n"), i); int nyp = NPES / i; int ysub = ny / nyp; @@ -373,7 +373,7 @@ int BoutMesh::load() { ny, jyseps2_2, ny - jyseps2_2 - 1, ysub); continue; } - output_info.write("\t -> Good value\n"); + output_info.write(_("\t -> Good value\n")); // Found an acceptable value if ((NXPE < 1) || (fabs(ideal - i) < fabs(ideal - NXPE))) NXPE = i; // Keep value nearest to the ideal diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 70112cfe91..80c9c1834c 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -114,14 +114,14 @@ int Mesh::get(Vector2D &var, const string &name) { TRACE("Loading 2D vector: Mesh::get(Vector2D, %s)", name.c_str()); if(var.covariant) { - output << "\tReading covariant vector " << name << endl; + output << _("\tReading covariant vector ") << name << endl; get(var.x, name+"_x"); get(var.y, name+"_y"); get(var.z, name+"_z"); }else { - output << "\tReading contravariant vector " << name << endl; + output << _("\tReading contravariant vector ") << name << endl; get(var.x, name+"x"); get(var.y, name+"y"); @@ -135,14 +135,14 @@ int Mesh::get(Vector3D &var, const string &name) { TRACE("Loading 3D vector: Mesh::get(Vector3D, %s)", name.c_str()); if(var.covariant) { - output << "\tReading covariant vector " << name << endl; + output << _("\tReading covariant vector ") << name << endl; get(var.x, name+"_x"); get(var.y, name+"_y"); get(var.z, name+"_z"); }else { - output << "\tReading contravariant vector " << name << endl; + output << ("\tReading contravariant vector ") << name << endl; get(var.x, name+"x"); get(var.y, name+"y"); @@ -275,11 +275,11 @@ const vector Mesh::readInts(const string &name, int n) { if(source->hasVar(name)) { if(!source->get(this, result, name, n, 0)) { // Error reading - throw BoutException("Could not read integer array '%s'\n", name.c_str()); + throw BoutException(_("Could not read integer array '%s'\n"), name.c_str()); } }else { // Not found - throw BoutException("Missing integer array %s\n", name.c_str()); + throw BoutException(_("Missing integer array %s\n"), name.c_str()); } return result; @@ -310,8 +310,8 @@ void Mesh::setParallelTransform() { transform = std::unique_ptr(new FCITransform(*this, fci_zperiodic)); }else { - throw BoutException("Unrecognised paralleltransform option.\n" - "Valid choices are 'identity', 'shifted', 'fci'"); + throw BoutException(_("Unrecognised paralleltransform option.\n" + "Valid choices are 'identity', 'shifted', 'fci'")); } } @@ -338,7 +338,7 @@ std::shared_ptr Mesh::createDefaultCoordinates(const CELL_LOC locat const Region<> & Mesh::getRegion3D(const std::string ®ion_name) const { const auto found = regionMap3D.find(region_name); if (found == end(regionMap3D)) { - throw BoutException("Couldn't find region %s in regionMap3D", region_name.c_str()); + throw BoutException(_("Couldn't find region %s in regionMap3D"), region_name.c_str()); } return found->second; } @@ -346,7 +346,7 @@ const Region<> & Mesh::getRegion3D(const std::string ®ion_name) const { const Region & Mesh::getRegion2D(const std::string ®ion_name) const { const auto found = regionMap2D.find(region_name); if (found == end(regionMap2D)) { - throw BoutException("Couldn't find region %s in regionMap2D", region_name.c_str()); + throw BoutException(_("Couldn't find region %s in regionMap2D"), region_name.c_str()); } return found->second; } @@ -354,35 +354,35 @@ const Region & Mesh::getRegion2D(const std::string ®ion_name) const { const Region &Mesh::getRegionPerp(const std::string ®ion_name) const { const auto found = regionMapPerp.find(region_name); if (found == end(regionMapPerp)) { - throw BoutException("Couldn't find region %s in regionMapPerp", region_name.c_str()); + throw BoutException(_("Couldn't find region %s in regionMapPerp"), region_name.c_str()); } return found->second; } void Mesh::addRegion3D(const std::string ®ion_name, const Region<> ®ion) { if (regionMap3D.count(region_name)) { - throw BoutException("Trying to add an already existing region %s to regionMap3D"); + throw BoutException(_("Trying to add an already existing region %s to regionMap3D")); } regionMap3D[region_name] = region; - output_info << "Registered region 3D " << region_name << ": \n"; + output_info << _("Registered region 3D ") << region_name << ": \n"; output_info << "\t" << region.getStats() << "\n"; } void Mesh::addRegion2D(const std::string ®ion_name, const Region ®ion) { if (regionMap2D.count(region_name)) { - throw BoutException("Trying to add an already existing region %s to regionMap2D"); + throw BoutException(_("Trying to add an already existing region %s to regionMap2D")); } regionMap2D[region_name] = region; - output_info << "Registered region 2D " << region_name << ": \n"; + output_info << _("Registered region 2D ") << region_name << ": \n"; output_info << "\t" << region.getStats() << "\n"; } void Mesh::addRegionPerp(const std::string ®ion_name, const Region ®ion) { if (regionMapPerp.count(region_name)) { - throw BoutException("Trying to add an already existing region %s to regionMapPerp"); + throw BoutException(_("Trying to add an already existing region %s to regionMapPerp")); } regionMapPerp[region_name] = region; - output_info << "Registered region Perp " << region_name << ": \n"; + output_info << _("Registered region Perp ") << region_name << ": \n"; output_info << "\t" << region.getStats() << "\n"; } diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index b723d5e21c..9aafd6ba20 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -594,9 +594,9 @@ int Solver::init(int UNUSED(nout), BoutReal UNUSED(tstep)) { TRACE("Solver::init()"); if (initialised) - throw BoutException("ERROR: Solver is already initialised\n"); + throw BoutException(_("ERROR: Solver is already initialised\n")); - output_progress.write("Initialising solver\n"); + output_progress.write(_("Initialising solver\n")); MPI_Comm_size(BoutComm::get(), &NPES); MPI_Comm_rank(BoutComm::get(), &MYPE); @@ -639,14 +639,14 @@ void Solver::addMonitor(Monitor * mon, MonitorPosition pos) { timestep = mon->timestep; } if (!isMultiple(timestep,mon->timestep)) - throw BoutException("Couldn't add Monitor: %g is not a multiple of %g!" + throw BoutException(_("Couldn't add Monitor: %g is not a multiple of %g!") ,timestep,mon->timestep); if (mon->timestep > timestep*1.5){ mon->freq=(mon->timestep/timestep)+.5; } else { // mon.timestep is truly smaller if (initCalled) - throw BoutException("Solver::addMonitor: Cannot reduce timestep \ -(from %g to %g) after init is called!" + throw BoutException(_("Solver::addMonitor: Cannot reduce timestep \ +(from %g to %g) after init is called!") ,timestep,mon->timestep); int multi = timestep/mon->timestep+.5; timestep=mon->timestep; @@ -693,14 +693,14 @@ int Solver::call_monitors(BoutReal simtime, int iter, int NOUT) { // Call each monitor one by one int ret = it->call(this, simtime,iter/it->freq-1, NOUT/it->freq); if(ret) - throw BoutException("Monitor signalled to quit"); + throw BoutException(_("Monitor signalled to quit")); } } } catch (BoutException &e) { for (const auto &it : monitors){ it->cleanup(); } - output_error.write("Monitor signalled to quit\n"); + output_error.write(_("Monitor signalled to quit\n")); throw; } @@ -1017,11 +1017,11 @@ void Solver::load_derivs(BoutReal *udata) { void Solver::save_vars(BoutReal *udata) { for(const auto& f : f2d) if(!f.var->isAllocated()) - throw BoutException("Variable '%s' not initialised", f.name.c_str()); + throw BoutException(_("Variable '%s' not initialised"), f.name.c_str()); for(const auto& f : f3d) if(!f.var->isAllocated()) - throw BoutException("Variable '%s' not initialised", f.name.c_str()); + throw BoutException(_("Variable '%s' not initialised"), f.name.c_str()); // Make sure vectors in correct basis for(const auto& v : v2d) { @@ -1058,7 +1058,7 @@ void Solver::save_derivs(BoutReal *dudata) { // Make sure 3D fields are at the correct cell location for(const auto& f : f3d) { if(f.var->getLocation() != (f.F_var)->getLocation()) { - throw BoutException("Time derivative at wrong location - Field is at %s, derivative is at %s for field '%s'\n",strLocation(f.var->getLocation()), strLocation(f.F_var->getLocation()),f.name.c_str()); + throw BoutException(_("Time derivative at wrong location - Field is at %s, derivative is at %s for field '%s'\n"),strLocation(f.var->getLocation()), strLocation(f.F_var->getLocation()),f.name.c_str()); } } @@ -1264,7 +1264,7 @@ void Solver::post_rhs(BoutReal UNUSED(t)) { #if CHECK > 0 for(const auto& f : f3d) { if(!f.F_var->isAllocated()) - throw BoutException("Time derivative for '%s' not set", f.name.c_str()); + throw BoutException(_("Time derivative for variable '%s' not set"), f.name.c_str()); } #endif // Make sure vectors in correct basis diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 340bf7b5e5..4e710caee1 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -8,7 +8,7 @@ #include /// The source label given to default values -const std::string Options::DEFAULT_SOURCE{"default"}; +const std::string Options::DEFAULT_SOURCE{_("default")}; Options *Options::root_instance{nullptr}; Options &Options::root() { @@ -56,7 +56,7 @@ const Options &Options::operator[](const std::string &name) const { TRACE("Options::operator[] const"); if (!is_section) { - throw BoutException("Option %s is not a section", full_name.c_str()); + throw BoutException(_("Option %s is not a section"), full_name.c_str()); } if (name.empty()) { @@ -67,7 +67,7 @@ const Options &Options::operator[](const std::string &name) const { auto it = children.find(lowercase(name)); if (it == children.end()) { // Doesn't exist - throw BoutException("Option %s:%s does not exist", full_name.c_str(), name.c_str()); + throw BoutException(_("Option %s:%s does not exist"), full_name.c_str(), name.c_str()); } return it->second; @@ -94,12 +94,12 @@ void Options::_set(string val, std::string source, bool force) { if (value.value != val) { if (force or value.source != source) { output_warn << _("\tOption ") << full_name << " = " << value.value << " (" - << value.source << ") overwritten with:" + << value.source << _(") overwritten with:") << "\n" << "\t\t" << full_name << " = " << val << " (" << source << ")\n"; } else { - throw BoutException("Options: Setting a value from same source (%s) to new value " - "'%s' - old value was '%s'.", + throw BoutException(_("Options: Setting a value from same source (%s) to new value " + "'%s' - old value was '%s'."), source.c_str(), val.c_str(), value.value.c_str()); } } @@ -127,7 +127,7 @@ bool Options::isSet() const { template <> std::string Options::as() const { if (!is_value) { - throw BoutException("Option %s has no value", full_name.c_str()); + throw BoutException(_("Option %s has no value"), full_name.c_str()); } // Mark this option as used @@ -145,7 +145,7 @@ template <> std::string Options::as() const { template <> int Options::as() const { if (!is_value) { - throw BoutException("Option %s has no value", full_name.c_str()); + throw BoutException(_("Option %s has no value"), full_name.c_str()); } // Use FieldFactory to evaluate expression @@ -153,7 +153,7 @@ template <> int Options::as() const { // then generate a value at t,x,y,z = 0,0,0,0 auto gen = FieldFactory::get()->parse(value.value, this); if (!gen) { - throw BoutException("Couldn't get integer from %s = '%s'", full_name.c_str(), + throw BoutException(_("Couldn't get integer from option %s = '%s'"), full_name.c_str(), value.value.c_str()); } BoutReal rval = gen->generate(0, 0, 0, 0); @@ -163,7 +163,8 @@ template <> int Options::as() const { // Check that the value is close to an integer if (fabs(rval - static_cast(val)) > 1e-3) { - throw BoutException("Value for %s = %e is not an integer", full_name.c_str(), rval); + throw BoutException(_("Value for option %s = %e is not an integer"), + full_name.c_str(), rval); } value.used = true; @@ -180,7 +181,7 @@ template <> int Options::as() const { template <> BoutReal Options::as() const { if (!is_value) { - throw BoutException("Option %s has no value", full_name.c_str()); + throw BoutException(_("Option %s has no value"), full_name.c_str()); } // Use FieldFactory to evaluate expression @@ -188,7 +189,7 @@ template <> BoutReal Options::as() const { // then generate a value at t,x,y,z = 0,0,0,0 std::shared_ptr gen = FieldFactory::get()->parse(value.value, this); if (!gen) { - throw BoutException("Couldn't get BoutReal from %s = '%s'", full_name.c_str(), + throw BoutException(_("Couldn't get BoutReal from option %s = '%s'"), full_name.c_str(), value.value.c_str()); } BoutReal val = gen->generate(0, 0, 0, 0); @@ -208,7 +209,7 @@ template <> BoutReal Options::as() const { template <> bool Options::as() const { if (!is_value) { - throw BoutException("Option %s has no value", full_name.c_str()); + throw BoutException(_("Option %s has no value"), full_name.c_str()); } value.used = true; @@ -222,7 +223,7 @@ template <> bool Options::as() const { val = false; output_info << _("\tOption ") << full_name << " = false"; } else { - throw BoutException("\tOption '%s': Boolean expected. Got '%s'\n", full_name.c_str(), + throw BoutException(_("\tOption '%s': Boolean expected. Got '%s'\n"), full_name.c_str(), value.value.c_str()); } if (!value.source.empty()) { @@ -244,9 +245,9 @@ void Options::printUnused() const { } } if (allused) { - output_info << "All options used\n"; + output_info << _("All options used\n"); } else { - output_info << "Unused options:\n"; + output_info << _("Unused options:\n"); for (const auto &it : children) { if (it.second.is_value && !it.second.value.used) { output_info << "\t" << full_name << ":" << it.first << " = " diff --git a/src/sys/options/options_ini.cxx b/src/sys/options/options_ini.cxx index 62eaeca90a..e13c66f416 100644 --- a/src/sys/options/options_ini.cxx +++ b/src/sys/options/options_ini.cxx @@ -71,7 +71,7 @@ void OptionINI::read(Options *options, const string &filename) { fin.open(filename.c_str()); if (!fin.good()) { - throw BoutException("\tOptions file '%s' not found\n", filename.c_str()); + throw BoutException(_("\tOptions file '%s' not found\n"), filename.c_str()); } Options *section = options; // Current section @@ -129,7 +129,7 @@ void OptionINI::write(Options *options, const std::string &filename) { fout.open(filename, ios::out | ios::trunc); if (!fout.good()) { - throw BoutException("Could not open output file '%s'\n", filename.c_str()); + throw BoutException(_("Could not open output file '%s'\n"), filename.c_str()); } // Call recursive function to write to file @@ -170,7 +170,7 @@ void OptionINI::parse(const string &buffer, string &key, string &value) key = trim(buffer.substr(0, startpos), " \t\r\n\""); value = trim(buffer.substr(startpos+1), " \t\r\n\""); - if(key.empty()) throw BoutException("\tEmpty key\n\tLine: %s", buffer.c_str()); + if(key.empty()) throw BoutException(_("\tEmpty key\n\tLine: %s"), buffer.c_str()); } void OptionINI::writeSection(const Options *options, std::ofstream &fout) { diff --git a/src/sys/optionsreader.cxx b/src/sys/optionsreader.cxx index a791e5b10f..0d5fc5c2ec 100644 --- a/src/sys/optionsreader.cxx +++ b/src/sys/optionsreader.cxx @@ -57,7 +57,7 @@ void OptionsReader::write(Options *options, const char *file, ...) { bout_vsnprintf(filename,buf_len, file); - output_info << "Writing options to file " << filename << "\n"; + output_info << _("Writing options to file ") << filename << "\n"; // Need to decide what file format to use OptionParser *parser = new OptionINI(); @@ -124,7 +124,7 @@ void OptionsReader::parseCommandLine(Options *options, int argc, char **argv) { } else { size_t endpos = buffer.find_last_of('='); - if(startpos != endpos) throw BoutException("\tMultiple '=' in command-line argument '%s'\n", buffer.c_str()); + if(startpos != endpos) throw BoutException(_("\tMultiple '=' in command-line argument '%s'\n"), buffer.c_str()); string key = trim(buffer.substr(0, startpos)); string value = trim(buffer.substr(startpos+1)); @@ -137,9 +137,9 @@ void OptionsReader::parseCommandLine(Options *options, int argc, char **argv) { options = options->getSection(section); } - if(key.empty() || value.empty()) throw BoutException("\tEmpty key or value in command line '%s'\n", buffer.c_str()); + if(key.empty() || value.empty()) throw BoutException(_("\tEmpty key or value in command line '%s'\n"), buffer.c_str()); - options->set(key, value, "Command line"); + options->set(key, value, _("Command line")); } } } From f54ea347f58bb0f7f50fd22e9f797a6c554f26af Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 27 Oct 2018 17:42:21 +0100 Subject: [PATCH 0141/1783] Add section to the manual Small tweaks to makefiles, instructions in manual. --- locale/libbout.pot | 2 +- locale/makefile | 4 +- locale/zh_TW/libbout.po | 163 +++++++++++++++++++++-- make.config.in | 3 + manual/sphinx/user_docs/running_bout.rst | 34 +++++ src/bout++.cxx | 2 +- 6 files changed, 190 insertions(+), 18 deletions(-) diff --git a/locale/libbout.pot b/locale/libbout.pot index 19bd580d28..b7f5ac2001 100644 --- a/locale/libbout.pot +++ b/locale/libbout.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-27 16:33+0100\n" +"POT-Creation-Date: 2018-10-27 17:37+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/locale/makefile b/locale/makefile index eb9aa71b0b..74e245618f 100644 --- a/locale/makefile +++ b/locale/makefile @@ -32,9 +32,9 @@ libbout.pot: FORCE @msgfmt --output-file=$@ $*/libbout.po # Shortcut target for building single language -# e.g. "make po-fr" +# e.g. "make locale-fr" # Note: invoking make since otherwise the intermediate file is deleted -po-%: +locale-%: $(MAKE) $*/libbout.po mo-%: $(MAKE) $*/LC_MESSAGES/libbout.mo diff --git a/locale/zh_TW/libbout.po b/locale/zh_TW/libbout.po index 80e8d3a3cb..3412591258 100644 --- a/locale/zh_TW/libbout.po +++ b/locale/zh_TW/libbout.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: BOUT++ 4.2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-23 00:03+0100\n" +"POT-Creation-Date: 2018-10-27 16:36+0100\n" "PO-Revision-Date: 2018-10-22 22:56+0100\n" "Last-Translator: \n" "Language-Team: Chinese (traditional)\n" @@ -16,21 +16,83 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/bout++.cxx:365 +#: ../src/mesh/impls/bout/boutmesh.cxx:376 +msgid "\t -> Good value\n" +msgstr "\t -> 好的號碼\n" + +#. Loop over all possibilities +#. Processors divide equally +#. Mesh in X divides equally +#. Mesh in Y divides equally +#: ../src/mesh/impls/bout/boutmesh.cxx:311 +#, c-format +msgid "\tCandidate value: %d\n" +msgstr "\t候選人數目 %d\n" + +#: ../src/bout++.cxx:372 msgid "\tChecking disabled\n" msgstr "\t測試關掉\n" -#: src/bout++.cxx:363 +#: ../src/bout++.cxx:370 #, c-format msgid "\tChecking enabled, level %d\n" msgstr "\t測試打開,级别 %d\n" -#: src/sys/options.cxx:96 src/sys/options.cxx:136 src/sys/options.cxx:171 -#: src/sys/options.cxx:199 src/sys/options.cxx:220 src/sys/options.cxx:223 +#. The stringify is needed here as BOUT_FLAGS_STRING may already contain quoted strings +#. which could cause problems (e.g. terminate strings). +#: ../src/bout++.cxx:413 +#, c-format +msgid "\tCompiled with flags : %s\n" +msgstr "\t用設置編譯: %s\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:390 +#, c-format +msgid "" +"\tDomain split (NXPE=%d, NYPE=%d) into domains (localNx=%d, localNy=%d)\n" +msgstr "\t域 (NXPE=%d, NYPE=%d) 分裂成域 (localNx=%d, localNy=%d)\n" + +#: ../src/sys/optionsreader.cxx:140 +#, c-format +msgid "\tEmpty key or value in command line '%s'\n" +msgstr "\t命令行中的空鍵或值 '%s'\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:127 +msgid "\tGrid size: " +msgstr "\t網格大小: " + +#: ../src/bout++.cxx:400 +msgid "\tOpenMP parallelisation disabled\n" +msgstr "\tOpenMP並行化已禁用\n" + +#: ../src/bout++.cxx:398 +#, c-format +msgid "\tOpenMP parallelisation enabled, using %d threads\n" +msgstr "\t啟用OpenMP並行化。 使用%d個線程\n" + +#. Mark the option as used +#. Option not found +#: ../src/sys/options.cxx:96 ../src/sys/options.cxx:136 +#: ../src/sys/options.cxx:172 ../src/sys/options.cxx:200 +#: ../src/sys/options.cxx:221 ../src/sys/options.cxx:224 +#: ../include/options.hxx:298 ../include/options.hxx:319 msgid "\tOption " msgstr "\t選項 " -#: src/solver/solver.cxx:563 +#: ../src/sys/options.cxx:226 +#, c-format +msgid "\tOption '%s': Boolean expected. Got '%s'\n" +msgstr "\t選項 '%s': 布爾預期. 拿到 '%s'\n" + +#: ../src/sys/options/options_ini.cxx:74 +#, c-format +msgid "\tOptions file '%s' not found\n" +msgstr "\t找不到選項文件 '%s'\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:842 +msgid "\tdone\n" +msgstr "\t完\n" + +#: ../src/solver/solver.cxx:563 #, c-format msgid "" "\n" @@ -39,7 +101,7 @@ msgstr "" "\n" "计算结束于 %s\n" -#: src/solver/solver.cxx:534 +#: ../src/solver/solver.cxx:534 #, c-format msgid "" "\n" @@ -48,7 +110,13 @@ msgstr "" "\n" "计算从 %s 开始\n" -#: src/bout++.cxx:350 +#. / Print intro +#: ../src/bout++.cxx:350 +#, c-format +msgid "BOUT++ version %s\n" +msgstr "BOUT++ 版 %s\n" + +#: ../src/bout++.cxx:357 #, c-format msgid "" "Code compiled on %s at %s\n" @@ -57,34 +125,101 @@ msgstr "" "代碼於 %s %s 编译\n" "\n" -#: src/bout++.cxx:256 +#. / Print compile-time options +#: ../src/bout++.cxx:367 +msgid "Compile-time options:\n" +msgstr "編譯選項:\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:384 +msgid "" +"Could not find a valid value for NXPE. Try a different number of processors." +msgstr "無法找到NXPE的有效值。 嘗試不同數量的處理器。" + +#: ../src/sys/options/options_ini.cxx:132 +#, c-format +msgid "Could not open output file '%s'\n" +msgstr "無法打開輸出文件 '%s'\n" + +#: ../src/bout++.cxx:263 #, c-format msgid "DataDir \"%s\" does not exist or is not accessible\n" msgstr "\"%s\" 不存在或不可訪問\n" -#: src/bout++.cxx:253 +#: ../src/bout++.cxx:260 #, c-format msgid "DataDir \"%s\" is not a directory\n" msgstr "\"%s\" 不是目錄\n" -#: src/bout++.cxx:424 +#: ../src/bout++.cxx:431 msgid "Error encountered during initialisation\n" msgstr "啟動時遇到錯誤\n" -#: src/bout++.cxx:469 +#: ../src/bout++.cxx:476 #, c-format msgid "Error encountered during initialisation: %s\n" msgstr "啟動時遇到錯誤 : %s\n" -#: src/solver/solver.cxx:564 +#: ../src/solver/solver.cxx:599 +msgid "Initialising solver\n" +msgstr "初始化求解器\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:91 +msgid "Loading mesh" +msgstr "加載網格" + +#: ../src/sys/options.cxx:59 +#, fuzzy, c-format +msgid "Option %s is not a section" +msgstr "\"%s\" 不是目錄\n" + +#. Doesn't exist +#: ../src/sys/options.cxx:70 +#, c-format +msgid "Option %s:%s does not exist" +msgstr "選項%s:%s不存在" + +#: ../src/bout++.cxx:352 +#, c-format +msgid "Revision: %s\n" +msgstr "版: %s\n" + +#: ../src/solver/solver.cxx:564 msgid "Run time : " msgstr "計算時間" #. / Run the solver -#: src/solver/solver.cxx:531 +#: ../src/solver/solver.cxx:531 msgid "" "Running simulation\n" "\n" msgstr "" "模擬\n" "\n" + +#: ../src/bout++.cxx:621 +msgid "" +"Sim Time | RHS evals | Wall Time | Calc Inv Comm I/O SOLVER\n" +"\n" +msgstr "" +"模擬時間 | 評估數量 | 時鐘時間 | 計算 逆溫 通訊 輸入輸出 時間整合\n" +"\n" + +#: ../src/bout++.cxx:624 +msgid "" +"Sim Time | RHS_e evals | RHS_I evals | Wall Time | Calc Inv " +"Comm I/O SOLVER\n" +"\n" +msgstr "" +"模擬時間 | 評估數量(e) | 評估數量(I) | 時鐘時間 | 計算 逆溫 " +"通訊 輸入輸出 時間整合\n" +"\n" + +#: ../src/sys/optionsreader.cxx:60 +msgid "Writing options to file " +msgstr "寫選項到文件 " + +#. / The source label given to default values +#: ../src/sys/options.cxx:11 +msgid "default" +msgstr "默认设置" + diff --git a/make.config.in b/make.config.in index dff8866683..4a82e0caa6 100644 --- a/make.config.in +++ b/make.config.in @@ -173,6 +173,9 @@ install: libfast $(INSTALL_DATA) tools/pylib/boutdata/*.py $(DESTDIR)@datadir@/bout++/pylib/boutdata/ $(INSTALL_DATA) tools/pylib/boututils/*.py $(DESTDIR)@datadir@/bout++/pylib/boututils/ $(INSTALL_DATA) make.config $(DESTDIR)@datadir@/bout++/ + $(INSTALL_DATA) locale/fr/LC_MESSAGES/libbout.mo $(DESTDIR)@localedir@/fr/LC_MESSAGES/ + $(INSTALL_DATA) locale/zh_TW/LC_MESSAGES/libbout.mo $(DESTDIR)@localedir@/zh_TW/LC_MESSAGES/ + $(INSTALL_DATA) locale/zh_CN/LC_MESSAGES/libbout.mo $(DESTDIR)@localedir@/zh_CN/LC_MESSAGES/ $(POST_INSTALL) # Post-install commands follow. diff --git a/manual/sphinx/user_docs/running_bout.rst b/manual/sphinx/user_docs/running_bout.rst index 280966e6a5..84aee5d5cb 100644 --- a/manual/sphinx/user_docs/running_bout.rst +++ b/manual/sphinx/user_docs/running_bout.rst @@ -210,6 +210,40 @@ and to make this a coloured contour plot The equivalent commands in Python are as follows. + +Natural language support +------------------------ + +BOUT++ has support for languages other than English, using GNU +gettext. If you have locales installed, then the ``LANG`` environment +variable selects the language to use. Currently only limited support +for ``fr``, ``zh_TW`` and ``zh_CN`` e.g. :: + + LANG=zh_TW.utf8 ./conduction + +Adding support for a new language, or improving the translations in +the existing files can be done by: + +1. Going to the ``locale`` BOUT++ subdirectory and running:: + + make locale-ll + + where ``ll`` is the language code e.g. ``make locale-de``. This + will create a file ``libbout.po`` under a ``locale/ll`` + subdirectory. +2. Edit the ``locale/ll/libbout.po`` file. Each ``msgid`` entry should + have a translated ``msgstr`` entry: Either translate each entry or + delete the entries you don't translate. +3. In the ``locale`` directory run ``make``. This should output + something like:: + + Building language: fr + Building language: zh_CN + Building language: zh_TW + +The new language should now be available (no need to recompile BOUT++). + + Further examples ---------------- diff --git a/src/bout++.cxx b/src/bout++.cxx index 48c8e0c7e7..fce954103c 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -155,7 +155,7 @@ int BoutInitialise(int &argc, char **&argv) { bindtextdomain ("libbout", CMDLINE(BOUT_LOCALE_PATH)); textdomain ("libbout"); - fprintf(stderr, "LOCALE_PATH = '%s'", CMDLINE(BOUT_LOCALE_PATH)); + fprintf(stderr, "LOCALE_PATH = '%s'\n", CMDLINE(BOUT_LOCALE_PATH)); } catch (const std::runtime_error &e) { fprintf(stderr, "WARNING: Could not set locale. Try a different LANG setting\n"); } From 56f6212b6f3666bb9c9a612abb2c3ded7ccd6033 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 27 Oct 2018 17:51:21 +0100 Subject: [PATCH 0142/1783] Replace spaces -> tabs in makefile --- make.config.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/make.config.in b/make.config.in index 4a82e0caa6..12625ed512 100644 --- a/make.config.in +++ b/make.config.in @@ -173,9 +173,9 @@ install: libfast $(INSTALL_DATA) tools/pylib/boutdata/*.py $(DESTDIR)@datadir@/bout++/pylib/boutdata/ $(INSTALL_DATA) tools/pylib/boututils/*.py $(DESTDIR)@datadir@/bout++/pylib/boututils/ $(INSTALL_DATA) make.config $(DESTDIR)@datadir@/bout++/ - $(INSTALL_DATA) locale/fr/LC_MESSAGES/libbout.mo $(DESTDIR)@localedir@/fr/LC_MESSAGES/ - $(INSTALL_DATA) locale/zh_TW/LC_MESSAGES/libbout.mo $(DESTDIR)@localedir@/zh_TW/LC_MESSAGES/ - $(INSTALL_DATA) locale/zh_CN/LC_MESSAGES/libbout.mo $(DESTDIR)@localedir@/zh_CN/LC_MESSAGES/ + $(INSTALL_DATA) locale/fr/LC_MESSAGES/libbout.mo $(DESTDIR)@localedir@/fr/LC_MESSAGES/ + $(INSTALL_DATA) locale/zh_TW/LC_MESSAGES/libbout.mo $(DESTDIR)@localedir@/zh_TW/LC_MESSAGES/ + $(INSTALL_DATA) locale/zh_CN/LC_MESSAGES/libbout.mo $(DESTDIR)@localedir@/zh_CN/LC_MESSAGES/ $(POST_INSTALL) # Post-install commands follow. From 74db4786d2403c3a7c9d5ba4c430756ab465e65e Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 27 Oct 2018 18:39:28 +0100 Subject: [PATCH 0143/1783] Add missing strings Somehow removed arguments to BoutException Caught by unit tests! --- src/mesh/mesh.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 80c9c1834c..d629684a03 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -361,7 +361,7 @@ const Region &Mesh::getRegionPerp(const std::string ®ion_name) const void Mesh::addRegion3D(const std::string ®ion_name, const Region<> ®ion) { if (regionMap3D.count(region_name)) { - throw BoutException(_("Trying to add an already existing region %s to regionMap3D")); + throw BoutException(_("Trying to add an already existing region %s to regionMap3D"), region_name.c_str()); } regionMap3D[region_name] = region; output_info << _("Registered region 3D ") << region_name << ": \n"; @@ -370,7 +370,7 @@ void Mesh::addRegion3D(const std::string ®ion_name, const Region<> ®ion) { void Mesh::addRegion2D(const std::string ®ion_name, const Region ®ion) { if (regionMap2D.count(region_name)) { - throw BoutException(_("Trying to add an already existing region %s to regionMap2D")); + throw BoutException(_("Trying to add an already existing region %s to regionMap2D"), region_name.c_str()); } regionMap2D[region_name] = region; output_info << _("Registered region 2D ") << region_name << ": \n"; @@ -379,7 +379,7 @@ void Mesh::addRegion2D(const std::string ®ion_name, const Region ®i void Mesh::addRegionPerp(const std::string ®ion_name, const Region ®ion) { if (regionMapPerp.count(region_name)) { - throw BoutException(_("Trying to add an already existing region %s to regionMapPerp")); + throw BoutException(_("Trying to add an already existing region %s to regionMapPerp"), region_name.c_str()); } regionMapPerp[region_name] = region; output_info << _("Registered region Perp ") << region_name << ": \n"; From b74867f0f61a4cf47eb9f3152d911ea8a6ed7a39 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 27 Oct 2018 22:51:56 +0100 Subject: [PATCH 0144/1783] Fixing string, removing test Test was used for trying out gettext, not portable. Closing bracket in the wrong place when OpenMP enabled. --- locale/fr/LC_MESSAGES/test.mo | Bin 462 -> 0 bytes locale/fr/LC_MESSAGES/test.po | 24 ----------------------- manual/sphinx/user_docs/running_bout.rst | 5 ++--- src/bout++.cxx | 2 +- tests/integrated/test-i18n/data/BOUT.inp | 8 -------- tests/integrated/test-i18n/makefile | 5 ----- tests/integrated/test-i18n/test-i18n.cxx | 19 ------------------ 7 files changed, 3 insertions(+), 60 deletions(-) delete mode 100644 locale/fr/LC_MESSAGES/test.mo delete mode 100644 locale/fr/LC_MESSAGES/test.po delete mode 100644 tests/integrated/test-i18n/data/BOUT.inp delete mode 100644 tests/integrated/test-i18n/makefile delete mode 100644 tests/integrated/test-i18n/test-i18n.cxx diff --git a/locale/fr/LC_MESSAGES/test.mo b/locale/fr/LC_MESSAGES/test.mo deleted file mode 100644 index 45ba3e9d6fda2d315171baa90c4319c7d26b3a64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 462 zcmZvX&rSj{5XM)dm&S{pJ%4CoO5intY7I7^W4Cj zv3Vkbo;4GUy=*7)6|Kt*De&mL%pj_e=;Pd2FS{5K z*BMnI9&78+*Kc2%?e^BU9A|`9K2U6uj8X-aVdh0IFRadG%h;JyK=akr)yq{_r}Yzp W21KV-5!@M?n8HGiFf){(2>t;1`F?2t diff --git a/locale/fr/LC_MESSAGES/test.po b/locale/fr/LC_MESSAGES/test.po deleted file mode 100644 index 66e41e224b..0000000000 --- a/locale/fr/LC_MESSAGES/test.po +++ /dev/null @@ -1,24 +0,0 @@ -# French translations for test-i package. -# Copyright (C) 2018 THE test-i'S COPYRIGHT HOLDER -# This file is distributed under the same license as the test-i package. -# , 2018. -# -msgid "" -msgstr "" -"Project-Id-Version: test-i 18n\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-10-20 21:34+0100\n" -"PO-Revision-Date: 2018-10-20 21:36+0100\n" -"Last-Translator: \n" -"Language-Team: French\n" -"Language: fr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=ASCII\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#: test-i18n.cxx:13 -#, c-format -msgid "Hello World\n" -msgstr "Bonjour le monde\n" - diff --git a/manual/sphinx/user_docs/running_bout.rst b/manual/sphinx/user_docs/running_bout.rst index 84aee5d5cb..ff1323577a 100644 --- a/manual/sphinx/user_docs/running_bout.rst +++ b/manual/sphinx/user_docs/running_bout.rst @@ -216,8 +216,8 @@ Natural language support BOUT++ has support for languages other than English, using GNU gettext. If you have locales installed, then the ``LANG`` environment -variable selects the language to use. Currently only limited support -for ``fr``, ``zh_TW`` and ``zh_CN`` e.g. :: +variable selects the language to use. Currently BOUT++ only has limited support +for ``fr``, ``zh_TW`` and ``zh_CN`` locales e.g. :: LANG=zh_TW.utf8 ./conduction @@ -243,7 +243,6 @@ the existing files can be done by: The new language should now be available (no need to recompile BOUT++). - Further examples ---------------- diff --git a/src/bout++.cxx b/src/bout++.cxx index fce954103c..d62e7ef148 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -395,7 +395,7 @@ int BoutInitialise(int &argc, char **&argv) { #endif #ifdef _OPENMP - output_info.write(_("\tOpenMP parallelisation enabled, using %d threads\n",omp_get_max_threads())); + output_info.write(_("\tOpenMP parallelisation enabled, using %d threads\n"),omp_get_max_threads()); #else output_info.write(_("\tOpenMP parallelisation disabled\n")); #endif diff --git a/tests/integrated/test-i18n/data/BOUT.inp b/tests/integrated/test-i18n/data/BOUT.inp deleted file mode 100644 index 4882c631fe..0000000000 --- a/tests/integrated/test-i18n/data/BOUT.inp +++ /dev/null @@ -1,8 +0,0 @@ - -mxg = 0 -myg = 0 -[mesh] - -nx = 1 -ny = 1 -nz = 1 diff --git a/tests/integrated/test-i18n/makefile b/tests/integrated/test-i18n/makefile deleted file mode 100644 index 96868cf602..0000000000 --- a/tests/integrated/test-i18n/makefile +++ /dev/null @@ -1,5 +0,0 @@ -BOUT_TOP = ../../.. - -SOURCEC = test-i18n.cxx - -include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-i18n/test-i18n.cxx b/tests/integrated/test-i18n/test-i18n.cxx deleted file mode 100644 index f92866eece..0000000000 --- a/tests/integrated/test-i18n/test-i18n.cxx +++ /dev/null @@ -1,19 +0,0 @@ - -#include "bout.hxx" -#include "bout/sys/gettext.hxx" - -int main(int argc, char**argv) { - // Setting the i18n environment - if (setlocale (LC_ALL, "") == NULL) { - throw BoutException("Failed to set locale"); - } - bindtextdomain ("test", "/home/bd512/BOUT-dev/locale/"); - textdomain ("test"); - - BoutInitialise(argc, argv); - - output.write(_("Hello World\n")); - - BoutFinalise(); - return 0; -} From 497fc6ec429282ad95271822d51c4beb8fd3ae93 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 27 Oct 2018 22:56:12 +0100 Subject: [PATCH 0145/1783] More manual Copying some text from the PR description into the manual Not really sure where the manual entry for this belongs. --- manual/sphinx/user_docs/running_bout.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/manual/sphinx/user_docs/running_bout.rst b/manual/sphinx/user_docs/running_bout.rst index ff1323577a..8f201279d6 100644 --- a/manual/sphinx/user_docs/running_bout.rst +++ b/manual/sphinx/user_docs/running_bout.rst @@ -231,9 +231,13 @@ the existing files can be done by: where ``ll`` is the language code e.g. ``make locale-de``. This will create a file ``libbout.po`` under a ``locale/ll`` subdirectory. -2. Edit the ``locale/ll/libbout.po`` file. Each ``msgid`` entry should - have a translated ``msgstr`` entry: Either translate each entry or - delete the entries you don't translate. +2. Edit the ``locale/ll/libbout.po`` file. Edit the .po file in de + subdirectory (not the .pot file!), adding the translations. Each + ``msgid`` entry should have a translated ``msgstr`` entry. If you + don't want to translate them all, just delete the ones you don't + translate. Any missing will just revert to the version in the + code. If you're adding UTF-8 characters, change the content line in + the .po file to have charset=UTF-8. 3. In the ``locale`` directory run ``make``. This should output something like:: From 24981479eaef3400375ed9f25a7226562097d4df Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 27 Oct 2018 23:22:19 +0100 Subject: [PATCH 0146/1783] Changing README example to use cross rather than ^ Deprecated method for cross products now removed, but used in example on front page README. Now changed. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8d4271d5ea..2454dce8e9 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,8 @@ can be written simply as: ```cpp ddt(rho) = -V_dot_Grad(v, rho) - rho*Div(v); ddt(p) = -V_dot_Grad(v, p) - g*p*Div(v); -ddt(v) = -V_dot_Grad(v, v) + ((Curl(B)^B) - Grad(p))/rho; -ddt(B) = Curl(v^B); +ddt(v) = -V_dot_Grad(v, v) + (cross(Curl(B),B) - Grad(p))/rho; +ddt(B) = Curl(cross(v,B)); ``` The full code for this example can be found in the [orszag-tang From 8575feae41238c864d78159a0aa59734ded33513 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 27 Oct 2018 23:38:42 +0100 Subject: [PATCH 0147/1783] Manual small fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added π to list of symbols defined in expressions - Remove `_` from section references --- manual/sphinx/user_docs/bout_options.rst | 4 ++-- manual/sphinx/user_docs/variable_init.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index 664ab865af..e904db1371 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -77,8 +77,8 @@ are first read, and then processed afterwards. The value ``pi`` is already defined, as is ``π``, and can be used in expressions. Uses for expressions include initialising variables -:ref:`_sec-expressions` and input sources, defining grids -:ref:`_sec-gridgen` and MMS convergence tests :ref:`_sec-mms`. +:ref:`sec-expressions` and input sources, defining grids +:ref:`sec-gridgen` and MMS convergence tests :ref:`sec-mms`. Expressions can include addition (``+``), subtraction (``-``), multiplication (``*``), division (``/``) and exponentiation (``^``) diff --git a/manual/sphinx/user_docs/variable_init.rst b/manual/sphinx/user_docs/variable_init.rst index 3c03660bd1..0553fab60c 100644 --- a/manual/sphinx/user_docs/variable_init.rst +++ b/manual/sphinx/user_docs/variable_init.rst @@ -87,7 +87,7 @@ following values are also already defined: +--------+------------------------------------------------------------------------------------+ | z | :math:`z` position between :math:`0` and :math:`2\pi` (excluding the last point) | +--------+------------------------------------------------------------------------------------+ -| pi | :math:`3.1415\ldots` | +| pi π | :math:`3.1415\ldots` | +--------+------------------------------------------------------------------------------------+ Table: Initialisation expression values From 3cc7bf7daac4a6462910a356045b59d8c925ab27 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Oct 2018 11:04:19 +0000 Subject: [PATCH 0148/1783] Fix up/down fields in FV::Div_par_K_Grad_par Previously, fup/fdown and Kup/Kdown fields were defined but not used. The inputs fin and Kin were copied to f and K before checking hasYupYdown(), but since yup_field and ydown_field are not copied in the Field3D assignment operator, the yup/ydown branch could never be used. --- src/mesh/fv_ops.cxx | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index 75d3debaf5..6c509d637f 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -125,15 +125,18 @@ namespace FV { // K and f fields in yup and ydown directions Field3D Kup(mesh), Kdown(mesh); Field3D fup(mesh), fdown(mesh); - Field3D f = fin; - Field3D K = Kin; - if (K.hasYupYdown() && f.hasYupYdown()) { + Field3D f(mesh); + Field3D K(mesh); + if (Kin.hasYupYdown() && fin.hasYupYdown()) { // Both inputs have yup and ydown - Kup = K.yup(); - Kdown = K.ydown(); + f = fin; + K = Kin; + + Kup = Kin.yup(); + Kdown = Kin.ydown(); - fup = f.yup(); - fdown = f.ydown(); + fup = fin.yup(); + fdown = fin.ydown(); } else { // At least one input doesn't have yup/ydown fields. // Need to shift to/from field aligned coordinates @@ -155,11 +158,11 @@ namespace FV { if (bndry_flux || !mesh->lastY() || (i.y() != mesh->yend)) { - BoutReal c = 0.5*(K[i] + K.yup()[iyp]); // K at the upper boundary + BoutReal c = 0.5*(K[i] + Kup[iyp]); // K at the upper boundary BoutReal J = 0.5*(coord->J[i] + coord->J[iyp]); // Jacobian at boundary BoutReal g_22 = 0.5*(coord->g_22[i] + coord->g_22[iyp]); - BoutReal gradient = 2.*(f.yup()[iyp] - f[i]) / (coord->dy[i] + coord->dy[iyp]); + BoutReal gradient = 2.*(fup[iyp] - f[i]) / (coord->dy[i] + coord->dy[iyp]); BoutReal flux = c * J * gradient / g_22; @@ -168,12 +171,12 @@ namespace FV { // Calculate flux at lower surface if (bndry_flux || !mesh->firstY() || (i.y() != mesh->ystart)) { - BoutReal c = 0.5*(K[i] + K.ydown()[iym]); // K at the lower boundary + BoutReal c = 0.5*(K[i] + Kdown[iym]); // K at the lower boundary BoutReal J = 0.5*(coord->J[i] + coord->J[iym]); // Jacobian at boundary BoutReal g_22 = 0.5*(coord->g_22[i] + coord->g_22[i]); - BoutReal gradient = 2.*(f[i] - f.ydown()[iym]) / (coord->dy[i] + coord->dy[iym]); + BoutReal gradient = 2.*(f[i] - fdown[iym]) / (coord->dy[i] + coord->dy[iym]); BoutReal flux = c * J * gradient / g_22; @@ -181,7 +184,7 @@ namespace FV { } } - if (!(K.hasYupYdown() && f.hasYupYdown())) { + if (!(Kin.hasYupYdown() && fin.hasYupYdown())) { // Shifted to field aligned coordinates, so need to shift back result = mesh->fromFieldAligned(result); } From 53e239b0f5e5e1e9685931bcc2b074ebb14750e9 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Oct 2018 11:18:23 +0000 Subject: [PATCH 0149/1783] Use Field3D& references to avoid making copies in FV::Div_par_K_Grad_par --- src/mesh/fv_ops.cxx | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index 6c509d637f..c01f7f67ad 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -122,31 +122,16 @@ namespace FV { Mesh *mesh = Kin.getMesh(); Field3D result(0.0, mesh); + bool use_yup_ydown = (Kin.hasYupYdown() && fin.hasYupYdown()); + + const Field3D& K = use_yup_ydown ? Kin : mesh->toFieldAligned(Kin); + const Field3D& f = use_yup_ydown ? fin : mesh->toFieldAligned(fin); + // K and f fields in yup and ydown directions - Field3D Kup(mesh), Kdown(mesh); - Field3D fup(mesh), fdown(mesh); - Field3D f(mesh); - Field3D K(mesh); - if (Kin.hasYupYdown() && fin.hasYupYdown()) { - // Both inputs have yup and ydown - f = fin; - K = Kin; - - Kup = Kin.yup(); - Kdown = Kin.ydown(); - - fup = fin.yup(); - fdown = fin.ydown(); - } else { - // At least one input doesn't have yup/ydown fields. - // Need to shift to/from field aligned coordinates - - f = mesh->toFieldAligned(fin); - K = mesh->toFieldAligned(Kin); - - fup = fdown = f; - Kup = Kdown = K; - } + const Field3D& Kup = use_yup_ydown ? Kin.yup() : K; + const Field3D& Kdown = use_yup_ydown ? Kin.ydown() : K; + const Field3D& fup = use_yup_ydown ? fin.yup() : f; + const Field3D& fdown = use_yup_ydown ? fin.ydown() : f; Coordinates *coord = fin.getCoordinates(); From 192ec95e3d03a07754cb96cc9e6a5686a997af9f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 29 Oct 2018 13:46:19 +0000 Subject: [PATCH 0150/1783] Reorder existing formatting options --- .clang-format | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/.clang-format b/.clang-format index 1b61b16ed4..9bae58aef0 100644 --- a/.clang-format +++ b/.clang-format @@ -1,57 +1,60 @@ --- Language: Cpp -BasedOnStyle: LLVM +# BasedOnStyle: LLVM AccessModifierOffset: -2 -ConstructorInitializerIndentWidth: 4 AlignEscapedNewlinesLeft: false AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: All AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false -AllowShortFunctionsOnASingleLine: All -AlwaysBreakTemplateDeclarations: false AlwaysBreakBeforeMultilineStrings: false -BreakBeforeBinaryOperators: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false -BinPackParameters: true ColumnLimit: 90 +CommentPragmas: '^ IWYU pragma:' ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true DerivePointerAlignment: false +DisableFormat: false ExperimentalAutoDetectBinPacking: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH IndentCaseLabels: false +IndentWidth: 2 IndentWrappedFunctionNames: false IndentFunctionDeclarationAfterType: false -MaxEmptyLinesToKeep: 1 KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakComment: 300 -PenaltyBreakString: 1000 PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Right +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 -Cpp11BracedListStyle: true +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false Standard: Cpp11 -IndentWidth: 2 TabWidth: 8 UseTab: Never -BreakBeforeBraces: Attach -SpacesInParentheses: false -SpacesInAngles: false -SpaceInEmptyParentheses: false -SpacesInCStyleCastParentheses: false -SpacesInContainerLiterals: true -SpaceBeforeAssignmentOperators: true -ContinuationIndentWidth: 4 -CommentPragmas: '^ IWYU pragma:' -ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] -SpaceBeforeParens: ControlStatements -DisableFormat: false ... From 29074a76c1a876b19f97bf9f91c4baeb77ab6a27 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 29 Oct 2018 13:50:09 +0000 Subject: [PATCH 0151/1783] Rename old clang-format option --- .clang-format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index 9bae58aef0..f651e61c69 100644 --- a/.clang-format +++ b/.clang-format @@ -2,7 +2,7 @@ Language: Cpp # BasedOnStyle: LLVM AccessModifierOffset: -2 -AlignEscapedNewlinesLeft: false +AlignEscapedNewlines: Right AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false From 672ebe030d802fe7232d6884d124a2cb4e0b7620 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Oct 2018 14:07:36 +0000 Subject: [PATCH 0152/1783] Use 'const auto&' instead of 'const Field3D&' --- src/mesh/fv_ops.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index c01f7f67ad..e1e4fe3437 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -124,14 +124,14 @@ namespace FV { bool use_yup_ydown = (Kin.hasYupYdown() && fin.hasYupYdown()); - const Field3D& K = use_yup_ydown ? Kin : mesh->toFieldAligned(Kin); - const Field3D& f = use_yup_ydown ? fin : mesh->toFieldAligned(fin); + const auto& K = use_yup_ydown ? Kin : mesh->toFieldAligned(Kin); + const auto& f = use_yup_ydown ? fin : mesh->toFieldAligned(fin); // K and f fields in yup and ydown directions - const Field3D& Kup = use_yup_ydown ? Kin.yup() : K; - const Field3D& Kdown = use_yup_ydown ? Kin.ydown() : K; - const Field3D& fup = use_yup_ydown ? fin.yup() : f; - const Field3D& fdown = use_yup_ydown ? fin.ydown() : f; + const auto& Kup = use_yup_ydown ? Kin.yup() : K; + const auto& Kdown = use_yup_ydown ? Kin.ydown() : K; + const auto& fup = use_yup_ydown ? fin.yup() : f; + const auto& fdown = use_yup_ydown ? fin.ydown() : f; Coordinates *coord = fin.getCoordinates(); From b5baeafe7c6bda5a60c9fd01baa3bb80112e2124 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 29 Oct 2018 14:12:28 +0000 Subject: [PATCH 0153/1783] Add some new clang-format options --- .clang-format | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/.clang-format b/.clang-format index f651e61c69..50b1915f0e 100644 --- a/.clang-format +++ b/.clang-format @@ -2,22 +2,51 @@ Language: Cpp # BasedOnStyle: LLVM AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false AlignEscapedNewlines: Right +AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: All AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: false BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true BreakBeforeBinaryOperators: None BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true ColumnLimit: 90 CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 @@ -25,19 +54,24 @@ Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false -ForEachMacros: +FixNamespaceComments: true +ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH +IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false +IndentPPDirectives: None IndentWidth: 2 IndentWrappedFunctionNames: false -IndentFunctionDeclarationAfterType: false KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 @@ -45,6 +79,11 @@ PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Right +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false @@ -53,8 +92,8 @@ SpacesInAngles: false SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false +SpacesInSquareBrackets: false Standard: Cpp11 TabWidth: 8 UseTab: Never ... - From d57d2601c186a39e38a3919f5c6369536e54b7ec Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 29 Oct 2018 14:12:37 +0000 Subject: [PATCH 0154/1783] Add clang-format option for how to sort includes Tries to put `#include "bout/.*"` into separate group than `include `. Will be nicer when all headers are under `bout/` namespace --- .clang-format | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.clang-format b/.clang-format index 50b1915f0e..e1cadb46ec 100644 --- a/.clang-format +++ b/.clang-format @@ -59,6 +59,16 @@ ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^(<|")bout/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '^<.*>' + Priority: 4 + - Regex: '.*' + Priority: 1 IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false IndentPPDirectives: None From 5cf9fae52fd00afccc47a83ca662a048eab2bd38 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 29 Oct 2018 14:15:25 +0000 Subject: [PATCH 0155/1783] Change clang-format to always break after template declaration Do this: template class C {}; --- .clang-format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index e1cadb46ec..30d2e8b0b7 100644 --- a/.clang-format +++ b/.clang-format @@ -17,7 +17,7 @@ AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: false +AlwaysBreakTemplateDeclarations: true BinPackArguments: true BinPackParameters: true BraceWrapping: From 581f8f0f6061fce3485930f6e08f0e804791404f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 29 Oct 2018 14:16:16 +0000 Subject: [PATCH 0156/1783] Change clang-format to put the pointer on the type Do this: T* foo(); T& bar = func(); --- .clang-format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index 30d2e8b0b7..9d9af2c922 100644 --- a/.clang-format +++ b/.clang-format @@ -88,7 +88,7 @@ PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 60 -PointerAlignment: Right +PointerAlignment: Left ReflowComments: true SortIncludes: true SortUsingDeclarations: true From 6ed9937695c77f4f1b5d21764acf2186a275682c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 29 Oct 2018 14:20:48 +0000 Subject: [PATCH 0157/1783] Change clang-format to break before binary operators Put the operator at the start of the next line (and indent appropriately) --- .clang-format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index 9d9af2c922..af60f0e15b 100644 --- a/.clang-format +++ b/.clang-format @@ -36,7 +36,7 @@ BraceWrapping: SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true -BreakBeforeBinaryOperators: None +BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Attach BreakBeforeInheritanceComma: false BreakBeforeTernaryOperators: true From 0256ef5e1f192049479cd344035f377279639b3c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 29 Oct 2018 16:40:33 +0000 Subject: [PATCH 0158/1783] Add swap(Field3D, Field3D) and test --- include/field3d.hxx | 20 ++++++++ tests/unit/field/test_field3d.cxx | 76 +++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/include/field3d.hxx b/include/field3d.hxx index e9f090bea6..107092b4d9 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -443,6 +443,26 @@ class Field3D : public Field, public FieldData { void applyParallelBoundary(const char* condition) { applyParallelBoundary(string(condition)); } void applyParallelBoundary(const string ®ion, const string &condition); void applyParallelBoundary(const string ®ion, const string &condition, Field3D *f); + + friend void swap(Field3D& first, Field3D& second) noexcept { + using std::swap; + swap(first.data, second.data); + swap(first.fieldmesh, second.fieldmesh); + swap(first.fieldCoordinates, second.fieldCoordinates); + swap(first.background, second.background); + swap(first.nx, second.nx); + swap(first.ny, second.ny); + swap(first.nz, second.nz); + swap(first.location, second.location); + swap(first.deriv, second.deriv); + swap(first.yup_field, second.yup_field); + swap(first.ydown_field, second.ydown_field); + swap(first.bndry_op, second.bndry_op); + swap(first.boundaryIsCopy, second.boundaryIsCopy); + swap(first.boundaryIsSet, second.boundaryIsSet); + swap(first.bndry_op_par, second.bndry_op_par); + swap(first.bndry_generator, second.bndry_generator); + } private: /// Boundary - add a 2D field diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 649a3abb1b..933e99e4b3 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -1950,5 +1950,81 @@ TEST_F(Field3DTest, OpenMPIterator) { } #endif +TEST_F(Field3DTest, Swap) { + auto backup = mesh->StaggerGrids; + mesh->StaggerGrids = true; + + // First field + Field3D first(1., mesh); + + first.setLocation(CELL_XLOW); + + first.splitYupYdown(); + first.yup() = 1.5; + first.ydown() = 0.5; + + ddt(first) = 1.1; + + // Mesh for second field + constexpr int second_nx = Field3DTest::nx + 2; + constexpr int second_ny = Field3DTest::ny + 2; + constexpr int second_nz = Field3DTest::nz + 2; + + FakeMesh second_mesh{second_nx, second_ny, second_nz}; + second_mesh.StaggerGrids = false; + output_info.disable(); + second_mesh.createDefaultRegions(); + output_info.enable(); + + // Second field + Field3D second(2., &second_mesh); + + second.splitYupYdown(); + second.yup() = 2.2; + second.ydown() = 1.2; + + ddt(second) = 2.4; + + // Basic sanity check + EXPECT_TRUE(IsField3DEqualBoutReal(first, 1.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(second, 2.0)); + + // swap is marked noexcept, so absolutely should not throw! + ASSERT_NO_THROW(swap(first, second)); + + // Values + EXPECT_TRUE(IsField3DEqualBoutReal(first, 2.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(second, 1.0)); + + EXPECT_TRUE(IsField3DEqualBoutReal(first.yup(), 2.2)); + EXPECT_TRUE(IsField3DEqualBoutReal(first.ydown(), 1.2)); + + EXPECT_TRUE(IsField3DEqualBoutReal(second.yup(), 1.5)); + EXPECT_TRUE(IsField3DEqualBoutReal(second.ydown(), 0.5)); + + EXPECT_TRUE(IsField3DEqualBoutReal(ddt(first), 2.4)); + EXPECT_TRUE(IsField3DEqualBoutReal(ddt(second), 1.1)); + + // Mesh properties + EXPECT_EQ(first.getMesh(), &second_mesh); + EXPECT_EQ(second.getMesh(), mesh); + + EXPECT_EQ(first.getNx(), second_nx); + EXPECT_EQ(first.getNy(), second_ny); + EXPECT_EQ(first.getNz(), second_nz); + + EXPECT_EQ(second.getNx(), Field3DTest::nx); + EXPECT_EQ(second.getNy(), Field3DTest::ny); + EXPECT_EQ(second.getNz(), Field3DTest::nz); + + EXPECT_EQ(first.getLocation(), CELL_CENTRE); + EXPECT_EQ(second.getLocation(), CELL_XLOW); + + // We don't check the boundaries, but the data is protected and + // there are no inquiry functions + + mesh->StaggerGrids = backup; +} + // Restore compiler warnings #pragma GCC diagnostic pop From e811a3771a20c49f9d255d3902eb9db56951a524 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 29 Oct 2018 17:21:15 +0000 Subject: [PATCH 0159/1783] Reuse the test fixture for creating/destroying FakeMesh Note this also makes the tests more independent by constructing/destructing the mesh on every test --- tests/unit/field/test_field2d.cxx | 31 ++--------------------- tests/unit/field/test_field3d.cxx | 31 ++--------------------- tests/unit/field/test_fieldperp.cxx | 30 +--------------------- tests/unit/include/bout/test_region.cxx | 33 +++---------------------- tests/unit/test_extras.cxx | 5 ++++ tests/unit/test_extras.hxx | 27 ++++++++++++++++++++ 6 files changed, 40 insertions(+), 117 deletions(-) diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index 1a87816f21..e4472da225 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -20,35 +20,8 @@ /// Global mesh extern Mesh *mesh; -/// Test fixture to make sure the global mesh is our fake one -class Field2DTest : public ::testing::Test { -protected: - static void SetUpTestCase() { - // Delete any existing mesh - if (mesh != nullptr) { - delete mesh; - mesh = nullptr; - } - mesh = new FakeMesh(nx, ny, nz); - output_info.disable(); - mesh->createDefaultRegions(); - output_info.enable(); - } - - static void TearDownTestCase() { - delete mesh; - mesh = nullptr; - } - -public: - static const int nx; - static const int ny; - static const int nz; -}; - -const int Field2DTest::nx = 3; -const int Field2DTest::ny = 5; -const int Field2DTest::nz = 7; +// Reuse the "standard" fixture for FakeMesh +using Field2DTest = FakeMeshFixture; TEST_F(Field2DTest, IsReal) { Field2D field; diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 649a3abb1b..a3518625ba 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -20,35 +20,8 @@ /// Global mesh extern Mesh *mesh; -/// Test fixture to make sure the global mesh is our fake one -class Field3DTest : public ::testing::Test { -protected: - static void SetUpTestCase() { - // Delete any existing mesh - if (mesh != nullptr) { - delete mesh; - mesh = nullptr; - } - mesh = new FakeMesh(nx, ny, nz); - output_info.disable(); - mesh->createDefaultRegions(); - output_info.enable(); - } - - static void TearDownTestCase() { - delete mesh; - mesh = nullptr; - } - -public: - static const int nx; - static const int ny; - static const int nz; -}; - -const int Field3DTest::nx = 3; -const int Field3DTest::ny = 5; -const int Field3DTest::nz = 7; +// Reuse the "standard" fixture for FakeMesh +using Field3DTest = FakeMeshFixture; TEST_F(Field3DTest, IsReal) { Field3D field; diff --git a/tests/unit/field/test_fieldperp.cxx b/tests/unit/field/test_fieldperp.cxx index 3b5291a3f7..89611614e9 100644 --- a/tests/unit/field/test_fieldperp.cxx +++ b/tests/unit/field/test_fieldperp.cxx @@ -20,35 +20,7 @@ extern Mesh *mesh; /// Test fixture to make sure the global mesh is our fake one -class FieldPerpTest : public ::testing::Test { -protected: - static void SetUpTestCase() { - // Delete any existing mesh - if (mesh != nullptr) { - delete mesh; - mesh = nullptr; - } - mesh = new FakeMesh(nx, ny, nz); - - output_info.disable(); - mesh->createDefaultRegions(); - output_info.enable(); - } - - static void TearDownTestCase() { - delete mesh; - mesh = nullptr; - } - -public: - static const int nx; - static const int ny; - static const int nz; -}; - -const int FieldPerpTest::nx = 3; -const int FieldPerpTest::ny = 5; -const int FieldPerpTest::nz = 7; +using FieldPerpTest = FakeMeshFixture; TEST_F(FieldPerpTest, Allocate) { FieldPerp field; diff --git a/tests/unit/include/bout/test_region.cxx b/tests/unit/include/bout/test_region.cxx index 50f37a29a7..b58e117a42 100644 --- a/tests/unit/include/bout/test_region.cxx +++ b/tests/unit/include/bout/test_region.cxx @@ -18,34 +18,7 @@ extern Mesh *mesh; /// Test fixture to make sure the global mesh is our fake one -class RegionTest : public ::testing::Test { -protected: - static void SetUpTestCase() { - // Delete any existing mesh - if (mesh != nullptr) { - delete mesh; - mesh = nullptr; - } - mesh = new FakeMesh(nx, ny, nz); - output_info.disable(); - mesh->createDefaultRegions(); - output_info.enable(); - } - - static void TearDownTestCase() { - delete mesh; - mesh = nullptr; - } - -public: - static const int nx; - static const int ny; - static const int nz; -}; - -const int RegionTest::nx = 3; -const int RegionTest::ny = 5; -const int RegionTest::nz = 7; +using RegionTest = FakeMeshFixture; TEST_F(RegionTest, maxBlockSize) { EXPECT_TRUE(MAXREGIONBLOCKSIZE > 0); } @@ -1684,7 +1657,7 @@ TYPED_TEST(FieldIndexTest, Modulus) { /// Test fixture to make sure the global mesh is our fake one class IndexOffsetTest : public ::testing::Test { protected: - static void SetUpTestCase() { + IndexOffsetTest() { // Delete any existing mesh if (mesh != nullptr) { delete mesh; @@ -1696,7 +1669,7 @@ class IndexOffsetTest : public ::testing::Test { output_info.enable(); } - static void TearDownTestCase() { + ~IndexOffsetTest() { delete mesh; mesh = nullptr; } diff --git a/tests/unit/test_extras.cxx b/tests/unit/test_extras.cxx index 8e8d69bcdb..dd6e8af103 100644 --- a/tests/unit/test_extras.cxx +++ b/tests/unit/test_extras.cxx @@ -3,6 +3,11 @@ #include +// Need to provide a redundant declaration because C++ +constexpr int FakeMeshFixture::nx; +constexpr int FakeMeshFixture::ny; +constexpr int FakeMeshFixture::nz; + ::testing::AssertionResult IsSubString(const std::string &str, const std::string &substring) { if (str.find(substring) != std::string::npos) { diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 6e6c9dc2ad..f2cc1e448f 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -162,6 +162,33 @@ private: vector boundaries; }; +/// Test fixture to make sure the global mesh is our fake +/// one. Multiple tests have exactly the same fixture, so use a type +/// alias to make a new test: +/// +/// using MyTest = FakeMeshFixture; +class FakeMeshFixture : public ::testing::Test { +public: + FakeMeshFixture() { + // Delete any existing mesh + if (mesh != nullptr) { + delete mesh; + mesh = nullptr; + } + mesh = new FakeMesh(nx, ny, nz); + output_info.disable(); + mesh->createDefaultRegions(); + output_info.enable(); + } + ~FakeMeshFixture() { + delete mesh; + mesh = nullptr; + } + + static constexpr int nx = 3; + static constexpr int ny = 5; + static constexpr int nz = 7; +}; #endif // TEST_EXTRAS_H__ From dd5b2e8616a6748ea3162b3e82142ca23494e6a2 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 29 Oct 2018 17:21:33 +0000 Subject: [PATCH 0160/1783] Providing initial routines for templated derivatives --- include/bout/deriv_store.hxx | 154 +++++++ include/bout/derivs.hxx | 535 +++++++++++++++++++++++++ include/bout/template_combinations.hxx | 145 +++++++ 3 files changed, 834 insertions(+) create mode 100644 include/bout/deriv_store.hxx create mode 100644 include/bout/derivs.hxx create mode 100644 include/bout/template_combinations.hxx diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx new file mode 100644 index 0000000000..2464d5b6a1 --- /dev/null +++ b/include/bout/deriv_store.hxx @@ -0,0 +1,154 @@ +#ifndef __DERIV_STORE_HXX__ +#define __DERIV_STORE_HXX__ + +#include +#include + +#include + +/// Here we have a templated singleton that is used to store DerivativeFunctions +/// for all types of derivatives. It is templated on the FieldType (2D or 3D) as +/// the function interfaces also depend on this. It provides public routines for +/// registering and fetching derivative methods defined by a string key (e.g. "C2") +/// a DIRECTION (e.g. DIRECTION::X) and a STAGGER (e.g. STAGGER::None). There is +/// one routine for each class of derivative (standard, standard2nd, standard4th, +/// upwind and flux). +template +struct DerivativeStore{ + using standardFunc = std::function; + using upwindFunc = std::function; + using fluxFunc = std::function; + + // Singleton method + static DerivativeStore &getInstance() { + static DerivativeStore instance; + return instance; + } + + /// Register a function with standardFunc interface. Which map is used + /// depends on the derivType input. + void registerDerivative(const standardFunc func, const DERIV derivType, const DIRECTION direction, const STAGGER stagger, const std::string methodName) { + const auto key = getKey(direction, stagger, methodName); + + switch(derivType) { + case(DERIV::Standard) : + getInstance().standard[key] = func; + return; + case(DERIV::StandardSecond) : + getInstance().standardSecond[key] = func; + return; + case(DERIV::StandardFourth) : + getInstance().standardFourth[key] = func; + return; + // default: + //throw BoutException("Invalid function signature for DerivativeMethod : ..."); + }; + return; + }; + + /// Register a function with upwindFunc/fluxFunc interface. Which map is used + /// depends on the derivType input. + void registerDerivative(const upwindFunc func, const DERIV derivType, const DIRECTION direction, const STAGGER stagger, const std::string methodName) { + const auto key = getKey(direction, stagger, methodName); + switch(derivType) { + case(DERIV::Upwind) : + getInstance().upwind[key] = func; + return; + case(DERIV::Flux) : + getInstance().flux[key] = func; + return; + // default: + //throw BoutException("Invalid function signature for DerivativeMethod : ..."); + }; + return; + }; + + /// Templated versions of the above registration routines. + template + void registerDerivative(standardFunc func) { + registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), Stagger{}.lookup(), Method{}.meta.key); + }; + template + void registerDerivative(upwindFunc func) { + registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), Stagger{}.lookup(), Method{}.meta.key); + }; + + /// Routines to return a specific differential operator. Note we have to have a separate routine for different + /// methods as they have different return types. As such we choose to use a different name for each of the + /// method-classes so everything is consistently treated + standardFunc getStandardDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { + const auto instance = getInstance(); + const auto key = getKey(direction, stagger, name); + const auto resultOfFind = instance.standard.find(key); + if(resultOfFind != instance.standard.end()) return resultOfFind->second; + //throw BoutException("Couldn't find requested method ...."); + }; + standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { + const auto instance = getInstance(); + const auto key = getKey(direction, stagger, name); + const auto resultOfFind = instance.standardSecond.find(key); + if(resultOfFind != instance.standardSecond.end()) return resultOfFind->second; + //throw BoutException("Couldn't find requested method ...."); + }; + standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { + const auto instance = getInstance(); + const auto key = getKey(direction, stagger, name); + const auto resultOfFind = instance.standardFourth.find(key); + if(resultOfFind != instance.standardFourth.end()) return resultOfFind->second; + //throw BoutException("Couldn't find requested method ...."); + }; + upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { + const auto instance = getInstance(); + const auto key = getKey(direction, stagger, name); + const auto resultOfFind = instance.upwind.find(key); + if(resultOfFind != instance.upwind.end()) return resultOfFind->second; + //throw BoutException("Couldn't find requested method ...."); + }; + fluxFunc getFluxDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { + const auto instance = getInstance(); + const auto key = getKey(direction, stagger, name); + const auto resultOfFind = instance.flux.find(key); + if(resultOfFind != instance.flux.end()) return resultOfFind->second; + //throw BoutException("Couldn't find requested method ...."); + }; + +private: + std::map standard; + std::map standardSecond; + std::map standardFourth; + std::map upwind; + std::map flux; + + + /// Provides a routine to produce a unique key given information about the specific type + /// required. This is templated so requires compile-time information. Need to also supply + /// a non-templated version to account for run-time choices + /// Note : We could include the derivType in the key -- this would allow us to store + /// all methods with the same function interface in the same map, which might be nice. + std::size_t getKey(DIRECTION direction, STAGGER stagger, std::string key) { + // Note this key is indepedent of the field type (and hence the key is the same for 3D/2D + // fields) as we have to use different maps to store the different field types as the + // signature is different. + std::size_t result; + result = std::hash{}(DIRECTION_STRING(direction)); + result = result ^ std::hash{}(STAGGER_STRING(stagger)); + result = result ^ std::hash{}(key); + return result; + } + + /// Provides a routine to produce a unique key given information about the specific type + /// required. This is templated so requires compile-time information. Makes use of + /// a non-templated version that can be used to account for run-time choices + template + std::size_t getKey() { + // Note this key is indepedent of the field type (and hence the key is the same for 3D/2D + // fields) as we have to use different maps to store the different field types as the + // signature is different. + return getKey(Direction{}.lookup(), Stagger{}.lookup(), Method{}.meta.key); + } +}; + +#endif diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx new file mode 100644 index 0000000000..f22f492c75 --- /dev/null +++ b/include/bout/derivs.hxx @@ -0,0 +1,535 @@ +#ifndef __DERIVS_HXX__ +#define __DERIVS_HXX__ + +#include +#include + +#include +#include +#include +#include + +const BoutReal WENO_SMALL = 1.0e-8; // Small number for WENO schemes + +struct metaData{ + const std::string key; + const int nGuards; + const DERIV derivType; //Can be used to identify the type of the derivative +}; + +/// Provide an easy way to report a Region's statistics +inline std::ostream &operator<<(std::ostream &out, const metaData &meta){ + out<<"key : "< +class DerivativeType { +public: + template + void standard(const T &var, T &result, const REGION region) const { + // A loop over the field setting the stencil, applying the specific method + // and storing in result -- in this test case we don't have REGION etc. so + // we comment this out for now. + // + // ASSERT2(meta.derivType is one of Standard, StandardSecond and StandardFourth) + // ASSERT2(var.getMesh().getNguard() >= meta.nGuard); + // + // BOUT_FOR(i, var.getRegion(region)) { + // result[i] = apply(populateStencil(var, i)); + // } + //std::cout< + void upwindOrFlux(const T& vel, const T &var, T &result, const REGION region) const { + // A loop over the field setting the stencil, applying the specific method + // and storing in result -- in this test case we don't have REGION etc. so + // we comment this out for now. + // + // ASSERT2(meta.derivType is one of Upwind, Flux) + // ASSERT2(var.getMesh().getNguard() >= meta.nGuard); + // + // if Stagger isn't none or derivType is flux { + // BOUT_FOR(i, var.getRegion(region)) { + // result[i] = apply(populateStencil(vel, i), + // populateStencil(var, i) + // ); + // else it's a non-staggered upwind so do + // BOUT_FOR(i, var.getRegion(region)) { + // result[i] = apply(vel[i], + // populateStencil(var, i) + // ); + // } + //std::cout< centred values, or left -> left +/// +//////////////////////////////////////////////////////////////////////////////// +std::tuple vUpDown(const BoutReal v){ + return std::tuple{ 0.5*(v + fabs(v)), 0.5*(v - fabs(v))}; +} + +/// Upwinding: Central, 2nd order +DEFINE_UPWIND_DERIV(VDDX_C2, "C2", 1, DERIV::Upwind) { return vc * 0.5 * (f.p - f.m);} + +/// Upwinding: Central, 4th order +DEFINE_UPWIND_DERIV(VDDX_C4, "C4", 2, DERIV::Upwind) { return vc * (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.;} + +/// upwind, 1st order +DEFINE_UPWIND_DERIV(VDDX_U1, "U1", 1, DERIV::Upwind) { //No vec + // Existing form doesn't vectorise due to branching + return vc >= 0.0 ? vc * (f.c - f.m) : vc * (f.p - f.c); + // Alternative form would but may involve more operations + const auto vSplit = vUpDown(vc); + return (std::get<0>(vSplit)*(f.p-f.c) + + std::get<1>(vSplit) * (f.c-f.m)); +} + +/// upwind, 2nd order +DEFINE_UPWIND_DERIV(VDDX_U2, "U2", 2, DERIV::Upwind) { //No vec + // Existing form doesn't vectorise due to branching + return vc >= 0.0 ? vc * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) + : vc * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c); + // Alternative form would but may involve more operations + const auto vSplit = vUpDown(vc); + return (std::get<0>(vSplit) * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) + + std::get<1>(vSplit) * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c)); + +} + +/// upwind, 3rd order +DEFINE_UPWIND_DERIV(VDDX_U3, "U3", 2, DERIV::Upwind) { //No vec + // Existing form doesn't vectorise due to branching + return vc >= 0.0 ? vc*(4.*f.p - 12.*f.m + 2.*f.mm + 6.*f.c)/12. + : vc*(-4.*f.m + 12.*f.p - 2.*f.pp - 6.*f.c)/12.; + // Alternative form would but may involve more operations + const auto vSplit = vUpDown(vc); + return (std::get<0>(vSplit) * (4.*f.p - 12.*f.m + 2.*f.mm + 6.*f.c) + + std::get<1>(vSplit)*(-4.*f.m + 12.*f.p - 2.*f.pp - 6.*f.c))/12.; + +} + +/// 3rd-order WENO scheme +DEFINE_UPWIND_DERIV(VDDX_WENO3, "W3", 2, DERIV::Upwind) { //No vec + BoutReal deriv, w, r; + // Existing form doesn't vectorise due to branching + + if (vc > 0.0) { + // Left-biased stencil + + r = (WENO_SMALL + SQ(f.c - 2.0 * f.m + f.mm)) / + (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); + + deriv = (-f.mm + 3. * f.m - 3. * f.c + f.p); + + } else { + // Right-biased + + r = (WENO_SMALL + SQ(f.pp - 2.0 * f.p + f.c)) / + (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); + + deriv = (-f.m + 3. * f.c - 3. * f.p + f.pp); + } + + w = 1.0 / (1.0 + 2.0 * r * r); + deriv = 0.5 * ((f.p - f.m) - w * deriv); + + return vc * deriv; +} + +///----------------------------------------------------------------- +/// 3rd-order CWENO. Uses the upwinding code and split flux +DEFINE_STANDARD_DERIV(DDX_CWENO3, "W3", 2, DERIV::Standard) { + BoutReal a, ma = fabs(f.c); + // Split flux + a = fabs(f.m); + if (a > ma) + ma = a; + a = fabs(f.p); + if (a > ma) + ma = a; + a = fabs(f.mm); + if (a > ma) + ma = a; + a = fabs(f.pp); + if (a > ma) + ma = a; + + stencil sp, sm; + + sp.mm = f.mm + ma; + sp.m = f.m + ma; + sp.c = f.c + ma; + sp.p = f.p + ma; + sp.pp = f.pp + ma; + + sm.mm = ma - f.mm; + sm.m = ma - f.m; + sm.c = ma - f.c; + sm.p = ma - f.p; + sm.pp = ma - f.pp; + + const DerivativeType upwindOp; + return upwindOp.apply(0.5, sp) + upwindOp.apply(-0.5, sm); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Flux non-staggered methods +/// +/// Basic derivative methods. +/// All expect to have an input grid cell at the same location as the output +/// Hence convert cell centred values -> centred values, or left -> left +/// +//////////////////////////////////////////////////////////////////////////////// + +DEFINE_FLUX_DERIV(FDDX_U1, "U1", 1, DERIV::Flux) { //No vec + + // Velocity at lower end + BoutReal vs = 0.5 * (v.m + v.c); + BoutReal result = (vs >= 0.0) ? vs * f.m : vs * f.c; + // and at upper + vs = 0.5 * (v.c + v.p); + // Existing form doesn't vectorise due to branching + result -= (vs >= 0.0) ? vs * f.c : vs * f.p; + return - result; + + // Alternative form would but may involve more operations + const auto vSplit = vUpDown(vs); + return result - std::get<0>(vSplit) * f.c + std::get<1>(vSplit) * f.p; +} + +DEFINE_FLUX_DERIV(FDDX_C2, "C2", 2, DERIV::Flux) { return 0.5 * (v.p * f.p - v.m * f.m);} + +DEFINE_FLUX_DERIV(FDDX_C4, "C4", 2, DERIV::Flux) { return (8. * v.p * f.p - 8. * v.m * f.m + v.mm * f.mm - v.pp * f.pp) / 12.;} + +//////////////////////////////////////////////////////////////////////////////// +/// Staggered methods +/// +/// Map Centre -> Low or Low -> Centre +/// +/// These expect the output grid cell to be at a different location to the input +/// +/// The stencil no longer has a value in 'C' (centre) +/// instead, points are shifted as follows: +/// +/// mm -> -3/2 h +/// m -> -1/2 h +/// p -> +1/2 h +/// pp -? +3/2 h +/// +/// NOTE: Cell widths (dx, dy, dz) are currently defined as centre->centre +/// for the methods above. This is currently not taken account of, so large +/// variations in cell size will cause issues. +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// Standard methods -- first order +//////////////////////////////////////////////////////////////////////////////// +DEFINE_STANDARD_DERIV_STAGGERED(DDX_C2_stag, "C2", 1, DERIV::Standard) { return f.p - f.m; } + +DEFINE_STANDARD_DERIV_STAGGERED(DDX_C4_stag, "C4", 2, DERIV::Standard) { return (27. * (f.p - f.m) - (f.pp - f.mm)) / 24.; } + +//////////////////////////////////////////////////////////////////////////////// +/// Standard methods -- second order +//////////////////////////////////////////////////////////////////////////////// +DEFINE_STANDARD_DERIV_STAGGERED(D2DX2_C2_stag, "C2", 2, DERIV::StandardSecond) { return (f.pp + f.mm - f.p - f.m) / 2.; } + +//////////////////////////////////////////////////////////////////////////////// +/// Upwind methods +//////////////////////////////////////////////////////////////////////////////// +DEFINE_UPWIND_DERIV_STAGGERED(VDDX_U1_stag, "U1", 1, DERIV::Upwind) { + // Lower cell boundary + BoutReal result = (v.m >= 0) ? v.m * f.m : v.m * f.c; + + // Upper cell boundary + result -= (v.p >= 0) ? v.p * f.c : v.p * f.p; + result *= -1; + + // result is now d/dx(v*f), but want v*d/dx(f) so subtract f*d/dx(v) + result -= f.c * (v.p - v.m); + return result; +} + +DEFINE_UPWIND_DERIV_STAGGERED(VDDX_U2_stag, "U2", 2, DERIV::Upwind) { + // Calculate d(v*f)/dx = (v*f)[i+1/2] - (v*f)[i-1/2] + + // Upper cell boundary + BoutReal result = (v.p >= 0.) ? v.p * (1.5*f.c - 0.5*f.m) : v.p * (1.5*f.p - 0.5*f.pp); + + // Lower cell boundary + result -= (v.m >= 0.) ? v.m * (1.5*f.m - 0.5*f.mm) : v.m * (1.5*f.c - 0.5*f.p); + + // result is now d/dx(v*f), but want v*d/dx(f) so subtract f*d/dx(v) + result -= f.c * (v.p - v.m); + + return result; +} + +DEFINE_UPWIND_DERIV_STAGGERED(VDDX_C2_stag, "C2", 1, DERIV::Upwind) { + // Result is needed at location of f: interpolate v to f's location and take an + // unstaggered derivative of f + return 0.5 * (v.p + v.m) * 0.5 * (f.p - f.m); +} + +DEFINE_UPWIND_DERIV_STAGGERED(VDDX_C4_stag, "C4", 2, DERIV::Upwind) { + // Result is needed at location of f: interpolate v to f's location and take an + // unstaggered derivative of f + return (9. * (v.m + v.p) - v.mm - v.pp) / 16. * (8. * f.p - 8. * f.m + f.mm - f.pp) / + 12.; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Flux methods +//////////////////////////////////////////////////////////////////////////////// +DEFINE_FLUX_DERIV_STAGGERED(FDDX_U1_stag, "U1", 1, DERIV::Flux) { + // Lower cell boundary + BoutReal result = (v.m >= 0) ? v.m * f.m : v.m * f.c; + + // Upper cell boundary + result -= (v.p >= 0) ? v.p * f.c : v.p * f.p; + + return - result; +} + +///////////////////////////////////////////////////////////////////////////////// +/// Following code is for dealing with registering a method/methods for all +/// template combinations, in conjunction with the template_combinations code. +///////////////////////////////////////////////////////////////////////////////// + +struct registerMethod { + template + void operator()(Direction, Stagger, FieldType, Method) { + using namespace std::placeholders; + + auto derivativeRegister = DerivativeStore{}.getInstance(); + switch(Method{}.meta.derivType){ + case(DERIV::Standard): + case(DERIV::StandardSecond): + case(DERIV::StandardFourth): + { + const auto theFunc = std::bind( + // Method to store in function + &Method::template standard, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + Method{}, _1, _2, _3 + ); + derivativeRegister.template registerDerivative(theFunc); + break; + } + case(DERIV::Upwind): + case(DERIV::Flux): + { + const auto theFunc = std::bind( + // Method to store in function + &Method::template upwindOrFlux, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + Method{}, _1, _2, _3, _4 + ); + derivativeRegister.template registerDerivative(theFunc); + break; + } + }; + } +}; + +/// Some helper defines for now that allow us to wrap up enums +/// and the specific methods. +#define e(family, value) enumWrapper + +///////////////////////////////////////////////////////////////////////////////// +/// Here's an example of registering a couple of DerivativeType methods +/// at once for no staggering +///////////////////////////////////////////////////////////////////////////////// + +// Could use Ben's magic macro for thing here to register multiple routines at once +#define REGISTER_DERIVATIVE(name) \ + namespace {produceCombinations< \ + Set, \ + Set, \ + Set, \ + Set>\ + > reg(registerMethod{});} +#define REGISTER_STAGGERED_DERIVATIVE(name) \ + namespace {produceCombinations< \ + Set, \ + Set, \ + Set, \ + Set>\ + > reg(registerMethod{});} + +produceCombinations< + Set, + Set, + Set, + Set< + // Standard + DerivativeType, + DerivativeType, + DerivativeType, + DerivativeType, + DerivativeType, + // Standard 2nd order + DerivativeType, + DerivativeType, + // Standard 4th order + DerivativeType, + // Upwind + DerivativeType, + DerivativeType, + DerivativeType, + DerivativeType, + DerivativeType, + DerivativeType, + // Flux + DerivativeType, + DerivativeType, + DerivativeType + > + > registerDerivatives(registerMethod{}); + +produceCombinations< + Set, + Set, + Set, + Set< + // Standard + DerivativeType, + DerivativeType, + // Standard 2nd order + DerivativeType, + // Upwind + DerivativeType, + DerivativeType, + DerivativeType, + DerivativeType, + // Flux + DerivativeType + > + > registerStaggeredDerivatives(registerMethod{}); + +#endif diff --git a/include/bout/template_combinations.hxx b/include/bout/template_combinations.hxx new file mode 100644 index 0000000000..c415de24e1 --- /dev/null +++ b/include/bout/template_combinations.hxx @@ -0,0 +1,145 @@ +#ifndef __TEMPLATE_COMBINATIONS_H__ +#define __TEMPLATE_COMBINATIONS_H__ + +/// Here we define an empty templated struct that can represent +/// a collection of arbitrary types. This is useful for passing +/// template packs (typename...) around whilst being able to +/// distinguish between different template packs. +template +struct Set{}; + +/// Define a struct (functor) that we use to build up the final +/// collection of template values. Each time we create one of these +/// objects we provide one more type to the templatePack. We may call +/// the operator() method by providing all the required template parameters +/// for whatever the storedFunc is at that point -- once we have built a +/// complete templatePack we don't need to specify any of these template +/// parameters as they can be deduced/inferred. +template +struct DeferredFunction { + // Just store the actual function we wish to apply + DeferredFunction(currentFunction f): storedFunc(f){}; + + // The actual function we wish to apply with the functor + currentFunction storedFunc; + + // Make the struct a functor by defining operator() we use + // type inference to populate the templatePack/args + template + void operator()(templatePack... args) { + storedFunc(currentType{}, args...); + } +}; + +/////////////////////////////////////////////////////////// +/// Now we define routines for dealing with Sets of types +/// We use recursion to unpack each Set such that we can +/// form all combinations of the contained types. +/// As we empty Sets and get individual items we change +/// the number of arguments and hence provide several +/// overloads with different numbers of Sets. +/// Finally we end up with a single item -- this is the +/// point at which we have a unique combination of the +/// template types and can final invoke the DeferredFunction +/// +/// Note that we define the routines from the bottom up so +/// that we don't have to pre-declare routines. +/// +/// Note we make use of type inferenence with templates to +/// be able to refer to the first item in a Set/pack allowing +/// us to extract items from Sets. +/// +/////////////////////////////////////////////////////////// + +//-------------------------------------------------------- +// Routines for extracting single items from Sets and +// adding to DeferredFunction. +//-------------------------------------------------------- + +/// This is the lowest level routine -- we now have a unique +/// combination of template parameters provided to the +/// DeferredFunction (completed by passing in `item`) and +/// can therefore invoke this functor. +template +void addItemToDeferredFunction(theFunction func, item) { + // Create a new DeferredFunction building on the passed DeferredFunction (func) + // and adding the next template parameter, `item`, to the stored pack. + DeferredFunction theFinalFunction(func); + + // As we have no more Sets to process here we have a unique/complete + // combination of the template items and hence can call the final DeferredFunction + // This terminates this path and we move onto the next values in the Sets. + theFinalFunction(); +} + +/// One Set left to process so no template pack required +template +void addItemToDeferredFunction(theFunction func, item, lastSet) { + // Create a new DeferredFunction building on the passed DeferredFunction (func) + // and adding the next template parameter, `item`, to the stored pack. + DeferredFunction theNextFunction(func); + + // Process the lastSet, passing in the current state of DeferredFunction. + processSet(theNextFunction, lastSet{}); +} + +/// More than one Set left to process. +template +void addItemToDeferredFunction(theFunction func, item, nextSet, otherSets...) { + // Create a new DeferredFunction building on the passed DeferredFunction (func) + // and adding the next template parameter, `item`, to the stored pack. + DeferredFunction theNextFunction(func); + + // Process the nextSet, passing in the current state of DeferredFunction + // and the other remaining Sets. + processSet(theNextFunction, nextSet{}, otherSets{}...); +} + +//-------------------------------------------------------- +// Routines for extracting Sets from Set packs and +// passing onto the routines for processing items in a Set. +//-------------------------------------------------------- + +/// Terminal routine -- the current Set is empty +/// so nothing left to do. +template +void processSet(theFunction func, Set<>, Sets...){}; + +/// Here we use type inference to allow us to refer to the firstItem in the first Set +/// and the otherItems in this Set. We use this to pass the firstItem off to the routines +/// that will add this to the DeferredFunction. Following this we use recursion to call this +/// routine again to process the rest of this Set. +template +void processSet(theFunction func, Set, otherSets... others) { + // Take the firstItem out of the current (first) Set and add to the DeferredFunction + addItemToDeferredFunction(func, firstItem{}, others...); + + // Invoke this routine again with the items left in this Set (i.e. without firstItem) + processSet(func, Set{}, others...); +} + +//-------------------------------------------------------- +// Routine(s) for kicking off the process of processing +// the Sets. +//-------------------------------------------------------- + +/// This is the top level routine that takes the different Sets of types +/// and triggers the construction of instances of theFunction with all the +/// combinations of the template types defined by the Sets. +/// +/// A use of this might look like: +/// produceCombinations< +/// Set, +/// Set +/// >(someFunctionWhichTakesTwoTemplateTypeArguments); +/// +/// Note we wrap this in a struct such that by declaring a global variable of this +/// type we trigger the creation of the combinations. +template +struct produceCombinations{ + template + produceCombinations(theFunction func) { + processSet(func, FirstSet{}, otherSets{}...); + }; +}; +#endif From cf2b76d56557e21cbf7771992e9ef778096bbe74 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 29 Oct 2018 17:21:57 +0000 Subject: [PATCH 0161/1783] Add a few extra types/helper types --- include/bout_types.hxx | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 65ad7ba5ac..2d314ffd1c 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -54,6 +54,18 @@ inline const std::string& CELL_LOC_STRING(CELL_LOC location) { /// Differential methods. Both central and upwind enum DIFF_METHOD {DIFF_DEFAULT, DIFF_U1, DIFF_U2, DIFF_C2, DIFF_W2, DIFF_W3, DIFF_C4, DIFF_U3, DIFF_FFT, DIFF_SPLIT, DIFF_NND, DIFF_S2}; +const std::map DIFF_METHODtoString = { + {DIFF_DEFAULT, "C2"}, + {DIFF_U1, "U1"}, {DIFF_U2, "U2"}, {DIFF_U3, "U3"}, + {DIFF_C2, "C2"}, {DIFF_C4, "C4"}, {DIFF_S2, "S2"}, + {DIFF_W2, "W2"}, {DIFF_W3, "W3"}, {DIFF_FFT, "FFT"}, + {DIFF_SPLIT, "SPLIT"}, {DIFF_NND, "NND"} +}; + +inline const std::string& DIFF_METHOD_STRING(DIFF_METHOD location) { + return DIFF_METHODtoString.at(location); +} + /// Specify grid region for looping enum REGION {RGN_ALL, RGN_NOBNDRY, RGN_NOX, RGN_NOY, RGN_NOZ}; @@ -99,6 +111,28 @@ inline const std::string& STAGGER_STRING(STAGGER stagger) { return STAGGERtoString.at(stagger); } +/// To identify types of derivative method combinations +enum class DERIV { Standard = 0, StandardSecond = 1, StandardFourth = 2, + Upwind = 3, Flux = 4 }; + +static std::map derivToString = { + {DERIV::Standard, "Standard"}, + {DERIV::StandardSecond, "Standard -- second order"}, + {DERIV::StandardFourth, "Standard -- fourth order"}, + {DERIV::Upwind, "Upwind"}, + {DERIV::Flux, "Flux"} +}; + +// A small struct that can be used to wrap a specific enum value, giving +// it a unique type that can be passed as a valid type to templates and +// which can be inspected to provide the actual value of the enum +template +struct enumWrapper { + using type = T; + static const type value = val; + T lookup(){return val;}; +}; + /// Boundary condition function typedef BoutReal (*FuncPtr)(BoutReal t, BoutReal x, BoutReal y, BoutReal z); From 64117e16dd602e2631ed0c2f73ce6a76bbc81ea6 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 29 Oct 2018 17:22:47 +0000 Subject: [PATCH 0162/1783] First stab at making index_derivs use the templated derivatives --- include/bout/mesh.hxx | 208 +- src/mesh/index_derivs.cxx | 1936 ++--------------- src/mesh/interpolation/hermite_spline.cxx | 2 +- .../monotonic_hermite_spline.cxx | 2 +- 4 files changed, 266 insertions(+), 1882 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 07870aba0b..52571c242a 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -449,118 +449,48 @@ class Mesh { // Implemented in src/mesh/index_derivs.hxx BoutReal fft_derivs_filter; ///< Fraction of modes to filter. This is set in derivs_init from option "ddz:fft_filter" - /// First derivative in X direction, in index space - const Field3D indexDDX(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, + + const STAGGER getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc); + const STAGGER getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc); + + template + const T indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region); + + template + const T indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region); + + /// Derivatives in X direction, in index space + template + const T indexDDX(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); - /// First derivative in X direction, in index space - const Field2D indexDDX(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, - REGION region= RGN_NOBNDRY); - /// First derivative in Y direction in index space - const Field3D indexDDY(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, + template + const T indexD2DX2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); - /// First derivative in Y direction in index space - const Field2D indexDDY(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, + template + const T indexD4DX4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); - /// First derivative in Z direction in index space - const Field3D indexDDZ(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, + + /// Derivatives in Y direction, in index space + template + const T indexDDY(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); - const Field3D indexDDZ(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, - bool inc_xbndry) { - return indexDDZ(f, outloc, method, inc_xbndry? RGN_NOY : RGN_NOBNDRY); - } - /// First derivative in Z direction in index space - const Field2D indexDDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, + template + const T indexD2DY2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, + REGION region=RGN_NOBNDRY); + template + const T indexD4DY4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); - // Second derivatives in index space - // Implemented in src/mesh/index_derivs.hxx - - /// Second derivative in X direction in index space - /// - /// @param[in] f The field to be differentiated - /// @param[in] outloc The cell location where the result is desired - /// @param[in] method The differencing method to use, overriding default - /// @param[in] region The region of the grid for which the result is calculated. - const Field3D indexD2DX2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, - REGION region=RGN_NOBNDRY); - /// Second derivative in X direction in index space - const Field2D indexD2DX2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); - - /// Second derivative in Y direction in index space - /// - /// @param[in] f The field to be differentiated - /// @param[in] outloc The cell location where the result is desired - /// @param[in] method The differencing method to use, overriding default - /// @param[in] region The region of the grid for which the result is calculated. - const Field3D indexD2DY2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, - REGION region=RGN_NOBNDRY); - /// Second derivative in Y direction in index space - const Field2D indexD2DY2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); - - /// Second derivative in Z direction in index space - /// - /// @param[in] f The field to be differentiated - /// @param[in] outloc The cell location where the result is desired - /// @param[in] method The differencing method to use, overriding default - /// @param[in] region The region of the grid for which the result is calculated. - const Field3D indexD2DZ2(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region); - const Field3D indexD2DZ2(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, bool inc_xbndry) { - return indexD2DZ2(f,outloc, method, inc_xbndry ? RGN_NOY : RGN_NOBNDRY); - } - - // Fourth derivatives in index space - /// Fourth derivative in X direction in index space - const Field3D indexD4DX4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); - /// Fourth derivative in X direction in index space - const Field2D indexD4DX4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); - /// Fourth derivative in Y direction in index space - const Field3D indexD4DY4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); - /// Fourth derivative in Y direction in index space - const Field2D indexD4DY4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); - /// Fourth derivative in Z direction in index space - const Field3D indexD4DZ4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); - /// Fourth derivative in Z direction in index space - const Field2D indexD4DZ4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); - - // Advection schemes - - /// Advection operator in index space in X direction - /// - /// \f[ - /// v \frac{d}{di} f - /// \f] - /// - /// @param[in] v The velocity in the X direction - /// @param[in] f The field being advected - /// @param[in] outloc The cell location where the result is desired. - /// The default is the same as \p f - /// @param[in] method The differencing method to use - /// @param[in] region The region of the grid for which the result is calculated - const Field2D indexVDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY); - const Field3D indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY); + /// Derivatives in Z direction, in index space + template + const T indexDDZ(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, + REGION region=RGN_NOBNDRY); + template + const T indexD2DZ2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, + REGION region=RGN_NOBNDRY); + template + const T indexD4DZ4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, + REGION region=RGN_NOBNDRY); /// Advection operator in index space in Y direction /// @@ -573,41 +503,35 @@ class Mesh { /// @param[in] outloc The cell location where the result is desired. The default is the same as \p f /// @param[in] method The differencing method to use /// @param[in] region The region of the grid for which the result is calculated. - const Field2D indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region=RGN_NOBNDRY); - const Field3D indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region=RGN_NOBNDRY); + template + const T indexVDDX(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, + DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); + template + const T indexVDDY(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, + DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); + template + const T indexVDDZ(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, + DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); + + + + /// Flux functions + template + const T indexFDDX(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, + DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); + template + const T indexFDDY(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, + DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); + template + const T indexFDDZ(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, + DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); - /// Advection operator in index space in Z direction - /// - /// \f[ - /// v \frac{d}{di} f - /// \f] - /// - /// @param[in] v The velocity in the Z direction - /// @param[in] f The field being advected - /// @param[in] outloc The cell location where the result is desired. The default is the same as \p f - /// @param[in] method The differencing method to use - /// @param[in] region The region of the grid for which the result is calculated. - const Field3D indexVDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region=RGN_NOBNDRY); - - const Field2D indexFDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region=RGN_NOBNDRY); - const Field3D indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region=RGN_NOBNDRY); - const Field2D indexFDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region=RGN_NOBNDRY); - const Field3D indexFDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region=RGN_NOBNDRY); - const Field3D indexFDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region=RGN_NOBNDRY); /// Derivative functions of a single field stencil - typedef BoutReal (*deriv_func)(stencil &); + typedef BoutReal (*deriv_func)(const stencil &); /// Derivative functions of a BoutReal velocity, and field stencil - typedef BoutReal (*upwind_func)(BoutReal, stencil &); + typedef BoutReal (*upwind_func)(const BoutReal&, const stencil &); /// Derivative functions of a velocity field, and field stencil v, f - typedef BoutReal (*flux_func)(stencil&, stencil &); + typedef BoutReal (*flux_func)(const stencil&, const stencil &); /// Transform a field into field-aligned coordinates const Field3D toFieldAligned(const Field3D &f) { @@ -730,8 +654,13 @@ class Mesh { /// Initialise derivatives void derivs_init(Options* options); - - /// Loop over mesh, applying a stencil in the X direction + + template + const CELL_LOC getAllowedStaggerLoc(); + + template + const int getNpoints(); + template const T applyXdiff(const T &var, deriv_func func, CELL_LOC loc = CELL_DEFAULT, @@ -763,5 +692,6 @@ private: Array indexLookup3Dto2D; }; + #endif // __MESH_H__ diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 528ca211d5..de471cbf31 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -83,165 +84,6 @@ BoutReal SUPERBEE(BoutReal r) { * Hence convert cell centred values -> centred values, or left -> left *******************************************************************************/ -const BoutReal WENO_SMALL = 1.0e-8; // Small number for WENO schemes - -////////////////////// FIRST DERIVATIVES ///////////////////// - -/// central, 2nd order -BoutReal DDX_C2(stencil &f) { return 0.5 * (f.p - f.m); } - -/// central, 4th order -BoutReal DDX_C4(stencil &f) { return (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; } - -/// Central WENO method, 2nd order (reverts to 1st order near shocks) -BoutReal DDX_CWENO2(stencil &f) { - BoutReal isl, isr, isc; // Smoothness indicators - BoutReal al, ar, ac, sa; // Un-normalised weights - BoutReal dl, dr, dc; // Derivatives using different stencils - - dc = 0.5 * (f.p - f.m); - dl = f.c - f.m; - dr = f.p - f.c; - - isl = SQ(dl); - isr = SQ(dr); - isc = (13. / 3.) * SQ(f.p - 2. * f.c + f.m) + 0.25 * SQ(f.p - f.m); - - al = 0.25 / SQ(WENO_SMALL + isl); - ar = 0.25 / SQ(WENO_SMALL + isr); - ac = 0.5 / SQ(WENO_SMALL + isc); - sa = al + ar + ac; - - return (al * dl + ar * dr + ac * dc) / sa; -} - -// Smoothing 2nd order derivative -BoutReal DDX_S2(stencil &f) { - - // 4th-order differencing - BoutReal result = (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; - - result += SIGN(f.c) * (f.pp - 4. * f.p + 6. * f.c - 4. * f.m + f.mm) / 12.; - - return result; -} - -///////////////////// SECOND DERIVATIVES //////////////////// - -/// Second derivative: Central, 2nd order -BoutReal D2DX2_C2(stencil &f) { return f.p + f.m - 2. * f.c; } - -/// Second derivative: Central, 4th order -BoutReal D2DX2_C4(stencil &f) { - return (-f.pp + 16. * f.p - 30. * f.c + 16. * f.m - f.mm) / 12.; -} - -//////////////////////// UPWIND METHODS /////////////////////// - -/// Upwinding: Central, 2nd order -BoutReal VDDX_C2(BoutReal vc, stencil &f) { return vc * 0.5 * (f.p - f.m); } - -/// Upwinding: Central, 4th order -BoutReal VDDX_C4(BoutReal vc, stencil &f) { - return vc * (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; -} - -/// upwind, 1st order -BoutReal VDDX_U1(BoutReal vc, stencil &f) { - return vc >= 0.0 ? vc * (f.c - f.m) : vc * (f.p - f.c); -} - -/// upwind, 2nd order -BoutReal VDDX_U2(BoutReal vc, stencil &f) { - return vc >= 0.0 ? vc * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) - : vc * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c); -} - -/// upwind, 3rd order -BoutReal VDDX_U3(BoutReal vc, stencil &f) { - return vc >= 0.0 ? vc*(4.*f.p - 12.*f.m + 2.*f.mm + 6.*f.c)/12. - : vc*(-4.*f.m + 12.*f.p - 2.*f.pp - 6.*f.c)/12.; -} - -/// 3rd-order WENO scheme -BoutReal VDDX_WENO3(BoutReal vc, stencil &f) { - BoutReal deriv, w, r; - - if (vc > 0.0) { - // Left-biased stencil - - r = (WENO_SMALL + SQ(f.c - 2.0 * f.m + f.mm)) / - (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); - w = 1.0 / (1.0 + 2.0 * r * r); - - deriv = 0.5 * (f.p - f.m) - 0.5 * w * (-f.mm + 3. * f.m - 3. * f.c + f.p); - - } else { - // Right-biased - - r = (WENO_SMALL + SQ(f.pp - 2.0 * f.p + f.c)) / - (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); - w = 1.0 / (1.0 + 2.0 * r * r); - - deriv = 0.5 * (f.p - f.m) - 0.5 * w * (-f.m + 3. * f.c - 3. * f.p + f.pp); - } - - return vc * deriv; -} - -/// 3rd-order CWENO. Uses the upwinding code and split flux -BoutReal DDX_CWENO3(stencil &f) { - BoutReal a, ma = fabs(f.c); - // Split flux - a = fabs(f.m); - if (a > ma) - ma = a; - a = fabs(f.p); - if (a > ma) - ma = a; - a = fabs(f.mm); - if (a > ma) - ma = a; - a = fabs(f.pp); - if (a > ma) - ma = a; - - stencil sp, sm; - - sp.mm = f.mm + ma; - sp.m = f.m + ma; - sp.c = f.c + ma; - sp.p = f.p + ma; - sp.pp = f.pp + ma; - - sm.mm = ma - f.mm; - sm.m = ma - f.m; - sm.c = ma - f.c; - sm.p = ma - f.p; - sm.pp = ma - f.pp; - - return VDDX_WENO3(0.5, sp) + VDDX_WENO3(-0.5, sm); -} - -//////////////////////// FLUX METHODS /////////////////////// - -BoutReal FDDX_U1(stencil &v, stencil &f) { - // Velocity at lower end - BoutReal vs = 0.5 * (v.m + v.c); - BoutReal result = (vs >= 0.0) ? vs * f.m : vs * f.c; - // and at upper - vs = 0.5 * (v.c + v.p); - result -= (vs >= 0.0) ? vs * f.c : vs * f.p; - - return - result; -} - -BoutReal FDDX_C2(stencil &v, stencil &f) { return 0.5 * (v.p * f.p - v.m * f.m); } - -BoutReal FDDX_C4(stencil &v, stencil &f) { - return (8. * v.p * f.p - 8. * v.m * f.m + v.mm * f.mm - v.pp * f.pp) / 12.; -} - //////////////////////// MUSCL scheme /////////////////////// void DDX_KT_LR(const stencil &f, BoutReal &fLp, BoutReal &fRp, BoutReal &fLm, @@ -272,97 +114,6 @@ BoutReal DDX_KT(const stencil &f, const stencil &u, const BoutReal Vmax) { return Fm - Fp; } -/******************************************************************************* - * Staggered differencing methods - * These expect the output grid cell to be at a different location to the input - * - * The stencil no longer has a value in 'C' (centre) - * instead, points are shifted as follows: - * - * mm -> -3/2 h - * m -> -1/2 h - * p -> +1/2 h - * pp -? +3/2 h - * - * NOTE: Cell widths (dx, dy, dz) are currently defined as centre->centre - * for the methods above. This is currently not taken account of, so large - * variations in cell size will cause issues. - *******************************************************************************/ - -/////////////////////// FIRST DERIVATIVES ////////////////////// -// Map Centre -> Low or Low -> Centre - -// Second order differencing (staggered) -BoutReal DDX_C2_stag(stencil &f) { return f.p - f.m; } - -BoutReal DDX_C4_stag(stencil &f) { return (27. * (f.p - f.m) - (f.pp - f.mm)) / 24.; } - -BoutReal D2DX2_C2_stag(stencil &f) { return (f.pp + f.mm - f.p - f.m) / 2.; } -/////////////////////////// UPWINDING /////////////////////////// -// Map (Low, Centre) -> Centre or (Centre, Low) -> Low -// Hence v contains only (mm, m, p, pp) fields whilst f has 'c' too -// -// v.p is v at +1/2, v.m is at -1/2 - -BoutReal VDDX_U1_stag(stencil &v, stencil &f) { - // Lower cell boundary - BoutReal result = (v.m >= 0) ? v.m * f.m : v.m * f.c; - - // Upper cell boundary - result -= (v.p >= 0) ? v.p * f.c : v.p * f.p; - - result *= -1; - - // result is now d/dx(v*f), but want v*d/dx(f) so subtract f*d/dx(v) - result -= f.c * (v.p - v.m); - - return result; -} - -BoutReal VDDX_U2_stag(stencil &v, stencil &f) { - // Calculate d(v*f)/dx = (v*f)[i+1/2] - (v*f)[i-1/2] - - // Upper cell boundary - BoutReal result = (v.p >= 0.) ? v.p * (1.5*f.c - 0.5*f.m) : v.p * (1.5*f.p - 0.5*f.pp); - - // Lower cell boundary - result -= (v.m >= 0.) ? v.m * (1.5*f.m - 0.5*f.mm) : v.m * (1.5*f.c - 0.5*f.p); - - // result is now d/dx(v*f), but want v*d/dx(f) so subtract f*d/dx(v) - result -= f.c * (v.p - v.m); - - return result; -} - -BoutReal VDDX_C2_stag(stencil &v, stencil &f) { - // Result is needed at location of f: interpolate v to f's location and take an - // unstaggered derivative of f - return 0.5 * (v.p + v.m) * 0.5 * (f.p - f.m); -} - -BoutReal VDDX_C4_stag(stencil &v, stencil &f) { - // Result is needed at location of f: interpolate v to f's location and take an - // unstaggered derivative of f - return (9. * (v.m + v.p) - v.mm - v.pp) / 16. * (8. * f.p - 8. * f.m + f.mm - f.pp) / - 12.; -} - -/////////////////////////// FLUX /////////////////////////// -// Map (Low, Centre) -> Centre or (Centre, Low) -> Low -// Hence v contains only (mm, m, p, pp) fields whilst f has 'c' too -// -// v.p is v at +1/2, v.m is at -1/2 - -BoutReal FDDX_U1_stag(stencil &v, stencil &f) { - // Lower cell boundary - BoutReal result = (v.m >= 0) ? v.m * f.m : v.m * f.c; - - // Upper cell boundary - result -= (v.p >= 0) ? v.p * f.c : v.p * f.p; - - return - result; -} - /******************************************************************************* * Lookup tables of functions. Map between names, codes and functions *******************************************************************************/ @@ -407,51 +158,28 @@ static DiffNameLookup DiffNameTable[] = { {DIFF_DEFAULT, nullptr, nullptr}}; // Use to terminate the list /// First derivative lookup table -static DiffLookup FirstDerivTable[] = { - {DIFF_C2, DDX_C2, nullptr, nullptr}, {DIFF_W2, DDX_CWENO2, nullptr, nullptr}, - {DIFF_W3, DDX_CWENO3, nullptr, nullptr}, {DIFF_C4, DDX_C4, nullptr, nullptr}, - {DIFF_S2, DDX_S2, nullptr, nullptr}, {DIFF_FFT, nullptr, nullptr, nullptr}, - {DIFF_DEFAULT, nullptr, nullptr, nullptr}}; +static DiffLookup FirstDerivTable[] = {}; /// Second derivative lookup table -static DiffLookup SecondDerivTable[] = {{DIFF_C2, D2DX2_C2, nullptr, nullptr}, - {DIFF_C4, D2DX2_C4, nullptr, nullptr}, - {DIFF_FFT, nullptr, nullptr, nullptr}, - {DIFF_DEFAULT, nullptr, nullptr, nullptr}}; +static DiffLookup SecondDerivTable[] = {}; /// Upwinding functions lookup table -static DiffLookup UpwindTable[] = { - {DIFF_U1, nullptr, VDDX_U1, nullptr}, {DIFF_U2, nullptr, VDDX_U2, nullptr}, - {DIFF_C2, nullptr, VDDX_C2, nullptr}, {DIFF_U3, nullptr, VDDX_U3, nullptr}, - {DIFF_W3, nullptr, VDDX_WENO3, nullptr}, {DIFF_C4, nullptr, VDDX_C4, nullptr}, - {DIFF_DEFAULT, nullptr, nullptr, nullptr}}; +static DiffLookup UpwindTable[] = {}; /// Flux functions lookup table -static DiffLookup FluxTable[] = { - {DIFF_SPLIT, nullptr, nullptr, nullptr}, {DIFF_U1, nullptr, nullptr, FDDX_U1}, - {DIFF_C2, nullptr, nullptr, FDDX_C2}, {DIFF_C4, nullptr, nullptr, FDDX_C4}, - {DIFF_DEFAULT, nullptr, nullptr, nullptr}}; +static DiffLookup FluxTable[] = {}; /// First staggered derivative lookup -static DiffLookup FirstStagDerivTable[] = {{DIFF_C2, DDX_C2_stag, nullptr, nullptr}, - {DIFF_C4, DDX_C4_stag, nullptr, nullptr}, - {DIFF_DEFAULT, nullptr, nullptr, nullptr}}; +static DiffLookup FirstStagDerivTable[] = {}; /// Second staggered derivative lookup -static DiffLookup SecondStagDerivTable[] = {{DIFF_C2, D2DX2_C2_stag, nullptr, nullptr}, - {DIFF_DEFAULT, nullptr, nullptr, nullptr}}; +static DiffLookup SecondStagDerivTable[] = {}; /// Upwinding staggered lookup -static DiffLookup UpwindStagTable[] = {{DIFF_U1, nullptr, nullptr, VDDX_U1_stag}, - {DIFF_U2, nullptr, nullptr, VDDX_U2_stag}, - {DIFF_C2, nullptr, nullptr, VDDX_C2_stag}, - {DIFF_C4, nullptr, nullptr, VDDX_C4_stag}, - {DIFF_DEFAULT, nullptr, nullptr, nullptr}}; +static DiffLookup UpwindStagTable[] = {}; /// Flux staggered lookup -static DiffLookup FluxStagTable[] = {{DIFF_SPLIT, nullptr, nullptr, nullptr}, - {DIFF_U1, nullptr, nullptr, FDDX_U1_stag}, - {DIFF_DEFAULT, nullptr, nullptr, nullptr}}; +static DiffLookup FluxStagTable[] = {}; /******************************************************************************* * Routines to use the above tables to map between function codes, names @@ -899,1526 +627,252 @@ void Mesh::applyDiffKernel(const T &var, Mesh::deriv_func func, T &result, * First central derivatives *******************************************************************************/ -////////////// X DERIVATIVE ///////////////// - -const Field3D Mesh::indexDDX(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - - Mesh::deriv_func func = fDDX; // Set to default function - DiffLookup *table = FirstDerivTable; - - CELL_LOC inloc = f.getLocation(); // Input location - // Allowed staggers: - if (outloc == CELL_DEFAULT) - outloc = inloc; - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_XLOW) || - (outloc == CELL_XLOW && inloc == CELL_CENTRE)); - - if (StaggerGrids && (outloc != inloc)) { - // Shifting in X. Centre -> Xlow, or Xlow -> Centre - - func = sfDDX; // Set default - table = FirstStagDerivTable; // Set table for others - } +const STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) { + ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == allowedStaggerLoc) || + (outloc == allowedStaggerLoc && inloc == CELL_CENTRE)); - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - if (func == nullptr) - throw BoutException("Cannot use FFT for X derivatives"); + if ( (!StaggerGrids) || outloc == inloc) return STAGGER::None; + if (outloc == allowedStaggerLoc) { + return STAGGER::C2L; + } else { + return STAGGER::L2C; } - - return applyXdiff(f, func, outloc, region); } -const Field2D Mesh::indexDDX(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); - ASSERT1(method == DIFF_DEFAULT); - return applyXdiff(f, fDDX, f.getLocation(), region); +const STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) { + ASSERT1(vloc == inloc); + return getStagger(inloc, outloc, allowedStaggerLoc); } -////////////// Y DERIVATIVE ///////////////// - -const Field3D Mesh::indexDDY(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, - REGION region) { - Mesh::deriv_func func = fDDY; // Set to default function - DiffLookup *table = FirstDerivTable; - - CELL_LOC inloc = f.getLocation(); // Input location - // Allowed staggers: - if (outloc == CELL_DEFAULT) - outloc = inloc; - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_YLOW) || - (outloc == CELL_YLOW && inloc == CELL_CENTRE)); - - if (StaggerGrids && (outloc != inloc)) { - // Shifting in Y. Centre -> Ylow, or Ylow -> Centre - func = sfDDY; // Set default - table = FirstStagDerivTable; // Set table for others - } - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - if (func == nullptr) - throw BoutException("Cannot use FFT for Y derivatives"); +template +const CELL_LOC Mesh::getAllowedStaggerLoc() { + switch(direction) { + case(DIRECTION::X): + return CELL_XLOW; + case(DIRECTION::Y): + case(DIRECTION::YOrthogonal): + case(DIRECTION::YAligned): + return CELL_YLOW; + case(DIRECTION::Z): + return CELL_ZLOW; } +}; - return applyYdiff(f, func, outloc, region); -} -const Field2D Mesh::indexDDY(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); - ASSERT1(method == DIFF_DEFAULT); - return applyYdiff(f, fDDY, f.getLocation(), region); -} +template +const int Mesh::getNpoints() { + switch(direction) { + case(DIRECTION::X): + return LocalNx; + case(DIRECTION::Y): + case(DIRECTION::YOrthogonal): + case(DIRECTION::YAligned): + return LocalNy; + case(DIRECTION::Z): + return LocalNz; + } +}; -////////////// Z DERIVATIVE ///////////////// +template +const T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + // Checks + static_assert(std::is_base_of::value || std::is_base_of::value, + "indexDDX only works on Field2D or Field3D input"); + // Check that the mesh is correct + ASSERT1(this == f.getMesh()); + // Check that the input variable has data + ASSERT1(f.isAllocated()); -const Field3D Mesh::indexDDZ(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - Mesh::deriv_func func = fDDZ; // Set to default function - DiffLookup *table = FirstDerivTable; + // Define properties of this approach + const CELL_LOC allowedStaggerLoc = getAllowedStaggerLoc(); - CELL_LOC inloc = f.getLocation(); // Input location + // Handle the staggering + const CELL_LOC inloc = f.getLocation(); // Input location if (outloc == CELL_DEFAULT) outloc = inloc; - // Allowed staggers: - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_ZLOW) || - (outloc == CELL_ZLOW && inloc == CELL_CENTRE)); - - Field3D result(this); + const STAGGER stagger = getStagger(inloc, outloc, allowedStaggerLoc); - if (StaggerGrids && (outloc != inloc)) { - // Shifting in Z. Centre -> Zlow, or Zlow -> Centre - func = sfDDZ; // Set default - table = FirstStagDerivTable; // Set table for others - } + // Check for early exit + const int nPoint = getNpoints(); - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); + if (nPoint == 1) { + auto tmp = T(0., this); + tmp.setLocation(outloc); + return tmp; } - - if (func == nullptr) { - // Use FFT - - BoutReal shift = 0.; // Shifting result in Z? - if (StaggerGrids && (outloc != inloc)) { - if (outloc == CELL_ZLOW) { - // Shifting down - multiply by exp(-0.5*i*k*dz) - shift = -1.; - throw BoutException("Not tested - probably broken"); - } else { - // Shifting up - shift = 1.; - throw BoutException("Not tested - probably broken"); - } - } - - result.allocate(); // Make sure data allocated - - // Calculate how many Z wavenumbers will be removed - const int ncz = LocalNz; - int kfilter = - static_cast(fft_derivs_filter * ncz / 2); // truncates, rounding down - if (kfilter < 0) - kfilter = 0; - if (kfilter > (ncz / 2)) - kfilter = ncz / 2; - const int kmax = ncz / 2 - kfilter; // Up to and including this wavenumber index - - const auto region_str = REGION_STRING(region); - - // Only allow a whitelist of regions for now - ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" || - region_str == "RGN_NOX" || region_str == "RGN_NOY"); - - BOUT_OMP(parallel) - { - Array cv(ncz / 2 + 1); - const BoutReal kwaveFac = TWOPI / ncz; - - // Note we lookup a 2D region here even though we're operating on a Field3D - // as we only want to loop over {x, y} and then handle z differently. The - // Region blocks are constructed for elements contiguous assuming nz=1, - // as that isn't the case for Field3D (in general) this shouldn't be expected - // to vectorise (not that it would anyway) but it should still OpenMP parallelise - // ok. - // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro - // here, - // but should be ok for now. - BOUT_FOR_INNER(i, getRegion2D(region_str)) { - auto i3D = ind2Dto3D(i, 0); - rfft(&f[i3D], ncz, cv.begin()); // Forward FFT - - for (int jz = 0; jz <= kmax; jz++) { - const BoutReal kwave = jz * kwaveFac; // wave number is 1/[rad] - - cv[jz] *= dcomplex(0, kwave); - if (shift) - cv[jz] *= exp(Im * (shift * kwave)); - } - for (int jz = kmax + 1; jz <= ncz / 2; jz++) { - cv[jz] = 0.0; - } - - irfft(cv.begin(), ncz, &result[i3D]); // Reverse FFT - } - } - -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = false; - result.bndry_xout = false; - result.bndry_yup = false; - result.bndry_ydown = false; -#endif - - result.setLocation(outloc); - + + // Lookup the method + auto derivativeStore = DerivativeStore{}.getInstance(); + typename DerivativeStore::standardFunc derivativeMethod; + + if (order == 1) { + derivativeMethod = derivativeStore.getStandardDerivative(DIFF_METHOD_STRING(method), direction, stagger); + } else if (order == 2) { + derivativeMethod = derivativeStore.getStandard2ndDerivative(DIFF_METHOD_STRING(method), direction, stagger); + } else if (order == 4) { + derivativeMethod = derivativeStore.getStandard4thDerivative(DIFF_METHOD_STRING(method), direction, stagger); } else { - // All other (non-FFT) functions - result = applyZdiff(f, func, outloc, region); + throw BoutException("Invalid order used in indexStandardDerivative."); } + + // Create the result field + T result(this); + result.allocate(); // Make sure data allocated + result.setLocation(outloc); - return result; -} + // Apply method + derivativeMethod(f, result, region); -const Field2D Mesh::indexDDZ(const Field2D &f, CELL_LOC UNUSED(outloc), - DIFF_METHOD UNUSED(method), REGION UNUSED(region)) { - ASSERT1(this == f.getMesh()); - auto tmp = Field2D(0., this); - tmp.setLocation(f.getLocation()); - return tmp; + return result; } -/******************************************************************************* - * 2nd derivatives - *******************************************************************************/ - ////////////// X DERIVATIVE ///////////////// -/*! - * @brief Calculates second X derivative on Mesh in index space - * - * @param[in] f 3D scalar field to be differentiated. - * Must be allocated and finite - * - * @param[in] outloc The cell location of the result - * - * @param[in] method The numerical method to use - * - * @return A 3D scalar field with invalid data in the - * guard cells - * - */ -const Field3D Mesh::indexD2DX2(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - Mesh::deriv_func func = fD2DX2; // Set to default function - DiffLookup *table = SecondDerivTable; - - CELL_LOC inloc = f.getLocation(); // Input location - if (outloc == CELL_DEFAULT) - outloc = inloc; - // Allowed staggers: - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_XLOW) || - (outloc == CELL_XLOW && inloc == CELL_CENTRE)); - - ASSERT1(this == f.getMesh()); - - if (StaggerGrids && (outloc != inloc)) { - // Shifting in X. Centre -> Xlow, or Xlow -> Centre - func = sfD2DX2; // Set default - table = SecondStagDerivTable; // Set table for others - } - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - if (func == nullptr) - throw BoutException("Cannot use FFT for X derivatives"); - } +template +const T Mesh::indexDDX(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} - return applyXdiff(f, func, outloc, region); +template +const T Mesh::indexD2DX2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); } -/*! - * @brief Calculates second X derivative on Mesh in index space - * - * @param[in] f 2D scalar field to be differentiated. - * Must be allocated and finite - * - * @return A 2D scalar field with invalid data in the - * guard cells - * - */ -const Field2D Mesh::indexD2DX2(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); - ASSERT1(method == DIFF_DEFAULT); - return applyXdiff(f, fD2DX2, f.getLocation(), region); +template +const T Mesh::indexD4DX4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// -/*! - * @brief Calculates second Y derivative on Mesh in index space - * - * @param[in] f 3D scalar field to be differentiated. - * Must be allocated and finite - * - * @return A 3D scalar field with invalid data in the - * guard cells - * - */ -const Field3D Mesh::indexD2DY2(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - Mesh::deriv_func func = fD2DY2; // Set to default function - DiffLookup *table = SecondDerivTable; +template +const T Mesh::indexDDY(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} - ASSERT1(this == f.getMesh()); +template +const T Mesh::indexD2DY2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} - CELL_LOC inloc = f.getLocation(); // Input location - // Allowed staggers: - if (outloc == CELL_DEFAULT) - outloc = inloc; - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_YLOW) || - (outloc == CELL_YLOW && inloc == CELL_CENTRE)); +template +const T Mesh::indexD4DY4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} - if (StaggerGrids && (outloc != inloc)) { - // Shifting in Y. Centre -> Ylow, or Ylow -> Centre - func = sfD2DY2; // Set default - table = SecondStagDerivTable; // Set table for others - } +////////////// Z DERIVATIVE ///////////////// +template +const T Mesh::indexDDZ(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - if (func == nullptr) - throw BoutException("Cannot use FFT for Y derivatives"); - } +template +const T Mesh::indexD2DZ2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} - return applyYdiff(f, func, outloc, region); +template +const T Mesh::indexD4DZ4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); } -/*! - * @brief Calculates second Y derivative on Mesh in index space - * - * @param[in] f 2D scalar field to be differentiated. - * Must be allocated and finite - * - * @return A 2D scalar field with invalid data in the - * guard cells +/******************************************************************************* + * Advection schemes * - */ -const Field2D Mesh::indexD2DY2(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); - ASSERT1(method == DIFF_DEFAULT); - return applyYdiff(f, fD2DY2, f.getLocation(), region); -} + * Jan 2018 - Re-written to use iterators and handle staggering as different cases + * Jan 2009 - Re-written to use Set*Stencil routines + *******************************************************************************/ -////////////// Z DERIVATIVE ///////////////// +/******************************************************************************* + * Flux conserving schemes + *******************************************************************************/ -/*! - * @brief Calculates second Z derivative on Mesh in index space - * - * @param[in] f 3D scalar field to be differentiated. - * Must be allocated and finite - * - * @return A 3D scalar field with invalid data in the - * guard cells - * - */ -const Field3D Mesh::indexD2DZ2(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - Mesh::deriv_func func = fD2DZ2; // Set to default function - DiffLookup *table = SecondDerivTable; +template +const T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + // Checks + static_assert(std::is_base_of::value || std::is_base_of::value, + "indexDDX only works on Field2D or Field3D input"); + // Check that the mesh is correct ASSERT1(this == f.getMesh()); + ASSERT1(this == v.getMesh()); + // Check that the input variable has data + ASSERT1(f.isAllocated()); + ASSERT1(v.isAllocated()); - CELL_LOC inloc = f.getLocation(); // Input location - // Allowed staggers: + // Define properties of this approach + const CELL_LOC allowedStaggerLoc = getAllowedStaggerLoc(); + + // Handle the staggering + const CELL_LOC inloc = f.getLocation(); // Input locations + const CELL_LOC vloc = vel.getLocation(); if (outloc == CELL_DEFAULT) outloc = inloc; - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == CELL_ZLOW) || - (outloc == CELL_ZLOW && inloc == CELL_CENTRE)); + const STAGGER stagger = getStagger(vloc, inloc, outloc, allowedStaggerLoc); - Field3D result(this); + // Check for early exit + const int nPoint = getNpoints(); - if (StaggerGrids && (outloc != inloc)) { - // Shifting in Z. Centre -> Zlow, or Zlow -> Centre - func = sfD2DZ2; // Set default - table = SecondStagDerivTable; // Set table for others + if (nPoint == 1) { + auto tmp = T(0., this); + tmp.setLocation(outloc); + return tmp; } - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); + + // Lookup the method + auto derivativeStore = DerivativeStore{}.getInstance(); + typename DerivativeStore::upwindFunc derivativeMethod; + if (derivType == DERIV::Upwind) { + derivativeMethod = derivativeStore.getUpwindDerivative(DIFF_METHOD_STRING(method), direction, stagger); + } else if (derivType == DERIV::Flux) { + derivativeMethod = derivativeStore.getFluxDerivative(DIFF_METHOD_STRING(method), direction, stagger); + } else { + throw BoutException("Invalid derivative type in call to indexFlowDerivative."); } + + // Create the result field + T result(this); + result.allocate(); // Make sure data allocated + result.setLocation(outloc); - if (func == nullptr) { - // Use FFT - - BoutReal shift = 0.; // Shifting result in Z? - if (StaggerGrids && (outloc != inloc)) { - if (outloc == CELL_ZLOW) { - // Shifting down - multiply by exp(-0.5*i*k*dz) - throw BoutException("Not tested - probably broken"); - } else { - // Shifting up - throw BoutException("Not tested - probably broken"); - } - } - - result.allocate(); // Make sure data allocated - - // No filtering in 2nd derivative method - const int ncz = LocalNz; - const int kmax = ncz / 2; // Up to and including this wavenumber index - - const auto region_str = REGION_STRING(region); - - // Only allow a whitelist of regions for now - ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" || - region_str == "RGN_NOX" || region_str == "RGN_NOY"); + // Apply method + derivativeMethod(vel, f, result, region); - BOUT_OMP(parallel) { - Array cv(ncz / 2 + 1); - const BoutReal kwaveFac = TWOPI / ncz; + return result; +} - // Note we lookup a 2D region here even though we're operating on a Field3D - // as we only want to loop over {x, y} and then handle z differently. The - // Region blocks are constructed for elements contiguous assuming nz=1, - // as that isn't the case for Field3D (in general) this shouldn't be expected - // to vectorise (not that it would anyway) but it should still OpenMP parallelise - // ok. - // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro - // here, - // but should be ok for now. - BOUT_FOR_INNER(i, getRegion2D(region_str)) { - auto i3D = ind2Dto3D(i, 0); +////////////// X DERIVATIVE ///////////////// - rfft(&f[i3D], ncz, cv.begin()); // Forward FFT +template +const T Mesh::indexVDDX(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexFlowDerivative(vel, f, outloc, method, region); +} - for (int jz = 0; jz <= kmax; jz++) { - const BoutReal kwave = jz * kwaveFac; // wave number is 1/[rad] +template +const T Mesh::indexFDDX(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexFlowDerivative(vel, f, outloc, method, region); +} - cv[jz] *= -kwave * kwave; - if (shift) - cv[jz] *= exp(0.5 * Im * (shift * kwave)); - } - for (int jz = kmax + 1; jz <= ncz / 2; jz++) { - cv[jz] = 0.0; - } +////////////// Y DERIVATIVE ///////////////// - irfft(cv.begin(), ncz, &result[i3D]); // Reverse FFT - } - } +template +const T Mesh::indexVDDY(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexFlowDerivative(vel, f, outloc, method, region); +} -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = false; - result.bndry_xout = false; - result.bndry_yup = false; - result.bndry_ydown = false; -#endif +template +const T Mesh::indexFDDY(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexFlowDerivative(vel, f, outloc, method, region); +} - result.setLocation(outloc); +////////////// Z DERIVATIVE ///////////////// - } else { - // All other (non-FFT) functions - result = applyZdiff(f, func, outloc, region); - } +template +const T Mesh::indexVDDZ(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexFlowDerivative(vel, f, outloc, method, region); +} - return result; -} - -/******************************************************************************* - * Fourth derivatives - *******************************************************************************/ - -BoutReal D4DX4_C2(stencil &f) { return (f.pp - 4. * f.p + 6. * f.c - 4. * f.m + f.mm); } - -const Field3D Mesh::indexD4DX4(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); - ASSERT1(method == DIFF_DEFAULT); - return applyXdiff(f, D4DX4_C2, f.getLocation(), region); -} - -const Field2D Mesh::indexD4DX4(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); - ASSERT1(method == DIFF_DEFAULT); - return applyXdiff(f, D4DX4_C2, f.getLocation(), region); -} - -const Field3D Mesh::indexD4DY4(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); - ASSERT1(method == DIFF_DEFAULT); - return applyYdiff(f, D4DX4_C2, f.getLocation(), region); -} - -const Field2D Mesh::indexD4DY4(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); - ASSERT1(method == DIFF_DEFAULT); - return applyYdiff(f, D4DX4_C2, f.getLocation(), region); -} - -const Field3D Mesh::indexD4DZ4(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region){ - ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); - ASSERT1(method == DIFF_DEFAULT); - return applyZdiff(f, D4DX4_C2, f.getLocation(), region); -} - -const Field2D Mesh::indexD4DZ4(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD UNUSED(method), REGION UNUSED(region)) { - ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); - auto tmp = Field2D(0., this); - tmp.setLocation(f.getLocation()); - return tmp; -} - -/******************************************************************************* - * Mixed derivatives - *******************************************************************************/ - -/******************************************************************************* - * Advection schemes - * - * Jan 2018 - Re-written to use iterators and handle staggering as different cases - * Jan 2009 - Re-written to use Set*Stencil routines - *******************************************************************************/ - -////////////// X DERIVATIVE ///////////////// - -/// Special case where both arguments are 2D. Output location ignored for now -const Field2D Mesh::indexVDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - TRACE("Mesh::indexVDDX(Field2D, Field2D)"); - - CELL_LOC inloc = f.getLocation(); - CELL_LOC vloc = v.getLocation(); - if (outloc == CELL_DEFAULT) - outloc = inloc; - // Allowed staggers: - ASSERT1(outloc == inloc && inloc == vloc); - - Mesh::upwind_func func = fVDDX; - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(UpwindTable, method); - } - - ASSERT1(xstart > 0); // Need at least one guard cell - ASSERT1(this == f.getMesh()); - ASSERT1(this == v.getMesh()); - - Field2D result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - if (xstart > 1) { - // Two or more guard cells - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, f, i); - result[i] = func(v[i], s); - } - } - - } else { - // Only one guard cell - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, f, i); - result[i] = func(v[i], s); - } - } - } - -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = result.bndry_xout = false; -#endif - - return result; -} - -/// General version for 3D objects. -/// 2D objects passed as input will result in copying -const Field3D Mesh::indexVDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - TRACE("Mesh::indexVDDX(Field3D, Field3D)"); - - ASSERT1(xstart > 0); // Need at least one guard cell - ASSERT1(this == v.getMesh()); - ASSERT1(this == f.getMesh()); - - - CELL_LOC vloc = v.getLocation(); - CELL_LOC inloc = f.getLocation(); // Input location - if (outloc == CELL_DEFAULT) - outloc = inloc; - // Allowed staggers: - ASSERT1(outloc == inloc && - ((vloc == inloc) || (vloc == CELL_CENTRE && inloc == CELL_XLOW) || - (vloc == CELL_XLOW && inloc == CELL_CENTRE))); - - Field3D result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - if (StaggerGrids && (vloc != inloc)) { - // Staggered grids enabled, and velocity at different location to value - - Mesh::flux_func func = sfVDDX; - DiffLookup *table = UpwindTable; - - // V staggered w.r.t. variable - func = sfVDDX; - table = UpwindStagTable; - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - } - - // Note: The velocity stencil contains only (mm, m, p, pp) - // v.p is v at +1/2, v.m is at -1/2 relative to the field f - - if (xstart > 1) { - // Two or more guard cells - - if (vloc == CELL_XLOW) { - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - - } else { - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } - } else { - // One guard cell - - if (vloc == CELL_XLOW) { - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - - } else { - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } - } - - } else { - // Not staggered - Mesh::upwind_func func = fVDDX; - DiffLookup *table = UpwindTable; - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - } - - if (xstart > 1) { - // Two or more guard cells - BOUT_OMP(parallel) { - stencil fs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - result[i] = func(v[i], fs); - } - } - } else { - // Only one guard cell - BOUT_OMP(parallel) { - stencil fs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - result[i] = func(v[i], fs); - } - } - } - } - -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; -#endif - - return result; -} - -////////////// Y DERIVATIVE ///////////////// - -// special case where both are 2D -const Field2D Mesh::indexVDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - TRACE("Mesh::indexVDDY"); - - ASSERT1(this == v.getMesh()); - ASSERT1(this == f.getMesh()); - - CELL_LOC vloc = v.getLocation(); - CELL_LOC inloc = f.getLocation(); // Input location - if (outloc == CELL_DEFAULT) - outloc = inloc; - // Allowed staggers: - ASSERT1(outloc == inloc && - ((vloc == inloc) || (vloc == CELL_CENTRE && inloc == CELL_YLOW) || - (vloc == CELL_YLOW && inloc == CELL_CENTRE))); - - Field2D result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - if (LocalNy == 1) { - result=0; - return result; - } - - ASSERT1(ystart > 0); // Must have at least one guard cell - - if (StaggerGrids && (vloc != inloc)) { - // Staggered grids enabled, and velocity at different location to value - - Mesh::flux_func func = sfVDDY; - DiffLookup *table = UpwindTable; - - // V staggered w.r.t. variable - func = sfVDDY; - table = UpwindStagTable; - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - } - - // Note: vs.c not used for staggered differencing - // vs.m is at i-1/2, vs.p is as i+1/2 - if (vloc == CELL_YLOW) { - if (ystart > 1) { - // Two or more guard cells - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } else { - // Only one guard cell - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } - } else { - if (ystart > 1) { - // Two or more guard cells - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } else { - // Only one guard cell - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } - } - - } else { - // Not staggered - - Mesh::upwind_func func = fVDDY; - DiffLookup *table = UpwindTable; - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - } - - if (ystart > 1) { - // Two or more guard cells - BOUT_OMP(parallel) { - stencil fs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - result[i] = func(v[i], fs); - } - } - } else { - // Only one guard cell - BOUT_OMP(parallel) { - stencil fs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - result[i] = func(v[i], fs); - } - } - } - } - -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; -#endif - - return result; -} - -// general case -const Field3D Mesh::indexVDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - TRACE("Mesh::indexVDDY(Field3D, Field3D)"); - - ASSERT1(this == v.getMesh()); - ASSERT1(this == f.getMesh()); - - CELL_LOC vloc = v.getLocation(); - CELL_LOC inloc = f.getLocation(); // Input location - if (outloc == CELL_DEFAULT) - outloc = inloc; - // Allowed staggers: - ASSERT1(outloc == inloc && - ((vloc == inloc) || (vloc == CELL_CENTRE && inloc == CELL_YLOW) || - (vloc == CELL_YLOW && inloc == CELL_CENTRE))); - - Field3D result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - if (LocalNy == 1) { - result=0; - return result; - } - - ASSERT1(ystart > 0); // Need at least one guard cell - - if (StaggerGrids && (vloc != inloc)) { - // Staggered grids enabled, and velocity at different location to value - - Mesh::flux_func func = sfVDDY; - DiffLookup *table = UpwindTable; - - // V staggered w.r.t. variable - func = sfVDDY; - table = UpwindStagTable; - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - } - - // If *UseUpDown is true, field "*" has distinct yup and ydown fields which - // will be used to calculate a derivative along the magnetic field - bool vUseUpDown = (v.hasYupYdown() && ((&v.yup() != &v) || (&v.ydown() != &v))); - bool fUseUpDown = (f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); - - if (vUseUpDown && fUseUpDown) { - // Both v and f have up/down fields - if (inloc == CELL_YLOW) { - BOUT_OMP(parallel) { - stencil vval, fval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f, i); - populateStencil(vval, v, i); - result[i] = func(vval, fval); - } - } - } else { - BOUT_OMP(parallel) { - stencil vval, fval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f, i); - populateStencil(vval, v, i); - result[i] = func(vval, fval); - } - } - } - } else { - // Both must shift to field aligned - // (even if one of v and f has yup/ydown fields, it doesn't make sense to - // multiply them with one in field-aligned and one in non-field-aligned - // coordinates) - Field3D v_fa = toFieldAligned(v); - Field3D f_fa = toFieldAligned(f); - if (inloc == CELL_YLOW) { - BOUT_OMP(parallel) { - stencil vval, fval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f_fa, i); - populateStencil(vval, v_fa, i); - result[i] = func(vval, fval); - } - } - } else { - BOUT_OMP(parallel) { - stencil vval, fval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f_fa, i); - populateStencil(vval, v_fa, i); - result[i] = func(vval, fval); - } - } - } - - result = fromFieldAligned(result); - } - } else { - // Non-staggered case - - Mesh::upwind_func func = fVDDY; - DiffLookup *table = UpwindTable; - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - } - - if (f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))) { - // f has yup and ydown fields which are distinct - BOUT_OMP(parallel) { - stencil fs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - result[i] = func(v[i], fs); - } - } - } else { - // Not using yup/ydown fields, so first transform to field-aligned coordinates - Field3D f_fa = toFieldAligned(f); - Field3D v_fa = toFieldAligned(v); - - if (ystart > 1) { - BOUT_OMP(parallel) { - stencil fs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f_fa, i); - result[i] = func(v_fa[i], fs); - } - } - } else { - BOUT_OMP(parallel) { - stencil fs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f_fa, i); - result[i] = func(v_fa[i], fs); - } - } - } - // Shift result back - result = fromFieldAligned(result); - } - } - -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; -#endif - - return result; -} - -////////////// Z DERIVATIVE ///////////////// - -// general case -const Field3D Mesh::indexVDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - TRACE("Mesh::indexVDDZ"); - - ASSERT1(this == v.getMesh()); - ASSERT1(this == f.getMesh()); - - CELL_LOC vloc = v.getLocation(); - CELL_LOC inloc = f.getLocation(); // Input location - if (outloc == CELL_DEFAULT) - outloc = inloc; - // Allowed staggers: - ASSERT1(outloc == inloc && - ((vloc == inloc) || (vloc == CELL_CENTRE && inloc == CELL_ZLOW) || - (vloc == CELL_ZLOW && inloc == CELL_CENTRE))); - - Field3D result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - if (StaggerGrids && (vloc != inloc)) { - // Staggered grids enabled, and velocity at different location to value - - Mesh::flux_func func = sfVDDZ; - DiffLookup *table = UpwindTable; - - // V staggered w.r.t. variable - func = sfVDDZ; - table = UpwindStagTable; - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - } - - if (inloc == CELL_ZLOW) { - // Producing a stencil centred around a lower Z value - BOUT_OMP(parallel) { - stencil vval, fval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f, i); - populateStencil(vval, v, i); - result[i] = func(vval, fval); - } - } - } else { - // Stencil centred around a cell centre - BOUT_OMP(parallel) { - stencil vval, fval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f, i); - populateStencil(vval, v, i); - result[i] = func(vval, fval); - } - } - } - } else { - Mesh::upwind_func func = fVDDZ; - DiffLookup *table = UpwindTable; - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - } - - BOUT_OMP(parallel) { - stencil fval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f, i); - result[i] = func(v[i], fval); - } - } - } - -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; -#endif - - return result; -} - -/******************************************************************************* - * Flux conserving schemes - *******************************************************************************/ - -const Field2D Mesh::indexFDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - TRACE("Mesh::::indexFDDX(Field2D, Field2D)"); - - ASSERT1(xstart > 0); // Need at least one guard cell - - if (outloc == CELL_DEFAULT) - outloc = f.getLocation(); - - if ((method == DIFF_SPLIT) || ((method == DIFF_DEFAULT) && (fFDDX == nullptr))) { - // Split into an upwind and a central differencing part - // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) - return indexVDDX(v, f, outloc, DIFF_DEFAULT) + interp_to(f, outloc) * indexDDX(v, outloc); - } - - ASSERT1(outloc == f.getLocation() && v.getLocation() == f.getLocation()); - - Mesh::flux_func func = fFDDX; - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(FluxTable, method); - } - - Field2D result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - ASSERT1(this == v.getMesh()); - ASSERT1(this == f.getMesh()); - - if (xstart > 1) { - // Two or more guard cells - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } else { - // Only one guard cell - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } - -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = result.bndry_xout = false; -#endif - - return result; -} - -const Field3D Mesh::indexFDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - TRACE("Mesh::indexFDDX(Field3D, Field3D)"); - - ASSERT1(xstart > 0); // Need at least one guard cell - - CELL_LOC vloc = v.getLocation(); - CELL_LOC inloc = f.getLocation(); // Input location - if (outloc == CELL_DEFAULT) - outloc = inloc; - - if ((method == DIFF_SPLIT) || ((method == DIFF_DEFAULT) && (fFDDX == nullptr))) { - // Split into an upwind and a central differencing part - // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) - return indexVDDX(v, f, outloc, DIFF_DEFAULT) + indexDDX(v, outloc, DIFF_DEFAULT) * interp_to(f, outloc); - } - - ASSERT1(this == f.getMesh()); - ASSERT1(this == v.getMesh()); - - // Allowed staggers: - ASSERT1(outloc == inloc && - ((vloc == inloc) || (vloc == CELL_CENTRE && inloc == CELL_XLOW) || - (vloc == CELL_XLOW && inloc == CELL_CENTRE))); - - Mesh::flux_func func = fFDDX; - DiffLookup *table = FluxTable; - - if (StaggerGrids && (vloc != inloc)) { - // V staggered w.r.t. variable - func = sfFDDX; - table = FluxStagTable; - } - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - } - - Field3D result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - if (xstart > 1) { - // Two or more guard cells - if (StaggerGrids && vloc != inloc) { - if (inloc == CELL_XLOW) { - // Producing a stencil centred around a lower X value - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, f.getRegion(region)) { - // Location of f always the same as the output - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } else { - // Stencil centred around a cell centre - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, f.getRegion(region)) { - // Location of f always the same as the output - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } - } else { - // Non-staggered, two or more guard cells - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } - } else { - // One guard cell - if (StaggerGrids && vloc != inloc) { - if (inloc == CELL_XLOW) { - // Producing a stencil centred around a lower X value - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } else { - // Stencil centred around a cell centre - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } - } else { - // Non-staggered, one guard cell - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } - } - -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; -#endif - - return result; -} - -///////////////////////////////////////////////////////////////////////// - -const Field2D Mesh::indexFDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - TRACE("Mesh::indexFDDY(Field2D, Field2D)"); - - ASSERT1(ystart > 0); // Need at least one guard cell - ASSERT1(this == v.getMesh()); - ASSERT1(this == f.getMesh()); - - if (outloc == CELL_DEFAULT) - outloc = f.getLocation(); - - if ((method == DIFF_SPLIT) || ((method == DIFF_DEFAULT) && (fFDDY == nullptr))) { - // Split into an upwind and a central differencing part - // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) - return indexVDDY(v, f, outloc, DIFF_DEFAULT) + interp_to(f, outloc) * indexDDY(v, outloc); - } - - ASSERT1(outloc == f.getLocation() && v.getLocation() == f.getLocation()); - - Mesh::flux_func func = fFDDY; - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(FluxTable, method); - } - - Field2D result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - if (ystart > 1) { - // Two or more guard cells - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - - } else { - // Only one guard cell - BOUT_OMP(parallel) { - stencil fs, vs; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fs, f, i); - populateStencil(vs, v, i); - result[i] = func(vs, fs); - } - } - } - -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = result.bndry_xout = false; -#endif - - return result; -} - -const Field3D Mesh::indexFDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - TRACE("Mesh::indexFDDY"); - - CELL_LOC vloc = v.getLocation(); - CELL_LOC inloc = f.getLocation(); // Input location - if (outloc == CELL_DEFAULT) - outloc = inloc; - - if ((method == DIFF_SPLIT) || ((method == DIFF_DEFAULT) && (fFDDY == nullptr))) { - // Split into an upwind and a central differencing part - // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) - return indexVDDY(v, f, outloc, DIFF_DEFAULT) + indexDDY(v, outloc, DIFF_DEFAULT) * interp_to(f, outloc); - } - Mesh::flux_func func = fFDDY; - DiffLookup *table = FluxTable; - - // Allowed staggers: - ASSERT1(outloc == inloc && - ((vloc == inloc) || (vloc == CELL_CENTRE && inloc == CELL_YLOW) || - (vloc == CELL_YLOW && inloc == CELL_CENTRE))); - - if (StaggerGrids && (vloc != inloc)) { - // V staggered w.r.t. variable - func = sfFDDY; - table = FluxStagTable; - } - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - } - - if (func == nullptr) { - // To catch when no function - return indexVDDY(v, f, outloc, DIFF_DEFAULT) + indexDDY(v, outloc, DIFF_DEFAULT) * interp_to(f, outloc); - } - - ASSERT1(this == v.getMesh()); - ASSERT1(this == f.getMesh()); - - Field3D result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - // If *UseUpDown is true, field "*" has distinct yup and ydown fields which - // will be used to calculate a derivative along the magnetic field - bool vUseUpDown = (v.hasYupYdown() && ((&v.yup() != &v) || (&v.ydown() != &v))); - bool fUseUpDown = (f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); - - if (vUseUpDown && fUseUpDown) { - // Both v and f have up/down fields - if (StaggerGrids && (inloc != vloc)) { - if (inloc == CELL_YLOW) { - BOUT_OMP(parallel) { - stencil fval, vval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f, i); - populateStencil(vval, v, i); - result[i] = func(vval, fval); - } - } - } else { - BOUT_OMP(parallel) { - stencil fval, vval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f, i); - populateStencil(vval, v, i); - result[i] = func(vval, fval); - } - } - } - } else { - BOUT_OMP(parallel) { - stencil fval, vval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f, i); - populateStencil(vval, v, i); - result[i] = func(vval, fval); - } - } - } - } else { - // Both must shift to field aligned - // (even if one of v and f has yup/ydown fields, it doesn't make sense to - // multiply them with one in field-aligned and one in non-field-aligned - // coordinates) - Field3D v_fa = toFieldAligned(v); - Field3D f_fa = toFieldAligned(f); - if (StaggerGrids && (inloc != vloc)) { - // Non-centred stencil - if (inloc == CELL_YLOW) { - BOUT_OMP(parallel) { - stencil fval, vval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f_fa, i); - populateStencil(vval, v_fa, i); - result[i] = func(vval, fval); - } - } - } else { - BOUT_OMP(parallel) { - stencil fval, vval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f_fa, i); - populateStencil(vval, v_fa, i); - result[i] = func(vval, fval); - } - } - } - } else { - BOUT_OMP(parallel) { - stencil fval, vval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f_fa, i); - populateStencil(vval, v_fa, i); - result[i] = func(vval, fval); - } - } - } - - result = fromFieldAligned(result); - } - -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; -#endif - - return result; -} - -///////////////////////////////////////////////////////////////////////// - -const Field3D Mesh::indexFDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region) { - TRACE("Mesh::indexFDDZ(Field3D, Field3D)"); - - CELL_LOC vloc = v.getLocation(); - CELL_LOC inloc = f.getLocation(); // Input location - if (outloc == CELL_DEFAULT) - outloc = inloc; - - if ((method == DIFF_SPLIT) || ((method == DIFF_DEFAULT) && (fFDDZ == nullptr))) { - // Split into an upwind and a central differencing part - // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) - return indexVDDZ(v, f, outloc, DIFF_DEFAULT) + - indexDDZ(v, outloc, DIFF_DEFAULT, true) * interp_to(f, outloc); - } - - Mesh::flux_func func = fFDDZ; - DiffLookup *table = FluxTable; - - // Allowed staggers: - ASSERT1(outloc == inloc && - ((vloc == inloc) || (vloc == CELL_CENTRE && inloc == CELL_ZLOW) || - (vloc == CELL_ZLOW && inloc == CELL_CENTRE))); - - if (StaggerGrids && (vloc != inloc)) { - // V staggered w.r.t. variable - func = sfFDDZ; - table = FluxStagTable; - } - - if (method != DIFF_DEFAULT) { - // Lookup function - func = lookupFunc(table, method); - } - - ASSERT1(this == v.getMesh()); - ASSERT1(this == f.getMesh()); - - Field3D result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - if (StaggerGrids && (inloc != vloc)) { - // Non-centred stencil - - if (inloc == CELL_ZLOW) { - // Producing a stencil centred around a lower Z value - BOUT_OMP(parallel) { - stencil vval, fval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f, i); - populateStencil(vval, v, i); - result[i] = func(vval, fval); - } - } - } else { - BOUT_OMP(parallel) { - stencil vval, fval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f, i); - populateStencil(vval, v, i); - result[i] = func(vval, fval); - } - } - } - } else { - BOUT_OMP(parallel) { - stencil vval, fval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(fval, f, i); - populateStencil(vval, v, i); - result[i] = func(vval, fval); - } - } - } - -#if CHECK > 0 - // Mark boundaries as invalid - result.bndry_xin = result.bndry_xout = result.bndry_yup = result.bndry_ydown = false; -#endif - - return result; +template +const T Mesh::indexFDDZ(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexFlowDerivative(vel, f, outloc, method, region); } diff --git a/src/mesh/interpolation/hermite_spline.cxx b/src/mesh/interpolation/hermite_spline.cxx index 59367f544a..41f51b2ae5 100644 --- a/src/mesh/interpolation/hermite_spline.cxx +++ b/src/mesh/interpolation/hermite_spline.cxx @@ -115,7 +115,7 @@ Field3D HermiteSpline::interpolate(const Field3D &f) const { // coordinates Field3D fx = localmesh->indexDDX(f, CELL_DEFAULT, DIFF_DEFAULT); localmesh->communicateXZ(fx); - Field3D fz = localmesh->indexDDZ(f, CELL_DEFAULT, DIFF_DEFAULT, true); + Field3D fz = localmesh->indexDDZ(f, CELL_DEFAULT, DIFF_DEFAULT, RGN_ALL); localmesh->communicateXZ(fz); Field3D fxz = localmesh->indexDDX(fz, CELL_DEFAULT, DIFF_DEFAULT); localmesh->communicateXZ(fxz); diff --git a/src/mesh/interpolation/monotonic_hermite_spline.cxx b/src/mesh/interpolation/monotonic_hermite_spline.cxx index 7507da6a57..e9884e5f0f 100644 --- a/src/mesh/interpolation/monotonic_hermite_spline.cxx +++ b/src/mesh/interpolation/monotonic_hermite_spline.cxx @@ -37,7 +37,7 @@ Field3D MonotonicHermiteSpline::interpolate(const Field3D &f) const { // coordinates Field3D fx = localmesh->indexDDX(f, CELL_DEFAULT, DIFF_DEFAULT); localmesh->communicateXZ(fx); - Field3D fz = localmesh->indexDDZ(f, CELL_DEFAULT, DIFF_DEFAULT, true); + Field3D fz = localmesh->indexDDZ(f, CELL_DEFAULT, DIFF_DEFAULT, RGN_ALL); localmesh->communicateXZ(fz); Field3D fxz = localmesh->indexDDX(fz, CELL_DEFAULT, DIFF_DEFAULT); localmesh->communicateXZ(fxz); From 93cbed038c0ff803dba1e3c75995c67248bb7c15 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 29 Oct 2018 17:23:59 +0000 Subject: [PATCH 0163/1783] Remove apply?Diff routines --- src/mesh/index_derivs.cxx | 271 +------------------------------------- 1 file changed, 5 insertions(+), 266 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index de471cbf31..9ad3fdd640 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -359,272 +359,7 @@ void Mesh::derivs_init(Options *options) { } /******************************************************************************* - * Apply differential operators. These are fairly brain-dead functions - * which apply a derivative function to a field (sort of like map). Decisions - * of what to apply are made in the DDX,DDY and DDZ functions lower down. - * - * loc is the cell location of the result - *******************************************************************************/ - -// X derivative -template -const T Mesh::applyXdiff(const T &var, Mesh::deriv_func func, - CELL_LOC outloc, REGION region) { - - static_assert(std::is_base_of::value || std::is_base_of::value, - "applyXdiff only works on Field2D or Field3D input"); - - // Check that the mesh is correct - ASSERT1(this == var.getMesh()); - // Check that the input variable has data - ASSERT1(var.isAllocated()); - - CELL_LOC inloc = var.getLocation(); - if (outloc == CELL_DEFAULT) - outloc = inloc; - - // Determine what the non-centre allowed location is for outloc - CELL_LOC allowedStaggerLoc; - allowedStaggerLoc = CELL_XLOW; - - // Allowed staggers: - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == allowedStaggerLoc) || - (outloc == allowedStaggerLoc && inloc == CELL_CENTRE)); - - int nPoint, nGuard; - nPoint = var.getNx(); - nGuard = xstart; - - if (nPoint == 1) { - auto tmp = T(0., this); - tmp.setLocation(outloc); - return tmp; - } - - T result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - if (StaggerGrids && (outloc != inloc)) { - // Staggered differencing - - if (nGuard > 1) { - // More than one guard cell, so set pp and mm values - // This allows higher-order methods to be used - if (outloc == allowedStaggerLoc) { - applyDiffKernel(var, func, result, region); - } else { - applyDiffKernel(var, func, result, region); - } - } else { - // Only one guard cell, so no pp or mm values - if (outloc == allowedStaggerLoc) { - applyDiffKernel(var, func, result, region); - } else { - applyDiffKernel(var, func, result, region); - } - } - } else { - // Non-staggered differencing - if (nGuard > 1) { - // More than one guard cell, so set pp and mm values - // This allows higher-order methods to be used - applyDiffKernel(var, func, result, region); - } else { - // Only one guard cell, so no pp or mm values - applyDiffKernel(var, func, result, region); - } - } - - return result; -} - -// Y derivative -template -const T Mesh::applyYdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, - REGION region) { - - static_assert(std::is_base_of::value || std::is_base_of::value, - "applyYdiff only works on Field2D or Field3D input"); - - ASSERT1(this == var.getMesh()); - // Check that the input variable has data - ASSERT1(var.isAllocated()); - - // Cell location of the input field - CELL_LOC inloc = var.getLocation(); - if (outloc == CELL_DEFAULT) - outloc = inloc; - - // Determine what the non-centre allowed location is for outloc - CELL_LOC allowedStaggerLoc; - allowedStaggerLoc = CELL_YLOW; - - // Allowed staggers: - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == allowedStaggerLoc) || - (outloc == allowedStaggerLoc && inloc == CELL_CENTRE)); - - int nPoint, nGuard; - nPoint = var.getNy(); - nGuard = ystart; - - if (nPoint == 1) { - auto tmp = T(0., this); - tmp.setLocation(outloc); - return tmp; - } - - T result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - if (std::is_base_of::value && var.hasYupYdown() && - ((&var.yup() != &var) || (&var.ydown() != &var))) { - // Field "var" has distinct yup and ydown fields which - // will be used to calculate a derivative along - // the magnetic field - - if (StaggerGrids && (outloc != inloc)) { - // Staggered differencing - if (outloc == allowedStaggerLoc) { - applyDiffKernel(var, func, result, - region); - } else { - applyDiffKernel(var, func, result, - region); - } - } else { - // Non-staggered - applyDiffKernel(var, func, result, - region); - } - } else { - // var has no yup/ydown fields, so we need to shift into field-aligned coordinates - T var_fa = toFieldAligned(var); - - if (StaggerGrids && (outloc != inloc)) { - // Staggered differencing - if (nGuard > 1) { - // More than one guard cell, so set pp and mm values - // This allows higher-order methods to be used - if (outloc == allowedStaggerLoc) { - applyDiffKernel(var_fa, func, result, region); - } else { - applyDiffKernel(var_fa, func, result, region); - } - } else { - // Only one guard cell, so no pp or mm values - if (outloc == allowedStaggerLoc) { - applyDiffKernel(var_fa, func, result, region); - } else { - applyDiffKernel(var_fa, func, result, region); - } - } - } else { - // Non-staggered differencing - - if (nGuard > 1) { - // More than one guard cell, so set pp and mm values - // This allows higher-order methods to be used - applyDiffKernel(var_fa, func, result, region); - } else { - // Only one guard cell, so no pp or mm values - applyDiffKernel(var_fa, func, result, region); - } - } - - // Shift result back - result = fromFieldAligned(result); - } - - return result; -} - -// Z derivative -template -const T Mesh::applyZdiff(const T &var, Mesh::deriv_func func, CELL_LOC outloc, - REGION region) { - - static_assert(std::is_base_of::value || std::is_base_of::value, - "applyZdiff only works on Field2D or Field3D input"); - - ASSERT1(this == var.getMesh()); - // Check that the input variable has data - ASSERT1(var.isAllocated()); - - CELL_LOC inloc = var.getLocation(); - if (outloc == CELL_DEFAULT) - outloc = inloc; - - // Determine what the non-centre allowed location is for outloc - CELL_LOC allowedStaggerLoc; - allowedStaggerLoc = CELL_ZLOW; - - // Allowed staggers: - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == allowedStaggerLoc) || - (outloc == allowedStaggerLoc && inloc == CELL_CENTRE)); - - int nPoint, nGuard; - nPoint = var.getNz(); - nGuard = 2; - - if (nPoint == 1) { - auto tmp = T(0., this); - tmp.setLocation(outloc); - return tmp; - } - - T result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - if (StaggerGrids && (outloc != inloc)) { - // Staggered differencing - if (nGuard > 1) { - // More than one guard cell, so set pp and mm values - // This allows higher-order methods to be used - if (outloc == allowedStaggerLoc) { - applyDiffKernel(var, func, result, region); - } else { - applyDiffKernel(var, func, result, region); - } - } else { - // Only one guard cell, so no pp or mm values - if (outloc == allowedStaggerLoc) { - applyDiffKernel(var, func, result, region); - } else { - applyDiffKernel(var, func, result, region); - } - } - } else { - // Non-staggered differencing - if (nGuard > 1) { - // More than one guard cell, so set pp and mm values - // This allows higher-order methods to be used - applyDiffKernel(var, func, result, region); - } else { - // Only one guard cell, so no pp or mm values - applyDiffKernel(var, func, result, region); - } - } - - return result; -} - -template -void Mesh::applyDiffKernel(const T &var, Mesh::deriv_func func, T &result, - REGION region) { - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region)) { - populateStencil(s, var, i); - result[i] = func(s); - } - } - return; -} -/******************************************************************************* - * First central derivatives + * Helper routines *******************************************************************************/ const STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) { @@ -673,6 +408,10 @@ const int Mesh::getNpoints() { } }; +/******************************************************************************* + * Actual derivative operators + *******************************************************************************/ + template const T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { // Checks From 032f771747def98aace07ab27440e9969ed04fe2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 29 Oct 2018 17:24:01 +0000 Subject: [PATCH 0164/1783] Use individual testcase setup/teardown for vector tests Rather than test set level --- tests/unit/field/test_vector2d.cxx | 16 ++++++++-------- tests/unit/field/test_vector3d.cxx | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index 7824f2b2cf..5681bc6c12 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -15,7 +15,7 @@ extern Mesh *mesh; /// Test fixture to make sure the global mesh is our fake one class Vector2DTest : public ::testing::Test { protected: - static void SetUpTestCase() { + Vector2DTest() { // Delete any existing mesh if (mesh != nullptr) { // Delete boundary regions @@ -37,7 +37,7 @@ class Vector2DTest : public ::testing::Test { mesh->addBoundary(new BoundaryRegionYDown("lower_target", 1, nx - 2, mesh)); } - static void TearDownTestCase() { + ~Vector2DTest() { if (mesh != nullptr) { // Delete boundary regions for (auto &r : mesh->getBoundaries()) { @@ -49,14 +49,14 @@ class Vector2DTest : public ::testing::Test { } public: - static const int nx; - static const int ny; - static const int nz; + static constexpr int nx = 5; + static constexpr int ny = 5; + static constexpr int nz = 1; }; -const int Vector2DTest::nx = 5; -const int Vector2DTest::ny = 5; -const int Vector2DTest::nz = 1; +constexpr int Vector2DTest::nx; +constexpr int Vector2DTest::ny; +constexpr int Vector2DTest::nz; TEST_F(Vector2DTest, ApplyBoundaryString) { Vector2D v; diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index fb77078781..1058a7918c 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -14,7 +14,7 @@ extern Mesh *mesh; /// Test fixture to make sure the global mesh is our fake one class Vector3DTest : public ::testing::Test { protected: - static void SetUpTestCase() { + Vector3DTest() { // Delete any existing mesh if (mesh != nullptr) { // Delete boundary regions @@ -36,7 +36,7 @@ class Vector3DTest : public ::testing::Test { mesh->addBoundary(new BoundaryRegionYDown("lower_target", 1, nx - 2, mesh)); } - static void TearDownTestCase() { + ~Vector3DTest() { if (mesh != nullptr) { // Delete boundary regions for (auto &r : mesh->getBoundaries()) { From dc95c252d9447ca72d27d4cc0d30f4d9c8a91a41 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 29 Oct 2018 17:25:17 +0000 Subject: [PATCH 0165/1783] Small fix to locale/README.md Changed makefile target, but hadn't updated README. --- locale/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locale/README.md b/locale/README.md index 4f35c2da08..9b0ed60967 100644 --- a/locale/README.md +++ b/locale/README.md @@ -19,7 +19,7 @@ Update the template (.pot) file: Start a new translation: - make po-XX + make locale-XX where XX is the language e.g. "de" for German, or a language_country code e.g. "de_DE". This will update a .po file if it already exists. From 3608ca202ae25eecc88eecf20dd9dc7c4c0c2bdb Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 29 Oct 2018 17:28:51 +0000 Subject: [PATCH 0166/1783] Remove backup/restore of mesh settings Not needed now mesh is independent between individual tests --- tests/unit/field/test_field3d.cxx | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index a3518625ba..da42300599 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -1100,7 +1100,6 @@ TEST_F(Field3DTest, AddEqualsField3D) { } TEST_F(Field3DTest, AddEqualsField3DField3DStagger) { - auto backup = mesh->StaggerGrids; mesh->StaggerGrids = true; // Force staggering Field3D a, b; @@ -1117,8 +1116,6 @@ TEST_F(Field3DTest, AddEqualsField3DField3DStagger) { #else EXPECT_NO_THROW(a += b); #endif - - mesh->StaggerGrids = backup; } TEST_F(Field3DTest, AddField3DBoutReal) { @@ -1172,7 +1169,6 @@ TEST_F(Field3DTest, AddField3DField3D) { } TEST_F(Field3DTest, AddField3DField3DStagger) { - auto backup = mesh->StaggerGrids; mesh->StaggerGrids = true; // Force staggering Field3D a, b, c; @@ -1197,8 +1193,6 @@ TEST_F(Field3DTest, AddField3DField3DStagger) { // Hence the first case should now not throw EXPECT_NO_THROW(c = a + b); - - mesh->StaggerGrids = backup; } TEST_F(Field3DTest, MultiplyEqualsBoutReal) { @@ -1253,7 +1247,6 @@ TEST_F(Field3DTest, MultiplyEqualsField3D) { } TEST_F(Field3DTest, MultiplyEqualsField3DField3DStagger) { - auto backup = mesh->StaggerGrids; mesh->StaggerGrids = true; // Force staggering Field3D a, b; @@ -1270,8 +1263,6 @@ TEST_F(Field3DTest, MultiplyEqualsField3DField3DStagger) { #else EXPECT_NO_THROW(a *= b); #endif - - mesh->StaggerGrids = backup; } TEST_F(Field3DTest, MultiplyField3DBoutReal) { @@ -1325,7 +1316,6 @@ TEST_F(Field3DTest, MultiplyField3DField3D) { } TEST_F(Field3DTest, MultiplyField3DField3DStagger) { - auto backup = mesh->StaggerGrids; mesh->StaggerGrids = true; // Force staggering Field3D a, b, c; @@ -1350,8 +1340,6 @@ TEST_F(Field3DTest, MultiplyField3DField3DStagger) { // Hence the first case should now not throw EXPECT_NO_THROW(c = a * b); - - mesh->StaggerGrids = backup; } TEST_F(Field3DTest, SubtractEqualsBoutReal) { @@ -1406,7 +1394,6 @@ TEST_F(Field3DTest, SubtractEqualsField3D) { } TEST_F(Field3DTest, SubtractEqualsField3DField3DStagger) { - auto backup = mesh->StaggerGrids; mesh->StaggerGrids = true; // Force staggering Field3D a, b; @@ -1423,8 +1410,6 @@ TEST_F(Field3DTest, SubtractEqualsField3DField3DStagger) { #else EXPECT_NO_THROW(a -= b); #endif - - mesh->StaggerGrids = backup; } TEST_F(Field3DTest, SubtractField3DBoutReal) { @@ -1478,7 +1463,6 @@ TEST_F(Field3DTest, SubtractField3DField3D) { } TEST_F(Field3DTest, SubtractField3DField3DStagger) { - auto backup = mesh->StaggerGrids; mesh->StaggerGrids = true; // Force staggering Field3D a, b, c; @@ -1503,8 +1487,6 @@ TEST_F(Field3DTest, SubtractField3DField3DStagger) { // Hence the first case should now not throw EXPECT_NO_THROW(c = a - b); - - mesh->StaggerGrids = backup; } TEST_F(Field3DTest, DivideEqualsBoutReal) { @@ -1559,7 +1541,6 @@ TEST_F(Field3DTest, DivideEqualsField3D) { } TEST_F(Field3DTest, DivideEqualsField3DField3DStagger) { - auto backup = mesh->StaggerGrids; mesh->StaggerGrids = true; // Force staggering Field3D a, b; @@ -1576,8 +1557,6 @@ TEST_F(Field3DTest, DivideEqualsField3DField3DStagger) { #else EXPECT_NO_THROW(a /= b); #endif - - mesh->StaggerGrids = backup; } TEST_F(Field3DTest, DivideField3DBoutReal) { @@ -1631,7 +1610,6 @@ TEST_F(Field3DTest, DivideField3DField3D) { } TEST_F(Field3DTest, DivideField3DField3DStagger) { - auto backup = mesh->StaggerGrids; mesh->StaggerGrids = true; // Force staggering Field3D a, b, c; @@ -1656,8 +1634,6 @@ TEST_F(Field3DTest, DivideField3DField3DStagger) { // Hence the first case should now not throw EXPECT_NO_THROW(c = a / b); - - mesh->StaggerGrids = backup; } TEST_F(Field3DTest, PowBoutRealField3D) { From 4dcb54c47862292f4bba61fd069388831184623a Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 29 Oct 2018 17:50:07 +0000 Subject: [PATCH 0167/1783] Tests now compile --- include/bout/mesh.hxx | 252 +++++++++++++++++++++++++++++++++++--- src/mesh/index_derivs.cxx | 249 +++---------------------------------- 2 files changed, 246 insertions(+), 255 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 52571c242a..0257fe13b0 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -45,6 +45,7 @@ class Mesh; #include "mpi.h" +#include #include "field_data.hxx" #include "bout_types.hxx" #include "field2d.hxx" @@ -660,26 +661,6 @@ class Mesh { template const int getNpoints(); - - template - const T applyXdiff(const T &var, deriv_func func, - CELL_LOC loc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY); - - template - const T applyYdiff(const T &var, deriv_func func, - CELL_LOC loc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY); - - template - const T applyZdiff(const T &var, deriv_func func, - CELL_LOC loc = CELL_DEFAULT, - REGION region = RGN_NOBNDRY); - - template - void applyDiffKernel(const T &var, deriv_func func, T &result, - REGION region = RGN_NOBNDRY); - private: /// Allocates default Coordinates objects @@ -692,6 +673,237 @@ private: Array indexLookup3Dto2D; }; +////// STANDARD OPERATORS + +////////////// X DERIVATIVE ///////////////// + +template +const T Mesh::indexDDX(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} + +template +const T Mesh::indexD2DX2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} + +template +const T Mesh::indexD4DX4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} + +////////////// Y DERIVATIVE ///////////////// + +template +const T Mesh::indexDDY(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} + +template +const T Mesh::indexD2DY2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} + +template +const T Mesh::indexD4DY4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} + +////////////// Z DERIVATIVE ///////////////// +template +const T Mesh::indexDDZ(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} + +template +const T Mesh::indexD2DZ2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} + +template +const T Mesh::indexD4DZ4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexStandardDerivative(f, outloc, method, region); +} + +////// ADVECTION AND FLUX OPERATORS + +////////////// X DERIVATIVE ///////////////// + +template +const T Mesh::indexVDDX(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexFlowDerivative(vel, f, outloc, method, region); +} + +template +const T Mesh::indexFDDX(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexFlowDerivative(vel, f, outloc, method, region); +} + +////////////// Y DERIVATIVE ///////////////// + +template +const T Mesh::indexVDDY(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexFlowDerivative(vel, f, outloc, method, region); +} + +template +const T Mesh::indexFDDY(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexFlowDerivative(vel, f, outloc, method, region); +} + +////////////// Z DERIVATIVE ///////////////// + +template +const T Mesh::indexVDDZ(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexFlowDerivative(vel, f, outloc, method, region); +} + +template +const T Mesh::indexFDDZ(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + return indexFlowDerivative(vel, f, outloc, method, region); +} + + + +template +const T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + // Checks + static_assert(std::is_base_of::value || std::is_base_of::value, + "indexDDX only works on Field2D or Field3D input"); + // Check that the mesh is correct + ASSERT1(this == f.getMesh()); + ASSERT1(this == v.getMesh()); + // Check that the input variable has data + ASSERT1(f.isAllocated()); + ASSERT1(v.isAllocated()); + + // Define properties of this approach + const CELL_LOC allowedStaggerLoc = getAllowedStaggerLoc(); + + // Handle the staggering + const CELL_LOC inloc = f.getLocation(); // Input locations + const CELL_LOC vloc = vel.getLocation(); + if (outloc == CELL_DEFAULT) + outloc = inloc; + const STAGGER stagger = getStagger(vloc, inloc, outloc, allowedStaggerLoc); + + // Check for early exit + const int nPoint = getNpoints(); + + if (nPoint == 1) { + auto tmp = T(0., this); + tmp.setLocation(outloc); + return tmp; + } + + // Lookup the method + auto derivativeStore = DerivativeStore{}.getInstance(); + typename DerivativeStore::upwindFunc derivativeMethod; + if (derivType == DERIV::Upwind) { + derivativeMethod = derivativeStore.getUpwindDerivative(DIFF_METHOD_STRING(method), direction, stagger); + } else if (derivType == DERIV::Flux) { + derivativeMethod = derivativeStore.getFluxDerivative(DIFF_METHOD_STRING(method), direction, stagger); + } else { + throw BoutException("Invalid derivative type in call to indexFlowDerivative."); + } + + // Create the result field + T result(this); + result.allocate(); // Make sure data allocated + result.setLocation(outloc); + + // Apply method + derivativeMethod(vel, f, result, region); + + return result; +} + + +template +const T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { + // Checks + static_assert(std::is_base_of::value || std::is_base_of::value, + "indexDDX only works on Field2D or Field3D input"); + // Check that the mesh is correct + ASSERT1(this == f.getMesh()); + // Check that the input variable has data + ASSERT1(f.isAllocated()); + + // Define properties of this approach + const CELL_LOC allowedStaggerLoc = getAllowedStaggerLoc(); + + // Handle the staggering + const CELL_LOC inloc = f.getLocation(); // Input location + if (outloc == CELL_DEFAULT) + outloc = inloc; + const STAGGER stagger = getStagger(inloc, outloc, allowedStaggerLoc); + + // Check for early exit + const int nPoint = getNpoints(); + + if (nPoint == 1) { + auto tmp = T(0., this); + tmp.setLocation(outloc); + return tmp; + } + + // Lookup the method + auto derivativeStore = DerivativeStore{}.getInstance(); + typename DerivativeStore::standardFunc derivativeMethod; + + if (order == 1) { + derivativeMethod = derivativeStore.getStandardDerivative(DIFF_METHOD_STRING(method), direction, stagger); + } else if (order == 2) { + derivativeMethod = derivativeStore.getStandard2ndDerivative(DIFF_METHOD_STRING(method), direction, stagger); + } else if (order == 4) { + derivativeMethod = derivativeStore.getStandard4thDerivative(DIFF_METHOD_STRING(method), direction, stagger); + } else { + throw BoutException("Invalid order used in indexStandardDerivative."); + } + + // Create the result field + T result(this); + result.allocate(); // Make sure data allocated + result.setLocation(outloc); + + // Apply method + derivativeMethod(f, result, region); + + return result; +} + +/******************************************************************************* + * Helper routines + *******************************************************************************/ + +template +const CELL_LOC Mesh::getAllowedStaggerLoc() { + switch(direction) { + case(DIRECTION::X): + return CELL_XLOW; + case(DIRECTION::Y): + case(DIRECTION::YOrthogonal): + case(DIRECTION::YAligned): + return CELL_YLOW; + case(DIRECTION::Z): + return CELL_ZLOW; + } +}; + + +template +const int Mesh::getNpoints() { + switch(direction) { + case(DIRECTION::X): + return LocalNx; + case(DIRECTION::Y): + case(DIRECTION::YOrthogonal): + case(DIRECTION::YAligned): + return LocalNy; + case(DIRECTION::Z): + return LocalNz; + } +}; #endif // __MESH_H__ diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 9ad3fdd640..a75fe45b84 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -358,163 +358,11 @@ void Mesh::derivs_init(Options *options) { options->getSection("ddz")->get("fft_filter", fft_derivs_filter, 0.0); } -/******************************************************************************* - * Helper routines - *******************************************************************************/ - -const STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) { - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == allowedStaggerLoc) || - (outloc == allowedStaggerLoc && inloc == CELL_CENTRE)); - - if ( (!StaggerGrids) || outloc == inloc) return STAGGER::None; - if (outloc == allowedStaggerLoc) { - return STAGGER::C2L; - } else { - return STAGGER::L2C; - } -} - -const STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) { - ASSERT1(vloc == inloc); - return getStagger(inloc, outloc, allowedStaggerLoc); -} - -template -const CELL_LOC Mesh::getAllowedStaggerLoc() { - switch(direction) { - case(DIRECTION::X): - return CELL_XLOW; - case(DIRECTION::Y): - case(DIRECTION::YOrthogonal): - case(DIRECTION::YAligned): - return CELL_YLOW; - case(DIRECTION::Z): - return CELL_ZLOW; - } -}; - - -template -const int Mesh::getNpoints() { - switch(direction) { - case(DIRECTION::X): - return LocalNx; - case(DIRECTION::Y): - case(DIRECTION::YOrthogonal): - case(DIRECTION::YAligned): - return LocalNy; - case(DIRECTION::Z): - return LocalNz; - } -}; /******************************************************************************* * Actual derivative operators *******************************************************************************/ -template -const T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - // Checks - static_assert(std::is_base_of::value || std::is_base_of::value, - "indexDDX only works on Field2D or Field3D input"); - // Check that the mesh is correct - ASSERT1(this == f.getMesh()); - // Check that the input variable has data - ASSERT1(f.isAllocated()); - - // Define properties of this approach - const CELL_LOC allowedStaggerLoc = getAllowedStaggerLoc(); - - // Handle the staggering - const CELL_LOC inloc = f.getLocation(); // Input location - if (outloc == CELL_DEFAULT) - outloc = inloc; - const STAGGER stagger = getStagger(inloc, outloc, allowedStaggerLoc); - - // Check for early exit - const int nPoint = getNpoints(); - - if (nPoint == 1) { - auto tmp = T(0., this); - tmp.setLocation(outloc); - return tmp; - } - - // Lookup the method - auto derivativeStore = DerivativeStore{}.getInstance(); - typename DerivativeStore::standardFunc derivativeMethod; - - if (order == 1) { - derivativeMethod = derivativeStore.getStandardDerivative(DIFF_METHOD_STRING(method), direction, stagger); - } else if (order == 2) { - derivativeMethod = derivativeStore.getStandard2ndDerivative(DIFF_METHOD_STRING(method), direction, stagger); - } else if (order == 4) { - derivativeMethod = derivativeStore.getStandard4thDerivative(DIFF_METHOD_STRING(method), direction, stagger); - } else { - throw BoutException("Invalid order used in indexStandardDerivative."); - } - - // Create the result field - T result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - // Apply method - derivativeMethod(f, result, region); - - return result; -} - -////////////// X DERIVATIVE ///////////////// - -template -const T Mesh::indexDDX(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexStandardDerivative(f, outloc, method, region); -} - -template -const T Mesh::indexD2DX2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexStandardDerivative(f, outloc, method, region); -} - -template -const T Mesh::indexD4DX4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexStandardDerivative(f, outloc, method, region); -} - -////////////// Y DERIVATIVE ///////////////// - -template -const T Mesh::indexDDY(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexStandardDerivative(f, outloc, method, region); -} - -template -const T Mesh::indexD2DY2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexStandardDerivative(f, outloc, method, region); -} - -template -const T Mesh::indexD4DY4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexStandardDerivative(f, outloc, method, region); -} - -////////////// Z DERIVATIVE ///////////////// -template -const T Mesh::indexDDZ(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexStandardDerivative(f, outloc, method, region); -} - -template -const T Mesh::indexD2DZ2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexStandardDerivative(f, outloc, method, region); -} - -template -const T Mesh::indexD4DZ4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexStandardDerivative(f, outloc, method, region); -} - /******************************************************************************* * Advection schemes * @@ -526,92 +374,23 @@ const T Mesh::indexD4DZ4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION * Flux conserving schemes *******************************************************************************/ +/******************************************************************************* + * Helper routines + *******************************************************************************/ -template -const T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - // Checks - static_assert(std::is_base_of::value || std::is_base_of::value, - "indexDDX only works on Field2D or Field3D input"); - // Check that the mesh is correct - ASSERT1(this == f.getMesh()); - ASSERT1(this == v.getMesh()); - // Check that the input variable has data - ASSERT1(f.isAllocated()); - ASSERT1(v.isAllocated()); - - // Define properties of this approach - const CELL_LOC allowedStaggerLoc = getAllowedStaggerLoc(); - - // Handle the staggering - const CELL_LOC inloc = f.getLocation(); // Input locations - const CELL_LOC vloc = vel.getLocation(); - if (outloc == CELL_DEFAULT) - outloc = inloc; - const STAGGER stagger = getStagger(vloc, inloc, outloc, allowedStaggerLoc); - - // Check for early exit - const int nPoint = getNpoints(); - - if (nPoint == 1) { - auto tmp = T(0., this); - tmp.setLocation(outloc); - return tmp; - } - - // Lookup the method - auto derivativeStore = DerivativeStore{}.getInstance(); - typename DerivativeStore::upwindFunc derivativeMethod; - if (derivType == DERIV::Upwind) { - derivativeMethod = derivativeStore.getUpwindDerivative(DIFF_METHOD_STRING(method), direction, stagger); - } else if (derivType == DERIV::Flux) { - derivativeMethod = derivativeStore.getFluxDerivative(DIFF_METHOD_STRING(method), direction, stagger); +const STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) { + ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == allowedStaggerLoc) || + (outloc == allowedStaggerLoc && inloc == CELL_CENTRE)); + + if ( (!StaggerGrids) || outloc == inloc) return STAGGER::None; + if (outloc == allowedStaggerLoc) { + return STAGGER::C2L; } else { - throw BoutException("Invalid derivative type in call to indexFlowDerivative."); + return STAGGER::L2C; } - - // Create the result field - T result(this); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - // Apply method - derivativeMethod(vel, f, result, region); - - return result; } -////////////// X DERIVATIVE ///////////////// - -template -const T Mesh::indexVDDX(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexFlowDerivative(vel, f, outloc, method, region); -} - -template -const T Mesh::indexFDDX(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexFlowDerivative(vel, f, outloc, method, region); -} - -////////////// Y DERIVATIVE ///////////////// - -template -const T Mesh::indexVDDY(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexFlowDerivative(vel, f, outloc, method, region); -} - -template -const T Mesh::indexFDDY(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexFlowDerivative(vel, f, outloc, method, region); -} - -////////////// Z DERIVATIVE ///////////////// - -template -const T Mesh::indexVDDZ(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexFlowDerivative(vel, f, outloc, method, region); -} - -template -const T Mesh::indexFDDZ(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { - return indexFlowDerivative(vel, f, outloc, method, region); +const STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) { + ASSERT1(vloc == inloc); + return getStagger(inloc, outloc, allowedStaggerLoc); } From 115f86750f9b4b4c2f68b782aef24e0f38ccc49a Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 29 Oct 2018 17:54:08 +0000 Subject: [PATCH 0168/1783] Add keyword arguments to BoundaryFactory Parses arguments with "key=value" form as keywords, so dirichlet(1, width=3) passes into `clone` a list of arguments ["1"] and a map of keywords {"width":"3"}. This is not particularly clever, so may go wrong in a variety of interesting ways. It should work for the simple cases we support. --- include/boundary_op.hxx | 6 +++++ include/parallel_boundary_op.hxx | 5 ++++ src/mesh/boundary_factory.cxx | 42 +++++++++++++++++++------------- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index 5a15fd21ff..2d5510ba6f 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -15,6 +15,7 @@ class BoundaryModifier; #include #include #include +#include using std::string; using std::list; @@ -56,6 +57,11 @@ public: virtual BoundaryOp* clone(BoundaryRegion *UNUSED(region), const list &UNUSED(args)) { return nullptr; } + + virtual BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map& UNUSED(keywords)) { + // If not implemented, call two-argument version + return clone(region, args); + } /// Apply a boundary condition on ddt(f) virtual void apply_ddt(Field2D &f) { diff --git a/include/parallel_boundary_op.hxx b/include/parallel_boundary_op.hxx index 3bd0be5c15..ba4729ea71 100644 --- a/include/parallel_boundary_op.hxx +++ b/include/parallel_boundary_op.hxx @@ -31,6 +31,11 @@ public: virtual BoundaryOpPar* clone(BoundaryRegionPar *UNUSED(region), const list &UNUSED(args)) {return nullptr; } virtual BoundaryOpPar* clone(BoundaryRegionPar *UNUSED(region), Field3D *UNUSED(f)) {return nullptr; } + virtual BoundaryOpPar* clone(BoundaryRegionPar *region, const list &args, const std::map& UNUSED(keywords)) { + // If not implemented, call two-argument version + return clone(region, args); + } + using BoundaryOpBase::apply; void apply(Field2D &UNUSED(f)) override { throw BoutException("Can't apply parallel boundary conditions to Field2D!"); diff --git a/src/mesh/boundary_factory.cxx b/src/mesh/boundary_factory.cxx index 86a617e2fd..bb2b5de2ee 100644 --- a/src/mesh/boundary_factory.cxx +++ b/src/mesh/boundary_factory.cxx @@ -5,6 +5,7 @@ #include #include +#include using std::list; using std::string; @@ -82,7 +83,7 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * // Search for a string of the form: modifier(operation) auto pos = name.find('('); - if(pos == string::npos) { + if (pos == string::npos) { // No more (opening) brackets. Should be a boundary operation // Need to strip whitespace @@ -123,10 +124,11 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * // NOTE: Commas could be part of sub-expressions, so // need to take account of brackets list arglist; + std::map keywords; int level = 0; int start = 0; - for(string::size_type i = 0;i::iterator it=arglist.begin(); it != arglist.end(); it++) { - // Trim each argument - (*it) = trim(*it); - } - */ + auto poseq = s.find('='); + if (poseq != string::npos) { + keywords[trim(s.substr(0,poseq))] = trim(s.substr(poseq+1)); + } else { + // No '=', so a positional argument + arglist.push_back(trim(s)); + } // Test if func is a modifier BoundaryModifier *mod = findBoundaryMod(func); @@ -178,14 +186,14 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * BoundaryOpPar *pop = findBoundaryOpPar(trim(func)); if (pop != nullptr) { // An operation with arguments - return pop->clone(static_cast(region), arglist); + return pop->clone(static_cast(region), arglist, keywords); } } else { // Perpendicular boundary BoundaryOp *op = findBoundaryOp(trim(func)); if (op != nullptr) { // An operation with arguments - return op->clone(static_cast(region), arglist); + return op->clone(static_cast(region), arglist, keywords); } } From f667ea6106860b058f13bd534db0386eef70f120 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 25 Oct 2018 13:30:05 +0100 Subject: [PATCH 0169/1783] Add multiple yup/ydown fields --- include/field3d.hxx | 48 +++++++++------ src/field/field3d.cxx | 97 +++++++++++++------------------ tests/unit/field/test_field3d.cxx | 28 ++++++++- 3 files changed, 100 insertions(+), 73 deletions(-) diff --git a/include/field3d.hxx b/include/field3d.hxx index e9f090bea6..3a774e2d48 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -40,6 +40,8 @@ class Mesh; // #include "bout/mesh.hxx" #include "bout/field_visitor.hxx" +#include + /// Class for 3D X-Y-Z scalar fields /*! This class represents a scalar field defined over the mesh. @@ -226,30 +228,42 @@ class Field3D : public Field, public FieldData { /// Check if this field has yup and ydown fields bool hasYupYdown() const { - return (yup_field != nullptr) && (ydown_field != nullptr); + return !yup_fields.empty() and !ydown_fields.empty(); } /// Return reference to yup field - Field3D& yup() { - ASSERT2(yup_field != nullptr); // Check for communicate - return *yup_field; + Field3D &yup(std::vector::size_type index = 0) { + if (yup_fields.empty()) { + return *this; + } + ASSERT2(index < yup_fields.size()); // Check for communicate + return yup_fields[index]; } /// Return const reference to yup field - const Field3D& yup() const { - ASSERT2(yup_field != nullptr); - return *yup_field; + const Field3D &yup(std::vector::size_type index = 0) const { + if (yup_fields.empty()) { + return *this; + } + ASSERT2(index < yup_fields.size()); + return yup_fields[index]; } - + /// Return reference to ydown field - Field3D& ydown() { - ASSERT2(ydown_field != nullptr); - return *ydown_field; + Field3D &ydown(std::vector::size_type index = 0) { + if (ydown_fields.empty()) { + return *this; + } + ASSERT2(index < ydown_fields.size()); + return ydown_fields[index]; } - + /// Return const reference to ydown field - const Field3D& ydown() const { - ASSERT2(ydown_field != nullptr); - return *ydown_field; + const Field3D &ydown(std::vector::size_type index = 0) const { + if (ydown_fields.empty()) { + return *this; + } + ASSERT2(index < ydown_fields.size()); + return ydown_fields[index]; } /// Return yup if dir=+1, and ydown if dir=-1 @@ -457,8 +471,8 @@ private: Field3D *deriv; ///< Time derivative (may be NULL) - /// Pointers to fields containing values along Y - Field3D *yup_field, *ydown_field; + /// Fields containing values along Y + std::vector yup_fields{}, ydown_fields{}; }; // Non-member overloaded operators diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 7d9dda7cea..519db35b08 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -45,8 +45,7 @@ /// Constructor Field3D::Field3D(Mesh *localmesh) - : Field(localmesh), background(nullptr), deriv(nullptr), yup_field(nullptr), - ydown_field(nullptr) { + : Field(localmesh), background(nullptr), deriv(nullptr) { #ifdef TRACK name = ""; #endif @@ -55,6 +54,9 @@ Field3D::Field3D(Mesh *localmesh) nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; + + yup_fields.reserve(fieldmesh->ystart); + ydown_fields.reserve(fieldmesh->ystart); } #if CHECK > 0 else { @@ -72,7 +74,7 @@ Field3D::Field3D(Mesh *localmesh) Field3D::Field3D(const Field3D &f) : Field(f.fieldmesh), // The mesh containing array sizes background(nullptr), data(f.data), // This handles references to the data array - deriv(nullptr), yup_field(nullptr), ydown_field(nullptr) { + deriv(nullptr) { TRACE("Field3D(Field3D&)"); @@ -84,6 +86,9 @@ Field3D::Field3D(const Field3D &f) nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; + + yup_fields.reserve(fieldmesh->ystart); + ydown_fields.reserve(fieldmesh->ystart); } #if CHECK > 0 else { @@ -95,13 +100,12 @@ Field3D::Field3D(const Field3D &f) location = f.location; fieldCoordinates = f.fieldCoordinates; - + boundaryIsSet = false; } Field3D::Field3D(const Field2D &f) - : Field(f.getMesh()), background(nullptr), deriv(nullptr), yup_field(nullptr), - ydown_field(nullptr) { + : Field(f.getMesh()), background(nullptr), deriv(nullptr) { TRACE("Field3D: Copy constructor from Field2D"); @@ -118,8 +122,7 @@ Field3D::Field3D(const Field2D &f) } Field3D::Field3D(const BoutReal val, Mesh *localmesh) - : Field(localmesh), background(nullptr), deriv(nullptr), yup_field(nullptr), - ydown_field(nullptr) { + : Field(localmesh), background(nullptr), deriv(nullptr) { TRACE("Field3D: Copy constructor from value"); @@ -135,23 +138,8 @@ Field3D::Field3D(const BoutReal val, Mesh *localmesh) Field3D::~Field3D() { /// Delete the time derivative variable if allocated if (deriv != nullptr) { - // The ddt of the yup/ydown_fields point to the same place as ddt.yup_field - // only delete once - // Also need to check that separate yup_field exists - if ((yup_field != this) && (yup_field != nullptr)) - yup_field->deriv = nullptr; - if ((ydown_field != this) && (ydown_field != nullptr)) - ydown_field->deriv = nullptr; - - // Now delete them as part of the deriv vector delete deriv; } - - if((yup_field != this) && (yup_field != nullptr)) - delete yup_field; - - if((ydown_field != this) && (ydown_field != nullptr)) - delete ydown_field; } void Field3D::allocate() { @@ -181,54 +169,53 @@ Field3D* Field3D::timeDeriv() { void Field3D::splitYupYdown() { TRACE("Field3D::splitYupYdown"); - if((yup_field != this) && (yup_field != nullptr)) + if (!yup_fields.empty()) { return; + } - // yup_field and ydown_field null - yup_field = new Field3D(fieldmesh); - ydown_field = new Field3D(fieldmesh); + for (int i = 0; i < fieldmesh->ystart; ++i) { + yup_fields.emplace_back(fieldmesh); + ydown_fields.emplace_back(fieldmesh); + } } void Field3D::mergeYupYdown() { TRACE("Field3D::mergeYupYdown"); - - if(yup_field == this && ydown_field == this) - return; - if(yup_field != nullptr){ - delete yup_field; - } - - if(ydown_field != nullptr) { - delete ydown_field; + if (yup_fields.empty() && ydown_fields.empty()) { + return; } - yup_field = this; - ydown_field = this; + yup_fields.clear(); + ydown_fields.clear(); } -Field3D& Field3D::ynext(int dir) { - switch(dir) { - case +1: - return yup(); - case -1: - return ydown(); - default: - throw BoutException("Field3D: Call to ynext with strange direction %d. Only +/-1 currently supported", dir); +const Field3D& Field3D::ynext(int dir) const { + // Asked for more than yguards + if (std::abs(dir) > fieldmesh->ystart) { + throw BoutException( + "Field3D: Call to ynext with %d which is more than number of yguards (%d)", dir, + fieldmesh->ystart); } -} -const Field3D& Field3D::ynext(int dir) const { - switch(dir) { - case +1: - return yup(); - case -1: - return ydown(); - default: - throw BoutException("Field3D: Call to ynext with strange direction %d. Only +/-1 currently supported", dir); + // ynext uses 1-indexing, but yup wants 0-indexing + if (dir > 0) { + return yup(dir - 1); + } else if (dir < 0) { + return ydown(std::abs(dir) - 1); + } else { + return *this; } } +Field3D &Field3D::ynext(int dir) { + // Call the `const` version: need to add `const` to `this` to call + // it, then throw it away after. This is ok because `this` wasn't + // `const` to begin with. + // See Effective C++, Scott Meyers, p23, for a better explanation + return const_cast(static_cast(*this).ynext(dir)); +} + void Field3D::setLocation(CELL_LOC new_location) { if (getMesh()->StaggerGrids) { if (new_location == CELL_VSHIFT) { diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 649a3abb1b..775a383621 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -243,7 +243,7 @@ TEST_F(Field3DTest, MergeYupYDown) { field.mergeYupYdown(); - EXPECT_TRUE(field.hasYupYdown()); + EXPECT_FALSE(field.hasYupYdown()); auto& yup = field.yup(); EXPECT_EQ(&field, &yup); @@ -278,6 +278,32 @@ TEST_F(Field3DTest, SplitThenMergeYupYDown) { EXPECT_EQ(&field, &ydown2); } +TEST_F(Field3DTest, MultipleYupYdown) { + FakeMesh newmesh{3, 5, 7}; + newmesh.ystart = 2; + + Field3D field{&newmesh}; + + field.splitYupYdown(); + + EXPECT_TRUE(field.hasYupYdown()); + + auto &yup = field.yup(); + EXPECT_NE(&field, &yup); + auto &ydown = field.ydown(); + EXPECT_NE(&field, &ydown); + auto &yup1 = field.yup(1); + EXPECT_NE(&field, &yup1); + EXPECT_NE(&yup, &yup1); + auto &ydown1 = field.ydown(1); + EXPECT_NE(&field, &ydown1); + EXPECT_NE(&ydown, &ydown1); + +#if CHECK > 1 + EXPECT_THROW(field.yup(2), BoutException); +#endif +} + TEST_F(Field3DTest, Ynext) { Field3D field; From e65e8f080369d1cb5dda585da067d6fc72e8cab8 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 29 Oct 2018 21:37:05 +0000 Subject: [PATCH 0170/1783] Bug fix for populateStencil --- include/stencils.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/stencils.hxx b/include/stencils.hxx index 6d98563e35..5f66ff82e8 100644 --- a/include/stencils.hxx +++ b/include/stencils.hxx @@ -100,7 +100,7 @@ void inline populateStencil(stencil &s, const FieldType& f, const typename Field template stencil inline populateStencil(const FieldType& f, const typename FieldType::ind_type i){ stencil s; - populateStencil(s, f, i); + populateStencil(s, f, i); return s; } #endif /* __STENCILS_H__ */ From 0400dfb4f613f0c884f8ed43611522cb9d345b49 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 29 Oct 2018 21:37:25 +0000 Subject: [PATCH 0171/1783] Add routine that provide number of guard cells --- include/bout/mesh.hxx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 0257fe13b0..b833f9d379 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -661,6 +661,9 @@ class Mesh { template const int getNpoints(); + + template + const int getNguard(); private: /// Allocates default Coordinates objects @@ -905,5 +908,19 @@ const int Mesh::getNpoints() { } }; +template +const int Mesh::getNguard() { + switch(direction) { + case(DIRECTION::X): + return xstart; + case(DIRECTION::Y): + case(DIRECTION::YOrthogonal): + case(DIRECTION::YAligned): + return ystart; + case(DIRECTION::Z): + return 2; + } +}; + #endif // __MESH_H__ From eed79876f6711b981e4ca5e63f3a9e0fb4407f49 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 29 Oct 2018 21:37:46 +0000 Subject: [PATCH 0172/1783] Removed unused derivative code --- src/mesh/index_derivs.cxx | 215 -------------------------------------- 1 file changed, 215 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index a75fe45b84..c57dfe03ad 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -114,27 +114,6 @@ BoutReal DDX_KT(const stencil &f, const stencil &u, const BoutReal Vmax) { return Fm - Fp; } -/******************************************************************************* - * Lookup tables of functions. Map between names, codes and functions - *******************************************************************************/ - -/// Translate between DIFF_METHOD codes, and functions -struct DiffLookup { - DIFF_METHOD method; - Mesh::deriv_func func; // Single-argument differencing function - Mesh::upwind_func up_func; // Upwinding function - Mesh::flux_func fl_func; // Flux function - operator Mesh::deriv_func (){ - return func; - } - operator Mesh::upwind_func (){ - return up_func; - } - operator Mesh::flux_func (){ - return fl_func; - } -}; - /// Translate between short names, long names and DIFF_METHOD codes struct DiffNameLookup { DIFF_METHOD method; @@ -157,203 +136,9 @@ static DiffNameLookup DiffNameTable[] = { {DIFF_SPLIT, "SPLIT", "Split into upwind and central"}, {DIFF_DEFAULT, nullptr, nullptr}}; // Use to terminate the list -/// First derivative lookup table -static DiffLookup FirstDerivTable[] = {}; - -/// Second derivative lookup table -static DiffLookup SecondDerivTable[] = {}; - -/// Upwinding functions lookup table -static DiffLookup UpwindTable[] = {}; - -/// Flux functions lookup table -static DiffLookup FluxTable[] = {}; - -/// First staggered derivative lookup -static DiffLookup FirstStagDerivTable[] = {}; - -/// Second staggered derivative lookup -static DiffLookup SecondStagDerivTable[] = {}; - -/// Upwinding staggered lookup -static DiffLookup UpwindStagTable[] = {}; - -/// Flux staggered lookup -static DiffLookup FluxStagTable[] = {}; - -/******************************************************************************* - * Routines to use the above tables to map between function codes, names - * and pointers - *******************************************************************************/ - - -/// Test if a given DIFF_METHOD exists in a table -bool isImplemented(DiffLookup *table, DIFF_METHOD method) { - int i = 0; - do { - if (table[i].method == method) - return true; - i++; - } while (table[i].method != DIFF_DEFAULT); - - return false; -} - - -DiffLookup lookupFunc(DiffLookup * table, DIFF_METHOD method) { - for (int i=0; ; ++i){ - if (table[i].method == method) { - return table[i]; - } - if (table[i].method == DIFF_DEFAULT){ - return table[i]; - } - } -} - -void printFuncName(DIFF_METHOD method) { - // Find this entry - int i = 0; - do { - if (DiffNameTable[i].method == method) { - output_info.write(" %s (%s)\n", DiffNameTable[i].name, DiffNameTable[i].label); - return; - } - i++; - } while (DiffNameTable[i].method != DIFF_DEFAULT); - - // None - output_error.write(" == INVALID DIFFERENTIAL METHOD ==\n"); -} - -/// This function is used during initialisation only (i.e. doesn't need to be particularly -/// fast) Returns DIFF_METHOD, rather than function so can be applied to central and -/// upwind tables -DiffLookup lookupFunc(DiffLookup *table, const std::string & label){ - - // Loop through the name lookup table - for (int i = 0; DiffNameTable[i].method != DIFF_DEFAULT; ++i) { - if (strcasecmp(label.c_str(), DiffNameTable[i].label) == 0) { // Whole match - auto method=DiffNameTable[i].method; - if (isImplemented(table, method)) { - printFuncName(method); - for (int j=0;;++j){ - if (table[j].method == method){ - return table[j]; - } - } - } - } - } - - // No exact match, so throw - std::string avail{}; - for (int i = 0; DiffNameTable[i].method != DIFF_DEFAULT; ++i) { - avail += DiffNameTable[i].label; - avail += "\n"; - } - throw BoutException("Unknown option %s.\nAvailable options are:\n%s", label.c_str(), - avail.c_str()); -} - - -/******************************************************************************* - * Default functions - * - * - *******************************************************************************/ - -// Central -> Central (or Left -> Left) functions -Mesh::deriv_func fDDX, fDDY, fDDZ; ///< Differencing methods for each dimension -Mesh::deriv_func fD2DX2, fD2DY2, fD2DZ2; ///< second differential operators -Mesh::upwind_func fVDDX, fVDDY, fVDDZ; ///< Upwind functions in the three directions -Mesh::flux_func fFDDX, fFDDY, fFDDZ; ///< Default flux functions - -// Central -> Left (or Left -> Central) functions -Mesh::deriv_func sfDDX, sfDDY, sfDDZ; -Mesh::deriv_func sfD2DX2, sfD2DY2, sfD2DZ2; -Mesh::flux_func sfVDDX, sfVDDY, sfVDDZ; -Mesh::flux_func sfFDDX, sfFDDY, sfFDDZ; - -/******************************************************************************* - * Initialisation - *******************************************************************************/ - -/// Set the derivative method, given a table and option name -template -void derivs_set(std::vector options, DiffLookup *table, DiffLookup *stable, - const std::string &name, const std::string &def, T &f, Ts &sf, - bool staggerGrids) { - TRACE("derivs_set()"); - output_info.write("\t%-12s: ", name.c_str()); - string label = def; - for (auto &opts : options) { - if (opts->isSet(name)) { - opts->get(name, label, ""); - break; - } - } - - f = lookupFunc(table, label); // Find the function - - label = def; - if (staggerGrids) { - output_info.write("\tStag. %-6s: ", name.c_str()); - for (auto &_name : {name + "stag", name}) { - for (auto &opts : options) { - if (opts->isSet(_name)) { - opts->get(_name, label, ""); - sf = lookupFunc(stable, label); // Find the function - return; - } - } - } - } - sf = lookupFunc(stable, label); // Find the function -} - -/// Initialise derivatives from options -void derivs_initialise(Options *optionbase, std::string sec, bool staggerGrids, - Mesh::deriv_func &fdd, Mesh::deriv_func &sfdd, - Mesh::deriv_func &fd2d, Mesh::deriv_func &sfd2d, - Mesh::upwind_func &fu, Mesh::flux_func &sfu, Mesh::flux_func &ff, - Mesh::flux_func &sff) { - std::vector options = {optionbase->getSection(sec), - optionbase->getSection("diff")}; - derivs_set(options, FirstDerivTable, FirstStagDerivTable, "First", "C2", fdd, sfdd, - staggerGrids); - - derivs_set(options, SecondDerivTable, SecondStagDerivTable, "Second", "C2", fd2d, sfd2d, - staggerGrids); - - derivs_set(options, UpwindTable, UpwindStagTable, "Upwind", "U1", fu, sfu, - staggerGrids); - - derivs_set(options, FluxTable, FluxStagTable, "Flux", "U1", ff, sff, staggerGrids); -} - /// Initialise the derivative methods. Must be called before any derivatives are used void Mesh::derivs_init(Options *options) { TRACE("Initialising derivatives"); - - output_info.write("Setting X differencing methods\n"); - derivs_initialise(options, "ddx", StaggerGrids, fDDX, sfDDX, fD2DX2, sfD2DX2, fVDDX, - sfVDDX, fFDDX, sfFDDX); - - if ((fDDX == nullptr) || (fD2DX2 == nullptr)) - throw BoutException("FFT cannot be used in X\n"); - - output_info.write("Setting Y differencing methods\n"); - derivs_initialise(options, "ddy", StaggerGrids, fDDY, sfDDY, fD2DY2, sfD2DY2, fVDDY, - sfVDDY, fFDDY, sfFDDY); - - if ((fDDY == nullptr) || (fD2DY2 == nullptr)) - throw BoutException("FFT cannot be used in Y\n"); - - output_info.write("Setting Z differencing methods\n"); - derivs_initialise(options, "ddz", StaggerGrids, fDDZ, sfDDZ, fD2DZ2, sfD2DZ2, fVDDZ, - sfVDDZ, fFDDZ, sfFDDZ); - // Get the fraction of modes filtered out in FFT derivatives options->getSection("ddz")->get("fft_filter", fft_derivs_filter, 0.0); } From 29c148cc1ce8e1e748fcd9e4e8640eeada1cf19f Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 29 Oct 2018 22:02:37 +0000 Subject: [PATCH 0173/1783] Make derivatives actually do something --- include/bout/derivs.hxx | 49 ++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index f22f492c75..6142d28814 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -42,12 +43,12 @@ public: // and storing in result -- in this test case we don't have REGION etc. so // we comment this out for now. // - // ASSERT2(meta.derivType is one of Standard, StandardSecond and StandardFourth) - // ASSERT2(var.getMesh().getNguard() >= meta.nGuard); - // - // BOUT_FOR(i, var.getRegion(region)) { - // result[i] = apply(populateStencil(var, i)); - // } + ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond || meta.derivType == DERIV::StandardFourth) + ASSERT2(var.getMesh().getNguard() >= meta.nGuard); + + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(var, i)); + } //std::cout<() >= meta.nGuard); - // - // if Stagger isn't none or derivType is flux { - // BOUT_FOR(i, var.getRegion(region)) { - // result[i] = apply(populateStencil(vel, i), - // populateStencil(var, i) - // ); - // else it's a non-staggered upwind so do - // BOUT_FOR(i, var.getRegion(region)) { - // result[i] = apply(vel[i], - // populateStencil(var, i) - // ); - // } + ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) + ASSERT2(var.getMesh().getNguard() >= meta.nGuard); + + if (meta.derivType == DERIV::Flux || stagger != STAGGER::None) { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(vel, i), + populateStencil(var, i) + ); + } + } else { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(vel[i], + populateStencil(var, i) + ); + } + } //std::cout< Date: Mon, 29 Oct 2018 22:27:46 +0000 Subject: [PATCH 0174/1783] Small bug fixes --- include/bout/derivs.hxx | 4 ++-- include/bout/mesh.hxx | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index 6142d28814..e270456e37 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -44,7 +44,7 @@ public: // we comment this out for now. // ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond || meta.derivType == DERIV::StandardFourth) - ASSERT2(var.getMesh().getNguard() >= meta.nGuard); + ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); BOUT_FOR(i, var.getRegion(region)) { result[i] = apply(populateStencil(var, i)); @@ -63,7 +63,7 @@ public: // we comment this out for now. // ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) - ASSERT2(var.getMesh().getNguard() >= meta.nGuard); + ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); if (meta.derivType == DERIV::Flux || stagger != STAGGER::None) { BOUT_FOR(i, var.getRegion(region)) { diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index b833f9d379..b9df3fe0f2 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -527,6 +527,9 @@ class Mesh { const T indexFDDZ(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); + template + const int getNguard(); + /// Derivative functions of a single field stencil typedef BoutReal (*deriv_func)(const stencil &); /// Derivative functions of a BoutReal velocity, and field stencil @@ -661,9 +664,6 @@ class Mesh { template const int getNpoints(); - - template - const int getNguard(); private: /// Allocates default Coordinates objects @@ -775,10 +775,10 @@ const T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIF "indexDDX only works on Field2D or Field3D input"); // Check that the mesh is correct ASSERT1(this == f.getMesh()); - ASSERT1(this == v.getMesh()); + ASSERT1(this == vel.getMesh()); // Check that the input variable has data ASSERT1(f.isAllocated()); - ASSERT1(v.isAllocated()); + ASSERT1(vel.isAllocated()); // Define properties of this approach const CELL_LOC allowedStaggerLoc = getAllowedStaggerLoc(); From 97ebc077b341b5d7d2062e459b194e322776cdca Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 29 Oct 2018 22:56:34 +0000 Subject: [PATCH 0175/1783] Small clarification of option type --- manual/sphinx/user_docs/bout_options.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index e904db1371..af50220ea5 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -105,7 +105,7 @@ use the ``round`` function: ok_integer = round(256.4) Note that it is still possible to read ``bad_integer`` as a real -number though. +number, since the type is determined by how it is used. Have a look through the examples to see how the options are used. From 28efdbb9523b0d264a07b7ab9f0e0e80d2ff6a6c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 30 Oct 2018 09:02:03 +0000 Subject: [PATCH 0176/1783] Re-use use_yup_ydown bool in FV::Div_par_K_Grad_par() --- src/mesh/fv_ops.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index e1e4fe3437..698460c1ff 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -169,7 +169,7 @@ namespace FV { } } - if (!(Kin.hasYupYdown() && fin.hasYupYdown())) { + if (!use_yup_ydown) { // Shifted to field aligned coordinates, so need to shift back result = mesh->fromFieldAligned(result); } From efee28d6d1b016979780d00b45281cacf4641082 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 30 Oct 2018 16:09:23 +0000 Subject: [PATCH 0177/1783] Generate backtrace when exception is thrown rather than caught --- include/boutexception.hxx | 7 ++++++- src/sys/boutexception.cxx | 9 +++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/boutexception.hxx b/include/boutexception.hxx index 029bc4d19a..109beada9f 100644 --- a/include/boutexception.hxx +++ b/include/boutexception.hxx @@ -17,7 +17,9 @@ void BoutParallelThrowRhsFail(int status, const char* message); class BoutException : public std::exception { public: BoutException(const char *, ...); - BoutException(std::string msg) : message(std::move(msg)) {} + BoutException(std::string msg) : message(std::move(msg)) { + backtrace_message = makeBacktrace(); + } ~BoutException() override; const char* what() const noexcept override { @@ -29,6 +31,8 @@ public: /// backtrace (if available) std::string getBacktrace() const; + std::string makeBacktrace() const; + const std::string header{"====== Exception thrown ======\n"}; protected: @@ -39,6 +43,7 @@ protected: #ifdef BACKTRACE static constexpr unsigned int TRACE_MAX = 128; #endif + std::string backtrace_message{}; }; class BoutRhsFail : public BoutException { diff --git a/src/sys/boutexception.cxx b/src/sys/boutexception.cxx index 280a250c01..a29f385393 100644 --- a/src/sys/boutexception.cxx +++ b/src/sys/boutexception.cxx @@ -33,7 +33,11 @@ BoutException::~BoutException() { msg_stack.clear(); } -std::string BoutException::getBacktrace() const{ +std::string BoutException::getBacktrace() const { + return header + message + "\n" + msg_stack.getDump() + backtrace_message; +} + +std::string BoutException::makeBacktrace() const { std::string backtrace_message; #ifdef BACKTRACE @@ -89,7 +93,7 @@ std::string BoutException::getBacktrace() const{ #else backtrace_message = "Stacktrace not enabled.\n"; #endif - return header + message + "\n" + msg_stack.getDump() + backtrace_message; + return backtrace_message; } /// Common set up for exceptions @@ -117,6 +121,7 @@ std::string BoutException::getBacktrace() const{ delete[] buffer; \ buffer = nullptr; \ } \ + backtrace_message = makeBacktrace(); \ } BoutException::BoutException(const char *s, ...) { INIT_EXCEPTION(s); } From ceb34bfe399960211b80011aaea18c6d613b81cb Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 30 Oct 2018 16:09:54 +0000 Subject: [PATCH 0178/1783] Reverse order of backtrace messages Puts exception message at bottom and reverses order of backtrace messages so inner most frame is at bottom --- src/sys/boutexception.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sys/boutexception.cxx b/src/sys/boutexception.cxx index a29f385393..bb21e59d79 100644 --- a/src/sys/boutexception.cxx +++ b/src/sys/boutexception.cxx @@ -34,7 +34,7 @@ BoutException::~BoutException() { } std::string BoutException::getBacktrace() const { - return header + message + "\n" + msg_stack.getDump() + backtrace_message; + return backtrace_message + msg_stack.getDump() + "\n" + header + message + "\n"; } std::string BoutException::makeBacktrace() const { @@ -48,8 +48,8 @@ std::string BoutException::makeBacktrace() const { backtrace_message = "====== Exception path ======\n"; char buf[1024]; // skip first stack frame (points here) - for (int i = 1; i < trace_size; ++i) { - snprintf(buf, sizeof(buf) - 1, "[bt] #%d %s\n", i, messages[i]); + for (int i = trace_size - 1; i > 1; --i) { + snprintf(buf, sizeof(buf) - 1, "[bt] #%d %s\n", i - 1, messages[i]); backtrace_message += buf; // find first occurence of '(' or ' ' in message[i] and assume // everything before that is the file name. (Don't go beyond 0 though From 389dc37e9b4ffb4ed1c58d5e6c82702dbaa7f147 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 31 Oct 2018 00:08:37 +0000 Subject: [PATCH 0179/1783] Add unit test, fix bug in old code Unit test of BoundaryFactory registers a dummy boundary operation, then uses this to test different combinations of positional arguments and keywords. Fixed long-standing bug in boundary factory, where this was intended to slice from start to i, but actually produced a string of length i. string s = arg.substr(start, i); --- include/boundary_op.hxx | 15 +++- src/mesh/boundary_factory.cxx | 16 ++-- tests/unit/mesh/test_boundary_factory.cxx | 92 +++++++++++++++++++++++ 3 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 tests/unit/mesh/test_boundary_factory.cxx diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index 2d5510ba6f..ce232163e1 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -55,11 +55,18 @@ public: // Note: All methods must implement clone, except for modifiers (see below) virtual BoundaryOp* clone(BoundaryRegion *UNUSED(region), const list &UNUSED(args)) { - return nullptr; + throw BoutException("BoundaryOp::clone not implemented"); } - - virtual BoundaryOp* clone(BoundaryRegion *region, const list &args, const std::map& UNUSED(keywords)) { - // If not implemented, call two-argument version + + /// Clone using positional args and keywords + /// If not implemented, check if keywords are passed, then call two-argument version + virtual BoundaryOp *clone(BoundaryRegion *region, const list &args, + const std::map &keywords) { + if (!keywords.empty()) { + // Given keywords, but not using + throw BoutException("Keywords ignored in boundary : %s", keywords.begin()->first.c_str()); + } + return clone(region, args); } diff --git a/src/mesh/boundary_factory.cxx b/src/mesh/boundary_factory.cxx index bb2b5de2ee..4824561320 100644 --- a/src/mesh/boundary_factory.cxx +++ b/src/mesh/boundary_factory.cxx @@ -96,18 +96,20 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * if (pop == nullptr) throw BoutException("Could not find parallel boundary condition '%s'", name.c_str()); - // Clone the boundary operation, passing the region to operate over and an empty args list + // Clone the boundary operation, passing the region to operate over, + // an empty args list and empty keyword map list args; - return pop->clone(static_cast(region), args); + return pop->clone(static_cast(region), args, {}); } else { // Perpendicular boundary BoundaryOp *op = findBoundaryOp(trim(name)); if (op == nullptr) throw BoutException("Could not find boundary condition '%s'", name.c_str()); - // Clone the boundary operation, passing the region to operate over and an empty args list + // Clone the boundary operation, passing the region to operate over, + // an empty args list and empty keyword map list args; - return op->clone(static_cast(region), args); + return op->clone(static_cast(region), args, {}); } } // Contains a bracket. Find the last bracket and remove @@ -141,12 +143,12 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * break; case ',': { if (level == 0) { - string s = arg.substr(start, i); + string s = arg.substr(start, i-start); // Check if s contains '=', and if so treat as a keyword auto poseq = s.find('='); if (poseq != string::npos) { - keywords[trim(s.substr(0, poseq))] = s.substr(poseq + 1); + keywords[trim(s.substr(0, poseq))] = trim(s.substr(poseq + 1)); } else { // No '=', so a positional argument arglist.push_back(trim(s)); @@ -157,7 +159,7 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * } }; } - string s = arg.substr(start, arg.length()); + string s = arg.substr(start); auto poseq = s.find('='); if (poseq != string::npos) { keywords[trim(s.substr(0,poseq))] = trim(s.substr(poseq+1)); diff --git a/tests/unit/mesh/test_boundary_factory.cxx b/tests/unit/mesh/test_boundary_factory.cxx new file mode 100644 index 0000000000..850eadd2f4 --- /dev/null +++ b/tests/unit/mesh/test_boundary_factory.cxx @@ -0,0 +1,92 @@ +#include "gtest/gtest.h" + +#include "boundary_factory.hxx" +#include "boundary_region.hxx" + +#include "test_extras.hxx" + +/// Global mesh +extern Mesh *mesh; + +class TestBoundary : public BoundaryOp { +public: + BoundaryOp *clone(BoundaryRegion *UNUSED(region), const std::list &args, + const std::map &keywords) override { + auto *testboundary = new TestBoundary(); + testboundary->args = args; + testboundary->keywords = keywords; + return testboundary; + } + std::list args; + std::map keywords; + + void apply(Field2D &UNUSED(f)) override {} + void apply(Field3D &UNUSED(f)) override {} +}; + +TEST(BoundaryFactoryTests, IsSingleton) { + BoundaryFactory* fac1 = BoundaryFactory::getInstance(); + BoundaryFactory* fac2 = BoundaryFactory::getInstance(); + + EXPECT_EQ(fac1, fac2); +} + +TEST(BoundaryFactoryTests, CreateTestBoundary) { + mesh = new FakeMesh(3, 3, 3); + + BoundaryFactory* fac = BoundaryFactory::getInstance(); + fac->add(new TestBoundary(), "testboundary"); + + BoundaryRegionXIn region("test_region", 0, 1, mesh); + + // Check no brackets + + auto *boundary = fac->create("testboundary", ®ion); + + EXPECT_TRUE( boundary != nullptr ); + + EXPECT_EQ(typeid(*boundary), typeid(TestBoundary)); + + delete boundary; + + // Positional arguments + + boundary = fac->create("testboundary(a, 1)", ®ion); + EXPECT_TRUE( boundary != nullptr ); + + TestBoundary *tb = dynamic_cast(boundary); + + EXPECT_EQ( tb->args.size(), 2 ); + EXPECT_EQ( tb->args.front(), "a" ); + EXPECT_EQ( tb->args.back(), "1" ); + EXPECT_TRUE( tb->keywords.empty() ); + + delete boundary; + + // Test keywords + boundary = fac->create("testboundary(key=1, b=value)", ®ion); + EXPECT_TRUE( boundary != nullptr ); + + tb = dynamic_cast(boundary); + + EXPECT_TRUE( tb->args.empty() ); + EXPECT_EQ( tb->keywords.size(), 2 ); + EXPECT_EQ( tb->keywords.at("key"), "1" ); + EXPECT_EQ( tb->keywords.at("b"), "value" ); + + delete boundary; + + // Mix of positional args and keywords + boundary = fac->create("testboundary(0.23, key =1+2 , something(),b=value ,a + sin(1.2))", ®ion); + EXPECT_TRUE( boundary != nullptr ); + + tb = dynamic_cast(boundary); + + std::list args_expected = {"0.23", "something()", "a + sin(1.2)"}; + + EXPECT_EQ( tb->args, args_expected ); + + EXPECT_EQ( tb->keywords.size(), 2 ); + EXPECT_EQ( tb->keywords.at("key"), "1+2" ); + EXPECT_EQ( tb->keywords.at("b"), "value" ); +} From 6a96da50500b54676b2290346cb31f66312e4fcb Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 31 Oct 2018 20:47:54 +0000 Subject: [PATCH 0180/1783] Add some throws and make naming more consistent --- include/bout/deriv_store.hxx | 25 ++++++++++++++++--------- include/bout/derivs.hxx | 20 +++----------------- include/bout_types.hxx | 6 +++++- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 2464d5b6a1..02ff616c66 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -5,6 +5,7 @@ #include #include +#include /// Here we have a templated singleton that is used to store DerivativeFunctions /// for all types of derivatives. It is templated on the FieldType (2D or 3D) as @@ -43,8 +44,8 @@ struct DerivativeStore{ case(DERIV::StandardFourth) : getInstance().standardFourth[key] = func; return; - // default: - //throw BoutException("Invalid function signature for DerivativeMethod : ..."); + default: + throw BoutException("Invalid function signature in registerDerivative : Function signature 'standard' but derivative type %s passed",DERIV_STRING(derivType)); }; return; }; @@ -60,8 +61,8 @@ struct DerivativeStore{ case(DERIV::Flux) : getInstance().flux[key] = func; return; - // default: - //throw BoutException("Invalid function signature for DerivativeMethod : ..."); + default: + throw BoutException("Invalid function signature in registerDerivative : Function signature 'upwind/flux' but derivative type %s passed",DERIV_STRING(derivType)); }; return; }; @@ -76,6 +77,10 @@ struct DerivativeStore{ registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), Stagger{}.lookup(), Method{}.meta.key); }; + std::string getMethodName(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { + return name + " ("+DIRECTION_STRING(direction)+", "+STAGGER_STRING(stagger)+")"; + }; + /// Routines to return a specific differential operator. Note we have to have a separate routine for different /// methods as they have different return types. As such we choose to use a different name for each of the /// method-classes so everything is consistently treated @@ -84,35 +89,37 @@ struct DerivativeStore{ const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.standard.find(key); if(resultOfFind != instance.standard.end()) return resultOfFind->second; - //throw BoutException("Couldn't find requested method ...."); + throw BoutException("Couldn't find requested method %s in map for standard derivative.", getMethodName(name, direction, stagger)); }; + standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.standardSecond.find(key); if(resultOfFind != instance.standardSecond.end()) return resultOfFind->second; - //throw BoutException("Couldn't find requested method ...."); + throw BoutException("Couldn't find requested method %s in map for standardSecond derivative.", getMethodName(name, direction, stagger)); }; + standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.standardFourth.find(key); if(resultOfFind != instance.standardFourth.end()) return resultOfFind->second; - //throw BoutException("Couldn't find requested method ...."); + throw BoutException("Couldn't find requested method %s in map for standardFourth derivative.", getMethodName(name, direction, stagger)); }; upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.upwind.find(key); if(resultOfFind != instance.upwind.end()) return resultOfFind->second; - //throw BoutException("Couldn't find requested method ...."); + throw BoutException("Couldn't find requested method %s in map for upwind derivative.", getMethodName(name, direction, stagger)); }; fluxFunc getFluxDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.flux.find(key); if(resultOfFind != instance.flux.end()) return resultOfFind->second; - //throw BoutException("Couldn't find requested method ...."); + throw BoutException("Couldn't find requested method %s in map for flux derivative.", getMethodName(name, direction, stagger)); }; private: diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index e270456e37..ff10483406 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -24,7 +24,7 @@ inline std::ostream &operator<<(std::ostream &out, const metaData &meta){ out<<", "; out<<"nGuards : "< void standard(const T &var, T &result, const REGION region) const { - // A loop over the field setting the stencil, applying the specific method - // and storing in result -- in this test case we don't have REGION etc. so - // we comment this out for now. - // ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond || meta.derivType == DERIV::StandardFourth) ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); BOUT_FOR(i, var.getRegion(region)) { result[i] = apply(populateStencil(var, i)); } - //std::cout< void upwindOrFlux(const T& vel, const T &var, T &result, const REGION region) const { - // A loop over the field setting the stencil, applying the specific method - // and storing in result -- in this test case we don't have REGION etc. so - // we comment this out for now. - // ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); @@ -78,10 +66,6 @@ public: ); } } - //std::cout<(theFunc); break; } + default: + throw BoutException("Unhandled derivative method in registerMethod."); }; } }; diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 2d314ffd1c..aa3ec38c7f 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -115,7 +115,7 @@ inline const std::string& STAGGER_STRING(STAGGER stagger) { enum class DERIV { Standard = 0, StandardSecond = 1, StandardFourth = 2, Upwind = 3, Flux = 4 }; -static std::map derivToString = { +static std::map DERIVtoString = { {DERIV::Standard, "Standard"}, {DERIV::StandardSecond, "Standard -- second order"}, {DERIV::StandardFourth, "Standard -- fourth order"}, @@ -123,6 +123,10 @@ static std::map derivToString = { {DERIV::Flux, "Flux"} }; +inline const std::string& DERIV_STRING(DERIV deriv) { + return DERIVtoString.at(deriv); +} + // A small struct that can be used to wrap a specific enum value, giving // it a unique type that can be passed as a valid type to templates and // which can be inspected to provide the actual value of the enum From 045229e75420b654a4391c0cebdf5fa231d56cc0 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 31 Oct 2018 20:49:07 +0000 Subject: [PATCH 0181/1783] Whitespace tidyup --- include/bout/deriv_store.hxx | 28 ++++++------ include/bout/derivs.hxx | 62 +++++++++++++------------- include/bout/template_combinations.hxx | 10 ++--- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 02ff616c66..0ada3ad17b 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -21,8 +21,8 @@ struct DerivativeStore{ using upwindFunc = std::function; using fluxFunc = std::function; - + FieldType&, const REGION)>; + // Singleton method static DerivativeStore &getInstance() { static DerivativeStore instance; @@ -33,7 +33,7 @@ struct DerivativeStore{ /// depends on the derivType input. void registerDerivative(const standardFunc func, const DERIV derivType, const DIRECTION direction, const STAGGER stagger, const std::string methodName) { const auto key = getKey(direction, stagger, methodName); - + switch(derivType) { case(DERIV::Standard) : getInstance().standard[key] = func; @@ -74,15 +74,15 @@ struct DerivativeStore{ }; template void registerDerivative(upwindFunc func) { - registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), Stagger{}.lookup(), Method{}.meta.key); + registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), Stagger{}.lookup(), Method{}.meta.key); }; std::string getMethodName(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { return name + " ("+DIRECTION_STRING(direction)+", "+STAGGER_STRING(stagger)+")"; }; - - /// Routines to return a specific differential operator. Note we have to have a separate routine for different - /// methods as they have different return types. As such we choose to use a different name for each of the + + /// Routines to return a specific differential operator. Note we have to have a separate routine for different + /// methods as they have different return types. As such we choose to use a different name for each of the /// method-classes so everything is consistently treated standardFunc getStandardDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { const auto instance = getInstance(); @@ -99,13 +99,13 @@ struct DerivativeStore{ if(resultOfFind != instance.standardSecond.end()) return resultOfFind->second; throw BoutException("Couldn't find requested method %s in map for standardSecond derivative.", getMethodName(name, direction, stagger)); }; - + standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.standardFourth.find(key); if(resultOfFind != instance.standardFourth.end()) return resultOfFind->second; - throw BoutException("Couldn't find requested method %s in map for standardFourth derivative.", getMethodName(name, direction, stagger)); + throw BoutException("Couldn't find requested method %s in map for standardFourth derivative.", getMethodName(name, direction, stagger)); }; upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { const auto instance = getInstance(); @@ -119,17 +119,17 @@ struct DerivativeStore{ const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.flux.find(key); if(resultOfFind != instance.flux.end()) return resultOfFind->second; - throw BoutException("Couldn't find requested method %s in map for flux derivative.", getMethodName(name, direction, stagger)); + throw BoutException("Couldn't find requested method %s in map for flux derivative.", getMethodName(name, direction, stagger)); }; - + private: std::map standard; std::map standardSecond; - std::map standardFourth; + std::map standardFourth; std::map upwind; - std::map flux; + std::map flux; + - /// Provides a routine to produce a unique key given information about the specific type /// required. This is templated so requires compile-time information. Need to also supply /// a non-templated version to account for run-time choices diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index ff10483406..be2d902236 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -21,10 +21,10 @@ struct metaData{ /// Provide an easy way to report a Region's statistics inline std::ostream &operator<<(std::ostream &out, const metaData &meta){ out<<"key : "<template getNguard() >= meta.nGuards); - - BOUT_FOR(i, var.getRegion(region)) { + + BOUT_FOR(i, var.getRegion(region)) { result[i] = apply(populateStencil(var, i)); } return; @@ -50,17 +50,17 @@ public: template void upwindOrFlux(const T& vel, const T &var, T &result, const REGION region) const { - ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) + ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); - + if (meta.derivType == DERIV::Flux || stagger != STAGGER::None) { - BOUT_FOR(i, var.getRegion(region)) { + BOUT_FOR(i, var.getRegion(region)) { result[i] = apply(populateStencil(vel, i), populateStencil(var, i) ); } } else { - BOUT_FOR(i, var.getRegion(region)) { + BOUT_FOR(i, var.getRegion(region)) { result[i] = apply(vel[i], populateStencil(var, i) ); @@ -101,7 +101,7 @@ public: metaData meta = {key, nGuards, type}; \ }; \ BoutReal name::operator()(const BoutReal &vc, const stencil &f) const - + #define DEFINE_FLUX_DERIV(name, key, nGuards, type) \ struct name { \ BoutReal operator()(const stencil &f) const {}; \ @@ -110,7 +110,7 @@ public: metaData meta = {key, nGuards, type}; \ }; \ BoutReal name::operator()(const stencil &v, const stencil &f) const - + #define DEFINE_STANDARD_DERIV_STAGGERED(name, key, nGuards, type) DEFINE_STANDARD_DERIV(name, key, nGuards, type) #define DEFINE_UPWIND_DERIV_STAGGERED(name, key, nGuards, type) DEFINE_FLUX_DERIV(name, key, nGuards, type) #define DEFINE_FLUX_DERIV_STAGGERED(name, key, nGuards, type) DEFINE_FLUX_DERIV(name, key, nGuards, type) @@ -196,18 +196,18 @@ DEFINE_UPWIND_DERIV(VDDX_U1, "U1", 1, DERIV::Upwind) { //No vec // Existing form doesn't vectorise due to branching return vc >= 0.0 ? vc * (f.c - f.m) : vc * (f.p - f.c); // Alternative form would but may involve more operations - const auto vSplit = vUpDown(vc); + const auto vSplit = vUpDown(vc); return (std::get<0>(vSplit)*(f.p-f.c) + std::get<1>(vSplit) * (f.c-f.m)); } /// upwind, 2nd order DEFINE_UPWIND_DERIV(VDDX_U2, "U2", 2, DERIV::Upwind) { //No vec - // Existing form doesn't vectorise due to branching + // Existing form doesn't vectorise due to branching return vc >= 0.0 ? vc * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) : vc * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c); // Alternative form would but may involve more operations - const auto vSplit = vUpDown(vc); + const auto vSplit = vUpDown(vc); return (std::get<0>(vSplit) * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) + std::get<1>(vSplit) * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c)); @@ -222,19 +222,19 @@ DEFINE_UPWIND_DERIV(VDDX_U3, "U3", 2, DERIV::Upwind) { //No vec const auto vSplit = vUpDown(vc); return (std::get<0>(vSplit) * (4.*f.p - 12.*f.m + 2.*f.mm + 6.*f.c) + std::get<1>(vSplit)*(-4.*f.m + 12.*f.p - 2.*f.pp - 6.*f.c))/12.; - + } /// 3rd-order WENO scheme DEFINE_UPWIND_DERIV(VDDX_WENO3, "W3", 2, DERIV::Upwind) { //No vec BoutReal deriv, w, r; // Existing form doesn't vectorise due to branching - + if (vc > 0.0) { // Left-biased stencil r = (WENO_SMALL + SQ(f.c - 2.0 * f.m + f.mm)) / - (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); + (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); deriv = (-f.mm + 3. * f.m - 3. * f.c + f.p); @@ -242,14 +242,14 @@ DEFINE_UPWIND_DERIV(VDDX_WENO3, "W3", 2, DERIV::Upwind) { //No vec // Right-biased r = (WENO_SMALL + SQ(f.pp - 2.0 * f.p + f.c)) / - (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); + (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); deriv = (-f.m + 3. * f.c - 3. * f.p + f.pp); } - + w = 1.0 / (1.0 + 2.0 * r * r); deriv = 0.5 * ((f.p - f.m) - w * deriv); - + return vc * deriv; } @@ -324,7 +324,7 @@ DEFINE_FLUX_DERIV(FDDX_C4, "C4", 2, DERIV::Flux) { return (8. * v.p * f.p - 8. * /// Map Centre -> Low or Low -> Centre /// /// These expect the output grid cell to be at a different location to the input -/// +/// /// The stencil no longer has a value in 'C' (centre) /// instead, points are shifted as follows: /// @@ -340,14 +340,14 @@ DEFINE_FLUX_DERIV(FDDX_C4, "C4", 2, DERIV::Flux) { return (8. * v.p * f.p - 8. * //////////////////////////////////////////////////////////////////////////////// /// Standard methods -- first order -//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// DEFINE_STANDARD_DERIV_STAGGERED(DDX_C2_stag, "C2", 1, DERIV::Standard) { return f.p - f.m; } DEFINE_STANDARD_DERIV_STAGGERED(DDX_C4_stag, "C4", 2, DERIV::Standard) { return (27. * (f.p - f.m) - (f.pp - f.mm)) / 24.; } //////////////////////////////////////////////////////////////////////////////// /// Standard methods -- second order -//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// DEFINE_STANDARD_DERIV_STAGGERED(D2DX2_C2_stag, "C2", 2, DERIV::StandardSecond) { return (f.pp + f.mm - f.p - f.m) / 2.; } //////////////////////////////////////////////////////////////////////////////// @@ -391,7 +391,7 @@ DEFINE_UPWIND_DERIV_STAGGERED(VDDX_C4_stag, "C4", 2, DERIV::Upwind) { // Result is needed at location of f: interpolate v to f's location and take an // unstaggered derivative of f return (9. * (v.m + v.p) - v.mm - v.pp) / 16. * (8. * f.p - 8. * f.m + f.mm - f.pp) / - 12.; + 12.; } //////////////////////////////////////////////////////////////////////////////// @@ -416,7 +416,7 @@ struct registerMethod { template void operator()(Direction, Stagger, FieldType, Method) { using namespace std::placeholders; - + auto derivativeRegister = DerivativeStore{}.getInstance(); switch(Method{}.meta.derivType){ case(DERIV::Standard): @@ -472,11 +472,11 @@ struct registerMethod { #define REGISTER_STAGGERED_DERIVATIVE(name) \ namespace {produceCombinations< \ Set, \ - Set, \ + Set, \ Set, \ Set>\ > reg(registerMethod{});} - + produceCombinations< Set, Set, @@ -488,22 +488,22 @@ produceCombinations< DerivativeType, DerivativeType, DerivativeType, - // Standard 2nd order + // Standard 2nd order DerivativeType, DerivativeType, - // Standard 4th order + // Standard 4th order DerivativeType, // Upwind DerivativeType, DerivativeType, DerivativeType, DerivativeType, - DerivativeType, + DerivativeType, DerivativeType, // Flux DerivativeType, DerivativeType, - DerivativeType + DerivativeType > > registerDerivatives(registerMethod{}); @@ -515,7 +515,7 @@ produceCombinations< // Standard DerivativeType, DerivativeType, - // Standard 2nd order + // Standard 2nd order DerivativeType, // Upwind DerivativeType, diff --git a/include/bout/template_combinations.hxx b/include/bout/template_combinations.hxx index c415de24e1..e226d4a323 100644 --- a/include/bout/template_combinations.hxx +++ b/include/bout/template_combinations.hxx @@ -8,12 +8,12 @@ template struct Set{}; -/// Define a struct (functor) that we use to build up the final -/// collection of template values. Each time we create one of these +/// Define a struct (functor) that we use to build up the final +/// collection of template values. Each time we create one of these /// objects we provide one more type to the templatePack. We may call /// the operator() method by providing all the required template parameters -/// for whatever the storedFunc is at that point -- once we have built a -/// complete templatePack we don't need to specify any of these template +/// for whatever the storedFunc is at that point -- once we have built a +/// complete templatePack we don't need to specify any of these template /// parameters as they can be deduced/inferred. template struct DeferredFunction { @@ -101,7 +101,7 @@ void addItemToDeferredFunction(theFunction func, item, nextSet, otherSets...) { //-------------------------------------------------------- /// Terminal routine -- the current Set is empty -/// so nothing left to do. +/// so nothing left to do. template void processSet(theFunction func, Set<>, Sets...){}; From 4c535e635d93b2c19d8f1077a7757403a2f442a0 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 31 Oct 2018 20:50:45 +0000 Subject: [PATCH 0182/1783] Clang format new files --- include/bout/deriv_store.hxx | 127 +++++---- include/bout/derivs.hxx | 357 ++++++++++++------------- include/bout/template_combinations.hxx | 31 +-- 3 files changed, 266 insertions(+), 249 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 0ada3ad17b..823c4f989a 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -14,14 +14,12 @@ /// a DIRECTION (e.g. DIRECTION::X) and a STAGGER (e.g. STAGGER::None). There is /// one routine for each class of derivative (standard, standard2nd, standard4th, /// upwind and flux). -template -struct DerivativeStore{ - using standardFunc = std::function; - using upwindFunc = std::function; - using fluxFunc = std::function; +template struct DerivativeStore { + using standardFunc = std::function; + using upwindFunc = std::function; + using fluxFunc = std::function; // Singleton method static DerivativeStore &getInstance() { @@ -31,95 +29,127 @@ struct DerivativeStore{ /// Register a function with standardFunc interface. Which map is used /// depends on the derivType input. - void registerDerivative(const standardFunc func, const DERIV derivType, const DIRECTION direction, const STAGGER stagger, const std::string methodName) { + void registerDerivative(const standardFunc func, const DERIV derivType, + const DIRECTION direction, const STAGGER stagger, + const std::string methodName) { const auto key = getKey(direction, stagger, methodName); - switch(derivType) { - case(DERIV::Standard) : + switch (derivType) { + case (DERIV::Standard): getInstance().standard[key] = func; return; - case(DERIV::StandardSecond) : + case (DERIV::StandardSecond): getInstance().standardSecond[key] = func; return; - case(DERIV::StandardFourth) : + case (DERIV::StandardFourth): getInstance().standardFourth[key] = func; return; default: - throw BoutException("Invalid function signature in registerDerivative : Function signature 'standard' but derivative type %s passed",DERIV_STRING(derivType)); + throw BoutException("Invalid function signature in registerDerivative : Function " + "signature 'standard' but derivative type %s passed", + DERIV_STRING(derivType)); }; return; }; /// Register a function with upwindFunc/fluxFunc interface. Which map is used /// depends on the derivType input. - void registerDerivative(const upwindFunc func, const DERIV derivType, const DIRECTION direction, const STAGGER stagger, const std::string methodName) { + void registerDerivative(const upwindFunc func, const DERIV derivType, + const DIRECTION direction, const STAGGER stagger, + const std::string methodName) { const auto key = getKey(direction, stagger, methodName); - switch(derivType) { - case(DERIV::Upwind) : + switch (derivType) { + case (DERIV::Upwind): getInstance().upwind[key] = func; return; - case(DERIV::Flux) : + case (DERIV::Flux): getInstance().flux[key] = func; return; default: - throw BoutException("Invalid function signature in registerDerivative : Function signature 'upwind/flux' but derivative type %s passed",DERIV_STRING(derivType)); + throw BoutException("Invalid function signature in registerDerivative : Function " + "signature 'upwind/flux' but derivative type %s passed", + DERIV_STRING(derivType)); }; return; }; /// Templated versions of the above registration routines. - template + template void registerDerivative(standardFunc func) { - registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), Stagger{}.lookup(), Method{}.meta.key); + registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), + Stagger{}.lookup(), Method{}.meta.key); }; - template + template void registerDerivative(upwindFunc func) { - registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), Stagger{}.lookup(), Method{}.meta.key); + registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), + Stagger{}.lookup(), Method{}.meta.key); }; - std::string getMethodName(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { - return name + " ("+DIRECTION_STRING(direction)+", "+STAGGER_STRING(stagger)+")"; + std::string getMethodName(std::string name, DIRECTION direction, + STAGGER stagger = STAGGER::None) { + return name + " (" + DIRECTION_STRING(direction) + ", " + STAGGER_STRING(stagger) + + ")"; }; - /// Routines to return a specific differential operator. Note we have to have a separate routine for different - /// methods as they have different return types. As such we choose to use a different name for each of the + /// Routines to return a specific differential operator. Note we have to have a separate + /// routine for different + /// methods as they have different return types. As such we choose to use a different + /// name for each of the /// method-classes so everything is consistently treated - standardFunc getStandardDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { + standardFunc getStandardDerivative(std::string name, DIRECTION direction, + STAGGER stagger = STAGGER::None) { const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.standard.find(key); - if(resultOfFind != instance.standard.end()) return resultOfFind->second; - throw BoutException("Couldn't find requested method %s in map for standard derivative.", getMethodName(name, direction, stagger)); + if (resultOfFind != instance.standard.end()) + return resultOfFind->second; + throw BoutException( + "Couldn't find requested method %s in map for standard derivative.", + getMethodName(name, direction, stagger)); }; - standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { + standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, + STAGGER stagger = STAGGER::None) { const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.standardSecond.find(key); - if(resultOfFind != instance.standardSecond.end()) return resultOfFind->second; - throw BoutException("Couldn't find requested method %s in map for standardSecond derivative.", getMethodName(name, direction, stagger)); + if (resultOfFind != instance.standardSecond.end()) + return resultOfFind->second; + throw BoutException( + "Couldn't find requested method %s in map for standardSecond derivative.", + getMethodName(name, direction, stagger)); }; - standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { + standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, + STAGGER stagger = STAGGER::None) { const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.standardFourth.find(key); - if(resultOfFind != instance.standardFourth.end()) return resultOfFind->second; - throw BoutException("Couldn't find requested method %s in map for standardFourth derivative.", getMethodName(name, direction, stagger)); + if (resultOfFind != instance.standardFourth.end()) + return resultOfFind->second; + throw BoutException( + "Couldn't find requested method %s in map for standardFourth derivative.", + getMethodName(name, direction, stagger)); }; - upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { + upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, + STAGGER stagger = STAGGER::None) { const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.upwind.find(key); - if(resultOfFind != instance.upwind.end()) return resultOfFind->second; - throw BoutException("Couldn't find requested method %s in map for upwind derivative.", getMethodName(name, direction, stagger)); + if (resultOfFind != instance.upwind.end()) + return resultOfFind->second; + throw BoutException("Couldn't find requested method %s in map for upwind derivative.", + getMethodName(name, direction, stagger)); }; - fluxFunc getFluxDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { + fluxFunc getFluxDerivative(std::string name, DIRECTION direction, + STAGGER stagger = STAGGER::None) { const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.flux.find(key); - if(resultOfFind != instance.flux.end()) return resultOfFind->second; - throw BoutException("Couldn't find requested method %s in map for flux derivative.", getMethodName(name, direction, stagger)); + if (resultOfFind != instance.flux.end()) + return resultOfFind->second; + throw BoutException("Couldn't find requested method %s in map for flux derivative.", + getMethodName(name, direction, stagger)); }; private: @@ -129,14 +159,15 @@ private: std::map upwind; std::map flux; - /// Provides a routine to produce a unique key given information about the specific type - /// required. This is templated so requires compile-time information. Need to also supply + /// required. This is templated so requires compile-time information. Need to also + /// supply /// a non-templated version to account for run-time choices /// Note : We could include the derivType in the key -- this would allow us to store /// all methods with the same function interface in the same map, which might be nice. std::size_t getKey(DIRECTION direction, STAGGER stagger, std::string key) { - // Note this key is indepedent of the field type (and hence the key is the same for 3D/2D + // Note this key is indepedent of the field type (and hence the key is the same for + // 3D/2D // fields) as we have to use different maps to store the different field types as the // signature is different. std::size_t result; @@ -149,9 +180,9 @@ private: /// Provides a routine to produce a unique key given information about the specific type /// required. This is templated so requires compile-time information. Makes use of /// a non-templated version that can be used to account for run-time choices - template - std::size_t getKey() { - // Note this key is indepedent of the field type (and hence the key is the same for 3D/2D + template std::size_t getKey() { + // Note this key is indepedent of the field type (and hence the key is the same for + // 3D/2D // fields) as we have to use different maps to store the different field types as the // signature is different. return getKey(Direction{}.lookup(), Stagger{}.lookup(), Method{}.meta.key); diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index be2d902236..47ed0466c5 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -1,30 +1,30 @@ #ifndef __DERIVS_HXX__ #define __DERIVS_HXX__ -#include #include +#include #include +#include +#include #include #include -#include -#include const BoutReal WENO_SMALL = 1.0e-8; // Small number for WENO schemes -struct metaData{ +struct metaData { const std::string key; const int nGuards; - const DERIV derivType; //Can be used to identify the type of the derivative + const DERIV derivType; // Can be used to identify the type of the derivative }; /// Provide an easy way to report a Region's statistics -inline std::ostream &operator<<(std::ostream &out, const metaData &meta){ - out<<"key : "< -class DerivativeType { +template class DerivativeType { public: - template + template void standard(const T &var, T &result, const REGION region) const { - ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond || meta.derivType == DERIV::StandardFourth) + ASSERT2(meta.derivType == DERIV::Standard || + meta.derivType == DERIV::StandardSecond || + meta.derivType == DERIV::StandardFourth) ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); BOUT_FOR(i, var.getRegion(region)) { @@ -48,72 +49,65 @@ public: return; } - template - void upwindOrFlux(const T& vel, const T &var, T &result, const REGION region) const { + template + void upwindOrFlux(const T &vel, const T &var, T &result, const REGION region) const { ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); if (meta.derivType == DERIV::Flux || stagger != STAGGER::None) { BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(vel, i), - populateStencil(var, i) - ); + result[i] = apply(populateStencil(vel, i), + populateStencil(var, i)); } } else { BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(vel[i], - populateStencil(var, i) - ); + result[i] = apply(vel[i], populateStencil(var, i)); } } return; } - BoutReal apply(const stencil &f) const { - return func(f); - } - BoutReal apply(const BoutReal &v, const stencil &f) const { - return func(v, f); - } - BoutReal apply(const stencil &v, const stencil &f) const { - return func(v, f); - } + BoutReal apply(const stencil &f) const { return func(f); } + BoutReal apply(const BoutReal &v, const stencil &f) const { return func(v, f); } + BoutReal apply(const stencil &v, const stencil &f) const { return func(v, f); } FF func{}; metaData meta = func.meta; - }; -#define DEFINE_STANDARD_DERIV(name, key, nGuards, type) \ - struct name { \ - BoutReal operator()(const stencil &f) const; \ - metaData meta = {key, nGuards, type}; \ - BoutReal operator()(const BoutReal &vc, const stencil &f) const{};\ - BoutReal operator()(const stencil &v, const stencil &f) const{}; \ - }; \ +#define DEFINE_STANDARD_DERIV(name, key, nGuards, type) \ + struct name { \ + BoutReal operator()(const stencil &f) const; \ + metaData meta = {key, nGuards, type}; \ + BoutReal operator()(const BoutReal &vc, const stencil &f) const {}; \ + BoutReal operator()(const stencil &v, const stencil &f) const {}; \ + }; \ BoutReal name::operator()(const stencil &f) const -#define DEFINE_UPWIND_DERIV(name, key, nGuards, type) \ - struct name { \ - BoutReal operator()(const stencil &f) const{}; \ - BoutReal operator()(const BoutReal &vc, const stencil &f) const; \ - BoutReal operator()(const stencil &v, const stencil &f) const{}; \ - metaData meta = {key, nGuards, type}; \ - }; \ +#define DEFINE_UPWIND_DERIV(name, key, nGuards, type) \ + struct name { \ + BoutReal operator()(const stencil &f) const {}; \ + BoutReal operator()(const BoutReal &vc, const stencil &f) const; \ + BoutReal operator()(const stencil &v, const stencil &f) const {}; \ + metaData meta = {key, nGuards, type}; \ + }; \ BoutReal name::operator()(const BoutReal &vc, const stencil &f) const -#define DEFINE_FLUX_DERIV(name, key, nGuards, type) \ - struct name { \ - BoutReal operator()(const stencil &f) const {}; \ - BoutReal operator()(const BoutReal &vc, const stencil &f) const {}; \ - BoutReal operator()(const stencil &v, const stencil &f) const; \ - metaData meta = {key, nGuards, type}; \ - }; \ +#define DEFINE_FLUX_DERIV(name, key, nGuards, type) \ + struct name { \ + BoutReal operator()(const stencil &f) const {}; \ + BoutReal operator()(const BoutReal &vc, const stencil &f) const {}; \ + BoutReal operator()(const stencil &v, const stencil &f) const; \ + metaData meta = {key, nGuards, type}; \ + }; \ BoutReal name::operator()(const stencil &v, const stencil &f) const -#define DEFINE_STANDARD_DERIV_STAGGERED(name, key, nGuards, type) DEFINE_STANDARD_DERIV(name, key, nGuards, type) -#define DEFINE_UPWIND_DERIV_STAGGERED(name, key, nGuards, type) DEFINE_FLUX_DERIV(name, key, nGuards, type) -#define DEFINE_FLUX_DERIV_STAGGERED(name, key, nGuards, type) DEFINE_FLUX_DERIV(name, key, nGuards, type) +#define DEFINE_STANDARD_DERIV_STAGGERED(name, key, nGuards, type) \ + DEFINE_STANDARD_DERIV(name, key, nGuards, type) +#define DEFINE_UPWIND_DERIV_STAGGERED(name, key, nGuards, type) \ + DEFINE_FLUX_DERIV(name, key, nGuards, type) +#define DEFINE_FLUX_DERIV_STAGGERED(name, key, nGuards, type) \ + DEFINE_FLUX_DERIV(name, key, nGuards, type) ////////////////////// FIRST DERIVATIVES ///////////////////// @@ -121,7 +115,9 @@ public: DEFINE_STANDARD_DERIV(DDX_C2, "C2", 1, DERIV::Standard) { return 0.5 * (f.p - f.m); }; /// central, 4th order -DEFINE_STANDARD_DERIV(DDX_C4, "C4", 2, DERIV::Standard) { return (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; } +DEFINE_STANDARD_DERIV(DDX_C4, "C4", 2, DERIV::Standard) { + return (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; +} /// Central WENO method, 2nd order (reverts to 1st order near shocks) DEFINE_STANDARD_DERIV(DDX_CWENO2, "W2", 1, DERIV::Standard) { @@ -163,15 +159,21 @@ DEFINE_STANDARD_DERIV(DDX_S2, "S2", 2, DERIV::Standard) { ////////////////////////////// /// Second derivative: Central, 2nd order -DEFINE_STANDARD_DERIV(D2DX2_C2, "C2", 1, DERIV::StandardSecond) { return f.p + f.m - 2. * f.c; } +DEFINE_STANDARD_DERIV(D2DX2_C2, "C2", 1, DERIV::StandardSecond) { + return f.p + f.m - 2. * f.c; +} /// Second derivative: Central, 4th order -DEFINE_STANDARD_DERIV(D2DX2_C4, "C4", 2, DERIV::StandardSecond) {return (-f.pp + 16. * f.p - 30. * f.c + 16. * f.m - f.mm) / 12.;} +DEFINE_STANDARD_DERIV(D2DX2_C4, "C4", 2, DERIV::StandardSecond) { + return (-f.pp + 16. * f.p - 30. * f.c + 16. * f.m - f.mm) / 12.; +} ////////////////////////////// //--- Fourth order derivatives ////////////////////////////// -DEFINE_STANDARD_DERIV(D4DX4_C2, "C2", 2, DERIV::StandardFourth) { return (f.pp - 4. * f.p + 6. * f.c - 4. * f.m + f.mm); } +DEFINE_STANDARD_DERIV(D4DX4_C2, "C2", 2, DERIV::StandardFourth) { + return (f.pp - 4. * f.p + 6. * f.c - 4. * f.m + f.mm); +} //////////////////////////////////////////////////////////////////////////////// /// Upwind non-staggered methods @@ -181,52 +183,52 @@ DEFINE_STANDARD_DERIV(D4DX4_C2, "C2", 2, DERIV::StandardFourth) { return (f.pp - /// Hence convert cell centred values -> centred values, or left -> left /// //////////////////////////////////////////////////////////////////////////////// -std::tuple vUpDown(const BoutReal v){ - return std::tuple{ 0.5*(v + fabs(v)), 0.5*(v - fabs(v))}; +std::tuple vUpDown(const BoutReal v) { + return std::tuple{0.5 * (v + fabs(v)), 0.5 * (v - fabs(v))}; } /// Upwinding: Central, 2nd order -DEFINE_UPWIND_DERIV(VDDX_C2, "C2", 1, DERIV::Upwind) { return vc * 0.5 * (f.p - f.m);} +DEFINE_UPWIND_DERIV(VDDX_C2, "C2", 1, DERIV::Upwind) { return vc * 0.5 * (f.p - f.m); } /// Upwinding: Central, 4th order -DEFINE_UPWIND_DERIV(VDDX_C4, "C4", 2, DERIV::Upwind) { return vc * (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.;} +DEFINE_UPWIND_DERIV(VDDX_C4, "C4", 2, DERIV::Upwind) { + return vc * (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; +} /// upwind, 1st order -DEFINE_UPWIND_DERIV(VDDX_U1, "U1", 1, DERIV::Upwind) { //No vec +DEFINE_UPWIND_DERIV(VDDX_U1, "U1", 1, DERIV::Upwind) { // No vec // Existing form doesn't vectorise due to branching return vc >= 0.0 ? vc * (f.c - f.m) : vc * (f.p - f.c); // Alternative form would but may involve more operations const auto vSplit = vUpDown(vc); - return (std::get<0>(vSplit)*(f.p-f.c) - + std::get<1>(vSplit) * (f.c-f.m)); + return (std::get<0>(vSplit) * (f.p - f.c) + std::get<1>(vSplit) * (f.c - f.m)); } /// upwind, 2nd order -DEFINE_UPWIND_DERIV(VDDX_U2, "U2", 2, DERIV::Upwind) { //No vec +DEFINE_UPWIND_DERIV(VDDX_U2, "U2", 2, DERIV::Upwind) { // No vec // Existing form doesn't vectorise due to branching return vc >= 0.0 ? vc * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) - : vc * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c); + : vc * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c); // Alternative form would but may involve more operations const auto vSplit = vUpDown(vc); - return (std::get<0>(vSplit) * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) - + std::get<1>(vSplit) * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c)); - + return (std::get<0>(vSplit) * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) + + std::get<1>(vSplit) * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c)); } /// upwind, 3rd order -DEFINE_UPWIND_DERIV(VDDX_U3, "U3", 2, DERIV::Upwind) { //No vec +DEFINE_UPWIND_DERIV(VDDX_U3, "U3", 2, DERIV::Upwind) { // No vec // Existing form doesn't vectorise due to branching - return vc >= 0.0 ? vc*(4.*f.p - 12.*f.m + 2.*f.mm + 6.*f.c)/12. - : vc*(-4.*f.m + 12.*f.p - 2.*f.pp - 6.*f.c)/12.; + return vc >= 0.0 ? vc * (4. * f.p - 12. * f.m + 2. * f.mm + 6. * f.c) / 12. + : vc * (-4. * f.m + 12. * f.p - 2. * f.pp - 6. * f.c) / 12.; // Alternative form would but may involve more operations const auto vSplit = vUpDown(vc); - return (std::get<0>(vSplit) * (4.*f.p - 12.*f.m + 2.*f.mm + 6.*f.c) - + std::get<1>(vSplit)*(-4.*f.m + 12.*f.p - 2.*f.pp - 6.*f.c))/12.; - + return (std::get<0>(vSplit) * (4. * f.p - 12. * f.m + 2. * f.mm + 6. * f.c) + + std::get<1>(vSplit) * (-4. * f.m + 12. * f.p - 2. * f.pp - 6. * f.c)) / + 12.; } /// 3rd-order WENO scheme -DEFINE_UPWIND_DERIV(VDDX_WENO3, "W3", 2, DERIV::Upwind) { //No vec +DEFINE_UPWIND_DERIV(VDDX_WENO3, "W3", 2, DERIV::Upwind) { // No vec BoutReal deriv, w, r; // Existing form doesn't vectorise due to branching @@ -234,7 +236,7 @@ DEFINE_UPWIND_DERIV(VDDX_WENO3, "W3", 2, DERIV::Upwind) { //No vec // Left-biased stencil r = (WENO_SMALL + SQ(f.c - 2.0 * f.m + f.mm)) / - (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); + (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); deriv = (-f.mm + 3. * f.m - 3. * f.c + f.p); @@ -242,7 +244,7 @@ DEFINE_UPWIND_DERIV(VDDX_WENO3, "W3", 2, DERIV::Upwind) { //No vec // Right-biased r = (WENO_SMALL + SQ(f.pp - 2.0 * f.p + f.c)) / - (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); + (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); deriv = (-f.m + 3. * f.c - 3. * f.p + f.pp); } @@ -298,7 +300,7 @@ DEFINE_STANDARD_DERIV(DDX_CWENO3, "W3", 2, DERIV::Standard) { /// //////////////////////////////////////////////////////////////////////////////// -DEFINE_FLUX_DERIV(FDDX_U1, "U1", 1, DERIV::Flux) { //No vec +DEFINE_FLUX_DERIV(FDDX_U1, "U1", 1, DERIV::Flux) { // No vec // Velocity at lower end BoutReal vs = 0.5 * (v.m + v.c); @@ -307,16 +309,18 @@ DEFINE_FLUX_DERIV(FDDX_U1, "U1", 1, DERIV::Flux) { //No vec vs = 0.5 * (v.c + v.p); // Existing form doesn't vectorise due to branching result -= (vs >= 0.0) ? vs * f.c : vs * f.p; - return - result; + return -result; // Alternative form would but may involve more operations const auto vSplit = vUpDown(vs); return result - std::get<0>(vSplit) * f.c + std::get<1>(vSplit) * f.p; } -DEFINE_FLUX_DERIV(FDDX_C2, "C2", 2, DERIV::Flux) { return 0.5 * (v.p * f.p - v.m * f.m);} +DEFINE_FLUX_DERIV(FDDX_C2, "C2", 2, DERIV::Flux) { return 0.5 * (v.p * f.p - v.m * f.m); } -DEFINE_FLUX_DERIV(FDDX_C4, "C4", 2, DERIV::Flux) { return (8. * v.p * f.p - 8. * v.m * f.m + v.mm * f.mm - v.pp * f.pp) / 12.;} +DEFINE_FLUX_DERIV(FDDX_C4, "C4", 2, DERIV::Flux) { + return (8. * v.p * f.p - 8. * v.m * f.m + v.mm * f.mm - v.pp * f.pp) / 12.; +} //////////////////////////////////////////////////////////////////////////////// /// Staggered methods @@ -341,14 +345,20 @@ DEFINE_FLUX_DERIV(FDDX_C4, "C4", 2, DERIV::Flux) { return (8. * v.p * f.p - 8. * //////////////////////////////////////////////////////////////////////////////// /// Standard methods -- first order //////////////////////////////////////////////////////////////////////////////// -DEFINE_STANDARD_DERIV_STAGGERED(DDX_C2_stag, "C2", 1, DERIV::Standard) { return f.p - f.m; } +DEFINE_STANDARD_DERIV_STAGGERED(DDX_C2_stag, "C2", 1, DERIV::Standard) { + return f.p - f.m; +} -DEFINE_STANDARD_DERIV_STAGGERED(DDX_C4_stag, "C4", 2, DERIV::Standard) { return (27. * (f.p - f.m) - (f.pp - f.mm)) / 24.; } +DEFINE_STANDARD_DERIV_STAGGERED(DDX_C4_stag, "C4", 2, DERIV::Standard) { + return (27. * (f.p - f.m) - (f.pp - f.mm)) / 24.; +} //////////////////////////////////////////////////////////////////////////////// /// Standard methods -- second order //////////////////////////////////////////////////////////////////////////////// -DEFINE_STANDARD_DERIV_STAGGERED(D2DX2_C2_stag, "C2", 2, DERIV::StandardSecond) { return (f.pp + f.mm - f.p - f.m) / 2.; } +DEFINE_STANDARD_DERIV_STAGGERED(D2DX2_C2_stag, "C2", 2, DERIV::StandardSecond) { + return (f.pp + f.mm - f.p - f.m) / 2.; +} //////////////////////////////////////////////////////////////////////////////// /// Upwind methods @@ -370,10 +380,11 @@ DEFINE_UPWIND_DERIV_STAGGERED(VDDX_U2_stag, "U2", 2, DERIV::Upwind) { // Calculate d(v*f)/dx = (v*f)[i+1/2] - (v*f)[i-1/2] // Upper cell boundary - BoutReal result = (v.p >= 0.) ? v.p * (1.5*f.c - 0.5*f.m) : v.p * (1.5*f.p - 0.5*f.pp); + BoutReal result = + (v.p >= 0.) ? v.p * (1.5 * f.c - 0.5 * f.m) : v.p * (1.5 * f.p - 0.5 * f.pp); // Lower cell boundary - result -= (v.m >= 0.) ? v.m * (1.5*f.m - 0.5*f.mm) : v.m * (1.5*f.c - 0.5*f.p); + result -= (v.m >= 0.) ? v.m * (1.5 * f.m - 0.5 * f.mm) : v.m * (1.5 * f.c - 0.5 * f.p); // result is now d/dx(v*f), but want v*d/dx(f) so subtract f*d/dx(v) result -= f.c * (v.p - v.m); @@ -391,7 +402,7 @@ DEFINE_UPWIND_DERIV_STAGGERED(VDDX_C4_stag, "C4", 2, DERIV::Upwind) { // Result is needed at location of f: interpolate v to f's location and take an // unstaggered derivative of f return (9. * (v.m + v.p) - v.mm - v.pp) / 16. * (8. * f.p - 8. * f.m + f.mm - f.pp) / - 12.; + 12.; } //////////////////////////////////////////////////////////////////////////////// @@ -404,7 +415,7 @@ DEFINE_FLUX_DERIV_STAGGERED(FDDX_U1_stag, "U1", 1, DERIV::Flux) { // Upper cell boundary result -= (v.p >= 0) ? v.p * f.c : v.p * f.p; - return - result; + return -result; } ///////////////////////////////////////////////////////////////////////////////// @@ -413,39 +424,35 @@ DEFINE_FLUX_DERIV_STAGGERED(FDDX_U1_stag, "U1", 1, DERIV::Flux) { ///////////////////////////////////////////////////////////////////////////////// struct registerMethod { - template + template void operator()(Direction, Stagger, FieldType, Method) { using namespace std::placeholders; auto derivativeRegister = DerivativeStore{}.getInstance(); - switch(Method{}.meta.derivType){ - case(DERIV::Standard): - case(DERIV::StandardSecond): - case(DERIV::StandardFourth): - { - const auto theFunc = std::bind( - // Method to store in function - &Method::template standard, - // Arguments -- first is hidden this of type-bound, others are placeholders - // for input field, output field, region - Method{}, _1, _2, _3 - ); - derivativeRegister.template registerDerivative(theFunc); - break; - } - case(DERIV::Upwind): - case(DERIV::Flux): - { - const auto theFunc = std::bind( - // Method to store in function - &Method::template upwindOrFlux, - // Arguments -- first is hidden this of type-bound, others are placeholders - // for input field, output field, region - Method{}, _1, _2, _3, _4 - ); - derivativeRegister.template registerDerivative(theFunc); - break; - } + switch (Method{}.meta.derivType) { + case (DERIV::Standard): + case (DERIV::StandardSecond): + case (DERIV::StandardFourth): { + const auto theFunc = std::bind( + // Method to store in function + &Method::template standard, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + Method{}, _1, _2, _3); + derivativeRegister.template registerDerivative(theFunc); + break; + } + case (DERIV::Upwind): + case (DERIV::Flux): { + const auto theFunc = std::bind( + // Method to store in function + &Method::template upwindOrFlux, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + Method{}, _1, _2, _3, _4); + derivativeRegister.template registerDerivative(theFunc); + break; + } default: throw BoutException("Unhandled derivative method in registerMethod."); }; @@ -462,69 +469,51 @@ struct registerMethod { ///////////////////////////////////////////////////////////////////////////////// // Could use Ben's magic macro for thing here to register multiple routines at once -#define REGISTER_DERIVATIVE(name) \ - namespace {produceCombinations< \ - Set, \ - Set, \ - Set, \ - Set>\ - > reg(registerMethod{});} -#define REGISTER_STAGGERED_DERIVATIVE(name) \ - namespace {produceCombinations< \ - Set, \ - Set, \ - Set, \ - Set>\ - > reg(registerMethod{});} - -produceCombinations< - Set, - Set, - Set, - Set< - // Standard - DerivativeType, - DerivativeType, - DerivativeType, - DerivativeType, - DerivativeType, - // Standard 2nd order - DerivativeType, - DerivativeType, - // Standard 4th order - DerivativeType, - // Upwind - DerivativeType, - DerivativeType, - DerivativeType, - DerivativeType, - DerivativeType, - DerivativeType, - // Flux - DerivativeType, - DerivativeType, - DerivativeType - > - > registerDerivatives(registerMethod{}); +#define REGISTER_DERIVATIVE(name) \ + namespace { \ + produceCombinations, \ + Set, Set, \ + Set>> \ + reg(registerMethod{}); \ + } +#define REGISTER_STAGGERED_DERIVATIVE(name) \ + namespace { \ + produceCombinations, \ + Set, Set, \ + Set>> \ + reg(registerMethod{}); \ + } produceCombinations< - Set, - Set, - Set, - Set< - // Standard - DerivativeType, - DerivativeType, - // Standard 2nd order - DerivativeType, - // Upwind - DerivativeType, - DerivativeType, - DerivativeType, - DerivativeType, - // Flux - DerivativeType - > - > registerStaggeredDerivatives(registerMethod{}); + Set, Set, + Set, + Set< + // Standard + DerivativeType, DerivativeType, DerivativeType, + DerivativeType, DerivativeType, + // Standard 2nd order + DerivativeType, DerivativeType, + // Standard 4th order + DerivativeType, + // Upwind + DerivativeType, DerivativeType, DerivativeType, + DerivativeType, DerivativeType, DerivativeType, + // Flux + DerivativeType, DerivativeType, DerivativeType>> + registerDerivatives(registerMethod{}); + +produceCombinations, + Set, Set, + Set< + // Standard + DerivativeType, DerivativeType, + // Standard 2nd order + DerivativeType, + // Upwind + DerivativeType, DerivativeType, + DerivativeType, DerivativeType, + // Flux + DerivativeType>> + registerStaggeredDerivatives(registerMethod{}); #endif diff --git a/include/bout/template_combinations.hxx b/include/bout/template_combinations.hxx index e226d4a323..7d660b0b39 100644 --- a/include/bout/template_combinations.hxx +++ b/include/bout/template_combinations.hxx @@ -5,8 +5,7 @@ /// a collection of arbitrary types. This is useful for passing /// template packs (typename...) around whilst being able to /// distinguish between different template packs. -template -struct Set{}; +template struct Set {}; /// Define a struct (functor) that we use to build up the final /// collection of template values. Each time we create one of these @@ -15,18 +14,16 @@ struct Set{}; /// for whatever the storedFunc is at that point -- once we have built a /// complete templatePack we don't need to specify any of these template /// parameters as they can be deduced/inferred. -template -struct DeferredFunction { +template struct DeferredFunction { // Just store the actual function we wish to apply - DeferredFunction(currentFunction f): storedFunc(f){}; + DeferredFunction(currentFunction f) : storedFunc(f){}; // The actual function we wish to apply with the functor currentFunction storedFunc; // Make the struct a functor by defining operator() we use // type inference to populate the templatePack/args - template - void operator()(templatePack... args) { + template void operator()(templatePack... args) { storedFunc(currentType{}, args...); } }; @@ -60,7 +57,7 @@ struct DeferredFunction { /// combination of template parameters provided to the /// DeferredFunction (completed by passing in `item`) and /// can therefore invoke this functor. -template +template void addItemToDeferredFunction(theFunction func, item) { // Create a new DeferredFunction building on the passed DeferredFunction (func) // and adding the next template parameter, `item`, to the stored pack. @@ -73,7 +70,7 @@ void addItemToDeferredFunction(theFunction func, item) { } /// One Set left to process so no template pack required -template +template void addItemToDeferredFunction(theFunction func, item, lastSet) { // Create a new DeferredFunction building on the passed DeferredFunction (func) // and adding the next template parameter, `item`, to the stored pack. @@ -84,7 +81,7 @@ void addItemToDeferredFunction(theFunction func, item, lastSet) { } /// More than one Set left to process. -template +template void addItemToDeferredFunction(theFunction func, item, nextSet, otherSets...) { // Create a new DeferredFunction building on the passed DeferredFunction (func) // and adding the next template parameter, `item`, to the stored pack. @@ -102,14 +99,16 @@ void addItemToDeferredFunction(theFunction func, item, nextSet, otherSets...) { /// Terminal routine -- the current Set is empty /// so nothing left to do. -template +template void processSet(theFunction func, Set<>, Sets...){}; /// Here we use type inference to allow us to refer to the firstItem in the first Set /// and the otherItems in this Set. We use this to pass the firstItem off to the routines -/// that will add this to the DeferredFunction. Following this we use recursion to call this +/// that will add this to the DeferredFunction. Following this we use recursion to call +/// this /// routine again to process the rest of this Set. -template +template void processSet(theFunction func, Set, otherSets... others) { // Take the firstItem out of the current (first) Set and add to the DeferredFunction addItemToDeferredFunction(func, firstItem{}, others...); @@ -135,10 +134,8 @@ void processSet(theFunction func, Set, otherSets... ot /// /// Note we wrap this in a struct such that by declaring a global variable of this /// type we trigger the creation of the combinations. -template -struct produceCombinations{ - template - produceCombinations(theFunction func) { +template struct produceCombinations { + template produceCombinations(theFunction func) { processSet(func, FirstSet{}, otherSets{}...); }; }; From 586fa65f3cbbec96c92fabb1ecef5b8f328efaec Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 31 Oct 2018 21:51:29 +0000 Subject: [PATCH 0183/1783] Remove pointless qualifiers on return type --- include/bout/mesh.hxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index b9df3fe0f2..855c7b208f 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -528,7 +528,7 @@ class Mesh { DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); template - const int getNguard(); + int getNguard() const; /// Derivative functions of a single field stencil typedef BoutReal (*deriv_func)(const stencil &); @@ -660,10 +660,10 @@ class Mesh { void derivs_init(Options* options); template - const CELL_LOC getAllowedStaggerLoc(); + CELL_LOC getAllowedStaggerLoc() const; template - const int getNpoints(); + int getNpoints() const; private: /// Allocates default Coordinates objects @@ -880,7 +880,7 @@ const T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD m *******************************************************************************/ template -const CELL_LOC Mesh::getAllowedStaggerLoc() { +CELL_LOC Mesh::getAllowedStaggerLoc() const { switch(direction) { case(DIRECTION::X): return CELL_XLOW; @@ -895,7 +895,7 @@ const CELL_LOC Mesh::getAllowedStaggerLoc() { template -const int Mesh::getNpoints() { +int Mesh::getNpoints() const { switch(direction) { case(DIRECTION::X): return LocalNx; @@ -909,7 +909,7 @@ const int Mesh::getNpoints() { }; template -const int Mesh::getNguard() { +int Mesh::getNguard() const { switch(direction) { case(DIRECTION::X): return xstart; From 2654fed1b2519c19ee7090489d39ee7fd5656539 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 31 Oct 2018 21:52:20 +0000 Subject: [PATCH 0184/1783] Add initial low effort TRACE entries --- include/bout/deriv_store.hxx | 68 ++++++++++++++++++++++-------------- include/bout/derivs.hxx | 48 ++++++++++++++----------- 2 files changed, 68 insertions(+), 48 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 823c4f989a..5bb80c8a84 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -4,8 +4,10 @@ #include #include +#include #include #include +#include /// Here we have a templated singleton that is used to store DerivativeFunctions /// for all types of derivatives. It is templated on the FieldType (2D or 3D) as @@ -17,9 +19,9 @@ template struct DerivativeStore { using standardFunc = std::function; using upwindFunc = std::function; + const REGION)>; using fluxFunc = std::function; + const REGION)>; // Singleton method static DerivativeStore &getInstance() { @@ -30,8 +32,9 @@ template struct DerivativeStore { /// Register a function with standardFunc interface. Which map is used /// depends on the derivType input. void registerDerivative(const standardFunc func, const DERIV derivType, - const DIRECTION direction, const STAGGER stagger, - const std::string methodName) { + const DIRECTION direction, const STAGGER stagger, + const std::string methodName) { + TRACE("%s", __thefunc__); const auto key = getKey(direction, stagger, methodName); switch (derivType) { @@ -46,8 +49,8 @@ template struct DerivativeStore { return; default: throw BoutException("Invalid function signature in registerDerivative : Function " - "signature 'standard' but derivative type %s passed", - DERIV_STRING(derivType)); + "signature 'standard' but derivative type %s passed", + DERIV_STRING(derivType)); }; return; }; @@ -55,8 +58,9 @@ template struct DerivativeStore { /// Register a function with upwindFunc/fluxFunc interface. Which map is used /// depends on the derivType input. void registerDerivative(const upwindFunc func, const DERIV derivType, - const DIRECTION direction, const STAGGER stagger, - const std::string methodName) { + const DIRECTION direction, const STAGGER stagger, + const std::string methodName) { + TRACE("%s", __thefunc__); const auto key = getKey(direction, stagger, methodName); switch (derivType) { case (DERIV::Upwind): @@ -67,8 +71,8 @@ template struct DerivativeStore { return; default: throw BoutException("Invalid function signature in registerDerivative : Function " - "signature 'upwind/flux' but derivative type %s passed", - DERIV_STRING(derivType)); + "signature 'upwind/flux' but derivative type %s passed", + DERIV_STRING(derivType)); }; return; }; @@ -76,19 +80,22 @@ template struct DerivativeStore { /// Templated versions of the above registration routines. template void registerDerivative(standardFunc func) { + TRACE("%s", __thefunc__); registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), - Stagger{}.lookup(), Method{}.meta.key); + Stagger{}.lookup(), Method{}.meta.key); }; template void registerDerivative(upwindFunc func) { + TRACE("%s", __thefunc__); registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), - Stagger{}.lookup(), Method{}.meta.key); + Stagger{}.lookup(), Method{}.meta.key); }; std::string getMethodName(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) { + STAGGER stagger = STAGGER::None) { + TRACE("%s", __thefunc__); return name + " (" + DIRECTION_STRING(direction) + ", " + STAGGER_STRING(stagger) + - ")"; + ")"; }; /// Routines to return a specific differential operator. Note we have to have a separate @@ -97,59 +104,64 @@ template struct DerivativeStore { /// name for each of the /// method-classes so everything is consistently treated standardFunc getStandardDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) { + STAGGER stagger = STAGGER::None) { + TRACE("%s", __thefunc__); const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.standard.find(key); if (resultOfFind != instance.standard.end()) return resultOfFind->second; throw BoutException( - "Couldn't find requested method %s in map for standard derivative.", - getMethodName(name, direction, stagger)); + "Couldn't find requested method %s in map for standard derivative.", + getMethodName(name, direction, stagger)); }; standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) { + STAGGER stagger = STAGGER::None) { + TRACE("%s", __thefunc__); const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.standardSecond.find(key); if (resultOfFind != instance.standardSecond.end()) return resultOfFind->second; throw BoutException( - "Couldn't find requested method %s in map for standardSecond derivative.", - getMethodName(name, direction, stagger)); + "Couldn't find requested method %s in map for standardSecond derivative.", + getMethodName(name, direction, stagger)); }; standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) { + STAGGER stagger = STAGGER::None) { + TRACE("%s", __thefunc__); const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.standardFourth.find(key); if (resultOfFind != instance.standardFourth.end()) return resultOfFind->second; throw BoutException( - "Couldn't find requested method %s in map for standardFourth derivative.", - getMethodName(name, direction, stagger)); + "Couldn't find requested method %s in map for standardFourth derivative.", + getMethodName(name, direction, stagger)); }; upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) { + STAGGER stagger = STAGGER::None) { + TRACE("%s", __thefunc__); const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.upwind.find(key); if (resultOfFind != instance.upwind.end()) return resultOfFind->second; throw BoutException("Couldn't find requested method %s in map for upwind derivative.", - getMethodName(name, direction, stagger)); + getMethodName(name, direction, stagger)); }; fluxFunc getFluxDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) { + STAGGER stagger = STAGGER::None) { + TRACE("%s", __thefunc__); const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); const auto resultOfFind = instance.flux.find(key); if (resultOfFind != instance.flux.end()) return resultOfFind->second; throw BoutException("Couldn't find requested method %s in map for flux derivative.", - getMethodName(name, direction, stagger)); + getMethodName(name, direction, stagger)); }; private: @@ -166,6 +178,7 @@ private: /// Note : We could include the derivType in the key -- this would allow us to store /// all methods with the same function interface in the same map, which might be nice. std::size_t getKey(DIRECTION direction, STAGGER stagger, std::string key) { + TRACE("%s", __thefunc__); // Note this key is indepedent of the field type (and hence the key is the same for // 3D/2D // fields) as we have to use different maps to store the different field types as the @@ -181,6 +194,7 @@ private: /// required. This is templated so requires compile-time information. Makes use of /// a non-templated version that can be used to account for run-time choices template std::size_t getKey() { + TRACE("%s", __thefunc__); // Note this key is indepedent of the field type (and hence the key is the same for // 3D/2D // fields) as we have to use different maps to store the different field types as the diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index 47ed0466c5..a0d16584d0 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -6,8 +6,10 @@ #include #include +#include #include #include +#include #include const BoutReal WENO_SMALL = 1.0e-8; // Small number for WENO schemes @@ -38,6 +40,8 @@ template class DerivativeType { public: template void standard(const T &var, T &result, const REGION region) const { + TRACE("%s",__thefunc__); + throw BoutException("TESTING ERROR TRACE"); ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond || meta.derivType == DERIV::StandardFourth) @@ -51,6 +55,7 @@ public: template void upwindOrFlux(const T &vel, const T &var, T &result, const REGION region) const { + TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); @@ -75,31 +80,31 @@ public: metaData meta = func.meta; }; -#define DEFINE_STANDARD_DERIV(name, key, nGuards, type) \ - struct name { \ - BoutReal operator()(const stencil &f) const; \ - metaData meta = {key, nGuards, type}; \ - BoutReal operator()(const BoutReal &vc, const stencil &f) const {}; \ - BoutReal operator()(const stencil &v, const stencil &f) const {}; \ - }; \ +#define DEFINE_STANDARD_DERIV(name, key, nGuards, type) \ + struct name { \ + BoutReal operator()(const stencil &f) const; \ + metaData meta = {key, nGuards, type}; \ + BoutReal operator()(const BoutReal &vc, const stencil &f) const {return BoutNaN;}; \ + BoutReal operator()(const stencil &v, const stencil &f) const {return BoutNaN;}; \ + }; \ BoutReal name::operator()(const stencil &f) const -#define DEFINE_UPWIND_DERIV(name, key, nGuards, type) \ - struct name { \ - BoutReal operator()(const stencil &f) const {}; \ - BoutReal operator()(const BoutReal &vc, const stencil &f) const; \ - BoutReal operator()(const stencil &v, const stencil &f) const {}; \ - metaData meta = {key, nGuards, type}; \ - }; \ +#define DEFINE_UPWIND_DERIV(name, key, nGuards, type) \ + struct name { \ + BoutReal operator()(const stencil &f) const {return BoutNaN;}; \ + BoutReal operator()(const BoutReal &vc, const stencil &f) const; \ + BoutReal operator()(const stencil &v, const stencil &f) const {return BoutNaN;}; \ + metaData meta = {key, nGuards, type}; \ + }; \ BoutReal name::operator()(const BoutReal &vc, const stencil &f) const -#define DEFINE_FLUX_DERIV(name, key, nGuards, type) \ - struct name { \ - BoutReal operator()(const stencil &f) const {}; \ - BoutReal operator()(const BoutReal &vc, const stencil &f) const {}; \ - BoutReal operator()(const stencil &v, const stencil &f) const; \ - metaData meta = {key, nGuards, type}; \ - }; \ +#define DEFINE_FLUX_DERIV(name, key, nGuards, type) \ + struct name { \ + BoutReal operator()(const stencil &f) const {return BoutNaN;}; \ + BoutReal operator()(const BoutReal &vc, const stencil &f) const {return BoutNaN;}; \ + BoutReal operator()(const stencil &v, const stencil &f) const; \ + metaData meta = {key, nGuards, type}; \ + }; \ BoutReal name::operator()(const stencil &v, const stencil &f) const #define DEFINE_STANDARD_DERIV_STAGGERED(name, key, nGuards, type) \ @@ -426,6 +431,7 @@ DEFINE_FLUX_DERIV_STAGGERED(FDDX_U1_stag, "U1", 1, DERIV::Flux) { struct registerMethod { template void operator()(Direction, Stagger, FieldType, Method) { + TRACE("%s", __thefunc__); using namespace std::placeholders; auto derivativeRegister = DerivativeStore{}.getInstance(); From f20a2b14b236209f98a4147d1d04f12b41ca9e5b Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 31 Oct 2018 21:58:25 +0000 Subject: [PATCH 0185/1783] Remove testing exception throw --- include/bout/derivs.hxx | 1 - 1 file changed, 1 deletion(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index a0d16584d0..03466d5d74 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -41,7 +41,6 @@ public: template void standard(const T &var, T &result, const REGION region) const { TRACE("%s",__thefunc__); - throw BoutException("TESTING ERROR TRACE"); ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond || meta.derivType == DERIV::StandardFourth) From 1afaa2bd6e370695d1d6cace8dc83e5189361928 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 31 Oct 2018 21:58:40 +0000 Subject: [PATCH 0186/1783] Actually use the passed stagger value in standard derivatives. Should help the staggered tests do a bit better --- include/bout/derivs.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index 03466d5d74..ef12b3dbf3 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -47,7 +47,7 @@ public: ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(var, i)); + result[i] = apply(populateStencil(var, i)); } return; } From b5b72d1a239b1a2118010ec62dd886b481c5fa52 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 31 Oct 2018 22:08:17 +0000 Subject: [PATCH 0187/1783] Remove more const qualifiers on return types --- include/bout/mesh.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 855c7b208f..d2378c4271 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -451,8 +451,8 @@ class Mesh { BoutReal fft_derivs_filter; ///< Fraction of modes to filter. This is set in derivs_init from option "ddz:fft_filter" - const STAGGER getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc); - const STAGGER getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc); + STAGGER getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc) const; + STAGGER getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc) const; template const T indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region); From e9ad53b5ac9b034da0e69d6a602f10f3839f5177 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 31 Oct 2018 22:13:25 +0000 Subject: [PATCH 0188/1783] Marking parameter unused --- include/bout/template_combinations.hxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/bout/template_combinations.hxx b/include/bout/template_combinations.hxx index 7d660b0b39..ff76923d84 100644 --- a/include/bout/template_combinations.hxx +++ b/include/bout/template_combinations.hxx @@ -1,6 +1,8 @@ #ifndef __TEMPLATE_COMBINATIONS_H__ #define __TEMPLATE_COMBINATIONS_H__ +#include + /// Here we define an empty templated struct that can represent /// a collection of arbitrary types. This is useful for passing /// template packs (typename...) around whilst being able to @@ -100,7 +102,7 @@ void addItemToDeferredFunction(theFunction func, item, nextSet, otherSets...) { /// Terminal routine -- the current Set is empty /// so nothing left to do. template -void processSet(theFunction func, Set<>, Sets...){}; +void processSet(theFunction UNUSED(func), Set<>, Sets...){}; /// Here we use type inference to allow us to refer to the firstItem in the first Set /// and the otherItems in this Set. We use this to pass the firstItem off to the routines From f66df65699f95094d2a259faf0fc1166c8988d8e Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 31 Oct 2018 22:23:05 +0000 Subject: [PATCH 0189/1783] Correct getStagger signature --- src/mesh/index_derivs.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index c57dfe03ad..5e800da61f 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -163,7 +163,7 @@ void Mesh::derivs_init(Options *options) { * Helper routines *******************************************************************************/ -const STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) { +STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == allowedStaggerLoc) || (outloc == allowedStaggerLoc && inloc == CELL_CENTRE)); @@ -175,7 +175,7 @@ const STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, cons } } -const STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) { +STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { ASSERT1(vloc == inloc); return getStagger(inloc, outloc, allowedStaggerLoc); } From 2780ce2c481c629ea1ca899bac3c3cff9051bf6f Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 31 Oct 2018 22:25:47 +0000 Subject: [PATCH 0190/1783] Convert std::string to c_str in exceptions --- include/bout/deriv_store.hxx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 5bb80c8a84..1b53b84134 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -50,7 +50,7 @@ template struct DerivativeStore { default: throw BoutException("Invalid function signature in registerDerivative : Function " "signature 'standard' but derivative type %s passed", - DERIV_STRING(derivType)); + DERIV_STRING(derivType).c_str()); }; return; }; @@ -72,7 +72,7 @@ template struct DerivativeStore { default: throw BoutException("Invalid function signature in registerDerivative : Function " "signature 'upwind/flux' but derivative type %s passed", - DERIV_STRING(derivType)); + DERIV_STRING(derivType).c_str()); }; return; }; @@ -113,7 +113,7 @@ template struct DerivativeStore { return resultOfFind->second; throw BoutException( "Couldn't find requested method %s in map for standard derivative.", - getMethodName(name, direction, stagger)); + getMethodName(name, direction, stagger).c_str()); }; standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, @@ -126,7 +126,7 @@ template struct DerivativeStore { return resultOfFind->second; throw BoutException( "Couldn't find requested method %s in map for standardSecond derivative.", - getMethodName(name, direction, stagger)); + getMethodName(name, direction, stagger).c_str()); }; standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, @@ -139,7 +139,7 @@ template struct DerivativeStore { return resultOfFind->second; throw BoutException( "Couldn't find requested method %s in map for standardFourth derivative.", - getMethodName(name, direction, stagger)); + getMethodName(name, direction, stagger).c_str()); }; upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { @@ -150,7 +150,7 @@ template struct DerivativeStore { if (resultOfFind != instance.upwind.end()) return resultOfFind->second; throw BoutException("Couldn't find requested method %s in map for upwind derivative.", - getMethodName(name, direction, stagger)); + getMethodName(name, direction, stagger).c_str()); }; fluxFunc getFluxDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) { @@ -161,7 +161,7 @@ template struct DerivativeStore { if (resultOfFind != instance.flux.end()) return resultOfFind->second; throw BoutException("Couldn't find requested method %s in map for flux derivative.", - getMethodName(name, direction, stagger)); + getMethodName(name, direction, stagger).c_str()); }; private: From 3bd96ab06a3205ad797267c7744e4594f4abc672 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 31 Oct 2018 22:44:59 +0000 Subject: [PATCH 0191/1783] Mark more arguments as unused --- include/bout/derivs.hxx | 17 +++++++++++------ src/mesh/index_derivs.cxx | 6 +++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index ef12b3dbf3..4dc7fb5cc4 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -11,6 +11,7 @@ #include #include #include +#include const BoutReal WENO_SMALL = 1.0e-8; // Small number for WENO schemes @@ -83,24 +84,28 @@ public: struct name { \ BoutReal operator()(const stencil &f) const; \ metaData meta = {key, nGuards, type}; \ - BoutReal operator()(const BoutReal &vc, const stencil &f) const {return BoutNaN;}; \ - BoutReal operator()(const stencil &v, const stencil &f) const {return BoutNaN;}; \ + BoutReal operator()(const BoutReal &UNUSED(vc),\ + const stencil &UNUSED(f)) const {return BoutNaN;}; \ + BoutReal operator()(const stencil &UNUSED(v),\ + const stencil &UNUSED(f)) const {return BoutNaN;}; \ }; \ BoutReal name::operator()(const stencil &f) const #define DEFINE_UPWIND_DERIV(name, key, nGuards, type) \ struct name { \ - BoutReal operator()(const stencil &f) const {return BoutNaN;}; \ + BoutReal operator()(const stencil &UNUSED(f)) const {return BoutNaN;}; \ BoutReal operator()(const BoutReal &vc, const stencil &f) const; \ - BoutReal operator()(const stencil &v, const stencil &f) const {return BoutNaN;}; \ + BoutReal operator()(const stencil &UNUSED(v),\ + const stencil &UNUSED(f)) const {return BoutNaN;}; \ metaData meta = {key, nGuards, type}; \ }; \ BoutReal name::operator()(const BoutReal &vc, const stencil &f) const #define DEFINE_FLUX_DERIV(name, key, nGuards, type) \ struct name { \ - BoutReal operator()(const stencil &f) const {return BoutNaN;}; \ - BoutReal operator()(const BoutReal &vc, const stencil &f) const {return BoutNaN;}; \ + BoutReal operator()(const stencil &UNUSED(f)) const {return BoutNaN;}; \ + BoutReal operator()(const BoutReal &UNUSED(vc),\ + const stencil &UNUSED(f)) const {return BoutNaN;}; \ BoutReal operator()(const stencil &v, const stencil &f) const; \ metaData meta = {key, nGuards, type}; \ }; \ diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 5e800da61f..fb967e6245 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -55,7 +55,6 @@ #include #include -#include #include #include @@ -175,7 +174,12 @@ STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL } } +#if CHECK > 0 STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { +#else +STAGGER Mesh::getStagger(const CELL_LOC UNUSED(vloc), const CELL_LOC inloc, + const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { +#endif ASSERT1(vloc == inloc); return getStagger(inloc, outloc, allowedStaggerLoc); } From 54499599a20d219742d28f775874897063937133 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 31 Oct 2018 22:45:26 +0000 Subject: [PATCH 0192/1783] Fix for include statement --- include/bout/derivs.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index 4dc7fb5cc4..aad73b278e 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -11,7 +11,7 @@ #include #include #include -#include +#include const BoutReal WENO_SMALL = 1.0e-8; // Small number for WENO schemes From a6d1e8d41c0b9398b80bda47a1685c0fc21966fc Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 12:02:03 +0000 Subject: [PATCH 0193/1783] Improve const uses in the derivatives part of Mesh. Involves a slight hack to work around the fact that Field constructors require a non-const Mesh point. This forces us to replace `this` with `f.getMesh()` in const Mesh member functions when creating fields. --- include/bout/mesh.hxx | 118 +++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 65 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index d2378c4271..28fa5cd5c0 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -455,43 +455,43 @@ class Mesh { STAGGER getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc) const; template - const T indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region); + T indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const; template - const T indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region); + T indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const; /// Derivatives in X direction, in index space template - const T indexDDX(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); + T indexDDX(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, + REGION region=RGN_NOBNDRY) const; template - const T indexD2DX2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); + T indexD2DX2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, + REGION region=RGN_NOBNDRY) const; template - const T indexD4DX4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); + T indexD4DX4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, + REGION region=RGN_NOBNDRY) const; /// Derivatives in Y direction, in index space template - const T indexDDY(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); + T indexDDY(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, + REGION region=RGN_NOBNDRY) const; template - const T indexD2DY2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); + T indexD2DY2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, + REGION region=RGN_NOBNDRY) const; template - const T indexD4DY4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); + T indexD4DY4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, + REGION region=RGN_NOBNDRY) const; /// Derivatives in Z direction, in index space template - const T indexDDZ(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); + T indexDDZ(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, + REGION region=RGN_NOBNDRY) const; template - const T indexD2DZ2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); + T indexD2DZ2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, + REGION region=RGN_NOBNDRY) const; template - const T indexD4DZ4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY); + T indexD4DZ4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, + REGION region=RGN_NOBNDRY) const; /// Advection operator in index space in Y direction /// @@ -505,38 +505,29 @@ class Mesh { /// @param[in] method The differencing method to use /// @param[in] region The region of the grid for which the result is calculated. template - const T indexVDDX(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); + T indexVDDX(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, + DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY) const; template - const T indexVDDY(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); + T indexVDDY(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, + DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY) const; template - const T indexVDDZ(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); - - + T indexVDDZ(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, + DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY) const; /// Flux functions template - const T indexFDDX(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); + T indexFDDX(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, + DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY) const; template - const T indexFDDY(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); + T indexFDDY(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, + DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY) const; template - const T indexFDDZ(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY); + T indexFDDZ(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, + DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY) const; template int getNguard() const; - /// Derivative functions of a single field stencil - typedef BoutReal (*deriv_func)(const stencil &); - /// Derivative functions of a BoutReal velocity, and field stencil - typedef BoutReal (*upwind_func)(const BoutReal&, const stencil &); - /// Derivative functions of a velocity field, and field stencil v, f - typedef BoutReal (*flux_func)(const stencil&, const stencil &); - /// Transform a field into field-aligned coordinates const Field3D toFieldAligned(const Field3D &f) { return getParallelTransform().toFieldAligned(f); @@ -681,50 +672,50 @@ private: ////////////// X DERIVATIVE ///////////////// template -const T Mesh::indexDDX(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexDDX(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexStandardDerivative(f, outloc, method, region); } template -const T Mesh::indexD2DX2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexD2DX2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexStandardDerivative(f, outloc, method, region); } template -const T Mesh::indexD4DX4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexD4DX4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexStandardDerivative(f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// template -const T Mesh::indexDDY(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexDDY(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexStandardDerivative(f, outloc, method, region); } template -const T Mesh::indexD2DY2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexD2DY2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexStandardDerivative(f, outloc, method, region); } template -const T Mesh::indexD4DY4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexD4DY4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexStandardDerivative(f, outloc, method, region); } ////////////// Z DERIVATIVE ///////////////// template -const T Mesh::indexDDZ(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexDDZ(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexStandardDerivative(f, outloc, method, region); } template -const T Mesh::indexD2DZ2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexD2DZ2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexStandardDerivative(f, outloc, method, region); } template -const T Mesh::indexD4DZ4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexD4DZ4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexStandardDerivative(f, outloc, method, region); } @@ -733,43 +724,41 @@ const T Mesh::indexD4DZ4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION ////////////// X DERIVATIVE ///////////////// template -const T Mesh::indexVDDX(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexVDDX(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexFlowDerivative(vel, f, outloc, method, region); } template -const T Mesh::indexFDDX(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexFDDX(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexFlowDerivative(vel, f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// template -const T Mesh::indexVDDY(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexVDDY(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexFlowDerivative(vel, f, outloc, method, region); } template -const T Mesh::indexFDDY(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexFDDY(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexFlowDerivative(vel, f, outloc, method, region); } ////////////// Z DERIVATIVE ///////////////// template -const T Mesh::indexVDDZ(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexVDDZ(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexFlowDerivative(vel, f, outloc, method, region); } template -const T Mesh::indexFDDZ(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexFDDZ(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { return indexFlowDerivative(vel, f, outloc, method, region); } - - template -const T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { // Checks static_assert(std::is_base_of::value || std::is_base_of::value, "indexDDX only works on Field2D or Field3D input"); @@ -794,7 +783,7 @@ const T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIF const int nPoint = getNpoints(); if (nPoint == 1) { - auto tmp = T(0., this); + auto tmp = T(0., f.getMesh()); tmp.setLocation(outloc); return tmp; } @@ -811,7 +800,7 @@ const T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIF } // Create the result field - T result(this); + T result(f.getMesh()); result.allocate(); // Make sure data allocated result.setLocation(outloc); @@ -821,9 +810,8 @@ const T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIF return result; } - template -const T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { // Checks static_assert(std::is_base_of::value || std::is_base_of::value, "indexDDX only works on Field2D or Field3D input"); @@ -845,7 +833,7 @@ const T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD m const int nPoint = getNpoints(); if (nPoint == 1) { - auto tmp = T(0., this); + auto tmp = T(0., f.getMesh()); tmp.setLocation(outloc); return tmp; } @@ -865,7 +853,7 @@ const T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD m } // Create the result field - T result(this); + T result(f.getMesh()); result.allocate(); // Make sure data allocated result.setLocation(outloc); From 087d9f94f09776d6148b07b4a21423a2ff494b3a Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 12:08:59 +0000 Subject: [PATCH 0194/1783] Mark derivative store members as const where possible --- include/bout/deriv_store.hxx | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 1b53b84134..1640a46b07 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -91,11 +91,7 @@ template struct DerivativeStore { Stagger{}.lookup(), Method{}.meta.key); }; - std::string getMethodName(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) { TRACE("%s", __thefunc__); - return name + " (" + DIRECTION_STRING(direction) + ", " + STAGGER_STRING(stagger) + - ")"; }; /// Routines to return a specific differential operator. Note we have to have a separate @@ -104,7 +100,7 @@ template struct DerivativeStore { /// name for each of the /// method-classes so everything is consistently treated standardFunc getStandardDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) { + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); @@ -117,7 +113,7 @@ template struct DerivativeStore { }; standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) { + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); @@ -130,7 +126,7 @@ template struct DerivativeStore { }; standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) { + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); @@ -142,7 +138,7 @@ template struct DerivativeStore { getMethodName(name, direction, stagger).c_str()); }; upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) { + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); @@ -153,7 +149,7 @@ template struct DerivativeStore { getMethodName(name, direction, stagger).c_str()); }; fluxFunc getFluxDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) { + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); const auto key = getKey(direction, stagger, name); @@ -171,13 +167,19 @@ private: std::map upwind; std::map flux; + std::string getMethodName(std::string name, DIRECTION direction, + STAGGER stagger = STAGGER::None) const { + TRACE("%s", __thefunc__); + return name + " (" + DIRECTION_STRING(direction) + ", " + STAGGER_STRING(stagger) + + ")"; + }; /// Provides a routine to produce a unique key given information about the specific type /// required. This is templated so requires compile-time information. Need to also /// supply /// a non-templated version to account for run-time choices /// Note : We could include the derivType in the key -- this would allow us to store /// all methods with the same function interface in the same map, which might be nice. - std::size_t getKey(DIRECTION direction, STAGGER stagger, std::string key) { + std::size_t getKey(DIRECTION direction, STAGGER stagger, std::string key) const { TRACE("%s", __thefunc__); // Note this key is indepedent of the field type (and hence the key is the same for // 3D/2D @@ -193,7 +195,8 @@ private: /// Provides a routine to produce a unique key given information about the specific type /// required. This is templated so requires compile-time information. Makes use of /// a non-templated version that can be used to account for run-time choices - template std::size_t getKey() { + template + std::size_t getKey() const { TRACE("%s", __thefunc__); // Note this key is indepedent of the field type (and hence the key is the same for // 3D/2D From 9df5b1c71cc680af753a8d47830be38256a7f6fa Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 14:15:33 +0000 Subject: [PATCH 0195/1783] Add uppercase utility function to convert strings to upper case --- include/utils.hxx | 5 +++++ src/sys/utils.cxx | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/include/utils.hxx b/include/utils.hxx index 2b0052817f..d7719439fc 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -348,6 +348,11 @@ const string toString(const T& val) { */ const string lowercase(const string &str); +/*! + * Convert a string to upper case + */ +const string uppercase(const string &str); + /*! * Convert to lower case, except inside quotes (" or ') */ diff --git a/src/sys/utils.cxx b/src/sys/utils.cxx index 8eef7335e6..053498bb21 100644 --- a/src/sys/utils.cxx +++ b/src/sys/utils.cxx @@ -58,6 +58,14 @@ const string lowercase(const string &str) { return strlow; } +// Convert a string to upper case +const string uppercase(const string &str) { + string strlow(str); + + std::transform(strlow.begin(), strlow.end(), strlow.begin(), ::toupper); + return strlow; +} + // Convert to lowercase, except for inside strings const string lowercasequote(const string &str) { string strlow(str); From 0ed627ca20eb07134c277f0d41a51c798d906fc4 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 14:16:19 +0000 Subject: [PATCH 0196/1783] Adding initial (ugly) code for dealing with setting the default methods --- include/bout/deriv_store.hxx | 130 +++++++++++++++++++++++++++++++---- include/bout_types.hxx | 2 +- src/mesh/index_derivs.cxx | 4 ++ 3 files changed, 122 insertions(+), 14 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 1640a46b07..9528e66c1f 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -8,6 +8,7 @@ #include #include #include +#include /// Here we have a templated singleton that is used to store DerivativeFunctions /// for all types of derivatives. It is templated on the FieldType (2D or 3D) as @@ -91,9 +92,6 @@ template struct DerivativeStore { Stagger{}.lookup(), Method{}.meta.key); }; - TRACE("%s", __thefunc__); - }; - /// Routines to return a specific differential operator. Note we have to have a separate /// routine for different /// methods as they have different return types. As such we choose to use a different @@ -103,63 +101,165 @@ template struct DerivativeStore { STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); - const auto key = getKey(direction, stagger, name); + const auto realName = nameLookup(name, + defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Standard)))); + const auto key = getKey(direction, stagger, realName); const auto resultOfFind = instance.standard.find(key); if (resultOfFind != instance.standard.end()) return resultOfFind->second; throw BoutException( "Couldn't find requested method %s in map for standard derivative.", - getMethodName(name, direction, stagger).c_str()); + getMethodName(realName, direction, stagger).c_str()); }; standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); - const auto key = getKey(direction, stagger, name); + const auto realName = nameLookup(name, + defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::StandardSecond)))); + const auto key = getKey(direction, stagger, realName); const auto resultOfFind = instance.standardSecond.find(key); if (resultOfFind != instance.standardSecond.end()) return resultOfFind->second; throw BoutException( "Couldn't find requested method %s in map for standardSecond derivative.", - getMethodName(name, direction, stagger).c_str()); + getMethodName(realName, direction, stagger).c_str()); }; standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); - const auto key = getKey(direction, stagger, name); + const auto realName = nameLookup(name, + defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::StandardFourth)))); + const auto key = getKey(direction, stagger, realName); const auto resultOfFind = instance.standardFourth.find(key); if (resultOfFind != instance.standardFourth.end()) return resultOfFind->second; throw BoutException( "Couldn't find requested method %s in map for standardFourth derivative.", - getMethodName(name, direction, stagger).c_str()); + getMethodName(realName, direction, stagger).c_str()); }; upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); - const auto key = getKey(direction, stagger, name); + const auto realName = nameLookup(name, + defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Upwind)))); + const auto key = getKey(direction, stagger, realName); const auto resultOfFind = instance.upwind.find(key); if (resultOfFind != instance.upwind.end()) return resultOfFind->second; throw BoutException("Couldn't find requested method %s in map for upwind derivative.", - getMethodName(name, direction, stagger).c_str()); + getMethodName(realName, direction, stagger).c_str()); }; fluxFunc getFluxDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); - const auto key = getKey(direction, stagger, name); + const auto realName = nameLookup(name, + defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Flux)))); + const auto key = getKey(direction, stagger, realName); const auto resultOfFind = instance.flux.find(key); if (resultOfFind != instance.flux.end()) return resultOfFind->second; throw BoutException("Couldn't find requested method %s in map for flux derivative.", - getMethodName(name, direction, stagger).c_str()); + getMethodName(realName, direction, stagger).c_str()); }; + void initialise(Options *options) { + TRACE("%s", __thefunc__); + + //To replicate the existing behaviour we first search for a section called + //"dd?" and if the option isn't in there we search a section called "diff" + auto backupSection = options->getSection("diff"); + + std::map initialDefaultMethods = { + {DERIV::Standard, "C2"}, {DERIV::StandardSecond, "C2"}, {DERIV::StandardFourth, "C2"}, + {DERIV::Upwind, "U1"}, {DERIV::Flux, "U1"}}; + + std::map directions = { + {DIRECTION::X,"ddx"}, {DIRECTION::Y,"ddy"}, {DIRECTION::Z,"ddz"} + }; + + std::map derivTypes = { + {DERIV::Standard,"First"}, {DERIV::StandardSecond,"Second"}, + {DERIV::StandardFourth,"Fourth"}, {DERIV::Upwind,"Upwind"}, + {DERIV::Flux,"Flux"} + }; + + for(const auto& direction : directions) { + for(const auto& deriv : derivTypes) { + std::string theDefault; + + // This corresponds to the key in the input file + auto derivName = deriv.second; + + const auto theDirection = direction.first; + const auto theDerivType = deriv.first; + const auto theDerivTypeString = DERIV_STRING(theDerivType); + + //------------------------------------------------------------- + // Unstaggered + //------------------------------------------------------------- + + // The direction specific section to consider + auto specificSection = options->getSection(direction.second); + + // Find the appropriate value for theDefault either from + // the input file or if not found then use the value in initialDefaultMethods + if(specificSection->isSet(derivName)) { + specificSection->get(derivName, theDefault, ""); + } else if (backupSection->isSet(derivName)) { + backupSection->get(derivName, theDefault, ""); + } else { + theDefault = initialDefaultMethods[theDerivType]; + } + + // Now we have the default method we should store it in defaultMethods + theDefault = uppercase(theDefault); + defaultMethods[getKey(theDirection, STAGGER::None, theDerivTypeString)] = theDefault; + output_info << "The default method for derivative type "<< theDerivTypeString; + output_info << " in direction "<getSection(direction.second+"stag"); + + // Find the appropriate value for theDefault either from + // the input file. Note if the specific section for staggering isn't + // found then we leave the default as for the non-staggered version + if(specificSection->isSet(derivName)) { + specificSection->get(derivName, theDefault, ""); + } + + // Now we have the default method we should store it in defaultMethods + theDefault = uppercase(theDefault); + defaultMethods[getKey(theDirection, STAGGER::L2C, theDerivTypeString)] = theDefault; + defaultMethods[getKey(theDirection, STAGGER::C2L, theDerivTypeString)] = theDefault; + output_info << "The default method for staggered derivative type "<< theDerivTypeString; + output_info << " in direction "< defaultMethods; + private: std::map standard; std::map standardSecond; @@ -173,6 +273,10 @@ private: return name + " (" + DIRECTION_STRING(direction) + ", " + STAGGER_STRING(stagger) + ")"; }; + + std::string nameLookup(const std::string name, const std::string defaultName) const { + return name != DIFF_METHOD_STRING(DIFF_DEFAULT) ? name : defaultName; + } /// Provides a routine to produce a unique key given information about the specific type /// required. This is templated so requires compile-time information. Need to also /// supply diff --git a/include/bout_types.hxx b/include/bout_types.hxx index aa3ec38c7f..b7201dfb55 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -55,7 +55,7 @@ inline const std::string& CELL_LOC_STRING(CELL_LOC location) { enum DIFF_METHOD {DIFF_DEFAULT, DIFF_U1, DIFF_U2, DIFF_C2, DIFF_W2, DIFF_W3, DIFF_C4, DIFF_U3, DIFF_FFT, DIFF_SPLIT, DIFF_NND, DIFF_S2}; const std::map DIFF_METHODtoString = { - {DIFF_DEFAULT, "C2"}, + {DIFF_DEFAULT, "default"}, {DIFF_U1, "U1"}, {DIFF_U2, "U2"}, {DIFF_U3, "U3"}, {DIFF_C2, "C2"}, {DIFF_C4, "C4"}, {DIFF_S2, "S2"}, {DIFF_W2, "W2"}, {DIFF_W3, "W3"}, {DIFF_FFT, "FFT"}, diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index fb967e6245..008fcfd407 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -138,6 +138,10 @@ static DiffNameLookup DiffNameTable[] = { /// Initialise the derivative methods. Must be called before any derivatives are used void Mesh::derivs_init(Options *options) { TRACE("Initialising derivatives"); + // For each direction need to set what the default method is for each type + // of derivative. + DerivativeStore::getInstance().initialise(options); + DerivativeStore::getInstance().initialise(options); // Get the fraction of modes filtered out in FFT derivatives options->getSection("ddz")->get("fft_filter", fft_derivs_filter, 0.0); } From 748b720596e0be53c9e4dfda809f327a4d46e67e Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 14:41:24 +0000 Subject: [PATCH 0197/1783] Make a couple of mesh helpers public --- include/bout/mesh.hxx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 28fa5cd5c0..398c90e578 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -454,6 +454,15 @@ class Mesh { STAGGER getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc) const; STAGGER getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc) const; + template + CELL_LOC getAllowedStaggerLoc() const; + + template + int getNpoints() const; + + template + int getNguard() const; + template T indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const; @@ -525,9 +534,6 @@ class Mesh { T indexFDDZ(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY) const; - template - int getNguard() const; - /// Transform a field into field-aligned coordinates const Field3D toFieldAligned(const Field3D &f) { return getParallelTransform().toFieldAligned(f); @@ -649,12 +655,6 @@ class Mesh { /// Initialise derivatives void derivs_init(Options* options); - - template - CELL_LOC getAllowedStaggerLoc() const; - - template - int getNpoints() const; private: /// Allocates default Coordinates objects From d33038d8ff660ae715f1750d94c7431eb6fda9a8 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 14:41:41 +0000 Subject: [PATCH 0198/1783] Initial stab at adding back FFT methods --- include/bout/derivs.hxx | 146 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index aad73b278e..90c9a95c74 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -526,4 +526,150 @@ produceCombinations, DerivativeType>> registerStaggeredDerivatives(registerMethod{}); + +class FFTDerivativeType { +public: + template + void standard(const T &var, T &result, const REGION region) const { + TRACE("%s",__thefunc__); + ASSERT2(meta.derivType == DERIV::Standard) + ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); + ASSERT2(direction == DIRECTION::Z); //Only in Z for now + ASSERT2(stagger == STAGGER::None); //Staggering not currently supported + ASSERT2((std::is_base_of::value)); //Should never need to call this with Field2D + + const auto region_str = REGION_STRING(region); + + // Only allow a whitelist of regions for now + ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" || + region_str == "RGN_NOX" || region_str == "RGN_NOY"); + + auto *theMesh = var.getMesh(); + + // Calculate how many Z wavenumbers will be removed + const int ncz = theMesh->template getNpoints(); + + int kfilter = + static_cast(theMesh->fft_derivs_filter * ncz / 2); // truncates, rounding down + if (kfilter < 0) + kfilter = 0; + if (kfilter > (ncz / 2)) + kfilter = ncz / 2; + const int kmax = ncz / 2 - kfilter; // Up to and including this wavenumber index + + BOUT_OMP(parallel) + { + Array cv(ncz / 2 + 1); + const BoutReal kwaveFac = TWOPI / ncz; + + // Note we lookup a 2D region here even though we're operating on a Field3D + // as we only want to loop over {x, y} and then handle z differently. The + // Region blocks are constructed for elements contiguous assuming nz=1, + // as that isn't the case for Field3D (in general) this shouldn't be expected + // to vectorise (not that it would anyway) but it should still OpenMP parallelise + // ok. + // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro + // here, + // but should be ok for now. + BOUT_FOR_INNER(i, theMesh->getRegion2D(region_str)) { + auto i3D = theMesh->ind2Dto3D(i, 0); + rfft(&var[i3D], ncz, cv.begin()); // Forward FFT + + for (int jz = 0; jz <= kmax; jz++) { + const BoutReal kwave = jz * kwaveFac; // wave number is 1/[rad] + cv[jz] *= dcomplex(0, kwave); + } + for (int jz = kmax + 1; jz <= ncz / 2; jz++) { + cv[jz] = 0.0; + } + + irfft(cv.begin(), ncz, &result[i3D]); // Reverse FFT + } + } + + return; + } + + template + void upwindOrFlux(const T &vel, const T &var, T &result, const REGION region) const { + TRACE("%s",__thefunc__); + throw BoutException("The FFT METHOD isn't available in upwind/Flux"); + return; + } + metaData meta{"FFT", 0, DERIV::Standard}; +}; + + +class FFT2ndDerivativeType { +public: + template + void standard(const T &var, T &result, const REGION region) const { + TRACE("%s",__thefunc__); + ASSERT2(meta.derivType == DERIV::Standard) + ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); + ASSERT2(direction == DIRECTION::Z); //Only in Z for now + ASSERT2(stagger == STAGGER::None); //Staggering not currently supported + ASSERT2((std::is_base_of::value)); //Should never need to call this with Field2D + + const auto region_str = REGION_STRING(region); + + // Only allow a whitelist of regions for now + ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" || + region_str == "RGN_NOX" || region_str == "RGN_NOY"); + + auto *theMesh = var.getMesh(); + + // Calculate how many Z wavenumbers will be removed + const int ncz = theMesh->template getNpoints(); + const int kmax = ncz/2; + + BOUT_OMP(parallel) + { + Array cv(ncz / 2 + 1); + const BoutReal kwaveFac = TWOPI / ncz; + + // Note we lookup a 2D region here even though we're operating on a Field3D + // as we only want to loop over {x, y} and then handle z differently. The + // Region blocks are constructed for elements contiguous assuming nz=1, + // as that isn't the case for Field3D (in general) this shouldn't be expected + // to vectorise (not that it would anyway) but it should still OpenMP parallelise + // ok. + // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro + // here, + // but should be ok for now. + BOUT_FOR_INNER(i, theMesh->getRegion2D(region_str)) { + auto i3D = theMesh->ind2Dto3D(i, 0); + rfft(&var[i3D], ncz, cv.begin()); // Forward FFT + + for (int jz = 0; jz <= kmax; jz++) { + const BoutReal kwave = jz * kwaveFac; // wave number is 1/[rad] + cv[jz] *= -kwave*kwave; + } + for (int jz = kmax + 1; jz <= ncz / 2; jz++) { + cv[jz] = 0.0; + } + + irfft(cv.begin(), ncz, &result[i3D]); // Reverse FFT + } + } + + return; + } + + template + void upwindOrFlux(const T &vel, const T &var, T &result, const REGION region) const { + TRACE("%s",__thefunc__); + throw BoutException("The FFT METHOD isn't available in upwind/Flux"); + return; + } + metaData meta{"FFT", 0, DERIV::StandardSecond}; +}; + + +produceCombinations< + Set, Set, Set, + Set + > + registerFFTDerivative(registerMethod{}); + #endif From cd75d1cb342f4d86df16e82593daf94facb87885 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 16:22:19 +0000 Subject: [PATCH 0199/1783] Adding some checking to the inner derivative functions --- include/bout/mesh.hxx | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 398c90e578..3474bd7922 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -759,6 +759,8 @@ T Mesh::indexFDDZ(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, template T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { + TRACE("%s", __thefunc__); + // Checks static_assert(std::is_base_of::value || std::is_base_of::value, "indexDDX only works on Field2D or Field3D input"); @@ -768,6 +770,13 @@ T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METH // Check that the input variable has data ASSERT1(f.isAllocated()); ASSERT1(vel.isAllocated()); + + //Check the input data is valid + { + TRACE("Checking inputs"); + checkData(f); + checkData(vel); + } // Define properties of this approach const CELL_LOC allowedStaggerLoc = getAllowedStaggerLoc(); @@ -807,11 +816,19 @@ T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METH // Apply method derivativeMethod(vel, f, result, region); + //Check the result is valid + { + TRACE("Checking result"); + checkData(result); + } + return result; } template T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { + TRACE("%s", __thefunc__); + // Checks static_assert(std::is_base_of::value || std::is_base_of::value, "indexDDX only works on Field2D or Field3D input"); @@ -820,6 +837,12 @@ T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, // Check that the input variable has data ASSERT1(f.isAllocated()); + //Check the input data is valid + { + TRACE("Checking input"); + checkData(f); + } + // Define properties of this approach const CELL_LOC allowedStaggerLoc = getAllowedStaggerLoc(); @@ -860,6 +883,12 @@ T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, // Apply method derivativeMethod(f, result, region); + //Check the result is valid + { + TRACE("Checking result"); + checkData(result); + } + return result; } From 8c3907b883c717ebf3dca2b9242117059849f8b2 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 16:23:07 +0000 Subject: [PATCH 0200/1783] Fixing derivatives to use the correct number of guard cells. --- include/bout/derivs.hxx | 50 ++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index 90c9a95c74..acc966c3ef 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -47,8 +47,18 @@ public: meta.derivType == DERIV::StandardFourth) ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(var, i)); + // For now use a runtime check on the required number of guards to pick + // how we call populateStencil. In future it would be nice to be able + // to replace 1/2 with a constexpr of some form (can do it now if + // meta didn't contain a string). + if(meta.nGuards == 1) { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(var, i)); + } + } else { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(var, i)); + } } return; } @@ -60,13 +70,26 @@ public: ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); if (meta.derivType == DERIV::Flux || stagger != STAGGER::None) { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(vel, i), - populateStencil(var, i)); + if(meta.nGuards == 1) { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(vel, i), + populateStencil(var, i)); + } + } else { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(vel, i), + populateStencil(var, i)); + } } } else { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(vel[i], populateStencil(var, i)); + if(meta.nGuards == 1) { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(vel[i], populateStencil(var, i)); + } + } else { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(vel[i], populateStencil(var, i)); + } } } return; @@ -76,14 +99,14 @@ public: BoutReal apply(const BoutReal &v, const stencil &f) const { return func(v, f); } BoutReal apply(const stencil &v, const stencil &f) const { return func(v, f); } - FF func{}; - metaData meta = func.meta; + const FF func{}; + const metaData meta = func.meta; }; #define DEFINE_STANDARD_DERIV(name, key, nGuards, type) \ struct name { \ BoutReal operator()(const stencil &f) const; \ - metaData meta = {key, nGuards, type}; \ + const metaData meta = {key, nGuards, type}; \ BoutReal operator()(const BoutReal &UNUSED(vc),\ const stencil &UNUSED(f)) const {return BoutNaN;}; \ BoutReal operator()(const stencil &UNUSED(v),\ @@ -97,7 +120,7 @@ public: BoutReal operator()(const BoutReal &vc, const stencil &f) const; \ BoutReal operator()(const stencil &UNUSED(v),\ const stencil &UNUSED(f)) const {return BoutNaN;}; \ - metaData meta = {key, nGuards, type}; \ + const metaData meta = {key, nGuards, type}; \ }; \ BoutReal name::operator()(const BoutReal &vc, const stencil &f) const @@ -107,7 +130,7 @@ public: BoutReal operator()(const BoutReal &UNUSED(vc),\ const stencil &UNUSED(f)) const {return BoutNaN;}; \ BoutReal operator()(const stencil &v, const stencil &f) const; \ - metaData meta = {key, nGuards, type}; \ + const metaData meta = {key, nGuards, type}; \ }; \ BoutReal name::operator()(const stencil &v, const stencil &f) const @@ -438,7 +461,8 @@ struct registerMethod { TRACE("%s", __thefunc__); using namespace std::placeholders; - auto derivativeRegister = DerivativeStore{}.getInstance(); + auto derivativeRegister = DerivativeStore::getInstance(); + switch (Method{}.meta.derivType) { case (DERIV::Standard): case (DERIV::StandardSecond): From 3c1ac093cf8954dc4dad6b743697321b1ead7e14 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 16:34:17 +0000 Subject: [PATCH 0201/1783] Remove no longer valid unit tests --- tests/unit/mesh/test_mesh.cxx | 118 ---------------------------------- 1 file changed, 118 deletions(-) diff --git a/tests/unit/mesh/test_mesh.cxx b/tests/unit/mesh/test_mesh.cxx index a231f4dcb9..e428f2551c 100644 --- a/tests/unit/mesh/test_mesh.cxx +++ b/tests/unit/mesh/test_mesh.cxx @@ -156,121 +156,3 @@ TEST_F(MeshTest, Ind3DToPerp) { } } } - -extern Mesh::deriv_func fDDX, fDDY, fDDZ; ///< Differencing methods for each dimension -extern Mesh::deriv_func fD2DX2, fD2DY2, fD2DZ2; ///< second differential operators -extern Mesh::upwind_func fVDDX, fVDDY, fVDDZ; ///< Upwind functions in the three directions -extern Mesh::flux_func fFDDX, fFDDY, fFDDZ; ///< Default flux functions -extern Mesh::deriv_func sfDDX, sfDDY, sfDDZ; -extern Mesh::deriv_func sfD2DX2, sfD2DY2, sfD2DZ2; -extern Mesh::flux_func sfVDDX, sfVDDY, sfVDDZ; -extern Mesh::flux_func sfFDDX, sfFDDY, sfFDDZ; - -#define RESET \ - fDDX=nullptr; fDDY=nullptr; fDDZ=nullptr; \ - fD2DX2=nullptr; fD2DY2=nullptr; fD2DZ2=nullptr; \ - fVDDX=nullptr; fVDDY=nullptr; fVDDZ=nullptr; \ - fFDDX=nullptr; fFDDY=nullptr; fFDDZ=nullptr; \ - sfDDX=nullptr; sfDDY=nullptr; sfDDZ=nullptr; \ - sfD2DX2=nullptr; sfD2DY2=nullptr; sfD2DZ2=nullptr; \ - sfVDDX=nullptr; sfVDDY=nullptr; sfVDDZ=nullptr; \ - sfFDDX=nullptr; sfFDDY=nullptr; sfFDDZ=nullptr; - - -BoutReal DDX_C2(stencil &f); -BoutReal DDX_C4(stencil &f); -BoutReal DDX_CWENO2(stencil &f); -BoutReal DDX_S2(stencil &f); -BoutReal VDDX_C2(BoutReal vc, stencil &f); -BoutReal VDDX_C4(BoutReal vc, stencil &f); -BoutReal VDDX_U1(BoutReal vc, stencil &f); -BoutReal VDDX_U2(BoutReal vc, stencil &f); -BoutReal VDDX_U3(BoutReal vc, stencil &f); -BoutReal VDDX_WENO3(BoutReal vc, stencil &f); -BoutReal DDX_CWENO3(stencil &f); -BoutReal FDDX_U1(stencil &v, stencil &f); -BoutReal FDDX_C2(stencil &v, stencil &f); -BoutReal FDDX_C4(stencil &v, stencil &f); -BoutReal DDX_C2_stag(stencil &f); -BoutReal DDX_C4_stag(stencil &f); -BoutReal VDDX_U1_stag(stencil &v, stencil &f); -BoutReal VDDX_U2_stag(stencil &v, stencil &f); -BoutReal VDDX_C2_stag(stencil &v, stencil &f); -BoutReal VDDX_C4_stag(stencil &v, stencil &f); -BoutReal FDDX_U1_stag(stencil &v, stencil &f); - -TEST_F(MeshTest, SetDerivativesDefault) { - RESET - Options opt; - localmesh.initDerivs(&opt); - EXPECT_EQ(fDDX,&DDX_C2); - EXPECT_EQ(sfDDX,&DDX_C2_stag); -} - -TEST_F(MeshTest, SetDerivativesDiff) { - RESET - Options opt; - opt.getSection("diff")->set("first","C4","test"); - localmesh.initDerivs(&opt); - EXPECT_EQ(fDDY,&DDX_C4); - EXPECT_EQ(sfDDY,&DDX_C4_stag); -} - -TEST_F(MeshTest, SetDerivativesDiffStag) { - RESET - Options opt; - opt.getSection("diff")->set("first","C2","test"); - opt.getSection("diff")->set("firstStag","C4","test"); - localmesh.initDerivs(&opt); - EXPECT_EQ(fDDZ,&DDX_C2); - EXPECT_EQ(sfDDZ,&DDX_C4_stag); -} - -TEST_F(MeshTest, SetDerivativesDdxBeforeDiff) { - RESET - Options opt; - opt.getSection("diff")->set("firstStag","C4","test"); - opt.getSection("ddx")->set("firstStag","C2","test"); - localmesh.initDerivs(&opt); - EXPECT_EQ(sfDDZ,&DDX_C4_stag); - EXPECT_EQ(sfDDX,&DDX_C2_stag); -} - -TEST_F(MeshTest, SetDerivativesDiffStagBeforeDDXNone) { - RESET - Options opt; - opt.getSection("diff")->set("firstStag","C4","test"); - opt.getSection("ddx")->set("first","C2","test"); - localmesh.initDerivs(&opt); - EXPECT_EQ(sfDDX,&DDX_C4_stag); -} - -TEST_F(MeshTest, SetDerivativesInvalid) { - RESET - Options opt; - // An invalid but unused option is fine - opt.getSection("diff")->set("firstStag","XXX","test"); - opt.getSection("ddx")->set("firstStag","C2","test"); - opt.getSection("ddy")->set("firstStag","C2","test"); - opt.getSection("ddz")->set("firstStag","C2","test"); - localmesh.initDerivs(&opt); - EXPECT_EQ(sfDDX,&DDX_C2_stag); -} - -TEST_F(MeshTest, SetDerivativesInvalid2) { - RESET - Options opt; - opt.getSection("diff")->set("firstStag","XXX","test"); - EXPECT_THROW(localmesh.initDerivs(&opt),BoutException); -} - -TEST_F(MeshTest, SetDerivativesInvalid3) { - RESET - Options opt; - // Invalid for this option - expect error - opt.getSection("diff")->set("SecondStag","C4","test"); - EXPECT_THROW(localmesh.initDerivs(&opt),BoutException); -} - - -#undef RESET From 6b598e188f860053e4bbba03921f4e18dd8849aa Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 16:50:20 +0000 Subject: [PATCH 0202/1783] Provide a simple struct that can be used as a TypeContainer This can be useful in passing around types with creating instances of the type of interest (instead we create instances of this TypeContainer, which themselves can be used to create instances of the actual type as and when required). --- include/bout/template_combinations.hxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/bout/template_combinations.hxx b/include/bout/template_combinations.hxx index ff76923d84..97a4774af0 100644 --- a/include/bout/template_combinations.hxx +++ b/include/bout/template_combinations.hxx @@ -9,6 +9,11 @@ /// distinguish between different template packs. template struct Set {}; +/// Here we provide a container type that can be used to pass around +/// a type without needing to create instances of the specific type +/// (instead we create instances of the container type). +template struct TypeContainer{ using type = T; }; + /// Define a struct (functor) that we use to build up the final /// collection of template values. Each time we create one of these /// objects we provide one more type to the templatePack. We may call From b9707d8ba573352e417949aec1a982b0a3464b84 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 17:01:34 +0000 Subject: [PATCH 0203/1783] Wrap the field type in a TypeContainer for template combinations Helps to avoid creating empty field instances during the derivative method procedure, which helps to avoid checkData failing due to copying empty fields. --- include/bout/derivs.hxx | 102 ++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index acc966c3ef..1b31672b8e 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -456,11 +456,16 @@ DEFINE_FLUX_DERIV_STAGGERED(FDDX_U1_stag, "U1", 1, DERIV::Flux) { ///////////////////////////////////////////////////////////////////////////////// struct registerMethod { - template - void operator()(Direction, Stagger, FieldType, Method) { + template + void operator()(Direction, Stagger, FieldTypeContainer, Method) { TRACE("%s", __thefunc__); using namespace std::placeholders; + // Now we want to get the actual field type out of the TypeContainer + // used to pass this around + using FieldType = typename FieldTypeContainer::type; + + auto derivativeRegister = DerivativeStore::getInstance(); switch (Method{}.meta.derivType) { @@ -469,7 +474,7 @@ struct registerMethod { case (DERIV::StandardFourth): { const auto theFunc = std::bind( // Method to store in function - &Method::template standard, + &Method::template standard, // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region Method{}, _1, _2, _3); @@ -480,7 +485,7 @@ struct registerMethod { case (DERIV::Flux): { const auto theFunc = std::bind( // Method to store in function - &Method::template upwindOrFlux, + &Method::template upwindOrFlux, // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region Method{}, _1, _2, _3, _4); @@ -503,53 +508,56 @@ struct registerMethod { ///////////////////////////////////////////////////////////////////////////////// // Could use Ben's magic macro for thing here to register multiple routines at once -#define REGISTER_DERIVATIVE(name) \ - namespace { \ - produceCombinations, \ - Set, Set, \ - Set>> \ - reg(registerMethod{}); \ +#define REGISTER_DERIVATIVE(name) \ + namespace { \ + produceCombinations, \ + Set, \ + Set, TypeContainer>, \ + Set>> \ + reg(registerMethod{}); \ } -#define REGISTER_STAGGERED_DERIVATIVE(name) \ - namespace { \ - produceCombinations, \ - Set, Set, \ - Set>> \ - reg(registerMethod{}); \ +#define REGISTER_STAGGERED_DERIVATIVE(name) \ + namespace { \ + produceCombinations, \ + Set, \ + Set, TypeContainer>, \ + Set>> \ + reg(registerMethod{}); \ } produceCombinations< - Set, Set, - Set, - Set< - // Standard - DerivativeType, DerivativeType, DerivativeType, - DerivativeType, DerivativeType, - // Standard 2nd order - DerivativeType, DerivativeType, - // Standard 4th order - DerivativeType, - // Upwind - DerivativeType, DerivativeType, DerivativeType, - DerivativeType, DerivativeType, DerivativeType, - // Flux - DerivativeType, DerivativeType, DerivativeType>> - registerDerivatives(registerMethod{}); - -produceCombinations, - Set, Set, - Set< - // Standard - DerivativeType, DerivativeType, - // Standard 2nd order - DerivativeType, - // Upwind - DerivativeType, DerivativeType, - DerivativeType, DerivativeType, - // Flux - DerivativeType>> - registerStaggeredDerivatives(registerMethod{}); + Set, Set, + Set, TypeContainer>, + Set< + // Standard + DerivativeType, DerivativeType, DerivativeType, + DerivativeType, DerivativeType, + // Standard 2nd order + DerivativeType, DerivativeType, + // Standard 4th order + DerivativeType, + // Upwind + DerivativeType, DerivativeType, DerivativeType, + DerivativeType, DerivativeType, DerivativeType, + // Flux + DerivativeType, DerivativeType, DerivativeType>> +registerDerivatives(registerMethod{}); +produceCombinations< + Set, + Set, + Set, TypeContainer>, + Set< + // Standard + DerivativeType, DerivativeType, + // Standard 2nd order + DerivativeType, + // Upwind + DerivativeType, DerivativeType, + DerivativeType, DerivativeType, + // Flux + DerivativeType>> +registerStaggeredDerivatives(registerMethod{}); class FFTDerivativeType { public: @@ -691,7 +699,7 @@ public: produceCombinations< - Set, Set, Set, + Set, Set, Set>, Set > registerFFTDerivative(registerMethod{}); From 47125d128702098c8405338fbf6ae573baf1b12c Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 1 Nov 2018 17:42:54 +0000 Subject: [PATCH 0204/1783] Make install work with locales - localedir used in bout++.cxx to set path. If `make install` is used then this will be correct, but otherwise `localedir` needs to be set at configure time. - `make install` now finds all locale .mo files and installs them. Modest amounts of Makefile / shell magic needed. - Updated manual, with small sections in install and running user guide, and a section in the developer guides on adding languages. --- configure | 4 +-- configure.ac | 2 +- include/bout/sys/gettext.hxx | 4 ++- locale/libbout.pot | 4 --- make.config.in | 13 ++++--- .../developer_docs/natural_language.rst | 32 +++++++++++++++++ manual/sphinx/index.rst | 1 + manual/sphinx/user_docs/installing.rst | 20 +++++++++++ manual/sphinx/user_docs/running_bout.rst | 36 ++++++------------- src/bout++.cxx | 34 +++++++++--------- 10 files changed, 93 insertions(+), 57 deletions(-) create mode 100644 manual/sphinx/developer_docs/natural_language.rst diff --git a/configure b/configure index d7205eb1f1..2fdab25691 100755 --- a/configure +++ b/configure @@ -17107,8 +17107,8 @@ $as_echo "$as_me: Lapack support : $HAS_LAPACK" >&6;} $as_echo "$as_me: Scorep support : $HAS_SCOREP" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: OpenMP support : $HAS_OPENMP (schedule: $OPENMP_SCHEDULE)" >&5 $as_echo "$as_me: OpenMP support : $HAS_OPENMP (schedule: $OPENMP_SCHEDULE)" >&6;} -{ $as_echo "$as_me:${as_lineno-$LINENO}: Natural language support: $HAS_NLS" >&5 -$as_echo "$as_me: Natural language support: $HAS_NLS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Natural language support: $HAS_NLS (path: $localedir)" >&5 +$as_echo "$as_me: Natural language support: $HAS_NLS (path: $localedir)" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: " >&5 $as_echo "$as_me: " >&6;} diff --git a/configure.ac b/configure.ac index 8451b37c3e..d39b91cb8c 100644 --- a/configure.ac +++ b/configure.ac @@ -1299,7 +1299,7 @@ AC_MSG_NOTICE([ MUMPS support : $HAS_MUMPS]) AC_MSG_NOTICE([ Lapack support : $HAS_LAPACK]) AC_MSG_NOTICE([ Scorep support : $HAS_SCOREP]) AC_MSG_NOTICE([ OpenMP support : $HAS_OPENMP (schedule: $OPENMP_SCHEDULE)]) -AC_MSG_NOTICE([ Natural language support: $HAS_NLS]) +AC_MSG_NOTICE([ Natural language support: $HAS_NLS (path: $localedir)]) AC_MSG_NOTICE([]) AC_MSG_NOTICE([-------------------------------]) diff --git a/include/bout/sys/gettext.hxx b/include/bout/sys/gettext.hxx index 6baa49b5c7..3546921f3b 100644 --- a/include/bout/sys/gettext.hxx +++ b/include/bout/sys/gettext.hxx @@ -8,7 +8,9 @@ #include #include -#define _(string) gettext(string) +#define GETTEXT_PACKAGE "libbout" + +#define _(string) dgettext(GETTEXT_PACKAGE, string) #else diff --git a/locale/libbout.pot b/locale/libbout.pot index b7f5ac2001..1c7477d90b 100644 --- a/locale/libbout.pot +++ b/locale/libbout.pot @@ -328,10 +328,6 @@ msgstr "" msgid "Failed to initialise solver-> Aborting\n" msgstr "" -#: ../tests/integrated/test-i18n/test-i18n.cxx:15 -msgid "Hello World\n" -msgstr "" - #: ../src/solver/solver.cxx:599 msgid "Initialising solver\n" msgstr "" diff --git a/make.config.in b/make.config.in index 12625ed512..d9e70f9ee2 100644 --- a/make.config.in +++ b/make.config.in @@ -28,9 +28,11 @@ SLEPC_ARCH ?= @SLEPC_ARCH@ # They are used in the CXXFLAGS variable below rather than hard-coding the directories BOUT_INCLUDE_PATH=$(BOUT_TOP)/include BOUT_LIB_PATH=$(BOUT_TOP)/lib -BOUT_LOCALE_PATH=$(realpath $(BOUT_TOP)/locale/) BOUT_CONFIG_FILE=$(BOUT_TOP)/make.config +# This path to the locale (.mo) files is hard-wired into bout++.cxx at compile time +BOUT_LOCALE_PATH=@localedir@ + # Created this variable so that a user won't overwrite the CXXFLAGS variable # on the command line, just add to this one BOUT_FLAGS = $(CXXFLAGS) @CXXFLAGS@ @OPENMP_CXXFLAGS@ @CXX11_FLAGS@ @COVERAGE_FLAGS@ @@ -151,6 +153,9 @@ INSTALL_DATA = ${INSTALL} -m 644 INSTALL_INCLUDE_PATH = $(DESTDIR)@includedir@/bout++/ +# A list of relative paths e.g. "fr/LC_MESSAGES/libbout.mo zh_CN/LC_MESSAGES/libbout.mo" +MO_FILES = $(shell cd locale; ls */LC_MESSAGES/libbout.mo) + install: libfast $(PRE_INSTALL) # Pre-install commands follow. @@ -173,10 +178,7 @@ install: libfast $(INSTALL_DATA) tools/pylib/boutdata/*.py $(DESTDIR)@datadir@/bout++/pylib/boutdata/ $(INSTALL_DATA) tools/pylib/boututils/*.py $(DESTDIR)@datadir@/bout++/pylib/boututils/ $(INSTALL_DATA) make.config $(DESTDIR)@datadir@/bout++/ - $(INSTALL_DATA) locale/fr/LC_MESSAGES/libbout.mo $(DESTDIR)@localedir@/fr/LC_MESSAGES/ - $(INSTALL_DATA) locale/zh_TW/LC_MESSAGES/libbout.mo $(DESTDIR)@localedir@/zh_TW/LC_MESSAGES/ - $(INSTALL_DATA) locale/zh_CN/LC_MESSAGES/libbout.mo $(DESTDIR)@localedir@/zh_CN/LC_MESSAGES/ - + for mo in $(MO_FILES); do $(MKDIR) $(DESTDIR)@localedir@/`dirname $$mo`; $(INSTALL_DATA) locale/$$mo $(DESTDIR)@localedir@/$$mo; done $(POST_INSTALL) # Post-install commands follow. @# Modify paths in the bout-config script @@ -205,6 +207,7 @@ uninstall: $(RM) $(DESTDIR)@libdir@/libpvode.a $(RM) $(DESTDIR)@libdir@/libpvpre.a $(RM) -r $(DESTDIR)@includedir@/bout++/ + $(RM) $(DESTDIR)@localedir@/*/LC_MESSAGES/libbout.mo $(POST_UNINSTALL) # Post-uninstall commands follow. diff --git a/manual/sphinx/developer_docs/natural_language.rst b/manual/sphinx/developer_docs/natural_language.rst new file mode 100644 index 0000000000..55e05af47c --- /dev/null +++ b/manual/sphinx/developer_docs/natural_language.rst @@ -0,0 +1,32 @@ +Natural Language Support +======================== + +BOUT++ uses GNU ``gettext`` to provide translations of output strings. +Configuration is described in :ref:`sec-config-nls` and running in +:ref:`sec-run-nls`. + +Adding support for a new language, or improving the translations in +the existing files can be done by: + +1. Going to the ``locale`` BOUT++ subdirectory and running:: + + make locale-ll + + where ``ll`` is the language code e.g. ``make locale-de``. This + will create a file ``libbout.po`` under a ``locale/ll`` + subdirectory. +2. Edit the ``locale/ll/libbout.po`` file. Edit the .po file in de + subdirectory (not the .pot file!), adding the translations. Each + ``msgid`` entry should have a translated ``msgstr`` entry. If you + don't want to translate them all, just delete the ones you don't + translate. Any missing will just revert to the version in the + code. If you're adding UTF-8 characters, change the content line in + the .po file to have charset=UTF-8. +3. In the ``locale`` directory run ``make``. This should output + something like:: + + Building language: fr + Building language: zh_CN + Building language: zh_TW + +The new language should now be available (no need to recompile BOUT++). diff --git a/manual/sphinx/index.rst b/manual/sphinx/index.rst index 51ef1d193b..1522f105bc 100644 --- a/manual/sphinx/index.rst +++ b/manual/sphinx/index.rst @@ -89,6 +89,7 @@ The documentation is divided into the following sections: developer_docs/data_types developer_docs/mesh developer_docs/file_io + developer_docs/natural_language api_reference diff --git a/manual/sphinx/user_docs/installing.rst b/manual/sphinx/user_docs/installing.rst index 8f433d45eb..a39bfae310 100644 --- a/manual/sphinx/user_docs/installing.rst +++ b/manual/sphinx/user_docs/installing.rst @@ -274,6 +274,26 @@ configuration:: If not, see :ref:`sec-advancedinstall` for some things you can try to resolve common problems. +.. _sec-config-nls: + +Natural Language Support +------------------------ + +BOUT++ has support for languages other than English, using GNU +gettext. If you are planning on installing BOUT++ (see +:ref:`sec-install-bout`) then this should work automatically, but if +you will be running BOUT++ from the directory you downloaded it into, +then configure with the option:: + + ./configure --localedir=$PWD/locale + +This will enable BOUT++ to find the translations. When ``configure`` +finishes, the configuration summary should contain a line like:: + + configure: Natural language support: yes (path: /home/user/BOUT-dev/locale) + +where the ``path`` is the directory containing the translations. + .. _sec-configanalysis: Configuring analysis routines diff --git a/manual/sphinx/user_docs/running_bout.rst b/manual/sphinx/user_docs/running_bout.rst index 8f201279d6..228e802a6e 100644 --- a/manual/sphinx/user_docs/running_bout.rst +++ b/manual/sphinx/user_docs/running_bout.rst @@ -210,43 +210,27 @@ and to make this a coloured contour plot The equivalent commands in Python are as follows. +.. _sec-run-nls: Natural language support ------------------------ -BOUT++ has support for languages other than English, using GNU -gettext. If you have locales installed, then the ``LANG`` environment +If you have locales installed, and configured the ``locale`` path +correctly (see :ref:`sec-config-nls`), then the ``LANG`` environment variable selects the language to use. Currently BOUT++ only has limited support for ``fr``, ``zh_TW`` and ``zh_CN`` locales e.g. :: LANG=zh_TW.utf8 ./conduction -Adding support for a new language, or improving the translations in -the existing files can be done by: +which should produce an output like:: -1. Going to the ``locale`` BOUT++ subdirectory and running:: - - make locale-ll - - where ``ll`` is the language code e.g. ``make locale-de``. This - will create a file ``libbout.po`` under a ``locale/ll`` - subdirectory. -2. Edit the ``locale/ll/libbout.po`` file. Edit the .po file in de - subdirectory (not the .pot file!), adding the translations. Each - ``msgid`` entry should have a translated ``msgstr`` entry. If you - don't want to translate them all, just delete the ones you don't - translate. Any missing will just revert to the version in the - code. If you're adding UTF-8 characters, change the content line in - the .po file to have charset=UTF-8. -3. In the ``locale`` directory run ``make``. This should output - something like:: - - Building language: fr - Building language: zh_CN - Building language: zh_TW - -The new language should now be available (no need to recompile BOUT++). + BOUT++ 版 4.2.0 + 版: dc95c252d9447ca72d27d4cc0d30f4d9c8a91a41 + MD5 checksum: 086b600cc54f9c0eb0ee9338dbba71a6 + 代碼於 Nov 1 2018 17:41:02 编译 + ... + Further examples ---------------- diff --git a/src/bout++.cxx b/src/bout++.cxx index d62e7ef148..e63d8b986b 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -30,22 +30,13 @@ const char DEFAULT_OPT[] = "BOUT.inp"; const char DEFAULT_SET[] = "BOUT.settings"; const char DEFAULT_LOG[] = "BOUT.log"; -#define CMDLINE1_(x) #x -#define CMDLINE(x) CMDLINE1_(x) - -// MD5 Checksum passed at compile-time -#define CHECKSUM1_(x) #x -#define CHECKSUM_(x) CHECKSUM1_(x) -#define CHECKSUM CHECKSUM_(MD5SUM) - -// Revision passed at compile time -#define REV1_(x) #x -#define REV_(x) REV1_(x) -#define REV REV_(REVISION) +// Value passed at compile time +// Used for MD5SUM, BOUT_LOCALE_PATH, and REVISION +#define BUILDFLAG1_(x) #x +#define BUILDFLAG(x) BUILDFLAG1_(x) #define GLOBALORIGIN - #define INDIRECT1_BOUTMAIN(a) #a #define INDIRECT0_BOUTMAIN(...) INDIRECT1_BOUTMAIN(#__VA_ARGS__) #define STRINGIFY(a) INDIRECT0_BOUTMAIN(a) @@ -146,16 +137,23 @@ int BoutInitialise(int &argc, char **&argv) { #if BOUT_HAS_GETTEXT // Setting the i18n environment + // + // For libraries: + // https://www.gnu.org/software/gettext/manual/html_node/Libraries.html + // try { // Note: Would like to use std::locale::global // std::locale::global(std::locale("")); // but the Numeric aspect causes problems parsing input strings + // + // Note: Since BOUT++ is a library, it shouldn't really call setlocale; + // that should be part of main(). std::setlocale(LC_ALL, ""); std::setlocale(LC_NUMERIC, "C"); - bindtextdomain ("libbout", CMDLINE(BOUT_LOCALE_PATH)); - textdomain ("libbout"); - fprintf(stderr, "LOCALE_PATH = '%s'\n", CMDLINE(BOUT_LOCALE_PATH)); + bindtextdomain (GETTEXT_PACKAGE, BUILDFLAG(BOUT_LOCALE_PATH)); + + fprintf(stderr, "LOCALE_PATH = '%s'\n", BUILDFLAG(BOUT_LOCALE_PATH)); } catch (const std::runtime_error &e) { fprintf(stderr, "WARNING: Could not set locale. Try a different LANG setting\n"); } @@ -349,10 +347,10 @@ int BoutInitialise(int &argc, char **&argv) { /// Print intro output_progress.write(_("BOUT++ version %s\n"), BOUT_VERSION_STRING); #ifdef REVISION - output_progress.write(_("Revision: %s\n"), REV); + output_progress.write(_("Revision: %s\n"), BUILDFLAG(REVISION)); #endif #ifdef MD5SUM - output_progress.write("MD5 checksum: %s\n", CHECKSUM); + output_progress.write("MD5 checksum: %s\n", BUILDFLAG(MD5SUM)); #endif output_progress.write(_("Code compiled on %s at %s\n\n"), __DATE__, __TIME__); output_info.write("B.Dudson (University of York), M.Umansky (LLNL) 2007\n"); From 4b192b996f1d41980881c71fcf6caa14eed594c3 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 19:10:54 +0000 Subject: [PATCH 0205/1783] Tidy up the mesh header a bit to reduce duplication --- include/bout/mesh.hxx | 263 +++++++++++++++++++----------------------- 1 file changed, 116 insertions(+), 147 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 3474bd7922..2d816aedd1 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -446,63 +446,102 @@ class Mesh { } } - // First derivatives in index space - // Implemented in src/mesh/index_derivs.hxx - - BoutReal fft_derivs_filter; ///< Fraction of modes to filter. This is set in derivs_init from option "ddz:fft_filter" - - STAGGER getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc) const; - STAGGER getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc) const; - + /// Returns the non-CELL_CENTRE location + /// allowed as a staggered location template CELL_LOC getAllowedStaggerLoc() const; + /// Returns the number of grid points in the + /// particular direction template int getNpoints() const; + /// Returns the number of guard points in the + /// particular direction template int getNguard() const; + /////////////////////////////////////////////////////////// + // INDEX DERIVATIVE OPERATORS + /////////////////////////////////////////////////////////// + + ////// Utilties and parameters + + BoutReal fft_derivs_filter; ///< Fraction of modes to filter. This is set in derivs_init from option "ddz:fft_filter" + + /// Determines the resultant output stagger location in derivatives + /// given the input and output location. Also checks that the + /// combination of locations is allowed + STAGGER getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc) const; + + /// Determines the resultant output stagger location in derivatives + /// given the input and output location. Also checks that the + /// combination of locations is allowed. This overload also checks + /// the location of a second input field (velocity) is consistent. + STAGGER getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc) const; + + ////// STANDARD OPERATORS + + /// The main kernel used for all standard derivatives template T indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const; - template - T indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const; - - /// Derivatives in X direction, in index space + ////////////// X DERIVATIVE ///////////////// template - T indexDDX(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY) const; + T indexDDX(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexStandardDerivative(f, outloc, method, region); + } + template - T indexD2DX2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY) const; + T indexD2DX2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexStandardDerivative(f, outloc, method, region); + } + template - T indexD4DX4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY) const; - - /// Derivatives in Y direction, in index space + T indexD4DX4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexStandardDerivative(f, outloc, method, region); + } + + ////////////// Y DERIVATIVE ///////////////// + template - T indexDDY(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY) const; + T indexDDY(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexStandardDerivative(f, outloc, method, region); + } + template - T indexD2DY2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY) const; + T indexD2DY2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexStandardDerivative(f, outloc, method, region); + } + template - T indexD4DY4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY) const; + T indexD4DY4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexStandardDerivative(f, outloc, method, region); + } - /// Derivatives in Z direction, in index space + ////////////// Z DERIVATIVE ///////////////// template - T indexDDZ(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY) const; + T indexDDZ(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexStandardDerivative(f, outloc, method, region); + } + template - T indexD2DZ2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY) const; + T indexD2DZ2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexStandardDerivative(f, outloc, method, region); + } + template - T indexD4DZ4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, - REGION region=RGN_NOBNDRY) const; + T indexD4DZ4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexStandardDerivative(f, outloc, method, region); + } + + ////// ADVECTION AND FLUX OPERATORS + + /// The main kernel used for all upwind and flux derivatives + template + T indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const; - /// Advection operator in index space in Y direction + /// Advection operator in index space in [] direction /// /// \f[ /// v \frac{d}{di} f @@ -513,26 +552,46 @@ class Mesh { /// @param[in] outloc The cell location where the result is desired. The default is the same as \p f /// @param[in] method The differencing method to use /// @param[in] region The region of the grid for which the result is calculated. + + ////////////// X DERIVATIVE ///////////////// + template - T indexVDDX(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY) const; - template - T indexVDDY(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY) const; + T indexVDDX(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexFlowDerivative(vel, f, outloc, method, region); + } + template - T indexVDDZ(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY) const; + T indexFDDX(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexFlowDerivative(vel, f, outloc, method, region); + } + + ////////////// Y DERIVATIVE ///////////////// - /// Flux functions template - T indexFDDX(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY) const; + T indexVDDY(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexFlowDerivative(vel, f, outloc, method, region); + } + + template + T indexFDDY(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexFlowDerivative(vel, f, outloc, method, region); + } + + ////////////// Z DERIVATIVE ///////////////// + template - T indexFDDY(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY) const; + T indexVDDZ(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexFlowDerivative(vel, f, outloc, method, region); + } + template - T indexFDDZ(const T &v, const T &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region=RGN_NOBNDRY) const; + T indexFDDZ(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + return indexFlowDerivative(vel, f, outloc, method, region); + } + + /////////////////////////////////////////////////////////// + // PARALLEL TRANSFORMS + /////////////////////////////////////////////////////////// /// Transform a field into field-aligned coordinates const Field3D toFieldAligned(const Field3D &f) { @@ -571,9 +630,14 @@ class Mesh { */ void setParallelTransform(); - ///////////////////////// - // Region related routines - ///////////////////////// + /*! + * Return the parallel transform, setting it if need be + */ + ParallelTransform& getParallelTransform(); + + /////////////////////////////////////////////////////////// + // REGION RELATED ROUTINES + /////////////////////////////////////////////////////////// // The maxregionblocksize to use when creating the default regions. // Can be set in the input file and the global default is set by, @@ -630,12 +694,7 @@ class Mesh { /// /// Creates RGN_{ALL,NOBNDRY,NOX,NOY} void createDefaultRegions(); - - /*! - * Return the parallel transform, setting it if need be - */ - ParallelTransform& getParallelTransform(); - + protected: GridDataSource *source; ///< Source for grid data @@ -667,96 +726,6 @@ private: Array indexLookup3Dto2D; }; -////// STANDARD OPERATORS - -////////////// X DERIVATIVE ///////////////// - -template -T Mesh::indexDDX(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexStandardDerivative(f, outloc, method, region); -} - -template -T Mesh::indexD2DX2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexStandardDerivative(f, outloc, method, region); -} - -template -T Mesh::indexD4DX4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexStandardDerivative(f, outloc, method, region); -} - -////////////// Y DERIVATIVE ///////////////// - -template -T Mesh::indexDDY(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexStandardDerivative(f, outloc, method, region); -} - -template -T Mesh::indexD2DY2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexStandardDerivative(f, outloc, method, region); -} - -template -T Mesh::indexD4DY4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexStandardDerivative(f, outloc, method, region); -} - -////////////// Z DERIVATIVE ///////////////// -template -T Mesh::indexDDZ(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexStandardDerivative(f, outloc, method, region); -} - -template -T Mesh::indexD2DZ2(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexStandardDerivative(f, outloc, method, region); -} - -template -T Mesh::indexD4DZ4(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexStandardDerivative(f, outloc, method, region); -} - -////// ADVECTION AND FLUX OPERATORS - -////////////// X DERIVATIVE ///////////////// - -template -T Mesh::indexVDDX(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexFlowDerivative(vel, f, outloc, method, region); -} - -template -T Mesh::indexFDDX(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexFlowDerivative(vel, f, outloc, method, region); -} - -////////////// Y DERIVATIVE ///////////////// - -template -T Mesh::indexVDDY(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexFlowDerivative(vel, f, outloc, method, region); -} - -template -T Mesh::indexFDDY(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexFlowDerivative(vel, f, outloc, method, region); -} - -////////////// Z DERIVATIVE ///////////////// - -template -T Mesh::indexVDDZ(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexFlowDerivative(vel, f, outloc, method, region); -} - -template -T Mesh::indexFDDZ(const T& vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { - return indexFlowDerivative(vel, f, outloc, method, region); -} - template T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { TRACE("%s", __thefunc__); From 1083460b89d3604e9941cae50a3e5faf783ad8c4 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 20:57:19 +0000 Subject: [PATCH 0206/1783] Make sure YOrthogonal has default derivatives set --- include/bout/deriv_store.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 9528e66c1f..a0cad9c456 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -180,7 +180,7 @@ template struct DerivativeStore { {DERIV::Upwind, "U1"}, {DERIV::Flux, "U1"}}; std::map directions = { - {DIRECTION::X,"ddx"}, {DIRECTION::Y,"ddy"}, {DIRECTION::Z,"ddz"} + {DIRECTION::X,"ddx"}, {DIRECTION::Y,"ddy"}, {DIRECTION::YOrthogonal,"ddy"}, {DIRECTION::Z,"ddz"} }; std::map derivTypes = { From 738f547b285a064c82726da468b058bead1d8ebf Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 20:58:05 +0000 Subject: [PATCH 0207/1783] Remove static_assert related to YOrthogonal requiring nguard being one This is in anticipation of the future reintroduction of multiple parallel slices. --- include/stencils.hxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/stencils.hxx b/include/stencils.hxx index 5f66ff82e8..517929b1dc 100644 --- a/include/stencils.hxx +++ b/include/stencils.hxx @@ -43,9 +43,6 @@ void inline populateStencil(stencil &s, const FieldType& f, const typename Field static_assert(nGuard == 1 || nGuard == 2, "populateStencil currently only supports one or two guard cells" ); - static_assert(direction != DIRECTION::YOrthogonal || nGuard == 1, - "Orthogonal Y currently only supports one guard cell" - ); switch(stagger) { case(STAGGER::None): From 38e1277bebe9f711daddd4ee2f92eea284c406da Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 20:59:34 +0000 Subject: [PATCH 0208/1783] Register derivatives for YOrthogonal direction --- include/bout/derivs.hxx | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index 1b31672b8e..1ec6eda630 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -464,7 +464,6 @@ struct registerMethod { // Now we want to get the actual field type out of the TypeContainer // used to pass this around using FieldType = typename FieldTypeContainer::type; - auto derivativeRegister = DerivativeStore::getInstance(); @@ -543,6 +542,22 @@ produceCombinations< DerivativeType, DerivativeType, DerivativeType>> registerDerivatives(registerMethod{}); + +produceCombinations< + Set, Set, + Set, TypeContainer>, + Set< + // Standard + DerivativeType, DerivativeType, + // Standard 2nd order + DerivativeType, + // Standard 4th order + // Upwind + DerivativeType, DerivativeType, + // Flux + DerivativeType>> +registerDerivativesYOrtho(registerMethod{}); + produceCombinations< Set, Set, @@ -559,6 +574,21 @@ produceCombinations< DerivativeType>> registerStaggeredDerivatives(registerMethod{}); +produceCombinations< + Set, + Set, + Set, TypeContainer>, + Set< + // Standard + DerivativeType, + // Standard 2nd order + // Upwind + DerivativeType, + DerivativeType, + // Flux + DerivativeType>> +registerStaggeredDerivativesYOrtho(registerMethod{}); + class FFTDerivativeType { public: template From d2053a75a05c2452134c1f24336e3f7515b12d18 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 1 Nov 2018 21:00:11 +0000 Subject: [PATCH 0209/1783] Add handling for Y derivative Choose between YOrthogonal+parallel slices or Y and shifting to aligned. --- include/bout/mesh.hxx | 49 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 2d816aedd1..30bc1b0ae7 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -506,17 +506,38 @@ class Mesh { template T indexDDY(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative(f, outloc, method, region); + if (std::is_base_of::value && f.hasYupYdown() && + ((&f.yup() != &f) || (&f.ydown() != &f))) { + return indexStandardDerivative(f, outloc, method, region); + } else { + const T f_aligned = f.getMesh()->toFieldAligned(f); + T result = indexStandardDerivative(f, outloc, method, region); + return f.getMesh()->fromFieldAligned(result); + } } template T indexD2DY2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative(f, outloc, method, region); + if (std::is_base_of::value && f.hasYupYdown() && + ((&f.yup() != &f) || (&f.ydown() != &f))) { + return indexStandardDerivative(f, outloc, method, region); + } else { + const T f_aligned = f.getMesh()->toFieldAligned(f); + T result = indexStandardDerivative(f, outloc, method, region); + return f.getMesh()->fromFieldAligned(result); + } } template T indexD4DY4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative(f, outloc, method, region); + if (std::is_base_of::value && f.hasYupYdown() && + ((&f.yup() != &f) || (&f.ydown() != &f))) { + return indexStandardDerivative(f, outloc, method, region); + } else { + const T f_aligned = f.getMesh()->toFieldAligned(f); + T result = indexStandardDerivative(f, outloc, method, region); + return f.getMesh()->fromFieldAligned(result); + } } ////////////// Z DERIVATIVE ///////////////// @@ -569,12 +590,30 @@ class Mesh { template T indexVDDY(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { - return indexFlowDerivative(vel, f, outloc, method, region); + bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); + bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); + if (fHasParallelSlices && velHasParallelSlices) { + return indexFlowDerivative(vel, f, outloc, method, region); + } else { + const T f_aligned = f.getMesh()->toFieldAligned(f); + const T vel_aligned = vel.getMesh()->toFieldAligned(vel); + T result = indexFlowDerivative(vel_aligned, f_aligned, outloc, method, region); + return f.getMesh()->fromFieldAligned(result); + } } template T indexFDDY(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { - return indexFlowDerivative(vel, f, outloc, method, region); + bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); + bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); + if (fHasParallelSlices && velHasParallelSlices) { + return indexFlowDerivative(vel, f, outloc, method, region); + } else { + const T f_aligned = f.getMesh()->toFieldAligned(f); + const T vel_aligned = vel.getMesh()->toFieldAligned(vel); + T result = indexFlowDerivative(vel_aligned, f_aligned, outloc, method, region); + return f.getMesh()->fromFieldAligned(result); + } } ////////////// Z DERIVATIVE ///////////////// From 71b1d3742a7ffbc61daf46fee769fd23b683d94e Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 1 Nov 2018 23:02:35 +0000 Subject: [PATCH 0210/1783] Fix merge bug, add some docs Merging with next brought in a use of the ``REV`` preprocessor variable, which had been removed in this branch. Add some more developer docs on updating gettext translations. --- .../developer_docs/natural_language.rst | 33 +++++++++++++++---- src/bout++.cxx | 2 +- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/manual/sphinx/developer_docs/natural_language.rst b/manual/sphinx/developer_docs/natural_language.rst index 55e05af47c..7a00985323 100644 --- a/manual/sphinx/developer_docs/natural_language.rst +++ b/manual/sphinx/developer_docs/natural_language.rst @@ -1,9 +1,30 @@ Natural Language Support ======================== -BOUT++ uses GNU ``gettext`` to provide translations of output strings. -Configuration is described in :ref:`sec-config-nls` and running in -:ref:`sec-run-nls`. +BOUT++ uses `GNU gettext `_. to +provide translations of output strings. Configuration is described in +:ref:`sec-config-nls` and running in :ref:`sec-run-nls`. Currently +only ``fr``, ``zh_TW``, and ``zh_CN`` have been added, but it is quite +easy to add more. See ``locale/README.md`` or below. + + +Marking strings for translation +------------------------------- + +In the code strings are wrapped with ``_()`` e.g. ``"hello world"`` +becomes ``_("hello world")``. Find a string you want to replace (which +can include formatting like ``%d``), surround it with ``_()``. Then in +the locale directory:: + + make libbout.pot + +will update the template file ``libbout.pot`` under +``BOUT_TOP/locale``. The template file should not be edited, but is +used to generate language-specific files (``libbout.po``). +To update these language files see the next section. + +Adding translations +------------------- Adding support for a new language, or improving the translations in the existing files can be done by: @@ -12,9 +33,9 @@ the existing files can be done by: make locale-ll - where ``ll`` is the language code e.g. ``make locale-de``. This - will create a file ``libbout.po`` under a ``locale/ll`` - subdirectory. + where ``ll`` is the language code e.g. ``make locale-zh_TW`` or + ``make locale-de``. This will create a file ``libbout.po`` under a + ``locale/ll`` subdirectory. 2. Edit the ``locale/ll/libbout.po`` file. Edit the .po file in de subdirectory (not the .pot file!), adding the translations. Each ``msgid`` entry should have a translated ``msgstr`` entry. If you diff --git a/src/bout++.cxx b/src/bout++.cxx index cf6265e5d1..ddc67db98f 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -428,7 +428,7 @@ int BoutInitialise(int &argc, char **&argv) { // Note: have to force value, since may already be set if a previously // output BOUT.settings file was used as input runinfo["version"].force(BOUT_VERSION_STRING, ""); - runinfo["revision"].force(REV, ""); + runinfo["revision"].force(BUILDFLAG(REVISION), ""); time_t start_time = time(nullptr); runinfo["started"].force(ctime(&start_time), ""); From e2dd9a0eab67711ee014c13df6da8260a4ef289a Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 1 Nov 2018 23:17:10 +0000 Subject: [PATCH 0211/1783] Delete dependency .mk files in clean target If dependencies change, or files move around, ``make`` can fail with odd error messages about missing dependencies. Deleting any ``.*.mk`` files (recursively) should fix the problem. Fixes issue #1330 --- make.config.in | 1 + 1 file changed, 1 insertion(+) diff --git a/make.config.in b/make.config.in index 3743fc4c53..9df51dce34 100644 --- a/make.config.in +++ b/make.config.in @@ -309,6 +309,7 @@ clean:: -@$(RM) -rf $(OBJ) $(DEPS) $(TARGET) @for pp in $(DIRS); do echo " " $$pp cleaned; $(MAKE) --no-print-directory -C $$pp clean; done @$(RM) -f $(SUB_LIBS) + @$(RM) .*.mk @test -f make.config && ( find src | grep '\.o$$' && echo "WARNING: Some object files remain - which might cause issues. Clean with $(MAKE) clean-remove-object-files" ) || exit 0 clean-remove-object-files: From c932cd92bd6ad5f411c53a06cf60b1c65eb11b3f Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 2 Nov 2018 08:33:13 +0000 Subject: [PATCH 0212/1783] Ignore failure when deleting .mk files `$(RM)` seems to be set to `rm -f` in most cases, but if it were just `rm` then `rm .*.mk` could fail. This fix causes `Make` to ignore this failure. Thanks to @dschwoerer for spotting. --- make.config.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make.config.in b/make.config.in index 9df51dce34..ee49c2f4c0 100644 --- a/make.config.in +++ b/make.config.in @@ -309,7 +309,7 @@ clean:: -@$(RM) -rf $(OBJ) $(DEPS) $(TARGET) @for pp in $(DIRS); do echo " " $$pp cleaned; $(MAKE) --no-print-directory -C $$pp clean; done @$(RM) -f $(SUB_LIBS) - @$(RM) .*.mk + -@$(RM) .*.mk @test -f make.config && ( find src | grep '\.o$$' && echo "WARNING: Some object files remain - which might cause issues. Clean with $(MAKE) clean-remove-object-files" ) || exit 0 clean-remove-object-files: From 4c5d32b0c9ccb858bab576e4c47c5d0c95a3392b Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 2 Nov 2018 10:54:46 +0000 Subject: [PATCH 0213/1783] Simplify the choice of how many guards to use. Replaces a runtime check with compile-time information --- include/bout/derivs.hxx | 72 ++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 45 deletions(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index 1ec6eda630..1750bcd0ab 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -16,7 +16,12 @@ const BoutReal WENO_SMALL = 1.0e-8; // Small number for WENO schemes struct metaData { - const std::string key; + // Would rather use a std::string here but this causes the + // metaData struct to be non-trivially destrucible which + // can prevent using temporary instances of this. Instead + // we'll use char* for now. + //const std::string key; + const char* key; const int nGuards; const DERIV derivType; // Can be used to identify the type of the derivative }; @@ -39,57 +44,34 @@ inline std::ostream &operator<<(std::ostream &out, const metaData &meta) { /// type as well. template class DerivativeType { public: - template + template void standard(const T &var, T &result, const REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond || meta.derivType == DERIV::StandardFourth) - ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); + ASSERT2(var.getMesh()->template getNguard() >= nGuards); - // For now use a runtime check on the required number of guards to pick - // how we call populateStencil. In future it would be nice to be able - // to replace 1/2 with a constexpr of some form (can do it now if - // meta didn't contain a string). - if(meta.nGuards == 1) { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(var, i)); - } - } else { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(var, i)); - } + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(var, i)); } return; } - template + template void upwindOrFlux(const T &vel, const T &var, T &result, const REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) - ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); + ASSERT2(var.getMesh()->template getNguard() >= nGuards); if (meta.derivType == DERIV::Flux || stagger != STAGGER::None) { - if(meta.nGuards == 1) { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(vel, i), - populateStencil(var, i)); - } - } else { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(vel, i), - populateStencil(var, i)); - } + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(vel, i), + populateStencil(var, i)); } } else { - if(meta.nGuards == 1) { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(vel[i], populateStencil(var, i)); - } - } else { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(vel[i], populateStencil(var, i)); - } + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(vel[i], populateStencil(var, i)); } } return; @@ -464,7 +446,8 @@ struct registerMethod { // Now we want to get the actual field type out of the TypeContainer // used to pass this around using FieldType = typename FieldTypeContainer::type; - + + const int nGuards = Method{}.meta.nGuards; auto derivativeRegister = DerivativeStore::getInstance(); switch (Method{}.meta.derivType) { @@ -473,7 +456,7 @@ struct registerMethod { case (DERIV::StandardFourth): { const auto theFunc = std::bind( // Method to store in function - &Method::template standard, + &Method::template standard, // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region Method{}, _1, _2, _3); @@ -484,7 +467,7 @@ struct registerMethod { case (DERIV::Flux): { const auto theFunc = std::bind( // Method to store in function - &Method::template upwindOrFlux, + &Method::template upwindOrFlux, // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region Method{}, _1, _2, _3, _4); @@ -591,11 +574,11 @@ registerStaggeredDerivativesYOrtho(registerMethod{}); class FFTDerivativeType { public: - template + template void standard(const T &var, T &result, const REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Standard) - ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); + ASSERT2(var.getMesh()->template getNguard() >= nGuards); ASSERT2(direction == DIRECTION::Z); //Only in Z for now ASSERT2(stagger == STAGGER::None); //Staggering not currently supported ASSERT2((std::is_base_of::value)); //Should never need to call this with Field2D @@ -652,7 +635,7 @@ public: return; } - template + template void upwindOrFlux(const T &vel, const T &var, T &result, const REGION region) const { TRACE("%s",__thefunc__); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); @@ -664,11 +647,11 @@ public: class FFT2ndDerivativeType { public: - template + template void standard(const T &var, T &result, const REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Standard) - ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); + ASSERT2(var.getMesh()->template getNguard() >= nGuards); ASSERT2(direction == DIRECTION::Z); //Only in Z for now ASSERT2(stagger == STAGGER::None); //Staggering not currently supported ASSERT2((std::is_base_of::value)); //Should never need to call this with Field2D @@ -718,7 +701,7 @@ public: return; } - template + template void upwindOrFlux(const T &vel, const T &var, T &result, const REGION region) const { TRACE("%s",__thefunc__); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); @@ -727,7 +710,6 @@ public: metaData meta{"FFT", 0, DERIV::StandardSecond}; }; - produceCombinations< Set, Set, Set>, Set From f7f782080e2fd5cdeacfc664d4a1f51293e22630 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 2 Nov 2018 10:58:53 +0000 Subject: [PATCH 0214/1783] Remove pass by reference on BoutReal --- include/bout/derivs.hxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index 1750bcd0ab..7f0f184eb4 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -78,7 +78,7 @@ public: } BoutReal apply(const stencil &f) const { return func(f); } - BoutReal apply(const BoutReal &v, const stencil &f) const { return func(v, f); } + BoutReal apply(const BoutReal v, const stencil &f) const { return func(v, f); } BoutReal apply(const stencil &v, const stencil &f) const { return func(v, f); } const FF func{}; @@ -89,7 +89,7 @@ public: struct name { \ BoutReal operator()(const stencil &f) const; \ const metaData meta = {key, nGuards, type}; \ - BoutReal operator()(const BoutReal &UNUSED(vc),\ + BoutReal operator()(const BoutReal UNUSED(vc),\ const stencil &UNUSED(f)) const {return BoutNaN;}; \ BoutReal operator()(const stencil &UNUSED(v),\ const stencil &UNUSED(f)) const {return BoutNaN;}; \ @@ -99,17 +99,17 @@ public: #define DEFINE_UPWIND_DERIV(name, key, nGuards, type) \ struct name { \ BoutReal operator()(const stencil &UNUSED(f)) const {return BoutNaN;}; \ - BoutReal operator()(const BoutReal &vc, const stencil &f) const; \ + BoutReal operator()(const BoutReal vc, const stencil &f) const; \ BoutReal operator()(const stencil &UNUSED(v),\ const stencil &UNUSED(f)) const {return BoutNaN;}; \ const metaData meta = {key, nGuards, type}; \ }; \ - BoutReal name::operator()(const BoutReal &vc, const stencil &f) const + BoutReal name::operator()(const BoutReal vc, const stencil &f) const #define DEFINE_FLUX_DERIV(name, key, nGuards, type) \ struct name { \ BoutReal operator()(const stencil &UNUSED(f)) const {return BoutNaN;}; \ - BoutReal operator()(const BoutReal &UNUSED(vc),\ + BoutReal operator()(const BoutReal UNUSED(vc),\ const stencil &UNUSED(f)) const {return BoutNaN;}; \ BoutReal operator()(const stencil &v, const stencil &f) const; \ const metaData meta = {key, nGuards, type}; \ From 8d23303cb446908145da76880cb7e71ebfe53e33 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 2 Nov 2018 11:03:16 +0000 Subject: [PATCH 0215/1783] Remove pass by const value --- include/bout/deriv_store.hxx | 12 ++++++------ include/bout/derivs.hxx | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index a0cad9c456..261842fa5e 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -32,9 +32,9 @@ template struct DerivativeStore { /// Register a function with standardFunc interface. Which map is used /// depends on the derivType input. - void registerDerivative(const standardFunc func, const DERIV derivType, - const DIRECTION direction, const STAGGER stagger, - const std::string methodName) { + void registerDerivative(standardFunc func, DERIV derivType, + DIRECTION direction, STAGGER stagger, + std::string methodName) { TRACE("%s", __thefunc__); const auto key = getKey(direction, stagger, methodName); @@ -58,9 +58,9 @@ template struct DerivativeStore { /// Register a function with upwindFunc/fluxFunc interface. Which map is used /// depends on the derivType input. - void registerDerivative(const upwindFunc func, const DERIV derivType, - const DIRECTION direction, const STAGGER stagger, - const std::string methodName) { + void registerDerivative(upwindFunc func, DERIV derivType, + DIRECTION direction, STAGGER stagger, + std::string methodName) { TRACE("%s", __thefunc__); const auto key = getKey(direction, stagger, methodName); switch (derivType) { diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index 7f0f184eb4..dc1992bcb2 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -45,7 +45,7 @@ inline std::ostream &operator<<(std::ostream &out, const metaData &meta) { template class DerivativeType { public: template - void standard(const T &var, T &result, const REGION region) const { + void standard(const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond || @@ -59,7 +59,7 @@ public: } template - void upwindOrFlux(const T &vel, const T &var, T &result, const REGION region) const { + void upwindOrFlux(const T &vel, const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) ASSERT2(var.getMesh()->template getNguard() >= nGuards); @@ -78,7 +78,7 @@ public: } BoutReal apply(const stencil &f) const { return func(f); } - BoutReal apply(const BoutReal v, const stencil &f) const { return func(v, f); } + BoutReal apply(BoutReal v, const stencil &f) const { return func(v, f); } BoutReal apply(const stencil &v, const stencil &f) const { return func(v, f); } const FF func{}; @@ -89,7 +89,7 @@ public: struct name { \ BoutReal operator()(const stencil &f) const; \ const metaData meta = {key, nGuards, type}; \ - BoutReal operator()(const BoutReal UNUSED(vc),\ + BoutReal operator()(BoutReal UNUSED(vc),\ const stencil &UNUSED(f)) const {return BoutNaN;}; \ BoutReal operator()(const stencil &UNUSED(v),\ const stencil &UNUSED(f)) const {return BoutNaN;}; \ @@ -99,17 +99,17 @@ public: #define DEFINE_UPWIND_DERIV(name, key, nGuards, type) \ struct name { \ BoutReal operator()(const stencil &UNUSED(f)) const {return BoutNaN;}; \ - BoutReal operator()(const BoutReal vc, const stencil &f) const; \ + BoutReal operator()(BoutReal vc, const stencil &f) const; \ BoutReal operator()(const stencil &UNUSED(v),\ const stencil &UNUSED(f)) const {return BoutNaN;}; \ const metaData meta = {key, nGuards, type}; \ }; \ - BoutReal name::operator()(const BoutReal vc, const stencil &f) const + BoutReal name::operator()(BoutReal vc, const stencil &f) const #define DEFINE_FLUX_DERIV(name, key, nGuards, type) \ struct name { \ BoutReal operator()(const stencil &UNUSED(f)) const {return BoutNaN;}; \ - BoutReal operator()(const BoutReal UNUSED(vc),\ + BoutReal operator()(BoutReal UNUSED(vc),\ const stencil &UNUSED(f)) const {return BoutNaN;}; \ BoutReal operator()(const stencil &v, const stencil &f) const; \ const metaData meta = {key, nGuards, type}; \ @@ -197,7 +197,7 @@ DEFINE_STANDARD_DERIV(D4DX4_C2, "C2", 2, DERIV::StandardFourth) { /// Hence convert cell centred values -> centred values, or left -> left /// //////////////////////////////////////////////////////////////////////////////// -std::tuple vUpDown(const BoutReal v) { +std::tuple vUpDown(BoutReal v) { return std::tuple{0.5 * (v + fabs(v)), 0.5 * (v - fabs(v))}; } @@ -575,7 +575,7 @@ registerStaggeredDerivativesYOrtho(registerMethod{}); class FFTDerivativeType { public: template - void standard(const T &var, T &result, const REGION region) const { + void standard(const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Standard) ASSERT2(var.getMesh()->template getNguard() >= nGuards); @@ -636,7 +636,7 @@ public: } template - void upwindOrFlux(const T &vel, const T &var, T &result, const REGION region) const { + void upwindOrFlux(const T &vel, const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); return; @@ -648,7 +648,7 @@ public: class FFT2ndDerivativeType { public: template - void standard(const T &var, T &result, const REGION region) const { + void standard(const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Standard) ASSERT2(var.getMesh()->template getNguard() >= nGuards); @@ -702,7 +702,7 @@ public: } template - void upwindOrFlux(const T &vel, const T &var, T &result, const REGION region) const { + void upwindOrFlux(const T &vel, const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); return; From f89bcedb90908ecfc0bd0810632e3c0a9b2ea6cf Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 2 Nov 2018 11:35:26 +0000 Subject: [PATCH 0216/1783] Revert "Simplify the choice of how many guards to use." This reverts commit 4c5d32b0c9ccb858bab576e4c47c5d0c95a3392b. This is currently necessary for gcc compilers using oldish libstdc++ This is evident on travis which uses the 4.8 contemporary version (for both v4.8 and v7 of the compiler). This shouldn't be necessary for newer versions and has been tested as working with gcc 5.4 using v6 of the libstdc++ Hopefully we can reintroduce the commit that this reverts in the future as we change the versions of things that we support. --- include/bout/derivs.hxx | 72 +++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index dc1992bcb2..54ff094a95 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -16,12 +16,7 @@ const BoutReal WENO_SMALL = 1.0e-8; // Small number for WENO schemes struct metaData { - // Would rather use a std::string here but this causes the - // metaData struct to be non-trivially destrucible which - // can prevent using temporary instances of this. Instead - // we'll use char* for now. - //const std::string key; - const char* key; + const std::string key; const int nGuards; const DERIV derivType; // Can be used to identify the type of the derivative }; @@ -44,34 +39,57 @@ inline std::ostream &operator<<(std::ostream &out, const metaData &meta) { /// type as well. template class DerivativeType { public: - template + template void standard(const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond || meta.derivType == DERIV::StandardFourth) - ASSERT2(var.getMesh()->template getNguard() >= nGuards); + ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(var, i)); + // For now use a runtime check on the required number of guards to pick + // how we call populateStencil. In future it would be nice to be able + // to replace 1/2 with a constexpr of some form (can do it now if + // meta didn't contain a string). + if(meta.nGuards == 1) { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(var, i)); + } + } else { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(var, i)); + } } return; } - template + template void upwindOrFlux(const T &vel, const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) - ASSERT2(var.getMesh()->template getNguard() >= nGuards); + ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); if (meta.derivType == DERIV::Flux || stagger != STAGGER::None) { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(vel, i), - populateStencil(var, i)); + if(meta.nGuards == 1) { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(vel, i), + populateStencil(var, i)); + } + } else { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(vel, i), + populateStencil(var, i)); + } } } else { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(vel[i], populateStencil(var, i)); + if(meta.nGuards == 1) { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(vel[i], populateStencil(var, i)); + } + } else { + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(vel[i], populateStencil(var, i)); + } } } return; @@ -446,8 +464,7 @@ struct registerMethod { // Now we want to get the actual field type out of the TypeContainer // used to pass this around using FieldType = typename FieldTypeContainer::type; - - const int nGuards = Method{}.meta.nGuards; + auto derivativeRegister = DerivativeStore::getInstance(); switch (Method{}.meta.derivType) { @@ -456,7 +473,7 @@ struct registerMethod { case (DERIV::StandardFourth): { const auto theFunc = std::bind( // Method to store in function - &Method::template standard, + &Method::template standard, // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region Method{}, _1, _2, _3); @@ -467,7 +484,7 @@ struct registerMethod { case (DERIV::Flux): { const auto theFunc = std::bind( // Method to store in function - &Method::template upwindOrFlux, + &Method::template upwindOrFlux, // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region Method{}, _1, _2, _3, _4); @@ -574,11 +591,11 @@ registerStaggeredDerivativesYOrtho(registerMethod{}); class FFTDerivativeType { public: - template + template void standard(const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Standard) - ASSERT2(var.getMesh()->template getNguard() >= nGuards); + ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); ASSERT2(direction == DIRECTION::Z); //Only in Z for now ASSERT2(stagger == STAGGER::None); //Staggering not currently supported ASSERT2((std::is_base_of::value)); //Should never need to call this with Field2D @@ -635,7 +652,7 @@ public: return; } - template + template void upwindOrFlux(const T &vel, const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); @@ -647,11 +664,11 @@ public: class FFT2ndDerivativeType { public: - template + template void standard(const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Standard) - ASSERT2(var.getMesh()->template getNguard() >= nGuards); + ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); ASSERT2(direction == DIRECTION::Z); //Only in Z for now ASSERT2(stagger == STAGGER::None); //Staggering not currently supported ASSERT2((std::is_base_of::value)); //Should never need to call this with Field2D @@ -701,7 +718,7 @@ public: return; } - template + template void upwindOrFlux(const T &vel, const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); @@ -710,6 +727,7 @@ public: metaData meta{"FFT", 0, DERIV::StandardSecond}; }; + produceCombinations< Set, Set, Set>, Set From 629db057bf37b2604484cc306333cad2bf1c0947 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 2 Nov 2018 12:00:46 +0000 Subject: [PATCH 0217/1783] Revert "Revert "Simplify the choice of how many guards to use."" This reverts commit f89bcedb90908ecfc0bd0810632e3c0a9b2ea6cf. A small workaround has had to be added for old (at least 4.8.3) versions of gcc/libstdc++ The code can be tidier once support for these old versions is dropped. --- include/bout/derivs.hxx | 120 +++++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 56 deletions(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index 54ff094a95..313af050b5 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -16,7 +16,12 @@ const BoutReal WENO_SMALL = 1.0e-8; // Small number for WENO schemes struct metaData { - const std::string key; + // Would rather use a std::string here but this causes the + // metaData struct to be non-trivially destrucible which + // can prevent using temporary instances of this. Instead + // we'll use char* for now. + //const std::string key; + const char* key; const int nGuards; const DERIV derivType; // Can be used to identify the type of the derivative }; @@ -39,57 +44,34 @@ inline std::ostream &operator<<(std::ostream &out, const metaData &meta) { /// type as well. template class DerivativeType { public: - template + template void standard(const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond || meta.derivType == DERIV::StandardFourth) - ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); + ASSERT2(var.getMesh()->template getNguard() >= nGuards); - // For now use a runtime check on the required number of guards to pick - // how we call populateStencil. In future it would be nice to be able - // to replace 1/2 with a constexpr of some form (can do it now if - // meta didn't contain a string). - if(meta.nGuards == 1) { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(var, i)); - } - } else { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(var, i)); - } + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(var, i)); } return; } - template + template void upwindOrFlux(const T &vel, const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) - ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); + ASSERT2(var.getMesh()->template getNguard() >= nGuards); if (meta.derivType == DERIV::Flux || stagger != STAGGER::None) { - if(meta.nGuards == 1) { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(vel, i), - populateStencil(var, i)); - } - } else { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(vel, i), - populateStencil(var, i)); - } + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(populateStencil(vel, i), + populateStencil(var, i)); } } else { - if(meta.nGuards == 1) { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(vel[i], populateStencil(var, i)); - } - } else { - BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(vel[i], populateStencil(var, i)); - } + BOUT_FOR(i, var.getRegion(region)) { + result[i] = apply(vel[i], populateStencil(var, i)); } } return; @@ -464,6 +446,13 @@ struct registerMethod { // Now we want to get the actual field type out of the TypeContainer // used to pass this around using FieldType = typename FieldTypeContainer::type; + + // Note whilst this should be known at compile time using this directly in the + // template parameters below causes problems for old versions of gcc/libstdc++ + // (tested with 4.8.3) so we currently use a hacky workaround. Once we drop + // support for these versions the branching in the case statement below can be + // removed and we can use nGuard directly in the template statement. + const int nGuards = Method{}.meta.nGuards; auto derivativeRegister = DerivativeStore::getInstance(); @@ -471,24 +460,44 @@ struct registerMethod { case (DERIV::Standard): case (DERIV::StandardSecond): case (DERIV::StandardFourth): { - const auto theFunc = std::bind( - // Method to store in function - &Method::template standard, - // Arguments -- first is hidden this of type-bound, others are placeholders - // for input field, output field, region - Method{}, _1, _2, _3); - derivativeRegister.template registerDerivative(theFunc); + if(nGuards == 1) { + const auto theFunc = std::bind( + // Method to store in function + &Method::template standard, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + Method{}, _1, _2, _3); + derivativeRegister.template registerDerivative(theFunc); + } else { + const auto theFunc = std::bind( + // Method to store in function + &Method::template standard, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + Method{}, _1, _2, _3); + derivativeRegister.template registerDerivative(theFunc); + } break; } case (DERIV::Upwind): case (DERIV::Flux): { - const auto theFunc = std::bind( - // Method to store in function - &Method::template upwindOrFlux, - // Arguments -- first is hidden this of type-bound, others are placeholders - // for input field, output field, region - Method{}, _1, _2, _3, _4); - derivativeRegister.template registerDerivative(theFunc); + if(nGuards == 1) { + const auto theFunc = std::bind( + // Method to store in function + &Method::template upwindOrFlux, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + Method{}, _1, _2, _3, _4); + derivativeRegister.template registerDerivative(theFunc); + } else { + const auto theFunc = std::bind( + // Method to store in function + &Method::template upwindOrFlux, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + Method{}, _1, _2, _3, _4); + derivativeRegister.template registerDerivative(theFunc); + } break; } default: @@ -591,11 +600,11 @@ registerStaggeredDerivativesYOrtho(registerMethod{}); class FFTDerivativeType { public: - template + template void standard(const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Standard) - ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); + ASSERT2(var.getMesh()->template getNguard() >= nGuards); ASSERT2(direction == DIRECTION::Z); //Only in Z for now ASSERT2(stagger == STAGGER::None); //Staggering not currently supported ASSERT2((std::is_base_of::value)); //Should never need to call this with Field2D @@ -652,7 +661,7 @@ public: return; } - template + template void upwindOrFlux(const T &vel, const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); @@ -664,11 +673,11 @@ public: class FFT2ndDerivativeType { public: - template + template void standard(const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); ASSERT2(meta.derivType == DERIV::Standard) - ASSERT2(var.getMesh()->template getNguard() >= meta.nGuards); + ASSERT2(var.getMesh()->template getNguard() >= nGuards); ASSERT2(direction == DIRECTION::Z); //Only in Z for now ASSERT2(stagger == STAGGER::None); //Staggering not currently supported ASSERT2((std::is_base_of::value)); //Should never need to call this with Field2D @@ -718,7 +727,7 @@ public: return; } - template + template void upwindOrFlux(const T &vel, const T &var, T &result, REGION region) const { TRACE("%s",__thefunc__); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); @@ -727,7 +736,6 @@ public: metaData meta{"FFT", 0, DERIV::StandardSecond}; }; - produceCombinations< Set, Set, Set>, Set From 2f0c991874d89437e65469018365d0c6bbe7291b Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 2 Nov 2018 12:48:02 +0000 Subject: [PATCH 0218/1783] Mark arguments as unused in derivs.hxx --- include/bout/derivs.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index 313af050b5..bfe8025428 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -662,7 +662,7 @@ public: } template - void upwindOrFlux(const T &vel, const T &var, T &result, REGION region) const { + void upwindOrFlux(const T &UNUSED(vel), const T &UNUSED(var), T &UNUSED(result), REGION UNUSED(region)) const { TRACE("%s",__thefunc__); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); return; @@ -728,7 +728,7 @@ public: } template - void upwindOrFlux(const T &vel, const T &var, T &result, REGION region) const { + void upwindOrFlux(const T &UNUSED(vel), const T &UNUSED(var), T &UNUSED(result), REGION UNUSED(region)) const { TRACE("%s",__thefunc__); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); return; From 9bb874d7bd2e4597d2e4dc686695e5cf2473ee38 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 2 Nov 2018 13:04:17 +0000 Subject: [PATCH 0219/1783] Remove unused variables and includes --- include/bout/derivs.hxx | 7 +++++ src/mesh/index_derivs.cxx | 63 ++++----------------------------------- 2 files changed, 13 insertions(+), 57 deletions(-) diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index bfe8025428..e1cdf8f745 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -5,14 +5,21 @@ #include #include +#include #include +#include #include #include + #include +#include #include #include #include +class Field3D; +class Field2D; + const BoutReal WENO_SMALL = 1.0e-8; // Small number for WENO schemes struct metaData { diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 008fcfd407..565b7293b2 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -44,27 +44,12 @@ * **************************************************************************/ -#include -#include -#include -#include -#include -#include #include -#include - +#include #include #include #include -#include -#include -#include - -#include - -#include - /******************************************************************************* * Limiters *******************************************************************************/ @@ -113,27 +98,9 @@ BoutReal DDX_KT(const stencil &f, const stencil &u, const BoutReal Vmax) { return Fm - Fp; } -/// Translate between short names, long names and DIFF_METHOD codes -struct DiffNameLookup { - DIFF_METHOD method; - const char *label; // Short name - const char *name; // Long name -}; - -/// Differential function name/code lookup -static DiffNameLookup DiffNameTable[] = { - {DIFF_U1, "U1", "First order upwinding"}, - {DIFF_U2, "U2", "Second order upwinding"}, - {DIFF_C2, "C2", "Second order central"}, - {DIFF_W2, "W2", "Second order WENO"}, - {DIFF_W3, "W3", "Third order WENO"}, - {DIFF_C4, "C4", "Fourth order central"}, - {DIFF_U3, "U3", "Third order upwinding"}, - {DIFF_U3, "U4", "Third order upwinding (Can't do 4th order yet)."}, - {DIFF_S2, "S2", "Smoothing 2nd order"}, - {DIFF_FFT, "FFT", "FFT"}, - {DIFF_SPLIT, "SPLIT", "Split into upwind and central"}, - {DIFF_DEFAULT, nullptr, nullptr}}; // Use to terminate the list +/******************************************************************************* + * Helper routines + *******************************************************************************/ /// Initialise the derivative methods. Must be called before any derivatives are used void Mesh::derivs_init(Options *options) { @@ -146,27 +113,8 @@ void Mesh::derivs_init(Options *options) { options->getSection("ddz")->get("fft_filter", fft_derivs_filter, 0.0); } - -/******************************************************************************* - * Actual derivative operators - *******************************************************************************/ - -/******************************************************************************* - * Advection schemes - * - * Jan 2018 - Re-written to use iterators and handle staggering as different cases - * Jan 2009 - Re-written to use Set*Stencil routines - *******************************************************************************/ - -/******************************************************************************* - * Flux conserving schemes - *******************************************************************************/ - -/******************************************************************************* - * Helper routines - *******************************************************************************/ - STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { + TRACE("Mesh::getStagger -- three arguments"); ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == allowedStaggerLoc) || (outloc == allowedStaggerLoc && inloc == CELL_CENTRE)); @@ -184,6 +132,7 @@ STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_L STAGGER Mesh::getStagger(const CELL_LOC UNUSED(vloc), const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { #endif + TRACE("Mesh::getStagger -- four arugments"); ASSERT1(vloc == inloc); return getStagger(inloc, outloc, allowedStaggerLoc); } From cfe469e52162fea41a62cf467cb6aee785d908c3 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 2 Nov 2018 13:14:39 +0000 Subject: [PATCH 0220/1783] Adding license header to new files --- include/bout/deriv_store.hxx | 29 ++++++++++++++++++++++++++ include/bout/derivs.hxx | 28 +++++++++++++++++++++++++ include/bout/template_combinations.hxx | 29 ++++++++++++++++++++++++++ src/mesh/index_derivs.cxx | 6 ------ 4 files changed, 86 insertions(+), 6 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 261842fa5e..f7c49fa7f2 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -1,3 +1,31 @@ +/*!************************************************************************ + * \file deriv_store.hxx + * + * Definition of derivative methods storage class + * + ************************************************************************** + * Copyright 2018 + * D.Dickinson, P.Hill, B.Dudson + * + * Contact: Ben Dudson, bd512@york.ac.uk + * + * This file is part of BOUT++. + * + * BOUT++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BOUT++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with BOUT++. If not, see . + * + **************************************************************************/ + #ifndef __DERIV_STORE_HXX__ #define __DERIV_STORE_HXX__ @@ -5,6 +33,7 @@ #include #include + #include #include #include diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index e1cdf8f745..7d4a89eb5a 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -1,3 +1,31 @@ +/*!************************************************************************ + * \file derivs.hxx + * + * Definition of available derivative methods and registration within store + * + ************************************************************************** + * Copyright 2018 + * D.Dickinson, P.Hill, B.Dudson + * + * Contact: Ben Dudson, bd512@york.ac.uk + * + * This file is part of BOUT++. + * + * BOUT++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BOUT++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with BOUT++. If not, see . + * + **************************************************************************/ + #ifndef __DERIVS_HXX__ #define __DERIVS_HXX__ diff --git a/include/bout/template_combinations.hxx b/include/bout/template_combinations.hxx index 97a4774af0..148a92fa37 100644 --- a/include/bout/template_combinations.hxx +++ b/include/bout/template_combinations.hxx @@ -1,3 +1,32 @@ +/*!************************************************************************ + * \file template_combinations.hxx + * + * Routines and helper types for calling a templated function with all combinations + * of various sets of types/values. + * + ************************************************************************** + * Copyright 2018 + * D.Dickinson, P.Hill + * + * Contact: Ben Dudson, bd512@york.ac.uk + * + * This file is part of BOUT++. + * + * BOUT++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BOUT++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with BOUT++. If not, see . + * + **************************************************************************/ + #ifndef __TEMPLATE_COMBINATIONS_H__ #define __TEMPLATE_COMBINATIONS_H__ diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 565b7293b2..0f5446b566 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -62,12 +62,6 @@ BoutReal SUPERBEE(BoutReal r) { return BOUTMAX(0.0, BOUTMIN(2. * r, 1.0), BOUTMIN(r, 2.)); } -/******************************************************************************* - * Basic derivative methods. - * All expect to have an input grid cell at the same location as the output - * Hence convert cell centred values -> centred values, or left -> left - *******************************************************************************/ - //////////////////////// MUSCL scheme /////////////////////// void DDX_KT_LR(const stencil &f, BoutReal &fLp, BoutReal &fRp, BoutReal &fLm, From 6de45a8c81c2ee38d7d2be2d8f50c8cdd9df791b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 2 Nov 2018 16:19:14 +0000 Subject: [PATCH 0221/1783] Support for reading/writing file-level attributes in netCDF/HDF5 If 'varname' argument of setAttribute() is the empty string, then get/set attribute of the file instead of a particular variable. --- include/dataformat.hxx | 20 ++++- src/fileio/impls/hdf5/h5_format.cxx | 94 ++++++++++++++-------- src/fileio/impls/netcdf/nc_format.cxx | 104 ++++++++++++++++-------- src/fileio/impls/netcdf4/ncxx4.cxx | 111 ++++++++++++++++++-------- 4 files changed, 223 insertions(+), 106 deletions(-) diff --git a/include/dataformat.hxx b/include/dataformat.hxx index 7186cfdf2e..67331c3393 100644 --- a/include/dataformat.hxx +++ b/include/dataformat.hxx @@ -114,7 +114,10 @@ class DataFormat { /// Inputs /// ------ /// - /// @param[in] varname Variable name. The variable must already exist + /// @param[in] varname Variable name. The variable must already exist. If + /// varname is the empty string "" then the attribute + /// will be added to the file instead of to a + /// variable. /// @param[in] attrname Attribute name /// @param[in] text A string attribute to attach to the variable virtual void setAttribute(const string &varname, const string &attrname, @@ -125,7 +128,10 @@ class DataFormat { /// Inputs /// ------ /// - /// @param[in] varname Variable name. The variable must already exist + /// @param[in] varname Variable name. The variable must already exist. If + /// varname is the empty string "" then the attribute + /// will be added to the file instead of to a + /// variable. /// @param[in] attrname Attribute name /// @param[in] value A string attribute to attach to the variable virtual void setAttribute(const string &varname, const string &attrname, @@ -135,7 +141,10 @@ class DataFormat { /// Inputs /// ------ /// - /// @param[in] varname Variable name. The variable must already exist + /// @param[in] varname Variable name. The variable must already exist. If + /// varname is the empty string "" then get the + /// attribute from the top-level of the file instead + /// of from a variable. /// @param[in] attrname Attribute name /// /// Returns @@ -148,7 +157,10 @@ class DataFormat { /// Inputs /// ------ /// - /// @param[in] varname Variable name. The variable must already exist + /// @param[in] varname Variable name. The variable must already exist. If + /// varname is the empty string "" then get the + /// attribute from the top-level of the file instead + /// of from a variable. /// @param[in] attrname Attribute name /// /// Returns diff --git a/src/fileio/impls/hdf5/h5_format.cxx b/src/fileio/impls/hdf5/h5_format.cxx index 378220cfd4..6c66b815c0 100644 --- a/src/fileio/impls/hdf5/h5_format.cxx +++ b/src/fileio/impls/hdf5/h5_format.cxx @@ -819,16 +819,23 @@ void H5Format::setAttribute(const std::string &varname, const std::string &attrn } // else: attribute does not exist, so just write it - hid_t dataSet = H5Dopen(dataFile, varname.c_str(), H5P_DEFAULT); - if (dataSet < 0) { - // Negative value indicates error, i.e. variable does not exist - throw BoutException("Trying to create attribute for variable that does not exist"); - } + if (varname == "") { + // attribute of file + setAttribute(dataFile, attrname, text); + } else { + // attribute of variable + hid_t dataSet = H5Dopen(dataFile, varname.c_str(), H5P_DEFAULT); + if (dataSet < 0) { + // Negative value indicates error, i.e. variable does not exist + throw BoutException("Trying to create attribute for variable that does not exist"); + } - setAttribute(dataSet, attrname, text); + setAttribute(dataSet, attrname, text); - if (H5Dclose(dataSet) < 0) - throw BoutException("Failed to close dataSet"); + if (H5Dclose(dataSet) < 0) { + throw BoutException("Failed to close dataSet"); + } + } } void H5Format::setAttribute(const std::string &varname, const std::string &attrname, @@ -844,16 +851,23 @@ void H5Format::setAttribute(const std::string &varname, const std::string &attrn } // else: attribute does not exist, so just write it - hid_t dataSet = H5Dopen(dataFile, varname.c_str(), H5P_DEFAULT); - if (dataSet < 0) { - // Negative value indicates error, i.e. variable does not exist - throw BoutException("Trying to create attribute for variable that does not exist"); - } + if (varname == "") { + // attribute of file + setAttribute(dataFile, attrname, value); + } else { + // attribute of variable + hid_t dataSet = H5Dopen(dataFile, varname.c_str(), H5P_DEFAULT); + if (dataSet < 0) { + // Negative value indicates error, i.e. variable does not exist + throw BoutException("Trying to create attribute for variable that does not exist"); + } - setAttribute(dataSet, attrname, value); + setAttribute(dataSet, attrname, value); - if (H5Dclose(dataSet) < 0) - throw BoutException("Failed to close dataSet"); + if (H5Dclose(dataSet) < 0) { + throw BoutException("Failed to close dataSet"); + } + } } void H5Format::setAttribute(const hid_t &dataSet, const std::string &attrname, @@ -916,35 +930,47 @@ void H5Format::setAttribute(const hid_t &dataSet, const std::string &attrname, bool H5Format::getAttribute(const std::string &varname, const std::string &attrname, std::string &text) { TRACE("H5Format::getAttribute(varname, attrname, string)"); - hid_t dataSet = H5Dopen(dataFile, varname.c_str(), H5P_DEFAULT); - if (dataSet < 0) { - // Negative value indicates error, i.e. variable does not exist - throw BoutException("Trying to read attribute for variable that does not exist"); - } + if (varname == "") { + // attribute of file + return getAttribute(dataFile, attrname, text); + } else { + // attribute of variable + hid_t dataSet = H5Dopen(dataFile, varname.c_str(), H5P_DEFAULT); + if (dataSet < 0) { + // Negative value indicates error, i.e. variable does not exist + throw BoutException("Trying to read attribute for variable that does not exist"); + } - bool result = getAttribute(dataSet, attrname, text); + bool result = getAttribute(dataSet, attrname, text); - if (H5Dclose(dataSet) < 0) - throw BoutException("Failed to close dataSet"); + if (H5Dclose(dataSet) < 0) + throw BoutException("Failed to close dataSet"); - return result; + return result; + } } bool H5Format::getAttribute(const std::string &varname, const std::string &attrname, int &value) { TRACE("H5Format::getAttribute(varname, attrname, int)"); - hid_t dataSet = H5Dopen(dataFile, varname.c_str(), H5P_DEFAULT); - if (dataSet < 0) { - // Negative value indicates error, i.e. variable does not exist - throw BoutException("Trying to read attribute for variable that does not exist"); - } + if (varname == "") { + // attribute of file + return getAttribute(dataFile, attrname, value); + } else { + // attribute of variable + hid_t dataSet = H5Dopen(dataFile, varname.c_str(), H5P_DEFAULT); + if (dataSet < 0) { + // Negative value indicates error, i.e. variable does not exist + throw BoutException("Trying to read attribute for variable that does not exist"); + } - bool result = getAttribute(dataSet, attrname, value); + bool result = getAttribute(dataSet, attrname, value); - if (H5Dclose(dataSet) < 0) - throw BoutException("Failed to close dataSet"); + if (H5Dclose(dataSet) < 0) + throw BoutException("Failed to close dataSet"); - return result; + return result; + } } bool H5Format::getAttribute(const hid_t &dataSet, const std::string &attrname, std::string &text) { diff --git a/src/fileio/impls/netcdf/nc_format.cxx b/src/fileio/impls/netcdf/nc_format.cxx index cc5b01598b..2b93187806 100644 --- a/src/fileio/impls/netcdf/nc_format.cxx +++ b/src/fileio/impls/netcdf/nc_format.cxx @@ -896,11 +896,6 @@ void NcFormat::setAttribute(const std::string &varname, const std::string &attrn const std::string &text) { TRACE("NcFormat::setAttribute(string)"); - NcVar* var = dataFile->get_var(varname.c_str()); - if (!var->is_valid()) { - throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); - } - #ifdef NCDF_VERBOSE NcError err(NcError::verbose_nonfatal); #else @@ -915,19 +910,25 @@ void NcFormat::setAttribute(const std::string &varname, const std::string &attrn } } // else: attribute does not exist, so just write it - - var->add_att(attrname.c_str(), text.c_str()); + + if (varname == "" ) { + // file attribute + dataFile->add_att(attrname.c_str(), text.c_str()); + } else { + // variable attribute + NcVar* var = dataFile->get_var(varname.c_str()); + if (!var->is_valid()) { + throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); + } + + var->add_att(attrname.c_str(), text.c_str()); + } } void NcFormat::setAttribute(const std::string &varname, const std::string &attrname, int value) { TRACE("NcFormat::setAttribute(int)"); - NcVar* var = dataFile->get_var(varname.c_str()); - if (!var->is_valid()) { - throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); - } - #ifdef NCDF_VERBOSE NcError err(NcError::verbose_nonfatal); #else @@ -943,53 +944,90 @@ void NcFormat::setAttribute(const std::string &varname, const std::string &attrn } // else: attribute does not exist, so just write it - var->add_att(attrname.c_str(), value); + if (varname == "") { + // attribute of file + dataFile->add_att(attrname.c_str(), value); + } else { + // attribute of variable + NcVar* var = dataFile->get_var(varname.c_str()); + if (!var->is_valid()) { + throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); + } + + var->add_att(attrname.c_str(), value); + } } bool NcFormat::getAttribute(const std::string &varname, const std::string &attrname, std::string &text) { TRACE("NcFormat::getStringAttribute(string)"); - NcVar* var = dataFile->get_var(varname.c_str()); - if (!var->is_valid()) { - throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); - } - #ifdef NCDF_VERBOSE NcError err(NcError::verbose_nonfatal); #else NcError err(NcError::silent_nonfatal); #endif - NcAtt* varAtt; - if (!(varAtt = var->get_att(attrname.c_str()))) - return false; + if (varname == "") { + // attribute of file + NcAtt* fileAtt; + if (!(fileAtt = dataFile->get_att(attrname.c_str()))) { + return false; + } - text = varAtt->values()->as_string(0); + text = fileAtt->values()->as_string(0); - return true; + return true; + } else { + NcVar* var = dataFile->get_var(varname.c_str()); + if (!var->is_valid()) { + throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); + } + + NcAtt* varAtt; + if (!(varAtt = var->get_att(attrname.c_str()))) { + return false; + } + + text = varAtt->values()->as_string(0); + + return true; + } } bool NcFormat::getAttribute(const std::string &varname, const std::string &attrname, int &value) { TRACE("NcFormat::getIntAttribute(string)"); - NcVar* var; - if (!(var = dataFile->get_var(varname.c_str()))) { - throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); - } - #ifdef NCDF_VERBOSE NcError err(NcError::verbose_nonfatal); #else NcError err(NcError::silent_nonfatal); #endif - NcAtt* varAtt = var->get_att(attrname.c_str()); - if (!varAtt->is_valid()) - return false; + if (varname == "") { + // attribute of file + NcAtt* fileAtt; + if (!(fileAtt = dataFile->get_att(attrname.c_str()))) { + return false; + } - value = varAtt->values()->as_int(0); + value = fileAtt->values()->as_int(0); - return true; + return true; + } else { + // attribute of variable + NcVar* var; + if (!(var = dataFile->get_var(varname.c_str()))) { + throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); + } + + NcAtt* varAtt; + if (!(varAtt = var->get_att(attrname.c_str()))) + return false; + + value = varAtt->values()->as_int(0); + + return true; + } } diff --git a/src/fileio/impls/netcdf4/ncxx4.cxx b/src/fileio/impls/netcdf4/ncxx4.cxx index 3673e577da..ad3a417adc 100644 --- a/src/fileio/impls/netcdf4/ncxx4.cxx +++ b/src/fileio/impls/netcdf4/ncxx4.cxx @@ -759,11 +759,6 @@ void Ncxx4::setAttribute(const std::string &varname, const std::string &attrname const std::string &text) { TRACE("Ncxx4::setAttribute(string)"); - NcVar var = dataFile->getVar(varname); - if (var.isNull()) { - throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); - } - std::string existing_att; if (getAttribute(varname, attrname, existing_att)) { if (text != existing_att) { @@ -772,19 +767,25 @@ void Ncxx4::setAttribute(const std::string &varname, const std::string &attrname } } // else: attribute does not exist, so just write it - - var.putAtt(attrname, text); + + if (varname == "") { + // write attribute of file + dataFile->putAtt(attrname, text); + } else { + // write attribute of variable + NcVar var = dataFile->getVar(varname); + if (var.isNull()) { + throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); + } + + var.putAtt(attrname, text); + } } void Ncxx4::setAttribute(const std::string &varname, const std::string &attrname, int value) { TRACE("Ncxx4::setAttribute(int)"); - NcVar var = dataFile->getVar(varname); - if (var.isNull()) { - throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); - } - int existing_att; if (getAttribute(varname, attrname, existing_att)) { if (value != existing_att) { @@ -794,46 +795,86 @@ void Ncxx4::setAttribute(const std::string &varname, const std::string &attrname } // else: attribute does not exist, so just write it - var.putAtt(attrname, NcType::nc_INT, value); + if (varname == "") { + // write attribute of file + dataFile->putAtt(attrname, NcType::nc_INT, value); + } else { + // write attribute of variable + NcVar var = dataFile->getVar(varname); + if (var.isNull()) { + throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); + } + + var.putAtt(attrname, NcType::nc_INT, value); + } } bool Ncxx4::getAttribute(const std::string &varname, const std::string &attrname, std::string &text) { TRACE("Ncxx4::getStringAttribute(string)"); - NcVar var = dataFile->getVar(varname); - if (var.isNull()) { - throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); - } + if (varname == "") { + // attribute of file + // Check if attribute exists without throwing exception when it doesn't + std::multimap fileAtts_list = dataFile->getAtts(); + if (fileAtts_list.find(attrname) == fileAtts_list.end()) { + return false; + } else { + NcGroupAtt fileAtt = dataFile->getAtt(attrname); + fileAtt.getValues(text); - // Check if attribute exists without throwing exception when it doesn't - map varAtts_list = var.getAtts(); - if (varAtts_list.find(attrname) == varAtts_list.end()) { - return false; + return true; + } } else { - NcVarAtt varAtt = var.getAtt(attrname); - varAtt.getValues(text); + // attribute of variable + NcVar var = dataFile->getVar(varname); + if (var.isNull()) { + throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); + } - return true; + // Check if attribute exists without throwing exception when it doesn't + map varAtts_list = var.getAtts(); + if (varAtts_list.find(attrname) == varAtts_list.end()) { + return false; + } else { + NcVarAtt varAtt = var.getAtt(attrname); + varAtt.getValues(text); + + return true; + } } } bool Ncxx4::getAttribute(const std::string &varname, const std::string &attrname, int &value) { TRACE("Ncxx4::getIntAttribute(string)"); - NcVar var = dataFile->getVar(varname); - if (var.isNull()) { - throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); - } + if (varname == "") { + // attribute of file + // Check if attribute exists without throwing exception when it doesn't + std::multimap fileAtts_list = dataFile->getAtts(); + if (fileAtts_list.find(attrname) == fileAtts_list.end()) { + return false; + } else { + NcGroupAtt fileAtt = dataFile->getAtt(attrname); + fileAtt.getValues(&value); - // Check if attribute exists without throwing exception when it doesn't - map varAtts_list = var.getAtts(); - if (varAtts_list.find(attrname) == varAtts_list.end()) { - return false; + return true; + } } else { - NcVarAtt varAtt = var.getAtt(attrname); - varAtt.getValues(&value); + NcVar var = dataFile->getVar(varname); + if (var.isNull()) { + throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); + } - return true; + // Check if attribute exists without throwing exception when it doesn't + map varAtts_list = var.getAtts(); + if (varAtts_list.find(attrname) == varAtts_list.end()) { + return false; + } else { + NcVarAtt varAtt = var.getAtt(attrname); + varAtt.getValues(&value); + + return true; + } } } From ec6cac7252a618db1325006872941dc05e26a025 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 2 Nov 2018 16:41:17 +0000 Subject: [PATCH 0222/1783] Add support for BoutReal attributes of data files --- include/datafile.hxx | 1 + include/dataformat.hxx | 35 +++++++++- src/fileio/datafile.cxx | 29 ++++++++ src/fileio/impls/hdf5/h5_format.cxx | 96 +++++++++++++++++++++++++++ src/fileio/impls/hdf5/h5_format.hxx | 6 ++ src/fileio/impls/netcdf/nc_format.cxx | 73 +++++++++++++++++++- src/fileio/impls/netcdf/nc_format.hxx | 3 + src/fileio/impls/netcdf4/ncxx4.cxx | 65 +++++++++++++++++- src/fileio/impls/netcdf4/ncxx4.hxx | 3 + 9 files changed, 305 insertions(+), 6 deletions(-) diff --git a/include/datafile.hxx b/include/datafile.hxx index 15ef36a356..f4a6e2d6e0 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -75,6 +75,7 @@ class Datafile { void setAttribute(const string &varname, const string &attrname, const string &text); void setAttribute(const string &varname, const string &attrname, int value); + void setAttribute(const string &varname, const string &attrname, BoutReal value); private: bool parallel; // Use parallel formats? diff --git a/include/dataformat.hxx b/include/dataformat.hxx index 67331c3393..b3de842f0c 100644 --- a/include/dataformat.hxx +++ b/include/dataformat.hxx @@ -133,9 +133,24 @@ class DataFormat { /// will be added to the file instead of to a /// variable. /// @param[in] attrname Attribute name - /// @param[in] value A string attribute to attach to the variable + /// @param[in] value An int attribute to attach to the variable virtual void setAttribute(const string &varname, const string &attrname, int value) = 0; + + /// Sets a BoutReal attribute + /// + /// Inputs + /// ------ + /// + /// @param[in] varname Variable name. The variable must already exist. If + /// varname is the empty string "" then the attribute + /// will be added to the file instead of to a + /// variable. + /// @param[in] attrname Attribute name + /// @param[in] value A BoutReal attribute to attach to the variable + virtual void setAttribute(const string &varname, const string &attrname, + BoutReal value) = 0; + /// Gets a string attribute /// /// Inputs @@ -152,7 +167,7 @@ class DataFormat { /// text A string attribute of the variable virtual bool getAttribute(const string &varname, const string &attrname, std::string &text) = 0; - /// Sets an integer attribute + /// Gets an integer attribute /// /// Inputs /// ------ @@ -167,6 +182,22 @@ class DataFormat { /// ------- /// value An int attribute of the variable virtual bool getAttribute(const string &varname, const string &attrname, int &value) = 0; + + /// Gets a BoutReal attribute + /// + /// Inputs + /// ------ + /// + /// @param[in] varname Variable name. The variable must already exist. If + /// varname is the empty string "" then get the + /// attribute from the top-level of the file instead + /// of from a variable. + /// @param[in] attrname Attribute name + /// + /// Returns + /// ------- + /// value A BoutReal attribute of the variable + virtual bool getAttribute(const string &varname, const string &attrname, BoutReal &value) = 0; }; // For backwards compatability. In formatfactory.cxx diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index b11636fc33..d8a389edb5 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -1064,6 +1064,35 @@ void Datafile::setAttribute(const string &varname, const string &attrname, int v } } +void Datafile::setAttribute(const string &varname, const string &attrname, BoutReal value) { + + TRACE("Datafile::setAttribute(string, string, BoutReal)"); + + Timer timer("io"); + + if(!file) + throw BoutException("Datafile::write: File is not valid!"); + + if(openclose && (flushFrequencyCounter % flushFrequency == 0)) { + // Open the file + int MYPE; + MPI_Comm_rank(BoutComm::get(), &MYPE); + if(!file->openw(filename, MYPE, appending)) + throw BoutException("Datafile::write: Failed to open file!"); + appending = true; + flushFrequencyCounter = 0; + } + + if(!file->is_valid()) + throw BoutException("Datafile::setAttribute: File is not valid!"); + + file->setAttribute(varname, attrname, value); + + if (openclose) { + file->close(); + } +} + ///////////////////////////////////////////////////////////// bool Datafile::read_f2d(const string &name, Field2D *f, bool save_repeat) { diff --git a/src/fileio/impls/hdf5/h5_format.cxx b/src/fileio/impls/hdf5/h5_format.cxx index 6c66b815c0..16b3b31457 100644 --- a/src/fileio/impls/hdf5/h5_format.cxx +++ b/src/fileio/impls/hdf5/h5_format.cxx @@ -870,6 +870,38 @@ void H5Format::setAttribute(const std::string &varname, const std::string &attrn } } +void H5Format::setAttribute(const std::string &varname, const std::string &attrname, + BoutReal value) { + TRACE("H5Format::setAttribute(varname, attrname, BoutReal)"); + + BoutReal existing_att; + if (getAttribute(varname, attrname, existing_att)) { + if (value != existing_att) { + output_warn.write("Overwriting attribute '%s' of variable '%s' with '%d', was previously '%d'", + attrname.c_str(), varname.c_str(), value, existing_att); + } + } + // else: attribute does not exist, so just write it + + if (varname == "") { + // attribute of file + setAttribute(dataFile, attrname, value); + } else { + // attribute of variable + hid_t dataSet = H5Dopen(dataFile, varname.c_str(), H5P_DEFAULT); + if (dataSet < 0) { + // Negative value indicates error, i.e. variable does not exist + throw BoutException("Trying to create attribute for variable that does not exist"); + } + + setAttribute(dataSet, attrname, value); + + if (H5Dclose(dataSet) < 0) { + throw BoutException("Failed to close dataSet"); + } + } +} + void H5Format::setAttribute(const hid_t &dataSet, const std::string &attrname, const std::string &text) { TRACE("H5Format::setAttribute(dataSet, attrname, string)"); @@ -927,6 +959,28 @@ void H5Format::setAttribute(const hid_t &dataSet, const std::string &attrname, throw BoutException("Failed to close myatt_in"); } +void H5Format::setAttribute(const hid_t &dataSet, const std::string &attrname, + BoutReal value) { + TRACE("H5Format::setAttribute(dataSet, attrname, BoutReal)"); + + // Create new dataspace for attribute + hid_t attribute_dataspace = H5Screate(H5S_SCALAR); + if (attribute_dataspace < 0) + throw BoutException("Failed to create attribute_dataspace"); + + // Create attribute and write to it + hid_t myatt_in = H5Acreate(dataSet, attrname.c_str(), H5T_NATIVE_DOUBLE, attribute_dataspace, H5P_DEFAULT, H5P_DEFAULT); + if (myatt_in < 0) + throw BoutException("Failed to create attribute"); + if (H5Awrite(myatt_in, H5T_NATIVE_DOUBLE, &value) < 0) + throw BoutException("Failed to write attribute"); + + if (H5Sclose(attribute_dataspace) < 0) + throw BoutException("Failed to close attribute_dataspace"); + if (H5Aclose(myatt_in) < 0) + throw BoutException("Failed to close myatt_in"); +} + bool H5Format::getAttribute(const std::string &varname, const std::string &attrname, std::string &text) { TRACE("H5Format::getAttribute(varname, attrname, string)"); @@ -973,6 +1027,29 @@ bool H5Format::getAttribute(const std::string &varname, const std::string &attrn } } +bool H5Format::getAttribute(const std::string &varname, const std::string &attrname, BoutReal &value) { + TRACE("H5Format::getAttribute(varname, attrname, BoutReal)"); + + if (varname == "") { + // attribute of file + return getAttribute(dataFile, attrname, value); + } else { + // attribute of variable + hid_t dataSet = H5Dopen(dataFile, varname.c_str(), H5P_DEFAULT); + if (dataSet < 0) { + // Negative value indicates error, i.e. variable does not exist + throw BoutException("Trying to read attribute for variable that does not exist"); + } + + bool result = getAttribute(dataSet, attrname, value); + + if (H5Dclose(dataSet) < 0) + throw BoutException("Failed to close dataSet"); + + return result; + } +} + bool H5Format::getAttribute(const hid_t &dataSet, const std::string &attrname, std::string &text) { TRACE("H5Format::getAttribute(hid_t, attrname, string)"); @@ -1020,5 +1097,24 @@ bool H5Format::getAttribute(const hid_t &dataSet, const std::string &attrname, i return true; } +bool H5Format::getAttribute(const hid_t &dataSet, const std::string &attrname, BoutReal &value) { + TRACE("H5Format::getAttribute(hid_t, attrname, BoutReal)"); + + // Open attribute + hid_t myatt = H5Aopen(dataSet, attrname.c_str(), H5P_DEFAULT); + if (myatt < 0) { + return false; + } + + // Read attribute + if (H5Aread(myatt, H5T_NATIVE_DOUBLE, &value) < 0) + throw BoutException("Failed to read attribute"); + + if (H5Aclose(myatt) < 0) + throw BoutException("Failed to close myatt_in"); + + return true; +} + #endif // HDF5 diff --git a/src/fileio/impls/hdf5/h5_format.hxx b/src/fileio/impls/hdf5/h5_format.hxx index bb2fd9e07e..957502fb9b 100644 --- a/src/fileio/impls/hdf5/h5_format.hxx +++ b/src/fileio/impls/hdf5/h5_format.hxx @@ -121,8 +121,11 @@ class H5Format : public DataFormat { const std::string &text) override; void setAttribute(const std::string &varname, const std::string &attrname, int value) override; + void setAttribute(const std::string &varname, const std::string &attrname, + BoutReal value) override; bool getAttribute(const std::string &varname, const std::string &attrname, std::string &text) override; bool getAttribute(const std::string &varname, const std::string &attrname, int &value) override; + bool getAttribute(const std::string &varname, const std::string &attrname, BoutReal &value) override; private: @@ -152,8 +155,11 @@ class H5Format : public DataFormat { const std::string &text); void setAttribute(const hid_t &dataSet, const std::string &attrname, int value); + void setAttribute(const hid_t &dataSet, const std::string &attrname, + BoutReal value); bool getAttribute(const hid_t &dataSet, const std::string &attrname, std::string &text); bool getAttribute(const hid_t &dataSet, const std::string &attrname, int &value); + bool getAttribute(const hid_t &dataSet, const std::string &attrname, BoutReal &value); }; #endif // __H5FORMAT_H__ diff --git a/src/fileio/impls/netcdf/nc_format.cxx b/src/fileio/impls/netcdf/nc_format.cxx index 2b93187806..eeab3ca96e 100644 --- a/src/fileio/impls/netcdf/nc_format.cxx +++ b/src/fileio/impls/netcdf/nc_format.cxx @@ -958,8 +958,41 @@ void NcFormat::setAttribute(const std::string &varname, const std::string &attrn } } +void NcFormat::setAttribute(const std::string &varname, const std::string &attrname, + BoutReal value) { + TRACE("NcFormat::setAttribute(BoutReal)"); + +#ifdef NCDF_VERBOSE + NcError err(NcError::verbose_nonfatal); +#else + NcError err(NcError::silent_nonfatal); +#endif + + int existing_att; + if (getAttribute(varname, attrname, existing_att)) { + if (value != existing_att) { + output_warn.write("Overwriting attribute '%s' of variable '%s' with '%d', was previously '%d'", + attrname.c_str(), varname.c_str(), value, existing_att); + } + } + // else: attribute does not exist, so just write it + + if (varname == "") { + // attribute of file + dataFile->add_att(attrname.c_str(), value); + } else { + // attribute of variable + NcVar* var = dataFile->get_var(varname.c_str()); + if (!var->is_valid()) { + throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); + } + + var->add_att(attrname.c_str(), value); + } +} + bool NcFormat::getAttribute(const std::string &varname, const std::string &attrname, std::string &text) { - TRACE("NcFormat::getStringAttribute(string)"); + TRACE("NcFormat::getAttribute(string)"); #ifdef NCDF_VERBOSE NcError err(NcError::verbose_nonfatal); @@ -995,7 +1028,7 @@ bool NcFormat::getAttribute(const std::string &varname, const std::string &attrn } bool NcFormat::getAttribute(const std::string &varname, const std::string &attrname, int &value) { - TRACE("NcFormat::getIntAttribute(string)"); + TRACE("NcFormat::getAttribute(int)"); #ifdef NCDF_VERBOSE NcError err(NcError::verbose_nonfatal); @@ -1030,6 +1063,42 @@ bool NcFormat::getAttribute(const std::string &varname, const std::string &attrn } } +bool NcFormat::getAttribute(const std::string &varname, const std::string &attrname, BoutReal &value) { + TRACE("NcFormat::getAttribute(BoutReal)"); + +#ifdef NCDF_VERBOSE + NcError err(NcError::verbose_nonfatal); +#else + NcError err(NcError::silent_nonfatal); +#endif + + if (varname == "") { + // attribute of file + NcAtt* fileAtt; + if (!(fileAtt = dataFile->get_att(attrname.c_str()))) { + return false; + } + + value = fileAtt->values()->as_double(0); + + return true; + } else { + // attribute of variable + NcVar* var; + if (!(var = dataFile->get_var(varname.c_str()))) { + throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); + } + + NcAtt* varAtt; + if (!(varAtt = var->get_att(attrname.c_str()))) + return false; + + value = varAtt->values()->as_double(0); + + return true; + } +} + /*************************************************************************** * Private functions diff --git a/src/fileio/impls/netcdf/nc_format.hxx b/src/fileio/impls/netcdf/nc_format.hxx index a04557066f..6d5c0d574e 100644 --- a/src/fileio/impls/netcdf/nc_format.hxx +++ b/src/fileio/impls/netcdf/nc_format.hxx @@ -125,8 +125,11 @@ class NcFormat : public DataFormat { const std::string &text) override; void setAttribute(const std::string &varname, const std::string &attrname, int value) override; + void setAttribute(const std::string &varname, const std::string &attrname, + BoutReal value) override; bool getAttribute(const std::string &varname, const std::string &attrname, std::string &text) override; bool getAttribute(const std::string &varname, const std::string &attrname, int &value) override; + bool getAttribute(const std::string &varname, const std::string &attrname, BoutReal &value) override; private: diff --git a/src/fileio/impls/netcdf4/ncxx4.cxx b/src/fileio/impls/netcdf4/ncxx4.cxx index ad3a417adc..ef5c881fec 100644 --- a/src/fileio/impls/netcdf4/ncxx4.cxx +++ b/src/fileio/impls/netcdf4/ncxx4.cxx @@ -809,8 +809,35 @@ void Ncxx4::setAttribute(const std::string &varname, const std::string &attrname } } +void Ncxx4::setAttribute(const std::string &varname, const std::string &attrname, + BoutReal value) { + TRACE("Ncxx4::setAttribute(BoutReal)"); + + BoutReal existing_att; + if (getAttribute(varname, attrname, existing_att)) { + if (value != existing_att) { + output_warn.write("Overwriting attribute '%s' of variable '%s' with '%d', was previously '%d'", + attrname.c_str(), varname.c_str(), value, existing_att); + } + } + // else: attribute does not exist, so just write it + + if (varname == "") { + // write attribute of file + dataFile->putAtt(attrname, NcType::nc_DOUBLE, value); + } else { + // write attribute of variable + NcVar var = dataFile->getVar(varname); + if (var.isNull()) { + throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); + } + + var.putAtt(attrname, NcType::nc_DOUBLE, value); + } +} + bool Ncxx4::getAttribute(const std::string &varname, const std::string &attrname, std::string &text) { - TRACE("Ncxx4::getStringAttribute(string)"); + TRACE("Ncxx4::getAttribute(string)"); if (varname == "") { // attribute of file @@ -845,7 +872,41 @@ bool Ncxx4::getAttribute(const std::string &varname, const std::string &attrname } bool Ncxx4::getAttribute(const std::string &varname, const std::string &attrname, int &value) { - TRACE("Ncxx4::getIntAttribute(string)"); + TRACE("Ncxx4::getAttribute(int)"); + + if (varname == "") { + // attribute of file + // Check if attribute exists without throwing exception when it doesn't + std::multimap fileAtts_list = dataFile->getAtts(); + if (fileAtts_list.find(attrname) == fileAtts_list.end()) { + return false; + } else { + NcGroupAtt fileAtt = dataFile->getAtt(attrname); + fileAtt.getValues(&value); + + return true; + } + } else { + NcVar var = dataFile->getVar(varname); + if (var.isNull()) { + throw BoutException("Variable '%s' not in NetCDF file", varname.c_str()); + } + + // Check if attribute exists without throwing exception when it doesn't + map varAtts_list = var.getAtts(); + if (varAtts_list.find(attrname) == varAtts_list.end()) { + return false; + } else { + NcVarAtt varAtt = var.getAtt(attrname); + varAtt.getValues(&value); + + return true; + } + } +} + +bool Ncxx4::getAttribute(const std::string &varname, const std::string &attrname, BoutReal &value) { + TRACE("Ncxx4::getAttribute(BoutReal)"); if (varname == "") { // attribute of file diff --git a/src/fileio/impls/netcdf4/ncxx4.hxx b/src/fileio/impls/netcdf4/ncxx4.hxx index 7d2b2a2ebd..59d19db23b 100644 --- a/src/fileio/impls/netcdf4/ncxx4.hxx +++ b/src/fileio/impls/netcdf4/ncxx4.hxx @@ -123,8 +123,11 @@ class Ncxx4 : public DataFormat { const std::string &text) override; void setAttribute(const std::string &varname, const std::string &attrname, int value) override; + void setAttribute(const std::string &varname, const std::string &attrname, + BoutReal value) override; bool getAttribute(const std::string &varname, const std::string &attrname, std::string &text) override; bool getAttribute(const std::string &varname, const std::string &attrname, int &value) override; + bool getAttribute(const std::string &varname, const std::string &attrname, BoutReal &value) override; private: From d5ec4548b26bbc435374bd7610c0ea55c05260f2 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 2 Nov 2018 20:20:20 +0000 Subject: [PATCH 0223/1783] Add some routines for inspecting the registered derivative methods --- include/bout/deriv_store.hxx | 40 ++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index f7c49fa7f2..a7030dcf8f 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -59,6 +59,33 @@ template struct DerivativeStore { return instance; } + /// Returns a vector of all registered method names for the + /// specified derivative type, direction and stagger. + std::vector getAvailableMethods(DERIV derivType, DIRECTION direction, STAGGER stagger = STAGGER::None) { + TRACE("%s", __thefunc__); + // Get the key + auto key = getKey(direction, stagger, DERIV_STRING(derivType)); + return getInstance().registeredMethods.at(key); + }; + + /// Outputs a list of all registered method names for the + /// specified derivative type, direction and stagger. + void listAvailableMethods(DERIV derivType, DIRECTION direction, STAGGER stagger = STAGGER::None) { + TRACE("%s", __thefunc__); + + // Introductory information + output_info << "Available methods for derivative type '"; + output_info << DERIV_STRING(derivType); + output_info << "' in direction "; + output_info << DIRECTION_STRING(direction); + output_info << " ( Staggering : "; + output_info << STAGGER_STRING(stagger) << " ) : \n"; + + for (const auto &i : getInstance().getAvailableMethods(derivType, direction, stagger)) { + output_info << "\t" << i << "\n"; + }; + }; + /// Register a function with standardFunc interface. Which map is used /// depends on the derivType input. void registerDerivative(standardFunc func, DERIV derivType, @@ -67,6 +94,10 @@ template struct DerivativeStore { TRACE("%s", __thefunc__); const auto key = getKey(direction, stagger, methodName); + // Register this method name in lookup of known methods + getInstance().registeredMethods[getKey(direction, stagger, + DERIV_STRING(derivType))].push_back(methodName); + switch (derivType) { case (DERIV::Standard): getInstance().standard[key] = func; @@ -92,6 +123,11 @@ template struct DerivativeStore { std::string methodName) { TRACE("%s", __thefunc__); const auto key = getKey(direction, stagger, methodName); + + // Register this method name in lookup of known methods + getInstance().registeredMethods[getKey(direction, stagger, + DERIV_STRING(derivType))].push_back(methodName); + switch (derivType) { case (DERIV::Upwind): getInstance().upwind[key] = func; @@ -277,8 +313,6 @@ template struct DerivativeStore { } } - - } /// The following stores what actual method to use when DIFF_DEFAULT @@ -296,6 +330,8 @@ private: std::map upwind; std::map flux; + std::map> registeredMethods; + std::string getMethodName(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); From c58d0815718f0b8573b2cc888aa0c310cb58d914 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 2 Nov 2018 20:24:37 +0000 Subject: [PATCH 0224/1783] Tidy up deriv_store code --- include/bout/deriv_store.hxx | 317 ++++++++++++++++++++--------------- 1 file changed, 180 insertions(+), 137 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index a7030dcf8f..a73d13a5b9 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -70,9 +70,10 @@ template struct DerivativeStore { /// Outputs a list of all registered method names for the /// specified derivative type, direction and stagger. - void listAvailableMethods(DERIV derivType, DIRECTION direction, STAGGER stagger = STAGGER::None) { + void listAvailableMethods(DERIV derivType, DIRECTION direction, + STAGGER stagger = STAGGER::None) { TRACE("%s", __thefunc__); - + // Introductory information output_info << "Available methods for derivative type '"; output_info << DERIV_STRING(derivType); @@ -81,23 +82,25 @@ template struct DerivativeStore { output_info << " ( Staggering : "; output_info << STAGGER_STRING(stagger) << " ) : \n"; - for (const auto &i : getInstance().getAvailableMethods(derivType, direction, stagger)) { + for (const auto &i : + getInstance().getAvailableMethods(derivType, direction, stagger)) { output_info << "\t" << i << "\n"; }; }; - + /// Register a function with standardFunc interface. Which map is used /// depends on the derivType input. void registerDerivative(standardFunc func, DERIV derivType, - DIRECTION direction, STAGGER stagger, - std::string methodName) { + DIRECTION direction, STAGGER stagger, + std::string methodName) { TRACE("%s", __thefunc__); const auto key = getKey(direction, stagger, methodName); // Register this method name in lookup of known methods - getInstance().registeredMethods[getKey(direction, stagger, - DERIV_STRING(derivType))].push_back(methodName); - + getInstance() + .registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))] + .push_back(methodName); + switch (derivType) { case (DERIV::Standard): getInstance().standard[key] = func; @@ -109,24 +112,25 @@ template struct DerivativeStore { getInstance().standardFourth[key] = func; return; default: - throw BoutException("Invalid function signature in registerDerivative : Function " - "signature 'standard' but derivative type %s passed", - DERIV_STRING(derivType).c_str()); + throw BoutException( + "Invalid function signature in registerDerivative : Function " + "signature 'standard' but derivative type %s passed", + DERIV_STRING(derivType).c_str()); }; return; }; /// Register a function with upwindFunc/fluxFunc interface. Which map is used /// depends on the derivType input. - void registerDerivative(upwindFunc func, DERIV derivType, - DIRECTION direction, STAGGER stagger, - std::string methodName) { + void registerDerivative(upwindFunc func, DERIV derivType, DIRECTION direction, + STAGGER stagger, std::string methodName) { TRACE("%s", __thefunc__); const auto key = getKey(direction, stagger, methodName); // Register this method name in lookup of known methods - getInstance().registeredMethods[getKey(direction, stagger, - DERIV_STRING(derivType))].push_back(methodName); + getInstance() + .registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))] + .push_back(methodName); switch (derivType) { case (DERIV::Upwind): @@ -136,9 +140,10 @@ template struct DerivativeStore { getInstance().flux[key] = func; return; default: - throw BoutException("Invalid function signature in registerDerivative : Function " - "signature 'upwind/flux' but derivative type %s passed", - DERIV_STRING(derivType).c_str()); + throw BoutException( + "Invalid function signature in registerDerivative : Function " + "signature 'upwind/flux' but derivative type %s passed", + DERIV_STRING(derivType).c_str()); }; return; }; @@ -148,169 +153,194 @@ template struct DerivativeStore { void registerDerivative(standardFunc func) { TRACE("%s", __thefunc__); registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), - Stagger{}.lookup(), Method{}.meta.key); + Stagger{}.lookup(), Method{}.meta.key); }; template void registerDerivative(upwindFunc func) { TRACE("%s", __thefunc__); registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), - Stagger{}.lookup(), Method{}.meta.key); + Stagger{}.lookup(), Method{}.meta.key); }; - /// Routines to return a specific differential operator. Note we have to have a separate + /// Routines to return a specific differential operator. Note we have to have + /// a separate /// routine for different - /// methods as they have different return types. As such we choose to use a different + /// methods as they have different return types. As such we choose to use a + /// different /// name for each of the /// method-classes so everything is consistently treated standardFunc getStandardDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) const { + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); - const auto realName = nameLookup(name, - defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Standard)))); + const auto realName = + nameLookup(name, + defaultMethods.at(getKey(direction, stagger, + DERIV_STRING(DERIV::Standard)))); const auto key = getKey(direction, stagger, realName); const auto resultOfFind = instance.standard.find(key); if (resultOfFind != instance.standard.end()) return resultOfFind->second; throw BoutException( - "Couldn't find requested method %s in map for standard derivative.", - getMethodName(realName, direction, stagger).c_str()); + "Couldn't find requested method %s in map for standard derivative.", + getMethodName(realName, direction, stagger).c_str()); }; standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) const { + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); - const auto realName = nameLookup(name, - defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::StandardSecond)))); + const auto realName = nameLookup( + name, + defaultMethods.at( + getKey(direction, stagger, DERIV_STRING(DERIV::StandardSecond)))); const auto key = getKey(direction, stagger, realName); const auto resultOfFind = instance.standardSecond.find(key); if (resultOfFind != instance.standardSecond.end()) return resultOfFind->second; - throw BoutException( - "Couldn't find requested method %s in map for standardSecond derivative.", - getMethodName(realName, direction, stagger).c_str()); + throw BoutException("Couldn't find requested method %s in map for " + "standardSecond derivative.", + getMethodName(realName, direction, stagger).c_str()); }; standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) const { + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); - const auto realName = nameLookup(name, - defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::StandardFourth)))); + const auto realName = nameLookup( + name, + defaultMethods.at( + getKey(direction, stagger, DERIV_STRING(DERIV::StandardFourth)))); const auto key = getKey(direction, stagger, realName); const auto resultOfFind = instance.standardFourth.find(key); if (resultOfFind != instance.standardFourth.end()) return resultOfFind->second; - throw BoutException( - "Couldn't find requested method %s in map for standardFourth derivative.", - getMethodName(realName, direction, stagger).c_str()); + throw BoutException("Couldn't find requested method %s in map for " + "standardFourth derivative.", + getMethodName(realName, direction, stagger).c_str()); }; upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) const { + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); - const auto realName = nameLookup(name, - defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Upwind)))); + const auto realName = + nameLookup(name, + defaultMethods.at(getKey(direction, stagger, + DERIV_STRING(DERIV::Upwind)))); const auto key = getKey(direction, stagger, realName); const auto resultOfFind = instance.upwind.find(key); if (resultOfFind != instance.upwind.end()) return resultOfFind->second; - throw BoutException("Couldn't find requested method %s in map for upwind derivative.", - getMethodName(realName, direction, stagger).c_str()); + throw BoutException( + "Couldn't find requested method %s in map for upwind derivative.", + getMethodName(realName, direction, stagger).c_str()); }; fluxFunc getFluxDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) const { + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); const auto instance = getInstance(); - const auto realName = nameLookup(name, - defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Flux)))); + const auto realName = + nameLookup(name, + defaultMethods.at( + getKey(direction, stagger, DERIV_STRING(DERIV::Flux)))); const auto key = getKey(direction, stagger, realName); const auto resultOfFind = instance.flux.find(key); if (resultOfFind != instance.flux.end()) return resultOfFind->second; - throw BoutException("Couldn't find requested method %s in map for flux derivative.", - getMethodName(realName, direction, stagger).c_str()); + throw BoutException( + "Couldn't find requested method %s in map for flux derivative.", + getMethodName(realName, direction, stagger).c_str()); }; void initialise(Options *options) { TRACE("%s", __thefunc__); - //To replicate the existing behaviour we first search for a section called + // To replicate the existing behaviour we first search for a section called //"dd?" and if the option isn't in there we search a section called "diff" auto backupSection = options->getSection("diff"); std::map initialDefaultMethods = { - {DERIV::Standard, "C2"}, {DERIV::StandardSecond, "C2"}, {DERIV::StandardFourth, "C2"}, - {DERIV::Upwind, "U1"}, {DERIV::Flux, "U1"}}; - + {DERIV::Standard, "C2"}, + {DERIV::StandardSecond, "C2"}, + {DERIV::StandardFourth, "C2"}, + {DERIV::Upwind, "U1"}, + {DERIV::Flux, "U1"}}; + std::map directions = { - {DIRECTION::X,"ddx"}, {DIRECTION::Y,"ddy"}, {DIRECTION::YOrthogonal,"ddy"}, {DIRECTION::Z,"ddz"} - }; + {DIRECTION::X, "ddx"}, + {DIRECTION::Y, "ddy"}, + {DIRECTION::YOrthogonal, "ddy"}, + {DIRECTION::Z, "ddz"}}; std::map derivTypes = { - {DERIV::Standard,"First"}, {DERIV::StandardSecond,"Second"}, - {DERIV::StandardFourth,"Fourth"}, {DERIV::Upwind,"Upwind"}, - {DERIV::Flux,"Flux"} - }; - - for(const auto& direction : directions) { - for(const auto& deriv : derivTypes) { - std::string theDefault; - - // This corresponds to the key in the input file - auto derivName = deriv.second; - - const auto theDirection = direction.first; - const auto theDerivType = deriv.first; - const auto theDerivTypeString = DERIV_STRING(theDerivType); - - //------------------------------------------------------------- - // Unstaggered - //------------------------------------------------------------- - - // The direction specific section to consider - auto specificSection = options->getSection(direction.second); - - // Find the appropriate value for theDefault either from - // the input file or if not found then use the value in initialDefaultMethods - if(specificSection->isSet(derivName)) { - specificSection->get(derivName, theDefault, ""); - } else if (backupSection->isSet(derivName)) { - backupSection->get(derivName, theDefault, ""); - } else { - theDefault = initialDefaultMethods[theDerivType]; - } - - // Now we have the default method we should store it in defaultMethods - theDefault = uppercase(theDefault); - defaultMethods[getKey(theDirection, STAGGER::None, theDerivTypeString)] = theDefault; - output_info << "The default method for derivative type "<< theDerivTypeString; - output_info << " in direction "<getSection(direction.second+"stag"); - - // Find the appropriate value for theDefault either from - // the input file. Note if the specific section for staggering isn't - // found then we leave the default as for the non-staggered version - if(specificSection->isSet(derivName)) { - specificSection->get(derivName, theDefault, ""); - } - - // Now we have the default method we should store it in defaultMethods - theDefault = uppercase(theDefault); - defaultMethods[getKey(theDirection, STAGGER::L2C, theDerivTypeString)] = theDefault; - defaultMethods[getKey(theDirection, STAGGER::C2L, theDerivTypeString)] = theDefault; - output_info << "The default method for staggered derivative type "<< theDerivTypeString; - output_info << " in direction "<getSection(direction.second); + + // Find the appropriate value for theDefault either from + // the input file or if not found then use the value in + // initialDefaultMethods + if (specificSection->isSet(derivName)) { + specificSection->get(derivName, theDefault, ""); + } else if (backupSection->isSet(derivName)) { + backupSection->get(derivName, theDefault, ""); + } else { + theDefault = initialDefaultMethods[theDerivType]; + } + + // Now we have the default method we should store it in defaultMethods + theDefault = uppercase(theDefault); + defaultMethods[getKey(theDirection, STAGGER::None, + theDerivTypeString)] = theDefault; + output_info << "The default method for derivative type " + << theDerivTypeString; + output_info << " in direction " << DIRECTION_STRING(theDirection); + output_info << " is " << theDefault << "\n"; + + //------------------------------------------------------------- + // Staggered + //------------------------------------------------------------- + + // The direction specific section to consider with staggering + specificSection = options->getSection(direction.second + "stag"); + + // Find the appropriate value for theDefault either from + // the input file. Note if the specific section for staggering isn't + // found then we leave the default as for the non-staggered version + if (specificSection->isSet(derivName)) { + specificSection->get(derivName, theDefault, ""); + } + + // Now we have the default method we should store it in defaultMethods + theDefault = uppercase(theDefault); + defaultMethods[getKey(theDirection, STAGGER::L2C, theDerivTypeString)] = + theDefault; + defaultMethods[getKey(theDirection, STAGGER::C2L, theDerivTypeString)] = + theDefault; + output_info << "The default method for staggered derivative type " + << theDerivTypeString; + output_info << " in direction " << DIRECTION_STRING(theDirection); + output_info << " is " << theDefault << "\n"; } } } @@ -322,7 +352,7 @@ template struct DerivativeStore { /// currently assume the default method is independent of staggering -- /// it might be useful to relax this assumption! std::map defaultMethods; - + private: std::map standard; std::map standardSecond; @@ -331,28 +361,37 @@ private: std::map flux; std::map> registeredMethods; - + std::string getMethodName(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) const { + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); - return name + " (" + DIRECTION_STRING(direction) + ", " + STAGGER_STRING(stagger) + - ")"; + return name + " (" + DIRECTION_STRING(direction) + ", " + + STAGGER_STRING(stagger) + ")"; }; - std::string nameLookup(const std::string name, const std::string defaultName) const { - return name != DIFF_METHOD_STRING(DIFF_DEFAULT) ? name : defaultName; + std::string nameLookup(const std::string name, + const std::string defaultName) const { + return name != DIFF_METHOD_STRING(DIFF_DEFAULT) ? name : defaultName; } - /// Provides a routine to produce a unique key given information about the specific type - /// required. This is templated so requires compile-time information. Need to also + + /// Provides a routine to produce a unique key given information about the + /// specific type + /// required. This is templated so requires compile-time information. Need to + /// also /// supply /// a non-templated version to account for run-time choices - /// Note : We could include the derivType in the key -- this would allow us to store - /// all methods with the same function interface in the same map, which might be nice. - std::size_t getKey(DIRECTION direction, STAGGER stagger, std::string key) const { + /// Note : We could include the derivType in the key -- this would allow us to + /// store + /// all methods with the same function interface in the same map, which might + /// be nice. + std::size_t getKey(DIRECTION direction, STAGGER stagger, + std::string key) const { TRACE("%s", __thefunc__); - // Note this key is indepedent of the field type (and hence the key is the same for + // Note this key is indepedent of the field type (and hence the key is the + // same for // 3D/2D - // fields) as we have to use different maps to store the different field types as the + // fields) as we have to use different maps to store the different field + // types as the // signature is different. std::size_t result; result = std::hash{}(DIRECTION_STRING(direction)); @@ -361,15 +400,19 @@ private: return result; } - /// Provides a routine to produce a unique key given information about the specific type - /// required. This is templated so requires compile-time information. Makes use of + /// Provides a routine to produce a unique key given information about the + /// specific type + /// required. This is templated so requires compile-time information. Makes + /// use of /// a non-templated version that can be used to account for run-time choices template std::size_t getKey() const { TRACE("%s", __thefunc__); - // Note this key is indepedent of the field type (and hence the key is the same for + // Note this key is indepedent of the field type (and hence the key is the + // same for // 3D/2D - // fields) as we have to use different maps to store the different field types as the + // fields) as we have to use different maps to store the different field + // types as the // signature is different. return getKey(Direction{}.lookup(), Stagger{}.lookup(), Method{}.meta.key); } From 45197e0356d653946b38e869ac5cb379b3fad67d Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 2 Nov 2018 20:46:20 +0000 Subject: [PATCH 0225/1783] Make introspection routines const --- include/bout/deriv_store.hxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index a73d13a5b9..5996dde9dc 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -61,7 +61,8 @@ template struct DerivativeStore { /// Returns a vector of all registered method names for the /// specified derivative type, direction and stagger. - std::vector getAvailableMethods(DERIV derivType, DIRECTION direction, STAGGER stagger = STAGGER::None) { + std::vector getAvailableMethods(DERIV derivType, DIRECTION direction, + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); // Get the key auto key = getKey(direction, stagger, DERIV_STRING(derivType)); @@ -71,7 +72,7 @@ template struct DerivativeStore { /// Outputs a list of all registered method names for the /// specified derivative type, direction and stagger. void listAvailableMethods(DERIV derivType, DIRECTION direction, - STAGGER stagger = STAGGER::None) { + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); // Introductory information From d88ef4e2d8c815d67f0888024bd31563806e8438 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 5 Nov 2018 14:44:18 +0000 Subject: [PATCH 0226/1783] Make sure can't create instances of deriv_store outside struct. Take advantage of this to remove calls to getInstance inside the struct member routines. This reduces the overhead of getting derivative operators out of the store. --- include/bout/deriv_store.hxx | 81 ++++++++++++++++++++---------------- include/bout/derivs.hxx | 2 +- include/bout/mesh.hxx | 4 +- 3 files changed, 48 insertions(+), 39 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 5996dde9dc..1f114c2819 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -31,6 +31,7 @@ #include #include +#include #include @@ -52,9 +53,17 @@ template struct DerivativeStore { const REGION)>; using fluxFunc = std::function; + +#ifdef USE_ORDERED_MAP_FOR_DERIVATIVE_STORE + template + using storageType = std::map; +#else + template + using storageType = std::unordered_map; +#endif // Singleton method - static DerivativeStore &getInstance() { + static DerivativeStore& getInstance() { static DerivativeStore instance; return instance; } @@ -66,7 +75,7 @@ template struct DerivativeStore { TRACE("%s", __thefunc__); // Get the key auto key = getKey(direction, stagger, DERIV_STRING(derivType)); - return getInstance().registeredMethods.at(key); + return registeredMethods.at(key); }; /// Outputs a list of all registered method names for the @@ -84,7 +93,7 @@ template struct DerivativeStore { output_info << STAGGER_STRING(stagger) << " ) : \n"; for (const auto &i : - getInstance().getAvailableMethods(derivType, direction, stagger)) { + getAvailableMethods(derivType, direction, stagger)) { output_info << "\t" << i << "\n"; }; }; @@ -98,19 +107,18 @@ template struct DerivativeStore { const auto key = getKey(direction, stagger, methodName); // Register this method name in lookup of known methods - getInstance() - .registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))] - .push_back(methodName); + registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))] + .push_back(methodName); switch (derivType) { case (DERIV::Standard): - getInstance().standard[key] = func; + standard[key] = func; return; case (DERIV::StandardSecond): - getInstance().standardSecond[key] = func; + standardSecond[key] = func; return; case (DERIV::StandardFourth): - getInstance().standardFourth[key] = func; + standardFourth[key] = func; return; default: throw BoutException( @@ -129,16 +137,15 @@ template struct DerivativeStore { const auto key = getKey(direction, stagger, methodName); // Register this method name in lookup of known methods - getInstance() - .registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))] + registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))] .push_back(methodName); switch (derivType) { case (DERIV::Upwind): - getInstance().upwind[key] = func; + upwind[key] = func; return; case (DERIV::Flux): - getInstance().flux[key] = func; + flux[key] = func; return; default: throw BoutException( @@ -173,14 +180,13 @@ template struct DerivativeStore { standardFunc getStandardDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); - const auto instance = getInstance(); const auto realName = nameLookup(name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Standard)))); const auto key = getKey(direction, stagger, realName); - const auto resultOfFind = instance.standard.find(key); - if (resultOfFind != instance.standard.end()) + const auto resultOfFind = standard.find(key); + if (resultOfFind != standard.end()) return resultOfFind->second; throw BoutException( "Couldn't find requested method %s in map for standard derivative.", @@ -190,14 +196,13 @@ template struct DerivativeStore { standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); - const auto instance = getInstance(); const auto realName = nameLookup( name, defaultMethods.at( getKey(direction, stagger, DERIV_STRING(DERIV::StandardSecond)))); const auto key = getKey(direction, stagger, realName); - const auto resultOfFind = instance.standardSecond.find(key); - if (resultOfFind != instance.standardSecond.end()) + const auto resultOfFind = standardSecond.find(key); + if (resultOfFind != standardSecond.end()) return resultOfFind->second; throw BoutException("Couldn't find requested method %s in map for " "standardSecond derivative.", @@ -207,30 +212,29 @@ template struct DerivativeStore { standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); - const auto instance = getInstance(); const auto realName = nameLookup( name, defaultMethods.at( getKey(direction, stagger, DERIV_STRING(DERIV::StandardFourth)))); const auto key = getKey(direction, stagger, realName); - const auto resultOfFind = instance.standardFourth.find(key); - if (resultOfFind != instance.standardFourth.end()) + const auto resultOfFind = standardFourth.find(key); + if (resultOfFind != standardFourth.end()) return resultOfFind->second; throw BoutException("Couldn't find requested method %s in map for " "standardFourth derivative.", getMethodName(realName, direction, stagger).c_str()); }; + upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); - const auto instance = getInstance(); const auto realName = nameLookup(name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Upwind)))); const auto key = getKey(direction, stagger, realName); - const auto resultOfFind = instance.upwind.find(key); - if (resultOfFind != instance.upwind.end()) + const auto resultOfFind = upwind.find(key); + if (resultOfFind != upwind.end()) return resultOfFind->second; throw BoutException( "Couldn't find requested method %s in map for upwind derivative.", @@ -239,14 +243,13 @@ template struct DerivativeStore { fluxFunc getFluxDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); - const auto instance = getInstance(); const auto realName = nameLookup(name, defaultMethods.at( getKey(direction, stagger, DERIV_STRING(DERIV::Flux)))); const auto key = getKey(direction, stagger, realName); - const auto resultOfFind = instance.flux.find(key); - if (resultOfFind != instance.flux.end()) + const auto resultOfFind = flux.find(key); + if (resultOfFind != flux.end()) return resultOfFind->second; throw BoutException( "Couldn't find requested method %s in map for flux derivative.", @@ -352,16 +355,22 @@ template struct DerivativeStore { /// upwind etc.). Note for now we'll always use STAGGER::None as we /// currently assume the default method is independent of staggering -- /// it might be useful to relax this assumption! - std::map defaultMethods; + storageType defaultMethods; private: - std::map standard; - std::map standardSecond; - std::map standardFourth; - std::map upwind; - std::map flux; - - std::map> registeredMethods; + // Make the constructor private so we can't make instances outside + // of the struct + DerivativeStore(){}; + // No copy constructor allowed + DerivativeStore(const DerivativeStore &junk) = delete; + + storageType standard; + storageType standardSecond; + storageType standardFourth; + storageType upwind; + storageType flux; + + storageType> registeredMethods; std::string getMethodName(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { diff --git a/include/bout/derivs.hxx b/include/bout/derivs.hxx index 7d4a89eb5a..e96d0c58b6 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/derivs.hxx @@ -489,7 +489,7 @@ struct registerMethod { // removed and we can use nGuard directly in the template statement. const int nGuards = Method{}.meta.nGuards; - auto derivativeRegister = DerivativeStore::getInstance(); + auto& derivativeRegister = DerivativeStore::getInstance(); switch (Method{}.meta.derivType) { case (DERIV::Standard): diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 30bc1b0ae7..eb82dbcccc 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -806,7 +806,7 @@ T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METH } // Lookup the method - auto derivativeStore = DerivativeStore{}.getInstance(); + auto& derivativeStore = DerivativeStore::getInstance(); typename DerivativeStore::upwindFunc derivativeMethod; if (derivType == DERIV::Upwind) { derivativeMethod = derivativeStore.getUpwindDerivative(DIFF_METHOD_STRING(method), direction, stagger); @@ -870,7 +870,7 @@ T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, } // Lookup the method - auto derivativeStore = DerivativeStore{}.getInstance(); + auto& derivativeStore = DerivativeStore::getInstance(); typename DerivativeStore::standardFunc derivativeMethod; if (order == 1) { From 8bf186476bcb482bf393d9ee7f80fcd036401a0d Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 5 Nov 2018 15:01:40 +0000 Subject: [PATCH 0227/1783] Remove obsolete cases from iterator-offsets test Adds two new cases to test the derivative methods in the DerivativeStore --- .../iterator-offsets/iterator-offsets.cxx | 200 ++++-------------- .../iterator-offsets/make_scaling_example.sh | 5 +- 2 files changed, 44 insertions(+), 161 deletions(-) diff --git a/examples/performance/iterator-offsets/iterator-offsets.cxx b/examples/performance/iterator-offsets/iterator-offsets.cxx index d1e069cfe0..a64eccf580 100644 --- a/examples/performance/iterator-offsets/iterator-offsets.cxx +++ b/examples/performance/iterator-offsets/iterator-offsets.cxx @@ -34,7 +34,8 @@ BoutReal test_ddy(stencil &s) { return (s.p - s.m); } -Mesh::deriv_func func_ptr = &test_ddy; +typedef BoutReal (*deriv_func)(stencil &); +deriv_func func_ptr = &test_ddy; int main(int argc, char **argv) { BoutInitialise(argc, argv); @@ -86,170 +87,51 @@ int main(int argc, char **argv) { } ); - // Range based for DataIterator with indices - ITERATOR_TEST_BLOCK( - "C++11 range-based for (omp)", - BOUT_OMP(parallel) - for(auto i : result.region(RGN_NOY)){ - result(i.x,i.y,i.z) = (a(i.x,i.y+1,i.z) - a(i.x,i.y-1,i.z)); - } - ); - - // Range based DataIterator - ITERATOR_TEST_BLOCK( - "C++11 range-based for [i] (omp)", - BOUT_OMP(parallel) - for(const auto &i : result.region(RGN_NOY)){ - result[i] = (a[i.yp()] - a[i.ym()]); - } - ); - - ITERATOR_TEST_BLOCK( - "C++11 range-based for over Region [i] (omp)", - BOUT_OMP(parallel) - { - for(const auto &i : mesh->getRegion3D("RGN_NOY")){ - result[i] = (a[i.yp()] - a[i.ym()]); - } - } - ); - - ITERATOR_TEST_BLOCK( - "C++11 range-based for [i] with stencil (omp)", - BOUT_OMP(parallel) - { - stencil s; - for(const auto &i : result.region(RGN_NOY)){ - s.mm = nan(""); - s.m = a[i.ym()]; - s.c = a[i]; - s.p = a[i.yp()]; - s.pp = nan(""); - result[i] = (s.p - s.m); - } - } - ); #endif + { + auto deriv = DerivativeStore::getInstance().getStandardDerivative("C2",DIRECTION::Y, STAGGER::None); + ITERATOR_TEST_BLOCK( + "DerivativeStore without fetching", + deriv(a, result, RGN_NOY); + ); + }; + ITERATOR_TEST_BLOCK( - "C++11 range-based for [i] with stencil (serial)", - stencil s; - for(const auto &i : result.region(RGN_NOY)){ - s.mm = nan(""); - s.m = a[i.ym()]; - s.c = a[i]; - s.p = a[i.yp()]; - s.pp = nan(""); - result[i] = (s.p - s.m); - } - ); - - // Region macro - ITERATOR_TEST_BLOCK( - "Region with stencil (serial)", - stencil s; - BOUT_FOR_SERIAL(i, mesh->getRegion3D("RGN_NOY")) { - s.mm = nan(""); - s.m = a[i.ym()]; - s.c = a[i]; - s.p = a[i.yp()]; - s.pp = nan(""); - - result[i] = (s.p - s.m); - } - ); - -#ifdef _OPENMP - - ITERATOR_TEST_BLOCK( - "Region with stencil (parallel section nowait omp)", - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, mesh->getRegion3D("RGN_NOY")) { - s.mm = nan(""); - s.m = a[i.ym()]; - s.c = a[i]; - s.p = a[i.yp()]; - s.pp = nan(""); - - result[i] = (s.p - s.m); - } - } - ); - - ITERATOR_TEST_BLOCK( - "Region with stencil (parallel section wait omp)", - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_OMP(i, mesh->getRegion3D("RGN_NOY"), for schedule(guided)) { - s.mm = nan(""); - s.m = a[i.ym()]; - s.c = a[i]; - s.p = a[i.yp()]; - s.pp = nan(""); - - result[i] = (s.p - s.m); - } - } - ); + "DerivativeStore with fetch", + auto deriv = DerivativeStore::getInstance().getStandardDerivative("C2",DIRECTION::Y, STAGGER::None); + deriv(a, result, RGN_NOY); + ); ITERATOR_TEST_BLOCK( - "Region with stencil & raw ints (parallel section omp)", - const auto nz = mesh->LocalNz; - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, mesh->getRegion3D("RGN_NOY")) { - s.mm = nan(""); - s.m = a[i.ind - (nz)]; - s.c = a[i.ind]; - s.p = a[i.ind + (nz)]; - s.pp = nan(""); - - result[i] = (s.p - s.m); - } - } - ); - - ITERATOR_TEST_BLOCK( - "Region with stencil (single loop omp)", - BOUT_OMP(parallel) - { - stencil s; - const auto ®ion = mesh->getRegion3D("RGN_NOY").getIndices(); - BOUT_OMP(for schedule(guided)) - for (auto i = region.cbegin(); i < region.cend(); ++i) { - s.mm = nan(""); - s.m = a[i->ym()]; - s.c = a[*i]; - s.p = a[i->yp()]; - s.pp = nan(""); - - result[*i] = (s.p - s.m); - } - } - ); - + "Region with stencil", + BOUT_OMP(parallel) + { + stencil s; + BOUT_FOR_INNER(i, mesh->getRegion3D("RGN_NOY")) { + s.m = a[i.ym()]; + s.c = a[i]; + s.p = a[i.yp()]; + + result[i] = (s.p - s.m); + } + } + ); + ITERATOR_TEST_BLOCK( - "Region with stencil and function pointer (parallel section nowait omp)", - BOUT_OMP(parallel) - { - stencil s; - BOUT_FOR_INNER(i, mesh->getRegion3D("RGN_NOY")) { - s.mm = nan(""); - s.m = a[i.ym()]; - s.c = a[i]; - s.p = a[i.yp()]; - s.pp = nan(""); - - result[i] = func_ptr(s); - } - } - ); - -#endif + "Region with stencil and function pointer", + BOUT_OMP(parallel) + { + stencil s; + BOUT_FOR_INNER(i, mesh->getRegion3D("RGN_NOY")) { + s.m = a[i.ym()]; + s.c = a[i]; + s.p = a[i.yp()]; + + result[i] = func_ptr(s); + } + } + ); if (profileMode) { int nthreads = 0; diff --git a/examples/performance/iterator-offsets/make_scaling_example.sh b/examples/performance/iterator-offsets/make_scaling_example.sh index 99bf54d7e5..c3b861ffaa 100755 --- a/examples/performance/iterator-offsets/make_scaling_example.sh +++ b/examples/performance/iterator-offsets/make_scaling_example.sh @@ -5,15 +5,16 @@ GRID_SIZES=(4 8 16 32 64 128) EXE=iterator-offsets NP=1 +NTHREADS=1 FLAGS="-q -q -q -q performanceIterator:profileMode=true" #Make first run currGrid=${GRID_SIZES[0]} -mpirun -np ${NP} ./${EXE} ${FLAGS} mesh:nx=${currGrid} mesh:ny=${currGrid} mesh:nz=${currGrid} +OMP_NUM_THREADS=${NTHREADS} mpirun -np ${NP} ./${EXE} ${FLAGS} mesh:nx=${currGrid} mesh:ny=${currGrid} mesh:nz=${currGrid} #Do other values for currGrid in ${GRID_SIZES[@]:1} do - mpirun -np ${NP} ./${EXE} ${FLAGS} mesh:nx=${currGrid} mesh:ny=${currGrid} mesh:nz=${currGrid} performanceIterator:includeHeader=false + OMP_NUM_THREADS=${NTHREADS} mpirun -np ${NP} ./${EXE} ${FLAGS} mesh:nx=${currGrid} mesh:ny=${currGrid} mesh:nz=${currGrid} performanceIterator:includeHeader=false done From c6da1903b02c7b153c0fa82090de150fd4bac955 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 6 Nov 2018 14:53:15 +0000 Subject: [PATCH 0228/1783] Adding some simple performance tests for different derivative methods --- examples/performance/ddx/data/BOUT.inp | 13 ++ examples/performance/ddx/ddx.cxx | 152 +++++++++++++++++ .../performance/ddx/make_scaling_example.sh | 28 ++++ examples/performance/ddx/makefile | 6 + .../performance/ddx/new_scaling_parser.py | 55 ++++++ examples/performance/ddy/data/BOUT.inp | 13 ++ examples/performance/ddy/ddy.cxx | 152 +++++++++++++++++ .../performance/ddy/make_scaling_example.sh | 28 ++++ examples/performance/ddy/makefile | 6 + .../performance/ddy/new_scaling_parser.py | 55 ++++++ examples/performance/ddz/data/BOUT.inp | 13 ++ examples/performance/ddz/ddz.cxx | 157 ++++++++++++++++++ .../performance/ddz/make_scaling_example.sh | 28 ++++ examples/performance/ddz/makefile | 6 + .../performance/ddz/new_scaling_parser.py | 55 ++++++ 15 files changed, 767 insertions(+) create mode 100644 examples/performance/ddx/data/BOUT.inp create mode 100644 examples/performance/ddx/ddx.cxx create mode 100755 examples/performance/ddx/make_scaling_example.sh create mode 100644 examples/performance/ddx/makefile create mode 100644 examples/performance/ddx/new_scaling_parser.py create mode 100644 examples/performance/ddy/data/BOUT.inp create mode 100644 examples/performance/ddy/ddy.cxx create mode 100755 examples/performance/ddy/make_scaling_example.sh create mode 100644 examples/performance/ddy/makefile create mode 100644 examples/performance/ddy/new_scaling_parser.py create mode 100644 examples/performance/ddz/data/BOUT.inp create mode 100644 examples/performance/ddz/ddz.cxx create mode 100755 examples/performance/ddz/make_scaling_example.sh create mode 100644 examples/performance/ddz/makefile create mode 100644 examples/performance/ddz/new_scaling_parser.py diff --git a/examples/performance/ddx/data/BOUT.inp b/examples/performance/ddx/data/BOUT.inp new file mode 100644 index 0000000000..11e3cbf4b7 --- /dev/null +++ b/examples/performance/ddx/data/BOUT.inp @@ -0,0 +1,13 @@ + +MZ = 100 +MXG=1 +MYG=1 + +[mesh] +nx = 100 +ny = 100 + +[performanceIterator] +NUM_LOOPS = 50 +profileMode = false +includeHeader = true \ No newline at end of file diff --git a/examples/performance/ddx/ddx.cxx b/examples/performance/ddx/ddx.cxx new file mode 100644 index 0000000000..a895ada0bd --- /dev/null +++ b/examples/performance/ddx/ddx.cxx @@ -0,0 +1,152 @@ +/* + * Testing performance of iterators over the mesh + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "bout/openmpwrap.hxx" +#include "bout/region.hxx" +#include "derivs.hxx" + +using SteadyClock = std::chrono::time_point; +using Duration = std::chrono::duration; +using namespace std::chrono; + +#define ITERATOR_TEST_BLOCK(NAME, ...) \ + { \ + __VA_ARGS__ \ + names.push_back(NAME); \ + SteadyClock start = steady_clock::now(); \ + for (int repetitionIndex = 0; repetitionIndex < NUM_LOOPS; repetitionIndex++) { \ + __VA_ARGS__; \ + } \ + times.push_back(steady_clock::now() - start); \ + } + +BoutReal test_ddy(stencil &s) { + return (s.p - s.m); +} + +typedef BoutReal (*deriv_func)(stencil &); +deriv_func func_ptr = &test_ddy; + +int main(int argc, char **argv) { + BoutInitialise(argc, argv); + std::vector names; + std::vector times; + + //Get options root + Options *globalOptions = Options::getRoot(); + Options *modelOpts = globalOptions->getSection("performanceIterator"); + int NUM_LOOPS; + OPTION(modelOpts, NUM_LOOPS, 100); + bool profileMode, includeHeader; + OPTION(modelOpts, profileMode, false); + OPTION(modelOpts, includeHeader, false); + + ConditionalOutput time_output{Output::getInstance()}; + time_output.enable(true); + + const Field3D a{1.0}; + const Field3D b{2.0}; + + Field3D result; + result.allocate(); + + const int len = mesh->LocalNx*mesh->LocalNy*mesh->LocalNz; + + // Nested loops over block data + ITERATOR_TEST_BLOCK( + "DDX Default", + result = DDX(a); + ); + + ITERATOR_TEST_BLOCK( + "DDX C2", + result = DDX(a, CELL_DEFAULT, DIFF_C2); + ); + + ITERATOR_TEST_BLOCK( + "DDX C4", + result = DDX(a, CELL_DEFAULT, DIFF_C4); + ); + + ITERATOR_TEST_BLOCK( + "DDX S2", + result = DDX(a, CELL_DEFAULT, DIFF_S2); + ); + + ITERATOR_TEST_BLOCK( + "DDX W2", + result = DDX(a, CELL_DEFAULT, DIFF_W2); + ); + + ITERATOR_TEST_BLOCK( + "DDX W3", + result = DDX(a, CELL_DEFAULT, DIFF_W3); + ); + + if (profileMode) { + int nthreads = 0; +#ifdef _OPENMP + nthreads = omp_get_max_threads(); +#endif + + int width = 12; + if (includeHeader) { + time_output << "\n------------------------------------------------\n"; + time_output << "Case legend"; + time_output << "\n------------------------------------------------\n"; + + for (std::size_t i = 0; i < names.size(); i++) { + time_output << std::setw(width) << "Case " << i << ".\t" << names[i] << "\n"; + } + time_output << "\n"; + time_output << std::setw(width) << "Nprocs" << "\t"; + time_output << std::setw(width) << "Nthreads" << "\t"; + time_output << std::setw(width) << "Num_loops" << "\t"; + time_output << std::setw(width) << "Local grid" << "\t"; + time_output << std::setw(width) << "Nx (global)" << "\t"; + time_output << std::setw(width) << "Ny (global)" << "\t"; + time_output << std::setw(width) << "Nz (global)" << "\t"; + for (std::size_t i = 0; i < names.size(); i++) { + time_output << std::setw(width) << "Case " << i << "\t"; + } + time_output << "\n"; + } + + time_output << std::setw(width) << BoutComm::size() << "\t"; + time_output << std::setw(width) << nthreads << "\t"; + time_output << std::setw(width) << NUM_LOOPS << "\t"; + time_output << std::setw(width) << len << "\t"; + time_output << std::setw(width) << mesh->GlobalNx << "\t"; + time_output << std::setw(width) << mesh->GlobalNy << "\t"; + time_output << std::setw(width) << mesh->GlobalNz << "\t"; + for (const auto &time : times) { + time_output << std::setw(width) << time.count() / NUM_LOOPS << "\t"; + } + time_output << "\n"; + } else { + std::vector sizes(names.size()); + std::transform(names.begin(), names.end(), sizes.begin(), + [](const std::string &name) -> int { return static_cast(name.size()); }); + int width = *std::max_element(sizes.begin(), sizes.end()); + width += 5; + time_output << std::setw(width) << "Case name" << "\t" << "Time per iteration (s)" << "\n"; + for (std::size_t i = 0; i < names.size(); i++) { + time_output << std::setw(width) << names[i] << "\t" << times[i].count() / NUM_LOOPS + << "\n"; + } + }; + + BoutFinalise(); + return 0; +} diff --git a/examples/performance/ddx/make_scaling_example.sh b/examples/performance/ddx/make_scaling_example.sh new file mode 100755 index 0000000000..fb9f515114 --- /dev/null +++ b/examples/performance/ddx/make_scaling_example.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +#A simple example of using the iterator test to explore scaling of the different approaches + +GRID_SIZES=(4 8 16 32 64 128) +EXE=ddx +NP=1 +NTHREADS=1 +FLAGS="-q -q -q -q performanceIterator:profileMode=true" + +#Make first run +currGrid=${GRID_SIZES[0]} +OMP_NUM_THREADS=${NTHREADS} mpirun -np ${NP} ./${EXE} ${FLAGS} mesh:nx=${currGrid} mesh:ny=${currGrid} mesh:nz=${currGrid} +#Do other values +for currGrid in ${GRID_SIZES[@]:1} +do + OMP_NUM_THREADS=${NTHREADS} mpirun -np ${NP} ./${EXE} ${FLAGS} mesh:nx=${currGrid} mesh:ny=${currGrid} mesh:nz=${currGrid} performanceIterator:includeHeader=false +done + + +# #Make first run +# mpirun -np ${NP} ./${EXE} ${FLAGS} +# #Do other values +# for NP in 2 4 +# do +# mpirun -np ${NP} ./${EXE} ${FLAGS} performanceIterator:includeHeader=false +# done + diff --git a/examples/performance/ddx/makefile b/examples/performance/ddx/makefile new file mode 100644 index 0000000000..d6aae3a42b --- /dev/null +++ b/examples/performance/ddx/makefile @@ -0,0 +1,6 @@ + +BOUT_TOP = ../../.. + +SOURCEC = ddx.cxx + +include $(BOUT_TOP)/make.config diff --git a/examples/performance/ddx/new_scaling_parser.py b/examples/performance/ddx/new_scaling_parser.py new file mode 100644 index 0000000000..e65b30ffd4 --- /dev/null +++ b/examples/performance/ddx/new_scaling_parser.py @@ -0,0 +1,55 @@ +import csv + + +def read_file(filename): + reader = csv.reader(open(filename, 'r'), delimiter='\t', + skipinitialspace=True) + + # Skip header + for _, _ in zip(range(4), reader): + continue + + from collections import OrderedDict + case_lines = OrderedDict() #{} + for line in reader: + if line == []: + break + case_lines[line[0].rstrip('.')] = line[1] + + titles = next(reader) + cases_weak = {col.strip(): [] for col in titles[:-1]} + + for line in reader: + if line == []: + break + for title, col in zip(titles, line[:-1]): + cases_weak[title].append(float(col)) + + axis = cases_weak['Local grid'] + data = [cases_weak[x] for x in case_lines] + labels = [case_lines[x] for x in case_lines] + + return {'axis':axis, 'data':data, 'labels':labels} + +def getScan(baseName = "timing_{n}.txt", nthreads = [1,2,4,8,16,32]): + from numpy import zeros + + dataS = [] + for n in nthreads: + f = baseName.format(n=n) + dataS.append(read_file(f)) + + + nnt = len(dataS) + nlines = len(dataS[0]['data']) + nval = len(dataS[0]['data'][0]) + rawDat = zeros([nnt,nval,nlines]) + + for i, dat in enumerate(dataS): + print(len(dat['data'])) + + rawDat[i,:,:] = dat['data'] + + axes = [nthreads, dataS[0]['axis']] + + return axes, rawDat, dataS[0]['labels'] diff --git a/examples/performance/ddy/data/BOUT.inp b/examples/performance/ddy/data/BOUT.inp new file mode 100644 index 0000000000..11e3cbf4b7 --- /dev/null +++ b/examples/performance/ddy/data/BOUT.inp @@ -0,0 +1,13 @@ + +MZ = 100 +MXG=1 +MYG=1 + +[mesh] +nx = 100 +ny = 100 + +[performanceIterator] +NUM_LOOPS = 50 +profileMode = false +includeHeader = true \ No newline at end of file diff --git a/examples/performance/ddy/ddy.cxx b/examples/performance/ddy/ddy.cxx new file mode 100644 index 0000000000..7ca7c08e53 --- /dev/null +++ b/examples/performance/ddy/ddy.cxx @@ -0,0 +1,152 @@ +/* + * Testing performance of iterators over the mesh + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "bout/openmpwrap.hxx" +#include "bout/region.hxx" +#include "derivs.hxx" + +using SteadyClock = std::chrono::time_point; +using Duration = std::chrono::duration; +using namespace std::chrono; + +#define ITERATOR_TEST_BLOCK(NAME, ...) \ + { \ + __VA_ARGS__ \ + names.push_back(NAME); \ + SteadyClock start = steady_clock::now(); \ + for (int repetitionIndex = 0; repetitionIndex < NUM_LOOPS; repetitionIndex++) { \ + __VA_ARGS__; \ + } \ + times.push_back(steady_clock::now() - start); \ + } + +BoutReal test_ddy(stencil &s) { + return (s.p - s.m); +} + +typedef BoutReal (*deriv_func)(stencil &); +deriv_func func_ptr = &test_ddy; + +int main(int argc, char **argv) { + BoutInitialise(argc, argv); + std::vector names; + std::vector times; + + //Get options root + Options *globalOptions = Options::getRoot(); + Options *modelOpts = globalOptions->getSection("performanceIterator"); + int NUM_LOOPS; + OPTION(modelOpts, NUM_LOOPS, 100); + bool profileMode, includeHeader; + OPTION(modelOpts, profileMode, false); + OPTION(modelOpts, includeHeader, false); + + ConditionalOutput time_output{Output::getInstance()}; + time_output.enable(true); + + const Field3D a{1.0}; + const Field3D b{2.0}; + + Field3D result; + result.allocate(); + + const int len = mesh->LocalNx*mesh->LocalNy*mesh->LocalNz; + + // Nested loops over block data + ITERATOR_TEST_BLOCK( + "DDY Default", + result = DDY(a); + ); + + ITERATOR_TEST_BLOCK( + "DDY C2", + result = DDY(a, CELL_DEFAULT, DIFF_C2); + ); + + ITERATOR_TEST_BLOCK( + "DDY C4", + result = DDY(a, CELL_DEFAULT, DIFF_C4); + ); + + ITERATOR_TEST_BLOCK( + "DDY S2", + result = DDY(a, CELL_DEFAULT, DIFF_S2); + ); + + ITERATOR_TEST_BLOCK( + "DDY W2", + result = DDY(a, CELL_DEFAULT, DIFF_W2); + ); + + ITERATOR_TEST_BLOCK( + "DDY W3", + result = DDY(a, CELL_DEFAULT, DIFF_W3); + ); + + if (profileMode) { + int nthreads = 0; +#ifdef _OPENMP + nthreads = omp_get_max_threads(); +#endif + + int width = 12; + if (includeHeader) { + time_output << "\n------------------------------------------------\n"; + time_output << "Case legend"; + time_output << "\n------------------------------------------------\n"; + + for (std::size_t i = 0; i < names.size(); i++) { + time_output << std::setw(width) << "Case " << i << ".\t" << names[i] << "\n"; + } + time_output << "\n"; + time_output << std::setw(width) << "Nprocs" << "\t"; + time_output << std::setw(width) << "Nthreads" << "\t"; + time_output << std::setw(width) << "Num_loops" << "\t"; + time_output << std::setw(width) << "Local grid" << "\t"; + time_output << std::setw(width) << "Nx (global)" << "\t"; + time_output << std::setw(width) << "Ny (global)" << "\t"; + time_output << std::setw(width) << "Nz (global)" << "\t"; + for (std::size_t i = 0; i < names.size(); i++) { + time_output << std::setw(width) << "Case " << i << "\t"; + } + time_output << "\n"; + } + + time_output << std::setw(width) << BoutComm::size() << "\t"; + time_output << std::setw(width) << nthreads << "\t"; + time_output << std::setw(width) << NUM_LOOPS << "\t"; + time_output << std::setw(width) << len << "\t"; + time_output << std::setw(width) << mesh->GlobalNx << "\t"; + time_output << std::setw(width) << mesh->GlobalNy << "\t"; + time_output << std::setw(width) << mesh->GlobalNz << "\t"; + for (const auto &time : times) { + time_output << std::setw(width) << time.count() / NUM_LOOPS << "\t"; + } + time_output << "\n"; + } else { + std::vector sizes(names.size()); + std::transform(names.begin(), names.end(), sizes.begin(), + [](const std::string &name) -> int { return static_cast(name.size()); }); + int width = *std::max_element(sizes.begin(), sizes.end()); + width += 5; + time_output << std::setw(width) << "Case name" << "\t" << "Time per iteration (s)" << "\n"; + for (std::size_t i = 0; i < names.size(); i++) { + time_output << std::setw(width) << names[i] << "\t" << times[i].count() / NUM_LOOPS + << "\n"; + } + }; + + BoutFinalise(); + return 0; +} diff --git a/examples/performance/ddy/make_scaling_example.sh b/examples/performance/ddy/make_scaling_example.sh new file mode 100755 index 0000000000..3880ae6069 --- /dev/null +++ b/examples/performance/ddy/make_scaling_example.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +#A simple example of using the iterator test to explore scaling of the different approaches + +GRID_SIZES=(4 8 16 32 64 128) +EXE=ddy +NP=1 +NTHREADS=1 +FLAGS="-q -q -q -q performanceIterator:profileMode=true" + +#Make first run +currGrid=${GRID_SIZES[0]} +OMP_NUM_THREADS=${NTHREADS} mpirun -np ${NP} ./${EXE} ${FLAGS} mesh:nx=${currGrid} mesh:ny=${currGrid} mesh:nz=${currGrid} +#Do other values +for currGrid in ${GRID_SIZES[@]:1} +do + OMP_NUM_THREADS=${NTHREADS} mpirun -np ${NP} ./${EXE} ${FLAGS} mesh:nx=${currGrid} mesh:ny=${currGrid} mesh:nz=${currGrid} performanceIterator:includeHeader=false +done + + +# #Make first run +# mpirun -np ${NP} ./${EXE} ${FLAGS} +# #Do other values +# for NP in 2 4 +# do +# mpirun -np ${NP} ./${EXE} ${FLAGS} performanceIterator:includeHeader=false +# done + diff --git a/examples/performance/ddy/makefile b/examples/performance/ddy/makefile new file mode 100644 index 0000000000..99df08f35d --- /dev/null +++ b/examples/performance/ddy/makefile @@ -0,0 +1,6 @@ + +BOUT_TOP = ../../.. + +SOURCEC = ddy.cxx + +include $(BOUT_TOP)/make.config diff --git a/examples/performance/ddy/new_scaling_parser.py b/examples/performance/ddy/new_scaling_parser.py new file mode 100644 index 0000000000..e65b30ffd4 --- /dev/null +++ b/examples/performance/ddy/new_scaling_parser.py @@ -0,0 +1,55 @@ +import csv + + +def read_file(filename): + reader = csv.reader(open(filename, 'r'), delimiter='\t', + skipinitialspace=True) + + # Skip header + for _, _ in zip(range(4), reader): + continue + + from collections import OrderedDict + case_lines = OrderedDict() #{} + for line in reader: + if line == []: + break + case_lines[line[0].rstrip('.')] = line[1] + + titles = next(reader) + cases_weak = {col.strip(): [] for col in titles[:-1]} + + for line in reader: + if line == []: + break + for title, col in zip(titles, line[:-1]): + cases_weak[title].append(float(col)) + + axis = cases_weak['Local grid'] + data = [cases_weak[x] for x in case_lines] + labels = [case_lines[x] for x in case_lines] + + return {'axis':axis, 'data':data, 'labels':labels} + +def getScan(baseName = "timing_{n}.txt", nthreads = [1,2,4,8,16,32]): + from numpy import zeros + + dataS = [] + for n in nthreads: + f = baseName.format(n=n) + dataS.append(read_file(f)) + + + nnt = len(dataS) + nlines = len(dataS[0]['data']) + nval = len(dataS[0]['data'][0]) + rawDat = zeros([nnt,nval,nlines]) + + for i, dat in enumerate(dataS): + print(len(dat['data'])) + + rawDat[i,:,:] = dat['data'] + + axes = [nthreads, dataS[0]['axis']] + + return axes, rawDat, dataS[0]['labels'] diff --git a/examples/performance/ddz/data/BOUT.inp b/examples/performance/ddz/data/BOUT.inp new file mode 100644 index 0000000000..11e3cbf4b7 --- /dev/null +++ b/examples/performance/ddz/data/BOUT.inp @@ -0,0 +1,13 @@ + +MZ = 100 +MXG=1 +MYG=1 + +[mesh] +nx = 100 +ny = 100 + +[performanceIterator] +NUM_LOOPS = 50 +profileMode = false +includeHeader = true \ No newline at end of file diff --git a/examples/performance/ddz/ddz.cxx b/examples/performance/ddz/ddz.cxx new file mode 100644 index 0000000000..be532a4849 --- /dev/null +++ b/examples/performance/ddz/ddz.cxx @@ -0,0 +1,157 @@ +/* + * Testing performance of iterators over the mesh + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "bout/openmpwrap.hxx" +#include "bout/region.hxx" +#include "derivs.hxx" + +using SteadyClock = std::chrono::time_point; +using Duration = std::chrono::duration; +using namespace std::chrono; + +#define ITERATOR_TEST_BLOCK(NAME, ...) \ + { \ + __VA_ARGS__ \ + names.push_back(NAME); \ + SteadyClock start = steady_clock::now(); \ + for (int repetitionIndex = 0; repetitionIndex < NUM_LOOPS; repetitionIndex++) { \ + __VA_ARGS__; \ + } \ + times.push_back(steady_clock::now() - start); \ + } + +BoutReal test_ddy(stencil &s) { + return (s.p - s.m); +} + +typedef BoutReal (*deriv_func)(stencil &); +deriv_func func_ptr = &test_ddy; + +int main(int argc, char **argv) { + BoutInitialise(argc, argv); + std::vector names; + std::vector times; + + //Get options root + Options *globalOptions = Options::getRoot(); + Options *modelOpts = globalOptions->getSection("performanceIterator"); + int NUM_LOOPS; + OPTION(modelOpts, NUM_LOOPS, 100); + bool profileMode, includeHeader; + OPTION(modelOpts, profileMode, false); + OPTION(modelOpts, includeHeader, false); + + ConditionalOutput time_output{Output::getInstance()}; + time_output.enable(true); + + const Field3D a{1.0}; + const Field3D b{2.0}; + + Field3D result; + result.allocate(); + + const int len = mesh->LocalNx*mesh->LocalNy*mesh->LocalNz; + + // Nested loops over block data + ITERATOR_TEST_BLOCK( + "DDZ Default", + result = DDZ(a); + ); + + ITERATOR_TEST_BLOCK( + "DDZ C2", + result = DDZ(a, CELL_DEFAULT, DIFF_C2); + ); + + ITERATOR_TEST_BLOCK( + "DDZ C4", + result = DDZ(a, CELL_DEFAULT, DIFF_C4); + ); + + ITERATOR_TEST_BLOCK( + "DDZ S2", + result = DDZ(a, CELL_DEFAULT, DIFF_S2); + ); + + ITERATOR_TEST_BLOCK( + "DDZ W2", + result = DDZ(a, CELL_DEFAULT, DIFF_W2); + ); + + ITERATOR_TEST_BLOCK( + "DDZ W3", + result = DDZ(a, CELL_DEFAULT, DIFF_W3); + ); + + ITERATOR_TEST_BLOCK( + "DDZ FFT", + result = DDZ(a, CELL_DEFAULT, DIFF_FFT); + ); + + if (profileMode) { + int nthreads = 0; +#ifdef _OPENMP + nthreads = omp_get_max_threads(); +#endif + + int width = 12; + if (includeHeader) { + time_output << "\n------------------------------------------------\n"; + time_output << "Case legend"; + time_output << "\n------------------------------------------------\n"; + + for (std::size_t i = 0; i < names.size(); i++) { + time_output << std::setw(width) << "Case " << i << ".\t" << names[i] << "\n"; + } + time_output << "\n"; + time_output << std::setw(width) << "Nprocs" << "\t"; + time_output << std::setw(width) << "Nthreads" << "\t"; + time_output << std::setw(width) << "Num_loops" << "\t"; + time_output << std::setw(width) << "Local grid" << "\t"; + time_output << std::setw(width) << "Nx (global)" << "\t"; + time_output << std::setw(width) << "Ny (global)" << "\t"; + time_output << std::setw(width) << "Nz (global)" << "\t"; + for (std::size_t i = 0; i < names.size(); i++) { + time_output << std::setw(width) << "Case " << i << "\t"; + } + time_output << "\n"; + } + + time_output << std::setw(width) << BoutComm::size() << "\t"; + time_output << std::setw(width) << nthreads << "\t"; + time_output << std::setw(width) << NUM_LOOPS << "\t"; + time_output << std::setw(width) << len << "\t"; + time_output << std::setw(width) << mesh->GlobalNx << "\t"; + time_output << std::setw(width) << mesh->GlobalNy << "\t"; + time_output << std::setw(width) << mesh->GlobalNz << "\t"; + for (const auto &time : times) { + time_output << std::setw(width) << time.count() / NUM_LOOPS << "\t"; + } + time_output << "\n"; + } else { + std::vector sizes(names.size()); + std::transform(names.begin(), names.end(), sizes.begin(), + [](const std::string &name) -> int { return static_cast(name.size()); }); + int width = *std::max_element(sizes.begin(), sizes.end()); + width += 5; + time_output << std::setw(width) << "Case name" << "\t" << "Time per iteration (s)" << "\n"; + for (std::size_t i = 0; i < names.size(); i++) { + time_output << std::setw(width) << names[i] << "\t" << times[i].count() / NUM_LOOPS + << "\n"; + } + }; + + BoutFinalise(); + return 0; +} diff --git a/examples/performance/ddz/make_scaling_example.sh b/examples/performance/ddz/make_scaling_example.sh new file mode 100755 index 0000000000..06dc998153 --- /dev/null +++ b/examples/performance/ddz/make_scaling_example.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +#A simple example of using the iterator test to explore scaling of the different approaches + +GRID_SIZES=(4 8 16 32 64 128) +EXE=ddz +NP=1 +NTHREADS=1 +FLAGS="-q -q -q -q performanceIterator:profileMode=true" + +#Make first run +currGrid=${GRID_SIZES[0]} +OMP_NUM_THREADS=${NTHREADS} mpirun -np ${NP} ./${EXE} ${FLAGS} mesh:nx=${currGrid} mesh:ny=${currGrid} mesh:nz=${currGrid} +#Do other values +for currGrid in ${GRID_SIZES[@]:1} +do + OMP_NUM_THREADS=${NTHREADS} mpirun -np ${NP} ./${EXE} ${FLAGS} mesh:nx=${currGrid} mesh:ny=${currGrid} mesh:nz=${currGrid} performanceIterator:includeHeader=false +done + + +# #Make first run +# mpirun -np ${NP} ./${EXE} ${FLAGS} +# #Do other values +# for NP in 2 4 +# do +# mpirun -np ${NP} ./${EXE} ${FLAGS} performanceIterator:includeHeader=false +# done + diff --git a/examples/performance/ddz/makefile b/examples/performance/ddz/makefile new file mode 100644 index 0000000000..c389553de1 --- /dev/null +++ b/examples/performance/ddz/makefile @@ -0,0 +1,6 @@ + +BOUT_TOP = ../../.. + +SOURCEC = ddz.cxx + +include $(BOUT_TOP)/make.config diff --git a/examples/performance/ddz/new_scaling_parser.py b/examples/performance/ddz/new_scaling_parser.py new file mode 100644 index 0000000000..e65b30ffd4 --- /dev/null +++ b/examples/performance/ddz/new_scaling_parser.py @@ -0,0 +1,55 @@ +import csv + + +def read_file(filename): + reader = csv.reader(open(filename, 'r'), delimiter='\t', + skipinitialspace=True) + + # Skip header + for _, _ in zip(range(4), reader): + continue + + from collections import OrderedDict + case_lines = OrderedDict() #{} + for line in reader: + if line == []: + break + case_lines[line[0].rstrip('.')] = line[1] + + titles = next(reader) + cases_weak = {col.strip(): [] for col in titles[:-1]} + + for line in reader: + if line == []: + break + for title, col in zip(titles, line[:-1]): + cases_weak[title].append(float(col)) + + axis = cases_weak['Local grid'] + data = [cases_weak[x] for x in case_lines] + labels = [case_lines[x] for x in case_lines] + + return {'axis':axis, 'data':data, 'labels':labels} + +def getScan(baseName = "timing_{n}.txt", nthreads = [1,2,4,8,16,32]): + from numpy import zeros + + dataS = [] + for n in nthreads: + f = baseName.format(n=n) + dataS.append(read_file(f)) + + + nnt = len(dataS) + nlines = len(dataS[0]['data']) + nval = len(dataS[0]['data'][0]) + rawDat = zeros([nnt,nval,nlines]) + + for i, dat in enumerate(dataS): + print(len(dat['data'])) + + rawDat[i,:,:] = dat['data'] + + axes = [nthreads, dataS[0]['axis']] + + return axes, rawDat, dataS[0]['labels'] From 83eae092ba29e7496ad9c74b5be9a87374b00b41 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 6 Nov 2018 14:57:08 +0000 Subject: [PATCH 0229/1783] Rename new derivs header to avoid confusion with existing derivs header --- include/bout/{derivs.hxx => index_derivs.hxx} | 6 +++--- src/mesh/index_derivs.cxx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) rename include/bout/{derivs.hxx => index_derivs.hxx} (99%) diff --git a/include/bout/derivs.hxx b/include/bout/index_derivs.hxx similarity index 99% rename from include/bout/derivs.hxx rename to include/bout/index_derivs.hxx index e96d0c58b6..056c23c8cf 100644 --- a/include/bout/derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -1,5 +1,5 @@ /*!************************************************************************ - * \file derivs.hxx + * \file index_derivs.hxx * * Definition of available derivative methods and registration within store * @@ -26,8 +26,8 @@ * **************************************************************************/ -#ifndef __DERIVS_HXX__ -#define __DERIVS_HXX__ +#ifndef __INDEX_DERIVS_HXX__ +#define __INDEX_DERIVS_HXX__ #include #include diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 0f5446b566..a8eb38d081 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -44,7 +44,7 @@ * **************************************************************************/ -#include +#include #include #include #include From 14acd96980da9230ac7006c7b783974302557cb5 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 6 Nov 2018 21:19:24 +0000 Subject: [PATCH 0230/1783] Remove unused code --- src/mesh/index_derivs.cxx | 67 --------------------------------------- 1 file changed, 67 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index a8eb38d081..e0d797bdc0 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -1,28 +1,4 @@ /************************************************************************** - * Basic derivative methods in mesh index space - * - * - * Four kinds of differencing methods: - * - * 1. First derivative DD* - * Central differencing e.g. Div(f) - * - * 2. Second derivatives D2D*2 - * Central differencing e.g. Delp2(f) - * - * 3. Upwinding VDD* - * Terms like v*Grad(f) - * - * 4. Flux methods FDD* (e.g. flux conserving, limiting) - * Div(v*f) - * - * Changelog - * ========= - * - * 2014-11-22 Ben Dudson - * o Moved here from sys/derivs, made part of Mesh - * - ************************************************************************** * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk @@ -47,51 +23,8 @@ #include #include #include -#include #include -/******************************************************************************* - * Limiters - *******************************************************************************/ - -/// Van Leer limiter. Used in TVD code -BoutReal VANLEER(BoutReal r) { return r + fabs(r) / (1.0 + fabs(r)); } - -// Superbee limiter -BoutReal SUPERBEE(BoutReal r) { - return BOUTMAX(0.0, BOUTMIN(2. * r, 1.0), BOUTMIN(r, 2.)); -} - -//////////////////////// MUSCL scheme /////////////////////// - -void DDX_KT_LR(const stencil &f, BoutReal &fLp, BoutReal &fRp, BoutReal &fLm, - BoutReal &fRm) { - // Limiter functions - BoutReal phi = SUPERBEE((f.c - f.m) / (f.p - f.c)); - BoutReal phi_m = SUPERBEE((f.m - f.mm) / (f.c - f.m)); - BoutReal phi_p = SUPERBEE((f.p - f.c) / (f.pp - f.p)); - - fLp = f.c + 0.5 * phi * (f.p - f.c); - fRp = f.p - 0.5 * phi_p * (f.pp - f.p); - - fLm = f.m + 0.5 * phi_m * (f.c - f.m); - fRm = f.c - 0.5 * phi * (f.p - f.c); -} - -// du/dt = d/dx(f) with maximum local velocity Vmax -BoutReal DDX_KT(const stencil &f, const stencil &u, const BoutReal Vmax) { - BoutReal uLp, uRp, uLm, uRm; - BoutReal fLp, fRp, fLm, fRm; - - DDX_KT_LR(u, uLp, uRp, uLm, uRm); - DDX_KT_LR(f, fLp, fRp, fLm, fRm); - - BoutReal Fm = 0.5 * (fRm + fLm - Vmax * (uRm - uLm)); - BoutReal Fp = 0.5 * (fRp + fLp - Vmax * (uRp - uLp)); - - return Fm - Fp; -} - /******************************************************************************* * Helper routines *******************************************************************************/ From e9b2d9ce625c683df917bd8cdcc88320ecdb6402 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 7 Nov 2018 11:01:33 +0000 Subject: [PATCH 0231/1783] Comment out clang-format directives that need clang-format >= 6 --- .clang-format | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/.clang-format b/.clang-format index af60f0e15b..1cff2689ad 100644 --- a/.clang-format +++ b/.clang-format @@ -1,11 +1,13 @@ --- +# Note: commented out lines require clang-format >= 6 Language: Cpp -# BasedOnStyle: LLVM +BasedOnStyle: LLVM AccessModifierOffset: -2 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false -AlignEscapedNewlines: Right +# AlignEscapedNewlines: Right +AlignEscapedNewlinesLeft: true AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true @@ -29,24 +31,24 @@ BraceWrapping: AfterObjCDeclaration: false AfterStruct: false AfterUnion: false - AfterExternBlock: false +# AfterExternBlock: false BeforeCatch: false BeforeElse: false IndentBraces: false - SplitEmptyFunction: true - SplitEmptyRecord: true - SplitEmptyNamespace: true +# SplitEmptyFunction: true +# SplitEmptyRecord: true +# SplitEmptyNamespace: true BreakBeforeBinaryOperators: NonAssignment BreakBeforeBraces: Attach -BreakBeforeInheritanceComma: false +# BreakBeforeInheritanceComma: false BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: BeforeColon +# BreakConstructorInitializers: BeforeColon BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true ColumnLimit: 90 CommentPragmas: '^ IWYU pragma:' -CompactNamespaces: false +# CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 @@ -54,12 +56,12 @@ Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false -FixNamespaceComments: true +# FixNamespaceComments: true ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH -IncludeBlocks: Regroup +# IncludeBlocks: Regroup IncludeCategories: - Regex: '^(<|")bout/' Priority: 2 @@ -71,7 +73,7 @@ IncludeCategories: Priority: 1 IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false -IndentPPDirectives: None +# IndentPPDirectives: None IndentWidth: 2 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: true @@ -81,7 +83,7 @@ MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true -PenaltyBreakAssignment: 2 +# PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 @@ -91,7 +93,7 @@ PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Left ReflowComments: true SortIncludes: true -SortUsingDeclarations: true +# SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true From 377254642766b65f114dbcb49a7039ef6d9cc1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Wed, 7 Nov 2018 12:33:38 +0000 Subject: [PATCH 0232/1783] Disable broken tests Running tests which are knowingly broken is a waste of CPU time. Futher, it obfuscates new failures. --- tests/MMS/GBS/{runtest => runtest.broken} | 0 tests/MMS/advection/weno3/{runtest => runtest.broken} | 0 tests/MMS/elm-pb/{runtest => runtest.broken} | 0 tests/MMS/fieldalign/{runtest => runtest.broken} | 0 tests/MMS/spatial/advection/{runtest => runtest.broken} | 0 tests/MMS/time-petsc/{runtest => runtest.broken} | 0 tests/MMS/tokamak/{runtest => runtest.broken} | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename tests/MMS/GBS/{runtest => runtest.broken} (100%) rename tests/MMS/advection/weno3/{runtest => runtest.broken} (100%) rename tests/MMS/elm-pb/{runtest => runtest.broken} (100%) rename tests/MMS/fieldalign/{runtest => runtest.broken} (100%) rename tests/MMS/spatial/advection/{runtest => runtest.broken} (100%) rename tests/MMS/time-petsc/{runtest => runtest.broken} (100%) rename tests/MMS/tokamak/{runtest => runtest.broken} (100%) diff --git a/tests/MMS/GBS/runtest b/tests/MMS/GBS/runtest.broken similarity index 100% rename from tests/MMS/GBS/runtest rename to tests/MMS/GBS/runtest.broken diff --git a/tests/MMS/advection/weno3/runtest b/tests/MMS/advection/weno3/runtest.broken similarity index 100% rename from tests/MMS/advection/weno3/runtest rename to tests/MMS/advection/weno3/runtest.broken diff --git a/tests/MMS/elm-pb/runtest b/tests/MMS/elm-pb/runtest.broken similarity index 100% rename from tests/MMS/elm-pb/runtest rename to tests/MMS/elm-pb/runtest.broken diff --git a/tests/MMS/fieldalign/runtest b/tests/MMS/fieldalign/runtest.broken similarity index 100% rename from tests/MMS/fieldalign/runtest rename to tests/MMS/fieldalign/runtest.broken diff --git a/tests/MMS/spatial/advection/runtest b/tests/MMS/spatial/advection/runtest.broken similarity index 100% rename from tests/MMS/spatial/advection/runtest rename to tests/MMS/spatial/advection/runtest.broken diff --git a/tests/MMS/time-petsc/runtest b/tests/MMS/time-petsc/runtest.broken similarity index 100% rename from tests/MMS/time-petsc/runtest rename to tests/MMS/time-petsc/runtest.broken diff --git a/tests/MMS/tokamak/runtest b/tests/MMS/tokamak/runtest.broken similarity index 100% rename from tests/MMS/tokamak/runtest rename to tests/MMS/tokamak/runtest.broken From 5976a90cdbc69db53a4894f8195ee7b67cd6ac2b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 7 Nov 2018 15:47:23 +0000 Subject: [PATCH 0233/1783] Remove test-dataiterator --- tests/integrated/test-dataiterator/.gitignore | 3 - .../test-dataiterator/data/BOUT.inp | 23 -- tests/integrated/test-dataiterator/makefile | 6 - tests/integrated/test-dataiterator/runtest | 49 ---- .../test-dataiterator/test_dataiterator.cxx | 219 ------------------ 5 files changed, 300 deletions(-) delete mode 100644 tests/integrated/test-dataiterator/.gitignore delete mode 100644 tests/integrated/test-dataiterator/data/BOUT.inp delete mode 100644 tests/integrated/test-dataiterator/makefile delete mode 100755 tests/integrated/test-dataiterator/runtest delete mode 100644 tests/integrated/test-dataiterator/test_dataiterator.cxx diff --git a/tests/integrated/test-dataiterator/.gitignore b/tests/integrated/test-dataiterator/.gitignore deleted file mode 100644 index 0426b69349..0000000000 --- a/tests/integrated/test-dataiterator/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# name of binaries -test_dataiterator -speed \ No newline at end of file diff --git a/tests/integrated/test-dataiterator/data/BOUT.inp b/tests/integrated/test-dataiterator/data/BOUT.inp deleted file mode 100644 index 0bf484c358..0000000000 --- a/tests/integrated/test-dataiterator/data/BOUT.inp +++ /dev/null @@ -1,23 +0,0 @@ -# Test of the FieldFactory class -# -# Generates a set of fields and writes them to output file -# - -NOUT = 0 # No timesteps - -MZ = 5 # Z size - - - -dump_format = "nc" # NetCDF format. Alternative is "pdb" - -[mesh] -symmetricGlobalX = false -nx=16 -ny=3 - - -[laplace] -all_terms = false -filter = 0.2 - diff --git a/tests/integrated/test-dataiterator/makefile b/tests/integrated/test-dataiterator/makefile deleted file mode 100644 index 95bcb189e4..0000000000 --- a/tests/integrated/test-dataiterator/makefile +++ /dev/null @@ -1,6 +0,0 @@ - -BOUT_TOP = ../../.. - -SOURCEC = test_dataiterator.cxx - -include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-dataiterator/runtest b/tests/integrated/test-dataiterator/runtest deleted file mode 100755 index 734f6abd9a..0000000000 --- a/tests/integrated/test-dataiterator/runtest +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python3 - -# -# Run the test, check it completed successfully -# - -#requires: all_tests - -from __future__ import print_function -try: - from builtins import str -except: - pass -from boututils.run_wrapper import shell, shell_safe, launch, getmpirun -from boutdata.collect import collect -from sys import stdout, exit - -MPIRUN=getmpirun() - -print("Making DataIterator test") -shell_safe("make > make.log",pipe=True) -errors=[] - -for nproc in [1,2,4]: - for mproc in [1,2,3,4]: - cmd = "./test_dataiterator" - - print(" %d x %d threads...." % (nproc,mproc)) - - shell("rm data/BOUT.dmp.* 2> err.log") - - # Run the case - s, out = launch(cmd, runcmd=MPIRUN, nproc=nproc, mthread=mproc, pipe=True) - with open("run.log."+str(nproc)+"."+str(mproc), "w") as f: - f.write(out) - if s: - errors.append([n,m,s,out]) - -if errors: - print(" => Some data iteration tests failed") - for n,m,s,out in errors: - print("Run with n=%d mpi threads and m=%d openmp threads failed.",n,m) - print() - for n,m,s,out in errors: - print(" * Run n=%d m=%d - exit %d\nError was:\n\n%s\n\n",n,m,s,out) - print() - exit(1) -else: - print(" => All data iteration tests passed") diff --git a/tests/integrated/test-dataiterator/test_dataiterator.cxx b/tests/integrated/test-dataiterator/test_dataiterator.cxx deleted file mode 100644 index b066d834e7..0000000000 --- a/tests/integrated/test-dataiterator/test_dataiterator.cxx +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Test Cyclic Reduction parallel solver - * - */ - -#include -#include - -//#include -#include - -#include - -Field3D n; - -#ifdef _OPENMP -#define PRINT_DEBUG {\ - usleep(2e5*omp_get_thread_num()); \ - output.write("FieldIterator failed at ???"); \ - output.write("- expected %.1f but got %.1f. ",exp,d3[i]); \ - output.write("I am %d !\n",omp_get_thread_num()); \ - usleep(2e5*omp_get_num_threads()); \ - abort(); } -#else -#define PRINT_DEBUG { \ - output.write("FieldIterator failed at "); \ - output.write("- expected %.1f but got %.1f. ",exp,d3[i]); \ - abort(); } -#endif - -int spread_work(int num_work, int thread, int max_thread); - -int physics_init(bool restarting) { - - // for (int w=2;w<8;w++){ - // int we=pow(2,w)+1.1; - // output.write("spreading %d\n",we); - // for (int t=1;t<5;++t){ - // for (int ct=0;ct<=t;++ct){ - // output.write("%d ",spread_work(we,ct,t)); - // } - // output.write("\n"); - // } - // } - - - /********************************************** - * * * * * * - * * * Field3D test * * * - * * * * * * - **********************************************/ - - Field3D d3=1; - - BoutReal exp=1; - // for (FieldIteratorCIndex cxit( *mesh);cxit;cxit.next3()){ - // if (d3[cxit] != exp) PRINT_DEBUG; - // d3[cxit]=2; - // } - // exp=2; - -#pragma omp parallel - for (auto i: d3){ - if (d3[i] != exp) PRINT_DEBUG; - //if (i.x != 8) - d3[i]=3; - } - exp=3; - - for (int jx=0;jxLocalNx;++jx) - for (int jy=0;jyLocalNy;++jy) - for (int jz=0;jzLocalNz;++jz){ - if (d3(jx,jy,jz) != exp) { - output.print("%d %d %d: expected %g got %g",jx,jy,jz,exp,d3(jx,jy,jz)) ; - }; - assert(d3(jx,jy,jz)==exp); - } - - /* -#pragma omp parallel - for (auto i: d3){ - if (d3[i] != exp) PRINT_DEBUG; - d3[i]=4; - } - - for (int jx=0;jxLocalNx;++jx){ - if (jx < mesh->xstart || jx > mesh->xend) - exp=3; - else - exp=4; - for (int jy=0;jyLocalNy;++jy) - for (int jz=0;jzLocalNz;++jz) - assert(d3(jx,jy,jz)==exp); - } - d3=3; - #pragma omp parallel - for (auto i : d3){ - if (d3[i] != exp) PRINT_DEBUG; - d3[i]=4; - } - for (int jx=0;jxLocalNx;++jx) - for (int jy=0;jyLocalNy;++jy){ - if (jy < mesh->ystart || jy > mesh->yend) - exp=3; - else - exp=4; - for (int jz=0;jzLocalNz;++jz) - assert(d3(jx,jy,jz)==exp); - } - d3=3;exp=3; - #pragma omp parallel - for (auto i: d3){ - if (d3[i] != exp) PRINT_DEBUG; - d3[i]=4; - } - for (int jx=0;jxLocalNx;++jx) - for (int jy=0;jyLocalNy;++jy) - for (int jz=0;jzLocalNz;++jz){ - if (jz == mesh->LocalNz) - exp=3; - else - exp=4; - assert(d3(jx,jy,jz)==exp); - } - d3=3;exp=3; - #pragma omp parallel - for (auto i:d3){ - if (d3[i] != exp) PRINT_DEBUG; - d3[i]=4; - } - for (int jx=0;jxLocalNx;++jx) - for (int jy=0;jyLocalNy;++jy) - for (int jz=0;jzLocalNz;++jz){ - if (jz == mesh->LocalNz || - jy < mesh->ystart || jy > mesh->yend || - jx < mesh->xstart || jx > mesh->xend) - exp=3; - else - exp=4; - assert(d3(jx,jy,jz)==exp); - } -*/ - - /********************************************** - * * * * * * - * * * Field2D test * * * - * * * * * * - **********************************************/ - - Field2D d2=1; - exp=1; - #pragma omp parallel - for (auto i: d2){ - if (d2[i] != exp) PRINT_DEBUG; - d2[i]=3; - } - exp=3; - for (int jx=0;jxLocalNx;++jx) - for (int jy=0;jyLocalNy;++jy) - assert(d2(jx,jy)==exp); - /* - d2=1;exp=1; - for (auto i : d2){ - if (d2[i] != exp) PRINT_DEBUG; - d2[ i]=2; - } - for (int jx=0;jxLocalNx;++jx){ - if (jx < mesh->xstart || jx > mesh->xend) - exp=1; - else - exp=2; - for (int jy=0;jyLocalNy;++jy) - assert(d2(jx,jy)==exp); - } - d2=1;exp=1; - for (auto i:d2){ - if (d2[i] != exp) PRINT_DEBUG; - d2[i]=2; - } - for (int jx=0;jxLocalNx;++jx) - for (int jy=0;jyLocalNy;++jy){ - if (jy < mesh->ystart || jy > mesh->yend) - exp=1; - else - exp=2; - assert(d2(jx,jy)==exp); - } - d2=1;exp=1; - for (auto i:d2){ - if (d2[i] != exp) PRINT_DEBUG; - d2[i]=2; - } - for (int jx=0;jxLocalNx;++jx) - for (int jy=0;jyLocalNy;++jy){ - if (jx < mesh->xstart || jx > mesh->xend || - jy < mesh->ystart || jy > mesh->yend) - exp=1; - else - exp=2; - assert(d2(jx,jy)==exp); - } - - */ - - bool fail; - OPTION(Options::getRoot(), fail, false) ; - n=1; - SOLVE_FOR(n); - if (fail){ - return 1; - } - return 0; -} - -int physics_run(BoutReal t) { - // Doesn't do anything - ddt(n)=0; - return 0; -} From eedb65ac89b505e697e7098208db0485f6e932c1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 7 Nov 2018 15:47:54 +0000 Subject: [PATCH 0234/1783] Remove operators_di --- include/bout/operators_di.hxx | 124 ---------------------------------- 1 file changed, 124 deletions(-) delete mode 100644 include/bout/operators_di.hxx diff --git a/include/bout/operators_di.hxx b/include/bout/operators_di.hxx deleted file mode 100644 index 51923cbc03..0000000000 --- a/include/bout/operators_di.hxx +++ /dev/null @@ -1,124 +0,0 @@ - -#pragma once - -#ifndef __OPERATORS_DI_H__ -#define __OPERATORS_DI_H__ - -#include -#include -#include - -/// \brief 2nd order central differencing in X -/// -/// Performs calculation at a single point. The input field -/// must be defined at i.xp() and i.xm() -/// -/// @param f The field to be differentiated -/// @param i The point where the result is calculated -/// -inline BoutReal DDX_C2(const Field3D &f, const DataIterator &i) { - return (f[i.xp()] - f[i.xm()])/(2.*f.getCoordinates()->dx[i]); -} - -/// \brief 2nd order central differencing in Y using yup/down fields -/// -/// @param f The field to be differentiated -/// @param i The point where the result is calculated -/// -inline BoutReal DDY_C2(const Field3D &f, const DataIterator &i) { - return (f.yup()[i.yp()] - f.ydown()[i.ym()])/(2.*f.getCoordinates()->dy[i]); -} - -/// \brief 2nd order central differencing in Y assuming field aligned -/// -/// @param f The field to be differentiated (field aligned) -/// @param i The point where the result is calculated -/// -inline BoutReal DDY_C2_FA(const Field3D &f, const DataIterator &i) { - return (f[i.yp()] - f[i.ym()])/(2.*f.getCoordinates()->dy[i]); -} - -/// \brief 2nd order central differencing in Z -/// -/// @param f The field to be differentiated -/// @param i The point where the result is calculated -/// -inline BoutReal DDZ_C2(const Field3D &f, const DataIterator &i) { - return (f[i.zp()] - f[i.zm()])/(2.*f.getCoordinates()->dz); -} - - -/// -/// d/dx( g^xx df/dx + g^xz df/dz) + d/dz( g^zz df/dz + g^xz df/dx) -/// -BoutReal Delp2_C2(const Field3D &f, const DataIterator &i) { - Coordinates *metric = f.getCoordinates(); - - // o -- UZ -- o - // | | - // LX RX - // | | - // o -- DZ -- o - - // Upper Z boundary (UZ) - - -} - -/// \brief Arakawa bracket in X-Z [f,g] -/// -/// @param[in] f Field to be differentiated -/// @param[in] g Field to be differentiated -/// @param[in] i The point where the result is calculated -BoutReal bracket_arakawa(const Field3D &f, const Field3D &g, const DataIterator &i) { - Coordinates *metric = f.getCoordinates(); - - // Indexing - const auto xp = i.xp(); - const auto xm = i.xm(); - const auto zp = i.zp(); - const auto zm = i.zm(); - - const auto xpzp = i.offset(1,0,1); - const auto xpzm = i.offset(1,0,-1); - const auto xmzp = i.offset(-1,0,1); - const auto xmzm = i.offset(-1,0,-1); - - const BoutReal fxp = f[xp]; - const BoutReal fxm = f[xm]; - const BoutReal fzp = f[zp]; - const BoutReal fzm = f[zm]; - - const BoutReal fpp = f[xpzp]; - const BoutReal fpm = f[xpzm]; - const BoutReal fmp = f[xmzp]; - const BoutReal fmm = f[xmzm]; - - const BoutReal gxp = g[xp]; - const BoutReal gxm = g[xm]; - const BoutReal gzp = g[zp]; - const BoutReal gzm = g[zm]; - - // J++ = DDZ(f)*DDX(g) - DDX(f)*DDZ(g) - BoutReal Jpp = - (fzp - fzm) * (gxp - gxm) - - (fxp - fxm) * (gzp - gzm); - - // J+x - BoutReal Jpx = - gxp * (fpp - fpm) - - gxm * (fmp - fmm) - - gzp * (fpp - fmp) - + gzm * (fpm - fmm); - - // Jx+ - BoutReal Jxp = - g[xpzp] * (fzp - fxp) - - g[xmzm] * (fxm - fzm) - - g[xmzp] * (fzp - fxm) - + g[xpzm] * (fxp - fzm); - - return (Jpp + Jpx + Jxp) / (12. * metric->dx[i] * metric->dz); -} - -#endif // __OPERATORS_DI_H__ From dd7623c0f5a907769efc665a360444d9c87f81c5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 7 Nov 2018 16:07:51 +0000 Subject: [PATCH 0235/1783] Remove blob2d-outerloop --- examples/blob2d-outerloop/blob2d.cxx | 178 --------------------- examples/blob2d-outerloop/delta_1/BOUT.inp | 121 -------------- examples/blob2d-outerloop/makefile | 6 - 3 files changed, 305 deletions(-) delete mode 100644 examples/blob2d-outerloop/blob2d.cxx delete mode 100644 examples/blob2d-outerloop/delta_1/BOUT.inp delete mode 100644 examples/blob2d-outerloop/makefile diff --git a/examples/blob2d-outerloop/blob2d.cxx b/examples/blob2d-outerloop/blob2d.cxx deleted file mode 100644 index 3c99604a41..0000000000 --- a/examples/blob2d-outerloop/blob2d.cxx +++ /dev/null @@ -1,178 +0,0 @@ -/// -/// \file blob2d.cxx -/// -/// 2D simulations of a plasma blob in a slab -/// -/// This version uses DataIterator indexed operators -/// which reduce the number of loops over the domain -/// - -#include // Commonly used BOUT++ components -#include // To use DDZ() -#include // Laplacian inversion - -#include // For DataIterator indexed operators - -/// 2D drift-reduced model, mainly used for blob studies -/// -/// -class Blob2D : public PhysicsModel { -private: - // Evolving variables - Field3D n, omega; ///< Density and vorticity - - // Auxilliary variables - Field3D phi; ///< Electrostatic potential - - // Parameters - BoutReal rho_s; ///< Bohm gyro radius - BoutReal Omega_i; ///< Ion cyclotron frequency - BoutReal c_s; ///< Bohm sound speed - BoutReal n0; ///< Reference density - - // Constants to calculate the parameters - BoutReal Te0; ///< Isothermal temperature [eV] - BoutReal B0; ///< Constant magnetic field [T] - BoutReal m_i; ///< Ion mass [kg] - BoutReal m_e; ///< Electron mass [kg] - BoutReal e; ///< Electron charge [C] - - BoutReal D_n, D_vort; ///< Diffusion coefficients - BoutReal R_c; ///< Radius of curvature - BoutReal L_par; ///< Parallel connection length - - // Model options - bool boussinesq; ///< Use the Boussinesq approximation in vorticity - bool compressible; ///< If allow inclusion of n grad phi term in density evolution - bool sheath; ///< Sheath connected? - - Laplacian *phiSolver; ///< Performs Laplacian inversions to calculate phi - -protected: - int init(bool restarting) { - TRACE("blob2d::init"); - - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("model"); - - // Load system parameters - options->get("Te0", Te0, 30); // Temp in eV - options->get("e", e, 1.602e-19); - options->get("m_i", m_i, 2 * 1.667e-27); - options->get("m_e", m_e, 9.11e-31); - - options->get("n0", n0, 1e19); // Background density in cubic m - options->get("D_vort", D_vort, 0); // Viscous diffusion coefficient - options->get("D_n", D_n, 0); // Density diffusion coefficient - - options->get("R_c", R_c, 1.5); // Radius of curvature - options->get("L_par", L_par, 10); // Parallel connection length - OPTION(options, B0, 0.35); // Value of magnetic field strength - - // System option switches - - OPTION(options, compressible, - false); // Include compressible ExB term in density equation - OPTION(options, boussinesq, true); // Use Boussinesq approximation in vorticity - OPTION(options, sheath, true); // Sheath closure - - // Calculate parameters - - Omega_i = e * B0 / m_i; // Cyclotron Frequency - c_s = sqrt(e * Te0 / m_i); // Bohm sound speed - rho_s = c_s / Omega_i; // Bohm gyro-radius - - output.write("\n\n\t----------Parameters: ------------ \n\tOmega_i = %e /s,\n\tc_s = " - "%e m/s,\n\trho_s = %e m\n", - Omega_i, c_s, rho_s); - - // Calculate delta_*, blob size scaling - output.write("\tdelta_* = rho_s * (dn/n) * %e ", - pow(L_par * L_par / (R_c * rho_s), 1. / 5)); - - // Create a solver for potential - - if (boussinesq) { - // BOUT.inp section "phiBoussinesq" - phiSolver = Laplacian::create(Options::getRoot()->getSection("phiBoussinesq")); - } else { - // BOUT.inp section "phiSolver" - phiSolver = Laplacian::create(Options::getRoot()->getSection("phiSolver")); - } - phi = 0.0; // Starting guess for first solve (if iterative) - - // Tell BOUT++ what to solve - - SOLVE_FOR2(n, omega); - - // Output phi - SAVE_REPEAT(phi); - SAVE_ONCE3(rho_s, c_s, Omega_i); - - return 0; - } - - int rhs(BoutReal t) { - TRACE("blob2d::rhs"); - - // Run communications - //////////////////////////////////////////////////////////////////////////// - mesh->communicate(n, omega); - - // Invert div(n grad(phi)) = grad(n) grad(phi) + n Delp_perp^2(phi) = omega - //////////////////////////////////////////////////////////////////////////// - - if (!boussinesq) { - // Including full density in vorticit inversion - phiSolver->setCoefC(n); // Update the 'C' coefficient. See invert_laplace.hxx - phi = phiSolver->solve(omega / n, phi); // Use previous solution as guess - } else { - // Background density only (1 in normalised units) - phi = phiSolver->solve(omega); - } - - mesh->communicate(phi); - - // Allocate time derivative fields - ddt(n).allocate(); - ddt(omega).allocate(); - - // Loop over the domain, avoiding boundaries - for (auto &i : n.region(RGN_NOBNDRY)) { - - // Density Evolution - - ddt(n)[i] = -bracket_arakawa(phi, n, i) // ExB term - + 2 * DDZ_C2(n, i) * (rho_s / R_c) // Curvature term - ; // Diffusion term - if (compressible) { - ddt(n)[i] -= 2 * n[i] * DDZ_C2(phi, i) * (rho_s / R_c); // ExB Compression term - } - - if (sheath) { - ddt(n)[i] += n[i] * phi[i] * - (rho_s / L_par); // - (n - 1)*(rho_s/L_par); // Sheath closure - } - - // Vorticity evolution - - ddt(omega)[i] = -bracket_arakawa(phi, omega, i) // ExB term - + 2 * DDZ_C2(n, i) * (rho_s / R_c) / n[i] // Curvature term - - ; - - if (sheath) { - ddt(omega)[i] += phi[i] * (rho_s / L_par); - } - } - - // Operators not yet indexed - ddt(n) += D_n * Delp2(n); - - ddt(omega) += D_vort * Delp2(omega) / n; // Viscous diffusion term - return 0; - } -}; - -// Define a standard main() function -BOUTMAIN(Blob2D); diff --git a/examples/blob2d-outerloop/delta_1/BOUT.inp b/examples/blob2d-outerloop/delta_1/BOUT.inp deleted file mode 100644 index 4a6a8f22fb..0000000000 --- a/examples/blob2d-outerloop/delta_1/BOUT.inp +++ /dev/null @@ -1,121 +0,0 @@ -# settings file for BOUT++ -# -# Blob simulation in a 2D slab -# -# This case has blob size -# -# delta = 0.3*256 ~ 10 * delta_* - - -# settings used by the core code - -NOUT = 50 # number of time-steps -TIMESTEP = 50 # time between outputs [1/wci] - - -MXG = 2 # Number of X guard cells -MYG = 0 # No y derivatives, so no guard cells needed in y - -[mesh] - -nx = 260 # Note: 4 guard cells -ny = 1 -nz = 256 - -dx = 0.3 # Grid spacing [rho_s] -dz = 0.3 - -################################################## -# derivative methods - -[mesh:ddx] - -first = C2 -second = C2 -upwind = W3 - -[mesh:ddy] - -first = C2 -second = C2 -upwind = W3 - -[mesh:ddz] - -first = FFT -second = FFT -upwind = W3 - -################################################### -# Time-integration solver - -[solver] - -ATOL = 1.0e-10 # absolute tolerance -RTOL = 1.0e-5 # relative tolerance -mxstep = 10000 # Maximum internal steps per output - -################################################### -# Electrostatic potential solver -# These options are used if boussinesq = false - -[phiSolver] -type = petsc # Needed if Boussinesq = false -pctype = user # Preconditioning type - -fourth_order = true # 4th order or 2nd order - -flags = 0 # inversion flags for phi - # 0 = Zero value - # 10 = Zero gradient AC inner & outer - # 15 = Zero gradient AC and DC - # 768 = Zero laplace inner & outer - -[phiSolver:precon] # Preconditioner (if pctype=user) -filter = 0. # Must not filter solution -flags = 49152 # set_rhs i.e. identity matrix in boundaries - -################################################### -# Electrostatic potential solver (Boussinesq) - -[phiBoussinesq] -# By default type is tri (serial) or spt (parallel) -flags = 0 - -################################################## -# general settings for the model - -[model] - -Te0 = 5 # Electron Temperature (eV) - -n0 = 2e18 # Background plasma density (m^-3) - -compressible = false # Compressibility? - -boussinesq = true # Boussinesq approximation (no perturbed n in vorticity) - -D_vort = 1e-6 # Viscosity -D_n = 1e-6 # Diffusion - -R_c = 1.5 # Radius of curvature (m) - -# settings for individual variables -# The section "All" defines default settings for all variables -# These can be overridden for individual variables in -# a section of that name. - -[All] -scale = 0.0 # default size of initial perturbations - -bndry_all = neumann # Zero-gradient on all boundaries - -[n] # Density -scale = 1.0 # size of perturbation - -height = 0.5 -width = 0.05 - -function = 1 + height * exp(-((x-0.25)/width)^2 - ((z/(2*pi) - 0.5)/width)^2) - - diff --git a/examples/blob2d-outerloop/makefile b/examples/blob2d-outerloop/makefile deleted file mode 100644 index 1ab6de5387..0000000000 --- a/examples/blob2d-outerloop/makefile +++ /dev/null @@ -1,6 +0,0 @@ -BOUT_TOP = ../.. - -SOURCEC = blob2d.cxx - -include $(BOUT_TOP)/make.config - From bd053bf8a8e84056337d063f719d7026f6d1d67e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 7 Nov 2018 16:08:01 +0000 Subject: [PATCH 0236/1783] Remove more uses of DataIterator --- examples/performance/difops/test-difops.cxx | 74 ------------------- .../iterator-offsets/iterator-offsets.cxx | 46 ------------ examples/performance/iterator/iterator.cxx | 34 --------- tests/unit/field/test_field3d.cxx | 37 ---------- 4 files changed, 191 deletions(-) diff --git a/examples/performance/difops/test-difops.cxx b/examples/performance/difops/test-difops.cxx index 4d58f99121..dade6b11d3 100644 --- a/examples/performance/difops/test-difops.cxx +++ b/examples/performance/difops/test-difops.cxx @@ -22,28 +22,6 @@ ///////////////////////////////////////////////////////////////////////////// // 2nd order central differencing -/*! - * \brief 2nd order central differencing in X - * - * Performs calculation at a single point. The input field - * must be defined at i.xp() and i.xm() - * - * @param f The field to be differentiated - * @param i The point where the result is calculated - */ -inline BoutReal DDX_C2(const Field3D &f, const DataIterator &i) { - return (f[i.xp()] - f[i.xm()])/(2.*mesh->coordinates()->dx[i]); -} - -inline BoutReal DDY_C2(const Field3D &f, const DataIterator &i) { - return (f.yup()[i.yp()] - f.ydown()[i.ym()])/(2.*mesh->coordinates()->dy[i]); -} - - -inline BoutReal DDZ_C2(const Field3D &f, const DataIterator &i) { - return (f[i.zp()] - f[i.zm()])/(2.*mesh->coordinates()->dz); -} - /*! * 2nd order central differencing in X * Performs operation over RGN_NOBNDRY @@ -86,20 +64,6 @@ const Field3D DDZ_C2(const Field3D &f) { ///////////////////////////////////////////////////////////////////////////// // 4th order central differencing -/*! - * 4th order central differencing in X - */ -inline BoutReal DDX_C4(const Field3D &f, const DataIterator &i) { - return (8.*f[i.xp()] - 8.*f[i.xm()] + f[i.offset(-2,0,0)] - f[i.offset(2,0,0)])/(12.*mesh->coordinates()->dx[i]); -} - -/*! - * 4th order central differencing in Z - */ -inline BoutReal DDZ_C4(const Field3D &f, const DataIterator &i) { - return (8.*f[i.zp()] - 8.*f[i.zm()] + f[i.offset(0,0,-2)] - f[i.offset(0,0,2)])/(12.*mesh->coordinates()->dz); -} - /*! * 4th order central differencing in X * Performs operation over RGN_NOBNDRY @@ -158,44 +122,6 @@ const Field3D DDX_test(const Field3D &f) { ///////////////////////////////////////////////////////////////////////////// // Arakawa brackets -BoutReal bracket_arakawa(const Field3D &f, const Field3D &g, const DataIterator &i) { - Coordinates *metric = mesh->coordinates(); - - BoutReal fxp = f[i.xp()]; - BoutReal fxm = f[i.xm()]; - BoutReal fzp = f[i.zp()]; - BoutReal fzm = f[i.zm()]; - - BoutReal fpp = f[i.offset(1,0,1)]; - BoutReal fpm = f[i.offset(1,0,-1)]; - BoutReal fmp = f[i.offset(-1,0,1)]; - BoutReal fmm = f[i.offset(-1,0,-1)]; - - BoutReal gxp = g[i.xp()]; - BoutReal gxm = g[i.xm()]; - BoutReal gzp = g[i.zp()]; - BoutReal gzm = g[i.zm()]; - - // J++ = DDZ(f)*DDX(g) - DDX(f)*DDZ(g) - BoutReal Jpp = 0.25*( (fzp - fzm)* - (gxp - gxm) - - (fxp - fxm)* - (gzp - gzm) ); - - // J+x - BoutReal Jpx = 0.25*( gxp*(fpp-fpm) - - gxm*(fmp-fmm) - - gzp*(fpp-fmp) + - gzm*(fpm-fmm)); - // Jx+ - BoutReal Jxp = 0.25*( g[i.offset(1,0,1)]*(fzp-fxp) - - g[i.offset(-1,0,-1)]*(fxm-fzm) - - g[i.offset(-1,0,1)]*(fzp-fxm) + - g[i.offset(1,0,-1)]*(fxp-fzm) ); - - return (Jpp + Jpx + Jxp) / (3. * metric->dx[i] * metric->dz); -} - const Field3D bracket_arakawa(const Field3D &f, const Field3D &g) { Field3D result; result.allocate(); diff --git a/examples/performance/iterator-offsets/iterator-offsets.cxx b/examples/performance/iterator-offsets/iterator-offsets.cxx index d1e069cfe0..345caf5995 100644 --- a/examples/performance/iterator-offsets/iterator-offsets.cxx +++ b/examples/performance/iterator-offsets/iterator-offsets.cxx @@ -86,24 +86,6 @@ int main(int argc, char **argv) { } ); - // Range based for DataIterator with indices - ITERATOR_TEST_BLOCK( - "C++11 range-based for (omp)", - BOUT_OMP(parallel) - for(auto i : result.region(RGN_NOY)){ - result(i.x,i.y,i.z) = (a(i.x,i.y+1,i.z) - a(i.x,i.y-1,i.z)); - } - ); - - // Range based DataIterator - ITERATOR_TEST_BLOCK( - "C++11 range-based for [i] (omp)", - BOUT_OMP(parallel) - for(const auto &i : result.region(RGN_NOY)){ - result[i] = (a[i.yp()] - a[i.ym()]); - } - ); - ITERATOR_TEST_BLOCK( "C++11 range-based for over Region [i] (omp)", BOUT_OMP(parallel) @@ -114,36 +96,8 @@ int main(int argc, char **argv) { } ); - ITERATOR_TEST_BLOCK( - "C++11 range-based for [i] with stencil (omp)", - BOUT_OMP(parallel) - { - stencil s; - for(const auto &i : result.region(RGN_NOY)){ - s.mm = nan(""); - s.m = a[i.ym()]; - s.c = a[i]; - s.p = a[i.yp()]; - s.pp = nan(""); - result[i] = (s.p - s.m); - } - } - ); #endif - ITERATOR_TEST_BLOCK( - "C++11 range-based for [i] with stencil (serial)", - stencil s; - for(const auto &i : result.region(RGN_NOY)){ - s.mm = nan(""); - s.m = a[i.ym()]; - s.c = a[i]; - s.p = a[i.yp()]; - s.pp = nan(""); - result[i] = (s.p - s.m); - } - ); - // Region macro ITERATOR_TEST_BLOCK( "Region with stencil (serial)", diff --git a/examples/performance/iterator/iterator.cxx b/examples/performance/iterator/iterator.cxx index 03a6f61aa7..7c1033ca21 100644 --- a/examples/performance/iterator/iterator.cxx +++ b/examples/performance/iterator/iterator.cxx @@ -98,40 +98,6 @@ int main(int argc, char **argv) { ); #endif - // DataIterator using begin(), end() - ITERATOR_TEST_BLOCK("DI begin/end", - for(DataIterator i = std::begin(result), rend=std::end(result); i != rend; ++i){ - result(i.x,i.y,i.z) = a(i.x,i.y,i.z) + b(i.x,i.y,i.z); - } - ); - - // DataIterator with done() - ITERATOR_TEST_BLOCK("DI begin/done", - for(DataIterator i = std::begin(result); !i.done() ; ++i){ - result(i.x,i.y,i.z) = a(i.x,i.y,i.z) + b(i.x,i.y,i.z); - } - ); - - // Range based for DataIterator with indices - ITERATOR_TEST_BLOCK("C++11 range-based for", - for(auto i : result){ - result(i.x,i.y,i.z) = a(i.x,i.y,i.z) + b(i.x,i.y,i.z); - } - ); - - // Range based DataIterator - ITERATOR_TEST_BLOCK("C++11 range-based for [i]", - for (const auto &i : result) { - result[i] = a[i] + b[i]; - } - ); - - // DataIterator over fields - ITERATOR_TEST_BLOCK("DI (done) [i]", - for(DataIterator d = result.iterator(); !d.done(); d++) - result[d] = a[d] + b[d]; - ); - //Raw C loop ITERATOR_TEST_BLOCK("C loop repeat", for(int j=0;jLocalNx; ++jx) { - for (int jy = 0; jy < mesh->LocalNy; ++jy) { - for (int jz = 0; jz < mesh->LocalNz; ++jz) { - EXPECT_DOUBLE_EQ(d3[i](jx, jy, jz), expected); - } - } - } - } - - delete[] d3; -} -#endif - // Restore compiler warnings #pragma GCC diagnostic pop From 6488ecdbb24bb68ba1d0671e0751458ec024f98e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 7 Nov 2018 16:12:57 +0000 Subject: [PATCH 0237/1783] Remove manual section on outerloops --- .../user_docs/differential_operators.rst | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/manual/sphinx/user_docs/differential_operators.rst b/manual/sphinx/user_docs/differential_operators.rst index 90f587ccdf..487e04295e 100644 --- a/manual/sphinx/user_docs/differential_operators.rst +++ b/manual/sphinx/user_docs/differential_operators.rst @@ -470,45 +470,6 @@ values. Several slope limiters are defined in ``fv_ops.hxx``: default. -Operators on a single index ---------------------------- - -**Note: Experimental** - -The standard functions implemented in BOUT++ (such as ``DDX``, or -``bracket``) typically operate on a whole field, internally iterating -over the entire mesh. This is convenient, but leads to many loops over -the mesh, which can be inefficient due to cache misses. One way to try -to improve efficiency is to move to a single loop over the mesh. To do -this, some operators are implemented in ``bout/operators_di.hxx`` -which have the same (or similar) names as the standard operators but -an additional `DataIterator` index. - -For example, in ``examples/blob2d.cxx`` - -:: - - ddt(n) = - bracket(phi,n,BRACKET_ARAKAWA) - + 2 * DDZ(n) * (rho_s / R_c) - ; - -which in ``examples/blob2d-outerloop.cxx`` becomes:: - - for(auto &i : n.region(RGN_NOBNDRY)) { - ... - ddt(n)[i] = - bracket_arakawa(phi, n, i) - + 2 * DDZ_C2(n, i) * (rho_s / R_c) - ; - } - -Note that in addition to providing an index ``i`` which is of type -`DataIterator`, the function name includes the method (``arakawa`` or -``C2``). This is so that the function call does not have to contain -logic to decide the method to use at runtime. The standard operators -only have to decide which method to use once, then loop over the -entire mesh, but these indexed functions would have to decide the -method for every index. - .. _sec-derivatives: Derivative internals From a972f59b980a5ad91b2fac9b46bdb99f2c2adfe7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 7 Nov 2018 17:27:15 +0000 Subject: [PATCH 0238/1783] Don't return *this from yup/ydown if there are no parallel slices This changes the behaviour of mergeYupYdown: afterwards, the parallel slices are not valid --- include/field3d.hxx | 12 ------------ tests/unit/field/test_field3d.cxx | 19 +++++-------------- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/include/field3d.hxx b/include/field3d.hxx index 3a774e2d48..b662225860 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -233,35 +233,23 @@ class Field3D : public Field, public FieldData { /// Return reference to yup field Field3D &yup(std::vector::size_type index = 0) { - if (yup_fields.empty()) { - return *this; - } ASSERT2(index < yup_fields.size()); // Check for communicate return yup_fields[index]; } /// Return const reference to yup field const Field3D &yup(std::vector::size_type index = 0) const { - if (yup_fields.empty()) { - return *this; - } ASSERT2(index < yup_fields.size()); return yup_fields[index]; } /// Return reference to ydown field Field3D &ydown(std::vector::size_type index = 0) { - if (ydown_fields.empty()) { - return *this; - } ASSERT2(index < ydown_fields.size()); return ydown_fields[index]; } /// Return const reference to ydown field const Field3D &ydown(std::vector::size_type index = 0) const { - if (ydown_fields.empty()) { - return *this; - } ASSERT2(index < ydown_fields.size()); return ydown_fields[index]; } diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 775a383621..842c279a61 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -245,18 +245,11 @@ TEST_F(Field3DTest, MergeYupYDown) { EXPECT_FALSE(field.hasYupYdown()); - auto& yup = field.yup(); - EXPECT_EQ(&field, &yup); - auto& ydown = field.ydown(); - EXPECT_EQ(&field, &ydown); + EXPECT_THROW(field.yup(), BoutException); + EXPECT_THROW(field.ydown(), BoutException); // Should be able to merge again without any problems - field.mergeYupYdown(); - - auto& yup2 = field.yup(); - EXPECT_EQ(&field, &yup2); - auto& ydown2 = field.ydown(); - EXPECT_EQ(&field, &ydown2); + EXPECT_NO_THROW(field.mergeYupYdown()); } TEST_F(Field3DTest, SplitThenMergeYupYDown) { @@ -272,10 +265,8 @@ TEST_F(Field3DTest, SplitThenMergeYupYDown) { field.mergeYupYdown(); - auto& yup2 = field.yup(); - EXPECT_EQ(&field, &yup2); - auto& ydown2 = field.ydown(); - EXPECT_EQ(&field, &ydown2); + EXPECT_THROW(field.yup(), BoutException); + EXPECT_THROW(field.ydown(), BoutException); } TEST_F(Field3DTest, MultipleYupYdown) { From a360f6340abb68e740885a2f6e8b8b4c797ac76b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 8 Nov 2018 11:44:06 +0000 Subject: [PATCH 0239/1783] Fix path for locale files as localedir may rely on datarootpath, prefix, ... they need to be set before the static evaluation. Thus moving the lines to the top fixes this. --- make.config.in | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/make.config.in b/make.config.in index 213287c271..4fee8499e3 100644 --- a/make.config.in +++ b/make.config.in @@ -30,8 +30,12 @@ BOUT_INCLUDE_PATH=$(BOUT_TOP)/include BOUT_LIB_PATH=$(BOUT_TOP)/lib BOUT_CONFIG_FILE=$(BOUT_TOP)/make.config +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ + # This path to the locale (.mo) files is hard-wired into bout++.cxx at compile time -BOUT_LOCALE_PATH=@localedir@ +BOUT_LOCALE_PATH=@localedir@ # Created this variable so that a user won't overwrite the CXXFLAGS variable # on the command line, just add to this one @@ -143,9 +147,6 @@ $(BOUT_TOP)/include $(BOUT_TOP)/lib: #################################################################### # Install header files and libraries #################################################################### -prefix = @prefix@ -exec_prefix = @exec_prefix@ -datarootdir = @datarootdir@ INSTALL = @INSTALL@ INSTALL_PROGRAM = ${INSTALL} From 0c11867a599e13cba8e29ec3f8f5ec69ebdecfb7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 8 Nov 2018 14:52:41 +0000 Subject: [PATCH 0240/1783] Declare lots of things in Array as noexcept Some of these aren't technically true but are really required, e.g. the destructor calls `Array::release()` which calls `Array::store()` which might throw. If that happens, the only thing we can do is abort anyway -- which is what will happen if `noexcept` is violated. --- include/bout/array.hxx | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/include/bout/array.hxx b/include/bout/array.hxx index 6869dac93e..3c95f55016 100644 --- a/include/bout/array.hxx +++ b/include/bout/array.hxx @@ -77,7 +77,7 @@ public: * a.empty(); // True * */ - Array() : ptr(nullptr) {} + Array() noexcept : ptr(nullptr) {} /*! * Create an array of given length @@ -89,14 +89,14 @@ public: /*! * Destructor. Releases the underlying ArrayData */ - ~Array() { + ~Array() noexcept { release(ptr); } /*! * Copy constructor */ - Array(const Array &other) { + Array(const Array &other) noexcept { ptr = other.ptr; } @@ -106,7 +106,7 @@ public: * * Uses copy-and-swap idiom */ - Array& operator=(Array other) { + Array& operator=(Array other) noexcept { swap(*this, other); return *this; } @@ -114,7 +114,7 @@ public: /*! * Move constructor */ - Array(Array&& other) { + Array(Array&& other) noexcept { swap(*this, other); } @@ -127,7 +127,7 @@ public: * but can be set to false by passing "false" as input. * Once set to false it can't be changed back to true. */ - static bool useStore( bool keep_using = true ) { + static bool useStore( bool keep_using = true ) noexcept { static bool value = true; if (keep_using) { return value; @@ -141,7 +141,7 @@ public: * Release data. After this the Array is empty and any data access * will be invalid */ - void clear() { + void clear() noexcept { release(ptr); } @@ -161,17 +161,19 @@ public: /*! * Returns true if the Array is empty */ - bool empty() const { + bool empty() const noexcept { return ptr == nullptr; } /*! * Return size of the array. Zero if the array is empty. */ - int size() const { + int size() const noexcept { if(!ptr) return 0; #ifdef BOUT_ARRAY_WITH_VALARRAY + // Note: std::valarray::size is not noexcept, so Array::size + // shouldn't be either if we're using valarrays return ptr->size(); #else return ptr->len; @@ -182,7 +184,7 @@ public: * Returns true if the data is unique to this Array. * */ - bool unique() const { + bool unique() const noexcept { return ptr.use_count() == 1; } @@ -216,20 +218,20 @@ public: typedef T* iterator; typedef const T* const_iterator; #ifndef BOUT_ARRAY_WITH_VALARRAY - iterator begin() { + iterator begin() noexcept { return (ptr) ? ptr->data : nullptr; } - iterator end() { + iterator end() noexcept { return (ptr) ? ptr->data + ptr->len : nullptr; } // Const iterators - const_iterator begin() const { + const_iterator begin() const noexcept { return (ptr) ? ptr->data : nullptr; } - const_iterator end() const { + const_iterator end() const noexcept { return (ptr) ? ptr->data + ptr->len : nullptr; } #else @@ -279,7 +281,7 @@ public: * Exchange contents with another Array of the same type. * Sizes of the arrays may differ. */ - friend void swap(Array &first, Array &second) { + friend void swap(Array &first, Array &second) noexcept { using std::swap; swap(first.ptr, second.ptr); } @@ -391,6 +393,9 @@ private: p = st.back(); st.pop_back(); } else { + // Ensure that when we release the data block later we'll have + // enough space to put it in the store + st.reserve(1); p = std::make_shared(len); } @@ -403,8 +408,13 @@ private: * It's important to pass a reference to the pointer, otherwise we get * a copy of the shared_ptr, which therefore increases the use count * and doesn't allow us to free the pass pointer directly + * + * Note that this is noexcept only because we've ensure that both a) + * store()[] already exists, and b) it has space for at least + * one data block. Of course, store() could throw -- in which case + * we're doomed anyway, so the only thing we can do is abort */ - void release(dataPtrType &d) { + void release(dataPtrType &d) noexcept { if (!d) return; From d4850915748da3387b03327b258828f6c8ade78a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 8 Nov 2018 16:57:07 +0000 Subject: [PATCH 0241/1783] Clean squashoutput.py --- tools/pylib/boutdata/squashoutput.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tools/pylib/boutdata/squashoutput.py b/tools/pylib/boutdata/squashoutput.py index 52bcaa40d1..c0ed69a81b 100644 --- a/tools/pylib/boutdata/squashoutput.py +++ b/tools/pylib/boutdata/squashoutput.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - """ Collect all data from BOUT.dmp.* files and create a single output file. @@ -8,11 +6,6 @@ Useful because this discards ghost cell data (that is only useful for debugging) and because single files are quicker to download. -When run as script: - - first command line argument specifies data directory (default is the - current directory where the script is run) - - optional argument "--outputname " can be given to change the name - of the output file """ from boutdata.data import BoutOutputs From c6ae18c686f5c792262f4eaffa3f15a1974905fa Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 8 Nov 2018 19:38:11 +0000 Subject: [PATCH 0242/1783] Small tweak to CWENO3 --- include/bout/index_derivs.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index 056c23c8cf..a8aa1dce69 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -336,8 +336,8 @@ DEFINE_STANDARD_DERIV(DDX_CWENO3, "W3", 2, DERIV::Standard) { sm.p = ma - f.p; sm.pp = ma - f.pp; - const DerivativeType upwindOp; - return upwindOp.apply(0.5, sp) + upwindOp.apply(-0.5, sm); + const VDDX_WENO3 upwindOp{}; + return upwindOp(0.5, sp) + upwindOp(-0.5, sm); } //////////////////////////////////////////////////////////////////////////////// From cb702c3228d68293047cf7c7ee9d6837c9e9a093 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 9 Nov 2018 11:48:54 +0000 Subject: [PATCH 0243/1783] Optimisations to certain vector routines ToCovariant/Contravariant now use explicit loop rather than multiple field operations. Can provide significant reduction in time. V_dot_grad for two vector arguments now written in terms of a templated routine to avoid large amounts of duplicated code. The templated routine also introduces a loop over the mesh rather than using field operations. Together these changes should reduce the time for vector based models be a reasonable fraction (e.g. the orszag-tang example). --- src/field/vecops.cxx | 288 +++++++++++------------------------------ src/field/vector2d.cxx | 106 +++++++++++---- src/field/vector3d.cxx | 106 +++++++++++---- 3 files changed, 236 insertions(+), 264 deletions(-) diff --git a/src/field/vecops.cxx b/src/field/vecops.cxx index 4ebb9fb7e3..d5af58bf38 100644 --- a/src/field/vecops.cxx +++ b/src/field/vecops.cxx @@ -24,6 +24,8 @@ * **************************************************************************/ +#include + #include #include #include @@ -36,7 +38,7 @@ const Vector2D Grad(const Field2D &f, CELL_LOC outloc) { TRACE("Grad( Field2D )"); - + SCOREP0(); CELL_LOC outloc_x, outloc_y, outloc_z; if (outloc == CELL_VSHIFT) { outloc_x = CELL_XLOW; @@ -65,7 +67,7 @@ const Vector2D Grad(const Field2D &f, CELL_LOC outloc) { const Vector3D Grad(const Field3D &f, CELL_LOC outloc) { TRACE("Grad( Field3D )"); - + SCOREP0(); CELL_LOC outloc_x, outloc_y, outloc_z; if (outloc == CELL_VSHIFT) { outloc_x = CELL_XLOW; @@ -94,7 +96,7 @@ const Vector3D Grad(const Field3D &f, CELL_LOC outloc) { const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc) { TRACE("Grad_perp( Field3D )"); - + SCOREP0(); ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); Coordinates *metric = f.getCoordinates(outloc); @@ -118,7 +120,7 @@ const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc) { const Field2D Div(const Vector2D &v, CELL_LOC outloc) { TRACE("Div( Vector2D )"); - + SCOREP0(); if (outloc == CELL_DEFAULT) { outloc = v.getLocation(); } @@ -144,7 +146,7 @@ const Field2D Div(const Vector2D &v, CELL_LOC outloc) { const Field3D Div(const Vector3D &v, CELL_LOC outloc) { TRACE("Div( Vector3D )"); - + SCOREP0(); if (outloc == CELL_DEFAULT) { outloc = v.getLocation(); } @@ -175,7 +177,7 @@ const Field3D Div(const Vector3D &v, CELL_LOC outloc) { const Field2D Div(const Vector2D &v, const Field2D &f, CELL_LOC outloc) { TRACE("Div( Vector2D, Field2D )"); - + SCOREP0(); if (outloc == CELL_DEFAULT) { outloc = v.getLocation(); } @@ -202,7 +204,7 @@ const Field2D Div(const Vector2D &v, const Field2D &f, CELL_LOC outloc) { const Field3D Div(const Vector3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc) { TRACE("Div( Vector3D, Field3D )"); - + SCOREP0(); if (outloc == CELL_DEFAULT) { outloc = v.getLocation(); } @@ -269,7 +271,7 @@ const Vector2D Curl(const Vector2D &v) { const Vector3D Curl(const Vector3D &v) { TRACE("Curl( Vector3D )"); - + SCOREP0(); ASSERT1(v.getLocation() != CELL_VSHIFT); Mesh *localmesh = v.x.getMesh(); @@ -298,16 +300,15 @@ const Vector3D Curl(const Vector3D &v) { /************************************************************************** * Upwinding operators **************************************************************************/ - const Field2D V_dot_Grad(const Vector2D &v, const Field2D &f) { TRACE("V_dot_Grad( Vector2D , Field2D )"); - + SCOREP0(); Field2D result(f.getMesh()); // Get contravariant components of v - Vector2D vcn = v; + auto vcn = v; vcn.toContravariant(); - + result = VDDX(vcn.x, f) + VDDY(vcn.y, f) + VDDZ(vcn.z, f); return result; @@ -315,27 +316,27 @@ const Field2D V_dot_Grad(const Vector2D &v, const Field2D &f) { const Field3D V_dot_Grad(const Vector2D &v, const Field3D &f) { TRACE("V_dot_Grad( Vector2D , Field3D )"); - + SCOREP0(); Field3D result(f.getMesh()); // Get contravariant components of v - Vector2D vcn = v; + auto vcn = v; vcn.toContravariant(); - + result = VDDX(vcn.x, f) + VDDY(vcn.y, f) + VDDZ(vcn.z, f); return result; } const Field3D V_dot_Grad(const Vector3D &v, const Field2D &f) { - TRACE("V_dot_Grad( Vector3D , Field2D )"); - + TRACE("V_dot_Grad( Vector3D , Field3D )"); + SCOREP0(); Field3D result(f.getMesh()); // Get contravariant components of v - Vector3D vcn = v; + auto vcn = v; vcn.toContravariant(); - + result = VDDX(vcn.x, f) + VDDY(vcn.y, f) + VDDZ(vcn.z, f); return result; @@ -343,11 +344,11 @@ const Field3D V_dot_Grad(const Vector3D &v, const Field2D &f) { const Field3D V_dot_Grad(const Vector3D &v, const Field3D &f) { TRACE("V_dot_Grad( Vector3D , Field3D )"); - + SCOREP0(); Field3D result(f.getMesh()); // Get contravariant components of v - Vector3D vcn = v; + auto vcn = v; vcn.toContravariant(); result = VDDX(vcn.x, f) + VDDY(vcn.y, f) + VDDZ(vcn.z, f); @@ -355,220 +356,89 @@ const Field3D V_dot_Grad(const Vector3D &v, const Field3D &f) { return result; } -const Vector2D V_dot_Grad(const Vector2D &v, const Vector2D &a) { - TRACE("V_dot_Grad( Vector2D , Vector2D )"); - +// Here R is the deduced return type based on a promoting +// operation (addition) between the two input types. +template +R V_dot_Grad(const T &v, const F &a) { + TRACE("%s", __thefunc__); + SCOREP0(); ASSERT1(v.getLocation() == a.getLocation()); ASSERT1(v.getLocation() != CELL_VSHIFT); - Vector2D result{v.x.getMesh()}; + // Note by default R will describe a const vector type. By using + // the following form of declaring result we ignore the const + // qualifier here but keep it on the return type in the function + // signature. + auto result = R{v.x.getMesh()}; auto metric = v.x.getCoordinates(); - Vector2D vcn = v; + auto vcn = v; vcn.toContravariant(); - if (a.covariant) { - + if (a.covariant) { result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); - result.x -= vcn.x * (metric->G1_11 * a.x + metric->G2_11 * a.y + metric->G3_11 * a.z); - result.x -= vcn.y * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); - result.x -= vcn.z * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); - + BOUT_FOR(i, result.x.getRegion("RGN_ALL")) { + result.x[i] -= vcn.x[i] * (metric->G1_11[i] * a.x[i] + metric->G2_11[i] * a.y[i] + metric->G3_11[i] * a.z[i]); + result.x[i] -= vcn.y[i] * (metric->G1_12[i] * a.x[i] + metric->G2_12[i] * a.y[i] + metric->G3_12[i] * a.z[i]); + result.x[i] -= vcn.z[i] * (metric->G1_13[i] * a.x[i] + metric->G2_13[i] * a.y[i] + metric->G3_13[i] * a.z[i]); + } + result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); - result.y -= vcn.x * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); - result.y -= vcn.y * (metric->G1_22 * a.x + metric->G2_22 * a.y + metric->G3_22 * a.z); - result.y -= vcn.z * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); - + BOUT_FOR(i, result.y.getRegion("RGN_ALL")) { + result.y[i] -= vcn.x[i] * (metric->G1_12[i] * a.x[i] + metric->G2_12[i] * a.y[i] + metric->G3_12[i] * a.z[i]); + result.y[i] -= vcn.y[i] * (metric->G1_22[i] * a.x[i] + metric->G2_22[i] * a.y[i] + metric->G3_22[i] * a.z[i]); + result.y[i] -= vcn.z[i] * (metric->G1_23[i] * a.x[i] + metric->G2_23[i] * a.y[i] + metric->G3_23[i] * a.z[i]); + } + result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); - result.z -= vcn.x * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); - result.z -= vcn.y * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); - result.z -= vcn.z * (metric->G1_33 * a.x + metric->G2_33 * a.y + metric->G3_33 * a.z); - + BOUT_FOR(i, result.z.getRegion("RGN_ALL")) { + result.z[i] -= vcn.x[i] * (metric->G1_13[i] * a.x[i] + metric->G2_13[i] * a.y[i] + metric->G3_13[i] * a.z[i]); + result.z[i] -= vcn.y[i] * (metric->G1_23[i] * a.x[i] + metric->G2_23[i] * a.y[i] + metric->G3_23[i] * a.z[i]); + result.z[i] -= vcn.z[i] * (metric->G1_33[i] * a.x[i] + metric->G2_33[i] * a.y[i] + metric->G3_33[i] * a.z[i]); + } result.covariant = true; } else { - result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); - result.x += vcn.x * (metric->G1_11 * a.x + metric->G1_12 * a.y + metric->G1_13 * a.z); - result.x += vcn.y * (metric->G1_12 * a.x + metric->G1_22 * a.y + metric->G1_23 * a.z); - result.x += vcn.z * (metric->G1_13 * a.x + metric->G1_23 * a.y + metric->G1_33 * a.z); - + BOUT_FOR(i, result.x.getRegion("RGN_ALL")) { + result.x[i] += vcn.x[i] * (metric->G1_11[i] * a.x[i] + metric->G1_12[i] * a.y[i] + metric->G1_13[i] * a.z[i]); + result.x[i] += vcn.y[i] * (metric->G1_12[i] * a.x[i] + metric->G1_22[i] * a.y[i] + metric->G1_23[i] * a.z[i]); + result.x[i] += vcn.z[i] * (metric->G1_13[i] * a.x[i] + metric->G1_23[i] * a.y[i] + metric->G1_33[i] * a.z[i]); + } + result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); - result.y += vcn.x * (metric->G2_11 * a.x + metric->G2_12 * a.y + metric->G2_13 * a.z); - result.y += vcn.y * (metric->G2_12 * a.x + metric->G2_22 * a.y + metric->G2_23 * a.z); - result.y += vcn.z * (metric->G2_13 * a.x + metric->G2_23 * a.y + metric->G2_33 * a.z); - + BOUT_FOR(i, result.y.getRegion("RGN_ALL")) { + result.y[i] += vcn.x[i] * (metric->G2_11[i] * a.x[i] + metric->G2_12[i] * a.y[i] + metric->G2_13[i] * a.z[i]); + result.y[i] += vcn.y[i] * (metric->G2_12[i] * a.x[i] + metric->G2_22[i] * a.y[i] + metric->G2_23[i] * a.z[i]); + result.y[i] += vcn.z[i] * (metric->G2_13[i] * a.x[i] + metric->G2_23[i] * a.y[i] + metric->G2_33[i] * a.z[i]); + } + result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); - result.z += vcn.x * (metric->G3_11 * a.x + metric->G3_12 * a.y + metric->G3_13 * a.z); - result.z += vcn.y * (metric->G3_12 * a.x + metric->G3_22 * a.y + metric->G3_23 * a.z); - result.z += vcn.z * (metric->G3_13 * a.x + metric->G3_23 * a.y + metric->G3_33 * a.z); - + BOUT_FOR(i, result.z.getRegion("RGN_ALL")) { + result.z[i] += vcn.x[i] * (metric->G3_11[i] * a.x[i] + metric->G3_12[i] * a.y[i] + metric->G3_13[i] * a.z[i]); + result.z[i] += vcn.y[i] * (metric->G3_12[i] * a.x[i] + metric->G3_22[i] * a.y[i] + metric->G3_23[i] * a.z[i]); + result.z[i] += vcn.z[i] * (metric->G3_13[i] * a.x[i] + metric->G3_23[i] * a.y[i] + metric->G3_33[i] * a.z[i]); + } + result.covariant = false; } result.setLocation(v.getLocation()); return result; -} + +}; +// Implement vector-vector operation in terms of templated routine above +const Vector2D V_dot_Grad(const Vector2D &v, const Vector2D &a) { + return V_dot_Grad(v, a); +} const Vector3D V_dot_Grad(const Vector2D &v, const Vector3D &a) { - TRACE("V_dot_Grad( Vector2D , Vector3D )"); - - ASSERT1(v.getLocation() == a.getLocation()); - ASSERT1(v.getLocation() != CELL_VSHIFT); - - Vector3D result{v.x.getMesh()}; - - auto metric = v.x.getCoordinates(); - - Vector2D vcn = v; - vcn.toContravariant(); - - if (a.covariant) { - result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); - result.x -= vcn.x * (metric->G1_11 * a.x + metric->G2_11 * a.y + metric->G3_11 * a.z); - result.x -= vcn.y * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); - result.x -= vcn.z * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); - - result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); - result.y -= vcn.x * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); - result.y -= vcn.y * (metric->G1_22 * a.x + metric->G2_22 * a.y + metric->G3_22 * a.z); - result.y -= vcn.z * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); - - result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); - result.z -= vcn.x * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); - result.z -= vcn.y * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); - result.z -= vcn.z * (metric->G1_33 * a.x + metric->G2_33 * a.y + metric->G3_33 * a.z); - - result.covariant = true; - } else { - result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); - result.x += vcn.x * (metric->G1_11 * a.x + metric->G1_12 * a.y + metric->G1_13 * a.z); - result.x += vcn.y * (metric->G1_12 * a.x + metric->G1_22 * a.y + metric->G1_23 * a.z); - result.x += vcn.z * (metric->G1_13 * a.x + metric->G1_23 * a.y + metric->G1_33 * a.z); - - result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); - result.y += vcn.x * (metric->G2_11 * a.x + metric->G2_12 * a.y + metric->G2_13 * a.z); - result.y += vcn.y * (metric->G2_12 * a.x + metric->G2_22 * a.y + metric->G2_23 * a.z); - result.y += vcn.z * (metric->G2_13 * a.x + metric->G2_23 * a.y + metric->G2_33 * a.z); - - result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); - result.z += vcn.x * (metric->G3_11 * a.x + metric->G3_12 * a.y + metric->G3_13 * a.z); - result.z += vcn.y * (metric->G3_12 * a.x + metric->G3_22 * a.y + metric->G3_23 * a.z); - result.z += vcn.z * (metric->G3_13 * a.x + metric->G3_23 * a.y + metric->G3_33 * a.z); - - result.covariant = false; - } - - result.setLocation(v.getLocation()); - - return result; + return V_dot_Grad(v, a); } - const Vector3D V_dot_Grad(const Vector3D &v, const Vector2D &a) { - TRACE("V_dot_Grad( Vector3D , Vector2D )"); - - ASSERT1(v.getLocation() == a.getLocation()); - ASSERT1(v.getLocation() != CELL_VSHIFT); - - Vector3D result{v.x.getMesh()}; - - auto metric = v.x.getCoordinates(); - - Vector3D vcn = v; - vcn.toContravariant(); - - if (a.covariant) { - result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); - result.x -= vcn.x * (metric->G1_11 * a.x + metric->G2_11 * a.y + metric->G3_11 * a.z); - result.x -= vcn.y * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); - result.x -= vcn.z * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); - - result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); - result.y -= vcn.x * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); - result.y -= vcn.y * (metric->G1_22 * a.x + metric->G2_22 * a.y + metric->G3_22 * a.z); - result.y -= vcn.z * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); - - result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); - result.z -= vcn.x * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); - result.z -= vcn.y * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); - result.z -= vcn.z * (metric->G1_33 * a.x + metric->G2_33 * a.y + metric->G3_33 * a.z); - - result.covariant = true; - } else { - result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); - result.x += vcn.x * (metric->G1_11 * a.x + metric->G1_12 * a.y + metric->G1_13 * a.z); - result.x += vcn.y * (metric->G1_12 * a.x + metric->G1_22 * a.y + metric->G1_23 * a.z); - result.x += vcn.z * (metric->G1_13 * a.x + metric->G1_23 * a.y + metric->G1_33 * a.z); - - result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); - result.y += vcn.x * (metric->G2_11 * a.x + metric->G2_12 * a.y + metric->G2_13 * a.z); - result.y += vcn.y * (metric->G2_12 * a.x + metric->G2_22 * a.y + metric->G2_23 * a.z); - result.y += vcn.z * (metric->G2_13 * a.x + metric->G2_23 * a.y + metric->G2_33 * a.z); - - result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); - result.z += vcn.x * (metric->G3_11 * a.x + metric->G3_12 * a.y + metric->G3_13 * a.z); - result.z += vcn.y * (metric->G3_12 * a.x + metric->G3_22 * a.y + metric->G3_23 * a.z); - result.z += vcn.z * (metric->G3_13 * a.x + metric->G3_23 * a.y + metric->G3_33 * a.z); - - result.covariant = false; - } - - result.setLocation(v.getLocation()); - - return result; + return V_dot_Grad(v, a); } - const Vector3D V_dot_Grad(const Vector3D &v, const Vector3D &a) { - TRACE("V_dot_Grad( Vector3D , Vector3D )"); - - ASSERT1(v.getLocation() == a.getLocation()); - ASSERT1(v.getLocation() != CELL_VSHIFT); - - Vector3D result{v.x.getMesh()}; - - auto metric = v.x.getCoordinates(); - - Vector3D vcn = v; - vcn.toContravariant(); - - if (a.covariant) { - result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); - result.x -= vcn.x * (metric->G1_11 * a.x + metric->G2_11 * a.y + metric->G3_11 * a.z); - result.x -= vcn.y * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); - result.x -= vcn.z * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); - - result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); - result.y -= vcn.x * (metric->G1_12 * a.x + metric->G2_12 * a.y + metric->G3_12 * a.z); - result.y -= vcn.y * (metric->G1_22 * a.x + metric->G2_22 * a.y + metric->G3_22 * a.z); - result.y -= vcn.z * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); - - result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); - result.z -= vcn.x * (metric->G1_13 * a.x + metric->G2_13 * a.y + metric->G3_13 * a.z); - result.z -= vcn.y * (metric->G1_23 * a.x + metric->G2_23 * a.y + metric->G3_23 * a.z); - result.z -= vcn.z * (metric->G1_33 * a.x + metric->G2_33 * a.y + metric->G3_33 * a.z); - - result.covariant = true; - } else { - result.x = VDDX(vcn.x, a.x) + VDDY(vcn.y, a.x) + VDDZ(vcn.z, a.x); - result.x += vcn.x * (metric->G1_11 * a.x + metric->G1_12 * a.y + metric->G1_13 * a.z); - result.x += vcn.y * (metric->G1_12 * a.x + metric->G1_22 * a.y + metric->G1_23 * a.z); - result.x += vcn.z * (metric->G1_13 * a.x + metric->G1_23 * a.y + metric->G1_33 * a.z); - - result.y = VDDX(vcn.x, a.y) + VDDY(vcn.y, a.y) + VDDZ(vcn.z, a.y); - result.y += vcn.x * (metric->G2_11 * a.x + metric->G2_12 * a.y + metric->G2_13 * a.z); - result.y += vcn.y * (metric->G2_12 * a.x + metric->G2_22 * a.y + metric->G2_23 * a.z); - result.y += vcn.z * (metric->G2_13 * a.x + metric->G2_23 * a.y + metric->G2_33 * a.z); - - result.z = VDDX(vcn.x, a.z) + VDDY(vcn.y, a.z) + VDDZ(vcn.z, a.z); - result.z += vcn.x * (metric->G3_11 * a.x + metric->G3_12 * a.y + metric->G3_13 * a.z); - result.z += vcn.y * (metric->G3_12 * a.x + metric->G3_22 * a.y + metric->G3_23 * a.z); - result.z += vcn.z * (metric->G3_13 * a.x + metric->G3_23 * a.y + metric->G3_33 * a.z); - - result.covariant = false; - } - - result.setLocation(v.getLocation()); - - return result; + return V_dot_Grad(v, a); } diff --git a/src/field/vector2d.cxx b/src/field/vector2d.cxx index 541715b15b..38b7ea156c 100644 --- a/src/field/vector2d.cxx +++ b/src/field/vector2d.cxx @@ -33,6 +33,7 @@ #include #include #include +#include #include Vector2D::Vector2D(Mesh *localmesh) @@ -55,60 +56,106 @@ Vector2D::~Vector2D() { } } -void Vector2D::toCovariant() { +void Vector2D::toCovariant() { + SCOREP0(); if(!covariant) { Mesh *localmesh = x.getMesh(); - Field2D gx(localmesh), gy(localmesh), gz(localmesh); - Coordinates *metric_x, *metric_y, *metric_z; if (location == CELL_VSHIFT) { + Coordinates *metric_x, *metric_y, *metric_z; metric_x = localmesh->getCoordinates(CELL_XLOW); metric_y = localmesh->getCoordinates(CELL_YLOW); metric_z = localmesh->getCoordinates(CELL_ZLOW); + + // Fields at different locations so we need to interpolate + // Note : Could reduce peak memory requirement here by just + // dealing with the three components seperately. This would + // require the use of temporary fields to hold the intermediate + // result so would likely only reduce memory usage by one field + const auto y_at_x = interp_to(y, x.getLocation()); + const auto z_at_x = interp_to(z, x.getLocation()); + const auto x_at_y = interp_to(x, y.getLocation()); + const auto z_at_y = interp_to(z, y.getLocation()); + const auto x_at_z = interp_to(x, z.getLocation()); + const auto y_at_z = interp_to(y, z.getLocation()); + + // multiply by g_{ij} + BOUT_FOR(i, localmesh->getRegion2D("RGN_ALL")){ + x[i] = metric_x->g_11[i]*x[i] + metric_x->g_12[i]*y_at_x[i] + metric_x->g_13[i]*z_at_x[i]; + y[i] = metric_y->g_22[i]*y[i] + metric_y->g_12[i]*x_at_y[i] + metric_y->g_23[i]*z_at_y[i]; + z[i] = metric_z->g_33[i]*z[i] + metric_z->g_13[i]*x_at_z[i] + metric_z->g_23[i]*y_at_z[i]; + }; } else { - metric_x = localmesh->getCoordinates(location); - metric_y = localmesh->getCoordinates(location); - metric_z = localmesh->getCoordinates(location); - } + const auto metric = localmesh->getCoordinates(location); - // multiply by g_{ij} - gx = x*metric_x->g_11 + metric_x->g_12*interp_to(y, x.getLocation()) + metric_x->g_13*interp_to(z, x.getLocation()); - gy = y*metric_y->g_22 + metric_y->g_12*interp_to(x, y.getLocation()) + metric_y->g_23*interp_to(z, y.getLocation()); - gz = z*metric_z->g_33 + metric_z->g_13*interp_to(x, z.getLocation()) + metric_z->g_23*interp_to(y, z.getLocation()); + // Need to use temporary arrays to store result + Field2D gx(localmesh), gy(localmesh), gz(localmesh); + gx.allocate(); gy.allocate(); gz.allocate(); + + BOUT_FOR(i, localmesh->getRegion2D("RGN_ALL")){ + gx[i] = metric->g_11[i]*x[i] + metric->g_12[i]*y[i] + metric->g_13[i]*z[i]; + gy[i] = metric->g_22[i]*y[i] + metric->g_12[i]*x[i] + metric->g_23[i]*z[i]; + gz[i] = metric->g_33[i]*z[i] + metric->g_13[i]*x[i] + metric->g_23[i]*y[i]; + }; + + x = gx; + y = gy; + z = gz; + } - x = gx; - y = gy; - z = gz; - covariant = true; } } - void Vector2D::toContravariant() { + SCOREP0(); if(covariant) { // multiply by g^{ij} Mesh *localmesh = x.getMesh(); Field2D gx(localmesh), gy(localmesh), gz(localmesh); - Coordinates *metric_x, *metric_y, *metric_z; if (location == CELL_VSHIFT) { + Coordinates *metric_x, *metric_y, *metric_z; + metric_x = localmesh->getCoordinates(CELL_XLOW); metric_y = localmesh->getCoordinates(CELL_YLOW); metric_z = localmesh->getCoordinates(CELL_ZLOW); + + // Fields at different locations so we need to interpolate + // Note : Could reduce peak memory requirement here by just + // dealing with the three components seperately. This would + // require the use of temporary fields to hold the intermediate + // result so would likely only reduce memory usage by one field + const auto y_at_x = interp_to(y, x.getLocation()); + const auto z_at_x = interp_to(z, x.getLocation()); + const auto x_at_y = interp_to(x, y.getLocation()); + const auto z_at_y = interp_to(z, y.getLocation()); + const auto x_at_z = interp_to(x, z.getLocation()); + const auto y_at_z = interp_to(y, z.getLocation()); + + // multiply by g_{ij} + BOUT_FOR(i, localmesh->getRegion2D("RGN_ALL")){ + x[i] = metric_x->g11[i]*x[i] + metric_x->g12[i]*y_at_x[i] + metric_x->g13[i]*z_at_x[i]; + y[i] = metric_y->g22[i]*y[i] + metric_y->g12[i]*x_at_y[i] + metric_y->g23[i]*z_at_y[i]; + z[i] = metric_z->g33[i]*z[i] + metric_z->g13[i]*x_at_z[i] + metric_z->g23[i]*y_at_z[i]; + }; + } else { - metric_x = localmesh->getCoordinates(location); - metric_y = localmesh->getCoordinates(location); - metric_z = localmesh->getCoordinates(location); - } + const auto metric = localmesh->getCoordinates(location); + + // Need to use temporary arrays to store result + Field2D gx(localmesh), gy(localmesh), gz(localmesh); + gx.allocate(); gy.allocate(); gz.allocate(); - // multiply by g_{ij} - gx = x*metric_x->g11 + metric_x->g12*interp_to(y, x.getLocation()) + metric_x->g13*interp_to(z, x.getLocation()); - gy = y*metric_y->g22 + metric_y->g12*interp_to(x, y.getLocation()) + metric_y->g23*interp_to(z, y.getLocation()); - gz = z*metric_z->g33 + metric_z->g13*interp_to(x, z.getLocation()) + metric_z->g23*interp_to(y, z.getLocation()); + BOUT_FOR(i, localmesh->getRegion2D("RGN_ALL")){ + gx[i] = metric->g11[i]*x[i] + metric->g12[i]*y[i] + metric->g13[i]*z[i]; + gy[i] = metric->g22[i]*y[i] + metric->g12[i]*x[i] + metric->g23[i]*z[i]; + gz[i] = metric->g33[i]*z[i] + metric->g13[i]*x[i] + metric->g23[i]*y[i]; + }; - x = gx; - y = gy; - z = gz; + x = gx; + y = gy; + z = gz; + } covariant = false; } @@ -148,6 +195,7 @@ Vector2D* Vector2D::timeDeriv() { /////////////////// ASSIGNMENT //////////////////// Vector2D & Vector2D::operator=(const Vector2D &rhs) { + SCOREP0(); x = rhs.x; y = rhs.y; z = rhs.z; @@ -160,6 +208,7 @@ Vector2D & Vector2D::operator=(const Vector2D &rhs) { } Vector2D & Vector2D::operator=(const BoutReal val) { + SCOREP0(); x = val; y = val; z = val; @@ -373,6 +422,7 @@ CELL_LOC Vector2D::getLocation() const { } void Vector2D::setLocation(CELL_LOC loc) { + SCOREP0(); TRACE("Vector2D::setLocation"); if (loc == CELL_DEFAULT) { loc = CELL_CENTRE; diff --git a/src/field/vector3d.cxx b/src/field/vector3d.cxx index 000e5e0fec..e425586d71 100644 --- a/src/field/vector3d.cxx +++ b/src/field/vector3d.cxx @@ -34,6 +34,7 @@ #include #include #include +#include #include Vector3D::Vector3D(Mesh *localmesh) @@ -56,59 +57,106 @@ Vector3D::~Vector3D() { } } -void Vector3D::toCovariant() { +void Vector3D::toCovariant() { + SCOREP0(); if(!covariant) { Mesh *localmesh = x.getMesh(); - Field3D gx(localmesh), gy(localmesh), gz(localmesh); - Coordinates *metric_x, *metric_y, *metric_z; if (location == CELL_VSHIFT) { + Coordinates *metric_x, *metric_y, *metric_z; metric_x = localmesh->getCoordinates(CELL_XLOW); metric_y = localmesh->getCoordinates(CELL_YLOW); metric_z = localmesh->getCoordinates(CELL_ZLOW); + + // Fields at different locations so we need to interpolate + // Note : Could reduce peak memory requirement here by just + // dealing with the three components seperately. This would + // require the use of temporary fields to hold the intermediate + // result so would likely only reduce memory usage by one field + const auto y_at_x = interp_to(y, x.getLocation()); + const auto z_at_x = interp_to(z, x.getLocation()); + const auto x_at_y = interp_to(x, y.getLocation()); + const auto z_at_y = interp_to(z, y.getLocation()); + const auto x_at_z = interp_to(x, z.getLocation()); + const auto y_at_z = interp_to(y, z.getLocation()); + + // multiply by g_{ij} + BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")){ + x[i] = metric_x->g_11[i]*x[i] + metric_x->g_12[i]*y_at_x[i] + metric_x->g_13[i]*z_at_x[i]; + y[i] = metric_y->g_22[i]*y[i] + metric_y->g_12[i]*x_at_y[i] + metric_y->g_23[i]*z_at_y[i]; + z[i] = metric_z->g_33[i]*z[i] + metric_z->g_13[i]*x_at_z[i] + metric_z->g_23[i]*y_at_z[i]; + }; } else { - metric_x = localmesh->getCoordinates(location); - metric_y = localmesh->getCoordinates(location); - metric_z = localmesh->getCoordinates(location); - } + const auto metric = localmesh->getCoordinates(location); - // multiply by g_{ij} - gx = x*metric_x->g_11 + metric_x->g_12*interp_to(y, x.getLocation()) + metric_x->g_13*interp_to(z, x.getLocation()); - gy = y*metric_y->g_22 + metric_y->g_12*interp_to(x, y.getLocation()) + metric_y->g_23*interp_to(z, y.getLocation()); - gz = z*metric_z->g_33 + metric_z->g_13*interp_to(x, z.getLocation()) + metric_z->g_23*interp_to(y, z.getLocation()); + // Need to use temporary arrays to store result + Field3D gx(localmesh), gy(localmesh), gz(localmesh); + gx.allocate(); gy.allocate(); gz.allocate(); + + BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")){ + gx[i] = metric->g_11[i]*x[i] + metric->g_12[i]*y[i] + metric->g_13[i]*z[i]; + gy[i] = metric->g_22[i]*y[i] + metric->g_12[i]*x[i] + metric->g_23[i]*z[i]; + gz[i] = metric->g_33[i]*z[i] + metric->g_13[i]*x[i] + metric->g_23[i]*y[i]; + }; + + x = gx; + y = gy; + z = gz; + } - x = gx; - y = gy; - z = gz; - covariant = true; } } void Vector3D::toContravariant() { + SCOREP0(); if(covariant) { // multiply by g^{ij} Mesh *localmesh = x.getMesh(); Field3D gx(localmesh), gy(localmesh), gz(localmesh); - Coordinates *metric_x, *metric_y, *metric_z; if (location == CELL_VSHIFT) { + Coordinates *metric_x, *metric_y, *metric_z; + metric_x = localmesh->getCoordinates(CELL_XLOW); metric_y = localmesh->getCoordinates(CELL_YLOW); metric_z = localmesh->getCoordinates(CELL_ZLOW); + + // Fields at different locations so we need to interpolate + // Note : Could reduce peak memory requirement here by just + // dealing with the three components seperately. This would + // require the use of temporary fields to hold the intermediate + // result so would likely only reduce memory usage by one field + const auto y_at_x = interp_to(y, x.getLocation()); + const auto z_at_x = interp_to(z, x.getLocation()); + const auto x_at_y = interp_to(x, y.getLocation()); + const auto z_at_y = interp_to(z, y.getLocation()); + const auto x_at_z = interp_to(x, z.getLocation()); + const auto y_at_z = interp_to(y, z.getLocation()); + + // multiply by g_{ij} + BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")){ + x[i] = metric_x->g11[i]*x[i] + metric_x->g12[i]*y_at_x[i] + metric_x->g13[i]*z_at_x[i]; + y[i] = metric_y->g22[i]*y[i] + metric_y->g12[i]*x_at_y[i] + metric_y->g23[i]*z_at_y[i]; + z[i] = metric_z->g33[i]*z[i] + metric_z->g13[i]*x_at_z[i] + metric_z->g23[i]*y_at_z[i]; + }; + } else { - metric_x = localmesh->getCoordinates(location); - metric_y = localmesh->getCoordinates(location); - metric_z = localmesh->getCoordinates(location); - } + const auto metric = localmesh->getCoordinates(location); + + // Need to use temporary arrays to store result + Field3D gx(localmesh), gy(localmesh), gz(localmesh); + gx.allocate(); gy.allocate(); gz.allocate(); - // multiply by g_{ij} - gx = x*metric_x->g11 + metric_x->g12*interp_to(y, x.getLocation()) + metric_x->g13*interp_to(z, x.getLocation()); - gy = y*metric_y->g22 + metric_y->g12*interp_to(x, y.getLocation()) + metric_y->g23*interp_to(z, y.getLocation()); - gz = z*metric_z->g33 + metric_z->g13*interp_to(x, z.getLocation()) + metric_z->g23*interp_to(y, z.getLocation()); + BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")){ + gx[i] = metric->g11[i]*x[i] + metric->g12[i]*y[i] + metric->g13[i]*z[i]; + gy[i] = metric->g22[i]*y[i] + metric->g12[i]*x[i] + metric->g23[i]*z[i]; + gz[i] = metric->g33[i]*z[i] + metric->g13[i]*x[i] + metric->g23[i]*y[i]; + }; - x = gx; - y = gy; - z = gz; + x = gx; + y = gy; + z = gz; + } covariant = false; } @@ -149,6 +197,7 @@ Vector3D* Vector3D::timeDeriv() { /////////////////// ASSIGNMENT //////////////////// Vector3D & Vector3D::operator=(const Vector3D &rhs) { + SCOREP0(); x = rhs.x; y = rhs.y; z = rhs.z; @@ -160,6 +209,7 @@ Vector3D & Vector3D::operator=(const Vector3D &rhs) { } Vector3D & Vector3D::operator=(const Vector2D &rhs) { + SCOREP0(); x = rhs.x; y = rhs.y; z = rhs.z; @@ -173,6 +223,7 @@ Vector3D & Vector3D::operator=(const Vector2D &rhs) { Vector3D & Vector3D::operator=(const BoutReal val) { + SCOREP0(); x = val; y = val; z = val; @@ -499,6 +550,7 @@ CELL_LOC Vector3D::getLocation() const { } void Vector3D::setLocation(CELL_LOC loc) { + SCOREP0(); TRACE("Vector3D::setLocation"); if (loc == CELL_DEFAULT) { loc = CELL_CENTRE; From 7820c9c0ae1b5ed290d94fdffdd5fb26dc7cb653 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 12 Nov 2018 16:20:38 +0000 Subject: [PATCH 0244/1783] Move definition of __thefunc__ to bout_types --- include/bout/scorepwrapper.hxx | 13 ++----------- include/bout_types.hxx | 11 +++++++++++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/bout/scorepwrapper.hxx b/include/bout/scorepwrapper.hxx index 1ae479270c..71248dc652 100644 --- a/include/bout/scorepwrapper.hxx +++ b/include/bout/scorepwrapper.hxx @@ -1,6 +1,8 @@ #ifndef __BOUT_SCOREP_H__ #define __BOUT_SCOREP_H__ +#include + #ifdef BOUT_HAS_SCOREP #include #endif @@ -9,17 +11,6 @@ #define SCOREPLVL 0 #endif -/// The __PRETTY_FUNCTION__ variable is defined by GCC (and some other families) but is not a part -/// of the standard. The __func__ variable *is* a part of the c++11 standard so we'd like to fall back -/// to this if possible. However as these are variables/constants and not macros we can't just -/// check if __PRETTY_FUNCITON__ is defined or not. Instead we need to say if we support this -/// or not by defining HAS_PRETTY_FUNCTION (to be implemented in configure) -#ifdef HAS_PRETTY_FUNCTION -#define __thefunc__ __PRETTY_FUNCTION__ -#else -#define __thefunc__ __func__ -#endif - /// Instrument a region/function with scorep /// /// The scorep call is identical for all levels, so just define it here. diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 0553159867..6c2c1e4cdd 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -27,6 +27,17 @@ #include #include +/// The __PRETTY_FUNCTION__ variable is defined by GCC (and some other families) but is not a part +/// of the standard. The __func__ variable *is* a part of the c++11 standard so we'd like to fall back +/// to this if possible. However as these are variables/constants and not macros we can't just +/// check if __PRETTY_FUNCITON__ is defined or not. Instead we need to say if we support this +/// or not by defining HAS_PRETTY_FUNCTION (to be implemented in configure) +#ifdef HAS_PRETTY_FUNCTION +#define __thefunc__ __PRETTY_FUNCTION__ +#else +#define __thefunc__ __func__ +#endif + /// Size of real numbers typedef double BoutReal; From afef1bb8a993704168d92c2e1f62f875d6db5a57 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 12 Nov 2018 16:20:52 +0000 Subject: [PATCH 0245/1783] Add AUTO_TRACE macro. This acts a bit like TRACE but swallows arguments and instead uses the name given by `__thefunc__` --- include/msg_stack.hxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/msg_stack.hxx b/include/msg_stack.hxx index 71481f598b..61a3d15642 100644 --- a/include/msg_stack.hxx +++ b/include/msg_stack.hxx @@ -156,6 +156,7 @@ private: * } // Scope ends, message popped */ #if CHECK > 0 + /* Would like to have something like TRACE(message, ...) so that we can directly refer to the (required) first argument, which is the main message string. However because we want to allow TRACE("Message with no args") we have to deal with the case where @@ -172,4 +173,6 @@ private: #define TRACE(...) #endif +#define AUTO_TRACE(...) TRACE("%s", __thefunc__) + #endif // __MSG_STACK_H__ From 4dbcc201bfaf9cf3f327be8fc934022957339c95 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 12 Nov 2018 16:48:48 +0000 Subject: [PATCH 0246/1783] Remove unused DIFF_NND option/enum --- include/bout_types.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index b7201dfb55..3e014d6e24 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -52,14 +52,14 @@ inline const std::string& CELL_LOC_STRING(CELL_LOC location) { } /// Differential methods. Both central and upwind -enum DIFF_METHOD {DIFF_DEFAULT, DIFF_U1, DIFF_U2, DIFF_C2, DIFF_W2, DIFF_W3, DIFF_C4, DIFF_U3, DIFF_FFT, DIFF_SPLIT, DIFF_NND, DIFF_S2}; +enum DIFF_METHOD {DIFF_DEFAULT, DIFF_U1, DIFF_U2, DIFF_C2, DIFF_W2, DIFF_W3, DIFF_C4, DIFF_U3, DIFF_FFT, DIFF_SPLIT, DIFF_S2}; const std::map DIFF_METHODtoString = { {DIFF_DEFAULT, "default"}, {DIFF_U1, "U1"}, {DIFF_U2, "U2"}, {DIFF_U3, "U3"}, {DIFF_C2, "C2"}, {DIFF_C4, "C4"}, {DIFF_S2, "S2"}, {DIFF_W2, "W2"}, {DIFF_W3, "W3"}, {DIFF_FFT, "FFT"}, - {DIFF_SPLIT, "SPLIT"}, {DIFF_NND, "NND"} + {DIFF_SPLIT, "SPLIT"} }; inline const std::string& DIFF_METHOD_STRING(DIFF_METHOD location) { From c1cd487b4138cc53c80e104e17c6b7bd30662cd2 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 12 Nov 2018 17:08:48 +0000 Subject: [PATCH 0247/1783] Add special handling for SPLIT flux method --- include/bout/mesh.hxx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index eb82dbcccc..6a242c6db5 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -772,6 +772,16 @@ T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METH // Checks static_assert(std::is_base_of::value || std::is_base_of::value, "indexDDX only works on Field2D or Field3D input"); + + // Special handling for SPLIT method + if ((derivType == DERIV::Flux) && (method == DIFF_SPLIT)) { + // Split into an upwind and a central differencing part + // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) + auto tmp = indexFlowDerivative(vel, f, outloc, DIFF_DEFAULT, region); + tmp += indexStandardDerivative(vel, outloc, DIFF_DEFAULT, region) * interp_to(f, tmp.getLocation()); + return tmp; + } + // Check that the mesh is correct ASSERT1(this == f.getMesh()); ASSERT1(this == vel.getMesh()); From 181e7e96709e5eba38239c2ef5ef34b85f874703 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 13 Nov 2018 09:01:18 +0000 Subject: [PATCH 0248/1783] Move __thefunc__ into msg_stack --- include/bout_types.hxx | 11 ----------- include/msg_stack.hxx | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 6c2c1e4cdd..0553159867 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -27,17 +27,6 @@ #include #include -/// The __PRETTY_FUNCTION__ variable is defined by GCC (and some other families) but is not a part -/// of the standard. The __func__ variable *is* a part of the c++11 standard so we'd like to fall back -/// to this if possible. However as these are variables/constants and not macros we can't just -/// check if __PRETTY_FUNCITON__ is defined or not. Instead we need to say if we support this -/// or not by defining HAS_PRETTY_FUNCTION (to be implemented in configure) -#ifdef HAS_PRETTY_FUNCTION -#define __thefunc__ __PRETTY_FUNCTION__ -#else -#define __thefunc__ __func__ -#endif - /// Size of real numbers typedef double BoutReal; diff --git a/include/msg_stack.hxx b/include/msg_stack.hxx index 61a3d15642..7d8fa7e262 100644 --- a/include/msg_stack.hxx +++ b/include/msg_stack.hxx @@ -39,6 +39,17 @@ class MsgStack; /// The maximum length (in chars) of messages, not including terminating '0' #define MSG_MAX_SIZE 127 +/// The __PRETTY_FUNCTION__ variable is defined by GCC (and some other families) but is not a part +/// of the standard. The __func__ variable *is* a part of the c++11 standard so we'd like to fall back +/// to this if possible. However as these are variables/constants and not macros we can't just +/// check if __PRETTY_FUNCITON__ is defined or not. Instead we need to say if we support this +/// or not by defining HAS_PRETTY_FUNCTION (to be implemented in configure) +#ifdef HAS_PRETTY_FUNCTION +#define __thefunc__ __PRETTY_FUNCTION__ +#else +#define __thefunc__ __func__ +#endif + /*! * Message stack * From cb546a66767eeb558b03ec6ac30b19a557c7fb28 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 13 Nov 2018 09:41:03 +0000 Subject: [PATCH 0249/1783] Starting to update documentation --- .../user_docs/differential_operators.rst | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/manual/sphinx/user_docs/differential_operators.rst b/manual/sphinx/user_docs/differential_operators.rst index 90f587ccdf..e1ef52da11 100644 --- a/manual/sphinx/user_docs/differential_operators.rst +++ b/manual/sphinx/user_docs/differential_operators.rst @@ -35,6 +35,8 @@ categories: - ``C4``: 4\ :math:`^{th}` order :math:`(-f_{-2} + 16f_{-1} - 30f_0 + 16f_1 - f_2)/12` + - ``S2``: 2\ :math:`^{nd}` order smoothing derivative + - ``W2``: 2\ :math:`^{nd}` order CWENO - ``W3``: 3\ :math:`^{rd}` order CWENO @@ -46,25 +48,34 @@ categories: - ``U1``: 1\ :math:`^{st}` order upwinding + - ``U2``: 2\ :math:`^{nd}` order upwinding + + - ``U3``: 3\ :math:`^{rd}` order upwinding + - ``U4``: 4\ :math:`^{th}` order upwinding + - ``C2``: 2\ :math:`^{nd}` order central + + - ``C4``: 4\ :math:`^{th}` order central + - ``W3``: 3\ :math:`^{rd}` order `Weighted Essentially Non-Oscillatory (WENO)`_ - Flux conserving and limiting methods for terms of the form :math:`\frac{d}{dx}(v_x f)` + - ``U1``: 1\ :math:`^{st}` order upwinding + + - ``C2``: 2\ :math:`^{nd}` order central + + - ``C4``: 4\ :math:`^{th}` order central + - ``SPLIT``: split into upwind and central terms :math:`\frac{d}{dx}(v_x f) = v_x\frac{df}{dx} + f\frac{dv_x}{dx}` - - ``NND``: `Non-oscillatory, containing No free parameters and - Dissipative (NND) scheme`_ - .. _Weighted Essentially Non-Oscillatory (WENO): https://doi.org/10.1137/S106482759732455X -.. _Non-oscillatory, containing No free parameters and Dissipative (NND) scheme: https://doi.org/10.1088/0253-6102/54/6/28 - -Both of these methods avoid overshoots (Gibbs phenomena) at sharp +WENO methods avoid overshoots (Gibbs phenomena) at sharp gradients such as shocks, but the simple 1st-order method has very large artificial diffusion. WENO schemes are a development of the ENO reconstruction schemes which combine good handling of sharp-gradient @@ -93,11 +104,11 @@ top of your physics module:: +--------------+-----------------------------------------------+ | D2DZ2(f) | :math:`\partial^2 f / \partial z^2` | +--------------+-----------------------------------------------+ - | D2DX4(f) | :math:`\partial^4 f / \partial x^4` | + | D4DX4(f) | :math:`\partial^4 f / \partial x^4` | +--------------+-----------------------------------------------+ - | D2DY4(f) | :math:`\partial^4 f / \partial y^4` | + | D4DY4(f) | :math:`\partial^4 f / \partial y^4` | +--------------+-----------------------------------------------+ - | D2DZ4(f) | :math:`\partial^4 f / \partial z^4` | + | D4DZ4(f) | :math:`\partial^4 f / \partial z^4` | +--------------+-----------------------------------------------+ | D2DXDZ(f) | :math:`\partial^2 f / \partial x\partial z` | +--------------+-----------------------------------------------+ @@ -514,6 +525,8 @@ method for every index. Derivative internals -------------------- +FOLLOWING NOW OUT OF DATE + This is probably the part of the code most people will want to alter, and is in ``bout++/src/sys/derivs.cxx``. The main task of this module is to map functions on fields like ``DDX`` to direction-independent From 3c584c77609a68026f0193670a3784fe31baf106 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 13 Nov 2018 09:51:21 +0000 Subject: [PATCH 0250/1783] Make derivative kernels private --- include/bout/mesh.hxx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 6a242c6db5..551ab9a89f 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -482,10 +482,6 @@ class Mesh { ////// STANDARD OPERATORS - /// The main kernel used for all standard derivatives - template - T indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const; - ////////////// X DERIVATIVE ///////////////// template T indexDDX(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { @@ -558,10 +554,6 @@ class Mesh { ////// ADVECTION AND FLUX OPERATORS - /// The main kernel used for all upwind and flux derivatives - template - T indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const; - /// Advection operator in index space in [] direction /// /// \f[ @@ -755,6 +747,15 @@ class Mesh { void derivs_init(Options* options); private: + + /// The main kernel used for all standard derivatives + template + T indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const; + + /// The main kernel used for all upwind and flux derivatives + template + T indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const; + /// Allocates default Coordinates objects std::shared_ptr createDefaultCoordinates(const CELL_LOC location); From fb2eaeb8c5df800cd9bd385e2bc39c4f584d5d0e Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 13 Nov 2018 16:23:03 +0000 Subject: [PATCH 0251/1783] Replace DIFF_METHOD with std::string in many derivative signatures Provides overload that takes DIFF_METHOD, converts to string and passes the string on. This is required in order to support user defined and registered derivative methods as we cannot extend enums. --- include/bout/coordinates.hxx | 67 +++- include/bout/mesh.hxx | 54 +-- include/derivs.hxx | 321 ++++++++++++++---- include/derivs.hxx.in.jinja | 16 - include/derivs.hxx.in.py | 203 ----------- include/makefile | 10 - src/mesh/coordinates.cxx | 22 +- src/mesh/interpolation/hermite_spline.cxx | 6 +- .../monotonic_hermite_spline.cxx | 6 +- src/sys/derivs.cxx | 88 ++--- 10 files changed, 392 insertions(+), 401 deletions(-) delete mode 100644 include/derivs.hxx.in.jinja delete mode 100755 include/derivs.hxx.in.py delete mode 100644 include/makefile diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index e649cdfcc7..f8a1d8c2c8 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -101,30 +101,75 @@ public: // Operators const Field2D DDX(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); + const Field2D DDX(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, + REGION region = RGN_NOBNDRY){ + return DDX(f, outloc, DIFF_METHOD_STRING(method), region); + }; + const Field2D DDY(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); + const Field2D DDY(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, + REGION region = RGN_NOBNDRY){ + return DDY(f, outloc, DIFF_METHOD_STRING(method), region); + }; + const Field2D DDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); + const Field2D DDZ(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, + REGION region = RGN_NOBNDRY){ + return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); + }; /// Gradient along magnetic field b.Grad(f) - const Field2D Grad_par(const Field2D &var, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); - const Field3D Grad_par(const Field3D &var, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); + const Field2D Grad_par(const Field2D &var, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); + const Field2D Grad_par(const Field2D &var, CELL_LOC outloc, DIFF_METHOD method){ + return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); + }; + + const Field3D Grad_par(const Field3D &var, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); + const Field3D Grad_par(const Field3D &var, CELL_LOC outloc, DIFF_METHOD method){ + return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); + }; /// Advection along magnetic field V*b.Grad(f) - const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); - const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); + const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); + const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, CELL_LOC outloc, DIFF_METHOD method){ + return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); + }; + + const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); + const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method){ + return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); + }; /// Divergence along magnetic field Div(b*f) = B.Grad(f/B) - const Field2D Div_par(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); - const Field3D Div_par(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); + const Field2D Div_par(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); + const Field2D Div_par(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method){ + return Div_par(f, outloc, DIFF_METHOD_STRING(method)); + }; + + const Field3D Div_par(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); + const Field3D Div_par(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method){ + return Div_par(f, outloc, DIFF_METHOD_STRING(method)); + }; // Second derivative along magnetic field - const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); - const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); + const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); + const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method){ + return Grad2_par2(f, outloc, DIFF_METHOD_STRING(method)); + }; + + const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); + const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method){ + return Grad2_par2(f, outloc, DIFF_METHOD_STRING(method)); + }; // Perpendicular Laplacian operator, using only X-Z derivatives // NOTE: This might be better bundled with the Laplacian inversion code diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 551ab9a89f..731f54d727 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -484,24 +484,24 @@ class Mesh { ////////////// X DERIVATIVE ///////////////// template - T indexDDX(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexDDX(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexStandardDerivative(f, outloc, method, region); } template - T indexD2DX2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexD2DX2(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexStandardDerivative(f, outloc, method, region); } template - T indexD4DX4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexD4DX4(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexStandardDerivative(f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// template - T indexDDY(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexDDY(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { if (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))) { return indexStandardDerivative(f, outloc, method, region); @@ -513,7 +513,7 @@ class Mesh { } template - T indexD2DY2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexD2DY2(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { if (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))) { return indexStandardDerivative(f, outloc, method, region); @@ -525,7 +525,7 @@ class Mesh { } template - T indexD4DY4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexD4DY4(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { if (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))) { return indexStandardDerivative(f, outloc, method, region); @@ -538,17 +538,17 @@ class Mesh { ////////////// Z DERIVATIVE ///////////////// template - T indexDDZ(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexDDZ(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexStandardDerivative(f, outloc, method, region); } template - T indexD2DZ2(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexD2DZ2(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexStandardDerivative(f, outloc, method, region); } template - T indexD4DZ4(const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexD4DZ4(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexStandardDerivative(f, outloc, method, region); } @@ -569,19 +569,19 @@ class Mesh { ////////////// X DERIVATIVE ///////////////// template - T indexVDDX(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexVDDX(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexFlowDerivative(vel, f, outloc, method, region); } template - T indexFDDX(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexFDDX(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexFlowDerivative(vel, f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// template - T indexVDDY(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexVDDY(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); if (fHasParallelSlices && velHasParallelSlices) { @@ -595,7 +595,7 @@ class Mesh { } template - T indexFDDY(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexFDDY(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); if (fHasParallelSlices && velHasParallelSlices) { @@ -611,12 +611,12 @@ class Mesh { ////////////// Z DERIVATIVE ///////////////// template - T indexVDDZ(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexVDDZ(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexFlowDerivative(vel, f, outloc, method, region); } template - T indexFDDZ(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY) const { + T indexFDDZ(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexFlowDerivative(vel, f, outloc, method, region); } @@ -750,11 +750,11 @@ private: /// The main kernel used for all standard derivatives template - T indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const; + T indexStandardDerivative(const T &f, CELL_LOC outloc, const std::string &method, REGION region) const; /// The main kernel used for all upwind and flux derivatives template - T indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const; + T indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, const std::string &method, REGION region) const; /// Allocates default Coordinates objects std::shared_ptr createDefaultCoordinates(const CELL_LOC location); @@ -767,7 +767,7 @@ private: }; template -T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { +T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, const std::string &method, REGION region) const { TRACE("%s", __thefunc__); // Checks @@ -775,11 +775,11 @@ T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METH "indexDDX only works on Field2D or Field3D input"); // Special handling for SPLIT method - if ((derivType == DERIV::Flux) && (method == DIFF_SPLIT)) { + if ((derivType == DERIV::Flux) && (method == DIFF_METHOD_STRING(DIFF_SPLIT))) { // Split into an upwind and a central differencing part // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) - auto tmp = indexFlowDerivative(vel, f, outloc, DIFF_DEFAULT, region); - tmp += indexStandardDerivative(vel, outloc, DIFF_DEFAULT, region) * interp_to(f, tmp.getLocation()); + auto tmp = indexFlowDerivative(vel, f, outloc, "DEFAULT", region); + tmp += indexStandardDerivative(vel, outloc, "DEFAULT", region) * interp_to(f, tmp.getLocation()); return tmp; } @@ -820,9 +820,9 @@ T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METH auto& derivativeStore = DerivativeStore::getInstance(); typename DerivativeStore::upwindFunc derivativeMethod; if (derivType == DERIV::Upwind) { - derivativeMethod = derivativeStore.getUpwindDerivative(DIFF_METHOD_STRING(method), direction, stagger); + derivativeMethod = derivativeStore.getUpwindDerivative(method, direction, stagger); } else if (derivType == DERIV::Flux) { - derivativeMethod = derivativeStore.getFluxDerivative(DIFF_METHOD_STRING(method), direction, stagger); + derivativeMethod = derivativeStore.getFluxDerivative(method, direction, stagger); } else { throw BoutException("Invalid derivative type in call to indexFlowDerivative."); } @@ -845,7 +845,7 @@ T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, DIFF_METH } template -T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) const { +T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, const std::string &method, REGION region) const { TRACE("%s", __thefunc__); // Checks @@ -885,11 +885,11 @@ T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, DIFF_METHOD method, typename DerivativeStore::standardFunc derivativeMethod; if (order == 1) { - derivativeMethod = derivativeStore.getStandardDerivative(DIFF_METHOD_STRING(method), direction, stagger); + derivativeMethod = derivativeStore.getStandardDerivative(method, direction, stagger); } else if (order == 2) { - derivativeMethod = derivativeStore.getStandard2ndDerivative(DIFF_METHOD_STRING(method), direction, stagger); + derivativeMethod = derivativeStore.getStandard2ndDerivative(method, direction, stagger); } else if (order == 4) { - derivativeMethod = derivativeStore.getStandard4thDerivative(DIFF_METHOD_STRING(method), direction, stagger); + derivativeMethod = derivativeStore.getStandard4thDerivative(method, direction, stagger); } else { throw BoutException("Invalid order used in indexStandardDerivative."); } diff --git a/include/derivs.hxx b/include/derivs.hxx index a0060e71d6..569beeb504 100644 --- a/include/derivs.hxx +++ b/include/derivs.hxx @@ -56,7 +56,11 @@ /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D DDX(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D DDX(const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { + return DDX(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate first partial derivative in X /// @@ -71,7 +75,11 @@ const Field3D DDX(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D DDX(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D DDX(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return DDX(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate first partial derivative in Y /// @@ -86,7 +94,11 @@ const Field2D DDX(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D DDY(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D DDY(const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return DDY(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate first partial derivative in Y /// @@ -101,7 +113,11 @@ const Field3D DDY(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D DDY(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D DDY(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return DDY(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate first partial derivative in Z /// @@ -116,7 +132,11 @@ const Field2D DDY(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D DDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D DDZ(const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate first partial derivative in Z /// @@ -131,7 +151,52 @@ const Field3D DDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D DDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D DDZ(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); +}; + + +/// Calculate first partial derivative in Z +/// +/// \f$\partial / \partial z\f$ +/// +/// @param[in] f The field to be differentiated +/// @param[in] outloc The cell location where the result is desired. If +/// staggered grids is not enabled then this has no effect +/// If not given, defaults to CELL_DEFAULT +/// @param[in] method Differencing method to use. This overrides the default +/// If not given, defaults to DIFF_DEFAULT +/// @param[in] region What region is expected to be calculated +/// If not given, defaults to RGN_NOBNDRY +const Vector3D DDZ(const Vector3D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Vector3D DDZ(const Vector3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); +}; + + +/// Calculate first partial derivative in Z +/// +/// \f$\partial / \partial z\f$ +/// +/// @param[in] f The field to be differentiated +/// @param[in] outloc The cell location where the result is desired. If +/// staggered grids is not enabled then this has no effect +/// If not given, defaults to CELL_DEFAULT +/// @param[in] method Differencing method to use. This overrides the default +/// If not given, defaults to DIFF_DEFAULT +/// @param[in] region What region is expected to be calculated +/// If not given, defaults to RGN_NOBNDRY +const Vector2D DDZ(const Vector2D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Vector2D DDZ(const Vector2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); +}; + ////////// SECOND DERIVATIVES ////////// /// Calculate second partial derivative in X @@ -147,7 +212,11 @@ const Field2D DDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D D2DX2(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D2DX2(const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D2DX2(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate second partial derivative in X /// @@ -162,7 +231,11 @@ const Field3D D2DX2(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D D2DX2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D2DX2(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D2DX2(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate second partial derivative in Y /// @@ -177,7 +250,11 @@ const Field2D D2DX2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D D2DY2(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D2DY2(const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D2DY2(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate second partial derivative in Y /// @@ -192,7 +269,11 @@ const Field3D D2DY2(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D D2DY2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D2DY2(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D2DY2(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate second partial derivative in Z /// @@ -207,7 +288,11 @@ const Field2D D2DY2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D2DZ2(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate second partial derivative in Z /// @@ -222,7 +307,11 @@ const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D D2DZ2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D2DZ2(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D2DZ2(f, outloc, DIFF_METHOD_STRING(method), region); +}; ////////// FOURTH DERIVATIVES ////////// @@ -239,7 +328,11 @@ const Field2D D2DZ2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D D4DX4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D4DX4(const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D4DX4(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate forth partial derivative in X /// @@ -254,7 +347,11 @@ const Field3D D4DX4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D D4DX4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D4DX4(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D4DX4(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate forth partial derivative in Y /// @@ -269,7 +366,11 @@ const Field2D D4DX4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D D4DY4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D4DY4(const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D4DY4(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate forth partial derivative in Y /// @@ -284,7 +385,11 @@ const Field3D D4DY4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D D4DY4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D4DY4(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D4DY4(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate forth partial derivative in Z /// @@ -299,7 +404,11 @@ const Field2D D4DY4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D D4DZ4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D4DZ4(const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D4DZ4(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate forth partial derivative in Z /// @@ -314,7 +423,11 @@ const Field3D D4DZ4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D4DZ4(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// For terms of form v * grad(f) /// @@ -330,7 +443,11 @@ const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return VDDX(v, f, outloc, DIFF_METHOD_STRING(method), region); +}; /// For terms of form v * grad(f) /// @@ -346,7 +463,11 @@ const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DE /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return VDDX(v, f, outloc, DIFF_METHOD_STRING(method), region); +}; /// For terms of form v * grad(f) /// @@ -362,7 +483,11 @@ const Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DE /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return VDDY(v, f, outloc, DIFF_METHOD_STRING(method), region); +}; /// For terms of form v * grad(f) /// @@ -378,7 +503,11 @@ const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DE /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return VDDY(v, f, outloc, DIFF_METHOD_STRING(method), region); +}; /// For terms of form v * grad(f) /// @@ -394,7 +523,11 @@ const Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DE /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return VDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); +}; /// For terms of form v * grad(f) /// @@ -410,11 +543,16 @@ const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DE /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D VDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D VDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return VDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); +}; -/// for terms of form div(v * f) + +/// For terms of form v * grad(f) /// -/// \f$\partial (v f) / \partial x\f$ +/// \f$v \cdot \partial f / \partial z\f$ /// /// @param[in] v The velocity field /// @param[in] f The field of the advected quantity @@ -425,8 +563,12 @@ const Field2D VDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DE /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); +const Field2D VDDZ(const Field3D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D VDDZ(const Field3D &v, const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return VDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); +}; /// for terms of form div(v * f) /// @@ -441,12 +583,16 @@ const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DE /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); +const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return FDDX(v, f, outloc, DIFF_METHOD_STRING(method), region); +}; /// for terms of form div(v * f) /// -/// \f$\partial (v f) / \partial y\f$ +/// \f$\partial (v f) / \partial x\f$ /// /// @param[in] v The velocity field /// @param[in] f The field of the advected quantity @@ -457,8 +603,12 @@ const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DE /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); +const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return FDDX(v, f, outloc, DIFF_METHOD_STRING(method), region); +}; /// for terms of form div(v * f) /// @@ -473,12 +623,16 @@ const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DE /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); +const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return FDDY(v, f, outloc, DIFF_METHOD_STRING(method), region); +}; /// for terms of form div(v * f) /// -/// \f$\partial (v f) / \partial z\f$ +/// \f$\partial (v f) / \partial y\f$ /// /// @param[in] v The velocity field /// @param[in] f The field of the advected quantity @@ -489,8 +643,12 @@ const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DE /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); +const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return FDDY(v, f, outloc, DIFF_METHOD_STRING(method), region); +}; /// for terms of form div(v * f) /// @@ -505,14 +663,19 @@ const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DE /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D FDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); +const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return FDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); +}; -/// Calculate first partial derivative in Z +/// for terms of form div(v * f) /// -/// \f$\partial / \partial z\f$ +/// \f$\partial (v f) / \partial z\f$ /// -/// @param[in] f The field to be differentiated +/// @param[in] v The velocity field +/// @param[in] f The field of the advected quantity /// @param[in] outloc The cell location where the result is desired. If /// staggered grids is not enabled then this has no effect /// If not given, defaults to CELL_DEFAULT @@ -520,8 +683,12 @@ const Field2D FDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DE /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Vector3D DDZ(const Vector3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); +const Field2D FDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D FDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return FDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate mixed partial derivative in x and y /// @@ -535,8 +702,12 @@ const Vector3D DDZ(const Vector3D &f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); +const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D2DXDY(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate mixed partial derivative in x and y /// @@ -550,8 +721,12 @@ const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); +const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D2DXDY(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate mixed partial derivative in x and z /// @@ -565,8 +740,12 @@ const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); +const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D2DXDZ(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate mixed partial derivative in x and z /// @@ -580,8 +759,12 @@ const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); +const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D2DXDZ(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate mixed partial derivative in y and z /// @@ -595,8 +778,12 @@ const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); +const Field3D D2DYDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D2DYDZ(const Field3D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D2DYDZ(f, outloc, DIFF_METHOD_STRING(method), region); +}; /// Calculate mixed partial derivative in y and z /// @@ -610,24 +797,12 @@ const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DYDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); - -/// For terms of form v * grad(f) -/// -/// \f$v \cdot \partial f / \partial z\f$ -/// -/// @param[in] v The velocity field -/// @param[in] f The field of the advected quantity -/// @param[in] outloc The cell location where the result is desired. If -/// staggered grids is not enabled then this has no effect -/// If not given, defaults to CELL_DEFAULT -/// @param[in] method Differencing method to use. This overrides the default -/// If not given, defaults to DIFF_DEFAULT -/// @param[in] region What region is expected to be calculated -/// If not given, defaults to RGN_NOBNDRY -const Field2D VDDZ(const Field3D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, REGION region = RGN_NOBNDRY); +const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, + const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY){ + return D2DYDZ(f, outloc, DIFF_METHOD_STRING(method), region); +}; // Deprecated methods // diff --git a/include/derivs.hxx.in.jinja b/include/derivs.hxx.in.jinja deleted file mode 100644 index 9d26e638a5..0000000000 --- a/include/derivs.hxx.in.jinja +++ /dev/null @@ -1,16 +0,0 @@ - -/// {{desc}} -/// -/// \f${{latex}}\f$ -/// -{{in_field_desc}} -/// @param[in] outloc The cell location where the result is desired. If -/// staggered grids is not enabled then this has no effect -/// If not given, defaults to CELL_DEFAULT -/// @param[in] method Differencing method to use. This overrides the default -/// If not given, defaults to DIFF_DEFAULT -/// @param[in] region What region is expected to be calculated -/// If not given, defaults to RGN_NOBNDRY -const {{field}} {{DD}}({{in_sig}}, CELL_LOC outloc = CELL_DEFAULT, - DIFF_METHOD method = DIFF_DEFAULT, - REGION region = RGN_NOBNDRY); diff --git a/include/derivs.hxx.in.py b/include/derivs.hxx.in.py deleted file mode 100755 index ee344c912d..0000000000 --- a/include/derivs.hxx.in.py +++ /dev/null @@ -1,203 +0,0 @@ -#!/usr/bin/python3 -""" Code generator for derivs.hxx - -""" - -import jinja2 - - -file_header="""\ -/*!************************************************************************ - * \\file derivs.hxx - * - * Basic differential functions - * - ************************************************************************** - * Copyright 2010,2017 - * B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu, D. Schwörer - * - * Contact: Ben Dudson, bd512@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - **************************************************************************/ - -#ifndef __DERIVS_H__ -#define __DERIVS_H__ - -#include "field3d.hxx" -#include "field2d.hxx" -#include "vector3d.hxx" -#include "vector2d.hxx" - -#include "bout_types.hxx" - -// Feel free to edit this file (derivs.hxx) rather then the generating -// files. If this is easier then changing derivx.hxx.in.py or -// derivs.hxx.in.jinja do so, but please remove the derivs.hxx.in.* -// files to make clear the file is not auto-generated anymore. -""" - - -class Function(object): - def __init__(self,name,flux=None,desc=None,latex=None): - if flux is not None: - self.name=name - self.flux=flux - self.desc=desc - self.latex=latex - else: - # Copy constructor - self.name=name.name - self.flux=name.flux - self.desc=name.desc - self.latex=name.latex - if flux: - self.in_field_desc = "/// @param[in] v The velocity field\n" - self.in_field_desc+= "/// @param[in] f The field of the advected quantity" - else: - self.in_field_desc = "/// @param[in] f The field to be differentiated" - if flux: - self.in_sig="const $f &v, const $f &f" - self.in_field="v, f" - else: - self.in_sig="const $f &f" - self.in_field="f" - def set(self,d,field): - copy=Function(self.name.replace('d',d), - self.flux, - self.desc.replace('$d',d), - self.latex.replace('$d_lower',d.lower())) - copy.in_sig=self.in_sig.replace('$f',field) - copy.field=field - copy.d=d - return copy - def render(self): - args=vars(self) - args['DD']=self.name - global function_template - print(function_template.render(**args)) - -env = jinja2.Environment(loader=jinja2.FileSystemLoader('.'), - trim_blocks=True) - -function_template = env.get_template("derivs.hxx.in.jinja") - -first=Function('DDd',False, - desc="Calculate first partial derivative in $d", - latex="\partial / \partial $d_lower") -second=Function('D2Dd2',False, - desc="Calculate second partial derivative in $d", - latex="\partial^2 / \partial $d_lower^2") -upwind=Function('VDDd',True, - desc="For terms of form v * grad(f)", - latex="v \cdot \partial f / \partial $d_lower") -funcs=[first, - second, - Function('D4Dd4',False, - desc="Calculate forth partial derivative in $d", - latex="\partial^4 / \partial $d_lower^4"), - upwind, - Function('FDDd',True, - desc="for terms of form div(v * f)", - latex="\partial (v f) / \partial $d_lower")] - -deprecated_methods=""" -// Deprecated methods -// -// Calculate first partial derivative in Z -// -// \f$\partial / \partial z\f$ -// -// @param[in] f The field to be differentiated -// @param[in] outloc The cell location where the result is desired. -// If staggered grids is not enabled then this has no effect -// @param[in] method Differencing method to use. This overrides the default -// @param[in] inc_xbndry DEPRECATED: use REGION flags -// Determines whether the derivative should be calculated in -// the X boundaries. This allows mixed operators (e.g. -// D2DXDZ) without additional communication - - -inline const Field3D DDZ(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, bool inc_xbndry) { - return DDZ(f, outloc, method, inc_xbndry ? RGN_NOY : RGN_NOBNDRY); -} - -inline const Field3D DDZ(const Field3D &f, DIFF_METHOD method, CELL_LOC outloc, bool inc_xbndry) { - return DDZ(f, outloc, method, inc_xbndry ? RGN_NOY : RGN_NOBNDRY); -} - -inline const Field3D DDZ(const Field3D &f, DIFF_METHOD method, bool inc_xbndry) { - return DDZ(f, CELL_DEFAULT, method, inc_xbndry ? RGN_NOY : RGN_NOBNDRY); -} - -inline const Field3D DDZ(const Field3D &f, bool inc_xbndry) { - return DDZ(f, CELL_DEFAULT, DIFF_DEFAULT, inc_xbndry ? RGN_NOY : RGN_NOBNDRY); -} - -""" - -end_of_file="#endif // __DERIVS_H__" - -if __name__ == "__main__": - print(file_header) - - # Generate normal derivatives for Field3D and Field2D for the - # various directions - for fun in funcs: - if fun.name == 'DDd': - print("////////// FIRST DERIVATIVES //////////") - elif fun.name == 'D2Dd2': - print("////////// SECOND DERIVATIVES //////////") - elif fun.name == 'D4Dd4': - print("////////// FORTH DERIVATIVES //////////") - elif fun.name == 'VDDd': - print("///////// UPWINDING METHODS /////////////") - elif fun.name == 'FDDd': - print("///////// FLUX METHODS /////////////") - else: - print("Unhandeled case") - exit(1) - for d in ['X', 'Y', 'Z']: - for field in ['Field3D', 'Field2D']: - # get copy - fun.set(d,field).render() - - - # Generate header file for the Z derivative of Vector 3D - first.set('Z',"Vector3D").render() - - # Generate the mixed derivative - x='x' - y='y' - z='z' - for DD in [[x,y],[x,z],[y,z]]: - for field in ['Field2D', 'Field3D']: - cur=second.set('error',field) - cur.name="D2D%sD%s"%(DD[0].upper(),DD[1].upper()) - cur.desc="Calculate mixed partial derivative in %s and %s"%(DD[0],DD[1]) - cur.latex="\partial^2 / \partial %s \partial %s"%(DD[0],DD[1]) - cur.render() - - # Generate a case of mixed Field2D and Field3D for Z upwinding - # scheeme - cur=upwind.set('Z','Field2D') - cur.in_sig="const Field3D &v, const Field2D &f" - cur.render() - - print(deprecated_methods) - - print(end_of_file) diff --git a/include/makefile b/include/makefile deleted file mode 100644 index 93dee43780..0000000000 --- a/include/makefile +++ /dev/null @@ -1,10 +0,0 @@ -all: derivs.hxx - - -derivs.hxx: derivs.hxx.in.py derivs.hxx.in.jinja -# run first dependency and write output to target -# on failure delete output and report error - @echo " Generating $@" - @./$< > $@.tmp || (fail=$$?; echo "touch $@ to ignore failed generation" ; exit $$fail) - @mv $@.tmp $@ - @clang-format -i $@ || echo "Formatting failed" diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 81c0e921e4..d59ea2dc5f 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -623,18 +623,18 @@ int Coordinates::jacobian() { * *******************************************************************************/ -const Field2D Coordinates::DDX(const Field2D &f, CELL_LOC loc, DIFF_METHOD method, REGION region) { +const Field2D Coordinates::DDX(const Field2D &f, CELL_LOC loc, const std::string &method, REGION region) { ASSERT1(location == loc || loc == CELL_DEFAULT); return localmesh->indexDDX(f, loc, method, region) / dx; } -const Field2D Coordinates::DDY(const Field2D &f, CELL_LOC loc, DIFF_METHOD method, REGION region) { +const Field2D Coordinates::DDY(const Field2D &f, CELL_LOC loc, const std::string &method, REGION region) { ASSERT1(location == loc || loc == CELL_DEFAULT); return localmesh->indexDDY(f, loc, method, region) / dy; } const Field2D Coordinates::DDZ(const Field2D &f, CELL_LOC loc, - DIFF_METHOD UNUSED(method), REGION UNUSED(region)) { + const std::string &UNUSED(method), REGION UNUSED(region)) { ASSERT1(location == loc || loc == CELL_DEFAULT); ASSERT1(f.getMesh() == localmesh); auto result = Field2D(0.0, localmesh); @@ -648,7 +648,7 @@ const Field2D Coordinates::DDZ(const Field2D &f, CELL_LOC loc, // Parallel gradient const Field2D Coordinates::Grad_par(const Field2D &var, CELL_LOC outloc, - DIFF_METHOD UNUSED(method)) { + const std::string &UNUSED(method)) { TRACE("Coordinates::Grad_par( Field2D )"); ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == var.getLocation())); @@ -656,7 +656,7 @@ const Field2D Coordinates::Grad_par(const Field2D &var, CELL_LOC outloc, } const Field3D Coordinates::Grad_par(const Field3D &var, CELL_LOC outloc, - DIFF_METHOD method) { + const std::string &method) { TRACE("Coordinates::Grad_par( Field3D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); @@ -669,13 +669,13 @@ const Field3D Coordinates::Grad_par(const Field3D &var, CELL_LOC outloc, const Field2D Coordinates::Vpar_Grad_par(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD UNUSED(method)) { + const std::string &UNUSED(method)) { ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == f.getLocation())); return VDDY(v, f) / sqrt(g_22); } const Field3D Coordinates::Vpar_Grad_par(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method) { + const std::string &method) { ASSERT1(location == outloc || outloc == CELL_DEFAULT); return VDDY(v, f, outloc, method) / sqrt(g_22); } @@ -684,7 +684,7 @@ const Field3D Coordinates::Vpar_Grad_par(const Field3D &v, const Field3D &f, CEL // Parallel divergence const Field2D Coordinates::Div_par(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method) { + const std::string &method) { TRACE("Coordinates::Div_par( Field2D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); @@ -696,7 +696,7 @@ const Field2D Coordinates::Div_par(const Field2D &f, CELL_LOC outloc, } const Field3D Coordinates::Div_par(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method) { + const std::string &method) { TRACE("Coordinates::Div_par( Field3D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); @@ -728,7 +728,7 @@ const Field3D Coordinates::Div_par(const Field3D &f, CELL_LOC outloc, // second parallel derivative (b dot Grad)(b dot Grad) // Note: For parallel Laplacian use Laplace_par -const Field2D Coordinates::Grad2_par2(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method) { +const Field2D Coordinates::Grad2_par2(const Field2D &f, CELL_LOC outloc, const std::string &method) { TRACE("Coordinates::Grad2_par2( Field2D )"); ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == f.getLocation())); @@ -738,7 +738,7 @@ const Field2D Coordinates::Grad2_par2(const Field2D &f, CELL_LOC outloc, DIFF_ME return result; } -const Field3D Coordinates::Grad2_par2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method) { +const Field3D Coordinates::Grad2_par2(const Field3D &f, CELL_LOC outloc, const std::string &method) { TRACE("Coordinates::Grad2_par2( Field3D )"); if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); diff --git a/src/mesh/interpolation/hermite_spline.cxx b/src/mesh/interpolation/hermite_spline.cxx index 41f51b2ae5..3900ca0136 100644 --- a/src/mesh/interpolation/hermite_spline.cxx +++ b/src/mesh/interpolation/hermite_spline.cxx @@ -113,11 +113,11 @@ Field3D HermiteSpline::interpolate(const Field3D &f) const { // Derivatives are used for tension and need to be on dimensionless // coordinates - Field3D fx = localmesh->indexDDX(f, CELL_DEFAULT, DIFF_DEFAULT); + Field3D fx = localmesh->indexDDX(f, CELL_DEFAULT, "DEFAULT"); localmesh->communicateXZ(fx); - Field3D fz = localmesh->indexDDZ(f, CELL_DEFAULT, DIFF_DEFAULT, RGN_ALL); + Field3D fz = localmesh->indexDDZ(f, CELL_DEFAULT, "DEFAULT", RGN_ALL); localmesh->communicateXZ(fz); - Field3D fxz = localmesh->indexDDX(fz, CELL_DEFAULT, DIFF_DEFAULT); + Field3D fxz = localmesh->indexDDX(fz, CELL_DEFAULT, "DEFAULT"); localmesh->communicateXZ(fxz); for (int x = localmesh->xstart; x <= localmesh->xend; x++) { diff --git a/src/mesh/interpolation/monotonic_hermite_spline.cxx b/src/mesh/interpolation/monotonic_hermite_spline.cxx index e9884e5f0f..e76f2f2a69 100644 --- a/src/mesh/interpolation/monotonic_hermite_spline.cxx +++ b/src/mesh/interpolation/monotonic_hermite_spline.cxx @@ -35,11 +35,11 @@ Field3D MonotonicHermiteSpline::interpolate(const Field3D &f) const { // Derivatives are used for tension and need to be on dimensionless // coordinates - Field3D fx = localmesh->indexDDX(f, CELL_DEFAULT, DIFF_DEFAULT); + Field3D fx = localmesh->indexDDX(f, CELL_DEFAULT, "DEFAULT"); localmesh->communicateXZ(fx); - Field3D fz = localmesh->indexDDZ(f, CELL_DEFAULT, DIFF_DEFAULT, RGN_ALL); + Field3D fz = localmesh->indexDDZ(f, CELL_DEFAULT, "DEFAULT", RGN_ALL); localmesh->communicateXZ(fz); - Field3D fxz = localmesh->indexDDX(fz, CELL_DEFAULT, DIFF_DEFAULT); + Field3D fxz = localmesh->indexDDX(fz, CELL_DEFAULT, "DEFAULT"); localmesh->communicateXZ(fxz); for (int x = localmesh->xstart; x <= localmesh->xend; x++) { diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 40dc10d73c..c89cc9f819 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -59,7 +59,7 @@ ////////////// X DERIVATIVE ///////////////// -const Field3D DDX(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D DDX(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { Field3D result = f.getMesh()->indexDDX(f,outloc, method, region); Coordinates *coords = f.getCoordinates(outloc); result /= coords->dx; @@ -75,34 +75,34 @@ const Field3D DDX(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION return result; } -const Field2D DDX(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field2D DDX(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getCoordinates(outloc)->DDX(f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// -const Field3D DDY(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D DDY(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexDDY(f, outloc, method, region) / f.getCoordinates(outloc)->dy; } -const Field2D DDY(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field2D DDY(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getCoordinates(outloc)->DDY(f, outloc, method, region); } ////////////// Z DERIVATIVE ///////////////// -const Field3D DDZ(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D DDZ(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexDDZ(f, outloc, method, region) / f.getCoordinates(outloc)->dz; } -const Field2D DDZ(const Field2D &f, CELL_LOC UNUSED(outloc), DIFF_METHOD UNUSED(method), +const Field2D DDZ(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), REGION UNUSED(region)) { auto tmp = Field2D(0., f.getMesh()); tmp.setLocation(f.getLocation()); return tmp; } -const Vector3D DDZ(const Vector3D &v, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Vector3D DDZ(const Vector3D &v, CELL_LOC outloc, const std::string &method, REGION region) { Vector3D result(v.x.getMesh()); ASSERT2(v.x.getMesh()==v.y.getMesh()); @@ -130,7 +130,7 @@ const Vector3D DDZ(const Vector3D &v, CELL_LOC outloc, DIFF_METHOD method, REGIO return result; } -const Vector2D DDZ(const Vector2D &v, CELL_LOC UNUSED(outloc), DIFF_METHOD UNUSED(method), +const Vector2D DDZ(const Vector2D &v, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), REGION UNUSED(region)) { Vector2D result(v.x.getMesh()); @@ -152,14 +152,14 @@ const Vector2D DDZ(const Vector2D &v, CELL_LOC UNUSED(outloc), DIFF_METHOD UNUSE ////////////// X DERIVATIVE ///////////////// -const Field3D D2DX2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D D2DX2(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { Coordinates *coords = f.getCoordinates(outloc); Field3D result = f.getMesh()->indexD2DX2(f, outloc, method, region) / SQ(coords->dx); if(coords->non_uniform) { // Correction for non-uniform f.getMesh() - result += coords->d1_dx * f.getMesh()->indexDDX(f, outloc, DIFF_DEFAULT, region)/coords->dx; + result += coords->d1_dx * f.getMesh()->indexDDX(f, outloc, "DEFAULT", region)/coords->dx; } ASSERT2(((outloc == CELL_DEFAULT) && (result.getLocation() == f.getLocation())) || @@ -168,14 +168,14 @@ const Field3D D2DX2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGIO return result; } -const Field2D D2DX2(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field2D D2DX2(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { Coordinates *coords = f.getCoordinates(outloc); Field2D result = f.getMesh()->indexD2DX2(f, outloc, method, region) / SQ(coords->dx); if(coords->non_uniform) { // Correction for non-uniform f.getMesh() - result += coords->d1_dx * f.getMesh()->indexDDX(f, outloc, DIFF_DEFAULT, region) / coords->dx; + result += coords->d1_dx * f.getMesh()->indexDDX(f, outloc, "DEFAULT", region) / coords->dx; } return result; @@ -183,14 +183,14 @@ const Field2D D2DX2(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGIO ////////////// Y DERIVATIVE ///////////////// -const Field3D D2DY2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D D2DY2(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { Coordinates *coords = f.getCoordinates(outloc); Field3D result = f.getMesh()->indexD2DY2(f, outloc, method, region) / SQ(coords->dy); if(coords->non_uniform) { // Correction for non-uniform f.getMesh() - result += coords->d1_dy * f.getMesh()->indexDDY(f, outloc, DIFF_DEFAULT, region) / coords->dy; + result += coords->d1_dy * f.getMesh()->indexDDY(f, outloc, "DEFAULT", region) / coords->dy; } ASSERT2(((outloc == CELL_DEFAULT) && (result.getLocation() == f.getLocation())) || @@ -199,13 +199,13 @@ const Field3D D2DY2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGIO return result; } -const Field2D D2DY2(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field2D D2DY2(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { Coordinates *coords = f.getCoordinates(outloc); Field2D result = f.getMesh()->indexD2DY2(f, outloc, method, region) / SQ(coords->dy); if(coords->non_uniform) { // Correction for non-uniform f.getMesh() - result += coords->d1_dy * f.getMesh()->indexDDY(f, outloc, DIFF_DEFAULT, region) / coords->dy; + result += coords->d1_dy * f.getMesh()->indexDDY(f, outloc, "DEFAULT", region) / coords->dy; } return result; @@ -213,12 +213,12 @@ const Field2D D2DY2(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGIO ////////////// Z DERIVATIVE ///////////////// -const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexD2DZ2(f, outloc, method, region) / SQ(f.getCoordinates(outloc)->dz); } -const Field2D D2DZ2(const Field2D &f, CELL_LOC UNUSED(outloc), DIFF_METHOD UNUSED(method), +const Field2D D2DZ2(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), REGION UNUSED(region)) { auto tmp = Field2D(0., f.getMesh()); tmp.setLocation(f.getLocation()); @@ -229,32 +229,32 @@ const Field2D D2DZ2(const Field2D &f, CELL_LOC UNUSED(outloc), DIFF_METHOD UNUSE * Fourth derivatives *******************************************************************************/ -const Field3D D4DX4(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D D4DX4(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexD4DX4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dx)); } -const Field2D D4DX4(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field2D D4DX4(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexD4DX4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dx)); } -const Field3D D4DY4(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D D4DY4(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexD4DY4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dy)); } -const Field2D D4DY4(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field2D D4DY4(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexD4DY4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dy)); } -const Field3D D4DZ4(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D D4DZ4(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexD4DZ4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dz)); } -const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexD4DZ4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dz)); } @@ -270,7 +270,7 @@ const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGIO * * ** Applies Neumann boundary in Y, communicates */ -const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { Field2D dfdy = DDY(f, outloc, method, RGN_NOY); f.getMesh()->communicate(dfdy); return DDX(dfdy, outloc, method, region); @@ -283,21 +283,21 @@ const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGI * * ** Applies Neumann boundary in Y, communicates */ -const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { Field3D dfdy = DDY(f, outloc, method, RGN_NOY); f.getMesh()->communicate(dfdy); return DDX(dfdy, outloc, method, region); } const Field2D D2DXDZ(const Field2D &f, CELL_LOC UNUSED(outloc), - DIFF_METHOD UNUSED(method), REGION UNUSED(region)) { + const std::string &UNUSED(method), REGION UNUSED(region)) { auto tmp = Field2D(0., f.getMesh()); tmp.setLocation(f.getLocation()); return tmp; } /// X-Z mixed derivative -const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { // Take derivative in Z, including in X boundaries. Then take derivative in X // Maybe should average results of DDX(DDZ) and DDZ(DDX)? ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); @@ -321,20 +321,20 @@ const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGI } const Field2D D2DYDZ(const Field2D &f, CELL_LOC UNUSED(outloc), - DIFF_METHOD UNUSED(method), REGION UNUSED(region)) { + const std::string &UNUSED(method), REGION UNUSED(region)) { auto tmp = Field2D(0., f.getMesh()); tmp.setLocation(f.getLocation()); return tmp; } -const Field3D D2DYDZ(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION UNUSED(region)) { +const Field3D D2DYDZ(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION UNUSED(region)) { Coordinates *coords = f.getCoordinates(outloc); Field3D result(f.getMesh()); ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); result.allocate(); result.setLocation(f.getLocation()); - ASSERT1(method == DIFF_DEFAULT); + ASSERT1(method == "DEFAULT"); for(int i=f.getMesh()->xstart;i<=f.getMesh()->xend;i++) for(int j=f.getMesh()->ystart;j<=f.getMesh()->yend;j++) for(int k=0;kLocalNz;k++) { @@ -363,13 +363,13 @@ const Field3D D2DYDZ(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGI ////////////// X DERIVATIVE ///////////////// /// Special case where both arguments are 2D. Output location ignored for now -const Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexVDDX(v, f, outloc, method, region) / f.getCoordinates(outloc)->dx; } /// General version for 2 or 3-D objects -const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexVDDX(v, f, outloc, method, region) / f.getCoordinates(outloc)->dx; } @@ -377,13 +377,13 @@ const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_MET ////////////// Y DERIVATIVE ///////////////// // special case where both are 2D -const Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexVDDY(v, f, outloc, method, region) / f.getCoordinates(outloc)->dy; } // general case -const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexVDDY(v, f, outloc, method, region) / f.getCoordinates(outloc)->dy; } @@ -392,7 +392,7 @@ const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_MET // special case where both are 2D const Field2D VDDZ(const Field2D &v, const Field2D &UNUSED(f), CELL_LOC UNUSED(outloc), - DIFF_METHOD UNUSED(method), REGION UNUSED(region)) { + const std::string &UNUSED(method), REGION UNUSED(region)) { // Should we take location from v or f? auto tmp = Field2D(0., v.getMesh()); tmp.setLocation(v.getLocation()); @@ -401,7 +401,7 @@ const Field2D VDDZ(const Field2D &v, const Field2D &UNUSED(f), CELL_LOC UNUSED(o // Note that this is zero because no compression is included const Field2D VDDZ(const Field3D &v, const Field2D &UNUSED(f), CELL_LOC UNUSED(outloc), - DIFF_METHOD UNUSED(method), REGION UNUSED(region)) { + const std::string &UNUSED(method), REGION UNUSED(region)) { // Should we take location from v or f? auto tmp = Field2D(0., v.getMesh()); tmp.setLocation(v.getLocation()); @@ -409,7 +409,7 @@ const Field2D VDDZ(const Field3D &v, const Field2D &UNUSED(f), CELL_LOC UNUSED(o } // general case -const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexVDDZ(v, f, outloc, method, region) / f.getCoordinates(outloc)->dz; } @@ -417,24 +417,24 @@ const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_MET /******************************************************************************* * Flux conserving schemes *******************************************************************************/ -const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexFDDX(v, f, outloc, method, region) / f.getCoordinates(outloc)->dx; } -const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexFDDX(v, f, outloc, method, region) / f.getCoordinates(outloc)->dx; } ///////////////////////////////////////////////////////////////////////// -const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexFDDY(v, f, outloc, method, region) / f.getCoordinates(outloc)->dy; } -const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexFDDY(v, f, outloc, method, region) / f.getCoordinates(outloc)->dy; } @@ -442,14 +442,14 @@ const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_MET ///////////////////////////////////////////////////////////////////////// const Field2D FDDZ(const Field2D &v, const Field2D &UNUSED(f), CELL_LOC UNUSED(outloc), - DIFF_METHOD UNUSED(method), REGION UNUSED(region)) { + const std::string &UNUSED(method), REGION UNUSED(region)) { // Should we take location from v or f? auto tmp = Field2D(0., v.getMesh()); tmp.setLocation(v.getLocation()); return tmp; } -const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method, REGION region) { +const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { return f.getMesh()->indexFDDZ(v, f, outloc, method, region) / f.getCoordinates(outloc)->dz; } From 6df72021893be798eb06d568b3cff82a26c80d87 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 13 Nov 2018 17:07:52 +0000 Subject: [PATCH 0252/1783] Finishing replacing DIFF_METHOD --- include/difops.hxx | 162 +++++++++++++++++++++++-------------------- include/vecops.hxx | 13 +++- src/field/vecops.cxx | 16 ++--- src/mesh/difops.cxx | 39 ++++++----- 4 files changed, 128 insertions(+), 102 deletions(-) diff --git a/include/difops.hxx b/include/difops.hxx index 52caf84bc5..cf98c5d31c 100644 --- a/include/difops.hxx +++ b/include/difops.hxx @@ -41,6 +41,7 @@ #include "bout_types.hxx" +#include "bout/deprecated.hxx" #include "bout/solver.hxx" /*! @@ -51,10 +52,23 @@ * @param[in] outloc The cell location where the output is needed (if staggered grids is enabled) * @param[in] method The method to use. The default is set in the options. */ -const Field2D Grad_par(const Field2D &var, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); -const Field2D Grad_par(const Field2D &var, DIFF_METHOD method, CELL_LOC outloc=CELL_DEFAULT); -const Field3D Grad_par(const Field3D &var, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); -const Field3D Grad_par(const Field3D &var, DIFF_METHOD method, CELL_LOC outloc=CELL_DEFAULT); +const Field2D Grad_par(const Field2D &var, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); +DEPRECATED(const Field2D Grad_par(const Field2D &var, const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); +inline const Field2D Grad_par(const Field2D &var, CELL_LOC outloc, DIFF_METHOD method){ + return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); +}; +DEPRECATED(inline const Field2D Grad_par(const Field2D &var, DIFF_METHOD method, CELL_LOC outloc)) { + return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); +}; + +const Field3D Grad_par(const Field3D &var, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); +DEPRECATED(const Field3D Grad_par(const Field3D &var, const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); +inline const DEPRECATED(Field3D Grad_par(const Field3D &var, CELL_LOC outloc, DIFF_METHOD method)) { + return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); +}; +DEPRECATED(inline const DEPRECATED(Field3D Grad_par(const Field3D &var, DIFF_METHOD method, CELL_LOC outloc))) { + return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); +}; /*! * Derivative along perturbed magnetic field @@ -68,35 +82,6 @@ const Field3D Grad_par(const Field3D &var, DIFF_METHOD method, CELL_LOC outloc=C */ const Field3D Grad_parP(const Field3D &apar, const Field3D &f); -/*! - * vpar times parallel derivative along unperturbed B-field (upwinding) - * - * \f[ - * v\mathbf{b}_0 \cdot \nabla f - * \f] - * - * @param[in] v The velocity in y direction - * @param[in] f The scalar field to be differentiated - * - */ -const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f); - -/*! - * vpar times parallel derivative along unperturbed B-field (upwinding) - * - * \f[ - * v\mathbf{b}_0 \cdot \nabla f - * \f] - * - * @param[in] v The velocity in y direction - * @param[in] f The scalar field to be differentiated - * @param[in] outloc The cell location of the output. By default this is the same as \p f - * @param[in] method The numerical method to use. The default is set in the options - * - */ -const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, - CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); - /*! * vpar times parallel derivative along unperturbed B-field (upwinding) * @@ -110,35 +95,29 @@ const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, * @param[in] method The numerical method to use. The default is set in the options * */ -const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc=CELL_DEFAULT); - - -/*! - * parallel divergence operator - * - * \f[ - * B \partial_{||}(f/B) = B \nabla\cdot (\mathbf{b}f/B ) - * \f] - * - * @param[in] f The component of a vector along the magnetic field - * - */ -const Field2D Div_par(const Field2D &f); +const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, + CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); +DEPRECATED(const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, + const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); +inline const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, + CELL_LOC outloc, DIFF_METHOD method){ + return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); +}; +DEPRECATED(inline const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, DIFF_METHOD method, CELL_LOC outloc)) { + return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); +}; -/*! - * parallel divergence operator - * - * \f[ - * B \partial_{||}(f/B) = B \nabla\cdot (\mathbf{b}f/B ) - * \f] - * - * @param[in] f The component of a vector along the magnetic field - * @param[in] outloc The cell location for the result. By default the same as \p f - * @param[in] method The numerical method to use - * - */ -const Field3D Div_par(const Field3D &f, - CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); +const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, + CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); +DEPRECATED(const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, + const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); +inline const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, + CELL_LOC outloc, DIFF_METHOD method){ + return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); +}; +DEPRECATED(inline const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc)) { + return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); +}; /*! * parallel divergence operator @@ -152,12 +131,31 @@ const Field3D Div_par(const Field3D &f, * @param[in] method The numerical method to use * */ -const Field3D Div_par(const Field3D &f, DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT); +const Field2D Div_par(const Field2D &f, + CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); +DEPRECATED(const Field2D Div_par(const Field2D &f, + const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); +inline const Field2D Div_par(const Field2D &f, + CELL_LOC outloc, DIFF_METHOD method){ + return Div_par(f, outloc, DIFF_METHOD_STRING(method)); +}; +DEPRECATED(inline const Field2D Div_par(const Field2D &f, + DIFF_METHOD method, CELL_LOC outloc)) { + return Div_par(f, outloc, DIFF_METHOD_STRING(method)); +}; -// Flux methods. Model divergence of flux: df/dt = Div(v * f) -const Field3D Div_par_flux(const Field3D &v, const Field3D &f, - CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); -const Field3D Div_par_flux(const Field3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT); +const Field3D Div_par(const Field3D &f, + CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); +DEPRECATED(const Field3D Div_par(const Field3D &f, + const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); +inline const Field3D Div_par(const Field3D &f, + CELL_LOC outloc, DIFF_METHOD method){ + return Div_par(f, outloc, DIFF_METHOD_STRING(method)); +}; +DEPRECATED(inline const Field3D Div_par(const Field3D &f, + DIFF_METHOD method, CELL_LOC outloc)) { + return Div_par(f, outloc, DIFF_METHOD_STRING(method)); +}; // Divergence of a parallel flow: Div(f*v) // Both f and v are interpolated onto cell boundaries @@ -165,15 +163,19 @@ const Field3D Div_par_flux(const Field3D &v, const Field3D &f, DIFF_METHOD metho // to get the flux at the boundary. const Field3D Div_par(const Field3D &f, const Field3D &v); -/*! - * second parallel derivative - * \f[ - * (\mathbf{b} dot \nabla)(\mathbf{b} dot \nabla) - * \f] - * - * Note: For parallel Laplacian use LaplacePar - */ -const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); +// Flux methods. Model divergence of flux: df/dt = Div(v * f) +// TODO : Should we add Field2D versions? +const Field3D Div_par_flux(const Field3D &v, const Field3D &f, + CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); +DEPRECATED(const Field3D Div_par_flux(const Field3D &v, const Field3D &f, + const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); +inline const Field3D Div_par_flux(const Field3D &v, const Field3D &f, + CELL_LOC outloc, DIFF_METHOD method){ + return Div_par_flux(v, f, outloc, DIFF_METHOD_STRING(method)); +}; +DEPRECATED(inline const Field3D Div_par_flux(const Field3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT)) { + return Div_par_flux(v, f, outloc, DIFF_METHOD_STRING(method)); +}; /*! * second parallel derivative @@ -186,7 +188,15 @@ const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_ME * @param[in] f The field to be differentiated * @param[in] outloc The cell location of the result */ -const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, DIFF_METHOD method=DIFF_DEFAULT); +const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); +inline const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method) { + return Grad2_par2(f, outloc, DIFF_METHOD_STRING(method)); +}; + +const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); +inline const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method){ + return Grad2_par2(f, outloc, DIFF_METHOD_STRING(method)); +}; /*! * Parallel derivatives, converting between cell-centred and lower cell boundary diff --git a/include/vecops.hxx b/include/vecops.hxx index 134e76006f..57c41c93e4 100644 --- a/include/vecops.hxx +++ b/include/vecops.hxx @@ -34,6 +34,8 @@ #include "vector2d.hxx" #include "vector3d.hxx" +#include "bout/deprecated.hxx" + /// Gradient of scalar field \p f, returning a covariant vector /// /// All locations supported @@ -69,10 +71,17 @@ const Field2D Div(const Vector2D &v, CELL_LOC outloc = CELL_DEFAULT); const Field3D Div(const Vector3D &v, CELL_LOC outloc = CELL_DEFAULT); const Field2D Div(const Vector2D &v, const Field2D &f); -const Field3D Div(const Vector3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT); -const Field3D Div(const Vector3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method = DIFF_DEFAULT); const Field3D Div(const Vector3D &v, const Field3D &f); +const Field3D Div(const Vector3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method = "DEFAULT"); +DEPRECATED(const Field3D Div(const Vector3D &v, const Field3D &f, const std::string &method, CELL_LOC outloc = CELL_DEFAULT)); +inline const Field3D Div(const Vector3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method = DIFF_DEFAULT){ + return Div(v, f, outloc, DIFF_METHOD_STRING(method)); +}; +DEPRECATED(inline const Field3D Div(const Vector3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT)) { + return Div(v, f, outloc, DIFF_METHOD_STRING(method)); +}; + /// Curl of a vector /// /// Does not currently support any output locations. \p v must not be diff --git a/src/field/vecops.cxx b/src/field/vecops.cxx index 4ebb9fb7e3..9f9e8a2ae0 100644 --- a/src/field/vecops.cxx +++ b/src/field/vecops.cxx @@ -199,10 +199,15 @@ const Field2D Div(const Vector2D &v, const Field2D &f, CELL_LOC outloc) { return result; } -const Field3D Div(const Vector3D &v, const Field3D &f, DIFF_METHOD method, +const Field3D Div(const Vector3D &v, const Field3D &f, const std::string &method, CELL_LOC outloc) { - TRACE("Div( Vector3D, Field3D )"); + TRACE("Div( Vector3D, Field3D)"); + return Div(v, f, outloc, method); +} + +const Field3D Div(const Vector3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method) { + TRACE("Div( Vector3D, Field3D )"); if (outloc == CELL_DEFAULT) { outloc = v.getLocation(); } @@ -225,14 +230,9 @@ const Field3D Div(const Vector3D &v, const Field3D &f, DIFF_METHOD method, return result; } -const Field3D Div(const Vector3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method) { - TRACE("Div( Vector3D, Field3D)"); - return Div(v, f, method, outloc); -} - const Field3D Div(const Vector3D &v, const Field3D &f) { TRACE("Div( Vector3D, Field3D)"); - return Div(v, f, DIFF_DEFAULT, CELL_DEFAULT); + return Div(v, f, CELL_DEFAULT, DIFF_DEFAULT); } /************************************************************************** diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index 12c1c1771e..e9fe75e0f6 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -46,19 +46,19 @@ * The parallel derivative along unperturbed B-field *******************************************************************************/ -const Field2D Grad_par(const Field2D &var, CELL_LOC outloc, DIFF_METHOD method) { +const Field2D Grad_par(const Field2D &var, CELL_LOC outloc, const std::string &method) { return var.getCoordinates(outloc)->Grad_par(var, outloc, method); } -const Field2D Grad_par(const Field2D &var, DIFF_METHOD method, CELL_LOC outloc) { +const Field2D Grad_par(const Field2D &var, const std::string &method, CELL_LOC outloc) { return var.getCoordinates(outloc)->Grad_par(var, outloc, method); } -const Field3D Grad_par(const Field3D &var, CELL_LOC outloc, DIFF_METHOD method) { +const Field3D Grad_par(const Field3D &var, CELL_LOC outloc, const std::string &method) { return var.getCoordinates(outloc)->Grad_par(var, outloc, method); } -const Field3D Grad_par(const Field3D &var, DIFF_METHOD method, CELL_LOC outloc) { +const Field3D Grad_par(const Field3D &var, const std::string &method, CELL_LOC outloc) { return var.getCoordinates(outloc)->Grad_par(var, outloc, method); } @@ -167,15 +167,19 @@ const Field3D Grad_parP(const Field3D &apar, const Field3D &f) { * vparallel times the parallel derivative along unperturbed B-field *******************************************************************************/ -const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, CELL_LOC outloc) { - return f.getCoordinates(outloc)->Vpar_Grad_par(v, f, outloc); +const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method) { + return f.getCoordinates(outloc)->Vpar_Grad_par(v, f, outloc, method); +} + +const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, const std::string &method, CELL_LOC outloc) { + return f.getCoordinates(outloc)->Vpar_Grad_par(v, f, outloc, method); } -const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method) { +const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method) { return f.getCoordinates(outloc)->Vpar_Grad_par(v, f, outloc, method); } -const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc) { +const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, const std::string &method, CELL_LOC outloc) { return f.getCoordinates(outloc)->Vpar_Grad_par(v, f, outloc, method); } @@ -183,16 +187,19 @@ const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, DIFF_METHOD meth * Div_par * parallel divergence operator B \partial_{||} (F/B) *******************************************************************************/ +const Field2D Div_par(const Field2D &f, CELL_LOC outloc, const std::string &method) { + return f.getCoordinates(outloc)->Div_par(f, outloc, method); +} -const Field2D Div_par(const Field2D &f, CELL_LOC outloc) { - return f.getCoordinates(outloc)->Div_par(f, outloc); +const Field2D Div_par(const Field2D &f, const std::string &method, CELL_LOC outloc) { + return f.getCoordinates(outloc)->Div_par(f, outloc, method); } -const Field3D Div_par(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method) { +const Field3D Div_par(const Field3D &f, CELL_LOC outloc, const std::string &method) { return f.getCoordinates(outloc)->Div_par(f, outloc, method); } -const Field3D Div_par(const Field3D &f, DIFF_METHOD method, CELL_LOC outloc) { +const Field3D Div_par(const Field3D &f, const std::string &method, CELL_LOC outloc) { return f.getCoordinates(outloc)->Div_par(f, outloc, method); } @@ -237,7 +244,7 @@ const Field3D Div_par(const Field3D &f, const Field3D &v) { //////// Flux methods -const Field3D Div_par_flux(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method) { +const Field3D Div_par_flux(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method) { Coordinates *metric = f.getCoordinates(outloc); Field2D Bxy_floc = f.getCoordinates()->Bxy; @@ -260,7 +267,7 @@ const Field3D Div_par_flux(const Field3D &v, const Field3D &f, CELL_LOC outloc, return metric->Bxy*FDDY(v, f_B, outloc, method)/sqrt(metric->g_22); } -const Field3D Div_par_flux(const Field3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc) { +const Field3D Div_par_flux(const Field3D &v, const Field3D &f, const std::string &method, CELL_LOC outloc) { return Div_par_flux(v,f, outloc, method); } @@ -504,11 +511,11 @@ const Field3D Div_par_CtoL(const Field3D &var) { * Note: For parallel Laplacian use LaplacePar *******************************************************************************/ -const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method) { +const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc, const std::string &method) { return f.getCoordinates(outloc)->Grad2_par2(f, outloc, method); } -const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method) { +const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc, const std::string &method) { return f.getCoordinates(outloc)->Grad2_par2(f, outloc, method); } From 9d203caf0d551ed51fcfcdeea764ad4bf359c2ce Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 13 Nov 2018 22:16:45 +0000 Subject: [PATCH 0253/1783] Fix case of DIFF_DEFAULT --- include/bout_types.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 3e014d6e24..4a12502316 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -55,7 +55,7 @@ inline const std::string& CELL_LOC_STRING(CELL_LOC location) { enum DIFF_METHOD {DIFF_DEFAULT, DIFF_U1, DIFF_U2, DIFF_C2, DIFF_W2, DIFF_W3, DIFF_C4, DIFF_U3, DIFF_FFT, DIFF_SPLIT, DIFF_S2}; const std::map DIFF_METHODtoString = { - {DIFF_DEFAULT, "default"}, + {DIFF_DEFAULT, "DEFAULT"}, {DIFF_U1, "U1"}, {DIFF_U2, "U2"}, {DIFF_U3, "U3"}, {DIFF_C2, "C2"}, {DIFF_C4, "C4"}, {DIFF_S2, "S2"}, {DIFF_W2, "W2"}, {DIFF_W3, "W3"}, {DIFF_FFT, "FFT"}, From ba48ba02731eca3e29ffad9ee70455424f6937dd Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 14 Nov 2018 10:28:29 +0000 Subject: [PATCH 0254/1783] Try to fix enum parsing with a regexp for grep --- tools/pylib/_boutcore_build/resolve_enum.pxd.in | 2 +- tools/pylib/_boutcore_build/resolve_enum_inv.pyx.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/pylib/_boutcore_build/resolve_enum.pxd.in b/tools/pylib/_boutcore_build/resolve_enum.pxd.in index ac61275487..eca61983c4 100644 --- a/tools/pylib/_boutcore_build/resolve_enum.pxd.in +++ b/tools/pylib/_boutcore_build/resolve_enum.pxd.in @@ -8,7 +8,7 @@ do end=${file##*/} # In each file we are checking for enums, and then parse them - grep enum $file| \ + grep -E "^[ \t]*\benum\b" $file| \ while read line do # first remove the start, which is just enum diff --git a/tools/pylib/_boutcore_build/resolve_enum_inv.pyx.in b/tools/pylib/_boutcore_build/resolve_enum_inv.pyx.in index 4b2005c905..2e16bf9373 100644 --- a/tools/pylib/_boutcore_build/resolve_enum_inv.pyx.in +++ b/tools/pylib/_boutcore_build/resolve_enum_inv.pyx.in @@ -8,7 +8,7 @@ do end=${file##*/} # In each file we are checking for enums, and then parse them - grep enum $file| \ + grep -E "^[ \t]*\benum\b" $file| \ while read line do # first remove the start, which is just enum From 2195950a2e0d949d9051520e4126389198efb1e1 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 14 Nov 2018 10:58:57 +0000 Subject: [PATCH 0255/1783] Relax location combination constraints for flow derivatives --- src/mesh/index_derivs.cxx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index e0d797bdc0..bab0d54a17 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -59,7 +59,10 @@ STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_L STAGGER Mesh::getStagger(const CELL_LOC UNUSED(vloc), const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { #endif - TRACE("Mesh::getStagger -- four arugments"); - ASSERT1(vloc == inloc); + TRACE("Mesh::getStagger -- four arguments"); + ASSERT1(vloc == inloc || + (vloc == CELL_CENTRE && inloc == allowedStaggerLoc) || + (vloc == allowedStaggerLoc && inloc == CELL_CENTRE) + ); return getStagger(inloc, outloc, allowedStaggerLoc); } From 447d543e91ed53f48141c2b5fcb10a07c8cba52b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 14 Nov 2018 12:12:01 +0000 Subject: [PATCH 0256/1783] Remove usage of global 'mesh' pointer in Laplacian solvers Allow Laplacian solvers to be initialized with a local Mesh object, stored as Laplacian::localmesh. Use localmesh everywhere instead of global mesh, or mesh from Field*D.getMesh() to ensure consistency between initialization and solve methods. Includes ASSERT1 checks that 'localmesh == rhs.getMesh()', etc. --- include/invert_laplace.hxx | 21 +- include/invert_parderiv.hxx | 18 +- .../laplace/impls/cyclic/cyclic_laplace.cxx | 119 ++++----- .../laplace/impls/cyclic/cyclic_laplace.hxx | 5 +- .../impls/multigrid/multigrid_laplace.cxx | 75 +++--- .../impls/multigrid/multigrid_laplace.hxx | 16 +- .../laplace/impls/mumps/mumps_laplace.cxx | 226 +++++++++--------- .../laplace/impls/mumps/mumps_laplace.hxx | 18 +- .../laplace/impls/naulin/naulin_laplace.cxx | 30 +-- .../laplace/impls/naulin/naulin_laplace.hxx | 12 +- src/invert/laplace/impls/pdd/pdd.cxx | 142 +++++------ src/invert/laplace/impls/pdd/pdd.hxx | 7 +- .../laplace/impls/petsc/petsc_laplace.cxx | 159 ++++++------ .../laplace/impls/petsc/petsc_laplace.hxx | 18 +- .../laplace/impls/serial_band/serial_band.cxx | 54 +++-- .../laplace/impls/serial_band/serial_band.hxx | 5 +- .../laplace/impls/serial_tri/serial_tri.cxx | 32 +-- .../laplace/impls/serial_tri/serial_tri.hxx | 5 +- .../laplace/impls/shoot/shoot_laplace.cxx | 53 ++-- .../laplace/impls/shoot/shoot_laplace.hxx | 5 +- src/invert/laplace/impls/spt/spt.cxx | 171 ++++++------- src/invert/laplace/impls/spt/spt.hxx | 11 +- src/invert/laplace/invert_laplace.cxx | 74 +++--- src/invert/laplace/laplacefactory.cxx | 38 +-- src/invert/laplace/laplacefactory.hxx | 2 +- src/invert/parderiv/impls/cyclic/cyclic.cxx | 32 +-- src/invert/parderiv/impls/cyclic/cyclic.hxx | 27 ++- src/invert/parderiv/impls/serial/serial.cxx | 41 ++-- src/invert/parderiv/impls/serial/serial.hxx | 27 ++- src/invert/parderiv/invert_parderiv.cxx | 4 +- src/invert/parderiv/parderiv_factory.cxx | 14 +- src/invert/parderiv/parderiv_factory.hxx | 6 +- 32 files changed, 799 insertions(+), 668 deletions(-) diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index 77d43e5565..005cc61a78 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -105,14 +105,14 @@ const int INVERT_OUT_RHS = 32768; ///< Use input value in RHS at outer boundary /// Base class for Laplacian inversion class Laplacian { public: - Laplacian(Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE); + Laplacian(Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh* mesh_in = mesh); virtual ~Laplacian() {} /// Set coefficients for inversion. Re-builds matrices if necessary virtual void setCoefA(const Field2D &val) = 0; virtual void setCoefA(const Field3D &val) { setCoefA(DC(val)); } virtual void setCoefA(BoutReal r) { - Field2D f(r); + Field2D f(r, localmesh); f.setLocation(location); setCoefA(f); } @@ -120,7 +120,7 @@ public: virtual void setCoefC(const Field2D &val) = 0; virtual void setCoefC(const Field3D &val) { setCoefC(DC(val)); } virtual void setCoefC(BoutReal r) { - Field2D f(r); + Field2D f(r, localmesh); f.setLocation(location); setCoefC(f); } @@ -130,7 +130,7 @@ public: } virtual void setCoefC1(const Field3D &val) { setCoefC1(DC(val)); } virtual void setCoefC1(BoutReal r) { - Field2D f(r); + Field2D f(r, localmesh); f.setLocation(location); setCoefC1(f); } @@ -140,7 +140,7 @@ public: } virtual void setCoefC2(const Field3D &val) { setCoefC2(DC(val)); } virtual void setCoefC2(BoutReal r) { - Field2D f(r); + Field2D f(r, localmesh); f.setLocation(location); setCoefC2(f); } @@ -148,7 +148,7 @@ public: virtual void setCoefD(const Field2D &val) = 0; virtual void setCoefD(const Field3D &val) { setCoefD(DC(val)); } virtual void setCoefD(BoutReal r) { - Field2D f(r); + Field2D f(r, localmesh); f.setLocation(location); setCoefD(f); } @@ -156,7 +156,7 @@ public: virtual void setCoefEx(const Field2D &val) = 0; virtual void setCoefEx(const Field3D &val) { setCoefEx(DC(val)); } virtual void setCoefEx(BoutReal r) { - Field2D f(r); + Field2D f(r, localmesh); f.setLocation(location); setCoefEx(f); } @@ -164,7 +164,7 @@ public: virtual void setCoefEz(const Field2D &val) = 0; virtual void setCoefEz(const Field3D &val) { setCoefEz(DC(val)); } virtual void setCoefEz(BoutReal r) { - Field2D f(r); + Field2D f(r, localmesh); f.setLocation(location); setCoefEz(f); } @@ -192,7 +192,7 @@ public: * * @param[in] opt The options section to use. By default "laplace" will be used */ - static Laplacian *create(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); + static Laplacian *create(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); static Laplacian* defaultInstance(); ///< Return pointer to global singleton static void cleanup(); ///< Frees all memory @@ -227,7 +227,8 @@ protected: const Field2D *a, const Field2D *ccoef, const Field2D *d, bool includeguards=true); - CELL_LOC location; + CELL_LOC location; ///< staggered grid location of this solver + Mesh* localmesh; ///< Mesh object for this solver private: /// Singleton instance static Laplacian *instance; diff --git a/include/invert_parderiv.hxx b/include/invert_parderiv.hxx index 1ab6a9c4bb..0f562a2f79 100644 --- a/include/invert_parderiv.hxx +++ b/include/invert_parderiv.hxx @@ -64,7 +64,8 @@ public: * with pure virtual members, so can't be created directly. * To create an InvertPar object call the create() static function. */ - InvertPar(Options *UNUSED(opt)) {} + InvertPar(Options *UNUSED(opt), Mesh *mesh_in = mesh) + : localmesh(mesh_in) {} virtual ~InvertPar() {} /*! @@ -72,7 +73,7 @@ public: * * Note: For consistency this should be renamed "create" and take an Options* argument */ - static InvertPar* Create(); + static InvertPar* Create(Mesh *mesh_in = mesh); /*! * Solve the system of equations @@ -100,35 +101,38 @@ public: */ virtual void setCoefA(const Field2D &f) = 0; virtual void setCoefA(const Field3D &f) {setCoefA(DC(f));} - virtual void setCoefA(BoutReal f) {setCoefA(Field2D(f));} + virtual void setCoefA(BoutReal f) {setCoefA(Field2D(f, localmesh));} /*! * Set the Grad2_par2 coefficient B */ virtual void setCoefB(const Field2D &f) = 0; virtual void setCoefB(const Field3D &f) {setCoefB(DC(f));} - virtual void setCoefB(BoutReal f) {setCoefB(Field2D(f));} + virtual void setCoefB(BoutReal f) {setCoefB(Field2D(f, localmesh));} /*! * Set the D2DYDZ coefficient C */ virtual void setCoefC(const Field2D &f) = 0; virtual void setCoefC(const Field3D &f) {setCoefB(DC(f));} - virtual void setCoefC(BoutReal f) {setCoefB(Field2D(f));} + virtual void setCoefC(BoutReal f) {setCoefB(Field2D(f, localmesh));} /*! * Set the D2DZ2 coefficient D */ virtual void setCoefD(const Field2D &f) = 0; virtual void setCoefD(const Field3D &f) {setCoefB(DC(f));} - virtual void setCoefD(BoutReal f) {setCoefB(Field2D(f));} + virtual void setCoefD(BoutReal f) {setCoefB(Field2D(f, localmesh));} /*! * Set the DDY coefficient E */ virtual void setCoefE(const Field2D &f) = 0; virtual void setCoefE(const Field3D &f) {setCoefB(DC(f));} - virtual void setCoefE(BoutReal f) {setCoefB(Field2D(f));} + virtual void setCoefE(BoutReal f) {setCoefB(Field2D(f, localmesh));} + +protected: + Mesh* localmesh; ///< Mesh object for this solver private: }; diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index 3661b95dda..4d0df4e7c4 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -43,8 +43,8 @@ #include "cyclic_laplace.hxx" -LaplaceCyclic::LaplaceCyclic(Options *opt, const CELL_LOC loc) - : Laplacian(opt, loc), Acoef(0.0), Ccoef(1.0), Dcoef(1.0) { +LaplaceCyclic::LaplaceCyclic(Options *opt, const CELL_LOC loc, Mesh *mesh_in) + : Laplacian(opt, loc, mesh_in), Acoef(0.0), Ccoef(1.0), Dcoef(1.0) { Acoef.setLocation(location); Ccoef.setLocation(location); Dcoef.setLocation(location); @@ -54,7 +54,7 @@ LaplaceCyclic::LaplaceCyclic(Options *opt, const CELL_LOC loc) OPTION(opt, dst, false); if(dst) { - nmode = mesh->LocalNz-2; + nmode = localmesh->LocalNz-2; }else nmode = maxmode+1; // Number of Z modes. maxmode set in invert_laplace.cxx from options @@ -62,13 +62,13 @@ LaplaceCyclic::LaplaceCyclic(Options *opt, const CELL_LOC loc) // Allocate arrays - xs = mesh->xstart; // Starting X index - if(mesh->firstX() && !mesh->periodicX){ // Only want to include guard cells at boundaries (unless periodic in x) + xs = localmesh->xstart; // Starting X index + if(localmesh->firstX() && !localmesh->periodicX){ // Only want to include guard cells at boundaries (unless periodic in x) xs = 0; } - xe = mesh->xend; // Last X index - if(mesh->lastX() && !mesh->periodicX){ // Only want to include guard cells at boundaries (unless periodic in x) - xe = mesh->LocalNx-1; + xe = localmesh->xend; // Last X index + if(localmesh->lastX() && !localmesh->periodicX){ // Only want to include guard cells at boundaries (unless periodic in x) + xe = localmesh->LocalNx-1; } int n = xe - xs + 1; // Number of X points on this processor, // including boundaries but not guard cells @@ -80,8 +80,8 @@ LaplaceCyclic::LaplaceCyclic(Options *opt, const CELL_LOC loc) bcmplx = Matrix(nmode, n); // Create a cyclic reduction object, operating on dcomplex values - cr = new CyclicReduce(mesh->getXcomm(), n); - cr->setPeriodic(mesh->periodicX); + cr = new CyclicReduce(localmesh->getXcomm(), n); + cr->setPeriodic(localmesh->periodicX); } LaplaceCyclic::~LaplaceCyclic() { @@ -90,11 +90,12 @@ LaplaceCyclic::~LaplaceCyclic() { } const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) { - Mesh *mesh = rhs.getMesh(); - FieldPerp x(mesh); // Result + ASSERT1(localmesh == rhs.getMesh() && localmesh == x0.getMesh()); + + FieldPerp x(localmesh); // Result x.allocate(); - Coordinates *coord = mesh->getCoordinates(location); + Coordinates *coord = localmesh->getCoordinates(location); int jy = rhs.getIndex(); // Get the Y index x.setIndex(jy); @@ -102,8 +103,8 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) // Get the width of the boundary // If the flags to assign that only one guard cell should be used is set - int inbndry = mesh->xstart, outbndry=mesh->xstart; - if((global_flags & INVERT_BOTH_BNDRY_ONE) || (mesh->xstart < 2)) { + int inbndry = localmesh->xstart, outbndry=localmesh->xstart; + if((global_flags & INVERT_BOTH_BNDRY_ONE) || (localmesh->xstart < 2)) { inbndry = outbndry = 1; } if(inner_boundary_flags & INVERT_BNDRY_ONE) @@ -115,7 +116,7 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) BOUT_OMP(parallel) { /// Create a local thread-scope working array auto k1d = - Array(mesh->LocalNz); // ZFFT routine expects input of this length + Array(localmesh->LocalNz); // ZFFT routine expects input of this length // Loop over X indices, including boundaries but not guard cells. (unless periodic // in x) @@ -123,13 +124,13 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) for (int ix = xs; ix <= xe; ix++) { // Take DST in Z direction and put result in k1d - if (((ix < inbndry) && (inner_boundary_flags & INVERT_SET) && mesh->firstX()) || + if (((ix < inbndry) && (inner_boundary_flags & INVERT_SET) && localmesh->firstX()) || ((xe - ix < outbndry) && (outer_boundary_flags & INVERT_SET) && - mesh->lastX())) { + localmesh->lastX())) { // Use the values in x0 in the boundary - DST(x0[ix] + 1, mesh->LocalNz - 2, std::begin(k1d)); + DST(x0[ix] + 1, localmesh->LocalNz - 2, std::begin(k1d)); } else { - DST(rhs[ix] + 1, mesh->LocalNz - 2, std::begin(k1d)); + DST(rhs[ix] + 1, localmesh->LocalNz - 2, std::begin(k1d)); } // Copy into array, transposing so kz is first index @@ -141,7 +142,7 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) // including boundary conditions BOUT_OMP(for nowait) for (int kz = 0; kz < nmode; kz++) { - BoutReal zlen = coord->dz * (mesh->LocalNz - 3); + BoutReal zlen = coord->dz * (localmesh->LocalNz - 3); BoutReal kwave = kz * 2.0 * PI / (2. * zlen); // wave number is 1/[rad]; DST has extra 2. @@ -162,27 +163,27 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) BOUT_OMP(parallel) { /// Create a local thread-scope working array auto k1d = - Array(mesh->LocalNz); // ZFFT routine expects input of this length + Array(localmesh->LocalNz); // ZFFT routine expects input of this length BOUT_OMP(for nowait) for (int ix = xs; ix <= xe; ix++) { for (int kz = 0; kz < nmode; kz++) k1d[kz] = xcmplx(kz, ix - xs); - for (int kz = nmode; kz < (mesh->LocalNz); kz++) + for (int kz = nmode; kz < (localmesh->LocalNz); kz++) k1d[kz] = 0.0; // Filtering out all higher harmonics - DST_rev(std::begin(k1d), mesh->LocalNz - 2, x[ix] + 1); + DST_rev(std::begin(k1d), localmesh->LocalNz - 2, x[ix] + 1); x(ix, 0) = -x(ix, 2); - x(ix, mesh->LocalNz - 1) = -x(ix, mesh->LocalNz - 3); + x(ix, localmesh->LocalNz - 1) = -x(ix, localmesh->LocalNz - 3); } } }else { BOUT_OMP(parallel) { /// Create a local thread-scope working array - auto k1d = Array((mesh->LocalNz) / 2 + + auto k1d = Array((localmesh->LocalNz) / 2 + 1); // ZFFT routine expects input of this length // Loop over X indices, including boundaries but not guard cells (unless periodic in @@ -191,13 +192,13 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) for (int ix = xs; ix <= xe; ix++) { // Take FFT in Z direction, apply shift, and put result in k1d - if (((ix < inbndry) && (inner_boundary_flags & INVERT_SET) && mesh->firstX()) || + if (((ix < inbndry) && (inner_boundary_flags & INVERT_SET) && localmesh->firstX()) || ((xe - ix < outbndry) && (outer_boundary_flags & INVERT_SET) && - mesh->lastX())) { + localmesh->lastX())) { // Use the values in x0 in the boundary - rfft(x0[ix], mesh->LocalNz, std::begin(k1d)); + rfft(x0[ix], localmesh->LocalNz, std::begin(k1d)); } else { - rfft(rhs[ix], mesh->LocalNz, std::begin(k1d)); + rfft(rhs[ix], localmesh->LocalNz, std::begin(k1d)); } // Copy into array, transposing so kz is first index @@ -227,7 +228,7 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) BOUT_OMP(parallel) { /// Create a local thread-scope working array - auto k1d = Array((mesh->LocalNz) / 2 + + auto k1d = Array((localmesh->LocalNz) / 2 + 1); // ZFFT routine expects input of this length BOUT_OMP(for nowait) @@ -235,10 +236,10 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) for (int kz = 0; kz < nmode; kz++) k1d[kz] = xcmplx(kz, ix - xs); - for (int kz = nmode; kz < (mesh->LocalNz) / 2 + 1; kz++) + for (int kz = nmode; kz < (localmesh->LocalNz) / 2 + 1; kz++) k1d[kz] = 0.0; // Filtering out all higher harmonics - irfft(std::begin(k1d), mesh->LocalNz, x[ix]); + irfft(std::begin(k1d), localmesh->LocalNz, x[ix]); } } } @@ -250,11 +251,11 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { ASSERT1(rhs.getLocation() == location); ASSERT1(x0.getLocation() == location); + ASSERT1(localmesh == rhs.getMesh() && localmesh == x0.getMesh()); Timer timer("invert"); - Mesh *mesh = rhs.getMesh(); - Field3D x(mesh); // Result + Field3D x(localmesh); // Result x.allocate(); x.setLocation(location); @@ -263,8 +264,8 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { // Get the width of the boundary // If the flags to assign that only one guard cell should be used is set - int inbndry = mesh->xstart, outbndry = mesh->xstart; - if ((global_flags & INVERT_BOTH_BNDRY_ONE) || (mesh->xstart < 2)) { + int inbndry = localmesh->xstart, outbndry = localmesh->xstart; + if ((global_flags & INVERT_BOTH_BNDRY_ONE) || (localmesh->xstart < 2)) { inbndry = outbndry = 1; } if (inner_boundary_flags & INVERT_BNDRY_ONE) @@ -275,17 +276,17 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { int nx = xe - xs + 1; // Number of X points on this processor // Get range of Y indices - int ys = mesh->ystart, ye = mesh->yend; + int ys = localmesh->ystart, ye = localmesh->yend; - if (mesh->hasBndryLowerY()) { + if (localmesh->hasBndryLowerY()) { if (include_yguards) ys = 0; // Mesh contains a lower boundary and we are solving in the guard cells ys += extra_yguards_lower; } - if (mesh->hasBndryUpperY()) { + if (localmesh->hasBndryUpperY()) { if (include_yguards) - ye = mesh->LocalNy - + ye = localmesh->LocalNy - 1; // Contains upper boundary and we are solving in the guard cells ye -= extra_yguards_upper; @@ -306,7 +307,7 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { BOUT_OMP(parallel) { /// Create a local thread-scope working array auto k1d = - Array(mesh->LocalNz); // ZFFT routine expects input of this length + Array(localmesh->LocalNz); // ZFFT routine expects input of this length // Loop over X and Y indices, including boundaries but not guard cells. // (unless periodic in x) @@ -318,13 +319,13 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { // Take DST in Z direction and put result in k1d - if (((ix < inbndry) && (inner_boundary_flags & INVERT_SET) && mesh->firstX()) || + if (((ix < inbndry) && (inner_boundary_flags & INVERT_SET) && localmesh->firstX()) || ((xe - ix < outbndry) && (outer_boundary_flags & INVERT_SET) && - mesh->lastX())) { + localmesh->lastX())) { // Use the values in x0 in the boundary - DST(x0(ix, iy) + 1, mesh->LocalNz - 2, std::begin(k1d)); + DST(x0(ix, iy) + 1, localmesh->LocalNz - 2, std::begin(k1d)); } else { - DST(rhs(ix, iy) + 1, mesh->LocalNz - 2, std::begin(k1d)); + DST(rhs(ix, iy) + 1, localmesh->LocalNz - 2, std::begin(k1d)); } // Copy into array, transposing so kz is first index @@ -340,7 +341,7 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { int iy = ys + ind / nmode; int kz = ind % nmode; - BoutReal zlen = coord->dz * (mesh->LocalNz - 3); + BoutReal zlen = coord->dz * (localmesh->LocalNz - 3); BoutReal kwave = kz * 2.0 * PI / (2. * zlen); // wave number is 1/[rad]; DST has extra 2. @@ -361,7 +362,7 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { BOUT_OMP(parallel) { /// Create a local thread-scope working array auto k1d = - Array(mesh->LocalNz); // ZFFT routine expects input of this length + Array(localmesh->LocalNz); // ZFFT routine expects input of this length BOUT_OMP(for nowait) for (int ind = 0; ind < nxny; ++ind) { // Loop over X and Y @@ -372,19 +373,19 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { for (int kz = 0; kz < nmode; kz++) k1d[kz] = xcmplx3D((iy - ys) * nmode + kz, ix - xs); - for (int kz = nmode; kz < mesh->LocalNz; kz++) + for (int kz = nmode; kz < localmesh->LocalNz; kz++) k1d[kz] = 0.0; // Filtering out all higher harmonics - DST_rev(std::begin(k1d), mesh->LocalNz - 2, &x(ix, iy, 1)); + DST_rev(std::begin(k1d), localmesh->LocalNz - 2, &x(ix, iy, 1)); x(ix, iy, 0) = -x(ix, iy, 2); - x(ix, iy, mesh->LocalNz - 1) = -x(ix, iy, mesh->LocalNz - 3); + x(ix, iy, localmesh->LocalNz - 1) = -x(ix, iy, localmesh->LocalNz - 3); } } } else { BOUT_OMP(parallel) { /// Create a local thread-scope working array - auto k1d = Array(mesh->LocalNz / 2 + + auto k1d = Array(localmesh->LocalNz / 2 + 1); // ZFFT routine expects input of this length // Loop over X and Y indices, including boundaries but not guard cells @@ -398,13 +399,13 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { // Take FFT in Z direction, apply shift, and put result in k1d - if (((ix < inbndry) && (inner_boundary_flags & INVERT_SET) && mesh->firstX()) || + if (((ix < inbndry) && (inner_boundary_flags & INVERT_SET) && localmesh->firstX()) || ((xe - ix < outbndry) && (outer_boundary_flags & INVERT_SET) && - mesh->lastX())) { + localmesh->lastX())) { // Use the values in x0 in the boundary - rfft(x0(ix, iy), mesh->LocalNz, std::begin(k1d)); + rfft(x0(ix, iy), localmesh->LocalNz, std::begin(k1d)); } else { - rfft(rhs(ix, iy), mesh->LocalNz, std::begin(k1d)); + rfft(rhs(ix, iy), localmesh->LocalNz, std::begin(k1d)); } // Copy into array, transposing so kz is first index @@ -437,7 +438,7 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { // FFT back to real space BOUT_OMP(parallel) { /// Create a local thread-scope working array - auto k1d = Array((mesh->LocalNz) / 2 + + auto k1d = Array((localmesh->LocalNz) / 2 + 1); // ZFFT routine expects input of this length BOUT_OMP(for nowait) @@ -449,10 +450,10 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { for (int kz = 0; kz < nmode; kz++) k1d[kz] = xcmplx3D((iy - ys) * nmode + kz, ix - xs); - for (int kz = nmode; kz < mesh->LocalNz / 2 + 1; kz++) + for (int kz = nmode; kz < localmesh->LocalNz / 2 + 1; kz++) k1d[kz] = 0.0; // Filtering out all higher harmonics - irfft(std::begin(k1d), mesh->LocalNz, x(ix, iy)); + irfft(std::begin(k1d), localmesh->LocalNz, x(ix, iy)); } } } diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx index bb1d9f31c2..b007542569 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx @@ -44,22 +44,25 @@ class LaplaceCyclic; */ class LaplaceCyclic : public Laplacian { public: - LaplaceCyclic(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); + LaplaceCyclic(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); ~LaplaceCyclic(); using Laplacian::setCoefA; void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); Acoef = val; } using Laplacian::setCoefC; void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); Ccoef = val; } using Laplacian::setCoefD; void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); Dcoef = val; } using Laplacian::setCoefEx; diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index 17e0e6b127..567ec0e583 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -37,8 +37,8 @@ BoutReal soltime=0.0,settime=0.0; -LaplaceMultigrid::LaplaceMultigrid(Options *opt, const CELL_LOC loc) : - Laplacian(opt, loc), +LaplaceMultigrid::LaplaceMultigrid(Options *opt, const CELL_LOC loc, Mesh *mesh_in) : + Laplacian(opt, loc, mesh_in), A(0.0), C1(1.0), C2(1.0), D(1.0) { TRACE("LaplaceMultigrid::LaplaceMultigrid(Options *opt)"); @@ -84,20 +84,20 @@ LaplaceMultigrid::LaplaceMultigrid(Options *opt, const CELL_LOC loc) : throw BoutException("Attempted to set Laplacian outer boundary inversion flag that is not implemented in LaplaceMultigrid."); } - commX = mesh->getXcomm(); + commX = localmesh->getXcomm(); - Nx_local = mesh->xend - mesh->xstart + 1; // excluding guard cells - Nx_global = mesh->GlobalNx - 2*mesh->xstart; // excluding guard cells + Nx_local = localmesh->xend - localmesh->xstart + 1; // excluding guard cells + Nx_global = localmesh->GlobalNx - 2*localmesh->xstart; // excluding guard cells if (mgcount == 0) { output <<"Nx="<GlobalNz; + Nz_global = localmesh->GlobalNz; Nz_local = Nz_global; // No parallelization in z-direction (for now) // //else { - // Nz_local = mesh->zend - mesh->zstart + 1; // excluding guard cells - // Nz_global = mesh->GlobalNz - 2*mesh->zstart; // excluding guard cells + // Nz_local = localmesh->zend - localmesh->zstart + 1; // excluding guard cells + // Nz_global = localmesh->GlobalNz - 2*localmesh->zstart; // excluding guard cells // } if (mgcount==0) { output <<"Nz="<getCoordinates(location); + Coordinates *coords = localmesh->getCoordinates(location); yindex = b_in.getIndex(); int level = kMG->mglevel-1; @@ -231,7 +232,7 @@ BOUT_OMP(parallel default(shared) ) BOUT_OMP(for collapse(2)) for (int i=1; ixstart; + int i2 = i-1+localmesh->xstart; int k2 = k-1; x[i*lz2+k] = x0[i2][k2]; } @@ -243,13 +244,13 @@ BOUT_OMP(parallel default(shared) ) BOUT_OMP(for collapse(2)) for (int i=1; ixstart; + int i2 = i-1+localmesh->xstart; int k2 = k-1; b[i*lz2+k] = b_in(i2, k2); } } - if (mesh->firstX()) { + if (localmesh->firstX()) { if ( inner_boundary_flags & INVERT_AC_GRAD ) { // Neumann boundary condition if ( inner_boundary_flags & INVERT_SET ) { @@ -258,7 +259,7 @@ BOUT_OMP(parallel default(shared) ) BOUT_OMP(for) for (int k=1; kxstart-1, k2)*sqrt(coords->g_11(mesh->xstart, yindex))*coords->dx(mesh->xstart, yindex); + x[k] = -x0(localmesh->xstart-1, k2)*sqrt(coords->g_11(localmesh->xstart, yindex))*coords->dx(localmesh->xstart, yindex); } } else { // zero gradient inner boundary condition @@ -277,7 +278,7 @@ BOUT_OMP(parallel default(shared) ) BOUT_OMP(for) for (int k=1; kxstart-1, k2); + x[k] = 2.*x0(localmesh->xstart-1, k2); // this is the value to set at the inner boundary } } @@ -292,7 +293,7 @@ BOUT_OMP(for) } } } - if (mesh->lastX()) { + if (localmesh->lastX()) { if ( outer_boundary_flags & INVERT_AC_GRAD ) { // Neumann boundary condition if ( inner_boundary_flags & INVERT_SET ) { @@ -301,7 +302,7 @@ BOUT_OMP(parallel default(shared) ) BOUT_OMP(for) for (int k=1; kxend+1, k2)*sqrt(coords->g_11(mesh->xend, yindex))*coords->dx(mesh->xend, yindex); + x[(lxx+1)*lz2+k] = x0(localmesh->xend+1, k2)*sqrt(coords->g_11(localmesh->xend, yindex))*coords->dx(localmesh->xend, yindex); // this is the value to set the gradient to at the outer boundary } } @@ -323,7 +324,7 @@ BOUT_OMP(parallel default(shared) ) BOUT_OMP(for) for (int k=1; kxend+1, k2); + x[(lxx+1)*lz2+k]=2.*x0(localmesh->xend+1, k2); // this is the value to set at the outer boundary } } @@ -423,13 +424,13 @@ BOUT_OMP(for) } } - FieldPerp result(mesh); + FieldPerp result(localmesh); result.allocate(); result.setIndex(yindex); #if CHECK>2 // Make any unused elements NaN so that user does not try to do calculations with them - const auto ®ion = mesh->getRegionPerp("RGN_ALL"); + const auto ®ion = localmesh->getRegionPerp("RGN_ALL"); BOUT_FOR(i, region) { result[i] = BoutNaN; } @@ -439,27 +440,27 @@ BOUT_OMP(parallel default(shared) ) BOUT_OMP(for collapse(2)) for (int i=1; ixstart; + int i2 = i-1+localmesh->xstart; int k2 = k-1; result(i2, k2) = x[i*lz2+k]; } } - if (mesh->firstX()) { + if (localmesh->firstX()) { if ( inner_boundary_flags & INVERT_AC_GRAD ) { // Neumann boundary condition if ( inner_boundary_flags & INVERT_SET ) { // guard cells of x0 specify gradient to set at inner boundary - int i2 = -1+mesh->xstart; + int i2 = -1+localmesh->xstart; BOUT_OMP(parallel default(shared) ) BOUT_OMP(for) for (int k=1; kxstart-1, k2)*sqrt(coords->g_11(mesh->xstart, yindex))*coords->dx(mesh->xstart, yindex); + result(i2, k2) = x[lz2+k] - x0(localmesh->xstart-1, k2)*sqrt(coords->g_11(localmesh->xstart, yindex))*coords->dx(localmesh->xstart, yindex); } } else { // zero gradient inner boundary condition - int i2 = -1+mesh->xstart; + int i2 = -1+localmesh->xstart; BOUT_OMP(parallel default(shared) ) BOUT_OMP(for) for (int k=1; kxstart; + int i2 = -1+localmesh->xstart; BOUT_OMP(parallel default(shared) ) BOUT_OMP(for) for (int k=1; kxstart-1,k2) - x[lz2+k]; + result(i2, k2) = 2.*x0(localmesh->xstart-1,k2) - x[lz2+k]; } } else { // zero value inner boundary condition - int i2 = -1+mesh->xstart; + int i2 = -1+localmesh->xstart; BOUT_OMP(parallel default(shared) ) BOUT_OMP(for) for (int k=1; klastX()) { + if (localmesh->lastX()) { if ( outer_boundary_flags & INVERT_AC_GRAD ) { // Neumann boundary condition if ( inner_boundary_flags & INVERT_SET ) { // guard cells of x0 specify gradient to set at outer boundary - int i2 = lxx+mesh->xstart; + int i2 = lxx+localmesh->xstart; BOUT_OMP(parallel default(shared) ) BOUT_OMP(for) for (int k=1; kxend+1, k2)*sqrt(coords->g_11(mesh->xend, yindex))*coords->dx(mesh->xend, yindex); + result(i2, k2) = x[lxx*lz2+k] + x0(localmesh->xend+1, k2)*sqrt(coords->g_11(localmesh->xend, yindex))*coords->dx(localmesh->xend, yindex); } } else { // zero gradient outer boundary condition - int i2 = lxx+mesh->xstart; + int i2 = lxx+localmesh->xstart; BOUT_OMP(parallel default(shared) ) BOUT_OMP(for) for (int k=1; kxstart; + int i2 = lxx+localmesh->xstart; BOUT_OMP(parallel default(shared) ) BOUT_OMP(for) for (int k=1; kxend+1,k2) - x[lxx*lz2+k]; + result(i2, k2) = 2.*x0(localmesh->xend+1,k2) - x[lxx*lz2+k]; } } else { // zero value inner boundary condition - int i2 = lxx+mesh->xstart; + int i2 = lxx+localmesh->xstart; BOUT_OMP(parallel default(shared) ) BOUT_OMP(for) for (int k=1; kgetCoordinates(location); + Coordinates *coords = localmesh->getCoordinates(location); BoutReal *mat; mat = kMG->matmg[level]; int llx = kMG->lnx[level]; @@ -564,7 +565,7 @@ BOUT_OMP(parallel default(shared)) BOUT_OMP(for collapse(2)) for (int i=1; ixstart; + int i2 = i-1+localmesh->xstart; int k2 = k-1; int k2p = (k2+1)%Nz_global; int k2m = (k2+Nz_global-1)%Nz_global; diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx index 6c22d8105a..00eaf96a6b 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx @@ -132,28 +132,33 @@ private: class LaplaceMultigrid : public Laplacian { public: - LaplaceMultigrid(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); + LaplaceMultigrid(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); ~LaplaceMultigrid() {}; void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); A = val; } void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); C1 = val; C2 = val; } void setCoefC1(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); C1 = val; } void setCoefC2(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); C2 = val; } void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); D = val; } void setCoefEx(const Field2D &UNUSED(val)) override { throw BoutException("setCoefEx is not implemented in LaplaceMultigrid"); } @@ -161,28 +166,35 @@ public: void setCoefA(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); A = val; } void setCoefC(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); C1 = val; C2 = val; } void setCoefC1(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); C1 = val; } void setCoefC2(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); C2 = val; } void setCoefD(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); D = val; } const FieldPerp solve(const FieldPerp &b) override { - FieldPerp zero(b.getMesh()); + ASSERT1(localmesh == b.getMesh()); + + FieldPerp zero(localmesh); zero = 0.; zero.setIndex(b.getIndex()); return solve(b, zero); diff --git a/src/invert/laplace/impls/mumps/mumps_laplace.cxx b/src/invert/laplace/impls/mumps/mumps_laplace.cxx index df8967babc..dd30e4b15e 100644 --- a/src/invert/laplace/impls/mumps/mumps_laplace.cxx +++ b/src/invert/laplace/impls/mumps/mumps_laplace.cxx @@ -34,8 +34,8 @@ #include #include -LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc) : - Laplacian(opt, loc), +LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc, Mesh *mesh_in = mesh) : + Laplacian(opt, loc, mesh_in), A(0.0), C1(1.0), C2(1.0), D(1.0), Ex(0.0), Ez(0.0), issetD(false), issetC(false), issetE(false) { @@ -65,21 +65,21 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc) : if (outer_boundary_flags & ~implemented_boundary_flags) { throw BoutException("Attempted to set Laplacian inversion boundary condition flag that is not implemented in mumps_laplace.cxx"); } - if(mesh->periodicX) { - throw BoutException("LaplaceMumps does not work with periodicity in the x direction (mesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); + if(localmesh->periodicX) { + throw BoutException("LaplaceMumps does not work with periodicity in the x direction (localmesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); } #endif // Get communicator for group of processors in X - all points in z-x plane for fixed y. - comm = mesh->getXcomm(); + comm = localmesh->getXcomm(); // Need to determine local size to use based on prior parallelisation // Coefficient values are stored only on local processors. - localN = (mesh->xend - mesh->xstart + 1) * (mesh->LocalNz); - if(mesh->firstX()) - localN += mesh->xstart * (mesh->LocalNz); // If on first processor add on width of boundary region - if(mesh->lastX()) - localN += mesh->xstart * (mesh->LocalNz); // If on last processor add on width of boundary region + localN = (localmesh->xend - localmesh->xstart + 1) * (localmesh->LocalNz); + if(localmesh->firstX()) + localN += localmesh->xstart * (localmesh->LocalNz); // If on first processor add on width of boundary region + if(localmesh->lastX()) + localN += localmesh->xstart * (localmesh->LocalNz); // If on last processor add on width of boundary region // Calculate total number of points in physical grid @@ -87,11 +87,11 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc) : throw BoutException("Error in MPI_Allreduce during LaplacePetsc initialisation"); // Calculate total (physical) grid dimensions - meshz = mesh->GlobalNz-1; + meshz = localmesh->GlobalNz-1; meshx = size / meshz; // Calculate number of guard cells in x-direction - nxguards = mesh->LocalNx - (mesh->xend-mesh->xstart+1); + nxguards = localmesh->LocalNx - (localmesh->xend-localmesh->xstart+1); // Get implementation specific options opts->get("fourth_order", fourth_order, false); @@ -99,7 +99,7 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc) : sol.allocate(); - mumps_struc.comm_fortran = (MUMPS_INT) MPI_Comm_c2f(mesh->getXcomm()); // MPI communicator for MUMPS, in fortran format + mumps_struc.comm_fortran = (MUMPS_INT) MPI_Comm_c2f(localmesh->getXcomm()); // MPI communicator for MUMPS, in fortran format mumps_struc.sym = 0; // Solve using unsymmetric matrix mumps_struc.par = 1; // Use the host processor (rank 0) to do work for the solution @@ -112,39 +112,39 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc) : // nz is the total number of non-zero elements in the matrix, nz_loc is the number of non-zero elements on this processor if (fourth_order) { mumps_struc.nz = 25*(meshx-nxguards)*meshz; - mumps_struc.nz_loc = 25*(mesh->xend-mesh->xstart+1)*(mesh->LocalNz); + mumps_struc.nz_loc = 25*(localmesh->xend-localmesh->xstart+1)*(localmesh->LocalNz); } else { mumps_struc.nz = 9*(meshx-nxguards)*meshz; - mumps_struc.nz_loc = 9*(mesh->xend-mesh->xstart+1)*(mesh->LocalNz); + mumps_struc.nz_loc = 9*(localmesh->xend-localmesh->xstart+1)*(localmesh->LocalNz); } if (inner_boundary_flags & INVERT_AC_GRAD) { if (fourth_order) { - mumps_struc.nz += 5*meshz*mesh->xstart; - if (mesh->firstX()) mumps_struc.nz_loc += 5*mesh->xstart*(mesh->LocalNz); + mumps_struc.nz += 5*meshz*localmesh->xstart; + if (localmesh->firstX()) mumps_struc.nz_loc += 5*localmesh->xstart*(localmesh->LocalNz); } else { - mumps_struc.nz += 3*meshz*(mesh->xstart); - if (mesh->firstX()) mumps_struc.nz_loc += 3*mesh->xstart*(mesh->LocalNz); + mumps_struc.nz += 3*meshz*(localmesh->xstart); + if (localmesh->firstX()) mumps_struc.nz_loc += 3*localmesh->xstart*(localmesh->LocalNz); } } else { - mumps_struc.nz += mesh->xstart*meshz; - if (mesh->firstX()) mumps_struc.nz_loc += mesh->xstart*(mesh->LocalNz); + mumps_struc.nz += localmesh->xstart*meshz; + if (localmesh->firstX()) mumps_struc.nz_loc += localmesh->xstart*(localmesh->LocalNz); } if (outer_boundary_flags & INVERT_AC_GRAD) { if (fourth_order) { - mumps_struc.nz += 5*(mesh->LocalNx-mesh->xend-1)*meshz; - if (mesh->lastX()) mumps_struc.nz_loc += 5*(mesh->LocalNx-mesh->xend-1)*(mesh->LocalNz); + mumps_struc.nz += 5*(localmesh->LocalNx-localmesh->xend-1)*meshz; + if (localmesh->lastX()) mumps_struc.nz_loc += 5*(localmesh->LocalNx-localmesh->xend-1)*(localmesh->LocalNz); } else { - mumps_struc.nz += 3*(mesh->LocalNx-mesh->xend-1)*meshz; - if (mesh->lastX()) mumps_struc.nz_loc += 3*(mesh->LocalNx-mesh->xend-1)*(mesh->LocalNz); + mumps_struc.nz += 3*(localmesh->LocalNx-localmesh->xend-1)*meshz; + if (localmesh->lastX()) mumps_struc.nz_loc += 3*(localmesh->LocalNx-localmesh->xend-1)*(localmesh->LocalNz); } } else { - mumps_struc.nz += (mesh->LocalNx-mesh->xend-1)*meshz; - if (mesh->lastX()) mumps_struc.nz_loc += (mesh->LocalNx-mesh->xend-1)*(mesh->LocalNz); + mumps_struc.nz += (localmesh->LocalNx-localmesh->xend-1)*meshz; + if (localmesh->lastX()) mumps_struc.nz_loc += (localmesh->LocalNx-localmesh->xend-1)*(localmesh->LocalNz); } // // These would be needed if giving the matrix only on the host processor, or possibly if providing the structure on the host processor for analysis // mumps_struc.irn = new MUMPS_INT[mumps_struc.nz]; @@ -154,13 +154,13 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc) : mumps_struc.jcn_loc = new MUMPS_INT[mumps_struc.nz_loc]; // list of GLOBAL column indices of local matrix entries mumps_struc.a_loc = new BoutReal[mumps_struc.nz_loc]; // the matrix entries - if (mesh->firstX()) { + if (localmesh->firstX()) { mumps_struc.nrhs = 1; // number of right hand side vectors mumps_struc.lrhs = mumps_struc.n; // leading dimension of rhs (i.e. length of vector) // mumps_struc.rhs = new BoutReal[mumps_struc.lrhs*mumps_struc.nrhs]; // rhs, to be provided on the rank-0 processor only } -// if (mesh->firstX()) mumps_struc.sol_loc = *sol.getData(); // pointer to the array to put the solution in, starts at 0 on first processor -// else mumps_struc.sol_loc = *sol.getData() + mesh->xstart*meshz; // pointer to the array to put the solution in, starts at mesh->xstart +// if (localmesh->firstX()) mumps_struc.sol_loc = *sol.getData(); // pointer to the array to put the solution in, starts at 0 on first processor +// else mumps_struc.sol_loc = *sol.getData() + localmesh->xstart*meshz; // pointer to the array to put the solution in, starts at localmesh->xstart // mumps_struc.lsol_loc = localN; // size of the (local) solution array // mumps_struc.isol_loc = new MUMPS_INT[localN]; // list of indices of the solution array (though this is all local points) mumps_struc.icntl[2] = 0; // Suppress output of global information @@ -180,43 +180,43 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc) : // mumps_struc.job = MUMPS_JOB_ALL; // iteration_count = repeat_analysis; -// localrhssize = (mesh->xend-mesh->xstart+1)*mesh->LocalNy*mesh->LocalNz; -// if (mesh->lastX()) { -// localrhssize += (mesh->LocalNx-mesh->xend-1)*mesh->LocalNy*mesh->LocalNz; +// localrhssize = (localmesh->xend-localmesh->xstart+1)*localmesh->LocalNy*localmesh->LocalNz; +// if (localmesh->lastX()) { +// localrhssize += (localmesh->LocalNx-localmesh->xend-1)*localmesh->LocalNy*localmesh->LocalNz; // } -// if (mesh->firstX()) { -// localrhssize += mesh->xstart*mesh->LocalNy*mesh->LocalNz; +// if (localmesh->firstX()) { +// localrhssize += localmesh->xstart*localmesh->LocalNy*localmesh->LocalNz; // -// int nxpe = mesh->NXPE; +// int nxpe = localmesh->NXPE; // localrhs_size_array = new int[nxpe]; // localrhs_size_array[0] = localrhssize; // if (nxpe>1) { // for (int i=1; ixend-mesh->xstart+1)*mesh->LocalNy*mesh->LocalNz; -// localrhs_size_array[nxpe-1] = (mesh->LocalNx-mesh->xstart)*mesh->LocalNy*mesh->LocalNz; +// localrhs_size_array[i] = (localmesh->xend-localmesh->xstart+1)*localmesh->LocalNy*localmesh->LocalNz; +// localrhs_size_array[nxpe-1] = (localmesh->LocalNx-localmesh->xstart)*localmesh->LocalNy*localmesh->LocalNz; // } // rhs_positions = new int[nxpe]; // rhs_positions[0] = 0; // for (int i=1; iLocalNy*mesh->LocalNz]; -// rhs_slice = new BoutReal[meshx*mesh->LocalNz]; +// rhs = new BoutReal[meshx*localmesh->LocalNy*localmesh->LocalNz]; +// rhs_slice = new BoutReal[meshx*localmesh->LocalNz]; // } - localrhssize = (mesh->xend-mesh->xstart+1)*(mesh->LocalNz); - if (mesh->lastX()) { - localrhssize += (mesh->LocalNx-mesh->xend-1)*(mesh->LocalNz); + localrhssize = (localmesh->xend-localmesh->xstart+1)*(localmesh->LocalNz); + if (localmesh->lastX()) { + localrhssize += (localmesh->LocalNx-localmesh->xend-1)*(localmesh->LocalNz); } - if (mesh->firstX()) { - localrhssize += mesh->xstart*(mesh->LocalNz); + if (localmesh->firstX()) { + localrhssize += localmesh->xstart*(localmesh->LocalNz); - int nxpe = mesh->NXPE; + int nxpe = localmesh->NXPE; localrhs_size_array = Array(nxpe); localrhs_size_array[0] = localrhssize; if (nxpe>1) { for (int i=1; ixend-mesh->xstart+1)*(mesh->LocalNz); - localrhs_size_array[nxpe-1] = (mesh->LocalNx-mesh->xstart)*(mesh->LocalNz); + localrhs_size_array[i] = (localmesh->xend-localmesh->xstart+1)*(localmesh->LocalNz); + localrhs_size_array[nxpe-1] = (localmesh->LocalNx-localmesh->xstart)*(localmesh->LocalNz); } rhs_positions = Array(nxpe); rhs_positions[0] = 0; @@ -229,9 +229,9 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc) : // Set Arrays of matrix indices, using i (0<=ifirstX()) - for (int x=0; xxstart; x++) - for (int z=0; zLocalNz; z++) { + if (localmesh->firstX()) + for (int x=0; xxstart; x++) + for (int z=0; zLocalNz; z++) { int x0 = x; int xp = x+1; int xpp = x+2; @@ -263,13 +263,13 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc) : // mumps_struc.isol_loc[j] = x0*meshz + z0 + 1; // Indices for fortran arrays that start at 1 // j++; } - for (int x=mesh->xstart; x<=mesh->xend; x++) - for (int z=0; zLocalNz; z++) { - int xmm = mesh->XGLOBAL(x)-2; - int xm = mesh->XGLOBAL(x)-1; - int x0 = mesh->XGLOBAL(x); - int xp = mesh->XGLOBAL(x)+1; - int xpp = mesh->XGLOBAL(x)+2; + for (int x=localmesh->xstart; x<=localmesh->xend; x++) + for (int z=0; zLocalNz; z++) { + int xmm = localmesh->XGLOBAL(x)-2; + int xm = localmesh->XGLOBAL(x)-1; + int x0 = localmesh->XGLOBAL(x); + int xp = localmesh->XGLOBAL(x)+1; + int xpp = localmesh->XGLOBAL(x)+2; int zmm = (z-2<0) ? (z-2+meshz) : (z-2); int zm = (z-1<0) ? (z-1+meshz) : (z-1); int z0 = z; @@ -384,12 +384,12 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc) : // mumps_struc.isol_loc[j] = x0*meshz + z0 + 1; // Indices for fortran arrays that start at 1 // j++; } - if (mesh->lastX()) - for (int x=mesh->xend+1; xLocalNx; x++) - for (int z=0; zLocalNz; z++) { - int xmm = mesh->XGLOBAL(mesh->xend)+x-mesh->xend-2; - int xm = mesh->XGLOBAL(mesh->xend)+x-mesh->xend-1; - int x0 = mesh->XGLOBAL(mesh->xend)+x-mesh->xend; + if (localmesh->lastX()) + for (int x=localmesh->xend+1; xLocalNx; x++) + for (int z=0; zLocalNz; z++) { + int xmm = localmesh->XGLOBAL(localmesh->xend)+x-localmesh->xend-2; + int xm = localmesh->XGLOBAL(localmesh->xend)+x-localmesh->xend-1; + int x0 = localmesh->XGLOBAL(localmesh->xend)+x-localmesh->xend; int z0 = z; if(outer_boundary_flags & INVERT_AC_GRAD) { mumps_struc.irn_loc[i] = x0*meshz + z0 + 1; // Indices for fortran arrays that start at 1 @@ -442,17 +442,17 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc) : // #if CHECK > 0 // msg_stack.push("Laplacian::solve(Field3D)"); // #endif -// int ys = mesh->ystart, ye = mesh->yend; +// int ys = localmesh->ystart, ye = localmesh->yend; // -// if(mesh->hasBndryLowerY()) { +// if(localmesh->hasBndryLowerY()) { // if (include_yguards) // ys = 0; // Mesh contains a lower boundary and we are solving in the guard cells // // ys += extra_yguards_lower; // } -// if(mesh->hasBndryUpperY()) { +// if(localmesh->hasBndryUpperY()) { // if (include_yguards) -// ye = mesh->LocalNy-1; // Contains upper boundary and we are solving in the guard cells +// ye = localmesh->LocalNy-1; // Contains upper boundary and we are solving in the guard cells // // ye -= extra_yguards_upper; // } @@ -460,43 +460,43 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc) : // Field3D x = copy(b); // Force new memory allocation as we will mess around with x's data via pointers (i.e. 'unsafely') // // BoutReal* localrhs = **x.getData(); // Input the rhs in the solution field as solution will be returned in place by MUMPS -// if (!mesh->firstX()) localrhs += mesh->xstart*mesh->LocalNy*mesh->LocalNz; -// MPI_Gatherv(localrhs,localrhssize,MPI_DOUBLE,rhs,localrhs_size_array,rhs_positions,MPI_DOUBLE,0,mesh->getXcomm()); +// if (!localmesh->firstX()) localrhs += localmesh->xstart*localmesh->LocalNy*localmesh->LocalNz; +// MPI_Gatherv(localrhs,localrhssize,MPI_DOUBLE,rhs,localrhs_size_array,rhs_positions,MPI_DOUBLE,0,localmesh->getXcomm()); // // if ( ++iteration_count > repeat_analysis ) { // mumps_struc.job = MUMPS_JOB_ALL; // for(int jy=ys; jy <= ye; jy++) { -// if (mesh->firstX()) +// if (localmesh->firstX()) // for(int jx=0; jxLocalNy*mesh->LocalNz + jy*mesh->LocalNz + jz]; +// rhs_slice[jx*meshz+jz] = rhs[jx*localmesh->LocalNy*localmesh->LocalNz + jy*localmesh->LocalNz + jz]; // // solve(rhs_slice,jy); // -// if (mesh->firstX()) +// if (localmesh->firstX()) // for(int jx=0; jxLocalNy*mesh->LocalNz + jy*mesh->LocalNz + jz] = rhs_slice[jx*meshz+jz]; +// rhs[jx*localmesh->LocalNy*localmesh->LocalNz + jy*localmesh->LocalNz + jz] = rhs_slice[jx*meshz+jz]; // } // mumps_struc.job = MUMPS_JOB_BOTH; // } // else { // for(int jy=ys; jy <= ye; jy++) { -// if (mesh->firstX()) +// if (localmesh->firstX()) // for(int jx=0; jxLocalNy*mesh->LocalNz + jy*mesh->LocalNz + jz]; +// rhs_slice[jx*meshz+jz] = rhs[jx*localmesh->LocalNy*localmesh->LocalNz + jy*localmesh->LocalNz + jz]; // // solve(rhs_slice,jy); // -// if (mesh->firstX()) +// if (localmesh->firstX()) // for(int jx=0; jxLocalNy*mesh->LocalNz + jy*mesh->LocalNz + jz] = rhs_slice[jx*meshz+jz]; +// rhs[jx*localmesh->LocalNy*localmesh->LocalNz + jy*localmesh->LocalNz + jz] = rhs_slice[jx*meshz+jz]; // } // } // -// MPI_Scatterv(rhs,localrhs_size_array,rhs_positions,MPI_DOUBLE,localrhs,localrhssize,MPI_DOUBLE,0,mesh->getXcomm()); // Scatters solution from host back to localrhs (which points to x's data) on all processors +// MPI_Scatterv(rhs,localrhs_size_array,rhs_positions,MPI_DOUBLE,localrhs,localrhssize,MPI_DOUBLE,0,localmesh->getXcomm()); // Scatters solution from host back to localrhs (which points to x's data) on all processors // // #if CHECK > 0 // msg_stack.pop(); @@ -516,17 +516,17 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc) : // #if CHECK > 0 // msg_stack.push("Laplacian::solve(Field3D)"); // #endif -// int ys = mesh->ystart, ye = mesh->yend; +// int ys = localmesh->ystart, ye = localmesh->yend; // -// if(mesh->hasBndryLowerY()) { +// if(localmesh->hasBndryLowerY()) { // if (include_yguards) // ys = 0; // Mesh contains a lower boundary and we are solving in the guard cells // // ys += extra_yguards_lower; // } -// if(mesh->hasBndryUpperY()) { +// if(localmesh->hasBndryUpperY()) { // if (include_yguards) -// ye = mesh->LocalNy-1; // Contains upper boundary and we are solving in the guard cells +// ye = localmesh->LocalNy-1; // Contains upper boundary and we are solving in the guard cells // // ye -= extra_yguards_upper; // } @@ -563,36 +563,38 @@ const FieldPerp LaplaceMumps::solve(const FieldPerp &b, const FieldPerp &x0) { } const FieldPerp LaplaceMumps::solve(const FieldPerp &b) { + ASSERT1(localmesh == b.getMesh()); + int y = b.getIndex(); sol = 0.; sol.setIndex(y); // Set boundary conditions through rhs if needed if (!(inner_boundary_flags & INVERT_RHS)) { - if (mesh->firstX()) - for (int z=0; zLocalNz; z++) - for (int x=mesh->xstart-1; x>=0; x--) { + if (localmesh->firstX()) + for (int z=0; zLocalNz; z++) + for (int x=localmesh->xstart-1; x>=0; x--) { b[x][z]=0.; } } if (!(outer_boundary_flags & INVERT_RHS)) { - if (mesh->lastX()) - for (int z=0; zLocalNz; z++) - for (int x=mesh->xend+1; xLocalNx; x++) { + if (localmesh->lastX()) + for (int z=0; zLocalNz; z++) + for (int x=localmesh->xend+1; xLocalNx; x++) { b[x][z]=0.; } } BoutReal* bdata = *b.getData(); int xs,xe; - if (mesh->firstX()) xs=0; - else xs=mesh->xstart; - if (mesh->lastX()) xe=mesh->LocalNx-1; - else xe=mesh->xend; + if (localmesh->firstX()) xs=0; + else xs=localmesh->xstart; + if (localmesh->lastX()) xe=localmesh->LocalNx-1; + else xe=localmesh->xend; for (int x=xs; x<=xe; x++) - for (int z=0; zLocalNz; z++) - localrhs[(x-xs)*(mesh->LocalNz)+z] = bdata[x*mesh->LocalNz+z]; + for (int z=0; zLocalNz; z++) + localrhs[(x-xs)*(localmesh->LocalNz)+z] = bdata[x*localmesh->LocalNz+z]; MPI_Gatherv(localrhs,localrhssize,MPI_DOUBLE,rhs,localrhs_size_array,rhs_positions,MPI_DOUBLE,0,comm); @@ -602,8 +604,8 @@ const FieldPerp LaplaceMumps::solve(const FieldPerp &b) { BoutReal* soldata = *sol.getData(); for (int x=xs; x<=xe; x++) - for (int z=0; zLocalNz; z++) - soldata[x*mesh->LocalNz+z] = localrhs[(x-xs)*(mesh->LocalNz)+z]; + for (int z=0; zLocalNz; z++) + soldata[x*localmesh->LocalNz+z] = localrhs[(x-xs)*(localmesh->LocalNz)+z]; return sol; } @@ -613,14 +615,14 @@ void LaplaceMumps::solve(BoutReal* rhs, int y) { { Timer timer("mumpssetup"); int i = 0; - Coordinates *coord = mesh->coordinates(location); + Coordinates *coord = localmesh->coordinates(location); // Set Matrix Elements corresponding to index lists created in constructor (x,z) loop over rows - // X=0 to mesh->xstart-1 defines the boundary region of the domain. - if( mesh->firstX() ) - for(int x=0; xxstart; x++) - for(int z=0; zLocalNz; z++) { + // X=0 to localmesh->xstart-1 defines the boundary region of the domain. + if( localmesh->firstX() ) + for(int x=0; xxstart; x++) + for(int z=0; zLocalNz; z++) { // Set values corresponding to nodes adjacent in x if Neumann Boundary Conditions are required. if(inner_boundary_flags & INVERT_AC_GRAD) if( fourth_order ) { @@ -653,8 +655,8 @@ void LaplaceMumps::solve(BoutReal* rhs, int y) { } // Main domain with Laplacian operator - for(int x=mesh->xstart; x <= mesh->xend; x++) - for(int z=0; zLocalNz; z++) { + for(int x=localmesh->xstart; x <= localmesh->xend; x++) + for(int z=0; zLocalNz; z++) { BoutReal A0, A1, A2, A3, A4, A5; A0 = A[x][y][z]; Coeffs( x, y, z, A1, A2, A3, A4, A5 ); @@ -806,10 +808,10 @@ void LaplaceMumps::solve(BoutReal* rhs, int y) { } } - // X=mesh->xend+1 to mesh->LocalNx-1 defines the upper boundary region of the domain. - if( mesh->lastX() ) - for(int x=mesh->xend+1; xLocalNx; x++) - for(int z=0; zLocalNz; z++) { + // X=localmesh->xend+1 to localmesh->LocalNx-1 defines the upper boundary region of the domain. + if( localmesh->lastX() ) + for(int x=localmesh->xend+1; xLocalNx; x++) + for(int z=0; zLocalNz; z++) { // Set values corresponding to nodes adjacent in x if Neumann Boundary Conditions are required. if(outer_boundary_flags & INVERT_AC_GRAD) { @@ -856,7 +858,7 @@ void LaplaceMumps::solve(BoutReal* rhs, int y) { void LaplaceMumps::Coeffs( int x, int y, int z, BoutReal &coef1, BoutReal &coef2, BoutReal &coef3, BoutReal &coef4, BoutReal &coef5 ) { - Coordinates *coord = mesh->coordinates(location); + Coordinates *coord = localmesh->coordinates(location); coef1 = coord->g11[x][y]; // X 2nd derivative coefficient coef2 = coord->g33[x][y]; // Z 2nd derivative coefficient @@ -872,7 +874,7 @@ void LaplaceMumps::Coeffs( int x, int y, int z, BoutReal &coef1, BoutReal &coef2 if(nonuniform) { // non-uniform mesh correction - if((x != 0) && (x != (mesh->LocalNx-1))) + if((x != 0) && (x != (localmesh->LocalNx-1))) { //coef4 += coord->g11[jx][jy]*0.25*( (1.0/dx[jx+1][jy]) - (1.0/dx[jx-1][jy]) )/dx[jx][jy]; // SHOULD BE THIS (?) //coef4 -= 0.5 * ( ( coord->dx[x+1][y] - coord->dx[x-1][y] ) / SQ ( coord->dx[x][y] ) ) * coef1; // BOUT-06 term @@ -893,8 +895,8 @@ void LaplaceMumps::Coeffs( int x, int y, int z, BoutReal &coef1, BoutReal &coef2 // A second/fourth order derivative term if (issetC) { -// if( (x > 0) && (x < (mesh->LocalNx-1)) ) //Valid if doing second order derivative, not if fourth: should only be called for xstart<=x<=xend anyway - if( (x > 1) && (x < (mesh->LocalNx-2)) ) { +// if( (x > 0) && (x < (localmesh->LocalNx-1)) ) //Valid if doing second order derivative, not if fourth: should only be called for xstart<=x<=xend anyway + if( (x > 1) && (x < (localmesh->LocalNx-2)) ) { int zp = z+1; if (zp > meshz-1) zp -= meshz; int zm = z-1; diff --git a/src/invert/laplace/impls/mumps/mumps_laplace.hxx b/src/invert/laplace/impls/mumps/mumps_laplace.hxx index bac607afa0..6c37e63fa9 100644 --- a/src/invert/laplace/impls/mumps/mumps_laplace.hxx +++ b/src/invert/laplace/impls/mumps/mumps_laplace.hxx @@ -36,7 +36,7 @@ class LaplaceMumps; class LaplaceMumps : public Laplacian { public: - LaplaceMumps(Options *UNUSED(opt) = nullptr, const CELL_LOC UNUSED(loc) = CELL_CENTRE) { + LaplaceMumps(Options *UNUSED(opt) = nullptr, const CELL_LOC UNUSED(loc) = CELL_CENTRE, Mesh *UNUSED(mesh_in) = mesh) { throw BoutException("Mumps library not available"); } @@ -76,7 +76,7 @@ public: class LaplaceMumps : public Laplacian { public: - LaplaceMumps(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); + LaplaceMumps(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); ~LaplaceMumps() { mumps_struc.job = -2; dmumps_c(&mumps_struc); @@ -88,72 +88,86 @@ public: void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); A = val; } void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C1 = val; C2 = val; issetC = true; } void setCoefC1(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C1 = val; issetC = true; } void setCoefC2(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C2 = val; issetC = true; } void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); D = val; issetD = true; } void setCoefEx(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Ex = val; issetE = true; } void setCoefEz(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Ez = val; issetE = true; } void setCoefA(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); A = val; } void setCoefC(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C1 = val; C2 = val; issetC = true; } void setCoefC1(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C1 = val; issetC = true; } void setCoefC2(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C2 = val; issetC = true; } void setCoefD(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); D = val; issetD = true; } void setCoefEx(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Ex = val; issetE = true; } void setCoefEz(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Ez = val; issetE = true; } diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index 81e1297899..87e1093a61 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -120,8 +120,8 @@ #include "naulin_laplace.hxx" -LaplaceNaulin::LaplaceNaulin(Options *opt, const CELL_LOC loc) - : Laplacian(opt, loc), Acoef(0.0), C1coef(1.0), C2coef(0.0), Dcoef(1.0), +LaplaceNaulin::LaplaceNaulin(Options *opt, const CELL_LOC loc, Mesh *mesh_in) + : Laplacian(opt, loc, mesh_in), Acoef(0.0), C1coef(1.0), C2coef(0.0), Dcoef(1.0), delp2solver(nullptr), naulinsolver_mean_its(0.), ncalls(0) { ASSERT1(opt != nullptr); // An Options pointer should always be passed in by LaplaceFactory @@ -135,7 +135,7 @@ LaplaceNaulin::LaplaceNaulin(Options *opt, const CELL_LOC loc) OPTION(opt, rtol, 1.e-7); OPTION(opt, atol, 1.e-20); OPTION(opt, maxits, 100); - delp2solver = create(opt->getSection("delp2solver"), location); + delp2solver = create(opt->getSection("delp2solver"), location, localmesh); std::string delp2type; opt->getSection("delp2solver")->get("type", delp2type, "cyclic"); // Check delp2solver is using an FFT scheme, otherwise it will not exactly @@ -170,8 +170,8 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { ASSERT1(C1coef.getLocation() == location); ASSERT1(C2coef.getLocation() == location); ASSERT1(Acoef.getLocation() == location); + ASSERT1(localmesh == rhs.getMesh() && localmesh == x0.getMesh()); - Mesh *mesh = rhs.getMesh(); Coordinates *coords = rhs.getCoordinates(); Field3D x(x0); // Result @@ -203,12 +203,12 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { if ( (inner_boundary_flags & INVERT_SET) || (outer_boundary_flags & INVERT_SET) ) // This passes in the boundary conditions from x0's guard cells - copy_x_boundaries(x, x0, mesh); + copy_x_boundaries(x, x0, localmesh); // NB need to pass x in case boundary flags require 'x0', even if // delp2solver is not iterative and does not use an initial guess x = delp2solver->solve(b, x); - mesh->communicate(x); + localmesh->communicate(x); // re-calculate the rhs from the new solution // Use here to calculate an error, can also use for the next iteration @@ -233,17 +233,17 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { return x; } -void LaplaceNaulin::copy_x_boundaries(Field3D &x, const Field3D &x0, Mesh *mesh) { - if (mesh->firstX()) { - for (int i=mesh->xstart-1; i>=0; i--) - for (int j=mesh->ystart; j<=mesh->yend; j++) - for (int k=0; kLocalNz; k++) +void LaplaceNaulin::copy_x_boundaries(Field3D &x, const Field3D &x0, Mesh *localmesh) { + if (localmesh->firstX()) { + for (int i=localmesh->xstart-1; i>=0; i--) + for (int j=localmesh->ystart; j<=localmesh->yend; j++) + for (int k=0; kLocalNz; k++) x(i, j, k) = x0(i, j, k); } - if (mesh->lastX()) { - for (int i=mesh->xend+1; iLocalNx; i++) - for (int j=mesh->ystart; j<=mesh->yend; j++) - for (int k=0; kLocalNz; k++) + if (localmesh->lastX()) { + for (int i=localmesh->xend+1; iLocalNx; i++) + for (int j=localmesh->ystart; j<=localmesh->yend; j++) + for (int k=0; kLocalNz; k++) x(i, j, k) = x0(i, j, k); } } diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.hxx b/src/invert/laplace/impls/naulin/naulin_laplace.hxx index c8d2e8c359..b58d63f678 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.hxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.hxx @@ -37,7 +37,7 @@ class LaplaceNaulin; */ class LaplaceNaulin : public Laplacian { public: - LaplaceNaulin(Options *opt = NULL, const CELL_LOC loc = CELL_CENTRE); + LaplaceNaulin(Options *opt = NULL, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); ~LaplaceNaulin(); // ACoef is not implemented because the delp2solver that we use can probably @@ -45,44 +45,54 @@ public: // where we allow Dcoef to be a Field3D void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Acoef = val; } void setCoefA(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Acoef = val; } void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); setCoefC1(val); setCoefC2(val); } void setCoefC(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); setCoefC1(val); setCoefC2(val); } void setCoefC1(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C1coef = val; } void setCoefC1(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C1coef = val; } void setCoefC2(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C2coef = val; } void setCoefC2(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C2coef = val; } void setCoefD(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Dcoef = val; } void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Dcoef = val; } void setCoefEx(const Field2D &UNUSED(val)) override { diff --git a/src/invert/laplace/impls/pdd/pdd.cxx b/src/invert/laplace/impls/pdd/pdd.cxx index f71b551ccb..4a2fbbf46a 100644 --- a/src/invert/laplace/impls/pdd/pdd.cxx +++ b/src/invert/laplace/impls/pdd/pdd.cxx @@ -39,9 +39,11 @@ #include "pdd.hxx" const FieldPerp LaplacePDD::solve(const FieldPerp &b) { + ASSERT1(localmesh == b.getMesh()); + PDD_data data; - FieldPerp x(b.getMesh()); + FieldPerp x(localmesh); x.allocate(); start(b, data); @@ -52,17 +54,18 @@ const FieldPerp LaplacePDD::solve(const FieldPerp &b) { } const Field3D LaplacePDD::solve(const Field3D &b) { - Mesh *mesh = b.getMesh(); - Field3D x(mesh); + ASSERT1(localmesh == b.getMesh()); + + Field3D x(localmesh); x.allocate(); - FieldPerp xperp(mesh); + FieldPerp xperp(localmesh); xperp.allocate(); - int ys = mesh->ystart, ye = mesh->yend; - if(mesh->hasBndryLowerY()) + int ys = localmesh->ystart, ye = localmesh->yend; + if(localmesh->hasBndryLowerY()) ys = 0; // Mesh contains a lower boundary - if(mesh->hasBndryUpperY()) - ye = mesh->LocalNy-1; // Contains upper boundary + if(localmesh->hasBndryUpperY()) + ye = localmesh->LocalNy-1; // Contains upper boundary if(low_mem) { // Solve one slice at a time @@ -110,37 +113,38 @@ const Field3D LaplacePDD::solve(const Field3D &b) { /// @param[in] b RHS values (Ax = b) /// @param[in] data Internal data used for multiple calls in parallel mode void LaplacePDD::start(const FieldPerp &b, PDD_data &data) { + ASSERT1(localmesh == b.getMesh()); + int ix, kz; - Mesh *mesh = b.getMesh(); - int ncz = mesh->LocalNz; + int ncz = localmesh->LocalNz; data.jy = b.getIndex(); - if(mesh->firstX() && mesh->lastX()) + if(localmesh->firstX() && localmesh->lastX()) throw BoutException("Error: PDD method only works for NXPE > 1\n"); - if(mesh->periodicX) { - throw BoutException("LaplacePDD does not work with periodicity in the x direction (mesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); + if(localmesh->periodicX) { + throw BoutException("LaplacePDD does not work with periodicity in the x direction (localmesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); } if (data.bk.empty()) { // Need to allocate working memory // RHS vector - data.bk = Matrix(maxmode + 1, mesh->LocalNx); + data.bk = Matrix(maxmode + 1, localmesh->LocalNx); // Matrix to be solved - data.avec = Matrix(maxmode + 1, mesh->LocalNx); - data.bvec = Matrix(maxmode + 1, mesh->LocalNx); - data.cvec = Matrix(maxmode + 1, mesh->LocalNx); + data.avec = Matrix(maxmode + 1, localmesh->LocalNx); + data.bvec = Matrix(maxmode + 1, localmesh->LocalNx); + data.cvec = Matrix(maxmode + 1, localmesh->LocalNx); // Working vectors - data.v = Matrix(maxmode + 1, mesh->LocalNx); - data.w = Matrix(maxmode + 1, mesh->LocalNx); + data.v = Matrix(maxmode + 1, localmesh->LocalNx); + data.w = Matrix(maxmode + 1, localmesh->LocalNx); // Result - data.xk = Matrix(maxmode + 1, mesh->LocalNx); + data.xk = Matrix(maxmode + 1, localmesh->LocalNx); // Communication buffers. Space for 2 complex values for each kz data.snd = Array(4 * (maxmode + 1)); @@ -152,7 +156,7 @@ void LaplacePDD::start(const FieldPerp &b, PDD_data &data) { /// Take FFTs of data Array bk1d(ncz / 2 + 1); ///< 1D in Z for taking FFTs - for(ix=0; ix < mesh->LocalNx; ix++) { + for(ix=0; ix < localmesh->LocalNx; ix++) { rfft(b[ix], ncz, std::begin(bk1d)); for(kz = 0; kz <= maxmode; kz++) data.bk(kz, ix) = bk1d[kz]; @@ -160,7 +164,7 @@ void LaplacePDD::start(const FieldPerp &b, PDD_data &data) { /// Create the matrices to be inverted (one for each z point) - BoutReal kwaveFactor = 2.0 * PI / mesh->getCoordinates(location)->zlength(); + BoutReal kwaveFactor = 2.0 * PI / localmesh->getCoordinates(location)->zlength(); /// Set matrix elements for (int kz = 0; kz <= maxmode; kz++) { @@ -169,8 +173,8 @@ void LaplacePDD::start(const FieldPerp &b, PDD_data &data) { outer_boundary_flags, &Acoef, &Ccoef, &Dcoef); } - Array e(mesh->LocalNx); - for (ix = 0; ix < mesh->LocalNx; ix++) + Array e(localmesh->LocalNx); + for (ix = 0; ix < localmesh->LocalNx; ix++) e[ix] = 0.0; // Do we need this? for(kz = 0; kz <= maxmode; kz++) { @@ -180,51 +184,51 @@ void LaplacePDD::start(const FieldPerp &b, PDD_data &data) { dcomplex v0, x0; // Values to be sent to processor i-1 - if(mesh->firstX()) { + if(localmesh->firstX()) { // Domain includes inner boundary tridag(&data.avec(kz, 0), &data.bvec(kz, 0), &data.cvec(kz, 0), &data.bk(kz, 0), - &data.xk(kz, 0), mesh->xend + 1); + &data.xk(kz, 0), localmesh->xend + 1); // Add C (row m-1) from next processor - e[mesh->xend] = data.cvec(kz, mesh->xend); + e[localmesh->xend] = data.cvec(kz, localmesh->xend); tridag(&data.avec(kz, 0), &data.bvec(kz, 0), &data.cvec(kz, 0), std::begin(e), - &data.w(kz, 0), mesh->xend + 1); + &data.w(kz, 0), localmesh->xend + 1); - }else if(mesh->lastX()) { + }else if(localmesh->lastX()) { // Domain includes outer boundary - tridag(&data.avec(kz, mesh->xstart), &data.bvec(kz, mesh->xstart), - &data.cvec(kz, mesh->xstart), &data.bk(kz, mesh->xstart), - &data.xk(kz, mesh->xstart), mesh->xend - mesh->xend + 1); + tridag(&data.avec(kz, localmesh->xstart), &data.bvec(kz, localmesh->xstart), + &data.cvec(kz, localmesh->xstart), &data.bk(kz, localmesh->xstart), + &data.xk(kz, localmesh->xstart), localmesh->xend - localmesh->xend + 1); // Add A (row 0) from previous processor - e[0] = data.avec(kz, mesh->xstart); - tridag(&data.avec(kz, mesh->xstart), &data.bvec(kz, mesh->xstart), - &data.cvec(kz, mesh->xstart), std::begin(e), &data.v(kz, mesh->xstart), - mesh->xend + 1); + e[0] = data.avec(kz, localmesh->xstart); + tridag(&data.avec(kz, localmesh->xstart), &data.bvec(kz, localmesh->xstart), + &data.cvec(kz, localmesh->xstart), std::begin(e), &data.v(kz, localmesh->xstart), + localmesh->xend + 1); - x0 = data.xk(kz, mesh->xstart); - v0 = data.v(kz, mesh->xstart); + x0 = data.xk(kz, localmesh->xstart); + v0 = data.v(kz, localmesh->xstart); }else { // No boundaries - tridag(&data.avec(kz, mesh->xstart), &data.bvec(kz, mesh->xstart), - &data.cvec(kz, mesh->xstart), &data.bk(kz, mesh->xstart), - &data.xk(kz, mesh->xstart), mesh->xend - mesh->xstart + 1); + tridag(&data.avec(kz, localmesh->xstart), &data.bvec(kz, localmesh->xstart), + &data.cvec(kz, localmesh->xstart), &data.bk(kz, localmesh->xstart), + &data.xk(kz, localmesh->xstart), localmesh->xend - localmesh->xstart + 1); // Add A (row 0) from previous processor - e[0] = data.avec(kz, mesh->xstart); - tridag(&data.avec(kz, mesh->xstart), &data.bvec(kz, mesh->xstart), - &data.cvec(kz, mesh->xstart), &e[mesh->xstart], &data.v(kz, mesh->xstart), - mesh->xend - mesh->xstart + 1); + e[0] = data.avec(kz, localmesh->xstart); + tridag(&data.avec(kz, localmesh->xstart), &data.bvec(kz, localmesh->xstart), + &data.cvec(kz, localmesh->xstart), &e[localmesh->xstart], &data.v(kz, localmesh->xstart), + localmesh->xend - localmesh->xstart + 1); e[0] = 0.0; // Add C (row m-1) from next processor - e[mesh->xend] = data.cvec(kz, mesh->xend); - tridag(&data.avec(kz, mesh->xstart), &data.bvec(kz, mesh->xstart), - &data.cvec(kz, mesh->xstart), &e[mesh->xstart], &data.v(kz, mesh->xstart), - mesh->xend - mesh->xstart + 1); - e[mesh->xend] = 0.0; + e[localmesh->xend] = data.cvec(kz, localmesh->xend); + tridag(&data.avec(kz, localmesh->xstart), &data.bvec(kz, localmesh->xstart), + &data.cvec(kz, localmesh->xstart), &e[localmesh->xstart], &data.v(kz, localmesh->xstart), + localmesh->xend - localmesh->xstart + 1); + e[localmesh->xend] = 0.0; } // Put values into communication buffers @@ -236,17 +240,17 @@ void LaplacePDD::start(const FieldPerp &b, PDD_data &data) { // Stage 3: Communicate x0, v0 from node i to i-1 - if(!mesh->lastX()) { + if(!localmesh->lastX()) { // All except the last processor expect to receive data // Post async receive data.recv_handle = - mesh->irecvXOut(std::begin(data.rcv), 4 * (maxmode + 1), PDD_COMM_XV); + localmesh->irecvXOut(std::begin(data.rcv), 4 * (maxmode + 1), PDD_COMM_XV); } - if(!mesh->firstX()) { + if(!localmesh->firstX()) { // Send the data - mesh->sendXIn(std::begin(data.snd), 4 * (maxmode + 1), PDD_COMM_XV); + localmesh->sendXIn(std::begin(data.snd), 4 * (maxmode + 1), PDD_COMM_XV); } } @@ -255,8 +259,8 @@ void LaplacePDD::start(const FieldPerp &b, PDD_data &data) { void LaplacePDD::next(PDD_data &data) { // Wait for x0 and v0 to arrive from processor i+1 - if(!mesh->lastX()) { - mesh->wait(data.recv_handle); + if(!localmesh->lastX()) { + localmesh->wait(data.recv_handle); /*! Now solving on all except the last processor * @@ -273,18 +277,18 @@ void LaplacePDD::next(PDD_data &data) { x0 = dcomplex(data.rcv[4*kz], data.rcv[4*kz+1]); v0 = dcomplex(data.rcv[4*kz+2], data.rcv[4*kz+3]); - data.y2i[kz] = (data.xk(kz, mesh->xend) - data.w(kz, mesh->xend) * x0) / - (1. - data.w(kz, mesh->xend) * v0); + data.y2i[kz] = (data.xk(kz, localmesh->xend) - data.w(kz, localmesh->xend) * x0) / + (1. - data.w(kz, localmesh->xend) * v0); } } - if(!mesh->firstX()) { + if(!localmesh->firstX()) { // All except pe=0 receive values from i-1. Posting async receive data.recv_handle = - mesh->irecvXIn(std::begin(data.rcv), 2 * (maxmode + 1), PDD_COMM_Y); + localmesh->irecvXIn(std::begin(data.rcv), 2 * (maxmode + 1), PDD_COMM_Y); } - if(!mesh->lastX()) { + if(!localmesh->lastX()) { // Send value to the (i+1)th processor for(int kz = 0; kz <= maxmode; kz++) { @@ -292,7 +296,7 @@ void LaplacePDD::next(PDD_data &data) { data.snd[2*kz+1] = data.y2i[kz].imag(); } - mesh->sendXOut(std::begin(data.snd), 2 * (maxmode + 1), PDD_COMM_Y); + localmesh->sendXOut(std::begin(data.snd), 2 * (maxmode + 1), PDD_COMM_Y); } } @@ -303,32 +307,32 @@ void LaplacePDD::finish(PDD_data &data, FieldPerp &x) { x.allocate(); x.setIndex(data.jy); - if(!mesh->lastX()) { + if(!localmesh->lastX()) { for(kz = 0; kz <= maxmode; kz++) { - for(ix=0; ix < mesh->LocalNx; ix++) + for(ix=0; ix < localmesh->LocalNx; ix++) data.xk(kz, ix) -= data.w(kz, ix) * data.y2i[kz]; } } - if(!mesh->firstX()) { - mesh->wait(data.recv_handle); + if(!localmesh->firstX()) { + localmesh->wait(data.recv_handle); for(kz = 0; kz <= maxmode; kz++) { dcomplex y2m = dcomplex(data.rcv[2*kz], data.rcv[2*kz+1]); - for(ix=0; ix < mesh->LocalNx; ix++) + for(ix=0; ix < localmesh->LocalNx; ix++) data.xk(kz, ix) -= data.v(kz, ix) * y2m; } } // Have result in Fourier space. Convert back to BoutReal space - int ncz = mesh->LocalNz; + int ncz = localmesh->LocalNz; Array xk1d(ncz / 2 + 1); ///< 1D in Z for taking FFTs for (kz = maxmode; kz <= ncz / 2; kz++) xk1d[kz] = 0.0; - for(ix=0; ixLocalNx; ix++){ + for(ix=0; ixLocalNx; ix++){ for(kz = 0; kz <= maxmode; kz++) { xk1d[kz] = data.xk(kz, ix); diff --git a/src/invert/laplace/impls/pdd/pdd.hxx b/src/invert/laplace/impls/pdd/pdd.hxx index e9fdccf342..0dff1dd6e0 100644 --- a/src/invert/laplace/impls/pdd/pdd.hxx +++ b/src/invert/laplace/impls/pdd/pdd.hxx @@ -40,8 +40,8 @@ class LaplacePDD; class LaplacePDD : public Laplacian { public: - LaplacePDD(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE) - : Laplacian(opt, loc), Acoef(0.0), Ccoef(1.0), Dcoef(1.0), PDD_COMM_XV(123), + LaplacePDD(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh) + : Laplacian(opt, loc, mesh_in), Acoef(0.0), Ccoef(1.0), Dcoef(1.0), PDD_COMM_XV(123), PDD_COMM_Y(456) { Acoef.setLocation(location); Ccoef.setLocation(location); @@ -52,16 +52,19 @@ public: using Laplacian::setCoefA; void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Acoef = val; } using Laplacian::setCoefC; void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Ccoef = val; } using Laplacian::setCoefD; void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Dcoef = val; } using Laplacian::setCoefEx; diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.cxx b/src/invert/laplace/impls/petsc/petsc_laplace.cxx index 27f01a3161..1555345456 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.cxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.cxx @@ -57,8 +57,8 @@ static PetscErrorCode laplacePCapply(PC pc,Vec x,Vec y) { PetscFunctionReturn(s->precon(x, y)); } -LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc) : - Laplacian(opt, loc), +LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc, Mesh *mesh_in) : + Laplacian(opt, loc, mesh_in), A(0.0), C1(1.0), C2(1.0), D(1.0), Ex(0.0), Ez(0.0), issetD(false), issetC(false), issetE(false) { @@ -92,28 +92,28 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc) : if ( outer_boundary_flags & ~implemented_boundary_flags ) { throw BoutException("Attempted to set Laplacian inversion boundary flag that is not implemented in petsc_laplace.cxx"); } - if(mesh->periodicX) { - throw BoutException("LaplacePetsc does not work with periodicity in the x direction (mesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); + if(localmesh->periodicX) { + throw BoutException("LaplacePetsc does not work with periodicity in the x direction (localmesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); } #endif // Get communicator for group of processors in X - all points in z-x plane for fixed y. - comm = mesh->getXcomm(); + comm = localmesh->getXcomm(); // Need to determine local size to use based on prior parallelisation // Coefficient values are stored only on local processors. - localN = (mesh->xend - mesh->xstart + 1) * (mesh->LocalNz); - if(mesh->firstX()) - localN += mesh->xstart * (mesh->LocalNz); // If on first processor add on width of boundary region - if(mesh->lastX()) - localN += mesh->xstart * (mesh->LocalNz); // If on last processor add on width of boundary region + localN = (localmesh->xend - localmesh->xstart + 1) * (localmesh->LocalNz); + if(localmesh->firstX()) + localN += localmesh->xstart * (localmesh->LocalNz); // If on first processor add on width of boundary region + if(localmesh->lastX()) + localN += localmesh->xstart * (localmesh->LocalNz); // If on last processor add on width of boundary region // Calculate 'size' (the total number of points in physical grid) if(MPI_Allreduce(&localN, &size, 1, MPI_INT, MPI_SUM, comm) != MPI_SUCCESS) throw BoutException("Error in MPI_Allreduce during LaplacePetsc initialisation"); // Calculate total (physical) grid dimensions - meshz = mesh->LocalNz; + meshz = localmesh->LocalNz; meshx = size / meshz; // Create PETSc type of vectors for the solution and the RHS vector @@ -143,43 +143,43 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc) : PetscMalloc( (localN)*sizeof(PetscInt), &d_nnz ); PetscMalloc( (localN)*sizeof(PetscInt), &o_nnz ); if (fourth_order) { - // first and last 2*mesh-LocalNz entries are the edge x-values that (may) have 'off-diagonal' components (i.e. on another processor) - if ( mesh->firstX() && mesh->lastX() ) { - for (int i=0; iLocalNz; i++) { + // first and last 2*localmesh-LocalNz entries are the edge x-values that (may) have 'off-diagonal' components (i.e. on another processor) + if ( localmesh->firstX() && localmesh->lastX() ) { + for (int i=0; iLocalNz; i++) { d_nnz[i]=15; d_nnz[localN-1-i]=15; o_nnz[i]=0; o_nnz[localN-1-i]=0; } - for (int i=(mesh->LocalNz); i<2*(mesh->LocalNz); i++) { + for (int i=(localmesh->LocalNz); i<2*(localmesh->LocalNz); i++) { d_nnz[i]=20; d_nnz[localN-1-i]=20; o_nnz[i]=0; o_nnz[localN-1-i]=0; } } - else if ( mesh->firstX() ) { - for (int i=0; iLocalNz; i++) { + else if ( localmesh->firstX() ) { + for (int i=0; iLocalNz; i++) { d_nnz[i]=15; d_nnz[localN-1-i]=15; o_nnz[i]=0; o_nnz[localN-1-i]=10; } - for (int i=(mesh->LocalNz); i<2*(mesh->LocalNz); i++) { + for (int i=(localmesh->LocalNz); i<2*(localmesh->LocalNz); i++) { d_nnz[i]=20; d_nnz[localN-1-i]=20; o_nnz[i]=0; o_nnz[localN-1-i]=5; } } - else if ( mesh->lastX() ) { - for (int i=0; iLocalNz; i++) { + else if ( localmesh->lastX() ) { + for (int i=0; iLocalNz; i++) { d_nnz[i]=15; d_nnz[localN-1-i]=15; o_nnz[i]=10; o_nnz[localN-1-i]=0; } - for (int i=(mesh->LocalNz); i<2*(mesh->LocalNz); i++) { + for (int i=(localmesh->LocalNz); i<2*(localmesh->LocalNz); i++) { d_nnz[i]=20; d_nnz[localN-1-i]=20; o_nnz[i]=5; @@ -187,13 +187,13 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc) : } } else { - for (int i=0; iLocalNz; i++) { + for (int i=0; iLocalNz; i++) { d_nnz[i]=15; d_nnz[localN-1-i]=15; o_nnz[i]=10; o_nnz[localN-1-i]=10; } - for (int i=(mesh->LocalNz); i<2*(mesh->LocalNz); i++) { + for (int i=(localmesh->LocalNz); i<2*(localmesh->LocalNz); i++) { d_nnz[i]=20; d_nnz[localN-1-i]=20; o_nnz[i]=5; @@ -201,7 +201,7 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc) : } } - for (int i=2*(mesh->LocalNz); iLocalNz));i++) { + for (int i=2*(localmesh->LocalNz); iLocalNz));i++) { d_nnz[i]=25; d_nnz[localN-1-i]=25; o_nnz[i]=0; @@ -209,7 +209,7 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc) : } // Use d_nnz and o_nnz for preallocating the matrix - if (mesh->firstX() && mesh->lastX()) { + if (localmesh->firstX() && localmesh->lastX()) { // Only one processor in X MatSeqAIJSetPreallocation( MatA, 0, d_nnz ); }else { @@ -217,25 +217,25 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc) : } } else { - // first and last mesh-LocalNz entries are the edge x-values that (may) have 'off-diagonal' components (i.e. on another processor) - if ( mesh->firstX() && mesh->lastX() ) { - for (int i=0; iLocalNz; i++) { + // first and last localmesh->LocalNz entries are the edge x-values that (may) have 'off-diagonal' components (i.e. on another processor) + if ( localmesh->firstX() && localmesh->lastX() ) { + for (int i=0; iLocalNz; i++) { d_nnz[i]=6; d_nnz[localN-1-i]=6; o_nnz[i]=0; o_nnz[localN-1-i]=0; } } - else if ( mesh->firstX() ) { - for (int i=0; iLocalNz; i++) { + else if ( localmesh->firstX() ) { + for (int i=0; iLocalNz; i++) { d_nnz[i]=6; d_nnz[localN-1-i]=6; o_nnz[i]=0; o_nnz[localN-1-i]=3; } } - else if ( mesh->lastX() ) { - for (int i=0; iLocalNz; i++) { + else if ( localmesh->lastX() ) { + for (int i=0; iLocalNz; i++) { d_nnz[i]=6; d_nnz[localN-1-i]=6; o_nnz[i]=3; @@ -243,7 +243,7 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc) : } } else { - for (int i=0; iLocalNz; i++) { + for (int i=0; iLocalNz; i++) { d_nnz[i]=6; d_nnz[localN-1-i]=6; o_nnz[i]=3; @@ -251,7 +251,7 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc) : } } - for (int i=mesh->LocalNz; iLocalNz);i++) { + for (int i=localmesh->LocalNz; iLocalNz);i++) { d_nnz[i]=9; d_nnz[localN-1-i]=9; o_nnz[i]=0; @@ -259,7 +259,7 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc) : } // Use d_nnz and o_nnz for preallocating the matrix - if (mesh->firstX() && mesh->lastX()) { + if (localmesh->firstX() && localmesh->lastX()) { MatSeqAIJSetPreallocation( MatA, 0, d_nnz ); } else { MatMPIAIJSetPreallocation( MatA, 0, d_nnz, 0, o_nnz ); @@ -344,6 +344,8 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b) { */ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { TRACE("LaplacePetsc::solve"); + + ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); #if CHECK > 0 // Checking flags are set to something which is not implemented (see @@ -361,7 +363,7 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { #endif // Get the metric tensor - Coordinates* coord = mesh->getCoordinates(location); + Coordinates* coord = localmesh->getCoordinates(location); int y = b.getIndex(); // Get the Y index sol.setIndex(y); // Initialize the solution field. @@ -389,11 +391,11 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { * In other word the indexing is done in a row-major order, but starting at * bottom left rather than top left */ - // X=0 to mesh->xstart-1 defines the boundary region of the domain. + // X=0 to localmesh->xstart-1 defines the boundary region of the domain. // Set the values for the inner boundary region - if( mesh->firstX() ) { - for(int x=0; xxstart; x++) { - for(int z=0; zLocalNz; z++) { + if( localmesh->firstX() ) { + for(int x=0; xxstart; x++) { + for(int z=0; zLocalNz; z++) { PetscScalar val; // Value of element to be set in the matrix // If Neumann Boundary Conditions are set. if(inner_boundary_flags & INVERT_AC_GRAD) { @@ -460,8 +462,8 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { } // Set the values for the main domain - for(int x=mesh->xstart; x <= mesh->xend; x++) { - for(int z=0; zLocalNz; z++) { + for(int x=localmesh->xstart; x <= localmesh->xend; x++) { + for(int z=0; zLocalNz; z++) { // NOTE: Only A0 is the A from setCoefA () BoutReal A0, A1, A2, A3, A4, A5; A0 = A(x,y,z); @@ -635,11 +637,11 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { } } - // X=mesh->xend+1 to mesh->LocalNx-1 defines the upper boundary region of the domain. + // X=localmesh->xend+1 to localmesh->LocalNx-1 defines the upper boundary region of the domain. // Set the values for the outer boundary region - if( mesh->lastX() ) { - for(int x=mesh->xend+1; xLocalNx; x++) { - for(int z=0; zLocalNz; z++) { + if( localmesh->lastX() ) { + for(int x=localmesh->xend+1; xLocalNx; x++) { + for(int z=0; zLocalNz; z++) { // Set Diagonal Values to 1 PetscScalar val = 1; Element(i,x,z, 0, 0, val, MatA ); @@ -803,9 +805,9 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { // Add data to FieldPerp Object i = Istart; // Set the inner boundary values - if(mesh->firstX()) { - for(int x=0; xxstart; x++) { - for(int z=0; zLocalNz; z++) { + if(localmesh->firstX()) { + for(int x=0; xxstart; x++) { + for(int z=0; zLocalNz; z++) { PetscScalar val = 0; VecGetValues(xs, 1, &i, &val ); sol[x][z] = val; @@ -815,8 +817,8 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { } // Set the main domain values - for(int x=mesh->xstart; x <= mesh->xend; x++) { - for(int z=0; zLocalNz; z++) { + for(int x=localmesh->xstart; x <= localmesh->xend; x++) { + for(int z=0; zLocalNz; z++) { PetscScalar val = 0; VecGetValues(xs, 1, &i, &val ); sol[x][z] = val; @@ -825,9 +827,9 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { } // Set the outer boundary values - if(mesh->lastX()) { - for(int x=mesh->xend+1; xLocalNx; x++) { - for(int z=0;z < mesh->LocalNz; z++) { + if(localmesh->lastX()) { + for(int x=localmesh->xend+1; xLocalNx; x++) { + for(int z=0;z < localmesh->LocalNz; z++) { PetscScalar val = 0; VecGetValues(xs, 1, &i, &val ); sol[x][z] = val; @@ -871,7 +873,7 @@ void LaplacePetsc::Element(int i, int x, int z, // Calculate the row to be set int row_new = x + xshift; // should never be out of range. - if( !mesh->firstX() ) row_new += (xoffset - mesh->xstart); + if( !localmesh->firstX() ) row_new += (xoffset - localmesh->xstart); // Calculate the column to be set int col_new = z + zshift; @@ -935,7 +937,7 @@ void LaplacePetsc::Element(int i, int x, int z, */ void LaplacePetsc::Coeffs( int x, int y, int z, BoutReal &coef1, BoutReal &coef2, BoutReal &coef3, BoutReal &coef4, BoutReal &coef5 ) { - Coordinates *coord = mesh->getCoordinates(location); // Get metric tensor + Coordinates *coord = localmesh->getCoordinates(location); // Get metric tensor coef1 = coord->g11(x,y); // X 2nd derivative coefficient coef2 = coord->g33(x,y); // Z 2nd derivative coefficient @@ -954,12 +956,12 @@ void LaplacePetsc::Coeffs( int x, int y, int z, BoutReal &coef1, BoutReal &coef2 if(nonuniform) { // non-uniform mesh correction - if((x != 0) && (x != (mesh->LocalNx-1))) { + if((x != 0) && (x != (localmesh->LocalNx-1))) { coef4 -= 0.5 * ( ( coord->dx(x+1,y) - coord->dx(x-1,y) ) / SQ(coord->dx(x,y)) ) * coef1; // BOUT-06 term } } - if(mesh->IncIntShear) { + if(localmesh->IncIntShear) { // d2dz2 term coef2 += coord->g11(x,y) * coord->IntShiftTorsion(x,y) * coord->IntShiftTorsion(x,y); // Mixed derivative @@ -976,8 +978,8 @@ void LaplacePetsc::Coeffs( int x, int y, int z, BoutReal &coef1, BoutReal &coef2 // A second/fourth order derivative term if (issetC) { -// if( (x > 0) && (x < (mesh->LocalNx-1)) ) //Valid if doing second order derivative, not if fourth: should only be called for xstart<=x<=xend anyway - if( (x > 1) && (x < (mesh->LocalNx-2)) ) { +// if( (x > 0) && (x < (localmesh->LocalNx-1)) ) //Valid if doing second order derivative, not if fourth: should only be called for xstart<=x<=xend anyway + if( (x > 1) && (x < (localmesh->LocalNx-2)) ) { int zp = z+1; // z plus 1 if (zp > meshz-1) zp -= meshz; int zm = z-1; // z minus 1 @@ -1024,13 +1026,16 @@ void LaplacePetsc::Coeffs( int x, int y, int z, BoutReal &coef1, BoutReal &coef2 void LaplacePetsc::vecToField(Vec xs, FieldPerp &f) { + + ASSERT1(localmesh == f.getMesh()); + f.allocate(); int i = Istart; - if(mesh->firstX()) + if(localmesh->firstX()) { - for(int x=0; xxstart; x++) + for(int x=0; xxstart; x++) { - for(int z=0; zLocalNz; z++) + for(int z=0; zLocalNz; z++) { PetscScalar val; VecGetValues(xs, 1, &i, &val ); @@ -1040,9 +1045,9 @@ void LaplacePetsc::vecToField(Vec xs, FieldPerp &f) { } } - for(int x=mesh->xstart; x <= mesh->xend; x++) + for(int x=localmesh->xstart; x <= localmesh->xend; x++) { - for(int z=0; zLocalNz; z++) + for(int z=0; zLocalNz; z++) { PetscScalar val; VecGetValues(xs, 1, &i, &val ); @@ -1051,11 +1056,11 @@ void LaplacePetsc::vecToField(Vec xs, FieldPerp &f) { } } - if(mesh->lastX()) + if(localmesh->lastX()) { - for(int x=mesh->xend+1; xLocalNx; x++) + for(int x=localmesh->xend+1; xLocalNx; x++) { - for(int z=0;z < mesh->LocalNz; z++) + for(int z=0;z < localmesh->LocalNz; z++) { PetscScalar val; VecGetValues(xs, 1, &i, &val ); @@ -1068,10 +1073,12 @@ void LaplacePetsc::vecToField(Vec xs, FieldPerp &f) { } void LaplacePetsc::fieldToVec(const FieldPerp &f, Vec bs) { + ASSERT1(localmesh == f.getMesh()); + int i = Istart; - if(mesh->firstX()) { - for(int x=0; xxstart; x++) { - for(int z=0; zLocalNz; z++) { + if(localmesh->firstX()) { + for(int x=0; xxstart; x++) { + for(int z=0; zLocalNz; z++) { PetscScalar val = f[x][z]; VecSetValues( bs, 1, &i, &val, INSERT_VALUES ); i++; // Increment row in Petsc matrix @@ -1079,17 +1086,17 @@ void LaplacePetsc::fieldToVec(const FieldPerp &f, Vec bs) { } } - for(int x=mesh->xstart; x <= mesh->xend; x++) { - for(int z=0; zLocalNz; z++) { + for(int x=localmesh->xstart; x <= localmesh->xend; x++) { + for(int z=0; zLocalNz; z++) { PetscScalar val = f[x][z]; VecSetValues( bs, 1, &i, &val, INSERT_VALUES ); i++; // Increment row in Petsc matrix } } - if(mesh->lastX()) { - for(int x=mesh->xend+1; xLocalNx; x++) { - for(int z=0;z < mesh->LocalNz; z++) { + if(localmesh->lastX()) { + for(int x=localmesh->xend+1; xLocalNx; x++) { + for(int z=0;z < localmesh->LocalNz; z++) { PetscScalar val = f[x][z]; VecSetValues( bs, 1, &i, &val, INSERT_VALUES ); i++; // Increment row in Petsc matrix diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.hxx b/src/invert/laplace/impls/petsc/petsc_laplace.hxx index 919be782bc..61b094ace2 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.hxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.hxx @@ -37,7 +37,7 @@ class LaplacePetsc; class LaplacePetsc : public Laplacian { public: - LaplacePetsc(Options *UNUSED(opt) = nullptr, const CELL_LOC UNUSED(loc) = CELL_CENTRE) { + LaplacePetsc(Options *UNUSED(opt) = nullptr, const CELL_LOC UNUSED(loc) = CELL_CENTRE, Mesh *UNUSED(mesh_in) = mesh) { throw BoutException("No PETSc solver available"); } @@ -68,7 +68,7 @@ public: class LaplacePetsc : public Laplacian { public: - LaplacePetsc(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); + LaplacePetsc(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); ~LaplacePetsc() { KSPDestroy( &ksp ); VecDestroy( &xs ); @@ -78,12 +78,14 @@ public: void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); A = val; /*Acoefchanged = true;*/ if(pcsolve) pcsolve->setCoefA(val); } void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C1 = val; C2 = val; issetC = true; /*coefchanged = true;*/ @@ -91,28 +93,33 @@ public: } void setCoefC1(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C1 = val; issetC = true; } void setCoefC2(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C2 = val; issetC = true; } void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); D = val; issetD = true; /*coefchanged = true;*/ if(pcsolve) pcsolve->setCoefD(val); } void setCoefEx(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Ex = val; issetE = true; /*coefchanged = true;*/ if(pcsolve) pcsolve->setCoefEx(val); } void setCoefEz(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Ez = val; issetE = true; /*coefchanged = true;*/ if(pcsolve) pcsolve->setCoefEz(val); @@ -120,12 +127,14 @@ public: void setCoefA(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); A = val; /*Acoefchanged = true;*/ if(pcsolve) pcsolve->setCoefA(val); } void setCoefC(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C1 = val; C2 = val; issetC = true; /*coefchanged = true;*/ @@ -133,28 +142,33 @@ public: } void setCoefC1(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C1 = val; issetC = true; } void setCoefC2(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); C2 = val; issetC = true; } void setCoefD(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); D = val; issetD = true; /*coefchanged = true;*/ if(pcsolve) pcsolve->setCoefD(val); } void setCoefEx(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Ex = val; issetE = true; /*coefchanged = true;*/ if(pcsolve) pcsolve->setCoefEx(val); } void setCoefEz(const Field3D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); Ez = val; issetE = true; /*coefchanged = true;*/ if(pcsolve) pcsolve->setCoefEz(val); diff --git a/src/invert/laplace/impls/serial_band/serial_band.cxx b/src/invert/laplace/impls/serial_band/serial_band.cxx index f2dfa04a66..b9541bf867 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.cxx +++ b/src/invert/laplace/impls/serial_band/serial_band.cxx @@ -38,40 +38,41 @@ //#define SECONDORDER // Define to use 2nd order differencing -LaplaceSerialBand::LaplaceSerialBand(Options *opt, const CELL_LOC loc) : Laplacian(opt, loc), Acoef(0.0), Ccoef(1.0), Dcoef(1.0) { +LaplaceSerialBand::LaplaceSerialBand(Options *opt, const CELL_LOC loc, Mesh *mesh_in) + : Laplacian(opt, loc, mesh_in), Acoef(0.0), Ccoef(1.0), Dcoef(1.0) { Acoef.setLocation(location); Ccoef.setLocation(location); Dcoef.setLocation(location); - if(!mesh->firstX() || !mesh->lastX()) - throw BoutException("LaplaceSerialBand only works for mesh->NXPE = 1"); - if(mesh->periodicX) { - throw BoutException("LaplaceSerialBand does not work with periodicity in the x direction (mesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); + if(!localmesh->firstX() || !localmesh->lastX()) + throw BoutException("LaplaceSerialBand only works for localmesh->NXPE = 1"); + if(localmesh->periodicX) { + throw BoutException("LaplaceSerialBand does not work with periodicity in the x direction (localmesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); } // Allocate memory - int ncz = mesh->LocalNz; - bk = Matrix(mesh->LocalNx, ncz / 2 + 1); - bk1d = Array(mesh->LocalNx); + int ncz = localmesh->LocalNz; + bk = Matrix(localmesh->LocalNx, ncz / 2 + 1); + bk1d = Array(localmesh->LocalNx); //Initialise bk to 0 as we only visit 0<= kz <= maxmode in solve for(int kz=maxmode+1; kz < ncz/2 + 1; kz++){ - for (int ix=0; ixLocalNx; ix++){ + for (int ix=0; ixLocalNx; ix++){ bk(ix, kz) = 0.0; } } - xk = Matrix(mesh->LocalNx, ncz / 2 + 1); - xk1d = Array(mesh->LocalNx); + xk = Matrix(localmesh->LocalNx, ncz / 2 + 1); + xk1d = Array(localmesh->LocalNx); //Initialise xk to 0 as we only visit 0<= kz <= maxmode in solve for(int kz=maxmode+1; kz < ncz/2 + 1; kz++){ - for (int ix=0; ixLocalNx; ix++){ + for (int ix=0; ixLocalNx; ix++){ xk(ix, kz) = 0.0; } } - A = Matrix(mesh->LocalNx, 5); + A = Matrix(localmesh->LocalNx, 5); } const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b) { @@ -79,25 +80,26 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b) { } const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0) { - Mesh *mesh = b.getMesh(); - FieldPerp x(mesh); + ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); + + FieldPerp x(localmesh); x.allocate(); int jy = b.getIndex(); x.setIndex(jy); - Coordinates *coord = mesh->getCoordinates(location); + Coordinates *coord = localmesh->getCoordinates(location); - int ncz = mesh->LocalNz; - int ncx = mesh->LocalNx-1; + int ncz = localmesh->LocalNz; + int ncx = localmesh->LocalNx-1; - int xbndry = mesh->xstart; // Width of the x boundary + int xbndry = localmesh->xstart; // Width of the x boundary // If the flags to assign that only one guard cell should be used is set - if((global_flags & INVERT_BOTH_BNDRY_ONE) || (mesh->xstart < 2)) + if((global_flags & INVERT_BOTH_BNDRY_ONE) || (localmesh->xstart < 2)) xbndry = 1; BOUT_OMP(parallel for) - for(int ix=0;ixLocalNx;ix++) { + for(int ix=0;ixLocalNx;ix++) { // for fixed ix,jy set a complex vector rho(z) if(((ix < xbndry) && (inner_boundary_flags & INVERT_SET)) || @@ -115,7 +117,7 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 xend = ncx-xbndry; }else { xstart = 2; - xend = mesh->LocalNx-2; + xend = localmesh->LocalNx-2; } for(int iz=0;iz<=maxmode;iz++) { @@ -129,7 +131,7 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 kwave=iz*2.0*PI/coord->zlength(); // wave number is 1/[rad] // set bk1d - for(int ix=0;ixLocalNx;ix++) + for(int ix=0;ixLocalNx;ix++) bk1d[ix] = bk(ix, iz); // Fill in interior points @@ -166,14 +168,14 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 } if(nonuniform) { - // non-uniform mesh correction + // non-uniform localmesh correction if((ix != 0) && (ix != ncx)) coef4 += coord->g11(ix,jy)*( (1.0/coord->dx(ix+1,jy)) - (1.0/coord->dx(ix-1,jy)) )/(2.0*coord->dx(ix,jy)); } // A first order derivative term (1/c)\nabla_perp c\cdot\nabla_\perp x - if((ix > 1) && (ix < (mesh->LocalNx-2))) + if((ix > 1) && (ix < (localmesh->LocalNx-2))) coef4 += coord->g11(ix,jy) * (Ccoef(ix-2,jy) - 8.*Ccoef(ix-1,jy) + 8.*Ccoef(ix+1,jy) - Ccoef(ix+2,jy)) / (12.*coord->dx(ix,jy)*(Ccoef(ix,jy))); // Put into matrix @@ -392,7 +394,7 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 } // Perform inversion - cband_solve(A, mesh->LocalNx, 2, 2, bk1d); + cband_solve(A, localmesh->LocalNx, 2, 2, bk1d); if((global_flags & INVERT_KX_ZERO) && (iz == 0)) { // Set the Kx = 0, n = 0 component to zero. For now just subtract diff --git a/src/invert/laplace/impls/serial_band/serial_band.hxx b/src/invert/laplace/impls/serial_band/serial_band.hxx index 7051b5925d..05a7649e32 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.hxx +++ b/src/invert/laplace/impls/serial_band/serial_band.hxx @@ -36,22 +36,25 @@ class LaplaceSerialBand; class LaplaceSerialBand : public Laplacian { public: - LaplaceSerialBand(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE); + LaplaceSerialBand(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = mesh); ~LaplaceSerialBand(){}; using Laplacian::setCoefA; void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); Acoef = val; } using Laplacian::setCoefC; void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); Ccoef = val; } using Laplacian::setCoefD; void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); Dcoef = val; } using Laplacian::setCoefEx; diff --git a/src/invert/laplace/impls/serial_tri/serial_tri.cxx b/src/invert/laplace/impls/serial_tri/serial_tri.cxx index 7080f18b31..0a2cbe02b1 100644 --- a/src/invert/laplace/impls/serial_tri/serial_tri.cxx +++ b/src/invert/laplace/impls/serial_tri/serial_tri.cxx @@ -37,13 +37,14 @@ #include -LaplaceSerialTri::LaplaceSerialTri(Options *opt, CELL_LOC loc) : Laplacian(opt, loc), A(0.0), C(1.0), D(1.0) { +LaplaceSerialTri::LaplaceSerialTri(Options *opt, CELL_LOC loc, Mesh *mesh_in) + : Laplacian(opt, loc, mesh_in), A(0.0), C(1.0), D(1.0) { A.setLocation(location); C.setLocation(location); D.setLocation(location); - if(!mesh->firstX() || !mesh->lastX()) { - throw BoutException("LaplaceSerialTri only works for mesh->NXPE = 1"); + if(!localmesh->firstX() || !localmesh->lastX()) { + throw BoutException("LaplaceSerialTri only works for localmesh->NXPE = 1"); } } @@ -72,24 +73,25 @@ const FieldPerp LaplaceSerialTri::solve(const FieldPerp &b) { * \return The inverted variable. */ const FieldPerp LaplaceSerialTri::solve(const FieldPerp &b, const FieldPerp &x0) { - Mesh *mesh = b.getMesh(); - FieldPerp x(mesh); + ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); + + FieldPerp x(localmesh); x.allocate(); int jy = b.getIndex(); x.setIndex(jy); - int ncz = mesh->LocalNz; // No of z pnts - int ncx = mesh->LocalNx; // No of x pnts + int ncz = localmesh->LocalNz; // No of z pnts + int ncx = localmesh->LocalNx; // No of x pnts - BoutReal kwaveFactor = 2.0 * PI / mesh->getCoordinates(location)->zlength(); + BoutReal kwaveFactor = 2.0 * PI / localmesh->getCoordinates(location)->zlength(); // Setting the width of the boundary. // NOTE: The default is a width of 2 guard cells - int inbndry = mesh->xstart, outbndry=mesh->xstart; + int inbndry = localmesh->xstart, outbndry=localmesh->xstart; // If the flags to assign that only one guard cell should be used is set - if((global_flags & INVERT_BOTH_BNDRY_ONE) || (mesh->xstart < 2)) { + if((global_flags & INVERT_BOTH_BNDRY_ONE) || (localmesh->xstart < 2)) { inbndry = outbndry = 1; } if (inner_boundary_flags & INVERT_BNDRY_ONE) @@ -185,7 +187,7 @@ const FieldPerp LaplaceSerialTri::solve(const FieldPerp &b, const FieldPerp &x0) outer_boundary_flags, &A, &C, &D); ///////// PERFORM INVERSION ///////// - if (!mesh->periodicX) { + if (!localmesh->periodicX) { // Call tridiagonal solver tridag(std::begin(avec), std::begin(bvec), std::begin(cvec), std::begin(bk1d), std::begin(xk1d), ncx); @@ -193,7 +195,7 @@ const FieldPerp LaplaceSerialTri::solve(const FieldPerp &b, const FieldPerp &x0) } else { // Periodic in X, so cyclic tridiagonal - int xs = mesh->xstart; + int xs = localmesh->xstart; cyclic_tridag(&avec[xs], &bvec[xs], &cvec[xs], &bk1d[xs], &xk1d[xs], ncx - 2 * xs); // Copy boundary regions @@ -206,11 +208,11 @@ const FieldPerp LaplaceSerialTri::solve(const FieldPerp &b, const FieldPerp &x0) // If the global flag is set to INVERT_KX_ZERO if ((global_flags & INVERT_KX_ZERO) && (kz == 0)) { dcomplex offset(0.0); - for (int ix = mesh->xstart; ix <= mesh->xend; ix++) { + for (int ix = localmesh->xstart; ix <= localmesh->xend; ix++) { offset += xk1d[ix]; } - offset /= static_cast(mesh->xend - mesh->xstart + 1); - for (int ix = mesh->xstart; ix <= mesh->xend; ix++) { + offset /= static_cast(localmesh->xend - localmesh->xstart + 1); + for (int ix = localmesh->xstart; ix <= localmesh->xend; ix++) { xk1d[ix] -= offset; } } diff --git a/src/invert/laplace/impls/serial_tri/serial_tri.hxx b/src/invert/laplace/impls/serial_tri/serial_tri.hxx index 86e98e49f1..519dc9a361 100644 --- a/src/invert/laplace/impls/serial_tri/serial_tri.hxx +++ b/src/invert/laplace/impls/serial_tri/serial_tri.hxx @@ -35,22 +35,25 @@ class LaplaceSerialTri; class LaplaceSerialTri : public Laplacian { public: - LaplaceSerialTri(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); + LaplaceSerialTri(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); ~LaplaceSerialTri(){}; using Laplacian::setCoefA; void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); A = val; } using Laplacian::setCoefC; void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); C = val; } using Laplacian::setCoefD; void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); D = val; } using Laplacian::setCoefEx; diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.cxx b/src/invert/laplace/impls/shoot/shoot_laplace.cxx index 0db36a3c65..86430f928c 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.cxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.cxx @@ -36,23 +36,23 @@ #include #include -LaplaceShoot::LaplaceShoot(Options *opt, const CELL_LOC loc) - : Laplacian(opt, loc), Acoef(0.0), Ccoef(1.0), Dcoef(1.0) { +LaplaceShoot::LaplaceShoot(Options *opt, const CELL_LOC loc, Mesh *mesh_in) + : Laplacian(opt, loc, mesh_in), Acoef(0.0), Ccoef(1.0), Dcoef(1.0) { throw BoutException("LaplaceShoot is a test implementation and does not currently work. Please select a different implementation."); Acoef.setLocation(location); Ccoef.setLocation(location); Dcoef.setLocation(location); - if(mesh->periodicX) { - throw BoutException("LaplaceShoot does not work with periodicity in the x direction (mesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); + if(localmesh->periodicX) { + throw BoutException("LaplaceShoot does not work with periodicity in the x direction (localmesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); } nmode = maxmode + 1; // Number of Z modes. maxmode set in invert_laplace.cxx from options // Allocate memory - int size = (mesh->LocalNz)/2 + 1; + int size = (localmesh->LocalNz)/2 + 1; km = Array(size); kc = Array(size); kp = Array(size); @@ -69,20 +69,21 @@ LaplaceShoot::LaplaceShoot(Options *opt, const CELL_LOC loc) } const FieldPerp LaplaceShoot::solve(const FieldPerp &rhs) { - Mesh *mesh = rhs.getMesh(); - FieldPerp x(mesh); // Result + ASSERT1(localmesh = rhs.getMesh()); + + FieldPerp x(localmesh); // Result x.allocate(); int jy = rhs.getIndex(); // Get the Y index x.setIndex(jy); - Coordinates *coord = mesh->getCoordinates(location); + Coordinates *coord = localmesh->getCoordinates(location); // Get the width of the boundary - int inbndry = mesh->xstart, outbndry=mesh->xstart; + int inbndry = localmesh->xstart, outbndry=localmesh->xstart; // If the flags to assign that only one guard cell should be used is set - if((global_flags & INVERT_BOTH_BNDRY_ONE) || (mesh->xstart < 2)) { + if((global_flags & INVERT_BOTH_BNDRY_ONE) || (localmesh->xstart < 2)) { inbndry = outbndry = 1; } if(inner_boundary_flags & INVERT_BNDRY_ONE) @@ -91,14 +92,14 @@ const FieldPerp LaplaceShoot::solve(const FieldPerp &rhs) { outbndry = 1; int xs, xe; - xs = mesh->xstart; // Starting X index - if(mesh->firstX()) + xs = localmesh->xstart; // Starting X index + if(localmesh->firstX()) xs = inbndry; - xe = mesh->xend; // Last X index - if(mesh->lastX()) - xe = mesh->LocalNx-outbndry-1; + xe = localmesh->xend; // Last X index + if(localmesh->lastX()) + xe = localmesh->LocalNx-outbndry-1; - if(mesh->lastX()) { + if(localmesh->lastX()) { // Set initial value and gradient to zero // by setting kc and kp @@ -107,15 +108,15 @@ const FieldPerp LaplaceShoot::solve(const FieldPerp &rhs) { kp[i] = 0.0; } - for(int ix=xe;ixLocalNx;ix++) - for(int iz=0;izLocalNz;iz++) { + for(int ix=xe;ixLocalNx;ix++) + for(int iz=0;izLocalNz;iz++) { x(ix, iz) = 0.0; } }else { // Wait for processor outer X - comm_handle handle = mesh->irecvXOut(std::begin(buffer), 4 * maxmode, jy); - mesh->wait(handle); + comm_handle handle = localmesh->irecvXOut(std::begin(buffer), 4 * maxmode, jy); + localmesh->wait(handle); // Copy into kc, kp for(int i=0;iLocalNz, x[xe]); + irfft(std::begin(kc), localmesh->LocalNz, x[xe]); } // kc and kp now set to result at x and x+1 respectively // Use b at x to get km at x-1 // Loop inwards from edge for(int ix=xe; ix >= xs; ix--) { - rfft(rhs[ix], mesh->LocalNz, std::begin(rhsk)); + rfft(rhs[ix], localmesh->LocalNz, std::begin(rhsk)); for(int kz=0; kzzlength()); // wave number is 1/[rad] @@ -147,7 +148,7 @@ const FieldPerp LaplaceShoot::solve(const FieldPerp &rhs) { } // Inverse FFT to get x[ix-1] - irfft(std::begin(km), mesh->LocalNz, x[ix - 1]); + irfft(std::begin(km), localmesh->LocalNz, x[ix - 1]); // Cycle km->kc->kp std::swap(kp, kc); @@ -155,7 +156,7 @@ const FieldPerp LaplaceShoot::solve(const FieldPerp &rhs) { } // Finished on this processor. Send data to next inner processor - if(!mesh->firstX()) { + if(!localmesh->firstX()) { // Should be able to send dcomplex buffers. For now copy into BoutReal buffer for(int i=0;isendXIn(std::begin(buffer), 4 * maxmode, jy); + localmesh->sendXIn(std::begin(buffer), 4 * maxmode, jy); }else { // Set inner boundary for(int ix=xs-2;ix>=0;ix--) { - for(int iz=0;izLocalNz;iz++) { + for(int iz=0;izLocalNz;iz++) { x(ix, iz) = x(xs - 1, iz); } } diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.hxx b/src/invert/laplace/impls/shoot/shoot_laplace.hxx index 999fb20ba2..db6e1bd617 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.hxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.hxx @@ -37,22 +37,25 @@ class LaplaceShoot; class LaplaceShoot : public Laplacian { public: - LaplaceShoot(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE); + LaplaceShoot(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = mesh); ~LaplaceShoot(){}; using Laplacian::setCoefA; void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); Acoef = val; } using Laplacian::setCoefC; void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); Ccoef = val; } using Laplacian::setCoefD; void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); Dcoef = val; } using Laplacian::setCoefEx; diff --git a/src/invert/laplace/impls/spt/spt.cxx b/src/invert/laplace/impls/spt/spt.cxx index b7867a87d5..e75cad6cae 100644 --- a/src/invert/laplace/impls/spt/spt.cxx +++ b/src/invert/laplace/impls/spt/spt.cxx @@ -41,23 +41,23 @@ #include "spt.hxx" -LaplaceSPT::LaplaceSPT(Options *opt, const CELL_LOC loc) - : Laplacian(opt, loc), Acoef(0.0), Ccoef(1.0), Dcoef(1.0) { +LaplaceSPT::LaplaceSPT(Options *opt, const CELL_LOC loc, Mesh *mesh_in) + : Laplacian(opt, loc, mesh_in), Acoef(0.0), Ccoef(1.0), Dcoef(1.0) { Acoef.setLocation(location); Ccoef.setLocation(location); Dcoef.setLocation(location); - if(mesh->periodicX) { - throw BoutException("LaplaceSPT does not work with periodicity in the x direction (mesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); + if(localmesh->periodicX) { + throw BoutException("LaplaceSPT does not work with periodicity in the x direction (localmesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); } // Get start and end indices - ys = mesh->ystart; - ye = mesh->yend; - if(mesh->hasBndryLowerY() && include_yguards) + ys = localmesh->ystart; + ye = localmesh->yend; + if(localmesh->hasBndryLowerY() && include_yguards) ys = 0; // Mesh contains a lower boundary - if(mesh->hasBndryUpperY() && include_yguards) - ye = mesh->LocalNy-1; // Contains upper boundary + if(localmesh->hasBndryUpperY() && include_yguards) + ye = localmesh->LocalNy-1; // Contains upper boundary alldata = new SPT_data[ye - ys + 1]; alldata -= ys; // Re-number indices to start at ys @@ -66,7 +66,7 @@ LaplaceSPT::LaplaceSPT(Options *opt, const CELL_LOC loc) } // Temporary array for taking FFTs - int ncz = mesh->LocalNz; + int ncz = localmesh->LocalNz; dc1d = Array(ncz / 2 + 1); } @@ -80,27 +80,28 @@ const FieldPerp LaplaceSPT::solve(const FieldPerp &b) { } const FieldPerp LaplaceSPT::solve(const FieldPerp &b, const FieldPerp &x0) { - Mesh *mesh = b.getMesh(); - FieldPerp x(mesh); + ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); + + FieldPerp x(localmesh); x.allocate(); if( (inner_boundary_flags & INVERT_SET) || (outer_boundary_flags & INVERT_SET) ) { FieldPerp bs = copy(b); - int xbndry = mesh->xstart; + int xbndry = localmesh->xstart; // If the flags to assign that only one guard cell should be used is set - if((global_flags & INVERT_BOTH_BNDRY_ONE) || (mesh->xstart < 2)) + if((global_flags & INVERT_BOTH_BNDRY_ONE) || (localmesh->xstart < 2)) xbndry = 1; - if((inner_boundary_flags & INVERT_SET) && mesh->firstX()) { + if((inner_boundary_flags & INVERT_SET) && localmesh->firstX()) { // Copy x0 inner boundary into bs for(int ix=0;ixLocalNz;iz++) + for(int iz=0;izLocalNz;iz++) bs[ix][iz] = x0[ix][iz]; } - if((outer_boundary_flags & INVERT_SET) && mesh->lastX()) { + if((outer_boundary_flags & INVERT_SET) && localmesh->lastX()) { // Copy x0 outer boundary into bs - for(int ix=mesh->LocalNx-1;ix>=mesh->LocalNx-xbndry;ix--) - for(int iz=0;izLocalNz;iz++) + for(int ix=localmesh->LocalNx-1;ix>=localmesh->LocalNx-xbndry;ix--) + for(int iz=0;izLocalNz;iz++) bs[ix][iz] = x0[ix][iz]; } start(bs, slicedata); @@ -113,17 +114,17 @@ const FieldPerp LaplaceSPT::solve(const FieldPerp &b, const FieldPerp &x0) { /// Extracts perpendicular slices from 3D fields and inverts separately /*! - * In parallel (mesh->NXPE > 1) this tries to overlap computation and communication. + * In parallel (localmesh->NXPE > 1) this tries to overlap computation and communication. * This is done at the expense of more memory useage. Setting low_mem * in the config file uses less memory, and less communication overlap */ const Field3D LaplaceSPT::solve(const Field3D &b) { ASSERT1(b.getLocation() == location); + ASSERT1(localmesh = b.getMesh()); Timer timer("invert"); - Mesh *mesh = b.getMesh(); - Field3D x(mesh); + Field3D x(localmesh); x.allocate(); for(int jy=ys; jy <= ye; jy++) { @@ -142,7 +143,7 @@ const Field3D LaplaceSPT::solve(const Field3D &b) { running = next(alldata[jy]) == 0; }while(running); - FieldPerp xperp(mesh); + FieldPerp xperp(localmesh); xperp.allocate(); // All calculations finished. Get result @@ -157,27 +158,29 @@ const Field3D LaplaceSPT::solve(const Field3D &b) { } const Field3D LaplaceSPT::solve(const Field3D &b, const Field3D &x0) { - if( ((inner_boundary_flags & INVERT_SET) && mesh->firstX()) || - ((outer_boundary_flags & INVERT_SET) && mesh->lastX()) ) { + ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); + + if( ((inner_boundary_flags & INVERT_SET) && localmesh->firstX()) || + ((outer_boundary_flags & INVERT_SET) && localmesh->lastX()) ) { Field3D bs = copy(b); - int xbndry = mesh->xstart; + int xbndry = localmesh->xstart; // If the flags to assign that only one guard cell should be used is set - if((global_flags & INVERT_BOTH_BNDRY_ONE) || (mesh->xstart < 2)) + if((global_flags & INVERT_BOTH_BNDRY_ONE) || (localmesh->xstart < 2)) xbndry = 1; - if((inner_boundary_flags & INVERT_SET) && mesh->firstX()) { + if((inner_boundary_flags & INVERT_SET) && localmesh->firstX()) { // Copy x0 inner boundary into bs for(int ix=0;ixLocalNy;iy++) - for(int iz=0;izLocalNz;iz++) + for(int iy=0;iyLocalNy;iy++) + for(int iz=0;izLocalNz;iz++) bs(ix,iy,iz) = x0(ix,iy,iz); } - if((outer_boundary_flags & INVERT_SET) && mesh->lastX()) { + if((outer_boundary_flags & INVERT_SET) && localmesh->lastX()) { // Copy x0 outer boundary into bs - for(int ix=mesh->LocalNx-1;ix>=mesh->LocalNx-xbndry;ix--) - for(int iy=0;iyLocalNy;iy++) - for(int iz=0;izLocalNz;iz++) + for(int ix=localmesh->LocalNx-1;ix>=localmesh->LocalNx-xbndry;ix--) + for(int iy=0;iyLocalNy;iy++) + for(int iz=0;izLocalNz;iz++) bs(ix,iy,iz) = x0(ix,iy,iz); } return solve(bs); @@ -235,8 +238,8 @@ void LaplaceSPT::tridagForward(dcomplex *a, dcomplex *b, dcomplex *c, * @param[inout] u Result to be solved (Au = r) * @param[in] n Size of the problem * @param[in] gam Intermediate values produced by the forward part - * @param[inout] gp gam from the processor mesh->PE_XIND + 1, and returned to mesh->PE_XIND - 1 - * @param[inout] up u from processor mesh->PE_XIND + 1, and returned to mesh->PE_XIND - 1 + * @param[inout] gp gam from the processor localmesh->PE_XIND + 1, and returned to localmesh->PE_XIND - 1 + * @param[inout] up u from processor localmesh->PE_XIND + 1, and returned to localmesh->PE_XIND - 1 */ void LaplaceSPT::tridagBack(dcomplex *u, int n, dcomplex *gam, dcomplex &gp, dcomplex &up) { @@ -256,39 +259,39 @@ void LaplaceSPT::tridagBack(dcomplex *u, int n, /// /// This is a reference code which performs the same operations as the /// serial code. To invert a single XZ slice (FieldPerp object), data -/// must pass from the innermost processor (mesh->PE_XIND = 0) to the -/// outermost (mesh->PE_XIND = mesh->NXPE-1) and back again. +/// must pass from the innermost processor (localmesh->PE_XIND = 0) to the +/// outermost (localmesh->PE_XIND = localmesh->NXPE-1) and back again. /// /// Some parallelism is achieved by running several inversions /// simultaneously, so while processor #1 is inverting Y=0, processor /// #0 is starting on Y=1. This works ok as long as the number of /// slices to be inverted is greater than the number of X processors -/// (MYSUB > mesh->NXPE). If MYSUB < mesh->NXPE then not all +/// (MYSUB > localmesh->NXPE). If MYSUB < localmesh->NXPE then not all /// processors can be busy at once, and so efficiency will fall /// sharply. /// /// @param[in] b RHS values (Ax = b) /// @param[out] data Structure containing data needed for second half of inversion int LaplaceSPT::start(const FieldPerp &b, SPT_data &data) { - if(mesh->firstX() && mesh->lastX()) - throw BoutException("Error: SPT method only works for mesh->NXPE > 1\n"); + if(localmesh->firstX() && localmesh->lastX()) + throw BoutException("Error: SPT method only works for localmesh->NXPE > 1\n"); data.jy = b.getIndex(); - int mm = mesh->LocalNz/2 + 1; - data.allocate(mm, mesh->LocalNx); // Make sure data is allocated. Already allocated -> does nothing + int mm = localmesh->LocalNz/2 + 1; + data.allocate(mm, localmesh->LocalNx); // Make sure data is allocated. Already allocated -> does nothing /// Take FFTs of data - int ncz = mesh->LocalNz; + int ncz = localmesh->LocalNz; - for(int ix=0; ix < mesh->LocalNx; ix++) { + for(int ix=0; ix < localmesh->LocalNx; ix++) { rfft(b[ix], ncz, std::begin(dc1d)); for(int kz = 0; kz <= maxmode; kz++) data.bk(kz, ix) = dc1d[kz]; } - BoutReal kwaveFactor = 2.0 * PI / mesh->getCoordinates(location)->zlength(); + BoutReal kwaveFactor = 2.0 * PI / localmesh->getCoordinates(location)->zlength(); /// Set matrix elements for (int kz = 0; kz <= maxmode; kz++) { @@ -300,13 +303,13 @@ int LaplaceSPT::start(const FieldPerp &b, SPT_data &data) { data.proc = 0; //< Starts at processor 0 data.dir = 1; - if(mesh->firstX()) { + if(localmesh->firstX()) { BOUT_OMP(parallel for) for(int kz = 0; kz <= maxmode; kz++) { dcomplex bet, u0; // Start tridiagonal solve tridagForward(&data.avec(kz, 0), &data.bvec(kz, 0), &data.cvec(kz, 0), - &data.bk(kz, 0), &data.xk(kz, 0), mesh->xend + 1, &data.gam(kz, 0), + &data.bk(kz, 0), &data.xk(kz, 0), localmesh->xend + 1, &data.gam(kz, 0), bet, u0, true); // Load intermediate values into buffers data.buffer[4*kz] = bet.real(); @@ -316,16 +319,16 @@ int LaplaceSPT::start(const FieldPerp &b, SPT_data &data) { } // Send data - mesh->sendXOut(std::begin(data.buffer), 4 * (maxmode + 1), data.comm_tag); + localmesh->sendXOut(std::begin(data.buffer), 4 * (maxmode + 1), data.comm_tag); - }else if(mesh->PE_XIND == 1) { + }else if(localmesh->PE_XIND == 1) { // Post a receive data.recv_handle = - mesh->irecvXIn(std::begin(data.buffer), 4 * (maxmode + 1), data.comm_tag); + localmesh->irecvXIn(std::begin(data.buffer), 4 * (maxmode + 1), data.comm_tag); } data.proc++; // Now moved onto the next processor - if(mesh->NXPE == 2) + if(localmesh->NXPE == 2) data.dir = -1; // Special case. Otherwise reversal handled in spt_continue return 0; @@ -341,13 +344,13 @@ int LaplaceSPT::next(SPT_data &data) { if(data.proc < 0) // Already finished return 1; - if(mesh->PE_XIND == data.proc) { + if(localmesh->PE_XIND == data.proc) { /// This processor's turn to do inversion // Wait for data to arrive - mesh->wait(data.recv_handle); + localmesh->wait(data.recv_handle); - if(mesh->lastX()) { + if(localmesh->lastX()) { // Last processor, turn-around BOUT_OMP(parallel for) @@ -356,16 +359,16 @@ int LaplaceSPT::next(SPT_data &data) { dcomplex gp, up; bet = dcomplex(data.buffer[4*kz], data.buffer[4*kz + 1]); u0 = dcomplex(data.buffer[4*kz + 2], data.buffer[4*kz + 3]); - tridagForward(&data.avec(kz, mesh->xstart), &data.bvec(kz, mesh->xstart), - &data.cvec(kz, mesh->xstart), &data.bk(kz, mesh->xstart), - &data.xk(kz, mesh->xstart), mesh->xend + 1, - &data.gam(kz, mesh->xstart), bet, u0); + tridagForward(&data.avec(kz, localmesh->xstart), &data.bvec(kz, localmesh->xstart), + &data.cvec(kz, localmesh->xstart), &data.bk(kz, localmesh->xstart), + &data.xk(kz, localmesh->xstart), localmesh->xend + 1, + &data.gam(kz, localmesh->xstart), bet, u0); // Back-substitute gp = 0.0; up = 0.0; - tridagBack(&data.xk(kz, mesh->xstart), mesh->LocalNx - mesh->xstart, - &data.gam(kz, mesh->xstart), gp, up); + tridagBack(&data.xk(kz, localmesh->xstart), localmesh->LocalNx - localmesh->xstart, + &data.gam(kz, localmesh->xstart), gp, up); data.buffer[4*kz] = gp.real(); data.buffer[4*kz + 1] = gp.imag(); data.buffer[4*kz + 2] = up.real(); @@ -380,10 +383,10 @@ int LaplaceSPT::next(SPT_data &data) { dcomplex bet, u0; bet = dcomplex(data.buffer[4*kz], data.buffer[4*kz + 1]); u0 = dcomplex(data.buffer[4*kz + 2], data.buffer[4*kz + 3]); - tridagForward(&data.avec(kz, mesh->xstart), &data.bvec(kz, mesh->xstart), - &data.cvec(kz, mesh->xstart), &data.bk(kz, mesh->xstart), - &data.xk(kz, mesh->xstart), mesh->xend - mesh->xstart + 1, - &data.gam(kz, mesh->xstart), bet, u0); + tridagForward(&data.avec(kz, localmesh->xstart), &data.bvec(kz, localmesh->xstart), + &data.cvec(kz, localmesh->xstart), &data.bk(kz, localmesh->xstart), + &data.xk(kz, localmesh->xstart), localmesh->xend - localmesh->xstart + 1, + &data.gam(kz, localmesh->xstart), bet, u0); // Load intermediate values into buffers data.buffer[4*kz] = bet.real(); data.buffer[4*kz + 1] = bet.imag(); @@ -391,7 +394,7 @@ int LaplaceSPT::next(SPT_data &data) { data.buffer[4*kz + 3] = u0.imag(); } - }else if(mesh->firstX()) { + }else if(localmesh->firstX()) { // Back to the start BOUT_OMP(parallel for) @@ -400,7 +403,7 @@ BOUT_OMP(parallel for) gp = dcomplex(data.buffer[4*kz], data.buffer[4*kz + 1]); up = dcomplex(data.buffer[4*kz + 2], data.buffer[4*kz + 3]); - tridagBack(&data.xk(kz, 0), mesh->xend + 1, &data.gam(kz, 0), gp, up); + tridagBack(&data.xk(kz, 0), localmesh->xend + 1, &data.gam(kz, 0), gp, up); } }else { @@ -411,8 +414,8 @@ BOUT_OMP(parallel for) dcomplex gp = dcomplex(data.buffer[4*kz], data.buffer[4*kz + 1]); dcomplex up = dcomplex(data.buffer[4*kz + 2], data.buffer[4*kz + 3]); - tridagBack(&data.xk(kz, mesh->xstart), mesh->xend - mesh->xstart + 1, - &data.gam(kz, mesh->xstart), gp, up); + tridagBack(&data.xk(kz, localmesh->xstart), localmesh->xend - localmesh->xstart + 1, + &data.gam(kz, localmesh->xstart), gp, up); data.buffer[4*kz] = gp.real(); data.buffer[4*kz + 1] = gp.imag(); @@ -421,29 +424,29 @@ BOUT_OMP(parallel for) } } - if(mesh->PE_XIND != 0) { // If not finished yet + if(localmesh->PE_XIND != 0) { // If not finished yet /// Send data if(data.dir > 0) { - mesh->sendXOut(std::begin(data.buffer), 4 * (maxmode + 1), data.comm_tag); + localmesh->sendXOut(std::begin(data.buffer), 4 * (maxmode + 1), data.comm_tag); }else - mesh->sendXIn(std::begin(data.buffer), 4 * (maxmode + 1), data.comm_tag); + localmesh->sendXIn(std::begin(data.buffer), 4 * (maxmode + 1), data.comm_tag); } - }else if(mesh->PE_XIND == data.proc + data.dir) { + }else if(localmesh->PE_XIND == data.proc + data.dir) { // This processor is next, post receive if(data.dir > 0) { data.recv_handle = - mesh->irecvXIn(std::begin(data.buffer), 4 * (maxmode + 1), data.comm_tag); + localmesh->irecvXIn(std::begin(data.buffer), 4 * (maxmode + 1), data.comm_tag); }else data.recv_handle = - mesh->irecvXOut(std::begin(data.buffer), 4 * (maxmode + 1), data.comm_tag); + localmesh->irecvXOut(std::begin(data.buffer), 4 * (maxmode + 1), data.comm_tag); } data.proc += data.dir; - if(data.proc == mesh->NXPE-1) + if(data.proc == localmesh->NXPE-1) data.dir = -1; // Reverses direction at the end return 0; @@ -454,8 +457,8 @@ BOUT_OMP(parallel for) /// @param[inout] data Structure keeping track of calculation /// @param[out] x The result void LaplaceSPT::finish(SPT_data &data, FieldPerp &x) { - int ncx = mesh->LocalNx-1; - int ncz = mesh->LocalNz; + int ncx = localmesh->LocalNx-1; + int ncz = localmesh->LocalNz; x.allocate(); x.setIndex(data.jy); @@ -479,17 +482,17 @@ void LaplaceSPT::finish(SPT_data &data, FieldPerp &x) { irfft(std::begin(dc1d), ncz, x[ix]); } - if(!mesh->firstX()) { + if(!localmesh->firstX()) { // Set left boundary to zero (Prevent unassigned values in corners) - for(int ix=0; ixxstart; ix++){ - for(int kz=0;kzLocalNz;kz++) + for(int ix=0; ixxstart; ix++){ + for(int kz=0;kzLocalNz;kz++) x(ix,kz) = 0.0; } } - if(!mesh->lastX()) { + if(!localmesh->lastX()) { // Same for right boundary - for(int ix=mesh->xend+1; ixLocalNx; ix++){ - for(int kz=0;kzLocalNz;kz++) + for(int ix=localmesh->xend+1; ixLocalNx; ix++){ + for(int kz=0;kzLocalNz;kz++) x(ix,kz) = 0.0; } } diff --git a/src/invert/laplace/impls/spt/spt.hxx b/src/invert/laplace/impls/spt/spt.hxx index 564f9c844c..44b7d98eb8 100644 --- a/src/invert/laplace/impls/spt/spt.hxx +++ b/src/invert/laplace/impls/spt/spt.hxx @@ -50,12 +50,12 @@ class LaplaceSPT; /*! * This is a reference code which performs the same operations as the serial code. * To invert a single XZ slice (FieldPerp object), data must pass from the innermost - * processor (mesh->PE_XIND = 0) to the outermost (mesh->PE_XIND = mesh->NXPE-1) and back again. + * processor (localmesh->PE_XIND = 0) to the outermost (localmesh->PE_XIND = localmesh->NXPE-1) and back again. * * Some parallelism is achieved by running several inversions simultaneously, so while * processor #1 is inverting Y=0, processor #0 is starting on Y=1. This works ok as long - * as the number of slices to be inverted is greater than the number of X processors (MYSUB > mesh->NXPE). - * If MYSUB < mesh->NXPE then not all processors can be busy at once, and so efficiency will fall sharply. + * as the number of slices to be inverted is greater than the number of X processors (MYSUB > localmesh->NXPE). + * If MYSUB < localmesh->NXPE then not all processors can be busy at once, and so efficiency will fall sharply. * * @param[in] b RHS values (Ax = b) * @param[in] flags Inversion settings (see boundary.h for values) @@ -66,22 +66,25 @@ class LaplaceSPT; */ class LaplaceSPT : public Laplacian { public: - LaplaceSPT(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE); + LaplaceSPT(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = mesh); ~LaplaceSPT(); using Laplacian::setCoefA; void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); Acoef = val; } using Laplacian::setCoefC; void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); Ccoef = val; } using Laplacian::setCoefD; void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); + ASSERT1(localmesh = val.getMesh()); Dcoef = val; } using Laplacian::setCoefEx; diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index c9478eb20d..2e66fa3767 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -51,7 +51,8 @@ **********************************************************************************/ /// Laplacian inversion initialisation. Called once at the start to get settings -Laplacian::Laplacian(Options *options, const CELL_LOC loc) : location(loc) { +Laplacian::Laplacian(Options *options, const CELL_LOC loc, Mesh *mesh_in) + : location(loc), localmesh(mesh_in) { if (options == nullptr) { // Use the default options @@ -69,7 +70,7 @@ Laplacian::Laplacian(Options *options, const CELL_LOC loc) : location(loc) { BoutReal filter; ///< Fraction of Z modes to filter out. Between 0 and 1 OPTION(options, filter, 0.0); - int ncz = mesh->LocalNz; + int ncz = localmesh->LocalNz; // convert filtering into an integer number of modes maxmode = ROUND((1.0 - filter) * static_cast(ncz / 2)); // Can be overriden by max_mode option @@ -80,7 +81,7 @@ Laplacian::Laplacian(Options *options, const CELL_LOC loc) : location(loc) { OPTION(options, low_mem, false); OPTION(options, nonuniform, - mesh->getCoordinates(location)->non_uniform); // Default is the mesh setting + localmesh->getCoordinates(location)->non_uniform); // Default is the mesh setting OPTION(options, all_terms, true); // Include first derivative terms @@ -103,13 +104,13 @@ Laplacian::Laplacian(Options *options, const CELL_LOC loc) : location(loc) { OPTION2(options, extra_yguards_lower, extra_yguards_upper, 0); } -Laplacian* Laplacian::create(Options *opts, const CELL_LOC location) { +Laplacian* Laplacian::create(Options *opts, const CELL_LOC location, Mesh *mesh_in) { // Factory pattern: // 1. getInstance() is making an instance of LaplacianFactory // 2. createLaplacian() is accessing this instance and returning a Laplacian // form one of the child classes of the Laplacian (the laplace solver // implementations) - return LaplaceFactory::getInstance()->createLaplacian(opts, location); + return LaplaceFactory::getInstance()->createLaplacian(opts, location, mesh_in); } Laplacian *Laplacian::instance = nullptr; @@ -135,26 +136,25 @@ const Field3D Laplacian::solve(const Field3D &b) { TRACE("Laplacian::solve(Field3D)"); ASSERT1(b.getLocation() == location); - - Mesh *mesh = b.getMesh(); + ASSERT1(localmesh = b.getMesh()); Timer timer("invert"); - int ys = mesh->ystart, ye = mesh->yend; + int ys = localmesh->ystart, ye = localmesh->yend; - if(mesh->hasBndryLowerY()) { + if(localmesh->hasBndryLowerY()) { if (include_yguards) ys = 0; // Mesh contains a lower boundary and we are solving in the guard cells ys += extra_yguards_lower; } - if(mesh->hasBndryUpperY()) { + if(localmesh->hasBndryUpperY()) { if (include_yguards) - ye = mesh->LocalNy-1; // Contains upper boundary and we are solving in the guard cells + ye = localmesh->LocalNy-1; // Contains upper boundary and we are solving in the guard cells ye -= extra_yguards_upper; } - Field3D x(mesh); + Field3D x(localmesh); x.allocate(); int status = 0; @@ -198,18 +198,18 @@ const Field3D Laplacian::solve(const Field3D &b, const Field3D &x0) { ASSERT1(b.getLocation() == location); ASSERT1(x0.getLocation() == location); + ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); Timer timer("invert"); - Mesh *mesh = b.getMesh(); // Setting the start and end range of the y-slices - int ys = mesh->ystart, ye = mesh->yend; - if(mesh->hasBndryLowerY() && include_yguards) + int ys = localmesh->ystart, ye = localmesh->yend; + if(localmesh->hasBndryLowerY() && include_yguards) ys = 0; // Mesh contains a lower boundary - if(mesh->hasBndryUpperY() && include_yguards) - ye = mesh->LocalNy-1; // Contains upper boundary + if(localmesh->hasBndryUpperY() && include_yguards) + ye = localmesh->LocalNy-1; // Contains upper boundary - Field3D x(mesh); + Field3D x(localmesh); x.allocate(); int status = 0; @@ -249,7 +249,7 @@ void Laplacian::tridagCoefs(int jx, int jy, int jz, ASSERT1(ccoef == nullptr || ccoef->getLocation() == loc); ASSERT1(d == nullptr || d->getLocation() == loc); - Coordinates *coord = mesh->getCoordinates(loc); + Coordinates *coord = localmesh->getCoordinates(loc); BoutReal kwave=jz*2.0*PI/coord->zlength(); // wave number is 1/[rad] @@ -275,7 +275,7 @@ void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, * Input: * jx - The current x index * jy - The current y index - * kwave - The mode number multiplied with (2*pi)/mesh->zlength(), where + * kwave - The mode number multiplied with (2*pi)/localmesh->zlength(), where * zlength() is the length of the full z domain (usually 2*pi) * a - Lower diagonal of the tridiagonal matrix. DO NOT CONFUSE WITH A * b - The main diagonal @@ -296,7 +296,7 @@ void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, BoutReal coef1, coef2, coef3, coef4, coef5; - Coordinates *coord = mesh->getCoordinates(loc); + Coordinates *coord = localmesh->getCoordinates(loc); coef1=coord->g11(jx,jy); ///< X 2nd derivative coefficient coef2=coord->g33(jx,jy); ///< Z 2nd derivative coefficient @@ -321,18 +321,18 @@ void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, if(nonuniform) { // non-uniform mesh correction - if((jx != 0) && (jx != (mesh->LocalNx-1))) { + if((jx != 0) && (jx != (localmesh->LocalNx-1))) { coef4 -= 0.5*((coord->dx(jx+1,jy) - coord->dx(jx-1,jy))/SQ(coord->dx(jx,jy)))*coef1; } } if (ccoef != nullptr) { // A first order derivative term - if((jx > 0) && (jx < (mesh->LocalNx-1))) + if((jx > 0) && (jx < (localmesh->LocalNx-1))) coef4 += coord->g11(jx,jy) * ((*ccoef)(jx+1,jy) - (*ccoef)(jx-1,jy)) / (2.*coord->dx(jx,jy)*((*ccoef)(jx,jy))); } - if(mesh->IncIntShear) { + if(localmesh->IncIntShear) { // d2dz2 term coef2 += coord->g11(jx,jy) * coord->IntShiftTorsion(jx,jy) * coord->IntShiftTorsion(jx,jy); // Mixed derivative @@ -361,7 +361,7 @@ void Laplacian::tridagMatrix(dcomplex **avec, dcomplex **bvec, dcomplex **cvec, ASSERT1(ccoef->getLocation() == location); ASSERT1(d->getLocation() == location); - Coordinates *coord = mesh->getCoordinates(location); + Coordinates *coord = localmesh->getCoordinates(location); BOUT_OMP(parallel for) for(int kz = 0; kz <= maxmode; kz++) { @@ -424,27 +424,27 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, ASSERT1(d->getLocation() == location); int xs = 0; // xstart set to the start of x on this processor (including ghost points) - int xe = mesh->LocalNx-1; // xend set to the end of x on this processor (including ghost points) + int xe = localmesh->LocalNx-1; // xend set to the end of x on this processor (including ghost points) - Coordinates *coord = mesh->getCoordinates(location); + Coordinates *coord = localmesh->getCoordinates(location); // Do not want boundary cells if x is periodic for cyclic solver. Only other solver which // works with periodicX is serial_tri, which uses includeguards==true, so the below isn't called. if(!includeguards) { - if(!mesh->firstX() || mesh->periodicX) - xs = mesh->xstart; // Inner edge is a guard cell - if(!mesh->lastX() || mesh->periodicX) - xe = mesh->xend; // Outer edge is a guard cell + if(!localmesh->firstX() || localmesh->periodicX) + xs = localmesh->xstart; // Inner edge is a guard cell + if(!localmesh->lastX() || localmesh->periodicX) + xe = localmesh->xend; // Outer edge is a guard cell } int ncx = xe - xs; // Total number of points in x to be used // Setting the width of the boundary. - // NOTE: The default is a width of (mesh->xstart) guard cells - int inbndry = mesh->xstart, outbndry=mesh->xstart; + // NOTE: The default is a width of (localmesh->xstart) guard cells + int inbndry = localmesh->xstart, outbndry=localmesh->xstart; // If the flags to assign that only one guard cell should be used is set - if((global_flags & INVERT_BOTH_BNDRY_ONE) || (mesh->xstart < 2)) { + if((global_flags & INVERT_BOTH_BNDRY_ONE) || (localmesh->xstart < 2)) { inbndry = outbndry = 1; } if(inner_boundary_flags & INVERT_BNDRY_ONE) @@ -463,8 +463,8 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, } // Set the boundary conditions if x is not periodic - if(!mesh->periodicX) { - if(mesh->firstX()) { + if(!localmesh->periodicX) { + if(localmesh->firstX()) { // INNER BOUNDARY ON THIS PROCESSOR // If no user specified value is set on inner boundary, set the first @@ -627,7 +627,7 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, } } } - if(mesh->lastX()) { + if(localmesh->lastX()) { // OUTER BOUNDARY ON THIS PROCESSOR // If no user specified value is set on outer boundary, set the last diff --git a/src/invert/laplace/laplacefactory.cxx b/src/invert/laplace/laplacefactory.cxx index 6a04e6e68e..5446426508 100644 --- a/src/invert/laplace/laplacefactory.cxx +++ b/src/invert/laplace/laplacefactory.cxx @@ -37,35 +37,35 @@ LaplaceFactory* LaplaceFactory::getInstance() { return instance; } -Laplacian* LaplaceFactory::createLaplacian(Options *options, const CELL_LOC loc) { +Laplacian* LaplaceFactory::createLaplacian(Options *options, const CELL_LOC loc, Mesh *mesh_in) { if (options == nullptr) options = Options::getRoot()->getSection("laplace"); string type; - if(mesh->firstX() && mesh->lastX()) { + if(mesh_in->firstX() && mesh_in->lastX()) { // Can use serial algorithm options->get("type", type, LAPLACE_CYCLIC); if(strcasecmp(type.c_str(), LAPLACE_TRI) == 0) { - return new LaplaceSerialTri(options, loc); + return new LaplaceSerialTri(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_BAND) == 0) { - return new LaplaceSerialBand(options, loc); + return new LaplaceSerialBand(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_SPT) == 0) { - return new LaplaceSPT(options, loc); + return new LaplaceSPT(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_PETSC) == 0) { - return new LaplacePetsc(options, loc); + return new LaplacePetsc(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_MUMPS) == 0) { - return new LaplaceMumps(options, loc); + return new LaplaceMumps(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_CYCLIC) == 0) { - return new LaplaceCyclic(options, loc); + return new LaplaceCyclic(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_SHOOT) == 0) { - return new LaplaceShoot(options, loc); + return new LaplaceShoot(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_MULTIGRID) == 0) { - return new LaplaceMultigrid(options, loc); + return new LaplaceMultigrid(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_NAULIN) == 0) { - return new LaplaceNaulin(options, loc); + return new LaplaceNaulin(options, loc, mesh_in); }else { throw BoutException("Unknown serial Laplacian solver type '%s'", type.c_str()); } @@ -75,21 +75,21 @@ Laplacian* LaplaceFactory::createLaplacian(Options *options, const CELL_LOC loc) // Parallel algorithm if(strcasecmp(type.c_str(), LAPLACE_PDD) == 0) { - return new LaplacePDD(options, loc); + return new LaplacePDD(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_SPT) == 0) { - return new LaplaceSPT(options, loc); + return new LaplaceSPT(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_PETSC) == 0) { - return new LaplacePetsc(options, loc); + return new LaplacePetsc(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_MUMPS) == 0) { - return new LaplaceMumps(options, loc); + return new LaplaceMumps(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_CYCLIC) == 0) { - return new LaplaceCyclic(options, loc); + return new LaplaceCyclic(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_SHOOT) == 0) { - return new LaplaceShoot(options, loc); + return new LaplaceShoot(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_MULTIGRID) == 0) { - return new LaplaceMultigrid(options, loc); + return new LaplaceMultigrid(options, loc, mesh_in); }else if(strcasecmp(type.c_str(), LAPLACE_NAULIN) == 0) { - return new LaplaceNaulin(options, loc); + return new LaplaceNaulin(options, loc, mesh_in); }else { throw BoutException("Unknown parallel Laplacian solver type '%s'", type.c_str()); } diff --git a/src/invert/laplace/laplacefactory.hxx b/src/invert/laplace/laplacefactory.hxx index e71543a073..215ee8790d 100644 --- a/src/invert/laplace/laplacefactory.hxx +++ b/src/invert/laplace/laplacefactory.hxx @@ -11,7 +11,7 @@ class LaplaceFactory { /// Return a pointer to the only instance static LaplaceFactory* getInstance(); - Laplacian *createLaplacian(Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE); + Laplacian *createLaplacian(Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); private: LaplaceFactory() {} // Prevent instantiation of this class diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index f6d0a3eb2f..2dfc7c2de3 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -48,18 +48,19 @@ #include -InvertParCR::InvertParCR(Options *opt) : InvertPar(opt), A(1.0), B(0.0), C(0.0), D(0.0), E(0.0) { +InvertParCR::InvertParCR(Options *opt, Mesh *mesh_in) + : InvertPar(opt, mesh_in), A(1.0), B(0.0), C(0.0), D(0.0), E(0.0) { // Number of k equations to solve for each x location - nsys = 1 + (mesh->LocalNz)/2; + nsys = 1 + (localmesh->LocalNz)/2; - rhs = Matrix(mesh->LocalNy, nsys); + rhs = Matrix(localmesh->LocalNy, nsys); // Find out if we are on a boundary - int size = mesh->LocalNy-4; - SurfaceIter surf(mesh); + int size = localmesh->LocalNy-4; + SurfaceIter surf(localmesh); for(surf.first(); !surf.isDone(); surf.next()) { BoutReal ts; - int n = mesh->LocalNy-4; + int n = localmesh->LocalNy-4; if(!surf.closed(ts)) { // Open field line if(surf.firstY()) @@ -84,8 +85,9 @@ InvertParCR::~InvertParCR() { const Field3D InvertParCR::solve(const Field3D &f) { TRACE("InvertParCR::solve(Field3D)"); - Mesh *mesh = f.getMesh(); - Field3D result(mesh); + ASSERT1(localmesh == f.getMesh()); + + Field3D result(localmesh); result.allocate(); result.setLocation(f.getLocation()); @@ -96,7 +98,7 @@ const Field3D InvertParCR::solve(const Field3D &f) { new CyclicReduce(); // Loop over flux-surfaces - SurfaceIter surf(mesh); + SurfaceIter surf(localmesh); for(surf.first(); !surf.isDone(); surf.next()) { int x = surf.xpos; @@ -105,7 +107,7 @@ const Field3D InvertParCR::solve(const Field3D &f) { bool closed = surf.closed(ts); // Number of rows - int y0 = 0, size = mesh->LocalNy-4; // If no boundaries + int y0 = 0, size = localmesh->LocalNy-4; // If no boundaries if(!closed) { if(surf.firstY()) { y0 += 2; @@ -120,13 +122,13 @@ const Field3D InvertParCR::solve(const Field3D &f) { cr->setPeriodic(closed); // Take Fourier transform - for(int y=0;yLocalNy-4;y++) - rfft(f(x, y + 2), mesh->LocalNz, &rhs(y + y0, 0)); + for(int y=0;yLocalNy-4;y++) + rfft(f(x, y + 2), localmesh->LocalNz, &rhs(y + y0, 0)); // Set up tridiagonal system for(int k=0; kzlength(); // wave number is 1/[rad] - for(int y=0;yLocalNy-4;y++) { + for(int y=0;yLocalNy-4;y++) { BoutReal acoef = A(x, y+2); // Constant BoutReal bcoef = B(x, y+2) / coord->g_22(x,y+2); // d2dy2 @@ -165,7 +167,7 @@ const Field3D InvertParCR::solve(const Field3D &f) { for(int k=0; kzlength(); // wave number is 1/[rad] dcomplex phase(cos(kwave*ts) , sin(kwave*ts)); - c(k, mesh->LocalNy - 5) *= phase; + c(k, localmesh->LocalNy - 5) *= phase; } } }else { @@ -206,7 +208,7 @@ const Field3D InvertParCR::solve(const Field3D &f) { // Inverse Fourier transform for(int y=0;yLocalNz, result(x, y + 2 - y0)); + irfft(&rhs(y, 0), localmesh->LocalNz, result(x, y + 2 - y0)); } // Delete cyclic reduction object diff --git a/src/invert/parderiv/impls/cyclic/cyclic.hxx b/src/invert/parderiv/impls/cyclic/cyclic.hxx index 2de04d0575..de4758315c 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.hxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.hxx @@ -45,22 +45,37 @@ class InvertParCR : public InvertPar { public: - InvertParCR(Options *opt); + InvertParCR(Options *opt, Mesh *mesh_in = mesh); ~InvertParCR(); using InvertPar::solve; const Field3D solve(const Field3D &f) override; using InvertPar::setCoefA; - void setCoefA(const Field2D &f) override { A = f; } + void setCoefA(const Field2D &f) override { + ASSERT1(localmesh == f.getMesh()); + A = f; + } using InvertPar::setCoefB; - void setCoefB(const Field2D &f) override { B = f; } + void setCoefB(const Field2D &f) override { + ASSERT1(localmesh == f.getMesh()); + B = f; + } using InvertPar::setCoefC; - void setCoefC(const Field2D &f) override { C = f; } + void setCoefC(const Field2D &f) override { + ASSERT1(localmesh == f.getMesh()); + C = f; + } using InvertPar::setCoefD; - void setCoefD(const Field2D &f) override { D = f; } + void setCoefD(const Field2D &f) override { + ASSERT1(localmesh == f.getMesh()); + D = f; + } using InvertPar::setCoefE; - void setCoefE(const Field2D &f) override { E = f; } + void setCoefE(const Field2D &f) override { + ASSERT1(localmesh == f.getMesh()); + E = f; + } private: Field2D A, B, C, D, E; diff --git a/src/invert/parderiv/impls/serial/serial.cxx b/src/invert/parderiv/impls/serial/serial.cxx index 200650efd2..65b56ed8e8 100644 --- a/src/invert/parderiv/impls/serial/serial.cxx +++ b/src/invert/parderiv/impls/serial/serial.cxx @@ -51,26 +51,29 @@ #include -InvertParSerial::InvertParSerial(Options *opt) : InvertPar(opt), A(1.0), B(0.0), C(0.0), D(0.0), E(0.0) { - rhs = Matrix(mesh->LocalNy, (mesh->LocalNz)/2 + 1); - rhsk = Array(mesh->LocalNy-4); - xk = Array(mesh->LocalNy-4); - a = Array(mesh->LocalNy-4); - b = Array(mesh->LocalNy-4); - c = Array(mesh->LocalNy-4); +InvertParSerial::InvertParSerial(Options *opt, Mesh *mesh_in) + : InvertPar(opt, mesh_in), A(1.0), B(0.0), C(0.0), D(0.0), E(0.0) { + rhs = Matrix(localmesh->LocalNy, (localmesh->LocalNz)/2 + 1); + rhsk = Array(localmesh->LocalNy-4); + xk = Array(localmesh->LocalNy-4); + a = Array(localmesh->LocalNy-4); + b = Array(localmesh->LocalNy-4); + c = Array(localmesh->LocalNy-4); } const Field3D InvertParSerial::solve(const Field3D &f) { TRACE("InvertParSerial::solve(Field3D)"); - Field3D result(f.getMesh()); + ASSERT1(localmesh == f.getMesh()); + + Field3D result(localmesh); result.allocate(); result.setLocation(f.getLocation()); Coordinates *coord = f.getCoordinates(); // Loop over flux-surfaces - SurfaceIter surf(mesh); + SurfaceIter surf(localmesh); for(surf.first(); !surf.isDone(); surf.next()) { int x = surf.xpos; BoutReal ts; // Twist-shift angle @@ -78,20 +81,20 @@ const Field3D InvertParSerial::solve(const Field3D &f) { throw BoutException("InvertParSerial doesn't handle open surfaces"); // Take Fourier transform - for(int y=0;yLocalNy-4;y++) - rfft(f(x,y+2), mesh->LocalNz, &rhs(y, 0)); + for(int y=0;yLocalNy-4;y++) + rfft(f(x,y+2), localmesh->LocalNz, &rhs(y, 0)); // Solve cyclic tridiagonal system for each k - int nyq = (mesh->LocalNz)/2; + int nyq = (localmesh->LocalNz)/2; for(int k=0;k<=nyq;k++) { // Copy component of rhs into 1D array - for(int y=0;yLocalNy-4;y++) + for(int y=0;yLocalNy-4;y++) rhsk[y] = rhs(y, k); BoutReal kwave=k*2.0*PI/coord->zlength(); // wave number is 1/[rad] // Set up tridiagonal system - for(int y=0;yLocalNy-4;y++) { + for(int y=0;yLocalNy-4;y++) { BoutReal acoef = A(x, y+2); // Constant BoutReal bcoef = B(x, y+2) / coord->g_22(x,y+2); // d2dy2 BoutReal ccoef = C(x, y+2); // d2dydz @@ -113,19 +116,19 @@ const Field3D InvertParSerial::solve(const Field3D &f) { // Modify coefficients across twist-shift dcomplex phase(cos(kwave*ts) , -sin(kwave*ts)); a[0] *= phase; - c[mesh->LocalNy-5] /= phase; + c[localmesh->LocalNy-5] /= phase; // Solve cyclic tridiagonal system - cyclic_tridag(std::begin(a), std::begin(b), std::begin(c), std::begin(rhsk), std::begin(xk), mesh->LocalNy-4); + cyclic_tridag(std::begin(a), std::begin(b), std::begin(c), std::begin(rhsk), std::begin(xk), localmesh->LocalNy-4); // Put back into rhs array - for(int y=0;yLocalNy-4;y++) + for(int y=0;yLocalNy-4;y++) rhs(y, k) = xk[y]; } // Inverse Fourier transform - for(int y=0;yLocalNy-4;y++) - irfft(&rhs(y, 0), mesh->LocalNz, result(x,y+2)); + for(int y=0;yLocalNy-4;y++) + irfft(&rhs(y, 0), localmesh->LocalNz, result(x,y+2)); } return result; diff --git a/src/invert/parderiv/impls/serial/serial.hxx b/src/invert/parderiv/impls/serial/serial.hxx index a009c966c3..547c5be5d4 100644 --- a/src/invert/parderiv/impls/serial/serial.hxx +++ b/src/invert/parderiv/impls/serial/serial.hxx @@ -47,22 +47,37 @@ class InvertParSerial : public InvertPar { public: - InvertParSerial(Options* opt); + InvertParSerial(Options* opt, Mesh* mesh_in = mesh); ~InvertParSerial(){}; using InvertPar::solve; const Field3D solve(const Field3D &f) override; using InvertPar::setCoefA; - void setCoefA(const Field2D &f) override { A = f; } + void setCoefA(const Field2D &f) override { + ASSERT1(localmesh == f.getMesh()); + A = f; + } using InvertPar::setCoefB; - void setCoefB(const Field2D &f) override { B = f; } + void setCoefB(const Field2D &f) override { + ASSERT1(localmesh == f.getMesh()); + B = f; + } using InvertPar::setCoefC; - void setCoefC(const Field2D &f) override { C = f; } + void setCoefC(const Field2D &f) override { + ASSERT1(localmesh == f.getMesh()); + C = f; + } using InvertPar::setCoefD; - void setCoefD(const Field2D &f) override { D = f; } + void setCoefD(const Field2D &f) override { + ASSERT1(localmesh == f.getMesh()); + D = f; + } using InvertPar::setCoefE; - void setCoefE(const Field2D &f) override { E = f; } + void setCoefE(const Field2D &f) override { + ASSERT1(localmesh == f.getMesh()); + E = f; + } private: Field2D A, B, C, D, E; diff --git a/src/invert/parderiv/invert_parderiv.cxx b/src/invert/parderiv/invert_parderiv.cxx index 1938a383b6..9a06c9449e 100644 --- a/src/invert/parderiv/invert_parderiv.cxx +++ b/src/invert/parderiv/invert_parderiv.cxx @@ -30,8 +30,8 @@ #include #include "parderiv_factory.hxx" -InvertPar* InvertPar::Create() { - return ParDerivFactory::getInstance()->createInvertPar(); +InvertPar* InvertPar::Create(Mesh* mesh_in) { + return ParDerivFactory::getInstance()->createInvertPar(mesh_in); } const Field2D InvertPar::solve(const Field2D &f) { diff --git a/src/invert/parderiv/parderiv_factory.cxx b/src/invert/parderiv/parderiv_factory.cxx index 1408dd8960..2fa681e08f 100644 --- a/src/invert/parderiv/parderiv_factory.cxx +++ b/src/invert/parderiv/parderiv_factory.cxx @@ -23,14 +23,14 @@ ParDerivFactory* ParDerivFactory::getInstance() { return instance; } -InvertPar* ParDerivFactory::createInvertPar() { +InvertPar* ParDerivFactory::createInvertPar(Mesh *mesh_in) { // Get the default options section Options *opt = Options::getRoot()->getSection(default_section); - return createInvertPar( opt ); + return createInvertPar(opt, mesh_in); } -InvertPar* ParDerivFactory::createInvertPar(const char* type, Options *opt) { +InvertPar* ParDerivFactory::createInvertPar(const char* type, Options *opt, Mesh *mesh_in) { int NPES; MPI_Comm_size(BoutComm::get(), &NPES); @@ -38,17 +38,17 @@ InvertPar* ParDerivFactory::createInvertPar(const char* type, Options *opt) { opt = Options::getRoot()->getSection(default_section); if(!strcasecmp(type, PARDERIVSERIAL)) { - return new InvertParSerial(opt); + return new InvertParSerial(opt, mesh_in); }else if(!strcasecmp(type, PARDERIVCYCLIC)) { - return new InvertParCR(opt); + return new InvertParCR(opt, mesh_in); } throw BoutException("No such ParDeriv solver exists in this build, type: %s", type); } -InvertPar* ParDerivFactory::createInvertPar(Options *opts) { +InvertPar* ParDerivFactory::createInvertPar(Options *opts, Mesh *mesh_in) { string type; opts->get("type", type, "cyclic"); - return createInvertPar(type.c_str(), opts); + return createInvertPar(type.c_str(), opts, mesh_in); } diff --git a/src/invert/parderiv/parderiv_factory.hxx b/src/invert/parderiv/parderiv_factory.hxx index 9bdc314419..d5a3a5cb17 100644 --- a/src/invert/parderiv/parderiv_factory.hxx +++ b/src/invert/parderiv/parderiv_factory.hxx @@ -11,9 +11,9 @@ class ParDerivFactory { /// Return a pointer to the only instance static ParDerivFactory* getInstance(); - InvertPar* createInvertPar(); - InvertPar *createInvertPar(const char *type, Options *opt = nullptr); - InvertPar* createInvertPar(Options *opts); + InvertPar* createInvertPar(Mesh* mesh_in = mesh); + InvertPar *createInvertPar(const char *type, Options *opt = nullptr, Mesh* mesh_in = mesh); + InvertPar* createInvertPar(Options *opts, Mesh* mesh_in = mesh); private: ParDerivFactory() {} // Prevent instantiation of this class static ParDerivFactory* instance; ///< The only instance of this class (Singleton) From 8c887838723e1337248864c59750e9fea70c4f0b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 14 Nov 2018 13:43:15 +0000 Subject: [PATCH 0257/1783] Save Coordinates* pointer in Laplacian Always need the same Coordinates*, so call getCoordinates(location) once in constructor instead of in each call to solve(). --- include/invert_laplace.hxx | 2 + .../laplace/impls/cyclic/cyclic_laplace.cxx | 12 +-- .../impls/multigrid/multigrid_laplace.cxx | 3 - .../laplace/impls/naulin/naulin_laplace.cxx | 1 - src/invert/laplace/impls/pdd/pdd.cxx | 2 +- .../laplace/impls/petsc/petsc_laplace.cxx | 81 +++++++++---------- .../laplace/impls/serial_band/serial_band.cxx | 80 +++++++++--------- .../laplace/impls/serial_tri/serial_tri.cxx | 2 +- .../laplace/impls/shoot/shoot_laplace.cxx | 4 +- src/invert/laplace/impls/spt/spt.cxx | 2 +- src/invert/laplace/invert_laplace.cxx | 78 +++++++++--------- 11 files changed, 123 insertions(+), 144 deletions(-) diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index 005cc61a78..17d1e48507 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -229,6 +229,8 @@ protected: bool includeguards=true); CELL_LOC location; ///< staggered grid location of this solver Mesh* localmesh; ///< Mesh object for this solver + Coordinates* coords; ///< Coordinates object, so we only have to call + /// localmesh->getCoordinates(location) once private: /// Singleton instance static Laplacian *instance; diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index 4d0df4e7c4..ff31e5a77b 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -95,8 +95,6 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) FieldPerp x(localmesh); // Result x.allocate(); - Coordinates *coord = localmesh->getCoordinates(location); - int jy = rhs.getIndex(); // Get the Y index x.setIndex(jy); @@ -142,7 +140,7 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) // including boundary conditions BOUT_OMP(for nowait) for (int kz = 0; kz < nmode; kz++) { - BoutReal zlen = coord->dz * (localmesh->LocalNz - 3); + BoutReal zlen = coords->dz * (localmesh->LocalNz - 3); BoutReal kwave = kz * 2.0 * PI / (2. * zlen); // wave number is 1/[rad]; DST has extra 2. @@ -210,7 +208,7 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) // including boundary conditions BOUT_OMP(for nowait) for (int kz = 0; kz < nmode; kz++) { - BoutReal kwave = kz * 2.0 * PI / (coord->zlength()); // wave number is 1/[rad] + BoutReal kwave = kz * 2.0 * PI / (coords->zlength()); // wave number is 1/[rad] tridagMatrix(&a(kz, 0), &b(kz, 0), &c(kz, 0), &bcmplx(kz, 0), jy, kz, // True for the component constant (DC) in Z kwave, // Z wave number @@ -259,8 +257,6 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { x.allocate(); x.setLocation(location); - Coordinates *coord = rhs.getCoordinates(); - // Get the width of the boundary // If the flags to assign that only one guard cell should be used is set @@ -341,7 +337,7 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { int iy = ys + ind / nmode; int kz = ind % nmode; - BoutReal zlen = coord->dz * (localmesh->LocalNz - 3); + BoutReal zlen = coords->dz * (localmesh->LocalNz - 3); BoutReal kwave = kz * 2.0 * PI / (2. * zlen); // wave number is 1/[rad]; DST has extra 2. @@ -421,7 +417,7 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { int iy = ys + ind / nmode; int kz = ind % nmode; - BoutReal kwave = kz * 2.0 * PI / (coord->zlength()); // wave number is 1/[rad] + BoutReal kwave = kz * 2.0 * PI / (coords->zlength()); // wave number is 1/[rad] tridagMatrix(&a3D(ind, 0), &b3D(ind, 0), &c3D(ind, 0), &bcmplx3D(ind, 0), iy, kz, // True for the component constant (DC) in Z kwave, // Z wave number diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index 567ec0e583..d3e419e54f 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -209,8 +209,6 @@ const FieldPerp LaplaceMultigrid::solve(const FieldPerp &b_in, const FieldPerp & BoutReal t0,t1; - Coordinates *coords = localmesh->getCoordinates(location); - yindex = b_in.getIndex(); int level = kMG->mglevel-1; int lzz = kMG->lnz[level]; @@ -555,7 +553,6 @@ void LaplaceMultigrid::generateMatrixF(int level) { // Set (fine-level) matrix entries - Coordinates *coords = localmesh->getCoordinates(location); BoutReal *mat; mat = kMG->matmg[level]; int llx = kMG->lnx[level]; diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index 87e1093a61..a216d9de70 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -172,7 +172,6 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { ASSERT1(Acoef.getLocation() == location); ASSERT1(localmesh == rhs.getMesh() && localmesh == x0.getMesh()); - Coordinates *coords = rhs.getCoordinates(); Field3D x(x0); // Result Field3D rhsOverD = rhs/Dcoef; diff --git a/src/invert/laplace/impls/pdd/pdd.cxx b/src/invert/laplace/impls/pdd/pdd.cxx index 4a2fbbf46a..23c09145c7 100644 --- a/src/invert/laplace/impls/pdd/pdd.cxx +++ b/src/invert/laplace/impls/pdd/pdd.cxx @@ -164,7 +164,7 @@ void LaplacePDD::start(const FieldPerp &b, PDD_data &data) { /// Create the matrices to be inverted (one for each z point) - BoutReal kwaveFactor = 2.0 * PI / localmesh->getCoordinates(location)->zlength(); + BoutReal kwaveFactor = 2.0 * PI / coords->zlength(); /// Set matrix elements for (int kz = 0; kz <= maxmode; kz++) { diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.cxx b/src/invert/laplace/impls/petsc/petsc_laplace.cxx index 1555345456..d8cf5a0ff6 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.cxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.cxx @@ -362,9 +362,6 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { } #endif - // Get the metric tensor - Coordinates* coord = localmesh->getCoordinates(location); - int y = b.getIndex(); // Get the Y index sol.setIndex(y); // Initialize the solution field. sol = 0.; @@ -402,21 +399,21 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { // Set values corresponding to nodes adjacent in x if( fourth_order ) { // Fourth Order Accuracy on Boundary - Element(i,x,z, 0, 0, -25.0 / (12.0*coord->dx(x,y)) / sqrt(coord->g_11(x,y)), MatA ); - Element(i,x,z, 1, 0, 4.0 / coord->dx(x,y) / sqrt(coord->g_11(x,y)), MatA ); - Element(i,x,z, 2, 0, -3.0 / coord->dx(x,y) / sqrt(coord->g_11(x,y)), MatA ); - Element(i,x,z, 3, 0, 4.0 / (3.0*coord->dx(x,y)) / sqrt(coord->g_11(x,y)), MatA ); - Element(i,x,z, 4, 0, -1.0 / (4.0*coord->dx(x,y)) / sqrt(coord->g_11(x,y)), MatA ); + Element(i,x,z, 0, 0, -25.0 / (12.0*coords->dx(x,y)) / sqrt(coords->g_11(x,y)), MatA ); + Element(i,x,z, 1, 0, 4.0 / coords->dx(x,y) / sqrt(coords->g_11(x,y)), MatA ); + Element(i,x,z, 2, 0, -3.0 / coords->dx(x,y) / sqrt(coords->g_11(x,y)), MatA ); + Element(i,x,z, 3, 0, 4.0 / (3.0*coords->dx(x,y)) / sqrt(coords->g_11(x,y)), MatA ); + Element(i,x,z, 4, 0, -1.0 / (4.0*coords->dx(x,y)) / sqrt(coords->g_11(x,y)), MatA ); } else { // // Second Order Accuracy on Boundary -// Element(i,x,z, 0, 0, -3.0 / (2.0*coord->dx(x,y)), MatA ); -// Element(i,x,z, 1, 0, 2.0 / coord->dx(x,y), MatA ); -// Element(i,x,z, 2, 0, -1.0 / (2.0*coord->dx(x,y)), MatA ); +// Element(i,x,z, 0, 0, -3.0 / (2.0*coords->dx(x,y)), MatA ); +// Element(i,x,z, 1, 0, 2.0 / coords->dx(x,y), MatA ); +// Element(i,x,z, 2, 0, -1.0 / (2.0*coords->dx(x,y)), MatA ); // // Element(i,x,z, 3, 0, 0.0, MatA ); // Reset these elements to 0 in case 4th order flag was used previously: not allowed now // // Element(i,x,z, 4, 0, 0.0, MatA ); // Second Order Accuracy on Boundary, set half-way between grid points - Element(i,x,z, 0, 0, -1.0 / coord->dx(x,y) / sqrt(coord->g_11(x,y)), MatA ); - Element(i,x,z, 1, 0, 1.0 / coord->dx(x,y) / sqrt(coord->g_11(x,y)), MatA ); + Element(i,x,z, 0, 0, -1.0 / coords->dx(x,y) / sqrt(coords->g_11(x,y)), MatA ); + Element(i,x,z, 1, 0, 1.0 / coords->dx(x,y) / sqrt(coords->g_11(x,y)), MatA ); Element(i,x,z, 2, 0, 0.0, MatA ); // Element(i,x,z, 3, 0, 0.0, MatA ); // Reset these elements to 0 in case 4th order flag was used previously: not allowed now // Element(i,x,z, 4, 0, 0.0, MatA ); @@ -473,11 +470,11 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { // Set the matrix coefficients Coeffs( x, y, z, A1, A2, A3, A4, A5 ); - BoutReal dx = coord->dx(x,y); - BoutReal dx2 = SQ(coord->dx(x,y)); - BoutReal dz = coord->dz; - BoutReal dz2 = SQ(coord->dz); - BoutReal dxdz = coord->dx(x,y) * coord->dz; + BoutReal dx = coords->dx(x,y); + BoutReal dx2 = SQ(coords->dx(x,y)); + BoutReal dz = coords->dz; + BoutReal dz2 = SQ(coords->dz); + BoutReal dxdz = coords->dx(x,y) * coords->dz; ASSERT3(finite(A1)); ASSERT3(finite(A2)); @@ -651,22 +648,22 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { // Set values corresponding to nodes adjacent in x if( fourth_order ) { // Fourth Order Accuracy on Boundary - Element(i,x,z, 0, 0, 25.0 / (12.0*coord->dx(x,y)) / sqrt(coord->g_11(x,y)), MatA ); - Element(i,x,z, -1, 0, -4.0 / coord->dx(x,y) / sqrt(coord->g_11(x,y)), MatA ); - Element(i,x,z, -2, 0, 3.0 / coord->dx(x,y) / sqrt(coord->g_11(x,y)), MatA ); - Element(i,x,z, -3, 0, -4.0 / (3.0*coord->dx(x,y)) / sqrt(coord->g_11(x,y)), MatA ); - Element(i,x,z, -4, 0, 1.0 / (4.0*coord->dx(x,y)) / sqrt(coord->g_11(x,y)), MatA ); + Element(i,x,z, 0, 0, 25.0 / (12.0*coords->dx(x,y)) / sqrt(coords->g_11(x,y)), MatA ); + Element(i,x,z, -1, 0, -4.0 / coords->dx(x,y) / sqrt(coords->g_11(x,y)), MatA ); + Element(i,x,z, -2, 0, 3.0 / coords->dx(x,y) / sqrt(coords->g_11(x,y)), MatA ); + Element(i,x,z, -3, 0, -4.0 / (3.0*coords->dx(x,y)) / sqrt(coords->g_11(x,y)), MatA ); + Element(i,x,z, -4, 0, 1.0 / (4.0*coords->dx(x,y)) / sqrt(coords->g_11(x,y)), MatA ); } else { // // Second Order Accuracy on Boundary -// Element(i,x,z, 0, 0, 3.0 / (2.0*coord->dx(x,y)), MatA ); -// Element(i,x,z, -1, 0, -2.0 / coord->dx(x,y), MatA ); -// Element(i,x,z, -2, 0, 1.0 / (2.0*coord->dx(x,y)), MatA ); +// Element(i,x,z, 0, 0, 3.0 / (2.0*coords->dx(x,y)), MatA ); +// Element(i,x,z, -1, 0, -2.0 / coords->dx(x,y), MatA ); +// Element(i,x,z, -2, 0, 1.0 / (2.0*coords->dx(x,y)), MatA ); // // Element(i,x,z, -3, 0, 0.0, MatA ); // Reset these elements to 0 in case 4th order flag was used previously: not allowed now // // Element(i,x,z, -4, 0, 0.0, MatA ); // Second Order Accuracy on Boundary, set half-way between grid points - Element(i,x,z, 0, 0, 1.0 / coord->dx(x,y) / sqrt(coord->g_11(x,y)), MatA ); - Element(i,x,z, -1, 0, -1.0 / coord->dx(x,y) / sqrt(coord->g_11(x,y)), MatA ); + Element(i,x,z, 0, 0, 1.0 / coords->dx(x,y) / sqrt(coords->g_11(x,y)), MatA ); + Element(i,x,z, -1, 0, -1.0 / coords->dx(x,y) / sqrt(coords->g_11(x,y)), MatA ); Element(i,x,z, -2, 0, 0.0, MatA ); // Element(i,x,z, -3, 0, 0.0, MatA ); // Reset these elements to 0 in case 4th order flag was used previously: not allowed now // Element(i,x,z, -4, 0, 0.0, MatA ); @@ -937,18 +934,16 @@ void LaplacePetsc::Element(int i, int x, int z, */ void LaplacePetsc::Coeffs( int x, int y, int z, BoutReal &coef1, BoutReal &coef2, BoutReal &coef3, BoutReal &coef4, BoutReal &coef5 ) { - Coordinates *coord = localmesh->getCoordinates(location); // Get metric tensor - - coef1 = coord->g11(x,y); // X 2nd derivative coefficient - coef2 = coord->g33(x,y); // Z 2nd derivative coefficient - coef3 = 2.*coord->g13(x,y); // X-Z mixed derivative coefficient + coef1 = coords->g11(x,y); // X 2nd derivative coefficient + coef2 = coords->g33(x,y); // Z 2nd derivative coefficient + coef3 = 2.*coords->g13(x,y); // X-Z mixed derivative coefficient coef4 = 0.0; coef5 = 0.0; // If global flag all_terms are set (true by default) if (all_terms) { - coef4 = coord->G1(x,y); // X 1st derivative - coef5 = coord->G3(x,y); // Z 1st derivative + coef4 = coords->G1(x,y); // X 1st derivative + coef5 = coords->G3(x,y); // Z 1st derivative ASSERT3(finite(coef4)); ASSERT3(finite(coef5)); @@ -957,13 +952,13 @@ void LaplacePetsc::Coeffs( int x, int y, int z, BoutReal &coef1, BoutReal &coef2 if(nonuniform) { // non-uniform mesh correction if((x != 0) && (x != (localmesh->LocalNx-1))) { - coef4 -= 0.5 * ( ( coord->dx(x+1,y) - coord->dx(x-1,y) ) / SQ(coord->dx(x,y)) ) * coef1; // BOUT-06 term + coef4 -= 0.5 * ( ( coords->dx(x+1,y) - coords->dx(x-1,y) ) / SQ(coords->dx(x,y)) ) * coef1; // BOUT-06 term } } if(localmesh->IncIntShear) { // d2dz2 term - coef2 += coord->g11(x,y) * coord->IntShiftTorsion(x,y) * coord->IntShiftTorsion(x,y); + coef2 += coords->g11(x,y) * coords->IntShiftTorsion(x,y) * coords->IntShiftTorsion(x,y); // Mixed derivative coef3 = 0.0; // This cancels out } @@ -993,19 +988,19 @@ void LaplacePetsc::Coeffs( int x, int y, int z, BoutReal &coef1, BoutReal &coef2 int zmm = z-2; // z minus 1 minus 1 if (zmm<0) zmm += meshz; // Fourth order discretization of C in x - ddx_C = (-C2(x+2,y,z) + 8.*C2(x+1,y,z) - 8.*C2(x-1,y,z) + C2(x-2,y,z)) / (12.*coord->dx(x,y)*(C1(x,y,z))); + ddx_C = (-C2(x+2,y,z) + 8.*C2(x+1,y,z) - 8.*C2(x-1,y,z) + C2(x-2,y,z)) / (12.*coords->dx(x,y)*(C1(x,y,z))); // Fourth order discretization of C in z - ddz_C = (-C2(x,y,zpp) + 8.*C2(x,y,zp) - 8.*C2(x,y,zm) + C2(x,y,zmm)) / (12.*coord->dz*(C1(x,y,z))); + ddz_C = (-C2(x,y,zpp) + 8.*C2(x,y,zp) - 8.*C2(x,y,zm) + C2(x,y,zmm)) / (12.*coords->dz*(C1(x,y,z))); } else { // Second order discretization of C in x - ddx_C = (C2(x+1,y,z) - C2(x-1,y,z)) / (2.*coord->dx(x,y)*(C1(x,y,z))); + ddx_C = (C2(x+1,y,z) - C2(x-1,y,z)) / (2.*coords->dx(x,y)*(C1(x,y,z))); // Second order discretization of C in z - ddz_C = (C2(x,y,zp) - C2(x,y,zm)) / (2.*coord->dz*(C1(x,y,z))); + ddz_C = (C2(x,y,zp) - C2(x,y,zm)) / (2.*coords->dz*(C1(x,y,z))); } - coef4 += coord->g11(x,y) * ddx_C + coord->g13(x,y) * ddz_C; - coef5 += coord->g13(x,y) * ddx_C + coord->g33(x,y) * ddz_C; + coef4 += coords->g11(x,y) * ddx_C + coords->g13(x,y) * ddz_C; + coef5 += coords->g13(x,y) * ddx_C + coords->g33(x,y) * ddz_C; } } diff --git a/src/invert/laplace/impls/serial_band/serial_band.cxx b/src/invert/laplace/impls/serial_band/serial_band.cxx index b9541bf867..46835d8174 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.cxx +++ b/src/invert/laplace/impls/serial_band/serial_band.cxx @@ -88,8 +88,6 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 int jy = b.getIndex(); x.setIndex(jy); - Coordinates *coord = localmesh->getCoordinates(location); - int ncz = localmesh->LocalNz; int ncx = localmesh->LocalNx-1; @@ -128,7 +126,7 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 ///////// PERFORM INVERSION ///////// // shift freqs according to FFT convention - kwave=iz*2.0*PI/coord->zlength(); // wave number is 1/[rad] + kwave=iz*2.0*PI/coords->zlength(); // wave number is 1/[rad] // set bk1d for(int ix=0;ixLocalNx;ix++) @@ -150,9 +148,9 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 A(ix, 4) = 0.; #else // Set coefficients - coef1 = coord->g11(ix,jy); // X 2nd derivative - coef2 = coord->g33(ix,jy); // Z 2nd derivative - coef3 = coord->g13(ix,jy); // X-Z mixed derivatives + coef1 = coords->g11(ix,jy); // X 2nd derivative + coef2 = coords->g33(ix,jy); // Z 2nd derivative + coef3 = coords->g13(ix,jy); // X-Z mixed derivatives coef4 = 0.0; // X 1st derivative coef5 = 0.0; // Z 1st derivative coef6 = Acoef(ix,jy); // Constant @@ -163,26 +161,26 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 coef3 *= Dcoef(ix,jy); if(all_terms) { - coef4 = coord->G1(ix,jy); - coef5 = coord->G3(ix,jy); + coef4 = coords->G1(ix,jy); + coef5 = coords->G3(ix,jy); } if(nonuniform) { // non-uniform localmesh correction if((ix != 0) && (ix != ncx)) - coef4 += coord->g11(ix,jy)*( (1.0/coord->dx(ix+1,jy)) - (1.0/coord->dx(ix-1,jy)) )/(2.0*coord->dx(ix,jy)); + coef4 += coords->g11(ix,jy)*( (1.0/coords->dx(ix+1,jy)) - (1.0/coords->dx(ix-1,jy)) )/(2.0*coords->dx(ix,jy)); } // A first order derivative term (1/c)\nabla_perp c\cdot\nabla_\perp x if((ix > 1) && (ix < (localmesh->LocalNx-2))) - coef4 += coord->g11(ix,jy) * (Ccoef(ix-2,jy) - 8.*Ccoef(ix-1,jy) + 8.*Ccoef(ix+1,jy) - Ccoef(ix+2,jy)) / (12.*coord->dx(ix,jy)*(Ccoef(ix,jy))); + coef4 += coords->g11(ix,jy) * (Ccoef(ix-2,jy) - 8.*Ccoef(ix-1,jy) + 8.*Ccoef(ix+1,jy) - Ccoef(ix+2,jy)) / (12.*coords->dx(ix,jy)*(Ccoef(ix,jy))); // Put into matrix - coef1 /= 12.* SQ(coord->dx(ix,jy)); + coef1 /= 12.* SQ(coords->dx(ix,jy)); coef2 *= SQ(kwave); - coef3 *= kwave / (12. * coord->dx(ix,jy)); - coef4 /= 12. * coord->dx(ix,jy); + coef3 *= kwave / (12. * coords->dx(ix,jy)); + coef4 /= 12. * coords->dx(ix,jy); coef5 *= kwave; A(ix, 0) = dcomplex(-coef1 + coef4, coef3); @@ -198,9 +196,9 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 int ix = 1; - coef1=coord->g11(ix,jy)/(SQ(coord->dx(ix,jy))); - coef2=coord->g33(ix,jy); - coef3= kwave * coord->g13(ix,jy)/(2. * coord->dx(ix,jy)); + coef1=coords->g11(ix,jy)/(SQ(coords->dx(ix,jy))); + coef2=coords->g33(ix,jy); + coef3= kwave * coords->g13(ix,jy)/(2. * coords->dx(ix,jy)); // Multiply Delp2 component by a factor coef1 *= Dcoef(ix,jy); @@ -215,9 +213,9 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 ix = ncx-1; - coef1=coord->g11(ix,jy)/(SQ(coord->dx(ix,jy))); - coef2=coord->g33(ix,jy); - coef3= kwave * coord->g13(ix,jy)/(2. * coord->dx(ix,jy)); + coef1=coords->g11(ix,jy)/(SQ(coords->dx(ix,jy))); + coef2=coords->g33(ix,jy); + coef3= kwave * coords->g13(ix,jy)/(2. * coords->dx(ix,jy)); A(ix, 0) = 0.0; A(ix, 1) = dcomplex(coef1, -coef3); @@ -253,8 +251,8 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 for (int ix=0;ixg_11(ix, jy)) / coord->dx(ix, jy); - A(ix, 3) = .5 / sqrt(coord->g_11(ix, jy)) / coord->dx(ix, jy); + A(ix, 2) = -.5 / sqrt(coords->g_11(ix, jy)) / coords->dx(ix, jy); + A(ix, 3) = .5 / sqrt(coords->g_11(ix, jy)) / coords->dx(ix, jy); A(ix, 4) = 0.; } @@ -275,18 +273,18 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 for (int ix=0;ixg_22(ix, jy)); - A(ix, 3) = 4. / sqrt(coord->g_22(ix + 1, jy)); - A(ix, 4) = -1. / sqrt(coord->g_22(ix + 2, jy)); + A(ix, 2) = -3. / sqrt(coords->g_22(ix, jy)); + A(ix, 3) = 4. / sqrt(coords->g_22(ix + 1, jy)); + A(ix, 4) = -1. / sqrt(coords->g_22(ix + 2, jy)); } } else if(inner_boundary_flags & INVERT_DC_GRADPARINV) { for (int ix=0;ixg_22(ix, jy)); - A(ix, 3) = 4. * sqrt(coord->g_22(ix + 1, jy)); - A(ix, 4) = -sqrt(coord->g_22(ix + 2, jy)); + A(ix, 2) = -3. * sqrt(coords->g_22(ix, jy)); + A(ix, 3) = 4. * sqrt(coords->g_22(ix + 1, jy)); + A(ix, 4) = -sqrt(coords->g_22(ix + 2, jy)); } } else if (inner_boundary_flags & INVERT_DC_LAP) { @@ -319,27 +317,27 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 int ix = 1; - coef1=coord->g11(ix,jy)/(12.* SQ(coord->dx(ix,jy))); + coef1=coords->g11(ix,jy)/(12.* SQ(coords->dx(ix,jy))); - coef2=coord->g33(ix,jy); + coef2=coords->g33(ix,jy); - coef3= kwave * coord->g13(ix,jy)/(2. * coord->dx(ix,jy)); + coef3= kwave * coords->g13(ix,jy)/(2. * coords->dx(ix,jy)); coef4 = Acoef(ix,jy); // Combine 4th order at 1 with 2nd order at 0 A(1, 0) = 0.0; // Not used A(1, 1) = dcomplex( - (14. - SQ(coord->dx(0, jy) * kwave) * coord->g33(0, jy) / coord->g11(0, jy)) * + (14. - SQ(coords->dx(0, jy) * kwave) * coords->g33(0, jy) / coords->g11(0, jy)) * coef1, -coef3); A(1, 2) = dcomplex(-29. * coef1 - SQ(kwave) * coef2 + coef4, 0.0); A(1, 3) = dcomplex(16. * coef1, coef3); A(1, 4) = dcomplex(-coef1, 0.0); - coef1=coord->g11(ix,jy)/(SQ(coord->dx(ix,jy))); - coef2=coord->g33(ix,jy); - coef3= kwave * coord->g13(ix,jy)/(2. * coord->dx(ix,jy)); + coef1=coords->g11(ix,jy)/(SQ(coords->dx(ix,jy))); + coef2=coords->g33(ix,jy); + coef3= kwave * coords->g13(ix,jy)/(2. * coords->dx(ix,jy)); // Use 2nd order at 1 A(0, 0) = 0.0; // Should never be used @@ -361,11 +359,11 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 int ix = ncx-1; - coef1=coord->g11(ix,jy)/(12.* SQ(coord->dx(ix,jy))); + coef1=coords->g11(ix,jy)/(12.* SQ(coords->dx(ix,jy))); - coef2=coord->g33(ix,jy); + coef2=coords->g33(ix,jy); - coef3= kwave * coord->g13(ix,jy)/(2. * coord->dx(ix,jy)); + coef3= kwave * coords->g13(ix,jy)/(2. * coords->dx(ix,jy)); coef4 = Acoef(ix,jy); @@ -375,14 +373,14 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 A(ix, 2) = dcomplex(-29. * coef1 - SQ(kwave) * coef2 + coef4, 0.0); A(ix, 3) = dcomplex( (14. - - SQ(coord->dx(ncx, jy) * kwave) * coord->g33(ncx, jy) / coord->g11(ncx, jy)) * + SQ(coords->dx(ncx, jy) * kwave) * coords->g33(ncx, jy) / coords->g11(ncx, jy)) * coef1, coef3); A(ix, 4) = 0.0; // Not used - coef1=coord->g11(ix,jy)/(SQ(coord->dx(ix,jy))); - coef2=coord->g33(ix,jy); - coef3= kwave * coord->g13(ix,jy)/(2. * coord->dx(ix,jy)); + coef1=coords->g11(ix,jy)/(SQ(coords->dx(ix,jy))); + coef2=coords->g33(ix,jy); + coef3= kwave * coords->g13(ix,jy)/(2. * coords->dx(ix,jy)); // Use 2nd order at ncx - 1 A(ncx, 0) = dcomplex(coef1, -coef3); diff --git a/src/invert/laplace/impls/serial_tri/serial_tri.cxx b/src/invert/laplace/impls/serial_tri/serial_tri.cxx index 0a2cbe02b1..fc4c226ac7 100644 --- a/src/invert/laplace/impls/serial_tri/serial_tri.cxx +++ b/src/invert/laplace/impls/serial_tri/serial_tri.cxx @@ -84,7 +84,7 @@ const FieldPerp LaplaceSerialTri::solve(const FieldPerp &b, const FieldPerp &x0) int ncz = localmesh->LocalNz; // No of z pnts int ncx = localmesh->LocalNx; // No of x pnts - BoutReal kwaveFactor = 2.0 * PI / localmesh->getCoordinates(location)->zlength(); + BoutReal kwaveFactor = 2.0 * PI / coords->zlength(); // Setting the width of the boundary. // NOTE: The default is a width of 2 guard cells diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.cxx b/src/invert/laplace/impls/shoot/shoot_laplace.cxx index 86430f928c..3b515e6ed7 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.cxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.cxx @@ -77,8 +77,6 @@ const FieldPerp LaplaceShoot::solve(const FieldPerp &rhs) { int jy = rhs.getIndex(); // Get the Y index x.setIndex(jy); - Coordinates *coord = localmesh->getCoordinates(location); - // Get the width of the boundary int inbndry = localmesh->xstart, outbndry=localmesh->xstart; @@ -135,7 +133,7 @@ const FieldPerp LaplaceShoot::solve(const FieldPerp &rhs) { rfft(rhs[ix], localmesh->LocalNz, std::begin(rhsk)); for(int kz=0; kzzlength()); // wave number is 1/[rad] + BoutReal kwave=kz*2.0*PI/(coords->zlength()); // wave number is 1/[rad] // Get the coefficients dcomplex a,b,c; diff --git a/src/invert/laplace/impls/spt/spt.cxx b/src/invert/laplace/impls/spt/spt.cxx index e75cad6cae..42b1f30935 100644 --- a/src/invert/laplace/impls/spt/spt.cxx +++ b/src/invert/laplace/impls/spt/spt.cxx @@ -291,7 +291,7 @@ int LaplaceSPT::start(const FieldPerp &b, SPT_data &data) { data.bk(kz, ix) = dc1d[kz]; } - BoutReal kwaveFactor = 2.0 * PI / localmesh->getCoordinates(location)->zlength(); + BoutReal kwaveFactor = 2.0 * PI / coords->zlength(); /// Set matrix elements for (int kz = 0; kz <= maxmode; kz++) { diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index 2e66fa3767..e120f86244 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -65,6 +65,8 @@ Laplacian::Laplacian(Options *options, const CELL_LOC loc, Mesh *mesh_in) location = CELL_CENTRE; } + coords = localmesh->getCoordinates(location); + // Communication option. Controls if asyncronous sends are used options->get("async", async_send, true); @@ -81,7 +83,7 @@ Laplacian::Laplacian(Options *options, const CELL_LOC loc, Mesh *mesh_in) OPTION(options, low_mem, false); OPTION(options, nonuniform, - localmesh->getCoordinates(location)->non_uniform); // Default is the mesh setting + coords->non_uniform); // Default is the mesh setting OPTION(options, all_terms, true); // Include first derivative terms @@ -249,9 +251,7 @@ void Laplacian::tridagCoefs(int jx, int jy, int jz, ASSERT1(ccoef == nullptr || ccoef->getLocation() == loc); ASSERT1(d == nullptr || d->getLocation() == loc); - Coordinates *coord = localmesh->getCoordinates(loc); - - BoutReal kwave=jz*2.0*PI/coord->zlength(); // wave number is 1/[rad] + BoutReal kwave=jz*2.0*PI/coords->zlength(); // wave number is 1/[rad] tridagCoefs(jx, jy, kwave, a, b, c, @@ -296,18 +296,16 @@ void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, BoutReal coef1, coef2, coef3, coef4, coef5; - Coordinates *coord = localmesh->getCoordinates(loc); - - coef1=coord->g11(jx,jy); ///< X 2nd derivative coefficient - coef2=coord->g33(jx,jy); ///< Z 2nd derivative coefficient - coef3=2.*coord->g13(jx,jy); ///< X-Z mixed derivative coefficient + coef1=coords->g11(jx,jy); ///< X 2nd derivative coefficient + coef2=coords->g33(jx,jy); ///< Z 2nd derivative coefficient + coef3=2.*coords->g13(jx,jy); ///< X-Z mixed derivative coefficient coef4 = 0.0; coef5 = 0.0; // If global flag all_terms are set (true by default) if(all_terms) { - coef4 = coord->G1(jx,jy); // X 1st derivative - coef5 = coord->G3(jx,jy); // Z 1st derivative + coef4 = coords->G1(jx,jy); // X 1st derivative + coef5 = coords->G3(jx,jy); // Z 1st derivative } if (d != nullptr) { @@ -322,26 +320,26 @@ void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, if(nonuniform) { // non-uniform mesh correction if((jx != 0) && (jx != (localmesh->LocalNx-1))) { - coef4 -= 0.5*((coord->dx(jx+1,jy) - coord->dx(jx-1,jy))/SQ(coord->dx(jx,jy)))*coef1; + coef4 -= 0.5*((coords->dx(jx+1,jy) - coords->dx(jx-1,jy))/SQ(coords->dx(jx,jy)))*coef1; } } if (ccoef != nullptr) { // A first order derivative term if((jx > 0) && (jx < (localmesh->LocalNx-1))) - coef4 += coord->g11(jx,jy) * ((*ccoef)(jx+1,jy) - (*ccoef)(jx-1,jy)) / (2.*coord->dx(jx,jy)*((*ccoef)(jx,jy))); + coef4 += coords->g11(jx,jy) * ((*ccoef)(jx+1,jy) - (*ccoef)(jx-1,jy)) / (2.*coords->dx(jx,jy)*((*ccoef)(jx,jy))); } if(localmesh->IncIntShear) { // d2dz2 term - coef2 += coord->g11(jx,jy) * coord->IntShiftTorsion(jx,jy) * coord->IntShiftTorsion(jx,jy); + coef2 += coords->g11(jx,jy) * coords->IntShiftTorsion(jx,jy) * coords->IntShiftTorsion(jx,jy); // Mixed derivative coef3 = 0.0; // This cancels out } - coef1 /= SQ(coord->dx(jx,jy)); - coef3 /= 2.*coord->dx(jx,jy); - coef4 /= 2.*coord->dx(jx,jy); + coef1 /= SQ(coords->dx(jx,jy)); + coef3 /= 2.*coords->dx(jx,jy); + coef4 /= 2.*coords->dx(jx,jy); a = dcomplex(coef1 - coef4,-kwave*coef3); b = dcomplex(-2.0*coef1 - SQ(kwave)*coef2,kwave*coef5); @@ -361,11 +359,9 @@ void Laplacian::tridagMatrix(dcomplex **avec, dcomplex **bvec, dcomplex **cvec, ASSERT1(ccoef->getLocation() == location); ASSERT1(d->getLocation() == location); - Coordinates *coord = localmesh->getCoordinates(location); - BOUT_OMP(parallel for) for(int kz = 0; kz <= maxmode; kz++) { - BoutReal kwave=kz*2.0*PI/coord->zlength(); // wave number is 1/[rad] + BoutReal kwave=kz*2.0*PI/coords->zlength(); // wave number is 1/[rad] tridagMatrix(avec[kz], bvec[kz], cvec[kz], bk[kz], @@ -426,8 +422,6 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, int xs = 0; // xstart set to the start of x on this processor (including ghost points) int xe = localmesh->LocalNx-1; // xend set to the end of x on this processor (including ghost points) - Coordinates *coord = localmesh->getCoordinates(location); - // Do not want boundary cells if x is periodic for cyclic solver. Only other solver which // works with periodicX is serial_tri, which uses includeguards==true, so the below isn't called. if(!includeguards) { @@ -481,8 +475,8 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, // Zero gradient at inner boundary for (int ix=0;ixg_11(ix,jy))/coord->dx(ix,jy); - cvec[ix] = 1./sqrt(coord->g_11(ix,jy))/coord->dx(ix,jy); + bvec[ix] = -1./sqrt(coords->g_11(ix,jy))/coords->dx(ix,jy); + cvec[ix] = 1./sqrt(coords->g_11(ix,jy))/coords->dx(ix,jy); } } else if(inner_boundary_flags & INVERT_DC_GRAD) { @@ -496,15 +490,15 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, else if(inner_boundary_flags & INVERT_DC_GRADPAR) { for (int ix=0;ixg_22(ix,jy)); - cvec[ix] = -1.0/sqrt(coord->g_22(ix+1,jy)); + bvec[ix] = 1.0/sqrt(coords->g_22(ix,jy)); + cvec[ix] = -1.0/sqrt(coords->g_22(ix+1,jy)); } } else if(inner_boundary_flags & INVERT_DC_GRADPARINV) { for (int ix=0;ixg_22(ix,jy)); - cvec[ix] = -sqrt(coord->g_22(ix+1,jy)); + bvec[ix] = sqrt(coords->g_22(ix,jy)); + cvec[ix] = -sqrt(coords->g_22(ix+1,jy)); } } else if (inner_boundary_flags & INVERT_DC_LAP) { @@ -519,7 +513,7 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, for (int ix=0;ixdx(ix,jy)/sqrt(coord->g11(ix,jy))); + cvec[ix] = -exp(-k*coords->dx(ix,jy)/sqrt(coords->g11(ix,jy))); } } else if (inner_boundary_flags & INVERT_IN_CYLINDER){ @@ -581,8 +575,8 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, // Zero gradient at inner boundary for (int ix=0;ixg_11(ix,jy))/coord->dx(ix,jy); - cvec[ix] = dcomplex(1.,0.)/sqrt(coord->g_11(ix,jy))/coord->dx(ix,jy); + bvec[ix] = dcomplex(-1.,0.)/sqrt(coords->g_11(ix,jy))/coords->dx(ix,jy); + cvec[ix] = dcomplex(1.,0.)/sqrt(coords->g_11(ix,jy))/coords->dx(ix,jy); } } else if(inner_boundary_flags & INVERT_AC_GRAD) { @@ -598,7 +592,7 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, for (int ix=0;ixg33(ix,jy)/coord->g11(ix,jy))*kwave*coord->dx(ix,jy)); + cvec[ix] = -exp(-1.0*sqrt(coords->g33(ix,jy)/coords->g11(ix,jy))*kwave*coords->dx(ix,jy)); } } else if (inner_boundary_flags & INVERT_IN_CYLINDER) { @@ -644,8 +638,8 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, if(outer_boundary_flags & INVERT_DC_GRAD && ( outer_boundary_flags & INVERT_SET || outer_boundary_flags & INVERT_RHS)) { // Zero gradient at outer boundary for (int ix=0;ixg_11(ncx-ix,jy))/coord->dx(ncx-ix,jy); - bvec[ncx-ix]=dcomplex(1.,0.)/sqrt(coord->g_11(ncx-ix,jy))/coord->dx(ncx-ix,jy); + avec[ncx-ix]=dcomplex(-1.,0.)/sqrt(coords->g_11(ncx-ix,jy))/coords->dx(ncx-ix,jy); + bvec[ncx-ix]=dcomplex(1.,0.)/sqrt(coords->g_11(ncx-ix,jy))/coords->dx(ncx-ix,jy); cvec[ncx-ix]=dcomplex(0.,0.); } } @@ -659,15 +653,15 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, } else if(inner_boundary_flags & INVERT_DC_GRADPAR) { for (int ix=0;ixg_22(ncx-ix+1,jy)); - bvec[ncx-ix] = -1.0/sqrt(coord->g_22(ncx-ix,jy)); + avec[ncx-ix] = 1.0/sqrt(coords->g_22(ncx-ix+1,jy)); + bvec[ncx-ix] = -1.0/sqrt(coords->g_22(ncx-ix,jy)); cvec[ncx-ix] = 0.0; } } else if(inner_boundary_flags & INVERT_DC_GRADPARINV) { for (int ix=0;ixg_22(ncx-ix-1,jy)); - bvec[ncx-ix] = -sqrt(coord->g_22(ncx-ix,jy)); + avec[ncx-ix] = sqrt(coords->g_22(ncx-ix-1,jy)); + bvec[ncx-ix] = -sqrt(coords->g_22(ncx-ix,jy)); cvec[ncx-ix] = 0.0; } } @@ -683,7 +677,7 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, for (int ix=0;ixdx(ncx-ix,jy)/sqrt(coord->g11(ncx-ix,jy))); + avec[ncx-ix] = -exp(-k*coords->dx(ncx-ix,jy)/sqrt(coords->g11(ncx-ix,jy))); } } else { @@ -702,8 +696,8 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, if(outer_boundary_flags & INVERT_AC_GRAD && ( outer_boundary_flags & INVERT_SET || outer_boundary_flags & INVERT_RHS)) { // Zero gradient at outer boundary for (int ix=0;ixg_11(ncx-ix,jy))/coord->dx(ncx-ix,jy); - bvec[ncx-ix]=dcomplex(1.,0.)/sqrt(coord->g_11(ncx-ix,jy))/coord->dx(ncx-ix,jy); + avec[ncx-ix]=dcomplex(-1.,0.)/sqrt(coords->g_11(ncx-ix,jy))/coords->dx(ncx-ix,jy); + bvec[ncx-ix]=dcomplex(1.,0.)/sqrt(coords->g_11(ncx-ix,jy))/coords->dx(ncx-ix,jy); cvec[ncx-ix]=dcomplex(0.,0.); } } @@ -718,7 +712,7 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, else if(outer_boundary_flags & INVERT_AC_LAP) { // Use decaying zero-Laplacian solution in the boundary for (int ix=0;ixg33(xe-ix,jy)/coord->g11(xe-ix,jy))*kwave*coord->dx(xe-ix,jy)); + avec[ncx-ix] = -exp(-1.0*sqrt(coords->g33(xe-ix,jy)/coords->g11(xe-ix,jy))*kwave*coords->dx(xe-ix,jy)); bvec[ncx-ix] = 1.0; cvec[ncx-ix] = 0.0; } From 79f9e7471207af50b97c9e38286a3e61aa47c752 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 14 Nov 2018 18:40:04 +0000 Subject: [PATCH 0258/1783] Remove ignored arguments from AUTO_TRACE and add doxygen comment --- include/msg_stack.hxx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/include/msg_stack.hxx b/include/msg_stack.hxx index 7d8fa7e262..c9a1ff46fc 100644 --- a/include/msg_stack.hxx +++ b/include/msg_stack.hxx @@ -184,6 +184,23 @@ private: #define TRACE(...) #endif -#define AUTO_TRACE(...) TRACE("%s", __thefunc__) +/*! + * The AUTO_TRACE macro provides a convenient way to put messages onto the msg_stack + * It pushes a message onto the stack, and pops it when the scope ends + * The message is automatically derived from the function signature + * as identified by the compiler. This will be PRETTY_FUNCTION if available + * else it will be the mangled form. + * + * This is implemented as a use of the TRACE macro with specific arguments. + * + * Example + * ------- + * + * { + * AUTO_TRACE(); + * + * } // Scope ends, message popped + */ +#define AUTO_TRACE()("%s", __thefunc__) #endif // __MSG_STACK_H__ From 2b6e234d25360d7e09bdaad57742d5c17faa8cbf Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 14 Nov 2018 19:09:08 +0000 Subject: [PATCH 0259/1783] Print command line options to output_info --- src/bout++.cxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bout++.cxx b/src/bout++.cxx index ddc67db98f..977ce7d155 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -410,6 +410,13 @@ int BoutInitialise(int &argc, char **&argv) { //which could cause problems (e.g. terminate strings). output_info.write(_("\tCompiled with flags : %s\n"),STRINGIFY(BOUT_FLAGS_STRING)); + // Print command line options + output_info.write(_("\tCommand line options for this run : ")); + for (int i=0; i Date: Wed, 14 Nov 2018 19:44:04 +0000 Subject: [PATCH 0260/1783] Tweak upwinding3 MMS test to also display passed tests if any errors occur --- tests/MMS/upwinding3/runtest | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/MMS/upwinding3/runtest b/tests/MMS/upwinding3/runtest index c0fd2129a3..9a2e21d2bc 100755 --- a/tests/MMS/upwinding3/runtest +++ b/tests/MMS/upwinding3/runtest @@ -10,11 +10,12 @@ import itertools from sys import exit errorlist=[] - +passlist=[] boutcore.init("-d data -q -q -q".split(" ")) def runtests(functions,derivatives,directions,stag,msg): global errorlist + global passlist for direction in directions: direction, fac,guards, diff_func = direction locations=['CENTRE'] @@ -56,6 +57,9 @@ def runtests(functions,derivatives,directions,stag,msg): conv=errc/difc if order-.1 < conv < order+.1: pass + passMsg="%s: %s is working. Expected %f got %f"%(msg,info,order,conv) + passlist.append(passMsg) + else: info="%s - %s - %s - %s - %s -> %s "%(vfunc,ffunc,diff,direction,floc,vloc) error="%s: %s is not working. Expected %f got %f"%(msg,info,order,conv) @@ -106,6 +110,9 @@ runtests(functions,derivatives,directions,stag=True,msg="DD") if errorlist: for error in errorlist: print(error) + if passlist: + for passMsg in passlist: + print(passMsg) exit(1) else: print("Pass") From 0b98665b02f520e3b427380d1037839a892be9c7 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 14 Nov 2018 19:44:42 +0000 Subject: [PATCH 0261/1783] Indentation fix --- tests/MMS/upwinding3/runtest | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/MMS/upwinding3/runtest b/tests/MMS/upwinding3/runtest index 9a2e21d2bc..dcab1e5fd1 100755 --- a/tests/MMS/upwinding3/runtest +++ b/tests/MMS/upwinding3/runtest @@ -111,8 +111,8 @@ if errorlist: for error in errorlist: print(error) if passlist: - for passMsg in passlist: - print(passMsg) + for passMsg in passlist: + print(passMsg) exit(1) else: print("Pass") From 12dfecd417f34a48cdf66a8a3da8df32b9d129fd Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 14 Nov 2018 20:00:39 +0000 Subject: [PATCH 0262/1783] Fix previous two commits --- tests/MMS/upwinding3/runtest | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/MMS/upwinding3/runtest b/tests/MMS/upwinding3/runtest index dcab1e5fd1..41a9b04573 100755 --- a/tests/MMS/upwinding3/runtest +++ b/tests/MMS/upwinding3/runtest @@ -56,10 +56,9 @@ def runtests(functions,derivatives,directions,stag,msg): difc=np.log(nzs[-1]/nzs[-2]) conv=errc/difc if order-.1 < conv < order+.1: - pass + info="%s - %s - %s - %s - %s -> %s "%(vfunc,ffunc,diff,direction,floc,vloc) passMsg="%s: %s is working. Expected %f got %f"%(msg,info,order,conv) passlist.append(passMsg) - else: info="%s - %s - %s - %s - %s -> %s "%(vfunc,ffunc,diff,direction,floc,vloc) error="%s: %s is not working. Expected %f got %f"%(msg,info,order,conv) From e4d1195a16a8e71cfcbdff4080cfb01126b7e375 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 14 Nov 2018 20:32:21 +0000 Subject: [PATCH 0263/1783] Bug fix for selecting staggering in flow derivatives --- src/mesh/index_derivs.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index bab0d54a17..29f4d31e14 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -56,7 +56,7 @@ STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL #if CHECK > 0 STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { #else -STAGGER Mesh::getStagger(const CELL_LOC UNUSED(vloc), const CELL_LOC inloc, +STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC UNUSED(inloc), const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { #endif TRACE("Mesh::getStagger -- four arguments"); @@ -64,5 +64,5 @@ STAGGER Mesh::getStagger(const CELL_LOC UNUSED(vloc), const CELL_LOC inloc, (vloc == CELL_CENTRE && inloc == allowedStaggerLoc) || (vloc == allowedStaggerLoc && inloc == CELL_CENTRE) ); - return getStagger(inloc, outloc, allowedStaggerLoc); + return getStagger(vloc, outloc, allowedStaggerLoc); } From ca7000b1d66098d6321c5ec13fce2de975d1c33e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 15 Nov 2018 18:53:41 +0000 Subject: [PATCH 0264/1783] Remove regeneration test The test caused many issues: * Changed the timestamp of files, forcing thus regeneration. * Failed if clang-format was not available or a different version than used to format it initially. * Detection of run inside repository not reliable, thus could lead to data loss. --- tests/integrated/test-code-style/runtest | 34 ------------------------ 1 file changed, 34 deletions(-) diff --git a/tests/integrated/test-code-style/runtest b/tests/integrated/test-code-style/runtest index 31018dcd19..33845575fa 100755 --- a/tests/integrated/test-code-style/runtest +++ b/tests/integrated/test-code-style/runtest @@ -19,40 +19,6 @@ grep [\(,][[:space:]]*const[[:space:]][[:alnum:]]*[[:space:]][[:alnum:]]*[[:spac paths="src include examples tests" -GIT=git -if $GIT status > /dev/null 2>&1 -then - # Find autogenerated files - autogens="" - for path in $paths - do - autogens="$(for f in $(find $BOUT_TOP/$path |grep '\.in\.[a-z0-9A-Z]*$') - do - echo ${f%.in.*} - done | sort -u) $autogens" - done - for autogen in $autogens - do - if ! $GIT diff --exit-code $autogen > /dev/null 2>&1 - then - error=1 - echo "$autogen changed - but should be autogenerated" - fi - if ! test "$error" - then - make -C ${autogen%/*} --no-print-directory - fi - if ! $GIT diff --exit-code $autogen > /dev/null 2>&1 - then - error=1 - echo "$autogen changed upon recreation" - echo "Checking file out - to prevent further changes" - $GIT checkout $autogen - fi - done -else - echo "Skipping test - as git is not available!" -fi # Check that exceptions are caught by reference for path in $paths From 73b69ca82f882c39151bab8b4ecff6debe0e14eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 15 Nov 2018 19:13:54 +0000 Subject: [PATCH 0265/1783] Add documentation --- tools/pylib/_boutcore_build/boutcore.pyx.in | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 63559f9786..89c0d39c47 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -1421,6 +1421,20 @@ cdef class Options: cdef c.bool isSelfOwned def __init__(self,name=""): + """ + Get a section from the global options tree + + Parameters + ---------- + name : string + The name of the section. Can contain ':' to specify subsections. + Defaults to the root section ''. + + Returns + ------- + Options + The Options object + """ checkInit() self.cobj = c.Options.getRoot() cdef c.string sec_ From 13a96e6653dd91d098253bbe99ab0e87e22f7c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 15 Nov 2018 19:37:20 +0000 Subject: [PATCH 0266/1783] boutcore docs update --- manual/sphinx/user_docs/python_boutcore.rst | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/manual/sphinx/user_docs/python_boutcore.rst b/manual/sphinx/user_docs/python_boutcore.rst index 235cdcdbf6..950f6d5fd3 100644 --- a/manual/sphinx/user_docs/python_boutcore.rst +++ b/manual/sphinx/user_docs/python_boutcore.rst @@ -43,16 +43,12 @@ configured with something like: ``--enable-shared`` is required, so that pvode etc. is compiles as position independent code. -To only build the python2 module, run ``make python2``. - -To build both, run ``make python-all`` - If you are running fedora - you can install pre-build binaries: .. code-block:: bash sudo dnf copr enable davidsch/bout - sudo dnf install python3-bout++-nightly-mpich + sudo dnf install python3-bout++-mpich module load mpi/mpich-$(arch) @@ -64,18 +60,16 @@ It allows to calculate e.g. BOUT++ derivatives in python. State ----- -This is still in early development, and things might change. -However, it should still be useful. - -Field3D is working. The other fields are not exposed. -Field3D can be accessed directly using the [] operators, and give a list of slice objects. +Field3D and Field2D are working. If other fields are needed, please open an issue. +Fields can be accessed directly using the [] operators, and give a list of slice objects. The get all data, ``f3d.getAll()`` is equivalent to ``f3d[:,:,]`` and returns a numpy array. This array can be addressed with e.g. ``[]`` operators, and then the field can be set again with ``f3d.setAll(numpyarray)``. It is also possible to set a part of an Field3D with the ``[]`` operators. -Addition, multiplication etc. should all be available. -Most of the derivatives are available, if something is missing open a bug. +Addition, multiplication etc. are all available. +The derivatives should all be working, if find a missing one, please open an issue. +Vectors are not exposed yet. Functions --------- From 56a85e015300e0d0b6c193c534063f7dba6efa54 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 16 Nov 2018 08:21:19 +0000 Subject: [PATCH 0267/1783] Add missing TRACE call --- include/msg_stack.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/msg_stack.hxx b/include/msg_stack.hxx index c9a1ff46fc..2bfdf67da0 100644 --- a/include/msg_stack.hxx +++ b/include/msg_stack.hxx @@ -201,6 +201,6 @@ private: * * } // Scope ends, message popped */ -#define AUTO_TRACE()("%s", __thefunc__) +#define AUTO_TRACE() TRACE("%s", __thefunc__) #endif // __MSG_STACK_H__ From 64ad98998d0c0047587f5a80a1ca7c7b18dbcf73 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 16 Nov 2018 08:24:21 +0000 Subject: [PATCH 0268/1783] Correct trace statement --- src/field/vecops.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/field/vecops.cxx b/src/field/vecops.cxx index d5af58bf38..86f514fbf1 100644 --- a/src/field/vecops.cxx +++ b/src/field/vecops.cxx @@ -329,7 +329,7 @@ const Field3D V_dot_Grad(const Vector2D &v, const Field3D &f) { } const Field3D V_dot_Grad(const Vector3D &v, const Field2D &f) { - TRACE("V_dot_Grad( Vector3D , Field3D )"); + TRACE("V_dot_Grad( Vector3D , Field2D )"); SCOREP0(); Field3D result(f.getMesh()); From 365ab65bf9185229f1a461f06eb24b6223aed542 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 16 Nov 2018 08:26:00 +0000 Subject: [PATCH 0269/1783] Replace tabs with spaces --- src/field/vector2d.cxx | 32 ++++++++++++++++---------------- src/field/vector3d.cxx | 40 ++++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/field/vector2d.cxx b/src/field/vector2d.cxx index 38b7ea156c..473805aaa7 100644 --- a/src/field/vector2d.cxx +++ b/src/field/vector2d.cxx @@ -81,9 +81,9 @@ void Vector2D::toCovariant() { // multiply by g_{ij} BOUT_FOR(i, localmesh->getRegion2D("RGN_ALL")){ - x[i] = metric_x->g_11[i]*x[i] + metric_x->g_12[i]*y_at_x[i] + metric_x->g_13[i]*z_at_x[i]; - y[i] = metric_y->g_22[i]*y[i] + metric_y->g_12[i]*x_at_y[i] + metric_y->g_23[i]*z_at_y[i]; - z[i] = metric_z->g_33[i]*z[i] + metric_z->g_13[i]*x_at_z[i] + metric_z->g_23[i]*y_at_z[i]; + x[i] = metric_x->g_11[i]*x[i] + metric_x->g_12[i]*y_at_x[i] + metric_x->g_13[i]*z_at_x[i]; + y[i] = metric_y->g_22[i]*y[i] + metric_y->g_12[i]*x_at_y[i] + metric_y->g_23[i]*z_at_y[i]; + z[i] = metric_z->g_33[i]*z[i] + metric_z->g_13[i]*x_at_z[i] + metric_z->g_23[i]*y_at_z[i]; }; } else { const auto metric = localmesh->getCoordinates(location); @@ -93,9 +93,9 @@ void Vector2D::toCovariant() { gx.allocate(); gy.allocate(); gz.allocate(); BOUT_FOR(i, localmesh->getRegion2D("RGN_ALL")){ - gx[i] = metric->g_11[i]*x[i] + metric->g_12[i]*y[i] + metric->g_13[i]*z[i]; - gy[i] = metric->g_22[i]*y[i] + metric->g_12[i]*x[i] + metric->g_23[i]*z[i]; - gz[i] = metric->g_33[i]*z[i] + metric->g_13[i]*x[i] + metric->g_23[i]*y[i]; + gx[i] = metric->g_11[i]*x[i] + metric->g_12[i]*y[i] + metric->g_13[i]*z[i]; + gy[i] = metric->g_22[i]*y[i] + metric->g_12[i]*x[i] + metric->g_23[i]*z[i]; + gz[i] = metric->g_33[i]*z[i] + metric->g_13[i]*x[i] + metric->g_23[i]*y[i]; }; x = gx; @@ -134,9 +134,9 @@ void Vector2D::toContravariant() { // multiply by g_{ij} BOUT_FOR(i, localmesh->getRegion2D("RGN_ALL")){ - x[i] = metric_x->g11[i]*x[i] + metric_x->g12[i]*y_at_x[i] + metric_x->g13[i]*z_at_x[i]; - y[i] = metric_y->g22[i]*y[i] + metric_y->g12[i]*x_at_y[i] + metric_y->g23[i]*z_at_y[i]; - z[i] = metric_z->g33[i]*z[i] + metric_z->g13[i]*x_at_z[i] + metric_z->g23[i]*y_at_z[i]; + x[i] = metric_x->g11[i]*x[i] + metric_x->g12[i]*y_at_x[i] + metric_x->g13[i]*z_at_x[i]; + y[i] = metric_y->g22[i]*y[i] + metric_y->g12[i]*x_at_y[i] + metric_y->g23[i]*z_at_y[i]; + z[i] = metric_z->g33[i]*z[i] + metric_z->g13[i]*x_at_z[i] + metric_z->g23[i]*y_at_z[i]; }; } else { @@ -147,9 +147,9 @@ void Vector2D::toContravariant() { gx.allocate(); gy.allocate(); gz.allocate(); BOUT_FOR(i, localmesh->getRegion2D("RGN_ALL")){ - gx[i] = metric->g11[i]*x[i] + metric->g12[i]*y[i] + metric->g13[i]*z[i]; - gy[i] = metric->g22[i]*y[i] + metric->g12[i]*x[i] + metric->g23[i]*z[i]; - gz[i] = metric->g33[i]*z[i] + metric->g13[i]*x[i] + metric->g23[i]*y[i]; + gx[i] = metric->g11[i]*x[i] + metric->g12[i]*y[i] + metric->g13[i]*z[i]; + gy[i] = metric->g22[i]*y[i] + metric->g12[i]*x[i] + metric->g23[i]*z[i]; + gz[i] = metric->g33[i]*z[i] + metric->g13[i]*x[i] + metric->g23[i]*y[i]; }; x = gx; @@ -386,14 +386,14 @@ const Field2D Vector2D::operator*(const Vector2D &rhs) const { // Both covariant result = x*rhs.x*metric->g11 + y*rhs.y*metric->g22 + z*rhs.z*metric->g33; result += (x*rhs.y + y*rhs.x)*metric->g12 - + (x*rhs.z + z*rhs.x)*metric->g13 - + (y*rhs.z + z*rhs.y)*metric->g23; + + (x*rhs.z + z*rhs.x)*metric->g13 + + (y*rhs.z + z*rhs.y)*metric->g23; }else { // Both contravariant result = x*rhs.x*metric->g_11 + y*rhs.y*metric->g_22 + z*rhs.z*metric->g_33; result += (x*rhs.y + y*rhs.x)*metric->g_12 - + (x*rhs.z + z*rhs.x)*metric->g_13 - + (y*rhs.z + z*rhs.y)*metric->g_23; + + (x*rhs.z + z*rhs.x)*metric->g_13 + + (y*rhs.z + z*rhs.y)*metric->g_23; } } diff --git a/src/field/vector3d.cxx b/src/field/vector3d.cxx index e425586d71..1959ce3bbe 100644 --- a/src/field/vector3d.cxx +++ b/src/field/vector3d.cxx @@ -82,9 +82,9 @@ void Vector3D::toCovariant() { // multiply by g_{ij} BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")){ - x[i] = metric_x->g_11[i]*x[i] + metric_x->g_12[i]*y_at_x[i] + metric_x->g_13[i]*z_at_x[i]; - y[i] = metric_y->g_22[i]*y[i] + metric_y->g_12[i]*x_at_y[i] + metric_y->g_23[i]*z_at_y[i]; - z[i] = metric_z->g_33[i]*z[i] + metric_z->g_13[i]*x_at_z[i] + metric_z->g_23[i]*y_at_z[i]; + x[i] = metric_x->g_11[i]*x[i] + metric_x->g_12[i]*y_at_x[i] + metric_x->g_13[i]*z_at_x[i]; + y[i] = metric_y->g_22[i]*y[i] + metric_y->g_12[i]*x_at_y[i] + metric_y->g_23[i]*z_at_y[i]; + z[i] = metric_z->g_33[i]*z[i] + metric_z->g_13[i]*x_at_z[i] + metric_z->g_23[i]*y_at_z[i]; }; } else { const auto metric = localmesh->getCoordinates(location); @@ -94,9 +94,9 @@ void Vector3D::toCovariant() { gx.allocate(); gy.allocate(); gz.allocate(); BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")){ - gx[i] = metric->g_11[i]*x[i] + metric->g_12[i]*y[i] + metric->g_13[i]*z[i]; - gy[i] = metric->g_22[i]*y[i] + metric->g_12[i]*x[i] + metric->g_23[i]*z[i]; - gz[i] = metric->g_33[i]*z[i] + metric->g_13[i]*x[i] + metric->g_23[i]*y[i]; + gx[i] = metric->g_11[i]*x[i] + metric->g_12[i]*y[i] + metric->g_13[i]*z[i]; + gy[i] = metric->g_22[i]*y[i] + metric->g_12[i]*x[i] + metric->g_23[i]*z[i]; + gz[i] = metric->g_33[i]*z[i] + metric->g_13[i]*x[i] + metric->g_23[i]*y[i]; }; x = gx; @@ -135,9 +135,9 @@ void Vector3D::toContravariant() { // multiply by g_{ij} BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")){ - x[i] = metric_x->g11[i]*x[i] + metric_x->g12[i]*y_at_x[i] + metric_x->g13[i]*z_at_x[i]; - y[i] = metric_y->g22[i]*y[i] + metric_y->g12[i]*x_at_y[i] + metric_y->g23[i]*z_at_y[i]; - z[i] = metric_z->g33[i]*z[i] + metric_z->g13[i]*x_at_z[i] + metric_z->g23[i]*y_at_z[i]; + x[i] = metric_x->g11[i]*x[i] + metric_x->g12[i]*y_at_x[i] + metric_x->g13[i]*z_at_x[i]; + y[i] = metric_y->g22[i]*y[i] + metric_y->g12[i]*x_at_y[i] + metric_y->g23[i]*z_at_y[i]; + z[i] = metric_z->g33[i]*z[i] + metric_z->g13[i]*x_at_z[i] + metric_z->g23[i]*y_at_z[i]; }; } else { @@ -148,9 +148,9 @@ void Vector3D::toContravariant() { gx.allocate(); gy.allocate(); gz.allocate(); BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")){ - gx[i] = metric->g11[i]*x[i] + metric->g12[i]*y[i] + metric->g13[i]*z[i]; - gy[i] = metric->g22[i]*y[i] + metric->g12[i]*x[i] + metric->g23[i]*z[i]; - gz[i] = metric->g33[i]*z[i] + metric->g13[i]*x[i] + metric->g23[i]*y[i]; + gx[i] = metric->g11[i]*x[i] + metric->g12[i]*y[i] + metric->g13[i]*z[i]; + gy[i] = metric->g22[i]*y[i] + metric->g12[i]*x[i] + metric->g23[i]*z[i]; + gz[i] = metric->g33[i]*z[i] + metric->g13[i]*x[i] + metric->g23[i]*y[i]; }; x = gx; @@ -487,14 +487,14 @@ const Field3D Vector3D::operator*(const Vector3D &rhs) const { // Both covariant result = x*rhs.x*metric->g11 + y*rhs.y*metric->g22 + z*rhs.z*metric->g33; result += (x*rhs.y + y*rhs.x)*metric->g12 - + (x*rhs.z + z*rhs.x)*metric->g13 - + (y*rhs.z + z*rhs.y)*metric->g23; + + (x*rhs.z + z*rhs.x)*metric->g13 + + (y*rhs.z + z*rhs.y)*metric->g23; }else { // Both contravariant result = x*rhs.x*metric->g_11 + y*rhs.y*metric->g_22 + z*rhs.z*metric->g_33; result += (x*rhs.y + y*rhs.x)*metric->g_12 - + (x*rhs.z + z*rhs.x)*metric->g_13 - + (y*rhs.z + z*rhs.y)*metric->g_23; + + (x*rhs.z + z*rhs.x)*metric->g_13 + + (y*rhs.z + z*rhs.y)*metric->g_23; } } @@ -518,14 +518,14 @@ const Field3D Vector3D::operator*(const Vector2D &rhs) const // Both covariant result = x*rhs.x*metric->g11 + y*rhs.y*metric->g22 + z*rhs.z*metric->g33; result += (x*rhs.y + y*rhs.x)*metric->g12 - + (x*rhs.z + z*rhs.x)*metric->g13 - + (y*rhs.z + z*rhs.y)*metric->g23; + + (x*rhs.z + z*rhs.x)*metric->g13 + + (y*rhs.z + z*rhs.y)*metric->g23; }else { // Both contravariant result = x*rhs.x*metric->g_11 + y*rhs.y*metric->g_22 + z*rhs.z*metric->g_33; result += (x*rhs.y + y*rhs.x)*metric->g_12 - + (x*rhs.z + z*rhs.x)*metric->g_13 - + (y*rhs.z + z*rhs.y)*metric->g_23; + + (x*rhs.z + z*rhs.x)*metric->g_13 + + (y*rhs.z + z*rhs.y)*metric->g_23; } } From ad939cc44bbedd707aa317012fb4143c7269f494 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 16 Nov 2018 11:18:59 +0000 Subject: [PATCH 0270/1783] Clang format new files and some of the changed regions --- include/bout/coordinates.hxx | 104 +++--- include/bout/deriv_store.hxx | 160 +++++---- include/bout/index_derivs.hxx | 429 +++++++++++++------------ include/bout/mesh.hxx | 286 ++++++++++------- include/bout/template_combinations.hxx | 20 +- include/derivs.hxx | 322 +++++++++---------- include/difops.hxx | 142 ++++---- include/vecops.hxx | 12 +- src/mesh/index_derivs.cxx | 23 +- 9 files changed, 779 insertions(+), 719 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index f8a1d8c2c8..7922be9d0b 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -100,76 +100,82 @@ public: // Operators - const Field2D DDX(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", - REGION region = RGN_NOBNDRY); - const Field2D DDX(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, - REGION region = RGN_NOBNDRY){ + const Field2D DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); + const Field2D DDX(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return DDX(f, outloc, DIFF_METHOD_STRING(method), region); }; - - const Field2D DDY(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", - REGION region = RGN_NOBNDRY); - const Field2D DDY(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, - REGION region = RGN_NOBNDRY){ + + const Field2D DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); + const Field2D DDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return DDY(f, outloc, DIFF_METHOD_STRING(method), region); }; - - const Field2D DDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", - REGION region = RGN_NOBNDRY); - const Field2D DDZ(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, - REGION region = RGN_NOBNDRY){ + + const Field2D DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); + const Field2D DDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); }; - + /// Gradient along magnetic field b.Grad(f) - const Field2D Grad_par(const Field2D &var, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); - const Field2D Grad_par(const Field2D &var, CELL_LOC outloc, DIFF_METHOD method){ + const Field2D Grad_par(const Field2D& var, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + const Field2D Grad_par(const Field2D& var, CELL_LOC outloc, DIFF_METHOD method) { return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); }; - - const Field3D Grad_par(const Field3D &var, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); - const Field3D Grad_par(const Field3D &var, CELL_LOC outloc, DIFF_METHOD method){ + + const Field3D Grad_par(const Field3D& var, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + const Field3D Grad_par(const Field3D& var, CELL_LOC outloc, DIFF_METHOD method) { return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); }; - + /// Advection along magnetic field V*b.Grad(f) - const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); - const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, CELL_LOC outloc, DIFF_METHOD method){ + const Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, + CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + const Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, CELL_LOC outloc, + DIFF_METHOD method) { return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); }; - - const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); - const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method){ + + const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, + CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, CELL_LOC outloc, + DIFF_METHOD method) { return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); - }; - + }; + /// Divergence along magnetic field Div(b*f) = B.Grad(f/B) - const Field2D Div_par(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); - const Field2D Div_par(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method){ + const Field2D Div_par(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + const Field2D Div_par(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { return Div_par(f, outloc, DIFF_METHOD_STRING(method)); - }; - - const Field3D Div_par(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); - const Field3D Div_par(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method){ + }; + + const Field3D Div_par(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + const Field3D Div_par(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { return Div_par(f, outloc, DIFF_METHOD_STRING(method)); - }; - + }; + // Second derivative along magnetic field - const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); - const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method){ + const Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + const Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { return Grad2_par2(f, outloc, DIFF_METHOD_STRING(method)); - }; - - const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); - const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method){ + }; + + const Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + const Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { return Grad2_par2(f, outloc, DIFF_METHOD_STRING(method)); - }; + }; // Perpendicular Laplacian operator, using only X-Z derivatives // NOTE: This might be better bundled with the Laplacian inversion code diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 1f114c2819..68f715b5ec 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -47,18 +47,19 @@ /// a DIRECTION (e.g. DIRECTION::X) and a STAGGER (e.g. STAGGER::None). There is /// one routine for each class of derivative (standard, standard2nd, standard4th, /// upwind and flux). -template struct DerivativeStore { - using standardFunc = std::function; - using upwindFunc = std::function; - using fluxFunc = std::function; - +template +struct DerivativeStore { + using standardFunc = std::function; + using upwindFunc = + std::function; + using fluxFunc = + std::function; + #ifdef USE_ORDERED_MAP_FOR_DERIVATIVE_STORE - template + template using storageType = std::map; #else - template + template using storageType = std::unordered_map; #endif @@ -71,7 +72,7 @@ template struct DerivativeStore { /// Returns a vector of all registered method names for the /// specified derivative type, direction and stagger. std::vector getAvailableMethods(DERIV derivType, DIRECTION direction, - STAGGER stagger = STAGGER::None) const { + STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); // Get the key auto key = getKey(direction, stagger, DERIV_STRING(derivType)); @@ -92,23 +93,21 @@ template struct DerivativeStore { output_info << " ( Staggering : "; output_info << STAGGER_STRING(stagger) << " ) : \n"; - for (const auto &i : - getAvailableMethods(derivType, direction, stagger)) { + for (const auto& i : getAvailableMethods(derivType, direction, stagger)) { output_info << "\t" << i << "\n"; }; }; /// Register a function with standardFunc interface. Which map is used /// depends on the derivType input. - void registerDerivative(standardFunc func, DERIV derivType, - DIRECTION direction, STAGGER stagger, - std::string methodName) { + void registerDerivative(standardFunc func, DERIV derivType, DIRECTION direction, + STAGGER stagger, std::string methodName) { TRACE("%s", __thefunc__); const auto key = getKey(direction, stagger, methodName); // Register this method name in lookup of known methods - registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))] - .push_back(methodName); + registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))].push_back( + methodName); switch (derivType) { case (DERIV::Standard): @@ -121,10 +120,9 @@ template struct DerivativeStore { standardFourth[key] = func; return; default: - throw BoutException( - "Invalid function signature in registerDerivative : Function " - "signature 'standard' but derivative type %s passed", - DERIV_STRING(derivType).c_str()); + throw BoutException("Invalid function signature in registerDerivative : Function " + "signature 'standard' but derivative type %s passed", + DERIV_STRING(derivType).c_str()); }; return; }; @@ -137,8 +135,8 @@ template struct DerivativeStore { const auto key = getKey(direction, stagger, methodName); // Register this method name in lookup of known methods - registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))] - .push_back(methodName); + registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))].push_back( + methodName); switch (derivType) { case (DERIV::Upwind): @@ -148,10 +146,9 @@ template struct DerivativeStore { flux[key] = func; return; default: - throw BoutException( - "Invalid function signature in registerDerivative : Function " - "signature 'upwind/flux' but derivative type %s passed", - DERIV_STRING(derivType).c_str()); + throw BoutException("Invalid function signature in registerDerivative : Function " + "signature 'upwind/flux' but derivative type %s passed", + DERIV_STRING(derivType).c_str()); }; return; }; @@ -180,10 +177,9 @@ template struct DerivativeStore { standardFunc getStandardDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); - const auto realName = - nameLookup(name, - defaultMethods.at(getKey(direction, stagger, - DERIV_STRING(DERIV::Standard)))); + const auto realName = nameLookup( + name, + defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Standard)))); const auto key = getKey(direction, stagger, realName); const auto resultOfFind = standard.find(key); if (resultOfFind != standard.end()) @@ -196,10 +192,10 @@ template struct DerivativeStore { standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); - const auto realName = nameLookup( - name, - defaultMethods.at( - getKey(direction, stagger, DERIV_STRING(DERIV::StandardSecond)))); + const auto realName = + nameLookup(name, + defaultMethods.at( + getKey(direction, stagger, DERIV_STRING(DERIV::StandardSecond)))); const auto key = getKey(direction, stagger, realName); const auto resultOfFind = standardSecond.find(key); if (resultOfFind != standardSecond.end()) @@ -212,10 +208,10 @@ template struct DerivativeStore { standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); - const auto realName = nameLookup( - name, - defaultMethods.at( - getKey(direction, stagger, DERIV_STRING(DERIV::StandardFourth)))); + const auto realName = + nameLookup(name, + defaultMethods.at( + getKey(direction, stagger, DERIV_STRING(DERIV::StandardFourth)))); const auto key = getKey(direction, stagger, realName); const auto resultOfFind = standardFourth.find(key); if (resultOfFind != standardFourth.end()) @@ -224,67 +220,58 @@ template struct DerivativeStore { "standardFourth derivative.", getMethodName(realName, direction, stagger).c_str()); }; - + upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); - const auto realName = - nameLookup(name, - defaultMethods.at(getKey(direction, stagger, - DERIV_STRING(DERIV::Upwind)))); + const auto realName = nameLookup( + name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Upwind)))); const auto key = getKey(direction, stagger, realName); const auto resultOfFind = upwind.find(key); if (resultOfFind != upwind.end()) return resultOfFind->second; - throw BoutException( - "Couldn't find requested method %s in map for upwind derivative.", - getMethodName(realName, direction, stagger).c_str()); + throw BoutException("Couldn't find requested method %s in map for upwind derivative.", + getMethodName(realName, direction, stagger).c_str()); }; fluxFunc getFluxDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); - const auto realName = - nameLookup(name, - defaultMethods.at( - getKey(direction, stagger, DERIV_STRING(DERIV::Flux)))); + const auto realName = nameLookup( + name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Flux)))); const auto key = getKey(direction, stagger, realName); const auto resultOfFind = flux.find(key); if (resultOfFind != flux.end()) return resultOfFind->second; - throw BoutException( - "Couldn't find requested method %s in map for flux derivative.", - getMethodName(realName, direction, stagger).c_str()); + throw BoutException("Couldn't find requested method %s in map for flux derivative.", + getMethodName(realName, direction, stagger).c_str()); }; - void initialise(Options *options) { + void initialise(Options* options) { TRACE("%s", __thefunc__); // To replicate the existing behaviour we first search for a section called //"dd?" and if the option isn't in there we search a section called "diff" auto backupSection = options->getSection("diff"); - std::map initialDefaultMethods = { - {DERIV::Standard, "C2"}, - {DERIV::StandardSecond, "C2"}, - {DERIV::StandardFourth, "C2"}, - {DERIV::Upwind, "U1"}, - {DERIV::Flux, "U1"}}; - - std::map directions = { - {DIRECTION::X, "ddx"}, - {DIRECTION::Y, "ddy"}, - {DIRECTION::YOrthogonal, "ddy"}, - {DIRECTION::Z, "ddz"}}; - - std::map derivTypes = { - {DERIV::Standard, "First"}, - {DERIV::StandardSecond, "Second"}, - {DERIV::StandardFourth, "Fourth"}, - {DERIV::Upwind, "Upwind"}, - {DERIV::Flux, "Flux"}}; - - for (const auto &direction : directions) { - for (const auto &deriv : derivTypes) { + std::map initialDefaultMethods = {{DERIV::Standard, "C2"}, + {DERIV::StandardSecond, "C2"}, + {DERIV::StandardFourth, "C2"}, + {DERIV::Upwind, "U1"}, + {DERIV::Flux, "U1"}}; + + std::map directions = {{DIRECTION::X, "ddx"}, + {DIRECTION::Y, "ddy"}, + {DIRECTION::YOrthogonal, "ddy"}, + {DIRECTION::Z, "ddz"}}; + + std::map derivTypes = {{DERIV::Standard, "First"}, + {DERIV::StandardSecond, "Second"}, + {DERIV::StandardFourth, "Fourth"}, + {DERIV::Upwind, "Upwind"}, + {DERIV::Flux, "Flux"}}; + + for (const auto& direction : directions) { + for (const auto& deriv : derivTypes) { std::string theDefault; // This corresponds to the key in the input file @@ -314,10 +301,9 @@ template struct DerivativeStore { // Now we have the default method we should store it in defaultMethods theDefault = uppercase(theDefault); - defaultMethods[getKey(theDirection, STAGGER::None, - theDerivTypeString)] = theDefault; - output_info << "The default method for derivative type " - << theDerivTypeString; + defaultMethods[getKey(theDirection, STAGGER::None, theDerivTypeString)] = + theDefault; + output_info << "The default method for derivative type " << theDerivTypeString; output_info << " in direction " << DIRECTION_STRING(theDirection); output_info << " is " << theDefault << "\n"; @@ -362,7 +348,7 @@ private: // of the struct DerivativeStore(){}; // No copy constructor allowed - DerivativeStore(const DerivativeStore &junk) = delete; + DerivativeStore(const DerivativeStore& junk) = delete; storageType standard; storageType standardSecond; @@ -375,12 +361,11 @@ private: std::string getMethodName(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { TRACE("%s", __thefunc__); - return name + " (" + DIRECTION_STRING(direction) + ", " + - STAGGER_STRING(stagger) + ")"; + return name + " (" + DIRECTION_STRING(direction) + ", " + STAGGER_STRING(stagger) + + ")"; }; - std::string nameLookup(const std::string name, - const std::string defaultName) const { + std::string nameLookup(const std::string name, const std::string defaultName) const { return name != DIFF_METHOD_STRING(DIFF_DEFAULT) ? name : defaultName; } @@ -394,8 +379,7 @@ private: /// store /// all methods with the same function interface in the same map, which might /// be nice. - std::size_t getKey(DIRECTION direction, STAGGER stagger, - std::string key) const { + std::size_t getKey(DIRECTION direction, STAGGER stagger, std::string key) const { TRACE("%s", __thefunc__); // Note this key is indepedent of the field type (and hence the key is the // same for diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index a8aa1dce69..bb381cb804 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -55,14 +55,14 @@ struct metaData { // metaData struct to be non-trivially destrucible which // can prevent using temporary instances of this. Instead // we'll use char* for now. - //const std::string key; + // const std::string key; const char* key; const int nGuards; const DERIV derivType; // Can be used to identify the type of the derivative }; /// Provide an easy way to report a Region's statistics -inline std::ostream &operator<<(std::ostream &out, const metaData &meta) { +inline std::ostream& operator<<(std::ostream& out, const metaData& meta) { out << "key : " << meta.key; out << ", "; out << "nGuards : " << meta.nGuards; @@ -77,14 +77,14 @@ inline std::ostream &operator<<(std::ostream &out, const metaData &meta) { /// to avoid needing different classes to represent the different operations /// The use of a functor here makes it possible to wrap up metaData into the /// type as well. -template class DerivativeType { +template +class DerivativeType { public: template - void standard(const T &var, T &result, REGION region) const { - TRACE("%s",__thefunc__); - ASSERT2(meta.derivType == DERIV::Standard || - meta.derivType == DERIV::StandardSecond || - meta.derivType == DERIV::StandardFourth) + void standard(const T& var, T& result, REGION region) const { + TRACE("%s", __thefunc__); + ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond + || meta.derivType == DERIV::StandardFourth) ASSERT2(var.getMesh()->template getNguard() >= nGuards); BOUT_FOR(i, var.getRegion(region)) { @@ -94,68 +94,73 @@ public: } template - void upwindOrFlux(const T &vel, const T &var, T &result, REGION region) const { - TRACE("%s",__thefunc__); + void upwindOrFlux(const T& vel, const T& var, T& result, REGION region) const { + TRACE("%s", __thefunc__); ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) ASSERT2(var.getMesh()->template getNguard() >= nGuards); if (meta.derivType == DERIV::Flux || stagger != STAGGER::None) { BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(populateStencil(vel, i), - populateStencil(var, i)); + result[i] = apply(populateStencil(vel, i), + populateStencil(var, i)); } } else { BOUT_FOR(i, var.getRegion(region)) { - result[i] = apply(vel[i], populateStencil(var, i)); + result[i] = + apply(vel[i], populateStencil(var, i)); } } return; } - BoutReal apply(const stencil &f) const { return func(f); } - BoutReal apply(BoutReal v, const stencil &f) const { return func(v, f); } - BoutReal apply(const stencil &v, const stencil &f) const { return func(v, f); } + BoutReal apply(const stencil& f) const { return func(f); } + BoutReal apply(BoutReal v, const stencil& f) const { return func(v, f); } + BoutReal apply(const stencil& v, const stencil& f) const { return func(v, f); } const FF func{}; const metaData meta = func.meta; }; -#define DEFINE_STANDARD_DERIV(name, key, nGuards, type) \ - struct name { \ - BoutReal operator()(const stencil &f) const; \ - const metaData meta = {key, nGuards, type}; \ - BoutReal operator()(BoutReal UNUSED(vc),\ - const stencil &UNUSED(f)) const {return BoutNaN;}; \ - BoutReal operator()(const stencil &UNUSED(v),\ - const stencil &UNUSED(f)) const {return BoutNaN;}; \ - }; \ - BoutReal name::operator()(const stencil &f) const - -#define DEFINE_UPWIND_DERIV(name, key, nGuards, type) \ - struct name { \ - BoutReal operator()(const stencil &UNUSED(f)) const {return BoutNaN;}; \ - BoutReal operator()(BoutReal vc, const stencil &f) const; \ - BoutReal operator()(const stencil &UNUSED(v),\ - const stencil &UNUSED(f)) const {return BoutNaN;}; \ - const metaData meta = {key, nGuards, type}; \ - }; \ - BoutReal name::operator()(BoutReal vc, const stencil &f) const - -#define DEFINE_FLUX_DERIV(name, key, nGuards, type) \ - struct name { \ - BoutReal operator()(const stencil &UNUSED(f)) const {return BoutNaN;}; \ - BoutReal operator()(BoutReal UNUSED(vc),\ - const stencil &UNUSED(f)) const {return BoutNaN;}; \ - BoutReal operator()(const stencil &v, const stencil &f) const; \ - const metaData meta = {key, nGuards, type}; \ - }; \ - BoutReal name::operator()(const stencil &v, const stencil &f) const - -#define DEFINE_STANDARD_DERIV_STAGGERED(name, key, nGuards, type) \ +#define DEFINE_STANDARD_DERIV(name, key, nGuards, type) \ + struct name { \ + BoutReal operator()(const stencil& f) const; \ + const metaData meta = {key, nGuards, type}; \ + BoutReal operator()(BoutReal UNUSED(vc), const stencil& UNUSED(f)) const { \ + return BoutNaN; \ + }; \ + BoutReal operator()(const stencil& UNUSED(v), const stencil& UNUSED(f)) const { \ + return BoutNaN; \ + }; \ + }; \ + BoutReal name::operator()(const stencil& f) const + +#define DEFINE_UPWIND_DERIV(name, key, nGuards, type) \ + struct name { \ + BoutReal operator()(const stencil& UNUSED(f)) const { return BoutNaN; }; \ + BoutReal operator()(BoutReal vc, const stencil& f) const; \ + BoutReal operator()(const stencil& UNUSED(v), const stencil& UNUSED(f)) const { \ + return BoutNaN; \ + }; \ + const metaData meta = {key, nGuards, type}; \ + }; \ + BoutReal name::operator()(BoutReal vc, const stencil& f) const + +#define DEFINE_FLUX_DERIV(name, key, nGuards, type) \ + struct name { \ + BoutReal operator()(const stencil& UNUSED(f)) const { return BoutNaN; }; \ + BoutReal operator()(BoutReal UNUSED(vc), const stencil& UNUSED(f)) const { \ + return BoutNaN; \ + }; \ + BoutReal operator()(const stencil& v, const stencil& f) const; \ + const metaData meta = {key, nGuards, type}; \ + }; \ + BoutReal name::operator()(const stencil& v, const stencil& f) const + +#define DEFINE_STANDARD_DERIV_STAGGERED(name, key, nGuards, type) \ DEFINE_STANDARD_DERIV(name, key, nGuards, type) -#define DEFINE_UPWIND_DERIV_STAGGERED(name, key, nGuards, type) \ +#define DEFINE_UPWIND_DERIV_STAGGERED(name, key, nGuards, type) \ DEFINE_FLUX_DERIV(name, key, nGuards, type) -#define DEFINE_FLUX_DERIV_STAGGERED(name, key, nGuards, type) \ +#define DEFINE_FLUX_DERIV_STAGGERED(name, key, nGuards, type) \ DEFINE_FLUX_DERIV(name, key, nGuards, type) ////////////////////// FIRST DERIVATIVES ///////////////////// @@ -260,8 +265,8 @@ DEFINE_UPWIND_DERIV(VDDX_U2, "U2", 2, DERIV::Upwind) { // No vec : vc * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c); // Alternative form would but may involve more operations const auto vSplit = vUpDown(vc); - return (std::get<0>(vSplit) * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) + - std::get<1>(vSplit) * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c)); + return (std::get<0>(vSplit) * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) + + std::get<1>(vSplit) * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c)); } /// upwind, 3rd order @@ -271,9 +276,9 @@ DEFINE_UPWIND_DERIV(VDDX_U3, "U3", 2, DERIV::Upwind) { // No vec : vc * (-4. * f.m + 12. * f.p - 2. * f.pp - 6. * f.c) / 12.; // Alternative form would but may involve more operations const auto vSplit = vUpDown(vc); - return (std::get<0>(vSplit) * (4. * f.p - 12. * f.m + 2. * f.mm + 6. * f.c) + - std::get<1>(vSplit) * (-4. * f.m + 12. * f.p - 2. * f.pp - 6. * f.c)) / - 12.; + return (std::get<0>(vSplit) * (4. * f.p - 12. * f.m + 2. * f.mm + 6. * f.c) + + std::get<1>(vSplit) * (-4. * f.m + 12. * f.p - 2. * f.pp - 6. * f.c)) + / 12.; } /// 3rd-order WENO scheme @@ -284,16 +289,16 @@ DEFINE_UPWIND_DERIV(VDDX_WENO3, "W3", 2, DERIV::Upwind) { // No vec if (vc > 0.0) { // Left-biased stencil - r = (WENO_SMALL + SQ(f.c - 2.0 * f.m + f.mm)) / - (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); + r = (WENO_SMALL + SQ(f.c - 2.0 * f.m + f.mm)) + / (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); deriv = (-f.mm + 3. * f.m - 3. * f.c + f.p); } else { // Right-biased - r = (WENO_SMALL + SQ(f.pp - 2.0 * f.p + f.c)) / - (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); + r = (WENO_SMALL + SQ(f.pp - 2.0 * f.p + f.c)) + / (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); deriv = (-f.m + 3. * f.c - 3. * f.p + f.pp); } @@ -337,7 +342,7 @@ DEFINE_STANDARD_DERIV(DDX_CWENO3, "W3", 2, DERIV::Standard) { sm.pp = ma - f.pp; const VDDX_WENO3 upwindOp{}; - return upwindOp(0.5, sp) + upwindOp(-0.5, sm); + return upwindOp(0.5, sp) + upwindOp(-0.5, sm); } //////////////////////////////////////////////////////////////////////////////// @@ -450,8 +455,8 @@ DEFINE_UPWIND_DERIV_STAGGERED(VDDX_C2_stag, "C2", 1, DERIV::Upwind) { DEFINE_UPWIND_DERIV_STAGGERED(VDDX_C4_stag, "C4", 2, DERIV::Upwind) { // Result is needed at location of f: interpolate v to f's location and take an // unstaggered derivative of f - return (9. * (v.m + v.p) - v.mm - v.pp) / 16. * (8. * f.p - 8. * f.m + f.mm - f.pp) / - 12.; + return (9. * (v.m + v.p) - v.mm - v.pp) / 16. * (8. * f.p - 8. * f.m + f.mm - f.pp) + / 12.; } //////////////////////////////////////////////////////////////////////////////// @@ -473,7 +478,8 @@ DEFINE_FLUX_DERIV_STAGGERED(FDDX_U1_stag, "U1", 1, DERIV::Flux) { ///////////////////////////////////////////////////////////////////////////////// struct registerMethod { - template + template void operator()(Direction, Stagger, FieldTypeContainer, Method) { TRACE("%s", __thefunc__); using namespace std::placeholders; @@ -488,50 +494,56 @@ struct registerMethod { // support for these versions the branching in the case statement below can be // removed and we can use nGuard directly in the template statement. const int nGuards = Method{}.meta.nGuards; - + auto& derivativeRegister = DerivativeStore::getInstance(); switch (Method{}.meta.derivType) { case (DERIV::Standard): case (DERIV::StandardSecond): case (DERIV::StandardFourth): { - if(nGuards == 1) { - const auto theFunc = std::bind( - // Method to store in function - &Method::template standard, - // Arguments -- first is hidden this of type-bound, others are placeholders - // for input field, output field, region - Method{}, _1, _2, _3); - derivativeRegister.template registerDerivative(theFunc); + if (nGuards == 1) { + const auto theFunc = std::bind( + // Method to store in function + &Method::template standard, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + Method{}, _1, _2, _3); + derivativeRegister.template registerDerivative( + theFunc); } else { - const auto theFunc = std::bind( - // Method to store in function - &Method::template standard, - // Arguments -- first is hidden this of type-bound, others are placeholders - // for input field, output field, region - Method{}, _1, _2, _3); - derivativeRegister.template registerDerivative(theFunc); - } + const auto theFunc = std::bind( + // Method to store in function + &Method::template standard, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + Method{}, _1, _2, _3); + derivativeRegister.template registerDerivative( + theFunc); + } break; } case (DERIV::Upwind): case (DERIV::Flux): { - if(nGuards == 1) { - const auto theFunc = std::bind( - // Method to store in function - &Method::template upwindOrFlux, - // Arguments -- first is hidden this of type-bound, others are placeholders - // for input field, output field, region - Method{}, _1, _2, _3, _4); - derivativeRegister.template registerDerivative(theFunc); + if (nGuards == 1) { + const auto theFunc = std::bind( + // Method to store in function + &Method::template upwindOrFlux, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + Method{}, _1, _2, _3, _4); + derivativeRegister.template registerDerivative( + theFunc); } else { - const auto theFunc = std::bind( - // Method to store in function - &Method::template upwindOrFlux, - // Arguments -- first is hidden this of type-bound, others are placeholders - // for input field, output field, region - Method{}, _1, _2, _3, _4); - derivativeRegister.template registerDerivative(theFunc); + const auto theFunc = std::bind( + // Method to store in function + &Method::template upwindOrFlux, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + Method{}, _1, _2, _3, _4); + derivativeRegister.template registerDerivative( + theFunc); } break; } @@ -551,120 +563,117 @@ struct registerMethod { ///////////////////////////////////////////////////////////////////////////////// // Could use Ben's magic macro for thing here to register multiple routines at once -#define REGISTER_DERIVATIVE(name) \ - namespace { \ - produceCombinations, \ - Set, \ - Set, TypeContainer>, \ - Set>> \ - reg(registerMethod{}); \ +#define REGISTER_DERIVATIVE(name) \ + namespace { \ + produceCombinations, \ + Set, \ + Set, TypeContainer>, \ + Set>> \ + reg(registerMethod{}); \ } -#define REGISTER_STAGGERED_DERIVATIVE(name) \ - namespace { \ - produceCombinations, \ - Set, \ - Set, TypeContainer>, \ - Set>> \ - reg(registerMethod{}); \ +#define REGISTER_STAGGERED_DERIVATIVE(name) \ + namespace { \ + produceCombinations, \ + Set, \ + Set, TypeContainer>, \ + Set>> \ + reg(registerMethod{}); \ } -produceCombinations< - Set, Set, - Set, TypeContainer>, - Set< - // Standard - DerivativeType, DerivativeType, DerivativeType, - DerivativeType, DerivativeType, - // Standard 2nd order - DerivativeType, DerivativeType, - // Standard 4th order - DerivativeType, - // Upwind - DerivativeType, DerivativeType, DerivativeType, - DerivativeType, DerivativeType, DerivativeType, - // Flux - DerivativeType, DerivativeType, DerivativeType>> -registerDerivatives(registerMethod{}); - - -produceCombinations< - Set, Set, - Set, TypeContainer>, - Set< - // Standard - DerivativeType, DerivativeType, - // Standard 2nd order - DerivativeType, - // Standard 4th order - // Upwind - DerivativeType, DerivativeType, - // Flux - DerivativeType>> -registerDerivativesYOrtho(registerMethod{}); - -produceCombinations< - Set, - Set, - Set, TypeContainer>, - Set< - // Standard - DerivativeType, DerivativeType, - // Standard 2nd order - DerivativeType, - // Upwind - DerivativeType, DerivativeType, - DerivativeType, DerivativeType, - // Flux - DerivativeType>> -registerStaggeredDerivatives(registerMethod{}); - -produceCombinations< - Set, - Set, - Set, TypeContainer>, - Set< - // Standard - DerivativeType, - // Standard 2nd order - // Upwind - DerivativeType, - DerivativeType, - // Flux - DerivativeType>> -registerStaggeredDerivativesYOrtho(registerMethod{}); +produceCombinations, + Set, + Set, TypeContainer>, + Set< + // Standard + DerivativeType, DerivativeType, + DerivativeType, DerivativeType, + DerivativeType, + // Standard 2nd order + DerivativeType, DerivativeType, + // Standard 4th order + DerivativeType, + // Upwind + DerivativeType, DerivativeType, + DerivativeType, DerivativeType, + DerivativeType, DerivativeType, + // Flux + DerivativeType, DerivativeType, + DerivativeType>> + registerDerivatives(registerMethod{}); + +produceCombinations, Set, + Set, TypeContainer>, + Set< + // Standard + DerivativeType, DerivativeType, + // Standard 2nd order + DerivativeType, + // Standard 4th order + // Upwind + DerivativeType, DerivativeType, + // Flux + DerivativeType>> + registerDerivativesYOrtho(registerMethod{}); + +produceCombinations, + Set, + Set, TypeContainer>, + Set< + // Standard + DerivativeType, DerivativeType, + // Standard 2nd order + DerivativeType, + // Upwind + DerivativeType, DerivativeType, + DerivativeType, DerivativeType, + // Flux + DerivativeType>> + registerStaggeredDerivatives(registerMethod{}); + +produceCombinations, Set, + Set, TypeContainer>, + Set< + // Standard + DerivativeType, + // Standard 2nd order + // Upwind + DerivativeType, DerivativeType, + // Flux + DerivativeType>> + registerStaggeredDerivativesYOrtho(registerMethod{}); class FFTDerivativeType { public: template - void standard(const T &var, T &result, REGION region) const { - TRACE("%s",__thefunc__); + void standard(const T& var, T& result, REGION region) const { + TRACE("%s", __thefunc__); ASSERT2(meta.derivType == DERIV::Standard) ASSERT2(var.getMesh()->template getNguard() >= nGuards); - ASSERT2(direction == DIRECTION::Z); //Only in Z for now - ASSERT2(stagger == STAGGER::None); //Staggering not currently supported - ASSERT2((std::is_base_of::value)); //Should never need to call this with Field2D - + ASSERT2(direction == DIRECTION::Z); // Only in Z for now + ASSERT2(stagger == STAGGER::None); // Staggering not currently supported + ASSERT2((std::is_base_of::value)); // Should never need to call this with Field2D + const auto region_str = REGION_STRING(region); // Only allow a whitelist of regions for now - ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" || - region_str == "RGN_NOX" || region_str == "RGN_NOY"); + ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" + || region_str == "RGN_NOX" || region_str == "RGN_NOY"); + + auto* theMesh = var.getMesh(); - auto *theMesh = var.getMesh(); - // Calculate how many Z wavenumbers will be removed const int ncz = theMesh->template getNpoints(); - int kfilter = - static_cast(theMesh->fft_derivs_filter * ncz / 2); // truncates, rounding down + int kfilter = static_cast(theMesh->fft_derivs_filter * ncz + / 2); // truncates, rounding down if (kfilter < 0) kfilter = 0; if (kfilter > (ncz / 2)) kfilter = ncz / 2; const int kmax = ncz / 2 - kfilter; // Up to and including this wavenumber index - BOUT_OMP(parallel) - { + BOUT_OMP(parallel) { Array cv(ncz / 2 + 1); const BoutReal kwaveFac = TWOPI / ncz; @@ -697,40 +706,40 @@ public: } template - void upwindOrFlux(const T &UNUSED(vel), const T &UNUSED(var), T &UNUSED(result), REGION UNUSED(region)) const { - TRACE("%s",__thefunc__); + void upwindOrFlux(const T& UNUSED(vel), const T& UNUSED(var), T& UNUSED(result), + REGION UNUSED(region)) const { + TRACE("%s", __thefunc__); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); return; } metaData meta{"FFT", 0, DERIV::Standard}; }; - class FFT2ndDerivativeType { public: template - void standard(const T &var, T &result, REGION region) const { - TRACE("%s",__thefunc__); + void standard(const T& var, T& result, REGION region) const { + TRACE("%s", __thefunc__); ASSERT2(meta.derivType == DERIV::Standard) ASSERT2(var.getMesh()->template getNguard() >= nGuards); - ASSERT2(direction == DIRECTION::Z); //Only in Z for now - ASSERT2(stagger == STAGGER::None); //Staggering not currently supported - ASSERT2((std::is_base_of::value)); //Should never need to call this with Field2D - + ASSERT2(direction == DIRECTION::Z); // Only in Z for now + ASSERT2(stagger == STAGGER::None); // Staggering not currently supported + ASSERT2((std::is_base_of::value)); // Should never need to call this with Field2D + const auto region_str = REGION_STRING(region); // Only allow a whitelist of regions for now - ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" || - region_str == "RGN_NOX" || region_str == "RGN_NOY"); + ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" + || region_str == "RGN_NOX" || region_str == "RGN_NOY"); + + auto* theMesh = var.getMesh(); - auto *theMesh = var.getMesh(); - // Calculate how many Z wavenumbers will be removed const int ncz = theMesh->template getNpoints(); - const int kmax = ncz/2; + const int kmax = ncz / 2; - BOUT_OMP(parallel) - { + BOUT_OMP(parallel) { Array cv(ncz / 2 + 1); const BoutReal kwaveFac = TWOPI / ncz; @@ -749,7 +758,7 @@ public: for (int jz = 0; jz <= kmax; jz++) { const BoutReal kwave = jz * kwaveFac; // wave number is 1/[rad] - cv[jz] *= -kwave*kwave; + cv[jz] *= -kwave * kwave; } for (int jz = kmax + 1; jz <= ncz / 2; jz++) { cv[jz] = 0.0; @@ -763,18 +772,18 @@ public: } template - void upwindOrFlux(const T &UNUSED(vel), const T &UNUSED(var), T &UNUSED(result), REGION UNUSED(region)) const { - TRACE("%s",__thefunc__); + void upwindOrFlux(const T& UNUSED(vel), const T& UNUSED(var), T& UNUSED(result), + REGION UNUSED(region)) const { + TRACE("%s", __thefunc__); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); return; } metaData meta{"FFT", 0, DERIV::StandardSecond}; }; -produceCombinations< - Set, Set, Set>, - Set - > +produceCombinations, Set, + Set>, + Set> registerFFTDerivative(registerMethod{}); #endif diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 731f54d727..c284a95fc0 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -448,19 +448,19 @@ class Mesh { /// Returns the non-CELL_CENTRE location /// allowed as a staggered location - template + template CELL_LOC getAllowedStaggerLoc() const; /// Returns the number of grid points in the /// particular direction - template + template int getNpoints() const; /// Returns the number of guard points in the /// particular direction - template + template int getNguard() const; - + /////////////////////////////////////////////////////////// // INDEX DERIVATIVE OPERATORS /////////////////////////////////////////////////////////// @@ -472,83 +472,97 @@ class Mesh { /// Determines the resultant output stagger location in derivatives /// given the input and output location. Also checks that the /// combination of locations is allowed - STAGGER getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc) const; - + STAGGER getStagger(const CELL_LOC inloc, const CELL_LOC outloc, + const CELL_LOC allowedloc) const; + /// Determines the resultant output stagger location in derivatives /// given the input and output location. Also checks that the /// combination of locations is allowed. This overload also checks /// the location of a second input field (velocity) is consistent. - STAGGER getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc) const; - + STAGGER getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, + const CELL_LOC allowedloc) const; + ////// STANDARD OPERATORS ////////////// X DERIVATIVE ///////////////// - template - T indexDDX(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + template + T indexDDX(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexStandardDerivative(f, outloc, method, region); } - template - T indexD2DX2(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + template + T indexD2DX2(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexStandardDerivative(f, outloc, method, region); } - template - T indexD4DX4(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + template + T indexD4DX4(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexStandardDerivative(f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// - template - T indexDDY(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - if (std::is_base_of::value && f.hasYupYdown() && - ((&f.yup() != &f) || (&f.ydown() != &f))) { - return indexStandardDerivative(f, outloc, method, region); + template + T indexDDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + if (std::is_base_of::value && f.hasYupYdown() + && ((&f.yup() != &f) || (&f.ydown() != &f))) { + return indexStandardDerivative(f, outloc, method, + region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); T result = indexStandardDerivative(f, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); + return f.getMesh()->fromFieldAligned(result); } } - template - T indexD2DY2(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - if (std::is_base_of::value && f.hasYupYdown() && - ((&f.yup() != &f) || (&f.ydown() != &f))) { - return indexStandardDerivative(f, outloc, method, region); + template + T indexD2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + if (std::is_base_of::value && f.hasYupYdown() + && ((&f.yup() != &f) || (&f.ydown() != &f))) { + return indexStandardDerivative(f, outloc, method, + region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); T result = indexStandardDerivative(f, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); + return f.getMesh()->fromFieldAligned(result); } } - template - T indexD4DY4(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - if (std::is_base_of::value && f.hasYupYdown() && - ((&f.yup() != &f) || (&f.ydown() != &f))) { - return indexStandardDerivative(f, outloc, method, region); + template + T indexD4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + if (std::is_base_of::value && f.hasYupYdown() + && ((&f.yup() != &f) || (&f.ydown() != &f))) { + return indexStandardDerivative(f, outloc, method, + region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); T result = indexStandardDerivative(f, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); + return f.getMesh()->fromFieldAligned(result); } } ////////////// Z DERIVATIVE ///////////////// - template - T indexDDZ(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + template + T indexDDZ(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexStandardDerivative(f, outloc, method, region); } - template - T indexD2DZ2(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + template + T indexD2DZ2(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexStandardDerivative(f, outloc, method, region); } - template - T indexD4DZ4(const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + template + T indexD4DZ4(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { return indexStandardDerivative(f, outloc, method, region); } @@ -562,64 +576,83 @@ class Mesh { /// /// @param[in] v The velocity in the Y direction /// @param[in] f The field being advected - /// @param[in] outloc The cell location where the result is desired. The default is the same as \p f + /// @param[in] outloc The cell location where the result is desired. The default is the + /// same as \p f /// @param[in] method The differencing method to use /// @param[in] region The region of the grid for which the result is calculated. ////////////// X DERIVATIVE ///////////////// - template - T indexVDDX(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexFlowDerivative(vel, f, outloc, method, region); + template + T indexVDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + return indexFlowDerivative(vel, f, outloc, method, + region); } - template - T indexFDDX(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexFlowDerivative(vel, f, outloc, method, region); + template + T indexFDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + return indexFlowDerivative(vel, f, outloc, method, + region); } ////////////// Y DERIVATIVE ///////////////// - template - T indexVDDY(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); - bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); + template + T indexVDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() + && ((&f.yup() != &f) || (&f.ydown() != &f))); + bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() + && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); if (fHasParallelSlices && velHasParallelSlices) { - return indexFlowDerivative(vel, f, outloc, method, region); + return indexFlowDerivative( + vel, f, outloc, method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); - const T vel_aligned = vel.getMesh()->toFieldAligned(vel); - T result = indexFlowDerivative(vel_aligned, f_aligned, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); + const T vel_aligned = vel.getMesh()->toFieldAligned(vel); + T result = indexFlowDerivative( + vel_aligned, f_aligned, outloc, method, region); + return f.getMesh()->fromFieldAligned(result); } } - template - T indexFDDY(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); - bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); + template + T indexFDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() + && ((&f.yup() != &f) || (&f.ydown() != &f))); + bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() + && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); if (fHasParallelSlices && velHasParallelSlices) { - return indexFlowDerivative(vel, f, outloc, method, region); + return indexFlowDerivative(vel, f, outloc, + method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); - const T vel_aligned = vel.getMesh()->toFieldAligned(vel); - T result = indexFlowDerivative(vel_aligned, f_aligned, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); + const T vel_aligned = vel.getMesh()->toFieldAligned(vel); + T result = indexFlowDerivative( + vel_aligned, f_aligned, outloc, method, region); + return f.getMesh()->fromFieldAligned(result); } } ////////////// Z DERIVATIVE ///////////////// - template - T indexVDDZ(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexFlowDerivative(vel, f, outloc, method, region); + template + T indexVDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + return indexFlowDerivative(vel, f, outloc, method, + region); } - template - T indexFDDZ(const T& vel, const T &f, CELL_LOC outloc = CELL_DEFAULT, const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexFlowDerivative(vel, f, outloc, method, region); + template + T indexFDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { + return indexFlowDerivative(vel, f, outloc, method, + region); } - + /////////////////////////////////////////////////////////// // PARALLEL TRANSFORMS /////////////////////////////////////////////////////////// @@ -747,14 +780,15 @@ class Mesh { void derivs_init(Options* options); private: - /// The main kernel used for all standard derivatives - template - T indexStandardDerivative(const T &f, CELL_LOC outloc, const std::string &method, REGION region) const; + template + T indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method, + REGION region) const; /// The main kernel used for all upwind and flux derivatives - template - T indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, const std::string &method, REGION region) const; + template + T indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, + const std::string& method, REGION region) const; /// Allocates default Coordinates objects std::shared_ptr createDefaultCoordinates(const CELL_LOC location); @@ -766,10 +800,11 @@ private: Array indexLookup3Dto2D; }; -template -T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, const std::string &method, REGION region) const { +template +T Mesh::indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, + const std::string& method, REGION region) const { TRACE("%s", __thefunc__); - + // Checks static_assert(std::is_base_of::value || std::is_base_of::value, "indexDDX only works on Field2D or Field3D input"); @@ -778,23 +813,25 @@ T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, const std if ((derivType == DERIV::Flux) && (method == DIFF_METHOD_STRING(DIFF_SPLIT))) { // Split into an upwind and a central differencing part // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) - auto tmp = indexFlowDerivative(vel, f, outloc, "DEFAULT", region); - tmp += indexStandardDerivative(vel, outloc, "DEFAULT", region) * interp_to(f, tmp.getLocation()); - return tmp; + auto tmp = indexFlowDerivative(vel, f, outloc, "DEFAULT", + region); + tmp += indexStandardDerivative(vel, outloc, "DEFAULT", region) + * interp_to(f, tmp.getLocation()); + return tmp; } - + // Check that the mesh is correct ASSERT1(this == f.getMesh()); - ASSERT1(this == vel.getMesh()); + ASSERT1(this == vel.getMesh()); // Check that the input variable has data ASSERT1(f.isAllocated()); - ASSERT1(vel.isAllocated()); - - //Check the input data is valid + ASSERT1(vel.isAllocated()); + + // Check the input data is valid { TRACE("Checking inputs"); checkData(f); - checkData(vel); + checkData(vel); } // Define properties of this approach @@ -815,7 +852,7 @@ T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, const std tmp.setLocation(outloc); return tmp; } - + // Lookup the method auto& derivativeStore = DerivativeStore::getInstance(); typename DerivativeStore::upwindFunc derivativeMethod; @@ -826,7 +863,7 @@ T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, const std } else { throw BoutException("Invalid derivative type in call to indexFlowDerivative."); } - + // Create the result field T result(f.getMesh()); result.allocate(); // Make sure data allocated @@ -835,19 +872,20 @@ T Mesh::indexFlowDerivative(const T &vel, const T &f, CELL_LOC outloc, const std // Apply method derivativeMethod(vel, f, result, region); - //Check the result is valid + // Check the result is valid { TRACE("Checking result"); checkData(result); } - + return result; } -template -T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, const std::string &method, REGION region) const { +template +T Mesh::indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method, + REGION region) const { TRACE("%s", __thefunc__); - + // Checks static_assert(std::is_base_of::value || std::is_base_of::value, "indexDDX only works on Field2D or Field3D input"); @@ -856,12 +894,12 @@ T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, const std::string & // Check that the input variable has data ASSERT1(f.isAllocated()); - //Check the input data is valid + // Check the input data is valid { TRACE("Checking input"); checkData(f); } - + // Define properties of this approach const CELL_LOC allowedStaggerLoc = getAllowedStaggerLoc(); @@ -879,21 +917,23 @@ T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, const std::string & tmp.setLocation(outloc); return tmp; } - + // Lookup the method auto& derivativeStore = DerivativeStore::getInstance(); typename DerivativeStore::standardFunc derivativeMethod; - + if (order == 1) { derivativeMethod = derivativeStore.getStandardDerivative(method, direction, stagger); } else if (order == 2) { - derivativeMethod = derivativeStore.getStandard2ndDerivative(method, direction, stagger); + derivativeMethod = + derivativeStore.getStandard2ndDerivative(method, direction, stagger); } else if (order == 4) { - derivativeMethod = derivativeStore.getStandard4thDerivative(method, direction, stagger); + derivativeMethod = + derivativeStore.getStandard4thDerivative(method, direction, stagger); } else { throw BoutException("Invalid order used in indexStandardDerivative."); } - + // Create the result field T result(f.getMesh()); result.allocate(); // Make sure data allocated @@ -902,12 +942,12 @@ T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, const std::string & // Apply method derivativeMethod(f, result, region); - //Check the result is valid + // Check the result is valid { TRACE("Checking result"); checkData(result); } - + return result; } @@ -915,48 +955,46 @@ T Mesh::indexStandardDerivative(const T &f, CELL_LOC outloc, const std::string & * Helper routines *******************************************************************************/ -template +template CELL_LOC Mesh::getAllowedStaggerLoc() const { - switch(direction) { - case(DIRECTION::X): + switch (direction) { + case (DIRECTION::X): return CELL_XLOW; - case(DIRECTION::Y): - case(DIRECTION::YOrthogonal): - case(DIRECTION::YAligned): + case (DIRECTION::Y): + case (DIRECTION::YOrthogonal): + case (DIRECTION::YAligned): return CELL_YLOW; - case(DIRECTION::Z): + case (DIRECTION::Z): return CELL_ZLOW; } }; - -template +template int Mesh::getNpoints() const { - switch(direction) { - case(DIRECTION::X): + switch (direction) { + case (DIRECTION::X): return LocalNx; - case(DIRECTION::Y): - case(DIRECTION::YOrthogonal): - case(DIRECTION::YAligned): + case (DIRECTION::Y): + case (DIRECTION::YOrthogonal): + case (DIRECTION::YAligned): return LocalNy; - case(DIRECTION::Z): + case (DIRECTION::Z): return LocalNz; } }; -template +template int Mesh::getNguard() const { - switch(direction) { - case(DIRECTION::X): + switch (direction) { + case (DIRECTION::X): return xstart; - case(DIRECTION::Y): - case(DIRECTION::YOrthogonal): - case(DIRECTION::YAligned): + case (DIRECTION::Y): + case (DIRECTION::YOrthogonal): + case (DIRECTION::YAligned): return ystart; - case(DIRECTION::Z): + case (DIRECTION::Z): return 2; } }; #endif // __MESH_H__ - diff --git a/include/bout/template_combinations.hxx b/include/bout/template_combinations.hxx index 148a92fa37..19f5e6ad10 100644 --- a/include/bout/template_combinations.hxx +++ b/include/bout/template_combinations.hxx @@ -36,12 +36,16 @@ /// a collection of arbitrary types. This is useful for passing /// template packs (typename...) around whilst being able to /// distinguish between different template packs. -template struct Set {}; +template +struct Set {}; /// Here we provide a container type that can be used to pass around /// a type without needing to create instances of the specific type /// (instead we create instances of the container type). -template struct TypeContainer{ using type = T; }; +template +struct TypeContainer { + using type = T; +}; /// Define a struct (functor) that we use to build up the final /// collection of template values. Each time we create one of these @@ -50,7 +54,8 @@ template struct TypeContainer{ using type = T; }; /// for whatever the storedFunc is at that point -- once we have built a /// complete templatePack we don't need to specify any of these template /// parameters as they can be deduced/inferred. -template struct DeferredFunction { +template +struct DeferredFunction { // Just store the actual function we wish to apply DeferredFunction(currentFunction f) : storedFunc(f){}; @@ -59,7 +64,8 @@ template struct DeferredFunctio // Make the struct a functor by defining operator() we use // type inference to populate the templatePack/args - template void operator()(templatePack... args) { + template + void operator()(templatePack... args) { storedFunc(currentType{}, args...); } }; @@ -170,8 +176,10 @@ void processSet(theFunction func, Set, otherSets... ot /// /// Note we wrap this in a struct such that by declaring a global variable of this /// type we trigger the creation of the combinations. -template struct produceCombinations { - template produceCombinations(theFunction func) { +template +struct produceCombinations { + template + produceCombinations(theFunction func) { processSet(func, FirstSet{}, otherSets{}...); }; }; diff --git a/include/derivs.hxx b/include/derivs.hxx index 569beeb504..b48dc89e40 100644 --- a/include/derivs.hxx +++ b/include/derivs.hxx @@ -36,11 +36,6 @@ #include "bout_types.hxx" -// Feel free to edit this file (derivs.hxx) rather then the generating -// files. If this is easier then changing derivx.hxx.in.py or -// derivs.hxx.in.jinja do so, but please remove the derivs.hxx.in.* -// files to make clear the file is not auto-generated anymore. - ////////// FIRST DERIVATIVES ////////// /// Calculate first partial derivative in X @@ -55,10 +50,10 @@ /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D DDX(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D DDX(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { +const Field3D DDX(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D DDX(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return DDX(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -74,11 +69,11 @@ inline const Field3D DDX(const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D DDX(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D DDX(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ - return DDX(f, outloc, DIFF_METHOD_STRING(method), region); +const Field2D DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D DDX(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { + return DDX(f, outloc, DIFF_METHOD_STRING(method), region); }; /// Calculate first partial derivative in Y @@ -93,10 +88,10 @@ inline const Field2D DDX(const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D DDY(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D DDY(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D DDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D DDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return DDY(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -112,10 +107,10 @@ inline const Field3D DDY(const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D DDY(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D DDY(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D DDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return DDY(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -131,10 +126,10 @@ inline const Field2D DDY(const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D DDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D DDZ(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D DDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D DDZ(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -150,14 +145,13 @@ inline const Field3D DDZ(const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D DDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D DDZ(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D DDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); }; - /// Calculate first partial derivative in Z /// /// \f$\partial / \partial z\f$ @@ -170,14 +164,13 @@ inline const Field2D DDZ(const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Vector3D DDZ(const Vector3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Vector3D DDZ(const Vector3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Vector3D DDZ(const Vector3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Vector3D DDZ(const Vector3D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); }; - /// Calculate first partial derivative in Z /// /// \f$\partial / \partial z\f$ @@ -190,10 +183,10 @@ inline const Vector3D DDZ(const Vector3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Vector2D DDZ(const Vector2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Vector2D DDZ(const Vector2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Vector2D DDZ(const Vector2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Vector2D DDZ(const Vector2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -211,10 +204,10 @@ inline const Vector2D DDZ(const Vector2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DX2(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D2DX2(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D D2DX2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D2DX2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D2DX2(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -230,10 +223,10 @@ inline const Field3D D2DX2(const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DX2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D2DX2(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D D2DX2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D2DX2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D2DX2(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -249,10 +242,10 @@ inline const Field2D D2DX2(const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DY2(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D2DY2(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D D2DY2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D2DY2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D2DY2(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -268,10 +261,10 @@ inline const Field3D D2DY2(const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DY2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D2DY2(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D D2DY2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D2DY2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D2DY2(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -287,10 +280,10 @@ inline const Field2D D2DY2(const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D D2DZ2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D2DZ2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D2DZ2(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -306,10 +299,10 @@ inline const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DZ2(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D2DZ2(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D D2DZ2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D2DZ2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D2DZ2(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -327,10 +320,10 @@ inline const Field2D D2DZ2(const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D4DX4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D4DX4(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D D4DX4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D4DX4(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D4DX4(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -346,10 +339,10 @@ inline const Field3D D4DX4(const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D4DX4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D4DX4(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D D4DX4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D4DX4(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D4DX4(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -365,10 +358,10 @@ inline const Field2D D4DX4(const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D4DY4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D4DY4(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D D4DY4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D4DY4(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D4DY4(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -384,10 +377,10 @@ inline const Field3D D4DY4(const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D4DY4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D4DY4(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D D4DY4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D4DY4(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D4DY4(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -403,10 +396,10 @@ inline const Field2D D4DY4(const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D4DZ4(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D4DZ4(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D D4DZ4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D4DZ4(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D4DZ4(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -422,10 +415,10 @@ inline const Field3D D4DZ4(const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D D4DZ4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D4DZ4(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D4DZ4(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -442,10 +435,10 @@ inline const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D VDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D VDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { return VDDX(v, f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -462,10 +455,10 @@ inline const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D VDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D VDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { return VDDX(v, f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -482,10 +475,10 @@ inline const Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D VDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D VDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { return VDDY(v, f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -502,10 +495,10 @@ inline const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D VDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D VDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { return VDDY(v, f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -522,10 +515,10 @@ inline const Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D VDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D VDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { return VDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -542,14 +535,13 @@ inline const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D VDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D VDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D VDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D VDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { return VDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); }; - /// For terms of form v * grad(f) /// /// \f$v \cdot \partial f / \partial z\f$ @@ -563,10 +555,10 @@ inline const Field2D VDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D VDDZ(const Field3D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D VDDZ(const Field3D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D VDDZ(const Field3D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D VDDZ(const Field3D& v, const Field2D& f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { return VDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -583,10 +575,10 @@ inline const Field2D VDDZ(const Field3D &v, const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D FDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D FDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { return FDDX(v, f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -603,10 +595,10 @@ inline const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D FDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D FDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { return FDDX(v, f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -623,10 +615,10 @@ inline const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D FDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D FDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { return FDDY(v, f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -643,10 +635,10 @@ inline const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D FDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D FDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { return FDDY(v, f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -663,10 +655,10 @@ inline const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D FDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D FDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { return FDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -683,10 +675,10 @@ inline const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D FDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D FDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D FDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D FDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc, + DIFF_METHOD method, REGION region = RGN_NOBNDRY) { return FDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -702,10 +694,10 @@ inline const Field2D FDDZ(const Field2D &v, const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D2DXDY(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -721,10 +713,10 @@ inline const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D2DXDY(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -740,10 +732,10 @@ inline const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D D2DXDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D2DXDZ(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D2DXDZ(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -759,10 +751,10 @@ inline const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D D2DXDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D2DXDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D2DXDZ(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -778,10 +770,10 @@ inline const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DYDZ(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D2DYDZ(const Field3D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D2DYDZ(f, outloc, DIFF_METHOD_STRING(method), region); }; @@ -797,10 +789,10 @@ inline const Field3D D2DYDZ(const Field3D &f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT, - const std::string &method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY){ +const Field2D D2DYDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); +inline const Field2D D2DYDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + REGION region = RGN_NOBNDRY) { return D2DYDZ(f, outloc, DIFF_METHOD_STRING(method), region); }; diff --git a/include/difops.hxx b/include/difops.hxx index cf98c5d31c..a12ee3492f 100644 --- a/include/difops.hxx +++ b/include/difops.hxx @@ -46,27 +46,35 @@ /*! * Parallel derivative (central differencing) in Y - * along unperturbed field + * along unperturbed field * * @param[in] var The field to be differentiated - * @param[in] outloc The cell location where the output is needed (if staggered grids is enabled) - * @param[in] method The method to use. The default is set in the options. + * @param[in] outloc The cell location where the output is needed (if staggered grids is + * enabled) + * @param[in] method The method to use. The default is set in the options. */ -const Field2D Grad_par(const Field2D &var, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); -DEPRECATED(const Field2D Grad_par(const Field2D &var, const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); -inline const Field2D Grad_par(const Field2D &var, CELL_LOC outloc, DIFF_METHOD method){ +const Field2D Grad_par(const Field2D& var, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +DEPRECATED(const Field2D Grad_par(const Field2D& var, const std::string& method, + CELL_LOC outloc = CELL_DEFAULT)); +inline const Field2D Grad_par(const Field2D& var, CELL_LOC outloc, DIFF_METHOD method) { return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); }; -DEPRECATED(inline const Field2D Grad_par(const Field2D &var, DIFF_METHOD method, CELL_LOC outloc)) { +DEPRECATED(inline const Field2D Grad_par(const Field2D& var, DIFF_METHOD method, + CELL_LOC outloc)) { return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); }; -const Field3D Grad_par(const Field3D &var, CELL_LOC outloc=CELL_DEFAULT, const std::string &method = "DEFAULT"); -DEPRECATED(const Field3D Grad_par(const Field3D &var, const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); -inline const DEPRECATED(Field3D Grad_par(const Field3D &var, CELL_LOC outloc, DIFF_METHOD method)) { +const Field3D Grad_par(const Field3D& var, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +DEPRECATED(const Field3D Grad_par(const Field3D& var, const std::string& method, + CELL_LOC outloc = CELL_DEFAULT)); +inline const DEPRECATED(Field3D Grad_par(const Field3D& var, CELL_LOC outloc, + DIFF_METHOD method)) { return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); }; -DEPRECATED(inline const DEPRECATED(Field3D Grad_par(const Field3D &var, DIFF_METHOD method, CELL_LOC outloc))) { +DEPRECATED(inline const DEPRECATED( + Field3D Grad_par(const Field3D& var, DIFF_METHOD method, CELL_LOC outloc))) { return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); }; @@ -80,80 +88,84 @@ DEPRECATED(inline const DEPRECATED(Field3D Grad_par(const Field3D &var, DIFF_MET * Combines the parallel and perpendicular calculation to include * grid-points at the corners. */ -const Field3D Grad_parP(const Field3D &apar, const Field3D &f); +const Field3D Grad_parP(const Field3D& apar, const Field3D& f); /*! * vpar times parallel derivative along unperturbed B-field (upwinding) * - * \f[ + * \f[ * v\mathbf{b}_0 \cdot \nabla f * \f] - * + * * @param[in] v The velocity in y direction * @param[in] f The scalar field to be differentiated * @param[in] outloc The cell location of the output. By default this is the same as \p f * @param[in] method The numerical method to use. The default is set in the options - * + * */ -const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, - CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); -DEPRECATED(const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, - const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); -inline const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, - CELL_LOC outloc, DIFF_METHOD method){ +const Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, + CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +DEPRECATED(const Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, + const std::string& method, + CELL_LOC outloc = CELL_DEFAULT)); +inline const Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, CELL_LOC outloc, + DIFF_METHOD method) { return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); }; -DEPRECATED(inline const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, DIFF_METHOD method, CELL_LOC outloc)) { +DEPRECATED(inline const Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, + DIFF_METHOD method, CELL_LOC outloc)) { return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); }; -const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, - CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); -DEPRECATED(const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, - const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); -inline const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, - CELL_LOC outloc, DIFF_METHOD method){ +const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, + CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +DEPRECATED(const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, + const std::string& method, + CELL_LOC outloc = CELL_DEFAULT)); +inline const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, CELL_LOC outloc, + DIFF_METHOD method) { return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); }; -DEPRECATED(inline const Field3D Vpar_Grad_par(const Field3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc)) { +DEPRECATED(inline const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, + DIFF_METHOD method, CELL_LOC outloc)) { return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); }; /*! * parallel divergence operator - * + * * \f[ * B \partial_{||}(f/B) = B \nabla\cdot (\mathbf{b}f/B ) * \f] - * - * @param[in] f The component of a vector along the magnetic field + * + * @param[in] f The component of a vector along the magnetic field * @param[in] outloc The cell location for the result. By default the same as \p f * @param[in] method The numerical method to use - * + * */ -const Field2D Div_par(const Field2D &f, - CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); -DEPRECATED(const Field2D Div_par(const Field2D &f, - const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); -inline const Field2D Div_par(const Field2D &f, - CELL_LOC outloc, DIFF_METHOD method){ +const Field2D Div_par(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +DEPRECATED(const Field2D Div_par(const Field2D& f, const std::string& method, + CELL_LOC outloc = CELL_DEFAULT)); +inline const Field2D Div_par(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { return Div_par(f, outloc, DIFF_METHOD_STRING(method)); }; -DEPRECATED(inline const Field2D Div_par(const Field2D &f, - DIFF_METHOD method, CELL_LOC outloc)) { +DEPRECATED(inline const Field2D Div_par(const Field2D& f, DIFF_METHOD method, + CELL_LOC outloc)) { return Div_par(f, outloc, DIFF_METHOD_STRING(method)); }; -const Field3D Div_par(const Field3D &f, - CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); -DEPRECATED(const Field3D Div_par(const Field3D &f, - const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); -inline const Field3D Div_par(const Field3D &f, - CELL_LOC outloc, DIFF_METHOD method){ +const Field3D Div_par(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +DEPRECATED(const Field3D Div_par(const Field3D& f, const std::string& method, + CELL_LOC outloc = CELL_DEFAULT)); +inline const Field3D Div_par(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { return Div_par(f, outloc, DIFF_METHOD_STRING(method)); }; -DEPRECATED(inline const Field3D Div_par(const Field3D &f, - DIFF_METHOD method, CELL_LOC outloc)) { +DEPRECATED(inline const Field3D Div_par(const Field3D& f, DIFF_METHOD method, + CELL_LOC outloc)) { return Div_par(f, outloc, DIFF_METHOD_STRING(method)); }; @@ -161,19 +173,23 @@ DEPRECATED(inline const Field3D Div_par(const Field3D &f, // Both f and v are interpolated onto cell boundaries // using 2nd order central difference, then multiplied together // to get the flux at the boundary. -const Field3D Div_par(const Field3D &f, const Field3D &v); +const Field3D Div_par(const Field3D& f, const Field3D& v); // Flux methods. Model divergence of flux: df/dt = Div(v * f) // TODO : Should we add Field2D versions? -const Field3D Div_par_flux(const Field3D &v, const Field3D &f, - CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); -DEPRECATED(const Field3D Div_par_flux(const Field3D &v, const Field3D &f, - const std::string &method, CELL_LOC outloc=CELL_DEFAULT)); -inline const Field3D Div_par_flux(const Field3D &v, const Field3D &f, - CELL_LOC outloc, DIFF_METHOD method){ +const Field3D Div_par_flux(const Field3D& v, const Field3D& f, + CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +DEPRECATED(const Field3D Div_par_flux(const Field3D& v, const Field3D& f, + const std::string& method, + CELL_LOC outloc = CELL_DEFAULT)); +inline const Field3D Div_par_flux(const Field3D& v, const Field3D& f, CELL_LOC outloc, + DIFF_METHOD method) { return Div_par_flux(v, f, outloc, DIFF_METHOD_STRING(method)); }; -DEPRECATED(inline const Field3D Div_par_flux(const Field3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT)) { +DEPRECATED(inline const Field3D Div_par_flux(const Field3D& v, const Field3D& f, + DIFF_METHOD method, + CELL_LOC outloc = CELL_DEFAULT)) { return Div_par_flux(v, f, outloc, DIFF_METHOD_STRING(method)); }; @@ -186,15 +202,17 @@ DEPRECATED(inline const Field3D Div_par_flux(const Field3D &v, const Field3D &f, * Note: For parallel Laplacian use LaplacePar * * @param[in] f The field to be differentiated - * @param[in] outloc The cell location of the result + * @param[in] outloc The cell location of the result */ -const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); -inline const Field2D Grad2_par2(const Field2D &f, CELL_LOC outloc, DIFF_METHOD method) { +const Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +inline const Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { return Grad2_par2(f, outloc, DIFF_METHOD_STRING(method)); }; -const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT, const std::string &method="DEFAULT"); -inline const Field3D Grad2_par2(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method){ +const Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +inline const Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { return Grad2_par2(f, outloc, DIFF_METHOD_STRING(method)); }; diff --git a/include/vecops.hxx b/include/vecops.hxx index 57c41c93e4..2cd611d177 100644 --- a/include/vecops.hxx +++ b/include/vecops.hxx @@ -73,12 +73,16 @@ const Field3D Div(const Vector3D &v, CELL_LOC outloc = CELL_DEFAULT); const Field2D Div(const Vector2D &v, const Field2D &f); const Field3D Div(const Vector3D &v, const Field3D &f); -const Field3D Div(const Vector3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method = "DEFAULT"); -DEPRECATED(const Field3D Div(const Vector3D &v, const Field3D &f, const std::string &method, CELL_LOC outloc = CELL_DEFAULT)); -inline const Field3D Div(const Vector3D &v, const Field3D &f, CELL_LOC outloc, DIFF_METHOD method = DIFF_DEFAULT){ +const Field3D Div(const Vector3D& v, const Field3D& f, CELL_LOC outloc, + const std::string& method = "DEFAULT"); +DEPRECATED(const Field3D Div(const Vector3D& v, const Field3D& f, + const std::string& method, CELL_LOC outloc = CELL_DEFAULT)); +inline const Field3D Div(const Vector3D& v, const Field3D& f, CELL_LOC outloc, + DIFF_METHOD method = DIFF_DEFAULT) { return Div(v, f, outloc, DIFF_METHOD_STRING(method)); }; -DEPRECATED(inline const Field3D Div(const Vector3D &v, const Field3D &f, DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT)) { +DEPRECATED(inline const Field3D Div(const Vector3D& v, const Field3D& f, + DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT)) { return Div(v, f, outloc, DIFF_METHOD_STRING(method)); }; diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 29f4d31e14..764895a9d8 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -30,7 +30,7 @@ *******************************************************************************/ /// Initialise the derivative methods. Must be called before any derivatives are used -void Mesh::derivs_init(Options *options) { +void Mesh::derivs_init(Options* options) { TRACE("Initialising derivatives"); // For each direction need to set what the default method is for each type // of derivative. @@ -40,12 +40,14 @@ void Mesh::derivs_init(Options *options) { options->getSection("ddz")->get("fft_filter", fft_derivs_filter, 0.0); } -STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { +STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, + const CELL_LOC allowedStaggerLoc) const { TRACE("Mesh::getStagger -- three arguments"); - ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == allowedStaggerLoc) || - (outloc == allowedStaggerLoc && inloc == CELL_CENTRE)); + ASSERT1(outloc == inloc || (outloc == CELL_CENTRE && inloc == allowedStaggerLoc) + || (outloc == allowedStaggerLoc && inloc == CELL_CENTRE)); - if ( (!StaggerGrids) || outloc == inloc) return STAGGER::None; + if ((!StaggerGrids) || outloc == inloc) + return STAGGER::None; if (outloc == allowedStaggerLoc) { return STAGGER::C2L; } else { @@ -54,15 +56,14 @@ STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, const CELL } #if CHECK > 0 -STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { +STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, + const CELL_LOC allowedStaggerLoc) const { #else STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC UNUSED(inloc), const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { #endif - TRACE("Mesh::getStagger -- four arguments"); - ASSERT1(vloc == inloc || - (vloc == CELL_CENTRE && inloc == allowedStaggerLoc) || - (vloc == allowedStaggerLoc && inloc == CELL_CENTRE) - ); + TRACE("Mesh::getStagger -- four arguments"); + ASSERT1(vloc == inloc || (vloc == CELL_CENTRE && inloc == allowedStaggerLoc) + || (vloc == allowedStaggerLoc && inloc == CELL_CENTRE)); return getStagger(vloc, outloc, allowedStaggerLoc); } From ce5b46ed50e274429ba6c70eb1c7e52d1e92a75f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 16 Nov 2018 11:50:25 +0000 Subject: [PATCH 0271/1783] Make sure command line short-options override options file settings --- src/bout++.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 977ce7d155..b223d06b8e 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -261,11 +261,6 @@ int BoutInitialise(int &argc, char **&argv) { throw BoutException(_("DataDir \"%s\" does not exist or is not accessible\n"),data_dir); } - // Set options - Options::getRoot()->set("datadir", string(data_dir)); - Options::getRoot()->set("optionfile", string(opt_file)); - Options::getRoot()->set("settingsfile", string(set_file)); - // Set the command-line arguments SlepcLib::setArgs(argc, argv); // SLEPc initialisation PetscLib::setArgs(argc, argv); // PETSc initialisation @@ -428,6 +423,11 @@ int BoutInitialise(int &argc, char **&argv) { // Get options override from command-line reader->parseCommandLine(options, argc, argv); + // Override options set from short option from the command-line + Options::root()["datadir"] = data_dir; + Options::root()["optionfile"] = opt_file; + Options::root()["settingsfile"] = set_file; + // Put some run information in the options. // This is mainly so it can be easily read in post-processing auto &runinfo = Options::root()["run"]; From 34e4446d059328bea8129c70c17738d48239eab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 15 Nov 2018 20:28:05 +0000 Subject: [PATCH 0272/1783] Improve documentation --- tools/pylib/_boutcore_build/boutcore.pyx.in | 55 +++++++++++---------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 89c0d39c47..c227b19722 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -162,11 +162,11 @@ cdef class $ftype: Parameters ---------- - tind : int + tind : int, optional time slice to read - mesh : Mesh + mesh : Mesh, optional if not defined, use global mesh - ignoreDataType : bool + ignoreDataType : bool, optional Do not fail if data is not float64 **kwargs remaining arguments are passed to collect @@ -223,11 +223,11 @@ cdef class $ftype: ---------- outputs : BoutOutputs object to read from - tind : int + tind : int, optional time slice to read - mesh : Mesh + mesh : Mesh, optional if not defined, use global mesh - ignoreDataType : bool + ignoreDataType : bool, optional Do not fail if data is not float64 **kwargs remaining arguments are passed to collect @@ -299,7 +299,7 @@ cdef class $ftype: ---------- data : array_like The data to be set - ignoreDataType : bool + ignoreDataType : bool, optional Ignore if data is off different type to BoutReal """ return self.setAll(data,ignoreDataType) @@ -312,7 +312,7 @@ cdef class $ftype: ---------- data : array_like The data to be set - ignoreDataType : bool + ignoreDataType : bool, optional Ignore if data is off different type to BoutRealxx """ EOF @@ -402,6 +402,11 @@ cat <val).cobj) @@ -436,7 +441,7 @@ cat < Date: Fri, 16 Nov 2018 12:00:00 +0000 Subject: [PATCH 0273/1783] Documentation improvements --- tools/pylib/_boutcore_build/boutcore.pyx.in | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index c227b19722..2c754f3814 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -393,11 +393,6 @@ cat < Date: Fri, 16 Nov 2018 11:59:10 +0000 Subject: [PATCH 0274/1783] Fix:Escaping in makefile Prevent make from expanding variables intended for bash --- tools/pylib/_boutcore_build/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pylib/_boutcore_build/Makefile b/tools/pylib/_boutcore_build/Makefile index a583292e1c..a5fa87a795 100644 --- a/tools/pylib/_boutcore_build/Makefile +++ b/tools/pylib/_boutcore_build/Makefile @@ -12,7 +12,7 @@ TOGEN=setup.py boutcore.pyx resolve_enum.pxd helper.cxx helper.h boutcpp.pxd $(TOGEN): Makefile $(BOUT_TOP)/make.config @echo " Generating $@" @PATH=$(BOUT_TOP)/bin:$$PATH PY=$(PY) bash $@.in > $@.tmp \ - || (fail=$?; echo "touch $@ to ignore failed generation" ; exit $fail) + || (fail=$$?; echo "touch $@ to ignore failed generation" ; exit $$fail) @mv $@.tmp $@ boutcore.so: boutcore.pyx setup.py helper.cxx helper.h $(TOGEN) From a93fcddba5713d0d904dfc694e088e3a4c71ef44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 16 Nov 2018 12:01:36 +0000 Subject: [PATCH 0275/1783] Basic Vector support for boutcore Grad_perp returns a vector. Thus a Vector3D and the dot product is needed as well. --- include/vecops.hxx | 3 + tools/pylib/_boutcore_build/boutcore.pyx.in | 69 ++++++++++++++++++++- tools/pylib/_boutcore_build/boutcpp.pxd.in | 19 ++++++ tools/pylib/_boutcore_build/common.sh | 23 +++++++ tools/pylib/_boutcore_build/helper.h.in | 13 ++++ 5 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 tools/pylib/_boutcore_build/common.sh diff --git a/include/vecops.hxx b/include/vecops.hxx index 134e76006f..0bc40194d0 100644 --- a/include/vecops.hxx +++ b/include/vecops.hxx @@ -56,6 +56,9 @@ const Vector3D Grad(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT); /// @param[in] outloc The cell location where the result is desired /// const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT); +inline const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method){ + return Grad_perp(f,outloc); +} /// Divergence of a vector \p v, returning a scalar /// diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 89c0d39c47..3a9bbdc8bb 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -77,6 +77,8 @@ makelist () { start="$spacing" ; i=$(( i + 1 )) done ; } +. common.sh + for ftype in "Field3D" "Field2D" do if [ $ftype = "Field3D" ]; then @@ -607,8 +609,56 @@ cat <self).cobj, (<$vec?>rhs).cobj)) + else: + raise NotImplementedError("unexpected argument type '"+ + str(type(self))+"' and '"+str(type(rhs))+ + "' - not supported (yet?).") + +cdef $vec ${vdd}FromObj(c.$vec i): + v=$vec() + v.cobj = new c.$vec( i) + return v +EOF +done + + cat < #include @@ -34,6 +36,17 @@ do done echo "$ftype c_minus($ftype a){return -a;};" done +for vec in $vecs +do + setvars $vec + #if [ $vec = "Vector2D" ]; then field=Field2D + #elif [ $vec = "Vector3D" ]; then field=Field2D + #else echo "$vec - Not implemented" ; exit 2 + #fi + cat < Date: Fri, 16 Nov 2018 13:56:12 +0000 Subject: [PATCH 0276/1783] Add test for clobbering datadir from commandline --- tests/integrated/test-command-args/runtest | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/integrated/test-command-args/runtest b/tests/integrated/test-command-args/runtest index 42488c61a0..6cdae132a8 100755 --- a/tests/integrated/test-command-args/runtest +++ b/tests/integrated/test-command-args/runtest @@ -90,6 +90,21 @@ if ! ./command-args -d test 2> stderr.log ; then exit 1 fi +echo +echo "=========== Running with -d arg -f BOUT.settings in test2 directory ==============" +cp -r test test2 + +if ! ./command-args -d test2 -f BOUT.settings -o testsettings > stdout.log 2> stderr.log ; then + cat stderr.log + echo "FAIL: Run fails with '-d test' command-line arg" + exit 1 +fi + +if ! [ "$(grep datadir test2/testsettings )" == "datadir = test2" ] ; then + echo "FAIL: datadir from command line clobbered by BOUT.settings" + exit 1 +fi + echo "=> All passed" exit 0 From 9f0996ea797a39ce45389f86695fb0a2353082a8 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 16 Nov 2018 13:57:20 +0000 Subject: [PATCH 0277/1783] Make test-command-args quieter --- tests/integrated/test-command-args/runtest | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/integrated/test-command-args/runtest b/tests/integrated/test-command-args/runtest index 6cdae132a8..bfae1e583e 100755 --- a/tests/integrated/test-command-args/runtest +++ b/tests/integrated/test-command-args/runtest @@ -9,7 +9,7 @@ rm -rf test # Run without any directory, check that an exception is thrown echo "=========== Running without input directory ==============" -if ./command-args 2> stderr.log; then +if ./command-args > stdout.log 2> stderr.log; then cat stderr.log echo "FAIL: Run should fail when no input directory" exit 1 @@ -28,7 +28,7 @@ echo "=========== Running without args in data directory ==============" mkdir -p data cp BOUT.inp data -./command-args +./command-args > stdout.log 2> stderr.log # Check that we have a BOUT.settings and BOUT.log.0 file @@ -48,7 +48,7 @@ echo "=========== Running with -l arg in data directory ==============" rm -r data mkdir -p data cp BOUT.inp data -./command-args -l different.log +./command-args -l different.log > stdout.log 2> stderr.log if [ -f "data/BOUT.log.0" ] ; then echo "FAIL: BOUT.log.0 file in data directory" @@ -66,7 +66,7 @@ echo "=========== Running with --log arg in data directory ==============" rm -r data mkdir -p data cp BOUT.inp data -./command-args --log log +./command-args --log log > stdout.log 2> stderr.log if [ -f "data/BOUT.log.0" ] ; then echo "FAIL: BOUT.log.0 file in data directory" @@ -84,7 +84,7 @@ rm -r data mkdir -p test cp BOUT.inp test -if ! ./command-args -d test 2> stderr.log ; then +if ! ./command-args -d test > stdout.log 2> stderr.log ; then cat stderr.log echo "FAIL: Run fails with '-d test' command-line arg" exit 1 From 956042f0b09c6885e36d5c4728e847b2630b10b3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 8 Nov 2018 15:26:42 +0000 Subject: [PATCH 0278/1783] Add move constructor for Field3D --- include/field3d.hxx | 4 ++- tests/unit/field/test_field3d.cxx | 41 +++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/include/field3d.hxx b/include/field3d.hxx index 107092b4d9..d9dde36ee0 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -171,7 +171,9 @@ class Field3D : public Field, public FieldData { * Copy constructor */ Field3D(const Field3D& f); - + + /// Move constructor + Field3D(Field3D&& f) noexcept : Field3D() { swap(*this, f); } /// Constructor from 2D field Field3D(const Field2D& f); /// Constructor from value diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 933e99e4b3..898aa4eaaa 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -2026,5 +2026,46 @@ TEST_F(Field3DTest, Swap) { mesh->StaggerGrids = backup; } +TEST_F(Field3DTest, MoveCtor) { + auto backup = mesh->StaggerGrids; + mesh->StaggerGrids = true; + + // First field + Field3D first(1., mesh); + + first.setLocation(CELL_XLOW); + + first.splitYupYdown(); + first.yup() = 1.5; + first.ydown() = 0.5; + + ddt(first) = 1.1; + + // Second field + Field3D second{std::move(first)}; + + // Values + EXPECT_TRUE(IsField3DEqualBoutReal(second, 1.0)); + + EXPECT_TRUE(IsField3DEqualBoutReal(second.yup(), 1.5)); + EXPECT_TRUE(IsField3DEqualBoutReal(second.ydown(), 0.5)); + + EXPECT_TRUE(IsField3DEqualBoutReal(ddt(second), 1.1)); + + // Mesh properties + EXPECT_EQ(second.getMesh(), mesh); + + EXPECT_EQ(second.getNx(), Field3DTest::nx); + EXPECT_EQ(second.getNy(), Field3DTest::ny); + EXPECT_EQ(second.getNz(), Field3DTest::nz); + + EXPECT_EQ(second.getLocation(), CELL_XLOW); + + // We don't check the boundaries, but the data is protected and + // there are no inquiry functions + + mesh->StaggerGrids = backup; +} + // Restore compiler warnings #pragma GCC diagnostic pop From 223e0d290b00255deec06847739d0fda790c8ac5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 8 Nov 2018 15:37:46 +0000 Subject: [PATCH 0279/1783] Add swap function for Field2D --- include/field2d.hxx | 20 +++++++++- tests/unit/field/test_field2d.cxx | 62 +++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/include/field2d.hxx b/include/field2d.hxx index 1b9dde93ac..af7c7268ed 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -235,8 +235,24 @@ class Field2D : public Field, public FieldData { void applyBoundary(const string ®ion, const string &condition); void applyTDerivBoundary() override; void setBoundaryTo(const Field2D &f2d); ///< Copy the boundary region - - private: + + friend void swap(Field2D& first, Field2D& second) noexcept { + using std::swap; + swap(first.data, second.data); + swap(first.fieldmesh, second.fieldmesh); + swap(first.fieldCoordinates, second.fieldCoordinates); + swap(first.nx, second.nx); + swap(first.ny, second.ny); + swap(first.location, second.location); + swap(first.deriv, second.deriv); + swap(first.bndry_op, second.bndry_op); + swap(first.boundaryIsCopy, second.boundaryIsCopy); + swap(first.boundaryIsSet, second.boundaryIsSet); + swap(first.bndry_op_par, second.bndry_op_par); + swap(first.bndry_generator, second.bndry_generator); + } + +private: int nx, ny; ///< Array sizes (from fieldmesh). These are valid only if fieldmesh is not null /// Internal data array. Handles allocation/freeing of memory diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index 1a87816f21..65fa54c167 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -1109,4 +1109,66 @@ TEST_F(Field2DTest, Max) { EXPECT_EQ(max(field, true, RGN_ALL), 99.0); } +TEST_F(Field2DTest, Swap) { + auto backup = mesh->StaggerGrids; + mesh->StaggerGrids = true; + + // First field + Field2D first(1., mesh); + + first.setLocation(CELL_XLOW); + + ddt(first) = 1.1; + + // Mesh for second field + constexpr int second_nx = Field2DTest::nx + 2; + constexpr int second_ny = Field2DTest::ny + 2; + constexpr int second_nz = Field2DTest::nz + 2; + + FakeMesh second_mesh{second_nx, second_ny, second_nz}; + second_mesh.StaggerGrids = false; + output_info.disable(); + second_mesh.createDefaultRegions(); + output_info.enable(); + + // Second field + Field2D second(2., &second_mesh); + + ddt(second) = 2.4; + + // Basic sanity check + EXPECT_TRUE(IsField2DEqualBoutReal(first, 1.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(second, 2.0)); + + // swap is marked noexcept, so absolutely should not throw! + ASSERT_NO_THROW(swap(first, second)); + + // Values + EXPECT_TRUE(IsField2DEqualBoutReal(first, 2.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(second, 1.0)); + + EXPECT_TRUE(IsField2DEqualBoutReal(ddt(first), 2.4)); + EXPECT_TRUE(IsField2DEqualBoutReal(ddt(second), 1.1)); + + // Mesh properties + EXPECT_EQ(first.getMesh(), &second_mesh); + EXPECT_EQ(second.getMesh(), mesh); + + EXPECT_EQ(first.getNx(), second_nx); + EXPECT_EQ(first.getNy(), second_ny); + EXPECT_EQ(first.getNz(), 1); + + EXPECT_EQ(second.getNx(), Field2DTest::nx); + EXPECT_EQ(second.getNy(), Field2DTest::ny); + EXPECT_EQ(second.getNz(), 1); + + EXPECT_EQ(first.getLocation(), CELL_CENTRE); + EXPECT_EQ(second.getLocation(), CELL_XLOW); + + // We don't check the boundaries, but the data is protected and + // there are no inquiry functions + + mesh->StaggerGrids = backup; +} + #pragma GCC diagnostic pop From 9b0bb11335e845ec9c013b11d36b5b167fa29464 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 8 Nov 2018 15:41:58 +0000 Subject: [PATCH 0280/1783] Add move constructor for Field2D --- include/field2d.hxx | 2 +- tests/unit/field/test_field2d.cxx | 34 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/include/field2d.hxx b/include/field2d.hxx index af7c7268ed..6d5a43e1bc 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -74,7 +74,7 @@ class Field2D : public Field, public FieldData { /*! * Move constructor */ - Field2D(Field2D&& f) = default; + Field2D(Field2D&& f) noexcept : Field2D() { swap(*this, f); }; /*! * Constructor. This creates a Field2D using the global Mesh pointer (mesh) diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index 65fa54c167..fb71a1d2d5 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -1171,4 +1171,38 @@ TEST_F(Field2DTest, Swap) { mesh->StaggerGrids = backup; } +TEST_F(Field2DTest, MoveCtor) { + auto backup = mesh->StaggerGrids; + mesh->StaggerGrids = true; + + // First field + Field2D first(1., mesh); + + first.setLocation(CELL_XLOW); + + ddt(first) = 1.1; + + // Second field + Field2D second{std::move(first)}; + + // Values + EXPECT_TRUE(IsField2DEqualBoutReal(second, 1.0)); + + EXPECT_TRUE(IsField2DEqualBoutReal(ddt(second), 1.1)); + + // Mesh properties + EXPECT_EQ(second.getMesh(), mesh); + + EXPECT_EQ(second.getNx(), Field2DTest::nx); + EXPECT_EQ(second.getNy(), Field2DTest::ny); + EXPECT_EQ(second.getNz(), 1); + + EXPECT_EQ(second.getLocation(), CELL_XLOW); + + // We don't check the boundaries, but the data is protected and + // there are no inquiry functions + + mesh->StaggerGrids = backup; +} + #pragma GCC diagnostic pop From 20845668d0cd0811634bc6b7ac49776e742ec9af Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 19 Nov 2018 13:00:09 +0000 Subject: [PATCH 0281/1783] Default initialise some Field3D/2D members --- include/field2d.hxx | 4 ++-- include/field3d.hxx | 8 ++++---- src/field/field2d.cxx | 24 +++++++++++------------- src/field/field3d.cxx | 21 ++++++--------------- 4 files changed, 23 insertions(+), 34 deletions(-) diff --git a/include/field2d.hxx b/include/field2d.hxx index 6d5a43e1bc..545cb73881 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -74,7 +74,7 @@ class Field2D : public Field, public FieldData { /*! * Move constructor */ - Field2D(Field2D&& f) noexcept : Field2D() { swap(*this, f); }; + Field2D(Field2D&& f) noexcept { swap(*this, f); }; /*! * Constructor. This creates a Field2D using the global Mesh pointer (mesh) @@ -260,7 +260,7 @@ private: CELL_LOC location = CELL_CENTRE; ///< Location of the variable in the cell - Field2D *deriv; ///< Time-derivative, can be NULL + Field2D *deriv{nullptr}; ///< Time-derivative, can be NULL }; // Non-member overloaded operators diff --git a/include/field3d.hxx b/include/field3d.hxx index d9dde36ee0..c8ec9db94d 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -173,7 +173,7 @@ class Field3D : public Field, public FieldData { Field3D(const Field3D& f); /// Move constructor - Field3D(Field3D&& f) noexcept : Field3D() { swap(*this, f); } + Field3D(Field3D&& f) noexcept { swap(*this, f); } /// Constructor from 2D field Field3D(const Field2D& f); /// Constructor from value @@ -468,7 +468,7 @@ class Field3D : public Field, public FieldData { private: /// Boundary - add a 2D field - const Field2D *background; + const Field2D *background{nullptr}; int nx, ny, nz; ///< Array sizes (from fieldmesh). These are valid only if fieldmesh is not null @@ -477,10 +477,10 @@ private: CELL_LOC location = CELL_CENTRE; ///< Location of the variable in the cell - Field3D *deriv; ///< Time derivative (may be NULL) + Field3D *deriv{nullptr}; ///< Time derivative (may be NULL) /// Pointers to fields containing values along Y - Field3D *yup_field, *ydown_field; + Field3D *yup_field{nullptr}, *ydown_field{nullptr}; }; // Non-member overloaded operators diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index a675039078..e909a3f15f 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -45,18 +45,18 @@ #include -Field2D::Field2D(Mesh *localmesh) : Field(localmesh), deriv(nullptr) { +Field2D::Field2D(Mesh* localmesh) : Field(localmesh) { boundaryIsSet = false; - if(fieldmesh) { + if (fieldmesh) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; } #if CHECK > 0 else { - nx=-1; - ny=-1; + nx = -1; + ny = -1; } #endif @@ -65,9 +65,7 @@ Field2D::Field2D(Mesh *localmesh) : Field(localmesh), deriv(nullptr) { #endif } -Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), // The mesh containing array sizes - data(f.data), // This handles references to the data array - deriv(nullptr) { +Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), data(f.data) { TRACE("Field2D(Field2D&)"); #ifdef TRACK @@ -77,25 +75,25 @@ Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), // The mesh containing #if CHECK > 2 checkData(f); #endif - - if(fieldmesh) { + + if (fieldmesh) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; } #if CHECK > 0 else { - nx=-1; - ny=-1; + nx = -1; + ny = -1; } #endif location = f.location; fieldCoordinates = f.fieldCoordinates; - + boundaryIsSet = false; } -Field2D::Field2D(BoutReal val, Mesh *localmesh) : Field(localmesh), deriv(nullptr) { +Field2D::Field2D(BoutReal val, Mesh* localmesh) : Field(localmesh) { boundaryIsSet = false; nx = fieldmesh->LocalNx; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 7d9dda7cea..d321b46bda 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -44,9 +44,7 @@ #include /// Constructor -Field3D::Field3D(Mesh *localmesh) - : Field(localmesh), background(nullptr), deriv(nullptr), yup_field(nullptr), - ydown_field(nullptr) { +Field3D::Field3D(Mesh* localmesh) : Field(localmesh) { #ifdef TRACK name = ""; #endif @@ -69,10 +67,7 @@ Field3D::Field3D(Mesh *localmesh) /// Doesn't copy any data, just create a new reference to the same data (copy on change /// later) -Field3D::Field3D(const Field3D &f) - : Field(f.fieldmesh), // The mesh containing array sizes - background(nullptr), data(f.data), // This handles references to the data array - deriv(nullptr), yup_field(nullptr), ydown_field(nullptr) { +Field3D::Field3D(const Field3D& f) : Field(f.fieldmesh), data(f.data) { TRACE("Field3D(Field3D&)"); @@ -95,13 +90,11 @@ Field3D::Field3D(const Field3D &f) location = f.location; fieldCoordinates = f.fieldCoordinates; - + boundaryIsSet = false; } -Field3D::Field3D(const Field2D &f) - : Field(f.getMesh()), background(nullptr), deriv(nullptr), yup_field(nullptr), - ydown_field(nullptr) { +Field3D::Field3D(const Field2D& f) : Field(f.getMesh()) { TRACE("Field3D: Copy constructor from Field2D"); @@ -113,13 +106,11 @@ Field3D::Field3D(const Field2D &f) location = f.getLocation(); fieldCoordinates = nullptr; - + *this = f; } -Field3D::Field3D(const BoutReal val, Mesh *localmesh) - : Field(localmesh), background(nullptr), deriv(nullptr), yup_field(nullptr), - ydown_field(nullptr) { +Field3D::Field3D(const BoutReal val, Mesh* localmesh) : Field(localmesh) { TRACE("Field3D: Copy constructor from value"); From f60cefefb719c8aa015eddb922e28345a7ff4a41 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 19 Nov 2018 13:27:08 +0000 Subject: [PATCH 0282/1783] Default initialise boundaryIs{Copy,Set} in FieldData NOTE: changes default value of `boundaryIsSet` from `true` to `false`. Shouldn't affect anything though as child classes all immediately set it to `false` in their ctors --- include/field.hxx | 6 +++--- include/field_data.hxx | 6 +++--- src/field/field.cxx | 4 ++-- src/field/field2d.cxx | 6 ------ src/field/field3d.cxx | 8 -------- src/field/field_data.cxx | 4 ---- 6 files changed, 8 insertions(+), 26 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index 0fa26f3c52..200c1e7fc8 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -115,9 +115,9 @@ class Field { */ virtual int getNz() const; - protected: - Mesh * fieldmesh; - mutable Coordinates * fieldCoordinates = nullptr; +protected: + Mesh* fieldmesh{nullptr}; + mutable Coordinates* fieldCoordinates{nullptr}; }; /// Unary + operator. This doesn't do anything diff --git a/include/field_data.hxx b/include/field_data.hxx index c4fadd4e95..566d23eff2 100644 --- a/include/field_data.hxx +++ b/include/field_data.hxx @@ -62,7 +62,7 @@ class FieldVisitor; */ class FieldData { public: - FieldData(); + FieldData() = default; virtual ~FieldData(); // Visitor pattern support @@ -93,8 +93,8 @@ public: protected: vector bndry_op; ///< Boundary conditions - bool boundaryIsCopy; ///< True if bndry_op is a copy - bool boundaryIsSet; ///< Set to true when setBoundary called + bool boundaryIsCopy{false}; ///< True if bndry_op is a copy + bool boundaryIsSet{false}; ///< Set to true when setBoundary called // Parallel boundaries vector bndry_op_par; ///< Boundary conditions diff --git a/src/field/field.cxx b/src/field/field.cxx index dfef4ce140..7d47545783 100644 --- a/src/field/field.cxx +++ b/src/field/field.cxx @@ -34,13 +34,13 @@ #include #include -Field::Field() : fieldmesh(nullptr), fieldCoordinates(nullptr) { +Field::Field() { #if CHECK > 0 bndry_xin = bndry_xout = bndry_yup = bndry_ydown = true; #endif } -Field::Field(Mesh *localmesh) : fieldmesh(localmesh), fieldCoordinates(nullptr) { +Field::Field(Mesh *localmesh) : fieldmesh(localmesh) { if (fieldmesh == nullptr) { fieldmesh = mesh; } diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index e909a3f15f..f7270fc5a4 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -47,8 +47,6 @@ Field2D::Field2D(Mesh* localmesh) : Field(localmesh) { - boundaryIsSet = false; - if (fieldmesh) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; @@ -89,13 +87,9 @@ Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), data(f.data) { location = f.location; fieldCoordinates = f.fieldCoordinates; - - boundaryIsSet = false; } Field2D::Field2D(BoutReal val, Mesh* localmesh) : Field(localmesh) { - boundaryIsSet = false; - nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index d321b46bda..adf7609832 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -61,8 +61,6 @@ Field3D::Field3D(Mesh* localmesh) : Field(localmesh) { nz = -1; } #endif - - boundaryIsSet = false; } /// Doesn't copy any data, just create a new reference to the same data (copy on change @@ -90,16 +88,12 @@ Field3D::Field3D(const Field3D& f) : Field(f.fieldmesh), data(f.data) { location = f.location; fieldCoordinates = f.fieldCoordinates; - - boundaryIsSet = false; } Field3D::Field3D(const Field2D& f) : Field(f.getMesh()) { TRACE("Field3D: Copy constructor from Field2D"); - boundaryIsSet = false; - nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; @@ -114,8 +108,6 @@ Field3D::Field3D(const BoutReal val, Mesh* localmesh) : Field(localmesh) { TRACE("Field3D: Copy constructor from value"); - boundaryIsSet = false; - nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 6ab19709c7..6854d7a266 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -6,10 +6,6 @@ #include #include "unused.hxx" -FieldData::FieldData() : boundaryIsCopy(false), boundaryIsSet(true) { - -} - FieldData::~FieldData() { if(!boundaryIsCopy) { // Delete the boundary operations From 4269b325454398fd2acb02e4b100fe4e5c8835eb Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 19 Nov 2018 13:40:42 +0000 Subject: [PATCH 0283/1783] Default initialise field sizes and Field::bndry* status Allows removing `#if CHECK > 0` bracketed code from ctors --- include/field.hxx | 7 ++++--- include/field2d.hxx | 5 +++-- include/field3d.hxx | 5 +++-- include/fieldperp.hxx | 7 ++++--- src/field/field.cxx | 10 ---------- src/field/field2d.cxx | 12 ------------ src/field/field3d.cxx | 14 -------------- src/field/fieldperp.cxx | 7 ------- 8 files changed, 14 insertions(+), 53 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index 200c1e7fc8..80861ffd91 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -53,7 +53,7 @@ extern Mesh * mesh; ///< Global mesh */ class Field { public: - Field(); + Field() = default; Field(Mesh * localmesh); virtual ~Field() { } @@ -82,9 +82,10 @@ class Field { return true; } - // Status of the 4 boundaries - bool bndry_xin, bndry_xout, bndry_yup, bndry_ydown; + /// Status of the 4 boundaries + bool bndry_xin{true}, bndry_xout{true}, bndry_yup{true}, bndry_ydown{true}; #endif + virtual Mesh * getMesh() const{ if (fieldmesh){ return fieldmesh; diff --git a/include/field2d.hxx b/include/field2d.hxx index 545cb73881..92d2751bec 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -253,8 +253,9 @@ class Field2D : public Field, public FieldData { } private: - int nx, ny; ///< Array sizes (from fieldmesh). These are valid only if fieldmesh is not null - + /// Array sizes (from fieldmesh). These are valid only if fieldmesh is not null + int nx{-1}, ny{-1}; + /// Internal data array. Handles allocation/freeing of memory Array data; diff --git a/include/field3d.hxx b/include/field3d.hxx index c8ec9db94d..d14b23aad1 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -470,8 +470,9 @@ private: /// Boundary - add a 2D field const Field2D *background{nullptr}; - int nx, ny, nz; ///< Array sizes (from fieldmesh). These are valid only if fieldmesh is not null - + /// Array sizes (from fieldmesh). These are valid only if fieldmesh is not null + int nx{-1}, ny{-1}, nz{-1}; + /// Internal data array. Handles allocation/freeing of memory Array data; diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index a587ce0ad9..20dd0e3a60 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -242,11 +242,12 @@ class FieldPerp : public Field { */ int getNz() const override {return nz;}; - private: - int yindex = -1; ///< The Y index at which this FieldPerp is defined +private: + /// The Y index at which this FieldPerp is defined + int yindex{-1}; /// The size of the data array - int nx, nz; + int nx{-1}, nz{-1}; /// The underlying data array Array data; diff --git a/src/field/field.cxx b/src/field/field.cxx index 7d47545783..4ed8e8273d 100644 --- a/src/field/field.cxx +++ b/src/field/field.cxx @@ -34,12 +34,6 @@ #include #include -Field::Field() { -#if CHECK > 0 - bndry_xin = bndry_xout = bndry_yup = bndry_ydown = true; -#endif -} - Field::Field(Mesh *localmesh) : fieldmesh(localmesh) { if (fieldmesh == nullptr) { fieldmesh = mesh; @@ -50,10 +44,6 @@ Field::Field(Mesh *localmesh) : fieldmesh(localmesh) { // call fieldmesh->coordinates, which would create fields, which would then call // getCoordinates again etc.). This also requires care in the derived class // constructors. - -#if CHECK > 0 - bndry_xin = bndry_xout = bndry_yup = bndry_ydown = true; -#endif } Coordinates *Field::getCoordinates() const { diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index f7270fc5a4..bf0cde131d 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -51,12 +51,6 @@ Field2D::Field2D(Mesh* localmesh) : Field(localmesh) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; } -#if CHECK > 0 - else { - nx = -1; - ny = -1; - } -#endif #ifdef TRACK name = ""; @@ -78,12 +72,6 @@ Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), data(f.data) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; } -#if CHECK > 0 - else { - nx = -1; - ny = -1; - } -#endif location = f.location; fieldCoordinates = f.fieldCoordinates; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index adf7609832..d0cea3e02e 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -54,13 +54,6 @@ Field3D::Field3D(Mesh* localmesh) : Field(localmesh) { ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; } -#if CHECK > 0 - else { - nx = -1; - ny = -1; - nz = -1; - } -#endif } /// Doesn't copy any data, just create a new reference to the same data (copy on change @@ -78,13 +71,6 @@ Field3D::Field3D(const Field3D& f) : Field(f.fieldmesh), data(f.data) { ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; } -#if CHECK > 0 - else { - nx = -1; - ny = -1; - nz = -1; - } -#endif location = f.location; fieldCoordinates = f.fieldCoordinates; diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index ad7c2ad8d2..f1de283f8e 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -39,13 +39,6 @@ FieldPerp::FieldPerp(Mesh *localmesh) : Field(localmesh) { nx = fieldmesh->LocalNx; nz = fieldmesh->LocalNz; } - -#if CHECK > 0 - else { - nx=-1; - nz=-1; - } -#endif } FieldPerp::FieldPerp(BoutReal val, Mesh *localmesh) : Field(localmesh) { From b00563980cc1117ad0831bbaa4bb374bd2603840 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 19 Nov 2018 14:30:55 +0000 Subject: [PATCH 0284/1783] Use `Options::force` to overwrite options quietly --- src/bout++.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index b223d06b8e..2500672e6b 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -424,9 +424,9 @@ int BoutInitialise(int &argc, char **&argv) { reader->parseCommandLine(options, argc, argv); // Override options set from short option from the command-line - Options::root()["datadir"] = data_dir; - Options::root()["optionfile"] = opt_file; - Options::root()["settingsfile"] = set_file; + Options::root()["datadir"].force(data_dir); + Options::root()["optionfile"].force(opt_file); + Options::root()["settingsfile"].force(set_file); // Put some run information in the options. // This is mainly so it can be easily read in post-processing From 4912abac93657369912dcd8ddacb6ef5cd442c1a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 16 Nov 2018 17:44:22 +0000 Subject: [PATCH 0285/1783] Replace bash test with python version Uses standard lib unittest --- tests/integrated/test-command-args/runtest | 186 +++++++++------------ 1 file changed, 76 insertions(+), 110 deletions(-) diff --git a/tests/integrated/test-command-args/runtest b/tests/integrated/test-command-args/runtest index bfae1e583e..1eaff1c124 100755 --- a/tests/integrated/test-command-args/runtest +++ b/tests/integrated/test-command-args/runtest @@ -1,110 +1,76 @@ -#!/bin/bash - -# Compile command-args -make || exit 1 - -# Remove directories which may be left from previous run -rm -rf data -rm -rf test - -# Run without any directory, check that an exception is thrown -echo "=========== Running without input directory ==============" -if ./command-args > stdout.log 2> stderr.log; then - cat stderr.log - echo "FAIL: Run should fail when no input directory" - exit 1 -fi - -# Check that an error message was output -if ! grep "\"data\" does not exist" stderr.log > output.log ; then - cat stderr.log - echo "FAIL: Error message not printed when missing input directory" - exit 1 -fi - -# Run tests in "data" directory -echo -echo "=========== Running without args in data directory ==============" - -mkdir -p data -cp BOUT.inp data -./command-args > stdout.log 2> stderr.log - -# Check that we have a BOUT.settings and BOUT.log.0 file - -if ! [ -f "data/BOUT.settings" ] ; then - echo "FAIL: No BOUT.settings file in data directory" - exit 1 -fi - -if ! [ -f "data/BOUT.log.0" ] ; then - echo "FAIL: No BOUT.log.0 file in data directory" - exit 1 -fi - -# Change the log file name -echo -echo "=========== Running with -l arg in data directory ==============" -rm -r data -mkdir -p data -cp BOUT.inp data -./command-args -l different.log > stdout.log 2> stderr.log - -if [ -f "data/BOUT.log.0" ] ; then - echo "FAIL: BOUT.log.0 file in data directory" - exit 1 -fi - -if ! [ -f "data/different.log.0" ] ; then - echo "FAIL: no different.log.0 file in data directory" - exit 1 -fi - -# Change the log file name using long option -echo -echo "=========== Running with --log arg in data directory ==============" -rm -r data -mkdir -p data -cp BOUT.inp data -./command-args --log log > stdout.log 2> stderr.log - -if [ -f "data/BOUT.log.0" ] ; then - echo "FAIL: BOUT.log.0 file in data directory" - exit 1 -fi - -if ! [ -f "data/log.0" ] ; then - echo "FAIL: no log.0 file in data directory" - exit 1 -fi - -echo -echo "=========== Running with -d arg in test directory ==============" -rm -r data -mkdir -p test -cp BOUT.inp test - -if ! ./command-args -d test > stdout.log 2> stderr.log ; then - cat stderr.log - echo "FAIL: Run fails with '-d test' command-line arg" - exit 1 -fi - -echo -echo "=========== Running with -d arg -f BOUT.settings in test2 directory ==============" -cp -r test test2 - -if ! ./command-args -d test2 -f BOUT.settings -o testsettings > stdout.log 2> stderr.log ; then - cat stderr.log - echo "FAIL: Run fails with '-d test' command-line arg" - exit 1 -fi - -if ! [ "$(grep datadir test2/testsettings )" == "datadir = test2" ] ; then - echo "FAIL: datadir from command line clobbered by BOUT.settings" - exit 1 -fi - -echo "=> All passed" - -exit 0 +#!/usr/bin/env python3 +from boututils.run_wrapper import shell_safe + +import os +import shutil +import unittest + + +class TestCommandLineArgs(unittest.TestCase): + command = "./command-args 2>stderr.log" + + def makeDirAndCopyInput(self, path): + os.mkdir(path) + shutil.copy("BOUT.inp", path) + + def setUp(self): + os.remove("stderr.log") + shutil.rmtree("./data", ignore_errors=True) + shutil.rmtree("./test", ignore_errors=True) + shutil.rmtree("./test_copy", ignore_errors=True) + + def testNoArgumentsNoDirectory(self): + with self.assertRaises(RuntimeError): + shell_safe(self.command, pipe=True) + with open("stderr.log") as f: + contents = f.read() + self.assertIn('"data" does not exist', contents, + msg="FAIL: Error message not printed when missing input directory") + + def testNoArgumentsDefaultDirectory(self): + self.makeDirAndCopyInput("data") + shell_safe(self.command, pipe=True) + self.assertTrue(os.path.exists("data/BOUT.settings"), + msg="FAIL: No BOUT.settings file in data directory") + self.assertTrue(os.path.exists("data/BOUT.log.0"), + msg="FAIL: No BOUT.log.0 file in data directory") + + def testShortLogArgument(self): + self.makeDirAndCopyInput("data") + shell_safe(self.command + " -l different.log", pipe=True) + self.assertFalse(os.path.exists("data/BOUT.log.0"), + msg="FAIL: BOUT.log.0 file in data directory") + self.assertTrue(os.path.exists("data/different.log.0"), + msg="FAIL: no different.log.0 file in data directory") + + def testLongLogArgument(self): + self.makeDirAndCopyInput("data") + shell_safe(self.command + " --log log", pipe=True) + self.assertFalse(os.path.exists("data/BOUT.log.0"), + msg="FAIL: BOUT.log.0 file in data directory") + self.assertTrue(os.path.exists("data/log.0"), + msg="FAIL: no log.0 file in data directory") + + def testDirectoryArgument(self): + self.makeDirAndCopyInput("test") + shell_safe(self.command + " -d test", pipe=True) + self.assertTrue(os.path.exists("test/BOUT.settings"), + msg="FAIL: No BOUT.settings file in test directory") + self.assertTrue(os.path.exists("test/BOUT.log.0"), + msg="FAIL: No BOUT.log.0 file in data directory") + + def testDirectoryArgumentOldSettingsFile(self): + self.makeDirAndCopyInput("test") + shell_safe(self.command + " -d test", pipe=True) + shutil.copytree("test", "test_copy") + shell_safe(self.command + " -d test_copy -f BOUT.settings -o testsettings", pipe=True) + + with open("test_copy/testsettings") as f: + contents = f.read() + self.assertIn("datadir = test_copy", contents, + msg="FAIL: datadir from command line clobbered by BOUT.settings") + + +if __name__ == "__main__": + shell_safe("make") + unittest.main(verbosity=2) From 2410aad43ce737499faafe7f4630f74b312f5b2e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 19 Nov 2018 17:23:10 +0000 Subject: [PATCH 0286/1783] Don't complain if stderr.log doesn't exist; add tearDown --- tests/integrated/test-command-args/runtest | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/integrated/test-command-args/runtest b/tests/integrated/test-command-args/runtest index 1eaff1c124..cb82db78dd 100755 --- a/tests/integrated/test-command-args/runtest +++ b/tests/integrated/test-command-args/runtest @@ -14,11 +14,17 @@ class TestCommandLineArgs(unittest.TestCase): shutil.copy("BOUT.inp", path) def setUp(self): - os.remove("stderr.log") + try: + os.remove("stderr.log") + except OSError: + pass shutil.rmtree("./data", ignore_errors=True) shutil.rmtree("./test", ignore_errors=True) shutil.rmtree("./test_copy", ignore_errors=True) + # Teardown same as setup in case something went wrong with last run + tearDown = setUp + def testNoArgumentsNoDirectory(self): with self.assertRaises(RuntimeError): shell_safe(self.command, pipe=True) From 91ca12b9f9a8b2fabb3e04361fbeed53781c41d4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 19 Nov 2018 17:24:00 +0000 Subject: [PATCH 0287/1783] Don't print whole settings file if test fails --- tests/integrated/test-command-args/runtest | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/integrated/test-command-args/runtest b/tests/integrated/test-command-args/runtest index cb82db78dd..564fcf7725 100755 --- a/tests/integrated/test-command-args/runtest +++ b/tests/integrated/test-command-args/runtest @@ -72,8 +72,16 @@ class TestCommandLineArgs(unittest.TestCase): shell_safe(self.command + " -d test_copy -f BOUT.settings -o testsettings", pipe=True) with open("test_copy/testsettings") as f: - contents = f.read() - self.assertIn("datadir = test_copy", contents, + contents = f.readlines() + + datadir = "" + for line in contents: + if line.startswith("datadir"): + # Assuming that this line looks like "datadir = # comment" + datadir = line.split()[2] + break + + self.assertIn("test_copy", datadir, msg="FAIL: datadir from command line clobbered by BOUT.settings") From ba4275176ff3907fac77431573653dc7d402d934 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 19 Nov 2018 17:55:23 +0000 Subject: [PATCH 0288/1783] Improve some comments; use uniform initialisation more consistently --- include/bout/array.hxx | 33 +++++++++++++++++---------------- include/field2d.hxx | 6 ++++-- include/field3d.hxx | 6 ++++-- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/include/bout/array.hxx b/include/bout/array.hxx index 3c95f55016..3da8349fed 100644 --- a/include/bout/array.hxx +++ b/include/bout/array.hxx @@ -172,8 +172,9 @@ public: if(!ptr) return 0; #ifdef BOUT_ARRAY_WITH_VALARRAY - // Note: std::valarray::size is not noexcept, so Array::size - // shouldn't be either if we're using valarrays + // Note: std::valarray::size is technically not noexcept, so + // Array::size shouldn't be either if we're using valarrays -- in + // practice, it is so this shouldn't matter return ptr->size(); #else return ptr->len; @@ -394,16 +395,17 @@ private: st.pop_back(); } else { // Ensure that when we release the data block later we'll have - // enough space to put it in the store + // enough space to put it in the store so that `release` can be + // noexcept st.reserve(1); p = std::make_shared(len); } return p; } - + /*! - * Release an ArrayData object, reducing its reference count by one. + * Release an ArrayData object, reducing its reference count by one. * If no more references, then put back into the store. * It's important to pass a reference to the pointer, otherwise we get * a copy of the shared_ptr, which therefore increases the use count @@ -414,27 +416,26 @@ private: * one data block. Of course, store() could throw -- in which case * we're doomed anyway, so the only thing we can do is abort */ - void release(dataPtrType &d) noexcept { + void release(dataPtrType& d) noexcept { if (!d) return; - + // Reduce reference count, and if zero return to store - if(d.use_count()==1) { + if (d.use_count() == 1) { if (useStore()) { - // Put back into store + // Put back into store #ifdef BOUT_ARRAY_WITH_VALARRAY - store()[d->size()].push_back(std::move(d)); -#else - store()[d->len ].push_back(std::move(d)); + store()[d->size()].push_back(std::move(d)); +#else + store()[d->len].push_back(std::move(d)); #endif - //Could return here but seems to slow things down a lot + // Could return here but seems to slow things down a lot } } - //Finish by setting pointer to nullptr if not putting on store - d=nullptr; + // Finish by setting pointer to nullptr if not putting on store + d = nullptr; } - }; /*! diff --git a/include/field2d.hxx b/include/field2d.hxx index 92d2751bec..68c0d3af63 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -259,9 +259,11 @@ private: /// Internal data array. Handles allocation/freeing of memory Array data; - CELL_LOC location = CELL_CENTRE; ///< Location of the variable in the cell + /// Location of the variable in the cell + CELL_LOC location{CELL_CENTRE}; - Field2D *deriv{nullptr}; ///< Time-derivative, can be NULL + /// Time-derivative, can be nullptr + Field2D *deriv{nullptr}; }; // Non-member overloaded operators diff --git a/include/field3d.hxx b/include/field3d.hxx index d14b23aad1..0033c6c034 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -476,9 +476,11 @@ private: /// Internal data array. Handles allocation/freeing of memory Array data; - CELL_LOC location = CELL_CENTRE; ///< Location of the variable in the cell + /// Location of the variable in the cell + CELL_LOC location{CELL_CENTRE}; - Field3D *deriv{nullptr}; ///< Time derivative (may be NULL) + /// Time derivative (may be nullptr) + Field3D *deriv{nullptr}; /// Pointers to fields containing values along Y Field3D *yup_field{nullptr}, *ydown_field{nullptr}; From a45bc40618b36bdd4ea5ea256d85b77fe14234a3 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 19 Nov 2018 19:34:53 +0000 Subject: [PATCH 0289/1783] Bug fix -- header signature for Vpar_Grad_par(Field2D, Field2D) didn't match implementation as missing CELL_LOC --- include/difops.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/difops.hxx b/include/difops.hxx index 52caf84bc5..02f4c9718b 100644 --- a/include/difops.hxx +++ b/include/difops.hxx @@ -79,7 +79,7 @@ const Field3D Grad_parP(const Field3D &apar, const Field3D &f); * @param[in] f The scalar field to be differentiated * */ -const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f); +const Field2D Vpar_Grad_par(const Field2D &v, const Field2D &f, CELL_LOC outloc=CELL_DEFAULT); /*! * vpar times parallel derivative along unperturbed B-field (upwinding) From cd7bc7a53282c24a5e93858cca26e2e25abcd534 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 19 Nov 2018 19:35:07 +0000 Subject: [PATCH 0290/1783] Update many examples so they compile --- examples/2Dturbulence_multigrid/esel.cxx | 2 +- examples/6field-simple/elm_6f.cxx | 27 ++-------- examples/advdiff/advdiff.cxx | 2 +- examples/advdiff2/init.cxx | 4 +- examples/conducting-wall-mode/cwm.cxx | 4 +- examples/dalf3/dalf3.cxx | 2 +- examples/elm-pb/elm_pb.cxx | 12 ++--- examples/em-drift/2fluid.cxx | 4 +- examples/fci-wave-logn/fci-wave.cxx | 8 +-- examples/fci-wave/fci-wave.cxx | 8 +-- examples/gravity_reduced/gravity_reduced.cxx | 2 +- examples/gyro-gem/gem.cxx | 2 +- examples/jorek-compare/jorek_compare.cxx | 4 +- examples/lapd-drift/lapd_drift.cxx | 14 ++--- examples/non-local_1d/cubic_spline_local.hxx | 1 + examples/reconnect-2field/2field.cxx | 2 +- examples/shear-alfven-wave/2fluid.cxx | 2 +- examples/subsampling/monitor.cxx | 5 +- examples/uedge-benchmark/ue_bmark.cxx | 55 ++++++++++---------- examples/wave-slab/wave_slab.cxx | 37 ++++++------- 20 files changed, 89 insertions(+), 108 deletions(-) diff --git a/examples/2Dturbulence_multigrid/esel.cxx b/examples/2Dturbulence_multigrid/esel.cxx index 6e9d481094..a2af1225a0 100644 --- a/examples/2Dturbulence_multigrid/esel.cxx +++ b/examples/2Dturbulence_multigrid/esel.cxx @@ -69,7 +69,7 @@ class ESEL : public PhysicsModel { return 1; } - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); // generate coordinate system // coord->J = R0/B0 ; diff --git a/examples/6field-simple/elm_6f.cxx b/examples/6field-simple/elm_6f.cxx index 96b1413296..5c6c1ea7fa 100644 --- a/examples/6field-simple/elm_6f.cxx +++ b/examples/6field-simple/elm_6f.cxx @@ -247,27 +247,6 @@ const Field2D N0tanh(BoutReal n0_height, BoutReal n0_ave, BoutReal n0_width, Bou const Field3D field_larger(const Field3D &f, const BoutReal limit); -const Field2D Invert_laplace2(const Field2D &f, int flags) { - Field3D f_tmp, result_tmp; - Field2D result; - f_tmp.allocate(); - result_tmp.allocate(); - result.allocate(); - - f_tmp = f; - - result_tmp = invert_laplace(f_tmp, flags, NULL); - mesh->communicate(result_tmp); - result_tmp = smooth_x(result_tmp); - result_tmp = nl_filter_y(result_tmp, 1); - - for(auto i : result) { - result[i] = result_tmp[i]; - } - - return(result); -} - const Field3D field_larger(const Field3D &f, const BoutReal limit) { Field3D result; result.allocate(); @@ -356,7 +335,7 @@ int physics_init(bool restarting) { bool noshear; // Get the metric tensor - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); output.write("Solving high-beta flute reduced equations\n"); output.write("\tFile : %s\n", __FILE__); @@ -1174,7 +1153,7 @@ const Field3D Grad_parP(const Field3D &f, CELL_LOC loc = CELL_DEFAULT) { fp = interpolate(f, Xip_x, Xip_z); fm = interpolate(f, Xim_x, Xim_z); - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); result.allocate(); for(auto i : result) { @@ -1204,7 +1183,7 @@ bool first_run = true; // For printing out some diagnostics first time around int physics_run(BoutReal t) { - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); // Perform communications mesh->communicate(comms); diff --git a/examples/advdiff/advdiff.cxx b/examples/advdiff/advdiff.cxx index a748e2e2d2..d320e2bde6 100644 --- a/examples/advdiff/advdiff.cxx +++ b/examples/advdiff/advdiff.cxx @@ -19,7 +19,7 @@ class AdvDiff : public PhysicsModel { // Read initial conditions - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); mesh->get(V0, "V0"); mesh->get(coord->dx, "dx"); diff --git a/examples/advdiff2/init.cxx b/examples/advdiff2/init.cxx index 22c3bdae56..efa2cd5c83 100644 --- a/examples/advdiff2/init.cxx +++ b/examples/advdiff2/init.cxx @@ -13,8 +13,8 @@ int physics_init(bool restarting) // Read initial conditions mesh->get(V0, "V0"); - mesh->get(mesh->dx, "dx"); - mesh->get(mesh->dy, "dy"); + mesh->get(mesh->getCoordinates()->dx, "dx"); + mesh->get(mesh->getCoordinates()->dy, "dy"); // read options diff --git a/examples/conducting-wall-mode/cwm.cxx b/examples/conducting-wall-mode/cwm.cxx index 915e0c7b5c..a88b15f9cf 100644 --- a/examples/conducting-wall-mode/cwm.cxx +++ b/examples/conducting-wall-mode/cwm.cxx @@ -76,7 +76,7 @@ class CWM : public PhysicsModel { mesh->get(rho0, "rho0"); mesh->get(Ajpar0, "Ajpar0"); - coord = mesh->coordinates(); + coord = mesh->getCoordinates(); // Load magnetic curvature term b0xcv.covariant = false; // Read contravariant components @@ -245,7 +245,7 @@ class CWM : public PhysicsModel { // Time derivatives calculated here int rhs(BoutReal t) { - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); // Invert vorticity to get phi diff --git a/examples/dalf3/dalf3.cxx b/examples/dalf3/dalf3.cxx index d5c2fda6b5..3609486a94 100644 --- a/examples/dalf3/dalf3.cxx +++ b/examples/dalf3/dalf3.cxx @@ -166,7 +166,7 @@ class DALF3 : public PhysicsModel { return 1; } - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); // SHIFTED RADIAL COORDINATES diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index 8677dab4a8..abecb78e80 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -240,11 +240,11 @@ const Field2D N0tanh(BoutReal n0_height, BoutReal n0_ave, BoutReal n0_width, Bou //output.write("Jysep2_2 = %i Ixsep1 = %i\n", int(Jysep2), int(Jxsep)); for(auto i : result) { - BoutReal mgx = mesh->GlobalX(i.x); + BoutReal mgx = mesh->GlobalX(i.x()); BoutReal xgrid_num = (Jxsep+1.)/Grid_NX; //output.write("mgx = %e xgrid_num = %e\n", mgx); - int globaly = mesh->YGLOBAL(i.y); + int globaly = mesh->YGLOBAL(i.y()); //output.write("local y = %i; global y: %i\n", i.y, globaly); if ( mgx > xgrid_num || (globaly<=int(Jysep)-4) || (globaly>int(Jysep2)) ) mgx = xgrid_num; @@ -255,7 +255,7 @@ const Field2D N0tanh(BoutReal n0_height, BoutReal n0_ave, BoutReal n0_width, Bou } } else { //circular geometry for(auto i : result) { - BoutReal mgx = mesh->GlobalX(i.x); + BoutReal mgx = mesh->GlobalX(i.x()); BoutReal xgrid_num = Grid_NXlimit/Grid_NX; if (mgx > xgrid_num) mgx = xgrid_num; @@ -290,7 +290,7 @@ const Field3D Grad2_par2new(const Field3D &f) { int physics_init(bool restarting) { bool noshear; - Coordinates *metric = mesh->coordinates(); + Coordinates *metric = mesh->getCoordinates(); output.write("Solving high-beta flute reduced equations\n"); output.write("\tFile : %s\n", __FILE__); @@ -576,7 +576,7 @@ int physics_init(bool restarting) { for(int jy=0;jyLocalNy;jy++) for(int jz=0;jzLocalNz;jz++) { - BoutReal angle = rmp_m * pol_angle(jx,jy) + rmp_n * ((BoutReal) jz) * mesh->coordinates()->dz; + BoutReal angle = rmp_m * pol_angle(jx,jy) + rmp_n * ((BoutReal) jz) * mesh->getCoordinates()->dz; rmp_Psi0(jx,jy,jz) = (((BoutReal)(jx - 4)) / ((BoutReal)(mesh->LocalNx - 5))) * rmp_factor * cos(angle); if(rmp_polwid > 0.0) { // Multiply by a Gaussian in poloidal angle @@ -1093,7 +1093,7 @@ int physics_run(BoutReal t) { // Perform communications mesh->communicate(comms); - Coordinates *metric = mesh->coordinates(); + Coordinates *metric = mesh->getCoordinates(); //////////////////////////////////////////// // Transitions from 0 in core to 1 in vacuum diff --git a/examples/em-drift/2fluid.cxx b/examples/em-drift/2fluid.cxx index a4aeceafb9..b0af69aecc 100644 --- a/examples/em-drift/2fluid.cxx +++ b/examples/em-drift/2fluid.cxx @@ -55,7 +55,7 @@ class EMdrift : public PhysicsModel { /************* LOAD DATA FROM GRID FILE ****************/ - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); // Load 2D profiles (set to zero if not found) mesh->get(Ni0, "Ni0"); @@ -243,7 +243,7 @@ class EMdrift : public PhysicsModel { int rhs(BoutReal t) override { - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); // Solve EM fields diff --git a/examples/fci-wave-logn/fci-wave.cxx b/examples/fci-wave-logn/fci-wave.cxx index a6c3afaabd..c64c2356e8 100644 --- a/examples/fci-wave-logn/fci-wave.cxx +++ b/examples/fci-wave-logn/fci-wave.cxx @@ -38,15 +38,15 @@ class FCIwave : public PhysicsModel { Field3D result; result.allocate(); - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); - for(auto i : result.region(RGN_NOBNDRY)) { + for(auto i : result.getRegion(RGN_NOBNDRY)) { result[i] = Bxyz[i] * (f_B.yup()[i.yp()] - f_B.ydown()[i.ym()]) / (2.*coord->dy[i] * sqrt(coord->g_22[i])); if (!finite(result[i])) { output.write("[%d,%d,%d]: %e, %e -> %e\n", - i.x, i.y, i.z, + i.x(), i.y(), i.z(), f_B.yup()[i.yp()], f_B.ydown()[i.ym()], result[i]); @@ -131,7 +131,7 @@ class FCIwave : public PhysicsModel { // Apply a soft floor to the density // Hard floors (setting ddt = 0) can slow convergence of solver - for (auto i : logn.region(RGN_NOBNDRY)) { + for (auto i : logn.getRegion(RGN_NOBNDRY)) { if (ddt(logn)[i] < 0.0) { ddt(logn)[i] *= (1. - exp(log_background - logn[i])); } diff --git a/examples/fci-wave/fci-wave.cxx b/examples/fci-wave/fci-wave.cxx index 013acf6c91..a922b92407 100644 --- a/examples/fci-wave/fci-wave.cxx +++ b/examples/fci-wave/fci-wave.cxx @@ -40,14 +40,14 @@ class FCIwave : public PhysicsModel { Field3D result; result.allocate(); - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); - for (auto i : result.region(RGN_NOBNDRY)) { + for (auto i : result.getRegion(RGN_NOBNDRY)) { result[i] = Bxyz[i] * (f_B.yup()[i.yp()] - f_B.ydown()[i.ym()]) / (2. * coord->dy[i] * sqrt(coord->g_22[i])); if (!finite(result[i])) { - output.write("[%d,%d,%d]: %e, %e -> %e\n", i.x, i.y, i.z, f_B.yup()[i.yp()], + output.write("[%d,%d,%d]: %e, %e -> %e\n", i.x(), i.y(), i.z(), f_B.yup()[i.yp()], f_B.ydown()[i.ym()], result[i]); } } @@ -159,7 +159,7 @@ class FCIwave : public PhysicsModel { // Apply a soft floor to the density // Hard floors (setting ddt = 0) can slow convergence of solver - for (auto i : logn.region(RGN_NOBNDRY)) { + for (auto i : logn.getRegion(RGN_NOBNDRY)) { if (ddt(logn)[i] < 0.0) { ddt(logn)[i] *= (1. - exp(log_background - logn[i])); } diff --git a/examples/gravity_reduced/gravity_reduced.cxx b/examples/gravity_reduced/gravity_reduced.cxx index 72041ff99a..6be8500c8a 100644 --- a/examples/gravity_reduced/gravity_reduced.cxx +++ b/examples/gravity_reduced/gravity_reduced.cxx @@ -130,7 +130,7 @@ class GravityReduced : public PhysicsModel { //load metric tensor components - coord = mesh->coordinates(); + coord = mesh->getCoordinates(); BoutReal Lz; // Size of the Z box diff --git a/examples/gyro-gem/gem.cxx b/examples/gyro-gem/gem.cxx index d9c3145127..f9562e71d9 100644 --- a/examples/gyro-gem/gem.cxx +++ b/examples/gyro-gem/gem.cxx @@ -330,7 +330,7 @@ class GEM : public PhysicsModel { ////////////////////////////////// // Metric tensor components - coord = mesh->coordinates(); + coord = mesh->getCoordinates(); // Normalise hthe /= Lbar; // parallel derivatives normalised to Lperp diff --git a/examples/jorek-compare/jorek_compare.cxx b/examples/jorek-compare/jorek_compare.cxx index 4b166501ed..cc9b3aa88a 100644 --- a/examples/jorek-compare/jorek_compare.cxx +++ b/examples/jorek-compare/jorek_compare.cxx @@ -178,7 +178,7 @@ class Jorek : public PhysicsModel { Field2D Rxy, Bpxy, Btxy, hthe; Field2D I; // Shear factor - coord = mesh->coordinates(); + coord = mesh->getCoordinates(); if (mesh->get(Rxy, "Rxy")) { // m output_error.write("Error: Cannot read Rxy from grid\n"); @@ -466,7 +466,7 @@ class Jorek : public PhysicsModel { { TRACE("Flux vExB"); // ExB velocity - vExB = (B0vec ^ Grad_perp(phi))/(B0*B0); + vExB = (cross(B0vec, Grad_perp(phi)))/(B0*B0); vExB.applyBoundary(); } diff --git a/examples/lapd-drift/lapd_drift.cxx b/examples/lapd-drift/lapd_drift.cxx index c0e48f0643..4628f93395 100644 --- a/examples/lapd-drift/lapd_drift.cxx +++ b/examples/lapd-drift/lapd_drift.cxx @@ -133,7 +133,7 @@ class LAPDdrift : public PhysicsModel { b0xcv.covariant = false; // Read contravariant components mesh->get(b0xcv, "bxcv"); // b0xkappa terms - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); // Load metrics mesh->get(Rxy, "Rxy"); @@ -431,7 +431,7 @@ class LAPDdrift : public PhysicsModel { /// Time derivatives calculated here int rhs(BoutReal t) { - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); // Invert vorticity to get phi @@ -727,7 +727,7 @@ class LAPDdrift : public PhysicsModel { /****************SPECIAL DIFFERENTIAL OPERATORS******************/ const Field2D Perp_Grad_dot_Grad(const Field2D &p, const Field2D &f) { - return DDX(p)*DDX(f)*mesh->coordinates()->g11; + return DDX(p)*DDX(f)*mesh->getCoordinates()->g11; } @@ -743,13 +743,13 @@ class LAPDdrift : public PhysicsModel { } else { // Use full expression with all terms - result = b0xGrad_dot_Grad(p, f) / mesh->coordinates()->Bxy; + result = b0xGrad_dot_Grad(p, f) / mesh->getCoordinates()->Bxy; } return result; } const Field3D vE_Grad(const Field2D &f, const Field3D &p) { - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); Field3D result; if (arakawa) { // Arakawa scheme for perpendicular flow. Here as a test @@ -803,7 +803,7 @@ class LAPDdrift : public PhysicsModel { result = VDDZ(-DDX(p), f); } else { // Use full expression with all terms - result = b0xGrad_dot_Grad(p, f) / mesh->coordinates()->Bxy; + result = b0xGrad_dot_Grad(p, f) / mesh->getCoordinates()->Bxy; } return result; } @@ -811,7 +811,7 @@ class LAPDdrift : public PhysicsModel { const Field3D vE_Grad(const Field3D &f, const Field3D &p) { Field3D result; - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); if (arakawa) { // Arakawa scheme for perpendicular flow. Here as a test diff --git a/examples/non-local_1d/cubic_spline_local.hxx b/examples/non-local_1d/cubic_spline_local.hxx index 81f7b0cf42..c185c95eb0 100644 --- a/examples/non-local_1d/cubic_spline_local.hxx +++ b/examples/non-local_1d/cubic_spline_local.hxx @@ -29,6 +29,7 @@ #include #include +#include #include #include diff --git a/examples/reconnect-2field/2field.cxx b/examples/reconnect-2field/2field.cxx index 2c7d1ec1c0..1628029d2d 100644 --- a/examples/reconnect-2field/2field.cxx +++ b/examples/reconnect-2field/2field.cxx @@ -64,7 +64,7 @@ class TwoField : public PhysicsModel { Ni0 *= 1e20; // To m^-3 // Coordinate system - coord = mesh->coordinates(); + coord = mesh->getCoordinates(); // Load metrics GRID_LOAD(Rxy, Bpxy, Btxy, hthe); diff --git a/examples/shear-alfven-wave/2fluid.cxx b/examples/shear-alfven-wave/2fluid.cxx index 3077a614bb..1e15ba4a18 100644 --- a/examples/shear-alfven-wave/2fluid.cxx +++ b/examples/shear-alfven-wave/2fluid.cxx @@ -65,7 +65,7 @@ class ShearAlfven : public PhysicsModel { GRID_LOAD(Ajpar0); // Coordinate system - coord = mesh->coordinates(); + coord = mesh->getCoordinates(); // Load magnetic curvature term b0xcv.covariant = false; // Read contravariant components diff --git a/examples/subsampling/monitor.cxx b/examples/subsampling/monitor.cxx index 980cf2b64d..d077b79b2f 100644 --- a/examples/subsampling/monitor.cxx +++ b/examples/subsampling/monitor.cxx @@ -89,9 +89,8 @@ class MonitorExample : public PhysicsModel { solver->addMonitor(slow); // the derived monitor Monitor1dData can dump 1d data, which we can // now add: - Indices start{mesh->xstart,mesh->ystart,0}; - probes->add(n[start],"n_up"); - probes->add(T[start],"T_up"); + probes->add(n(mesh->xstart,mesh->ystart,0),"n_up"); + probes->add(T(mesh->xstart,mesh->ystart,0),"T_up"); // add the corner value slow->add(T(0,0,0),"T"); // T is already present in BOUT.dmp - but // as it is a differnt file, this doesn't diff --git a/examples/uedge-benchmark/ue_bmark.cxx b/examples/uedge-benchmark/ue_bmark.cxx index 5eb59c8132..ba79647868 100644 --- a/examples/uedge-benchmark/ue_bmark.cxx +++ b/examples/uedge-benchmark/ue_bmark.cxx @@ -60,7 +60,7 @@ int physics_init(bool restarting) GRID_LOAD(Rxy); // Major radius [m] GRID_LOAD2(Bpxy, Btxy); // Poloidal, Toroidal B field [T] GRID_LOAD(hthe); // Poloidal arc length [m / radian] - mesh->get(mesh->dx, "dpsi"); + mesh->get(mesh->getCoordinates()->dx, "dpsi"); // Load normalisation values GRID_LOAD(Te_x); @@ -107,6 +107,7 @@ int physics_init(bool restarting) output.write("\tNormalising to rho_s = %e\n", rho_s); + auto * coords = mesh->getCoordinates(); // Normalise profiles Ni0 /= Ni_x/1.0e14; Ti0 /= Te_x; @@ -116,12 +117,12 @@ int physics_init(bool restarting) // Normalise geometry Rxy /= rho_s; hthe /= rho_s; - mesh->dx /= rho_s*rho_s*(bmag/1e4); + coords->dx /= rho_s*rho_s*(bmag/1e4); // Normalise magnetic field Bpxy /= (bmag/1e4); Btxy /= (bmag/1e4); - mesh->Bxy /= (bmag/1e4); + coords->Bxy /= (bmag/1e4); // calculate pressures pei0 = (Ti0 + Te0)*Ni0; @@ -141,23 +142,23 @@ int physics_init(bool restarting) /////////////// CALCULATE METRICS ///////////////// - mesh->g11 = (Rxy*Bpxy)^2; - mesh->g22 = 1.0 / (hthe^2); - mesh->g33 = (mesh->Bxy^2)/mesh->g11; - mesh->g12 = 0.0; - mesh->g13 = 0.0; - mesh->g23 = -Btxy/(hthe*Bpxy*Rxy); + coords->g11 = pow(Rxy*Bpxy,2.0); + coords->g22 = 1.0 / pow(hthe,2.0); + coords->g33 = pow(coords->Bxy,2.0)/coords->g11; + coords->g12 = 0.0; + coords->g13 = 0.0; + coords->g23 = -Btxy/(hthe*Bpxy*Rxy); - mesh->J = hthe / Bpxy; + coords->J = hthe / Bpxy; - mesh->g_11 = 1.0/mesh->g11; - mesh->g_22 = (mesh->Bxy*hthe/Bpxy)^2; - mesh->g_33 = Rxy*Rxy; - mesh->g_12 = 0.0; - mesh->g_13 = 0.0; - mesh->g_23 = Btxy*hthe*Rxy/Bpxy; + coords->g_11 = 1.0/coords->g11; + coords->g_22 = pow(coords->Bxy*hthe/Bpxy,2.0); + coords->g_33 = Rxy*Rxy; + coords->g_12 = 0.0; + coords->g_13 = 0.0; + coords->g_23 = Btxy*hthe*Rxy/Bpxy; - mesh->geometry(); // Calculate other metrics + coords->geometry(); // Calculate other metrics //////////////// BOUNDARIES /////////////////////// // @@ -168,9 +169,9 @@ int physics_init(bool restarting) Te0.applyBoundary("neumann"); Ti0.applyBoundary("neumann"); - Ni.setBackground(Ni0); - Te.setBackground(Te0); - Ti.setBackground(Ti0); + setBackground(Ni,Ni0); + setBackground(Te,Te0); + setBackground(Ti,Ti0); ///////////// SET EVOLVING VARIABLES ////////////// // @@ -212,7 +213,7 @@ Field3D Div_X_K_Grad_X(const Field3D &difFi, const Field3D &Fi) { Field3D result; - result = difFi * ( (Rxy*Bpxy)^2 ) * D2DX2(Fi) + result = difFi * ( pow(Rxy*Bpxy,2.0) ) * D2DX2(Fi) + (Bpxy / hthe) * DDX( difFi * Rxy * Rxy * Bpxy * hthe ) * DDX(Fi); return result; @@ -224,14 +225,14 @@ int physics_run(BoutReal t) mesh->communicate(Ni, Vi, Te, Ti); // Update profiles - Nit = Ni0 + Ni.DC(); - Tit = Ti0 + Ti.DC(); - Tet = Te0 + Te.DC(); - Vit = Vi0 + Vi.DC(); + Nit = Ni0 + DC(Ni); + Tit = Ti0 + DC(Ti); + Tet = Te0 + DC(Te); + Vit = Vi0 + DC(Vi); // Update non-linear coefficients on the mesh - kapa_Te = 3.2*(1./fmei)*(wci/nueix)*(Tet^2.5); - kapa_Ti = 3.9*(wci/nuiix)*(Tit^2.5); + kapa_Te = 3.2*(1./fmei)*(wci/nueix)*pow(Tet,2.5); + kapa_Ti = 3.9*(wci/nuiix)*pow(Tit,2.5); peit = (Tet+Tit)*Nit; diff --git a/examples/wave-slab/wave_slab.cxx b/examples/wave-slab/wave_slab.cxx index 9cde230793..68c96c9dbb 100644 --- a/examples/wave-slab/wave_slab.cxx +++ b/examples/wave-slab/wave_slab.cxx @@ -16,37 +16,38 @@ class WaveTest : public PhysicsModel { public: int init(bool restarting) { - + auto *coords = mesh->getCoordinates(); Field2D Rxy, Bpxy, Btxy, hthe, I; GRID_LOAD(Rxy); GRID_LOAD(Bpxy); GRID_LOAD(Btxy); GRID_LOAD(hthe); - mesh->get(mesh->Bxy, "Bxy"); - - if(mesh->ShiftXderivs) { + mesh->get(coords->Bxy, "Bxy"); + int ShiftXderivs = 0; + mesh->get(ShiftXderivs, "false"); + if(ShiftXderivs) { // No integrated shear in metric I = 0.0; }else mesh->get(I, "sinty"); - mesh->g11 = (Rxy*Bpxy)^2; - mesh->g22 = 1.0 / (hthe^2); - mesh->g33 = (I^2)*mesh->g11 + (mesh->Bxy^2)/mesh->g11; - mesh->g12 = 0.0; - mesh->g13 = -I*mesh->g11; - mesh->g23 = -Btxy/(hthe*Bpxy*Rxy); + coords->g11 = pow(Rxy*Bpxy,2.0); + coords->g22 = 1.0 / pow(hthe,2.0); + coords->g33 = pow(I,2.0)*coords->g11 + pow(coords->Bxy,2.0)/coords->g11; + coords->g12 = 0.0; + coords->g13 = -I*coords->g11; + coords->g23 = -Btxy/(hthe*Bpxy*Rxy); - mesh->J = hthe / Bpxy; + coords->J = hthe / Bpxy; - mesh->g_11 = 1.0/mesh->g11 + ((I*Rxy)^2); - mesh->g_22 = (mesh->Bxy*hthe/Bpxy)^2; - mesh->g_33 = Rxy*Rxy; - mesh->g_12 = Btxy*hthe*I*Rxy/Bpxy; - mesh->g_13 = I*Rxy*Rxy; - mesh->g_23 = Btxy*hthe*Rxy/Bpxy; + coords->g_11 = 1.0/coords->g11 + (pow(I*Rxy,2.0)); + coords->g_22 = pow(coords->Bxy*hthe/Bpxy,2.0); + coords->g_33 = Rxy*Rxy; + coords->g_12 = Btxy*hthe*I*Rxy/Bpxy; + coords->g_13 = I*Rxy*Rxy; + coords->g_23 = Btxy*hthe*Rxy/Bpxy; - mesh->geometry(); + coords->geometry(); solver->add(f, "f"); solver->add(g, "g"); From c37a6522dab7db2ace5251efab42092cc650a430 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 19 Nov 2018 19:35:25 +0000 Subject: [PATCH 0291/1783] Make gas_compress compile. CELL_VSHIFT may not be the best option in Grad call. --- examples/gas-compress/gas_compress.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/gas-compress/gas_compress.cxx b/examples/gas-compress/gas_compress.cxx index fd8d62be63..b56878c9b3 100644 --- a/examples/gas-compress/gas_compress.cxx +++ b/examples/gas-compress/gas_compress.cxx @@ -60,9 +60,9 @@ int GasCompress::rhs(BoutReal t) { if(sub_initial) { // Subtract force balance of initial profiles - ddt(V) = -V_dot_Grad(V, V) - Grad(P - P0, CELL_DEFAULT, CELL_YLOW)/N; + ddt(V) = -V_dot_Grad(V, V) - Grad(P - P0, CELL_VSHIFT)/N; }else { - ddt(V) = -V_dot_Grad(V, V) - Grad(P, CELL_DEFAULT, CELL_YLOW)/N + g; + ddt(V) = -V_dot_Grad(V, V) - Grad(P, CELL_VSHIFT)/N + g; } if(include_viscosity) { From 3f2033252984dc2bbf4e4c58fbc0046311b31f39 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 19 Nov 2018 21:05:55 +0000 Subject: [PATCH 0292/1783] Adding simple integrated test to compile all example files --- .../test-compile-examples/README.md | 6 ++++ .../integrated/test-compile-examples/runtest | 31 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/integrated/test-compile-examples/README.md create mode 100755 tests/integrated/test-compile-examples/runtest diff --git a/tests/integrated/test-compile-examples/README.md b/tests/integrated/test-compile-examples/README.md new file mode 100644 index 0000000000..889044fa4c --- /dev/null +++ b/tests/integrated/test-compile-examples/README.md @@ -0,0 +1,6 @@ +test-compile-examples +===================== + +This test ensures that all models in examples can be compiled. + +This currently works by finding any makefile located beneath examples. As such this test will also attempt to build documentation provided with some of the models and hence may fail if a suitable document compiler is not available. \ No newline at end of file diff --git a/tests/integrated/test-compile-examples/runtest b/tests/integrated/test-compile-examples/runtest new file mode 100755 index 0000000000..55e7d7c79c --- /dev/null +++ b/tests/integrated/test-compile-examples/runtest @@ -0,0 +1,31 @@ +#!/bin/bash + +#requires: all_tests +#requires: not make + +BOUT_TOP=../../.. +export PATH=$BOUT_TOP/bin:$PATH + +error=0 + +failed= +for target in $(find $BOUT_TOP/examples/ -name makefile) +do + dir=$(dirname ${target}) + echo "Trying to compile ${dir}" + + (cd ${dir} && make 2>&1) + ex=$? + + if test $ex -gt 0 + then + echo $(basename $dir) failed + error=1 + failed="$failed\n$(basename $dir) failed" + fi + +done + +echo -e $failed + +exit $error From 9c3d78fb32ab62492136d972bc036e2db4ddf9db Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 19 Nov 2018 21:16:07 +0000 Subject: [PATCH 0293/1783] Replace TRACE("%s",__thefunc__) with AUTO_TRACE() --- include/bout/deriv_store.hxx | 30 +++++++++++++++--------------- include/bout/index_derivs.hxx | 14 +++++++------- include/bout/mesh.hxx | 4 ++-- src/field/vecops.cxx | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 68f715b5ec..a30c9872c6 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -73,7 +73,7 @@ struct DerivativeStore { /// specified derivative type, direction and stagger. std::vector getAvailableMethods(DERIV derivType, DIRECTION direction, STAGGER stagger = STAGGER::None) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); // Get the key auto key = getKey(direction, stagger, DERIV_STRING(derivType)); return registeredMethods.at(key); @@ -83,7 +83,7 @@ struct DerivativeStore { /// specified derivative type, direction and stagger. void listAvailableMethods(DERIV derivType, DIRECTION direction, STAGGER stagger = STAGGER::None) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); // Introductory information output_info << "Available methods for derivative type '"; @@ -102,7 +102,7 @@ struct DerivativeStore { /// depends on the derivType input. void registerDerivative(standardFunc func, DERIV derivType, DIRECTION direction, STAGGER stagger, std::string methodName) { - TRACE("%s", __thefunc__); + AUTO_TRACE(); const auto key = getKey(direction, stagger, methodName); // Register this method name in lookup of known methods @@ -131,7 +131,7 @@ struct DerivativeStore { /// depends on the derivType input. void registerDerivative(upwindFunc func, DERIV derivType, DIRECTION direction, STAGGER stagger, std::string methodName) { - TRACE("%s", __thefunc__); + AUTO_TRACE(); const auto key = getKey(direction, stagger, methodName); // Register this method name in lookup of known methods @@ -156,13 +156,13 @@ struct DerivativeStore { /// Templated versions of the above registration routines. template void registerDerivative(standardFunc func) { - TRACE("%s", __thefunc__); + AUTO_TRACE(); registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), Stagger{}.lookup(), Method{}.meta.key); }; template void registerDerivative(upwindFunc func) { - TRACE("%s", __thefunc__); + AUTO_TRACE(); registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), Stagger{}.lookup(), Method{}.meta.key); }; @@ -176,7 +176,7 @@ struct DerivativeStore { /// method-classes so everything is consistently treated standardFunc getStandardDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); const auto realName = nameLookup( name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Standard)))); @@ -191,7 +191,7 @@ struct DerivativeStore { standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); const auto realName = nameLookup(name, defaultMethods.at( @@ -207,7 +207,7 @@ struct DerivativeStore { standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); const auto realName = nameLookup(name, defaultMethods.at( @@ -223,7 +223,7 @@ struct DerivativeStore { upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); const auto realName = nameLookup( name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Upwind)))); const auto key = getKey(direction, stagger, realName); @@ -235,7 +235,7 @@ struct DerivativeStore { }; fluxFunc getFluxDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); const auto realName = nameLookup( name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Flux)))); const auto key = getKey(direction, stagger, realName); @@ -247,7 +247,7 @@ struct DerivativeStore { }; void initialise(Options* options) { - TRACE("%s", __thefunc__); + AUTO_TRACE(); // To replicate the existing behaviour we first search for a section called //"dd?" and if the option isn't in there we search a section called "diff" @@ -360,7 +360,7 @@ private: std::string getMethodName(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); return name + " (" + DIRECTION_STRING(direction) + ", " + STAGGER_STRING(stagger) + ")"; }; @@ -380,7 +380,7 @@ private: /// all methods with the same function interface in the same map, which might /// be nice. std::size_t getKey(DIRECTION direction, STAGGER stagger, std::string key) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); // Note this key is indepedent of the field type (and hence the key is the // same for // 3D/2D @@ -401,7 +401,7 @@ private: /// a non-templated version that can be used to account for run-time choices template std::size_t getKey() const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); // Note this key is indepedent of the field type (and hence the key is the // same for // 3D/2D diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index bb381cb804..4939f69035 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -82,7 +82,7 @@ class DerivativeType { public: template void standard(const T& var, T& result, REGION region) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond || meta.derivType == DERIV::StandardFourth) ASSERT2(var.getMesh()->template getNguard() >= nGuards); @@ -95,7 +95,7 @@ public: template void upwindOrFlux(const T& vel, const T& var, T& result, REGION region) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) ASSERT2(var.getMesh()->template getNguard() >= nGuards); @@ -481,7 +481,7 @@ struct registerMethod { template void operator()(Direction, Stagger, FieldTypeContainer, Method) { - TRACE("%s", __thefunc__); + AUTO_TRACE(); using namespace std::placeholders; // Now we want to get the actual field type out of the TypeContainer @@ -646,7 +646,7 @@ class FFTDerivativeType { public: template void standard(const T& var, T& result, REGION region) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); ASSERT2(meta.derivType == DERIV::Standard) ASSERT2(var.getMesh()->template getNguard() >= nGuards); ASSERT2(direction == DIRECTION::Z); // Only in Z for now @@ -708,7 +708,7 @@ public: template void upwindOrFlux(const T& UNUSED(vel), const T& UNUSED(var), T& UNUSED(result), REGION UNUSED(region)) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); return; } @@ -719,7 +719,7 @@ class FFT2ndDerivativeType { public: template void standard(const T& var, T& result, REGION region) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); ASSERT2(meta.derivType == DERIV::Standard) ASSERT2(var.getMesh()->template getNguard() >= nGuards); ASSERT2(direction == DIRECTION::Z); // Only in Z for now @@ -774,7 +774,7 @@ public: template void upwindOrFlux(const T& UNUSED(vel), const T& UNUSED(var), T& UNUSED(result), REGION UNUSED(region)) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); return; } diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index c284a95fc0..866830eada 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -803,7 +803,7 @@ private: template T Mesh::indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, const std::string& method, REGION region) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); // Checks static_assert(std::is_base_of::value || std::is_base_of::value, @@ -884,7 +884,7 @@ T Mesh::indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, template T Mesh::indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method, REGION region) const { - TRACE("%s", __thefunc__); + AUTO_TRACE(); // Checks static_assert(std::is_base_of::value || std::is_base_of::value, diff --git a/src/field/vecops.cxx b/src/field/vecops.cxx index 3a578fa29e..a14855a5ab 100644 --- a/src/field/vecops.cxx +++ b/src/field/vecops.cxx @@ -360,7 +360,7 @@ const Field3D V_dot_Grad(const Vector3D &v, const Field3D &f) { // operation (addition) between the two input types. template R V_dot_Grad(const T &v, const F &a) { - TRACE("%s", __thefunc__); + AUTO_TRACE(); SCOREP0(); ASSERT1(v.getLocation() == a.getLocation()); ASSERT1(v.getLocation() != CELL_VSHIFT); From ff156c689a27c106f95701d3ef9775742b14cf59 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 19 Nov 2018 21:43:17 +0000 Subject: [PATCH 0294/1783] Fix for missing std:: --- include/utils.hxx | 2 +- src/sys/utils.cxx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/utils.hxx b/include/utils.hxx index 99c2414fce..9184b4218d 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -356,7 +356,7 @@ const std::string lowercase(const std::string &str); /*! * Convert a string to upper case */ -const string uppercase(const string &str); +const std::string uppercase(const std::string &str); /*! * Convert to lower case, except inside quotes (" or ') diff --git a/src/sys/utils.cxx b/src/sys/utils.cxx index bc6504b764..71611fe732 100644 --- a/src/sys/utils.cxx +++ b/src/sys/utils.cxx @@ -62,8 +62,8 @@ const std::string lowercase(const std::string &str) { } // Convert a string to upper case -const string uppercase(const string &str) { - string strlow(str); +const std::string uppercase(const std::string& str) { + std::string strlow(str); std::transform(strlow.begin(), strlow.end(), strlow.begin(), ::toupper); return strlow; From dd539cd7efbb86ff0b5f6353d437f4dd59b1117a Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 19 Nov 2018 23:10:44 +0000 Subject: [PATCH 0295/1783] uedge-benchmark compiles again Main change is to replace the `setBackground` functionality, by applying boundary conditions to the total fields. Converted to PhysicsModel, some minor tidying. Don't know if it runs (need 16 cores), but compiles... --- examples/uedge-benchmark/data/BOUT.inp | 4 - examples/uedge-benchmark/ue_bmark.cxx | 476 ++++++++++++------------- 2 files changed, 231 insertions(+), 249 deletions(-) diff --git a/examples/uedge-benchmark/data/BOUT.inp b/examples/uedge-benchmark/data/BOUT.inp index 8d2b03a9bc..9801105414 100644 --- a/examples/uedge-benchmark/data/BOUT.inp +++ b/examples/uedge-benchmark/data/BOUT.inp @@ -5,8 +5,6 @@ NOUT = 400 # number of time-steps TIMESTEP = 1e3 # time between outputs -#NOUT = 10 -#TIMESTEP = 1 ShiftXderivs = false # use shifted radial derivatives? TwistShift = false # use twist-shift condition? @@ -22,8 +20,6 @@ MYG = 2 grid="uedge.grd_Up_Ni_Tei_2d.nc" -NXPE = 1 # X parallelised if > 1 - dump_format = "nc" # NetCDF format [comms] diff --git a/examples/uedge-benchmark/ue_bmark.cxx b/examples/uedge-benchmark/ue_bmark.cxx index ba79647868..7717fe39d7 100644 --- a/examples/uedge-benchmark/ue_bmark.cxx +++ b/examples/uedge-benchmark/ue_bmark.cxx @@ -1,267 +1,253 @@ /******************************************************************************* * UEDGE benchmark case * - * Solves equations for + * Solves equations for * density Ni * parallel ion velocity Vi * electron and ion temperatures Te, Ti - * + * * Intended to be run for NZ=1 (i.e. X and Y only) for comparison with UEDGE * *******************************************************************************/ #include -#include +#include #include #include -// 2D initial profiles -Field2D Ni0, Ti0, Te0, Vi0; - -// 3D evolving fields -Field3D Te, Ni, Vi, Ti; - -// Non-linear coefficients -Field3D kapa_Te, kapa_Ti; - -// 3D total values -Field3D Nit, Tit, Tet, Vit; - -// pressures -Field3D peit, pe; -Field2D pei0, pe0; - -// Metric coefficients -Field2D Rxy, Bpxy, Btxy, hthe; - -// parameters -BoutReal Te_x, Ti_x, Ni_x, Vi_x, bmag, rho_s, fmei, AA, ZZ; -BoutReal lambda_ei, lambda_ii; -BoutReal nu_hat, mui_hat, wci, nueix, nuiix; - -BoutReal chi_perp, D_perp, mu_perp; - -int physics_init(bool restarting) -{ - Field2D I; // Shear factor - - output.write("Solving transport equations for Ni, Vi, Ti, Te\n"); - - /////////////// LOAD DATA FROM GRID FILE ////////////// - - // Load 2D profiles (set to zero if not found) - GRID_LOAD(Ni0); - GRID_LOAD(Ti0); - GRID_LOAD(Te0); - GRID_LOAD(Vi0); - - // Load metrics - GRID_LOAD(Rxy); // Major radius [m] - GRID_LOAD2(Bpxy, Btxy); // Poloidal, Toroidal B field [T] - GRID_LOAD(hthe); // Poloidal arc length [m / radian] - mesh->get(mesh->getCoordinates()->dx, "dpsi"); - - // Load normalisation values - GRID_LOAD(Te_x); - GRID_LOAD(Ti_x); - GRID_LOAD(Ni_x); - GRID_LOAD(bmag); - - Ni_x *= 1.0e14; - bmag *= 1.0e4; - - /////////////// READ OPTIONS ////////////////////////// - - // Read some parameters - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("uedge"); - OPTION(options, AA, 2.0); - OPTION(options, ZZ, 1.0); - - OPTION(options, chi_perp, 0.6); // Read in m^2 / s - OPTION(options, D_perp, 0.6); - OPTION(options, mu_perp, 0.6); - - ////////////// CALCULATE PARAMETERS /////////////////// - - rho_s = 1.02*sqrt(AA*Te_x)/ZZ/bmag; - fmei = 1./1836.2/AA; - - lambda_ei = 24.-log(sqrt(Ni_x)/Te_x); - lambda_ii = 23.-log(ZZ*ZZ*ZZ*sqrt(2.*Ni_x)/pow(Ti_x, 1.5)); - wci = 9.58e3*ZZ*bmag/AA; - nueix = 2.91e-6*Ni_x*lambda_ei/pow(Te_x, 1.5); - nuiix = 4.78e-8*pow(ZZ,4.)*Ni_x*lambda_ii/pow(Ti_x, 1.5)/sqrt(AA); - - Vi_x = wci * rho_s; - - ///////////// PRINT Z INFORMATION ///////////////////// - - BoutReal hthe0; - if(GRID_LOAD(hthe0) == 0) { - output.write(" ****NOTE: input from BOUT, Z length needs to be divided by %e\n", hthe0/rho_s); +class UedgeBenchmark : public PhysicsModel { +private: + // 2D initial profiles + Field2D Ni0, Ti0, Te0, Vi0; + + // 3D evolving fields + Field3D Te, Ni, Vi, Ti; + + // Non-linear coefficients + Field3D kapa_Te, kapa_Ti; + + // 3D total values + Field3D Nit, Tit, Tet, Vit; + + // pressures + Field3D peit, pe; + Field2D pei0, pe0; + + // Metric coefficients + Field2D Rxy, Bpxy, Btxy, hthe; + + // parameters + BoutReal Te_x, Ti_x, Ni_x, Vi_x, bmag, rho_s, fmei, AA, ZZ; + BoutReal lambda_ei, lambda_ii; + BoutReal nu_hat, mui_hat, wci, nueix, nuiix; + + BoutReal chi_perp, D_perp, mu_perp; + +protected: + + int init(bool UNUSED(restarting)) { + Field2D I; // Shear factor + + output.write("Solving transport equations for Ni, Vi, Ti, Te\n"); + + /////////////// LOAD DATA FROM GRID FILE ////////////// + + // Load 2D profiles (set to zero if not found) + GRID_LOAD(Ni0, Ti0, Te0, Vi0); + + // Load metrics + GRID_LOAD(Rxy); // Major radius [m] + GRID_LOAD(Bpxy, Btxy); // Poloidal, Toroidal B field [T] + GRID_LOAD(hthe); // Poloidal arc length [m / radian] + mesh->get(mesh->getCoordinates()->dx, "dpsi"); + + // Load normalisation values + GRID_LOAD(Te_x, Ti_x, Ni_x, bmag); + + Ni_x *= 1.0e14; + bmag *= 1.0e4; + + /////////////// READ OPTIONS ////////////////////////// + + // Read some parameters + auto& globalOptions = Options::root(); + auto& options = globalOptions["uedge"]; + OPTION(options, AA, 2.0); + OPTION(options, ZZ, 1.0); + + OPTION(options, chi_perp, 0.6); // Read in m^2 / s + OPTION(options, D_perp, 0.6); + OPTION(options, mu_perp, 0.6); + + ////////////// CALCULATE PARAMETERS /////////////////// + + rho_s = 1.02 * sqrt(AA * Te_x) / ZZ / bmag; + fmei = 1. / 1836.2 / AA; + + lambda_ei = 24. - log(sqrt(Ni_x) / Te_x); + lambda_ii = 23. - log(ZZ * ZZ * ZZ * sqrt(2. * Ni_x) / pow(Ti_x, 1.5)); + wci = 9.58e3 * ZZ * bmag / AA; + nueix = 2.91e-6 * Ni_x * lambda_ei / pow(Te_x, 1.5); + nuiix = 4.78e-8 * pow(ZZ, 4.) * Ni_x * lambda_ii / pow(Ti_x, 1.5) / sqrt(AA); + + Vi_x = wci * rho_s; + + ///////////// PRINT Z INFORMATION ///////////////////// + + BoutReal hthe0; + if (GRID_LOAD1(hthe0) == 0) { + output.write(" ****NOTE: input from BOUT, Z length needs to be divided by %e\n", + hthe0 / rho_s); + } + + ///////////// NORMALISE QUANTITIES //////////////////// + + output.write("\tNormalising to rho_s = %e\n", rho_s); + + auto* coords = mesh->getCoordinates(); + // Normalise profiles + Ni0 /= Ni_x / 1.0e14; + Ti0 /= Te_x; + Te0 /= Te_x; + Vi0 /= Vi_x; + + // Normalise geometry + Rxy /= rho_s; + hthe /= rho_s; + coords->dx /= rho_s * rho_s * (bmag / 1e4); + + // Normalise magnetic field + Bpxy /= (bmag / 1e4); + Btxy /= (bmag / 1e4); + coords->Bxy /= (bmag / 1e4); + + // calculate pressures + pei0 = (Ti0 + Te0) * Ni0; + pe0 = Te0 * Ni0; + + // Normalise coefficients + chi_perp /= rho_s * rho_s * wci; + D_perp /= rho_s * rho_s * wci; + mu_perp /= rho_s * rho_s * wci; + + chi_perp = 0.1; + D_perp = 0.1; + mu_perp = 0.1; + + output.write("Diffusion coefficients: chi %e D %e Mu %e\n", chi_perp, D_perp, mu_perp); + + /////////////// CALCULATE METRICS ///////////////// + + coords->g11 = pow(Rxy * Bpxy, 2.0); + coords->g22 = 1.0 / pow(hthe, 2.0); + coords->g33 = pow(coords->Bxy, 2.0) / coords->g11; + coords->g12 = 0.0; + coords->g13 = 0.0; + coords->g23 = -Btxy / (hthe * Bpxy * Rxy); + + coords->J = hthe / Bpxy; + + coords->g_11 = 1.0 / coords->g11; + coords->g_22 = pow(coords->Bxy * hthe / Bpxy, 2.0); + coords->g_33 = Rxy * Rxy; + coords->g_12 = 0.0; + coords->g_13 = 0.0; + coords->g_23 = Btxy * hthe * Rxy / Bpxy; + + coords->geometry(); // Calculate other metrics + + //////////////// BOUNDARIES /////////////////////// + // + // We want to apply the relaxing boundries to total density, + // temperature etc. + + Nit.setBoundary("Ni"); + Tet.setBoundary("Te"); + Tit.setBoundary("Ti"); + Vit.setBoundary("Vi"); + + Ni0.applyBoundary("neumann"); + Te0.applyBoundary("neumann"); + Ti0.applyBoundary("neumann"); + + ///////////// SET EVOLVING VARIABLES ////////////// + // + // Tell BOUT++ which variables to evolve + + SOLVE_FOR(Ni, Vi, Te, Ti); + + ///////////// ADD OUTPUT VARIABLES //////////////// + // + // Add any other variables to be dumped to file + + SAVE_ONCE(Ni0, Te0, Ti0); // Background quantities + SAVE_ONCE(Te_x, Ti_x, Ni_x, rho_s, wci); // Normalisation factors + + return 0; } - ///////////// NORMALISE QUANTITIES //////////////////// - - output.write("\tNormalising to rho_s = %e\n", rho_s); - - auto * coords = mesh->getCoordinates(); - // Normalise profiles - Ni0 /= Ni_x/1.0e14; - Ti0 /= Te_x; - Te0 /= Te_x; - Vi0 /= Vi_x; - - // Normalise geometry - Rxy /= rho_s; - hthe /= rho_s; - coords->dx /= rho_s*rho_s*(bmag/1e4); - - // Normalise magnetic field - Bpxy /= (bmag/1e4); - Btxy /= (bmag/1e4); - coords->Bxy /= (bmag/1e4); - - // calculate pressures - pei0 = (Ti0 + Te0)*Ni0; - pe0 = Te0*Ni0; - - // Normalise coefficients - chi_perp /= rho_s*rho_s*wci; - D_perp /= rho_s*rho_s*wci; - mu_perp /= rho_s*rho_s*wci; - - chi_perp = 0.1; - D_perp = 0.1; - mu_perp = 0.1; - - output.write("Diffusion coefficients: chi %e D %e Mu %e\n", - chi_perp, D_perp, mu_perp); - - /////////////// CALCULATE METRICS ///////////////// - - coords->g11 = pow(Rxy*Bpxy,2.0); - coords->g22 = 1.0 / pow(hthe,2.0); - coords->g33 = pow(coords->Bxy,2.0)/coords->g11; - coords->g12 = 0.0; - coords->g13 = 0.0; - coords->g23 = -Btxy/(hthe*Bpxy*Rxy); - - coords->J = hthe / Bpxy; - - coords->g_11 = 1.0/coords->g11; - coords->g_22 = pow(coords->Bxy*hthe/Bpxy,2.0); - coords->g_33 = Rxy*Rxy; - coords->g_12 = 0.0; - coords->g_13 = 0.0; - coords->g_23 = Btxy*hthe*Rxy/Bpxy; - - coords->geometry(); // Calculate other metrics - - //////////////// BOUNDARIES /////////////////////// - // - // We want to apply the relaxing boundries to total density, - // temperature etc. - - Ni0.applyBoundary("neumann"); - Te0.applyBoundary("neumann"); - Ti0.applyBoundary("neumann"); - - setBackground(Ni,Ni0); - setBackground(Te,Te0); - setBackground(Ti,Ti0); - - ///////////// SET EVOLVING VARIABLES ////////////// - // - // Tell BOUT++ which variables to evolve - // add evolving variables to the communication object - - Ni = Vi = Te = Ti = 0.0; - SOLVE_FOR4(Ni, Vi, Te, Ti); - - ///////////// ADD OUTPUT VARIABLES //////////////// - // - // Add any other variables to be dumped to file - - SAVE_ONCE3(Ni0, Te0, Ti0); // Background quantities - SAVE_ONCE5(Te_x, Ti_x, Ni_x, rho_s, wci); // Normalisation factors - + // Operator for radial diffusive flux /* - dump.add(ddt(Ni), "ddt_ni", 1); - dump.add(ddt(Ti), "ddt_ti", 1); - dump.add(ddt(Te), "ddt_te", 1); - dump.add(ddt(Vi), "ddt_vi", 1); - */ - - return(0); -} - -// Operator for radial diffusive flux -/* -Field3D Div_X_K_Grad_X(const Field3D &difVi, const Field3D &Vi) -{ - Field2D sg = 1./sqrt(mesh->g_11); - return difVi * D2DX2(Vi)/mesh->g_11 + Field3D Div_X_K_Grad_X(const Field3D &difVi, const Field3D &Vi) { + Field2D sg = 1./sqrt(mesh->g_11); + return difVi * D2DX2(Vi)/mesh->g_11 + DDX( difVi * sg ) * DDX(Vi) * sg; -} -*/ - -// This version the same as in BOUT-06. Note the R's moved,and hthe added -Field3D Div_X_K_Grad_X(const Field3D &difFi, const Field3D &Fi) -{ - Field3D result; + } + */ - result = difFi * ( pow(Rxy*Bpxy,2.0) ) * D2DX2(Fi) - + (Bpxy / hthe) * DDX( difFi * Rxy * Rxy * Bpxy * hthe ) * DDX(Fi); - - return result; -} - -int physics_run(BoutReal t) -{ - // Communicate variables - mesh->communicate(Ni, Vi, Te, Ti); - - // Update profiles - Nit = Ni0 + DC(Ni); - Tit = Ti0 + DC(Ti); - Tet = Te0 + DC(Te); - Vit = Vi0 + DC(Vi); - - // Update non-linear coefficients on the mesh - kapa_Te = 3.2*(1./fmei)*(wci/nueix)*pow(Tet,2.5); - kapa_Ti = 3.9*(wci/nuiix)*pow(Tit,2.5); + // This version the same as in BOUT-06. Note the R's moved,and hthe added + Field3D Div_X_K_Grad_X(const Field3D& difFi, const Field3D& Fi) { + Field3D result; + + result = difFi * (pow(Rxy * Bpxy, 2.0)) * D2DX2(Fi) + + (Bpxy / hthe) * DDX(difFi * Rxy * Rxy * Bpxy * hthe) * DDX(Fi); + + return result; + } - peit = (Tet+Tit)*Nit; + int rhs(BoutReal UNUSED(t)) { + // Communicate variables + mesh->communicate(Ni, Vi, Te, Ti); + + // Update profiles + Nit = Ni0 + DC(Ni); + Tit = Ti0 + DC(Ti); + Tet = Te0 + DC(Te); + Vit = Vi0 + DC(Vi); + + // Apply boundary conditions to total fields + Nit.applyBoundary(); + Tet.applyBoundary(); + Tit.applyBoundary(); + Vit.applyBoundary(); + + // Update non-linear coefficients on the mesh + kapa_Te = 3.2 * (1. / fmei) * (wci / nueix) * pow(Tet, 2.5); + kapa_Ti = 3.9 * (wci / nuiix) * pow(Tit, 2.5); + + peit = (Tet + Tit) * Nit; + + // DENSITY EQUATION + ddt(Ni) = -Vpar_Grad_par(Vit, Nit) - Nit * Div_par(Vit) + + Div_X_K_Grad_X(D_perp * (Nit * 0.0 + 1.0), Nit); + + // ION VELOCITY + ddt(Vi) = (-Grad_par(peit) + Div_X_K_Grad_X(mu_perp * Nit, Vit)) / Nit + - Vpar_Grad_par(Vit, Nit * Vit) / Nit - ddt(Ni) * Vit / Nit; + + // ELECTRON TEMPERATURE + ddt(Te) = (Div_par_K_Grad_par(kapa_Te, Tet) + Div_X_K_Grad_X(chi_perp * Nit, Tet)) + / (1.5 * Nit) + - ddt(Ni) * Tet / Nit; + + // ION TEMPERATURE + ddt(Ti) = (Div_par_K_Grad_par(kapa_Ti, Tit) + Div_X_K_Grad_X(chi_perp * Nit, Tit)) + / (1.5 * Nit) + - ddt(Ni) * Tit / Nit; + + return 0; + } +}; - // DENSITY EQUATION - ddt(Ni) = -Vpar_Grad_par(Vit, Nit) - -Nit*Div_par(Vit) - +Div_X_K_Grad_X(D_perp*(Nit*0.0+1.0), Nit) - ; - - // ION VELOCITY - ddt(Vi) = ( - -Grad_par(peit) - +Div_X_K_Grad_X(mu_perp*Nit, Vit) - )/Nit - -Vpar_Grad_par(Vit, Nit*Vit)/Nit - - ddt(Ni)*Vit/Nit - ; - - // ELECTRON TEMPERATURE - ddt(Te) = (Div_par_K_Grad_par(kapa_Te, Tet) - +Div_X_K_Grad_X(chi_perp*Nit, Tet) - )/(1.5*Nit) - - ddt(Ni)*Tet/Nit; - - // ION TEMPERATURE - ddt(Ti) = (Div_par_K_Grad_par(kapa_Ti, Tit) - +Div_X_K_Grad_X(chi_perp*Nit, Tit) - )/(1.5*Nit) - - ddt(Ni)*Tit/Nit; - - return(0); -} +BOUTMAIN(UedgeBenchmark); From fbab86087741038f2c3043f5b975de32fb6eea73 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 20 Nov 2018 14:42:58 +0000 Subject: [PATCH 0296/1783] Fix use of abs in rkgeneric --- src/solver/impls/rkgeneric/rkscheme.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/solver/impls/rkgeneric/rkscheme.cxx b/src/solver/impls/rkgeneric/rkscheme.cxx index cca8e6a5a4..a7eac475ae 100644 --- a/src/solver/impls/rkgeneric/rkscheme.cxx +++ b/src/solver/impls/rkgeneric/rkscheme.cxx @@ -71,7 +71,7 @@ void RKScheme::setCurState(const Array &start, Array &out, //Construct the current state from previous results -- This is expensive for(int j=0;jatol) warn=true; + if(std::abs(timeCoeffs[i]-tmp)>atol) warn=true; } //Optional warning @@ -239,7 +239,7 @@ void RKScheme::verifyCoeffs(){ tmp += resultCoeffs(i, j); } output<<"Order : "<atol) warn=true; + if(std::abs(1.0-tmp)>atol) warn=true; } //Optional warning From 9b12f53bae7b1458571b935fb53c8020f32297cb Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 20 Nov 2018 14:43:53 +0000 Subject: [PATCH 0297/1783] Fix abs use in slepc solver --- src/solver/impls/slepc/slepc.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index 60989d1ea5..19bcabe740 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -137,7 +137,7 @@ std::string formatEig(BoutReal reEig, BoutReal imEig){ //Note we use abs here and put the -/+ into pads to cope with //the case where the Eig is -0.000/0.000 which require different //padding but evaluate as the same number when doing comparisons - tmp< Date: Tue, 20 Nov 2018 14:44:28 +0000 Subject: [PATCH 0298/1783] Fix use of abs in imex-bdf2 solver --- src/solver/impls/imex-bdf2/imex-bdf2.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/solver/impls/imex-bdf2/imex-bdf2.cxx b/src/solver/impls/imex-bdf2/imex-bdf2.cxx index 3a0080ba8c..341bf6a474 100644 --- a/src/solver/impls/imex-bdf2/imex-bdf2.cxx +++ b/src/solver/impls/imex-bdf2/imex-bdf2.cxx @@ -874,9 +874,9 @@ int IMEXBDF2::run() { //Find local data for(int i=0;i Date: Tue, 20 Nov 2018 14:45:17 +0000 Subject: [PATCH 0299/1783] Fix use of abs in cyclic_reduction --- include/cyclic_reduction.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cyclic_reduction.hxx b/include/cyclic_reduction.hxx index c8acb130cf..307b87061e 100644 --- a/include/cyclic_reduction.hxx +++ b/include/cyclic_reduction.hxx @@ -545,7 +545,7 @@ private: for (int i = nloc - 3; i >= 0; i--) { // Check for zero pivot - if (abs(ifc(j, 1)) < 1e-10) + if (std::abs(ifc(j, 1)) < 1e-10) throw BoutException("Zero pivot in CyclicReduce::reduce"); // beta <- v_{i,i+1} / v_u,i @@ -571,7 +571,7 @@ private: for (int i = 2; i < nloc; i++) { - if (abs(ifc(j, 4 + 1)) < 1e-10) + if (std::abs(ifc(j, 4 + 1)) < 1e-10) throw BoutException("Zero pivot in CyclicReduce::reduce"); // alpha <- v_{i,i-1} / v_l,i-1 From b1df97688682145529b2b4076f5899d8600310c0 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 20 Nov 2018 14:46:22 +0000 Subject: [PATCH 0300/1783] Fix use of abs in utils.hxx --- include/utils.hxx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/utils.hxx b/include/utils.hxx index dfda67b0f9..76aa01d431 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -199,8 +199,6 @@ private: template int invert3x3(Matrix &a, BoutReal small = 1.0e-15) { TRACE("invert3x3"); - using std::abs; - // Calculate the first co-factors T A = a(1, 1) * a(2, 2) - a(1, 2) * a(2, 1); T B = a(1, 2) * a(2, 0) - a(1, 0) * a(2, 2); @@ -209,7 +207,7 @@ template int invert3x3(Matrix &a, BoutReal small = 1.0e-15) { // Calculate the determinant T det = a(0, 0) * A + a(0, 1) * B + a(0, 2) * C; - if (abs(det) < abs(small)) { + if (std::abs(det) < std::abs(small)) { if (small >=0 ){ throw BoutException("Determinant of matrix < %e --> Poorly conditioned", small); } else { @@ -312,7 +310,7 @@ T SIGN(T a) { // Return +1 or -1 (0 -> +1) * if |a| < |b| then return a, otherwise return b */ inline BoutReal MINMOD(BoutReal a, BoutReal b) { - return 0.5*(SIGN(a) + SIGN(b)) * BOUTMIN(fabs(a), fabs(b)); + return 0.5*(SIGN(a) + SIGN(b)) * BOUTMIN(std::abs(a), std::abs(b)); } #if CHECK > 0 From 27c5ed1561a5298a6b8dfee46cfd9695b1a5bac9 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 20 Nov 2018 14:47:41 +0000 Subject: [PATCH 0301/1783] Fix use of abs in fieldgenerators --- src/field/fieldgenerators.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/field/fieldgenerators.cxx b/src/field/fieldgenerators.cxx index 2881917398..0cc1f83953 100644 --- a/src/field/fieldgenerators.cxx +++ b/src/field/fieldgenerators.cxx @@ -94,7 +94,7 @@ FieldGeneratorPtr FieldAbs::clone(const std::list args) { } BoutReal FieldAbs::generate(double x, double y, double z, double t) { - return fabs(gen->generate(x,y,z,t)); + return std::abs(gen->generate(x,y,z,t)); } FieldGeneratorPtr FieldSqrt::clone(const std::list args) { @@ -217,7 +217,7 @@ BoutReal FieldMixmode::generate(double x, double y, double z, double t) { // A mixture of mode numbers for(int i=0;i<14;i++) { // This produces a spectrum which is peaked around mode number 4 - result += ( 1./SQ(1. + abs(i - 4)) ) * + result += ( 1./SQ(1. + std::abs(i - 4)) ) * cos(i * arg->generate(x,y,z,t) + phase[i]); } From 7cf809aaae7e00c364b1d10ee6d18b9d902bb54d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 20 Nov 2018 16:03:24 +0000 Subject: [PATCH 0302/1783] Replace deprecated C headers with C++ version Removes unneeded ones as well --- include/datafile.hxx | 4 ++-- include/field.hxx | 2 +- include/msg_stack.hxx | 2 +- include/optionsreader.hxx | 3 --- src/bout++.cxx | 2 +- src/field/field.cxx | 2 -- src/field/fieldperp.cxx | 3 +-- src/field/initialprofiles.cxx | 3 --- src/fileio/formatfactory.cxx | 2 +- src/invert/fft_fftw.cxx | 2 +- src/mesh/difops.cxx | 3 +-- src/mesh/index_derivs.cxx | 4 ++-- src/physics/smoothing.cxx | 2 +- src/physics/sourcex.cxx | 2 +- src/solver/impls/petsc/petsc.cxx | 2 +- src/solver/impls/slepc/slepc.cxx | 2 +- src/solver/solver.cxx | 4 ++-- src/sys/boutexception.cxx | 1 - src/sys/comm_group.cxx | 4 ++-- src/sys/derivs.cxx | 2 -- src/sys/expressionparser.cxx | 5 ----- src/sys/msg_stack.cxx | 2 +- src/sys/output.cxx | 6 +++--- src/sys/utils.cxx | 7 +++---- 24 files changed, 26 insertions(+), 45 deletions(-) diff --git a/include/datafile.hxx b/include/datafile.hxx index edd07fed94..ecfd369312 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -24,8 +24,8 @@ class Datafile; #include "dataformat.hxx" -#include -#include +#include +#include #include #include diff --git a/include/field.hxx b/include/field.hxx index 80861ffd91..13c288f635 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -29,7 +29,7 @@ class Field; #ifndef __FIELD_H__ #define __FIELD_H__ -#include +#include #include "bout_types.hxx" #include "stencils.hxx" diff --git a/include/msg_stack.hxx b/include/msg_stack.hxx index 2bfdf67da0..8846f7fa4d 100644 --- a/include/msg_stack.hxx +++ b/include/msg_stack.hxx @@ -32,7 +32,7 @@ class MsgStack; #include "unused.hxx" #include -#include +#include #include #include diff --git a/include/optionsreader.hxx b/include/optionsreader.hxx index ee4fcd5a86..454011e4d2 100644 --- a/include/optionsreader.hxx +++ b/include/optionsreader.hxx @@ -36,9 +36,6 @@ class OptionsReader; #include "options.hxx" -#include -#include - /// Class to handle reading options from file /// /// Example diff --git a/src/bout++.cxx b/src/bout++.cxx index 977ce7d155..b8e6986e77 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -74,7 +74,7 @@ using std::string; #include #endif -#include +#include void bout_signal_handler(int sig); // Handles signals #ifdef BOUT_FPE #include diff --git a/src/field/field.cxx b/src/field/field.cxx index 4ed8e8273d..3e4fd46987 100644 --- a/src/field/field.cxx +++ b/src/field/field.cxx @@ -25,8 +25,6 @@ //#include -#include - #include #include #include diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index f1de283f8e..a2d56a72ba 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -26,8 +26,7 @@ #include #include -#include -#include +#include #include #include diff --git a/src/field/initialprofiles.cxx b/src/field/initialprofiles.cxx index ff5426cf7d..16b0fbc156 100644 --- a/src/field/initialprofiles.cxx +++ b/src/field/initialprofiles.cxx @@ -45,9 +45,6 @@ #include #include "unused.hxx" -#include -#include -#include void initial_profile(const std::string &name, Field3D &var) { TRACE("initial_profile(string, Field3D)"); diff --git a/src/fileio/formatfactory.cxx b/src/fileio/formatfactory.cxx index f71faeb833..b389284919 100644 --- a/src/fileio/formatfactory.cxx +++ b/src/fileio/formatfactory.cxx @@ -12,7 +12,7 @@ #include #include -#include +#include FormatFactory *FormatFactory::instance = nullptr; diff --git a/src/invert/fft_fftw.cxx b/src/invert/fft_fftw.cxx index adc9a0f06d..22115a106e 100644 --- a/src/invert/fft_fftw.cxx +++ b/src/invert/fft_fftw.cxx @@ -32,7 +32,7 @@ #include #include -#include +#include #ifdef _OPENMP #include diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index 1aaafb7598..94d4c3330b 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -38,8 +38,7 @@ #include #include -#include -#include +#include /******************************************************************************* * Grad_par diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 00181318cf..44e10a32b3 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -58,8 +58,8 @@ #include #include -#include -#include +#include +#include #include diff --git a/src/physics/smoothing.cxx b/src/physics/smoothing.cxx index 7386a51037..4a3bc507b4 100644 --- a/src/physics/smoothing.cxx +++ b/src/physics/smoothing.cxx @@ -30,7 +30,7 @@ * **************************************************************/ -#include +#include #include #include diff --git a/src/physics/sourcex.cxx b/src/physics/sourcex.cxx index 4655b94582..79b55e93bd 100644 --- a/src/physics/sourcex.cxx +++ b/src/physics/sourcex.cxx @@ -3,7 +3,7 @@ **************************************************************/ #include -#include +#include #include #include diff --git a/src/solver/impls/petsc/petsc.cxx b/src/solver/impls/petsc/petsc.cxx index f96a23da8c..a4358118fb 100644 --- a/src/solver/impls/petsc/petsc.cxx +++ b/src/solver/impls/petsc/petsc.cxx @@ -33,7 +33,7 @@ #include -#include +#include #include // Cell interpolation #include diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index 60989d1ea5..2482d214a3 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -30,7 +30,7 @@ #include -#include +#include #include // Cell interpolation #include diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 425bb5468a..331df82c05 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -22,8 +22,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/sys/boutexception.cxx b/src/sys/boutexception.cxx index b3f468a291..adf610cba7 100644 --- a/src/sys/boutexception.cxx +++ b/src/sys/boutexception.cxx @@ -4,7 +4,6 @@ #include #include #include -#include #ifdef BACKTRACE #include diff --git a/src/sys/comm_group.cxx b/src/sys/comm_group.cxx index 2f4f0f9719..8fbd7464e6 100644 --- a/src/sys/comm_group.cxx +++ b/src/sys/comm_group.cxx @@ -25,8 +25,8 @@ ***********************************************************************/ #include -#include -#include +#include +#include #include #include diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 63e259540f..0eb844feb2 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -48,8 +48,6 @@ #include #include -#include -#include #include diff --git a/src/sys/expressionparser.cxx b/src/sys/expressionparser.cxx index 94a4330205..dc14c22815 100644 --- a/src/sys/expressionparser.cxx +++ b/src/sys/expressionparser.cxx @@ -26,15 +26,10 @@ #include // for lowercase -#include -#include - using std::string; using std::list; using std::stringstream; -#include - ///////////////////////////////////////////// namespace { // These classes only visible in this file diff --git a/src/sys/msg_stack.cxx b/src/sys/msg_stack.cxx index f52513370b..b34351100c 100644 --- a/src/sys/msg_stack.cxx +++ b/src/sys/msg_stack.cxx @@ -26,7 +26,7 @@ #include #include -#include +#include #include #if CHECK > 1 diff --git a/src/sys/output.cxx b/src/sys/output.cxx index 7c43756ee3..d03aeaa356 100644 --- a/src/sys/output.cxx +++ b/src/sys/output.cxx @@ -23,9 +23,9 @@ * **************************************************************************/ -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/sys/utils.cxx b/src/sys/utils.cxx index 60461dc049..25b34d2eee 100644 --- a/src/sys/utils.cxx +++ b/src/sys/utils.cxx @@ -24,10 +24,9 @@ **************************************************************************/ #include -#include -#include -#include -#include +#include +#include +#include #include #include #include From a05406c8f3672b0bb46d59c03dbc59d8c28b5efa Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 20 Nov 2018 16:54:14 +0000 Subject: [PATCH 0303/1783] Split BoundaryFactory tests into smaller tests; use a fixture --- tests/unit/mesh/test_boundary_factory.cxx | 113 +++++++++++++--------- 1 file changed, 67 insertions(+), 46 deletions(-) diff --git a/tests/unit/mesh/test_boundary_factory.cxx b/tests/unit/mesh/test_boundary_factory.cxx index 850eadd2f4..c21a37c7a4 100644 --- a/tests/unit/mesh/test_boundary_factory.cxx +++ b/tests/unit/mesh/test_boundary_factory.cxx @@ -24,69 +24,90 @@ class TestBoundary : public BoundaryOp { void apply(Field3D &UNUSED(f)) override {} }; -TEST(BoundaryFactoryTests, IsSingleton) { +class BoundaryFactoryTest : public ::testing::Test { +public: + BoundaryFactoryTest() { + if (mesh != nullptr) { + delete mesh; + mesh = nullptr; + } + mesh = new FakeMesh(3, 3, 3); + + fac->add(new TestBoundary(), "testboundary"); + + region = new BoundaryRegionXIn{"test_region", 0, 1, mesh}; + } + + ~BoundaryFactoryTest() { + delete mesh; + mesh = nullptr; + + delete region; + + BoundaryFactory::cleanup(); + + if (boundary != nullptr) { + delete boundary; + boundary = nullptr; + } + } + + BoundaryFactory* fac{BoundaryFactory::getInstance()}; + BoundaryRegionXIn* region{nullptr}; + BoundaryOpBase* boundary{nullptr}; +}; + +TEST_F(BoundaryFactoryTest, IsSingleton) { BoundaryFactory* fac1 = BoundaryFactory::getInstance(); BoundaryFactory* fac2 = BoundaryFactory::getInstance(); EXPECT_EQ(fac1, fac2); } -TEST(BoundaryFactoryTests, CreateTestBoundary) { - mesh = new FakeMesh(3, 3, 3); - - BoundaryFactory* fac = BoundaryFactory::getInstance(); - fac->add(new TestBoundary(), "testboundary"); - - BoundaryRegionXIn region("test_region", 0, 1, mesh); +TEST_F(BoundaryFactoryTest, CreateTestBoundaryNoBrackets) { + boundary = fac->create("testboundary", region); - // Check no brackets - - auto *boundary = fac->create("testboundary", ®ion); + EXPECT_TRUE(boundary != nullptr); - EXPECT_TRUE( boundary != nullptr ); - EXPECT_EQ(typeid(*boundary), typeid(TestBoundary)); +} - delete boundary; - - // Positional arguments - - boundary = fac->create("testboundary(a, 1)", ®ion); - EXPECT_TRUE( boundary != nullptr ); +TEST_F(BoundaryFactoryTest, CreateTestBoundaryPositionalArguments) { + boundary = fac->create("testboundary(a, 1)", region); + EXPECT_TRUE(boundary != nullptr); - TestBoundary *tb = dynamic_cast(boundary); + auto* tb = dynamic_cast(boundary); - EXPECT_EQ( tb->args.size(), 2 ); - EXPECT_EQ( tb->args.front(), "a" ); - EXPECT_EQ( tb->args.back(), "1" ); - EXPECT_TRUE( tb->keywords.empty() ); - - delete boundary; + EXPECT_EQ(tb->args.size(), 2); + EXPECT_EQ(tb->args.front(), "a"); + EXPECT_EQ(tb->args.back(), "1"); + EXPECT_TRUE(tb->keywords.empty()); +} - // Test keywords - boundary = fac->create("testboundary(key=1, b=value)", ®ion); - EXPECT_TRUE( boundary != nullptr ); +TEST_F(BoundaryFactoryTest, CreateTestBoundaryKeywords) { + boundary = fac->create("testboundary(key=1, b=value)", region); + EXPECT_TRUE(boundary != nullptr); - tb = dynamic_cast(boundary); - - EXPECT_TRUE( tb->args.empty() ); - EXPECT_EQ( tb->keywords.size(), 2 ); - EXPECT_EQ( tb->keywords.at("key"), "1" ); - EXPECT_EQ( tb->keywords.at("b"), "value" ); + auto* tb = dynamic_cast(boundary); - delete boundary; + EXPECT_TRUE(tb->args.empty()); + EXPECT_EQ(tb->keywords.size(), 2); + EXPECT_EQ(tb->keywords.at("key"), "1"); + EXPECT_EQ(tb->keywords.at("b"), "value"); +} - // Mix of positional args and keywords - boundary = fac->create("testboundary(0.23, key =1+2 , something(),b=value ,a + sin(1.2))", ®ion); - EXPECT_TRUE( boundary != nullptr ); +TEST_F(BoundaryFactoryTest, CreateTestBoundaryPositionalArgumentsAndKeywords) { + boundary = fac->create( + "testboundary(0.23, key =1+2 , something(),b=value ,a + sin(1.2))", region); + EXPECT_TRUE(boundary != nullptr); - tb = dynamic_cast(boundary); + auto* tb = dynamic_cast(boundary); std::list args_expected = {"0.23", "something()", "a + sin(1.2)"}; - - EXPECT_EQ( tb->args, args_expected ); - - EXPECT_EQ( tb->keywords.size(), 2 ); - EXPECT_EQ( tb->keywords.at("key"), "1+2" ); - EXPECT_EQ( tb->keywords.at("b"), "value" ); + + EXPECT_EQ(tb->args, args_expected); + + EXPECT_EQ(tb->keywords.size(), 2); + EXPECT_EQ(tb->keywords.at("key"), "1+2"); + EXPECT_EQ(tb->keywords.at("b"), "value"); } From ee63062f00f4dd5f99d8ce929a430e3d50163123 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 20 Nov 2018 20:01:03 +0000 Subject: [PATCH 0304/1783] Small style fixes to python prompted by codacy --- examples/performance/ddx/new_scaling_parser.py | 3 +-- examples/performance/ddy/new_scaling_parser.py | 3 +-- examples/performance/ddz/new_scaling_parser.py | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/examples/performance/ddx/new_scaling_parser.py b/examples/performance/ddx/new_scaling_parser.py index e65b30ffd4..d2a5fee191 100644 --- a/examples/performance/ddx/new_scaling_parser.py +++ b/examples/performance/ddx/new_scaling_parser.py @@ -28,10 +28,9 @@ def read_file(filename): axis = cases_weak['Local grid'] data = [cases_weak[x] for x in case_lines] labels = [case_lines[x] for x in case_lines] - return {'axis':axis, 'data':data, 'labels':labels} -def getScan(baseName = "timing_{n}.txt", nthreads = [1,2,4,8,16,32]): +def getScan(baseName = "timing_{n}.txt", nthreads = (1,2,4,8,16,32)): from numpy import zeros dataS = [] diff --git a/examples/performance/ddy/new_scaling_parser.py b/examples/performance/ddy/new_scaling_parser.py index e65b30ffd4..d2a5fee191 100644 --- a/examples/performance/ddy/new_scaling_parser.py +++ b/examples/performance/ddy/new_scaling_parser.py @@ -28,10 +28,9 @@ def read_file(filename): axis = cases_weak['Local grid'] data = [cases_weak[x] for x in case_lines] labels = [case_lines[x] for x in case_lines] - return {'axis':axis, 'data':data, 'labels':labels} -def getScan(baseName = "timing_{n}.txt", nthreads = [1,2,4,8,16,32]): +def getScan(baseName = "timing_{n}.txt", nthreads = (1,2,4,8,16,32)): from numpy import zeros dataS = [] diff --git a/examples/performance/ddz/new_scaling_parser.py b/examples/performance/ddz/new_scaling_parser.py index e65b30ffd4..d2a5fee191 100644 --- a/examples/performance/ddz/new_scaling_parser.py +++ b/examples/performance/ddz/new_scaling_parser.py @@ -28,10 +28,9 @@ def read_file(filename): axis = cases_weak['Local grid'] data = [cases_weak[x] for x in case_lines] labels = [case_lines[x] for x in case_lines] - return {'axis':axis, 'data':data, 'labels':labels} -def getScan(baseName = "timing_{n}.txt", nthreads = [1,2,4,8,16,32]): +def getScan(baseName = "timing_{n}.txt", nthreads = (1,2,4,8,16,32)): from numpy import zeros dataS = [] From 86f7e9578e4010188be173a205a92e893fada880 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 20 Nov 2018 20:01:30 +0000 Subject: [PATCH 0305/1783] Remove unneeded return statement, prompted by codacy --- include/bout/index_derivs.hxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index 4939f69035..7dc373b909 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -710,7 +710,6 @@ public: REGION UNUSED(region)) const { AUTO_TRACE(); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); - return; } metaData meta{"FFT", 0, DERIV::Standard}; }; @@ -776,7 +775,6 @@ public: REGION UNUSED(region)) const { AUTO_TRACE(); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); - return; } metaData meta{"FFT", 0, DERIV::StandardSecond}; }; From 4b5221aa6d3d509f3e8ae84dfddc397938239a0e Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 20 Nov 2018 20:01:54 +0000 Subject: [PATCH 0306/1783] Mark constructors as explicit, prompted by codacy --- include/bout/template_combinations.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bout/template_combinations.hxx b/include/bout/template_combinations.hxx index 19f5e6ad10..9637f41553 100644 --- a/include/bout/template_combinations.hxx +++ b/include/bout/template_combinations.hxx @@ -57,7 +57,7 @@ struct TypeContainer { template struct DeferredFunction { // Just store the actual function we wish to apply - DeferredFunction(currentFunction f) : storedFunc(f){}; + explicit DeferredFunction(currentFunction f) : storedFunc(f){}; // The actual function we wish to apply with the functor currentFunction storedFunc; @@ -179,7 +179,7 @@ void processSet(theFunction func, Set, otherSets... ot template struct produceCombinations { template - produceCombinations(theFunction func) { + explicit produceCombinations(theFunction func) { processSet(func, FirstSet{}, otherSets{}...); }; }; From 8a688d69209433ffdaecf83b665bf82ff3c57a24 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 21 Nov 2018 09:04:55 +0000 Subject: [PATCH 0307/1783] Use a more sensible macro name and tidy up after ourselves --- include/bout/index_derivs.hxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index 7dc373b909..c9d75ef2df 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -555,7 +555,9 @@ struct registerMethod { /// Some helper defines for now that allow us to wrap up enums /// and the specific methods. -#define e(family, value) enumWrapper +#define WRAP_ENUM(family, value) enumWrapper +/// Temporary short hand +#define e(family, value) WRAP_ENUM(family, value) ///////////////////////////////////////////////////////////////////////////////// /// Here's an example of registering a couple of DerivativeType methods @@ -784,4 +786,5 @@ produceCombinations, Set, Set> registerFFTDerivative(registerMethod{}); +#undef e #endif From a66fb8496dda744211f308b60c795873c72de092 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 21 Nov 2018 10:33:23 +0000 Subject: [PATCH 0308/1783] Don't reserve yup/ydown_fields vectors now that we have move ctors --- src/field/field3d.cxx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 02740a12c5..c59aa6f7db 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -53,9 +53,6 @@ Field3D::Field3D(Mesh* localmesh) : Field(localmesh) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; - - yup_fields.reserve(fieldmesh->ystart); - ydown_fields.reserve(fieldmesh->ystart); } } @@ -73,9 +70,6 @@ Field3D::Field3D(const Field3D& f) : Field(f.fieldmesh), data(f.data) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; - - yup_fields.reserve(fieldmesh->ystart); - ydown_fields.reserve(fieldmesh->ystart); } location = f.location; From 59c6d37467b9895e747f233ecb01ba092c3e742d Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 21 Nov 2018 10:47:04 +0000 Subject: [PATCH 0309/1783] Adding a unit test for include/bout/test_template_combinations.hxx --- .../bout/test_template_combinations.cxx | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 tests/unit/include/bout/test_template_combinations.cxx diff --git a/tests/unit/include/bout/test_template_combinations.cxx b/tests/unit/include/bout/test_template_combinations.cxx new file mode 100644 index 0000000000..00b07ca362 --- /dev/null +++ b/tests/unit/include/bout/test_template_combinations.cxx @@ -0,0 +1,185 @@ +#include "gtest/gtest.h" + +#include +#include +#include + +#include + +using innerType = std::vector; +using registrationType = std::vector; + +struct test1 {}; +struct test2 {}; + +const std::map humanName{ + {std::type_index(typeid(int)), "int"}, + {std::type_index(typeid(long)), "long"}, + {std::type_index(typeid(float)), "float"}, + {std::type_index(typeid(double)), "double"}, + {std::type_index(typeid(std::string)), "std::string"}, + {std::type_index(typeid(bool)), "boolean"}, + {std::type_index(typeid(test1)), "test1 struct"}, + {std::type_index(typeid(test2)), "test2 struct"}, + +}; + +template +std::string typeName() { + // Note because this routine is templated this is evaluated at compile time + // and as such + // we need to make sure that there is an entry for type T in humanName at + // compile time + // -- in other words we can't expand the map in the below routines. + return humanName.at(std::type_index(typeid(T))); +} + +// Helper struct that acts as the bottom level object that deals +// with the provided types +struct registerItems { + template + void operator()(T) { + innerType thisCase; + thisCase.push_back(typeName()); + registrations.push_back(thisCase); + }; + template + void operator()(T, T2) { + innerType thisCase; + thisCase.push_back(typeName()); + thisCase.push_back(typeName()); + registrations.push_back(thisCase); + }; + template + void operator()(T, T2, T3) { + innerType thisCase; + thisCase.push_back(typeName()); + thisCase.push_back(typeName()); + thisCase.push_back(typeName()); + registrations.push_back(thisCase); + }; + template + void operator()(T, T2, T3, T4) { + innerType thisCase; + thisCase.push_back(typeName()); + thisCase.push_back(typeName()); + thisCase.push_back(typeName()); + thisCase.push_back(typeName()); + registrations.push_back(thisCase); + }; + + registrationType& registrations; +}; + +TEST(TemplateCombinationsTest, SingleSetSingleTypeItem) { + registrationType registrations; + registerItems reg{registrations}; + + produceCombinations> junk(reg); + + // Check number of registrations + ASSERT_EQ(reg.registrations.size(), 1); + // Check size of each registration + for (const auto& entry : registrations) { + ASSERT_EQ(entry.size(), 1); + } + + EXPECT_EQ(reg.registrations[0][0], typeName()); +} + +TEST(TemplateCombinationsTest, SingleSetTwoTypesItem) { + registrationType registrations; + registerItems reg{registrations}; + + produceCombinations> junk(reg); + + // Check number of registrations + ASSERT_EQ(reg.registrations.size(), 2); + // Check size of each registration + for (const auto& entry : registrations) { + ASSERT_EQ(entry.size(), 1); + } + + EXPECT_EQ(reg.registrations[0][0], typeName()); + EXPECT_EQ(reg.registrations[1][0], typeName()); +} + +TEST(TemplateCombinationsTest, TwoSetsOneTypeItem) { + registrationType registrations; + registerItems reg{registrations}; + + produceCombinations, Set> junk(reg); + + // Check number of registrations + ASSERT_EQ(reg.registrations.size(), 1); + // Check size of each registration + for (const auto& entry : registrations) { + ASSERT_EQ(entry.size(), 2); + } + + EXPECT_EQ(reg.registrations[0][0], typeName()); + EXPECT_EQ(reg.registrations[0][1], typeName()); +} + +TEST(TemplateCombinationsTest, TwoSetsMultiTypeItem) { + registrationType registrations; + registerItems reg{registrations}; + + produceCombinations, Set> junk(reg); + + innerType firstSet{typeName(), typeName()}; + innerType secondSet{typeName(), typeName(), typeName()}; + + // Check number of registrations + ASSERT_EQ(reg.registrations.size(), firstSet.size() * secondSet.size()); + // Check size of each registration + for (const auto& entry : registrations) { + ASSERT_EQ(entry.size(), 2); + } + + int count = 0; + for (const auto& first : firstSet) { + EXPECT_EQ(reg.registrations[count][0], first); + for (const auto& second : secondSet) { + EXPECT_EQ(reg.registrations[count][1], second); + count++; + } + }; +} + +TEST(TemplateCombinationsTest, FourSetsMultiTypeItem) { + registrationType registrations; + registerItems reg{registrations}; + + produceCombinations, Set, Set, + Set> + junk(reg); + + innerType firstSet{typeName(), typeName()}; + innerType secondSet{typeName(), typeName(), typeName()}; + innerType thirdSet{typeName()}; + innerType fourthSet{typeName(), typeName()}; + + // Check number of registrations + ASSERT_EQ(reg.registrations.size(), + firstSet.size() * secondSet.size() * thirdSet.size() * fourthSet.size()); + // Check size of each registration + for (const auto& entry : registrations) { + ASSERT_EQ(entry.size(), 4); + } + + int count = 0; + for (const auto& first : firstSet) { + EXPECT_EQ(reg.registrations[count][0], first); + for (const auto& second : secondSet) { + EXPECT_EQ(reg.registrations[count][1], second); + for (const auto& third : thirdSet) { + EXPECT_EQ(reg.registrations[count][2], third); + for (const auto& fourth : fourthSet) { + EXPECT_EQ(reg.registrations[count][3], fourth); + count++; + } + } + } + }; +} From 3d7df2464dde4fa78132c1e2ed0bdbf688fc9489 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 21 Nov 2018 13:23:02 +0000 Subject: [PATCH 0310/1783] Improve variable name in uppercase --- src/sys/utils.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sys/utils.cxx b/src/sys/utils.cxx index 71611fe732..55de4112c9 100644 --- a/src/sys/utils.cxx +++ b/src/sys/utils.cxx @@ -63,10 +63,10 @@ const std::string lowercase(const std::string &str) { // Convert a string to upper case const std::string uppercase(const std::string& str) { - std::string strlow(str); + std::string strup(str); - std::transform(strlow.begin(), strlow.end(), strlow.begin(), ::toupper); - return strlow; + std::transform(strup.begin(), strup.end(), strup.begin(), ::toupper); + return strup; } // Convert to lowercase, except for inside strings From 62db25ccb5ab153fe819170db6cdc3babaa2b565 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 21 Nov 2018 13:55:51 +0000 Subject: [PATCH 0311/1783] Add some introspection routines to deriv_store Transition to using std::set to hold registered method names rather than std::vector -- ensures there's a unique entry for a given key --- include/bout/deriv_store.hxx | 58 ++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index a30c9872c6..1bebc66da6 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -69,14 +70,41 @@ struct DerivativeStore { return instance; } + /// Report if store has any registered methods + bool isEmpty() const { + AUTO_TRACE(); + return registeredMethods.empty(); + }; + + /// Report if store has any registered methods for specific type determined by key + bool isEmpty(std::size_t key) const { + AUTO_TRACE(); + return registeredMethods.count(key) == 0; + } + + /// Report if store has any registered methods for specific type + bool isEmpty(DERIV derivType, DIRECTION direction, + STAGGER stagger = STAGGER::None) const { + AUTO_TRACE(); + + // Get the key + auto key = getKey(direction, stagger, DERIV_STRING(derivType)); + return isEmpty(key); + } + /// Returns a vector of all registered method names for the /// specified derivative type, direction and stagger. - std::vector getAvailableMethods(DERIV derivType, DIRECTION direction, - STAGGER stagger = STAGGER::None) const { + std::set getAvailableMethods(DERIV derivType, DIRECTION direction, + STAGGER stagger = STAGGER::None) const { AUTO_TRACE(); + // Get the key auto key = getKey(direction, stagger, DERIV_STRING(derivType)); - return registeredMethods.at(key); + if (isEmpty(key)) { + return std::set{}; + } else { + return registeredMethods.at(key); + } }; /// Outputs a list of all registered method names for the @@ -106,7 +134,7 @@ struct DerivativeStore { const auto key = getKey(direction, stagger, methodName); // Register this method name in lookup of known methods - registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))].push_back( + registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))].insert( methodName); switch (derivType) { @@ -135,7 +163,7 @@ struct DerivativeStore { const auto key = getKey(direction, stagger, methodName); // Register this method name in lookup of known methods - registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))].push_back( + registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))].insert( methodName); switch (derivType) { @@ -343,6 +371,24 @@ struct DerivativeStore { /// it might be useful to relax this assumption! storageType defaultMethods; + /// Provide a method to override/force a specific default method + void forceDefaultMethod(std::string methodName, DERIV deriv, DIRECTION direction, + STAGGER stagger = STAGGER::None) { + const auto key = getKey(direction, stagger, DERIV_STRING(deriv)); + defaultMethods[key] = uppercase(methodName); + } + + /// Empty all member storage + void reset() { + defaultMethods.clear(); + standard.clear(); + standardSecond.clear(); + standardFourth.clear(); + upwind.clear(); + flux.clear(); + registeredMethods.clear(); + } + private: // Make the constructor private so we can't make instances outside // of the struct @@ -356,7 +402,7 @@ private: storageType upwind; storageType flux; - storageType> registeredMethods; + storageType> registeredMethods; std::string getMethodName(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { From bbf51b7890667764c94586bd21c60b88c81e6d86 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 21 Nov 2018 14:25:20 +0000 Subject: [PATCH 0312/1783] Initial unit tests for deriv_store --- tests/unit/include/bout/test_deriv_store.cxx | 226 +++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 tests/unit/include/bout/test_deriv_store.cxx diff --git a/tests/unit/include/bout/test_deriv_store.cxx b/tests/unit/include/bout/test_deriv_store.cxx new file mode 100644 index 0000000000..8012848daa --- /dev/null +++ b/tests/unit/include/bout/test_deriv_store.cxx @@ -0,0 +1,226 @@ +#include "gtest/gtest.h" + +#include +#include +#include +#include +#include + +#include + +using FieldType = std::vector; + +using standardType = DerivativeStore::standardFunc; +using flowType = DerivativeStore::upwindFunc; + +void standardReturnTenSetToOne(const FieldType& UNUSED(inp), FieldType& out, + const REGION = RGN_ALL) { + out.resize(10, 1.0); +} + +void flowReturnSixSetToTwo(const FieldType& UNUSED(vel), const FieldType& UNUSED(inp), + FieldType& out, const REGION = RGN_ALL) { + out.resize(6, 2.0); +} + +TEST(DerivativeStoreTest, CanGetInstance) { + EXPECT_NO_THROW(DerivativeStore::getInstance()); +} + +TEST(DerivativeStoreTest, IsAllEmpty) { + auto& store = DerivativeStore::getInstance(); + EXPECT_TRUE(store.isEmpty()); +} + +TEST(DerivativeStoreTest, IsEmptySpecificType) { + auto& store = DerivativeStore::getInstance(); + EXPECT_TRUE(store.isEmpty(DERIV::Standard, DIRECTION::X, STAGGER::None)); +} + +TEST(DerivativeStoreTest, GetAvailableMethodsEmpty) { + auto& store = DerivativeStore::getInstance(); + EXPECT_TRUE(store.isEmpty()); + const auto methods = store.getAvailableMethods(DERIV::Standard, DIRECTION::X); + EXPECT_EQ(methods.size(), 0); +} + +TEST(DerivativeStoreTest, RegisterStandardMethod) { + auto& store = DerivativeStore::getInstance(); + + store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, + "FirstStandard"); + const auto methods = store.getAvailableMethods(DERIV::Standard, DIRECTION::X); + EXPECT_EQ(methods.size(), 1); + + store.reset(); +} + +TEST(DerivativeStoreTest, RegisterStandardMethodAndClear) { + auto& store = DerivativeStore::getInstance(); + + store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, + "FirstStandard"); + + auto methods = store.getAvailableMethods(DERIV::Standard, DIRECTION::X); + EXPECT_EQ(methods.size(), 1); + EXPECT_NE(methods.find("FirstStandard"), methods.end()); + + store.reset(); + methods = store.getAvailableMethods(DERIV::Standard, DIRECTION::X); + EXPECT_EQ(methods.size(), 0); +} + +TEST(DerivativeStoreTest, RegisterMatchingMethodStandardMethodTwice) { + auto& store = DerivativeStore::getInstance(); + + store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, + "FirstStandard"); + auto methods = store.getAvailableMethods(DERIV::Standard, DIRECTION::X); + EXPECT_EQ(methods.size(), 1); + EXPECT_NE(methods.find("FirstStandard"), methods.end()); + + // Register another method with the same key + store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, + "FirstStandard"); + + methods = store.getAvailableMethods(DERIV::Standard, DIRECTION::X); + EXPECT_EQ(methods.size(), 1); + EXPECT_NE(methods.find("FirstStandard"), methods.end()); + + store.reset(); +} + +TEST(DerivativeStoreTest, RegisterMatchingMethodStandardMethodTwo) { + auto& store = DerivativeStore::getInstance(); + + store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, + "FirstStandard"); + auto methods = store.getAvailableMethods(DERIV::Standard, DIRECTION::X); + EXPECT_EQ(methods.size(), 1); + + // Register another method with a different key + store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, + "SecondStandard"); + + methods = store.getAvailableMethods(DERIV::Standard, DIRECTION::X); + EXPECT_EQ(methods.size(), 2); + + EXPECT_NE(methods.find("FirstStandard"), methods.end()); + EXPECT_NE(methods.find("SecondStandard"), methods.end()); + store.reset(); +} + +TEST(DerivativeStoreTest, RegisterStandardSecond) { + auto& store = DerivativeStore::getInstance(); + const DERIV type = DERIV::StandardSecond; + const DIRECTION dir = DIRECTION::X; + + store.registerDerivative(standardType{}, type, dir, STAGGER::None, "FirstStandard"); + auto methods = store.getAvailableMethods(type, dir); + EXPECT_EQ(methods.size(), 1); + EXPECT_NE(methods.find("FirstStandard"), methods.end()); + store.reset(); +} + +TEST(DerivativeStoreTest, RegisterStandardFourth) { + auto& store = DerivativeStore::getInstance(); + const DERIV type = DERIV::StandardFourth; + const DIRECTION dir = DIRECTION::X; + + store.registerDerivative(standardType{}, type, dir, STAGGER::None, "FirstStandard"); + auto methods = store.getAvailableMethods(type, dir); + EXPECT_EQ(methods.size(), 1); + EXPECT_NE(methods.find("FirstStandard"), methods.end()); + store.reset(); +} + +TEST(DerivativeStoreTest, RegisterUpwind) { + auto& store = DerivativeStore::getInstance(); + const DERIV type = DERIV::Upwind; + const DIRECTION dir = DIRECTION::X; + + store.registerDerivative(flowType{}, type, dir, STAGGER::None, "FirstStandard"); + auto methods = store.getAvailableMethods(type, dir); + EXPECT_EQ(methods.size(), 1); + EXPECT_NE(methods.find("FirstStandard"), methods.end()); + store.reset(); +} + +TEST(DerivativeStoreTest, RegisterFlux) { + auto& store = DerivativeStore::getInstance(); + const DERIV type = DERIV::Flux; + const DIRECTION dir = DIRECTION::X; + + store.registerDerivative(flowType{}, type, dir, STAGGER::None, "FirstStandard"); + auto methods = store.getAvailableMethods(type, dir); + EXPECT_EQ(methods.size(), 1); + EXPECT_NE(methods.find("FirstStandard"), methods.end()); + store.reset(); +} + +TEST(DerivativeStoreTest, RegisterStandardAndGetBack) { + auto& store = DerivativeStore::getInstance(); + const DERIV type = DERIV::Standard; + const DIRECTION dir = DIRECTION::X; + const std::string firstName = "FIRSTSTANDARD"; + + store.forceDefaultMethod("UNKNOWN", type, dir, STAGGER::None); + + store.registerDerivative(standardReturnTenSetToOne, type, dir, STAGGER::None, + firstName); + auto methods = store.getAvailableMethods(type, dir); + EXPECT_EQ(methods.size(), 1); + EXPECT_NE(methods.find(firstName), methods.end()); + + // Note pass functions around by value etc. so we can't just compare the address + // of the returned function against the original method. + standardType returned = store.getStandardDerivative(firstName, dir); + + FieldType inOrig, outOrig; + standardReturnTenSetToOne(inOrig, outOrig); + + FieldType outRet; + returned(inOrig, outRet, RGN_ALL); + + EXPECT_EQ(outOrig.size(), 10); + ASSERT_EQ(outRet.size(), outOrig.size()); + + for (unsigned int i = 0; i < outOrig.size(); i++) { + EXPECT_EQ(outOrig[i], outRet[i]); + }; + + store.reset(); +} + +TEST(DerivativeStoreTest, RegisterFlowAndGetBack) { + auto& store = DerivativeStore::getInstance(); + const DERIV type = DERIV::Upwind; + const DIRECTION dir = DIRECTION::X; + const std::string firstName = "FIRSTSTANDARD"; + + store.forceDefaultMethod("UNKNOWN", type, dir, STAGGER::None); + + store.registerDerivative(flowReturnSixSetToTwo, type, dir, STAGGER::None, firstName); + auto methods = store.getAvailableMethods(type, dir); + EXPECT_EQ(methods.size(), 1); + EXPECT_NE(methods.find(firstName), methods.end()); + + // Note pass functions around by value etc. so we can't just compare the address + // of the returned function against the original method. + flowType returned = store.getUpwindDerivative(firstName, dir); + + FieldType inOrig, outOrig; + flowReturnSixSetToTwo(inOrig, inOrig, outOrig); + + FieldType outRet; + returned(inOrig, inOrig, outRet, RGN_ALL); + + EXPECT_EQ(outOrig.size(), 6); + ASSERT_EQ(outRet.size(), outOrig.size()); + + for (unsigned int i = 0; i < outOrig.size(); i++) { + EXPECT_EQ(outOrig[i], outRet[i]); + }; + + store.reset(); +} From d887cac0dc85b8836a553f45cf8634c94c5f8023 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 21 Nov 2018 15:03:43 +0000 Subject: [PATCH 0313/1783] Ensure attempts to override previously registered methods fail. --- include/bout/deriv_store.hxx | 25 ++++++++++++++++++++ tests/unit/include/bout/test_deriv_store.cxx | 7 +++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 1bebc66da6..afa3f13ee6 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -139,12 +139,27 @@ struct DerivativeStore { switch (derivType) { case (DERIV::Standard): + if(standard.count(key) != 0) { + throw BoutException("Trying to override standard derivative : " + "direction %s, stagger %s, key %s", + DIRECTION_STRING(direction).c_str(), STAGGER_STRING(stagger).c_str(), methodName.c_str()); + } standard[key] = func; return; case (DERIV::StandardSecond): + if(standardSecond.count(key) != 0) { + throw BoutException("Trying to override standardSecond derivative : " + "direction %s, stagger %s, key %s", + DIRECTION_STRING(direction).c_str(), STAGGER_STRING(stagger).c_str(), methodName.c_str()); + } standardSecond[key] = func; return; case (DERIV::StandardFourth): + if(standardFourth.count(key) != 0) { + throw BoutException("Trying to override standardFourth derivative : " + "direction %s, stagger %s, key %s", + DIRECTION_STRING(direction).c_str(), STAGGER_STRING(stagger).c_str(), methodName.c_str()); + } standardFourth[key] = func; return; default: @@ -168,9 +183,19 @@ struct DerivativeStore { switch (derivType) { case (DERIV::Upwind): + if(upwind.count(key) != 0) { + throw BoutException("Trying to override upwind derivative : " + "direction %s, stagger %s, key %s", + DIRECTION_STRING(direction).c_str(), STAGGER_STRING(stagger).c_str(), methodName.c_str()); + } upwind[key] = func; return; case (DERIV::Flux): + if(flux.count(key) != 0) { + throw BoutException("Trying to override flux derivative : " + "direction %s, stagger %s, key %s", + DIRECTION_STRING(direction).c_str(), STAGGER_STRING(stagger).c_str(), methodName.c_str()); + } flux[key] = func; return; default: diff --git a/tests/unit/include/bout/test_deriv_store.cxx b/tests/unit/include/bout/test_deriv_store.cxx index 8012848daa..ea00f6468a 100644 --- a/tests/unit/include/bout/test_deriv_store.cxx +++ b/tests/unit/include/bout/test_deriv_store.cxx @@ -79,9 +79,10 @@ TEST(DerivativeStoreTest, RegisterMatchingMethodStandardMethodTwice) { EXPECT_EQ(methods.size(), 1); EXPECT_NE(methods.find("FirstStandard"), methods.end()); - // Register another method with the same key - store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, - "FirstStandard"); + // Try to register another method with the same key + EXPECT_THROW(store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, + STAGGER::None, "FirstStandard"), + BoutException); methods = store.getAvailableMethods(DERIV::Standard, DIRECTION::X); EXPECT_EQ(methods.size(), 1); From 21d400cc5997406bed37d688d99111f12c99217d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 21 Nov 2018 15:14:38 +0000 Subject: [PATCH 0314/1783] Add implementation for Identity parallel transform + tests --- include/bout/paralleltransform.hxx | 2 +- src/mesh/parallel/identity.cxx | 11 +++++++ src/mesh/parallel/makefile | 2 +- tests/unit/mesh/test_paralleltransform.cxx | 37 ++++++++++++++++++++++ 4 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src/mesh/parallel/identity.cxx create mode 100644 tests/unit/mesh/test_paralleltransform.cxx diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index a25540354a..9308b8dad9 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -59,7 +59,7 @@ public: * Merges the yup and ydown() fields of f, so that * f.yup() = f.ydown() = f */ - void calcYUpDown(Field3D &f) override {f.mergeYupYdown();} + void calcYUpDown(Field3D &f) override; /*! * The field is already aligned in Y, so this diff --git a/src/mesh/parallel/identity.cxx b/src/mesh/parallel/identity.cxx new file mode 100644 index 0000000000..437d04178b --- /dev/null +++ b/src/mesh/parallel/identity.cxx @@ -0,0 +1,11 @@ +#include "bout/paralleltransform.hxx" +#include "bout/mesh.hxx" + +void ParallelTransformIdentity::calcYUpDown(Field3D& f) { + f.splitYupYdown(); + + for (int i = 0; i < f.getMesh()->ystart; ++i) { + f.yup(i) = f; + f.ydown(i) = f; + } +} diff --git a/src/mesh/parallel/makefile b/src/mesh/parallel/makefile index 9c4817b008..2e522318de 100644 --- a/src/mesh/parallel/makefile +++ b/src/mesh/parallel/makefile @@ -2,7 +2,7 @@ BOUT_TOP = ../../.. DIRS = -SOURCEC = shiftedmetric.cxx fci.cxx +SOURCEC = shiftedmetric.cxx fci.cxx identity.cxx TARGET = lib include $(BOUT_TOP)/make.config diff --git a/tests/unit/mesh/test_paralleltransform.cxx b/tests/unit/mesh/test_paralleltransform.cxx new file mode 100644 index 0000000000..6550243b2a --- /dev/null +++ b/tests/unit/mesh/test_paralleltransform.cxx @@ -0,0 +1,37 @@ +#include "gtest/gtest.h" + +#include "test_extras.hxx" +#include "bout/paralleltransform.hxx" + +extern Mesh* mesh; + +using ParallelTransformTest = FakeMeshFixture; + +TEST_F(ParallelTransformTest, IdentityCalcYUpDown) { + + ParallelTransformIdentity transform{}; + + Field3D field{1.0}; + + transform.calcYUpDown(field); + + EXPECT_TRUE(IsField3DEqualBoutReal(field.yup(), 1.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(field.ydown(), 1.0)); +} + +TEST_F(ParallelTransformTest, IdentityCalcYUpDownTwoSlices) { + + ParallelTransformIdentity transform{}; + + mesh->ystart = 2; + + Field3D field{1.0}; + + transform.calcYUpDown(field); + + EXPECT_TRUE(IsField3DEqualBoutReal(field.yup(0), 1.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(field.yup(1), 1.0)); + + EXPECT_TRUE(IsField3DEqualBoutReal(field.ydown(0), 1.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(field.ydown(1), 1.0)); +} From 02b4371ce04eca2eb06ef1f8896f5edca3974f84 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 12 Jul 2018 17:36:10 +0100 Subject: [PATCH 0315/1783] Add implementation of make_unique --- include/utils.hxx | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/include/utils.hxx b/include/utils.hxx index 76aa01d431..8f4ba5278c 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -43,6 +43,43 @@ #include #include #include +#include + +#ifndef __cpp_lib_make_unique +// Provide our own make_unique if the stl doesn't give us one +// Implementation from https://isocpp.org/files/papers/N3656.txt +// i.e. what's already in the stl + +template struct _Unique_if { + using _Single_object = std::unique_ptr; +}; + +template struct _Unique_if { + using _Unknown_bound = std::unique_ptr; +}; + +template struct _Unique_if { + using _Known_bound = void; +}; + +template +typename _Unique_if::_Single_object +make_unique(Args&&... args) { + return std::unique_ptr(new T(std::forward(args)...)); +} + +template +typename _Unique_if::_Unknown_bound +make_unique(size_t n) { + using U = typename std::remove_extent::type; + return std::unique_ptr(new U[n]()); +} + +template +typename _Unique_if::_Known_bound +make_unique(Args&&...) = delete; + +#endif /// Helper class for 2D arrays /// From 43fc333ce1875933c40eb24498de3312b9888b82 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 12 Jul 2018 17:37:44 +0100 Subject: [PATCH 0316/1783] Use make_unique where type is named twice --- src/fileio/formatfactory.cxx | 22 +++++++++++-------- .../impls/multigrid/multigrid_laplace.cxx | 8 +++++-- .../impls/multigrid/multigrid_solver.cxx | 10 ++++----- src/invert/laplacexy/laplacexy.cxx | 4 +--- src/mesh/mesh.cxx | 10 ++++++--- tests/unit/mesh/test_interpolation.cxx | 7 ++++-- 6 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/fileio/formatfactory.cxx b/src/fileio/formatfactory.cxx index f71faeb833..30ab77966d 100644 --- a/src/fileio/formatfactory.cxx +++ b/src/fileio/formatfactory.cxx @@ -14,6 +14,10 @@ #include #include +#ifdef __cpp_lib_make_unique +using std::make_unique; +#endif + FormatFactory *FormatFactory::instance = nullptr; FormatFactory* FormatFactory::getInstance() { @@ -32,20 +36,20 @@ std::unique_ptr FormatFactory::createDataFormat(const char *filename if (parallel) { #ifdef PNCDF - return std::unique_ptr(new PncFormat); + return make_unique(); #else } #ifdef NCDF4 - return std::unique_ptr(new Ncxx4); + return make_unique(); #else #ifdef NCDF - return std::unique_ptr(new NcFormat); + return make_unique(); #else #ifdef HDF5 - return std::unique_ptr(new H5Format); + return make_unique(); #else #error No file format available; aborting. @@ -75,7 +79,7 @@ std::unique_ptr FormatFactory::createDataFormat(const char *filename const char *pncdf_match[] = {"cdl", "nc", "ncdf"}; if(matchString(s, 3, pncdf_match) != -1) { output.write("\tUsing Parallel NetCDF format for file '%s'\n", filename); - return std::unique_ptr(new PncFormat); + return make_unique(); } } #endif @@ -84,7 +88,7 @@ std::unique_ptr FormatFactory::createDataFormat(const char *filename const char *ncdf_match[] = {"cdl", "nc", "ncdf"}; if(matchString(s, 3, ncdf_match) != -1) { output.write("\tUsing NetCDF4 format for file '%s'\n", filename); - return std::unique_ptr(new Ncxx4); + return make_unique(); } #endif @@ -92,7 +96,7 @@ std::unique_ptr FormatFactory::createDataFormat(const char *filename const char *ncdf_match[] = {"cdl", "nc", "ncdf"}; if(matchString(s, 3, ncdf_match) != -1) { output.write("\tUsing NetCDF format for file '%s'\n", filename); - return std::unique_ptr(new NcFormat); + return make_unique(); } #endif @@ -101,9 +105,9 @@ std::unique_ptr FormatFactory::createDataFormat(const char *filename if(matchString(s, 3, hdf5_match) != -1) { output.write("\tUsing HDF5 format for file '%s'\n", filename); #ifdef PHDF5 - return std::unique_ptr(new H5Format(parallel)); + return make_unique(parallel); #else - return std::unique_ptr(new H5Format()); + return make_unique(); #endif } #endif diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index d3e419e54f..cbc2016230 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -41,6 +41,10 @@ LaplaceMultigrid::LaplaceMultigrid(Options *opt, const CELL_LOC loc, Mesh *mesh_ Laplacian(opt, loc, mesh_in), A(0.0), C1(1.0), C2(1.0), D(1.0) { +#ifdef __cpp_lib_make_unique + using std::make_unique; +#endif + TRACE("LaplaceMultigrid::LaplaceMultigrid(Options *opt)"); A.setLocation(location); @@ -159,8 +163,8 @@ LaplaceMultigrid::LaplaceMultigrid(Options *opt, const CELL_LOC loc, Mesh *mesh_ else aclevel = 1; adlevel = mglevel - aclevel; - kMG = std::unique_ptr(new Multigrid1DP( - aclevel, Nx_local, Nz_local, Nx_global, adlevel, mgmpi, commX, pcheck)); + kMG = make_unique(aclevel, Nx_local, Nz_local, Nx_global, adlevel, mgmpi, + commX, pcheck); kMG->mgplag = mgplag; kMG->mgsm = mgsm; kMG->cftype = cftype; diff --git a/src/invert/laplace/impls/multigrid/multigrid_solver.cxx b/src/invert/laplace/impls/multigrid/multigrid_solver.cxx index 8bfdba7a11..56d2682665 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_solver.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_solver.cxx @@ -125,8 +125,8 @@ Multigrid1DP::Multigrid1DP(int level,int lx, int lz, int gx, int dl, int merge, int colors = rProcI/nz; int keys = rProcI/nz; MPI_Comm_split(commMG,colors,keys,&comm2D); - rMG = std::unique_ptr(new Multigrid2DPf1D( - kk, lx, lz, gnx[0], lnz[0], dl - kk + 1, nx, nz, commMG, pcheck)); + rMG = make_unique(kk, lx, lz, gnx[0], lnz[0], dl - kk + 1, nx, nz, + commMG, pcheck); } else { int nn = gnx[0]; @@ -144,8 +144,7 @@ Multigrid1DP::Multigrid1DP(int level,int lx, int lz, int gx, int dl, int merge, output <<"To Ser "<( - new MultigridSerial(kk, gnx[0], lnz[0], commMG, pcheck)); + sMG = make_unique(kk, gnx[0], lnz[0], commMG, pcheck); } } else kflag = 0; @@ -552,8 +551,7 @@ Multigrid2DPf1D::Multigrid2DPf1D(int level,int lx,int lz, int gx, int gz, output <<"total dim"<( - new MultigridSerial(kk, gnx[0], gnz[0], commMG, pcheck)); + sMG = make_unique(kk, gnx[0], gnz[0], commMG, pcheck); } else kflag = 0; } diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index 78ca7a990e..34ac81a1e3 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -92,9 +92,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat bvals = Matrix(nsys, nloc); // Create a cyclic reduction object - // FIXME: replace with make_unique when we upgrade to C++14 or add our own version - cr = std::unique_ptr>( - new CyclicReduce(mesh->getXcomm(), nloc)); + cr = make_unique>(mesh->getXcomm(), nloc); ////////////////////////////////////////////////// // Pre-allocate PETSc storage diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 740ae1a8a1..3dd35508ae 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -287,6 +287,10 @@ const std::vector Mesh::readInts(const std::string &name, int n) { void Mesh::setParallelTransform() { +#ifdef __cpp_lib_make_unique + using std::make_unique; +#endif + std::string ptstr; options->get("paralleltransform", ptstr, "identity"); @@ -295,11 +299,11 @@ void Mesh::setParallelTransform() { if(ptstr == "identity") { // Identity method i.e. no transform needed - transform = std::unique_ptr(new ParallelTransformIdentity()); + transform = make_unique(); }else if(ptstr == "shifted") { // Shifted metric method - transform = std::unique_ptr(new ShiftedMetric(*this)); + transform = make_unique(*this); }else if(ptstr == "fci") { @@ -307,7 +311,7 @@ void Mesh::setParallelTransform() { // Flux Coordinate Independent method bool fci_zperiodic; fci_options->get("z_periodic", fci_zperiodic, true); - transform = std::unique_ptr(new FCITransform(*this, fci_zperiodic)); + transform = make_unique(*this, fci_zperiodic); }else { throw BoutException(_("Unrecognised paralleltransform option.\n" diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index 9f9406358c..e458d20934 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -42,6 +42,10 @@ class Field3DInterpToTest : public ::testing::Test { } static void SetUpTestCase() { +#ifdef __cpp_lib_make_unique + using std::make_unique; +#endif + // Delete any existing mesh if (mesh != nullptr) { delete mesh; @@ -53,8 +57,7 @@ class Field3DInterpToTest : public ::testing::Test { mesh->ystart = 2; mesh->xend = nx - 3; mesh->yend = ny - 3; - mesh->setParallelTransform( - std::unique_ptr(new ParallelTransformIdentity())); + mesh->setParallelTransform(make_unique()); output_info.disable(); mesh->createDefaultRegions(); output_info.enable(); From 90dbb13db165338bf758e8ea4e323423e6a465b7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 22 Nov 2018 12:19:36 +0000 Subject: [PATCH 0317/1783] Add basic Python wrapper for BoutException --- tools/pylib/_boutcore_build/boutcore.pyx.in | 23 +++++++++++-------- tools/pylib/_boutcore_build/boutcpp.pxd.in | 8 +++++-- .../_boutcore_build/boutexception_helper.cxx | 11 +++++++++ .../_boutcore_build/boutexception_helper.hxx | 1 + 4 files changed, 31 insertions(+), 12 deletions(-) mode change 100644 => 100755 tools/pylib/_boutcore_build/boutcpp.pxd.in create mode 100644 tools/pylib/_boutcore_build/boutexception_helper.cxx create mode 100644 tools/pylib/_boutcore_build/boutexception_helper.hxx diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 63559f9786..6fc125bfd6 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -42,7 +42,7 @@ cat < + +void raise_bout_py_error() { + try { + throw; + } catch (const BoutException& e) { + PyErr_SetString(PyExc_RuntimeError, e.getBacktrace().c_str()); + } +} + diff --git a/tools/pylib/_boutcore_build/boutexception_helper.hxx b/tools/pylib/_boutcore_build/boutexception_helper.hxx new file mode 100644 index 0000000000..55f2f8f524 --- /dev/null +++ b/tools/pylib/_boutcore_build/boutexception_helper.hxx @@ -0,0 +1 @@ +extern const char* raise_bout_py_error(); From f7bb047d72464c9314d4467876b0bb355405eb82 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 22 Nov 2018 14:19:37 +0000 Subject: [PATCH 0318/1783] Put make_unique in bout::utils namespace bout::utils::make_unique always exists but falls back to std::make_unique if that is available --- include/utils.hxx | 32 +++++++++++-------- src/fileio/formatfactory.cxx | 22 ++++++------- .../impls/multigrid/multigrid_laplace.cxx | 8 ++--- .../impls/multigrid/multigrid_solver.cxx | 11 +++---- src/invert/laplacexy/laplacexy.cxx | 2 +- src/mesh/mesh.cxx | 10 ++---- tests/unit/mesh/test_interpolation.cxx | 5 +-- 7 files changed, 39 insertions(+), 51 deletions(-) diff --git a/include/utils.hxx b/include/utils.hxx index 8f4ba5278c..18bd168a04 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -45,41 +45,45 @@ #include #include +namespace bout { +namespace utils { #ifndef __cpp_lib_make_unique // Provide our own make_unique if the stl doesn't give us one // Implementation from https://isocpp.org/files/papers/N3656.txt // i.e. what's already in the stl - -template struct _Unique_if { +template +struct _Unique_if { using _Single_object = std::unique_ptr; }; -template struct _Unique_if { +template +struct _Unique_if { using _Unknown_bound = std::unique_ptr; }; -template struct _Unique_if { +template +struct _Unique_if { using _Known_bound = void; }; -template -typename _Unique_if::_Single_object -make_unique(Args&&... args) { +template +typename _Unique_if::_Single_object make_unique(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } -template -typename _Unique_if::_Unknown_bound -make_unique(size_t n) { +template +typename _Unique_if::_Unknown_bound make_unique(size_t n) { using U = typename std::remove_extent::type; return std::unique_ptr(new U[n]()); } -template -typename _Unique_if::_Known_bound -make_unique(Args&&...) = delete; - +template +typename _Unique_if::_Known_bound make_unique(Args&&...) = delete; +#else +using std::make_unique; #endif +} // namespace utils +} // namespace bout /// Helper class for 2D arrays /// diff --git a/src/fileio/formatfactory.cxx b/src/fileio/formatfactory.cxx index 30ab77966d..3980d24047 100644 --- a/src/fileio/formatfactory.cxx +++ b/src/fileio/formatfactory.cxx @@ -14,10 +14,6 @@ #include #include -#ifdef __cpp_lib_make_unique -using std::make_unique; -#endif - FormatFactory *FormatFactory::instance = nullptr; FormatFactory* FormatFactory::getInstance() { @@ -36,20 +32,20 @@ std::unique_ptr FormatFactory::createDataFormat(const char *filename if (parallel) { #ifdef PNCDF - return make_unique(); + return bout::utils::make_unique(); #else } #ifdef NCDF4 - return make_unique(); + return bout::utils::make_unique(); #else #ifdef NCDF - return make_unique(); + return bout::utils::make_unique(); #else #ifdef HDF5 - return make_unique(); + return bout::utils::make_unique(); #else #error No file format available; aborting. @@ -79,7 +75,7 @@ std::unique_ptr FormatFactory::createDataFormat(const char *filename const char *pncdf_match[] = {"cdl", "nc", "ncdf"}; if(matchString(s, 3, pncdf_match) != -1) { output.write("\tUsing Parallel NetCDF format for file '%s'\n", filename); - return make_unique(); + return bout::utils::make_unique(); } } #endif @@ -88,7 +84,7 @@ std::unique_ptr FormatFactory::createDataFormat(const char *filename const char *ncdf_match[] = {"cdl", "nc", "ncdf"}; if(matchString(s, 3, ncdf_match) != -1) { output.write("\tUsing NetCDF4 format for file '%s'\n", filename); - return make_unique(); + return bout::utils::make_unique(); } #endif @@ -96,7 +92,7 @@ std::unique_ptr FormatFactory::createDataFormat(const char *filename const char *ncdf_match[] = {"cdl", "nc", "ncdf"}; if(matchString(s, 3, ncdf_match) != -1) { output.write("\tUsing NetCDF format for file '%s'\n", filename); - return make_unique(); + return bout::utils::make_unique(); } #endif @@ -105,9 +101,9 @@ std::unique_ptr FormatFactory::createDataFormat(const char *filename if(matchString(s, 3, hdf5_match) != -1) { output.write("\tUsing HDF5 format for file '%s'\n", filename); #ifdef PHDF5 - return make_unique(parallel); + return bout::utils::make_unique(parallel); #else - return make_unique(); + return bout::utils::make_unique(); #endif } #endif diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index cbc2016230..a2512ea73d 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -41,10 +41,6 @@ LaplaceMultigrid::LaplaceMultigrid(Options *opt, const CELL_LOC loc, Mesh *mesh_ Laplacian(opt, loc, mesh_in), A(0.0), C1(1.0), C2(1.0), D(1.0) { -#ifdef __cpp_lib_make_unique - using std::make_unique; -#endif - TRACE("LaplaceMultigrid::LaplaceMultigrid(Options *opt)"); A.setLocation(location); @@ -163,8 +159,8 @@ LaplaceMultigrid::LaplaceMultigrid(Options *opt, const CELL_LOC loc, Mesh *mesh_ else aclevel = 1; adlevel = mglevel - aclevel; - kMG = make_unique(aclevel, Nx_local, Nz_local, Nx_global, adlevel, mgmpi, - commX, pcheck); + kMG = bout::utils::make_unique(aclevel, Nx_local, Nz_local, Nx_global, + adlevel, mgmpi, commX, pcheck); kMG->mgplag = mgplag; kMG->mgsm = mgsm; kMG->cftype = cftype; diff --git a/src/invert/laplace/impls/multigrid/multigrid_solver.cxx b/src/invert/laplace/impls/multigrid/multigrid_solver.cxx index 56d2682665..47daecfae6 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_solver.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_solver.cxx @@ -125,10 +125,9 @@ Multigrid1DP::Multigrid1DP(int level,int lx, int lz, int gx, int dl, int merge, int colors = rProcI/nz; int keys = rProcI/nz; MPI_Comm_split(commMG,colors,keys,&comm2D); - rMG = make_unique(kk, lx, lz, gnx[0], lnz[0], dl - kk + 1, nx, nz, - commMG, pcheck); - } - else { + rMG = bout::utils::make_unique( + kk, lx, lz, gnx[0], lnz[0], dl - kk + 1, nx, nz, commMG, pcheck); + } else { int nn = gnx[0]; int mm = gnz[0]; int kk = 1; @@ -144,7 +143,7 @@ Multigrid1DP::Multigrid1DP(int level,int lx, int lz, int gx, int dl, int merge, output <<"To Ser "<(kk, gnx[0], lnz[0], commMG, pcheck); + sMG = bout::utils::make_unique(kk, gnx[0], lnz[0], commMG, pcheck); } } else kflag = 0; @@ -551,7 +550,7 @@ Multigrid2DPf1D::Multigrid2DPf1D(int level,int lx,int lz, int gx, int gz, output <<"total dim"<(kk, gnx[0], gnz[0], commMG, pcheck); + sMG = bout::utils::make_unique(kk, gnx[0], gnz[0], commMG, pcheck); } else kflag = 0; } diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index 34ac81a1e3..5e5a5a4f93 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -92,7 +92,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat bvals = Matrix(nsys, nloc); // Create a cyclic reduction object - cr = make_unique>(mesh->getXcomm(), nloc); + cr = bout::utils::make_unique>(mesh->getXcomm(), nloc); ////////////////////////////////////////////////// // Pre-allocate PETSc storage diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 3dd35508ae..73bca69767 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -287,10 +287,6 @@ const std::vector Mesh::readInts(const std::string &name, int n) { void Mesh::setParallelTransform() { -#ifdef __cpp_lib_make_unique - using std::make_unique; -#endif - std::string ptstr; options->get("paralleltransform", ptstr, "identity"); @@ -299,11 +295,11 @@ void Mesh::setParallelTransform() { if(ptstr == "identity") { // Identity method i.e. no transform needed - transform = make_unique(); + transform = bout::utils::make_unique(); }else if(ptstr == "shifted") { // Shifted metric method - transform = make_unique(*this); + transform = bout::utils::make_unique(*this); }else if(ptstr == "fci") { @@ -311,7 +307,7 @@ void Mesh::setParallelTransform() { // Flux Coordinate Independent method bool fci_zperiodic; fci_options->get("z_periodic", fci_zperiodic, true); - transform = make_unique(*this, fci_zperiodic); + transform = bout::utils::make_unique(*this, fci_zperiodic); }else { throw BoutException(_("Unrecognised paralleltransform option.\n" diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index e458d20934..f48b5c5c52 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -42,9 +42,6 @@ class Field3DInterpToTest : public ::testing::Test { } static void SetUpTestCase() { -#ifdef __cpp_lib_make_unique - using std::make_unique; -#endif // Delete any existing mesh if (mesh != nullptr) { @@ -57,7 +54,7 @@ class Field3DInterpToTest : public ::testing::Test { mesh->ystart = 2; mesh->xend = nx - 3; mesh->yend = ny - 3; - mesh->setParallelTransform(make_unique()); + mesh->setParallelTransform(bout::utils::make_unique()); output_info.disable(); mesh->createDefaultRegions(); output_info.enable(); From fcc95fe5be667e2a7a4e3bda6e922dbb1133a2d9 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 22 Nov 2018 14:24:18 +0000 Subject: [PATCH 0319/1783] Move working space to be local to the solve routine. Can be helpful to avoid threading issues --- src/invert/parderiv/impls/serial/serial.cxx | 15 +++++++++------ src/invert/parderiv/impls/serial/serial.hxx | 5 ----- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/invert/parderiv/impls/serial/serial.cxx b/src/invert/parderiv/impls/serial/serial.cxx index 65b56ed8e8..064a4bedff 100644 --- a/src/invert/parderiv/impls/serial/serial.cxx +++ b/src/invert/parderiv/impls/serial/serial.cxx @@ -53,12 +53,6 @@ InvertParSerial::InvertParSerial(Options *opt, Mesh *mesh_in) : InvertPar(opt, mesh_in), A(1.0), B(0.0), C(0.0), D(0.0), E(0.0) { - rhs = Matrix(localmesh->LocalNy, (localmesh->LocalNz)/2 + 1); - rhsk = Array(localmesh->LocalNy-4); - xk = Array(localmesh->LocalNy-4); - a = Array(localmesh->LocalNy-4); - b = Array(localmesh->LocalNy-4); - c = Array(localmesh->LocalNy-4); } const Field3D InvertParSerial::solve(const Field3D &f) { @@ -72,6 +66,15 @@ const Field3D InvertParSerial::solve(const Field3D &f) { Coordinates *coord = f.getCoordinates(); + // The following is the number of nonguard points + const int ny = localmesh->LocalNy - 2 * localmesh->ystart; + + auto rhs = Matrix(localmesh->LocalNy, (localmesh->LocalNz) / 2 + 1); + auto rhsk = Array(ny); + auto xk = Array(ny); + auto a = Array(ny); + auto b = Array(ny); + auto c = Array(ny); // Loop over flux-surfaces SurfaceIter surf(localmesh); for(surf.first(); !surf.isDone(); surf.next()) { diff --git a/src/invert/parderiv/impls/serial/serial.hxx b/src/invert/parderiv/impls/serial/serial.hxx index 547c5be5d4..ba3c1769db 100644 --- a/src/invert/parderiv/impls/serial/serial.hxx +++ b/src/invert/parderiv/impls/serial/serial.hxx @@ -81,11 +81,6 @@ public: private: Field2D A, B, C, D, E; - - Matrix rhs; - Array rhsk; - Array xk; - Array a, b, c; // Matrix coefficients }; From cd24711d0d55122d161fa07db4a2cf725b5af548 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 22 Nov 2018 14:25:01 +0000 Subject: [PATCH 0320/1783] Convert to/from field aligned in parallel inversion --- src/invert/parderiv/impls/serial/serial.cxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/invert/parderiv/impls/serial/serial.cxx b/src/invert/parderiv/impls/serial/serial.cxx index 064a4bedff..fed664324b 100644 --- a/src/invert/parderiv/impls/serial/serial.cxx +++ b/src/invert/parderiv/impls/serial/serial.cxx @@ -75,6 +75,9 @@ const Field3D InvertParSerial::solve(const Field3D &f) { auto a = Array(ny); auto b = Array(ny); auto c = Array(ny); + + Field3D alignedField = localmesh->toFieldAligned(f); + // Loop over flux-surfaces SurfaceIter surf(localmesh); for(surf.first(); !surf.isDone(); surf.next()) { @@ -135,5 +138,7 @@ const Field3D InvertParSerial::solve(const Field3D &f) { } return result; + + return localmesh->fromFieldAligned(result); } From a0b1eefcc7e1e64e9cc496d880f41c68a984ac0c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 22 Nov 2018 14:25:22 +0000 Subject: [PATCH 0321/1783] Remove assumption that MYG=0 in serial implementation of parderiv --- src/invert/parderiv/impls/serial/serial.cxx | 75 +++++++++++---------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/src/invert/parderiv/impls/serial/serial.cxx b/src/invert/parderiv/impls/serial/serial.cxx index fed664324b..bde5ed79b4 100644 --- a/src/invert/parderiv/impls/serial/serial.cxx +++ b/src/invert/parderiv/impls/serial/serial.cxx @@ -86,58 +86,59 @@ const Field3D InvertParSerial::solve(const Field3D &f) { if(!surf.closed(ts)) throw BoutException("InvertParSerial doesn't handle open surfaces"); - // Take Fourier transform - for(int y=0;yLocalNy-4;y++) - rfft(f(x,y+2), localmesh->LocalNz, &rhs(y, 0)); - + // Take Fourier transform + for (int y = localmesh->ystart; y <= localmesh->yend; y++) + rfft(alignedField(x, y), localmesh->LocalNz, &rhs(y - localmesh->ystart, 0)); + // Solve cyclic tridiagonal system for each k - int nyq = (localmesh->LocalNz)/2; + const int nyq = (localmesh->LocalNz) / 2; + const BoutReal waveFac = TWOPI / coord->zlength(); for(int k=0;k<=nyq;k++) { // Copy component of rhs into 1D array - for(int y=0;yLocalNy-4;y++) + for (int y = 0; y < ny; y++) rhsk[y] = rhs(y, k); - - BoutReal kwave=k*2.0*PI/coord->zlength(); // wave number is 1/[rad] - + + BoutReal kwave = k * waveFace; // wave number is 1/[rad] + // Set up tridiagonal system - for(int y=0;yLocalNy-4;y++) { - BoutReal acoef = A(x, y+2); // Constant - BoutReal bcoef = B(x, y+2) / coord->g_22(x,y+2); // d2dy2 - BoutReal ccoef = C(x, y+2); // d2dydz - BoutReal dcoef = D(x, y+2); // d2dz2 - BoutReal ecoef = E(x, y+2); // ddy - - bcoef /= SQ(coord->dy(x, y+2)); - ccoef /= coord->dy(x,y+2)*coord->dz; + for (int y = localmesh->ystart; y <= localmesh->yend; y++) { + BoutReal acoef = A(x, y); // Constant + BoutReal bcoef = B(x, y) / coord->g_22(x, y); // d2dy2 + BoutReal ccoef = C(x, y); // d2dydz + BoutReal dcoef = D(x, y); // d2dz2 + BoutReal ecoef = E(x, y); // ddy + + bcoef /= SQ(coord->dy(x, y)); + ccoef /= coord->dy(x, y) * coord->dz; dcoef /= SQ(coord->dz); - ecoef /= coord->dy(x,y+2); - - // const d2dy2 d2dydz d2dz2 ddy - // ----- ----- ------ ----- --- - a[y] = bcoef - 0.5*Im*kwave*ccoef -0.5*ecoef; - b[y] = acoef - 2.*bcoef - SQ(kwave)*dcoef; - c[y] = bcoef + 0.5*Im*kwave*ccoef +0.5*ecoef; + ecoef /= coord->dy(x, y); + + // const d2dy2 d2dydz d2dz2 ddy + // ----- ----- ------ ----- --- + a[y - localmesh->ystart] = bcoef - 0.5 * Im * kwave * ccoef - 0.5 * ecoef; + b[y - localmesh->ystart] = acoef - 2. * bcoef - SQ(kwave) * dcoef; + c[y - localmesh->ystart] = bcoef + 0.5 * Im * kwave * ccoef + 0.5 * ecoef; } - - // Modify coefficients across twist-shift + + // Modify coefficients across twist-shift -- accounts for pseudo-periodicity + // across y-boundary to produce periodic value dcomplex phase(cos(kwave*ts) , -sin(kwave*ts)); a[0] *= phase; - c[localmesh->LocalNy-5] /= phase; - + c[ny - 1] /= phase; + // Solve cyclic tridiagonal system - cyclic_tridag(std::begin(a), std::begin(b), std::begin(c), std::begin(rhsk), std::begin(xk), localmesh->LocalNy-4); - + cyclic_tridag(std::begin(a), std::begin(b), std::begin(c), std::begin(rhsk), + std::begin(xk), ny); + // Put back into rhs array - for(int y=0;yLocalNy-4;y++) + for (int y = 0; y < ny; y++) rhs(y, k) = xk[y]; } - // Inverse Fourier transform - for(int y=0;yLocalNy-4;y++) - irfft(&rhs(y, 0), localmesh->LocalNz, result(x,y+2)); + // Inverse Fourier transform + for (int y = localmesh->ystart; y <= localmesh->yend; y++) + irfft(&rhs(y - localmesh->ystart, 0), localmesh->LocalNz, result(x, y)); } - - return result; return localmesh->fromFieldAligned(result); } From a539d11299e3eaaf8ed54aa58f4335dc604f8617 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 22 Nov 2018 14:44:12 +0000 Subject: [PATCH 0322/1783] Fix typo --- src/invert/parderiv/impls/serial/serial.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/invert/parderiv/impls/serial/serial.cxx b/src/invert/parderiv/impls/serial/serial.cxx index bde5ed79b4..849c91c7b9 100644 --- a/src/invert/parderiv/impls/serial/serial.cxx +++ b/src/invert/parderiv/impls/serial/serial.cxx @@ -98,7 +98,7 @@ const Field3D InvertParSerial::solve(const Field3D &f) { for (int y = 0; y < ny; y++) rhsk[y] = rhs(y, k); - BoutReal kwave = k * waveFace; // wave number is 1/[rad] + BoutReal kwave = k * waveFac; // wave number is 1/[rad] // Set up tridiagonal system for (int y = localmesh->ystart; y <= localmesh->yend; y++) { From a89e70b32a7b61d4f88a9064d78a9d593f6188e5 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 22 Nov 2018 14:48:52 +0000 Subject: [PATCH 0323/1783] Remove assumption about number of guard cells and ensure we use field aligned field --- src/invert/parderiv/impls/cyclic/cyclic.cxx | 63 +++++++++++---------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index 2dfc7c2de3..b1b6946f9d 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -56,18 +56,18 @@ InvertParCR::InvertParCR(Options *opt, Mesh *mesh_in) rhs = Matrix(localmesh->LocalNy, nsys); // Find out if we are on a boundary - int size = localmesh->LocalNy-4; + int size = localmesh->LocalNy - 2 * localmesh->ystart; SurfaceIter surf(localmesh); for(surf.first(); !surf.isDone(); surf.next()) { BoutReal ts; - int n = localmesh->LocalNy-4; + int n = localmesh->LocalNy - 2 * localmesh->ystart; if(!surf.closed(ts)) { // Open field line if(surf.firstY()) - n += 2; + n += localmesh->ystart; if(surf.lastY()) - n += 2; - + n += localmesh->ystart; + if(n > size) size = n; // Maximum size } @@ -92,7 +92,9 @@ const Field3D InvertParCR::solve(const Field3D &f) { result.setLocation(f.getLocation()); Coordinates *coord = f.getCoordinates(); - + + Field3D alignedField = localmesh->toFieldAligned(f); + // Create cyclic reduction object CyclicReduce *cr = new CyclicReduce(); @@ -107,40 +109,41 @@ const Field3D InvertParCR::solve(const Field3D &f) { bool closed = surf.closed(ts); // Number of rows - int y0 = 0, size = localmesh->LocalNy-4; // If no boundaries + int y0 = 0, size = localmesh->LocalNy - 2 * localmesh->ystart; // If no boundaries if(!closed) { if(surf.firstY()) { - y0 += 2; - size += 2; + y0 += localmesh->ystart; + size += localmesh->ystart; } if(surf.lastY()) - size += 2; + size += localmesh->ystart; } // Setup CyclicReduce object cr->setup(surf.communicator(), size); cr->setPeriodic(closed); - // Take Fourier transform - for(int y=0;yLocalNy-4;y++) - rfft(f(x, y + 2), localmesh->LocalNz, &rhs(y + y0, 0)); + // Take Fourier transform + for (int y = 0; y < localmesh->LocalNy - 2 * localmesh->ystart; y++) + rfft(alignedField(x, y + localmesh->ystart), localmesh->LocalNz, &rhs(y + y0, 0)); // Set up tridiagonal system for(int k=0; kzlength(); // wave number is 1/[rad] - for(int y=0;yLocalNy-4;y++) { - - BoutReal acoef = A(x, y+2); // Constant - BoutReal bcoef = B(x, y+2) / coord->g_22(x,y+2); // d2dy2 - BoutReal ccoef = C(x, y+2); // d2dydz - BoutReal dcoef = D(x, y+2); // d2dz2 - BoutReal ecoef = E(x, y+2); // ddy - - bcoef /= SQ(coord->dy(x, y+2)); - ccoef /= coord->dy(x,y+2)*coord->dz; + for (int y = 0; y < localmesh->LocalNy - 2 * localmesh->ystart; y++) { + + BoutReal acoef = A(x, y + localmesh->ystart); // Constant + BoutReal bcoef = + B(x, y + localmesh->ystart) / coord->g_22(x, y + localmesh->ystart); // d2dy2 + BoutReal ccoef = C(x, y + localmesh->ystart); // d2dydz + BoutReal dcoef = D(x, y + localmesh->ystart); // d2dz2 + BoutReal ecoef = E(x, y + localmesh->ystart); // ddy + + bcoef /= SQ(coord->dy(x, y + localmesh->ystart)); + ccoef /= coord->dy(x, y + localmesh->ystart) * coord->dz; dcoef /= SQ(coord->dz); - ecoef /= coord->dy(x,y+2); - + ecoef /= coord->dy(x, y + localmesh->ystart); + // const d2dy2 d2dydz d2dz2 ddy // ----- ----- ------ ----- --- a(k, y + y0) = bcoef - 0.5 * Im * kwave * ccoef - 0.5 * ecoef; @@ -167,14 +170,14 @@ const Field3D InvertParCR::solve(const Field3D &f) { for(int k=0; kzlength(); // wave number is 1/[rad] dcomplex phase(cos(kwave*ts) , sin(kwave*ts)); - c(k, localmesh->LocalNy - 5) *= phase; + c(k, localmesh->LocalNy - 2 * localmesh->ystart - 1) *= phase; } } }else { // Open surface, so may have boundaries if(surf.firstY()) { for(int k=0; kystart; y++) { a(k, y) = 0.; b(k, y) = 1.; c(k, y) = -1.; @@ -185,7 +188,7 @@ const Field3D InvertParCR::solve(const Field3D &f) { } if(surf.lastY()) { for(int k=0; kystart; y < size; y++) { a(k, y) = -1.; b(k, y) = 1.; c(k, y) = 0.; @@ -208,12 +211,12 @@ const Field3D InvertParCR::solve(const Field3D &f) { // Inverse Fourier transform for(int y=0;yLocalNz, result(x, y + 2 - y0)); + irfft(&rhs(y, 0), localmesh->LocalNz, result(x, y + localmesh->ystart - y0)); } // Delete cyclic reduction object delete cr; - return result; + return localmesh->fromFieldAligned(result); } From 668940b9cdb72ef95ec1a162d8f7f73b3c781627 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 22 Nov 2018 14:52:02 +0000 Subject: [PATCH 0324/1783] Remove serial impl of parderiv --- include/invert_parderiv.hxx | 1 - src/invert/parderiv/impls/makefile | 2 +- src/invert/parderiv/impls/serial/makefile | 8 -- src/invert/parderiv/impls/serial/serial.cxx | 145 -------------------- src/invert/parderiv/impls/serial/serial.hxx | 87 ------------ src/invert/parderiv/parderiv_factory.cxx | 5 +- 6 files changed, 2 insertions(+), 246 deletions(-) delete mode 100644 src/invert/parderiv/impls/serial/makefile delete mode 100644 src/invert/parderiv/impls/serial/serial.cxx delete mode 100644 src/invert/parderiv/impls/serial/serial.hxx diff --git a/include/invert_parderiv.hxx b/include/invert_parderiv.hxx index 0f562a2f79..ddca5c3366 100644 --- a/include/invert_parderiv.hxx +++ b/include/invert_parderiv.hxx @@ -37,7 +37,6 @@ #include "unused.hxx" // Parderiv implementations -#define PARDERIVSERIAL "serial" #define PARDERIVCYCLIC "cyclic" /// Base class for parallel inversion solvers diff --git a/src/invert/parderiv/impls/makefile b/src/invert/parderiv/impls/makefile index 24cd93dc6a..2f417f8106 100644 --- a/src/invert/parderiv/impls/makefile +++ b/src/invert/parderiv/impls/makefile @@ -1,7 +1,7 @@ BOUT_TOP = ../../../.. -DIRS = serial cyclic +DIRS = cyclic TARGET = lib include $(BOUT_TOP)/make.config diff --git a/src/invert/parderiv/impls/serial/makefile b/src/invert/parderiv/impls/serial/makefile deleted file mode 100644 index e1d1e71363..0000000000 --- a/src/invert/parderiv/impls/serial/makefile +++ /dev/null @@ -1,8 +0,0 @@ - -BOUT_TOP = ../../../../.. - -SOURCEC = serial.cxx -SOURCEH = serial.hxx -TARGET = lib - -include $(BOUT_TOP)/make.config diff --git a/src/invert/parderiv/impls/serial/serial.cxx b/src/invert/parderiv/impls/serial/serial.cxx deleted file mode 100644 index 849c91c7b9..0000000000 --- a/src/invert/parderiv/impls/serial/serial.cxx +++ /dev/null @@ -1,145 +0,0 @@ -/************************************************************************ - * Inversion of parallel derivatives - * - * Inverts a matrix of the form - * - * A + B * Grad2_par2 - * - * SERIAL ALGORITHM, for testing only - * - * Author: Ben Dudson, University of York, Oct 2011 - * - * Known issues: - * ------------ - * - * - Only works for NPE = 1 - * - Assumes all flux surfaces closed - * - Coefficients A and B must be 2D (X,Y) - * - ************************************************************************** - * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu - * - * Contact: Ben Dudson, bd512@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - ************************************************************************/ - -#include -#include -#include "serial.hxx" -#include -#include -#include -#include -#include - -#include - -#include - -InvertParSerial::InvertParSerial(Options *opt, Mesh *mesh_in) - : InvertPar(opt, mesh_in), A(1.0), B(0.0), C(0.0), D(0.0), E(0.0) { -} - -const Field3D InvertParSerial::solve(const Field3D &f) { - TRACE("InvertParSerial::solve(Field3D)"); - - ASSERT1(localmesh == f.getMesh()); - - Field3D result(localmesh); - result.allocate(); - result.setLocation(f.getLocation()); - - Coordinates *coord = f.getCoordinates(); - - // The following is the number of nonguard points - const int ny = localmesh->LocalNy - 2 * localmesh->ystart; - - auto rhs = Matrix(localmesh->LocalNy, (localmesh->LocalNz) / 2 + 1); - auto rhsk = Array(ny); - auto xk = Array(ny); - auto a = Array(ny); - auto b = Array(ny); - auto c = Array(ny); - - Field3D alignedField = localmesh->toFieldAligned(f); - - // Loop over flux-surfaces - SurfaceIter surf(localmesh); - for(surf.first(); !surf.isDone(); surf.next()) { - int x = surf.xpos; - BoutReal ts; // Twist-shift angle - if(!surf.closed(ts)) - throw BoutException("InvertParSerial doesn't handle open surfaces"); - - // Take Fourier transform - for (int y = localmesh->ystart; y <= localmesh->yend; y++) - rfft(alignedField(x, y), localmesh->LocalNz, &rhs(y - localmesh->ystart, 0)); - - // Solve cyclic tridiagonal system for each k - const int nyq = (localmesh->LocalNz) / 2; - const BoutReal waveFac = TWOPI / coord->zlength(); - for(int k=0;k<=nyq;k++) { - // Copy component of rhs into 1D array - for (int y = 0; y < ny; y++) - rhsk[y] = rhs(y, k); - - BoutReal kwave = k * waveFac; // wave number is 1/[rad] - - // Set up tridiagonal system - for (int y = localmesh->ystart; y <= localmesh->yend; y++) { - BoutReal acoef = A(x, y); // Constant - BoutReal bcoef = B(x, y) / coord->g_22(x, y); // d2dy2 - BoutReal ccoef = C(x, y); // d2dydz - BoutReal dcoef = D(x, y); // d2dz2 - BoutReal ecoef = E(x, y); // ddy - - bcoef /= SQ(coord->dy(x, y)); - ccoef /= coord->dy(x, y) * coord->dz; - dcoef /= SQ(coord->dz); - ecoef /= coord->dy(x, y); - - // const d2dy2 d2dydz d2dz2 ddy - // ----- ----- ------ ----- --- - a[y - localmesh->ystart] = bcoef - 0.5 * Im * kwave * ccoef - 0.5 * ecoef; - b[y - localmesh->ystart] = acoef - 2. * bcoef - SQ(kwave) * dcoef; - c[y - localmesh->ystart] = bcoef + 0.5 * Im * kwave * ccoef + 0.5 * ecoef; - } - - // Modify coefficients across twist-shift -- accounts for pseudo-periodicity - // across y-boundary to produce periodic value - dcomplex phase(cos(kwave*ts) , -sin(kwave*ts)); - a[0] *= phase; - c[ny - 1] /= phase; - - // Solve cyclic tridiagonal system - cyclic_tridag(std::begin(a), std::begin(b), std::begin(c), std::begin(rhsk), - std::begin(xk), ny); - - // Put back into rhs array - for (int y = 0; y < ny; y++) - rhs(y, k) = xk[y]; - } - - // Inverse Fourier transform - for (int y = localmesh->ystart; y <= localmesh->yend; y++) - irfft(&rhs(y - localmesh->ystart, 0), localmesh->LocalNz, result(x, y)); - } - - return localmesh->fromFieldAligned(result); -} - diff --git a/src/invert/parderiv/impls/serial/serial.hxx b/src/invert/parderiv/impls/serial/serial.hxx deleted file mode 100644 index ba3c1769db..0000000000 --- a/src/invert/parderiv/impls/serial/serial.hxx +++ /dev/null @@ -1,87 +0,0 @@ -/************************************************************************ - * Inversion of parallel derivatives - * - * Inverts a matrix of the form - * - * A + B * Grad2_par2 - * - * SERIAL ALGORITHM, for testing only - * - * Author: Ben Dudson, University of York, Oct 2011 - * - * Known issues: - * ------------ - * - * - Only works for NPE = 1 - * - Assumes all flux surfaces closed - * - Coefficients A and B must be 2D (X,Y) - * - ************************************************************************** - * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu - * - * Contact: Ben Dudson, bd512@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - ************************************************************************/ - -#ifndef __INV_PAR_SERIAL_H__ -#define __INV_PAR_SERIAL_H__ - -#include "invert_parderiv.hxx" -#include "dcomplex.hxx" -#include "utils.hxx" - -class InvertParSerial : public InvertPar { -public: - InvertParSerial(Options* opt, Mesh* mesh_in = mesh); - ~InvertParSerial(){}; - - using InvertPar::solve; - const Field3D solve(const Field3D &f) override; - - using InvertPar::setCoefA; - void setCoefA(const Field2D &f) override { - ASSERT1(localmesh == f.getMesh()); - A = f; - } - using InvertPar::setCoefB; - void setCoefB(const Field2D &f) override { - ASSERT1(localmesh == f.getMesh()); - B = f; - } - using InvertPar::setCoefC; - void setCoefC(const Field2D &f) override { - ASSERT1(localmesh == f.getMesh()); - C = f; - } - using InvertPar::setCoefD; - void setCoefD(const Field2D &f) override { - ASSERT1(localmesh == f.getMesh()); - D = f; - } - using InvertPar::setCoefE; - void setCoefE(const Field2D &f) override { - ASSERT1(localmesh == f.getMesh()); - E = f; - } - -private: - Field2D A, B, C, D, E; -}; - - -#endif // __INV_PAR_SERIAL_H__ diff --git a/src/invert/parderiv/parderiv_factory.cxx b/src/invert/parderiv/parderiv_factory.cxx index 2b45670870..bf9ff4fa42 100644 --- a/src/invert/parderiv/parderiv_factory.cxx +++ b/src/invert/parderiv/parderiv_factory.cxx @@ -7,7 +7,6 @@ #include "parderiv_factory.hxx" -#include "impls/serial/serial.hxx" #include "impls/cyclic/cyclic.hxx" ParDerivFactory *ParDerivFactory::instance = nullptr; @@ -37,9 +36,7 @@ InvertPar* ParDerivFactory::createInvertPar(const char* type, Options *opt, Mesh if (opt == nullptr) opt = Options::getRoot()->getSection(default_section); - if(!strcasecmp(type, PARDERIVSERIAL)) { - return new InvertParSerial(opt, mesh_in); - }else if(!strcasecmp(type, PARDERIVCYCLIC)) { + if (!strcasecmp(type, PARDERIVCYCLIC)) { return new InvertParCR(opt, mesh_in); } From 71e959647853abd9312b74a94384e675ebbd6045 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 22 Nov 2018 14:54:30 +0000 Subject: [PATCH 0325/1783] Make workspace be locally declared in solve --- src/invert/parderiv/impls/cyclic/cyclic.cxx | 57 ++++++++++----------- src/invert/parderiv/impls/cyclic/cyclic.hxx | 5 -- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index b1b6946f9d..e326aa5767 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -52,32 +52,6 @@ InvertParCR::InvertParCR(Options *opt, Mesh *mesh_in) : InvertPar(opt, mesh_in), A(1.0), B(0.0), C(0.0), D(0.0), E(0.0) { // Number of k equations to solve for each x location nsys = 1 + (localmesh->LocalNz)/2; - - rhs = Matrix(localmesh->LocalNy, nsys); - - // Find out if we are on a boundary - int size = localmesh->LocalNy - 2 * localmesh->ystart; - SurfaceIter surf(localmesh); - for(surf.first(); !surf.isDone(); surf.next()) { - BoutReal ts; - int n = localmesh->LocalNy - 2 * localmesh->ystart; - if(!surf.closed(ts)) { - // Open field line - if(surf.firstY()) - n += localmesh->ystart; - if(surf.lastY()) - n += localmesh->ystart; - - if(n > size) - size = n; // Maximum size - } - } - - rhsk = Matrix(nsys, size); - xk = Matrix(nsys, size); - a = Matrix(nsys, size); - b = Matrix(nsys, size); - c = Matrix(nsys, size); } InvertParCR::~InvertParCR() { @@ -98,10 +72,34 @@ const Field3D InvertParCR::solve(const Field3D &f) { // Create cyclic reduction object CyclicReduce *cr = new CyclicReduce(); - - // Loop over flux-surfaces + + // Find out if we are on a boundary + int size = localmesh->LocalNy - 2 * localmesh->ystart; SurfaceIter surf(localmesh); for(surf.first(); !surf.isDone(); surf.next()) { + BoutReal ts; + int n = localmesh->LocalNy - 2 * localmesh->ystart; + if (!surf.closed(ts)) { + // Open field line + if (surf.firstY()) + n += localmesh->ystart; + if (surf.lastY()) + n += localmesh->ystart; + + if (n > size) + size = n; // Maximum size + } + } + + auto rhs = Matrix(localmesh->LocalNy, nsys); + auto rhsk = Matrix(nsys, size); + auto xk = Matrix(nsys, size); + auto a = Matrix(nsys, size); + auto b = Matrix(nsys, size); + auto c = Matrix(nsys, size); + + // Loop over flux-surfaces + for (surf.first(); !surf.isDone(); surf.next()) { int x = surf.xpos; // Test if open or closed field-lines @@ -109,7 +107,8 @@ const Field3D InvertParCR::solve(const Field3D &f) { bool closed = surf.closed(ts); // Number of rows - int y0 = 0, size = localmesh->LocalNy - 2 * localmesh->ystart; // If no boundaries + int y0 = 0; + size = localmesh->LocalNy - 2 * localmesh->ystart; // If no boundaries if(!closed) { if(surf.firstY()) { y0 += localmesh->ystart; diff --git a/src/invert/parderiv/impls/cyclic/cyclic.hxx b/src/invert/parderiv/impls/cyclic/cyclic.hxx index de4758315c..328c213a64 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.hxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.hxx @@ -81,11 +81,6 @@ private: Field2D A, B, C, D, E; int nsys; - - Matrixrhs; - Matrixrhsk; - Matrixxk; - Matrix a, b, c; // Matrix coefficients }; From 49ae7d3b8faeeae55821cb2698db3dacd7d10697 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 22 Nov 2018 14:59:37 +0000 Subject: [PATCH 0326/1783] Exit cleanly for if --help used on command line --- src/bout++.cxx | 2 +- tests/integrated/test-command-args/runtest | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 2500672e6b..cb52b2bc5f 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -189,7 +189,7 @@ int BoutInitialise(int &argc, char **&argv) { "physics model source (e.g. %s.cxx)\n"), argv[0]); - return -1; + std::exit(EXIT_SUCCESS); } } bool color_output = false; // Will be set true if -c is in the options diff --git a/tests/integrated/test-command-args/runtest b/tests/integrated/test-command-args/runtest index 564fcf7725..465a3f4d4c 100755 --- a/tests/integrated/test-command-args/runtest +++ b/tests/integrated/test-command-args/runtest @@ -33,6 +33,13 @@ class TestCommandLineArgs(unittest.TestCase): self.assertIn('"data" does not exist', contents, msg="FAIL: Error message not printed when missing input directory") + def testHelpArgument(self): + self.makeDirAndCopyInput("data") + _, out = shell_safe(self.command + " --help", pipe=True) + # Not a great test! + self.assertNotIn("Writing options", out, + msg="FAIL: Attempting to write options") + def testNoArgumentsDefaultDirectory(self): self.makeDirAndCopyInput("data") shell_safe(self.command, pipe=True) From 60511aa23a0e026dda3e22189a029ce3947849e4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 22 Nov 2018 16:03:45 +0000 Subject: [PATCH 0327/1783] Remove consumed command line options from argv --- src/bout++.cxx | 60 +++++++++++----------- tests/integrated/test-command-args/runtest | 10 ++++ 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index cb52b2bc5f..b9baf5040a 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -112,10 +112,10 @@ int BoutInitialise(int &argc, char **&argv) { string dump_ext; ///< Extensions for restart and dump files - const char *data_dir; ///< Directory for data input/output - const char *opt_file; ///< Filename for the options file - const char *set_file; ///< Filename for the options file - const char *log_file; ///< File name for the log file + std::string data_dir{DEFAULT_DIR}; ///< Directory for data input/output + std::string opt_file{DEFAULT_OPT}; ///< Filename for the options file + std::string set_file{DEFAULT_SET}; ///< Filename for the options file + std::string log_file{DEFAULT_LOG}; ///< File name for the log file #ifdef SIGHANDLE /// Set a signal handler for segmentation faults @@ -129,12 +129,6 @@ int BoutInitialise(int &argc, char **&argv) { /// Trap SIGUSR1 to allow a clean exit after next write signal(SIGUSR1, bout_signal_handler); - // Set default data directory - data_dir = DEFAULT_DIR; - opt_file = DEFAULT_OPT; - set_file = DEFAULT_SET; - log_file = DEFAULT_LOG; - #if BOUT_HAS_GETTEXT // Setting the i18n environment // @@ -200,17 +194,19 @@ int BoutInitialise(int &argc, char **&argv) { fprintf(stderr, _("Usage is %s -d \n"), argv[0]); return 1; } - i++; - data_dir = argv[i]; - + argv[i][0] = 0; + data_dir = argv[++i]; + argv[i][0] = 0; + } else if (string(argv[i]) == "-f") { // Set options file if (i+1 >= argc) { fprintf(stderr, _("Usage is %s -f \n"), argv[0]); return 1; } - i++; - opt_file = argv[i]; + argv[i][0] = 0; + opt_file = argv[++i]; + argv[i][0] = 0; } else if (string(argv[i]) == "-o") { // Set options file @@ -218,24 +214,28 @@ int BoutInitialise(int &argc, char **&argv) { fprintf(stderr, _("Usage is %s -o \n"), argv[0]); return 1; } - i++; - set_file = argv[i]; + argv[i][0] = 0; + set_file = argv[++i]; + argv[i][0] = 0; } else if ((string(argv[i]) == "-l") || (string(argv[i]) == "--log")) { if (i + 1 >= argc) { fprintf(stderr, _("Usage is %s -l \n"), argv[0]); return 1; } - i++; - log_file = argv[i]; + argv[i][0] = 0; + log_file = argv[++i]; + argv[i][0] = 0; } else if ( (string(argv[i]) == "-v") || (string(argv[i]) == "--verbose") ){ verbosity++; + argv[i][0] = 0; } else if ( (string(argv[i]) == "-q") || (string(argv[i]) == "--quiet")) { verbosity--; + argv[i][0] = 0; } else if ( (string(argv[i]) == "-c") || (string(argv[i]) == "--color") ) { @@ -243,6 +243,7 @@ int BoutInitialise(int &argc, char **&argv) { // This is done after checking all command-line inputs // in case -c is set multiple times color_output = true; + argv[i][0] = 0; } } @@ -253,14 +254,15 @@ int BoutInitialise(int &argc, char **&argv) { // Check that data_dir exists. We do not check whether we can write, as it is // sufficient that the files we need are writeable ... struct stat test; - if (stat(data_dir, &test) == 0){ - if (!S_ISDIR(test.st_mode)){ - throw BoutException(_("DataDir \"%s\" is not a directory\n"),data_dir); + if (stat(data_dir.c_str(), &test) == 0) { + if (!S_ISDIR(test.st_mode)) { + throw BoutException(_("DataDir \"%s\" is not a directory\n"), data_dir.c_str()); } } else { - throw BoutException(_("DataDir \"%s\" does not exist or is not accessible\n"),data_dir); + throw BoutException(_("DataDir \"%s\" does not exist or is not accessible\n"), + data_dir.c_str()); } - + // Set the command-line arguments SlepcLib::setArgs(argc, argv); // SLEPc initialisation PetscLib::setArgs(argc, argv); // PETSc initialisation @@ -313,7 +315,7 @@ int BoutInitialise(int &argc, char **&argv) { /// Open an output file to echo everything to /// On processor 0 anything written to output will go to stdout and the file - if (output.open("%s/%s.%d", data_dir, log_file, MYPE)) { + if (output.open("%s/%s.%d", data_dir.c_str(), log_file.c_str(), MYPE)) { return 1; } } @@ -418,7 +420,7 @@ int BoutInitialise(int &argc, char **&argv) { try { /// Load settings file OptionsReader *reader = OptionsReader::getInstance(); - reader->read(options, "%s/%s", data_dir, opt_file); + reader->read(options, "%s/%s", data_dir.c_str(), opt_file.c_str()); // Get options override from command-line reader->parseCommandLine(options, argc, argv); @@ -442,7 +444,7 @@ int BoutInitialise(int &argc, char **&argv) { // Save settings if (BoutComm::rank() == 0) { - reader->write(options, "%s/%s", data_dir, set_file); + reader->write(options, "%s/%s", data_dir.c_str(), set_file.c_str()); } } catch (BoutException &e) { output << _("Error encountered during initialisation\n"); @@ -475,9 +477,9 @@ int BoutInitialise(int &argc, char **&argv) { /// Open a file for the output if(append) { - dump.opena("%s/BOUT.dmp.%s", data_dir, dump_ext.c_str()); + dump.opena("%s/BOUT.dmp.%s", data_dir.c_str(), dump_ext.c_str()); }else { - dump.openw("%s/BOUT.dmp.%s", data_dir, dump_ext.c_str()); + dump.openw("%s/BOUT.dmp.%s", data_dir.c_str(), dump_ext.c_str()); } /// Add book-keeping variables to the output files diff --git a/tests/integrated/test-command-args/runtest b/tests/integrated/test-command-args/runtest index 465a3f4d4c..c437fb4357 100755 --- a/tests/integrated/test-command-args/runtest +++ b/tests/integrated/test-command-args/runtest @@ -91,6 +91,16 @@ class TestCommandLineArgs(unittest.TestCase): self.assertIn("test_copy", datadir, msg="FAIL: datadir from command line clobbered by BOUT.settings") + def testShortOptionsAreCleaned(self): + self.makeDirAndCopyInput("test") + shell_safe(self.command + " -d test", pipe=True) + shutil.copytree("test", "test_copy") + shell_safe(self.command + " -d test_copy -f BOUT.settings -o testsettings", pipe=True) + + with open("test_copy/testsettings") as f: + contents = f.read() + self.assertNotIn("Command line", contents, + msg="FAIL: command line short options written to BOUT.settings") if __name__ == "__main__": shell_safe("make") From e5485eb1df47e0e05ad7bbd1aaa10ac8ab369c18 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 22 Nov 2018 16:09:56 +0000 Subject: [PATCH 0328/1783] Preserve original command line args for printing out --- src/bout++.cxx | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index b9baf5040a..e01365728f 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -64,7 +64,7 @@ const char DEFAULT_LOG[] = "BOUT.log"; #include #include -#include +#include using std::string; #include #include @@ -186,7 +186,10 @@ int BoutInitialise(int &argc, char **&argv) { std::exit(EXIT_SUCCESS); } } + bool color_output = false; // Will be set true if -c is in the options + std::vector original_argv; + for (int i=1;i\n"), argv[0]); return 1; } - argv[i][0] = 0; + data_dir = argv[++i]; + + original_argv.push_back(argv[i - 1]); + original_argv.push_back(argv[i]); + + argv[i - 1][0] = 0; argv[i][0] = 0; } else if (string(argv[i]) == "-f") { @@ -204,8 +212,13 @@ int BoutInitialise(int &argc, char **&argv) { fprintf(stderr, _("Usage is %s -f \n"), argv[0]); return 1; } - argv[i][0] = 0; + opt_file = argv[++i]; + + original_argv.push_back(argv[i - 1]); + original_argv.push_back(argv[i]); + + argv[i - 1][0] = 0; argv[i][0] = 0; } else if (string(argv[i]) == "-o") { @@ -214,8 +227,13 @@ int BoutInitialise(int &argc, char **&argv) { fprintf(stderr, _("Usage is %s -o \n"), argv[0]); return 1; } - argv[i][0] = 0; + set_file = argv[++i]; + + original_argv.push_back(argv[i - 1]); + original_argv.push_back(argv[i]); + + argv[i - 1][0] = 0; argv[i][0] = 0; } else if ((string(argv[i]) == "-l") || (string(argv[i]) == "--log")) { @@ -223,18 +241,27 @@ int BoutInitialise(int &argc, char **&argv) { fprintf(stderr, _("Usage is %s -l \n"), argv[0]); return 1; } - argv[i][0] = 0; + log_file = argv[++i]; + + original_argv.push_back(argv[i - 1]); + original_argv.push_back(argv[i]); + + argv[i - 1][0] = 0; argv[i][0] = 0; } else if ( (string(argv[i]) == "-v") || (string(argv[i]) == "--verbose") ){ verbosity++; + + original_argv.push_back(argv[i]); argv[i][0] = 0; } else if ( (string(argv[i]) == "-q") || (string(argv[i]) == "--quiet")) { verbosity--; + + original_argv.push_back(argv[i]); argv[i][0] = 0; } else if ( (string(argv[i]) == "-c") || @@ -243,6 +270,8 @@ int BoutInitialise(int &argc, char **&argv) { // This is done after checking all command-line inputs // in case -c is set multiple times color_output = true; + + original_argv.push_back(argv[i]); argv[i][0] = 0; } } @@ -409,8 +438,8 @@ int BoutInitialise(int &argc, char **&argv) { // Print command line options output_info.write(_("\tCommand line options for this run : ")); - for (int i=0; i Date: Thu, 22 Nov 2018 16:23:48 +0000 Subject: [PATCH 0329/1783] Tidy up some comments and follow cppcoreguidlines in a couple of places --- include/bout/deriv_store.hxx | 67 ++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index afa3f13ee6..d17cfbb612 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -64,6 +64,9 @@ struct DerivativeStore { using storageType = std::unordered_map; #endif + // No copy constructor allowed + DerivativeStore(const DerivativeStore& junk) = delete; + // Singleton method static DerivativeStore& getInstance() { static DerivativeStore instance; @@ -220,13 +223,11 @@ struct DerivativeStore { Stagger{}.lookup(), Method{}.meta.key); }; - /// Routines to return a specific differential operator. Note we have to have - /// a separate - /// routine for different - /// methods as they have different return types. As such we choose to use a - /// different - /// name for each of the - /// method-classes so everything is consistently treated + /// Routines to return a specific differential operator. Note we + /// have to have a separate routine for different methods as they + /// have different return types. As such we choose to use a + /// different name for each of the method-classes so everything is + /// consistently treated standardFunc getStandardDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { AUTO_TRACE(); @@ -415,11 +416,9 @@ struct DerivativeStore { } private: - // Make the constructor private so we can't make instances outside + // Make empty constructor private so we can't make instances outside // of the struct - DerivativeStore(){}; - // No copy constructor allowed - DerivativeStore(const DerivativeStore& junk) = delete; + DerivativeStore() = default; storageType standard; storageType standardSecond; @@ -440,24 +439,19 @@ private: return name != DIFF_METHOD_STRING(DIFF_DEFAULT) ? name : defaultName; } - /// Provides a routine to produce a unique key given information about the - /// specific type - /// required. This is templated so requires compile-time information. Need to - /// also - /// supply - /// a non-templated version to account for run-time choices - /// Note : We could include the derivType in the key -- this would allow us to - /// store - /// all methods with the same function interface in the same map, which might - /// be nice. + /// Provides a routine to produce a unique key given information + /// about the specific type required. This is templated so requires + /// compile-time information. Need to also supply a non-templated + /// version to account for run-time choices Note : We could include + /// the derivType in the key -- this would allow us to store all + /// methods with the same function interface in the same map, which + /// might be nice. std::size_t getKey(DIRECTION direction, STAGGER stagger, std::string key) const { AUTO_TRACE(); - // Note this key is indepedent of the field type (and hence the key is the - // same for - // 3D/2D - // fields) as we have to use different maps to store the different field - // types as the - // signature is different. + // Note this key is indepedent of the field type (and hence the + // key is the same for 3D/2D fields) as we have to use different + // maps to store the different field types as the signature is + // different. std::size_t result; result = std::hash{}(DIRECTION_STRING(direction)); result = result ^ std::hash{}(STAGGER_STRING(stagger)); @@ -465,20 +459,17 @@ private: return result; } - /// Provides a routine to produce a unique key given information about the - /// specific type - /// required. This is templated so requires compile-time information. Makes - /// use of - /// a non-templated version that can be used to account for run-time choices + /// Provides a routine to produce a unique key given information + /// about the specific type required. This is templated so requires + /// compile-time information. Makes use of a non-templated version + /// that can be used to account for run-time choices template std::size_t getKey() const { AUTO_TRACE(); - // Note this key is indepedent of the field type (and hence the key is the - // same for - // 3D/2D - // fields) as we have to use different maps to store the different field - // types as the - // signature is different. + // Note this key is indepedent of the field type (and hence the + // key is the same for 3D/2D fields) as we have to use different + // maps to store the different field types as the signature is + // different. return getKey(Direction{}.lookup(), Stagger{}.lookup(), Method{}.meta.key); } }; From 46926587a546decf29f2796f7d4021c252988186 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 22 Nov 2018 16:26:01 +0000 Subject: [PATCH 0330/1783] Tiny formatting change --- include/bout/deriv_store.hxx | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index d17cfbb612..b8f1a2a2f1 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -142,26 +142,29 @@ struct DerivativeStore { switch (derivType) { case (DERIV::Standard): - if(standard.count(key) != 0) { + if (standard.count(key) != 0) { throw BoutException("Trying to override standard derivative : " "direction %s, stagger %s, key %s", - DIRECTION_STRING(direction).c_str(), STAGGER_STRING(stagger).c_str(), methodName.c_str()); + DIRECTION_STRING(direction).c_str(), + STAGGER_STRING(stagger).c_str(), methodName.c_str()); } standard[key] = func; return; case (DERIV::StandardSecond): - if(standardSecond.count(key) != 0) { + if (standardSecond.count(key) != 0) { throw BoutException("Trying to override standardSecond derivative : " "direction %s, stagger %s, key %s", - DIRECTION_STRING(direction).c_str(), STAGGER_STRING(stagger).c_str(), methodName.c_str()); + DIRECTION_STRING(direction).c_str(), + STAGGER_STRING(stagger).c_str(), methodName.c_str()); } standardSecond[key] = func; return; case (DERIV::StandardFourth): - if(standardFourth.count(key) != 0) { + if (standardFourth.count(key) != 0) { throw BoutException("Trying to override standardFourth derivative : " "direction %s, stagger %s, key %s", - DIRECTION_STRING(direction).c_str(), STAGGER_STRING(stagger).c_str(), methodName.c_str()); + DIRECTION_STRING(direction).c_str(), + STAGGER_STRING(stagger).c_str(), methodName.c_str()); } standardFourth[key] = func; return; @@ -186,18 +189,20 @@ struct DerivativeStore { switch (derivType) { case (DERIV::Upwind): - if(upwind.count(key) != 0) { + if (upwind.count(key) != 0) { throw BoutException("Trying to override upwind derivative : " "direction %s, stagger %s, key %s", - DIRECTION_STRING(direction).c_str(), STAGGER_STRING(stagger).c_str(), methodName.c_str()); + DIRECTION_STRING(direction).c_str(), + STAGGER_STRING(stagger).c_str(), methodName.c_str()); } upwind[key] = func; return; case (DERIV::Flux): - if(flux.count(key) != 0) { + if (flux.count(key) != 0) { throw BoutException("Trying to override flux derivative : " "direction %s, stagger %s, key %s", - DIRECTION_STRING(direction).c_str(), STAGGER_STRING(stagger).c_str(), methodName.c_str()); + DIRECTION_STRING(direction).c_str(), + STAGGER_STRING(stagger).c_str(), methodName.c_str()); } flux[key] = func; return; From eb770fb2b391d104035b8b07110c0cddc04fbe98 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 22 Nov 2018 16:43:00 +0000 Subject: [PATCH 0331/1783] Make sure entire argv is copied --- src/bout++.cxx | 20 +++++------------- tests/integrated/test-command-args/runtest | 24 ++++++++++++++++++++-- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index e01365728f..aaa5551a7c 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -189,6 +189,11 @@ int BoutInitialise(int &argc, char **&argv) { bool color_output = false; // Will be set true if -c is in the options std::vector original_argv; + original_argv.reserve(argc); + + for (int i = 0; i < argc; i++) { + original_argv.emplace_back(argv[i]); + } for (int i=1;i Date: Fri, 23 Nov 2018 11:01:53 +0000 Subject: [PATCH 0332/1783] Bugfix: new_location check would always be false --- src/field/field2d.cxx | 8 ++++---- src/field/field3d.cxx | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 2fbf307bd2..d397e13827 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -129,11 +129,13 @@ void Field2D::setLocation(CELL_LOC new_location) { if (new_location == CELL_DEFAULT) { new_location = CELL_CENTRE; } - location = new_location; // Invalidate the coordinates pointer - if (new_location != location) + if (new_location != location) { fieldCoordinates = nullptr; + } + + location = new_location; } else { #if CHECK > 0 @@ -145,8 +147,6 @@ void Field2D::setLocation(CELL_LOC new_location) { #endif location = CELL_CENTRE; } - - } CELL_LOC Field2D::getLocation() const { diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 3c5d610945..a26640c21e 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -207,11 +207,14 @@ void Field3D::setLocation(CELL_LOC new_location) { if (new_location == CELL_DEFAULT) { new_location = CELL_CENTRE; } - location = new_location; // Invalidate the coordinates pointer - if (new_location != location) + if (new_location != location) { fieldCoordinates = nullptr; + } + + location = new_location; + } else { #if CHECK > 0 if (new_location != CELL_CENTRE && new_location != CELL_DEFAULT) { From 87c8e4af81020a0870314534e68e74db92f58258 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 23 Nov 2018 11:25:10 +0000 Subject: [PATCH 0333/1783] Add constructor for allowing coordinates to be tested --- include/bout/coordinates.hxx | 6 ++++++ src/mesh/coordinates.cxx | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index e649cdfcc7..95b449dbfe 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -53,6 +53,12 @@ public: /// Constructor interpolating from another Coordinates object Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coords_in); + /// Standard constructor from input + Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2D J, Field2D Bxy, + Field2D g11, Field2D g22, Field2D g33, Field2D g12, Field2D g13, + Field2D g23, Field2D g_11, Field2D g_22, Field2D g_33, Field2D g_12, + Field2D g_13, Field2D g_23); + ~Coordinates() {} /*! diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 81c0e921e4..fc0eb76ce1 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -17,6 +17,16 @@ #include +Coordinates::Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2D J, + Field2D Bxy, Field2D g11, Field2D g22, Field2D g33, Field2D g12, + Field2D g13, Field2D g23, Field2D g_11, Field2D g_22, + Field2D g_33, Field2D g_12, Field2D g_13, Field2D g_23) + : dx(std::move(dx)), dy(std::move(dy)), dz(dz), J(std::move(J)), Bxy(std::move(Bxy)), + g11(std::move(g11)), g22(std::move(g22)), g33(std::move(g33)), g12(std::move(g12)), + g13(std::move(g13)), g23(std::move(g23)), g_11(std::move(g_11)), + g_22(std::move(g_22)), g_33(std::move(g_33)), g_12(std::move(g_12)), + g_13(std::move(g_13)), g_23(std::move(g_23)), nz(mesh->LocalNz), localmesh(mesh), location(CELL_CENTRE) {} + Coordinates::Coordinates(Mesh *mesh) : dx(1, mesh), dy(1, mesh), dz(1), d1_dx(mesh), d1_dy(mesh), J(1, mesh), Bxy(1, mesh), // Identity metric tensor From 542f753b2906e1fafe17906dda985da2348d4829 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 23 Nov 2018 11:41:13 +0000 Subject: [PATCH 0334/1783] Provide helper macros for defining and registering a derivative method --- include/bout/index_derivs.hxx | 65 +++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index c9d75ef2df..a5af3a1147 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -121,7 +121,7 @@ public: const metaData meta = func.meta; }; -#define DEFINE_STANDARD_DERIV(name, key, nGuards, type) \ +#define DEFINE_STANDARD_DERIV_CORE(name, key, nGuards, type) \ struct name { \ BoutReal operator()(const stencil& f) const; \ const metaData meta = {key, nGuards, type}; \ @@ -131,10 +131,12 @@ public: BoutReal operator()(const stencil& UNUSED(v), const stencil& UNUSED(f)) const { \ return BoutNaN; \ }; \ - }; \ + }; +#define DEFINE_STANDARD_DERIV(name, key, nGuards, type) \ + DEFINE_STANDARD_DERIV_CORE(name, key, nGuards, type) \ BoutReal name::operator()(const stencil& f) const -#define DEFINE_UPWIND_DERIV(name, key, nGuards, type) \ +#define DEFINE_UPWIND_DERIV_CORE(name, key, nGuards, type) \ struct name { \ BoutReal operator()(const stencil& UNUSED(f)) const { return BoutNaN; }; \ BoutReal operator()(BoutReal vc, const stencil& f) const; \ @@ -142,10 +144,12 @@ public: return BoutNaN; \ }; \ const metaData meta = {key, nGuards, type}; \ - }; \ + }; +#define DEFINE_UPWIND_DERIV(name, key, nGuards, type) \ + DEFINE_UPWIND_DERIV_CORE(name, key, nGuards, type) \ BoutReal name::operator()(BoutReal vc, const stencil& f) const -#define DEFINE_FLUX_DERIV(name, key, nGuards, type) \ +#define DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ struct name { \ BoutReal operator()(const stencil& UNUSED(f)) const { return BoutNaN; }; \ BoutReal operator()(BoutReal UNUSED(vc), const stencil& UNUSED(f)) const { \ @@ -153,7 +157,9 @@ public: }; \ BoutReal operator()(const stencil& v, const stencil& f) const; \ const metaData meta = {key, nGuards, type}; \ - }; \ + }; +#define DEFINE_FLUX_DERIV(name, key, nGuards, type) \ + DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ BoutReal name::operator()(const stencil& v, const stencil& f) const #define DEFINE_STANDARD_DERIV_STAGGERED(name, key, nGuards, type) \ @@ -559,12 +565,6 @@ struct registerMethod { /// Temporary short hand #define e(family, value) WRAP_ENUM(family, value) -///////////////////////////////////////////////////////////////////////////////// -/// Here's an example of registering a couple of DerivativeType methods -/// at once for no staggering -///////////////////////////////////////////////////////////////////////////////// - -// Could use Ben's magic macro for thing here to register multiple routines at once #define REGISTER_DERIVATIVE(name) \ namespace { \ produceCombinations, \ @@ -582,14 +582,49 @@ struct registerMethod { reg(registerMethod{}); \ } +#define REGISTER_STANDARD_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_STANDARD_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_DERIVATIVE(name) \ + BoutReal name::operator()(const stencil& f) const + +#define REGISTER_UPWIND_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_UPWIND_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_DERIVATIVE(name) \ + BoutReal name::operator()(BoutReal vc, const stencil& f) const + +#define REGISTER_FLUX_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_DERIVATIVE(name) \ + BoutReal name::operator()(const stencil& v, const stencil& f) const + +#define REGISTER_STANDARD_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_STANDARD_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_STAGGERED_DERIVATIVE(name) \ + BoutReal name::operator()(const stencil& f) const + +#define REGISTER_UPWIND_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ + /*Note staggered upwind looks like flux*/ \ + DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_STAGGERED_DERIVATIVE(name) \ + BoutReal name::operator()(const stencil& v, const stencil& f) const + +#define REGISTER_FLUX_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_STAGGERED_DERIVATIVE(name) \ + BoutReal name::operator()(const stencil& v, const stencil& f) const + +///////////////////////////////////////////////////////////////////////////////// +/// Here's an example of registering a couple of DerivativeType methods +/// at once for no staggering +///////////////////////////////////////////////////////////////////////////////// + produceCombinations, Set, Set, TypeContainer>, Set< // Standard - DerivativeType, DerivativeType, - DerivativeType, DerivativeType, - DerivativeType, + DerivativeType, DerivativeType, + DerivativeType, DerivativeType, // Standard 2nd order DerivativeType, DerivativeType, // Standard 4th order From 3e16ec43c21b5eb36e3cb85b8fe57073fc531bdd Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 23 Nov 2018 11:41:36 +0000 Subject: [PATCH 0335/1783] Provide user documentation for new differencing approach --- .../user_docs/differential_operators.rst | 128 ++++++++++++++++-- 1 file changed, 117 insertions(+), 11 deletions(-) diff --git a/manual/sphinx/user_docs/differential_operators.rst b/manual/sphinx/user_docs/differential_operators.rst index 3459ff770a..1471d83c10 100644 --- a/manual/sphinx/user_docs/differential_operators.rst +++ b/manual/sphinx/user_docs/differential_operators.rst @@ -23,8 +23,8 @@ central differencing), and differential operators (such as Differencing methods -------------------- -Methods are implemented on 5-point stencils, and are divided into three -categories: +Methods are typically implemented on *5-point* stencils (although +exceptions are possible) and are divided into three categories: - Central-differencing methods, for diffusion operators :math:`\frac{df}{dx}`, :math:`\frac{d^2f}{dx^2}`. Each method has a @@ -41,9 +41,6 @@ categories: - ``W3``: 3\ :math:`^{rd}` order CWENO - - ``FFT``: Fourier Transform method in Z (axisymmetric) direction - only - - Upwinding methods for advection operators :math:`v_x\frac{df}{dx}` - ``U1``: 1\ :math:`^{st}` order upwinding @@ -70,8 +67,15 @@ categories: - ``C4``: 4\ :math:`^{th}` order central - - ``SPLIT``: split into upwind and central terms - :math:`\frac{d}{dx}(v_x f) = v_x\frac{df}{dx} + f\frac{dv_x}{dx}` +Special methods : + +- ``FFT``: Classed as a central method, Fourier Transform method in Z + (axisymmetric) direction only. Currently available for ``first`` + and ``second`` order central difference + +- ``SPLIT``: A flux method that splits into upwind and central terms + :math:`\frac{d}{dx}(v_x f) = v_x\frac{df}{dx} + f\frac{dv_x}{dx}` + .. _Weighted Essentially Non-Oscillatory (WENO): https://doi.org/10.1137/S106482759732455X @@ -81,11 +85,28 @@ artificial diffusion. WENO schemes are a development of the ENO reconstruction schemes which combine good handling of sharp-gradient regions with high accuracy in smooth regions. -To use these differencing operators directly, add the following to the -top of your physics module:: +The stencil based methods are based by a kernel that combines the data +in a stencil to produce a single BoutReal (note upwind/flux methods +take extra information about the flow, either a ``BoutReal`` or +another ``stencil``). It is not anticipated that the user would wish +to apply one of these kernels directly so documentation is not +provided here for how to do so. If this is of interest please look at +``include/bout/index_derivs.hxx``. Internally, these kernel routines +are combined within a functor struct that uses a ``BOUT_FOR`` loop +over the domain to provide a routine that will apply the kernel to +every point, calculating the derivative everywhere. These routines are +registered in the appropriate ``DerivativeStore`` and identified by +the direction of differential, the staggering, the type +(central/upwind/flux) and a key such as "C2". The typical user does +not need to interact with this store, instead one can add the +following to the top of your physics module:: #include +to provide access to the following routines. These take care of +selecting the appropriate method from the store and ensuring the +input/output field locations are compatible. + .. _tab-coordinate-derivatives: .. table:: Coordinate derivatives @@ -129,8 +150,93 @@ top of your physics module:: By default the method used will be the one specified in the options input file (see :ref:`sec-diffmethodoptions`), but most of these -methods can take an optional `DIFF_METHOD` argument, specifying -exactly which method to use. +methods can take an optional `std::string` argument (or a +`DIFF_METHOD` argument - to be deprecated), specifying exactly which +method to use. + +.. _sec-diffmethod-userregistration: + +User registered methods +----------------------- + +_Advanced_ It is possible for the user to define their own +differencing routines, either by supplying a stencil using kernel or +writing their own functor that calculates the differential +everywhere. It is then possible to register these methods with the +derivative store (for any direction, staggering etc.). For examples +please look at ``include/bout/index_derivs.hxx`` to see how these +approaches work. + +Here is a verbose example showing how the ``C2`` method is +implemented. + +:: + + DEFINE_STANDARD_DERIV(DDX_C2, "C2", 1, DERIV::Stanard) { + return 0.5*(f.p - f.m); + }; + + +Here `DEFINE_STANARD_DERIV` is a macro that acts on the kernel `return +0.5*(f.p - f.m);` and produces the functor that will apply the +differencing method over an entire field. The macro takes several +arguments; + +- the first (`DDX_C2`) is the name of the generated functor -- this + needs to be unique and allows advanced users to refer to a specific + derivative functor without having to go through the derivative store + if desired. + +- the second (`"C2"`) is the string key that is used to refer to this + specific method when registering/retrieving the method from the + derivative store. + +- the third (`1`) is the number of guard cells required to be able to + use this method (i.e. here the stencil will consist of three values + -- the field at the current point and one point either side). This + can be 1 or 2. + +- the fourth (`DERIV::Standard`) identifies the type of method - here + a central method. + +Alongside `DEFINE_STANDARD_DERIV` there's also `DEFINE_UPWIND_DERIV`, +`DEFINE_FLUX_DERIV` and the staggered versions +`DEFINE_STANDARD_DERIV_STAGGERED`, `DEFINE_UPWIND_DERIV_STAGGERED` and +`DEFINE_FLUX_DERIV_STAGGERED`. + +To register this method with the derivative store in `X` and `Z` with +no staggering for both field types we can then use the following code: + +:: + + produceCombinations, + Set, + Set>, + Set> + someUniqueNameForDerivativeRegistration(registerMethod{}); + + +For the common case where the user wishes to register the method in +`X`, `Y` and `Z` and for both field types we provide the helper +macros, `REGISTER_DERIVATIVE` and `REGISTER_STAGGERED_DERIVATIVE` +which could be used as `REGISTER_DERIVATIVE(DDX_C2)`. + +To simplify matters further we provide `REGISTER_STANDARD_DERIVATIVE`, +`REGISTER_UPWIND_DERIVATIVE`, `REGISTER_FLUX_DERIVATIVE`, +`REGISTER_STANDARD_STAGGERED_DERIVATIVE`, +`REGISTER_UPWIND_STAGGERED_DERIVATIVE` and +`REGISTER_FLUX_STAGGERED_DERIVATIVE` macros that can define and +register a stencil using kernel in a single step. For example: + +:: + + REGISTER_STANDARD_DERIVATIVE(DDX_C2, "C2", 1, DERIV::Standard) { return 0.5*(f.p-f.m);}; + + +Will define the `DDX_C2` functor and register it with the derivative +store using key `"C2"` for all three directions and both fields with +no staggering. + .. _sec-diffmethod-nonuniform: From 9cd50d1033f0cb380bf8a82685ce53318b580eed Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 23 Nov 2018 11:25:36 +0000 Subject: [PATCH 0336/1783] Add some basic tests for coordinates --- src/mesh/coordinates.cxx | 3 +- tests/unit/mesh/test_coordinates.cxx | 74 ++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 tests/unit/mesh/test_coordinates.cxx diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index fc0eb76ce1..301c3bfb53 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -25,7 +25,8 @@ Coordinates::Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2 g11(std::move(g11)), g22(std::move(g22)), g33(std::move(g33)), g12(std::move(g12)), g13(std::move(g13)), g23(std::move(g23)), g_11(std::move(g_11)), g_22(std::move(g_22)), g_33(std::move(g_33)), g_12(std::move(g_12)), - g_13(std::move(g_13)), g_23(std::move(g_23)), nz(mesh->LocalNz), localmesh(mesh), location(CELL_CENTRE) {} + g_13(std::move(g_13)), g_23(std::move(g_23)), nz(mesh->LocalNz), localmesh(mesh), + location(CELL_CENTRE) {} Coordinates::Coordinates(Mesh *mesh) : dx(1, mesh), dy(1, mesh), dz(1), d1_dx(mesh), d1_dy(mesh), J(1, mesh), Bxy(1, mesh), diff --git a/tests/unit/mesh/test_coordinates.cxx b/tests/unit/mesh/test_coordinates.cxx new file mode 100644 index 0000000000..02a87dd8fc --- /dev/null +++ b/tests/unit/mesh/test_coordinates.cxx @@ -0,0 +1,74 @@ +#include "gtest/gtest.h" + +#include "bout/coordinates.hxx" +#include "bout/mesh.hxx" +#include "output.hxx" + +#include "test_extras.hxx" + +/// Global mesh +extern Mesh *mesh; + +using CoordinatesTest = FakeMeshFixture; + +TEST_F(CoordinatesTest, ZLength) { + Coordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, + Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}}; + + EXPECT_DOUBLE_EQ(coords.zlength(), 7.0); +} + +TEST_F(CoordinatesTest, Jacobian) { + Coordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, + Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}}; + + EXPECT_NO_THROW(coords.jacobian()); + + EXPECT_TRUE(IsField3DEqualBoutReal(coords.J, 1.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(coords.Bxy, 1.0)); +} + +TEST_F(CoordinatesTest, CalcContravariant) { + Coordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, + Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}}; + + output_info.disable(); + coords.calcCovariant(); + output_info.enable(); + + EXPECT_TRUE(IsField2DEqualBoutReal(coords.g_11, 1.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(coords.g_22, 1.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(coords.g_33, 1.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(coords.g_12, 0.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(coords.g_13, 0.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(coords.g_23, 0.0)); +} + +TEST_F(CoordinatesTest, CalcCovariant) { + Coordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}}; + + output_info.disable(); + coords.calcContravariant(); + output_info.enable(); + + EXPECT_TRUE(IsField2DEqualBoutReal(coords.g11, 1.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(coords.g22, 1.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(coords.g33, 1.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(coords.g12, 0.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(coords.g13, 0.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(coords.g23, 0.0)); +} + From b9924383185aadcb7f2f09d95373a1509a210346 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 23 Nov 2018 11:44:03 +0000 Subject: [PATCH 0337/1783] Remove out of date derivative internals --- .../user_docs/differential_operators.rst | 149 +----------------- 1 file changed, 1 insertion(+), 148 deletions(-) diff --git a/manual/sphinx/user_docs/differential_operators.rst b/manual/sphinx/user_docs/differential_operators.rst index 1471d83c10..c83716727b 100644 --- a/manual/sphinx/user_docs/differential_operators.rst +++ b/manual/sphinx/user_docs/differential_operators.rst @@ -587,154 +587,7 @@ values. Several slope limiters are defined in ``fv_ops.hxx``: default. -.. _sec-derivatives: - -Derivative internals --------------------- - -FOLLOWING NOW OUT OF DATE - -This is probably the part of the code most people will want to alter, -and is in ``bout++/src/sys/derivs.cxx``. The main task of this module is -to map functions on fields like ``DDX`` to direction-independent -differential methods on stencils such as :math:`4^{th}`-order central -differencing. This mapping depends on global settings in ``BOUT.inp`` -and is illustrated in :numref:`fig-diffOverview`. - -.. _fig-diffOverview: -.. figure:: ../figs/diffOverview.* - :alt: Overview of ``derivs`` module - - Overview of ``derivs`` module, mapping derivative functions on fields - to direction-independent differential methods - -Four kinds of differencing methods are supported - -#. | First derivative ``DDX``, ``DDY``, ``DDZ`` - | Central differencing type schemes for first-order derivatives - -#. | Second derivatives ``D2DX2``, ``D2DZ2``, ``D2DZ2`` - | Central differencing second derivatives e.g. for :math:`\nabla^2` - -#. | Upwinding ``VDDX``, ``VDDY``, ``VDDZ`` - | Terms like :math:`\mathbf{v}\cdot\nabla` - -#. | Flux methods ``FDDX``, ``FDDY``, ``FDDZ`` - | Flux conserving, limiting methods for terms like - :math:`\nabla\cdot\left(\mathbf{v}f\right)` - -The differencing methods themselves are independent on direction, and -have types defined in :doc:`derivs.cxx<../_breathe_autogen/file/derivs_8cxx>` - -:: - - typedef BoutReal (*deriv_func)(stencil &); // f - typedef BoutReal (*upwind_func)(stencil &, stencil &); // v, f - -These operate on ``stencil`` objects. This class is in :doc:`stencils.hxx<../_breathe_autogen/file/stencils_8hxx>` - -:: - - class stencil { - public: - int jx, jy, jz; // Central location - BoutReal c, p, m, pp, mm; // stencil 2 each side of the centre - Overloaded operators - =,+,-,*,/ - Functions - min, max, abs - }; - -The main purpose of this class is to store a 5-element stencil. To -simplify some code this class also has a bunch of overloaded operators -on BoutReals and other stencil objects. There are also some functions to -calculate things like absolute, minimum, and maximum values. - -Lookup tables -~~~~~~~~~~~~~ - -To convert between short variable names (“C2”), long descriptions -(“2nd order Central Differencing”), ``DIFF_METHOD`` enums used to -specify methods at runtime (DIFF\_C2, defined in -:doc:`bout_types.hxx<../_breathe_autogen/file/bout__types_8hxx>`), and -function pointers (``DDX_C2``), taking into account whether variables -are shifted or not, BOUT++ uses a set of lookup tables. - -To find function pointers, tables of the following type are used:: - - /// Translate between DIFF_METHOD codes, and functions - struct DiffLookup { - DIFF_METHOD method; - deriv_func func; // Single-argument differencing function - upwind_func up_func; // Upwinding function - }; - -Because the ``DiffLookup`` type contains a ``deriv_func`` and -``upwind_func`` pointer, it is used for all function lookup tables. -There is a separate table for each type of differencing method, so for -example the table of non-staggered upwinding methods is - -:: - - /// Upwinding functions lookup table - static DiffLookup UpwindTable[] = { {DIFF_U1, NULL, VDDX_U1}, - {DIFF_C2, NULL, VDDX_C2}, - {DIFF_U4, NULL, VDDX_U4}, - {DIFF_W3, NULL, VDDX_WENO3}, - {DIFF_C4, NULL, VDDX_C4}, - {DIFF_DEFAULT}}; - -The ``DIFF_DEFAULT`` at the end is used to terminate the array. These -tables are used by functions - -:: - - deriv_func lookupFunc(DiffLookup* table, DIFF_METHOD method); - upwind_func lookupUpwindFunc(DiffLookup* table, DIFF_METHOD method); - -which return the function pointer corresponding to the given method. If -the method isn’t in the table, then the first entry in the table is -used. These functions can be used at run-time to allow a user to specify -the method to use for specific operators. - -When reading settings from the input file, they are specified as short -strings like “C2”, and a longer description of the method chosen should -be written to the output log. To do this, there is a name lookup table:: - - /// Translate between short names, long names and DIFF_METHOD codes - struct DiffNameLookup { - DIFF_METHOD method; - const char* label; // Short name - const char* name; // Long name - }; - - static DiffNameLookup DiffNameTable[] = { - {DIFF_U1, "U1", "First order upwinding"}, - {DIFF_C2, "C2", "Second order central"}, - {DIFF_W2, "W2", "Second order WENO"}, - {DIFF_W3, "W3", "Third order WENO"}, - {DIFF_C4, "C4", "Fourth order central"}, - {DIFF_U4, "U4", "Fourth order upwinding"}, - {DIFF_FFT, "FFT", "FFT"}, - {DIFF_DEFAULT}}; // Use to terminate the list - -To search this table, there is the function - -:: - - DIFF_METHOD lookupFunc(DiffLookup *table, const string &label) - -During initialisation, the lookup therefore works in two stages, shown -in :numref:`fig-diffLookup`. First the short description is turned into a -``DIFF_METHOD`` enum code, then this code is turned into a function -pointer. - -.. _fig-diffLookup: -.. figure:: ../figs/diffLookup.* - :alt: Lookup tables for differential method - - Lookup tables for mapping between differential method labels, codes, - descriptions and function pointers +.. _sec-staggeredgrids: Staggered grids ~~~~~~~~~~~~~~~ From 672acc401ae6bd065381a61dfaa8b068b8466716 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 23 Nov 2018 12:03:02 +0000 Subject: [PATCH 0338/1783] Restore missing DDX_C2 --- include/bout/index_derivs.hxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index a5af3a1147..fff3a69138 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -623,8 +623,9 @@ produceCombinations, Set, TypeContainer>, Set< // Standard - DerivativeType, DerivativeType, - DerivativeType, DerivativeType, + DerivativeType, DerivativeType, + DerivativeType, DerivativeType, + DerivativeType, // Standard 2nd order DerivativeType, DerivativeType, // Standard 4th order From bb450c07b7e80f13a090bf3393d111f1d13f5cb8 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 23 Nov 2018 14:52:56 +0000 Subject: [PATCH 0339/1783] Add some tests for vector operations that need the metric --- tests/unit/field/test_vector2d.cxx | 169 +++++++++++++++++++++++ tests/unit/field/test_vector3d.cxx | 213 ++++++++++++++++++++++++++++- tests/unit/test_extras.hxx | 4 + 3 files changed, 385 insertions(+), 1 deletion(-) diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index 5681bc6c12..d87c17ebea 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -35,6 +35,14 @@ class Vector2DTest : public ::testing::Test { mesh->addBoundary(new BoundaryRegionXOut("sol", 1, ny - 2, mesh)); mesh->addBoundary(new BoundaryRegionYUp("upper_target", 1, nx - 2, mesh)); mesh->addBoundary(new BoundaryRegionYDown("lower_target", 1, nx - 2, mesh)); + + auto coords = std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, + Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, + Field2D{5.0}, Field2D{6.0}); + + dynamic_cast(mesh)->setCoordinates(coords); } ~Vector2DTest() { @@ -498,3 +506,164 @@ TEST_F(Vector2DTest, DivideVector2DField3D) { EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 2.0)); EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 3.0)); } + +TEST_F(Vector2DTest, Cross2D3D) { + Vector2D vector1; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector3D vector2; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = cross(vector1, vector2); + + EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 0.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 0.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 0.0)); +} + +TEST_F(Vector2DTest, Cross2D2D) { + Vector2D vector1; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector2D vector2; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = cross(vector1, vector2); + + EXPECT_TRUE(IsField2DEqualBoutReal(result.x, 0.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(result.y, 0.0)); + EXPECT_TRUE(IsField2DEqualBoutReal(result.z, 0.0)); +} + +TEST_F(Vector2DTest, Dot2D3DCoCo) { + Vector2D vector1; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector3D vector2; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = vector1 * vector2; + + EXPECT_TRUE(IsField3DEqualBoutReal(result, 308.0)); +} + +TEST_F(Vector2DTest, Dot2D2DCoCo) { + Vector2D vector1; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector2D vector2; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = vector1 * vector2; + + EXPECT_TRUE(IsField2DEqualBoutReal(result, 308.0)); +} + +TEST_F(Vector2DTest, Dot2D3DCoContra) { + Vector2D vector1; + vector1.covariant = false; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector3D vector2; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = vector1 * vector2; + + EXPECT_TRUE(IsField3DEqualBoutReal(result, 28.0)); +} + +TEST_F(Vector2DTest, Dot2D2DCoContra) { + Vector2D vector1; + vector1.covariant = false; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector2D vector2; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = vector1 * vector2; + + EXPECT_TRUE(IsField2DEqualBoutReal(result, 28.0)); +} + +TEST_F(Vector2DTest, Dot2D3DContraContra) { + Vector2D vector1; + vector1.covariant = false; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector3D vector2; + vector2.covariant = false; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = vector1 * vector2; + + EXPECT_TRUE(IsField3DEqualBoutReal(result, 308.0)); +} + +TEST_F(Vector2DTest, Dot2D2DContraContra) { + Vector2D vector1; + vector1.covariant = false; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector2D vector2; + vector2.covariant = false; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = vector1 * vector2; + + EXPECT_TRUE(IsField2DEqualBoutReal(result, 308.0)); +} + +TEST_F(Vector2DTest, AbsCo) { + Vector2D vector1; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + auto result = abs(vector1); + + EXPECT_TRUE(IsField2DEqualBoutReal(result, 24.819347291981714)); +} + +TEST_F(Vector2DTest, AbsContra) { + Vector2D vector1; + vector1.covariant = false; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + auto result = abs(vector1); + + EXPECT_TRUE(IsField2DEqualBoutReal(result, 24.819347291981714)); +} diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index 1058a7918c..500824b82f 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -18,7 +18,7 @@ class Vector3DTest : public ::testing::Test { // Delete any existing mesh if (mesh != nullptr) { // Delete boundary regions - for (auto &r : mesh->getBoundaries()) { + for (auto& r : mesh->getBoundaries()) { delete r; } @@ -34,6 +34,14 @@ class Vector3DTest : public ::testing::Test { mesh->addBoundary(new BoundaryRegionXOut("sol", 1, ny - 2, mesh)); mesh->addBoundary(new BoundaryRegionYUp("upper_target", 1, nx - 2, mesh)); mesh->addBoundary(new BoundaryRegionYDown("lower_target", 1, nx - 2, mesh)); + + auto coords = std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, + Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, + Field2D{5.0}, Field2D{6.0}); + + dynamic_cast(mesh)->setCoordinates(coords); } ~Vector3DTest() { @@ -516,3 +524,206 @@ TEST_F(Vector3DTest, DivideVector3DField3D) { EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 2.0)); EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 3.0)); } + +TEST_F(Vector3DTest, ToCovariant) { + auto coords = std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, + Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}); + + dynamic_cast(mesh)->setCoordinates(coords); + + Vector3D vector; + vector.covariant = false; + vector.x = 2.0; + vector.y = 4.0; + vector.z = 6.0; + + vector.toCovariant(); + + EXPECT_TRUE(IsField3DEqualBoutReal(vector.x, 48.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(vector.y, 52.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(vector.z, 52.0)); +} + +TEST_F(Vector3DTest, ToContravariant) { + auto coords = std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, + Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}); + + dynamic_cast(mesh)->setCoordinates(coords); + + Vector3D vector; + vector.covariant = true; + vector.x = 2.0; + vector.y = 4.0; + vector.z = 6.0; + + vector.toContravariant(); + + EXPECT_TRUE(IsField3DEqualBoutReal(vector.x, 48.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(vector.y, 52.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(vector.z, 52.0)); +} + +TEST_F(Vector3DTest, Cross3D3D) { + Vector3D vector1; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector3D vector2; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = cross(vector1, vector2); + + EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 0.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 0.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 0.0)); +} + +TEST_F(Vector3DTest, Cross3D2D) { + Vector3D vector1; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector2D vector2; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = cross(vector1, vector2); + + EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 0.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 0.0)); + EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 0.0)); +} + +TEST_F(Vector3DTest, Dot3D3DCoContra) { + Vector3D vector1; + vector1.covariant = false; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector3D vector2; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = vector1 * vector2; + + EXPECT_TRUE(IsField3DEqualBoutReal(result, 28.0)); +} + +TEST_F(Vector3DTest, Dot3D2DCoContra) { + Vector3D vector1; + vector1.covariant = false; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector2D vector2; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = vector1 * vector2; + + EXPECT_TRUE(IsField3DEqualBoutReal(result, 28.0)); +} + +TEST_F(Vector3DTest, Dot3D3DCoCo) { + Vector3D vector1; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector3D vector2; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = vector1 * vector2; + + EXPECT_TRUE(IsField3DEqualBoutReal(result, 308.0)); +} + +TEST_F(Vector3DTest, Dot3D2DCoCo) { + Vector3D vector1; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector2D vector2; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = vector1 * vector2; + + EXPECT_TRUE(IsField3DEqualBoutReal(result, 308.0)); +} + +TEST_F(Vector3DTest, Dot3D3DContraContra) { + Vector3D vector1; + vector1.covariant = false; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector3D vector2; + vector2.covariant = false; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = vector1 * vector2; + + EXPECT_TRUE(IsField3DEqualBoutReal(result, 308.0)); +} + +TEST_F(Vector3DTest, Dot3D2DContraContra) { + Vector3D vector1; + vector1.covariant = false; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + Vector2D vector2; + vector2.covariant = false; + vector2.x = 1.0; + vector2.y = 2.0; + vector2.z = 3.0; + + auto result = vector1 * vector2; + + EXPECT_TRUE(IsField3DEqualBoutReal(result, 308.0)); +} + +TEST_F(Vector3DTest, AbsCo) { + Vector3D vector1; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + auto result = abs(vector1); + + EXPECT_TRUE(IsField3DEqualBoutReal(result, 24.819347291981714)); +} + +TEST_F(Vector3DTest, AbsContra) { + Vector3D vector1; + vector1.covariant = false; + vector1.x = 2.0; + vector1.y = 4.0; + vector1.z = 6.0; + + auto result = abs(vector1); + + EXPECT_TRUE(IsField3DEqualBoutReal(result, 24.819347291981714)); +} diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index b042e2a933..256be62152 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -75,6 +75,10 @@ public: maxregionblocksize = MAXREGIONBLOCKSIZE; } + void setCoordinates(std::shared_ptr coords, CELL_LOC location = CELL_CENTRE) { + coords_map[location] = coords; + } + comm_handle send(FieldGroup &UNUSED(g)) { return nullptr; }; int wait(comm_handle UNUSED(handle)) { return 0; } MPI_Request sendToProc(int UNUSED(xproc), int UNUSED(yproc), BoutReal *UNUSED(buffer), From 6cb01d6f731695a3702bd04bcd9a331aaa481d58 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 20 Nov 2018 11:17:20 +0000 Subject: [PATCH 0340/1783] Remove unused `nd` variable from nc_format --- src/fileio/impls/netcdf/nc_format.cxx | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/fileio/impls/netcdf/nc_format.cxx b/src/fileio/impls/netcdf/nc_format.cxx index 612bd1ef96..9cc38a5d04 100644 --- a/src/fileio/impls/netcdf/nc_format.cxx +++ b/src/fileio/impls/netcdf/nc_format.cxx @@ -572,11 +572,6 @@ bool NcFormat::write(int *data, const char *name, int lx, int ly, int lz) { // Check for valid name checkName(name); - int nd = 0; // Number of dimensions - if(lx != 0) nd = 1; - if(ly != 0) nd = 2; - if(lz != 0) nd = 3; - TRACE("NcFormat::write(int)"); #ifdef NCDF_VERBOSE @@ -620,11 +615,6 @@ bool NcFormat::write(BoutReal *data, const char *name, int lx, int ly, int lz) { TRACE("NcFormat::write(BoutReal)"); - int nd = 0; // Number of dimensions - if(lx != 0) nd = 1; - if(ly != 0) nd = 2; - if(lz != 0) nd = 3; - #ifdef NCDF_VERBOSE NcError err(NcError::verbose_nonfatal); #else @@ -771,11 +761,6 @@ bool NcFormat::write_rec(int *data, const char *name, int lx, int ly, int lz) { // Check for valid name checkName(name); - int nd = 1; // Number of dimensions - if(lx != 0) nd = 2; - if(ly != 0) nd = 3; - if(lz != 0) nd = 4; - #ifdef NCDF_VERBOSE NcError err(NcError::verbose_nonfatal); #else @@ -823,11 +808,6 @@ bool NcFormat::write_rec(BoutReal *data, const char *name, int lx, int ly, int l TRACE("NcFormat::write_rec(BoutReal*)"); - int nd = 1; // Number of dimensions - if(lx != 0) nd = 2; - if(ly != 0) nd = 3; - if(lz != 0) nd = 4; - #ifdef NCDF_VERBOSE NcError err(NcError::verbose_nonfatal); #else From 8d231ae2ea2eebf4c6edfc1c018e19ef4bd4964a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 20 Nov 2018 14:29:32 +0000 Subject: [PATCH 0341/1783] Remove whole function definition if not used at CHECK level --- src/field/field2d.cxx | 3 ++- src/field/field3d.cxx | 3 ++- src/mesh/boundary_standard.cxx | 11 +++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 2fbf307bd2..59809d07e8 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -567,7 +567,8 @@ namespace { } } } -#else +#elif CHECK > 1 + // No-op for no checking void checkDataIsFiniteOnRegion(const Field2D &UNUSED(f), REGION UNUSED(region)) {} #endif } diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 3c5d610945..1c52a7e659 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -1082,7 +1082,8 @@ namespace { } } } -#else +#elif CHECK > 1 + // No-op for no checking void checkDataIsFiniteOnRegion(const Field3D &UNUSED(f), REGION UNUSED(region)) {} #endif } diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 5c7146ff27..e727562803 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -23,13 +23,10 @@ lead to an out of bounds access error later but we add it here to provide a more explanatory message. */ +#if CHECK > 0 void verifyNumPoints(BoundaryRegion *region, int ptsRequired) { TRACE("Verifying number of points available for BC"); -#ifndef CHECK - return; //No checking so just return -#else - int ptsAvailGlobal, ptsAvailLocal, ptsAvail; std::string side, gridType; @@ -97,9 +94,11 @@ void verifyNumPoints(BoundaryRegion *region, int ptsRequired) { throw BoutException("Too few %s grid points for %s boundary, have %d but need at least %d", gridType.c_str(),side.c_str(),ptsAvail,ptsRequired); } - -#endif } +#else +// No-op for no checking +void verifyNumPoints(BoundaryRegion*, int) {} +#endif /////////////////////////////////////////////////////////////// From 948fa9c1b602aa340109b5095ae008210805fd28 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 20 Nov 2018 14:29:58 +0000 Subject: [PATCH 0342/1783] Remove argument names from Lapack function stubs --- src/invert/lapack_routines.cxx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/invert/lapack_routines.cxx b/src/invert/lapack_routines.cxx index bc1232128f..3efbcf1bd8 100644 --- a/src/invert/lapack_routines.cxx +++ b/src/invert/lapack_routines.cxx @@ -259,22 +259,21 @@ void cband_solve(Matrix &a, int n, int m1, int m2, Array &b) // No LAPACK available. Routines throw exceptions /// Tri-diagonal complex matrix inversion -int tridag(const dcomplex *a, const dcomplex *b, const dcomplex *c, const dcomplex *r, - dcomplex *u, int n) { +int tridag(const dcomplex*, const dcomplex*, const dcomplex*, const dcomplex*, dcomplex*, int) { throw BoutException("complex tridag function not available. Compile BOUT++ with Lapack support."); } /// Tri-diagonal matrix inversion (BoutReal) -bool tridag(const BoutReal *a, const BoutReal *b, const BoutReal *c, const BoutReal *r, BoutReal *x, int n) { +bool tridag(const BoutReal*, const BoutReal*, const BoutReal*, const BoutReal*, BoutReal*, int) { throw BoutException("tridag function not available. Compile BOUT++ with Lapack support."); } /// Solve a cyclic tridiagonal matrix -void cyclic_tridag(BoutReal *a, BoutReal *b, BoutReal *c, BoutReal *r, BoutReal *x, int n) { +void cyclic_tridag(BoutReal*, BoutReal*, BoutReal*, BoutReal*, BoutReal*, int) { throw BoutException("cyclic_tridag function not available. Compile BOUT++ with Lapack support."); } -void cband_solve(Matrix &a, int n, int m1, int m2, Array &b) { +void cband_solve(Matrix&, int, int, int, Array&) { throw BoutException("cband_solve function not available. Compile BOUT++ with Lapack support."); } From 54a8690a6ca018e4dfc290664bd6b7c4a88c213c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 23 Nov 2018 15:33:32 +0000 Subject: [PATCH 0343/1783] Add a macro for marking things as maybe unused --- include/unused.hxx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/unused.hxx b/include/unused.hxx index dd1c96915a..3026bf4fe0 100644 --- a/include/unused.hxx +++ b/include/unused.hxx @@ -35,4 +35,19 @@ # define UNUSED(x) x #endif +/// Mark a function parameter as possibly unused in the function body +/// +/// Unlike `UNUSED`, this has to go around the type as well: +/// +/// MAYBE_UNUSED(int foo); +#ifdef __has_cpp_attribute +#if __has_cpp_attribute(maybe_unused) +# define MAYBE_UNUSED(x) [[maybe_unused]] x +#endif +#elif defined(__GNUC__) +# define MAYBE_UNUSED(x) x __attribute__((unused)) +#else +# define MAYBE_UNUSED(x) x +#endif + #endif //__UNUSED_H__ From 94b0cfaf333da035dbdf631c8203c128ba8437f2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 23 Nov 2018 16:24:28 +0000 Subject: [PATCH 0344/1783] Make some arguments as MAYBE_UNUSED --- src/invert/laplace/impls/multigrid/multigrid_alg.cxx | 8 +++++--- src/mesh/coordinates.cxx | 6 +++--- src/solver/solver.cxx | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx index 0191e07b51..df39fe6c5a 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx @@ -29,6 +29,7 @@ #include "multigrid_laplace.hxx" #include +#include "unused.hxx" // Define basic multigrid algorithm @@ -611,9 +612,10 @@ BOUT_OMP(for collapse(2)) } void MultigridAlg::communications(BoutReal* x, int level) { - - MPI_Status status[4]; - int stag,rtag,ierr; + + MPI_Status status[4]; + int stag, rtag; + MAYBE_UNUSED(int ierr); if(zNP > 1) { MPI_Datatype xvector; diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 81c0e921e4..a894b161d6 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -633,7 +633,7 @@ const Field2D Coordinates::DDY(const Field2D &f, CELL_LOC loc, DIFF_METHOD metho return localmesh->indexDDY(f, loc, method, region) / dy; } -const Field2D Coordinates::DDZ(const Field2D &f, CELL_LOC loc, +const Field2D Coordinates::DDZ(MAYBE_UNUSED(const Field2D &f), CELL_LOC loc, DIFF_METHOD UNUSED(method), REGION UNUSED(region)) { ASSERT1(location == loc || loc == CELL_DEFAULT); ASSERT1(f.getMesh() == localmesh); @@ -647,7 +647,7 @@ const Field2D Coordinates::DDZ(const Field2D &f, CELL_LOC loc, ///////////////////////////////////////////////////////// // Parallel gradient -const Field2D Coordinates::Grad_par(const Field2D &var, CELL_LOC outloc, +const Field2D Coordinates::Grad_par(const Field2D &var, MAYBE_UNUSED(CELL_LOC outloc), DIFF_METHOD UNUSED(method)) { TRACE("Coordinates::Grad_par( Field2D )"); ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == var.getLocation())); @@ -668,7 +668,7 @@ const Field3D Coordinates::Grad_par(const Field3D &var, CELL_LOC outloc, // vparallel times the parallel derivative along unperturbed B-field const Field2D Coordinates::Vpar_Grad_par(const Field2D &v, const Field2D &f, - CELL_LOC outloc, + MAYBE_UNUSED(CELL_LOC outloc), DIFF_METHOD UNUSED(method)) { ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == f.getLocation())); return VDDY(v, f) / sqrt(g_22); diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 331df82c05..4e6b57d289 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -1282,7 +1282,7 @@ void Solver::post_rhs(BoutReal UNUSED(t)) { } // Make sure 3D fields are at the correct cell location - for(const auto& f : f3d) { + for (MAYBE_UNUSED(const auto& f) : f3d) { ASSERT1(f.var->getLocation() == f.F_var->getLocation()); ASSERT1(f.var->getMesh() == f.F_var->getMesh()); } From 00e1d9b72b9c34f4e8c55894a77d56575cf7474a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 23 Nov 2018 16:25:20 +0000 Subject: [PATCH 0345/1783] Use unused variable --- src/field/where.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/field/where.cxx b/src/field/where.cxx index 6a003cedf2..671e3b7cc7 100644 --- a/src/field/where.cxx +++ b/src/field/where.cxx @@ -160,7 +160,7 @@ const Field2D where(const Field2D &test, BoutReal gt0, const Field2D &le0) { const Field2D where(const Field2D &test, BoutReal gt0, BoutReal le0) { const auto testMesh = test.getMesh(); - Field2D result(test.getMesh()); + Field2D result(testMesh); result.allocate(); BOUT_FOR(i, testMesh->getRegion2D("RGN_ALL")) { From a60748a09509de99283685bd0e1ba87b32d8aa7e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 23 Nov 2018 16:25:34 +0000 Subject: [PATCH 0346/1783] Mark test PhysicsModels arguments as UNUSED --- tests/integrated/test-delp2/test_delp2.cxx | 5 +++-- tests/integrated/test-drift-instability/2fluid.cxx | 4 ++-- tests/integrated/test-fci-slab/fci_slab.cxx | 2 +- .../test-multigrid_laplace/test_multigrid_laplace.cxx | 4 ---- .../integrated/test-naulin-laplace/test_naulin_laplace.cxx | 4 ---- .../test-region-iterator/test_region_iterator.cxx | 4 ++-- tests/integrated/test-restarting/test_restarting.cxx | 7 +++---- tests/integrated/test-stopCheck/test_stopCheck.cxx | 5 +++-- tests/integrated/test-subdir/subdirs.cxx | 4 ++-- tests/integrated/test-vec/testVec.cxx | 4 ++-- 10 files changed, 18 insertions(+), 25 deletions(-) diff --git a/tests/integrated/test-delp2/test_delp2.cxx b/tests/integrated/test-delp2/test_delp2.cxx index b05150023d..9206a5e959 100644 --- a/tests/integrated/test-delp2/test_delp2.cxx +++ b/tests/integrated/test-delp2/test_delp2.cxx @@ -1,9 +1,10 @@ #include +#include "unused.hxx" class TestDelp2 : public PhysicsModel { protected: - int init(bool restarting) { + int init(bool UNUSED(restarting)) { Options *opt = Options::getRoot()->getSection("diffusion"); OPTION(opt, D, 0.1); @@ -12,7 +13,7 @@ class TestDelp2 : public PhysicsModel { return 0; } - int rhs(BoutReal t) { + int rhs(BoutReal UNUSED(t)) { mesh->communicate(n); ddt(n) = D * Delp2(n); diff --git a/tests/integrated/test-drift-instability/2fluid.cxx b/tests/integrated/test-drift-instability/2fluid.cxx index 3e55a2c6fb..d1e45da8ed 100644 --- a/tests/integrated/test-drift-instability/2fluid.cxx +++ b/tests/integrated/test-drift-instability/2fluid.cxx @@ -64,7 +64,7 @@ Coordinates *coord; // Coordinate system CELL_LOC maybe_ylow; -int physics_init(bool restarting) { +int physics_init(bool UNUSED(restarting)) { Field2D I; // Shear factor output.write("Solving 6-variable 2-fluid equations\n"); @@ -311,7 +311,7 @@ int physics_init(bool restarting) { // just define a macro for V_E dot Grad #define vE_Grad(f, p) ( b0xGrad_dot_Grad(p, f) / coord->Bxy ) -int physics_run(BoutReal t) { +int physics_run(BoutReal UNUSED(t)) { // Solve EM fields solve_phi_tridag(rho, phi, phi_flags); diff --git a/tests/integrated/test-fci-slab/fci_slab.cxx b/tests/integrated/test-fci-slab/fci_slab.cxx index 84ba090355..60a6bfd4ca 100644 --- a/tests/integrated/test-fci-slab/fci_slab.cxx +++ b/tests/integrated/test-fci-slab/fci_slab.cxx @@ -8,7 +8,7 @@ class FCISlab : public PhysicsModel { // We need to initialise the FCI object with the mesh FCISlab() {} - int init(bool restarting) { + int init(bool UNUSED(restarting)) { D = 10; diff --git a/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx b/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx index 0f5f107c5c..748a85ae7e 100644 --- a/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx +++ b/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx @@ -48,10 +48,6 @@ int main(int argc, char** argv) { Field3D absolute_error1; BoutReal max_error1; //Output of test - // Use Field3D's, but solver only works on FieldPerp slices, so only use 1 y-point - BoutReal nx = mesh->GlobalNx-2*mesh->xstart; - BoutReal nz = mesh->GlobalNz; - dump.add(mesh->getCoordinates()->G1,"G1"); dump.add(mesh->getCoordinates()->G3,"G3"); diff --git a/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx b/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx index 8a5f1f8103..b2873903ac 100644 --- a/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx +++ b/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx @@ -50,10 +50,6 @@ int main(int argc, char** argv) { Field3D absolute_error1; BoutReal max_error1; //Output of test - // Use Field3D's, but solver only works on FieldPerp slices, so only use 1 y-point - BoutReal nx = mesh->GlobalNx-2*mesh->xstart; - BoutReal nz = mesh->GlobalNz; - dump.add(mesh->getCoordinates()->G1,"G1"); dump.add(mesh->getCoordinates()->G3,"G3"); diff --git a/tests/integrated/test-region-iterator/test_region_iterator.cxx b/tests/integrated/test-region-iterator/test_region_iterator.cxx index 0ddd07b80b..36451c5f7a 100644 --- a/tests/integrated/test-region-iterator/test_region_iterator.cxx +++ b/tests/integrated/test-region-iterator/test_region_iterator.cxx @@ -6,7 +6,7 @@ Field3D n; -int physics_init(bool restarting) { +int physics_init(bool UNUSED(restarting)) { Field3D a=1.0, b=1.0, c=2.0; @@ -55,7 +55,7 @@ int physics_init(bool restarting) { return 0; } -int physics_run(BoutReal t) { +int physics_run(BoutReal UNUSED(t)) { ddt(n) = 0.; return 0; } diff --git a/tests/integrated/test-restarting/test_restarting.cxx b/tests/integrated/test-restarting/test_restarting.cxx index a283043ab3..ba340d19ca 100644 --- a/tests/integrated/test-restarting/test_restarting.cxx +++ b/tests/integrated/test-restarting/test_restarting.cxx @@ -1,18 +1,17 @@ - - #include +#include "unused.hxx" class RestartTest : public PhysicsModel { private: Field3D f3d; Field2D f2d; protected: - int init(bool restarting) { + int init(bool UNUSED(restarting)) { // Evolve a 3D and a 2D field SOLVE_FOR2(f3d, f2d); return 0; } - int rhs(BoutReal time) { + int rhs(BoutReal UNUSED(time)) { // Simple time evolution ddt(f3d) = 0.1*f3d; ddt(f2d) = -0.1*f2d; diff --git a/tests/integrated/test-stopCheck/test_stopCheck.cxx b/tests/integrated/test-stopCheck/test_stopCheck.cxx index f7bd5924b5..9fc3583c78 100644 --- a/tests/integrated/test-stopCheck/test_stopCheck.cxx +++ b/tests/integrated/test-stopCheck/test_stopCheck.cxx @@ -5,15 +5,16 @@ #include #include +#include "unused.hxx" Field3D N; -int physics_init(bool restarting) { +int physics_init(bool UNUSED(restarting)) { solver->add(N,"N"); return 0; } -int physics_run(BoutReal t) { +int physics_run(BoutReal UNUSED(t)) { mesh->communicate(N); ddt(N) = 0.; return 0; diff --git a/tests/integrated/test-subdir/subdirs.cxx b/tests/integrated/test-subdir/subdirs.cxx index be955d17c8..09c5661616 100644 --- a/tests/integrated/test-subdir/subdirs.cxx +++ b/tests/integrated/test-subdir/subdirs.cxx @@ -9,7 +9,7 @@ class SubDirs : public PhysicsModel { Field3D n; protected: - int init(bool restart) override { + int init(bool UNUSED(restart)) override { n=1; SOLVE_FOR(n); // test functions @@ -18,7 +18,7 @@ class SubDirs : public PhysicsModel { return 0; } - int rhs(BoutReal time) override { + int rhs(BoutReal UNUSED(time)) override { ddt(n)=0; return 0; } diff --git a/tests/integrated/test-vec/testVec.cxx b/tests/integrated/test-vec/testVec.cxx index ac027bf61f..fbdc502372 100644 --- a/tests/integrated/test-vec/testVec.cxx +++ b/tests/integrated/test-vec/testVec.cxx @@ -14,13 +14,13 @@ class VecTest : public PhysicsModel { }; -int VecTest::init(bool restarting) { +int VecTest::init(bool UNUSED(restarting)) { TRACE("Halt in VecTest::init"); SOLVE_FOR(n); return 0; } -int VecTest::rhs(BoutReal t) { +int VecTest::rhs(BoutReal UNUSED(t)) { TRACE("Halt in VecTest::rhs"); mesh->communicate(n); gradPerpN = Grad_perp(n); From 6beca72c842dfd2fdff6a22b0cc7503ae5c52c86 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 23 Nov 2018 23:22:35 +0000 Subject: [PATCH 0347/1783] Update documentation for Field3D::setBoundaryTo Previous documentation was misleading, and had not been updated following changes. Fixes issue #1259 --- include/field3d.hxx | 7 ++++++- manual/sphinx/user_docs/physics_models.rst | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/include/field3d.hxx b/include/field3d.hxx index e9f090bea6..35fb2a656b 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -435,7 +435,12 @@ class Field3D : public Field, public FieldData { void applyBoundary(const char* condition) { applyBoundary(string(condition)); } void applyBoundary(const string ®ion, const string &condition); void applyTDerivBoundary() override; - void setBoundaryTo(const Field3D &f3d); ///< Copy the boundary region + + /// Copy the boundary values half-way between cells + /// This uses 2nd order central differences to set the value + /// on the boundary to the value on the boundary in field \p f3d. + /// Note: does not just copy values in boundary region. + void setBoundaryTo(const Field3D &f3d); void applyParallelBoundary(); void applyParallelBoundary(BoutReal t); diff --git a/manual/sphinx/user_docs/physics_models.rst b/manual/sphinx/user_docs/physics_models.rst index a723792a6e..5ab237474b 100644 --- a/manual/sphinx/user_docs/physics_models.rst +++ b/manual/sphinx/user_docs/physics_models.rst @@ -664,6 +664,28 @@ Another way to set the boundaries is to copy them from another variable:: a.setBoundaryTo(b); // Copy b's boundaries into a ... +Note that this will copy the value at the boundary, which is half-way between +mesh points. This is not the same as copying the guard cells from +field ``b`` to field ``a``. The value at the boundary cell is +calculated using second-order central difference. For example if +there is one boundary cell, so that ``a(0,y,z)`` is the boundary cell, +and ``a(1,y,z)`` is in the domain, then the boundary would be set so that:: + + a(0,y,z) + a(1,y,z) = b(0,y,z) + b(1,y,z) + +rearranged as:: + + a(0,y,z) = - a(1,y,z) + b(0,y,z) + b(1,y,z) + +To copy the boundary cells (and communication guard cells), iterate +over them:: + + BOUT_FOR(i, a.getRegion("RGN_GUARDS")) { + a[i] = b[i]; + } + +See :ref:`sec-iterating` for more details on iterating over custom regions. + .. _sec-custom-bc: Custom boundary conditions From bd025add046bd8e131e16a384fd0a19872f9fbce Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 23 Nov 2018 23:29:54 +0000 Subject: [PATCH 0348/1783] Remove restart.split python routine Does't compile, and is in any case incomplete. There are other routines for changing the number of restart files, in particular `restart.redistribute`. Fixes issue #1076 --- tools/pylib/boutdata/restart.py | 102 -------------------------------- 1 file changed, 102 deletions(-) diff --git a/tools/pylib/boutdata/restart.py b/tools/pylib/boutdata/restart.py index 269bc85f17..b1bf1fbd44 100644 --- a/tools/pylib/boutdata/restart.py +++ b/tools/pylib/boutdata/restart.py @@ -30,108 +30,6 @@ except ImportError: pass - -def split(nxpe, nype, path="data", output="./", informat="nc", outformat=None, mxg=2, myg=2): - """Split restart files across NXPE x NYPE processors. - - Returns True on success - - Parameters - ---------- - nxpe, nype : int - The number of processors in x and y - path : str, optional - Path to original restart files (default: "data") - output : str, optional - Path to write new restart files (default: current directory) - informat : str, optional - File extension of original files (default: "nc") - outformat : str, optional - File extension of new files (default: use the same as `informat`) - mxg, myg : int, optional - The number of guard cells in x and y - - TODO - ---- - - Replace printing errors with raising `ValueError` - - Fix undefined variables! - - Make informat work like `redistribute` - - """ - - if outformat is None: - outformat = informat - - npes = nxpe * nype - - if npes <= 0: - print("ERROR: Negative or zero number of processors") - return False - - if path == output: - print("ERROR: Can't overwrite restart files") - return False - - file_list = glob.glob(os.path.join(path, "BOUT.restart.*."+informat)) - nfiles = len(file_list) - - if nfiles == 0: - print("ERROR: No restart files found") - return False - - # Read old processor layout - f = DataFile(os.path.join(path, file_list[0])) - old_layout = get_processor_layout(f, False) - f.close() - - if nfiles != old_layout.npes: - print("WARNING: Number of restart files inconsistent with NPES") - print("Setting nfiles = " + str(old_npes)) - nfiles = old_layout.npes - - if old_layout.npes % old_layout.nxpe != 0: - print("ERROR: Old NPES is not a multiple of old NXPE") - return False - - if nype % old_layout.nype != 0: - print("SORRY: New nype must be a multiple of old nype") - return False - - if nxpe % old_layout.nxpe != 0: - print("SORRY: New nxpe must be a multiple of old nxpe") - return False - - # Calculate total size of the grid - nx = old_layout.mxsub * old_layout.nxpe - ny = old_layout.mysub * old_layout.nype - print(("Grid sizes: ", nx, ny, mz)) - - # Create the new restart files - for mype in range(npes): - # Calculate X and Y processor numbers - pex = mype % nxpe - pey = int(mype / nxpe) - - old_pex = int(pex / xs) - old_pey = int(pey / ys) - - old_x = pex % xs - old_y = pey % ys - - # Old restart file number - old_mype = old_layout.nxpe * old_pey + old_pex - - # Calculate indices in old restart file - xmin = old_x*mxsub - xmax = xmin + mxsub - 1 + 2*mxg - ymin = old_y*mysub - ymax = ymin + mysub - 1 + 2*myg - - print("New: "+str(mype)+" ("+str(pex)+", "+str(pey)+")") - print(" => "+str(old_layout.mype)+" ("+str(old_pex)+", " + - str(old_pey)+") : ("+str(old_x)+", "+str(old_y)+")") - - def resize3DField(var, data, coordsAndSizesTuple, method, mute): """Resize 3D fields From 5a90a63a33ad66ca02f9966934cbe04c1f826d37 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 23 Nov 2018 23:35:40 +0000 Subject: [PATCH 0349/1783] Remove comm_group as not used anywhere Provides an interface for MPI gather/scatter operations, but too low level to be really useful. If this functionality is needed again, I would prefer a better API. Fixes issue #1213 --- include/comm_group.hxx | 68 ------------ src/sys/comm_group.cxx | 244 ----------------------------------------- 2 files changed, 312 deletions(-) delete mode 100644 include/comm_group.hxx delete mode 100644 src/sys/comm_group.cxx diff --git a/include/comm_group.hxx b/include/comm_group.hxx deleted file mode 100644 index 003d73b943..0000000000 --- a/include/comm_group.hxx +++ /dev/null @@ -1,68 +0,0 @@ -/*********************************************************************** - * Non-blocking collective operations (gather, scatter) - * - * - ************************************************************************** - * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu - * - * Contact Ben Dudson, bd512@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - ***********************************************************************/ - -#ifndef __COMM_GROUP_H__ -#define __COMM_GROUP_H__ - -#include "mpi.h" - -namespace comm_group { - /// Communication handle - typedef struct { - // Communication info - int root, myrank, nprocs; - - // Handles - int nreq; ///< Number of MPI requests - MPI_Request *request; - bool current; ///< True if currently in progress - }Comm_handle_t; - - /// Begin a gather operation - bool Comm_gather_start(void *local, int nlocal, MPI_Datatype type, - void *data, - int root, MPI_Comm comm, - Comm_handle_t *handle); - - bool Comm_scatter_start( void *sendbuf, int sendcnt, MPI_Datatype type, - void *recvbuf, - int root, MPI_Comm comm, - Comm_handle_t *handle); - - /// Wait for a single operation to finish - bool Comm_wait(Comm_handle_t *handle); - - /// Wait for all the communications to finish - bool Comm_wait_all(int n, Comm_handle_t *handles); -} - -using comm_group::Comm_handle_t; -using comm_group::Comm_gather_start; -using comm_group::Comm_scatter_start; -using comm_group::Comm_wait; -using comm_group::Comm_wait_all; - -#endif // __COMM_GROUP_H__ diff --git a/src/sys/comm_group.cxx b/src/sys/comm_group.cxx deleted file mode 100644 index 8fbd7464e6..0000000000 --- a/src/sys/comm_group.cxx +++ /dev/null @@ -1,244 +0,0 @@ -/*********************************************************************** - * Non-blocking collective operations (gather, scatter) - * - * - ************************************************************************** - * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu - * - * Contact Ben Dudson, bd512@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - ***********************************************************************/ - -#include -#include -#include - -#include -#include -#include - -namespace comm_group { - - const int COMM_GROUP_TAG = 31415; - - static bool initialised = false; - static bool nonblock; - - void Comm_initialise() - { - if(initialised) - return; - - output.write("Initialising group comms\n"); - Options *options = Options::getRoot(); - options = options->getSection("comms"); - options->get("group_nonblock", nonblock, true); - - initialised = true; - } - - bool Comm_gather_start(void *local, int nlocal, MPI_Datatype type, - void *data, - int root, MPI_Comm comm, - Comm_handle_t *handle) - { - TRACE("Comm_gather_start(%d -> %d)", nlocal, root); - - Comm_initialise(); - - // Put communication info into handle - MPI_Comm_size(comm, &handle->nprocs); - MPI_Comm_rank(comm, &handle->myrank); - handle->root = root; - - if(!nonblock) { - // Blocking comms using the MPI call - // May be faster for different architectures, and useful - // for debugging - - MPI_Gather(local, nlocal, type, - data, nlocal, type, - root, comm); - - handle->current = true; - - return (root == handle->myrank); - } - - int type_size; // Get size of the datatype - MPI_Type_size(type, &type_size); - - if(root == handle->myrank) { - // All arriving on this processor. Post receives - - handle->request = (MPI_Request *)malloc(sizeof(MPI_Request) * (handle->nprocs - 1)); - handle->nreq = handle->nprocs-1; - - MPI_Request *r = handle->request; - for(int p=0;pnprocs; p++) { - if(p != root) { - MPI_Irecv((void*) ( ((char*) data) + p*nlocal*type_size), - nlocal, - type, - p, - COMM_GROUP_TAG, - comm, - r); - r++; // Next request - } - } - - // Copy local data into output - memcpy((void*) (((char*) data) + handle->myrank*nlocal*type_size), - local, - nlocal*type_size); - }else { - // Sending to root processor - - handle->request = (MPI_Request *)malloc(sizeof(MPI_Request)); - handle->nreq = 1; - - MPI_Isend(local, - nlocal, - type, - root, - COMM_GROUP_TAG, - comm, - handle->request); - } - - handle->current = true; // Mark as in progress - - return (root == handle->myrank); - } - - /// start a scatter operation - /*! - * @param[in] sendbuf Buffer of data to be send (only used on root process) - * @param[in] sendcnt Number of elements to be sent to each process (NOT TOTAL!) - * @param[in] type Data type - * @param[out] recvbuf Where to store the data - * @param[in] root Process rank where data originates - * @param[in] comm Communicator - * @param[out] handle Used for completion later - */ - bool Comm_scatter_start( void *sendbuf, int sendcnt, MPI_Datatype type, - void *recvbuf, - int root, MPI_Comm comm, - Comm_handle_t *handle) - { - TRACE("Comm_scatter_start(%d -> %d)", root, sendcnt); - - Comm_initialise(); - - MPI_Comm_size(comm, &handle->nprocs); - MPI_Comm_rank(comm, &handle->myrank); - handle->root = root; - - if(!nonblock) { - MPI_Scatter ( sendbuf, sendcnt, type, recvbuf, sendcnt, type, root, comm ); - handle->current = true; - - return (root == handle->myrank); - } - - int type_size; // Get size of the datatype - MPI_Type_size(type, &type_size); - - if(root == handle->myrank) { - // Sending from this processor - - handle->request = (MPI_Request*) malloc(sizeof(MPI_Request)*(handle->nprocs-1)); - handle->nreq = handle->nprocs-1; - - MPI_Request *r = handle->request; - for(int p=0;pnprocs; p++) { - if(p != root) { - - MPI_Isend((void*) ( ((char*) sendbuf) + p*sendcnt*type_size), - sendcnt, - type, - p, - COMM_GROUP_TAG, - comm, - r); - r++; // Next request - } - } - - // Copy local data - memcpy(recvbuf, - (void*) (((char*) sendbuf) + root*sendcnt*type_size), - sendcnt*type_size); - }else { - // Receiving one message from root - - handle->request = (MPI_Request*) malloc(sizeof(MPI_Request)); - handle->nreq = 1; - - MPI_Irecv(recvbuf, - sendcnt, - type, - root, - COMM_GROUP_TAG, - comm, - handle->request); - } - - handle->current = true; - - return (root == handle->myrank); - } - - bool Comm_wait(Comm_handle_t *handle) { - if (handle == nullptr) { - return false; - } - - TRACE("Comm_gather_wait(%d)", handle->root); - - if(!handle->current) - return false; - - if(!nonblock) { // Already done communication - handle->current = false; - return (handle->root == handle->myrank); - } - - MPI_Status *s = (MPI_Status*) malloc(sizeof(MPI_Status)*(handle->nreq)); - MPI_Waitall(handle->nreq, - handle->request, - s); - - free(s); - free(handle->request); - handle->current = false; - - return (handle->root == handle->myrank); - } - - bool Comm_wait_all(int n, Comm_handle_t *handles) - { - bool newdata = false; - - for(int i=0; i Date: Mon, 26 Nov 2018 11:31:03 +0000 Subject: [PATCH 0350/1783] Make Coordinates testing ctor protected, inherit from it for tests --- include/bout/coordinates.hxx | 20 +++++++------ tests/unit/field/test_vector2d.cxx | 6 ++-- tests/unit/field/test_vector3d.cxx | 20 ++----------- tests/unit/mesh/test_coordinates.cxx | 43 ++++++++++++++-------------- tests/unit/test_extras.hxx | 11 +++++++ 5 files changed, 48 insertions(+), 52 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index 95b449dbfe..36e5c64a81 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -52,15 +52,9 @@ public: /// Constructor interpolating from another Coordinates object Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coords_in); - - /// Standard constructor from input - Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2D J, Field2D Bxy, - Field2D g11, Field2D g22, Field2D g33, Field2D g12, Field2D g13, - Field2D g23, Field2D g_11, Field2D g_22, Field2D g_33, Field2D g_12, - Field2D g_13, Field2D g_23); - ~Coordinates() {} - + ~Coordinates() = default; + /*! * Adds variables to the output file, for post-processing * @@ -152,6 +146,16 @@ private: int nz; // Size of mesh in Z. This is mesh->ngz-1 Mesh * localmesh; CELL_LOC location; + +protected: + /// A constructor useful for testing purposes. To use it, inherit + /// from Coordinates. Note: makes a partially constructed + /// object. Non-uniform variables, Christoffel symbols, and + /// shift-torsion variables are not defined. + Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2D J, Field2D Bxy, + Field2D g11, Field2D g22, Field2D g33, Field2D g12, Field2D g13, + Field2D g23, Field2D g_11, Field2D g_22, Field2D g_33, Field2D g_12, + Field2D g_13, Field2D g_23); }; /* diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index d87c17ebea..1d516c3784 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -36,13 +36,11 @@ class Vector2DTest : public ::testing::Test { mesh->addBoundary(new BoundaryRegionYUp("upper_target", 1, nx - 2, mesh)); mesh->addBoundary(new BoundaryRegionYDown("lower_target", 1, nx - 2, mesh)); - auto coords = std::make_shared( + dynamic_cast(mesh)->setCoordinates(std::make_shared( mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, - Field2D{5.0}, Field2D{6.0}); - - dynamic_cast(mesh)->setCoordinates(coords); + Field2D{5.0}, Field2D{6.0})); } ~Vector2DTest() { diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index 500824b82f..0b9210db38 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -35,13 +35,11 @@ class Vector3DTest : public ::testing::Test { mesh->addBoundary(new BoundaryRegionYUp("upper_target", 1, nx - 2, mesh)); mesh->addBoundary(new BoundaryRegionYDown("lower_target", 1, nx - 2, mesh)); - auto coords = std::make_shared( + dynamic_cast(mesh)->setCoordinates(std::make_shared( mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, - Field2D{5.0}, Field2D{6.0}); - - dynamic_cast(mesh)->setCoordinates(coords); + Field2D{5.0}, Field2D{6.0})); } ~Vector3DTest() { @@ -526,13 +524,6 @@ TEST_F(Vector3DTest, DivideVector3DField3D) { } TEST_F(Vector3DTest, ToCovariant) { - auto coords = std::make_shared( - mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, - Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}); - - dynamic_cast(mesh)->setCoordinates(coords); - Vector3D vector; vector.covariant = false; vector.x = 2.0; @@ -547,13 +538,6 @@ TEST_F(Vector3DTest, ToCovariant) { } TEST_F(Vector3DTest, ToContravariant) { - auto coords = std::make_shared( - mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, - Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}); - - dynamic_cast(mesh)->setCoordinates(coords); - Vector3D vector; vector.covariant = true; vector.x = 2.0; diff --git a/tests/unit/mesh/test_coordinates.cxx b/tests/unit/mesh/test_coordinates.cxx index 02a87dd8fc..ac4a7b28fb 100644 --- a/tests/unit/mesh/test_coordinates.cxx +++ b/tests/unit/mesh/test_coordinates.cxx @@ -12,21 +12,21 @@ extern Mesh *mesh; using CoordinatesTest = FakeMeshFixture; TEST_F(CoordinatesTest, ZLength) { - Coordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, - Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}}; - + FakeCoordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, + Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}}; + EXPECT_DOUBLE_EQ(coords.zlength(), 7.0); } TEST_F(CoordinatesTest, Jacobian) { - Coordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, - Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}}; + FakeCoordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, + Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}}; EXPECT_NO_THROW(coords.jacobian()); @@ -35,11 +35,11 @@ TEST_F(CoordinatesTest, Jacobian) { } TEST_F(CoordinatesTest, CalcContravariant) { - Coordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, - Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}}; + FakeCoordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, + Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}}; output_info.disable(); coords.calcCovariant(); @@ -54,11 +54,11 @@ TEST_F(CoordinatesTest, CalcContravariant) { } TEST_F(CoordinatesTest, CalcCovariant) { - Coordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}}; + FakeCoordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}}; output_info.disable(); coords.calcContravariant(); @@ -71,4 +71,3 @@ TEST_F(CoordinatesTest, CalcCovariant) { EXPECT_TRUE(IsField2DEqualBoutReal(coords.g13, 0.0)); EXPECT_TRUE(IsField2DEqualBoutReal(coords.g23, 0.0)); } - diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 256be62152..92eecc76ea 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -7,6 +7,7 @@ #include #include "bout/mesh.hxx" +#include "bout/coordinates.hxx" #include "field3d.hxx" #include "unused.hxx" @@ -166,6 +167,16 @@ private: std::vector boundaries; }; +class FakeCoordinates : public Coordinates { +public: + FakeCoordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2D J, Field2D Bxy, + Field2D g11, Field2D g22, Field2D g33, Field2D g12, Field2D g13, + Field2D g23, Field2D g_11, Field2D g_22, Field2D g_33, Field2D g_12, + Field2D g_13, Field2D g_23) + : Coordinates(mesh, dx, dy, dz, J, Bxy, g11, g22, g33, g12, g13, g23, g_11, g_22, + g_33, g_12, g_13, g_23) {} +}; + /// Test fixture to make sure the global mesh is our fake /// one. Multiple tests have exactly the same fixture, so use a type /// alias to make a new test: From f432fd0b2479e2d19ca4026d1401ac65b267ac71 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 26 Nov 2018 17:18:06 +0000 Subject: [PATCH 0351/1783] Remove references to comm_group from auxiliary files --- manual/sphinx/developer_docs/code_layout.rst | 2 -- src/sys/makefile | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/manual/sphinx/developer_docs/code_layout.rst b/manual/sphinx/developer_docs/code_layout.rst index 4f8a50e0d7..b10de99cdc 100644 --- a/manual/sphinx/developer_docs/code_layout.rst +++ b/manual/sphinx/developer_docs/code_layout.rst @@ -345,8 +345,6 @@ The current source code files are: - sys - - :doc:`boutcomm.cxx<../_breathe_autogen/file/boutcomm_8cxx>` - - :doc:`boutexception.cxx<../_breathe_autogen/file/boutexception_8cxx>` is an exception class which are used for error handling diff --git a/src/sys/makefile b/src/sys/makefile index beb3fd1bab..b443ee698b 100644 --- a/src/sys/makefile +++ b/src/sys/makefile @@ -1,7 +1,7 @@ BOUT_TOP = ../.. DIRS = options -SOURCEC = boutexception.cxx comm_group.cxx derivs.cxx \ +SOURCEC = boutexception.cxx derivs.cxx \ msg_stack.cxx options.cxx output.cxx \ utils.cxx optionsreader.cxx boutcomm.cxx \ timer.cxx range.cxx petsclib.cxx expressionparser.cxx \ From 1707f12b166897666fa2d2839b31565fe7308bdf Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 27 Nov 2018 11:08:25 +0000 Subject: [PATCH 0352/1783] Reinstate removed boutcomm in docs and remove comm_group --- manual/sphinx/developer_docs/code_layout.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/manual/sphinx/developer_docs/code_layout.rst b/manual/sphinx/developer_docs/code_layout.rst index b10de99cdc..2f4ec9efaf 100644 --- a/manual/sphinx/developer_docs/code_layout.rst +++ b/manual/sphinx/developer_docs/code_layout.rst @@ -345,14 +345,11 @@ The current source code files are: - sys + - :doc:`boutcomm.cxx<../_breathe_autogen/file/boutcomm_8cxx>` + - :doc:`boutexception.cxx<../_breathe_autogen/file/boutexception_8cxx>` is an exception class which are used for error handling - - :doc:`comm_group.cxx<../_breathe_autogen/file/comm__group_8cxx>` - provides routines for non-blocking collective MPI - operations. These are not available in MPI-2, though are planned - for MPI-3. - - :doc:`derivs.cxx<../_breathe_autogen/file/derivs_8cxx>` contains basic derivative methods such as upwinding, central difference and WENO methods. These are then used by From 8def7378e4ec932a969b260803e94fcdee041eb0 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Tue, 27 Nov 2018 11:15:35 +0000 Subject: [PATCH 0353/1783] List OpenMP schedule options in configure help --- configure | 2 +- configure.ac | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 2fdab25691..80ae74f6ac 100755 --- a/configure +++ b/configure @@ -1500,7 +1500,7 @@ Optional Packages: --with-mumps Link with MUMPS library for direct matrix inversions --with-arkode Use the SUNDIALS ARKODE solver --with-scorep Enable support for scorep based instrumentation - --with-openmp-schedule=static + --with-openmp-schedule=static/dynamic/guided/auto Set OpenMP schedule (default: static) --with-gcov=GCOV use given GCOV for coverage (GCOV=gcov). --with-hdf5=yes/no/PATH location of h5cc for serial HDF5 configuration diff --git a/configure.ac b/configure.ac index d39b91cb8c..0946c908fe 100644 --- a/configure.ac +++ b/configure.ac @@ -87,8 +87,8 @@ AC_ARG_ENABLE(shared, [AS_HELP_STRING([--enable-shared], [Enable building bout++ into an shared object])],,[enable_shared=no]) AC_ARG_ENABLE(openmp, [AS_HELP_STRING([--enable-openmp], [Enable building with OpenMP support])],,[enable_openmp=no]) -AC_ARG_WITH(openmp_schedule,[AS_HELP_STRING([--with-openmp-schedule=static], - [Set OpenMP schedule (default: static)])],,[with_openmp_schedule=static]) +AC_ARG_WITH(openmp_schedule,[AS_HELP_STRING([--with-openmp-schedule=static/dynamic/guided/auto], + [Set OpenMP schedule (default: static)])],,[with_openmp_schedule=static/dynamic/guided/auto]) AC_ARG_ENABLE(pvode_openmp, [AS_HELP_STRING([--enable-pvode-openmp], [Enable building PVODE with OpenMP support])],,[enable_pvode_openmp=no]) From aa70ceb69a10477f7847288f0f5addcdb8e74c6a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 27 Nov 2018 11:46:03 +0000 Subject: [PATCH 0354/1783] Fix MAYBE_UNUSED for some compilers Some compilers may have `__has_cpp_attribute` but not `maybe_unused`. Make sure MAYBE_UNUSED always gets defined to something --- include/unused.hxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/unused.hxx b/include/unused.hxx index 3026bf4fe0..701d1b65c9 100644 --- a/include/unused.hxx +++ b/include/unused.hxx @@ -44,10 +44,13 @@ #if __has_cpp_attribute(maybe_unused) # define MAYBE_UNUSED(x) [[maybe_unused]] x #endif -#elif defined(__GNUC__) +#endif +#ifndef MAYBE_UNUSED +#if defined(__GNUC__) # define MAYBE_UNUSED(x) x __attribute__((unused)) #else # define MAYBE_UNUSED(x) x #endif +#endif #endif //__UNUSED_H__ From 9010ddf819b5c4b63aa47faf9f6992aa7646d06c Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Tue, 27 Nov 2018 11:51:09 +0000 Subject: [PATCH 0355/1783] Fix default --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0946c908fe..75222ab618 100644 --- a/configure.ac +++ b/configure.ac @@ -88,7 +88,7 @@ AC_ARG_ENABLE(shared, [AS_HELP_STRING([--enable-shared], AC_ARG_ENABLE(openmp, [AS_HELP_STRING([--enable-openmp], [Enable building with OpenMP support])],,[enable_openmp=no]) AC_ARG_WITH(openmp_schedule,[AS_HELP_STRING([--with-openmp-schedule=static/dynamic/guided/auto], - [Set OpenMP schedule (default: static)])],,[with_openmp_schedule=static/dynamic/guided/auto]) + [Set OpenMP schedule (default: static)])],,[with_openmp_schedule=static]) AC_ARG_ENABLE(pvode_openmp, [AS_HELP_STRING([--enable-pvode-openmp], [Enable building PVODE with OpenMP support])],,[enable_pvode_openmp=no]) From e4349046e80b40b1b2c2a8b5c1fee05f2f5aeeff Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 27 Nov 2018 11:58:24 +0000 Subject: [PATCH 0356/1783] Add some missing autoconf macros needed to build configure --- m4/ax_append_compile_flags.m4 | 67 +++++++++++++++++++++++++++++++ m4/ax_append_flag.m4 | 71 +++++++++++++++++++++++++++++++++ m4/ax_check_compile_flag.m4 | 74 +++++++++++++++++++++++++++++++++++ m4/ax_require_defined.m4 | 37 ++++++++++++++++++ 4 files changed, 249 insertions(+) create mode 100644 m4/ax_append_compile_flags.m4 create mode 100644 m4/ax_append_flag.m4 create mode 100644 m4/ax_check_compile_flag.m4 create mode 100644 m4/ax_require_defined.m4 diff --git a/m4/ax_append_compile_flags.m4 b/m4/ax_append_compile_flags.m4 new file mode 100644 index 0000000000..5b6f1af51d --- /dev/null +++ b/m4/ax_append_compile_flags.m4 @@ -0,0 +1,67 @@ +# ============================================================================ +# https://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# For every FLAG1, FLAG2 it is checked whether the compiler works with the +# flag. If it does, the flag is added FLAGS-VARIABLE +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. During the check the flag is always added to the +# current language's flags. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: This macro depends on the AX_APPEND_FLAG and +# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with +# AX_APPEND_LINK_FLAGS. +# +# LICENSE +# +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 6 + +AC_DEFUN([AX_APPEND_COMPILE_FLAGS], +[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG]) +AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) +for flag in $1; do + AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4]) +done +])dnl AX_APPEND_COMPILE_FLAGS diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4 new file mode 100644 index 0000000000..e8c5312af6 --- /dev/null +++ b/m4/ax_append_flag.m4 @@ -0,0 +1,71 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_append_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) +# +# DESCRIPTION +# +# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space +# added in between. +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains +# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly +# FLAG. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 7 + +AC_DEFUN([AX_APPEND_FLAG], +[dnl +AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF +AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) +AS_VAR_SET_IF(FLAGS,[ + AS_CASE([" AS_VAR_GET(FLAGS) "], + [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], + [ + AS_VAR_APPEND(FLAGS,[" $1"]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) + ], + [ + AS_VAR_SET(FLAGS,[$1]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) +AS_VAR_POPDEF([FLAGS])dnl +])dnl AX_APPEND_FLAG diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4 new file mode 100644 index 0000000000..dcabb92a14 --- /dev/null +++ b/m4/ax_check_compile_flag.m4 @@ -0,0 +1,74 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 5 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/m4/ax_require_defined.m4 b/m4/ax_require_defined.m4 new file mode 100644 index 0000000000..17c3eab7da --- /dev/null +++ b/m4/ax_require_defined.m4 @@ -0,0 +1,37 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_require_defined.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_REQUIRE_DEFINED(MACRO) +# +# DESCRIPTION +# +# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have +# been defined and thus are available for use. This avoids random issues +# where a macro isn't expanded. Instead the configure script emits a +# non-fatal: +# +# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found +# +# It's like AC_REQUIRE except it doesn't expand the required macro. +# +# Here's an example: +# +# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) +# +# LICENSE +# +# Copyright (c) 2014 Mike Frysinger +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 2 + +AC_DEFUN([AX_REQUIRE_DEFINED], [dnl + m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) +])dnl AX_REQUIRE_DEFINED From 90c0aabb384a5fe06e47c7a9d3311143edd0fdd7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 27 Nov 2018 15:35:25 +0000 Subject: [PATCH 0357/1783] Split backtrace generation and prettification up Also make BoutException::makeBacktrace protected -- not useful as part of public API --- include/boutexception.hxx | 9 ++++++--- src/sys/boutexception.cxx | 21 ++++++++++----------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/include/boutexception.hxx b/include/boutexception.hxx index 1fb4c414cc..d0f15916b1 100644 --- a/include/boutexception.hxx +++ b/include/boutexception.hxx @@ -17,7 +17,7 @@ class BoutException : public std::exception { public: BoutException(const char *, ...); BoutException(std::string msg) : message(std::move(msg)) { - backtrace_message = makeBacktrace(); + makeBacktrace(); } ~BoutException() override; @@ -30,8 +30,6 @@ public: /// backtrace (if available) std::string getBacktrace() const; - std::string makeBacktrace() const; - const std::string header{"====== Exception thrown ======\n"}; protected: @@ -41,8 +39,13 @@ protected: std::string message; #ifdef BACKTRACE static constexpr unsigned int TRACE_MAX = 128; + void* trace[TRACE_MAX]; + int trace_size; + char** messages; #endif std::string backtrace_message{}; + + void makeBacktrace(); }; class BoutRhsFail : public BoutException { diff --git a/src/sys/boutexception.cxx b/src/sys/boutexception.cxx index 2c9727cf40..a1c801a4bb 100644 --- a/src/sys/boutexception.cxx +++ b/src/sys/boutexception.cxx @@ -33,17 +33,8 @@ BoutException::~BoutException() { } std::string BoutException::getBacktrace() const { - return backtrace_message + msg_stack.getDump() + "\n" + header + message + "\n"; -} - -std::string BoutException::makeBacktrace() const { std::string backtrace_message; #ifdef BACKTRACE - - void *trace[TRACE_MAX]; - auto trace_size = backtrace(trace, TRACE_MAX); - auto **messages = backtrace_symbols(trace, trace_size); - backtrace_message = "====== Exception path ======\n"; char buf[1024]; // skip first stack frame (points here) @@ -92,7 +83,15 @@ std::string BoutException::makeBacktrace() const { #else backtrace_message = "Stacktrace not enabled.\n"; #endif - return backtrace_message; + + return backtrace_message + msg_stack.getDump() + "\n" + header + message + "\n"; +} + +void BoutException::makeBacktrace() { +#ifdef BACKTRACE + trace_size = backtrace(trace, TRACE_MAX); + messages = backtrace_symbols(trace, trace_size); +#endif } /// Common set up for exceptions @@ -120,7 +119,7 @@ std::string BoutException::makeBacktrace() const { delete[] buffer; \ buffer = nullptr; \ } \ - backtrace_message = makeBacktrace(); \ + makeBacktrace(); \ } BoutException::BoutException(const char *s, ...) { INIT_EXCEPTION(s); } From 9241e72234c869e6e2d234a967f07ba8de300c4b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 27 Nov 2018 15:42:37 +0000 Subject: [PATCH 0358/1783] Add legal disclaimer about GPL licensed autoconf macros --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 2454dce8e9..f44e67b889 100644 --- a/README.md +++ b/README.md @@ -174,3 +174,10 @@ GNU Lesser General Public License for more details. A copy of the LGPL license is in [LICENSE](LICENSE). Since this is based on (and refers to) the GPL, this is included in [LICENSE.GPL](LICENSE.GPL). + +Some of the autoconf macros under [m4](m4) are licensed under +GPLv3. These are not necessary to either build or run BOUT++, but are +used in the creation of [configure](configure) from +[configure.ac](configure.ac), and are provided as a courtesy to +developers. You are free to substitute them with other autoconf macros +that provide equivalent functionality. From ee98ed62d95e8488f6f3b437b97f972d5618056a Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 27 Nov 2018 16:34:39 +0000 Subject: [PATCH 0359/1783] Improve documentation slightly --- manual/sphinx/user_docs/bout_options.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index 664ab865af..411c5c9a2d 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -336,11 +336,13 @@ name, e.g. if multiple meshes are used. - ``second``, method for second derivatives +- ``fourth``, method for fourth derivatives + - ``upwind``, method for upwinding terms - ``flux``, for conservation law terms -The methods which can be specified are U1, U4, C2, C4, W2, W3, FFT Apart +The methods which can be specified include U1, U4, C2, C4, W2, W3, FFT Apart from FFT, the first letter gives the type of method (U = upwind, C = central, W = WENO), and the number gives the order. From a1d83f746e0f3e504f626c30f3bc69e8a9d33c85 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 27 Nov 2018 16:45:41 +0000 Subject: [PATCH 0360/1783] Small documentation formatting tweak --- manual/sphinx/user_docs/differential_operators.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/manual/sphinx/user_docs/differential_operators.rst b/manual/sphinx/user_docs/differential_operators.rst index c83716727b..1579a2753c 100644 --- a/manual/sphinx/user_docs/differential_operators.rst +++ b/manual/sphinx/user_docs/differential_operators.rst @@ -159,7 +159,9 @@ method to use. User registered methods ----------------------- -_Advanced_ It is possible for the user to define their own +.. note:: The following may be considered advanced usage. + +It is possible for the user to define their own differencing routines, either by supplying a stencil using kernel or writing their own functor that calculates the differential everywhere. It is then possible to register these methods with the From 528571b8c990ee03579ab2ff81d9967834cb2c58 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 28 Nov 2018 15:52:45 +0000 Subject: [PATCH 0361/1783] Use [[gnu::unused]] attribute for GNU-ish compilers --- include/unused.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/unused.hxx b/include/unused.hxx index 701d1b65c9..c3d6f63328 100644 --- a/include/unused.hxx +++ b/include/unused.hxx @@ -47,7 +47,7 @@ #endif #ifndef MAYBE_UNUSED #if defined(__GNUC__) -# define MAYBE_UNUSED(x) x __attribute__((unused)) +# define MAYBE_UNUSED(x) [[gnu::unused]] x #else # define MAYBE_UNUSED(x) x #endif From d4fe185d50d72d2467cd53c1d09d23bec1cb526b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 28 Nov 2018 17:28:08 +0000 Subject: [PATCH 0362/1783] Make "dumb" Coordinates constructor public again; provide all fields Also a flag for calling `geometry` in the ctor --- include/bout/coordinates.hxx | 19 +++++++------ src/mesh/coordinates.cxx | 15 ++++++++--- tests/unit/field/test_vector2d.cxx | 4 +-- tests/unit/field/test_vector3d.cxx | 4 +-- tests/unit/mesh/test_coordinates.cxx | 40 ++++++++++++++-------------- tests/unit/test_extras.hxx | 10 ------- 6 files changed, 45 insertions(+), 47 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index 36e5c64a81..533e3d772e 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -53,6 +53,15 @@ public: /// Constructor interpolating from another Coordinates object Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coords_in); + /// A constructor useful for testing purposes. To use it, inherit + /// from Coordinates. If \p calculate_geometry is true (default), + /// calculate the non-uniform variables, Christoffel symbols + Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2D J, Field2D Bxy, + Field2D g11, Field2D g22, Field2D g33, Field2D g12, Field2D g13, + Field2D g23, Field2D g_11, Field2D g_22, Field2D g_33, Field2D g_12, + Field2D g_13, Field2D g_23, Field2D ShiftTorsion, Field2D IntShiftTorsion, + bool calculate_geometry = true); + ~Coordinates() = default; /*! @@ -146,16 +155,6 @@ private: int nz; // Size of mesh in Z. This is mesh->ngz-1 Mesh * localmesh; CELL_LOC location; - -protected: - /// A constructor useful for testing purposes. To use it, inherit - /// from Coordinates. Note: makes a partially constructed - /// object. Non-uniform variables, Christoffel symbols, and - /// shift-torsion variables are not defined. - Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2D J, Field2D Bxy, - Field2D g11, Field2D g22, Field2D g33, Field2D g12, Field2D g13, - Field2D g23, Field2D g_11, Field2D g_22, Field2D g_33, Field2D g_12, - Field2D g_13, Field2D g_23); }; /* diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 301c3bfb53..2c3a7cd007 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -20,13 +20,22 @@ Coordinates::Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2D J, Field2D Bxy, Field2D g11, Field2D g22, Field2D g33, Field2D g12, Field2D g13, Field2D g23, Field2D g_11, Field2D g_22, - Field2D g_33, Field2D g_12, Field2D g_13, Field2D g_23) + Field2D g_33, Field2D g_12, Field2D g_13, Field2D g_23, + Field2D ShiftTorsion, Field2D IntShiftTorsion, + bool calculate_geometry) : dx(std::move(dx)), dy(std::move(dy)), dz(dz), J(std::move(J)), Bxy(std::move(Bxy)), g11(std::move(g11)), g22(std::move(g22)), g33(std::move(g33)), g12(std::move(g12)), g13(std::move(g13)), g23(std::move(g23)), g_11(std::move(g_11)), g_22(std::move(g_22)), g_33(std::move(g_33)), g_12(std::move(g_12)), - g_13(std::move(g_13)), g_23(std::move(g_23)), nz(mesh->LocalNz), localmesh(mesh), - location(CELL_CENTRE) {} + g_13(std::move(g_13)), g_23(std::move(g_23)), ShiftTorsion(std::move(ShiftTorsion)), + IntShiftTorsion(std::move(IntShiftTorsion)), nz(mesh->LocalNz), localmesh(mesh), + location(CELL_CENTRE) { + if (calculate_geometry) { + if (geometry()) { + throw BoutException("Differential geometry failed\n"); + } + } +} Coordinates::Coordinates(Mesh *mesh) : dx(1, mesh), dy(1, mesh), dz(1), d1_dx(mesh), d1_dy(mesh), J(1, mesh), Bxy(1, mesh), diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index 1d516c3784..a6ec890c34 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -36,11 +36,11 @@ class Vector2DTest : public ::testing::Test { mesh->addBoundary(new BoundaryRegionYUp("upper_target", 1, nx - 2, mesh)); mesh->addBoundary(new BoundaryRegionYDown("lower_target", 1, nx - 2, mesh)); - dynamic_cast(mesh)->setCoordinates(std::make_shared( + dynamic_cast(mesh)->setCoordinates(std::make_shared( mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, - Field2D{5.0}, Field2D{6.0})); + Field2D{5.0}, Field2D{6.0}, Field2D{0.0}, Field2D{0.0}, false)); } ~Vector2DTest() { diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index 0b9210db38..eae149755d 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -35,11 +35,11 @@ class Vector3DTest : public ::testing::Test { mesh->addBoundary(new BoundaryRegionYUp("upper_target", 1, nx - 2, mesh)); mesh->addBoundary(new BoundaryRegionYDown("lower_target", 1, nx - 2, mesh)); - dynamic_cast(mesh)->setCoordinates(std::make_shared( + dynamic_cast(mesh)->setCoordinates(std::make_shared( mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, - Field2D{5.0}, Field2D{6.0})); + Field2D{5.0}, Field2D{6.0}, Field2D{0.0}, Field2D{0.0}, false)); } ~Vector3DTest() { diff --git a/tests/unit/mesh/test_coordinates.cxx b/tests/unit/mesh/test_coordinates.cxx index ac4a7b28fb..91781334b9 100644 --- a/tests/unit/mesh/test_coordinates.cxx +++ b/tests/unit/mesh/test_coordinates.cxx @@ -12,21 +12,21 @@ extern Mesh *mesh; using CoordinatesTest = FakeMeshFixture; TEST_F(CoordinatesTest, ZLength) { - FakeCoordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, - Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}}; + Coordinates coords{ + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{1.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, false}; EXPECT_DOUBLE_EQ(coords.zlength(), 7.0); } TEST_F(CoordinatesTest, Jacobian) { - FakeCoordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, - Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}}; + Coordinates coords{ + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{1.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, false}; EXPECT_NO_THROW(coords.jacobian()); @@ -35,11 +35,11 @@ TEST_F(CoordinatesTest, Jacobian) { } TEST_F(CoordinatesTest, CalcContravariant) { - FakeCoordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, - Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}}; + Coordinates coords{ + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, false}; output_info.disable(); coords.calcCovariant(); @@ -54,11 +54,11 @@ TEST_F(CoordinatesTest, CalcContravariant) { } TEST_F(CoordinatesTest, CalcCovariant) { - FakeCoordinates coords{mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}}; + Coordinates coords{ + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, false}; output_info.disable(); coords.calcContravariant(); diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 92eecc76ea..7bb41523e4 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -167,16 +167,6 @@ private: std::vector boundaries; }; -class FakeCoordinates : public Coordinates { -public: - FakeCoordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2D J, Field2D Bxy, - Field2D g11, Field2D g22, Field2D g33, Field2D g12, Field2D g13, - Field2D g23, Field2D g_11, Field2D g_22, Field2D g_33, Field2D g_12, - Field2D g_13, Field2D g_23) - : Coordinates(mesh, dx, dy, dz, J, Bxy, g11, g22, g33, g12, g13, g23, g_11, g_22, - g_33, g_12, g_13, g_23) {} -}; - /// Test fixture to make sure the global mesh is our fake /// one. Multiple tests have exactly the same fixture, so use a type /// alias to make a new test: From a875052144f772a6e418adc4bf47c5ca5ba675fc Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 29 Nov 2018 11:37:29 +0000 Subject: [PATCH 0363/1783] Add new constructor for ShiftedMetric that takes pre-computed zShift Moves main body of constructors into private cachePhases method --- include/bout/paralleltransform.hxx | 7 +++ src/mesh/parallel/shiftedmetric.cxx | 90 ++++++++++++++++------------- 2 files changed, 57 insertions(+), 40 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index a25540354a..92f3983b29 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -93,7 +93,10 @@ public: class ShiftedMetric : public ParallelTransform { public: ShiftedMetric() = delete; + /// Read zShift from the mesh ShiftedMetric(Mesh &mesh); + /// Use an existing zShift + ShiftedMetric(Mesh &mesh, Field2D zShift); /*! * Calculates the yup() and ydown() fields of f @@ -182,6 +185,10 @@ private: * @param[out] out A 1D array of length mesh.LocalNz, already allocated */ void shiftZ(const BoutReal *in, const std::vector &phs, BoutReal *out); + + /// Calculate and store the phases for to/from field aligned and for + /// the parallel slices using zShift + void cachePhases(); }; diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 80fdc37274..75334e6671 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -17,8 +17,7 @@ ShiftedMetric::ShiftedMetric(Mesh &m) : mesh(m), zShift(&m) { // Read the zShift angle from the mesh - - if(mesh.get(zShift, "zShift")) { + if (mesh.get(zShift, "zShift")) { // No zShift variable. Try qinty in BOUT grid files mesh.get(zShift, "qinty"); } @@ -28,76 +27,87 @@ ShiftedMetric::ShiftedMetric(Mesh &m) : mesh(m), zShift(&m) { bool twistshift = Options::root()["TwistShift"].withDefault(false); bool shift_without_twist = Options::root()["ShiftWithoutTwist"].withDefault(false); if (!twistshift and !shift_without_twist) { - throw BoutException("ShiftedMetric usually requires the option TwistShift=true\n" + throw BoutException( + "ShiftedMetric usually requires the option TwistShift=true\n" " Set ShiftWithoutTwist=true to use ShiftedMetric without TwistShift"); } - //If we wanted to be efficient we could move the following cached phase setup - //into the relevant shifting routines (with static bool first protection) - //so that we only calculate the phase if we actually call a relevant shift - //routine -- however as we're only going to do this initialisation once I - //think it's cleaner to put it in the constructor here. + cachePhases(); +} + +ShiftedMetric::ShiftedMetric(Mesh &m, Field2D zShift_) : mesh(m), zShift(std::move(zShift_)) { + cachePhases(); +} - //As we're attached to a mesh we can expect the z direction to - //not change once we've been created so precalculate the complex - //phases used in transformations - int nmodes = mesh.LocalNz/2 + 1; +void ShiftedMetric::cachePhases() { + // If we wanted to be efficient we could move the following cached phase setup + // into the relevant shifting routines (with static bool first protection) + // so that we only calculate the phase if we actually call a relevant shift + // routine -- however as we're only going to do this initialisation once I + // think it's cleaner to put it in the constructor here. + + // As we're attached to a mesh we can expect the z direction to + // not change once we've been created so precalculate the complex + // phases used in transformations + int nmodes = mesh.LocalNz / 2 + 1; BoutReal zlength = mesh.getCoordinates()->zlength(); - //Allocate storage for complex intermediate + // Allocate storage for complex intermediate cmplx.resize(nmodes); std::fill(cmplx.begin(), cmplx.end(), 0.0); - //Allocate storage for our 3d vector structures. - //This could be made more succinct but this approach is fairly - //verbose --> transparent + // Allocate storage for our 3d vector structures. + // This could be made more succinct but this approach is fairly + // verbose --> transparent fromAlignedPhs.resize(mesh.LocalNx); toAlignedPhs.resize(mesh.LocalNx); - + yupPhs.resize(mesh.LocalNx); ydownPhs.resize(mesh.LocalNx); - for(int jx=0;jx Date: Thu, 29 Nov 2018 13:26:11 +0000 Subject: [PATCH 0364/1783] Make fft_init public, add overload that takes a bool --- include/fft.hxx | 5 +++++ src/invert/fft_fftw.cxx | 44 ++++++++++++++++++++++++++--------------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/include/fft.hxx b/include/fft.hxx index dbafc214e1..105e98a750 100644 --- a/include/fft.hxx +++ b/include/fft.hxx @@ -30,6 +30,11 @@ #include "dcomplex.hxx" +class Options; + +void fft_init(bool fft_measure); +void fft_init(Options* options = nullptr); + /*! * Returns the fft of a real signal using fftw_forward * diff --git a/src/invert/fft_fftw.cxx b/src/invert/fft_fftw.cxx index 22115a106e..9c82cd5a64 100644 --- a/src/invert/fft_fftw.cxx +++ b/src/invert/fft_fftw.cxx @@ -38,20 +38,26 @@ #include #endif -bool fft_options = false; +namespace bout { +namespace fft { +bool fft_initialised = false; bool fft_measure; +} // namespace fft +} // namespace bout -void fft_init() -{ - if(fft_options) +void fft_init(Options* options) { + if (bout::fft::fft_initialised) { return; - //BOUT_OMP(critical) - { - Options *opt = Options::getRoot(); - opt = opt->getSection("fft"); - opt->get("fft_measure", fft_measure, false); - fft_options = true; } + if (options == nullptr) { + options = Options::getRoot()->getSection("fft"); + } + fft_init((*options)["fft_measure"].withDefault(false)); +} + +void fft_init(bool fft_measure) { + bout::fft::fft_measure = fft_measure; + bout::fft::fft_initialised = true; } /*********************************************************** @@ -89,8 +95,9 @@ void rfft(const BoutReal *in, int length, dcomplex *out) { fout = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * (length/2 + 1)); unsigned int flags = FFTW_ESTIMATE; - if(fft_measure) + if (bout::fft::fft_measure) { flags = FFTW_MEASURE; + } /* fftw call * Plan a real-input/complex-output discrete Fourier transform (DFT) @@ -157,8 +164,9 @@ void irfft(const dcomplex *in, int length, BoutReal *out) { fout = (double*) fftw_malloc(sizeof(double) * length); unsigned int flags = FFTW_ESTIMATE; - if(fft_measure) + if (bout::fft::fft_measure) { flags = FFTW_MEASURE; + } /* fftw call * Plan a complex-input/real-output discrete Fourier transform (DFT) @@ -225,8 +233,9 @@ void rfft(const BoutReal *in, int length, dcomplex *out) { p = new fftw_plan[n_th]; //Never freed unsigned int flags = FFTW_ESTIMATE; - if(fft_measure) + if (bout::fft::fft_measure) { flags = FFTW_MEASURE; + } for(int i=0;i(fftw_malloc(sizeof(fftw_complex) * 2 * length)); unsigned int flags = FFTW_ESTIMATE; - if(fft_measure) + if (bout::fft::fft_measure) { flags = FFTW_MEASURE; + } // fftw call // Plan a real-input/complex-output discrete Fourier transform (DFT) @@ -404,8 +415,9 @@ void DST_rev(dcomplex *in, int length, BoutReal *out) { fout = static_cast(fftw_malloc(sizeof(double) * 2 * (length - 1))); unsigned int flags = FFTW_ESTIMATE; - if(fft_measure) + if (bout::fft::fft_measure) { flags = FFTW_MEASURE; + } p = fftw_plan_dft_c2r_1d(2*(length-1), fin, fout, flags); From 5208910c26f79707876f0e9cba3adc8153ff329d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 29 Nov 2018 13:26:35 +0000 Subject: [PATCH 0365/1783] Add basic sanity tests for fft and DST --- tests/unit/invert/test_fft.cxx | 149 +++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 tests/unit/invert/test_fft.cxx diff --git a/tests/unit/invert/test_fft.cxx b/tests/unit/invert/test_fft.cxx new file mode 100644 index 0000000000..9f5f22ff31 --- /dev/null +++ b/tests/unit/invert/test_fft.cxx @@ -0,0 +1,149 @@ +#include "gtest/gtest.h" + +#include "bout/array.hxx" +#include "bout/constants.hxx" +#include "dcomplex.hxx" +#include "fft.hxx" +#include "test_extras.hxx" + +#include +#include +#include + +TEST(FFTTest, rfft) { + + // Make sure fft functions are quiet by setting fft_measure to false + fft_init(false); + + constexpr int size{8}; + + // Calculate sin(x) + cos(2x) on [0, 2pi] + Array indices(size); + std::iota(indices.begin(), indices.end(), 0); + + Array input(size); + std::transform(indices.begin(), indices.end(), input.begin(), + [](BoutReal i) -> BoutReal { + return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); + }); + + Array output(size); + + // Compute forward real FFT + rfft(input.begin(), size, output.begin()); + + // Real part should have exactly one frequency + Array expected_real(size); + std::fill(expected_real.begin(), expected_real.end(), 0.); + expected_real[2] = 0.5; + + // Imaginary part should have exactly one frequency + Array expected_imag(size); + std::fill(expected_imag.begin(), expected_imag.end(), 0.); + expected_imag[1] = -0.5; + + for (int i = 0; i < size; ++i) { + EXPECT_NEAR(real(output[i]), expected_real[i], BoutRealTolerance); + EXPECT_NEAR(imag(output[i]), expected_imag[i], BoutRealTolerance); + } +} + +TEST(FFTTest, irfft) { + + // Make sure fft functions are quiet by setting fft_measure to false + fft_init(false); + + constexpr int size{8}; + + // Make a spectrum with two frequencies + Array input(size); + std::fill(input.begin(), input.end(), dcomplex{0., 0.}); + input[1] = dcomplex{0., -0.5}; + input[2] = dcomplex{0.5, 0.}; + + Array output(size); + + // Compute inverse real FFT + irfft(input.begin(), size, output.begin()); + + // Calculate sin(x) + cos(2x) on [0, 2pi] + Array indices(size); + std::iota(indices.begin(), indices.end(), 0); + + Array expected(size); + std::transform(indices.begin(), indices.end(), expected.begin(), + [](BoutReal i) -> BoutReal { + return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); + }); + + for (int i = 0; i < size; ++i) { + EXPECT_NEAR(output[i], expected[i], BoutRealTolerance); + } +} + +TEST(FFTTest, DST) { + + // Make sure fft functions are quiet by setting fft_measure to false + fft_init(false); + + constexpr int size{8}; + + // Get numbers 0 to size-1 + Array indices(size); + std::iota(indices.begin(), indices.end(), 0); + + // Calculate sin(x) on [0, 2pi] + Array input(size); + std::transform(indices.begin(), indices.end(), input.begin(), + [](BoutReal i) -> BoutReal { return std::sin(i * TWOPI / size); }); + + Array output(size); + + // Compute forward DST + DST(input.begin(), size, output.begin()); + + // Real part should have exactly one frequency + Array expected_real(size); + std::fill(expected_real.begin(), expected_real.end(), 0.); + + // Imaginary part should have exactly one frequency + Array expected_imag(size); + std::fill(expected_imag.begin(), expected_imag.end(), 0.); + expected_imag[1] = -0.5; + + for (int i = 0; i < size; ++i) { + EXPECT_NEAR(real(output[i]), expected_real[i], BoutRealTolerance); + EXPECT_NEAR(imag(output[i]), expected_imag[i], BoutRealTolerance); + } +} + +TEST(FFTTest, DST_rev) { + + // Make sure fft functions are quiet by setting fft_measure to false + fft_init(false); + + constexpr int size{8}; + + // Make a spectrum with a single frequency + Array input(size); + std::fill(input.begin(), input.end(), dcomplex{0., 0.}); + input[1] = dcomplex{0., -0.5}; + + Array output(size); + + // Compute inverse DST + DST_rev(input.begin(), size, output.begin()); + + // Get numbers 0 to size-1 + Array indices(size); + std::iota(indices.begin(), indices.end(), 0); + + // Calculate sin(x) on [0, 2pi] + Array expected(size); + std::transform(indices.begin(), indices.end(), expected.begin(), + [](BoutReal i) -> BoutReal { return std::sin(i * TWOPI / size); }); + + for (int i = 0; i < size; ++i) { + EXPECT_NEAR(output[i], expected[i], BoutRealTolerance); + } +} From 48b69c0565cadab48c2306313f645cb029ea2ea2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 29 Nov 2018 15:37:16 +0000 Subject: [PATCH 0366/1783] Remove DST tests --- tests/unit/invert/test_fft.cxx | 67 ---------------------------------- 1 file changed, 67 deletions(-) diff --git a/tests/unit/invert/test_fft.cxx b/tests/unit/invert/test_fft.cxx index 9f5f22ff31..4c06e1717a 100644 --- a/tests/unit/invert/test_fft.cxx +++ b/tests/unit/invert/test_fft.cxx @@ -80,70 +80,3 @@ TEST(FFTTest, irfft) { EXPECT_NEAR(output[i], expected[i], BoutRealTolerance); } } - -TEST(FFTTest, DST) { - - // Make sure fft functions are quiet by setting fft_measure to false - fft_init(false); - - constexpr int size{8}; - - // Get numbers 0 to size-1 - Array indices(size); - std::iota(indices.begin(), indices.end(), 0); - - // Calculate sin(x) on [0, 2pi] - Array input(size); - std::transform(indices.begin(), indices.end(), input.begin(), - [](BoutReal i) -> BoutReal { return std::sin(i * TWOPI / size); }); - - Array output(size); - - // Compute forward DST - DST(input.begin(), size, output.begin()); - - // Real part should have exactly one frequency - Array expected_real(size); - std::fill(expected_real.begin(), expected_real.end(), 0.); - - // Imaginary part should have exactly one frequency - Array expected_imag(size); - std::fill(expected_imag.begin(), expected_imag.end(), 0.); - expected_imag[1] = -0.5; - - for (int i = 0; i < size; ++i) { - EXPECT_NEAR(real(output[i]), expected_real[i], BoutRealTolerance); - EXPECT_NEAR(imag(output[i]), expected_imag[i], BoutRealTolerance); - } -} - -TEST(FFTTest, DST_rev) { - - // Make sure fft functions are quiet by setting fft_measure to false - fft_init(false); - - constexpr int size{8}; - - // Make a spectrum with a single frequency - Array input(size); - std::fill(input.begin(), input.end(), dcomplex{0., 0.}); - input[1] = dcomplex{0., -0.5}; - - Array output(size); - - // Compute inverse DST - DST_rev(input.begin(), size, output.begin()); - - // Get numbers 0 to size-1 - Array indices(size); - std::iota(indices.begin(), indices.end(), 0); - - // Calculate sin(x) on [0, 2pi] - Array expected(size); - std::transform(indices.begin(), indices.end(), expected.begin(), - [](BoutReal i) -> BoutReal { return std::sin(i * TWOPI / size); }); - - for (int i = 0; i < size; ++i) { - EXPECT_NEAR(output[i], expected[i], BoutRealTolerance); - } -} From 19f49f58d9e6fd524e8f283701bc485db4ceacbd Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 29 Nov 2018 15:46:19 +0000 Subject: [PATCH 0367/1783] Namespace fft_init function --- include/fft.hxx | 4 ++++ src/invert/fft_fftw.cxx | 13 +++++++------ tests/unit/invert/test_fft.cxx | 4 ++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/include/fft.hxx b/include/fft.hxx index 105e98a750..1a80f72afb 100644 --- a/include/fft.hxx +++ b/include/fft.hxx @@ -32,8 +32,12 @@ class Options; +namespace bout { +namespace fft { void fft_init(bool fft_measure); void fft_init(Options* options = nullptr); +} // namespace fft +} // namespace bout /*! * Returns the fft of a real signal using fftw_forward diff --git a/src/invert/fft_fftw.cxx b/src/invert/fft_fftw.cxx index 9c82cd5a64..3763fda218 100644 --- a/src/invert/fft_fftw.cxx +++ b/src/invert/fft_fftw.cxx @@ -42,8 +42,6 @@ namespace bout { namespace fft { bool fft_initialised = false; bool fft_measure; -} // namespace fft -} // namespace bout void fft_init(Options* options) { if (bout::fft::fft_initialised) { @@ -60,6 +58,9 @@ void fft_init(bool fft_measure) { bout::fft::fft_initialised = true; } +} // namespace fft +} // namespace bout + /*********************************************************** * Real FFTs ***********************************************************/ @@ -83,7 +84,7 @@ void rfft(const BoutReal *in, int length, dcomplex *out) { fftw_free(fout); } - fft_init(); + bout::fft::fft_init(); // Initialize the input for the fourier transformation fin = (double*) fftw_malloc(sizeof(double) * length); @@ -152,7 +153,7 @@ void irfft(const dcomplex *in, int length, BoutReal *out) { fftw_free(fout); } - fft_init(); + bout::fft::fft_init(); // Initilaize the input for the inverse fourier transformation /* NOTE: Only the non-redundant input is given @@ -225,7 +226,7 @@ void rfft(const BoutReal *in, int length, dcomplex *out) { fftw_free(foutall); } - fft_init(); + bout::fft::fft_init(); finall = static_cast(fftw_malloc(sizeof(double) * length * n_th)); foutall = static_cast( @@ -296,7 +297,7 @@ void irfft(const dcomplex *in, int length, BoutReal *out) { fftw_free(foutall); } - fft_init(); + bout::fft::fft_init(); finall = static_cast( fftw_malloc(sizeof(fftw_complex) * (length / 2 + 1) * n_th)); diff --git a/tests/unit/invert/test_fft.cxx b/tests/unit/invert/test_fft.cxx index 4c06e1717a..832a1826c6 100644 --- a/tests/unit/invert/test_fft.cxx +++ b/tests/unit/invert/test_fft.cxx @@ -13,7 +13,7 @@ TEST(FFTTest, rfft) { // Make sure fft functions are quiet by setting fft_measure to false - fft_init(false); + bout::fft::fft_init(false); constexpr int size{8}; @@ -51,7 +51,7 @@ TEST(FFTTest, rfft) { TEST(FFTTest, irfft) { // Make sure fft functions are quiet by setting fft_measure to false - fft_init(false); + bout::fft::fft_init(false); constexpr int size{8}; From 591fe1159b8d81c15be6d2ee7a7d0060d2465182 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 09:54:51 +0000 Subject: [PATCH 0368/1783] Remove shorthand for WRAP_ENUM --- include/bout/index_derivs.hxx | 56 +++++++---------------------------- 1 file changed, 10 insertions(+), 46 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index fff3a69138..07949ab8f2 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -562,47 +562,9 @@ struct registerMethod { /// Some helper defines for now that allow us to wrap up enums /// and the specific methods. #define WRAP_ENUM(family, value) enumWrapper -/// Temporary short hand -#define e(family, value) WRAP_ENUM(family, value) #define REGISTER_DERIVATIVE(name) \ namespace { \ - produceCombinations, \ - Set, \ - Set, TypeContainer>, \ - Set>> \ - reg(registerMethod{}); \ - } -#define REGISTER_STAGGERED_DERIVATIVE(name) \ - namespace { \ - produceCombinations, \ - Set, \ - Set, TypeContainer>, \ - Set>> \ - reg(registerMethod{}); \ - } - -#define REGISTER_STANDARD_DERIVATIVE(name, key, nGuards, type) \ - DEFINE_STANDARD_DERIV_CORE(name, key, nGuards, type) \ - REGISTER_DERIVATIVE(name) \ - BoutReal name::operator()(const stencil& f) const - -#define REGISTER_UPWIND_DERIVATIVE(name, key, nGuards, type) \ - DEFINE_UPWIND_DERIV_CORE(name, key, nGuards, type) \ - REGISTER_DERIVATIVE(name) \ - BoutReal name::operator()(BoutReal vc, const stencil& f) const - -#define REGISTER_FLUX_DERIVATIVE(name, key, nGuards, type) \ - DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ - REGISTER_DERIVATIVE(name) \ - BoutReal name::operator()(const stencil& v, const stencil& f) const - -#define REGISTER_STANDARD_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ - DEFINE_STANDARD_DERIV_CORE(name, key, nGuards, type) \ - REGISTER_STAGGERED_DERIVATIVE(name) \ - BoutReal name::operator()(const stencil& f) const - -#define REGISTER_UPWIND_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ /*Note staggered upwind looks like flux*/ \ DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ REGISTER_STAGGERED_DERIVATIVE(name) \ @@ -618,8 +580,9 @@ struct registerMethod { /// at once for no staggering ///////////////////////////////////////////////////////////////////////////////// -produceCombinations, - Set, +produceCombinations, + Set, Set, TypeContainer>, Set< // Standard @@ -639,7 +602,7 @@ produceCombinations, DerivativeType>> registerDerivatives(registerMethod{}); -produceCombinations, Set, +produceCombinations, Set, Set, TypeContainer>, Set< // Standard @@ -653,8 +616,9 @@ produceCombinations, Set, DerivativeType>> registerDerivativesYOrtho(registerMethod{}); -produceCombinations, - Set, +produceCombinations, + Set, Set, TypeContainer>, Set< // Standard @@ -668,7 +632,8 @@ produceCombinations, DerivativeType>> registerStaggeredDerivatives(registerMethod{}); -produceCombinations, Set, +produceCombinations, + Set, Set, TypeContainer>, Set< // Standard @@ -817,10 +782,9 @@ public: metaData meta{"FFT", 0, DERIV::StandardSecond}; }; -produceCombinations, Set, +produceCombinations, Set, Set>, Set> registerFFTDerivative(registerMethod{}); -#undef e #endif From 277c747a287d8e8838b894891b6e15df623815e0 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 09:59:50 +0000 Subject: [PATCH 0369/1783] Partially revert "Remove shorthand for WRAP_ENUM" This partially reverts commit 591fe1159b8d81c15be6d2ee7a7d0060d2465182. due to unintended code removal. --- include/bout/index_derivs.hxx | 45 ++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index 07949ab8f2..fd9fdf87bb 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -563,8 +563,46 @@ struct registerMethod { /// and the specific methods. #define WRAP_ENUM(family, value) enumWrapper -#define REGISTER_DERIVATIVE(name) \ - namespace { \ +#define REGISTER_DERIVATIVE(name) \ + namespace { \ + produceCombinations, \ + Set, \ + Set, TypeContainer>, \ + Set>> \ + reg(registerMethod{}); \ + } +#define REGISTER_STAGGERED_DERIVATIVE(name) \ + namespace { \ + produceCombinations, \ + Set, \ + Set, TypeContainer>, \ + Set>> \ + reg(registerMethod{}); \ + } + +#define REGISTER_STANDARD_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_STANDARD_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_DERIVATIVE(name) \ + BoutReal name::operator()(const stencil& f) const + +#define REGISTER_UPWIND_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_UPWIND_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_DERIVATIVE(name) \ + BoutReal name::operator()(BoutReal vc, const stencil& f) const + +#define REGISTER_FLUX_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_DERIVATIVE(name) \ + BoutReal name::operator()(const stencil& v, const stencil& f) const + +#define REGISTER_STANDARD_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_STANDARD_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_STAGGERED_DERIVATIVE(name) \ + BoutReal name::operator()(const stencil& f) const + +#define REGISTER_UPWIND_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ /*Note staggered upwind looks like flux*/ \ DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ REGISTER_STAGGERED_DERIVATIVE(name) \ @@ -782,9 +820,10 @@ public: metaData meta{"FFT", 0, DERIV::StandardSecond}; }; -produceCombinations, Set, +produceCombinations, Set, Set>, Set> registerFFTDerivative(registerMethod{}); +#undef e #endif From 4693db781add4b6889da16476a1a9abc48587160 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 10:12:48 +0000 Subject: [PATCH 0370/1783] Replace e with WRAP_ENUM in last place --- include/bout/index_derivs.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index fd9fdf87bb..020fb3dabf 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -820,7 +820,7 @@ public: metaData meta{"FFT", 0, DERIV::StandardSecond}; }; -produceCombinations, Set, +produceCombinations, Set, Set>, Set> registerFFTDerivative(registerMethod{}); From 39f1b0725d6903b9353fcd5d21e5bfcfdaba4a7a Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 10:32:03 +0000 Subject: [PATCH 0371/1783] Remove need for explicit template statement --- include/bout/deriv_store.hxx | 14 ++++++++------ include/bout/index_derivs.hxx | 12 ++++-------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index b8f1a2a2f1..a56109f593 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -216,16 +216,18 @@ struct DerivativeStore { /// Templated versions of the above registration routines. template - void registerDerivative(standardFunc func) { + void registerDerivative(standardFunc func, Direction direction, Stagger stagger, + Method method) { AUTO_TRACE(); - registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), - Stagger{}.lookup(), Method{}.meta.key); + registerDerivative(func, method.meta.derivType, direction.lookup(), stagger.lookup(), + method.meta.key); }; template - void registerDerivative(upwindFunc func) { + void registerDerivative(upwindFunc func, Direction direction, Stagger stagger, + Method method) { AUTO_TRACE(); - registerDerivative(func, Method{}.meta.derivType, Direction{}.lookup(), - Stagger{}.lookup(), Method{}.meta.key); + registerDerivative(func, method.meta.derivType, direction.lookup(), stagger.lookup(), + method.meta.key); }; /// Routines to return a specific differential operator. Note we diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index 020fb3dabf..1a467b1952 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -514,8 +514,7 @@ struct registerMethod { // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region Method{}, _1, _2, _3); - derivativeRegister.template registerDerivative( - theFunc); + derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, Method{}); } else { const auto theFunc = std::bind( // Method to store in function @@ -523,8 +522,7 @@ struct registerMethod { // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region Method{}, _1, _2, _3); - derivativeRegister.template registerDerivative( - theFunc); + derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, Method{}); } break; } @@ -538,8 +536,7 @@ struct registerMethod { // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region Method{}, _1, _2, _3, _4); - derivativeRegister.template registerDerivative( - theFunc); + derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, Method{}); } else { const auto theFunc = std::bind( // Method to store in function @@ -548,8 +545,7 @@ struct registerMethod { // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region Method{}, _1, _2, _3, _4); - derivativeRegister.template registerDerivative( - theFunc); + derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, Method{}); } break; } From 163052e12f9756031452dada833400dc4a68bbf4 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 11:53:16 +0000 Subject: [PATCH 0372/1783] Make default methods map private --- include/bout/deriv_store.hxx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index a56109f593..c6ef3faffe 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -396,14 +396,6 @@ struct DerivativeStore { } } - /// The following stores what actual method to use when DIFF_DEFAULT - /// is passed. The key is determined using the getKey routine here, - /// where the name we pass is determined by the type of method (standard, - /// upwind etc.). Note for now we'll always use STAGGER::None as we - /// currently assume the default method is independent of staggering -- - /// it might be useful to relax this assumption! - storageType defaultMethods; - /// Provide a method to override/force a specific default method void forceDefaultMethod(std::string methodName, DERIV deriv, DIRECTION direction, STAGGER stagger = STAGGER::None) { @@ -435,6 +427,14 @@ private: storageType> registeredMethods; + /// The following stores what actual method to use when DIFF_DEFAULT + /// is passed. The key is determined using the getKey routine here, + /// where the name we pass is determined by the type of method (standard, + /// upwind etc.). Note for now we'll always use STAGGER::None as we + /// currently assume the default method is independent of staggering -- + /// it might be useful to relax this assumption! + storageType defaultMethods; + std::string getMethodName(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { AUTO_TRACE(); From 981c173b380759cf953b6d56d5df43c0b06f1e22 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 12:30:47 +0000 Subject: [PATCH 0373/1783] Put braces around one statement logic --- include/bout/mesh.hxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 9fc0d01b19..4d8614e550 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -840,8 +840,9 @@ T Mesh::indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, // Handle the staggering const CELL_LOC inloc = f.getLocation(); // Input locations const CELL_LOC vloc = vel.getLocation(); - if (outloc == CELL_DEFAULT) + if (outloc == CELL_DEFAULT) { outloc = inloc; + } const STAGGER stagger = getStagger(vloc, inloc, outloc, allowedStaggerLoc); // Check for early exit @@ -905,8 +906,9 @@ T Mesh::indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& // Handle the staggering const CELL_LOC inloc = f.getLocation(); // Input location - if (outloc == CELL_DEFAULT) + if (outloc == CELL_DEFAULT) { outloc = inloc; + } const STAGGER stagger = getStagger(inloc, outloc, allowedStaggerLoc); // Check for early exit From 1dd2e1092f32d040972d6337b75e8ed2e07c3b85 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 12:48:38 +0000 Subject: [PATCH 0374/1783] Replace throws with static_assert --- include/bout/mesh.hxx | 19 +++++++++++-------- include/bout/region.hxx | 12 ++++++------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 4d8614e550..68787bd4ce 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -807,7 +807,10 @@ T Mesh::indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, // Checks static_assert(std::is_base_of::value || std::is_base_of::value, - "indexDDX only works on Field2D or Field3D input"); + "indexFlowDerivative only works on Field2D or Field3D input"); + + static_assert(derivType == DERIV::Upwind || derivType == DERIV::Flux, + "indexFlowDerivative only works for derivType in {Upwind, Flux}."); // Special handling for SPLIT method if ((derivType == DERIV::Flux) && (method == DIFF_METHOD_STRING(DIFF_SPLIT))) { @@ -859,10 +862,8 @@ T Mesh::indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, typename DerivativeStore::upwindFunc derivativeMethod; if (derivType == DERIV::Upwind) { derivativeMethod = derivativeStore.getUpwindDerivative(method, direction, stagger); - } else if (derivType == DERIV::Flux) { - derivativeMethod = derivativeStore.getFluxDerivative(method, direction, stagger); } else { - throw BoutException("Invalid derivative type in call to indexFlowDerivative."); + derivativeMethod = derivativeStore.getFluxDerivative(method, direction, stagger); } // Create the result field @@ -889,7 +890,11 @@ T Mesh::indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& // Checks static_assert(std::is_base_of::value || std::is_base_of::value, - "indexDDX only works on Field2D or Field3D input"); + "indexStandardDerivative only works on Field2D or Field3D input"); + + static_assert(order == 1 || order == 2 || order == 4, + "indexStandardDerivative only works for order in {1, 2, 4}"); + // Check that the mesh is correct ASSERT1(this == f.getMesh()); // Check that the input variable has data @@ -929,11 +934,9 @@ T Mesh::indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& } else if (order == 2) { derivativeMethod = derivativeStore.getStandard2ndDerivative(method, direction, stagger); - } else if (order == 4) { + } else { derivativeMethod = derivativeStore.getStandard4thDerivative(method, direction, stagger); - } else { - throw BoutException("Invalid order used in indexStandardDerivative."); } // Create the result field diff --git a/include/bout/region.hxx b/include/bout/region.hxx index 59a539050b..799faeab0e 100644 --- a/include/bout/region.hxx +++ b/include/bout/region.hxx @@ -231,6 +231,9 @@ public: /// to the `dd` template argument. template const inline SpecificInd plus() const{ + static_assert(dir == DIRECTION::X || dir == DIRECTION::Y || dir == DIRECTION::Z + || dir == DIRECTION::YAligned || dir == DIRECTION::YOrthogonal, + "Unhandled DIRECTION in SpecificInd::plus"); switch(dir) { case(DIRECTION::X): return xp(dd); @@ -240,9 +243,6 @@ public: return yp(dd); case(DIRECTION::Z): return zp(dd); -#if CHECK > 2 - default: throw BoutException("Invalid direction passed to SpecificInd.plus"); -#endif } } @@ -251,6 +251,9 @@ public: /// to the `dd` template argument. template const inline SpecificInd minus() const{ + static_assert(dir == DIRECTION::X || dir == DIRECTION::Y || dir == DIRECTION::Z + || dir == DIRECTION::YAligned || dir == DIRECTION::YOrthogonal, + "Unhandled DIRECTION in SpecificInd::minus"); switch(dir) { case(DIRECTION::X): return xm(dd); @@ -260,9 +263,6 @@ public: return ym(dd); case(DIRECTION::Z): return zm(dd); -#if CHECK > 2 - default: throw BoutException("Invalid direction passed to SpecificInd.minus"); -#endif } } From a64bb2db16744b162003b9cbe88c0011e89848e6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 30 Nov 2018 13:21:21 +0000 Subject: [PATCH 0375/1783] Add fft overloads for Array --- include/fft.hxx | 33 ++++++++++++----- src/invert/fft_fftw.cxx | 30 ++++++++++----- tests/unit/invert/test_fft.cxx | 67 ++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 19 deletions(-) diff --git a/include/fft.hxx b/include/fft.hxx index 1a80f72afb..a3e1ff175d 100644 --- a/include/fft.hxx +++ b/include/fft.hxx @@ -30,15 +30,6 @@ #include "dcomplex.hxx" -class Options; - -namespace bout { -namespace fft { -void fft_init(bool fft_measure); -void fft_init(Options* options = nullptr); -} // namespace fft -} // namespace bout - /*! * Returns the fft of a real signal using fftw_forward * @@ -87,4 +78,28 @@ void DST(const BoutReal *in, int length, dcomplex *out); */ void DST_rev(dcomplex *in, int length, BoutReal *out); +template +class Array; + +class Options; + +namespace bout { +namespace fft { +/// Should the FFT functions find and use an optimised plan? +void fft_init(bool fft_measure); +/// Should the FFT functions find and use an optimised plan? +/// +/// If \p options is not nullptr, it should contain a bool called +/// "fftw_measure". If it is nullptr, use the global `Options` root +void fft_init(Options* options = nullptr); + +/// Returns the fft of a real signal \p in using fftw_forward +Array rfft(const Array& in); + +/// Take the inverse fft of signal \p in where the outputs are only reals +Array irfft(const Array& in); + +} // namespace fft +} // namespace bout + #endif // __FFT_H__ diff --git a/src/invert/fft_fftw.cxx b/src/invert/fft_fftw.cxx index 3763fda218..b889ef19a5 100644 --- a/src/invert/fft_fftw.cxx +++ b/src/invert/fft_fftw.cxx @@ -126,16 +126,6 @@ void rfft(const BoutReal *in, int length, dcomplex *out) { out[i] = dcomplex(fout[i][0], fout[i][1]) * fac; // Normalise } -const Array rfft(const Array &in) { - ASSERT1(!in.empty()); // Check that there is data - - int size = in.size(); - Array out(size); // Allocates data array - - rfft(in.begin(), size, out.begin()); - return out; -} - void irfft(const dcomplex *in, int length, BoutReal *out) { // static variables initialized once static fftw_complex *fin; @@ -446,3 +436,23 @@ void DST_rev(dcomplex *in, int length, BoutReal *out) { for(int i=1;i bout::fft::rfft(const Array& in) { + ASSERT1(!in.empty()); + + int size{in.size()}; + Array out{size}; + + ::rfft(in.begin(), size, out.begin()); + return out; +} + +Array bout::fft::irfft(const Array& in) { + ASSERT1(!in.empty()); + + int size{in.size()}; + Array out{size}; + + ::irfft(in.begin(), size, out.begin()); + return out; +} diff --git a/tests/unit/invert/test_fft.cxx b/tests/unit/invert/test_fft.cxx index 832a1826c6..ff974de3f9 100644 --- a/tests/unit/invert/test_fft.cxx +++ b/tests/unit/invert/test_fft.cxx @@ -80,3 +80,70 @@ TEST(FFTTest, irfft) { EXPECT_NEAR(output[i], expected[i], BoutRealTolerance); } } + +TEST(FFTTest, rfftWithArray) { + + // Make sure fft functions are quiet by setting fft_measure to false + bout::fft::fft_init(false); + + constexpr int size{8}; + + // Calculate sin(x) + cos(2x) on [0, 2pi] + Array indices(size); + std::iota(indices.begin(), indices.end(), 0); + + Array input(size); + std::transform(indices.begin(), indices.end(), input.begin(), + [](BoutReal i) -> BoutReal { + return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); + }); + + // Compute forward real FFT + auto output = bout::fft::rfft(input); + + // Real part should have exactly one frequency + Array expected_real(size); + std::fill(expected_real.begin(), expected_real.end(), 0.); + expected_real[2] = 0.5; + + // Imaginary part should have exactly one frequency + Array expected_imag(size); + std::fill(expected_imag.begin(), expected_imag.end(), 0.); + expected_imag[1] = -0.5; + + for (int i = 0; i < size; ++i) { + EXPECT_NEAR(real(output[i]), expected_real[i], BoutRealTolerance); + EXPECT_NEAR(imag(output[i]), expected_imag[i], BoutRealTolerance); + } +} + +TEST(FFTTest, irfftWithArray) { + + // Make sure fft functions are quiet by setting fft_measure to false + bout::fft::fft_init(false); + + constexpr int size{8}; + + // Make a spectrum with two frequencies + Array input(size); + std::fill(input.begin(), input.end(), dcomplex{0., 0.}); + input[1] = dcomplex{0., -0.5}; + input[2] = dcomplex{0.5, 0.}; + + // Compute inverse real FFT + auto output = bout::fft::irfft(input); + + // Calculate sin(x) + cos(2x) on [0, 2pi] + Array indices(size); + std::iota(indices.begin(), indices.end(), 0); + + Array expected(size); + std::transform(indices.begin(), indices.end(), expected.begin(), + [](BoutReal i) -> BoutReal { + return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); + }); + + for (int i = 0; i < size; ++i) { + EXPECT_NEAR(output[i], expected[i], BoutRealTolerance); + } +} From 99bf00de431e08f7015899ea85949c8a4f1e51e2 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 13:28:11 +0000 Subject: [PATCH 0376/1783] Simplify handling of derivative type/order in mesh header. Pushes some complexity into derivStore --- include/bout/deriv_store.hxx | 107 ++++++++++++++++++++--------------- include/bout/mesh.hxx | 70 ++++++++++++----------- 2 files changed, 97 insertions(+), 80 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index c6ef3faffe..4ccedb4aae 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -51,10 +51,10 @@ template struct DerivativeStore { using standardFunc = std::function; - using upwindFunc = - std::function; - using fluxFunc = + using flowFunc = std::function; + using upwindFunc = flowFunc; + using fluxFunc = flowFunc; #ifdef USE_ORDERED_MAP_FOR_DERIVATIVE_STORE template @@ -236,75 +236,90 @@ struct DerivativeStore { /// different name for each of the method-classes so everything is /// consistently treated standardFunc getStandardDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) const { + STAGGER stagger = STAGGER::None, + DERIV derivType = DERIV::Standard) const { + AUTO_TRACE(); const auto realName = nameLookup( - name, - defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Standard)))); + name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(derivType)))); const auto key = getKey(direction, stagger, realName); - const auto resultOfFind = standard.find(key); - if (resultOfFind != standard.end()) + + const storageType* theMap = nullptr; + + if (derivType == DERIV::Standard) { + theMap = &standard; + } else if (derivType == DERIV::StandardSecond) { + theMap = &standardSecond; + } else if (derivType == DERIV::StandardFourth) { + theMap = &standardFourth; + } else { + throw BoutException("getStandardDerivative only works for derivType in {Standard, " + "StandardSecond, StandardFourth} but receieved %s", + DERIV_STRING(derivType).c_str()); + }; + + const auto resultOfFind = (*theMap).find(key); + if (resultOfFind != (*theMap).end()) return resultOfFind->second; + throw BoutException( - "Couldn't find requested method %s in map for standard derivative.", - getMethodName(realName, direction, stagger).c_str()); + "Couldn't find requested method %s in map for standard derivative of type %s.", + getMethodName(realName, direction, stagger).c_str(), + DERIV_STRING(derivType).c_str()); }; standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { AUTO_TRACE(); - const auto realName = - nameLookup(name, - defaultMethods.at( - getKey(direction, stagger, DERIV_STRING(DERIV::StandardSecond)))); - const auto key = getKey(direction, stagger, realName); - const auto resultOfFind = standardSecond.find(key); - if (resultOfFind != standardSecond.end()) - return resultOfFind->second; - throw BoutException("Couldn't find requested method %s in map for " - "standardSecond derivative.", - getMethodName(realName, direction, stagger).c_str()); + return getStandardDerivative(name, direction, stagger, DERIV::StandardSecond); }; standardFunc getStandard4thDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { AUTO_TRACE(); - const auto realName = - nameLookup(name, - defaultMethods.at( - getKey(direction, stagger, DERIV_STRING(DERIV::StandardFourth)))); - const auto key = getKey(direction, stagger, realName); - const auto resultOfFind = standardFourth.find(key); - if (resultOfFind != standardFourth.end()) - return resultOfFind->second; - throw BoutException("Couldn't find requested method %s in map for " - "standardFourth derivative.", - getMethodName(realName, direction, stagger).c_str()); + return getStandardDerivative(name, direction, stagger, DERIV::StandardFourth); }; - upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, - STAGGER stagger = STAGGER::None) const { + flowFunc getFlowDerivative(std::string name, DIRECTION direction, + STAGGER stagger = STAGGER::None, + DERIV derivType = DERIV::Upwind) const { AUTO_TRACE(); const auto realName = nameLookup( name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Upwind)))); const auto key = getKey(direction, stagger, realName); - const auto resultOfFind = upwind.find(key); - if (resultOfFind != upwind.end()) + + const storageType* theMap = nullptr; + + if (derivType == DERIV::Upwind) { + theMap = &upwind; + } else if (derivType == DERIV::Flux) { + theMap = &flux; + } else { + throw BoutException( + "getFlowDerivative only works for derivType in {Upwind, Flux} but receieved %s", + DERIV_STRING(derivType).c_str()); + }; + + const auto resultOfFind = (*theMap).find(key); + if (resultOfFind != (*theMap).end()) return resultOfFind->second; - throw BoutException("Couldn't find requested method %s in map for upwind derivative.", - getMethodName(realName, direction, stagger).c_str()); + + throw BoutException( + "Couldn't find requested method %s in map for standard flow of type %s.", + getMethodName(realName, direction, stagger).c_str(), + DERIV_STRING(derivType).c_str()); + } + + upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, + STAGGER stagger = STAGGER::None) const { + AUTO_TRACE(); + return getFlowDerivative(name, direction, stagger, DERIV::Upwind); }; + fluxFunc getFluxDerivative(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { AUTO_TRACE(); - const auto realName = nameLookup( - name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Flux)))); - const auto key = getKey(direction, stagger, realName); - const auto resultOfFind = flux.find(key); - if (resultOfFind != flux.end()) - return resultOfFind->second; - throw BoutException("Couldn't find requested method %s in map for flux derivative.", - getMethodName(realName, direction, stagger).c_str()); + return getFlowDerivative(name, direction, stagger, DERIV::Flux); }; void initialise(Options* options) { diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 68787bd4ce..5ec69d51ef 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -488,19 +488,22 @@ class Mesh { template T indexDDX(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative(f, outloc, method, region); + return indexStandardDerivative(f, outloc, method, + region); } template T indexD2DX2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative(f, outloc, method, region); + return indexStandardDerivative( + f, outloc, method, region); } template T indexD4DX4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative(f, outloc, method, region); + return indexStandardDerivative( + f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// @@ -510,11 +513,12 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { if (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))) { - return indexStandardDerivative(f, outloc, method, - region); + return indexStandardDerivative( + f, outloc, method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = indexStandardDerivative(f, outloc, method, region); + T result = indexStandardDerivative( + f, outloc, method, region); return f.getMesh()->fromFieldAligned(result); } } @@ -524,11 +528,12 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { if (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))) { - return indexStandardDerivative(f, outloc, method, - region); + return indexStandardDerivative( + f, outloc, method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = indexStandardDerivative(f, outloc, method, region); + T result = indexStandardDerivative( + f, outloc, method, region); return f.getMesh()->fromFieldAligned(result); } } @@ -538,11 +543,12 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { if (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))) { - return indexStandardDerivative(f, outloc, method, - region); + return indexStandardDerivative( + f, outloc, method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = indexStandardDerivative(f, outloc, method, region); + T result = indexStandardDerivative( + f, outloc, method, region); return f.getMesh()->fromFieldAligned(result); } } @@ -551,19 +557,22 @@ class Mesh { template T indexDDZ(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative(f, outloc, method, region); + return indexStandardDerivative(f, outloc, method, + region); } template T indexD2DZ2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative(f, outloc, method, region); + return indexStandardDerivative( + f, outloc, method, region); } template T indexD4DZ4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative(f, outloc, method, region); + return indexStandardDerivative( + f, outloc, method, region); } ////// ADVECTION AND FLUX OPERATORS @@ -781,7 +790,7 @@ class Mesh { private: /// The main kernel used for all standard derivatives - template + template T indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method, REGION region) const; @@ -818,7 +827,8 @@ T Mesh::indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) auto tmp = indexFlowDerivative(vel, f, outloc, "DEFAULT", region); - tmp += indexStandardDerivative(vel, outloc, "DEFAULT", region) + tmp += indexStandardDerivative(vel, outloc, "DEFAULT", + region) * interp_to(f, tmp.getLocation()); return tmp; } @@ -860,11 +870,8 @@ T Mesh::indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, // Lookup the method auto& derivativeStore = DerivativeStore::getInstance(); typename DerivativeStore::upwindFunc derivativeMethod; - if (derivType == DERIV::Upwind) { - derivativeMethod = derivativeStore.getUpwindDerivative(method, direction, stagger); - } else { - derivativeMethod = derivativeStore.getFluxDerivative(method, direction, stagger); - } + derivativeMethod = + derivativeStore.getFlowDerivative(method, direction, stagger, derivType); // Create the result field T result(f.getMesh()); @@ -883,7 +890,7 @@ T Mesh::indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, return result; } -template +template T Mesh::indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method, REGION region) const { AUTO_TRACE(); @@ -892,8 +899,10 @@ T Mesh::indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& static_assert(std::is_base_of::value || std::is_base_of::value, "indexStandardDerivative only works on Field2D or Field3D input"); - static_assert(order == 1 || order == 2 || order == 4, - "indexStandardDerivative only works for order in {1, 2, 4}"); + static_assert(derivType == DERIV::Standard || derivType == DERIV::StandardSecond + || derivType == DERIV::StandardFourth, + "indexStandardDerivative only works for derivType in {Standard, " + "StandardSecond, StandardFourth}"); // Check that the mesh is correct ASSERT1(this == f.getMesh()); @@ -929,15 +938,8 @@ T Mesh::indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& auto& derivativeStore = DerivativeStore::getInstance(); typename DerivativeStore::standardFunc derivativeMethod; - if (order == 1) { - derivativeMethod = derivativeStore.getStandardDerivative(method, direction, stagger); - } else if (order == 2) { - derivativeMethod = - derivativeStore.getStandard2ndDerivative(method, direction, stagger); - } else { - derivativeMethod = - derivativeStore.getStandard4thDerivative(method, direction, stagger); - } + derivativeMethod = + derivativeStore.getStandardDerivative(method, direction, stagger, derivType); // Create the result field T result(f.getMesh()); From d972d0429a91af5cf2e041b85af92c1a23086a84 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 13:33:27 +0000 Subject: [PATCH 0377/1783] Use -> rather than direct dereferencing --- include/bout/deriv_store.hxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 4ccedb4aae..a59a4cdf93 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -258,8 +258,8 @@ struct DerivativeStore { DERIV_STRING(derivType).c_str()); }; - const auto resultOfFind = (*theMap).find(key); - if (resultOfFind != (*theMap).end()) + const auto resultOfFind = theMap->find(key); + if (resultOfFind != theMap->end()) return resultOfFind->second; throw BoutException( @@ -300,8 +300,8 @@ struct DerivativeStore { DERIV_STRING(derivType).c_str()); }; - const auto resultOfFind = (*theMap).find(key); - if (resultOfFind != (*theMap).end()) + const auto resultOfFind = theMap->find(key); + if (resultOfFind != theMap->end()) return resultOfFind->second; throw BoutException( From b2ff064bfc74502c9c57b031d93e9b12740b670e Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 13:39:40 +0000 Subject: [PATCH 0378/1783] Use MAYBE_UNUSED instead of guarded UNUSED --- src/mesh/index_derivs.cxx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 764895a9d8..19ef95a32d 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -55,13 +55,8 @@ STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, } } -#if CHECK > 0 -STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, - const CELL_LOC allowedStaggerLoc) const { -#else -STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC UNUSED(inloc), +STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC MAYBE_UNUSED(inloc), const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { -#endif TRACE("Mesh::getStagger -- four arguments"); ASSERT1(vloc == inloc || (vloc == CELL_CENTRE && inloc == allowedStaggerLoc) || (vloc == allowedStaggerLoc && inloc == CELL_CENTRE)); From d7facafa623403548327c8130fc8817a601e4806 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 14:53:31 +0000 Subject: [PATCH 0379/1783] Correct use of MAYBE_UNUSED --- src/mesh/index_derivs.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 19ef95a32d..ea06fa66e7 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -55,7 +55,7 @@ STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, } } -STAGGER Mesh::getStagger(const CELL_LOC vloc, const CELL_LOC MAYBE_UNUSED(inloc), +STAGGER Mesh::getStagger(const CELL_LOC vloc, MAYBE_UNUSED(const CELL_LOC inloc), const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { TRACE("Mesh::getStagger -- four arguments"); ASSERT1(vloc == inloc || (vloc == CELL_CENTRE && inloc == allowedStaggerLoc) From 9f2113e50c8506887a41bdfd7db3ea52e86e4aa3 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 16:43:14 +0000 Subject: [PATCH 0380/1783] Move main index?Derivative routines into standalone header Removes them from being mesh members Rewrite approach for Flux:Split method to be implemented as all other derivatives. --- include/bout/index_derivs.hxx | 33 ++++- include/bout/index_derivs_interface.hxx | 180 ++++++++++++++++++++++++ include/bout/mesh.hxx | 167 ++-------------------- 3 files changed, 222 insertions(+), 158 deletions(-) create mode 100644 include/bout/index_derivs_interface.hxx diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index 1a467b1952..49e64367e4 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -35,12 +35,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -821,5 +823,34 @@ produceCombinations, Set, Set> registerFFTDerivative(registerMethod{}); -#undef e +class SplitFluxDerivativeType { +public: + template + void standard(const T&, T&, REGION) const { + AUTO_TRACE(); + throw BoutException("The SPLIT method isn't available for standard"); + } + + template + void upwindOrFlux(const T& vel, const T& var, T& result, REGION region) const { + AUTO_TRACE(); + // Split into an upwind and a central differencing part + // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) + result = indexFlowDerivative( + vel, var, result.getLocation(), "DEFAULT", region); + result += indexStandardDerivative( + vel, result.getLocation(), "DEFAULT", region) + * interp_to(var, result.getLocation()); + return; + } + metaData meta{"SPLIT", 2, DERIV::Flux}; +}; + +produceCombinations, + Set, + Set, TypeContainer>, + Set> + registerSplitDerivative(registerMethod{}); + #endif diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx new file mode 100644 index 0000000000..b2b6189f56 --- /dev/null +++ b/include/bout/index_derivs_interface.hxx @@ -0,0 +1,180 @@ +/*!************************************************************************ + * \file index_derivs_interface.hxx + * + * Definition of main derivative kernels + * + ************************************************************************** + * Copyright 2018 + * D.Dickinson + * + * Contact: Ben Dudson, bd512@york.ac.uk + * + * This file is part of BOUT++. + * + * BOUT++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BOUT++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with BOUT++. If not, see . + * + **************************************************************************/ + +#ifndef __INDEX_DERIVS_INTERFACE_HXX__ +#define __INDEX_DERIVS_INTERFACE_HXX__ + +#include +#include + +class Field3D; +class Field2D; + +/// The main kernel used for all upwind and flux derivatives +template +T indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, + const std::string& method, REGION region) { + AUTO_TRACE(); + + // Checks + static_assert(std::is_base_of::value || std::is_base_of::value, + "indexFlowDerivative only works on Field2D or Field3D input"); + + static_assert(derivType == DERIV::Upwind || derivType == DERIV::Flux, + "indexFlowDerivative only works for derivType in {Upwind, Flux}."); + + auto* localmesh = f.getMesh(); + + // Check that the mesh is correct + ASSERT1(vel.getMesh() == localmesh); + // Check that the input variable has data + ASSERT1(f.isAllocated()); + ASSERT1(vel.isAllocated()); + + // Check the input data is valid + { + TRACE("Checking inputs"); + checkData(f); + checkData(vel); + } + + // Define properties of this approach + const CELL_LOC allowedStaggerLoc = + localmesh->template getAllowedStaggerLoc(); + + // Handle the staggering + const CELL_LOC inloc = f.getLocation(); // Input locations + const CELL_LOC vloc = vel.getLocation(); + if (outloc == CELL_DEFAULT) { + outloc = inloc; + } + const STAGGER stagger = localmesh->getStagger(vloc, inloc, outloc, allowedStaggerLoc); + + // Check for early exit + const int nPoint = localmesh->template getNpoints(); + + if (nPoint == 1) { + auto tmp = T(0., localmesh); + tmp.setLocation(outloc); + return tmp; + } + + // Lookup the method + auto& derivativeStore = DerivativeStore::getInstance(); + typename DerivativeStore::upwindFunc derivativeMethod; + derivativeMethod = + derivativeStore.getFlowDerivative(method, direction, stagger, derivType); + + // Create the result field + T result(localmesh); + result.allocate(); // Make sure data allocated + result.setLocation(outloc); + + // Apply method + derivativeMethod(vel, f, result, region); + + // Check the result is valid + { + TRACE("Checking result"); + checkData(result); + } + + return result; +} + +/// The main kernel used for all standard derivatives +template +T indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method, + REGION region) { + AUTO_TRACE(); + + // Checks + static_assert(std::is_base_of::value || std::is_base_of::value, + "indexStandardDerivative only works on Field2D or Field3D input"); + + static_assert(derivType == DERIV::Standard || derivType == DERIV::StandardSecond + || derivType == DERIV::StandardFourth, + "indexStandardDerivative only works for derivType in {Standard, " + "StandardSecond, StandardFourth}"); + + auto* localmesh = f.getMesh(); + + // Check that the input variable has data + ASSERT1(f.isAllocated()); + + // Check the input data is valid + { + TRACE("Checking input"); + checkData(f); + } + + // Define properties of this approach + const CELL_LOC allowedStaggerLoc = + localmesh->template getAllowedStaggerLoc(); + + // Handle the staggering + const CELL_LOC inloc = f.getLocation(); // Input location + if (outloc == CELL_DEFAULT) { + outloc = inloc; + } + const STAGGER stagger = localmesh->getStagger(inloc, outloc, allowedStaggerLoc); + + // Check for early exit + const int nPoint = localmesh->template getNpoints(); + + if (nPoint == 1) { + auto tmp = T(0., localmesh); + tmp.setLocation(outloc); + return tmp; + } + + // Lookup the method + auto& derivativeStore = DerivativeStore::getInstance(); + typename DerivativeStore::standardFunc derivativeMethod; + + derivativeMethod = + derivativeStore.getStandardDerivative(method, direction, stagger, derivType); + + // Create the result field + T result(localmesh); + result.allocate(); // Make sure data allocated + result.setLocation(outloc); + + // Apply method + derivativeMethod(f, result, region); + + // Check the result is valid + { + TRACE("Checking result"); + checkData(result); + } + + return result; +} + +#endif diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 5ec69d51ef..27f547006f 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -46,6 +46,8 @@ class Mesh; #include "mpi.h" #include +#include + #include "field_data.hxx" #include "bout_types.hxx" #include "field2d.hxx" @@ -789,15 +791,15 @@ class Mesh { void derivs_init(Options* options); private: - /// The main kernel used for all standard derivatives - template - T indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method, - REGION region) const; + // /// The main kernel used for all standard derivatives + // template + // T indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method, + // REGION region) const; - /// The main kernel used for all upwind and flux derivatives - template - T indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, - const std::string& method, REGION region) const; + // /// The main kernel used for all upwind and flux derivatives + // template + // T indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, + // const std::string& method, REGION region) const; /// Allocates default Coordinates objects std::shared_ptr createDefaultCoordinates(const CELL_LOC location); @@ -809,155 +811,6 @@ private: Array indexLookup3Dto2D; }; -template -T Mesh::indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, - const std::string& method, REGION region) const { - AUTO_TRACE(); - - // Checks - static_assert(std::is_base_of::value || std::is_base_of::value, - "indexFlowDerivative only works on Field2D or Field3D input"); - - static_assert(derivType == DERIV::Upwind || derivType == DERIV::Flux, - "indexFlowDerivative only works for derivType in {Upwind, Flux}."); - - // Special handling for SPLIT method - if ((derivType == DERIV::Flux) && (method == DIFF_METHOD_STRING(DIFF_SPLIT))) { - // Split into an upwind and a central differencing part - // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) - auto tmp = indexFlowDerivative(vel, f, outloc, "DEFAULT", - region); - tmp += indexStandardDerivative(vel, outloc, "DEFAULT", - region) - * interp_to(f, tmp.getLocation()); - return tmp; - } - - // Check that the mesh is correct - ASSERT1(this == f.getMesh()); - ASSERT1(this == vel.getMesh()); - // Check that the input variable has data - ASSERT1(f.isAllocated()); - ASSERT1(vel.isAllocated()); - - // Check the input data is valid - { - TRACE("Checking inputs"); - checkData(f); - checkData(vel); - } - - // Define properties of this approach - const CELL_LOC allowedStaggerLoc = getAllowedStaggerLoc(); - - // Handle the staggering - const CELL_LOC inloc = f.getLocation(); // Input locations - const CELL_LOC vloc = vel.getLocation(); - if (outloc == CELL_DEFAULT) { - outloc = inloc; - } - const STAGGER stagger = getStagger(vloc, inloc, outloc, allowedStaggerLoc); - - // Check for early exit - const int nPoint = getNpoints(); - - if (nPoint == 1) { - auto tmp = T(0., f.getMesh()); - tmp.setLocation(outloc); - return tmp; - } - - // Lookup the method - auto& derivativeStore = DerivativeStore::getInstance(); - typename DerivativeStore::upwindFunc derivativeMethod; - derivativeMethod = - derivativeStore.getFlowDerivative(method, direction, stagger, derivType); - - // Create the result field - T result(f.getMesh()); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - // Apply method - derivativeMethod(vel, f, result, region); - - // Check the result is valid - { - TRACE("Checking result"); - checkData(result); - } - - return result; -} - -template -T Mesh::indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method, - REGION region) const { - AUTO_TRACE(); - - // Checks - static_assert(std::is_base_of::value || std::is_base_of::value, - "indexStandardDerivative only works on Field2D or Field3D input"); - - static_assert(derivType == DERIV::Standard || derivType == DERIV::StandardSecond - || derivType == DERIV::StandardFourth, - "indexStandardDerivative only works for derivType in {Standard, " - "StandardSecond, StandardFourth}"); - - // Check that the mesh is correct - ASSERT1(this == f.getMesh()); - // Check that the input variable has data - ASSERT1(f.isAllocated()); - - // Check the input data is valid - { - TRACE("Checking input"); - checkData(f); - } - - // Define properties of this approach - const CELL_LOC allowedStaggerLoc = getAllowedStaggerLoc(); - - // Handle the staggering - const CELL_LOC inloc = f.getLocation(); // Input location - if (outloc == CELL_DEFAULT) { - outloc = inloc; - } - const STAGGER stagger = getStagger(inloc, outloc, allowedStaggerLoc); - - // Check for early exit - const int nPoint = getNpoints(); - - if (nPoint == 1) { - auto tmp = T(0., f.getMesh()); - tmp.setLocation(outloc); - return tmp; - } - - // Lookup the method - auto& derivativeStore = DerivativeStore::getInstance(); - typename DerivativeStore::standardFunc derivativeMethod; - - derivativeMethod = - derivativeStore.getStandardDerivative(method, direction, stagger, derivType); - - // Create the result field - T result(f.getMesh()); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); - - // Apply method - derivativeMethod(f, result, region); - - // Check the result is valid - { - TRACE("Checking result"); - checkData(result); - } - - return result; -} - /******************************************************************************* * Helper routines *******************************************************************************/ From dc8e805c540a94254edcd1e5e1f2e8468e33b399 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 16:55:56 +0000 Subject: [PATCH 0381/1783] Remove templating from a couple of helper functions as not required. --- include/bout/index_derivs.hxx | 12 +-- include/bout/index_derivs_interface.hxx | 10 +-- include/bout/mesh.hxx | 101 ++++++++++-------------- 3 files changed, 50 insertions(+), 73 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index 49e64367e4..c4ad588493 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -87,7 +87,7 @@ public: AUTO_TRACE(); ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond || meta.derivType == DERIV::StandardFourth) - ASSERT2(var.getMesh()->template getNguard() >= nGuards); + ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); BOUT_FOR(i, var.getRegion(region)) { result[i] = apply(populateStencil(var, i)); @@ -99,7 +99,7 @@ public: void upwindOrFlux(const T& vel, const T& var, T& result, REGION region) const { AUTO_TRACE(); ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) - ASSERT2(var.getMesh()->template getNguard() >= nGuards); + ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); if (meta.derivType == DERIV::Flux || stagger != STAGGER::None) { BOUT_FOR(i, var.getRegion(region)) { @@ -687,7 +687,7 @@ public: void standard(const T& var, T& result, REGION region) const { AUTO_TRACE(); ASSERT2(meta.derivType == DERIV::Standard) - ASSERT2(var.getMesh()->template getNguard() >= nGuards); + ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); ASSERT2(direction == DIRECTION::Z); // Only in Z for now ASSERT2(stagger == STAGGER::None); // Staggering not currently supported ASSERT2((std::is_base_oftemplate getNpoints(); + const int ncz = theMesh->getNpoints(direction); int kfilter = static_cast(theMesh->fft_derivs_filter * ncz / 2); // truncates, rounding down @@ -759,7 +759,7 @@ public: void standard(const T& var, T& result, REGION region) const { AUTO_TRACE(); ASSERT2(meta.derivType == DERIV::Standard) - ASSERT2(var.getMesh()->template getNguard() >= nGuards); + ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); ASSERT2(direction == DIRECTION::Z); // Only in Z for now ASSERT2(stagger == STAGGER::None); // Staggering not currently supported ASSERT2((std::is_base_oftemplate getNpoints(); + const int ncz = theMesh->getNpoints(direction); const int kmax = ncz / 2; BOUT_OMP(parallel) { diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index b2b6189f56..c54d7f4496 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -64,8 +64,7 @@ T indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, } // Define properties of this approach - const CELL_LOC allowedStaggerLoc = - localmesh->template getAllowedStaggerLoc(); + const CELL_LOC allowedStaggerLoc = localmesh->getAllowedStaggerLoc(direction); // Handle the staggering const CELL_LOC inloc = f.getLocation(); // Input locations @@ -76,7 +75,7 @@ T indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, const STAGGER stagger = localmesh->getStagger(vloc, inloc, outloc, allowedStaggerLoc); // Check for early exit - const int nPoint = localmesh->template getNpoints(); + const int nPoint = localmesh->getNpoints(direction); if (nPoint == 1) { auto tmp = T(0., localmesh); @@ -134,8 +133,7 @@ T indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method } // Define properties of this approach - const CELL_LOC allowedStaggerLoc = - localmesh->template getAllowedStaggerLoc(); + const CELL_LOC allowedStaggerLoc = localmesh->getAllowedStaggerLoc(direction); // Handle the staggering const CELL_LOC inloc = f.getLocation(); // Input location @@ -145,7 +143,7 @@ T indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method const STAGGER stagger = localmesh->getStagger(inloc, outloc, allowedStaggerLoc); // Check for early exit - const int nPoint = localmesh->template getNpoints(); + const int nPoint = localmesh->getNpoints(direction); if (nPoint == 1) { auto tmp = T(0., localmesh); diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 27f547006f..7f43c70839 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -450,18 +450,48 @@ class Mesh { /// Returns the non-CELL_CENTRE location /// allowed as a staggered location - template - CELL_LOC getAllowedStaggerLoc() const; + CELL_LOC getAllowedStaggerLoc(DIRECTION direction) const { + switch (direction) { + case (DIRECTION::X): + return CELL_XLOW; + case (DIRECTION::Y): + case (DIRECTION::YOrthogonal): + case (DIRECTION::YAligned): + return CELL_YLOW; + case (DIRECTION::Z): + return CELL_ZLOW; + } + }; /// Returns the number of grid points in the /// particular direction - template - int getNpoints() const; + int getNpoints(DIRECTION direction) const { + switch (direction) { + case (DIRECTION::X): + return LocalNx; + case (DIRECTION::Y): + case (DIRECTION::YOrthogonal): + case (DIRECTION::YAligned): + return LocalNy; + case (DIRECTION::Z): + return LocalNz; + } + }; /// Returns the number of guard points in the /// particular direction - template - int getNguard() const; + int getNguard(DIRECTION direction) const { + switch (direction) { + case (DIRECTION::X): + return xstart; + case (DIRECTION::Y): + case (DIRECTION::YOrthogonal): + case (DIRECTION::YAligned): + return ystart; + case (DIRECTION::Z): + return 2; + } + }; /////////////////////////////////////////////////////////// // INDEX DERIVATIVE OPERATORS @@ -484,6 +514,10 @@ class Mesh { STAGGER getStagger(const CELL_LOC vloc, const CELL_LOC inloc, const CELL_LOC outloc, const CELL_LOC allowedloc) const; + // All of these derivative routines should probably be moved out of mesh to become + // free functions. As an intermediate step the member routines could just call the + // free functions. + ////// STANDARD OPERATORS ////////////// X DERIVATIVE ///////////////// @@ -791,15 +825,6 @@ class Mesh { void derivs_init(Options* options); private: - // /// The main kernel used for all standard derivatives - // template - // T indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method, - // REGION region) const; - - // /// The main kernel used for all upwind and flux derivatives - // template - // T indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, - // const std::string& method, REGION region) const; /// Allocates default Coordinates objects std::shared_ptr createDefaultCoordinates(const CELL_LOC location); @@ -811,50 +836,4 @@ private: Array indexLookup3Dto2D; }; -/******************************************************************************* - * Helper routines - *******************************************************************************/ - -template -CELL_LOC Mesh::getAllowedStaggerLoc() const { - switch (direction) { - case (DIRECTION::X): - return CELL_XLOW; - case (DIRECTION::Y): - case (DIRECTION::YOrthogonal): - case (DIRECTION::YAligned): - return CELL_YLOW; - case (DIRECTION::Z): - return CELL_ZLOW; - } -}; - -template -int Mesh::getNpoints() const { - switch (direction) { - case (DIRECTION::X): - return LocalNx; - case (DIRECTION::Y): - case (DIRECTION::YOrthogonal): - case (DIRECTION::YAligned): - return LocalNy; - case (DIRECTION::Z): - return LocalNz; - } -}; - -template -int Mesh::getNguard() const { - switch (direction) { - case (DIRECTION::X): - return xstart; - case (DIRECTION::Y): - case (DIRECTION::YOrthogonal): - case (DIRECTION::YAligned): - return ystart; - case (DIRECTION::Z): - return 2; - } -}; - #endif // __MESH_H__ From d40fda13c32490ad2cf7b3a3929071db93f73dc3 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 30 Nov 2018 17:09:32 +0000 Subject: [PATCH 0382/1783] Remove a couple of redundant lines --- include/bout/index_derivs_interface.hxx | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index c54d7f4496..f27b709de4 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -84,10 +84,8 @@ T indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, } // Lookup the method - auto& derivativeStore = DerivativeStore::getInstance(); - typename DerivativeStore::upwindFunc derivativeMethod; - derivativeMethod = - derivativeStore.getFlowDerivative(method, direction, stagger, derivType); + auto derivativeMethod = DerivativeStore::getInstance().getFlowDerivative( + method, direction, stagger, derivType); // Create the result field T result(localmesh); @@ -152,11 +150,8 @@ T indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method } // Lookup the method - auto& derivativeStore = DerivativeStore::getInstance(); - typename DerivativeStore::standardFunc derivativeMethod; - - derivativeMethod = - derivativeStore.getStandardDerivative(method, direction, stagger, derivType); + auto derivativeMethod = DerivativeStore::getInstance().getStandardDerivative( + method, direction, stagger, derivType); // Create the result field T result(localmesh); From 64b345cf315071a27bb4da5a5190fd0cf8d6b6c2 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 3 Dec 2018 14:42:39 +0000 Subject: [PATCH 0383/1783] Move index derivatives into index_derivs_interface header out of mesh Deprecate mesh member versions that call these free functions --- include/bout/index_derivs_interface.hxx | 194 ++++++++++++++++++++++++ include/bout/mesh.hxx | 184 ++++++++++------------ 2 files changed, 270 insertions(+), 108 deletions(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index f27b709de4..31efa3019f 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -170,4 +170,198 @@ T indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method return result; } +////// STANDARD OPERATORS + +////////////// X DERIVATIVE ///////////////// +template +T indexDDX(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + return indexStandardDerivative(f, outloc, method, + region); +} + +template +T indexD2DX2(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + return indexStandardDerivative(f, outloc, + method, region); +} + +template +T indexD4DX4(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + return indexStandardDerivative(f, outloc, + method, region); +} + +////////////// Y DERIVATIVE ///////////////// + +template +T indexDDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + if (std::is_base_of::value && f.hasYupYdown() + && ((&f.yup() != &f) || (&f.ydown() != &f))) { + return indexStandardDerivative( + f, outloc, method, region); + } else { + const T f_aligned = f.getMesh()->toFieldAligned(f); + T result = indexStandardDerivative(f, outloc, + method, region); + return f.getMesh()->fromFieldAligned(result); + } +} + +template +T indexD2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + if (std::is_base_of::value && f.hasYupYdown() + && ((&f.yup() != &f) || (&f.ydown() != &f))) { + return indexStandardDerivative( + f, outloc, method, region); + } else { + const T f_aligned = f.getMesh()->toFieldAligned(f); + T result = indexStandardDerivative( + f, outloc, method, region); + return f.getMesh()->fromFieldAligned(result); + } +} + +template +T indexD4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + if (std::is_base_of::value && f.hasYupYdown() + && ((&f.yup() != &f) || (&f.ydown() != &f))) { + return indexStandardDerivative( + f, outloc, method, region); + } else { + const T f_aligned = f.getMesh()->toFieldAligned(f); + T result = indexStandardDerivative( + f, outloc, method, region); + return f.getMesh()->fromFieldAligned(result); + } +} + +////////////// Z DERIVATIVE ///////////////// +template +T indexDDZ(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + return indexStandardDerivative(f, outloc, method, + region); +} + +template +T indexD2DZ2(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + return indexStandardDerivative(f, outloc, + method, region); +} + +template +T indexD4DZ4(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + return indexStandardDerivative(f, outloc, + method, region); +} + +////// ADVECTION AND FLUX OPERATORS + +/// Advection operator in index space in [] direction +/// +/// \f[ +/// v \frac{d}{di} f +/// \f] +/// +/// @param[in] v The velocity in the Y direction +/// @param[in] f The field being advected +/// @param[in] outloc The cell location where the result is desired. The default is the +/// same as \p f +/// @param[in] method The differencing method to use +/// @param[in] region The region of the grid for which the result is calculated. + +////////////// X DERIVATIVE ///////////////// + +template +T indexVDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + return indexFlowDerivative(vel, f, outloc, method, + region); +} + +template +T indexFDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + return indexFlowDerivative(vel, f, outloc, method, + region); +} + +////////////// Y DERIVATIVE ///////////////// + +template +T indexVDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() + && ((&f.yup() != &f) || (&f.ydown() != &f))); + bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() + && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); + if (fHasParallelSlices && velHasParallelSlices) { + return indexFlowDerivative(vel, f, outloc, + method, region); + } else { + const T f_aligned = f.getMesh()->toFieldAligned(f); + const T vel_aligned = vel.getMesh()->toFieldAligned(vel); + T result = indexFlowDerivative( + vel_aligned, f_aligned, outloc, method, region); + return f.getMesh()->fromFieldAligned(result); + } +} + +template +T indexFDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() + && ((&f.yup() != &f) || (&f.ydown() != &f))); + bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() + && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); + if (fHasParallelSlices && velHasParallelSlices) { + return indexFlowDerivative(vel, f, outloc, + method, region); + } else { + const T f_aligned = f.getMesh()->toFieldAligned(f); + const T vel_aligned = vel.getMesh()->toFieldAligned(vel); + T result = indexFlowDerivative(vel_aligned, f_aligned, + outloc, method, region); + return f.getMesh()->fromFieldAligned(result); + } +} + +////////////// Z DERIVATIVE ///////////////// + +template +T indexVDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + return indexFlowDerivative(vel, f, outloc, method, + region); +} + +template +T indexFDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + AUTO_TRACE(); + return indexFlowDerivative(vel, f, outloc, method, + region); +} #endif diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 7f43c70839..81423a1960 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -45,6 +45,7 @@ class Mesh; #include "mpi.h" +#include #include #include @@ -522,93 +523,78 @@ class Mesh { ////////////// X DERIVATIVE ///////////////// template - T indexDDX(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative(f, outloc, method, - region); + DEPRECATED(T indexDDX(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexDDX(f, outloc, method, region); } template - T indexD2DX2(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative( - f, outloc, method, region); + DEPRECATED(T indexD2DX2(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexD2DX2(f, outloc, method, region); } template - T indexD4DX4(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative( - f, outloc, method, region); + DEPRECATED(T indexD4DX4(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexD4DX4(f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// template - T indexDDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - if (std::is_base_of::value && f.hasYupYdown() - && ((&f.yup() != &f) || (&f.ydown() != &f))) { - return indexStandardDerivative( - f, outloc, method, region); - } else { - const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = indexStandardDerivative( - f, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); - } + DEPRECATED(T indexDDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexDDY(f, outloc, method, region); } template - T indexD2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - if (std::is_base_of::value && f.hasYupYdown() - && ((&f.yup() != &f) || (&f.ydown() != &f))) { - return indexStandardDerivative( - f, outloc, method, region); - } else { - const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = indexStandardDerivative( - f, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); - } + DEPRECATED(T indexD2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexD2DY2(f, outloc, method, region); } template - T indexD4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - if (std::is_base_of::value && f.hasYupYdown() - && ((&f.yup() != &f) || (&f.ydown() != &f))) { - return indexStandardDerivative( - f, outloc, method, region); - } else { - const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = indexStandardDerivative( - f, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); - } + DEPRECATED(T indexD4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexD4DY4(f, outloc, method, region); } ////////////// Z DERIVATIVE ///////////////// template - T indexDDZ(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative(f, outloc, method, - region); + DEPRECATED(T indexDDZ(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexDDZ(f, outloc, method, region); } template - T indexD2DZ2(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative( - f, outloc, method, region); + DEPRECATED(T indexD2DZ2(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexD2DZ2(f, outloc, method, region); } template - T indexD4DZ4(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexStandardDerivative( - f, outloc, method, region); + DEPRECATED(T indexD4DZ4(const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexD4DZ4(f, outloc, method, region); } ////// ADVECTION AND FLUX OPERATORS @@ -629,73 +615,55 @@ class Mesh { ////////////// X DERIVATIVE ///////////////// template - T indexVDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexFlowDerivative(vel, f, outloc, method, - region); + DEPRECATED(T indexVDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexVDDX(vel, f, outloc, method, region); } template - T indexFDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexFlowDerivative(vel, f, outloc, method, - region); + DEPRECATED(T indexFDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexFDDX(vel, f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// template - T indexVDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() - && ((&f.yup() != &f) || (&f.ydown() != &f))); - bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() - && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); - if (fHasParallelSlices && velHasParallelSlices) { - return indexFlowDerivative( - vel, f, outloc, method, region); - } else { - const T f_aligned = f.getMesh()->toFieldAligned(f); - const T vel_aligned = vel.getMesh()->toFieldAligned(vel); - T result = indexFlowDerivative( - vel_aligned, f_aligned, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); - } + DEPRECATED(T indexVDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexVDDY(vel, f, outloc, method, region); } template - T indexFDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() - && ((&f.yup() != &f) || (&f.ydown() != &f))); - bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() - && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); - if (fHasParallelSlices && velHasParallelSlices) { - return indexFlowDerivative(vel, f, outloc, - method, region); - } else { - const T f_aligned = f.getMesh()->toFieldAligned(f); - const T vel_aligned = vel.getMesh()->toFieldAligned(vel); - T result = indexFlowDerivative( - vel_aligned, f_aligned, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); - } + DEPRECATED(T indexFDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexFDDY(vel, f, outloc, method, region); } ////////////// Z DERIVATIVE ///////////////// template - T indexVDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexFlowDerivative(vel, f, outloc, method, - region); + DEPRECATED(T indexVDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexVDDZ(vel, f, outloc, method, region); } template - T indexFDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const { - return indexFlowDerivative(vel, f, outloc, method, - region); + DEPRECATED(T indexFDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) const) { + AUTO_TRACE(); + return ::indexFDDZ(vel, f, outloc, method, region); } /////////////////////////////////////////////////////////// From 97a9802a6f823e83251dbe3863deb9706b573cd9 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 3 Dec 2018 14:46:03 +0000 Subject: [PATCH 0384/1783] Put index_deriv routines in bout::derivatives::index namespace --- include/bout/index_derivs.hxx | 9 ++++---- include/bout/index_derivs_interface.hxx | 8 +++++++ include/bout/mesh.hxx | 30 ++++++++++++------------- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index c4ad588493..9cd4014229 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -836,11 +836,12 @@ public: AUTO_TRACE(); // Split into an upwind and a central differencing part // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) - result = indexFlowDerivative( + result = bout::derivatives::index::indexFlowDerivative( vel, var, result.getLocation(), "DEFAULT", region); - result += indexStandardDerivative( - vel, result.getLocation(), "DEFAULT", region) - * interp_to(var, result.getLocation()); + result += + bout::derivatives::index::indexStandardDerivative( + vel, result.getLocation(), "DEFAULT", region) + * interp_to(var, result.getLocation()); return; } metaData meta{"SPLIT", 2, DERIV::Flux}; diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 31efa3019f..0be85ce5b0 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -35,6 +35,10 @@ class Field3D; class Field2D; +namespace bout { +namespace derivatives { +namespace index { + /// The main kernel used for all upwind and flux derivatives template T indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, @@ -364,4 +368,8 @@ T indexFDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, return indexFlowDerivative(vel, f, outloc, method, region); } + +} // Namespace index +} // Namespace derivatives +} // Namespace bout #endif diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 81423a1960..fa7a13746c 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -527,7 +527,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexDDX(f, outloc, method, region); + return bout::derivatives::index::indexDDX(f, outloc, method, region); } template @@ -535,7 +535,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexD2DX2(f, outloc, method, region); + return bout::derivatives::index::indexD2DX2(f, outloc, method, region); } template @@ -543,7 +543,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexD4DX4(f, outloc, method, region); + return bout::derivatives::index::indexD4DX4(f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// @@ -553,7 +553,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexDDY(f, outloc, method, region); + return bout::derivatives::index::indexDDY(f, outloc, method, region); } template @@ -561,7 +561,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexD2DY2(f, outloc, method, region); + return bout::derivatives::index::indexD2DY2(f, outloc, method, region); } template @@ -569,7 +569,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexD4DY4(f, outloc, method, region); + return bout::derivatives::index::indexD4DY4(f, outloc, method, region); } ////////////// Z DERIVATIVE ///////////////// @@ -578,7 +578,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexDDZ(f, outloc, method, region); + return bout::derivatives::index::indexDDZ(f, outloc, method, region); } template @@ -586,7 +586,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexD2DZ2(f, outloc, method, region); + return bout::derivatives::index::indexD2DZ2(f, outloc, method, region); } template @@ -594,7 +594,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexD4DZ4(f, outloc, method, region); + return bout::derivatives::index::indexD4DZ4(f, outloc, method, region); } ////// ADVECTION AND FLUX OPERATORS @@ -619,7 +619,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexVDDX(vel, f, outloc, method, region); + return bout::derivatives::index::indexVDDX(vel, f, outloc, method, region); } template @@ -627,7 +627,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexFDDX(vel, f, outloc, method, region); + return bout::derivatives::index::indexFDDX(vel, f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// @@ -637,7 +637,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexVDDY(vel, f, outloc, method, region); + return bout::derivatives::index::indexVDDY(vel, f, outloc, method, region); } template @@ -645,7 +645,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexFDDY(vel, f, outloc, method, region); + return bout::derivatives::index::indexFDDY(vel, f, outloc, method, region); } ////////////// Z DERIVATIVE ///////////////// @@ -655,7 +655,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexVDDZ(vel, f, outloc, method, region); + return bout::derivatives::index::indexVDDZ(vel, f, outloc, method, region); } template @@ -663,7 +663,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return ::indexFDDZ(vel, f, outloc, method, region); + return bout::derivatives::index::indexFDDZ(vel, f, outloc, method, region); } /////////////////////////////////////////////////////////// From 161aea463139f36d41e075c1f7ff11013aa2eda3 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 3 Dec 2018 17:46:44 +0000 Subject: [PATCH 0385/1783] Remove index from start of index derivative names now namespaced --- include/bout/index_derivs.hxx | 9 +- include/bout/index_derivs_interface.hxx | 146 ++++++++++++------------ include/bout/mesh.hxx | 30 ++--- 3 files changed, 89 insertions(+), 96 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index 9cd4014229..eb8e0a8575 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -836,12 +836,11 @@ public: AUTO_TRACE(); // Split into an upwind and a central differencing part // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) - result = bout::derivatives::index::indexFlowDerivative( + result = bout::derivatives::index::flowDerivative( vel, var, result.getLocation(), "DEFAULT", region); - result += - bout::derivatives::index::indexStandardDerivative( - vel, result.getLocation(), "DEFAULT", region) - * interp_to(var, result.getLocation()); + result += bout::derivatives::index::standardDerivative( + vel, result.getLocation(), "DEFAULT", region) + * interp_to(var, result.getLocation()); return; } metaData meta{"SPLIT", 2, DERIV::Flux}; diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 0be85ce5b0..78096e5ce1 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -41,16 +41,16 @@ namespace index { /// The main kernel used for all upwind and flux derivatives template -T indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, - const std::string& method, REGION region) { +T flowDerivative(const T& vel, const T& f, CELL_LOC outloc, const std::string& method, + REGION region) { AUTO_TRACE(); // Checks static_assert(std::is_base_of::value || std::is_base_of::value, - "indexFlowDerivative only works on Field2D or Field3D input"); + "flowDerivative only works on Field2D or Field3D input"); static_assert(derivType == DERIV::Upwind || derivType == DERIV::Flux, - "indexFlowDerivative only works for derivType in {Upwind, Flux}."); + "flowDerivative only works for derivType in {Upwind, Flux}."); auto* localmesh = f.getMesh(); @@ -110,17 +110,17 @@ T indexFlowDerivative(const T& vel, const T& f, CELL_LOC outloc, /// The main kernel used for all standard derivatives template -T indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method, - REGION region) { +T standardDerivative(const T& f, CELL_LOC outloc, const std::string& method, + REGION region) { AUTO_TRACE(); // Checks static_assert(std::is_base_of::value || std::is_base_of::value, - "indexStandardDerivative only works on Field2D or Field3D input"); + "standardDerivative only works on Field2D or Field3D input"); static_assert(derivType == DERIV::Standard || derivType == DERIV::StandardSecond || derivType == DERIV::StandardFourth, - "indexStandardDerivative only works for derivType in {Standard, " + "standardDerivative only works for derivType in {Standard, " "StandardSecond, StandardFourth}"); auto* localmesh = f.getMesh(); @@ -178,102 +178,100 @@ T indexStandardDerivative(const T& f, CELL_LOC outloc, const std::string& method ////////////// X DERIVATIVE ///////////////// template -T indexDDX(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T DDX(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - return indexStandardDerivative(f, outloc, method, - region); + return standardDerivative(f, outloc, method, region); } template -T indexD2DX2(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T D2DX2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - return indexStandardDerivative(f, outloc, - method, region); + return standardDerivative(f, outloc, method, + region); } template -T indexD4DX4(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T D4DX4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - return indexStandardDerivative(f, outloc, - method, region); + return standardDerivative(f, outloc, method, + region); } ////////////// Y DERIVATIVE ///////////////// template -T indexDDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T DDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) { AUTO_TRACE(); if (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))) { - return indexStandardDerivative( - f, outloc, method, region); + return standardDerivative(f, outloc, + method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = indexStandardDerivative(f, outloc, - method, region); + T result = + standardDerivative(f, outloc, method, region); return f.getMesh()->fromFieldAligned(result); } } template -T indexD2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T D2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) { AUTO_TRACE(); if (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))) { - return indexStandardDerivative( + return standardDerivative( f, outloc, method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = indexStandardDerivative( - f, outloc, method, region); + T result = standardDerivative(f, outloc, + method, region); return f.getMesh()->fromFieldAligned(result); } } template -T indexD4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T D4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) { AUTO_TRACE(); if (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))) { - return indexStandardDerivative( + return standardDerivative( f, outloc, method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = indexStandardDerivative( - f, outloc, method, region); + T result = standardDerivative(f, outloc, + method, region); return f.getMesh()->fromFieldAligned(result); } } ////////////// Z DERIVATIVE ///////////////// template -T indexDDZ(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T DDZ(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - return indexStandardDerivative(f, outloc, method, - region); + return standardDerivative(f, outloc, method, region); } template -T indexD2DZ2(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T D2DZ2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - return indexStandardDerivative(f, outloc, - method, region); + return standardDerivative(f, outloc, method, + region); } template -T indexD4DZ4(const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T D4DZ4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", + REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - return indexStandardDerivative(f, outloc, - method, region); + return standardDerivative(f, outloc, method, + region); } ////// ADVECTION AND FLUX OPERATORS @@ -294,59 +292,57 @@ T indexD4DZ4(const T& f, CELL_LOC outloc = CELL_DEFAULT, ////////////// X DERIVATIVE ///////////////// template -T indexVDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T VDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - return indexFlowDerivative(vel, f, outloc, method, - region); + return flowDerivative(vel, f, outloc, method, region); } template -T indexFDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T FDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - return indexFlowDerivative(vel, f, outloc, method, - region); + return flowDerivative(vel, f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// template -T indexVDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); if (fHasParallelSlices && velHasParallelSlices) { - return indexFlowDerivative(vel, f, outloc, - method, region); + return flowDerivative(vel, f, outloc, + method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); const T vel_aligned = vel.getMesh()->toFieldAligned(vel); - T result = indexFlowDerivative( - vel_aligned, f_aligned, outloc, method, region); + T result = flowDerivative(vel_aligned, f_aligned, + outloc, method, region); return f.getMesh()->fromFieldAligned(result); } } template -T indexFDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T FDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); if (fHasParallelSlices && velHasParallelSlices) { - return indexFlowDerivative(vel, f, outloc, - method, region); + return flowDerivative(vel, f, outloc, method, + region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); const T vel_aligned = vel.getMesh()->toFieldAligned(vel); - T result = indexFlowDerivative(vel_aligned, f_aligned, - outloc, method, region); + T result = flowDerivative(vel_aligned, f_aligned, + outloc, method, region); return f.getMesh()->fromFieldAligned(result); } } @@ -354,19 +350,17 @@ T indexFDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, ////////////// Z DERIVATIVE ///////////////// template -T indexVDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T VDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - return indexFlowDerivative(vel, f, outloc, method, - region); + return flowDerivative(vel, f, outloc, method, region); } template -T indexFDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { +T FDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - return indexFlowDerivative(vel, f, outloc, method, - region); + return flowDerivative(vel, f, outloc, method, region); } } // Namespace index diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index fa7a13746c..231f02df49 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -527,7 +527,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexDDX(f, outloc, method, region); + return bout::derivatives::index::DDX(f, outloc, method, region); } template @@ -535,7 +535,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexD2DX2(f, outloc, method, region); + return bout::derivatives::index::D2DX2(f, outloc, method, region); } template @@ -543,7 +543,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexD4DX4(f, outloc, method, region); + return bout::derivatives::index::D4DX4(f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// @@ -553,7 +553,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexDDY(f, outloc, method, region); + return bout::derivatives::index::DDY(f, outloc, method, region); } template @@ -561,7 +561,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexD2DY2(f, outloc, method, region); + return bout::derivatives::index::D2DY2(f, outloc, method, region); } template @@ -569,7 +569,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexD4DY4(f, outloc, method, region); + return bout::derivatives::index::D4DY4(f, outloc, method, region); } ////////////// Z DERIVATIVE ///////////////// @@ -578,7 +578,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexDDZ(f, outloc, method, region); + return bout::derivatives::index::DDZ(f, outloc, method, region); } template @@ -586,7 +586,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexD2DZ2(f, outloc, method, region); + return bout::derivatives::index::D2DZ2(f, outloc, method, region); } template @@ -594,7 +594,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexD4DZ4(f, outloc, method, region); + return bout::derivatives::index::D4DZ4(f, outloc, method, region); } ////// ADVECTION AND FLUX OPERATORS @@ -619,7 +619,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexVDDX(vel, f, outloc, method, region); + return bout::derivatives::index::VDDX(vel, f, outloc, method, region); } template @@ -627,7 +627,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexFDDX(vel, f, outloc, method, region); + return bout::derivatives::index::FDDX(vel, f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// @@ -637,7 +637,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexVDDY(vel, f, outloc, method, region); + return bout::derivatives::index::VDDY(vel, f, outloc, method, region); } template @@ -645,7 +645,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexFDDY(vel, f, outloc, method, region); + return bout::derivatives::index::FDDY(vel, f, outloc, method, region); } ////////////// Z DERIVATIVE ///////////////// @@ -655,7 +655,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexVDDZ(vel, f, outloc, method, region); + return bout::derivatives::index::VDDZ(vel, f, outloc, method, region); } template @@ -663,7 +663,7 @@ class Mesh { const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) const) { AUTO_TRACE(); - return bout::derivatives::index::indexFDDZ(vel, f, outloc, method, region); + return bout::derivatives::index::FDDZ(vel, f, outloc, method, region); } /////////////////////////////////////////////////////////// From eba3636d42e0f14862fe26d38c99475dc52b04fc Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 3 Dec 2018 21:59:10 +0000 Subject: [PATCH 0386/1783] Use free index derivative routines rather than deprecated ones --- include/bout/index_derivs_interface.hxx | 1 + src/mesh/coordinates.cxx | 8 +- src/mesh/interpolation/hermite_spline.cxx | 9 +- .../monotonic_hermite_spline.cxx | 10 +- src/sys/derivs.cxx | 102 ++++++++++-------- 5 files changed, 71 insertions(+), 59 deletions(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 78096e5ce1..742b2b0110 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -29,6 +29,7 @@ #ifndef __INDEX_DERIVS_INTERFACE_HXX__ #define __INDEX_DERIVS_INTERFACE_HXX__ +#include #include #include diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index f247be5754..4d1891ebcf 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -447,7 +447,7 @@ int Coordinates::geometry() { if (localmesh->get(d2x, "d2x")) { output_warn.write( "\tWARNING: differencing quantity 'd2x' not found. Calculating from dx\n"); - d1_dx = localmesh->indexDDX(1. / dx); // d/di(1/dx) + d1_dx = bout::derivatives::index::DDX(1. / dx); // d/di(1/dx) } else { d1_dx = -d2x / (dx * dx); } @@ -455,7 +455,7 @@ int Coordinates::geometry() { if (localmesh->get(d2y, "d2y")) { output_warn.write( "\tWARNING: differencing quantity 'd2y' not found. Calculating from dy\n"); - d1_dy = localmesh->indexDDY(1. / dy); // d/di(1/dy) + d1_dy = bout::derivatives::index::DDY(1. / dy); // d/di(1/dy) } else { d1_dy = -d2y / (dy * dy); } @@ -625,12 +625,12 @@ int Coordinates::jacobian() { const Field2D Coordinates::DDX(const Field2D &f, CELL_LOC loc, const std::string &method, REGION region) { ASSERT1(location == loc || loc == CELL_DEFAULT); - return localmesh->indexDDX(f, loc, method, region) / dx; + return bout::derivatives::index::DDX(f, loc, method, region) / dx; } const Field2D Coordinates::DDY(const Field2D &f, CELL_LOC loc, const std::string &method, REGION region) { ASSERT1(location == loc || loc == CELL_DEFAULT); - return localmesh->indexDDY(f, loc, method, region) / dy; + return bout::derivatives::index::DDY(f, loc, method, region) / dy; } const Field2D Coordinates::DDZ(MAYBE_UNUSED(const Field2D &f), CELL_LOC loc, diff --git a/src/mesh/interpolation/hermite_spline.cxx b/src/mesh/interpolation/hermite_spline.cxx index 3900ca0136..b0c425470a 100644 --- a/src/mesh/interpolation/hermite_spline.cxx +++ b/src/mesh/interpolation/hermite_spline.cxx @@ -20,9 +20,10 @@ * **************************************************************************/ -#include "bout/mesh.hxx" #include "globals.hxx" #include "interpolation.hxx" +#include "bout/index_derivs_interface.hxx" +#include "bout/mesh.hxx" #include @@ -113,11 +114,11 @@ Field3D HermiteSpline::interpolate(const Field3D &f) const { // Derivatives are used for tension and need to be on dimensionless // coordinates - Field3D fx = localmesh->indexDDX(f, CELL_DEFAULT, "DEFAULT"); + Field3D fx = bout::derivatives::index::DDX(f, CELL_DEFAULT, "DEFAULT"); localmesh->communicateXZ(fx); - Field3D fz = localmesh->indexDDZ(f, CELL_DEFAULT, "DEFAULT", RGN_ALL); + Field3D fz = bout::derivatives::index::DDZ(f, CELL_DEFAULT, "DEFAULT", RGN_ALL); localmesh->communicateXZ(fz); - Field3D fxz = localmesh->indexDDX(fz, CELL_DEFAULT, "DEFAULT"); + Field3D fxz = bout::derivatives::index::DDX(fz, CELL_DEFAULT, "DEFAULT"); localmesh->communicateXZ(fxz); for (int x = localmesh->xstart; x <= localmesh->xend; x++) { diff --git a/src/mesh/interpolation/monotonic_hermite_spline.cxx b/src/mesh/interpolation/monotonic_hermite_spline.cxx index e76f2f2a69..d0cbf380e4 100644 --- a/src/mesh/interpolation/monotonic_hermite_spline.cxx +++ b/src/mesh/interpolation/monotonic_hermite_spline.cxx @@ -20,11 +20,11 @@ * **************************************************************************/ - -#include "bout/mesh.hxx" #include "globals.hxx" #include "interpolation.hxx" #include "output.hxx" +#include "bout/index_derivs_interface.hxx" +#include "bout/mesh.hxx" #include @@ -35,11 +35,11 @@ Field3D MonotonicHermiteSpline::interpolate(const Field3D &f) const { // Derivatives are used for tension and need to be on dimensionless // coordinates - Field3D fx = localmesh->indexDDX(f, CELL_DEFAULT, "DEFAULT"); + Field3D fx = bout::derivatives::index::DDX(f, CELL_DEFAULT, "DEFAULT"); localmesh->communicateXZ(fx); - Field3D fz = localmesh->indexDDZ(f, CELL_DEFAULT, "DEFAULT", RGN_ALL); + Field3D fz = bout::derivatives::index::DDZ(f, CELL_DEFAULT, "DEFAULT", RGN_ALL); localmesh->communicateXZ(fz); - Field3D fxz = localmesh->indexDDX(fz, CELL_DEFAULT, "DEFAULT"); + Field3D fxz = bout::derivatives::index::DDX(fz, CELL_DEFAULT, "DEFAULT"); localmesh->communicateXZ(fxz); for (int x = localmesh->xstart; x <= localmesh->xend; x++) { diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 55bc95ad22..c7ae870da7 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -58,7 +58,7 @@ ////////////// X DERIVATIVE ///////////////// const Field3D DDX(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - Field3D result = f.getMesh()->indexDDX(f,outloc, method, region); + Field3D result = bout::derivatives::index::DDX(f, outloc, method, region); Coordinates *coords = f.getCoordinates(outloc); result /= coords->dx; @@ -80,7 +80,8 @@ const Field2D DDX(const Field2D &f, CELL_LOC outloc, const std::string &method, ////////////// Y DERIVATIVE ///////////////// const Field3D DDY(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexDDY(f, outloc, method, region) / f.getCoordinates(outloc)->dy; + return bout::derivatives::index::DDY(f, outloc, method, region) + / f.getCoordinates(outloc)->dy; } const Field2D DDY(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { @@ -90,7 +91,8 @@ const Field2D DDY(const Field2D &f, CELL_LOC outloc, const std::string &method, ////////////// Z DERIVATIVE ///////////////// const Field3D DDZ(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexDDZ(f, outloc, method, region) / f.getCoordinates(outloc)->dz; + return bout::derivatives::index::DDZ(f, outloc, method, region) + / f.getCoordinates(outloc)->dz; } const Field2D DDZ(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), @@ -153,11 +155,13 @@ const Vector2D DDZ(const Vector2D &v, CELL_LOC UNUSED(outloc), const std::string const Field3D D2DX2(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { Coordinates *coords = f.getCoordinates(outloc); - Field3D result = f.getMesh()->indexD2DX2(f, outloc, method, region) / SQ(coords->dx); - + Field3D result = + bout::derivatives::index::D2DX2(f, outloc, method, region) / SQ(coords->dx); + if(coords->non_uniform) { // Correction for non-uniform f.getMesh() - result += coords->d1_dx * f.getMesh()->indexDDX(f, outloc, "DEFAULT", region)/coords->dx; + result += coords->d1_dx * bout::derivatives::index::DDX(f, outloc, "DEFAULT", region) + / coords->dx; } ASSERT2(((outloc == CELL_DEFAULT) && (result.getLocation() == f.getLocation())) || @@ -169,11 +173,13 @@ const Field3D D2DX2(const Field3D &f, CELL_LOC outloc, const std::string &method const Field2D D2DX2(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { Coordinates *coords = f.getCoordinates(outloc); - Field2D result = f.getMesh()->indexD2DX2(f, outloc, method, region) / SQ(coords->dx); + Field2D result = + bout::derivatives::index::D2DX2(f, outloc, method, region) / SQ(coords->dx); if(coords->non_uniform) { // Correction for non-uniform f.getMesh() - result += coords->d1_dx * f.getMesh()->indexDDX(f, outloc, "DEFAULT", region) / coords->dx; + result += coords->d1_dx * bout::derivatives::index::DDX(f, outloc, "DEFAULT", region) + / coords->dx; } return result; @@ -184,11 +190,13 @@ const Field2D D2DX2(const Field2D &f, CELL_LOC outloc, const std::string &method const Field3D D2DY2(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { Coordinates *coords = f.getCoordinates(outloc); - Field3D result = f.getMesh()->indexD2DY2(f, outloc, method, region) / SQ(coords->dy); + Field3D result = + bout::derivatives::index::D2DY2(f, outloc, method, region) / SQ(coords->dy); if(coords->non_uniform) { // Correction for non-uniform f.getMesh() - result += coords->d1_dy * f.getMesh()->indexDDY(f, outloc, "DEFAULT", region) / coords->dy; + result += coords->d1_dy * bout::derivatives::index::DDY(f, outloc, "DEFAULT", region) + / coords->dy; } ASSERT2(((outloc == CELL_DEFAULT) && (result.getLocation() == f.getLocation())) || @@ -200,10 +208,12 @@ const Field3D D2DY2(const Field3D &f, CELL_LOC outloc, const std::string &method const Field2D D2DY2(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { Coordinates *coords = f.getCoordinates(outloc); - Field2D result = f.getMesh()->indexD2DY2(f, outloc, method, region) / SQ(coords->dy); + Field2D result = + bout::derivatives::index::D2DY2(f, outloc, method, region) / SQ(coords->dy); if(coords->non_uniform) { // Correction for non-uniform f.getMesh() - result += coords->d1_dy * f.getMesh()->indexDDY(f, outloc, "DEFAULT", region) / coords->dy; + result += coords->d1_dy * bout::derivatives::index::DDY(f, outloc, "DEFAULT", region) + / coords->dy; } return result; @@ -212,8 +222,8 @@ const Field2D D2DY2(const Field2D &f, CELL_LOC outloc, const std::string &method ////////////// Z DERIVATIVE ///////////////// const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexD2DZ2(f, outloc, method, region) / - SQ(f.getCoordinates(outloc)->dz); + return bout::derivatives::index::D2DZ2(f, outloc, method, region) + / SQ(f.getCoordinates(outloc)->dz); } const Field2D D2DZ2(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), @@ -228,33 +238,33 @@ const Field2D D2DZ2(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string *******************************************************************************/ const Field3D D4DX4(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexD4DX4(f, outloc, method, region) / - SQ(SQ(f.getCoordinates(outloc)->dx)); + return bout::derivatives::index::D4DX4(f, outloc, method, region) + / SQ(SQ(f.getCoordinates(outloc)->dx)); } const Field2D D4DX4(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexD4DX4(f, outloc, method, region) / - SQ(SQ(f.getCoordinates(outloc)->dx)); + return bout::derivatives::index::D4DX4(f, outloc, method, region) + / SQ(SQ(f.getCoordinates(outloc)->dx)); } const Field3D D4DY4(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexD4DY4(f, outloc, method, region) / - SQ(SQ(f.getCoordinates(outloc)->dy)); + return bout::derivatives::index::D4DY4(f, outloc, method, region) + / SQ(SQ(f.getCoordinates(outloc)->dy)); } const Field2D D4DY4(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexD4DY4(f, outloc, method, region) / - SQ(SQ(f.getCoordinates(outloc)->dy)); + return bout::derivatives::index::D4DY4(f, outloc, method, region) + / SQ(SQ(f.getCoordinates(outloc)->dy)); } const Field3D D4DZ4(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexD4DZ4(f, outloc, method, region) / - SQ(SQ(f.getCoordinates(outloc)->dz)); + return bout::derivatives::index::D4DZ4(f, outloc, method, region) + / SQ(SQ(f.getCoordinates(outloc)->dz)); } const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexD4DZ4(f, outloc, method, region) / - SQ(SQ(f.getCoordinates(outloc)->dz)); + return bout::derivatives::index::D4DZ4(f, outloc, method, region) + / SQ(SQ(f.getCoordinates(outloc)->dz)); } /******************************************************************************* @@ -362,28 +372,28 @@ const Field3D D2DYDZ(const Field3D &f, CELL_LOC outloc, const std::string &metho /// Special case where both arguments are 2D. Output location ignored for now const Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexVDDX(v, f, outloc, method, region) / - f.getCoordinates(outloc)->dx; + return bout::derivatives::index::VDDX(v, f, outloc, method, region) + / f.getCoordinates(outloc)->dx; } /// General version for 2 or 3-D objects const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexVDDX(v, f, outloc, method, region) / - f.getCoordinates(outloc)->dx; + return bout::derivatives::index::VDDX(v, f, outloc, method, region) + / f.getCoordinates(outloc)->dx; } ////////////// Y DERIVATIVE ///////////////// // special case where both are 2D const Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexVDDY(v, f, outloc, method, region) / - f.getCoordinates(outloc)->dy; + return bout::derivatives::index::VDDY(v, f, outloc, method, region) + / f.getCoordinates(outloc)->dy; } // general case const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexVDDY(v, f, outloc, method, region) / - f.getCoordinates(outloc)->dy; + return bout::derivatives::index::VDDY(v, f, outloc, method, region) + / f.getCoordinates(outloc)->dy; } ////////////// Z DERIVATIVE ///////////////// @@ -408,33 +418,33 @@ const Field2D VDDZ(const Field3D &v, const Field2D &UNUSED(f), CELL_LOC UNUSED(o // general case const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexVDDZ(v, f, outloc, method, region) / - f.getCoordinates(outloc)->dz; + return bout::derivatives::index::VDDZ(v, f, outloc, method, region) + / f.getCoordinates(outloc)->dz; } /******************************************************************************* * Flux conserving schemes *******************************************************************************/ const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexFDDX(v, f, outloc, method, region) / - f.getCoordinates(outloc)->dx; + return bout::derivatives::index::FDDX(v, f, outloc, method, region) + / f.getCoordinates(outloc)->dx; } const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexFDDX(v, f, outloc, method, region) / - f.getCoordinates(outloc)->dx; + return bout::derivatives::index::FDDX(v, f, outloc, method, region) + / f.getCoordinates(outloc)->dx; } ///////////////////////////////////////////////////////////////////////// const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexFDDY(v, f, outloc, method, region) / - f.getCoordinates(outloc)->dy; + return bout::derivatives::index::FDDY(v, f, outloc, method, region) + / f.getCoordinates(outloc)->dy; } const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexFDDY(v, f, outloc, method, region) / - f.getCoordinates(outloc)->dy; + return bout::derivatives::index::FDDY(v, f, outloc, method, region) + / f.getCoordinates(outloc)->dy; } ///////////////////////////////////////////////////////////////////////// @@ -448,6 +458,6 @@ const Field2D FDDZ(const Field2D &v, const Field2D &UNUSED(f), CELL_LOC UNUSED(o } const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - return f.getMesh()->indexFDDZ(v, f, outloc, method, region) / - f.getCoordinates(outloc)->dz; + return bout::derivatives::index::FDDZ(v, f, outloc, method, region) + / f.getCoordinates(outloc)->dz; } From 063123e7d377122ecb5148fcb3acbeb7d2d868f5 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 5 Dec 2018 10:35:29 +0000 Subject: [PATCH 0387/1783] Ensure we install cython for Travis before netcdf4 --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4b5369cee8..479c4a94c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ matrix: - env: &default_env - CONFIGURE_OPTIONS='--enable-checks=no --enable-optimize=3 --disable-signal --disable-track --disable-backtrace' - SCRIPT_FLAGS='-uim' - - PIP_PACKAGES='netcdf4 sympy' + - PIP_PACKAGES='cython netcdf4 sympy' - addons: apt: sources: @@ -53,7 +53,6 @@ matrix: - *default_env - CONFIGURE_OPTIONS='--enable-shared' - SCRIPT_FLAGS="-uim -t python -t shared" - - PIP_PACKAGES='netcdf4 cython sympy' - env: - *default_env - CONFIGURE_OPTIONS='--enable-openmp' From e737341e1309439fc48fa013cb3106206d1a739a Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 6 Dec 2018 14:22:44 +0000 Subject: [PATCH 0388/1783] Workaround for gcc ICE to do with binding class bound member with transient instance of class Previous code worked ok for v7.3.1 but failed for some versions of v7.3.0 (and passed for others!) --- include/bout/index_derivs.hxx | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index c4ad588493..384e7bc71c 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -496,16 +496,18 @@ struct registerMethod { // used to pass this around using FieldType = typename FieldTypeContainer::type; + Method method{}; + // Note whilst this should be known at compile time using this directly in the // template parameters below causes problems for old versions of gcc/libstdc++ // (tested with 4.8.3) so we currently use a hacky workaround. Once we drop // support for these versions the branching in the case statement below can be // removed and we can use nGuard directly in the template statement. - const int nGuards = Method{}.meta.nGuards; + const int nGuards = method.meta.nGuards; auto& derivativeRegister = DerivativeStore::getInstance(); - switch (Method{}.meta.derivType) { + switch (method.meta.derivType) { case (DERIV::Standard): case (DERIV::StandardSecond): case (DERIV::StandardFourth): { @@ -515,16 +517,16 @@ struct registerMethod { &Method::template standard, // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region - Method{}, _1, _2, _3); - derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, Method{}); + method, _1, _2, _3); + derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, method); } else { const auto theFunc = std::bind( // Method to store in function &Method::template standard, // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region - Method{}, _1, _2, _3); - derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, Method{}); + method, _1, _2, _3); + derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, method); } break; } @@ -537,8 +539,8 @@ struct registerMethod { FieldType>, // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region - Method{}, _1, _2, _3, _4); - derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, Method{}); + method, _1, _2, _3, _4); + derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, method); } else { const auto theFunc = std::bind( // Method to store in function @@ -546,8 +548,8 @@ struct registerMethod { FieldType>, // Arguments -- first is hidden this of type-bound, others are placeholders // for input field, output field, region - Method{}, _1, _2, _3, _4); - derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, Method{}); + method, _1, _2, _3, _4); + derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, method); } break; } From 620f3709dc26fe7d95562ff7df862cb99ab12251 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 6 Dec 2018 14:35:58 +0000 Subject: [PATCH 0389/1783] Provide a default case to some switch statements --- include/bout/mesh.hxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 7f43c70839..68af621358 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -451,6 +451,7 @@ class Mesh { /// Returns the non-CELL_CENTRE location /// allowed as a staggered location CELL_LOC getAllowedStaggerLoc(DIRECTION direction) const { + AUTO_TRACE(); switch (direction) { case (DIRECTION::X): return CELL_XLOW; @@ -460,12 +461,15 @@ class Mesh { return CELL_YLOW; case (DIRECTION::Z): return CELL_ZLOW; + case default: + throw BoutException("Unhandled direction encountered in getAllowedStaggerLoc"); } }; /// Returns the number of grid points in the /// particular direction int getNpoints(DIRECTION direction) const { + AUTO_TRACE(); switch (direction) { case (DIRECTION::X): return LocalNx; @@ -475,12 +479,15 @@ class Mesh { return LocalNy; case (DIRECTION::Z): return LocalNz; + case default: + throw BoutException("Unhandled direction encountered in getNpoints"); } }; /// Returns the number of guard points in the /// particular direction int getNguard(DIRECTION direction) const { + AUTO_TRACE(); switch (direction) { case (DIRECTION::X): return xstart; @@ -490,6 +497,8 @@ class Mesh { return ystart; case (DIRECTION::Z): return 2; + case default: + throw BoutException("Unhandled direction encountered in getNguard"); } }; From 37fdbee89534c95f241d35f74b73d223b603614b Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 6 Dec 2018 15:26:49 +0000 Subject: [PATCH 0390/1783] Use correct syntax for default case --- include/bout/mesh.hxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 68af621358..b745d7e81e 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -461,7 +461,7 @@ class Mesh { return CELL_YLOW; case (DIRECTION::Z): return CELL_ZLOW; - case default: + default: throw BoutException("Unhandled direction encountered in getAllowedStaggerLoc"); } }; @@ -479,7 +479,7 @@ class Mesh { return LocalNy; case (DIRECTION::Z): return LocalNz; - case default: + default: throw BoutException("Unhandled direction encountered in getNpoints"); } }; @@ -497,7 +497,7 @@ class Mesh { return ystart; case (DIRECTION::Z): return 2; - case default: + default: throw BoutException("Unhandled direction encountered in getNguard"); } }; From e978407d3bc12868af27c3b1439b0549ca31870a Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 6 Dec 2018 19:05:26 +0000 Subject: [PATCH 0391/1783] First steps to making FFTW an optional dependency --- configure | 31 ++++++++++--------------------- configure.ac | 4 ++++ src/invert/fft_fftw.cxx | 30 +++++++++++++++++++++++++++++- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/configure b/configure index 80ae74f6ac..fb3eb055f1 100755 --- a/configure +++ b/configure @@ -6457,6 +6457,10 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +#If we've reached this point then we're happy that we have FFTW so +#add our define to CXXFLAGS +CXXFLAGS="$CXXFLAGS -DBOUT_HAS_FFTW" + ############################################################# # netCDF support ############################################################# @@ -13348,21 +13352,16 @@ else /* end confdefs.h. */ #include -#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +$gt_revision_test_code extern int _nl_msg_cat_cntr; extern int *_nl_domain_bindings; -#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_domain_bindings) -#else -#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 -#endif -$gt_revision_test_code int main () { bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings ; return 0; @@ -14115,25 +14114,20 @@ else /* end confdefs.h. */ #include -#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +$gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); -#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) -#else -#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 -#endif -$gt_revision_test_code int main () { bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") ; return 0; @@ -14152,25 +14146,20 @@ rm -f core conftest.err conftest.$ac_objext \ /* end confdefs.h. */ #include -#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +$gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); -#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) -#else -#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 -#endif -$gt_revision_test_code int main () { bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") ; return 0; diff --git a/configure.ac b/configure.ac index 75222ab618..703daa5e63 100644 --- a/configure.ac +++ b/configure.ac @@ -403,6 +403,10 @@ AS_IF([test "x$fftw_path" != "xno"], [ BOUT_ADDPATH_CHECK_HEADER(fftw3.h, ,AC_MSG_ERROR([FFTW3 is needed by BOUT++]), $with_fftw) BOUT_ADDPATH_CHECK_LIB(fftw3, fftw_plan_dft_r2c_1d, ,AC_MSG_ERROR([FFTW3 is needed by BOUT++]), $with_fftw) +#If we've reached this point then we're happy that we have FFTW so +#add our define to CXXFLAGS +CXXFLAGS="$CXXFLAGS -DBOUT_HAS_FFTW" + ############################################################# # netCDF support ############################################################# diff --git a/src/invert/fft_fftw.cxx b/src/invert/fft_fftw.cxx index 22115a106e..3b493d0965 100644 --- a/src/invert/fft_fftw.cxx +++ b/src/invert/fft_fftw.cxx @@ -28,6 +28,8 @@ #include #include #include + +#ifdef BOUT_HAS_FFTW #include #include @@ -37,6 +39,9 @@ #ifdef _OPENMP #include #endif +#else +#include +#endif bool fft_options = false; bool fft_measure; @@ -45,7 +50,6 @@ void fft_init() { if(fft_options) return; - //BOUT_OMP(critical) { Options *opt = Options::getRoot(); opt = opt->getSection("fft"); @@ -61,6 +65,7 @@ void fft_init() #ifndef _OPENMP // Serial code void rfft(const BoutReal *in, int length, dcomplex *out) { +#ifdef BOUT_HAS_FFTW // static variables initialized once static double *fin; static fftw_complex *fout; @@ -116,6 +121,9 @@ void rfft(const BoutReal *in, int length, dcomplex *out) { // Store the output in out, and normalize for(int i=0;i rfft(const Array &in) { @@ -129,6 +137,7 @@ const Array rfft(const Array &in) { } void irfft(const dcomplex *in, int length, BoutReal *out) { +#ifdef BOUT_HAS_FFTW // static variables initialized once static fftw_complex *fin; static double *fout; @@ -183,11 +192,15 @@ void irfft(const dcomplex *in, int length, BoutReal *out) { // Store the output of the fftw to the out for(int i=0;i(length) - 1); // Normalise +#else + throw BoutException("This instance of BOUT++ has been compiled without fftw support."); +#endif } void DST_rev(dcomplex *in, int length, BoutReal *out) { +#ifdef BOUT_HAS_FFTW static fftw_complex *fin; static double *fout; static fftw_plan p; @@ -432,4 +457,7 @@ void DST_rev(dcomplex *in, int length, BoutReal *out) { out[length-1]=0.0; for(int i=1;i Date: Thu, 6 Dec 2018 19:24:02 +0000 Subject: [PATCH 0392/1783] Only search for FFTW if requested and report result in configure summary --- configure | 19 ++++++++++++------- configure.ac | 14 ++++++++------ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/configure b/configure index fb3eb055f1..7427dc9ccb 100755 --- a/configure +++ b/configure @@ -6212,8 +6212,6 @@ $as_echo X"$fftw_wisdom0" | s/.*/./; q'` with_fftw="$with_fftw $fftw_wisdom" -fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fftw3.h" >&5 $as_echo_n "checking for fftw3.h... " >&6; } @@ -6305,7 +6303,7 @@ fi if test .$BACH_found = .yes; then : else - as_fn_error $? "FFTW3 is needed by BOUT++" "$LINENO" 5 + as_fn_error $? "FFTW3 requested but not found" "$LINENO" 5 fi @@ -6443,7 +6441,7 @@ fi if test $BACL_found = yes; then : else - as_fn_error $? "FFTW3 is needed by BOUT++" "$LINENO" 5 + as_fn_error $? "FFTW3 requested but not found" "$LINENO" 5 fi LIBS=$save_LIBS @@ -6457,9 +6455,14 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -#If we've reached this point then we're happy that we have FFTW so -#add our define to CXXFLAGS -CXXFLAGS="$CXXFLAGS -DBOUT_HAS_FFTW" + #If we've reached this point then we're happy that we have FFTW so + #add our define to CXXFLAGS + CXXFLAGS="$CXXFLAGS -DBOUT_HAS_FFTW" + HAS_FFTW="yes" + +else + HAS_FFTW="no" +fi ############################################################# # netCDF support @@ -17082,6 +17085,8 @@ $as_echo "$as_me: IDA support : $HAS_IDA" >&6;} $as_echo "$as_me: CVODE support : $HAS_CVODE" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: ARKODE support : $HAS_ARKODE" >&5 $as_echo "$as_me: ARKODE support : $HAS_ARKODE" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: FFTW support : $HAS_FFTW" >&5 +$as_echo "$as_me: FFTW support : $HAS_FFTW" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: NetCDF support : $HAS_NETCDF" >&5 $as_echo "$as_me: NetCDF support : $HAS_NETCDF" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: Parallel-NetCDF support : $HAS_PNETCDF" >&5 diff --git a/configure.ac b/configure.ac index 703daa5e63..f1a48f191d 100644 --- a/configure.ac +++ b/configure.ac @@ -398,14 +398,15 @@ AS_IF([test "x$fftw_path" != "xno"], [ fftw_wisdom0=`AS_DIRNAME(["$fftw_path"])` fftw_wisdom=`AS_DIRNAME(["$fftw_wisdom0"])` with_fftw="$with_fftw $fftw_wisdom" -]) -BOUT_ADDPATH_CHECK_HEADER(fftw3.h, ,AC_MSG_ERROR([FFTW3 is needed by BOUT++]), $with_fftw) -BOUT_ADDPATH_CHECK_LIB(fftw3, fftw_plan_dft_r2c_1d, ,AC_MSG_ERROR([FFTW3 is needed by BOUT++]), $with_fftw) + BOUT_ADDPATH_CHECK_HEADER(fftw3.h, ,AC_MSG_ERROR([FFTW3 requested but not found]), $with_fftw) + BOUT_ADDPATH_CHECK_LIB(fftw3, fftw_plan_dft_r2c_1d, ,AC_MSG_ERROR([FFTW3 requested but not found]), $with_fftw) -#If we've reached this point then we're happy that we have FFTW so -#add our define to CXXFLAGS -CXXFLAGS="$CXXFLAGS -DBOUT_HAS_FFTW" + #If we've reached this point then we're happy that we have FFTW so + #add our define to CXXFLAGS + CXXFLAGS="$CXXFLAGS -DBOUT_HAS_FFTW" + HAS_FFTW="yes" +], [HAS_FFTW="no"]) ############################################################# # netCDF support @@ -1296,6 +1297,7 @@ AC_MSG_NOTICE([ SLEPc support : $HAS_SLEPC]) AC_MSG_NOTICE([ IDA support : $HAS_IDA]) AC_MSG_NOTICE([ CVODE support : $HAS_CVODE]) AC_MSG_NOTICE([ ARKODE support : $HAS_ARKODE]) +AC_MSG_NOTICE([ FFTW support : $HAS_FFTW]) AC_MSG_NOTICE([ NetCDF support : $HAS_NETCDF]) AC_MSG_NOTICE([ Parallel-NetCDF support : $HAS_PNETCDF]) AC_MSG_NOTICE([ HDF5 support : $HAS_HDF5 (parallel: $HAS_PHDF5)]) From 12c9916cf4a6598554d68408dbb7630ff3cf8f49 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 6 Dec 2018 19:28:59 +0000 Subject: [PATCH 0393/1783] Make fftw configure a bit more verbose in different cases --- configure | 11 ++++++++--- configure.ac | 10 ++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/configure b/configure index 7427dc9ccb..496640cea0 100755 --- a/configure +++ b/configure @@ -6120,6 +6120,8 @@ fi # FFT routines ############################################################# +if test "x$with_fftw" != "xno"; then : + # Extract the first word of "fftw-wisdom", so it can be a program name with args. set dummy fftw-wisdom; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 @@ -6162,7 +6164,7 @@ fi -if test "x$fftw_path" != "xno"; then : + if test "x$fftw_path" != "xno"; then : fftw_wisdom0=`$as_dirname -- "$fftw_path" || $as_expr X"$fftw_path" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ @@ -6303,7 +6305,7 @@ fi if test .$BACH_found = .yes; then : else - as_fn_error $? "FFTW3 requested but not found" "$LINENO" 5 + as_fn_error $? "FFTW3 requested but header not found" "$LINENO" 5 fi @@ -6441,7 +6443,7 @@ fi if test $BACL_found = yes; then : else - as_fn_error $? "FFTW3 requested but not found" "$LINENO" 5 + as_fn_error $? "FFTW3 requested but library not found" "$LINENO" 5 fi LIBS=$save_LIBS @@ -6460,6 +6462,9 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu CXXFLAGS="$CXXFLAGS -DBOUT_HAS_FFTW" HAS_FFTW="yes" +else + as_fn_error $? "FFTW3 requested but fftw-wisdom not found" "$LINENO" 5 +fi else HAS_FFTW="no" fi diff --git a/configure.ac b/configure.ac index f1a48f191d..9cb928b2bf 100644 --- a/configure.ac +++ b/configure.ac @@ -392,21 +392,23 @@ AS_IF([test $? = 0], [ # FFT routines ############################################################# +AS_IF([test "x$with_fftw" != "xno"], [ AC_PATH_PROG([fftw_path], [fftw-wisdom], [no], [$with_fftw$PATH_SEPARATOR$PATH]) -AS_IF([test "x$fftw_path" != "xno"], [ + AS_IF([test "x$fftw_path" != "xno"], [ fftw_wisdom0=`AS_DIRNAME(["$fftw_path"])` fftw_wisdom=`AS_DIRNAME(["$fftw_wisdom0"])` with_fftw="$with_fftw $fftw_wisdom" - BOUT_ADDPATH_CHECK_HEADER(fftw3.h, ,AC_MSG_ERROR([FFTW3 requested but not found]), $with_fftw) - BOUT_ADDPATH_CHECK_LIB(fftw3, fftw_plan_dft_r2c_1d, ,AC_MSG_ERROR([FFTW3 requested but not found]), $with_fftw) + BOUT_ADDPATH_CHECK_HEADER(fftw3.h, ,AC_MSG_ERROR([FFTW3 requested but header not found]), $with_fftw) + BOUT_ADDPATH_CHECK_LIB(fftw3, fftw_plan_dft_r2c_1d, ,AC_MSG_ERROR([FFTW3 requested but library not found]), $with_fftw) #If we've reached this point then we're happy that we have FFTW so #add our define to CXXFLAGS CXXFLAGS="$CXXFLAGS -DBOUT_HAS_FFTW" HAS_FFTW="yes" -], [HAS_FFTW="no"]) +], AC_MSG_ERROR([FFTW3 requested but fftw-wisdom not found]))], +[HAS_FFTW="no"]) ############################################################# # netCDF support From ec9533184c1daa97b8b4b88b538aec03a6f94073 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 6 Dec 2018 19:40:07 +0000 Subject: [PATCH 0394/1783] Be more explicit that we don't recommend configuring without fftw --- configure | 6 +++++- configure.ac | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 496640cea0..ac1c112489 100755 --- a/configure +++ b/configure @@ -6466,7 +6466,11 @@ else as_fn_error $? "FFTW3 requested but fftw-wisdom not found" "$LINENO" 5 fi else - HAS_FFTW="no" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: Configuring without FFTW3 is not recommended" >&5 +$as_echo "$as_me: Configuring without FFTW3 is not recommended" >&6;} +HAS_FFTW="no" + fi ############################################################# diff --git a/configure.ac b/configure.ac index 9cb928b2bf..267eae7e0b 100644 --- a/configure.ac +++ b/configure.ac @@ -408,7 +408,10 @@ AC_PATH_PROG([fftw_path], [fftw-wisdom], [no], [$with_fftw$PATH_SEPARATOR$PATH]) CXXFLAGS="$CXXFLAGS -DBOUT_HAS_FFTW" HAS_FFTW="yes" ], AC_MSG_ERROR([FFTW3 requested but fftw-wisdom not found]))], -[HAS_FFTW="no"]) +[ +AC_MSG_NOTICE([Configuring without FFTW3 is not recommended]) +HAS_FFTW="no" +]) ############################################################# # netCDF support From 6d6a8f1bb87d50615cee9a3b580bb48404f02dc3 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 6 Dec 2018 19:42:25 +0000 Subject: [PATCH 0395/1783] Tweak manual to indicate fftw isn't required but recommended --- manual/sphinx/user_docs/installing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manual/sphinx/user_docs/installing.rst b/manual/sphinx/user_docs/installing.rst index a39bfae310..2dc88775b9 100644 --- a/manual/sphinx/user_docs/installing.rst +++ b/manual/sphinx/user_docs/installing.rst @@ -126,9 +126,9 @@ The bare-minimum requirements for compiling and running BOUT++ are: MPICH ( `https://www.mpich.org/ `__) or LAM (`www.lam-mpi.org/ `__) -#. The FFTW-3 library ( `http://www.fftw.org/ `__ ) - #. The NetCDF library ( `https://www.unidata.ucar.edu/downloads/netcdf `__ ) + +The FFTW-3 library ( `http://www.fftw.org/ `__ ) is also strongly recommended .. note:: If you use an Intel compiler, you must also make sure that you have From 7bdb78baa2e84929ac312d366d43b56ac94f51fd Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Dec 2018 19:42:06 +0000 Subject: [PATCH 0396/1783] Add zstart and zend to mesh and some initial code for introducing z boundaries --- include/bout/mesh.hxx | 4 ++-- src/mesh/impls/bout/boutmesh.cxx | 41 +++++++++++++++++++++++--------- src/mesh/impls/bout/boutmesh.hxx | 10 ++++---- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index b745d7e81e..debd1a5298 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -426,8 +426,8 @@ class Mesh { int LocalNx, LocalNy, LocalNz; /// Local ranges of data (inclusive), excluding guard cells - int xstart, xend, ystart, yend; - + int xstart, xend, ystart, yend, zstart, zend; + bool StaggerGrids; ///< Enable staggered grids (Centre, Lower). Otherwise all vars are cell centred (default). bool IncIntShear; ///< Include integrated shear (if shifting X) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 0bf59de09a..dfbde17f56 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -108,23 +108,24 @@ int BoutMesh::load() { if (Mesh::get(ny, "ny")) throw BoutException(_("Mesh must contain ny")); - int MZ; - - if (Mesh::get(MZ, "nz")) { + if (Mesh::get(nz, "nz")) { // No "nz" variable in the grid file. Instead read MZ from options OPTION(options, MZ, 64); - if (!is_pow2(MZ)) { + OPTION(options, nz, MZ); + ASSERT0(nz == MZ); + if (!is_pow2(nz)) { // Should be a power of 2 for efficient FFTs - output_warn.write(_("WARNING: Number of toroidal points should be 2^n for efficient " - "FFT performance -- consider changing MZ if using FFTs\n"), - MZ); + output_warn.write( + _("WARNING: Number of toroidal points should be 2^n for efficient " + "FFT performance -- consider changing MZ if using FFTs\n"), + nz); } } else { output_info.write(_("\tRead nz from input grid file\n")); } - output_info << _("\tGrid size: ") << nx << " x " << ny << " x " << MZ << endl; + output_info << _("\tGrid size: ") << nx << " x " << ny << " x " << nz << endl; // Get guard cell sizes // Try to read from grid file first, then if not found @@ -140,7 +141,12 @@ int BoutMesh::load() { } ASSERT0(MYG >= 0); - output_info << _("\tGuard cells (x,y): ") << MXG << ", " << MYG << std::endl; + // For now only support no z-guard cells + MZG = 0; + ASSERT0(MZG >= 0); + + output_info << _("\tGuard cells (x,y,z): ") << MXG << ", " << MYG << ", " << MZG + << std::endl; // Check that nx is large enough if (nx <= 2 * MXG) { @@ -150,7 +156,7 @@ int BoutMesh::load() { // Set global grid sizes GlobalNx = nx; GlobalNy = ny + 2 * MYG; - GlobalNz = MZ; + GlobalNz = nz; if (2 * MXG >= nx) throw BoutException(_("nx must be greater than 2*MXG")); @@ -227,6 +233,9 @@ int BoutMesh::load() { jyseps2_2 = jyseps1_2; } + // For now don't parallelise z + NZPE = 1; + if (options->isSet("NXPE")) { // Specified NXPE options->get("NXPE", NXPE, 1); // Decomposition in the radial direction if ((NPES % NXPE) != 0) { @@ -415,6 +424,12 @@ int BoutMesh::load() { _("\tERROR: Cannot split %d Y points equally between %d processors\n"), MY, NYPE); } + MZSUB = MZ / NZPE; + if ((MY % NYPE) != 0) { + throw BoutException( + _("\tERROR: Cannot split %d Z points equally between %d processors\n"), MZ, NZPE); + } + /// Get mesh options OPTION(options, IncIntShear, false); OPTION(options, periodicX, false); // Periodic in X @@ -441,10 +456,13 @@ int BoutMesh::load() { /// Number of grid cells is ng* = M*SUB + guard/boundary cells LocalNx = MXSUB + 2 * MXG; LocalNy = MYSUB + 2 * MYG; - LocalNz = MZ; + LocalNz = MZSUB + 2 * MZG; // Set local index ranges + zstart = MZG; + zend = MZG + MZSUB - 1; + xstart = MXG; xend = MXG + MXSUB - 1; @@ -2541,6 +2559,7 @@ void BoutMesh::outputVars(Datafile &file) { file.add(MYG, "MYG", false); file.add(nx, "nx", false); file.add(ny, "ny", false); + file.add(LocalNz, "nz", false); file.add(LocalNz, "MZ", false); file.add(NXPE, "NXPE", false); file.add(NYPE, "NYPE", false); diff --git a/src/mesh/impls/bout/boutmesh.hxx b/src/mesh/impls/bout/boutmesh.hxx index 6964ebf2dc..a6db6a2fa9 100644 --- a/src/mesh/impls/bout/boutmesh.hxx +++ b/src/mesh/impls/bout/boutmesh.hxx @@ -161,10 +161,10 @@ class BoutMesh : public Mesh { private: std::string gridname; - int nx, ny; ///< Size of the grid in the input file - int MX, MY; ///< size of the grid excluding boundary regions + int nx, ny, nz; ///< Size of the grid in the input file + int MX, MY, MZ; ///< size of the grid excluding boundary regions - int MYSUB, MXSUB; ///< Size of the grid on this processor + int MYSUB, MXSUB, MZSUB; ///< Size of the grid on this processor int NPES; ///< Number of processors int MYPE; ///< Rank of this processor @@ -172,6 +172,8 @@ class BoutMesh : public Mesh { int PE_YIND; ///< Y index of this processor int NYPE; // Number of processors in the Y direction + int NZPE; + int MYPE_IN_CORE; // 1 if processor in core // Topology @@ -207,7 +209,7 @@ class BoutMesh : public Mesh { int zperiod; BoutReal ZMIN, ZMAX; // Range of the Z domain (in fractions of 2pi) - int MXG, MYG; // Boundary sizes + int MXG, MYG, MZG; // Boundary sizes void default_connections(); void set_connection(int ypos1, int ypos2, int xge, int xlt, bool ts = false); From 6d0591917f96a2bd1b11369bc8a0da0e45b44ae5 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Dec 2018 19:46:16 +0000 Subject: [PATCH 0397/1783] Update default regions to use zstart/end --- src/mesh/mesh.cxx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 73bca69767..6679f16cb4 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -390,12 +390,14 @@ void Mesh::createDefaultRegions(){ //3D regions addRegion3D("RGN_ALL", Region(0, LocalNx - 1, 0, LocalNy - 1, 0, LocalNz - 1, LocalNy, LocalNz, maxregionblocksize)); - addRegion3D("RGN_NOBNDRY", Region(xstart, xend, ystart, yend, 0, LocalNz - 1, + addRegion3D("RGN_NOBNDRY", Region(xstart, xend, ystart, yend, zstart, zend, LocalNy, LocalNz, maxregionblocksize)); addRegion3D("RGN_NOX", Region(xstart, xend, 0, LocalNy - 1, 0, LocalNz - 1, LocalNy, LocalNz, maxregionblocksize)); addRegion3D("RGN_NOY", Region(0, LocalNx - 1, ystart, yend, 0, LocalNz - 1, LocalNy, LocalNz, maxregionblocksize)); + addRegion3D("RGN_NOZ", Region(0, LocalNx - 1, 0, LocalNy - 1, zstart, zend, + LocalNy, LocalNz, maxregionblocksize)); addRegion3D("RGN_GUARDS", mask(getRegion3D("RGN_ALL"), getRegion3D("RGN_NOBNDRY"))); //2D regions @@ -412,13 +414,15 @@ void Mesh::createDefaultRegions(){ // Perp regions addRegionPerp("RGN_ALL", Region(0, LocalNx - 1, 0, 0, 0, LocalNz - 1, 1, LocalNz, maxregionblocksize)); - addRegionPerp("RGN_NOBNDRY", Region(xstart, xend, 0, 0, 0, LocalNz - 1, 1, + addRegionPerp("RGN_NOBNDRY", Region(xstart, xend, 0, 0, zstart, zend, 1, LocalNz, maxregionblocksize)); addRegionPerp("RGN_NOX", Region(xstart, xend, 0, 0, 0, LocalNz - 1, 1, LocalNz, maxregionblocksize)); // Same as NOBNDRY addRegionPerp("RGN_NOY", Region(0, LocalNx - 1, 0, 0, 0, LocalNz - 1, 1, - LocalNz, maxregionblocksize)); // Same as ALL - addRegionPerp("RGN_NOZ", getRegionPerp("RGN_ALL")); // Currently the same as ALL + LocalNz, maxregionblocksize)); + + addRegionPerp("RGN_NOZ", Region(0, LocalNx - 1, 0, 0, zstart, zend, 1, LocalNz, + maxregionblocksize)); addRegionPerp("RGN_GUARDS", mask(getRegionPerp("RGN_ALL"), getRegionPerp("RGN_NOBNDRY"))); // Construct index lookup for 3D-->2D From ab2229f42b33e2c4299c45e66851fa745879cca7 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Dec 2018 19:50:43 +0000 Subject: [PATCH 0398/1783] Update some z-loops in difops --- src/mesh/difops.cxx | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index d271a4cda1..26eb3e58c0 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -217,9 +217,9 @@ const Field3D Div_par(const Field3D &f, const Field3D &v) { for(int i=mesh->xstart;i<=mesh->xend;i++) for(int j=mesh->ystart;j<=mesh->yend;j++) { - for(int k=0;kLocalNz;k++) { - - // Value of f and v at left cell face + for (int k = mesh->zstart; k <= mesh->zend; k++) { + + // Value of f and v at left cell face BoutReal fL = 0.5*(f(i,j,k) + f.ydown()(i,j-1,k)); BoutReal vL = 0.5*(v(i,j,k) + v.ydown()(i,j-1,k)); @@ -814,8 +814,8 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, int ncz = mesh->LocalNz; for(int x=mesh->xstart;x<=mesh->xend;x++) for(int y=mesh->ystart;y<=mesh->yend;y++) { - for(int z=0;zLocalNz; z++) { + int zm = (z - 1 + ncz) % ncz; int zp = (z + 1) % ncz; BoutReal gp, gm; @@ -884,7 +884,7 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, } // The middle block - for (int jz = 1; jz < ncz - 1; jz++) { + for (int jz = 1; jz < mesh->LocalNz - 1; jz++) { const int jzp = jz + 1; const int jzm = jz - 1; @@ -925,8 +925,8 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, for(int jx=mesh->xstart;jx<=mesh->xend;jx++){ for(int jy=mesh->ystart;jy<=mesh->yend;jy++){ const BoutReal spacingFactor = partialFactor / metric->dx(jx,jy); - for(int jz=0;jzLocalNz; jz++) { + const int jzp = jz+1 < ncz ? jz + 1 : 0; //Above is alternative to const int jzp = (jz + 1) % ncz; const int jzm = jz-1 >= 0 ? jz - 1 : ncz-1; //Above is alternative to const int jzmTmp = (jz - 1 + ncz) % ncz; @@ -1049,7 +1049,7 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, int ncz = mesh->LocalNz; for(int y=mesh->ystart;y<=mesh->yend;y++) { for(int x=1;x<=mesh->LocalNx-2;x++) { - for(int z=0;zLocalNz; z++) { int zm = (z - 1 + ncz) % ncz; int zp = (z + 1) % ncz; @@ -1175,7 +1175,7 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, result(jx, jy, jz) = (Jpp + Jpx + Jxp) * spacingFactor; } - for (int jz = 1; jz < ncz - 1; jz++) { + for (int jz = 1; jz < mesh->LocalNz - 1; jz++) { const int jzp = jz + 1; const int jzm = jz - 1; @@ -1245,8 +1245,8 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, const BoutReal *Gxm = g_temp(jx-1, jy); const BoutReal *Gx = g_temp(jx, jy); const BoutReal *Gxp = g_temp(jx+1, jy); - for(int jz=0;jzLocalNz; jz++) { + const int jzp = jz+1 < ncz ? jz + 1 : 0; //Above is alternative to const int jzp = (jz + 1) % ncz; const int jzm = jz-1 >= 0 ? jz - 1 : ncz-1; //Above is alternative to const int jzm = (jz - 1 + ncz) % ncz; From 9ef339bae1a07a4208b67cca8f72b6d3ae10843e Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Dec 2018 20:30:26 +0000 Subject: [PATCH 0399/1783] Fix unit tests for introduction of zstart/zend and RGN_NOZ --- tests/unit/field/test_field3d.cxx | 54 +++++++++++++++++++++++++++++-- tests/unit/test_extras.hxx | 2 ++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index a8b4525b27..4ef1b69808 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -578,10 +578,58 @@ TEST_F(Field3DTest, IterateOverRGN_NOY) { } TEST_F(Field3DTest, IterateOverRGN_NOZ) { - Field3D field = 1.0; + const int mzguard = 0; + Field3D field; + + field = 1.0; + + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0, 0}); + test_indices.insert({0, 0, 1}); + test_indices.insert({0, 1, 0}); + test_indices.insert({1, 0, 0}); + test_indices.insert({0, 1, 1}); + test_indices.insert({1, 0, 1}); + test_indices.insert({1, 1, 0}); + test_indices.insert({1, 1, 1}); - // This is not a valid region for Field3D - EXPECT_THROW(field.getRegion(RGN_NOZ), BoutException); + // This is the set of indices actually inside the region we want + std::set> region_indices; + region_indices.insert({0, 0, 0}); + region_indices.insert({0, 0, 1}); + region_indices.insert({0, 1, 0}); + region_indices.insert({1, 0, 0}); + region_indices.insert({0, 1, 1}); + region_indices.insert({1, 0, 1}); + region_indices.insert({1, 1, 0}); + region_indices.insert({1, 1, 1}); + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (const auto index : test_indices) { + field(index[0], index[1], index[2]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (const auto& i : field.getRegion(RGN_NOZ)) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.y(), i.z()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, + ((nx * (ny) * (nz - mzguard)) - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); } TEST_F(Field3DTest, IterateOver2DRGN_ALL) { diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index b042e2a933..bdfff3f5e7 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -64,6 +64,8 @@ public: xend = nx - 2; ystart = 1; yend = ny - 2; + zstart = 0; + zend = nz - 1; StaggerGrids=true; // Unused variables From ecb6f2b8348c299ce713c2e90b176245002b0095 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 7 Dec 2018 21:07:28 +0000 Subject: [PATCH 0400/1783] Small bug fix, ensure MZ is initialised --- src/mesh/impls/bout/boutmesh.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index dfbde17f56..78e8bf1d55 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -122,6 +122,7 @@ int BoutMesh::load() { nz); } } else { + MZ = nz; output_info.write(_("\tRead nz from input grid file\n")); } From 8b657d314ba8e127d7537bdf33455a8d363c079d Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Sat, 8 Dec 2018 17:29:47 +0000 Subject: [PATCH 0401/1783] Tweak to MMS test to force mesh:nz default --- tests/MMS/bracket/runtest | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/MMS/bracket/runtest b/tests/MMS/bracket/runtest index 726ff307e9..a4b83b3191 100755 --- a/tests/MMS/bracket/runtest +++ b/tests/MMS/bracket/runtest @@ -35,6 +35,7 @@ def genMesh(nx,ny,nz,**kwargs): bc.setOption("mesh:nx",str(nx + 4 if nx > 1 else nx), force=True) bc.setOption("mesh:ny",str(ny), force=True) bc.setOption("mz",str(nz), force=True) + bc.setOption("mesh:nz",str(nz), force=True) bc.setOption("mesh:dx","2*pi/(%d)"%(nx), force=True) bc.setOption("mesh:dy","1/(%d)"%(ny), force=True) bc.setOption("mesh:dz","1/(%d)"%(nz), force=True) From fd1fade549c8513ef216d360ce5cae31e71e0656 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sun, 9 Dec 2018 00:19:34 +0000 Subject: [PATCH 0402/1783] Adding toString specialisations - Handle bool, converting to "true" or "false" - Extend precision of BoutReal conversion (update unit test) Added more unit tests --- include/utils.hxx | 33 +++++++++++++++++++++++++++------ src/sys/utils.cxx | 9 ++++++++- tests/unit/sys/test_utils.cxx | 20 +++++++++++++++++++- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/include/utils.hxx b/include/utils.hxx index b78cdaa9f7..e58a4eb952 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -371,21 +371,42 @@ inline void checkData(BoutReal UNUSED(f)){}; */ char* copy_string(const char* s); -/*! - * Convert a value to a string - * by writing to a stringstream - */ + +/// Convert a value to a string +/// by writing to a stringstream template -const std::string toString(const T& val) { +std::string toString(const T& val) { std::stringstream ss; ss << val; return ss.str(); } +/// Simple case where input is already a string +/// This is so that toString can be used in templates +/// where the type may be std::string. +template <> +inline std::string toString<>(const std::string& val) { + return val; +} + +/// Convert a bool to "true" or "false" +template <> +inline std::string toString<>(const bool& val) { + if (val) { + return "true"; + } + return "false"; +} + +/// Convert BoutReal to string +/// Make sure the precision is large enough to hold a BoutReal +template <> +std::string toString<>(const BoutReal& val); + /// Convert a time stamp to a string /// This uses std::localtime and std::put_time template <> -const std::string toString<>(const time_t& time); +std::string toString<>(const time_t& time); /*! * Convert a string to lower case diff --git a/src/sys/utils.cxx b/src/sys/utils.cxx index b255a7711c..32b8bdfc6d 100644 --- a/src/sys/utils.cxx +++ b/src/sys/utils.cxx @@ -139,7 +139,14 @@ std::string trimComments(const std::string &s, const std::string &c) { } template <> -const std::string toString<>(const time_t& time) { +std::string toString<>(const BoutReal& val) { + std::stringstream ss; + ss << std::scientific << std::setprecision(17) << val; + return ss.str(); +} + +template <> +std::string toString<>(const time_t& time) { // Get local time std::tm *tm = std::localtime(&time); diff --git a/tests/unit/sys/test_utils.cxx b/tests/unit/sys/test_utils.cxx index a11b672889..e0c2a30c7d 100644 --- a/tests/unit/sys/test_utils.cxx +++ b/tests/unit/sys/test_utils.cxx @@ -518,6 +518,24 @@ TEST(StringUtilitiesTest, StringToIntFail) { EXPECT_THROW(stringToInt(number_string), BoutException); } +TEST(StringUtilitiesTest, BoolToString) { + std::string true_string = "true"; + std::string false_string = "false"; + + EXPECT_EQ(true_string, toString(true)); + EXPECT_EQ(false_string, toString(false)); +} + +TEST(StringUtilitiesTest, ConstCharToString) { + EXPECT_EQ(std::string("hello"), toString("hello")); +} + +TEST(StringUtilitiesTest, StringToString) { + std::string test_string = "dlkjl872kj"; + + EXPECT_EQ( test_string, toString(test_string) ); +} + TEST(StringUtilitiesTest, IntToString) { int number_int = 42; std::string number_string = "42"; @@ -527,7 +545,7 @@ TEST(StringUtilitiesTest, IntToString) { TEST(StringUtilitiesTest, RealToString) { BoutReal number_real = 3.142e8; - std::string number_string = "3.142e+08"; + std::string number_string = "3.14200000000000000e+08"; EXPECT_EQ(number_string, toString(number_real)); } From 390e6a74f4fc3daa88fcf18d6560881d005d596b Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Sun, 9 Dec 2018 17:32:18 +0000 Subject: [PATCH 0403/1783] Remove duplicated routines from merge --- src/field/field2d.cxx | 4 ---- src/field/fieldperp.cxx | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 810cf78d01..02f2a2e480 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -120,10 +120,6 @@ const Region &Field2D::getRegion(const std::string ®ion_name) const { return fieldmesh->getRegion2D(region_name); }; -const Region& Field2D::getRegion(const std::string ®ion_name) const { - return fieldmesh->getRegion2D(region_name); -} - void Field2D::setLocation(CELL_LOC new_location) { if (getMesh()->StaggerGrids) { if (new_location == CELL_VSHIFT) { diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 11513c58f1..d7b8602ce0 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -169,10 +169,6 @@ const Region &FieldPerp::getRegion(const std::string ®ion_name) cons return fieldmesh->getRegionPerp(region_name); }; -const Region& FieldPerp::getRegion(const std::string ®ion_name) const { - return fieldmesh->getRegionPerp(region_name); -} - //////////////// NON-MEMBER FUNCTIONS ////////////////// ////////////// NON-MEMBER OVERLOADED OPERATORS ////////////// From 14a9494ce993298188dba237eee3e884a46601d2 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Sun, 9 Dec 2018 17:54:45 +0000 Subject: [PATCH 0404/1783] Clang format extra file --- include/bout/invertable_operator.hxx | 172 +++++++++++++++------------ 1 file changed, 93 insertions(+), 79 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 494c6c186e..7122d16333 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -23,6 +23,14 @@ * **************************************************************************/ +template +class InvertableOperator; + +#ifndef __INVERTABLE_OPERATOR_H__ +#define __INVERTABLE_OPERATOR_H__ + +#ifdef BOUT_HAS_PETSC + #include #include #include @@ -30,24 +38,21 @@ #include #include -template class InvertableOperator; - -#ifndef __INVERTABLE_OPERATOR_H__ -#define __INVERTABLE_OPERATOR_H__ - -#ifdef BOUT_HAS_PETSC - #include #include /// No-op function to use as a default -- may wish to remove once testing phase complete -template T identity(const T &in) { return in; }; +template +T identity(const T& in) { + return in; +}; -template class InvertableOperator { +template +class InvertableOperator { static_assert( - std::is_base_of::value || std::is_base_of::value || - std::is_base_of::value, + std::is_base_of::value || std::is_base_of::value + || std::is_base_of::value, "InvertableOperator must be templated with one of FieldPerp, Field2D or Field3D"); public: @@ -55,14 +60,14 @@ public: using data_type = T; /// The signature of the functor that applies the operator. - using function_signature = std::function; + using function_signature = std::function; /// Almost empty constructor -- currently don't actually use Options for anything - InvertableOperator(const function_signature &func = identity, Options *opt = nullptr, - Mesh *localmesh = nullptr) - : operatorFunction(func), preconditionerFunction(func), - opt(opt ? opt : Options::getRoot()->getSection("invertableOperator")), - localmesh(localmesh ? localmesh : mesh), doneSetup(false) { + InvertableOperator(const function_signature& func = identity, Options* opt = nullptr, + Mesh* localmesh = nullptr) + : operatorFunction(func), preconditionerFunction(func), + opt(opt ? opt : Options::getRoot()->getSection("invertableOperator")), + localmesh(localmesh ? localmesh : mesh), doneSetup(false) { TRACE("InvertableOperator::constructor"); }; @@ -71,14 +76,15 @@ public: TRACE("InvertableOperator::destructor"); #if CHECK > 3 output_info << endl; - output_info << "Destroying KSP object in InvertableOperator with properties: " << endl; + output_info << "Destroying KSP object in InvertableOperator with properties: " + << endl; KSPView(ksp, PETSC_VIEWER_STDOUT_SELF); output_info << endl; #endif KSPDestroy(&ksp); MatDestroy(&matOperator); - MatDestroy(&matPreconditioner); + MatDestroy(&matPreconditioner); VecDestroy(&rhs); VecDestroy(&lhs); }; @@ -87,20 +93,21 @@ public: /// Note by default we set the preconditioner function to match this /// as this is the usual mode of operation. If the user doesn't want to /// do this they can set alsoSetPreconditioner to false. - void setOperatorFunction(const function_signature& func, bool alsoSetPreconditioner = true){ + void setOperatorFunction(const function_signature& func, + bool alsoSetPreconditioner = true) { TRACE("InvertableOperator::setOperatorFunction"); operatorFunction = func; - if ( alsoSetPreconditioner ) { + if (alsoSetPreconditioner) { preconditionerFunction = func; } } /// Allow the user to override the existing preconditioner function - void setPreconditionerFunction(const function_signature& func){ - TRACE("InvertableOperator::setPreconditionerFunction"); + void setPreconditionerFunction(const function_signature& func) { + TRACE("InvertableOperator::setPreconditionerFunction"); preconditionerFunction = func; } - + /// Provide a way to apply the operator to a Field T operator()(const T& input) { TRACE("InvertableOperator::operator()"); @@ -108,19 +115,20 @@ public: } /// Provide a synonym for applying the operator to a Field - T apply(const T& input){ return operator()(input); } - + T apply(const T& input) { return operator()(input); } + /// Sets up the PETSc objects required for inverting the operator /// Currently also takes the functor that applies the operator this class /// represents. Not actually required by any of the setup so this should /// probably be moved to a separate place (maybe the constructor). PetscErrorCode setup() { TRACE("InvertableOperator::setup"); - + Timer timer("invertable_operator_setup"); if (doneSetup) { - throw BoutException("Trying to call setup on an InvertableOperator instance that has " - "already been setup."); + throw BoutException( + "Trying to call setup on an InvertableOperator instance that has " + "already been setup."); } PetscInt ierr; @@ -140,14 +148,12 @@ public: &matOperator); CHKERRQ(ierr); - /// Create vectors compatible with matrix -#if PETSC_VERSION_LT(3,6,0) - ierr = MatGetVecs(matOperator, &rhs, - &lhs); -#else - ierr = MatCreateVecs(matOperator, &rhs, - &lhs); -#endif +/// Create vectors compatible with matrix +#if PETSC_VERSION_LT(3, 6, 0) + ierr = MatGetVecs(matOperator, &rhs, &lhs); +#else + ierr = MatCreateVecs(matOperator, &rhs, &lhs); +#endif CHKERRQ(ierr); /// Zero out the lhs vector as values used for initial guess @@ -155,7 +161,7 @@ public: /// done in the callback function using the passed Field. ierr = VecSet(lhs, 0.0); CHKERRQ(ierr); - + /// Now register Matrix_multiply operation ierr = MatShellSetOperation(matOperator, MATOP_MULT, (void (*)(void))(functionWrapper)); @@ -168,23 +174,24 @@ public: CHKERRQ(ierr); /// Now register Matrix_multiply operation - ierr = - MatShellSetOperation(matPreconditioner, MATOP_MULT, (void (*)(void))(preconditionerWrapper)); + ierr = MatShellSetOperation(matPreconditioner, MATOP_MULT, + (void (*)(void))(preconditionerWrapper)); CHKERRQ(ierr); /// Now create and setup the linear solver with the matrix ierr = KSPCreate(BoutComm::get(), &ksp); CHKERRQ(ierr); -#if PETSC_VERSION_LT(3,5,0) +#if PETSC_VERSION_LT(3, 5, 0) /// Need to provide a MatStructure flag in versions <3.5. This details if we expect /// the preconditioner matrix structure to vary between calls to KSPSolve. /// Safest but slowest option is DIFFERENT_NONZERO_PATTERN but can probably usually /// use SAME_PRECONDITIONER. - ierr = KSPSetOperators(ksp, matOperator, matPreconditioner, DIFFERENT_NONZERO_PATTERN); + ierr = + KSPSetOperators(ksp, matOperator, matPreconditioner, DIFFERENT_NONZERO_PATTERN); #else ierr = KSPSetOperators(ksp, matOperator, matPreconditioner); -#endif +#endif CHKERRQ(ierr); /// By default allow a non-zero initial guess as this is probably the @@ -194,7 +201,7 @@ public: /// guess of zero being used. ierr = KSPSetInitialGuessNonzero(ksp, PETSC_TRUE); CHKERRQ(ierr); - + /// Allow options to be set on command line using a --invert_ksp_* prefix. ierr = KSPSetOptionsPrefix(ksp, "invert_"); CHKERRQ(ierr); @@ -214,22 +221,22 @@ public: // This may be the way to set the initial guess // but suspect it's not as there are KSPGuess objects // to deal with. - T invert(const T &rhsField, const T &guess) { + T invert(const T& rhsField, const T& guess) { fieldToPetscVec(guess, lhs); return invert(rhsField); } - + /// Triggers the solve of A.x = b for x, where b = rhs and A is the matrix /// representation /// of the operator we represent. Should probably provide an overload or similar as a /// way of setting the initial guess. - T invert(const T &rhsField) { + T invert(const T& rhsField) { TRACE("InvertableOperator::invert"); Timer timer("invertable_operator_invert"); if (!doneSetup) { - throw BoutException( - "Trying to call invert on an InvertableOperator instance that has not been setup."); + throw BoutException("Trying to call invert on an InvertableOperator instance that " + "has not been setup."); } ASSERT2(localmesh == rhsField.getMesh()); @@ -269,11 +276,11 @@ public: /// With checks enabled provides a convience routine to check that /// applying the registered function on the calculated inverse gives /// back the initial values. - bool verify(const T &rhsIn, BoutReal tol = 1.0e-5) { + bool verify(const T& rhsIn, BoutReal tol = 1.0e-5) { TRACE("InvertableOperator::verify"); #if CHECK > 1 T result = invert(rhsIn); - localmesh->communicate(result); + localmesh->communicate(result); const T applied = operator()(result); const BoutReal maxDiff = max(abs(applied - rhsIn), true); #if CHECK > 3 @@ -294,7 +301,7 @@ public: /// that as the Timer "labels" are not unique to an instance the time /// reported is summed across all different instances. static void reportTime() { - TRACE("InvertableOperator::reportTime"); + TRACE("InvertableOperator::reportTime"); BoutReal time_setup = Timer::resetTime("invertable_operator_setup"); BoutReal time_invert = Timer::resetTime("invertable_operator_invert"); BoutReal time_packing = Timer::resetTime("invertable_operator_packing"); @@ -302,28 +309,30 @@ public: BoutReal time_operate = Timer::resetTime("invertable_operator_operate"); output_warn << "InvertableOperator timing :: Setup " << time_setup; output_warn << " , Invert(packing) " << time_invert << "("; - output_warn << time_packing << ")" ; - output_warn << " operate :"<; - /// The function that represents the preconditioner for the operator that we wish to invert + /// The function that represents the preconditioner for the operator that we wish to + /// invert function_signature preconditionerFunction = identity; - // To ensure PETSc has been setup -- a bit noisy if creating/destroying InvertableOperator, + // Internal types + Options* opt; // Do we need this? + Mesh* localmesh; //< To ensure we can create T on the right mesh + bool doneSetup = false; + + // To ensure PETSc has been setup -- a bit noisy if creating/destroying + // InvertableOperator, // maybe this should be static to avoid this but then how do we initialise it? PetscLib lib; // Do we need this? @@ -333,9 +342,10 @@ private: /// copies the result into the v2 argument. static PetscErrorCode functionWrapper(Mat m, Vec v1, Vec v2) { TRACE("InvertableOperator::functionWrapper"); - InvertableOperator *ctx; + InvertableOperator* ctx; auto ierr = MatShellGetContext(m, &ctx); - T tmpField(ctx->localmesh); tmpField.allocate(); + T tmpField(ctx->localmesh); + tmpField.allocate(); petscVecToField(v1, tmpField); // Need following communicate if operator() uses guard cells, i.e. differential // operator. Could delegate to the user function but then need to remove const @@ -343,14 +353,14 @@ private: // @TODO : Consider removing the communicate and introduce requirement for user // function to communicate if required. This would be neater as currently result // of invert needs explicitly communicating if we want to apply the operator to - // it, for example (e.g. see verify). - ctx->localmesh->communicate(tmpField); + // it, for example (e.g. see verify). + ctx->localmesh->communicate(tmpField); T tmpField2 = ctx->operator()(tmpField); // This communicate is required in case operator() ends up not setting // all periodic boundaries correctly (possibly -- need to check?) // @TODO : Consider need for this communicate. Could communicate at the // end of the user routine. - ctx->localmesh->communicate(tmpField2); + ctx->localmesh->communicate(tmpField2); fieldToPetscVec(tmpField2, v2); return ierr; } @@ -361,9 +371,10 @@ private: /// copies the result into the v2 argument. static PetscErrorCode preconditionerWrapper(Mat m, Vec v1, Vec v2) { TRACE("InvertableOperator::functionWrapper"); - InvertableOperator *ctx; + InvertableOperator* ctx; auto ierr = MatShellGetContext(m, &ctx); - T tmpField(ctx->localmesh); tmpField.allocate(); + T tmpField(ctx->localmesh); + tmpField.allocate(); petscVecToField(v1, tmpField); // Need following communicate if operator() uses guard cells, i.e. differential // operator. Could delegate to the user function but then need to remove const @@ -371,32 +382,33 @@ private: // @TODO : Consider removing the communicate and introduce requirement for user // function to communicate if required. This would be neater as currently result // of invert needs explicitly communicating if we want to apply the operator to - // it, for example (e.g. see verify). - ctx->localmesh->communicate(tmpField); + // it, for example (e.g. see verify). + ctx->localmesh->communicate(tmpField); T tmpField2 = ctx->preconditionerFunction(tmpField); // This communicate is required in case operator() ends up not setting // all periodic boundaries correctly (possibly -- need to check?) // @TODO : Consider need for this communicate. Could communicate at the // end of the user routine. - ctx->localmesh->communicate(tmpField2); + ctx->localmesh->communicate(tmpField2); fieldToPetscVec(tmpField2, v2); return ierr; } }; /// Pack a PetscVec from a Field -template PetscErrorCode fieldToPetscVec(const T &in, Vec out) { +template +PetscErrorCode fieldToPetscVec(const T& in, Vec out) { TRACE("fieldToPetscVec"); Timer timer("invertable_operator_packing"); - PetscScalar *vecData; + PetscScalar* vecData; auto ierr = VecGetArray(out, &vecData); CHKERRQ(ierr); int counter = 0; - BOUT_FOR_SERIAL(i, in.getRegion("RGN_NOCORNERS") ) { + BOUT_FOR_SERIAL(i, in.getRegion("RGN_NOCORNERS")) { vecData[counter] = in[i]; counter++; } @@ -408,18 +420,19 @@ template PetscErrorCode fieldToPetscVec(const T &in, Vec out) { } /// Pack a Field from a PetscVec -template PetscErrorCode petscVecToField(Vec in, T &out) { +template +PetscErrorCode petscVecToField(Vec in, T& out) { TRACE("petscVecToField"); Timer timer("invertable_operator_packing"); - const PetscScalar *vecData; + const PetscScalar* vecData; auto ierr = VecGetArrayRead(in, &vecData); CHKERRQ(ierr); int counter = 0; - BOUT_FOR_SERIAL(i, out.getRegion("RGN_NOCORNERS") ) { + BOUT_FOR_SERIAL(i, out.getRegion("RGN_NOCORNERS")) { out[i] = vecData[counter]; counter++; } @@ -432,7 +445,8 @@ template PetscErrorCode petscVecToField(Vec in, T &out) { #else -template class InvertableOperator { +template +class InvertableOperator { public: }; From 7cee32d0c14bb32db7d30a6848e811309c6c01ed Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Sun, 9 Dec 2018 17:55:19 +0000 Subject: [PATCH 0405/1783] Ignore executable example --- examples/invertable_operator/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 examples/invertable_operator/.gitignore diff --git a/examples/invertable_operator/.gitignore b/examples/invertable_operator/.gitignore new file mode 100644 index 0000000000..1d6c85a9e7 --- /dev/null +++ b/examples/invertable_operator/.gitignore @@ -0,0 +1 @@ +invertable_operator \ No newline at end of file From 48f63d85f30ed0c1bb79f71d3ff424c156dd5265 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Sun, 9 Dec 2018 18:02:04 +0000 Subject: [PATCH 0406/1783] Provide introspection routines to find out if a region has already been defined --- include/bout/mesh.hxx | 5 +++++ src/mesh/mesh.cxx | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index b745d7e81e..a58fb7f428 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -772,6 +772,11 @@ class Mesh { const Region &getRegion2D(const std::string ®ion_name) const; const Region &getRegionPerp(const std::string ®ion_name) const; + /// Indicate if named region has already been defined + const bool hasRegion3D(const std::string& region_name) const; + const bool hasRegion2D(const std::string& region_name) const; + const bool hasRegionPerp(const std::string& region_name) const; + /// Add a new region to the region_map for the data iterator /// /// Outputs an error message if region_name already exists diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 44d77228a6..2e45b4e62a 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -359,6 +359,33 @@ const Region &Mesh::getRegionPerp(const std::string ®ion_name) const return found->second; } +const bool Mesh::hasRegion3D(const std::string& region_name) const { + const auto found = regionMap3D.find(region_name); + if (found == end(regionMap3D)) { + return false; + } else { + return true; + } +} + +const bool Mesh::hasRegion2D(const std::string& region_name) const { + const auto found = regionMap2D.find(region_name); + if (found == end(regionMap2D)) { + return false; + } else { + return true; + } +} + +const bool Mesh::hasRegionPerp(const std::string& region_name) const { + const auto found = regionMapPerp.find(region_name); + if (found == end(regionMapPerp)) { + return false; + } else { + return true; + } +} + void Mesh::addRegion3D(const std::string ®ion_name, const Region<> ®ion) { if (regionMap3D.count(region_name)) { throw BoutException(_("Trying to add an already existing region %s to regionMap3D"), region_name.c_str()); From 0008b1fb907755941d733b8368d3290095eec237 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Sun, 9 Dec 2018 18:59:13 +0000 Subject: [PATCH 0407/1783] Move creation of RGN_NOCORNERS into InvertableOperator constructor --- include/bout/invertable_operator.hxx | 102 ++++++++++++++++++++++++++- src/mesh/mesh.cxx | 60 ---------------- 2 files changed, 100 insertions(+), 62 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 7122d16333..6bf9354097 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -64,11 +64,109 @@ public: /// Almost empty constructor -- currently don't actually use Options for anything InvertableOperator(const function_signature& func = identity, Options* opt = nullptr, - Mesh* localmesh = nullptr) + Mesh* localmeshIn = nullptr) : operatorFunction(func), preconditionerFunction(func), opt(opt ? opt : Options::getRoot()->getSection("invertableOperator")), - localmesh(localmesh ? localmesh : mesh), doneSetup(false) { + localmesh(localmeshIn == nullptr ? mesh : localmeshIn), doneSetup(false) { TRACE("InvertableOperator::constructor"); + + if (std::is_same::value) { + if (not localmesh->hasRegion3D("RGN_NOCORNERS")) { + // This avoids all guard cells and corners but includes boundaries + // Note we probably don't want to include periodic boundaries as these + // are essentially just duplicate points so should be careful here (particularly + // in y) + // to only include unique points + Region nocorner3D = localmesh->getRegion3D("RGN_NOBNDRY"); + if (!localmesh->periodicX) { + if (localmesh->firstX()) + nocorner3D += Region(0, localmesh->xstart - 1, localmesh->ystart, + localmesh->yend, 0, localmesh->LocalNz - 1, + localmesh->LocalNy, localmesh->LocalNz, + localmesh->maxregionblocksize); + if (localmesh->lastX()) + nocorner3D += Region( + localmesh->LocalNx - localmesh->xstart, localmesh->LocalNx - 1, + localmesh->ystart, localmesh->yend, 0, localmesh->LocalNz - 1, + localmesh->LocalNy, localmesh->LocalNz, localmesh->maxregionblocksize); + } + if (localmesh->firstY() or localmesh->lastY()) { + for (int ix = localmesh->xstart; ix <= localmesh->xend; ix++) { + if (not localmesh->periodicY(ix)) { + if (localmesh->firstY()) + nocorner3D += + Region(ix, ix, 0, localmesh->ystart - 1, 0, + localmesh->LocalNz - 1, localmesh->LocalNy, + localmesh->LocalNz, localmesh->maxregionblocksize); + if (localmesh->lastY()) + nocorner3D += Region( + ix, ix, localmesh->LocalNy - localmesh->ystart, + localmesh->LocalNy - 1, 0, localmesh->LocalNz - 1, localmesh->LocalNy, + localmesh->LocalNz, localmesh->maxregionblocksize); + } + } + } + + nocorner3D.unique(); + localmesh->addRegion3D("RGN_NOCORNERS", nocorner3D); + } + + } else if (std::is_same::value) { + if (not localmesh->hasRegion2D("RGN_NOCORNERS")) { + // This avoids all guard cells and corners but includes boundaries + Region nocorner2D = localmesh->getRegion2D("RGN_NOBNDRY"); + if (!localmesh->periodicX) { + if (localmesh->firstX()) + nocorner2D += Region(0, localmesh->xstart - 1, localmesh->ystart, + localmesh->yend, 0, 0, localmesh->LocalNy, 1, + localmesh->maxregionblocksize); + if (localmesh->lastX()) + nocorner2D += + Region(localmesh->LocalNx - localmesh->xstart, + localmesh->LocalNx - 1, localmesh->ystart, localmesh->yend, + 0, 0, localmesh->LocalNy, 1, localmesh->maxregionblocksize); + } + if (localmesh->firstY() or localmesh->lastY()) { + for (int ix = localmesh->xstart; ix <= localmesh->xend; ix++) { + if (not localmesh->periodicY(ix)) { + if (localmesh->firstY()) + nocorner2D += + Region(ix, ix, 0, localmesh->ystart - 1, 0, 0, + localmesh->LocalNy, 1, localmesh->maxregionblocksize); + if (localmesh->lastY()) + nocorner2D += + Region(ix, ix, localmesh->LocalNy - localmesh->ystart, + localmesh->LocalNy - 1, 0, 0, localmesh->LocalNy, 1, + localmesh->maxregionblocksize); + } + } + } + nocorner2D.unique(); + localmesh->addRegion2D("RGN_NOCORNERS", nocorner2D); + } + + } else if (std::is_same::value) { + if (not localmesh->hasRegionPerp("RGN_NOCORNERS")) { + // This avoids all guard cells and corners but includes boundaries + Region nocornerPerp = localmesh->getRegionPerp("RGN_NOBNDRY"); + if (!localmesh->periodicX) { + if (localmesh->firstX()) + nocornerPerp += + Region(0, localmesh->xstart - 1, 0, 0, 0, localmesh->LocalNz - 1, + 1, localmesh->LocalNz, localmesh->maxregionblocksize); + if (localmesh->lastX()) + nocornerPerp += + Region(localmesh->LocalNx - localmesh->xstart, + localmesh->LocalNx - 1, 0, 0, 0, localmesh->LocalNz - 1, + 1, localmesh->LocalNz, localmesh->maxregionblocksize); + } + nocornerPerp.unique(); + localmesh->addRegionPerp("RGN_NOCORNERS", nocornerPerp); + } + + } else { + throw BoutException("Invalid template type provided to InvertableOperator"); + } }; /// Destructor just has to cleanup the PETSc owned objects. diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 2e45b4e62a..c17020bb4b 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -425,32 +425,6 @@ void Mesh::createDefaultRegions(){ LocalNy, LocalNz, maxregionblocksize)); addRegion3D("RGN_GUARDS", mask(getRegion3D("RGN_ALL"), getRegion3D("RGN_NOBNDRY"))); - - // This avoids all guard cells and corners but includes boundaries - // Note we probably don't want to include periodic boundaries as these - // are essentially just duplicate points so should be careful here (particularly in y) - // to only include unique points - Region nocorner3D = getRegion3D("RGN_NOBNDRY"); - if(!periodicX) { - if (firstX()) nocorner3D += Region(0,1,ystart, yend, 0, LocalNz -1, - LocalNy, LocalNz, maxregionblocksize); - if (lastX()) nocorner3D += Region(LocalNx - 2,LocalNx - 1,ystart, yend, 0, LocalNz -1, - LocalNy, LocalNz, maxregionblocksize); - } - if(firstY() or lastY()) { - for(int ix = xstart; ix <= xend; ix++) { - if(not periodicY(ix)) { - if (firstY()) nocorner3D += Region(ix,ix,0, 1, 0, LocalNz -1, - LocalNy, LocalNz, maxregionblocksize); - if (lastY()) nocorner3D += Region(ix,ix,LocalNy-2, LocalNy-1, 0, LocalNz -1, - LocalNy, LocalNz, maxregionblocksize); - } - } - } - - nocorner3D.unique(); - addRegion3D("RGN_NOCORNERS", nocorner3D); - //2D regions addRegion2D("RGN_ALL", Region(0, LocalNx - 1, 0, LocalNy - 1, 0, 0, LocalNy, 1, maxregionblocksize)); @@ -462,28 +436,6 @@ void Mesh::createDefaultRegions(){ maxregionblocksize)); addRegion2D("RGN_GUARDS", mask(getRegion2D("RGN_ALL"), getRegion2D("RGN_NOBNDRY"))); - - // This avoids all guard cells and corners but includes boundaries - Region nocorner2D = getRegion2D("RGN_NOBNDRY"); - if(!periodicX) { - if (firstX()) nocorner2D += Region(0,1,ystart, yend, 0, 0, - LocalNy, 1, maxregionblocksize); - if (lastX()) nocorner2D += Region(LocalNx - 2,LocalNx - 1,ystart, yend, 0, 0, - LocalNy, 1, maxregionblocksize); - } - if(firstY() or lastY()) { - for(int ix = xstart; ix <= xend; ix++) { - if(not periodicY(ix)) { - if (firstY()) nocorner2D += Region(ix,ix,0, 1, 0, 0, - LocalNy, 1, maxregionblocksize); - if (lastY()) nocorner2D += Region(ix,ix,LocalNy-2, LocalNy-1, 0, 0, - LocalNy, 1, maxregionblocksize); - } - } - } - nocorner2D.unique(); - addRegion2D("RGN_NOCORNERS", nocorner2D); - // Perp regions addRegionPerp("RGN_ALL", Region(0, LocalNx - 1, 0, 0, 0, LocalNz - 1, 1, LocalNz, maxregionblocksize)); @@ -495,18 +447,6 @@ void Mesh::createDefaultRegions(){ LocalNz, maxregionblocksize)); // Same as ALL addRegionPerp("RGN_NOZ", getRegionPerp("RGN_ALL")); // Currently the same as ALL addRegionPerp("RGN_GUARDS", mask(getRegionPerp("RGN_ALL"), getRegionPerp("RGN_NOBNDRY"))); - - // This avoids all guard cells and corners but includes boundaries - Region nocornerPerp = getRegionPerp("RGN_NOBNDRY"); - if(!periodicX) { - if (firstX()) nocornerPerp += Region(0,1,0, 0, 0, LocalNz -1, - 1, LocalNz, maxregionblocksize); - if (lastX()) nocornerPerp += Region(LocalNx - 2,LocalNx - 1,0, 0, 0, LocalNz -1, - 1, LocalNz, maxregionblocksize); - } - nocornerPerp.unique(); - addRegionPerp("RGN_NOCORNERS", nocornerPerp); - // Construct index lookup for 3D-->2D indexLookup3Dto2D = Array(LocalNx*LocalNy*LocalNz); From af742d6c1615afa612a77320bb5f5065df37d0f5 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 10 Dec 2018 00:09:57 +0000 Subject: [PATCH 0408/1783] Removing toString Not really necessary, fails code style test --- include/utils.hxx | 5 ----- src/sys/utils.cxx | 7 ------- 2 files changed, 12 deletions(-) diff --git a/include/utils.hxx b/include/utils.hxx index e58a4eb952..a574c27264 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -398,11 +398,6 @@ inline std::string toString<>(const bool& val) { return "false"; } -/// Convert BoutReal to string -/// Make sure the precision is large enough to hold a BoutReal -template <> -std::string toString<>(const BoutReal& val); - /// Convert a time stamp to a string /// This uses std::localtime and std::put_time template <> diff --git a/src/sys/utils.cxx b/src/sys/utils.cxx index 32b8bdfc6d..72582b6f17 100644 --- a/src/sys/utils.cxx +++ b/src/sys/utils.cxx @@ -138,13 +138,6 @@ std::string trimComments(const std::string &s, const std::string &c) { return s.substr(0, s.find_first_of(c)); } -template <> -std::string toString<>(const BoutReal& val) { - std::stringstream ss; - ss << std::scientific << std::setprecision(17) << val; - return ss.str(); -} - template <> std::string toString<>(const time_t& time) { // Get local time From 67770d5bcdf2143317179bbb0a3f2e62bb5eaada Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 8 Dec 2018 23:24:35 +0000 Subject: [PATCH 0409/1783] WIP, adapting Options to use std::variant std::variant will be replaced by single header file so works with C++11. Aim is to use Option as a value store, suitable also for reading and writing data files. --- include/options.hxx | 125 ++++++++++++++++++++++++++------------------ src/sys/options.cxx | 38 -------------- 2 files changed, 75 insertions(+), 88 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index f2dbedf82b..93b9e09337 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -190,12 +190,7 @@ public: /// and then saves the resulting string. template T operator=(T inputvalue) { - // Convert to string - std::stringstream ss; - ss << inputvalue; - - // Set the internal value. - _set(ss.str(), "", false); + assign(inputvalue); return inputvalue; } @@ -207,6 +202,7 @@ public: /// Options option; /// option["test"].assign(42, "some source"); /// + /// Note: Specialised versions for types stored in ValueType template void assign(T val, const std::string source="") { std::stringstream ss; @@ -214,6 +210,14 @@ public: _set(ss.str(), source, false); } + // Specialised assign methods for types stored in ValueType + template<> void assign<>(bool val, const std::string source) { _set(val, source, false); } + template<> void assign<>(int val, const std::string source) { _set(val, source, false); } + template<> void assign<>(BoutReal val, const std::string source) { _set(val, source, false); } + template<> void assign<>(std::string val, const std::string source) { _set(val, source, false); } + // Note: const char* version needed to avoid conversion to bool + template<> void assign<>(const char *val, const std::string source) { _set(std::string(val), source, false);} + /// Force to a value /// Overwrites any existing setting template @@ -238,7 +242,7 @@ public: /// int value = option["test"]; /// template operator T() const { return as(); } - + /// Get the value as a specified type /// If there is no value then an exception is thrown /// Note there are specialised versions of this template @@ -256,31 +260,39 @@ public: } T val; - std::stringstream ss(value.value); - ss >> val; - // Check if the parse failed - if (ss.fail()) { - throw BoutException("Option %s could not be parsed ('%s')", full_name.c_str(), value.value.c_str()); - } + if (std::holds_alternative(value)) { + + std::stringstream ss(std::get(value)); + ss >> val; + + // Check if the parse failed + if (ss.fail()) { + throw BoutException("Option %s could not be parsed ('%s')", full_name.c_str(), value.value.c_str()); + } - // Check if there are characters remaining - std::string remainder; - std::getline(ss, remainder); - for (const char &ch : remainder) { - if (!std::isspace(static_cast(ch))) { - // Meaningful character not parsed - throw BoutException("Option %s could not be parsed", full_name.c_str()); + // Check if there are characters remaining + std::string remainder; + std::getline(ss, remainder); + for (const char &ch : remainder) { + if (!std::isspace(static_cast(ch))) { + // Meaningful character not parsed + throw BoutException("Option %s could not be parsed", full_name.c_str()); + } } + } else { + // Value not holding a string. Try casting to the requested type + + val = std::visit( StaticCast(), value ); } // Mark this option as used - value.used = true; // Note this is mutable + attributes["used"] = true; // Note this is mutable output_info << "\tOption " << full_name << " = " << val; - if (!value.source.empty()) { + if (!attributes["source"].empty()) { // Specify the source of the setting - output_info << " (" << value.source << ")"; + output_info << " (" << attributes["source"] << ")"; } output_info << endl; @@ -403,6 +415,12 @@ public: /// clean the cache of parsed options static void cleanCache(); + using ValueType = std::variant; + using AttributeType = std::variant; + + ValueType value; + std::map attributes; + /*! * Class used to store values, together with * information about their origin and usage @@ -434,47 +452,54 @@ public: std::map children; ///< If a section then has children bool is_value = false; ///< Is this Options object a value? - OptionValue value{}; ///< If a value - - void _set(std::string val, std::string source, bool force); + template + void _set(T val, std::string source, bool force) { + if (isSet()) { + // Check if current value the same as new value + if (value != val) { + if (force or attributes["source"] != source) { + output_warn << _("\tOption ") << full_name << " = " << toString(value) << " (" + << attributes["source"] << _(") overwritten with:") << "\n" + << "\t\t" << full_name << " = " << toString(val) << " (" << source + << ")\n"; + } else { + throw BoutException( + _("Options: Setting a value from same source (%s) to new value " + "'%s' - old value was '%s'."), + source.c_str(), toString(val).c_str(), toString(value).c_str()); + } + } + } + + value = std::move(val); + attributes["source"] = std::move(source); + attributes["used"] = false; + is_value = true; + } + /// Tests if two values are similar. template bool similar(T a, T b) const { return a == b; } + + /// Functor to perform static casting with std::visit + /// from https://stackoverflow.com/questions/8806453/functor-version-of-static-cast-in-stdbind + template struct StaticCast { + template Target operator()(Source &&source) const { + return static_cast(std::forward(source)); + } + }; + }; /// Specialised similar comparison methods template <> inline bool Options::similar(BoutReal a, BoutReal b) const { return fabs(a - b) < 1e-10; } -/// Specialised assignment operator -template <> -inline BoutReal Options::operator=(BoutReal inputvalue) { - std::stringstream ss; - // Make sure the precision is large enough to hold a BoutReal - ss << std::scientific << std::setprecision(17) << inputvalue; - _set(ss.str(), "", false); - return inputvalue; -} - /// Specialised as routines template <> std::string Options::as() const; template <> int Options::as() const; template <> BoutReal Options::as() const; template <> bool Options::as() const; -// Specialised assign methods -template<> void Options::assign(bool val, const std::string source); -template<> void Options::assign(BoutReal val, const std::string source); - -// Note: const char* version needed to avoid conversion to bool -template<> -inline void Options::assign(const char *val, const std::string source) { - _set(val,source,false); -} -template<> -inline void Options::assign(std::string val, const std::string source) { - _set(val,source,false); -}; - /// Define for reading options which passes the variable name #define OPTION(options, var, def) \ pointer(options)->get(#var, var, def) diff --git a/src/sys/options.cxx b/src/sys/options.cxx index ede54a01d7..72d668da8d 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -73,44 +73,6 @@ const Options &Options::operator[](const std::string &name) const { return it->second; } -template <> void Options::assign(bool val, const std::string source) { - if (val) { - _set("true", source, false); - } else { - _set("false", source, false); - } -} - -template <> void Options::assign(BoutReal val, const std::string source) { - std::stringstream ss; - // Make sure the precision is large enough to hold a BoutReal - ss << std::scientific << std::setprecision(17) << val; - _set(ss.str(), source, false); -} - -void Options::_set(std::string val, std::string source, bool force) { - if (isSet()) { - // Check if current value the same as new value - if (value.value != val) { - if (force or value.source != source) { - output_warn << _("\tOption ") << full_name << " = " << value.value << " (" - << value.source << _(") overwritten with:") - << "\n" - << "\t\t" << full_name << " = " << val << " (" << source << ")\n"; - } else { - throw BoutException(_("Options: Setting a value from same source (%s) to new value " - "'%s' - old value was '%s'."), - source.c_str(), val.c_str(), value.value.c_str()); - } - } - } - - value.value = std::move(val); - value.source = std::move(source); - value.used = false; - is_value = true; -} - bool Options::isSet() const { // Check if no value if (!is_value) { From bc521ccf49024db696f5719b05862a57b5d39780 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 10 Dec 2018 00:04:30 +0000 Subject: [PATCH 0410/1783] Change Options to use std::variant Options stores values as bool/int/BoutReal/string rather than only strings. This could be extended so that Options stored Field2D/Field3D etc. Variant utility code in bout/src/variant.hxx Imports std::variant etc. into namespace bout::utils For now needs C++17, but this should allow a different implementation to be used for C++11 compatibility. --- include/bout/sys/variant.hxx | 145 ++++++++++++++++++++++++++++ include/options.hxx | 127 ++++++++++++------------ make.config.in | 2 +- src/sys/options.cxx | 181 ++++++++++++++++++++++------------- 4 files changed, 328 insertions(+), 127 deletions(-) create mode 100644 include/bout/sys/variant.hxx diff --git a/include/bout/sys/variant.hxx b/include/bout/sys/variant.hxx new file mode 100644 index 0000000000..309c5a3e9e --- /dev/null +++ b/include/bout/sys/variant.hxx @@ -0,0 +1,145 @@ +/// +/// Variant utilities +/// +/// All in namespace bout::utils +/// variant +/// visit +/// holds_alternative +/// get +/// +/// variantEqualTo +/// variantStaticCastOrThrow +/// variantToString +/// +/// Internal implementation in bout::utils::details + +#pragma once + +#ifndef __VARIANT_HXX__ +#define __VARIANT_HXX__ + +#include + +#include "utils.hxx" + +namespace bout { +namespace utils { + +/// Import variant, visit into bout::utils namespace +using std::variant; +using std::visit; +using std::holds_alternative; +using std::get; + +//////////////////////////////////////////////////////////// +// Variant comparison + +namespace details { + +/// Compare two values. +/// Different types -> false +template +struct CompareTypes { + bool operator()(const T& UNUSED(v), const U& UNUSED(t)) { return false; } +}; + +/// Compare two values +/// Same type -> use `==` operator to compare +template +struct CompareTypes { + bool operator()(const T& v, const T& t) { return v == t; } +}; + +/// A visitor for std::variant which compares +/// the value stored in the variant with a given value using CompareTypes +template +struct IsEqual { + const T& t; + IsEqual(const T& t) : t(t) {} + + template + bool operator()(const U& u) { + return CompareTypes()(t, u); + } +}; +} // namespace details + +/// Return true only if the given variant \p v +/// has the same type and value as \p t +/// +/// Note: Handles the case that \p t is not of a type +/// which \v can hold. +template +bool variantEqualTo(const Variant& v, const T& t) { + return visit(details::IsEqual(t), v); +} + +//////////////////////////////////////////////////////////// +// Variant casting + +namespace details { + +/// Helper class for casting between two types +/// The general case is that casting can't be done +/// +/// Note: This must be a class/struct because partial +/// specialisation is not allowed for functions +template +struct _StaticCastOrThrow { + Target operator()(Source&& UNUSED(source)) { throw std::bad_cast{}; } +}; + +/// Specialised case (bool = true) +/// This version is used when casting can be done +template +struct _StaticCastOrThrow { + Target operator()(Source&& source) { + return static_cast(std::forward(source)); + } +}; + +/// Functor to perform static casting with std::visit +/// If the Target cannot be constructed from the Source +/// then an exception (std::bad_cast) will be thrown at run time. +/// +/// Note: This needs to be at runtime because the particular +/// type which a variant is holding is only known at runtime. +template +struct StaticCastOrThrow { + template + Target operator()(Source&& source) const { + return _StaticCastOrThrow::value>()( + std::forward(source)); + } +}; +} // namespace details + +/// Cast a variant to a given type using static_cast +/// If this can't be done then a std::bad_cast exception is thrown +/// +/// Note: \p T can be a type which variant \v cannot hold +/// in which case std::bad_cast will be thrown at runtime +template +T variantStaticCastOrThrow(const Variant &v) { + std::visit( details::StaticCastOrThrow(), v ); +} + +namespace details { + +struct ToString { + template + std::string operator()(T&& val) { + return toString(std::forward(val)); + } +}; + +} // namespace details + +template +std::string variantToString(const Variant& v) { return visit(details::ToString(), v); } + +} // namespace utils +} // namespace bout + +#endif //__VARIANT_HXX__ diff --git a/include/options.hxx b/include/options.hxx index 93b9e09337..3b1a17b253 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -43,6 +43,7 @@ class Options; #include "unused.hxx" #include "output.hxx" #include "utils.hxx" +#include "bout/sys/variant.hxx" #include #include @@ -158,13 +159,23 @@ public: /// @param[in] sectionName Name of the section, including path from the root Options(Options *parent_instance, std::string full_name) : parent_instance(parent_instance), full_name(std::move(full_name)){}; - + /// Get a reference to the only root instance static Options &root(); /// Free all memory static void cleanup(); + /// The type used to store values + using ValueType = bout::utils::variant; + /// The type used to store attributes + using AttributeType = bout::utils::variant; + + /// The value stored + ValueType value; + /// A collection of attributes belonging to the value + std::map attributes; + /// Get a sub-section or value /// /// Example: @@ -209,14 +220,6 @@ public: ss << val; _set(ss.str(), source, false); } - - // Specialised assign methods for types stored in ValueType - template<> void assign<>(bool val, const std::string source) { _set(val, source, false); } - template<> void assign<>(int val, const std::string source) { _set(val, source, false); } - template<> void assign<>(BoutReal val, const std::string source) { _set(val, source, false); } - template<> void assign<>(std::string val, const std::string source) { _set(val, source, false); } - // Note: const char* version needed to avoid conversion to bool - template<> void assign<>(const char *val, const std::string source) { _set(std::string(val), source, false);} /// Force to a value /// Overwrites any existing setting @@ -258,41 +261,48 @@ public: if (!is_value) { throw BoutException("Option %s has no value", full_name.c_str()); } - + T val; - if (std::holds_alternative(value)) { - - std::stringstream ss(std::get(value)); - ss >> val; + // Try casting. This will throw std::bad_cast if it can't be done + try { + val = bout::utils::variantStaticCastOrThrow(value); + } catch (const std::bad_cast &e) { + // If the variant is a string then we may be able to parse it - // Check if the parse failed - if (ss.fail()) { - throw BoutException("Option %s could not be parsed ('%s')", full_name.c_str(), value.value.c_str()); - } - - // Check if there are characters remaining - std::string remainder; - std::getline(ss, remainder); - for (const char &ch : remainder) { - if (!std::isspace(static_cast(ch))) { - // Meaningful character not parsed - throw BoutException("Option %s could not be parsed", full_name.c_str()); + if (bout::utils::holds_alternative(value)) { + std::stringstream ss(bout::utils::get(value)); + ss >> val; + + // Check if the parse failed + if (ss.fail()) { + throw BoutException("Option %s could not be parsed ('%s')", full_name.c_str(), + bout::utils::variantToString(value).c_str()); + } + + // Check if there are characters remaining + std::string remainder; + std::getline(ss, remainder); + for (const char &ch : remainder) { + if (!std::isspace(static_cast(ch))) { + // Meaningful character not parsed + throw BoutException("Option %s could not be parsed", full_name.c_str()); + } } + } else { + // Another type which can't be casted + throw BoutException("Option %s could not be converted to type %s", + full_name.c_str(), typeid(T).name()); } - } else { - // Value not holding a string. Try casting to the requested type - - val = std::visit( StaticCast(), value ); } // Mark this option as used - attributes["used"] = true; // Note this is mutable + value_used = true; // Note this is mutable output_info << "\tOption " << full_name << " = " << val; - if (!attributes["source"].empty()) { + if (attributes.count("source")) { // Specify the source of the setting - output_info << " (" << attributes["source"] << ")"; + output_info << " (" << bout::utils::variantToString(attributes.at("source")) << ")"; } output_info << endl; @@ -305,7 +315,7 @@ public: if (!is_value) { // Option not found assign(def, DEFAULT_SOURCE); - value.used = true; // Mark the option as used + value_used = true; // Mark the option as used output_info << _("\tOption ") << full_name << " = " << def << " (" << DEFAULT_SOURCE << ")" << std::endl; @@ -313,11 +323,11 @@ public: } T val = as(); // Check if this was previously set as a default option - if (value.source == DEFAULT_SOURCE) { + if (bout::utils::variantEqualTo(attributes.at("source"), DEFAULT_SOURCE)) { // Check that the default values are the same if (!similar(val, def)) { throw BoutException("Inconsistent default values for '%s': '%s' then '%s'", - full_name.c_str(), value.value.c_str(), toString(def).c_str()); + full_name.c_str(), bout::utils::variantToString(value).c_str(), toString(def).c_str()); } } return val; @@ -334,11 +344,11 @@ public: } T val = as(); // Check if this was previously set as a default option - if (value.source == DEFAULT_SOURCE) { + if (bout::utils::variantEqualTo(attributes.at("source"), DEFAULT_SOURCE)) { // Check that the default values are the same if (!similar(val, def)) { throw BoutException("Inconsistent default values for '%s': '%s' then '%s'", - full_name.c_str(), value.value.c_str(), toString(def).c_str()); + full_name.c_str(), bout::utils::variantToString(value).c_str(), toString(def).c_str()); } } return val; @@ -414,12 +424,6 @@ public: /// clean the cache of parsed options static void cleanCache(); - - using ValueType = std::variant; - using AttributeType = std::variant; - - ValueType value; - std::map attributes; /*! * Class used to store values, together with @@ -452,45 +456,48 @@ public: std::map children; ///< If a section then has children bool is_value = false; ///< Is this Options object a value? - + mutable bool value_used = false; ///< Record whether this value is used + template void _set(T val, std::string source, bool force) { if (isSet()) { // Check if current value the same as new value - if (value != val) { - if (force or attributes["source"] != source) { - output_warn << _("\tOption ") << full_name << " = " << toString(value) << " (" - << attributes["source"] << _(") overwritten with:") << "\n" + if (!bout::utils::variantEqualTo(value, val)) { + if (force or !bout::utils::variantEqualTo(attributes["source"], source)) { + output_warn << _("\tOption ") << full_name << " = " + << bout::utils::variantToString(value) << " (" + << bout::utils::variantToString(attributes["source"]) + << _(") overwritten with:") << "\n" << "\t\t" << full_name << " = " << toString(val) << " (" << source << ")\n"; } else { throw BoutException( _("Options: Setting a value from same source (%s) to new value " "'%s' - old value was '%s'."), - source.c_str(), toString(val).c_str(), toString(value).c_str()); + source.c_str(), toString(val).c_str(), + bout::utils::variantToString(value).c_str()); } } } value = std::move(val); attributes["source"] = std::move(source); - attributes["used"] = false; + value_used = false; is_value = true; } /// Tests if two values are similar. template bool similar(T a, T b) const { return a == b; } - - /// Functor to perform static casting with std::visit - /// from https://stackoverflow.com/questions/8806453/functor-version-of-static-cast-in-stdbind - template struct StaticCast { - template Target operator()(Source &&source) const { - return static_cast(std::forward(source)); - } - }; - }; +// Specialised assign methods for types stored in ValueType +template<> inline void Options::assign<>(bool val, const std::string source) { _set(val, source, false); } +template<> inline void Options::assign<>(int val, const std::string source) { _set(val, source, false); } +template<> inline void Options::assign<>(BoutReal val, const std::string source) { _set(val, source, false); } +template<> inline void Options::assign<>(std::string val, const std::string source) { _set(val, source, false); } +// Note: const char* version needed to avoid conversion to bool +template<> inline void Options::assign<>(const char *val, const std::string source) { _set(std::string(val), source, false);} + /// Specialised similar comparison methods template <> inline bool Options::similar(BoutReal a, BoutReal b) const { return fabs(a - b) < 1e-10; } diff --git a/make.config.in b/make.config.in index 4fee8499e3..d32fcd0d72 100644 --- a/make.config.in +++ b/make.config.in @@ -39,7 +39,7 @@ BOUT_LOCALE_PATH=@localedir@ # Created this variable so that a user won't overwrite the CXXFLAGS variable # on the command line, just add to this one -BOUT_FLAGS = $(CXXFLAGS) @CXXFLAGS@ @OPENMP_CXXFLAGS@ @CXX11_FLAGS@ @COVERAGE_FLAGS@ +BOUT_FLAGS = -std=c++17 $(CXXFLAGS) @CXXFLAGS@ @OPENMP_CXXFLAGS@ @CXX11_FLAGS@ @COVERAGE_FLAGS@ #Use := here to force a "static" evaluation of the current state of BOUT_FLAGS to #avoid infinite recursion that would arise if BOUT_FLAGS appeared on both sides of = BOUT_FLAGS := $(BOUT_FLAGS) -DBOUT_FLAGS_STRING="$(BOUT_FLAGS)" diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 72d668da8d..3cd051046b 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -80,7 +80,7 @@ bool Options::isSet() const { } // Ignore if set from default - if (value.source == DEFAULT_SOURCE) { + if (bout::utils::variantEqualTo(attributes.at("source"), DEFAULT_SOURCE)) { return false; } @@ -93,16 +93,18 @@ template <> std::string Options::as() const { } // Mark this option as used - value.used = true; + value_used = true; - output_info << _("\tOption ") << full_name << " = " << value.value; - if (!value.source.empty()) { + std::string result = bout::utils::variantToString(value); + + output_info << _("\tOption ") << full_name << " = " << result; + if (attributes.count("source")) { // Specify the source of the setting - output_info << " (" << value.source << ")"; + output_info << " (" << bout::utils::variantToString(attributes.at("source")) << ")"; } output_info << endl; - return value.value; + return result; } template <> int Options::as() const { @@ -110,35 +112,54 @@ template <> int Options::as() const { throw BoutException(_("Option %s has no value"), full_name.c_str()); } - // Use FieldFactory to evaluate expression - // Parse the string, giving this Option pointer for the context - // then generate a value at t,x,y,z = 0,0,0,0 - auto gen = FieldFactory::get()->parse(value.value, this); - if (!gen) { - throw BoutException(_("Couldn't get integer from option %s = '%s'"), full_name.c_str(), - value.value.c_str()); - } - BoutReal rval = gen->generate(0, 0, 0, 0); - - // Convert to int by rounding - int val = ROUND(rval); + int result; - // Check that the value is close to an integer - if (fabs(rval - static_cast(val)) > 1e-3) { - throw BoutException(_("Value for option %s = %e is not an integer"), - full_name.c_str(), rval); + if (std::holds_alternative(value)) { + result = std::get(value); + + } else { + // Cases which get a BoutReal then check if close to an integer + BoutReal rval; + + if (std::holds_alternative(value)) { + rval = std::get(value); + + } else if (std::holds_alternative(value)) { + // Use FieldFactory to evaluate expression + // Parse the string, giving this Option pointer for the context + // then generate a value at t,x,y,z = 0,0,0,0 + auto gen = FieldFactory::get()->parse(std::get(value), this); + if (!gen) { + throw BoutException(_("Couldn't get integer from option %s = '%s'"), + full_name.c_str(), bout::utils::variantToString(value).c_str()); + } + rval = gen->generate(0, 0, 0, 0); + } else { + // Another type which can't be converted + throw BoutException(_("Value for option %s is not an integer"), + full_name.c_str()); + } + + // Convert to int by rounding + result = ROUND(rval); + + // Check that the value is close to an integer + if (fabs(rval - static_cast(result)) > 1e-3) { + throw BoutException(_("Value for option %s = %e is not an integer"), + full_name.c_str(), rval); + } } - value.used = true; + value_used = true; - output_info << _("\tOption ") << full_name << " = " << val; - if (!value.source.empty()) { + output_info << _("\tOption ") << full_name << " = " << result; + if (attributes.count("source")) { // Specify the source of the setting - output_info << " (" << value.source << ")"; + output_info << " (" << bout::utils::variantToString(attributes.at("source")) << ")"; } output_info << endl; - return val; + return result; } template <> BoutReal Options::as() const { @@ -146,62 +167,88 @@ template <> BoutReal Options::as() const { throw BoutException(_("Option %s has no value"), full_name.c_str()); } - // Use FieldFactory to evaluate expression - // Parse the string, giving this Option pointer for the context - // then generate a value at t,x,y,z = 0,0,0,0 - std::shared_ptr gen = FieldFactory::get()->parse(value.value, this); - if (!gen) { - throw BoutException(_("Couldn't get BoutReal from option %s = '%s'"), full_name.c_str(), - value.value.c_str()); + BoutReal result; + + if (std::holds_alternative(value)) { + result = static_cast(std::get(value)); + + } else if (std::holds_alternative(value)) { + result = std::get(value); + + } else if (std::holds_alternative(value)) { + + // Use FieldFactory to evaluate expression + // Parse the string, giving this Option pointer for the context + // then generate a value at t,x,y,z = 0,0,0,0 + std::shared_ptr gen = FieldFactory::get()->parse(std::get(value), this); + if (!gen) { + throw BoutException(_("Couldn't get BoutReal from option %s = '%s'"), full_name.c_str(), + std::get(value).c_str()); + } + result = gen->generate(0, 0, 0, 0); + } else { + throw BoutException(_("Value for option %s cannot be converted to a BoutReal"), + full_name.c_str()); } - BoutReal val = gen->generate(0, 0, 0, 0); - + // Mark this option as used - value.used = true; - - output_info << _("\tOption ") << full_name << " = " << val; - if (!value.source.empty()) { + value_used = true; + + output_info << _("\tOption ") << full_name << " = " << result; + if (attributes.count("source")) { // Specify the source of the setting - output_info << " (" << value.source << ")"; + output_info << " (" << bout::utils::variantToString(attributes.at("source")) << ")"; } output_info << endl; - - return val; + + return result; } template <> bool Options::as() const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); } - - value.used = true; - - bool val; - char c = static_cast(toupper((value.value)[0])); - if ((c == 'Y') || (c == 'T') || (c == '1')) { - val = true; - output_info << _("\tOption ") << full_name << " = true"; - } else if ((c == 'N') || (c == 'F') || (c == '0')) { - val = false; - output_info << _("\tOption ") << full_name << " = false"; + + bool result; + + if (std::holds_alternative(value)) { + result = std::get(value); + + } else if(std::holds_alternative(value)) { + std::string strvalue = std::get(value); + + char c = static_cast(toupper((strvalue)[0])); + if ((c == 'Y') || (c == 'T') || (c == '1')) { + result = true; + } else if ((c == 'N') || (c == 'F') || (c == '0')) { + result = false; + } else { + throw BoutException(_("\tOption '%s': Boolean expected. Got '%s'\n"), full_name.c_str(), + strvalue.c_str()); + } } else { - throw BoutException(_("\tOption '%s': Boolean expected. Got '%s'\n"), full_name.c_str(), - value.value.c_str()); + throw BoutException(_("Value for option %s cannot be converted to a bool"), + full_name.c_str()); } - if (!value.source.empty()) { + + value_used = true; + + output_info << _("\tOption ") << full_name << " = " << toString(result); + + if (attributes.count("source")) { // Specify the source of the setting - output_info << " (" << value.source << ")"; + output_info << " (" << bout::utils::variantToString(attributes.at("source")) << ")"; } output_info << endl; - return val; + return result; } void Options::printUnused() const { bool allused = true; // Check if any options are unused for (const auto &it : children) { - if (it.second.is_value && !it.second.value.used) { + if (it.second.is_value && !it.second.value_used) { allused = false; break; } @@ -211,11 +258,11 @@ void Options::printUnused() const { } else { output_info << _("Unused options:\n"); for (const auto &it : children) { - if (it.second.is_value && !it.second.value.used) { + if (it.second.is_value && !it.second.value_used) { output_info << "\t" << full_name << ":" << it.first << " = " - << it.second.value.value; - if (!it.second.value.source.empty()) - output_info << " (" << it.second.value.source << ")"; + << bout::utils::variantToString(it.second.value); + if (it.second.attributes.count("source")) + output_info << " (" << bout::utils::variantToString(it.second.attributes.at("source")) << ")"; output_info << endl; } } @@ -231,9 +278,11 @@ void Options::cleanCache() { FieldFactory::get()->cleanCache(); } std::map Options::values() const { std::map options; - for (const auto &it : children) { + for (const auto& it : children) { if (it.second.is_value) { - options[it.first] = it.second.value; + options.emplace(it.first, OptionValue{ bout::utils::variantToString(it.second.value), + bout::utils::variantToString(it.second.attributes.at("source")), + it.second.value_used}); } } return options; From 40496cd39c1e0213a29cba602f4faa12cae189eb Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 10 Dec 2018 00:33:53 +0000 Subject: [PATCH 0411/1783] Revert change to toString unit test When toString was removed, forgot to go back to previous unit test. --- tests/unit/sys/test_utils.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/sys/test_utils.cxx b/tests/unit/sys/test_utils.cxx index e0c2a30c7d..710eea70e8 100644 --- a/tests/unit/sys/test_utils.cxx +++ b/tests/unit/sys/test_utils.cxx @@ -545,7 +545,7 @@ TEST(StringUtilitiesTest, IntToString) { TEST(StringUtilitiesTest, RealToString) { BoutReal number_real = 3.142e8; - std::string number_string = "3.14200000000000000e+08"; + std::string number_string = "3.142e+08"; EXPECT_EQ(number_string, toString(number_real)); } From 1475f0d3df2ec0ee5c0a043858461c36eb8baf87 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 10 Dec 2018 09:33:00 +0000 Subject: [PATCH 0412/1783] Adding mpark::variant Supplies std::variant for C++11 --- include/bout/sys/variant.hxx | 24 +- include/external/mpark/config.hpp | 79 ++ include/external/mpark/in_place.hpp | 35 + include/external/mpark/lib.hpp | 446 +++++++ include/external/mpark/variant.hpp | 1930 +++++++++++++++++++++++++++ make.config.in | 2 +- 6 files changed, 2508 insertions(+), 8 deletions(-) create mode 100644 include/external/mpark/config.hpp create mode 100644 include/external/mpark/in_place.hpp create mode 100644 include/external/mpark/lib.hpp create mode 100644 include/external/mpark/variant.hpp diff --git a/include/bout/sys/variant.hxx b/include/bout/sys/variant.hxx index 309c5a3e9e..0ffcb3c51e 100644 --- a/include/bout/sys/variant.hxx +++ b/include/bout/sys/variant.hxx @@ -18,7 +18,10 @@ #ifndef __VARIANT_HXX__ #define __VARIANT_HXX__ -#include +// std::variant added in C++17 +//#include + +#include "external/mpark/variant.hpp" #include "utils.hxx" @@ -26,11 +29,18 @@ namespace bout { namespace utils { /// Import variant, visit into bout::utils namespace -using std::variant; -using std::visit; -using std::holds_alternative; -using std::get; +// From C++17 +// using std::variant; +// using std::visit; +// using std::holds_alternative; +// using std::get; + +using mpark::variant; +using mpark::visit; +using mpark::holds_alternative; +using mpark::get; + //////////////////////////////////////////////////////////// // Variant comparison @@ -71,7 +81,7 @@ struct IsEqual { /// which \v can hold. template bool variantEqualTo(const Variant& v, const T& t) { - return visit(details::IsEqual(t), v); + return visit(details::IsEqual(t), v); } //////////////////////////////////////////////////////////// @@ -122,7 +132,7 @@ struct StaticCastOrThrow { /// in which case std::bad_cast will be thrown at runtime template T variantStaticCastOrThrow(const Variant &v) { - std::visit( details::StaticCastOrThrow(), v ); + visit( details::StaticCastOrThrow(), v ); } namespace details { diff --git a/include/external/mpark/config.hpp b/include/external/mpark/config.hpp new file mode 100644 index 0000000000..4c93412f4b --- /dev/null +++ b/include/external/mpark/config.hpp @@ -0,0 +1,79 @@ +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_CONFIG_HPP +#define MPARK_CONFIG_HPP + +// MSVC 2015 Update 3. +#if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) +#error "MPark.Variant requires C++11 support." +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#ifndef __has_include +#define __has_include(x) 0 +#endif + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#if __has_builtin(__builtin_addressof) || \ + (defined(__GNUC__) && __GNUC__ >= 7) || defined(_MSC_VER) +#define MPARK_BUILTIN_ADDRESSOF +#endif + +#if __has_builtin(__builtin_unreachable) +#define MPARK_BUILTIN_UNREACHABLE __builtin_unreachable() +#elif defined(_MSC_VER) +#define MPARK_BUILTIN_UNREACHABLE __assume(false) +#else +#define MPARK_BUILTIN_UNREACHABLE +#endif + +#if __has_builtin(__type_pack_element) +#define MPARK_TYPE_PACK_ELEMENT +#endif + +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 && \ + !(defined(_MSC_VER) && _MSC_VER <= 1915) +#define MPARK_CPP14_CONSTEXPR +#endif + +#if __has_feature(cxx_exceptions) || defined(__cpp_exceptions) || \ + (defined(_MSC_VER) && defined(_CPPUNWIND)) +#define MPARK_EXCEPTIONS +#endif + +#if defined(__cpp_generic_lambdas) || defined(_MSC_VER) +#define MPARK_GENERIC_LAMBDAS +#endif + +#if defined(__cpp_lib_integer_sequence) +#define MPARK_INTEGER_SEQUENCE +#endif + +#if defined(__cpp_return_type_deduction) || defined(_MSC_VER) +#define MPARK_RETURN_TYPE_DEDUCTION +#endif + +#if defined(__cpp_lib_transparent_operators) || defined(_MSC_VER) +#define MPARK_TRANSPARENT_OPERATORS +#endif + +#if defined(__cpp_variable_templates) || defined(_MSC_VER) +#define MPARK_VARIABLE_TEMPLATES +#endif + +#if !defined(__GLIBCXX__) || __has_include() // >= libstdc++-5 +#define MPARK_TRIVIALITY_TYPE_TRAITS +#endif + +#endif // MPARK_CONFIG_HPP diff --git a/include/external/mpark/in_place.hpp b/include/external/mpark/in_place.hpp new file mode 100644 index 0000000000..56cae13113 --- /dev/null +++ b/include/external/mpark/in_place.hpp @@ -0,0 +1,35 @@ +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_IN_PLACE_HPP +#define MPARK_IN_PLACE_HPP + +#include + +#include "config.hpp" + +namespace mpark { + + struct in_place_t { explicit in_place_t() = default; }; + + template + struct in_place_index_t { explicit in_place_index_t() = default; }; + + template + struct in_place_type_t { explicit in_place_type_t() = default; }; + +#ifdef MPARK_VARIABLE_TEMPLATES + constexpr in_place_t in_place{}; + + template constexpr in_place_index_t in_place_index{}; + + template constexpr in_place_type_t in_place_type{}; +#endif + +} // namespace mpark + +#endif // MPARK_IN_PLACE_HPP diff --git a/include/external/mpark/lib.hpp b/include/external/mpark/lib.hpp new file mode 100644 index 0000000000..81ffabf289 --- /dev/null +++ b/include/external/mpark/lib.hpp @@ -0,0 +1,446 @@ +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_LIB_HPP +#define MPARK_LIB_HPP + +#include +#include +#include +#include + +#include "config.hpp" + +#define MPARK_RETURN(...) -> decltype(__VA_ARGS__) { return __VA_ARGS__; } + +namespace mpark { + namespace lib { + template + struct identity { using type = T; }; + + inline namespace cpp14 { + template + struct array { + constexpr const T &operator[](std::size_t index) const { + return data[index]; + } + + T data[N == 0 ? 1 : N]; + }; + + template + using add_pointer_t = typename std::add_pointer::type; + + template + using common_type_t = typename std::common_type::type; + + template + using decay_t = typename std::decay::type; + + template + using enable_if_t = typename std::enable_if::type; + + template + using remove_const_t = typename std::remove_const::type; + + template + using remove_reference_t = typename std::remove_reference::type; + + template + inline constexpr T &&forward(remove_reference_t &t) noexcept { + return static_cast(t); + } + + template + inline constexpr T &&forward(remove_reference_t &&t) noexcept { + static_assert(!std::is_lvalue_reference::value, + "can not forward an rvalue as an lvalue"); + return static_cast(t); + } + + template + inline constexpr remove_reference_t &&move(T &&t) noexcept { + return static_cast &&>(t); + } + +#ifdef MPARK_INTEGER_SEQUENCE + using std::integer_sequence; + using std::index_sequence; + using std::make_index_sequence; + using std::index_sequence_for; +#else + template + struct integer_sequence { + using value_type = T; + static constexpr std::size_t size() noexcept { return sizeof...(Is); } + }; + + template + using index_sequence = integer_sequence; + + template + struct make_index_sequence_concat; + + template + struct make_index_sequence_concat, + index_sequence> + : identity> {}; + + template + struct make_index_sequence_impl; + + template + using make_index_sequence = typename make_index_sequence_impl::type; + + template + struct make_index_sequence_impl + : make_index_sequence_concat, + make_index_sequence> {}; + + template <> + struct make_index_sequence_impl<0> : identity> {}; + + template <> + struct make_index_sequence_impl<1> : identity> {}; + + template + using index_sequence_for = make_index_sequence; +#endif + + // +#ifdef MPARK_TRANSPARENT_OPERATORS + using equal_to = std::equal_to<>; +#else + struct equal_to { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward(lhs) == lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using not_equal_to = std::not_equal_to<>; +#else + struct not_equal_to { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward(lhs) != lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using less = std::less<>; +#else + struct less { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward(lhs) < lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using greater = std::greater<>; +#else + struct greater { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward(lhs) > lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using less_equal = std::less_equal<>; +#else + struct less_equal { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward(lhs) <= lib::forward(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using greater_equal = std::greater_equal<>; +#else + struct greater_equal { + template + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward(lhs) >= lib::forward(rhs)) + }; +#endif + } // namespace cpp14 + + inline namespace cpp17 { + + // + template + using bool_constant = std::integral_constant; + + template + struct voider : identity {}; + + template + using void_t = typename voider::type; + + namespace detail { + namespace swappable { + + using std::swap; + + template + struct is_swappable { + private: + template (), + std::declval()))> + inline static std::true_type test(int); + + template + inline static std::false_type test(...); + + public: + static constexpr bool value = decltype(test(0))::value; + }; + + template ::value> + struct is_nothrow_swappable { +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnoexcept" +#endif + static constexpr bool value = + noexcept(swap(std::declval(), std::declval())); +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + }; + + template + struct is_nothrow_swappable : std::false_type {}; + + } // namespace swappable + } // namespace detail + + using detail::swappable::is_swappable; + using detail::swappable::is_nothrow_swappable; + + // +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + template + inline constexpr auto invoke(F &&f, As &&... as) + MPARK_RETURN(lib::forward(f)(lib::forward(as)...)) +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + template + inline constexpr auto invoke(T B::*pmv, D &&d) + MPARK_RETURN(lib::forward(d).*pmv) + + template + inline constexpr auto invoke(Pmv pmv, Ptr &&ptr) + MPARK_RETURN((*lib::forward(ptr)).*pmv) + + template + inline constexpr auto invoke(T B::*pmf, D &&d, As &&... as) + MPARK_RETURN((lib::forward(d).*pmf)(lib::forward(as)...)) + + template + inline constexpr auto invoke(Pmf pmf, Ptr &&ptr, As &&... as) + MPARK_RETURN(((*lib::forward(ptr)).*pmf)(lib::forward(as)...)) + + namespace detail { + + template + struct invoke_result {}; + + template + struct invoke_result(), std::declval()...))>, + F, + Args...> + : identity(), std::declval()...))> {}; + + } // namespace detail + + template + using invoke_result = detail::invoke_result; + + template + using invoke_result_t = typename invoke_result::type; + + namespace detail { + + template + struct is_invocable : std::false_type {}; + + template + struct is_invocable>, F, Args...> + : std::true_type {}; + + template + struct is_invocable_r : std::false_type {}; + + template + struct is_invocable_r>, + R, + F, + Args...> + : std::is_convertible, R> {}; + + } // namespace detail + + template + using is_invocable = detail::is_invocable; + + template + using is_invocable_r = detail::is_invocable_r; + + // +#ifdef MPARK_BUILTIN_ADDRESSOF + template + inline constexpr T *addressof(T &arg) noexcept { + return __builtin_addressof(arg); + } +#else + namespace detail { + + namespace has_addressof_impl { + + struct fail; + + template + inline fail operator&(T &&); + + template + inline static constexpr bool impl() { + return (std::is_class::value || std::is_union::value) && + !std::is_same()), fail>::value; + } + + } // namespace has_addressof_impl + + template + using has_addressof = bool_constant()>; + + template + inline constexpr T *addressof(T &arg, std::true_type) noexcept { + return std::addressof(arg); + } + + template + inline constexpr T *addressof(T &arg, std::false_type) noexcept { + return &arg; + } + + } // namespace detail + + template + inline constexpr T *addressof(T &arg) noexcept { + return detail::addressof(arg, detail::has_addressof{}); + } +#endif + + template + inline constexpr T *addressof(const T &&) = delete; + + } // namespace cpp17 + + template + struct remove_all_extents : identity {}; + + template + struct remove_all_extents> : remove_all_extents {}; + + template + using remove_all_extents_t = typename remove_all_extents::type; + + template + using size_constant = std::integral_constant; + + template + struct indexed_type : size_constant { using type = T; }; + + template + using all = std::is_same, + integer_sequence>; + +#ifdef MPARK_TYPE_PACK_ELEMENT + template + using type_pack_element_t = __type_pack_element; +#else + template + struct type_pack_element_impl { + private: + template + struct set; + + template + struct set> : indexed_type... {}; + + template + inline static std::enable_if impl(indexed_type); + + inline static std::enable_if impl(...); + + public: + using type = decltype(impl(set>{})); + }; + + template + using type_pack_element = typename type_pack_element_impl::type; + + template + using type_pack_element_t = typename type_pack_element::type; +#endif + +#ifdef MPARK_TRIVIALITY_TYPE_TRAITS + using std::is_trivially_copy_constructible; + using std::is_trivially_move_constructible; + using std::is_trivially_copy_assignable; + using std::is_trivially_move_assignable; +#else + template + struct is_trivially_copy_constructible + : bool_constant< + std::is_copy_constructible::value && __has_trivial_copy(T)> {}; + + template + struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {}; + + template + struct is_trivially_copy_assignable + : bool_constant< + std::is_copy_assignable::value && __has_trivial_assign(T)> {}; + + template + struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {}; +#endif + + template + struct dependent_type : T {}; + + template + struct push_back; + + template + using push_back_t = typename push_back::type; + + template + struct push_back, J> { + using type = index_sequence; + }; + + } // namespace lib +} // namespace mpark + +#undef MPARK_RETURN + +#endif // MPARK_LIB_HPP diff --git a/include/external/mpark/variant.hpp b/include/external/mpark/variant.hpp new file mode 100644 index 0000000000..bc7dd87d63 --- /dev/null +++ b/include/external/mpark/variant.hpp @@ -0,0 +1,1930 @@ +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_VARIANT_HPP +#define MPARK_VARIANT_HPP + +/* + variant synopsis + +namespace std { + + // 20.7.2, class template variant + template + class variant { + public: + + // 20.7.2.1, constructors + constexpr variant() noexcept(see below); + variant(const variant&); + variant(variant&&) noexcept(see below); + + template constexpr variant(T&&) noexcept(see below); + + template + constexpr explicit variant(in_place_type_t, Args&&...); + + template + constexpr explicit variant( + in_place_type_t, initializer_list, Args&&...); + + template + constexpr explicit variant(in_place_index_t, Args&&...); + + template + constexpr explicit variant( + in_place_index_t, initializer_list, Args&&...); + + // 20.7.2.2, destructor + ~variant(); + + // 20.7.2.3, assignment + variant& operator=(const variant&); + variant& operator=(variant&&) noexcept(see below); + + template variant& operator=(T&&) noexcept(see below); + + // 20.7.2.4, modifiers + template + T& emplace(Args&&...); + + template + T& emplace(initializer_list, Args&&...); + + template + variant_alternative& emplace(Args&&...); + + template + variant_alternative& emplace(initializer_list, Args&&...); + + // 20.7.2.5, value status + constexpr bool valueless_by_exception() const noexcept; + constexpr size_t index() const noexcept; + + // 20.7.2.6, swap + void swap(variant&) noexcept(see below); + }; + + // 20.7.3, variant helper classes + template struct variant_size; // undefined + + template + constexpr size_t variant_size_v = variant_size::value; + + template struct variant_size; + template struct variant_size; + template struct variant_size; + + template + struct variant_size>; + + template struct variant_alternative; // undefined + + template + using variant_alternative_t = typename variant_alternative::type; + + template struct variant_alternative; + template struct variant_alternative; + template struct variant_alternative; + + template + struct variant_alternative>; + + constexpr size_t variant_npos = -1; + + // 20.7.4, value access + template + constexpr bool holds_alternative(const variant&) noexcept; + + template + constexpr variant_alternative_t>& + get(variant&); + + template + constexpr variant_alternative_t>&& + get(variant&&); + + template + constexpr variant_alternative_t> const& + get(const variant&); + + template + constexpr variant_alternative_t> const&& + get(const variant&&); + + template + constexpr T& get(variant&); + + template + constexpr T&& get(variant&&); + + template + constexpr const T& get(const variant&); + + template + constexpr const T&& get(const variant&&); + + template + constexpr add_pointer_t>> + get_if(variant*) noexcept; + + template + constexpr add_pointer_t>> + get_if(const variant*) noexcept; + + template + constexpr add_pointer_t + get_if(variant*) noexcept; + + template + constexpr add_pointer_t + get_if(const variant*) noexcept; + + // 20.7.5, relational operators + template + constexpr bool operator==(const variant&, const variant&); + + template + constexpr bool operator!=(const variant&, const variant&); + + template + constexpr bool operator<(const variant&, const variant&); + + template + constexpr bool operator>(const variant&, const variant&); + + template + constexpr bool operator<=(const variant&, const variant&); + + template + constexpr bool operator>=(const variant&, const variant&); + + // 20.7.6, visitation + template + constexpr see below visit(Visitor&&, Variants&&...); + + // 20.7.7, class monostate + struct monostate; + + // 20.7.8, monostate relational operators + constexpr bool operator<(monostate, monostate) noexcept; + constexpr bool operator>(monostate, monostate) noexcept; + constexpr bool operator<=(monostate, monostate) noexcept; + constexpr bool operator>=(monostate, monostate) noexcept; + constexpr bool operator==(monostate, monostate) noexcept; + constexpr bool operator!=(monostate, monostate) noexcept; + + // 20.7.9, specialized algorithms + template + void swap(variant&, variant&) noexcept(see below); + + // 20.7.10, class bad_variant_access + class bad_variant_access; + + // 20.7.11, hash support + template struct hash; + template struct hash>; + template <> struct hash; + +} // namespace std + +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "config.hpp" +#include "in_place.hpp" +#include "lib.hpp" + +namespace mpark { + +#ifdef MPARK_RETURN_TYPE_DEDUCTION + +#define AUTO auto +#define AUTO_RETURN(...) { return __VA_ARGS__; } + +#define AUTO_REFREF auto && +#define AUTO_REFREF_RETURN(...) { return __VA_ARGS__; } + +#define DECLTYPE_AUTO decltype(auto) +#define DECLTYPE_AUTO_RETURN(...) { return __VA_ARGS__; } + +#else + +#define AUTO auto +#define AUTO_RETURN(...) \ + -> lib::decay_t { return __VA_ARGS__; } + +#define AUTO_REFREF auto +#define AUTO_REFREF_RETURN(...) \ + -> decltype((__VA_ARGS__)) { \ + static_assert(std::is_reference::value, ""); \ + return __VA_ARGS__; \ + } + +#define DECLTYPE_AUTO auto +#define DECLTYPE_AUTO_RETURN(...) \ + -> decltype(__VA_ARGS__) { return __VA_ARGS__; } + +#endif + + class bad_variant_access : public std::exception { + public: + virtual const char *what() const noexcept override { return "bad_variant_access"; } + }; + + [[noreturn]] inline void throw_bad_variant_access() { +#ifdef MPARK_EXCEPTIONS + throw bad_variant_access{}; +#else + std::terminate(); + MPARK_BUILTIN_UNREACHABLE; +#endif + } + + template + class variant; + + template + struct variant_size; + +#ifdef MPARK_VARIABLE_TEMPLATES + template + constexpr std::size_t variant_size_v = variant_size::value; +#endif + + template + struct variant_size : variant_size {}; + + template + struct variant_size : variant_size {}; + + template + struct variant_size : variant_size {}; + + template + struct variant_size> : lib::size_constant {}; + + template + struct variant_alternative; + + template + using variant_alternative_t = typename variant_alternative::type; + + template + struct variant_alternative + : std::add_const> {}; + + template + struct variant_alternative + : std::add_volatile> {}; + + template + struct variant_alternative + : std::add_cv> {}; + + template + struct variant_alternative> { + static_assert(I < sizeof...(Ts), + "index out of bounds in `std::variant_alternative<>`"); + using type = lib::type_pack_element_t; + }; + + constexpr std::size_t variant_npos = static_cast(-1); + + namespace detail { + + constexpr std::size_t not_found = static_cast(-1); + constexpr std::size_t ambiguous = static_cast(-2); + +#ifdef MPARK_CPP14_CONSTEXPR + template + inline constexpr std::size_t find_index() { + constexpr lib::array matches = { + {std::is_same::value...} + }; + std::size_t result = not_found; + for (std::size_t i = 0; i < sizeof...(Ts); ++i) { + if (matches[i]) { + if (result != not_found) { + return ambiguous; + } + result = i; + } + } + return result; + } +#else + inline constexpr std::size_t find_index_impl(std::size_t result, + std::size_t) { + return result; + } + + template + inline constexpr std::size_t find_index_impl(std::size_t result, + std::size_t idx, + bool b, + Bs... bs) { + return b ? (result != not_found ? ambiguous + : find_index_impl(idx, idx + 1, bs...)) + : find_index_impl(result, idx + 1, bs...); + } + + template + inline constexpr std::size_t find_index() { + return find_index_impl(not_found, 0, std::is_same::value...); + } +#endif + + template + using find_index_sfinae_impl = + lib::enable_if_t>; + + template + using find_index_sfinae = find_index_sfinae_impl()>; + + template + struct find_index_checked_impl : lib::size_constant { + static_assert(I != not_found, "the specified type is not found."); + static_assert(I != ambiguous, "the specified type is ambiguous."); + }; + + template + using find_index_checked = find_index_checked_impl()>; + + struct valueless_t {}; + + enum class Trait { TriviallyAvailable, Available, Unavailable }; + + template class IsTriviallyAvailable, + template class IsAvailable> + inline constexpr Trait trait() { + return IsTriviallyAvailable::value + ? Trait::TriviallyAvailable + : IsAvailable::value ? Trait::Available + : Trait::Unavailable; + } + +#ifdef MPARK_CPP14_CONSTEXPR + template + inline constexpr Trait common_trait(Traits... traits) { + Trait result = Trait::TriviallyAvailable; + for (Trait t : {traits...}) { + if (static_cast(t) > static_cast(result)) { + result = t; + } + } + return result; + } +#else + inline constexpr Trait common_trait_impl(Trait result) { return result; } + + template + inline constexpr Trait common_trait_impl(Trait result, + Trait t, + Traits... ts) { + return static_cast(t) > static_cast(result) + ? common_trait_impl(t, ts...) + : common_trait_impl(result, ts...); + } + + template + inline constexpr Trait common_trait(Traits... ts) { + return common_trait_impl(Trait::TriviallyAvailable, ts...); + } +#endif + + template + struct traits { + static constexpr Trait copy_constructible_trait = + common_trait(trait()...); + + static constexpr Trait move_constructible_trait = + common_trait(trait()...); + + static constexpr Trait copy_assignable_trait = + common_trait(copy_constructible_trait, + trait()...); + + static constexpr Trait move_assignable_trait = + common_trait(move_constructible_trait, + trait()...); + + static constexpr Trait destructible_trait = + common_trait(trait()...); + }; + + namespace access { + + struct recursive_union { +#ifdef MPARK_RETURN_TYPE_DEDUCTION + template + inline static constexpr auto &&get_alt(V &&v, in_place_index_t<0>) { + return lib::forward(v).head_; + } + + template + inline static constexpr auto &&get_alt(V &&v, in_place_index_t) { + return get_alt(lib::forward(v).tail_, in_place_index_t{}); + } +#else + template + struct get_alt_impl { + template + inline constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v).tail_)) + }; + + template + struct get_alt_impl<0, Dummy> { + template + inline constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN(lib::forward(v).head_) + }; + + template + inline static constexpr AUTO_REFREF get_alt(V &&v, in_place_index_t) + AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v))) +#endif + }; + + struct base { + template + inline static constexpr AUTO_REFREF get_alt(V &&v) + AUTO_REFREF_RETURN(recursive_union::get_alt( + data(lib::forward(v)), in_place_index_t{})) + }; + + struct variant { + template + inline static constexpr AUTO_REFREF get_alt(V &&v) + AUTO_REFREF_RETURN(base::get_alt(lib::forward(v).impl_)) + }; + + } // namespace access + + namespace visitation { + + struct base { + template + inline static constexpr const T &at(const T &elem) noexcept { + return elem; + } + + template + inline static constexpr const lib::remove_all_extents_t &at( + const lib::array &elems, std::size_t i, Is... is) noexcept { + return at(elems[i], is...); + } + + template + inline static constexpr int visit_visitor_return_type_check() { + static_assert(lib::all::value...>::value, + "`mpark::visit` requires the visitor to have a single " + "return type."); + return 0; + } + + template + inline static constexpr lib::array< + lib::common_type_t...>, + sizeof...(Fs)> + make_farray(Fs &&... fs) { + using result = lib::array...>, + sizeof...(Fs)>; + return visit_visitor_return_type_check...>(), + result{{lib::forward(fs)...}}; + } + + template + struct dispatcher { + template + struct impl { + inline static constexpr DECLTYPE_AUTO dispatch(F f, Vs... vs) + DECLTYPE_AUTO_RETURN(lib::invoke( + static_cast(f), + access::base::get_alt(static_cast(vs))...)) + }; + }; + + template + inline static constexpr AUTO make_dispatch(lib::index_sequence) + AUTO_RETURN(&dispatcher::template impl::dispatch) + + template + inline static constexpr AUTO make_fdiagonal_impl() + AUTO_RETURN(make_dispatch( + lib::index_sequence::value...>{})) + + template + inline static constexpr AUTO make_fdiagonal_impl( + lib::index_sequence) + AUTO_RETURN(make_farray(make_fdiagonal_impl()...)) + + template + inline static constexpr /* auto * */ auto make_fdiagonal() + -> decltype(make_fdiagonal_impl( + lib::make_index_sequence::size()>{})) { + static_assert(lib::all<(lib::decay_t::size() == + lib::decay_t::size())...>::value, + "all of the variants must be the same size."); + return make_fdiagonal_impl( + lib::make_index_sequence::size()>{}); + } + +#ifdef MPARK_RETURN_TYPE_DEDUCTION + template + inline static constexpr auto make_fmatrix_impl(Is is) { + return make_dispatch(is); + } + + template + inline static constexpr auto make_fmatrix_impl( + Is, lib::index_sequence, Ls... ls) { + return make_farray(make_fmatrix_impl( + lib::push_back_t{}, ls...)...); + } + + template + inline static constexpr auto make_fmatrix() { + return make_fmatrix_impl( + lib::index_sequence<>{}, + lib::make_index_sequence::size()>{}...); + } +#else + template + struct make_fmatrix_impl { + template + struct impl; + + template + struct impl { + inline constexpr AUTO operator()() const + AUTO_RETURN(make_dispatch(Is{})) + }; + + template + struct impl, Ls...> { + inline constexpr AUTO operator()() const + AUTO_RETURN( + make_farray(impl, Ls...>{}()...)) + }; + }; + + template + inline static constexpr AUTO make_fmatrix() + AUTO_RETURN( + typename make_fmatrix_impl::template impl< + lib::index_sequence<>, + lib::make_index_sequence::size()>...>{}()) +#endif + }; // namespace base + + template + using FDiagonal = decltype(base::make_fdiagonal()); + + template + struct fdiagonal { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4268) +#endif + static constexpr FDiagonal value = + base::make_fdiagonal(); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + + template + constexpr FDiagonal fdiagonal::value; + + template + using FMatrix = decltype(base::make_fmatrix()); + + template + struct fmatrix { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4268) +#endif + static constexpr FMatrix value = + base::make_fmatrix(); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + + template + constexpr FMatrix fmatrix::value; + + struct alt { + template + inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN(base::at( + fdiagonal(vs)))...>::value, + index)(lib::forward(visitor), + as_base(lib::forward(vs))...)) + + template + inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN(base::at( + fmatrix(vs)))...>::value, + vs.index()...)(lib::forward(visitor), + as_base(lib::forward(vs))...)) + }; + + struct variant { + private: + template + struct visit_exhaustive_visitor_check { + static_assert( + lib::is_invocable::value, + "`mpark::visit` requires the visitor to be exhaustive."); + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + inline constexpr DECLTYPE_AUTO operator()(Visitor &&visitor, + Values &&... values) const + DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward(visitor), + lib::forward(values)...)) +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + + template + struct value_visitor { + Visitor &&visitor_; + + template + inline constexpr DECLTYPE_AUTO operator()(Alts &&... alts) const + DECLTYPE_AUTO_RETURN( + visit_exhaustive_visitor_check< + Visitor, + decltype((lib::forward(alts).value))...>{}( + lib::forward(visitor_), + lib::forward(alts).value...)) + }; + + template + inline static constexpr AUTO make_value_visitor(Visitor &&visitor) + AUTO_RETURN(value_visitor{lib::forward(visitor)}) + + public: + template + inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + alt::visit_alt_at(index, + lib::forward(visitor), + lib::forward(vs).impl_...)) + + template + inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN(alt::visit_alt(lib::forward(visitor), + lib::forward(vs).impl_...)) + + template + inline static constexpr DECLTYPE_AUTO visit_value_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + visit_alt_at(index, + make_value_visitor(lib::forward(visitor)), + lib::forward(vs)...)) + + template + inline static constexpr DECLTYPE_AUTO visit_value(Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + visit_alt(make_value_visitor(lib::forward(visitor)), + lib::forward(vs)...)) + }; + + } // namespace visitation + + template + struct alt { + using value_type = T; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + template + inline explicit constexpr alt(in_place_t, Args &&... args) + : value(lib::forward(args)...) {} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + T value; + }; + + template + union recursive_union; + + template + union recursive_union {}; + +#define MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ + template \ + union recursive_union { \ + public: \ + inline explicit constexpr recursive_union(valueless_t) noexcept \ + : dummy_{} {} \ + \ + template \ + inline explicit constexpr recursive_union(in_place_index_t<0>, \ + Args &&... args) \ + : head_(in_place_t{}, lib::forward(args)...) {} \ + \ + template \ + inline explicit constexpr recursive_union(in_place_index_t, \ + Args &&... args) \ + : tail_(in_place_index_t{}, lib::forward(args)...) {} \ + \ + recursive_union(const recursive_union &) = default; \ + recursive_union(recursive_union &&) = default; \ + \ + destructor \ + \ + recursive_union &operator=(const recursive_union &) = default; \ + recursive_union &operator=(recursive_union &&) = default; \ + \ + private: \ + char dummy_; \ + alt head_; \ + recursive_union tail_; \ + \ + friend struct access::recursive_union; \ + } + + MPARK_VARIANT_RECURSIVE_UNION(Trait::TriviallyAvailable, + ~recursive_union() = default;); + MPARK_VARIANT_RECURSIVE_UNION(Trait::Available, + ~recursive_union() {}); + MPARK_VARIANT_RECURSIVE_UNION(Trait::Unavailable, + ~recursive_union() = delete;); + +#undef MPARK_VARIANT_RECURSIVE_UNION + + using index_t = unsigned int; + + template + class base { + public: + inline explicit constexpr base(valueless_t tag) noexcept + : data_(tag), index_(static_cast(-1)) {} + + template + inline explicit constexpr base(in_place_index_t, Args &&... args) + : data_(in_place_index_t{}, lib::forward(args)...), + index_(I) {} + + inline constexpr bool valueless_by_exception() const noexcept { + return index_ == static_cast(-1); + } + + inline constexpr std::size_t index() const noexcept { + return valueless_by_exception() ? variant_npos : index_; + } + + protected: + using data_t = recursive_union; + + friend inline constexpr base &as_base(base &b) { return b; } + friend inline constexpr const base &as_base(const base &b) { return b; } + friend inline constexpr base &&as_base(base &&b) { return lib::move(b); } + friend inline constexpr const base &&as_base(const base &&b) { return lib::move(b); } + + friend inline constexpr data_t &data(base &b) { return b.data_; } + friend inline constexpr const data_t &data(const base &b) { return b.data_; } + friend inline constexpr data_t &&data(base &&b) { return lib::move(b).data_; } + friend inline constexpr const data_t &&data(const base &&b) { return lib::move(b).data_; } + + inline static constexpr std::size_t size() { return sizeof...(Ts); } + + data_t data_; + index_t index_; + + friend struct access::base; + friend struct visitation::base; + }; + + struct dtor { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + template + inline void operator()(Alt &alt) const noexcept { alt.~Alt(); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + +#if defined(_MSC_VER) && _MSC_VER < 1910 +#define MPARK_INHERITING_CTOR(type, base) \ + template \ + inline explicit constexpr type(Args &&... args) \ + : base(lib::forward(args)...) {} +#else +#define MPARK_INHERITING_CTOR(type, base) using base::base; +#endif + + template + class destructor; + +#define MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ + template \ + class destructor, destructible_trait> \ + : public base { \ + using super = base; \ + \ + public: \ + MPARK_INHERITING_CTOR(destructor, super) \ + using super::operator=; \ + \ + destructor(const destructor &) = default; \ + destructor(destructor &&) = default; \ + definition \ + destructor &operator=(const destructor &) = default; \ + destructor &operator=(destructor &&) = default; \ + \ + protected: \ + destroy \ + } + + MPARK_VARIANT_DESTRUCTOR( + Trait::TriviallyAvailable, + ~destructor() = default;, + inline void destroy() noexcept { + this->index_ = static_cast(-1); + }); + + MPARK_VARIANT_DESTRUCTOR( + Trait::Available, + ~destructor() { destroy(); }, + inline void destroy() noexcept { + if (!this->valueless_by_exception()) { + visitation::alt::visit_alt(dtor{}, *this); + } + this->index_ = static_cast(-1); + }); + + MPARK_VARIANT_DESTRUCTOR( + Trait::Unavailable, + ~destructor() = delete;, + inline void destroy() noexcept = delete;); + +#undef MPARK_VARIANT_DESTRUCTOR + + template + class constructor : public destructor { + using super = destructor; + + public: + MPARK_INHERITING_CTOR(constructor, super) + using super::operator=; + + protected: +#ifndef MPARK_GENERIC_LAMBDAS + struct ctor { + template + inline void operator()(LhsAlt &lhs_alt, RhsAlt &&rhs_alt) const { + constructor::construct_alt(lhs_alt, + lib::forward(rhs_alt).value); + } + }; +#endif + + template + inline static T &construct_alt(alt &a, Args &&... args) { + ::new (static_cast(lib::addressof(a))) + alt(in_place_t{}, lib::forward(args)...); + return a.value; + } + + template + inline static void generic_construct(constructor &lhs, Rhs &&rhs) { + lhs.destroy(); + if (!rhs.valueless_by_exception()) { + visitation::alt::visit_alt_at( + rhs.index(), +#ifdef MPARK_GENERIC_LAMBDAS + [](auto &lhs_alt, auto &&rhs_alt) { + constructor::construct_alt( + lhs_alt, lib::forward(rhs_alt).value); + } +#else + ctor{} +#endif + , + lhs, + lib::forward(rhs)); + lhs.index_ = rhs.index_; + } + } + }; + + template + class move_constructor; + +#define MPARK_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, definition) \ + template \ + class move_constructor, move_constructible_trait> \ + : public constructor> { \ + using super = constructor>; \ + \ + public: \ + MPARK_INHERITING_CTOR(move_constructor, super) \ + using super::operator=; \ + \ + move_constructor(const move_constructor &) = default; \ + definition \ + ~move_constructor() = default; \ + move_constructor &operator=(const move_constructor &) = default; \ + move_constructor &operator=(move_constructor &&) = default; \ + } + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::TriviallyAvailable, + move_constructor(move_constructor &&that) = default;); + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::Available, + move_constructor(move_constructor &&that) noexcept( + lib::all::value...>::value) + : move_constructor(valueless_t{}) { + this->generic_construct(*this, lib::move(that)); + }); + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::Unavailable, + move_constructor(move_constructor &&) = delete;); + +#undef MPARK_VARIANT_MOVE_CONSTRUCTOR + + template + class copy_constructor; + +#define MPARK_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, definition) \ + template \ + class copy_constructor, copy_constructible_trait> \ + : public move_constructor> { \ + using super = move_constructor>; \ + \ + public: \ + MPARK_INHERITING_CTOR(copy_constructor, super) \ + using super::operator=; \ + \ + definition \ + copy_constructor(copy_constructor &&) = default; \ + ~copy_constructor() = default; \ + copy_constructor &operator=(const copy_constructor &) = default; \ + copy_constructor &operator=(copy_constructor &&) = default; \ + } + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::TriviallyAvailable, + copy_constructor(const copy_constructor &that) = default;); + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::Available, + copy_constructor(const copy_constructor &that) + : copy_constructor(valueless_t{}) { + this->generic_construct(*this, that); + }); + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::Unavailable, + copy_constructor(const copy_constructor &) = delete;); + +#undef MPARK_VARIANT_COPY_CONSTRUCTOR + + template + class assignment : public copy_constructor { + using super = copy_constructor; + + public: + MPARK_INHERITING_CTOR(assignment, super) + using super::operator=; + + template + inline /* auto & */ auto emplace(Args &&... args) + -> decltype(this->construct_alt(access::base::get_alt(*this), + lib::forward(args)...)) { + this->destroy(); + auto &result = this->construct_alt(access::base::get_alt(*this), + lib::forward(args)...); + this->index_ = I; + return result; + } + + protected: +#ifndef MPARK_GENERIC_LAMBDAS + template + struct assigner { + template + inline void operator()(ThisAlt &this_alt, ThatAlt &&that_alt) const { + self->assign_alt(this_alt, lib::forward(that_alt).value); + } + assignment *self; + }; +#endif + + template + inline void assign_alt(alt &a, Arg &&arg) { + if (this->index() == I) { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + a.value = lib::forward(arg); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } else { + struct { + void operator()(std::true_type) const { + this_->emplace(lib::forward(arg_)); + } + void operator()(std::false_type) const { + this_->emplace(T(lib::forward(arg_))); + } + assignment *this_; + Arg &&arg_; + } impl{this, lib::forward(arg)}; + impl(lib::bool_constant< + std::is_nothrow_constructible::value || + !std::is_nothrow_move_constructible::value>{}); + } + } + + template + inline void generic_assign(That &&that) { + if (this->valueless_by_exception() && that.valueless_by_exception()) { + // do nothing. + } else if (that.valueless_by_exception()) { + this->destroy(); + } else { + visitation::alt::visit_alt_at( + that.index(), +#ifdef MPARK_GENERIC_LAMBDAS + [this](auto &this_alt, auto &&that_alt) { + this->assign_alt( + this_alt, lib::forward(that_alt).value); + } +#else + assigner{this} +#endif + , + *this, + lib::forward(that)); + } + } + }; + + template + class move_assignment; + +#define MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ + template \ + class move_assignment, move_assignable_trait> \ + : public assignment> { \ + using super = assignment>; \ + \ + public: \ + MPARK_INHERITING_CTOR(move_assignment, super) \ + using super::operator=; \ + \ + move_assignment(const move_assignment &) = default; \ + move_assignment(move_assignment &&) = default; \ + ~move_assignment() = default; \ + move_assignment &operator=(const move_assignment &) = default; \ + definition \ + } + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::TriviallyAvailable, + move_assignment &operator=(move_assignment &&that) = default;); + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::Available, + move_assignment & + operator=(move_assignment &&that) noexcept( + lib::all<(std::is_nothrow_move_constructible::value && + std::is_nothrow_move_assignable::value)...>::value) { + this->generic_assign(lib::move(that)); + return *this; + }); + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::Unavailable, + move_assignment &operator=(move_assignment &&) = delete;); + +#undef MPARK_VARIANT_MOVE_ASSIGNMENT + + template + class copy_assignment; + +#define MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ + template \ + class copy_assignment, copy_assignable_trait> \ + : public move_assignment> { \ + using super = move_assignment>; \ + \ + public: \ + MPARK_INHERITING_CTOR(copy_assignment, super) \ + using super::operator=; \ + \ + copy_assignment(const copy_assignment &) = default; \ + copy_assignment(copy_assignment &&) = default; \ + ~copy_assignment() = default; \ + definition \ + copy_assignment &operator=(copy_assignment &&) = default; \ + } + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::TriviallyAvailable, + copy_assignment &operator=(const copy_assignment &that) = default;); + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::Available, + copy_assignment &operator=(const copy_assignment &that) { + this->generic_assign(that); + return *this; + }); + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::Unavailable, + copy_assignment &operator=(const copy_assignment &) = delete;); + +#undef MPARK_VARIANT_COPY_ASSIGNMENT + + template + class impl : public copy_assignment> { + using super = copy_assignment>; + + public: + MPARK_INHERITING_CTOR(impl, super) + using super::operator=; + + template + inline void assign(Arg &&arg) { + this->assign_alt(access::base::get_alt(*this), + lib::forward(arg)); + } + + inline void swap(impl &that) { + if (this->valueless_by_exception() && that.valueless_by_exception()) { + // do nothing. + } else if (this->index() == that.index()) { + visitation::alt::visit_alt_at(this->index(), +#ifdef MPARK_GENERIC_LAMBDAS + [](auto &this_alt, auto &that_alt) { + using std::swap; + swap(this_alt.value, + that_alt.value); + } +#else + swapper{} +#endif + , + *this, + that); + } else { + impl *lhs = this; + impl *rhs = lib::addressof(that); + if (lhs->move_nothrow() && !rhs->move_nothrow()) { + std::swap(lhs, rhs); + } + impl tmp(lib::move(*rhs)); +#ifdef MPARK_EXCEPTIONS + // EXTENSION: When the move construction of `lhs` into `rhs` throws + // and `tmp` is nothrow move constructible then we move `tmp` back + // into `rhs` and provide the strong exception safety guarantee. + try { + this->generic_construct(*rhs, lib::move(*lhs)); + } catch (...) { + if (tmp.move_nothrow()) { + this->generic_construct(*rhs, lib::move(tmp)); + } + throw; + } +#else + this->generic_construct(*rhs, lib::move(*lhs)); +#endif + this->generic_construct(*lhs, lib::move(tmp)); + } + } + + private: +#ifndef MPARK_GENERIC_LAMBDAS + struct swapper { + template + inline void operator()(ThisAlt &this_alt, ThatAlt &that_alt) const { + using std::swap; + swap(this_alt.value, that_alt.value); + } + }; +#endif + + inline constexpr bool move_nothrow() const { + return this->valueless_by_exception() || + lib::array{ + {std::is_nothrow_move_constructible::value...} + }[this->index()]; + } + }; + +#undef MPARK_INHERITING_CTOR + + template + struct overload_leaf { + using F = lib::size_constant (*)(T); + operator F() const { return nullptr; } + }; + + template + struct overload_impl { + private: + template + struct impl; + + template + struct impl> : overload_leaf... {}; + + public: + using type = impl>; + }; + + template + using overload = typename overload_impl::type; + + template + using best_match = lib::invoke_result_t, T &&>; + + template + struct is_in_place_index : std::false_type {}; + + template + struct is_in_place_index> : std::true_type {}; + + template + struct is_in_place_type : std::false_type {}; + + template + struct is_in_place_type> : std::true_type {}; + + } // detail + + template + class variant { + static_assert(0 < sizeof...(Ts), + "variant must consist of at least one alternative."); + + static_assert(lib::all::value...>::value, + "variant can not have an array type as an alternative."); + + static_assert(lib::all::value...>::value, + "variant can not have a reference type as an alternative."); + + static_assert(lib::all::value...>::value, + "variant can not have a void type as an alternative."); + + public: + template < + typename Front = lib::type_pack_element_t<0, Ts...>, + lib::enable_if_t::value, int> = 0> + inline constexpr variant() noexcept( + std::is_nothrow_default_constructible::value) + : impl_(in_place_index_t<0>{}) {} + + variant(const variant &) = default; + variant(variant &&) = default; + + template < + typename Arg, + typename Decayed = lib::decay_t, + lib::enable_if_t::value, int> = 0, + lib::enable_if_t::value, int> = 0, + lib::enable_if_t::value, int> = 0, + std::size_t I = detail::best_match::value, + typename T = lib::type_pack_element_t, + lib::enable_if_t::value, int> = 0> + inline constexpr variant(Arg &&arg) noexcept( + std::is_nothrow_constructible::value) + : impl_(in_place_index_t{}, lib::forward(arg)) {} + + template < + std::size_t I, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t::value, int> = 0> + inline explicit constexpr variant( + in_place_index_t, + Args &&... args) noexcept(std::is_nothrow_constructible::value) + : impl_(in_place_index_t{}, lib::forward(args)...) {} + + template < + std::size_t I, + typename Up, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline explicit constexpr variant( + in_place_index_t, + std::initializer_list il, + Args &&... args) noexcept(std:: + is_nothrow_constructible< + T, + std::initializer_list &, + Args...>::value) + : impl_(in_place_index_t{}, il, lib::forward(args)...) {} + + template < + typename T, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t::value, int> = 0> + inline explicit constexpr variant( + in_place_type_t, + Args &&... args) noexcept(std::is_nothrow_constructible::value) + : impl_(in_place_index_t{}, lib::forward(args)...) {} + + template < + typename T, + typename Up, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline explicit constexpr variant( + in_place_type_t, + std::initializer_list il, + Args &&... args) noexcept(std:: + is_nothrow_constructible< + T, + std::initializer_list &, + Args...>::value) + : impl_(in_place_index_t{}, il, lib::forward(args)...) {} + + ~variant() = default; + + variant &operator=(const variant &) = default; + variant &operator=(variant &&) = default; + + template , variant>::value, + int> = 0, + std::size_t I = detail::best_match::value, + typename T = lib::type_pack_element_t, + lib::enable_if_t<(std::is_assignable::value && + std::is_constructible::value), + int> = 0> + inline variant &operator=(Arg &&arg) noexcept( + (std::is_nothrow_assignable::value && + std::is_nothrow_constructible::value)) { + impl_.template assign(lib::forward(arg)); + return *this; + } + + template < + std::size_t I, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t::value, int> = 0> + inline T &emplace(Args &&... args) { + return impl_.template emplace(lib::forward(args)...); + } + + template < + std::size_t I, + typename Up, + typename... Args, + typename T = lib::type_pack_element_t, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline T &emplace(std::initializer_list il, Args &&... args) { + return impl_.template emplace(il, lib::forward(args)...); + } + + template < + typename T, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t::value, int> = 0> + inline T &emplace(Args &&... args) { + return impl_.template emplace(lib::forward(args)...); + } + + template < + typename T, + typename Up, + typename... Args, + std::size_t I = detail::find_index_sfinae::value, + lib::enable_if_t &, + Args...>::value, + int> = 0> + inline T &emplace(std::initializer_list il, Args &&... args) { + return impl_.template emplace(il, lib::forward(args)...); + } + + inline constexpr bool valueless_by_exception() const noexcept { + return impl_.valueless_by_exception(); + } + + inline constexpr std::size_t index() const noexcept { + return impl_.index(); + } + + template , + Dummy>::value && + lib::dependent_type, + Dummy>::value)...>::value, + int> = 0> + inline void swap(variant &that) noexcept( + lib::all<(std::is_nothrow_move_constructible::value && + lib::is_nothrow_swappable::value)...>::value) { + impl_.swap(that.impl_); + } + + private: + detail::impl impl_; + + friend struct detail::access::variant; + friend struct detail::visitation::variant; + }; + + template + inline constexpr bool holds_alternative(const variant &v) noexcept { + return v.index() == I; + } + + template + inline constexpr bool holds_alternative(const variant &v) noexcept { + return holds_alternative::value>(v); + } + + namespace detail { + template + struct generic_get_impl { + constexpr generic_get_impl(int) noexcept {} + + constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN( + access::variant::get_alt(lib::forward(v)).value) + }; + + template + inline constexpr AUTO_REFREF generic_get(V &&v) + AUTO_REFREF_RETURN(generic_get_impl( + holds_alternative(v) ? 0 : (throw_bad_variant_access(), 0))( + lib::forward(v))) + } // namespace detail + + template + inline constexpr variant_alternative_t> &get( + variant &v) { + return detail::generic_get(v); + } + + template + inline constexpr variant_alternative_t> &&get( + variant &&v) { + return detail::generic_get(lib::move(v)); + } + + template + inline constexpr const variant_alternative_t> &get( + const variant &v) { + return detail::generic_get(v); + } + + template + inline constexpr const variant_alternative_t> &&get( + const variant &&v) { + return detail::generic_get(lib::move(v)); + } + + template + inline constexpr T &get(variant &v) { + return get::value>(v); + } + + template + inline constexpr T &&get(variant &&v) { + return get::value>(lib::move(v)); + } + + template + inline constexpr const T &get(const variant &v) { + return get::value>(v); + } + + template + inline constexpr const T &&get(const variant &&v) { + return get::value>(lib::move(v)); + } + + namespace detail { + + template + inline constexpr /* auto * */ AUTO generic_get_if(V *v) noexcept + AUTO_RETURN(v && holds_alternative(*v) + ? lib::addressof(access::variant::get_alt(*v).value) + : nullptr) + + } // namespace detail + + template + inline constexpr lib::add_pointer_t>> + get_if(variant *v) noexcept { + return detail::generic_get_if(v); + } + + template + inline constexpr lib::add_pointer_t< + const variant_alternative_t>> + get_if(const variant *v) noexcept { + return detail::generic_get_if(v); + } + + template + inline constexpr lib::add_pointer_t + get_if(variant *v) noexcept { + return get_if::value>(v); + } + + template + inline constexpr lib::add_pointer_t + get_if(const variant *v) noexcept { + return get_if::value>(v); + } + + namespace detail { + template + struct convert_to_bool { + template + inline constexpr bool operator()(Lhs &&lhs, Rhs &&rhs) const { + static_assert(std::is_convertible, + bool>::value, + "relational operators must return a type" + " implicitly convertible to bool"); + return lib::invoke( + RelOp{}, lib::forward(lhs), lib::forward(rhs)); + } + }; + } // namespace detail + + template + inline constexpr bool operator==(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using equal_to = detail::convert_to_bool; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.index() != rhs.index()) return false; + if (lhs.valueless_by_exception()) return true; + return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); +#else + return lhs.index() == rhs.index() && + (lhs.valueless_by_exception() || + variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); +#endif + } + + template + inline constexpr bool operator!=(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using not_equal_to = detail::convert_to_bool; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.index() != rhs.index()) return true; + if (lhs.valueless_by_exception()) return false; + return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); +#else + return lhs.index() != rhs.index() || + (!lhs.valueless_by_exception() && + variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); +#endif + } + + template + inline constexpr bool operator<(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using less = detail::convert_to_bool; +#ifdef MPARK_CPP14_CONSTEXPR + if (rhs.valueless_by_exception()) return false; + if (lhs.valueless_by_exception()) return true; + if (lhs.index() < rhs.index()) return true; + if (lhs.index() > rhs.index()) return false; + return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); +#else + return !rhs.valueless_by_exception() && + (lhs.valueless_by_exception() || lhs.index() < rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); +#endif + } + + template + inline constexpr bool operator>(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using greater = detail::convert_to_bool; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.valueless_by_exception()) return false; + if (rhs.valueless_by_exception()) return true; + if (lhs.index() > rhs.index()) return true; + if (lhs.index() < rhs.index()) return false; + return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); +#else + return !lhs.valueless_by_exception() && + (rhs.valueless_by_exception() || lhs.index() > rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); +#endif + } + + template + inline constexpr bool operator<=(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using less_equal = detail::convert_to_bool; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.valueless_by_exception()) return true; + if (rhs.valueless_by_exception()) return false; + if (lhs.index() < rhs.index()) return true; + if (lhs.index() > rhs.index()) return false; + return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); +#else + return lhs.valueless_by_exception() || + (!rhs.valueless_by_exception() && + (lhs.index() < rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); +#endif + } + + template + inline constexpr bool operator>=(const variant &lhs, + const variant &rhs) { + using detail::visitation::variant; + using greater_equal = detail::convert_to_bool; +#ifdef MPARK_CPP14_CONSTEXPR + if (rhs.valueless_by_exception()) return true; + if (lhs.valueless_by_exception()) return false; + if (lhs.index() > rhs.index()) return true; + if (lhs.index() < rhs.index()) return false; + return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); +#else + return rhs.valueless_by_exception() || + (!lhs.valueless_by_exception() && + (lhs.index() > rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at( + lhs.index(), greater_equal{}, lhs, rhs)))); +#endif + } + + struct monostate {}; + + inline constexpr bool operator<(monostate, monostate) noexcept { + return false; + } + + inline constexpr bool operator>(monostate, monostate) noexcept { + return false; + } + + inline constexpr bool operator<=(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator>=(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator==(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator!=(monostate, monostate) noexcept { + return false; + } + +#ifdef MPARK_CPP14_CONSTEXPR + namespace detail { + + inline constexpr bool all(std::initializer_list bs) { + for (bool b : bs) { + if (!b) { + return false; + } + } + return true; + } + + } // namespace detail + + template + inline constexpr decltype(auto) visit(Visitor &&visitor, Vs &&... vs) { + return (detail::all({!vs.valueless_by_exception()...}) + ? (void)0 + : throw_bad_variant_access()), + detail::visitation::variant::visit_value( + lib::forward(visitor), lib::forward(vs)...); + } +#else + namespace detail { + + template + inline constexpr bool all_impl(const lib::array &bs, + std::size_t idx) { + return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); + } + + template + inline constexpr bool all(const lib::array &bs) { + return all_impl(bs, 0); + } + + } // namespace detail + + template + inline constexpr DECLTYPE_AUTO visit(Visitor &&visitor, Vs &&... vs) + DECLTYPE_AUTO_RETURN( + (detail::all( + lib::array{{!vs.valueless_by_exception()...}}) + ? (void)0 + : throw_bad_variant_access()), + detail::visitation::variant::visit_value(lib::forward(visitor), + lib::forward(vs)...)) +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnoexcept" +#endif + template + inline auto swap(variant &lhs, + variant &rhs) noexcept(noexcept(lhs.swap(rhs))) + -> decltype(lhs.swap(rhs)) { + lhs.swap(rhs); + } +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + + namespace detail { + + template + using enabled_type = T; + + namespace hash { + + template + constexpr bool meets_requirements() noexcept { + return std::is_copy_constructible::value && + std::is_move_constructible::value && + lib::is_invocable_r::value; + } + + template + constexpr bool is_enabled() noexcept { + using H = std::hash; + return meets_requirements() && + std::is_default_constructible::value && + std::is_copy_assignable::value && + std::is_move_assignable::value; + } + + } // namespace hash + + } // namespace detail + +#undef AUTO +#undef AUTO_RETURN + +#undef AUTO_REFREF +#undef AUTO_REFREF_RETURN + +#undef DECLTYPE_AUTO +#undef DECLTYPE_AUTO_RETURN + +} // namespace mpark + +namespace std { + + template + struct hash, + mpark::lib::enable_if_t>()...>::value>>> { + using argument_type = mpark::variant; + using result_type = std::size_t; + + inline result_type operator()(const argument_type &v) const { + using mpark::detail::visitation::variant; + std::size_t result = + v.valueless_by_exception() + ? 299792458 // Random value chosen by the universe upon creation + : variant::visit_alt( +#ifdef MPARK_GENERIC_LAMBDAS + [](const auto &alt) { + using alt_type = mpark::lib::decay_t; + using value_type = mpark::lib::remove_const_t< + typename alt_type::value_type>; + return hash{}(alt.value); + } +#else + hasher{} +#endif + , + v); + return hash_combine(result, hash{}(v.index())); + } + + private: +#ifndef MPARK_GENERIC_LAMBDAS + struct hasher { + template + inline std::size_t operator()(const Alt &alt) const { + using alt_type = mpark::lib::decay_t; + using value_type = + mpark::lib::remove_const_t; + return hash{}(alt.value); + } + }; +#endif + + static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { + return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); + } + }; + + template <> + struct hash { + using argument_type = mpark::monostate; + using result_type = std::size_t; + + inline result_type operator()(const argument_type &) const noexcept { + return 66740831; // return a fundamentally attractive random value. + } + }; + +} // namespace std + +#endif // MPARK_VARIANT_HPP diff --git a/make.config.in b/make.config.in index d32fcd0d72..4fee8499e3 100644 --- a/make.config.in +++ b/make.config.in @@ -39,7 +39,7 @@ BOUT_LOCALE_PATH=@localedir@ # Created this variable so that a user won't overwrite the CXXFLAGS variable # on the command line, just add to this one -BOUT_FLAGS = -std=c++17 $(CXXFLAGS) @CXXFLAGS@ @OPENMP_CXXFLAGS@ @CXX11_FLAGS@ @COVERAGE_FLAGS@ +BOUT_FLAGS = $(CXXFLAGS) @CXXFLAGS@ @OPENMP_CXXFLAGS@ @CXX11_FLAGS@ @COVERAGE_FLAGS@ #Use := here to force a "static" evaluation of the current state of BOUT_FLAGS to #avoid infinite recursion that would arise if BOUT_FLAGS appeared on both sides of = BOUT_FLAGS := $(BOUT_FLAGS) -DBOUT_FLAGS_STRING="$(BOUT_FLAGS)" From 9f6ea8882426f3868c8efbcaaa54951610371eb7 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 10 Dec 2018 10:11:21 +0000 Subject: [PATCH 0413/1783] Small refactor and tidy --- include/bout/invertable_operator.hxx | 171 ++++++++++++++------------- 1 file changed, 89 insertions(+), 82 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 6bf9354097..dd9928848a 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -35,6 +35,7 @@ class InvertableOperator; #include #include #include +#include #include #include @@ -45,6 +46,7 @@ class InvertableOperator; /// No-op function to use as a default -- may wish to remove once testing phase complete template T identity(const T& in) { + AUTO_TRACE(); return in; }; @@ -63,13 +65,79 @@ public: using function_signature = std::function; /// Almost empty constructor -- currently don't actually use Options for anything - InvertableOperator(const function_signature& func = identity, Options* opt = nullptr, - Mesh* localmeshIn = nullptr) + InvertableOperator(const function_signature& func = identity, + Options* optIn = nullptr, Mesh* localmeshIn = nullptr) : operatorFunction(func), preconditionerFunction(func), - opt(opt ? opt : Options::getRoot()->getSection("invertableOperator")), + opt(optIn == nullptr ? optIn + : Options::getRoot()->getSection("invertableOperator")), localmesh(localmeshIn == nullptr ? mesh : localmeshIn), doneSetup(false) { - TRACE("InvertableOperator::constructor"); + AUTO_TRACE(); + }; + + /// Destructor just has to cleanup the PETSc owned objects. + ~InvertableOperator() { + TRACE("InvertableOperator::destructor"); +#if CHECK > 3 // For initial development + output_info << endl; + output_info << "Destroying KSP object in InvertableOperator with properties: " + << endl; + KSPView(ksp, PETSC_VIEWER_STDOUT_SELF); + output_info << endl; +#endif + + KSPDestroy(&ksp); + MatDestroy(&matOperator); + MatDestroy(&matPreconditioner); + VecDestroy(&rhs); + VecDestroy(&lhs); + }; + + /// Allow the user to override the existing function + /// Note by default we set the preconditioner function to match this + /// as this is the usual mode of operation. If the user doesn't want to + /// do this they can set alsoSetPreconditioner to false. + void setOperatorFunction(const function_signature& func, + bool alsoSetPreconditioner = true) { + TRACE("InvertableOperator::setOperatorFunction"); + operatorFunction = func; + if (alsoSetPreconditioner) { + preconditionerFunction = func; + } + } + /// Allow the user to override the existing preconditioner function + void setPreconditionerFunction(const function_signature& func) { + TRACE("InvertableOperator::setPreconditionerFunction"); + preconditionerFunction = func; + } + + /// Provide a way to apply the operator to a Field + T operator()(const T& input) { + TRACE("InvertableOperator::operator()"); + return operatorFunction(input); + } + + /// Provide a synonym for applying the operator to a Field + T apply(const T& input) { + AUTO_TRACE(); + return operator()(input); + } + + /// Sets up the PETSc objects required for inverting the operator + /// Currently also takes the functor that applies the operator this class + /// represents. Not actually required by any of the setup so this should + /// probably be moved to a separate place (maybe the constructor). + PetscErrorCode setup() { + TRACE("InvertableOperator::setup"); + + Timer timer("invertable_operator_setup"); + if (doneSetup) { + throw BoutException( + "Trying to call setup on an InvertableOperator instance that has " + "already been setup."); + } + + // Add the RGN_NOCORNERS region to the mesh. Requires RGN_NOBNDRY to be defined. if (std::is_same::value) { if (not localmesh->hasRegion3D("RGN_NOCORNERS")) { // This avoids all guard cells and corners but includes boundaries @@ -167,67 +235,6 @@ public: } else { throw BoutException("Invalid template type provided to InvertableOperator"); } - }; - - /// Destructor just has to cleanup the PETSc owned objects. - ~InvertableOperator() { - TRACE("InvertableOperator::destructor"); -#if CHECK > 3 - output_info << endl; - output_info << "Destroying KSP object in InvertableOperator with properties: " - << endl; - KSPView(ksp, PETSC_VIEWER_STDOUT_SELF); - output_info << endl; -#endif - - KSPDestroy(&ksp); - MatDestroy(&matOperator); - MatDestroy(&matPreconditioner); - VecDestroy(&rhs); - VecDestroy(&lhs); - }; - - /// Allow the user to override the existing function - /// Note by default we set the preconditioner function to match this - /// as this is the usual mode of operation. If the user doesn't want to - /// do this they can set alsoSetPreconditioner to false. - void setOperatorFunction(const function_signature& func, - bool alsoSetPreconditioner = true) { - TRACE("InvertableOperator::setOperatorFunction"); - operatorFunction = func; - if (alsoSetPreconditioner) { - preconditionerFunction = func; - } - } - - /// Allow the user to override the existing preconditioner function - void setPreconditionerFunction(const function_signature& func) { - TRACE("InvertableOperator::setPreconditionerFunction"); - preconditionerFunction = func; - } - - /// Provide a way to apply the operator to a Field - T operator()(const T& input) { - TRACE("InvertableOperator::operator()"); - return operatorFunction(input); - } - - /// Provide a synonym for applying the operator to a Field - T apply(const T& input) { return operator()(input); } - - /// Sets up the PETSc objects required for inverting the operator - /// Currently also takes the functor that applies the operator this class - /// represents. Not actually required by any of the setup so this should - /// probably be moved to a separate place (maybe the constructor). - PetscErrorCode setup() { - TRACE("InvertableOperator::setup"); - - Timer timer("invertable_operator_setup"); - if (doneSetup) { - throw BoutException( - "Trying to call setup on an InvertableOperator instance that has " - "already been setup."); - } PetscInt ierr; @@ -294,14 +301,14 @@ public: /// By default allow a non-zero initial guess as this is probably the /// most helpful mode of operation. To disable this user can pass - /// `-invert_ksp_initial_guess_nonzero false` on the command line or simply - /// use `result = operator.invert(rhs, 0.0)` which will lead to an initial - /// guess of zero being used. + /// `-invertable_ksp_initial_guess_nonzero false` on the command line or simply + /// use `result = operator.invert(rhs, T{})` which will lead to an initial + /// guess of whatever is in the instance of T that is passed. ierr = KSPSetInitialGuessNonzero(ksp, PETSC_TRUE); CHKERRQ(ierr); - /// Allow options to be set on command line using a --invert_ksp_* prefix. - ierr = KSPSetOptionsPrefix(ksp, "invert_"); + /// Allow options to be set on command line using a --invertable_ksp_* prefix. + ierr = KSPSetOptionsPrefix(ksp, "invertable_"); CHKERRQ(ierr); ierr = KSPSetFromOptions(ksp); CHKERRQ(ierr); @@ -320,6 +327,7 @@ public: // but suspect it's not as there are KSPGuess objects // to deal with. T invert(const T& rhsField, const T& guess) { + AUTO_TRACE(); fieldToPetscVec(guess, lhs); return invert(rhsField); } @@ -358,9 +366,8 @@ public: throw BoutException("KSPSolve failed with reason %d.", reason); } -#if CHECK > 3 - output_info << "KSPSolve finished with converged reason : " << reason << endl; -#endif + // Probably want to remove the following in the long run + output_debug << "KSPSolve finished with converged reason : " << reason << endl; // lhs to lhsField -- first make the output field and ensure it has space allocated T lhsField(localmesh); @@ -381,14 +388,12 @@ public: localmesh->communicate(result); const T applied = operator()(result); const BoutReal maxDiff = max(abs(applied - rhsIn), true); -#if CHECK > 3 if (maxDiff >= tol) { - output_info << "Maximum difference in verify is " << maxDiff << endl; - output_info << "Max rhs is " << max(abs(rhsIn), true) << endl; - output_info << "Max applied is " << max(abs(applied), true) << endl; - output_info << "Max result is " << max(abs(result), true) << endl; + output_debug << "Maximum difference in verify is " << maxDiff << endl; + output_debug << "Max rhs is " << max(abs(rhsIn), true) << endl; + output_debug << "Max applied is " << max(abs(applied), true) << endl; + output_debug << "Max result is " << max(abs(result), true) << endl; }; -#endif return maxDiff < tol; #else return true; @@ -406,9 +411,9 @@ public: BoutReal time_operate = Timer::resetTime("invertable_operator_operate"); output_warn << "InvertableOperator timing :: Setup " << time_setup; - output_warn << " , Invert(packing) " << time_invert << "("; - output_warn << time_packing << ")"; - output_warn << " operate :" << time_operate << endl; + output_warn << " , Invert(packing, operation) " << time_invert << "("; + output_warn << time_packing << ", "; + output_warn << time_operate << "). Total : " << time_setup + time_invert << endl; }; private: @@ -506,6 +511,7 @@ PetscErrorCode fieldToPetscVec(const T& in, Vec out) { int counter = 0; + // Should explore ability to OpenMP this BOUT_FOR_SERIAL(i, in.getRegion("RGN_NOCORNERS")) { vecData[counter] = in[i]; counter++; @@ -530,6 +536,7 @@ PetscErrorCode petscVecToField(Vec in, T& out) { int counter = 0; + // Should explore ability to OpenMP this BOUT_FOR_SERIAL(i, out.getRegion("RGN_NOCORNERS")) { out[i] = vecData[counter]; counter++; From 1fe38124d794f4a943ad737138add8485cd8147c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 10 Dec 2018 10:11:43 +0000 Subject: [PATCH 0414/1783] Tidy example --- .../invertable_operator.cxx | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/invertable_operator/invertable_operator.cxx b/examples/invertable_operator/invertable_operator.cxx index 1b01125e2c..851ece6679 100644 --- a/examples/invertable_operator/invertable_operator.cxx +++ b/examples/invertable_operator/invertable_operator.cxx @@ -67,7 +67,7 @@ class HW : public PhysicsModel { // or even a Lambda // mySolver([](const Field3D &input) { return input + Delp2(input); }); - class Laplacian *phiSolverXZ; + class Laplacian* laplacianSolver; const int nits = 10; @@ -87,10 +87,10 @@ class HW : public PhysicsModel { mySolver.setOperatorFunction(mm); mySolver.setup(); - phiSolverXZ = Laplacian::create(); - phiSolverXZ->setCoefA(mm.A); - phiSolverXZ->setCoefC(1.0); - phiSolverXZ->setCoefD(mm.D); + laplacianSolver = Laplacian::create(); + laplacianSolver->setCoefA(mm.A); + laplacianSolver->setCoefC(1.0); + laplacianSolver->setCoefD(mm.D); n.applyBoundary("dirichlet"); @@ -117,27 +117,27 @@ class HW : public PhysicsModel { mesh->communicate(solutionInv); - output_warn << std::endl; + output << std::endl; auto pass = mySolver.verify(n) == 0 ? "False" : "True"; - output_warn << "Has test passed ? " << pass << std::endl; - output_warn << std::endl; + output << "Has test passed ? " << pass << std::endl; + output << std::endl; { Timer timer("sol_lap"); try { for (int i = 0; i < nits; i++) { - solutionLap = phiSolverXZ->solve(n); + solutionLap = laplacianSolver->solve(n); } } catch (BoutException &e) { }; } - output_warn << "Max diff undo Invertable is " << max(abs(mm(solutionInv) - n), true) - << endl; - output_warn << "MAX DIFF SOL " << max(abs(solutionLap - solutionInv), true) << endl; + output << "Max diff undo Invertable is " << max(abs(mm(solutionInv) - n), true) + << endl; + output << "MAX DIFF SOL " << max(abs(solutionLap - solutionInv), true) << endl; mySolver.reportTime(); - output_warn << "Laplacian time is " << Timer::resetTime("sol_lap") << endl; + output << "Laplacian time is " << Timer::resetTime("sol_lap") << endl; return 0; } From 2b6c33c4af0fd7cdd5ba0335344ae667f2135d4d Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 10 Dec 2018 10:42:49 +0000 Subject: [PATCH 0415/1783] Convert some std:: to bout::utils:: Missed some instances where std::holds_alternative and std::get --- include/options.hxx | 6 ++--- src/sys/options.cxx | 34 +++++++++++++-------------- tests/unit/sys/test_optionsreader.cxx | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index 3b1a17b253..fd2154a2de 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -4,9 +4,9 @@ * The Options class represents a tree structure of key-value settings. * Provides get and set methods on these options. * -* Internally, all quantities are stored as strings for simplicity -* and so that option file parsers don't have to do type conversion -* without knowing the type a priori. +* Internally, values are stored in a variant. Conversion of types +* is handled internally, so this is transparent to the user. If desired, +* the user can directly access the "value" member which is the variant. * * There is a singleton object "root" which contains the top-level * options and allows access to all sub-sections diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 3cd051046b..e7413700de 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -114,21 +114,21 @@ template <> int Options::as() const { int result; - if (std::holds_alternative(value)) { - result = std::get(value); + if (bout::utils::holds_alternative(value)) { + result = bout::utils::get(value); } else { // Cases which get a BoutReal then check if close to an integer BoutReal rval; - if (std::holds_alternative(value)) { - rval = std::get(value); + if (bout::utils::holds_alternative(value)) { + rval = bout::utils::get(value); - } else if (std::holds_alternative(value)) { + } else if (bout::utils::holds_alternative(value)) { // Use FieldFactory to evaluate expression // Parse the string, giving this Option pointer for the context // then generate a value at t,x,y,z = 0,0,0,0 - auto gen = FieldFactory::get()->parse(std::get(value), this); + auto gen = FieldFactory::get()->parse(bout::utils::get(value), this); if (!gen) { throw BoutException(_("Couldn't get integer from option %s = '%s'"), full_name.c_str(), bout::utils::variantToString(value).c_str()); @@ -169,21 +169,21 @@ template <> BoutReal Options::as() const { BoutReal result; - if (std::holds_alternative(value)) { - result = static_cast(std::get(value)); + if (bout::utils::holds_alternative(value)) { + result = static_cast(bout::utils::get(value)); - } else if (std::holds_alternative(value)) { - result = std::get(value); + } else if (bout::utils::holds_alternative(value)) { + result = bout::utils::get(value); - } else if (std::holds_alternative(value)) { + } else if (bout::utils::holds_alternative(value)) { // Use FieldFactory to evaluate expression // Parse the string, giving this Option pointer for the context // then generate a value at t,x,y,z = 0,0,0,0 - std::shared_ptr gen = FieldFactory::get()->parse(std::get(value), this); + std::shared_ptr gen = FieldFactory::get()->parse(bout::utils::get(value), this); if (!gen) { throw BoutException(_("Couldn't get BoutReal from option %s = '%s'"), full_name.c_str(), - std::get(value).c_str()); + bout::utils::get(value).c_str()); } result = gen->generate(0, 0, 0, 0); } else { @@ -211,11 +211,11 @@ template <> bool Options::as() const { bool result; - if (std::holds_alternative(value)) { - result = std::get(value); + if (bout::utils::holds_alternative(value)) { + result = bout::utils::get(value); - } else if(std::holds_alternative(value)) { - std::string strvalue = std::get(value); + } else if(bout::utils::holds_alternative(value)) { + std::string strvalue = bout::utils::get(value); char c = static_cast(toupper((strvalue)[0])); if ((c == 'Y') || (c == 'T') || (c == '1')) { diff --git a/tests/unit/sys/test_optionsreader.cxx b/tests/unit/sys/test_optionsreader.cxx index 5d6c2952ab..4e394fad7d 100644 --- a/tests/unit/sys/test_optionsreader.cxx +++ b/tests/unit/sys/test_optionsreader.cxx @@ -357,7 +357,7 @@ TEST_F(OptionsReaderTest, WriteFile) { test_file.close(); std::vector expected = {"bool_key = true", "[section1]", - "int_key = 17", "real_key = 6.17000000000000006e+23", + "int_key = 17", "real_key = 6.17e+23", "[section1:subsection2]", "string_key = BOUT++"}; for (auto &result : expected) { From 0c994fe09069df6577b5c10bc5d242b6c0d6bd08 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 10 Dec 2018 10:51:26 +0000 Subject: [PATCH 0416/1783] Make verify always check whatever CHECK level is used --- include/bout/invertable_operator.hxx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index dd9928848a..fa7825b550 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -383,7 +383,7 @@ public: /// back the initial values. bool verify(const T& rhsIn, BoutReal tol = 1.0e-5) { TRACE("InvertableOperator::verify"); -#if CHECK > 1 + T result = invert(rhsIn); localmesh->communicate(result); const T applied = operator()(result); @@ -395,9 +395,6 @@ public: output_debug << "Max result is " << max(abs(result), true) << endl; }; return maxDiff < tol; -#else - return true; -#endif }; /// Reports the time spent in various parts of InvertableOperator. Note From 12f46f6cb4d6398dccd4fd7accd581b471900f2d Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 10 Dec 2018 13:34:43 +0000 Subject: [PATCH 0417/1783] Add auto, use map::insert rather than emplace Previous syntax with map::emplace seems to work on some compilers (the one on my machine), but not on Travis. Hopefully map::insert infers the type correctly. Added auto in a few places following @ZedThree's suggestions. --- src/sys/options.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sys/options.cxx b/src/sys/options.cxx index e7413700de..e771ab9d98 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -180,7 +180,7 @@ template <> BoutReal Options::as() const { // Use FieldFactory to evaluate expression // Parse the string, giving this Option pointer for the context // then generate a value at t,x,y,z = 0,0,0,0 - std::shared_ptr gen = FieldFactory::get()->parse(bout::utils::get(value), this); + auto gen = FieldFactory::get()->parse(bout::utils::get(value), this); if (!gen) { throw BoutException(_("Couldn't get BoutReal from option %s = '%s'"), full_name.c_str(), bout::utils::get(value).c_str()); @@ -215,9 +215,9 @@ template <> bool Options::as() const { result = bout::utils::get(value); } else if(bout::utils::holds_alternative(value)) { - std::string strvalue = bout::utils::get(value); + auto strvalue = bout::utils::get(value); - char c = static_cast(toupper((strvalue)[0])); + auto c = static_cast(toupper((strvalue)[0])); if ((c == 'Y') || (c == 'T') || (c == '1')) { result = true; } else if ((c == 'N') || (c == 'F') || (c == '0')) { @@ -280,9 +280,9 @@ std::map Options::values() const { std::map options; for (const auto& it : children) { if (it.second.is_value) { - options.emplace(it.first, OptionValue{ bout::utils::variantToString(it.second.value), - bout::utils::variantToString(it.second.attributes.at("source")), - it.second.value_used}); + options.insert({it.first, { bout::utils::variantToString(it.second.value), + bout::utils::variantToString(it.second.attributes.at("source")), + it.second.value_used}}); } } return options; From 8d922a9c94a7478c7f2d18c120bc1b114f4868bb Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 10 Dec 2018 14:17:53 +0000 Subject: [PATCH 0418/1783] Add OptionValue constructor, use map::emplace Partly revert previous change, now compiles with -std=c++11 --- include/options.hxx | 5 +++++ src/sys/options.cxx | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index fd2154a2de..1e68f015f9 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -433,6 +433,11 @@ public: std::string value; std::string source; // Source of the setting mutable bool used = false; // Set to true when used + + /// This constructor needed for map::emplace + /// Can be removed in C++17 with map::insert and brace initialisation + OptionValue(std::string value, std::string source, bool used) + : value(value), source(source), used(used) {} }; /// Read-only access to internal options and sections diff --git a/src/sys/options.cxx b/src/sys/options.cxx index e771ab9d98..2195855692 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -280,9 +280,9 @@ std::map Options::values() const { std::map options; for (const auto& it : children) { if (it.second.is_value) { - options.insert({it.first, { bout::utils::variantToString(it.second.value), - bout::utils::variantToString(it.second.attributes.at("source")), - it.second.value_used}}); + options.emplace(it.first, OptionValue { bout::utils::variantToString(it.second.value), + bout::utils::variantToString(it.second.attributes.at("source")), + it.second.value_used}); } } return options; From 73a7706ddb9af5dc367b0462525dac0660907a8c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 17 Jul 2018 12:08:49 +0100 Subject: [PATCH 0419/1783] Remove result_fa from interp_to Remove the intermediate variable result_fa in branch of interp_to that transforms to field-aligned variables. Just store the intermediate result in 'result' instead, to save memory. --- src/mesh/interpolation.cxx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/mesh/interpolation.cxx b/src/mesh/interpolation.cxx index a979df641f..5572e3c9d4 100644 --- a/src/mesh/interpolation.cxx +++ b/src/mesh/interpolation.cxx @@ -151,11 +151,9 @@ const Field3D interp_to(const Field3D &var, CELL_LOC loc, REGION region) { // coordinates Field3D var_fa = fieldmesh->toFieldAligned(var); - Field3D result_fa(fieldmesh); if (region != RGN_NOBNDRY) { - result_fa = fieldmesh->toFieldAligned(result); + result = fieldmesh->toFieldAligned(result); } - result_fa.allocate(); if (fieldmesh->ystart > 1) { // More than one guard cell, so set pp and mm values @@ -180,7 +178,7 @@ const Field3D interp_to(const Field3D &var, CELL_LOC loc, REGION region) { s.m = s.c; } - result_fa[i] = interp(s); + result[i] = interp(s); } } } else { @@ -206,12 +204,12 @@ const Field3D interp_to(const Field3D &var, CELL_LOC loc, REGION region) { s.m = s.c; } - result_fa[i] = interp(s); + result[i] = interp(s); } } } - result = fieldmesh->fromFieldAligned(result_fa); + result = fieldmesh->fromFieldAligned(result); } break; } From 1d3f03229becf7f8311127f8d3aa82576054e6b3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 10 Dec 2018 13:46:13 +0000 Subject: [PATCH 0420/1783] Avoid duplicating toFieldAligned call --- src/mesh/interpolation.cxx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/mesh/interpolation.cxx b/src/mesh/interpolation.cxx index 5572e3c9d4..441f442eec 100644 --- a/src/mesh/interpolation.cxx +++ b/src/mesh/interpolation.cxx @@ -152,7 +152,14 @@ const Field3D interp_to(const Field3D &var, CELL_LOC loc, REGION region) { Field3D var_fa = fieldmesh->toFieldAligned(var); if (region != RGN_NOBNDRY) { - result = fieldmesh->toFieldAligned(result); + // repeat the hack above for boundary points + // this avoids a duplicate toFieldAligned call if we had called + // result = toFieldAligned(result) + // to get the boundary cells + // + // result is requested in some boundary region(s) + result = var_fa; // NOTE: This is just for boundaries. FIX! + result.allocate(); } if (fieldmesh->ystart > 1) { From 9fcfbcd2888fd4f0bd9651231734606d377c8a1e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 18 Jul 2018 11:10:28 +0100 Subject: [PATCH 0421/1783] Add region arguments for toFieldAligned/fromFieldAligned Add region arguments (where it is valid to give RGN_NOX or RGN_NOBNDRY) so functions like toFieldAligned/fromFieldAligned can be used both when y-guard cells have been set and when they have not. e.g. when using fromFieldAligned on the results of interpolation or derivatives, y-guard cells cannot be included, but when using toFieldAligned on the inputs to interpolation or derivatives, y-guard cells must be included. --- include/bout/fv_ops.hxx | 4 +-- include/bout/mesh.hxx | 22 ++++++------- include/bout/paralleltransform.hxx | 18 +++++------ src/invert/parderiv/impls/cyclic/cyclic.cxx | 2 +- src/mesh/difops.cxx | 4 +-- src/mesh/fv_ops.cxx | 6 ++-- src/mesh/interpolation.cxx | 2 +- src/mesh/parallel/fci.hxx | 4 +-- src/mesh/parallel/shiftedmetric.cxx | 35 ++++++++++++--------- 9 files changed, 51 insertions(+), 46 deletions(-) diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index f1bbf8bd6e..2b892ba770 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -322,7 +322,7 @@ namespace FV { } } } - return mesh->fromFieldAligned(result); + return mesh->fromFieldAligned(result, RGN_NOBNDRY); } /*! @@ -483,7 +483,7 @@ namespace FV { yresult(i,j,k) = (nU*vU - nD*vD) / (coord->J(i,j)*coord->dy(i,j)); } - return result + mesh->fromFieldAligned(yresult); + return result + mesh->fromFieldAligned(yresult, RGN_NOBNDRY); } } diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index b745d7e81e..1d2137cc68 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -564,7 +564,7 @@ class Mesh { const T f_aligned = f.getMesh()->toFieldAligned(f); T result = indexStandardDerivative( f, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); + return f.getMesh()->fromFieldAligned(result, region); } } @@ -579,7 +579,7 @@ class Mesh { const T f_aligned = f.getMesh()->toFieldAligned(f); T result = indexStandardDerivative( f, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); + return f.getMesh()->fromFieldAligned(result, region); } } @@ -594,7 +594,7 @@ class Mesh { const T f_aligned = f.getMesh()->toFieldAligned(f); T result = indexStandardDerivative( f, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); + return f.getMesh()->fromFieldAligned(result, region); } } @@ -668,7 +668,7 @@ class Mesh { const T vel_aligned = vel.getMesh()->toFieldAligned(vel); T result = indexFlowDerivative( vel_aligned, f_aligned, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); + return f.getMesh()->fromFieldAligned(result, region); } } @@ -687,7 +687,7 @@ class Mesh { const T vel_aligned = vel.getMesh()->toFieldAligned(vel); T result = indexFlowDerivative( vel_aligned, f_aligned, outloc, method, region); - return f.getMesh()->fromFieldAligned(result); + return f.getMesh()->fromFieldAligned(result, region); } } @@ -712,18 +712,18 @@ class Mesh { /////////////////////////////////////////////////////////// /// Transform a field into field-aligned coordinates - const Field3D toFieldAligned(const Field3D &f) { - return getParallelTransform().toFieldAligned(f); + const Field3D toFieldAligned(const Field3D &f, const REGION region = RGN_NOX) { + return getParallelTransform().toFieldAligned(f, region); } - const Field2D toFieldAligned(const Field2D &f) { + const Field2D toFieldAligned(const Field2D &f, const REGION UNUSED(region) = RGN_NOX) { return f; } /// Convert back into standard form - const Field3D fromFieldAligned(const Field3D &f) { - return getParallelTransform().fromFieldAligned(f); + const Field3D fromFieldAligned(const Field3D &f, const REGION region = RGN_NOX) { + return getParallelTransform().fromFieldAligned(f, region); } - const Field2D fromFieldAligned(const Field2D &f) { + const Field2D fromFieldAligned(const Field2D &f, const REGION UNUSED(region) = RGN_NOX) { return f; } diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index a25540354a..bab43dd61e 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -38,11 +38,11 @@ public: /// Convert a 3D field into field-aligned coordinates /// so that the y index is along the magnetic field - virtual const Field3D toFieldAligned(const Field3D &f) = 0; + virtual const Field3D toFieldAligned(const Field3D &f, const REGION region = RGN_NOX) = 0; /// Convert back from field-aligned coordinates /// into standard form - virtual const Field3D fromFieldAligned(const Field3D &f) = 0; + virtual const Field3D fromFieldAligned(const Field3D &f, const REGION region = RGN_NOX) = 0; virtual bool canToFromFieldAligned() = 0; }; @@ -65,7 +65,7 @@ public: * The field is already aligned in Y, so this * does nothing */ - const Field3D toFieldAligned(const Field3D &f) override { + const Field3D toFieldAligned(const Field3D &f, const REGION UNUSED(region)) override { return f; } @@ -73,7 +73,7 @@ public: * The field is already aligned in Y, so this * does nothing */ - const Field3D fromFieldAligned(const Field3D &f) override { + const Field3D fromFieldAligned(const Field3D &f, const REGION UNUSED(region)) override { return f; } @@ -109,13 +109,13 @@ public: * in X-Z, and the metric tensor will need to be changed * if X derivatives are used. */ - const Field3D toFieldAligned(const Field3D &f) override; + const Field3D toFieldAligned(const Field3D &f, const REGION region=RGN_NOX) override; /*! * Converts a field back to X-Z orthogonal coordinates * from field aligned coordinates. */ - const Field3D fromFieldAligned(const Field3D &f) override; + const Field3D fromFieldAligned(const Field3D &f, const REGION region=RGN_NOX) override; bool canToFromFieldAligned() override{ return true; @@ -142,7 +142,7 @@ private: * Shift a 2D field in Z. * Since 2D fields are constant in Z, this has no effect */ - const Field2D shiftZ(const Field2D &f, const Field2D &UNUSED(zangle)){return f;}; + const Field2D shiftZ(const Field2D &f, const Field2D &UNUSED(zangle), const REGION UNUSED(region)=RGN_NOX){return f;}; /*! * Shift a 3D field \p f in Z by the given \p zangle @@ -151,7 +151,7 @@ private: * @param[in] zangle Toroidal angle (z) * */ - const Field3D shiftZ(const Field3D &f, const Field2D &zangle); + const Field3D shiftZ(const Field3D &f, const Field2D &zangle, const REGION region=RGN_NOX); /*! * Shift a 3D field \p f by the given phase \p phs in Z @@ -162,7 +162,7 @@ private: * @param[in] f The field to shift * @param[in] phs The phase to shift by */ - const Field3D shiftZ(const Field3D &f, const arr3Dvec &phs); + const Field3D shiftZ(const Field3D &f, const arr3Dvec &phs, const REGION region=RGN_NOX); /*! * Shift a given 1D array, assumed to be in Z, by the given \p zangle diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index e326aa5767..57537519d4 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -216,6 +216,6 @@ const Field3D InvertParCR::solve(const Field3D &f) { // Delete cyclic reduction object delete cr; - return localmesh->fromFieldAligned(result); + return localmesh->fromFieldAligned(result, RGN_NOBNDRY); } diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index d271a4cda1..7287bcbfa2 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -388,7 +388,7 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg result[i] -= (vval.p >= 0.0) ? vval.p * fval.c : vval.p * fval.p; } - result = vMesh->fromFieldAligned(result); + result = vMesh->fromFieldAligned(result, region); } } @@ -420,7 +420,7 @@ const Field3D Grad_par_LtoC(const Field3D &var) { BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { result[i] = (var_fa[i.yp()] - var_fa[i]) / (metric->dy[i]*sqrt(metric->g_22[i])); } - result = varMesh->fromFieldAligned(result); + result = varMesh->fromFieldAligned(result, RGN_NOBNDRY); } result.setLocation(CELL_CENTRE); diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index 51359cc34e..8bb08321bb 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -171,7 +171,7 @@ namespace FV { if (!use_yup_ydown) { // Shifted to field aligned coordinates, so need to shift back - result = mesh->fromFieldAligned(result); + result = mesh->fromFieldAligned(result, RGN_NOBNDRY); } return result; @@ -226,7 +226,7 @@ namespace FV { } // Convert result back to non-aligned coordinates - return mesh->fromFieldAligned(result); + return mesh->fromFieldAligned(result, RGN_NOBNDRY); } const Field3D D4DY4_Index(const Field3D &f_in, bool bndry_flux) { @@ -335,7 +335,7 @@ namespace FV { } // Convert result back to non-aligned coordinates - return mesh->fromFieldAligned(result); + return mesh->fromFieldAligned(result, RGN_NOBNDRY); } void communicateFluxes(Field3D &f) { diff --git a/src/mesh/interpolation.cxx b/src/mesh/interpolation.cxx index a979df641f..c809f0c962 100644 --- a/src/mesh/interpolation.cxx +++ b/src/mesh/interpolation.cxx @@ -211,7 +211,7 @@ const Field3D interp_to(const Field3D &var, CELL_LOC loc, REGION region) { } } - result = fieldmesh->fromFieldAligned(result_fa); + result = fieldmesh->fromFieldAligned(result_fa, RGN_NOBNDRY); } break; } diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index 293113b91d..747f311c03 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -73,11 +73,11 @@ public: void integrateYUpDown(Field3D &f) override; - const Field3D toFieldAligned(const Field3D &UNUSED(f)) override { + const Field3D toFieldAligned(const Field3D &UNUSED(f), const REGION UNUSED(region)) override { throw BoutException("FCI method cannot transform into field aligned grid"); } - const Field3D fromFieldAligned(const Field3D &UNUSED(f)) override { + const Field3D fromFieldAligned(const Field3D &UNUSED(f), const REGION UNUSED(region)) override { throw BoutException("FCI method cannot transform into field aligned grid"); } diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 80fdc37274..53a5fdea96 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -129,30 +129,29 @@ void ShiftedMetric::calcYUpDown(Field3D &f) { * Shift the field so that X-Z is not orthogonal, * and Y is then field aligned. */ -const Field3D ShiftedMetric::toFieldAligned(const Field3D &f) { - return shiftZ(f, toAlignedPhs); +const Field3D ShiftedMetric::toFieldAligned(const Field3D &f, const REGION region) { + return shiftZ(f, toAlignedPhs, region); } /*! * Shift back, so that X-Z is orthogonal, * but Y is not field aligned. */ -const Field3D ShiftedMetric::fromFieldAligned(const Field3D &f) { - return shiftZ(f, fromAlignedPhs); +const Field3D ShiftedMetric::fromFieldAligned(const Field3D &f, const REGION region) { + return shiftZ(f, fromAlignedPhs, region); } -const Field3D ShiftedMetric::shiftZ(const Field3D &f, const arr3Dvec &phs) { +const Field3D ShiftedMetric::shiftZ(const Field3D &f, const arr3Dvec &phs, const REGION region) { ASSERT1(&mesh == f.getMesh()); + ASSERT1(region == RGN_NOX || region == RGN_NOBNDRY); // Never calculate x-guard cells here if(mesh.LocalNz == 1) return f; // Shifting makes no difference Field3D result(&mesh); result.allocate(); - - for(int jx=0;jx &phs, } //Old approach retained so we can still specify a general zShift -const Field3D ShiftedMetric::shiftZ(const Field3D &f, const Field2D &zangle) { +const Field3D ShiftedMetric::shiftZ(const Field3D &f, const Field2D &zangle, const REGION region) { ASSERT1(&mesh == f.getMesh()); + ASSERT1(region == RGN_NOX || region == RGN_NOBNDRY); // Never calculate x-guard cells here + ASSERT1(f.getLocation() == zangle.getLocation()); if(mesh.LocalNz == 1) return f; // Shifting makes no difference Field3D result(&mesh); result.allocate(); - for(int jx=0;jx Date: Fri, 2 Nov 2018 14:13:41 +0000 Subject: [PATCH 0422/1783] Fix location checking in ShiftedMetric::shiftZ() Fixing the low-level shiftZ method means that toFieldAligned/fromFieldAligned also do the right thing. Check that input to shiftZ is at same location as the shift angle zShift (i.e. CELL_CENTRE). Set location of result returned from zShift to be the same as the location of the input. --- src/mesh/parallel/shiftedmetric.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 80fdc37274..fc81e9fbe7 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -143,11 +143,13 @@ const Field3D ShiftedMetric::fromFieldAligned(const Field3D &f) { const Field3D ShiftedMetric::shiftZ(const Field3D &f, const arr3Dvec &phs) { ASSERT1(&mesh == f.getMesh()); + ASSERT1(f.getLocation() == CELL_CENTRE); // only have zShift for CELL_CENTRE, so can only deal with CELL_CENTRE inputs if(mesh.LocalNz == 1) return f; // Shifting makes no difference Field3D result(&mesh); result.allocate(); + result.setLocation(f.getLocation()); for(int jx=0;jx Date: Mon, 10 Dec 2018 17:09:34 +0000 Subject: [PATCH 0423/1783] Fix FV::Div_par_K_Grad_par Should loop over RGN_NOBNDRY, previously loop was over RGN_ALL, which causes some indexes to go out of bounds. --- src/mesh/fv_ops.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index 51359cc34e..d67fe767a6 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -135,7 +135,7 @@ namespace FV { Coordinates *coord = fin.getCoordinates(); - BOUT_FOR(i, result.getRegion("RGN_ALL")) { + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { // Calculate flux at upper surface const auto iyp = i.yp(); From 9df06a14b0aea4c06377ac6429032aba7028a2d5 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 10 Dec 2018 23:32:01 +0000 Subject: [PATCH 0424/1783] Add Options copy constructor and assignment operator Update parent pointer so remains consistent, copies all values. Includes unit tests Probably need to (re)consider the root instance, since not guaranteed to be the root of all objects if there are copies. --- include/options.hxx | 42 ++++++++++++- tests/unit/sys/test_options.cxx | 107 ++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 1 deletion(-) diff --git a/include/options.hxx b/include/options.hxx index 1e68f015f9..33693f720b 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -160,6 +160,20 @@ public: Options(Options *parent_instance, std::string full_name) : parent_instance(parent_instance), full_name(std::move(full_name)){}; + /// Copy constructor + Options(const Options& other) + : value(other.value), attributes(other.attributes), + parent_instance(other.parent_instance), full_name(other.full_name), + is_section(other.is_section), children(other.children), is_value(other.is_value), + value_used(other.value_used) { + + // Ensure that this is the parent of all children, + // otherwise will point to the original Options instance + for (auto &child : children) { + child.second.parent_instance = this; + } + } + /// Get a reference to the only root instance static Options &root(); @@ -205,6 +219,32 @@ public: return inputvalue; } + /// Copy assignment + /// + /// This replaces the value, attributes and all children + /// + /// Note that if only the value is desired, then that can be copied using + /// the value member directly e.g. option2.value = option1.value; + /// + Options& operator=(const Options& other) { + // Note: Here can't do copy-and-swap because pointers to parents are stored + + value = other.value; + attributes = other.attributes; + full_name = other.full_name; + is_section = other.is_section; + children = other.children; + is_value = other.is_value; + value_used = other.value_used; + + // Ensure that this is the parent of all children, + // otherwise will point to the original Options instance + for (auto &child : children) { + child.second.parent_instance = this; + } + return *this; + } + /// Assign a value to the option. /// This will throw an exception if already has a value /// @@ -220,7 +260,7 @@ public: ss << val; _set(ss.str(), source, false); } - + /// Force to a value /// Overwrites any existing setting template diff --git a/tests/unit/sys/test_options.cxx b/tests/unit/sys/test_options.cxx index 732c5c5016..1c21b2a8ff 100644 --- a/tests/unit/sys/test_options.cxx +++ b/tests/unit/sys/test_options.cxx @@ -477,3 +477,110 @@ TEST_F(OptionsTest, OptionsMacroConstReference) { EXPECT_EQ(val, 42); } +/// Copy constructor copies value +TEST_F(OptionsTest, CopyOption) { + Options option1; + + option1 = 42; + + Options option2(option1); + + EXPECT_EQ(option2.as(), 42); +} + +/// Copy constructor makes independent copy +TEST_F(OptionsTest, CopyOptionDistinct) { + Options option1; + option1 = 42; + + Options option2(option1); + + option1.force(23); + + EXPECT_EQ(option1.as(), 23); + EXPECT_EQ(option2.as(), 42); +} + +/// Copies of sections get values +TEST_F(OptionsTest, CopySection) { + Options option1; + + option1["key"] = 42; // option1 now a section + + Options option2(option1); + + EXPECT_EQ(option2["key"].as(), 42); +} + +/// The parent should be updated when copied +TEST_F(OptionsTest, CopySectionParent) { + Options option1; + + option1["key"] = 42; + + Options option2(option1); + + EXPECT_TRUE( &option2["key"].parent() == &option2 ); +} + +TEST_F(OptionsTest, AssignOption) { + Options option1, option2; + + option1 = 42; + + option2 = option1; + + EXPECT_EQ(option2.as(), 42); +} + +TEST_F(OptionsTest, AssignSection) { + Options option1, option2; + + option1["key"] = 42; + + option2 = option1; + + EXPECT_EQ(option2["key"].as(), 42); +} + +TEST_F(OptionsTest, AssignSectionReplace) { + Options option1, option2; + + option1["key"] = 42; + option2["key"] = 23; + + option2 = option1; + + EXPECT_EQ(option2["key"].as(), 42); +} + +TEST_F(OptionsTest, AssignSectionParent) { + Options option1, option2; + + option1["key"] = 42; + + option2 = option1; + + EXPECT_TRUE( &option2["key"].parent() == &option2 ); +} + +TEST_F(OptionsTest, AssignSubSection) { + Options option1, option2; + + option1["key1"] = 42; + + option2["key2"] = option1; + + EXPECT_EQ(option2["key2"]["key1"].as(), 42); +} + +TEST_F(OptionsTest, AssignSubSectionParent) { + Options option1, option2; + + option1["key1"] = 42; + + option2["key2"] = option1; + + EXPECT_EQ(&option2["key2"].parent(), &option2); + EXPECT_EQ(&option2["key2"]["key1"].parent(), &option2["key2"]); +} From a94d99ac0832b6d086f784848ecba01a02fd0e77 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 08:40:22 +0000 Subject: [PATCH 0425/1783] Initialise some InvertableOperator members --- include/bout/invertable_operator.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index fa7825b550..cfeab3021c 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -427,8 +427,8 @@ private: function_signature preconditionerFunction = identity; // Internal types - Options* opt; // Do we need this? - Mesh* localmesh; //< To ensure we can create T on the right mesh + Options* opt = nullptr; // Do we need this? + Mesh* localmesh = nullptr; //< To ensure we can create T on the right mesh bool doneSetup = false; // To ensure PETSc has been setup -- a bit noisy if creating/destroying From ba4189ca5a47bdd1d080df6c4a936e8ceffc3c67 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 11 Dec 2018 09:48:32 +0000 Subject: [PATCH 0426/1783] Check locations are the same in ShiftedMetric::shiftZ(Field3D,Field2D) --- src/mesh/parallel/shiftedmetric.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index fc81e9fbe7..1d0c119dc4 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -181,6 +181,7 @@ void ShiftedMetric::shiftZ(const BoutReal *in, const std::vector &phs, //Old approach retained so we can still specify a general zShift const Field3D ShiftedMetric::shiftZ(const Field3D &f, const Field2D &zangle) { ASSERT1(&mesh == f.getMesh()); + ASSERT1(f.getLocation() == zangle.getLocation()); if(mesh.LocalNz == 1) return f; // Shifting makes no difference From 0b47f397303bfb23ed67aa8408f14a4df6a5e871 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 11 Dec 2018 09:57:34 +0000 Subject: [PATCH 0427/1783] Check Mesh and location in ShiftedMetric::calcYUpDown() --- src/mesh/parallel/shiftedmetric.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 1d0c119dc4..91a858b87d 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -104,6 +104,9 @@ ShiftedMetric::ShiftedMetric(Mesh &m) : mesh(m), zShift(&m) { * Calculate the Y up and down fields */ void ShiftedMetric::calcYUpDown(Field3D &f) { + ASSERT1(&mesh == f.getMesh()); + ASSERT1(f.getLocation() == CELL_CENTRE); // only have zShift for CELL_CENTRE, so can only deal with CELL_CENTRE inputs + f.splitYupYdown(); Field3D& yup = f.yup(); From 39df79a76577011814c9496c80b7fb7260bd94da Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 11 Dec 2018 10:01:23 +0000 Subject: [PATCH 0428/1783] Check Mesh and location in FCI::calcYUpDown, FCI::integrateYUpDown --- src/mesh/parallel/fci.cxx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 25002ffed3..eeb1d96b46 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -296,6 +296,12 @@ const Field3D FCIMap::integrate(Field3D &f) const { void FCITransform::calcYUpDown(Field3D &f) { TRACE("FCITransform::calcYUpDown"); + ASSERT1(f.getMesh() == &mesh); + + // Only have forward_map/backward_map for CELL_CENTRE, so can only deal with + // CELL_CENTRE inputs + ASSERT1(f.getLocation() == CELL_CENTRE); + // Ensure that yup and ydown are different fields f.splitYupYdown(); @@ -307,6 +313,12 @@ void FCITransform::calcYUpDown(Field3D &f) { void FCITransform::integrateYUpDown(Field3D &f) { TRACE("FCITransform::integrateYUpDown"); + ASSERT1(f.getMesh() == &mesh); + + // Only have forward_map/backward_map for CELL_CENTRE, so can only deal with + // CELL_CENTRE inputs + ASSERT1(f.getLocation() == CELL_CENTRE); + // Ensure that yup and ydown are different fields f.splitYupYdown(); From b85fb8894d594f35cd0d426afe01a2228574e4ba Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 10:52:53 +0000 Subject: [PATCH 0429/1783] Fix Delp2(FieldPerp) for MXG/=2 --- src/mesh/coordinates.cxx | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index f247be5754..77667a0d3d 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -777,12 +777,15 @@ const Field2D Coordinates::Delp2(const Field2D &f, CELL_LOC outloc) { return result; } -const Field3D Coordinates::Delp2(const Field3D &f, CELL_LOC outloc) { +const Field3D Coordinates::Delp2(const Field3D &f, CELL_LOC outloc, bool useFFT) { TRACE("Coordinates::Delp2( Field3D )"); + if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } + ASSERT1(location == outloc); + ASSERT2(f.getLocation() == outloc); if (localmesh->GlobalNx == 1 && localmesh->GlobalNz == 1) { // copy mesh, location, etc @@ -790,11 +793,9 @@ const Field3D Coordinates::Delp2(const Field3D &f, CELL_LOC outloc) { } ASSERT2(localmesh->xstart > 0); // Need at least one guard cell - ASSERT2(f.getLocation() == outloc); - Field3D result(localmesh); result.allocate(); - result.setLocation(f.getLocation()); + result.setLocation(outloc); int ncz = localmesh->LocalNz; @@ -812,12 +813,12 @@ const Field3D Coordinates::Delp2(const Field3D &f, CELL_LOC outloc) { // Loop over kz for (int jz = 0; jz <= ncz / 2; jz++) { - dcomplex a, b, c; // No smoothing in the x direction for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { // Perform x derivative + dcomplex a, b, c; laplace_tridag_coefs(jx, jy, jz, a, b, c, nullptr, nullptr, outloc); delft(jx, jz) = a * ft(jx - 1, jz) + b * ft(jx, jz) + c * ft(jx + 1, jz); @@ -849,11 +850,19 @@ const Field3D Coordinates::Delp2(const Field3D &f, CELL_LOC outloc) { const FieldPerp Coordinates::Delp2(const FieldPerp &f, CELL_LOC outloc) { TRACE("Coordinates::Delp2( FieldPerp )"); - if (outloc == CELL_DEFAULT) outloc = f.getLocation(); + if (outloc == CELL_DEFAULT) { + outloc = f.getLocation(); + } ASSERT1(location == outloc); ASSERT2(f.getLocation() == outloc); + if (localmesh->GlobalNx == 1 && localmesh->GlobalNz == 1) { + // copy mesh, location, etc + return f * 0; + } + ASSERT2(localmesh->xstart > 0); // Need at least one guard cell + FieldPerp result(localmesh); result.allocate(); result.setLocation(outloc); @@ -875,7 +884,7 @@ const FieldPerp Coordinates::Delp2(const FieldPerp &f, CELL_LOC outloc) { for (int jz = 0; jz <= ncz / 2; jz++) { // No smoothing in the x direction - for (int jx = 2; jx < (localmesh->LocalNx - 2); jx++) { + for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { // Perform x derivative dcomplex a, b, c; @@ -886,14 +895,18 @@ const FieldPerp Coordinates::Delp2(const FieldPerp &f, CELL_LOC outloc) { } // Reverse FFT - for (int jx = 1; jx < (localmesh->LocalNx - 1); jx++) { + for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { irfft(&delft(jx, 0), ncz, &result(jx, 0)); } // Boundaries for (int jz = 0; jz < ncz; jz++) { - result(0, jz) = 0.0; - result(localmesh->LocalNx - 1, jz) = 0.0; + for (int jx = 0; jx < localmesh->xstart; jx++) { + result(jx, jz) = 0.0; + } + for (int jx = localmesh->xend + 1; jx < localmesh->LocalNx; jx++) { + result(jx, jy, jz) = 0.0; + } } return result; From 9df370c77796c0735092278a1b03c84443ad18d4 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 10:55:53 +0000 Subject: [PATCH 0430/1783] Remove unused zsmooth input to Delp2 and add useFFT flag Currently useFFT is ignored --- examples/hasegawa-wakatani/hw.cxx | 6 +++--- examples/lapd-drift/lapd_drift.cxx | 8 ++++---- include/bout/coordinates.hxx | 11 +++++++---- include/difops.hxx | 7 ++++--- src/mesh/coordinates.cxx | 6 +++--- src/mesh/difops.cxx | 12 ++++++------ 6 files changed, 27 insertions(+), 23 deletions(-) diff --git a/examples/hasegawa-wakatani/hw.cxx b/examples/hasegawa-wakatani/hw.cxx index 891ef6f18a..e55987fa99 100644 --- a/examples/hasegawa-wakatani/hw.cxx +++ b/examples/hasegawa-wakatani/hw.cxx @@ -24,11 +24,11 @@ class HW : public PhysicsModel { // Simple implementation of 4th order perpendicular Laplacian Field3D Delp4(const Field3D &var) { Field3D tmp; - tmp = Delp2(var, 0.0); + tmp = Delp2(var); mesh->communicate(tmp); tmp.applyBoundary("neumann"); - return Delp2(tmp, 0.0); - + return Delp2(tmp); + //return Delp2(var); } diff --git a/examples/lapd-drift/lapd_drift.cxx b/examples/lapd-drift/lapd_drift.cxx index 4628f93395..1ccef281d1 100644 --- a/examples/lapd-drift/lapd_drift.cxx +++ b/examples/lapd-drift/lapd_drift.cxx @@ -548,7 +548,7 @@ class LAPDdrift : public PhysicsModel { } if (ni_diff) { - ddt(ni) += ni_perpdiff * Delp2(ni,-1.0); + ddt(ni) += ni_perpdiff * Delp2(ni); } if (evolve_source_ni) { @@ -577,11 +577,11 @@ class LAPDdrift : public PhysicsModel { } if (rho_rho1) { - ddt(rho) += mu_i*Delp2(rho,-1.0); //Check second argument meaning in difops.cpp + ddt(rho) += mu_i * Delp2(rho); // Check second argument meaning in difops.cpp } if (rho_diff) { - ddt(rho) += rho_perpdiff * Delp2(rho,-1.0); + ddt(rho) += rho_perpdiff * Delp2(rho); } if (rho_rho1_phi1) { @@ -684,7 +684,7 @@ class LAPDdrift : public PhysicsModel { } if (te_diff) { - ddt(te) += te_perpdiff * Delp2(te,-1.0); + ddt(te) += te_perpdiff * Delp2(te); } if (remove_tor_av_te) { diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index 7922be9d0b..6b2a098239 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -180,10 +180,13 @@ public: // Perpendicular Laplacian operator, using only X-Z derivatives // NOTE: This might be better bundled with the Laplacian inversion code // since it makes use of the same coefficients and FFT routines - const Field2D Delp2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT); - const Field3D Delp2(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT); - const FieldPerp Delp2(const FieldPerp &f, CELL_LOC outloc=CELL_DEFAULT); - + const Field2D Delp2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + bool useFFT = true); + const Field3D Delp2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + bool useFFT = true); + const FieldPerp Delp2(const FieldPerp& f, CELL_LOC outloc = CELL_DEFAULT, + bool useFFT = true); + // Full parallel Laplacian operator on scalar field // Laplace_par(f) = Div( b (b dot Grad(f)) ) const Field2D Laplace_par(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT); diff --git a/include/difops.hxx b/include/difops.hxx index 79c5328242..f636b06fb0 100644 --- a/include/difops.hxx +++ b/include/difops.hxx @@ -257,9 +257,10 @@ const Field3D Div_par_K_Grad_par(const Field3D &kY, const Field3D &f, CELL_LOC o * * For the full perpendicular Laplacian, use Laplace_perp */ -const Field2D Delp2(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT); -const Field3D Delp2(const Field3D &f, BoutReal zsmooth=-1.0, CELL_LOC outloc=CELL_DEFAULT); -const FieldPerp Delp2(const FieldPerp &f, BoutReal zsmooth=-1.0, CELL_LOC outloc=CELL_DEFAULT); +const Field2D Delp2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, bool useFFT = true); +const Field3D Delp2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, bool useFFT = true); +const FieldPerp Delp2(const FieldPerp& f, CELL_LOC outloc = CELL_DEFAULT, + bool useFFT = true); /*! * Perpendicular Laplacian, keeping y derivatives diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 77667a0d3d..45f19ede2a 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -768,7 +768,7 @@ const Field3D Coordinates::Grad2_par2(const Field3D &f, CELL_LOC outloc, const s #include // Delp2 uses same coefficients as inversion code -const Field2D Coordinates::Delp2(const Field2D &f, CELL_LOC outloc) { +const Field2D Coordinates::Delp2(const Field2D& f, CELL_LOC outloc, bool useFFT) { TRACE("Coordinates::Delp2( Field2D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); @@ -777,7 +777,7 @@ const Field2D Coordinates::Delp2(const Field2D &f, CELL_LOC outloc) { return result; } -const Field3D Coordinates::Delp2(const Field3D &f, CELL_LOC outloc, bool useFFT) { +const Field3D Coordinates::Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) { TRACE("Coordinates::Delp2( Field3D )"); if (outloc == CELL_DEFAULT) { @@ -847,7 +847,7 @@ const Field3D Coordinates::Delp2(const Field3D &f, CELL_LOC outloc, bool useFFT) return result; } -const FieldPerp Coordinates::Delp2(const FieldPerp &f, CELL_LOC outloc) { +const FieldPerp Coordinates::Delp2(const FieldPerp& f, CELL_LOC outloc, bool useFFT) { TRACE("Coordinates::Delp2( FieldPerp )"); if (outloc == CELL_DEFAULT) { diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index d271a4cda1..399ef9a047 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -552,16 +552,16 @@ const Field3D Div_par_K_Grad_par(const Field3D &kY, const Field3D &f, CELL_LOC o * perpendicular Laplacian operator *******************************************************************************/ -const Field2D Delp2(const Field2D &f, CELL_LOC outloc) { - return f.getCoordinates(outloc)->Delp2(f, outloc); +const Field2D Delp2(const Field2D& f, CELL_LOC outloc, bool useFFT) { + return f.getCoordinates(outloc)->Delp2(f, outloc, useFFT); } -const Field3D Delp2(const Field3D &f, BoutReal UNUSED(zsmooth), CELL_LOC outloc) { - return f.getCoordinates(outloc)->Delp2(f, outloc); +const Field3D Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) { + return f.getCoordinates(outloc)->Delp2(f, outloc, useFFT); } -const FieldPerp Delp2(const FieldPerp &f, BoutReal UNUSED(zsmooth), CELL_LOC outloc) { - return f.getCoordinates(outloc)->Delp2(f, outloc); +const FieldPerp Delp2(const FieldPerp& f, CELL_LOC outloc, bool useFFT) { + return f.getCoordinates(outloc)->Delp2(f, outloc, useFFT); } /******************************************************************************* From a131004eabb081231f0ff49fad350ea5507b14e5 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 11:01:15 +0000 Subject: [PATCH 0431/1783] Implement non-fft based Delp2 for Field3D and FieldPerp Note FieldPerp version currently throws as we don't provide standard derivative operators for FieldPerp --- src/mesh/coordinates.cxx | 134 ++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 59 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 45f19ede2a..0d65834b17 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -797,52 +797,57 @@ const Field3D Coordinates::Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) result.allocate(); result.setLocation(outloc); - int ncz = localmesh->LocalNz; + if (useFFT) { + int ncz = localmesh->LocalNz; - // Allocate memory - auto ft = Matrix(localmesh->LocalNx, ncz / 2 + 1); - auto delft = Matrix(localmesh->LocalNx, ncz / 2 + 1); + // Allocate memory + auto ft = Matrix(localmesh->LocalNx, ncz / 2 + 1); + auto delft = Matrix(localmesh->LocalNx, ncz / 2 + 1); - // Loop over all y indices - for (int jy = 0; jy < localmesh->LocalNy; jy++) { + // Loop over all y indices + for (int jy = 0; jy < localmesh->LocalNy; jy++) { - // Take forward FFT + // Take forward FFT - for (int jx = 0; jx < localmesh->LocalNx; jx++) - rfft(&f(jx, jy, 0), ncz, &ft(jx, 0)); + for (int jx = 0; jx < localmesh->LocalNx; jx++) + rfft(&f(jx, jy, 0), ncz, &ft(jx, 0)); - // Loop over kz - for (int jz = 0; jz <= ncz / 2; jz++) { + // Loop over kz + for (int jz = 0; jz <= ncz / 2; jz++) { - // No smoothing in the x direction - for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { - // Perform x derivative + // No smoothing in the x direction + for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { + // Perform x derivative - dcomplex a, b, c; - laplace_tridag_coefs(jx, jy, jz, a, b, c, nullptr, nullptr, outloc); + dcomplex a, b, c; + laplace_tridag_coefs(jx, jy, jz, a, b, c, nullptr, nullptr, outloc); - delft(jx, jz) = a * ft(jx - 1, jz) + b * ft(jx, jz) + c * ft(jx + 1, jz); + delft(jx, jz) = a * ft(jx - 1, jz) + b * ft(jx, jz) + c * ft(jx + 1, jz); + } } - } - - // Reverse FFT - for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { - irfft(&delft(jx, 0), ncz, &result(jx, jy, 0)); - } + // Reverse FFT + for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { - // Boundaries - for (int jz = 0; jz < ncz; jz++) { - for (int jx = 0; jx < localmesh->xstart; jx++) { - result(jx, jy, jz) = 0.0; + irfft(&delft(jx, 0), ncz, &result(jx, jy, 0)); } - for (int jx = localmesh->xend + 1; jx < localmesh->LocalNx; jx++) { - result(jx, jy, jz) = 0.0; + + // Boundaries + for (int jz = 0; jz < ncz; jz++) { + for (int jx = 0; jx < localmesh->xstart; jx++) { + result(jx, jy, jz) = 0.0; + } + for (int jx = localmesh->xend + 1; jx < localmesh->LocalNx; jx++) { + result(jx, jy, jz) = 0.0; + } } } - } + } else { + result = G1 * ::DDX(f, outloc) + G3 * ::DDZ(f, outloc) + g11 * ::D2DX2(f, outloc) + + g33 * ::D2DZ2(f, outloc) + 2 * g13 * ::D2DXDZ(f, outloc); + }; - ASSERT2(result.getLocation() == f.getLocation()); + ASSERT2(result.getLocation() == outloc); return result; } @@ -870,44 +875,53 @@ const FieldPerp Coordinates::Delp2(const FieldPerp& f, CELL_LOC outloc, bool use int jy = f.getIndex(); result.setIndex(jy); - int ncz = localmesh->LocalNz; + if (useFFT) { + int ncz = localmesh->LocalNz; - // Allocate memory - auto ft = Matrix(localmesh->LocalNx, ncz / 2 + 1); - auto delft = Matrix(localmesh->LocalNx, ncz / 2 + 1); + // Allocate memory + auto ft = Matrix(localmesh->LocalNx, ncz / 2 + 1); + auto delft = Matrix(localmesh->LocalNx, ncz / 2 + 1); - // Take forward FFT - for (int jx = 0; jx < localmesh->LocalNx; jx++) - rfft(&f(jx, 0), ncz, &ft(jx, 0)); + // Take forward FFT + for (int jx = 0; jx < localmesh->LocalNx; jx++) + rfft(&f(jx, 0), ncz, &ft(jx, 0)); - // Loop over kz - for (int jz = 0; jz <= ncz / 2; jz++) { + // Loop over kz + for (int jz = 0; jz <= ncz / 2; jz++) { - // No smoothing in the x direction - for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { - // Perform x derivative + // No smoothing in the x direction + for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { + // Perform x derivative - dcomplex a, b, c; - laplace_tridag_coefs(jx, jy, jz, a, b, c); + dcomplex a, b, c; + laplace_tridag_coefs(jx, jy, jz, a, b, c); - delft(jx, jz) = a * ft(jx - 1, jz) + b * ft(jx, jz) + c * ft(jx + 1, jz); + delft(jx, jz) = a * ft(jx - 1, jz) + b * ft(jx, jz) + c * ft(jx + 1, jz); + } } - } - // Reverse FFT - for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { - irfft(&delft(jx, 0), ncz, &result(jx, 0)); - } - - // Boundaries - for (int jz = 0; jz < ncz; jz++) { - for (int jx = 0; jx < localmesh->xstart; jx++) { - result(jx, jz) = 0.0; + // Reverse FFT + for (int jx = localmesh->xstart; jx <= localmesh->xend; jx++) { + irfft(&delft(jx, 0), ncz, &result(jx, 0)); } - for (int jx = localmesh->xend + 1; jx < localmesh->LocalNx; jx++) { - result(jx, jy, jz) = 0.0; + + // Boundaries + for (int jz = 0; jz < ncz; jz++) { + for (int jx = 0; jx < localmesh->xstart; jx++) { + result(jx, jz) = 0.0; + } + for (int jx = localmesh->xend + 1; jx < localmesh->LocalNx; jx++) { + result(jx, jy, jz) = 0.0; + } } - } + + } else { + throw BoutException("Non-fourier Delp2 not currently implented for FieldPerp."); + // Would be the following but don't have standard derivative operators for FieldPerps + // yet + // result = G1 * ::DDX(f, outloc) + G3 * ::DDZ(f, outloc) + g11 * ::D2DX2(f, outloc) + // + g33 * ::D2DZ2(f, outloc) + 2 * g13 * ::D2DXDZ(f, outloc); + }; return result; } @@ -931,6 +945,8 @@ const Field2D Coordinates::Laplace(const Field2D &f, CELL_LOC outloc) { Field2D result = G1 * DDX(f, outloc) + G2 * DDY(f, outloc) + g11 * D2DX2(f, outloc) + g22 * D2DY2(f, outloc) + 2.0 * g12 * D2DXDY(f, outloc); + ASSERT2(result.getLocation() == outloc); + return result; } From 3fb3d1042e601e8143af51108d9c294c8fb56ebe Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 11:36:47 +0000 Subject: [PATCH 0432/1783] Add non-fft cases to test-delp2 --- tests/integrated/test-delp2/runtest | 5 +++-- tests/integrated/test-delp2/test_delp2.cxx | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/integrated/test-delp2/runtest b/tests/integrated/test-delp2/runtest index 1df61b0651..bfdf18c095 100755 --- a/tests/integrated/test-delp2/runtest +++ b/tests/integrated/test-delp2/runtest @@ -21,8 +21,9 @@ shell_safe("make > make.log") exefile = "./test_delp2" # List of settings to apply -settings = ["mxg=2 mesh:nx=36", - "mxg=1 mesh:nx=34"] +settings = ["mxg=2 mesh:nx=36 diffusion:useFFT=true", + "mxg=1 mesh:nx=34 diffusion:useFFT=true", "mxg=2 mesh:nx=36 diffusion:useFFT=false", + "mxg=1 mesh:nx=34 diffusion:useFFT=false"] success = True diff --git a/tests/integrated/test-delp2/test_delp2.cxx b/tests/integrated/test-delp2/test_delp2.cxx index 9206a5e959..283b314bff 100644 --- a/tests/integrated/test-delp2/test_delp2.cxx +++ b/tests/integrated/test-delp2/test_delp2.cxx @@ -7,7 +7,8 @@ class TestDelp2 : public PhysicsModel { int init(bool UNUSED(restarting)) { Options *opt = Options::getRoot()->getSection("diffusion"); OPTION(opt, D, 0.1); - + OPTION(opt, useFFT, true); + SOLVE_FOR(n); return 0; @@ -15,15 +16,16 @@ class TestDelp2 : public PhysicsModel { int rhs(BoutReal UNUSED(t)) { mesh->communicate(n); - - ddt(n) = D * Delp2(n); - + + ddt(n) = D * Delp2(n, CELL_DEFAULT, useFFT); + return 0; } private: Field3D n; BoutReal D; + bool useFFT; }; BOUTMAIN(TestDelp2); From 4e47eedfaf7748eccabdad5ea1d3c0276a3305cd Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 12:25:18 +0000 Subject: [PATCH 0433/1783] Remove zeroing of boundaries in Delp2 This could hide incorrect uses of the guard cells before required communication/boundary conditions --- examples/lapd-drift/lapd_drift.cxx | 2 +- src/mesh/coordinates.cxx | 24 ++---------------------- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/examples/lapd-drift/lapd_drift.cxx b/examples/lapd-drift/lapd_drift.cxx index 1ccef281d1..3421a313f1 100644 --- a/examples/lapd-drift/lapd_drift.cxx +++ b/examples/lapd-drift/lapd_drift.cxx @@ -577,7 +577,7 @@ class LAPDdrift : public PhysicsModel { } if (rho_rho1) { - ddt(rho) += mu_i * Delp2(rho); // Check second argument meaning in difops.cpp + ddt(rho) += mu_i * Delp2(rho); } if (rho_diff) { diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 0d65834b17..3018ed6eac 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -785,7 +785,7 @@ const Field3D Coordinates::Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) } ASSERT1(location == outloc); - ASSERT2(f.getLocation() == outloc); + ASSERT1(f.getLocation() == outloc); if (localmesh->GlobalNx == 1 && localmesh->GlobalNz == 1) { // copy mesh, location, etc @@ -831,16 +831,6 @@ const Field3D Coordinates::Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) irfft(&delft(jx, 0), ncz, &result(jx, jy, 0)); } - - // Boundaries - for (int jz = 0; jz < ncz; jz++) { - for (int jx = 0; jx < localmesh->xstart; jx++) { - result(jx, jy, jz) = 0.0; - } - for (int jx = localmesh->xend + 1; jx < localmesh->LocalNx; jx++) { - result(jx, jy, jz) = 0.0; - } - } } } else { result = G1 * ::DDX(f, outloc) + G3 * ::DDZ(f, outloc) + g11 * ::D2DX2(f, outloc) @@ -860,7 +850,7 @@ const FieldPerp Coordinates::Delp2(const FieldPerp& f, CELL_LOC outloc, bool use } ASSERT1(location == outloc); - ASSERT2(f.getLocation() == outloc); + ASSERT1(f.getLocation() == outloc); if (localmesh->GlobalNx == 1 && localmesh->GlobalNz == 1) { // copy mesh, location, etc @@ -905,16 +895,6 @@ const FieldPerp Coordinates::Delp2(const FieldPerp& f, CELL_LOC outloc, bool use irfft(&delft(jx, 0), ncz, &result(jx, 0)); } - // Boundaries - for (int jz = 0; jz < ncz; jz++) { - for (int jx = 0; jx < localmesh->xstart; jx++) { - result(jx, jz) = 0.0; - } - for (int jx = localmesh->xend + 1; jx < localmesh->LocalNx; jx++) { - result(jx, jy, jz) = 0.0; - } - } - } else { throw BoutException("Non-fourier Delp2 not currently implented for FieldPerp."); // Would be the following but don't have standard derivative operators for FieldPerps From f79b6b7b41ea32371a30fef17fad290467d311b6 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 12:28:17 +0000 Subject: [PATCH 0434/1783] Remove zsmoothing from Delp2 in boutcore --- tools/pylib/_boutcore_build/boutcore.pyx.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index a966ef6495..4c67e1a5f9 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -1216,10 +1216,10 @@ def Laplace(Field3D a): checkInit() return f3dFromObj(c.Laplace(a.cobj[0])) -def Delp2(Field3D a, zsmooth=-1): -# """Delp2(Field3D a, zsmooth=-1)""" +def Delp2(Field3D a): +# """Delp2(Field3D a)""" checkInit() - return f3dFromObj(c.Delp2(a.cobj[0],float(zsmooth))) + return f3dFromObj(c.Delp2(a.cobj[0])) def Grad_perp_dot_Grad_perp(Field3D a, Field3D b): """ From 784f5eef226b8c98899dccf4413e01cb82bf2a7f Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 12:45:57 +0000 Subject: [PATCH 0435/1783] Add some initial rough documentation about InvertableOperator --- .../sphinx/user_docs/invertable_operator.rst | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 manual/sphinx/user_docs/invertable_operator.rst diff --git a/manual/sphinx/user_docs/invertable_operator.rst b/manual/sphinx/user_docs/invertable_operator.rst new file mode 100644 index 0000000000..1f94ca2066 --- /dev/null +++ b/manual/sphinx/user_docs/invertable_operator.rst @@ -0,0 +1,147 @@ +.. _sec-invertable: + +Invertable operators +==================== + +A common problem in physics models is solve a matrix equation of the +form + +.. math:: + + \underline{\underline{A}} \cdot \underline{x} = \underline{b} + +for the unknown :math:`\underline{x}`. Here +:math:`\underline{\underline{A}}` represents some differential +operator subject to boundary conditions. A specific example is the set +of Laplacian operators described in :ref:`sec-laplacian`. + +Whilst specific tools are provided to deal with Laplacian and parallel +Helmholtz like equations these do not capture all possible systems and +are typically implemented (at least partially) independently of the +finite difference representation of the forward operators provided by +the rest of BOUT++. To address this a class `InvertableOperator` has +been implemented that allows the user to define a generic differential +operator and provides a simple (for the user) method to invert the +operator to find :math:`\underline{x}`. This class currently relies on +PETSc to provide the inversion functionality and hence is not +available when configuring without PETSc support. + +There is an example in `examples/invertable_operator` that uses the +class to solve a simple Laplacian operator and compares to the +specific Laplacian inversion solvers. + +The `InvertableOperator` class is templated on the field type of the +operator (essentially defining the domain over which the problem +exists). To define the operator that the `InvertableOperator` +instances represents one should use the +`InvertableOperator::setOperatorFunction` method. This takes a function +of signature ``std::function``. This can be a ``std::function``, compatible function pointer, lambda or a functor. The last of these allows more complicated functions that use a local context. For example the following code snippet demonstrates a functor that stores several auxilliary ``Field3D`` variables used in the ``operator()`` call:: + + struct myLaplacian { + Field3D D = 1.0, C = 1.0, A = 0.0; + + // Drop C term for now + Field3D operator()(const Field3D &input) { + TRACE("myLaplacian::operator()"); + Timer timer("invertable_operator_operate"); + Field3D result = A * input + D * Delp2(input); + + // Ensure boundary points are set appropriately as given by the input field. + result.setBoundaryTo(input); + + return result; + }; + }; + + + +A more complete example is :: + + struct myLaplacian { + Field3D D = 1.0, C = 1.0, A = 0.0; + + // Drop C term for now + Field3D operator()(const Field3D &input) { + TRACE("myLaplacian::operator()"); + Timer timer("invertable_operator_operate"); + Field3D result = A * input + D * Delp2(input); + + // Ensure boundary points are set appropriately as given by the input field. + result.setBoundaryTo(input); + + return result; + }; + }; + + InveratbleOperator solver; + myLaplacian laplacianOperator; + laplacianOperator.A = 1.0; + laplacianOperator.B = 2.0; + + // Set the function defining the operator + solver.setOperatorFunction(laplacianOperator); + + // Perform initial setup + solver.setup(); + + // Now invert the operator for a given right hand side. + Field3D rhs = 3.0*x; + auto solution = solver.invert(rhs); + + +The PETSc backend solver is an iterative solver. It can be controlled +through the usual PETSc command line options. Note we define the +options prefix here to be `-invertable`, so instead of `-ksp_type` one +would use `-invertable_ksp_type` for example. + +By default the solver caches the result to use as the initial guess +for the next call to ``invert``. There is an overload of ``invert`` +that takes a second field, which is used to set the initial guess to +use in that call. + +The routine ``setOperatorFunction`` takes the function by value, and +hence subsequent changes to the functor will not be reflected in the +operator without a further call to ``setOperatorFunction``. For +example:: + + InveratbleOperator solver; + myLaplacian laplacianOperator; + laplacianOperator.A = 1.0; + laplacianOperator.B = 2.0; + + // Set the function defining the operator + solver.setOperatorFunction(laplacianOperator); + + // Perform initial setup + solver.setup(); + + // This does not change the operator represented by + // solver yet. + laplacianOperator.B = -1.0; + + // This call updates the function used by solver + // and hence the operator is update to reflect the state + // of laplacianOperator. + solver.setOperatorFunction(laplacianOperator); + +The class provides a ``reportTime`` method that reports the time spent +in various parts of the class. Note that by including ``Timer +timer("invertable_operator_operate");`` in the function representing +the operator ``reportTime`` will include the time spent actually +applying the operator. + +The class provides both ``apply`` and ``operator()`` methods that can +be used to apply the operator to a field. For example the following +should be equivalent to no operation:: + + // Here result should == input, at least in the main simulation domain + auto result = solver(solver.invert(input)); + + +The class provides a ``verify`` method that checks that applying the +operator to the calculated inverse returns the input field within some +tolerance. + +It's also possible to register a function to use as a +preconditioner. By default this is the same as the full operator +function. From db6be770254cca7fc76268096725ae4456080060 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 14:59:53 +0000 Subject: [PATCH 0436/1783] Remove zsmooth in one more place in boutcore --- tools/pylib/_boutcore_build/boutcpp.pxd.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pylib/_boutcore_build/boutcpp.pxd.in b/tools/pylib/_boutcore_build/boutcpp.pxd.in index 36142a16f8..f5342511c3 100755 --- a/tools/pylib/_boutcore_build/boutcpp.pxd.in +++ b/tools/pylib/_boutcore_build/boutcpp.pxd.in @@ -112,7 +112,7 @@ cdef extern from "difops.hxx": Field3D Laplace(Field3D) Field3D Vpar_Grad_par(Field3D, Field3D, benum.CELL_LOC, benum.DIFF_METHOD) Field3D bracket(Field3D,Field3D, benum.BRACKET_METHOD, benum.CELL_LOC) - Field3D Delp2(Field3D,double) + Field3D Delp2(Field3D) cdef extern from "options.hxx": cppclass Options: From edfc386a2d86d4e1d58ab4d1c89b939ed1a0df40 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 15:31:10 +0000 Subject: [PATCH 0437/1783] Be more explicit about how many threads to use in some tests. Don't force mthread=1 in all tests as we would then not test OpenMP sections very effectively. A balance between testing more things with OpenMP and resources consumed on travis etc. --- tests/integrated/test-cyclic/runtest | 2 +- tests/integrated/test-delp2/runtest | 2 +- tests/integrated/test-fci-slab/runtest | 4 ++-- tests/integrated/test-invpar/runtest | 2 +- tests/integrated/test-laplace/runtest | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/integrated/test-cyclic/runtest b/tests/integrated/test-cyclic/runtest index 884a68dc57..b9043f71ec 100755 --- a/tests/integrated/test-cyclic/runtest +++ b/tests/integrated/test-cyclic/runtest @@ -32,7 +32,7 @@ for nproc in [1,2,4]: shell("rm data/BOUT.dmp.* 2> err.log") # Run the case - s, out = launch_safe(cmd+" "+f, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd+" "+f, runcmd=MPIRUN, nproc=nproc, mthread=1, pipe=True) with open("run.log."+str(nproc)+"."+str(r), "w") as f: f.write(out) diff --git a/tests/integrated/test-delp2/runtest b/tests/integrated/test-delp2/runtest index 1df61b0651..81eb283f54 100755 --- a/tests/integrated/test-delp2/runtest +++ b/tests/integrated/test-delp2/runtest @@ -42,7 +42,7 @@ for i, opts in enumerate(settings): shell("rm data/BOUT.dmp.*.nc") stdout.write(" %d processor...." % (nproc)) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, mthread=1, pipe=True) with open("run.log."+str(i)+"."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-fci-slab/runtest b/tests/integrated/test-fci-slab/runtest index b87ee5ab67..196b2471f0 100755 --- a/tests/integrated/test-fci-slab/runtest +++ b/tests/integrated/test-fci-slab/runtest @@ -26,7 +26,7 @@ nx = 5 # Not changed for these tests # Resolution in y and z nlist = [64,128] #[8,16,32,64,128,256] -nproc = 4 +nproc = 2 directory = "mms" @@ -79,7 +79,7 @@ for n in nlist: print("Running command: "+cmd) # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, mthread=1, pipe=True) # Save output to log file with open("run.log."+str(n), "w") as f: diff --git a/tests/integrated/test-invpar/runtest b/tests/integrated/test-invpar/runtest index 3c1d24be74..ce853888bc 100755 --- a/tests/integrated/test-invpar/runtest +++ b/tests/integrated/test-invpar/runtest @@ -33,7 +33,7 @@ for nproc in [1,2,4]: shell("rm data/BOUT.dmp.* 2> err.log") # Run the case - s, out = launch_safe(cmd+" "+f, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd+" "+f, runcmd=MPIRUN, nproc=nproc, mthread=1, pipe=True) with open("run.log."+str(nproc)+"."+str(r), "w") as f: f.write(out) diff --git a/tests/integrated/test-laplace/runtest b/tests/integrated/test-laplace/runtest index 81af3da736..d19cbe536d 100755 --- a/tests/integrated/test-laplace/runtest +++ b/tests/integrated/test-laplace/runtest @@ -47,7 +47,7 @@ for nproc in [1,2,4]: shell("rm data/BOUT.dmp.*.nc") print(" %d processors (nxpe = %d)...." % (nproc, nxpe)) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, mthread=1, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) From 8ac595499e29e04a40682bc56615b91f0321eba1 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 16:12:11 +0000 Subject: [PATCH 0438/1783] Make test-stopCheck only test signal based method --- tests/integrated/test-stopCheck/README.md | 8 --- .../test-stopCheck/dataSecond/BOUT.inp | 17 ----- .../test-stopCheck/dataSecond/otherStop.check | 0 tests/integrated/test-stopCheck/runtest | 25 +++++++- tests/integrated/test-stopCheck/runtest1 | 63 ------------------- tests/integrated/test-stopCheck/runtest2 | 24 ------- 6 files changed, 22 insertions(+), 115 deletions(-) delete mode 100644 tests/integrated/test-stopCheck/README.md delete mode 100644 tests/integrated/test-stopCheck/dataSecond/BOUT.inp delete mode 100644 tests/integrated/test-stopCheck/dataSecond/otherStop.check delete mode 100755 tests/integrated/test-stopCheck/runtest1 delete mode 100755 tests/integrated/test-stopCheck/runtest2 diff --git a/tests/integrated/test-stopCheck/README.md b/tests/integrated/test-stopCheck/README.md deleted file mode 100644 index 4fcc735ea2..0000000000 --- a/tests/integrated/test-stopCheck/README.md +++ /dev/null @@ -1,8 +0,0 @@ -Stop check test case -==================== - -This example tests the `stopCheck` functionality by checking that the number of output steps matches the expectations for a run with `stopCheck=false` and one with `stopCheck=true`. - -Note the data*/BOUT.stop file is expected to exist and is not created by the test runner. - -This tests both the behaviour of `checkStop` with default options as well as the behaviour with non-default data_dir and stop file name. \ No newline at end of file diff --git a/tests/integrated/test-stopCheck/dataSecond/BOUT.inp b/tests/integrated/test-stopCheck/dataSecond/BOUT.inp deleted file mode 100644 index c0dd9d8f5e..0000000000 --- a/tests/integrated/test-stopCheck/dataSecond/BOUT.inp +++ /dev/null @@ -1,17 +0,0 @@ -# Test of smoothing operators -# -# Creates some variables, smooths them, then compares -# the results on varying numbers of processors -# - -NOUT = 10 # No timesteps - -MZ = 8 # Z size - -[mesh] -NX = 10 -NY = 3 - -dump_format = "nc" # NetCDF format. Alternative is "pdb" - - diff --git a/tests/integrated/test-stopCheck/dataSecond/otherStop.check b/tests/integrated/test-stopCheck/dataSecond/otherStop.check deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/integrated/test-stopCheck/runtest b/tests/integrated/test-stopCheck/runtest index e3e0364c77..aa0920d087 100755 --- a/tests/integrated/test-stopCheck/runtest +++ b/tests/integrated/test-stopCheck/runtest @@ -1,5 +1,24 @@ -#!/bin/sh +#!/bin/bash -./runtest1 || exit +make || exit -./runtest2 || exit +./test_stopCheck nout=10000 > run.log.signal 2>&1 & + +# stop backgroud process +kill -s USR1 $! + +# wait for background process +wait + +# check number of iteration processed +num=$(ncdump -h data/BOUT.dmp.0.nc |grep UNL|grep [0-9]* -o) + +# make sure not all have been run +if test $num -lt 10000 +then + echo " => Test successful" +else + cat run.log.signal + echo + echo " => Test failed" +fi diff --git a/tests/integrated/test-stopCheck/runtest1 b/tests/integrated/test-stopCheck/runtest1 deleted file mode 100755 index cd7474549e..0000000000 --- a/tests/integrated/test-stopCheck/runtest1 +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python3 - -# -# Run the test, compare results against the benchmark -# - -# Variables to compare -from __future__ import print_function -try: - from builtins import str -except: - pass - -from boututils.run_wrapper import shell, launch, getmpirun -from boutdata.collect import collect -import numpy as np -from sys import stdout, exit - -nproc = 1 - -MPIRUN=getmpirun() - -print("Making stopCheck test") -shell("make > make.log") - -checkVal=[True,False] -nstepExpect=[1,11] -dats = ["data","dataSecond"] -datStopFiles = ["BOUT.stop","otherStop.check"] - -vars=["t_array"] - -print("Running stopCheck test") -success = True - -for j, dat in enumerate(dats): - for i, check in enumerate(checkVal): - cmd = "./test_stopCheck" - - s, out = launch(cmd+" -d "+dat+" stopCheck="+str(check)+" stopCheckName="+datStopFiles[j], runcmd=MPIRUN, nproc=nproc, pipe=True) - f = open("run.log."+dat+"."+str(check).lower(), "w") - f.write(out) - f.close() - - # Collect output data - for v in vars: - result = collect(v, path=dat, info=False) - - # Compare benchmark and output - if result.shape[0] != nstepExpect[i]: - print("Fail, wrong shape") - print("Option is "+str(check)+"/"+dat+"/"+datStopFiles[j]) - print("shape is "+str(result.shape[0])) - print("expecting "+str(nstepExpect[i])) - success = False - continue - -if success: - print(" => All checkStop tests passed") - exit(0) -else: - print(" => Some failed tests") - exit(1) diff --git a/tests/integrated/test-stopCheck/runtest2 b/tests/integrated/test-stopCheck/runtest2 deleted file mode 100755 index aa0920d087..0000000000 --- a/tests/integrated/test-stopCheck/runtest2 +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -make || exit - -./test_stopCheck nout=10000 > run.log.signal 2>&1 & - -# stop backgroud process -kill -s USR1 $! - -# wait for background process -wait - -# check number of iteration processed -num=$(ncdump -h data/BOUT.dmp.0.nc |grep UNL|grep [0-9]* -o) - -# make sure not all have been run -if test $num -lt 10000 -then - echo " => Test successful" -else - cat run.log.signal - echo - echo " => Test failed" -fi From 8de9f710b363cef8477ec73999839e8ff3d972e1 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 16:13:34 +0000 Subject: [PATCH 0439/1783] Add test-stopCheck file to test file based method Don't run this on travis to avoid occasional issue with shared build --- .../integrated/test-stopCheck-file/README.md | 8 +++ .../test-stopCheck-file/data/BOUT.inp | 17 +++++ .../test-stopCheck-file/data/BOUT.stop | 0 .../test-stopCheck-file/dataSecond/BOUT.inp | 17 +++++ .../dataSecond/otherStop.check | 0 tests/integrated/test-stopCheck-file/makefile | 6 ++ tests/integrated/test-stopCheck-file/runtest | 64 +++++++++++++++++++ .../test-stopCheck-file/test_stopCheck.cxx | 21 ++++++ 8 files changed, 133 insertions(+) create mode 100644 tests/integrated/test-stopCheck-file/README.md create mode 100644 tests/integrated/test-stopCheck-file/data/BOUT.inp create mode 100644 tests/integrated/test-stopCheck-file/data/BOUT.stop create mode 100644 tests/integrated/test-stopCheck-file/dataSecond/BOUT.inp create mode 100644 tests/integrated/test-stopCheck-file/dataSecond/otherStop.check create mode 100644 tests/integrated/test-stopCheck-file/makefile create mode 100755 tests/integrated/test-stopCheck-file/runtest create mode 100644 tests/integrated/test-stopCheck-file/test_stopCheck.cxx diff --git a/tests/integrated/test-stopCheck-file/README.md b/tests/integrated/test-stopCheck-file/README.md new file mode 100644 index 0000000000..4fcc735ea2 --- /dev/null +++ b/tests/integrated/test-stopCheck-file/README.md @@ -0,0 +1,8 @@ +Stop check test case +==================== + +This example tests the `stopCheck` functionality by checking that the number of output steps matches the expectations for a run with `stopCheck=false` and one with `stopCheck=true`. + +Note the data*/BOUT.stop file is expected to exist and is not created by the test runner. + +This tests both the behaviour of `checkStop` with default options as well as the behaviour with non-default data_dir and stop file name. \ No newline at end of file diff --git a/tests/integrated/test-stopCheck-file/data/BOUT.inp b/tests/integrated/test-stopCheck-file/data/BOUT.inp new file mode 100644 index 0000000000..c0dd9d8f5e --- /dev/null +++ b/tests/integrated/test-stopCheck-file/data/BOUT.inp @@ -0,0 +1,17 @@ +# Test of smoothing operators +# +# Creates some variables, smooths them, then compares +# the results on varying numbers of processors +# + +NOUT = 10 # No timesteps + +MZ = 8 # Z size + +[mesh] +NX = 10 +NY = 3 + +dump_format = "nc" # NetCDF format. Alternative is "pdb" + + diff --git a/tests/integrated/test-stopCheck-file/data/BOUT.stop b/tests/integrated/test-stopCheck-file/data/BOUT.stop new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/integrated/test-stopCheck-file/dataSecond/BOUT.inp b/tests/integrated/test-stopCheck-file/dataSecond/BOUT.inp new file mode 100644 index 0000000000..c0dd9d8f5e --- /dev/null +++ b/tests/integrated/test-stopCheck-file/dataSecond/BOUT.inp @@ -0,0 +1,17 @@ +# Test of smoothing operators +# +# Creates some variables, smooths them, then compares +# the results on varying numbers of processors +# + +NOUT = 10 # No timesteps + +MZ = 8 # Z size + +[mesh] +NX = 10 +NY = 3 + +dump_format = "nc" # NetCDF format. Alternative is "pdb" + + diff --git a/tests/integrated/test-stopCheck-file/dataSecond/otherStop.check b/tests/integrated/test-stopCheck-file/dataSecond/otherStop.check new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/integrated/test-stopCheck-file/makefile b/tests/integrated/test-stopCheck-file/makefile new file mode 100644 index 0000000000..2d2e644a9e --- /dev/null +++ b/tests/integrated/test-stopCheck-file/makefile @@ -0,0 +1,6 @@ + +BOUT_TOP = ../../.. + +SOURCEC = test_stopCheck.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-stopCheck-file/runtest b/tests/integrated/test-stopCheck-file/runtest new file mode 100755 index 0000000000..7530d4845f --- /dev/null +++ b/tests/integrated/test-stopCheck-file/runtest @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +#requires: not travis +# +# Run the test, compare results against the benchmark +# + +# Variables to compare +from __future__ import print_function +try: + from builtins import str +except: + pass + +from boututils.run_wrapper import shell, launch, getmpirun +from boutdata.collect import collect +import numpy as np +from sys import stdout, exit + +nproc = 1 + +MPIRUN=getmpirun() + +print("Making stopCheck test") +shell("make > make.log") + +checkVal=[True,False] +nstepExpect=[1,11] +dats = ["data","dataSecond"] +datStopFiles = ["BOUT.stop","otherStop.check"] + +vars=["t_array"] + +print("Running stopCheck test") +success = True + +for j, dat in enumerate(dats): + for i, check in enumerate(checkVal): + cmd = "./test_stopCheck" + + s, out = launch(cmd+" -d "+dat+" stopCheck="+str(check)+" stopCheckName="+datStopFiles[j], runcmd=MPIRUN, nproc=nproc, pipe=True) + f = open("run.log."+dat+"."+str(check).lower(), "w") + f.write(out) + f.close() + + # Collect output data + for v in vars: + result = collect(v, path=dat, info=False) + + # Compare benchmark and output + if result.shape[0] != nstepExpect[i]: + print("Fail, wrong shape") + print("Option is "+str(check)+"/"+dat+"/"+datStopFiles[j]) + print("shape is "+str(result.shape[0])) + print("expecting "+str(nstepExpect[i])) + success = False + continue + +if success: + print(" => All checkStop tests passed") + exit(0) +else: + print(" => Some failed tests") + exit(1) diff --git a/tests/integrated/test-stopCheck-file/test_stopCheck.cxx b/tests/integrated/test-stopCheck-file/test_stopCheck.cxx new file mode 100644 index 0000000000..9fc3583c78 --- /dev/null +++ b/tests/integrated/test-stopCheck-file/test_stopCheck.cxx @@ -0,0 +1,21 @@ +/* + * Check stop tests + * + */ + +#include +#include +#include "unused.hxx" + +Field3D N; + +int physics_init(bool UNUSED(restarting)) { + solver->add(N,"N"); + return 0; +} + +int physics_run(BoutReal UNUSED(t)) { + mesh->communicate(N); + ddt(N) = 0.; + return 0; +} From 94debc68c43a1b97fbbb8f0ccc8d2cd4dbbb4d79 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 19:56:35 +0000 Subject: [PATCH 0440/1783] Remove commented out code from example input file --- examples/invertable_operator/data/BOUT.inp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/invertable_operator/data/BOUT.inp b/examples/invertable_operator/data/BOUT.inp index c01be865d8..2a18be0c01 100644 --- a/examples/invertable_operator/data/BOUT.inp +++ b/examples/invertable_operator/data/BOUT.inp @@ -10,8 +10,8 @@ first = fft second = fft [laplace] -inner_boundary_flags = 0#32#2 -outer_boundary_flags = 0#32#2 +inner_boundary_flags = 0 +outer_boundary_flags = 0 [all] bndry_all = none @@ -19,4 +19,4 @@ function = 0. [n] scale = 1.0 -function = sin(z) #gauss(x-0.5)*cos(x*2*pi)*sin(z) \ No newline at end of file +function = sin(z) \ No newline at end of file From 0dce166a102969c0c6e5ac81c01d5e4c488d8867 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 11 Dec 2018 20:15:14 +0000 Subject: [PATCH 0441/1783] Removes explicit request for timezone The "Ec" requests time in the current locale's alternate format -- this may or may not contain a timezone, however I guess now that we're using locales we should probably try to respect the locale's preferred format for things where possible. --- src/sys/utils.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/utils.cxx b/src/sys/utils.cxx index b255a7711c..dbb39f844c 100644 --- a/src/sys/utils.cxx +++ b/src/sys/utils.cxx @@ -150,6 +150,6 @@ const std::string toString<>(const time_t& time) { // Older compilers char buffer[80]; - strftime(buffer, 80, "%Ec %Z", tm); + strftime(buffer, 80, "%Ec", tm); return std::string(buffer); } From 671b50e4cb26a98680c5c6e0350987c446768078 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 11 Dec 2018 23:46:26 +0000 Subject: [PATCH 0442/1783] Add simple handling of strings to DataFile Suspect this only works for format='NETCDF4' due to the lack of sane string handling in other formats. --- tools/pylib/boututils/datafile.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tools/pylib/boututils/datafile.py b/tools/pylib/boututils/datafile.py index 093e7e19e6..edf49336a8 100644 --- a/tools/pylib/boututils/datafile.py +++ b/tools/pylib/boututils/datafile.py @@ -652,14 +652,17 @@ def find_dim(dim): if var is None: raise Exception("Couldn't create variable") - + # Write the data - try: - # Some libraries allow this for arrays - var.assignValue(data) - except: - # And some others only this - var[:] = data + if t == 'str': + var[0] = data + else: + try: + # Some libraries allow this for arrays + var.assignValue(data) + except: + # And some others only this + var[:] = data # Write attributes, if present try: From d71f250dc0c0c64a70417b40f470c0b12ed0e1a6 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 12 Dec 2018 00:04:25 +0000 Subject: [PATCH 0443/1783] Add OptionsNetCDF reader Reads NetCDF file scalar variables into Options tree Currently handles int, float, double and strings. Short integrated test reads NetCDF file, writes INI file. --- include/options_netcdf.hxx | 51 +++++++++++++++ src/sys/options/makefile | 2 +- src/sys/options/options_netcdf.cxx | 63 +++++++++++++++++++ .../test-options-netcdf/data/BOUT.inp | 6 ++ tests/integrated/test-options-netcdf/makefile | 6 ++ tests/integrated/test-options-netcdf/runtest | 29 +++++++++ .../test-options-netcdf.cxx | 22 +++++++ 7 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 include/options_netcdf.hxx create mode 100644 src/sys/options/options_netcdf.cxx create mode 100644 tests/integrated/test-options-netcdf/data/BOUT.inp create mode 100644 tests/integrated/test-options-netcdf/makefile create mode 100755 tests/integrated/test-options-netcdf/runtest create mode 100644 tests/integrated/test-options-netcdf/test-options-netcdf.cxx diff --git a/include/options_netcdf.hxx b/include/options_netcdf.hxx new file mode 100644 index 0000000000..4ce4666def --- /dev/null +++ b/include/options_netcdf.hxx @@ -0,0 +1,51 @@ + +#pragma once + +#ifndef __OPTIONS_NETCDF_H__ +#define __OPTIONS_NETCDF_H__ + +#ifndef NCDF4 + +#include + +#include "boutexception.hxx" +#include "options.hxx" + +class OptionsNetCDF { +public: + OptionsNetCDF(const std::string &filename) {} + + /// Read options from file + Options read() { + throw BoutException("OptionNetCDF not available\n"); + } + + /// Write options to file + void write(const Options &options) { + throw BoutException("OptionNetCDF not available\n"); + } +}; + +#else + +#include + +#include "options.hxx" + +class OptionsNetCDF { +public: + OptionsNetCDF(const std::string &filename) : filename(filename) {} + + /// Read options from file + Options read(); + + /// Write options to file + void write(const Options &options); + +private: + std::string filename; +}; + +#endif + +#endif // __OPTIONS_NETCDF_H__ diff --git a/src/sys/options/makefile b/src/sys/options/makefile index 77a61de988..e38608b68c 100644 --- a/src/sys/options/makefile +++ b/src/sys/options/makefile @@ -1,5 +1,5 @@ BOUT_TOP = ../../.. -SOURCEC = options_ini.cxx +SOURCEC = options_ini.cxx options_netcdf.cxx SOURCEH = $(SOURCEC:%.cxx=%.hxx) globals.hxx bout_types.hxx multiostream.hxx TARGET = lib diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx new file mode 100644 index 0000000000..326752f7b3 --- /dev/null +++ b/src/sys/options/options_netcdf.cxx @@ -0,0 +1,63 @@ + +#ifdef NCDF4 + +#include "options_netcdf.hxx" + +#include + +using namespace netCDF; + +Options OptionsNetCDF::read() { + // Open file + NcFile dataFile(filename, NcFile::read); + + if (dataFile.isNull()) { + throw BoutException("Could not open NetCDF file '%s'", filename.c_str()); + } + + Options result; + + // Iterate over all variables + for (const auto& varpair : dataFile.getVars()) { + const auto& var_name = varpair.first; // Name of the variable + const auto& var = varpair.second; // The NcVar object + + if (var.getDimCount() == 0) { + // Scalar variables + + auto var_type = var.getType(); + + if (var_type == ncDouble) { + double value; + var.getVar(&value); + result[var_name] = value; + result[var_name].attributes["source"] = filename; + } else if (var_type == ncFloat) { + float value; + var.getVar(&value); + result[var_name] = value; + result[var_name].attributes["source"] = filename; + } else if (var_type == ncInt) { + int value; + var.getVar(&value); + result[var_name] = value; + result[var_name].attributes["source"] = filename; + } else if (var_type == ncString) { + char* value; + var.getVar(&value); + result[var_name] = std::string(value); + result[var_name].attributes["source"] = filename; + } + // else ignore + } + } + return result; +} + +/// Write options to file +void OptionsNetCDF::write(const Options &options) { + +} + + +#endif // NCDF4 diff --git a/tests/integrated/test-options-netcdf/data/BOUT.inp b/tests/integrated/test-options-netcdf/data/BOUT.inp new file mode 100644 index 0000000000..a5692dce34 --- /dev/null +++ b/tests/integrated/test-options-netcdf/data/BOUT.inp @@ -0,0 +1,6 @@ + + +[mesh] +nx = 5 +ny = 5 + diff --git a/tests/integrated/test-options-netcdf/makefile b/tests/integrated/test-options-netcdf/makefile new file mode 100644 index 0000000000..f9197480fb --- /dev/null +++ b/tests/integrated/test-options-netcdf/makefile @@ -0,0 +1,6 @@ + +BOUT_TOP = ../../.. + +SOURCEC = test-options-netcdf.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-options-netcdf/runtest b/tests/integrated/test-options-netcdf/runtest new file mode 100755 index 0000000000..65bf8e6411 --- /dev/null +++ b/tests/integrated/test-options-netcdf/runtest @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +from boututils.datafile import DataFile +from boututils.run_wrapper import shell +from boutdata.data import BoutOptionsFile + +import math + +shell("make") + +# Create a NetCDF input file +with DataFile("test.nc", create=True, format="NETCDF4") as f: + f.write("int", 42); + f.write("real", 3.1415); + f.write("string", "hello"); + +# run BOUT++ +shell("./test-options-netcdf") + +# Check the output INI file +result = BoutOptionsFile("test.settings") + +print(result) + +assert result["int"] == 42 +assert math.isclose(result["real"], 3.1415) +assert result["string"] == "hello" + +print("Passed") diff --git a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx new file mode 100644 index 0000000000..136e5e1ebd --- /dev/null +++ b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx @@ -0,0 +1,22 @@ + +#include "bout.hxx" + +#include "options_netcdf.hxx" +#include "optionsreader.hxx" + +int main(int argc, char** argv) { + BoutInitialise(argc, argv); + + // Read values from a NetCDF file + OptionsNetCDF file("test.nc"); + + auto values = file.read(); + + values.printUnused(); + + // Write to an INI text file + OptionsReader *reader = OptionsReader::getInstance(); + reader->write(&values, "test.settings"); + + BoutFinalise(); +}; From e24a501e73c311c86a2f88c8bfcd3e30ce878359 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 12 Dec 2018 07:13:04 +0000 Subject: [PATCH 0444/1783] Change test-options-netcdf runtest to python3 `python` defaults to python2 on Travis, which fails since the `future` module is not installed there. --- tests/integrated/test-options-netcdf/runtest | 5 +++-- tools/pylib/boututils/datafile.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/integrated/test-options-netcdf/runtest b/tests/integrated/test-options-netcdf/runtest index 65bf8e6411..d07fb69b81 100755 --- a/tests/integrated/test-options-netcdf/runtest +++ b/tests/integrated/test-options-netcdf/runtest @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from boututils.datafile import DataFile from boututils.run_wrapper import shell @@ -7,6 +7,7 @@ from boutdata.data import BoutOptionsFile import math shell("make") +shell("rm -f test.settings") # Create a NetCDF input file with DataFile("test.nc", create=True, format="NETCDF4") as f: @@ -26,4 +27,4 @@ assert result["int"] == 42 assert math.isclose(result["real"], 3.1415) assert result["string"] == "hello" -print("Passed") +print(" => Passed") diff --git a/tools/pylib/boututils/datafile.py b/tools/pylib/boututils/datafile.py index edf49336a8..690df0de3a 100644 --- a/tools/pylib/boututils/datafile.py +++ b/tools/pylib/boututils/datafile.py @@ -652,7 +652,7 @@ def find_dim(dim): if var is None: raise Exception("Couldn't create variable") - + # Write the data if t == 'str': var[0] = data From db4ffb9560f5b32fa78b6bb658062f00e1e1da01 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Dec 2018 09:44:18 +0000 Subject: [PATCH 0445/1783] Putting InvertableOperator in bout::inversion namespace --- .../invertable_operator.cxx | 2 +- include/bout/invertable_operator.hxx | 118 ++++++++++-------- .../sphinx/user_docs/invertable_operator.rst | 17 ++- 3 files changed, 80 insertions(+), 57 deletions(-) diff --git a/examples/invertable_operator/invertable_operator.cxx b/examples/invertable_operator/invertable_operator.cxx index 851ece6679..ae64d26d12 100644 --- a/examples/invertable_operator/invertable_operator.cxx +++ b/examples/invertable_operator/invertable_operator.cxx @@ -61,7 +61,7 @@ class HW : public PhysicsModel { }; myLaplacian mm; - InvertableOperator mySolver; + bout::inversion::InvertableOperator mySolver; // Above could also be: // mySolver(delp); // or even a Lambda diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index cfeab3021c..e873d04a57 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -1,5 +1,5 @@ /************************************************************************** - * Invert arbitrary linear global operation using PETSc. to invert + * Invert arbitrary linear global operation using PETSc. * ************************************************************************** * Copyright 2018 D. Dickinson @@ -23,8 +23,12 @@ * **************************************************************************/ +namespace bout { +namespace inversion { template class InvertableOperator; +}; +}; #ifndef __INVERTABLE_OPERATOR_H__ #define __INVERTABLE_OPERATOR_H__ @@ -43,6 +47,13 @@ class InvertableOperator; #include +#endif + +namespace bout { +namespace inversion { + +#ifdef BOUT_HAS_PETSC + /// No-op function to use as a default -- may wish to remove once testing phase complete template T identity(const T& in) { @@ -50,6 +61,58 @@ T identity(const T& in) { return in; }; +/// Pack a PetscVec from a Field +template +PetscErrorCode fieldToPetscVec(const T& in, Vec out) { + TRACE("fieldToPetscVec"); + Timer timer("invertable_operator_packing"); + + PetscScalar* vecData; + + auto ierr = VecGetArray(out, &vecData); + CHKERRQ(ierr); + + int counter = 0; + + // Should explore ability to OpenMP this + BOUT_FOR_SERIAL(i, in.getRegion("RGN_NOCORNERS")) { + vecData[counter] = in[i]; + counter++; + } + + ierr = VecRestoreArray(out, &vecData); + CHKERRQ(ierr); + + return ierr; +} + +/// Pack a Field from a PetscVec +template +PetscErrorCode petscVecToField(Vec in, T& out) { + TRACE("petscVecToField"); + Timer timer("invertable_operator_packing"); + + const PetscScalar* vecData; + + auto ierr = VecGetArrayRead(in, &vecData); + CHKERRQ(ierr); + + int counter = 0; + + // Should explore ability to OpenMP this + BOUT_FOR_SERIAL(i, out.getRegion("RGN_NOCORNERS")) { + out[i] = vecData[counter]; + counter++; + } + + ierr = VecRestoreArrayRead(in, &vecData); + CHKERRQ(ierr); + + return ierr; +}; + +/// Class to define an invertable operator. Provides interface to PETSc routines +/// for solving A.x = b template class InvertableOperator { static_assert( @@ -495,56 +558,6 @@ private: } }; -/// Pack a PetscVec from a Field -template -PetscErrorCode fieldToPetscVec(const T& in, Vec out) { - TRACE("fieldToPetscVec"); - Timer timer("invertable_operator_packing"); - - PetscScalar* vecData; - - auto ierr = VecGetArray(out, &vecData); - CHKERRQ(ierr); - - int counter = 0; - - // Should explore ability to OpenMP this - BOUT_FOR_SERIAL(i, in.getRegion("RGN_NOCORNERS")) { - vecData[counter] = in[i]; - counter++; - } - - ierr = VecRestoreArray(out, &vecData); - CHKERRQ(ierr); - - return ierr; -} - -/// Pack a Field from a PetscVec -template -PetscErrorCode petscVecToField(Vec in, T& out) { - TRACE("petscVecToField"); - Timer timer("invertable_operator_packing"); - - const PetscScalar* vecData; - - auto ierr = VecGetArrayRead(in, &vecData); - CHKERRQ(ierr); - - int counter = 0; - - // Should explore ability to OpenMP this - BOUT_FOR_SERIAL(i, out.getRegion("RGN_NOCORNERS")) { - out[i] = vecData[counter]; - counter++; - } - - ierr = VecRestoreArrayRead(in, &vecData); - CHKERRQ(ierr); - - return ierr; -} - #else template @@ -553,4 +566,7 @@ public: }; #endif // PETSC +}; +}; + #endif // HEADER GUARD diff --git a/manual/sphinx/user_docs/invertable_operator.rst b/manual/sphinx/user_docs/invertable_operator.rst index 1f94ca2066..9be3a2863a 100644 --- a/manual/sphinx/user_docs/invertable_operator.rst +++ b/manual/sphinx/user_docs/invertable_operator.rst @@ -24,7 +24,8 @@ been implemented that allows the user to define a generic differential operator and provides a simple (for the user) method to invert the operator to find :math:`\underline{x}`. This class currently relies on PETSc to provide the inversion functionality and hence is not -available when configuring without PETSc support. +available when configuring without PETSc support. It is available in +the namespace ``bout::inversion``. There is an example in `examples/invertable_operator` that uses the class to solve a simple Laplacian operator and compares to the @@ -34,8 +35,13 @@ The `InvertableOperator` class is templated on the field type of the operator (essentially defining the domain over which the problem exists). To define the operator that the `InvertableOperator` instances represents one should use the -`InvertableOperator::setOperatorFunction` method. This takes a function -of signature ``std::function``. This can be a ``std::function``, compatible function pointer, lambda or a functor. The last of these allows more complicated functions that use a local context. For example the following code snippet demonstrates a functor that stores several auxilliary ``Field3D`` variables used in the ``operator()`` call:: +`InvertableOperator::setOperatorFunction` method. This takes a +function of signature ``std::function``. This can be a +``std::function``, compatible function pointer, lambda or a +functor. The last of these allows more complicated functions that use +a local context. For example the following code snippet demonstrates a +functor that stores several auxilliary ``Field3D`` variables used in +the ``operator()`` call:: struct myLaplacian { Field3D D = 1.0, C = 1.0, A = 0.0; @@ -73,7 +79,7 @@ A more complete example is :: }; }; - InveratbleOperator solver; + bout::inversion::InveratbleOperator solver; myLaplacian laplacianOperator; laplacianOperator.A = 1.0; laplacianOperator.B = 2.0; @@ -104,7 +110,8 @@ hence subsequent changes to the functor will not be reflected in the operator without a further call to ``setOperatorFunction``. For example:: - InveratbleOperator solver; + using bout::inversion; + InvertableOperator solver; myLaplacian laplacianOperator; laplacianOperator.A = 1.0; laplacianOperator.B = 2.0; From 0f6a0feb1a713106d69d688240d6692cba9983ae Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 12 Dec 2018 12:03:21 +0000 Subject: [PATCH 0446/1783] Remove region restrictions in ShiftedMetric::shiftZ Following discussion in PR #1432: it is not necessary to restrict the regions for to/fromFieldAligned or shiftZ to RGN_NOX and RGN_NOBNDRY as was being done previously. --- src/mesh/parallel/shiftedmetric.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 53a5fdea96..32ca2b84ec 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -143,7 +143,6 @@ const Field3D ShiftedMetric::fromFieldAligned(const Field3D &f, const REGION reg const Field3D ShiftedMetric::shiftZ(const Field3D &f, const arr3Dvec &phs, const REGION region) { ASSERT1(&mesh == f.getMesh()); - ASSERT1(region == RGN_NOX || region == RGN_NOBNDRY); // Never calculate x-guard cells here if(mesh.LocalNz == 1) return f; // Shifting makes no difference @@ -178,7 +177,6 @@ void ShiftedMetric::shiftZ(const BoutReal *in, const std::vector &phs, //Old approach retained so we can still specify a general zShift const Field3D ShiftedMetric::shiftZ(const Field3D &f, const Field2D &zangle, const REGION region) { ASSERT1(&mesh == f.getMesh()); - ASSERT1(region == RGN_NOX || region == RGN_NOBNDRY); // Never calculate x-guard cells here ASSERT1(f.getLocation() == zangle.getLocation()); if(mesh.LocalNz == 1) return f; // Shifting makes no difference From 7bfee6a4e68bd94e374dd358d02ff64d87f7f45d Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Dec 2018 12:09:00 +0000 Subject: [PATCH 0447/1783] Simplify hasRegion routines --- src/mesh/mesh.cxx | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index c17020bb4b..dc45ba8091 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -360,30 +360,15 @@ const Region &Mesh::getRegionPerp(const std::string ®ion_name) const } const bool Mesh::hasRegion3D(const std::string& region_name) const { - const auto found = regionMap3D.find(region_name); - if (found == end(regionMap3D)) { - return false; - } else { - return true; - } + return regionMap3D.find(region_name) != std::end(regionMap3D); } const bool Mesh::hasRegion2D(const std::string& region_name) const { - const auto found = regionMap2D.find(region_name); - if (found == end(regionMap2D)) { - return false; - } else { - return true; - } + return regionMap2D.find(region_name) != std::end(regionMap2D); } const bool Mesh::hasRegionPerp(const std::string& region_name) const { - const auto found = regionMapPerp.find(region_name); - if (found == end(regionMapPerp)) { - return false; - } else { - return true; - } + return regionMapPerp.find(region_name) != std::end(regionMapPerp); } void Mesh::addRegion3D(const std::string ®ion_name, const Region<> ®ion) { From 396df9f29cb6eaf6768b779e4b7966f50111ef4c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Dec 2018 12:10:11 +0000 Subject: [PATCH 0448/1783] Move declaration of ierr --- include/bout/invertable_operator.hxx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index e873d04a57..293eace0b2 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -299,8 +299,6 @@ public: throw BoutException("Invalid template type provided to InvertableOperator"); } - PetscInt ierr; - // Hacky way to determine the local size for now PetscInt nlocal = 0; { @@ -312,8 +310,8 @@ public: /// Create the shell matrix representing the operator to invert /// Note we currently pass "this" as the Matrix context - ierr = MatCreateShell(BoutComm::get(), nlocal, nlocal, nglobal, nglobal, this, - &matOperator); + PetscInt ierr = MatCreateShell(BoutComm::get(), nlocal, nlocal, nglobal, nglobal, + this, &matOperator); CHKERRQ(ierr); /// Create vectors compatible with matrix From dd1e6fb4da4970a87bf67723cc4b35d15b2a9825 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Dec 2018 12:24:45 +0000 Subject: [PATCH 0449/1783] Adding integrated test for InvertableOperator --- .../test-invertable-operator/.gitignore | 1 + .../test-invertable-operator/data/BOUT.inp | 22 +++++ .../invertable_operator.cxx | 88 +++++++++++++++++++ .../test-invertable-operator/makefile | 5 ++ .../test-invertable-operator/runtest | 56 ++++++++++++ 5 files changed, 172 insertions(+) create mode 100644 tests/integrated/test-invertable-operator/.gitignore create mode 100644 tests/integrated/test-invertable-operator/data/BOUT.inp create mode 100644 tests/integrated/test-invertable-operator/invertable_operator.cxx create mode 100644 tests/integrated/test-invertable-operator/makefile create mode 100755 tests/integrated/test-invertable-operator/runtest diff --git a/tests/integrated/test-invertable-operator/.gitignore b/tests/integrated/test-invertable-operator/.gitignore new file mode 100644 index 0000000000..1d6c85a9e7 --- /dev/null +++ b/tests/integrated/test-invertable-operator/.gitignore @@ -0,0 +1 @@ +invertable_operator \ No newline at end of file diff --git a/tests/integrated/test-invertable-operator/data/BOUT.inp b/tests/integrated/test-invertable-operator/data/BOUT.inp new file mode 100644 index 0000000000..2a18be0c01 --- /dev/null +++ b/tests/integrated/test-invertable-operator/data/BOUT.inp @@ -0,0 +1,22 @@ +NOUT=0 + +[mesh] +nx = 20 +ny = 16 +nz = 16 + +[mesh:ddz] +first = fft +second = fft + +[laplace] +inner_boundary_flags = 0 +outer_boundary_flags = 0 + +[all] +bndry_all = none +function = 0. + +[n] +scale = 1.0 +function = sin(z) \ No newline at end of file diff --git a/tests/integrated/test-invertable-operator/invertable_operator.cxx b/tests/integrated/test-invertable-operator/invertable_operator.cxx new file mode 100644 index 0000000000..c85cee9cfd --- /dev/null +++ b/tests/integrated/test-invertable-operator/invertable_operator.cxx @@ -0,0 +1,88 @@ +#include +#include + +#include +#include + +class InvertableOperatorTest : public PhysicsModel { +private: + Field3D n, solutionInv, solutionLap; + + int passVerification = 0; + BoutReal maxRelErrLaplacians = 0; + + struct myLaplacian { + Field3D D = 1.0, A = 1.0e-1; + + // Drop C term for now + Field3D operator()(const Field3D& input) { + TRACE("myLaplacian::operator()"); + Field3D result = A * input + D * Delp2(input); + + // Ensure boundary points are set appropriately as given by the input field. + result.setBoundaryTo(input); + + return result; + }; + }; + + myLaplacian mm; + bout::inversion::InvertableOperator mySolver; + + class Laplacian* laplacianSolver; + + const int nits = 10; + +protected: + int init(bool restart) { + SOLVE_FOR(n); + SOLVE_FOR(solutionLap); + SOLVE_FOR(solutionInv); + + SAVE_REPEAT(passVerification); + SAVE_REPEAT(maxRelErrLaplacians); + + mm.A = 1.0e-1; + mm.D = 1.0; + + // Note mySolve takes a copy of the passed functor so updates to the local + // instance won't have any effect, but the function _can_ be changed (currently) + // through setOperatorFunction + + mySolver.setOperatorFunction(mm); + mySolver.setup(); + + laplacianSolver = Laplacian::create(); + laplacianSolver->setCoefA(mm.A); + laplacianSolver->setCoefC(1.0); + laplacianSolver->setCoefD(mm.D); + + n.applyBoundary("dirichlet"); + + return 0; + } + + int rhs(BoutReal time) { + ddt(n) = 0.; + ddt(solutionInv) = 0.; + ddt(solutionLap) = 0.; + + // First run to get the solution with zero initial guess + solutionInv = mySolver.invert(n, 0.0); + mesh->communicate(solutionInv); + + passVerification = mySolver.verify(n); + + solutionLap = laplacianSolver->solve(n); + + maxRelErrLaplacians = + max(abs(solutionInv - solutionLap), true) / max(abs(solutionLap)); + + return 0; + } + +public: +}; + +// Define a main() function +BOUTMAIN(InvertableOperatorTest); diff --git a/tests/integrated/test-invertable-operator/makefile b/tests/integrated/test-invertable-operator/makefile new file mode 100644 index 0000000000..e0b6d92849 --- /dev/null +++ b/tests/integrated/test-invertable-operator/makefile @@ -0,0 +1,5 @@ +BOUT_TOP = ../../.. + +SOURCEC = invertable_operator.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-invertable-operator/runtest b/tests/integrated/test-invertable-operator/runtest new file mode 100755 index 0000000000..c83c902f86 --- /dev/null +++ b/tests/integrated/test-invertable-operator/runtest @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 + +#requires: petsc + +# +# Run the test, compare results against expected value +# + +from __future__ import print_function +from __future__ import division + +from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boutdata.collect import collect +import numpy as np +from sys import stdout, exit + +nprocs = [1,2] # Number of processors to run on +reltol = 1.e-3 # Allowed relative tolerance +nthreads=1 +MPIRUN = getmpirun() + +print("Making invertable operator test") +shell_safe("make > make.log") + +# Delete old output files +shell("rm data/BOUT.dmp.*") + +def run(path, nproc, log=False): + pipe = False + if log != False: + pipe = True + s, out = launch_safe("./invertable_operator -d "+path, runcmd=MPIRUN, nproc=nproc, mthread=nthreads, pipe=pipe) + if pipe: + f = open(log, "w") + f.write(out) + f.close() + + # Get result of the test + passVerification = collect("passVerification", path=path)[-1] + maxRelErrLaplacians = collect("maxRelErrLaplacians", path=path)[-1] + + if passVerification == 0: + print(" => Failed (verification step - value is {s})".format(s=passVerification)) + exit(1) + + if maxRelErrLaplacians > reltol: + print(" => Failed (relative tolerance step -- difference of {s})".format(s=maxRelErrLaplacians)) + exit(1) + + +for np in nprocs: + run("data",np) + +print(" => All tests passed") +exit(0) + From ed9c9dbc5752c99abff5bc06afac648ae761048e Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Dec 2018 12:30:02 +0000 Subject: [PATCH 0450/1783] Remove some testing code --- include/bout/invertable_operator.hxx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 293eace0b2..d535c8f0c0 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -140,13 +140,6 @@ public: /// Destructor just has to cleanup the PETSc owned objects. ~InvertableOperator() { TRACE("InvertableOperator::destructor"); -#if CHECK > 3 // For initial development - output_info << endl; - output_info << "Destroying KSP object in InvertableOperator with properties: " - << endl; - KSPView(ksp, PETSC_VIEWER_STDOUT_SELF); - output_info << endl; -#endif KSPDestroy(&ksp); MatDestroy(&matOperator); From 1e2ff1f716f24bc6e82491d9f1eabb8d8e6d0ffa Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Dec 2018 13:19:29 +0000 Subject: [PATCH 0451/1783] Be more consistent with checking the returned error code --- include/bout/invertable_operator.hxx | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index d535c8f0c0..6886cb4a13 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -382,7 +382,8 @@ public: // to deal with. T invert(const T& rhsField, const T& guess) { AUTO_TRACE(); - fieldToPetscVec(guess, lhs); + auto ierr = fieldToPetscVec(guess, lhs); + CHKERRQ(ierr); return invert(rhsField); } @@ -402,7 +403,8 @@ public: ASSERT2(localmesh == rhsField.getMesh()); // rhsField to rhs - fieldToPetscVec(rhsField, rhs); + auto ierr = fieldToPetscVec(rhsField, rhs); + CHKERRQ(ierr); /// Do the solve with solution stored in lhs /// Note: the values in lhs on input are used as the initial guess @@ -411,7 +413,7 @@ public: /// between calls to invert (as a class member rather than local scope) /// we automatically provide the previous solution as the initial guess /// for subsequent solves. - auto ierr = KSPSolve(ksp, rhs, lhs); + ierr = KSPSolve(ksp, rhs, lhs); CHKERRQ(ierr); KSPConvergedReason reason; @@ -427,7 +429,8 @@ public: T lhsField(localmesh); lhsField.allocate(); - petscVecToField(lhs, lhsField); + ierr = petscVecToField(lhs, lhsField); + CHKERRQ(ierr); return lhsField; }; @@ -500,7 +503,8 @@ private: auto ierr = MatShellGetContext(m, &ctx); T tmpField(ctx->localmesh); tmpField.allocate(); - petscVecToField(v1, tmpField); + ierr = petscVecToField(v1, tmpField); + CHKERRQ(ierr); // Need following communicate if operator() uses guard cells, i.e. differential // operator. Could delegate to the user function but then need to remove const // from signature of the function (function_signature) likely involving a copy. @@ -515,7 +519,8 @@ private: // @TODO : Consider need for this communicate. Could communicate at the // end of the user routine. ctx->localmesh->communicate(tmpField2); - fieldToPetscVec(tmpField2, v2); + ierr = fieldToPetscVec(tmpField2, v2); + CHKERRQ(ierr); return ierr; } @@ -529,7 +534,8 @@ private: auto ierr = MatShellGetContext(m, &ctx); T tmpField(ctx->localmesh); tmpField.allocate(); - petscVecToField(v1, tmpField); + ierr = petscVecToField(v1, tmpField); + CHKERRQ(ierr); // Need following communicate if operator() uses guard cells, i.e. differential // operator. Could delegate to the user function but then need to remove const // from signature of the function (function_signature) likely involving a copy. @@ -544,7 +550,8 @@ private: // @TODO : Consider need for this communicate. Could communicate at the // end of the user routine. ctx->localmesh->communicate(tmpField2); - fieldToPetscVec(tmpField2, v2); + ierr = fieldToPetscVec(tmpField2, v2); + CHKERRQ(ierr); return ierr; } }; From 00f0b9c586d99a161be889b2cefaaa0a52ef4bbb Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Dec 2018 13:37:04 +0000 Subject: [PATCH 0452/1783] Make Field3D copy the location from Field2D when using operator=(Field2D) --- src/field/field3d.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 6ab7a4ef79..8fa458dbd0 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -199,6 +199,7 @@ const Field3D& Field3D::ynext(int dir) const { } void Field3D::setLocation(CELL_LOC new_location) { + AUTO_TRACE(); if (getMesh()->StaggerGrids) { if (new_location == CELL_VSHIFT) { throw BoutException( @@ -228,6 +229,7 @@ void Field3D::setLocation(CELL_LOC new_location) { } CELL_LOC Field3D::getLocation() const { + AUTO_TRACE(); return location; } @@ -294,9 +296,8 @@ Field3D & Field3D::operator=(const Field2D &rhs) { /// Copy data BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] = rhs[i]; } - /// Only 3D fields have locations for now - //location = CELL_CENTRE; - + setLocation(rhs.getLocation()); + return *this; } From 3f652b4097569a2ae4b5d76631497df9bdd5b61d Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Dec 2018 13:54:01 +0000 Subject: [PATCH 0453/1783] Adding location to FieldPerp --- include/fieldperp.hxx | 17 ++- src/field/field3d.cxx | 4 + src/field/fieldperp.cxx | 231 ++++++++++++++++++++++++---------------- 3 files changed, 160 insertions(+), 92 deletions(-) diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 20dd0e3a60..10763158cd 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -58,8 +58,9 @@ class FieldPerp : public Field { * Copy constructor. After this the data * will be shared (non unique) */ - FieldPerp(const FieldPerp &f) - : Field(f.fieldmesh), yindex(f.yindex), nx(f.nx), nz(f.nz), data(f.data) {} + FieldPerp(const FieldPerp& f) + : Field(f.fieldmesh), yindex(f.yindex), nx(f.nx), nz(f.nz), data(f.data), + location(f.location) {} /*! * Move constructor @@ -82,6 +83,15 @@ class FieldPerp : public Field { FieldPerp &operator=(FieldPerp &&rhs) = default; FieldPerp &operator=(BoutReal rhs); + /// Set variable location for staggered grids to @param new_location + /// + /// Throws BoutException if new_location is not `CELL_CENTRE` and + /// staggered grids are turned off and checks are on. If checks are + /// off, silently sets location to ``CELL_CENTRE`` instead. + void setLocation(CELL_LOC new_location) override; + /// Get variable location + CELL_LOC getLocation() const override; + /// Return a Region reference to use to iterate over this field const Region& getRegion(REGION region) const; const Region& getRegion(const std::string ®ion_name) const; @@ -251,6 +261,9 @@ private: /// The underlying data array Array data; + + /// Location of the variable in the cell + CELL_LOC location{CELL_CENTRE}; }; // Non-member overloaded operators diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 8fa458dbd0..a29222ca9c 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -312,6 +312,10 @@ void Field3D::operator=(const FieldPerp &rhs) { /// Copy data BOUT_FOR(i, rhs.getRegion("RGN_ALL")) { (*this)(i, rhs.getIndex()) = rhs[i]; } + + // Alternative to setting the location of *this, is to ASSERT on input + // that rhs.getLocation() == location; + setLocation(rhs.getLocation()); } Field3D & Field3D::operator=(const BoutReal val) { diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index d7b8602ce0..5787f0ce29 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -62,6 +62,41 @@ void FieldPerp::allocate() { data.ensureUnique(); } +void FieldPerp::setLocation(CELL_LOC new_location) { + AUTO_TRACE(); + if (getMesh()->StaggerGrids) { + if (new_location == CELL_VSHIFT) { + throw BoutException( + "FieldPerp: CELL_VSHIFT cell location only makes sense for vectors"); + } + if (new_location == CELL_DEFAULT) { + new_location = CELL_CENTRE; + } + + // Invalidate the coordinates pointer + if (new_location != location) { + fieldCoordinates = nullptr; + } + + location = new_location; + + } else { +#if CHECK > 0 + if (new_location != CELL_CENTRE && new_location != CELL_DEFAULT) { + throw BoutException("FieldPerp: Trying to set off-centre location on " + "non-staggered grid\n" + " Did you mean to enable staggered grids?"); + } +#endif + location = CELL_CENTRE; + } +} + +CELL_LOC FieldPerp::getLocation() const { + AUTO_TRACE(); + return location; +} + /*************************************************************** * ASSIGNMENT ***************************************************************/ @@ -78,6 +113,8 @@ FieldPerp &FieldPerp::operator=(const FieldPerp &rhs) { nz = rhs.nz; yindex = rhs.yindex; data = rhs.data; + + setLocation(rhs.location); return *this; } @@ -97,18 +134,20 @@ FieldPerp & FieldPerp::operator=(const BoutReal rhs) { * OPERATORS ***************************************************************/ -#define FPERP_OP_FPERP(op, bop) \ - FieldPerp &FieldPerp::operator op(const FieldPerp &rhs) { \ - if (data.unique()) { \ - checkData(rhs); \ - /* Only reference to the data */ \ - BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] op rhs[i]; } \ - checkData(*this); \ - } else { \ - /* Shared with another FieldPerp */ \ - (*this) = (*this)bop rhs; \ - } \ - return *this; \ +#define FPERP_OP_FPERP(op, bop) \ + FieldPerp& FieldPerp::operator op(const FieldPerp& rhs) { \ + ASSERT1(getMesh() == rhs.getMesh()); \ + ASSERT1(location == rhs.getLocation()); \ + if (data.unique()) { \ + checkData(rhs); \ + /* Only reference to the data */ \ + BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] op rhs[i]; } \ + checkData(*this); \ + } else { \ + /* Shared with another FieldPerp */ \ + (*this) = (*this)bop rhs; \ + } \ + return *this; \ } FPERP_OP_FPERP(+=, +); @@ -116,19 +155,21 @@ FPERP_OP_FPERP(-=, -); FPERP_OP_FPERP(*=, *); FPERP_OP_FPERP(/=, /); -#define FPERP_OP_FIELD(op, bop, ftype) \ - FieldPerp &FieldPerp::operator op(const ftype &rhs) { \ - if (data.unique()) { \ - checkData(*this); \ - checkData(rhs); \ - /* Only reference to the data */ \ - BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] op rhs(i.x(), yindex, i.z()); } \ - checkData(*this); \ - } else { \ - /* Shared with another FieldPerp */ \ - (*this) = (*this)bop rhs; \ - } \ - return *this; \ +#define FPERP_OP_FIELD(op, bop, ftype) \ + FieldPerp& FieldPerp::operator op(const ftype& rhs) { \ + ASSERT1(getMesh() == rhs.getMesh()); \ + ASSERT1(location == rhs.getLocation()); \ + if (data.unique()) { \ + checkData(*this); \ + checkData(rhs); \ + /* Only reference to the data */ \ + BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] op rhs(i.x(), yindex, i.z()); } \ + checkData(*this); \ + } else { \ + /* Shared with another FieldPerp */ \ + (*this) = (*this)bop rhs; \ + } \ + return *this; \ } FPERP_OP_FIELD(+=, +, Field3D); @@ -177,17 +218,20 @@ const Region &FieldPerp::getRegion(const std::string ®ion_name) cons FieldPerp operator-(const FieldPerp &f) { return -1.0 * f; } // Operator on FieldPerp and another field -#define FPERP_FPERP_OP_FPERP(op) \ - const FieldPerp operator op(const FieldPerp &lhs, const FieldPerp &rhs) { \ - checkData(lhs); \ - checkData(rhs); \ - FieldPerp result(lhs.getMesh()); \ - result.allocate(); \ - result.setIndex(lhs.getIndex()); \ - \ - BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs[i] op rhs[i]; } \ - checkData(result); \ - return result; \ +#define FPERP_FPERP_OP_FPERP(op) \ + const FieldPerp operator op(const FieldPerp& lhs, const FieldPerp& rhs) { \ + ASSERT1(lhs.getMesh() == rhs.getMesh()); \ + ASSERT1(rhs.getLocation() == rhs.getLocation()); \ + checkData(lhs); \ + checkData(rhs); \ + FieldPerp result(lhs.getMesh()); \ + result.allocate(); \ + result.setIndex(lhs.getIndex()); \ + result.setLocation(rhs.getLocation()); \ + \ + BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs[i] op rhs[i]; } \ + checkData(result); \ + return result; \ } FPERP_FPERP_OP_FPERP(+); @@ -196,19 +240,22 @@ FPERP_FPERP_OP_FPERP(*); FPERP_FPERP_OP_FPERP(/); // Operator on FieldPerp and another field -#define FPERP_FPERP_OP_FIELD(op, ftype) \ - const FieldPerp operator op(const FieldPerp &lhs, const ftype &rhs) { \ - checkData(lhs); \ - checkData(rhs); \ - FieldPerp result(lhs.getMesh()); \ - result.allocate(); \ - result.setIndex(lhs.getIndex()); \ - \ - BOUT_FOR(i, result.getRegion("RGN_ALL")) { \ - result[i] = lhs[i] op rhs(i.x(), lhs.getIndex(), i.z()); \ - } \ - checkData(result); \ - return result; \ +#define FPERP_FPERP_OP_FIELD(op, ftype) \ + const FieldPerp operator op(const FieldPerp& lhs, const ftype& rhs) { \ + ASSERT1(lhs.getMesh() == rhs.getMesh()); \ + ASSERT1(rhs.getLocation() == rhs.getLocation()); \ + checkData(lhs); \ + checkData(rhs); \ + FieldPerp result(lhs.getMesh()); \ + result.allocate(); \ + result.setIndex(lhs.getIndex()); \ + result.setLocation(rhs.getLocation()); \ + \ + BOUT_FOR(i, result.getRegion("RGN_ALL")) { \ + result[i] = lhs[i] op rhs(i.x(), lhs.getIndex(), i.z()); \ + } \ + checkData(result); \ + return result; \ } FPERP_FPERP_OP_FIELD(+, Field3D); @@ -224,18 +271,19 @@ FPERP_FPERP_OP_FIELD(/, Field3D); FPERP_FPERP_OP_FIELD(/, Field2D); // Operator on FieldPerp and BoutReal -#define FPERP_FPERP_OP_REAL(op) \ - const FieldPerp operator op(const FieldPerp &lhs, BoutReal rhs) { \ - checkData(lhs); \ - checkData(rhs); \ - FieldPerp result(lhs.getMesh()); \ - result.allocate(); \ - result.setIndex(lhs.getIndex()); \ - \ - BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs[i] op rhs; } \ - \ - checkData(result); \ - return result; \ +#define FPERP_FPERP_OP_REAL(op) \ + const FieldPerp operator op(const FieldPerp& lhs, BoutReal rhs) { \ + checkData(lhs); \ + checkData(rhs); \ + FieldPerp result(lhs.getMesh()); \ + result.allocate(); \ + result.setIndex(lhs.getIndex()); \ + result.setLocation(lhs.getLocation()); \ + \ + BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs[i] op rhs; } \ + \ + checkData(result); \ + return result; \ } FPERP_FPERP_OP_REAL(+); @@ -243,18 +291,19 @@ FPERP_FPERP_OP_REAL(-); FPERP_FPERP_OP_REAL(*); FPERP_FPERP_OP_REAL(/); -#define FPERP_REAL_OP_FPERP(op) \ - const FieldPerp operator op(BoutReal lhs, const FieldPerp &rhs) { \ - checkData(lhs); \ - checkData(rhs); \ - FieldPerp result(rhs.getMesh()); \ - result.allocate(); \ - result.setIndex(rhs.getIndex()); \ - \ - BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs op rhs[i]; } \ - \ - checkData(result); \ - return result; \ +#define FPERP_REAL_OP_FPERP(op) \ + const FieldPerp operator op(BoutReal lhs, const FieldPerp& rhs) { \ + checkData(lhs); \ + checkData(rhs); \ + FieldPerp result(rhs.getMesh()); \ + result.allocate(); \ + result.setIndex(rhs.getIndex()); \ + result.setLocation(rhs.getLocation()); \ + \ + BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs op rhs[i]; } \ + \ + checkData(result); \ + return result; \ } // Only need the asymmetric operators @@ -280,19 +329,20 @@ FPERP_REAL_OP_FPERP(/); * result for non-finite numbers * */ -#define FPERP_FUNC(name, func) \ - const FieldPerp name(const FieldPerp &f, REGION rgn) { \ - checkData(f); \ - TRACE(#name "(FieldPerp)"); \ - /* Check if the input is allocated */ \ - ASSERT1(f.isAllocated()); \ - /* Define and allocate the output result */ \ - FieldPerp result(f.getMesh()); \ - result.allocate(); \ - result.setIndex(f.getIndex()); \ - BOUT_FOR(d, result.getRegion(rgn)) { result[d] = func(f[d]); } \ - checkData(result); \ - return result; \ +#define FPERP_FUNC(name, func) \ + const FieldPerp name(const FieldPerp& f, REGION rgn) { \ + checkData(f); \ + TRACE(#name "(FieldPerp)"); \ + /* Check if the input is allocated */ \ + ASSERT1(f.isAllocated()); \ + /* Define and allocate the output result */ \ + FieldPerp result(f.getMesh()); \ + result.allocate(); \ + result.setIndex(f.getIndex()); \ + result.setLocation(f.getLocation()); \ + BOUT_FOR(d, result.getRegion(rgn)) { result[d] = func(f[d]); } \ + checkData(result); \ + return result; \ } FPERP_FUNC(abs, ::fabs); @@ -339,7 +389,7 @@ const FieldPerp sliceXZ(const Field3D& f, int y) { // Allocate memory result.allocate(); result.setIndex(y); - + result.setLocation(f.getLocation()); BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = f(i, y); } checkData(result); @@ -417,10 +467,11 @@ FieldPerp pow(const FieldPerp &lhs, const FieldPerp &rhs, REGION rgn) { // Define and allocate the output result ASSERT1(lhs.getMesh() == rhs.getMesh()); ASSERT1(lhs.getIndex() == rhs.getIndex()); + ASSERT1(lhs.getLocation() == rhs.getLocation()); FieldPerp result(lhs.getMesh()); result.allocate(); result.setIndex(lhs.getIndex()); - + result.setLocation(lhs.getLocation()); BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } checkData(result); @@ -437,7 +488,7 @@ FieldPerp pow(const FieldPerp &lhs, BoutReal rhs, REGION rgn) { FieldPerp result(lhs.getMesh()); result.allocate(); result.setIndex(lhs.getIndex()); - + result.setLocation(lhs.getLocation()); BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs); } checkData(result); @@ -454,7 +505,7 @@ FieldPerp pow(BoutReal lhs, const FieldPerp &rhs, REGION rgn) { FieldPerp result(rhs.getMesh()); result.allocate(); result.setIndex(rhs.getIndex()); - + result.setLocation(rhs.getLocation()); BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs, rhs[i]); } checkData(result); From c53ab1714634c2dfd03bec17aa1c860bcd7d3be0 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Dec 2018 14:21:23 +0000 Subject: [PATCH 0454/1783] Adding some location checks to the unit tests --- tests/unit/field/test_fieldperp.cxx | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/unit/field/test_fieldperp.cxx b/tests/unit/field/test_fieldperp.cxx index 89611614e9..55757dc83e 100644 --- a/tests/unit/field/test_fieldperp.cxx +++ b/tests/unit/field/test_fieldperp.cxx @@ -190,6 +190,43 @@ TEST_F(FieldPerpTest, CreateCopyOnNullMesh) { } #endif +TEST_F(FieldPerpTest, SetGetLocation) { + FieldPerp field; + + field.getMesh()->StaggerGrids = true; + + field.setLocation(CELL_XLOW); + EXPECT_EQ(field.getLocation(), CELL_XLOW); + + field.setLocation(CELL_DEFAULT); + EXPECT_EQ(field.getLocation(), CELL_CENTRE); + + EXPECT_THROW(field.setLocation(CELL_VSHIFT), BoutException); +} + +TEST_F(FieldPerpTest, SetGetLocationNonStaggered) { + FieldPerp field; + + field.getMesh()->StaggerGrids = false; + +#if CHECK > 0 + EXPECT_THROW(field.setLocation(CELL_XLOW), BoutException); + EXPECT_THROW(field.setLocation(CELL_VSHIFT), BoutException); + + field.setLocation(CELL_DEFAULT); + EXPECT_EQ(field.getLocation(), CELL_CENTRE); +#else + field.setLocation(CELL_XLOW); + EXPECT_EQ(field.getLocation(), CELL_CENTRE); + + field.setLocation(CELL_DEFAULT); + EXPECT_EQ(field.getLocation(), CELL_CENTRE); + + field.setLocation(CELL_VSHIFT); + EXPECT_EQ(field.getLocation(), CELL_CENTRE); +#endif +} + /// This test is split into two parts: a very basic sanity check first /// (do we visit the right number of elements?), followed by a /// slightly more complex check one which checks certain indices are From 2a2fce6c7896a4885ccd0db7c1740c445908914c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Dec 2018 14:36:13 +0000 Subject: [PATCH 0455/1783] Set location of FieldPerp in a few more places. --- src/field/field3d.cxx | 16 +++------------- src/mesh/difops.cxx | 2 ++ 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index a29222ca9c..9a5a95ac36 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -603,16 +603,6 @@ void Field3D::applyParallelBoundary(const std::string ®ion, const std::string Field3D operator-(const Field3D &f) { return -1.0 * f; } -#define F3D_OP_FPERP(op) \ - FieldPerp operator op(const Field3D &lhs, const FieldPerp &rhs) { \ - FieldPerp result; \ - result.allocate(); \ - result.setIndex(rhs.getIndex()); \ - BOUT_FOR(i, rhs.getRegion("RGN_ALL")) { \ - result[i] = lhs(i, rhs.getIndex()) op rhs[i]; \ - return result; \ - } - //////////////// NON-MEMBER FUNCTIONS ////////////////// Field3D pow(const Field3D &lhs, const Field3D &rhs, REGION rgn) { @@ -657,17 +647,17 @@ FieldPerp pow(const Field3D &lhs, const FieldPerp &rhs, REGION rgn) { checkData(lhs); checkData(rhs); ASSERT1(lhs.getMesh() == rhs.getMesh()); + ASSERT1(lhs.getLocation() == rhs.getLocation()); FieldPerp result{rhs.getMesh()}; result.allocate(); result.setIndex(rhs.getIndex()); - + result.setLocation(rhs.getLocation()); + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs(i, rhs.getIndex()), rhs[i]); } - result.setLocation( lhs.getLocation() ); - checkData(result); return result; } diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index d271a4cda1..4dc083283b 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -1044,7 +1044,9 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, FieldPerp vx(mesh), vz(mesh); vx.allocate(); + vx.setLocation(outloc); vz.allocate(); + vz.setLocation(outloc); int ncz = mesh->LocalNz; for(int y=mesh->ystart;y<=mesh->yend;y++) { From 1be1568611c4539b70d169531831010a0ceecb75 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Dec 2018 14:52:37 +0000 Subject: [PATCH 0456/1783] Make Field::get/setLocation always throw now that all derived Fields override these --- include/field.hxx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index 13c288f635..216c12a2a8 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -32,9 +32,10 @@ class Field; #include #include "bout_types.hxx" +#include "boutexception.hxx" +#include "msg_stack.hxx" #include "stencils.hxx" #include -#include "boutexception.hxx" #include "unused.hxx" @@ -57,12 +58,15 @@ class Field { Field(Mesh * localmesh); virtual ~Field() { } - virtual void setLocation(CELL_LOC loc) { - if (loc != CELL_CENTRE) - throw BoutException("not implemented!"); + virtual void setLocation(CELL_LOC UNUSED(loc)) { + AUTO_TRACE(); + throw BoutException( + "Calling Field::setLocation which is intentionally not fully implemented."); } virtual CELL_LOC getLocation() const { - return CELL_CENTRE; + AUTO_TRACE(); + throw BoutException( + "Calling Field::getLocation which is intentionally not fully implemented."); } std::string name; From fd9e11453bcc271d4de842bc63e6b94c4b82941e Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 12 Dec 2018 15:14:46 +0000 Subject: [PATCH 0457/1783] Writing of Options to NetCDF Currently supports int, float, double and string. No sections/groups yet. --- include/options.hxx | 4 + src/sys/options/options_netcdf.cxx | 76 +++++++++++++++++++ tests/integrated/test-options-netcdf/runtest | 12 +++ .../test-options-netcdf.cxx | 3 + 4 files changed, 95 insertions(+) diff --git a/include/options.hxx b/include/options.hxx index 33693f720b..671455d314 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -485,6 +485,10 @@ public: std::map values() const; std::map subsections() const; + const std::map& getChildren() const { + return children; + } + private: /// The source label given to default values diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 326752f7b3..0305d5453c 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -54,9 +54,85 @@ Options OptionsNetCDF::read() { return result; } +/// Convert variant into NcType +/// If the type is not recognised then NcType null object is returned +struct NcTypeVisitor { + template + NcType operator()(const T& UNUSED(t)) { + return {}; // Null object by defaul + } +}; + +template <> +NcType NcTypeVisitor::operator()(const int& UNUSED(t)) { + return ncInt; +} + +template <> +NcType NcTypeVisitor::operator()(const double& UNUSED(t)) { + return ncDouble; +} + +template <> +NcType NcTypeVisitor::operator()(const float& UNUSED(t)) { + return ncFloat; +} + +template <> +NcType NcTypeVisitor::operator()(const std::string& UNUSED(t)) { + return ncString; +} + +/// Visit a variant type, and put the data into a NcVar +struct NcPutVarVisitor { + NcPutVarVisitor(NcVar &var) : var(var) {} + template + void operator()(const T& UNUSED(t)) {} +private: + NcVar &var; +}; + +template<> +void NcPutVarVisitor::operator()(const int &value) { + var.putVar(&value); +} +template<> +void NcPutVarVisitor::operator()(const double &value) { + var.putVar(&value); +} +template<> +void NcPutVarVisitor::operator()(const float &value) { + var.putVar(&value); +} +template<> +void NcPutVarVisitor::operator()(const std::string &value) { + const char* cstr = value.c_str(); + var.putVar(&cstr); +} + /// Write options to file void OptionsNetCDF::write(const Options &options) { + NcFile dataFile(filename, NcFile::replace); + + if (dataFile.isNull()) { + throw BoutException("Could not open NetCDF file '%s' for writing", filename.c_str()); + } + for (const auto& childpair : options.getChildren()) { + const auto &name = childpair.first; + const auto &child = childpair.second; + + auto nctype = bout::utils::visit(NcTypeVisitor(), child.value); + + if (nctype.isNull()) { + continue; // Skip this value + } + + auto var = dataFile.addVar(name, nctype); + + // Put the data into the variable + bout::utils::visit(NcPutVarVisitor(var), child.value); + } } diff --git a/tests/integrated/test-options-netcdf/runtest b/tests/integrated/test-options-netcdf/runtest index d07fb69b81..938fa3f97f 100755 --- a/tests/integrated/test-options-netcdf/runtest +++ b/tests/integrated/test-options-netcdf/runtest @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +#requires: false + from boututils.datafile import DataFile from boututils.run_wrapper import shell from boutdata.data import BoutOptionsFile @@ -8,6 +10,8 @@ import math shell("make") shell("rm -f test.settings") +shell("rm -f output.nc") + # Create a NetCDF input file with DataFile("test.nc", create=True, format="NETCDF4") as f: @@ -27,4 +31,12 @@ assert result["int"] == 42 assert math.isclose(result["real"], 3.1415) assert result["string"] == "hello" +print("Checking saved NetCDF file") + +# Check the output NetCDF file +with DataFile("output.nc") as f: + assert f["int"] == 42 + assert math.isclose(f["real"], 3.1415) + assert result["string"] == "hello" + print(" => Passed") diff --git a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx index 136e5e1ebd..6042df29e8 100644 --- a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx +++ b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx @@ -17,6 +17,9 @@ int main(int argc, char** argv) { // Write to an INI text file OptionsReader *reader = OptionsReader::getInstance(); reader->write(&values, "test.settings"); + + // Write to a NetCDF file + OptionsNetCDF("output.nc").write(values); BoutFinalise(); }; From 70a42c29aeb7fccd6ef7b58db6d245a8e20ebced Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 12 Dec 2018 16:24:24 +0000 Subject: [PATCH 0458/1783] Reading and writing Options groups to NetCDF Uses NetCDF groups to represent tree of options --- include/options.hxx | 8 +- src/sys/options/options_netcdf.cxx | 109 +++++++++++------- tests/integrated/test-options-netcdf/runtest | 18 ++- .../test-options-netcdf.cxx | 15 ++- 4 files changed, 102 insertions(+), 48 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index 671455d314..0c7f07ef85 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -488,7 +488,13 @@ public: const std::map& getChildren() const { return children; } - + + bool isValue() const { + return is_value; + } + bool isSection() const { + return is_section; + } private: /// The source label given to default values diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 0305d5453c..fb6c17468a 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -7,21 +7,14 @@ using namespace netCDF; -Options OptionsNetCDF::read() { - // Open file - NcFile dataFile(filename, NcFile::read); - - if (dataFile.isNull()) { - throw BoutException("Could not open NetCDF file '%s'", filename.c_str()); - } +namespace { +void readGroup(const std::string &filename, NcGroup group, Options& result) { - Options result; - // Iterate over all variables - for (const auto& varpair : dataFile.getVars()) { + for (const auto& varpair : group.getVars()) { const auto& var_name = varpair.first; // Name of the variable - const auto& var = varpair.second; // The NcVar object - + const auto& var = varpair.second; // The NcVar object + if (var.getDimCount() == 0) { // Scalar variables @@ -51,13 +44,37 @@ Options OptionsNetCDF::read() { // else ignore } } + + // Iterate over groups + for (const auto& grouppair : group.getGroups()) { + const auto& name = grouppair.first; + const auto& subgroup = grouppair.second; + + readGroup(filename, subgroup, result[name]); + } +} +} // namespace + +Options OptionsNetCDF::read() { + // Open file + NcFile dataFile(filename, NcFile::read); + + if (dataFile.isNull()) { + throw BoutException("Could not open NetCDF file '%s'", filename.c_str()); + } + + Options result; + readGroup(filename, dataFile, result); + return result; } +namespace { + /// Convert variant into NcType /// If the type is not recognised then NcType null object is returned struct NcTypeVisitor { - template + template NcType operator()(const T& UNUSED(t)) { return {}; // Null object by defaul } @@ -85,55 +102,67 @@ NcType NcTypeVisitor::operator()(const std::string& UNUSED(t)) { /// Visit a variant type, and put the data into a NcVar struct NcPutVarVisitor { - NcPutVarVisitor(NcVar &var) : var(var) {} - template + NcPutVarVisitor(NcVar& var) : var(var) {} + template void operator()(const T& UNUSED(t)) {} + private: - NcVar &var; + NcVar& var; }; -template<> -void NcPutVarVisitor::operator()(const int &value) { +template <> +void NcPutVarVisitor::operator()(const int& value) { var.putVar(&value); } -template<> -void NcPutVarVisitor::operator()(const double &value) { +template <> +void NcPutVarVisitor::operator()(const double& value) { var.putVar(&value); } -template<> -void NcPutVarVisitor::operator()(const float &value) { +template <> +void NcPutVarVisitor::operator()(const float& value) { var.putVar(&value); } -template<> -void NcPutVarVisitor::operator()(const std::string &value) { +template <> +void NcPutVarVisitor::operator()(const std::string& value) { const char* cstr = value.c_str(); var.putVar(&cstr); } -/// Write options to file -void OptionsNetCDF::write(const Options &options) { - NcFile dataFile(filename, NcFile::replace); +void writeGroup(const Options& options, NcGroup group) { - if (dataFile.isNull()) { - throw BoutException("Could not open NetCDF file '%s' for writing", filename.c_str()); - } - for (const auto& childpair : options.getChildren()) { - const auto &name = childpair.first; - const auto &child = childpair.second; + const auto& name = childpair.first; + const auto& child = childpair.second; - auto nctype = bout::utils::visit(NcTypeVisitor(), child.value); + if (child.isValue()) { + auto nctype = bout::utils::visit(NcTypeVisitor(), child.value); - if (nctype.isNull()) { - continue; // Skip this value - } + if (nctype.isNull()) { + continue; // Skip this value + } + + auto var = group.addVar(name, nctype); - auto var = dataFile.addVar(name, nctype); + // Put the data into the variable + bout::utils::visit(NcPutVarVisitor(var), child.value); + } - // Put the data into the variable - bout::utils::visit(NcPutVarVisitor(var), child.value); + if (child.isSection()) { + writeGroup(child, group.addGroup(name)); + } } } +} // namespace +/// Write options to file +void OptionsNetCDF::write(const Options& options) { + NcFile dataFile(filename, NcFile::replace); + + if (dataFile.isNull()) { + throw BoutException("Could not open NetCDF file '%s' for writing", filename.c_str()); + } + + writeGroup(options, dataFile); +} #endif // NCDF4 diff --git a/tests/integrated/test-options-netcdf/runtest b/tests/integrated/test-options-netcdf/runtest index 938fa3f97f..521883c66b 100755 --- a/tests/integrated/test-options-netcdf/runtest +++ b/tests/integrated/test-options-netcdf/runtest @@ -9,9 +9,8 @@ from boutdata.data import BoutOptionsFile import math shell("make") -shell("rm -f test.settings") -shell("rm -f output.nc") - +shell("rm -f test-out.ini") +shell("rm -f test-out.nc") # Create a NetCDF input file with DataFile("test.nc", create=True, format="NETCDF4") as f: @@ -23,7 +22,7 @@ with DataFile("test.nc", create=True, format="NETCDF4") as f: shell("./test-options-netcdf") # Check the output INI file -result = BoutOptionsFile("test.settings") +result = BoutOptionsFile("test-out.ini") print(result) @@ -34,9 +33,18 @@ assert result["string"] == "hello" print("Checking saved NetCDF file") # Check the output NetCDF file -with DataFile("output.nc") as f: +with DataFile("test-out.nc") as f: assert f["int"] == 42 assert math.isclose(f["real"], 3.1415) assert result["string"] == "hello" +print("Checking saved settings.ini") + +# Check the settings.ini file, coming from BOUT.inp +# which is converted to NetCDF, read in, then written again +settings = BoutOptionsFile("settings.ini") + +assert settings["mesh"]["nx"] == 5 +assert settings["mesh"]["ny"] == 5 + print(" => Passed") diff --git a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx index 6042df29e8..82c5c09e98 100644 --- a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx +++ b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx @@ -16,10 +16,21 @@ int main(int argc, char** argv) { // Write to an INI text file OptionsReader *reader = OptionsReader::getInstance(); - reader->write(&values, "test.settings"); + reader->write(&values, "test-out.ini"); // Write to a NetCDF file - OptionsNetCDF("output.nc").write(values); + OptionsNetCDF("test-out.nc").write(values); + + /////////////////////////// + + // Write the BOUT.inp settings to NetCDF file + OptionsNetCDF("settings.nc").write(Options::root()); + + // Read back in + auto settings = OptionsNetCDF("settings.nc").read(); + + // Write to INI file + reader->write(&settings, "settings.ini"); BoutFinalise(); }; From 4482c84cc7a42ab35d8d70ff7b9e461ecb3da4dc Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 12 Dec 2018 16:49:19 +0000 Subject: [PATCH 0459/1783] Make free interpolate use the Lagrange4pt class This helps avoid code duplication --- include/interpolation.hxx | 13 +++--- src/mesh/interpolation.cxx | 81 +------------------------------------- 2 files changed, 7 insertions(+), 87 deletions(-) diff --git a/include/interpolation.hxx b/include/interpolation.hxx index 73e3115512..7f58f5a31c 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -52,18 +52,15 @@ const Field3D interpolate(const Field2D &f, const Field3D &delta_x); class Interpolation { protected: + Mesh* localmesh{nullptr}; + // 3D vector of points to skip (true -> skip this point) BoutMask skip_mask; - Mesh *localmesh; - public: - Interpolation(int y_offset = 0, Mesh *mesh = nullptr) - : localmesh(mesh), y_offset(y_offset) { - if (mesh == nullptr) { - localmesh = mesh; - } - } + Interpolation(int y_offset = 0, Mesh* localmeshIn = nullptr) + : localmesh(localmeshIn == nullptr ? mesh : localmeshIn), + skip_mask(*localmesh, false), y_offset(y_offset) {} Interpolation(const BoutMask &mask, int y_offset = 0, Mesh *mesh = nullptr) : Interpolation(y_offset, mesh) { skip_mask = mask; diff --git a/src/mesh/interpolation.cxx b/src/mesh/interpolation.cxx index a979df641f..3598235aaf 100644 --- a/src/mesh/interpolation.cxx +++ b/src/mesh/interpolation.cxx @@ -427,88 +427,11 @@ void printLocation(const Field2D &var) { output.write(strLocation(var.getLocatio const char *strLocation(CELL_LOC loc) { return CELL_LOC_STRING(loc).c_str(); } -// 4-point Lagrangian interpolation -// offset must be between 0 and 1 -BoutReal lagrange_4pt(BoutReal v2m, BoutReal vm, BoutReal vp, BoutReal v2p, - BoutReal offset) { - return -offset * (offset - 1.0) * (offset - 2.0) * v2m / 6.0 + - 0.5 * (offset * offset - 1.0) * (offset - 2.0) * vm - - 0.5 * offset * (offset + 1.0) * (offset - 2.0) * vp + - offset * (offset * offset - 1.0) * v2p / 6.0; -} - -BoutReal lagrange_4pt(BoutReal v[], BoutReal offset) { - return lagrange_4pt(v[0], v[1], v[2], v[3], offset); -} - const Field3D interpolate(const Field3D &f, const Field3D &delta_x, const Field3D &delta_z) { TRACE("Interpolating 3D field"); - - Mesh *mesh = f.getMesh(); - ASSERT1(mesh == delta_x.getMesh()); - ASSERT1(mesh == delta_z.getMesh()); - Field3D result(mesh); - result.allocate(); - - // Loop over output grid points - for (int jx = 0; jx < mesh->LocalNx; jx++) { - for (int jy = 0; jy < mesh->LocalNy; jy++) { - for (int jz = 0; jz < mesh->LocalNz; jz++) { - // Need to get value of f at - // [jx + delta_x[jx][jy][jz]][jy][jz + delta_z[jx][jy][jz]] - - // get lower (rounded down) index - int jxmnew = static_cast(delta_x(jx, jy, jz)); - int jzmnew = static_cast(delta_z(jx, jy, jz)); - // and the distance from this point - BoutReal xs = delta_x(jx, jy, jz) - static_cast(jxmnew); - BoutReal zs = delta_z(jx, jy, jz) - static_cast(jzmnew); - // Get new lower index - jxmnew += jx; - jzmnew += jz; - - // Check bounds. If beyond bounds just constant - if (jxmnew < 0) { - jxmnew = 0; - xs = 0.0; - } else if (jxmnew >= (mesh->LocalNx - 1)) { - // Want to always be able to use [jxnew] and [jxnew+1] - jxmnew = mesh->LocalNx - 2; - xs = 1.0; - } - - int jx2mnew = (jxmnew == 0) ? 0 : (jxmnew - 1); - int jxpnew = jxmnew + 1; - int jx2pnew = (jxmnew == (mesh->LocalNx - 2)) ? jxpnew : (jxpnew + 1); - - int ncz = mesh->LocalNz; - - // Get the 4 Z points - jzmnew = ((jzmnew % ncz) + ncz) % ncz; - int jzpnew = (jzmnew + 1) % ncz; - int jz2pnew = (jzmnew + 2) % ncz; - int jz2mnew = (jzmnew - 1 + ncz) % ncz; - - // Now have 4 indices for X and Z to interpolate - - // Interpolate in Z first - BoutReal xvals[4]; - - xvals[0] = lagrange_4pt(f(jx2mnew, jy, jz2mnew), f(jx2mnew, jy, jzmnew), - f(jx2mnew, jy, jzpnew), f(jx2mnew, jy, jz2pnew), zs); - xvals[1] = lagrange_4pt(f(jxmnew, jy, jz2mnew), f(jxmnew, jy, jzmnew), - f(jxmnew, jy, jzpnew), f(jxmnew, jy, jz2pnew), zs); - xvals[2] = lagrange_4pt(f(jxpnew, jy, jz2mnew), f(jxpnew, jy, jzmnew), - f(jxpnew, jy, jzpnew), f(jxpnew, jy, jz2pnew), zs); - xvals[3] = lagrange_4pt(f(jx2pnew, jy, jz2mnew), f(jx2pnew, jy, jzmnew), - f(jx2pnew, jy, jzpnew), f(jx2pnew, jy, jz2pnew), zs); - // Then in X - result(jx, jy, jz) = lagrange_4pt(xvals, xs); - } - } - } - return result; + Lagrange4pt interpolateMethod{f.getMesh()}; + return interpolateMethod.interpolate(f, delta_x, delta_z); } const Field3D interpolate(const Field2D &f, const Field3D &delta_x, From 6393b0a671b497a4c102195886e5c55fa45a5c25 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 12 Dec 2018 16:47:49 +0000 Subject: [PATCH 0460/1783] Check derivatives that transform to field-aligned in test-yupdown Use a variable that does not have calcYUpDown called, so that the branch of the derivative that uses toFieldAligned/fromFieldAligned is entered. Also make test-yupdown part of the standard test suite by removing all_tests requirement --- tests/integrated/test-yupdown/runtest | 28 ++++++++++--------- .../integrated/test-yupdown/test_yupdown.cxx | 16 +++++++---- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/tests/integrated/test-yupdown/runtest b/tests/integrated/test-yupdown/runtest index c1da2a7501..dc6859090e 100755 --- a/tests/integrated/test-yupdown/runtest +++ b/tests/integrated/test-yupdown/runtest @@ -1,10 +1,8 @@ #!/usr/bin/env python3 -#requires: all_tests - from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun from boutdata.collect import collect -from sys import stdout, exit +from sys import exit from numpy import max, abs @@ -18,18 +16,22 @@ s, out = launch_safe("./test_yupdown", runcmd=MPIRUN, nproc=1, pipe=True, verbos with open("run.log", "w") as f: f.write(out) -vars = [ ("ddy", "ddy2") ] -for v1, v2 in vars: - stdout.write("Testing %s and %s ... " % (v1, v2) ) - ddy = collect(v1, path="data", xguards=False, yguards=False, info=False) - ddy2 = collect(v2, path="data", xguards=False, yguards=False, info=False) +vars = [ ("ddy", "ddy_check"), ("ddy2", "ddy_check") ] +success = True +for v, v_check in vars: + print("Testing %s and %s ... " % (v, v_check) ) + ddy = collect(v, path="data", xguards=False, yguards=False, info=False) + ddy_check = collect(v_check, path="data", xguards=False, yguards=False, info=False) - diff = max(abs(ddy - ddy2)) + diff = max(abs(ddy - ddy_check)) if diff < 1e-8: - print("Passed (Max difference %e)" % (diff)) + print(v+" passed (Max difference %e)" % (diff)) else: - print("Failed (Max difference %e)" % (diff)) + print(v+" failed (Max difference %e)" % (diff)) + success = False + +if success: + exit(0) +else: exit(1) - -exit(0) diff --git a/tests/integrated/test-yupdown/test_yupdown.cxx b/tests/integrated/test-yupdown/test_yupdown.cxx index e414c0ba88..dbadc6372f 100644 --- a/tests/integrated/test-yupdown/test_yupdown.cxx +++ b/tests/integrated/test-yupdown/test_yupdown.cxx @@ -42,25 +42,31 @@ int main(int argc, char** argv) { // Read variable from mesh Field3D var; mesh->get(var, "var"); + + Field3D var2 = copy(var); // Var starts in orthogonal X-Z coordinates // Calculate yup and ydown s.calcYUpDown(var); - // Calculate d/dy ysing yup() and ydown() fields - Field3D ddy = DDY_yud(var); + // Calculate d/dy using yup() and ydown() fields + Field3D ddy = DDY(var); + + // Calculate d/dy by transform to field-aligned coordinates + // (var2 has no yup/ydown fields) + Field3D ddy2 = DDY(var2); // Change into field-aligned coordinates Field3D var_aligned = mesh->toFieldAligned(var); // var now field aligned - Field3D ddy2 = DDY_aligned(var_aligned); + Field3D ddy_check = DDY_aligned(var_aligned); // Shift back to orthogonal X-Z coordinates - ddy2 = mesh->fromFieldAligned(ddy2); + ddy_check = mesh->fromFieldAligned(ddy_check); - SAVE_ONCE2(ddy, ddy2); + SAVE_ONCE3(ddy, ddy2, ddy_check); dump.write(); BoutFinalise(); From 74898d22120509c9dcb475c47d19347dac80ea29 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 12 Dec 2018 16:38:22 +0000 Subject: [PATCH 0461/1783] Pass f_aligned to standardDerivative in DDY/D2DY2/D4DY4 --- include/bout/index_derivs_interface.hxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 742b2b0110..154a6b9fd6 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -214,7 +214,7 @@ T DDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "D } else { const T f_aligned = f.getMesh()->toFieldAligned(f); T result = - standardDerivative(f, outloc, method, region); + standardDerivative(f_aligned, outloc, method, region); return f.getMesh()->fromFieldAligned(result); } } @@ -229,7 +229,7 @@ T D2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = f, outloc, method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = standardDerivative(f, outloc, + T result = standardDerivative(f_aligned, outloc, method, region); return f.getMesh()->fromFieldAligned(result); } @@ -245,7 +245,7 @@ T D4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = f, outloc, method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = standardDerivative(f, outloc, + T result = standardDerivative(f_aligned, outloc, method, region); return f.getMesh()->fromFieldAligned(result); } From 6d7e8e23c3320973edea4fb9d754ecd0d4865cb2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 12 Dec 2018 17:01:26 +0000 Subject: [PATCH 0462/1783] Add output_verbose for non-default messages --- include/output.hxx | 1 + src/bout++.cxx | 15 ++++++++------- src/sys/output.cxx | 1 + 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/include/output.hxx b/include/output.hxx index 49dbd28ba8..5103758909 100644 --- a/include/output.hxx +++ b/include/output.hxx @@ -259,6 +259,7 @@ extern ConditionalOutput output_warn; ///< warnings extern ConditionalOutput output_progress; ///< progress extern ConditionalOutput output_info; ///< information extern ConditionalOutput output_error; ///< errors +extern ConditionalOutput output_verbose; ///< less interesting messages /// Generic output, given the same level as output_progress extern ConditionalOutput output; diff --git a/src/bout++.cxx b/src/bout++.cxx index f2b6525924..76aede060c 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -338,13 +338,14 @@ int BoutInitialise(int &argc, char **&argv) { return 1; } } - - output_error.enable(verbosity>0); - output_warn.enable(verbosity>1); - output_progress.enable(verbosity>2); - output_info.enable(verbosity>3); - output_debug.enable(verbosity>4); //Only actually enabled if also compiled with DEBUG - + + output_error.enable(verbosity > 0); + output_warn.enable(verbosity > 1); + output_progress.enable(verbosity > 2); + output_info.enable(verbosity > 3); + output_debug.enable(verbosity > 4); // Only actually enabled if also compiled with DEBUG + output_verbose.enable(verbosity > 5); + // The backward-compatible output object same as output_progress output.enable(verbosity>2); diff --git a/src/sys/output.cxx b/src/sys/output.cxx index d03aeaa356..19945304b7 100644 --- a/src/sys/output.cxx +++ b/src/sys/output.cxx @@ -150,6 +150,7 @@ ConditionalOutput output_warn(Output::getInstance()); ConditionalOutput output_info(Output::getInstance()); ConditionalOutput output_progress(Output::getInstance()); ConditionalOutput output_error(Output::getInstance()); +ConditionalOutput output_verbose(Output::getInstance()); ConditionalOutput output(Output::getInstance()); #undef bout_vsnprint_pre From eba566a69aa25acfdbd62a84f31ec80ef2700354 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 12 Dec 2018 17:16:11 +0000 Subject: [PATCH 0463/1783] Add optional argument for ConditionalOutput to disable by default --- include/output.hxx | 3 ++- src/sys/output.cxx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/output.hxx b/include/output.hxx index 5103758909..7c330a0a5a 100644 --- a/include/output.hxx +++ b/include/output.hxx @@ -148,7 +148,8 @@ public: class ConditionalOutput : public Output { public: /// @param[in] base The Output object which will be written to if enabled - ConditionalOutput(Output *base) : base(base), enabled(true) {}; + /// @param[in] enabled Should this be enabled by default? + ConditionalOutput(Output *base, bool enabled = true) : base(base), enabled(enabled) {}; /// Constuctor taking ConditionalOutput. This allows several layers of conditions /// diff --git a/src/sys/output.cxx b/src/sys/output.cxx index 19945304b7..42cad9195e 100644 --- a/src/sys/output.cxx +++ b/src/sys/output.cxx @@ -150,7 +150,7 @@ ConditionalOutput output_warn(Output::getInstance()); ConditionalOutput output_info(Output::getInstance()); ConditionalOutput output_progress(Output::getInstance()); ConditionalOutput output_error(Output::getInstance()); -ConditionalOutput output_verbose(Output::getInstance()); +ConditionalOutput output_verbose(Output::getInstance(), false); ConditionalOutput output(Output::getInstance()); #undef bout_vsnprint_pre From 7e7a571b98b321b1e7a4b79415eb390158dcc29d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 12 Dec 2018 17:20:02 +0000 Subject: [PATCH 0464/1783] Don't throw if trying to enable a DummyOutput --- include/output.hxx | 10 ++-------- tests/unit/sys/test_output.cxx | 6 +++--- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/include/output.hxx b/include/output.hxx index 7c330a0a5a..1d85f16b75 100644 --- a/include/output.hxx +++ b/include/output.hxx @@ -128,15 +128,9 @@ class DummyOutput : public Output { public: void write(const char *UNUSED(str), ...) override{}; void print(const char *UNUSED(str), ...) override{}; - void enable() override { - throw BoutException("DummyOutput cannot be enabled.\nTry compiling with " - "--enable-debug or be less verbose?"); - }; + void enable() override{}; void disable() override{}; - void enable(bool enable) { - if (enable) - this->enable(); - }; + void enable(MAYBE_UNUSED(bool enable)){}; bool isEnabled() override { return false; } }; diff --git a/tests/unit/sys/test_output.cxx b/tests/unit/sys/test_output.cxx index 742fdc420d..63055a2ce6 100644 --- a/tests/unit/sys/test_output.cxx +++ b/tests/unit/sys/test_output.cxx @@ -271,11 +271,11 @@ TEST_F(OutputTest, DummyCheckEnableDoesntWork) { DummyOutput dummy; EXPECT_FALSE(dummy.isEnabled()); - EXPECT_THROW(dummy.enable(), BoutException); + dummy.enable(); EXPECT_FALSE(dummy.isEnabled()); - EXPECT_THROW(dummy.enable(true), BoutException); + dummy.enable(true); EXPECT_FALSE(dummy.isEnabled()); - EXPECT_NO_THROW(dummy.enable(false)); + dummy.enable(false); EXPECT_FALSE(dummy.isEnabled()); dummy.disable(); EXPECT_FALSE(dummy.isEnabled()); From d5d7d26ccc4db8538f1b50dab90223f6d42aed4c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 12 Dec 2018 17:24:55 +0000 Subject: [PATCH 0465/1783] Use output_verbose when registering regions --- src/mesh/mesh.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 73bca69767..55c79c6801 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -364,8 +364,8 @@ void Mesh::addRegion3D(const std::string ®ion_name, const Region<> ®ion) { throw BoutException(_("Trying to add an already existing region %s to regionMap3D"), region_name.c_str()); } regionMap3D[region_name] = region; - output_info << _("Registered region 3D ") << region_name << ": \n"; - output_info << "\t" << region.getStats() << "\n"; + output_verbose << _("Registered region 3D ") << region_name << ": \n" + << "\t" << region.getStats() << "\n"; } void Mesh::addRegion2D(const std::string ®ion_name, const Region ®ion) { @@ -373,8 +373,8 @@ void Mesh::addRegion2D(const std::string ®ion_name, const Region ®i throw BoutException(_("Trying to add an already existing region %s to regionMap2D"), region_name.c_str()); } regionMap2D[region_name] = region; - output_info << _("Registered region 2D ") << region_name << ": \n"; - output_info << "\t" << region.getStats() << "\n"; + output_verbose << _("Registered region 2D ") << region_name << ": \n" + << "\t" << region.getStats() << "\n"; } void Mesh::addRegionPerp(const std::string ®ion_name, const Region ®ion) { @@ -382,8 +382,8 @@ void Mesh::addRegionPerp(const std::string ®ion_name, const Region & throw BoutException(_("Trying to add an already existing region %s to regionMapPerp"), region_name.c_str()); } regionMapPerp[region_name] = region; - output_info << _("Registered region Perp ") << region_name << ": \n"; - output_info << "\t" << region.getStats() << "\n"; + output_verbose << _("Registered region Perp ") << region_name << ": \n" + << "\t" << region.getStats() << "\n"; } void Mesh::createDefaultRegions(){ From ac4274f3ae695ca5687275481cecded6a59d527a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 12 Dec 2018 17:30:22 +0000 Subject: [PATCH 0466/1783] Use output_verbose in derivative store --- include/bout/deriv_store.hxx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index a59a4cdf93..92ae5fa846 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -379,9 +379,9 @@ struct DerivativeStore { theDefault = uppercase(theDefault); defaultMethods[getKey(theDirection, STAGGER::None, theDerivTypeString)] = theDefault; - output_info << "The default method for derivative type " << theDerivTypeString; - output_info << " in direction " << DIRECTION_STRING(theDirection); - output_info << " is " << theDefault << "\n"; + output_verbose << "The default method for derivative type " << theDerivTypeString + << " in direction " << DIRECTION_STRING(theDirection) << " is " + << theDefault << "\n"; //------------------------------------------------------------- // Staggered @@ -403,10 +403,9 @@ struct DerivativeStore { theDefault; defaultMethods[getKey(theDirection, STAGGER::C2L, theDerivTypeString)] = theDefault; - output_info << "The default method for staggered derivative type " - << theDerivTypeString; - output_info << " in direction " << DIRECTION_STRING(theDirection); - output_info << " is " << theDefault << "\n"; + output_verbose << "The default method for staggered derivative type " + << theDerivTypeString << " in direction " + << DIRECTION_STRING(theDirection) << " is " << theDefault << "\n"; } } } From 1b5e9441741bbb08e55f658c880fc6428f5dc208 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 12 Dec 2018 17:44:26 +0000 Subject: [PATCH 0467/1783] Fix python false->False and add note Configure defines NCDF on Travis, but NCDF4 is needed for new code. --- tests/integrated/test-options-netcdf/runtest | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/integrated/test-options-netcdf/runtest b/tests/integrated/test-options-netcdf/runtest index 521883c66b..760d229f3c 100755 --- a/tests/integrated/test-options-netcdf/runtest +++ b/tests/integrated/test-options-netcdf/runtest @@ -1,6 +1,7 @@ #!/usr/bin/env python3 -#requires: false +# Note: This test requires NCDF4, whereas on Travis NCDF is used +#requires: False from boututils.datafile import DataFile from boututils.run_wrapper import shell From 468f8161e9534f0bd4ae495a1af41a01c56f585f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 13 Dec 2018 11:32:55 +0000 Subject: [PATCH 0468/1783] Add a few more explicit region arguments to fromFieldAligned calls --- src/field/field_factory.cxx | 2 +- src/fileio/datafile.cxx | 2 +- src/mesh/difops.cxx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index a281e97779..bc679e8a30 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -229,7 +229,7 @@ const Field3D FieldFactory::create3D(const std::string &value, const Options *op if (localmesh->canToFromFieldAligned()){ // Ask wheter it is possible // Transform from field aligned coordinates, to be compatible with // older BOUT++ inputs. This is not a particularly "nice" solution. - result = localmesh->fromFieldAligned(result); + result = localmesh->fromFieldAligned(result, RGN_ALL); } return result; diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index ba6b259395..b6ef8a1298 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -1151,7 +1151,7 @@ bool Datafile::read_f3d(const std::string &name, Field3D *f, bool save_repeat) { if (shiftInput) { // Input file is in field-aligned coordinates e.g. BOUT++ 3.x restart file - *f = mesh->fromFieldAligned(*f); + *f = mesh->fromFieldAligned(*f, RGN_ALL); } return true; diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index 7287bcbfa2..9dacc13998 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -306,7 +306,7 @@ const Field3D Grad_par_CtoL(const Field3D &var) { } } - result = mesh->fromFieldAligned(result); + result = mesh->fromFieldAligned(result, RGN_NOBNDRY); } result.setLocation(CELL_YLOW); From 18731d72e59aceb2943edf404fcb337610abe0fb Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 13 Dec 2018 17:08:24 +0000 Subject: [PATCH 0469/1783] Options can store Field2D, Field3D Variant type now has these fields in the type list. Handling these required some related changes: - Added toString specialisations for Field2D, Field3D - The Options::as() template function now takes an optional Mesh pointer. For most types this is not used, but for fields it can be used to parse strings using FieldFactory. Unit tests added in sys/test_options_fields. The `FieldFactory::create2D/3D` routines end up calling `Mesh::getParallelTransform`, which uses the `Mesh::options` pointer. This is now set to `Options::root` in `FakeMesh`. --- include/bout/sys/variant.hxx | 2 +- include/field2d.hxx | 8 ++ include/field3d.hxx | 9 ++ include/options.hxx | 33 +++++-- src/sys/options.cxx | 52 ++++++++++- tests/unit/sys/test_options_fields.cxx | 119 +++++++++++++++++++++++++ tests/unit/test_extras.hxx | 3 + 7 files changed, 214 insertions(+), 12 deletions(-) create mode 100644 tests/unit/sys/test_options_fields.cxx diff --git a/include/bout/sys/variant.hxx b/include/bout/sys/variant.hxx index 0ffcb3c51e..09f37f12e7 100644 --- a/include/bout/sys/variant.hxx +++ b/include/bout/sys/variant.hxx @@ -132,7 +132,7 @@ struct StaticCastOrThrow { /// in which case std::bad_cast will be thrown at runtime template T variantStaticCastOrThrow(const Variant &v) { - visit( details::StaticCastOrThrow(), v ); + return visit( details::StaticCastOrThrow(), v ); } namespace details { diff --git a/include/field2d.hxx b/include/field2d.hxx index adbf8b0800..955044904d 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -41,6 +41,7 @@ class Field3D; //#include "field3d.hxx" #include "bout/array.hxx" #include "bout/region.hxx" +#include "utils.hxx" #include "unused.hxx" @@ -463,4 +464,11 @@ inline Field2D& ddt(Field2D &f) { return *(f.timeDeriv()); } +/// toString template specialisation +/// Defined in utils.hxx +template <> +inline std::string toString<>(const Field2D& UNUSED(val)) { + return ""; +} + #endif /* __FIELD2D_H__ */ diff --git a/include/field3d.hxx b/include/field3d.hxx index f72d21f502..c3bd525f12 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -40,6 +40,8 @@ class Mesh; // #include "bout/mesh.hxx" #include "bout/field_visitor.hxx" +#include "utils.hxx" + /// Class for 3D X-Y-Z scalar fields /*! This class represents a scalar field defined over the mesh. @@ -752,4 +754,11 @@ inline Field3D& ddt(Field3D &f) { return *(f.timeDeriv()); } +/// toString template specialisation +/// Defined in utils.hxx +template <> +inline std::string toString<>(const Field3D& UNUSED(val)) { + return ""; +} + #endif /* __FIELD3D_H__ */ diff --git a/include/options.hxx b/include/options.hxx index 0c7f07ef85..16c9f77e88 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -44,6 +44,8 @@ class Options; #include "output.hxx" #include "utils.hxx" #include "bout/sys/variant.hxx" +#include "field2d.hxx" +#include "field3d.hxx" #include #include @@ -181,7 +183,7 @@ public: static void cleanup(); /// The type used to store values - using ValueType = bout::utils::variant; + using ValueType = bout::utils::variant; /// The type used to store attributes using AttributeType = bout::utils::variant; @@ -297,7 +299,8 @@ public: /// option["test"] = 2.0; /// int value = option["test"].as(); /// - template T as() const { + template + T as(Mesh* mesh = nullptr) const { if (!is_value) { throw BoutException("Option %s has no value", full_name.c_str()); } @@ -306,7 +309,7 @@ public: // Try casting. This will throw std::bad_cast if it can't be done try { - val = bout::utils::variantStaticCastOrThrow(value); + val = bout::utils::variantStaticCastOrThrow(value); } catch (const std::bad_cast &e) { // If the variant is a string then we may be able to parse it @@ -552,15 +555,31 @@ template<> inline void Options::assign<>(BoutReal val, const std::string source) template<> inline void Options::assign<>(std::string val, const std::string source) { _set(val, source, false); } // Note: const char* version needed to avoid conversion to bool template<> inline void Options::assign<>(const char *val, const std::string source) { _set(std::string(val), source, false);} +// Note: Field assignments don't check for previous assignment (always force) +template<> inline void Options::assign<>(Field2D val, const std::string source) { + value = std::move(val); + attributes["source"] = std::move(source); + value_used = false; + is_value = true; +} +template<> inline void Options::assign<>(Field3D val, const std::string source) { + value = std::move(val); + attributes["source"] = std::move(source); + value_used = false; + is_value = true; +} + /// Specialised similar comparison methods template <> inline bool Options::similar(BoutReal a, BoutReal b) const { return fabs(a - b) < 1e-10; } /// Specialised as routines -template <> std::string Options::as() const; -template <> int Options::as() const; -template <> BoutReal Options::as() const; -template <> bool Options::as() const; +template <> std::string Options::as(Mesh* mesh) const; +template <> int Options::as(Mesh* mesh) const; +template <> BoutReal Options::as(Mesh* mesh) const; +template <> bool Options::as(Mesh* mesh) const; +template <> Field2D Options::as(Mesh* mesh) const; +template <> Field3D Options::as(Mesh* mesh) const; /// Define for reading options which passes the variable name #define OPTION(options, var, def) \ diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 2195855692..a5a3ccf9ce 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -87,7 +87,7 @@ bool Options::isSet() const { return true; } -template <> std::string Options::as() const { +template <> std::string Options::as(Mesh* UNUSED(mesh)) const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); } @@ -107,7 +107,7 @@ template <> std::string Options::as() const { return result; } -template <> int Options::as() const { +template <> int Options::as(Mesh* UNUSED(mesh)) const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); } @@ -162,7 +162,7 @@ template <> int Options::as() const { return result; } -template <> BoutReal Options::as() const { +template <> BoutReal Options::as(Mesh* UNUSED(mesh)) const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); } @@ -204,7 +204,7 @@ template <> BoutReal Options::as() const { return result; } -template <> bool Options::as() const { +template <> bool Options::as(Mesh* UNUSED(mesh)) const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); } @@ -244,6 +244,50 @@ template <> bool Options::as() const { return result; } +template <> Field3D Options::as(Mesh* mesh) const { + if (!is_value) { + throw BoutException("Option %s has no value", full_name.c_str()); + } + + Field3D val; + + try { + val = bout::utils::variantStaticCastOrThrow(value); + } catch (const std::bad_cast &e) { + + // Convert from a string using FieldFactory + if (bout::utils::holds_alternative(value)) { + return FieldFactory::get()->create3D( bout::utils::get(value), this, mesh); + } else { + throw BoutException(_("Value for option %s cannot be converted to a BoutReal"), + full_name.c_str()); + } + } + return val; +} + +template <> Field2D Options::as(Mesh* mesh) const { + if (!is_value) { + throw BoutException("Option %s has no value", full_name.c_str()); + } + + Field2D val; + + try { + val = bout::utils::variantStaticCastOrThrow(value); + } catch (const std::bad_cast &e) { + + // Convert from a string using FieldFactory + if (bout::utils::holds_alternative(value)) { + return FieldFactory::get()->create2D( bout::utils::get(value), this, mesh); + } else { + throw BoutException(_("Value for option %s cannot be converted to a BoutReal"), + full_name.c_str()); + } + } + return val; +} + void Options::printUnused() const { bool allused = true; // Check if any options are unused diff --git a/tests/unit/sys/test_options_fields.cxx b/tests/unit/sys/test_options_fields.cxx new file mode 100644 index 0000000000..c1b47eeb6e --- /dev/null +++ b/tests/unit/sys/test_options_fields.cxx @@ -0,0 +1,119 @@ +// Test the Options class methods which involve Field2D/3D +// These need a Mesh fixture, unlike the tests with scalars + +#include "gtest/gtest.h" + +#include "bout/mesh.hxx" +#include "field3d.hxx" +#include "test_extras.hxx" + +/// Global mesh +extern Mesh *mesh; + +// Reuse the "standard" fixture for FakeMesh +using OptionsFieldTest = FakeMeshFixture; + +TEST_F(OptionsFieldTest, StoreField3D) { + Field3D field = 1.0; + Options options; + + EXPECT_FALSE(options.isValue()); + + options = field; + + EXPECT_TRUE(options.isValue()); +} + +TEST_F(OptionsFieldTest, StoreField2D) { + Field2D field = 1.0; + Options options; + + EXPECT_FALSE(options.isValue()); + + options = field; + + EXPECT_TRUE(options.isValue()); +} + +TEST_F(OptionsFieldTest, RetrieveField3D) { + Field3D field = 1.0; + field(0,1,1) = 2.0; + + Options options; + options = field; + + Field3D other = options; + + EXPECT_DOUBLE_EQ(other(0,1,0), 1.0); + EXPECT_DOUBLE_EQ(other(0,1,1), 2.0); +} + +TEST_F(OptionsFieldTest, RetrieveField3DfromBoutReal) { + Options options; + options = 1.2; + + Field3D other = options; + + EXPECT_DOUBLE_EQ(other(0,1,0), 1.2); + EXPECT_DOUBLE_EQ(other(0,0,1), 1.2); +} + +TEST_F(OptionsFieldTest, RetrieveBoutRealfromField3D) { + Options options; + Field3D field = 1.2; + options = field; + + EXPECT_THROW(BoutReal value = options, BoutException); +} + +TEST_F(OptionsFieldTest, RetrieveField2DfromField3D) { + Options options; + Field3D field = 1.2; + options = field; + + EXPECT_THROW(Field2D value = options.as(mesh), BoutException); +} + +TEST_F(OptionsFieldTest, RetrieveStringfromField3D) { + Options options; + Field3D field = 1.2; + options = field; + + EXPECT_EQ(options.as(), ""); +} + +TEST_F(OptionsFieldTest, RetrieveStringfromField2D) { + Options options; + Field2D field = 1.2; + options = field; + + EXPECT_EQ(options.as(), ""); +} + +TEST_F(OptionsFieldTest, RetrieveField3DfromString) { + Options options; + options = "1 + 2"; + + Field3D other = options.as(mesh); + + EXPECT_DOUBLE_EQ(other(0,1,0), 3.0); + EXPECT_DOUBLE_EQ(other(0,0,1), 3.0); +} + +TEST_F(OptionsFieldTest, RetrieveField2DfromString) { + Options options; + options = "1 + 2"; + + Field2D other = options.as(mesh); + + EXPECT_DOUBLE_EQ(other(0,1,0), 3.0); + EXPECT_DOUBLE_EQ(other(0,0,1), 3.0); +} + +TEST_F(OptionsFieldTest, RetrieveField2DfromBadString) { + Options options; + options = "1 + "; + + EXPECT_THROW(Field2D other = options.as(mesh), ParseException); +} + diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index b042e2a933..5da2dd017a 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -73,6 +73,9 @@ public: StaggerGrids = false; IncIntShear = false; maxregionblocksize = MAXREGIONBLOCKSIZE; + + // Need some options for parallelTransform + options = Options::getRoot(); } comm_handle send(FieldGroup &UNUSED(g)) { return nullptr; }; From f8907133dabad34664946ad33fe4c2fbc4dba144 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 14 Dec 2018 00:10:10 +0000 Subject: [PATCH 0470/1783] Write Field2D,Field3D from Options to NetCDF Can put Field2D and Field3D objects into an Options tree, then write out to NetCDF. Doesn't yet handle time dimensions. --- src/sys/options/options_netcdf.cxx | 90 ++++++++++++++++++- .../test-options-netcdf/data/BOUT.inp | 4 +- tests/integrated/test-options-netcdf/runtest | 13 ++- .../test-options-netcdf.cxx | 3 + 4 files changed, 102 insertions(+), 8 deletions(-) diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index fb6c17468a..9e19dbabe9 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -3,6 +3,7 @@ #include "options_netcdf.hxx" +#include #include using namespace netCDF; @@ -100,6 +101,74 @@ NcType NcTypeVisitor::operator()(const std::string& UNUSED(t)) { return ncString; } +template <> +NcType NcTypeVisitor::operator()(const Field2D& UNUSED(t)) { + return operator()(0.0); +} + +template <> +NcType NcTypeVisitor::operator()(const Field3D& UNUSED(t)) { + return operator()(0.0); +} + +/// Visit a variant type, returning dimensions +struct NcDimVisitor { + NcDimVisitor(NcGroup& group) : group(group) {} + template + std::vector operator()(const T& UNUSED(t)) { + return {}; + } +private: + NcGroup& group; +}; + +NcDim findDimension(NcGroup& group, const std::string& name, unsigned int size) { + // Get the dimension + auto dim = group.getDim(name, NcGroup::ParentsAndCurrent); + if (dim.isNull()) { + // Dimension doesn't yet exist + dim = group.addDim(name, size); + } else { + // Dimension exists, check it's the right size + if (dim.getSize() != size) { + // wrong size. Check this group + dim = group.getDim(name, NcGroup::Current); + if (!dim.isNull()) { + // Already defined in this group + return {}; // Return null object + } + // Define in this group + dim = group.addDim(name, size); + } + } + return dim; +} + +template <> +std::vector NcDimVisitor::operator()(const Field2D& value) { + auto xdim = findDimension(group, "x", value.getNx()); + ASSERT0(!xdim.isNull()); + + auto ydim = findDimension(group, "y", value.getNy()); + ASSERT0(!ydim.isNull()); + + return {xdim, ydim}; +} + +template <> +std::vector NcDimVisitor::operator()(const Field3D& value) { + auto xdim = findDimension(group, "x", value.getNx()); + ASSERT0(!xdim.isNull()); + + auto ydim = findDimension(group, "y", value.getNy()); + ASSERT0(!ydim.isNull()); + + auto zdim = findDimension(group, "z", value.getNz()); + ASSERT0(!zdim.isNull()); + + return {xdim, ydim, zdim}; +} + /// Visit a variant type, and put the data into a NcVar struct NcPutVarVisitor { NcPutVarVisitor(NcVar& var) : var(var) {} @@ -127,7 +196,17 @@ void NcPutVarVisitor::operator()(const std::string& value) { const char* cstr = value.c_str(); var.putVar(&cstr); } - +template <> +void NcPutVarVisitor::operator()(const Field2D& value) { + // Pointer to data. Assumed to be contiguous array + var.putVar(&value(0,0)); +} +template <> +void NcPutVarVisitor::operator()(const Field3D& value) { + // Pointer to data. Assumed to be contiguous array + var.putVar(&value(0,0,0)); +} + void writeGroup(const Options& options, NcGroup group) { for (const auto& childpair : options.getChildren()) { @@ -141,8 +220,10 @@ void writeGroup(const Options& options, NcGroup group) { continue; // Skip this value } - auto var = group.addVar(name, nctype); - + auto dims = bout::utils::visit(NcDimVisitor(group), child.value); + + auto var = group.addVar(name, nctype, dims); + // Put the data into the variable bout::utils::visit(NcPutVarVisitor(var), child.value); } @@ -152,8 +233,9 @@ void writeGroup(const Options& options, NcGroup group) { } } } - + } // namespace + /// Write options to file void OptionsNetCDF::write(const Options& options) { NcFile dataFile(filename, NcFile::replace); diff --git a/tests/integrated/test-options-netcdf/data/BOUT.inp b/tests/integrated/test-options-netcdf/data/BOUT.inp index a5692dce34..fa0f6d3681 100644 --- a/tests/integrated/test-options-netcdf/data/BOUT.inp +++ b/tests/integrated/test-options-netcdf/data/BOUT.inp @@ -2,5 +2,5 @@ [mesh] nx = 5 -ny = 5 - +ny = 2 +nz = 2 diff --git a/tests/integrated/test-options-netcdf/runtest b/tests/integrated/test-options-netcdf/runtest index 760d229f3c..e8a2a2328f 100755 --- a/tests/integrated/test-options-netcdf/runtest +++ b/tests/integrated/test-options-netcdf/runtest @@ -8,6 +8,7 @@ from boututils.run_wrapper import shell from boutdata.data import BoutOptionsFile import math +import numpy as np shell("make") shell("rm -f test-out.ini") @@ -46,6 +47,14 @@ print("Checking saved settings.ini") settings = BoutOptionsFile("settings.ini") assert settings["mesh"]["nx"] == 5 -assert settings["mesh"]["ny"] == 5 - +assert settings["mesh"]["ny"] == 2 + +print("Checking saved settings.nc") + +with DataFile("settings.nc") as f: + assert f["f2d"].shape == (5,6) # Field2D + assert f["f3d"].shape == (5,6,2) # Field3D + assert np.allclose(f["f2d"], 1.0) + assert np.allclose(f["f3d"], 2.0) + print(" => Passed") diff --git a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx index 82c5c09e98..2b6a017406 100644 --- a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx +++ b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx @@ -22,6 +22,9 @@ int main(int argc, char** argv) { OptionsNetCDF("test-out.nc").write(values); /////////////////////////// + + Options::root()["f2d"] = Field2D(1.0); + Options::root()["f3d"] = Field3D(2.0); // Write the BOUT.inp settings to NetCDF file OptionsNetCDF("settings.nc").write(Options::root()); From c85628fbcf3fd3698a890b834674a973942b9468 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 14 Dec 2018 10:09:28 +0000 Subject: [PATCH 0471/1783] Remove const from bool return Compiler ( gcc (GCC) 8.2.1 20180831 ) warns: `type qualifiers ignored on function return type` --- include/bout/mesh.hxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 191c4bac40..326c2f2fa3 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -741,9 +741,9 @@ class Mesh { const Region &getRegionPerp(const std::string ®ion_name) const; /// Indicate if named region has already been defined - const bool hasRegion3D(const std::string& region_name) const; - const bool hasRegion2D(const std::string& region_name) const; - const bool hasRegionPerp(const std::string& region_name) const; + bool hasRegion3D(const std::string& region_name) const; + bool hasRegion2D(const std::string& region_name) const; + bool hasRegionPerp(const std::string& region_name) const; /// Add a new region to the region_map for the data iterator /// From 603cc9dfe4d550ef84c8f3b7ae00187ee8ed1f79 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Dec 2018 10:46:13 +0000 Subject: [PATCH 0472/1783] Move all fft functions into bout::fft with non-namespace shims --- include/fft.hxx | 33 +++++++++++++++++++++++++------- src/invert/fft_fftw.cxx | 42 ++++++++++++++++++++++------------------- 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/include/fft.hxx b/include/fft.hxx index a3e1ff175d..d31ac8b9c9 100644 --- a/include/fft.hxx +++ b/include/fft.hxx @@ -30,6 +30,14 @@ #include "dcomplex.hxx" +template +class Array; + +class Options; + +namespace bout { +namespace fft { + /*! * Returns the fft of a real signal using fftw_forward * @@ -78,13 +86,6 @@ void DST(const BoutReal *in, int length, dcomplex *out); */ void DST_rev(dcomplex *in, int length, BoutReal *out); -template -class Array; - -class Options; - -namespace bout { -namespace fft { /// Should the FFT functions find and use an optimised plan? void fft_init(bool fft_measure); /// Should the FFT functions find and use an optimised plan? @@ -102,4 +103,22 @@ Array irfft(const Array& in); } // namespace fft } // namespace bout +// Legacy non-namespaced versions + +inline void rfft(const BoutReal *in, int length, dcomplex *out) { + return bout::fft::rfft(in, length, out); +} + +inline void irfft(const dcomplex *in, int length, BoutReal *out) { + return bout::fft::irfft(in, length, out); +} + +inline void DST(const BoutReal *in, int length, dcomplex *out) { + return bout::fft::DST(in, length, out); +} + +inline void DST_rev(dcomplex *in, int length, BoutReal *out) { + return bout::fft::DST_rev(in, length, out); +} + #endif // __FFT_H__ diff --git a/src/invert/fft_fftw.cxx b/src/invert/fft_fftw.cxx index b889ef19a5..1a3cb5ea5c 100644 --- a/src/invert/fft_fftw.cxx +++ b/src/invert/fft_fftw.cxx @@ -40,11 +40,14 @@ namespace bout { namespace fft { -bool fft_initialised = false; -bool fft_measure; + +/// Have we set fft_measure? +bool fft_initialised{false}; +/// Should FFTW find an optimised plan by measuring various plans? +bool fft_measure{false}; void fft_init(Options* options) { - if (bout::fft::fft_initialised) { + if (fft_initialised) { return; } if (options == nullptr) { @@ -55,12 +58,9 @@ void fft_init(Options* options) { void fft_init(bool fft_measure) { bout::fft::fft_measure = fft_measure; - bout::fft::fft_initialised = true; + fft_initialised = true; } -} // namespace fft -} // namespace bout - /*********************************************************** * Real FFTs ***********************************************************/ @@ -84,7 +84,7 @@ void rfft(const BoutReal *in, int length, dcomplex *out) { fftw_free(fout); } - bout::fft::fft_init(); + fft_init(); // Initialize the input for the fourier transformation fin = (double*) fftw_malloc(sizeof(double) * length); @@ -96,7 +96,7 @@ void rfft(const BoutReal *in, int length, dcomplex *out) { fout = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * (length/2 + 1)); unsigned int flags = FFTW_ESTIMATE; - if (bout::fft::fft_measure) { + if (fft_measure) { flags = FFTW_MEASURE; } @@ -143,7 +143,7 @@ void irfft(const dcomplex *in, int length, BoutReal *out) { fftw_free(fout); } - bout::fft::fft_init(); + fft_init(); // Initilaize the input for the inverse fourier transformation /* NOTE: Only the non-redundant input is given @@ -155,7 +155,7 @@ void irfft(const dcomplex *in, int length, BoutReal *out) { fout = (double*) fftw_malloc(sizeof(double) * length); unsigned int flags = FFTW_ESTIMATE; - if (bout::fft::fft_measure) { + if (fft_measure) { flags = FFTW_MEASURE; } @@ -216,7 +216,7 @@ void rfft(const BoutReal *in, int length, dcomplex *out) { fftw_free(foutall); } - bout::fft::fft_init(); + fft_init(); finall = static_cast(fftw_malloc(sizeof(double) * length * n_th)); foutall = static_cast( @@ -224,7 +224,7 @@ void rfft(const BoutReal *in, int length, dcomplex *out) { p = new fftw_plan[n_th]; //Never freed unsigned int flags = FFTW_ESTIMATE; - if (bout::fft::fft_measure) { + if (fft_measure) { flags = FFTW_MEASURE; } @@ -287,7 +287,7 @@ void irfft(const dcomplex *in, int length, BoutReal *out) { fftw_free(foutall); } - bout::fft::fft_init(); + fft_init(); finall = static_cast( fftw_malloc(sizeof(fftw_complex) * (length / 2 + 1) * n_th)); @@ -296,7 +296,7 @@ void irfft(const dcomplex *in, int length, BoutReal *out) { p = new fftw_plan[n_th]; // Never freed unsigned int flags = FFTW_ESTIMATE; - if (bout::fft::fft_measure) { + if (fft_measure) { flags = FFTW_MEASURE; } @@ -351,7 +351,7 @@ void DST(const BoutReal *in, int length, dcomplex *out) { fout = static_cast(fftw_malloc(sizeof(fftw_complex) * 2 * length)); unsigned int flags = FFTW_ESTIMATE; - if (bout::fft::fft_measure) { + if (fft_measure) { flags = FFTW_MEASURE; } @@ -406,7 +406,7 @@ void DST_rev(dcomplex *in, int length, BoutReal *out) { fout = static_cast(fftw_malloc(sizeof(double) * 2 * (length - 1))); unsigned int flags = FFTW_ESTIMATE; - if (bout::fft::fft_measure) { + if (fft_measure) { flags = FFTW_MEASURE; } @@ -437,7 +437,7 @@ void DST_rev(dcomplex *in, int length, BoutReal *out) { out[i] = fout[i]; } -Array bout::fft::rfft(const Array& in) { +Array rfft(const Array& in) { ASSERT1(!in.empty()); int size{in.size()}; @@ -447,7 +447,7 @@ Array bout::fft::rfft(const Array& in) { return out; } -Array bout::fft::irfft(const Array& in) { +Array irfft(const Array& in) { ASSERT1(!in.empty()); int size{in.size()}; @@ -456,3 +456,7 @@ Array bout::fft::irfft(const Array& in) { ::irfft(in.begin(), size, out.begin()); return out; } + +} // namespace fft +} // namespace bout + From 58445034b877ece1ff35fb26ac48eb89743796e7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Dec 2018 11:00:15 +0000 Subject: [PATCH 0473/1783] Invert preprocessor conditionals for BOUT_HAS_FFTW Also mark arguments as maybe_unused --- src/invert/fft_fftw.cxx | 49 +++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/src/invert/fft_fftw.cxx b/src/invert/fft_fftw.cxx index 85143e239c..b82638b124 100644 --- a/src/invert/fft_fftw.cxx +++ b/src/invert/fft_fftw.cxx @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef BOUT_HAS_FFTW #include @@ -72,8 +73,10 @@ void fft_init(bool fft_measure) { #ifndef _OPENMP // Serial code -void rfft(const BoutReal *in, int length, dcomplex *out) { -#ifdef BOUT_HAS_FFTW +void rfft(MAYBE_UNUSED(const BoutReal *in), MAYBE_UNUSED(int length), MAYBE_UNUSED(dcomplex *out)) { +#ifndef BOUT_HAS_FFTW + throw BoutException("This instance of BOUT++ has been compiled without fftw support."); +#else // static variables initialized once static double *fin; static fftw_complex *fout; @@ -130,13 +133,13 @@ void rfft(const BoutReal *in, int length, dcomplex *out) { // Store the output in out, and normalize for(int i=0;i(length) - 1); // Normalise -#else - throw BoutException("This instance of BOUT++ has been compiled without fftw support."); #endif } -void DST_rev(dcomplex *in, int length, BoutReal *out) { -#ifdef BOUT_HAS_FFTW +void DST_rev(MAYBE_UNUSED(dcomplex *in), MAYBE_UNUSED(int length), MAYBE_UNUSED(BoutReal *out)) { +#ifndef BOUT_HAS_FFTW + throw BoutException("This instance of BOUT++ has been compiled without fftw support."); +#else static fftw_complex *fin; static double *fout; static fftw_plan p; @@ -461,8 +464,6 @@ void DST_rev(dcomplex *in, int length, BoutReal *out) { out[length-1]=0.0; for(int i=1;i Date: Fri, 14 Dec 2018 11:19:18 +0000 Subject: [PATCH 0474/1783] Also remove const from .cxx file Forgot to remove from implementation of `Mesh::getRegion*` --- src/mesh/mesh.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index dc45ba8091..f645b89f0c 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -359,15 +359,15 @@ const Region &Mesh::getRegionPerp(const std::string ®ion_name) const return found->second; } -const bool Mesh::hasRegion3D(const std::string& region_name) const { +bool Mesh::hasRegion3D(const std::string& region_name) const { return regionMap3D.find(region_name) != std::end(regionMap3D); } -const bool Mesh::hasRegion2D(const std::string& region_name) const { +bool Mesh::hasRegion2D(const std::string& region_name) const { return regionMap2D.find(region_name) != std::end(regionMap2D); } -const bool Mesh::hasRegionPerp(const std::string& region_name) const { +bool Mesh::hasRegionPerp(const std::string& region_name) const { return regionMapPerp.find(region_name) != std::end(regionMapPerp); } From 470209e0a1d42be953aefc7b51a9ce1b04dea5e0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 14 Dec 2018 11:47:42 +0000 Subject: [PATCH 0475/1783] Implement FieldPerp location in Laplacian inversion classes --- src/invert/laplace/impls/cyclic/cyclic_laplace.cxx | 2 ++ src/invert/laplace/impls/multigrid/multigrid_laplace.cxx | 3 +++ src/invert/laplace/impls/multigrid/multigrid_laplace.hxx | 1 + src/invert/laplace/impls/mumps/mumps_laplace.cxx | 1 + src/invert/laplace/impls/pdd/pdd.cxx | 5 +++++ src/invert/laplace/impls/petsc/petsc_laplace.cxx | 2 ++ src/invert/laplace/impls/serial_band/serial_band.cxx | 3 +++ src/invert/laplace/impls/serial_tri/serial_tri.cxx | 3 +++ src/invert/laplace/impls/shoot/shoot_laplace.cxx | 2 ++ src/invert/laplace/impls/spt/spt.cxx | 8 ++++++++ src/invert/laplace/invert_laplace.cxx | 7 +++++++ 11 files changed, 37 insertions(+) diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index ff31e5a77b..af950b7cbe 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -91,6 +91,8 @@ LaplaceCyclic::~LaplaceCyclic() { const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) { ASSERT1(localmesh == rhs.getMesh() && localmesh == x0.getMesh()); + ASSERT1(rhs.getLocation() == location); + ASSERT1(x0.getLocation() == location); FieldPerp x(localmesh); // Result x.allocate(); diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index bb06c2b469..1ff40e9b0b 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -202,6 +202,8 @@ const FieldPerp LaplaceMultigrid::solve(const FieldPerp &b_in, const FieldPerp & TRACE("LaplaceMultigrid::solve(const FieldPerp, const FieldPerp)"); ASSERT1(localmesh == b_in.getMesh() && localmesh == x0.getMesh()); + ASSERT1(b_in.getLocation() == location); + ASSERT1(x0.getLocation() == location); checkData(b_in); checkData(x0); @@ -423,6 +425,7 @@ BOUT_OMP(for) } FieldPerp result(localmesh); + result.setLocation(location); result.allocate(); result.setIndex(yindex); diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx index 00eaf96a6b..0067e1bb51 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx @@ -196,6 +196,7 @@ public: FieldPerp zero(localmesh); zero = 0.; + zero.setLocation(location); zero.setIndex(b.getIndex()); return solve(b, zero); } diff --git a/src/invert/laplace/impls/mumps/mumps_laplace.cxx b/src/invert/laplace/impls/mumps/mumps_laplace.cxx index dd30e4b15e..fa12c9844f 100644 --- a/src/invert/laplace/impls/mumps/mumps_laplace.cxx +++ b/src/invert/laplace/impls/mumps/mumps_laplace.cxx @@ -564,6 +564,7 @@ const FieldPerp LaplaceMumps::solve(const FieldPerp &b, const FieldPerp &x0) { const FieldPerp LaplaceMumps::solve(const FieldPerp &b) { ASSERT1(localmesh == b.getMesh()); + ASSERT1(b.getLocation() == location); int y = b.getIndex(); sol = 0.; diff --git a/src/invert/laplace/impls/pdd/pdd.cxx b/src/invert/laplace/impls/pdd/pdd.cxx index 23c09145c7..dc792e18cf 100644 --- a/src/invert/laplace/impls/pdd/pdd.cxx +++ b/src/invert/laplace/impls/pdd/pdd.cxx @@ -40,6 +40,7 @@ const FieldPerp LaplacePDD::solve(const FieldPerp &b) { ASSERT1(localmesh == b.getMesh()); + ASSERT1(b.getLocation() == location); PDD_data data; @@ -55,6 +56,7 @@ const FieldPerp LaplacePDD::solve(const FieldPerp &b) { const Field3D LaplacePDD::solve(const Field3D &b) { ASSERT1(localmesh == b.getMesh()); + ASSERT1(b.getLocation() == location); Field3D x(localmesh); x.allocate(); @@ -114,6 +116,7 @@ const Field3D LaplacePDD::solve(const Field3D &b) { /// @param[in] data Internal data used for multiple calls in parallel mode void LaplacePDD::start(const FieldPerp &b, PDD_data &data) { ASSERT1(localmesh == b.getMesh()); + ASSERT1(b.getLocation() == location); int ix, kz; @@ -302,6 +305,8 @@ void LaplacePDD::next(PDD_data &data) { /// Last part of the PDD algorithm void LaplacePDD::finish(PDD_data &data, FieldPerp &x) { + ASSERT1(x.getLocation() == location); + int ix, kz; x.allocate(); diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.cxx b/src/invert/laplace/impls/petsc/petsc_laplace.cxx index cafa8bb2d5..c986b25910 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.cxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.cxx @@ -346,6 +346,8 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { TRACE("LaplacePetsc::solve"); ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); + ASSERT1(b.getLocation() == location); + ASSERT1(x0.getLocation() == location); #if CHECK > 0 // Checking flags are set to something which is not implemented (see diff --git a/src/invert/laplace/impls/serial_band/serial_band.cxx b/src/invert/laplace/impls/serial_band/serial_band.cxx index 46835d8174..f773f90996 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.cxx +++ b/src/invert/laplace/impls/serial_band/serial_band.cxx @@ -81,8 +81,11 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b) { const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0) { ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); + ASSERT1(b.getLocation() == location); + ASSERT1(x0.getLocation() == location); FieldPerp x(localmesh); + x.setLocation(location); x.allocate(); int jy = b.getIndex(); diff --git a/src/invert/laplace/impls/serial_tri/serial_tri.cxx b/src/invert/laplace/impls/serial_tri/serial_tri.cxx index fc4c226ac7..f2d98e3f22 100644 --- a/src/invert/laplace/impls/serial_tri/serial_tri.cxx +++ b/src/invert/laplace/impls/serial_tri/serial_tri.cxx @@ -74,8 +74,11 @@ const FieldPerp LaplaceSerialTri::solve(const FieldPerp &b) { */ const FieldPerp LaplaceSerialTri::solve(const FieldPerp &b, const FieldPerp &x0) { ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); + ASSERT1(b.getLocation() == location); + ASSERT1(x0.getLocation() == location); FieldPerp x(localmesh); + x.setLocation(location); x.allocate(); int jy = b.getIndex(); diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.cxx b/src/invert/laplace/impls/shoot/shoot_laplace.cxx index 3b515e6ed7..405fef96be 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.cxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.cxx @@ -70,8 +70,10 @@ LaplaceShoot::LaplaceShoot(Options *opt, const CELL_LOC loc, Mesh *mesh_in) const FieldPerp LaplaceShoot::solve(const FieldPerp &rhs) { ASSERT1(localmesh = rhs.getMesh()); + ASSERT1(rhs.getLocation() == location); FieldPerp x(localmesh); // Result + x.setLocation(location); x.allocate(); int jy = rhs.getIndex(); // Get the Y index diff --git a/src/invert/laplace/impls/spt/spt.cxx b/src/invert/laplace/impls/spt/spt.cxx index 42b1f30935..705f198c29 100644 --- a/src/invert/laplace/impls/spt/spt.cxx +++ b/src/invert/laplace/impls/spt/spt.cxx @@ -81,8 +81,11 @@ const FieldPerp LaplaceSPT::solve(const FieldPerp &b) { const FieldPerp LaplaceSPT::solve(const FieldPerp &b, const FieldPerp &x0) { ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); + ASSERT1(b.getLocation() == location); + ASSERT1(x0.getLocation() == location); FieldPerp x(localmesh); + x.setLocation(location); x.allocate(); if( (inner_boundary_flags & INVERT_SET) || (outer_boundary_flags & INVERT_SET) ) { @@ -144,6 +147,7 @@ const Field3D LaplaceSPT::solve(const Field3D &b) { }while(running); FieldPerp xperp(localmesh); + xperp.setLocation(location); xperp.allocate(); // All calculations finished. Get result @@ -276,6 +280,8 @@ int LaplaceSPT::start(const FieldPerp &b, SPT_data &data) { if(localmesh->firstX() && localmesh->lastX()) throw BoutException("Error: SPT method only works for localmesh->NXPE > 1\n"); + ASSERT1(b.getLocation() == location); + data.jy = b.getIndex(); int mm = localmesh->LocalNz/2 + 1; @@ -460,6 +466,8 @@ void LaplaceSPT::finish(SPT_data &data, FieldPerp &x) { int ncx = localmesh->LocalNx-1; int ncz = localmesh->LocalNz; + ASSERT1(x.getLocation() == location); + x.allocate(); x.setIndex(data.jy); diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index e120f86244..c106a7a52e 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -745,6 +745,13 @@ void laplace_tridag_coefs(int jx, int jy, int jz, dcomplex &a, dcomplex &b, dcom int invert_laplace(const FieldPerp &b, FieldPerp &x, int flags, const Field2D *a, const Field2D *c, const Field2D *d) { + // Laplacian::defaultInstance is at CELL_CENTRE + ASSERT1(b.getLocation() == CELL_CENTRE); + ASSERT1(x.getLocation() == CELL_CENTRE); + ASSERT1(a->getLocation() == CELL_CENTRE); + ASSERT1(c->getLocation() == CELL_CENTRE); + ASSERT1(d->getLocation() == CELL_CENTRE); + Laplacian *lap = Laplacian::defaultInstance(); if (a != nullptr) { From 4f13ada0a609cec272df99dc6ab32c01ce83a8bb Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 14 Dec 2018 12:03:09 +0000 Subject: [PATCH 0476/1783] Add unit tests for bout::utils::variant functions Three functions which internally use a visitor pattern to extract values from variant types. --- tests/unit/sys/test_variant.cxx | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/unit/sys/test_variant.cxx diff --git a/tests/unit/sys/test_variant.cxx b/tests/unit/sys/test_variant.cxx new file mode 100644 index 0000000000..12df5a36ad --- /dev/null +++ b/tests/unit/sys/test_variant.cxx @@ -0,0 +1,53 @@ +#include "gtest/gtest.h" + +#include "bout/sys/variant.hxx" + +#include +#include + +// Check that we can compare values which can and can't be stored in the variant +TEST(VariantTest, IsEqualTest) { + bout::utils::variant var; + + var = true; + + EXPECT_TRUE(bout::utils::variantEqualTo(var, true)); + EXPECT_FALSE(bout::utils::variantEqualTo(var, false)); + EXPECT_FALSE(bout::utils::variantEqualTo(var, 2)); + EXPECT_FALSE(bout::utils::variantEqualTo(var, "test")); + + var = 2; + + EXPECT_FALSE(bout::utils::variantEqualTo(var, true)); + EXPECT_FALSE(bout::utils::variantEqualTo(var, false)); + EXPECT_TRUE(bout::utils::variantEqualTo(var, 2)); + EXPECT_FALSE(bout::utils::variantEqualTo(var, 3)); + EXPECT_FALSE(bout::utils::variantEqualTo(var, "test")); +} + +// Check casting to allowed types +TEST(VariantTest, StaticCastTest) { + using VarType = bout::utils::variant; + VarType var; + + var = 3; + + // Note: Extra brackets needed to avoid passing macro 3 arguments + EXPECT_EQ((bout::utils::variantStaticCastOrThrow(var)), 3); + EXPECT_DOUBLE_EQ((bout::utils::variantStaticCastOrThrow(var)), 3.0); + EXPECT_THROW((bout::utils::variantStaticCastOrThrow(var)), + std::bad_cast); +} + +// Check conversion of variant to std::string +TEST(VariantTest, ToStringTest) { + bout::utils::variant var; + + var = 42; + + EXPECT_EQ(bout::utils::variantToString(var), "42"); + + var = true; + + EXPECT_EQ(bout::utils::variantToString(var), "true"); +} From 99f96c5ec57d8d50cf43d544506ca79311cd16ad Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 14 Dec 2018 12:15:09 +0000 Subject: [PATCH 0477/1783] Deprecate invert_laplace() free functions --- include/invert_laplace.hxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index 17d1e48507..bab11d7ec6 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -244,14 +244,14 @@ void laplace_tridag_coefs(int jx, int jy, int jz, dcomplex &a, dcomplex &b, dcom const Field2D *ccoef = nullptr, const Field2D *d = nullptr, CELL_LOC loc = CELL_DEFAULT); -int invert_laplace(const FieldPerp &b, FieldPerp &x, int flags, const Field2D *a, - const Field2D *c = nullptr, const Field2D *d = nullptr); -int invert_laplace(const Field3D &b, Field3D &x, int flags, const Field2D *a, - const Field2D *c = nullptr, const Field2D *d = nullptr); +DEPRECATED(int invert_laplace(const FieldPerp &b, FieldPerp &x, int flags, const Field2D *a, + const Field2D *c = nullptr, const Field2D *d = nullptr)); +DEPRECATED(int invert_laplace(const Field3D &b, Field3D &x, int flags, const Field2D *a, + const Field2D *c = nullptr, const Field2D *d = nullptr)); /// More readable API for calling Laplacian inversion. Returns x -const Field3D invert_laplace(const Field3D &b, int flags, const Field2D *a = nullptr, - const Field2D *c = nullptr, const Field2D *d = nullptr); +DEPRECATED(const Field3D invert_laplace(const Field3D &b, int flags, const Field2D *a = nullptr, + const Field2D *c = nullptr, const Field2D *d = nullptr)); #endif // __LAPLACE_H__ From ff56bf90e373aec4af40f0617b5b188b1ba33297 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Dec 2018 12:16:09 +0000 Subject: [PATCH 0478/1783] Add round-trip fft test --- tests/unit/invert/test_fft.cxx | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/unit/invert/test_fft.cxx b/tests/unit/invert/test_fft.cxx index ff974de3f9..0ea15a3607 100644 --- a/tests/unit/invert/test_fft.cxx +++ b/tests/unit/invert/test_fft.cxx @@ -147,3 +147,31 @@ TEST(FFTTest, irfftWithArray) { EXPECT_NEAR(output[i], expected[i], BoutRealTolerance); } } + +TEST(FFTTest, RoundTrip) { + // Checks normalisation is == 1 + + // Make sure fft functions are quiet by setting fft_measure to false + bout::fft::fft_init(false); + + constexpr int size{8}; + + // Make grid indices from [0, size - 1] + Array indices{size}; + std::iota(indices.begin(), indices.end(), 0.0); + + // Calculate sin(x) + cos(2x) on [0, 2pi] + Array input{size}; + std::transform(indices.begin(), indices.end(), input.begin(), + [](BoutReal i) -> BoutReal { + return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); + }); + + Array output{bout::fft::irfft(bout::fft::rfft(input))}; + + EXPECT_EQ(output.size(), input.size()); + + for (int i = 0; i < size; ++i) { + EXPECT_NEAR(output[i], input[i], BoutRealTolerance); + } +} From 6f1cdeaa1f0f2430b2081436dcd017b6deb0eb98 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Dec 2018 12:16:22 +0000 Subject: [PATCH 0479/1783] Be more explicit about sizes of rfft/irfft Arrays --- src/invert/fft_fftw.cxx | 8 ++-- tests/unit/invert/test_fft.cxx | 80 ++++++++++++++++++++-------------- 2 files changed, 52 insertions(+), 36 deletions(-) diff --git a/src/invert/fft_fftw.cxx b/src/invert/fft_fftw.cxx index b82638b124..b0af7a6413 100644 --- a/src/invert/fft_fftw.cxx +++ b/src/invert/fft_fftw.cxx @@ -471,19 +471,19 @@ Array rfft(const Array& in) { ASSERT1(!in.empty()); int size{in.size()}; - Array out{size}; + Array out{(size / 2) + 1}; - ::rfft(in.begin(), size, out.begin()); + rfft(in.begin(), size, out.begin()); return out; } Array irfft(const Array& in) { ASSERT1(!in.empty()); - int size{in.size()}; + int size{(in.size() - 1) * 2}; Array out{size}; - ::irfft(in.begin(), size, out.begin()); + irfft(in.begin(), size, out.begin()); return out; } diff --git a/tests/unit/invert/test_fft.cxx b/tests/unit/invert/test_fft.cxx index 0ea15a3607..c7be814818 100644 --- a/tests/unit/invert/test_fft.cxx +++ b/tests/unit/invert/test_fft.cxx @@ -1,10 +1,10 @@ #include "gtest/gtest.h" -#include "bout/array.hxx" -#include "bout/constants.hxx" #include "dcomplex.hxx" #include "fft.hxx" #include "test_extras.hxx" +#include "bout/array.hxx" +#include "bout/constants.hxx" #include #include @@ -16,33 +16,37 @@ TEST(FFTTest, rfft) { bout::fft::fft_init(false); constexpr int size{8}; + constexpr int nmodes{(size / 2) + 1}; - // Calculate sin(x) + cos(2x) on [0, 2pi] - Array indices(size); - std::iota(indices.begin(), indices.end(), 0); + // Make grid indices from [0, size - 1] + Array indices{size}; + std::iota(indices.begin(), indices.end(), 0.0); - Array input(size); + // Calculate sin(x) + cos(2x) on [0, 2pi] + Array input{size}; std::transform(indices.begin(), indices.end(), input.begin(), [](BoutReal i) -> BoutReal { return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); }); - Array output(size); + Array output{nmodes}; // Compute forward real FFT rfft(input.begin(), size, output.begin()); // Real part should have exactly one frequency - Array expected_real(size); + Array expected_real{nmodes}; std::fill(expected_real.begin(), expected_real.end(), 0.); expected_real[2] = 0.5; // Imaginary part should have exactly one frequency - Array expected_imag(size); + Array expected_imag{nmodes}; std::fill(expected_imag.begin(), expected_imag.end(), 0.); expected_imag[1] = -0.5; - for (int i = 0; i < size; ++i) { + EXPECT_EQ(output.size(), nmodes); + + for (int i = 0; i < nmodes; ++i) { EXPECT_NEAR(real(output[i]), expected_real[i], BoutRealTolerance); EXPECT_NEAR(imag(output[i]), expected_imag[i], BoutRealTolerance); } @@ -53,29 +57,33 @@ TEST(FFTTest, irfft) { // Make sure fft functions are quiet by setting fft_measure to false bout::fft::fft_init(false); - constexpr int size{8}; + constexpr int nmodes{5}; + constexpr int size{(nmodes - 1) * 2}; // Make a spectrum with two frequencies - Array input(size); + Array input{nmodes}; std::fill(input.begin(), input.end(), dcomplex{0., 0.}); input[1] = dcomplex{0., -0.5}; input[2] = dcomplex{0.5, 0.}; - Array output(size); + Array output{size}; // Compute inverse real FFT irfft(input.begin(), size, output.begin()); - // Calculate sin(x) + cos(2x) on [0, 2pi] - Array indices(size); - std::iota(indices.begin(), indices.end(), 0); + // Make grid indices from [0, size - 1] + Array indices{size}; + std::iota(indices.begin(), indices.end(), 0.0); - Array expected(size); + // Calculate sin(x) + cos(2x) on [0, 2pi] + Array expected{size}; std::transform(indices.begin(), indices.end(), expected.begin(), [](BoutReal i) -> BoutReal { return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); }); + EXPECT_EQ(output.size(), size); + for (int i = 0; i < size; ++i) { EXPECT_NEAR(output[i], expected[i], BoutRealTolerance); } @@ -87,31 +95,35 @@ TEST(FFTTest, rfftWithArray) { bout::fft::fft_init(false); constexpr int size{8}; + constexpr int nmodes{(size / 2) + 1}; - // Calculate sin(x) + cos(2x) on [0, 2pi] - Array indices(size); - std::iota(indices.begin(), indices.end(), 0); + // Make grid indices from [0, size - 1] + Array indices{size}; + std::iota(indices.begin(), indices.end(), 0.0); - Array input(size); + // Calculate sin(x) + cos(2x) on [0, 2pi] + Array input{size}; std::transform(indices.begin(), indices.end(), input.begin(), [](BoutReal i) -> BoutReal { return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); }); // Compute forward real FFT - auto output = bout::fft::rfft(input); + Array output = bout::fft::rfft(input); // Real part should have exactly one frequency - Array expected_real(size); + Array expected_real{nmodes}; std::fill(expected_real.begin(), expected_real.end(), 0.); expected_real[2] = 0.5; // Imaginary part should have exactly one frequency - Array expected_imag(size); + Array expected_imag{nmodes}; std::fill(expected_imag.begin(), expected_imag.end(), 0.); expected_imag[1] = -0.5; - for (int i = 0; i < size; ++i) { + EXPECT_EQ(output.size(), nmodes); + + for (int i = 0; i < nmodes; ++i) { EXPECT_NEAR(real(output[i]), expected_real[i], BoutRealTolerance); EXPECT_NEAR(imag(output[i]), expected_imag[i], BoutRealTolerance); } @@ -122,27 +134,31 @@ TEST(FFTTest, irfftWithArray) { // Make sure fft functions are quiet by setting fft_measure to false bout::fft::fft_init(false); - constexpr int size{8}; + constexpr int nmodes{5}; + constexpr int size{(nmodes - 1) * 2}; // Make a spectrum with two frequencies - Array input(size); + Array input{nmodes}; std::fill(input.begin(), input.end(), dcomplex{0., 0.}); input[1] = dcomplex{0., -0.5}; input[2] = dcomplex{0.5, 0.}; // Compute inverse real FFT - auto output = bout::fft::irfft(input); + Array output = bout::fft::irfft(input); - // Calculate sin(x) + cos(2x) on [0, 2pi] - Array indices(size); - std::iota(indices.begin(), indices.end(), 0); + // Make grid indices from [0, size - 1] + Array indices{size}; + std::iota(indices.begin(), indices.end(), 0.0); - Array expected(size); + // Calculate sin(x) + cos(2x) on [0, 2pi] + Array expected{size}; std::transform(indices.begin(), indices.end(), expected.begin(), [](BoutReal i) -> BoutReal { return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); }); + EXPECT_EQ(output.size(), size); + for (int i = 0; i < size; ++i) { EXPECT_NEAR(output[i], expected[i], BoutRealTolerance); } From 5197d8f152cfded2130c98bb49909d1d07435496 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Dec 2018 12:41:58 +0000 Subject: [PATCH 0480/1783] Enable output_verbose (with '-v') before output_debug (with '-v -v') --- src/bout++.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 76aede060c..6e4ef0b5cd 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -343,8 +343,8 @@ int BoutInitialise(int &argc, char **&argv) { output_warn.enable(verbosity > 1); output_progress.enable(verbosity > 2); output_info.enable(verbosity > 3); - output_debug.enable(verbosity > 4); // Only actually enabled if also compiled with DEBUG - output_verbose.enable(verbosity > 5); + output_verbose.enable(verbosity > 4); + output_debug.enable(verbosity > 5); // Only actually enabled if also compiled with DEBUG // The backward-compatible output object same as output_progress output.enable(verbosity>2); From 5c6c0a008bdb1eced4f25d7e94a13cd42a758d90 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 14 Dec 2018 12:44:45 +0000 Subject: [PATCH 0481/1783] Replace nested loops in shiftedmetric.cxx with BOUT_FOR --- src/mesh/parallel/shiftedmetric.cxx | 46 ++++++++++++----------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 32ca2b84ec..e50c7531af 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -73,28 +73,24 @@ ShiftedMetric::ShiftedMetric(Mesh &m) : mesh(m), zShift(&m) { } //To/From field aligned phases - for(int jx=0;jx Date: Fri, 14 Dec 2018 13:59:18 +0000 Subject: [PATCH 0482/1783] Make most examples compilable test-difops and non_local still won't compile Also adds .gitignore files for most examples to ignore the generated example executable --- examples/2Dturbulence_multigrid/.gitignore | 1 + examples/6field-simple/.gitignore | 1 + examples/IMEX/advection-diffusion/.gitignore | 1 + examples/IMEX/advection-reaction/.gitignore | 1 + examples/IMEX/diffusion-nl/.gitignore | 1 + examples/IMEX/drift-wave-constraint/.gitignore | 1 + .../IMEX/drift-wave-constraint/test-drift.cxx | 2 +- examples/IMEX/drift-wave/.gitignore | 1 + examples/advdiff/.gitignore | 1 + examples/advdiff2/.gitignore | 1 + examples/backtrace/.gitignore | 1 + examples/blob2d-laplacexz/.gitignore | 1 + examples/blob2d/.gitignore | 1 + .../boundary-conditions/advection/.gitignore | 1 + examples/conducting-wall-mode/.gitignore | 1 + examples/conducting-wall-mode/cwm.cxx | 2 +- examples/conduction/.gitignore | 1 + examples/constraints/alfven-wave/.gitignore | 1 + examples/constraints/alfven-wave/alfven.cxx | 4 ++-- examples/constraints/laplace-dae/.gitignore | 1 + examples/dalf3/.gitignore | 1 + examples/dalf3/dalf3.cxx | 2 +- examples/dalf3/doc/.gitignore | 1 + examples/eigen-box/.gitignore | 1 + examples/elm-pb/.gitignore | 1 + examples/elm-pb/doc/.gitignore | 1 + examples/em-drift/.gitignore | 1 + examples/em-drift/2fluid.cxx | 2 +- examples/fci-wave-logn/.gitignore | 1 + examples/fci-wave/.gitignore | 1 + examples/finite-volume/diffusion/.gitignore | 1 + examples/finite-volume/fluid/.gitignore | 1 + examples/finite-volume/test/.gitignore | 1 + examples/gravity_reduced/.gitignore | 1 + examples/gyro-gem/.gitignore | 1 + examples/gyro-gem/doc/.gitignore | 1 + examples/hasegawa-wakatani/.gitignore | 1 + examples/jorek-compare/doc/.gitignore | 1 + examples/jorek-compare/jorek_compare.cxx | 2 +- examples/lapd-drift/lapd_drift.cxx | 2 +- examples/laplacexy/alfven-wave/.gitignore | 1 + examples/laplacexy/laplace_perp/.gitignore | 1 + examples/laplacexy/simple/.gitignore | 1 + examples/monitor-newapi/.gitignore | 1 + examples/monitor/.gitignore | 1 + examples/non-local_1d/cubic_spline_local.hxx | 4 ++++ examples/performance/arithmetic/.gitignore | 1 + .../performance/arithmetic_3d2d/.gitignore | 1 + examples/performance/bracket/.gitignore | 1 + examples/performance/ddx/.gitignore | 1 + examples/performance/ddy/.gitignore | 1 + examples/performance/ddz/.gitignore | 1 + examples/performance/difops/test-difops.cxx | 18 +++++++++--------- .../performance/iterator-offsets/.gitignore | 1 + .../tuning_regionblocksize/.gitignore | 1 + examples/preconditioning/wave/.gitignore | 1 + examples/reconnect-2field/.gitignore | 1 + examples/shear-alfven-wave/.gitignore | 1 + examples/shear-alfven-wave/2fluid.cxx | 2 +- examples/staggered_grid/.gitignore | 1 + examples/tokamak-2fluid/.gitignore | 1 + examples/tokamak-2fluid/2fluid.cxx | 2 +- examples/wave-slab/.gitignore | 1 + 63 files changed, 75 insertions(+), 19 deletions(-) create mode 100644 examples/2Dturbulence_multigrid/.gitignore create mode 100644 examples/6field-simple/.gitignore create mode 100644 examples/IMEX/advection-diffusion/.gitignore create mode 100644 examples/IMEX/advection-reaction/.gitignore create mode 100644 examples/IMEX/diffusion-nl/.gitignore create mode 100644 examples/IMEX/drift-wave-constraint/.gitignore create mode 100644 examples/IMEX/drift-wave/.gitignore create mode 100644 examples/advdiff/.gitignore create mode 100644 examples/advdiff2/.gitignore create mode 100644 examples/backtrace/.gitignore create mode 100644 examples/blob2d-laplacexz/.gitignore create mode 100644 examples/blob2d/.gitignore create mode 100644 examples/boundary-conditions/advection/.gitignore create mode 100644 examples/conducting-wall-mode/.gitignore create mode 100644 examples/conduction/.gitignore create mode 100644 examples/constraints/alfven-wave/.gitignore create mode 100644 examples/constraints/laplace-dae/.gitignore create mode 100644 examples/dalf3/.gitignore create mode 100644 examples/dalf3/doc/.gitignore create mode 100644 examples/eigen-box/.gitignore create mode 100644 examples/elm-pb/.gitignore create mode 100644 examples/elm-pb/doc/.gitignore create mode 100644 examples/em-drift/.gitignore create mode 100644 examples/fci-wave-logn/.gitignore create mode 100644 examples/fci-wave/.gitignore create mode 100644 examples/finite-volume/diffusion/.gitignore create mode 100644 examples/finite-volume/fluid/.gitignore create mode 100644 examples/finite-volume/test/.gitignore create mode 100644 examples/gravity_reduced/.gitignore create mode 100644 examples/gyro-gem/.gitignore create mode 100644 examples/gyro-gem/doc/.gitignore create mode 100644 examples/hasegawa-wakatani/.gitignore create mode 100644 examples/jorek-compare/doc/.gitignore create mode 100644 examples/laplacexy/alfven-wave/.gitignore create mode 100644 examples/laplacexy/laplace_perp/.gitignore create mode 100644 examples/laplacexy/simple/.gitignore create mode 100644 examples/monitor-newapi/.gitignore create mode 100644 examples/monitor/.gitignore create mode 100644 examples/performance/arithmetic/.gitignore create mode 100644 examples/performance/arithmetic_3d2d/.gitignore create mode 100644 examples/performance/bracket/.gitignore create mode 100644 examples/performance/ddx/.gitignore create mode 100644 examples/performance/ddy/.gitignore create mode 100644 examples/performance/ddz/.gitignore create mode 100644 examples/performance/iterator-offsets/.gitignore create mode 100644 examples/performance/tuning_regionblocksize/.gitignore create mode 100644 examples/preconditioning/wave/.gitignore create mode 100644 examples/reconnect-2field/.gitignore create mode 100644 examples/shear-alfven-wave/.gitignore create mode 100644 examples/staggered_grid/.gitignore create mode 100644 examples/tokamak-2fluid/.gitignore create mode 100644 examples/wave-slab/.gitignore diff --git a/examples/2Dturbulence_multigrid/.gitignore b/examples/2Dturbulence_multigrid/.gitignore new file mode 100644 index 0000000000..26b1c65f51 --- /dev/null +++ b/examples/2Dturbulence_multigrid/.gitignore @@ -0,0 +1 @@ +esel \ No newline at end of file diff --git a/examples/6field-simple/.gitignore b/examples/6field-simple/.gitignore new file mode 100644 index 0000000000..49045c5bf5 --- /dev/null +++ b/examples/6field-simple/.gitignore @@ -0,0 +1 @@ +elm_6f \ No newline at end of file diff --git a/examples/IMEX/advection-diffusion/.gitignore b/examples/IMEX/advection-diffusion/.gitignore new file mode 100644 index 0000000000..5a7f23771a --- /dev/null +++ b/examples/IMEX/advection-diffusion/.gitignore @@ -0,0 +1 @@ +imex diff --git a/examples/IMEX/advection-reaction/.gitignore b/examples/IMEX/advection-reaction/.gitignore new file mode 100644 index 0000000000..ffd539b44e --- /dev/null +++ b/examples/IMEX/advection-reaction/.gitignore @@ -0,0 +1 @@ +split_operator \ No newline at end of file diff --git a/examples/IMEX/diffusion-nl/.gitignore b/examples/IMEX/diffusion-nl/.gitignore new file mode 100644 index 0000000000..3c9d1f0767 --- /dev/null +++ b/examples/IMEX/diffusion-nl/.gitignore @@ -0,0 +1 @@ +diffusion-nl \ No newline at end of file diff --git a/examples/IMEX/drift-wave-constraint/.gitignore b/examples/IMEX/drift-wave-constraint/.gitignore new file mode 100644 index 0000000000..ca1bc679e9 --- /dev/null +++ b/examples/IMEX/drift-wave-constraint/.gitignore @@ -0,0 +1 @@ +test-drift \ No newline at end of file diff --git a/examples/IMEX/drift-wave-constraint/test-drift.cxx b/examples/IMEX/drift-wave-constraint/test-drift.cxx index 34f3273f71..163775f043 100644 --- a/examples/IMEX/drift-wave-constraint/test-drift.cxx +++ b/examples/IMEX/drift-wave-constraint/test-drift.cxx @@ -26,7 +26,7 @@ class DriftWave : public PhysicsModel { phi = 0.0; // Coordinate system - coord = mesh->coordinates(); + coord = mesh->getCoordinates(); return 0; } diff --git a/examples/IMEX/drift-wave/.gitignore b/examples/IMEX/drift-wave/.gitignore new file mode 100644 index 0000000000..ca1bc679e9 --- /dev/null +++ b/examples/IMEX/drift-wave/.gitignore @@ -0,0 +1 @@ +test-drift \ No newline at end of file diff --git a/examples/advdiff/.gitignore b/examples/advdiff/.gitignore new file mode 100644 index 0000000000..e04e9b916a --- /dev/null +++ b/examples/advdiff/.gitignore @@ -0,0 +1 @@ +advdiff \ No newline at end of file diff --git a/examples/advdiff2/.gitignore b/examples/advdiff2/.gitignore new file mode 100644 index 0000000000..e04e9b916a --- /dev/null +++ b/examples/advdiff2/.gitignore @@ -0,0 +1 @@ +advdiff \ No newline at end of file diff --git a/examples/backtrace/.gitignore b/examples/backtrace/.gitignore new file mode 100644 index 0000000000..f587f481cd --- /dev/null +++ b/examples/backtrace/.gitignore @@ -0,0 +1 @@ +backtrace \ No newline at end of file diff --git a/examples/blob2d-laplacexz/.gitignore b/examples/blob2d-laplacexz/.gitignore new file mode 100644 index 0000000000..a7710fec04 --- /dev/null +++ b/examples/blob2d-laplacexz/.gitignore @@ -0,0 +1 @@ +blob2d \ No newline at end of file diff --git a/examples/blob2d/.gitignore b/examples/blob2d/.gitignore new file mode 100644 index 0000000000..a7710fec04 --- /dev/null +++ b/examples/blob2d/.gitignore @@ -0,0 +1 @@ +blob2d \ No newline at end of file diff --git a/examples/boundary-conditions/advection/.gitignore b/examples/boundary-conditions/advection/.gitignore new file mode 100644 index 0000000000..93c6c5f634 --- /dev/null +++ b/examples/boundary-conditions/advection/.gitignore @@ -0,0 +1 @@ +advection \ No newline at end of file diff --git a/examples/conducting-wall-mode/.gitignore b/examples/conducting-wall-mode/.gitignore new file mode 100644 index 0000000000..0db77ca896 --- /dev/null +++ b/examples/conducting-wall-mode/.gitignore @@ -0,0 +1 @@ +cwm \ No newline at end of file diff --git a/examples/conducting-wall-mode/cwm.cxx b/examples/conducting-wall-mode/cwm.cxx index a88b15f9cf..f89cba9a68 100644 --- a/examples/conducting-wall-mode/cwm.cxx +++ b/examples/conducting-wall-mode/cwm.cxx @@ -125,7 +125,7 @@ class CWM : public PhysicsModel { /************* SHIFTED RADIAL COORDINATES ************/ // Check type of parallel transform - string ptstr; + std::string ptstr; Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); if (lowercase(ptstr) == "shifted") { diff --git a/examples/conduction/.gitignore b/examples/conduction/.gitignore new file mode 100644 index 0000000000..04d6a20467 --- /dev/null +++ b/examples/conduction/.gitignore @@ -0,0 +1 @@ +conduction \ No newline at end of file diff --git a/examples/constraints/alfven-wave/.gitignore b/examples/constraints/alfven-wave/.gitignore new file mode 100644 index 0000000000..b7be7f915f --- /dev/null +++ b/examples/constraints/alfven-wave/.gitignore @@ -0,0 +1 @@ +alfven \ No newline at end of file diff --git a/examples/constraints/alfven-wave/alfven.cxx b/examples/constraints/alfven-wave/alfven.cxx index c9ba1f73e5..33d3f64699 100644 --- a/examples/constraints/alfven-wave/alfven.cxx +++ b/examples/constraints/alfven-wave/alfven.cxx @@ -166,7 +166,7 @@ class Alfven : public PhysicsModel { GRID_LOAD5(Rxy, Bpxy, Btxy, hthe, sinty); // Load metrics // Get the coordinates object - Coordinates *coord = mesh->coordinates(); + Coordinates *coord = mesh->getCoordinates(); // Checking for dpsi and qinty used in BOUT grids Field2D dx; @@ -188,7 +188,7 @@ class Alfven : public PhysicsModel { coord->Bxy /= Bnorm; // Check type of parallel transform - string ptstr; + std::string ptstr; Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); if(lowercase(ptstr) == "shifted") { diff --git a/examples/constraints/laplace-dae/.gitignore b/examples/constraints/laplace-dae/.gitignore new file mode 100644 index 0000000000..97592c28fe --- /dev/null +++ b/examples/constraints/laplace-dae/.gitignore @@ -0,0 +1 @@ +laplace_dae \ No newline at end of file diff --git a/examples/dalf3/.gitignore b/examples/dalf3/.gitignore new file mode 100644 index 0000000000..5fe434edd8 --- /dev/null +++ b/examples/dalf3/.gitignore @@ -0,0 +1 @@ +dalf3 \ No newline at end of file diff --git a/examples/dalf3/dalf3.cxx b/examples/dalf3/dalf3.cxx index 3609486a94..5310bbe6f7 100644 --- a/examples/dalf3/dalf3.cxx +++ b/examples/dalf3/dalf3.cxx @@ -171,7 +171,7 @@ class DALF3 : public PhysicsModel { // SHIFTED RADIAL COORDINATES // Check type of parallel transform - string ptstr; + std::string ptstr; Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); if(lowercase(ptstr) == "shifted") { diff --git a/examples/dalf3/doc/.gitignore b/examples/dalf3/doc/.gitignore new file mode 100644 index 0000000000..4130e30207 --- /dev/null +++ b/examples/dalf3/doc/.gitignore @@ -0,0 +1 @@ +dalf3.pdf \ No newline at end of file diff --git a/examples/eigen-box/.gitignore b/examples/eigen-box/.gitignore new file mode 100644 index 0000000000..e81bc792a5 --- /dev/null +++ b/examples/eigen-box/.gitignore @@ -0,0 +1 @@ +eigen-box \ No newline at end of file diff --git a/examples/elm-pb/.gitignore b/examples/elm-pb/.gitignore new file mode 100644 index 0000000000..61ca49a01c --- /dev/null +++ b/examples/elm-pb/.gitignore @@ -0,0 +1 @@ +elm_pb diff --git a/examples/elm-pb/doc/.gitignore b/examples/elm-pb/doc/.gitignore new file mode 100644 index 0000000000..cb301f2520 --- /dev/null +++ b/examples/elm-pb/doc/.gitignore @@ -0,0 +1 @@ +elm_pb.pdf \ No newline at end of file diff --git a/examples/em-drift/.gitignore b/examples/em-drift/.gitignore new file mode 100644 index 0000000000..d837f17cae --- /dev/null +++ b/examples/em-drift/.gitignore @@ -0,0 +1 @@ +2fluid \ No newline at end of file diff --git a/examples/em-drift/2fluid.cxx b/examples/em-drift/2fluid.cxx index b0af69aecc..e298d4373f 100644 --- a/examples/em-drift/2fluid.cxx +++ b/examples/em-drift/2fluid.cxx @@ -107,7 +107,7 @@ class EMdrift : public PhysicsModel { /************* SHIFTED RADIAL COORDINATES ************/ // Check type of parallel transform - string ptstr; + std::string ptstr; Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); if (lowercase(ptstr) == "shifted") { diff --git a/examples/fci-wave-logn/.gitignore b/examples/fci-wave-logn/.gitignore new file mode 100644 index 0000000000..a7303d2660 --- /dev/null +++ b/examples/fci-wave-logn/.gitignore @@ -0,0 +1 @@ +fci-wave \ No newline at end of file diff --git a/examples/fci-wave/.gitignore b/examples/fci-wave/.gitignore new file mode 100644 index 0000000000..a7303d2660 --- /dev/null +++ b/examples/fci-wave/.gitignore @@ -0,0 +1 @@ +fci-wave \ No newline at end of file diff --git a/examples/finite-volume/diffusion/.gitignore b/examples/finite-volume/diffusion/.gitignore new file mode 100644 index 0000000000..cdafb08583 --- /dev/null +++ b/examples/finite-volume/diffusion/.gitignore @@ -0,0 +1 @@ +diffusion \ No newline at end of file diff --git a/examples/finite-volume/fluid/.gitignore b/examples/finite-volume/fluid/.gitignore new file mode 100644 index 0000000000..c0a635f567 --- /dev/null +++ b/examples/finite-volume/fluid/.gitignore @@ -0,0 +1 @@ +fluid \ No newline at end of file diff --git a/examples/finite-volume/test/.gitignore b/examples/finite-volume/test/.gitignore new file mode 100644 index 0000000000..222fc0fecb --- /dev/null +++ b/examples/finite-volume/test/.gitignore @@ -0,0 +1 @@ +finite_volume \ No newline at end of file diff --git a/examples/gravity_reduced/.gitignore b/examples/gravity_reduced/.gitignore new file mode 100644 index 0000000000..99931b2c71 --- /dev/null +++ b/examples/gravity_reduced/.gitignore @@ -0,0 +1 @@ +gravity_reduced \ No newline at end of file diff --git a/examples/gyro-gem/.gitignore b/examples/gyro-gem/.gitignore new file mode 100644 index 0000000000..b668afd1c3 --- /dev/null +++ b/examples/gyro-gem/.gitignore @@ -0,0 +1 @@ +gem \ No newline at end of file diff --git a/examples/gyro-gem/doc/.gitignore b/examples/gyro-gem/doc/.gitignore new file mode 100644 index 0000000000..e8e4926218 --- /dev/null +++ b/examples/gyro-gem/doc/.gitignore @@ -0,0 +1 @@ +gem.pdf \ No newline at end of file diff --git a/examples/hasegawa-wakatani/.gitignore b/examples/hasegawa-wakatani/.gitignore new file mode 100644 index 0000000000..04c6b38c18 --- /dev/null +++ b/examples/hasegawa-wakatani/.gitignore @@ -0,0 +1 @@ +hw \ No newline at end of file diff --git a/examples/jorek-compare/doc/.gitignore b/examples/jorek-compare/doc/.gitignore new file mode 100644 index 0000000000..878c7d9dac --- /dev/null +++ b/examples/jorek-compare/doc/.gitignore @@ -0,0 +1 @@ +jorek_compare.pdf \ No newline at end of file diff --git a/examples/jorek-compare/jorek_compare.cxx b/examples/jorek-compare/jorek_compare.cxx index cc9b3aa88a..6f0be93b88 100644 --- a/examples/jorek-compare/jorek_compare.cxx +++ b/examples/jorek-compare/jorek_compare.cxx @@ -246,7 +246,7 @@ class Jorek : public PhysicsModel { // SHIFTED RADIAL COORDINATES // Check type of parallel transform - string ptstr; + std::string ptstr; Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); if (lowercase(ptstr) == "shifted") { diff --git a/examples/lapd-drift/lapd_drift.cxx b/examples/lapd-drift/lapd_drift.cxx index 4628f93395..55022c6e03 100644 --- a/examples/lapd-drift/lapd_drift.cxx +++ b/examples/lapd-drift/lapd_drift.cxx @@ -252,7 +252,7 @@ class LAPDdrift : public PhysicsModel { /************* SHIFTED RADIAL COORDINATES ************/ // Check type of parallel transform - string ptstr; + std::string ptstr; Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); if (lowercase(ptstr) == "shifted") { diff --git a/examples/laplacexy/alfven-wave/.gitignore b/examples/laplacexy/alfven-wave/.gitignore new file mode 100644 index 0000000000..b7be7f915f --- /dev/null +++ b/examples/laplacexy/alfven-wave/.gitignore @@ -0,0 +1 @@ +alfven \ No newline at end of file diff --git a/examples/laplacexy/laplace_perp/.gitignore b/examples/laplacexy/laplace_perp/.gitignore new file mode 100644 index 0000000000..30d74d2584 --- /dev/null +++ b/examples/laplacexy/laplace_perp/.gitignore @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/examples/laplacexy/simple/.gitignore b/examples/laplacexy/simple/.gitignore new file mode 100644 index 0000000000..14b380ea81 --- /dev/null +++ b/examples/laplacexy/simple/.gitignore @@ -0,0 +1 @@ +test-laplacexy \ No newline at end of file diff --git a/examples/monitor-newapi/.gitignore b/examples/monitor-newapi/.gitignore new file mode 100644 index 0000000000..edffd38e3d --- /dev/null +++ b/examples/monitor-newapi/.gitignore @@ -0,0 +1 @@ +monitor \ No newline at end of file diff --git a/examples/monitor/.gitignore b/examples/monitor/.gitignore new file mode 100644 index 0000000000..edffd38e3d --- /dev/null +++ b/examples/monitor/.gitignore @@ -0,0 +1 @@ +monitor \ No newline at end of file diff --git a/examples/non-local_1d/cubic_spline_local.hxx b/examples/non-local_1d/cubic_spline_local.hxx index c185c95eb0..f73baa7c1e 100644 --- a/examples/non-local_1d/cubic_spline_local.hxx +++ b/examples/non-local_1d/cubic_spline_local.hxx @@ -33,6 +33,10 @@ #include #include +struct bindex{ + int jx, jy, jz; +}; + class CubicSpline { public: CubicSpline(); diff --git a/examples/performance/arithmetic/.gitignore b/examples/performance/arithmetic/.gitignore new file mode 100644 index 0000000000..077be4cbd0 --- /dev/null +++ b/examples/performance/arithmetic/.gitignore @@ -0,0 +1 @@ +arithmetic \ No newline at end of file diff --git a/examples/performance/arithmetic_3d2d/.gitignore b/examples/performance/arithmetic_3d2d/.gitignore new file mode 100644 index 0000000000..14968af063 --- /dev/null +++ b/examples/performance/arithmetic_3d2d/.gitignore @@ -0,0 +1 @@ +arithmetic_3d2d \ No newline at end of file diff --git a/examples/performance/bracket/.gitignore b/examples/performance/bracket/.gitignore new file mode 100644 index 0000000000..7c67f22887 --- /dev/null +++ b/examples/performance/bracket/.gitignore @@ -0,0 +1 @@ +bracket \ No newline at end of file diff --git a/examples/performance/ddx/.gitignore b/examples/performance/ddx/.gitignore new file mode 100644 index 0000000000..b3962fd5f1 --- /dev/null +++ b/examples/performance/ddx/.gitignore @@ -0,0 +1 @@ +ddx \ No newline at end of file diff --git a/examples/performance/ddy/.gitignore b/examples/performance/ddy/.gitignore new file mode 100644 index 0000000000..bbc4b0775d --- /dev/null +++ b/examples/performance/ddy/.gitignore @@ -0,0 +1 @@ +ddy \ No newline at end of file diff --git a/examples/performance/ddz/.gitignore b/examples/performance/ddz/.gitignore new file mode 100644 index 0000000000..74f0a96055 --- /dev/null +++ b/examples/performance/ddz/.gitignore @@ -0,0 +1 @@ +ddz \ No newline at end of file diff --git a/examples/performance/difops/test-difops.cxx b/examples/performance/difops/test-difops.cxx index dade6b11d3..a7bfc94747 100644 --- a/examples/performance/difops/test-difops.cxx +++ b/examples/performance/difops/test-difops.cxx @@ -29,7 +29,7 @@ const Field3D DDX_C2(const Field3D &f) { Field3D result; result.allocate(); - for(auto i : result.region(RGN_NOBNDRY)) { + for(auto i : result.getRegion(RGN_NOBNDRY)) { result[i] = DDX_C2(f, i); } return result; @@ -42,7 +42,7 @@ const Field3D DDX_C2(const Field3D &f) { const Field3D DDY_C2(const Field3D &f) { Field3D result; result.allocate(); - for(auto i : result.region(RGN_NOBNDRY)) { + for(auto i : result.getRegion(RGN_NOBNDRY)) { result[i] = DDY_C2(f, i); } return result; @@ -55,7 +55,7 @@ const Field3D DDY_C2(const Field3D &f) { const Field3D DDZ_C2(const Field3D &f) { Field3D result; result.allocate(); - for(auto i : result.region(RGN_NOBNDRY)) { + for(auto i : result.getRegion(RGN_NOBNDRY)) { result[i] = DDZ_C2(f, i); } return result; @@ -71,7 +71,7 @@ const Field3D DDZ_C2(const Field3D &f) { const Field3D DDX_C4(const Field3D &f) { Field3D result; result.allocate(); - for(auto i : result.region(RGN_NOBNDRY)) { + for(auto i : result.getRegion(RGN_NOBNDRY)) { result[i] = DDX_C4(f, i); } return result; @@ -84,7 +84,7 @@ const Field3D DDX_C4(const Field3D &f) { const Field3D DDZ_C4(const Field3D &f) { Field3D result; result.allocate(); - for(auto i : result.region(RGN_NOBNDRY)) { + for(auto i : result.getRegion(RGN_NOBNDRY)) { result[i] = DDZ_C4(f, i); } return result; @@ -101,7 +101,7 @@ const Field3D DDX_test(const Field3D &f) { if(!func) { // Not defined yet - string setting; + std::string setting; Options::getRoot()->getSection("operators")->get("ddx", setting, "c2"); setting = lowercase(setting); @@ -125,7 +125,7 @@ const Field3D DDX_test(const Field3D &f) { const Field3D bracket_arakawa(const Field3D &f, const Field3D &g) { Field3D result; result.allocate(); - for(auto i : result.region(RGN_NOBNDRY)) { + for(auto i : result.getRegion(RGN_NOBNDRY)) { result[i] = bracket_arakawa(f, g, i); } return result; @@ -151,7 +151,7 @@ int main(int argc, char **argv) { // Note: Need to allocate ddt() fields before [] access ddt(n).allocate(); ddt(vort).allocate(); - for(auto i : n.region(RGN_NOBNDRY)) { + for(auto i : n.getRegion(RGN_NOBNDRY)) { ddt(n)[i] = - bracket_arakawa(phi, n, i) @@ -189,7 +189,7 @@ int main(int argc, char **argv) { ///////////////////////////////////////////////// // Check results - for(auto i : n.region(RGN_NOBNDRY)) { + for(auto i : n.getRegion(RGN_NOBNDRY)) { if(abs(ddt(n)[i] - dn_2[i]) > 1e-5) { output.write("Difference in ddt(n) at (%d,%d,%d): %e, %e\n", i.x, i.y, i.z, ddt(n)[i], dn_2[i]); diff --git a/examples/performance/iterator-offsets/.gitignore b/examples/performance/iterator-offsets/.gitignore new file mode 100644 index 0000000000..ad079c67b1 --- /dev/null +++ b/examples/performance/iterator-offsets/.gitignore @@ -0,0 +1 @@ +iterator-offsets \ No newline at end of file diff --git a/examples/performance/tuning_regionblocksize/.gitignore b/examples/performance/tuning_regionblocksize/.gitignore new file mode 100644 index 0000000000..3aaa5b7653 --- /dev/null +++ b/examples/performance/tuning_regionblocksize/.gitignore @@ -0,0 +1 @@ +tuning_regionblocksize \ No newline at end of file diff --git a/examples/preconditioning/wave/.gitignore b/examples/preconditioning/wave/.gitignore new file mode 100644 index 0000000000..ccf9f3db8f --- /dev/null +++ b/examples/preconditioning/wave/.gitignore @@ -0,0 +1 @@ +test_precon \ No newline at end of file diff --git a/examples/reconnect-2field/.gitignore b/examples/reconnect-2field/.gitignore new file mode 100644 index 0000000000..4e2e9e147e --- /dev/null +++ b/examples/reconnect-2field/.gitignore @@ -0,0 +1 @@ +2field \ No newline at end of file diff --git a/examples/shear-alfven-wave/.gitignore b/examples/shear-alfven-wave/.gitignore new file mode 100644 index 0000000000..d837f17cae --- /dev/null +++ b/examples/shear-alfven-wave/.gitignore @@ -0,0 +1 @@ +2fluid \ No newline at end of file diff --git a/examples/shear-alfven-wave/2fluid.cxx b/examples/shear-alfven-wave/2fluid.cxx index 1e15ba4a18..e0a70f17eb 100644 --- a/examples/shear-alfven-wave/2fluid.cxx +++ b/examples/shear-alfven-wave/2fluid.cxx @@ -110,7 +110,7 @@ class ShearAlfven : public PhysicsModel { /************* SHIFTED RADIAL COORDINATES ************/ // Check type of parallel transform - string ptstr; + std::string ptstr; Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); if (lowercase(ptstr) == "shifted") { diff --git a/examples/staggered_grid/.gitignore b/examples/staggered_grid/.gitignore new file mode 100644 index 0000000000..dd25165a6c --- /dev/null +++ b/examples/staggered_grid/.gitignore @@ -0,0 +1 @@ +test_staggered \ No newline at end of file diff --git a/examples/tokamak-2fluid/.gitignore b/examples/tokamak-2fluid/.gitignore new file mode 100644 index 0000000000..d837f17cae --- /dev/null +++ b/examples/tokamak-2fluid/.gitignore @@ -0,0 +1 @@ +2fluid \ No newline at end of file diff --git a/examples/tokamak-2fluid/2fluid.cxx b/examples/tokamak-2fluid/2fluid.cxx index 93f55fa3e2..01f932f9fb 100644 --- a/examples/tokamak-2fluid/2fluid.cxx +++ b/examples/tokamak-2fluid/2fluid.cxx @@ -288,7 +288,7 @@ class TwoFluid : public PhysicsModel { // SHIFTED RADIAL COORDINATES // Check type of parallel transform - string ptstr; + std::string ptstr; Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); if (lowercase(ptstr) == "shifted") { diff --git a/examples/wave-slab/.gitignore b/examples/wave-slab/.gitignore new file mode 100644 index 0000000000..e87f73cf55 --- /dev/null +++ b/examples/wave-slab/.gitignore @@ -0,0 +1 @@ +wave_slab \ No newline at end of file From 5733b0e8226a5aee4c5907df39f959bb7e61278f Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 14 Dec 2018 14:25:18 +0000 Subject: [PATCH 0483/1783] Add some .gitignore files for the integrated tests --- tests/integrated/test-drift-instability-staggered/.gitignore | 2 ++ tests/integrated/test-naulin-laplace/.gitignore | 1 + tests/integrated/test-solver/.gitignore | 1 + tests/integrated/test-stopCheck-file/.gitignore | 1 + 4 files changed, 5 insertions(+) create mode 100644 tests/integrated/test-drift-instability-staggered/.gitignore create mode 100644 tests/integrated/test-naulin-laplace/.gitignore create mode 100644 tests/integrated/test-solver/.gitignore create mode 100644 tests/integrated/test-stopCheck-file/.gitignore diff --git a/tests/integrated/test-drift-instability-staggered/.gitignore b/tests/integrated/test-drift-instability-staggered/.gitignore new file mode 100644 index 0000000000..00af1f1ce8 --- /dev/null +++ b/tests/integrated/test-drift-instability-staggered/.gitignore @@ -0,0 +1,2 @@ +2fluid +data \ No newline at end of file diff --git a/tests/integrated/test-naulin-laplace/.gitignore b/tests/integrated/test-naulin-laplace/.gitignore new file mode 100644 index 0000000000..d5c09c3f65 --- /dev/null +++ b/tests/integrated/test-naulin-laplace/.gitignore @@ -0,0 +1 @@ +test_naulin_laplace \ No newline at end of file diff --git a/tests/integrated/test-solver/.gitignore b/tests/integrated/test-solver/.gitignore new file mode 100644 index 0000000000..3cee2d13a7 --- /dev/null +++ b/tests/integrated/test-solver/.gitignore @@ -0,0 +1 @@ +test_solver diff --git a/tests/integrated/test-stopCheck-file/.gitignore b/tests/integrated/test-stopCheck-file/.gitignore new file mode 100644 index 0000000000..cedbd25109 --- /dev/null +++ b/tests/integrated/test-stopCheck-file/.gitignore @@ -0,0 +1 @@ +test_stopCheck \ No newline at end of file From bd23c71eb31c654345e72052542cce15863378d4 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 14 Dec 2018 16:05:43 +0000 Subject: [PATCH 0484/1783] Fix ShiftedMetric BOUT_FOR loops --- src/mesh/parallel/shiftedmetric.cxx | 30 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index e50c7531af..a94b9228c9 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -73,18 +73,18 @@ ShiftedMetric::ShiftedMetric(Mesh &m) : mesh(m), zShift(&m) { } //To/From field aligned phases - BOUT_FOR(i, zShift.getRegion("RGN_ALL")) { + BOUT_FOR(i, mesh.getRegion2D("RGN_ALL")) { for(int jz=0;jz Date: Sat, 15 Dec 2018 21:08:22 +0000 Subject: [PATCH 0485/1783] Fix regions for loops in ShiftedMetric Regions used in BOUT_FOR loops must exclude y-guard cells, like the previous nested loops. --- src/mesh/parallel/shiftedmetric.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index a94b9228c9..d0298f2591 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -82,7 +82,7 @@ ShiftedMetric::ShiftedMetric(Mesh &m) : mesh(m), zShift(&m) { } //Yup/Ydown phases -- note we don't shift in the boundaries/guards - BOUT_FOR(i, mesh.getRegion2D("RGN_ALL")) { + BOUT_FOR(i, mesh.getRegion2D("RGN_NOY")) { BoutReal yupShift = zShift[i] - zShift[i.yp()]; BoutReal ydownShift = zShift[i] - zShift[i.ym()]; @@ -107,14 +107,14 @@ void ShiftedMetric::calcYUpDown(Field3D &f) { Field3D& yup = f.yup(); yup.allocate(); - BOUT_FOR(i, mesh.getRegion2D("RGN_NOX")) { + BOUT_FOR(i, mesh.getRegion2D("RGN_NOY")) { shiftZ(&f(i.x(), i.y()+1, 0), yupPhs[i.x()][i.y()], &yup(i.x(),i.y()+1,0)); } Field3D& ydown = f.ydown(); ydown.allocate(); - BOUT_FOR(i, mesh.getRegion2D("RGN_NOX")) { + BOUT_FOR(i, mesh.getRegion2D("RGN_NOY")) { shiftZ(&f(i.x(), i.y()-1, 0), ydownPhs[i.x()][i.y()], &ydown(i.x(),i.y()-1,0)); } } From d4ba172bf7a6380ce6b82b1bee1902f408c46347 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 16 Dec 2018 13:10:28 +0000 Subject: [PATCH 0486/1783] Check location of FieldPerp when assigning to Field3D --- src/field/field3d.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 9a5a95ac36..65511f428a 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -304,6 +304,8 @@ Field3D & Field3D::operator=(const Field2D &rhs) { void Field3D::operator=(const FieldPerp &rhs) { TRACE("Field3D = FieldPerp"); + ASSERT1(location == rhs.getLocation()); + /// Check that the data is valid checkData(rhs); From 2c31bed813864c3fa8b1e89e9568622c2a701502 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 17 Dec 2018 12:15:32 +0000 Subject: [PATCH 0487/1783] Use function local storage in shiftZ rather than member storage Those should help improve OpenMP safety. --- include/bout/paralleltransform.hxx | 4 ++-- src/mesh/parallel/shiftedmetric.cxx | 13 +++++-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index bab43dd61e..1bcea0bfcf 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -129,8 +129,8 @@ private: /// This is the shift in toroidal angle (z) which takes a point from /// X-Z orthogonal to field-aligned along Y. Field2D zShift; - std::vector cmplx; ///< A temporary array, used for input/output to fft routines - std::vector cmplxLoc; ///< A temporary array, used for input/output to fft routines + + int nmodes; arr3Dvec toAlignedPhs; ///< Cache of phase shifts for transforming from X-Z orthogonal coordinates to field-aligned coordinates arr3Dvec fromAlignedPhs; ///< Cache of phase shifts for transforming from field-aligned coordinates to X-Z orthogonal coordinates diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index d0298f2591..05854aecbd 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -41,13 +41,9 @@ ShiftedMetric::ShiftedMetric(Mesh &m) : mesh(m), zShift(&m) { //As we're attached to a mesh we can expect the z direction to //not change once we've been created so precalculate the complex //phases used in transformations - int nmodes = mesh.LocalNz/2 + 1; + nmodes = mesh.LocalNz / 2 + 1; BoutReal zlength = mesh.getCoordinates()->zlength(); - //Allocate storage for complex intermediate - cmplx.resize(nmodes); - std::fill(cmplx.begin(), cmplx.end(), 0.0); - //Allocate storage for our 3d vector structures. //This could be made more succinct but this approach is fairly //verbose --> transparent @@ -152,6 +148,8 @@ const Field3D ShiftedMetric::shiftZ(const Field3D &f, const arr3Dvec &phs, const } void ShiftedMetric::shiftZ(const BoutReal *in, const std::vector &phs, BoutReal *out) { + Array cmplx(nmodes); + // Take forward FFT rfft(in, mesh.LocalNz, &cmplx[0]); @@ -160,7 +158,6 @@ void ShiftedMetric::shiftZ(const BoutReal *in, const std::vector &phs, // std::transform(cmplxOneOff.begin(),cmplxOneOff.end(), ptr.begin(), // cmplxOneOff.begin(), std::multiplies()); - const int nmodes = cmplx.size(); for(int jz=1;jz cmplxLoc(nmodes); + // Take forward FFT rfft(in, len, &cmplxLoc[0]); From d49cb3af4097340d6ca76395f93b60b3ae021b75 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 17 Dec 2018 12:46:44 +0000 Subject: [PATCH 0488/1783] Use Tensor for 3D storage in shifted metric rather than nested vectors --- include/bout/paralleltransform.hxx | 23 ++++++------ src/mesh/parallel/shiftedmetric.cxx | 54 +++++++++++------------------ 2 files changed, 33 insertions(+), 44 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 1bcea0bfcf..f2f40ed62f 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -6,15 +6,14 @@ #ifndef __PARALLELTRANSFORM_H__ #define __PARALLELTRANSFORM_H__ -#include #include #include +#include #include +#include class Mesh; -#include - /*! * Calculates the values of a field along the magnetic * field (y direction) @@ -121,8 +120,6 @@ public: return true; } - /// A 3D array, implemented as nested vectors - typedef std::vector>> arr3Dvec; private: Mesh &mesh; ///< The mesh this paralleltransform is part of @@ -132,11 +129,14 @@ private: int nmodes; - arr3Dvec toAlignedPhs; ///< Cache of phase shifts for transforming from X-Z orthogonal coordinates to field-aligned coordinates - arr3Dvec fromAlignedPhs; ///< Cache of phase shifts for transforming from field-aligned coordinates to X-Z orthogonal coordinates + Tensor toAlignedPhs; ///< Cache of phase shifts for transforming from X-Z + ///orthogonal coordinates to field-aligned coordinates + Tensor fromAlignedPhs; ///< Cache of phase shifts for transforming from + ///field-aligned coordinates to X-Z orthogonal + ///coordinates - arr3Dvec yupPhs; ///< Cache of phase shifts for calculating yup fields - arr3Dvec ydownPhs; ///< Cache of phase shifts for calculating ydown fields + Tensor yupPhs; ///< Cache of phase shifts for calculating yup fields + Tensor ydownPhs; ///< Cache of phase shifts for calculating ydown fields /*! * Shift a 2D field in Z. @@ -162,7 +162,8 @@ private: * @param[in] f The field to shift * @param[in] phs The phase to shift by */ - const Field3D shiftZ(const Field3D &f, const arr3Dvec &phs, const REGION region=RGN_NOX); + const Field3D shiftZ(const Field3D& f, const Tensor& phs, + const REGION region = RGN_NOX); /*! * Shift a given 1D array, assumed to be in Z, by the given \p zangle @@ -181,7 +182,7 @@ private: * @param[in] phs Phase shift, assumed to have length (mesh.LocalNz/2 + 1) i.e. the number of modes * @param[out] out A 1D array of length mesh.LocalNz, already allocated */ - void shiftZ(const BoutReal *in, const std::vector &phs, BoutReal *out); + void shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* out); }; diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 05854aecbd..0481971671 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -44,36 +44,21 @@ ShiftedMetric::ShiftedMetric(Mesh &m) : mesh(m), zShift(&m) { nmodes = mesh.LocalNz / 2 + 1; BoutReal zlength = mesh.getCoordinates()->zlength(); - //Allocate storage for our 3d vector structures. - //This could be made more succinct but this approach is fairly - //verbose --> transparent - fromAlignedPhs.resize(mesh.LocalNx); - toAlignedPhs.resize(mesh.LocalNx); - - yupPhs.resize(mesh.LocalNx); - ydownPhs.resize(mesh.LocalNx); - - for(int jx=0;jx(mesh.LocalNx, mesh.LocalNy, nmodes); + toAlignedPhs = Tensor(mesh.LocalNx, mesh.LocalNy, nmodes); + + yupPhs = Tensor(mesh.LocalNx, mesh.LocalNy, nmodes); + ydownPhs = Tensor(mesh.LocalNx, mesh.LocalNy, nmodes); + //To/From field aligned phases BOUT_FOR(i, mesh.getRegion2D("RGN_ALL")) { for(int jz=0;jz& phs, + const REGION region) { ASSERT1(&mesh == f.getMesh()); if(mesh.LocalNz == 1) return f; // Shifting makes no difference @@ -140,14 +128,14 @@ const Field3D ShiftedMetric::shiftZ(const Field3D &f, const arr3Dvec &phs, const result.allocate(); BOUT_FOR(i, mesh.getRegion2D(REGION_STRING(region))) { - shiftZ(&f(i.x(), i.y(), 0), phs[i.x()][i.y()], &result(i.x(), i.y(), 0)); + shiftZ(&f(i.x(), i.y(), 0), &phs(i.x(), i.y(), 0), &result(i.x(), i.y(), 0)); } return result; } -void ShiftedMetric::shiftZ(const BoutReal *in, const std::vector &phs, BoutReal *out) { +void ShiftedMetric::shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* out) { Array cmplx(nmodes); // Take forward FFT From bd1f5e26f12993265d1befcc3f308e81846a382b Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Mon, 17 Dec 2018 12:54:59 +0000 Subject: [PATCH 0489/1783] Use Ind2D indexing in shifted metric rather than three integers where possible. --- src/mesh/parallel/shiftedmetric.cxx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 0481971671..7a7c439c14 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -90,15 +90,14 @@ void ShiftedMetric::calcYUpDown(Field3D &f) { yup.allocate(); BOUT_FOR(i, mesh.getRegion2D("RGN_NOY")) { - shiftZ(&f(i.x(), i.y() + 1, 0), &yupPhs(i.x(), i.y(), 0), &yup(i.x(), i.y() + 1, 0)); + shiftZ(&f(i.yp(), 0), &yupPhs(i.x(), i.y(), 0), &yup(i.yp(), 0)); } Field3D& ydown = f.ydown(); ydown.allocate(); BOUT_FOR(i, mesh.getRegion2D("RGN_NOY")) { - shiftZ(&f(i.x(), i.y() - 1, 0), &ydownPhs(i.x(), i.y(), 0), - &ydown(i.x(), i.y() - 1, 0)); + shiftZ(&f(i.ym(), 0), &ydownPhs(i.x(), i.y(), 0), &ydown(i.ym(), 0)); } } @@ -128,7 +127,7 @@ const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Tensor& ph result.allocate(); BOUT_FOR(i, mesh.getRegion2D(REGION_STRING(region))) { - shiftZ(&f(i.x(), i.y(), 0), &phs(i.x(), i.y(), 0), &result(i.x(), i.y(), 0)); + shiftZ(&f(i, 0), &phs(i.x(), i.y(), 0), &result(i, 0)); } return result; @@ -170,7 +169,7 @@ const Field3D ShiftedMetric::shiftZ(const Field3D &f, const Field2D &zangle, con // the whole grid, because zShift is not initialized in the corner guard // cells.) BOUT_FOR(i, mesh.getRegion2D(REGION_STRING(region))) { - shiftZ(&f(i.x(), i.y(), 0), mesh.LocalNz, zangle[i], &result(i.x(), i.y(), 0)); + shiftZ(&f(i, 0), mesh.LocalNz, zangle[i], &result(i, 0)); } return result; From 01da86f22be9f99bcb5d09423aba29bda6743f51 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 17 Dec 2018 23:20:12 +0000 Subject: [PATCH 0490/1783] Work on handling of time dimensions Seem to need to keep track of the record (time index) in order to append data to time-dependent outputs. Mark variables as time evolving by setting an attribute "time_dimension" to a string e.g "t". Currently doesn't support appending to files, but writes the first record. --- include/options_netcdf.hxx | 5 + src/sys/options/options_netcdf.cxx | 100 ++++++++++++++++-- .../test-options-netcdf.cxx | 3 + 3 files changed, 101 insertions(+), 7 deletions(-) diff --git a/include/options_netcdf.hxx b/include/options_netcdf.hxx index 4ce4666def..77b1e81893 100644 --- a/include/options_netcdf.hxx +++ b/include/options_netcdf.hxx @@ -44,6 +44,11 @@ public: private: std::string filename; + + /// NetCDF doesn't seem to keep track of the current index + /// for each variable. This map keeps track of the current + /// index being written for each time dimension + std::map time_index; }; #endif diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 9e19dbabe9..b58a0aad25 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -206,8 +206,51 @@ void NcPutVarVisitor::operator()(const Field3D& value) { // Pointer to data. Assumed to be contiguous array var.putVar(&value(0,0,0)); } + + +/// Visit a variant type, and put the data into a NcVar +struct NcPutVarCountVisitor { + NcPutVarCountVisitor(NcVar& var, const std::vector &start, const std::vector &count) + : var(var), start(start), count(count) {} + template + void operator()(const T& UNUSED(t)) {} + +private: + NcVar& var; + const std::vector &start; ///< Starting (corner) index + const std::vector &count; ///< Index count in each dimension +}; + +template <> +void NcPutVarCountVisitor::operator()(const int& value) { + var.putVar(start, &value); +} +template <> +void NcPutVarCountVisitor::operator()(const double& value) { + var.putVar(start, &value); +} +template <> +void NcPutVarCountVisitor::operator()(const float& value) { + var.putVar(start, &value); +} +template <> +void NcPutVarCountVisitor::operator()(const std::string& value) { + const char* cstr = value.c_str(); + var.putVar(start, &cstr); +} +template <> +void NcPutVarCountVisitor::operator()(const Field2D& value) { + // Pointer to data. Assumed to be contiguous array + var.putVar(start, count, &value(0,0)); +} +template <> +void NcPutVarCountVisitor::operator()(const Field3D& value) { + // Pointer to data. Assumed to be contiguous array + var.putVar(start, count, &value(0,0,0)); +} + -void writeGroup(const Options& options, NcGroup group) { + void writeGroup(const Options& options, NcGroup group, std::map &time_index) { for (const auto& childpair : options.getChildren()) { const auto& name = childpair.first; @@ -222,14 +265,57 @@ void writeGroup(const Options& options, NcGroup group) { auto dims = bout::utils::visit(NcDimVisitor(group), child.value); - auto var = group.addVar(name, nctype, dims); - - // Put the data into the variable - bout::utils::visit(NcPutVarVisitor(var), child.value); + auto time_it = child.attributes.find("time_dimension"); + if (time_it != child.attributes.end()) { + // Has a time dimension + + auto time_name = bout::utils::get(time_it->second); + auto time_dim = group.getDim(time_name, NcGroup::ParentsAndCurrent); + if (time_dim.isNull()) { + time_dim = group.addDim(time_name); + } + + // Get the index + auto time_index_it = time_index.find(time_dim.getId()); + + if (time_index_it == time_index.end()) { + // Haven't seen this index before + time_index[time_dim.getId()] = time_dim.getSize(); + } + + // prepend to vector of dimensions + dims.insert(dims.begin(), time_dim); + + std::vector start_index; ///< Starting index where data will be inserted + std::vector count_index; ///< Size of each dimension + + // Time dimension + start_index.push_back(time_index[time_dim.getId()]); + count_index.push_back(1); // Writing one record + + // Other dimensions (if any) + for (const auto& dim : dims) { + start_index.push_back(0); + count_index.push_back(dim.getSize()); + } + + // Create variable + auto var = group.addVar(name, nctype, dims); + + // Put the data into the variable + bout::utils::visit(NcPutVarCountVisitor(var, start_index, count_index), child.value); + } else { + // No time index + + auto var = group.addVar(name, nctype, dims); + + // Put the data into the variable + bout::utils::visit(NcPutVarVisitor(var), child.value); + } } if (child.isSection()) { - writeGroup(child, group.addGroup(name)); + writeGroup(child, group.addGroup(name), time_index); } } } @@ -244,7 +330,7 @@ void OptionsNetCDF::write(const Options& options) { throw BoutException("Could not open NetCDF file '%s' for writing", filename.c_str()); } - writeGroup(options, dataFile); + writeGroup(options, dataFile, time_index); } #endif // NCDF4 diff --git a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx index 2b6a017406..76374c7571 100644 --- a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx +++ b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx @@ -25,6 +25,9 @@ int main(int argc, char** argv) { Options::root()["f2d"] = Field2D(1.0); Options::root()["f3d"] = Field3D(2.0); + + Options::root()["time_test"] = 1.0; + Options::root()["time_test"].attributes["time_dimension"] = std::string("t"); // Write the BOUT.inp settings to NetCDF file OptionsNetCDF("settings.nc").write(Options::root()); From e3ab88c7c7bf75e56b1a8892367626384cfc5330 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 18 Dec 2018 10:56:49 +0000 Subject: [PATCH 0491/1783] Ensure the location is initialised --- include/bout/invert/laplacexz.hxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/bout/invert/laplacexz.hxx b/include/bout/invert/laplacexz.hxx index 1c7d84902d..2769b5322b 100644 --- a/include/bout/invert/laplacexz.hxx +++ b/include/bout/invert/laplacexz.hxx @@ -38,7 +38,8 @@ class LaplaceXZ { public: - LaplaceXZ(Mesh *UNUSED(m), Options *UNUSED(options), const CELL_LOC UNUSED(loc)) {} + LaplaceXZ(Mesh* UNUSED(m), Options* UNUSED(options), const CELL_LOC loc = CELL_CENTRE) + : location(loc) {} virtual ~LaplaceXZ() {} virtual void setCoefs(const Field2D &A, const Field2D &B) = 0; From 7956a2c0d0c7371272ee624fb07c35b5e6432356 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 18 Dec 2018 11:50:45 +0000 Subject: [PATCH 0492/1783] Ensure paralleltransform methods propagate field location --- src/mesh/parallel/fci.cxx | 1 + src/mesh/parallel/shiftedmetric.cxx | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 25002ffed3..eb62510406 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -247,6 +247,7 @@ const Field3D FCIMap::integrate(Field3D &f) const { Field3D result; result.allocate(); + result.setLocation(f.getLocation()); int nz = mesh->LocalNz; diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 80fdc37274..b1b8f58764 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -148,7 +148,8 @@ const Field3D ShiftedMetric::shiftZ(const Field3D &f, const arr3Dvec &phs) { Field3D result(&mesh); result.allocate(); - + result.setLocation(f.getLocation()); + for(int jx=0;jx Date: Tue, 18 Dec 2018 11:51:08 +0000 Subject: [PATCH 0493/1783] Make interp_to a templated routine to reduce code duplication Also makes use of populateStencil to reduce lines of code and easily lift branching out of loop --- include/interpolation.hxx | 188 +++++++++++++++++- src/mesh/interpolation.cxx | 398 ------------------------------------- 2 files changed, 186 insertions(+), 400 deletions(-) diff --git a/include/interpolation.hxx b/include/interpolation.hxx index 7f58f5a31c..ad72870878 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -29,11 +29,195 @@ #include "bout_types.hxx" #include "field3d.hxx" #include "mask.hxx" +#include "stencils.hxx" #include "utils.hxx" +/// Perform interpolation between centre -> shifted or vice-versa +/*! + Interpolate using 4th-order staggered formula + + @param[in] s Input stencil. mm -> -3/2, m -> -1/2, p -> +1/2, pp -> +3/2 +*/ +inline BoutReal interp(const stencil& s) { + return (9. * (s.m + s.p) - s.mm - s.pp) / 16.; +} + /// Interpolate to a give cell location -const Field3D interp_to(const Field3D &var, CELL_LOC loc, REGION region = RGN_ALL); -const Field2D interp_to(const Field2D &var, CELL_LOC loc, REGION region = RGN_ALL); +/*! + Interpolate between different cell locations + + NOTE: This requires communication if the result is required in guard cells + NOTE: Since corner guard cells cannot be communicated, it never makes sense + to calculate interpolation in guard cells. If guard cell values are required, + we must communicate (unless interpolating in z). Since mesh->communicate() + communicates both x- and y-guard cells by default, there is no difference + between RGN_ALL, RGN_NOX and RGN_NOY. + + @param[in] var Input variable + @param[in] loc Location of output values + @param[in] region Region where output will be calculated +*/ +template +const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { + AUTO_TRACE(); + static_assert(std::is_base_of::value || std::is_base_of::value, + "interp_to must be templated with one of Field2D or Field3D."); + + Mesh* fieldmesh = var.getMesh(); + T result(fieldmesh); + + if ((loc != CELL_CENTRE && loc != CELL_DEFAULT) && (fieldmesh->StaggerGrids == false)) { + throw BoutException("Asked to interpolate, but StaggerGrids is disabled!"); + } + + if (fieldmesh->StaggerGrids && (var.getLocation() != loc)) { + + // Staggered grids enabled, and need to perform interpolation + TRACE("Interpolating %s -> %s", CELL_LOC_STRING(var.getLocation()).c_str(), + CELL_LOC_STRING(loc).c_str()); + + if (region != RGN_NOBNDRY) { + // result is requested in some boundary region(s) + result = var; // NOTE: This is just for boundaries. FIX! + } + // NOTE: invalidateGuards() is called in Field3D::alloctate() if the data + // block is not already allocated, so will be called here if + // region==RGN_NOBNDRY + result.allocate(); + result.setLocation(loc); + + // Cell location of the input field + const CELL_LOC location = var.getLocation(); + + if ((location == CELL_CENTRE) || (loc == CELL_CENTRE)) { + // Going between centred and shifted + + // Get the non-centre location for interpolation direction + const CELL_LOC dir = (loc == CELL_CENTRE) ? location : loc; + + switch (dir) { + case CELL_XLOW: { + // At least 2 boundary cells needed for interpolation in x-direction + ASSERT0(fieldmesh->xstart >= 2); + + if ((location == CELL_CENTRE) && (loc == CELL_XLOW)) { // C2L + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Producing a stencil centred around a lower X value + result[i] = interp(populateStencil(var, i)); + } + } else if (location == CELL_XLOW) { // L2C + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Stencil centred around a cell centre + result[i] = interp(populateStencil(var, i)); + } + } + + break; + } + case CELL_YLOW: { + // At least 2 boundary cells needed for interpolation in y-direction + ASSERT0(fieldmesh->ystart >= 2); + + if (var.hasYupYdown() && ((&var.yup() != &var) || (&var.ydown() != &var))) { + // Field "var" has distinct yup and ydown fields which + // will be used to calculate a derivative along + // the magnetic field + throw BoutException( + "At the moment, fields with yup/ydown cannot use interp_to.\n" + "If we implement a 3-point stencil for interpolate or double-up\n" + "/double-down fields, then we can use this case."); + + if ((location == CELL_CENTRE) && (loc == CELL_YLOW)) { // C2L + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Producing a stencil centred around a lower X value + result[i] = interp( + populateStencil(var, i)); + } + } else if (location == CELL_YLOW) { // L2C + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Stencil centred around a cell centre + result[i] = interp( + populateStencil(var, i)); + } + } + } else { + // var has no yup/ydown fields, so we need to shift into field-aligned + // coordinates + + const T var_fa = fieldmesh->toFieldAligned(var); + if (region != RGN_NOBNDRY) { + // repeat the hack above for boundary points + // this avoids a duplicate toFieldAligned call if we had called + // result = toFieldAligned(result) + // to get the boundary cells + // + // result is requested in some boundary region(s) + result = var_fa; // NOTE: This is just for boundaries. FIX! + result.allocate(); + result.setLocation(loc); + } + + if ((location == CELL_CENTRE) && (loc == CELL_YLOW)) { // C2L + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Producing a stencil centred around a lower X value + result[i] = interp( + populateStencil(var_fa, i)); + } + } else if (location == CELL_YLOW) { // L2C + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Stencil centred around a cell centre + result[i] = interp( + populateStencil(var_fa, i)); + } + } + + result = fieldmesh->fromFieldAligned(result); + } + break; + } + case CELL_ZLOW: { + + if ((location == CELL_CENTRE) && (loc == CELL_ZLOW)) { // C2L + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Producing a stencil centred around a lower X value + result[i] = interp(populateStencil(var, i)); + } + } else if (location == CELL_ZLOW) { // L2C + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Stencil centred around a cell centre + result[i] = interp(populateStencil(var, i)); + } + } + break; + } + default: { + // This should never happen + throw BoutException("Unsupported direction of interpolation\n" + " - don't know how to interpolate to %s", + CELL_LOC_STRING(loc).c_str()); + } + }; + + if ((dir != CELL_ZLOW) && (region != RGN_NOBNDRY)) { + fieldmesh->communicate(result); + } + + } else { + // Shifted -> shifted + // For now, shift to centre then to final location loc + // We probably should not rely on this, but it might work if one of the + // shifts is in the z-direction where guard cells aren't needed. + result = interp_to(interp_to(var, CELL_CENTRE), loc, region); + } + return result; + } else { + // Nothing to do - just return unchanged + // Copying into result to return as returning var may increase the number of + // references to the var data whilst returning result doesn't + result = var; + return result; + } +} /// Print out the cell location (for debugging) void printLocation(const Field3D &var); diff --git a/src/mesh/interpolation.cxx b/src/mesh/interpolation.cxx index 41c841f71b..2cd432791c 100644 --- a/src/mesh/interpolation.cxx +++ b/src/mesh/interpolation.cxx @@ -27,406 +27,8 @@ #include #include #include -#include #include -/// Perform interpolation between centre -> shifted or vice-versa -/*! - Interpolate using 4th-order staggered formula - - @param[in] s Input stencil. mm -> -3/2, m -> -1/2, p -> +1/2, pp -> +3/2 -*/ -BoutReal interp(const stencil &s) { return (9. * (s.m + s.p) - s.mm - s.pp) / 16.; } - -/*! - Interpolate between different cell locations - - NOTE: This requires communication if the result is required in guard cells - NOTE: Since corner guard cells cannot be communicated, it never makes sense - to calculate interpolation in guard cells. If guard cell values are required, - we must communicate (unless interpolating in z). Since mesh->communicate() - communicates both x- and y-guard cells by default, there is no difference - between RGN_ALL, RGN_NOX and RGN_NOY. - - @param[in] var Input variable - @param[in] loc Location of output values - @param[in] region Region where output will be calculated -*/ -const Field3D interp_to(const Field3D &var, CELL_LOC loc, REGION region) { - - Mesh *fieldmesh = var.getMesh(); - Field3D result(fieldmesh); - - if ((loc != CELL_CENTRE && loc != CELL_DEFAULT) && (fieldmesh->StaggerGrids == false)) { - throw BoutException("Asked to interpolate, but StaggerGrids is disabled!"); - } - if (fieldmesh->StaggerGrids && (var.getLocation() != loc)) { - - // Staggered grids enabled, and need to perform interpolation - TRACE("Interpolating %s -> %s", strLocation(var.getLocation()), strLocation(loc)); - - if (region != RGN_NOBNDRY) { - // result is requested in some boundary region(s) - result = var; // NOTE: This is just for boundaries. FIX! - } - // NOTE: invalidateGuards() is called in Field3D::alloctate() if the data - // block is not already allocated, so will be called here if - // region==RGN_NOBNDRY - result.allocate(); - - // Cell location of the input field - CELL_LOC location = var.getLocation(); - - if ((location == CELL_CENTRE) || (loc == CELL_CENTRE)) { - // Going between centred and shifted - CELL_LOC dir; - - // Get the non-centre location for interpolation direction - dir = (loc == CELL_CENTRE) ? location : loc; - - switch (dir) { - case CELL_XLOW: { - // At least 2 boundary cells needed for interpolation in x-direction - ASSERT0(fieldmesh->xstart >= 2); - - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion("RGN_NOBNDRY")) { - // Set stencils - s.mm = var[i.xmm()]; - s.m = var[i.xm()]; - s.c = var[i]; - s.p = var[i.xp()]; - s.pp = var[i.xpp()]; - - if ((location == CELL_CENTRE) && (loc == CELL_XLOW)) { - // Producing a stencil centred around a lower X value - s.pp = s.p; - s.p = s.c; - } else if (location == CELL_XLOW) { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; - } - - result[i] = interp(s); - } - } - break; - } - case CELL_YLOW: { - // At least 2 boundary cells needed for interpolation in y-direction - ASSERT0(fieldmesh->ystart >= 2); - - if (var.hasYupYdown() && ((&var.yup() != &var) || (&var.ydown() != &var))) { - // Field "var" has distinct yup and ydown fields which - // will be used to calculate a derivative along - // the magnetic field - throw BoutException("At the moment, fields with yup/ydown cannot use interp_to.\n" - "If we implement a 3-point stencil for interpolate or double-up\n" - "/double-down fields, then we can use this case."); - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion("RGN_NOBNDRY")) { - // Set stencils - s.m = var.ydown()[i.ym()]; - s.c = var[i]; - s.p = var.yup()[i.yp()]; - - if ((location == CELL_CENTRE) && (loc == CELL_YLOW)) { - // Producing a stencil centred around a lower Y value - s.pp = s.p; - s.p = s.c; - } else if (location == CELL_YLOW) { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; - } - - result[i] = interp(s); - } - } - } else { - // var has no yup/ydown fields, so we need to shift into field-aligned - // coordinates - - Field3D var_fa = fieldmesh->toFieldAligned(var); - if (region != RGN_NOBNDRY) { - // repeat the hack above for boundary points - // this avoids a duplicate toFieldAligned call if we had called - // result = toFieldAligned(result) - // to get the boundary cells - // - // result is requested in some boundary region(s) - result = var_fa; // NOTE: This is just for boundaries. FIX! - result.allocate(); - } - if (fieldmesh->ystart > 1) { - - // More than one guard cell, so set pp and mm values - // This allows higher-order methods to be used - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion("RGN_NOBNDRY")) { - // Set stencils - s.mm = var_fa[i.ymm()]; - s.m = var_fa[i.ym()]; - s.c = var_fa[i]; - s.p = var_fa[i.yp()]; - s.pp = var_fa[i.ypp()]; - - if (location == CELL_CENTRE) { - // Producing a stencil centred around a lower Y value - s.pp = s.p; - s.p = s.c; - } else { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; - } - - result[i] = interp(s); - } - } - } else { - // Only one guard cell, so no pp or mm values - // Note: at the moment we cannot reach this case because of the - // 'ASSERT0(fieldmesh->ystart >=2)' above, but if we implement a 3-point - // stencil for interp, then this will be useful - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion("RGN_NOBNDRY")) { - // Set stencils - s.m = var_fa[i.ym()]; - s.c = var_fa[i]; - s.p = var_fa[i.yp()]; - - if (location == CELL_CENTRE) { - // Producing a stencil centred around a lower Y value - s.pp = s.p; - s.p = s.c; - } else { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; - } - - result[i] = interp(s); - } - } - } - - result = fieldmesh->fromFieldAligned(result); - } - break; - } - case CELL_ZLOW: { - /// Convert REGION enum to a Region string identifier - const auto region_str = REGION_STRING(region); - - BOUT_OMP(parallel) { - stencil s; - BOUT_FOR_INNER(i, result.getRegion(region_str)) { - s.mm = var[i.zmm()]; - s.m = var[i.zm()]; - s.c = var[i]; - s.p = var[i.zp()]; - s.pp = var[i.zpp()]; - - if (location == CELL_CENTRE) { - // Producing a stencil centred around a lower Z value - s.pp = s.p; - s.p = s.c; - } else { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; - } - - result[i] = interp(s); - } - } - break; - } - default: { - // This should never happen - throw BoutException("Unsupported direction of interpolation\n" - " - don't know how to interpolate to %s",strLocation(loc)); - } - }; - - if ((dir != CELL_ZLOW) && (region != RGN_NOBNDRY)) { - fieldmesh->communicate(result); - } - - } else { - // Shifted -> shifted - // For now, shift to centre then to final location loc - // We probably should not rely on this, but it might work if one of the - // shifts is in the z-direction where guard cells aren't needed. - result = interp_to(interp_to(var, CELL_CENTRE), loc, region); - } - result.setLocation(loc); - - return result; - } - - // Nothing to do - just return unchanged - // Copying into result to return as returning var may increase the number of - // references to the var data whilst returning result doesn't - result = var; - return result; -} - -const Field2D interp_to(const Field2D &var, CELL_LOC loc, REGION region) { - - Mesh *fieldmesh = var.getMesh(); - Field2D result(fieldmesh); - - if ((loc != CELL_CENTRE && loc != CELL_DEFAULT) && (fieldmesh->StaggerGrids == false)) { - throw BoutException("Asked to interpolate, but StaggerGrids is disabled!"); - } - if (fieldmesh->StaggerGrids && (var.getLocation() != loc)) { - - // Staggered grids enabled, and need to perform interpolation - TRACE("Interpolating %s -> %s", strLocation(var.getLocation()), strLocation(loc)); - - if (region != RGN_NOBNDRY) { - // result is requested in some boundary region(s) - result = var; // NOTE: This is just for boundaries. FIX! - } - // NOTE: invalidateGuards() is called in Field3D::alloctate() if the data - // block is not already allocated, so will be called here if - // region==RGN_NOBNDRY - result.allocate(); - - // Cell location of the input field - CELL_LOC location = var.getLocation(); - - if ((location == CELL_CENTRE) || (loc == CELL_CENTRE)) { - // Going between centred and shifted - - stencil s; - CELL_LOC dir; - - // Get the non-centre location for interpolation direction - dir = (loc == CELL_CENTRE) ? location : loc; - - switch (dir) { - case CELL_XLOW: { - ASSERT0(fieldmesh->xstart >= 2); // At least 2 boundary cells needed for interpolation in x-direction - - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - - // Set stencils - s.c = var[i]; - s.p = var[i.xp()]; - s.m = var[i.xm()]; - s.pp = var[i.offset(2, 0, 0)]; - s.mm = var[i.offset(-2, 0, 0)]; - - if ((location == CELL_CENTRE) && (loc == CELL_XLOW)) { - // Producing a stencil centred around a lower X value - s.pp = s.p; - s.p = s.c; - } else if (location == CELL_XLOW) { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; - } - - result[i] = interp(s); - } - break; - } - case CELL_YLOW: { - ASSERT0(fieldmesh->ystart >= 2); // At least 2 boundary cells needed for interpolation in y-direction - - if (fieldmesh->ystart > 1) { - - // More than one guard cell, so set pp and mm values - // This allows higher-order methods to be used - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - // Set stencils - s.c = var[i]; - s.p = var[i.yp()]; - s.m = var[i.ym()]; - s.pp = var[i.offset(0, 2, 0)]; - s.mm = var[i.offset(0, -2, 0)]; - - if (location == CELL_CENTRE) { - // Producing a stencil centred around a lower Y value - s.pp = s.p; - s.p = s.c; - } else { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; - } - - result[i] = interp(s); - } - } else { - // Only one guard cell, so no pp or mm values - // Note: at the moment we cannot reach this case because of the - // 'ASSERT0(fieldmesh->ystart >=2)' above, but if we implement a 3-point - // stencil for interp, then this will be useful - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - // Set stencils - s.c = var[i]; - s.p = var[i.yp()]; - s.m = var[i.ym()]; - - if (location == CELL_CENTRE) { - // Producing a stencil centred around a lower Y value - s.pp = s.p; - s.p = s.c; - } else { - // Stencil centred around a cell centre - s.mm = s.m; - s.m = s.c; - } - - result[i] = interp(s); - } - } - break; - } - case CELL_ZLOW: { - // Nothing to do for Field2D as Field2D is constant in z-direction - result = var; - break; - } - default: { - // This should never happen - throw BoutException("Unsupported direction of interpolation\n" - " - don't know how to interpolate to %s",strLocation(loc)); - } - }; - - if ((dir != CELL_ZLOW) && (region != RGN_NOBNDRY)) { - fieldmesh->communicate(result); - } - - } else { - // Shifted -> shifted - // For now, shift to centre then to final location loc - // We probably should not rely on this, but it might work if one of the - // shifts is in the z-direction where guard cells aren't needed. - result = interp_to(interp_to(var, CELL_CENTRE), loc, region); - } - result.setLocation(loc); - - return result; - } - - // Nothing to do - just return unchanged - // Copying into result to return as returning var may increase the number of - // references to the var data whilst returning result doesn't - result = var; - return result; -} - void printLocation(const Field3D &var) { output.write(strLocation(var.getLocation())); } void printLocation(const Field2D &var) { output.write(strLocation(var.getLocation())); } From 199c26bd7f63f3f8ddf9deecd41eee78a16a9ce9 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 12:49:13 +0000 Subject: [PATCH 0494/1783] Add location checks to LaplaceXY --- src/invert/laplacexy/laplacexy.cxx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index 5e5a5a4f93..ebde215fe4 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -283,12 +283,19 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat /////////////////////////////////////////////////// // Set the default coefficients - setCoefs(1.0, 0.0); + Field2D one(1., &mesh); + Field2D zero(0., &mesh); + one.setLocation(location); + zero.setLocation(location); + setCoefs(one, zero); } void LaplaceXY::setCoefs(const Field2D &A, const Field2D &B) { Timer timer("invert"); + ASSERT1(A.getLocation() == location); + ASSERT1(B.getLocation() == location); + Coordinates *coords = mesh->getCoordinates(location); ////////////////////////////////////////////////// @@ -514,6 +521,9 @@ LaplaceXY::~LaplaceXY() { const Field2D LaplaceXY::solve(const Field2D &rhs, const Field2D &x0) { Timer timer("invert"); + ASSERT1(rhs.getLocation() == location); + ASSERT1(x0.getLocation() == location); + // Load initial guess x0 into xs and rhs into bs for(int x=mesh->xstart;x<= mesh->xend;x++) { @@ -632,7 +642,7 @@ const Field2D LaplaceXY::solve(const Field2D &rhs, const Field2D &x0) { Field2D result; result.allocate(); - result.setLocation(rhs.getLocation()); + result.setLocation(location); for(int x=mesh->xstart;x<= mesh->xend;x++) { for(int y=mesh->ystart;y<=mesh->yend;y++) { From e90e93c598a46e67efe7bb868a06672c00f81891 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 12:49:38 +0000 Subject: [PATCH 0495/1783] Add location checks to LaplaceXZ --- .../laplacexz/impls/cyclic/laplacexz-cyclic.cxx | 14 ++++++++++++-- .../laplacexz/impls/petsc/laplacexz-petsc.cxx | 8 +++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx index 115c325267..0b9076de9d 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx @@ -48,7 +48,11 @@ LaplaceXZcyclic::LaplaceXZcyclic(Mesh *m, Options *options, const CELL_LOC loc) OPTION(options, outer_boundary_flags, 0); // Set default coefficients - setCoefs(Field2D(1.0), Field2D(0.0)); + Field2D one(1., &mesh); + Field2D zero(0., &mesh); + one.setLocation(location); + zero.setLocation(location); + setCoefs(one, zero); } LaplaceXZcyclic::~LaplaceXZcyclic() { @@ -59,6 +63,9 @@ LaplaceXZcyclic::~LaplaceXZcyclic() { void LaplaceXZcyclic::setCoefs(const Field2D &A2D, const Field2D &B2D) { TRACE("LaplaceXZcyclic::setCoefs"); Timer timer("invert"); + + ASSERT1(A2D.getLocation() == location); + ASSERT1(B2D.getLocation() == location); // Set coefficients @@ -157,6 +164,9 @@ void LaplaceXZcyclic::setCoefs(const Field2D &A2D, const Field2D &B2D) { Field3D LaplaceXZcyclic::solve(const Field3D &rhs, const Field3D &x0) { Timer timer("invert"); + ASSERT1(rhs.getLocation() == location); + ASSERT1(x0.getLocation() == location); + Mesh *mesh = rhs.getMesh(); // Create the rhs array int ind = 0; @@ -244,7 +254,7 @@ Field3D LaplaceXZcyclic::solve(const Field3D &rhs, const Field3D &x0) { Field3D result(mesh); result.allocate(); - result.setLocation(rhs.getLocation()); + result.setLocation(location); ind = 0; for(int y=mesh->ystart; y <= mesh->yend; y++) { diff --git a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx index 09d8b4ccc0..66234e83b6 100644 --- a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx +++ b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx @@ -276,6 +276,9 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { TRACE("LaplaceXZpetsc::setCoefs"); + ASSERT1(Ain.getLocation() == location); + ASSERT1(Bin.getLocation() == location); + #if CHECK > 0 // Checking flags are set to something which is not implemented // This is done binary (which is possible as each flag is a power of 2) @@ -578,6 +581,9 @@ Field3D LaplaceXZpetsc::solve(const Field3D &bin, const Field3D &x0in) { TRACE("LaplaceXZpetsc::solve"); + ASSERT1(bin.getLocation() == location); + ASSERT1(x0in.getLocation() == location); + if(!coefs_set) { throw BoutException("LaplaceXZpetsc: solve called before setCoefs"); } @@ -589,7 +595,7 @@ Field3D LaplaceXZpetsc::solve(const Field3D &bin, const Field3D &x0in) { Field3D result; result.allocate(); - result.setLocation(bin.getLocation()); + result.setLocation(location); for (auto &it : slice) { /// Get y index From 350cddfa1a1fe9e64933c7fd09169becfd610e5d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 14:04:47 +0000 Subject: [PATCH 0496/1783] Add default arguments for LaplaceXY and LaplaceXZ constructors Also need to rename the 'mesh' members to 'localmesh' to avoid name clash with global 'mesh' when global 'mesh' is used as a default argument. --- include/bout/invert/laplacexy.hxx | 6 +- include/bout/invert/laplacexz.hxx | 2 +- src/invert/laplacexy/laplacexy.cxx | 266 +++++++++--------- .../impls/cyclic/laplacexz-cyclic.cxx | 52 ++-- .../impls/cyclic/laplacexz-cyclic.hxx | 6 +- .../laplacexz/impls/petsc/laplacexz-petsc.cxx | 160 +++++------ .../laplacexz/impls/petsc/laplacexz-petsc.hxx | 7 +- 7 files changed, 251 insertions(+), 248 deletions(-) diff --git a/include/bout/invert/laplacexy.hxx b/include/bout/invert/laplacexy.hxx index 4a6b487d68..f78aab93c8 100644 --- a/include/bout/invert/laplacexy.hxx +++ b/include/bout/invert/laplacexy.hxx @@ -49,7 +49,7 @@ */ class LaplaceXY { public: - LaplaceXY(Mesh *m, Options *opt = nullptr, const CELL_LOC = CELL_CENTRE) { + LaplaceXY(Mesh *m = mesh, Options *opt = nullptr, const CELL_LOC = CELL_CENTRE) { throw BoutException("LaplaceXY requires PETSc. No LaplaceXY available"); } void setCoefs(const Field2D &A, const Field2D &B) {} @@ -68,7 +68,7 @@ public: /*! * Constructor */ - LaplaceXY(Mesh *m, Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); + LaplaceXY(Mesh *m = mesh, Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); /*! * Destructor */ @@ -113,7 +113,7 @@ private: KSP ksp; ///< Krylov Subspace solver PC pc; ///< Preconditioner - Mesh *mesh; ///< The mesh this operates on, provides metrics and communication + Mesh *localmesh; ///< The mesh this operates on, provides metrics and communication // Preconditioner int xstart, xend; diff --git a/include/bout/invert/laplacexz.hxx b/include/bout/invert/laplacexz.hxx index 2769b5322b..319b0f44bb 100644 --- a/include/bout/invert/laplacexz.hxx +++ b/include/bout/invert/laplacexz.hxx @@ -47,7 +47,7 @@ public: virtual Field3D solve(const Field3D &b, const Field3D &x0) = 0; - static LaplaceXZ *create(Mesh *m, Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); + static LaplaceXZ *create(Mesh *m = mesh, Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); protected: static const int INVERT_DC_GRAD = 1; diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index ebde215fe4..55ad3a84e0 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -25,7 +25,7 @@ static PetscErrorCode laplacePCapply(PC pc,Vec x,Vec y) { PetscFunctionReturn(s->precon(x, y)); } -LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), location(loc) { +LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : localmesh(m), location(loc) { Timer timer("invert"); if (opt == nullptr) { @@ -59,21 +59,21 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat int ind = 0; // Y boundaries - for(RangeIterator it=mesh->iterateBndryLowerY(); !it.isDone(); it++) { - indexXY(it.ind, mesh->ystart-1) = ind++; + for(RangeIterator it=localmesh->iterateBndryLowerY(); !it.isDone(); it++) { + indexXY(it.ind, localmesh->ystart-1) = ind++; } - for(RangeIterator it=mesh->iterateBndryUpperY(); !it.isDone(); it++) { - indexXY(it.ind, mesh->yend+1) = ind++; + for(RangeIterator it=localmesh->iterateBndryUpperY(); !it.isDone(); it++) { + indexXY(it.ind, localmesh->yend+1) = ind++; } - xstart = mesh->xstart; - if(mesh->firstX()) + xstart = localmesh->xstart; + if(localmesh->firstX()) xstart -= 1; // Include X guard cells - xend = mesh->xend; - if(mesh->lastX()) + xend = localmesh->xend; + if(localmesh->lastX()) xend += 1; for(int x=xstart;x<=xend;x++) - for(int y=mesh->ystart;y<=mesh->yend;y++) { + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { indexXY(x,y) = ind++; } @@ -83,7 +83,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat // Allocate storage for preconditioner nloc = xend - xstart + 1; // Number of X points on this processor - nsys = mesh->yend - mesh->ystart + 1; // Number of separate Y slices + nsys = localmesh->yend - localmesh->ystart + 1; // Number of separate Y slices acoef = Matrix(nsys, nloc); bcoef = Matrix(nsys, nloc); @@ -92,7 +92,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat bvals = Matrix(nsys, nloc); // Create a cyclic reduction object - cr = bout::utils::make_unique>(mesh->getXcomm(), nloc); + cr = bout::utils::make_unique>(localmesh->getXcomm(), nloc); ////////////////////////////////////////////////// // Pre-allocate PETSc storage @@ -109,10 +109,10 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat } // X boundaries - if(mesh->firstX()) { + if(localmesh->firstX()) { // Lower X boundary - for(int y=mesh->ystart;y<=mesh->yend;y++) { - int localIndex = indexXY(mesh->xstart-1,y); + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { + int localIndex = indexXY(localmesh->xstart-1,y); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] = 2; // Diagonal sub-matrix @@ -120,25 +120,25 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat } }else { // On another processor - for(int y=mesh->ystart;y<=mesh->yend;y++) { - int localIndex = indexXY(mesh->xstart,y); + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { + int localIndex = indexXY(localmesh->xstart,y); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] -= 1; o_nnz[localIndex] += 1; } } - if(mesh->lastX()) { + if(localmesh->lastX()) { // Upper X boundary - for(int y=mesh->ystart;y<=mesh->yend;y++) { - int localIndex = indexXY(mesh->xend+1,y); + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { + int localIndex = indexXY(localmesh->xend+1,y); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] = 2; // Diagonal sub-matrix o_nnz[localIndex] = 0; // Off-diagonal sub-matrix } }else { // On another processor - for(int y=mesh->ystart;y<=mesh->yend;y++) { - int localIndex = indexXY(mesh->xend,y); + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { + int localIndex = indexXY(localmesh->xend,y); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] -= 1; o_nnz[localIndex] += 1; @@ -146,41 +146,41 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat } // Y boundaries - for(int x=mesh->xstart; x <=mesh->xend; x++) { + for(int x=localmesh->xstart; x <=localmesh->xend; x++) { // Default to no boundary // NOTE: This assumes that communications in Y are to other // processors. If Y is communicated with this processor (e.g. NYPE=1) // then this will result in PETSc warnings about out of range allocations - int localIndex = indexXY(x, mesh->ystart); + int localIndex = indexXY(x, localmesh->ystart); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); //d_nnz[localIndex] -= 1; // Note: Slightly inefficient o_nnz[localIndex] += 1; - localIndex = indexXY(x, mesh->yend); + localIndex = indexXY(x, localmesh->yend); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); //d_nnz[localIndex] -= 1; // Note: Slightly inefficient o_nnz[localIndex] += 1; } - for(RangeIterator it=mesh->iterateBndryLowerY(); !it.isDone(); it++) { - int localIndex = indexXY(it.ind, mesh->ystart-1); + for(RangeIterator it=localmesh->iterateBndryLowerY(); !it.isDone(); it++) { + int localIndex = indexXY(it.ind, localmesh->ystart-1); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] = 2; // Diagonal sub-matrix o_nnz[localIndex] = 0; // Off-diagonal sub-matrix - localIndex = indexXY(it.ind, mesh->ystart); + localIndex = indexXY(it.ind, localmesh->ystart); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] += 1; o_nnz[localIndex] -= 1; } - for(RangeIterator it=mesh->iterateBndryUpperY(); !it.isDone(); it++) { - int localIndex = indexXY(it.ind, mesh->yend+1); + for(RangeIterator it=localmesh->iterateBndryUpperY(); !it.isDone(); it++) { + int localIndex = indexXY(it.ind, localmesh->yend+1); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] = 2; // Diagonal sub-matrix o_nnz[localIndex] = 0; // Off-diagonal sub-matrix - localIndex = indexXY(it.ind, mesh->yend); + localIndex = indexXY(it.ind, localmesh->yend); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] += 1; o_nnz[localIndex] -= 1; @@ -200,7 +200,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat indexXY += Istart; // Now communicate to fill guard cells - mesh->communicate(indexXY); + localmesh->communicate(indexXY); ////////////////////////////////////////////////// // Set up KSP @@ -267,7 +267,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat /////////////////////////////////////////////////// // Decide boundary condititions - if(mesh->periodicY(mesh->xstart)) { + if(localmesh->periodicY(localmesh->xstart)) { // Periodic in Y, so in the core opt->get("core_bndry_dirichlet", x_inner_dirichlet, false); }else { @@ -283,8 +283,8 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : mesh(m), locat /////////////////////////////////////////////////// // Set the default coefficients - Field2D one(1., &mesh); - Field2D zero(0., &mesh); + Field2D one(1., localmesh); + Field2D zero(0., localmesh); one.setLocation(location); zero.setLocation(location); setCoefs(one, zero); @@ -296,15 +296,15 @@ void LaplaceXY::setCoefs(const Field2D &A, const Field2D &B) { ASSERT1(A.getLocation() == location); ASSERT1(B.getLocation() == location); - Coordinates *coords = mesh->getCoordinates(location); + Coordinates *coords = localmesh->getCoordinates(location); ////////////////////////////////////////////////// // Set Matrix elements // // (1/J) d/dx ( J * g11 d/dx ) + (1/J) d/dy ( J * g22 d/dy ) - for(int x=mesh->xstart; x <= mesh->xend; x++) { - for(int y=mesh->ystart;y<=mesh->yend;y++) { + for(int x=localmesh->xstart; x <= localmesh->xend; x++) { + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { // stencil entries PetscScalar c, xm, xp, ym, yp; @@ -333,9 +333,9 @@ void LaplaceXY::setCoefs(const Field2D &A, const Field2D &B) { c += B(x,y); // Put values into the preconditioner, X derivatives only - acoef(y - mesh->ystart, x - xstart) = xm; - bcoef(y - mesh->ystart, x - xstart) = c; - ccoef(y - mesh->ystart, x - xstart) = xp; + acoef(y - localmesh->ystart, x - xstart) = xm; + bcoef(y - localmesh->ystart, x - xstart) = c; + ccoef(y - localmesh->ystart, x - xstart) = xp; if( include_y_derivs ) { // YY component @@ -394,97 +394,97 @@ void LaplaceXY::setCoefs(const Field2D &A, const Field2D &B) { } // X boundaries - if(mesh->firstX()) { + if(localmesh->firstX()) { if(x_inner_dirichlet) { // Dirichlet on inner X boundary - for(int y=mesh->ystart;y<=mesh->yend;y++) { - int row = globalIndex(mesh->xstart-1,y); + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { + int row = globalIndex(localmesh->xstart-1,y); PetscScalar val = 0.5; MatSetValues(MatA,1,&row,1,&row,&val,INSERT_VALUES); - int col = globalIndex(mesh->xstart,y); + int col = globalIndex(localmesh->xstart,y); MatSetValues(MatA,1,&row,1,&col,&val,INSERT_VALUES); // Preconditioner - bcoef(y - mesh->ystart, 0) = 0.5; - ccoef(y - mesh->ystart, 0) = 0.5; + bcoef(y - localmesh->ystart, 0) = 0.5; + ccoef(y - localmesh->ystart, 0) = 0.5; } }else { // Neumann on inner X boundary - for(int y=mesh->ystart;y<=mesh->yend;y++) { - int row = globalIndex(mesh->xstart-1,y); + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { + int row = globalIndex(localmesh->xstart-1,y); PetscScalar val = 1.0; MatSetValues(MatA,1,&row,1,&row,&val,INSERT_VALUES); - int col = globalIndex(mesh->xstart,y); + int col = globalIndex(localmesh->xstart,y); val = -1.0; MatSetValues(MatA,1,&row,1,&col,&val,INSERT_VALUES); // Preconditioner - bcoef(y - mesh->ystart, 0) = 1.0; - ccoef(y - mesh->ystart, 0) = -1.0; + bcoef(y - localmesh->ystart, 0) = 1.0; + ccoef(y - localmesh->ystart, 0) = -1.0; } } } - if(mesh->lastX()) { + if(localmesh->lastX()) { // Dirichlet on outer X boundary - for(int y=mesh->ystart;y<=mesh->yend;y++) { - int row = globalIndex(mesh->xend+1,y); + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { + int row = globalIndex(localmesh->xend+1,y); PetscScalar val = 0.5; MatSetValues(MatA,1,&row,1,&row,&val,INSERT_VALUES); - int col = globalIndex(mesh->xend,y); + int col = globalIndex(localmesh->xend,y); MatSetValues(MatA,1,&row,1,&col,&val,INSERT_VALUES); // Preconditioner - acoef(y - mesh->ystart, mesh->xend + 1 - xstart) = 0.5; - bcoef(y - mesh->ystart, mesh->xend + 1 - xstart) = 0.5; + acoef(y - localmesh->ystart, localmesh->xend + 1 - xstart) = 0.5; + bcoef(y - localmesh->ystart, localmesh->xend + 1 - xstart) = 0.5; } } if(y_bndry_dirichlet) { // Dirichlet on Y boundaries - for(RangeIterator it=mesh->iterateBndryLowerY(); !it.isDone(); it++) { - int row = globalIndex(it.ind, mesh->ystart-1); + for(RangeIterator it=localmesh->iterateBndryLowerY(); !it.isDone(); it++) { + int row = globalIndex(it.ind, localmesh->ystart-1); PetscScalar val = 0.5; MatSetValues(MatA,1,&row,1,&row,&val,INSERT_VALUES); - int col = globalIndex(it.ind, mesh->ystart); + int col = globalIndex(it.ind, localmesh->ystart); MatSetValues(MatA,1,&row,1,&col,&val,INSERT_VALUES); } - for(RangeIterator it=mesh->iterateBndryUpperY(); !it.isDone(); it++) { - int row = globalIndex(it.ind, mesh->yend+1); + for(RangeIterator it=localmesh->iterateBndryUpperY(); !it.isDone(); it++) { + int row = globalIndex(it.ind, localmesh->yend+1); PetscScalar val = 0.5; MatSetValues(MatA,1,&row,1,&row,&val,INSERT_VALUES); - int col = globalIndex(it.ind, mesh->yend); + int col = globalIndex(it.ind, localmesh->yend); MatSetValues(MatA,1,&row,1,&col,&val,INSERT_VALUES); } }else { // Neumann on Y boundaries - for(RangeIterator it=mesh->iterateBndryLowerY(); !it.isDone(); it++) { - int row = globalIndex(it.ind, mesh->ystart-1); + for(RangeIterator it=localmesh->iterateBndryLowerY(); !it.isDone(); it++) { + int row = globalIndex(it.ind, localmesh->ystart-1); PetscScalar val = 1.0; MatSetValues(MatA,1,&row,1,&row,&val,INSERT_VALUES); val = -1.0; - int col = globalIndex(it.ind, mesh->ystart); + int col = globalIndex(it.ind, localmesh->ystart); MatSetValues(MatA,1,&row,1,&col,&val,INSERT_VALUES); } - for(RangeIterator it=mesh->iterateBndryUpperY(); !it.isDone(); it++) { - int row = globalIndex(it.ind, mesh->yend+1); + for(RangeIterator it=localmesh->iterateBndryUpperY(); !it.isDone(); it++) { + int row = globalIndex(it.ind, localmesh->yend+1); PetscScalar val = 1.0; MatSetValues(MatA,1,&row,1,&row,&val,INSERT_VALUES); val = -1.0; - int col = globalIndex(it.ind, mesh->yend); + int col = globalIndex(it.ind, localmesh->yend); MatSetValues(MatA,1,&row,1,&col,&val,INSERT_VALUES); } } @@ -526,8 +526,8 @@ const Field2D LaplaceXY::solve(const Field2D &rhs, const Field2D &x0) { // Load initial guess x0 into xs and rhs into bs - for(int x=mesh->xstart;x<= mesh->xend;x++) { - for(int y=mesh->ystart;y<=mesh->yend;y++) { + for(int x=localmesh->xstart;x<= localmesh->xend;x++) { + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { int ind = globalIndex(x,y); PetscScalar val = x0(x,y); @@ -538,80 +538,80 @@ const Field2D LaplaceXY::solve(const Field2D &rhs, const Field2D &x0) { } } - if(mesh->firstX()) { + if(localmesh->firstX()) { if(x_inner_dirichlet) { - for(int y=mesh->ystart;y<=mesh->yend;y++) { - int ind = globalIndex(mesh->xstart-1,y); + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { + int ind = globalIndex(localmesh->xstart-1,y); - PetscScalar val = x0(mesh->xstart-1,y); + PetscScalar val = x0(localmesh->xstart-1,y); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); - val = 0.5*(x0(mesh->xstart-1,y) + x0(mesh->xstart,y)); + val = 0.5*(x0(localmesh->xstart-1,y) + x0(localmesh->xstart,y)); VecSetValues( bs, 1, &ind, &val, INSERT_VALUES ); } }else { // Inner X boundary (Neumann) - for(int y=mesh->ystart;y<=mesh->yend;y++) { - int ind = globalIndex(mesh->xstart-1,y); + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { + int ind = globalIndex(localmesh->xstart-1,y); - PetscScalar val = x0(mesh->xstart-1,y); + PetscScalar val = x0(localmesh->xstart-1,y); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); - val = 0.0; //x0(mesh->xstart-1,y) - x0(mesh->xstart,y); + val = 0.0; //x0(localmesh->xstart-1,y) - x0(localmesh->xstart,y); VecSetValues( bs, 1, &ind, &val, INSERT_VALUES ); } } } // Outer X boundary (Dirichlet) - if(mesh->lastX()) { - for(int y=mesh->ystart;y<=mesh->yend;y++) { - int ind = globalIndex(mesh->xend+1,y); + if(localmesh->lastX()) { + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { + int ind = globalIndex(localmesh->xend+1,y); - PetscScalar val = x0(mesh->xend+1,y); + PetscScalar val = x0(localmesh->xend+1,y); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); - val = 0.5*(x0(mesh->xend,y) + x0(mesh->xend+1,y)); + val = 0.5*(x0(localmesh->xend,y) + x0(localmesh->xend+1,y)); VecSetValues( bs, 1, &ind, &val, INSERT_VALUES ); } } if(y_bndry_dirichlet) { - for(RangeIterator it=mesh->iterateBndryLowerY(); !it.isDone(); it++) { - int ind = globalIndex(it.ind, mesh->ystart-1); + for(RangeIterator it=localmesh->iterateBndryLowerY(); !it.isDone(); it++) { + int ind = globalIndex(it.ind, localmesh->ystart-1); - PetscScalar val = x0(it.ind,mesh->ystart-1); + PetscScalar val = x0(it.ind,localmesh->ystart-1); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); - val = 0.5*(x0(it.ind, mesh->ystart-1) + x0(it.ind, mesh->ystart)); + val = 0.5*(x0(it.ind, localmesh->ystart-1) + x0(it.ind, localmesh->ystart)); VecSetValues( bs, 1, &ind, &val, INSERT_VALUES ); } - for(RangeIterator it=mesh->iterateBndryUpperY(); !it.isDone(); it++) { - int ind = globalIndex(it.ind, mesh->yend+1); + for(RangeIterator it=localmesh->iterateBndryUpperY(); !it.isDone(); it++) { + int ind = globalIndex(it.ind, localmesh->yend+1); - PetscScalar val = x0(it.ind,mesh->yend+1); + PetscScalar val = x0(it.ind,localmesh->yend+1); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); - val = 0.5*(x0(it.ind, mesh->yend+1) + x0(it.ind, mesh->yend)); + val = 0.5*(x0(it.ind, localmesh->yend+1) + x0(it.ind, localmesh->yend)); VecSetValues( bs, 1, &ind, &val, INSERT_VALUES ); } } else { // Y boundaries Neumann - for(RangeIterator it=mesh->iterateBndryLowerY(); !it.isDone(); it++) { - int ind = globalIndex(it.ind, mesh->ystart-1); + for(RangeIterator it=localmesh->iterateBndryLowerY(); !it.isDone(); it++) { + int ind = globalIndex(it.ind, localmesh->ystart-1); - PetscScalar val = x0(it.ind,mesh->ystart-1); + PetscScalar val = x0(it.ind,localmesh->ystart-1); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); val = 0.0; VecSetValues( bs, 1, &ind, &val, INSERT_VALUES ); } - for(RangeIterator it=mesh->iterateBndryUpperY(); !it.isDone(); it++) { - int ind = globalIndex(it.ind, mesh->yend+1); + for(RangeIterator it=localmesh->iterateBndryUpperY(); !it.isDone(); it++) { + int ind = globalIndex(it.ind, localmesh->yend+1); - PetscScalar val = x0(it.ind,mesh->yend+1); + PetscScalar val = x0(it.ind,localmesh->yend+1); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); val = 0.0; @@ -644,8 +644,8 @@ const Field2D LaplaceXY::solve(const Field2D &rhs, const Field2D &x0) { result.allocate(); result.setLocation(location); - for(int x=mesh->xstart;x<= mesh->xend;x++) { - for(int y=mesh->ystart;y<=mesh->yend;y++) { + for(int x=localmesh->xstart;x<= localmesh->xend;x++) { + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { int ind = globalIndex(x,y); PetscScalar val; @@ -655,42 +655,42 @@ const Field2D LaplaceXY::solve(const Field2D &rhs, const Field2D &x0) { } // Inner X boundary - if(mesh->firstX()) { - for(int y=mesh->ystart;y<=mesh->yend;y++) { - int ind = globalIndex(mesh->xstart-1,y); + if(localmesh->firstX()) { + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { + int ind = globalIndex(localmesh->xstart-1,y); PetscScalar val; VecGetValues(xs, 1, &ind, &val ); - for(int x=mesh->xstart-1; x >= 0; x--) + for(int x=localmesh->xstart-1; x >= 0; x--) result(x,y) = val; } } // Outer X boundary - if(mesh->lastX()) { - for(int y=mesh->ystart;y<=mesh->yend;y++) { - int ind = globalIndex(mesh->xend+1,y); + if(localmesh->lastX()) { + for(int y=localmesh->ystart;y<=localmesh->yend;y++) { + int ind = globalIndex(localmesh->xend+1,y); PetscScalar val; VecGetValues(xs, 1, &ind, &val ); - for(int x=mesh->xend+1;x < mesh->LocalNx;x++) + for(int x=localmesh->xend+1;x < localmesh->LocalNx;x++) result(x,y) = val; } } // Lower Y boundary - for(RangeIterator it=mesh->iterateBndryLowerY(); !it.isDone(); it++) { - int ind = globalIndex(it.ind, mesh->ystart-1); + for(RangeIterator it=localmesh->iterateBndryLowerY(); !it.isDone(); it++) { + int ind = globalIndex(it.ind, localmesh->ystart-1); PetscScalar val; VecGetValues(xs, 1, &ind, &val ); - for(int y=mesh->ystart-1;y>=0;y--) + for(int y=localmesh->ystart-1;y>=0;y--) result(it.ind, y) = val; } // Upper Y boundary - for(RangeIterator it=mesh->iterateBndryUpperY(); !it.isDone(); it++) { - int ind = globalIndex(it.ind, mesh->yend+1); + for(RangeIterator it=localmesh->iterateBndryUpperY(); !it.isDone(); it++) { + int ind = globalIndex(it.ind, localmesh->yend+1); PetscScalar val; VecGetValues(xs, 1, &ind, &val ); - for(int y=mesh->yend+1;yLocalNy;y++) + for(int y=localmesh->yend+1;yLocalNy;y++) result(it.ind, y) = val; } @@ -707,9 +707,9 @@ int LaplaceXY::precon(Vec input, Vec result) { // Starting index int ind = -1; - RangeIterator itdwn=mesh->iterateBndryLowerY(); + RangeIterator itdwn=localmesh->iterateBndryLowerY(); if(!itdwn.isDone()) { - ind = globalIndex(itdwn.ind, mesh->ystart-1); + ind = globalIndex(itdwn.ind, localmesh->ystart-1); for(; !itdwn.isDone(); itdwn++) { PetscScalar val; @@ -718,11 +718,11 @@ int LaplaceXY::precon(Vec input, Vec result) { ind++; } } - RangeIterator itup=mesh->iterateBndryUpperY(); + RangeIterator itup=localmesh->iterateBndryUpperY(); if(!itup.isDone()) { if(ind == -1) { // No lower boundary - ind = globalIndex(itup.ind, mesh->yend+1); + ind = globalIndex(itup.ind, localmesh->yend+1); } for(; !itup.isDone(); itup++) { PetscScalar val; @@ -733,16 +733,16 @@ int LaplaceXY::precon(Vec input, Vec result) { } if(ind == -1) { // No Y boundaries - ind = globalIndex(xstart, mesh->ystart); + ind = globalIndex(xstart, localmesh->ystart); } int ind0 = ind; // Load vector x into bvals array for(int x=xstart;x<=xend;x++) { - for(int y=mesh->ystart; y<=mesh->yend;y++) { + for(int y=localmesh->ystart; y<=localmesh->yend;y++) { PetscScalar val; VecGetValues(input, 1, &ind, &val ); - bvals(y - mesh->ystart, x - xstart) = val; + bvals(y - localmesh->ystart, x - xstart) = val; ind++; } } @@ -753,8 +753,8 @@ int LaplaceXY::precon(Vec input, Vec result) { // Save result xvals into y array ind = ind0; for(int x=xstart;x<=xend;x++) { - for(int y=mesh->ystart; y<=mesh->yend;y++) { - PetscScalar val = xvals(y - mesh->ystart, x - xstart); + for(int y=localmesh->ystart; y<=localmesh->yend;y++) { + PetscScalar val = xvals(y - localmesh->ystart, x - xstart); VecSetValues(result, 1, &ind, &val, INSERT_VALUES ); ind++; } @@ -769,22 +769,22 @@ int LaplaceXY::precon(Vec input, Vec result) { int LaplaceXY::localSize() { // Bulk of points - int nx = mesh->xend - mesh->xstart + 1; - int ny = mesh->yend - mesh->ystart + 1; + int nx = localmesh->xend - localmesh->xstart + 1; + int ny = localmesh->yend - localmesh->ystart + 1; int n = nx * ny; // X boundaries - if(mesh->firstX()) + if(localmesh->firstX()) n += ny; - if(mesh->lastX()) + if(localmesh->lastX()) n += ny; // Y boundaries - for(RangeIterator it=mesh->iterateBndryLowerY(); !it.isDone(); it++) { + for(RangeIterator it=localmesh->iterateBndryLowerY(); !it.isDone(); it++) { n++; } - for(RangeIterator it=mesh->iterateBndryUpperY(); !it.isDone(); it++) { + for(RangeIterator it=localmesh->iterateBndryUpperY(); !it.isDone(); it++) { n++; } @@ -792,8 +792,8 @@ int LaplaceXY::localSize() { } int LaplaceXY::globalIndex(int x, int y) { - if( (x < 0) || (x >= mesh->LocalNx) || - (y < 0) || (y >= mesh->LocalNy) ) + if( (x < 0) || (x >= localmesh->LocalNx) || + (y < 0) || (y >= localmesh->LocalNy) ) return -1; // Out of range // Get the index from a Field2D, round to integer diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx index 0b9076de9d..45ac1b1182 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx @@ -8,7 +8,7 @@ #include -LaplaceXZcyclic::LaplaceXZcyclic(Mesh *m, Options *options, const CELL_LOC loc) : LaplaceXZ(m, options, loc), mesh(m) { +LaplaceXZcyclic::LaplaceXZcyclic(Mesh *m, Options *options, const CELL_LOC loc) : LaplaceXZ(m, options, loc), localmesh(m) { // Number of Z Fourier modes, including DC nmode = (m->LocalNz) / 2 + 1; @@ -41,15 +41,15 @@ LaplaceXZcyclic::LaplaceXZcyclic(Mesh *m, Options *options, const CELL_LOC loc) k1d_2 = Array((m->LocalNz) / 2 + 1); // Create a cyclic reduction object, operating on dcomplex values - cr = new CyclicReduce(mesh->getXcomm(), nloc); + cr = new CyclicReduce(localmesh->getXcomm(), nloc); // Getting the boundary flags OPTION(options, inner_boundary_flags, 0); OPTION(options, outer_boundary_flags, 0); // Set default coefficients - Field2D one(1., &mesh); - Field2D zero(0., &mesh); + Field2D one(1., localmesh); + Field2D zero(0., localmesh); one.setLocation(location); zero.setLocation(location); setCoefs(one, zero); @@ -69,17 +69,17 @@ void LaplaceXZcyclic::setCoefs(const Field2D &A2D, const Field2D &B2D) { // Set coefficients - Coordinates *coord = mesh->getCoordinates(location); + Coordinates *coord = localmesh->getCoordinates(location); // NOTE: For now the X-Z terms are omitted, so check that they are small ASSERT2(max(abs(coord->g13)) < 1e-5); int ind = 0; - for(int y=mesh->ystart; y <= mesh->yend; y++) { + for(int y=localmesh->ystart; y <= localmesh->yend; y++) { for(int kz = 0; kz < nmode; kz++) { BoutReal kwave=kz*2.0*PI/(coord->zlength()); - if(mesh->firstX()) { + if(localmesh->firstX()) { // Inner X boundary if( ((kz == 0) && (inner_boundary_flags & INVERT_DC_GRAD)) || @@ -98,7 +98,7 @@ void LaplaceXZcyclic::setCoefs(const Field2D &A2D, const Field2D &B2D) { } // Bulk of the domain - for(int x=mesh->xstart; x <= mesh->xend; x++) { + for(int x=localmesh->xstart; x <= localmesh->xend; x++) { acoef(ind, x - xstart) = 0.0; // X-1 bcoef(ind, x - xstart) = 0.0; // Diagonal ccoef(ind, x - xstart) = 0.0; // X+1 @@ -138,7 +138,7 @@ void LaplaceXZcyclic::setCoefs(const Field2D &A2D, const Field2D &B2D) { } // Outer X boundary - if(mesh->lastX()) { + if(localmesh->lastX()) { // Outer X boundary if( ((kz == 0) && (outer_boundary_flags & INVERT_DC_GRAD)) || ((kz != 0) && (outer_boundary_flags & INVERT_AC_GRAD)) ) { @@ -167,18 +167,18 @@ Field3D LaplaceXZcyclic::solve(const Field3D &rhs, const Field3D &x0) { ASSERT1(rhs.getLocation() == location); ASSERT1(x0.getLocation() == location); - Mesh *mesh = rhs.getMesh(); + Mesh *localmesh = rhs.getMesh(); // Create the rhs array int ind = 0; - for(int y=mesh->ystart; y <= mesh->yend; y++) { + for(int y=localmesh->ystart; y <= localmesh->yend; y++) { - if(mesh->firstX()) { + if(localmesh->firstX()) { // Inner X boundary if(inner_boundary_flags & INVERT_SET) { // Fourier transform x0 in Z at xstart-1 and xstart - rfft(&x0(mesh->xstart - 1, y, 0), mesh->LocalNz, std::begin(k1d)); - rfft(&x0(mesh->xstart, y, 0), mesh->LocalNz, std::begin(k1d_2)); + rfft(&x0(localmesh->xstart - 1, y, 0), localmesh->LocalNz, std::begin(k1d)); + rfft(&x0(localmesh->xstart, y, 0), localmesh->LocalNz, std::begin(k1d_2)); for(int kz = 0; kz < nmode; kz++) { // Use the same coefficients as applied to the solution // so can either set gradient or value @@ -187,8 +187,8 @@ Field3D LaplaceXZcyclic::solve(const Field3D &rhs, const Field3D &x0) { } }else if(inner_boundary_flags & INVERT_RHS) { // Fourier transform rhs in Z at xstart-1 and xstart - rfft(&rhs(mesh->xstart - 1, y, 0), mesh->LocalNz, std::begin(k1d)); - rfft(&rhs(mesh->xstart, y, 0), mesh->LocalNz, std::begin(k1d_2)); + rfft(&rhs(localmesh->xstart - 1, y, 0), localmesh->LocalNz, std::begin(k1d)); + rfft(&rhs(localmesh->xstart, y, 0), localmesh->LocalNz, std::begin(k1d_2)); for(int kz = 0; kz < nmode; kz++) { // Use the same coefficients as applied to the solution // so can either set gradient or value @@ -203,21 +203,21 @@ Field3D LaplaceXZcyclic::solve(const Field3D &rhs, const Field3D &x0) { } // Bulk of the domain - for(int x=mesh->xstart; x <= mesh->xend; x++) { + for(int x=localmesh->xstart; x <= localmesh->xend; x++) { // Fourier transform RHS - rfft(&rhs(x, y, 0), mesh->LocalNz, std::begin(k1d)); + rfft(&rhs(x, y, 0), localmesh->LocalNz, std::begin(k1d)); for(int kz = 0; kz < nmode; kz++) { rhscmplx(ind + kz, x - xstart) = k1d[kz]; } } // Outer X boundary - if(mesh->lastX()) { + if(localmesh->lastX()) { // Outer X boundary if(outer_boundary_flags & INVERT_SET) { // Fourier transform x0 in Z at xend and xend+1 - rfft(&x0(mesh->xend, y, 0), mesh->LocalNz, std::begin(k1d)); - rfft(&x0(mesh->xend + 1, y, 0), mesh->LocalNz, std::begin(k1d_2)); + rfft(&x0(localmesh->xend, y, 0), localmesh->LocalNz, std::begin(k1d)); + rfft(&x0(localmesh->xend + 1, y, 0), localmesh->LocalNz, std::begin(k1d_2)); for(int kz = 0; kz < nmode; kz++) { // Use the same coefficients as applied to the solution // so can either set gradient or value @@ -226,8 +226,8 @@ Field3D LaplaceXZcyclic::solve(const Field3D &rhs, const Field3D &x0) { } }else if(outer_boundary_flags & INVERT_RHS) { // Fourier transform rhs in Z at xstart-1 and xstart - rfft(&rhs(mesh->xend, y, 0), mesh->LocalNz, std::begin(k1d)); - rfft(&rhs(mesh->xend + 1, y, 0), mesh->LocalNz, std::begin(k1d_2)); + rfft(&rhs(localmesh->xend, y, 0), localmesh->LocalNz, std::begin(k1d)); + rfft(&rhs(localmesh->xend + 1, y, 0), localmesh->LocalNz, std::begin(k1d_2)); for(int kz = 0; kz < nmode; kz++) { // Use the same coefficients as applied to the solution // so can either set gradient or value @@ -252,19 +252,19 @@ Field3D LaplaceXZcyclic::solve(const Field3D &rhs, const Field3D &x0) { // FFT back to real space - Field3D result(mesh); + Field3D result(localmesh); result.allocate(); result.setLocation(location); ind = 0; - for(int y=mesh->ystart; y <= mesh->yend; y++) { + for(int y=localmesh->ystart; y <= localmesh->yend; y++) { for(int x=xstart;x<=xend;x++) { for(int kz = 0; kz < nmode; kz++) { k1d[kz] = xcmplx(ind + kz, x - xstart); } // This shifts back to field-aligned coordinates - irfft(std::begin(k1d), mesh->LocalNz, &result(x, y, 0)); + irfft(std::begin(k1d), localmesh->LocalNz, &result(x, y, 0)); } ind += nmode; } diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx index 7e8902a295..06c5279706 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx @@ -2,11 +2,13 @@ #include #include #include +#include #include "utils.hxx" class LaplaceXZcyclic : public LaplaceXZ { public: - LaplaceXZcyclic(Mesh *m, Options *options, const CELL_LOC loc); + LaplaceXZcyclic(Mesh *m = mesh, Options *options = nullptr, + const CELL_LOC loc = CELL_CENTRE); ~LaplaceXZcyclic(); using LaplaceXZ::setCoefs; @@ -15,7 +17,7 @@ public: using LaplaceXZ::solve; Field3D solve(const Field3D &b, const Field3D &x0) override; private: - Mesh *mesh; ///< The mesh this operates on, provides metrics and communication + Mesh *localmesh; ///< The mesh this operates on, provides metrics and communication int xstart, xend; int nmode, nloc, nsys; diff --git a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx index 66234e83b6..cffa4f1365 100644 --- a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx +++ b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx @@ -19,7 +19,7 @@ #include LaplaceXZpetsc::LaplaceXZpetsc(Mesh *m, Options *opt, const CELL_LOC loc) - : LaplaceXZ(m, opt, loc), mesh(m), coefs_set(false) { + : LaplaceXZ(m, opt, loc), localmesh(m), coefs_set(false) { /* Constructor: LaplaceXZpetsc * Purpose: - Setting inversion solver options * - Setting the solver method @@ -112,8 +112,8 @@ LaplaceXZpetsc::LaplaceXZpetsc(Mesh *m, Options *opt, const CELL_LOC loc) if ( outer_boundary_flags & ~implemented_boundary_flags ) { throw BoutException("Attempted to set LaplaceXZ inversion boundary flag that is not implemented in petsc_laplace.cxx"); } - if(mesh->periodicX) { - throw BoutException("LaplacePetsc does not work with periodicity in the x direction (mesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); + if(localmesh->periodicX) { + throw BoutException("LaplacePetsc does not work with periodicity in the x direction (localmesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); } #endif @@ -141,15 +141,15 @@ LaplaceXZpetsc::LaplaceXZpetsc(Mesh *m, Options *opt, const CELL_LOC loc) opt->get("factor_package", factor_package, "petsc", true); // Get MPI communicator - MPI_Comm comm = mesh->getXcomm(); + MPI_Comm comm = localmesh->getXcomm(); // Local size - int localN = (mesh->xend - mesh->xstart + 1) * (mesh->LocalNz); - if(mesh->firstX()) { - localN += mesh->LocalNz; + int localN = (localmesh->xend - localmesh->xstart + 1) * (localmesh->LocalNz); + if(localmesh->firstX()) { + localN += localmesh->LocalNz; } - if(mesh->lastX()) { - localN += mesh->LocalNz; + if(localmesh->lastX()) { + localN += localmesh->LocalNz; } // Create Vectors @@ -158,7 +158,7 @@ LaplaceXZpetsc::LaplaceXZpetsc(Mesh *m, Options *opt, const CELL_LOC loc) VecSetFromOptions( xs ); VecDuplicate( xs , &bs ); - for(int y = mesh->ystart; y <= mesh->yend; y++) { + for(int y = localmesh->ystart; y <= localmesh->yend; y++) { YSlice data; data.yindex = y; @@ -183,27 +183,27 @@ LaplaceXZpetsc::LaplaceXZpetsc(Mesh *m, Options *opt, const CELL_LOC loc) } // X boundaries - if(mesh->firstX()) { - for(int z=0;zLocalNz;z++) { + if(localmesh->firstX()) { + for(int z=0;zLocalNz;z++) { d_nnz[z] = 2; } }else { // One point on another processor - for(int z=0;zLocalNz;z++) { + for(int z=0;zLocalNz;z++) { d_nnz[z] -= 1; o_nnz[z] += 1; } } - if(mesh->lastX()) { - for(int z=0;zLocalNz;z++) { - int ind = localN - (mesh->LocalNz) + z; + if(localmesh->lastX()) { + for(int z=0;zLocalNz;z++) { + int ind = localN - (localmesh->LocalNz) + z; d_nnz[ind] = 2; } }else { // One point on another processor - for(int z=0;zLocalNz;z++) { - int ind = localN - (mesh->LocalNz) + z; + for(int z=0;zLocalNz;z++) { + int ind = localN - (localmesh->LocalNz) + z; d_nnz[ind] -= 1; o_nnz[ind] += 1; } @@ -306,17 +306,17 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { //////////////////////////////////////////////// // Inner X boundary (see note about BC in LaplaceXZ constructor) int row = Istart; - if(mesh->firstX()) { + if(localmesh->firstX()) { if (inner_boundary_flags & INVERT_AC_GRAD){ // Neumann 0 /* NOTE: Sign of the elements are opposite of what one might expect, * see note about BC in LaplaceXZ constructor for more details */ - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { PetscScalar val = 1.0; MatSetValues(it.MatA, 1, &row, 1, &row, &val, INSERT_VALUES); - int col = row + (mesh->LocalNz); // +1 in X + int col = row + (localmesh->LocalNz); // +1 in X val = -1.0; MatSetValues(it.MatA, 1, &row, 1, &col, &val, INSERT_VALUES); @@ -325,11 +325,11 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { } else if(inner_boundary_flags & INVERT_SET){ // Setting BC from x0 - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { PetscScalar val = 1.0; MatSetValues(it.MatA, 1, &row, 1, &row, &val, INSERT_VALUES); - int col = row + (mesh->LocalNz); // +1 in X + int col = row + (localmesh->LocalNz); // +1 in X val = 0.0; MatSetValues(it.MatA, 1, &row, 1, &col, &val, INSERT_VALUES); @@ -338,11 +338,11 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { } else if(inner_boundary_flags & INVERT_RHS){ // Setting BC from b - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { PetscScalar val = 1.0; MatSetValues(it.MatA, 1, &row, 1, &row, &val, INSERT_VALUES); - int col = row + (mesh->LocalNz); // +1 in X + int col = row + (localmesh->LocalNz); // +1 in X val = 0.0; MatSetValues(it.MatA, 1, &row, 1, &col, &val, INSERT_VALUES); @@ -354,11 +354,11 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { /* NOTE: Sign of the elements are opposite of what one might expect, * see note about BC in LaplaceXZ constructor for more details */ - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { PetscScalar val = 0.5; MatSetValues(it.MatA, 1, &row, 1, &row, &val, INSERT_VALUES); - int col = row + (mesh->LocalNz); // +1 in X + int col = row + (localmesh->LocalNz); // +1 in X MatSetValues(it.MatA, 1, &row, 1, &col, &val, INSERT_VALUES); row++; @@ -371,13 +371,13 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { // // (1/J) d/dx ( A * J * g11 d/dx ) + (1/J) d/dz ( A * J * g33 d/dz ) + B - Coordinates *coords = mesh->getCoordinates(location); + Coordinates *coords = localmesh->getCoordinates(location); // NOTE: For now the X-Z terms are omitted, so check that they are small ASSERT2(max(abs(coords->g13)) < 1e-5); - for(int x=mesh->xstart; x <= mesh->xend; x++) { - for(int z=0; z < mesh->LocalNz; z++) { + for(int x=localmesh->xstart; x <= localmesh->xend; x++) { + for(int z=0; z < localmesh->LocalNz; z++) { // stencil entries PetscScalar c, xm, xp, zm, zp; @@ -407,8 +407,8 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { // Note that because metrics are constant in Z many terms cancel // Wrap around z-1 and z+1 indices - int zminus = (z - 1 + (mesh->LocalNz)) % (mesh->LocalNz); - int zplus = (z + 1) % (mesh->LocalNz); + int zminus = (z - 1 + (localmesh->LocalNz)) % (localmesh->LocalNz); + int zplus = (z + 1) % (localmesh->LocalNz); // Metrics on z+1/2 boundary Acoef = 0.5*(A(x,y,z) + A(x,y,zplus)); @@ -434,24 +434,24 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { MatSetValues(it.MatA, 1, &row, 1, &row, &c, INSERT_VALUES); // X + 1 - int col = row + (mesh->LocalNz); + int col = row + (localmesh->LocalNz); MatSetValues(it.MatA, 1, &row, 1, &col, &xp, INSERT_VALUES); // X - 1 - col = row - (mesh->LocalNz); + col = row - (localmesh->LocalNz); MatSetValues(it.MatA, 1, &row, 1, &col, &xm, INSERT_VALUES); // Z + 1 col = row + 1; - if(z == mesh->LocalNz-1) { - col -= mesh->LocalNz; // Wrap around + if(z == localmesh->LocalNz-1) { + col -= localmesh->LocalNz; // Wrap around } MatSetValues(it.MatA, 1, &row, 1, &col, &zp, INSERT_VALUES); // Z - 1 col = row - 1; if(z == 0) { - col += mesh->LocalNz; // Wrap around + col += localmesh->LocalNz; // Wrap around } MatSetValues(it.MatA, 1, &row, 1, &col, &zm, INSERT_VALUES); @@ -461,14 +461,14 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { //////////////////////////////////////////////// // Outer X boundary (see note about BC in LaplaceXZ constructor) - if(mesh->lastX()) { + if(localmesh->lastX()) { if (outer_boundary_flags & INVERT_AC_GRAD){ // Neumann 0 - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { PetscScalar val = 1.0; MatSetValues(it.MatA, 1, &row, 1, &row, &val, INSERT_VALUES); - int col = row - (mesh->LocalNz); // -1 in X + int col = row - (localmesh->LocalNz); // -1 in X val = -1.0; MatSetValues(it.MatA, 1, &row, 1, &col, &val, INSERT_VALUES); @@ -477,11 +477,11 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { } else if (outer_boundary_flags & INVERT_SET){ // Setting BC from x0 - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { PetscScalar val = 1.0; MatSetValues(it.MatA, 1, &row, 1, &row, &val, INSERT_VALUES); - int col = row - (mesh->LocalNz); // -1 in X + int col = row - (localmesh->LocalNz); // -1 in X val = 0.0; MatSetValues(it.MatA, 1, &row, 1, &col, &val, INSERT_VALUES); @@ -490,11 +490,11 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { } else if (outer_boundary_flags & INVERT_RHS){ // Setting BC from b - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { PetscScalar val = 1.0; MatSetValues(it.MatA, 1, &row, 1, &row, &val, INSERT_VALUES); - int col = row - (mesh->LocalNz); // -1 in X + int col = row - (localmesh->LocalNz); // -1 in X val = 0.0; MatSetValues(it.MatA, 1, &row, 1, &col, &val, INSERT_VALUES); @@ -505,10 +505,10 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { //Default: Dirichlet on outer X boundary PetscScalar val = 0.5; - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { MatSetValues(it.MatA, 1, &row, 1, &row, &val, INSERT_VALUES); - int col = row - (mesh->LocalNz); // -1 in X + int col = row - (localmesh->LocalNz); // -1 in X MatSetValues(it.MatA, 1, &row, 1, &col, &val, INSERT_VALUES); row++; @@ -613,12 +613,12 @@ Field3D LaplaceXZpetsc::solve(const Field3D &bin, const Field3D &x0in) { int ind = Istart; // Inner X boundary (see note about BC in LaplaceXZ constructor) - if(mesh->firstX()) { + if(localmesh->firstX()) { if (inner_boundary_flags & INVERT_AC_GRAD){ // Neumann 0 - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { // Setting the initial guess x0 - PetscScalar val = x0(mesh->xstart-1,y,z); + PetscScalar val = x0(localmesh->xstart-1,y,z); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); // Setting the solution b @@ -629,39 +629,39 @@ Field3D LaplaceXZpetsc::solve(const Field3D &bin, const Field3D &x0in) { } else if (inner_boundary_flags & INVERT_SET){ // Setting BC from x0 - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { // Setting the initial guess x0 - PetscScalar val = x0(mesh->xstart-1,y,z); + PetscScalar val = x0(localmesh->xstart-1,y,z); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); // Setting the solution b - val = x0(mesh->xstart,y,z); + val = x0(localmesh->xstart,y,z); VecSetValues( bs, 1, &ind, &val, INSERT_VALUES ); ind++; } } else if (inner_boundary_flags & INVERT_RHS){ // Setting BC from b - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { // Setting the initial guess x0 - PetscScalar val = x0(mesh->xstart-1,y,z); + PetscScalar val = x0(localmesh->xstart-1,y,z); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); // Setting the solution b - val = b(mesh->xstart,y,z); + val = b(localmesh->xstart,y,z); VecSetValues( bs, 1, &ind, &val, INSERT_VALUES ); ind++; } } else{ // Default: Neumann on inner x boundary - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { // Setting the initial guess x0 - PetscScalar val = x0(mesh->xstart-1,y,z); + PetscScalar val = x0(localmesh->xstart-1,y,z); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); // Setting the solution b - val = x0(mesh->xstart-1,y,z) - x0(mesh->xstart,y,z); + val = x0(localmesh->xstart-1,y,z) - x0(localmesh->xstart,y,z); VecSetValues( bs, 1, &ind, &val, INSERT_VALUES ); ind++; } @@ -669,8 +669,8 @@ Field3D LaplaceXZpetsc::solve(const Field3D &bin, const Field3D &x0in) { } // Set the inner points - for(int x=mesh->xstart;x<= mesh->xend;x++) { - for(int z=0; z < mesh->LocalNz; z++) { + for(int x=localmesh->xstart;x<= localmesh->xend;x++) { + for(int z=0; z < localmesh->LocalNz; z++) { PetscScalar val = x0(x,y,z); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); @@ -681,12 +681,12 @@ Field3D LaplaceXZpetsc::solve(const Field3D &bin, const Field3D &x0in) { } // Outer X boundary (see note about BC in LaplaceXZ constructor) - if(mesh->lastX()) { + if(localmesh->lastX()) { if (outer_boundary_flags & INVERT_AC_GRAD){ // Neumann 0 - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { // Setting the initial guess x0 - PetscScalar val = x0(mesh->xend+1,y,z); + PetscScalar val = x0(localmesh->xend+1,y,z); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); // Setting the solution b @@ -698,13 +698,13 @@ Field3D LaplaceXZpetsc::solve(const Field3D &bin, const Field3D &x0in) { } else if (outer_boundary_flags & INVERT_SET){ // Setting BC from x0 - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { // Setting the initial guess x0 - PetscScalar val = x0(mesh->xend+1,y,z); + PetscScalar val = x0(localmesh->xend+1,y,z); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); // Setting the solution b - val = x0(mesh->xend+1,y,z); + val = x0(localmesh->xend+1,y,z); VecSetValues( bs, 1, &ind, &val, INSERT_VALUES ); ind++; @@ -712,13 +712,13 @@ Field3D LaplaceXZpetsc::solve(const Field3D &bin, const Field3D &x0in) { } else if (outer_boundary_flags & INVERT_RHS){ // Setting BC from b - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { // Setting the initial guess x0 - PetscScalar val = x0(mesh->xend+1,y,z); + PetscScalar val = x0(localmesh->xend+1,y,z); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); // Setting the solution b - val = b(mesh->xend+1,y,z); + val = b(localmesh->xend+1,y,z); VecSetValues( bs, 1, &ind, &val, INSERT_VALUES ); ind++; @@ -726,13 +726,13 @@ Field3D LaplaceXZpetsc::solve(const Field3D &bin, const Field3D &x0in) { } else{ //Default: Dirichlet on outer X boundary - for(int z=0; z < mesh->LocalNz; z++) { + for(int z=0; z < localmesh->LocalNz; z++) { // Setting the initial guess x0 - PetscScalar val = x0(mesh->xend+1,y,z); + PetscScalar val = x0(localmesh->xend+1,y,z); VecSetValues( xs, 1, &ind, &val, INSERT_VALUES ); // Setting the solution b - val = 0.5*(x0(mesh->xend,y,z) + x0(mesh->xend+1,y,z)); + val = 0.5*(x0(localmesh->xend,y,z) + x0(localmesh->xend+1,y,z)); VecSetValues( bs, 1, &ind, &val, INSERT_VALUES ); ind++; @@ -768,17 +768,17 @@ Field3D LaplaceXZpetsc::solve(const Field3D &bin, const Field3D &x0in) { ind = Istart; // Inner X boundary - if(mesh->firstX()) { - for(int z=0; z < mesh->LocalNz; z++) { + if(localmesh->firstX()) { + for(int z=0; z < localmesh->LocalNz; z++) { PetscScalar val; VecGetValues(xs, 1, &ind, &val ); - result(mesh->xstart-1,y,z) = val; + result(localmesh->xstart-1,y,z) = val; ind++; } } - for(int x=mesh->xstart;x<= mesh->xend;x++) { - for(int z=0; z < mesh->LocalNz; z++) { + for(int x=localmesh->xstart;x<= localmesh->xend;x++) { + for(int z=0; z < localmesh->LocalNz; z++) { PetscScalar val; VecGetValues(xs, 1, &ind, &val ); result(x,y,z) = val; @@ -787,11 +787,11 @@ Field3D LaplaceXZpetsc::solve(const Field3D &bin, const Field3D &x0in) { } // Outer X boundary - if(mesh->lastX()) { - for(int z=0; z < mesh->LocalNz; z++) { + if(localmesh->lastX()) { + for(int z=0; z < localmesh->LocalNz; z++) { PetscScalar val; VecGetValues(xs, 1, &ind, &val ); - result(mesh->xend+1,y,z) = val; + result(localmesh->xend+1,y,z) = val; ind++; } } diff --git a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.hxx b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.hxx index 6c40e2bac6..6f036e8455 100644 --- a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.hxx +++ b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.hxx @@ -16,7 +16,8 @@ class LaplaceXZpetsc; #include class LaplaceXZpetsc : public LaplaceXZ { public: - LaplaceXZpetsc(Mesh *m, Options *options, const CELL_LOC loc) : LaplaceXZ(m, options, loc) { + LaplaceXZpetsc(Mesh *m = mesh, Options *options = nullptr, + const CELL_LOC loc = CELL_CENTRE) : LaplaceXZ(m, options, loc) { throw BoutException("No PETSc LaplaceXZ solver available"); } @@ -39,7 +40,7 @@ public: /*! * Constructor */ - LaplaceXZpetsc(Mesh *m, Options *options, const CELL_LOC loc); + LaplaceXZpetsc(Mesh *m = mesh, Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE); /*! * Destructor @@ -75,7 +76,7 @@ private: Vec xs, bs; ///< Solution and RHS vectors - Mesh *mesh; ///< The mesh this operates on, provides metrics and communication + Mesh *localmesh; ///< The mesh this operates on, provides metrics and communication int reuse_limit; ///< How many times can the preconditioner be reused? int reuse_count; ///< How many times has it been reused? From 8282c3576ee3d8e9c906494c5315242133f4b327 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 16:47:23 +0000 Subject: [PATCH 0497/1783] Store Mesh* in base LaplaceXZ; pass nullptr as default Mesh* argument Protected Mesh* localmesh member of base LaplaceXZ class, instead of having localmesh members of both implementations. Pass nullptr instead of global mesh pointer as default argument to LaplaceXY and LaplaceXZ constructors and create() method. Handle localmesh==nullptr by seting localmesh=mesh in the constructor bodies. Allows changing of this handling in future without changing the interface. --- include/bout/invert/laplacexy.hxx | 4 ++-- include/bout/invert/laplacexz.hxx | 13 ++++++++++--- src/invert/laplacexy/laplacexy.cxx | 5 +++++ .../laplacexz/impls/cyclic/laplacexz-cyclic.cxx | 2 +- .../laplacexz/impls/cyclic/laplacexz-cyclic.hxx | 4 +--- .../laplacexz/impls/petsc/laplacexz-petsc.cxx | 2 +- .../laplacexz/impls/petsc/laplacexz-petsc.hxx | 6 ++---- src/invert/laplacexz/laplacexz.cxx | 8 +++++++- 8 files changed, 29 insertions(+), 15 deletions(-) diff --git a/include/bout/invert/laplacexy.hxx b/include/bout/invert/laplacexy.hxx index f78aab93c8..6369683724 100644 --- a/include/bout/invert/laplacexy.hxx +++ b/include/bout/invert/laplacexy.hxx @@ -49,7 +49,7 @@ */ class LaplaceXY { public: - LaplaceXY(Mesh *m = mesh, Options *opt = nullptr, const CELL_LOC = CELL_CENTRE) { + LaplaceXY(Mesh *m = nullptr, Options *opt = nullptr, const CELL_LOC = CELL_CENTRE) { throw BoutException("LaplaceXY requires PETSc. No LaplaceXY available"); } void setCoefs(const Field2D &A, const Field2D &B) {} @@ -68,7 +68,7 @@ public: /*! * Constructor */ - LaplaceXY(Mesh *m = mesh, Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); + LaplaceXY(Mesh *m = nullptr, Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); /*! * Destructor */ diff --git a/include/bout/invert/laplacexz.hxx b/include/bout/invert/laplacexz.hxx index 319b0f44bb..025e06a113 100644 --- a/include/bout/invert/laplacexz.hxx +++ b/include/bout/invert/laplacexz.hxx @@ -38,8 +38,14 @@ class LaplaceXZ { public: - LaplaceXZ(Mesh* UNUSED(m), Options* UNUSED(options), const CELL_LOC loc = CELL_CENTRE) - : location(loc) {} + LaplaceXZ(Mesh* m = nullptr, Options* UNUSED(options) = nullptr, + const CELL_LOC loc = CELL_CENTRE) + : localmesh(m), location(loc) { + if (localmesh == nullptr) { + // use global mesh + localmesh = mesh; + } + } virtual ~LaplaceXZ() {} virtual void setCoefs(const Field2D &A, const Field2D &B) = 0; @@ -47,13 +53,14 @@ public: virtual Field3D solve(const Field3D &b, const Field3D &x0) = 0; - static LaplaceXZ *create(Mesh *m = mesh, Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); + static LaplaceXZ *create(Mesh *m = nullptr, Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE); protected: static const int INVERT_DC_GRAD = 1; static const int INVERT_AC_GRAD = 2; // Use zero neumann (NOTE: AC is a misnomer) static const int INVERT_SET = 16; // Set boundary to x0 value static const int INVERT_RHS = 32; // Set boundary to b value + Mesh* localmesh; ///< The mesh this operates on, provides metrics and communication CELL_LOC location; private: diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index 55ad3a84e0..f6c8507eb1 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -28,6 +28,11 @@ static PetscErrorCode laplacePCapply(PC pc,Vec x,Vec y) { LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : localmesh(m), location(loc) { Timer timer("invert"); + if (localmesh == nullptr) { + // Use global mesh + localmesh = mesh; + } + if (opt == nullptr) { // If no options supplied, use default opt = Options::getRoot()->getSection("laplacexy"); diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx index 45ac1b1182..85f58b212b 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx @@ -8,7 +8,7 @@ #include -LaplaceXZcyclic::LaplaceXZcyclic(Mesh *m, Options *options, const CELL_LOC loc) : LaplaceXZ(m, options, loc), localmesh(m) { +LaplaceXZcyclic::LaplaceXZcyclic(Mesh *m, Options *options, const CELL_LOC loc) : LaplaceXZ(m, options, loc) { // Number of Z Fourier modes, including DC nmode = (m->LocalNz) / 2 + 1; diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx index 06c5279706..93c0a22665 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx @@ -7,7 +7,7 @@ class LaplaceXZcyclic : public LaplaceXZ { public: - LaplaceXZcyclic(Mesh *m = mesh, Options *options = nullptr, + LaplaceXZcyclic(Mesh *m = nullptr, Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE); ~LaplaceXZcyclic(); @@ -17,8 +17,6 @@ public: using LaplaceXZ::solve; Field3D solve(const Field3D &b, const Field3D &x0) override; private: - Mesh *localmesh; ///< The mesh this operates on, provides metrics and communication - int xstart, xend; int nmode, nloc, nsys; Matrix acoef, bcoef, ccoef, xcmplx, rhscmplx; diff --git a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx index cffa4f1365..acaa125670 100644 --- a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx +++ b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx @@ -19,7 +19,7 @@ #include LaplaceXZpetsc::LaplaceXZpetsc(Mesh *m, Options *opt, const CELL_LOC loc) - : LaplaceXZ(m, opt, loc), localmesh(m), coefs_set(false) { + : LaplaceXZ(m, opt, loc), coefs_set(false) { /* Constructor: LaplaceXZpetsc * Purpose: - Setting inversion solver options * - Setting the solver method diff --git a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.hxx b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.hxx index 6f036e8455..b99d2a00bf 100644 --- a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.hxx +++ b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.hxx @@ -16,7 +16,7 @@ class LaplaceXZpetsc; #include class LaplaceXZpetsc : public LaplaceXZ { public: - LaplaceXZpetsc(Mesh *m = mesh, Options *options = nullptr, + LaplaceXZpetsc(Mesh *m = nullptr, Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE) : LaplaceXZ(m, options, loc) { throw BoutException("No PETSc LaplaceXZ solver available"); } @@ -40,7 +40,7 @@ public: /*! * Constructor */ - LaplaceXZpetsc(Mesh *m = mesh, Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE); + LaplaceXZpetsc(Mesh *m = nullptr, Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE); /*! * Destructor @@ -76,8 +76,6 @@ private: Vec xs, bs; ///< Solution and RHS vectors - Mesh *localmesh; ///< The mesh this operates on, provides metrics and communication - int reuse_limit; ///< How many times can the preconditioner be reused? int reuse_count; ///< How many times has it been reused? diff --git a/src/invert/laplacexz/laplacexz.cxx b/src/invert/laplacexz/laplacexz.cxx index b3a066105c..1703c0b076 100644 --- a/src/invert/laplacexz/laplacexz.cxx +++ b/src/invert/laplacexz/laplacexz.cxx @@ -7,8 +7,14 @@ #include LaplaceXZ* LaplaceXZ::create(Mesh *m, Options *options, const CELL_LOC loc) { - if (options == nullptr) + if (m == nullptr) { + // use global mesh + m = mesh; + } + + if (options == nullptr) { options = Options::getRoot()->getSection("laplacexz"); + } std::string type; options->get("type", type, "cyclic"); From ccf830eda21065a2b855fb70a8539808632f0012 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 16:49:59 +0000 Subject: [PATCH 0498/1783] Add checks of mesh pointers in LaplaceXY/LaplaceXZ methods --- src/invert/laplacexy/laplacexy.cxx | 4 ++++ src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx | 4 ++++ src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index f6c8507eb1..85845283e7 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -298,6 +298,8 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : localmesh(m), void LaplaceXY::setCoefs(const Field2D &A, const Field2D &B) { Timer timer("invert"); + ASSERT1(A.getMesh() == localmesh); + ASSERT1(B.getMesh() == localmesh); ASSERT1(A.getLocation() == location); ASSERT1(B.getLocation() == location); @@ -526,6 +528,8 @@ LaplaceXY::~LaplaceXY() { const Field2D LaplaceXY::solve(const Field2D &rhs, const Field2D &x0) { Timer timer("invert"); + ASSERT1(rhs.getMesh() == localmesh); + ASSERT1(x0.getMesh() == localmesh); ASSERT1(rhs.getLocation() == location); ASSERT1(x0.getLocation() == location); diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx index 85f58b212b..eaf3f3fd98 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx @@ -64,6 +64,8 @@ void LaplaceXZcyclic::setCoefs(const Field2D &A2D, const Field2D &B2D) { TRACE("LaplaceXZcyclic::setCoefs"); Timer timer("invert"); + ASSERT1(A2D.getMesh() == localmesh); + ASSERT1(B2D.getMesh() == localmesh); ASSERT1(A2D.getLocation() == location); ASSERT1(B2D.getLocation() == location); @@ -164,6 +166,8 @@ void LaplaceXZcyclic::setCoefs(const Field2D &A2D, const Field2D &B2D) { Field3D LaplaceXZcyclic::solve(const Field3D &rhs, const Field3D &x0) { Timer timer("invert"); + ASSERT1(rhs.getMesh() == localmesh); + ASSERT1(x0.getMesh() == localmesh); ASSERT1(rhs.getLocation() == location); ASSERT1(x0.getLocation() == location); diff --git a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx index acaa125670..8b94d4fe03 100644 --- a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx +++ b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx @@ -276,6 +276,8 @@ void LaplaceXZpetsc::setCoefs(const Field3D &Ain, const Field3D &Bin) { TRACE("LaplaceXZpetsc::setCoefs"); + ASSERT1(Ain.getMesh() == localmesh); + ASSERT1(Bin.getMesh() == localmesh); ASSERT1(Ain.getLocation() == location); ASSERT1(Bin.getLocation() == location); @@ -581,6 +583,8 @@ Field3D LaplaceXZpetsc::solve(const Field3D &bin, const Field3D &x0in) { TRACE("LaplaceXZpetsc::solve"); + ASSERT1(bin.getMesh() == localmesh); + ASSERT1(x0in.getMesh() == localmesh); ASSERT1(bin.getLocation() == location); ASSERT1(x0in.getLocation() == location); From 9cd07463230014c691051bc39806ad92e87d4031 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 16:53:20 +0000 Subject: [PATCH 0499/1783] Don't shadow localmesh member --- src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx index eaf3f3fd98..662f75112f 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx @@ -171,7 +171,6 @@ Field3D LaplaceXZcyclic::solve(const Field3D &rhs, const Field3D &x0) { ASSERT1(rhs.getLocation() == location); ASSERT1(x0.getLocation() == location); - Mesh *localmesh = rhs.getMesh(); // Create the rhs array int ind = 0; for(int y=localmesh->ystart; y <= localmesh->yend; y++) { From d44f3ff75593e995e90d32e1e676d94c660b0a1e Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 18 Dec 2018 23:58:43 +0000 Subject: [PATCH 0500/1783] Add Options<->NetCDF bool support Unfortunately NetCDF does not support boolean atoms, so writing booleans to file as integers. Could also write as strings "true"/"false" if that turned out to be better. --- include/options_netcdf.hxx | 4 +-- src/sys/options/options_netcdf.cxx | 46 ++++++++++++------------------ 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/include/options_netcdf.hxx b/include/options_netcdf.hxx index 77b1e81893..70735e7a86 100644 --- a/include/options_netcdf.hxx +++ b/include/options_netcdf.hxx @@ -17,12 +17,12 @@ public: /// Read options from file Options read() { - throw BoutException("OptionNetCDF not available\n"); + throw BoutException("OptionsNetCDF not available\n"); } /// Write options to file void write(const Options &options) { - throw BoutException("OptionNetCDF not available\n"); + throw BoutException("OptionsNetCDF not available\n"); } }; diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index b58a0aad25..2354b04604 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -42,6 +42,7 @@ void readGroup(const std::string &filename, NcGroup group, Options& result) { result[var_name] = std::string(value); result[var_name].attributes["source"] = filename; } + // Note: NetCDF does not support boolean atoms // else ignore } } @@ -77,10 +78,15 @@ namespace { struct NcTypeVisitor { template NcType operator()(const T& UNUSED(t)) { - return {}; // Null object by defaul + return {}; // Null object by default } }; +template <> +NcType NcTypeVisitor::operator()(const bool& UNUSED(t)) { + return ncInt; +} + template <> NcType NcTypeVisitor::operator()(const int& UNUSED(t)) { return ncInt; @@ -173,24 +179,20 @@ std::vector NcDimVisitor::operator()(const Field3D& value) { struct NcPutVarVisitor { NcPutVarVisitor(NcVar& var) : var(var) {} template - void operator()(const T& UNUSED(t)) {} + void operator()(const T& value) { + var.putVar(&value); + } private: NcVar& var; }; template <> -void NcPutVarVisitor::operator()(const int& value) { - var.putVar(&value); -} -template <> -void NcPutVarVisitor::operator()(const double& value) { - var.putVar(&value); -} -template <> -void NcPutVarVisitor::operator()(const float& value) { - var.putVar(&value); +void NcPutVarVisitor::operator()(const bool& value) { + int int_val = value ? 1 : 0; + var.putVar(&int_val); } + template <> void NcPutVarVisitor::operator()(const std::string& value) { const char* cstr = value.c_str(); @@ -207,13 +209,14 @@ void NcPutVarVisitor::operator()(const Field3D& value) { var.putVar(&value(0,0,0)); } - /// Visit a variant type, and put the data into a NcVar struct NcPutVarCountVisitor { NcPutVarCountVisitor(NcVar& var, const std::vector &start, const std::vector &count) : var(var), start(start), count(count) {} template - void operator()(const T& UNUSED(t)) {} + void operator()(const T& value) { + var.putVar(start, &value); + } private: NcVar& var; @@ -221,18 +224,6 @@ struct NcPutVarCountVisitor { const std::vector &count; ///< Index count in each dimension }; -template <> -void NcPutVarCountVisitor::operator()(const int& value) { - var.putVar(start, &value); -} -template <> -void NcPutVarCountVisitor::operator()(const double& value) { - var.putVar(start, &value); -} -template <> -void NcPutVarCountVisitor::operator()(const float& value) { - var.putVar(start, &value); -} template <> void NcPutVarCountVisitor::operator()(const std::string& value) { const char* cstr = value.c_str(); @@ -248,9 +239,8 @@ void NcPutVarCountVisitor::operator()(const Field3D& value) { // Pointer to data. Assumed to be contiguous array var.putVar(start, count, &value(0,0,0)); } - - void writeGroup(const Options& options, NcGroup group, std::map &time_index) { +void writeGroup(const Options& options, NcGroup group, std::map &time_index) { for (const auto& childpair : options.getChildren()) { const auto& name = childpair.first; From 059e56aa67bc94562a27fd0d66578df583c447a3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 10:02:48 +0000 Subject: [PATCH 0501/1783] Use non-Fourier Delp2 in test-multigrid_laplace Replaces custom this_Grad_perp2 operator defined just for this test. --- .../test_multigrid_laplace.cxx | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx b/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx index 748a85ae7e..bc532c7e12 100644 --- a/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx +++ b/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx @@ -33,7 +33,6 @@ #include BoutReal max_error_at_ystart(const Field3D &error); -Field3D this_Grad_perp2(const Field3D &f); Field3D this_Grad_perp_dot_Grad_perp(const Field3D &f, const Field3D &g); int main(int argc, char** argv) { @@ -58,7 +57,7 @@ int main(int argc, char** argv) { c1 = FieldFactory::get()->create3D("c1:function", Options::getRoot(), mesh); a1 = FieldFactory::get()->create3D("a1:function", Options::getRoot(), mesh); - b1 = d1*this_Grad_perp2(f1) + this_Grad_perp_dot_Grad_perp(c1,f1)/c1 + a1*f1; + b1 = d1*Delp2(f1, CELL_DEFAULT, false) + this_Grad_perp_dot_Grad_perp(c1,f1)/c1 + a1*f1; sol1 = 0.; invert->setInnerBoundaryFlags(0); @@ -71,7 +70,7 @@ int main(int argc, char** argv) { sol1 = invert->solve(sliceXZ(b1, mesh->ystart)); mesh->communicate(sol1); checkData(sol1); - bcheck1 = d1*this_Grad_perp2(sol1) + this_Grad_perp_dot_Grad_perp(c1,sol1)/c1 + a1*sol1; + bcheck1 = d1*Delp2(sol1, CELL_DEFAULT, false) + this_Grad_perp_dot_Grad_perp(c1,sol1)/c1 + a1*sol1; absolute_error1 = f1-sol1; max_error1 = max_error_at_ystart(abs(absolute_error1, RGN_NOBNDRY)); } catch (BoutException &err) { @@ -83,7 +82,7 @@ int main(int argc, char** argv) { absolute_error1 = -1.; } - d1 = this_Grad_perp2(f1); + d1 = Delp2(f1, CELL_DEFAULT, false); c1 = this_Grad_perp_dot_Grad_perp(c1,f1)/c1; a1 = a1*f1; @@ -110,7 +109,7 @@ int main(int argc, char** argv) { c2 = FieldFactory::get()->create3D("c2:function", Options::getRoot(), mesh); a2 = FieldFactory::get()->create3D("a2:function", Options::getRoot(), mesh); - b2 = d2*this_Grad_perp2(f2) + this_Grad_perp_dot_Grad_perp(c2,f2)/c2 + a2*f2; + b2 = d2*Delp2(f2, CELL_DEFAULT, false) + this_Grad_perp_dot_Grad_perp(c2,f2)/c2 + a2*f2; sol2 = 0.; invert->setInnerBoundaryFlags(INVERT_AC_GRAD); @@ -122,7 +121,7 @@ int main(int argc, char** argv) { try { sol2 = invert->solve(sliceXZ(b2, mesh->ystart)); mesh->communicate(sol2); - bcheck2 = d2*this_Grad_perp2(sol2) + this_Grad_perp_dot_Grad_perp(c2,sol2)/c2 + a2*sol2; + bcheck2 = d2*Delp2(sol2, CELL_DEFAULT, false) + this_Grad_perp_dot_Grad_perp(c2,sol2)/c2 + a2*sol2; absolute_error2 = f2-sol2; max_error2 = max_error_at_ystart(abs(absolute_error2, RGN_NOBNDRY)); } catch (BoutException &err) { @@ -157,7 +156,7 @@ int main(int argc, char** argv) { c3 = FieldFactory::get()->create3D("c3:function", Options::getRoot(), mesh); a3 = FieldFactory::get()->create3D("a3:function", Options::getRoot(), mesh); - b3 = d3*this_Grad_perp2(f3) + this_Grad_perp_dot_Grad_perp(c3,f3)/c3 + a3*f3; + b3 = d3*Delp2(f3, CELL_DEFAULT, false) + this_Grad_perp_dot_Grad_perp(c3,f3)/c3 + a3*f3; sol3 = 0.; invert->setInnerBoundaryFlags(INVERT_SET); @@ -178,7 +177,7 @@ int main(int argc, char** argv) { try { sol3 = invert->solve(sliceXZ(b3, mesh->ystart), sliceXZ(x0, mesh->ystart)); mesh->communicate(sol3); - bcheck3 = d3*this_Grad_perp2(sol3) + this_Grad_perp_dot_Grad_perp(c3,f3)/c3 + a3*sol3; + bcheck3 = d3*Delp2(sol3, CELL_DEFAULT, false) + this_Grad_perp_dot_Grad_perp(c3,f3)/c3 + a3*sol3; absolute_error3 = f3-sol3; max_error3 = max_error_at_ystart(abs(absolute_error3, RGN_NOBNDRY)); } catch (BoutException &err) { @@ -213,7 +212,7 @@ int main(int argc, char** argv) { c4 = FieldFactory::get()->create3D("c4:function", Options::getRoot(), mesh); a4 = FieldFactory::get()->create3D("a4:function", Options::getRoot(), mesh); - b4 = d4*this_Grad_perp2(f4) + this_Grad_perp_dot_Grad_perp(c4,f4)/c4 + a4*f4; + b4 = d4*Delp2(f4, CELL_DEFAULT, false) + this_Grad_perp_dot_Grad_perp(c4,f4)/c4 + a4*f4; sol4 = 0.; invert->setInnerBoundaryFlags(INVERT_AC_GRAD+INVERT_SET); @@ -238,7 +237,7 @@ int main(int argc, char** argv) { try { sol4 = invert->solve(sliceXZ(b4, mesh->ystart), sliceXZ(x0, mesh->ystart)); mesh->communicate(sol4); - bcheck4 = d4*this_Grad_perp2(sol4) + this_Grad_perp_dot_Grad_perp(c4,sol4)/c4 + a4*sol4; + bcheck4 = d4*Delp2(sol4, CELL_DEFAULT, false) + this_Grad_perp_dot_Grad_perp(c4,sol4)/c4 + a4*sol4; absolute_error4 = f4-sol4; max_error4 = max_error_at_ystart(abs(absolute_error4, RGN_NOBNDRY)); } catch (BoutException &err) { @@ -275,17 +274,6 @@ int main(int argc, char** argv) { } -// Need custom version of perpendicular Laplacian operator, which is the inverse of the multigrid solver -// Delp2 uses FFT z-derivatives and Laplace includes y-derivatives, so can't use those -// The function is a copy of Laplace() with the y-derivatives deleted -Field3D this_Grad_perp2(const Field3D &f) { - Field3D result = mesh->getCoordinates()->G1 * ::DDX(f) + mesh->getCoordinates()->G3 * ::DDZ(f) + - mesh->getCoordinates()->g11 * ::D2DX2(f) + mesh->getCoordinates()->g33 * ::D2DZ2(f) + - 2.0 * mesh->getCoordinates()->g13 * ::D2DXDZ(f); - - return result; -} - Field3D this_Grad_perp_dot_Grad_perp(const Field3D &f, const Field3D &g) { Field3D result = mesh->getCoordinates()->g11 * ::DDX(f) * ::DDX(g) + mesh->getCoordinates()->g33 * ::DDZ(f) * ::DDZ(g) + mesh->getCoordinates()->g13 * (DDX(f)*DDZ(g) + DDZ(f)*DDX(g)); From 502244a58e2d99407930dbeacc089a679f924394 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 19 Dec 2018 10:44:40 +0000 Subject: [PATCH 0502/1783] Remove invert_laplace calls from some examples Replace use of free functions with Laplacian objects. Also some reformatting and small tidying efforts. Still quite a few uses of invert_laplace in other examples --- examples/6field-simple/elm_6f.cxx | 1283 ++++++------- examples/elm-pb/elm_pb.cxx | 1703 +++++++++--------- examples/gravity_reduced/gravity_reduced.cxx | 139 +- examples/gyro-gem/gem.cxx | 32 +- examples/shear-alfven-wave/2fluid.cxx | 44 +- 5 files changed, 1588 insertions(+), 1613 deletions(-) diff --git a/examples/6field-simple/elm_6f.cxx b/examples/6field-simple/elm_6f.cxx index 5c6c1ea7fa..66c009c948 100644 --- a/examples/6field-simple/elm_6f.cxx +++ b/examples/6field-simple/elm_6f.cxx @@ -7,29 +7,29 @@ *******************************************************************************/ #include "bout.hxx" +#include "derivs.hxx" #include "initialprofiles.hxx" +#include "interpolation.hxx" #include "invert_laplace.hxx" #include "invert_parderiv.hxx" -#include "interpolation.hxx" -#include "derivs.hxx" -#include #include "sourcex.hxx" #include +#include #include +BoutReal n0_height, n0_ave, n0_width, n0_center, + n0_bottom_x; // the total height, average width and center of profile of N0 +BoutReal Tconst; // the ampitude of congstant temperature -BoutReal n0_height, n0_ave, n0_width, n0_center, n0_bottom_x; //the total height, average width and center of profile of N0 -BoutReal Tconst; //the ampitude of congstant temperature - -BoutReal laplace_alpha; //test the effect of first order term of invert Laplace function -BoutReal Tau_ie; //the ratio of Ti0/Te0 +BoutReal laplace_alpha; // test the effect of first order term of invert Laplace function +BoutReal Tau_ie; // the ratio of Ti0/Te0 // 2D inital profiles -Field2D J0, P0; // Current and pressure +Field2D J0, P0; // Current and pressure Vector2D b0xcv; // Curvature term Field2D phi0; // When diamagnetic terms used -Field2D N0,Ti0,Te0,Ne0; // number density and temperature +Field2D N0, Ti0, Te0, Ne0; // number density and temperature Field2D Pi0, Pe0; Field2D q95; BoutReal q95_input; @@ -53,70 +53,71 @@ Field3D Vipar, Vepar; // Derived 3D variables Field3D Jpar, phi; // Parallel current, electric potential -Field3D Ajpar; // Parallel current, electric potential +Field3D Ajpar; // Parallel current, electric potential bool emass; -BoutReal emass_inv; // inverse of electron mass +BoutReal emass_inv; // inverse of electron mass BoutReal coef_jpar; -BoutReal delta_e; // Normalized electron skin depth +BoutReal delta_e; // Normalized electron skin depth BoutReal delta_e_inv; // inverse normalized electron skin depth -BoutReal gyroAlv; // Normalized ion current coef +BoutReal gyroAlv; // Normalized ion current coef Field3D ubyn; - -Field3D Jpar2; // Delp2 of Parallel current -Field3D tmpA2; // Grad2_par2new of Parallel vector potential +Field3D Jpar2; // Delp2 of Parallel current +Field3D tmpA2; // Grad2_par2new of Parallel vector potential Field3D tmpN2, tmpTi2, tmpTe2, tmpVp2; // Grad2_par2new of Parallel density // Constraint Field3D C_phi; // Parameters -BoutReal density; // Number density [m^-3] +BoutReal density; // Number density [m^-3] BoutReal Bbar, Lbar, Tbar, Va; // Normalisation constants BoutReal Nbar, Tibar, Tebar; BoutReal dia_fact; // Multiply diamagnetic term by this -BoutReal diffusion_par; //Parallel thermal conductivity -BoutReal diffusion_perp; //Perpendicular thermal conductivity (>0 open) -BoutReal diffusion_n4, diffusion_ti4, diffusion_te4; //M: 4th Parallel density diffusion +BoutReal diffusion_par; // Parallel thermal conductivity +BoutReal diffusion_perp; // Perpendicular thermal conductivity (>0 open) +BoutReal diffusion_n4, diffusion_ti4, diffusion_te4; // M: 4th Parallel density diffusion BoutReal diffusion_v4; -BoutReal diffusion_u4; //xqx: parallel hyper-viscous diffusion for vorticity +BoutReal diffusion_u4; // xqx: parallel hyper-viscous diffusion for vorticity -BoutReal heating_P; // heating power in pressure +BoutReal heating_P; // heating power in pressure BoutReal hp_width; // heating profile radial width in pressure -BoutReal hp_length; // heating radial domain in pressure -BoutReal sink_vp; // sink in pressure -BoutReal sp_width; // sink profile radial width in pressure -BoutReal sp_length; // sink radial domain in pressure +BoutReal hp_length; // heating radial domain in pressure +BoutReal sink_vp; // sink in pressure +BoutReal sp_width; // sink profile radial width in pressure +BoutReal sp_length; // sink radial domain in pressure -BoutReal sink_Ul; // left edge sink in vorticity -BoutReal su_widthl; // left edge sink profile radial width in vorticity -BoutReal su_lengthl; // left edge sink radial domain in vorticity +BoutReal sink_Ul; // left edge sink in vorticity +BoutReal su_widthl; // left edge sink profile radial width in vorticity +BoutReal su_lengthl; // left edge sink radial domain in vorticity -BoutReal sink_Ur; // right edge sink in vorticity -BoutReal su_widthr; // right edge sink profile radial width in vorticity -BoutReal su_lengthr; // right edge sink radial domain in vorticity +BoutReal sink_Ur; // right edge sink in vorticity +BoutReal su_widthr; // right edge sink profile radial width in vorticity +BoutReal su_lengthr; // right edge sink radial domain in vorticity BoutReal viscos_par; // Parallel viscosity BoutReal viscos_perp; // Perpendicular viscosity BoutReal hyperviscos; // Hyper-viscosity (radial) -Field3D hyper_mu_x; // Hyper-viscosity coefficient +Field3D hyper_mu_x; // Hyper-viscosity coefficient -Field3D Dperp2Phi0, Dperp2Phi, GradPhi02, GradPhi2; //Temporary variables for gyroviscous +Field3D Dperp2Phi0, Dperp2Phi, GradPhi02, GradPhi2; // Temporary variables for gyroviscous Field3D GradparPhi02, GradparPhi2, GradcPhi, GradcparPhi; Field3D Dperp2Pi0, Dperp2Pi, bracketPhi0P, bracketPhiP0, bracketPhiP; -BoutReal Psipara1, Upara0, Upara1; // Temporary normalization constants for all the equations +BoutReal Psipara1, Upara0, + Upara1; // Temporary normalization constants for all the equations BoutReal Upara2, Upara3, Nipara1; BoutReal Tipara1, Tipara2; BoutReal Tepara1, Tepara2, Tepara3, Tepara4; BoutReal Vepara, Vipara; -BoutReal Low_limit; //To limit the negative value of total density and temperatures +BoutReal Low_limit; // To limit the negative value of total density and temperatures -Field3D Te_tmp, Ti_tmp, N_tmp; //to avoid the negative value of total value -BoutReal gamma_i_BC, gamma_e_BC; //sheath energy transmission factors +Field3D Te_tmp, Ti_tmp, N_tmp; // to avoid the negative value of total value +BoutReal gamma_i_BC, gamma_e_BC; // sheath energy transmission factors int Sheath_width; -Field3D c_se, Jpar_sh, q_se, q_si, vth_et, c_set; //variables for sheath boundary conditions +Field3D c_se, Jpar_sh, q_se, q_si, vth_et, + c_set; // variables for sheath boundary conditions Field2D vth_e0, c_se0, Jpar_sh0; BoutReal const_cse; @@ -133,28 +134,28 @@ Field3D vac_mask; int phi_flags, apar_flags; bool nonlinear; -bool evolve_jpar; +bool evolve_jpar; BoutReal g; // Only if compressible bool phi_curv; // Poisson brackets: b0 x Grad(f) dot Grad(g) / B = [f, g] -// Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE -BRACKET_METHOD bm_exb, bm_mag; // Bracket method for advection terms +// Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE +BRACKET_METHOD bm_exb, bm_mag; // Bracket method for advection terms int bracket_method_exb, bracket_method_mag; bool diamag; bool energy_flux, energy_exch; // energy flux term -bool diamag_phi0; // Include the diamagnetic equilibrium phi0 -bool thermal_force; // Include the thermal flux term in Ohm's law +bool diamag_phi0; // Include the diamagnetic equilibrium phi0 +bool thermal_force; // Include the thermal flux term in Ohm's law bool eHall; BoutReal AA; // ion mass in units of the proton mass; AA=Mi/Mp BoutReal Vt0; // equilibrium toroidal flow normalized to Alfven velocity BoutReal Vp0; // equilibrium poloidal flow normalized to Alfven velocity -bool experiment_Er; //read in phi_0 from experiment -Field2D V0, Dphi0; //net flow amplitude, differential potential to flux -Vector2D V0net; //net flow +bool experiment_Er; // read in phi_0 from experiment +Field2D V0, Dphi0; // net flow amplitude, differential potential to flux +Vector2D V0net; // net flow bool nogradparj; bool filter_z; @@ -165,9 +166,9 @@ int zonal_field; int zonal_bkgd; bool relax_j_vac; BoutReal relax_j_tconst; // Time-constant for j relax -Field3D Psitarget; // The (moving) target to relax to +Field3D Psitarget; // The (moving) target to relax to -bool smooth_j_x; // Smooth Jpar in the x direction +bool smooth_j_x; // Smooth Jpar in the x direction BoutReal filter_nl; int jpar_bndry_width; // Zero jpar in a boundary region @@ -177,82 +178,85 @@ bool parallel_lr_diff; // Use left and right shifted stencils for parallel diffe bool parallel_lagrange; // Use (semi-) Lagrangian method for parallel derivatives bool parallel_project; // Use Apar to project field-lines - - //******************** - -Field3D Xip_x, Xip_z; // Displacement of y+1 (in cell index space) - -Field3D Xim_x, Xim_z; // Displacement of y-1 (in cell index space) - -bool phi_constraint; // Solver for phi using a solver constraint - -BoutReal vac_lund, core_lund; // Lundquist number S = (Tau_R / Tau_A). -ve -> infty -BoutReal vac_resist, core_resist; // The resistivities (just 1 / S) -Field3D eta; // Resistivity profile (1 / S) -bool spitzer_resist; // Use Spitzer formula for resistivity - -Field3D eta_spitzer; // Resistivity profile (kg*m^3 / S / C^2) -Field3D nu_i; // Ion collision frequency profile (1 / S) -Field3D nu_e; // Electron collision frequency profile (1 / S) -Field3D vth_i; // Ion Thermal Velocity profile (M / S) -Field3D vth_e; // Electron Thermal Velocity profile (M / S) -Field3D kappa_par_i; // Ion Thermal Conductivity profile (kg&M / S^2) -Field3D kappa_par_e; // Electron Thermal Conductivity profile (kg*M / S^2) -Field2D omega_ci, omega_ce; //cyclotron frequency -Field3D kappa_perp_i; // Ion perpendicular Thermal Conductivity profile (kg&M / S^2) -Field3D kappa_perp_e; // Electron perpendicular Thermal Conductivity profile (kg*M / S^2) - -bool output_transfer; // output the results of energy transfer -bool output_ohm; // output the results of the terms in Ohm's law -bool output_flux_par; // output the results of parallel particle and heat flux -Field3D T_M, T_R, T_ID, T_C, T_G; //Maxwell stress, Reynolds stress, ion diamagbetic and curvature term +Field3D Xip_x, Xip_z; // Displacement of y+1 (in cell index space) + +Field3D Xim_x, Xim_z; // Displacement of y-1 (in cell index space) + +bool phi_constraint; // Solver for phi using a solver constraint + +BoutReal vac_lund, core_lund; // Lundquist number S = (Tau_R / Tau_A). -ve -> infty +BoutReal vac_resist, core_resist; // The resistivities (just 1 / S) +Field3D eta; // Resistivity profile (1 / S) +bool spitzer_resist; // Use Spitzer formula for resistivity + +Field3D eta_spitzer; // Resistivity profile (kg*m^3 / S / C^2) +Field3D nu_i; // Ion collision frequency profile (1 / S) +Field3D nu_e; // Electron collision frequency profile (1 / S) +Field3D vth_i; // Ion Thermal Velocity profile (M / S) +Field3D vth_e; // Electron Thermal Velocity profile (M / S) +Field3D kappa_par_i; // Ion Thermal Conductivity profile (kg&M / S^2) +Field3D kappa_par_e; // Electron Thermal Conductivity profile (kg*M / S^2) +Field2D omega_ci, omega_ce; // cyclotron frequency +Field3D kappa_perp_i; // Ion perpendicular Thermal Conductivity profile (kg&M / S^2) +Field3D kappa_perp_e; // Electron perpendicular Thermal Conductivity profile (kg*M / S^2) + +bool output_transfer; // output the results of energy transfer +bool output_ohm; // output the results of the terms in Ohm's law +bool output_flux_par; // output the results of parallel particle and heat flux +Field3D T_M, T_R, T_ID, T_C, + T_G; // Maxwell stress, Reynolds stress, ion diamagbetic and curvature term Field3D ohm_phi, ohm_hall, ohm_thermal; -Field3D gamma_par_i, heatf_par_i, heatf_par_e; // particle flux, ion and elelctron heat flux +Field3D gamma_par_i, heatf_par_i, + heatf_par_e; // particle flux, ion and elelctron heat flux -BoutReal hyperresist; // Hyper-resistivity coefficient (in core only) -BoutReal ehyperviscos; // electron Hyper-viscosity coefficient -Field3D hyper_eta_x; // Radial resistivity profile -Field3D hyper_eta_z; // Toroidal resistivity profile +BoutReal hyperresist; // Hyper-resistivity coefficient (in core only) +BoutReal ehyperviscos; // electron Hyper-viscosity coefficient +Field3D hyper_eta_x; // Radial resistivity profile +Field3D hyper_eta_z; // Toroidal resistivity profile -int damp_width; // Width of inner damped region -BoutReal damp_t_const; // Timescale of damping +int damp_width; // Width of inner damped region +BoutReal damp_t_const; // Timescale of damping // Metric coefficients Field2D Rxy, Bpxy, Btxy, B0, hthe; -Field2D I; // Shear factor -BoutReal LnLambda; // ln(Lambda) -//Field3D LnLambda; +Field2D I; // Shear factor +BoutReal LnLambda; // ln(Lambda) +// Field3D LnLambda; const BoutReal PI = 3.14159265; -const BoutReal MU0 = 4.0e-7*PI; -BoutReal Mi = 1.6726e-27; // Ion mass -const BoutReal KB = 1.38065e-23; // Boltamann constant -const BoutReal ee = 1.602e-19; // ln(Lambda) -const BoutReal eV_K = 11605.0; // 1eV = 11605K - -//const BoutReal Low_limit = 1.e-10; // limit of the profile to prevent minus total value +const BoutReal MU0 = 4.0e-7 * PI; +BoutReal Mi = 1.6726e-27; // Ion mass +const BoutReal KB = 1.38065e-23; // Boltamann constant +const BoutReal ee = 1.602e-19; // ln(Lambda) +const BoutReal eV_K = 11605.0; // 1eV = 11605K // Communication objects FieldGroup comms; -void advect_tracer(const Field3D &p, // phi (input) - const Field3D &delta_x, const Field3D &delta_z, // Current location (input) - Field3D &F_dx, Field3D &F_dz); // Time-derivative of location +/// Solver for inverting Laplacian +Laplacian* phiSolver; +Laplacian* aparSolver; -const Field3D Grad2_par2new(const Field3D &f); //for 4th order diffusion +void advect_tracer(const Field3D& p, // phi (input) + const Field3D& delta_x, + const Field3D& delta_z, // Current location (input) + Field3D& F_dx, Field3D& F_dz); // Time-derivative of location -const Field2D N0tanh(BoutReal n0_height, BoutReal n0_ave, BoutReal n0_width, BoutReal n0_center, BoutReal n0_bottom_x); +const Field3D Grad2_par2new(const Field3D& f); // for 4th order diffusion -const Field3D field_larger(const Field3D &f, const BoutReal limit); +const Field2D N0tanh(BoutReal n0_height, BoutReal n0_ave, BoutReal n0_width, + BoutReal n0_center, BoutReal n0_bottom_x); -const Field3D field_larger(const Field3D &f, const BoutReal limit) { +const Field3D field_larger(const Field3D& f, const BoutReal limit); + +const Field3D field_larger(const Field3D& f, const BoutReal limit) { Field3D result; result.allocate(); - for(auto i : result) { - if(f[i] >= limit) + for (auto i : result) { + if (f[i] >= limit) result[i] = f[i]; else result[i] = limit; @@ -261,81 +265,79 @@ const Field3D field_larger(const Field3D &f, const BoutReal limit) { return result; } -const Field3D Grad2_par2new(const Field3D &f) { +const Field3D Grad2_par2new(const Field3D& f) { /* * This function implements d2/dy2 where y is the poloidal coordinate theta */ - TRACE("Grad2_par2new( Field3D )"); - + Field3D result = D2DY2(f); - + #ifdef TRACK - result.name = "Grad2_par2new("+f.name+")"; + result.name = "Grad2_par2new(" + f.name + ")"; #endif - + return result; } -const Field2D N0tanh(BoutReal n0_height, BoutReal n0_ave, BoutReal n0_width, BoutReal n0_center, BoutReal n0_bottom_x) { +const Field2D N0tanh(BoutReal n0_height, BoutReal n0_ave, BoutReal n0_width, + BoutReal n0_center, BoutReal n0_bottom_x) { Field2D result; result.allocate(); - BoutReal Grid_NX, Grid_NXlimit; //the grid number on x, and the + BoutReal Grid_NX, Grid_NXlimit; // the grid number on x, and the BoutReal Jysep; mesh->get(Grid_NX, "nx"); mesh->get(Jysep, "jyseps1_1"); - Grid_NXlimit = n0_bottom_x * Grid_NX; + Grid_NXlimit = n0_bottom_x * Grid_NX; output.write("Jysep1_1 = %i Grid number = %e\n", int(Jysep), Grid_NX); - - if (Jysep > 0.) { //for single null geometry - + + if (Jysep > 0.) { // for single null geometry + BoutReal Jxsep, Jysep2; mesh->get(Jxsep, "ixseps1"); mesh->get(Jysep2, "jyseps2_2"); - //output.write("Jysep2_2 = %i Ixsep1 = %i\n", int(Jysep2), int(Jxsep)); - - for (int jx=0;jxLocalNx;jx++) { + + for (int jx = 0; jx < mesh->LocalNx; jx++) { BoutReal mgx = mesh->GlobalX(jx); - BoutReal xgrid_num = (Jxsep+1.)/Grid_NX; - //output.write("mgx = %e xgrid_num = %e\n", mgx); - for (int jy=0;jyLocalNy;jy++) { + BoutReal xgrid_num = (Jxsep + 1.) / Grid_NX; + // output.write("mgx = %e xgrid_num = %e\n", mgx); + for (int jy = 0; jy < mesh->LocalNy; jy++) { int globaly = mesh->YGLOBAL(jy); - //output.write("local y = %i; global y: %i\n", jy, globaly); - if ( mgx > xgrid_num || (globaly<=int(Jysep)-4) || (globaly>int(Jysep2)) ) + // output.write("local y = %i; global y: %i\n", jy, globaly); + if (mgx > xgrid_num || (globaly <= int(Jysep) - 4) || (globaly > int(Jysep2))) mgx = xgrid_num; BoutReal rlx = mgx - n0_center; - BoutReal temp = exp(rlx/n0_width); + BoutReal temp = exp(rlx / n0_width); BoutReal dampr = ((temp - 1.0 / temp) / (temp + 1.0 / temp)); - result(jx,jy) = 0.5*(1.0 - dampr) * n0_height + n0_ave; + result(jx, jy) = 0.5 * (1.0 - dampr) * n0_height + n0_ave; } } - } else { //circular geometry - for (int jx=0;jxLocalNx;jx++) { + } else { // circular geometry + for (int jx = 0; jx < mesh->LocalNx; jx++) { BoutReal mgx = mesh->GlobalX(jx); - BoutReal xgrid_num = Grid_NXlimit/Grid_NX; + BoutReal xgrid_num = Grid_NXlimit / Grid_NX; if (mgx > xgrid_num) mgx = xgrid_num; BoutReal rlx = mgx - n0_center; - BoutReal temp = exp(rlx/n0_width); + BoutReal temp = exp(rlx / n0_width); BoutReal dampr = ((temp - 1.0 / temp) / (temp + 1.0 / temp)); - for(int jy=0;jyLocalNy;jy++) - result(jx,jy) = 0.5*(1.0 - dampr) * n0_height + n0_ave; + for (int jy = 0; jy < mesh->LocalNy; jy++) + result(jx, jy) = 0.5 * (1.0 - dampr) * n0_height + n0_ave; } } - + mesh->communicate(result); return result; } - - + int physics_init(bool restarting) { bool noshear; - + // Get the metric tensor - Coordinates *coord = mesh->getCoordinates(); + Coordinates* coord = mesh->getCoordinates(); output.write("Solving high-beta flute reduced equations\n"); output.write("\tFile : %s\n", __FILE__); @@ -347,84 +349,80 @@ int physics_init(bool restarting) { // Load 2D profiles mesh->get(J0, "Jpar0"); // A / m^2 mesh->get(P0, "pressure"); // Pascals -// mesh->get(P0, "pres2"); // Pascals - - // Load curvature term - b0xcv.covariant = false; // Read contravariant components + b0xcv.covariant = false; // Read contravariant components mesh->get(b0xcv, "bxcv"); // mixed units x: T y: m^-2 z: m^-2 // Load metrics - if(mesh->get(Rxy, "Rxy")) { // m + if (mesh->get(Rxy, "Rxy")) { // m output_error.write("Error: Cannot read Rxy from grid\n"); return 1; } - if(mesh->get(Bpxy, "Bpxy")) { // T + if (mesh->get(Bpxy, "Bpxy")) { // T output_error.write("Error: Cannot read Bpxy from grid\n"); return 1; } mesh->get(Btxy, "Btxy"); // T - mesh->get(B0, "Bxy"); // T + mesh->get(B0, "Bxy"); // T mesh->get(hthe, "hthe"); // m - mesh->get(I, "sinty");// m^-2 T^-1 + mesh->get(I, "sinty"); // m^-2 T^-1 ////////////////////////////////////////////////////////////// // Read parameters from the options file - // + // // Options.get ( NAME, VARIABLE, DEFAULT VALUE) // // or if NAME = "VARIABLE" then just // - // OPTION(VARIABLE, DEFAULT VALUE) + // OPTION(VARIABLE, DEFAULT VALUE) // // Prints out what values are assigned ///////////////////////////////////////////////////////////// - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("highbeta"); - + auto globalOptions = Options::root(); + auto options = globalOptions["highbeta"]; - OPTION(options, n0_fake_prof, false); //use the hyperbolic profile of n0. If both n0_fake_prof and T0_fake_prof are false, use the profiles from grid file - OPTION(options, n0_height, 0.4); //the total height of profile of N0, in percentage of Ni_x - OPTION(options, n0_ave, 0.01); //the center or average of N0, in percentage of Ni_x - OPTION(options, n0_width, 0.1); //the width of the gradient of N0,in percentage of x - OPTION(options, n0_center, 0.633); //the grid number of the center of N0, in percentage of x - OPTION(options, n0_bottom_x, 0.81); //the start of flat region of N0 on SOL side, in percentage of x - OPTION(options, T0_fake_prof, false); - OPTION(options, Tconst, -1.0); //the amplitude of constant temperature, in percentage + OPTION(options, n0_fake_prof, false); // use the hyperbolic profile of n0. If both n0_fake_prof and + // T0_fake_prof are false, use the profiles from grid file + OPTION(options, n0_height, 0.4); // the total height of profile of N0, in percentage of Ni_x + OPTION(options, n0_ave, 0.01); // the center or average of N0, in percentage of Ni_x + OPTION(options, n0_width, 0.1); // the width of the gradient of N0,in percentage of x + OPTION(options, n0_center, 0.633); // the grid number of the center of N0, in percentage of x + OPTION(options, n0_bottom_x, 0.81); // the start of flat region of N0 on SOL side, in percentage of x + OPTION(options, T0_fake_prof, false); + OPTION(options, Tconst, -1.0); // the amplitude of constant temperature, in percentage - OPTION(options, experiment_Er, false); + OPTION(options, experiment_Er, false); - OPTION(options, laplace_alpha, 1.0); //test parameter for the cross term of invert Lapalace - OPTION(options, Low_limit, 1.0e-10); //limit the negative value of total quantities - OPTION(options, q95_input, 5.0); //input q95 as a constant, if <0 use profile from grid - OPTION(options, local_q, false); //using magnetic field to calculate q profile - OPTION(options, q_alpha, 1.0); //flux-limiting coefficient, typical value is [0.03, 3] + OPTION(options, laplace_alpha, 1.0); // test parameter for the cross term of invert Lapalace + OPTION(options, Low_limit, 1.0e-10); // limit the negative value of total quantities + OPTION(options, q95_input, 5.0); // input q95 as a constant, if <0 use profile from grid + OPTION(options, local_q, false); // using magnetic field to calculate q profile + OPTION(options, q_alpha, 1.0); // flux-limiting coefficient, typical value is [0.03, 3] - OPTION(options, gamma_i_BC, -1.0); //sheath energy transmission factor for ion - OPTION(options, gamma_e_BC, -1.0); //sheath energy transmission factor for electron - OPTION(options, Sheath_width, 1); //Sheath boundary width in grid number + OPTION(options, gamma_i_BC, -1.0); // sheath energy transmission factor for ion + OPTION(options, gamma_e_BC, -1.0); // sheath energy transmission factor for electron + OPTION(options, Sheath_width, 1); // Sheath boundary width in grid number - OPTION(options, density, 1.0e19); // Number density [m^-3] - OPTION(options, Zi, 1); // ion charge number - OPTION(options, continuity, false); // use continuity equation + OPTION(options, density, 1.0e19); // Number density [m^-3] + OPTION(options, Zi, 1); // ion charge number + OPTION(options, continuity, false); // use continuity equation - OPTION(options, evolve_jpar, false); // If true, evolve J raher than Psi - OPTION(options, phi_constraint, false); // Use solver constraint for phi + OPTION(options, evolve_jpar, false); // If true, evolve J raher than Psi + OPTION(options, phi_constraint, false); // Use solver constraint for phi // Effects to include/exclude OPTION(options, include_curvature, true); - OPTION(options, include_jpar0, true); - OPTION(options, evolve_pressure, true); - - OPTION(options, compress0, false); - OPTION(options, nonlinear, false); + OPTION(options, include_jpar0, true); + OPTION(options, evolve_pressure, true); + OPTION(options, compress0, false); + OPTION(options, nonlinear, false); // int bracket_method; OPTION(options, bracket_method_exb, 0); - switch(bracket_method_exb) { + switch (bracket_method_exb) { case 0: { bm_exb = BRACKET_STD; output << "\tBrackets for ExB: default differencing\n"; @@ -452,7 +450,7 @@ int physics_init(bool restarting) { // int bracket_method; OPTION(options, bracket_method_mag, 2); - switch(bracket_method_mag) { + switch (bracket_method_mag) { case 0: { bm_mag = BRACKET_STD; output << "\tBrackets: default differencing\n"; @@ -478,183 +476,192 @@ int physics_init(bool restarting) { return 1; } - OPTION(options, AA, 1.0); // ion mass in units of proton mass + OPTION(options, AA, 1.0); // ion mass in units of proton mass Mi *= AA; - OPTION(options, emass, false); // including electron inertial, electron mass - OPTION(options, emass_inv, 1.0); // inverse of electron mass + OPTION(options, emass, false); // including electron inertial, electron mass + OPTION(options, emass_inv, 1.0); // inverse of electron mass - OPTION(options, diamag, false); // Diamagnetic effects? - OPTION(options, diamag_phi0, diamag); // Include equilibrium phi0 - OPTION(options, dia_fact, 1.0); // Scale diamagnetic effects by this factor + OPTION(options, diamag, false); // Diamagnetic effects? + OPTION(options, diamag_phi0, diamag); // Include equilibrium phi0 + OPTION(options, dia_fact, 1.0); // Scale diamagnetic effects by this factor - OPTION(options, noshear, false); + OPTION(options, noshear, false); + + OPTION(options, relax_j_vac, false); // Relax vacuum current to zero + OPTION(options, relax_j_tconst, 0.1); - OPTION(options, relax_j_vac, false); // Relax vacuum current to zero - OPTION(options, relax_j_tconst, 0.1); - // Toroidal filtering - OPTION(options, filter_z, false); // Filter a single n - OPTION(options, filter_z_mode, 1); - OPTION(options, low_pass_z, -1); // Low-pass filter - OPTION(options, zonal_flow, -1); // zonal flow filter - OPTION(options, zonal_field, -1); // zonal field filter - OPTION(options, zonal_bkgd, -1); // zonal background P filter + OPTION(options, filter_z, false); // Filter a single n + OPTION(options, filter_z_mode, 1); + OPTION(options, low_pass_z, -1); // Low-pass filter + OPTION(options, zonal_flow, -1); // zonal flow filter + OPTION(options, zonal_field, -1); // zonal field filter + OPTION(options, zonal_bkgd, -1); // zonal background P filter - OPTION(options, filter_nl, -1); // zonal background P filter + OPTION(options, filter_nl, -1); // zonal background P filter // Radial smoothing - OPTION(options, smooth_j_x, false); // Smooth Jpar in x + OPTION(options, smooth_j_x, false); // Smooth Jpar in x // Jpar boundary region OPTION(options, jpar_bndry_width, -1); // Parallel differencing OPTION(options, parallel_lr_diff, false); - OPTION(options, parallel_lagrange, false); // Use a (semi-) Lagrangian method for Grad_parP + OPTION(options, parallel_lagrange, + false); // Use a (semi-) Lagrangian method for Grad_parP OPTION(options, parallel_project, false); // Vacuum region control - OPTION(options, vacuum_pressure, 0.02); // Fraction of peak pressure - OPTION(options, vacuum_trans, 0.005); // Transition width in pressure - + OPTION(options, vacuum_pressure, 0.02); // Fraction of peak pressure + OPTION(options, vacuum_trans, 0.005); // Transition width in pressure + // Resistivity and hyper-resistivity options - OPTION(options, vac_lund, 0.0); // Lundquist number in vacuum region - OPTION(options, core_lund, 0.0); // Lundquist number in core region - OPTION(options, hyperresist, -1.0); - OPTION(options, ehyperviscos, -1.0); - OPTION(options, spitzer_resist, false); // Use Spitzer resistivity + OPTION(options, vac_lund, 0.0); // Lundquist number in vacuum region + OPTION(options, core_lund, 0.0); // Lundquist number in core region + OPTION(options, hyperresist, -1.0); + OPTION(options, ehyperviscos, -1.0); + OPTION(options, spitzer_resist, false); // Use Spitzer resistivity // Inner boundary damping - OPTION(options, damp_width, 0); - OPTION(options, damp_t_const, 0.1); + OPTION(options, damp_width, 0); + OPTION(options, damp_t_const, 0.1); // Viscosity and hyper-viscosity - OPTION(options, viscos_par, -1.0); // Parallel viscosity - OPTION(options, viscos_perp, -1.0); // Perpendicular viscosity - OPTION(options, hyperviscos, -1.0); // Radial hyperviscosity - - OPTION(options, diffusion_par, -1.0); // Parallel temperature diffusion - OPTION(options, diffusion_n4, -1.0); // M: 4th Parallel density diffusion - OPTION(options, diffusion_ti4, -1.0); // M: 4th Parallel ion temperature diffusion - OPTION(options, diffusion_te4, -1.0); // M: 4th Parallel electron temperature diffusion - OPTION(options, diffusion_v4, -1.0); // M: 4th Parallel ion parallel velocity diffusion - OPTION(options, diffusion_u4, -1.0); //xqx: parallel hyper-viscous diffusion for vorticity + OPTION(options, viscos_par, -1.0); // Parallel viscosity + OPTION(options, viscos_perp, -1.0); // Perpendicular viscosity + OPTION(options, hyperviscos, -1.0); // Radial hyperviscosity + + OPTION(options, diffusion_par, -1.0); // Parallel temperature diffusion + OPTION(options, diffusion_n4, -1.0); // M: 4th Parallel density diffusion + OPTION(options, diffusion_ti4, -1.0); // M: 4th Parallel ion temperature diffusion + OPTION(options, diffusion_te4, -1.0); // M: 4th Parallel electron temperature diffusion + OPTION(options, diffusion_v4, -1.0); // M: 4th Parallel ion parallel velocity diffusion + OPTION(options, diffusion_u4, + -1.0); // xqx: parallel hyper-viscous diffusion for vorticity // heating factor in pressure - OPTION(options, heating_P, -1.0); // heating power in pressure - OPTION(options, hp_width, 0.1); // the percentage of radial grid points for heating profile radial width in pressure - OPTION(options, hp_length, 0.04); // the percentage of radial grid points for heating profile radial domain in pressure + OPTION(options, heating_P, -1.0); // heating power in pressure + OPTION(options, hp_width, 0.1); // the percentage of radial grid points for heating + // profile radial width in pressure + OPTION(options, hp_length, 0.04); // the percentage of radial grid points for heating + // profile radial domain in pressure // sink factor in pressure - OPTION(options, sink_vp, -1.0); // sink in pressure - OPTION(options, sp_width, 0.05); // the percentage of radial grid points for sink profile radial width in pressure - OPTION(options, sp_length, 0.04); // the percentage of radial grid points for sink profile radial domain in pressure - + OPTION(options, sink_vp, -1.0); // sink in pressure + OPTION(options, sp_width, 0.05); // the percentage of radial grid points for sink + // profile radial width in pressure + OPTION(options, sp_length, 0.04); // the percentage of radial grid points for sink + // profile radial domain in pressure // left edge sink factor in vorticity - OPTION(options, sink_Ul, -1.0); // left edge sink in vorticity - OPTION(options, su_widthl, 0.06); // the percentage of left edge radial grid points for sink profile radial width in vorticity - OPTION(options, su_lengthl, 0.15); // the percentage of left edge radial grid points for sink profile radial domain in vorticity + OPTION(options, sink_Ul, -1.0); // left edge sink in vorticity + OPTION(options, su_widthl, 0.06); // the percentage of left edge radial grid points for + // sink profile radial width in vorticity + OPTION(options, su_lengthl, 0.15); // the percentage of left edge radial grid points + // for sink profile radial domain in vorticity // right edge sink factor in vorticity - OPTION(options, sink_Ur, -1.0); // right edge sink in vorticity - OPTION(options, su_widthr, 0.06); // the percentage of right edge radial grid points for sink profile radial width in vorticity - OPTION(options, su_lengthr, 0.15); // the percentage of right edge radial grid points for sink profile radial domain in vorticity + OPTION(options, sink_Ur, -1.0); // right edge sink in vorticity + OPTION(options, su_widthr, 0.06); // the percentage of right edge radial grid points + // for sink profile radial width in vorticity + OPTION(options, su_lengthr, 0.15); // the percentage of right edge radial grid points + // for sink profile radial domain in vorticity // Compressional terms - OPTION(options, phi_curv, true); - options->get("gamma", g, 5.0/3.0); - + OPTION(options, phi_curv, true); + g = options["gamma"].withDefault(5.0 / 3.0); + // Field inversion flags - OPTION(options, phi_flags, 0); - OPTION(options, apar_flags, 0); + OPTION(options, phi_flags, 0); + OPTION(options, apar_flags, 0); - if(!include_curvature) + if (!include_curvature) b0xcv = 0.0; - - if(!include_jpar0) + + if (!include_jpar0) J0 = 0.0; - if(noshear) { - if(include_curvature) - b0xcv.z += I*b0xcv.x; + if (noshear) { + if (include_curvature) + b0xcv.z += I * b0xcv.x; I = 0.0; } - + ////////////////////////////////////////////////////////////// // SHIFTED RADIAL COORDINATES - if(mesh->IncIntShear) { + if (mesh->IncIntShear) { // BOUT-06 style, using d/dx = d/dpsi + I * d/dz coord->IntShiftTorsion = I; - - }else { + + } else { // Dimits style, using local coordinate system - if(include_curvature) - b0xcv.z += I*b0xcv.x; - I = 0.0; // I disappears from metric + if (include_curvature) + b0xcv.z += I * b0xcv.x; + I = 0.0; // I disappears from metric } - + ////////////////////////////////////////////////////////////// // NORMALISE QUANTITIES - - if(mesh->get(Bbar, "bmag")) // Typical magnetic field + + if (mesh->get(Bbar, "bmag")) // Typical magnetic field Bbar = 1.0; - if(mesh->get(Lbar, "rmag")) // Typical length scale + if (mesh->get(Lbar, "rmag")) // Typical length scale Lbar = 1.0; - if(mesh->get(Tibar, "Ti_x")) // Typical ion temperature scale + if (mesh->get(Tibar, "Ti_x")) // Typical ion temperature scale Tibar = 1.0; - if(mesh->get(Tebar, "Te_x")) // Typical electron temperature scale + if (mesh->get(Tebar, "Te_x")) // Typical electron temperature scale Tebar = 1.0; - if(mesh->get(Nbar, "Nixexp")) // Typical ion density scale + if (mesh->get(Nbar, "Nixexp")) // Typical ion density scale Nbar = 1.0; - Nbar *= 1.e20/density; + Nbar *= 1.e20 / density; - Tau_ie = Tibar/Tebar; + Tau_ie = Tibar / Tebar; - Va = sqrt(Bbar*Bbar / (MU0*Mi*Nbar*density)); + Va = sqrt(Bbar * Bbar / (MU0 * Mi * Nbar * density)); Tbar = Lbar / Va; output.write("Normalisations: Bbar = %e T Lbar = %e m\n", Bbar, Lbar); output.write(" Va = %e m/s Tbar = %e s\n", Va, Tbar); - output.write(" Nbar = %e * %e m^-3\n",Nbar,density); + output.write(" Nbar = %e * %e m^-3\n", Nbar, density); output.write("Tibar = %e eV Tebar = %e eV Ti/Te = %e\n", Tibar, Tebar, Tau_ie); output.write(" Resistivity\n"); - Upara0 = KB * Tebar*eV_K / (Zi * ee * Bbar * Va * Lbar); - Upara1 = KB*Tebar*eV_K/Mi/Va/Va; + Upara0 = KB * Tebar * eV_K / (Zi * ee * Bbar * Va * Lbar); + Upara1 = KB * Tebar * eV_K / Mi / Va / Va; output.write("vorticity cinstant: Upara0 = %e Upara1 = %e\n", Upara0, Upara1); - + if (diamag) { - Nipara1 = KB * Tibar*eV_K/ (Zi*ee*Bbar*Lbar*Va); + Nipara1 = KB * Tibar * eV_K / (Zi * ee * Bbar * Lbar * Va); Tipara2 = Nipara1; - Tepara2 = KB * Tebar*eV_K / (ee * Bbar * Lbar * Va); + Tepara2 = KB * Tebar * eV_K / (ee * Bbar * Lbar * Va); Tepara3 = Bbar / (ee * MU0 * Nbar * density * Lbar * Va); - output.write("Nipara1 = %e Tipara2 = %e\n", Nipara1, Tipara2); + output.write("Nipara1 = %e Tipara2 = %e\n", Nipara1, Tipara2); output.write("Tepara2 = %e Tepara3 = %e\n", Tepara2, Tepara3); } - + if (compress0) { output.write("Including compression (Vipar) effects\n"); - Vipara = MU0 * KB * Nbar*density * Tebar*eV_K / (Bbar*Bbar); - Vepara = Bbar/(MU0*Zi*ee*Nbar*density*Lbar*Va); + Vipara = MU0 * KB * Nbar * density * Tebar * eV_K / (Bbar * Bbar); + Vepara = Bbar / (MU0 * Zi * ee * Nbar * density * Lbar * Va); output.write("Normalized constant for Vipar : Vipara = %e\n", Vipara); output.write("Normalized constant for Vepar : Vepara = %e\n", Vepara); } if (diffusion_par > 0.0) { - Tipara1 = 2.0/ 3.0 / (Lbar * Va); + Tipara1 = 2.0 / 3.0 / (Lbar * Va); Tepara1 = Tipara1 / Zi; } - + if (vac_lund > 0.0) { - output.write(" Vacuum Tau_R = %e s eta = %e Ohm m\n", vac_lund * Tbar, - MU0 * Lbar * Lbar / (vac_lund * Tbar)); + output.write(" Vacuum Tau_R = %e s eta = %e Ohm m\n", vac_lund * Tbar, + MU0 * Lbar * Lbar / (vac_lund * Tbar)); vac_resist = 1. / vac_lund; } else { output.write(" Vacuum - Zero resistivity -\n"); @@ -662,7 +669,7 @@ int physics_init(bool restarting) { } if (core_lund > 0.0) { output.write(" Core Tau_R = %e s eta = %e Ohm m\n", core_lund * Tbar, - MU0 * Lbar * Lbar / (core_lund * Tbar)); + MU0 * Lbar * Lbar / (core_lund * Tbar)); core_resist = 1. / core_lund; } else { output.write(" Core - Zero resistivity -\n"); @@ -674,7 +681,7 @@ int physics_init(bool restarting) { dump.add(hyper_eta_x, "hyper_eta_x", 1); dump.add(hyper_eta_z, "hyper_eta_z", 1); } - + if (ehyperviscos > 0.0) { output.write(" electron Hyper-viscosity coefficient: %e\n", ehyperviscos); } @@ -688,32 +695,32 @@ int physics_init(bool restarting) { output.write(" diffusion_par: %e\n", diffusion_par); dump.add(diffusion_par, "diffusion_par", 0); } - - //M: 4th order diffusion of p + + // M: 4th order diffusion of p if (diffusion_n4 > 0.0) { output.write(" diffusion_n4: %e\n", diffusion_n4); dump.add(diffusion_n4, "diffusion_n4", 0); } - //M: 4th order diffusion of Ti + // M: 4th order diffusion of Ti if (diffusion_ti4 > 0.0) { output.write(" diffusion_ti4: %e\n", diffusion_ti4); dump.add(diffusion_ti4, "diffusion_ti4", 0); } - - //M: 4th order diffusion of Te + + // M: 4th order diffusion of Te if (diffusion_te4 > 0.0) { output.write(" diffusion_te4: %e\n", diffusion_te4); dump.add(diffusion_te4, "diffusion_te4", 0); } - //M: 4th order diffusion of Vipar + // M: 4th order diffusion of Vipar if (diffusion_v4 > 0.0) { output.write(" diffusion_v4: %e\n", diffusion_v4); dump.add(diffusion_v4, "diffusion_v4", 0); } - - //xqx: parallel hyper-viscous diffusion for vorticity + + // xqx: parallel hyper-viscous diffusion for vorticity if (diffusion_u4 > 0.0) { output.write(" diffusion_u4: %e\n", diffusion_u4); dump.add(diffusion_u4, "diffusion_u4", 0); @@ -723,50 +730,49 @@ int physics_init(bool restarting) { output.write(" sink_vp(rate): %e\n", sink_vp); dump.add(sink_vp, "sink_vp", 1); - output.write(" sp_width(%): %e\n",sp_width); + output.write(" sp_width(%): %e\n", sp_width); dump.add(sp_width, "sp_width", 1); - output.write(" sp_length(%): %e\n",sp_length); + output.write(" sp_length(%): %e\n", sp_length); dump.add(sp_length, "sp_length", 1); } - - J0 = MU0*Lbar * J0 / B0; - P0 = P0/(KB * (Tibar+Tebar)*eV_K /2. * Nbar*density); + J0 = MU0 * Lbar * J0 / B0; + P0 = P0 / (KB * (Tibar + Tebar) * eV_K / 2. * Nbar * density); b0xcv.x /= Bbar; - b0xcv.y *= Lbar*Lbar; - b0xcv.z *= Lbar*Lbar; + b0xcv.y *= Lbar * Lbar; + b0xcv.z *= Lbar * Lbar; - Rxy /= Lbar; + Rxy /= Lbar; Bpxy /= Bbar; Btxy /= Bbar; - B0 /= Bbar; + B0 /= Bbar; hthe /= Lbar; - coord->dx /= Lbar*Lbar*Bbar; - I *= Lbar*Lbar*Bbar; + coord->dx /= Lbar * Lbar * Bbar; + I *= Lbar * Lbar * Bbar; - if( (!T0_fake_prof) && n0_fake_prof ) { - N0 = N0tanh(n0_height*Nbar, n0_ave*Nbar, n0_width, n0_center, n0_bottom_x); - - Ti0 = P0/N0/2.0; + if ((!T0_fake_prof) && n0_fake_prof) { + N0 = N0tanh(n0_height * Nbar, n0_ave * Nbar, n0_width, n0_center, n0_bottom_x); + + Ti0 = P0 / N0 / 2.0; Te0 = Ti0; } else if (T0_fake_prof) { Ti0 = Tconst; Te0 = Ti0; - N0 = P0/(Ti0+Te0); + N0 = P0 / (Ti0 + Te0); } else { - if (mesh->get(N0, "Niexp")) { // N_i0 + if (mesh->get(N0, "Niexp")) { // N_i0 output_error.write("Error: Cannot read Ni0 from grid\n"); return 1; - } - - if (mesh->get(Ti0, "Tiexp")) { // T_i0 + } + + if (mesh->get(Ti0, "Tiexp")) { // T_i0 output_error.write("Error: Cannot read Ti0 from grid\n"); return 1; } - if (mesh->get(Te0, "Teexp")) { // T_e0 + if (mesh->get(Te0, "Teexp")) { // T_e0 output_error.write("Error: Cannot read Te0 from grid\n"); return 1; } @@ -779,17 +785,17 @@ int physics_init(bool restarting) { Pi0 = N0 * Ti0; Pe0 = Ne0 * Te0; - nu_e.setLocation(CELL_YLOW); - nu_e.setBoundary("kappa"); + nu_e.setLocation(CELL_YLOW); + nu_e.setBoundary("kappa"); if (spitzer_resist) { - eta_spitzer.setLocation(CELL_YLOW); + eta_spitzer.setLocation(CELL_YLOW); eta_spitzer.setBoundary("kappa"); } if (diffusion_par > 0.0) { nu_i.setLocation(CELL_YLOW); nu_i.setBoundary("kappa"); - vth_i.setLocation(CELL_YLOW); - vth_e.setLocation(CELL_YLOW); + vth_i.setLocation(CELL_YLOW); + vth_e.setLocation(CELL_YLOW); vth_i.setBoundary("kappa"); vth_e.setBoundary("kappa"); kappa_par_i.setLocation(CELL_YLOW); @@ -801,120 +807,135 @@ int physics_init(bool restarting) { kappa_perp_i.setBoundary("kappa"); kappa_perp_e.setBoundary("kappa"); } - + if (compress0) { eta_i0.setLocation(CELL_CENTRE); eta_i0.setBoundary("Ti"); pi_ci.setLocation(CELL_CENTRE); pi_ci.setBoundary("Ti"); - - //dump.add(eta_i0, "eta_i0", 1); - //dump.add(pi_ci, "pi_ci", 1); + + // dump.add(eta_i0, "eta_i0", 1); + // dump.add(pi_ci, "pi_ci", 1); } - + BoutReal pnorm = max(P0, true); // Maximum over all processors - + vacuum_pressure *= pnorm; // Get pressure from fraction vacuum_trans *= pnorm; // Transitions from 0 in core to 1 in vacuum - vac_mask = (1.0 - tanh( (P0 - vacuum_pressure) / vacuum_trans )) / 2.0; + vac_mask = (1.0 - tanh((P0 - vacuum_pressure) / vacuum_trans)) / 2.0; if (diffusion_par > 0.0) { - if (q95_input >0 ) { - q95 = q95_input; //use a constant for test + if (q95_input > 0) { + q95 = q95_input; // use a constant for test } else { if (local_q) { - q95 = abs(hthe * Btxy / ( Bpxy)) * q_alpha; + q95 = abs(hthe * Btxy / (Bpxy)) * q_alpha; } else { output.write("\tUsing q profile from grid.\n"); - if(mesh->get(q95, "q")) { - output.write("Cannot get q profile from grid!\nPlease run addqprofile.pro first\n"); + if (mesh->get(q95, "q")) { + output.write( + "Cannot get q profile from grid!\nPlease run addqprofile.pro first\n"); return 1; - } + } } } output.write("\tlocal max q: %e\n", max(q95)); output.write("\tlocal min q: %e\n", min(q95)); } - LnLambda = 24.0 - log(pow(Zi*Nbar*density/1.e6, 0.5) * pow(Tebar, -1.0)); //xia: ln Lambda + LnLambda = + 24.0 + - log(pow(Zi * Nbar * density / 1.e6, 0.5) * pow(Tebar, -1.0)); // xia: ln Lambda output.write("\tlog Lambda: %e\n", LnLambda); - nu_e = 2.91e-6*LnLambda*((N0)*Nbar*density/1.e6)*pow(Te0*Tebar,-1.5); // nu_e in 1/S. + nu_e = 2.91e-6 * LnLambda * ((N0)*Nbar * density / 1.e6) + * pow(Te0 * Tebar, -1.5); // nu_e in 1/S. output.write("\telectron collision rate: %e -> %e [1/s]\n", min(nu_e), max(nu_e)); - //nu_e.applyBoundary(); - //mesh->communicate(nu_e); + // nu_e.applyBoundary(); + // mesh->communicate(nu_e); if (diffusion_par > 0.0) { - - output.write("\tion thermal noramlized constant: Tipara1 = %e\n",Tipara1); - output.write("\telectron normalized thermal constant: Tepara1 = %e\n",Tepara1); - //xqx addition, begin - // Use Spitzer thermal conductivities - nu_i = 4.80e-8*(Zi*Zi*Zi*Zi/sqrt(AA))*LnLambda*((N0)*Nbar*density/1.e6)*pow(Ti0*Tibar,-1.5); // nu_i in 1/S. - //output.write("\tCoulomb Logarithm: %e \n", max(LnLambda)); + + output.write("\tion thermal noramlized constant: Tipara1 = %e\n", Tipara1); + output.write("\telectron normalized thermal constant: Tepara1 = %e\n", Tepara1); + // xqx addition, begin + // Use Spitzer thermal conductivities + nu_i = 4.80e-8 * (Zi * Zi * Zi * Zi / sqrt(AA)) * LnLambda + * ((N0)*Nbar * density / 1.e6) * pow(Ti0 * Tibar, -1.5); // nu_i in 1/S. + // output.write("\tCoulomb Logarithm: %e \n", max(LnLambda)); output.write("\tion collision rate: %e -> %e [1/s]\n", min(nu_i), max(nu_i)); - //nu_i.applyBoundary(); - //mesh->communicate(nu_i); - - vth_i = 9.79e3*sqrt((Ti0)*Tibar/AA); // vth_i in m/S. + // nu_i.applyBoundary(); + // mesh->communicate(nu_i); + + vth_i = 9.79e3 * sqrt((Ti0)*Tibar / AA); // vth_i in m/S. output.write("\tion thermal velocity: %e -> %e [m/s]\n", min(vth_i), max(vth_i)); - //vth_i.applyBoundary(); - //mesh->communicate(vth_i); - vth_e = 4.19e5*sqrt((Te0)*Tebar); // vth_e in m/S. + // vth_i.applyBoundary(); + // mesh->communicate(vth_i); + vth_e = 4.19e5 * sqrt((Te0)*Tebar); // vth_e in m/S. output.write("\telectron thermal velocity: %e -> %e [m/s]\n", min(vth_e), max(vth_e)); - //vth_e.applyBoundary(); - //mesh->communicate(vth_e); + // vth_e.applyBoundary(); + // mesh->communicate(vth_e); } - + if (compress0) { - eta_i0 = 0.96 * Pi0*Tau_ie * nu_i * Tbar; - output.write("\tCoefficients of parallel viscocity: %e -> %e [kg/(m s)]\n", min(eta_i0), max(eta_i0)); + eta_i0 = 0.96 * Pi0 * Tau_ie * nu_i * Tbar; + output.write("\tCoefficients of parallel viscocity: %e -> %e [kg/(m s)]\n", + min(eta_i0), max(eta_i0)); } - + if (diffusion_par > 0.0) { - kappa_par_i=3.9*vth_i*vth_i/nu_i;// * 1.e4; - kappa_par_e=3.2*vth_e*vth_e/nu_e;// * 1.e4; - - output.write("\tion thermal conductivity: %e -> %e [m^2/s]\n", min(kappa_par_i), max(kappa_par_i)); - output.write("\telectron thermal conductivity: %e -> %e [m^2/s]\n", min(kappa_par_e), max(kappa_par_e)); - - output.write("\tnormalized ion thermal conductivity: %e -> %e \n", min(kappa_par_i*Tipara1), max(kappa_par_i*Tipara1)); - output.write("\tnormalized electron thermal conductivity: %e -> %e \n", min(kappa_par_e*Tepara1), max(kappa_par_e*Tepara1)); - + kappa_par_i = 3.9 * vth_i * vth_i / nu_i; // * 1.e4; + kappa_par_e = 3.2 * vth_e * vth_e / nu_e; // * 1.e4; + + output.write("\tion thermal conductivity: %e -> %e [m^2/s]\n", min(kappa_par_i), + max(kappa_par_i)); + output.write("\telectron thermal conductivity: %e -> %e [m^2/s]\n", min(kappa_par_e), + max(kappa_par_e)); + + output.write("\tnormalized ion thermal conductivity: %e -> %e \n", + min(kappa_par_i * Tipara1), max(kappa_par_i * Tipara1)); + output.write("\tnormalized electron thermal conductivity: %e -> %e \n", + min(kappa_par_e * Tepara1), max(kappa_par_e * Tepara1)); + Field3D kappa_par_i_fl, kappa_par_e_fl; - - kappa_par_i_fl = vth_i * (q95 * Lbar);// * 1.e2; - kappa_par_e_fl = vth_e * (q95 * Lbar);// * 1.e2; - + + kappa_par_i_fl = vth_i * (q95 * Lbar); // * 1.e2; + kappa_par_e_fl = vth_e * (q95 * Lbar); // * 1.e2; + kappa_par_i *= kappa_par_i_fl / (kappa_par_i + kappa_par_i_fl); - kappa_par_i *= Tipara1*N0; - output.write("\tUsed normalized ion thermal conductivity: %e -> %e \n", min(kappa_par_i), max(kappa_par_i)); - //kappa_par_i.applyBoundary(); - //mesh->communicate(kappa_par_i); + kappa_par_i *= Tipara1 * N0; + output.write("\tUsed normalized ion thermal conductivity: %e -> %e \n", + min(kappa_par_i), max(kappa_par_i)); + // kappa_par_i.applyBoundary(); + // mesh->communicate(kappa_par_i); kappa_par_e *= kappa_par_e_fl / (kappa_par_e + kappa_par_e_fl); - kappa_par_e *= Tepara1*N0/Zi; - output.write("\tUsed normalized electron thermal conductivity: %e -> %e \n", min(kappa_par_e), max(kappa_par_e)); - //kappa_par_e.applyBoundary(); - //mesh->communicate(kappa_par_e); - + kappa_par_e *= Tepara1 * N0 / Zi; + output.write("\tUsed normalized electron thermal conductivity: %e -> %e \n", + min(kappa_par_e), max(kappa_par_e)); + // kappa_par_e.applyBoundary(); + // mesh->communicate(kappa_par_e); + dump.add(kappa_par_i, "kappa_par_i", 1); dump.add(kappa_par_e, "kappa_par_e", 1); } - + if (spitzer_resist) { - // Use Spitzer resistivity + // Use Spitzer resistivity output.write(""); output.write("\tSpizter parameters"); - //output.write("\tTemperature: %e -> %e [eV]\n", min(Te), max(Te)); - eta_spitzer = 0.51*1.03e-4*Zi*LnLambda*pow(Te0*Tebar,-1.5); // eta in Ohm-m. NOTE: ln(Lambda) = 20 - output.write("\tSpitzer resistivity: %e -> %e [Ohm m]\n", min(eta_spitzer), max(eta_spitzer)); + // output.write("\tTemperature: %e -> %e [eV]\n", min(Te), max(Te)); + eta_spitzer = 0.51 * 1.03e-4 * Zi * LnLambda + * pow(Te0 * Tebar, -1.5); // eta in Ohm-m. NOTE: ln(Lambda) = 20 + output.write("\tSpitzer resistivity: %e -> %e [Ohm m]\n", min(eta_spitzer), + max(eta_spitzer)); eta_spitzer /= MU0 * Va * Lbar; - //eta_spitzer.applyBoundary(); - //mesh->communicate(eta_spitzer); - output.write("\t -> Lundquist %e -> %e\n", 1.0/max(eta_spitzer), 1.0/min(eta_spitzer)); + // eta_spitzer.applyBoundary(); + // mesh->communicate(eta_spitzer); + output.write("\t -> Lundquist %e -> %e\n", 1.0 / max(eta_spitzer), + 1.0 / min(eta_spitzer)); dump.add(eta_spitzer, "eta_spitzer", 1); } else { // transition from 0 for large P0 to resistivity for small P0 @@ -922,37 +943,37 @@ int physics_init(bool restarting) { eta_spitzer = 0.; dump.add(eta, "eta", 0); } - + /**************** CALCULATE METRICS ******************/ - coord->g11 = SQ(Rxy*Bpxy); + coord->g11 = SQ(Rxy * Bpxy); coord->g22 = 1.0 / SQ(hthe); - coord->g33 = SQ(I)*coord->g11 + SQ(B0)/coord->g11; + coord->g33 = SQ(I) * coord->g11 + SQ(B0) / coord->g11; coord->g12 = 0.0; - coord->g13 = -I*coord->g11; - coord->g23 = -Btxy/(hthe*Bpxy*Rxy); - + coord->g13 = -I * coord->g11; + coord->g23 = -Btxy / (hthe * Bpxy * Rxy); + coord->J = hthe / Bpxy; coord->Bxy = B0; - - coord->g_11 = 1.0/coord->g11 + SQ(I*Rxy); - coord->g_22 = SQ(B0*hthe/Bpxy); - coord->g_33 = Rxy*Rxy; - coord->g_12 = Btxy*hthe*I*Rxy/Bpxy; - coord->g_13 = I*Rxy*Rxy; - coord->g_23 = Btxy*hthe*Rxy/Bpxy; - + + coord->g_11 = 1.0 / coord->g11 + SQ(I * Rxy); + coord->g_22 = SQ(B0 * hthe / Bpxy); + coord->g_33 = Rxy * Rxy; + coord->g_12 = Btxy * hthe * I * Rxy / Bpxy; + coord->g_13 = I * Rxy * Rxy; + coord->g_23 = Btxy * hthe * Rxy / Bpxy; + coord->geometry(); // Calculate quantities from metric tensor // Set B field vector - + B0vec.covariant = false; B0vec.x = 0.; B0vec.y = Bpxy / hthe; B0vec.z = 0.; // Set V0vec field vector - + V0vec.covariant = false; V0vec.x = 0.; V0vec.y = Vp0 / hthe; @@ -962,8 +983,8 @@ int physics_init(bool restarting) { V0eff.covariant = false; V0eff.x = 0.; - V0eff.y = -(Btxy/(B0*B0))*(Vp0*Btxy-Vt0*Bpxy) / hthe; - V0eff.z = (Bpxy/(B0*B0))*(Vp0*Btxy-Vt0*Bpxy) / Rxy; + V0eff.y = -(Btxy / (B0 * B0)) * (Vp0 * Btxy - Vt0 * Bpxy) / hthe; + V0eff.z = (Bpxy / (B0 * B0)) * (Vp0 * Btxy - Vt0 * Bpxy) / Rxy; /**************** SET VARIABLE LOCATIONS *************/ @@ -989,7 +1010,7 @@ int physics_init(bool restarting) { Ti_tmp.setLocation(CELL_CENTRE); Te_tmp.setLocation(CELL_CENTRE); } - + Pe.setBoundary("P"); Pi.setBoundary("P"); @@ -1006,22 +1027,22 @@ int physics_init(bool restarting) { dump.add(P, "P", 1); dump.add(Vepar, "Vepar", 1); - + if (parallel_lagrange) { // Evolving the distortion of the flux surfaces (Ideal-MHD only!) - + bout_solve(Xip_x, "Xip_x"); bout_solve(Xip_z, "Xip_z"); - + bout_solve(Xim_x, "Xim_x"); bout_solve(Xim_z, "Xim_z"); } - + if (parallel_project) { // Add Xi to the dump file dump.add(Xip_x, "Xip_x", 1); dump.add(Xip_z, "Xip_z", 1); - + dump.add(Xim_x, "Xim_x", 1); dump.add(Xim_z, "Xim_z", 1); } @@ -1035,25 +1056,26 @@ int physics_init(bool restarting) { if (phi_constraint) { // Implicit Phi solve using IDA - + if (!bout_constrain(phi, C_phi, "phi")) { - output_error.write("ERROR: Cannot constrain. Run again with phi_constraint=false\n"); + output_error.write( + "ERROR: Cannot constrain. Run again with phi_constraint=false\n"); throw BoutException("Aborting.\n"); } - + } else { // Phi solved in RHS (explicitly) dump.add(phi, "phi", 1); } // Diamagnetic phi0 - if(diamag && diamag_phi0) { - if(experiment_Er) { //get phi0 from grid file - mesh->get(phi0,"Phi_0"); - phi0 /= B0*Lbar*Va; + if (diamag && diamag_phi0) { + if (experiment_Er) { // get phi0 from grid file + mesh->get(phi0, "Phi_0"); + phi0 /= B0 * Lbar * Va; } else { // Stationary equilibrium plasma. ExB velocity balances diamagnetic drift - phi0 = -Upara0*Pi0/B0/N0; + phi0 = -Upara0 * Pi0 / B0 / N0; } SAVE_ONCE(phi0); } @@ -1066,13 +1088,20 @@ int physics_init(bool restarting) { SAVE_ONCE2(Va, B0); SAVE_ONCE3(Ti0, Te0, N0); + // Create a solver for the Laplacian + phiSolver = Laplacian::create(); + phiSolver->setFlags(phi_flags); + + aparSolver = Laplacian::create(); + aparSolver->setFlags(apar_flags); + /////////////// CHECK VACUUM /////////////////////// // In vacuum region, initial vorticity should equal zero - + ubyn.setLocation(CELL_CENTRE); ubyn.setBoundary("U"); - - if(!restarting) { + + if (!restarting) { // Only if not restarting: Check initial perturbation // Set U to zero where P0 < vacuum_pressure @@ -1082,18 +1111,18 @@ int physics_init(bool restarting) { Field2D logn0 = laplace_alpha * N0; Field3D Ntemp; Ntemp = N0; - ubyn = U*B0/Ntemp; + ubyn = U * B0 / Ntemp; // Phi should be consistent with U if (laplace_alpha <= 0.0) { - phi = invert_laplace(ubyn, phi_flags, NULL)/B0; + phi = phiSolver->solve(ubyn) / B0; } else { - phi = invert_laplace(ubyn, phi_flags, NULL, &logn0, NULL)/B0; + phiSolver->setCoefC(logn0); + phi = phiSolver->solve(ubyn) / B0; } } - /************** SETUP COMMUNICATIONS **************/ - + comms.add(U); comms.add(Ni); comms.add(Ti); @@ -1104,7 +1133,6 @@ int physics_init(bool restarting) { comms.add(Ajpar); } - if (compress0) { comms.add(Vipar); Vepar.setBoundary("Vipar"); @@ -1117,11 +1145,11 @@ int physics_init(bool restarting) { if (diffusion_n4 > 0.0) { tmpN2.setBoundary("Ni"); } - + if (diffusion_ti4 > 0.0) { tmpTi2.setBoundary("Ti"); } - + if (diffusion_te4 > 0.0) { tmpTe2.setBoundary("Te"); } @@ -1140,39 +1168,39 @@ int physics_init(bool restarting) { } // Parallel gradient along perturbed field-line -const Field3D Grad_parP(const Field3D &f, CELL_LOC loc = CELL_DEFAULT) { +const Field3D Grad_parP(const Field3D& f, CELL_LOC loc = CELL_DEFAULT) { TRACE("Grad_parP"); - + Field3D result; - + if (parallel_lagrange || parallel_project) { // Moving stencil locations - + Field3D fp, fm; // Interpolated on + and - y locations - + fp = interpolate(f, Xip_x, Xip_z); fm = interpolate(f, Xim_x, Xim_z); - - Coordinates *coord = mesh->getCoordinates(); - + + Coordinates* coord = mesh->getCoordinates(); + result.allocate(); - for(auto i : result) { - result[i] = (fp[i.yp()] - fm[i.ym()])/(2.*coord->dy[i]*sqrt(coord->g_22[i])); + for (auto i : result) { + result[i] = (fp[i.yp()] - fm[i.ym()]) / (2. * coord->dy[i] * sqrt(coord->g_22[i])); } } else { if (parallel_lr_diff) { // Use left/right biased stencils. NOTE: First order only! if (loc == CELL_YLOW) { - result = Grad_par_CtoL(f); + result = Grad_par_CtoL(f); } else { - result = Grad_par_LtoC(f); + result = Grad_par_LtoC(f); } } else { result = Grad_par(f, loc); } - + if (nonlinear) { - result -= bracket(Psi, f, bm_mag)*B0; + result -= bracket(Psi, f, bm_mag) * B0; } } @@ -1181,118 +1209,114 @@ const Field3D Grad_parP(const Field3D &f, CELL_LOC loc = CELL_DEFAULT) { bool first_run = true; // For printing out some diagnostics first time around -int physics_run(BoutReal t) { +int physics_run(BoutReal UNUSED(t)) { - Coordinates *coord = mesh->getCoordinates(); + Coordinates* coord = mesh->getCoordinates(); // Perform communications mesh->communicate(comms); // Inversion - Pi = Ni*Ti0 + N0 * Ti; - if(nonlinear) { - Pi += Ni*Ti; + Pi = Ni * Ti0 + N0 * Ti; + if (nonlinear) { + Pi += Ni * Ti; } mesh->communicate(Pi); - - Pe = Zi * (Ni*Te0 + N0 * Te); - if(nonlinear) { - Pe += Zi * Ni * Te; + Pe = Zi * (Ni * Te0 + N0 * Te); + if (nonlinear) { + Pe += Zi * Ni * Te; } mesh->communicate(Pe); - P = Tau_ie*Pi + Pe; + P = Tau_ie * Pi + Pe; mesh->communicate(P); // Field2D lap_temp=0.0; Field2D logn0 = laplace_alpha * N0; - ubyn = U*B0/N0; + ubyn = U * B0 / N0; if (diamag) { - ubyn -= Upara0/N0 * Delp2(Pi)/B0; + ubyn -= Upara0 / N0 * Delp2(Pi) / B0; mesh->communicate(ubyn); ubyn.applyBoundary(); } // Invert laplacian for phi - if (laplace_alpha <= 0.0) { - phi = invert_laplace(ubyn, phi_flags, NULL)/B0; - } else { - phi = invert_laplace(ubyn, phi_flags, NULL, &logn0, NULL)/B0; + if (laplace_alpha > 0.0) { + phiSolver->setCoefC(logn0); } - + phi = phiSolver->solve(ubyn) / B0; + mesh->communicate(phi); if (emass) { - static Field2D acoeff; - static bool aset = false; - - if (!aset) { // calculate Apar coefficient - acoeff = -delta_e_inv*N0*N0; - } - aset = true; + Field2D acoeff = -delta_e_inv * N0 * N0; if (compress0) { - Psi = invert_laplace(acoeff*Ajpar-gyroAlv*Vipar, apar_flags, &acoeff); + Psi = aparSolver->solve(acoeff * Ajpar - gyroAlv * Vipar); } else { - Psi = invert_laplace(acoeff*Ajpar, apar_flags, &acoeff); + Psi = aparSolver->solve(acoeff * Ajpar); } mesh->communicate(Psi); } BoutReal N_tmp1; N_tmp1 = Low_limit; - N_tmp = field_larger(N0+Ni, N_tmp1); + N_tmp = field_larger(N0 + Ni, N_tmp1); BoutReal Te_tmp1, Ti_tmp1; Te_tmp1 = Low_limit; Ti_tmp1 = Low_limit; - - Ti_tmp = field_larger(Ti0+Ti, Ti_tmp1); - Te_tmp = field_larger(Te0+Te, Te_tmp1); - + + Ti_tmp = field_larger(Ti0 + Ti, Ti_tmp1); + Te_tmp = field_larger(Te0 + Te, Te_tmp1); + // vac_mask transitions from 0 in core to 1 in vacuum if (nonlinear) { - vac_mask = (1.0 - tanh( ((P0 + P) - vacuum_pressure) / vacuum_trans )) / 2.0; + vac_mask = (1.0 - tanh(((P0 + P) - vacuum_pressure) / vacuum_trans)) / 2.0; // Update resistivity if (spitzer_resist) { // Use Spitzer formula - eta_spitzer = 0.51*1.03e-4*Zi*LnLambda*pow(Te_tmp*Tebar,-1.5); // eta in Ohm-m. ln(Lambda) = 20 - eta_spitzer /= MU0 *Va * Lbar; - //eta_spitzer.applyBoundary(); - //mesh->communicate(eta_spitzer); + eta_spitzer = 0.51 * 1.03e-4 * Zi * LnLambda + * pow(Te_tmp * Tebar, -1.5); // eta in Ohm-m. ln(Lambda) = 20 + eta_spitzer /= MU0 * Va * Lbar; + // eta_spitzer.applyBoundary(); + // mesh->communicate(eta_spitzer); } else { eta = core_resist + (vac_resist - core_resist) * vac_mask; } - nu_e = 2.91e-6*LnLambda*(N_tmp*Nbar*density/1.e6)*pow(Te_tmp*Tebar,-1.5); // nu_e in 1/S. - //nu_e.applyBoundary(); - //mesh->communicate(nu_e); - - if (diffusion_par >0.0) { - //xqx addition, begin + nu_e = 2.91e-6 * LnLambda * (N_tmp * Nbar * density / 1.e6) + * pow(Te_tmp * Tebar, -1.5); // nu_e in 1/S. + // nu_e.applyBoundary(); + // mesh->communicate(nu_e); + + if (diffusion_par > 0.0) { + // xqx addition, begin // Use Spitzer thermal conductivities - - nu_i = 4.80e-8*(Zi*Zi*Zi*Zi/sqrt(AA))*LnLambda*(N_tmp*Nbar*density/1.e6)*pow(Ti_tmp*Tibar,-1.5); // nu_i in 1/S. - vth_i = 9.79e3*sqrt(Ti_tmp*Tibar/AA); // vth_i in m/S. - vth_e = 4.19e5*sqrt(Te_tmp*Tebar); // vth_e in m/S. + + nu_i = 4.80e-8 * (Zi * Zi * Zi * Zi / sqrt(AA)) * LnLambda + * (N_tmp * Nbar * density / 1.e6) + * pow(Ti_tmp * Tibar, -1.5); // nu_i in 1/S. + vth_i = 9.79e3 * sqrt(Ti_tmp * Tibar / AA); // vth_i in m/S. + vth_e = 4.19e5 * sqrt(Te_tmp * Tebar); // vth_e in m/S. } - if (diffusion_par >0.0) { - kappa_par_i=3.9*vth_i*vth_i/nu_i;// * 1.e4; - kappa_par_e=3.2*vth_e*vth_e/nu_e;// * 1.e4; - + if (diffusion_par > 0.0) { + kappa_par_i = 3.9 * vth_i * vth_i / nu_i; // * 1.e4; + kappa_par_e = 3.2 * vth_e * vth_e / nu_e; // * 1.e4; + Field3D kappa_par_i_fl, kappa_par_e_fl; - - kappa_par_i_fl = vth_i * (q95 * Lbar);// * 1.e2; - kappa_par_e_fl = vth_e * (q95 * Lbar);// * 1.e2; - + + kappa_par_i_fl = vth_i * (q95 * Lbar); // * 1.e2; + kappa_par_e_fl = vth_e * (q95 * Lbar); // * 1.e2; + kappa_par_i *= kappa_par_i_fl / (kappa_par_i + kappa_par_i_fl); - kappa_par_i *= Tipara1*N_tmp; - //kappa_par_i.applyBoundary(); - //mesh->communicate(kappa_par_i); + kappa_par_i *= Tipara1 * N_tmp; + // kappa_par_i.applyBoundary(); + // mesh->communicate(kappa_par_i); kappa_par_e *= kappa_par_e_fl / (kappa_par_e + kappa_par_e_fl); - kappa_par_e *= Tepara1*N_tmp*Zi; - //kappa_par_e.applyBoundary(); - //mesh->communicate(kappa_par_e); + kappa_par_e *= Tepara1 * N_tmp * Zi; + // kappa_par_e.applyBoundary(); + // mesh->communicate(kappa_par_e); } } @@ -1300,22 +1324,22 @@ int physics_run(BoutReal t) { Jpar.applyBoundary(); mesh->communicate(Jpar); - if(jpar_bndry_width > 0) { + if (jpar_bndry_width > 0) { // Zero j in boundary regions. Prevents vorticity drive // at the boundary - - for(int i=0;iLocalNy;j++) - for(int k=0;kLocalNz;k++) { - if (mesh->firstX()) - Jpar(i,j,k) = 0.0; - if (mesh->lastX()) - Jpar(mesh->LocalNx-1-i,j,k) = 0.0; - } - } - - // Smooth j in x - if(smooth_j_x) + + for (int i = 0; i < jpar_bndry_width; i++) + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + if (mesh->firstX()) + Jpar(i, j, k) = 0.0; + if (mesh->lastX()) + Jpar(mesh->LocalNx - 1 - i, j, k) = 0.0; + } + } + + // Smooth j in x + if (smooth_j_x) Jpar = smooth_x(Jpar); if (compress0) { @@ -1327,172 +1351,174 @@ int physics_run(BoutReal t) { mesh->communicate(Vepar); } } - - //xqx begin + + // xqx begin // Get Delp2(J) from J Jpar2 = -Delp2(Jpar); Jpar2.applyBoundary(); mesh->communicate(Jpar2); - if(jpar_bndry_width > 0) { + if (jpar_bndry_width > 0) { // Zero jpar2 in boundary regions. Prevents vorticity drive // at the boundary - - for(int i=0;iLocalNy;j++) - for(int k=0;kLocalNz;k++) { - if(mesh->firstX()) - Jpar2(i,j,k) = 0.0; - if(mesh->lastX()) - Jpar2(mesh->LocalNx-1-i,j,k) = 0.0; - } + + for (int i = 0; i < jpar_bndry_width; i++) + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + if (mesh->firstX()) + Jpar2(i, j, k) = 0.0; + if (mesh->lastX()) + Jpar2(mesh->LocalNx - 1 - i, j, k) = 0.0; + } } //////////////////////////////////////////////////// // Parallel electric field { TRACE("ddt(Psi)"); - + ddt(Psi) = 0.0; - + if (spitzer_resist) { - ddt(Psi) = -Grad_parP(B0*phi, CELL_CENTRE) / B0 - eta_spitzer*Jpar; + ddt(Psi) = -Grad_parP(B0 * phi, CELL_CENTRE) / B0 - eta_spitzer * Jpar; } else { - ddt(Psi) = -Grad_parP(B0*phi, CELL_CENTRE) / B0 - eta*Jpar; + ddt(Psi) = -Grad_parP(B0 * phi, CELL_CENTRE) / B0 - eta * Jpar; } - + if (diamag) { - ddt(Psi) -= bracket(B0*phi0, Psi, bm_exb); // Equilibrium flow + ddt(Psi) -= bracket(B0 * phi0, Psi, bm_exb); // Equilibrium flow } - + // Hyper-resistivity if (hyperresist > 0.0) { ddt(Psi) += hyperresist * Delp2(Jpar); } } - + //////////////////////////////////////////////////// // Vorticity equation - + { TRACE("ddt(U)"); - + ddt(U) = 0.0; - ddt(U) = -SQ(B0) * bracket(Psi, J0, bm_mag)*B0; // Grad j term - - ddt(U) += 2.0* Upara1 * b0xcv*Grad(P); // curvature term - - ddt(U) += SQ(B0)*Grad_parP(Jpar, CELL_CENTRE); // b dot grad j - + ddt(U) = -SQ(B0) * bracket(Psi, J0, bm_mag) * B0; // Grad j term + + ddt(U) += 2.0 * Upara1 * b0xcv * Grad(P); // curvature term + + ddt(U) += SQ(B0) * Grad_parP(Jpar, CELL_CENTRE); // b dot grad j + if (diamag) { - ddt(U) -= bracket(B0*phi0, U, bm_exb); // Equilibrium flow + ddt(U) -= bracket(B0 * phi0, U, bm_exb); // Equilibrium flow } - + if (nonlinear) { - ddt(U) -= bracket(B0*phi, U, bm_exb); // Advection + ddt(U) -= bracket(B0 * phi, U, bm_exb); // Advection /*if (compress0) //ddt(U) -= Vipar*Grad_par(U); ddt(U) -= Vpar_Grad_par(Vipar, U);*/ } - - //xqx: parallel hyper-viscous diffusion for vector potential + + // xqx: parallel hyper-viscous diffusion for vector potential if (diffusion_u4 > 0.0) { tmpA2 = Grad2_par2new(Psi); mesh->communicate(tmpA2); tmpA2.applyBoundary(); ddt(U) -= diffusion_u4 * Grad2_par2new(tmpA2); } - - // Viscosity terms + + // Viscosity terms if (viscos_par > 0.0) { ddt(U) += viscos_par * Grad2_par2(U); // Parallel viscosity } - + if (hyperviscos > 0.0) { // Calculate coefficient. - - hyper_mu_x = hyperviscos * coord->g_11*SQ(coord->dx) * abs(coord->g11*D2DX2(U)) / (abs(U) + 1e-3); + + hyper_mu_x = hyperviscos * coord->g_11 * SQ(coord->dx) * abs(coord->g11 * D2DX2(U)) + / (abs(U) + 1e-3); hyper_mu_x.applyBoundary("dirichlet"); // Set to zero on all boundaries - - ddt(U) += hyper_mu_x * coord->g11*D2DX2(U); - + + ddt(U) += hyper_mu_x * coord->g11 * D2DX2(U); + if (first_run) { // Print out maximum values of viscosity used on this processor output.write(" Hyper-viscosity values:\n"); - output.write(" Max mu_x = %e, Max_DC mu_x = %e\n", max(hyper_mu_x), max(DC(hyper_mu_x))); + output.write(" Max mu_x = %e, Max_DC mu_x = %e\n", max(hyper_mu_x), + max(DC(hyper_mu_x))); } } - - // left edge sink terms - if(sink_Ul > 0.0){ - ddt(U) -= sink_Ul*sink_tanhxl(P0,U,su_widthl,su_lengthl); // core sink + + // left edge sink terms + if (sink_Ul > 0.0) { + ddt(U) -= sink_Ul * sink_tanhxl(P0, U, su_widthl, su_lengthl); // core sink } - - // right edge sink terms - if(sink_Ur > 0.0){ - ddt(U) -= sink_Ur*sink_tanhxr(P0,U,su_widthr,su_lengthr); // sol sink + + // right edge sink terms + if (sink_Ur > 0.0) { + ddt(U) -= sink_Ur * sink_tanhxr(P0, U, su_widthr, su_lengthr); // sol sink } } - + /////////////////////////////////////////////// // number density equation { TRACE("ddt(Ni)"); - + ddt(Ni) = 0.0; - - ddt(Ni) -= bracket(B0*phi, N0, bm_exb); - + + ddt(Ni) -= bracket(B0 * phi, N0, bm_exb); + if (diamag) { - ddt(Ni) -= bracket(B0*phi0, Ni, bm_exb); // Equilibrium flow + ddt(Ni) -= bracket(B0 * phi0, Ni, bm_exb); // Equilibrium flow } - + if (nonlinear) { - ddt(Ni) -= bracket(B0*phi, Ni, bm_exb); // Advection + ddt(Ni) -= bracket(B0 * phi, Ni, bm_exb); // Advection } - + if (compress0) { - ddt(Ni) -= N0 * B0 * Grad_parP(Vipar/B0, CELL_CENTRE); + ddt(Ni) -= N0 * B0 * Grad_parP(Vipar / B0, CELL_CENTRE); } - - //M: 4th order Parallel diffusion terms - if(diffusion_n4 > 0.0) { + + // M: 4th order Parallel diffusion terms + if (diffusion_n4 > 0.0) { tmpN2 = Grad2_par2new(Ni); mesh->communicate(tmpN2); tmpN2.applyBoundary(); ddt(Ni) -= diffusion_n4 * Grad2_par2new(tmpN2); } } - + /////////////////////////////////////////////// // ion temperature equation { TRACE("ddt(Ti)"); - + ddt(Ti) = 0.0; - - ddt(Ti) -= bracket(B0*phi, Ti0, bm_exb); - + + ddt(Ti) -= bracket(B0 * phi, Ti0, bm_exb); + if (diamag) { - ddt(Ti) -= bracket(phi0*B0, Ti, bm_exb); // Equilibrium flow + ddt(Ti) -= bracket(phi0 * B0, Ti, bm_exb); // Equilibrium flow } - + if (nonlinear) { - ddt(Ti) -= bracket(phi*B0, Ti, bm_exb); // Advection + ddt(Ti) -= bracket(phi * B0, Ti, bm_exb); // Advection } - + if (compress0) { - ddt(Ti) -= 2.0/3.0 * Ti0 * B0 * Grad_parP(Vipar/B0, CELL_CENTRE); + ddt(Ti) -= 2.0 / 3.0 * Ti0 * B0 * Grad_parP(Vipar / B0, CELL_CENTRE); } - + if (diffusion_par > 0.0) { - ddt(Ti) += kappa_par_i * Grad2_par2(Ti)/N0; // Parallel diffusion - ddt(Ti) += Grad_par(kappa_par_i, CELL_CENTRE) * Grad_par(Ti, CELL_YLOW)/N0; + ddt(Ti) += kappa_par_i * Grad2_par2(Ti) / N0; // Parallel diffusion + ddt(Ti) += Grad_par(kappa_par_i, CELL_CENTRE) * Grad_par(Ti, CELL_YLOW) / N0; } - - //M: 4th order Parallel diffusion terms + + // M: 4th order Parallel diffusion terms if (diffusion_ti4 > 0.0) { tmpTi2 = Grad2_par2new(Ti); mesh->communicate(tmpTi2); @@ -1500,34 +1526,34 @@ int physics_run(BoutReal t) { ddt(Ti) -= diffusion_ti4 * Grad2_par2new(tmpTi2); } } - + /////////////////////////////////////////////// // electron temperature equation - + { TRACE("ddt(Te)"); - + ddt(Te) = 0.0; - - ddt(Te) -= bracket(B0*phi, Te0, bm_exb); - + + ddt(Te) -= bracket(B0 * phi, Te0, bm_exb); + if (diamag) { - ddt(Te) -= bracket(B0*phi0, Te, bm_exb); // Equilibrium flow + ddt(Te) -= bracket(B0 * phi0, Te, bm_exb); // Equilibrium flow } - + if (nonlinear) { - ddt(Te) -= bracket(B0*phi, Te, bm_exb); // Advection + ddt(Te) -= bracket(B0 * phi, Te, bm_exb); // Advection } - + if (compress0) { - ddt(Te) -= 2.0/3.0 * Te0 * B0 * Grad_parP(Vepar/B0, CELL_CENTRE); + ddt(Te) -= 2.0 / 3.0 * Te0 * B0 * Grad_parP(Vepar / B0, CELL_CENTRE); } - + if (diffusion_par > 0.0) { - ddt(Te) += kappa_par_e * Grad2_par2(Te)/N0; // Parallel diffusion - ddt(Te) += Grad_par(kappa_par_e, CELL_CENTRE) * Grad_par(Te, CELL_YLOW)/N0; + ddt(Te) += kappa_par_e * Grad2_par2(Te) / N0; // Parallel diffusion + ddt(Te) += Grad_par(kappa_par_e, CELL_CENTRE) * Grad_par(Te, CELL_YLOW) / N0; } - + if (diffusion_te4 > 0.0) { tmpTe2 = Grad2_par2new(Te); mesh->communicate(tmpTe2); @@ -1535,47 +1561,46 @@ int physics_run(BoutReal t) { ddt(Te) -= diffusion_te4 * Grad2_par2new(tmpTe2); } } - + ////////////////////////////////////////////////////////////////////// - if (compress0) { //parallel velocity equation + if (compress0) { // parallel velocity equation TRACE("ddt(Vipar)"); - + ddt(Vipar) = 0.0; - + ddt(Vipar) -= Vipara * Grad_parP(P, CELL_YLOW) / N0; ddt(Vipar) += Vipara * bracket(Psi, P0, bm_mag) * B0 / N0; - + if (diamag) { - ddt(Vipar) -= bracket(B0*phi0, Vipar, bm_exb); + ddt(Vipar) -= bracket(B0 * phi0, Vipar, bm_exb); } if (nonlinear) { - ddt(Vipar) -= bracket(B0*phi, Vipar, bm_exb); + ddt(Vipar) -= bracket(B0 * phi, Vipar, bm_exb); } - //xqx: parallel hyper-viscous diffusion for vector potential + // xqx: parallel hyper-viscous diffusion for vector potential if (diffusion_v4 > 0.0) { tmpVp2 = Grad2_par2new(Vipar); mesh->communicate(tmpVp2); tmpVp2.applyBoundary(); ddt(Vipar) -= diffusion_v4 * Grad2_par2new(tmpVp2); } - + if (sink_vp > 0.0) { Field2D V0tmp = 0.; - ddt(Vipar) -= sink_vp*sink_tanhxl(V0tmp,Vipar,sp_width,sp_length); // sink + ddt(Vipar) -= sink_vp * sink_tanhxl(V0tmp, Vipar, sp_width, sp_length); // sink } } - /////////////////////////////////////////////////////////////////////// if (filter_z) { // Filter out all except filter_z_mode TRACE("filter_z"); - + ddt(Psi) = filter(ddt(Psi), filter_z_mode); - + ddt(U) = filter(ddt(U), filter_z_mode); ddt(Ni) = filter(ddt(Ni), filter_z_mode); @@ -1594,7 +1619,7 @@ int physics_run(BoutReal t) { if (low_pass_z > 0) { // Low-pass filter, keeping n up to low_pass_z TRACE("low_pass_z"); - + if (!emass) { ddt(Psi) = lowPass(ddt(Psi), low_pass_z, zonal_field); } else { @@ -1607,32 +1632,30 @@ int physics_run(BoutReal t) { ddt(Te) = lowPass(ddt(Te), low_pass_z, zonal_bkgd); ddt(Ni) = lowPass(ddt(Ni), low_pass_z, zonal_bkgd); - if(compress0) { + if (compress0) { ddt(Vipar) = lowPass(ddt(Vipar), low_pass_z, zonal_bkgd); } } - if(damp_width > 0) { - for(int i=0;iLocalNy;j++) - for(int k=0;kLocalNz;k++) { - if(mesh->firstX()) - ddt(U)(i,j,k) -= U(i,j,k) / damp_t_const; - if(mesh->lastX()) - ddt(U)(mesh->LocalNx-1-i,j,k) -= U(mesh->LocalNx-1-i,j,k) / damp_t_const; - } + if (damp_width > 0) { + for (int i = 0; i < damp_width; i++) { + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + if (mesh->firstX()) + ddt(U)(i, j, k) -= U(i, j, k) / damp_t_const; + if (mesh->lastX()) + ddt(U)(mesh->LocalNx - 1 - i, j, k) -= + U(mesh->LocalNx - 1 - i, j, k) / damp_t_const; + } } } - if (filter_nl >0) { + if (filter_nl > 0) { TRACE("filter_nl"); - ddt(Ni) = nl_filter( ddt(Ni), filter_nl); + ddt(Ni) = nl_filter(ddt(Ni), filter_nl); } first_run = false; return 0; } - - - diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index abecb78e80..7d3e6bcd40 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -4,35 +4,36 @@ * Basically the same as Hazeltine-Meiss but different normalisations. * Can also include the Vpar compressional term *******************************************************************************/ - + +#include #include +#include +#include #include +#include #include #include -#include -#include -#include -#include -#include #include +#include #include #include // 2D inital profiles -Field2D J0, P0; // Current and pressure -Vector2D b0xcv; // Curvature term -Field2D beta, gradparB; // Used for Vpar terms -Field2D phi0; // When diamagnetic terms used -Field2D U0, Psixy, x; //0th vorticity of equilibrium flow, -//radial flux coordinate, normalized radial flux coordinate +Field2D J0, P0; // Current and pressure +Vector2D b0xcv; // Curvature term +Field2D beta, gradparB; // Used for Vpar terms +Field2D phi0; // When diamagnetic terms used +Field2D U0, Psixy, x; // 0th vorticity of equilibrium flow, +// radial flux coordinate, normalized radial flux coordinate bool constn0; -BoutReal n0_height, n0_ave, n0_width, n0_center, n0_bottom_x, Nbar, Tibar, Tebar; //the total height, average width and center of profile of N0 -BoutReal Tconst; //the ampitude of congstant temperature -//Field3D sourp; +// the total height, average width and center of profile of N0 +BoutReal n0_height, n0_ave, n0_width, n0_center, n0_bottom_x, Nbar, Tibar, Tebar; + +BoutReal Tconst; // the ampitude of constant temperature -Field2D N0,Ti0,Te0,Ne0; // number density and temperature +Field2D N0, Ti0, Te0, Ne0; // number density and temperature Field2D Pi0, Pe0; Field2D q95; Field3D ubyn; @@ -44,7 +45,7 @@ BoutReal Zi; // charge number of ion Vector2D B0vec; // B0 field vector // V0 field vectors -Vector2D V0net; //net flow +Vector2D V0net; // net flow // 3D evolving variables Field3D U, Psi, P, Vpar; @@ -62,39 +63,39 @@ Field3D tmpA2; // Grad2_par2new of Parallel vector potential Field3D C_phi; // Parameters -BoutReal density; // Number density [m^-3] +BoutReal density; // Number density [m^-3] BoutReal Bbar, Lbar, Tbar, Va; // Normalisation constants -BoutReal dnorm; // For diamagnetic terms: 1 / (2. * wci * Tbar) -BoutReal dia_fact; // Multiply diamagnetic term by this -BoutReal delta_i; // Normalized ion skin depth -BoutReal omega_i; // ion gyrofrequency - -BoutReal diffusion_p4; //xqx: parallel hyper-viscous diffusion for pressure -BoutReal diffusion_u4; //xqx: parallel hyper-viscous diffusion for vorticity -BoutReal diffusion_a4; //xqx: parallel hyper-viscous diffusion for vector potential - -BoutReal diffusion_par; // Parallel pressure diffusion -BoutReal heating_P; // heating power in pressure -BoutReal hp_width; // heating profile radial width in pressure -BoutReal hp_length; // heating radial domain in pressure -BoutReal sink_P; // sink in pressure -BoutReal sp_width; // sink profile radial width in pressure -BoutReal sp_length; // sink radial domain in pressure - -BoutReal sink_Ul; // left edge sink in vorticity -BoutReal su_widthl; // left edge sink profile radial width in vorticity -BoutReal su_lengthl; // left edge sink radial domain in vorticity - -BoutReal sink_Ur; // right edge sink in vorticity -BoutReal su_widthr; // right edge sink profile radial width in vorticity -BoutReal su_lengthr; // right edge sink radial domain in vorticity +BoutReal dnorm; // For diamagnetic terms: 1 / (2. * wci * Tbar) +BoutReal dia_fact; // Multiply diamagnetic term by this +BoutReal delta_i; // Normalized ion skin depth +BoutReal omega_i; // ion gyrofrequency + +BoutReal diffusion_p4; // xqx: parallel hyper-viscous diffusion for pressure +BoutReal diffusion_u4; // xqx: parallel hyper-viscous diffusion for vorticity +BoutReal diffusion_a4; // xqx: parallel hyper-viscous diffusion for vector potential + +BoutReal diffusion_par; // Parallel pressure diffusion +BoutReal heating_P; // heating power in pressure +BoutReal hp_width; // heating profile radial width in pressure +BoutReal hp_length; // heating radial domain in pressure +BoutReal sink_P; // sink in pressure +BoutReal sp_width; // sink profile radial width in pressure +BoutReal sp_length; // sink radial domain in pressure + +BoutReal sink_Ul; // left edge sink in vorticity +BoutReal su_widthl; // left edge sink profile radial width in vorticity +BoutReal su_lengthl; // left edge sink radial domain in vorticity + +BoutReal sink_Ur; // right edge sink in vorticity +BoutReal su_widthr; // right edge sink profile radial width in vorticity +BoutReal su_lengthr; // right edge sink radial domain in vorticity BoutReal viscos_par; // Parallel viscosity BoutReal viscos_perp; // Perpendicular viscosity BoutReal hyperviscos; // Hyper-viscosity (radial) -Field3D hyper_mu_x; // Hyper-viscosity coefficient +Field3D hyper_mu_x; // Hyper-viscosity coefficient -Field3D Dperp2Phi0, Dperp2Phi, GradPhi02, GradPhi2; //Temporary variables for gyroviscous +Field3D Dperp2Phi0, Dperp2Phi, GradPhi02, GradPhi2; // Temporary variables for gyroviscous Field3D GradparPhi02, GradparPhi2, GradcPhi, GradcparPhi; Field3D Dperp2Pi0, Dperp2Pi, bracketPhi0P, bracketPhiP0, bracketPhiP; BoutReal Upara2; @@ -109,14 +110,14 @@ Field3D vac_mask; int phi_flags, apar_flags; bool nonlinear; -bool evolve_jpar; +bool evolve_jpar; BoutReal g; // Only if compressible bool phi_curv; // Poisson brackets: b0 x Grad(f) dot Grad(g) / B = [f, g] -// Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE +// Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE /* - * Bracket method + * Bracket method * * BRACKET_STD - Same as b0xGrad_dot_Grad, methods in BOUT.inp * BRACKET_SIMPLE - Subset of terms, used in BOUT-06 @@ -125,7 +126,7 @@ bool phi_curv; * */ -// Bracket method for advection terms +// Bracket method for advection terms BRACKET_METHOD bm_exb; BRACKET_METHOD bm_mag; int bm_exb_flag; @@ -140,21 +141,21 @@ bool diamag_phi0; // Include the diamagnetic equilibrium phi0 bool eHall; BoutReal AA; // ion mass in units of the proton mass; AA=Mi/Mp -//net flow, Er=-R*Bp*Dphi0,Dphi0=-D_min-0.5*D_0*(1.0-tanh(D_s*(x-x0))) -Field2D V0; //net flow amplitude -Field2D Dphi0; //differential potential to flux -BoutReal D_0; // potential amplitude -BoutReal D_s; // shear parameter -BoutReal x0; //velocity peak location -BoutReal sign; //direction of flow -BoutReal Psiaxis, Psibndry; -bool withflow; -bool K_H_term; //Kelvin-Holmhotz term -Field2D perp; //for test -BoutReal D_min; //constant in flow - -//for C_mod -bool experiment_Er; //read in total Er from experiment +// net flow, Er=-R*Bp*Dphi0,Dphi0=-D_min-0.5*D_0*(1.0-tanh(D_s*(x-x0))) +Field2D V0; // net flow amplitude +Field2D Dphi0; // differential potential to flux +BoutReal D_0; // potential amplitude +BoutReal D_s; // shear parameter +BoutReal x0; // velocity peak location +BoutReal sign; // direction of flow +BoutReal Psiaxis, Psibndry; +bool withflow; +bool K_H_term; // Kelvin-Holmhotz term +Field2D perp; // for test +BoutReal D_min; // constant in flow + +// for C_mod +bool experiment_Er; // read in total Er from experiment bool nogradparj; bool filter_z; @@ -165,9 +166,9 @@ int zonal_field; int zonal_bkgd; bool relax_j_vac; BoutReal relax_j_tconst; // Time-constant for j relax -Field3D Psitarget; // The (moving) target to relax to +Field3D Psitarget; // The (moving) target to relax to -bool smooth_j_x; // Smooth Jpar in the x direction +bool smooth_j_x; // Smooth Jpar in the x direction int jpar_bndry_width; // Zero jpar in a boundary region @@ -175,122 +176,128 @@ bool sheath_boundaries; // Apply sheath boundaries in Y bool parallel_lr_diff; // Use left and right shifted stencils for parallel differences -bool phi_constraint; // Solver for phi using a solver constraint +bool phi_constraint; // Solver for phi using a solver constraint -bool include_rmp; // Include RMP coil perturbation -bool simple_rmp; // Just use a simple form for the perturbation -int rmp_n, rmp_m; // toroidal and poloidal mode numbers +bool include_rmp; // Include RMP coil perturbation +bool simple_rmp; // Just use a simple form for the perturbation +int rmp_n, rmp_m; // toroidal and poloidal mode numbers BoutReal rmp_polwid; // Poloidal width (-ve -> full, fraction of 2pi) BoutReal rmp_polpeak; // Peak poloidal location (fraction of 2pi) BoutReal rmp_factor; // Multiply amplitude by this factor BoutReal rmp_ramp; // Ramp-up time for RMP [s]. negative -> instant BoutReal rmp_freq; // Amplitude oscillation frequency [Hz] (negative -> no oscillation) BoutReal rmp_rotate; // Rotation rate [Hz] -bool rmp_vac_mask; // Should a vacuum mask be applied? -Field3D rmp_Psi0; // Parallel vector potential from Resonant Magnetic Perturbation (RMP) coils -Field3D rmp_Psi; // Value used in calculations +bool rmp_vac_mask; // Should a vacuum mask be applied? +Field3D + rmp_Psi0; // Parallel vector potential from Resonant Magnetic Perturbation (RMP) coils +Field3D rmp_Psi; // Value used in calculations Field3D rmp_dApdt; // Time variation -BoutReal vac_lund, core_lund; // Lundquist number S = (Tau_R / Tau_A). -ve -> infty -BoutReal vac_resist, core_resist; // The resistivities (just 1 / S) -Field3D eta; // Resistivity profile (1 / S) -bool spitzer_resist; // Use Spitzer formula for resistivity -BoutReal Zeff; // Z effective for resistivity formula +BoutReal vac_lund, core_lund; // Lundquist number S = (Tau_R / Tau_A). -ve -> infty +BoutReal vac_resist, core_resist; // The resistivities (just 1 / S) +Field3D eta; // Resistivity profile (1 / S) +bool spitzer_resist; // Use Spitzer formula for resistivity +BoutReal Zeff; // Z effective for resistivity formula -BoutReal hyperresist; // Hyper-resistivity coefficient (in core only) -BoutReal ehyperviscos; // electron Hyper-viscosity coefficient +BoutReal hyperresist; // Hyper-resistivity coefficient (in core only) +BoutReal ehyperviscos; // electron Hyper-viscosity coefficient -int damp_width; // Width of inner damped region -BoutReal damp_t_const; // Timescale of damping +int damp_width; // Width of inner damped region +BoutReal damp_t_const; // Timescale of damping // Metric coefficients Field2D Rxy, Bpxy, Btxy, B0, hthe; Field2D I; // Shear factor -const BoutReal MU0 = 4.0e-7*PI; -const BoutReal Mi = 2.0*1.6726e-27; // Ion mass -const BoutReal Me = 9.1094e-31; // Electron mass -const BoutReal mi_me = Mi/Me; +const BoutReal MU0 = 4.0e-7 * PI; +const BoutReal Mi = 2.0 * 1.6726e-27; // Ion mass +const BoutReal Me = 9.1094e-31; // Electron mass +const BoutReal mi_me = Mi / Me; // Communication objects FieldGroup comms; +/// Solver for inverting Laplacian +Laplacian* phiSolver; +Laplacian* aparSolver; + int precon(BoutReal t, BoutReal cj, BoutReal delta); // Preconditioner -int jacobian(BoutReal t); // Jacobian-vector multiply +int jacobian(BoutReal t); // Jacobian-vector multiply -int precon_phi(BoutReal t, BoutReal cj, BoutReal delta); // Preconditioner with phi constraint +int precon_phi(BoutReal t, BoutReal cj, + BoutReal delta); // Preconditioner with phi constraint -const Field3D Grad2_par2new(const Field3D &f); //for 4th order diffusion +const Field3D Grad2_par2new(const Field3D& f); // for 4th order diffusion -const Field2D N0tanh(BoutReal n0_height, BoutReal n0_ave, BoutReal n0_width, BoutReal n0_center, BoutReal n0_bottom_x) { +const Field2D N0tanh(BoutReal n0_height, BoutReal n0_ave, BoutReal n0_width, + BoutReal n0_center, BoutReal n0_bottom_x) { Field2D result; result.allocate(); - BoutReal Grid_NX, Grid_NXlimit; //the grid number on x, and the + BoutReal Grid_NX, Grid_NXlimit; // the grid number on x, and the BoutReal Jysep; mesh->get(Grid_NX, "nx"); mesh->get(Jysep, "jyseps1_1"); - Grid_NXlimit = n0_bottom_x * Grid_NX; + Grid_NXlimit = n0_bottom_x * Grid_NX; output.write("Jysep1_1 = %i Grid number = %e\n", int(Jysep), Grid_NX); - - if (Jysep > 0.) { //for single null geometry + + if (Jysep > 0.) { // for single null geometry BoutReal Jxsep, Jysep2; mesh->get(Jxsep, "ixseps1"); mesh->get(Jysep2, "jyseps2_2"); - //output.write("Jysep2_2 = %i Ixsep1 = %i\n", int(Jysep2), int(Jxsep)); - - for(auto i : result) { + // output.write("Jysep2_2 = %i Ixsep1 = %i\n", int(Jysep2), int(Jxsep)); + + for (auto i : result) { BoutReal mgx = mesh->GlobalX(i.x()); - BoutReal xgrid_num = (Jxsep+1.)/Grid_NX; - //output.write("mgx = %e xgrid_num = %e\n", mgx); - + BoutReal xgrid_num = (Jxsep + 1.) / Grid_NX; + // output.write("mgx = %e xgrid_num = %e\n", mgx); + int globaly = mesh->YGLOBAL(i.y()); - //output.write("local y = %i; global y: %i\n", i.y, globaly); - if ( mgx > xgrid_num || (globaly<=int(Jysep)-4) || (globaly>int(Jysep2)) ) + // output.write("local y = %i; global y: %i\n", i.y, globaly); + if (mgx > xgrid_num || (globaly <= int(Jysep) - 4) || (globaly > int(Jysep2))) mgx = xgrid_num; BoutReal rlx = mgx - n0_center; - BoutReal temp = exp(rlx/n0_width); + BoutReal temp = exp(rlx / n0_width); BoutReal dampr = ((temp - 1.0 / temp) / (temp + 1.0 / temp)); - result[i] = 0.5*(1.0 - dampr) * n0_height + n0_ave; + result[i] = 0.5 * (1.0 - dampr) * n0_height + n0_ave; } - } else { //circular geometry - for(auto i : result) { + } else { // circular geometry + for (auto i : result) { BoutReal mgx = mesh->GlobalX(i.x()); - BoutReal xgrid_num = Grid_NXlimit/Grid_NX; + BoutReal xgrid_num = Grid_NXlimit / Grid_NX; if (mgx > xgrid_num) mgx = xgrid_num; BoutReal rlx = mgx - n0_center; - BoutReal temp = exp(rlx/n0_width); + BoutReal temp = exp(rlx / n0_width); BoutReal dampr = ((temp - 1.0 / temp) / (temp + 1.0 / temp)); - result[i] = 0.5*(1.0 - dampr) * n0_height + n0_ave; + result[i] = 0.5 * (1.0 - dampr) * n0_height + n0_ave; } } - + mesh->communicate(result); return result; } - /*! * This function implements d2/dy2 where y is the poloidal coordinate theta */ -const Field3D Grad2_par2new(const Field3D &f) { +const Field3D Grad2_par2new(const Field3D& f) { TRACE("Grad2_par2new( Field3D )"); Field3D result = D2DY2(f); - + #ifdef TRACK - result.name = "Grad2_par2new("+f.name+")"; + result.name = "Grad2_par2new(" + f.name + ")"; #endif - + return result; } int physics_init(bool restarting) { bool noshear; - - Coordinates *metric = mesh->getCoordinates(); + + Coordinates* metric = mesh->getCoordinates(); output.write("Solving high-beta flute reduced equations\n"); output.write("\tFile : %s\n", __FILE__); @@ -304,69 +311,70 @@ int physics_init(bool restarting) { mesh->get(P0, "pressure"); // Pascals // Load curvature term - b0xcv.covariant = false; // Read contravariant components + b0xcv.covariant = false; // Read contravariant components mesh->get(b0xcv, "bxcv"); // mixed units x: T y: m^-2 z: m^-2 // Load metrics - if(mesh->get(Rxy, "Rxy")) { // m + if (mesh->get(Rxy, "Rxy")) { // m output_error.write("Error: Cannot read Rxy from grid\n"); return 1; } - if(mesh->get(Bpxy, "Bpxy")) { // T + if (mesh->get(Bpxy, "Bpxy")) { // T output_error.write("Error: Cannot read Bpxy from grid\n"); return 1; } - mesh->get(Btxy, "Btxy"); // T - mesh->get(B0, "Bxy"); // T - mesh->get(hthe, "hthe"); // m - mesh->get(I, "sinty");// m^-2 T^-1 - mesh->get(Psixy, "psixy");//get Psi - mesh->get(Psiaxis,"psi_axis");//axis flux - mesh->get(Psibndry,"psi_bndry");//edge flux + mesh->get(Btxy, "Btxy"); // T + mesh->get(B0, "Bxy"); // T + mesh->get(hthe, "hthe"); // m + mesh->get(I, "sinty"); // m^-2 T^-1 + mesh->get(Psixy, "psixy"); // get Psi + mesh->get(Psiaxis, "psi_axis"); // axis flux + mesh->get(Psibndry, "psi_bndry"); // edge flux ////////////////////////////////////////////////////////////// // Read parameters from the options file - // + // // Options.get ( NAME, VARIABLE, DEFAULT VALUE) // // or if NAME = "VARIABLE" then just // - // OPTION(VARIABLE, DEFAULT VALUE) + // OPTION(VARIABLE, DEFAULT VALUE) // // Prints out what values are assigned ///////////////////////////////////////////////////////////// - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("highbeta"); + auto globalOptions = Options::root(); + auto options = globalOptions["highbeta"]; - OPTION(options, constn0, true); - OPTION(options, n0_fake_prof, false); //use the hyperbolic profile of n0. If both n0_fake_prof and T0_fake_prof are false, use the profiles from grid file - OPTION(options, n0_height, 0.4); //the total height of profile of N0, in percentage of Ni_x - OPTION(options, n0_ave, 0.01); //the center or average of N0, in percentage of Ni_x - OPTION(options, n0_width, 0.1); //the width of the gradient of N0,in percentage of x - OPTION(options, n0_center, 0.633); //the grid number of the center of N0, in percentage of x - OPTION(options, n0_bottom_x, 0.81); //the start of flat region of N0 on SOL side, in percentage of x - OPTION(options, T0_fake_prof, false); - OPTION(options, Tconst, -1.0); //the amplitude of constant temperature, in percentage + OPTION(options, constn0, true); + OPTION(options, n0_fake_prof, false); // use the hyperbolic profile of n0. If both n0_fake_prof and + // T0_fake_prof are false, use the profiles from grid file + OPTION(options, n0_height, 0.4); // the total height of profile of N0, in percentage of Ni_x + OPTION(options, n0_ave, 0.01); // the center or average of N0, in percentage of Ni_x + OPTION(options, n0_width, 0.1); // the width of the gradient of N0,in percentage of x + OPTION(options, n0_center, 0.633); // the grid number of the center of N0, in percentage of x + OPTION(options, n0_bottom_x, 0.81); // the start of flat region of N0 on SOL side, in percentage of x + OPTION(options, T0_fake_prof, false); + OPTION(options, Tconst, -1.0); // the amplitude of constant temperature, in percentage - OPTION(options, density, 1.0e19); // Number density [m^-3] + OPTION(options, density, 1.0e19); // Number density [m^-3] - OPTION(options, evolve_jpar, false); // If true, evolve J raher than Psi - OPTION(options, phi_constraint, false); // Use solver constraint for phi + OPTION(options, evolve_jpar, false); // If true, evolve J raher than Psi + OPTION(options, phi_constraint, false); // Use solver constraint for phi // Effects to include/exclude OPTION(options, include_curvature, true); - OPTION(options, include_jpar0, true); - OPTION(options, evolve_pressure, true); - OPTION(options, nogradparj, false); - - OPTION(options, compress0, false); - OPTION(options, gyroviscous, false); - OPTION(options, nonlinear, false); + OPTION(options, include_jpar0, true); + OPTION(options, evolve_pressure, true); + OPTION(options, nogradparj, false); + + OPTION(options, compress0, false); + OPTION(options, gyroviscous, false); + OPTION(options, nonlinear, false); - // option for ExB Poisson Bracket - OPTION(options, bm_exb_flag, 0); - switch(bm_exb_flag) { + // option for ExB Poisson Bracket + OPTION(options, bm_exb_flag, 0); + switch (bm_exb_flag) { case 0: { bm_exb = BRACKET_STD; output << "\tBrackets for ExB: default differencing\n"; @@ -393,8 +401,8 @@ int physics_init(bool restarting) { } // option for magnetic flutter Poisson Bracket - OPTION(options, bm_mag_flag, 0); - switch(bm_mag_flag) { + OPTION(options, bm_mag_flag, 0); + switch (bm_mag_flag) { case 0: { bm_mag = BRACKET_STD; output << "\tBrackets: default differencing\n"; @@ -420,39 +428,39 @@ int physics_init(bool restarting) { return 1; } - OPTION(options, eHall, false); // electron Hall or electron parallel pressue gradient effects? - OPTION(options, AA, 1.0); // ion mass in units of proton mass + OPTION(options, eHall, false); // electron Hall or electron parallel pressue gradient effects? + OPTION(options, AA, 1.0); // ion mass in units of proton mass - OPTION(options, diamag, false); // Diamagnetic effects? - OPTION(options, diamag_grad_t, diamag); // Grad_par(Te) term in Psi equation - OPTION(options, diamag_phi0, diamag); // Include equilibrium phi0 - OPTION(options, dia_fact, 1.0); // Scale diamagnetic effects by this factor - - OPTION(options, withflow, false); //withflow or not - OPTION(options, K_H_term, true); //keep K-H term - OPTION(options, D_0, 0.0); // velocity magnitude - OPTION(options, D_s, 0.0); // flowshear - OPTION(options, x0, 0.0); //flow location - OPTION(options, sign, 1.0); //flow direction, -1 means negative electric field - OPTION(options, D_min, 3000.0); //a constant + OPTION(options, diamag, false); // Diamagnetic effects? + OPTION(options, diamag_grad_t, diamag); // Grad_par(Te) term in Psi equation + OPTION(options, diamag_phi0, diamag); // Include equilibrium phi0 + OPTION(options, dia_fact, 1.0); // Scale diamagnetic effects by this factor - OPTION(options, experiment_Er, false); + OPTION(options, withflow, false); // withflow or not + OPTION(options, K_H_term, true); // keep K-H term + OPTION(options, D_0, 0.0); // velocity magnitude + OPTION(options, D_s, 0.0); // flowshear + OPTION(options, x0, 0.0); // flow location + OPTION(options, sign, 1.0); // flow direction, -1 means negative electric field + OPTION(options, D_min, 3000.0); // a constant - OPTION(options, noshear, false); + OPTION(options, experiment_Er, false); + + OPTION(options, noshear, false); + + OPTION(options, relax_j_vac, false); // Relax vacuum current to zero + OPTION(options, relax_j_tconst, 0.1); - OPTION(options, relax_j_vac, false); // Relax vacuum current to zero - OPTION(options, relax_j_tconst, 0.1); - // Toroidal filtering - OPTION(options, filter_z, false); // Filter a single n - OPTION(options, filter_z_mode, 1); - OPTION(options, low_pass_z, -1); // Low-pass filter - OPTION(options, zonal_flow, -1); // zonal flow filter - OPTION(options, zonal_field, -1); // zonal field filter - OPTION(options, zonal_bkgd, -1); // zonal background P filter + OPTION(options, filter_z, false); // Filter a single n + OPTION(options, filter_z_mode, 1); + OPTION(options, low_pass_z, -1); // Low-pass filter + OPTION(options, zonal_flow, -1); // zonal flow filter + OPTION(options, zonal_field, -1); // zonal field filter + OPTION(options, zonal_bkgd, -1); // zonal background P filter // Radial smoothing - OPTION(options, smooth_j_x, false); // Smooth Jpar in x + OPTION(options, smooth_j_x, false); // Smooth Jpar in x // Jpar boundary region OPTION(options, jpar_bndry_width, -1); @@ -463,518 +471,519 @@ int physics_init(bool restarting) { OPTION(options, parallel_lr_diff, false); // RMP-related options - OPTION(options, include_rmp, false); // Read RMP data from grid - - OPTION(options, simple_rmp, false); // Include a simple RMP model - OPTION(options, rmp_factor, 1.0); - OPTION(options, rmp_ramp, -1.0); - OPTION(options, rmp_freq, -1.0); - OPTION(options, rmp_rotate, 0.0); + OPTION(options, include_rmp, false); // Read RMP data from grid + + OPTION(options, simple_rmp, false); // Include a simple RMP model + OPTION(options, rmp_factor, 1.0); + OPTION(options, rmp_ramp, -1.0); + OPTION(options, rmp_freq, -1.0); + OPTION(options, rmp_rotate, 0.0); // Vacuum region control - OPTION(options, vacuum_pressure, 0.02); // Fraction of peak pressure - OPTION(options, vacuum_trans, 0.005); // Transition width in pressure - + OPTION(options, vacuum_pressure, 0.02); // Fraction of peak pressure + OPTION(options, vacuum_trans, 0.005); // Transition width in pressure + // Resistivity and hyper-resistivity options - OPTION(options, vac_lund, 0.0); // Lundquist number in vacuum region - OPTION(options, core_lund, 0.0); // Lundquist number in core region - OPTION(options, hyperresist, -1.0); - OPTION(options, ehyperviscos, -1.0); - OPTION(options, spitzer_resist, false); // Use Spitzer resistivity - OPTION(options, Zeff, 2.0); // Z effective + OPTION(options, vac_lund, 0.0); // Lundquist number in vacuum region + OPTION(options, core_lund, 0.0); // Lundquist number in core region + OPTION(options, hyperresist, -1.0); + OPTION(options, ehyperviscos, -1.0); + OPTION(options, spitzer_resist, false); // Use Spitzer resistivity + OPTION(options, Zeff, 2.0); // Z effective // Inner boundary damping - OPTION(options, damp_width, 0); - OPTION(options, damp_t_const, 0.1); + OPTION(options, damp_width, 0); + OPTION(options, damp_t_const, 0.1); // Viscosity and hyper-viscosity - OPTION(options, viscos_par, -1.0); // Parallel viscosity - OPTION(options, viscos_perp, -1.0); // Perpendicular viscosity - OPTION(options, hyperviscos, -1.0); // Radial hyperviscosity - + OPTION(options, viscos_par, -1.0); // Parallel viscosity + OPTION(options, viscos_perp, -1.0); // Perpendicular viscosity + OPTION(options, hyperviscos, -1.0); // Radial hyperviscosity + // parallel pressure diffusion - OPTION(options, diffusion_par, -1.0); // Parallel pressure diffusion - OPTION(options, diffusion_p4, -1.0); //xqx: parallel hyper-viscous diffusion for pressure - OPTION(options, diffusion_u4, -1.0); //xqx: parallel hyper-viscous diffusion for vorticity - OPTION(options, diffusion_a4, -1.0); //xqx: parallel hyper-viscous diffusion for vector potential + OPTION(options, diffusion_par, -1.0); // Parallel pressure diffusion + OPTION(options, diffusion_p4, -1.0); // xqx: parallel hyper-viscous diffusion for pressure + OPTION(options, diffusion_u4, -1.0); // xqx: parallel hyper-viscous diffusion for vorticity + OPTION(options, diffusion_a4, -1.0); // xqx: parallel hyper-viscous diffusion for vector potential // heating factor in pressure - OPTION(options, heating_P, -1.0); // heating power in pressure - OPTION(options, hp_width, 0.1); // the percentage of radial grid points for heating profile radial width in pressure - OPTION(options, hp_length, 0.04); // the percentage of radial grid points for heating profile radial domain in pressure + OPTION(options, heating_P, -1.0); // heating power in pressure + OPTION(options, hp_width, 0.1); // the percentage of radial grid points for heating + // profile radial width in pressure + OPTION(options, hp_length, 0.04); // the percentage of radial grid points for heating + // profile radial domain in pressure // sink factor in pressure - OPTION(options, sink_P, -1.0); // sink in pressure - OPTION(options, sp_width, 0.05); // the percentage of radial grid points for sink profile radial width in pressure - OPTION(options, sp_length, 0.04); // the percentage of radial grid points for sink profile radial domain in pressure - + OPTION(options, sink_P, -1.0); // sink in pressure + OPTION(options, sp_width, 0.05); // the percentage of radial grid points for sink + // profile radial width in pressure + OPTION(options, sp_length, 0.04); // the percentage of radial grid points for sink + // profile radial domain in pressure // left edge sink factor in vorticity - OPTION(options, sink_Ul, -1.0); // left edge sink in vorticity - OPTION(options, su_widthl, 0.06); // the percentage of left edge radial grid points for sink profile radial width in vorticity - OPTION(options, su_lengthl, 0.15); // the percentage of left edge radial grid points for sink profile radial domain in vorticity + OPTION(options, sink_Ul, -1.0); // left edge sink in vorticity + OPTION(options, su_widthl, 0.06); // the percentage of left edge radial grid points for + // sink profile radial width in vorticity + OPTION(options, su_lengthl, 0.15); // the percentage of left edge radial grid points + // for sink profile radial domain in vorticity // right edge sink factor in vorticity - OPTION(options, sink_Ur, -1.0); // right edge sink in vorticity - OPTION(options, su_widthr, 0.06); // the percentage of right edge radial grid points for sink profile radial width in vorticity - OPTION(options, su_lengthr, 0.15); // the percentage of right edge radial grid points for sink profile radial domain in vorticity + OPTION(options, sink_Ur, -1.0); // right edge sink in vorticity + OPTION(options, su_widthr, 0.06); // the percentage of right edge radial grid points + // for sink profile radial width in vorticity + OPTION(options, su_lengthr, 0.15); // the percentage of right edge radial grid points + // for sink profile radial domain in vorticity // Compressional terms - OPTION(options, phi_curv, true); - options->get("gamma", g, 5.0/3.0); - + OPTION(options, phi_curv, true); + g = options["gamma"].withDefault(5.0 / 3.0); + // Field inversion flags - OPTION(options, phi_flags, 0); - OPTION(options, apar_flags, 0); - - x=(Psixy-Psiaxis)/(Psibndry-Psiaxis); - - if(experiment_Er){ //get er from experiment - mesh->get(Dphi0,"Epsi"); - diamag_phi0=false; - K_H_term=false; + OPTION(options, phi_flags, 0); + OPTION(options, apar_flags, 0); + + x = (Psixy - Psiaxis) / (Psibndry - Psiaxis); + + if (experiment_Er) { // get er from experiment + mesh->get(Dphi0, "Epsi"); + diamag_phi0 = false; + K_H_term = false; } else { - Dphi0=-D_min-0.5*D_0*(1.0-tanh(D_s*(x-x0))); + Dphi0 = -D_min - 0.5 * D_0 * (1.0 - tanh(D_s * (x - x0))); } - if(sign<0) //change flow direction - Dphi0*=-1; + if (sign < 0) // change flow direction + Dphi0 *= -1; - V0=-Rxy*Bpxy*Dphi0/B0; - - if(simple_rmp) + V0 = -Rxy * Bpxy * Dphi0 / B0; + + if (simple_rmp) include_rmp = true; - if(include_rmp) { - // Including external field coils. - if(simple_rmp) { + if (include_rmp) { + // Including external field coils. + if (simple_rmp) { // Use a fairly simple form for the perturbation Field2D pol_angle; - if(mesh->get(pol_angle, "pol_angle")) { - output_warn.write(" ***WARNING: need poloidal angle for simple RMP\n"); - include_rmp = false; - }else { - OPTION(options, rmp_n, 3); - OPTION(options, rmp_m, 9); - OPTION(options, rmp_polwid, -1.0); - OPTION(options, rmp_polpeak, 0.5); + if (mesh->get(pol_angle, "pol_angle")) { + output_warn.write(" ***WARNING: need poloidal angle for simple RMP\n"); + include_rmp = false; + } else { + OPTION(options, rmp_n, 3); + OPTION(options, rmp_m, 9); + OPTION(options, rmp_polwid, -1.0); + OPTION(options, rmp_polpeak, 0.5); OPTION(options, rmp_vac_mask, true); - // Divide n by the size of the domain - int zperiod; - globalOptions->get("zperiod", zperiod, 1); - if((rmp_n % zperiod) != 0) - output_warn.write(" ***WARNING: rmp_n (%d) not a multiple of zperiod (%d)\n", rmp_n, zperiod); - - output.write("\tMagnetic perturbation: n = %d, m = %d, magnitude %e Tm\n", - rmp_n, rmp_m, rmp_factor); - - rmp_Psi0 = 0.0; - if(mesh->lastX()) { - // Set the outer boundary - for(int jx=mesh->LocalNx-4;jxLocalNx;jx++) - for(int jy=0;jyLocalNy;jy++) - for(int jz=0;jzLocalNz;jz++) { - - BoutReal angle = rmp_m * pol_angle(jx,jy) + rmp_n * ((BoutReal) jz) * mesh->getCoordinates()->dz; - rmp_Psi0(jx,jy,jz) = (((BoutReal)(jx - 4)) / ((BoutReal)(mesh->LocalNx - 5))) * rmp_factor * cos(angle); - if(rmp_polwid > 0.0) { + // Divide n by the size of the domain + int zperiod = globalOptions["zperiod"].withDefault(1); + if ((rmp_n % zperiod) != 0) + output_warn.write(" ***WARNING: rmp_n (%d) not a multiple of zperiod (%d)\n", rmp_n, + zperiod); + + output.write("\tMagnetic perturbation: n = %d, m = %d, magnitude %e Tm\n", rmp_n, + rmp_m, rmp_factor); + + rmp_Psi0 = 0.0; + if (mesh->lastX()) { + // Set the outer boundary + for (int jx = mesh->LocalNx - 4; jx < mesh->LocalNx; jx++) + for (int jy = 0; jy < mesh->LocalNy; jy++) + for (int jz = 0; jz < mesh->LocalNz; jz++) { + + BoutReal angle = rmp_m * pol_angle(jx, jy) + + rmp_n * ((BoutReal)jz) * mesh->getCoordinates()->dz; + rmp_Psi0(jx, jy, jz) = + (((BoutReal)(jx - 4)) / ((BoutReal)(mesh->LocalNx - 5))) * rmp_factor + * cos(angle); + if (rmp_polwid > 0.0) { // Multiply by a Gaussian in poloidal angle - BoutReal gx = ((pol_angle(jx,jy) / (2.*PI)) - rmp_polpeak) / rmp_polwid; - rmp_Psi0(jx,jy,jz) *= exp(-gx*gx); + BoutReal gx = + ((pol_angle(jx, jy) / (2. * PI)) - rmp_polpeak) / rmp_polwid; + rmp_Psi0(jx, jy, jz) *= exp(-gx * gx); } - } + } } - // Now have a simple model for Psi due to coils at the outer boundary - // Need to calculate Psi inside the domain, enforcing j = 0 - - Jpar = 0.0; - Laplacian *psiLap = Laplacian::create(); + // Now have a simple model for Psi due to coils at the outer boundary + // Need to calculate Psi inside the domain, enforcing j = 0 + + Jpar = 0.0; + Laplacian* psiLap = Laplacian::create(); psiLap->setInnerBoundaryFlags(INVERT_AC_GRAD); // Zero gradient inner BC - psiLap->setOuterBoundaryFlags(INVERT_SET); // Set to rmp_Psi0 on outer boundary - rmp_Psi0 = psiLap->solve(Jpar, rmp_Psi0); - mesh->communicate(rmp_Psi0); - + psiLap->setOuterBoundaryFlags(INVERT_SET); // Set to rmp_Psi0 on outer boundary + rmp_Psi0 = psiLap->solve(Jpar, rmp_Psi0); + mesh->communicate(rmp_Psi0); } - }else { + } else { // Load perturbation from grid file. include_rmp = !mesh->get(rmp_Psi0, "rmp_A"); // Only include if found - if(!include_rmp) { - output_warn.write("WARNING: Couldn't read 'rmp_A' from grid file\n"); + if (!include_rmp) { + output_warn.write("WARNING: Couldn't read 'rmp_A' from grid file\n"); } // Multiply by factor rmp_Psi0 *= rmp_factor; } } - if(!include_curvature) + if (!include_curvature) b0xcv = 0.0; - - if(!include_jpar0) + + if (!include_jpar0) J0 = 0.0; - if(noshear) { - if(include_curvature) - b0xcv.z += I*b0xcv.x; + if (noshear) { + if (include_curvature) + b0xcv.z += I * b0xcv.x; I = 0.0; } - + ////////////////////////////////////////////////////////////// // SHIFTED RADIAL COORDINATES - if(mesh->IncIntShear) { + if (mesh->IncIntShear) { // BOUT-06 style, using d/dx = d/dpsi + I * d/dz metric->IntShiftTorsion = I; - - }else { + + } else { // Dimits style, using local coordinate system - if(include_curvature) - b0xcv.z += I*b0xcv.x; - I = 0.0; // I disappears from metric + if (include_curvature) + b0xcv.z += I * b0xcv.x; + I = 0.0; // I disappears from metric } ////////////////////////////////////////////////////////////// // NORMALISE QUANTITIES - - if(mesh->get(Bbar, "bmag")) // Typical magnetic field + + if (mesh->get(Bbar, "bmag")) // Typical magnetic field Bbar = 1.0; - if(mesh->get(Lbar, "rmag")) // Typical length scale + if (mesh->get(Lbar, "rmag")) // Typical length scale Lbar = 1.0; - - Va = sqrt(Bbar*Bbar / (MU0*density*Mi)); + + Va = sqrt(Bbar * Bbar / (MU0 * density * Mi)); Tbar = Lbar / Va; - dnorm = dia_fact * Mi / (2.*1.602e-19*Bbar*Tbar); + dnorm = dia_fact * Mi / (2. * 1.602e-19 * Bbar * Tbar); - delta_i = AA*60.67*5.31e5/sqrt(density/1e6)/(Lbar*100.0); + delta_i = AA * 60.67 * 5.31e5 / sqrt(density / 1e6) / (Lbar * 100.0); output.write("Normalisations: Bbar = %e T Lbar = %e m\n", Bbar, Lbar); output.write(" Va = %e m/s Tbar = %e s\n", Va, Tbar); output.write(" dnorm = %e\n", dnorm); output.write(" Resistivity\n"); - if(gyroviscous) { - omega_i = 9.58e7*Zeff*Bbar; - Upara2 = 0.5/(Tbar*omega_i); - //Upara3 = 1.0; + if (gyroviscous) { + omega_i = 9.58e7 * Zeff * Bbar; + Upara2 = 0.5 / (Tbar * omega_i); + // Upara3 = 1.0; output.write("Upara2 = %e Omega_i = %e\n", Upara2, omega_i); } - if(eHall) + if (eHall) output.write(" delta_i = %e AA = %e \n", delta_i, AA); - if(vac_lund > 0.0) { - output.write(" Vacuum Tau_R = %e s eta = %e Ohm m\n", vac_lund * Tbar, - MU0 * Lbar * Lbar / (vac_lund * Tbar)); + if (vac_lund > 0.0) { + output.write(" Vacuum Tau_R = %e s eta = %e Ohm m\n", vac_lund * Tbar, + MU0 * Lbar * Lbar / (vac_lund * Tbar)); vac_resist = 1. / vac_lund; - }else { + } else { output.write(" Vacuum - Zero resistivity -\n"); vac_resist = 0.0; } - if(core_lund > 0.0) { + if (core_lund > 0.0) { output.write(" Core Tau_R = %e s eta = %e Ohm m\n", core_lund * Tbar, - MU0 * Lbar * Lbar / (core_lund * Tbar)); + MU0 * Lbar * Lbar / (core_lund * Tbar)); core_resist = 1. / core_lund; - }else { + } else { output.write(" Core - Zero resistivity -\n"); core_resist = 0.0; } - if(hyperresist > 0.0) { + if (hyperresist > 0.0) { output.write(" Hyper-resistivity coefficient: %e\n", hyperresist); } - if(ehyperviscos > 0.0) { + if (ehyperviscos > 0.0) { output.write(" electron Hyper-viscosity coefficient: %e\n", ehyperviscos); } - if(hyperviscos > 0.0) { + if (hyperviscos > 0.0) { output.write(" Hyper-viscosity coefficient: %e\n", hyperviscos); dump.add(hyper_mu_x, "hyper_mu_x", 1); } - if(diffusion_par > 0.0) { + if (diffusion_par > 0.0) { output.write(" diffusion_par: %e\n", diffusion_par); dump.add(diffusion_par, "diffusion_par", 1); } - //xqx: parallel hyper-viscous diffusion for pressure - if(diffusion_p4 > 0.0) { + // xqx: parallel hyper-viscous diffusion for pressure + if (diffusion_p4 > 0.0) { output.write(" diffusion_p4: %e\n", diffusion_p4); dump.add(diffusion_p4, "diffusion_p4", 1); } - //xqx: parallel hyper-viscous diffusion for vorticity - if(diffusion_u4 > 0.0) { + // xqx: parallel hyper-viscous diffusion for vorticity + if (diffusion_u4 > 0.0) { output.write(" diffusion_u4: %e\n", diffusion_u4); dump.add(diffusion_u4, "diffusion_u4", 1); } - //xqx: parallel hyper-viscous diffusion for vector potential - if(diffusion_a4 > 0.0) { + // xqx: parallel hyper-viscous diffusion for vector potential + if (diffusion_a4 > 0.0) { output.write(" diffusion_a4: %e\n", diffusion_a4); dump.add(diffusion_a4, "diffusion_a4", 1); } - if(heating_P > 0.0) { + if (heating_P > 0.0) { output.write(" heating_P(watts): %e\n", heating_P); dump.add(heating_P, "heating_P", 1); - output.write(" hp_width(%): %e\n",hp_width); + output.write(" hp_width(%): %e\n", hp_width); dump.add(hp_width, "hp_width", 1); - output.write(" hp_length(%): %e\n",hp_length); + output.write(" hp_length(%): %e\n", hp_length); dump.add(hp_length, "hp_length", 1); } - if(sink_P > 0.0) { + if (sink_P > 0.0) { output.write(" sink_P(rate): %e\n", sink_P); dump.add(sink_P, "sink_P", 1); - output.write(" sp_width(%): %e\n",sp_width); + output.write(" sp_width(%): %e\n", sp_width); dump.add(sp_width, "sp_width", 1); - output.write(" sp_length(%): %e\n",sp_length); + output.write(" sp_length(%): %e\n", sp_length); dump.add(sp_length, "sp_length", 1); } - if(K_H_term) + if (K_H_term) output.write(" keep K-H term\n"); else - output.write(" drop K-H term\n"); + output.write(" drop K-H term\n"); Field2D Te; - Te = P0 / (2.0*density * 1.602e-19); // Temperature in eV + Te = P0 / (2.0 * density * 1.602e-19); // Temperature in eV + + J0 = -MU0 * Lbar * J0 / B0; + P0 = 2.0 * MU0 * P0 / (Bbar * Bbar); + V0 = V0 / Va; + Dphi0 *= Tbar; - J0 = - MU0*Lbar * J0 / B0; - P0 = 2.0*MU0 * P0 / (Bbar*Bbar); - V0=V0/Va; - Dphi0*=Tbar; - b0xcv.x /= Bbar; - b0xcv.y *= Lbar*Lbar; - b0xcv.z *= Lbar*Lbar; + b0xcv.y *= Lbar * Lbar; + b0xcv.z *= Lbar * Lbar; - Rxy /= Lbar; + Rxy /= Lbar; Bpxy /= Bbar; Btxy /= Bbar; - B0 /= Bbar; + B0 /= Bbar; hthe /= Lbar; - metric->dx /= Lbar*Lbar*Bbar; - I *= Lbar*Lbar*Bbar; + metric->dx /= Lbar * Lbar * Bbar; + I *= Lbar * Lbar * Bbar; - if (constn0) - { - T0_fake_prof = false; - n0_fake_prof = false; - } - else - { - Nbar = 1.0; - Tibar=1000.0; - Tebar=1000.0; - - if( (!T0_fake_prof) && n0_fake_prof ) - { - N0 = N0tanh(n0_height*Nbar, n0_ave*Nbar, n0_width, n0_center, n0_bottom_x); - - Ti0 = P0/N0/2.0; - Te0 = Ti0; - } - else if (T0_fake_prof) - { - Ti0 = Tconst; - Te0 = Ti0; - N0 = P0/(Ti0+Te0); - } - else - { - if(mesh->get(N0, "Niexp")) { // N_i0 - output_error.write("Error: Cannot read Ni0 from grid\n"); - return 1; - } - - if(mesh->get(Ti0, "Tiexp")) { // T_i0 - output_error.write("Error: Cannot read Ti0 from grid\n"); - return 1; - } - - if(mesh->get(Te0, "Teexp")) { // T_e0 - output_error.write("Error: Cannot read Te0 from grid\n"); - return 1; - } - N0 /= Nbar; - Ti0 /= Tibar; - Te0 /= Tebar; - } + if (constn0) { + T0_fake_prof = false; + n0_fake_prof = false; + } else { + Nbar = 1.0; + Tibar = 1000.0; + Tebar = 1000.0; + + if ((!T0_fake_prof) && n0_fake_prof) { + N0 = N0tanh(n0_height * Nbar, n0_ave * Nbar, n0_width, n0_center, n0_bottom_x); + + Ti0 = P0 / N0 / 2.0; + Te0 = Ti0; + } else if (T0_fake_prof) { + Ti0 = Tconst; + Te0 = Ti0; + N0 = P0 / (Ti0 + Te0); + } else { + if (mesh->get(N0, "Niexp")) { // N_i0 + output_error.write("Error: Cannot read Ni0 from grid\n"); + return 1; + } + + if (mesh->get(Ti0, "Tiexp")) { // T_i0 + output_error.write("Error: Cannot read Ti0 from grid\n"); + return 1; + } + + if (mesh->get(Te0, "Teexp")) { // T_e0 + output_error.write("Error: Cannot read Te0 from grid\n"); + return 1; + } + N0 /= Nbar; + Ti0 /= Tibar; + Te0 /= Tebar; } + } - if (gyroviscous) - { - Dperp2Phi0.setLocation(CELL_CENTRE); - Dperp2Phi0.setBoundary("phi"); - Dperp2Phi.setLocation(CELL_CENTRE); - Dperp2Phi.setBoundary("phi"); - GradPhi02.setLocation(CELL_CENTRE); - GradPhi02.setBoundary("phi"); - GradcPhi.setLocation(CELL_CENTRE); - GradcPhi.setBoundary("phi"); - Dperp2Pi0.setLocation(CELL_CENTRE); - Dperp2Pi0.setBoundary("P"); - Dperp2Pi.setLocation(CELL_CENTRE); - Dperp2Pi.setBoundary("P"); - bracketPhi0P.setLocation(CELL_CENTRE); - bracketPhi0P.setBoundary("P"); - bracketPhiP0.setLocation(CELL_CENTRE); - bracketPhiP0.setBoundary("P"); - if (nonlinear) - { - GradPhi2.setLocation(CELL_CENTRE); - GradPhi2.setBoundary("phi"); - bracketPhiP.setLocation(CELL_CENTRE); - bracketPhiP.setBoundary("P"); - } + if (gyroviscous) { + Dperp2Phi0.setLocation(CELL_CENTRE); + Dperp2Phi0.setBoundary("phi"); + Dperp2Phi.setLocation(CELL_CENTRE); + Dperp2Phi.setBoundary("phi"); + GradPhi02.setLocation(CELL_CENTRE); + GradPhi02.setBoundary("phi"); + GradcPhi.setLocation(CELL_CENTRE); + GradcPhi.setBoundary("phi"); + Dperp2Pi0.setLocation(CELL_CENTRE); + Dperp2Pi0.setBoundary("P"); + Dperp2Pi.setLocation(CELL_CENTRE); + Dperp2Pi.setBoundary("P"); + bracketPhi0P.setLocation(CELL_CENTRE); + bracketPhi0P.setBoundary("P"); + bracketPhiP0.setLocation(CELL_CENTRE); + bracketPhiP0.setBoundary("P"); + if (nonlinear) { + GradPhi2.setLocation(CELL_CENTRE); + GradPhi2.setBoundary("phi"); + bracketPhiP.setLocation(CELL_CENTRE); + bracketPhiP.setBoundary("P"); } + } BoutReal pnorm = max(P0, true); // Maximum over all processors - + vacuum_pressure *= pnorm; // Get pressure from fraction vacuum_trans *= pnorm; // Transitions from 0 in core to 1 in vacuum - vac_mask = (1.0 - tanh( (P0 - vacuum_pressure) / vacuum_trans )) / 2.0; + vac_mask = (1.0 - tanh((P0 - vacuum_pressure) / vacuum_trans)) / 2.0; - if(spitzer_resist) { - // Use Spitzer resistivity + if (spitzer_resist) { + // Use Spitzer resistivity output.write("\tTemperature: %e -> %e [eV]\n", min(Te), max(Te)); - eta = 0.51*1.03e-4*Zeff*20.*pow(Te,-1.5); // eta in Ohm-m. NOTE: ln(Lambda) = 20 + eta = 0.51 * 1.03e-4 * Zeff * 20. + * pow(Te, -1.5); // eta in Ohm-m. NOTE: ln(Lambda) = 20 output.write("\tSpitzer resistivity: %e -> %e [Ohm m]\n", min(eta), max(eta)); eta /= MU0 * Va * Lbar; - output.write("\t -> Lundquist %e -> %e\n", 1.0/max(eta), 1.0/min(eta)); - }else { + output.write("\t -> Lundquist %e -> %e\n", 1.0 / max(eta), 1.0 / min(eta)); + } else { // transition from 0 for large P0 to resistivity for small P0 eta = core_resist + (vac_resist - core_resist) * vac_mask; } - dump.add(eta, "eta", 0); + SAVE_ONCE(eta); - if(include_rmp) { + if (include_rmp) { // Normalise RMP quantities rmp_Psi0 /= Bbar * Lbar; - + rmp_ramp /= Tbar; rmp_freq *= Tbar; rmp_rotate *= Tbar; - + rmp_Psi = rmp_Psi0; rmp_dApdt = 0.0; bool apar_changing = false; output.write("Including magnetic perturbation\n"); - if(rmp_ramp > 0.0) { - output.write("\tRamping up over period t = %e (%e ms)\n", rmp_ramp, rmp_ramp*Tbar*1000.); + if (rmp_ramp > 0.0) { + output.write("\tRamping up over period t = %e (%e ms)\n", rmp_ramp, + rmp_ramp * Tbar * 1000.); apar_changing = true; } - if(rmp_freq > 0.0) { - output.write("\tOscillating with frequency f = %e (%e kHz)\n", rmp_freq, rmp_freq/Tbar/1000.); + if (rmp_freq > 0.0) { + output.write("\tOscillating with frequency f = %e (%e kHz)\n", rmp_freq, + rmp_freq / Tbar / 1000.); apar_changing = true; } - if(rmp_rotate != 0.0) { - output.write("\tRotating with a frequency f = %e (%e kHz)\n", rmp_rotate, rmp_rotate/Tbar/1000.); + if (rmp_rotate != 0.0) { + output.write("\tRotating with a frequency f = %e (%e kHz)\n", rmp_rotate, + rmp_rotate / Tbar / 1000.); apar_changing = true; } - if(apar_changing) { - dump.add(rmp_Psi, "rmp_Psi", 1); - dump.add(rmp_dApdt, "rmp_dApdt", 1); - }else { - dump.add(rmp_Psi, "rmp_Psi", 0); + if (apar_changing) { + SAVE_REPEAT(rmp_Psi, rmp_dApdt); + } else { + SAVE_ONCE(rmp_Psi); } - }else + } else rmp_Psi = 0.0; - + /**************** CALCULATE METRICS ******************/ - metric->g11 = SQ(Rxy*Bpxy); + metric->g11 = SQ(Rxy * Bpxy); metric->g22 = 1.0 / SQ(hthe); - metric->g33 = SQ(I)*metric->g11 + SQ(B0)/metric->g11; + metric->g33 = SQ(I) * metric->g11 + SQ(B0) / metric->g11; metric->g12 = 0.0; - metric->g13 = -I*metric->g11; - metric->g23 = -Btxy/(hthe*Bpxy*Rxy); - + metric->g13 = -I * metric->g11; + metric->g23 = -Btxy / (hthe * Bpxy * Rxy); + metric->J = hthe / Bpxy; metric->Bxy = B0; - - metric->g_11 = 1.0/metric->g11 + SQ(I*Rxy); - metric->g_22 = SQ(B0*hthe/Bpxy); - metric->g_33 = Rxy*Rxy; - metric->g_12 = Btxy*hthe*I*Rxy/Bpxy; - metric->g_13 = I*Rxy*Rxy; - metric->g_23 = Btxy*hthe*Rxy/Bpxy; - + + metric->g_11 = 1.0 / metric->g11 + SQ(I * Rxy); + metric->g_22 = SQ(B0 * hthe / Bpxy); + metric->g_33 = Rxy * Rxy; + metric->g_12 = Btxy * hthe * I * Rxy / Bpxy; + metric->g_13 = I * Rxy * Rxy; + metric->g_23 = Btxy * hthe * Rxy / Bpxy; + metric->geometry(); // Calculate quantities from metric tensor // Set B field vector - + B0vec.covariant = false; B0vec.x = 0.; B0vec.y = Bpxy / hthe; B0vec.z = 0.; - - V0net.covariant = false; //presentation for net flow + + V0net.covariant = false; // presentation for net flow V0net.x = 0.; - V0net.y = Rxy*Btxy*Bpxy/(hthe*B0*B0)*Dphi0; + V0net.y = Rxy * Btxy * Bpxy / (hthe * B0 * B0) * Dphi0; V0net.z = -Dphi0; - U0=B0vec*Curl(V0net)/B0; //get 0th vorticity for Kelvin-Holmholtz term - + U0 = B0vec * Curl(V0net) / B0; // get 0th vorticity for Kelvin-Holmholtz term + /**************** SET EVOLVING VARIABLES *************/ // Tell BOUT which variables to evolve - SOLVE_FOR(U); - SOLVE_FOR(P); + SOLVE_FOR(U, P); - if(evolve_jpar) { + if (evolve_jpar) { output.write("Solving for jpar: Inverting to get Psi\n"); SOLVE_FOR(Jpar); dump.add(Psi, "Psi", 1); - }else { + } else { output.write("Solving for Psi, Differentiating to get jpar\n"); SOLVE_FOR(Psi); dump.add(Jpar, "jpar", 1); } - + if (compress0) { output.write("Including compression (Vpar) effects\n"); - + SOLVE_FOR(Vpar); comms.add(Vpar); - beta = B0*B0 / ( 0.5 + (B0*B0 / (g*P0))); + beta = B0 * B0 / (0.5 + (B0 * B0 / (g * P0))); gradparB = Grad_par(B0) / B0; - output.write("Beta in range %e -> %e\n", - min(beta), max(beta)); + output.write("Beta in range %e -> %e\n", min(beta), max(beta)); } else { Vpar = 0.0; } - if(phi_constraint) { + if (phi_constraint) { // Implicit Phi solve using IDA - - if(!bout_constrain(phi, C_phi, "phi")) { + + if (!bout_constrain(phi, C_phi, "phi")) { output_error.write("ERROR: Cannot constrain. Run again with phi_constraint=false\n"); throw BoutException("Aborting.\n"); } - + // Set preconditioner solver->setPrecon(precon_phi); - }else { + } else { // Phi solved in RHS (explicitly) dump.add(phi, "phi", 1); @@ -986,74 +995,72 @@ int physics_init(bool restarting) { } // Diamagnetic phi0 - if(diamag_phi0) { + if (diamag_phi0) { if (constn0) - phi0 = -0.5*dnorm*P0/B0; + phi0 = -0.5 * dnorm * P0 / B0; else // Stationary equilibrium plasma. ExB velocity balances diamagnetic drift - phi0 = -0.5*dnorm*P0/B0/N0; + phi0 = -0.5 * dnorm * P0 / B0 / N0; SAVE_ONCE(phi0); } - - + // Add some equilibrium quantities and normalisations // everything needed to recover physical units - SAVE_ONCE2(J0, P0); - SAVE_ONCE4(density, Lbar, Bbar, Tbar); - SAVE_ONCE2(Va, B0); - SAVE_ONCE2(Dphi0, U0); - SAVE_ONCE(V0); + SAVE_ONCE(J0, P0); + SAVE_ONCE(density, Lbar, Bbar, Tbar); + SAVE_ONCE(Va, B0); + SAVE_ONCE(Dphi0, U0); + SAVE_ONCE(V0); if (!constn0) - SAVE_ONCE3(Ti0, Te0, N0); + SAVE_ONCE(Ti0, Te0, N0); + + // Create a solver for the Laplacian + phiSolver = Laplacian::create(); + phiSolver->setFlags(phi_flags); + + aparSolver = Laplacian::create(); + aparSolver->setFlags(apar_flags); + aparSolver->setCoefA(-delta_e_inv * N0 * N0); /////////////// CHECK VACUUM /////////////////////// // In vacuum region, initial vorticity should equal zero - - //ubyn.setLocation(CELL_YLOW); - //ubyn.setBoundary("U"); - if(!restarting) { + // ubyn.setLocation(CELL_YLOW); + // ubyn.setBoundary("U"); + + if (!restarting) { // Only if not restarting: Check initial perturbation // Set U to zero where P0 < vacuum_pressure U = where(P0 - vacuum_pressure, U, 0.0); - if (constn0) - { - ubyn = U; - // Phi should be consistent with U - phi = invert_laplace(ubyn, phi_flags, NULL); - } - else - { - ubyn = U/N0; - //dump.add(ubyn, "ubyn", 1); - //dump.add(sourp, "sourp", 1); - phi = invert_laplace(ubyn, phi_flags, NULL, &N0, NULL); - } - - //if(diamag) { - //phi -= 0.5*dnorm * P / B0; + if (constn0) { + ubyn = U; + // Phi should be consistent with U + phi = phiSolver->solve(ubyn); + } else { + ubyn = U / N0; + phiSolver->setCoefC(N0); + phi = phiSolver->solve(ubyn); + } + + // if(diamag) { + // phi -= 0.5*dnorm * P / B0; //} } - - /************** SETUP COMMUNICATIONS **************/ - - comms.add(U); - comms.add(P); - // comms.add(phi); + + comms.add(U, P); phi.setBoundary("phi"); // Set boundary conditions tmpU2.setBoundary("U"); tmpP2.setBoundary("P"); tmpA2.setBoundary("J"); - //sourp.setBoundary("U"); - if(evolve_jpar) { + if (evolve_jpar) { comms.add(Jpar); - }else { + } else { comms.add(Psi); // otherwise Need to communicate Jpar separately Jpar.setBoundary("J"); @@ -1064,26 +1071,26 @@ int physics_init(bool restarting) { } // Parallel gradient along perturbed field-line -const Field3D Grad_parP(const Field3D &f, CELL_LOC loc = CELL_DEFAULT) { +const Field3D Grad_parP(const Field3D& f, CELL_LOC loc = CELL_DEFAULT) { Field3D result; - - if(parallel_lr_diff) { + + if (parallel_lr_diff) { // Use left/right biased stencils. NOTE: First order only! - if(loc == CELL_YLOW) { + if (loc == CELL_YLOW) { result = Grad_par_CtoL(f); - }else + } else result = Grad_par_LtoC(f); - }else + } else result = Grad_par(f, loc); - - if(nonlinear) { - result -= bracket(Psi, f, bm_mag)*B0; - - if(include_rmp) { - result -= bracket(rmp_Psi, f, bm_mag)*B0; + + if (nonlinear) { + result -= bracket(Psi, f, bm_mag) * B0; + + if (include_rmp) { + result -= bracket(rmp_Psi, f, bm_mag) * B0; } } - + return result; } @@ -1092,22 +1099,22 @@ bool first_run = true; // For printing out some diagnostics first time around int physics_run(BoutReal t) { // Perform communications mesh->communicate(comms); - - Coordinates *metric = mesh->getCoordinates(); + + Coordinates* metric = mesh->getCoordinates(); //////////////////////////////////////////// // Transitions from 0 in core to 1 in vacuum - if(nonlinear) { - vac_mask = (1.0 - tanh( ((P0 + P) - vacuum_pressure) / vacuum_trans )) / 2.0; - + if (nonlinear) { + vac_mask = (1.0 - tanh(((P0 + P) - vacuum_pressure) / vacuum_trans)) / 2.0; + // Update resistivity - if(spitzer_resist) { + if (spitzer_resist) { // Use Spitzer formula Field3D Te; - Te = (P0+P)*Bbar*Bbar/(4.*MU0) / (density * 1.602e-19); // eV - eta = 0.51*1.03e-4*Zeff*20.*pow(Te, -1.5); // eta in Ohm-m. ln(Lambda) = 20 - eta /= MU0 * Va * Lbar; // Normalised eta - }else { + Te = (P0 + P) * Bbar * Bbar / (4. * MU0) / (density * 1.602e-19); // eV + eta = 0.51 * 1.03e-4 * Zeff * 20. * pow(Te, -1.5); // eta in Ohm-m. ln(Lambda) = 20 + eta /= MU0 * Va * Lbar; // Normalised eta + } else { // Use specified core and vacuum Lundquist numbers eta = core_resist + (vac_resist - core_resist) * vac_mask; } @@ -1116,160 +1123,149 @@ int physics_run(BoutReal t) { //////////////////////////////////////////// // Resonant Magnetic Perturbation code - if(include_rmp) { + if (include_rmp) { - if( (rmp_ramp > 0.0) || (rmp_freq > 0.0) || (rmp_rotate != 0.0) ) { + if ((rmp_ramp > 0.0) || (rmp_freq > 0.0) || (rmp_rotate != 0.0)) { // Need to update the RMP terms - - if((rmp_ramp > 0.0) && (t < rmp_ramp)) { - // Still in ramp phase - - rmp_Psi = (t / rmp_ramp) * rmp_Psi0 ; // Linear ramp - - rmp_dApdt = rmp_Psi0 / rmp_ramp; - }else { - rmp_Psi = rmp_Psi0; - rmp_dApdt = 0.0; + + if ((rmp_ramp > 0.0) && (t < rmp_ramp)) { + // Still in ramp phase + + rmp_Psi = (t / rmp_ramp) * rmp_Psi0; // Linear ramp + + rmp_dApdt = rmp_Psi0 / rmp_ramp; + } else { + rmp_Psi = rmp_Psi0; + rmp_dApdt = 0.0; } - - if(rmp_freq > 0.0) { - // Oscillating the amplitude - - rmp_dApdt = rmp_dApdt * sin(2.*PI * rmp_freq * t) - + rmp_Psi * (2.*PI * rmp_freq) * cos(2.*PI * rmp_freq * t); - - rmp_Psi *= sin(2.*PI * rmp_freq * t); - + + if (rmp_freq > 0.0) { + // Oscillating the amplitude + + rmp_dApdt = rmp_dApdt * sin(2. * PI * rmp_freq * t) + + rmp_Psi * (2. * PI * rmp_freq) * cos(2. * PI * rmp_freq * t); + + rmp_Psi *= sin(2. * PI * rmp_freq * t); } - - if(rmp_rotate != 0.0) { - // Rotate toroidally at given frequency - - shiftZ(rmp_Psi, 2*PI * rmp_rotate * t); - shiftZ(rmp_dApdt, 2*PI * rmp_rotate * t); - - // Add toroidal rotation term. CHECK SIGN - - rmp_dApdt += DDZ(rmp_Psi) * 2*PI * rmp_rotate; + + if (rmp_rotate != 0.0) { + // Rotate toroidally at given frequency + + shiftZ(rmp_Psi, 2 * PI * rmp_rotate * t); + shiftZ(rmp_dApdt, 2 * PI * rmp_rotate * t); + + // Add toroidal rotation term. CHECK SIGN + + rmp_dApdt += DDZ(rmp_Psi) * 2 * PI * rmp_rotate; } - + // Set to zero in the core - if(rmp_vac_mask) + if (rmp_vac_mask) rmp_Psi *= vac_mask; - }else { + } else { // Set to zero in the core region - if(rmp_vac_mask) - rmp_Psi = rmp_Psi0 * vac_mask; // Only in vacuum -> skin current -> diffuses inwards + if (rmp_vac_mask) + rmp_Psi = + rmp_Psi0 * vac_mask; // Only in vacuum -> skin current -> diffuses inwards } - + mesh->communicate(rmp_Psi); } - + //////////////////////////////////////////// // Inversion - if(evolve_jpar) { + if (evolve_jpar) { // Invert laplacian for Psi - Psi = invert_laplace(Jpar, apar_flags, NULL); + Psi = aparSolver->solve(Jpar); mesh->communicate(Psi); } - if(phi_constraint) { + if (phi_constraint) { // Phi being solved as a constraint - + Field3D Ctmp = phi; Ctmp.setBoundary("phi"); // Look up boundary conditions for phi Ctmp.applyBoundary(); Ctmp -= phi; // Now contains error in the boundary - + C_phi = Delp2(phi) - U; // Error in the bulk C_phi.setBoundaryTo(Ctmp); - }else { + } else { - if (constn0) - { - phi = invert_laplace(U, phi_flags, NULL); - - if(diamag) { - phi -= 0.5*dnorm * P / B0; - } + if (constn0) { + phi = phiSolver->solve(U); + + if (diamag) { + phi -= 0.5 * dnorm * P / B0; } - else - { - ubyn = U/N0; - if (diamag) - { - ubyn -= 0.5*dnorm/(N0*B0) * Delp2(P); - //ubyn.applyBoundary(); - mesh->communicate(ubyn); - //sourp = Delp2(P); - //sourp.applyBoundary(); - //mesh->communicate(sourp); - } - // Invert laplacian for phi - phi = invert_laplace(ubyn, phi_flags, NULL, &N0, NULL); + } else { + ubyn = U / N0; + if (diamag) { + ubyn -= 0.5 * dnorm / (N0 * B0) * Delp2(P); + mesh->communicate(ubyn); } + // Invert laplacian for phi + phiSolver->setCoefC(N0); + phi = phiSolver->solve(ubyn); + } // Apply a boundary condition on phi for target plates phi.applyBoundary(); - mesh->communicate(phi); + mesh->communicate(phi); } - - if(!evolve_jpar) { + if (!evolve_jpar) { // Get J from Psi Jpar = Delp2(Psi); - if(include_rmp) + if (include_rmp) Jpar += Delp2(rmp_Psi); Jpar.applyBoundary(); mesh->communicate(Jpar); - if(jpar_bndry_width > 0) { + if (jpar_bndry_width > 0) { // Zero j in boundary regions. Prevents vorticity drive // at the boundary - - for(int i=0;iLocalNy;j++) - for(int k=0;kLocalNz;k++) { - if(mesh->firstX()) - Jpar(i,j,k) = 0.0; - if(mesh->lastX()) - Jpar(mesh->LocalNx-1-i,j,k) = 0.0; - } + + for (int i = 0; i < jpar_bndry_width; i++) + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + if (mesh->firstX()) + Jpar(i, j, k) = 0.0; + if (mesh->lastX()) + Jpar(mesh->LocalNx - 1 - i, j, k) = 0.0; + } } // Smooth j in x - if(smooth_j_x) { + if (smooth_j_x) { Jpar = smooth_x(Jpar); Jpar.applyBoundary(); - //Recommunicate now smoothed + // Recommunicate now smoothed mesh->communicate(Jpar); } - - //xqx begin // Get Delp2(J) from J Jpar2 = Delp2(Jpar); Jpar2.applyBoundary(); mesh->communicate(Jpar2); - if(jpar_bndry_width > 0) { + if (jpar_bndry_width > 0) { // Zero jpar2 in boundary regions. Prevents vorticity drive // at the boundary - - for(int i=0;iLocalNy;j++) - for(int k=0;kLocalNz;k++) { - if(mesh->firstX()) - Jpar2(i,j,k) = 0.0; - if(mesh->lastX()) - Jpar2(mesh->LocalNx-1-i,j,k) = 0.0; - } + + for (int i = 0; i < jpar_bndry_width; i++) + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + if (mesh->firstX()) + Jpar2(i, j, k) = 0.0; + if (mesh->lastX()) + Jpar2(mesh->LocalNx - 1 - i, j, k) = 0.0; + } } - //xqx end } //////////////////////////////////////////////////// @@ -1277,103 +1273,101 @@ int physics_run(BoutReal t) { // Normalised and linearised, since here we have only pressure // rather than density and temperature. Applying a boundary // to Jpar so that Jpar = sqrt(mi/me)/(2*pi) * phi - // - - if(sheath_boundaries) { + // + + if (sheath_boundaries) { // At y = ystart (lower boundary) - - for(RangeIterator r=mesh->iterateBndryLowerY(); !r.isDone(); r++) { - for(int jz=0; jzLocalNz; jz++) { - - // Zero-gradient potential - BoutReal phisheath = phi(r.ind, mesh->ystart, jz); - - BoutReal jsheath = - (sqrt(mi_me)/(2.*sqrt(PI))) * phisheath; - - // Apply boundary condition half-way between cells - for(int jy = mesh->ystart-1;jy >= 0; jy--) { - // Neumann conditions - P(r.ind, jy, jz) = P(r.ind, mesh->ystart, jz); - phi(r.ind, jy, jz) = phisheath; - // Dirichlet condition on Jpar - Jpar(r.ind, jy, jz) = 2.*jsheath - Jpar(r.ind, mesh->ystart, jz); - - } + + for (RangeIterator r = mesh->iterateBndryLowerY(); !r.isDone(); r++) { + for (int jz = 0; jz < mesh->LocalNz; jz++) { + + // Zero-gradient potential + BoutReal phisheath = phi(r.ind, mesh->ystart, jz); + + BoutReal jsheath = -(sqrt(mi_me) / (2. * sqrt(PI))) * phisheath; + + // Apply boundary condition half-way between cells + for (int jy = mesh->ystart - 1; jy >= 0; jy--) { + // Neumann conditions + P(r.ind, jy, jz) = P(r.ind, mesh->ystart, jz); + phi(r.ind, jy, jz) = phisheath; + // Dirichlet condition on Jpar + Jpar(r.ind, jy, jz) = 2. * jsheath - Jpar(r.ind, mesh->ystart, jz); + } } } - + // At y = yend (upper boundary) - for(RangeIterator r=mesh->iterateBndryUpperY(); !r.isDone(); r++) { - for(int jz=0; jzLocalNz; jz++) { - - // Zero-gradient potential - BoutReal phisheath = phi(r.ind, mesh->yend, jz); - - BoutReal jsheath = (sqrt(mi_me)/(2.*sqrt(PI))) * phisheath; - - // Apply boundary condition half-way between cells - for(int jy = mesh->yend-1;jy >= 0; jy--) { - // Neumann conditions - P(r.ind, jy, jz) = P(r.ind, mesh->yend, jz); - phi(r.ind, jy, jz) = phisheath; - // Dirichlet condition on Jpar - Jpar(r.ind, jy, jz) = 2.*jsheath - Jpar(r.ind, mesh->yend, jz); - - } + for (RangeIterator r = mesh->iterateBndryUpperY(); !r.isDone(); r++) { + for (int jz = 0; jz < mesh->LocalNz; jz++) { + + // Zero-gradient potential + BoutReal phisheath = phi(r.ind, mesh->yend, jz); + + BoutReal jsheath = (sqrt(mi_me) / (2. * sqrt(PI))) * phisheath; + + // Apply boundary condition half-way between cells + for (int jy = mesh->yend - 1; jy >= 0; jy--) { + // Neumann conditions + P(r.ind, jy, jz) = P(r.ind, mesh->yend, jz); + phi(r.ind, jy, jz) = phisheath; + // Dirichlet condition on Jpar + Jpar(r.ind, jy, jz) = 2. * jsheath - Jpar(r.ind, mesh->yend, jz); + } } } - } //////////////////////////////////////////////////// // Parallel electric field - if(evolve_jpar) { + if (evolve_jpar) { // Jpar - Field3D B0U = B0*U ; + Field3D B0U = B0 * U; mesh->communicate(B0U); - ddt(Jpar) = -Grad_parP(B0U, CELL_YLOW) / B0 + eta*Delp2(Jpar); + ddt(Jpar) = -Grad_parP(B0U, CELL_YLOW) / B0 + eta * Delp2(Jpar); - if(relax_j_vac) { + if (relax_j_vac) { // Make ddt(Jpar) relax to zero. - + ddt(Jpar) -= vac_mask * Jpar / relax_j_tconst; } - }else { + } else { // Vector potential - ddt(Psi) = -Grad_parP(phi, CELL_CENTRE) + eta*Jpar; - - if(eHall) { - ddt(Psi) += 0.25*delta_i*(Grad_parP(P, CELL_CENTRE) - +bracket(P0, Psi, bm_mag)); // electron parallel pressure + ddt(Psi) = -Grad_parP(phi, CELL_CENTRE) + eta * Jpar; + + if (eHall) { + ddt(Psi) += 0.25 * delta_i + * (Grad_parP(P, CELL_CENTRE) + + bracket(P0, Psi, bm_mag)); // electron parallel pressure } - if(diamag_phi0) - ddt(Psi) -= bracket(phi0, Psi, bm_exb); // Equilibrium flow + if (diamag_phi0) + ddt(Psi) -= bracket(phi0, Psi, bm_exb); // Equilibrium flow - if(withflow) //net flow - ddt(Psi)-= V_dot_Grad(V0net, Psi); - - if(diamag_grad_t) { + if (withflow) // net flow + ddt(Psi) -= V_dot_Grad(V0net, Psi); + + if (diamag_grad_t) { // grad_par(T_e) correction ddt(Psi) += 1.71 * dnorm * 0.5 * Grad_parP(P, CELL_YLOW) / B0; } // Hyper-resistivity - if(hyperresist > 0.0) { - ddt(Psi) -= eta*hyperresist * Delp2(Jpar); + if (hyperresist > 0.0) { + ddt(Psi) -= eta * hyperresist * Delp2(Jpar); } // electron Hyper-viscosity coefficient - if(ehyperviscos > 0.0) { - ddt(Psi) -= eta*ehyperviscos * Delp2(Jpar2); + if (ehyperviscos > 0.0) { + ddt(Psi) -= eta * ehyperviscos * Delp2(Jpar2); } - //xqx: parallel hyper-viscous diffusion for vector potential - if(diffusion_a4 > 0.0){ + // xqx: parallel hyper-viscous diffusion for vector potential + if (diffusion_a4 > 0.0) { tmpA2 = Grad2_par2new(Psi); mesh->communicate(tmpA2); tmpA2.applyBoundary(); @@ -1381,89 +1375,92 @@ int physics_run(BoutReal t) { } // Vacuum solution - if(relax_j_vac) { + if (relax_j_vac) { // Calculate the J and Psi profile we're aiming for Field3D Jtarget = Jpar * (1.0 - vac_mask); // Zero in vacuum - + // Invert laplacian for Psi - Psitarget = invert_laplace(Jtarget, apar_flags, NULL); - + Psitarget = aparSolver->solve(Jtarget); + // Add a relaxation term in the vacuum - ddt(Psi) = ddt(Psi)*(1. - vac_mask) - (Psi - Psitarget)*vac_mask / relax_j_tconst; + ddt(Psi) = ddt(Psi) * (1. - vac_mask) - (Psi - Psitarget) * vac_mask / relax_j_tconst; } } - + //////////////////////////////////////////////////// // Vorticity equation - + // Grad j term ddt(U) = SQ(B0) * b0xGrad_dot_Grad(Psi, J0, CELL_CENTRE); - if(include_rmp) { + if (include_rmp) { ddt(U) += SQ(B0) * b0xGrad_dot_Grad(rmp_Psi, J0, CELL_CENTRE); } - - ddt(U) += b0xcv*Grad(P); // curvature term - if(!nogradparj) { + ddt(U) += b0xcv * Grad(P); // curvature term + + if (!nogradparj) { // Parallel current term - ddt(U) -= SQ(B0)*Grad_parP(Jpar, CELL_CENTRE); // b dot grad j + ddt(U) -= SQ(B0) * Grad_parP(Jpar, CELL_CENTRE); // b dot grad j } - if(withflow&&K_H_term) //K_H_term - ddt(U) -=b0xGrad_dot_Grad(phi,U0); + if (withflow && K_H_term) // K_H_term + ddt(U) -= b0xGrad_dot_Grad(phi, U0); - if(diamag_phi0) - ddt(U) -= b0xGrad_dot_Grad(phi0, U); // Equilibrium flow + if (diamag_phi0) + ddt(U) -= b0xGrad_dot_Grad(phi0, U); // Equilibrium flow - if(withflow) // net flow + if (withflow) // net flow ddt(U) -= V_dot_Grad(V0net, U); - if(nonlinear) { - ddt(U) -= bracket(phi, U, bm_exb)*B0; // Advection + if (nonlinear) { + ddt(U) -= bracket(phi, U, bm_exb) * B0; // Advection } - // Viscosity terms - if(viscos_par > 0.0) + // Viscosity terms + if (viscos_par > 0.0) ddt(U) += viscos_par * Grad2_par2(U); // Parallel viscosity - - //xqx: parallel hyper-viscous diffusion for vorticity - if(diffusion_u4 > 0.0){ + + // xqx: parallel hyper-viscous diffusion for vorticity + if (diffusion_u4 > 0.0) { tmpU2 = Grad2_par2new(U); mesh->communicate(tmpU2); tmpU2.applyBoundary(); // tmpU2.applyBoundary("neumann"); - ddt(U) -= diffusion_u4 * Grad2_par2new(tmpU2);} - - if(viscos_perp > 0.0) - ddt(U) += viscos_perp * Delp2(U); // Perpendicular viscosity + ddt(U) -= diffusion_u4 * Grad2_par2new(tmpU2); + } + + if (viscos_perp > 0.0) + ddt(U) += viscos_perp * Delp2(U); // Perpendicular viscosity // Hyper-viscosity - if(hyperviscos > 0.0) { + if (hyperviscos > 0.0) { // Calculate coefficient. - - hyper_mu_x = hyperviscos * metric->g_11*SQ(metric->dx) * abs(metric->g11*D2DX2(U)) / (abs(U) + 1e-3); + + hyper_mu_x = hyperviscos * metric->g_11 * SQ(metric->dx) * abs(metric->g11 * D2DX2(U)) + / (abs(U) + 1e-3); hyper_mu_x.applyBoundary("dirichlet"); // Set to zero on all boundaries - - ddt(U) += hyper_mu_x * metric->g11*D2DX2(U); - - if(first_run) { // Print out maximum values of viscosity used on this processor + + ddt(U) += hyper_mu_x * metric->g11 * D2DX2(U); + + if (first_run) { // Print out maximum values of viscosity used on this processor output.write(" Hyper-viscosity values:\n"); - output.write(" Max mu_x = %e, Max_DC mu_x = %e\n", max(hyper_mu_x), max(DC(hyper_mu_x))); + output.write(" Max mu_x = %e, Max_DC mu_x = %e\n", max(hyper_mu_x), + max(DC(hyper_mu_x))); } } - if(gyroviscous) { - + if (gyroviscous) { + Field3D Pi; Field2D Pi0; - Pi = 0.5*P; - Pi0 = 0.5*P0; - - Dperp2Phi0 = Field3D(Delp2(B0*phi0)); + Pi = 0.5 * P; + Pi0 = 0.5 * P0; + + Dperp2Phi0 = Field3D(Delp2(B0 * phi0)); Dperp2Phi0.applyBoundary(); mesh->communicate(Dperp2Phi0); - Dperp2Phi = Delp2(B0*phi); + Dperp2Phi = Delp2(B0 * phi); Dperp2Phi.applyBoundary(); mesh->communicate(Dperp2Phi); @@ -1475,143 +1472,145 @@ int physics_run(BoutReal t) { Dperp2Pi.applyBoundary(); mesh->communicate(Dperp2Pi); - bracketPhi0P = bracket(B0*phi0, Pi, bm_exb); + bracketPhi0P = bracket(B0 * phi0, Pi, bm_exb); bracketPhi0P.applyBoundary(); mesh->communicate(bracketPhi0P); - bracketPhiP0 = bracket(B0*phi, Pi0, bm_exb); + bracketPhiP0 = bracket(B0 * phi, Pi0, bm_exb); bracketPhiP0.applyBoundary(); mesh->communicate(bracketPhiP0); - ddt(U) -= 0.5*Upara2*bracket(Pi, Dperp2Phi0, bm_exb)/B0; - ddt(U) -= 0.5*Upara2*bracket(Pi0, Dperp2Phi, bm_exb)/B0; - Field3D B0phi = B0*phi; + ddt(U) -= 0.5 * Upara2 * bracket(Pi, Dperp2Phi0, bm_exb) / B0; + ddt(U) -= 0.5 * Upara2 * bracket(Pi0, Dperp2Phi, bm_exb) / B0; + Field3D B0phi = B0 * phi; mesh->communicate(B0phi); - Field3D B0phi0 = B0*phi0; + Field3D B0phi0 = B0 * phi0; mesh->communicate(B0phi0); - ddt(U) += 0.5*Upara2*bracket(B0phi, Dperp2Pi0, bm_exb)/B0; - ddt(U) += 0.5*Upara2*bracket(B0phi0, Dperp2Pi, bm_exb)/B0; - ddt(U) -= 0.5*Upara2*Delp2(bracketPhi0P)/B0; - ddt(U) -= 0.5*Upara2*Delp2(bracketPhiP0)/B0; - - if (nonlinear) - { - Field3D B0phi = B0*phi; - mesh->communicate(B0phi); - bracketPhiP = bracket(B0phi, Pi, bm_exb); - bracketPhiP.applyBoundary(); - mesh->communicate(bracketPhiP); - - ddt(U) -= 0.5*Upara2*bracket(Pi, Dperp2Phi, bm_exb)/B0; - ddt(U) += 0.5*Upara2*bracket(B0phi, Dperp2Pi, bm_exb)/B0; - ddt(U) -= 0.5*Upara2*Delp2(bracketPhiP)/B0; - } + ddt(U) += 0.5 * Upara2 * bracket(B0phi, Dperp2Pi0, bm_exb) / B0; + ddt(U) += 0.5 * Upara2 * bracket(B0phi0, Dperp2Pi, bm_exb) / B0; + ddt(U) -= 0.5 * Upara2 * Delp2(bracketPhi0P) / B0; + ddt(U) -= 0.5 * Upara2 * Delp2(bracketPhiP0) / B0; + + if (nonlinear) { + Field3D B0phi = B0 * phi; + mesh->communicate(B0phi); + bracketPhiP = bracket(B0phi, Pi, bm_exb); + bracketPhiP.applyBoundary(); + mesh->communicate(bracketPhiP); + + ddt(U) -= 0.5 * Upara2 * bracket(Pi, Dperp2Phi, bm_exb) / B0; + ddt(U) += 0.5 * Upara2 * bracket(B0phi, Dperp2Pi, bm_exb) / B0; + ddt(U) -= 0.5 * Upara2 * Delp2(bracketPhiP) / B0; + } } - // left edge sink terms - if(sink_Ul > 0.0){ - ddt(U) -= sink_Ul*sink_tanhxl(P0,U,su_widthl,su_lengthl); // core sink + // left edge sink terms + if (sink_Ul > 0.0) { + ddt(U) -= sink_Ul * sink_tanhxl(P0, U, su_widthl, su_lengthl); // core sink } - // right edge sink terms - if(sink_Ur > 0.0){ - ddt(U) -= sink_Ur*sink_tanhxr(P0,U,su_widthr,su_lengthr); // sol sink + // right edge sink terms + if (sink_Ur > 0.0) { + ddt(U) -= sink_Ur * sink_tanhxr(P0, U, su_widthr, su_lengthr); // sol sink } //////////////////////////////////////////////////// // Pressure equation ddt(P) = 0.0; - if(evolve_pressure) { + if (evolve_pressure) { ddt(P) -= b0xGrad_dot_Grad(phi, P0); - - if(diamag_phi0) - ddt(P) -= b0xGrad_dot_Grad(phi0, P); // Equilibrium flow - if(withflow) //net flow - ddt(P) -= V_dot_Grad(V0net, P); + if (diamag_phi0) + ddt(P) -= b0xGrad_dot_Grad(phi0, P); // Equilibrium flow + + if (withflow) // net flow + ddt(P) -= V_dot_Grad(V0net, P); - if(nonlinear) - ddt(P) -= bracket(phi, P, bm_exb)*B0; // Advection + if (nonlinear) + ddt(P) -= bracket(phi, P, bm_exb) * B0; // Advection } - // Parallel diffusion terms - if(diffusion_par > 0.0) + // Parallel diffusion terms + if (diffusion_par > 0.0) ddt(P) += diffusion_par * Grad2_par2(P); // Parallel diffusion - //xqx: parallel hyper-viscous diffusion for pressure - if(diffusion_p4 > 0.0){ + // xqx: parallel hyper-viscous diffusion for pressure + if (diffusion_p4 > 0.0) { tmpP2 = Grad2_par2new(P); mesh->communicate(tmpP2); tmpP2.applyBoundary(); ddt(P) = diffusion_p4 * Grad2_par2new(tmpP2); } - // heating source terms - if(heating_P > 0.0){ - BoutReal pnorm = P0(0,0); - ddt(P) += heating_P*source_expx2(P0,2.*hp_width,0.5*hp_length)*(Tbar/pnorm); // heat source - ddt(P) += (100.*source_tanhx(P0,hp_width,hp_length)+0.01) * metric->g11 * D2DX2(P) * (Tbar/Lbar/Lbar) ; // radial diffusion + // heating source terms + if (heating_P > 0.0) { + BoutReal pnorm = P0(0, 0); + ddt(P) += heating_P * source_expx2(P0, 2. * hp_width, 0.5 * hp_length) + * (Tbar / pnorm); // heat source + ddt(P) += (100. * source_tanhx(P0, hp_width, hp_length) + 0.01) * metric->g11 + * D2DX2(P) * (Tbar / Lbar / Lbar); // radial diffusion } - // sink terms - if(sink_P > 0.0){ - ddt(P) -= sink_P*sink_tanhxr(P0,P,sp_width,sp_length)*Tbar; // sink + // sink terms + if (sink_P > 0.0) { + ddt(P) -= sink_P * sink_tanhxr(P0, P, sp_width, sp_length) * Tbar; // sink } //////////////////////////////////////////////////// // Compressional effects - - if(compress0) { - - //ddt(P) += beta*( - Grad_parP(Vpar, CELL_CENTRE) + Vpar*gradparB ); - ddt(P) -= beta*Div_par_CtoL(Vpar); - - if(phi_curv) { - ddt(P) -= 2.*beta*b0xcv*Grad(phi); + + if (compress0) { + + // ddt(P) += beta*( - Grad_parP(Vpar, CELL_CENTRE) + Vpar*gradparB ); + ddt(P) -= beta * Div_par_CtoL(Vpar); + + if (phi_curv) { + ddt(P) -= 2. * beta * b0xcv * Grad(phi); } // Vpar equation - - //ddt(Vpar) = -0.5*Grad_parP(P + P0, CELL_YLOW); - ddt(Vpar) = -0.5*(Grad_par_LtoC(P) + Grad_par_LtoC(P0)); - if(nonlinear) - ddt(Vpar) -= bracket(phi, Vpar, bm_exb)*B0; // Advection + // ddt(Vpar) = -0.5*Grad_parP(P + P0, CELL_YLOW); + ddt(Vpar) = -0.5 * (Grad_par_LtoC(P) + Grad_par_LtoC(P0)); + + if (nonlinear) + ddt(Vpar) -= bracket(phi, Vpar, bm_exb) * B0; // Advection } - - if(filter_z) { + + if (filter_z) { // Filter out all except filter_z_mode - - if(evolve_jpar) { + + if (evolve_jpar) { ddt(Jpar) = filter(ddt(Jpar), filter_z_mode); - }else + } else ddt(Psi) = filter(ddt(Psi), filter_z_mode); ddt(U) = filter(ddt(U), filter_z_mode); ddt(P) = filter(ddt(P), filter_z_mode); } - if(low_pass_z > 0) { + if (low_pass_z > 0) { // Low-pass filter, keeping n up to low_pass_z - if(evolve_jpar) { + if (evolve_jpar) { ddt(Jpar) = lowPass(ddt(Jpar), low_pass_z, zonal_field); - }else + } else ddt(Psi) = lowPass(ddt(Psi), low_pass_z, zonal_field); ddt(U) = lowPass(ddt(U), low_pass_z, zonal_flow); ddt(P) = lowPass(ddt(P), low_pass_z, zonal_bkgd); } - if(damp_width > 0) { - for(int i=0;iLocalNy;j++) - for(int k=0;kLocalNz;k++) { - if(mesh->firstX()) - ddt(U)(i,j,k) -= U(i,j,k) / damp_t_const; - if(mesh->lastX()) - ddt(U)(mesh->LocalNx-1-i,j,k) -= U(mesh->LocalNx-1-i,j,k) / damp_t_const; - } + if (damp_width > 0) { + for (int i = 0; i < damp_width; i++) { + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + if (mesh->firstX()) + ddt(U)(i, j, k) -= U(i, j, k) / damp_t_const; + if (mesh->lastX()) + ddt(U)(mesh->LocalNx - 1 - i, j, k) -= + U(mesh->LocalNx - 1 - i, j, k) / damp_t_const; + } } } @@ -1620,39 +1619,37 @@ int physics_run(BoutReal t) { return 0; } - /******************************************************************************* * Preconditioner * * o System state in variables (as in rhs function) * o Values to be inverted in time derivatives - * + * * o Return values should be in time derivatives * * enable by setting solver / use_precon = true in BOUT.inp *******************************************************************************/ -int precon(BoutReal t, BoutReal gamma, BoutReal delta) { +int precon(BoutReal UNUSED(t), BoutReal gamma, BoutReal UNUSED(delta)) { // First matrix, applying L mesh->communicate(ddt(Psi)); Field3D Jrhs = Delp2(ddt(Psi)); Jrhs.applyBoundary("neumann"); - if(jpar_bndry_width > 0) { + if (jpar_bndry_width > 0) { // Boundary in jpar - if(mesh->firstX()) { - for(int i=jpar_bndry_width;i>=0;i--) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - Jrhs(i,j,k) = 0.5*Jrhs(i+1,j,k); + if (mesh->firstX()) { + for (int i = jpar_bndry_width; i >= 0; i--) + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + Jrhs(i, j, k) = 0.5 * Jrhs(i + 1, j, k); } - } - if(mesh->lastX()) { - for(int i=mesh->LocalNx-jpar_bndry_width-1;iLocalNx;i++) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - Jrhs(i,j,k) = 0.5*Jrhs(i-1,j,k); + if (mesh->lastX()) { + for (int i = mesh->LocalNx - jpar_bndry_width - 1; i < mesh->LocalNx; i++) + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + Jrhs(i, j, k) = 0.5 * Jrhs(i - 1, j, k); } } } @@ -1660,27 +1657,27 @@ int precon(BoutReal t, BoutReal gamma, BoutReal delta) { mesh->communicate(Jrhs, ddt(P)); Field3D U1 = ddt(U); - U1 += (gamma*B0*B0)*Grad_par(Jrhs, CELL_CENTRE) + (gamma*b0xcv)*Grad(P); + U1 += (gamma * B0 * B0) * Grad_par(Jrhs, CELL_CENTRE) + (gamma * b0xcv) * Grad(P); // Second matrix, solving Alfven wave dynamics - static InvertPar *invU = 0; - if(!invU) + static InvertPar* invU = 0; + if (!invU) invU = InvertPar::Create(); invU->setCoefA(1.); - invU->setCoefB(-SQ(gamma)*B0*B0); + invU->setCoefB(-SQ(gamma) * B0 * B0); ddt(U) = invU->solve(U1); ddt(U).applyBoundary(); - + // Third matrix, applying U - Field3D phi3 = invert_laplace(ddt(U), phi_flags, NULL); + Field3D phi3 = phiSolver->solve(ddt(U)); mesh->communicate(phi3); phi3.applyBoundary("neumann"); - Field3D B0phi3 = B0*phi3; - mesh->communicate(B0phi3); - ddt(Psi) = ddt(Psi) - gamma*Grad_par(B0phi3)/B0; + Field3D B0phi3 = B0 * phi3; + mesh->communicate(B0phi3); + ddt(Psi) = ddt(Psi) - gamma * Grad_par(B0phi3) / B0; ddt(Psi).applyBoundary(); - + return 0; } @@ -1692,34 +1689,36 @@ int precon(BoutReal t, BoutReal gamma, BoutReal delta) { * Vector v is in (F_P, F_Psi, F_U) * Output * Jacobian-vector multiplied Jv should be in (P, Psi, U) - * + * * NOTE: EXPERIMENTAL * enable by setting solver / use_jacobian = true in BOUT.inp *******************************************************************************/ -int jacobian(BoutReal t) { +int jacobian(BoutReal UNUSED(t)) { // NOTE: LINEAR ONLY! - + // Communicate mesh->communicate(ddt(P), ddt(Psi), ddt(U)); - phi = invert_laplace(ddt(U), phi_flags, NULL); + phi = phiSolver->solve(ddt(U)); Jpar = Delp2(ddt(Psi)); mesh->communicate(phi, Jpar); Field3D JP = -b0xGrad_dot_Grad(phi, P0); - JP.setBoundary("P"); JP.applyBoundary(); - Field3D B0phi = B0*phi; - mesh->communicate(B0phi); + JP.setBoundary("P"); + JP.applyBoundary(); + Field3D B0phi = B0 * phi; + mesh->communicate(B0phi); Field3D JPsi = -Grad_par(B0phi, CELL_YLOW) / B0; - JPsi.setBoundary("Psi"); JPsi.applyBoundary(); + JPsi.setBoundary("Psi"); + JPsi.applyBoundary(); - Field3D JU = b0xcv*Grad(ddt(P)) - - SQ(B0)*Grad_par(Jpar, CELL_CENTRE) - + SQ(B0) * b0xGrad_dot_Grad(ddt(Psi), J0, CELL_CENTRE); - JU.setBoundary("U"); JU.applyBoundary(); + Field3D JU = b0xcv * Grad(ddt(P)) - SQ(B0) * Grad_par(Jpar, CELL_CENTRE) + + SQ(B0) * b0xGrad_dot_Grad(ddt(Psi), J0, CELL_CENTRE); + JU.setBoundary("U"); + JU.applyBoundary(); // Put result into time-derivatives @@ -1736,11 +1735,11 @@ int jacobian(BoutReal t) { * * o System state in variables (as in rhs function) * o Values to be inverted in F_vars - * + * * o Return values should be in vars (overwriting system state) *******************************************************************************/ -int precon_phi(BoutReal t, BoutReal cj, BoutReal delta) { - ddt(phi) = invert_laplace(C_phi - ddt(U), phi_flags, NULL); +int precon_phi(BoutReal UNUSED(t), BoutReal UNUSED(cj), BoutReal UNUSED(delta)) { + ddt(phi) = phiSolver->solve(C_phi - ddt(U)); return 0; } diff --git a/examples/gravity_reduced/gravity_reduced.cxx b/examples/gravity_reduced/gravity_reduced.cxx index 6be8500c8a..53b0437d77 100644 --- a/examples/gravity_reduced/gravity_reduced.cxx +++ b/examples/gravity_reduced/gravity_reduced.cxx @@ -16,7 +16,7 @@ const BoutReal PI = 3.14159265; class GravityReduced : public PhysicsModel { private: - //2D initial profiles + // 2D initial profiles Field2D rho0, p0; Field2D Jpar0; //calculated from equilibrium B field used in bbmhd Jpar0=b.curlB0 @@ -24,43 +24,26 @@ class GravityReduced : public PhysicsModel { Field2D B0; Field2D G; //grad G will give us the gravity paramater. - //Initial perturbations + // Initial perturbations // Field3D U0; //calculated from intial velocity perturbation used in bbmhd. Field3D Vpar0; //parallel component of intial velocity perturbation. - // Field3D psi1; - // Field3D rho1; - // Field3D p1; Field3D phi0; - //testing variables - Field3D testa; - Field3D testb; - Field3D testc; - Field3D testd; - Field3D teste; - Field3D testf; - Field3D testg; - Field3D testh; - - //3D evolving fields Field3D U, rho, p, Vpar, Psi; //Derived variables Field3D Jpar, phi; - // Field3D gam_U, gam_Vpar, gam_p, gam_rho, gam_Psi; // Group of fields for communication FieldGroup comms; - bool nonlinear; - //metric coeffictients + // metric coeffictients Coordinates *coord; - - //parameters + // parameters BoutReal mu_0, Gamma; BoutReal viscos_par; // Parallel viscosity @@ -71,10 +54,13 @@ class GravityReduced : public PhysicsModel { int phi_flags; BRACKET_METHOD bm = BRACKET_ARAKAWA; + + /// Solver for inverting Laplacian + Laplacian *phiSolver; int init(bool restarting) override { - output <<"Solving flute reduced MHD in a slab with gravity\n"; + output << "Solving flute reduced MHD in a slab with gravity\n"; //*************** LOAD DATE FROM GRID FILE ******************** @@ -99,17 +85,11 @@ class GravityReduced : public PhysicsModel { GRID_LOAD(phi0); output << "Loaded phi0\n"; - // GRID_LOAD(p1); - // output << "Loaded p1\n"; - // GRID_LOAD(rho1); - // output << "Loaded rho1\n"; - // GRID_LOAD(psi1); - // output << "Loaded psi1\n"; - //options stuff + // options stuff - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("gravity"); + auto globalOptions = Options::root(); + auto options = globalOptions["gravity"]; OPTION(options, nonlinear, false); @@ -121,14 +101,13 @@ class GravityReduced : public PhysicsModel { OPTION(options, phi_flags, 0); phi.setBoundary("phi"); + + OPTION(options, viscos_par, 0.); + OPTION(options, viscos_perp, 0.); + OPTION(options, mu_0, 1.); + OPTION(options, Gamma, 5./3.); - options->get("viscos_par", viscos_par, 0.); - options->get("viscos_perp", viscos_par, 0.); - - options->get("mu_0", mu_0, 1.); - options->get("gamma", Gamma, 5./3.); - - //load metric tensor components + // load metric tensor components coord = mesh->getCoordinates(); @@ -145,73 +124,45 @@ class GravityReduced : public PhysicsModel { // Tell BOUT++ which variables to evolve // add evolving variables to the communication object - SOLVE_FOR5(rho, p, U, Psi, Vpar); + SOLVE_FOR(rho, p, U, Psi, Vpar); if (!restarting) { // Set initial perturbation // U = U0; // U = Delp2(phi0); U = coord->g11*D2DX2(phi0) + coord->g33*D2DZ2(phi0); - testa = coord->g11*D2DX2(phi0); - testb = coord->g33*D2DZ2(phi0); - testc = coord->g33*D2DZ2(Jpar0); - - testd = coord->g33*D2DZ2(rho0); - Vpar = Vpar0; - // p = p1; - // rho = rho1; - // Psi = psi1; } //******************Set up comms*************** comms.add(rho, p, U, Psi, Vpar); - //extra variables + // extra variables comms.add(phi); Jpar.setBoundary("jpar"); - - - //add variables to output file - - dump.add(phi, "phi", 1); - dump.add(Jpar, "Jpar", 1); - dump.add(G, "G", 0); - // dump.add(U0, "U0", 0); - dump.add(p0, "p0", 0); - dump.add(rho0, "rho0", 0); - dump.add(testa, "testa", 0); - dump.add(testb, "testb", 0); - dump.add(testa, "testc", 0); - dump.add(testb, "testd", 0); - dump.add(teste, "teste", 1); - dump.add(testf, "testf", 1); - dump.add(testg, "testg", 1); - dump.add(testh, "testh", 1); - // dump.add(p1, "p1", 0); - // dump.add(rho1, "rho1", 0); - // dump.add(psi1, "psi1", 0); - // dump.add(gam_Psi, "gam_psi", 1); - // dump.add(gam_p, "gam_p", 1); - // dump.add(gam_rho, "gam_rho", 1); - // dump.add(gam_U, "gam_U", 1); - // dump.add(gam_Vpar, "gam_Vpar", 1); - //dump.add(Vpar0, "Vpar0", 0); + // Add variables to output file + SAVE_REPEAT(phi, Jpar); // Save every output + SAVE_ONCE(G, p0, rho0); + + // Save time derivatives SAVE_REPEAT(ddt(Psi)); SAVE_REPEAT(ddt(U)); SAVE_REPEAT(ddt(rho)); + + // Create a solver for the Laplacian + phiSolver = Laplacian::create(); + phiSolver->setFlags(phi_flags); - return(0); + return 0; } - int rhs(BoutReal t) override { + int rhs(BoutReal UNUSED(t)) override { // U = Delp2(phi); - phi = invert_laplace(U, phi_flags); // Invert Laplacian, setting boundary condition in phi_flags - phi.applyBoundary(); - + phi = phiSolver->solve(U); // Invert Laplacian, setting boundary condition in phi_flags + phi.applyBoundary(); // Apply boundary condition in Y mesh->communicate(comms); @@ -224,21 +175,16 @@ class GravityReduced : public PhysicsModel { ddt(Psi) = -(1/B0)*Grad_par_CtoL(B0*phi);// + 1e-2*Jpar; if (nonlinear) { - //ddt(Psi) +=-(1/B0)*(- b0xGrad_dot_Grad(Psi,B0*phi)); ddt(Psi) += (1/B0)*bracket(Psi, B0*phi, bm)*coord->Bxy; } //Parallel vorticity ddt(U) = (SQ(B0)/rho0)*(Grad_par_LtoC(Jpar/B0) ); - teste = (SQ(B0)/rho0)*(Grad_par_LtoC(Jpar/B0) ); - //ddt(U) += -(1/rho0)*b0xGrad_dot_Grad(G,rho); ddt(U) -= (1/rho0)*bracket(G,rho, bm)*coord->Bxy; - testf = (1/rho0)*bracket(G,rho, bm)*coord->Bxy; - ddt(U) -= (SQ(B0)/rho0)*bracket(Psi,Jpar0/B0, bm)*coord->Bxy; ////added 02/03/2011 WAS MISSING BEFORE - check effect - see if stable. - still stable... - testg = (SQ(B0)/rho0)*bracket(Psi,Jpar0/B0, bm)*coord->Bxy; + ddt(U) -= (SQ(B0)/rho0)*bracket(Psi,Jpar0/B0, bm)*coord->Bxy; if (nonlinear) { ddt(U) -= bracket(phi,U, bm)*coord->Bxy; @@ -247,26 +193,24 @@ class GravityReduced : public PhysicsModel { } // Viscosity terms - if (viscos_par > 0.0) + if (viscos_par > 0.0) { ddt(U) += viscos_par * Grad2_par2(U); // Parallel viscosity + } - if (viscos_perp > 0.0) + if (viscos_perp > 0.0) { ddt(U) += viscos_perp * Delp2(U); // Perpendicular viscosity + } - //Parallel velocity - //ddt(Vpar) = + (b0xGrad_dot_Grad(Psi,p0))/rho0; + // Parallel velocity ddt(Vpar) = bracket(Psi,p0, bm)*coord->Bxy / rho0; ddt(Vpar) += -(Grad_par_CtoL(p))/rho0; - //ddt(Vpar) += b0xGrad_dot_Grad(G,Psi); ddt(Vpar) += bracket(G,Psi, bm)*coord->Bxy; if (nonlinear) { - //ddt(Vpar) += -b0xGrad_dot_Grad(phi,Vpar); ddt(Vpar) -= bracket(phi,Vpar,bm)*coord->Bxy; - //ddt(Vpar) += (b0xGrad_dot_Grad(Psi,p))/rho0; ddt(Vpar) += bracket(Psi,p,bm)*coord->Bxy / rho0; } @@ -302,13 +246,6 @@ class GravityReduced : public PhysicsModel { } } - - //gam_U = 1/U0; //ddt(U)/U0; - // gam_Vpar = 1/Vpar0; //ddt(Vpar)/Vpar0; - // gam_p = 1/p1; //ddt(p)/p1; - // gam_rho = 1/rho1; //ddt(rho)/rho1; - // gam_Psi = 1/psi1; //ddt(Psi)/psi1; - return 0; } }; diff --git a/examples/gyro-gem/gem.cxx b/examples/gyro-gem/gem.cxx index f9562e71d9..79de3dc07f 100644 --- a/examples/gyro-gem/gem.cxx +++ b/examples/gyro-gem/gem.cxx @@ -146,6 +146,10 @@ class GEM : public PhysicsModel { FieldGroup comms; // Communications + /// Solver for inverting Laplacian + Laplacian *phiSolver; + Laplacian *aparSolver; + //////////////////////////////////////////////////////////////////////// // Initialisation @@ -155,8 +159,8 @@ class GEM : public PhysicsModel { ////////////////////////////////// // Read options - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("gem"); + auto globalOptions = Options::root(); + auto options = globalOptions["gem"]; OPTION(options, adiabatic_electrons, false); OPTION(options, small_rho_e, true); @@ -220,9 +224,11 @@ class GEM : public PhysicsModel { ////////////////////////////////// // Pick normalisation factors - if (mesh->get(Lbar, "Lbar")) // Try to read from grid file - if (mesh->get(Lbar, "rmag")) + if (mesh->get(Lbar, "Lbar")) {// Try to read from grid file + if (mesh->get(Lbar, "rmag")) { Lbar = 1.0; + } + } OPTION(options, Lbar, Lbar); // Override in options file SAVE_ONCE(Lbar); // Save in output file @@ -524,6 +530,14 @@ class GEM : public PhysicsModel { phi.setBoundary("phi"); Apar.setBoundary("Apar"); + // Create a solver for the Laplacian + phiSolver = Laplacian::create(); + phiSolver->setFlags(phi_flags); + + aparSolver = Laplacian::create(); + aparSolver->setFlags(apar_flags); + aparSolver->setCoefA(beta_e * (1./mu_e - 1./mu_i)); + return 0; } @@ -551,14 +565,14 @@ class GEM : public PhysicsModel { Field3D dn = Ne - gyroPade1(Ni, rho_i) - gyroPade2(Tiperp, rho_i); - phi = invert_laplace(tau_i * dn / SQ(rho_i), phi_flags); + phi = phiSolver->solve(tau_i * dn / SQ(rho_i)); phi -= tau_i * dn; } else { Field3D dn = gyroPade1(Ne, rho_e) + gyroPade2(Teperp, rho_e) - gyroPade1(Ni, rho_i) - gyroPade2(Tiperp, rho_i); // Neglect electron gyroscreening - phi = invert_laplace(tau_i * dn / (rho_i * rho_i), phi_flags); + phi = phiSolver->solve(tau_i * dn / (rho_i * rho_i)); phi -= tau_i * dn; } @@ -568,7 +582,7 @@ class GEM : public PhysicsModel { // Helmholtz equation for Apar Field2D a = beta_e * (1./mu_e - 1./mu_i); - Apar = invert_laplace(ApUe/mu_e - ApUi/mu_i, apar_flags, &a); + Apar = aparSolver->solve(ApUe/mu_e - ApUi/mu_i); Apar.applyBoundary(); @@ -599,7 +613,7 @@ class GEM : public PhysicsModel { //////////////////////////////////////////////////////////////////////// // Non-stiff part of the RHS function - int convective(BoutReal time) override { + int convective(BoutReal UNUSED(time)) override { calc_aux(); //////////////////////////////////////////// @@ -933,7 +947,7 @@ class GEM : public PhysicsModel { // Stiff part of the RHS function // Artificial dissipation terms - int diffusive(BoutReal time) override { + int diffusive(BoutReal UNUSED(time)) override { Field3D S_D, K_par, K_perp, K_D; // Collisional dissipation terms calc_aux(); diff --git a/examples/shear-alfven-wave/2fluid.cxx b/examples/shear-alfven-wave/2fluid.cxx index 1e15ba4a18..32bd3b1ee3 100644 --- a/examples/shear-alfven-wave/2fluid.cxx +++ b/examples/shear-alfven-wave/2fluid.cxx @@ -46,8 +46,12 @@ class ShearAlfven : public PhysicsModel { // Coordinate system Coordinates *coord; + /// Solver for inverting Laplacian + Laplacian *phiSolver; + Laplacian *aparSolver; + protected: - int init(bool restarting) override { + int init(bool UNUSED(restarting)) override { Field2D I; // Shear factor output << "Solving 6-variable 2-fluid equations\n"; @@ -94,8 +98,8 @@ class ShearAlfven : public PhysicsModel { /*************** READ OPTIONS *************************/ // Read some parameters - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("2fluid"); + auto globalOptions = Options::root(); + auto options = globalOptions["2fluid"]; OPTION(options, AA, 2.0); OPTION(options, ZZ, 1.0); @@ -110,8 +114,7 @@ class ShearAlfven : public PhysicsModel { /************* SHIFTED RADIAL COORDINATES ************/ // Check type of parallel transform - string ptstr; - Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); + std::string ptstr = Options::root()["mesh"]["paralleltransform"].withDefault("identity"); if (lowercase(ptstr) == "shifted") { ShearFactor = 0.0; // I disappears from metric @@ -202,7 +205,7 @@ class ShearAlfven : public PhysicsModel { // Tell BOUT++ which variables to evolve // add evolving variables to the communication object - SOLVE_FOR2(rho, Ajpar); + SOLVE_FOR(rho, Ajpar); comms.add(rho, Ajpar); // Set boundary conditions @@ -217,18 +220,26 @@ class ShearAlfven : public PhysicsModel { } // Add any other variables to be dumped to file - SAVE_REPEAT3(phi, Apar, jpar); + SAVE_REPEAT(phi, Apar, jpar); - SAVE_ONCE3(Ni0, Te0, Ti0); - SAVE_ONCE5(Te_x, Ti_x, Ni_x, rho_s, wci); + SAVE_ONCE(Ni0, Te0, Ti0); + SAVE_ONCE(Te_x, Ti_x, Ni_x, rho_s, wci); + + // Create a solver for the Laplacian + phiSolver = Laplacian::create(); + phiSolver->setFlags(phi_flags); + + aparSolver = Laplacian::create(); + aparSolver->setFlags(apar_flags); + aparSolver->setCoefA((-0.5 * beta_p / fmei) * Ni0); return 0; } - int rhs(BoutReal t) override { + int rhs(BoutReal UNUSED(t)) override { // Solve EM fields - phi = invert_laplace(rho / Ni0, phi_flags); + phi = phiSolver->solve(rho / Ni0); if (ZeroElMass) { mesh->communicate(comms); @@ -239,16 +250,7 @@ class ShearAlfven : public PhysicsModel { mesh->communicate(jpar); } else { - static Field2D a; - static int set = 0; - - if (set == 0) { - // calculate a - a = (-0.5 * beta_p / fmei) * Ni0; - set = 1; - } - - Apar = invert_laplace(-a * Ajpar, apar_flags, &a); + Apar = aparSolver->solve((0.5 * beta_p / fmei) * Ni0 * Ajpar); // Communicate variables mesh->communicate(comms); From e00412e5e1b4835da0955856fe3e4633909d235b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 10:54:03 +0000 Subject: [PATCH 0503/1783] Handle null Mesh* pointers in initialization list --- include/bout/invert/laplacexz.hxx | 7 +------ src/invert/laplacexy/laplacexy.cxx | 8 ++------ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/include/bout/invert/laplacexz.hxx b/include/bout/invert/laplacexz.hxx index 025e06a113..5bdb3902be 100644 --- a/include/bout/invert/laplacexz.hxx +++ b/include/bout/invert/laplacexz.hxx @@ -40,12 +40,7 @@ class LaplaceXZ { public: LaplaceXZ(Mesh* m = nullptr, Options* UNUSED(options) = nullptr, const CELL_LOC loc = CELL_CENTRE) - : localmesh(m), location(loc) { - if (localmesh == nullptr) { - // use global mesh - localmesh = mesh; - } - } + : localmesh(m==nullptr ? mesh : m), location(loc) {} virtual ~LaplaceXZ() {} virtual void setCoefs(const Field2D &A, const Field2D &B) = 0; diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index 85845283e7..6fb32d5f14 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -25,14 +25,10 @@ static PetscErrorCode laplacePCapply(PC pc,Vec x,Vec y) { PetscFunctionReturn(s->precon(x, y)); } -LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) : localmesh(m), location(loc) { +LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) + : localmesh(m==nullptr ? mesh : m), location(loc) { Timer timer("invert"); - if (localmesh == nullptr) { - // Use global mesh - localmesh = mesh; - } - if (opt == nullptr) { // If no options supplied, use default opt = Options::getRoot()->getSection("laplacexy"); From 777306c7463c640fdfb0309ade5d72b466615839 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 19 Dec 2018 12:49:17 +0000 Subject: [PATCH 0504/1783] Appending NetCDF files working Values can have a "time_dimension" attribute, then the file appended to add additional records. --- include/options_netcdf.hxx | 15 +- src/sys/options/options_netcdf.cxx | 259 ++++++++++++------ tests/integrated/test-options-netcdf/runtest | 4 +- .../test-options-netcdf.cxx | 33 ++- 4 files changed, 217 insertions(+), 94 deletions(-) diff --git a/include/options_netcdf.hxx b/include/options_netcdf.hxx index 70735e7a86..5b4e171298 100644 --- a/include/options_netcdf.hxx +++ b/include/options_netcdf.hxx @@ -13,7 +13,12 @@ class OptionsNetCDF { public: - OptionsNetCDF(const std::string &filename) {} + enum class FileMode { + replace, ///< Overwrite file when writing + append ///< Append to file when writing + }; + + OptionsNetCDF(const std::string &filename, FileMode mode = FileMode::replace) {} /// Read options from file Options read() { @@ -34,7 +39,12 @@ public: class OptionsNetCDF { public: - OptionsNetCDF(const std::string &filename) : filename(filename) {} + enum class FileMode { + replace, ///< Overwrite file when writing + append ///< Append to file when writing + }; + + OptionsNetCDF(const std::string &filename, FileMode mode = FileMode::replace) : filename(filename), file_mode(mode) {} /// Read options from file Options read(); @@ -44,6 +54,7 @@ public: private: std::string filename; + FileMode file_mode; /// NetCDF doesn't seem to keep track of the current index /// for each variable. This map keeps track of the current diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 2354b04604..eaae502402 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -3,14 +3,15 @@ #include "options_netcdf.hxx" -#include +#include #include +#include using namespace netCDF; namespace { -void readGroup(const std::string &filename, NcGroup group, Options& result) { - +void readGroup(const std::string& filename, NcGroup group, Options& result) { + // Iterate over all variables for (const auto& varpair : group.getVars()) { const auto& var_name = varpair.first; // Name of the variable @@ -51,7 +52,7 @@ void readGroup(const std::string &filename, NcGroup group, Options& result) { for (const auto& grouppair : group.getGroups()) { const auto& name = grouppair.first; const auto& subgroup = grouppair.second; - + readGroup(filename, subgroup, result[name]); } } @@ -67,7 +68,7 @@ Options OptionsNetCDF::read() { Options result; readGroup(filename, dataFile, result); - + return result; } @@ -86,7 +87,7 @@ template <> NcType NcTypeVisitor::operator()(const bool& UNUSED(t)) { return ncInt; } - + template <> NcType NcTypeVisitor::operator()(const int& UNUSED(t)) { return ncInt; @@ -124,30 +125,35 @@ struct NcDimVisitor { std::vector operator()(const T& UNUSED(t)) { return {}; } + private: NcGroup& group; }; NcDim findDimension(NcGroup& group, const std::string& name, unsigned int size) { // Get the dimension - auto dim = group.getDim(name, NcGroup::ParentsAndCurrent); - if (dim.isNull()) { - // Dimension doesn't yet exist - dim = group.addDim(name, size); - } else { - // Dimension exists, check it's the right size - if (dim.getSize() != size) { - // wrong size. Check this group - dim = group.getDim(name, NcGroup::Current); - if (!dim.isNull()) { - // Already defined in this group - return {}; // Return null object - } - // Define in this group + try { + auto dim = group.getDim(name, NcGroup::ParentsAndCurrent); + if (dim.isNull()) { + // Dimension doesn't yet exist dim = group.addDim(name, size); + } else { + // Dimension exists, check it's the right size + if (dim.getSize() != size) { + // wrong size. Check this group + dim = group.getDim(name, NcGroup::Current); + if (!dim.isNull()) { + // Already defined in this group + return {}; // Return null object + } + // Define in this group + dim = group.addDim(name, size); + } } + return dim; + } catch (const std::exception& e) { + throw BoutException("Error in findDimension('%s'): %s", name.c_str(), e.what()); } - return dim; } template <> @@ -157,7 +163,7 @@ std::vector NcDimVisitor::operator()(const Field2D& value) { auto ydim = findDimension(group, "y", value.getNy()); ASSERT0(!ydim.isNull()); - + return {xdim, ydim}; } @@ -168,10 +174,10 @@ std::vector NcDimVisitor::operator()(const Field3D& value) { auto ydim = findDimension(group, "y", value.getNy()); ASSERT0(!ydim.isNull()); - + auto zdim = findDimension(group, "z", value.getNz()); ASSERT0(!zdim.isNull()); - + return {xdim, ydim, zdim}; } @@ -201,17 +207,18 @@ void NcPutVarVisitor::operator()(const std::string& value) { template <> void NcPutVarVisitor::operator()(const Field2D& value) { // Pointer to data. Assumed to be contiguous array - var.putVar(&value(0,0)); + var.putVar(&value(0, 0)); } template <> void NcPutVarVisitor::operator()(const Field3D& value) { // Pointer to data. Assumed to be contiguous array - var.putVar(&value(0,0,0)); + var.putVar(&value(0, 0, 0)); } /// Visit a variant type, and put the data into a NcVar struct NcPutVarCountVisitor { - NcPutVarCountVisitor(NcVar& var, const std::vector &start, const std::vector &count) + NcPutVarCountVisitor(NcVar& var, const std::vector& start, + const std::vector& count) : var(var), start(start), count(count) {} template void operator()(const T& value) { @@ -220,8 +227,8 @@ struct NcPutVarCountVisitor { private: NcVar& var; - const std::vector &start; ///< Starting (corner) index - const std::vector &count; ///< Index count in each dimension + const std::vector& start; ///< Starting (corner) index + const std::vector& count; ///< Index count in each dimension }; template <> @@ -232,89 +239,173 @@ void NcPutVarCountVisitor::operator()(const std::string& value) { template <> void NcPutVarCountVisitor::operator()(const Field2D& value) { // Pointer to data. Assumed to be contiguous array - var.putVar(start, count, &value(0,0)); + var.putVar(start, count, &value(0, 0)); } template <> void NcPutVarCountVisitor::operator()(const Field3D& value) { // Pointer to data. Assumed to be contiguous array - var.putVar(start, count, &value(0,0,0)); + for (unsigned int i=0;i &time_index) { + +void writeGroup(const Options& options, NcGroup group, + std::map& time_index) { for (const auto& childpair : options.getChildren()) { const auto& name = childpair.first; const auto& child = childpair.second; if (child.isValue()) { - auto nctype = bout::utils::visit(NcTypeVisitor(), child.value); - - if (nctype.isNull()) { - continue; // Skip this value - } + try { + auto nctype = bout::utils::visit(NcTypeVisitor(), child.value); - auto dims = bout::utils::visit(NcDimVisitor(group), child.value); - - auto time_it = child.attributes.find("time_dimension"); - if (time_it != child.attributes.end()) { - // Has a time dimension - - auto time_name = bout::utils::get(time_it->second); - auto time_dim = group.getDim(time_name, NcGroup::ParentsAndCurrent); - if (time_dim.isNull()) { - time_dim = group.addDim(time_name); + if (nctype.isNull()) { + continue; // Skip this value } - // Get the index - auto time_index_it = time_index.find(time_dim.getId()); - - if (time_index_it == time_index.end()) { - // Haven't seen this index before - time_index[time_dim.getId()] = time_dim.getSize(); + // Get spatial dimensions + auto spatial_dims = bout::utils::visit(NcDimVisitor(group), child.value); + + // Vector of all dimensions, including time + std::vector dims{spatial_dims}; + + // Get the time dimension + NcDim time_dim; ///< Time dimension (Null -> none) + auto time_it = child.attributes.find("time_dimension"); + if (time_it != child.attributes.end()) { + // Has a time dimension + + auto time_name = bout::utils::get(time_it->second); + time_dim = group.getDim(time_name, NcGroup::ParentsAndCurrent); + if (time_dim.isNull()) { + time_dim = group.addDim(time_name); + } + + // prepend to vector of dimensions + dims.insert(dims.begin(), time_dim); } - - // prepend to vector of dimensions - dims.insert(dims.begin(), time_dim); - - std::vector start_index; ///< Starting index where data will be inserted - std::vector count_index; ///< Size of each dimension - - // Time dimension - start_index.push_back(time_index[time_dim.getId()]); - count_index.push_back(1); // Writing one record - - // Other dimensions (if any) - for (const auto& dim : dims) { - start_index.push_back(0); - count_index.push_back(dim.getSize()); + + // Check if the variable exists + auto var = group.getVar(name); + if (var.isNull()) { + // Variable doesn't exist yet + // Create variable + var = group.addVar(name, nctype, dims); + } else { + // Variable does exist + + // Check types are the same + if (var.getType() != nctype) { + throw BoutException( + "Changed type of variable '%s'. Was '%s', now writing '%s'", name.c_str(), + var.getType().getName().c_str(), nctype.getName().c_str()); + } + + // Check that the dimensions are correct + auto var_dims = var.getDims(); + + // Same number of dimensions? + if (var_dims.size() != dims.size()) { + throw BoutException("Changed dimensions for variable '%s'\nIn file has %d " + "dimensions, now writing %d\n", + name.c_str(), var_dims.size(), dims.size()); + } + // Dimensions compatible? + for (std::vector::size_type i = 0; i < dims.size(); ++i) { + if (var_dims[i] == dims[i]) { + continue; // The same dimension -> ok + } + if (var_dims[i].isUnlimited() != dims[i].isUnlimited()) { + throw BoutException("Unlimited dimension changed for variable '%s'", + name.c_str()); + } + if (var_dims[i].getSize() != dims[i].getSize()) { + throw BoutException("Dimension size changed for variable '%s'", + name.c_str()); + } + } + // All ok. Set dimensions to the variable's NcDims + dims = var_dims; + + if (!time_dim.isNull()) { + // A time dimension + time_dim = dims[0]; + } } - // Create variable - auto var = group.addVar(name, nctype, dims); - - // Put the data into the variable - bout::utils::visit(NcPutVarCountVisitor(var, start_index, count_index), child.value); - } else { - // No time index - - auto var = group.addVar(name, nctype, dims); - - // Put the data into the variable - bout::utils::visit(NcPutVarVisitor(var), child.value); + // Write the variable + + if (time_dim.isNull()) { + // No time index + + // Put the data into the variable + bout::utils::visit(NcPutVarVisitor(var), child.value); + + } else { + // Has a time index, so need the record index + + // Get the index from the map storing the current index + // This is needed because NetCDF doesn't provide a way to get + // the size of this variable along an unlimited dimension. + // Instead the dimension is shared between variables. + + auto time_index_it = time_index.find(time_dim.getId()); + if (time_index_it == time_index.end()) { + // Haven't seen this index before + time_index[time_dim.getId()] = time_dim.getSize(); + } + + std::vector start_index; ///< Starting index where data will be inserted + std::vector count_index; ///< Size of each dimension + + + + // Dimensions, including time + for (const auto& dim : dims) { + start_index.push_back(0); + count_index.push_back(dim.getSize()); + } + // Time dimension + start_index[0] = time_index[time_dim.getId()]; + count_index[0] = 1; // Writing one record + + // Put the data into the variable + bout::utils::visit(NcPutVarCountVisitor(var, start_index, count_index), + child.value); + } + } catch (const std::exception &e) { + throw BoutException("Error while writing value '%s' : %s", name.c_str(), e.what()); } } if (child.isSection()) { - writeGroup(child, group.addGroup(name), time_index); + // Check if the group exists + TRACE("Writing group '%s'", name.c_str()); + + auto subgroup = group.getGroup(name); + if (subgroup.isNull()) { + // Doesn't exist yet, so create it + subgroup = group.addGroup(name); + } + + writeGroup(child, subgroup, time_index); } } } - + } // namespace /// Write options to file void OptionsNetCDF::write(const Options& options) { - NcFile dataFile(filename, NcFile::replace); + // Check the file mode to use + auto ncmode = NcFile::replace; + if (file_mode == FileMode::append) { + ncmode = NcFile::write; + } + + NcFile dataFile(filename, ncmode); if (dataFile.isNull()) { throw BoutException("Could not open NetCDF file '%s' for writing", filename.c_str()); diff --git a/tests/integrated/test-options-netcdf/runtest b/tests/integrated/test-options-netcdf/runtest index e8a2a2328f..c36e664e03 100755 --- a/tests/integrated/test-options-netcdf/runtest +++ b/tests/integrated/test-options-netcdf/runtest @@ -49,9 +49,9 @@ settings = BoutOptionsFile("settings.ini") assert settings["mesh"]["nx"] == 5 assert settings["mesh"]["ny"] == 2 -print("Checking saved settings.nc") +print("Checking saved fields.nc") -with DataFile("settings.nc") as f: +with DataFile("fields.nc") as f: assert f["f2d"].shape == (5,6) # Field2D assert f["f3d"].shape == (5,6,2) # Field3D assert np.allclose(f["f2d"], 1.0) diff --git a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx index 76374c7571..66809488dd 100644 --- a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx +++ b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx @@ -22,12 +22,6 @@ int main(int argc, char** argv) { OptionsNetCDF("test-out.nc").write(values); /////////////////////////// - - Options::root()["f2d"] = Field2D(1.0); - Options::root()["f3d"] = Field3D(2.0); - - Options::root()["time_test"] = 1.0; - Options::root()["time_test"].attributes["time_dimension"] = std::string("t"); // Write the BOUT.inp settings to NetCDF file OptionsNetCDF("settings.nc").write(Options::root()); @@ -38,5 +32,32 @@ int main(int argc, char** argv) { // Write to INI file reader->write(&settings, "settings.ini"); + /////////////////////////// + // Write fields + + Options fields; + fields["f2d"] = Field2D(1.0); + fields["f3d"] = Field3D(2.0); + OptionsNetCDF("fields.nc").write(fields); + + /////////////////////////// + // Time dependent values + + Options data; + data["scalar"] = 1.0; + data["scalar"].attributes["time_dimension"] = std::string("t"); + + data["field"] = Field3D(2.0); + data["field"].attributes["time_dimension"] = std::string("t"); + + OptionsNetCDF("time.nc").write(data); + + // Update time-dependent values + data["scalar"].force(2.0); + data["field"].force(Field3D(3.0)); + + // Append data to file + OptionsNetCDF("time.nc", OptionsNetCDF::FileMode::append).write(data); + BoutFinalise(); }; From 13d4ddc9377580c8b7e67f3e3eda2a8802293e7f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 14:55:55 +0000 Subject: [PATCH 0505/1783] Use unique_ptr for LaplaceXZcyclic::cr --- src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx | 7 +------ src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx | 4 ++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx index 662f75112f..b1f763b6eb 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx @@ -41,7 +41,7 @@ LaplaceXZcyclic::LaplaceXZcyclic(Mesh *m, Options *options, const CELL_LOC loc) k1d_2 = Array((m->LocalNz) / 2 + 1); // Create a cyclic reduction object, operating on dcomplex values - cr = new CyclicReduce(localmesh->getXcomm(), nloc); + cr = bout::utils::make_unique>(localmesh->getXcomm(), nloc); // Getting the boundary flags OPTION(options, inner_boundary_flags, 0); @@ -55,11 +55,6 @@ LaplaceXZcyclic::LaplaceXZcyclic(Mesh *m, Options *options, const CELL_LOC loc) setCoefs(one, zero); } -LaplaceXZcyclic::~LaplaceXZcyclic() { - // Delete tridiagonal solver - delete cr; -} - void LaplaceXZcyclic::setCoefs(const Field2D &A2D, const Field2D &B2D) { TRACE("LaplaceXZcyclic::setCoefs"); Timer timer("invert"); diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx index 93c0a22665..13e02dbcdf 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx @@ -9,7 +9,7 @@ class LaplaceXZcyclic : public LaplaceXZ { public: LaplaceXZcyclic(Mesh *m = nullptr, Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE); - ~LaplaceXZcyclic(); + ~LaplaceXZcyclic() {} using LaplaceXZ::setCoefs; void setCoefs(const Field2D &A, const Field2D &B) override; @@ -21,7 +21,7 @@ private: int nmode, nloc, nsys; Matrix acoef, bcoef, ccoef, xcmplx, rhscmplx; Array k1d, k1d_2; - CyclicReduce *cr; ///< Tridiagonal solver + std::unique_ptr> cr; ///< Tridiagonal solver int inner_boundary_flags; ///< Flags to set inner boundary condition int outer_boundary_flags; ///< Flags to set outer boundary condition From 8cf236239079f26539898259acddd412e5a0f380 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 19 Dec 2018 15:25:42 +0000 Subject: [PATCH 0506/1783] Add Array, Matrix and Tensor to Options variant Can store these objects in the Options tree, and use them to read from NetCDF files. Can't yet convert them to Fields. --- include/options.hxx | 23 ++++++++++- include/utils.hxx | 18 +++++++- src/sys/options.cxx | 23 ++++++++--- src/sys/options/options_netcdf.cxx | 41 ++++++++++++++++--- .../test-options-netcdf.cxx | 9 ++++ 5 files changed, 100 insertions(+), 14 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index 16c9f77e88..d21dfd834c 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -183,7 +183,9 @@ public: static void cleanup(); /// The type used to store values - using ValueType = bout::utils::variant; + using ValueType = + bout::utils::variant, Matrix, Tensor>; /// The type used to store attributes using AttributeType = bout::utils::variant; @@ -568,7 +570,24 @@ template<> inline void Options::assign<>(Field3D val, const std::string source) value_used = false; is_value = true; } - +template<> inline void Options::assign<>(Array val, const std::string source) { + value = std::move(val); + attributes["source"] = std::move(source); + value_used = false; + is_value = true; +} +template<> inline void Options::assign<>(Matrix val, const std::string source) { + value = std::move(val); + attributes["source"] = std::move(source); + value_used = false; + is_value = true; +} +template<> inline void Options::assign<>(Tensor val, const std::string source) { + value = std::move(val); + attributes["source"] = std::move(source); + value_used = false; + is_value = true; +} /// Specialised similar comparison methods template <> inline bool Options::similar(BoutReal a, BoutReal b) const { return fabs(a - b) < 1e-10; } diff --git a/include/utils.hxx b/include/utils.hxx index a574c27264..1ede0b05ee 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -222,12 +222,13 @@ public: void ensureUnique() { data.ensureUnique(); } - + private: size_type n1, n2, n3; Array data; }; + /************************************************************************** * Matrix routines **************************************************************************/ @@ -389,6 +390,21 @@ inline std::string toString<>(const std::string& val) { return val; } +template <> +inline std::string toString<>(const Array& UNUSED(val)) { + return ""; +} + +template <> +inline std::string toString<>(const Matrix& UNUSED(val)) { + return ""; +} + +template <> +inline std::string toString<>(const Tensor& UNUSED(val)) { + return ""; +} + /// Convert a bool to "true" or "false" template <> inline std::string toString<>(const bool& val) { diff --git a/src/sys/options.cxx b/src/sys/options.cxx index a5a3ccf9ce..e6a9ba3568 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -244,7 +244,7 @@ template <> bool Options::as(Mesh* UNUSED(mesh)) const { return result; } -template <> Field3D Options::as(Mesh* mesh) const { +template <> Field3D Options::as(Mesh* localmesh) const { if (!is_value) { throw BoutException("Option %s has no value", full_name.c_str()); } @@ -257,16 +257,22 @@ template <> Field3D Options::as(Mesh* mesh) const { // Convert from a string using FieldFactory if (bout::utils::holds_alternative(value)) { - return FieldFactory::get()->create3D( bout::utils::get(value), this, mesh); + return FieldFactory::get()->create3D( bout::utils::get(value), this, localmesh); + } else if (bout::utils::holds_alternative>(value)) { + if (!localmesh) { + throw BoutException("mesh must be supplied when converting Tensor to Field3D"); + } + + } else { - throw BoutException(_("Value for option %s cannot be converted to a BoutReal"), + throw BoutException(_("Value for option %s cannot be converted to a Field3D"), full_name.c_str()); } } return val; } -template <> Field2D Options::as(Mesh* mesh) const { +template <> Field2D Options::as(Mesh* localmesh) const { if (!is_value) { throw BoutException("Option %s has no value", full_name.c_str()); } @@ -279,9 +285,14 @@ template <> Field2D Options::as(Mesh* mesh) const { // Convert from a string using FieldFactory if (bout::utils::holds_alternative(value)) { - return FieldFactory::get()->create2D( bout::utils::get(value), this, mesh); + return FieldFactory::get()->create2D( bout::utils::get(value), this, localmesh); + } else if (bout::utils::holds_alternative>(value)) { + if (!localmesh) { + throw BoutException("mesh must be supplied when converting Matrix to Field2D"); + } + } else { - throw BoutException(_("Value for option %s cannot be converted to a BoutReal"), + throw BoutException(_("Value for option %s cannot be converted to a Field2D"), full_name.c_str()); } } diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index eaae502402..0a92db56ca 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -16,12 +16,15 @@ void readGroup(const std::string& filename, NcGroup group, Options& result) { for (const auto& varpair : group.getVars()) { const auto& var_name = varpair.first; // Name of the variable const auto& var = varpair.second; // The NcVar object - - if (var.getDimCount() == 0) { + + auto var_type = var.getType(); // Variable type + auto ndims = var.getDimCount(); // Number of dimensions + auto dims = var.getDims(); // Vector of dimensions + + switch (ndims) { + case 0: { // Scalar variables - - auto var_type = var.getType(); - + if (var_type == ncDouble) { double value; var.getVar(&value); @@ -45,6 +48,34 @@ void readGroup(const std::string& filename, NcGroup group, Options& result) { } // Note: NetCDF does not support boolean atoms // else ignore + break; + } + case 1: { + if (var_type == ncDouble) { + Array value{dims[0].getSize()}; + var.getVar(value.begin()); + result[var_name] = value; + result[var_name].attributes["source"] = filename; + } + break; + } + case 2: { + if (var_type == ncDouble) { + Matrix value{dims[0].getSize(), dims[1].getSize()}; + var.getVar(value.begin()); + result[var_name] = value; + result[var_name].attributes["source"] = filename; + } + break; + } + case 3: { + if (var_type == ncDouble) { + Tensor value{dims[0].getSize(), dims[1].getSize(), dims[2].getSize()}; + var.getVar(value.begin()); + result[var_name] = value; + result[var_name].attributes["source"] = filename; + } + } } } diff --git a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx index 66809488dd..74a8f2dd10 100644 --- a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx +++ b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx @@ -39,6 +39,15 @@ int main(int argc, char** argv) { fields["f2d"] = Field2D(1.0); fields["f3d"] = Field3D(2.0); OptionsNetCDF("fields.nc").write(fields); + + /////////////////////////// + // Read fields + + Options fields_in = OptionsNetCDF("fields.nc").read(); + + Field2D f2d = fields_in["f2d"]; + + reader->write(&fields_in, "fields.ini"); /////////////////////////// // Time dependent values From eb8850a46d0963d15f20372612868b3661756fac Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 19 Dec 2018 19:30:28 +0000 Subject: [PATCH 0507/1783] Make absence of fftw-wisdom non-fatal in configure --- configure | 14 ++++++++------ configure.ac | 9 +++++---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/configure b/configure index ac1c112489..47bb04ca98 100755 --- a/configure +++ b/configure @@ -6166,7 +6166,7 @@ fi if test "x$fftw_path" != "xno"; then : - fftw_wisdom0=`$as_dirname -- "$fftw_path" || + fftw_wisdom0=`$as_dirname -- "$fftw_path" || $as_expr X"$fftw_path" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$fftw_path" : 'X\(//\)[^/]' \| \ X"$fftw_path" : 'X\(//\)$' \| \ @@ -6189,7 +6189,7 @@ $as_echo X"$fftw_path" | q } s/.*/./; q'` - fftw_wisdom=`$as_dirname -- "$fftw_wisdom0" || + fftw_wisdom=`$as_dirname -- "$fftw_wisdom0" || $as_expr X"$fftw_wisdom0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$fftw_wisdom0" : 'X\(//\)[^/]' \| \ X"$fftw_wisdom0" : 'X\(//\)$' \| \ @@ -6212,7 +6212,12 @@ $as_echo X"$fftw_wisdom0" | q } s/.*/./; q'` - with_fftw="$with_fftw $fftw_wisdom" + with_fftw="$with_fftw $fftw_wisdom" + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: FFTW3 requested but fftw-wisdom not found" >&5 +$as_echo "$as_me: FFTW3 requested but fftw-wisdom not found" >&6;} +fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fftw3.h" >&5 @@ -6462,9 +6467,6 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu CXXFLAGS="$CXXFLAGS -DBOUT_HAS_FFTW" HAS_FFTW="yes" -else - as_fn_error $? "FFTW3 requested but fftw-wisdom not found" "$LINENO" 5 -fi else { $as_echo "$as_me:${as_lineno-$LINENO}: Configuring without FFTW3 is not recommended" >&5 diff --git a/configure.ac b/configure.ac index 267eae7e0b..7d787c0af4 100644 --- a/configure.ac +++ b/configure.ac @@ -396,9 +396,10 @@ AS_IF([test "x$with_fftw" != "xno"], [ AC_PATH_PROG([fftw_path], [fftw-wisdom], [no], [$with_fftw$PATH_SEPARATOR$PATH]) AS_IF([test "x$fftw_path" != "xno"], [ - fftw_wisdom0=`AS_DIRNAME(["$fftw_path"])` - fftw_wisdom=`AS_DIRNAME(["$fftw_wisdom0"])` - with_fftw="$with_fftw $fftw_wisdom" + fftw_wisdom0=`AS_DIRNAME(["$fftw_path"])` + fftw_wisdom=`AS_DIRNAME(["$fftw_wisdom0"])` + with_fftw="$with_fftw $fftw_wisdom" + ], AC_MSG_NOTICE([FFTW3 requested but fftw-wisdom not found])) BOUT_ADDPATH_CHECK_HEADER(fftw3.h, ,AC_MSG_ERROR([FFTW3 requested but header not found]), $with_fftw) BOUT_ADDPATH_CHECK_LIB(fftw3, fftw_plan_dft_r2c_1d, ,AC_MSG_ERROR([FFTW3 requested but library not found]), $with_fftw) @@ -407,7 +408,7 @@ AC_PATH_PROG([fftw_path], [fftw-wisdom], [no], [$with_fftw$PATH_SEPARATOR$PATH]) #add our define to CXXFLAGS CXXFLAGS="$CXXFLAGS -DBOUT_HAS_FFTW" HAS_FFTW="yes" -], AC_MSG_ERROR([FFTW3 requested but fftw-wisdom not found]))], +], [ AC_MSG_NOTICE([Configuring without FFTW3 is not recommended]) HAS_FFTW="no" From c93eefd314951ba5dafae7436fb7218d50c2f6cf Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 19 Dec 2018 23:57:36 +0000 Subject: [PATCH 0508/1783] Make Matrix and Tensor data members public Allow access to underlying Array storage. This is to enable Fields to be constructed from Matrix objects, if a Mesh is also supplied. Also make size() and empty() member functions const. --- include/utils.hxx | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/include/utils.hxx b/include/utils.hxx index 1ede0b05ee..236bd709ef 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -98,7 +98,7 @@ public: Matrix(size_type n1, size_type n2) : n1(n1), n2(n2) { data = Array(n1*n2); } - Matrix(const Matrix &other) : n1(other.n1), n2(other.n2), data(other.data) { + Matrix(const Matrix &other) : data(other.data), n1(other.n1), n2(other.n2) { // Prevent copy on write for Matrix data.ensureUnique(); } @@ -135,9 +135,9 @@ public: T* end() { return std::end(data);}; const T* end() const { return std::end(data);}; - std::tuple shape() { return std::make_tuple(n1, n2);}; + std::tuple shape() const { return std::make_tuple(n1, n2);}; - bool empty(){ + bool empty() const { return n1*n2 == 0; } @@ -150,9 +150,10 @@ public: data.ensureUnique(); } + /// Underlying 1D storage array + Array data; private: size_type n1, n2; - Array data; }; /// Helper class for 3D arrays @@ -168,7 +169,7 @@ public: Tensor(size_type n1, size_type n2, size_type n3) : n1(n1), n2(n2), n3(n3) { data = Array(n1*n2*n3); } - Tensor(const Tensor &other) : n1(other.n1), n2(other.n2), n3(other.n3), data(other.data) { + Tensor(const Tensor &other) : data(other.data), n1(other.n1), n2(other.n2), n3(other.n3) { // Prevent copy on write for Tensor data.ensureUnique(); } @@ -208,9 +209,9 @@ public: T* end() { return std::end(data);}; const T* end() const { return std::end(data);}; - std::tuple shape() { return std::make_tuple(n1, n2, n3);}; + std::tuple shape() const { return std::make_tuple(n1, n2, n3);}; - bool empty(){ + bool empty() const { return n1*n2*n3 == 0; } @@ -222,10 +223,11 @@ public: void ensureUnique() { data.ensureUnique(); } - + + /// Underlying 1D storage array + Array data; private: size_type n1, n2, n3; - Array data; }; From efca84b994c9f571cf41be2b950f0ecb1e4dcb95 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 19 Dec 2018 23:59:25 +0000 Subject: [PATCH 0509/1783] Add Field2D and Field3D constructors from Array Creates a Field from an Array, a Mesh, and a cell location (default CELL_CENTRE). --- include/field2d.hxx | 5 ++++- include/field3d.hxx | 2 ++ src/field/field2d.cxx | 12 ++++++++++++ src/field/field3d.cxx | 12 ++++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/include/field2d.hxx b/include/field2d.hxx index 955044904d..b5f43c6c1e 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -83,7 +83,10 @@ class Field2D : public Field, public FieldData { * boundary cells. */ Field2D(BoutReal val, Mesh *localmesh = nullptr); - + + /// Constructor from Array and Mesh + Field2D(Array data, Mesh *localmesh, CELL_LOC location = CELL_CENTRE); + /*! * Destructor */ diff --git a/include/field3d.hxx b/include/field3d.hxx index c3bd525f12..4f473ee5f5 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -180,6 +180,8 @@ class Field3D : public Field, public FieldData { Field3D(const Field2D& f); /// Constructor from value Field3D(BoutReal val, Mesh *localmesh = nullptr); + /// Constructor from Array and Mesh + Field3D(Array data, Mesh *localmesh, CELL_LOC location = CELL_CENTRE); /// Destructor ~Field3D() override; diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 02f2a2e480..8bc8a4740e 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -84,6 +84,18 @@ Field2D::Field2D(BoutReal val, Mesh* localmesh) : Field(localmesh) { *this = val; } +Field2D::Field2D(Array data, Mesh *localmesh, CELL_LOC datalocation) : Field(localmesh), data(data) { + + ASSERT1(fieldmesh != nullptr); + + nx = fieldmesh->LocalNx; + ny = fieldmesh->LocalNy; + + ASSERT1(data.size() == nx * ny); + + setLocation(datalocation); +} + Field2D::~Field2D() { if(deriv) delete deriv; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 6ab7a4ef79..228983db85 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -101,6 +101,18 @@ Field3D::Field3D(const BoutReal val, Mesh* localmesh) : Field(localmesh) { *this = val; } +Field3D::Field3D(Array data, Mesh *localmesh, CELL_LOC datalocation) : Field(localmesh), data(data) { + TRACE("Field3D: Copy constructor from Array and Mesh"); + + nx = fieldmesh->LocalNx; + ny = fieldmesh->LocalNy; + nz = fieldmesh->LocalNz; + + ASSERT1( data.size() == nx * ny * nz ); + + setLocation(datalocation); +} + Field3D::~Field3D() { /// Delete the time derivative variable if allocated if (deriv != nullptr) { From 383e870df96c12cc42717fa50ea1a00dc6f8bbb9 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 20 Dec 2018 00:01:10 +0000 Subject: [PATCH 0510/1783] Options convert Matrix->Field2D, Tensor->Field3D Need to be given a Mesh pointer, and currently only works if the dimension sizes are the same. More general conversion e.g. from grid file inputs, needs information on the global origin from Mesh. --- src/sys/options.cxx | 44 ++++++++++++------- src/sys/options/options_netcdf.cxx | 3 -- tests/integrated/test-options-netcdf/runtest | 8 ++++ .../test-options-netcdf.cxx | 10 ++++- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/sys/options.cxx b/src/sys/options.cxx index e6a9ba3568..cc274d7082 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -249,10 +249,8 @@ template <> Field3D Options::as(Mesh* localmesh) const { throw BoutException("Option %s has no value", full_name.c_str()); } - Field3D val; - try { - val = bout::utils::variantStaticCastOrThrow(value); + return bout::utils::variantStaticCastOrThrow(value); } catch (const std::bad_cast &e) { // Convert from a string using FieldFactory @@ -262,14 +260,24 @@ template <> Field3D Options::as(Mesh* localmesh) const { if (!localmesh) { throw BoutException("mesh must be supplied when converting Tensor to Field3D"); } + + // Get a reference, to try and avoid copying + const auto& tensor = bout::utils::get>(value); - - } else { - throw BoutException(_("Value for option %s cannot be converted to a Field3D"), - full_name.c_str()); + // Check if the dimension sizes are the same as a Field3D + if (tensor.shape() == std::make_tuple(localmesh->LocalNx, + localmesh->LocalNy, + localmesh->LocalNz)) { + return Field3D(tensor.data, localmesh); + } + // If dimension sizes not the same, may be able + // to select a region from it using Mesh e.g. if this + // is from the input grid file. + } } - return val; + throw BoutException(_("Value for option %s cannot be converted to a Field3D"), + full_name.c_str()); } template <> Field2D Options::as(Mesh* localmesh) const { @@ -277,10 +285,8 @@ template <> Field2D Options::as(Mesh* localmesh) const { throw BoutException("Option %s has no value", full_name.c_str()); } - Field2D val; - try { - val = bout::utils::variantStaticCastOrThrow(value); + return bout::utils::variantStaticCastOrThrow(value); } catch (const std::bad_cast &e) { // Convert from a string using FieldFactory @@ -290,13 +296,19 @@ template <> Field2D Options::as(Mesh* localmesh) const { if (!localmesh) { throw BoutException("mesh must be supplied when converting Matrix to Field2D"); } - - } else { - throw BoutException(_("Value for option %s cannot be converted to a Field2D"), - full_name.c_str()); + + // Get a reference, to try and avoid copying + const auto& matrix = bout::utils::get>(value); + + // Check if the dimension sizes are the same as a Field3D + if (matrix.shape() == std::make_tuple(localmesh->LocalNx, + localmesh->LocalNy)) { + return Field2D(matrix.data, localmesh); + } } } - return val; + throw BoutException(_("Value for option %s cannot be converted to a Field2D"), + full_name.c_str()); } void Options::printUnused() const { diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 0a92db56ca..d560f2f582 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -275,9 +275,6 @@ void NcPutVarCountVisitor::operator()(const Field2D& value) { template <> void NcPutVarCountVisitor::operator()(const Field3D& value) { // Pointer to data. Assumed to be contiguous array - for (unsigned int i=0;i Passed") diff --git a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx index 74a8f2dd10..e7d582b3a3 100644 --- a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx +++ b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx @@ -45,9 +45,15 @@ int main(int argc, char** argv) { Options fields_in = OptionsNetCDF("fields.nc").read(); - Field2D f2d = fields_in["f2d"]; + auto f2d = fields_in["f2d"].as(mesh); + auto f3d = fields_in["f3d"].as(mesh); + + Options fields2; + fields2["f2d"] = f2d; + fields2["f3d"] = f3d; - reader->write(&fields_in, "fields.ini"); + // Write out again + OptionsNetCDF("fields2.nc").write(fields2); /////////////////////////// // Time dependent values From 966e560f1a1ca6da354b8d2b7ac5924dede499f2 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 20 Dec 2018 13:30:37 +0000 Subject: [PATCH 0511/1783] Removing more invert_laplace uses Some changes to LaplaceXY header to squash warnings when PETSc is not available, mainly unused parameters. --- .../constraints/laplace-dae/laplace_dae.cxx | 28 +++++++++++-------- examples/dalf3/dalf3.cxx | 27 ++++++++++++------ examples/reconnect-2field/2field.cxx | 11 ++++++-- include/bout/invert/laplacexy.hxx | 9 +++--- 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/examples/constraints/laplace-dae/laplace_dae.cxx b/examples/constraints/laplace-dae/laplace_dae.cxx index 5f89a6d1d8..fbadf53c03 100644 --- a/examples/constraints/laplace-dae/laplace_dae.cxx +++ b/examples/constraints/laplace-dae/laplace_dae.cxx @@ -19,12 +19,14 @@ bool constraint; int flags; +Laplacian *phiSolver; ///< Inverts a Laplacian to get phi from U + // Preconditioner int precon_phi(BoutReal t, BoutReal cj, BoutReal delta); int jacobian(BoutReal t); // Jacobian-vector multiply int jacobian_constrain(BoutReal t); // Jacobian-vector multiply -int physics_init(bool restarting) { +int physics_init(bool UNUSED(restarting)) { // Give the solver two RHS functions // Get options @@ -32,14 +34,18 @@ int physics_init(bool restarting) { options = options->getSection("dae"); OPTION(options, constraint, true); OPTION(options, flags, 0); - + + // Create a solver for the Laplacian + phiSolver = Laplacian::create(); + phiSolver->setFlags(flags); + // Just solving one variable, U SOLVE_FOR2(U, Apar); if(constraint) { - phi = invert_laplace(U, flags); + phi = phiSolver->solve(U); // Add phi equation as a constraint - if(!bout_constrain(phi, ddt(phi), "phi")) + if (!bout_constrain(phi, ddt(phi), "phi")) throw BoutException("Solver does not support constraints"); // Set preconditioner @@ -64,7 +70,7 @@ int physics_init(bool restarting) { return 0; } -int physics_run(BoutReal time) { +int physics_run(BoutReal UNUSED(time)) { if(constraint) { mesh->communicate(Apar, phi); @@ -86,7 +92,7 @@ int physics_run(BoutReal time) { // Solving for phi here (dense Jacobian) output << "U " << max(U) << endl; - phi = invert_laplace(U, flags); + phi = phiSolver->solve(U); phi.applyBoundary(); } @@ -119,10 +125,10 @@ int physics_run(BoutReal time) { * o Return values should be in time derivatives *******************************************************************************/ -int precon_phi(BoutReal t, BoutReal cj, BoutReal delta) { +int precon_phi(BoutReal UNUSED(t), BoutReal UNUSED(cj), BoutReal UNUSED(delta)) { // Not preconditioning U or Apar equation - ddt(phi) = invert_laplace(ddt(phi) - ddt(U), flags); + ddt(phi) = phiSolver->solve(ddt(phi) - ddt(U)); return 0; } @@ -140,8 +146,8 @@ int precon_phi(BoutReal t, BoutReal cj, BoutReal delta) { /// Jacobian when solving phi in RHS -int jacobian(BoutReal t) { - Field3D Jphi = invert_laplace(ddt(U), flags); // Inversion makes this dense +int jacobian(BoutReal UNUSED(t)) { + Field3D Jphi = phiSolver->solve(ddt(U)); // Inversion makes this dense mesh->communicate(Jphi, ddt(Apar)); Field3D Jjpar = Delp2(ddt(Apar)); mesh->communicate(Jjpar); @@ -154,7 +160,7 @@ int jacobian(BoutReal t) { /// Jacobian when solving phi as a constraint. /// No inversion, only sparse Delp2 and Grad_par operators -int jacobian_constrain(BoutReal t) { +int jacobian_constrain(BoutReal UNUSED(t)) { mesh->communicate(ddt(Apar), ddt(phi)); Field3D Jjpar = Delp2(ddt(Apar)); diff --git a/examples/dalf3/dalf3.cxx b/examples/dalf3/dalf3.cxx index 5310bbe6f7..a18e7c65d7 100644 --- a/examples/dalf3/dalf3.cxx +++ b/examples/dalf3/dalf3.cxx @@ -73,12 +73,14 @@ class DALF3 : public PhysicsModel { bool smooth_separatrix; FieldGroup comms; - + + Laplacian *phiSolver; // Laplacian solver in X-Z + Laplacian *aparSolver; // Laplacian solver in X-Z for Apar LaplaceXY *laplacexy; // Laplacian solver in X-Y (n=0) Field2D phi2D; // Axisymmetric potential, used when split_n0=true protected: - int init(bool restarting) { + int init(bool UNUSED(restarting)) { ///////////////////////////////////////////////////// // Load data from the grid @@ -294,6 +296,10 @@ class DALF3 : public PhysicsModel { SAVE_ONCE(eta); } + // Create a solver for the Laplacian + phiSolver = Laplacian::create(); + phiSolver->setFlags(phi_flags); + // LaplaceXY for n=0 solve if (split_n0) { // Create an XY solver for n=0 component @@ -301,6 +307,13 @@ class DALF3 : public PhysicsModel { phi2D = 0.0; // Starting guess } + // Solver for Apar + // ajpar = beta_hat*apar + mu_hat*jpar + aparSolver = Laplacian::create(); + aparSolver->setFlags(apar_flags); + aparSolver->setCoefA(beta_hat); + aparSolver->setCoefD(-mu_hat); + return 0; } @@ -346,7 +359,7 @@ class DALF3 : public PhysicsModel { return result; } - int rhs(BoutReal time) { + int rhs(BoutReal UNUSED(time)) { // Invert vorticity to get electrostatic potential if (split_n0) { @@ -354,10 +367,10 @@ class DALF3 : public PhysicsModel { phi2D = laplacexy->solve(Vort2D, phi2D); // Solve non-axisymmetric part using X-Z solver - phi = invert_laplace((Vort-Vort2D)*B0, phi_flags); + phi = phiSolver->solve((Vort-Vort2D)*B0); phi += phi2D; // Add axisymmetric part } else { - phi = invert_laplace(Vort*B0, phi_flags); + phi = phiSolver->solve(Vort*B0); } phi.applyBoundary(); @@ -386,9 +399,7 @@ class DALF3 : public PhysicsModel { } else { // All terms - solve Helmholtz equation // ajpar = beta_hat*apar + mu_hat*jpar - Field2D a = beta_hat; - Field2D d = -mu_hat; - apar = invert_laplace(Ajpar, apar_flags, &a, NULL, &d); + apar = aparSolver->solve(Ajpar); apar.applyBoundary(); mesh->communicate(comms); diff --git a/examples/reconnect-2field/2field.cxx b/examples/reconnect-2field/2field.cxx index 1628029d2d..29e1ca6fa9 100644 --- a/examples/reconnect-2field/2field.cxx +++ b/examples/reconnect-2field/2field.cxx @@ -56,6 +56,9 @@ class TwoField : public PhysicsModel { // Coordinate system metric Coordinates *coord; + // Inverts a Laplacian to get potential + Laplacian *phiSolver; + protected: int init(bool UNUSED(restarting)) override { @@ -207,6 +210,10 @@ class TwoField : public PhysicsModel { U.setBoundary("U"); Apar.setBoundary("Apar"); + // Create a solver for the Laplacian + phiSolver = Laplacian::create(); + phiSolver->setFlags(phi_flags); + return 0; } @@ -251,7 +258,7 @@ class TwoField : public PhysicsModel { // Solve EM fields // U = (1/B) * Delp2(phi) - phi = invert_laplace(coord->Bxy * U, phi_flags); + phi = phiSolver->solve(coord->Bxy * U); phi.applyBoundary(); // For target plates only mesh->communicate(U, phi, Apar); @@ -345,7 +352,7 @@ class TwoField : public PhysicsModel { ddt(U) = inv->solve(U1); ddt(U).applyBoundary(); - Field3D phip = invert_laplace(coord->Bxy * ddt(U), phi_flags); + Field3D phip = phiSolver->solve(coord->Bxy * ddt(U)); mesh->communicate(phip); ddt(Apar) = ddt(Apar) - (gamma / beta_hat) * Grad_par_CtoL(phip); diff --git a/include/bout/invert/laplacexy.hxx b/include/bout/invert/laplacexy.hxx index 4a6b487d68..cade346e5e 100644 --- a/include/bout/invert/laplacexy.hxx +++ b/include/bout/invert/laplacexy.hxx @@ -48,12 +48,13 @@ * LaplaceXY is used. */ class LaplaceXY { - public: - LaplaceXY(Mesh *m, Options *opt = nullptr, const CELL_LOC = CELL_CENTRE) { +public: + LaplaceXY(Mesh* UNUSED(m), Options* UNUSED(opt) = nullptr, + const CELL_LOC UNUSED(loc) = CELL_CENTRE) { throw BoutException("LaplaceXY requires PETSc. No LaplaceXY available"); } - void setCoefs(const Field2D &A, const Field2D &B) {} - const Field2D solve(const Field2D &rhs, const Field2D &x0) {} + void setCoefs(const Field2D& UNUSED(A), const Field2D& UNUSED(B)) {} + const Field2D solve(const Field2D& UNUSED(rhs), const Field2D& UNUSED(x0)) {return {};} }; #else // BOUT_HAS_PETSC From f2f92ae61dd7dab6b639acde390e068b80ee2583 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 20 Dec 2018 23:42:46 +0000 Subject: [PATCH 0512/1783] Change Options::AttributeType Now inherits from `variant`, so that the cast operator and `as()` member can be implemented, along with an assigment operator from `const char*`. Added some unit tests of `Options::attributes` --- include/options.hxx | 44 ++++++++++++++++++++++++++++++- tests/unit/sys/test_options.cxx | 46 +++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/include/options.hxx b/include/options.hxx index d21dfd834c..4ccf6cffee 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -186,8 +186,50 @@ public: using ValueType = bout::utils::variant, Matrix, Tensor>; + /// The type used to store attributes - using AttributeType = bout::utils::variant; + /// Extends the variant class so that cast operator can be implemented + /// and assignment operator overloaded + /// + /// Note: Due to default initialisation rules, if an attribute + /// is used without being set, it will be false, 0, 0.0 and + /// throw std::bad_cast if cast to std::string + /// + class AttributeType : public bout::utils::variant { + public: + using Base = bout::utils::variant; + + /// Constructor + AttributeType() {} + /// Copy constructor + AttributeType(const AttributeType& other) : Base(other) {} + /// Move constructor + AttributeType(AttributeType&& other) : Base(other) {} + + /// Destructor + ~AttributeType() {} + + /// Assignment operator, including move assignment + using Base::operator=; + + /// Assignment from const char* + AttributeType& operator=(const char* str) { + operator=(std::string(str)); + return *this; + } + + /// Cast operator, which allows this class to be + /// assigned to type T + /// This will throw std::bad_cast if it can't be done + template operator T() const { return as(); } + + /// Get the value as a specified type + /// This will throw std::bad_cast if it can't be done + template + T as() const { + return bout::utils::variantStaticCastOrThrow(*this); + } + }; /// The value stored ValueType value; diff --git a/tests/unit/sys/test_options.cxx b/tests/unit/sys/test_options.cxx index 1c21b2a8ff..36644210b0 100644 --- a/tests/unit/sys/test_options.cxx +++ b/tests/unit/sys/test_options.cxx @@ -584,3 +584,49 @@ TEST_F(OptionsTest, AssignSubSectionParent) { EXPECT_EQ(&option2["key2"].parent(), &option2); EXPECT_EQ(&option2["key2"]["key1"].parent(), &option2["key2"]); } + +TEST_F(OptionsTest, AttributeMissingBool) { + Options option; + + bool a = option.attributes["test"]; + EXPECT_EQ(a, false); +} + +TEST_F(OptionsTest, AttributeMissingInt) { + Options option; + + int a = option.attributes["test"]; + EXPECT_EQ(a, 0); +} + +TEST_F(OptionsTest, AttributeMissingBoutReal) { + Options option; + + BoutReal a = option.attributes["test"]; + EXPECT_DOUBLE_EQ(a, 0.0); +} + +TEST_F(OptionsTest, AttributeMissingString) { + Options option; + + EXPECT_THROW(option.attributes["test"].as(), std::bad_cast); +} + +TEST_F(OptionsTest, AttributeStoreBool) { + Options option; + option.attributes["test"] = true; + + EXPECT_TRUE(option.attributes["test"].as()); + + option.attributes["test"] = false; + EXPECT_FALSE(option.attributes["test"].as()); +} + + +TEST_F(OptionsTest, AttributeConstChars) { + Options option; + option.attributes["test"] = "hello"; + + std::string test = option.attributes["test"]; + EXPECT_EQ(test, "hello"); +} From 78701b4aa85e143188c5d79a9cd49050d91ba95f Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 21 Dec 2018 16:39:50 +0000 Subject: [PATCH 0513/1783] Disable force check if time_dimension attribute set Allows Options values to be changed without using `force` if the variable is marked as time evolving. --- include/options.hxx | 11 ++++++- .../test-options-netcdf.cxx | 8 ++--- tests/unit/sys/test_options.cxx | 30 ++++++++++++++++++- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index 4ccf6cffee..5c12acf06e 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -233,7 +233,13 @@ public: /// The value stored ValueType value; + /// A collection of attributes belonging to the value + /// Special attributes: + /// - time_dimension [string] If this is set then changes to the value + /// do not need to be forced. The string will be used + /// when writing the output as the name of the time + /// dimension (unlimited first dimension in NetCDF files). std::map attributes; /// Get a sub-section or value @@ -562,7 +568,10 @@ public: template void _set(T val, std::string source, bool force) { - if (isSet()) { + // If already set, and not time evolving then check for changing values + // If a variable has a "time_dimension" attribute then it is assumed + // that updates to the value is ok and don't need to be forced. + if (isSet() && (attributes.find("time_dimension") == attributes.end())) { // Check if current value the same as new value if (!bout::utils::variantEqualTo(value, val)) { if (force or !bout::utils::variantEqualTo(attributes["source"], source)) { diff --git a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx index e7d582b3a3..183dfb9ecf 100644 --- a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx +++ b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx @@ -60,16 +60,16 @@ int main(int argc, char** argv) { Options data; data["scalar"] = 1.0; - data["scalar"].attributes["time_dimension"] = std::string("t"); + data["scalar"].attributes["time_dimension"] = "t"; data["field"] = Field3D(2.0); - data["field"].attributes["time_dimension"] = std::string("t"); + data["field"].attributes["time_dimension"] = "t"; OptionsNetCDF("time.nc").write(data); // Update time-dependent values - data["scalar"].force(2.0); - data["field"].force(Field3D(3.0)); + data["scalar"] = 2.0; + data["field"] = Field3D(3.0); // Append data to file OptionsNetCDF("time.nc", OptionsNetCDF::FileMode::append).write(data); diff --git a/tests/unit/sys/test_options.cxx b/tests/unit/sys/test_options.cxx index 36644210b0..8df7d4a522 100644 --- a/tests/unit/sys/test_options.cxx +++ b/tests/unit/sys/test_options.cxx @@ -622,11 +622,39 @@ TEST_F(OptionsTest, AttributeStoreBool) { EXPECT_FALSE(option.attributes["test"].as()); } +TEST_F(OptionsTest, AttributeStoreInt) { + Options option; + option.attributes["test"] = 42; + + int value = option.attributes["test"]; + EXPECT_EQ(value, 42); +} + +TEST_F(OptionsTest, AttributeStoreBoutReal) { + Options option; + option.attributes["test"] = 3.1415; + + BoutReal value = option.attributes["test"]; + EXPECT_DOUBLE_EQ(value, 3.1415); +} -TEST_F(OptionsTest, AttributeConstChars) { +TEST_F(OptionsTest, AttributeStoreConstChars) { Options option; option.attributes["test"] = "hello"; std::string test = option.attributes["test"]; EXPECT_EQ(test, "hello"); } + +TEST_F(OptionsTest, AttributeTimeDimension) { + Options option; + + option = 3; + EXPECT_EQ(option.as(), 3); + + option.attributes["time_dimension"] = "t"; + + option = 4; + + EXPECT_EQ(option.as(), 4); +} From 8d33ffd26636267a54cfa9876b8006d3b7044f80 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 22 Dec 2018 23:52:27 +0000 Subject: [PATCH 0514/1783] Almost all invert_laplace calls removed Removed all calls from code which is compiled by makefiles. Some variations / work in progress code which is not compiled still contains calls. Possibly that code should be deleted anyway. --- examples/conducting-wall-mode/cwm.cxx | 335 ++++++------ examples/em-drift/2fluid.cxx | 336 ++++++------ examples/jorek-compare/jorek_compare.cxx | 620 +++++++++++------------ examples/lapd-drift/lapd_drift.cxx | 56 +- examples/tokamak-2fluid/2fluid.cxx | 102 ++-- 5 files changed, 711 insertions(+), 738 deletions(-) diff --git a/examples/conducting-wall-mode/cwm.cxx b/examples/conducting-wall-mode/cwm.cxx index f89cba9a68..f99a5f884b 100644 --- a/examples/conducting-wall-mode/cwm.cxx +++ b/examples/conducting-wall-mode/cwm.cxx @@ -6,8 +6,8 @@ *******************************************************************************/ #include -#include #include +#include #include #include @@ -30,14 +30,14 @@ class CWM : public PhysicsModel { Field3D dphi_bc_ydown, dphi_bc_yup; // Metric coefficients - Field2D Rxy, Bpxy, Btxy, hthe,Zxy; + Field2D Rxy, Bpxy, Btxy, hthe, Zxy; // parameters BoutReal Te_x, Ti_x, Ni_x, Vi_x, bmag, rho_s, fmei, AA, ZZ; BoutReal lambda_ei, lambda_ii; BoutReal nu_hat, wci, nueix; - bool bout_exb; // Use BOUT-06 expression for ExB velocity + bool bout_exb; // Use BOUT-06 expression for ExB velocity BoutReal zeff, nu_perp; BoutReal ShearFactor; @@ -57,40 +57,43 @@ class CWM : public PhysicsModel { FieldGroup comms; // Coordinate system - Coordinates *coord; + Coordinates* coord; + + // Inverts a Laplacian to get potential + Laplacian* phiSolver; + + int init(bool UNUSED(restarting)) override { + Field2D I; // Shear factor - int init(bool restarting) override { - Field2D I; // Shear factor - output.write("Solving 6-variable 2-fluid equations\n"); - + /************* LOAD DATA FROM GRID FILE ****************/ - + // Load 2D profiles (set to zero if not found) - mesh->get(Ni0, "Ni0"); - mesh->get(Ti0, "Ti0"); - mesh->get(Te0, "Te0"); - mesh->get(Vi0, "Vi0"); - mesh->get(Ve0, "Ve0"); - mesh->get(phi0, "phi0"); - mesh->get(rho0, "rho0"); + mesh->get(Ni0, "Ni0"); + mesh->get(Ti0, "Ti0"); + mesh->get(Te0, "Te0"); + mesh->get(Vi0, "Vi0"); + mesh->get(Ve0, "Ve0"); + mesh->get(phi0, "phi0"); + mesh->get(rho0, "rho0"); mesh->get(Ajpar0, "Ajpar0"); coord = mesh->getCoordinates(); - + // Load magnetic curvature term - b0xcv.covariant = false; // Read contravariant components + b0xcv.covariant = false; // Read contravariant components mesh->get(b0xcv, "bxcv"); // b0xkappa terms - + // Load metrics - mesh->get(Rxy, "Rxy"); - mesh->get(Zxy, "Zxy"); + mesh->get(Rxy, "Rxy"); + mesh->get(Zxy, "Zxy"); mesh->get(Bpxy, "Bpxy"); mesh->get(Btxy, "Btxy"); mesh->get(hthe, "hthe"); - mesh->get(coord->dx, "dpsi"); - mesh->get(I, "sinty"); - + mesh->get(coord->dx, "dpsi"); + mesh->get(I, "sinty"); + // Load normalisation values mesh->get(Te_x, "Te_x"); mesh->get(Ti_x, "Ti_x"); @@ -100,236 +103,232 @@ class CWM : public PhysicsModel { // Get separatrix location mesh->get(my_ixseps, "ixseps1"); - Ni_x *= 1.0e14; bmag *= 1.0e4; - + /*************** READ OPTIONS *************************/ // Read some parameters - - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("2fluid"); + + auto globalOptions = Options::root(); + auto options = globalOptions["2fluid"]; OPTION(options, AA, 4.0); // <=> options.get("AA", AA, 1.0); OPTION(options, ZZ, 1.0); - OPTION(options, zeff, 1.0); - OPTION(options, nu_perp, 0.0); - OPTION(options, ShearFactor, 1.0); - OPTION(options, bout_exb, false); - - OPTION(options, phi_flags, 0); - + OPTION(options, zeff, 1.0); + OPTION(options, nu_perp, 0.0); + OPTION(options, ShearFactor, 1.0); + OPTION(options, bout_exb, false); + + OPTION(options, phi_flags, 0); + // Toroidal filtering - OPTION(options, filter_z, false); // Filter a single n - OPTION(options, filter_z_mode, 1); - + OPTION(options, filter_z, false); // Filter a single n + OPTION(options, filter_z_mode, 1); + /************* SHIFTED RADIAL COORDINATES ************/ // Check type of parallel transform - std::string ptstr; - Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); + std::string ptstr = + Options::root()["mesh"]["paralleltransform"].withDefault("identity"); if (lowercase(ptstr) == "shifted") { - ShearFactor = 0.0; // I disappears from metric - b0xcv.z += I*b0xcv.x; + ShearFactor = 0.0; // I disappears from metric + b0xcv.z += I * b0xcv.x; } - + /************** CALCULATE PARAMETERS *****************/ - - rho_s = 1.02*sqrt(AA*Te_x)/ZZ/bmag; - fmei = 1./1836.2/AA; - - lambda_ei = 24.-log(sqrt(Ni_x)/Te_x); - lambda_ii = 23.-log(ZZ*ZZ*ZZ*sqrt(2.*Ni_x)/pow(Ti_x, 1.5)); - wci = 9.58e3*ZZ*bmag/AA; - nueix = 2.91e-6*Ni_x*lambda_ei/pow(Te_x, 1.5); - nu_hat = zeff*nueix/wci; - + + rho_s = 1.02 * sqrt(AA * Te_x) / ZZ / bmag; + fmei = 1. / 1836.2 / AA; + + lambda_ei = 24. - log(sqrt(Ni_x) / Te_x); + lambda_ii = 23. - log(ZZ * ZZ * ZZ * sqrt(2. * Ni_x) / pow(Ti_x, 1.5)); + wci = 9.58e3 * ZZ * bmag / AA; + nueix = 2.91e-6 * Ni_x * lambda_ei / pow(Te_x, 1.5); + nu_hat = zeff * nueix / wci; + Vi_x = wci * rho_s; - + output.write("Collisions: nueix = %e, nu_hat = %e\n", nueix, nu_hat); /************** PRINT Z INFORMATION ******************/ - + BoutReal hthe0; - if(mesh->get(hthe0, "hthe0") == 0) { - output.write(" ****NOTE: input from BOUT, Z length needs to be divided by %e\n", hthe0/rho_s); + if (mesh->get(hthe0, "hthe0") == 0) { + output.write(" ****NOTE: input from BOUT, Z length needs to be divided by %e\n", + hthe0 / rho_s); } - - + /************** NORMALISE QUANTITIES *****************/ - + output.write("\tNormalising to rho_s = %e\n", rho_s); - + // Normalise profiles - Ni0 /= Ni_x/1.0e14; - Ti0 /= Te_x; - Te0 /= Te_x; + Ni0 /= Ni_x / 1.0e14; + Ti0 /= Te_x; + Te0 /= Te_x; phi0 /= Te_x; - Vi0 /= Vi_x; - + Vi0 /= Vi_x; + // Normalise curvature term - b0xcv.x /= (bmag/1e4); - b0xcv.y *= rho_s*rho_s; - b0xcv.z *= rho_s*rho_s; - - // Normalise geometry + b0xcv.x /= (bmag / 1e4); + b0xcv.y *= rho_s * rho_s; + b0xcv.z *= rho_s * rho_s; + + // Normalise geometry Rxy /= rho_s; hthe /= rho_s; - I *= rho_s*rho_s*(bmag/1e4)*ShearFactor; - coord->dx /= rho_s*rho_s*(bmag/1e4); - + I *= rho_s * rho_s * (bmag / 1e4) * ShearFactor; + coord->dx /= rho_s * rho_s * (bmag / 1e4); + // Normalise magnetic field - Bpxy /= (bmag/1.e4); - Btxy /= (bmag/1.e4); - coord->Bxy /= (bmag/1.e4); - + Bpxy /= (bmag / 1.e4); + Btxy /= (bmag / 1.e4); + coord->Bxy /= (bmag / 1.e4); + // Set nu - nu = nu_hat * Ni0 / pow(Te0,1.5); + nu = nu_hat * Ni0 / pow(Te0, 1.5); /**************** CALCULATE METRICS ******************/ - - coord->g11 = SQ(Rxy*Bpxy); + + coord->g11 = SQ(Rxy * Bpxy); coord->g22 = 1.0 / SQ(hthe); - coord->g33 = SQ(I)*coord->g11 + SQ(coord->Bxy)/coord->g11; + coord->g33 = SQ(I) * coord->g11 + SQ(coord->Bxy) / coord->g11; coord->g12 = 0.0; - coord->g13 = -I*coord->g11; - coord->g23 = -Btxy/(hthe*Bpxy*Rxy); - + coord->g13 = -I * coord->g11; + coord->g23 = -Btxy / (hthe * Bpxy * Rxy); + coord->J = hthe / Bpxy; - - coord->g_11 = 1.0/coord->g11 + SQ(I*Rxy); - coord->g_22 = SQ(coord->Bxy*hthe/Bpxy); - coord->g_33 = Rxy*Rxy; - coord->g_12 = Btxy*hthe*I*Rxy/Bpxy; - coord->g_13 = I*Rxy*Rxy; - coord->g_23 = Btxy*hthe*Rxy/Bpxy; - + + coord->g_11 = 1.0 / coord->g11 + SQ(I * Rxy); + coord->g_22 = SQ(coord->Bxy * hthe / Bpxy); + coord->g_33 = Rxy * Rxy; + coord->g_12 = Btxy * hthe * I * Rxy / Bpxy; + coord->g_13 = I * Rxy * Rxy; + coord->g_23 = Btxy * hthe * Rxy / Bpxy; + coord->geometry(); - + /**************** SET EVOLVING VARIABLES *************/ - + // Tell BOUT++ which variables to evolve // add evolving variables to the communication object SOLVE_FOR(rho); comms.add(rho); - + SOLVE_FOR(te); comms.add(te); - + /************** SETUP COMMUNICATIONS **************/ - + // add extra variables to communication comms.add(phi); - + /*************** DUMP VARIABLES TO OUTPUT**********/ - dump.add(phi, "phi", 1); + dump.add(phi, "phi", 1); + + SAVE_ONCE(Ni0, Te0, phi0, rho0); + SAVE_ONCE(Rxy, Bpxy, Btxy, Zxy, hthe); + + SAVE_ONCE(Te_x, Ti_x, Ni_x); + SAVE_ONCE(AA, ZZ, zeff, rho_s, wci, bmag); + dump.addOnce(mesh->LocalNx, "ngx"); + dump.addOnce(mesh->LocalNy, "ngy"); + dump.addOnce(mesh->LocalNz, "ngz"); + SAVE_ONCE(nu_hat, hthe0); + + // Create a solver for the Laplacian + phiSolver = Laplacian::create(); + phiSolver->setFlags(phi_flags); - SAVE_ONCE4(Ni0,Te0,phi0,rho0); - SAVE_ONCE5(Rxy,Bpxy,Btxy,Zxy,hthe); - - SAVE_ONCE3(Te_x,Ti_x,Ni_x); - SAVE_ONCE6(AA,ZZ,zeff,rho_s,wci,bmag); - dump.add(mesh->LocalNx, "ngx", 0); - dump.add(mesh->LocalNy, "ngy", 0); - dump.add(mesh->LocalNz, "ngz", 0); - SAVE_ONCE2(nu_hat,hthe0); - - return(0); + return 0; } // End of physics_init() ////////////////////////////////////////////////////////////////// - - + /////////////////////////////////////////////////////////////////// // Function called at each time step // Time derivatives calculated here - int rhs(BoutReal t) { - - Coordinates *coord = mesh->getCoordinates(); - + int rhs(BoutReal UNUSED(t)) { // Invert vorticity to get phi - + // Solves \nabla^2_\perp x + (1./c)*\nabla_perp c\cdot\nabla_\perp x + a x = b - // Arguments are: (b, bit-field, a, c) - // Passing NULL -> missing term - phi = invert_laplace(rho/Ni0, phi_flags, NULL, NULL); + phi = phiSolver->solve(rho / Ni0); // Communicate variables mesh->communicate(comms); - + phi_sheath_bndryconds(); - + // Evolve rho and te - ddt(rho) = -Ni0/(fmei*0.51*nu)*Grad2_par2(phi); + ddt(rho) = -Ni0 / (fmei * 0.51 * nu) * Grad2_par2(phi); ddt(te) = -vE_Grad(Te0, phi); // Z filtering if (filter_z) { // Filter out all except filter_z_mode - + ddt(rho) = filter(ddt(rho), filter_z_mode); ddt(te) = filter(ddt(te), filter_z_mode); } - - + return 0; } - //End of physics_run + // End of physics_run ///////////////////////////////////////////////////////////////// - - + /****************BOUNDARY FUNCTIONS*****************************/ // Sheath Boundary Conditions on Phi // Linearized void phi_sheath_bndryconds() { LAMBDA1 = 0.0; LAMBDA2 = 1.0; - //LAMBDA1 = 1.0; - //LAMBDA2 = log(2.0*sqrt(PI*fmei)); - - dphi_bc_ydown = fmei*0.51*nu*(LAMBDA1*phi + LAMBDA2*te); - dphi_bc_yup = -fmei*0.51*nu*(LAMBDA1*phi + LAMBDA2*te); + // LAMBDA1 = 1.0; + // LAMBDA2 = log(2.0*sqrt(PI*fmei)); - bndry_ydown_Grad_par(phi,dphi_bc_ydown); - bndry_yup_Grad_par(phi,dphi_bc_yup); - + dphi_bc_ydown = fmei * 0.51 * nu * (LAMBDA1 * phi + LAMBDA2 * te); + dphi_bc_yup = -fmei * 0.51 * nu * (LAMBDA1 * phi + LAMBDA2 * te); + + bndry_ydown_Grad_par(phi, dphi_bc_ydown); + bndry_yup_Grad_par(phi, dphi_bc_yup); } - - // Boundary gradient to specified Field3D object - void bndry_yup_Grad_par(Field3D &var, const Field3D &value) { - - RangeIterator xrup = mesh->iterateBndryUpperY(); - for(xrup.first(); !xrup.isDone(); xrup.next()) - for(int jy=mesh->yend+1; jyLocalNy; jy++) - for(int jz=0; jzLocalNz; jz++) { + // Boundary gradient to specified Field3D object + void bndry_yup_Grad_par(Field3D& var, const Field3D& value) { - var(xrup.ind,jy,jz) = var(xrup.ind,jy-1,jz) + coord->dy(xrup.ind,jy)*sqrt(coord->g_22(xrup.ind,jy))*value(xrup.ind,jy,jz); + RangeIterator xrup = mesh->iterateBndryUpperY(); - } + for (xrup.first(); !xrup.isDone(); xrup.next()) + for (int jy = mesh->yend + 1; jy < mesh->LocalNy; jy++) + for (int jz = 0; jz < mesh->LocalNz; jz++) { + var(xrup.ind, jy, jz) = var(xrup.ind, jy - 1, jz) + + coord->dy(xrup.ind, jy) + * sqrt(coord->g_22(xrup.ind, jy)) + * value(xrup.ind, jy, jz); + } } - void bndry_ydown_Grad_par(Field3D &var, const Field3D &value) { - + void bndry_ydown_Grad_par(Field3D& var, const Field3D& value) { + RangeIterator xrdn = mesh->iterateBndryLowerY(); - - for(xrdn.first(); !xrdn.isDone(); xrdn.next()) - for(int jy=mesh->ystart-1; jy>=0; jy--) - for(int jz=0; jzLocalNz; jz++) { - - var(xrdn.ind,jy,jz) = var(xrdn.ind,jy+1,jz) - coord->dy(xrdn.ind,jy)*sqrt(coord->g_22(xrdn.ind,jy))*value(xrdn.ind,jy,jz); - + + for (xrdn.first(); !xrdn.isDone(); xrdn.next()) + for (int jy = mesh->ystart - 1; jy >= 0; jy--) + for (int jz = 0; jz < mesh->LocalNz; jz++) { + + var(xrdn.ind, jy, jz) = var(xrdn.ind, jy + 1, jz) + - coord->dy(xrdn.ind, jy) + * sqrt(coord->g_22(xrdn.ind, jy)) + * value(xrdn.ind, jy, jz); } - } - + ///////////////////////////////////////////////////////////////// // ExB terms. These routines allow comparisons with BOUT-06 // if bout_exb=true is set in BOUT.inp ///////////////////////////////////////////////////////////////// - const Field3D vE_Grad(const Field2D &f, const Field3D &p) { + const Field3D vE_Grad(const Field2D& f, const Field3D& p) { Field3D result; if (bout_exb) { // Use a subset of terms for comparison to BOUT-06 @@ -341,24 +340,24 @@ class CWM : public PhysicsModel { return result; } - const Field3D vE_Grad(const Field3D &f, const Field2D &p) { + const Field3D vE_Grad(const Field3D& f, const Field2D& p) { Field3D result; - if(bout_exb) { + if (bout_exb) { // Use a subset of terms for comparison to BOUT-06 result = VDDZ(-DDX(p), f); - }else { + } else { // Use full expression with all terms result = b0xGrad_dot_Grad(p, f) / coord->Bxy; } return result; } - - const Field3D vE_Grad(const Field3D &f, const Field3D &p) { + + const Field3D vE_Grad(const Field3D& f, const Field3D& p) { Field3D result; - if(bout_exb) { + if (bout_exb) { // Use a subset of terms for comparison to BOUT-06 result = VDDX(DDZ(p), f) + VDDZ(-DDX(p), f); - }else { + } else { // Use full expression with all terms result = b0xGrad_dot_Grad(p, f) / coord->Bxy; } diff --git a/examples/em-drift/2fluid.cxx b/examples/em-drift/2fluid.cxx index e298d4373f..c3763ec521 100644 --- a/examples/em-drift/2fluid.cxx +++ b/examples/em-drift/2fluid.cxx @@ -1,6 +1,6 @@ /******************************************************************************* * 2-fluid equations for drift-wave tests - * + * * Settings: * - ZeroElMass * - AparInEpar @@ -8,33 +8,33 @@ #include -#include #include +#include #include class EMdrift : public PhysicsModel { private: // 2D initial profiles Field2D Ni0, Ti0, Te0; - + // 3D evolving fields Field3D rho, Ni, Ajpar; - + // Derived 3D variables Field3D phi, Apar, Ve, jpar; - + // Non-linear coefficients Field3D nu, mu_i; - + // Metric coefficients Field2D Rxy, Bpxy, Btxy, hthe; - + // parameters BoutReal Te_x, Ti_x, Ni_x, Vi_x, bmag, rho_s, fmei, AA, ZZ; BoutReal lambda_ei, lambda_ii; BoutReal nu_hat, mui_hat, wci, nueix, nuiix; BoutReal beta_p; - + // settings bool estatic, ZeroElMass; // Switch for electrostatic operation (true = no Apar) bool AparInEpar; @@ -42,158 +42,166 @@ class EMdrift : public PhysicsModel { bool evolve_ajpar; BoutReal ShearFactor; BoutReal nu_factor; - + int phi_flags, apar_flags; // Inversion flags - + // Communication object FieldGroup comms; + + // Inverts a Laplacian to get potential + Laplacian *phiSolver; - int init(bool restarting) override { - Field2D I; // Shear factor + // Solves the electromagnetic potential + Laplacian *aparSolver; + Field2D acoef; // Coefficient in the Helmholtz equation + int init(bool UNUSED(restarting)) override { + Field2D I; // Shear factor + output.write("Solving 6-variable 2-fluid equations\n"); - + /************* LOAD DATA FROM GRID FILE ****************/ - - Coordinates *coord = mesh->getCoordinates(); - + + Coordinates* coord = mesh->getCoordinates(); + // Load 2D profiles (set to zero if not found) - mesh->get(Ni0, "Ni0"); - mesh->get(Ti0, "Ti0"); - mesh->get(Te0, "Te0"); - + mesh->get(Ni0, "Ni0"); + mesh->get(Ti0, "Ti0"); + mesh->get(Te0, "Te0"); + // Load metrics - mesh->get(Rxy, "Rxy"); + mesh->get(Rxy, "Rxy"); mesh->get(Bpxy, "Bpxy"); mesh->get(Btxy, "Btxy"); mesh->get(hthe, "hthe"); - mesh->get(coord->dx, "dpsi"); - mesh->get(I, "sinty"); - + mesh->get(coord->dx, "dpsi"); + mesh->get(I, "sinty"); + // Load normalisation values mesh->get(Te_x, "Te_x"); mesh->get(Ti_x, "Ti_x"); mesh->get(Ni_x, "Ni_x"); mesh->get(bmag, "bmag"); - + Ni_x *= 1.0e14; bmag *= 1.0e4; - + /*************** READ OPTIONS *************************/ - - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("2fluid"); - + + auto globalOptions = Options::root(); + auto options = globalOptions["2fluid"]; + OPTION(options, AA, 2.0); OPTION(options, ZZ, 1.0); + + OPTION(options, estatic, false); + OPTION(options, ZeroElMass, false); + OPTION(options, AparInEpar, true); - options->get("estatic", estatic, false); - options->get("ZeroElMass", ZeroElMass, false); - options->get("AparInEpar", AparInEpar, true); - - options->get("Zeff", zeff, 1.0); - options->get("nu_perp", nu_perp, 0.0); - options->get("ShearFactor", ShearFactor, 1.0); - options->get("nu_factor", nu_factor, 1.0); + OPTION(options, zeff, 1.0); + OPTION(options, nu_perp, 0.0); + OPTION(options, ShearFactor, 1.0); + OPTION(options, nu_factor, 1.0); - options->get("phi_flags", phi_flags, 0); - options->get("apar_flags", apar_flags, 0); + OPTION(options, phi_flags, 0); + OPTION(options, apar_flags, 0); - (globalOptions->getSection("Ajpar"))->get("evolve", evolve_ajpar, true); + evolve_ajpar = globalOptions["Ajpar"]["evolve"].withDefault(true); - if(ZeroElMass) + if (ZeroElMass) { evolve_ajpar = 0; // Don't need ajpar - calculated from ohm's law - + } + /************* SHIFTED RADIAL COORDINATES ************/ - + // Check type of parallel transform - std::string ptstr; - Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); + std::string ptstr = Options::root()["mesh"]["paralleltransform"].withDefault("identity"); if (lowercase(ptstr) == "shifted") { - ShearFactor = 0.0; // I disappears from metric + ShearFactor = 0.0; // I disappears from metric } - + /************** CALCULATE PARAMETERS *****************/ - - rho_s = 1.02*sqrt(AA*Te_x)/ZZ/bmag; - fmei = 1./1836.2/AA; - - lambda_ei = 24.-log(sqrt(Ni_x)/Te_x); - lambda_ii = 23.-log(ZZ*ZZ*ZZ*sqrt(2.*Ni_x)/pow(Ti_x, 1.5)); - wci = 9.58e3*ZZ*bmag/AA; - nueix = 2.91e-6*Ni_x*lambda_ei/pow(Te_x, 1.5); - nuiix = 4.78e-8*pow(ZZ,4.)*Ni_x*lambda_ii/pow(Ti_x, 1.5)/sqrt(AA); - nu_hat = nu_factor*zeff*nueix/wci; - + + rho_s = 1.02 * sqrt(AA * Te_x) / ZZ / bmag; + fmei = 1. / 1836.2 / AA; + + lambda_ei = 24. - log(sqrt(Ni_x) / Te_x); + lambda_ii = 23. - log(ZZ * ZZ * ZZ * sqrt(2. * Ni_x) / pow(Ti_x, 1.5)); + wci = 9.58e3 * ZZ * bmag / AA; + nueix = 2.91e-6 * Ni_x * lambda_ei / pow(Te_x, 1.5); + nuiix = 4.78e-8 * pow(ZZ, 4.) * Ni_x * lambda_ii / pow(Ti_x, 1.5) / sqrt(AA); + nu_hat = nu_factor * zeff * nueix / wci; + if (nu_perp < 1.e-10) { - mui_hat = (3./10.)*nuiix/wci; + mui_hat = (3. / 10.) * nuiix / wci; } else - mui_hat = nu_perp; - + mui_hat = nu_perp; + if (estatic) { - beta_p = 1.e-29; + beta_p = 1.e-29; } else { - beta_p = 4.03e-11*Ni_x*Te_x/bmag/bmag; + beta_p = 4.03e-11 * Ni_x * Te_x / bmag / bmag; } - + Vi_x = wci * rho_s; - - output.write("Normalisation: rho_s = %e wci = %e beta_p = %e\n", rho_s, wci, beta_p); - + + output.write("Normalisation: rho_s = %e wci = %e beta_p = %e\n", rho_s, wci, + beta_p); + /************** PRINT Z INFORMATION ******************/ - + BoutReal hthe0; if (mesh->get(hthe0, "hthe0") == 0) { - output.write(" ****NOTE: input from BOUT, Z length needs to be divided by %e\n", hthe0/rho_s); + output.write(" ****NOTE: input from BOUT, Z length needs to be divided by %e\n", + hthe0 / rho_s); } /************** NORMALISE QUANTITIES *****************/ - + output.write("\tNormalising to rho_s = %e\n", rho_s); - + // Normalise profiles - Ni0 /= Ni_x/1.0e14; + Ni0 /= Ni_x / 1.0e14; Ti0 /= Te_x; Te0 /= Te_x; - - // Normalise geometry + + // Normalise geometry Rxy /= rho_s; hthe /= rho_s; - I *= rho_s*rho_s*(bmag/1e4)*ShearFactor; - coord->dx /= rho_s*rho_s*(bmag/1e4); - + I *= rho_s * rho_s * (bmag / 1e4) * ShearFactor; + coord->dx /= rho_s * rho_s * (bmag / 1e4); + // Normalise magnetic field - Bpxy /= (bmag/1.e4); - Btxy /= (bmag/1.e4); - coord->Bxy /= (bmag/1.e4); - + Bpxy /= (bmag / 1.e4); + Btxy /= (bmag / 1.e4); + coord->Bxy /= (bmag / 1.e4); + /**************** CALCULATE METRICS ******************/ - - coord->g11 = SQ(Rxy*Bpxy); + + coord->g11 = SQ(Rxy * Bpxy); coord->g22 = 1.0 / SQ(hthe); - coord->g33 = SQ(I)*coord->g11 + SQ(coord->Bxy)/coord->g11; + coord->g33 = SQ(I) * coord->g11 + SQ(coord->Bxy) / coord->g11; coord->g12 = 0.0; - coord->g13 = -I*coord->g11; - coord->g23 = -Btxy/(hthe*Bpxy*Rxy); - + coord->g13 = -I * coord->g11; + coord->g23 = -Btxy / (hthe * Bpxy * Rxy); + coord->J = hthe / Bpxy; - - coord->g_11 = 1.0/coord->g11 + SQ(I*Rxy); - coord->g_22 = SQ(coord->Bxy*hthe/Bpxy); - coord->g_33 = Rxy*Rxy; - coord->g_12 = Btxy*hthe*I*Rxy/Bpxy; - coord->g_13 = I*Rxy*Rxy; - coord->g_23 = Btxy*hthe*Rxy/Bpxy; - - + + coord->g_11 = 1.0 / coord->g11 + SQ(I * Rxy); + coord->g_22 = SQ(coord->Bxy * hthe / Bpxy); + coord->g_33 = Rxy * Rxy; + coord->g_12 = Btxy * hthe * I * Rxy / Bpxy; + coord->g_13 = I * Rxy * Rxy; + coord->g_23 = Btxy * hthe * Rxy / Bpxy; + /**************** SET EVOLVING VARIABLES *************/ - + // Tell BOUT++ which variables to evolve // add evolving variables to the communication object SOLVE_FOR(rho); comms.add(rho); - + SOLVE_FOR(Ni); comms.add(Ni); @@ -208,132 +216,104 @@ class EMdrift : public PhysicsModel { dump.add(Ajpar, "Ajpar", 1); // output calculated Ajpar } } - + jpar.setBoundary("jpar"); - + /************** SETUP COMMUNICATIONS **************/ - + // add extra variables to communication - comms.add(phi); - comms.add(Apar); + comms.add(phi, Apar); // Add any other variables to be dumped to file - dump.add(phi, "phi", 1); - dump.add(Apar, "Apar", 1); - dump.add(jpar, "jpar", 1); - - dump.add(Ni0, "Ni0", 0); - dump.add(Te0, "Te0", 0); - dump.add(Ti0, "Ti0", 0); + SAVE_REPEAT(phi, Apar, jpar); - dump.add(Te_x, "Te_x", 0); - dump.add(Ti_x, "Ti_x", 0); - dump.add(Ni_x, "Ni_x", 0); - dump.add(rho_s, "rho_s", 0); - dump.add(wci, "wci", 0); + SAVE_ONCE(Ni0, Te0, Ti0); + SAVE_ONCE(Te_x, Ti_x, Ni_x, rho_s, wci, zeff, AA); - dump.add(zeff, "Zeff", 0); - dump.add(AA, "AA", 0); + // Create a solver for the Laplacian + phiSolver = Laplacian::create(); + phiSolver->setFlags(phi_flags); + + if (! (estatic || ZeroElMass)) { + // Create a solver for the electromagnetic potential + aparSolver = Laplacian::create(); + aparSolver->setFlags(apar_flags); + acoef = (-0.5 * beta_p / fmei) * Ni0; + aparSolver->setCoefA(acoef); + } - return(0); + return 0; } // just define a macro for V_E dot Grad -#define vE_Grad(f, p) ( b0xGrad_dot_Grad(p, f) / coord->Bxy ) - - int rhs(BoutReal t) override { - - Coordinates *coord = mesh->getCoordinates(); - +#define vE_Grad(f, p) (b0xGrad_dot_Grad(p, f) / coord->Bxy) + + int rhs(BoutReal UNUSED(t)) override { + + Coordinates* coord = mesh->getCoordinates(); + // Solve EM fields - - solve_phi_tridag(rho, phi, 0); - + phi = phiSolver->solve(rho / Ni0); + if (estatic || ZeroElMass) { // Electrostatic operation - + Apar = 0.0; } else { - solve_apar_tridag(Ajpar, Apar, 0); // Linear Apar solver + Apar = aparSolver->solve(-acoef * Ajpar); } // Communicate variables mesh->communicate(comms); // Update non-linear coefficients on the mesh - nu = nu_hat * Ni0 / pow(Te0,1.5); - mu_i = mui_hat * Ni0 / sqrt(Ti0); - + nu = nu_hat * Ni0 / pow(Te0, 1.5); + mu_i = mui_hat * Ni0 / sqrt(Ti0); + if (ZeroElMass) { // Set jpar,Ve,Ajpar neglecting the electron inertia term - - jpar = ((Te0*Grad_par(Ni)) - (Ni0*Grad_par(phi)))/(fmei*0.51*nu); - + + jpar = ((Te0 * Grad_par(Ni)) - (Ni0 * Grad_par(phi))) / (fmei * 0.51 * nu); + // Set boundary conditions on jpar jpar.applyBoundary(); - + // Need to communicate jpar mesh->communicate(jpar); - - Ve = -jpar/Ni0; + + Ve = -jpar / Ni0; Ajpar = Ve; } else { // Evolving electron parallel velocity - + if (AparInEpar) { // Include Apar term in Eparallel Ve = Ajpar + Apar; } else { Ve = Ajpar; } - jpar = -Ni0*Ve; + jpar = -Ni0 * Ve; } - + // DENSITY EQUATION - + ddt(Ni) = -vE_Grad(Ni0, phi); - + // VORTICITY - - ddt(rho) = SQ(coord->Bxy)*Div_par(jpar); - + + ddt(rho) = SQ(coord->Bxy) * Div_par(jpar); + // AJPAR - + ddt(Ajpar) = 0.0; if (evolve_ajpar) { - ddt(Ajpar) += (1./fmei)*Grad_par(phi); - ddt(Ajpar) -= (1./fmei)*(Te0/Ni0)*Grad_par(Ni); - ddt(Ajpar) += 0.51*nu*jpar/Ni0; + ddt(Ajpar) += (1. / fmei) * Grad_par(phi); + ddt(Ajpar) -= (1. / fmei) * (Te0 / Ni0) * Grad_par(Ni); + ddt(Ajpar) += 0.51 * nu * jpar / Ni0; } - - return(0); - } - // Performs inversion of rho (r) to get phi (p) - int solve_phi_tridag(Field3D &r, Field3D &p, int flags) { - if(invert_laplace(r/Ni0, p, flags, NULL)) { - return 1; - } - return(0); - } - - int solve_apar_tridag(Field3D &aj, Field3D &ap, int flags) { - static Field2D a; - static int set = 0; - - if (set == 0) { - // calculate a - a = (-0.5*beta_p/fmei)*Ni0; - set = 1; - } - - if (invert_laplace(-a*aj, ap, flags, &a)) { - return 1; - } - - return(0); + return 0; } }; BOUTMAIN(EMdrift); - diff --git a/examples/jorek-compare/jorek_compare.cxx b/examples/jorek-compare/jorek_compare.cxx index 6f0be93b88..6c1ee0bc34 100644 --- a/examples/jorek-compare/jorek_compare.cxx +++ b/examples/jorek-compare/jorek_compare.cxx @@ -1,12 +1,12 @@ /************************************************************************** * Similar set of equations to JOREK - * + * **************************************************************************/ #include -#include #include +#include class Jorek : public PhysicsModel { private: @@ -14,36 +14,36 @@ class Jorek : public PhysicsModel { Field3D rho, Te, Ti, U, Vpar, Apar; // Derived quantities Field3D Jpar, phi; // Parallel current, electric potential - + // Equilibrium quantities Field2D rho0, Te0, Ti0; // Equilibrium mass density, electron and ion temperature Field2D B0, J0, P0; Vector2D b0xcv; // Curvature term Vector2D B0vec; // B0 field vector - + // Dissipation coefficients - Field2D D_perp; // Particle diffusion coefficient + Field2D D_perp; // Particle diffusion coefficient Field2D chi_eperp, chi_epar; // Electron heat diffusion coefficients Field2D chi_iperp, chi_ipar; // Ion heat diffusion coefficients - + // Collisional terms BoutReal tau_enorm; Field3D tau_e; // electron collision time - - Field2D eta0; // Resistivity + + Field2D eta0; // Resistivity Field3D eta; BoutReal viscos_par, viscos_perp, viscos_coll; // Viscosity coefficients - BoutReal hyperresist; // Hyper-resistivity coefficient + BoutReal hyperresist; // Hyper-resistivity coefficient int phi_flags; // Constants - const BoutReal MU0 = 4.0e-7*PI; - const BoutReal Charge = 1.60217646e-19; // electron charge e (C) - const BoutReal Mi = 2.0*1.67262158e-27; // Ion mass - const BoutReal Me = 9.1093816e-31; // Electron mass - const BoutReal Me_Mi = Me / Mi; // Electron mass / Ion mass + const BoutReal MU0 = 4.0e-7 * PI; + const BoutReal Charge = 1.60217646e-19; // electron charge e (C) + const BoutReal Mi = 2.0 * 1.67262158e-27; // Ion mass + const BoutReal Me = 9.1093816e-31; // Electron mass + const BoutReal Me_Mi = Me / Mi; // Electron mass / Ion mass // Normalisation factors BoutReal Tnorm, rhonorm; // Partial normalisation to rho and MU0. Temperature normalised @@ -51,9 +51,9 @@ class Jorek : public PhysicsModel { // options bool nonlinear; - bool full_bfield; // If true, use divergence-free expression for B - bool flux_method; // Use flux methods in rho and T equations - int jpar_bndry_width; // Set jpar = 0 in a boundary region + bool full_bfield; // If true, use divergence-free expression for B + bool flux_method; // Use flux methods in rho and T equations + int jpar_bndry_width; // Set jpar = 0 in a boundary region bool electron_density; // Solve Ne rather than Ni (adds Jpar term to density) @@ -68,7 +68,7 @@ class Jorek : public PhysicsModel { Vector3D vExB, vD; // Velocities Field3D divExB; // Divergence of ExB flow - BoutReal Wei; // Factor for the electron-ion collision term + BoutReal Wei; // Factor for the electron-ion collision term bool ohmic_heating; // Poisson brackets: b0 x Grad(f) dot Grad(g) / B = [f, g] @@ -79,31 +79,32 @@ class Jorek : public PhysicsModel { FieldGroup comms; // Coordinate system - Coordinates *coord; + Coordinates* coord; + + // Inverts a Laplacian to get potential + Laplacian* phiSolver; + + int init(bool UNUSED(restarting)) override { - int init(bool restarting) override { - output.write("Solving JOREK-like reduced MHD equations\n"); output.write("\tFile : %s\n", __FILE__); output.write("\tCompiled: %s at %s\n", __DATE__, __TIME__); - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("jorek"); + auto globalOptions = Options::root(); + auto options = globalOptions["jorek"]; ////////////////////////////////////////////////////////////// // Load data from the grid // Load 2D profiles - mesh->get(J0, "Jpar0"); // A / m^2 - + mesh->get(J0, "Jpar0"); // A / m^2 + if (mesh->get(rho0, "Ni0")) { output << "Warning: No density profile available\n"; - BoutReal d0; - options->get("density", d0, 1.0); - rho0 = d0; + rho0 = options["density"].withDefault(1.0); } rho0 *= 1e20; // Convert to m^[-3] - + // Read temperature mesh->get(Te0, "Te0"); mesh->get(Ti0, "Ti0"); @@ -114,11 +115,11 @@ class Jorek : public PhysicsModel { P0 = Charge * (Ti0 + Te0) * rho0; } else { // Make sure that density and temperature are consistent with pressure - + Field2D factor = P0 / (Charge * (Ti0 + Te0) * rho0); - - output.write("\tPressure factor %e -> %e\n", min(factor,true), max(factor, true)); - + + output.write("\tPressure factor %e -> %e\n", min(factor, true), max(factor, true)); + // Multiply temperatures by this factor Te0 *= factor; Ti0 *= factor; @@ -126,61 +127,54 @@ class Jorek : public PhysicsModel { rho0 *= Mi; // Convert density to mass density [kg / m^3] // Load dissipation coefficients, override in options file - if (options->isSet("D_perp")) { - BoutReal tmp; - options->get("D_perp", tmp, 0.0); - D_perp = tmp; - } else mesh->get(D_perp, "D_perp"); - - if (options->isSet("chi_eperp")) { - BoutReal tmp; - options->get("chi_eperp", tmp, 0.0); - chi_eperp = tmp; - } else mesh->get(chi_eperp, "chi_eperp"); - - if (options->isSet("chi_iperp")) { - BoutReal tmp; - options->get("chi_iperp", tmp, 0.0); - chi_iperp = tmp; - } else mesh->get(chi_iperp, "chi_iperp"); - - if (options->isSet("chi_epar")) { - BoutReal tmp; - options->get("chi_epar", tmp, 0.0); - chi_epar = tmp; - } else mesh->get(chi_epar, "chi_epar"); - - if (options->isSet("chi_ipar")) { - BoutReal tmp; - options->get("chi_ipar", tmp, 0.0); - chi_ipar = tmp; - } else mesh->get(chi_ipar, "chi_ipar"); - - if (options->isSet("viscos_perp")) { - BoutReal tmp; - options->get("viscos_perp", tmp, -1.0); - viscos_perp = tmp; - } else mesh->get(viscos_perp, "viscos_perp"); - - if (options->isSet("viscos_par")) { - BoutReal tmp; - options->get("viscos_par", tmp, -1.0); - viscos_par = tmp; - } else mesh->get(viscos_par, "viscos_par"); + if (options["D_perp"].isSet()) { + D_perp = options["D_perp"].withDefault(0.0); + } else + mesh->get(D_perp, "D_perp"); + + if (options["chi_eperp"].isSet()) { + chi_eperp = options["chi_eperp"].withDefault(0.0); + } else + mesh->get(chi_eperp, "chi_eperp"); + + if (options["chi_iperp"].isSet()) { + chi_iperp = options["chi_iperp"].withDefault(0.0); + } else + mesh->get(chi_iperp, "chi_iperp"); + + if (options["chi_epar"].isSet()) { + chi_epar = options["chi_epar"].withDefault(0.0); + } else + mesh->get(chi_epar, "chi_epar"); + + if (options["chi_ipar"].isSet()) { + chi_ipar = options["chi_ipar"].withDefault(0.0); + } else + mesh->get(chi_ipar, "chi_ipar"); + + if (options["viscos_perp"].isSet()) { + viscos_perp = options["viscos_perp"].withDefault(-1.0); + } else + mesh->get(viscos_perp, "viscos_perp"); + + if (options["viscos_par"].isSet()) { + viscos_par = options["viscos_par"].withDefault(-1.0); + } else + mesh->get(viscos_par, "viscos_par"); OPTION(options, viscos_coll, -1.0); // Load curvature term - b0xcv.covariant = false; // Read contravariant components + b0xcv.covariant = false; // Read contravariant components mesh->get(b0xcv, "bxcv"); // mixed units x: T y: m^-2 z: m^-2 - + // Metric coefficients Field2D Rxy, Bpxy, Btxy, hthe; Field2D I; // Shear factor - + coord = mesh->getCoordinates(); - - if (mesh->get(Rxy, "Rxy")) { // m + + if (mesh->get(Rxy, "Rxy")) { // m output_error.write("Error: Cannot read Rxy from grid\n"); return 1; } @@ -189,51 +183,49 @@ class Jorek : public PhysicsModel { return 1; } mesh->get(Btxy, "Btxy"); // T - mesh->get(B0, "Bxy"); // T + mesh->get(B0, "Bxy"); // T mesh->get(hthe, "hthe"); // m - mesh->get(I, "sinty");// m^-2 T^-1 - - OPTION(options, nonlinear, false); - OPTION(options, full_bfield, false); - OPTION(options, flux_method, false); - - OPTION(options, jpar_bndry_width, -1); - - OPTION(options, hyperresist, -1); - - OPTION(options, electron_density, false); - OPTION(options, vorticity_momentum, false); - OPTION(options, include_profiles, false); - OPTION(options, parallel_lc, true); - - OPTION(options, phi_flags, 0); - + mesh->get(I, "sinty"); // m^-2 T^-1 + + OPTION(options, nonlinear, false); + OPTION(options, full_bfield, false); + OPTION(options, flux_method, false); + + OPTION(options, jpar_bndry_width, -1); + + OPTION(options, hyperresist, -1); + + OPTION(options, electron_density, false); + OPTION(options, vorticity_momentum, false); + OPTION(options, include_profiles, false); + OPTION(options, parallel_lc, true); + + OPTION(options, phi_flags, 0); + OPTION(options, low_pass_z, -1); // Default is no filtering - + OPTION(options, Wei, 1.0); - + OPTION(options, ohmic_heating, true); - - int bracket_method; - OPTION(options, bracket_method, 0); - switch (bracket_method) { + + switch (options["bracket_method"].withDefault(0)) { case 0: { - bm = BRACKET_STD; + bm = BRACKET_STD; output << "\tBrackets: default differencing\n"; break; } case 1: { - bm = BRACKET_SIMPLE; + bm = BRACKET_SIMPLE; output << "\tBrackets: simplified operator\n"; break; } case 2: { - bm = BRACKET_ARAKAWA; + bm = BRACKET_ARAKAWA; output << "\tBrackets: Arakawa scheme\n"; break; } case 3: { - bm = BRACKET_CTU; + bm = BRACKET_CTU; output << "\tBrackets: Corner Transport Upwind method\n"; break; } @@ -241,88 +233,87 @@ class Jorek : public PhysicsModel { output << "ERROR: Invalid choice of bracket method. Must be 0 - 3\n"; return 1; } - + ////////////////////////////////////////////////////////////// // SHIFTED RADIAL COORDINATES - + // Check type of parallel transform - std::string ptstr; - Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); + std::string ptstr = + Options::root()["mesh"]["paralleltransform"].withDefault("identity"); if (lowercase(ptstr) == "shifted") { // Dimits style, using local coordinate system - b0xcv.z += I*b0xcv.x; - I = 0.0; // I disappears from metric + b0xcv.z += I * b0xcv.x; + I = 0.0; // I disappears from metric } ////////////////////////////////////////////////////////////// // NORMALISE QUANTITIES - - rhonorm = max(rho0, true); // Maximum over all grid - BoutReal Temax = max(Te0,true); // Maximum Te value + + rhonorm = max(rho0, true); // Maximum over all grid + BoutReal Temax = max(Te0, true); // Maximum Te value Tnorm = Mi / (MU0 * Charge * rhonorm); // Temperature normalisation - - SAVE_ONCE2(rhonorm, Tnorm); // Save normalisation factors to file - + + SAVE_ONCE(rhonorm, Tnorm); // Save normalisation factors to file + // Normalise quantities - + P0 *= MU0; J0 *= MU0; rho0 /= rhonorm; Te0 /= Tnorm; Ti0 /= Tnorm; - + viscos_perp *= sqrt(MU0 / rhonorm); - viscos_par *= sqrt(MU0 / rhonorm); - D_perp *= sqrt(MU0 * rhonorm); - chi_eperp *= sqrt(MU0 / rhonorm); - chi_epar *= sqrt(MU0 / rhonorm); - chi_iperp *= sqrt(MU0 / rhonorm); - chi_ipar *= sqrt(MU0 / rhonorm); - + viscos_par *= sqrt(MU0 / rhonorm); + D_perp *= sqrt(MU0 * rhonorm); + chi_eperp *= sqrt(MU0 / rhonorm); + chi_epar *= sqrt(MU0 / rhonorm); + chi_iperp *= sqrt(MU0 / rhonorm); + chi_ipar *= sqrt(MU0 / rhonorm); + // Coulomb logarithm - BoutReal CoulombLog = 6.6 - 0.5*log(rhonorm/(Mi*1e20)) + 1.5*log(Temax); + BoutReal CoulombLog = 6.6 - 0.5 * log(rhonorm / (Mi * 1e20)) + 1.5 * log(Temax); output << "\tCoulomb logarithm = " << CoulombLog << endl; - + // Factor in front of tau_e expression // tau_e = tau_enorm * Tet^1.5 / rhot - tau_enorm = 3.44e11*(Mi/rhonorm)*Tnorm*sqrt(Tnorm) / CoulombLog; - output << "\ttau_enorm = " << tau_enorm ; - tau_enorm /= sqrt(MU0*rhonorm); // Normalise + tau_enorm = 3.44e11 * (Mi / rhonorm) * Tnorm * sqrt(Tnorm) / CoulombLog; + output << "\ttau_enorm = " << tau_enorm; + tau_enorm /= sqrt(MU0 * rhonorm); // Normalise output << "\tNormalised tau_enorm = " << tau_enorm << endl; - + // Calculate or read in the resistivity - if (options->isSet("eta")) { - BoutReal etafactor; - options->get("eta", etafactor, 0.0); + if (options["eta"].isSet()) { + BoutReal etafactor = options["eta"].withDefault(0.0); // Calculate in normalised units - eta0 = etafactor * Me*Mi/(1.96*MU0*rhonorm*Charge*Charge*tau_enorm*rho0); + eta0 = etafactor * Me * Mi + / (1.96 * MU0 * rhonorm * Charge * Charge * tau_enorm * rho0); } else { mesh->get(eta0, "eta0"); // Read in SI units eta0 *= sqrt(rhonorm / MU0); // Normalise } - - + ////////////////////////////////////////////////////////////// // CALCULATE METRICS - - coord->g11 = SQ(Rxy*Bpxy); + + coord->g11 = SQ(Rxy * Bpxy); coord->g22 = 1.0 / SQ(hthe); - coord->g33 = SQ(I)*coord->g11 + SQ(B0)/coord->g11; + coord->g33 = SQ(I) * coord->g11 + SQ(B0) / coord->g11; coord->g12 = 0.0; - coord->g13 = -I*coord->g11; - coord->g23 = -Btxy/(hthe*Bpxy*Rxy); - + coord->g13 = -I * coord->g11; + coord->g23 = -Btxy / (hthe * Bpxy * Rxy); + coord->J = hthe / Bpxy; coord->Bxy = B0; - - coord->g_11 = 1.0/coord->g11 + SQ(I*Rxy); - coord->g_22 = SQ(B0*hthe/Bpxy); - coord->g_33 = Rxy*Rxy; - coord->g_12 = Btxy*hthe*I*Rxy/Bpxy; - coord->g_13 = I*Rxy*Rxy; - coord->g_23 = Btxy*hthe*Rxy/Bpxy; - + + coord->g_11 = 1.0 / coord->g11 + SQ(I * Rxy); + coord->g_22 = SQ(B0 * hthe / Bpxy); + coord->g_33 = Rxy * Rxy; + coord->g_12 = Btxy * hthe * I * Rxy / Bpxy; + coord->g_13 = I * Rxy * Rxy; + coord->g_23 = Btxy * hthe * Rxy / Bpxy; + coord->geometry(); // Calculate quantities from metric tensor // Set B field vector @@ -330,17 +321,17 @@ class Jorek : public PhysicsModel { B0vec.x = 0.; B0vec.y = Bpxy / hthe; B0vec.z = 0.; - + vExB.setBoundary("v"); vD.setBoundary("v"); - + Jpar.setBoundary("Jpar"); phi.setBoundary("phi"); // Set starting dissipation terms eta = eta0; - tau_e = tau_enorm * pow(Te0,1.5)/rho0; + tau_e = tau_enorm * pow(Te0, 1.5) / rho0; output.write("\tNormalised tau_e = %e -> %e\n", min(tau_e, true), max(tau_e, true)); @@ -349,12 +340,12 @@ class Jorek : public PhysicsModel { // SET EVOLVING VARIABLES - SOLVE_FOR6(rho, Te, Ti, U, Vpar, Apar); - + SOLVE_FOR(rho, Te, Ti, U, Vpar, Apar); + comms.add(rho, Te, Ti, U, Vpar, Apar); comms.add(phi); - - SAVE_ONCE5(P0, J0, rho0, Te0, Ti0); // Save normalised profiles + + SAVE_ONCE(P0, J0, rho0, Te0, Ti0); // Save normalised profiles if (nonlinear) { SAVE_REPEAT(eta); @@ -362,18 +353,23 @@ class Jorek : public PhysicsModel { SAVE_ONCE(eta); } - SAVE_REPEAT2(phi, Jpar); // Save each timestep - + SAVE_REPEAT(phi, Jpar); // Save each timestep SAVE_REPEAT(divExB); - + + // Create a solver for the Laplacian + phiSolver = Laplacian::create(); + phiSolver->setFlags(phi_flags); + if (vorticity_momentum) { + phiSolver->setCoefC(rho0); + } return 0; } // Parallel gradient along perturbed field-line - const Field3D Grad_parP(const Field3D &f, CELL_LOC loc = CELL_DEFAULT) { + const Field3D Grad_parP(const Field3D& f, CELL_LOC loc = CELL_DEFAULT) { // Derivative along equilibrium field-line Field3D result; - + if (parallel_lc) { if (loc == CELL_YLOW) { result = Grad_par_CtoL(f); @@ -381,7 +377,7 @@ class Jorek : public PhysicsModel { result = Grad_par_LtoC(f); } else result = Grad_par(f, loc); - + if (nonlinear) { if (full_bfield) { // Use full expression for perturbed B @@ -394,312 +390,294 @@ class Jorek : public PhysicsModel { } return result; } - - const Field3D Div_parP(const Field3D &f, CELL_LOC loc = CELL_DEFAULT) { - return B0*Grad_parP(f/B0, loc); + + const Field3D Div_parP(const Field3D& f, CELL_LOC loc = CELL_DEFAULT) { + return B0 * Grad_parP(f / B0, loc); } - + int rhs(BoutReal t) override { TRACE("Started physics_run(%e)", t); - + // Invert laplacian for phi if (vorticity_momentum) { // Vorticity is b dot curl(rho * v) Field2D rprof = rho0; - if (nonlinear) + if (nonlinear) { rprof += DC(rho); // Axisymmetric rho only - phi = invert_laplace(B0*U/rprof, phi_flags, NULL, &rprof); + phiSolver->setCoefC(rprof); + } + phi = phiSolver->solve(B0 * U / rprof); } else { // Vorticity is b dot curl(v) - phi = invert_laplace(B0*U, phi_flags); + phi = phiSolver->solve(B0 * U); } // Apply a boundary condition on phi for target plates phi.applyBoundary(); - + // Communicate variables mesh->communicate(comms); - - + // Get J from Psi Jpar = -Delp2(Apar); Jpar.applyBoundary(); - + if (jpar_bndry_width > 0) { // Boundary in jpar if (mesh->firstX()) { - for (int i=jpar_bndry_width;i>=0;i--) - for (int j=0;jLocalNy;j++) - for (int k=0;kLocalNz;k++) { - Jpar(i,j,k) = 0.5*Jpar(i+1,j,k); + for (int i = jpar_bndry_width; i >= 0; i--) + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + Jpar(i, j, k) = 0.5 * Jpar(i + 1, j, k); } } if (mesh->lastX()) { - for (int i=mesh->LocalNx-jpar_bndry_width-1;iLocalNx;i++) - for (int j=0;jLocalNy;j++) - for (int k=0;kLocalNz;k++) { - Jpar(i,j,k) = 0.5*Jpar(i-1,j,k); + for (int i = mesh->LocalNx - jpar_bndry_width - 1; i < mesh->LocalNx; i++) + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + Jpar(i, j, k) = 0.5 * Jpar(i - 1, j, k); } } } - + mesh->communicate(Jpar); - - //Jpar = smooth_x(Jpar); // Smooth in x direction - + + // Jpar = smooth_x(Jpar); // Smooth in x direction + Field3D rhot = rho0; Field3D Tet = Te0; Field3D Tit = Ti0; - Field3D P = rho*(Te0+Ti0) + (Te+Ti)*rho0; // Perturbed pressure - + Field3D P = rho * (Te0 + Ti0) + (Te + Ti) * rho0; // Perturbed pressure + if (nonlinear) { rhot += rho; Tet += Te; Tit += Ti; - P += rho*(Te+Ti); - - eta = eta0*pow(Tet/Te0,-1.5); // Update resistivity based on Te - - tau_e = tau_enorm*pow(Tet,1.5)/rhot; // Update electron collision rate + P += rho * (Te + Ti); + + eta = eta0 * pow(Tet / Te0, -1.5); // Update resistivity based on Te + + tau_e = tau_enorm * pow(Tet, 1.5) / rhot; // Update electron collision rate } - + if (flux_method) { { TRACE("Flux vExB"); // ExB velocity - vExB = (cross(B0vec, Grad_perp(phi)))/(B0*B0); + vExB = (cross(B0vec, Grad_perp(phi))) / (B0 * B0); vExB.applyBoundary(); } - + ////////// Density equation //////////////// - + { TRACE("Flux Density"); - + // Diffusive flux (perpendicular) vD = -D_perp * Grad_perp(rho); vD.applyBoundary(); - - ddt(rho) = -Div(vExB + vD, rhot); + + ddt(rho) = -Div(vExB + vD, rhot); } - + ////////// Temperature equations //////////// - + { TRACE("Flux Te"); - - vD = -chi_eperp * Grad_perp(Te) - Grad_par(Te, CELL_YLOW)*chi_epar*B0vec; + + vD = -chi_eperp * Grad_perp(Te) - Grad_par(Te, CELL_YLOW) * chi_epar * B0vec; vD.applyBoundary(); - - ddt(Te) = - - b0xGrad_dot_Grad(phi, Tet)/B0 - - (2./3.)*Tet*Div(vExB) - - Div(vD, Te)/rhot - ; + + ddt(Te) = -b0xGrad_dot_Grad(phi, Tet) / B0 - (2. / 3.) * Tet * Div(vExB) + - Div(vD, Te) / rhot; } - + { TRACE("Flux Ti"); - - vD = -chi_iperp * Grad_perp(Ti) - Grad_par(Ti, CELL_YLOW)*chi_ipar*B0vec; + + vD = -chi_iperp * Grad_perp(Ti) - Grad_par(Ti, CELL_YLOW) * chi_ipar * B0vec; vD.applyBoundary(); - - ddt(Ti) = - - b0xGrad_dot_Grad(phi, Tit)/B0 - - (2./3.)*Tit*Div(vExB) - - Div(vD, Ti)/rhot - ; + + ddt(Ti) = -b0xGrad_dot_Grad(phi, Tit) / B0 - (2. / 3.) * Tit * Div(vExB) + - Div(vD, Ti) / rhot; } } else { // Use analytic expressions, expand terms - + // Divergence of ExB velocity (neglecting parallel term) { TRACE("divExB"); - divExB = b0xcv*Grad(phi)/B0 - b0xGrad_dot_Grad(1./B0, phi); + divExB = b0xcv * Grad(phi) / B0 - b0xGrad_dot_Grad(1. / B0, phi); } - + { TRACE("density"); - ddt(rho) = - - bracket(phi, rhot, bm) // ExB advection - - divExB*rhot // Divergence of ExB (compression) - - Vpar_Grad_par(Vpar, rho) // Parallel advection - - rhot*Div_parP(Vpar, CELL_CENTRE) // Parallel compression - + D_perp * Delp2(rho) // Perpendicular diffusion - ; - + ddt(rho) = -bracket(phi, rhot, bm) // ExB advection + - divExB * rhot // Divergence of ExB (compression) + - Vpar_Grad_par(Vpar, rho) // Parallel advection + - rhot * Div_parP(Vpar, CELL_CENTRE) // Parallel compression + + D_perp * Delp2(rho) // Perpendicular diffusion + ; + if (electron_density) { // Using electron parallel velocity rather than ion - ddt(rho) += (Mi/(Charge*sqrt(MU0*rhonorm)))* Div_parP(Jpar, CELL_CENTRE); + ddt(rho) += (Mi / (Charge * sqrt(MU0 * rhonorm))) * Div_parP(Jpar, CELL_CENTRE); } if (low_pass_z > 0) - ddt(rho) = lowPass(ddt(rho), low_pass_z); - + ddt(rho) = lowPass(ddt(rho), low_pass_z); } - + { TRACE("Te"); - ddt(Te) = - -bracket(phi, Tet, bm) - Vpar_Grad_par(Vpar, Tet) // advection - - (2./3.)*Tet*(divExB + Div_parP(Vpar, CELL_CENTRE)) // Divergence of flow - + Div_par_K_Grad_par(chi_epar, Te) / rhot // Parallel diffusion - + chi_eperp*Delp2(Te) / rhot // Perpendicular diffusion - ; - + ddt(Te) = -bracket(phi, Tet, bm) - Vpar_Grad_par(Vpar, Tet) // advection + - (2. / 3.) * Tet + * (divExB + Div_parP(Vpar, CELL_CENTRE)) // Divergence of flow + + Div_par_K_Grad_par(chi_epar, Te) / rhot // Parallel diffusion + + chi_eperp * Delp2(Te) / rhot // Perpendicular diffusion + ; + if (ohmic_heating) - ddt(Te) += (2./3)*eta*Jpar*Jpar / rhot; // Ohmic heating - + ddt(Te) += (2. / 3) * eta * Jpar * Jpar / rhot; // Ohmic heating } - + { TRACE("Ti"); - ddt(Ti) = - - bracket(phi, Tit, bm) - Vpar_Grad_par(Vpar, Tit) - - (2./3.)*Tit*(divExB + Div_parP(Vpar, CELL_CENTRE)) - + Div_par_K_Grad_par(chi_ipar, Ti) / rhot - + chi_iperp*Delp2(Ti) / rhot - ; + ddt(Ti) = -bracket(phi, Tit, bm) - Vpar_Grad_par(Vpar, Tit) + - (2. / 3.) * Tit * (divExB + Div_parP(Vpar, CELL_CENTRE)) + + Div_par_K_Grad_par(chi_ipar, Ti) / rhot + + chi_iperp * Delp2(Ti) / rhot; } - - + if (Wei > 0.0) { TRACE("Wei"); // electron-ion collision term // Calculate Wi * (2/3)/rho term. Wei is a scaling factor from options - Field3D Tei = Wei * 2.*Me_Mi*(Te - Ti) / tau_e; - + Field3D Tei = Wei * 2. * Me_Mi * (Te - Ti) / tau_e; + ddt(Ti) += Tei; ddt(Te) -= Tei; } - + if (low_pass_z > 0) { ddt(Te) = lowPass(ddt(Te), low_pass_z); ddt(Ti) = lowPass(ddt(Ti), low_pass_z); } } - + ////////// Vorticity equation //////////// - - - if(vorticity_momentum) { + + if (vorticity_momentum) { TRACE("vorticity_momentum"); // Vorticity is b dot curl(rho * v) - - ddt(U) = - SQ(B0)*Grad_parP(Jpar/B0, CELL_CENTRE) // b0 dot J - + 2.*b0xcv*Grad(P) - - rhot*(divExB + Div_parP(Vpar, CELL_CENTRE)) * Delp2(phi)/B0 // drho/dt term - ; - + + ddt(U) = SQ(B0) * Grad_parP(Jpar / B0, CELL_CENTRE) // b0 dot J + + 2. * b0xcv * Grad(P) + - rhot * (divExB + Div_parP(Vpar, CELL_CENTRE)) * Delp2(phi) + / B0 // drho/dt term + ; + // b dot J0 if (full_bfield) { Vector3D Btilde = Curl(B0vec * Apar / B0); - ddt(U) += B0*Btilde * Grad(J0/B0); - }else { - ddt(U) -= SQ(B0)*bracket(Apar, J0/B0, BRACKET_ARAKAWA); + ddt(U) += B0 * Btilde * Grad(J0 / B0); + } else { + ddt(U) -= SQ(B0) * bracket(Apar, J0 / B0, BRACKET_ARAKAWA); } - + if (electron_density) { // drho/dt jpar term - ddt(U) += (Mi/(Charge*sqrt(MU0*rhonorm)))* rhot*Div_parP(Jpar/rhot, CELL_CENTRE) * Delp2(phi)/B0; + ddt(U) += (Mi / (Charge * sqrt(MU0 * rhonorm))) * rhot + * Div_parP(Jpar / rhot, CELL_CENTRE) * Delp2(phi) / B0; } - + if (include_profiles) { - ddt(U) += - SQ(B0)*Grad_par(J0/B0) // b0 dot J0 - + 2.*b0xcv*Grad(P0) - ; + ddt(U) += SQ(B0) * Grad_par(J0 / B0) // b0 dot J0 + + 2. * b0xcv * Grad(P0); } - + if (nonlinear) { ddt(U) -= bracket(phi, U, bm); // Advection - ddt(U) -= Vpar_Grad_par(Vpar, U); // Parallel advection + ddt(U) -= Vpar_Grad_par(Vpar, U); // Parallel advection } // Viscosity terms if (viscos_par > 0.0) ddt(U) += viscos_par * Grad2_par2(U); // Parallel viscosity - + if (viscos_perp > 0.0) - ddt(U) += viscos_perp * rhot*Delp2(U/rhot); // Perpendicular viscosity - + ddt(U) += viscos_perp * rhot * Delp2(U / rhot); // Perpendicular viscosity + } else { TRACE("vorticity"); // Vorticity is b dot curl(v) - ddt(U) = ( - SQ(B0)*Grad_parP(Jpar/B0, CELL_CENTRE) - + 2.*b0xcv*Grad(P) // curvature term - ) / rhot; - + ddt(U) = (SQ(B0) * Grad_parP(Jpar / B0, CELL_CENTRE) + + 2. * b0xcv * Grad(P) // curvature term + ) + / rhot; + // b dot J0 if (full_bfield) { Vector3D Btilde = Curl(B0vec * Apar / B0); - ddt(U) += B0*Btilde * Grad(J0/B0) / rhot; + ddt(U) += B0 * Btilde * Grad(J0 / B0) / rhot; } else { - ddt(U) -= SQ(B0)* bracket(Apar, J0/B0, BRACKET_ARAKAWA) / rhot; + ddt(U) -= SQ(B0) * bracket(Apar, J0 / B0, BRACKET_ARAKAWA) / rhot; } - + if (include_profiles) { - ddt(U) += ( - SQ(B0)*Grad_par(J0/B0) // b0 dot J0 - + 2.*b0xcv*Grad(P0) - ) / rhot; + ddt(U) += (SQ(B0) * Grad_par(J0 / B0) // b0 dot J0 + + 2. * b0xcv * Grad(P0)) + / rhot; } - + if (nonlinear) { - ddt(U) -= bracket(phi, U); // Advection - ddt(U) -= Vpar_Grad_par(Vpar, U); // Parallel advection + ddt(U) -= bracket(phi, U); // Advection + ddt(U) -= Vpar_Grad_par(Vpar, U); // Parallel advection } - + // Viscosity terms if (viscos_par > 0.0) ddt(U) += viscos_par * Grad2_par2(U) / rhot; // Parallel viscosity - + if (viscos_perp > 0.0) - ddt(U) += viscos_perp * Delp2(U) / rhot; // Perpendicular viscosity - + ddt(U) += viscos_perp * Delp2(U) / rhot; // Perpendicular viscosity + // Collisional viscosity if (viscos_coll > 0.0) ddt(U) += viscos_coll / MU0 * eta * Delp2(U) / rhot; } - + if (low_pass_z > 0) ddt(U) = lowPass(ddt(U), low_pass_z); - - + ////////// Parallel velocity equation //////////// - + { TRACE("Vpar"); - + ddt(Vpar) = -Grad_parP(P + P0, CELL_YLOW); if (nonlinear) { - ddt(Vpar) -= bracket(phi, Vpar); // Advection + ddt(Vpar) -= bracket(phi, Vpar); // Advection ddt(Vpar) -= Vpar_Grad_par(Vpar, Vpar); // Parallel advection } - + if (low_pass_z > 0) ddt(Vpar) = lowPass(ddt(Vpar), low_pass_z); - } ////////// Magnetic potential equation //////////// - + { TRACE("Apar"); - ddt(Apar) = - -Grad_parP(phi, CELL_YLOW) - - eta*Jpar; - + ddt(Apar) = -Grad_parP(phi, CELL_YLOW) - eta * Jpar; + if (hyperresist > 0.0) { - ddt(Apar) += eta*hyperresist * Delp2(Jpar); + ddt(Apar) += eta * hyperresist * Delp2(Jpar); } } - + if (low_pass_z > 0) ddt(Apar) = lowPass(ddt(Apar), low_pass_z); - + return 0; } }; diff --git a/examples/lapd-drift/lapd_drift.cxx b/examples/lapd-drift/lapd_drift.cxx index 25c26f1016..eb90490146 100644 --- a/examples/lapd-drift/lapd_drift.cxx +++ b/examples/lapd-drift/lapd_drift.cxx @@ -106,12 +106,14 @@ class LAPDdrift : public PhysicsModel { // Communication object FieldGroup comms; + // Laplacian inversion object + Laplacian *phiSolver; protected: /// Function called once at the start of the simulation /// /// @param[in] restarting True if simulation is restarting - int init(bool restarting) { + int init(bool UNUSED(restarting)) { Field2D I; // Shear factor output.write("Solving LAPD drift test case\n"); @@ -153,19 +155,18 @@ class LAPDdrift : public PhysicsModel { // Get separatrix location mesh->get(my_ixseps, "ixseps1"); - Ni_x *= 1.0e14; bmag *= 1.0e4; /*************** READ OPTIONS *************************/ // Read some parameters - Options *globalOptions = Options::getRoot(); + auto globalOptions = Options::root(); - globalOptions->get("TIMESTEP", time_step, 1.0); + time_step = globalOptions["TIMESTEP"].withDefault(1.0); - Options *options = globalOptions->getSection("2fluid"); - OPTION(options, AA, 4.0); // <=> options.get("AA", AA, 1.0); + auto options = globalOptions["2fluid"]; + OPTION(options, AA, 4.0); // <=> AA = options["AA"].withDefault(1.0); OPTION(options, ZZ, 1.0); OPTION(options, estatic, false); @@ -202,7 +203,7 @@ class LAPDdrift : public PhysicsModel { // Set default values for terms in each equation // Allows default to be overridden in BOUT.inp file - Options *option_rho = globalOptions->getSection("rho"); + auto option_rho = globalOptions["rho"]; OPTION(option_rho, evolve_rho, true); OPTION(option_rho, rho_jpar1, false); OPTION(option_rho, rho_nuin_rho1, false); @@ -214,7 +215,7 @@ class LAPDdrift : public PhysicsModel { OPTION(option_rho, rho_ve2t, false); OPTION(option_rho, rho_diff, false); - Options *option_ni = globalOptions->getSection("ni"); + auto option_ni = globalOptions["ni"]; OPTION(option_ni, evolve_ni, true); OPTION(option_ni, ni_jpar1, false); OPTION(option_ni, ni_ni0_phi1, false); @@ -223,7 +224,7 @@ class LAPDdrift : public PhysicsModel { OPTION(option_ni, ni_src_ni0, false); OPTION(option_ni, ni_diff, false); - Options *option_ajpar = globalOptions->getSection("ajpar"); + auto option_ajpar = globalOptions["ajpar"]; OPTION(option_ajpar, evolve_ajpar, true); OPTION(option_ajpar, ajpar_phi1, false); OPTION(option_ajpar, ajpar_jpar1, false); @@ -233,7 +234,7 @@ class LAPDdrift : public PhysicsModel { OPTION(option_ajpar, ajpar_ajpar1_phi1,false); OPTION(option_ajpar, ajpar_ve1_ve1, false); - Options *option_te = globalOptions->getSection("te"); + auto option_te = globalOptions["te"]; OPTION(option_te, evolve_te, true); OPTION(option_te, te_te1_phi0, false); OPTION(option_te, te_te0_phi1, false); @@ -252,8 +253,7 @@ class LAPDdrift : public PhysicsModel { /************* SHIFTED RADIAL COORDINATES ************/ // Check type of parallel transform - std::string ptstr; - Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); + std::string ptstr = Options::root()["mesh"]["paralleltransform"].withDefault("identity"); if (lowercase(ptstr) == "shifted") { ShearFactor = 0.0; // I disappears from metric @@ -408,17 +408,23 @@ class LAPDdrift : public PhysicsModel { /*************** DUMP VARIABLES TO OUTPUT**********/ dump.add(phi, "phi", 1); dump.add(jpar, "jpar", 1); - SAVE_ONCE4(Ni0,Te0,phi0,rho0); - SAVE_ONCE5(Rxy,Bpxy,Btxy,Zxy,hthe); - dump.add(coord->Bxy, "Bxy", 0); dump.add(my_ixseps, "ixseps", 0); - - SAVE_ONCE3(Te_x,Ti_x,Ni_x); - SAVE_ONCE6(AA,ZZ,zeff,rho_s,wci,bmag); - dump.add(mesh->LocalNx, "ngx", 0); - dump.add(mesh->LocalNy, "ngy", 0); - dump.add(mesh->LocalNz, "ngz", 0); - SAVE_ONCE6(mui_hat,nu_hat,nuIonNeutral,beta_p,time_step,hthe0); - SAVE_ONCE3(ni_perpdiff,rho_perpdiff,te_perpdiff); + SAVE_ONCE(Ni0,Te0,phi0,rho0); + SAVE_ONCE(Rxy,Bpxy,Btxy,Zxy,hthe); + dump.addOnce(coord->Bxy, "Bxy"); + dump.addOnce(my_ixseps, "ixseps"); + + SAVE_ONCE(Te_x,Ti_x,Ni_x); + SAVE_ONCE(AA,ZZ,zeff,rho_s,wci,bmag); + dump.addOnce(mesh->LocalNx, "ngx"); + dump.addOnce(mesh->LocalNy, "ngy"); + dump.addOnce(mesh->LocalNz, "ngz"); + SAVE_ONCE(mui_hat,nu_hat,nuIonNeutral,beta_p,time_step,hthe0); + SAVE_ONCE(ni_perpdiff,rho_perpdiff,te_perpdiff); + + // Laplacian inversion solver + phiSolver = Laplacian::create(); + phiSolver->setFlags(phi_flags); + phiSolver->setCoefC(Ni0); return 0; } @@ -439,9 +445,9 @@ class LAPDdrift : public PhysicsModel { // Arguments are: (b, bit-field, a, c) // Passing NULL -> missing term if (nonlinear) { - phi = invert_laplace(rho/(Ni0+ni), phi_flags, NULL, &Ni0); + phi = phiSolver->solve(rho/(Ni0+ni)); } else { - phi = invert_laplace(rho/Ni0, phi_flags, NULL, &Ni0); + phi = phiSolver->solve(rho/Ni0); } // Communicate variables diff --git a/examples/tokamak-2fluid/2fluid.cxx b/examples/tokamak-2fluid/2fluid.cxx index 01f932f9fb..47bd464bac 100644 --- a/examples/tokamak-2fluid/2fluid.cxx +++ b/examples/tokamak-2fluid/2fluid.cxx @@ -94,8 +94,15 @@ class TwoFluid : public PhysicsModel { // Coordinate system metrics Coordinates *coord; + + // Inverts a Laplacian to get potential + Laplacian *phiSolver; + + // Solves the electromagnetic potential + Laplacian *aparSolver; + Field2D acoef; // Coefficient in the Helmholtz equation - int init(bool restarting) override { + int init(bool UNUSED(restarting)) override { TRACE("int init(bool) "); Field2D I; // Shear factor @@ -151,8 +158,8 @@ class TwoFluid : public PhysicsModel { // READ OPTIONS // Read some parameters - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("2fluid"); + auto globalOptions = Options::root(); + auto options = globalOptions["2fluid"]; OPTION(options, AA, 2.0); OPTION(options, ZZ, 1.0); @@ -209,13 +216,12 @@ class TwoFluid : public PhysicsModel { OPTION(options, phi_flags, 0); OPTION(options, apar_flags, 0); - - (globalOptions->getSection("Ni"))->get("evolve", evolve_ni, true); - (globalOptions->getSection("rho"))->get("evolve", evolve_rho, true); - (globalOptions->getSection("vi"))->get("evolve", evolve_vi, true); - (globalOptions->getSection("te"))->get("evolve", evolve_te, true); - (globalOptions->getSection("ti"))->get("evolve", evolve_ti, true); - (globalOptions->getSection("Ajpar"))->get("evolve", evolve_ajpar, true); + + evolve_ni = globalOptions["Ni"]["evolve"].withDefault(true); + evolve_rho = globalOptions["rho"]["evolve"].withDefault(true); + evolve_vi = globalOptions["vi"]["evolve"].withDefault(true); + evolve_ti = globalOptions["ti"]["evolve"].withDefault(true); + evolve_ajpar = globalOptions["Ajpar"]["evolve"].withDefault(true); if (ZeroElMass) { evolve_ajpar = 0; // Don't need ajpar - calculated from ohm's law @@ -225,7 +231,7 @@ class TwoFluid : public PhysicsModel { // Equation terms if (evolve_ni) { - options = globalOptions->getSection("Ni"); + Options* options = &globalOptions["Ni"]; options->get("ni1_phi0", ni_ni1_phi0, false); options->get("ni0_phi1", ni_ni0_phi1, false); options->get("ni1_phi1", ni_ni1_phi1, false); @@ -243,7 +249,7 @@ class TwoFluid : public PhysicsModel { } if (evolve_rho) { - options = globalOptions->getSection("rho"); + Options* options = &globalOptions["rho"]; options->get("rho0_phi1", rho_rho0_phi1, false); options->get("rho1_phi0", rho_rho1_phi0, false); options->get("rho1_phi1", rho_rho1_phi1, false); @@ -256,7 +262,7 @@ class TwoFluid : public PhysicsModel { } if (evolve_vi) { - options = globalOptions->getSection("vi"); + Options* options = &globalOptions["vi"]; options->get("vi0_phi1", vi_vi0_phi1, false); options->get("vi1_phi0", vi_vi1_phi0, false); options->get("vi1_phi1", vi_vi1_phi1, false); @@ -271,14 +277,14 @@ class TwoFluid : public PhysicsModel { } if (evolve_te) { - options = globalOptions->getSection("te"); + Options* options = &globalOptions["te"]; options->get("te1_phi0", te_te1_phi0, false); options->get("te0_phi1", te_te0_phi1, false); options->get("te1_phi1", te_te1_phi1, false); } if (evolve_ti) { - options = globalOptions->getSection("ti"); + Options* options = &globalOptions["ti"]; options->get("ti1_phi0", ti_ti1_phi0, false); options->get("ti0_phi1", ti_ti0_phi1, false); options->get("ti1_phi1", ti_ti1_phi1, false); @@ -288,8 +294,7 @@ class TwoFluid : public PhysicsModel { // SHIFTED RADIAL COORDINATES // Check type of parallel transform - std::string ptstr; - Options::getRoot()->getSection("mesh")->get("paralleltransform", ptstr, "identity"); + std::string ptstr = Options::root()["mesh"]["paralleltransform"].withDefault("identity"); if (lowercase(ptstr) == "shifted") { ShearFactor = 0.0; // I disappears from metric @@ -473,27 +478,43 @@ class TwoFluid : public PhysicsModel { comms.add(Apar); // Add any other variables to be dumped to file - dump.add(phi, "phi", 1); - dump.add(Apar, "Apar", 1); - dump.add(jpar, "jpar", 1); - - dump.add(Ni0, "Ni0", 0); - dump.add(Te0, "Te0", 0); - dump.add(Ti0, "Ti0", 0); - - dump.add(Te_x, "Te_x", 0); - dump.add(Ti_x, "Ti_x", 0); - dump.add(Ni_x, "Ni_x", 0); - dump.add(rho_s, "rho_s", 0); - dump.add(wci, "wci", 0); + dump.addRepeat(phi, "phi"); + dump.addRepeat(Apar, "Apar"); + dump.addRepeat(jpar, "jpar"); + + dump.addOnce(Ni0, "Ni0"); + dump.addOnce(Te0, "Te0"); + dump.addOnce(Ti0, "Ti0"); + + dump.addOnce(Te_x, "Te_x"); + dump.addOnce(Ti_x, "Ti_x"); + dump.addOnce(Ni_x, "Ni_x"); + dump.addOnce(rho_s, "rho_s"); + dump.addOnce(wci, "wci"); + + // Create a solver for the Laplacian + phiSolver = Laplacian::create(); + phiSolver->setFlags(phi_flags); + if (laplace_extra_rho_term) { + // Include the first order term Grad_perp Ni dot Grad_perp phi + phiSolver->setCoefC(Ni0); + } + + if (! (estatic || ZeroElMass)) { + // Create a solver for the electromagnetic potential + aparSolver = Laplacian::create(); + aparSolver->setFlags(apar_flags); + acoef = (-0.5 * beta_p / fmei) * Ni0; + aparSolver->setCoefA(acoef); + } - return(0); + return 0; } // ExB terms using Poisson bracket #define vE_Grad(f, p) ( bracket(p, f, bm) ) - int rhs(BoutReal t) override { + int rhs(BoutReal UNUSED(t)) override { //////////////////////////////////////////////////////// // Invert vorticity to get phi @@ -504,12 +525,8 @@ class TwoFluid : public PhysicsModel { { TRACE("Solving for phi"); - if (laplace_extra_rho_term) { - // Include the first order term Grad_perp Ni dot Grad_perp phi - phi = invert_laplace(rho/Ni0, phi_flags, NULL, &Ni0); - } else { - phi = invert_laplace(rho/Ni0, phi_flags); - } + + phi = phiSolver->solve(rho/Ni0); if (vort_include_pi) { // Include Pi term in vorticity @@ -526,14 +543,7 @@ class TwoFluid : public PhysicsModel { // Electrostatic operation Apar = 0.0; } else { - static Field2D acoeff; - static bool aset = false; - - if (!aset) // calculate Apar coefficient - acoeff = (-0.5*beta_p/fmei)*Ni0; - aset = true; - - Apar = invert_laplace(acoeff*(Vi - Ajpar), apar_flags, &acoeff); + Apar = aparSolver->solve(acoef*(Vi - Ajpar)); } } From 18d35f7ccbecccc76e4c63df3681ab525844fa90 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sun, 23 Dec 2018 15:10:42 +0000 Subject: [PATCH 0515/1783] Deleting unused example code Not included in any makefile, most don't compile any more. --- examples/dalf3/dalf3_hotion.cxx | 533 -------------------- examples/reconnect-2field/2field-bc.cxx | 373 -------------- examples/reconnect-2field/2field-new.cxx | 355 ------------- examples/reconnect-2field/2field-precon.cxx | 346 ------------- examples/reconnect-2field/BOUT-new.inp | 219 -------- examples/reconnect-2field/makefile-new | 6 - 6 files changed, 1832 deletions(-) delete mode 100644 examples/dalf3/dalf3_hotion.cxx delete mode 100644 examples/reconnect-2field/2field-bc.cxx delete mode 100644 examples/reconnect-2field/2field-new.cxx delete mode 100644 examples/reconnect-2field/2field-precon.cxx delete mode 100644 examples/reconnect-2field/BOUT-new.inp delete mode 100644 examples/reconnect-2field/makefile-new diff --git a/examples/dalf3/dalf3_hotion.cxx b/examples/dalf3/dalf3_hotion.cxx deleted file mode 100644 index ce56be7f29..0000000000 --- a/examples/dalf3/dalf3_hotion.cxx +++ /dev/null @@ -1,533 +0,0 @@ -/**************************************************************** - * DALF3 model - * - * Four-field model for electron pressure, vorticity, A|| and - * parallel velocity - * - * References: - * - * B.Scott, Plasma Phys. Contr. Fusion 39 (1997) 1635 - * - * B.Scott, "Drift Wave versus Interchange Turbulence in - * Tokamak Geometry: Linear versus Nonlinear - * Mode Structure" - * arXiv:physics/0207126 Feb 2001 - * - * NOTE: The normalisation used here is different to in the above - * papers. See manual in doc/ subdirectory for details - * - ****************************************************************/ - -#include -#include - -#include -#include -#include - -// Constants -const BoutReal MU0 = 4.0e-7*PI; -const BoutReal Charge = 1.60217646e-19; // electron charge e (C) -const BoutReal Mi = 2.0*1.67262158e-27; // Ion mass -const BoutReal Me = 9.1093816e-31; // Electron mass -const BoutReal Me_Mi = Me / Mi; // Electron mass / Ion mass - -// Normalisation factors -BoutReal Tenorm, Nenorm, Bnorm; -BoutReal Cs, rho_s, wci; - -// Poisson brackets: b0 x Grad(f) dot Grad(g) / B = [f, g] -// Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE -BRACKET_METHOD bm; // Bracket method for advection terms - -// Evolving quantities -Field3D Vort, Ajpar, Pe, Vpar; - -Field3D phi, apar, jpar; - -Field2D B0, Pe0, Jpar0, P0; -Vector2D b0xcv; - -Field2D eta; // Collisional damping (resistivity) -BoutReal beta_hat, mu_hat; -BoutReal viscosity_par; - -int phi_flags, apar_flags; -bool ZeroElMass, estatic; -bool curv_kappa; -bool flat_resist; -BoutReal mul_resist; -bool parallel_lc; -bool nonlinear; -bool jpar_noderiv; // Don't take Delp2(apar) to get jpar -bool warm_ion; -bool vpar_advect; // Include Vpar advection terms - -bool filter_z; - -BoutReal viscosity, hyper_viscosity; - -bool smooth_separatrix; -int jpar_boundary; - -FieldGroup comms; - -int physics_init(bool restarting) { - - ///////////////////////////////////////////////////// - // Load data from the grid - - GRID_LOAD(Jpar0); - SAVE_ONCE(Jpar0); - - Field2D Ni0, Te0; - GRID_LOAD2(Ni0, Te0); - Ni0 *= 1e20; // To m^-3 - Pe0 = Charge * Ni0 * Te0; // Electron pressure in Pascals - P0 = 2.*Pe0; - if(!warm_ion) - Pe0 = P0; // No ion pressure - SAVE_ONCE2(Pe0, P0); - - // Load curvature term - b0xcv.covariant = false; // Read contravariant components - mesh->get(b0xcv, "bxcv"); // mixed units x: T y: m^-2 z: m^-2 - - // Metric coefficients - Field2D Rxy, Bpxy, Btxy, hthe; - Field2D I; // Shear factor - - if(mesh->get(Rxy, "Rxy")) { // m - output_error.write("ERROR: Cannot read Rxy from grid\n"); - return 1; - } - if(mesh->get(Bpxy, "Bpxy")) { // T - output_error.write("ERROR: Cannot read Bpxy from grid\n"); - return 1; - } - mesh->get(Btxy, "Btxy"); // T - mesh->get(B0, "Bxy"); // T - mesh->get(hthe, "hthe"); // m - mesh->get(I, "sinty");// m^-2 T^-1 - - ////////////////////////////////////////////////////////////// - // Options - - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("dalf3"); - - OPTION(options, phi_flags, 0); - OPTION(options, apar_flags, 0); - OPTION(options, estatic, false); - OPTION(options, ZeroElMass, false); - OPTION(options, jpar_noderiv, true); - OPTION(options, curv_kappa, false); - OPTION(options, flat_resist, false); - OPTION(options, mul_resist, 1.0); - OPTION(options, viscosity, -1.0); - OPTION(options, hyper_viscosity, -1.0); - OPTION(options, viscosity_par, -1.0); - OPTION(options, smooth_separatrix, false); - OPTION(options, warm_ion, false); - OPTION(options, vpar_advect, false); - OPTION(options, jpar_boundary, 5); - OPTION(options, filter_z, false); - - OPTION(options, parallel_lc, true); - OPTION(options, nonlinear, true); - - int bracket_method; - OPTION(options, bracket_method, 0); - switch(bracket_method) { - case 0: { - bm = BRACKET_STD; - output << "\tBrackets: default differencing\n"; - break; - } - case 1: { - bm = BRACKET_SIMPLE; - output << "\tBrackets: simplified operator\n"; - break; - } - case 2: { - bm = BRACKET_ARAKAWA; - output << "\tBrackets: Arakawa scheme\n"; - break; - } - case 3: { - bm = BRACKET_CTU; - output << "\tBrackets: Corner Transport Upwind method\n"; - break; - } - default: - output << "ERROR: Invalid choice of bracket method. Must be 0 - 3\n"; - return 1; - } - - // SHIFTED RADIAL COORDINATES - - if(mesh->ShiftXderivs) { - if(mesh->IncIntShear) { - // BOUT-06 style, using d/dx = d/dpsi + I * d/dz - mesh->IntShiftTorsion = I; - - }else { - // Dimits style, using local coordinate system - b0xcv.z += I*b0xcv.x; - I = 0.0; // I disappears from metric - } - } - - /////////////////////////////////////////////////// - // Normalisation - - Tenorm = max(Te0, true); - Nenorm = max(Ni0, true); - Bnorm = max(B0, true); - - // Sound speed in m/s - Cs = sqrt(Charge*Tenorm / Mi); - - // drift scale - rho_s = Cs * Mi / (Charge * Bnorm); - - // Ion cyclotron frequency - wci = Charge * Bnorm / Mi; - - beta_hat = 4.e-7*PI * Charge*Tenorm * Nenorm / (Bnorm*Bnorm); - - if(ZeroElMass) { - mu_hat = 0.; - }else - mu_hat = Me / Mi; - - SAVE_ONCE3(Tenorm, Nenorm, Bnorm); - SAVE_ONCE3(Cs, rho_s, wci); - SAVE_ONCE2(beta_hat, mu_hat); - - // Spitzer resistivity - if(flat_resist) { - // eta in Ohm-m. NOTE: ln(Lambda) = 20 - eta = 0.51*1.03e-4*20.*pow(Tenorm, -1.5); - }else { - eta = 0.51*1.03e-4*20.*(Te0^(-1.5)); - } - if(mul_resist < 0.0) - mul_resist = 0.0; - eta *= mul_resist; - - // Plasma quantities - Jpar0 /= Nenorm*Charge*Cs; - Pe0 /= Nenorm*Charge*Tenorm; - - // Coefficients - eta *= Charge * Nenorm / Bnorm; - - viscosity /= wci*SQ(rho_s); - hyper_viscosity /= wci*SQ(SQ(rho_s)); - viscosity_par /= wci*SQ(rho_s); - - b0xcv.x /= Bnorm; - b0xcv.y *= rho_s*rho_s; - b0xcv.z *= rho_s*rho_s; - - // Metrics - Rxy /= rho_s; - hthe /= rho_s; - I *= rho_s*rho_s*Bnorm; - Bpxy /= Bnorm; - Btxy /= Bnorm; - B0 /= Bnorm; - - mesh->dx /= rho_s*rho_s*Bnorm; - - /////////////////////////////////////////////////// - // CALCULATE METRICS - - mesh->g11 = (Rxy*Bpxy)^2; - mesh->g22 = 1.0 / (hthe^2); - mesh->g33 = (I^2)*mesh->g11 + (B0^2)/mesh->g11; - mesh->g12 = 0.0; - mesh->g13 = -I*mesh->g11; - mesh->g23 = -Btxy/(hthe*Bpxy*Rxy); - - mesh->J = hthe / Bpxy; - mesh->Bxy = B0; - - mesh->g_11 = 1.0/mesh->g11 + ((I*Rxy)^2); - mesh->g_22 = (B0*hthe/Bpxy)^2; - mesh->g_33 = Rxy*Rxy; - mesh->g_12 = Btxy*hthe*I*Rxy/Bpxy; - mesh->g_13 = I*Rxy*Rxy; - mesh->g_23 = Btxy*hthe*Rxy/Bpxy; - - mesh->geometry(); // Calculate quantities from metric tensor - - SOLVE_FOR3(Vort, Pe, Vpar); - comms.add(Vort, Pe, Vpar); - if(!(estatic && ZeroElMass)) { - SOLVE_FOR(Ajpar); - // Never differentiate Ajpar -> don't communicate - } - if(estatic) { - comms.add(jpar); - }else { - // Need to communicate apar first then jpar - comms.add(apar); - } - - comms.add(phi); - - phi.setBoundary("phi"); - apar.setBoundary("apar"); - jpar.setBoundary("jpar"); - - SAVE_REPEAT3(jpar, apar, phi); - - return 0; -} - -// Curvature operator -const Field3D Kappa(const Field3D &f) { - if(curv_kappa) { - // Use the b0xcv vector from grid file - return -2.*b0xcv*Grad(f) / B0; - } - - return 2.*bracket(log(B0), f, bm); -} - -const Field3D Grad_parP_LtoC(const Field3D &f) { - Field3D result; - if(parallel_lc) { - result = Grad_par_LtoC(f); - if(nonlinear) - result -= beta_hat * bracket(apar, f, BRACKET_ARAKAWA); - }else { - if(nonlinear) { - result = Grad_parP(apar*beta_hat, f); - }else { - result = Grad_par(f); - } - } - return result; -} - -const Field3D Grad_parP_CtoL(const Field3D &f) { - Field3D result; - if(parallel_lc) { - result = Grad_par_CtoL(f); - if(nonlinear) - result -= beta_hat * bracket(apar, f, BRACKET_ARAKAWA); - }else { - if(nonlinear) { - result = Grad_parP(apar*beta_hat, f); - }else { - result = Grad_par(f); - } - } - return result; -} - -int physics_run(BoutReal time) { - - // Invert vorticity to get electrostatic potential - phi = invert_laplace(Vort*B0, phi_flags); - if(warm_ion) { - phi -= 0.5*Pe / mesh->Bxy; // Pi = Pe - } - - phi.applyBoundary(); - - // Calculate apar and jpar - if(estatic) { - // Electrostatic - apar = 0.; - if(ZeroElMass) { - // Not evolving Ajpar - jpar = Grad_par_CtoL(Pe - phi) / eta; - jpar.applyBoundary(); - }else { - jpar = Ajpar / mu_hat; - } - mesh->communicate(comms); - }else { - // Electromagnetic - if(ZeroElMass) { - // Ignore electron inertia term - apar = Ajpar / beta_hat; - - mesh->communicate(comms); - jpar = -Delp2(apar); - jpar.applyBoundary(); - mesh->communicate(jpar); - }else { - // All terms - solve Helmholtz equation - // ajpar = beta_hat*apar + mu_hat*jpar - Field2D a = beta_hat; - Field2D d = -mu_hat; - apar = invert_laplace(Ajpar, apar_flags, &a, NULL, &d); - apar.applyBoundary(); - - mesh->communicate(comms); - if(jpar_noderiv) { - // Already applied boundaries on Ajpar and apar - jpar = (Ajpar - beta_hat*apar) / mu_hat; - }else { - jpar = -Delp2(apar); - jpar.applyBoundary(); - mesh->communicate(jpar); - } - } - } - - Field3D Pet = Pe0; - if(nonlinear) { - Pet += Pe; - } - - Field3D P = Pe; - if(warm_ion) - P *= 2.; // Ti = Te - - Field3D Ptot = P0; - if(nonlinear) - Ptot += P; - - if(jpar_boundary > 0) { - // Boundary in jpar - if(mesh->firstX()) { - for(int i=jpar_boundary-1;i>=0;i--) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - jpar[i][j][k] = 0.0; //0.5*jpar[i+1][j][k]; - } - } - if(mesh->lastX()) { - for(int i=mesh->LocalNx-jpar_boundary;iLocalNx;i++) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - jpar[i][j][k] = 0.0; //0.5*jpar[i-1][j][k]; - } - } - } - - // Vorticity equation - ddt(Vort) = - B0*B0*Grad_parP_LtoC(jpar/B0) - - B0*Kappa(P) // Total perturbed pressure - ; - - if(nonlinear) { - ddt(Vort) -= bracket(phi, Vort, bm); // ExB advection - - if(vpar_advect) - ddt(Vort) -= Vpar_Grad_par(Vpar, Vort); - } - - if(viscosity > 0.0) { - ddt(Vort) += viscosity * Delp2(Vort); - } - if(hyper_viscosity > 0.0) { - Field3D delp2_vort = Delp2(Vort); - delp2_vort.applyBoundary("neumann"); - mesh->communicate(delp2_vort); - - ddt(Vort) += hyper_viscosity*Delp2(delp2_vort); - } - - if(filter_z) - ddt(Vort) = filter(ddt(Vort), 1); - - // Parallel Ohm's law - if(!(estatic && ZeroElMass)) { - // beta_hat*apar + mu_hat*jpar - ddt(Ajpar) = - Grad_parP_CtoL(Pe - phi) // Electron pressure only - - beta_hat * bracket(apar, Pe0, BRACKET_ARAKAWA) - - eta*jpar - ; - - if(nonlinear) { - ddt(Ajpar) -= mu_hat*bracket(phi, jpar, bm); - } - - if(filter_z) - ddt(Ajpar) = filter(ddt(Ajpar), 1); - } - - // Parallel velocity - ddt(Vpar) = - - Grad_parP_CtoL(P) // Total pressure - + beta_hat * bracket(apar, P0, BRACKET_ARAKAWA) - ; - - if(nonlinear) { - ddt(Vpar) -= bracket(phi, Vpar, bm); - - if(vpar_advect) - ddt(Vpar) -= Vpar_Grad_par(Vpar, Vpar); - } - - if(viscosity_par > 0.) { - ddt(Vpar) += viscosity_par * Grad2_par2(Vpar); - } - - if(filter_z) - ddt(Vpar) = filter(ddt(Vpar), 1); - - // Electron pressure - ddt(Pe) = - - bracket(phi, Pet, bm) - + Pet * ( - Kappa(phi - Pe) - + B0*Grad_parP_LtoC( (jpar - Vpar)/B0 ) - ) - ; - - if(nonlinear) { - if(vpar_advect) - ddt(Vort) -= Vpar_Grad_par(Vpar, Pe); - } - - if(smooth_separatrix) { - // Experimental smoothing across separatrix - ddt(Vort) += mesh->smoothSeparatrix(Vort); - } - - if(filter_z) - ddt(Pe) = filter(ddt(Pe), 1); - - // Boundary in Vpar and vorticity - - if(mesh->firstX()) { - for(int i=3;i>=0;i--) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - ddt(Vpar)[i][j][k] = ddt(Vpar)[i+1][j][k]; - ddt(Vort)[i][j][k] = ddt(Vort)[i+1][j][k]; - } - - // Subtract DC component - for(int i=0;i<10;i++) - for(int j=0;jLocalNy;j++) { - BoutReal avg = 0.; - for(int k=0;kLocalNz;k++) - avg += ddt(Vort)[i][j][k]; - avg /= (BoutReal) mesh->LocalNz; - for(int k=0;kLocalNz;k++) - ddt(Vort)[i][j][k] -= avg; - } - } - if(mesh->lastX()) { - for(int i=mesh->LocalNx-3;iLocalNx;i++) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - ddt(Vpar)[i][j][k] = ddt(Vpar)[i-1][j][k]; - ddt(Vort)[i][j][k] = ddt(Vort)[i-1][j][k]; - } - } - - return 0; -} - diff --git a/examples/reconnect-2field/2field-bc.cxx b/examples/reconnect-2field/2field-bc.cxx deleted file mode 100644 index 633cf1f1bd..0000000000 --- a/examples/reconnect-2field/2field-bc.cxx +++ /dev/null @@ -1,373 +0,0 @@ -/***************************************************************************** - * 2 field (Apar, vorticity) model for benchmarking - * simple slab reconnection model - *****************************************************************************/ - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -// 2D initial profiles -Field2D Jpar0, Te0, Ni0; - -// 3D evolving fields -Field3D Upar, Apar; - -// Derived 3D variables -Field3D Phi, Jpar; - -// External fields -Field3D Apar_ext, Jpar_ext, Phi0_ext, Upar0_ext; - -// Metric coefficients -Field2D Rxy, Bpxy, Btxy, hthe, Bxy; - -// Constants -const BoutReal MU0 = 4.0e-7*PI; -const BoutReal Charge = 1.60217646e-19; // electron charge e (C) -const BoutReal Mi = 2.0*1.67262158e-27; // Ion mass -const BoutReal Me = 9.1093816e-31; // Electron mass -const BoutReal Me_Mi = Me / Mi; // Electron mass / Ion mass - -// normalisation parameters -BoutReal Tenorm, Nenorm, Bnorm; -BoutReal Cs, rho_s, wci, beta_hat; - -BoutReal eta, mu; - -// Poisson brackets: b0 x Grad(f) dot Grad(g) / B = [f, g] -// Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE -BRACKET_METHOD bm; // Bracket method for advection terms - -int phi_flags; // Inversion flags - -bool nonlinear; -bool parallel_lc; -bool include_jpar0; -int jpar_bndry; - -void smooth_bndry(Field3D f, int bndry = 2); -void set_bndry(Field3D f, BoutReal val=0.0, int bndry=2); -int precon(BoutReal t, BoutReal cj, BoutReal delta); // Preconditioner -InvertPar *inv; // Parallel inversion class used in preconditioner - -int physics_init(bool restarting) { - - // Load 2D profiles - GRID_LOAD3(Jpar0, Te0, Ni0); - Ni0 *= 1e20; // To m^-3 - - // Load metrics - GRID_LOAD(Rxy); - GRID_LOAD(Bpxy); - GRID_LOAD(Btxy); - GRID_LOAD(hthe); - mesh->get(mesh->Bxy, "Bxy"); - Bxy=mesh->Bxy; - - // Read some parameters - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("2field"); - - // normalisation values - OPTION(options, nonlinear, false); - OPTION(options, parallel_lc, true); - OPTION(options, include_jpar0, true); - OPTION(options, jpar_bndry, 0); - - OPTION(options, eta, 1e-3); // Normalised resistivity - OPTION(options, mu, 1.e-3); // Normalised vorticity - - OPTION(options, phi_flags, 0); - - int bracket_method; - OPTION(options, bracket_method, 0); - switch(bracket_method) { - case 0: { - bm = BRACKET_STD; - output << "\tBrackets: default differencing\n"; - break; - } - case 1: { - bm = BRACKET_SIMPLE; - output << "\tBrackets: simplified operator\n"; - break; - } - case 2: { - bm = BRACKET_ARAKAWA; - output << "\tBrackets: Arakawa scheme\n"; - break; - } - case 3: { - bm = BRACKET_CTU; - output << "\tBrackets: Corner Transport Upwind method\n"; - break; - } - default: - output << "ERROR: Invalid choice of bracket method. Must be 0 - 3\n"; - return 1; - } - - /////////////////////////////////////////////////// - // Normalisation - - Tenorm = max(Te0, true); - if(Tenorm < 1) - Tenorm = 1000; - Nenorm = max(Ni0, true); - if(Nenorm < 1) - Nenorm = 1.e19; - Bnorm = max(mesh->Bxy, true); - - // Sound speed in m/s - Cs = sqrt(Charge*Tenorm / Mi); - - // drift scale - rho_s = Cs * Mi / (Charge * Bnorm); - - // Ion cyclotron frequency - wci = Charge * Bnorm / Mi; - - beta_hat = MU0 * Charge*Tenorm * Nenorm / (Bnorm*Bnorm); - - output << "\tNormalisations:" << endl; - output << "\tCs = " << Cs << endl; - output << "\trho_s = " << rho_s << endl; - output << "\twci = " << wci << endl; - output << "\tbeta_hat = " << beta_hat << endl; - - SAVE_ONCE3(Tenorm, Nenorm, Bnorm); - SAVE_ONCE4(Cs, rho_s, wci, beta_hat); - - // Normalise geometry - Rxy /= rho_s; - hthe /= rho_s; - mesh->dx /= rho_s*rho_s*Bnorm; - - // Normalise magnetic field - Bpxy /= Bnorm; - Btxy /= Bnorm; - mesh->Bxy /= Bnorm; - Bxy /= Bnorm; - - // Plasma quantities - Jpar0 /= Nenorm*Charge*Cs; - - // CALCULATE METRICS - - mesh->g11 = (Rxy*Bpxy)^2; - mesh->g22 = 1.0 / (hthe^2); - mesh->g33 = (mesh->Bxy^2)/mesh->g11; - mesh->g12 = 0.0; - mesh->g13 = 0.; - mesh->g23 = -Btxy/(hthe*Bpxy*Rxy); - - mesh->J = hthe / Bpxy; - - mesh->g_11 = 1.0/mesh->g11; - mesh->g_22 = (mesh->Bxy*hthe/Bpxy)^2; - mesh->g_33 = Rxy*Rxy; - mesh->g_12 = 0.; - mesh->g_13 = 0.; - mesh->g_23 = Btxy*hthe*Rxy/Bpxy; - - mesh->geometry(); - - // Tell BOUT++ which variables to evolve - SOLVE_FOR2(Upar, Apar); - - // Set boundary conditions - Jpar.setBoundary("Jpar"); - Phi.setBoundary("Phi"); - - // Add any other variables to be dumped to file - SAVE_REPEAT2(Phi, Jpar); - SAVE_ONCE(Jpar0); - - // Generate external fields - Apar_ext=0; - Jpar_ext=0; - initial_profile("Apar_ext", Apar_ext); - Jpar_ext = -Delp2(Apar_ext); - set_bndry(Jpar_ext,0.0,2); - // Use vacuum field if requested - mesh->communicate(Apar_ext,Jpar_ext); - SAVE_ONCE2(Apar_ext,Jpar_ext); - - Phi0_ext=0; - Upar0_ext=0; - initial_profile("Phi0_ext", Phi0_ext); - Upar0_ext = -Delp2(Phi0_ext)/Bxy; - set_bndry(Upar0_ext,0.0,2); - mesh->communicate(Phi0_ext,Upar0_ext); - SAVE_ONCE2(Phi0_ext,Upar0_ext); - - // Give the solver the preconditioner function - solver->setPrecon(precon); - // Initialise parallel inversion class - inv = InvertPar::Create(); - inv->setCoefA(1.0); - Upar.setBoundary("Upar"); - Apar.setBoundary("Apar"); - - return 0; -} - -const Field3D Grad_parP_LtoC(const Field3D &f) { - Field3D result; - if(parallel_lc) { - result = Grad_par_LtoC(f); - if(nonlinear) { - result -= beta_hat * bracket(Apar_ext+Apar, f, BRACKET_ARAKAWA); - }else - result -= beta_hat * bracket(Apar_ext, f, BRACKET_ARAKAWA); - }else { - if(nonlinear) { - result = Grad_parP((Apar+Apar_ext)*beta_hat, f); - }else { - result = Grad_parP(Apar_ext*beta_hat, f); - } - } - return result; -} - -const Field3D Grad_parP_CtoL(const Field3D &f) { - Field3D result; - if(parallel_lc) { - result = Grad_par_CtoL(f); - if(nonlinear) { - result -= beta_hat * bracket(Apar + Apar_ext, f, BRACKET_ARAKAWA); - }else { - result -= beta_hat * bracket(Apar_ext, f, BRACKET_ARAKAWA); - } - }else { - if(nonlinear) { - result = Grad_parP((Apar+Apar_ext)*beta_hat, f); - }else { - result = Grad_parP(Apar_ext*beta_hat, f); - } - } - return result; -} - -int physics_run(BoutReal t) { - // Solve EM fields - - // Upar = (1/B) * Delp2(Phi) - Phi = invert_laplace(Bxy*Upar, phi_flags); - Phi.applyBoundary(); // For target plates only - - mesh->communicate(Upar, Phi, Apar); - - Jpar = -Delp2(Apar+Apar_ext); // Jpar includes external current - Jpar.applyBoundary(); - mesh->communicate(Jpar); - -/// if(jpar_bndry > 0) -/// smooth_bndry(Jpar,jpar_bndry); - - // VORTICITY - ddt(Upar) = SQ(Bxy)*Grad_parP_LtoC(Jpar/Bxy); - - if(include_jpar0) { - ddt(Upar) -= SQ(Bxy)*beta_hat * bracket(Apar+Apar_ext, Jpar0/Bxy, BRACKET_ARAKAWA); - } - - //ExB advection - ddt(Upar) -= bracket(Phi0_ext, Upar, bm); - // ddt(Upar) -= bracket(Phi, Upar0_ext, bm); - if(nonlinear) { - ddt(Upar) -= bracket(Phi, Upar, bm); - } - //Viscosity - if(mu > 0.) - ddt(Upar) += mu*Delp2(Upar); - - // APAR - // ddt(Apar) = -Grad_parP_CtoL(Phi) / beta_hat; - ddt(Apar) = -Grad_parP_CtoL(Phi+Phi0_ext) / beta_hat; - - if(eta > 0.) - ddt(Apar) -= eta*Jpar / beta_hat; - - return 0; -} - -/********************************************************* - * Preconditioner - * - * o System state in variables (as in rhs function) - * o Values to be inverted in time derivatives - * - * o Return values should be in time derivatives - * - *********************************************************/ -int precon(BoutReal t, BoutReal gamma, BoutReal delta) { - mesh->communicate(ddt(Apar)); - Field3D Jp; - - Jp = -Delp2(ddt(Apar)); - mesh->communicate(Jp); - -/// if(jpar_bndry > 0) -/// smooth_bndry(Jp,jpar_bndry); - - Field3D Upar1 = ddt(Upar) + gamma*SQ(Bxy)*Grad_par_LtoC(Jp/Bxy); - - inv->setCoefB(-SQ(gamma*Bxy)/beta_hat); - ddt(Upar) = inv->solve(Upar1); - ddt(Upar).applyBoundary(); - - Field3D Phip = invert_laplace(Bxy*ddt(Upar), phi_flags); - mesh->communicate(Phip); - - ddt(Apar) = ddt(Apar) - (gamma / beta_hat)*Grad_par_CtoL(Phip); - ddt(Apar).applyBoundary(); - - return 0; -} - -void smooth_bndry(Field3D f, int bndry) -{ - if(mesh->firstX()) { - for(int i=bndry;i>=0;i--) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - f[i][j][k] = f[i+1][j][k]; - } - } - if(mesh->lastX()) { - for(int i=mesh->LocalNx-bndry-1;iLocalNx;i++) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - f[i][j][k] = f[i-1][j][k]; - } - } -} - -void set_bndry(Field3D f, BoutReal val, int bndry) -{ - if(mesh->firstX()) { - for(int i=bndry;i>=0;i--) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - f[i][j][k] = val; - } - } - if(mesh->lastX()) { - for(int i=mesh->LocalNx-bndry-1;iLocalNx;i++) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - f[i][j][k] = val; - } - } -} - diff --git a/examples/reconnect-2field/2field-new.cxx b/examples/reconnect-2field/2field-new.cxx deleted file mode 100644 index 6aae522bec..0000000000 --- a/examples/reconnect-2field/2field-new.cxx +++ /dev/null @@ -1,355 +0,0 @@ -/***************************************************************************** - * 2 field (Apar, vorticity) model for benchmarking - * simple slab reconnection model - *****************************************************************************/ - -#include -#include - -#include -#include - -#include -#include -#include - -// 2D initial profiles -Field2D Jpar0, Te0, Ni0; - -// 3D evolving fields -Field3D U, Apar; - -// Derived 3D variables -Field3D phi, jpar; - -// External coil field -Field3D Apar_ext, Jpar_ext, Phi0_ext, Upar0_ext; - -// Metric coefficients -Field2D Rxy, Bpxy, Btxy, hthe, Bxy; - -// Constants -const BoutReal MU0 = 4.0e-7*PI; -const BoutReal Charge = 1.60217646e-19; // electron charge e (C) -const BoutReal Mi = 2.0*1.67262158e-27; // Ion mass -const BoutReal Me = 9.1093816e-31; // Electron mass -const BoutReal Me_Mi = Me / Mi; // Electron mass / Ion mass - -// normalisation parameters -BoutReal Tenorm, Nenorm, Bnorm; -BoutReal Cs, rho_s, wci, beta_hat; - -BoutReal eta, mu_perp, mu_par; -BoutReal eta_hyper_par, eta_hyper_perp; -BoutReal mu_hyper_par, mu_hyper_perp; - -// Poisson brackets: b0 x Grad(f) dot Grad(g) / B = [f, g] -// Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE -BRACKET_METHOD bm; // Bracket method for advection terms - -int phi_flags; // Inversion flags - -bool nonlinear; -bool parallel_lc; -bool include_jpar0; -int jpar_bndry, jpar_ext_bndry; -bool test_advection; -bool include_apar_ext, include_phi0_ext; - -void smooth_bndry(const Field3D &jpar, int jpar_bndry); - -int physics_init(bool restarting) { - - // Load 2D profiles - GRID_LOAD3(Jpar0, Te0, Ni0); - Ni0 *= 1e20; // To m^-3 - - // Load metrics - GRID_LOAD(Rxy); - GRID_LOAD(Bpxy); - GRID_LOAD(Btxy); - GRID_LOAD(hthe); - mesh->get(mesh->Bxy, "Bxy"); - - // Read some parameters - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("2field"); - - // normalisation values - OPTION(options, test_advection, false); - OPTION(options, nonlinear, false); - OPTION(options, parallel_lc, true); - OPTION(options, include_jpar0, true); - OPTION(options, jpar_bndry, 0); - - OPTION(options, eta, 1.e-3); // Normalised resistivity - OPTION(options, mu_perp, 1.e-7); // Normalised viscosity - OPTION(options, mu_par, 1.e-7); // Normalised viscosity - OPTION(options, eta_hyper_perp, 0.e-3); // Normalised resistivity - OPTION(options, eta_hyper_par, 0.e-3); // Normalised resistivity - OPTION(options, mu_hyper_perp, 0.e-3); // Normalised viscosity - OPTION(options, mu_hyper_par, 0.e-3); // Normalised viscosity - - OPTION(options, phi_flags, 0); - - int bracket_method; - OPTION(options, bracket_method, 0); - switch(bracket_method) { - case 0: { - bm = BRACKET_STD; - output << "\tBrackets: default differencing\n"; - break; - } - case 1: { - bm = BRACKET_SIMPLE; - output << "\tBrackets: simplified operator\n"; - break; - } - case 2: { - bm = BRACKET_ARAKAWA; - output << "\tBrackets: Arakawa scheme\n"; - break; - } - case 3: { - bm = BRACKET_CTU; - output << "\tBrackets: Corner Transport Upwind method\n"; - break; - } - default: - output << "ERROR: Invalid choice of bracket method. Must be 0 - 3\n"; - return 1; - } - - /////////////////////////////////////////////////// - // Normalisation - - Tenorm = max(Te0, true); - if(Tenorm < 1) - Tenorm = 1000; - Nenorm = max(Ni0, true); - if(Nenorm < 1) - Nenorm = 1.e19; - Bnorm = max(mesh->Bxy, true); - - // Sound speed in m/s - Cs = sqrt(Charge*Tenorm / Mi); - - // drift scale - rho_s = Cs * Mi / (Charge * Bnorm); - - // Ion cyclotron frequency - wci = Charge * Bnorm / Mi; - - beta_hat = MU0 * Charge*Tenorm * Nenorm / (Bnorm*Bnorm); - - output << "\tNormalisations:" << endl; - output << "\tCs = " << Cs << endl; - output << "\trho_s = " << rho_s << endl; - output << "\twci = " << wci << endl; - output << "\tbeta_hat = " << beta_hat << endl; - - SAVE_ONCE3(Tenorm, Nenorm, Bnorm); - SAVE_ONCE4(Cs, rho_s, wci, beta_hat); - - // Normalise geometry - Rxy /= rho_s; - hthe /= rho_s; - mesh->dx /= rho_s*rho_s*Bnorm; - - // Normalise magnetic field - Bpxy /= Bnorm; - Btxy /= Bnorm; - mesh->Bxy /= Bnorm; - Bxy = mesh->Bxy; - - // Plasma quantities - Jpar0 /= Nenorm*Charge*Cs; - - // CALCULATE METRICS - - mesh->g11 = (Rxy*Bpxy)^2; - mesh->g22 = 1.0 / (hthe^2); - mesh->g33 = Bxy^2/mesh->g11; - mesh->g12 = 0.0; - mesh->g13 = 0.; - mesh->g23 = -Btxy/(hthe*Bpxy*Rxy); - - mesh->J = hthe / Bpxy; - - mesh->g_11 = 1.0/mesh->g11; - mesh->g_22 = (Bxy*hthe/Bpxy)^2; - mesh->g_33 = Rxy*Rxy; - mesh->g_12 = 0.; - mesh->g_13 = 0.; - mesh->g_23 = Btxy*hthe*Rxy/Bpxy; - - mesh->geometry(); - - // Tell BOUT++ which variables to evolve - SOLVE_FOR2(U, Apar); - - // Set boundary conditions - jpar.setBoundary("jpar"); - phi.setBoundary("phi"); - - // Add any other variables to be dumped to file - SAVE_REPEAT2(phi, jpar); - SAVE_ONCE(Jpar0); - - // Generate external field - Options *Apar_ext_options = globalOptions->getSection("Apar_ext"); - OPTION(Apar_ext_options, include_apar_ext, false); - OPTION(Apar_ext_options, jpar_ext_bndry, 0); - - Options *Phi0_ext_options = globalOptions->getSection("Phi0_ext"); - OPTION(Phi0_ext_options, include_phi0_ext, false); - - if(include_apar_ext) { - output << "\tInitializing Apar_ext\n"; - initial_profile("Apar_ext", Apar_ext); - Jpar_ext = - Delp2(Apar_ext); - Jpar_ext.applyBoundary(); - smooth_bndry(Jpar_ext,jpar_ext_bndry); - SAVE_ONCE2(Apar_ext,Jpar_ext); - } - if(include_phi0_ext) { - output << "\tInitializing Phi0_ext\n"; - initial_profile("Phi0_ext", Phi0_ext); - Upar0_ext = Delp2(Phi0_ext)/Bxy; - Upar0_ext.applyBoundary(); - SAVE_ONCE2(Phi0_ext,Upar0_ext); - } - - return 0; -} - -const Field3D Grad_par0_LtoC(const Field3D &f) { - Field3D result; - if(parallel_lc) { - result = Grad_par_LtoC(f); - }else{ - result = Grad_par(f); - } - return result; -} - -const Field3D Grad_par0_CtoL(const Field3D &f) { - Field3D result; - if(parallel_lc) { - result = Grad_par_CtoL(f); - }else{ - result = Grad_par(f); - } - return result; -} - -const Field3D Grad_par1(const Field3D &f) { - Field3D result=0.; - - result -= beta_hat * bracket(Apar, f, BRACKET_ARAKAWA); - if (include_apar_ext) { - result -= beta_hat * bracket(Apar_ext, f, BRACKET_ARAKAWA); - } - return result; -} - -void smooth_bndry(const Field3D &f, int bndry) -{ - // Boundary in jpar - if(mesh->firstX()) { - for(int i=bndry;i>=0;i--) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - f[i][j][k] = f[i+1][j][k]; - } - } - if(mesh->lastX()) { - for(int i=mesh->LocalNx-bndry-1;iLocalNx;i++) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - f[i][j][k] = f[i-1][j][k]; - } - } -} - -int physics_run(BoutReal t) { - // Solve EM fields - - // U = (1/B) * Delp2(phi) - phi = invert_laplace(Bxy*U, phi_flags); - phi.applyBoundary(); // For target plates only - - mesh->communicate(U, phi, Apar); - - jpar = -Delp2(Apar); - jpar.applyBoundary(); - mesh->communicate(jpar); - - if(jpar_bndry > 0) { - smooth_bndry(jpar,jpar_bndry); - } - - // VORTICITY - ddt(U)=0.; - - if(!test_advection){ - ddt(U) += SQ(Bxy)*Grad_par0_LtoC(jpar/Bxy); - if(include_apar_ext) - ddt(U) += SQ(Bxy)*Grad_par0_LtoC(Jpar_ext/Bxy); - } - if(include_jpar0){ - // Grad_par0(Jpar0) should vanish - ddt(U) += SQ(Bxy)*Grad_par1(Jpar0/Bxy); - } - - if(include_phi0_ext) - ddt(U) -= bracket(Phi0_ext, U, bm); - - if(nonlinear) { - ddt(U) -= bracket(phi, U, bm); // ExB advection - ddt(U) -= SQ(Bxy)*Grad_par1(jpar/Bxy); - if(include_apar_ext) - ddt(U) += SQ(Bxy)*Grad_par1(Jpar_ext/Bxy); - } - - if(mu_perp > 0.) - ddt(U) += mu_perp*Delp2(U); - if(mu_par > 0.) - ddt(U) += mu_par*Grad2_par2(U); - if(mu_hyper_perp > 0.) - ddt(U) -= mu_hyper_perp*Delp2(Delp2(U)); - if(mu_hyper_par > 0.) - ddt(U) += mu_hyper_par*Grad2_par2(Grad2_par2(U)); - - // APAR - ddt(Apar)=0.; - - if(!test_advection) - ddt(Apar) -= Grad_par0_CtoL(phi) / beta_hat; - - if (include_phi0_ext) { - ddt(Apar) -= Grad_par0_CtoL(Phi0_ext) / beta_hat; - ddt(Apar) -= Grad_par1(Phi0_ext) / beta_hat; - } - if (nonlinear) { - ddt(Apar) -= Grad_par1(phi) / beta_hat; - } - - if(eta > 0.) { - ddt(Apar) -= eta*jpar / beta_hat; - if (include_apar_ext) - ddt(Apar) -= eta*Jpar_ext / beta_hat; - } - if(eta_hyper_perp > 0.) { - ddt(Apar) += eta_hyper_perp*Delp2(jpar) / beta_hat; - if (include_apar_ext) - ddt(Apar) += eta_hyper_perp*Delp2(Jpar_ext) / beta_hat; - } - if(eta_hyper_par > 0.) { - ddt(Apar) += eta_hyper_par*Grad_par0_LtoC(Bxy*Grad_par0_CtoL(jpar/Bxy)) / beta_hat; - if (include_apar_ext) - ddt(Apar) += eta_hyper_par*Grad_par0_LtoC(Bxy*Grad_par0_CtoL(Jpar_ext/Bxy)) / beta_hat; - } - return 0; -} - diff --git a/examples/reconnect-2field/2field-precon.cxx b/examples/reconnect-2field/2field-precon.cxx deleted file mode 100644 index b1b13c1d2a..0000000000 --- a/examples/reconnect-2field/2field-precon.cxx +++ /dev/null @@ -1,346 +0,0 @@ -/***************************************************************************** - * 2 field (Apar, vorticity) model for benchmarking - * simple slab reconnection model - *****************************************************************************/ - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -// 2D initial profiles -Field2D Jpar0, Te0, Ni0; - -// 3D evolving fields -Field3D Upar, Apar; - -// Derived 3D variables -Field3D Phi, Jpar; - -// External fields -Field3D Apar_ext, Jpar_ext, Phi0_ext, Upar0_ext; - -// Metric coefficients -Field2D Rxy, Bpxy, Btxy, hthe, Bxy; - -// Constants -const BoutReal MU0 = 4.0e-7*PI; -const BoutReal Charge = 1.60217646e-19; // electron charge e (C) -const BoutReal Mi = 2.0*1.67262158e-27; // Ion mass -const BoutReal Me = 9.1093816e-31; // Electron mass -const BoutReal Me_Mi = Me / Mi; // Electron mass / Ion mass - -// normalisation parameters -BoutReal Tenorm, Nenorm, Bnorm; -BoutReal Cs, rho_s, wci, beta_hat; - -BoutReal eta, mu; - -// Poisson brackets: b0 x Grad(f) dot Grad(g) / B = [f, g] -// Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE -BRACKET_METHOD bm; // Bracket method for advection terms - -int phi_flags; // Inversion flags - -bool nonlinear; -bool parallel_lc; -bool include_jpar0; -int jpar_bndry; - -void smooth_bndry(Field3D f, int bndry = 2); -int precon(BoutReal t, BoutReal cj, BoutReal delta); // Preconditioner -InvertPar *inv; // Parallel inversion class used in preconditioner - -int physics_init(bool restarting) { - - // Load 2D profiles - GRID_LOAD3(Jpar0, Te0, Ni0); - Ni0 *= 1e20; // To m^-3 - - // Load metrics - GRID_LOAD(Rxy); - GRID_LOAD(Bpxy); - GRID_LOAD(Btxy); - GRID_LOAD(hthe); - mesh->get(mesh->Bxy, "Bxy"); - Bxy=mesh->Bxy; - - // Read some parameters - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("2field"); - - // normalisation values - OPTION(options, nonlinear, false); - OPTION(options, parallel_lc, true); - OPTION(options, include_jpar0, true); - OPTION(options, jpar_bndry, 0); - - OPTION(options, eta, 1e-3); // Normalised resistivity - OPTION(options, mu, 1.e-3); // Normalised vorticity - - OPTION(options, phi_flags, 0); - - int bracket_method; - OPTION(options, bracket_method, 0); - switch(bracket_method) { - case 0: { - bm = BRACKET_STD; - output << "\tBrackets: default differencing\n"; - break; - } - case 1: { - bm = BRACKET_SIMPLE; - output << "\tBrackets: simplified operator\n"; - break; - } - case 2: { - bm = BRACKET_ARAKAWA; - output << "\tBrackets: Arakawa scheme\n"; - break; - } - case 3: { - bm = BRACKET_CTU; - output << "\tBrackets: Corner Transport Upwind method\n"; - break; - } - default: - output << "ERROR: Invalid choice of bracket method. Must be 0 - 3\n"; - return 1; - } - - /////////////////////////////////////////////////// - // Normalisation - - Tenorm = max(Te0, true); - if(Tenorm < 1) - Tenorm = 1000; - Nenorm = max(Ni0, true); - if(Nenorm < 1) - Nenorm = 1.e19; - Bnorm = max(mesh->Bxy, true); - - // Sound speed in m/s - Cs = sqrt(Charge*Tenorm / Mi); - - // drift scale - rho_s = Cs * Mi / (Charge * Bnorm); - - // Ion cyclotron frequency - wci = Charge * Bnorm / Mi; - - beta_hat = MU0 * Charge*Tenorm * Nenorm / (Bnorm*Bnorm); - - output << "\tNormalisations:" << endl; - output << "\tCs = " << Cs << endl; - output << "\trho_s = " << rho_s << endl; - output << "\twci = " << wci << endl; - output << "\tbeta_hat = " << beta_hat << endl; - - SAVE_ONCE3(Tenorm, Nenorm, Bnorm); - SAVE_ONCE4(Cs, rho_s, wci, beta_hat); - - // Normalise geometry - Rxy /= rho_s; - hthe /= rho_s; - mesh->dx /= rho_s*rho_s*Bnorm; - - // Normalise magnetic field - Bpxy /= Bnorm; - Btxy /= Bnorm; - mesh->Bxy /= Bnorm; - Bxy /= Bnorm; - - // Plasma quantities - Jpar0 /= Nenorm*Charge*Cs; - - // CALCULATE METRICS - - mesh->g11 = (Rxy*Bpxy)^2; - mesh->g22 = 1.0 / (hthe^2); - mesh->g33 = (mesh->Bxy^2)/mesh->g11; - mesh->g12 = 0.0; - mesh->g13 = 0.; - mesh->g23 = -Btxy/(hthe*Bpxy*Rxy); - - mesh->J = hthe / Bpxy; - - mesh->g_11 = 1.0/mesh->g11; - mesh->g_22 = (mesh->Bxy*hthe/Bpxy)^2; - mesh->g_33 = Rxy*Rxy; - mesh->g_12 = 0.; - mesh->g_13 = 0.; - mesh->g_23 = Btxy*hthe*Rxy/Bpxy; - - mesh->geometry(); - - // Tell BOUT++ which variables to evolve - SOLVE_FOR2(Upar, Apar); - - // Set boundary conditions - Jpar.setBoundary("Jpar"); - Phi.setBoundary("Phi"); - - // Add any other variables to be dumped to file - SAVE_REPEAT2(Phi, Jpar); - SAVE_ONCE(Jpar0); - - // Generate external field - - initial_profile("Apar_ext", Apar_ext); - Jpar_ext = -Delp2(Apar_ext); - SAVE_ONCE2(Apar_ext,Jpar_ext); - - initial_profile("Phi0_ext", Phi0_ext); - Upar0_ext = -Delp2(Phi0_ext); - SAVE_ONCE2(Phi0_ext,Upar0_ext); - - // Give the solver the preconditioner function - solver->setPrecon(precon); - // Initialise parallel inversion class - inv = InvertPar::Create(); - inv->setCoefA(1.0); - Upar.setBoundary("Upar"); - Apar.setBoundary("Apar"); - - return 0; -} - -const Field3D Grad_parP_LtoC(const Field3D &f) { - Field3D result; - if(parallel_lc) { - result = Grad_par_LtoC(f); - if(nonlinear) { - result -= beta_hat * bracket(Apar_ext+Apar, f, BRACKET_ARAKAWA); - }else - result -= beta_hat * bracket(Apar_ext, f, BRACKET_ARAKAWA); - }else { - if(nonlinear) { - result = Grad_parP((Apar+Apar_ext)*beta_hat, f); - }else { - result = Grad_parP(Apar_ext*beta_hat, f); - } - } - return result; -} - -const Field3D Grad_parP_CtoL(const Field3D &f) { - Field3D result; - if(parallel_lc) { - result = Grad_par_CtoL(f); - if(nonlinear) { - result -= beta_hat * bracket(Apar + Apar_ext, f, BRACKET_ARAKAWA); - }else { - result -= beta_hat * bracket(Apar_ext, f, BRACKET_ARAKAWA); - } - }else { - if(nonlinear) { - result = Grad_parP((Apar+Apar_ext)*beta_hat, f); - }else { - result = Grad_parP(Apar_ext*beta_hat, f); - } - } - return result; -} - -int physics_run(BoutReal t) { - // Solve EM fields - - // Upar = (1/B) * Delp2(Phi) - Phi = invert_laplace(Bxy*Upar, phi_flags); - Phi.applyBoundary(); // For target plates only - - mesh->communicate(Upar, Phi, Apar); - - Jpar = -Delp2(Apar+Apar_ext); // Jpar includes external current - Jpar.applyBoundary(); - mesh->communicate(Jpar); - -/// if(jpar_bndry > 0) -/// smooth_bndry(Jpar,jpar_bndry); - - // VORTICITY - ddt(Upar) = SQ(Bxy)*Grad_parP_LtoC(Jpar/Bxy); - - if(include_jpar0) { - ddt(Upar) -= SQ(Bxy)*beta_hat * bracket(Apar+Apar_ext, Jpar0/Bxy, BRACKET_ARAKAWA); - } - - //ExB advection - ddt(Upar) -= bracket(Phi0_ext, Upar, bm); - ddt(Upar) -= bracket(Phi, Upar0_ext, bm); - if(nonlinear) { - ddt(Upar) -= bracket(Phi, Upar, bm); - } - //Viscosity - if(mu > 0.) - ddt(Upar) += mu*Delp2(Upar); - - // APAR - - ddt(Apar) = -Grad_parP_CtoL(Phi+Phi0_ext) / beta_hat; - - if(eta > 0.) - ddt(Apar) -= eta*Jpar / beta_hat; - - return 0; -} - -/********************************************************* - * Preconditioner - * - * o System state in variables (as in rhs function) - * o Values to be inverted in time derivatives - * - * o Return values should be in time derivatives - * - *********************************************************/ -int precon(BoutReal t, BoutReal gamma, BoutReal delta) { - mesh->communicate(ddt(Apar)); - Field3D Jp; - - Jp = -Delp2(ddt(Apar)); - mesh->communicate(Jp); - -/// if(jpar_bndry > 0) -/// smooth_bndry(Jp,jpar_bndry); - - Field3D Upar1 = ddt(Upar) + gamma*SQ(Bxy)*Grad_par_LtoC(Jp/Bxy); - - inv->setCoefB(-SQ(gamma*Bxy)/beta_hat); - ddt(Upar) = inv->solve(Upar1); - ddt(Upar).applyBoundary(); - - Field3D Phip = invert_laplace(Bxy*ddt(Upar), phi_flags); - mesh->communicate(Phip); - - ddt(Apar) = ddt(Apar) - (gamma / beta_hat)*Grad_par_CtoL(Phip); - ddt(Apar).applyBoundary(); - - return 0; -} - -void smooth_bndry(Field3D f, int bndry) -{ - if(mesh->firstX()) { - for(int i=bndry;i>=0;i--) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - f[i][j][k] = f[i+1][j][k]; - } - } - if(mesh->lastX()) { - for(int i=mesh->LocalNx-bndry-1;iLocalNx;i++) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) { - f[i][j][k] = f[i-1][j][k]; - } - } -} - diff --git a/examples/reconnect-2field/BOUT-new.inp b/examples/reconnect-2field/BOUT-new.inp deleted file mode 100644 index 2a25c11211..0000000000 --- a/examples/reconnect-2field/BOUT-new.inp +++ /dev/null @@ -1,219 +0,0 @@ -# DALF3 model settings - -################################################## -# Global settings used by the core code - -NOUT = 50 # number of time-steps -TIMESTEP = 1000 # time between outputs -archive = 20 # Archive restart files after this number of outputs -wall_limit = 0.48 # wall time limit (in hours) - -ShiftXderivs = true # use shifted radial derivatives? -TwistShift = true # use twist-shift condition? -ShiftOrder = 0 # interpolation order (1 = nearest neighbour, 0=FFT) -TwistOrder = 0 # order of twist-shift interpolation - -ShiftInitial = true -ballooning = false - -MZ = 17 # number of points in z direction (2^n + 1) -ZPERIOD = 1 # Fraction of a torus to simulate - -MXG = 2 -MYG = 2 - -NXPE = 8 # Number of processor in X - -grid = "slab_68x32.nc" # Grid file - -dump_format = "nc" # Dump file format. "nc" = NetCDF, "pdb" = PDB -restart_format = "nc" # Restart file format - - -StaggerGrids = false # Use staggered grids (EXPERIMENTAL) - -################################################## -# Communications -# Fastest setting depends on machine and MPI -# implementation. Do not affect result. - -[comms] - -async = false # Use asyncronous sends? -pre_post = false # Post receives as early as possible -group_nonblock = false # Use non-blocking group operations? - -################################################## -# Laplacian inversion routines - -[laplace] - -# max_mode = 16 # Maximum N to solve for -all_terms = false -laplace_nonuniform = false -filter = 0.2 # Remove the top 20% of modes (BOUT-06 zwindow=0.4) - -################################################## -# FFTs - -[fft] - -fft_measure = true # If using FFTW, perform tests to determine fastest method - -################################################## -# derivative methods - -[ddx] - -first = C4 # order of first x derivatives (options are 2 or 4) -second = C4 # order of second x derivatives (2 or 4) -upwind = W3 # order of upwinding method (1, 4, 0 = TVD (DO NOT USE), 3 = WENO) - -[ddy] - -first = C4 -second = C4 -upwind = W3 - -[ddz] - -first = C4 # Z derivatives can be done using FFT -second = C4 -upwind = W3 - -################################################## -# Solver settings - -[solver] - -# mudq, mldq, mukeep, mlkeep preconditioner options -ATOL = 1.0e-8 # absolute tolerance -RTOL = 1.0e-5 # relative tolerance - -use_precon = false # Use preconditioner: User-supplied or BBD -use_jacobian = false # Use user-supplied Jacobian - -mxstep = 5000 # Number of internal steps between outputs -adams_moulton = false # Use Adams-Moulton method (default is BDF) -func_iter = false # Functional iteration (default is Newton) - -################################################## - -[2field] - - - -eta = 1.e-3 # Resistivity -mu_perp = -1.e-7 # Viscosity -mu_par = -1.e0 # Viscosity -mu_hyper_par = -1e0 -omegaz = 0. # Rotation frequency in BOUT z direction - -test_advection = true # Test ExB advection (acting on Apar) -nonlinear = false # Include nonlinear terms? -parallel_lc = true # Use quasi-staggered LtoC and CtoL in Y - -## Toroidal filtering -filter_z = false # remove all except one mode -filter_z_mode = 1 # Specify which harmonic to keep (1 = fundamental) - - -bracket_method = 2 # Method to use for [f,g] terms - # 0 = Use default differencing methods - # 1 = Simplified operator - # 2 = Arakawa scheme - # 3 = Corner Transport Upwind (CTU) - - -include_jpar0 = false -jpar_bndry = 0 # 3 is recommended default - # jpar_bndry=0 and jpar_ext_bndry=3 seemed to work best 4/9/12 - - - -# field inversion flags: Add the following -# 0 - Dirichlet -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -# 64 - Set the width of the boundary layer to 1 -# 128 - use 4th order differencing -# 256 - Laplacian = 0 inner boundary -# 512 - Laplacian = 0 outer boundary - -phi_flags = 768 #0 # 1 # 11 #769 - -[All] -scale = 0.0 # default size of initial perturbations - -######## Boundary conditions ######### -# dirichlet - Zero value -# neumann - Zero gradient -# zerolaplace - Laplacian = 0, decaying solution -# constlaplace - Laplacian = const, decaying solution -# -# relax( ) - Make boundary condition relaxing - -bndry_all = neumann - -########### Initial conditions ####### -# 0 - constant -# 1 - Gaussian -# 2 - Sinusoidal -# 3 - Mix of mode numbers (like original BOUT) - -########### Evolving variables ####### - -[Upar] # vorticity - -[Apar] - -#function = (1-4*x*(1-x))*sin(3*y - z) -xs_opt = 1 -ys_opt = 0 -zs_opt = 2 - -xs_s0 = 0.5 -xs_wd = 0.1 - -ys_s0 = 0.5 -ys_wd = 0.1 - -zs_mode = 1 - -scale = 0.0e-4 - -bndry_xin = zerolaplace # Radial BCs specified in inversion -bndry_xout = zerolaplace - -########### Auxilliary variables - -[Phi] - -#function = x * 10. * 6.46246*/1.0 -scale = 0.e-4 - -bndry_xin = zerolaplace # Radial BCs specified in laplace inversion -bndry_xout = zerolaplace # originally set to none - -[Jpar] - -########## External fields - -[Phi0_ext] - -function = x -scale = 0.e2 -include_phi0_ext = false - -[Apar_ext] - -function = (1.-(4.-0.)*x*(1.-x))*sin(3*y - z) -scale = 1.e-4 -include_apar_ext = true -jpar_ext_bndry=3 #presently, jpar_ext =0 on bndry, seems best to smooth? 4/9/12 - diff --git a/examples/reconnect-2field/makefile-new b/examples/reconnect-2field/makefile-new deleted file mode 100644 index 96e07348d9..0000000000 --- a/examples/reconnect-2field/makefile-new +++ /dev/null @@ -1,6 +0,0 @@ - -BOUT_TOP = ../.. - -SOURCEC = 2field-orig.cxx - -include $(BOUT_TOP)/make.config From 7886616a5d12075f18d61bdeafec06782d3cc5f5 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sun, 23 Dec 2018 16:24:52 +0000 Subject: [PATCH 0516/1783] Fix Options::withDefault for string input Using `withDefault("hello")` would set the return type to `const char*` rather than `std::string`. This is now caught using an overloaded function. --- include/options.hxx | 6 ++++++ tests/unit/sys/test_options.cxx | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/include/options.hxx b/include/options.hxx index 5c12acf06e..f52518df05 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -426,6 +426,12 @@ public: return val; } + /// Overloaded version for const char* + /// Note: Different from template since return type is different to input + std::string withDefault(const char* def) { + return withDefault(std::string(def)); + } + /// Get the value of this option. If not found, /// return the default value but do not set template T withDefault(T def) const { diff --git a/tests/unit/sys/test_options.cxx b/tests/unit/sys/test_options.cxx index 8df7d4a522..14661bdd74 100644 --- a/tests/unit/sys/test_options.cxx +++ b/tests/unit/sys/test_options.cxx @@ -437,6 +437,13 @@ TEST_F(OptionsTest, NewDefaultValueInt) { EXPECT_EQ(value, 99); } +TEST_F(OptionsTest, WithDefaultString) { + Options options; + + std::string value = options.withDefault("hello"); + EXPECT_EQ(value, "hello"); +} + TEST_F(OptionsTest, OptionsMacroPointer) { Options options; From c26a09aa0349d4c841523157d307da2b3aa6f718 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 25 Dec 2018 22:45:08 +0000 Subject: [PATCH 0517/1783] Add Options equality, comparison operators Attempts to convert to the same type, then peform comparison. Special treatment needed for `const char*` string literals. --- include/options.hxx | 22 ++++++++++++++- src/sys/options.cxx | 10 +++++++ tests/unit/sys/test_options.cxx | 50 +++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/include/options.hxx b/include/options.hxx index f52518df05..355edb6b6d 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -350,7 +350,7 @@ public: /// int value = option["test"].as(); /// template - T as(Mesh* mesh = nullptr) const { + T as(Mesh* UNUSED(mesh) = nullptr) const { if (!is_value) { throw BoutException("Option %s has no value", full_name.c_str()); } @@ -461,6 +461,26 @@ public: return *parent_instance; } + /// Equality operator + /// Converts to the same type and compares + /// This conversion may fail, throwing std::bad_cast + template + bool operator==(const T& other) const { + return as() == other; + } + + /// Overloaded equality operator for literal strings + bool operator==(const char* other) const; + + /// Comparison operator + template + bool operator<(const T& other) const { + return as() < other; + } + + /// Overloaded comparison operator for literal strings + bool operator<(const char* other) const; + ////////////////////////////////////// // Backward-compatible interface diff --git a/src/sys/options.cxx b/src/sys/options.cxx index cc274d7082..cb92d1cd97 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -311,6 +311,16 @@ template <> Field2D Options::as(Mesh* localmesh) const { full_name.c_str()); } +// Note: This is defined here rather than in the header +// to avoid using as before specialising it. +bool Options::operator==(const char* other) const { + return as() == std::string(other); +} + +bool Options::operator<(const char* other) const { + return as() < std::string(other); +} + void Options::printUnused() const { bool allused = true; // Check if any options are unused diff --git a/tests/unit/sys/test_options.cxx b/tests/unit/sys/test_options.cxx index 14661bdd74..baf95e99a0 100644 --- a/tests/unit/sys/test_options.cxx +++ b/tests/unit/sys/test_options.cxx @@ -665,3 +665,53 @@ TEST_F(OptionsTest, AttributeTimeDimension) { EXPECT_EQ(option.as(), 4); } + +TEST_F(OptionsTest, EqualityBool) { + Options option; + + option = true; + + EXPECT_TRUE(option == true); + EXPECT_FALSE(option == false); + + option.force(false); + + EXPECT_TRUE(option == false); + EXPECT_FALSE(option == true); +} + +TEST_F(OptionsTest, EqualityInt) { + Options option; + + option = 3; + + EXPECT_TRUE(option == 3); + EXPECT_FALSE(option == 4); +} + +TEST_F(OptionsTest, EqualityString) { + Options option; + + option = "hello"; + + EXPECT_TRUE(option == "hello"); + EXPECT_FALSE(option == "goodbye"); +} + +TEST_F(OptionsTest, ComparisonInt) { + Options option; + + option = 3; + + EXPECT_TRUE(option < 4); + EXPECT_FALSE(option < 3); +} + +TEST_F(OptionsTest, ComparisonString) { + Options option; + + option = "bbb"; + + EXPECT_TRUE(option < "ccc"); + EXPECT_FALSE(option < "aaa"); +} From 66852a12b045107e932c990b1da12a4957d2bf1b Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 25 Dec 2018 23:08:21 +0000 Subject: [PATCH 0518/1783] Read and write Options attributes to NetCDF Includes unit tests using std::tmpnam --- src/sys/options/options_netcdf.cxx | 69 +++++++++++++ tests/unit/sys/test_options_netcdf.cxx | 134 +++++++++++++++++++++++++ 2 files changed, 203 insertions(+) create mode 100644 tests/unit/sys/test_options_netcdf.cxx diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index d560f2f582..6d7d1124a7 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -77,6 +77,32 @@ void readGroup(const std::string& filename, NcGroup group, Options& result) { } } } + + // Get variable attributes + for (const auto& attpair : var.getAtts()) { + const auto &att_name = attpair.first; // Attribute name + const auto &att = attpair.second; // NcVarAtt object + + auto att_type = att.getType(); // Type of the attribute + if (att_type == ncInt) { + int value; + att.getValues(&value); + result[var_name].attributes[att_name] = value; + } else if (att_type == ncFloat) { + float value; + att.getValues(&value); + result[var_name].attributes[att_name] = value; + } else if (att_type == ncDouble) { + double value; + att.getValues(&value); + result[var_name].attributes[att_name] = value; + } else if (att_type == ncString) { + std::string value; + att.getValues(value); + result[var_name].attributes[att_name] = value; + } + // Else ignore + } } // Iterate over groups @@ -278,6 +304,40 @@ void NcPutVarCountVisitor::operator()(const Field3D& value) { var.putVar(start, count, &value(0, 0, 0)); } +/// Visit a variant type, and put the data into an attributute +struct NcPutAttVisitor { + NcPutAttVisitor(NcVar& var, std::string name) : var(var), name(name) {} + template + void operator()(const T& UNUSED(value)) { + // Default is to ignore if unhandled + } +private: + NcVar& var; + std::string name; +}; + +template <> +void NcPutAttVisitor::operator()(const bool& value) { + int ival = value ? 1 : 0; + var.putAtt(name, ncInt, ival); +} +template <> +void NcPutAttVisitor::operator()(const int& value) { + var.putAtt(name, ncInt, value); +} +template <> +void NcPutAttVisitor::operator()(const double& value) { + var.putAtt(name, ncDouble, value); +} +template <> +void NcPutAttVisitor::operator()(const float& value) { + var.putAtt(name, ncFloat, value); +} +template <> +void NcPutAttVisitor::operator()(const std::string& value) { + var.putAtt(name, value); +} + void writeGroup(const Options& options, NcGroup group, std::map& time_index) { @@ -403,6 +463,15 @@ void writeGroup(const Options& options, NcGroup group, bout::utils::visit(NcPutVarCountVisitor(var, start_index, count_index), child.value); } + + // Write attributes + for (const auto& it: child.attributes) { + const std::string& att_name = it.first; + const auto& att = it.second; + + bout::utils::visit(NcPutAttVisitor(var, att_name), att); + } + } catch (const std::exception &e) { throw BoutException("Error while writing value '%s' : %s", name.c_str(), e.what()); } diff --git a/tests/unit/sys/test_options_netcdf.cxx b/tests/unit/sys/test_options_netcdf.cxx new file mode 100644 index 0000000000..4d293a0fe8 --- /dev/null +++ b/tests/unit/sys/test_options_netcdf.cxx @@ -0,0 +1,134 @@ +// Test reading and writing to NetCDF + +#ifdef NCDF4 + +#include "gtest/gtest.h" + +#include "bout/mesh.hxx" +#include "field3d.hxx" +#include "test_extras.hxx" +#include "options_netcdf.hxx" + +/// Global mesh +extern Mesh *mesh; + +// Reuse the "standard" fixture for FakeMesh +using OptionsNetCDFTest = FakeMeshFixture; + + + +TEST_F(OptionsNetCDFTest, ReadWriteInt) { + // Temporary file + OptionsNetCDF file(std::tmpnam(nullptr)); + + Options options; + options["test"] = 42; + + // Write the file + file.write(options); + + // Read again + Options data = file.read(); + + EXPECT_EQ(data["test"], 42); +} + +TEST_F(OptionsNetCDFTest, ReadWriteString) { + std::string filename = std::tmpnam(nullptr); + + Options options; + options["test"] = "hello"; + + // Write file + OptionsNetCDF(filename).write(options); + + // Read file + Options data = OptionsNetCDF(filename).read(); + + EXPECT_EQ(data["test"], std::string("hello")); +} + +TEST_F(OptionsNetCDFTest, ReadWriteField2D) { + std::string filename = std::tmpnam(nullptr); + + Options options; + options["test"] = Field2D(1.0); + + // Write file + OptionsNetCDF(filename).write(options); + + // Read file + Options data = OptionsNetCDF(filename).read(); + + Field2D value = data["test"].as(mesh); + + EXPECT_DOUBLE_EQ(value(0,1), 1.0); + EXPECT_DOUBLE_EQ(value(1,0), 1.0); +} + +TEST_F(OptionsNetCDFTest, ReadWriteField3D) { + std::string filename = std::tmpnam(nullptr); + + Options options; + options["test"] = Field3D(2.4); + + // Write file + OptionsNetCDF(filename).write(options); + + // Read file + Options data = OptionsNetCDF(filename).read(); + + Field3D value = data["test"].as(mesh); + + EXPECT_DOUBLE_EQ(value(0,1,0), 2.4); + EXPECT_DOUBLE_EQ(value(1,0,1), 2.4); + EXPECT_DOUBLE_EQ(value(1,1,1), 2.4); +} + +TEST_F(OptionsNetCDFTest, AttributeInt) { + std::string filename = std::tmpnam(nullptr); + + Options options; + options["test"] = 3; + options["test"].attributes["thing"] = 4; + + // Write file + OptionsNetCDF(filename).write(options); + + // Read file + Options data = OptionsNetCDF(filename).read(); + EXPECT_EQ(options["test"].attributes["thing"].as(), 4); +} + +TEST_F(OptionsNetCDFTest, AttributeBoutReal) { + std::string filename = std::tmpnam(nullptr); + + Options options; + options["test"] = 3; + options["test"].attributes["thing"] = 3.14; + + // Write file + OptionsNetCDF(filename).write(options); + + // Read file + Options data = OptionsNetCDF(filename).read(); + EXPECT_DOUBLE_EQ(options["test"].attributes["thing"].as(), 3.14); +} + +TEST_F(OptionsNetCDFTest, AttributeString) { + std::string filename = std::tmpnam(nullptr); + + Options options; + options["test"] = 3; + options["test"].attributes["thing"] = "hello"; + + // Write file + OptionsNetCDF(filename).write(options); + + // Read file + Options data = OptionsNetCDF(filename).read(); + EXPECT_EQ(options["test"].attributes["thing"].as(), "hello"); +} + + +#endif // NCDF4 From ebb2a9f93363f6106bd9502d5aeb3fac19bc1c25 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 26 Dec 2018 17:02:12 +0000 Subject: [PATCH 0519/1783] Add unit test for NetCDF groups Writes then reads a file containing a group --- tests/unit/sys/test_options_netcdf.cxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/unit/sys/test_options_netcdf.cxx b/tests/unit/sys/test_options_netcdf.cxx index 4d293a0fe8..e6503f3b62 100644 --- a/tests/unit/sys/test_options_netcdf.cxx +++ b/tests/unit/sys/test_options_netcdf.cxx @@ -85,6 +85,20 @@ TEST_F(OptionsNetCDFTest, ReadWriteField3D) { EXPECT_DOUBLE_EQ(value(1,1,1), 2.4); } +TEST_F(OptionsNetCDFTest, Groups) { + std::string filename = std::tmpnam(nullptr); + + Options options; + options["test"]["key"] = 42; + + // Write file + OptionsNetCDF(filename).write(options); + + // Read file + Options data = OptionsNetCDF(filename).read(); + EXPECT_EQ(data["test"]["key"], 42); +} + TEST_F(OptionsNetCDFTest, AttributeInt) { std::string filename = std::tmpnam(nullptr); From 9a2a8d40b6138aa69659094b5213326c078db6bb Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 26 Dec 2018 17:16:48 +0000 Subject: [PATCH 0520/1783] Move some Options code out of header Can put some into the .cxx file to (perhaps) slightly improve compilation speed. --- include/options.hxx | 67 +++++--------------------------------------- src/sys/options.cxx | 68 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 60 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index 355edb6b6d..0c692cf634 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -163,18 +163,7 @@ public: : parent_instance(parent_instance), full_name(std::move(full_name)){}; /// Copy constructor - Options(const Options& other) - : value(other.value), attributes(other.attributes), - parent_instance(other.parent_instance), full_name(other.full_name), - is_section(other.is_section), children(other.children), is_value(other.is_value), - value_used(other.value_used) { - - // Ensure that this is the parent of all children, - // otherwise will point to the original Options instance - for (auto &child : children) { - child.second.parent_instance = this; - } - } + Options(const Options& other); /// Get a reference to the only root instance static Options &root(); @@ -278,24 +267,7 @@ public: /// Note that if only the value is desired, then that can be copied using /// the value member directly e.g. option2.value = option1.value; /// - Options& operator=(const Options& other) { - // Note: Here can't do copy-and-swap because pointers to parents are stored - - value = other.value; - attributes = other.attributes; - full_name = other.full_name; - is_section = other.is_section; - children = other.children; - is_value = other.is_value; - value_used = other.value_used; - - // Ensure that this is the parent of all children, - // otherwise will point to the original Options instance - for (auto &child : children) { - child.second.parent_instance = this; - } - return *this; - } + Options& operator=(const Options& other); /// Assign a value to the option. /// This will throw an exception if already has a value @@ -635,36 +607,11 @@ template<> inline void Options::assign<>(std::string val, const std::string sour // Note: const char* version needed to avoid conversion to bool template<> inline void Options::assign<>(const char *val, const std::string source) { _set(std::string(val), source, false);} // Note: Field assignments don't check for previous assignment (always force) -template<> inline void Options::assign<>(Field2D val, const std::string source) { - value = std::move(val); - attributes["source"] = std::move(source); - value_used = false; - is_value = true; -} -template<> inline void Options::assign<>(Field3D val, const std::string source) { - value = std::move(val); - attributes["source"] = std::move(source); - value_used = false; - is_value = true; -} -template<> inline void Options::assign<>(Array val, const std::string source) { - value = std::move(val); - attributes["source"] = std::move(source); - value_used = false; - is_value = true; -} -template<> inline void Options::assign<>(Matrix val, const std::string source) { - value = std::move(val); - attributes["source"] = std::move(source); - value_used = false; - is_value = true; -} -template<> inline void Options::assign<>(Tensor val, const std::string source) { - value = std::move(val); - attributes["source"] = std::move(source); - value_used = false; - is_value = true; -} +template<> void Options::assign<>(Field2D val, const std::string source); +template<> void Options::assign<>(Field3D val, const std::string source); +template<> void Options::assign<>(Array val, const std::string source); +template<> void Options::assign<>(Matrix val, const std::string source); +template<> void Options::assign<>(Tensor val, const std::string source); /// Specialised similar comparison methods template <> inline bool Options::similar(BoutReal a, BoutReal b) const { return fabs(a - b) < 1e-10; } diff --git a/src/sys/options.cxx b/src/sys/options.cxx index cb92d1cd97..2fb44883fb 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -26,6 +26,19 @@ void Options::cleanup() { root_instance = nullptr; } +Options::Options(const Options& other) + : value(other.value), attributes(other.attributes), + parent_instance(other.parent_instance), full_name(other.full_name), + is_section(other.is_section), children(other.children), is_value(other.is_value), + value_used(other.value_used) { + + // Ensure that this is the parent of all children, + // otherwise will point to the original Options instance + for (auto& child : children) { + child.second.parent_instance = this; + } +} + Options &Options::operator[](const std::string &name) { // Mark this object as being a section is_section = true; @@ -73,6 +86,25 @@ const Options &Options::operator[](const std::string &name) const { return it->second; } +Options& Options::operator=(const Options& other) { + // Note: Here can't do copy-and-swap because pointers to parents are stored + + value = other.value; + attributes = other.attributes; + full_name = other.full_name; + is_section = other.is_section; + children = other.children; + is_value = other.is_value; + value_used = other.value_used; + + // Ensure that this is the parent of all children, + // otherwise will point to the original Options instance + for (auto& child : children) { + child.second.parent_instance = this; + } + return *this; +} + bool Options::isSet() const { // Check if no value if (!is_value) { @@ -87,6 +119,42 @@ bool Options::isSet() const { return true; } +template <> +void Options::assign<>(Field2D val, const std::string source) { + value = std::move(val); + attributes["source"] = std::move(source); + value_used = false; + is_value = true; +} +template <> +void Options::assign<>(Field3D val, const std::string source) { + value = std::move(val); + attributes["source"] = std::move(source); + value_used = false; + is_value = true; +} +template <> +void Options::assign<>(Array val, const std::string source) { + value = std::move(val); + attributes["source"] = std::move(source); + value_used = false; + is_value = true; +} +template <> +void Options::assign<>(Matrix val, const std::string source) { + value = std::move(val); + attributes["source"] = std::move(source); + value_used = false; + is_value = true; +} +template <> +void Options::assign<>(Tensor val, const std::string source) { + value = std::move(val); + attributes["source"] = std::move(source); + value_used = false; + is_value = true; +} + template <> std::string Options::as(Mesh* UNUSED(mesh)) const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); From 12f11555b396d1b08a865b301436b77574c04060 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 28 Dec 2018 01:17:59 +0000 Subject: [PATCH 0521/1783] Remove duplicate StaggerGrids from FakeMesh Once set to true, once to false in constructor. --- tests/unit/test_extras.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 5da2dd017a..1dc609a783 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -65,12 +65,12 @@ public: ystart = 1; yend = ny - 2; - StaggerGrids=true; + StaggerGrids=false; + // Unused variables periodicX = false; NXPE = 1; PE_XIND = 0; - StaggerGrids = false; IncIntShear = false; maxregionblocksize = MAXREGIONBLOCKSIZE; From 38af80acb43b4e9ab8c2b91af2def6291f5dee0f Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 28 Dec 2018 01:19:17 +0000 Subject: [PATCH 0522/1783] cell_location attribute written to NetCDF Some fixes and additional tests --- src/sys/options/options_netcdf.cxx | 12 +- tests/unit/sys/test_options_netcdf.cxx | 192 ++++++++++++++++++------- 2 files changed, 155 insertions(+), 49 deletions(-) diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 6d7d1124a7..c1caa3bba4 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -84,6 +84,7 @@ void readGroup(const std::string& filename, NcGroup group, Options& result) { const auto &att = attpair.second; // NcVarAtt object auto att_type = att.getType(); // Type of the attribute + if (att_type == ncInt) { int value; att.getValues(&value); @@ -96,7 +97,7 @@ void readGroup(const std::string& filename, NcGroup group, Options& result) { double value; att.getValues(&value); result[var_name].attributes[att_name] = value; - } else if (att_type == ncString) { + } else if ((att_type == ncString) or (att_type == ncChar)) { std::string value; att.getValues(value); result[var_name].attributes[att_name] = value; @@ -261,15 +262,24 @@ void NcPutVarVisitor::operator()(const std::string& value) { const char* cstr = value.c_str(); var.putVar(&cstr); } + +/// In addition to writing the data, set the "cell_location" attribute template <> void NcPutVarVisitor::operator()(const Field2D& value) { // Pointer to data. Assumed to be contiguous array var.putVar(&value(0, 0)); + // Set cell location attribute + var.putAtt("cell_location", CELL_LOC_STRING(value.getLocation())); } + +/// In addition to writing the data, set the "cell_location" attribute template <> void NcPutVarVisitor::operator()(const Field3D& value) { // Pointer to data. Assumed to be contiguous array var.putVar(&value(0, 0, 0)); + + // Set cell location attribute + var.putAtt("cell_location", CELL_LOC_STRING(value.getLocation())); } /// Visit a variant type, and put the data into a NcVar diff --git a/tests/unit/sys/test_options_netcdf.cxx b/tests/unit/sys/test_options_netcdf.cxx index e6503f3b62..e5c3ce00c0 100644 --- a/tests/unit/sys/test_options_netcdf.cxx +++ b/tests/unit/sys/test_options_netcdf.cxx @@ -20,12 +20,14 @@ using OptionsNetCDFTest = FakeMeshFixture; TEST_F(OptionsNetCDFTest, ReadWriteInt) { // Temporary file OptionsNetCDF file(std::tmpnam(nullptr)); - - Options options; - options["test"] = 42; - // Write the file - file.write(options); + { + Options options; + options["test"] = 42; + + // Write the file + file.write(options); + } // Read again Options data = file.read(); @@ -36,12 +38,14 @@ TEST_F(OptionsNetCDFTest, ReadWriteInt) { TEST_F(OptionsNetCDFTest, ReadWriteString) { std::string filename = std::tmpnam(nullptr); - Options options; - options["test"] = "hello"; - - // Write file - OptionsNetCDF(filename).write(options); + { + Options options; + options["test"] = "hello"; + // Write file + OptionsNetCDF(filename).write(options); + } + // Read file Options data = OptionsNetCDF(filename).read(); @@ -51,12 +55,14 @@ TEST_F(OptionsNetCDFTest, ReadWriteString) { TEST_F(OptionsNetCDFTest, ReadWriteField2D) { std::string filename = std::tmpnam(nullptr); - Options options; - options["test"] = Field2D(1.0); - - // Write file - OptionsNetCDF(filename).write(options); - + { + Options options; + options["test"] = Field2D(1.0); + + // Write file + OptionsNetCDF(filename).write(options); + } + // Read file Options data = OptionsNetCDF(filename).read(); @@ -68,13 +74,15 @@ TEST_F(OptionsNetCDFTest, ReadWriteField2D) { TEST_F(OptionsNetCDFTest, ReadWriteField3D) { std::string filename = std::tmpnam(nullptr); - - Options options; - options["test"] = Field3D(2.4); - - // Write file - OptionsNetCDF(filename).write(options); + { + Options options; + options["test"] = Field3D(2.4); + + // Write file + OptionsNetCDF(filename).write(options); + } + // Read file Options data = OptionsNetCDF(filename).read(); @@ -87,13 +95,15 @@ TEST_F(OptionsNetCDFTest, ReadWriteField3D) { TEST_F(OptionsNetCDFTest, Groups) { std::string filename = std::tmpnam(nullptr); - - Options options; - options["test"]["key"] = 42; - - // Write file - OptionsNetCDF(filename).write(options); + { + Options options; + options["test"]["key"] = 42; + + // Write file + OptionsNetCDF(filename).write(options); + } + // Read file Options data = OptionsNetCDF(filename).read(); EXPECT_EQ(data["test"]["key"], 42); @@ -101,47 +111,133 @@ TEST_F(OptionsNetCDFTest, Groups) { TEST_F(OptionsNetCDFTest, AttributeInt) { std::string filename = std::tmpnam(nullptr); - - Options options; - options["test"] = 3; - options["test"].attributes["thing"] = 4; - // Write file - OptionsNetCDF(filename).write(options); + { + Options options; + options["test"] = 3; + options["test"].attributes["thing"] = 4; + // Write file + OptionsNetCDF(filename).write(options); + } + // Read file Options data = OptionsNetCDF(filename).read(); - EXPECT_EQ(options["test"].attributes["thing"].as(), 4); + EXPECT_EQ(data["test"].attributes["thing"].as(), 4); } TEST_F(OptionsNetCDFTest, AttributeBoutReal) { std::string filename = std::tmpnam(nullptr); + + { + Options options; + options["test"] = 3; + options["test"].attributes["thing"] = 3.14; + + // Write file + OptionsNetCDF(filename).write(options); + } - Options options; - options["test"] = 3; - options["test"].attributes["thing"] = 3.14; + // Read file + Options data = OptionsNetCDF(filename).read(); + EXPECT_DOUBLE_EQ(data["test"].attributes["thing"].as(), 3.14); +} - // Write file - OptionsNetCDF(filename).write(options); +TEST_F(OptionsNetCDFTest, AttributeString) { + std::string filename = std::tmpnam(nullptr); + { + Options options; + options["test"] = 3; + options["test"].attributes["thing"] = "hello"; + + // Write file + OptionsNetCDF(filename).write(options); + } + // Read file Options data = OptionsNetCDF(filename).read(); - EXPECT_DOUBLE_EQ(options["test"].attributes["thing"].as(), 3.14); + EXPECT_EQ(data["test"].attributes["thing"].as(), "hello"); } -TEST_F(OptionsNetCDFTest, AttributeString) { +TEST_F(OptionsNetCDFTest, Field2DWriteCellCentre) { + std::string filename = std::tmpnam(nullptr); + + { + Options options; + options["f2d"] = Field2D(2.0); + + // Write file + OptionsNetCDF(filename).write(options); + } + + // Read file + Options data = OptionsNetCDF(filename).read(); + + EXPECT_EQ(data["f2d"].attributes["cell_location"].as(), CELL_LOC_STRING(CELL_CENTRE)); +} + +TEST_F(OptionsNetCDFTest, Field2DWriteCellYLow) { + std::string filename = std::tmpnam(nullptr); + + // Enable staggered grids + mesh->StaggerGrids = true; + + { + Field2D f(2.0); + f.setLocation(CELL_YLOW); + + Options options; + options["f2d"] = f; + + // Write file + OptionsNetCDF(filename).write(options); + } + + // Read file + Options data = OptionsNetCDF(filename).read(); + + EXPECT_EQ(data["f2d"].attributes["cell_location"].as(), CELL_LOC_STRING(CELL_YLOW)); +} + +TEST_F(OptionsNetCDFTest, Field3DWriteCellCentre) { std::string filename = std::tmpnam(nullptr); + + { + Options options; + options["f3d"] = Field3D(2.0); + + // Write file + OptionsNetCDF(filename).write(options); + } - Options options; - options["test"] = 3; - options["test"].attributes["thing"] = "hello"; + // Read file + Options data = OptionsNetCDF(filename).read(); - // Write file - OptionsNetCDF(filename).write(options); + EXPECT_EQ(data["f3d"].attributes["cell_location"].as(), CELL_LOC_STRING(CELL_CENTRE)); +} + +TEST_F(OptionsNetCDFTest, Field3DWriteCellYLow) { + std::string filename = std::tmpnam(nullptr); + // Enable staggered grids + mesh->StaggerGrids = true; + + { + Field3D f(2.0); + f.setLocation(CELL_YLOW); + + Options options; + options["f3d"] = f; + + // Write file + OptionsNetCDF(filename).write(options); + } + // Read file Options data = OptionsNetCDF(filename).read(); - EXPECT_EQ(options["test"].attributes["thing"].as(), "hello"); + + EXPECT_EQ(data["f3d"].attributes["cell_location"].as(), CELL_LOC_STRING(CELL_YLOW)); } From c9a8bc00651107e8284f375868bc853309946071 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 17:50:55 +0000 Subject: [PATCH 0523/1783] Move global variables into namespace bout::globals --- include/bout/physicsmodel.hxx | 8 ++++ include/bout/solver.hxx | 2 + include/datafile.hxx | 84 +++++++++++++++++------------------ include/globals.hxx | 4 ++ src/physics/physicsmodel.cxx | 2 + 5 files changed, 58 insertions(+), 42 deletions(-) diff --git a/include/bout/physicsmodel.hxx b/include/bout/physicsmodel.hxx index 6e98ecebbf..13db3e8a8c 100644 --- a/include/bout/physicsmodel.hxx +++ b/include/bout/physicsmodel.hxx @@ -43,6 +43,14 @@ class PhysicsModel; #include "solver.hxx" #include "unused.hxx" #include "bout/macro_for_each.hxx" + +#ifndef BOUT_NO_USING_NAMESPACE_BOUTGLOBALS +// Include using statement by default in user code. +// Macro allows us to include physicsmodel.hxx without the using statement in +// library code. +using namespace bout::globals; +#endif // BOUT_NO_USING_NAMESPACE_BOUTGLOBALS + /*! Base class for physics models */ diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 411011f82e..24037e7f1d 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -71,7 +71,9 @@ typedef int (*TimestepMonitorFunc)(Solver *solver, BoutReal simtime, BoutReal la #include "vector2d.hxx" #include "vector3d.hxx" +#define BOUT_NO_USING_NAMESPACE_BOUTGLOBALS #include "physicsmodel.hxx" +#undef BOUT_NO_USING_NAMESPACE_BOUTGLOBALS #include #include diff --git a/include/datafile.hxx b/include/datafile.hxx index ecfd369312..a19246f34d 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -137,63 +137,63 @@ class Datafile { }; /// Write this variable once to the grid file -#define SAVE_ONCE1(var) dump.add(var, #var, 0); +#define SAVE_ONCE1(var) bout::globals::dump.add(var, #var, 0); #define SAVE_ONCE2(var1, var2) { \ - dump.add(var1, #var1, 0); \ - dump.add(var2, #var2, 0);} + bout::globals::dump.add(var1, #var1, 0); \ + bout::globals::dump.add(var2, #var2, 0);} #define SAVE_ONCE3(var1, var2, var3) {\ - dump.add(var1, #var1, 0); \ - dump.add(var2, #var2, 0); \ - dump.add(var3, #var3, 0);} + bout::globals::dump.add(var1, #var1, 0); \ + bout::globals::dump.add(var2, #var2, 0); \ + bout::globals::dump.add(var3, #var3, 0);} #define SAVE_ONCE4(var1, var2, var3, var4) { \ - dump.add(var1, #var1, 0); \ - dump.add(var2, #var2, 0); \ - dump.add(var3, #var3, 0); \ - dump.add(var4, #var4, 0);} + bout::globals::dump.add(var1, #var1, 0); \ + bout::globals::dump.add(var2, #var2, 0); \ + bout::globals::dump.add(var3, #var3, 0); \ + bout::globals::dump.add(var4, #var4, 0);} #define SAVE_ONCE5(var1, var2, var3, var4, var5) {\ - dump.add(var1, #var1, 0); \ - dump.add(var2, #var2, 0); \ - dump.add(var3, #var3, 0); \ - dump.add(var4, #var4, 0); \ - dump.add(var5, #var5, 0);} + bout::globals::dump.add(var1, #var1, 0); \ + bout::globals::dump.add(var2, #var2, 0); \ + bout::globals::dump.add(var3, #var3, 0); \ + bout::globals::dump.add(var4, #var4, 0); \ + bout::globals::dump.add(var5, #var5, 0);} #define SAVE_ONCE6(var1, var2, var3, var4, var5, var6) {\ - dump.add(var1, #var1, 0); \ - dump.add(var2, #var2, 0); \ - dump.add(var3, #var3, 0); \ - dump.add(var4, #var4, 0); \ - dump.add(var5, #var5, 0); \ - dump.add(var6, #var6, 0);} + bout::globals::dump.add(var1, #var1, 0); \ + bout::globals::dump.add(var2, #var2, 0); \ + bout::globals::dump.add(var3, #var3, 0); \ + bout::globals::dump.add(var4, #var4, 0); \ + bout::globals::dump.add(var5, #var5, 0); \ + bout::globals::dump.add(var6, #var6, 0);} #define SAVE_ONCE(...) \ { MACRO_FOR_EACH(SAVE_ONCE1, __VA_ARGS__) } /// Write this variable every timestep -#define SAVE_REPEAT1(var) dump.add(var, #var, 1); +#define SAVE_REPEAT1(var) bout::globals::dump.add(var, #var, 1); #define SAVE_REPEAT2(var1, var2) { \ - dump.add(var1, #var1, 1); \ - dump.add(var2, #var2, 1);} + bout::globals::dump.add(var1, #var1, 1); \ + bout::globals::dump.add(var2, #var2, 1);} #define SAVE_REPEAT3(var1, var2, var3) {\ - dump.add(var1, #var1, 1); \ - dump.add(var2, #var2, 1); \ - dump.add(var3, #var3, 1);} + bout::globals::dump.add(var1, #var1, 1); \ + bout::globals::dump.add(var2, #var2, 1); \ + bout::globals::dump.add(var3, #var3, 1);} #define SAVE_REPEAT4(var1, var2, var3, var4) { \ - dump.add(var1, #var1, 1); \ - dump.add(var2, #var2, 1); \ - dump.add(var3, #var3, 1); \ - dump.add(var4, #var4, 1);} + bout::globals::dump.add(var1, #var1, 1); \ + bout::globals::dump.add(var2, #var2, 1); \ + bout::globals::dump.add(var3, #var3, 1); \ + bout::globals::dump.add(var4, #var4, 1);} #define SAVE_REPEAT5(var1, var2, var3, var4, var5) {\ - dump.add(var1, #var1, 1); \ - dump.add(var2, #var2, 1); \ - dump.add(var3, #var3, 1); \ - dump.add(var4, #var4, 1); \ - dump.add(var5, #var5, 1);} + bout::globals::dump.add(var1, #var1, 1); \ + bout::globals::dump.add(var2, #var2, 1); \ + bout::globals::dump.add(var3, #var3, 1); \ + bout::globals::dump.add(var4, #var4, 1); \ + bout::globals::dump.add(var5, #var5, 1);} #define SAVE_REPEAT6(var1, var2, var3, var4, var5, var6) {\ - dump.add(var1, #var1, 1); \ - dump.add(var2, #var2, 1); \ - dump.add(var3, #var3, 1); \ - dump.add(var4, #var4, 1); \ - dump.add(var5, #var5, 1); \ - dump.add(var6, #var6, 1);} + bout::globals::dump.add(var1, #var1, 1); \ + bout::globals::dump.add(var2, #var2, 1); \ + bout::globals::dump.add(var3, #var3, 1); \ + bout::globals::dump.add(var4, #var4, 1); \ + bout::globals::dump.add(var5, #var5, 1); \ + bout::globals::dump.add(var6, #var6, 1);} #define SAVE_REPEAT(...) \ { MACRO_FOR_EACH(SAVE_REPEAT1, __VA_ARGS__) } diff --git a/include/globals.hxx b/include/globals.hxx index e98fe36345..5763ebe34d 100644 --- a/include/globals.hxx +++ b/include/globals.hxx @@ -31,6 +31,8 @@ #include "datafile.hxx" #include "bout/macro_for_each.hxx" +namespace bout { +namespace globals { #ifndef GLOBALORIGIN #define GLOBAL extern #define SETTING(name, val) extern name @@ -83,5 +85,7 @@ GLOBAL Datafile dump; #undef GLOBAL #undef SETTING +} // namespace globals +} // namespace bout #endif // __GLOBALS_H__ diff --git a/src/physics/physicsmodel.cxx b/src/physics/physicsmodel.cxx index 98c56a329b..cfd9cf1061 100644 --- a/src/physics/physicsmodel.cxx +++ b/src/physics/physicsmodel.cxx @@ -28,7 +28,9 @@ * **************************************************************************/ +#define BOUT_NO_USING_NAMESPACE_BOUTGLOBALS #include +#undef BOUT_NO_USING_NAMESPACE_BOUTGLOBALS PhysicsModel::PhysicsModel() : solver(nullptr), modelMonitor(this), splitop(false), userprecon(nullptr), From ffec7b607cf7e57ba97364ad0be117565d799652 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 18:42:39 +0000 Subject: [PATCH 0524/1783] Add namespaces to extern Mesh* mesh --- include/boundary_region.hxx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/boundary_region.hxx b/include/boundary_region.hxx index cc53f1b54e..09bdc3aa6c 100644 --- a/include/boundary_region.hxx +++ b/include/boundary_region.hxx @@ -8,7 +8,11 @@ class BoundaryRegion; #include class Mesh; -extern Mesh* mesh; +namespace bout { +namespace globals { + extern Mesh* mesh; ///< Global mesh +} // namespace bout +} // namespace globals /// Location of boundary enum BndryLoc {BNDRY_XIN=1, @@ -24,9 +28,9 @@ public: BoundaryRegionBase() = delete; BoundaryRegionBase(std::string name, Mesh *passmesh = nullptr) - : localmesh(passmesh ? passmesh : mesh), label(std::move(name)) {} + : localmesh(passmesh ? passmesh : bout::globals::mesh), label(std::move(name)) {} BoundaryRegionBase(std::string name, BndryLoc loc, Mesh *passmesh = nullptr) - : localmesh(passmesh ? passmesh : mesh), label(std::move(name)), location(loc) {} + : localmesh(passmesh ? passmesh : bout::globals::mesh), label(std::move(name)), location(loc) {} virtual ~BoundaryRegionBase() {} From 759a6239c4c862494fcc30cc9efcfe7680bb644b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 18:43:32 +0000 Subject: [PATCH 0525/1783] Make Solver::outputVars virtual, overload in Power Allows Power solver to add "eigenvalue" to the output as part of outputVars, without needing the global 'dump' Datafile. --- include/bout/solver.hxx | 2 +- src/solver/impls/power/power.cxx | 2 -- src/solver/impls/power/power.hxx | 8 ++++++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 24037e7f1d..5d0108f588 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -292,7 +292,7 @@ class Solver { /// /// @param[inout] outputfile The file to add variable to /// @param[in] save_repeat If true, add variables with time dimension - void outputVars(Datafile &outputfile, bool save_repeat=true); + virtual void outputVars(Datafile &outputfile, bool save_repeat=true); /*! * Create a Solver object. This uses the "type" option diff --git a/src/solver/impls/power/power.cxx b/src/solver/impls/power/power.cxx index 04a1dd3b18..7f2f777899 100644 --- a/src/solver/impls/power/power.cxx +++ b/src/solver/impls/power/power.cxx @@ -37,8 +37,6 @@ int PowerSolver::init(int nout, BoutReal tstep) { // Allocate memory f0 = Array(nlocal); - // Save the eigenvalue to the output - dump.add(eigenvalue, "eigenvalue", true); eigenvalue = 0.0; // Put starting values into f0 diff --git a/src/solver/impls/power/power.hxx b/src/solver/impls/power/power.hxx index a753167820..913bd583f0 100644 --- a/src/solver/impls/power/power.hxx +++ b/src/solver/impls/power/power.hxx @@ -48,6 +48,14 @@ class PowerSolver : public Solver { int init(int nout, BoutReal tstep) override; int run() override; + + void outputVars(Datafile &outputfile, bool save_repeat=true) override { + // Include base class functionality + this->Solver::outputVars(outputfile, save_repeat); + + // Save the eigenvalue to the output + outputfile.add(eigenvalue, "eigenvalue", true); + } private: BoutReal curtime; // Current simulation time (fixed) From de60d012857f41a228361a4cea52cd7a3b059ab3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 18:59:28 +0000 Subject: [PATCH 0526/1783] Remove use of global mesh in Vector3D::operator* --- src/field/vector3d.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/field/vector3d.cxx b/src/field/vector3d.cxx index 1959ce3bbe..80081d1931 100644 --- a/src/field/vector3d.cxx +++ b/src/field/vector3d.cxx @@ -472,7 +472,9 @@ const Vector3D Vector3D::operator/(const Field3D &rhs) const { ////////////////// DOT PRODUCT /////////////////// const Field3D Vector3D::operator*(const Vector3D &rhs) const { - Field3D result(x.getMesh()); + Mesh* mesh = x.getMesh(); + + Field3D result(mesh); ASSERT2(location == rhs.getLocation()) if(rhs.covariant ^ covariant) { From eda81e7691601c18dfdbb35db3c929772aac3c65 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 19:17:59 +0000 Subject: [PATCH 0527/1783] Use local Mesh* in Datafile and DataFormat Reduces dependence on bout::globals::mesh --- include/datafile.hxx | 3 ++- include/dataformat.hxx | 6 ++++++ src/bout++.cxx | 2 +- src/fileio/datafile.cxx | 15 +++++++++------ src/fileio/dataformat.cxx | 3 +++ src/fileio/formatfactory.cxx | 12 +++++++----- src/fileio/formatfactory.hxx | 3 ++- src/fileio/impls/hdf5/h5_format.cxx | 5 +++-- src/fileio/impls/hdf5/h5_format.hxx | 7 ++++--- src/fileio/impls/netcdf/nc_format.cxx | 4 ++-- src/fileio/impls/netcdf/nc_format.hxx | 7 ++++--- src/fileio/impls/netcdf4/ncxx4.cxx | 4 ++-- src/fileio/impls/netcdf4/ncxx4.hxx | 7 ++++--- src/fileio/impls/pnetcdf/pnetcdf.cxx | 4 ++-- src/fileio/impls/pnetcdf/pnetcdf.hxx | 7 ++++--- 15 files changed, 55 insertions(+), 34 deletions(-) diff --git a/include/datafile.hxx b/include/datafile.hxx index a19246f34d..97a5b8c299 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -37,7 +37,7 @@ class Datafile; */ class Datafile { public: - Datafile(Options *opt = nullptr); + Datafile(Options *opt = nullptr, Mesh* mesh_in = nullptr); Datafile(Datafile &&other) noexcept; ~Datafile(); // need to delete filename @@ -78,6 +78,7 @@ class Datafile { void setAttribute(const std::string &varname, const std::string &attrname, BoutReal value); private: + Mesh* mesh; bool parallel; // Use parallel formats? bool flush; // Flush after every write? bool guards; // Write guard cells? diff --git a/include/dataformat.hxx b/include/dataformat.hxx index b2ebd5d468..462bf712c0 100644 --- a/include/dataformat.hxx +++ b/include/dataformat.hxx @@ -40,9 +40,12 @@ class DataFormat; #include #include +class Mesh; + // Can't copy, to control access to file class DataFormat { public: + DataFormat(Mesh* mesh_in = nullptr); virtual ~DataFormat() { } // File opening routines virtual bool openr(const char *name) = 0; @@ -195,6 +198,9 @@ class DataFormat { /// ------- /// value A BoutReal attribute of the variable virtual bool getAttribute(const std::string &varname, const std::string &attrname, BoutReal &value) = 0; + + protected: + Mesh* mesh; }; // For backwards compatability. In formatfactory.cxx diff --git a/src/bout++.cxx b/src/bout++.cxx index 6e4ef0b5cd..ab4ae8cfb3 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -493,7 +493,7 @@ int BoutInitialise(int &argc, char **&argv) { // Set up the "dump" data output file output << "Setting up output (dump) file\n"; - dump = Datafile(options->getSection("output")); + dump = Datafile(options->getSection("output"), mesh); /// Open a file for the output if(append) { diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index ba6b259395..9f57c39944 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -46,10 +46,12 @@ #include #include "formatfactory.hxx" -Datafile::Datafile(Options *opt) : parallel(false), flush(true), guards(true), - floats(false), openclose(true), enabled(true), shiftOutput(false), - shiftInput(false), flushFrequencyCounter(0), flushFrequency(1), - file(nullptr), writable(false), appending(false), first_time(true) +Datafile::Datafile(Options *opt, Mesh* mesh_in) + : mesh(mesh_in==nullptr ? bout::globals::mesh : mesh_in), + parallel(false), flush(true), guards(true), floats(false), openclose(true), + enabled(true), shiftOutput(false), shiftInput(false), + flushFrequencyCounter(0), flushFrequency(1), file(nullptr), writable(false), + appending(false), first_time(true) { filenamelen=FILENAMELEN; filename=new char[filenamelen]; @@ -91,7 +93,7 @@ Datafile::Datafile(Datafile &&other) noexcept } Datafile::Datafile(const Datafile &other) : - parallel(other.parallel), flush(other.flush), guards(other.guards), + mesh(other.mesh), parallel(other.parallel), flush(other.flush), guards(other.guards), floats(other.floats), openclose(other.openclose), Lx(other.Lx), Ly(other.Ly), Lz(other.Lz), enabled(other.enabled), shiftOutput(other.shiftOutput), shiftInput(other.shiftInput), flushFrequencyCounter(other.flushFrequencyCounter), flushFrequency(other.flushFrequency), file(nullptr), writable(other.writable), appending(other.appending), first_time(other.first_time), @@ -106,6 +108,7 @@ Datafile::Datafile(const Datafile &other) : } Datafile& Datafile::operator=(Datafile &&rhs) noexcept { + mesh = rhs.mesh; parallel = rhs.parallel; flush = rhs.flush; guards = rhs.guards; @@ -189,7 +192,7 @@ bool Datafile::openw(const char *format, ...) { bout_vsnprintf(filename, filenamelen, format); // Get the data format - file = FormatFactory::getInstance()->createDataFormat(filename, parallel); + file = FormatFactory::getInstance()->createDataFormat(filename, parallel, mesh); if(!file) throw BoutException("Datafile::open: Factory failed to create a DataFormat!"); diff --git a/src/fileio/dataformat.cxx b/src/fileio/dataformat.cxx index 2fa1d9dd0d..2a9eb6069b 100644 --- a/src/fileio/dataformat.cxx +++ b/src/fileio/dataformat.cxx @@ -3,6 +3,9 @@ #include #include +DataFormat::DataFormat(Mesh* mesh_in) + : mesh(mesh_in==nullptr ? bout::globals::mesh : mesh_in) {} + bool DataFormat::openr(const std::string &name, int mype) { // Split into base name and extension size_t pos = name.find_last_of('.'); diff --git a/src/fileio/formatfactory.cxx b/src/fileio/formatfactory.cxx index 244b4da6e8..2de3ca1661 100644 --- a/src/fileio/formatfactory.cxx +++ b/src/fileio/formatfactory.cxx @@ -25,27 +25,29 @@ FormatFactory* FormatFactory::getInstance() { } // Work out which data format to use for given filename -std::unique_ptr FormatFactory::createDataFormat(const char *filename, bool parallel) { +std::unique_ptr FormatFactory::createDataFormat(const char *filename, + bool parallel, + Mesh* mesh_in) { if ((filename == nullptr) || (strcasecmp(filename, "default") == 0)) { // Return default file format if (parallel) { #ifdef PNCDF - return bout::utils::make_unique(); + return bout::utils::make_unique(mesh_in); #else } #ifdef NCDF4 - return bout::utils::make_unique(); + return bout::utils::make_unique(mesh_in); #else #ifdef NCDF - return bout::utils::make_unique(); + return bout::utils::make_unique(mesh_in); #else #ifdef HDF5 - return bout::utils::make_unique(); + return bout::utils::make_unique(mesh_in); #else #error No file format available; aborting. diff --git a/src/fileio/formatfactory.hxx b/src/fileio/formatfactory.hxx index c6830bb771..361773871c 100644 --- a/src/fileio/formatfactory.hxx +++ b/src/fileio/formatfactory.hxx @@ -14,7 +14,8 @@ public: static FormatFactory* getInstance(); std::unique_ptr createDataFormat(const char *filename = nullptr, - bool parallel = true); + bool parallel = true, + Mesh* mesh_in = nullptr); private: static FormatFactory* instance; ///< The only instance of this class (Singleton) diff --git a/src/fileio/impls/hdf5/h5_format.cxx b/src/fileio/impls/hdf5/h5_format.cxx index f6260982de..fbed69b0dc 100644 --- a/src/fileio/impls/hdf5/h5_format.cxx +++ b/src/fileio/impls/hdf5/h5_format.cxx @@ -34,7 +34,7 @@ #include #include -H5Format::H5Format(bool parallel_in) { +H5Format::H5Format(bool parallel_in, Mesh* mesh_in) : DataFormat(mesh_in) { parallel = parallel_in; x0 = y0 = z0 = t0 = 0; lowPrecision = false; @@ -69,7 +69,8 @@ H5Format::H5Format(bool parallel_in) { throw BoutException("Failed to set error stack to not print errors"); } -H5Format::H5Format(const char *name, bool parallel_in) { +H5Format::H5Format(const char *name, bool parallel_in, Mesh* mesh_in) + : DataFormat(mesh_in) { parallel = parallel_in; x0 = y0 = z0 = t0 = 0; lowPrecision = false; diff --git a/src/fileio/impls/hdf5/h5_format.hxx b/src/fileio/impls/hdf5/h5_format.hxx index 0853f695b6..b319aac461 100644 --- a/src/fileio/impls/hdf5/h5_format.hxx +++ b/src/fileio/impls/hdf5/h5_format.hxx @@ -54,9 +54,10 @@ class H5Format; class H5Format : public DataFormat { public: - H5Format(bool parallel_in = false); - H5Format(const char *name, bool parallel_in = false); - H5Format(const std::string &name, bool parallel_in = false) : H5Format(name.c_str(), parallel_in) {} + H5Format(bool parallel_in = false, Mesh* mesh_in = nullptr); + H5Format(const char *name, bool parallel_in = false, Mesh* mesh_in = nullptr); + H5Format(const std::string &name, bool parallel_in = false, Mesh* mesh_in = nullptr) + : H5Format(name.c_str(), parallel_in, mesh_in) {} ~H5Format(); using DataFormat::openr; diff --git a/src/fileio/impls/netcdf/nc_format.cxx b/src/fileio/impls/netcdf/nc_format.cxx index 9cc38a5d04..e06d564203 100644 --- a/src/fileio/impls/netcdf/nc_format.cxx +++ b/src/fileio/impls/netcdf/nc_format.cxx @@ -37,7 +37,7 @@ using std::vector; // Define this to see loads of info messages //#define NCDF_VERBOSE -NcFormat::NcFormat() { +NcFormat::NcFormat(Mesh* mesh_in) : DataFormat(mesh_in) { dataFile = nullptr; x0 = y0 = z0 = t0 = 0; recDimList = new const NcDim*[4]; @@ -50,7 +50,7 @@ NcFormat::NcFormat() { fname = nullptr; } -NcFormat::NcFormat(const char *name) { +NcFormat::NcFormat(const char *name, Mesh* mesh_in) : DataFormat(mesh_in) { dataFile = nullptr; x0 = y0 = z0 = t0 = 0; recDimList = new const NcDim*[4]; diff --git a/src/fileio/impls/netcdf/nc_format.hxx b/src/fileio/impls/netcdf/nc_format.hxx index 4b65329e21..e1ebfaa964 100644 --- a/src/fileio/impls/netcdf/nc_format.hxx +++ b/src/fileio/impls/netcdf/nc_format.hxx @@ -55,9 +55,10 @@ class NcFormat; class NcFormat : public DataFormat { public: - NcFormat(); - NcFormat(const char *name); - NcFormat(const std::string &name) : NcFormat(name.c_str()) {} + NcFormat(Mesh* mesh_in = nullptr); + NcFormat(const char *name, Mesh* mesh_in = nullptr); + NcFormat(const std::string &name, Mesh* mesh_in = nullptr) + : NcFormat(name.c_str(), mesh_in) {} ~NcFormat(); using DataFormat::openr; diff --git a/src/fileio/impls/netcdf4/ncxx4.cxx b/src/fileio/impls/netcdf4/ncxx4.cxx index c6c084c7ef..8591620496 100644 --- a/src/fileio/impls/netcdf4/ncxx4.cxx +++ b/src/fileio/impls/netcdf4/ncxx4.cxx @@ -38,7 +38,7 @@ using namespace netCDF; // Define this to see loads of info messages //#define NCDF_VERBOSE -Ncxx4::Ncxx4() { +Ncxx4::Ncxx4(Mesh* mesh_in) : DataFormat(mesh_in) { dataFile = nullptr; x0 = y0 = z0 = t0 = 0; recDimList = new const NcDim*[4]; @@ -51,7 +51,7 @@ Ncxx4::Ncxx4() { fname = nullptr; } -Ncxx4::Ncxx4(const char *name) { +Ncxx4::Ncxx4(const char *name, Mesh* mesh_in) : DataFormat(mesh_in) { dataFile = nullptr; x0 = y0 = z0 = t0 = 0; recDimList = new const NcDim*[4]; diff --git a/src/fileio/impls/netcdf4/ncxx4.hxx b/src/fileio/impls/netcdf4/ncxx4.hxx index c0a9bdc6df..497b32df0b 100644 --- a/src/fileio/impls/netcdf4/ncxx4.hxx +++ b/src/fileio/impls/netcdf4/ncxx4.hxx @@ -56,9 +56,10 @@ class Ncxx4; class Ncxx4 : public DataFormat { public: - Ncxx4(); - Ncxx4(const char *name); - Ncxx4(const std::string &name) : Ncxx4(name.c_str()) {} + Ncxx4(Mesh* mesh_in = nullptr); + Ncxx4(const char *name, Mesh* mesh_in = nullptr); + Ncxx4(const std::string &name, Mesh* mesh_in = nullptr) + : Ncxx4(name.c_str(), mesh_in) {} ~Ncxx4(); using DataFormat::openr; diff --git a/src/fileio/impls/pnetcdf/pnetcdf.cxx b/src/fileio/impls/pnetcdf/pnetcdf.cxx index 2ba919bd66..4234de61b4 100644 --- a/src/fileio/impls/pnetcdf/pnetcdf.cxx +++ b/src/fileio/impls/pnetcdf/pnetcdf.cxx @@ -41,7 +41,7 @@ // Define this to see loads of info messages //#define NCDF_VERBOSE -PncFormat::PncFormat() { +PncFormat::PncFormat(Mesh* mesh_in) : DataFormat(mesh_in) { x0 = y0 = z0 = t0 = 0; lowPrecision = false; dimList = recDimList+1; @@ -51,7 +51,7 @@ PncFormat::PncFormat() { fname = nullptr; } -PncFormat::PncFormat(const char *name) { +PncFormat::PncFormat(const char *name, Mesh* mesh_in) : DataFormat(mesh_in) { x0 = y0 = z0 = t0 = 0; lowPrecision = false; dimList = recDimList+1; diff --git a/src/fileio/impls/pnetcdf/pnetcdf.hxx b/src/fileio/impls/pnetcdf/pnetcdf.hxx index 19f23d2917..dd355f22df 100644 --- a/src/fileio/impls/pnetcdf/pnetcdf.hxx +++ b/src/fileio/impls/pnetcdf/pnetcdf.hxx @@ -52,9 +52,10 @@ class PncFormat; class PncFormat : public DataFormat { public: - PncFormat(); - PncFormat(const char *name); - PncFormat(const std::string &name) : PncFormat(name.c_str()) {} + PncFormat(Mesh* mesh_in = nullptr); + PncFormat(const char *name, Mesh* mesh_in = nullptr); + PncFormat(const std::string &name, Mesh* mesh_in = nullptr) + : PncFormat(name.c_str(), mesh_in) {} ~PncFormat(); bool openr(const char *name) override; From 9d056579bac9e7888901c0607c2f62b1d3af2bdb Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 23:33:25 +0000 Subject: [PATCH 0528/1783] Remove uses of global mesh pointer in BoutMesh --- src/mesh/impls/bout/boutmesh.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 0bf59de09a..e53f0d4454 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2208,7 +2208,7 @@ void BoutMesh::addBoundaryRegions() { all_boundaries.emplace_back("RGN_UPPER_Y"); // Inner X - if(mesh->firstX() && !mesh->periodicX) { + if(firstX() && !periodicX) { addRegion3D("RGN_INNER_X", Region(0, xstart-1, ystart, yend, 0, LocalNz-1, LocalNy, LocalNz, maxregionblocksize)); addRegion2D("RGN_INNER_X", Region(0, xstart-1, ystart, yend, 0, 0, @@ -2225,7 +2225,7 @@ void BoutMesh::addBoundaryRegions() { } // Outer X - if(mesh->firstX() && !mesh->periodicX) { + if(firstX() && !periodicX) { addRegion3D("RGN_OUTER_X", Region(xend+1, LocalNx-1, ystart, yend, 0, LocalNz-1, LocalNy, LocalNz, maxregionblocksize)); addRegion2D("RGN_OUTER_X", Region(xend+1, LocalNx-1, ystart, yend, 0, 0, From 41f8795c1873d550c9e7f2cb7ccd892a9af86559 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 23:37:15 +0000 Subject: [PATCH 0529/1783] Remove uses of global mesh pointer in FCITransform/FCIMap --- src/mesh/parallel/fci.cxx | 13 +++++++------ src/mesh/parallel/fci.hxx | 4 +++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index eb62510406..3f5312b83b 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -53,8 +53,9 @@ inline BoutReal sgn(BoutReal val) { return (BoutReal(0) < val) - (val < BoutReal // Calculate all the coefficients needed for the spline interpolation // dir MUST be either +1 or -1 -FCIMap::FCIMap(Mesh &mesh, int dir, bool zperiodic) - : dir(dir), boundary_mask(mesh), corner_boundary_mask(mesh), y_prime(&mesh) { +FCIMap::FCIMap(Mesh &mesh_in, int dir, bool zperiodic) + : mesh(mesh_in), dir(dir), boundary_mask(mesh), corner_boundary_mask(mesh), + y_prime(&mesh) { interp = InterpolationFactory::getInstance()->create(&mesh); interp->setYOffset(dir); @@ -249,10 +250,10 @@ const Field3D FCIMap::integrate(Field3D &f) const { result.allocate(); result.setLocation(f.getLocation()); - int nz = mesh->LocalNz; + int nz = mesh.LocalNz; - for(int x = mesh->xstart; x <= mesh->xend; x++) { - for(int y = mesh->ystart; y <= mesh->yend; y++) { + for(int x = mesh.xstart; x <= mesh.xend; x++) { + for(int y = mesh.ystart; y <= mesh.yend; y++) { int ynext = y+dir; @@ -269,7 +270,7 @@ const Field3D FCIMap::integrate(Field3D &f) const { if (corner_boundary_mask(x, y, z) || corner_boundary_mask(x - 1, y, z) || corner_boundary_mask(x, y, zm) || corner_boundary_mask(x - 1, y, zm) || - (x == mesh->xstart)) { + (x == mesh.xstart)) { // One of the corners leaves the domain. // Use the cell centre value, since boundary conditions are not // currently applied to corners. diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index 293113b91d..d9cfe5af0c 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -40,11 +40,13 @@ class FCIMap { Interpolation *interp; // Cell centre Interpolation *interp_corner; // Cell corner at (x+1, z+1) + Mesh& mesh; + /// Private constructor - must be initialised with mesh FCIMap(); public: /// dir MUST be either +1 or -1 - FCIMap(Mesh& mesh, int dir, bool zperiodic); + FCIMap(Mesh& mesh_in, int dir, bool zperiodic); int dir; /**< Direction of map */ From 38191f6e1c18dcfea0b9df3b3e3f50757def5170 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 23:51:53 +0000 Subject: [PATCH 0530/1783] Replace some more uses of global mesh difops.cxx and interpolation_factory.cxx --- src/mesh/difops.cxx | 2 ++ src/mesh/interpolation/interpolation_factory.cxx | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index c924ae11e0..f9ff129359 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -452,6 +452,7 @@ const Field3D Div_par_LtoC(const Field3D &var) { Field3D result; result.allocate(); + Mesh* mesh = var.getMesh(); Coordinates *metric = var.getCoordinates(CELL_CENTRE); // NOTE: Need to calculate one more point than centred vars @@ -481,6 +482,7 @@ const Field3D Div_par_CtoL(const Field3D &var) { Field3D result; result.allocate(); + Mesh* mesh = var.getMesh(); Coordinates *metric = var.getCoordinates(CELL_CENTRE); // NOTE: Need to calculate one more point than centred vars diff --git a/src/mesh/interpolation/interpolation_factory.cxx b/src/mesh/interpolation/interpolation_factory.cxx index fb57cb1e75..f77d2f2658 100644 --- a/src/mesh/interpolation/interpolation_factory.cxx +++ b/src/mesh/interpolation/interpolation_factory.cxx @@ -47,16 +47,19 @@ Interpolation* InterpolationFactory::create(Options *options, Mesh *mesh) { Interpolation* InterpolationFactory::create(const std::string &name, Options *options, Mesh *localmesh) { // If no options section passed (e.g. for a variable), then use the // "interpolation" section - if (options == nullptr) + if (options == nullptr) { options = Options::getRoot()->getSection("interpolation"); + } // Use the global mesh if none passed - if (localmesh == nullptr) - localmesh = mesh; + if (localmesh == nullptr) { + localmesh = bout::globals::mesh; + } auto interp = findInterpolation(name); - if (interp == nullptr) + if (interp == nullptr) { throw BoutException("Could not find interpolation method '%s'", name.c_str()); + } return interp(localmesh); } From b494e992449c78781d25d11510b11a1b2482c59b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 23:52:13 +0000 Subject: [PATCH 0531/1783] Replace uses of global mesh pointer in boundary_standard.cxx --- src/mesh/boundary_standard.cxx | 83 +++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 5e5c0a1c16..6e9e6a250f 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -29,6 +29,7 @@ void verifyNumPoints(BoundaryRegion *region, int ptsRequired) { int ptsAvailGlobal, ptsAvailLocal, ptsAvail; std::string side, gridType; + Mesh* mesh = region->localmesh; //Initialise var in case of no match and CHECK<=2 ptsAvail = ptsRequired; //Ensures test passes without exception @@ -121,6 +122,8 @@ void BoundaryDirichlet::apply(Field2D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); bndry->first(); // Decide which generator to use @@ -308,6 +311,8 @@ void BoundaryDirichlet::apply(Field3D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); bndry->first(); // Decide which generator to use @@ -545,6 +550,8 @@ void BoundaryDirichlet::apply_ddt(Field2D &f) { } void BoundaryDirichlet::apply_ddt(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -573,6 +580,8 @@ void BoundaryDirichlet_O3::apply(Field2D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); bndry->first(); // Decide which generator to use @@ -758,6 +767,8 @@ void BoundaryDirichlet_O3::apply(Field3D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); bndry->first(); // Decide which generator to use @@ -957,6 +968,8 @@ void BoundaryDirichlet_O3::apply_ddt(Field2D &f) { } void BoundaryDirichlet_O3::apply_ddt(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Field3D *dt = f.timeDeriv(); bndry->first() ; @@ -988,6 +1001,8 @@ void BoundaryDirichlet_O4::apply(Field2D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); bndry->first(); // Decide which generator to use @@ -1185,6 +1200,8 @@ void BoundaryDirichlet_O4::apply(Field3D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); bndry->first(); // Decide which generator to use @@ -1389,6 +1406,8 @@ void BoundaryDirichlet_O4::apply_ddt(Field2D &f) { } void BoundaryDirichlet_O4::apply_ddt(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -1417,6 +1436,8 @@ void BoundaryDirichlet_4thOrder::apply(Field2D &f) { } void BoundaryDirichlet_4thOrder::apply(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); // Set (at 4th order) the value at the mid-point between the guard cell and the grid cell to be val for(bndry->first(); !bndry->isDone(); bndry->next1d()) for(int z=0;zLocalNz;z++) { @@ -1432,6 +1453,8 @@ void BoundaryDirichlet_4thOrder::apply_ddt(Field2D &f) { } void BoundaryDirichlet_4thOrder::apply_ddt(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -1452,6 +1475,8 @@ BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const s } void BoundaryNeumann_NonOrthogonal::apply(Field2D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Coordinates *metric = f.getCoordinates(); // Calculate derivatives for metric use mesh->communicate(f); @@ -1492,6 +1517,8 @@ void BoundaryNeumann_NonOrthogonal::apply(Field2D &f) { } void BoundaryNeumann_NonOrthogonal::apply(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Coordinates *metric = f.getCoordinates(); // Calculate derivatives for metric use mesh->communicate(f); @@ -1557,6 +1584,8 @@ void BoundaryNeumann::apply(Field2D &f,BoutReal t) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Coordinates *metric = f.getCoordinates(); bndry->first(); @@ -1754,6 +1783,8 @@ void BoundaryNeumann::apply(Field3D &f) { void BoundaryNeumann::apply(Field3D &f,BoutReal t) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Coordinates *metric = f.getCoordinates(); bndry->first(); @@ -1957,6 +1988,8 @@ void BoundaryNeumann::apply_ddt(Field2D &f) { } void BoundaryNeumann::apply_ddt(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -1979,6 +2012,8 @@ void BoundaryNeumann_O4::apply(Field2D &f) { } void BoundaryNeumann_O4::apply(Field2D &f,BoutReal t) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); // Set (at 4th order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used @@ -2036,6 +2071,8 @@ void BoundaryNeumann_O4::apply(Field3D &f) { } void BoundaryNeumann_O4::apply(Field3D &f,BoutReal t) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); bndry->first(); // Decide which generator to use @@ -2091,6 +2128,8 @@ void BoundaryNeumann_O4::apply_ddt(Field2D &f) { } void BoundaryNeumann_O4::apply_ddt(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -2121,6 +2160,8 @@ void BoundaryNeumann_4thOrder::apply(Field2D &f) { } void BoundaryNeumann_4thOrder::apply(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Coordinates *metric = f.getCoordinates(); // Set (at 4th order) the gradient at the mid-point between the guard cell and the grid cell to be val // This sets the value of the co-ordinate derivative, i.e. DDX/DDY not Grad_par/Grad_perp.x @@ -2139,6 +2180,8 @@ void BoundaryNeumann_4thOrder::apply_ddt(Field2D &f) { } void BoundaryNeumann_4thOrder::apply_ddt(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -2164,6 +2207,8 @@ void BoundaryNeumannPar::apply(Field2D &f) { } void BoundaryNeumannPar::apply(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Coordinates *metric = f.getCoordinates(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -2219,6 +2264,8 @@ void BoundaryRobin::apply(Field2D &f) { } void BoundaryRobin::apply(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); if(fabs(bval) < 1.e-12) { for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -2242,6 +2289,8 @@ void BoundaryConstGradient::apply(Field2D &f){ } void BoundaryConstGradient::apply(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) f(bndry->x, bndry->y, z) = 2.*f(bndry->x - bndry->bx, bndry->y - bndry->by, z) - f(bndry->x - 2*bndry->bx,bndry->y - 2*bndry->by,z); @@ -2290,6 +2339,8 @@ void BoundaryZeroLaplace::apply(Field2D &f) { } void BoundaryZeroLaplace::apply(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); int ncz = mesh->LocalNz; Coordinates *metric = f.getCoordinates(); @@ -2380,6 +2431,8 @@ void BoundaryZeroLaplace2::apply(Field2D &f) { } void BoundaryZeroLaplace2::apply(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); int ncz = mesh->LocalNz; ASSERT0(ncz % 2 == 0); // Allocation assumes even number @@ -2476,6 +2529,8 @@ void BoundaryConstLaplace::apply(Field3D &f) { throw BoutException("ERROR: Can't apply Zero Laplace condition to non-X boundaries\n"); } + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Coordinates *metric = f.getCoordinates(); int ncz = mesh->LocalNz; @@ -2544,6 +2599,9 @@ void BoundaryDivCurl::apply(Vector2D &UNUSED(f)) { } void BoundaryDivCurl::apply(Vector3D &var) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = var.x.getMesh()); + int jx, jy, jz, jzp, jzm; BoutReal tmp; @@ -2652,6 +2710,8 @@ void BoundaryFree_O2::apply(Field2D &f) { // Set (at 2nd order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); bndry->first(); // Check for staggered grids @@ -2749,9 +2809,10 @@ void BoundaryFree_O2::apply(Field2D &f) { void BoundaryFree_O2::apply(Field3D &f) { // Extrapolate from the last evolved simulation cells into the guard cells at 3rd order. + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); bndry->first(); - // Check for staggered grids CELL_LOC loc = f.getLocation(); @@ -2868,6 +2929,8 @@ void BoundaryFree_O2::apply_ddt(Field2D &f) { } void BoundaryFree_O2::apply_ddt(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -2889,6 +2952,8 @@ BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const std::listlocalmesh; + ASSERT1(mesh = f.getMesh()); bndry->first(); // Check for staggered grids @@ -2987,6 +3052,8 @@ void BoundaryFree_O3::apply(Field2D &f) { void BoundaryFree_O3::apply(Field3D &f) { // Extrapolate from the last evolved simulation cells into the guard cells at 3rd order. + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); bndry->first(); @@ -3114,6 +3181,8 @@ void BoundaryFree_O3::apply_ddt(Field2D &f) { } void BoundaryFree_O3::apply_ddt(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -3165,6 +3234,9 @@ void BoundaryRelax::apply_ddt(Field2D &f) { void BoundaryRelax::apply_ddt(Field3D &f) { TRACE("BoundaryRelax::apply_ddt(Field3D)"); + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); + // Make a copy of f Field3D g = f; // NOTE: This is not very efficient... copying entire field // Apply the boundary to g @@ -3238,6 +3310,9 @@ void BoundaryToFieldAligned::apply(Field2D &f, BoutReal t) { } void BoundaryToFieldAligned::apply(Field3D &f, BoutReal t) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); + //NOTE: This is not very efficient... updating entire field f = mesh->fromFieldAligned(f); @@ -3257,6 +3332,8 @@ void BoundaryToFieldAligned::apply_ddt(Field2D &f) { } void BoundaryToFieldAligned::apply_ddt(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); f = mesh->fromFieldAligned(f); ddt(f) = mesh->fromFieldAligned(ddt(f)); op->apply_ddt(f); @@ -3281,6 +3358,8 @@ void BoundaryFromFieldAligned::apply(Field2D &f, BoutReal t) { } void BoundaryFromFieldAligned::apply(Field3D &f, BoutReal t) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); //NOTE: This is not very efficient... shifting entire field f = mesh->toFieldAligned(f); @@ -3300,6 +3379,8 @@ void BoundaryFromFieldAligned::apply_ddt(Field2D &f) { } void BoundaryFromFieldAligned::apply_ddt(Field3D &f) { + Mesh* mesh = bndry->localmesh; + ASSERT1(mesh = f.getMesh()); f = mesh->toFieldAligned(f); ddt(f) = mesh->toFieldAligned(ddt(f)); op->apply_ddt(f); From b150d10b554a793714c86cb891f419a720d278ea Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 00:04:21 +0000 Subject: [PATCH 0532/1783] Remove uses of global mesh pointer in FV operations --- include/bout/fv_ops.hxx | 7 +++++++ src/mesh/fv_ops.cxx | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index f1bbf8bd6e..797506c20d 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -182,6 +182,10 @@ namespace FV { ASSERT2(f_in.getLocation() == v_in.getLocation()); + Mesh* mesh = f_in.getMesh(); + ASSERT1(mesh == v_in.getMesh()); + ASSERT1(mesh == wave_speed.getMesh()); + CellEdges cellboundary; Field3D f = mesh->toFieldAligned(f_in); @@ -341,6 +345,9 @@ namespace FV { const Field3D Div_f_v(const Field3D &n_in, const Vector3D &v, bool bndry_flux) { ASSERT2(n_in.getLocation() == v.getLocation()); + Mesh* mesh = n_in.getMesh(); + ASSERT1(mesh == v.x.getMesh()); + CellEdges cellboundary; Coordinates *coord = n_in.getCoordinates(); diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index d67fe767a6..f65b93911b 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -180,6 +180,9 @@ namespace FV { const Field3D D4DY4(const Field3D &d_in, const Field3D &f_in) { ASSERT2(d_in.getLocation() == f_in.getLocation()); + Mesh* mesh = d_in.getMesh(); + ASSERT1(mesh = f_in.getMesh()); + Field3D result = 0.0; result.setLocation(f_in.getLocation()); @@ -233,6 +236,8 @@ namespace FV { Field3D result = 0.0; result.setLocation(f_in.getLocation()); + Mesh* mesh = f_in.getMesh(); + // Convert to field aligned coordinates Field3D f = mesh->toFieldAligned(f_in); @@ -339,6 +344,7 @@ namespace FV { } void communicateFluxes(Field3D &f) { + Mesh* mesh = f.getMesh(); // Use X=0 as temporary buffer if (mesh->xstart != 2) From 057ddf7c7381fcee30f2469c9ba7393140c7f0ce Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 00:06:46 +0000 Subject: [PATCH 0533/1783] Remove uses of global mesh pointer in ParallelBoundaryOp --- src/mesh/parallel_boundary_op.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mesh/parallel_boundary_op.cxx b/src/mesh/parallel_boundary_op.cxx index 1fdd82bcaa..1b13325682 100644 --- a/src/mesh/parallel_boundary_op.cxx +++ b/src/mesh/parallel_boundary_op.cxx @@ -7,6 +7,8 @@ BoutReal BoundaryOpPar::getValue(int x, int y, int z, BoutReal t) { + Mesh* mesh = bndry->localmesh; + BoutReal xnorm; BoutReal ynorm; BoutReal znorm; @@ -35,6 +37,8 @@ BoutReal BoundaryOpPar::getValue(int x, int y, int z, BoutReal t) { BoutReal BoundaryOpPar::getValue(const BoundaryRegionPar &bndry, BoutReal t) { + Mesh* mesh = bndry.localmesh; + BoutReal xnorm; BoutReal ynorm; BoutReal znorm; From 17057e7aa1479094d71621fa607abf18c6489bd7 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 00:09:43 +0000 Subject: [PATCH 0534/1783] Remove reference to global mesh in smoothing.cxx --- src/physics/smoothing.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/physics/smoothing.cxx b/src/physics/smoothing.cxx index 4a3bc507b4..ee8888282b 100644 --- a/src/physics/smoothing.cxx +++ b/src/physics/smoothing.cxx @@ -461,6 +461,6 @@ const Field3D nl_filter(const Field3D &f, BoutReal w) { /// Perform filtering in Z, Y then X Field3D result = nl_filter_x(nl_filter_y(nl_filter_z(f, w), w), w); /// Communicate boundaries - mesh->communicate(result); + f.getMesh()->communicate(result); return result; } From 7f5255fd86a00bebaa918cd7ca0da1631aa24c95 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 10:20:12 +0000 Subject: [PATCH 0535/1783] Remove uses of global mesh in sourcex.cxx --- src/physics/sourcex.cxx | 67 +++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/src/physics/sourcex.cxx b/src/physics/sourcex.cxx index 4094251960..21bc195486 100644 --- a/src/physics/sourcex.cxx +++ b/src/physics/sourcex.cxx @@ -16,57 +16,63 @@ BoutReal TanH(BoutReal a) { } // create radial buffer zones to set jpar zero near radial boundaries -const Field2D source_tanhx(const Field2D &UNUSED(f), BoutReal swidth, BoutReal slength) { - Field2D result; +const Field2D source_tanhx(const Field2D &f, BoutReal swidth, BoutReal slength) { + Mesh* localmesh = f.getMesh(); + + Field2D result(localmesh); result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary BOUT_FOR(i, result.getRegion("RGN_ALL")) { - BoutReal lx = mesh->GlobalX(i.x()) - slength; + BoutReal lx = localmesh->GlobalX(i.x()) - slength; BoutReal dampl = TanH(lx / swidth); result[i] = 0.5 * (1.0 - dampl); } // Need to communicate boundaries - mesh->communicate(result); + localmesh->communicate(result); return result; } // create radial buffer zones to set jpar zero near radial boundaries -const Field2D source_expx2(const Field2D &UNUSED(f), BoutReal swidth, BoutReal slength) { - Field2D result; +const Field2D source_expx2(const Field2D &f, BoutReal swidth, BoutReal slength) { + Mesh* localmesh = f.getMesh(); + + Field2D result(localmesh); result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary BOUT_FOR(i, result.getRegion("RGN_ALL")) { - BoutReal lx = mesh->GlobalX(i.x()) - slength; + BoutReal lx = localmesh->GlobalX(i.x()) - slength; BoutReal dampl = exp(-lx * lx / swidth / swidth); result[i] = dampl; } // Need to communicate boundaries - mesh->communicate(result); + localmesh->communicate(result); return result; } // create radial buffer zones to set jpar zero near radial boundaries -const Field3D sink_tanhx(const Field2D &UNUSED(f0), const Field3D &f, BoutReal swidth, +const Field3D sink_tanhx(const Field2D &f0, const Field3D &f, BoutReal swidth, BoutReal slength, bool UNUSED(BoutRealspace)) { - Field3D result; + Mesh* localmesh = f0.getMesh(); + + Field3D result(localmesh); result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary BOUT_FOR(i, result.getRegion("RGN_ALL")) { - BoutReal rlx = 1. - mesh->GlobalX(i.x()) - slength; + BoutReal rlx = 1. - localmesh->GlobalX(i.x()) - slength; BoutReal dampr = TanH(rlx / swidth); result[i] = 0.5 * (1.0 - dampr) * f[i]; } // Need to communicate boundaries - mesh->communicate(result); + localmesh->communicate(result); return result; } @@ -75,12 +81,14 @@ const Field3D sink_tanhx(const Field2D &UNUSED(f0), const Field3D &f, BoutReal s const Field3D mask_x(const Field3D &f, bool UNUSED(BoutRealspace)) { TRACE("mask_x"); - Field3D result; + Mesh* localmesh = f.getMesh(); + + Field3D result(localmesh); result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary BOUT_FOR(i, result.getRegion("RGN_ALL")) { - BoutReal lx = mesh->GlobalX(i.x()); + BoutReal lx = localmesh->GlobalX(i.x()); BoutReal dampl = TanH(lx / 40.0); BoutReal dampr = TanH((1. - lx) / 40.0); @@ -88,49 +96,54 @@ const Field3D mask_x(const Field3D &f, bool UNUSED(BoutRealspace)) { } // Need to communicate boundaries - mesh->communicate(result); + localmesh->communicate(result); return result; } // create radial buffer zones to set jpar zero near radial boundaries -const Field3D sink_tanhxl(const Field2D &UNUSED(f0), const Field3D &f, BoutReal swidth, +const Field3D sink_tanhxl(const Field2D &f0, const Field3D &f, BoutReal swidth, BoutReal slength, bool UNUSED(BoutRealspace)) { TRACE("sink_tanhx"); - Field3D result; + Mesh* localmesh = f0.getMesh(); + + Field3D result(localmesh); result.allocate(); BOUT_FOR(i, result.getRegion("RGN_ALL")) { - BoutReal lx = mesh->GlobalX(i.x()) - slength; + BoutReal lx = localmesh->GlobalX(i.x()) - slength; BoutReal dampl = TanH(lx / swidth); result[i] = 0.5 * (1.0 - dampl) * f[i]; } // Need to communicate boundaries - mesh->communicate(result); + localmesh->communicate(result); return result; } // create radial buffer zones to set jpar zero near radial boundaries -const Field3D sink_tanhxr(const Field2D &UNUSED(f0), const Field3D &f, BoutReal swidth, +const Field3D sink_tanhxr(const Field2D &f0, const Field3D &f, BoutReal swidth, BoutReal slength, bool UNUSED(BoutRealspace)) { TRACE("sink_tanhxr"); - Field3D result; + + Mesh* localmesh = f0.getMesh(); + + Field3D result(localmesh); result.allocate(); BOUT_FOR(i, result.getRegion("RGN_ALL")) { - BoutReal rlx = 1. - mesh->GlobalX(i.x()) - slength; + BoutReal rlx = 1. - localmesh->GlobalX(i.x()) - slength; BoutReal dampr = TanH(rlx / swidth); result[i] = 0.5 * (1.0 - dampr) * f[i]; } // Need to communicate boundaries - mesh->communicate(result); + localmesh->communicate(result); return result; } @@ -139,7 +152,9 @@ const Field3D sink_tanhxr(const Field2D &UNUSED(f0), const Field3D &f, BoutReal const Field3D buff_x(const Field3D &f, bool UNUSED(BoutRealspace)) { TRACE("buff_x"); - Field3D result; + Mesh* localmesh = f.getMesh(); + + Field3D result(localmesh); result.allocate(); const BoutReal dampl = 1.e0; @@ -148,7 +163,7 @@ const Field3D buff_x(const Field3D &f, bool UNUSED(BoutRealspace)) { const BoutReal deltar = 0.05; BOUT_FOR(i, result.getRegion("RGN_ALL")) { - BoutReal lx = mesh->GlobalX(i.x()); + BoutReal lx = localmesh->GlobalX(i.x()); BoutReal rlx = 1. - lx; result[i] = (dampl * exp(-(lx * lx) / (deltal * deltal)) + @@ -157,7 +172,7 @@ const Field3D buff_x(const Field3D &f, bool UNUSED(BoutRealspace)) { } // Need to communicate boundaries - mesh->communicate(result); + localmesh->communicate(result); return result; } From fb2238237978f59c94f66c7b61a2987dd9e1839b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 10:21:44 +0000 Subject: [PATCH 0536/1783] Replace uses of global mesh in gyro_average.cxx --- src/physics/gyro_average.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/physics/gyro_average.cxx b/src/physics/gyro_average.cxx index e67f11663a..a71fa23751 100644 --- a/src/physics/gyro_average.cxx +++ b/src/physics/gyro_average.cxx @@ -89,7 +89,7 @@ const Field2D gyroPade1(const Field2D &f, const Field2D &rho, int flags) { const Field3D gyroPade2(const Field3D &f, BoutReal rho, int flags) { Field3D result = gyroPade1(gyroPade1(f, rho, flags), rho, flags); - mesh->communicate(result); + result.getMesh()->communicate(result); result = 0.5*rho*rho*Delp2( result ); result.applyBoundary("dirichlet"); return result; @@ -97,7 +97,7 @@ const Field3D gyroPade2(const Field3D &f, BoutReal rho, int flags) { const Field3D gyroPade2(const Field3D &f, const Field2D &rho, int flags) { Field3D result = gyroPade1(gyroPade1(f, rho, flags), rho, flags); - mesh->communicate(result); + result.getMesh()->communicate(result); result = 0.5*rho*rho*Delp2( result ); result.applyBoundary("dirichlet"); return result; From ad932aaa47f29339254b28c176b05f769b75c5de Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 16:41:18 +0000 Subject: [PATCH 0537/1783] Initialize result with the mesh of the input field --- src/mesh/difops.cxx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index f9ff129359..b76f892e22 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -449,10 +449,11 @@ const Field2D Div_par_LtoC(const Field2D &var) { } const Field3D Div_par_LtoC(const Field3D &var) { - Field3D result; + Mesh* mesh = var.getMesh(); + + Field3D result(mesh); result.allocate(); - Mesh* mesh = var.getMesh(); Coordinates *metric = var.getCoordinates(CELL_CENTRE); // NOTE: Need to calculate one more point than centred vars @@ -479,10 +480,11 @@ const Field2D Div_par_CtoL(const Field2D &var) { } const Field3D Div_par_CtoL(const Field3D &var) { - Field3D result; + Mesh* mesh = var.getMesh(); + + Field3D result(mesh); result.allocate(); - Mesh* mesh = var.getMesh(); Coordinates *metric = var.getCoordinates(CELL_CENTRE); // NOTE: Need to calculate one more point than centred vars From 1d6570dd295b71a00648ec35a402ff1aa106bc23 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 16:52:37 +0000 Subject: [PATCH 0538/1783] Get mesh from already-used argument, restore UNUSED where possible --- src/physics/sourcex.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/physics/sourcex.cxx b/src/physics/sourcex.cxx index 21bc195486..284bb0cb2b 100644 --- a/src/physics/sourcex.cxx +++ b/src/physics/sourcex.cxx @@ -57,9 +57,9 @@ const Field2D source_expx2(const Field2D &f, BoutReal swidth, BoutReal slength) } // create radial buffer zones to set jpar zero near radial boundaries -const Field3D sink_tanhx(const Field2D &f0, const Field3D &f, BoutReal swidth, +const Field3D sink_tanhx(const Field2D &UNUSED(f0), const Field3D &f, BoutReal swidth, BoutReal slength, bool UNUSED(BoutRealspace)) { - Mesh* localmesh = f0.getMesh(); + Mesh* localmesh = f.getMesh(); Field3D result(localmesh); result.allocate(); @@ -102,11 +102,11 @@ const Field3D mask_x(const Field3D &f, bool UNUSED(BoutRealspace)) { } // create radial buffer zones to set jpar zero near radial boundaries -const Field3D sink_tanhxl(const Field2D &f0, const Field3D &f, BoutReal swidth, +const Field3D sink_tanhxl(const Field2D &UNUSED(f0), const Field3D &f, BoutReal swidth, BoutReal slength, bool UNUSED(BoutRealspace)) { TRACE("sink_tanhx"); - Mesh* localmesh = f0.getMesh(); + Mesh* localmesh = f.getMesh(); Field3D result(localmesh); @@ -126,11 +126,11 @@ const Field3D sink_tanhxl(const Field2D &f0, const Field3D &f, BoutReal swidth, } // create radial buffer zones to set jpar zero near radial boundaries -const Field3D sink_tanhxr(const Field2D &f0, const Field3D &f, BoutReal swidth, +const Field3D sink_tanhxr(const Field2D &UNUSED(f0), const Field3D &f, BoutReal swidth, BoutReal slength, bool UNUSED(BoutRealspace)) { TRACE("sink_tanhxr"); - Mesh* localmesh = f0.getMesh(); + Mesh* localmesh = f.getMesh(); Field3D result(localmesh); result.allocate(); From 6ce32e66e4dce86f82af12a90c22fd4a16af73ca Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 18:58:26 +0000 Subject: [PATCH 0539/1783] Use bout::globals in bout++.cxx --- src/bout++.cxx | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index ab4ae8cfb3..8dfd6c75f1 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -475,9 +475,9 @@ int BoutInitialise(int &argc, char **&argv) { try { ///////////////////////////////////////////// - mesh = Mesh::create(); ///< Create the mesh - mesh->load(); ///< Load from sources. Required for Field initialisation - mesh->setParallelTransform(); ///< Set the parallel transform from options + bout::globals::mesh = Mesh::create(); ///< Create the mesh + bout::globals::mesh->load(); ///< Load from sources. Required for Field initialisation + bout::globals::mesh->setParallelTransform(); ///< Set the parallel transform from options ///////////////////////////////////////////// /// Get some settings @@ -493,23 +493,23 @@ int BoutInitialise(int &argc, char **&argv) { // Set up the "dump" data output file output << "Setting up output (dump) file\n"; - dump = Datafile(options->getSection("output"), mesh); + bout::globals::dump = Datafile(options->getSection("output"), bout::globals::mesh); /// Open a file for the output if(append) { - dump.opena("%s/BOUT.dmp.%s", data_dir.c_str(), dump_ext.c_str()); + bout::globals::dump.opena("%s/BOUT.dmp.%s", data_dir.c_str(), dump_ext.c_str()); }else { - dump.openw("%s/BOUT.dmp.%s", data_dir.c_str(), dump_ext.c_str()); + bout::globals::dump.openw("%s/BOUT.dmp.%s", data_dir.c_str(), dump_ext.c_str()); } /// Add book-keeping variables to the output files - dump.add(const_cast(BOUT_VERSION), "BOUT_VERSION", false); - dump.add(simtime, "t_array", true); // Appends the time of dumps into an array - dump.add(iteration, "iteration", false); + bout::globals::dump.add(const_cast(BOUT_VERSION), "BOUT_VERSION", false); + bout::globals::dump.add(simtime, "t_array", true); // Appends the time of dumps into an array + bout::globals::dump.add(iteration, "iteration", false); //////////////////////////////////////////// - mesh->outputVars(dump); ///< Save mesh configuration into output file + bout::globals::mesh->outputVars(bout::globals::dump); ///< Save mesh configuration into output file }catch(BoutException &e) { output_error.write(_("Error encountered during initialisation: %s\n"), e.what()); @@ -556,10 +556,10 @@ int BoutFinalise() { } // Delete the mesh - delete mesh; + delete bout::globals::mesh; // Close the output file - dump.close(); + bout::globals::dump.close(); // Make sure all processes have finished writing before exit MPI_Barrier(BoutComm::get()); @@ -621,7 +621,7 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { iteration = iter; /// Write dump file - dump.write(); + bout::globals::dump.write(); /// Collect timing information BoutReal wtime = Timer::resetTime("run"); From a812c7c7229144b43e24bd7170ce181ec88cb575 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 18:59:42 +0000 Subject: [PATCH 0540/1783] Replace mesh with bout::globals::mesh Also replace default argument of 'mesh' with 'nullptr' and then handle 'nullptr' by setting local mesh to 'mesh' in a few places. --- include/field.hxx | 4 ++-- include/interpolation.hxx | 2 +- include/invert_laplace.hxx | 4 ++-- include/invert_parderiv.hxx | 6 +++--- include/mask.hxx | 2 +- src/field/field.cxx | 6 ++---- src/field/field2d.cxx | 2 +- src/field/field3d.cxx | 2 +- src/field/fieldperp.cxx | 2 +- 9 files changed, 14 insertions(+), 16 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index 216c12a2a8..fa0710e0d4 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -33,6 +33,7 @@ class Field; #include "bout_types.hxx" #include "boutexception.hxx" +#include #include "msg_stack.hxx" #include "stencils.hxx" #include @@ -41,7 +42,6 @@ class Field; class Mesh; class Coordinates; -extern Mesh * mesh; ///< Global mesh #ifdef TRACK #include @@ -94,7 +94,7 @@ class Field { if (fieldmesh){ return fieldmesh; } else { - return mesh; + return bout::globals::mesh; } } diff --git a/include/interpolation.hxx b/include/interpolation.hxx index ad72870878..6c688afb69 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -243,7 +243,7 @@ protected: public: Interpolation(int y_offset = 0, Mesh* localmeshIn = nullptr) - : localmesh(localmeshIn == nullptr ? mesh : localmeshIn), + : localmesh(localmeshIn == nullptr ? bout::globals::mesh : localmeshIn), skip_mask(*localmesh, false), y_offset(y_offset) {} Interpolation(const BoutMask &mask, int y_offset = 0, Mesh *mesh = nullptr) : Interpolation(y_offset, mesh) { diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index 17d1e48507..fa1d7d1ec7 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -105,7 +105,7 @@ const int INVERT_OUT_RHS = 32768; ///< Use input value in RHS at outer boundary /// Base class for Laplacian inversion class Laplacian { public: - Laplacian(Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh* mesh_in = mesh); + Laplacian(Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh* mesh_in = bout::globals::mesh); virtual ~Laplacian() {} /// Set coefficients for inversion. Re-builds matrices if necessary @@ -192,7 +192,7 @@ public: * * @param[in] opt The options section to use. By default "laplace" will be used */ - static Laplacian *create(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); + static Laplacian *create(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); static Laplacian* defaultInstance(); ///< Return pointer to global singleton static void cleanup(); ///< Frees all memory diff --git a/include/invert_parderiv.hxx b/include/invert_parderiv.hxx index ddca5c3366..cd5edaf7d3 100644 --- a/include/invert_parderiv.hxx +++ b/include/invert_parderiv.hxx @@ -63,8 +63,8 @@ public: * with pure virtual members, so can't be created directly. * To create an InvertPar object call the create() static function. */ - InvertPar(Options *UNUSED(opt), Mesh *mesh_in = mesh) - : localmesh(mesh_in) {} + InvertPar(Options *UNUSED(opt), Mesh *mesh_in = nullptr) + : localmesh(mesh_in==nullptr ? bout::globals::mesh : mesh_in) {} virtual ~InvertPar() {} /*! @@ -72,7 +72,7 @@ public: * * Note: For consistency this should be renamed "create" and take an Options* argument */ - static InvertPar* Create(Mesh *mesh_in = mesh); + static InvertPar* Create(Mesh *mesh_in = nullptr); /*! * Solve the system of equations diff --git a/include/mask.hxx b/include/mask.hxx index cc1539e550..60b82c0fa9 100644 --- a/include/mask.hxx +++ b/include/mask.hxx @@ -61,7 +61,7 @@ public: BoutMask(Mesh& mesh, bool value=false) : BoutMask(mesh.LocalNx, mesh.LocalNy, mesh.LocalNz, value) {} // Default constructor uses global mesh - BoutMask() : BoutMask(*mesh) {} + BoutMask() : BoutMask(*bout::globals::mesh) {} // Assignment from bool BoutMask& operator=(bool value) { diff --git a/src/field/field.cxx b/src/field/field.cxx index 3e4fd46987..4d133f722d 100644 --- a/src/field/field.cxx +++ b/src/field/field.cxx @@ -32,10 +32,8 @@ #include #include -Field::Field(Mesh *localmesh) : fieldmesh(localmesh) { - if (fieldmesh == nullptr) { - fieldmesh = mesh; - } +Field::Field(Mesh *localmesh) + : fieldmesh(localmesh==nullptr ? bout::globals::mesh : localmesh) { // Note we would like to do `fieldCoordinates = getCoordinates();` here but can't // currently as this would lead to circular/recursive behaviour (getCoordinates would diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 02f2a2e480..e13f121570 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -93,7 +93,7 @@ void Field2D::allocate() { if(data.empty()) { if(!fieldmesh) { /// If no mesh, use the global - fieldmesh = mesh; + fieldmesh = bout::globals::mesh; nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; } diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 65511f428a..44141b0b01 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -127,7 +127,7 @@ void Field3D::allocate() { if(data.empty()) { if(!fieldmesh) { /// If no mesh, use the global - fieldmesh = mesh; + fieldmesh = bout::globals::mesh; nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 5787f0ce29..e184bfc29a 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -50,7 +50,7 @@ void FieldPerp::allocate() { if (data.empty()) { if (!fieldmesh) { /// If no mesh, use the global - fieldmesh = mesh; + fieldmesh = bout::globals::mesh; nx = fieldmesh->LocalNx; nz = fieldmesh->LocalNz; } From 4427ce443720e89b0795487be86a7b2b29aaf4e8 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 18 Dec 2018 19:22:48 +0000 Subject: [PATCH 0541/1783] More replacements mesh->bout::globals::mesh in default arguments In Laplacian and InvertPar --- src/invert/laplace/impls/cyclic/cyclic_laplace.hxx | 2 +- src/invert/laplace/impls/multigrid/multigrid_laplace.hxx | 3 ++- src/invert/laplace/impls/mumps/mumps_laplace.hxx | 4 ++-- src/invert/laplace/impls/naulin/naulin_laplace.hxx | 2 +- src/invert/laplace/impls/pdd/pdd.hxx | 2 +- src/invert/laplace/impls/petsc/petsc_laplace.hxx | 4 ++-- src/invert/laplace/impls/serial_band/serial_band.hxx | 2 +- src/invert/laplace/impls/serial_tri/serial_tri.hxx | 2 +- src/invert/laplace/impls/shoot/shoot_laplace.hxx | 2 +- src/invert/laplace/impls/spt/spt.hxx | 2 +- src/invert/laplace/laplacefactory.hxx | 3 ++- src/invert/parderiv/impls/cyclic/cyclic.hxx | 3 ++- src/invert/parderiv/parderiv_factory.hxx | 6 +++--- 13 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx index b007542569..6d94cc8203 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx @@ -44,7 +44,7 @@ class LaplaceCyclic; */ class LaplaceCyclic : public Laplacian { public: - LaplaceCyclic(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); + LaplaceCyclic(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); ~LaplaceCyclic(); using Laplacian::setCoefA; diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx index 0067e1bb51..5b2a6ffd18 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx @@ -132,7 +132,8 @@ private: class LaplaceMultigrid : public Laplacian { public: - LaplaceMultigrid(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); + LaplaceMultigrid(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, + Mesh *mesh_in = bout::globals::mesh); ~LaplaceMultigrid() {}; void setCoefA(const Field2D &val) override { diff --git a/src/invert/laplace/impls/mumps/mumps_laplace.hxx b/src/invert/laplace/impls/mumps/mumps_laplace.hxx index 6c37e63fa9..75ca899193 100644 --- a/src/invert/laplace/impls/mumps/mumps_laplace.hxx +++ b/src/invert/laplace/impls/mumps/mumps_laplace.hxx @@ -36,7 +36,7 @@ class LaplaceMumps; class LaplaceMumps : public Laplacian { public: - LaplaceMumps(Options *UNUSED(opt) = nullptr, const CELL_LOC UNUSED(loc) = CELL_CENTRE, Mesh *UNUSED(mesh_in) = mesh) { + LaplaceMumps(Options *UNUSED(opt) = nullptr, const CELL_LOC UNUSED(loc) = CELL_CENTRE, Mesh *UNUSED(mesh_in) = bout::globals::mesh) { throw BoutException("Mumps library not available"); } @@ -76,7 +76,7 @@ public: class LaplaceMumps : public Laplacian { public: - LaplaceMumps(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); + LaplaceMumps(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); ~LaplaceMumps() { mumps_struc.job = -2; dmumps_c(&mumps_struc); diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.hxx b/src/invert/laplace/impls/naulin/naulin_laplace.hxx index b58d63f678..f6cd5b3ba2 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.hxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.hxx @@ -37,7 +37,7 @@ class LaplaceNaulin; */ class LaplaceNaulin : public Laplacian { public: - LaplaceNaulin(Options *opt = NULL, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); + LaplaceNaulin(Options *opt = NULL, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); ~LaplaceNaulin(); // ACoef is not implemented because the delp2solver that we use can probably diff --git a/src/invert/laplace/impls/pdd/pdd.hxx b/src/invert/laplace/impls/pdd/pdd.hxx index 0dff1dd6e0..76e54e737e 100644 --- a/src/invert/laplace/impls/pdd/pdd.hxx +++ b/src/invert/laplace/impls/pdd/pdd.hxx @@ -40,7 +40,7 @@ class LaplacePDD; class LaplacePDD : public Laplacian { public: - LaplacePDD(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh) + LaplacePDD(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh) : Laplacian(opt, loc, mesh_in), Acoef(0.0), Ccoef(1.0), Dcoef(1.0), PDD_COMM_XV(123), PDD_COMM_Y(456) { Acoef.setLocation(location); diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.hxx b/src/invert/laplace/impls/petsc/petsc_laplace.hxx index 61b094ace2..f949ebd169 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.hxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.hxx @@ -37,7 +37,7 @@ class LaplacePetsc; class LaplacePetsc : public Laplacian { public: - LaplacePetsc(Options *UNUSED(opt) = nullptr, const CELL_LOC UNUSED(loc) = CELL_CENTRE, Mesh *UNUSED(mesh_in) = mesh) { + LaplacePetsc(Options *UNUSED(opt) = nullptr, const CELL_LOC UNUSED(loc) = CELL_CENTRE, Mesh *UNUSED(mesh_in) = bout::globals::mesh) { throw BoutException("No PETSc solver available"); } @@ -68,7 +68,7 @@ public: class LaplacePetsc : public Laplacian { public: - LaplacePetsc(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); + LaplacePetsc(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); ~LaplacePetsc() { KSPDestroy( &ksp ); VecDestroy( &xs ); diff --git a/src/invert/laplace/impls/serial_band/serial_band.hxx b/src/invert/laplace/impls/serial_band/serial_band.hxx index 05a7649e32..98607d07a6 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.hxx +++ b/src/invert/laplace/impls/serial_band/serial_band.hxx @@ -36,7 +36,7 @@ class LaplaceSerialBand; class LaplaceSerialBand : public Laplacian { public: - LaplaceSerialBand(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = mesh); + LaplaceSerialBand(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); ~LaplaceSerialBand(){}; using Laplacian::setCoefA; diff --git a/src/invert/laplace/impls/serial_tri/serial_tri.hxx b/src/invert/laplace/impls/serial_tri/serial_tri.hxx index 519dc9a361..52c025fca9 100644 --- a/src/invert/laplace/impls/serial_tri/serial_tri.hxx +++ b/src/invert/laplace/impls/serial_tri/serial_tri.hxx @@ -35,7 +35,7 @@ class LaplaceSerialTri; class LaplaceSerialTri : public Laplacian { public: - LaplaceSerialTri(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); + LaplaceSerialTri(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); ~LaplaceSerialTri(){}; using Laplacian::setCoefA; diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.hxx b/src/invert/laplace/impls/shoot/shoot_laplace.hxx index db6e1bd617..5197781ce3 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.hxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.hxx @@ -37,7 +37,7 @@ class LaplaceShoot; class LaplaceShoot : public Laplacian { public: - LaplaceShoot(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = mesh); + LaplaceShoot(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); ~LaplaceShoot(){}; using Laplacian::setCoefA; diff --git a/src/invert/laplace/impls/spt/spt.hxx b/src/invert/laplace/impls/spt/spt.hxx index 44b7d98eb8..52391df81e 100644 --- a/src/invert/laplace/impls/spt/spt.hxx +++ b/src/invert/laplace/impls/spt/spt.hxx @@ -66,7 +66,7 @@ class LaplaceSPT; */ class LaplaceSPT : public Laplacian { public: - LaplaceSPT(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = mesh); + LaplaceSPT(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); ~LaplaceSPT(); using Laplacian::setCoefA; diff --git a/src/invert/laplace/laplacefactory.hxx b/src/invert/laplace/laplacefactory.hxx index 215ee8790d..79a618ef00 100644 --- a/src/invert/laplace/laplacefactory.hxx +++ b/src/invert/laplace/laplacefactory.hxx @@ -11,7 +11,8 @@ class LaplaceFactory { /// Return a pointer to the only instance static LaplaceFactory* getInstance(); - Laplacian *createLaplacian(Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = mesh); + Laplacian *createLaplacian(Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE, + Mesh *mesh_in = bout::globals::mesh); private: LaplaceFactory() {} // Prevent instantiation of this class diff --git a/src/invert/parderiv/impls/cyclic/cyclic.hxx b/src/invert/parderiv/impls/cyclic/cyclic.hxx index 328c213a64..390228b57f 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.hxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.hxx @@ -41,11 +41,12 @@ #include "invert_parderiv.hxx" #include "dcomplex.hxx" +#include #include "utils.hxx" class InvertParCR : public InvertPar { public: - InvertParCR(Options *opt, Mesh *mesh_in = mesh); + InvertParCR(Options *opt, Mesh *mesh_in = bout::globals::mesh); ~InvertParCR(); using InvertPar::solve; diff --git a/src/invert/parderiv/parderiv_factory.hxx b/src/invert/parderiv/parderiv_factory.hxx index d5a3a5cb17..5701f5ef48 100644 --- a/src/invert/parderiv/parderiv_factory.hxx +++ b/src/invert/parderiv/parderiv_factory.hxx @@ -11,9 +11,9 @@ class ParDerivFactory { /// Return a pointer to the only instance static ParDerivFactory* getInstance(); - InvertPar* createInvertPar(Mesh* mesh_in = mesh); - InvertPar *createInvertPar(const char *type, Options *opt = nullptr, Mesh* mesh_in = mesh); - InvertPar* createInvertPar(Options *opts, Mesh* mesh_in = mesh); + InvertPar* createInvertPar(Mesh* mesh_in = bout::globals::mesh); + InvertPar *createInvertPar(const char *type, Options *opt = nullptr, Mesh* mesh_in = bout::globals::mesh); + InvertPar* createInvertPar(Options *opts, Mesh* mesh_in = bout::globals::mesh); private: ParDerivFactory() {} // Prevent instantiation of this class static ParDerivFactory* instance; ///< The only instance of this class (Singleton) From e6ea1108abccd3326505725557546154aa36ea94 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 10:18:23 +0000 Subject: [PATCH 0542/1783] Add namespace to global mesh in PhysicsModel::postInit() --- src/physics/physicsmodel.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/physics/physicsmodel.cxx b/src/physics/physicsmodel.cxx index cfd9cf1061..6b408d8a0b 100644 --- a/src/physics/physicsmodel.cxx +++ b/src/physics/physicsmodel.cxx @@ -129,7 +129,7 @@ int PhysicsModel::postInit(bool restarting) { // Add mesh information to restart file // Note this is done after reading, so mesh variables // are not overwritten. - mesh->outputVars(restart); + bout::globals::mesh->outputVars(restart); // Version expected by collect routine restart.addOnce(const_cast(BOUT_VERSION), "BOUT_VERSION"); From 6deed69143df400414091dae3b7e0fdd4bd2379b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 11:03:07 +0000 Subject: [PATCH 0543/1783] Reduce uses of global mesh in solvers, add namespace to remaining Loops in solvers are hard-coded to use a single Mesh*: leave as the global 'bout::globals::mesh' for now, and leave removal of global mesh from solvers for later. --- src/solver/impls/arkode/arkode.cxx | 22 ++++++++++++++++------ src/solver/impls/cvode/cvode.cxx | 22 ++++++++++++++++------ src/solver/impls/ida/ida.cxx | 14 +++++++++++--- src/solver/impls/imex-bdf2/imex-bdf2.cxx | 6 ++++++ src/solver/impls/petsc/petsc.cxx | 18 +++++++++++++----- src/solver/impls/pvode/pvode.cxx | 15 ++++++++++++--- src/solver/solver.cxx | 22 ++++++++++++++++++---- 7 files changed, 92 insertions(+), 27 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index 20316aac44..d8ed659eeb 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -135,15 +135,25 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { bool use_precon, use_jacobian, use_vector_abstol,set_linear; BoutReal start_timestep, max_timestep, min_timestep,fixed_timestep; bool imex,expl,impl; // Time-integration method - int MXSUB = mesh->xend - mesh->xstart + 1; + + // Compute band_width_default from actually added fields, to allow for multiple Mesh objects + // + // Previous implementation was equivalent to: + // int MXSUB = mesh->xend - mesh->xstart + 1; + // int band_width_default = n3Dvars()*(MXSUB+2); + int band_width_default = 0; + for (auto fvar : f3d) { + band_width_default += fvar.var->getNx(); + } + BoutReal cfl_frac; bool fixed_step; int mxsteps; // Maximum number of steps to take between outputs int mxorder; // Maximum lmm order to be used by the solver {TRACE("Getting options"); - options->get("mudq", mudq, n3Dvars()*(MXSUB+2)); - options->get("mldq", mldq, n3Dvars()*(MXSUB+2)); + options->get("mudq", mudq, band_width_default); + options->get("mldq", mldq, band_width_default); options->get("mukeep", mukeep, n3Dvars()+n2Dvars()); options->get("mlkeep", mlkeep, n3Dvars()+n2Dvars()); options->get("ATOL", abstol, 1.0e-12); @@ -712,11 +722,11 @@ void ArkodeSolver::set_abstol_values(BoutReal *abstolvec_data, int p = 0; // Counter for location in abstolvec_data array // All boundaries - for (const auto &i2d : mesh->getRegion2D("RGN_BNDRY")) { + for (const auto &i2d : bout::globals::mesh->getRegion2D("RGN_BNDRY")) { loop_abstol_values_op(i2d, abstolvec_data, p, f2dtols, f3dtols, true); } // Bulk of points - for (const auto &i2d : mesh->getRegion2D("RGN_NOBNDRY")) { + for (const auto &i2d : bout::globals::mesh->getRegion2D("RGN_NOBNDRY")) { loop_abstol_values_op(i2d, abstolvec_data, p, f2dtols, f3dtols, false); } } @@ -733,7 +743,7 @@ void ArkodeSolver::loop_abstol_values_op(Ind2D UNUSED(i2d), p++; } - for (int jz=0; jz < mesh->LocalNz; jz++) { + for (int jz=0; jz < bout::globals::mesh->LocalNz; jz++) { // Loop over 3D variables for(std::vector::size_type i=0; ixend - mesh->xstart + 1; + + // Compute band_width_default from actually added fields, to allow for multiple Mesh objects + // + // Previous implementation was equivalent to: + // int MXSUB = mesh->xend - mesh->xstart + 1; + // int band_width_default = n3Dvars()*(MXSUB+2); + int band_width_default = 0; + for (auto fvar : f3d) { + band_width_default += fvar.var->getNx(); + } + int mxsteps; // Maximum number of steps to take between outputs int mxorder; // Maximum lmm order to be used by the solver int lmm = CV_BDF; int iter = CV_NEWTON; {TRACE("Getting options"); - options->get("mudq", mudq, n3Dvars()*(MXSUB+2)); - options->get("mldq", mldq, n3Dvars()*(MXSUB+2)); + options->get("mudq", mudq, band_width_default); + options->get("mldq", mldq, band_width_default); options->get("mukeep", mukeep, n3Dvars()+n2Dvars()); options->get("mlkeep", mlkeep, n3Dvars()+n2Dvars()); options->get("ATOL", abstol, 1.0e-12); @@ -581,11 +591,11 @@ void CvodeSolver::set_abstol_values(BoutReal* abstolvec_data, std::vectorgetRegion2D("RGN_BNDRY")) { + for (const auto &i2d : bout::globals::mesh->getRegion2D("RGN_BNDRY")) { loop_abstol_values_op(i2d, abstolvec_data, p, f2dtols, f3dtols, true); } // Bulk of points - for (const auto &i2d : mesh->getRegion2D("RGN_NOBNDRY")) { + for (const auto &i2d : bout::globals::mesh->getRegion2D("RGN_NOBNDRY")) { loop_abstol_values_op(i2d, abstolvec_data, p, f2dtols, f3dtols, false); } } @@ -603,7 +613,7 @@ void CvodeSolver::loop_abstol_values_op(Ind2D UNUSED(i2d), p++; } - for (int jz=0; jz < mesh->LocalNz; jz++) { + for (int jz=0; jz < bout::globals::mesh->LocalNz; jz++) { // Loop over 3D variables for(std::vector::size_type i=0; ixend - mesh->xstart + 1; + // Compute band_width_default from actually added fields, to allow for multiple Mesh objects + // + // Previous implementation was equivalent to: + // int MXSUB = mesh->xend - mesh->xstart + 1; + // int band_width_default = n3Dvars()*(MXSUB+2); + int band_width_default = 0; + for (auto fvar : f3d) { + band_width_default += fvar.var->getNx(); + } BoutReal abstol, reltol; int maxl; @@ -134,8 +142,8 @@ IdaSolver::~IdaSolver() { } bool use_precon; bool correct_start; - OPTION(options, mudq, n3d*(MXSUB+2)); - OPTION(options, mldq, n3d*(MXSUB+2)); + OPTION(options, mudq, band_width_default); + OPTION(options, mldq, band_width_default); OPTION(options, mukeep, n3d); OPTION(options, mlkeep, n3d); options->get("ATOL", abstol, 1.0e-12); diff --git a/src/solver/impls/imex-bdf2/imex-bdf2.cxx b/src/solver/impls/imex-bdf2/imex-bdf2.cxx index 341bf6a474..e586326d27 100644 --- a/src/solver/impls/imex-bdf2/imex-bdf2.cxx +++ b/src/solver/impls/imex-bdf2/imex-bdf2.cxx @@ -205,6 +205,9 @@ int IMEXBDF2::init(int nout, BoutReal tstep) { //Set up a snes object stored at the specified location void IMEXBDF2::constructSNES(SNES *snesIn){ + // Use global mesh for now + Mesh* mesh = bout::globals::mesh; + // Nonlinear solver interface (SNES) SNESCreate(BoutComm::get(),snesIn); @@ -1310,6 +1313,9 @@ PetscErrorCode IMEXBDF2::precon(Vec x, Vec f) { */ template< class Op > void IMEXBDF2::loopVars(BoutReal *u) { + // Use global mesh for now + Mesh* mesh = bout::globals::mesh; + // Loop over 2D variables for(auto it = f2d.begin(); it != f2d.end(); ++it) { Op op(it->var, it->F_var); // Initialise the operator diff --git a/src/solver/impls/petsc/petsc.cxx b/src/solver/impls/petsc/petsc.cxx index a4358118fb..15b3e36861 100644 --- a/src/solver/impls/petsc/petsc.cxx +++ b/src/solver/impls/petsc/petsc.cxx @@ -173,10 +173,18 @@ int PetscSolver::init(int NOUT, BoutReal TIMESTEP) { ierr = VecDestroy(&rhs_vec); ///////////// GET OPTIONS ///////////// - int MXSUB = mesh->xend - mesh->xstart + 1; + // Compute band_width_default from actually added fields, to allow for multiple Mesh objects + // + // Previous implementation was equivalent to: + // int MXSUB = mesh->xend - mesh->xstart + 1; + // int band_width_default = n3Dvars()*(MXSUB+2); + int band_width_default = 0; + for (auto fvar : f3d) { + band_width_default += fvar.var->getNx(); + } - OPTION(options, mudq, n3d*(MXSUB+2)); - OPTION(options, mldq, n3d*(MXSUB+2)); + OPTION(options, mudq, band_width_default); + OPTION(options, mldq, band_width_default); OPTION(options, mukeep, 0); OPTION(options, mlkeep, 0); OPTION(options, use_precon, false); @@ -376,14 +384,14 @@ int PetscSolver::init(int NOUT, BoutReal TIMESTEP) { PetscInt dof = n3Dvars(); // Maximum allowable size of stencil in x is the number of guard cells - PetscInt stencil_width = mesh->xstart; + PetscInt stencil_width_estimate = options->operator[]("stencil_width_estimate").withDefault(bout::globals::mesh->xstart); // This is the stencil in each direction (*2) along each dimension // (*3), plus the point itself. Not sure if this is correct // though, on several levels: // 1. Ignores corner points used in e.g. brackets // 2. Could have different stencil widths in each dimension // 3. FFTs couple every single point together - PetscInt cols = stencil_width*2*3+1; + PetscInt cols = stencil_width_estimate*2*3+1; PetscInt prealloc; // = cols*dof; ierr = MatCreate(comm,&J);CHKERRQ(ierr); diff --git a/src/solver/impls/pvode/pvode.cxx b/src/solver/impls/pvode/pvode.cxx index 6881e92110..4214ba7281 100644 --- a/src/solver/impls/pvode/pvode.cxx +++ b/src/solver/impls/pvode/pvode.cxx @@ -121,10 +121,19 @@ int PvodeSolver::init(int nout, BoutReal tstep) { ///////////// GET OPTIONS ///////////// int pvode_mxstep; - int MXSUB = mesh->xend - mesh->xstart + 1; + // Compute band_width_default from actually added fields, to allow for multiple Mesh objects + // + // Previous implementation was equivalent to: + // int MXSUB = mesh->xend - mesh->xstart + 1; + // int band_width_default = n3Dvars()*(MXSUB+2); + int band_width_default = 0; + for (auto fvar : f3d) { + band_width_default += fvar.var->getNx(); + } + - options->get("mudq", mudq, n3d*(MXSUB+2)); - options->get("mldq", mldq, n3d*(MXSUB+2)); + options->get("mudq", mudq, band_width_default); + options->get("mldq", mldq, band_width_default); options->get("mukeep", mukeep, 0); options->get("mlkeep", mlkeep, 0); options->get("ATOL", abstol, 1.0e-12); diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 4e6b57d289..d9f4e84686 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -158,7 +158,7 @@ void Solver::add(Field2D &v, const std::string name) { FieldFactory *fact = FieldFactory::get(); - v = fact->create2D("solution", Options::getRoot()->getSection(name), mesh); + v = fact->create2D("solution", Options::getRoot()->getSection(name), v.getMesh()); } else { initial_profile(name, v); } @@ -184,6 +184,8 @@ void Solver::add(Field2D &v, const std::string name) { void Solver::add(Field3D &v, const std::string name) { TRACE("Adding 3D field: Solver::add(%s)", name.c_str()); + Mesh* mesh = v.getMesh(); + #if CHECK > 0 if (varAdded(name)) throw BoutException("Variable '%s' already added to Solver", name.c_str()); @@ -772,6 +774,9 @@ int Solver::call_timestep_monitors(BoutReal simtime, BoutReal lastdt) { int Solver::getLocalN() { + // Use global mesh: FIX THIS! + Mesh* mesh = bout::globals::mesh; + /// Cache the value, so this is not repeatedly called. /// This value should not change after initialisation static int cacheLocalN = -1; @@ -828,6 +833,9 @@ Solver* Solver::create(SolverType &type, Options *opts) { /// Perform an operation at a given Ind2D (jx,jy) location, moving data between BOUT++ and CVODE void Solver::loop_vars_op(Ind2D i2d, BoutReal *udata, int &p, SOLVER_VAR_OP op, bool bndry) { + // Use global mesh: FIX THIS! + Mesh* mesh = bout::globals::mesh; + int nz = mesh->LocalNz; switch(op) { @@ -962,6 +970,9 @@ void Solver::loop_vars_op(Ind2D i2d, BoutReal *udata, int &p, SOLVER_VAR_OP op, /// Loop over variables and domain. Used for all data operations for consistency void Solver::loop_vars(BoutReal *udata, SOLVER_VAR_OP op) { + // Use global mesh: FIX THIS! + Mesh* mesh = bout::globals::mesh; + int p = 0; // Counter for location in udata array // All boundaries @@ -1075,6 +1086,9 @@ void Solver::set_id(BoutReal *udata) { * */ const Field3D Solver::globalIndex(int localStart) { + // Use global mesh: FIX THIS! + Mesh* mesh = bout::globals::mesh; + Field3D index(-1, mesh); // Set to -1, indicating out of domain int n2d = f2d.size(); @@ -1358,11 +1372,11 @@ void Solver::add_mms_sources(BoutReal t) { // Iterate over 2D variables for(const auto& f : f2d) { - *f.F_var += fact->create2D("source", Options::getRoot()->getSection(f.name), mesh, (f.var)->getLocation(), t); + *f.F_var += fact->create2D("source", Options::getRoot()->getSection(f.name), f.var->getMesh(), (f.var)->getLocation(), t); } for(const auto& f : f3d) { - *f.F_var += fact->create3D("source", Options::getRoot()->getSection(f.name), mesh, (f.var)->getLocation(), t); + *f.F_var += fact->create3D("source", Options::getRoot()->getSection(f.name), f.var->getMesh(), (f.var)->getLocation(), t); } } @@ -1371,7 +1385,7 @@ void Solver::calculate_mms_error(BoutReal t) { FieldFactory *fact = FieldFactory::get(); for(const auto& f : f3d) { - Field3D solution = fact->create3D("solution", Options::getRoot()->getSection(f.name), mesh, (f.var)->getLocation(), t); + Field3D solution = fact->create3D("solution", Options::getRoot()->getSection(f.name), f.var->getMesh(), (f.var)->getLocation(), t); *(f.MMS_err) = *(f.var) - solution; } From 7fff20fba85d7a2c76644b901a88bd9b55bbc4c3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 17:02:03 +0000 Subject: [PATCH 0544/1783] Restore exactly original behaviour of mudq/mldq defaults --- src/solver/impls/arkode/arkode.cxx | 3 ++- src/solver/impls/cvode/cvode.cxx | 3 ++- src/solver/impls/ida/ida.cxx | 3 ++- src/solver/impls/petsc/petsc.cxx | 3 ++- src/solver/impls/pvode/pvode.cxx | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index d8ed659eeb..884f64fc4e 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -143,7 +143,8 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { // int band_width_default = n3Dvars()*(MXSUB+2); int band_width_default = 0; for (auto fvar : f3d) { - band_width_default += fvar.var->getNx(); + Mesh* localmesh = fvar.var->getMesh(); + band_width_default += localmesh->xend - localmesh->xstart + 3; } BoutReal cfl_frac; diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index f1ee3f5b6a..58a3fc5edd 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -139,7 +139,8 @@ int CvodeSolver::init(int nout, BoutReal tstep) { // int band_width_default = n3Dvars()*(MXSUB+2); int band_width_default = 0; for (auto fvar : f3d) { - band_width_default += fvar.var->getNx(); + Mesh* localmesh = fvar.var->getMesh(); + band_width_default += localmesh->xend - localmesh->xstart + 3; } int mxsteps; // Maximum number of steps to take between outputs diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index ebcf665761..706ca47246 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -132,7 +132,8 @@ IdaSolver::~IdaSolver() { } // int band_width_default = n3Dvars()*(MXSUB+2); int band_width_default = 0; for (auto fvar : f3d) { - band_width_default += fvar.var->getNx(); + Mesh* localmesh = fvar.var->getMesh(); + band_width_default += localmesh->xend - localmesh->xstart + 3; } BoutReal abstol, reltol; diff --git a/src/solver/impls/petsc/petsc.cxx b/src/solver/impls/petsc/petsc.cxx index 15b3e36861..66bc8ff7ae 100644 --- a/src/solver/impls/petsc/petsc.cxx +++ b/src/solver/impls/petsc/petsc.cxx @@ -180,7 +180,8 @@ int PetscSolver::init(int NOUT, BoutReal TIMESTEP) { // int band_width_default = n3Dvars()*(MXSUB+2); int band_width_default = 0; for (auto fvar : f3d) { - band_width_default += fvar.var->getNx(); + Mesh* localmesh = fvar.var->getMesh(); + band_width_default += localmesh->xend - localmesh->xstart + 3; } OPTION(options, mudq, band_width_default); diff --git a/src/solver/impls/pvode/pvode.cxx b/src/solver/impls/pvode/pvode.cxx index 4214ba7281..3ff6b40207 100644 --- a/src/solver/impls/pvode/pvode.cxx +++ b/src/solver/impls/pvode/pvode.cxx @@ -128,7 +128,8 @@ int PvodeSolver::init(int nout, BoutReal tstep) { // int band_width_default = n3Dvars()*(MXSUB+2); int band_width_default = 0; for (auto fvar : f3d) { - band_width_default += fvar.var->getNx(); + Mesh* localmesh = fvar.var->getMesh(); + band_width_default += localmesh->xend - localmesh->xstart + 3; } From aa1879e4117fa2d4e16753c420739375e4b6647e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 11:38:15 +0000 Subject: [PATCH 0545/1783] Use globals namespace in boutcore --- tools/pylib/_boutcore_build/helper.cxx.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pylib/_boutcore_build/helper.cxx.in b/tools/pylib/_boutcore_build/helper.cxx.in index 73d2f46834..41e79c2385 100644 --- a/tools/pylib/_boutcore_build/helper.cxx.in +++ b/tools/pylib/_boutcore_build/helper.cxx.in @@ -160,7 +160,7 @@ void c_set_f2d_part_(Field2D * f2d, const double data,int xs,int xe, int dx,int } Mesh * c_get_global_mesh(){ - return mesh; + return bout::globals::mesh; } void c_mesh_normalise(Mesh * msh, double norm){ From 95146f26e4bf1d8d750f86912f3e0ba7071fcd6e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 11:57:54 +0000 Subject: [PATCH 0546/1783] Use bout::globals namespace in InvertableOperator --- include/bout/invertable_operator.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 6886cb4a13..d46fa17278 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -133,7 +133,7 @@ public: : operatorFunction(func), preconditionerFunction(func), opt(optIn == nullptr ? optIn : Options::getRoot()->getSection("invertableOperator")), - localmesh(localmeshIn == nullptr ? mesh : localmeshIn), doneSetup(false) { + localmesh(localmeshIn == nullptr ? bout::globals::mesh : localmeshIn), doneSetup(false) { AUTO_TRACE(); }; From 566614f8014c2282054b08ea0bc1132d58fb4e10 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 12:46:19 +0000 Subject: [PATCH 0547/1783] Use bout::globals namespace in unit tests Unit tests use the global mesh pointer. --- tests/unit/field/test_field2d.cxx | 7 +++++++ tests/unit/field/test_field3d.cxx | 7 +++++++ tests/unit/field/test_fieldperp.cxx | 7 +++++++ tests/unit/field/test_vector2d.cxx | 7 +++++++ tests/unit/field/test_vector3d.cxx | 7 +++++++ tests/unit/include/bout/test_region.cxx | 7 +++++++ tests/unit/mesh/test_boundary_factory.cxx | 7 +++++++ tests/unit/mesh/test_interpolation.cxx | 7 +++++++ tests/unit/test_extras.hxx | 14 +++++++------- 9 files changed, 63 insertions(+), 7 deletions(-) diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index f9df75f162..9f5a043815 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -18,7 +18,14 @@ #include /// Global mesh +namespace bout{ +namespace globals{ extern Mesh *mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; // Reuse the "standard" fixture for FakeMesh using Field2DTest = FakeMeshFixture; diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index a8b4525b27..0471ff1d66 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -18,7 +18,14 @@ #include /// Global mesh +namespace bout{ +namespace globals{ extern Mesh *mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; // Reuse the "standard" fixture for FakeMesh using Field3DTest = FakeMeshFixture; diff --git a/tests/unit/field/test_fieldperp.cxx b/tests/unit/field/test_fieldperp.cxx index 55757dc83e..3dfa1c599f 100644 --- a/tests/unit/field/test_fieldperp.cxx +++ b/tests/unit/field/test_fieldperp.cxx @@ -17,7 +17,14 @@ #include /// Global mesh +namespace bout{ +namespace globals{ extern Mesh *mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; /// Test fixture to make sure the global mesh is our fake one using FieldPerpTest = FakeMeshFixture; diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index a6ec890c34..9dfcbc5c95 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -10,7 +10,14 @@ #include "vector3d.hxx" /// Global mesh +namespace bout{ +namespace globals{ extern Mesh *mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; /// Test fixture to make sure the global mesh is our fake one class Vector2DTest : public ::testing::Test { diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index eae149755d..965e28f9ae 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -9,7 +9,14 @@ #include "vector3d.hxx" /// Global mesh +namespace bout{ +namespace globals{ extern Mesh *mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; /// Test fixture to make sure the global mesh is our fake one class Vector3DTest : public ::testing::Test { diff --git a/tests/unit/include/bout/test_region.cxx b/tests/unit/include/bout/test_region.cxx index a8496e232c..4e7d59be02 100644 --- a/tests/unit/include/bout/test_region.cxx +++ b/tests/unit/include/bout/test_region.cxx @@ -15,7 +15,14 @@ #include /// Global mesh +namespace bout{ +namespace globals{ extern Mesh *mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; /// Test fixture to make sure the global mesh is our fake one using RegionTest = FakeMeshFixture; diff --git a/tests/unit/mesh/test_boundary_factory.cxx b/tests/unit/mesh/test_boundary_factory.cxx index c21a37c7a4..15f69686f6 100644 --- a/tests/unit/mesh/test_boundary_factory.cxx +++ b/tests/unit/mesh/test_boundary_factory.cxx @@ -6,7 +6,14 @@ #include "test_extras.hxx" /// Global mesh +namespace bout{ +namespace globals{ extern Mesh *mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; class TestBoundary : public BoundaryOp { public: diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index f48b5c5c52..a4ad6ffe9d 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -19,7 +19,14 @@ /////// /// Global mesh +namespace bout{ +namespace globals{ extern Mesh *mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; /// Test fixture to make sure the global mesh is our fake one class Field3DInterpToTest : public ::testing::Test { diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 7bb41523e4..219eee7267 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -176,19 +176,19 @@ class FakeMeshFixture : public ::testing::Test { public: FakeMeshFixture() { // Delete any existing mesh - if (mesh != nullptr) { - delete mesh; - mesh = nullptr; + if (bout::globals::mesh != nullptr) { + delete bout::globals::mesh; + bout::globals::mesh = nullptr; } - mesh = new FakeMesh(nx, ny, nz); + bout::globals::mesh = new FakeMesh(nx, ny, nz); output_info.disable(); - mesh->createDefaultRegions(); + bout::globals::mesh->createDefaultRegions(); output_info.enable(); } ~FakeMeshFixture() { - delete mesh; - mesh = nullptr; + delete bout::globals::mesh; + bout::globals::mesh = nullptr; } static constexpr int nx = 3; From e2d18edfd67e63a392fe53360a564cbfbdf85566 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 20 Dec 2018 09:47:16 +0000 Subject: [PATCH 0548/1783] Add bout::globals:: in field_data.cxx FieldData uses the global mesh. Allow this to continue for now, pending a redesign of FieldData; add bout::globals:: namespace to uses of the global mesh pointer. --- src/field/field_data.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 4251ace1b4..9cb00a34a0 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -20,7 +20,7 @@ void FieldData::setBoundary(const std::string &name) { output_info << "Setting boundary for variable " << name << endl; /// Loop over the mesh boundary regions - for(const auto& reg : mesh->getBoundaries()) { + for(const auto& reg : bout::globals::mesh->getBoundaries()) { BoundaryOp* op = static_cast(bfact->createFromOptions(name, reg)); if (op != nullptr) bndry_op.push_back(op); @@ -28,9 +28,9 @@ void FieldData::setBoundary(const std::string &name) { } /// Get the mesh boundary regions - std::vector par_reg = mesh->getBoundariesPar(); + std::vector par_reg = bout::globals::mesh->getBoundariesPar(); /// Loop over the mesh parallel boundary regions - for(const auto& reg : mesh->getBoundariesPar()) { + for(const auto& reg : bout::globals::mesh->getBoundariesPar()) { BoundaryOpPar* op = static_cast(bfact->createFromOptions(name, reg)); if (op != nullptr) bndry_op_par.push_back(op); @@ -43,7 +43,7 @@ void FieldData::setBoundary(const std::string &name) { void FieldData::setBoundary(const std::string &UNUSED(region), BoundaryOp *op) { /// Get the mesh boundary regions - std::vector reg = mesh->getBoundaries(); + std::vector reg = bout::globals::mesh->getBoundaries(); /// Find the region @@ -72,7 +72,7 @@ void FieldData::addBndryFunction(FuncPtr userfunc, BndryLoc location){ void FieldData::addBndryGenerator(FieldGeneratorPtr gen, BndryLoc location) { if(location == BNDRY_ALL){ - for(const auto& reg : mesh->getBoundaries()) { + for(const auto& reg : bout::globals::mesh->getBoundaries()) { bndry_generator[reg->location] = gen; } } else { From 721c1a8aa9b54f1c6f5fa463d8a6d7c13b4b10ba Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 2 Jan 2019 12:02:07 +0000 Subject: [PATCH 0549/1783] Replace mesh->bout::globals::mesh in laplacexy.cxx --- src/invert/laplacexy/laplacexy.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index 6fb32d5f14..dc7ec8b97e 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -26,7 +27,7 @@ static PetscErrorCode laplacePCapply(PC pc,Vec x,Vec y) { } LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) - : localmesh(m==nullptr ? mesh : m), location(loc) { + : localmesh(m==nullptr ? bout::globals::mesh : m), location(loc) { Timer timer("invert"); if (opt == nullptr) { From 653057f41e0e7cc521ec8244f420d74e71b1fb90 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 2 Jan 2019 12:29:30 +0000 Subject: [PATCH 0550/1783] Change dump->bout::globals::dump in boutcore --- tools/pylib/_boutcore_build/helper.h.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/pylib/_boutcore_build/helper.h.in b/tools/pylib/_boutcore_build/helper.h.in index 4e4e0384ce..f06ff0ab65 100644 --- a/tools/pylib/_boutcore_build/helper.h.in +++ b/tools/pylib/_boutcore_build/helper.h.in @@ -88,7 +88,7 @@ public: solver->setModel(this); bout_monitor = new BoutMonitor(); solver->addMonitor(bout_monitor, Solver::BACK); - solver->outputVars(dump); + solver->outputVars(bout::globals::dump); }; void free(){ delete solver; @@ -101,7 +101,7 @@ public: _rhs=__rhs; }; void solve(){ - //solver->outputVars(dump); + //solver->outputVars(bout::globals::dump); solver->solve(); } Solver * getSolver(){ @@ -121,7 +121,7 @@ void throw_BoutException(std::string err){ } Datafile * c_get_global_datafile(){ - return &dump; + return &bout::globals::dump; } EOF From 8d762d735fe1a94090794cba97696831df0fed3a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 12:01:25 +0000 Subject: [PATCH 0551/1783] Move 'using namespace bout::globals' to bout.hxx Tests/examples that define their own main function still import bout.hxx, so this is the appropriate place for the 'using' statement. Remove '#include ' from difops.cxx; it should not be included anywhere within the library except in bout++.cxx. --- include/bout.hxx | 7 +++++++ include/bout/physicsmodel.hxx | 7 ------- src/bout++.cxx | 5 ++++- src/mesh/difops.cxx | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index 921d81bc7f..28fe47da09 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -65,6 +65,13 @@ const BoutReal BOUT_VERSION = BOUT_VERSION_DOUBLE; ///< Version number +#ifndef BOUT_NO_USING_NAMESPACE_BOUTGLOBALS +// Include using statement by default in user code. +// Macro allows us to include bout.hxx or physicsmodel.hxx without the using +// statement in library code. +using namespace bout::globals; +#endif // BOUT_NO_USING_NAMESPACE_BOUTGLOBALS + // BOUT++ main functions /*! diff --git a/include/bout/physicsmodel.hxx b/include/bout/physicsmodel.hxx index 13db3e8a8c..459ef68112 100644 --- a/include/bout/physicsmodel.hxx +++ b/include/bout/physicsmodel.hxx @@ -44,13 +44,6 @@ class PhysicsModel; #include "unused.hxx" #include "bout/macro_for_each.hxx" -#ifndef BOUT_NO_USING_NAMESPACE_BOUTGLOBALS -// Include using statement by default in user code. -// Macro allows us to include physicsmodel.hxx without the using statement in -// library code. -using namespace bout::globals; -#endif // BOUT_NO_USING_NAMESPACE_BOUTGLOBALS - /*! Base class for physics models */ diff --git a/src/bout++.cxx b/src/bout++.cxx index 8dfd6c75f1..53a5e45c39 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -44,13 +44,16 @@ const char DEFAULT_LOG[] = "BOUT.log"; #include "mpi.h" #include -#include #include #include #include #include #include +#define BOUT_NO_USING_NAMESPACE_BOUTGLOBALS +#include +#undef BOUT_NO_USING_NAMESPACE_BOUTGLOBALS + #include #include diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index b76f892e22..b3ba1cc95f 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -24,7 +24,7 @@ **************************************************************************/ #include -#include +#include #include #include #include From de8552f0a953a6bae2a7c3a95a62783fec3246a5 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 00:06:25 +0000 Subject: [PATCH 0552/1783] Forward-declare Mesh in datafile.hxx --- include/datafile.hxx | 1 + 1 file changed, 1 insertion(+) diff --git a/include/datafile.hxx b/include/datafile.hxx index 97a5b8c299..008b140a85 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -26,6 +26,7 @@ class Datafile; #include #include +class Mesh; #include #include From 0e204f0fc5360cb57e1256fcb685dd0c1d80b055 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 09:50:20 +0000 Subject: [PATCH 0553/1783] Remove unused localmesh variables in Field2D and Field3D --- src/field/field2d.cxx | 2 -- src/field/field3d.cxx | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index e13f121570..d8a6a08375 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -560,8 +560,6 @@ void checkData(const Field2D &f, REGION region) { #if CHECK > 2 void invalidateGuards(Field2D &var) { - Mesh *localmesh = var.getMesh(); - BOUT_FOR(i, var.getRegion("RGN_GUARDS")) { var[i] = BoutNaN; } } #endif diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 44141b0b01..b41177e1ef 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -1094,8 +1094,6 @@ Field2D DC(const Field3D &f, REGION rgn) { #if CHECK > 2 void invalidateGuards(Field3D &var) { - Mesh *localmesh = var.getMesh(); - BOUT_FOR(i, var.getRegion("RGN_GUARDS")) { var[i] = BoutNaN; } } #endif From 146f60b983c5cc1bbe95cc467554243698e0b743 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 14:14:45 +0000 Subject: [PATCH 0554/1783] Convert test-petsc_laplace to have mesh in input file Also set ny=1, myg=1. --- .../integrated/test-petsc_laplace/data/BOUT.inp | 7 +++++-- .../test-petsc_laplace/grids/flat_grid.nc | Bin 13744 -> 0 bytes 2 files changed, 5 insertions(+), 2 deletions(-) delete mode 100644 tests/integrated/test-petsc_laplace/grids/flat_grid.nc diff --git a/tests/integrated/test-petsc_laplace/data/BOUT.inp b/tests/integrated/test-petsc_laplace/data/BOUT.inp index 2fa9cca300..f152111b41 100644 --- a/tests/integrated/test-petsc_laplace/data/BOUT.inp +++ b/tests/integrated/test-petsc_laplace/data/BOUT.inp @@ -1,8 +1,11 @@ mz = 129 -#MYG = 0 -grid = "grids/flat_grid.nc" +MYG = 0 dump_format = "nc" +[mesh] +nx = 132 +ny = 1 + [mesh:ddx] first=C4 second=C4 diff --git a/tests/integrated/test-petsc_laplace/grids/flat_grid.nc b/tests/integrated/test-petsc_laplace/grids/flat_grid.nc deleted file mode 100644 index 1d09c4a7b4c6dca7c491384863222714116407d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13744 zcmeI3!AiqG5QfvF*rGjn@ZiD29`qDiITk3Gs2d7r=jS2>9UBQ3v*`K zZbp44qqRh8jXB3gAWoxs55iXy56t?rTzpkNmV3}QKp)Tt^a0-i9DoCG01m(bH~ Date: Wed, 19 Dec 2018 15:49:39 +0000 Subject: [PATCH 0555/1783] Don't include mesh.hxx in globals.hxx Forward declare class Mesh instead. Requires explicitly including mesh.hxx in several other files, plus a few other extra explicit includes. --- include/bout.hxx | 1 + include/bout/fv_ops.hxx | 1 + include/bout/invertable_operator.hxx | 1 + include/globals.hxx | 3 ++- src/field/field2d.cxx | 1 + src/field/field_data.cxx | 1 + src/field/fieldperp.cxx | 3 +-- src/field/initialprofiles.cxx | 3 +++ src/field/vecops.cxx | 2 ++ src/fileio/datafile.cxx | 2 ++ src/fileio/dataformat.cxx | 1 + src/fileio/formatfactory.cxx | 1 + src/fileio/impls/hdf5/h5_format.cxx | 1 + src/fileio/impls/netcdf/nc_format.cxx | 1 + src/fileio/impls/netcdf4/ncxx4.cxx | 1 + src/invert/lapack_routines.cxx | 1 + src/invert/laplace/impls/cyclic/cyclic_laplace.cxx | 1 + src/invert/laplace/impls/multigrid/multigrid_laplace.cxx | 1 + src/invert/laplace/impls/pdd/pdd.hxx | 1 + src/invert/laplace/impls/petsc/petsc_laplace.cxx | 1 + src/invert/laplace/impls/serial_band/serial_band.cxx | 1 + src/invert/laplace/impls/serial_tri/serial_tri.cxx | 1 + src/invert/laplace/impls/shoot/shoot_laplace.cxx | 1 + src/invert/laplace/impls/spt/spt.cxx | 1 + src/invert/laplace/invert_laplace.cxx | 1 + src/mesh/boundary_factory.cxx | 1 + src/mesh/boundary_region.cxx | 1 + src/mesh/boundary_standard.cxx | 1 + src/physics/gyro_average.cxx | 1 + src/physics/physicsmodel.cxx | 2 ++ src/physics/smoothing.cxx | 1 + src/physics/sourcex.cxx | 2 ++ src/solver/impls/imex-bdf2/imex-bdf2.cxx | 1 + src/solver/impls/pvode/pvode.cxx | 1 + tools/pylib/_boutcore_build/helper.cxx.in | 1 + 35 files changed, 42 insertions(+), 3 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index 28fe47da09..278a2a7fa2 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -38,6 +38,7 @@ #include "boutcomm.hxx" +#include #include "globals.hxx" #include "field2d.hxx" diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index 797506c20d..8015d97f0f 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -10,6 +10,7 @@ #include "../vector2d.hxx" #include "../utils.hxx" +#include namespace FV { /*! diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index d46fa17278..e5650f70c3 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -35,6 +35,7 @@ class InvertableOperator; #ifdef BOUT_HAS_PETSC +#include #include #include #include diff --git a/include/globals.hxx b/include/globals.hxx index 5763ebe34d..88bab32731 100644 --- a/include/globals.hxx +++ b/include/globals.hxx @@ -27,10 +27,11 @@ #ifndef __GLOBALS_H__ #define __GLOBALS_H__ -#include "bout/mesh.hxx" #include "datafile.hxx" #include "bout/macro_for_each.hxx" +class Mesh; + namespace bout { namespace globals { #ifndef GLOBALORIGIN diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index d8a6a08375..3016957eee 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -39,6 +39,7 @@ #include #include +#include #include #include diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 9cb00a34a0..8282f9cda4 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -1,4 +1,5 @@ +#include #include #include #include diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index e184bfc29a..6dc281e723 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -28,6 +28,7 @@ #include +#include #include #include #include @@ -542,8 +543,6 @@ void checkData(const FieldPerp &f, REGION region) { #if CHECK > 2 void invalidateGuards(FieldPerp &var) { - Mesh *localmesh = var.getMesh(); - BOUT_FOR(i, var.getRegion("RGN_GUARDS")) { var[i] = BoutNaN; } } #endif diff --git a/src/field/initialprofiles.cxx b/src/field/initialprofiles.cxx index 16b0fbc156..5fa35f98bb 100644 --- a/src/field/initialprofiles.cxx +++ b/src/field/initialprofiles.cxx @@ -36,6 +36,9 @@ * **************************************************************************/ +#include +#include +#include #include #include #include diff --git a/src/field/vecops.cxx b/src/field/vecops.cxx index a14855a5ab..fcc3fb155e 100644 --- a/src/field/vecops.cxx +++ b/src/field/vecops.cxx @@ -24,6 +24,7 @@ * **************************************************************************/ +#include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include /************************************************************************** * Gradient operators diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 9f57c39944..80310d20d3 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -36,9 +36,11 @@ //#include "mpi.h" // For MPI_Wtime() #include +#include #include #include #include +#include #include #include #include diff --git a/src/fileio/dataformat.cxx b/src/fileio/dataformat.cxx index 2a9eb6069b..cf09ea170b 100644 --- a/src/fileio/dataformat.cxx +++ b/src/fileio/dataformat.cxx @@ -1,4 +1,5 @@ +#include #include #include #include diff --git a/src/fileio/formatfactory.cxx b/src/fileio/formatfactory.cxx index 2de3ca1661..d2ee7fd8f8 100644 --- a/src/fileio/formatfactory.cxx +++ b/src/fileio/formatfactory.cxx @@ -12,6 +12,7 @@ #include #include +#include #include FormatFactory *FormatFactory::instance = nullptr; diff --git a/src/fileio/impls/hdf5/h5_format.cxx b/src/fileio/impls/hdf5/h5_format.cxx index fbed69b0dc..b938a52202 100644 --- a/src/fileio/impls/hdf5/h5_format.cxx +++ b/src/fileio/impls/hdf5/h5_format.cxx @@ -30,6 +30,7 @@ #include #include +#include #include #include #include diff --git a/src/fileio/impls/netcdf/nc_format.cxx b/src/fileio/impls/netcdf/nc_format.cxx index e06d564203..8e96547e44 100644 --- a/src/fileio/impls/netcdf/nc_format.cxx +++ b/src/fileio/impls/netcdf/nc_format.cxx @@ -28,6 +28,7 @@ #include #include +#include #include #include diff --git a/src/fileio/impls/netcdf4/ncxx4.cxx b/src/fileio/impls/netcdf4/ncxx4.cxx index 8591620496..a1c5c0e6e3 100644 --- a/src/fileio/impls/netcdf4/ncxx4.cxx +++ b/src/fileio/impls/netcdf4/ncxx4.cxx @@ -24,6 +24,7 @@ #ifdef NCDF4 +#include #include #include #include diff --git a/src/invert/lapack_routines.cxx b/src/invert/lapack_routines.cxx index 3efbcf1bd8..ce000e7d0b 100644 --- a/src/invert/lapack_routines.cxx +++ b/src/invert/lapack_routines.cxx @@ -38,6 +38,7 @@ #include #include #include +#include #ifdef LAPACK diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index af950b7cbe..a0d2d523ae 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -35,6 +35,7 @@ #include #include +#include #include #include #include diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index 1ff40e9b0b..86b912154f 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -28,6 +28,7 @@ **************************************************************************/ #include "multigrid_laplace.hxx" +#include #include #include diff --git a/src/invert/laplace/impls/pdd/pdd.hxx b/src/invert/laplace/impls/pdd/pdd.hxx index 76e54e737e..e25354809e 100644 --- a/src/invert/laplace/impls/pdd/pdd.hxx +++ b/src/invert/laplace/impls/pdd/pdd.hxx @@ -34,6 +34,7 @@ class LaplacePDD; #ifndef __LAPLACE_PDD_H__ #define __LAPLACE_PDD_H__ +#include #include #include #include diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.cxx b/src/invert/laplace/impls/petsc/petsc_laplace.cxx index c986b25910..fe9a4f2c62 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.cxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.cxx @@ -27,6 +27,7 @@ #include "petsc_laplace.hxx" +#include #include #include #include diff --git a/src/invert/laplace/impls/serial_band/serial_band.cxx b/src/invert/laplace/impls/serial_band/serial_band.cxx index f773f90996..38c0e3ffa3 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.cxx +++ b/src/invert/laplace/impls/serial_band/serial_band.cxx @@ -27,6 +27,7 @@ #include #include "serial_band.hxx" +#include #include #include #include diff --git a/src/invert/laplace/impls/serial_tri/serial_tri.cxx b/src/invert/laplace/impls/serial_tri/serial_tri.cxx index f2d98e3f22..efc40e7126 100644 --- a/src/invert/laplace/impls/serial_tri/serial_tri.cxx +++ b/src/invert/laplace/impls/serial_tri/serial_tri.cxx @@ -27,6 +27,7 @@ #include "globals.hxx" #include "serial_tri.hxx" +#include #include #include #include diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.cxx b/src/invert/laplace/impls/shoot/shoot_laplace.cxx index 405fef96be..6a813409ef 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.cxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.cxx @@ -32,6 +32,7 @@ */ #include "shoot_laplace.hxx" +#include #include #include #include diff --git a/src/invert/laplace/impls/spt/spt.cxx b/src/invert/laplace/impls/spt/spt.cxx index 705f198c29..9b4d9e7452 100644 --- a/src/invert/laplace/impls/spt/spt.cxx +++ b/src/invert/laplace/impls/spt/spt.cxx @@ -32,6 +32,7 @@ */ #include +#include #include #include #include diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index c106a7a52e..ffa19a24e6 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -31,6 +31,7 @@ * */ +#include #include #include #include diff --git a/src/mesh/boundary_factory.cxx b/src/mesh/boundary_factory.cxx index 29f7df07a0..e2454d7371 100644 --- a/src/mesh/boundary_factory.cxx +++ b/src/mesh/boundary_factory.cxx @@ -1,6 +1,7 @@ #include #include #include +#include #include #include diff --git a/src/mesh/boundary_region.cxx b/src/mesh/boundary_region.cxx index bee26d439e..e1bdd88201 100644 --- a/src/mesh/boundary_region.cxx +++ b/src/mesh/boundary_region.cxx @@ -1,4 +1,5 @@ +#include #include #include #include diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 6e9e6a250f..ff76562006 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/src/physics/gyro_average.cxx b/src/physics/gyro_average.cxx index a71fa23751..b8f1a0cd83 100644 --- a/src/physics/gyro_average.cxx +++ b/src/physics/gyro_average.cxx @@ -27,6 +27,7 @@ * **************************************************************/ +#include #include #include #include diff --git a/src/physics/physicsmodel.cxx b/src/physics/physicsmodel.cxx index 6b408d8a0b..6235b1be4c 100644 --- a/src/physics/physicsmodel.cxx +++ b/src/physics/physicsmodel.cxx @@ -32,6 +32,8 @@ #include #undef BOUT_NO_USING_NAMESPACE_BOUTGLOBALS +#include + PhysicsModel::PhysicsModel() : solver(nullptr), modelMonitor(this), splitop(false), userprecon(nullptr), userjacobian(nullptr), initialised(false) { diff --git a/src/physics/smoothing.cxx b/src/physics/smoothing.cxx index ee8888282b..77326e2cb8 100644 --- a/src/physics/smoothing.cxx +++ b/src/physics/smoothing.cxx @@ -32,6 +32,7 @@ #include +#include #include #include #include diff --git a/src/physics/sourcex.cxx b/src/physics/sourcex.cxx index 284bb0cb2b..1a549e50dc 100644 --- a/src/physics/sourcex.cxx +++ b/src/physics/sourcex.cxx @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include diff --git a/src/solver/impls/imex-bdf2/imex-bdf2.cxx b/src/solver/impls/imex-bdf2/imex-bdf2.cxx index e586326d27..b3dc3cf311 100644 --- a/src/solver/impls/imex-bdf2/imex-bdf2.cxx +++ b/src/solver/impls/imex-bdf2/imex-bdf2.cxx @@ -3,6 +3,7 @@ #include "imex-bdf2.hxx" +#include #include #include #include diff --git a/src/solver/impls/pvode/pvode.cxx b/src/solver/impls/pvode/pvode.cxx index 3ff6b40207..be9d4cbfa9 100644 --- a/src/solver/impls/pvode/pvode.cxx +++ b/src/solver/impls/pvode/pvode.cxx @@ -27,6 +27,7 @@ #ifdef BOUT_HAS_PVODE +#include #include #include #include diff --git a/tools/pylib/_boutcore_build/helper.cxx.in b/tools/pylib/_boutcore_build/helper.cxx.in index 41e79c2385..fb6f9660b6 100644 --- a/tools/pylib/_boutcore_build/helper.cxx.in +++ b/tools/pylib/_boutcore_build/helper.cxx.in @@ -3,6 +3,7 @@ cat < #include #include +#include #include EOF for ftype in "Field3D" "Field2D" From 71d0a9eb64228a7eca1420e566050eb93649fc41 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 16:04:47 +0000 Subject: [PATCH 0556/1783] Use nullptr instead of bout::globals::mesh as default argument Handle the nullptr case in the initializer list instead. --- include/invert_laplace.hxx | 2 +- src/invert/laplace/invert_laplace.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index fa1d7d1ec7..9ec16ec4a0 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -105,7 +105,7 @@ const int INVERT_OUT_RHS = 32768; ///< Use input value in RHS at outer boundary /// Base class for Laplacian inversion class Laplacian { public: - Laplacian(Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh* mesh_in = bout::globals::mesh); + Laplacian(Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh* mesh_in = nullptr); virtual ~Laplacian() {} /// Set coefficients for inversion. Re-builds matrices if necessary diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index ffa19a24e6..e2f4760100 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -53,7 +53,7 @@ /// Laplacian inversion initialisation. Called once at the start to get settings Laplacian::Laplacian(Options *options, const CELL_LOC loc, Mesh *mesh_in) - : location(loc), localmesh(mesh_in) { + : location(loc), localmesh(mesh_in==nullptr ? bout::globals::mesh : mesh_in) { if (options == nullptr) { // Use the default options From 32b172c029aae962ead6fa6a12eafc8b40cf0b50 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 19 Dec 2018 18:25:17 +0000 Subject: [PATCH 0557/1783] nullptr default Mesh* argument to Laplacian implementations constructors nullptr is handled by the base Laplacian class constructor and converted to bout::globals::mesh. --- src/invert/laplace/impls/cyclic/cyclic_laplace.hxx | 2 +- src/invert/laplace/impls/multigrid/multigrid_laplace.hxx | 2 +- src/invert/laplace/impls/mumps/mumps_laplace.hxx | 4 ++-- src/invert/laplace/impls/naulin/naulin_laplace.hxx | 2 +- src/invert/laplace/impls/pdd/pdd.hxx | 2 +- src/invert/laplace/impls/petsc/petsc_laplace.hxx | 4 ++-- src/invert/laplace/impls/serial_band/serial_band.hxx | 2 +- src/invert/laplace/impls/serial_tri/serial_tri.hxx | 2 +- src/invert/laplace/impls/shoot/shoot_laplace.hxx | 2 +- src/invert/laplace/impls/spt/spt.hxx | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx index 6d94cc8203..d4419dd5f2 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx @@ -44,7 +44,7 @@ class LaplaceCyclic; */ class LaplaceCyclic : public Laplacian { public: - LaplaceCyclic(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); + LaplaceCyclic(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = nullptr); ~LaplaceCyclic(); using Laplacian::setCoefA; diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx index 5b2a6ffd18..e0e05328eb 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx @@ -133,7 +133,7 @@ private: class LaplaceMultigrid : public Laplacian { public: LaplaceMultigrid(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, - Mesh *mesh_in = bout::globals::mesh); + Mesh *mesh_in = nullptr); ~LaplaceMultigrid() {}; void setCoefA(const Field2D &val) override { diff --git a/src/invert/laplace/impls/mumps/mumps_laplace.hxx b/src/invert/laplace/impls/mumps/mumps_laplace.hxx index 75ca899193..82fc082b7e 100644 --- a/src/invert/laplace/impls/mumps/mumps_laplace.hxx +++ b/src/invert/laplace/impls/mumps/mumps_laplace.hxx @@ -36,7 +36,7 @@ class LaplaceMumps; class LaplaceMumps : public Laplacian { public: - LaplaceMumps(Options *UNUSED(opt) = nullptr, const CELL_LOC UNUSED(loc) = CELL_CENTRE, Mesh *UNUSED(mesh_in) = bout::globals::mesh) { + LaplaceMumps(Options *UNUSED(opt) = nullptr, const CELL_LOC UNUSED(loc) = CELL_CENTRE, Mesh *UNUSED(mesh_in) = nullptr) { throw BoutException("Mumps library not available"); } @@ -76,7 +76,7 @@ public: class LaplaceMumps : public Laplacian { public: - LaplaceMumps(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); + LaplaceMumps(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = nullptr); ~LaplaceMumps() { mumps_struc.job = -2; dmumps_c(&mumps_struc); diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.hxx b/src/invert/laplace/impls/naulin/naulin_laplace.hxx index f6cd5b3ba2..d1088722ab 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.hxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.hxx @@ -37,7 +37,7 @@ class LaplaceNaulin; */ class LaplaceNaulin : public Laplacian { public: - LaplaceNaulin(Options *opt = NULL, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); + LaplaceNaulin(Options *opt = NULL, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = nullptr); ~LaplaceNaulin(); // ACoef is not implemented because the delp2solver that we use can probably diff --git a/src/invert/laplace/impls/pdd/pdd.hxx b/src/invert/laplace/impls/pdd/pdd.hxx index e25354809e..62c2031afb 100644 --- a/src/invert/laplace/impls/pdd/pdd.hxx +++ b/src/invert/laplace/impls/pdd/pdd.hxx @@ -41,7 +41,7 @@ class LaplacePDD; class LaplacePDD : public Laplacian { public: - LaplacePDD(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh) + LaplacePDD(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = nullptr) : Laplacian(opt, loc, mesh_in), Acoef(0.0), Ccoef(1.0), Dcoef(1.0), PDD_COMM_XV(123), PDD_COMM_Y(456) { Acoef.setLocation(location); diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.hxx b/src/invert/laplace/impls/petsc/petsc_laplace.hxx index f949ebd169..b71b504f59 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.hxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.hxx @@ -37,7 +37,7 @@ class LaplacePetsc; class LaplacePetsc : public Laplacian { public: - LaplacePetsc(Options *UNUSED(opt) = nullptr, const CELL_LOC UNUSED(loc) = CELL_CENTRE, Mesh *UNUSED(mesh_in) = bout::globals::mesh) { + LaplacePetsc(Options *UNUSED(opt) = nullptr, const CELL_LOC UNUSED(loc) = CELL_CENTRE, Mesh *UNUSED(mesh_in) = nullptr) { throw BoutException("No PETSc solver available"); } @@ -68,7 +68,7 @@ public: class LaplacePetsc : public Laplacian { public: - LaplacePetsc(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); + LaplacePetsc(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = nullptr); ~LaplacePetsc() { KSPDestroy( &ksp ); VecDestroy( &xs ); diff --git a/src/invert/laplace/impls/serial_band/serial_band.hxx b/src/invert/laplace/impls/serial_band/serial_band.hxx index 98607d07a6..41c29b8875 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.hxx +++ b/src/invert/laplace/impls/serial_band/serial_band.hxx @@ -36,7 +36,7 @@ class LaplaceSerialBand; class LaplaceSerialBand : public Laplacian { public: - LaplaceSerialBand(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); + LaplaceSerialBand(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = nullptr); ~LaplaceSerialBand(){}; using Laplacian::setCoefA; diff --git a/src/invert/laplace/impls/serial_tri/serial_tri.hxx b/src/invert/laplace/impls/serial_tri/serial_tri.hxx index 52c025fca9..770b71050d 100644 --- a/src/invert/laplace/impls/serial_tri/serial_tri.hxx +++ b/src/invert/laplace/impls/serial_tri/serial_tri.hxx @@ -35,7 +35,7 @@ class LaplaceSerialTri; class LaplaceSerialTri : public Laplacian { public: - LaplaceSerialTri(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); + LaplaceSerialTri(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = nullptr); ~LaplaceSerialTri(){}; using Laplacian::setCoefA; diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.hxx b/src/invert/laplace/impls/shoot/shoot_laplace.hxx index 5197781ce3..a31780a032 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.hxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.hxx @@ -37,7 +37,7 @@ class LaplaceShoot; class LaplaceShoot : public Laplacian { public: - LaplaceShoot(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); + LaplaceShoot(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = nullptr); ~LaplaceShoot(){}; using Laplacian::setCoefA; diff --git a/src/invert/laplace/impls/spt/spt.hxx b/src/invert/laplace/impls/spt/spt.hxx index 52391df81e..1bdc064b98 100644 --- a/src/invert/laplace/impls/spt/spt.hxx +++ b/src/invert/laplace/impls/spt/spt.hxx @@ -66,7 +66,7 @@ class LaplaceSPT; */ class LaplaceSPT : public Laplacian { public: - LaplaceSPT(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); + LaplaceSPT(Options *opt = nullptr, const CELL_LOC = CELL_CENTRE, Mesh *mesh_in = nullptr); ~LaplaceSPT(); using Laplacian::setCoefA; From caabb9c92d65dc60a2c070ffe027ccea77342273 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sun, 23 Dec 2018 15:49:42 +0000 Subject: [PATCH 0558/1783] Fix some errors, warnings Use bout::globals::mesh in Coordinates, and test_coordinates --- include/bout/invert/laplacexz.hxx | 4 ++-- src/invert/laplacexz/laplacexz.cxx | 2 +- src/mesh/coordinates.cxx | 2 +- tests/unit/mesh/test_coordinates.cxx | 8 +++++++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/include/bout/invert/laplacexz.hxx b/include/bout/invert/laplacexz.hxx index 5bdb3902be..34200a648e 100644 --- a/include/bout/invert/laplacexz.hxx +++ b/include/bout/invert/laplacexz.hxx @@ -39,8 +39,8 @@ class LaplaceXZ { public: LaplaceXZ(Mesh* m = nullptr, Options* UNUSED(options) = nullptr, - const CELL_LOC loc = CELL_CENTRE) - : localmesh(m==nullptr ? mesh : m), location(loc) {} + const CELL_LOC loc = CELL_CENTRE) + : localmesh(m == nullptr ? bout::globals::mesh : m), location(loc) {} virtual ~LaplaceXZ() {} virtual void setCoefs(const Field2D &A, const Field2D &B) = 0; diff --git a/src/invert/laplacexz/laplacexz.cxx b/src/invert/laplacexz/laplacexz.cxx index 1703c0b076..05bba728ca 100644 --- a/src/invert/laplacexz/laplacexz.cxx +++ b/src/invert/laplacexz/laplacexz.cxx @@ -9,7 +9,7 @@ LaplaceXZ* LaplaceXZ::create(Mesh *m, Options *options, const CELL_LOC loc) { if (m == nullptr) { // use global mesh - m = mesh; + m = bout::globals::mesh; } if (options == nullptr) { diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index d6ce7a38a0..e05dbdf7bb 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -788,7 +788,7 @@ const Field3D Coordinates::Grad2_par2(const Field3D &f, CELL_LOC outloc, const s #include // Delp2 uses same coefficients as inversion code -const Field2D Coordinates::Delp2(const Field2D& f, CELL_LOC outloc, bool useFFT) { +const Field2D Coordinates::Delp2(const Field2D& f, CELL_LOC outloc, bool UNUSED(useFFT)) { TRACE("Coordinates::Delp2( Field2D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); diff --git a/tests/unit/mesh/test_coordinates.cxx b/tests/unit/mesh/test_coordinates.cxx index 91781334b9..bb62537011 100644 --- a/tests/unit/mesh/test_coordinates.cxx +++ b/tests/unit/mesh/test_coordinates.cxx @@ -7,7 +7,13 @@ #include "test_extras.hxx" /// Global mesh -extern Mesh *mesh; +namespace bout { +namespace globals { +extern Mesh* mesh; +} +} // namespace bout + +using bout::globals::mesh; using CoordinatesTest = FakeMeshFixture; From d0401ee4e66680122045c352d57609be4e7027ab Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 2 Jan 2019 12:10:27 +0000 Subject: [PATCH 0559/1783] Use forward declares in datafile.hxx Forward declare Field2D, Field3D, Vector2D and Vector3D in datafile.hxx to avoid circular dependencies due to including datafile.hxx in globals.hxx. --- include/datafile.hxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/datafile.hxx b/include/datafile.hxx index 008b140a85..22cbc2c3be 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -15,10 +15,6 @@ class Datafile; #define __DATAFILE_H__ #include "bout_types.hxx" -#include "field2d.hxx" -#include "field3d.hxx" -#include "vector2d.hxx" -#include "vector3d.hxx" #include "options.hxx" #include "bout/macro_for_each.hxx" @@ -27,6 +23,10 @@ class Datafile; #include #include class Mesh; +class Field2D; +class Field3D; +class Vector2D; +class Vector3D; #include #include From 8886ff87fb642c2705f40f4d63397bfee8356b76 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 3 Jan 2019 10:14:27 +0000 Subject: [PATCH 0560/1783] Use bout::globals::dump in SlepcSolver Update SlepcSolver to use 'bout::globals::dump' instead of 'dump'. --- src/solver/impls/slepc/slepc.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index f327137062..aaf5d420c4 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -606,10 +606,10 @@ void SlepcSolver::monitor(PetscInt its, PetscInt nconv, PetscScalar eigr[], output< Date: Thu, 3 Jan 2019 10:26:08 +0000 Subject: [PATCH 0561/1783] Use bout::globals::dump in BOUTMAIN macro BOUTMAIN is defined in physicsmodel.hxx, so a file using it will usually include 'using namespace bout::globals' from physicsmodel.hxx, but in case the 'using' statement is explicitly excluded using the BOUT_NO_USING_NAMESPACE_BOUTGLOBALS macro or if in future the 'using' statement is removed, use the full name 'bout::globals::dump' instead of 'dump'. --- include/bout/physicsmodel.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/physicsmodel.hxx b/include/bout/physicsmodel.hxx index 459ef68112..8f4f3266d1 100644 --- a/include/bout/physicsmodel.hxx +++ b/include/bout/physicsmodel.hxx @@ -311,7 +311,7 @@ private: solver->setModel(model); \ Monitor * bout_monitor = new BoutMonitor(); \ solver->addMonitor(bout_monitor, Solver::BACK); \ - solver->outputVars(dump); \ + solver->outputVars(bout::globals::dump); \ solver->solve(); \ delete model; \ delete solver; \ From c51aee6184f6135e5af0c1ff5b055e01d684e95e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 3 Jan 2019 14:28:47 +0000 Subject: [PATCH 0562/1783] Remove deprecated invert_laplace functions from tests --- tests/MMS/elm-pb/data/BOUT.inp | 5 +- tests/MMS/elm-pb/elm_pb.cxx | 17 +++--- .../test-drift-instability/2fluid.cxx | 59 ++++--------------- .../test-drift-instability/BOUT.inp | 22 ++++--- .../test-interchange-instability/2fluid.cxx | 8 ++- .../data_1/BOUT.inp | 16 +---- .../data_10/BOUT.inp | 13 +--- 7 files changed, 43 insertions(+), 97 deletions(-) diff --git a/tests/MMS/elm-pb/data/BOUT.inp b/tests/MMS/elm-pb/data/BOUT.inp index f4ce5c0d48..74d9b4df11 100644 --- a/tests/MMS/elm-pb/data/BOUT.inp +++ b/tests/MMS/elm-pb/data/BOUT.inp @@ -35,6 +35,8 @@ floats = false # -> Output in double precision [laplace] all_terms = true +inner_boundary_flags = 0 +outer_boundary_flags = 0 ################################################## # derivative methods @@ -140,9 +142,6 @@ viscos_perp = -1.0 # Perpendicular phi_curv = true # Include curvature*Grad(phi) in P equation # gamma = 1.6666 -## field inversion flags -phi_flags = 0 - ################################################## # settings for individual variables # The section "All" defines default settings for all variables diff --git a/tests/MMS/elm-pb/elm_pb.cxx b/tests/MMS/elm-pb/elm_pb.cxx index 3ae0e27594..e89d2a63eb 100644 --- a/tests/MMS/elm-pb/elm_pb.cxx +++ b/tests/MMS/elm-pb/elm_pb.cxx @@ -63,7 +63,8 @@ BoutReal vacuum_pressure; BoutReal vacuum_trans; // Transition width Field3D vac_mask; -int phi_flags; +Laplacian* phi_solver; + bool nonlinear; BoutReal g; // Only if compressible bool phi_curv; @@ -273,9 +274,6 @@ int physics_init(bool restarting) { OPTION(options, phi_curv, true); options->get("gamma", g, 5.0/3.0); - // Field inversion flags - OPTION(options, phi_flags, 0); - OPTION(globalOptions->getSection("solver"), mms, false); if(!include_curvature) @@ -284,6 +282,11 @@ int physics_init(bool restarting) { if(!include_jpar0) J0 = 0.0; + ////////////////////////////////////////////////////////////// + // INITIALIZE LAPLACIAN SOLVER + + phi_solver = Laplacian::create(); + ////////////////////////////////////////////////////////////// // SHIFTED RADIAL COORDINATES @@ -468,7 +471,7 @@ int physics_init(bool restarting) { U = where(P0 - vacuum_pressure, U, 0.0); // Phi should be consistent with U - phi = invert_laplace(U, phi_flags, NULL); + phi = phi_solver->solve(U); //if(diamag) { //phi -= 0.5*dnorm * P / B0; @@ -530,9 +533,9 @@ int physics_run(BoutReal t) { if(mms) { // Solve for potential, adding a source term Field3D phiS = FieldFactory::get()->create3D("phi:source", Options::getRoot(), mesh, CELL_CENTRE, t); - phi = invert_laplace(U + phiS, phi_flags, NULL); + phi = phi_solver->solve(U + phiS, phi); }else { - phi = invert_laplace(U, phi_flags, NULL); + phi = phi_solver->solve(U, phi); } if(diamag) { diff --git a/tests/integrated/test-drift-instability/2fluid.cxx b/tests/integrated/test-drift-instability/2fluid.cxx index d1e45da8ed..75bade9a81 100644 --- a/tests/integrated/test-drift-instability/2fluid.cxx +++ b/tests/integrated/test-drift-instability/2fluid.cxx @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -51,12 +52,9 @@ BoutReal zeff, nu_perp; bool evolve_rho, evolve_te, evolve_ni, evolve_ajpar, evolve_vi, evolve_ti; BoutReal ShearFactor; -int phi_flags, apar_flags; // Inversion flags - -// Field routines -int solve_phi_tridag(Field3D &r, Field3D &p, int flags); -int solve_apar_tridag(Field3D &aj, Field3D &ap, int flags); - +// Inversion objects +Laplacian* phi_solver; +Laplacian* apar_solver; FieldGroup comms; // Group of variables for communications @@ -119,9 +117,6 @@ int physics_init(bool UNUSED(restarting)) { OPTION(options, nu_perp, 0.0); OPTION(options, ShearFactor, 1.0); - OPTION(options, phi_flags, 0); - OPTION(options, apar_flags, 0); - (globalOptions->getSection("Ni"))->get("evolve", evolve_ni, true); (globalOptions->getSection("rho"))->get("evolve", evolve_rho, true); (globalOptions->getSection("vi"))->get("evolve", evolve_vi, true); @@ -132,6 +127,12 @@ int physics_init(bool UNUSED(restarting)) { if(ZeroElMass) evolve_ajpar = false; // Don't need ajpar - calculated from ohm's law + /*************** INITIALIZE LAPLACIAN SOLVERS ********/ + phi_solver = Laplacian::create(globalOptions->getSection("phisolver")); + if (!estatic && !ZeroElMass) { + apar_solver = Laplacian::create(globalOptions->getSection("aparsolver")); + } + /************* SHIFTED RADIAL COORDINATES ************/ bool ShiftXderivs; @@ -314,13 +315,13 @@ int physics_init(bool UNUSED(restarting)) { int physics_run(BoutReal UNUSED(t)) { // Solve EM fields - solve_phi_tridag(rho, phi, phi_flags); + phi = phi_solver->solve(rho, phi); if(estatic || ZeroElMass) { // Electrostatic operation Apar = 0.0; }else { - solve_apar_tridag(Ajpar, Apar, apar_flags); // Linear Apar solver + Apar = apar_solver->solve(Ajpar, Apar); // Linear Apar solver } // Communicate variables @@ -421,39 +422,3 @@ int physics_run(BoutReal UNUSED(t)) { return(0); } - -/******************************************************************************* - * FAST LINEAR FIELD SOLVERS - *******************************************************************************/ - -#include - -// Performs inversion of rho (r) to get phi (p) -int solve_phi_tridag(Field3D &r, Field3D &p, int flags) { - - //output.write("Solving phi: %e, %e -> %e\n", max(abs(r)), min(Ni0), max(abs(r/Ni0))); - - if(invert_laplace(r/Ni0, p, flags, NULL)) { - return 1; - } - - //Field3D pertPi = Ti*Ni0 + Ni*Ti0; - //p -= pertPi/Ni0; - return(0); -} - -int solve_apar_tridag(Field3D &aj, Field3D &ap, int flags) { - static Field2D a; - static int set = 0; - - if(set == 0) { - // calculate a - a = (-0.5*beta_p/fmei)*Ni0; - set = 1; - } - - if(invert_laplace(a*(Vi - aj), ap, flags, &a)) - return 1; - - return(0); -} diff --git a/tests/integrated/test-drift-instability/BOUT.inp b/tests/integrated/test-drift-instability/BOUT.inp index 366ac4e454..17faaf6bb1 100644 --- a/tests/integrated/test-drift-instability/BOUT.inp +++ b/tests/integrated/test-drift-instability/BOUT.inp @@ -50,9 +50,18 @@ first = C4 second = C4 upwind = W3 -[laplace] +[phisolver] include_yguards = true all_terms = false +inner_boundary_flags = 0 +outer_boundary_flags = 0 + +[aparsolver] +include_yguards = true +all_terms = false +inner_boundary_flags = 0 +outer_boundary_flags = 0 + ################################################## # Solver settings @@ -78,17 +87,6 @@ nu_perp = 1.0e-20 ShearFactor = 0.0 -# field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -phi_flags = 0 # inversion flags for phi -apar_flags = 0 # flags for apar inversion - ################################################## # settings for individual variables # The section "All" defines default settings for all variables diff --git a/tests/integrated/test-interchange-instability/2fluid.cxx b/tests/integrated/test-interchange-instability/2fluid.cxx index ff1fd8524b..d4eaabe76b 100644 --- a/tests/integrated/test-interchange-instability/2fluid.cxx +++ b/tests/integrated/test-interchange-instability/2fluid.cxx @@ -31,7 +31,8 @@ class Interchange : public PhysicsModel { // Parameters BoutReal Te_x, Ti_x, Ni_x, Vi_x, bmag, rho_s, AA, ZZ, wci; - int phi_flags; // Inversion flags + // Laplacian inversion + Laplacian* phi_solver; Coordinates *coord; protected: @@ -84,7 +85,8 @@ class Interchange : public PhysicsModel { BoutReal ShearFactor; OPTION(options, ShearFactor, 1.0); - OPTION(options, phi_flags, 0); + /*************** INITIALIZE LAPLACE SOLVER ***********/ + phi_solver = Laplacian::create(); /************* SHIFTED RADIAL COORDINATES ************/ bool ShiftXderivs; @@ -168,7 +170,7 @@ class Interchange : public PhysicsModel { int rhs(BoutReal t) { // Solve EM fields - invert_laplace(rho / Ni0, phi, phi_flags, NULL); + phi = phi_solver->solve(rho / Ni0, phi); // Communicate variables mesh->communicate(rho, Ni, phi); diff --git a/tests/integrated/test-interchange-instability/data_1/BOUT.inp b/tests/integrated/test-interchange-instability/data_1/BOUT.inp index a5f084ec4d..12519ca368 100644 --- a/tests/integrated/test-interchange-instability/data_1/BOUT.inp +++ b/tests/integrated/test-interchange-instability/data_1/BOUT.inp @@ -27,8 +27,6 @@ grid = "slab.6b5.r1.cdl" dump_format = "nc" # Output format. nc = NetCDF -non_uniform = false - ################################################## # derivative methods @@ -53,7 +51,8 @@ upwind = W3 [laplace] include_yguards = true all_terms = false - +inner_boundary_flags = 0 # inner boundary inversion flags +outer_boundary_flags = 0 # outer boundary inversion flags ################################################## # Solver settings @@ -83,17 +82,6 @@ nu_perp = 1.0e-20 ShearFactor = 0.0 -# field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -phi_flags = 0 # inversion flags for phi -apar_flags = 0 # flags for apar inversion - ################################################## # settings for individual variables # The section "All" defines default settings for all variables diff --git a/tests/integrated/test-interchange-instability/data_10/BOUT.inp b/tests/integrated/test-interchange-instability/data_10/BOUT.inp index 8ffbafddf1..0a0672ff54 100644 --- a/tests/integrated/test-interchange-instability/data_10/BOUT.inp +++ b/tests/integrated/test-interchange-instability/data_10/BOUT.inp @@ -51,6 +51,8 @@ upwind = W3 [laplace] include_yguards = true all_terms = false +inner_boundary_flags = 0 # inner boundary inversion flags +outer_boundary_flags = 0 # outer boundary inversion flags ################################################## # Solver settings @@ -80,17 +82,6 @@ nu_perp = 1.0e-20 ShearFactor = 0.0 -# field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -phi_flags = 0 # inversion flags for phi -apar_flags = 0 # flags for apar inversion - ################################################## # settings for individual variables # The section "All" defines default settings for all variables From 7e02601278d844a3b42a6b2bc650fd9e92e2a2c2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 3 Jan 2019 14:29:20 +0000 Subject: [PATCH 0563/1783] Fix elm-pb MMS test boundary conditions Previously were using a 'shifted' modifier for the boundary conditions which is no longer implemented. It has been replaced with 'toFieldAligned' which transforms from field aligned to orthogonal coordinates, applies the boundary conditions and then transforms back to field aligned. --- tests/MMS/elm-pb/data/BOUT.inp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/MMS/elm-pb/data/BOUT.inp b/tests/MMS/elm-pb/data/BOUT.inp index 74d9b4df11..821da5042c 100644 --- a/tests/MMS/elm-pb/data/BOUT.inp +++ b/tests/MMS/elm-pb/data/BOUT.inp @@ -175,7 +175,7 @@ ddy = -0.01*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y source = -0.00064*x^2*(y + 0.1*sin(y))*(632812.5*y + 63281.25*sin(y) + 2531250.0)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) - 0.18*x*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^3*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) - (0.01*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*(-0.001*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))))*sin(6.28318530717959*x)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.01*((-1.125*x*(y + 0.1*sin(y))*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + (1125.0*x*(y + 0.1*sin(y)) - 562.5)*cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))))*sin(6.28318530717959*x) + 3534.29173528852*(sin(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))) + 0.001*cos(-y + z + (x^2 + 2)*(y + 0.1*sin(y))))*cos(6.28318530717959*x))*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))))*sqrt(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2)) + 0.001*(202500.0*x^2*(y + 0.1*sin(y))^2/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 6.25*(x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) + 0.002*(101250.0*x^2*(y + 0.1*sin(y))/((x^2 + 2)^2*(0.1*cos(y) + 1)) + 1.25*(x^2 + 2)^2*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)*sin(y) - 3.75*(x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2*sin(y) - 50625.0*(y + 0.1*sin(y))/((x^2 + 2)*(0.1*cos(y) + 1)))*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) + 0.016*(3.16049382716049e-6*x^2*(632812.5*y + 63281.25*sin(y) + 2531250.0)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) + sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))))*(6328.125*y + 632.8125*sin(y) + 25312.5)/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 2.0*((x^2 + 2)*(0.1*cos(y) + 1)*cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.001*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))))*sin(6.28318530717959*x)/sqrt((x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2) #bndry_all = dirichlet_o2(Psi:solution) -bndry_all = shifted(dirichlet_o2(Psi:solution_zshift)) +bndry_all = toFieldAligned(dirichlet_o2(Psi:solution_zshift)) [U] # vorticity solution = 2.0*cos(2*t)*cos(x + 4*y - z - (x^2 + 2)*(y + 0.1*sin(y))) @@ -188,7 +188,7 @@ ddy = -2.0*(-(x^2 + 2)*(0.1*cos(y) + 1) + 4)*sin(x + 4*y - z - (x^2 + 2)*(y + 0. source = (-(0.01*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*(-0.0064*x^2*(y + 0.1*sin(y))*(632812.5*y + 63281.25*sin(y) + 2531250.0)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 1.8*x*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^3*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 0.01*(202500.0*x^2*(y + 0.1*sin(y))^2/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 6.25*(x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.02*(101250.0*x^2*(y + 0.1*sin(y))/((x^2 + 2)^2*(0.1*cos(y) + 1)) + 1.25*(x^2 + 2)^2*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)*sin(y) - 3.75*(x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2*sin(y) - 50625.0*(y + 0.1*sin(y))/((x^2 + 2)*(0.1*cos(y) + 1)))*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) - 0.16*(-3.16049382716049e-6*x^2*(632812.5*y + 63281.25*sin(y) + 2531250.0)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) + cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))))*(6328.125*y + 632.8125*sin(y) + 25312.5)/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2))*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.01*(-14.4*x^3*(y + 0.1*sin(y))*(632812.5*y + 63281.25*sin(y) + 2531250.0)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^3*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) - 0.0064*x^2*(y + 0.1*sin(y))*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*(632812.5*y + 63281.25*sin(y) + 2531250.0)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) - 6075.0*x^2*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^4*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 7.2*x*(y + 0.1*sin(y))*(632812.5*y + 63281.25*sin(y) + 2531250.0)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 22.5*x*(101250.0*x^2*(y + 0.1*sin(y))/((x^2 + 2)^2*(0.1*cos(y) + 1)) + 1.25*(x^2 + 2)^2*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)*sin(y) - 3.75*(x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2*sin(y) - 50625.0*(y + 0.1*sin(y))/((x^2 + 2)*(0.1*cos(y) + 1)))*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) + 1.8*x*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)^2*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^3*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 360.0*x*(3.16049382716049e-6*x^2*(632812.5*y + 63281.25*sin(y) + 2531250.0)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) + sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))))*(6328.125*y + 632.8125*sin(y) + 25312.5)/((x^2 + 2)^3*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 1.8*x*(632812.5*y + 63281.25*sin(y) + 2531250.0)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^3*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 0.01*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*(202500.0*x^2*(y + 0.1*sin(y))^2/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 6.25*(x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.01*(-455625000.0*x^3*(y + 0.1*sin(y))^2/((x^2 + 2)^3*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 14062.5*x*(x^2 + 2)*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2 - 2250.0*x/((x^2 + 2)*(-0.2*cos(y) + 2)^2) + 227812500.0*x*(y + 0.1*sin(y))^2/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2))*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.02*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*(101250.0*x^2*(y + 0.1*sin(y))/((x^2 + 2)^2*(0.1*cos(y) + 1)) + 1.25*(x^2 + 2)^2*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)*sin(y) - 3.75*(x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2*sin(y) - 50625.0*(y + 0.1*sin(y))/((x^2 + 2)*(0.1*cos(y) + 1)))*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) - 0.02*(-227812500.0*x^3*(y + 0.1*sin(y))/((x^2 + 2)^3*(0.1*cos(y) + 1)) + 2812.5*x*(x^2 + 2)*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)*sin(y) - 8437.5*x*(x^2 + 2)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2*sin(y) + 170859375.0*x*(y + 0.1*sin(y))/((x^2 + 2)^2*(0.1*cos(y) + 1)))*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) - 0.16*(6328.125*y + 632.8125*sin(y) + 25312.5)*(-3.16049382716049e-6*x^2*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*(632812.5*y + 63281.25*sin(y) + 2531250.0)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) + 0.00355555555555556*x*(632812.5*y + 63281.25*sin(y) + 2531250.0)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) + (1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))))/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 1012.5*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^3*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2))*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))))*sqrt(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2)) + 2.0*(-0.0064*x^2*(y + 0.1*sin(y))*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*(632812.5*y + 63281.25*sin(y) + 2531250.0)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 0.0064*x^2*(y + 0.1*sin(y))*(63281.25*cos(y) + 632812.5)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 0.00128*x^2*(y + 0.1*sin(y))*(632812.5*y + 63281.25*sin(y) + 2531250.0)*sin(y)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^3) - 0.00256*x^2*(y + 0.1*sin(y))*(632812.5*y + 63281.25*sin(y) + 2531250.0)*sin(y)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^2*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)^2) + 0.0064*x^2*(632812.5*y + 63281.25*sin(y) + 2531250.0)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) + 2025.0*x^2*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^3*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) + 1.8*x*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^3*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 0.36*x*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*sin(y)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^3*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^3) - 0.72*x*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*sin(y)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)^3*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)^2) + 0.01*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*(202500.0*x^2*(y + 0.1*sin(y))^2/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 6.25*(x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.01*(40500.0*x^2*(y + 0.1*sin(y))^2*sin(y)/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^3) - 81000.0*x^2*(y + 0.1*sin(y))^2*sin(y)/((x^2 + 2)^2*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)^2) + 202500.0*x^2*(y + 0.1*sin(y))*(0.2*cos(y) + 2)/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) - 1.25*(x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)*sin(y) + 2.5*(x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)*(0.1*cos(y) + 1)^2*sin(y) + 6.25*(x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2*(-1.6*sin(y)/(-0.2*cos(y) + 2)^3 + 0.032*sin(y)/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^3) - 0.128*sin(y)/((x^2 + 2)^2*(-0.2*cos(y) + 2)^5*(0.1*cos(y) + 1)^2)))*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.02*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*(101250.0*x^2*(y + 0.1*sin(y))/((x^2 + 2)^2*(0.1*cos(y) + 1)) + 1.25*(x^2 + 2)^2*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)*sin(y) - 3.75*(x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2*sin(y) - 50625.0*(y + 0.1*sin(y))/((x^2 + 2)*(0.1*cos(y) + 1)))*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) - 0.02*(10125.0*x^2*(y + 0.1*sin(y))*sin(y)/((x^2 + 2)^2*(0.1*cos(y) + 1)^2) + 101250.0*x^2/(x^2 + 2)^2 + 1.25*(x^2 + 2)^2*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)*cos(y) - 0.125*(x^2 + 2)^2*(-0.2*cos(y) + 2)^3*sin(y)^2 - 3.75*(x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2*cos(y) + 1.5*(x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)*sin(y)^2 - 1.5*(x^2 + 2)^2*(-0.2*cos(y) + 2)*(0.1*cos(y) + 1)^2*sin(y)^2 - 5062.5*(y + 0.1*sin(y))*sin(y)/((x^2 + 2)*(0.1*cos(y) + 1)^2) - 50625.0/(x^2 + 2))*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) - 0.002*(101250.0*x^2*(y + 0.1*sin(y))/((x^2 + 2)^2*(0.1*cos(y) + 1)) + 1.25*(x^2 + 2)^2*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)*sin(y) - 3.75*(x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2*sin(y) - 50625.0*(y + 0.1*sin(y))/((x^2 + 2)*(0.1*cos(y) + 1)))*sin(y)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) + 0.008*(101250.0*x^2*(y + 0.1*sin(y))/((x^2 + 2)^2*(0.1*cos(y) + 1)) + 1.25*(x^2 + 2)^2*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)*sin(y) - 3.75*(x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2*sin(y) - 50625.0*(y + 0.1*sin(y))/((x^2 + 2)*(0.1*cos(y) + 1)))*sin(y)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))/((x^2 + 2)*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)) - 0.16*(3.16049382716049e-6*x^2*(632812.5*y + 63281.25*sin(y) + 2531250.0)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) + sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))))*(632.8125*cos(y) + 6328.125)/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2) - 0.032*(3.16049382716049e-6*x^2*(632812.5*y + 63281.25*sin(y) + 2531250.0)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) + sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))))*(6328.125*y + 632.8125*sin(y) + 25312.5)*sin(y)/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^3) + 0.064*(3.16049382716049e-6*x^2*(632812.5*y + 63281.25*sin(y) + 2531250.0)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) + sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))))*(6328.125*y + 632.8125*sin(y) + 25312.5)*sin(y)/((x^2 + 2)^2*(-0.2*cos(y) + 2)^3*(0.1*cos(y) + 1)^2) - 0.16*(6328.125*y + 632.8125*sin(y) + 25312.5)*(-3.16049382716049e-6*x^2*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*(632812.5*y + 63281.25*sin(y) + 2531250.0)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) + 3.16049382716049e-6*x^2*(63281.25*cos(y) + 632812.5)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) + ((x^2 + 2)*(0.1*cos(y) + 1) - 1)*cos(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))))/((x^2 + 2)^2*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)^2))/sqrt((x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2)) + (-0.005*sin(t)*cos(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + 0.5*sin(3.0*x^2 + y - z - (x^2 + 2)*(y + 0.1*sin(y)))*cos(t))*cos(y)/(-0.2*cos(y) + 2)^2 - 4.0*sin(2*t)*cos(x + 4*y - z - (x^2 + 2)*(y + 0.1*sin(y))) - 4.0*((-3534.29173528852*sin(3.14159265358979*x)*cos(3.14159265358979*x)*cos(y) - 562.5)*(-0.0025*(x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) + 0.01*(x^2 + 2)*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y)))) + (11.25*x*(x^2 + 2)*(y + 0.1*sin(y))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.01*(x^2 + 2)*(1125.0*x*(y + 0.1*sin(y)) + 4500.0*x)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)*sin(4.0*x^2 - y + z + (x^2 + 2)*(y + 0.1*sin(y))))*sin(3.14159265358979*x)^2*sin(y))*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))/(sqrt((x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2)*(x^2 + 2)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) + 4.0*(-2.0*(-1125.0*x*(y + 0.1*sin(y)) + 562.5)*(0.25*(x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.001*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))))*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2*sin(6.28318530717959*x) - (x^2 + 2)*((x^2 + 2)*(0.1*cos(y) + 1)*cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.001*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)*sin(6.28318530717959*x))*sin(x + 4*y - z - (x^2 + 2)*(y + 0.1*sin(y)))*cos(2*t) - 2.0*(-(x^2 + 2)*(0.1*cos(y) + 1) + 4)*(-1125.0*x*(x^2 + 2)*(y + 0.1*sin(y))*(-0.001*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)*sin(6.28318530717959*x) + (x^2 + 2)*((-1.125*x*(y + 0.1*sin(y))*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + (1125.0*x*(y + 0.1*sin(y)) - 562.5)*cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))))*sin(6.28318530717959*x) + 3534.29173528852*(sin(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))) + 0.001*cos(-y + z + (x^2 + 2)*(y + 0.1*sin(y))))*cos(6.28318530717959*x))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1))*sin(x + 4*y - z - (x^2 + 2)*(y + 0.1*sin(y)))*cos(2*t) + 2.0*(1125.0*x*(x^2 + 2)*(y + 0.1*sin(y))*((x^2 + 2)*(0.1*cos(y) + 1)*cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.001*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)*sin(6.28318530717959*x) - 0.25*(x^2 + 2)^2*((-1.125*x*(y + 0.1*sin(y))*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + (1125.0*x*(y + 0.1*sin(y)) - 562.5)*cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))))*sin(6.28318530717959*x) + 3534.29173528852*(sin(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))) + 0.001*cos(-y + z + (x^2 + 2)*(y + 0.1*sin(y))))*cos(6.28318530717959*x))*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2)*sin(x + 4*y - z - (x^2 + 2)*(y + 0.1*sin(y)))*cos(2*t))/(sqrt((x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2)*(x^2 + 2)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) #bndry_all = dirichlet_o2(U:solution) -bndry_all = shifted(dirichlet_o2(U:solution_zshift)) +bndry_all = toFieldAligned(dirichlet_o2(U:solution_zshift)) [P] # pressure solution = -0.005*sin(t)*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + 0.5*cos(t)*cos(3.0*x^2 + y - z - (x^2 + 2)*(y + 0.1*sin(y))) + 1 @@ -201,7 +201,7 @@ ddy = -0.5*(-(x^2 + 2)*(0.1*cos(y) + 1) + 1)*sin(3.0*x^2 + y - z - (x^2 + 2)*(y source = -0.5*sin(t)*cos(3.0*x^2 + y - z - (x^2 + 2)*(y + 0.1*sin(y))) - 0.005*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y)))*cos(t) - 7068.58347057703*(0.25*(x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.001*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))))*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2*sin(6.28318530717959*x) - (x^2 + 2)*((x^2 + 2)*(0.1*cos(y) + 1)*cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.001*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)*sin(6.28318530717959*x))*sin(3.14159265358979*x)/(sqrt((x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2)*(x^2 + 2)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) + 4.0*((-0.005*sin(t)*cos(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + 0.5*sin(3.0*x^2 + y - z - (x^2 + 2)*(y + 0.1*sin(y)))*cos(t))*(1125.0*x*(x^2 + 2)*(y + 0.1*sin(y))*((x^2 + 2)*(0.1*cos(y) + 1)*cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.001*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)*sin(6.28318530717959*x) - 0.25*(x^2 + 2)^2*((-1.125*x*(y + 0.1*sin(y))*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + (1125.0*x*(y + 0.1*sin(y)) - 562.5)*cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))))*sin(6.28318530717959*x) + 3534.29173528852*(sin(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))) + 0.001*cos(-y + z + (x^2 + 2)*(y + 0.1*sin(y))))*cos(6.28318530717959*x))*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2) + (-0.5*(-(x^2 + 2)*(0.1*cos(y) + 1) + 1)*sin(3.0*x^2 + y - z - (x^2 + 2)*(y + 0.1*sin(y)))*cos(t) - 0.005*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*sin(t)*cos(-y + z + (x^2 + 2)*(y + 0.1*sin(y))))*(-1125.0*x*(x^2 + 2)*(y + 0.1*sin(y))*(-0.001*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)*sin(6.28318530717959*x) + (x^2 + 2)*((-1.125*x*(y + 0.1*sin(y))*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + (1125.0*x*(y + 0.1*sin(y)) - 562.5)*cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))))*sin(6.28318530717959*x) + 3534.29173528852*(sin(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))) + 0.001*cos(-y + z + (x^2 + 2)*(y + 0.1*sin(y))))*cos(6.28318530717959*x))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) + (-5.625*x*(y + 0.1*sin(y))*sin(t)*cos(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.5*(-1125.0*x*(y + 0.1*sin(y)) + 3375.0*x)*sin(3.0*x^2 + y - z - (x^2 + 2)*(y + 0.1*sin(y)))*cos(t))*(0.25*(x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.001*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))) + cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))))*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2*sin(6.28318530717959*x) - (x^2 + 2)*((x^2 + 2)*(0.1*cos(y) + 1)*cos(t - x + z + (x^2 + 2)*(y + 0.1*sin(y))) - 0.001*((x^2 + 2)*(0.1*cos(y) + 1) - 1)*sin(-y + z + (x^2 + 2)*(y + 0.1*sin(y))))*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)*sin(6.28318530717959*x)))/(sqrt((x^2 + 2)^2*(4.0/(-0.2*cos(y) + 2)^2 + 0.16/((x^2 + 2)^2*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2))*(-0.2*cos(y) + 2)^4*(0.1*cos(y) + 1)^2)*(x^2 + 2)*(-0.2*cos(y) + 2)^2*(0.1*cos(y) + 1)) #bndry_all = dirichlet_o2(P:solution) -bndry_all = shifted(dirichlet_o2(P:solution_zshift)) +bndry_all = toFieldAligned(dirichlet_o2(P:solution_zshift)) [Vpar] From f15a7390e83144efa668f3647ab11df89c7061f8 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 3 Jan 2019 15:29:40 +0000 Subject: [PATCH 0564/1783] Support loc argument to Laplacian::tridagCoefs If a non-default 'CELL_LOC loc' argument is given to tridagCoefs, we need to get a 'Coordinates*' pointer at the specified location instead of using the 'coords' member of the Laplacian object. This ensures Delp2 is correct when called with non-CELL_CENTRE location arguments. --- src/invert/laplace/invert_laplace.cxx | 30 ++++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index c106a7a52e..038d7adc6c 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -289,23 +289,29 @@ void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, * c - The upper diagonal. DO NOT CONFUSE WITH C (called ccoef here) */ - if (loc == CELL_DEFAULT) loc = location; + Coordinates* localcoords; + if (loc == CELL_DEFAULT) { + loc = location; + localcoords = coords; + } else { + localcoords = localmesh->getCoordinates(loc); + } ASSERT1(ccoef == nullptr || ccoef->getLocation() == loc); ASSERT1(d == nullptr || d->getLocation() == loc); BoutReal coef1, coef2, coef3, coef4, coef5; - coef1=coords->g11(jx,jy); ///< X 2nd derivative coefficient - coef2=coords->g33(jx,jy); ///< Z 2nd derivative coefficient - coef3=2.*coords->g13(jx,jy); ///< X-Z mixed derivative coefficient + coef1=localcoords->g11(jx,jy); ///< X 2nd derivative coefficient + coef2=localcoords->g33(jx,jy); ///< Z 2nd derivative coefficient + coef3=2.*localcoords->g13(jx,jy); ///< X-Z mixed derivative coefficient coef4 = 0.0; coef5 = 0.0; // If global flag all_terms are set (true by default) if(all_terms) { - coef4 = coords->G1(jx,jy); // X 1st derivative - coef5 = coords->G3(jx,jy); // Z 1st derivative + coef4 = localcoords->G1(jx,jy); // X 1st derivative + coef5 = localcoords->G3(jx,jy); // Z 1st derivative } if (d != nullptr) { @@ -320,26 +326,26 @@ void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, if(nonuniform) { // non-uniform mesh correction if((jx != 0) && (jx != (localmesh->LocalNx-1))) { - coef4 -= 0.5*((coords->dx(jx+1,jy) - coords->dx(jx-1,jy))/SQ(coords->dx(jx,jy)))*coef1; + coef4 -= 0.5*((localcoords->dx(jx+1,jy) - localcoords->dx(jx-1,jy))/SQ(localcoords->dx(jx,jy)))*coef1; } } if (ccoef != nullptr) { // A first order derivative term if((jx > 0) && (jx < (localmesh->LocalNx-1))) - coef4 += coords->g11(jx,jy) * ((*ccoef)(jx+1,jy) - (*ccoef)(jx-1,jy)) / (2.*coords->dx(jx,jy)*((*ccoef)(jx,jy))); + coef4 += localcoords->g11(jx,jy) * ((*ccoef)(jx+1,jy) - (*ccoef)(jx-1,jy)) / (2.*localcoords->dx(jx,jy)*((*ccoef)(jx,jy))); } if(localmesh->IncIntShear) { // d2dz2 term - coef2 += coords->g11(jx,jy) * coords->IntShiftTorsion(jx,jy) * coords->IntShiftTorsion(jx,jy); + coef2 += localcoords->g11(jx,jy) * localcoords->IntShiftTorsion(jx,jy) * localcoords->IntShiftTorsion(jx,jy); // Mixed derivative coef3 = 0.0; // This cancels out } - coef1 /= SQ(coords->dx(jx,jy)); - coef3 /= 2.*coords->dx(jx,jy); - coef4 /= 2.*coords->dx(jx,jy); + coef1 /= SQ(localcoords->dx(jx,jy)); + coef3 /= 2.*localcoords->dx(jx,jy); + coef4 /= 2.*localcoords->dx(jx,jy); a = dcomplex(coef1 - coef4,-kwave*coef3); b = dcomplex(-2.0*coef1 - SQ(kwave)*coef2,kwave*coef5); From 9ccd1b9b63beb9321f113f8665f772dc502cad2b Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Sat, 5 Jan 2019 21:17:21 +0000 Subject: [PATCH 0565/1783] Move map and function definitions into source file for bout_types Make function internals static in bout_types as we return a reference to them --- include/bout_types.hxx | 75 ++++-------------------------------------- src/sys/bout_types.cxx | 59 +++++++++++++++++++++++++++++++++ src/sys/makefile | 2 +- 3 files changed, 66 insertions(+), 70 deletions(-) create mode 100644 src/sys/bout_types.cxx diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 4a12502316..219341d770 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -22,9 +22,7 @@ #ifndef __BOUT_TYPES_H__ #define __BOUT_TYPES_H__ -#include #include -#include #include /// Size of real numbers @@ -38,94 +36,33 @@ const BoutReal BoutNaN = std::numeric_limits::quiet_NaN(); /// 4 possible variable locations. Default is for passing to functions enum CELL_LOC {CELL_DEFAULT=0, CELL_CENTRE=1, CELL_CENTER=1, CELL_XLOW=2, CELL_YLOW=3, CELL_ZLOW=4, CELL_VSHIFT=5}; -const std::map CELL_LOCtoString = { - ENUMSTR(CELL_DEFAULT), - ENUMSTR(CELL_CENTRE), - ENUMSTR(CELL_XLOW), - ENUMSTR(CELL_YLOW), - ENUMSTR(CELL_ZLOW), - ENUMSTR(CELL_VSHIFT) -}; - -inline const std::string& CELL_LOC_STRING(CELL_LOC location) { - return CELL_LOCtoString.at(location); -} +const std::string& CELL_LOC_STRING(CELL_LOC location); /// Differential methods. Both central and upwind enum DIFF_METHOD {DIFF_DEFAULT, DIFF_U1, DIFF_U2, DIFF_C2, DIFF_W2, DIFF_W3, DIFF_C4, DIFF_U3, DIFF_FFT, DIFF_SPLIT, DIFF_S2}; -const std::map DIFF_METHODtoString = { - {DIFF_DEFAULT, "DEFAULT"}, - {DIFF_U1, "U1"}, {DIFF_U2, "U2"}, {DIFF_U3, "U3"}, - {DIFF_C2, "C2"}, {DIFF_C4, "C4"}, {DIFF_S2, "S2"}, - {DIFF_W2, "W2"}, {DIFF_W3, "W3"}, {DIFF_FFT, "FFT"}, - {DIFF_SPLIT, "SPLIT"} -}; - -inline const std::string& DIFF_METHOD_STRING(DIFF_METHOD location) { - return DIFF_METHODtoString.at(location); -} +const std::string& DIFF_METHOD_STRING(DIFF_METHOD location); /// Specify grid region for looping enum REGION {RGN_ALL, RGN_NOBNDRY, RGN_NOX, RGN_NOY, RGN_NOZ}; -const std::map REGIONtoString = { - ENUMSTR(RGN_ALL), - ENUMSTR(RGN_NOBNDRY), - ENUMSTR(RGN_NOX), - ENUMSTR(RGN_NOY), - ENUMSTR(RGN_NOZ) -}; - -inline const std::string& REGION_STRING(REGION region) { - return REGIONtoString.at(region); -} +const std::string& REGION_STRING(REGION region); /// To identify particular directions (in index space) enum class DIRECTION { X = 0, Y = 1, Z = 3, YAligned = 4, YOrthogonal = 5 }; -const std::map DIRECTIONtoString = { - {DIRECTION::X, "X"}, - {DIRECTION::Y, "Y"}, - {DIRECTION::Z, "Z"}, - {DIRECTION::YAligned, "Y - field aligned"}, - {DIRECTION::YOrthogonal, "Y - orthogonal"} - -}; - -inline const std::string& DIRECTION_STRING(DIRECTION direction) { - return DIRECTIONtoString.at(direction); -} +const std::string& DIRECTION_STRING(DIRECTION direction); /// To identify valid staggering combinations enum class STAGGER { None = 0, C2L = 1, L2C = 2}; -const std::map STAGGERtoString = { - {STAGGER::None, "No staggering"}, - {STAGGER::C2L, "Centre to Low"}, - {STAGGER::L2C, "Low to Centre"} - -}; - -inline const std::string& STAGGER_STRING(STAGGER stagger) { - return STAGGERtoString.at(stagger); -} +const std::string& STAGGER_STRING(STAGGER stagger); /// To identify types of derivative method combinations enum class DERIV { Standard = 0, StandardSecond = 1, StandardFourth = 2, Upwind = 3, Flux = 4 }; -static std::map DERIVtoString = { - {DERIV::Standard, "Standard"}, - {DERIV::StandardSecond, "Standard -- second order"}, - {DERIV::StandardFourth, "Standard -- fourth order"}, - {DERIV::Upwind, "Upwind"}, - {DERIV::Flux, "Flux"} -}; - -inline const std::string& DERIV_STRING(DERIV deriv) { - return DERIVtoString.at(deriv); -} +const std::string& DERIV_STRING(DERIV deriv); // A small struct that can be used to wrap a specific enum value, giving // it a unique type that can be passed as a valid type to templates and diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx new file mode 100644 index 0000000000..319be896a0 --- /dev/null +++ b/src/sys/bout_types.cxx @@ -0,0 +1,59 @@ +#include + +#include + +const std::string& CELL_LOC_STRING(CELL_LOC location) { + const static std::map CELL_LOCtoString = { + ENUMSTR(CELL_DEFAULT), ENUMSTR(CELL_CENTRE), ENUMSTR(CELL_XLOW), + ENUMSTR(CELL_YLOW), ENUMSTR(CELL_ZLOW), ENUMSTR(CELL_VSHIFT)}; + + return CELL_LOCtoString.at(location); +} + +const std::string& DIFF_METHOD_STRING(DIFF_METHOD location) { + const static std::map DIFF_METHODtoString = { + {DIFF_DEFAULT, "DEFAULT"}, {DIFF_U1, "U1"}, {DIFF_U2, "U2"}, {DIFF_U3, "U3"}, + {DIFF_C2, "C2"}, {DIFF_C4, "C4"}, {DIFF_S2, "S2"}, {DIFF_W2, "W2"}, + {DIFF_W3, "W3"}, {DIFF_FFT, "FFT"}, {DIFF_SPLIT, "SPLIT"}}; + + return DIFF_METHODtoString.at(location); +} + +const std::string& REGION_STRING(REGION region) { + const static std::map REGIONtoString = { + ENUMSTR(RGN_ALL), ENUMSTR(RGN_NOBNDRY), ENUMSTR(RGN_NOX), ENUMSTR(RGN_NOY), + ENUMSTR(RGN_NOZ)}; + + return REGIONtoString.at(region); +} + +const std::string& DIRECTION_STRING(DIRECTION direction) { + const static std::map DIRECTIONtoString = { + {DIRECTION::X, "X"}, + {DIRECTION::Y, "Y"}, + {DIRECTION::Z, "Z"}, + {DIRECTION::YAligned, "Y - field aligned"}, + {DIRECTION::YOrthogonal, "Y - orthogonal"}}; + + return DIRECTIONtoString.at(direction); +} + +const std::string& STAGGER_STRING(STAGGER stagger) { + const static std::map STAGGERtoString = { + {STAGGER::None, "No staggering"}, + {STAGGER::C2L, "Centre to Low"}, + {STAGGER::L2C, "Low to Centre"}}; + + return STAGGERtoString.at(stagger); +} + +const std::string& DERIV_STRING(DERIV deriv) { + const static std::map DERIVtoString = { + {DERIV::Standard, "Standard"}, + {DERIV::StandardSecond, "Standard -- second order"}, + {DERIV::StandardFourth, "Standard -- fourth order"}, + {DERIV::Upwind, "Upwind"}, + {DERIV::Flux, "Flux"}}; + + return DERIVtoString.at(deriv); +} diff --git a/src/sys/makefile b/src/sys/makefile index b443ee698b..061d15da47 100644 --- a/src/sys/makefile +++ b/src/sys/makefile @@ -1,7 +1,7 @@ BOUT_TOP = ../.. DIRS = options -SOURCEC = boutexception.cxx derivs.cxx \ +SOURCEC = bout_types.cxx boutexception.cxx derivs.cxx \ msg_stack.cxx options.cxx output.cxx \ utils.cxx optionsreader.cxx boutcomm.cxx \ timer.cxx range.cxx petsclib.cxx expressionparser.cxx \ From 3651999ea875108418a26222e124b0f7fcb900ec Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 22 Nov 2018 14:04:37 +0000 Subject: [PATCH 0566/1783] Add test helpers for filling Fields with values --- tests/unit/field/test_field2d.cxx | 16 +++++++++++ tests/unit/field/test_field3d.cxx | 48 +++++++++++++++++++++++++++++++ tests/unit/test_extras.cxx | 24 ++++++++++++++++ tests/unit/test_extras.hxx | 3 ++ 4 files changed, 91 insertions(+) diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index f9df75f162..0634813d4c 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -1178,4 +1178,20 @@ TEST_F(Field2DTest, MoveCtor) { mesh->StaggerGrids = backup; } +TEST_F(Field2DTest, FillField) { + Field2D f{mesh}; + + fillField(f, {{1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1.}}); + + EXPECT_TRUE(IsField3DEqualBoutReal(f, 1.)); + + fillField(f, {{0., 1., 2., 3., 4.}, {0., 1., 2., 3., 4.}, {0., 1., 2., 3., 4.}}); + + Field2D g{mesh}; + g.allocate(); + BOUT_FOR_SERIAL(i, g.getRegion("RGN_ALL")) { g[i] = i.y(); } + + EXPECT_TRUE(IsField2DEqualField2D(f, g)); +} + #pragma GCC diagnostic pop diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index a8b4525b27..487da64e56 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -1979,5 +1979,53 @@ TEST_F(Field3DTest, MoveCtor) { mesh->StaggerGrids = backup; } +TEST_F(Field3DTest, FillField) { + Field3D f{mesh}; + + fillField(f, {{{1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}}, + + {{1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}}, + + {{1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}, + {1., 1., 1., 1., 1., 1., 1.}}}); + + EXPECT_TRUE(IsField3DEqualBoutReal(f, 1.)); + + fillField(f, {{{0., 1., 2., 3., 4., 5., 6.}, + {0., 1., 2., 3., 4., 5., 6.}, + {0., 1., 2., 3., 4., 5., 6.}, + {0., 1., 2., 3., 4., 5., 6.}, + {0., 1., 2., 3., 4., 5., 6.}}, + + {{0., 1., 2., 3., 4., 5., 6.}, + {0., 1., 2., 3., 4., 5., 6.}, + {0., 1., 2., 3., 4., 5., 6.}, + {0., 1., 2., 3., 4., 5., 6.}, + {0., 1., 2., 3., 4., 5., 6.}}, + + {{0., 1., 2., 3., 4., 5., 6.}, + {0., 1., 2., 3., 4., 5., 6.}, + {0., 1., 2., 3., 4., 5., 6.}, + {0., 1., 2., 3., 4., 5., 6.}, + {0., 1., 2., 3., 4., 5., 6.}}}); + + Field3D g{mesh}; + g.allocate(); + BOUT_FOR_SERIAL(i, g.getRegion("RGN_ALL")) { g[i] = i.z(); } + + EXPECT_TRUE(IsField3DEqualField3D(f, g)); +} + // Restore compiler warnings #pragma GCC diagnostic pop diff --git a/tests/unit/test_extras.cxx b/tests/unit/test_extras.cxx index dd6e8af103..dce45eac16 100644 --- a/tests/unit/test_extras.cxx +++ b/tests/unit/test_extras.cxx @@ -58,3 +58,27 @@ ::testing::AssertionResult IsFieldPerpEqualBoutReal(const FieldPerp &field, return ::testing::AssertionSuccess(); } + +void fillField(Field3D& f, std::vector>> values) { + f.allocate(); + Ind3D i{0}; + for (auto& x : values) { + for (auto& y : x) { + for (auto& z : y) { + f[i] = z; + ++i; + } + } + } +} + +void fillField(Field2D& f, std::vector> values) { + f.allocate(); + Ind2D i{0}; + for (auto& x : values) { + for (auto& y : x) { + f[i] = y; + ++i; + } + } +} diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 7bb41523e4..c672358a15 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -5,6 +5,7 @@ #include #include +#include #include "bout/mesh.hxx" #include "bout/coordinates.hxx" @@ -29,6 +30,8 @@ const BoutReal BoutRealTolerance = 1e-15; ::testing::AssertionResult IsFieldPerpEqualBoutReal(const FieldPerp &field, BoutReal number, BoutReal tolerance = BoutRealTolerance); +void fillField(Field3D& f, std::vector>> values); +void fillField(Field2D& f, std::vector> values); /// Teach googletest how to print SpecificInds template From ff15c7d55c4660382dad3f82ad4475dfb2b48842 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 28 Nov 2018 15:49:07 +0000 Subject: [PATCH 0567/1783] Basic test for shiftedmetric --- .../unit/mesh/parallel/test_shiftedmetric.cxx | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tests/unit/mesh/parallel/test_shiftedmetric.cxx diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx new file mode 100644 index 0000000000..dea0dcb2e9 --- /dev/null +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -0,0 +1,64 @@ +#include "gtest/gtest.h" + +#include "bout/paralleltransform.hxx" +#include "test_extras.hxx" + +extern Mesh* mesh; + +using ShiftedMetricTest = FakeMeshFixture; + +TEST_F(ShiftedMetricTest, ToFieldAligned) { + Field2D zShift{mesh}; + + fillField(zShift, {{1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1.}}); + + dynamic_cast(mesh)->setCoordinates(std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0})); + + ShiftedMetric shifted{*mesh, zShift}; + + Field3D input{mesh}; + + fillField(input, {{{1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}}, + + {{1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}}, + + {{1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}}}); + + Field3D output{mesh}; + + fillField(output, {{{2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}}, + + {{2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}}, + + {{2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}}}); + + EXPECT_TRUE(IsField3DEqualField3D(shifted.toFieldAligned(input), output)); +} From 431bcd9709652a48ede8b9f21b468b58789231d8 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 29 Nov 2018 10:09:25 +0000 Subject: [PATCH 0568/1783] Add region argument for test field-field comparisons --- tests/unit/test_extras.cxx | 30 ++++++++++++++++++++++++++++++ tests/unit/test_extras.hxx | 8 ++++++++ 2 files changed, 38 insertions(+) diff --git a/tests/unit/test_extras.cxx b/tests/unit/test_extras.cxx index dce45eac16..1766f177b5 100644 --- a/tests/unit/test_extras.cxx +++ b/tests/unit/test_extras.cxx @@ -31,6 +31,21 @@ ::testing::AssertionResult IsField3DEqualBoutReal(const Field3D &field, BoutReal return ::testing::AssertionSuccess(); } +::testing::AssertionResult IsField3DEqualField3D(const Field3D& lhs, const Field3D& rhs, + const std::string& region_name, + BoutReal tolerance) { + const auto& region = lhs.getMesh()->getRegion3D(region_name); + BOUT_FOR_SERIAL(i, region) { + if (std::abs(lhs[i] - rhs[i]) > tolerance) { + return ::testing::AssertionFailure() + << "Field3D(" << i.x() << ", " << i.y() << ", " << i.z() << ") == " << lhs[i] + << "; Expected: " << rhs[i]; + } + } + + return ::testing::AssertionSuccess(); +} + ::testing::AssertionResult IsField2DEqualBoutReal(const Field2D &field, BoutReal number, BoutReal tolerance) { const auto ®ion = field.getMesh()->getRegion2D("RGN_ALL"); @@ -45,6 +60,21 @@ ::testing::AssertionResult IsField2DEqualBoutReal(const Field2D &field, BoutReal return ::testing::AssertionSuccess(); } +::testing::AssertionResult IsField2DEqualField2D(const Field2D& lhs, const Field2D& rhs, + const std::string& region_name, + BoutReal tolerance) { + const auto& region = lhs.getMesh()->getRegion2D(region_name); + BOUT_FOR_SERIAL(i, region) { + if (std::abs(lhs[i] - rhs[i]) > tolerance) { + return ::testing::AssertionFailure() + << "Field2D(" << i.x() << ", " << i.y() << ") == " << lhs[i] + << "; Expected: " << rhs[i]; + } + } + + return ::testing::AssertionSuccess(); +} + ::testing::AssertionResult IsFieldPerpEqualBoutReal(const FieldPerp &field, BoutReal number, BoutReal tolerance) { const auto ®ion = field.getMesh()->getRegionPerp("RGN_ALL"); diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index c672358a15..a4593c8657 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -22,10 +22,18 @@ const BoutReal BoutRealTolerance = 1e-15; ::testing::AssertionResult IsField3DEqualBoutReal(const Field3D &field, BoutReal number, BoutReal tolerance = BoutRealTolerance); +::testing::AssertionResult IsField3DEqualField3D(const Field3D &lhs, const Field3D &rhs, + const std::string& region = "RGN_ALL", + BoutReal tolerance = BoutRealTolerance); + /// Is \p field equal to \p number, with a tolerance of \p tolerance? ::testing::AssertionResult IsField2DEqualBoutReal(const Field2D &field, BoutReal number, BoutReal tolerance = BoutRealTolerance); +::testing::AssertionResult IsField2DEqualField2D(const Field2D &lhs, const Field2D &rhs, + const std::string& region = "RGN_ALL", + BoutReal tolerance = BoutRealTolerance); + /// Is \p field equal to \p number, with a tolerance of \p tolerance? ::testing::AssertionResult IsFieldPerpEqualBoutReal(const FieldPerp &field, BoutReal number, BoutReal tolerance = BoutRealTolerance); From b4b71249351aec1ca56e821fcf16847e2ed6ea10 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 29 Nov 2018 10:12:25 +0000 Subject: [PATCH 0569/1783] Add more ShiftedMetric tests --- .../unit/mesh/parallel/test_shiftedmetric.cxx | 185 ++++++++++++++++-- 1 file changed, 167 insertions(+), 18 deletions(-) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index dea0dcb2e9..36ba9f17dd 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -10,7 +10,7 @@ using ShiftedMetricTest = FakeMeshFixture; TEST_F(ShiftedMetricTest, ToFieldAligned) { Field2D zShift{mesh}; - fillField(zShift, {{1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1.}}); + fillField(zShift, {{1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}}); dynamic_cast(mesh)->setCoordinates(std::make_shared( mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, @@ -40,25 +40,174 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { {1., 2., 3., 4., 5., 6., 7.}, {1., 2., 3., 4., 5., 6., 7.}}}); - Field3D output{mesh}; + Field3D expected{mesh}; - fillField(output, {{{2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}}, + fillField(expected, {{{2., 3., 4., 5., 6., 7., 1.}, + {3., 4., 5., 6., 7., 1., 2.}, + {4., 5., 6., 7., 1., 2., 3.}, + {5., 6., 7., 1., 2., 3., 4.}, + {6., 7., 1., 2., 3., 4., 5.}}, - {{2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}}, + {{2., 3., 4., 5., 6., 7., 1.}, + {3., 4., 5., 6., 7., 1., 2.}, + {4., 5., 6., 7., 1., 2., 3.}, + {5., 6., 7., 1., 2., 3., 4.}, + {6., 7., 1., 2., 3., 4., 5.}}, - {{2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}}}); + {{2., 3., 4., 5., 6., 7., 1.}, + {3., 4., 5., 6., 7., 1., 2.}, + {4., 5., 6., 7., 1., 2., 3.}, + {5., 6., 7., 1., 2., 3., 4.}, + {6., 7., 1., 2., 3., 4., 5.}}}); - EXPECT_TRUE(IsField3DEqualField3D(shifted.toFieldAligned(input), output)); + EXPECT_TRUE(IsField3DEqualField3D(shifted.toFieldAligned(input), expected)); +} + +TEST_F(ShiftedMetricTest, FromFieldAligned) { + Field2D zShift{mesh}; + + fillField(zShift, {{1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}}); + + dynamic_cast(mesh)->setCoordinates(std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0})); + + ShiftedMetric shifted{*mesh, zShift}; + + Field3D input{mesh}; + + fillField(input, {{{1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}}, + + {{1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}}, + + {{1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}}}); + + Field3D expected{mesh}; + + fillField(expected, {{{7., 1., 2., 3., 4., 5., 6.}, + {6., 7., 1., 2., 3., 4., 5.}, + {5., 6., 7., 1., 2., 3., 4.}, + {4., 5., 6., 7., 1., 2., 3.}, + {3., 4., 5., 6., 7., 1., 2.}}, + + {{7., 1., 2., 3., 4., 5., 6.}, + {6., 7., 1., 2., 3., 4., 5.}, + {5., 6., 7., 1., 2., 3., 4.}, + {4., 5., 6., 7., 1., 2., 3.}, + {3., 4., 5., 6., 7., 1., 2.}}, + + {{7., 1., 2., 3., 4., 5., 6.}, + {6., 7., 1., 2., 3., 4., 5.}, + {5., 6., 7., 1., 2., 3., 4.}, + {4., 5., 6., 7., 1., 2., 3.}, + {3., 4., 5., 6., 7., 1., 2.}}}); + + // Loosen tolerance a bit due to FFTs + EXPECT_TRUE(IsField3DEqualField3D(shifted.fromFieldAligned(input), expected, "RGN_ALL", + 1.e-12)); +} + +TEST_F(ShiftedMetricTest, CalcYUpDown) { + Field2D zShift{mesh}; + + fillField(zShift, {{1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}}); + + dynamic_cast(mesh)->setCoordinates(std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0})); + + output_info.disable(); + auto region_yup = mesh->getRegion("RGN_NOY"); + region_yup.periodicShift(ShiftedMetricTest::nz, + ShiftedMetricTest::ny * ShiftedMetricTest::nz); + mesh->addRegion("RGN_YUP", region_yup); + + auto region_ydown = mesh->getRegion("RGN_NOY"); + region_ydown.periodicShift(-ShiftedMetricTest::nz, + ShiftedMetricTest::ny * ShiftedMetricTest::nz); + mesh->addRegion("RGN_YDOWN", region_ydown); + output_info.enable(); + + ShiftedMetric shifted{*mesh, zShift}; + + Field3D input{mesh}; + + fillField(input, {{{1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}}, + + {{1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}}, + + {{1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}, + {1., 2., 3., 4., 5., 6., 7.}}}); + + shifted.calcYUpDown(input); + + Field3D expected_up{mesh}; + + fillField(expected_up, {{{0., 0., 0., 0., 0., 0., 0.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}}, + + {{0., 0., 0., 0., 0., 0., 0.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}}, + + {{0., 0., 0., 0., 0., 0., 0.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}, + {2., 3., 4., 5., 6., 7., 1.}}}); + + Field3D expected_down{mesh}; + + fillField(expected_down, {{{7., 1., 2., 3., 4., 5., 6.}, + {7., 1., 2., 3., 4., 5., 6.}, + {7., 1., 2., 3., 4., 5., 6.}, + {7., 1., 2., 3., 4., 5., 6.}, + {0., 0., 0., 0., 0., 0., 0.}}, + + {{7., 1., 2., 3., 4., 5., 6.}, + {7., 1., 2., 3., 4., 5., 6.}, + {7., 1., 2., 3., 4., 5., 6.}, + {7., 1., 2., 3., 4., 5., 6.}, + {0., 0., 0., 0., 0., 0., 0.}}, + + {{7., 1., 2., 3., 4., 5., 6.}, + {7., 1., 2., 3., 4., 5., 6.}, + {7., 1., 2., 3., 4., 5., 6.}, + {7., 1., 2., 3., 4., 5., 6.}, + {0., 0., 0., 0., 0., 0., 0.}}}); + + EXPECT_TRUE(IsField3DEqualField3D(input.yup(), expected_up, "RGN_YUP")); + EXPECT_TRUE(IsField3DEqualField3D(input.ydown(), expected_down, "RGN_YDOWN")); } From 8ceef8773d7645f5077bddd0fea9ccf39e7090ff Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 29 Nov 2018 11:00:59 +0000 Subject: [PATCH 0570/1783] Move some initial setup into ShiftedMetric test fixture --- .../unit/mesh/parallel/test_shiftedmetric.cxx | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 36ba9f17dd..278b4d8854 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -5,19 +5,43 @@ extern Mesh* mesh; -using ShiftedMetricTest = FakeMeshFixture; +class ShiftedMetricTest : public ::testing::Test { +public: + ShiftedMetricTest() { + // Delete any existing mesh + if (mesh != nullptr) { + delete mesh; + mesh = nullptr; + } + mesh = new FakeMesh(nx, ny, nz); + output_info.disable(); + mesh->createDefaultRegions(); + output_info.enable(); + + zShift = Field2D{mesh}; + + fillField(zShift, {{1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}}); + + dynamic_cast(mesh)->setCoordinates(std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0})); + } + + ~ShiftedMetricTest() { + delete mesh; + mesh = nullptr; + } + + static constexpr int nx = 3; + static constexpr int ny = 5; + static constexpr int nz = 7; + + Field2D zShift; +}; TEST_F(ShiftedMetricTest, ToFieldAligned) { - Field2D zShift{mesh}; - - fillField(zShift, {{1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}}); - - dynamic_cast(mesh)->setCoordinates(std::make_shared( - mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0})); - ShiftedMetric shifted{*mesh, zShift}; Field3D input{mesh}; @@ -64,16 +88,6 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { } TEST_F(ShiftedMetricTest, FromFieldAligned) { - Field2D zShift{mesh}; - - fillField(zShift, {{1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}}); - - dynamic_cast(mesh)->setCoordinates(std::make_shared( - mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0})); - ShiftedMetric shifted{*mesh, zShift}; Field3D input{mesh}; @@ -122,16 +136,6 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { } TEST_F(ShiftedMetricTest, CalcYUpDown) { - Field2D zShift{mesh}; - - fillField(zShift, {{1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}}); - - dynamic_cast(mesh)->setCoordinates(std::make_shared( - mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0})); - output_info.disable(); auto region_yup = mesh->getRegion("RGN_NOY"); region_yup.periodicShift(ShiftedMetricTest::nz, From 7aed30f102066759ab4b2106d358f30048612c12 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 29 Nov 2018 12:41:02 +0000 Subject: [PATCH 0571/1783] Fix shiftedmetric test fixture --- tests/unit/mesh/parallel/test_shiftedmetric.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 278b4d8854..4d8c2885a7 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -22,11 +22,11 @@ class ShiftedMetricTest : public ::testing::Test { fillField(zShift, {{1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}}); - dynamic_cast(mesh)->setCoordinates(std::make_shared( + dynamic_cast(mesh)->setCoordinates(std::make_shared( mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0})); + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false)); } ~ShiftedMetricTest() { From a8fa97e9c4632d975199cca70b91679576768db3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 29 Nov 2018 16:25:31 +0000 Subject: [PATCH 0572/1783] Move ShiftedMetric::cmplx/cmplxLoc into shiftZ; make shiftZ const --- include/bout/paralleltransform.hxx | 21 +++++++-------- src/mesh/parallel/shiftedmetric.cxx | 40 ++++++++++++++--------------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 92f3983b29..33dcccb959 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -132,11 +132,10 @@ private: /// This is the shift in toroidal angle (z) which takes a point from /// X-Z orthogonal to field-aligned along Y. Field2D zShift; - std::vector cmplx; ///< A temporary array, used for input/output to fft routines - std::vector cmplxLoc; ///< A temporary array, used for input/output to fft routines - - arr3Dvec toAlignedPhs; ///< Cache of phase shifts for transforming from X-Z orthogonal coordinates to field-aligned coordinates - arr3Dvec fromAlignedPhs; ///< Cache of phase shifts for transforming from field-aligned coordinates to X-Z orthogonal coordinates + /// Cache of phase shifts for transforming from X-Z orthogonal coordinates to field-aligned coordinates + arr3Dvec toAlignedPhs; + /// Cache of phase shifts for transforming from field-aligned coordinates to X-Z orthogonal coordinates + arr3Dvec fromAlignedPhs; arr3Dvec yupPhs; ///< Cache of phase shifts for calculating yup fields arr3Dvec ydownPhs; ///< Cache of phase shifts for calculating ydown fields @@ -145,7 +144,9 @@ private: * Shift a 2D field in Z. * Since 2D fields are constant in Z, this has no effect */ - const Field2D shiftZ(const Field2D &f, const Field2D &UNUSED(zangle)){return f;}; + const Field2D shiftZ(const Field2D& f, const Field2D& UNUSED(zangle)) const { + return f; + }; /*! * Shift a 3D field \p f in Z by the given \p zangle @@ -154,7 +155,7 @@ private: * @param[in] zangle Toroidal angle (z) * */ - const Field3D shiftZ(const Field3D &f, const Field2D &zangle); + const Field3D shiftZ(const Field3D &f, const Field2D &zangle) const; /*! * Shift a 3D field \p f by the given phase \p phs in Z @@ -165,7 +166,7 @@ private: * @param[in] f The field to shift * @param[in] phs The phase to shift by */ - const Field3D shiftZ(const Field3D &f, const arr3Dvec &phs); + const Field3D shiftZ(const Field3D &f, const arr3Dvec &phs) const; /*! * Shift a given 1D array, assumed to be in Z, by the given \p zangle @@ -175,7 +176,7 @@ private: * @param[in] zangle The angle (z coordinate) to shift by * @param[out] out A 1D array of length \p len, already allocated */ - void shiftZ(const BoutReal *in, int len, BoutReal zangle, BoutReal *out); + void shiftZ(const BoutReal *in, int len, BoutReal zangle, BoutReal *out) const; /*! * Shift a given 1D array, assumed to be in Z, by the given \p zangle @@ -184,7 +185,7 @@ private: * @param[in] phs Phase shift, assumed to have length (mesh.LocalNz/2 + 1) i.e. the number of modes * @param[out] out A 1D array of length mesh.LocalNz, already allocated */ - void shiftZ(const BoutReal *in, const std::vector &phs, BoutReal *out); + void shiftZ(const BoutReal *in, const std::vector &phs, BoutReal *out) const; /// Calculate and store the phases for to/from field aligned and for /// the parallel slices using zShift diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 211a0b3e79..55eee670bd 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -52,10 +52,6 @@ void ShiftedMetric::cachePhases() { int nmodes = mesh.LocalNz / 2 + 1; BoutReal zlength = mesh.getCoordinates()->zlength(); - // Allocate storage for complex intermediate - cmplx.resize(nmodes); - std::fill(cmplx.begin(), cmplx.end(), 0.0); - // Allocate storage for our 3d vector structures. // This could be made more succinct but this approach is fairly // verbose --> transparent @@ -151,7 +147,7 @@ const Field3D ShiftedMetric::fromFieldAligned(const Field3D &f) { return shiftZ(f, fromAlignedPhs); } -const Field3D ShiftedMetric::shiftZ(const Field3D &f, const arr3Dvec &phs) { +const Field3D ShiftedMetric::shiftZ(const Field3D &f, const arr3Dvec &phs) const { ASSERT1(&mesh == f.getMesh()); if(mesh.LocalNz == 1) return f; // Shifting makes no difference @@ -170,17 +166,21 @@ const Field3D ShiftedMetric::shiftZ(const Field3D &f, const arr3Dvec &phs) { } -void ShiftedMetric::shiftZ(const BoutReal *in, const std::vector &phs, BoutReal *out) { +void ShiftedMetric::shiftZ(const BoutReal* in, const std::vector& phs, + BoutReal* out) const { + + int nmodes = mesh.LocalNz / 2 + 1; + Array cmplx(nmodes); + // Take forward FFT rfft(in, mesh.LocalNz, &cmplx[0]); - //Following is an algorithm approach to write a = a*b where a and b are - //vectors of dcomplex. - // std::transform(cmplxOneOff.begin(),cmplxOneOff.end(), ptr.begin(), + // Following is an algorithm approach to write a = a*b where a and b are + // vectors of dcomplex. + // std::transform(cmplxOneOff.begin(),cmplxOneOff.end(), ptr.begin(), // cmplxOneOff.begin(), std::multiplies()); - const int nmodes = cmplx.size(); - for(int jz=1;jz &phs, } //Old approach retained so we can still specify a general zShift -const Field3D ShiftedMetric::shiftZ(const Field3D &f, const Field2D &zangle) { +const Field3D ShiftedMetric::shiftZ(const Field3D &f, const Field2D &zangle) const { ASSERT1(&mesh == f.getMesh()); if(mesh.LocalNz == 1) return f; // Shifting makes no difference @@ -206,20 +206,20 @@ const Field3D ShiftedMetric::shiftZ(const Field3D &f, const Field2D &zangle) { return result; } -void ShiftedMetric::shiftZ(const BoutReal *in, int len, BoutReal zangle, BoutReal *out) { - int nmodes = len/2 + 1; +void ShiftedMetric::shiftZ(const BoutReal* in, int len, BoutReal zangle, BoutReal* out) const { + int nmodes = len / 2 + 1; // Complex array used for FFTs - cmplxLoc.resize(nmodes); - + Array cmplxLoc(nmodes); + // Take forward FFT rfft(in, len, &cmplxLoc[0]); - + // Apply phase shift BoutReal zlength = mesh.getCoordinates()->zlength(); - for(int jz=1;jz Date: Thu, 29 Nov 2018 16:36:32 +0000 Subject: [PATCH 0573/1783] Use type alias instead of typedef --- include/bout/paralleltransform.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 33dcccb959..2f85136be4 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -125,7 +125,7 @@ public: } /// A 3D array, implemented as nested vectors - typedef std::vector>> arr3Dvec; + using arr3Dvec = std::vector>>; private: Mesh &mesh; ///< The mesh this paralleltransform is part of From a00cbba12e5c704c3747fb61edea124125328ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 10 Jan 2019 19:44:35 +0000 Subject: [PATCH 0574/1783] Show available options in Factory --- include/bout/generic_factory.hxx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/bout/generic_factory.hxx b/include/bout/generic_factory.hxx index 324b6f7f39..47cb02e66f 100644 --- a/include/bout/generic_factory.hxx +++ b/include/bout/generic_factory.hxx @@ -59,7 +59,14 @@ public: if (index != std::end(type_map)) { return index->second(std::forward(args) ...); } - throw BoutException("Could not find '%s'", name.c_str()); + // List available options in error + const char* const delim = "\n"; + std::string available; + auto available_list = listAvailable(); + for (auto i : available_list) { + available += i + "\n"; + } + throw BoutException("Available:\n%s\nCould not find '%s'", available.c_str(), name.c_str()); } /// List available types that can be created From 5c113cfc8e60e3fa97afaaacb2cb319233932f02 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 11 Jan 2019 13:14:20 +0000 Subject: [PATCH 0575/1783] Add Array::resize to simplify changing the size of an Array --- include/bout/array.hxx | 10 ++++++++- tests/unit/include/bout/test_array.cxx | 31 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/include/bout/array.hxx b/include/bout/array.hxx index 3da8349fed..49cb3d7785 100644 --- a/include/bout/array.hxx +++ b/include/bout/array.hxx @@ -118,7 +118,15 @@ public: swap(*this, other); } - /*! + /*! + * Resize the array to \p new_size + */ + void resize(int new_size) { + release(ptr); + ptr = get(new_size); + } + + /*! * Holds a static variable which controls whether * memory blocks (ArrayData) are put into a store * or new/deleted each time. diff --git a/tests/unit/include/bout/test_array.cxx b/tests/unit/include/bout/test_array.cxx index 768a335b0f..6d51807105 100644 --- a/tests/unit/include/bout/test_array.cxx +++ b/tests/unit/include/bout/test_array.cxx @@ -121,6 +121,37 @@ TEST_F(ArrayTest, MoveArrayConstructor) { EXPECT_TRUE(b.unique()); } +TEST_F(ArrayTest, Resize) { + Array a{}; + + ASSERT_TRUE(a.empty()); + + // Resize from empty + a.resize(15); + std::iota(a.begin(), a.end(), 0); + + ASSERT_FALSE(a.empty()); + EXPECT_EQ(a.size(), 15); + EXPECT_DOUBLE_EQ(a[5], 5); + EXPECT_TRUE(a.unique()); + + // Resize to smaller + a.resize(7); + std::iota(a.begin(), a.end(), 10); + + ASSERT_FALSE(a.empty()); + EXPECT_EQ(a.size(), 7); + EXPECT_DOUBLE_EQ(a[5], 15); + + // Resize to larger + a.resize(30); + std::iota(a.begin(), a.end(), 20); + + ASSERT_FALSE(a.empty()); + EXPECT_EQ(a.size(), 30); + EXPECT_DOUBLE_EQ(a[5], 25); +} + TEST_F(ArrayTest, MakeUnique) { Array a(20); From 31e6a81641029d4c93cc5371b4fdae380a45a033 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 11 Jan 2019 13:54:14 +0000 Subject: [PATCH 0576/1783] Fix bug in `irfft(Array)`: length of original signal is needed The length is required because input signals to the forward transform of length `n` and `n + 1` both produce ffts of length `(n / 2) + 1` -- i.e. it's not possible to recover the length of the original signal from the fft alone. --- include/fft.hxx | 12 ++++++++++-- src/invert/fft_fftw.cxx | 8 ++++---- tests/unit/invert/test_fft.cxx | 8 ++++---- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/include/fft.hxx b/include/fft.hxx index d31ac8b9c9..b257488c3c 100644 --- a/include/fft.hxx +++ b/include/fft.hxx @@ -97,8 +97,16 @@ void fft_init(Options* options = nullptr); /// Returns the fft of a real signal \p in using fftw_forward Array rfft(const Array& in); -/// Take the inverse fft of signal \p in where the outputs are only reals -Array irfft(const Array& in); +/// Take the inverse fft of signal \p in where the outputs are only reals. +/// Requires the \p length of the original real signal +/// +/// \p length is required because input signals to the forward +/// transform of length `n` and `n + 1` both produce ffts of length +/// `(n / 2) + 1` -- i.e. it's not possible to recover the length of +/// the original signal from the fft alone. +/// +/// Expects that `in.size() == (length / 2) + 1` +Array irfft(const Array& in, int length); } // namespace fft } // namespace bout diff --git a/src/invert/fft_fftw.cxx b/src/invert/fft_fftw.cxx index b0af7a6413..5e8e3960bd 100644 --- a/src/invert/fft_fftw.cxx +++ b/src/invert/fft_fftw.cxx @@ -477,13 +477,13 @@ Array rfft(const Array& in) { return out; } -Array irfft(const Array& in) { +Array irfft(const Array& in, int length) { ASSERT1(!in.empty()); + ASSERT1(in.size() == (length / 2) + 1); - int size{(in.size() - 1) * 2}; - Array out{size}; + Array out{length}; - irfft(in.begin(), size, out.begin()); + irfft(in.begin(), length, out.begin()); return out; } diff --git a/tests/unit/invert/test_fft.cxx b/tests/unit/invert/test_fft.cxx index c7be814818..abf997e4b4 100644 --- a/tests/unit/invert/test_fft.cxx +++ b/tests/unit/invert/test_fft.cxx @@ -57,8 +57,8 @@ TEST(FFTTest, irfft) { // Make sure fft functions are quiet by setting fft_measure to false bout::fft::fft_init(false); - constexpr int nmodes{5}; - constexpr int size{(nmodes - 1) * 2}; + constexpr int size{8}; + constexpr int nmodes{(size / 2) + 1}; // Make a spectrum with two frequencies Array input{nmodes}; @@ -144,7 +144,7 @@ TEST(FFTTest, irfftWithArray) { input[2] = dcomplex{0.5, 0.}; // Compute inverse real FFT - Array output = bout::fft::irfft(input); + Array output = bout::fft::irfft(input, size); // Make grid indices from [0, size - 1] Array indices{size}; @@ -183,7 +183,7 @@ TEST(FFTTest, RoundTrip) { return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); }); - Array output{bout::fft::irfft(bout::fft::rfft(input))}; + Array output{bout::fft::irfft(bout::fft::rfft(input), size)}; EXPECT_EQ(output.size(), input.size()); From e79d61b6f0445fcd93361dc82c7cf3e8db0ede3a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 11 Jan 2019 14:47:01 +0000 Subject: [PATCH 0577/1783] Parameterise FFT tests over both even- and odd-length real signals Also reduce duplicated code in individual tests by moving it into the fixture -- bulk of tests was in creating the real/fft signals for input/expected output --- tests/unit/invert/test_fft.cxx | 183 ++++++++++----------------------- 1 file changed, 52 insertions(+), 131 deletions(-) diff --git a/tests/unit/invert/test_fft.cxx b/tests/unit/invert/test_fft.cxx index abf997e4b4..37ed3cb9b8 100644 --- a/tests/unit/invert/test_fft.cxx +++ b/tests/unit/invert/test_fft.cxx @@ -10,184 +10,105 @@ #include #include -TEST(FFTTest, rfft) { +class FFTTest : public ::testing::TestWithParam { +public: + FFTTest() + : size(GetParam()), nmodes((size / 2) + 1), real_signal(size), fft_signal(nmodes) { - // Make sure fft functions are quiet by setting fft_measure to false - bout::fft::fft_init(false); + // Make sure fft functions are quiet by setting fft_measure to false + bout::fft::fft_init(false); - constexpr int size{8}; - constexpr int nmodes{(size / 2) + 1}; + // Make grid indices from [0, size - 1] + Array indices{size}; + std::iota(indices.begin(), indices.end(), 0.0); - // Make grid indices from [0, size - 1] - Array indices{size}; - std::iota(indices.begin(), indices.end(), 0.0); + // Calculate sin(x) + cos(2x) on [0, 2pi] + std::transform(indices.begin(), indices.end(), real_signal.begin(), + [this](BoutReal i) -> BoutReal { + return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); + }); - // Calculate sin(x) + cos(2x) on [0, 2pi] - Array input{size}; - std::transform(indices.begin(), indices.end(), input.begin(), - [](BoutReal i) -> BoutReal { - return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); - }); + // Make a spectrum with two frequencies + std::fill(fft_signal.begin(), fft_signal.end(), dcomplex{0., 0.}); + fft_signal[1] = dcomplex{0., -0.5}; + fft_signal[2] = dcomplex{0.5, 0.}; + }; - Array output{nmodes}; + const int size; + const int nmodes; - // Compute forward real FFT - rfft(input.begin(), size, output.begin()); + Array real_signal; + Array fft_signal; + + // FFTs have a slightly looser tolerance than other functions + static constexpr BoutReal fft_tolerance{1.e-12}; +}; + +// Test the FFT functions with both even- and odd-length real signals +INSTANTIATE_TEST_CASE_P(FFTEvenAndOddSamples, FFTTest, ::testing::Values(8, 9)); - // Real part should have exactly one frequency - Array expected_real{nmodes}; - std::fill(expected_real.begin(), expected_real.end(), 0.); - expected_real[2] = 0.5; +TEST_P(FFTTest, rfft) { - // Imaginary part should have exactly one frequency - Array expected_imag{nmodes}; - std::fill(expected_imag.begin(), expected_imag.end(), 0.); - expected_imag[1] = -0.5; + Array output{nmodes}; + + // Compute forward real FFT + rfft(real_signal.begin(), size, output.begin()); EXPECT_EQ(output.size(), nmodes); for (int i = 0; i < nmodes; ++i) { - EXPECT_NEAR(real(output[i]), expected_real[i], BoutRealTolerance); - EXPECT_NEAR(imag(output[i]), expected_imag[i], BoutRealTolerance); + EXPECT_NEAR(real(output[i]), real(fft_signal[i]), fft_tolerance); + EXPECT_NEAR(imag(output[i]), imag(fft_signal[i]), fft_tolerance); } } -TEST(FFTTest, irfft) { - - // Make sure fft functions are quiet by setting fft_measure to false - bout::fft::fft_init(false); - - constexpr int size{8}; - constexpr int nmodes{(size / 2) + 1}; - - // Make a spectrum with two frequencies - Array input{nmodes}; - std::fill(input.begin(), input.end(), dcomplex{0., 0.}); - input[1] = dcomplex{0., -0.5}; - input[2] = dcomplex{0.5, 0.}; +TEST_P(FFTTest, irfft) { Array output{size}; // Compute inverse real FFT - irfft(input.begin(), size, output.begin()); - - // Make grid indices from [0, size - 1] - Array indices{size}; - std::iota(indices.begin(), indices.end(), 0.0); - - // Calculate sin(x) + cos(2x) on [0, 2pi] - Array expected{size}; - std::transform(indices.begin(), indices.end(), expected.begin(), - [](BoutReal i) -> BoutReal { - return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); - }); + irfft(fft_signal.begin(), size, output.begin()); EXPECT_EQ(output.size(), size); for (int i = 0; i < size; ++i) { - EXPECT_NEAR(output[i], expected[i], BoutRealTolerance); + EXPECT_NEAR(output[i], real_signal[i], fft_tolerance); } } -TEST(FFTTest, rfftWithArray) { - - // Make sure fft functions are quiet by setting fft_measure to false - bout::fft::fft_init(false); - - constexpr int size{8}; - constexpr int nmodes{(size / 2) + 1}; - - // Make grid indices from [0, size - 1] - Array indices{size}; - std::iota(indices.begin(), indices.end(), 0.0); - - // Calculate sin(x) + cos(2x) on [0, 2pi] - Array input{size}; - std::transform(indices.begin(), indices.end(), input.begin(), - [](BoutReal i) -> BoutReal { - return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); - }); +TEST_P(FFTTest, rfftWithArray) { // Compute forward real FFT - Array output = bout::fft::rfft(input); - - // Real part should have exactly one frequency - Array expected_real{nmodes}; - std::fill(expected_real.begin(), expected_real.end(), 0.); - expected_real[2] = 0.5; - - // Imaginary part should have exactly one frequency - Array expected_imag{nmodes}; - std::fill(expected_imag.begin(), expected_imag.end(), 0.); - expected_imag[1] = -0.5; + Array output{bout::fft::rfft(real_signal)}; EXPECT_EQ(output.size(), nmodes); for (int i = 0; i < nmodes; ++i) { - EXPECT_NEAR(real(output[i]), expected_real[i], BoutRealTolerance); - EXPECT_NEAR(imag(output[i]), expected_imag[i], BoutRealTolerance); + EXPECT_NEAR(real(output[i]), real(fft_signal[i]), fft_tolerance); + EXPECT_NEAR(imag(output[i]), imag(fft_signal[i]), fft_tolerance); } } -TEST(FFTTest, irfftWithArray) { - - // Make sure fft functions are quiet by setting fft_measure to false - bout::fft::fft_init(false); - - constexpr int nmodes{5}; - constexpr int size{(nmodes - 1) * 2}; - - // Make a spectrum with two frequencies - Array input{nmodes}; - std::fill(input.begin(), input.end(), dcomplex{0., 0.}); - input[1] = dcomplex{0., -0.5}; - input[2] = dcomplex{0.5, 0.}; +TEST_P(FFTTest, irfftWithArray) { // Compute inverse real FFT - Array output = bout::fft::irfft(input, size); - - // Make grid indices from [0, size - 1] - Array indices{size}; - std::iota(indices.begin(), indices.end(), 0.0); - - // Calculate sin(x) + cos(2x) on [0, 2pi] - Array expected{size}; - std::transform(indices.begin(), indices.end(), expected.begin(), - [](BoutReal i) -> BoutReal { - return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); - }); + Array output{bout::fft::irfft(fft_signal, size)}; EXPECT_EQ(output.size(), size); for (int i = 0; i < size; ++i) { - EXPECT_NEAR(output[i], expected[i], BoutRealTolerance); + EXPECT_NEAR(output[i], real_signal[i], fft_tolerance); } } -TEST(FFTTest, RoundTrip) { - // Checks normalisation is == 1 - - // Make sure fft functions are quiet by setting fft_measure to false - bout::fft::fft_init(false); - - constexpr int size{8}; +TEST_P(FFTTest, RoundTrip) { - // Make grid indices from [0, size - 1] - Array indices{size}; - std::iota(indices.begin(), indices.end(), 0.0); - - // Calculate sin(x) + cos(2x) on [0, 2pi] - Array input{size}; - std::transform(indices.begin(), indices.end(), input.begin(), - [](BoutReal i) -> BoutReal { - return std::sin(i * TWOPI / size) + std::cos(2. * i * TWOPI / size); - }); - - Array output{bout::fft::irfft(bout::fft::rfft(input), size)}; + // Checks normalisation is == 1 + Array output{bout::fft::irfft(bout::fft::rfft(real_signal), size)}; - EXPECT_EQ(output.size(), input.size()); + EXPECT_EQ(output.size(), real_signal.size()); for (int i = 0; i < size; ++i) { - EXPECT_NEAR(output[i], input[i], BoutRealTolerance); + EXPECT_NEAR(output[i], real_signal[i], fft_tolerance); } } From 61ce467a28d1aebb9bce67f4111e06fb491bdfe9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 11 Jan 2019 17:06:30 +0000 Subject: [PATCH 0578/1783] Add Matrix::resize, Tensor::resize --- include/utils.hxx | 15 +++++++++++++ tests/unit/sys/test_utils.cxx | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/include/utils.hxx b/include/utils.hxx index a574c27264..93d71e9bad 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -103,6 +103,13 @@ public: data.ensureUnique(); } + /// Resize the Matrix to \p new_size_1 by \p new_size_2 + void resize(size_type new_size_1, size_type new_size_2) { + n1 = new_size_1; + n2 = new_size_2; + data.resize(new_size_1 * new_size_2); + } + Matrix& operator=(const Matrix &other) { n1 = other.n1; n2 = other.n2; @@ -173,6 +180,14 @@ public: data.ensureUnique(); } + /// Resize the Tensor to \p new_size_1 by \p new_size_2 by \p new_size_3 + void resize(size_type new_size_1, size_type new_size_2, size_type new_size_3) { + n1 = new_size_1; + n2 = new_size_2; + n3 = new_size_3; + data.resize(new_size_1 * new_size_2 * new_size_3); + } + Tensor& operator=(const Tensor &other) { n1 = other.n1; n2 = other.n2; diff --git a/tests/unit/sys/test_utils.cxx b/tests/unit/sys/test_utils.cxx index 710eea70e8..e2fa8ce05b 100644 --- a/tests/unit/sys/test_utils.cxx +++ b/tests/unit/sys/test_utils.cxx @@ -21,6 +21,26 @@ TEST(MatrixTest, CreateGivenSize) { EXPECT_EQ(shape1, 5); } +TEST(MatrixTest, Resize) { + Matrix matrix{}; + + ASSERT_TRUE(matrix.empty()); + + matrix.resize(3, 5); + + int shape0, shape1; + std::tie(shape0, shape1) = matrix.shape(); + + EXPECT_EQ(shape0, 3); + EXPECT_EQ(shape1, 5); + + matrix.resize(5, 3); + std::tie(shape0, shape1) = matrix.shape(); + + EXPECT_EQ(shape0, 5); + EXPECT_EQ(shape1, 3); +} + TEST(MatrixTest, Empty) { Matrix matrix; EXPECT_TRUE(matrix.empty()); @@ -163,6 +183,28 @@ TEST(TensorTest, CreateGivenSize) { EXPECT_EQ(shape2, 7); } +TEST(TensorTest, Resize) { + Tensor tensor{}; + + ASSERT_TRUE(tensor.empty()); + + tensor.resize(3, 5, 7); + + int shape0, shape1, shape2; + std::tie(shape0, shape1, shape2) = tensor.shape(); + + EXPECT_EQ(shape0, 3); + EXPECT_EQ(shape1, 5); + EXPECT_EQ(shape2, 7); + + tensor.resize(5, 7, 3); + std::tie(shape0, shape1, shape2) = tensor.shape(); + + EXPECT_EQ(shape0, 5); + EXPECT_EQ(shape1, 7); + EXPECT_EQ(shape2, 3); +} + TEST(TensorTest, Empty) { Tensor tensor; EXPECT_TRUE(tensor.empty()); From 9a19b667bdfb1ebc19d338b61318216c1e2f331a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 11 Jan 2019 17:22:11 +0000 Subject: [PATCH 0579/1783] Use Array/Matrix/Tensor::resize instead of copy assignment --- include/cyclic_reduction.hxx | 22 ++++++------- include/utils.hxx | 4 +-- src/field/field2d.cxx | 2 +- src/field/field3d.cxx | 2 +- src/field/fieldperp.cxx | 2 +- src/field/globalfield.cxx | 2 +- .../laplace/impls/cyclic/cyclic_laplace.cxx | 10 +++--- .../laplace/impls/multigrid/multigrid_alg.cxx | 10 +++--- .../impls/multigrid/multigrid_laplace.cxx | 4 +-- .../laplace/impls/mumps/mumps_laplace.cxx | 8 ++--- src/invert/laplace/impls/pdd/pdd.cxx | 20 ++++++------ .../laplace/impls/serial_band/serial_band.cxx | 16 +++++----- .../laplace/impls/shoot/shoot_laplace.cxx | 10 +++--- src/invert/laplace/impls/spt/spt.cxx | 16 +++++----- src/invert/laplacexy/laplacexy.cxx | 14 ++++---- .../impls/cyclic/laplacexz-cyclic.cxx | 16 +++++----- src/mesh/impls/bout/boutmesh.cxx | 32 +++++++++---------- src/mesh/interpolation/bilinear.cxx | 4 +-- src/mesh/interpolation/hermite_spline.cxx | 4 +-- src/mesh/interpolation/lagrange_4pt.cxx | 4 +-- src/solver/impls/euler/euler.cxx | 4 +-- src/solver/impls/imex-bdf2/imex-bdf2.cxx | 8 ++--- src/solver/impls/karniadakis/karniadakis.cxx | 16 +++++----- src/solver/impls/power/power.cxx | 2 +- src/solver/impls/rk3-ssp/rk3-ssp.cxx | 10 +++--- src/solver/impls/rk4/rk4.cxx | 16 +++++----- .../rkgeneric/impls/cashkarp/cashkarp.cxx | 6 ++-- .../rkgeneric/impls/rk4simple/rk4simple.cxx | 6 ++-- .../impls/rkgeneric/impls/rkf34/rkf34.cxx | 6 ++-- .../impls/rkgeneric/impls/rkf45/rkf45.cxx | 6 ++-- src/solver/impls/rkgeneric/rkgeneric.cxx | 6 ++-- src/solver/impls/rkgeneric/rkscheme.cxx | 4 +-- src/solver/impls/slepc/slepc.cxx | 4 +-- tests/integrated/test-cyclic/test_cyclic.cxx | 10 +++--- 34 files changed, 153 insertions(+), 153 deletions(-) diff --git a/include/cyclic_reduction.hxx b/include/cyclic_reduction.hxx index 307b87061e..e74b4959d7 100644 --- a/include/cyclic_reduction.hxx +++ b/include/cyclic_reduction.hxx @@ -488,8 +488,8 @@ private: sys0 += nsextra; } - coefs = Matrix(Nsys, 4 * N); - myif = Matrix(Nsys, 8); + coefs.resize(Nsys, 4 * N); + myif.resize(Nsys, 8); // Note: The recvbuffer is used to receive data in both stages of the solve: // 1. In the gather step, this processor will receive myns interface equations @@ -498,22 +498,22 @@ private: // from each processor. The number of systems of equations received will // vary from myns to myns+1 (if myproc >= nsextra). // The size of the array reserved is therefore (myns+1) - recvbuffer = - Matrix(nprocs, (myns + 1) * 8); // Buffer for receiving from other processors + recvbuffer.resize(nprocs, (myns + 1) * 8); // Some interface systems to be solved on this processor // Note that the interface equations are organised by system (myns as first argument) // but communication buffers are organised by processor (nprocs first). - ifcs = Matrix(myns, 2 * 4 * nprocs); // Coefficients for interface solve - if (nprocs > 1) - if2x2 = Matrix(myns, 2 * 4); // 2x2 interface equations on this processor - ifx = Matrix(myns, 2 * nprocs); // Solution of interface equations - ifp = Array(myns * 2); // Solution to be sent to processor p + ifcs.resize(myns, 2 * 4 * nprocs); // Coefficients for interface solve + if (nprocs > 1) { + if2x2.resize(myns, 2 * 4); // 2x2 interface equations on this processor + } + ifx.resize(myns, 2 * nprocs); // Solution of interface equations + ifp.resize(myns * 2); // Solution to be sent to processor p // Each system to be solved on this processor has two interface equations from each // processor - x1 = Array(Nsys); - xn = Array(Nsys); + x1.resize(Nsys); + xn.resize(Nsys); } /// Calculate interface equations diff --git a/include/utils.hxx b/include/utils.hxx index 93d71e9bad..204da60217 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -96,7 +96,7 @@ public: Matrix() : n1(0), n2(0){}; Matrix(size_type n1, size_type n2) : n1(n1), n2(n2) { - data = Array(n1*n2); + data.resize(n1 * n2); } Matrix(const Matrix &other) : n1(other.n1), n2(other.n2), data(other.data) { // Prevent copy on write for Matrix @@ -173,7 +173,7 @@ public: Tensor() : n1(0), n2(0), n3(0) {}; Tensor(size_type n1, size_type n2, size_type n3) : n1(n1), n2(n2), n3(n3) { - data = Array(n1*n2*n3); + data.resize(n1 * n2 * n3); } Tensor(const Tensor &other) : n1(other.n1), n2(other.n2), n3(other.n3), data(other.data) { // Prevent copy on write for Tensor diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 02f2a2e480..dd037de727 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -97,7 +97,7 @@ void Field2D::allocate() { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; } - data = Array(nx*ny); + data.resize(nx*ny); #if CHECK > 2 invalidateGuards(*this); #endif diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 65511f428a..099b19c912 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -132,7 +132,7 @@ void Field3D::allocate() { ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; } - data = Array(nx*ny*nz); + data.resize(nx*ny*nz); #if CHECK > 2 invalidateGuards(*this); #endif diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 5787f0ce29..36d12966b3 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -54,7 +54,7 @@ void FieldPerp::allocate() { nx = fieldmesh->LocalNx; nz = fieldmesh->LocalNz; } - data = Array(nx * nz); + data.resize(nx * nz); #if CHECK > 2 invalidateGuards(*this); #endif diff --git a/src/field/globalfield.cxx b/src/field/globalfield.cxx index 716f1b59a8..37cc01f571 100644 --- a/src/field/globalfield.cxx +++ b/src/field/globalfield.cxx @@ -16,7 +16,7 @@ GlobalField::GlobalField(Mesh *m, int proc, int xsize, int ysize, int zsize) if(mype == proc) { // Allocate memory - data = Array(nx * ny * nz); + data.resize(nx * ny * nz); } } diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index af950b7cbe..3a91ac3f8e 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -73,11 +73,11 @@ LaplaceCyclic::LaplaceCyclic(Options *opt, const CELL_LOC loc, Mesh *mesh_in) int n = xe - xs + 1; // Number of X points on this processor, // including boundaries but not guard cells - a = Matrix(nmode, n); - b = Matrix(nmode, n); - c = Matrix(nmode, n); - xcmplx = Matrix(nmode, n); - bcmplx = Matrix(nmode, n); + a.resize(nmode, n); + b.resize(nmode, n); + c.resize(nmode, n); + xcmplx.resize(nmode, n); + bcmplx.resize(nmode, n); // Create a cyclic reduction object, operating on dcomplex values cr = new CyclicReduce(localmesh->getXcomm(), n); diff --git a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx index df39fe6c5a..a2b9f3038e 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx @@ -39,11 +39,11 @@ MultigridAlg::MultigridAlg(int level, int lx, int lz, int gx, int gz, MPI_Comm c if(pcheck > 0) output<<"Construct MG "<(mglevel); - gnz = Array(mglevel); - lnx = Array(mglevel); - lnz = Array(mglevel); + // Memory allocate for Multigrid + gnx.resize(mglevel); + gnz.resize(mglevel); + lnx.resize(mglevel); + lnz.resize(mglevel); gnx[mglevel-1] = gx; gnz[mglevel-1] = gz; diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index 1ff40e9b0b..6a57a0e621 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -172,8 +172,8 @@ LaplaceMultigrid::LaplaceMultigrid(Options *opt, const CELL_LOC loc, Mesh *mesh_ // Set up Multigrid Cycle - x = Array((Nx_local + 2) * (Nz_local + 2)); - b = Array((Nx_local + 2) * (Nz_local + 2)); + x.resize((Nx_local + 2) * (Nz_local + 2)); + b.resize((Nx_local + 2) * (Nz_local + 2)); if (mgcount == 0) { output<<" Smoothing type is "; diff --git a/src/invert/laplace/impls/mumps/mumps_laplace.cxx b/src/invert/laplace/impls/mumps/mumps_laplace.cxx index fa12c9844f..62adc88e58 100644 --- a/src/invert/laplace/impls/mumps/mumps_laplace.cxx +++ b/src/invert/laplace/impls/mumps/mumps_laplace.cxx @@ -211,21 +211,21 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc, Mesh *mesh_in = mes localrhssize += localmesh->xstart*(localmesh->LocalNz); int nxpe = localmesh->NXPE; - localrhs_size_array = Array(nxpe); + localrhs_size_array.resize(nxpe); localrhs_size_array[0] = localrhssize; if (nxpe>1) { for (int i=1; ixend-localmesh->xstart+1)*(localmesh->LocalNz); localrhs_size_array[nxpe-1] = (localmesh->LocalNx-localmesh->xstart)*(localmesh->LocalNz); } - rhs_positions = Array(nxpe); + rhs_positions.resize(nxpe); rhs_positions[0] = 0; for (int i=1; i(meshx * meshz); + rhs.resize(meshx * meshz); } - localrhs = Array(localrhssize); + localrhs.resize(localrhssize); // Set Arrays of matrix indices, using i (0<=i(maxmode + 1, localmesh->LocalNx); + data.bk.resize(maxmode + 1, localmesh->LocalNx); // Matrix to be solved - data.avec = Matrix(maxmode + 1, localmesh->LocalNx); - data.bvec = Matrix(maxmode + 1, localmesh->LocalNx); - data.cvec = Matrix(maxmode + 1, localmesh->LocalNx); + data.avec.resize(maxmode + 1, localmesh->LocalNx); + data.bvec.resize(maxmode + 1, localmesh->LocalNx); + data.cvec.resize(maxmode + 1, localmesh->LocalNx); // Working vectors - data.v = Matrix(maxmode + 1, localmesh->LocalNx); - data.w = Matrix(maxmode + 1, localmesh->LocalNx); + data.v.resize(maxmode + 1, localmesh->LocalNx); + data.w.resize(maxmode + 1, localmesh->LocalNx); // Result - data.xk = Matrix(maxmode + 1, localmesh->LocalNx); + data.xk.resize(maxmode + 1, localmesh->LocalNx); // Communication buffers. Space for 2 complex values for each kz - data.snd = Array(4 * (maxmode + 1)); - data.rcv = Array(4 * (maxmode + 1)); + data.snd.resize(4 * (maxmode + 1)); + data.rcv.resize(4 * (maxmode + 1)); - data.y2i = Array(maxmode + 1); + data.y2i.resize(maxmode + 1); } /// Take FFTs of data diff --git a/src/invert/laplace/impls/serial_band/serial_band.cxx b/src/invert/laplace/impls/serial_band/serial_band.cxx index f773f90996..c2d9f50493 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.cxx +++ b/src/invert/laplace/impls/serial_band/serial_band.cxx @@ -52,8 +52,8 @@ LaplaceSerialBand::LaplaceSerialBand(Options *opt, const CELL_LOC loc, Mesh *mes // Allocate memory int ncz = localmesh->LocalNz; - bk = Matrix(localmesh->LocalNx, ncz / 2 + 1); - bk1d = Array(localmesh->LocalNx); + bk.resize(localmesh->LocalNx, ncz / 2 + 1); + bk1d.resize(localmesh->LocalNx); //Initialise bk to 0 as we only visit 0<= kz <= maxmode in solve for(int kz=maxmode+1; kz < ncz/2 + 1; kz++){ @@ -62,17 +62,17 @@ LaplaceSerialBand::LaplaceSerialBand(Options *opt, const CELL_LOC loc, Mesh *mes } } - xk = Matrix(localmesh->LocalNx, ncz / 2 + 1); - xk1d = Array(localmesh->LocalNx); + xk.resize(localmesh->LocalNx, ncz / 2 + 1); + xk1d.resize(localmesh->LocalNx); - //Initialise xk to 0 as we only visit 0<= kz <= maxmode in solve - for(int kz=maxmode+1; kz < ncz/2 + 1; kz++){ - for (int ix=0; ixLocalNx; ix++){ + // Initialise xk to 0 as we only visit 0<= kz <= maxmode in solve + for (int kz = maxmode + 1; kz < ncz / 2 + 1; kz++) { + for (int ix = 0; ix < localmesh->LocalNx; ix++) { xk(ix, kz) = 0.0; } } - A = Matrix(localmesh->LocalNx, 5); + A.resize(localmesh->LocalNx, 5); } const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b) { diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.cxx b/src/invert/laplace/impls/shoot/shoot_laplace.cxx index 405fef96be..50044a937a 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.cxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.cxx @@ -53,9 +53,9 @@ LaplaceShoot::LaplaceShoot(Options *opt, const CELL_LOC loc, Mesh *mesh_in) // Allocate memory int size = (localmesh->LocalNz)/2 + 1; - km = Array(size); - kc = Array(size); - kp = Array(size); + km.resize(size); + kc.resize(size); + kp.resize(size); for(int i=0;i(size); + rhsk.resize(size); - buffer = Array(4 * maxmode); + buffer.resize(4 * maxmode); } const FieldPerp LaplaceShoot::solve(const FieldPerp &rhs) { diff --git a/src/invert/laplace/impls/spt/spt.cxx b/src/invert/laplace/impls/spt/spt.cxx index 705f198c29..22acf65cd9 100644 --- a/src/invert/laplace/impls/spt/spt.cxx +++ b/src/invert/laplace/impls/spt/spt.cxx @@ -67,7 +67,7 @@ LaplaceSPT::LaplaceSPT(Options *opt, const CELL_LOC loc, Mesh *mesh_in) // Temporary array for taking FFTs int ncz = localmesh->LocalNz; - dc1d = Array(ncz / 2 + 1); + dc1d.resize(ncz / 2 + 1); } LaplaceSPT::~LaplaceSPT() { @@ -510,16 +510,16 @@ void LaplaceSPT::finish(SPT_data &data, FieldPerp &x) { // SPT_data helper class void LaplaceSPT::SPT_data::allocate(int mm, int nx) { - bk = Matrix(mm, nx); - xk = Matrix(mm, nx); + bk.resize(mm, nx); + xk.resize(mm, nx); - gam = Matrix(mm, nx); + gam.resize(mm, nx); // Matrix to be solved - avec = Matrix(mm, nx); - bvec = Matrix(mm, nx); - cvec = Matrix(mm, nx); + avec.resize(mm, nx); + bvec.resize(mm, nx); + cvec.resize(mm, nx); - buffer = Array(4 * mm); + buffer.resize(4 * mm); } diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index 6fb32d5f14..87b6d3295d 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -82,15 +82,15 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) ////////////////////////////////////////////////// // Allocate storage for preconditioner - - nloc = xend - xstart + 1; // Number of X points on this processor + + nloc = xend - xstart + 1; // Number of X points on this processor nsys = localmesh->yend - localmesh->ystart + 1; // Number of separate Y slices - acoef = Matrix(nsys, nloc); - bcoef = Matrix(nsys, nloc); - ccoef = Matrix(nsys, nloc); - xvals = Matrix(nsys, nloc); - bvals = Matrix(nsys, nloc); + acoef.resize(nsys, nloc); + bcoef.resize(nsys, nloc); + ccoef.resize(nsys, nloc); + xvals.resize(nsys, nloc); + bvals.resize(nsys, nloc); // Create a cyclic reduction object cr = bout::utils::make_unique>(localmesh->getXcomm(), nloc); diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx index b1f763b6eb..6bb3206695 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx @@ -31,14 +31,14 @@ LaplaceXZcyclic::LaplaceXZcyclic(Mesh *m, Options *options, const CELL_LOC loc) // including boundaries but not guard cells nloc = xend - xstart + 1; - acoef = Matrix(nsys, nloc); - bcoef = Matrix(nsys, nloc); - ccoef = Matrix(nsys, nloc); - xcmplx = Matrix(nsys, nloc); - rhscmplx = Matrix(nsys, nloc); - - k1d = Array((m->LocalNz) / 2 + 1); - k1d_2 = Array((m->LocalNz) / 2 + 1); + acoef.resize(nsys, nloc); + bcoef.resize(nsys, nloc); + ccoef.resize(nsys, nloc); + xcmplx.resize(nsys, nloc); + rhscmplx.resize(nsys, nloc); + + k1d.resize((m->LocalNz) / 2 + 1); + k1d_2.resize((m->LocalNz) / 2 + 1); // Create a cyclic reduction object, operating on dcomplex values cr = bout::utils::make_unique>(localmesh->getXcomm(), nloc); diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 0bf59de09a..2cf52d9182 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -1856,17 +1856,17 @@ BoutMesh::CommHandle *BoutMesh::get_handle(int xlen, int ylen) { i = MPI_REQUEST_NULL; if (ylen > 0) { - ch->umsg_sendbuff = Array(ylen); - ch->dmsg_sendbuff = Array(ylen); - ch->umsg_recvbuff = Array(ylen); - ch->dmsg_recvbuff = Array(ylen); + ch->umsg_sendbuff.resize(ylen); + ch->dmsg_sendbuff.resize(ylen); + ch->umsg_recvbuff.resize(ylen); + ch->dmsg_recvbuff.resize(ylen); } if (xlen > 0) { - ch->imsg_sendbuff = Array(xlen); - ch->omsg_sendbuff = Array(xlen); - ch->imsg_recvbuff = Array(xlen); - ch->omsg_recvbuff = Array(xlen); + ch->imsg_sendbuff.resize(xlen); + ch->omsg_sendbuff.resize(xlen); + ch->imsg_recvbuff.resize(xlen); + ch->omsg_recvbuff.resize(xlen); } ch->xbufflen = xlen; @@ -1883,18 +1883,18 @@ BoutMesh::CommHandle *BoutMesh::get_handle(int xlen, int ylen) { // Check that the buffers are big enough (NOTE: Could search list for bigger buffers) if (ch->ybufflen < ylen) { - ch->umsg_sendbuff = Array(ylen); - ch->dmsg_sendbuff = Array(ylen); - ch->umsg_recvbuff = Array(ylen); - ch->dmsg_recvbuff = Array(ylen); + ch->umsg_sendbuff.resize(ylen); + ch->dmsg_sendbuff.resize(ylen); + ch->umsg_recvbuff.resize(ylen); + ch->dmsg_recvbuff.resize(ylen); ch->ybufflen = ylen; } if (ch->xbufflen < xlen) { - ch->imsg_sendbuff = Array(xlen); - ch->omsg_sendbuff = Array(xlen); - ch->imsg_recvbuff = Array(xlen); - ch->omsg_recvbuff = Array(xlen); + ch->imsg_sendbuff.resize(xlen); + ch->omsg_sendbuff.resize(xlen); + ch->imsg_recvbuff.resize(xlen); + ch->omsg_recvbuff.resize(xlen); ch->xbufflen = xlen; } diff --git a/src/mesh/interpolation/bilinear.cxx b/src/mesh/interpolation/bilinear.cxx index 0060cc12a0..ddfbc37586 100644 --- a/src/mesh/interpolation/bilinear.cxx +++ b/src/mesh/interpolation/bilinear.cxx @@ -31,8 +31,8 @@ Bilinear::Bilinear(int y_offset, Mesh *mesh) : Interpolation(y_offset, mesh), w0(localmesh), w1(localmesh), w2(localmesh), w3(localmesh) { // Index arrays contain guard cells in order to get subscripts right - i_corner = Tensor(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); - k_corner = Tensor(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); + i_corner.resize(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); + k_corner.resize(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); // Allocate Field3D members w0.allocate(); diff --git a/src/mesh/interpolation/hermite_spline.cxx b/src/mesh/interpolation/hermite_spline.cxx index b0c425470a..3fc0976a34 100644 --- a/src/mesh/interpolation/hermite_spline.cxx +++ b/src/mesh/interpolation/hermite_spline.cxx @@ -33,8 +33,8 @@ HermiteSpline::HermiteSpline(int y_offset, Mesh *mesh) h11_z(localmesh) { // Index arrays contain guard cells in order to get subscripts right - i_corner = Tensor(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); - k_corner = Tensor(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); + i_corner.resize(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); + k_corner.resize(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); // Allocate Field3D members h00_x.allocate(); diff --git a/src/mesh/interpolation/lagrange_4pt.cxx b/src/mesh/interpolation/lagrange_4pt.cxx index c942976bc3..a15fa5ded4 100644 --- a/src/mesh/interpolation/lagrange_4pt.cxx +++ b/src/mesh/interpolation/lagrange_4pt.cxx @@ -30,8 +30,8 @@ Lagrange4pt::Lagrange4pt(int y_offset, Mesh *mesh) : Interpolation(y_offset, mesh), t_x(localmesh), t_z(localmesh) { // Index arrays contain guard cells in order to get subscripts right - i_corner = Tensor(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); - k_corner = Tensor(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); + i_corner.resize(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); + k_corner.resize(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); t_x.allocate(); t_z.allocate(); diff --git a/src/solver/impls/euler/euler.cxx b/src/solver/impls/euler/euler.cxx index 235ff965e8..485bfa7b05 100644 --- a/src/solver/impls/euler/euler.cxx +++ b/src/solver/impls/euler/euler.cxx @@ -49,8 +49,8 @@ int EulerSolver::init(int nout, BoutReal tstep) { n3Dvars(), n2Dvars(), neq, nlocal); // Allocate memory - f0 = Array(nlocal); - f1 = Array(nlocal); + f0.resize(nlocal); + f1.resize(nlocal); // Put starting values into f0 save_vars(std::begin(f0)); diff --git a/src/solver/impls/imex-bdf2/imex-bdf2.cxx b/src/solver/impls/imex-bdf2/imex-bdf2.cxx index 341bf6a474..d792a28234 100644 --- a/src/solver/impls/imex-bdf2/imex-bdf2.cxx +++ b/src/solver/impls/imex-bdf2/imex-bdf2.cxx @@ -127,7 +127,7 @@ int IMEXBDF2::init(int nout, BoutReal tstep) { } if (have_constraints) { - is_dae = Array{nlocal}; + is_dae.resize(nlocal); // Call the Solver function, which sets the array // to zero when not a constraint, one for constraint set_id(std::begin(is_dae)); @@ -153,7 +153,7 @@ int IMEXBDF2::init(int nout, BoutReal tstep) { } // Allocate memory and initialise structures - u = Array{nlocal}; + u.resize(nlocal); for(int i=0;i{nlocal}); fV.emplace_back(Array{nlocal}); @@ -163,7 +163,7 @@ int IMEXBDF2::init(int nout, BoutReal tstep) { gFac.push_back(0.0); } - rhs = Array{nlocal}; + rhs.resize(nlocal); OPTION(options, adaptive, true); //Do we try to estimate the error? OPTION(options, nadapt, 4); //How often do we check the error @@ -171,7 +171,7 @@ int IMEXBDF2::init(int nout, BoutReal tstep) { OPTION(options, dtMax, out_timestep); OPTION(options, dtMin, dtMinFatal); if(adaptive){ - err = Array{nlocal}; + err.resize(nlocal); OPTION(options, adaptRtol, 1.0e-3); //Target relative error OPTION(options, mxstepAdapt, mxstep); //Maximum no. consecutive times we try to reduce timestep OPTION(options, scaleCushUp, 1.5); diff --git a/src/solver/impls/karniadakis/karniadakis.cxx b/src/solver/impls/karniadakis/karniadakis.cxx index 23cdc846b0..a714320334 100644 --- a/src/solver/impls/karniadakis/karniadakis.cxx +++ b/src/solver/impls/karniadakis/karniadakis.cxx @@ -74,16 +74,16 @@ int KarniadakisSolver::init(int nout, BoutReal tstep) { // Allocate memory - f1 = Array(nlocal); - f0 = Array(nlocal); - fm1 = Array(nlocal); - fm2 = Array(nlocal); + f1.resize(nlocal); + f0.resize(nlocal); + fm1.resize(nlocal); + fm2.resize(nlocal); - S0 = Array(nlocal); - Sm1 = Array(nlocal); - Sm2 = Array(nlocal); + S0.resize(nlocal); + Sm1.resize(nlocal); + Sm2.resize(nlocal); - D0 = Array(nlocal); + D0.resize(nlocal); first_time = true; diff --git a/src/solver/impls/power/power.cxx b/src/solver/impls/power/power.cxx index 04a1dd3b18..edb0467aaf 100644 --- a/src/solver/impls/power/power.cxx +++ b/src/solver/impls/power/power.cxx @@ -35,7 +35,7 @@ int PowerSolver::init(int nout, BoutReal tstep) { n3Dvars(), n2Dvars(), nglobal, nlocal); // Allocate memory - f0 = Array(nlocal); + f0.resize(nlocal); // Save the eigenvalue to the output dump.add(eigenvalue, "eigenvalue", true); diff --git a/src/solver/impls/rk3-ssp/rk3-ssp.cxx b/src/solver/impls/rk3-ssp/rk3-ssp.cxx index 435a9f40c1..6c6b3f8525 100644 --- a/src/solver/impls/rk3-ssp/rk3-ssp.cxx +++ b/src/solver/impls/rk3-ssp/rk3-ssp.cxx @@ -47,13 +47,13 @@ int RK3SSP::init(int nout, BoutReal tstep) { n3Dvars(), n2Dvars(), neq, nlocal); // Allocate memory - f = Array(nlocal); + f.resize(nlocal); // memory for taking a single time step - u1 = Array(nlocal); - u2 = Array(nlocal); - u3 = Array(nlocal); - L = Array(nlocal); + u1.resize(nlocal); + u2.resize(nlocal); + u3.resize(nlocal); + L.resize(nlocal); // Put starting values into f save_vars(std::begin(f)); diff --git a/src/solver/impls/rk4/rk4.cxx b/src/solver/impls/rk4/rk4.cxx index 867b5f881f..b910af96a3 100644 --- a/src/solver/impls/rk4/rk4.cxx +++ b/src/solver/impls/rk4/rk4.cxx @@ -52,16 +52,16 @@ int RK4Solver::init(int nout, BoutReal tstep) { n3Dvars(), n2Dvars(), neq, nlocal); // Allocate memory - f0 = Array(nlocal); - f1 = Array(nlocal); - f2 = Array(nlocal); + f0.resize(nlocal); + f1.resize(nlocal); + f2.resize(nlocal); // memory for taking a single time step - k1 = Array(nlocal); - k2 = Array(nlocal); - k3 = Array(nlocal); - k4 = Array(nlocal); - k5 = Array(nlocal); + k1.resize(nlocal); + k2.resize(nlocal); + k3.resize(nlocal); + k4.resize(nlocal); + k5.resize(nlocal); // Put starting values into f0 save_vars(std::begin(f0)); diff --git a/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx b/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx index c3bc0b3f3a..3aea8540b5 100644 --- a/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx +++ b/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx @@ -11,9 +11,9 @@ CASHKARPScheme::CASHKARPScheme(Options *options):RKScheme(options){ OPTION(options, followHighOrder, followHighOrder); //Allocate coefficient arrays - stageCoeffs = Matrix(numStages, numStages); - resultCoeffs = Matrix(numStages, numOrders); - timeCoeffs = Array(numStages); + stageCoeffs.resize(numStages, numStages); + resultCoeffs.resize(numStages, numOrders); + timeCoeffs.resize(numStages); //Zero out arrays (shouldn't be needed, but do for testing) for(int i=0;i(numStages, numStages); - resultCoeffs = Matrix(numStages, numOrders); - timeCoeffs = Array(numStages); + stageCoeffs.resize(numStages, numStages); + resultCoeffs.resize(numStages, numOrders); + timeCoeffs.resize(numStages); //Zero out arrays (shouldn't be needed, but do for testing) for(int i=0;i(numStages, numStages); - resultCoeffs = Matrix(numStages, numOrders); - timeCoeffs = Array(numStages); + stageCoeffs.resize(numStages, numStages); + resultCoeffs.resize(numStages, numOrders); + timeCoeffs.resize(numStages); //Zero out arrays (shouldn't be needed, but do for testing) for(int i=0;i(numStages, numStages); - resultCoeffs = Matrix(numStages, numOrders); - timeCoeffs = Array(numStages); + stageCoeffs.resize(numStages, numStages); + resultCoeffs.resize(numStages, numOrders); + timeCoeffs.resize(numStages); //Zero out arrays (shouldn't be needed, but do for testing) for(int i=0;i(nlocal); // Input - f2 = Array(nlocal); // Result--follow order - tmpState = Array(nlocal); + f0.resize(nlocal); // Input + f2.resize(nlocal); // Result--follow order + tmpState.resize(nlocal); // Put starting values into f0 save_vars(std::begin(f0)); diff --git a/src/solver/impls/rkgeneric/rkscheme.cxx b/src/solver/impls/rkgeneric/rkscheme.cxx index a7eac475ae..9be2387fa1 100644 --- a/src/solver/impls/rkgeneric/rkscheme.cxx +++ b/src/solver/impls/rkgeneric/rkscheme.cxx @@ -37,12 +37,12 @@ void RKScheme::init(const int nlocalIn, const int neqIn, const bool adaptiveIn, adaptive = adaptiveIn; //Allocate storage for stages - steps = Matrix(getStageCount(), nlocal); + steps.resize(getStageCount(), nlocal); zeroSteps(); //Allocate array for storing alternative order result if (adaptive) - resultAlt = Array(nlocal); // Result--alternative order + resultAlt.resize(nlocal); // Result--alternative order //Will probably only want the following when debugging, but leave it on for now if(diagnose){ diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index f327137062..96fb447ead 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -262,8 +262,8 @@ int SlepcSolver::init(int NOUT, BoutReal TIMESTEP) { //Also create vector for derivs etc. if SLEPc in charge of solving if(selfSolve && !ddtMode){ // Allocate memory - f0 = Array(localSize); - f1 = Array(localSize); + f0.resize(localSize); + f1.resize(localSize); } // Get total problem size diff --git a/tests/integrated/test-cyclic/test_cyclic.cxx b/tests/integrated/test-cyclic/test_cyclic.cxx index 4ab819d658..14c1445dce 100644 --- a/tests/integrated/test-cyclic/test_cyclic.cxx +++ b/tests/integrated/test-cyclic/test_cyclic.cxx @@ -37,11 +37,11 @@ int main(int argc, char **argv) { MPI_Comm_rank(BoutComm::get(), &mype); MPI_Comm_size(BoutComm::get(), &npe); - a = Matrix(nsys, n); - b = Matrix(nsys, n); - c = Matrix(nsys, n); - rhs = Matrix(nsys, n); - x = Matrix(nsys, n); + a.resize(nsys, n); + b.resize(nsys, n); + c.resize(nsys, n); + rhs.resize(nsys, n); + x.resize(nsys, n); // Set coefficients to some random numbers for(int s=0;s Date: Fri, 11 Jan 2019 17:25:04 +0000 Subject: [PATCH 0580/1783] Use type alias for Array::size_type = int --- include/bout/array.hxx | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/include/bout/array.hxx b/include/bout/array.hxx index 49cb3d7785..566f209183 100644 --- a/include/bout/array.hxx +++ b/include/bout/array.hxx @@ -69,6 +69,7 @@ template class Array { public: typedef T data_type; + using size_type = int; /*! * Create an empty array @@ -82,7 +83,7 @@ public: /*! * Create an array of given length */ - Array(int len) { + Array(size_type len) { ptr = get(len); } @@ -121,7 +122,7 @@ public: /*! * Resize the array to \p new_size */ - void resize(int new_size) { + void resize(size_type new_size) { release(ptr); ptr = get(new_size); } @@ -176,7 +177,7 @@ public: /*! * Return size of the array. Zero if the array is empty. */ - int size() const noexcept { + size_type size() const noexcept { if(!ptr) return 0; #ifdef BOUT_ARRAY_WITH_VALARRAY @@ -269,7 +270,7 @@ public: * or if ind is out of bounds. For efficiency no checking is performed, * so the user should perform checks. */ - T& operator[](int ind) { + T& operator[](size_type ind) { ASSERT3(0 <= ind && ind < size()); #ifdef BOUT_ARRAY_WITH_VALARRAY return ptr->operator[](ind); @@ -277,7 +278,7 @@ public: return ptr->data[ind]; #endif } - const T& operator[](int ind) const { + const T& operator[](size_type ind) const { ASSERT3(0 <= ind && ind < size()); #ifdef BOUT_ARRAY_WITH_VALARRAY return ptr->operator[](ind); @@ -303,10 +304,10 @@ private: * Handles the allocation and deletion of data */ struct ArrayData { - int len; ///< Size of the array + size_type len; ///< Size of the array T *data; ///< Array of data - ArrayData(int size) : len(size) { + ArrayData(size_type size) : len(size) { data = new T[len]; } ~ArrayData() { @@ -336,11 +337,11 @@ private: */ dataPtrType ptr; - typedef std::map< int, std::vector > storeType; - typedef std::vector< storeType > arenaType; + using storeType = std::map>; + using arenaType = std::vector; /*! - * This maps from array size (int) to vectors of pointers to ArrayData objects + * This maps from array size (size_type) to vectors of pointers to ArrayData objects * * By putting the static store inside a function it is initialised on first use, * and doesn't need to be separately declared for each type T @@ -393,7 +394,7 @@ private: * Returns a pointer to an ArrayData object with no * references. This is either from the store, or newly allocated */ - dataPtrType get(int len) { + dataPtrType get(size_type len) { dataPtrType p; auto& st = store()[len]; From 72248ef3ffd56f9a3a4099a390bd5417a94e05e4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 11 Jan 2019 17:25:48 +0000 Subject: [PATCH 0581/1783] Use type aliases consistently in Array (rather than typedefs) --- include/bout/array.hxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/bout/array.hxx b/include/bout/array.hxx index 566f209183..cd77812b85 100644 --- a/include/bout/array.hxx +++ b/include/bout/array.hxx @@ -68,7 +68,7 @@ template class Array { public: - typedef T data_type; + using data_type = T; using size_type = int; /*! @@ -225,8 +225,8 @@ public: ////////////////////////////////////////////////////////// // Iterators - typedef T* iterator; - typedef const T* const_iterator; + using iterator = T*; + using const_iterator = const T*; #ifndef BOUT_ARRAY_WITH_VALARRAY iterator begin() noexcept { return (ptr) ? ptr->data : nullptr; @@ -324,12 +324,12 @@ private: //Type defs to help keep things brief -- which backing do we use #ifdef BOUT_ARRAY_WITH_VALARRAY - typedef std::valarray dataBlock; + using dataBlock = std::valarray; #else - typedef ArrayData dataBlock; + using dataBlock = ArrayData; #endif - typedef std::shared_ptr dataPtrType; + using dataPtrType = std::shared_ptr; /*! * Pointer to the data container object owned by this Array. From 0c24a4a68bf3333847ffa2aa235786f344c3f405 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 11 Jan 2019 17:28:44 +0000 Subject: [PATCH 0582/1783] Check Arrays are of strictly positive size Assert is at a high CHECK level as this not a usual source of problems The check itself is in the low-level `Array::get` to avoid repeated checks in higher layers (e.g. `Matrix` constructors, `resize()`, etc.) --- include/bout/array.hxx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/bout/array.hxx b/include/bout/array.hxx index cd77812b85..96c0a1814f 100644 --- a/include/bout/array.hxx +++ b/include/bout/array.hxx @@ -391,10 +391,14 @@ private: } /*! - * Returns a pointer to an ArrayData object with no + * Returns a pointer to an ArrayData object of size \p len with no * references. This is either from the store, or newly allocated + * + * Expects \p len >= 0 */ dataPtrType get(size_type len) { + ASSERT3(len >= 0); + dataPtrType p; auto& st = store()[len]; From 658bb8d4cb3313afe4c87dca148218e13a03b9e5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 14 Jan 2019 09:49:49 +0000 Subject: [PATCH 0583/1783] Add warning to Array/Matrix/Tensor::resize docstring Existing data will be invalidated --- include/bout/array.hxx | 2 ++ include/utils.hxx | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/include/bout/array.hxx b/include/bout/array.hxx index 96c0a1814f..192144bb8b 100644 --- a/include/bout/array.hxx +++ b/include/bout/array.hxx @@ -121,6 +121,8 @@ public: /*! * Resize the array to \p new_size + * + * Note that this invalidates the existing data! */ void resize(size_type new_size) { release(ptr); diff --git a/include/utils.hxx b/include/utils.hxx index 204da60217..f481704689 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -104,6 +104,8 @@ public: } /// Resize the Matrix to \p new_size_1 by \p new_size_2 + /// + /// Note that this invalidates the existing data! void resize(size_type new_size_1, size_type new_size_2) { n1 = new_size_1; n2 = new_size_2; @@ -181,6 +183,8 @@ public: } /// Resize the Tensor to \p new_size_1 by \p new_size_2 by \p new_size_3 + /// + /// Note that this invalidates the existing data! void resize(size_type new_size_1, size_type new_size_2, size_type new_size_3) { n1 = new_size_1; n2 = new_size_2; From 17eed28ec879da12efe47174ced7649bcfc96513 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 14 Jan 2019 10:04:13 +0000 Subject: [PATCH 0584/1783] Add checks that Matrix/Tensor have strictly positive sizes --- include/utils.hxx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/utils.hxx b/include/utils.hxx index f481704689..d3d1f7f12e 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -96,6 +96,9 @@ public: Matrix() : n1(0), n2(0){}; Matrix(size_type n1, size_type n2) : n1(n1), n2(n2) { + ASSERT2(n1 >= 0); + ASSERT2(n2 >= 0); + data.resize(n1 * n2); } Matrix(const Matrix &other) : n1(other.n1), n2(other.n2), data(other.data) { @@ -107,6 +110,9 @@ public: /// /// Note that this invalidates the existing data! void resize(size_type new_size_1, size_type new_size_2) { + ASSERT2(new_size_1 >= 0); + ASSERT2(new_size_2 >= 0); + n1 = new_size_1; n2 = new_size_2; data.resize(new_size_1 * new_size_2); @@ -175,6 +181,9 @@ public: Tensor() : n1(0), n2(0), n3(0) {}; Tensor(size_type n1, size_type n2, size_type n3) : n1(n1), n2(n2), n3(n3) { + ASSERT2(n1 >= 0); + ASSERT2(n2 >= 0); + ASSERT2(n3 >= 0); data.resize(n1 * n2 * n3); } Tensor(const Tensor &other) : n1(other.n1), n2(other.n2), n3(other.n3), data(other.data) { @@ -186,6 +195,10 @@ public: /// /// Note that this invalidates the existing data! void resize(size_type new_size_1, size_type new_size_2, size_type new_size_3) { + ASSERT2(new_size_1 >= 0); + ASSERT2(new_size_2 >= 0); + ASSERT2(new_size_3 >= 0); + n1 = new_size_1; n2 = new_size_2; n3 = new_size_3; From d1449bbcb0f8f920d850852a2be420d8a793608e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 14 Jan 2019 11:16:37 +0000 Subject: [PATCH 0585/1783] Implement semi-optimisation for ShiftedMetric::calcYUpDown Forward-FFT whole field, then inverse-FFT for each parallel slice. Will make it easier to generalise to multiple parallel slices --- include/bout/paralleltransform.hxx | 7 ++- src/mesh/parallel/shiftedmetric.cxx | 69 +++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 34fabd061f..38b1604703 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -125,7 +125,7 @@ public: } /// A 3D array, implemented as nested vectors - using arr3Dvec = std::vector>>; + using arr3Dvec = std::vector>>; private: Mesh &mesh; ///< The mesh this paralleltransform is part of @@ -185,11 +185,14 @@ private: * @param[in] phs Phase shift, assumed to have length (mesh.LocalNz/2 + 1) i.e. the number of modes * @param[out] out A 1D array of length mesh.LocalNz, already allocated */ - void shiftZ(const BoutReal *in, const std::vector &phs, BoutReal *out) const; + void shiftZ(const BoutReal *in, const Array &phs, BoutReal *out) const; /// Calculate and store the phases for to/from field aligned and for /// the parallel slices using zShift void cachePhases(); + + std::vector shiftZ(const Field3D& f, const std::vector& phases, + const std::vector& y_offsets) const; }; diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 55eee670bd..6da967135b 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -109,28 +109,15 @@ void ShiftedMetric::cachePhases() { /*! * Calculate the Y up and down fields */ -void ShiftedMetric::calcYUpDown(Field3D &f) { +void ShiftedMetric::calcYUpDown(Field3D& f) { f.splitYupYdown(); - - Field3D& yup = f.yup(); - yup.allocate(); - - for(int jx=0;jx& phs, +void ShiftedMetric::shiftZ(const BoutReal* in, const Array& phs, BoutReal* out) const { int nmodes = mesh.LocalNz / 2 + 1; @@ -187,6 +174,50 @@ void ShiftedMetric::shiftZ(const BoutReal* in, const std::vector& phs, irfft(&cmplx[0], mesh.LocalNz, out); // Reverse FFT } +std::vector ShiftedMetric::shiftZ(const Field3D& f, + const std::vector& phases, + const std::vector& y_offsets) const { + + ASSERT1(phases.size() == y_offsets.size()); + + const int nmodes = mesh.LocalNz / 2 + 1; + + // FFT in Z of input field at each (x, y) point + arr3Dvec f_fft(mesh.LocalNx, + std::vector>(mesh.LocalNy, Array(nmodes))); + + std::vector results{}; + + for (int jx = 0; jx < mesh.LocalNx; jx++) { + for (int jy = 0; jy < mesh.LocalNy; jy++) { + rfft(f(jx, jy), mesh.LocalNz, &f_fft[jx][jy][0]); + } + } + + for (std::size_t i = 0; i < phases.size(); ++i) { + + results.emplace_back(&mesh); + results[i].allocate(); + results[i].setLocation(f.getLocation()); + + for (int jx = 0; jx < mesh.LocalNx; jx++) { + for (int jy = mesh.ystart; jy <= mesh.yend; jy++) { + + Array shifted_temp(f_fft[jx][jy + y_offsets[i]]); + shifted_temp.ensureUnique(); + + for (int jz = 1; jz < nmodes; ++jz) { + shifted_temp[jz] *= phases[i][jx][jy][jz]; + } + + irfft(&shifted_temp[0], mesh.LocalNz, results[i](jx, jy + y_offsets[i])); + } + } + } + + return results; +} + //Old approach retained so we can still specify a general zShift const Field3D ShiftedMetric::shiftZ(const Field3D &f, const Field2D &zangle) const { ASSERT1(&mesh == f.getMesh()); From f7fc1d861b7ebeb530f2dd2ddf4d3a1fc1952bc5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 14 Jan 2019 15:51:57 +0000 Subject: [PATCH 0586/1783] Implement multiple parallel slices for ShiftedMetric --- include/bout/paralleltransform.hxx | 23 ++- src/mesh/parallel/shiftedmetric.cxx | 112 ++++++++------ .../unit/mesh/parallel/test_shiftedmetric.cxx | 146 ++++++++++++------ 3 files changed, 191 insertions(+), 90 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 38b1604703..5ed14cd4f2 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -137,6 +137,20 @@ private: /// Cache of phase shifts for transforming from field-aligned coordinates to X-Z orthogonal coordinates arr3Dvec fromAlignedPhs; + /// Helper POD for parallel slice phase shifts + struct ParallelSlicePhase { + arr3Dvec phase_shift; + int y_offset; + }; + + /// Cache of phase shifts for the parallel slices. Slices are stored + /// in the following order: + /// {+1, ..., +n, -1, ..., -n} + /// slice[i] stores offset i+1 + /// slice[2*i + 1] stores offset -(i+1) + /// where i goes from 0 to (n-1), with n the number of y guard cells + std::vector parallel_slice_phases; + arr3Dvec yupPhs; ///< Cache of phase shifts for calculating yup fields arr3Dvec ydownPhs; ///< Cache of phase shifts for calculating ydown fields @@ -191,8 +205,13 @@ private: /// the parallel slices using zShift void cachePhases(); - std::vector shiftZ(const Field3D& f, const std::vector& phases, - const std::vector& y_offsets) const; + /// Shift a 3D field \p f in Z to all the parallel slices in \p phases + /// + /// @param[in] f The field to shift + /// @param[in] phases The phase and offset information for each parallel slice + /// @return The shifted parallel slices + std::vector shiftZ(const Field3D& f, + const std::vector& phases) const; }; diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 6da967135b..7abf316c7e 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -58,21 +58,13 @@ void ShiftedMetric::cachePhases() { fromAlignedPhs.resize(mesh.LocalNx); toAlignedPhs.resize(mesh.LocalNx); - yupPhs.resize(mesh.LocalNx); - ydownPhs.resize(mesh.LocalNx); - for (int jx = 0; jx < mesh.LocalNx; jx++) { fromAlignedPhs[jx].resize(mesh.LocalNy); toAlignedPhs[jx].resize(mesh.LocalNy); - yupPhs[jx].resize(mesh.LocalNy); - ydownPhs[jx].resize(mesh.LocalNy); for (int jy = 0; jy < mesh.LocalNy; jy++) { fromAlignedPhs[jx][jy].resize(nmodes); toAlignedPhs[jx][jy].resize(nmodes); - - yupPhs[jx][jy].resize(nmodes); - ydownPhs[jx][jy].resize(nmodes); } } @@ -89,33 +81,46 @@ void ShiftedMetric::cachePhases() { } } - // Yup/Ydown phases -- note we don't shift in the boundaries/guards - for (int jx = 0; jx < mesh.LocalNx; jx++) { - for (int jy = mesh.ystart; jy <= mesh.yend; jy++) { - BoutReal yupShift = zShift(jx, jy) - zShift(jx, jy + 1); - BoutReal ydownShift = zShift(jx, jy) - zShift(jx, jy - 1); - - for (int jz = 0; jz < nmodes; jz++) { - BoutReal kwave = jz * 2.0 * PI / zlength; // wave number is 1/[rad] + // Allocate space for parallel slice caches: y-guard cells in each + // direction + parallel_slice_phases.resize(mesh.ystart * 2); + + // Careful with the indices/offsets! Offsets are 1-indexed (as 0 + // would be the original slice), and Mesh::ystart is the number of + // guard cells. The parallel slice vector stores the offsets as + // {+1, ..., +n, -1, ..., -n} + // Once parallel_slice_phases is initialised though, each element + // stores its phase and offset, so we don't need to faff about after + // this + for (int i = 0; i < mesh.ystart; ++i) { + parallel_slice_phases[i].phase_shift = + arr3Dvec(mesh.LocalNx, + std::vector>(mesh.LocalNy, Array(nmodes))); + parallel_slice_phases[i].y_offset = i + 1; - yupPhs[jx][jy][jz] = dcomplex(cos(kwave * yupShift), -sin(kwave * yupShift)); - ydownPhs[jx][jy][jz] = - dcomplex(cos(kwave * ydownShift), -sin(kwave * ydownShift)); - } - } + parallel_slice_phases[mesh.ystart + i].phase_shift = + arr3Dvec(mesh.LocalNx, + std::vector>(mesh.LocalNy, Array(nmodes))); + parallel_slice_phases[mesh.ystart + i].y_offset = -(i + 1); } -} -/*! - * Calculate the Y up and down fields - */ -void ShiftedMetric::calcYUpDown(Field3D& f) { - f.splitYupYdown(); + // Parallel slice phases -- note we don't shift in the boundaries/guards + for (auto& slice : parallel_slice_phases) { + for (int jx = 0; jx < mesh.LocalNx; jx++) { + for (int jy = mesh.ystart; jy <= mesh.yend; jy++) { + + BoutReal slice_shift = zShift(jx, jy) - zShift(jx, jy + slice.y_offset); - auto results = shiftZ(f, {yupPhs, ydownPhs}, {+1, -1}); + for (int jz = 0; jz < nmodes; jz++) { + // wave number is 1/[rad] + BoutReal kwave = jz * 2.0 * PI / zlength; - f.yup() = results[0]; - f.ydown() = results[1]; + slice.phase_shift[jx][jy][jz] = + dcomplex(cos(kwave * slice_shift), -sin(kwave * slice_shift)); + } + } + } + } } /*! @@ -174,11 +179,23 @@ void ShiftedMetric::shiftZ(const BoutReal* in, const Array& phs, irfft(&cmplx[0], mesh.LocalNz, out); // Reverse FFT } -std::vector ShiftedMetric::shiftZ(const Field3D& f, - const std::vector& phases, - const std::vector& y_offsets) const { - ASSERT1(phases.size() == y_offsets.size()); +void ShiftedMetric::calcYUpDown(Field3D& f) { + + auto results = shiftZ(f, parallel_slice_phases); + + ASSERT3(results.size() == parallel_slice_phases.size()); + + f.splitYupYdown(); + + for (std::size_t i = 0; i < results.size(); ++i) { + f.ynext(parallel_slice_phases[i].y_offset) = std::move(results[i]); + } +} + +std::vector +ShiftedMetric::shiftZ(const Field3D& f, + const std::vector& phases) const { const int nmodes = mesh.LocalNz / 2 + 1; @@ -186,31 +203,40 @@ std::vector ShiftedMetric::shiftZ(const Field3D& f, arr3Dvec f_fft(mesh.LocalNx, std::vector>(mesh.LocalNy, Array(nmodes))); - std::vector results{}; - for (int jx = 0; jx < mesh.LocalNx; jx++) { for (int jy = 0; jy < mesh.LocalNy; jy++) { rfft(f(jx, jy), mesh.LocalNz, &f_fft[jx][jy][0]); } } - for (std::size_t i = 0; i < phases.size(); ++i) { + std::vector results{}; + + for (auto& phase : phases) { + // In C++17 std::vector::emplace_back returns a reference, which + // would be very useful here! - results.emplace_back(&mesh); - results[i].allocate(); - results[i].setLocation(f.getLocation()); + // FIXME: initialisation to -1 to avoid checkData choking on the + // uninitialised regions in assignment into the Field parallel + // slices in calcYUpDown + results.emplace_back(-1.0, &mesh); + auto& current_result = results.back(); + // FIXME: uncomment the following after fixing Field3D::operator= + // current_result.allocate(); + current_result.setLocation(f.getLocation()); for (int jx = 0; jx < mesh.LocalNx; jx++) { for (int jy = mesh.ystart; jy <= mesh.yend; jy++) { - Array shifted_temp(f_fft[jx][jy + y_offsets[i]]); + // Deep copy the FFT'd field + Array shifted_temp(f_fft[jx][jy + phase.y_offset]); shifted_temp.ensureUnique(); for (int jz = 1; jz < nmodes; ++jz) { - shifted_temp[jz] *= phases[i][jx][jy][jz]; + shifted_temp[jz] *= phase.phase_shift[jx][jy][jz]; } - irfft(&shifted_temp[0], mesh.LocalNz, results[i](jx, jy + y_offsets[i])); + irfft(shifted_temp.begin(), mesh.LocalNz, + current_result(jx, jy + phase.y_offset)); } } } diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 4d8c2885a7..a03cd9a593 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -136,20 +136,29 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { } TEST_F(ShiftedMetricTest, CalcYUpDown) { + // Use two y-guards to test multiple parallel slices + mesh->ystart = 2; + mesh->yend = mesh->LocalNy - 3; + + // We don't shift in the guard cells, and the parallel slices are + // stored offset in y, therefore we need to make new regions that we + // can compare the expected and actual outputs over output_info.disable(); - auto region_yup = mesh->getRegion("RGN_NOY"); - region_yup.periodicShift(ShiftedMetricTest::nz, - ShiftedMetricTest::ny * ShiftedMetricTest::nz); - mesh->addRegion("RGN_YUP", region_yup); - - auto region_ydown = mesh->getRegion("RGN_NOY"); - region_ydown.periodicShift(-ShiftedMetricTest::nz, - ShiftedMetricTest::ny * ShiftedMetricTest::nz); - mesh->addRegion("RGN_YDOWN", region_ydown); + mesh->addRegion3D("RGN_YUP", + Region(0, mesh->LocalNx - 1, mesh->ystart + 1, mesh->yend + 1, + 0, mesh->LocalNz - 1, mesh->LocalNy, mesh->LocalNz)); + mesh->addRegion3D("RGN_YUP2", + Region(0, mesh->LocalNx - 1, mesh->ystart + 2, mesh->yend + 2, + 0, mesh->LocalNz - 1, mesh->LocalNy, mesh->LocalNz)); + + mesh->addRegion3D("RGN_YDOWN", + Region(0, mesh->LocalNx - 1, mesh->ystart - 1, mesh->yend - 1, + 0, mesh->LocalNz - 1, mesh->LocalNy, mesh->LocalNz)); + mesh->addRegion3D("RGN_YDOWN2", + Region(0, mesh->LocalNx - 1, mesh->ystart - 2, mesh->yend - 2, + 0, mesh->LocalNz - 1, mesh->LocalNy, mesh->LocalNz)); output_info.enable(); - ShiftedMetric shifted{*mesh, zShift}; - Field3D input{mesh}; fillField(input, {{{1., 2., 3., 4., 5., 6., 7.}, @@ -170,48 +179,95 @@ TEST_F(ShiftedMetricTest, CalcYUpDown) { {1., 2., 3., 4., 5., 6., 7.}, {1., 2., 3., 4., 5., 6., 7.}}}); + // Actual interesting bit here! + ShiftedMetric shifted{*mesh, zShift}; shifted.calcYUpDown(input); - Field3D expected_up{mesh}; - - fillField(expected_up, {{{0., 0., 0., 0., 0., 0., 0.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}}, - - {{0., 0., 0., 0., 0., 0., 0.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}}, - - {{0., 0., 0., 0., 0., 0., 0.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}, - {2., 3., 4., 5., 6., 7., 1.}}}); + // Expected output values - Field3D expected_down{mesh}; + Field3D expected_up_1{mesh}; - fillField(expected_down, {{{7., 1., 2., 3., 4., 5., 6.}, - {7., 1., 2., 3., 4., 5., 6.}, - {7., 1., 2., 3., 4., 5., 6.}, - {7., 1., 2., 3., 4., 5., 6.}, + // Note: here zeroes are for values we don't expect to read + fillField(expected_up_1, {{{0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {2., 3., 4., 5., 6., 7., 1.}, {0., 0., 0., 0., 0., 0., 0.}}, - {{7., 1., 2., 3., 4., 5., 6.}, - {7., 1., 2., 3., 4., 5., 6.}, - {7., 1., 2., 3., 4., 5., 6.}, - {7., 1., 2., 3., 4., 5., 6.}, + {{0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {2., 3., 4., 5., 6., 7., 1.}, {0., 0., 0., 0., 0., 0., 0.}}, - {{7., 1., 2., 3., 4., 5., 6.}, - {7., 1., 2., 3., 4., 5., 6.}, - {7., 1., 2., 3., 4., 5., 6.}, - {7., 1., 2., 3., 4., 5., 6.}, + {{0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {2., 3., 4., 5., 6., 7., 1.}, {0., 0., 0., 0., 0., 0., 0.}}}); - EXPECT_TRUE(IsField3DEqualField3D(input.yup(), expected_up, "RGN_YUP")); - EXPECT_TRUE(IsField3DEqualField3D(input.ydown(), expected_down, "RGN_YDOWN")); + Field3D expected_up_2{mesh}; + + fillField(expected_up_2, {{{0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {3., 4., 5., 6., 7., 1., 2.}}, + + {{0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {3., 4., 5., 6., 7., 1., 2.}}, + + {{0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {3., 4., 5., 6., 7., 1., 2.}}}); + + Field3D expected_down_1{mesh}; + + fillField(expected_down_1, {{{0., 0., 0., 0., 0., 0., 0.}, + {7., 1., 2., 3., 4., 5., 6.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}}, + + {{0., 0., 0., 0., 0., 0., 0.}, + {7., 1., 2., 3., 4., 5., 6.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}}, + + {{0., 0., 0., 0., 0., 0., 0.}, + {7., 1., 2., 3., 4., 5., 6.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}}}); + + Field3D expected_down2{mesh}; + + fillField(expected_down2, {{{6., 7., 1., 2., 3., 4., 5.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}}, + + {{6., 7., 1., 2., 3., 4., 5.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}}, + + {{6., 7., 1., 2., 3., 4., 5.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0., 0., 0.}}}); + + EXPECT_TRUE(IsField3DEqualField3D(input.ynext(1), expected_up_1, "RGN_YUP")); + EXPECT_TRUE(IsField3DEqualField3D(input.ynext(2), expected_up_2, "RGN_YUP2")); + EXPECT_TRUE(IsField3DEqualField3D(input.ynext(-1), expected_down_1, "RGN_YDOWN")); + EXPECT_TRUE(IsField3DEqualField3D(input.ynext(-2), expected_down2, "RGN_YDOWN2")); } From 4064d23e6fd1daa223fbb87361ba95df32571723 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 21 Nov 2018 15:37:29 +0000 Subject: [PATCH 0587/1783] Guard tests that might not throw at low CHECK --- tests/unit/field/test_field3d.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 2b21b284a5..c6fe34f8c3 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -218,8 +218,10 @@ TEST_F(Field3DTest, MergeYupYDown) { EXPECT_FALSE(field.hasYupYdown()); +#if CHECK > 2 EXPECT_THROW(field.yup(), BoutException); EXPECT_THROW(field.ydown(), BoutException); +#endif // Should be able to merge again without any problems EXPECT_NO_THROW(field.mergeYupYdown()); @@ -238,8 +240,10 @@ TEST_F(Field3DTest, SplitThenMergeYupYDown) { field.mergeYupYdown(); +#if CHECK > 2 EXPECT_THROW(field.yup(), BoutException); EXPECT_THROW(field.ydown(), BoutException); +#endif } TEST_F(Field3DTest, MultipleYupYdown) { From 901b8c119e21f92ab0fafc6485ecef4b73d0b6eb Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 14 Jan 2019 16:38:34 +0000 Subject: [PATCH 0588/1783] Fix test-smooth for multiple parallel slices --- tests/integrated/test-smooth/test_smooth.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/integrated/test-smooth/test_smooth.cxx b/tests/integrated/test-smooth/test_smooth.cxx index f1246d0fed..15f7c656ec 100644 --- a/tests/integrated/test-smooth/test_smooth.cxx +++ b/tests/integrated/test-smooth/test_smooth.cxx @@ -17,7 +17,8 @@ int main(int argc, char **argv) { Field2D input2d = f.create2D("1 + sin(2*y)"); Field3D input3d = f.create3D("gauss(x-0.5,0.2)*gauss(y-pi)*sin(3*y - z)"); - input3d.mergeYupYdown(); + input3d.splitYupYdown(); + mesh->getParallelTransform().calcYUpDown(input3d); SAVE_ONCE2(input2d, input3d); From a215003ade26096122280c162fb1b18306f55ebb Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 14 Jan 2019 16:42:16 +0000 Subject: [PATCH 0589/1783] Let interp_to in y work with multiple parallel slices --- include/interpolation.hxx | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/include/interpolation.hxx b/include/interpolation.hxx index ad72870878..038285f824 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -118,15 +118,7 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { // At least 2 boundary cells needed for interpolation in y-direction ASSERT0(fieldmesh->ystart >= 2); - if (var.hasYupYdown() && ((&var.yup() != &var) || (&var.ydown() != &var))) { - // Field "var" has distinct yup and ydown fields which - // will be used to calculate a derivative along - // the magnetic field - throw BoutException( - "At the moment, fields with yup/ydown cannot use interp_to.\n" - "If we implement a 3-point stencil for interpolate or double-up\n" - "/double-down fields, then we can use this case."); - + if (var.hasYupYdown()) { if ((location == CELL_CENTRE) && (loc == CELL_YLOW)) { // C2L BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { // Producing a stencil centred around a lower X value From 1b0d149ca5afb394bf15cda06d45a3db612b48fe Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 14 Jan 2019 17:29:52 +0000 Subject: [PATCH 0590/1783] Enable higher-order derivatives with multiple parallel slices --- include/bout/index_derivs.hxx | 31 ++--------------------- include/bout/index_derivs_interface.hxx | 33 ++++++++++--------------- src/mesh/difops.cxx | 4 +-- 3 files changed, 17 insertions(+), 51 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index 6a4c2f5293..af453a5f83 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -619,7 +619,7 @@ struct registerMethod { ///////////////////////////////////////////////////////////////////////////////// produceCombinations, + WRAP_ENUM(DIRECTION, YOrthogonal), WRAP_ENUM(DIRECTION, Z)>, Set, Set, TypeContainer>, Set< @@ -640,22 +640,8 @@ produceCombinations>> registerDerivatives(registerMethod{}); -produceCombinations, Set, - Set, TypeContainer>, - Set< - // Standard - DerivativeType, DerivativeType, - // Standard 2nd order - DerivativeType, - // Standard 4th order - // Upwind - DerivativeType, DerivativeType, - // Flux - DerivativeType>> - registerDerivativesYOrtho(registerMethod{}); - produceCombinations, + WRAP_ENUM(DIRECTION, YOrthogonal), WRAP_ENUM(DIRECTION, Z)>, Set, Set, TypeContainer>, Set< @@ -670,19 +656,6 @@ produceCombinations>> registerStaggeredDerivatives(registerMethod{}); -produceCombinations, - Set, - Set, TypeContainer>, - Set< - // Standard - DerivativeType, - // Standard 2nd order - // Upwind - DerivativeType, DerivativeType, - // Flux - DerivativeType>> - registerStaggeredDerivativesYOrtho(registerMethod{}); - class FFTDerivativeType { public: template diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 154a6b9fd6..4ebdc2ac59 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -207,14 +207,13 @@ template T DDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - if (std::is_base_of::value && f.hasYupYdown() - && ((&f.yup() != &f) || (&f.ydown() != &f))) { + if (std::is_base_of::value && f.hasYupYdown()) { return standardDerivative(f, outloc, method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = - standardDerivative(f_aligned, outloc, method, region); + T result = standardDerivative(f_aligned, outloc, + method, region); return f.getMesh()->fromFieldAligned(result); } } @@ -223,14 +222,13 @@ template T D2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - if (std::is_base_of::value && f.hasYupYdown() - && ((&f.yup() != &f) || (&f.ydown() != &f))) { + if (std::is_base_of::value && f.hasYupYdown()) { return standardDerivative( f, outloc, method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = standardDerivative(f_aligned, outloc, - method, region); + T result = standardDerivative( + f_aligned, outloc, method, region); return f.getMesh()->fromFieldAligned(result); } } @@ -239,14 +237,13 @@ template T D4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - if (std::is_base_of::value && f.hasYupYdown() - && ((&f.yup() != &f) || (&f.ydown() != &f))) { + if (std::is_base_of::value && f.hasYupYdown()) { return standardDerivative( f, outloc, method, region); } else { const T f_aligned = f.getMesh()->toFieldAligned(f); - T result = standardDerivative(f_aligned, outloc, - method, region); + T result = standardDerivative( + f_aligned, outloc, method, region); return f.getMesh()->fromFieldAligned(result); } } @@ -312,10 +309,8 @@ template T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() - && ((&f.yup() != &f) || (&f.ydown() != &f))); - bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() - && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); + bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown()); + bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown()); if (fHasParallelSlices && velHasParallelSlices) { return flowDerivative(vel, f, outloc, method, region); @@ -332,10 +327,8 @@ template T FDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown() - && ((&f.yup() != &f) || (&f.ydown() != &f))); - bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown() - && ((&vel.yup() != &vel) || (&vel.ydown() != &vel))); + bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown()); + bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown()); if (fHasParallelSlices && velHasParallelSlices) { return flowDerivative(vel, f, outloc, method, region); diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index c924ae11e0..fa88ec6868 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -340,8 +340,8 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg result.allocate(); - bool vUseUpDown = (v.hasYupYdown() && ((&v.yup() != &v) || (&v.ydown() != &v))); - bool fUseUpDown = (f.hasYupYdown() && ((&f.yup() != &f) || (&f.ydown() != &f))); + bool vUseUpDown = v.hasYupYdown(); + bool fUseUpDown = f.hasYupYdown(); if (vUseUpDown && fUseUpDown) { // Both v and f have up/down fields From f7dd43a130b6610de8d12343d862914ee6b176da Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 15 Jan 2019 11:55:10 +0000 Subject: [PATCH 0591/1783] Provide functionality on ArrayData to match std::valarray interface Allows us to remove a large number of ifdef directives for conditional compilation --- include/bout/array.hxx | 57 ++++++++++-------------------------------- 1 file changed, 13 insertions(+), 44 deletions(-) diff --git a/include/bout/array.hxx b/include/bout/array.hxx index 49cb3d7785..1ecfcffaa4 100644 --- a/include/bout/array.hxx +++ b/include/bout/array.hxx @@ -179,14 +179,11 @@ public: int size() const noexcept { if(!ptr) return 0; -#ifdef BOUT_ARRAY_WITH_VALARRAY + // Note: std::valarray::size is technically not noexcept, so // Array::size shouldn't be either if we're using valarrays -- in // practice, it is so this shouldn't matter return ptr->size(); -#else - return ptr->len; -#endif } /*! @@ -210,11 +207,7 @@ public: dataPtrType p = get(size()); //Make copy of the underlying data -#ifdef BOUT_ARRAY_WITH_VALARRAY p->operator=((*ptr)); -#else - std::copy(begin(), end(), p->begin()); -#endif //Update the local pointer and release old //Can't just do ptr=p as need to try to add to store. @@ -226,41 +219,24 @@ public: // Iterators typedef T* iterator; typedef const T* const_iterator; -#ifndef BOUT_ARRAY_WITH_VALARRAY + iterator begin() noexcept { - return (ptr) ? ptr->data : nullptr; + return (ptr) ? std::begin(*ptr) : nullptr; } iterator end() noexcept { - return (ptr) ? ptr->data + ptr->len : nullptr; + return (ptr) ? std::end(*ptr) : nullptr; } // Const iterators const_iterator begin() const noexcept { - return (ptr) ? ptr->data : nullptr; - } - - const_iterator end() const noexcept { - return (ptr) ? ptr->data + ptr->len : nullptr; - } -#else - iterator begin() { return (ptr) ? std::begin(*ptr) : nullptr; } - iterator end() { + const_iterator end() const noexcept { return (ptr) ? std::end(*ptr) : nullptr; } - // Const iterators -- should revisit with cbegin and cend in c++14 and greater - const_iterator begin() const { - return (ptr) ? std::begin(*ptr) : nullptr; - } - - const_iterator end() const { - return (ptr) ? std::end(*ptr) : nullptr; - } -#endif ////////////////////////////////////////////////////////// // Element access @@ -271,19 +247,11 @@ public: */ T& operator[](int ind) { ASSERT3(0 <= ind && ind < size()); -#ifdef BOUT_ARRAY_WITH_VALARRAY return ptr->operator[](ind); -#else - return ptr->data[ind]; -#endif } const T& operator[](int ind) const { ASSERT3(0 <= ind && ind < size()); -#ifdef BOUT_ARRAY_WITH_VALARRAY return ptr->operator[](ind); -#else - return ptr->data[ind]; -#endif } /*! @@ -298,8 +266,9 @@ public: private: #ifndef BOUT_ARRAY_WITH_VALARRAY + /*! - * ArrayData holds the actual data, and reference count + * ArrayData holds the actual data * Handles the allocation and deletion of data */ struct ArrayData { @@ -312,13 +281,17 @@ private: ~ArrayData() { delete[] data; } - iterator begin() { + iterator begin() const { return data; } - iterator end() { + iterator end() const { return data + len; } + int size() const { return len;} + void operator=(ArrayData &in) { std::copy(std::begin(in), std::end(in), begin());} + T operator[](int ind){return data[ind];}; }; + #endif //Type defs to help keep things brief -- which backing do we use @@ -432,11 +405,7 @@ private: if (d.use_count() == 1) { if (useStore()) { // Put back into store -#ifdef BOUT_ARRAY_WITH_VALARRAY store()[d->size()].push_back(std::move(d)); -#else - store()[d->len].push_back(std::move(d)); -#endif // Could return here but seems to slow things down a lot } } From 4d065b3a022579282b21ed23a414d3ed9cfa3f06 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 15 Jan 2019 11:57:44 +0000 Subject: [PATCH 0592/1783] Fix bug with new ShiftedMetric implementation: Arrays weren't unique Tighten up the unit tests to catch this --- src/mesh/parallel/shiftedmetric.cxx | 8 +- .../unit/mesh/parallel/test_shiftedmetric.cxx | 342 +++++++++--------- 2 files changed, 182 insertions(+), 168 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 7abf316c7e..cf6124bd29 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -93,11 +93,15 @@ void ShiftedMetric::cachePhases() { // stores its phase and offset, so we don't need to faff about after // this for (int i = 0; i < mesh.ystart; ++i) { + // NOTE: std::vector constructor here takes a **copy** of the + // Array! We *must* call `Array::ensureUnique` on each element + // before using it! parallel_slice_phases[i].phase_shift = arr3Dvec(mesh.LocalNx, std::vector>(mesh.LocalNy, Array(nmodes))); parallel_slice_phases[i].y_offset = i + 1; + // Backwards parallel slices parallel_slice_phases[mesh.ystart + i].phase_shift = arr3Dvec(mesh.LocalNx, std::vector>(mesh.LocalNy, Array(nmodes))); @@ -109,6 +113,7 @@ void ShiftedMetric::cachePhases() { for (int jx = 0; jx < mesh.LocalNx; jx++) { for (int jy = mesh.ystart; jy <= mesh.yend; jy++) { + slice.phase_shift[jx][jy].ensureUnique(); BoutReal slice_shift = zShift(jx, jy) - zShift(jx, jy + slice.y_offset); for (int jz = 0; jz < nmodes; jz++) { @@ -205,7 +210,8 @@ ShiftedMetric::shiftZ(const Field3D& f, for (int jx = 0; jx < mesh.LocalNx; jx++) { for (int jy = 0; jy < mesh.LocalNy; jy++) { - rfft(f(jx, jy), mesh.LocalNz, &f_fft[jx][jy][0]); + f_fft[jx][jy].ensureUnique(); + rfft(f(jx, jy), mesh.LocalNz, f_fft[jx][jy].begin()); } } diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index a03cd9a593..8a806506c3 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -20,7 +20,37 @@ class ShiftedMetricTest : public ::testing::Test { zShift = Field2D{mesh}; - fillField(zShift, {{1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}}); + fillField(zShift, {{1., 2., 3., 4., 5., 6., 7.}, + {2., 4., 6., 8., 10., 12., 14.}, + {3., 6., 9., 12., 15., 18., 21.}}); + + Field3D input_temp{mesh}; + + fillField(input_temp, {{{1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}}, + + {{1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}}, + + {{1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}, + {1., 2., 3., 4., 5.}}}); + + input = std::move(input_temp); dynamic_cast(mesh)->setCoordinates(std::make_shared( mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, @@ -35,100 +65,74 @@ class ShiftedMetricTest : public ::testing::Test { } static constexpr int nx = 3; - static constexpr int ny = 5; - static constexpr int nz = 7; + static constexpr int ny = 7; + static constexpr int nz = 5; Field2D zShift; + Field3D input; }; TEST_F(ShiftedMetricTest, ToFieldAligned) { ShiftedMetric shifted{*mesh, zShift}; - Field3D input{mesh}; - - fillField(input, {{{1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}}, - - {{1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}}, - - {{1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}}}); - Field3D expected{mesh}; - fillField(expected, {{{2., 3., 4., 5., 6., 7., 1.}, - {3., 4., 5., 6., 7., 1., 2.}, - {4., 5., 6., 7., 1., 2., 3.}, - {5., 6., 7., 1., 2., 3., 4.}, - {6., 7., 1., 2., 3., 4., 5.}}, - - {{2., 3., 4., 5., 6., 7., 1.}, - {3., 4., 5., 6., 7., 1., 2.}, - {4., 5., 6., 7., 1., 2., 3.}, - {5., 6., 7., 1., 2., 3., 4.}, - {6., 7., 1., 2., 3., 4., 5.}}, - - {{2., 3., 4., 5., 6., 7., 1.}, - {3., 4., 5., 6., 7., 1., 2.}, - {4., 5., 6., 7., 1., 2., 3.}, - {5., 6., 7., 1., 2., 3., 4.}, - {6., 7., 1., 2., 3., 4., 5.}}}); - - EXPECT_TRUE(IsField3DEqualField3D(shifted.toFieldAligned(input), expected)); + fillField(expected, {{{2., 3., 4., 5., 1.}, + {3., 4., 5., 1., 2.}, + {4., 5., 1., 2., 3.}, + {5., 1., 2., 3., 4.}, + {1., 2., 3., 4., 5.}, + {2., 3., 4., 5., 1.}, + {3., 4., 5., 1., 2.}}, + + {{3., 4., 5., 1., 2.}, + {5., 1., 2., 3., 4.}, + {2., 3., 4., 5., 1.}, + {4., 5., 1., 2., 3.}, + {1., 2., 3., 4., 5.}, + {3., 4., 5., 1., 2.}, + {5., 1., 2., 3., 4.}}, + + {{4., 5., 1., 2., 3.}, + {2., 3., 4., 5., 1.}, + {5., 1., 2., 3., 4.}, + {3., 4., 5., 1., 2.}, + {1., 2., 3., 4., 5.}, + {4., 5., 1., 2., 3.}, + {2., 3., 4., 5., 1.}}}); + + EXPECT_TRUE( + IsField3DEqualField3D(shifted.toFieldAligned(input), expected, "RGN_ALL", 1.e-12)); } TEST_F(ShiftedMetricTest, FromFieldAligned) { ShiftedMetric shifted{*mesh, zShift}; - Field3D input{mesh}; - - fillField(input, {{{1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}}, - - {{1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}}, - - {{1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}}}); - Field3D expected{mesh}; - fillField(expected, {{{7., 1., 2., 3., 4., 5., 6.}, - {6., 7., 1., 2., 3., 4., 5.}, - {5., 6., 7., 1., 2., 3., 4.}, - {4., 5., 6., 7., 1., 2., 3.}, - {3., 4., 5., 6., 7., 1., 2.}}, - - {{7., 1., 2., 3., 4., 5., 6.}, - {6., 7., 1., 2., 3., 4., 5.}, - {5., 6., 7., 1., 2., 3., 4.}, - {4., 5., 6., 7., 1., 2., 3.}, - {3., 4., 5., 6., 7., 1., 2.}}, - - {{7., 1., 2., 3., 4., 5., 6.}, - {6., 7., 1., 2., 3., 4., 5.}, - {5., 6., 7., 1., 2., 3., 4.}, - {4., 5., 6., 7., 1., 2., 3.}, - {3., 4., 5., 6., 7., 1., 2.}}}); + fillField(expected, {{{5., 1., 2., 3., 4.}, + {4., 5., 1., 2., 3.}, + {3., 4., 5., 1., 2.}, + {2., 3., 4., 5., 1.}, + {1., 2., 3., 4., 5.}, + {5., 1., 2., 3., 4.}, + {4., 5., 1., 2., 3.}}, + + {{4., 5., 1., 2., 3.}, + {2., 3., 4., 5., 1.}, + {5., 1., 2., 3., 4.}, + {3., 4., 5., 1., 2.}, + {1., 2., 3., 4., 5.}, + {4., 5., 1., 2., 3.}, + {2., 3., 4., 5., 1.}}, + + {{3., 4., 5., 1., 2.}, + {5., 1., 2., 3., 4.}, + {2., 3., 4., 5., 1.}, + {4., 5., 1., 2., 3.}, + {1., 2., 3., 4., 5.}, + {3., 4., 5., 1., 2.}, + {5., 1., 2., 3., 4.}}}); // Loosen tolerance a bit due to FFTs EXPECT_TRUE(IsField3DEqualField3D(shifted.fromFieldAligned(input), expected, "RGN_ALL", @@ -159,26 +163,6 @@ TEST_F(ShiftedMetricTest, CalcYUpDown) { 0, mesh->LocalNz - 1, mesh->LocalNy, mesh->LocalNz)); output_info.enable(); - Field3D input{mesh}; - - fillField(input, {{{1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}}, - - {{1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}}, - - {{1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}, - {1., 2., 3., 4., 5., 6., 7.}}}); - // Actual interesting bit here! ShiftedMetric shifted{*mesh, zShift}; shifted.calcYUpDown(input); @@ -188,83 +172,107 @@ TEST_F(ShiftedMetricTest, CalcYUpDown) { Field3D expected_up_1{mesh}; // Note: here zeroes are for values we don't expect to read - fillField(expected_up_1, {{{0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {2., 3., 4., 5., 6., 7., 1.}, - {0., 0., 0., 0., 0., 0., 0.}}, - - {{0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {2., 3., 4., 5., 6., 7., 1.}, - {0., 0., 0., 0., 0., 0., 0.}}, - - {{0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {2., 3., 4., 5., 6., 7., 1.}, - {0., 0., 0., 0., 0., 0., 0.}}}); + fillField(expected_up_1, {{{0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {2., 3., 4., 5., 1.}, + {2., 3., 4., 5., 1.}, + {2., 3., 4., 5., 1.}, + {0., 0., 0., 0., 0.}}, + + {{0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {3., 4., 5., 1., 2.}, + {3., 4., 5., 1., 2.}, + {3., 4., 5., 1., 2.}, + {0., 0., 0., 0., 0.}}, + + {{0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {4., 5., 1., 2., 3.}, + {4., 5., 1., 2., 3.}, + {4., 5., 1., 2., 3.}, + {0., 0., 0., 0., 0.}}}); Field3D expected_up_2{mesh}; - fillField(expected_up_2, {{{0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {3., 4., 5., 6., 7., 1., 2.}}, - - {{0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {3., 4., 5., 6., 7., 1., 2.}}, - - {{0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {3., 4., 5., 6., 7., 1., 2.}}}); + fillField(expected_up_2, {{{0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {3., 4., 5., 1., 2.}, + {3., 4., 5., 1., 2.}, + {3., 4., 5., 1., 2.}}, + + {{0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {5., 1., 2., 3., 4.}, + {5., 1., 2., 3., 4.}, + {5., 1., 2., 3., 4.}}, + + {{0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {2., 3., 4., 5., 1.}, + {2., 3., 4., 5., 1.}, + {2., 3., 4., 5., 1.}}}); Field3D expected_down_1{mesh}; - fillField(expected_down_1, {{{0., 0., 0., 0., 0., 0., 0.}, - {7., 1., 2., 3., 4., 5., 6.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}}, - - {{0., 0., 0., 0., 0., 0., 0.}, - {7., 1., 2., 3., 4., 5., 6.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}}, - - {{0., 0., 0., 0., 0., 0., 0.}, - {7., 1., 2., 3., 4., 5., 6.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}}}); + fillField(expected_down_1, {{{0., 0., 0., 0., 0.}, + {5., 1., 2., 3., 4.}, + {5., 1., 2., 3., 4.}, + {5., 1., 2., 3., 4.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}}, + + {{0., 0., 0., 0., 0.}, + {4., 5., 1., 2., 3.}, + {4., 5., 1., 2., 3.}, + {4., 5., 1., 2., 3.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}}, + + {{0., 0., 0., 0., 0.}, + {3., 4., 5., 1., 2.}, + {3., 4., 5., 1., 2.}, + {3., 4., 5., 1., 2.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}}}); Field3D expected_down2{mesh}; - fillField(expected_down2, {{{6., 7., 1., 2., 3., 4., 5.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}}, - - {{6., 7., 1., 2., 3., 4., 5.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}}, - - {{6., 7., 1., 2., 3., 4., 5.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}, - {0., 0., 0., 0., 0., 0., 0.}}}); + fillField(expected_down2, {{{4., 5., 1., 2., 3.}, + {4., 5., 1., 2., 3.}, + {4., 5., 1., 2., 3.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}}, + + {{2., 3., 4., 5., 1.}, + {2., 3., 4., 5., 1.}, + {2., 3., 4., 5., 1.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}}, + + {{5., 1., 2., 3., 4.}, + {5., 1., 2., 3., 4.}, + {5., 1., 2., 3., 4.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}, + {0., 0., 0., 0., 0.}}}); EXPECT_TRUE(IsField3DEqualField3D(input.ynext(1), expected_up_1, "RGN_YUP")); EXPECT_TRUE(IsField3DEqualField3D(input.ynext(2), expected_up_2, "RGN_YUP2")); From 7d45fb5ffdf647dd86d65b531237bf2902b6bda1 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 15 Jan 2019 12:04:07 +0000 Subject: [PATCH 0593/1783] Move ArrayData definition out of Array --- include/bout/array.hxx | 76 +++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 45 deletions(-) diff --git a/include/bout/array.hxx b/include/bout/array.hxx index 1ecfcffaa4..e6d19b8cda 100644 --- a/include/bout/array.hxx +++ b/include/bout/array.hxx @@ -41,6 +41,31 @@ #include #include +namespace { +template +using iterator = T*; +template +using const_iterator = const T*; +} + +/*! + * ArrayData holds the actual data + * Handles the allocation and deletion of data + */ +template +struct ArrayData { + int len; ///< Size of the array + T* data; ///< Array of data + + ArrayData(int size) : len(size) { data = new T[len]; } + ~ArrayData() { delete[] data; } + iterator begin() const { return data; } + iterator end() const { return data + len; } + int size() const { return len; } + void operator=(ArrayData& in) { std::copy(std::begin(in), std::end(in), begin()); } + T& operator[](int ind) { return data[ind]; }; +}; + /*! * Data array type with automatic memory management * @@ -217,25 +242,15 @@ public: ////////////////////////////////////////////////////////// // Iterators - typedef T* iterator; - typedef const T* const_iterator; - iterator begin() noexcept { - return (ptr) ? std::begin(*ptr) : nullptr; - } + iterator begin() noexcept { return (ptr) ? std::begin(*ptr) : nullptr; } - iterator end() noexcept { - return (ptr) ? std::end(*ptr) : nullptr; - } + iterator end() noexcept { return (ptr) ? std::end(*ptr) : nullptr; } - // Const iterators - const_iterator begin() const noexcept { - return (ptr) ? std::begin(*ptr) : nullptr; - } + // Const iterators + const_iterator begin() const noexcept { return (ptr) ? std::begin(*ptr) : nullptr; } - const_iterator end() const noexcept { - return (ptr) ? std::end(*ptr) : nullptr; - } + const_iterator end() const noexcept { return (ptr) ? std::end(*ptr) : nullptr; } ////////////////////////////////////////////////////////// // Element access @@ -265,40 +280,11 @@ public: private: -#ifndef BOUT_ARRAY_WITH_VALARRAY - - /*! - * ArrayData holds the actual data - * Handles the allocation and deletion of data - */ - struct ArrayData { - int len; ///< Size of the array - T *data; ///< Array of data - - ArrayData(int size) : len(size) { - data = new T[len]; - } - ~ArrayData() { - delete[] data; - } - iterator begin() const { - return data; - } - iterator end() const { - return data + len; - } - int size() const { return len;} - void operator=(ArrayData &in) { std::copy(std::begin(in), std::end(in), begin());} - T operator[](int ind){return data[ind];}; - }; - -#endif - //Type defs to help keep things brief -- which backing do we use #ifdef BOUT_ARRAY_WITH_VALARRAY typedef std::valarray dataBlock; #else - typedef ArrayData dataBlock; + typedef ArrayData dataBlock; #endif typedef std::shared_ptr dataPtrType; From eae09e0f645248c22c2d40880ea219a69d15eada Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 15 Jan 2019 12:24:05 +0000 Subject: [PATCH 0594/1783] Add a second template argument to Array used to specify what type to use as the memory backing/container Defaults to ArrayData so no change required to user code. Allows us to remove the need to pick the backend at configure time (BOUT_FLAGS time) and allows us to mix and match (to some extent). Note this may make it harder for us to cleanup the array stores as we'll have a different store for every {data type, backend} combination used, which we currently have no easy way to discover. --- include/bout/array.hxx | 46 +++++++++++++++++++----------------------- include/fft.hxx | 4 +--- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/include/bout/array.hxx b/include/bout/array.hxx index e6d19b8cda..feafa17348 100644 --- a/include/bout/array.hxx +++ b/include/bout/array.hxx @@ -34,10 +34,6 @@ #include #endif -#ifdef BOUT_ARRAY_WITH_VALARRAY -#include -#endif - #include #include @@ -54,9 +50,6 @@ using const_iterator = const T*; */ template struct ArrayData { - int len; ///< Size of the array - T* data; ///< Array of data - ArrayData(int size) : len(size) { data = new T[len]; } ~ArrayData() { delete[] data; } iterator begin() const { return data; } @@ -64,6 +57,9 @@ struct ArrayData { int size() const { return len; } void operator=(ArrayData& in) { std::copy(std::begin(in), std::end(in), begin()); } T& operator[](int ind) { return data[ind]; }; +private: + int len; ///< Size of the array + T* data; ///< Array of data }; /*! @@ -80,7 +76,7 @@ struct ArrayData { * vals[10] = 1.0; // ok * * When an Array goes out of scope or is deleted, - * the underlying memory (ArrayData) is put into + * the underlying memory (dataBlock/Backing) is put into * a map, rather than being freed. * If the same size arrays are used repeatedly then this * avoids the need to use new and delete. @@ -89,11 +85,16 @@ struct ArrayData { * * Array::useStore(false); // Disables memory store * + * The second template argument determines what type of container to use to + * store data. This defaults to a custom struct but can be std::valarray ( + * provided T is a compatible type), std::vector etc. Must provide the following : + * size, operator=, operator[], begin, end */ -template +template> class Array { public: - typedef T data_type; + using data_type = T; + using size_type = int; /*! * Create an empty array @@ -112,7 +113,7 @@ public: } /*! - * Destructor. Releases the underlying ArrayData + * Destructor. Releases the underlying dataBlock */ ~Array() noexcept { release(ptr); @@ -127,7 +128,7 @@ public: /*! * Assignment operator - * After this both Arrays share the same ArrayData + * After this both Arrays share the same dataBlock * * Uses copy-and-swap idiom */ @@ -153,7 +154,7 @@ public: /*! * Holds a static variable which controls whether - * memory blocks (ArrayData) are put into a store + * memory blocks (dataBlock) are put into a store * or new/deleted each time. * * The variable is initialised to true on first use, @@ -280,14 +281,9 @@ public: private: - //Type defs to help keep things brief -- which backing do we use -#ifdef BOUT_ARRAY_WITH_VALARRAY - typedef std::valarray dataBlock; -#else - typedef ArrayData dataBlock; -#endif - - typedef std::shared_ptr dataPtrType; + //Type defs to help keep things brief -- which backing do we use + using dataBlock = Backing; + using dataPtrType = std::shared_ptr; /*! * Pointer to the data container object owned by this Array. @@ -299,7 +295,7 @@ private: typedef std::vector< storeType > arenaType; /*! - * This maps from array size (int) to vectors of pointers to ArrayData objects + * This maps from array size (int) to vectors of pointers to dataBlock objects * * By putting the static store inside a function it is initialised on first use, * and doesn't need to be separately declared for each type T @@ -307,7 +303,7 @@ private: * Inputs * ------ * - * @param[in] cleanup If set to true, deletes all ArrayData and clears the store + * @param[in] cleanup If set to true, deletes all dataBlock and clears the store */ static storeType& store(bool cleanup=false) { #ifdef _OPENMP @@ -349,7 +345,7 @@ private: } /*! - * Returns a pointer to an ArrayData object with no + * Returns a pointer to an dataBlock object with no * references. This is either from the store, or newly allocated */ dataPtrType get(int len) { @@ -372,7 +368,7 @@ private: } /*! - * Release an ArrayData object, reducing its reference count by one. + * Release an dataBlock object, reducing its reference count by one. * If no more references, then put back into the store. * It's important to pass a reference to the pointer, otherwise we get * a copy of the shared_ptr, which therefore increases the use count diff --git a/include/fft.hxx b/include/fft.hxx index b257488c3c..876217dd1a 100644 --- a/include/fft.hxx +++ b/include/fft.hxx @@ -29,9 +29,7 @@ #define __FFT_H__ #include "dcomplex.hxx" - -template -class Array; +#include class Options; From f3ee838a6dc736c90076f3693cf0ffcd9c6f1ab6 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 15 Jan 2019 12:43:26 +0000 Subject: [PATCH 0595/1783] Update Array copy for extra template argument --- include/bout/array.hxx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/bout/array.hxx b/include/bout/array.hxx index feafa17348..8a901dcf43 100644 --- a/include/bout/array.hxx +++ b/include/bout/array.hxx @@ -94,6 +94,7 @@ template> class Array { public: using data_type = T; + using backing_type = Backing; using size_type = int; /*! @@ -399,10 +400,10 @@ private: /*! * Create a copy of an Array, which does not share data - */ -template -Array copy(const Array &other) { - Array a(other); + */ +template +Array copy(const Array& other) { + Array a(other); a.ensureUnique(); return a; } From bc133eca6de3083f33f42ad4c6d838b39ad89008 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 15 Jan 2019 14:28:28 +0000 Subject: [PATCH 0596/1783] Ensure populateStencil fills in extra guard cells from parallel slices --- include/stencils.hxx | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/include/stencils.hxx b/include/stencils.hxx index 517929b1dc..fe3b8b1160 100644 --- a/include/stencils.hxx +++ b/include/stencils.hxx @@ -46,49 +46,73 @@ void inline populateStencil(stencil &s, const FieldType& f, const typename Field switch(stagger) { case(STAGGER::None): - if (nGuard == 2) s.mm = f[i.template minus<2, direction>()]; + if (nGuard == 2) { + if (direction == DIRECTION::YOrthogonal) { + s.mm = f.ynext(-2)[i.template minus<2, direction>()]; + } else { + s.mm = f[i.template minus<2, direction>()]; + } + } if (direction == DIRECTION::YOrthogonal) { - s.m = f.ydown()[i.template minus<1, direction>()]; + s.m = f.ynext(-1)[i.template minus<1, direction>()]; } else { s.m = f[i.template minus<1, direction>()]; } s.c = f[i]; if (direction == DIRECTION::YOrthogonal) { - s.p = f.yup()[i.template plus<1, direction>()]; + s.p = f.ynext(1)[i.template plus<1, direction>()]; } else { s.p = f[i.template plus<1, direction>()]; } - if (nGuard == 2) s.pp = f[i.template plus<2, direction>()]; + if (nGuard == 2) { + if (direction == DIRECTION::YOrthogonal) { + s.pp = f.ynext(2)[i.template plus<2, direction>()]; + } else { + s.pp = f[i.template plus<2, direction>()]; + } + } break; case(STAGGER::C2L): - if (nGuard == 2) s.mm = f[i.template minus<2, direction>()]; + if (nGuard == 2) { + if (direction == DIRECTION::YOrthogonal) { + s.mm = f.ynext(-2)[i.template minus<2, direction>()]; + } else { + s.mm = f[i.template minus<2, direction>()]; + } + } if (direction == DIRECTION::YOrthogonal) { - s.m = f.ydown()[i.template minus<1, direction>()]; + s.m = f.ynext(-1)[i.template minus<1, direction>()]; } else { s.m = f[i.template minus<1, direction>()]; } s.c = f[i]; s.p = s.c; if (direction == DIRECTION::YOrthogonal) { - s.pp = f.yup()[i.template plus<1, direction>()]; + s.pp = f.ynext(1)[i.template plus<1, direction>()]; } else { s.pp = f[i.template plus<1, direction>()]; } break; case(STAGGER::L2C): if (direction == DIRECTION::YOrthogonal) { - s.mm = f.ydown()[i.template minus<1, direction>()]; + s.mm = f.ynext(-1)[i.template minus<1, direction>()]; } else { s.mm = f[i.template minus<1, direction>()]; } s.m = f[i]; s.c = s.m; if (direction == DIRECTION::YOrthogonal) { - s.p = f.yup()[i.template plus<1, direction>()]; + s.p = f.ynext(1)[i.template plus<1, direction>()]; } else { s.p = f[i.template plus<1, direction>()]; } - if (nGuard == 2) s.pp = f[i.template plus<2, direction>()]; + if (nGuard == 2) { + if (direction == DIRECTION::YOrthogonal) { + s.pp = f.ynext(2)[i.template plus<2, direction>()]; + } else { + s.pp = f[i.template plus<2, direction>()]; + } + } break; } return; From ebcf7dd607b2795f41332a0ab8f4b631a1fde9cc Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 15 Jan 2019 14:36:51 +0000 Subject: [PATCH 0597/1783] Add `ynext` to `Field2D` --- include/field2d.hxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/field2d.hxx b/include/field2d.hxx index adbf8b0800..eae5befe62 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -129,7 +129,10 @@ class Field2D : public Field, public FieldData { const Field2D& ydown() const { return *this; } - + + Field2D& ynext(int UNUSED(dir)) { return *this; } + const Field2D& ynext(int UNUSED(dir)) const { return *this; } + // Operators /*! From 6e6dcd6fc0357d8526900d2a0215e2afd86c43da Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 15 Jan 2019 14:37:14 +0000 Subject: [PATCH 0598/1783] Move macros and add YOrthogonal to list of automatic directions to register --- include/bout/index_derivs.hxx | 108 +++++++++++++++++----------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index af453a5f83..88522b780b 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -171,6 +171,60 @@ public: #define DEFINE_FLUX_DERIV_STAGGERED(name, key, nGuards, type) \ DEFINE_FLUX_DERIV(name, key, nGuards, type) +/// Some helper defines for now that allow us to wrap up enums +/// and the specific methods. +#define WRAP_ENUM(family, value) enumWrapper + +#define REGISTER_DERIVATIVE(name) \ + namespace { \ + produceCombinations, \ + Set, \ + Set, TypeContainer>, \ + Set>> \ + reg(registerMethod{}); \ + } +#define REGISTER_STAGGERED_DERIVATIVE(name) \ + namespace { \ + produceCombinations, \ + Set, \ + Set, TypeContainer>, \ + Set>> \ + reg(registerMethod{}); \ + } + +#define REGISTER_STANDARD_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_STANDARD_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_DERIVATIVE(name) \ + BoutReal name::operator()(const stencil& f) const + +#define REGISTER_UPWIND_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_UPWIND_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_DERIVATIVE(name) \ + BoutReal name::operator()(BoutReal vc, const stencil& f) const + +#define REGISTER_FLUX_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_DERIVATIVE(name) \ + BoutReal name::operator()(const stencil& v, const stencil& f) const + +#define REGISTER_STANDARD_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_STANDARD_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_STAGGERED_DERIVATIVE(name) \ + BoutReal name::operator()(const stencil& f) const + +#define REGISTER_UPWIND_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ + /*Note staggered upwind looks like flux*/ \ + DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_STAGGERED_DERIVATIVE(name) \ + BoutReal name::operator()(const stencil& v, const stencil& f) const + +#define REGISTER_FLUX_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ + DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ + REGISTER_STAGGERED_DERIVATIVE(name) \ + BoutReal name::operator()(const stencil& v, const stencil& f) const + ////////////////////// FIRST DERIVATIVES ///////////////////// /// central, 2nd order @@ -559,60 +613,6 @@ struct registerMethod { } }; -/// Some helper defines for now that allow us to wrap up enums -/// and the specific methods. -#define WRAP_ENUM(family, value) enumWrapper - -#define REGISTER_DERIVATIVE(name) \ - namespace { \ - produceCombinations, \ - Set, \ - Set, TypeContainer>, \ - Set>> \ - reg(registerMethod{}); \ - } -#define REGISTER_STAGGERED_DERIVATIVE(name) \ - namespace { \ - produceCombinations, \ - Set, \ - Set, TypeContainer>, \ - Set>> \ - reg(registerMethod{}); \ - } - -#define REGISTER_STANDARD_DERIVATIVE(name, key, nGuards, type) \ - DEFINE_STANDARD_DERIV_CORE(name, key, nGuards, type) \ - REGISTER_DERIVATIVE(name) \ - BoutReal name::operator()(const stencil& f) const - -#define REGISTER_UPWIND_DERIVATIVE(name, key, nGuards, type) \ - DEFINE_UPWIND_DERIV_CORE(name, key, nGuards, type) \ - REGISTER_DERIVATIVE(name) \ - BoutReal name::operator()(BoutReal vc, const stencil& f) const - -#define REGISTER_FLUX_DERIVATIVE(name, key, nGuards, type) \ - DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ - REGISTER_DERIVATIVE(name) \ - BoutReal name::operator()(const stencil& v, const stencil& f) const - -#define REGISTER_STANDARD_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ - DEFINE_STANDARD_DERIV_CORE(name, key, nGuards, type) \ - REGISTER_STAGGERED_DERIVATIVE(name) \ - BoutReal name::operator()(const stencil& f) const - -#define REGISTER_UPWIND_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ - /*Note staggered upwind looks like flux*/ \ - DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ - REGISTER_STAGGERED_DERIVATIVE(name) \ - BoutReal name::operator()(const stencil& v, const stencil& f) const - -#define REGISTER_FLUX_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ - DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ - REGISTER_STAGGERED_DERIVATIVE(name) \ - BoutReal name::operator()(const stencil& v, const stencil& f) const - ///////////////////////////////////////////////////////////////////////////////// /// Here's an example of registering a couple of DerivativeType methods /// at once for no staggering From c24dc664f8d2c2f917b2e8b82c28cdd659d0512a Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 15 Jan 2019 14:51:07 +0000 Subject: [PATCH 0599/1783] Switch to define and register in one step for in-build derivative methods --- include/bout/index_derivs.hxx | 296 ++++++++++++++++------------------ 1 file changed, 136 insertions(+), 160 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index 88522b780b..80e63dac79 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -123,6 +123,85 @@ public: const metaData meta = func.meta; }; +///////////////////////////////////////////////////////////////////////////////// +/// Following code is for dealing with registering a method/methods for all +/// template combinations, in conjunction with the template_combinations code. +///////////////////////////////////////////////////////////////////////////////// + +struct registerMethod { + template + void operator()(Direction, Stagger, FieldTypeContainer, Method) { + AUTO_TRACE(); + using namespace std::placeholders; + + // Now we want to get the actual field type out of the TypeContainer + // used to pass this around + using FieldType = typename FieldTypeContainer::type; + + Method method{}; + + // Note whilst this should be known at compile time using this directly in the + // template parameters below causes problems for old versions of gcc/libstdc++ + // (tested with 4.8.3) so we currently use a hacky workaround. Once we drop + // support for these versions the branching in the case statement below can be + // removed and we can use nGuard directly in the template statement. + const int nGuards = method.meta.nGuards; + + auto& derivativeRegister = DerivativeStore::getInstance(); + + switch (method.meta.derivType) { + case (DERIV::Standard): + case (DERIV::StandardSecond): + case (DERIV::StandardFourth): { + if (nGuards == 1) { + const auto theFunc = std::bind( + // Method to store in function + &Method::template standard, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + method, _1, _2, _3); + derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, method); + } else { + const auto theFunc = std::bind( + // Method to store in function + &Method::template standard, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + method, _1, _2, _3); + derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, method); + } + break; + } + case (DERIV::Upwind): + case (DERIV::Flux): { + if (nGuards == 1) { + const auto theFunc = std::bind( + // Method to store in function + &Method::template upwindOrFlux, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + method, _1, _2, _3, _4); + derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, method); + } else { + const auto theFunc = std::bind( + // Method to store in function + &Method::template upwindOrFlux, + // Arguments -- first is hidden this of type-bound, others are placeholders + // for input field, output field, region + method, _1, _2, _3, _4); + derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, method); + } + break; + } + default: + throw BoutException("Unhandled derivative method in registerMethod."); + }; + } +}; + #define DEFINE_STANDARD_DERIV_CORE(name, key, nGuards, type) \ struct name { \ BoutReal operator()(const stencil& f) const; \ @@ -175,23 +254,23 @@ public: /// and the specific methods. #define WRAP_ENUM(family, value) enumWrapper -#define REGISTER_DERIVATIVE(name) \ - namespace { \ - produceCombinations, \ - Set, \ - Set, TypeContainer>, \ - Set>> \ - reg(registerMethod{}); \ + Set, \ + Set, TypeContainer>, \ + Set>> \ + reg##name(registerMethod{}); \ } -#define REGISTER_STAGGERED_DERIVATIVE(name) \ - namespace { \ - produceCombinations, \ - Set, \ - Set, TypeContainer>, \ - Set>> \ - reg(registerMethod{}); \ + Set, \ + Set, TypeContainer>, \ + Set>> \ + reg##name(registerMethod{}); \ } #define REGISTER_STANDARD_DERIVATIVE(name, key, nGuards, type) \ @@ -214,29 +293,39 @@ public: REGISTER_STAGGERED_DERIVATIVE(name) \ BoutReal name::operator()(const stencil& f) const +#define REGISTER_STANDARD_DERIVATIVE_STAGGERED(name, key, nGuards, type) \ + REGISTER_STANDARD_STAGGERED_DERIVATIVE(name, key, nGuards, type) + #define REGISTER_UPWIND_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ /*Note staggered upwind looks like flux*/ \ DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ REGISTER_STAGGERED_DERIVATIVE(name) \ BoutReal name::operator()(const stencil& v, const stencil& f) const +#define REGISTER_UPWIND_DERIVATIVE_STAGGERED(name, key, nGuards, type) \ + REGISTER_UPWIND_STAGGERED_DERIVATIVE(name, key, nGuards, type) + #define REGISTER_FLUX_STAGGERED_DERIVATIVE(name, key, nGuards, type) \ DEFINE_FLUX_DERIV_CORE(name, key, nGuards, type) \ REGISTER_STAGGERED_DERIVATIVE(name) \ BoutReal name::operator()(const stencil& v, const stencil& f) const +#define REGISTER_FLUX_DERIVATIVE_STAGGERED(name, key, nGuards, type) \ + REGISTER_FLUX_STAGGERED_DERIVATIVE(name, key, nGuards, type) ////////////////////// FIRST DERIVATIVES ///////////////////// /// central, 2nd order -DEFINE_STANDARD_DERIV(DDX_C2, "C2", 1, DERIV::Standard) { return 0.5 * (f.p - f.m); }; +REGISTER_STANDARD_DERIVATIVE(DDX_C2, "C2", 1, DERIV::Standard) { + return 0.5 * (f.p - f.m); +}; /// central, 4th order -DEFINE_STANDARD_DERIV(DDX_C4, "C4", 2, DERIV::Standard) { +REGISTER_STANDARD_DERIVATIVE(DDX_C4, "C4", 2, DERIV::Standard) { return (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; } /// Central WENO method, 2nd order (reverts to 1st order near shocks) -DEFINE_STANDARD_DERIV(DDX_CWENO2, "W2", 1, DERIV::Standard) { +REGISTER_STANDARD_DERIVATIVE(DDX_CWENO2, "W2", 1, DERIV::Standard) { BoutReal isl, isr, isc; // Smoothness indicators BoutReal al, ar, ac, sa; // Un-normalised weights BoutReal dl, dr, dc; // Derivatives using different stencils @@ -258,7 +347,7 @@ DEFINE_STANDARD_DERIV(DDX_CWENO2, "W2", 1, DERIV::Standard) { } // Smoothing 2nd order derivative -DEFINE_STANDARD_DERIV(DDX_S2, "S2", 2, DERIV::Standard) { +REGISTER_STANDARD_DERIVATIVE(DDX_S2, "S2", 2, DERIV::Standard) { // 4th-order differencing BoutReal result = (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; @@ -275,19 +364,19 @@ DEFINE_STANDARD_DERIV(DDX_S2, "S2", 2, DERIV::Standard) { ////////////////////////////// /// Second derivative: Central, 2nd order -DEFINE_STANDARD_DERIV(D2DX2_C2, "C2", 1, DERIV::StandardSecond) { +REGISTER_STANDARD_DERIVATIVE(D2DX2_C2, "C2", 1, DERIV::StandardSecond) { return f.p + f.m - 2. * f.c; } /// Second derivative: Central, 4th order -DEFINE_STANDARD_DERIV(D2DX2_C4, "C4", 2, DERIV::StandardSecond) { +REGISTER_STANDARD_DERIVATIVE(D2DX2_C4, "C4", 2, DERIV::StandardSecond) { return (-f.pp + 16. * f.p - 30. * f.c + 16. * f.m - f.mm) / 12.; } ////////////////////////////// //--- Fourth order derivatives ////////////////////////////// -DEFINE_STANDARD_DERIV(D4DX4_C2, "C2", 2, DERIV::StandardFourth) { +REGISTER_STANDARD_DERIVATIVE(D4DX4_C2, "C2", 2, DERIV::StandardFourth) { return (f.pp - 4. * f.p + 6. * f.c - 4. * f.m + f.mm); } @@ -304,15 +393,17 @@ std::tuple vUpDown(BoutReal v) { } /// Upwinding: Central, 2nd order -DEFINE_UPWIND_DERIV(VDDX_C2, "C2", 1, DERIV::Upwind) { return vc * 0.5 * (f.p - f.m); } +REGISTER_UPWIND_DERIVATIVE(VDDX_C2, "C2", 1, DERIV::Upwind) { + return vc * 0.5 * (f.p - f.m); +} /// Upwinding: Central, 4th order -DEFINE_UPWIND_DERIV(VDDX_C4, "C4", 2, DERIV::Upwind) { +REGISTER_UPWIND_DERIVATIVE(VDDX_C4, "C4", 2, DERIV::Upwind) { return vc * (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; } /// upwind, 1st order -DEFINE_UPWIND_DERIV(VDDX_U1, "U1", 1, DERIV::Upwind) { // No vec +REGISTER_UPWIND_DERIVATIVE(VDDX_U1, "U1", 1, DERIV::Upwind) { // No vec // Existing form doesn't vectorise due to branching return vc >= 0.0 ? vc * (f.c - f.m) : vc * (f.p - f.c); // Alternative form would but may involve more operations @@ -321,7 +412,7 @@ DEFINE_UPWIND_DERIV(VDDX_U1, "U1", 1, DERIV::Upwind) { // No vec } /// upwind, 2nd order -DEFINE_UPWIND_DERIV(VDDX_U2, "U2", 2, DERIV::Upwind) { // No vec +REGISTER_UPWIND_DERIVATIVE(VDDX_U2, "U2", 2, DERIV::Upwind) { // No vec // Existing form doesn't vectorise due to branching return vc >= 0.0 ? vc * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) : vc * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c); @@ -332,7 +423,7 @@ DEFINE_UPWIND_DERIV(VDDX_U2, "U2", 2, DERIV::Upwind) { // No vec } /// upwind, 3rd order -DEFINE_UPWIND_DERIV(VDDX_U3, "U3", 2, DERIV::Upwind) { // No vec +REGISTER_UPWIND_DERIVATIVE(VDDX_U3, "U3", 2, DERIV::Upwind) { // No vec // Existing form doesn't vectorise due to branching return vc >= 0.0 ? vc * (4. * f.p - 12. * f.m + 2. * f.mm + 6. * f.c) / 12. : vc * (-4. * f.m + 12. * f.p - 2. * f.pp - 6. * f.c) / 12.; @@ -344,7 +435,7 @@ DEFINE_UPWIND_DERIV(VDDX_U3, "U3", 2, DERIV::Upwind) { // No vec } /// 3rd-order WENO scheme -DEFINE_UPWIND_DERIV(VDDX_WENO3, "W3", 2, DERIV::Upwind) { // No vec +REGISTER_UPWIND_DERIVATIVE(VDDX_WENO3, "W3", 2, DERIV::Upwind) { // No vec BoutReal deriv, w, r; // Existing form doesn't vectorise due to branching @@ -373,7 +464,7 @@ DEFINE_UPWIND_DERIV(VDDX_WENO3, "W3", 2, DERIV::Upwind) { // No vec ///----------------------------------------------------------------- /// 3rd-order CWENO. Uses the upwinding code and split flux -DEFINE_STANDARD_DERIV(DDX_CWENO3, "W3", 2, DERIV::Standard) { +REGISTER_STANDARD_DERIVATIVE(DDX_CWENO3, "W3", 2, DERIV::Standard) { BoutReal a, ma = fabs(f.c); // Split flux a = fabs(f.m); @@ -416,7 +507,7 @@ DEFINE_STANDARD_DERIV(DDX_CWENO3, "W3", 2, DERIV::Standard) { /// //////////////////////////////////////////////////////////////////////////////// -DEFINE_FLUX_DERIV(FDDX_U1, "U1", 1, DERIV::Flux) { // No vec +REGISTER_FLUX_DERIVATIVE(FDDX_U1, "U1", 1, DERIV::Flux) { // No vec // Velocity at lower end BoutReal vs = 0.5 * (v.m + v.c); @@ -432,9 +523,11 @@ DEFINE_FLUX_DERIV(FDDX_U1, "U1", 1, DERIV::Flux) { // No vec return result - std::get<0>(vSplit) * f.c + std::get<1>(vSplit) * f.p; } -DEFINE_FLUX_DERIV(FDDX_C2, "C2", 2, DERIV::Flux) { return 0.5 * (v.p * f.p - v.m * f.m); } +REGISTER_FLUX_DERIVATIVE(FDDX_C2, "C2", 2, DERIV::Flux) { + return 0.5 * (v.p * f.p - v.m * f.m); +} -DEFINE_FLUX_DERIV(FDDX_C4, "C4", 2, DERIV::Flux) { +REGISTER_FLUX_DERIVATIVE(FDDX_C4, "C4", 2, DERIV::Flux) { return (8. * v.p * f.p - 8. * v.m * f.m + v.mm * f.mm - v.pp * f.pp) / 12.; } @@ -461,25 +554,25 @@ DEFINE_FLUX_DERIV(FDDX_C4, "C4", 2, DERIV::Flux) { //////////////////////////////////////////////////////////////////////////////// /// Standard methods -- first order //////////////////////////////////////////////////////////////////////////////// -DEFINE_STANDARD_DERIV_STAGGERED(DDX_C2_stag, "C2", 1, DERIV::Standard) { +REGISTER_STANDARD_DERIVATIVE_STAGGERED(DDX_C2_stag, "C2", 1, DERIV::Standard) { return f.p - f.m; } -DEFINE_STANDARD_DERIV_STAGGERED(DDX_C4_stag, "C4", 2, DERIV::Standard) { +REGISTER_STANDARD_DERIVATIVE_STAGGERED(DDX_C4_stag, "C4", 2, DERIV::Standard) { return (27. * (f.p - f.m) - (f.pp - f.mm)) / 24.; } //////////////////////////////////////////////////////////////////////////////// /// Standard methods -- second order //////////////////////////////////////////////////////////////////////////////// -DEFINE_STANDARD_DERIV_STAGGERED(D2DX2_C2_stag, "C2", 2, DERIV::StandardSecond) { +REGISTER_STANDARD_DERIVATIVE_STAGGERED(D2DX2_C2_stag, "C2", 2, DERIV::StandardSecond) { return (f.pp + f.mm - f.p - f.m) / 2.; } //////////////////////////////////////////////////////////////////////////////// /// Upwind methods //////////////////////////////////////////////////////////////////////////////// -DEFINE_UPWIND_DERIV_STAGGERED(VDDX_U1_stag, "U1", 1, DERIV::Upwind) { +REGISTER_UPWIND_DERIVATIVE_STAGGERED(VDDX_U1_stag, "U1", 1, DERIV::Upwind) { // Lower cell boundary BoutReal result = (v.m >= 0) ? v.m * f.m : v.m * f.c; @@ -492,7 +585,7 @@ DEFINE_UPWIND_DERIV_STAGGERED(VDDX_U1_stag, "U1", 1, DERIV::Upwind) { return result; } -DEFINE_UPWIND_DERIV_STAGGERED(VDDX_U2_stag, "U2", 2, DERIV::Upwind) { +REGISTER_UPWIND_DERIVATIVE_STAGGERED(VDDX_U2_stag, "U2", 2, DERIV::Upwind) { // Calculate d(v*f)/dx = (v*f)[i+1/2] - (v*f)[i-1/2] // Upper cell boundary @@ -508,13 +601,13 @@ DEFINE_UPWIND_DERIV_STAGGERED(VDDX_U2_stag, "U2", 2, DERIV::Upwind) { return result; } -DEFINE_UPWIND_DERIV_STAGGERED(VDDX_C2_stag, "C2", 1, DERIV::Upwind) { +REGISTER_UPWIND_DERIVATIVE_STAGGERED(VDDX_C2_stag, "C2", 1, DERIV::Upwind) { // Result is needed at location of f: interpolate v to f's location and take an // unstaggered derivative of f return 0.5 * (v.p + v.m) * 0.5 * (f.p - f.m); } -DEFINE_UPWIND_DERIV_STAGGERED(VDDX_C4_stag, "C4", 2, DERIV::Upwind) { +REGISTER_UPWIND_DERIVATIVE_STAGGERED(VDDX_C4_stag, "C4", 2, DERIV::Upwind) { // Result is needed at location of f: interpolate v to f's location and take an // unstaggered derivative of f return (9. * (v.m + v.p) - v.mm - v.pp) / 16. * (8. * f.p - 8. * f.m + f.mm - f.pp) @@ -524,7 +617,7 @@ DEFINE_UPWIND_DERIV_STAGGERED(VDDX_C4_stag, "C4", 2, DERIV::Upwind) { //////////////////////////////////////////////////////////////////////////////// /// Flux methods //////////////////////////////////////////////////////////////////////////////// -DEFINE_FLUX_DERIV_STAGGERED(FDDX_U1_stag, "U1", 1, DERIV::Flux) { +REGISTER_FLUX_DERIVATIVE_STAGGERED(FDDX_U1_stag, "U1", 1, DERIV::Flux) { // Lower cell boundary BoutReal result = (v.m >= 0) ? v.m * f.m : v.m * f.c; @@ -534,127 +627,10 @@ DEFINE_FLUX_DERIV_STAGGERED(FDDX_U1_stag, "U1", 1, DERIV::Flux) { return -result; } -///////////////////////////////////////////////////////////////////////////////// -/// Following code is for dealing with registering a method/methods for all -/// template combinations, in conjunction with the template_combinations code. -///////////////////////////////////////////////////////////////////////////////// - -struct registerMethod { - template - void operator()(Direction, Stagger, FieldTypeContainer, Method) { - AUTO_TRACE(); - using namespace std::placeholders; - - // Now we want to get the actual field type out of the TypeContainer - // used to pass this around - using FieldType = typename FieldTypeContainer::type; - - Method method{}; - - // Note whilst this should be known at compile time using this directly in the - // template parameters below causes problems for old versions of gcc/libstdc++ - // (tested with 4.8.3) so we currently use a hacky workaround. Once we drop - // support for these versions the branching in the case statement below can be - // removed and we can use nGuard directly in the template statement. - const int nGuards = method.meta.nGuards; - - auto& derivativeRegister = DerivativeStore::getInstance(); - - switch (method.meta.derivType) { - case (DERIV::Standard): - case (DERIV::StandardSecond): - case (DERIV::StandardFourth): { - if (nGuards == 1) { - const auto theFunc = std::bind( - // Method to store in function - &Method::template standard, - // Arguments -- first is hidden this of type-bound, others are placeholders - // for input field, output field, region - method, _1, _2, _3); - derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, method); - } else { - const auto theFunc = std::bind( - // Method to store in function - &Method::template standard, - // Arguments -- first is hidden this of type-bound, others are placeholders - // for input field, output field, region - method, _1, _2, _3); - derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, method); - } - break; - } - case (DERIV::Upwind): - case (DERIV::Flux): { - if (nGuards == 1) { - const auto theFunc = std::bind( - // Method to store in function - &Method::template upwindOrFlux, - // Arguments -- first is hidden this of type-bound, others are placeholders - // for input field, output field, region - method, _1, _2, _3, _4); - derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, method); - } else { - const auto theFunc = std::bind( - // Method to store in function - &Method::template upwindOrFlux, - // Arguments -- first is hidden this of type-bound, others are placeholders - // for input field, output field, region - method, _1, _2, _3, _4); - derivativeRegister.registerDerivative(theFunc, Direction{}, Stagger{}, method); - } - break; - } - default: - throw BoutException("Unhandled derivative method in registerMethod."); - }; - } -}; - -///////////////////////////////////////////////////////////////////////////////// -/// Here's an example of registering a couple of DerivativeType methods -/// at once for no staggering -///////////////////////////////////////////////////////////////////////////////// - -produceCombinations, - Set, - Set, TypeContainer>, - Set< - // Standard - DerivativeType, DerivativeType, - DerivativeType, DerivativeType, - DerivativeType, - // Standard 2nd order - DerivativeType, DerivativeType, - // Standard 4th order - DerivativeType, - // Upwind - DerivativeType, DerivativeType, - DerivativeType, DerivativeType, - DerivativeType, DerivativeType, - // Flux - DerivativeType, DerivativeType, - DerivativeType>> - registerDerivatives(registerMethod{}); - -produceCombinations, - Set, - Set, TypeContainer>, - Set< - // Standard - DerivativeType, DerivativeType, - // Standard 2nd order - DerivativeType, - // Upwind - DerivativeType, DerivativeType, - DerivativeType, DerivativeType, - // Flux - DerivativeType>> - registerStaggeredDerivatives(registerMethod{}); +///////////////////////////////////////////////////////////////////////////////////// +/// Here's an example of defining and registering a custom method that doesn't fit +/// into the standard stencil based approach. +// ///////////////////////////////////////////////////////////////////////////////// class FFTDerivativeType { public: From 7c34454f097ab6573523846ada89d03e26c94198 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 15 Jan 2019 14:16:11 +0000 Subject: [PATCH 0600/1783] Silence output from fft_init in ShiftedMetric tests --- tests/unit/mesh/parallel/test_shiftedmetric.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 8a806506c3..38f368ce6a 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -1,6 +1,7 @@ #include "gtest/gtest.h" #include "bout/paralleltransform.hxx" +#include "fft.hxx" #include "test_extras.hxx" extern Mesh* mesh; @@ -18,6 +19,9 @@ class ShiftedMetricTest : public ::testing::Test { mesh->createDefaultRegions(); output_info.enable(); + // Make sure fft functions are quiet by setting fft_measure to false + bout::fft::fft_init(false); + zShift = Field2D{mesh}; fillField(zShift, {{1., 2., 3., 4., 5., 6., 7.}, From 5e6672fd87cd9b8012c25eb37b46b1a37a5e7408 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 15 Jan 2019 14:39:38 +0000 Subject: [PATCH 0601/1783] Use consistent tolerance for FFT-based functions across unit tests --- tests/unit/invert/test_fft.cxx | 17 +++++++--------- .../unit/mesh/parallel/test_shiftedmetric.cxx | 20 +++++++++++-------- tests/unit/test_extras.hxx | 4 +++- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/tests/unit/invert/test_fft.cxx b/tests/unit/invert/test_fft.cxx index 37ed3cb9b8..735fcedb93 100644 --- a/tests/unit/invert/test_fft.cxx +++ b/tests/unit/invert/test_fft.cxx @@ -39,9 +39,6 @@ class FFTTest : public ::testing::TestWithParam { Array real_signal; Array fft_signal; - - // FFTs have a slightly looser tolerance than other functions - static constexpr BoutReal fft_tolerance{1.e-12}; }; // Test the FFT functions with both even- and odd-length real signals @@ -57,8 +54,8 @@ TEST_P(FFTTest, rfft) { EXPECT_EQ(output.size(), nmodes); for (int i = 0; i < nmodes; ++i) { - EXPECT_NEAR(real(output[i]), real(fft_signal[i]), fft_tolerance); - EXPECT_NEAR(imag(output[i]), imag(fft_signal[i]), fft_tolerance); + EXPECT_NEAR(real(output[i]), real(fft_signal[i]), FFTTolerance); + EXPECT_NEAR(imag(output[i]), imag(fft_signal[i]), FFTTolerance); } } @@ -72,7 +69,7 @@ TEST_P(FFTTest, irfft) { EXPECT_EQ(output.size(), size); for (int i = 0; i < size; ++i) { - EXPECT_NEAR(output[i], real_signal[i], fft_tolerance); + EXPECT_NEAR(output[i], real_signal[i], FFTTolerance); } } @@ -84,8 +81,8 @@ TEST_P(FFTTest, rfftWithArray) { EXPECT_EQ(output.size(), nmodes); for (int i = 0; i < nmodes; ++i) { - EXPECT_NEAR(real(output[i]), real(fft_signal[i]), fft_tolerance); - EXPECT_NEAR(imag(output[i]), imag(fft_signal[i]), fft_tolerance); + EXPECT_NEAR(real(output[i]), real(fft_signal[i]), FFTTolerance); + EXPECT_NEAR(imag(output[i]), imag(fft_signal[i]), FFTTolerance); } } @@ -97,7 +94,7 @@ TEST_P(FFTTest, irfftWithArray) { EXPECT_EQ(output.size(), size); for (int i = 0; i < size; ++i) { - EXPECT_NEAR(output[i], real_signal[i], fft_tolerance); + EXPECT_NEAR(output[i], real_signal[i], FFTTolerance); } } @@ -109,6 +106,6 @@ TEST_P(FFTTest, RoundTrip) { EXPECT_EQ(output.size(), real_signal.size()); for (int i = 0; i < size; ++i) { - EXPECT_NEAR(output[i], real_signal[i], fft_tolerance); + EXPECT_NEAR(output[i], real_signal[i], FFTTolerance); } } diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 38f368ce6a..cd224592e2 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -1,8 +1,8 @@ #include "gtest/gtest.h" -#include "bout/paralleltransform.hxx" #include "fft.hxx" #include "test_extras.hxx" +#include "bout/paralleltransform.hxx" extern Mesh* mesh; @@ -105,8 +105,8 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { {4., 5., 1., 2., 3.}, {2., 3., 4., 5., 1.}}}); - EXPECT_TRUE( - IsField3DEqualField3D(shifted.toFieldAligned(input), expected, "RGN_ALL", 1.e-12)); + EXPECT_TRUE(IsField3DEqualField3D(shifted.toFieldAligned(input), expected, "RGN_ALL", + FFTTolerance)); } TEST_F(ShiftedMetricTest, FromFieldAligned) { @@ -140,7 +140,7 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { // Loosen tolerance a bit due to FFTs EXPECT_TRUE(IsField3DEqualField3D(shifted.fromFieldAligned(input), expected, "RGN_ALL", - 1.e-12)); + FFTTolerance)); } TEST_F(ShiftedMetricTest, CalcYUpDown) { @@ -278,8 +278,12 @@ TEST_F(ShiftedMetricTest, CalcYUpDown) { {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}}}); - EXPECT_TRUE(IsField3DEqualField3D(input.ynext(1), expected_up_1, "RGN_YUP")); - EXPECT_TRUE(IsField3DEqualField3D(input.ynext(2), expected_up_2, "RGN_YUP2")); - EXPECT_TRUE(IsField3DEqualField3D(input.ynext(-1), expected_down_1, "RGN_YDOWN")); - EXPECT_TRUE(IsField3DEqualField3D(input.ynext(-2), expected_down2, "RGN_YDOWN2")); + EXPECT_TRUE( + IsField3DEqualField3D(input.ynext(1), expected_up_1, "RGN_YUP", FFTTolerance)); + EXPECT_TRUE( + IsField3DEqualField3D(input.ynext(2), expected_up_2, "RGN_YUP2", FFTTolerance)); + EXPECT_TRUE( + IsField3DEqualField3D(input.ynext(-1), expected_down_1, "RGN_YDOWN", FFTTolerance)); + EXPECT_TRUE( + IsField3DEqualField3D(input.ynext(-2), expected_down2, "RGN_YDOWN2", FFTTolerance)); } diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index a4593c8657..6b0c711a8d 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -12,7 +12,9 @@ #include "field3d.hxx" #include "unused.hxx" -const BoutReal BoutRealTolerance = 1e-15; +static constexpr BoutReal BoutRealTolerance{1e-15}; +// FFTs have a slightly looser tolerance than other functions +static constexpr BoutReal FFTTolerance{1.e-12}; /// Does \p str contain \p substring? ::testing::AssertionResult IsSubString(const std::string &str, From 7ca13d3edf6f5caee5efcb4ea6055bea2ecc0213 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 15 Jan 2019 15:47:23 +0000 Subject: [PATCH 0602/1783] specify python package versions for Travis Avoids surprises -- numpy 1.16 doesn't provide a whl for python 3.4 (not supported) so we were spending >2 minutes for each build compiling numpy. --- .pip_install_for_travis.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.pip_install_for_travis.sh b/.pip_install_for_travis.sh index 739885ea44..59b0392757 100755 --- a/.pip_install_for_travis.sh +++ b/.pip_install_for_travis.sh @@ -1,8 +1,7 @@ #!/bin/bash export PATH=${HOME}/.local/bin:${PATH} -pip3 install --user --upgrade pip setuptools -pip3 install --user --upgrade pip scipy numpy - +pip3 install --user --upgrade pip==18.1 setuptools==40.6.3 +pip3 install --user --upgrade scipy==1.2.0 numpy==1.15 for package in $@ do if test $package == "cython" From d341bd2d7d4e2054b0375813bf52a2c3896886a6 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 15 Jan 2019 16:53:40 +0000 Subject: [PATCH 0603/1783] FieldFactory: Separate parsing, looping stages in create{2,3}D To create a field in the RHS function, for example sources as a function of time, currently we have to do something like: ``` FieldFactory::get()->create3D( Options::root()["vorticity"]["source"], &Options::root()["vorticity"], mesh, CELL_CENTRE, time ); ``` which involves looking up an options string, parsing it and then evaluating the resulting generator over the mesh. This isn't as bad as it looks, because the string is hashed in the parser so is in a lookup table. To clean this up a little, this splits `create3D` into the parse step, and the part which calls the generator. This adds additional functions to the API which take a `FieldGeneratorPtr` rather than a `std::string`. The above example becomes: ``` FieldGeneratorPtr generator = FieldFactory::get()->parse(Options::root()["vorticity"]["source"], &Options::root()["vorticity"]); ... FieldFactory::get()->create3D( generator, mesh, CELL_CENTRE, time ); ``` Adds some documentation but no tests yet. --- include/field_factory.hxx | 33 ++++++++++++++++----- src/field/field_factory.cxx | 59 +++++++++++++++++++------------------ 2 files changed, 57 insertions(+), 35 deletions(-) diff --git a/include/field_factory.hxx b/include/field_factory.hxx index 5b0fe33275..ff372d59fd 100644 --- a/include/field_factory.hxx +++ b/include/field_factory.hxx @@ -57,30 +57,49 @@ public: FieldFactory(Mesh *m, Options *opt = nullptr); ~FieldFactory() override; + /// Create a 2D field by parsing a string and evaluating the expression + /// using the given options \p opt, over Mesh \p m at time \p t. + /// The resulting field is at cell location \p loc. const Field2D create2D(const std::string &value, const Options *opt = nullptr, Mesh *m = nullptr, CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); + + /// Create a 3D field by parsing a string and evaluating the expression + /// using the given options \p opt, over Mesh \p m at time \p t. + /// The resulting field is at cell location \p loc. const Field3D create3D(const std::string &value, const Options *opt = nullptr, Mesh *m = nullptr, CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); - // Parse a string into a tree of generators + /// Parse a string into a tree of generators FieldGeneratorPtr parse(const std::string &input, const Options *opt = nullptr); - // Singleton object - static FieldFactory *get(); + /// Create a 2D field from a generator, over a given mesh + /// at a given cell location and time. + const Field2D create2D(FieldGeneratorPtr generator, Mesh* m = nullptr, + CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); + + /// Create a 3D field from a generator, over a given mesh + /// at a given cell location and time. + const Field3D create3D(FieldGeneratorPtr generator, Mesh* m = nullptr, + CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); + + /// Get the Singleton object + static FieldFactory* get(); /// clean the cache of parsed strings void cleanCache(); protected: - // These functions called by the parser + /// These functions called by the parser to resolve unknown symbols. + /// This is used to enable options to be referred to in expressions. FieldGeneratorPtr resolve(std::string &name) override; private: - Mesh *fieldmesh; - const Options *options; + Mesh *fieldmesh; ///< The default mesh for create functions. + const Options *options; ///< Set in parse() and used in resolve() std::list lookup; // Names currently being parsed - // Cache parsed strings + /// Cache parsed strings so repeated evaluations + /// don't result in allocating more generators. std::map cache; const Options* findOption(const Options *opt, const std::string &name, std::string &val); diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index a281e97779..83f99cd141 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -99,30 +99,31 @@ FieldFactory::~FieldFactory() { } -const Field2D FieldFactory::create2D(const std::string &value, const Options *opt, - Mesh *localmesh, CELL_LOC loc, - BoutReal t) { +const Field2D FieldFactory::create2D(const std::string& value, const Options* opt, + Mesh* localmesh, CELL_LOC loc, BoutReal t) { + return create2D(parse(value, opt), localmesh, loc, t); +} - if(localmesh == nullptr) +const Field2D FieldFactory::create2D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC loc, + BoutReal t) { + AUTO_TRACE(); + + if (localmesh == nullptr) localmesh = fieldmesh; - if(localmesh == nullptr) + if (localmesh == nullptr) throw BoutException("Not a valid mesh"); - - Field2D result(0.,localmesh); - - if(localmesh->StaggerGrids == false){ - loc = CELL_CENTRE ; + + if (!gen) { + throw BoutException("Couldn't create 2D field from null generator"); } - result.setLocation(loc); + + Field2D result(0., localmesh); - FieldGeneratorPtr gen = parse(value, opt); - if(!gen) { - output << "FieldFactory error: Couldn't create 2D field from '" - << value - << "'" << endl; - return result; + if (localmesh->StaggerGrids == false) { + loc = CELL_CENTRE; } - + result.setLocation(loc); + switch(loc) { case CELL_XLOW: { BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -161,12 +162,22 @@ const Field2D FieldFactory::create2D(const std::string &value, const Options *op const Field3D FieldFactory::create3D(const std::string &value, const Options *opt, Mesh *localmesh, CELL_LOC loc, BoutReal t) { + return create3D(parse(value, opt), localmesh, loc, t); +} +const Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC loc, + BoutReal t) { + AUTO_TRACE(); + if(localmesh == nullptr) localmesh = fieldmesh; if(localmesh == nullptr) throw BoutException("Not a valid mesh"); - + + if (!gen) { + throw BoutException("Couldn't create 3D field from null generator"); + } + // Create a Field3D over mesh "localmesh" Field3D result(localmesh); @@ -174,13 +185,7 @@ const Field3D FieldFactory::create3D(const std::string &value, const Options *op result.allocate(); result.setLocation(loc); - - // Parse expression to create a tree of generators - FieldGeneratorPtr gen = parse(value, opt); - if(!gen) { - throw BoutException("FieldFactory error: Couldn't create 3D field from '%s'", value.c_str()); - } - + switch(loc) { case CELL_XLOW: { BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -223,8 +228,6 @@ const Field3D FieldFactory::create3D(const std::string &value, const Options *op } } }; - - // Don't delete generator if (localmesh->canToFromFieldAligned()){ // Ask wheter it is possible // Transform from field aligned coordinates, to be compatible with From 0bf2cd602ffc3b900591e7cb4c1460d7d56885ac Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 16 Jan 2019 19:07:20 +0000 Subject: [PATCH 0604/1783] Add null coordinates to map when creating new coordinates entry Helps avoid infinite recursion if trying to fetch coordinates at location currently being constructed --- include/bout/mesh.hxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 326c2f2fa3..3c5956400c 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -444,7 +444,8 @@ class Mesh { // No coordinate system set. Create default // Note that this can't be allocated here due to incomplete type // (circular dependency between Mesh and Coordinates) - coords_map.emplace(location, createDefaultCoordinates(location)); + coords_map[location] = std::shared_ptr(nullptr); + coords_map[location] = createDefaultCoordinates(location); return coords_map[location].get(); } } From e8ef9d9e535e18f82f1a14aca5266d9647920ce5 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 16 Jan 2019 19:31:05 +0000 Subject: [PATCH 0605/1783] Make field::setLocation immediately update the fieldCoordinates pointer --- src/field/field2d.cxx | 5 +---- src/field/field3d.cxx | 5 +---- src/field/fieldperp.cxx | 7 ++----- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 02f2a2e480..d76393bad7 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -130,10 +130,7 @@ void Field2D::setLocation(CELL_LOC new_location) { new_location = CELL_CENTRE; } - // Invalidate the coordinates pointer - if (new_location != location) { - fieldCoordinates = nullptr; - } + fieldCoordinates = getCoordinates(); location = new_location; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 65511f428a..febc9747b0 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -209,10 +209,7 @@ void Field3D::setLocation(CELL_LOC new_location) { new_location = CELL_CENTRE; } - // Invalidate the coordinates pointer - if (new_location != location) { - fieldCoordinates = nullptr; - } + fieldCoordinates = getCoordinates(); location = new_location; diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 5787f0ce29..dc93024a66 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -73,11 +73,8 @@ void FieldPerp::setLocation(CELL_LOC new_location) { new_location = CELL_CENTRE; } - // Invalidate the coordinates pointer - if (new_location != location) { - fieldCoordinates = nullptr; - } - + fieldCoordinates = getCoordinates(); + location = new_location; } else { From eacb979b135ae7df22115bdcaec6c3c6f138b310 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 16 Jan 2019 21:10:25 +0000 Subject: [PATCH 0606/1783] Make sure we update the location before storing the coordinate pointer --- src/field/field2d.cxx | 3 +-- src/field/field3d.cxx | 3 +-- src/field/fieldperp.cxx | 5 ++--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index d76393bad7..0862be5b37 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -130,9 +130,8 @@ void Field2D::setLocation(CELL_LOC new_location) { new_location = CELL_CENTRE; } - fieldCoordinates = getCoordinates(); - location = new_location; + fieldCoordinates = getCoordinates(); } else { #if CHECK > 0 diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index febc9747b0..f1a124af90 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -209,9 +209,8 @@ void Field3D::setLocation(CELL_LOC new_location) { new_location = CELL_CENTRE; } - fieldCoordinates = getCoordinates(); - location = new_location; + fieldCoordinates = getCoordinates(); } else { #if CHECK > 0 diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index dc93024a66..6477e6292d 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -72,11 +72,10 @@ void FieldPerp::setLocation(CELL_LOC new_location) { if (new_location == CELL_DEFAULT) { new_location = CELL_CENTRE; } - - fieldCoordinates = getCoordinates(); location = new_location; - + fieldCoordinates = getCoordinates(); + } else { #if CHECK > 0 if (new_location != CELL_CENTRE && new_location != CELL_DEFAULT) { From f188fba86e7e7b38bfab84668eac0ad4b745bed3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 16 Jan 2019 16:58:07 +0000 Subject: [PATCH 0607/1783] Simple test of Mesh::coords_map initialization Currently the test case hangs if 4 processors are used, see issue #1369. --- .../data/BOUT.inp | 9 +++++ .../test-coordinates-initialization/makefile | 6 ++++ .../test-coordinates-initialization.cxx | 34 +++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 tests/integrated/test-coordinates-initialization/data/BOUT.inp create mode 100644 tests/integrated/test-coordinates-initialization/makefile create mode 100644 tests/integrated/test-coordinates-initialization/test-coordinates-initialization.cxx diff --git a/tests/integrated/test-coordinates-initialization/data/BOUT.inp b/tests/integrated/test-coordinates-initialization/data/BOUT.inp new file mode 100644 index 0000000000..311aa45d4a --- /dev/null +++ b/tests/integrated/test-coordinates-initialization/data/BOUT.inp @@ -0,0 +1,9 @@ + +[mesh] +staggergrids = true +nx = 12 +ny = 2 +nz = 1 + +# include dx to be loaded, forces Coordinates constructor to communicate +dx = 1. diff --git a/tests/integrated/test-coordinates-initialization/makefile b/tests/integrated/test-coordinates-initialization/makefile new file mode 100644 index 0000000000..805ac0e1da --- /dev/null +++ b/tests/integrated/test-coordinates-initialization/makefile @@ -0,0 +1,6 @@ + +BOUT_TOP = ../../.. + +SOURCEC = test-coordinates-initialization.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-coordinates-initialization/test-coordinates-initialization.cxx b/tests/integrated/test-coordinates-initialization/test-coordinates-initialization.cxx new file mode 100644 index 0000000000..375cff5488 --- /dev/null +++ b/tests/integrated/test-coordinates-initialization/test-coordinates-initialization.cxx @@ -0,0 +1,34 @@ +/* + * Test of initialization of Coordinates objects in Mesh::coords_map + */ + +#include "bout.hxx" +#include "optionsreader.hxx" + +int main() { + + // Initialize options, needed to load mesh from BOUT.inp + Options *options = Options::getRoot(); + OptionsReader *reader = OptionsReader::getInstance(); + reader->read(options, "%s/%s", "data", "BOUT.inp"); + + // Initialize a mesh + mesh = Mesh::create(); + mesh->load(); + + // Test CELL_CENTRE + Field3D f(0., mesh); + f.applyBoundary("neumann"); + + // Test CELL_YLOW + Field3D f_ylow(0., mesh); + f_ylow.setLocation(CELL_YLOW); + f_ylow.applyBoundary("neumann"); + + // Synchronise all processors + MPI_Barrier(BoutComm::get()); + + MPI_Finalize(); + + return 0; +} From 26035fb89fdc8038ceca53e20f3e252021379a70 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 16 Jan 2019 17:03:33 +0000 Subject: [PATCH 0608/1783] Alternative test of Mesh::coords_map init, uses BoutInitialise() CELL_CENTRE Coordinates are initialized during BoutInitialise(), so this test only hangs in the CELL_YLOW applyBoundary("neumann"). --- .../data/BOUT.inp | 9 ++++++ .../test-coordinates-initialization2/makefile | 6 ++++ .../test-coordinates-initialization.cxx | 28 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 tests/integrated/test-coordinates-initialization2/data/BOUT.inp create mode 100644 tests/integrated/test-coordinates-initialization2/makefile create mode 100644 tests/integrated/test-coordinates-initialization2/test-coordinates-initialization.cxx diff --git a/tests/integrated/test-coordinates-initialization2/data/BOUT.inp b/tests/integrated/test-coordinates-initialization2/data/BOUT.inp new file mode 100644 index 0000000000..311aa45d4a --- /dev/null +++ b/tests/integrated/test-coordinates-initialization2/data/BOUT.inp @@ -0,0 +1,9 @@ + +[mesh] +staggergrids = true +nx = 12 +ny = 2 +nz = 1 + +# include dx to be loaded, forces Coordinates constructor to communicate +dx = 1. diff --git a/tests/integrated/test-coordinates-initialization2/makefile b/tests/integrated/test-coordinates-initialization2/makefile new file mode 100644 index 0000000000..805ac0e1da --- /dev/null +++ b/tests/integrated/test-coordinates-initialization2/makefile @@ -0,0 +1,6 @@ + +BOUT_TOP = ../../.. + +SOURCEC = test-coordinates-initialization.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-coordinates-initialization2/test-coordinates-initialization.cxx b/tests/integrated/test-coordinates-initialization2/test-coordinates-initialization.cxx new file mode 100644 index 0000000000..e7f160024f --- /dev/null +++ b/tests/integrated/test-coordinates-initialization2/test-coordinates-initialization.cxx @@ -0,0 +1,28 @@ +/* + * Test of initialization of Coordinates objects in Mesh::coords_map + */ + +#include "bout.hxx" +#include "optionsreader.hxx" + +int main(int argc, char** argv) { + + // Initialize BOUT++ + BoutInitialise(argc,argv); + + // Test CELL_CENTRE + Field3D f(0., mesh); + f.applyBoundary("neumann"); + + // Test CELL_YLOW + Field3D f_ylow(0., mesh); + f_ylow.setLocation(CELL_YLOW); + f_ylow.applyBoundary("neumann"); + + // Synchronise all processors + MPI_Barrier(BoutComm::get()); + + MPI_Finalize(); + + return 0; +} From 5d4629e0e6f7a6418610ff8f0c68ddb09834d29e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 16 Jan 2019 23:26:45 +0000 Subject: [PATCH 0609/1783] Add MPI_Barrier() to test-coordinates-initialization Without the MPI_Barrier() the test can pass by fluke, when the Coordinates constructor is called in f_ylow.setLocation() after not being called in f.applyBoundary("neumann"). --- .../test-coordinates-initialization.cxx | 3 +++ .../test-coordinates-initialization.cxx | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tests/integrated/test-coordinates-initialization/test-coordinates-initialization.cxx b/tests/integrated/test-coordinates-initialization/test-coordinates-initialization.cxx index 375cff5488..3b9ee97d4f 100644 --- a/tests/integrated/test-coordinates-initialization/test-coordinates-initialization.cxx +++ b/tests/integrated/test-coordinates-initialization/test-coordinates-initialization.cxx @@ -20,6 +20,9 @@ int main() { Field3D f(0., mesh); f.applyBoundary("neumann"); + // Synchronise all processors + MPI_Barrier(BoutComm::get()); + // Test CELL_YLOW Field3D f_ylow(0., mesh); f_ylow.setLocation(CELL_YLOW); diff --git a/tests/integrated/test-coordinates-initialization2/test-coordinates-initialization.cxx b/tests/integrated/test-coordinates-initialization2/test-coordinates-initialization.cxx index e7f160024f..1c45dc7103 100644 --- a/tests/integrated/test-coordinates-initialization2/test-coordinates-initialization.cxx +++ b/tests/integrated/test-coordinates-initialization2/test-coordinates-initialization.cxx @@ -14,6 +14,9 @@ int main(int argc, char** argv) { Field3D f(0., mesh); f.applyBoundary("neumann"); + // Synchronise all processors + MPI_Barrier(BoutComm::get()); + // Test CELL_YLOW Field3D f_ylow(0., mesh); f_ylow.setLocation(CELL_YLOW); From 566363bce20b1f65744f3c2afb03d25f4e3bddd6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 16 Jan 2019 23:45:04 +0000 Subject: [PATCH 0610/1783] Tidy up Coordinates initialization tests Add runtest scripts, README.md files and update .gitignore --- tests/integrated/.gitignore | 2 ++ tests/integrated/test-coordinates-initialization/README.md | 7 +++++++ tests/integrated/test-coordinates-initialization/runtest | 7 +++++++ .../integrated/test-coordinates-initialization2/README.md | 7 +++++++ tests/integrated/test-coordinates-initialization2/runtest | 7 +++++++ 5 files changed, 30 insertions(+) create mode 100644 tests/integrated/test-coordinates-initialization/README.md create mode 100755 tests/integrated/test-coordinates-initialization/runtest create mode 100644 tests/integrated/test-coordinates-initialization2/README.md create mode 100755 tests/integrated/test-coordinates-initialization2/runtest diff --git a/tests/integrated/.gitignore b/tests/integrated/.gitignore index 32030a8f3c..aa89de85ca 100644 --- a/tests/integrated/.gitignore +++ b/tests/integrated/.gitignore @@ -35,3 +35,5 @@ BOUT.settings /test-petsc_laplace_MAST-grid/test_petsc_laplace_MAST_grid /test-stopCheck/test_stopCheck /test-yupdown/test_yupdown +/test-coordinates-initialization/test-coordinates-initialization +/test-coordinates-initialization2/test-coordinates-initialization diff --git a/tests/integrated/test-coordinates-initialization/README.md b/tests/integrated/test-coordinates-initialization/README.md new file mode 100644 index 0000000000..7fd234b56f --- /dev/null +++ b/tests/integrated/test-coordinates-initialization/README.md @@ -0,0 +1,7 @@ +Solving Staggered Fields Test +============================= + +This test checks that BOUT++ doesn't hang when trying to apply boundary +conditions on boundaries that exist only on certain processes. This version +doesn't use BoutInitialise(). See +https://github.com/boutproject/BOUT-dev/issues/1369 for the original problem. diff --git a/tests/integrated/test-coordinates-initialization/runtest b/tests/integrated/test-coordinates-initialization/runtest new file mode 100755 index 0000000000..a535920326 --- /dev/null +++ b/tests/integrated/test-coordinates-initialization/runtest @@ -0,0 +1,7 @@ +#!/bin/bash + +set -e + +make +# Kill the test after 3 seconds, if it hasn't already exited +mpirun -n 4 timeout 3s ./test-coordinates-initialization diff --git a/tests/integrated/test-coordinates-initialization2/README.md b/tests/integrated/test-coordinates-initialization2/README.md new file mode 100644 index 0000000000..49300484eb --- /dev/null +++ b/tests/integrated/test-coordinates-initialization2/README.md @@ -0,0 +1,7 @@ +Solving Staggered Fields Test +============================= + +This test checks that BOUT++ doesn't hang when trying to apply boundary +conditions on boundaries that exist only on certain processes. This version +uses BoutInitialise(). See https://github.com/boutproject/BOUT-dev/issues/1369 +for the original problem. diff --git a/tests/integrated/test-coordinates-initialization2/runtest b/tests/integrated/test-coordinates-initialization2/runtest new file mode 100755 index 0000000000..a535920326 --- /dev/null +++ b/tests/integrated/test-coordinates-initialization2/runtest @@ -0,0 +1,7 @@ +#!/bin/bash + +set -e + +make +# Kill the test after 3 seconds, if it hasn't already exited +mpirun -n 4 timeout 3s ./test-coordinates-initialization From ed8186008d98a1127a4e3adaa8b37ca295dc4695 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 16 Jan 2019 23:51:11 +0000 Subject: [PATCH 0611/1783] Ensure CELL_CENTRE Coordinates are always initialized in a Mesh --- src/mesh/impls/bout/boutmesh.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 0bf59de09a..a8db998fb5 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -839,6 +839,9 @@ int BoutMesh::load() { // Add boundary regions addBoundaryRegions(); + // Initialize default coordinates + getCoordinates(); + output_info.write(_("\tdone\n")); return 0; From e975811952af3bbc4c8cebea098bcdae34bbcb78 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 17 Jan 2019 00:47:34 +0000 Subject: [PATCH 0612/1783] Fix unit tests for coords_map initialization Now need to make sure mesh has coords_map initialized so setLocation() can be used. Staggered tests need entry adding to coords_map for all locations used. Add global mesh_staggered for convenience, covers most staggered tests. --- tests/unit/field/test_field2d.cxx | 18 ++------- tests/unit/field/test_field3d.cxx | 52 +++++++------------------- tests/unit/field/test_fieldperp.cxx | 4 +- tests/unit/field/test_vector2d.cxx | 33 ++++++++-------- tests/unit/field/test_vector3d.cxx | 39 +++++++++---------- tests/unit/mesh/test_interpolation.cxx | 3 ++ tests/unit/test_extras.cxx | 5 +++ tests/unit/test_extras.hxx | 23 +++++++++++- 8 files changed, 86 insertions(+), 91 deletions(-) diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index 0634813d4c..cc1fe61cd9 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -1083,11 +1083,8 @@ TEST_F(Field2DTest, Max) { } TEST_F(Field2DTest, Swap) { - auto backup = mesh->StaggerGrids; - mesh->StaggerGrids = true; - // First field - Field2D first(1., mesh); + Field2D first(1., mesh_staggered); first.setLocation(CELL_XLOW); @@ -1125,7 +1122,7 @@ TEST_F(Field2DTest, Swap) { // Mesh properties EXPECT_EQ(first.getMesh(), &second_mesh); - EXPECT_EQ(second.getMesh(), mesh); + EXPECT_EQ(second.getMesh(), mesh_staggered); EXPECT_EQ(first.getNx(), second_nx); EXPECT_EQ(first.getNy(), second_ny); @@ -1140,16 +1137,11 @@ TEST_F(Field2DTest, Swap) { // We don't check the boundaries, but the data is protected and // there are no inquiry functions - - mesh->StaggerGrids = backup; } TEST_F(Field2DTest, MoveCtor) { - auto backup = mesh->StaggerGrids; - mesh->StaggerGrids = true; - // First field - Field2D first(1., mesh); + Field2D first(1., mesh_staggered); first.setLocation(CELL_XLOW); @@ -1164,7 +1156,7 @@ TEST_F(Field2DTest, MoveCtor) { EXPECT_TRUE(IsField2DEqualBoutReal(ddt(second), 1.1)); // Mesh properties - EXPECT_EQ(second.getMesh(), mesh); + EXPECT_EQ(second.getMesh(), mesh_staggered); EXPECT_EQ(second.getNx(), Field2DTest::nx); EXPECT_EQ(second.getNy(), Field2DTest::ny); @@ -1174,8 +1166,6 @@ TEST_F(Field2DTest, MoveCtor) { // We don't check the boundaries, but the data is protected and // there are no inquiry functions - - mesh->StaggerGrids = backup; } TEST_F(Field2DTest, FillField) { diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 487da64e56..b7242c7135 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -300,7 +300,7 @@ TEST_F(Field3DTest, GetLocalMesh) { } TEST_F(Field3DTest, SetGetLocation) { - Field3D field; + Field3D field(mesh_staggered); field.getMesh()->StaggerGrids = true; @@ -1100,9 +1100,7 @@ TEST_F(Field3DTest, AddEqualsField3D) { } TEST_F(Field3DTest, AddEqualsField3DField3DStagger) { - mesh->StaggerGrids = true; // Force staggering - - Field3D a, b; + Field3D a(mesh_staggered), b(mesh_staggered); a = 2.0; b = 3.0; @@ -1169,9 +1167,7 @@ TEST_F(Field3DTest, AddField3DField3D) { } TEST_F(Field3DTest, AddField3DField3DStagger) { - mesh->StaggerGrids = true; // Force staggering - - Field3D a, b, c; + Field3D a(mesh_staggered), b(mesh_staggered), c(mesh_staggered); a = 1.0; b = 2.0; @@ -1247,9 +1243,7 @@ TEST_F(Field3DTest, MultiplyEqualsField3D) { } TEST_F(Field3DTest, MultiplyEqualsField3DField3DStagger) { - mesh->StaggerGrids = true; // Force staggering - - Field3D a, b; + Field3D a(mesh_staggered), b(mesh_staggered); a = 2.5; b = 4.0; @@ -1316,9 +1310,7 @@ TEST_F(Field3DTest, MultiplyField3DField3D) { } TEST_F(Field3DTest, MultiplyField3DField3DStagger) { - mesh->StaggerGrids = true; // Force staggering - - Field3D a, b, c; + Field3D a(mesh_staggered), b(mesh_staggered), c(mesh_staggered); a = 1.0; b = 2.0; @@ -1394,9 +1386,7 @@ TEST_F(Field3DTest, SubtractEqualsField3D) { } TEST_F(Field3DTest, SubtractEqualsField3DField3DStagger) { - mesh->StaggerGrids = true; // Force staggering - - Field3D a, b; + Field3D a(mesh_staggered), b(mesh_staggered); a = 2.0; b = 7.0; @@ -1463,9 +1453,7 @@ TEST_F(Field3DTest, SubtractField3DField3D) { } TEST_F(Field3DTest, SubtractField3DField3DStagger) { - mesh->StaggerGrids = true; // Force staggering - - Field3D a, b, c; + Field3D a(mesh_staggered), b(mesh_staggered), c(mesh_staggered); a = 1.0; b = 2.0; @@ -1541,9 +1529,7 @@ TEST_F(Field3DTest, DivideEqualsField3D) { } TEST_F(Field3DTest, DivideEqualsField3DField3DStagger) { - mesh->StaggerGrids = true; // Force staggering - - Field3D a, b; + Field3D a(mesh_staggered), b(mesh_staggered); a = 5.0; b = 2.5; @@ -1610,9 +1596,7 @@ TEST_F(Field3DTest, DivideField3DField3D) { } TEST_F(Field3DTest, DivideField3DField3DStagger) { - mesh->StaggerGrids = true; // Force staggering - - Field3D a, b, c; + Field3D a(mesh_staggered), b(mesh_staggered), c(mesh_staggered); a = 1.0; b = 2.0; @@ -1863,11 +1847,8 @@ TEST_F(Field3DTest, DC) { } TEST_F(Field3DTest, Swap) { - auto backup = mesh->StaggerGrids; - mesh->StaggerGrids = true; - // First field - Field3D first(1., mesh); + Field3D first(1., mesh_staggered); first.setLocation(CELL_XLOW); @@ -1919,7 +1900,7 @@ TEST_F(Field3DTest, Swap) { // Mesh properties EXPECT_EQ(first.getMesh(), &second_mesh); - EXPECT_EQ(second.getMesh(), mesh); + EXPECT_EQ(second.getMesh(), mesh_staggered); EXPECT_EQ(first.getNx(), second_nx); EXPECT_EQ(first.getNy(), second_ny); @@ -1934,16 +1915,11 @@ TEST_F(Field3DTest, Swap) { // We don't check the boundaries, but the data is protected and // there are no inquiry functions - - mesh->StaggerGrids = backup; } TEST_F(Field3DTest, MoveCtor) { - auto backup = mesh->StaggerGrids; - mesh->StaggerGrids = true; - // First field - Field3D first(1., mesh); + Field3D first(1., mesh_staggered); first.setLocation(CELL_XLOW); @@ -1965,7 +1941,7 @@ TEST_F(Field3DTest, MoveCtor) { EXPECT_TRUE(IsField3DEqualBoutReal(ddt(second), 1.1)); // Mesh properties - EXPECT_EQ(second.getMesh(), mesh); + EXPECT_EQ(second.getMesh(), mesh_staggered); EXPECT_EQ(second.getNx(), Field3DTest::nx); EXPECT_EQ(second.getNy(), Field3DTest::ny); @@ -1975,8 +1951,6 @@ TEST_F(Field3DTest, MoveCtor) { // We don't check the boundaries, but the data is protected and // there are no inquiry functions - - mesh->StaggerGrids = backup; } TEST_F(Field3DTest, FillField) { diff --git a/tests/unit/field/test_fieldperp.cxx b/tests/unit/field/test_fieldperp.cxx index 55757dc83e..0a47ece053 100644 --- a/tests/unit/field/test_fieldperp.cxx +++ b/tests/unit/field/test_fieldperp.cxx @@ -191,9 +191,7 @@ TEST_F(FieldPerpTest, CreateCopyOnNullMesh) { #endif TEST_F(FieldPerpTest, SetGetLocation) { - FieldPerp field; - - field.getMesh()->StaggerGrids = true; + FieldPerp field(mesh_staggered); field.setLocation(CELL_XLOW); EXPECT_EQ(field.getLocation(), CELL_XLOW); diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index a6ec890c34..507111c55f 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -128,9 +128,8 @@ TEST_F(Vector2DTest, SetLocationNonStaggered) { } TEST_F(Vector2DTest, SetLocationXLOW) { - Vector2D vector; + Vector2D vector(mesh_staggered); CELL_LOC targetLoc = CELL_XLOW; - vector.x.getMesh()->StaggerGrids = true; EXPECT_EQ(vector.getLocation(), CELL_CENTRE); EXPECT_NO_THROW(vector.setLocation(targetLoc)); EXPECT_EQ(vector.getLocation(), targetLoc); @@ -140,9 +139,11 @@ TEST_F(Vector2DTest, SetLocationXLOW) { } TEST_F(Vector2DTest, SetLocationYLOW) { - Vector2D vector; + FakeMesh local_mesh{Vector2DTest::nx,Vector2DTest::ny,Vector2DTest::nz}; + local_mesh.StaggerGrids = true; + local_mesh.setCoordinates(nullptr, CELL_YLOW); + Vector2D vector(&local_mesh); CELL_LOC targetLoc = CELL_YLOW; - vector.x.getMesh()->StaggerGrids = true; EXPECT_EQ(vector.getLocation(), CELL_CENTRE); EXPECT_NO_THROW(vector.setLocation(targetLoc)); EXPECT_EQ(vector.getLocation(), targetLoc); @@ -152,9 +153,11 @@ TEST_F(Vector2DTest, SetLocationYLOW) { } TEST_F(Vector2DTest, SetLocationZLOW) { - Vector2D vector; + FakeMesh local_mesh{Vector2DTest::nx,Vector2DTest::ny,Vector2DTest::nz}; + local_mesh.StaggerGrids = true; + local_mesh.setCoordinates(nullptr, CELL_ZLOW); + Vector2D vector(&local_mesh); CELL_LOC targetLoc = CELL_ZLOW; - vector.x.getMesh()->StaggerGrids = true; EXPECT_EQ(vector.getLocation(), CELL_CENTRE); EXPECT_NO_THROW(vector.setLocation(targetLoc)); EXPECT_EQ(vector.getLocation(), targetLoc); @@ -164,8 +167,12 @@ TEST_F(Vector2DTest, SetLocationZLOW) { } TEST_F(Vector2DTest, SetLocationVSHIFT) { - Vector2D vector; - vector.x.getMesh()->StaggerGrids = true; + FakeMesh local_mesh{Vector2DTest::nx,Vector2DTest::ny,Vector2DTest::nz}; + local_mesh.StaggerGrids = true; + local_mesh.setCoordinates(nullptr, CELL_XLOW); + local_mesh.setCoordinates(nullptr, CELL_YLOW); + local_mesh.setCoordinates(nullptr, CELL_ZLOW); + Vector2D vector(&local_mesh); EXPECT_EQ(vector.getLocation(), CELL_CENTRE); EXPECT_NO_THROW(vector.setLocation(CELL_VSHIFT)); EXPECT_EQ(vector.getLocation(), CELL_VSHIFT); @@ -197,9 +204,7 @@ TEST_F(Vector2DTest, AssignFromBoutReal) { } TEST_F(Vector2DTest, AssignFromVector2D) { - Vector2D vector1, vector2; - - vector1.x.getMesh()->StaggerGrids = true; + Vector2D vector1(mesh_staggered), vector2(mesh_staggered); vector1.x = 1.0; vector1.y = 2.0; @@ -215,14 +220,12 @@ TEST_F(Vector2DTest, AssignFromVector2D) { } TEST_F(Vector2DTest, CreateFromVector2D) { - Vector2D vector1; - - vector1.x.getMesh()->StaggerGrids = true; + Vector2D vector1(mesh_staggered); vector1.x = 4.0; vector1.y = 5.0; vector1.z = 6.0; - vector1.setLocation(CELL_YLOW); + vector1.setLocation(CELL_XLOW); Vector2D vector2{vector1}; diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index eae149755d..520b6305d3 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -127,9 +127,8 @@ TEST_F(Vector3DTest, SetLocationNonStaggered) { } TEST_F(Vector3DTest, SetLocationXLOW) { - Vector3D vector; + Vector3D vector(mesh_staggered); CELL_LOC targetLoc = CELL_XLOW; - vector.x.getMesh()->StaggerGrids = true; EXPECT_EQ(vector.getLocation(), CELL_CENTRE); EXPECT_NO_THROW(vector.setLocation(targetLoc)); EXPECT_EQ(vector.getLocation(), targetLoc); @@ -139,9 +138,11 @@ TEST_F(Vector3DTest, SetLocationXLOW) { } TEST_F(Vector3DTest, SetLocationYLOW) { - Vector3D vector; + FakeMesh local_mesh{Vector3DTest::nx,Vector3DTest::ny,Vector3DTest::nz}; + local_mesh.StaggerGrids = true; + local_mesh.setCoordinates(nullptr, CELL_YLOW); + Vector3D vector(&local_mesh); CELL_LOC targetLoc = CELL_YLOW; - vector.x.getMesh()->StaggerGrids = true; EXPECT_EQ(vector.getLocation(), CELL_CENTRE); EXPECT_NO_THROW(vector.setLocation(targetLoc)); EXPECT_EQ(vector.getLocation(), targetLoc); @@ -151,9 +152,11 @@ TEST_F(Vector3DTest, SetLocationYLOW) { } TEST_F(Vector3DTest, SetLocationZLOW) { - Vector3D vector; + FakeMesh local_mesh{Vector3DTest::nx,Vector3DTest::ny,Vector3DTest::nz}; + local_mesh.StaggerGrids = true; + local_mesh.setCoordinates(nullptr, CELL_ZLOW); + Vector3D vector(&local_mesh); CELL_LOC targetLoc = CELL_ZLOW; - vector.x.getMesh()->StaggerGrids = true; EXPECT_EQ(vector.getLocation(), CELL_CENTRE); EXPECT_NO_THROW(vector.setLocation(targetLoc)); EXPECT_EQ(vector.getLocation(), targetLoc); @@ -163,8 +166,12 @@ TEST_F(Vector3DTest, SetLocationZLOW) { } TEST_F(Vector3DTest, SetLocationVSHIFT) { - Vector3D vector; - vector.x.getMesh()->StaggerGrids = true; + FakeMesh local_mesh{Vector3DTest::nx,Vector3DTest::ny,Vector3DTest::nz}; + local_mesh.StaggerGrids = true; + local_mesh.setCoordinates(nullptr, CELL_XLOW); + local_mesh.setCoordinates(nullptr, CELL_YLOW); + local_mesh.setCoordinates(nullptr, CELL_ZLOW); + Vector3D vector(&local_mesh); EXPECT_EQ(vector.getLocation(), CELL_CENTRE); EXPECT_NO_THROW(vector.setLocation(CELL_VSHIFT)); EXPECT_EQ(vector.getLocation(), CELL_VSHIFT); @@ -196,10 +203,8 @@ TEST_F(Vector3DTest, AssignFromBoutReal) { } TEST_F(Vector3DTest, AssignFromVector2D) { - Vector2D vector1; - Vector3D vector2; - - vector1.x.getMesh()->StaggerGrids = true; + Vector2D vector1(mesh_staggered); + Vector3D vector2(mesh_staggered); vector1.x = 1.0; vector1.y = 2.0; @@ -215,9 +220,7 @@ TEST_F(Vector3DTest, AssignFromVector2D) { } TEST_F(Vector3DTest, AssignFromVector3D) { - Vector3D vector1, vector2; - - vector1.x.getMesh()->StaggerGrids = true; + Vector3D vector1(mesh_staggered), vector2(mesh_staggered); vector1.x = 1.0; vector1.y = 2.0; @@ -233,14 +236,12 @@ TEST_F(Vector3DTest, AssignFromVector3D) { } TEST_F(Vector3DTest, CreateFromVector3D) { - Vector3D vector1; - - vector1.x.getMesh()->StaggerGrids = true; + Vector3D vector1(mesh_staggered); vector1.x = 4.0; vector1.y = 5.0; vector1.z = 6.0; - vector1.setLocation(CELL_YLOW); + vector1.setLocation(CELL_XLOW); Vector3D vector2{vector1}; diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index f48b5c5c52..bf5bcac1b3 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -54,6 +54,9 @@ class Field3DInterpToTest : public ::testing::Test { mesh->ystart = 2; mesh->xend = nx - 3; mesh->yend = ny - 3; + dynamic_cast(mesh)->setCoordinates(nullptr, CELL_XLOW); + dynamic_cast(mesh)->setCoordinates(nullptr, CELL_YLOW); + dynamic_cast(mesh)->setCoordinates(nullptr, CELL_ZLOW); mesh->setParallelTransform(bout::utils::make_unique()); output_info.disable(); mesh->createDefaultRegions(); diff --git a/tests/unit/test_extras.cxx b/tests/unit/test_extras.cxx index 1766f177b5..872dfa459e 100644 --- a/tests/unit/test_extras.cxx +++ b/tests/unit/test_extras.cxx @@ -3,6 +3,11 @@ #include +// Need to declare variable in exactly one source file +#ifndef GLOBALORIGIN +Mesh* mesh_staggered; +#endif + // Need to provide a redundant declaration because C++ constexpr int FakeMeshFixture::nx; constexpr int FakeMeshFixture::ny; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index a4593c8657..3d3e971689 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -14,6 +14,12 @@ const BoutReal BoutRealTolerance = 1e-15; +#ifndef GLOBALORIGIN +extern Mesh* mesh_staggered; +#else +Mesh* mesh_staggered = nullptr; +#endif + /// Does \p str contain \p substring? ::testing::AssertionResult IsSubString(const std::string &str, const std::string &substring); @@ -85,6 +91,8 @@ public: StaggerGrids = false; IncIntShear = false; maxregionblocksize = MAXREGIONBLOCKSIZE; + + setCoordinates(nullptr); } void setCoordinates(std::shared_ptr coords, CELL_LOC location = CELL_CENTRE) { @@ -179,7 +187,8 @@ private: }; /// Test fixture to make sure the global mesh is our fake -/// one. Multiple tests have exactly the same fixture, so use a type +/// one. Also initialize the global mesh_staggered for use in tests with +/// staggering. Multiple tests have exactly the same fixture, so use a type /// alias to make a new test: /// /// using MyTest = FakeMeshFixture; @@ -195,6 +204,18 @@ public: output_info.disable(); mesh->createDefaultRegions(); output_info.enable(); + + // Delete any existing mesh_staggered + if (mesh_staggered != nullptr) { + delete mesh_staggered; + mesh_staggered = nullptr; + } + mesh_staggered = new FakeMesh(nx, ny, nz); + mesh_staggered->StaggerGrids = true; + output_info.disable(); + dynamic_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); + mesh_staggered->createDefaultRegions(); + output_info.enable(); } ~FakeMeshFixture() { From ab37f7ac42ddf8fe72f07ad1856ebcf8d6b558a8 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 17 Jan 2019 10:22:38 +0000 Subject: [PATCH 0613/1783] Make mesh_staggered a member of test fixtures --- tests/unit/field/test_vector2d.cxx | 14 ++++++++++++++ tests/unit/field/test_vector3d.cxx | 14 ++++++++++++++ tests/unit/test_extras.cxx | 5 ----- tests/unit/test_extras.hxx | 10 ++++------ 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index 507111c55f..71cbb63105 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -41,6 +41,16 @@ class Vector2DTest : public ::testing::Test { Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{0.0}, Field2D{0.0}, false)); + + if (mesh_staggered != nullptr) { + delete mesh_staggered; + mesh_staggered = nullptr; + } + mesh_staggered = new FakeMesh(nx, ny, nz); + mesh_staggered->StaggerGrids = true; + output_info.disable(); + dynamic_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); + mesh_staggered->createDefaultRegions(); } ~Vector2DTest() { @@ -52,12 +62,16 @@ class Vector2DTest : public ::testing::Test { delete mesh; mesh = nullptr; } + delete mesh_staggered; + mesh_staggered = nullptr; } public: static constexpr int nx = 5; static constexpr int ny = 5; static constexpr int nz = 1; + + Mesh* mesh_staggered = nullptr; }; constexpr int Vector2DTest::nx; diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index 520b6305d3..1ffc4cc634 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -40,6 +40,16 @@ class Vector3DTest : public ::testing::Test { Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{0.0}, Field2D{0.0}, false)); + + if (mesh_staggered != nullptr) { + delete mesh_staggered; + mesh_staggered = nullptr; + } + mesh_staggered = new FakeMesh(nx, ny, nz); + mesh_staggered->StaggerGrids = true; + output_info.disable(); + dynamic_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); + mesh_staggered->createDefaultRegions(); } ~Vector3DTest() { @@ -51,12 +61,16 @@ class Vector3DTest : public ::testing::Test { } delete mesh; mesh = nullptr; + delete mesh_staggered; + mesh_staggered = nullptr; } public: static const int nx; static const int ny; static const int nz; + + Mesh* mesh_staggered = nullptr; }; const int Vector3DTest::nx = 5; diff --git a/tests/unit/test_extras.cxx b/tests/unit/test_extras.cxx index 872dfa459e..1766f177b5 100644 --- a/tests/unit/test_extras.cxx +++ b/tests/unit/test_extras.cxx @@ -3,11 +3,6 @@ #include -// Need to declare variable in exactly one source file -#ifndef GLOBALORIGIN -Mesh* mesh_staggered; -#endif - // Need to provide a redundant declaration because C++ constexpr int FakeMeshFixture::nx; constexpr int FakeMeshFixture::ny; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 3d3e971689..b16b2cd620 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -14,12 +14,6 @@ const BoutReal BoutRealTolerance = 1e-15; -#ifndef GLOBALORIGIN -extern Mesh* mesh_staggered; -#else -Mesh* mesh_staggered = nullptr; -#endif - /// Does \p str contain \p substring? ::testing::AssertionResult IsSubString(const std::string &str, const std::string &substring); @@ -221,11 +215,15 @@ public: ~FakeMeshFixture() { delete mesh; mesh = nullptr; + delete mesh_staggered; + mesh_staggered = nullptr; } static constexpr int nx = 3; static constexpr int ny = 5; static constexpr int nz = 7; + + Mesh* mesh_staggered = nullptr; }; #endif // TEST_EXTRAS_H__ From f2c00e3b583302eaae0931a46a89bba020f28a09 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 17 Jan 2019 12:45:04 +0000 Subject: [PATCH 0614/1783] Reduce number of threads, processors for test test-coordinates-initialization only needs 3 processors. Also force OMP_NUM_THREADS=1 so test is not too slow to pass on Travis. --- tests/integrated/test-coordinates-initialization/data/BOUT.inp | 2 +- tests/integrated/test-coordinates-initialization/runtest | 2 +- tests/integrated/test-coordinates-initialization2/data/BOUT.inp | 2 +- tests/integrated/test-coordinates-initialization2/runtest | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/integrated/test-coordinates-initialization/data/BOUT.inp b/tests/integrated/test-coordinates-initialization/data/BOUT.inp index 311aa45d4a..cb2c201586 100644 --- a/tests/integrated/test-coordinates-initialization/data/BOUT.inp +++ b/tests/integrated/test-coordinates-initialization/data/BOUT.inp @@ -1,7 +1,7 @@ [mesh] staggergrids = true -nx = 12 +nx = 10 ny = 2 nz = 1 diff --git a/tests/integrated/test-coordinates-initialization/runtest b/tests/integrated/test-coordinates-initialization/runtest index a535920326..94b589e2d4 100755 --- a/tests/integrated/test-coordinates-initialization/runtest +++ b/tests/integrated/test-coordinates-initialization/runtest @@ -4,4 +4,4 @@ set -e make # Kill the test after 3 seconds, if it hasn't already exited -mpirun -n 4 timeout 3s ./test-coordinates-initialization +OMP_NUM_THREADS=1 mpirun -n 3 timeout 3s ./test-coordinates-initialization diff --git a/tests/integrated/test-coordinates-initialization2/data/BOUT.inp b/tests/integrated/test-coordinates-initialization2/data/BOUT.inp index 311aa45d4a..cb2c201586 100644 --- a/tests/integrated/test-coordinates-initialization2/data/BOUT.inp +++ b/tests/integrated/test-coordinates-initialization2/data/BOUT.inp @@ -1,7 +1,7 @@ [mesh] staggergrids = true -nx = 12 +nx = 10 ny = 2 nz = 1 diff --git a/tests/integrated/test-coordinates-initialization2/runtest b/tests/integrated/test-coordinates-initialization2/runtest index a535920326..94b589e2d4 100755 --- a/tests/integrated/test-coordinates-initialization2/runtest +++ b/tests/integrated/test-coordinates-initialization2/runtest @@ -4,4 +4,4 @@ set -e make # Kill the test after 3 seconds, if it hasn't already exited -mpirun -n 4 timeout 3s ./test-coordinates-initialization +OMP_NUM_THREADS=1 mpirun -n 3 timeout 3s ./test-coordinates-initialization From 9444289b38a4fb520b344b4583d66ea81c394b3d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 17 Jan 2019 20:05:02 +0000 Subject: [PATCH 0615/1783] Move getCoordinates() call to the end of setLocation() Makes cases with StaggerGrids true or false behave similarly. Also replace 'fieldCoordinates = getCoordinates()' with just 'getCoordinates()' which sets 'fieldCoordinates' within itself. --- src/field/field2d.cxx | 5 +++-- src/field/field3d.cxx | 5 +++-- src/field/fieldperp.cxx | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 0862be5b37..d93b40a5e6 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -131,8 +131,6 @@ void Field2D::setLocation(CELL_LOC new_location) { } location = new_location; - fieldCoordinates = getCoordinates(); - } else { #if CHECK > 0 if (new_location != CELL_CENTRE && new_location != CELL_DEFAULT) { @@ -143,6 +141,9 @@ void Field2D::setLocation(CELL_LOC new_location) { #endif location = CELL_CENTRE; } + + // Ensures Coordinates object is initialized for this Field's location + getCoordinates(); } CELL_LOC Field2D::getLocation() const { diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index f1a124af90..891f3ac715 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -210,8 +210,6 @@ void Field3D::setLocation(CELL_LOC new_location) { } location = new_location; - fieldCoordinates = getCoordinates(); - } else { #if CHECK > 0 if (new_location != CELL_CENTRE && new_location != CELL_DEFAULT) { @@ -222,6 +220,9 @@ void Field3D::setLocation(CELL_LOC new_location) { #endif location = CELL_CENTRE; } + + // Ensures Coordinates object is initialized for this Field's location + getCoordinates(); } CELL_LOC Field3D::getLocation() const { diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 6477e6292d..e209374f88 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -74,8 +74,6 @@ void FieldPerp::setLocation(CELL_LOC new_location) { } location = new_location; - fieldCoordinates = getCoordinates(); - } else { #if CHECK > 0 if (new_location != CELL_CENTRE && new_location != CELL_DEFAULT) { @@ -86,6 +84,9 @@ void FieldPerp::setLocation(CELL_LOC new_location) { #endif location = CELL_CENTRE; } + + // Ensures Coordinates object is initialized for this Field's location + getCoordinates(); } CELL_LOC FieldPerp::getLocation() const { From dce16357b3a68401241bbc9eef9ae5063049bcaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 18 Jan 2019 16:38:57 +0000 Subject: [PATCH 0616/1783] Add outloc and method support for vec operations --- include/vecops.hxx | 36 ++++++++++++++++--------- src/field/vecops.cxx | 63 ++++++++++++++++++++------------------------ 2 files changed, 51 insertions(+), 48 deletions(-) diff --git a/include/vecops.hxx b/include/vecops.hxx index 51f3035a78..289a8d7613 100644 --- a/include/vecops.hxx +++ b/include/vecops.hxx @@ -41,10 +41,13 @@ /// All locations supported /// /// @param[in] f The field to differentiate -/// @param[in] outloc The location where the result is desired (if staggered meshes are enabled) -/// By default this is the same location as the input \p f -const Vector2D Grad(const Field2D &f, CELL_LOC outloc = CELL_DEFAULT); -const Vector3D Grad(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT); +/// @param[in] outloc The location where the result is desired +/// By default this is the same location as the input \p f +/// @param[in] method The method to use. The default is set in the options. +const Vector2D Grad(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +const Vector3D Grad(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); /// Perpendicular gradient of scalar field \p f /// @@ -56,10 +59,12 @@ const Vector3D Grad(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT); /// /// @param[in] f The field to differentiate /// @param[in] outloc The cell location where the result is desired +/// @param[in] method The method to use. The default is set in the options. /// -const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc = CELL_DEFAULT); -inline const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc, DIFF_METHOD method){ - return Grad_perp(f,outloc); +const Vector3D Grad_perp(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +inline const Vector3D Grad_perp(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { + return Grad_perp(f, outloc, DIFF_METHOD_STRING(method)); } /// Divergence of a vector \p v, returning a scalar @@ -69,17 +74,22 @@ inline const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc, DIFF_METHOD m /// /// @param[in] v The vector to differentiate /// @param[in] outloc The cell location where the result is desired +/// @param[in] method The method to use. The default is set in the options. /// -const Field2D Div(const Vector2D &v, CELL_LOC outloc = CELL_DEFAULT); -const Field3D Div(const Vector3D &v, CELL_LOC outloc = CELL_DEFAULT); +const Field2D Div(const Vector2D& v, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); +const Field3D Div(const Vector3D& v, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); const Field2D Div(const Vector2D &v, const Field2D &f); -const Field3D Div(const Vector3D &v, const Field3D &f); -const Field3D Div(const Vector3D& v, const Field3D& f, CELL_LOC outloc, +const Field3D Div(const Vector3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); -DEPRECATED(const Field3D Div(const Vector3D& v, const Field3D& f, - const std::string& method, CELL_LOC outloc = CELL_DEFAULT)); +DEPRECATED(inline const Field3D Div(const Vector3D& v, const Field3D& f, + const std::string& method, + CELL_LOC outloc = CELL_DEFAULT)) { + return Div(v, f, outloc, method); +} inline const Field3D Div(const Vector3D& v, const Field3D& f, CELL_LOC outloc, DIFF_METHOD method = DIFF_DEFAULT) { return Div(v, f, outloc, DIFF_METHOD_STRING(method)); diff --git a/src/field/vecops.cxx b/src/field/vecops.cxx index a14855a5ab..306317d2a9 100644 --- a/src/field/vecops.cxx +++ b/src/field/vecops.cxx @@ -36,7 +36,7 @@ * Gradient operators **************************************************************************/ -const Vector2D Grad(const Field2D &f, CELL_LOC outloc) { +const Vector2D Grad(const Field2D& f, CELL_LOC outloc, const std::string& method) { TRACE("Grad( Field2D )"); SCOREP0(); CELL_LOC outloc_x, outloc_y, outloc_z; @@ -50,9 +50,9 @@ const Vector2D Grad(const Field2D &f, CELL_LOC outloc) { Vector2D result(f.getMesh()); - result.x = DDX(f, outloc_x); - result.y = DDY(f, outloc_y); - result.z = DDZ(f, outloc_z); + result.x = DDX(f, outloc_x, method); + result.y = DDY(f, outloc_y, method); + result.z = DDZ(f, outloc_z, method); if (outloc == CELL_DEFAULT) { result.setLocation(result.x.getLocation()); @@ -65,7 +65,7 @@ const Vector2D Grad(const Field2D &f, CELL_LOC outloc) { return result; } -const Vector3D Grad(const Field3D &f, CELL_LOC outloc) { +const Vector3D Grad(const Field3D &f, CELL_LOC outloc, const std::string& method) { TRACE("Grad( Field3D )"); SCOREP0(); CELL_LOC outloc_x, outloc_y, outloc_z; @@ -79,9 +79,9 @@ const Vector3D Grad(const Field3D &f, CELL_LOC outloc) { Vector3D result(f.getMesh()); - result.x = DDX(f, outloc_x); - result.y = DDY(f, outloc_y); - result.z = DDZ(f, outloc_z); + result.x = DDX(f, outloc_x, method); + result.y = DDY(f, outloc_y, method); + result.z = DDZ(f, outloc_z, method); if (outloc == CELL_DEFAULT) { result.setLocation(result.x.getLocation()); @@ -94,7 +94,7 @@ const Vector3D Grad(const Field3D &f, CELL_LOC outloc) { return result; } -const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc) { +const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc, const std::string& method) { TRACE("Grad_perp( Field3D )"); SCOREP0(); ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); @@ -103,9 +103,11 @@ const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc) { Vector3D result(f.getMesh()); - result.x = DDX(f, outloc) - metric->g_12 * DDY(f, outloc) / SQ(metric->J * metric->Bxy); + result.x = DDX(f, outloc, method) + - metric->g_12 * DDY(f, outloc, method) / SQ(metric->J * metric->Bxy); result.y = 0.0; - result.z = DDZ(f, outloc) - metric->g_23 * DDY(f, outloc) / SQ(metric->J * metric->Bxy); + result.z = DDZ(f, outloc, method) + - metric->g_23 * DDY(f, outloc, method) / SQ(metric->J * metric->Bxy); result.setLocation(result.x.getLocation()); @@ -118,7 +120,7 @@ const Vector3D Grad_perp(const Field3D &f, CELL_LOC outloc) { * Divergence operators **************************************************************************/ -const Field2D Div(const Vector2D &v, CELL_LOC outloc) { +const Field2D Div(const Vector2D& v, CELL_LOC outloc, const std::string& method) { TRACE("Div( Vector2D )"); SCOREP0(); if (outloc == CELL_DEFAULT) { @@ -136,15 +138,15 @@ const Field2D Div(const Vector2D &v, CELL_LOC outloc) { Vector2D vcn = v; vcn.toContravariant(); - result = DDX(metric->J*vcn.x, outloc); - result += DDY(metric->J*vcn.y, outloc); - result += DDZ(metric->J*vcn.z, outloc); + result = DDX(metric->J*vcn.x, outloc, method); + result += DDY(metric->J*vcn.y, outloc, method); + result += DDZ(metric->J*vcn.z, outloc, method); result /= metric->J; return result; } -const Field3D Div(const Vector3D &v, CELL_LOC outloc) { +const Field3D Div(const Vector3D& v, CELL_LOC outloc, const std::string& method) { TRACE("Div( Vector3D )"); SCOREP0(); if (outloc == CELL_DEFAULT) { @@ -163,9 +165,9 @@ const Field3D Div(const Vector3D &v, CELL_LOC outloc) { Vector3D vcn = v; vcn.toContravariant(); - result = DDX(vcn.x.getCoordinates()->J * vcn.x, outloc); - result += DDY(vcn.y.getCoordinates()->J * vcn.y, outloc); - result += DDZ(vcn.z.getCoordinates()->J * vcn.z, outloc); + result = DDX(vcn.x.getCoordinates()->J * vcn.x, outloc, method); + result += DDY(vcn.y.getCoordinates()->J * vcn.y, outloc, method); + result += DDZ(vcn.z.getCoordinates()->J * vcn.z, outloc, method); result /= metric->J; return result; @@ -175,7 +177,8 @@ const Field3D Div(const Vector3D &v, CELL_LOC outloc) { * Divergence operators for flux methods **************************************************************************/ -const Field2D Div(const Vector2D &v, const Field2D &f, CELL_LOC outloc) { +const Field2D Div(const Vector2D& v, const Field2D& f, CELL_LOC outloc, + const std::string& method) { TRACE("Div( Vector2D, Field2D )"); SCOREP0(); if (outloc == CELL_DEFAULT) { @@ -193,21 +196,16 @@ const Field2D Div(const Vector2D &v, const Field2D &f, CELL_LOC outloc) { vcn.toContravariant(); Field2D result(localmesh); - result = FDDX(vcn.x.getCoordinates()->J * vcn.x, f, outloc); - result += FDDY(vcn.y.getCoordinates()->J * vcn.y, f, outloc); - result += FDDZ(vcn.z.getCoordinates()->J * vcn.z, f, outloc); + result = FDDX(vcn.x.getCoordinates()->J * vcn.x, f, outloc, method); + result += FDDY(vcn.y.getCoordinates()->J * vcn.y, f, outloc, method); + result += FDDZ(vcn.z.getCoordinates()->J * vcn.z, f, outloc, method); result /= metric->J; return result; } -const Field3D Div(const Vector3D &v, const Field3D &f, const std::string &method, - CELL_LOC outloc) { - TRACE("Div( Vector3D, Field3D)"); - return Div(v, f, outloc, method); -} - -const Field3D Div(const Vector3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method) { +const Field3D Div(const Vector3D& v, const Field3D& f, CELL_LOC outloc, + const std::string& method) { TRACE("Div( Vector3D, Field3D )"); if (outloc == CELL_DEFAULT) { @@ -232,11 +230,6 @@ const Field3D Div(const Vector3D &v, const Field3D &f, CELL_LOC outloc, const st return result; } -const Field3D Div(const Vector3D &v, const Field3D &f) { - TRACE("Div( Vector3D, Field3D)"); - return Div(v, f, CELL_DEFAULT, DIFF_DEFAULT); -} - /************************************************************************** * Curl operators **************************************************************************/ From 172f154ef6e3233eee477cfecbbd3b4b75a8af63 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 19 Jan 2019 19:41:25 +0000 Subject: [PATCH 0617/1783] Revert "Alternative test of Mesh::coords_map init, uses BoutInitialise()" This reverts commit 26035fb89fdc8038ceca53e20f3e252021379a70. The test 'test-coordinates-initialization2' added in the reverted commit is less strict than 'test-coordinates-initialization'. The stricter test now passes, so remove the less strict one. --- .../README.md | 7 ----- .../data/BOUT.inp | 9 ------ .../test-coordinates-initialization2/makefile | 6 ---- .../test-coordinates-initialization2/runtest | 7 ----- .../test-coordinates-initialization.cxx | 31 ------------------- 5 files changed, 60 deletions(-) delete mode 100644 tests/integrated/test-coordinates-initialization2/README.md delete mode 100644 tests/integrated/test-coordinates-initialization2/data/BOUT.inp delete mode 100644 tests/integrated/test-coordinates-initialization2/makefile delete mode 100755 tests/integrated/test-coordinates-initialization2/runtest delete mode 100644 tests/integrated/test-coordinates-initialization2/test-coordinates-initialization.cxx diff --git a/tests/integrated/test-coordinates-initialization2/README.md b/tests/integrated/test-coordinates-initialization2/README.md deleted file mode 100644 index 49300484eb..0000000000 --- a/tests/integrated/test-coordinates-initialization2/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Solving Staggered Fields Test -============================= - -This test checks that BOUT++ doesn't hang when trying to apply boundary -conditions on boundaries that exist only on certain processes. This version -uses BoutInitialise(). See https://github.com/boutproject/BOUT-dev/issues/1369 -for the original problem. diff --git a/tests/integrated/test-coordinates-initialization2/data/BOUT.inp b/tests/integrated/test-coordinates-initialization2/data/BOUT.inp deleted file mode 100644 index cb2c201586..0000000000 --- a/tests/integrated/test-coordinates-initialization2/data/BOUT.inp +++ /dev/null @@ -1,9 +0,0 @@ - -[mesh] -staggergrids = true -nx = 10 -ny = 2 -nz = 1 - -# include dx to be loaded, forces Coordinates constructor to communicate -dx = 1. diff --git a/tests/integrated/test-coordinates-initialization2/makefile b/tests/integrated/test-coordinates-initialization2/makefile deleted file mode 100644 index 805ac0e1da..0000000000 --- a/tests/integrated/test-coordinates-initialization2/makefile +++ /dev/null @@ -1,6 +0,0 @@ - -BOUT_TOP = ../../.. - -SOURCEC = test-coordinates-initialization.cxx - -include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-coordinates-initialization2/runtest b/tests/integrated/test-coordinates-initialization2/runtest deleted file mode 100755 index 94b589e2d4..0000000000 --- a/tests/integrated/test-coordinates-initialization2/runtest +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -e - -make -# Kill the test after 3 seconds, if it hasn't already exited -OMP_NUM_THREADS=1 mpirun -n 3 timeout 3s ./test-coordinates-initialization diff --git a/tests/integrated/test-coordinates-initialization2/test-coordinates-initialization.cxx b/tests/integrated/test-coordinates-initialization2/test-coordinates-initialization.cxx deleted file mode 100644 index 1c45dc7103..0000000000 --- a/tests/integrated/test-coordinates-initialization2/test-coordinates-initialization.cxx +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Test of initialization of Coordinates objects in Mesh::coords_map - */ - -#include "bout.hxx" -#include "optionsreader.hxx" - -int main(int argc, char** argv) { - - // Initialize BOUT++ - BoutInitialise(argc,argv); - - // Test CELL_CENTRE - Field3D f(0., mesh); - f.applyBoundary("neumann"); - - // Synchronise all processors - MPI_Barrier(BoutComm::get()); - - // Test CELL_YLOW - Field3D f_ylow(0., mesh); - f_ylow.setLocation(CELL_YLOW); - f_ylow.applyBoundary("neumann"); - - // Synchronise all processors - MPI_Barrier(BoutComm::get()); - - MPI_Finalize(); - - return 0; -} From 7391c5fd2208910cdb44ba019dd87ea61ff7117f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 21 Jan 2019 13:47:07 +0000 Subject: [PATCH 0618/1783] Revert "Initialize Coordinates objects in BoutMesh::load()" This reverts commit 77fc7cb2edb8d797d467b0481065253ac9b45e05. The reverted commit was a temporary bugfix, which has now been replaced. --- src/mesh/impls/bout/boutmesh.cxx | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 849206e347..a8db998fb5 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -842,21 +842,6 @@ int BoutMesh::load() { // Initialize default coordinates getCoordinates(); - // Initialize Coordinates at all locations, temporary fix for bug causing - // BOUT++ to hang - getCoordinates(CELL_CENTRE); - if (StaggerGrids) { - if (xstart >= 2) { - getCoordinates(CELL_XLOW); - } - if (ystart >= 2) { - getCoordinates(CELL_YLOW); - } - if (LocalNz > 3) { - getCoordinates(CELL_ZLOW); - } - } - output_info.write(_("\tdone\n")); return 0; From e828c2585a1e05b45d01e6989238509b52566913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Mon, 21 Jan 2019 14:44:15 +0000 Subject: [PATCH 0619/1783] Delp2 test requires fftw --- bin/bout-config.in | 1 + configure | 45 ++++++++++++++++------------- configure.ac | 1 + tests/integrated/test-delp2/runtest | 5 +++- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/bin/bout-config.in b/bin/bout-config.in index 0cc85012ce..96f6692144 100755 --- a/bin/bout-config.in +++ b/bin/bout-config.in @@ -40,6 +40,7 @@ has_mumps="@HAS_MUMPS@" has_arkode="@HAS_ARKODE@" has_openmp="@HAS_OPENMP@" has_nls="@HAS_NLS@" +has_fftw="@HAS_FFTW@" petsc_has_sundials="@PETSC_HAS_SUNDIALS@" diff --git a/configure b/configure index 47bb04ca98..622ff4f43c 100755 --- a/configure +++ b/configure @@ -622,7 +622,8 @@ ac_includes_default="\ #endif" gt_needs= -ac_subst_vars='HAS_NLS +ac_subst_vars='HAS_FFTW +HAS_NLS HAS_OPENMP SLEPC_ARCH SLEPC_DIR @@ -766,7 +767,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -879,7 +879,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1132,15 +1131,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1278,7 +1268,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1431,7 +1421,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -13366,16 +13355,21 @@ else /* end confdefs.h. */ #include -$gt_revision_test_code +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION extern int _nl_msg_cat_cntr; extern int *_nl_domain_bindings; +#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_domain_bindings) +#else +#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 +#endif +$gt_revision_test_code int main () { bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings +return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION ; return 0; @@ -14128,20 +14122,25 @@ else /* end confdefs.h. */ #include -$gt_revision_test_code +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); +#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) +#else +#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 +#endif +$gt_revision_test_code int main () { bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") +return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION ; return 0; @@ -14160,20 +14159,25 @@ rm -f core conftest.err conftest.$ac_objext \ /* end confdefs.h. */ #include -$gt_revision_test_code +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); +#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) +#else +#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 +#endif +$gt_revision_test_code int main () { bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") +return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION ; return 0; @@ -15758,6 +15762,7 @@ BOUT_INCLUDE_PATH=$PWD/include + ac_config_files="$ac_config_files bin/bout-config" diff --git a/configure.ac b/configure.ac index 7d787c0af4..1ae0ceb10b 100644 --- a/configure.ac +++ b/configure.ac @@ -1285,6 +1285,7 @@ AC_SUBST(SLEPC_DIR) AC_SUBST(SLEPC_ARCH) AC_SUBST(HAS_OPENMP) AC_SUBST(HAS_NLS) +AC_SUBST(HAS_FFTW) AC_CONFIG_FILES([bin/bout-config]) AC_OUTPUT diff --git a/tests/integrated/test-delp2/runtest b/tests/integrated/test-delp2/runtest index b5de4ba66a..6925b2f0c1 100755 --- a/tests/integrated/test-delp2/runtest +++ b/tests/integrated/test-delp2/runtest @@ -5,13 +5,16 @@ try: from builtins import str except: pass -tol = 1e-10 # Absolute tolerance + +#requires: fftw from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun from boutdata.collect import collect import numpy as np from sys import stdout, exit +tol = 1e-10 # Absolute tolerance + MPIRUN=getmpirun() print("Making Delp2 operator test") From b2974485751be219c2978eea1016aa6979f93ef7 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 22 Jan 2019 14:57:20 +0000 Subject: [PATCH 0620/1783] Fix assert in definition of FFT 2nd derivative --- include/bout/index_derivs.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index 6a4c2f5293..28b95f659e 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -760,7 +760,7 @@ public: template void standard(const T& var, T& result, REGION region) const { AUTO_TRACE(); - ASSERT2(meta.derivType == DERIV::Standard) + ASSERT2(meta.derivType == DERIV::StandardSecond); ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); ASSERT2(direction == DIRECTION::Z); // Only in Z for now ASSERT2(stagger == STAGGER::None); // Staggering not currently supported From c9f18472901e8e4509ab6a3f3709211afdb5c24d Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 22 Jan 2019 14:59:08 +0000 Subject: [PATCH 0621/1783] Comment out clang-format options that are not recognised Determined using clang-format-4.0 (clang++ version 4.0.0) --- .clang-format | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.clang-format b/.clang-format index 1cff2689ad..f8a08001e3 100644 --- a/.clang-format +++ b/.clang-format @@ -44,8 +44,8 @@ BreakBeforeBraces: Attach BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false # BreakConstructorInitializers: BeforeColon -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: true +#BreakAfterJavaFieldAnnotations: false +#BreakStringLiterals: true ColumnLimit: 90 CommentPragmas: '^ IWYU pragma:' # CompactNamespaces: false @@ -71,7 +71,7 @@ IncludeCategories: Priority: 4 - Regex: '.*' Priority: 1 -IncludeIsMainRegex: '(Test)?$' +#IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false # IndentPPDirectives: None IndentWidth: 2 @@ -95,7 +95,7 @@ ReflowComments: true SortIncludes: true # SortUsingDeclarations: true SpaceAfterCStyleCast: false -SpaceAfterTemplateKeyword: true +#SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false From dcb37af6b497b6817011f08906badf3deec6beef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Tue, 22 Jan 2019 18:20:25 +0000 Subject: [PATCH 0622/1783] Removed unused variable --- include/bout/generic_factory.hxx | 1 - 1 file changed, 1 deletion(-) diff --git a/include/bout/generic_factory.hxx b/include/bout/generic_factory.hxx index 47cb02e66f..5b70deeb05 100644 --- a/include/bout/generic_factory.hxx +++ b/include/bout/generic_factory.hxx @@ -60,7 +60,6 @@ public: return index->second(std::forward(args) ...); } // List available options in error - const char* const delim = "\n"; std::string available; auto available_list = listAvailable(); for (auto i : available_list) { From 1494402740f5d692ceebbc0a02a5f02c9e5c3b30 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 22 Jan 2019 19:39:09 +0000 Subject: [PATCH 0623/1783] Move googletest into externalpackages --- .gitmodules | 2 +- googletest => externalpackages/googletest | 0 manual/doxygen/Doxyfile | 2 +- manual/doxygen/Doxyfile_readthedocs | 2 +- tests/unit/makefile | 6 +++--- 5 files changed, 6 insertions(+), 6 deletions(-) rename googletest => externalpackages/googletest (100%) diff --git a/.gitmodules b/.gitmodules index 8cf8b5e334..e627b7449e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "googletest"] - path = googletest + path = externalpackages/googletest url = https://github.com/google/googletest.git diff --git a/googletest b/externalpackages/googletest similarity index 100% rename from googletest rename to externalpackages/googletest diff --git a/manual/doxygen/Doxyfile b/manual/doxygen/Doxyfile index 3271607d7a..83c7e36565 100644 --- a/manual/doxygen/Doxyfile +++ b/manual/doxygen/Doxyfile @@ -839,7 +839,7 @@ EXCLUDE = ../../examples \ ../../tools/ \ ../../manual/ \ ../../bin/ \ - ../../googletest/ \ + ../../externalpackages/googletest/ \ ../../tests/ # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or diff --git a/manual/doxygen/Doxyfile_readthedocs b/manual/doxygen/Doxyfile_readthedocs index 7f3dfd8a94..485fdd1304 100644 --- a/manual/doxygen/Doxyfile_readthedocs +++ b/manual/doxygen/Doxyfile_readthedocs @@ -789,7 +789,7 @@ EXCLUDE = ../../examples \ ../../tools/ \ ../../manual/ \ ../../bin/ \ - ../../googletest/ \ + ../../externalpackages/googletest/ \ ../../tests/ # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or diff --git a/tests/unit/makefile b/tests/unit/makefile index 447d55f95b..f55ba8fa78 100644 --- a/tests/unit/makefile +++ b/tests/unit/makefile @@ -6,8 +6,8 @@ BOUT_TOP = ../.. BOUT_TEST_DIR = . -GTEST_DIR = $(BOUT_TOP)/googletest/googletest -GMOCK_DIR = $(BOUT_TOP)/googletest/googlemock +GTEST_DIR = $(BOUT_TOP)/externalpackages/googletest/googletest +GMOCK_DIR = $(BOUT_TOP)/externalpackages/googletest/googlemock GTEST_SOURCES = $(GTEST_DIR)/src/gtest-all.cc @@ -31,7 +31,7 @@ include $(BOUT_TOP)/make.config LDFLAGS += -pthread # Existence of this file indicates that GTEST has been downloaded -GTEST_SENTINEL = $(BOUT_TOP)/googletest/README.md +GTEST_SENTINEL = $(BOUT_TOP)/externalpackages/googletest/README.md # House-keeping build targets. From 4a7537df6676f5fa0ae5c9b458f530c19b9b7203 Mon Sep 17 00:00:00 2001 From: Brendan Shanahan Date: Wed, 23 Jan 2019 08:32:16 +0100 Subject: [PATCH 0624/1783] Fix typo in petsc installation instructions * --download-f-blas-lapack=1 should be --download-fblas-lapack=1 --- manual/sphinx/user_docs/advanced_install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual/sphinx/user_docs/advanced_install.rst b/manual/sphinx/user_docs/advanced_install.rst index 6468f31d47..51ad8116ad 100644 --- a/manual/sphinx/user_docs/advanced_install.rst +++ b/manual/sphinx/user_docs/advanced_install.rst @@ -417,7 +417,7 @@ debugging. --download-mumps \ --download-scalapack \ --download-blacs \ - --download-f-blas-lapack=1 \ + --download-fblas-lapack=1 \ --download-parmetis \ --download-ptscotch \ --download-metis From 307e7f72a3d70510ac41bcdcfc7af39cfbef53c3 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 23 Jan 2019 10:55:59 +0000 Subject: [PATCH 0625/1783] Introduce GTEST_BASE to reduce duplication --- tests/unit/makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/unit/makefile b/tests/unit/makefile index f55ba8fa78..dc971e959c 100644 --- a/tests/unit/makefile +++ b/tests/unit/makefile @@ -6,8 +6,9 @@ BOUT_TOP = ../.. BOUT_TEST_DIR = . -GTEST_DIR = $(BOUT_TOP)/externalpackages/googletest/googletest -GMOCK_DIR = $(BOUT_TOP)/externalpackages/googletest/googlemock +GTEST_BASE = $(BOUT_TOP)/externalpackages/googletest +GTEST_DIR = $(GTEST_BASE)/googletest +GMOCK_DIR = $(GTEST_BASE)/googlemock GTEST_SOURCES = $(GTEST_DIR)/src/gtest-all.cc @@ -31,7 +32,7 @@ include $(BOUT_TOP)/make.config LDFLAGS += -pthread # Existence of this file indicates that GTEST has been downloaded -GTEST_SENTINEL = $(BOUT_TOP)/externalpackages/googletest/README.md +GTEST_SENTINEL = $(GTEST_BASE)/README.md # House-keeping build targets. From 72bbcd553cd133ae2766d4e54e9652eb1704d685 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Wed, 23 Jan 2019 11:06:14 +0000 Subject: [PATCH 0626/1783] Add some scorep documentation --- .../developer_docs/performance_profiling.rst | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 manual/sphinx/developer_docs/performance_profiling.rst diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst new file mode 100644 index 0000000000..fb9a2f06f1 --- /dev/null +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -0,0 +1,71 @@ +.. Use bash as the default language for syntax highlighting in this file +.. highlight:: console + +.. _sec-performanceprofiling: + +Performance profiling +===================== + +Analyzing code behaviour is vital for getting the best performance from BOUT++. +This is done by profiling the code, that is, building and running the code +using tools that report the time each processor spends in functions, on +communications, etc. + +This section describes how to compile and run BOUT++ using the +[Scorep](http://www.vi-hps.org/projects/score-p/)/ +[Scalasca](http://www.scalasca.org/) +tool chain. + +Scorep/Scalasca profiling +------------------------- + +Configure with ``--with-scorep`` to enable Scorep instrumentation, then build +as normal. This option can be combined with other options, but it is usually +desirable to profile the optimized code, configuring with the flags +``--enable-optimize=3 --enable-checks=0``. Build the code with ``make`` as +normal. + +When running the code, prepend the run command with ``scalasca -analyze``, e.g. +.. code-block:: bash + + $ scalasca -analyze mpirun -np 2 elm_pb + +The run then produces an "archive" containing profiling data in a directory +called ``scorep___sum``. To view the profiling +information with the cube viewer, do +.. code-block:: bash + + $ cube scorep___sum/profile.cubex + +Note that Scorep does not run if does so would produce an archive with the +same name as an existing archive. Therefore to rerun an executable on the same +number of processors, it is necessary to move or delete the first archive. + +.. _sec-machine-specific: + +Machine-specific installation +----------------------------- + +These are some configurations which have been found to work on +particular machines. + +Archer +~~~~~~ + +As of 23rd January 2019, the following configuration should work + +.. code-block:: bash + + $ module swap PrgEnv-cray PrgEnv-gnu + $ module load fftw + $ module load archer-netcdf/4.1.3 + $ module load scalasca + +Note that due to a bug in the ``CC`` compiler, it is necessary to modify +``make.config`` after configuration if profiling OpenMP-parallelized code: + +* add the flag ``-fopenmp`` to ``BOUT_FLAGS`` +* add the flag ``--thread=omp:ancestry`` as an argument to ``scorep`` in ``CXX`` + + + From 8dffd3c1d76bbab9ab9e8099d444be87ceb2c4b6 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 23 Jan 2019 11:29:52 +0000 Subject: [PATCH 0627/1783] Remove support for scipy/scientific netcdf libraries --- tools/pylib/boututils/datafile.py | 73 +++---------------------------- 1 file changed, 7 insertions(+), 66 deletions(-) diff --git a/tools/pylib/boututils/datafile.py b/tools/pylib/boututils/datafile.py index 093e7e19e6..5790f03bab 100644 --- a/tools/pylib/boututils/datafile.py +++ b/tools/pylib/boututils/datafile.py @@ -7,10 +7,6 @@ - ``h5py`` (for HDF5 files) - ``netCDF4`` (preferred NetCDF library) -- ``Scientific.IO.NetCDF`` -- ``scipy.io.netcdf``: - - old version (``create_dimension``, ``create_variable``) - - new version (``createDimension``, ``createVariable``) NOTE ---- @@ -36,31 +32,12 @@ from boututils.boutwarnings import alwayswarn from boututils.boutarray import BoutArray -# Record which library to use -library = None - try: from netCDF4 import Dataset - library = "netCDF4" has_netCDF = True except ImportError: - try: - from Scientific.IO.NetCDF import NetCDFFile as Dataset - from Scientific.N import Int, Float, Float32 - library = "Scientific" - has_netCDF = True - except ImportError: - try: - from scipy.io.netcdf import netcdf_file as Dataset - library = "scipy" - has_netCDF = True - if hasattr(Dataset, "create_dimension"): - # Monkey-patch old version - Dataset.createDimension = Dataset.create_dimension - Dataset.createVariable = Dataset.create_variable - except ImportError: - raise ImportError( - "DataFile: No supported NetCDF modules available") + raise ImportError( + "DataFile: No supported NetCDF modules available -- requires netCDF4") try: import h5py @@ -350,36 +327,15 @@ def attributes(self, varname): class DataFile_netCDF(DataFile): handle = None - # Print warning if netcdf is used without the netcdf library - if library != "netCDF4": - print("WARNING: netcdf4-python module not found") - print(" expect poor performance") - if library == "Scientific": - print(" => Using Scientific.IO.NetCDF instead") - elif library == "scipy": - print(" => Using scipy.io.netcdf instead") def open(self, filename, write=False, create=False, format='NETCDF3_CLASSIC'): if (not write) and (not create): - if library == "scipy": - self.handle = Dataset(filename, "r", mmap=False) - else: - self.handle = Dataset(filename, "r") + self.handle = Dataset(filename, "r") elif create: - if library == "Scientific": - self.handle = Dataset(filename, "w", - 'Created ' + time.ctime(time.time()) - + ' by ' + getpass.getuser()) - elif library == "scipy": - self.handle = Dataset(filename, "w") - else: - self.handle = Dataset(filename, "w", format=format) + self.handle = Dataset(filename, "w", format=format) else: - if library == "scipy": - raise Exception("scipy.io.netcdf doesn't support appending") - else: - self.handle = Dataset(filename, "a") + self.handle = Dataset(filename, "a") # Record if writing self.writeable = write or create @@ -446,12 +402,7 @@ def read(self, name, ranges=None, asBoutArray=True): "(got {}, expected {} or {})" .format(len(ranges), ndims, 2 * ndims)) - if library == "Scientific": - # Passing ranges to var[] doesn't seem to work - data = var[:] - data = data[ranges[:ndims]] - else: - data = var[ranges[:ndims]] + data = var[ranges[:ndims]] if asBoutArray: data = BoutArray(data, attributes=attributes) return data @@ -639,16 +590,7 @@ def find_dim(dim): dims = tuple(map(find_dim, dlist)) # Create the variable - if library == "Scientific": - if t == 'int' or t == ' Date: Wed, 23 Jan 2019 12:02:03 +0000 Subject: [PATCH 0628/1783] Add performance profiling to index --- manual/sphinx/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/manual/sphinx/index.rst b/manual/sphinx/index.rst index 1522f105bc..5261585193 100644 --- a/manual/sphinx/index.rst +++ b/manual/sphinx/index.rst @@ -90,6 +90,7 @@ The documentation is divided into the following sections: developer_docs/mesh developer_docs/file_io developer_docs/natural_language + developer_docs/performance_profiling api_reference From 4c95d4cbc85bcb89ecd889dbcfbffd3c5fbd83d9 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Wed, 23 Jan 2019 12:25:58 +0000 Subject: [PATCH 0629/1783] Small tweaks + Minor text edits + Fix hyperlinks + Fix code blocks --- .../sphinx/developer_docs/performance_profiling.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index fb9a2f06f1..06ef3ccdeb 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -8,13 +8,12 @@ Performance profiling Analyzing code behaviour is vital for getting the best performance from BOUT++. This is done by profiling the code, that is, building and running the code -using tools that report the time each processor spends in functions, on -communications, etc. +using tools that report the amount of time each processor spends in functions, +on communications, etc. This section describes how to compile and run BOUT++ using the -[Scorep](http://www.vi-hps.org/projects/score-p/)/ -[Scalasca](http://www.scalasca.org/) -tool chain. +`Scorep `_/ +`Scalasca `_ tool chain. Scorep/Scalasca profiling ------------------------- @@ -26,6 +25,7 @@ desirable to profile the optimized code, configuring with the flags normal. When running the code, prepend the run command with ``scalasca -analyze``, e.g. + .. code-block:: bash $ scalasca -analyze mpirun -np 2 elm_pb @@ -33,11 +33,12 @@ When running the code, prepend the run command with ``scalasca -analyze``, e.g. The run then produces an "archive" containing profiling data in a directory called ``scorep___sum``. To view the profiling information with the cube viewer, do + .. code-block:: bash $ cube scorep___sum/profile.cubex -Note that Scorep does not run if does so would produce an archive with the +Note that Scorep does not run if doing so would produce an archive with the same name as an existing archive. Therefore to rerun an executable on the same number of processors, it is necessary to move or delete the first archive. From 93e3e03abce2a21e3da683c91d69fe6687849c0e Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Wed, 23 Jan 2019 12:32:58 +0000 Subject: [PATCH 0630/1783] Fix spacing --- manual/sphinx/developer_docs/performance_profiling.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index 06ef3ccdeb..e6e4c61b2c 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -12,8 +12,8 @@ using tools that report the amount of time each processor spends in functions, on communications, etc. This section describes how to compile and run BOUT++ using the -`Scorep `_/ -`Scalasca `_ tool chain. +`Scorep `_/`Scalasca `_ +tool chain. Scorep/Scalasca profiling ------------------------- From 4214aa669879bccf7d87f437c931f6459645c780 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Wed, 23 Jan 2019 13:01:46 +0000 Subject: [PATCH 0631/1783] Add section on source instrumentation --- .../developer_docs/performance_profiling.rst | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index e6e4c61b2c..1575a774fb 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -18,6 +18,41 @@ tool chain. Scorep/Scalasca profiling ------------------------- +Instrumentation +~~~~~~~~~~~~~~~ + +Scorep automatically reports the time spend in MPI communications and OpenMP +loops. However, to obtain information on the time spent in specific functions, +it is necessary to instrument the source. The tools to do this are provided in +``scorepwrapper.hxx``. + +To include a function in Scorep's timing, include the scorep wrapper in the +source code + +.. code-block:: c++ + + #include + +and then write the macro ``SCOREP0()`` at the top of the function, e.g. + +.. code-block:: c++ + + int Field::getNx() const{ + SCOREP0(); + return getMesh()->LocalNx; + }; + +**Caution** Instrumenting a function makes it execute more slowly. This can +result in misleading profiling information, particularly if +fast-but-frequently-called functions are instrumented. Try to instrument +significant functions only. + +This warning notwithstanding, it is reasonable to expect sensibly-instrumented +code to run ~50% to 100% slower than the uninstrumented code. + +Configure and build +~~~~~~~~~~~~~~~~~~~ + Configure with ``--with-scorep`` to enable Scorep instrumentation, then build as normal. This option can be combined with other options, but it is usually desirable to profile the optimized code, configuring with the flags From d831f0ec2a9236d0ac69872ed7bf59a91157268e Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Wed, 23 Jan 2019 13:11:02 +0000 Subject: [PATCH 0632/1783] Tweaks to text --- manual/sphinx/developer_docs/performance_profiling.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index 1575a774fb..0cc0435708 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -23,8 +23,8 @@ Instrumentation Scorep automatically reports the time spend in MPI communications and OpenMP loops. However, to obtain information on the time spent in specific functions, -it is necessary to instrument the source. The tools to do this are provided in -``scorepwrapper.hxx``. +it is necessary to instrument the source code. The macros to do this are +provided in ``scorepwrapper.hxx``. To include a function in Scorep's timing, include the scorep wrapper in the source code @@ -47,8 +47,8 @@ result in misleading profiling information, particularly if fast-but-frequently-called functions are instrumented. Try to instrument significant functions only. -This warning notwithstanding, it is reasonable to expect sensibly-instrumented -code to run ~50% to 100% slower than the uninstrumented code. +This notwithstanding, it is reasonable to expect sensibly-instrumented code to +run about 50% to 100% slower than the uninstrumented code. Configure and build ~~~~~~~~~~~~~~~~~~~ From 36a296aca783b522239c653af2b10373dedddb38 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 24 Jan 2019 09:23:35 +0000 Subject: [PATCH 0633/1783] Use third order B.C. in MMS/advection/weno3 test case. With this change recover third order convergence --- tests/MMS/advection/data/BOUT.inp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/MMS/advection/data/BOUT.inp b/tests/MMS/advection/data/BOUT.inp index 2275970be5..6610ccc690 100644 --- a/tests/MMS/advection/data/BOUT.inp +++ b/tests/MMS/advection/data/BOUT.inp @@ -46,4 +46,4 @@ ddx = -1.27323954473516*x*sin(4.0*x^2 + 1.0*z) + 0.477464829275686*sin(t)*cos(3. source = -1.90985931710274*x*(2.0*sin(t)*cos(3.0*x + 2.0*z) - sin(4.0*x^2 + z))*cos(6.0*x^2 - z) - (-1.27323954473516*x*sin(4.0*x^2 + z) + 0.477464829275686*sin(t)*cos(3.0*x + 2.0*z))*cos(6.0*x^2 - 1.0*z) + sin(3.0*x + 2.0*z)*cos(t) -bndry_all = dirichlet_o2(f:solution) +bndry_all = dirichlet_o3(f:solution) From 1cbf1338879ad03e898305fa35a8ebc0f008b52e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 24 Jan 2019 09:55:36 +0000 Subject: [PATCH 0634/1783] Generalise Zoidberg to multiple parallel slices --- tools/pylib/zoidberg/zoidberg.py | 209 +++++++++++++++---------------- 1 file changed, 101 insertions(+), 108 deletions(-) diff --git a/tools/pylib/zoidberg/zoidberg.py b/tools/pylib/zoidberg/zoidberg.py index a7333d6762..e287132b5b 100644 --- a/tools/pylib/zoidberg/zoidberg.py +++ b/tools/pylib/zoidberg/zoidberg.py @@ -2,6 +2,11 @@ import numpy as np from boututils import datafile as bdata +from collections import namedtuple +from itertools import chain + +from . import fieldtracer +from .progress import update_progress # PyEVTK might be called pyevtk or evtk, depending on where it was # installed from @@ -14,13 +19,24 @@ except ImportError: have_evtk = False -# from . import grid -# from . import field -from . import fieldtracer -from .progress import update_progress + +def parallel_slice_field_name(field, offset): + """Form a unique, backwards-compatible name for field at a given offset + + Parameters + ---------- + field : str + Name of the field to convert + offset : int + Parallel slice offset + + """ + prefix = 'forward' if offset > 0 else 'backward' + suffix = "_{}".format(abs(offset)) if abs(offset) > 1 else "" + return "{}_{}{}".format(prefix, field, suffix) -def make_maps(grid, magnetic_field, quiet=False, **kwargs): +def make_maps(grid, magnetic_field, nslice=1, quiet=False, **kwargs): """Make the forward and backward FCI maps Parameters @@ -29,6 +45,8 @@ def make_maps(grid, magnetic_field, quiet=False, **kwargs): Grid generated by Zoidberg magnetic_field : :py:obj:`zoidberg.field.MagneticField` Zoidberg magnetic field object + nslice : int + Number of parallel slices in each direction quiet : bool Don't display progress bar kwargs @@ -51,110 +69,85 @@ def make_maps(grid, magnetic_field, quiet=False, **kwargs): shape = (nx, ny, nz) # Coordinates of each grid point - R = np.zeros( shape ) - Z = np.zeros( shape ) - - # Arrays to store X index at end of field-line - # starting from (x,y,z) and going forward in toroidal angle (y) - forward_xt_prime = np.zeros( shape ) - forward_zt_prime = np.zeros( shape ) - - forward_R = np.zeros( shape ) - forward_Z = np.zeros( shape ) - - # Same but going backwards in toroidal angle - backward_xt_prime = np.zeros( shape ) - backward_zt_prime = np.zeros( shape ) - - backward_R = np.zeros( shape ) - backward_Z = np.zeros( shape ) - - field_tracer = fieldtracer.FieldTracer(magnetic_field) + R = np.zeros(shape) + Z = np.zeros(shape) - try: - rtol = kwargs["rtol"] - except KeyError: - rtol = None - - # TODO: if axisymmetric, don't loop, do one slice and copy for j in range(ny): - if (not quiet) and (ny > 1): - update_progress(float(j)/float(ny-1), **kwargs) - - # Get this poloidal grid - pol, ycoord = grid.getPoloidalGrid(j) - - # Store coordinates - R[:,j,:] = pol.R - Z[:,j,:] = pol.Z - - # Get the next (forward) poloidal grid - pol_forward, y_forward = grid.getPoloidalGrid(j+1) - - # We only want the end point, as [0,...] is the initial position - coord = field_tracer.follow_field_lines(pol.R, pol.Z, [ycoord, y_forward], rtol=rtol)[1,...] - - # Store the coordinates in real space - forward_R[:,j,:] = coord[:,:,0] - forward_Z[:,j,:] = coord[:,:,1] - - # Get the indices into the forward poloidal grid - if pol_forward is None: - # No forward grid, so hit a boundary - xind = -1 - zind = -1 - else: - # Find the indices for these new locations on the forward poloidal grid - xcoord = coord[:,:,0] - zcoord = coord[:,:,1] - xind, zind = pol_forward.findIndex(xcoord, zcoord) - - # Check boundary defined by the field - outside = magnetic_field.boundary.outside(xcoord, y_forward, zcoord) - xind[outside] = -1 - zind[outside] = -1 - - forward_xt_prime[:,j,:] = xind - forward_zt_prime[:,j,:] = zind - - # Go backwards one poloidal grid - pol_back, y_back = grid.getPoloidalGrid(j-1) - - # We only want the end point, as [0,...] is the initial position - coord = field_tracer.follow_field_lines(pol.R, pol.Z, [ycoord, y_back], rtol=rtol)[1,...] - - # Store the coordinates in real space - backward_R[:,j,:] = coord[:,:,0] - backward_Z[:,j,:] = coord[:,:,1] - - if pol_back is None: - # Hit boundary - xind = -1 - zind = -1 - else: - # Find the indices for these new locations on the backward poloidal grid - xcoord = coord[:,:,0] - zcoord = coord[:,:,1] - xind, zind = pol_back.findIndex(xcoord, zcoord) - - # Check boundary defined by the field - outside = magnetic_field.boundary.outside(xcoord, y_back, zcoord) - xind[outside] = -1 - zind[outside] = -1 - - backward_xt_prime[:,j,:] = xind - backward_zt_prime[:,j,:] = zind + pol, _ = grid.getPoloidalGrid(j) + R[:, j, :] = pol.R + Z[:, j, :] = pol.Z + + field_tracer = fieldtracer.FieldTracer(magnetic_field) + + rtol = kwargs.get("rtol", None) + # The field line maps and coordinates, etc. maps = { - 'R' : R, 'Z':Z, - 'forward_R':forward_R, 'forward_Z':forward_Z, - 'forward_xt_prime' : forward_xt_prime, - 'forward_zt_prime' : forward_zt_prime, - 'backward_R':backward_R, 'backward_Z':backward_Z, - 'backward_xt_prime' : backward_xt_prime, - 'backward_zt_prime' : backward_zt_prime + 'R': R, + 'Z': Z, } + # A helper data structure that groups the various field line maps along with the offset + ParallelSlice = namedtuple('ParallelSlice', ['R', 'Z', 'xt_prime', 'zt_prime', 'offset']) + # A list of the above data structures for each offset we want + parallel_slices = [] + + # Loop over offsets {1, ... nslice, -1, ... -nslice} + for offset in chain(range(1, nslice + 1), range(-1, -(nslice + 1), -1)): + # Unique names of the field line maps for this offset + field_names = [parallel_slice_field_name(field, offset) + for field in ['R', 'Z', 'xt_prime', 'zt_prime']] + + # Initialise the field arrays -- puts them straight into the result dict + for field in field_names: + maps[field] = np.zeros(shape) + + # Get the field arrays we just made and wrap them up in our helper tuple + fields = map(lambda x: maps[x], field_names) + parallel_slices.append(ParallelSlice(*fields, offset)) + + # Total size of the progress bar + total_work = float((len(parallel_slices) - 1) * (ny-1)) + + # TODO: if axisymmetric, don't loop, do one slice and copy + # TODO: restart tracing for adjacent offsets + for slice_index, parallel_slice in enumerate(parallel_slices): + for j in range(ny): + if (not quiet) and (ny > 1): + update_progress(float(slice_index * j) / total_work, **kwargs) + + # Get this poloidal grid + pol, ycoord = grid.getPoloidalGrid(j) + + # Get the next poloidal grid + pol_slice, y_slice = grid.getPoloidalGrid(j + parallel_slice.offset) + + # We only want the end point, as [0,...] is the initial position + coord = field_tracer.follow_field_lines(pol.R, pol.Z, [ycoord, y_slice], rtol=rtol)[1, ...] + + # Store the coordinates in real space + parallel_slice.R[:, j, :] = coord[:, :, 0] + parallel_slice.Z[:, j, :] = coord[:, :, 1] + + # Get the indices into the slice poloidal grid + if pol_slice is None: + # No slice grid, so hit a boundary + xind = -1 + zind = -1 + else: + # Find the indices for these new locations on the slice poloidal grid + xcoord = coord[:, :, 0] + zcoord = coord[:, :, 1] + xind, zind = pol_slice.findIndex(xcoord, zcoord) + + # Check boundary defined by the field + outside = magnetic_field.boundary.outside(xcoord, y_slice, zcoord) + xind[outside] = -1 + zind[outside] = -1 + + parallel_slice.xt_prime[:, j, :] = xind + parallel_slice.zt_prime[:, j, :] = zind + return maps @@ -203,7 +196,7 @@ def write_maps(grid, magnetic_field, maps, gridfile='fci.grid.nc', Rmaj[:,yindex,:] = magnetic_field.Rfunc(pol_grid.R, pol_grid.Z, ypos) metric["gyy"] = 1./Rmaj**2 metric["g_yy"] = Rmaj**2 - + # Get magnetic field and pressure Bmag = np.zeros(grid.shape) pressure = np.zeros(grid.shape) @@ -220,7 +213,7 @@ def write_maps(grid, magnetic_field, maps, gridfile='fci.grid.nc', pol_grid, ypos = grid.getPoloidalGrid(yindex) attribute[:,yindex,:] = magnetic_field.attributes[name](pol_grid.R, pol_grid.Z, ypos) attributes[name] = attribute - + # Metric is now 3D if metric2d: # Remove the Z dimension from metric components @@ -250,7 +243,7 @@ def write_maps(grid, magnetic_field, maps, gridfile='fci.grid.nc', f.write("ixseps2",ixseps) # Metric tensor - + if new_names: for key, val in metric.items(): f.write(key, val) @@ -271,7 +264,7 @@ def write_maps(grid, magnetic_field, maps, gridfile='fci.grid.nc', if name in name_changes: name = name_changes[name] f.write(name, metric[key]) - + # Magnetic field f.write("B", Bmag) @@ -281,7 +274,7 @@ def write_maps(grid, magnetic_field, maps, gridfile='fci.grid.nc', # Attributes for name in attributes: f.write(name, attributes[name]) - + # Maps - write everything to file for key in maps: f.write(key, maps[key]) From 1e0a6148a2356f19f281aba3b64e55287caf5c95 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 24 Jan 2019 14:35:33 +0000 Subject: [PATCH 0635/1783] Remove unneeded yup/ydown phase caches from ShiftedMetric --- include/bout/paralleltransform.hxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 5ed14cd4f2..c7b6ebf7d8 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -151,9 +151,6 @@ private: /// where i goes from 0 to (n-1), with n the number of y guard cells std::vector parallel_slice_phases; - arr3Dvec yupPhs; ///< Cache of phase shifts for calculating yup fields - arr3Dvec ydownPhs; ///< Cache of phase shifts for calculating ydown fields - /*! * Shift a 2D field in Z. * Since 2D fields are constant in Z, this has no effect From 497838772abfe4373f9232e1a89ca7de44f18f14 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 24 Jan 2019 16:46:10 +0000 Subject: [PATCH 0636/1783] Generalise Zoidberg test to multiple parallel slices --- tools/pylib/zoidberg/test_zoidberg.py | 67 +++++++++++++-------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/tools/pylib/zoidberg/test_zoidberg.py b/tools/pylib/zoidberg/test_zoidberg.py index d82c30f0e2..23117c8dad 100644 --- a/tools/pylib/zoidberg/test_zoidberg.py +++ b/tools/pylib/zoidberg/test_zoidberg.py @@ -1,69 +1,68 @@ - +from itertools import chain, product import numpy as np from . import zoidberg, grid, field + def test_make_maps_slab(): nx = 5 - ny = 6 + ny = 8 nz = 7 # Create a straight magnetic field in a slab straight_field = field.Slab(By=1.0, Bz=0.0, Bzprime=0.0) - + # Create a rectangular grid in (x,y,z) - rectangle = grid.rectangular_grid(nx,ny,nz) + rectangle = grid.rectangular_grid(nx, ny, nz) + + # Two parallel slices in each direction + nslice = 2 # Calculate forwards and backwards maps - maps = zoidberg.make_maps(rectangle, straight_field) - - # Check that maps has the required forward and backward index variables - for var in ['forward_xt_prime', 'forward_zt_prime', 'backward_xt_prime', 'backward_zt_prime']: - assert var in maps + maps = zoidberg.make_maps(rectangle, straight_field, nslice=nslice) - # Each map should have the same shape as the grid - assert maps['forward_xt_prime'].shape == (nx,ny,nz) - assert maps['backward_xt_prime'].shape == (nx,ny,nz) - assert maps['forward_zt_prime'].shape == (nx,ny,nz) - assert maps['backward_zt_prime'].shape == (nx,ny,nz) - - # Since this is a straight magnetic field in a simple rectangle, + # Since this is a straight magnetic field in a simple rectangle, # all the maps should be the same, and should be the identity - identity_map_x, identity_map_z = np.meshgrid(np.arange(nx), np.arange(nz), indexing='ij') - for y in range(ny-1): - assert np.allclose(maps['forward_xt_prime'][:,y,:], identity_map_x) - assert np.allclose(maps['forward_zt_prime'][:,y,:], identity_map_z) + # Check that maps has the required forward and backward index variables + offsets = chain(range(1, nslice + 1), range(-1, -(nslice + 1), -1)) + field_line_maps = ["xt_prime", "zt_prime"] + + for field_line_map, offset in product(field_line_maps, offsets): + var = zoidberg.parallel_slice_field_name(field_line_map, offset) + print("Current field: ", var) + assert var in maps + + # Each map should have the same shape as the grid + maps[var].shape == (nx, ny, nz) - for y in range(1,ny): - assert np.allclose(maps['backward_xt_prime'][:,y,:], identity_map_x) - assert np.allclose(maps['backward_zt_prime'][:,y,:], identity_map_z) + # The first/last abs(offset) points are not valid, so ignore those + interior_range = range(ny-abs(offset)) if offset > 0 else range(abs(offset), ny) + # Those invalid points should be set to -1 + end_slice = slice(-1, -(offset + 1), -1) if offset > 0 else slice(0, -offset) + identity_map = identity_map_x if "x" in var else identity_map_z - # The last forward map should hit a boundary - assert np.allclose(maps['forward_xt_prime'][:,-1,:], -1.0) - assert np.allclose(maps['forward_zt_prime'][:,-1,:], -1.0) + for y in interior_range: + assert np.allclose(maps[var][:, y, :], identity_map) - # First backward map hits boundary - assert np.allclose(maps['backward_xt_prime'][:,0,:], -1.0) - assert np.allclose(maps['backward_zt_prime'][:,0,:], -1.0) + # The end slice should hit a boundary + assert np.allclose(maps[var][:, end_slice, :], -1.0) def test_make_maps_straight_stellarator(): nx = 5 ny = 6 nz = 7 - + # Create magnetic field magnetic_field = field.StraightStellarator(radius = np.sqrt(2.0)) - + # Create a rectangular grid in (x,y,z) rectangle = grid.rectangular_grid(nx,ny,nz, Lx = 1.0, Lz = 1.0, Ly = 10.0, yperiodic = True) - + # Here both the field and and grid are centred at (x,z) = (0,0) # and the rectangular grid here fits entirely within the coils maps = zoidberg.make_maps(rectangle, magnetic_field) - - From a3fb69f4f7c3c927225c5af0cdae527eb28785c8 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 24 Jan 2019 20:04:58 +0000 Subject: [PATCH 0637/1783] Ensure we use fourth order derivatives for central schemes --- tests/MMS/advection/data/BOUT.inp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/MMS/advection/data/BOUT.inp b/tests/MMS/advection/data/BOUT.inp index 6610ccc690..82d7ae1d9e 100644 --- a/tests/MMS/advection/data/BOUT.inp +++ b/tests/MMS/advection/data/BOUT.inp @@ -18,9 +18,17 @@ symmetricGlobalX = true ny = 1 [mesh:ddx] +first = C4 +second = C4 upwind=c2 +[mesh:ddy] +first = C4 +second = C4 + [mesh:ddz] +first = C4 +second = C4 upwind=c2 [solver] From 68618ada16e5b0ccc5127df3797fd73ace9f4dc0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 25 Jan 2019 10:12:24 +0000 Subject: [PATCH 0638/1783] Use static_cast instead of dynamic_cast went casting Mesh* to FakeMesh* in unit tests. --- tests/unit/field/test_vector2d.cxx | 4 ++-- tests/unit/field/test_vector3d.cxx | 4 ++-- tests/unit/mesh/parallel/test_shiftedmetric.cxx | 2 +- tests/unit/mesh/test_interpolation.cxx | 6 +++--- tests/unit/test_extras.hxx | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index 71cbb63105..09388f0338 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -36,7 +36,7 @@ class Vector2DTest : public ::testing::Test { mesh->addBoundary(new BoundaryRegionYUp("upper_target", 1, nx - 2, mesh)); mesh->addBoundary(new BoundaryRegionYDown("lower_target", 1, nx - 2, mesh)); - dynamic_cast(mesh)->setCoordinates(std::make_shared( + static_cast(mesh)->setCoordinates(std::make_shared( mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, @@ -49,7 +49,7 @@ class Vector2DTest : public ::testing::Test { mesh_staggered = new FakeMesh(nx, ny, nz); mesh_staggered->StaggerGrids = true; output_info.disable(); - dynamic_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); + static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); mesh_staggered->createDefaultRegions(); } diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index 1ffc4cc634..6eaf9738ac 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -35,7 +35,7 @@ class Vector3DTest : public ::testing::Test { mesh->addBoundary(new BoundaryRegionYUp("upper_target", 1, nx - 2, mesh)); mesh->addBoundary(new BoundaryRegionYDown("lower_target", 1, nx - 2, mesh)); - dynamic_cast(mesh)->setCoordinates(std::make_shared( + static_cast(mesh)->setCoordinates(std::make_shared( mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, @@ -48,7 +48,7 @@ class Vector3DTest : public ::testing::Test { mesh_staggered = new FakeMesh(nx, ny, nz); mesh_staggered->StaggerGrids = true; output_info.disable(); - dynamic_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); + static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); mesh_staggered->createDefaultRegions(); } diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 4d8c2885a7..d3c50a3233 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -22,7 +22,7 @@ class ShiftedMetricTest : public ::testing::Test { fillField(zShift, {{1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}, {1., 2., 3., 4., 5.}}); - dynamic_cast(mesh)->setCoordinates(std::make_shared( + static_cast(mesh)->setCoordinates(std::make_shared( mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index bf5bcac1b3..3474211fb3 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -54,9 +54,9 @@ class Field3DInterpToTest : public ::testing::Test { mesh->ystart = 2; mesh->xend = nx - 3; mesh->yend = ny - 3; - dynamic_cast(mesh)->setCoordinates(nullptr, CELL_XLOW); - dynamic_cast(mesh)->setCoordinates(nullptr, CELL_YLOW); - dynamic_cast(mesh)->setCoordinates(nullptr, CELL_ZLOW); + static_cast(mesh)->setCoordinates(nullptr, CELL_XLOW); + static_cast(mesh)->setCoordinates(nullptr, CELL_YLOW); + static_cast(mesh)->setCoordinates(nullptr, CELL_ZLOW); mesh->setParallelTransform(bout::utils::make_unique()); output_info.disable(); mesh->createDefaultRegions(); diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index b16b2cd620..8954c7afc7 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -207,7 +207,7 @@ public: mesh_staggered = new FakeMesh(nx, ny, nz); mesh_staggered->StaggerGrids = true; output_info.disable(); - dynamic_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); + static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); mesh_staggered->createDefaultRegions(); output_info.enable(); } From 7140ac070763a7e47da0fb35911c80393a684778 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 25 Jan 2019 11:44:09 +0000 Subject: [PATCH 0639/1783] Write job execution information to dump file --- include/bout/run_metrics.hxx | 65 ++++++++++++++++++++++++++++++++++++ src/bout++.cxx | 59 ++++++++++++-------------------- src/sys/makefile | 2 +- src/sys/run_metrics.cxx | 63 ++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 38 deletions(-) create mode 100644 include/bout/run_metrics.hxx create mode 100644 src/sys/run_metrics.cxx diff --git a/include/bout/run_metrics.hxx b/include/bout/run_metrics.hxx new file mode 100644 index 0000000000..a3659b776a --- /dev/null +++ b/include/bout/run_metrics.hxx @@ -0,0 +1,65 @@ +/************************************************************************** + * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu + * + * Run Metrics class by J. T. Parker 2019 + * + * Contact: Ben Dudson, bd512@york.ac.uk + * + * This file is part of BOUT++. + * + * BOUT++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BOUT++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with BOUT++. If not, see . + * + **************************************************************************/ + +/// Run Metrics class +/// +/// The `Run Metrics` class holds non-physics information about the job execution, +/// such as wall clock times and number of iterations. + +class RunMetrics; + +#ifndef __RUNMETRICS_H__ +#define __RUNMETRICS_H__ + +#include "datafile.hxx" + + +class RunMetrics { + public: + BoutReal simtime; // cumulative simulation time + BoutReal t_elapsed; // cumulative wall clock time in seconds + BoutReal wtime; // time step's wall clock time in seconds + + int ncalls; // number of RHS calls + int ncalls_e; // number of RHS calls for fast timescale + int ncalls_i; // number of RHS calls for slow timescale + + BoutReal wtime_rhs; // wall time spent calculating RHS + BoutReal wtime_invert; // wall time spent inverting Laplacian + BoutReal wtime_comms; // wall time spent communicating (part of RHS) + BoutReal wtime_io; // wall time spent on I/O + + /*! + * Adds variables to the output file, for post-processing + */ + void outputVars(Datafile &file); + + /*! + * Write job progress to screen + */ + void writeProgress(bool output_split); + +}; + +#endif // __RUNMETRICS_H__ diff --git a/src/bout++.cxx b/src/bout++.cxx index 6e4ef0b5cd..93b7ec536c 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -52,6 +52,7 @@ const char DEFAULT_LOG[] = "BOUT.log"; #include #include +#include #include @@ -83,7 +84,7 @@ void bout_signal_handler(int sig); // Handles signals #include -BoutReal simtime; +RunMetrics run_data; int iteration; bool user_requested_exit=false; @@ -504,7 +505,7 @@ int BoutInitialise(int &argc, char **&argv) { /// Add book-keeping variables to the output files dump.add(const_cast(BOUT_VERSION), "BOUT_VERSION", false); - dump.add(simtime, "t_array", true); // Appends the time of dumps into an array + run_data.outputVars(dump); // Add wall clock time etc to dump file dump.add(iteration, "iteration", false); //////////////////////////////////////////// @@ -617,23 +618,20 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { // Set the global variables. This is done because they need to be // written to the output file before the first step (initial condition) - simtime = t; + run_data.simtime = t; iteration = iter; - /// Write dump file - dump.write(); - /// Collect timing information - BoutReal wtime = Timer::resetTime("run"); - int ncalls = solver->resetRHSCounter(); - int ncalls_e = solver->resetRHSCounter_e(); - int ncalls_i = solver->resetRHSCounter_i(); + run_data.wtime = Timer::resetTime("run"); + run_data.ncalls = solver->resetRHSCounter(); + run_data.ncalls_e = solver->resetRHSCounter_e(); + run_data.ncalls_i = solver->resetRHSCounter_i(); bool output_split = solver->splitOperator(); - BoutReal wtime_rhs = Timer::resetTime("rhs"); - BoutReal wtime_invert = Timer::resetTime("invert"); - BoutReal wtime_comms = Timer::resetTime("comms"); // Time spent communicating (part of RHS) - BoutReal wtime_io = Timer::resetTime("io"); // Time spend on I/O + run_data.wtime_rhs = Timer::resetTime("rhs"); + run_data.wtime_invert = Timer::resetTime("invert"); + run_data.wtime_comms = Timer::resetTime("comms"); // Time spent communicating (part of RHS) + run_data.wtime_io = Timer::resetTime("io"); // Time spend on I/O output_progress.print("\r"); // Only goes to screen @@ -656,7 +654,7 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { } /// Record the starting time - mpi_start_time = MPI_Wtime() - wtime; + mpi_start_time = MPI_Wtime() - run_data.wtime; first_time = false; @@ -670,36 +668,23 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { } } - if (!output_split) { - output_progress.write("%.3e %5d %.2e %5.1f %5.1f %5.1f %5.1f %5.1f\n", - simtime, ncalls, wtime, - 100.0*(wtime_rhs - wtime_comms - wtime_invert)/wtime, - 100.*wtime_invert/wtime, // Inversions - 100.0*wtime_comms/wtime, // Communications - 100.* wtime_io / wtime, // I/O - 100.*(wtime - wtime_io - wtime_rhs)/wtime); // Everything else - - } else { - output_progress.write("%.3e %5d %5d %.2e %5.1f %5.1f %5.1f %5.1f %5.1f\n", - simtime, ncalls_e, ncalls_i, wtime, - 100.0*(wtime_rhs - wtime_comms - wtime_invert)/wtime, - 100.*wtime_invert/wtime, // Inversions - 100.0*wtime_comms/wtime, // Communications - 100.* wtime_io / wtime, // I/O - 100.*(wtime - wtime_io - wtime_rhs)/wtime); // Everything else - } + run_data.writeProgress(output_split); // This bit only to screen, not log file - BoutReal t_elapsed = MPI_Wtime() - mpi_start_time; - output_progress.print("%c Step %d of %d. Elapsed %s", get_spin(), iteration+1, NOUT, (time_to_hms(t_elapsed)).c_str()); - output_progress.print(" ETA %s", (time_to_hms(wtime * static_cast(NOUT - iteration - 1))).c_str()); + run_data.t_elapsed = MPI_Wtime() - mpi_start_time; + + output_progress.print("%c Step %d of %d. Elapsed %s", get_spin(), iteration+1, NOUT, (time_to_hms(run_data.t_elapsed)).c_str()); + output_progress.print(" ETA %s", (time_to_hms(run_data.wtime * static_cast(NOUT - iteration - 1))).c_str()); + + /// Write dump file + dump.write(); if (wall_limit > 0.0) { // Check if enough time left BoutReal t_remain = mpi_start_time + wall_limit - MPI_Wtime(); - if (t_remain < wtime) { + if (t_remain < run_data.wtime) { // Less than 1 time-step left output_warn.write(_("Only %e seconds left. Quitting\n"), t_remain); diff --git a/src/sys/makefile b/src/sys/makefile index 061d15da47..ecfbe9bb4b 100644 --- a/src/sys/makefile +++ b/src/sys/makefile @@ -5,7 +5,7 @@ SOURCEC = bout_types.cxx boutexception.cxx derivs.cxx \ msg_stack.cxx options.cxx output.cxx \ utils.cxx optionsreader.cxx boutcomm.cxx \ timer.cxx range.cxx petsclib.cxx expressionparser.cxx \ - slepclib.cxx + slepclib.cxx run_metrics.cxx SOURCEH = $(SOURCEC:%.cxx=%.hxx) globals.hxx bout_types.hxx multiostream.hxx TARGET = lib diff --git a/src/sys/run_metrics.cxx b/src/sys/run_metrics.cxx new file mode 100644 index 0000000000..168f29e92c --- /dev/null +++ b/src/sys/run_metrics.cxx @@ -0,0 +1,63 @@ +/*!************************************************************************ + * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu + * + * Contact Ben Dudson, bd512@york.ac.uk + * + * This file is part of BOUT++. + * + * BOUT++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BOUT++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with BOUT++. If not, see . + * + *********************************************************/ + +#include +#include +#include + +/*! + * Adds variables to the output file, for post-processing + */ +void RunMetrics::outputVars(Datafile &file) { + file.add(simtime, "t_array", true); + file.add(t_elapsed, "wall_time", true); + file.add(wtime, "wtime", true); + file.add(ncalls, "ncalls", true); + file.add(ncalls_e, "ncalls_e", true); + file.add(ncalls_i, "ncalls_i", true); + file.add(wtime_rhs, "wtime_rhs", true); + file.add(wtime_invert, "wtime_invert", true); + file.add(wtime_comms, "wtime_comms", true); + file.add(wtime_io, "wtime_io", true); +} + +void RunMetrics::writeProgress(bool output_split) { + + if (!output_split) { + output_progress.write("%.3e %5d %.2e %5.1f %5.1f %5.1f %5.1f %5.1f\n", + simtime, ncalls, wtime, + 100.0*(wtime_rhs - wtime_comms - wtime_invert)/wtime, + 100.*wtime_invert/wtime, // Inversions + 100.0*wtime_comms/wtime, // Communications + 100.* wtime_io / wtime, // I/O + 100.*(wtime - wtime_io - wtime_rhs)/wtime); // Everything else + + } else { + output_progress.write("%.3e %5d %5d %.2e %5.1f %5.1f %5.1f %5.1f %5.1f\n", + simtime, ncalls_e, ncalls_i, wtime, + 100.0*(wtime_rhs - wtime_comms - wtime_invert)/wtime, + 100.*wtime_invert/wtime, // Inversions + 100.0*wtime_comms/wtime, // Communications + 100.* wtime_io / wtime, // I/O + 100.*(wtime - wtime_io - wtime_rhs)/wtime); // Everything else + } +} From c5958d330dd84131ffb61fb431ae2fd10534af3c Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 25 Jan 2019 12:48:04 +0000 Subject: [PATCH 0640/1783] Doxygen-ify the comments. --- include/bout/run_metrics.hxx | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/include/bout/run_metrics.hxx b/include/bout/run_metrics.hxx index a3659b776a..b0a3e3fe2b 100644 --- a/include/bout/run_metrics.hxx +++ b/include/bout/run_metrics.hxx @@ -37,18 +37,28 @@ class RunMetrics; class RunMetrics { public: - BoutReal simtime; // cumulative simulation time - BoutReal t_elapsed; // cumulative wall clock time in seconds - BoutReal wtime; // time step's wall clock time in seconds + /// cumulative simulation time + BoutReal simtime; + /// cumulative wall clock time in seconds + BoutReal t_elapsed; + /// time step's wall clock time in seconds + BoutReal wtime; - int ncalls; // number of RHS calls - int ncalls_e; // number of RHS calls for fast timescale - int ncalls_i; // number of RHS calls for slow timescale + /// number of RHS calls + int ncalls; + /// number of RHS calls for fast timescale + int ncalls_e; + /// number of RHS calls for slow timescale + int ncalls_i; - BoutReal wtime_rhs; // wall time spent calculating RHS - BoutReal wtime_invert; // wall time spent inverting Laplacian - BoutReal wtime_comms; // wall time spent communicating (part of RHS) - BoutReal wtime_io; // wall time spent on I/O + /// wall time spent calculating RHS + BoutReal wtime_rhs; + /// wall time spent inverting Laplacian + BoutReal wtime_invert; + /// wall time spent communicating (part of RHS) + BoutReal wtime_comms; + /// wall time spent on I/O + BoutReal wtime_io; /*! * Adds variables to the output file, for post-processing From a5a7872932d099225837cfdca28d074f22451c7e Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 25 Jan 2019 13:32:30 +0000 Subject: [PATCH 0641/1783] Remove forward declaration of RunMetrics --- include/bout/run_metrics.hxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/bout/run_metrics.hxx b/include/bout/run_metrics.hxx index b0a3e3fe2b..f22215673b 100644 --- a/include/bout/run_metrics.hxx +++ b/include/bout/run_metrics.hxx @@ -27,8 +27,6 @@ /// The `Run Metrics` class holds non-physics information about the job execution, /// such as wall clock times and number of iterations. -class RunMetrics; - #ifndef __RUNMETRICS_H__ #define __RUNMETRICS_H__ From e74e77256bec942c428fe1a49b2e3ae27811e3af Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 25 Jan 2019 13:59:34 +0000 Subject: [PATCH 0642/1783] Revert simtime to being a global variable (used in petsc and slepc) --- include/bout/run_metrics.hxx | 4 +--- src/bout++.cxx | 6 ++++-- src/sys/run_metrics.cxx | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/bout/run_metrics.hxx b/include/bout/run_metrics.hxx index f22215673b..d9ecb377d3 100644 --- a/include/bout/run_metrics.hxx +++ b/include/bout/run_metrics.hxx @@ -35,8 +35,6 @@ class RunMetrics { public: - /// cumulative simulation time - BoutReal simtime; /// cumulative wall clock time in seconds BoutReal t_elapsed; /// time step's wall clock time in seconds @@ -66,7 +64,7 @@ class RunMetrics { /*! * Write job progress to screen */ - void writeProgress(bool output_split); + void writeProgress(BoutReal simtime, bool output_split); }; diff --git a/src/bout++.cxx b/src/bout++.cxx index 93b7ec536c..669f141b19 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -84,6 +84,7 @@ void bout_signal_handler(int sig); // Handles signals #include +BoutReal simtime; RunMetrics run_data; int iteration; bool user_requested_exit=false; @@ -505,6 +506,7 @@ int BoutInitialise(int &argc, char **&argv) { /// Add book-keeping variables to the output files dump.add(const_cast(BOUT_VERSION), "BOUT_VERSION", false); + dump.add(simtime, "t_array", true); // Appends the time of dumps into an array run_data.outputVars(dump); // Add wall clock time etc to dump file dump.add(iteration, "iteration", false); @@ -618,7 +620,7 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { // Set the global variables. This is done because they need to be // written to the output file before the first step (initial condition) - run_data.simtime = t; + simtime = t; iteration = iter; /// Collect timing information @@ -668,7 +670,7 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { } } - run_data.writeProgress(output_split); + run_data.writeProgress(simtime, output_split); // This bit only to screen, not log file diff --git a/src/sys/run_metrics.cxx b/src/sys/run_metrics.cxx index 168f29e92c..84b9f436d5 100644 --- a/src/sys/run_metrics.cxx +++ b/src/sys/run_metrics.cxx @@ -28,7 +28,6 @@ * Adds variables to the output file, for post-processing */ void RunMetrics::outputVars(Datafile &file) { - file.add(simtime, "t_array", true); file.add(t_elapsed, "wall_time", true); file.add(wtime, "wtime", true); file.add(ncalls, "ncalls", true); @@ -40,7 +39,7 @@ void RunMetrics::outputVars(Datafile &file) { file.add(wtime_io, "wtime_io", true); } -void RunMetrics::writeProgress(bool output_split) { +void RunMetrics::writeProgress(BoutReal simtime, bool output_split) { if (!output_split) { output_progress.write("%.3e %5d %.2e %5.1f %5.1f %5.1f %5.1f %5.1f\n", From af2ca9b1e78c83f35fd5bc79fa9db16e56c4ad4c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 25 Jan 2019 14:04:53 +0000 Subject: [PATCH 0643/1783] Add proper scaling test for FCI with C2 and C4 --- tests/MMS/.gitignore | 3 + tests/MMS/spatial/fci/data/BOUT.inp | 23 ++++ tests/MMS/spatial/fci/fci_mms.cxx | 28 +++++ tests/MMS/spatial/fci/makefile | 6 + tests/MMS/spatial/fci/mms.py | 35 ++++++ tests/MMS/spatial/fci/runtest | 176 ++++++++++++++++++++++++++++ tools/pylib/zoidberg/zoidberg.py | 54 +++++---- 7 files changed, 300 insertions(+), 25 deletions(-) create mode 100644 tests/MMS/spatial/fci/data/BOUT.inp create mode 100644 tests/MMS/spatial/fci/fci_mms.cxx create mode 100644 tests/MMS/spatial/fci/makefile create mode 100755 tests/MMS/spatial/fci/mms.py create mode 100755 tests/MMS/spatial/fci/runtest diff --git a/tests/MMS/.gitignore b/tests/MMS/.gitignore index 2946406b9b..c8f94147b3 100644 --- a/tests/MMS/.gitignore +++ b/tests/MMS/.gitignore @@ -30,6 +30,9 @@ BOUT.settings /spatial/d2dx2/test_d2dx2 /spatial/d2dz2/test_d2dz2 /spatial/diffusion/diffusion +/spatial/fci/fci_mms +/spatial/fci/fci.grid.nc +/spatial/fci/fci_mms.pkl /time/time /tokamak/tokamak /tokamak/tokamak.pkl diff --git a/tests/MMS/spatial/fci/data/BOUT.inp b/tests/MMS/spatial/fci/data/BOUT.inp new file mode 100644 index 0000000000..6ad5d66ca2 --- /dev/null +++ b/tests/MMS/spatial/fci/data/BOUT.inp @@ -0,0 +1,23 @@ +grid = fci.grid.nc + +input = sin(y - 2*z) + sin(y - z) + +solution = 6.28318530717959*(0.01*x + 0.045)*(-2*cos(y - 2*z) - cos(y - z)) + 0.628318530717959*cos(y - 2*z) + 0.628318530717959*cos(y - z) + +MXG = 1 +NXPE = 1 + +[mesh] +paralleltransform = fci +symmetricglobalx = true + +[mesh:ddy] +first = C2 +second = C2 + +[fci] +y_periodic = true +z_periodic = true + +[interpolation] +type = lagrange4pt diff --git a/tests/MMS/spatial/fci/fci_mms.cxx b/tests/MMS/spatial/fci/fci_mms.cxx new file mode 100644 index 0000000000..32b668f575 --- /dev/null +++ b/tests/MMS/spatial/fci/fci_mms.cxx @@ -0,0 +1,28 @@ +#include "bout.hxx" +#include "derivs.hxx" +#include "field_factory.hxx" + +int main(int argc, char** argv) { + BoutInitialise(argc, argv); + + Field3D input{FieldFactory::get()->create3D("input", Options::getRoot(), mesh)}; + Field3D solution{FieldFactory::get()->create3D("solution", Options::getRoot(), mesh)}; + + // Communicate to calculate parallel transform + mesh->communicate(input); + + Field3D result{DDY(input)}; + Field3D error{result - solution}; + BoutReal l_2{sqrt(mean(SQ(error)))}; + BoutReal l_inf{max(abs(error), true)}; + + SAVE_ONCE6(input, solution, result, error, l_2, l_inf); + + for (int slice = 1; slice < mesh->ystart; ++slice) { + SAVE_ONCE2(input.ynext(-slice), input.ynext(slice)); + } + + dump.write(); + + BoutFinalise(); +} diff --git a/tests/MMS/spatial/fci/makefile b/tests/MMS/spatial/fci/makefile new file mode 100644 index 0000000000..88ba6c77e7 --- /dev/null +++ b/tests/MMS/spatial/fci/makefile @@ -0,0 +1,6 @@ + +BOUT_TOP = ../../../.. + +SOURCEC = fci_mms.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/MMS/spatial/fci/mms.py b/tests/MMS/spatial/fci/mms.py new file mode 100755 index 0000000000..1154cfc9cc --- /dev/null +++ b/tests/MMS/spatial/fci/mms.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +# +# Generate manufactured solution and sources for FCI test +# + +from __future__ import division +from __future__ import print_function + +from boutdata.mms import * + +from sympy import sin, cos, sqrt + +from math import pi + +f = sin(y - z) + sin(y - 2*z) + +Lx = 0.1 +Ly = 10. +Lz = 1. + +Bt = 1.0 +Bp = 0.05 +Bpprime = 0.1 + +Bpx = Bp + (x-0.5)*Lx * Bpprime # Note: x in range [0,1] +B = sqrt(Bpx**2 + Bt**2) + +def FCI_ddy(f): + return ( Bt * diff(f, y)*2.*pi/Ly + Bpx * diff(f, z)*2.*pi/Lz ) + +############################################ +# Equations solved + +print("input = " + exprToStr(f)) +print("solution = " + exprToStr(FCI_ddy(f))) diff --git a/tests/MMS/spatial/fci/runtest b/tests/MMS/spatial/fci/runtest new file mode 100755 index 0000000000..36eb96c7d7 --- /dev/null +++ b/tests/MMS/spatial/fci/runtest @@ -0,0 +1,176 @@ +#!/usr/bin/env python3 +# +# Python script to run and analyse MMS test +# +from __future__ import division +from __future__ import print_function + +from boututils.run_wrapper import shell_safe, launch_safe, getmpirun +from boutdata.collect import collect + +from numpy import array, log, polyfit, linspace, arange + +import pickle + +from sys import stdout + +import zoidberg as zb + +nx = 3 # Not changed for these tests + +# Resolution in y and z +nlist = [8, 16, 32, 64, 128] + +# Number of parallel slices (in each direction) +nslices = [1, 2] + +directory = "data" + +nproc = 2 +mthread = 2 + +MPIRUN = getmpirun() + +success = True + +error_2 = {} +error_inf = {} +method_orders = {} + +# Run with periodic Y? +yperiodic = True + +failures = [] + +print("Making fci MMS test") +shell_safe("make > make.log") + +for nslice in nslices: + error_2[nslice] = [] + error_inf[nslice] = [] + + # Which central difference scheme to use and its expected order + order = nslice * 2 + method_orders[nslice] = { + "name": "C{}".format(order), + "order": order + } + + for n in nlist: + # Define the magnetic field using new poloidal gridding method + # Note that the Bz and Bzprime parameters here must be the same as in mms.py + field = zb.field.Slab(Bz=0.05, Bzprime=0.1) + # Create rectangular poloidal grids + poloidal_grid = zb.poloidal_grid.RectangularPoloidalGrid(nx, n, 1., 1.) + # Set the ylength and y locations + ylength = 10. + + if yperiodic: + ycoords = linspace(0.0, ylength, n, endpoint=False) + else: + # Doesn't include the end points + ycoords = (arange(n) + 0.5)*ylength/float(n) + + # Create the grid + grid = zb.grid.Grid(poloidal_grid, ycoords, ylength, yperiodic=yperiodic) + # Make and write maps + maps = zb.make_maps(grid, field, nslice=nslice, quiet=True) + zb.write_maps(grid, field, maps, new_names=False, metric2d=True, quiet=True) + + args = (" MZ={} MYG={} fci:y_periodic={} mesh:ddy:first={}" + .format(n, nslice, yperiodic, method_orders[nslice]["name"])) + + # Command to run + cmd = "./fci_mms "+args + + print("Running command: "+cmd) + + # Launch using MPI + s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, mthread=mthread, pipe=True) + + # Save output to log file + with open("run.log."+str(n), "w") as f: + f.write(out) + + if s: + print("Run failed!\nOutput was:\n") + print(out) + exit(s) + + # Collect data + l_2 = collect("l_2", tind=[1, 1], info=False, + path=directory, xguards=False, yguards=False) + l_inf = collect("l_inf", tind=[1, 1], info=False, + path=directory, xguards=False, yguards=False) + + error_2[nslice].append(l_2) + error_inf[nslice].append(l_inf) + + print("Errors : l-2 {:f} l-inf {:f}".format(l_2, l_inf)) + + dx = 1. / array(nlist) + + # Calculate convergence order + fit = polyfit(log(dx), log(error_2[nslice]), 1) + order = fit[0] + stdout.write("Convergence order = {:f} (fit)".format(order)) + + order = log(error_2[nslice][-2]/error_2[nslice][-1])/log(dx[-2]/dx[-1]) + stdout.write(", {:f} (small spacing)".format(order)) + + # Should be close to the expected order + if order > method_orders[nslice]["order"] * 0.95: + print("............ PASS\n") + else: + print("............ FAIL\n") + success = False + failures.append(method_orders[nslice]["name"]) + + +with open("fci_mms.pkl", "wb") as output: + pickle.dump(nlist, output) + for nslice in nslices: + pickle.dump(error_2[nslice], output) + pickle.dump(error_inf[nslice], output) + +# Do we want to show the plot as well as save it to file. +showPlot = True + +if False: + try: + # Plot using matplotlib if available + import matplotlib.pyplot as plt + + fig, ax = plt.subplots(1, 1) + + for nslice in nslices: + ax.plot(dx, error_2[nslice], '-', + label="{} $l_2$".format(method_orders[nslice]["name"])) + ax.plot(dx, error_inf[nslice], '--', + label="{} $l_\inf$".format(method_orders[nslice]["name"])) + ax.legend(loc="upper left") + ax.grid() + ax.set_yscale('log') + ax.set_xscale('log') + ax.set_title('error scaling') + ax.set_xlabel(r'Mesh spacing $\delta x$') + ax.set_ylabel("Error norm") + + plt.savefig("fci_mms.pdf") + + print("Plot saved to fci_mms.pdf") + + if showPlot: + plt.show() + plt.close() + except ImportError: + print("No matplotlib") + +if success: + print("All tests passed") + exit(0) +else: + print("Some tests failed:") + for failure in failures: + print("\t" + failure) + exit(1) diff --git a/tools/pylib/zoidberg/zoidberg.py b/tools/pylib/zoidberg/zoidberg.py index e287132b5b..3217b70c76 100644 --- a/tools/pylib/zoidberg/zoidberg.py +++ b/tools/pylib/zoidberg/zoidberg.py @@ -152,7 +152,8 @@ def make_maps(grid, magnetic_field, nslice=1, quiet=False, **kwargs): def write_maps(grid, magnetic_field, maps, gridfile='fci.grid.nc', - new_names=False, metric2d=True, format="NETCDF3_64BIT"): + new_names=False, metric2d=True, format="NETCDF3_64BIT", + quiet=False): """Write FCI maps to BOUT++ grid file Parameters @@ -169,8 +170,10 @@ def write_maps(grid, magnetic_field, maps, gridfile='fci.grid.nc', Write "g_yy" rather than "g_22" metric2d : bool, optional Output only 2D metrics - format : str + format : str, optional Specifies file format to use, passed to boutdata.DataFile + quiet : bool, optional + Don't warn about 2D metrics Returns ------- @@ -186,14 +189,14 @@ def write_maps(grid, magnetic_field, maps, gridfile='fci.grid.nc', # Check if the magnetic field is in cylindrical coordinates # If so, we need to change the gyy and g_yy metrics - pol_grid,ypos = grid.getPoloidalGrid(0) + pol_grid, ypos = grid.getPoloidalGrid(0) Rmaj = magnetic_field.Rfunc(pol_grid.R, pol_grid.Z, ypos) if Rmaj is not None: # In cylindrical coordinates Rmaj = np.zeros(grid.shape) for yindex in range(grid.numberOfPoloidalGrids()): - pol_grid,ypos = grid.getPoloidalGrid(yindex) - Rmaj[:,yindex,:] = magnetic_field.Rfunc(pol_grid.R, pol_grid.Z, ypos) + pol_grid, ypos = grid.getPoloidalGrid(yindex) + Rmaj[:, yindex, :] = magnetic_field.Rfunc(pol_grid.R, pol_grid.Z, ypos) metric["gyy"] = 1./Rmaj**2 metric["g_yy"] = Rmaj**2 @@ -201,9 +204,9 @@ def write_maps(grid, magnetic_field, maps, gridfile='fci.grid.nc', Bmag = np.zeros(grid.shape) pressure = np.zeros(grid.shape) for yindex in range(grid.numberOfPoloidalGrids()): - pol_grid,ypos = grid.getPoloidalGrid(yindex) - Bmag[:,yindex,:] = magnetic_field.Bmag(pol_grid.R, pol_grid.Z, ypos) - pressure[:,yindex,:] = magnetic_field.pressure(pol_grid.R, pol_grid.Z, ypos) + pol_grid, ypos = grid.getPoloidalGrid(yindex) + Bmag[:, yindex, :] = magnetic_field.Bmag(pol_grid.R, pol_grid.Z, ypos) + pressure[:, yindex, :] = magnetic_field.pressure(pol_grid.R, pol_grid.Z, ypos) # Get attributes from magnetic field (e.g. psi) attributes = {} @@ -211,23 +214,24 @@ def write_maps(grid, magnetic_field, maps, gridfile='fci.grid.nc', attribute = np.zeros(grid.shape) for yindex in range(grid.numberOfPoloidalGrids()): pol_grid, ypos = grid.getPoloidalGrid(yindex) - attribute[:,yindex,:] = magnetic_field.attributes[name](pol_grid.R, pol_grid.Z, ypos) + attribute[:, yindex, :] = magnetic_field.attributes[name](pol_grid.R, pol_grid.Z, ypos) attributes[name] = attribute # Metric is now 3D if metric2d: # Remove the Z dimension from metric components - print("WARNING: Outputting 2D metrics, discarding metric information.") + if not quiet: + print("WARNING: Outputting 2D metrics, discarding metric information.") for key in metric: try: - metric[key] = metric[key][:,:,0] - except: + metric[key] = metric[key][:, :, 0] + except TypeError: pass # Make dz a constant - metric["dz"] = metric["dz"][0,0] + metric["dz"] = metric["dz"][0, 0] # Add Rxy, Bxy - metric["Rxy"] = maps["R"][:,:,0] - metric["Bxy"] = Bmag[:,:,0] + metric["Rxy"] = maps["R"][:, :, 0] + metric["Bxy"] = Bmag[:, :, 0] with bdata.DataFile(gridfile, write=True, create=True, format=format) as f: ixseps = nx+1 @@ -239,8 +243,8 @@ def write_maps(grid, magnetic_field, maps, gridfile='fci.grid.nc', f.write("dy", metric["dy"]) f.write("dz", metric["dz"]) - f.write("ixseps1",ixseps) - f.write("ixseps2",ixseps) + f.write("ixseps1", ixseps) + f.write("ixseps2", ixseps) # Metric tensor @@ -251,14 +255,14 @@ def write_maps(grid, magnetic_field, maps, gridfile='fci.grid.nc', # Translate between output variable names and metric names # Map from new to old names. Anything not in this dict # is output unchanged - name_changes = {"g_yy":"g_22", - "gyy":"g22", - "gxx":"g11", - "gxz":"g13", - "gzz":"g33", - "g_xx":"g_11", - "g_xz":"g_13", - "g_zz":"g_33"} + name_changes = {"g_yy": "g_22", + "gyy": "g22", + "gxx": "g11", + "gxz": "g13", + "gzz": "g33", + "g_xx": "g_11", + "g_xz": "g_13", + "g_zz": "g_33"} for key in metric: name = key if name in name_changes: From 7c41f598d12ec87a23558a99cdcc4932829c3426 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 25 Jan 2019 14:14:23 +0000 Subject: [PATCH 0644/1783] Generalise FCI transform to multiple parallel slices --- src/mesh/parallel/fci.cxx | 72 +++++++++++++++++++-------------------- src/mesh/parallel/fci.hxx | 44 +++++++++++++++--------- 2 files changed, 63 insertions(+), 53 deletions(-) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index eb62510406..89558fc628 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -42,10 +42,12 @@ #include "parallel_boundary_region.hxx" #include #include -#include // See this for codes +#include #include #include +#include + /** * Return the sign of val */ @@ -53,14 +55,18 @@ inline BoutReal sgn(BoutReal val) { return (BoutReal(0) < val) - (val < BoutReal // Calculate all the coefficients needed for the spline interpolation // dir MUST be either +1 or -1 -FCIMap::FCIMap(Mesh &mesh, int dir, bool zperiodic) - : dir(dir), boundary_mask(mesh), corner_boundary_mask(mesh), y_prime(&mesh) { +FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperiodic) + : offset(offset_), boundary_mask(mesh), corner_boundary_mask(mesh), y_prime(&mesh) { + + if (offset == 0) { + throw BoutException("FCIMap called with offset = 0; You probably didn't mean to do that"); + } interp = InterpolationFactory::getInstance()->create(&mesh); - interp->setYOffset(dir); + interp->setYOffset(offset); interp_corner = InterpolationFactory::getInstance()->create(&mesh); - interp_corner->setYOffset(dir); + interp_corner->setYOffset(offset); // Index arrays contain guard cells in order to get subscripts right // x-index of bottom-left grid point @@ -76,28 +82,20 @@ FCIMap::FCIMap(Mesh &mesh, int dir, bool zperiodic) mesh.get(R, "R", 0.0, false); mesh.get(Z, "Z", 0.0, false); - // Load the floating point indices from the grid file - // Future, higher order parallel derivatives could require maps to +/-2 slices - if (dir == +1) { - mesh.get(xt_prime, "forward_xt_prime", 0.0, false); - mesh.get(zt_prime, "forward_zt_prime", 0.0, false); - mesh.get(R_prime, "forward_R", 0.0, false); - mesh.get(Z_prime, "forward_Z", 0.0, false); - boundary = new BoundaryRegionPar("FCI_forward", BNDRY_PAR_FWD, dir, &mesh); - } else if (dir == -1) { - mesh.get(xt_prime, "backward_xt_prime", 0.0, false); - mesh.get(zt_prime, "backward_zt_prime", 0.0, false); - mesh.get(R_prime, "backward_R", 0.0, false); - mesh.get(Z_prime, "backward_Z", 0.0, false); - boundary = new BoundaryRegionPar("FCI_backward", BNDRY_PAR_BKWD, dir, &mesh); - } else { - // Definitely shouldn't be called - throw BoutException("FCIMap called with strange direction: %d. Only +/-1 currently supported.", dir); - } + const auto parallel_slice_field_name = [&](std::string field) -> std::string { + const std::string direction = (offset > 0) ? "forward" : "backward"; + // We only have a suffix for parallel slices beyond the first + // This is for backwards compatibility + const std::string slice_suffix = + (std::abs(offset) > 1) ? "_" + std::to_string(std::abs(offset)) : ""; + return direction + "_" + field + slice_suffix; + }; + + mesh.get(xt_prime, parallel_slice_field_name("xt_prime"), 0.0, false); + mesh.get(zt_prime, parallel_slice_field_name("zt_prime"), 0.0, false); + mesh.get(R_prime, parallel_slice_field_name("R"), 0.0, false); + mesh.get(Z_prime, parallel_slice_field_name("Z"), 0.0, false); - // Add the boundary region to the mesh's vector of parallel boundaries - mesh.addBoundaryPar(boundary); - // Cell corners Field3D xt_prime_corner(&mesh), zt_prime_corner(&mesh); xt_prime_corner.allocate(); @@ -215,7 +213,7 @@ FCIMap::FCIMap(Mesh &mesh, int dir, bool zperiodic) BoutReal dx = (dZ_dz * dR - dR_dz * dZ) / det; BoutReal dz = (dR_dx * dZ - dZ_dx * dR) / det; boundary->add_point(x, y, z, - x + dx, y + 0.5*dir, z + dz, // Intersection point in local index space + x + dx, y + 0.5*offset, z + dz, // Intersection point in local index space 0.5*coord.dy(x,y), //sqrt( SQ(dR) + SQ(dZ) ), // Distance to intersection PI // Right-angle intersection ); @@ -236,7 +234,7 @@ FCIMap::FCIMap(Mesh &mesh, int dir, bool zperiodic) interp->setMask(boundary_mask); } -const Field3D FCIMap::integrate(Field3D &f) const { +Field3D FCIMap::integrate(Field3D &f) const { TRACE("FCIMap::integrate"); // Cell centre values @@ -254,7 +252,7 @@ const Field3D FCIMap::integrate(Field3D &f) const { for(int x = mesh->xstart; x <= mesh->xend; x++) { for(int y = mesh->ystart; y <= mesh->yend; y++) { - int ynext = y+dir; + int ynext = y+offset; for(int z = 0; z < nz; z++) { if (boundary_mask(x,y,z)) @@ -294,24 +292,26 @@ const Field3D FCIMap::integrate(Field3D &f) const { return result; } -void FCITransform::calcYUpDown(Field3D &f) { +void FCITransform::calcYUpDown(Field3D& f) { TRACE("FCITransform::calcYUpDown"); // Ensure that yup and ydown are different fields f.splitYupYdown(); // Interpolate f onto yup and ydown fields - f.ynext(forward_map.dir) = forward_map.interpolate(f); - f.ynext(backward_map.dir) = backward_map.interpolate(f); + for (const auto& map : field_line_maps) { + f.ynext(map.offset) = map.interpolate(f); + } } -void FCITransform::integrateYUpDown(Field3D &f) { +void FCITransform::integrateYUpDown(Field3D& f) { TRACE("FCITransform::integrateYUpDown"); - + // Ensure that yup and ydown are different fields f.splitYupYdown(); // Integrate f onto yup and ydown fields - f.ynext(forward_map.dir) = forward_map.integrate(f); - f.ynext(backward_map.dir) = backward_map.integrate(f); + for (const auto& map : field_line_maps) { + f.ynext(map.offset) = map.integrate(f); + } } diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index 293113b91d..765fc9fc83 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -32,6 +32,8 @@ #include #include +#include + /*! * Field line map - contains the coefficients for interpolation */ @@ -40,24 +42,21 @@ class FCIMap { Interpolation *interp; // Cell centre Interpolation *interp_corner; // Cell corner at (x+1, z+1) - /// Private constructor - must be initialised with mesh - FCIMap(); public: - /// dir MUST be either +1 or -1 - FCIMap(Mesh& mesh, int dir, bool zperiodic); + FCIMap() = delete; + FCIMap(Mesh& mesh, int offset, BoundaryRegionPar* boundary, bool zperiodic); - int dir; /**< Direction of map */ + /// Direction of map + const int offset; BoutMask boundary_mask; /**< boundary mask - has the field line left the domain */ BoutMask corner_boundary_mask; ///< If any of the integration area has left the domain Field3D y_prime; /**< distance to intersection with boundary */ - BoundaryRegionPar* boundary; /**< boundary region */ - - const Field3D interpolate(Field3D &f) const { return interp->interpolate(f); } + Field3D interpolate(Field3D &f) const { return interp->interpolate(f); } - const Field3D integrate(Field3D &f) const; + Field3D integrate(Field3D &f) const; }; /*! @@ -65,9 +64,21 @@ public: */ class FCITransform : public ParallelTransform { public: - FCITransform(Mesh &mesh, bool zperiodic = true) - : mesh(mesh), forward_map(mesh, +1, zperiodic), backward_map(mesh, -1, zperiodic), - zperiodic(zperiodic) {} + FCITransform() = delete; + FCITransform(Mesh& mesh, bool zperiodic = true) : mesh(mesh), zperiodic(zperiodic) { + auto forward_boundary = new BoundaryRegionPar("FCI_forward", BNDRY_PAR_FWD, +1, &mesh); + auto backward_boundary = new BoundaryRegionPar("FCI_backward", BNDRY_PAR_BKWD, -1, &mesh); + + // Add the boundary region to the mesh's vector of parallel boundaries + mesh.addBoundaryPar(forward_boundary); + mesh.addBoundaryPar(backward_boundary); + + field_line_maps.reserve(mesh.ystart * 2); + for (int offset = 1; offset < mesh.ystart + 1; ++offset) { + field_line_maps.emplace_back(mesh, offset, forward_boundary, zperiodic); + field_line_maps.emplace_back(mesh, -offset, backward_boundary, zperiodic); + } + } void calcYUpDown(Field3D &f) override; @@ -85,14 +96,13 @@ public: return false; } private: - FCITransform(); - Mesh& mesh; - FCIMap forward_map; /**< FCI map for field lines in +ve y */ - FCIMap backward_map; /**< FCI map for field lines in -ve y */ + /// FCI maps for field lines in +ve y + std::vector field_line_maps; - bool zperiodic; /**< Is the z-direction periodic? */ + /// Is the z-direction periodic? + bool zperiodic; }; #endif // __FCITRANSFORM_H__ From eed9451bf8364f6f56a136af1e983ded08b7ad5f Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 25 Jan 2019 14:18:34 +0000 Subject: [PATCH 0645/1783] Add derived metrics --- include/bout/run_metrics.hxx | 14 ++++++++++++++ src/bout++.cxx | 2 ++ src/sys/run_metrics.cxx | 11 +++++++++++ 3 files changed, 27 insertions(+) diff --git a/include/bout/run_metrics.hxx b/include/bout/run_metrics.hxx index d9ecb377d3..b77615ffef 100644 --- a/include/bout/run_metrics.hxx +++ b/include/bout/run_metrics.hxx @@ -56,11 +56,25 @@ class RunMetrics { /// wall time spent on I/O BoutReal wtime_io; + // Derived metrics + + /// wall time per RHS evaluation + BoutReal wtime_per_rhs; + /// wall time per fast timescale RHS evaluation + BoutReal wtime_per_rhs_e; + /// wall time per slow timescale RHS evaluation + BoutReal wtime_per_rhs_i; + /*! * Adds variables to the output file, for post-processing */ void outputVars(Datafile &file); + /*! + * Calculates derived metrics + */ + void calculateDerivedMetrics(); + /*! * Write job progress to screen */ diff --git a/src/bout++.cxx b/src/bout++.cxx index 669f141b19..3272956220 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -635,6 +635,8 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { run_data.wtime_comms = Timer::resetTime("comms"); // Time spent communicating (part of RHS) run_data.wtime_io = Timer::resetTime("io"); // Time spend on I/O + run_data.calculateDerivedMetrics(); + output_progress.print("\r"); // Only goes to screen if (first_time) { diff --git a/src/sys/run_metrics.cxx b/src/sys/run_metrics.cxx index 84b9f436d5..924877e2c9 100644 --- a/src/sys/run_metrics.cxx +++ b/src/sys/run_metrics.cxx @@ -28,6 +28,7 @@ * Adds variables to the output file, for post-processing */ void RunMetrics::outputVars(Datafile &file) { + file.add(t_elapsed, "wall_time", true); file.add(wtime, "wtime", true); file.add(ncalls, "ncalls", true); @@ -37,6 +38,16 @@ void RunMetrics::outputVars(Datafile &file) { file.add(wtime_invert, "wtime_invert", true); file.add(wtime_comms, "wtime_comms", true); file.add(wtime_io, "wtime_io", true); + file.add(wtime_per_rhs, "wtime_per_rhs", true); + file.add(wtime_per_rhs_e, "wtime_per_rhs_e", true); + file.add(wtime_per_rhs_i, "wtime_per_rhs_i", true); +} + +void RunMetrics::calculateDerivedMetrics() { + + wtime_per_rhs = wtime / ncalls; + wtime_per_rhs_e = wtime / ncalls_e; + wtime_per_rhs_i = wtime / ncalls_i; } void RunMetrics::writeProgress(BoutReal simtime, bool output_split) { From 13b68c12fd21d98a6378c260d30eaeef981587fe Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 25 Jan 2019 14:28:53 +0000 Subject: [PATCH 0646/1783] Throw if not enough parallel slices in FCI grid file --- src/mesh/parallel/fci.cxx | 56 ++++++++++++++++++++++++++------------- src/mesh/parallel/fci.hxx | 8 ++---- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 89558fc628..54b9152602 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -58,6 +58,8 @@ inline BoutReal sgn(BoutReal val) { return (BoutReal(0) < val) - (val < BoutReal FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperiodic) : offset(offset_), boundary_mask(mesh), corner_boundary_mask(mesh), y_prime(&mesh) { + TRACE("Creating FCIMAP for direction %d", offset); + if (offset == 0) { throw BoutException("FCIMap called with offset = 0; You probably didn't mean to do that"); } @@ -67,7 +69,7 @@ FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperio interp_corner = InterpolationFactory::getInstance()->create(&mesh); interp_corner->setYOffset(offset); - + // Index arrays contain guard cells in order to get subscripts right // x-index of bottom-left grid point auto i_corner = Tensor(mesh.LocalNx, mesh.LocalNy, mesh.LocalNz); @@ -91,10 +93,26 @@ FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperio return direction + "_" + field + slice_suffix; }; - mesh.get(xt_prime, parallel_slice_field_name("xt_prime"), 0.0, false); - mesh.get(zt_prime, parallel_slice_field_name("zt_prime"), 0.0, false); - mesh.get(R_prime, parallel_slice_field_name("R"), 0.0, false); - mesh.get(Z_prime, parallel_slice_field_name("Z"), 0.0, false); + if (mesh.get(xt_prime, parallel_slice_field_name("xt_prime"), 0.0, false) != 0) { + throw BoutException("Could not read %s from grid file!\n" + " Either add it to the grid file, or reduce MYG", + parallel_slice_field_name("xt_prime").c_str()); + } + if (mesh.get(zt_prime, parallel_slice_field_name("zt_prime"), 0.0, false) != 0) { + throw BoutException("Could not read %s from grid file!\n" + " Either add it to the grid file, or reduce MYG", + parallel_slice_field_name("zt_prime").c_str()); + } + if (mesh.get(R_prime, parallel_slice_field_name("R"), 0.0, false) != 0) { + throw BoutException("Could not read %s from grid file!\n" + " Either add it to the grid file, or reduce MYG", + parallel_slice_field_name("R").c_str()); + } + if (mesh.get(Z_prime, parallel_slice_field_name("Z"), 0.0, false) != 0) { + throw BoutException("Could not read %s from grid file!\n" + " Either add it to the grid file, or reduce MYG", + parallel_slice_field_name("Z").c_str()); + } // Cell corners Field3D xt_prime_corner(&mesh), zt_prime_corner(&mesh); @@ -110,12 +128,12 @@ FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperio (xt_prime(x + 1, y, z + 1) < 0.0) || (xt_prime(x, y, z + 1) < 0.0)) { // Hit a boundary corner_boundary_mask(x, y, z) = true; - + xt_prime_corner(x, y, z) = -1.0; zt_prime_corner(x, y, z) = -1.0; continue; } - + xt_prime_corner(x, y, z) = 0.25 * (xt_prime(x, y, z) + xt_prime(x + 1, y, z) + xt_prime(x, y, z + 1) + xt_prime(x + 1, y, z + 1)); @@ -126,12 +144,12 @@ FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperio } } } - + interp_corner->setMask(corner_boundary_mask); interp_corner->calcWeights(xt_prime_corner, zt_prime_corner); - + interp->calcWeights(xt_prime, zt_prime); - + int ncz = mesh.LocalNz; BoutReal t_x, t_z; @@ -212,7 +230,7 @@ FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperio // Invert 2x2 matrix to get change in index BoutReal dx = (dZ_dz * dR - dR_dz * dZ) / det; BoutReal dz = (dR_dx * dZ - dZ_dx * dR) / det; - boundary->add_point(x, y, z, + boundary->add_point(x, y, z, x + dx, y + 0.5*offset, z + dz, // Intersection point in local index space 0.5*coord.dy(x,y), //sqrt( SQ(dR) + SQ(dZ) ), // Distance to intersection PI // Right-angle intersection @@ -236,10 +254,10 @@ FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperio Field3D FCIMap::integrate(Field3D &f) const { TRACE("FCIMap::integrate"); - + // Cell centre values Field3D centre = interp->interpolate(f); - + // Cell corner values (x+1/2, z+1/2) Field3D corner = interp_corner->interpolate(f); @@ -248,23 +266,23 @@ Field3D FCIMap::integrate(Field3D &f) const { result.setLocation(f.getLocation()); int nz = mesh->LocalNz; - + for(int x = mesh->xstart; x <= mesh->xend; x++) { for(int y = mesh->ystart; y <= mesh->yend; y++) { - + int ynext = y+offset; - + for(int z = 0; z < nz; z++) { if (boundary_mask(x,y,z)) continue; - + int zm = z - 1; if (z == 0) { zm = nz-1; } - + BoutReal f_c = centre(x,ynext,z); - + if (corner_boundary_mask(x, y, z) || corner_boundary_mask(x - 1, y, z) || corner_boundary_mask(x, y, zm) || corner_boundary_mask(x - 1, y, zm) || (x == mesh->xstart)) { diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index 765fc9fc83..95fa241996 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -65,7 +65,8 @@ public: class FCITransform : public ParallelTransform { public: FCITransform() = delete; - FCITransform(Mesh& mesh, bool zperiodic = true) : mesh(mesh), zperiodic(zperiodic) { + FCITransform(Mesh& mesh, bool zperiodic = true) { + auto forward_boundary = new BoundaryRegionPar("FCI_forward", BNDRY_PAR_FWD, +1, &mesh); auto backward_boundary = new BoundaryRegionPar("FCI_backward", BNDRY_PAR_BKWD, -1, &mesh); @@ -96,13 +97,8 @@ public: return false; } private: - Mesh& mesh; - /// FCI maps for field lines in +ve y std::vector field_line_maps; - - /// Is the z-direction periodic? - bool zperiodic; }; #endif // __FCITRANSFORM_H__ From 33155db7bdccc014edeba3883ed9b5581782a3e2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 25 Jan 2019 17:36:36 +0000 Subject: [PATCH 0647/1783] Clean up FCI a bit - Remove unused variables - Store mesh and check it's the same as the field to be interpolated/integrated - Store interpolations as unique_ptrs to avoid potential memory leaks --- src/mesh/parallel/fci.cxx | 75 ++++++++++++++++++++------------------- src/mesh/parallel/fci.hxx | 40 +++++++++++---------- 2 files changed, 61 insertions(+), 54 deletions(-) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 54b9152602..d85f7df1e4 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -48,15 +48,9 @@ #include -/** - * Return the sign of val - */ -inline BoutReal sgn(BoutReal val) { return (BoutReal(0) < val) - (val < BoutReal(0)); } - -// Calculate all the coefficients needed for the spline interpolation -// dir MUST be either +1 or -1 -FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperiodic) - : offset(offset_), boundary_mask(mesh), corner_boundary_mask(mesh), y_prime(&mesh) { +FCIMap::FCIMap(Mesh& mesh, int offset_, BoundaryRegionPar* boundary, bool zperiodic) + : map_mesh(mesh), offset(offset_), boundary_mask(map_mesh), + corner_boundary_mask(map_mesh) { TRACE("Creating FCIMAP for direction %d", offset); @@ -64,26 +58,31 @@ FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperio throw BoutException("FCIMap called with offset = 0; You probably didn't mean to do that"); } - interp = InterpolationFactory::getInstance()->create(&mesh); + interp = + std::unique_ptr(InterpolationFactory::getInstance()->create(&map_mesh)); interp->setYOffset(offset); - interp_corner = InterpolationFactory::getInstance()->create(&mesh); + interp_corner = + std::unique_ptr(InterpolationFactory::getInstance()->create(&map_mesh)); interp_corner->setYOffset(offset); // Index arrays contain guard cells in order to get subscripts right // x-index of bottom-left grid point - auto i_corner = Tensor(mesh.LocalNx, mesh.LocalNy, mesh.LocalNz); + auto i_corner = Tensor(map_mesh.LocalNx, map_mesh.LocalNy, map_mesh.LocalNz); // z-index of bottom-left grid point - auto k_corner = Tensor(mesh.LocalNx, mesh.LocalNy, mesh.LocalNz); + auto k_corner = Tensor(map_mesh.LocalNx, map_mesh.LocalNy, map_mesh.LocalNz); - Field3D xt_prime(&mesh), zt_prime(&mesh); - Field3D R(&mesh), Z(&mesh); // Real-space coordinates of grid points - Field3D R_prime(&mesh), - Z_prime(&mesh); // Real-space coordinates of forward/backward points + // Index-space coordinates of forward/backward points + Field3D xt_prime(&map_mesh), zt_prime(&map_mesh); + // Real-space coordinates of grid points + Field3D R(&map_mesh), Z(&map_mesh); + // Real-space coordinates of forward/backward points + Field3D R_prime(&map_mesh), Z_prime(&map_mesh); - mesh.get(R, "R", 0.0, false); - mesh.get(Z, "Z", 0.0, false); + map_mesh.get(R, "R", 0.0, false); + map_mesh.get(Z, "Z", 0.0, false); + // Get a unique name for a field based on the sign/magnitude of the offset const auto parallel_slice_field_name = [&](std::string field) -> std::string { const std::string direction = (offset > 0) ? "forward" : "backward"; // We only have a suffix for parallel slices beyond the first @@ -93,35 +92,37 @@ FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperio return direction + "_" + field + slice_suffix; }; - if (mesh.get(xt_prime, parallel_slice_field_name("xt_prime"), 0.0, false) != 0) { + // If we can't read in any of these fields, things will silently not + // work, so best throw + if (map_mesh.get(xt_prime, parallel_slice_field_name("xt_prime"), 0.0, false) != 0) { throw BoutException("Could not read %s from grid file!\n" " Either add it to the grid file, or reduce MYG", parallel_slice_field_name("xt_prime").c_str()); } - if (mesh.get(zt_prime, parallel_slice_field_name("zt_prime"), 0.0, false) != 0) { + if (map_mesh.get(zt_prime, parallel_slice_field_name("zt_prime"), 0.0, false) != 0) { throw BoutException("Could not read %s from grid file!\n" " Either add it to the grid file, or reduce MYG", parallel_slice_field_name("zt_prime").c_str()); } - if (mesh.get(R_prime, parallel_slice_field_name("R"), 0.0, false) != 0) { + if (map_mesh.get(R_prime, parallel_slice_field_name("R"), 0.0, false) != 0) { throw BoutException("Could not read %s from grid file!\n" " Either add it to the grid file, or reduce MYG", parallel_slice_field_name("R").c_str()); } - if (mesh.get(Z_prime, parallel_slice_field_name("Z"), 0.0, false) != 0) { + if (map_mesh.get(Z_prime, parallel_slice_field_name("Z"), 0.0, false) != 0) { throw BoutException("Could not read %s from grid file!\n" " Either add it to the grid file, or reduce MYG", parallel_slice_field_name("Z").c_str()); } // Cell corners - Field3D xt_prime_corner(&mesh), zt_prime_corner(&mesh); + Field3D xt_prime_corner(&map_mesh), zt_prime_corner(&map_mesh); xt_prime_corner.allocate(); zt_prime_corner.allocate(); - for (int x = mesh.xstart; x <= mesh.xend; x++) { - for (int y = mesh.ystart; y <= mesh.yend; y++) { - for (int z = 0; z < mesh.LocalNz - 1; z++) { + for (int x = map_mesh.xstart; x <= map_mesh.xend; x++) { + for (int y = map_mesh.ystart; y <= map_mesh.yend; y++) { + for (int z = 0; z < map_mesh.LocalNz - 1; z++) { // Point interpolated from (x+1/2, z+1/2) if ((xt_prime(x, y, z) < 0.0) || (xt_prime(x + 1, y, z) < 0.0) || @@ -150,13 +151,13 @@ FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperio interp->calcWeights(xt_prime, zt_prime); - int ncz = mesh.LocalNz; + int ncz = map_mesh.LocalNz; BoutReal t_x, t_z; - Coordinates &coord = *(mesh.getCoordinates()); + Coordinates &coord = *(map_mesh.getCoordinates()); - for (int x = mesh.xstart; x <= mesh.xend; x++) { - for (int y = mesh.ystart; y <= mesh.yend; y++) { + for (int x = map_mesh.xstart; x <= map_mesh.xend; x++) { + for (int y = map_mesh.ystart; y <= map_mesh.yend; y++) { for (int z = 0; z < ncz; z++) { // The integer part of xt_prime, zt_prime are the indices of the cell @@ -213,7 +214,7 @@ FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperio dR_dz = R(x, y, z + 1) - R(x, y, z); dZ_dz = Z(x, y, z + 1) - Z(x, y, z); - } else if (z == mesh.LocalNz - 1) { + } else if (z == map_mesh.LocalNz - 1) { dR_dz = R(x, y, z) - R(x, y, z - 1); dZ_dz = Z(x, y, z) - Z(x, y, z - 1); @@ -255,6 +256,8 @@ FCIMap::FCIMap(Mesh &mesh, int offset_, BoundaryRegionPar* boundary, bool zperio Field3D FCIMap::integrate(Field3D &f) const { TRACE("FCIMap::integrate"); + ASSERT3(&map_mesh == f.getMesh()); + // Cell centre values Field3D centre = interp->interpolate(f); @@ -265,10 +268,10 @@ Field3D FCIMap::integrate(Field3D &f) const { result.allocate(); result.setLocation(f.getLocation()); - int nz = mesh->LocalNz; + int nz = map_mesh.LocalNz; - for(int x = mesh->xstart; x <= mesh->xend; x++) { - for(int y = mesh->ystart; y <= mesh->yend; y++) { + for(int x = map_mesh.xstart; x <= map_mesh.xend; x++) { + for(int y = map_mesh.ystart; y <= map_mesh.yend; y++) { int ynext = y+offset; @@ -285,7 +288,7 @@ Field3D FCIMap::integrate(Field3D &f) const { if (corner_boundary_mask(x, y, z) || corner_boundary_mask(x - 1, y, z) || corner_boundary_mask(x, y, zm) || corner_boundary_mask(x - 1, y, zm) || - (x == mesh->xstart)) { + (x == map_mesh.xstart)) { // One of the corners leaves the domain. // Use the cell centre value, since boundary conditions are not // currently applied to corners. diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index 95fa241996..37a87a96e6 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -32,36 +32,41 @@ #include #include +#include #include -/*! - * Field line map - contains the coefficients for interpolation - */ + +/// Field line map - contains the coefficients for interpolation class FCIMap { - /// Interpolation object - Interpolation *interp; // Cell centre - Interpolation *interp_corner; // Cell corner at (x+1, z+1) + /// Interpolation objects + std::unique_ptr interp; // Cell centre + std::unique_ptr interp_corner; // Cell corner at (x+1, z+1) public: FCIMap() = delete; FCIMap(Mesh& mesh, int offset, BoundaryRegionPar* boundary, bool zperiodic); + // The mesh this map was created on + Mesh& map_mesh; + /// Direction of map const int offset; - BoutMask boundary_mask; /**< boundary mask - has the field line left the domain */ - BoutMask corner_boundary_mask; ///< If any of the integration area has left the domain + /// boundary mask - has the field line left the domain + BoutMask boundary_mask; + /// If any of the integration area has left the domain + BoutMask corner_boundary_mask; - Field3D y_prime; /**< distance to intersection with boundary */ - - Field3D interpolate(Field3D &f) const { return interp->interpolate(f); } + Field3D interpolate(Field3D& f) const { + ASSERT3(&map_mesh == f.getMesh()); + return interp->interpolate(f); + } Field3D integrate(Field3D &f) const; }; -/*! - * Flux Coordinate Independent method for parallel derivatives - */ + +/// Flux Coordinate Independent method for parallel derivatives class FCITransform : public ParallelTransform { public: FCITransform() = delete; @@ -93,11 +98,10 @@ public: throw BoutException("FCI method cannot transform into field aligned grid"); } - bool canToFromFieldAligned() override{ - return false; - } + bool canToFromFieldAligned() override { return false; } + private: - /// FCI maps for field lines in +ve y + /// FCI maps for each of the parallel slices std::vector field_line_maps; }; From e743a525b6917eb150f4c57985f41a1319839447 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 25 Jan 2019 17:39:47 +0000 Subject: [PATCH 0648/1783] Remove old fci-slab test (replaced with better MMS test) --- tests/integrated/test-fci-slab/data/BOUT.inp | 26 --- tests/integrated/test-fci-slab/fci.py | 110 ------------ tests/integrated/test-fci-slab/fci_slab.cxx | 53 ------ tests/integrated/test-fci-slab/generate.py | 126 ------------- tests/integrated/test-fci-slab/makefile | 6 - tests/integrated/test-fci-slab/mms.py | 47 ----- tests/integrated/test-fci-slab/mms/BOUT.inp | 39 ----- tests/integrated/test-fci-slab/plot_funcs.py | 28 --- tests/integrated/test-fci-slab/plot_interp.py | 17 -- tests/integrated/test-fci-slab/runtest | 165 ------------------ tests/integrated/test-fci-slab/simple_test.py | 32 ---- 11 files changed, 649 deletions(-) delete mode 100644 tests/integrated/test-fci-slab/data/BOUT.inp delete mode 100644 tests/integrated/test-fci-slab/fci.py delete mode 100644 tests/integrated/test-fci-slab/fci_slab.cxx delete mode 100644 tests/integrated/test-fci-slab/generate.py delete mode 100644 tests/integrated/test-fci-slab/makefile delete mode 100644 tests/integrated/test-fci-slab/mms.py delete mode 100644 tests/integrated/test-fci-slab/mms/BOUT.inp delete mode 100644 tests/integrated/test-fci-slab/plot_funcs.py delete mode 100644 tests/integrated/test-fci-slab/plot_interp.py delete mode 100755 tests/integrated/test-fci-slab/runtest delete mode 100644 tests/integrated/test-fci-slab/simple_test.py diff --git a/tests/integrated/test-fci-slab/data/BOUT.inp b/tests/integrated/test-fci-slab/data/BOUT.inp deleted file mode 100644 index 218946e676..0000000000 --- a/tests/integrated/test-fci-slab/data/BOUT.inp +++ /dev/null @@ -1,26 +0,0 @@ -grid = fci.grid.nc -#grid = simple_test.nc - -nout = 50 -timestep = 0.2 - -MZ = 64 - -[mesh] -paralleltransform = fci - -symmetricglobalx = true - -[interpolation] -type=lagrange4pt - -[fci] -y_periodic = false -z_periodic = false - -[f] -scale = 1.0 -function = cos(y-z) - -bndry_par_yup = parallel_dirichlet(0.0) -bndry_par_ydown = parallel_dirichlet(0.0) diff --git a/tests/integrated/test-fci-slab/fci.py b/tests/integrated/test-fci-slab/fci.py deleted file mode 100644 index 1c505ffa20..0000000000 --- a/tests/integrated/test-fci-slab/fci.py +++ /dev/null @@ -1,110 +0,0 @@ -from __future__ import division -from builtins import object -from past.utils import old_div -import numpy as np -from math import pi -from scipy.integrate import odeint -import boututils.datafile as bdata -from boutdata.input import transform3D - -# Parameters -nx = 34 -########## y is toroidal! -ny = 64 -########## z is poloidal! -nz = 64 - -Lx = 0.1 # Radial domain size [m] -Ltor = 10. # "Toroidal" length [m] -Lpol = 1. # "Poloidal" length [m] - -delta_x = old_div(Lx,(nx)) -delta_pol = old_div(Lpol,(nz)) -delta_tor = old_div(Ltor,(ny)) - -Bt = 1.0 # Magnetic field [T] -Bp = 0.1 # Poloidal field at the middle of the domain [T] -Bpprime = 1.0 # Bp gradient [T/m] Bp(x) = Bp + Bpprime * x - -# Coord arrays -x = np.linspace(0,Lx,nx) -y = np.linspace(0,Ltor,ny) -z = np.linspace(0,Lpol,nz,endpoint=False) - -############################################################ - -# Effective major radius -R = old_div(Ltor, (2.*pi)) - -# Set poloidal magnetic field - -Bpx = Bp + (x-old_div(Lx,2)) * Bpprime - -Bpxy = np.transpose(np.resize(Bpx, (nz, ny, nx)), (2,1,0)) - -Bxy = np.sqrt(Bpxy**2 + Bt**2) - -############################################################ - -class Mappoint(object): - def __init__(self, xt, zt): - self.xt = xt - self.zt = zt - - self.xt_prime = old_div(xt,delta_x) - self.zt_prime = old_div(zt,delta_pol) - -def unroll_map_coeff(map_list, coeff): - coeff_array = np.transpose(np.resize(np.array([getattr(f, coeff) for f in map_list]).reshape( (nx,nz) ), (ny, nx, nz) ), (1, 0, 2) ) - return coeff_array - -def b_field(vector, y): - x0 = 0.05 # Centre of box, where bz = 0. - x, z = vector; - bx = 0. - bz = Bp + (x-x0) * Bpprime - - return [bx, bz] - -def field_line_tracer(direction, map_list): - - result = np.zeros( (nx, nz, 2) ) - - for i in np.arange(0,nx): - for k in np.arange(0,nz): - result[i,k,:] = odeint(b_field, [x[i], z[k]], [0, delta_tor*direction])[1,:] - result[i,k,1] = np.mod(result[i,k,1], Lpol) - - map_list.append(Mappoint(result[i,k,0],result[i,k,1])) - - return result - -if __name__ == "__main__": - - forward_map = [] - forward_coords = field_line_tracer(+1, forward_map) - backward_map = [] - backward_coords = field_line_tracer(-1, backward_map) - - X,Y = np.meshgrid(x,y,indexing='ij') - x0 = 0.5 - g_22 = np.sqrt(((Bp + (X-x0) * Lx * Bpprime)**2 + 1)) - - with bdata.DataFile('fci.grid.nc', write=True, create=True) as f: - f.write('nx', nx) - f.write('ny', ny) - f.write('nz', nz) - f.write("dx", delta_x) - f.write("dy", delta_tor) - f.write("g_22", g_22) - f.write("Bxy", transform3D(Bxy)) - - xt_prime = unroll_map_coeff(forward_map, 'xt_prime') - f.write('forward_xt_prime', transform3D(xt_prime)) - zt_prime = unroll_map_coeff(forward_map, 'zt_prime') - f.write('forward_zt_prime', transform3D(zt_prime)) - - xt_prime = unroll_map_coeff(backward_map, 'xt_prime') - f.write('backward_xt_prime', transform3D(xt_prime)) - zt_prime = unroll_map_coeff(backward_map, 'zt_prime') - f.write('backward_zt_prime', transform3D(zt_prime)) diff --git a/tests/integrated/test-fci-slab/fci_slab.cxx b/tests/integrated/test-fci-slab/fci_slab.cxx deleted file mode 100644 index 60a6bfd4ca..0000000000 --- a/tests/integrated/test-fci-slab/fci_slab.cxx +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include - -class FCISlab : public PhysicsModel { -public: - - // We need to initialise the FCI object with the mesh - FCISlab() {} - - int init(bool UNUSED(restarting)) { - - D = 10; - - Coordinates *coord = mesh->getCoordinates(); - - mesh->get(coord->g_22, "g_22"); - - coord->geometry(); - - solver->add(f, "f"); - solver->add(g, "g"); - - f.applyBoundary("dirichlet"); - g.applyBoundary("dirichlet"); - - return 0; - } - - int rhs(BoutReal time); - -private: - Field3D f, g; - - BoutReal D; -}; - -BOUTMAIN(FCISlab); - -int FCISlab::rhs(BoutReal time) { - mesh->communicate(f,g); - - Coordinates *coord = mesh->getCoordinates(); - - f.applyParallelBoundary(time); - g.applyParallelBoundary(time); - - ddt(f) = Grad_par(g) + D*SQ(coord->dy)*Grad2_par2(f); - - ddt(g) = Grad_par(f) + D*SQ(coord->dy)*Grad2_par2(g); - - return 0; -} diff --git a/tests/integrated/test-fci-slab/generate.py b/tests/integrated/test-fci-slab/generate.py deleted file mode 100644 index 03767db3a6..0000000000 --- a/tests/integrated/test-fci-slab/generate.py +++ /dev/null @@ -1,126 +0,0 @@ -from __future__ import division -from builtins import object -from past.utils import old_div -# -# Routines to generate slab meshes for FCI -# - -import numpy as np -from math import pi -from scipy.integrate import odeint -import boututils.datafile as bdata - - -def slab(nx, ny, nz, - filename="fci.grid.nc", - Lx=0.1, Ly=10., Lz = 1., - Bt=1.0, Bp = 0.1, Bpprime = 1.0): - """ - nx - Number of radial points - ny - Number of toroidal points (NOTE: Different to BOUT++ standard) - nz - Number of poloidal points - - Lx - Radial domain size [m] - Ly - Toroidal domain size [m] - Lz - Poloidal domain size [m] - - Bt - Toroidal magnetic field [T] - Bp - Poloidal magnetic field [T] - Bpprime - Gradient of Bp [T/m] Bp(x) = Bp + Bpprime * x - """ - - MXG = 2 - - # Make sure input types are sane - nx = int(nx) - ny = int(ny) - nz = int(nz) - - Lx = float(Lx) - Ly = float(Ly) - Lz = float(Lz) - - delta_x = old_div(Lx,(nx-2.*MXG)) - delta_pol = old_div(Lz,(nz)) - delta_tor = old_div(Ly,(ny)) - - # Coord arrays - x = Lx * (np.arange(nx) - MXG + 0.5)/(nx - 2.*MXG) # 0 and 1 half-way between cells - y = np.linspace(0,Ly,ny) - z = np.linspace(0,Lz,nz,endpoint=False) - - ############################################################ - - # Effective major radius - R = old_div(Ly, (2.*pi)) - - # Set poloidal magnetic field - - Bpx = Bp + (x-old_div(Lx,2)) * Bpprime - - Bpxy = np.transpose(np.resize(Bpx, (nz, ny, nx)), (2,1,0)) - - Bxy = np.sqrt(Bpxy**2 + Bt**2)[:,:,0] - - class Mappoint(object): - def __init__(self, xt, zt): - self.xt = xt - self.zt = zt - - self.xt_prime = old_div(xt,delta_x) + MXG - 0.5 - self.zt_prime = old_div(zt,delta_pol) - - def unroll_map_coeff(map_list, coeff): - coeff_array = np.transpose(np.resize(np.array([getattr(f, coeff) for f in map_list]).reshape( (nx,nz) ), (ny, nx, nz) ), (1, 0, 2) ) - return coeff_array - - def b_field(vector, y): - x0 = old_div(Lx,2.) # Centre of box, where bz = 0. - x, z = vector; - bx = 0. - bz = Bp + (x-x0) * Bpprime - - return [bx, bz] - - def field_line_tracer(direction, map_list): - - result = np.zeros( (nx, nz, 2) ) - - for i in np.arange(0,nx): - for k in np.arange(0,nz): - result[i,k,:] = odeint(b_field, [x[i], z[k]], [0, delta_tor*direction])[1,:] - map_list.append(Mappoint(result[i,k,0],result[i,k,1])) - - return result - - forward_map = [] - forward_coords = field_line_tracer(+1, forward_map) - backward_map = [] - backward_coords = field_line_tracer(-1, backward_map) - - X,Y = np.meshgrid(x,y,indexing='ij') - x0 = 0.5 - g_22 = old_div(((Bp + (X-x0) * Lx * Bpprime)**2 + Bt**2), Bt**2) - - with bdata.DataFile(filename, write=True, create=True) as f: - f.write('nx', nx) - f.write('ny', ny) - f.write('nz', nz) - f.write("dx", delta_x) - f.write("dy", delta_tor) - f.write("g_22", g_22) - f.write("Bxy", (Bxy)) - - xt_prime = unroll_map_coeff(forward_map, 'xt_prime') - f.write('forward_xt_prime', (xt_prime)) - zt_prime = unroll_map_coeff(forward_map, 'zt_prime') - f.write('forward_zt_prime', (zt_prime)) - - xt_prime = unroll_map_coeff(backward_map, 'xt_prime') - f.write('backward_xt_prime', (xt_prime)) - zt_prime = unroll_map_coeff(backward_map, 'zt_prime') - f.write('backward_zt_prime', (zt_prime)) - - -if __name__ == "__main__": - slab(34, 64, 64, filename="fci.grid.nc") diff --git a/tests/integrated/test-fci-slab/makefile b/tests/integrated/test-fci-slab/makefile deleted file mode 100644 index b0fbe93385..0000000000 --- a/tests/integrated/test-fci-slab/makefile +++ /dev/null @@ -1,6 +0,0 @@ - -BOUT_TOP = ../../.. - -SOURCEC = fci_slab.cxx - -include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-fci-slab/mms.py b/tests/integrated/test-fci-slab/mms.py deleted file mode 100644 index df00c5d68d..0000000000 --- a/tests/integrated/test-fci-slab/mms.py +++ /dev/null @@ -1,47 +0,0 @@ -# -# Generate manufactured solution and sources for FCI test -# - -from __future__ import division -from __future__ import print_function - -from boutdata.mms import * - -from sympy import sin, cos, sqrt - -from math import pi - -f = sin(y - z) + cos(t)*sin(y - 2*z) - -g = cos(y - z) - cos(t)*sin(y - 2*z) - -Lx = 0.1 -Ly = 10. -Lz = 1. - -Bt = 1.0 -Bp = 0.05 -Bpprime = 0.1 - -Bpx = Bp + (x-0.5)*Lx * Bpprime # Note: x in range [0,1] -B = sqrt(Bpx**2 + Bt**2) - -def FCI_Grad_par(f): - return ( Bt * diff(f, y)*2.*pi/Ly + Bpx * diff(f, z)*2.*pi/Lz ) / B - -############################################ -# Equations solved - -dfdt = FCI_Grad_par(g) -dgdt = FCI_Grad_par(f) - -# Loop over variables and print solution, source etc. -for v, dvdt, name in [ (f, dfdt, "f"), (g, dgdt, "g") ]: - # Calculate source - S = diff(v, t) - dvdt - - print("\n["+name+"]") - print("solution = "+exprToStr(v)) - print("\nsource = "+exprToStr(S)) - print("\nbndry_par_all = parallel_dirichlet("+name+":solution)") - diff --git a/tests/integrated/test-fci-slab/mms/BOUT.inp b/tests/integrated/test-fci-slab/mms/BOUT.inp deleted file mode 100644 index 3c1e5f9559..0000000000 --- a/tests/integrated/test-fci-slab/mms/BOUT.inp +++ /dev/null @@ -1,39 +0,0 @@ -grid = fci.grid.nc - -nout = 1 -timestep = 0.01 - -MZ = 64 - -NXPE = 1 - -[mesh] -paralleltransform = fci - -symmetricglobalx = true - -[fci] -y_periodic = false -z_periodic = false - -[interpolation] -type=lagrange4pt - -[solver] -ATOL = 1e-12 -RTOL = 1e-8 -mms = true - -[f] -solution = sin(y - 2*z)*cos(t) + sin(y - z) - -source = -sin(t)*sin(y - 2*z) - (6.28318530717959*(0.01*x + 0.045)*(sin(y - z) + 2*cos(t)*cos(y - 2*z)) - 0.628318530717959*sin(y - z) - 0.628318530717959*cos(t)*cos(y - 2*z))/sqrt((0.01*x + 0.045)^2 + 1.0) - -bndry_par_all = parallel_dirichlet(f:solution) - -[g] -solution = -sin(y - 2*z)*cos(t) + cos(y - z) - -source = sin(t)*sin(y - 2*z) - (6.28318530717959*(0.01*x + 0.045)*(-2*cos(t)*cos(y - 2*z) - cos(y - z)) + 0.628318530717959*cos(t)*cos(y - 2*z) + 0.628318530717959*cos(y - z))/sqrt((0.01*x + 0.045)^2 + 1.0) - -bndry_par_all = parallel_dirichlet(g:solution) diff --git a/tests/integrated/test-fci-slab/plot_funcs.py b/tests/integrated/test-fci-slab/plot_funcs.py deleted file mode 100644 index d233858f8f..0000000000 --- a/tests/integrated/test-fci-slab/plot_funcs.py +++ /dev/null @@ -1,28 +0,0 @@ -from builtins import str -from builtins import range -# Plot interpolating functions -# Input generated by simple_test.py - -from numpy import linspace -import matplotlib.pyplot as plt -from boutdata.collect import collect - -f = collect("f", path="data") -yup = collect("yup", path="data") - -ny = 20 -nz = 8 - -# Note: yup[y=0] is never set -y = linspace(-1, 1, ny-1) - -plt.plot(f[0,4,4,:], 'o', label="f") - -for z in range(nz): - plt.plot(y+z, yup[4,1:,z], label="z = "+str(z)) - -plt.legend(loc='upper center') - -plt.savefig("plot_funcs.pdf") - -plt.show() diff --git a/tests/integrated/test-fci-slab/plot_interp.py b/tests/integrated/test-fci-slab/plot_interp.py deleted file mode 100644 index 2278684fba..0000000000 --- a/tests/integrated/test-fci-slab/plot_interp.py +++ /dev/null @@ -1,17 +0,0 @@ - -import matplotlib.pyplot as plt - -from boutdata.collect import collect - -f = collect("f", path="data") -yup = collect("yup", path="data") -ydown = collect("ydown", path="data") - -plt.plot(f[0,4,4,:], label="f") -plt.plot(yup[4,4,:], label="f.yup") -plt.plot(ydown[4,4,:], label="f.ydown") - -plt.legend() - -plt.savefig("plot_interp.pdf") -plt.show() diff --git a/tests/integrated/test-fci-slab/runtest b/tests/integrated/test-fci-slab/runtest deleted file mode 100755 index 196b2471f0..0000000000 --- a/tests/integrated/test-fci-slab/runtest +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env python3 -# -# Python script to run and analyse MMS test -# -from __future__ import division -from __future__ import print_function -from builtins import zip -from builtins import str - -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun -from boututils.datafile import DataFile -from boutdata.collect import collect - -from numpy import sqrt, max, abs, mean, array, log, pi, polyfit, linspace, arange - -import pickle - -from sys import stdout - -import zoidberg as zb - -showPlot = False #Do we want to show the plot as well as save it to file. - -nx = 5 # Not changed for these tests - -# Resolution in y and z -nlist = [64,128] #[8,16,32,64,128,256] - -nproc = 2 - -directory = "mms" - -varlist = ["f", "g"] -markers = ['bo', 'r^'] -labels = [r'$f$', r'$g$'] - -MPIRUN = getmpirun() - -success=True - -print("Making fci-slab test") -shell_safe("make > make.log") - -error_2 = {} -error_inf = {} -for var in varlist: - error_2[var] = [] # The L2 error (RMS) - error_inf[var] = [] # The maximum error - -yperiodic=False # Run with periodic Y? - -for n in nlist: - - # Define the magnetic field using new poloidal gridding method - # Note that the Bz and Bzprime parameters here must be the same as in mms.py - field = zb.field.Slab(Bz=0.05, Bzprime=0.1) - # Create rectangular poloidal grids - poloidal_grid = zb.poloidal_grid.RectangularPoloidalGrid(nx,n,1.,1.) - # Set the ylength and y locations - ylength = 10. - - if yperiodic: - ycoords = linspace(0.0, ylength, n, endpoint=False) - else: - # Doesn't include the end points - ycoords = (arange(n) + 0.5)*ylength/float(n) - - # Create the grid - grid = zb.grid.Grid(poloidal_grid, ycoords, ylength, yperiodic=yperiodic) - # Make and write maps - maps = zb.make_maps(grid, field) - zb.write_maps(grid, field, maps, new_names=False, metric2d=True) - - args = " -d "+directory+" MZ="+str(n)+ " fci:y_periodic="+str(yperiodic) - - # Command to run - cmd = "./fci_slab "+args - - print("Running command: "+cmd) - - # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, mthread=1, pipe=True) - - # Save output to log file - with open("run.log."+str(n), "w") as f: - f.write(out) - - if s: - print("Run failed!\nOutput was:\n") - print(out) - exit(s) - - for var in varlist: - # Collect data - E = collect("E_"+var, tind=[1,1], info=False, path=directory) - E = E[:,2:-2, :,:] - - # Average error over domain - l2 = sqrt(mean(E**2)) - linf = max(abs( E )) - - error_2[var].append( l2 ) - error_inf[var].append( linf ) - - print("%s : l-2 %f l-inf %f" % (var, l2, linf)) - -dx = 1. / array(nlist) - -# Save data -with open("fci_mms.pkl", "wb") as output: - pickle.dump(nlist, output) - pickle.dump(error_2, output) - pickle.dump(error_inf, output) - -# Calculate convergence order -for var,mark,label in zip(varlist, markers, labels): - fit = polyfit(log(dx), log(error_2[var]), 1) - order = fit[0] - stdout.write("%s Convergence order = %f (fit)" % (var, order)) - - order = log(error_2[var][-2]/error_2[var][-1])/log(dx[-2]/dx[-1]) - stdout.write(", %f (small spacing)" % (order,)) - - if order > 1.5: # Should be second order accurate - print("............ PASS") - else: - print("............ FAIL") - success = False - -if False: - try: - # Plot using matplotlib if available - import matplotlib.pyplot as plt - - plt.figure() - - for var,mark,label in zip(varlist, markers, labels): - plt.plot(dx, error_2[var], '-'+mark, label=label) - plt.plot(dx, error_inf[var], '--'+mark) - - plt.legend(loc="upper left") - plt.grid() - - plt.yscale('log') - plt.xscale('log') - - plt.xlabel(r'Mesh spacing $\delta x$') - plt.ylabel("Error norm") - - plt.savefig("fci-norm.pdf") - - print("Plot saved to fci-norm.pdf") - - if showPlot: - plt.show() - plt.close() - except ImportError: - print("No matplotlib") -else: - print("Plotting disabled") - -if success: - exit(0) -else: - exit(1) diff --git a/tests/integrated/test-fci-slab/simple_test.py b/tests/integrated/test-fci-slab/simple_test.py deleted file mode 100644 index 95f245c8c2..0000000000 --- a/tests/integrated/test-fci-slab/simple_test.py +++ /dev/null @@ -1,32 +0,0 @@ -from builtins import range -from numpy import zeros, linspace, concatenate -import boututils.datafile as bdata -from boutdata.input import transform3D - -# Parameters -nx = 10 -ny = 20 -nz = 8 - -shape = [nx, ny, nz] - -xt_prime = zeros(shape) -zt_prime = zeros(shape) - -for x in range(nx): - # No interpolation in x - xt_prime[x,:,:] = x - - # Each y slice scans between neighbouring z points - for z in range(nz): - zt_prime[x,:,z] = z + concatenate([linspace(-1, 1, ny-1), [0]]) - - -with bdata.DataFile('simple_test.nc', write=True, create=True) as f: - f.write('nx',nx) - f.write('ny',ny) - - for direction_name in ['forward', 'backward']: - f.write(direction_name + '_xt_prime', transform3D(xt_prime)) - f.write(direction_name + '_zt_prime', transform3D(zt_prime)) - From 6d95e434272794b6f32ec3f614ce17a6ad181e53 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 25 Jan 2019 17:42:50 +0000 Subject: [PATCH 0649/1783] Fix outdated comments --- include/field3d.hxx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/field3d.hxx b/include/field3d.hxx index 2274df81a6..f9b23400ba 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -235,7 +235,7 @@ class Field3D : public Field, public FieldData { /// Return reference to yup field Field3D &yup(std::vector::size_type index = 0) { - ASSERT2(index < yup_fields.size()); // Check for communicate + ASSERT2(index < yup_fields.size()); return yup_fields[index]; } /// Return const reference to yup field @@ -256,9 +256,11 @@ class Field3D : public Field, public FieldData { return ydown_fields[index]; } - /// Return yup if dir=+1, and ydown if dir=-1 - Field3D& ynext(int dir); - const Field3D& ynext(int dir) const; + /// Return the parallel slice at \p offset + /// + /// \p offset of 0 returns the main field itself + Field3D& ynext(int offset); + const Field3D& ynext(int offset) const; /// Set variable location for staggered grids to @param new_location /// From 4b0612d1ef71701572192ea00d95d30ea28f5cec Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Mon, 28 Jan 2019 09:59:43 +0000 Subject: [PATCH 0650/1783] Replace #include datafile with class Datafile --- include/bout/run_metrics.hxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/bout/run_metrics.hxx b/include/bout/run_metrics.hxx index b77615ffef..891a65acbf 100644 --- a/include/bout/run_metrics.hxx +++ b/include/bout/run_metrics.hxx @@ -30,7 +30,9 @@ #ifndef __RUNMETRICS_H__ #define __RUNMETRICS_H__ -#include "datafile.hxx" + +class Datafile; +#include "bout_types.hxx" class RunMetrics { From 49de89c40459071d45940899fd78ee0c03259cef Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 29 Jan 2019 10:20:14 +0000 Subject: [PATCH 0651/1783] Reorder namedtuple arguments for compatibility with Python < 3.5 --- tools/pylib/zoidberg/zoidberg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/pylib/zoidberg/zoidberg.py b/tools/pylib/zoidberg/zoidberg.py index 3217b70c76..5833d01134 100644 --- a/tools/pylib/zoidberg/zoidberg.py +++ b/tools/pylib/zoidberg/zoidberg.py @@ -88,7 +88,7 @@ def make_maps(grid, magnetic_field, nslice=1, quiet=False, **kwargs): } # A helper data structure that groups the various field line maps along with the offset - ParallelSlice = namedtuple('ParallelSlice', ['R', 'Z', 'xt_prime', 'zt_prime', 'offset']) + ParallelSlice = namedtuple('ParallelSlice', ['offset', 'R', 'Z', 'xt_prime', 'zt_prime']) # A list of the above data structures for each offset we want parallel_slices = [] @@ -104,7 +104,7 @@ def make_maps(grid, magnetic_field, nslice=1, quiet=False, **kwargs): # Get the field arrays we just made and wrap them up in our helper tuple fields = map(lambda x: maps[x], field_names) - parallel_slices.append(ParallelSlice(*fields, offset)) + parallel_slices.append(ParallelSlice(offset, *fields)) # Total size of the progress bar total_work = float((len(parallel_slices) - 1) * (ny-1)) From 1e3b5469f03f6788dd42189f489998bd1d72d689 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 29 Jan 2019 10:34:11 +0000 Subject: [PATCH 0652/1783] Add some runtime checks for parallel slice consistency --- src/field/field3d.cxx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index c0c85b193a..43b2768bf9 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -135,6 +135,13 @@ Field3D* Field3D::timeDeriv() { void Field3D::splitYupYdown() { TRACE("Field3D::splitYupYdown"); +#if CHECK > 2 + if (yup_fields.size() != ydown_fields.size()) { + throw BoutException("Field3D::splitYupYdown: forward/backward parallel slices not in sync.\n" + " This is an internal library error"); + } +#endif + if (!yup_fields.empty()) { return; } @@ -148,6 +155,13 @@ void Field3D::splitYupYdown() { void Field3D::mergeYupYdown() { TRACE("Field3D::mergeYupYdown"); +#if CHECK > 2 + if (yup_fields.size() != ydown_fields.size()) { + throw BoutException("Field3D::mergeYupYdown: forward/backward parallel slices not in sync.\n" + " This is an internal library error"); + } +#endif + if (yup_fields.empty() && ydown_fields.empty()) { return; } @@ -157,12 +171,14 @@ void Field3D::mergeYupYdown() { } const Field3D& Field3D::ynext(int dir) const { +#if CHECK > 0 // Asked for more than yguards if (std::abs(dir) > fieldmesh->ystart) { throw BoutException( "Field3D: Call to ynext with %d which is more than number of yguards (%d)", dir, fieldmesh->ystart); } +#endif // ynext uses 1-indexing, but yup wants 0-indexing if (dir > 0) { From 07e3bdbf6aeb65ac9d0ae4df5b33e7f15d7b553d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Tue, 29 Jan 2019 11:05:59 +0000 Subject: [PATCH 0653/1783] Remove commented out code --- tools/pylib/_boutcore_build/helper.h.in | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tools/pylib/_boutcore_build/helper.h.in b/tools/pylib/_boutcore_build/helper.h.in index ce69e96646..5b69f71ea1 100644 --- a/tools/pylib/_boutcore_build/helper.h.in +++ b/tools/pylib/_boutcore_build/helper.h.in @@ -39,10 +39,6 @@ done for vec in $vecs do setvars $vec - #if [ $vec = "Vector2D" ]; then field=Field2D - #elif [ $vec = "Vector3D" ]; then field=Field2D - #else echo "$vec - Not implemented" ; exit 2 - #fi cat <outputVars(dump); solver->solve(); } Solver * getSolver(){ return solver; }; private: - //void (*init_func)(bool); - //void (*rhs_func)(BoutReal time); PythonModelCallback * _init; PythonModelCallback * _rhs; Solver * solver; From aaa33f6dee43498b104762f5d4c090099a362760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Tue, 29 Jan 2019 11:08:53 +0000 Subject: [PATCH 0654/1783] use setvars also for fields * Reduces duplicated code * Should help with adding FieldPerp Also move function makelists to common.sh --- tools/pylib/_boutcore_build/boutcore.pyx.in | 34 ++++----------------- tools/pylib/_boutcore_build/boutcpp.pxd.in | 8 ++--- tools/pylib/_boutcore_build/common.sh | 34 +++++++++++++++++++++ tools/pylib/_boutcore_build/helper.cxx.in | 5 ++- tools/pylib/_boutcore_build/helper.h.in | 10 ++---- 5 files changed, 49 insertions(+), 42 deletions(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 12c964c9f1..e6f9d2ac27 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -28,7 +28,9 @@ do fi done -# needed sometimes to add include dir ... +# needed sometimes to add include dir +# We need the header files for numpy, which are (hopefully) somewhere +# in the python directories. python_dirs=$($PY -c "import site; print('\n'.join(site.getsitepackages()))") numpyheader=$(for d in $python_dirs do @@ -65,37 +67,13 @@ cdef extern from "boutexception_helper.hxx": cdef void raise_bout_py_error() EOF -# make a list of the format "nx, ny, nz" or something similar -# 'n$d' gets expaneded to "nx, ny, nz" -# 'f[$i]' to "f[0], f[1], f[2]" -# NB: use single ticks to prevent to early expansion -makelist () { - format="$1" - test $# -gt 1 && - spacing="$2" || spacing=", " - start="" ; i=0 - for d in ${dims[@]} ; do - echo -n "$start" ; - eval echo -n "\"$format\"" - start="$spacing" ; i=$(( i + 1 )) - done ; } +# Include list of fields, and some functions . common.sh -for ftype in "Field3D" "Field2D" +for ftype in $fields do - if [ $ftype = "Field3D" ]; then - fdd="f3d" - ndim=3 - dims=(x y z) - elif [ $ftype = "Field2D" ]; then - fdd="f2d" - ndim=2 - dims=(x y) - else - echo "Error, unimplemented ftype" - exit 1 - fi + setvars $ftype cat < #include @@ -5,7 +8,7 @@ cat < #include EOF -for ftype in "Field3D" "Field2D" +for ftype in $fields do if [ $ftype = "Field3D" ]; then fdd="f3d"; elif [ $ftype = "Field2D" ]; then fdd="f2d"; diff --git a/tools/pylib/_boutcore_build/helper.h.in b/tools/pylib/_boutcore_build/helper.h.in index 5b69f71ea1..ec86ee7e82 100644 --- a/tools/pylib/_boutcore_build/helper.h.in +++ b/tools/pylib/_boutcore_build/helper.h.in @@ -5,14 +5,10 @@ cat < EOF -for ftype in "Field3D" "Field2D" +for ftype in $fields do - if [ $ftype = "Field3D" ]; then fdd="f3d"; - elif [ $ftype = "Field2D" ]; then fdd="f2d"; - else - echo "Error, unimplemented ftype"; exit 1 - fi -cat < Date: Tue, 29 Jan 2019 11:31:55 +0000 Subject: [PATCH 0655/1783] Guard unit tests for Field3D::ynext --- tests/unit/field/test_field3d.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index c6fe34f8c3..b9b9aac33b 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -284,7 +284,9 @@ TEST_F(Field3DTest, Ynext) { EXPECT_NE(&field, &ydown); EXPECT_NE(&yup, &ydown); +#if CHECK > 0 EXPECT_THROW(field.ynext(99), BoutException); +#endif } TEST_F(Field3DTest, ConstYnext) { @@ -300,7 +302,9 @@ TEST_F(Field3DTest, ConstYnext) { EXPECT_NE(&field2, &ydown); EXPECT_NE(&yup, &ydown); +#if CHECK > 0 EXPECT_THROW(field2.ynext(99), BoutException); +#endif } TEST_F(Field3DTest, GetGlobalMesh) { From 14cb3f3d4886c41240b7c01c01ad7c69db7c784d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Tue, 29 Jan 2019 11:41:18 +0000 Subject: [PATCH 0656/1783] update to new interface enum DIFF_METHOD is replaced by string The new interface does not support 'DIFF_' at the start of the string, so that needs to be removed, to remain compatible with old code. As before, the DIFF_ at the start is not required. --- tools/pylib/_boutcore_build/boutcore.pyx.in | 8 ++++++-- tools/pylib/_boutcore_build/boutcpp.pxd.in | 12 ++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index e6f9d2ac27..ae9fa592c6 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -1157,7 +1157,9 @@ def $DD($in1, outloc="CELL_DEFAULT", method="DIFF_DEFAULT", region="RGN_NOBNDRY" """ checkInit() cdef benum.CELL_LOC outloc_= benum.resolve_cell_loc(outloc) - cdef benum.DIFF_METHOD method_=benum.resolve_diff_method(method) + if method.startswith("DIFF_"): + method=method[5:] + cdef c.string method_ = method.encode('ascii') cdef benum.REGION region_=benum.resolve_region(region) return f3dFromObj(c.$DD($in2,outloc_,method_,region_)) EOF @@ -1205,7 +1207,9 @@ def $DD($in1, outloc="CELL_DEFAULT", method="DIFF_DEFAULT", region="RGN_NOBNDRY" """ checkInit() cdef benum.CELL_LOC outloc_= benum.resolve_cell_loc(outloc) - cdef benum.DIFF_METHOD method_=benum.resolve_diff_method(method) + if method.startswith("DIFF_"): + method=method[5:] + cdef c.string method_=method.encode('ascii') return ${rdd}FromObj(c.$DD($in2,outloc_,method_)) EOF } diff --git a/tools/pylib/_boutcore_build/boutcpp.pxd.in b/tools/pylib/_boutcore_build/boutcpp.pxd.in index 56eaf62bd0..c8bf368ac0 100755 --- a/tools/pylib/_boutcore_build/boutcpp.pxd.in +++ b/tools/pylib/_boutcore_build/boutcpp.pxd.in @@ -121,11 +121,11 @@ cdef extern from "invert_laplace.hxx": void setCoefEz(Field3D) cdef extern from "difops.hxx": - Field3D Div_par(Field3D, benum.CELL_LOC, benum.DIFF_METHOD) - Field3D Grad_par(Field3D, benum.CELL_LOC, benum.DIFF_METHOD) - Vector3D Grad_perp(Field3D, benum.CELL_LOC, benum.DIFF_METHOD) + Field3D Div_par(Field3D, benum.CELL_LOC, string) + Field3D Grad_par(Field3D, benum.CELL_LOC, string) + Vector3D Grad_perp(Field3D, benum.CELL_LOC, string) Field3D Laplace(Field3D) - Field3D Vpar_Grad_par(Field3D, Field3D, benum.CELL_LOC, benum.DIFF_METHOD) + Field3D Vpar_Grad_par(Field3D, Field3D, benum.CELL_LOC, string) Field3D bracket(Field3D,Field3D, benum.BRACKET_METHOD, benum.CELL_LOC) Field3D Delp2(Field3D) @@ -155,12 +155,12 @@ do for f in DDd D2Dd2 #VDDd FDDd do DD=${f/d/$d} - echo " Field3D $DD(Field3D, benum.CELL_LOC, benum.DIFF_METHOD, benum.REGION) except +raise_bout_py_error" + echo " Field3D $DD(Field3D, benum.CELL_LOC, string, benum.REGION) except +raise_bout_py_error" done for f in VDDd FDDd do DD=${f/d/$d} - echo " Field3D $DD(Field3D, Field3D, benum.CELL_LOC, benum.DIFF_METHOD, benum.REGION) except +raise_bout_py_error" + echo " Field3D $DD(Field3D, Field3D, benum.CELL_LOC, string, benum.REGION) except +raise_bout_py_error" done done cat < Date: Tue, 29 Jan 2019 11:42:45 +0000 Subject: [PATCH 0657/1783] Add dependencies in makefile bin/bout-config may be changed to change flags or libraries commons.sh may be changed to add or remove fields --- tools/pylib/_boutcore_build/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pylib/_boutcore_build/Makefile b/tools/pylib/_boutcore_build/Makefile index a5fa87a795..9bb890d215 100644 --- a/tools/pylib/_boutcore_build/Makefile +++ b/tools/pylib/_boutcore_build/Makefile @@ -9,7 +9,7 @@ helper.cxx:helper.cxx.in boutcpp.pxd:boutcpp.pxd.in TOGEN=setup.py boutcore.pyx resolve_enum.pxd helper.cxx helper.h boutcpp.pxd -$(TOGEN): Makefile $(BOUT_TOP)/make.config +$(TOGEN): Makefile $(BOUT_TOP)/make.config $(BOUT_TOP)/bin/bout-config common.sh @echo " Generating $@" @PATH=$(BOUT_TOP)/bin:$$PATH PY=$(PY) bash $@.in > $@.tmp \ || (fail=$$?; echo "touch $@ to ignore failed generation" ; exit $$fail) From 563e0008322003f3fa64d59f17cc9ed534d106c1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 29 Jan 2019 17:20:03 +0000 Subject: [PATCH 0658/1783] Add basic sanity tests for standard derivatives --- tests/unit/include/test_derivs.cxx | 74 ++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 tests/unit/include/test_derivs.cxx diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx new file mode 100644 index 0000000000..8dc6921d8e --- /dev/null +++ b/tests/unit/include/test_derivs.cxx @@ -0,0 +1,74 @@ +#include "gtest/gtest.h" + +#include "bout/constants.hxx" +#include "bout/deriv_store.hxx" +#include "bout_types.hxx" +#include "field3d.hxx" +#include "test_extras.hxx" + +#include + +// We don't just inherit from FakeMeshTest as we want to increase nx +// to get reasonable agreement +class DerivativesTest : public ::testing::TestWithParam { +public: + DerivativesTest() : input{mesh}, expected{mesh} { + if (mesh != nullptr) { + delete mesh; + mesh = nullptr; + } + mesh = new FakeMesh(nx, ny, nz); + mesh->xstart = 2; + mesh->xend = nx - 3; + + mesh->ystart = 0; + mesh->yend = ny - 1; + + output_info.disable(); + mesh->createDefaultRegions(); + output_info.enable(); + + Field3D input_{mesh}; + input_.allocate(); + + for (auto i : input_) { + input_[i] = std::sin(i.x() * TWOPI / (nx - 1)); + } + + input = input_; + + Field3D expected_{mesh}; + expected_.allocate(); + + for (auto i : expected_) { + expected_[i] = std::cos(i.x() * TWOPI / (nx - 1)) * TWOPI / (nx - 1); + } + + expected = expected_; + + DerivativeStore::getInstance().initialise(Options::getRoot()); + }; + + Field3D input; + Field3D expected; + + static constexpr int nx = 64; + static constexpr int ny = 3; + static constexpr int nz = 2; +}; + +INSTANTIATE_TEST_CASE_P(SanityCheck, DerivativesTest, + ::testing::ValuesIn(DerivativeStore::getInstance() + .getAvailableMethods(DERIV::Standard, + DIRECTION::X))); + +TEST_P(DerivativesTest, Basic) { + auto derivative = DerivativeStore::getInstance().getStandardDerivative( + GetParam(), DIRECTION::X); + + Field3D result{mesh}; + result.allocate(); + derivative(input, result, RGN_NOX); + + EXPECT_TRUE(IsField3DEqualField3D(result, expected, "RGN_NOBNDRY", 1.e-2)); +} From f30f4b36924555ab6400e2e9a0f06358eac76d20 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Thu, 31 Jan 2019 09:47:57 +0000 Subject: [PATCH 0659/1783] Revise downwards the acceptable profiling overhead --- manual/sphinx/developer_docs/performance_profiling.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index 0cc0435708..ea5182d70d 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -47,8 +47,8 @@ result in misleading profiling information, particularly if fast-but-frequently-called functions are instrumented. Try to instrument significant functions only. -This notwithstanding, it is reasonable to expect sensibly-instrumented code to -run about 50% to 100% slower than the uninstrumented code. +The profiling overhead in sensibly-instrumented code should be only a few +percent of runtime. Configure and build ~~~~~~~~~~~~~~~~~~~ From f4a48c30fe277943f9d4f4437ddd72c15c810064 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Thu, 31 Jan 2019 09:49:20 +0000 Subject: [PATCH 0660/1783] Make machine specific installation a subsection of Scalasca --- manual/sphinx/developer_docs/performance_profiling.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index ea5182d70d..ea415883b3 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -80,13 +80,13 @@ number of processors, it is necessary to move or delete the first archive. .. _sec-machine-specific: Machine-specific installation ------------------------------ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These are some configurations which have been found to work on particular machines. Archer -~~~~~~ +^^^^^^ As of 23rd January 2019, the following configuration should work From 93d8f6cd355ffd086287f1015dad8e98fbe3feb5 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Thu, 31 Jan 2019 12:34:43 +0000 Subject: [PATCH 0661/1783] Add section on extrae profiling TODO: + section on paraver analysis + machine-specific instructions for Archer --- .../developer_docs/performance_profiling.rst | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index ea415883b3..7c0f32de87 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -59,6 +59,9 @@ desirable to profile the optimized code, configuring with the flags ``--enable-optimize=3 --enable-checks=0``. Build the code with ``make`` as normal. +Running +~~~~~~~ + When running the code, prepend the run command with ``scalasca -analyze``, e.g. .. code-block:: bash @@ -77,8 +80,6 @@ Note that Scorep does not run if doing so would produce an archive with the same name as an existing archive. Therefore to rerun an executable on the same number of processors, it is necessary to move or delete the first archive. -.. _sec-machine-specific: - Machine-specific installation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -104,4 +105,55 @@ Note that due to a bug in the ``CC`` compiler, it is necessary to modify * add the flag ``--thread=omp:ancestry`` as an argument to ``scorep`` in ``CXX`` +Extrae/Paraver profiling +------------------------ + +[Extrae](https://tools.bsc.es/extrae) is a powerful tool allowing visualization +of commumication and computation in parallel codes. It requires minimal +instrumentation; however the trace files produced can be extremely large. + +Instrumentation, configure and build +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +No changes to the code are necessary. On some systems, environment variables +must be set before building. Otherwise, compile and build as normal. + +Running +~~~~~~~ + +To run, add a trace script into the normal run command, so that for example + +.. code-block:: bash + + $ aprun -n 16 blob2d -d delta_1 + +becomes + +.. code-block:: bash + + $ aprun -n 16 ./trace.sh blob2d -d delta_1 + +where ``trace.sh`` is the script file + +.. code-block:: bash + + #!/bin/bash + + export EXTRAE_CONFIG_FILE=./extrae.xml + export LD_PRELOAD=${EXTRAE_HOME}/lib/libmpitrace.so + + $* + +The run directory must also contain the file ``extrae.xml``, which configures +which data Extrae collects. Example ``extrae.xml`` files may be found in +``${EXTRAE_HOME}/share/example/*/extrae.xml`` + +Running produces a file called ``TRACE.mpits``. To generate the ``.prv`` trace +file that can be read by Paraver, do + +.. code-block:: bash + + TRACE_NAME=bout.prv + ${EXTRAE_HOME}/bin/mpi2prv -f ${EXTRAE_WORK_DIR}/TRACE.mpits -o ${TRACE_NAME} + From 0e64dc41cca54070716f8a2e4c7ff4b8c7460be0 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Thu, 31 Jan 2019 12:57:57 +0000 Subject: [PATCH 0662/1783] Correct Extrae hyperlink --- manual/sphinx/developer_docs/performance_profiling.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index 7c0f32de87..5b73acdbcc 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -108,7 +108,7 @@ Note that due to a bug in the ``CC`` compiler, it is necessary to modify Extrae/Paraver profiling ------------------------ -[Extrae](https://tools.bsc.es/extrae) is a powerful tool allowing visualization +`Extrae `_ is a powerful tool allowing visualization of commumication and computation in parallel codes. It requires minimal instrumentation; however the trace files produced can be extremely large. From 732fdb0af6f29862f8d15bda5201366581355067 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 31 Jan 2019 15:43:57 +0000 Subject: [PATCH 0663/1783] Remove checkData from copy constructor and assignment operator in Fields --- src/field/field2d.cxx | 6 ------ src/field/field3d.cxx | 15 --------------- src/field/fieldperp.cxx | 4 ---- 3 files changed, 25 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 02f2a2e480..bcfe3bd20c 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -64,10 +64,6 @@ Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), data(f.data) { name = f.name; #endif -#if CHECK > 2 - checkData(f); -#endif - if (fieldmesh) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; @@ -171,8 +167,6 @@ Field2D &Field2D::operator=(const Field2D &rhs) { TRACE("Field2D: Assignment from Field2D"); - checkData(rhs); - #ifdef TRACK name = rhs.name; #endif diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 65511f428a..64e3593b34 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -62,10 +62,6 @@ Field3D::Field3D(const Field3D& f) : Field(f.fieldmesh), data(f.data) { TRACE("Field3D(Field3D&)"); -#if CHECK > 2 - checkData(f); -#endif - if (fieldmesh) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; @@ -270,9 +266,6 @@ Field3D & Field3D::operator=(const Field3D &rhs) { TRACE("Field3D: Assignment from Field3D"); - /// Check that the data is valid - checkData(rhs); - // Copy the data and data sizes fieldmesh = rhs.fieldmesh; nx = rhs.nx; ny = rhs.ny; nz = rhs.nz; @@ -286,9 +279,6 @@ Field3D & Field3D::operator=(const Field3D &rhs) { Field3D & Field3D::operator=(const Field2D &rhs) { TRACE("Field3D = Field2D"); - - /// Check that the data is valid - checkData(rhs); /// Make sure there's a unique array to copy data into allocate(); @@ -306,9 +296,6 @@ void Field3D::operator=(const FieldPerp &rhs) { ASSERT1(location == rhs.getLocation()); - /// Check that the data is valid - checkData(rhs); - /// Make sure there's a unique array to copy data into allocate(); @@ -322,8 +309,6 @@ void Field3D::operator=(const FieldPerp &rhs) { Field3D & Field3D::operator=(const BoutReal val) { TRACE("Field3D = BoutReal"); - /// Check that the data is valid - checkData(val); allocate(); diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 5787f0ce29..07686b90f3 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -107,8 +107,6 @@ FieldPerp &FieldPerp::operator=(const FieldPerp &rhs) { return (*this); // skip this assignment } - checkData(rhs); - nx = rhs.nx; nz = rhs.nz; yindex = rhs.yindex; @@ -123,8 +121,6 @@ FieldPerp & FieldPerp::operator=(const BoutReal rhs) { allocate(); - checkData(rhs); - BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] = rhs; } return *this; From c78fd5c2deca4358e13dc85b47d334a99a37f966 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 31 Jan 2019 16:25:18 +0000 Subject: [PATCH 0664/1783] Partially revert "Remove checkData from copy constructor and assignment operator in Fields" This partially reverts commit 732fdb0af6f29862f8d15bda5201366581355067. --- src/field/field2d.cxx | 6 ++++++ src/field/field3d.cxx | 15 +++++++++++++++ src/field/fieldperp.cxx | 4 ++++ 3 files changed, 25 insertions(+) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index bcfe3bd20c..02f2a2e480 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -64,6 +64,10 @@ Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), data(f.data) { name = f.name; #endif +#if CHECK > 2 + checkData(f); +#endif + if (fieldmesh) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; @@ -167,6 +171,8 @@ Field2D &Field2D::operator=(const Field2D &rhs) { TRACE("Field2D: Assignment from Field2D"); + checkData(rhs); + #ifdef TRACK name = rhs.name; #endif diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 64e3593b34..65511f428a 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -62,6 +62,10 @@ Field3D::Field3D(const Field3D& f) : Field(f.fieldmesh), data(f.data) { TRACE("Field3D(Field3D&)"); +#if CHECK > 2 + checkData(f); +#endif + if (fieldmesh) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; @@ -266,6 +270,9 @@ Field3D & Field3D::operator=(const Field3D &rhs) { TRACE("Field3D: Assignment from Field3D"); + /// Check that the data is valid + checkData(rhs); + // Copy the data and data sizes fieldmesh = rhs.fieldmesh; nx = rhs.nx; ny = rhs.ny; nz = rhs.nz; @@ -279,6 +286,9 @@ Field3D & Field3D::operator=(const Field3D &rhs) { Field3D & Field3D::operator=(const Field2D &rhs) { TRACE("Field3D = Field2D"); + + /// Check that the data is valid + checkData(rhs); /// Make sure there's a unique array to copy data into allocate(); @@ -296,6 +306,9 @@ void Field3D::operator=(const FieldPerp &rhs) { ASSERT1(location == rhs.getLocation()); + /// Check that the data is valid + checkData(rhs); + /// Make sure there's a unique array to copy data into allocate(); @@ -309,6 +322,8 @@ void Field3D::operator=(const FieldPerp &rhs) { Field3D & Field3D::operator=(const BoutReal val) { TRACE("Field3D = BoutReal"); + /// Check that the data is valid + checkData(val); allocate(); diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 07686b90f3..5787f0ce29 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -107,6 +107,8 @@ FieldPerp &FieldPerp::operator=(const FieldPerp &rhs) { return (*this); // skip this assignment } + checkData(rhs); + nx = rhs.nx; nz = rhs.nz; yindex = rhs.yindex; @@ -121,6 +123,8 @@ FieldPerp & FieldPerp::operator=(const BoutReal rhs) { allocate(); + checkData(rhs); + BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] = rhs; } return *this; From 88bb50a6d23377a8ed87871f2b25dc04f8f14c0c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 31 Jan 2019 16:26:10 +0000 Subject: [PATCH 0665/1783] Update unit tests for checkData removals --- tests/unit/field/test_field3d.cxx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 487da64e56..295379fcce 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -1030,10 +1030,8 @@ TEST_F(Field3DTest, AssignFromField3D) { EXPECT_TRUE(IsField3DEqualBoutReal(field, -99.0)); -#if CHECK > 0 Field3D field3; - EXPECT_THROW(field = field3, BoutException); -#endif + EXPECT_NO_THROW(field = field3); } //-------------------- Arithmetic tests -------------------- From 168aa54e14f34df3cff478649fdf9371c22d9c47 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 31 Jan 2019 16:26:39 +0000 Subject: [PATCH 0666/1783] Actually remove the checkData calls --- src/field/field2d.cxx | 6 ------ src/field/field3d.cxx | 7 ------- src/field/fieldperp.cxx | 2 -- 3 files changed, 15 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 02f2a2e480..bcfe3bd20c 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -64,10 +64,6 @@ Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), data(f.data) { name = f.name; #endif -#if CHECK > 2 - checkData(f); -#endif - if (fieldmesh) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; @@ -171,8 +167,6 @@ Field2D &Field2D::operator=(const Field2D &rhs) { TRACE("Field2D: Assignment from Field2D"); - checkData(rhs); - #ifdef TRACK name = rhs.name; #endif diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 65511f428a..a2d4a24ebe 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -62,10 +62,6 @@ Field3D::Field3D(const Field3D& f) : Field(f.fieldmesh), data(f.data) { TRACE("Field3D(Field3D&)"); -#if CHECK > 2 - checkData(f); -#endif - if (fieldmesh) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; @@ -270,9 +266,6 @@ Field3D & Field3D::operator=(const Field3D &rhs) { TRACE("Field3D: Assignment from Field3D"); - /// Check that the data is valid - checkData(rhs); - // Copy the data and data sizes fieldmesh = rhs.fieldmesh; nx = rhs.nx; ny = rhs.ny; nz = rhs.nz; diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 5787f0ce29..602dfbf8eb 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -107,8 +107,6 @@ FieldPerp &FieldPerp::operator=(const FieldPerp &rhs) { return (*this); // skip this assignment } - checkData(rhs); - nx = rhs.nx; nz = rhs.nz; yindex = rhs.yindex; From 4ddc5f161418407c40aea9e0308db01af6ab372c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 31 Jan 2019 16:58:40 +0000 Subject: [PATCH 0667/1783] Test all first and second derivatives in X, Y and Z --- tests/unit/include/test_derivs.cxx | 198 +++++++++++++++++++++++++---- 1 file changed, 170 insertions(+), 28 deletions(-) diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index 8dc6921d8e..c4ef4384d4 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -1,28 +1,80 @@ #include "gtest/gtest.h" -#include "bout/constants.hxx" -#include "bout/deriv_store.hxx" #include "bout_types.hxx" +#include "fft.hxx" #include "field3d.hxx" #include "test_extras.hxx" +#include "bout/constants.hxx" +#include "bout/deriv_store.hxx" +#include "bout/paralleltransform.hxx" +#include #include +#include +#include -// We don't just inherit from FakeMeshTest as we want to increase nx -// to get reasonable agreement -class DerivativesTest : public ::testing::TestWithParam { +namespace { +// These are merely sanity checks, so don't expect them to agree very well! +constexpr BoutReal derivatives_tolerance{1.e-2}; +} + +class DerivativesTest + : public ::testing::TestWithParam> { public: - DerivativesTest() : input{mesh}, expected{mesh} { + DerivativesTest() : input{mesh}, first_order_expected{mesh} { + + // Make sure fft functions are quiet by setting fft_measure to false + bout::fft::fft_init(false); + + using Index = Field3D::ind_type; + + // Pointer to index method that converts to index-space + using DirectionFunction = int (Index::*)() const; + DirectionFunction dir; + + // Number of guard cells in (x, y). The "other" direction will + // have none + int x_guards{0}; + int y_guards{0}; + + // This must be a balance between getting any kind of accuracy and + // each derivative running in ~1ms or less + constexpr int grid_size{64}; + const BoutReal box_length{TWOPI / grid_size}; + + switch (std::get<0>(GetParam())) { + case DIRECTION::X: + nx = grid_size; + dir = &Index::x; + x_guards = 2; + region = RGN_NOX; + break; + case DIRECTION::Y: + ny = grid_size; + dir = &Index::y; + y_guards = 2; + region = RGN_NOY; + break; + case DIRECTION::Z: + nz = grid_size; + dir = &Index::z; + region = RGN_ALL; + break; + default: + throw BoutException("bad direction"); + } + if (mesh != nullptr) { delete mesh; mesh = nullptr; } + mesh = new FakeMesh(nx, ny, nz); - mesh->xstart = 2; - mesh->xend = nx - 3; - mesh->ystart = 0; - mesh->yend = ny - 1; + mesh->xstart = x_guards; + mesh->xend = nx - (x_guards + 1); + mesh->ystart = y_guards; + mesh->yend = ny - (y_guards + 1); output_info.disable(); mesh->createDefaultRegions(); @@ -32,43 +84,133 @@ class DerivativesTest : public ::testing::TestWithParam { input_.allocate(); for (auto i : input_) { - input_[i] = std::sin(i.x() * TWOPI / (nx - 1)); + input_[i] = std::sin((i.*dir)() * box_length); } input = input_; - Field3D expected_{mesh}; - expected_.allocate(); + // We need the parallel slices for the y-direction + ParallelTransformIdentity identity{}; + identity.calcYUpDown(input); - for (auto i : expected_) { - expected_[i] = std::cos(i.x() * TWOPI / (nx - 1)) * TWOPI / (nx - 1); + Field3D first_order_expected_{mesh}; + first_order_expected_.allocate(); + + for (auto i : first_order_expected_) { + first_order_expected_[i] = std::cos((i.*dir)() * box_length) * box_length; + } + + first_order_expected = first_order_expected_; + + Field3D second_order_expected_{mesh}; + second_order_expected_.allocate(); + + for (auto i : second_order_expected_) { + second_order_expected_[i] = -std::sin((i.*dir)() * box_length) * pow(box_length, 2); } - expected = expected_; + second_order_expected = second_order_expected_; DerivativeStore::getInstance().initialise(Options::getRoot()); }; Field3D input; - Field3D expected; + Field3D first_order_expected; + Field3D second_order_expected; + + int nx{3}; + int ny{3}; + int nz{2}; + + REGION region; +}; + +// Get all the available methods for this direction and turn it from a +// collection of strings to a collection of pairs of the direction and +// strings so that the test fixture knows which direction we're using +auto getMethodsForDirection(DERIV derivative_order, DIRECTION direction) + -> std::vector> { - static constexpr int nx = 64; - static constexpr int ny = 3; - static constexpr int nz = 2; + auto available_methods = DerivativeStore::getInstance().getAvailableMethods( + derivative_order, direction); + + // Method names paired with the current direction + std::vector> methods{}; + + std::transform(std::begin(available_methods), std::end(available_methods), + std::back_inserter(methods), [&direction](std::string method) { + return std::make_pair(direction, method); + }); + + return methods; }; -INSTANTIATE_TEST_CASE_P(SanityCheck, DerivativesTest, - ::testing::ValuesIn(DerivativeStore::getInstance() - .getAvailableMethods(DERIV::Standard, - DIRECTION::X))); +// Returns the method out of the direction/method pair for printing +// the test name +auto methodDirectionPairToString( + const ::testing::TestParamInfo>& param) + -> std::string { + return std::get<1>(param.param); +} + +using FirstDerivatives = DerivativesTest; -TEST_P(DerivativesTest, Basic) { +// Instantiate the test for X, Y, Z for first derivatives +INSTANTIATE_TEST_CASE_P(X, FirstDerivatives, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, + DIRECTION::X)), + methodDirectionPairToString); + +INSTANTIATE_TEST_CASE_P(Y, FirstDerivatives, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, + DIRECTION::Y)), + methodDirectionPairToString); + +INSTANTIATE_TEST_CASE_P(Z, FirstDerivatives, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, + DIRECTION::Z)), + methodDirectionPairToString); + +// The actual first derivative test! +TEST_P(FirstDerivatives, FirstOrder) { auto derivative = DerivativeStore::getInstance().getStandardDerivative( - GetParam(), DIRECTION::X); + std::get<1>(GetParam()), std::get<0>(GetParam())); + + Field3D result{mesh}; + result.allocate(); + derivative(input, result, region); + + EXPECT_TRUE(IsField3DEqualField3D(result, first_order_expected, "RGN_NOBNDRY", + derivatives_tolerance)); +} + +using SecondDerivatives = DerivativesTest; + +// Instantiate the test for X, Y, Z for second derivatives +INSTANTIATE_TEST_CASE_P(X, SecondDerivatives, + ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, + DIRECTION::X)), + methodDirectionPairToString); + +INSTANTIATE_TEST_CASE_P(Y, SecondDerivatives, + ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, + DIRECTION::Y)), + methodDirectionPairToString); + +INSTANTIATE_TEST_CASE_P(Z, SecondDerivatives, + ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, + DIRECTION::Z)), + methodDirectionPairToString); + +// The actual second derivative test! +TEST_P(SecondDerivatives, SecondOrder) { + auto derivative = DerivativeStore::getInstance().getStandard2ndDerivative( + std::get<1>(GetParam()), std::get<0>(GetParam())); Field3D result{mesh}; result.allocate(); - derivative(input, result, RGN_NOX); + derivative(input, result, region); - EXPECT_TRUE(IsField3DEqualField3D(result, expected, "RGN_NOBNDRY", 1.e-2)); + EXPECT_TRUE(IsField3DEqualField3D(result, second_order_expected, "RGN_NOBNDRY", + derivatives_tolerance)); } From c09bbf0c90d6ef025e9ba0c4eb8b97760b39ec0d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 31 Jan 2019 17:47:55 +0000 Subject: [PATCH 0668/1783] Add helper function for filling fields with function at each point Also add lovely explaining comments --- tests/unit/include/test_derivs.cxx | 54 +++++++++++++++++------------- tests/unit/test_extras.hxx | 19 +++++++++++ 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index c4ef4384d4..586702b70d 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -13,6 +13,22 @@ #include #include +// Some basic sanity checks for the derivative kernels. Checks the +// derivatives of sin(R) where R = {X, Y, Z} for each R +// individually. To make this as fast as possible, we use only a +// couple of points in the non-tested directions -- not just one +// though, as this allows us to check we're not introducing spurious +// variation in the other directions. +// +// This is one of the more complicated uses of googletest! We need to +// all combinations of methods and directions. Unfortunately, Z has +// one more method than X and Y -- FFT. This means we can't just use +// the provided `Combine` to produce the Cartesian product of +// directions and methods as the latter depends on the +// former. Instead, we instantiate the tests separately for each +// direction and test all the methods for that direction in that +// instantiation. + namespace { // These are merely sanity checks, so don't expect them to agree very well! constexpr BoutReal derivatives_tolerance{1.e-2}; @@ -42,6 +58,8 @@ class DerivativesTest constexpr int grid_size{64}; const BoutReal box_length{TWOPI / grid_size}; + // Set all the variables for this direction + // In C++14 this can be the more explicit std::get() switch (std::get<0>(GetParam())) { case DIRECTION::X: nx = grid_size; @@ -80,37 +98,23 @@ class DerivativesTest mesh->createDefaultRegions(); output_info.enable(); - Field3D input_{mesh}; - input_.allocate(); + // Make the input and expected output fields + // Weird `(i.*dir)()` syntax here in order to call the direction method + // C++17 makes this nicer with std::invoke + input = makeField([&](Index& i) { return std::sin((i.*dir)() * box_length); }, mesh); - for (auto i : input_) { - input_[i] = std::sin((i.*dir)() * box_length); - } + first_order_expected = makeField( + [&](Index& i) { return std::cos((i.*dir)() * box_length) * box_length; }, mesh); - input = input_; + second_order_expected = makeField( + [&](Index& i) { return -std::sin((i.*dir)() * box_length) * pow(box_length, 2); }, + mesh); // We need the parallel slices for the y-direction ParallelTransformIdentity identity{}; identity.calcYUpDown(input); - Field3D first_order_expected_{mesh}; - first_order_expected_.allocate(); - - for (auto i : first_order_expected_) { - first_order_expected_[i] = std::cos((i.*dir)() * box_length) * box_length; - } - - first_order_expected = first_order_expected_; - - Field3D second_order_expected_{mesh}; - second_order_expected_.allocate(); - - for (auto i : second_order_expected_) { - second_order_expected_[i] = -std::sin((i.*dir)() * box_length) * pow(box_length, 2); - } - - second_order_expected = second_order_expected_; - + // FIXME: remove when defaults are set in the DerivativeStore ctor DerivativeStore::getInstance().initialise(Options::getRoot()); }; @@ -153,6 +157,7 @@ auto methodDirectionPairToString( return std::get<1>(param.param); } +// Use an alias to distinguish the first and second derivative tests using FirstDerivatives = DerivativesTest; // Instantiate the test for X, Y, Z for first derivatives @@ -184,6 +189,7 @@ TEST_P(FirstDerivatives, FirstOrder) { derivatives_tolerance)); } +// Use an alias to distinguish the first and second derivative tests using SecondDerivatives = DerivativesTest; // Instantiate the test for X, Y, Z for second derivatives diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index a4593c8657..0dd4a91b1f 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -3,6 +3,7 @@ #include "gtest/gtest.h" +#include #include #include #include @@ -41,6 +42,24 @@ const BoutReal BoutRealTolerance = 1e-15; void fillField(Field3D& f, std::vector>> values); void fillField(Field2D& f, std::vector> values); +/// Enable a function if T is a subclass of Field +template +using EnableIfField = typename std::enable_if::value>::type; + +/// Returns a field filled with the result of \p fill_function at each point +/// Arbitrary arguments can be passed to the field constructor +template > +T makeField(std::function fill_function, Args... args) { + T result{std::forward(args)...}; + result.allocate(); + + for (auto i: result) { + result[i] = fill_function(i); + } + + return result; +} + /// Teach googletest how to print SpecificInds template inline std::ostream& operator<< (std::ostream &out, const SpecificInd &index) { From 22af7b88b9a0dda11f4584b2fd8b4be0c4a40b3b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 1 Feb 2019 09:54:17 +0000 Subject: [PATCH 0669/1783] Remove setLocation() in Field3D::operator=(FieldPerp) As noted in the comment above where setLocation() was called, setLocation() is not necessary if we have checked that the locations are the same (which is done at the top of the method). Also add check that Meshes are the same. --- src/field/field3d.cxx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 4d7f0e3b8f..50624f01b9 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -305,6 +305,7 @@ void Field3D::operator=(const FieldPerp &rhs) { TRACE("Field3D = FieldPerp"); ASSERT1(location == rhs.getLocation()); + ASSERT1(getMesh() == rhs.getMesh()); /// Check that the data is valid checkData(rhs); @@ -314,10 +315,6 @@ void Field3D::operator=(const FieldPerp &rhs) { /// Copy data BOUT_FOR(i, rhs.getRegion("RGN_ALL")) { (*this)(i, rhs.getIndex()) = rhs[i]; } - - // Alternative to setting the location of *this, is to ASSERT on input - // that rhs.getLocation() == location; - setLocation(rhs.getLocation()); } Field3D & Field3D::operator=(const BoutReal val) { From 88c298f93e2acc4dd6f32be63f80f00ab9725bd5 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 1 Feb 2019 10:21:48 +0000 Subject: [PATCH 0670/1783] Update intro to include Extrae/Paraver --- manual/sphinx/developer_docs/performance_profiling.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index 5b73acdbcc..1d3657a8b3 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -12,8 +12,14 @@ using tools that report the amount of time each processor spends in functions, on communications, etc. This section describes how to compile and run BOUT++ using the -`Scorep `_/`Scalasca `_ -tool chain. +`Scorep `_+`Scalasca `_ +and +`Extrae `_+`Paraver `_ +tool chains. +Both are suitable for analyzing code parallelized with MPI and/or OpenMP. +Scorep+Scalasca gives timings and call trees for each processor/thread, +while Extrae/Paraver produces visualizations showing what each processor/thread +is doing at a point in time. Scorep/Scalasca profiling ------------------------- From bcbe45d7e8ff913e9d95d0f2799090503cb75ead Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 1 Feb 2019 10:25:36 +0000 Subject: [PATCH 0671/1783] Add Extrae+Archer info --- .../developer_docs/performance_profiling.rst | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index 1d3657a8b3..8399511294 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -163,3 +163,27 @@ file that can be read by Paraver, do ${EXTRAE_HOME}/bin/mpi2prv -f ${EXTRAE_WORK_DIR}/TRACE.mpits -o ${TRACE_NAME} +Machine-specific installation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These are some configurations which have been found to work on +particular machines. + +Archer +^^^^^^ + +As of 1st February 2019, the following configuration should work + +.. code-block:: bash + + $ module swap PrgEnv-cray PrgEnv-gnu + $ module load fftw + $ module load archer-netcdf/4.1.3 + $ module load papi + $ module load bsctools/extrae + $ + $ export CRAYPE_LINK_TYPE=dynamic + +Note that due to a bug in the ``CC`` compiler, it is necessary to modify +``make.config`` after configuration to add the flag ``-fopenmp`` to +``BOUT_FLAGS``, when profiling OpenMP-parallelized code. From 1228976801d98f2da078abba2d54994cf6bdc973 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 1 Feb 2019 10:46:29 +0000 Subject: [PATCH 0672/1783] Add section on analyzing/manipulating trace files --- .../developer_docs/performance_profiling.rst | 50 +++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index 8399511294..396525ae54 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -65,8 +65,8 @@ desirable to profile the optimized code, configuring with the flags ``--enable-optimize=3 --enable-checks=0``. Build the code with ``make`` as normal. -Running -~~~~~~~ +Run and analysis +~~~~~~~~~~~~~~~~ When running the code, prepend the run command with ``scalasca -analyze``, e.g. @@ -124,8 +124,8 @@ Instrumentation, configure and build No changes to the code are necessary. On some systems, environment variables must be set before building. Otherwise, compile and build as normal. -Running -~~~~~~~ +Run +~~~ To run, add a trace script into the normal run command, so that for example @@ -162,6 +162,48 @@ file that can be read by Paraver, do TRACE_NAME=bout.prv ${EXTRAE_HOME}/bin/mpi2prv -f ${EXTRAE_WORK_DIR}/TRACE.mpits -o ${TRACE_NAME} +Analysis +~~~~~~~~ + +Open the trace file in `Paraver `_ with + +.. code-block:: bash + + $ wxparaver ${TRACE_NAME} + +To view time traces, go to ``File -> Load Congifuration``. There are many +configurations to choose from! Two useful configurations are: + +* ``mpi/views/MPI_call.cfg`` to show when MPI calls are made +* ``General/views/useful_duration.cfg`` to show continuous bursts of compuation + +Reducing trace file size +^^^^^^^^^^^^^^^^^^^^^^^^ + +When trace files are very large, Paraver will prompt the user to filter or cut +the file to reduce its size. +Filtering removes some information from the trace, making it small enough to +open and allow the user to select a region of interest. +Cutting crops the trace to a region of interest. +Both operations create new trace files, and never overwrite the original trace. + +The following prescription should work for manipulating large trace files: + +1. Open the large trace file in Paraver and click 'Yes' to filter it +2. Click on the tick box 'Filter' +3. Filter the trace file: + a) select box for Events + b) select box for Communications + c) in 'Keep States' select box for 'Running' + d) in 'Keep States' select box for 'IO' + e) select a min duration of 1000 + f) click 'Apply' +4. View 'useful duration' configuration and locate the region of interest +5. Zoom into the region of interest, and start and end the zoom on equivalent + large sections of computation (blue/green) +6. Right click -> Run -> Cutter +7. Change the 'Input' trace file to cut from the filtered to the original one. +8. Click cut. Machine-specific installation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 1fe5b878446541c774dfd3c896f3bad9ab725beb Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 1 Feb 2019 11:08:43 +0000 Subject: [PATCH 0673/1783] Fix links in intro --- manual/sphinx/developer_docs/performance_profiling.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index 396525ae54..568275b2ca 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -12,9 +12,9 @@ using tools that report the amount of time each processor spends in functions, on communications, etc. This section describes how to compile and run BOUT++ using the -`Scorep `_+`Scalasca `_ +`Scorep `_/`Scalasca `_ and -`Extrae `_+`Paraver `_ +`Extrae `_/`Paraver `_ tool chains. Both are suitable for analyzing code parallelized with MPI and/or OpenMP. Scorep+Scalasca gives timings and call trees for each processor/thread, From 3609518c31492309f0d837a8ea32259b83ec562d Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 1 Feb 2019 11:10:38 +0000 Subject: [PATCH 0674/1783] Allow assignment with non-finite but allocated data --- src/field/field2d.cxx | 5 ----- src/field/field3d.cxx | 14 ++++++-------- src/field/fieldperp.cxx | 2 -- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index bcfe3bd20c..1b64c7fbb9 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -193,11 +193,6 @@ Field2D &Field2D::operator=(const BoutReal rhs) { TRACE("Field2D = BoutReal"); allocate(); -#if CHECK > 0 - if (!finite(rhs)) - throw BoutException("Field2D: Assignment from non-finite BoutReal\n"); -#endif - BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] = rhs; } return *this; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index a2d4a24ebe..5cd8ca6221 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -279,10 +279,10 @@ Field3D & Field3D::operator=(const Field3D &rhs) { Field3D & Field3D::operator=(const Field2D &rhs) { TRACE("Field3D = Field2D"); - - /// Check that the data is valid - checkData(rhs); - + + /// Check that the data is allocated + ASSERT1(rhs.isAllocated()); + /// Make sure there's a unique array to copy data into allocate(); @@ -299,8 +299,8 @@ void Field3D::operator=(const FieldPerp &rhs) { ASSERT1(location == rhs.getLocation()); - /// Check that the data is valid - checkData(rhs); + /// Check that the data is allocated + ASSERT1(rhs.isAllocated()); /// Make sure there's a unique array to copy data into allocate(); @@ -315,8 +315,6 @@ void Field3D::operator=(const FieldPerp &rhs) { Field3D & Field3D::operator=(const BoutReal val) { TRACE("Field3D = BoutReal"); - /// Check that the data is valid - checkData(val); allocate(); diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 602dfbf8eb..07686b90f3 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -121,8 +121,6 @@ FieldPerp & FieldPerp::operator=(const BoutReal rhs) { allocate(); - checkData(rhs); - BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] = rhs; } return *this; From b141de38fe859f29178f5e412d48aa4abc93b971 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 1 Feb 2019 11:18:36 +0000 Subject: [PATCH 0675/1783] Fix typo --- manual/sphinx/developer_docs/performance_profiling.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index 568275b2ca..2145b15df8 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -175,7 +175,7 @@ To view time traces, go to ``File -> Load Congifuration``. There are many configurations to choose from! Two useful configurations are: * ``mpi/views/MPI_call.cfg`` to show when MPI calls are made -* ``General/views/useful_duration.cfg`` to show continuous bursts of compuation +* ``General/views/useful_duration.cfg`` to show continuous bursts of computation Reducing trace file size ^^^^^^^^^^^^^^^^^^^^^^^^ From 3b88c279402a120dfbd0e54b7d98f7be225503f1 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 1 Feb 2019 11:21:11 +0000 Subject: [PATCH 0676/1783] Update unit tests for assignment from non-finite --- tests/unit/field/test_field2d.cxx | 5 +---- tests/unit/field/test_field3d.cxx | 5 +---- tests/unit/field/test_fieldperp.cxx | 5 +---- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index 0634813d4c..5174afba11 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -650,11 +650,8 @@ TEST_F(Field2DTest, AssignFromBoutReal) { TEST_F(Field2DTest, AssignFromInvalid) { Field2D field; -#if CHECK > 0 - EXPECT_THROW(field = std::nan(""), BoutException); -#else EXPECT_NO_THROW(field = std::nan("")); -#endif + EXPECT_TRUE(IsField2DEqualBoutReal(field, std::nan(""))); } TEST_F(Field2DTest, UnaryMinus) { diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 295379fcce..3fa1c709d1 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -975,11 +975,8 @@ TEST_F(Field3DTest, AssignFromBoutReal) { TEST_F(Field3DTest, AssignFromInvalid) { Field3D field; -#if CHECK > 0 - EXPECT_THROW(field = std::nan(""), BoutException); -#else EXPECT_NO_THROW(field = std::nan("")); -#endif + EXPECT_TRUE(IsField3DEqualBoutReal(field, std::nan(""))); } TEST_F(Field3DTest, AssignFromField2D) { diff --git a/tests/unit/field/test_fieldperp.cxx b/tests/unit/field/test_fieldperp.cxx index 55757dc83e..f986a9968b 100644 --- a/tests/unit/field/test_fieldperp.cxx +++ b/tests/unit/field/test_fieldperp.cxx @@ -678,11 +678,8 @@ TEST_F(FieldPerpTest, AssignFromBoutReal) { TEST_F(FieldPerpTest, AssignFromInvalid) { FieldPerp field; -#if CHECK > 0 - EXPECT_THROW(field = std::nan(""), BoutException); -#else EXPECT_NO_THROW(field = std::nan("")); -#endif + EXPECT_TRUE(IsFieldPerpEqualBoutReal(field, std::nan(""))); } TEST_F(FieldPerpTest, UnaryMinus) { From 05c65d449aad1fbe74cd2f01ea55760bef8bf1c3 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 1 Feb 2019 11:22:37 +0000 Subject: [PATCH 0677/1783] Add line to trace manipulation section --- manual/sphinx/developer_docs/performance_profiling.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index 2145b15df8..1019da11c3 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -205,6 +205,9 @@ The following prescription should work for manipulating large trace files: 7. Change the 'Input' trace file to cut from the filtered to the original one. 8. Click cut. +This produces a trace file which has all the original profiling information, +but is much smaller as it is limited in time to a region of interest. + Machine-specific installation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From c5648533dd3f841d774765d0d236cb07080e4d58 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 1 Feb 2019 12:03:07 +0000 Subject: [PATCH 0678/1783] Be more generous with allowed order to count as pass Allows a bit more of the favourable range to count as a pass --- tests/MMS/advection/runtest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/MMS/advection/runtest b/tests/MMS/advection/runtest index 5664df819e..939fee497e 100755 --- a/tests/MMS/advection/runtest +++ b/tests/MMS/advection/runtest @@ -99,7 +99,7 @@ def run_mms(options,exit=True): order = log(error_2[-1] / error_2[-2]) / log(dx[-1] / dx[-2]) print("Convergence order = %f" % (order)) - if exp_order-.25 < order < exp_order+.25: + if exp_order-.25 < order < exp_order+0.75: print("............ PASS") else: success = False From 4c5942458c0ace108f9ce649e2302752850eb139 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 1 Feb 2019 12:58:39 +0000 Subject: [PATCH 0679/1783] Fix comments in derivatives test --- tests/unit/include/test_derivs.cxx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index 586702b70d..58005b67ff 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -21,9 +21,9 @@ // variation in the other directions. // // This is one of the more complicated uses of googletest! We need to -// all combinations of methods and directions. Unfortunately, Z has -// one more method than X and Y -- FFT. This means we can't just use -// the provided `Combine` to produce the Cartesian product of +// test all combinations of methods and directions. Unfortunately, Z +// has one more method than X and Y -- FFT. This means we can't just +// use the provided `Combine` to produce the Cartesian product of // directions and methods as the latter depends on the // former. Instead, we instantiate the tests separately for each // direction and test all the methods for that direction in that @@ -39,7 +39,8 @@ class DerivativesTest public: DerivativesTest() : input{mesh}, first_order_expected{mesh} { - // Make sure fft functions are quiet by setting fft_measure to false + // Make sure fft functions are both quiet and deterministic by + // setting fft_measure to false bout::fft::fft_init(false); using Index = Field3D::ind_type; From a6f0c70f37d693b41146ebc4521fac441f9613ef Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 1 Feb 2019 13:24:09 +0000 Subject: [PATCH 0680/1783] Further generalise derivatives unit test to fourth order methods --- tests/unit/include/test_derivs.cxx | 155 ++++++++++++++++------------- 1 file changed, 86 insertions(+), 69 deletions(-) diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index 58005b67ff..dadd9e8910 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -21,23 +21,26 @@ // variation in the other directions. // // This is one of the more complicated uses of googletest! We need to -// test all combinations of methods and directions. Unfortunately, Z -// has one more method than X and Y -- FFT. This means we can't just -// use the provided `Combine` to produce the Cartesian product of -// directions and methods as the latter depends on the -// former. Instead, we instantiate the tests separately for each -// direction and test all the methods for that direction in that -// instantiation. +// test all combinations of methods, directions and (standard) +// derivative types. Unfortunately, Z has one more method than X and Y +// (FFT), and the different orders have different sets of +// methods. This means we can't just use the provided `Combine` to +// produce the Cartesian product of methods, directions, and types as +// the first depends on the second two. Instead, we instantiate the +// tests separately for each direction and order and test all the +// methods for that direction in that instantiation. namespace { -// These are merely sanity checks, so don't expect them to agree very well! -constexpr BoutReal derivatives_tolerance{1.e-2}; +// These are merely sanity checks, so don't expect them to agree very +// well! This has to be sufficiently loose for the least accurate +// method to pass, or we need to also match up tolerances to methods +constexpr BoutReal derivatives_tolerance{5.e-3}; } class DerivativesTest - : public ::testing::TestWithParam> { + : public ::testing::TestWithParam> { public: - DerivativesTest() : input{mesh}, first_order_expected{mesh} { + DerivativesTest() : input{mesh}, expected{mesh} { // Make sure fft functions are both quiet and deterministic by // setting fft_measure to false @@ -45,7 +48,7 @@ class DerivativesTest using Index = Field3D::ind_type; - // Pointer to index method that converts to index-space + // Pointer to index method that converts single-index to 3-index space using DirectionFunction = int (Index::*)() const; DirectionFunction dir; @@ -54,6 +57,11 @@ class DerivativesTest int x_guards{0}; int y_guards{0}; + // Grid sizes + int nx{3}; + int ny{3}; + int nz{2}; + // This must be a balance between getting any kind of accuracy and // each derivative running in ~1ms or less constexpr int grid_size{64}; @@ -104,12 +112,26 @@ class DerivativesTest // C++17 makes this nicer with std::invoke input = makeField([&](Index& i) { return std::sin((i.*dir)() * box_length); }, mesh); - first_order_expected = makeField( + // Get the expected result for this order of derivative + // Again, could be nicer in C++17 with std::get(GetParam()) + switch (std::get<1>(GetParam())) { + case DERIV::Standard: + expected = makeField( [&](Index& i) { return std::cos((i.*dir)() * box_length) * box_length; }, mesh); - - second_order_expected = makeField( + break; + case DERIV::StandardSecond: + expected = makeField( [&](Index& i) { return -std::sin((i.*dir)() * box_length) * pow(box_length, 2); }, mesh); + break; + case DERIV::StandardFourth: + expected = makeField( + [&](Index& i) { return std::sin((i.*dir)() * box_length) * pow(box_length, 4); }, + mesh); + break; + default: + throw BoutException("Sorry, don't we test that type of derivative yet!"); + } // We need the parallel slices for the y-direction ParallelTransformIdentity identity{}; @@ -120,104 +142,99 @@ class DerivativesTest }; Field3D input; - Field3D first_order_expected; - Field3D second_order_expected; - - int nx{3}; - int ny{3}; - int nz{2}; + Field3D expected; + // Region not including the guard cells in current direction REGION region; }; // Get all the available methods for this direction and turn it from a -// collection of strings to a collection of pairs of the direction and -// strings so that the test fixture knows which direction we're using +// collection of strings to a collection of tuples of the direction, +// order, and strings so that the test fixture knows which direction +// we're using auto getMethodsForDirection(DERIV derivative_order, DIRECTION direction) - -> std::vector> { + -> std::vector> { auto available_methods = DerivativeStore::getInstance().getAvailableMethods( derivative_order, direction); - // Method names paired with the current direction - std::vector> methods{}; + // Method names together with the current direction and derivative type + std::vector> methods{}; std::transform(std::begin(available_methods), std::end(available_methods), - std::back_inserter(methods), [&direction](std::string method) { - return std::make_pair(direction, method); + std::back_inserter(methods), [&](std::string method) { + return std::make_tuple(direction, derivative_order, method); }); return methods; }; -// Returns the method out of the direction/method pair for printing -// the test name -auto methodDirectionPairToString( - const ::testing::TestParamInfo>& param) +// Returns the method out of the direction/order/method tuple for +// printing the test name +auto methodDirectionTupleToString( + const ::testing::TestParamInfo>& param) -> std::string { - return std::get<1>(param.param); + return std::get<2>(param.param); } -// Use an alias to distinguish the first and second derivative tests -using FirstDerivatives = DerivativesTest; - // Instantiate the test for X, Y, Z for first derivatives -INSTANTIATE_TEST_CASE_P(X, FirstDerivatives, +INSTANTIATE_TEST_CASE_P(FirstX, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, DIRECTION::X)), - methodDirectionPairToString); + methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(Y, FirstDerivatives, +INSTANTIATE_TEST_CASE_P(FirstY, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, DIRECTION::Y)), - methodDirectionPairToString); + methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(Z, FirstDerivatives, +INSTANTIATE_TEST_CASE_P(FirstZ, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, DIRECTION::Z)), - methodDirectionPairToString); - -// The actual first derivative test! -TEST_P(FirstDerivatives, FirstOrder) { - auto derivative = DerivativeStore::getInstance().getStandardDerivative( - std::get<1>(GetParam()), std::get<0>(GetParam())); - - Field3D result{mesh}; - result.allocate(); - derivative(input, result, region); - - EXPECT_TRUE(IsField3DEqualField3D(result, first_order_expected, "RGN_NOBNDRY", - derivatives_tolerance)); -} - -// Use an alias to distinguish the first and second derivative tests -using SecondDerivatives = DerivativesTest; + methodDirectionTupleToString); // Instantiate the test for X, Y, Z for second derivatives -INSTANTIATE_TEST_CASE_P(X, SecondDerivatives, +INSTANTIATE_TEST_CASE_P(SecondX, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, DIRECTION::X)), - methodDirectionPairToString); + methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(Y, SecondDerivatives, +INSTANTIATE_TEST_CASE_P(SecondY, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, DIRECTION::Y)), - methodDirectionPairToString); + methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(Z, SecondDerivatives, +INSTANTIATE_TEST_CASE_P(SecondZ, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, DIRECTION::Z)), - methodDirectionPairToString); + methodDirectionTupleToString); -// The actual second derivative test! -TEST_P(SecondDerivatives, SecondOrder) { - auto derivative = DerivativeStore::getInstance().getStandard2ndDerivative( - std::get<1>(GetParam()), std::get<0>(GetParam())); +// Instantiate the test for X, Y, Z for fourth derivatives +INSTANTIATE_TEST_CASE_P(FourthX, DerivativesTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardFourth, + DIRECTION::X)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(FourthY, DerivativesTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardFourth, + DIRECTION::Y)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(FourthZ, DerivativesTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardFourth, + DIRECTION::Z)), + methodDirectionTupleToString); + +// All standard derivatives have the same signature, so we can use a +// single test, just instantiate it for each direction/order combination +TEST_P(DerivativesTest, Sanity) { + auto derivative = DerivativeStore::getInstance().getStandardDerivative( + std::get<2>(GetParam()), std::get<0>(GetParam()), STAGGER::None, std::get<1>(GetParam())); Field3D result{mesh}; result.allocate(); derivative(input, result, region); - EXPECT_TRUE(IsField3DEqualField3D(result, second_order_expected, "RGN_NOBNDRY", + EXPECT_TRUE(IsField3DEqualField3D(result, expected, "RGN_NOBNDRY", derivatives_tolerance)); } From 774c12db538d5f6d81e59646155d30600da7f316 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 1 Feb 2019 14:21:38 +0000 Subject: [PATCH 0681/1783] Test fix: don't use adaptive time stepping when measure time scaling Fixes #1189 --- tests/MMS/time/data/BOUT.inp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/MMS/time/data/BOUT.inp b/tests/MMS/time/data/BOUT.inp index de894b88c8..399c3a9324 100644 --- a/tests/MMS/time/data/BOUT.inp +++ b/tests/MMS/time/data/BOUT.inp @@ -18,7 +18,7 @@ nx = 1 ny = 1 [solver] - +adaptive = false mms = true [f] From 578bc3922fbc574f8d0f1705105d159c59371645 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 1 Feb 2019 14:22:28 +0000 Subject: [PATCH 0682/1783] Remove some commented out bits from MMS/time Also don't need to specify adaptive=false for rkgeneric now that it is turned off for all time solvers --- tests/MMS/time/data/BOUT.inp | 2 -- tests/MMS/time/runtest | 9 ++------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/MMS/time/data/BOUT.inp b/tests/MMS/time/data/BOUT.inp index 399c3a9324..e6363e0c6f 100644 --- a/tests/MMS/time/data/BOUT.inp +++ b/tests/MMS/time/data/BOUT.inp @@ -22,8 +22,6 @@ adaptive = false mms = true [f] -#solution = sin(t) -#source = cos(t) solution = exp(t) source = 0 diff --git a/tests/MMS/time/runtest b/tests/MMS/time/runtest index bb32c80fab..61fc3a9f8c 100755 --- a/tests/MMS/time/runtest +++ b/tests/MMS/time/runtest @@ -35,24 +35,19 @@ shell_safe("make > make.log") # List of options to be passed for each test if "only_petsc" in sys.argv: # this requires petsc: - options = [("solver:type=imexbdf2 -snes_mf", "IMEX-BDF2", "-+",2)]# What's the expected order? - # should petsc solver also be added? - #options.append(("solver:type=petsc", "petsc", "-+",2))# What's the expected order? + options = [("solver:type=imexbdf2 -snes_mf", "IMEX-BDF2", "-+",2)] else: options = [ ("solver:type=euler", "Euler", "-^",1) ,("solver:type=karniadakis", "Karniadakis", "-x",2) # Whats the expected order? ,("solver:type=rk3ssp", "RK3-SSP", "-s",3) ,("solver:type=rk4", "RK4", "-o",4) - ,("solver:type=rkgeneric solver:adaptive=false", "RK-generic", "-o",4) - #,("solver:type=pvode solver:", "P-Vode", "-o",2) + ,("solver:type=rkgeneric", "RK-generic", "-o",4) ] #Missing: cvode, ida, slepc, power, arkode, snes # Is there a better way to check a certain solver should be enabled? -#options.append(("solver:type=power", "power", "-+",2))# What's the expected order? - # List of NX values to use timesteps = [4, 8, 16, 32, 64, 128, 256] From c5534738e358cb872dfb9bc3a3133d531bffde63 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 1 Feb 2019 14:23:07 +0000 Subject: [PATCH 0683/1783] Silence warnings in MMS/time --- tests/MMS/time/time.cxx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/MMS/time/time.cxx b/tests/MMS/time/time.cxx index e4d2d83370..ab87136d38 100644 --- a/tests/MMS/time/time.cxx +++ b/tests/MMS/time/time.cxx @@ -7,11 +7,11 @@ #include - +#include "unused.hxx" class TimeTest : public PhysicsModel { public: - int init(bool restart) { + int init(MAYBE_UNUSED(bool restart)) { solver->add(f, "f"); // Solve a single 3D field setSplitOperator(); @@ -19,17 +19,16 @@ class TimeTest : public PhysicsModel { return 0; } - int rhs(BoutReal time) { + int rhs(MAYBE_UNUSED(BoutReal time)) { ddt(f) = f; - //ddt(f) = 0.0; // No RHS here, only the MMS source return 0; } - int convective(BoutReal time) { + int convective(MAYBE_UNUSED(BoutReal time)) { ddt(f) = f; return 0; } - int diffusive(BoutReal time) { + int diffusive(MAYBE_UNUSED(BoutReal time)) { ddt(f) = 0; return 0; } From 79dbc33b87e46890482627fdcb03696503473d80 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 1 Feb 2019 14:36:43 +0000 Subject: [PATCH 0684/1783] Initialize variables to zero --- include/bout/run_metrics.hxx | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/bout/run_metrics.hxx b/include/bout/run_metrics.hxx index 891a65acbf..0c852f2afe 100644 --- a/include/bout/run_metrics.hxx +++ b/include/bout/run_metrics.hxx @@ -38,34 +38,34 @@ class Datafile; class RunMetrics { public: /// cumulative wall clock time in seconds - BoutReal t_elapsed; + BoutReal t_elapsed = 0; /// time step's wall clock time in seconds - BoutReal wtime; + BoutReal wtime = 0; /// number of RHS calls - int ncalls; + int ncalls = 0; /// number of RHS calls for fast timescale - int ncalls_e; + int ncalls_e = 0; /// number of RHS calls for slow timescale - int ncalls_i; + int ncalls_i = 0; /// wall time spent calculating RHS - BoutReal wtime_rhs; + BoutReal wtime_rhs = 0; /// wall time spent inverting Laplacian - BoutReal wtime_invert; + BoutReal wtime_invert = 0; /// wall time spent communicating (part of RHS) - BoutReal wtime_comms; + BoutReal wtime_comms = 0; /// wall time spent on I/O - BoutReal wtime_io; + BoutReal wtime_io = 0; // Derived metrics /// wall time per RHS evaluation - BoutReal wtime_per_rhs; + BoutReal wtime_per_rhs = 0; /// wall time per fast timescale RHS evaluation - BoutReal wtime_per_rhs_e; + BoutReal wtime_per_rhs_e = 0; /// wall time per slow timescale RHS evaluation - BoutReal wtime_per_rhs_i; + BoutReal wtime_per_rhs_i = 0; /*! * Adds variables to the output file, for post-processing From cb6390a44c8db5de354093e930ba2df796233786 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Feb 2019 11:53:57 +0000 Subject: [PATCH 0685/1783] Replace MMS/spatial/advection with simpler/more complete test Instead of time-evolving a steady-state solution, just calculate the bracket term directly and compare that to the analytic answer. Also checks the bracket operator with all the upwind derivatives --- tests/MMS/spatial/advection/advection.cxx | 64 ++++---- tests/MMS/spatial/advection/data/BOUT.inp | 41 ++--- tests/MMS/spatial/advection/mms.py | 32 ++-- tests/MMS/spatial/advection/runtest | 178 +++++++++++----------- 4 files changed, 135 insertions(+), 180 deletions(-) diff --git a/tests/MMS/spatial/advection/advection.cxx b/tests/MMS/spatial/advection/advection.cxx index ee6d93ff34..2025ee7820 100644 --- a/tests/MMS/spatial/advection/advection.cxx +++ b/tests/MMS/spatial/advection/advection.cxx @@ -1,37 +1,27 @@ -/* - * MMS test of advection operators - * - */ - -#include -#include -#include - -class AdvectMMS : public PhysicsModel { -public: - int init(bool restarting) { - solver->add(f, "f"); - - Options::getRoot()->get("method", method, 0); - - return 0; - } - int rhs(BoutReal time) { - mesh->communicate(f); - Coordinates *coords = mesh->getCoordinates(); - - g = FieldFactory::get()->create3D("g:solution", Options::getRoot(), mesh, CELL_CENTRE, time); - - ddt(f) = -bracket(g, f, (BRACKET_METHOD) method) - - 20.*(SQ(SQ(coords->dx))*D4DX4(f) + SQ(SQ(coords->dz))*D4DZ4(f)) - //+ 20.*(SQ(coords->dx)*D2DX2(f) + SQ(coords->dz)*D2DZ2(f)) - ; - - return 0; - } -private: - int method; - Field3D f,g; -}; - -BOUTMAIN(AdvectMMS); +#include "bout.hxx" +#include "derivs.hxx" +#include "field_factory.hxx" + +int main(int argc, char** argv) { + BoutInitialise(argc, argv); + + Field3D g{FieldFactory::get()->create3D("g", Options::getRoot(), mesh)}; + Field3D f{FieldFactory::get()->create3D("f", Options::getRoot(), mesh)}; + Field3D solution{FieldFactory::get()->create3D("solution", Options::getRoot(), mesh)}; + + mesh->communicate(f, g); + + auto method{static_cast(Options::root()["method"].as())}; + + Field3D result{bracket(g, f, method)}; + Field3D error{result - solution}; + BoutReal l_2{sqrt(mean(SQ(error), true, RGN_NOBNDRY))}; + BoutReal l_inf{max(abs(error), true, RGN_NOBNDRY)}; + + SAVE_ONCE2(f, g); + SAVE_ONCE5(solution, result, error, l_2, l_inf); + + dump.write(); + + BoutFinalise(); +} diff --git a/tests/MMS/spatial/advection/data/BOUT.inp b/tests/MMS/spatial/advection/data/BOUT.inp index 907ed2f1d8..38d2ec3bde 100644 --- a/tests/MMS/spatial/advection/data/BOUT.inp +++ b/tests/MMS/spatial/advection/data/BOUT.inp @@ -1,5 +1,6 @@ -NOUT = 1 -TIMESTEP = 50 +g = sin(6.0*x^2 - z) +f = cos(4.0*x^2 + z) +solution = 3.18309886183791*x*sin(4.0*x^2 + z)*cos(6.0*x^2 - z) MZ = 16 @@ -18,36 +19,12 @@ symmetricGlobalX = true ny = 1 [mesh:ddx] -upwind=c2 +first = c4 +second = c4 +upwind = c2 [mesh:ddz] -upwind=c2 +first = c4 +second = c4 +upwind = c2 -[solver] - -#type = rk4 - -ATOL = 1.0e-15 # absolute tolerance -RTOL = 1.0e-15 # relative tolerance -mxstep = 10000 # Maximum internal steps per output - -mms = true # -> Enable MMS testing -mms_initialise = false # Don't initialise with MMS solution - -[output] -floats = false # -> Output in double precision - -[g] -solution = sin(6.0*x^2 - z) - -[f] -scale = 0 -function = 0 - -solution = cos(4.0*x^2 + z) - -ddx = -1.27323954473516*x*sin(4.0*x^2 + z) - -source = 3.18309886183791*x*sin(4.0*x^2 + z)*cos(6.0*x^2 - z) - -bndry_all = dirichlet_o2(f:solution) diff --git a/tests/MMS/spatial/advection/mms.py b/tests/MMS/spatial/advection/mms.py index e61ba5a3c8..a75ab3e39b 100644 --- a/tests/MMS/spatial/advection/mms.py +++ b/tests/MMS/spatial/advection/mms.py @@ -10,7 +10,7 @@ ZMAX = Lz / (2*pi) -metric = Metric() # Identity metric +metric = Metric() # Identity metric # Define solution in terms of input x,y,z @@ -19,34 +19,22 @@ f = cos(4*x**2 + z) # Turn solution into real x and z coordinates -replace = [ (x, metric.x / Lx), (z, metric.z / ZMAX) ] +replace = [(x, metric.x / Lx), (z, metric.z / ZMAX)] f = f.subs(replace) g = g.subs(replace) # Calculate time derivatives -dfdt = -bracket(g, f, metric) - -# Calculate source -S = diff(f, t) - dfdt - -# Differentials for boundary conditions -dfdx = diff(f, metric.x) +solution = bracket(g, f, metric) # Substitute back to get input x and z coordinates -replace = [ (metric.x, x * Lx), (metric.z, z * ZMAX) ] - -g = g.subs(replace) -f = f.subs(replace) -dfdt = dfdt.subs(replace) -S = S.subs(replace) -dfdx = dfdx.subs(replace) +replace = [(metric.x, x * Lx), (metric.z, z * ZMAX)] -print("[g]") -print("solution = "+exprToStr(g)) +g = g.subs(replace) +f = f.subs(replace) +solution = solution.subs(replace) -print("\n[f]") -print("solution = "+exprToStr(f)) -print("\nddx = "+exprToStr(dfdx)) -print("\nsource = "+exprToStr(S)) +print("g = " + exprToStr(g)) +print("f = " + exprToStr(f)) +print("solution = " + exprToStr(solution)) diff --git a/tests/MMS/spatial/advection/runtest b/tests/MMS/spatial/advection/runtest index 0a7bab42e9..b9b4768a30 100755 --- a/tests/MMS/spatial/advection/runtest +++ b/tests/MMS/spatial/advection/runtest @@ -5,7 +5,7 @@ # Tests a range of different schemes # -#requires: all_tests +# requires: all_tests from __future__ import division from __future__ import print_function @@ -15,9 +15,7 @@ from builtins import range from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun from boutdata.collect import collect -from numpy import sqrt, max, abs, mean, array, log, pi - -from os.path import join +from numpy import array, log, pi import matplotlib.pyplot as plt @@ -30,76 +28,79 @@ shell_safe("make > make.log") # List of options to be passed for each test options = [ - ("method=2", "Arakawa", "-^" , 2), - ("method=0 mesh:ddx:upwind=u1 mesh:ddz:upwind=u1", "1st order upwind", "-o", 1), - ("method=0 mesh:ddx:upwind=c2 mesh:ddz:upwind=c2", "2nd order central", "-x", 2), - ("method=0 mesh:ddx:upwind=w3 mesh:ddz:upwind=w3", "3rd order WENO", "-s", 3) - ] + ("method=2", "Arakawa", "-^", 2), + ("method=1 mesh:ddx:upwind=u1 mesh:ddz:upwind=u1", "1st order upwind", "-o", 1), + ("method=1 mesh:ddx:upwind=u2 mesh:ddz:upwind=u2", "2nd order upwind", "-^", 2), + ("method=1 mesh:ddx:upwind=u3 mesh:ddz:upwind=u3", "3nd order upwind", "-v", 3), + ("method=1 mesh:ddx:upwind=c2 mesh:ddz:upwind=c2", "2nd order central", "-x", 2), + ("method=1 mesh:ddx:upwind=c4 mesh:ddz:upwind=c4", "4th order central", "-+", 4), + # NOTE: WENO3 seems to have two different regimes, one < 3, one > + # 3, so it's possible to make it pass by judicious choice of grid + # sizes, which is suspicious. It does seem to work correctly in + # other contexts, so not overly worrying that it doesn't work + # exactly as expected here + # ("method=1 mesh:ddx:upwind=w3 mesh:ddz:upwind=w3", "3rd order WENO", "-s", 3), +] # List of NX values to use -nxlist = [16, 32] -#nxlist = [16, 32, 64, 128, 256, 512, 1024] +nxlist = [16, 32, 64, 128, 256] nproc = 2 +mthread = 2 success = True err_2_all = [] err_inf_all = [] -for opts,label,sym,exp_ord in options: - error_2 = [] # The L2 error (RMS) +for opts, label, sym, exp_ord in options: + error_2 = [] # The L2 error (RMS) error_inf = [] # The maximum error for nx in nxlist: # Set the X and Z mesh size - dx = 2.*pi / (nx) args = opts + " mesh:nx="+str(nx+4)+" mesh:dx="+str(dx)+" MZ="+str(nx) - + print(" Running with " + args) # Delete old data shell("rm data/BOUT.dmp.*.nc") - + # Command to run cmd = "./advection "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, + mthread=mthread, pipe=True) # Save output to log file - f = open("run.log."+str(nx), "w") - f.write(out) - f.close() - - # Collect data - E_f = collect("E_f", tind=[1,1], info=False, path="data") - #E_f = E_f[0,2:-2,0,:] - - # Average error over domain - l2 = sqrt(mean(E_f**2)) - linf = max(abs( E_f )) - - error_2.append( l2 ) - error_inf.append( linf ) - + with open("run.log."+str(nx), "w") as f: + f.write(out) + + l2 = collect("l_2", tind=-1, xguards=False, + yguards=False, info=False, path="data") + linf = collect("l_inf", tind=-1, xguards=False, + yguards=False, info=False, path="data") + + error_2.append(l2) + error_inf.append(linf) + print(" -> Error norm: l-2 %f l-inf %f" % (l2, linf)) - - + # Append to list of all results - err_2_all.append( (error_2, label, sym) ) - err_inf_all.append( (error_inf, label, sym) ) + err_2_all.append((error_2, label, sym)) + err_inf_all.append((error_inf, label, sym)) # Calculate grid spacing dx = 1. / array(nxlist) # Calculate convergence order - + order = log(error_2[-1] / error_2[-2]) / log(dx[-1] / dx[-2]) print("Convergence order = %f" % (order)) - if not ( exp_ord + .2 > order > exp_ord - .2): - success=False + if not (exp_ord + .2 > order > exp_ord - .2): + success = False print("... Failure") else: print("... Success") @@ -107,22 +108,21 @@ for opts,label,sym,exp_ord in options: # plot errors if False: plt.figure() - + plt.plot(dx, error_2, '-o', label=r'$l^2$') plt.plot(dx, error_inf, '-x', label=r'$l^\infty$') - - plt.plot(dx, error_2[-1]*(dx/dx[-1])**order, '--', label="Order %.1f"%(order)) - + + plt.plot(dx, error_2[-1]*(dx/dx[-1])**order, + '--', label="Order %.1f" % (order)) + plt.legend(loc="upper left") plt.grid() - + plt.yscale('log') plt.xscale('log') - + plt.xlabel(r'Mesh spacing $\delta x$') plt.ylabel("Error norm") - - #plt.savefig("norm.pdf") plt.show() plt.close() @@ -132,61 +132,61 @@ with open("advection.pkl", "wb") as output: pickle.dump(err_2_all, output) pickle.dump(err_inf_all, output) -# Plot all results for comparison -plt.figure() -for e, label, sym in err_2_all: - plt.plot(dx, e, sym, label=label) +# Plot all errors +if False: + # Plot all results for comparison + plt.figure() + for e, label, sym in err_2_all: + plt.plot(dx, e, sym, label=label) -plt.legend(loc="upper left") -plt.grid() -plt.yscale('log') -plt.xscale('log') - -plt.xlabel(r'Mesh spacing $\delta x$') -plt.ylabel(r'$l^2$ error norm') -plt.savefig("advection_norm_l2.pdf") -plt.close() + plt.legend(loc="upper left") + plt.grid() + plt.yscale('log') + plt.xscale('log') -### + plt.xlabel(r'Mesh spacing $\delta x$') + plt.ylabel(r'$l_2$ error norm') + plt.savefig("advection_norm_l2.png") + plt.close() -plt.figure() -for e, label, sym in err_inf_all: - plt.plot(dx, e, sym, label=label) - for i in range(len(dx)): - print(str(label)+ ": %d Err: %e " % (nxlist[i], e[i])) - if i > 0: - print(" -> Rate %e " % (log(e[i] / e[i-1]) / log(dx[i] / dx[i-1]))) + ### + + plt.figure() + for e, label, sym in err_inf_all: + plt.plot(dx, e, sym, label=label) + + plt.legend(loc="upper left") + plt.grid() + plt.yscale('log') + plt.xscale('log') -plt.legend(loc="upper left") -plt.grid() -plt.yscale('log') -plt.xscale('log') - -plt.xlabel(r'Mesh spacing $\delta x$') -plt.ylabel(r'$l^\infty$ error norm') -plt.savefig("advection_norm_linf.pdf") -plt.close() + plt.xlabel(r'Mesh spacing $\delta x$') + plt.ylabel(r'$l_\infty$ error norm') + plt.savefig("advection_norm_linf.png") + plt.close() -###### + +def print_error_rate(e, nxlist, dx): + print("{}: {:>4} points | Error: {:f}".format(label, nxlist[i], e[i]), end="") + if i > 0: + print(" -> Rate {:f} ".format(log(e[i] / e[i-1]) / log(dx[i] / dx[i-1]))) + else: + print() -print("\n\n==== l-infty norm ====") +print("\n\n==== l-infinity norm ====") for e, label, sym in err_inf_all: for i in range(len(dx)): - print(str(label)+ ": %d Err: %e " % (nxlist[i], e[i])) - if i > 0: - print(" -> Rate %e " % (log(e[i] / e[i-1]) / log(dx[i] / dx[i-1]))) + print_error_rate(e, nxlist, dx) print("\n\n==== l-2 norm ====") for e, label, sym in err_2_all: for i in range(len(dx)): - print(str(label)+ ": %d Err: %e " % (nxlist[i], e[i])) - if i > 0: - print(" -> Rate %e " % (log(e[i] / e[i-1]) / log(dx[i] / dx[i-1]))) + print_error_rate(e, nxlist, dx) if success: - print(" => All tests passed") - exit(0) + print(" => All tests passed") + exit(0) else: - print(" => Some failed tests") - exit(1) + print(" => Some failed tests") + exit(1) From de5787ae7620098856f558816b597d7572210e76 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Feb 2019 12:17:38 +0000 Subject: [PATCH 0686/1783] Don't use both {} and auto for initialisation --- tests/MMS/spatial/advection/advection.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/MMS/spatial/advection/advection.cxx b/tests/MMS/spatial/advection/advection.cxx index 2025ee7820..dc82774d00 100644 --- a/tests/MMS/spatial/advection/advection.cxx +++ b/tests/MMS/spatial/advection/advection.cxx @@ -11,7 +11,7 @@ int main(int argc, char** argv) { mesh->communicate(f, g); - auto method{static_cast(Options::root()["method"].as())}; + auto method = static_cast(Options::root()["method"].as()); Field3D result{bracket(g, f, method)}; Field3D error{result - solution}; From fad37f1b40b9c9522bc0dcb010dc7d5d1d42913e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Feb 2019 12:53:06 +0000 Subject: [PATCH 0687/1783] Fix requires comment and move matplotlib import to use --- tests/MMS/spatial/advection/runtest | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/MMS/spatial/advection/runtest b/tests/MMS/spatial/advection/runtest index b9b4768a30..e0ebfcb9c9 100755 --- a/tests/MMS/spatial/advection/runtest +++ b/tests/MMS/spatial/advection/runtest @@ -5,7 +5,7 @@ # Tests a range of different schemes # -# requires: all_tests +#requires: all_tests from __future__ import division from __future__ import print_function @@ -17,8 +17,6 @@ from boutdata.collect import collect from numpy import array, log, pi -import matplotlib.pyplot as plt - import pickle MPIRUN = getmpirun() @@ -107,6 +105,7 @@ for opts, label, sym, exp_ord in options: # plot errors if False: + import matplotlib.pyplot as plt plt.figure() plt.plot(dx, error_2, '-o', label=r'$l^2$') @@ -134,6 +133,7 @@ with open("advection.pkl", "wb") as output: # Plot all errors if False: + import matplotlib.pyplot as plt # Plot all results for comparison plt.figure() for e, label, sym in err_2_all: From 815d34d6228fff637b5cc28573e4716eb6ba8c07 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Feb 2019 13:02:37 +0000 Subject: [PATCH 0688/1783] Fix typo in documentation --- manual/sphinx/developer_docs/performance_profiling.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index 1019da11c3..d052bf5ca6 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -171,7 +171,7 @@ Open the trace file in `Paraver `_ with $ wxparaver ${TRACE_NAME} -To view time traces, go to ``File -> Load Congifuration``. There are many +To view time traces, go to ``File -> Load Configuration``. There are many configurations to choose from! Two useful configurations are: * ``mpi/views/MPI_call.cfg`` to show when MPI calls are made From b8cfba3ba20f539b9be2f77b89e312d719cff65e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Feb 2019 13:17:26 +0000 Subject: [PATCH 0689/1783] Pass parameter pack by forwarding-ref, function by const-ref --- tests/unit/test_extras.hxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 0dd4a91b1f..69e3ea0f63 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -49,11 +49,12 @@ using EnableIfField = typename std::enable_if::value>: /// Returns a field filled with the result of \p fill_function at each point /// Arbitrary arguments can be passed to the field constructor template > -T makeField(std::function fill_function, Args... args) { +T makeField(const std::function& fill_function, + Args&&... args) { T result{std::forward(args)...}; result.allocate(); - for (auto i: result) { + for (auto i : result) { result[i] = fill_function(i); } From a7b1bd6c4d9c7617dc37f69be0ad2472451d6821 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Feb 2019 13:42:17 +0000 Subject: [PATCH 0690/1783] Add missing assert in test_zoidberg --- tools/pylib/zoidberg/test_zoidberg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pylib/zoidberg/test_zoidberg.py b/tools/pylib/zoidberg/test_zoidberg.py index 23117c8dad..45c1626381 100644 --- a/tools/pylib/zoidberg/test_zoidberg.py +++ b/tools/pylib/zoidberg/test_zoidberg.py @@ -34,7 +34,7 @@ def test_make_maps_slab(): assert var in maps # Each map should have the same shape as the grid - maps[var].shape == (nx, ny, nz) + assert maps[var].shape == (nx, ny, nz) # The first/last abs(offset) points are not valid, so ignore those interior_range = range(ny-abs(offset)) if offset > 0 else range(abs(offset), ny) From 6fb831965576cc91cc199cf97453c640b92deec2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Feb 2019 13:43:20 +0000 Subject: [PATCH 0691/1783] Don't store fields with placeholder values in shiftedmetric --- src/mesh/parallel/shiftedmetric.cxx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index cf6124bd29..d6171fc117 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -220,14 +220,9 @@ ShiftedMetric::shiftZ(const Field3D& f, for (auto& phase : phases) { // In C++17 std::vector::emplace_back returns a reference, which // would be very useful here! - - // FIXME: initialisation to -1 to avoid checkData choking on the - // uninitialised regions in assignment into the Field parallel - // slices in calcYUpDown - results.emplace_back(-1.0, &mesh); + results.emplace_back(&mesh); auto& current_result = results.back(); - // FIXME: uncomment the following after fixing Field3D::operator= - // current_result.allocate(); + current_result.allocate(); current_result.setLocation(f.getLocation()); for (int jx = 0; jx < mesh.LocalNx; jx++) { From 606c2013b9346661a55daa1270d5ec3c8adaaf44 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 4 Feb 2019 12:43:22 +0000 Subject: [PATCH 0692/1783] Pass mesh_in in initializer list of FCIMap::FCIMap constructor Avoids potential issues if order of FCIMap member declarations changes in the future. --- src/mesh/parallel/fci.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 3f5312b83b..1d37b1fe7a 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -54,8 +54,8 @@ inline BoutReal sgn(BoutReal val) { return (BoutReal(0) < val) - (val < BoutReal // Calculate all the coefficients needed for the spline interpolation // dir MUST be either +1 or -1 FCIMap::FCIMap(Mesh &mesh_in, int dir, bool zperiodic) - : mesh(mesh_in), dir(dir), boundary_mask(mesh), corner_boundary_mask(mesh), - y_prime(&mesh) { + : mesh(mesh_in), dir(dir), boundary_mask(mesh_in), corner_boundary_mask(mesh_in), + y_prime(&mesh_in) { interp = InterpolationFactory::getInstance()->create(&mesh); interp->setYOffset(dir); From 1825484fb684be53bfaef79d1ee95744d8fd08d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Mon, 4 Feb 2019 13:34:41 +0000 Subject: [PATCH 0693/1783] Improve make-script example * Cache bout-config results * Bail-out early if bout-config is not in path --- examples/make-script/makefile | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/make-script/makefile b/examples/make-script/makefile index 85a1a60241..cc76a53288 100644 --- a/examples/make-script/makefile +++ b/examples/make-script/makefile @@ -1,5 +1,6 @@ # Example makefile. Sources are listed in SOURCEC # and optionally a TARGET executable name can be given +# It requires that bout-config is in $PATH SOURCEC = test.cxx @@ -9,10 +10,17 @@ OBJ = $(SOURCEC:%.cxx=%.o) TARGET ?= $(SOURCEC:%.cxx=%) # Use the bout-config script to get compiler, flags -CXX=`bout-config --cxx` -CFLAGS=`bout-config --cflags` -LD=`bout-config --ld` -LDFLAGS=`bout-config --libs` +CXX:=$(shell bout-config --cxx) + +ifneq "$(.SHELLSTATUS)" "0" +which=$(shell which bout-config) +$(info Output of which bout-config: $(which)) +$(error Failed to run bout-config.) +endif + +CFLAGS:=$(shell bout-config --cflags) +LD:=$(shell bout-config --ld) +LDFLAGS:=$(shell bout-config --libs) $(TARGET): makefile $(OBJ) @echo " Linking" $(TARGET) From fd45aed918078c9fee63fa1f529b44b44561962c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Mon, 4 Feb 2019 14:43:16 +0000 Subject: [PATCH 0694/1783] Ignore hidden and temporary files --- locale/makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locale/makefile b/locale/makefile index 74e245618f..9b67440f6e 100644 --- a/locale/makefile +++ b/locale/makefile @@ -12,7 +12,7 @@ locale: $(MO_FILES) # Create the template file, combining all source files libbout.pot: FORCE - xgettext --keyword=_ --language=c++ --add-comments --sort-output -o $@ `find ../ -name "*.[ch]xx"` + xgettext --keyword=_ --language=c++ --add-comments --sort-output -o $@ `find ../ -name "[^.#]*.[ch]xx"` # Update a .po file # If it doesn't exist then create; if it exists then update From fc2db927376bc733a09ea7e63ef9606eb116b15c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 4 Feb 2019 15:36:08 +0000 Subject: [PATCH 0695/1783] Add 'using namespace bout::globals;' for new unit test files. --- tests/unit/include/test_derivs.cxx | 3 +++ tests/unit/mesh/parallel/test_shiftedmetric.cxx | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index dadd9e8910..eef95ee9f2 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -13,6 +13,9 @@ #include #include +// The unit tests use the global mesh +using namespace bout::globals; + // Some basic sanity checks for the derivative kernels. Checks the // derivatives of sin(R) where R = {X, Y, Z} for each R // individually. To make this as fast as possible, we use only a diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 4d8c2885a7..6d36c776cc 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -3,7 +3,14 @@ #include "bout/paralleltransform.hxx" #include "test_extras.hxx" -extern Mesh* mesh; +// The unit tests use the global mesh +using namespace bout::globals; + +namespace bout{ +namespace globals{ +extern Mesh *mesh; +} // namespace globals +} // namespace bout class ShiftedMetricTest : public ::testing::Test { public: From 3e62a35942631ba2fa312fe4b8229c6ccf9b1a70 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Feb 2019 17:23:03 +0000 Subject: [PATCH 0696/1783] Fix FCI MMS: g_22 should depend on the length of the field line Should be done better by actually calculating the arc length of the field line --- tests/MMS/spatial/fci/data/BOUT.inp | 2 +- tests/MMS/spatial/fci/fci_mms.cxx | 6 +++--- tests/MMS/spatial/fci/mms.py | 2 +- tests/MMS/spatial/fci/runtest | 2 +- tools/pylib/zoidberg/grid.py | 4 ++-- tools/pylib/zoidberg/zoidberg.py | 7 +++++++ 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/MMS/spatial/fci/data/BOUT.inp b/tests/MMS/spatial/fci/data/BOUT.inp index 6ad5d66ca2..cf2208e3b3 100644 --- a/tests/MMS/spatial/fci/data/BOUT.inp +++ b/tests/MMS/spatial/fci/data/BOUT.inp @@ -2,7 +2,7 @@ grid = fci.grid.nc input = sin(y - 2*z) + sin(y - z) -solution = 6.28318530717959*(0.01*x + 0.045)*(-2*cos(y - 2*z) - cos(y - z)) + 0.628318530717959*cos(y - 2*z) + 0.628318530717959*cos(y - z) +solution = (6.28318530717959*(0.01*x + 0.045)*(-2*cos(y - 2*z) - cos(y - z)) + 0.628318530717959*cos(y - 2*z) + 0.628318530717959*cos(y - z))/sqrt((0.01*x + 0.045)^2 + 1.0) MXG = 1 NXPE = 1 diff --git a/tests/MMS/spatial/fci/fci_mms.cxx b/tests/MMS/spatial/fci/fci_mms.cxx index 32b668f575..dc250d55b7 100644 --- a/tests/MMS/spatial/fci/fci_mms.cxx +++ b/tests/MMS/spatial/fci/fci_mms.cxx @@ -11,10 +11,10 @@ int main(int argc, char** argv) { // Communicate to calculate parallel transform mesh->communicate(input); - Field3D result{DDY(input)}; + Field3D result{Grad_par(input)}; Field3D error{result - solution}; - BoutReal l_2{sqrt(mean(SQ(error)))}; - BoutReal l_inf{max(abs(error), true)}; + BoutReal l_2{sqrt(mean(SQ(error), true, RGN_NOBNDRY))}; + BoutReal l_inf{max(abs(error), true, RGN_NOBNDRY)}; SAVE_ONCE6(input, solution, result, error, l_2, l_inf); diff --git a/tests/MMS/spatial/fci/mms.py b/tests/MMS/spatial/fci/mms.py index 1154cfc9cc..477c605e84 100755 --- a/tests/MMS/spatial/fci/mms.py +++ b/tests/MMS/spatial/fci/mms.py @@ -26,7 +26,7 @@ B = sqrt(Bpx**2 + Bt**2) def FCI_ddy(f): - return ( Bt * diff(f, y)*2.*pi/Ly + Bpx * diff(f, z)*2.*pi/Lz ) + return ( Bt * diff(f, y)*2.*pi/Ly + Bpx * diff(f, z)*2.*pi/Lz ) / B ############################################ # Equations solved diff --git a/tests/MMS/spatial/fci/runtest b/tests/MMS/spatial/fci/runtest index 36eb96c7d7..99ec92edc2 100755 --- a/tests/MMS/spatial/fci/runtest +++ b/tests/MMS/spatial/fci/runtest @@ -61,7 +61,7 @@ for nslice in nslices: # Note that the Bz and Bzprime parameters here must be the same as in mms.py field = zb.field.Slab(Bz=0.05, Bzprime=0.1) # Create rectangular poloidal grids - poloidal_grid = zb.poloidal_grid.RectangularPoloidalGrid(nx, n, 1., 1.) + poloidal_grid = zb.poloidal_grid.RectangularPoloidalGrid(nx, n, 0.1, 1.) # Set the ylength and y locations ylength = 10. diff --git a/tools/pylib/zoidberg/grid.py b/tools/pylib/zoidberg/grid.py index 99e247d43f..8ca964517b 100644 --- a/tools/pylib/zoidberg/grid.py +++ b/tools/pylib/zoidberg/grid.py @@ -184,8 +184,8 @@ def metric(self): # Note: These y metrics are for Cartesian coordinates # If in cylindrical coordinates then these should be different - g_yy = 1.0 # Rmaj**2 - gyy = 1.0 # 1/Rmaj**2 + g_yy = np.ones(self.shape) + gyy = np.ones(self.shape) return {"dx":dx, "dy":dy3d, "dz": dz, "gyy": gyy, "g_yy":g_yy, diff --git a/tools/pylib/zoidberg/zoidberg.py b/tools/pylib/zoidberg/zoidberg.py index 5833d01134..7d11882fb2 100644 --- a/tools/pylib/zoidberg/zoidberg.py +++ b/tools/pylib/zoidberg/zoidberg.py @@ -208,6 +208,13 @@ def write_maps(grid, magnetic_field, maps, gridfile='fci.grid.nc', Bmag[:, yindex, :] = magnetic_field.Bmag(pol_grid.R, pol_grid.Z, ypos) pressure[:, yindex, :] = magnetic_field.pressure(pol_grid.R, pol_grid.Z, ypos) + metric["g_yy"][:, yindex, :] = (metric["g_yy"][:, yindex, :] + * (Bmag[:, yindex, :] + / magnetic_field.Byfunc(pol_grid.R, pol_grid.Z, ypos))**2) + metric["gyy"][:, yindex, :] = (metric["gyy"][:, yindex, :] + * (magnetic_field.Byfunc(pol_grid.R, pol_grid.Z, ypos) + / Bmag[:, yindex, :])**2) + # Get attributes from magnetic field (e.g. psi) attributes = {} for name in magnetic_field.attributes: From 35cdc728776c2fb98cc478ebc4cdc413e00e7162 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Feb 2019 17:29:54 +0000 Subject: [PATCH 0697/1783] Remove some unnecessary code from test-smooth --- tests/integrated/test-smooth/test_smooth.cxx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/integrated/test-smooth/test_smooth.cxx b/tests/integrated/test-smooth/test_smooth.cxx index 15f7c656ec..c4670656c1 100644 --- a/tests/integrated/test-smooth/test_smooth.cxx +++ b/tests/integrated/test-smooth/test_smooth.cxx @@ -17,7 +17,6 @@ int main(int argc, char **argv) { Field2D input2d = f.create2D("1 + sin(2*y)"); Field3D input3d = f.create3D("gauss(x-0.5,0.2)*gauss(y-pi)*sin(3*y - z)"); - input3d.splitYupYdown(); mesh->getParallelTransform().calcYUpDown(input3d); SAVE_ONCE2(input2d, input3d); @@ -32,11 +31,6 @@ int main(int argc, char **argv) { // Output data dump.write(); - dump.close(); - - output << "\nFinished running test. Triggering error to quit\n\n"; - - MPI_Barrier(BoutComm::get()); // Wait for all processors to write data BoutFinalise(); return 0; From 8f299fb579179f55be4c157023d479a2e0d8ed3f Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Tue, 5 Feb 2019 09:50:52 +0000 Subject: [PATCH 0698/1783] Move run metrics to struct in monitor header --- include/bout/monitor.hxx | 52 +++++++++++++++++++++ include/bout/run_metrics.hxx | 87 ------------------------------------ src/bout++.cxx | 53 +++++++++++++++++++++- src/sys/run_metrics.cxx | 73 ------------------------------ 4 files changed, 104 insertions(+), 161 deletions(-) delete mode 100644 include/bout/run_metrics.hxx delete mode 100644 src/sys/run_metrics.cxx diff --git a/include/bout/monitor.hxx b/include/bout/monitor.hxx index 2a4cc3459b..107f5cb043 100644 --- a/include/bout/monitor.hxx +++ b/include/bout/monitor.hxx @@ -7,6 +7,7 @@ #include +class Datafile; class Solver; /// Return true if either \p a is a multiple of \p b or vice-versa @@ -68,6 +69,57 @@ private: bool is_added = false; ///< Set to true when Monitor is added to a Solver BoutReal timestep; int freq; + +}; + +struct RunMetrics { + public: + /// cumulative wall clock time in seconds + BoutReal t_elapsed = 0; + /// time step's wall clock time in seconds + BoutReal wtime = 0; + + /// number of RHS calls + int ncalls = 0; + /// number of RHS calls for fast timescale + int ncalls_e = 0; + /// number of RHS calls for slow timescale + int ncalls_i = 0; + + /// wall time spent calculating RHS + BoutReal wtime_rhs = 0; + /// wall time spent inverting Laplacian + BoutReal wtime_invert = 0; + /// wall time spent communicating (part of RHS) + BoutReal wtime_comms = 0; + /// wall time spent on I/O + BoutReal wtime_io = 0; + + // Derived metrics + + /// wall time per RHS evaluation + BoutReal wtime_per_rhs = 0; + /// wall time per fast timescale RHS evaluation + BoutReal wtime_per_rhs_e = 0; + /// wall time per slow timescale RHS evaluation + BoutReal wtime_per_rhs_i = 0; + + /*! + * Adds variables to the output file, for post-processing + */ + void outputVars(Datafile &file); + + /*! + * Calculates derived metrics + */ + void calculateDerivedMetrics(); + + /*! + * Write job progress to screen + */ + void writeProgress(BoutReal simtime, bool output_split); + }; + #endif // __MONITOR_H__ diff --git a/include/bout/run_metrics.hxx b/include/bout/run_metrics.hxx deleted file mode 100644 index 0c852f2afe..0000000000 --- a/include/bout/run_metrics.hxx +++ /dev/null @@ -1,87 +0,0 @@ -/************************************************************************** - * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu - * - * Run Metrics class by J. T. Parker 2019 - * - * Contact: Ben Dudson, bd512@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - **************************************************************************/ - -/// Run Metrics class -/// -/// The `Run Metrics` class holds non-physics information about the job execution, -/// such as wall clock times and number of iterations. - -#ifndef __RUNMETRICS_H__ -#define __RUNMETRICS_H__ - - -class Datafile; -#include "bout_types.hxx" - - -class RunMetrics { - public: - /// cumulative wall clock time in seconds - BoutReal t_elapsed = 0; - /// time step's wall clock time in seconds - BoutReal wtime = 0; - - /// number of RHS calls - int ncalls = 0; - /// number of RHS calls for fast timescale - int ncalls_e = 0; - /// number of RHS calls for slow timescale - int ncalls_i = 0; - - /// wall time spent calculating RHS - BoutReal wtime_rhs = 0; - /// wall time spent inverting Laplacian - BoutReal wtime_invert = 0; - /// wall time spent communicating (part of RHS) - BoutReal wtime_comms = 0; - /// wall time spent on I/O - BoutReal wtime_io = 0; - - // Derived metrics - - /// wall time per RHS evaluation - BoutReal wtime_per_rhs = 0; - /// wall time per fast timescale RHS evaluation - BoutReal wtime_per_rhs_e = 0; - /// wall time per slow timescale RHS evaluation - BoutReal wtime_per_rhs_i = 0; - - /*! - * Adds variables to the output file, for post-processing - */ - void outputVars(Datafile &file); - - /*! - * Calculates derived metrics - */ - void calculateDerivedMetrics(); - - /*! - * Write job progress to screen - */ - void writeProgress(BoutReal simtime, bool output_split); - -}; - -#endif // __RUNMETRICS_H__ diff --git a/src/bout++.cxx b/src/bout++.cxx index 3272956220..22d9cc13d1 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -52,7 +52,6 @@ const char DEFAULT_LOG[] = "BOUT.log"; #include #include -#include #include @@ -785,3 +784,55 @@ char get_spin() { i = (i+1) % 4; return c; } + +/************************************************************************** + * Functions for writing run information + **************************************************************************/ + +/*! + * Adds variables to the output file, for post-processing + */ +void RunMetrics::outputVars(Datafile &file) { + + file.add(t_elapsed, "wall_time", true); + file.add(wtime, "wtime", true); + file.add(ncalls, "ncalls", true); + file.add(ncalls_e, "ncalls_e", true); + file.add(ncalls_i, "ncalls_i", true); + file.add(wtime_rhs, "wtime_rhs", true); + file.add(wtime_invert, "wtime_invert", true); + file.add(wtime_comms, "wtime_comms", true); + file.add(wtime_io, "wtime_io", true); + file.add(wtime_per_rhs, "wtime_per_rhs", true); + file.add(wtime_per_rhs_e, "wtime_per_rhs_e", true); + file.add(wtime_per_rhs_i, "wtime_per_rhs_i", true); +} + +void RunMetrics::calculateDerivedMetrics() { + + wtime_per_rhs = wtime / ncalls; + wtime_per_rhs_e = wtime / ncalls_e; + wtime_per_rhs_i = wtime / ncalls_i; +} + +void RunMetrics::writeProgress(BoutReal simtime, bool output_split) { + + if (!output_split) { + output_progress.write("%.3e %5d %.2e %5.1f %5.1f %5.1f %5.1f %5.1f\n", + simtime, ncalls, wtime, + 100.0*(wtime_rhs - wtime_comms - wtime_invert)/wtime, + 100.*wtime_invert/wtime, // Inversions + 100.0*wtime_comms/wtime, // Communications + 100.* wtime_io / wtime, // I/O + 100.*(wtime - wtime_io - wtime_rhs)/wtime); // Everything else + + } else { + output_progress.write("%.3e %5d %5d %.2e %5.1f %5.1f %5.1f %5.1f %5.1f\n", + simtime, ncalls_e, ncalls_i, wtime, + 100.0*(wtime_rhs - wtime_comms - wtime_invert)/wtime, + 100.*wtime_invert/wtime, // Inversions + 100.0*wtime_comms/wtime, // Communications + 100.* wtime_io / wtime, // I/O + 100.*(wtime - wtime_io - wtime_rhs)/wtime); // Everything else + } +} diff --git a/src/sys/run_metrics.cxx b/src/sys/run_metrics.cxx deleted file mode 100644 index 924877e2c9..0000000000 --- a/src/sys/run_metrics.cxx +++ /dev/null @@ -1,73 +0,0 @@ -/*!************************************************************************ - * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu - * - * Contact Ben Dudson, bd512@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - *********************************************************/ - -#include -#include -#include - -/*! - * Adds variables to the output file, for post-processing - */ -void RunMetrics::outputVars(Datafile &file) { - - file.add(t_elapsed, "wall_time", true); - file.add(wtime, "wtime", true); - file.add(ncalls, "ncalls", true); - file.add(ncalls_e, "ncalls_e", true); - file.add(ncalls_i, "ncalls_i", true); - file.add(wtime_rhs, "wtime_rhs", true); - file.add(wtime_invert, "wtime_invert", true); - file.add(wtime_comms, "wtime_comms", true); - file.add(wtime_io, "wtime_io", true); - file.add(wtime_per_rhs, "wtime_per_rhs", true); - file.add(wtime_per_rhs_e, "wtime_per_rhs_e", true); - file.add(wtime_per_rhs_i, "wtime_per_rhs_i", true); -} - -void RunMetrics::calculateDerivedMetrics() { - - wtime_per_rhs = wtime / ncalls; - wtime_per_rhs_e = wtime / ncalls_e; - wtime_per_rhs_i = wtime / ncalls_i; -} - -void RunMetrics::writeProgress(BoutReal simtime, bool output_split) { - - if (!output_split) { - output_progress.write("%.3e %5d %.2e %5.1f %5.1f %5.1f %5.1f %5.1f\n", - simtime, ncalls, wtime, - 100.0*(wtime_rhs - wtime_comms - wtime_invert)/wtime, - 100.*wtime_invert/wtime, // Inversions - 100.0*wtime_comms/wtime, // Communications - 100.* wtime_io / wtime, // I/O - 100.*(wtime - wtime_io - wtime_rhs)/wtime); // Everything else - - } else { - output_progress.write("%.3e %5d %5d %.2e %5.1f %5.1f %5.1f %5.1f %5.1f\n", - simtime, ncalls_e, ncalls_i, wtime, - 100.0*(wtime_rhs - wtime_comms - wtime_invert)/wtime, - 100.*wtime_invert/wtime, // Inversions - 100.0*wtime_comms/wtime, // Communications - 100.* wtime_io / wtime, // I/O - 100.*(wtime - wtime_io - wtime_rhs)/wtime); // Everything else - } -} From f407b43e7a2d3017953c386380ec38d937678d2b Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Tue, 5 Feb 2019 10:19:43 +0000 Subject: [PATCH 0699/1783] Update makefile --- src/sys/makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/makefile b/src/sys/makefile index ecfbe9bb4b..061d15da47 100644 --- a/src/sys/makefile +++ b/src/sys/makefile @@ -5,7 +5,7 @@ SOURCEC = bout_types.cxx boutexception.cxx derivs.cxx \ msg_stack.cxx options.cxx output.cxx \ utils.cxx optionsreader.cxx boutcomm.cxx \ timer.cxx range.cxx petsclib.cxx expressionparser.cxx \ - slepclib.cxx run_metrics.cxx + slepclib.cxx SOURCEH = $(SOURCEC:%.cxx=%.hxx) globals.hxx bout_types.hxx multiostream.hxx TARGET = lib From 69aea2521fa91024329a68ff86099bc050046194 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 5 Feb 2019 11:13:51 +0000 Subject: [PATCH 0700/1783] Fix: do y-interpolation in field-aligned space --- include/interpolation.hxx | 71 +++++++++++++++------------------------ 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/include/interpolation.hxx b/include/interpolation.hxx index 038285f824..2fe51191d9 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -118,53 +118,38 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { // At least 2 boundary cells needed for interpolation in y-direction ASSERT0(fieldmesh->ystart >= 2); - if (var.hasYupYdown()) { - if ((location == CELL_CENTRE) && (loc == CELL_YLOW)) { // C2L - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - // Producing a stencil centred around a lower X value - result[i] = interp( - populateStencil(var, i)); - } - } else if (location == CELL_YLOW) { // L2C - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - // Stencil centred around a cell centre - result[i] = interp( - populateStencil(var, i)); - } + // We can't interpolate in y unless we're field-aligned + // FIXME: Add check once we label fields as orthogonal/aligned + + const T var_fa = fieldmesh->toFieldAligned(var); + if (region != RGN_NOBNDRY) { + // repeat the hack above for boundary points + // this avoids a duplicate toFieldAligned call if we had called + // result = toFieldAligned(result) + // to get the boundary cells + // + // result is requested in some boundary region(s) + result = var_fa; // NOTE: This is just for boundaries. FIX! + result.allocate(); + result.setLocation(loc); + } + + if ((location == CELL_CENTRE) && (loc == CELL_YLOW)) { // C2L + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Producing a stencil centred around a lower X value + result[i] = + interp(populateStencil(var_fa, i)); } - } else { - // var has no yup/ydown fields, so we need to shift into field-aligned - // coordinates - - const T var_fa = fieldmesh->toFieldAligned(var); - if (region != RGN_NOBNDRY) { - // repeat the hack above for boundary points - // this avoids a duplicate toFieldAligned call if we had called - // result = toFieldAligned(result) - // to get the boundary cells - // - // result is requested in some boundary region(s) - result = var_fa; // NOTE: This is just for boundaries. FIX! - result.allocate(); - result.setLocation(loc); + } else if (location == CELL_YLOW) { // L2C + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Stencil centred around a cell centre + result[i] = + interp(populateStencil(var_fa, i)); } + } - if ((location == CELL_CENTRE) && (loc == CELL_YLOW)) { // C2L - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - // Producing a stencil centred around a lower X value - result[i] = interp( - populateStencil(var_fa, i)); - } - } else if (location == CELL_YLOW) { // L2C - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - // Stencil centred around a cell centre - result[i] = interp( - populateStencil(var_fa, i)); - } - } + result = fieldmesh->fromFieldAligned(result); - result = fieldmesh->fromFieldAligned(result); - } break; } case CELL_ZLOW: { From 2fe32070883848665d1abdfa542d9129e2f67f0b Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 5 Feb 2019 12:44:02 +0000 Subject: [PATCH 0701/1783] Increase grid size used in test_derivs unit tests --- tests/unit/include/test_derivs.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index dadd9e8910..8ee56e50ed 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -64,7 +64,7 @@ class DerivativesTest // This must be a balance between getting any kind of accuracy and // each derivative running in ~1ms or less - constexpr int grid_size{64}; + constexpr int grid_size{128}; const BoutReal box_length{TWOPI / grid_size}; // Set all the variables for this direction From ea3863c10fe36c33dc729b97682b3c79efeaaac9 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Tue, 5 Feb 2019 12:44:20 +0000 Subject: [PATCH 0702/1783] Add initial simple tests for advection derivatives --- tests/unit/include/test_derivs.cxx | 62 +++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index 8ee56e50ed..6e9f30db84 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -112,6 +112,9 @@ class DerivativesTest // C++17 makes this nicer with std::invoke input = makeField([&](Index& i) { return std::sin((i.*dir)() * box_length); }, mesh); + // Make the velocity field + velocity = makeField([&](Index& UNUSED(i)) { return 2.0; }, mesh); + // Get the expected result for this order of derivative // Again, could be nicer in C++17 with std::get(GetParam()) switch (std::get<1>(GetParam())) { @@ -129,6 +132,14 @@ class DerivativesTest [&](Index& i) { return std::sin((i.*dir)() * box_length) * pow(box_length, 4); }, mesh); break; + // For now advection derivatives (upwind, flux) can have the same expected + // result as the velocity field is constant + case DERIV::Upwind: + case DERIV::Flux: + expected = makeField( + [&](Index& i) { return 2.0 * std::cos((i.*dir)() * box_length) * box_length; }, + mesh); + break; default: throw BoutException("Sorry, don't we test that type of derivative yet!"); } @@ -141,13 +152,15 @@ class DerivativesTest DerivativeStore::getInstance().initialise(Options::getRoot()); }; - Field3D input; + Field3D input, velocity; Field3D expected; // Region not including the guard cells in current direction REGION region; }; +using DerivativesTestAdvection = DerivativesTest; + // Get all the available methods for this direction and turn it from a // collection of strings to a collection of tuples of the direction, // order, and strings so that the test fixture knows which direction @@ -225,6 +238,38 @@ INSTANTIATE_TEST_CASE_P(FourthZ, DerivativesTest, DIRECTION::Z)), methodDirectionTupleToString); +// Instantiate the test for X, Y, Z for upwind derivatives +INSTANTIATE_TEST_CASE_P(UpwindX, DerivativesTestAdvection, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Upwind, + DIRECTION::X)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(UpwindY, DerivativesTestAdvection, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Upwind, + DIRECTION::Y)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(UpwindZ, DerivativesTestAdvection, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Upwind, + DIRECTION::Z)), + methodDirectionTupleToString); + +// Instantiate the test for X, Y, Z for flux derivatives +INSTANTIATE_TEST_CASE_P(FluxX, DerivativesTestAdvection, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Flux, + DIRECTION::X)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(FluxY, DerivativesTestAdvection, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Flux, + DIRECTION::Y)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(FluxZ, DerivativesTestAdvection, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Flux, + DIRECTION::Z)), + methodDirectionTupleToString); + // All standard derivatives have the same signature, so we can use a // single test, just instantiate it for each direction/order combination TEST_P(DerivativesTest, Sanity) { @@ -238,3 +283,18 @@ TEST_P(DerivativesTest, Sanity) { EXPECT_TRUE(IsField3DEqualField3D(result, expected, "RGN_NOBNDRY", derivatives_tolerance)); } + +// All advection (upwind/flux) derivatives have the same signature, so we can use a +// single test, just instantiate it for each direction/order combination +TEST_P(DerivativesTestAdvection, Sanity) { + auto derivative = DerivativeStore::getInstance().getFlowDerivative( + std::get<2>(GetParam()), std::get<0>(GetParam()), STAGGER::None, + std::get<1>(GetParam())); + + Field3D result{mesh}; + result.allocate(); + derivative(velocity, input, result, region); + + EXPECT_TRUE( + IsField3DEqualField3D(result, expected, "RGN_NOBNDRY", derivatives_tolerance)); +} From f9a3f2d1c1a6b69c62cd4195adc84031dd1324dc Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 5 Feb 2019 14:55:45 +0000 Subject: [PATCH 0703/1783] Fix bug in DST option for cyclic solve Was putting data into bcmplx rather than bcmplx3D, so this solver always returned zero. --- src/invert/laplace/impls/cyclic/cyclic_laplace.cxx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index af950b7cbe..b4eac31fff 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -327,8 +327,9 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { } // Copy into array, transposing so kz is first index - for (int kz = 0; kz < nmode; kz++) - bcmplx((iy - ys) * nmode + kz, ix - xs) = k1d[kz]; + for (int kz = 0; kz < nmode; kz++) { + bcmplx3D((iy - ys) * nmode + kz, ix - xs) = k1d[kz]; + } } // Get elements of the tridiagonal matrix @@ -368,8 +369,9 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { int ix = xs + ind / ny; int iy = ys + ind % ny; - for (int kz = 0; kz < nmode; kz++) + for (int kz = 0; kz < nmode; kz++) { k1d[kz] = xcmplx3D((iy - ys) * nmode + kz, ix - xs); + } for (int kz = nmode; kz < localmesh->LocalNz; kz++) k1d[kz] = 0.0; // Filtering out all higher harmonics From 64cbef311b54db650b9af5b90d25b5c0c23f43f6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 5 Feb 2019 16:04:13 +0000 Subject: [PATCH 0704/1783] Use nullptr as default Mesh* argument for Laplacian::create and also for LaplaceFactory::createLaplacian. LaplaceFactory uses bout::globals::mesh if the input 'Mesh* mesh_in' is nullptr. --- include/invert_laplace.hxx | 2 +- src/invert/laplace/laplacefactory.cxx | 4 ++++ src/invert/laplace/laplacefactory.hxx | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index a2cca2b2d0..e6a4417208 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -192,7 +192,7 @@ public: * * @param[in] opt The options section to use. By default "laplace" will be used */ - static Laplacian *create(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = bout::globals::mesh); + static Laplacian *create(Options *opt = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh *mesh_in = nullptr); static Laplacian* defaultInstance(); ///< Return pointer to global singleton static void cleanup(); ///< Frees all memory diff --git a/src/invert/laplace/laplacefactory.cxx b/src/invert/laplace/laplacefactory.cxx index 777cecb2dc..e112249d57 100644 --- a/src/invert/laplace/laplacefactory.cxx +++ b/src/invert/laplace/laplacefactory.cxx @@ -41,6 +41,10 @@ Laplacian* LaplaceFactory::createLaplacian(Options *options, const CELL_LOC loc, if (options == nullptr) options = Options::getRoot()->getSection("laplace"); + if (mesh_in == nullptr) { + mesh_in = bout::globals::mesh; + } + std::string type; if(mesh_in->firstX() && mesh_in->lastX()) { diff --git a/src/invert/laplace/laplacefactory.hxx b/src/invert/laplace/laplacefactory.hxx index 79a618ef00..780e8c2410 100644 --- a/src/invert/laplace/laplacefactory.hxx +++ b/src/invert/laplace/laplacefactory.hxx @@ -12,7 +12,7 @@ class LaplaceFactory { static LaplaceFactory* getInstance(); Laplacian *createLaplacian(Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE, - Mesh *mesh_in = bout::globals::mesh); + Mesh *mesh_in = nullptr); private: LaplaceFactory() {} // Prevent instantiation of this class From 77ab0d4a94f8dba1e6b4732a87394e473e78d92b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 5 Feb 2019 17:18:46 +0000 Subject: [PATCH 0705/1783] Replace IsField*Equal* predicates with templated versions --- tests/unit/field/test_field2d.cxx | 144 ++++++------ tests/unit/field/test_field3d.cxx | 210 +++++++++--------- tests/unit/field/test_fieldperp.cxx | 188 ++++++++-------- tests/unit/field/test_vector2d.cxx | 148 ++++++------ tests/unit/field/test_vector3d.cxx | 166 +++++++------- tests/unit/include/test_derivs.cxx | 6 +- .../unit/mesh/parallel/test_shiftedmetric.cxx | 9 +- tests/unit/mesh/test_coordinates.cxx | 28 +-- tests/unit/test_extras.cxx | 72 ------ tests/unit/test_extras.hxx | 80 +++++-- 10 files changed, 509 insertions(+), 542 deletions(-) diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index 5174afba11..f1baf92688 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -629,14 +629,14 @@ TEST_F(Field2DTest, InvalidateGuards) { TEST_F(Field2DTest, CreateFromBoutReal) { Field2D field(1.0); - EXPECT_TRUE(IsField2DEqualBoutReal(field, 1.0)); + EXPECT_TRUE(IsFieldEqual(field, 1.0)); } TEST_F(Field2DTest, CreateFromField2D) { Field2D field(99.0); Field2D result(field); - EXPECT_TRUE(IsField2DEqualBoutReal(result, 99.0)); + EXPECT_TRUE(IsFieldEqual(result, 99.0)); } TEST_F(Field2DTest, AssignFromBoutReal) { @@ -644,14 +644,14 @@ TEST_F(Field2DTest, AssignFromBoutReal) { field = 2.0; - EXPECT_TRUE(IsField2DEqualBoutReal(field, 2.0)); + EXPECT_TRUE(IsFieldEqual(field, 2.0)); } TEST_F(Field2DTest, AssignFromInvalid) { Field2D field; EXPECT_NO_THROW(field = std::nan("")); - EXPECT_TRUE(IsField2DEqualBoutReal(field, std::nan(""))); + EXPECT_TRUE(IsFieldEqual(field, std::nan(""))); } TEST_F(Field2DTest, UnaryMinus) { @@ -660,7 +660,7 @@ TEST_F(Field2DTest, UnaryMinus) { field = 2.0; field = -field; - EXPECT_TRUE(IsField2DEqualBoutReal(field, -2.0)); + EXPECT_TRUE(IsFieldEqual(field, -2.0)); } TEST_F(Field2DTest, AddEqualsBoutReal) { @@ -669,14 +669,14 @@ TEST_F(Field2DTest, AddEqualsBoutReal) { a = 1.0; a += 5.0; - EXPECT_TRUE(IsField2DEqualBoutReal(a, 6.0)); + EXPECT_TRUE(IsFieldEqual(a, 6.0)); // Check case where field is not unique auto c = a; c += 5.0; - EXPECT_TRUE(IsField2DEqualBoutReal(a, 6.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(c, 11.0)); + EXPECT_TRUE(IsFieldEqual(a, 6.0)); + EXPECT_TRUE(IsFieldEqual(c, 11.0)); } TEST_F(Field2DTest, AddEqualsField2D) { @@ -686,14 +686,14 @@ TEST_F(Field2DTest, AddEqualsField2D) { b = 3.0; a += b; - EXPECT_TRUE(IsField2DEqualBoutReal(a, 5.0)); + EXPECT_TRUE(IsFieldEqual(a, 5.0)); // Check case where field is not unique auto c = a; c += b; - EXPECT_TRUE(IsField2DEqualBoutReal(a, 5.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(c, 8.0)); + EXPECT_TRUE(IsFieldEqual(a, 5.0)); + EXPECT_TRUE(IsFieldEqual(c, 8.0)); } TEST_F(Field2DTest, AddField2DBoutReal) { @@ -702,7 +702,7 @@ TEST_F(Field2DTest, AddField2DBoutReal) { a = 1.0; b = a + 2.0; - EXPECT_TRUE(IsField2DEqualBoutReal(b, 3.0)); + EXPECT_TRUE(IsFieldEqual(b, 3.0)); } TEST_F(Field2DTest, AddBoutRealField2D) { @@ -711,7 +711,7 @@ TEST_F(Field2DTest, AddBoutRealField2D) { a = 1.0; b = 3.0 + a; - EXPECT_TRUE(IsField2DEqualBoutReal(b, 4.0)); + EXPECT_TRUE(IsFieldEqual(b, 4.0)); } TEST_F(Field2DTest, AddField2DField2D) { @@ -721,7 +721,7 @@ TEST_F(Field2DTest, AddField2DField2D) { b = 2.0; c = a + b; - EXPECT_TRUE(IsField2DEqualBoutReal(c, 3.0)); + EXPECT_TRUE(IsFieldEqual(c, 3.0)); } TEST_F(Field2DTest, MultiplyEqualsBoutReal) { @@ -730,14 +730,14 @@ TEST_F(Field2DTest, MultiplyEqualsBoutReal) { a = 2.0; a *= 1.5; - EXPECT_TRUE(IsField2DEqualBoutReal(a, 3.0)); + EXPECT_TRUE(IsFieldEqual(a, 3.0)); // Check case where field is not unique auto c = a; c *= 1.5; - EXPECT_TRUE(IsField2DEqualBoutReal(a, 3.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(c, 4.5)); + EXPECT_TRUE(IsFieldEqual(a, 3.0)); + EXPECT_TRUE(IsFieldEqual(c, 4.5)); } TEST_F(Field2DTest, MultiplyEqualsField2D) { @@ -747,14 +747,14 @@ TEST_F(Field2DTest, MultiplyEqualsField2D) { b = 4.0; a *= b; - EXPECT_TRUE(IsField2DEqualBoutReal(a, 10.0)); + EXPECT_TRUE(IsFieldEqual(a, 10.0)); // Check case where field is not unique auto c = a; c *= b; - EXPECT_TRUE(IsField2DEqualBoutReal(a, 10.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(c, 40.0)); + EXPECT_TRUE(IsFieldEqual(a, 10.0)); + EXPECT_TRUE(IsFieldEqual(c, 40.0)); } TEST_F(Field2DTest, MultiplyField2DBoutReal) { @@ -763,7 +763,7 @@ TEST_F(Field2DTest, MultiplyField2DBoutReal) { a = 1.5; b = a * 2.0; - EXPECT_TRUE(IsField2DEqualBoutReal(b, 3.0)); + EXPECT_TRUE(IsFieldEqual(b, 3.0)); } TEST_F(Field2DTest, MultiplyBoutRealField2D) { @@ -772,7 +772,7 @@ TEST_F(Field2DTest, MultiplyBoutRealField2D) { a = 2.5; b = 3.0 * a; - EXPECT_TRUE(IsField2DEqualBoutReal(b, 7.5)); + EXPECT_TRUE(IsFieldEqual(b, 7.5)); } TEST_F(Field2DTest, MultiplyField2DField2D) { @@ -782,7 +782,7 @@ TEST_F(Field2DTest, MultiplyField2DField2D) { b = 8.0; c = a * b; - EXPECT_TRUE(IsField2DEqualBoutReal(c, 32.0)); + EXPECT_TRUE(IsFieldEqual(c, 32.0)); } TEST_F(Field2DTest, SubtractEqualsBoutReal) { @@ -791,14 +791,14 @@ TEST_F(Field2DTest, SubtractEqualsBoutReal) { a = 1.0; a -= 5.0; - EXPECT_TRUE(IsField2DEqualBoutReal(a, -4.0)); + EXPECT_TRUE(IsFieldEqual(a, -4.0)); // Check case where field is not unique auto c = a; c -= 5.0; - EXPECT_TRUE(IsField2DEqualBoutReal(a, -4.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(c, -9.0)); + EXPECT_TRUE(IsFieldEqual(a, -4.0)); + EXPECT_TRUE(IsFieldEqual(c, -9.0)); } TEST_F(Field2DTest, SubtractEqualsField2D) { @@ -808,14 +808,14 @@ TEST_F(Field2DTest, SubtractEqualsField2D) { b = 7.0; a -= b; - EXPECT_TRUE(IsField2DEqualBoutReal(a, -5.0)); + EXPECT_TRUE(IsFieldEqual(a, -5.0)); // Check case where field is not unique auto c = a; c -= b; - EXPECT_TRUE(IsField2DEqualBoutReal(a, -5.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(c, -12.0)); + EXPECT_TRUE(IsFieldEqual(a, -5.0)); + EXPECT_TRUE(IsFieldEqual(c, -12.0)); } TEST_F(Field2DTest, SubtractField2DBoutReal) { @@ -824,7 +824,7 @@ TEST_F(Field2DTest, SubtractField2DBoutReal) { a = 10.0; b = a - 2.0; - EXPECT_TRUE(IsField2DEqualBoutReal(b, 8.0)); + EXPECT_TRUE(IsFieldEqual(b, 8.0)); } TEST_F(Field2DTest, SubtractBoutRealField2D) { @@ -833,7 +833,7 @@ TEST_F(Field2DTest, SubtractBoutRealField2D) { a = 10.0; b = 3.0 - a; - EXPECT_TRUE(IsField2DEqualBoutReal(b, -7.0)); + EXPECT_TRUE(IsFieldEqual(b, -7.0)); } TEST_F(Field2DTest, SubtractField2DField2D) { @@ -843,7 +843,7 @@ TEST_F(Field2DTest, SubtractField2DField2D) { b = 20.0; c = a - b; - EXPECT_TRUE(IsField2DEqualBoutReal(c, -10.0)); + EXPECT_TRUE(IsFieldEqual(c, -10.0)); } TEST_F(Field2DTest, DivideEqualsBoutReal) { @@ -852,14 +852,14 @@ TEST_F(Field2DTest, DivideEqualsBoutReal) { a = 2.5; a /= 5.0; - EXPECT_TRUE(IsField2DEqualBoutReal(a, 0.5)); + EXPECT_TRUE(IsFieldEqual(a, 0.5)); // Check case where field is not unique auto c = a; c /= 5.0; - EXPECT_TRUE(IsField2DEqualBoutReal(a, 0.5)); - EXPECT_TRUE(IsField2DEqualBoutReal(c, 0.1)); + EXPECT_TRUE(IsFieldEqual(a, 0.5)); + EXPECT_TRUE(IsFieldEqual(c, 0.1)); } TEST_F(Field2DTest, DivideEqualsField2D) { @@ -869,14 +869,14 @@ TEST_F(Field2DTest, DivideEqualsField2D) { b = 2.5; a /= b; - EXPECT_TRUE(IsField2DEqualBoutReal(a, 2.0)); + EXPECT_TRUE(IsFieldEqual(a, 2.0)); // Check case where field is not unique auto c = a; c /= b; - EXPECT_TRUE(IsField2DEqualBoutReal(a, 2.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(c, 0.8)); + EXPECT_TRUE(IsFieldEqual(a, 2.0)); + EXPECT_TRUE(IsFieldEqual(c, 0.8)); } TEST_F(Field2DTest, DivideField2DBoutReal) { @@ -885,7 +885,7 @@ TEST_F(Field2DTest, DivideField2DBoutReal) { a = 3.0; b = a / 2.0; - EXPECT_TRUE(IsField2DEqualBoutReal(b, 1.5)); + EXPECT_TRUE(IsFieldEqual(b, 1.5)); } TEST_F(Field2DTest, DivideBoutRealField2D) { @@ -894,7 +894,7 @@ TEST_F(Field2DTest, DivideBoutRealField2D) { a = 2.5; b = 10.0 / a; - EXPECT_TRUE(IsField2DEqualBoutReal(b, 4.0)); + EXPECT_TRUE(IsFieldEqual(b, 4.0)); } TEST_F(Field2DTest, DivideField2DField2D) { @@ -904,7 +904,7 @@ TEST_F(Field2DTest, DivideField2DField2D) { b = 8.0; c = a / b; - EXPECT_TRUE(IsField2DEqualBoutReal(c, 4.0)); + EXPECT_TRUE(IsFieldEqual(c, 4.0)); } TEST_F(Field2DTest, PowBoutRealField2D) { @@ -912,7 +912,7 @@ TEST_F(Field2DTest, PowBoutRealField2D) { a = 5.0; b = pow(2.0, a); - EXPECT_TRUE(IsField2DEqualBoutReal(b, 32.0)); + EXPECT_TRUE(IsFieldEqual(b, 32.0)); } TEST_F(Field2DTest, PowField2DBoutReal) { @@ -920,7 +920,7 @@ TEST_F(Field2DTest, PowField2DBoutReal) { a = 5.0; b = pow(a, 2.0); - EXPECT_TRUE(IsField2DEqualBoutReal(b, 25.0)); + EXPECT_TRUE(IsFieldEqual(b, 25.0)); } TEST_F(Field2DTest, PowField2DField2D) { @@ -929,21 +929,21 @@ TEST_F(Field2DTest, PowField2DField2D) { b = 6.0; c = pow(a, b); - EXPECT_TRUE(IsField2DEqualBoutReal(c, 64.0)); + EXPECT_TRUE(IsFieldEqual(c, 64.0)); } TEST_F(Field2DTest, Sqrt) { Field2D field; field = 16.0; - EXPECT_TRUE(IsField2DEqualBoutReal(sqrt(field), 4.0)); + EXPECT_TRUE(IsFieldEqual(sqrt(field), 4.0)); } TEST_F(Field2DTest, Abs) { Field2D field; field = -31.0; - EXPECT_TRUE(IsField2DEqualBoutReal(abs(field), 31.0)); + EXPECT_TRUE(IsFieldEqual(abs(field), 31.0)); } TEST_F(Field2DTest, Exp) { @@ -951,7 +951,7 @@ TEST_F(Field2DTest, Exp) { field = 2.5; const BoutReal expected = 12.182493960703473; - EXPECT_TRUE(IsField2DEqualBoutReal(exp(field), expected)); + EXPECT_TRUE(IsFieldEqual(exp(field), expected)); } TEST_F(Field2DTest, Log) { @@ -959,7 +959,7 @@ TEST_F(Field2DTest, Log) { field = 12.182493960703473; const BoutReal expected = 2.5; - EXPECT_TRUE(IsField2DEqualBoutReal(log(field), expected)); + EXPECT_TRUE(IsFieldEqual(log(field), expected)); } TEST_F(Field2DTest, LogExp) { @@ -967,37 +967,37 @@ TEST_F(Field2DTest, LogExp) { field = 2.5; const BoutReal expected = 2.5; - EXPECT_TRUE(IsField2DEqualBoutReal(log(exp(field)), expected)); + EXPECT_TRUE(IsFieldEqual(log(exp(field)), expected)); } TEST_F(Field2DTest, Sin) { Field2D field; field = PI / 2.0; - EXPECT_TRUE(IsField2DEqualBoutReal(sin(field), 1.0)); + EXPECT_TRUE(IsFieldEqual(sin(field), 1.0)); field = PI; - EXPECT_TRUE(IsField2DEqualBoutReal(sin(field), 0.0)); + EXPECT_TRUE(IsFieldEqual(sin(field), 0.0)); } TEST_F(Field2DTest, Cos) { Field2D field; field = PI / 2.0; - EXPECT_TRUE(IsField2DEqualBoutReal(cos(field), 0.0)); + EXPECT_TRUE(IsFieldEqual(cos(field), 0.0)); field = PI; - EXPECT_TRUE(IsField2DEqualBoutReal(cos(field), -1.0)); + EXPECT_TRUE(IsFieldEqual(cos(field), -1.0)); } TEST_F(Field2DTest, Tan) { Field2D field; field = PI / 4.0; - EXPECT_TRUE(IsField2DEqualBoutReal(tan(field), 1.0)); + EXPECT_TRUE(IsFieldEqual(tan(field), 1.0)); field = PI; - EXPECT_TRUE(IsField2DEqualBoutReal(tan(field), 0.0)); + EXPECT_TRUE(IsFieldEqual(tan(field), 0.0)); } TEST_F(Field2DTest, Sinh) { @@ -1005,10 +1005,10 @@ TEST_F(Field2DTest, Sinh) { field = 1.0; const BoutReal expected = 1.1752011936438014; - EXPECT_TRUE(IsField2DEqualBoutReal(sinh(field), expected)); + EXPECT_TRUE(IsFieldEqual(sinh(field), expected)); field = -1.0; - EXPECT_TRUE(IsField2DEqualBoutReal(sinh(field), -expected)); + EXPECT_TRUE(IsFieldEqual(sinh(field), -expected)); } TEST_F(Field2DTest, Cosh) { @@ -1016,10 +1016,10 @@ TEST_F(Field2DTest, Cosh) { field = 1.0; const BoutReal expected = 1.5430806348152437; - EXPECT_TRUE(IsField2DEqualBoutReal(cosh(field), expected)); + EXPECT_TRUE(IsFieldEqual(cosh(field), expected)); field = -1.0; - EXPECT_TRUE(IsField2DEqualBoutReal(cosh(field), expected)); + EXPECT_TRUE(IsFieldEqual(cosh(field), expected)); } TEST_F(Field2DTest, Tanh) { @@ -1027,10 +1027,10 @@ TEST_F(Field2DTest, Tanh) { field = 1.0; const BoutReal expected = 0.761594155955764; - EXPECT_TRUE(IsField2DEqualBoutReal(tanh(field), expected)); + EXPECT_TRUE(IsFieldEqual(tanh(field), expected)); field = -1.0; - EXPECT_TRUE(IsField2DEqualBoutReal(tanh(field), -expected)); + EXPECT_TRUE(IsFieldEqual(tanh(field), -expected)); } TEST_F(Field2DTest, Floor) { @@ -1042,7 +1042,7 @@ TEST_F(Field2DTest, Floor) { const BoutReal floor_value = 50.0; - EXPECT_TRUE(IsField2DEqualBoutReal(floor(field, floor_value), floor_value)); + EXPECT_TRUE(IsFieldEqual(floor(field, floor_value), floor_value)); } TEST_F(Field2DTest, Min) { @@ -1107,18 +1107,18 @@ TEST_F(Field2DTest, Swap) { ddt(second) = 2.4; // Basic sanity check - EXPECT_TRUE(IsField2DEqualBoutReal(first, 1.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(second, 2.0)); + EXPECT_TRUE(IsFieldEqual(first, 1.0)); + EXPECT_TRUE(IsFieldEqual(second, 2.0)); // swap is marked noexcept, so absolutely should not throw! ASSERT_NO_THROW(swap(first, second)); // Values - EXPECT_TRUE(IsField2DEqualBoutReal(first, 2.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(second, 1.0)); + EXPECT_TRUE(IsFieldEqual(first, 2.0)); + EXPECT_TRUE(IsFieldEqual(second, 1.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(ddt(first), 2.4)); - EXPECT_TRUE(IsField2DEqualBoutReal(ddt(second), 1.1)); + EXPECT_TRUE(IsFieldEqual(ddt(first), 2.4)); + EXPECT_TRUE(IsFieldEqual(ddt(second), 1.1)); // Mesh properties EXPECT_EQ(first.getMesh(), &second_mesh); @@ -1156,9 +1156,9 @@ TEST_F(Field2DTest, MoveCtor) { Field2D second{std::move(first)}; // Values - EXPECT_TRUE(IsField2DEqualBoutReal(second, 1.0)); + EXPECT_TRUE(IsFieldEqual(second, 1.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(ddt(second), 1.1)); + EXPECT_TRUE(IsFieldEqual(ddt(second), 1.1)); // Mesh properties EXPECT_EQ(second.getMesh(), mesh); @@ -1180,7 +1180,7 @@ TEST_F(Field2DTest, FillField) { fillField(f, {{1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1.}}); - EXPECT_TRUE(IsField3DEqualBoutReal(f, 1.)); + EXPECT_TRUE(IsFieldEqual(f, 1.)); fillField(f, {{0., 1., 2., 3., 4.}, {0., 1., 2., 3., 4.}, {0., 1., 2., 3., 4.}}); @@ -1188,7 +1188,7 @@ TEST_F(Field2DTest, FillField) { g.allocate(); BOUT_FOR_SERIAL(i, g.getRegion("RGN_ALL")) { g[i] = i.y(); } - EXPECT_TRUE(IsField2DEqualField2D(f, g)); + EXPECT_TRUE(IsFieldEqual(f, g)); } #pragma GCC diagnostic pop diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 3fa1c709d1..c9426fdbe4 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -947,21 +947,21 @@ TEST_F(Field3DTest, InvalidateGuards) { TEST_F(Field3DTest, CreateFromBoutReal) { Field3D field(1.0); - EXPECT_TRUE(IsField3DEqualBoutReal(field, 1.0)); + EXPECT_TRUE(IsFieldEqual(field, 1.0)); } TEST_F(Field3DTest, CreateFromField3D) { Field3D field(99.0); Field3D result(field); - EXPECT_TRUE(IsField3DEqualBoutReal(result, 99.0)); + EXPECT_TRUE(IsFieldEqual(result, 99.0)); } TEST_F(Field3DTest, CreateFromField2D) { Field2D field(99.0); Field3D result(field); - EXPECT_TRUE(IsField3DEqualBoutReal(result, 99.0)); + EXPECT_TRUE(IsFieldEqual(result, 99.0)); } TEST_F(Field3DTest, AssignFromBoutReal) { @@ -969,14 +969,14 @@ TEST_F(Field3DTest, AssignFromBoutReal) { field = 2.0; - EXPECT_TRUE(IsField3DEqualBoutReal(field, 2.0)); + EXPECT_TRUE(IsFieldEqual(field, 2.0)); } TEST_F(Field3DTest, AssignFromInvalid) { Field3D field; EXPECT_NO_THROW(field = std::nan("")); - EXPECT_TRUE(IsField3DEqualBoutReal(field, std::nan(""))); + EXPECT_TRUE(IsFieldEqual(field, std::nan(""))); } TEST_F(Field3DTest, AssignFromField2D) { @@ -985,7 +985,7 @@ TEST_F(Field3DTest, AssignFromField2D) { field = field2; - EXPECT_TRUE(IsField3DEqualBoutReal(field, 2.0)); + EXPECT_TRUE(IsFieldEqual(field, 2.0)); #if CHECK > 0 Field2D field3; @@ -1025,7 +1025,7 @@ TEST_F(Field3DTest, AssignFromField3D) { field2 = -99.0; field = field2; - EXPECT_TRUE(IsField3DEqualBoutReal(field, -99.0)); + EXPECT_TRUE(IsFieldEqual(field, -99.0)); Field3D field3; EXPECT_NO_THROW(field = field3); @@ -1039,8 +1039,8 @@ TEST_F(Field3DTest, UnaryMinus) { field = 2.0; field = -field; - EXPECT_TRUE(IsField3DEqualBoutReal(field, -2.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(-field, 2.0)); + EXPECT_TRUE(IsFieldEqual(field, -2.0)); + EXPECT_TRUE(IsFieldEqual(-field, 2.0)); } TEST_F(Field3DTest, AddEqualsBoutReal) { @@ -1049,14 +1049,14 @@ TEST_F(Field3DTest, AddEqualsBoutReal) { a = 1.0; a += 5.0; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 6.0)); + EXPECT_TRUE(IsFieldEqual(a, 6.0)); // Check case where field is not unique auto c = a; c += 5.0; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 6.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(c, 11.0)); + EXPECT_TRUE(IsFieldEqual(a, 6.0)); + EXPECT_TRUE(IsFieldEqual(c, 11.0)); } TEST_F(Field3DTest, AddEqualsField2D) { @@ -1067,14 +1067,14 @@ TEST_F(Field3DTest, AddEqualsField2D) { b = 3.0; a += b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 5.0)); + EXPECT_TRUE(IsFieldEqual(a, 5.0)); // Check case where field is not unique auto c = a; c += b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 5.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(c, 8.0)); + EXPECT_TRUE(IsFieldEqual(a, 5.0)); + EXPECT_TRUE(IsFieldEqual(c, 8.0)); } TEST_F(Field3DTest, AddEqualsField3D) { @@ -1084,14 +1084,14 @@ TEST_F(Field3DTest, AddEqualsField3D) { b = 3.0; a += b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 5.0)); + EXPECT_TRUE(IsFieldEqual(a, 5.0)); // Check case where field is not unique auto c = a; c += b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 5.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(c, 8.0)); + EXPECT_TRUE(IsFieldEqual(a, 5.0)); + EXPECT_TRUE(IsFieldEqual(c, 8.0)); } TEST_F(Field3DTest, AddEqualsField3DField3DStagger) { @@ -1119,7 +1119,7 @@ TEST_F(Field3DTest, AddField3DBoutReal) { a = 1.0; b = a + 2.0; - EXPECT_TRUE(IsField3DEqualBoutReal(b, 3.0)); + EXPECT_TRUE(IsFieldEqual(b, 3.0)); } TEST_F(Field3DTest, AddBoutRealField3D) { @@ -1128,7 +1128,7 @@ TEST_F(Field3DTest, AddBoutRealField3D) { a = 1.0; b = 3.0 + a; - EXPECT_TRUE(IsField3DEqualBoutReal(b, 4.0)); + EXPECT_TRUE(IsFieldEqual(b, 4.0)); } TEST_F(Field3DTest, AddField2DField3D) { @@ -1139,7 +1139,7 @@ TEST_F(Field3DTest, AddField2DField3D) { b = 2.0; c = a + b; - EXPECT_TRUE(IsField3DEqualBoutReal(c, 3.0)); + EXPECT_TRUE(IsFieldEqual(c, 3.0)); } TEST_F(Field3DTest, AddField3DField2D) { @@ -1150,7 +1150,7 @@ TEST_F(Field3DTest, AddField3DField2D) { b = 2.0; c = a + b; - EXPECT_TRUE(IsField3DEqualBoutReal(c, 3.0)); + EXPECT_TRUE(IsFieldEqual(c, 3.0)); } TEST_F(Field3DTest, AddField3DField3D) { @@ -1160,7 +1160,7 @@ TEST_F(Field3DTest, AddField3DField3D) { b = 2.0; c = a + b; - EXPECT_TRUE(IsField3DEqualBoutReal(c, 3.0)); + EXPECT_TRUE(IsFieldEqual(c, 3.0)); } TEST_F(Field3DTest, AddField3DField3DStagger) { @@ -1196,14 +1196,14 @@ TEST_F(Field3DTest, MultiplyEqualsBoutReal) { a = 2.0; a *= 1.5; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 3.0)); + EXPECT_TRUE(IsFieldEqual(a, 3.0)); // Check case where field is not unique auto c = a; c *= 1.5; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 3.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(c, 4.5)); + EXPECT_TRUE(IsFieldEqual(a, 3.0)); + EXPECT_TRUE(IsFieldEqual(c, 4.5)); } TEST_F(Field3DTest, MultiplyEqualsField2D) { @@ -1214,14 +1214,14 @@ TEST_F(Field3DTest, MultiplyEqualsField2D) { b = 4.0; a *= b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 10.0)); + EXPECT_TRUE(IsFieldEqual(a, 10.0)); // Check case where field is not unique auto c = a; c *= b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 10.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(c, 40.0)); + EXPECT_TRUE(IsFieldEqual(a, 10.0)); + EXPECT_TRUE(IsFieldEqual(c, 40.0)); } TEST_F(Field3DTest, MultiplyEqualsField3D) { @@ -1231,14 +1231,14 @@ TEST_F(Field3DTest, MultiplyEqualsField3D) { b = 4.0; a *= b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 10.0)); + EXPECT_TRUE(IsFieldEqual(a, 10.0)); // Check case where field is not unique auto c = a; c *= b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 10.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(c, 40.0)); + EXPECT_TRUE(IsFieldEqual(a, 10.0)); + EXPECT_TRUE(IsFieldEqual(c, 40.0)); } TEST_F(Field3DTest, MultiplyEqualsField3DField3DStagger) { @@ -1266,7 +1266,7 @@ TEST_F(Field3DTest, MultiplyField3DBoutReal) { a = 1.5; b = a * 2.0; - EXPECT_TRUE(IsField3DEqualBoutReal(b, 3.0)); + EXPECT_TRUE(IsFieldEqual(b, 3.0)); } TEST_F(Field3DTest, MultiplyBoutRealField3D) { @@ -1275,7 +1275,7 @@ TEST_F(Field3DTest, MultiplyBoutRealField3D) { a = 2.5; b = 3.0 * a; - EXPECT_TRUE(IsField3DEqualBoutReal(b, 7.5)); + EXPECT_TRUE(IsFieldEqual(b, 7.5)); } TEST_F(Field3DTest, MultiplyField2DField3D) { @@ -1286,7 +1286,7 @@ TEST_F(Field3DTest, MultiplyField2DField3D) { b = 4.0; c = a * b; - EXPECT_TRUE(IsField3DEqualBoutReal(c, 16.0)); + EXPECT_TRUE(IsFieldEqual(c, 16.0)); } TEST_F(Field3DTest, MultiplyField3DField2D) { @@ -1297,7 +1297,7 @@ TEST_F(Field3DTest, MultiplyField3DField2D) { b = 8.0; c = a * b; - EXPECT_TRUE(IsField3DEqualBoutReal(c, 64.0)); + EXPECT_TRUE(IsFieldEqual(c, 64.0)); } TEST_F(Field3DTest, MultiplyField3DField3D) { @@ -1307,7 +1307,7 @@ TEST_F(Field3DTest, MultiplyField3DField3D) { b = 8.0; c = a * b; - EXPECT_TRUE(IsField3DEqualBoutReal(c, 32.0)); + EXPECT_TRUE(IsFieldEqual(c, 32.0)); } TEST_F(Field3DTest, MultiplyField3DField3DStagger) { @@ -1343,14 +1343,14 @@ TEST_F(Field3DTest, SubtractEqualsBoutReal) { a = 1.0; a -= 5.0; - EXPECT_TRUE(IsField3DEqualBoutReal(a, -4.0)); + EXPECT_TRUE(IsFieldEqual(a, -4.0)); // Check case where field is not unique auto c = a; c -= 5.0; - EXPECT_TRUE(IsField3DEqualBoutReal(a, -4.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(c, -9.0)); + EXPECT_TRUE(IsFieldEqual(a, -4.0)); + EXPECT_TRUE(IsFieldEqual(c, -9.0)); } TEST_F(Field3DTest, SubtractEqualsField2D) { @@ -1361,14 +1361,14 @@ TEST_F(Field3DTest, SubtractEqualsField2D) { b = 7.0; a -= b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, -5.0)); + EXPECT_TRUE(IsFieldEqual(a, -5.0)); // Check case where field is not unique auto c = a; c -= b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, -5.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(c, -12.0)); + EXPECT_TRUE(IsFieldEqual(a, -5.0)); + EXPECT_TRUE(IsFieldEqual(c, -12.0)); } TEST_F(Field3DTest, SubtractEqualsField3D) { @@ -1378,14 +1378,14 @@ TEST_F(Field3DTest, SubtractEqualsField3D) { b = 7.0; a -= b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, -5.0)); + EXPECT_TRUE(IsFieldEqual(a, -5.0)); // Check case where field is not unique auto c = a; c -= b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, -5.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(c, -12.0)); + EXPECT_TRUE(IsFieldEqual(a, -5.0)); + EXPECT_TRUE(IsFieldEqual(c, -12.0)); } TEST_F(Field3DTest, SubtractEqualsField3DField3DStagger) { @@ -1413,7 +1413,7 @@ TEST_F(Field3DTest, SubtractField3DBoutReal) { a = 10.0; b = a - 2.0; - EXPECT_TRUE(IsField3DEqualBoutReal(b, 8.0)); + EXPECT_TRUE(IsFieldEqual(b, 8.0)); } TEST_F(Field3DTest, SubtractBoutRealField3D) { @@ -1422,7 +1422,7 @@ TEST_F(Field3DTest, SubtractBoutRealField3D) { a = 10.0; b = 3.0 - a; - EXPECT_TRUE(IsField3DEqualBoutReal(b, -7.0)); + EXPECT_TRUE(IsFieldEqual(b, -7.0)); } TEST_F(Field3DTest, SubtractField2DField3D) { @@ -1433,7 +1433,7 @@ TEST_F(Field3DTest, SubtractField2DField3D) { b = 20.0; c = a - b; - EXPECT_TRUE(IsField3DEqualBoutReal(c, -10.0)); + EXPECT_TRUE(IsFieldEqual(c, -10.0)); } TEST_F(Field3DTest, SubtractField3DField2D) { @@ -1444,7 +1444,7 @@ TEST_F(Field3DTest, SubtractField3DField2D) { b = 20.0; c = a - b; - EXPECT_TRUE(IsField3DEqualBoutReal(c, -10.0)); + EXPECT_TRUE(IsFieldEqual(c, -10.0)); } TEST_F(Field3DTest, SubtractField3DField3D) { @@ -1454,7 +1454,7 @@ TEST_F(Field3DTest, SubtractField3DField3D) { b = 20.0; c = a - b; - EXPECT_TRUE(IsField3DEqualBoutReal(c, -10.0)); + EXPECT_TRUE(IsFieldEqual(c, -10.0)); } TEST_F(Field3DTest, SubtractField3DField3DStagger) { @@ -1490,14 +1490,14 @@ TEST_F(Field3DTest, DivideEqualsBoutReal) { a = 2.5; a /= 5.0; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 0.5)); + EXPECT_TRUE(IsFieldEqual(a, 0.5)); // Check case where field is not unique auto c = a; c /= 5.0; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 0.5)); - EXPECT_TRUE(IsField3DEqualBoutReal(c, 0.1)); + EXPECT_TRUE(IsFieldEqual(a, 0.5)); + EXPECT_TRUE(IsFieldEqual(c, 0.1)); } TEST_F(Field3DTest, DivideEqualsField2D) { @@ -1508,14 +1508,14 @@ TEST_F(Field3DTest, DivideEqualsField2D) { b = 2.5; a /= b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 2.0)); + EXPECT_TRUE(IsFieldEqual(a, 2.0)); // Check case where field is not unique auto c = a; c /= b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 2.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(c, 0.8)); + EXPECT_TRUE(IsFieldEqual(a, 2.0)); + EXPECT_TRUE(IsFieldEqual(c, 0.8)); } TEST_F(Field3DTest, DivideEqualsField3D) { @@ -1525,14 +1525,14 @@ TEST_F(Field3DTest, DivideEqualsField3D) { b = 2.5; a /= b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 2.0)); + EXPECT_TRUE(IsFieldEqual(a, 2.0)); // Check case where field is not unique auto c = a; c /= b; - EXPECT_TRUE(IsField3DEqualBoutReal(a, 2.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(c, 0.8)); + EXPECT_TRUE(IsFieldEqual(a, 2.0)); + EXPECT_TRUE(IsFieldEqual(c, 0.8)); } TEST_F(Field3DTest, DivideEqualsField3DField3DStagger) { @@ -1560,7 +1560,7 @@ TEST_F(Field3DTest, DivideField3DBoutReal) { a = 3.0; b = a / 2.0; - EXPECT_TRUE(IsField3DEqualBoutReal(b, 1.5)); + EXPECT_TRUE(IsFieldEqual(b, 1.5)); } TEST_F(Field3DTest, DivideBoutRealField3D) { @@ -1569,7 +1569,7 @@ TEST_F(Field3DTest, DivideBoutRealField3D) { a = 2.5; b = 10.0 / a; - EXPECT_TRUE(IsField3DEqualBoutReal(b, 4.0)); + EXPECT_TRUE(IsFieldEqual(b, 4.0)); } TEST_F(Field3DTest, DivideField2DField3D) { @@ -1580,7 +1580,7 @@ TEST_F(Field3DTest, DivideField2DField3D) { b = 8.0; c = a / b; - EXPECT_TRUE(IsField3DEqualBoutReal(c, 4.0)); + EXPECT_TRUE(IsFieldEqual(c, 4.0)); } TEST_F(Field3DTest, DivideField3DField2D) { @@ -1591,7 +1591,7 @@ TEST_F(Field3DTest, DivideField3DField2D) { b = 8.0; c = a / b; - EXPECT_TRUE(IsField3DEqualBoutReal(c, 4.0)); + EXPECT_TRUE(IsFieldEqual(c, 4.0)); } TEST_F(Field3DTest, DivideField3DField3D) { @@ -1601,7 +1601,7 @@ TEST_F(Field3DTest, DivideField3DField3D) { b = 8.0; c = a / b; - EXPECT_TRUE(IsField3DEqualBoutReal(c, 4.0)); + EXPECT_TRUE(IsFieldEqual(c, 4.0)); } TEST_F(Field3DTest, DivideField3DField3DStagger) { @@ -1636,7 +1636,7 @@ TEST_F(Field3DTest, PowBoutRealField3D) { a = 5.0; b = pow(2.0, a); - EXPECT_TRUE(IsField3DEqualBoutReal(b, 32.0)); + EXPECT_TRUE(IsFieldEqual(b, 32.0)); } TEST_F(Field3DTest, PowField3DBoutReal) { @@ -1644,7 +1644,7 @@ TEST_F(Field3DTest, PowField3DBoutReal) { a = 5.0; b = pow(a, 2.0); - EXPECT_TRUE(IsField3DEqualBoutReal(b, 25.0)); + EXPECT_TRUE(IsFieldEqual(b, 25.0)); } TEST_F(Field3DTest, PowField3DFieldPerp) { @@ -1657,7 +1657,7 @@ TEST_F(Field3DTest, PowField3DFieldPerp) { b = 6.0; c = pow(a, b); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 64.0)); + EXPECT_TRUE(IsFieldEqual(c, 64.0)); } TEST_F(Field3DTest, PowField3DField2D) { @@ -1668,7 +1668,7 @@ TEST_F(Field3DTest, PowField3DField2D) { b = 6.0; c = pow(a, b); - EXPECT_TRUE(IsField3DEqualBoutReal(c, 64.0)); + EXPECT_TRUE(IsFieldEqual(c, 64.0)); } TEST_F(Field3DTest, PowField3DField3D) { @@ -1677,21 +1677,21 @@ TEST_F(Field3DTest, PowField3DField3D) { b = 6.0; c = pow(a, b); - EXPECT_TRUE(IsField3DEqualBoutReal(c, 64.0)); + EXPECT_TRUE(IsFieldEqual(c, 64.0)); } TEST_F(Field3DTest, Sqrt) { Field3D field; field = 16.0; - EXPECT_TRUE(IsField3DEqualBoutReal(sqrt(field), 4.0)); + EXPECT_TRUE(IsFieldEqual(sqrt(field), 4.0)); } TEST_F(Field3DTest, Abs) { Field3D field; field = -31.0; - EXPECT_TRUE(IsField3DEqualBoutReal(abs(field), 31.0)); + EXPECT_TRUE(IsFieldEqual(abs(field), 31.0)); } TEST_F(Field3DTest, Exp) { @@ -1699,7 +1699,7 @@ TEST_F(Field3DTest, Exp) { field = 2.5; const BoutReal expected = 12.182493960703473; - EXPECT_TRUE(IsField3DEqualBoutReal(exp(field), expected)); + EXPECT_TRUE(IsFieldEqual(exp(field), expected)); } TEST_F(Field3DTest, Log) { @@ -1707,7 +1707,7 @@ TEST_F(Field3DTest, Log) { field = 12.182493960703473; const BoutReal expected = 2.5; - EXPECT_TRUE(IsField3DEqualBoutReal(log(field), expected)); + EXPECT_TRUE(IsFieldEqual(log(field), expected)); } TEST_F(Field3DTest, LogExp) { @@ -1715,37 +1715,37 @@ TEST_F(Field3DTest, LogExp) { field = 2.5; const BoutReal expected = 2.5; - EXPECT_TRUE(IsField3DEqualBoutReal(log(exp(field)), expected)); + EXPECT_TRUE(IsFieldEqual(log(exp(field)), expected)); } TEST_F(Field3DTest, Sin) { Field3D field; field = PI / 2.0; - EXPECT_TRUE(IsField3DEqualBoutReal(sin(field), 1.0)); + EXPECT_TRUE(IsFieldEqual(sin(field), 1.0)); field = PI; - EXPECT_TRUE(IsField3DEqualBoutReal(sin(field), 0.0)); + EXPECT_TRUE(IsFieldEqual(sin(field), 0.0)); } TEST_F(Field3DTest, Cos) { Field3D field; field = PI / 2.0; - EXPECT_TRUE(IsField3DEqualBoutReal(cos(field), 0.0)); + EXPECT_TRUE(IsFieldEqual(cos(field), 0.0)); field = PI; - EXPECT_TRUE(IsField3DEqualBoutReal(cos(field), -1.0)); + EXPECT_TRUE(IsFieldEqual(cos(field), -1.0)); } TEST_F(Field3DTest, Tan) { Field3D field; field = PI / 4.0; - EXPECT_TRUE(IsField3DEqualBoutReal(tan(field), 1.0)); + EXPECT_TRUE(IsFieldEqual(tan(field), 1.0)); field = PI; - EXPECT_TRUE(IsField3DEqualBoutReal(tan(field), 0.0)); + EXPECT_TRUE(IsFieldEqual(tan(field), 0.0)); } TEST_F(Field3DTest, Sinh) { @@ -1753,10 +1753,10 @@ TEST_F(Field3DTest, Sinh) { field = 1.0; const BoutReal expected = 1.1752011936438014; - EXPECT_TRUE(IsField3DEqualBoutReal(sinh(field), expected)); + EXPECT_TRUE(IsFieldEqual(sinh(field), expected)); field = -1.0; - EXPECT_TRUE(IsField3DEqualBoutReal(sinh(field), -expected)); + EXPECT_TRUE(IsFieldEqual(sinh(field), -expected)); } TEST_F(Field3DTest, Cosh) { @@ -1764,10 +1764,10 @@ TEST_F(Field3DTest, Cosh) { field = 1.0; const BoutReal expected = 1.5430806348152437; - EXPECT_TRUE(IsField3DEqualBoutReal(cosh(field), expected)); + EXPECT_TRUE(IsFieldEqual(cosh(field), expected)); field = -1.0; - EXPECT_TRUE(IsField3DEqualBoutReal(cosh(field), expected)); + EXPECT_TRUE(IsFieldEqual(cosh(field), expected)); } TEST_F(Field3DTest, Tanh) { @@ -1775,10 +1775,10 @@ TEST_F(Field3DTest, Tanh) { field = 1.0; const BoutReal expected = 0.761594155955764; - EXPECT_TRUE(IsField3DEqualBoutReal(tanh(field), expected)); + EXPECT_TRUE(IsFieldEqual(tanh(field), expected)); field = -1.0; - EXPECT_TRUE(IsField3DEqualBoutReal(tanh(field), -expected)); + EXPECT_TRUE(IsFieldEqual(tanh(field), -expected)); } TEST_F(Field3DTest, Floor) { @@ -1790,7 +1790,7 @@ TEST_F(Field3DTest, Floor) { const BoutReal floor_value = 50.0; - EXPECT_TRUE(IsField3DEqualBoutReal(floor(field, floor_value), floor_value)); + EXPECT_TRUE(IsFieldEqual(floor(field, floor_value), floor_value)); } TEST_F(Field3DTest, Min) { @@ -1854,7 +1854,7 @@ TEST_F(Field3DTest, DC) { field[i] = i.z(); } - EXPECT_TRUE(IsField2DEqualBoutReal(DC(field), 3.0)); + EXPECT_TRUE(IsFieldEqual(DC(field), 3.0)); } TEST_F(Field3DTest, Swap) { @@ -1893,24 +1893,24 @@ TEST_F(Field3DTest, Swap) { ddt(second) = 2.4; // Basic sanity check - EXPECT_TRUE(IsField3DEqualBoutReal(first, 1.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(second, 2.0)); + EXPECT_TRUE(IsFieldEqual(first, 1.0)); + EXPECT_TRUE(IsFieldEqual(second, 2.0)); // swap is marked noexcept, so absolutely should not throw! ASSERT_NO_THROW(swap(first, second)); // Values - EXPECT_TRUE(IsField3DEqualBoutReal(first, 2.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(second, 1.0)); + EXPECT_TRUE(IsFieldEqual(first, 2.0)); + EXPECT_TRUE(IsFieldEqual(second, 1.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(first.yup(), 2.2)); - EXPECT_TRUE(IsField3DEqualBoutReal(first.ydown(), 1.2)); + EXPECT_TRUE(IsFieldEqual(first.yup(), 2.2)); + EXPECT_TRUE(IsFieldEqual(first.ydown(), 1.2)); - EXPECT_TRUE(IsField3DEqualBoutReal(second.yup(), 1.5)); - EXPECT_TRUE(IsField3DEqualBoutReal(second.ydown(), 0.5)); + EXPECT_TRUE(IsFieldEqual(second.yup(), 1.5)); + EXPECT_TRUE(IsFieldEqual(second.ydown(), 0.5)); - EXPECT_TRUE(IsField3DEqualBoutReal(ddt(first), 2.4)); - EXPECT_TRUE(IsField3DEqualBoutReal(ddt(second), 1.1)); + EXPECT_TRUE(IsFieldEqual(ddt(first), 2.4)); + EXPECT_TRUE(IsFieldEqual(ddt(second), 1.1)); // Mesh properties EXPECT_EQ(first.getMesh(), &second_mesh); @@ -1952,12 +1952,12 @@ TEST_F(Field3DTest, MoveCtor) { Field3D second{std::move(first)}; // Values - EXPECT_TRUE(IsField3DEqualBoutReal(second, 1.0)); + EXPECT_TRUE(IsFieldEqual(second, 1.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(second.yup(), 1.5)); - EXPECT_TRUE(IsField3DEqualBoutReal(second.ydown(), 0.5)); + EXPECT_TRUE(IsFieldEqual(second.yup(), 1.5)); + EXPECT_TRUE(IsFieldEqual(second.ydown(), 0.5)); - EXPECT_TRUE(IsField3DEqualBoutReal(ddt(second), 1.1)); + EXPECT_TRUE(IsFieldEqual(ddt(second), 1.1)); // Mesh properties EXPECT_EQ(second.getMesh(), mesh); @@ -1995,7 +1995,7 @@ TEST_F(Field3DTest, FillField) { {1., 1., 1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1., 1., 1.}}}); - EXPECT_TRUE(IsField3DEqualBoutReal(f, 1.)); + EXPECT_TRUE(IsFieldEqual(f, 1.)); fillField(f, {{{0., 1., 2., 3., 4., 5., 6.}, {0., 1., 2., 3., 4., 5., 6.}, @@ -2019,7 +2019,7 @@ TEST_F(Field3DTest, FillField) { g.allocate(); BOUT_FOR_SERIAL(i, g.getRegion("RGN_ALL")) { g[i] = i.z(); } - EXPECT_TRUE(IsField3DEqualField3D(f, g)); + EXPECT_TRUE(IsFieldEqual(f, g)); } // Restore compiler warnings diff --git a/tests/unit/field/test_fieldperp.cxx b/tests/unit/field/test_fieldperp.cxx index f986a9968b..b50f8e6fcb 100644 --- a/tests/unit/field/test_fieldperp.cxx +++ b/tests/unit/field/test_fieldperp.cxx @@ -657,14 +657,14 @@ TEST_F(FieldPerpTest, InvalidateGuards) { TEST_F(FieldPerpTest, CreateFromBoutReal) { FieldPerp field(1.0); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(field, 1.0)); + EXPECT_TRUE(IsFieldEqual(field, 1.0)); } TEST_F(FieldPerpTest, CreateFromFieldPerp) { FieldPerp field(99.0); FieldPerp result(field); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(result, 99.0)); + EXPECT_TRUE(IsFieldEqual(result, 99.0)); } TEST_F(FieldPerpTest, AssignFromBoutReal) { @@ -672,14 +672,14 @@ TEST_F(FieldPerpTest, AssignFromBoutReal) { field = 2.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(field, 2.0)); + EXPECT_TRUE(IsFieldEqual(field, 2.0)); } TEST_F(FieldPerpTest, AssignFromInvalid) { FieldPerp field; EXPECT_NO_THROW(field = std::nan("")); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(field, std::nan(""))); + EXPECT_TRUE(IsFieldEqual(field, std::nan(""))); } TEST_F(FieldPerpTest, UnaryMinus) { @@ -689,7 +689,7 @@ TEST_F(FieldPerpTest, UnaryMinus) { field = 2.0; field = -field; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(field, -2.0)); + EXPECT_TRUE(IsFieldEqual(field, -2.0)); } TEST_F(FieldPerpTest, AddEqualsBoutReal) { @@ -699,14 +699,14 @@ TEST_F(FieldPerpTest, AddEqualsBoutReal) { a = 1.0; a += 5.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 6.0)); + EXPECT_TRUE(IsFieldEqual(a, 6.0)); // Check case where field is not unique auto c = a; c += 5.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 6.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 11.0)); + EXPECT_TRUE(IsFieldEqual(a, 6.0)); + EXPECT_TRUE(IsFieldEqual(c, 11.0)); } TEST_F(FieldPerpTest, AddEqualsFieldPerp) { @@ -718,14 +718,14 @@ TEST_F(FieldPerpTest, AddEqualsFieldPerp) { b = 3.0; a += b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 5.0)); + EXPECT_TRUE(IsFieldEqual(a, 5.0)); // Check case where field is not unique auto c = a; c += b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 5.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 8.0)); + EXPECT_TRUE(IsFieldEqual(a, 5.0)); + EXPECT_TRUE(IsFieldEqual(c, 8.0)); } TEST_F(FieldPerpTest, AddEqualsField2D) { @@ -740,14 +740,14 @@ TEST_F(FieldPerpTest, AddEqualsField2D) { a.setIndex(1); EXPECT_NO_THROW(a += b); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 5.0)); + EXPECT_TRUE(IsFieldEqual(a, 5.0)); // Check case where field is not unique auto c = a; c += b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 5.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 8.0)); + EXPECT_TRUE(IsFieldEqual(a, 5.0)); + EXPECT_TRUE(IsFieldEqual(c, 8.0)); } TEST_F(FieldPerpTest, AddEqualsField3D) { @@ -762,14 +762,14 @@ TEST_F(FieldPerpTest, AddEqualsField3D) { a.setIndex(1); EXPECT_NO_THROW(a += b); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 5.0)); + EXPECT_TRUE(IsFieldEqual(a, 5.0)); // Check case where field is not unique auto c = a; c += b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 5.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 8.0)); + EXPECT_TRUE(IsFieldEqual(a, 5.0)); + EXPECT_TRUE(IsFieldEqual(c, 8.0)); } TEST_F(FieldPerpTest, AddFieldPerpBoutReal) { @@ -779,7 +779,7 @@ TEST_F(FieldPerpTest, AddFieldPerpBoutReal) { a = 1.0; b = a + 2.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(b, 3.0)); + EXPECT_TRUE(IsFieldEqual(b, 3.0)); } TEST_F(FieldPerpTest, AddBoutRealFieldPerp) { @@ -789,7 +789,7 @@ TEST_F(FieldPerpTest, AddBoutRealFieldPerp) { a = 1.0; b = 3.0 + a; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(b, 4.0)); + EXPECT_TRUE(IsFieldEqual(b, 4.0)); } TEST_F(FieldPerpTest, AddFieldPerpFieldPerp) { @@ -801,7 +801,7 @@ TEST_F(FieldPerpTest, AddFieldPerpFieldPerp) { b = 2.0; c = a + b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 3.0)); + EXPECT_TRUE(IsFieldEqual(c, 3.0)); } TEST_F(FieldPerpTest, AddFieldPerpField2D) { @@ -813,7 +813,7 @@ TEST_F(FieldPerpTest, AddFieldPerpField2D) { b = 2.0; c = a + b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 3.0)); + EXPECT_TRUE(IsFieldEqual(c, 3.0)); } TEST_F(FieldPerpTest, AddFieldPerpField3D) { @@ -825,7 +825,7 @@ TEST_F(FieldPerpTest, AddFieldPerpField3D) { b = 2.0; c = a + b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 3.0)); + EXPECT_TRUE(IsFieldEqual(c, 3.0)); } TEST_F(FieldPerpTest, MultiplyEqualsBoutReal) { @@ -835,14 +835,14 @@ TEST_F(FieldPerpTest, MultiplyEqualsBoutReal) { a = 2.0; a *= 1.5; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 3.0)); + EXPECT_TRUE(IsFieldEqual(a, 3.0)); // Check case where field is not unique auto c = a; c *= 1.5; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 3.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 4.5)); + EXPECT_TRUE(IsFieldEqual(a, 3.0)); + EXPECT_TRUE(IsFieldEqual(c, 4.5)); } TEST_F(FieldPerpTest, MultiplyEqualsFieldPerp) { @@ -854,14 +854,14 @@ TEST_F(FieldPerpTest, MultiplyEqualsFieldPerp) { b = 4.0; a *= b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 10.0)); + EXPECT_TRUE(IsFieldEqual(a, 10.0)); // Check case where field is not unique auto c = a; c *= b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 10.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 40.0)); + EXPECT_TRUE(IsFieldEqual(a, 10.0)); + EXPECT_TRUE(IsFieldEqual(c, 40.0)); } TEST_F(FieldPerpTest, MultiplyEqualsField2D) { @@ -876,14 +876,14 @@ TEST_F(FieldPerpTest, MultiplyEqualsField2D) { a.setIndex(1); EXPECT_NO_THROW(a *= b); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 10.0)); + EXPECT_TRUE(IsFieldEqual(a, 10.0)); // Check case where field is not unique auto c = a; c *= b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 10.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 40.0)); + EXPECT_TRUE(IsFieldEqual(a, 10.0)); + EXPECT_TRUE(IsFieldEqual(c, 40.0)); } TEST_F(FieldPerpTest, MultiplyEqualsField3D) { @@ -898,14 +898,14 @@ TEST_F(FieldPerpTest, MultiplyEqualsField3D) { a.setIndex(1); EXPECT_NO_THROW(a *= b); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 10.0)); + EXPECT_TRUE(IsFieldEqual(a, 10.0)); // Check case where field is not unique auto c = a; c *= b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 10.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 40.0)); + EXPECT_TRUE(IsFieldEqual(a, 10.0)); + EXPECT_TRUE(IsFieldEqual(c, 40.0)); } TEST_F(FieldPerpTest, MultiplyFieldPerpBoutReal) { @@ -915,7 +915,7 @@ TEST_F(FieldPerpTest, MultiplyFieldPerpBoutReal) { a = 1.5; b = a * 2.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(b, 3.0)); + EXPECT_TRUE(IsFieldEqual(b, 3.0)); } TEST_F(FieldPerpTest, MultiplyBoutRealFieldPerp) { @@ -925,7 +925,7 @@ TEST_F(FieldPerpTest, MultiplyBoutRealFieldPerp) { a = 2.5; b = 3.0 * a; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(b, 7.5)); + EXPECT_TRUE(IsFieldEqual(b, 7.5)); } TEST_F(FieldPerpTest, MultiplyFieldPerpFieldPerp) { @@ -937,7 +937,7 @@ TEST_F(FieldPerpTest, MultiplyFieldPerpFieldPerp) { b = 8.0; c = a * b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 32.0)); + EXPECT_TRUE(IsFieldEqual(c, 32.0)); } TEST_F(FieldPerpTest, MultiplyFieldPerpField2D) { @@ -949,7 +949,7 @@ TEST_F(FieldPerpTest, MultiplyFieldPerpField2D) { b = 8.0; c = a * b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 32.0)); + EXPECT_TRUE(IsFieldEqual(c, 32.0)); } TEST_F(FieldPerpTest, MultiplyFieldPerpField3D) { @@ -961,7 +961,7 @@ TEST_F(FieldPerpTest, MultiplyFieldPerpField3D) { b = 8.0; c = a * b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 32.0)); + EXPECT_TRUE(IsFieldEqual(c, 32.0)); } TEST_F(FieldPerpTest, SubtractEqualsBoutReal) { @@ -971,14 +971,14 @@ TEST_F(FieldPerpTest, SubtractEqualsBoutReal) { a = 1.0; a -= 5.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, -4.0)); + EXPECT_TRUE(IsFieldEqual(a, -4.0)); // Check case where field is not unique auto c = a; c -= 5.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, -4.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, -9.0)); + EXPECT_TRUE(IsFieldEqual(a, -4.0)); + EXPECT_TRUE(IsFieldEqual(c, -9.0)); } TEST_F(FieldPerpTest, SubtractEqualsFieldPerp) { @@ -990,14 +990,14 @@ TEST_F(FieldPerpTest, SubtractEqualsFieldPerp) { b = 7.0; a -= b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, -5.0)); + EXPECT_TRUE(IsFieldEqual(a, -5.0)); // Check case where field is not unique auto c = a; c -= b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, -5.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, -12.0)); + EXPECT_TRUE(IsFieldEqual(a, -5.0)); + EXPECT_TRUE(IsFieldEqual(c, -12.0)); } TEST_F(FieldPerpTest, SubtractEqualsField2D) { @@ -1012,14 +1012,14 @@ TEST_F(FieldPerpTest, SubtractEqualsField2D) { a.setIndex(1); EXPECT_NO_THROW(a -= b); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, -5.0)); + EXPECT_TRUE(IsFieldEqual(a, -5.0)); // Check case where field is not unique auto c = a; c -= b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, -5.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, -12.0)); + EXPECT_TRUE(IsFieldEqual(a, -5.0)); + EXPECT_TRUE(IsFieldEqual(c, -12.0)); } TEST_F(FieldPerpTest, SubtractEqualsField3D) { @@ -1034,14 +1034,14 @@ TEST_F(FieldPerpTest, SubtractEqualsField3D) { a.setIndex(1); EXPECT_NO_THROW(a -= b); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, -5.0)); + EXPECT_TRUE(IsFieldEqual(a, -5.0)); // Check case where field is not unique auto c = a; c -= b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, -5.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, -12.0)); + EXPECT_TRUE(IsFieldEqual(a, -5.0)); + EXPECT_TRUE(IsFieldEqual(c, -12.0)); } TEST_F(FieldPerpTest, SubtractFieldPerpBoutReal) { @@ -1051,7 +1051,7 @@ TEST_F(FieldPerpTest, SubtractFieldPerpBoutReal) { a = 10.0; b = a - 2.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(b, 8.0)); + EXPECT_TRUE(IsFieldEqual(b, 8.0)); } TEST_F(FieldPerpTest, SubtractBoutRealFieldPerp) { @@ -1061,7 +1061,7 @@ TEST_F(FieldPerpTest, SubtractBoutRealFieldPerp) { a = 10.0; b = 3.0 - a; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(b, -7.0)); + EXPECT_TRUE(IsFieldEqual(b, -7.0)); } TEST_F(FieldPerpTest, SubtractFieldPerpFieldPerp) { @@ -1073,7 +1073,7 @@ TEST_F(FieldPerpTest, SubtractFieldPerpFieldPerp) { b = 20.0; c = a - b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, -10.0)); + EXPECT_TRUE(IsFieldEqual(c, -10.0)); } TEST_F(FieldPerpTest, SubtractFieldPerpField2D) { @@ -1085,7 +1085,7 @@ TEST_F(FieldPerpTest, SubtractFieldPerpField2D) { b = 20.0; c = a - b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, -10.0)); + EXPECT_TRUE(IsFieldEqual(c, -10.0)); } TEST_F(FieldPerpTest, SubtractFieldPerpField3D) { @@ -1097,7 +1097,7 @@ TEST_F(FieldPerpTest, SubtractFieldPerpField3D) { b = 20.0; c = a - b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, -10.0)); + EXPECT_TRUE(IsFieldEqual(c, -10.0)); } TEST_F(FieldPerpTest, DivideEqualsBoutReal) { @@ -1107,14 +1107,14 @@ TEST_F(FieldPerpTest, DivideEqualsBoutReal) { a = 2.5; a /= 5.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 0.5)); + EXPECT_TRUE(IsFieldEqual(a, 0.5)); // Check case where field is not unique auto c = a; c /= 5.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 0.5)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 0.1)); + EXPECT_TRUE(IsFieldEqual(a, 0.5)); + EXPECT_TRUE(IsFieldEqual(c, 0.1)); } TEST_F(FieldPerpTest, DivideEqualsFieldPerp) { @@ -1126,14 +1126,14 @@ TEST_F(FieldPerpTest, DivideEqualsFieldPerp) { b = 2.5; a /= b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 2.0)); + EXPECT_TRUE(IsFieldEqual(a, 2.0)); // Check case where field is not unique auto c = a; c /= b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 2.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 0.8)); + EXPECT_TRUE(IsFieldEqual(a, 2.0)); + EXPECT_TRUE(IsFieldEqual(c, 0.8)); } TEST_F(FieldPerpTest, DivideEqualsField2D) { @@ -1148,14 +1148,14 @@ TEST_F(FieldPerpTest, DivideEqualsField2D) { a.setIndex(1); EXPECT_NO_THROW(a /= b); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 2.0)); + EXPECT_TRUE(IsFieldEqual(a, 2.0)); // Check case where field is not unique auto c = a; c /= b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 2.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 0.8)); + EXPECT_TRUE(IsFieldEqual(a, 2.0)); + EXPECT_TRUE(IsFieldEqual(c, 0.8)); } TEST_F(FieldPerpTest, DivideEqualsField3D) { @@ -1170,14 +1170,14 @@ TEST_F(FieldPerpTest, DivideEqualsField3D) { a.setIndex(1); EXPECT_NO_THROW(a /= b); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 2.0)); + EXPECT_TRUE(IsFieldEqual(a, 2.0)); // Check case where field is not unique auto c = a; c /= b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(a, 2.0)); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 0.8)); + EXPECT_TRUE(IsFieldEqual(a, 2.0)); + EXPECT_TRUE(IsFieldEqual(c, 0.8)); } TEST_F(FieldPerpTest, DivideFieldPerpBoutReal) { @@ -1187,7 +1187,7 @@ TEST_F(FieldPerpTest, DivideFieldPerpBoutReal) { a = 3.0; b = a / 2.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(b, 1.5)); + EXPECT_TRUE(IsFieldEqual(b, 1.5)); } TEST_F(FieldPerpTest, DivideBoutRealFieldPerp) { @@ -1197,7 +1197,7 @@ TEST_F(FieldPerpTest, DivideBoutRealFieldPerp) { a = 2.5; b = 10.0 / a; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(b, 4.0)); + EXPECT_TRUE(IsFieldEqual(b, 4.0)); } TEST_F(FieldPerpTest, DivideFieldPerpFieldPerp) { @@ -1209,7 +1209,7 @@ TEST_F(FieldPerpTest, DivideFieldPerpFieldPerp) { b = 8.0; c = a / b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 4.0)); + EXPECT_TRUE(IsFieldEqual(c, 4.0)); } TEST_F(FieldPerpTest, DivideFieldPerpField2D) { @@ -1221,7 +1221,7 @@ TEST_F(FieldPerpTest, DivideFieldPerpField2D) { b = 8.0; c = a / b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 4.0)); + EXPECT_TRUE(IsFieldEqual(c, 4.0)); } TEST_F(FieldPerpTest, DivideFieldPerpField3D) { @@ -1233,7 +1233,7 @@ TEST_F(FieldPerpTest, DivideFieldPerpField3D) { b = 8.0; c = a / b; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 4.0)); + EXPECT_TRUE(IsFieldEqual(c, 4.0)); } TEST_F(FieldPerpTest, PowBoutRealFieldPerp) { @@ -1244,7 +1244,7 @@ TEST_F(FieldPerpTest, PowBoutRealFieldPerp) { a = 5.0; b = pow(2.0, a); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(b, 32.0)); + EXPECT_TRUE(IsFieldEqual(b, 32.0)); } TEST_F(FieldPerpTest, PowFieldPerpBoutReal) { @@ -1254,7 +1254,7 @@ TEST_F(FieldPerpTest, PowFieldPerpBoutReal) { a = 5.0; b = pow(a, 2.0); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(b, 25.0)); + EXPECT_TRUE(IsFieldEqual(b, 25.0)); } TEST_F(FieldPerpTest, PowFieldPerpFieldPerp) { @@ -1266,7 +1266,7 @@ TEST_F(FieldPerpTest, PowFieldPerpFieldPerp) { b = 6.0; c = pow(a, b); - EXPECT_TRUE(IsFieldPerpEqualBoutReal(c, 64.0)); + EXPECT_TRUE(IsFieldEqual(c, 64.0)); } TEST_F(FieldPerpTest, Sqrt) { @@ -1274,7 +1274,7 @@ TEST_F(FieldPerpTest, Sqrt) { field.setIndex(0); field = 16.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(sqrt(field), 4.0)); + EXPECT_TRUE(IsFieldEqual(sqrt(field), 4.0)); } TEST_F(FieldPerpTest, Abs) { @@ -1282,7 +1282,7 @@ TEST_F(FieldPerpTest, Abs) { field.setIndex(0); field = -31.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(abs(field), 31.0)); + EXPECT_TRUE(IsFieldEqual(abs(field), 31.0)); } TEST_F(FieldPerpTest, Exp) { @@ -1291,7 +1291,7 @@ TEST_F(FieldPerpTest, Exp) { field = 2.5; const BoutReal expected = 12.182493960703473; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(exp(field), expected)); + EXPECT_TRUE(IsFieldEqual(exp(field), expected)); } TEST_F(FieldPerpTest, Log) { @@ -1300,7 +1300,7 @@ TEST_F(FieldPerpTest, Log) { field = 12.182493960703473; const BoutReal expected = 2.5; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(log(field), expected)); + EXPECT_TRUE(IsFieldEqual(log(field), expected)); } TEST_F(FieldPerpTest, LogExp) { @@ -1309,7 +1309,7 @@ TEST_F(FieldPerpTest, LogExp) { field = 2.5; const BoutReal expected = 2.5; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(log(exp(field)), expected)); + EXPECT_TRUE(IsFieldEqual(log(exp(field)), expected)); } TEST_F(FieldPerpTest, Sin) { @@ -1317,10 +1317,10 @@ TEST_F(FieldPerpTest, Sin) { field.setIndex(0); field = PI / 2.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(sin(field), 1.0)); + EXPECT_TRUE(IsFieldEqual(sin(field), 1.0)); field = PI; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(sin(field), 0.0)); + EXPECT_TRUE(IsFieldEqual(sin(field), 0.0)); } TEST_F(FieldPerpTest, Cos) { @@ -1328,10 +1328,10 @@ TEST_F(FieldPerpTest, Cos) { field.setIndex(0); field = PI / 2.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(cos(field), 0.0)); + EXPECT_TRUE(IsFieldEqual(cos(field), 0.0)); field = PI; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(cos(field), -1.0)); + EXPECT_TRUE(IsFieldEqual(cos(field), -1.0)); } TEST_F(FieldPerpTest, Tan) { @@ -1339,10 +1339,10 @@ TEST_F(FieldPerpTest, Tan) { field.setIndex(0); field = PI / 4.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(tan(field), 1.0)); + EXPECT_TRUE(IsFieldEqual(tan(field), 1.0)); field = PI; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(tan(field), 0.0)); + EXPECT_TRUE(IsFieldEqual(tan(field), 0.0)); } TEST_F(FieldPerpTest, Sinh) { @@ -1351,10 +1351,10 @@ TEST_F(FieldPerpTest, Sinh) { field = 1.0; const BoutReal expected = 1.1752011936438014; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(sinh(field), expected)); + EXPECT_TRUE(IsFieldEqual(sinh(field), expected)); field = -1.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(sinh(field), -expected)); + EXPECT_TRUE(IsFieldEqual(sinh(field), -expected)); } TEST_F(FieldPerpTest, Cosh) { @@ -1363,10 +1363,10 @@ TEST_F(FieldPerpTest, Cosh) { field = 1.0; const BoutReal expected = 1.5430806348152437; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(cosh(field), expected)); + EXPECT_TRUE(IsFieldEqual(cosh(field), expected)); field = -1.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(cosh(field), expected)); + EXPECT_TRUE(IsFieldEqual(cosh(field), expected)); } TEST_F(FieldPerpTest, Tanh) { @@ -1375,10 +1375,10 @@ TEST_F(FieldPerpTest, Tanh) { field = 1.0; const BoutReal expected = 0.761594155955764; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(tanh(field), expected)); + EXPECT_TRUE(IsFieldEqual(tanh(field), expected)); field = -1.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(tanh(field), -expected)); + EXPECT_TRUE(IsFieldEqual(tanh(field), -expected)); } TEST_F(FieldPerpTest, Floor) { @@ -1391,7 +1391,7 @@ TEST_F(FieldPerpTest, Floor) { const BoutReal floor_value = 50.0; - EXPECT_TRUE(IsFieldPerpEqualBoutReal(floor(field, floor_value), floor_value)); + EXPECT_TRUE(IsFieldEqual(floor(field, floor_value), floor_value)); } TEST_F(FieldPerpTest, Min) { diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index a6ec890c34..f4a4ff746e 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -191,9 +191,9 @@ TEST_F(Vector2DTest, AssignFromBoutReal) { vector = 0.0; - EXPECT_TRUE(IsField2DEqualBoutReal(vector.x, 0.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector.y, 0.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector.z, 0.0)); + EXPECT_TRUE(IsFieldEqual(vector.x, 0.0)); + EXPECT_TRUE(IsFieldEqual(vector.y, 0.0)); + EXPECT_TRUE(IsFieldEqual(vector.z, 0.0)); } TEST_F(Vector2DTest, AssignFromVector2D) { @@ -208,9 +208,9 @@ TEST_F(Vector2DTest, AssignFromVector2D) { vector2 = vector1; - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.x, 1.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.y, 2.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.z, 3.0)); + EXPECT_TRUE(IsFieldEqual(vector2.x, 1.0)); + EXPECT_TRUE(IsFieldEqual(vector2.y, 2.0)); + EXPECT_TRUE(IsFieldEqual(vector2.z, 3.0)); EXPECT_EQ(vector1.getLocation(), vector2.getLocation()); } @@ -226,9 +226,9 @@ TEST_F(Vector2DTest, CreateFromVector2D) { Vector2D vector2{vector1}; - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.x, 4.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.y, 5.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.z, 6.0)); + EXPECT_TRUE(IsFieldEqual(vector2.x, 4.0)); + EXPECT_TRUE(IsFieldEqual(vector2.y, 5.0)); + EXPECT_TRUE(IsFieldEqual(vector2.z, 6.0)); EXPECT_EQ(vector1.getLocation(), vector2.getLocation()); } @@ -242,9 +242,9 @@ TEST_F(Vector2DTest, UnaryMinus) { vector2 = -vector1; - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.x, -7.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.y, -8.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.z, -9.0)); + EXPECT_TRUE(IsFieldEqual(vector2.x, -7.0)); + EXPECT_TRUE(IsFieldEqual(vector2.y, -8.0)); + EXPECT_TRUE(IsFieldEqual(vector2.z, -9.0)); } TEST_F(Vector2DTest, AddEqualsVector2D) { @@ -260,9 +260,9 @@ TEST_F(Vector2DTest, AddEqualsVector2D) { vector2 += vector1; - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.x, 11.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.y, 13.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.z, 15.0)); + EXPECT_TRUE(IsFieldEqual(vector2.x, 11.0)); + EXPECT_TRUE(IsFieldEqual(vector2.y, 13.0)); + EXPECT_TRUE(IsFieldEqual(vector2.z, 15.0)); } TEST_F(Vector2DTest, AddVector2DVector2D) { @@ -278,9 +278,9 @@ TEST_F(Vector2DTest, AddVector2DVector2D) { Vector2D result = vector1 + vector2; - EXPECT_TRUE(IsField2DEqualBoutReal(result.x, 17.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.y, 19.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.z, 21.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 17.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 19.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 21.0)); } TEST_F(Vector2DTest, AddVector2DVector3D) { @@ -296,9 +296,9 @@ TEST_F(Vector2DTest, AddVector2DVector3D) { Vector3D result = vector1 + vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 7.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 9.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 11.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 7.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 9.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 11.0)); } TEST_F(Vector2DTest, MinusEqualsVector2D) { @@ -314,9 +314,9 @@ TEST_F(Vector2DTest, MinusEqualsVector2D) { vector2 -= vector1; - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.x, -97.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.y, -99.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector2.z, -101.0)); + EXPECT_TRUE(IsFieldEqual(vector2.x, -97.0)); + EXPECT_TRUE(IsFieldEqual(vector2.y, -99.0)); + EXPECT_TRUE(IsFieldEqual(vector2.z, -101.0)); } TEST_F(Vector2DTest, MinusVector2DVector2D) { @@ -332,9 +332,9 @@ TEST_F(Vector2DTest, MinusVector2DVector2D) { Vector2D result = vector1 - vector2; - EXPECT_TRUE(IsField2DEqualBoutReal(result.x, -3.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.y, -1.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.z, 1.0)); + EXPECT_TRUE(IsFieldEqual(result.x, -3.0)); + EXPECT_TRUE(IsFieldEqual(result.y, -1.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 1.0)); } TEST_F(Vector2DTest, MinusVector2DVector3D) { @@ -350,9 +350,9 @@ TEST_F(Vector2DTest, MinusVector2DVector3D) { Vector3D result = vector1 - vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 7.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 9.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 11.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 7.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 9.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 11.0)); } TEST_F(Vector2DTest, MultiplyEqualsBoutReal) { @@ -365,9 +365,9 @@ TEST_F(Vector2DTest, MultiplyEqualsBoutReal) { vector *= real; - EXPECT_TRUE(IsField2DEqualBoutReal(vector.x, 16.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector.y, 20.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector.z, 24.0)); + EXPECT_TRUE(IsFieldEqual(vector.x, 16.0)); + EXPECT_TRUE(IsFieldEqual(vector.y, 20.0)); + EXPECT_TRUE(IsFieldEqual(vector.z, 24.0)); } TEST_F(Vector2DTest, MultiplyEqualsField2D) { @@ -380,9 +380,9 @@ TEST_F(Vector2DTest, MultiplyEqualsField2D) { vector *= field; - EXPECT_TRUE(IsField2DEqualBoutReal(vector.x, 160.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector.y, 200.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector.z, 240.0)); + EXPECT_TRUE(IsFieldEqual(vector.x, 160.0)); + EXPECT_TRUE(IsFieldEqual(vector.y, 200.0)); + EXPECT_TRUE(IsFieldEqual(vector.z, 240.0)); } TEST_F(Vector2DTest, MultiplyVector2DBoutReal) { @@ -395,9 +395,9 @@ TEST_F(Vector2DTest, MultiplyVector2DBoutReal) { Vector2D result = vector * real; - EXPECT_TRUE(IsField2DEqualBoutReal(result.x, 2.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.y, 4.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.z, 6.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 2.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 4.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 6.0)); } TEST_F(Vector2DTest, MultiplyVector2DField2D) { @@ -410,9 +410,9 @@ TEST_F(Vector2DTest, MultiplyVector2DField2D) { Vector2D result = vector * field; - EXPECT_TRUE(IsField2DEqualBoutReal(result.x, 3.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.y, 6.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.z, 9.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 3.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 6.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 9.0)); } TEST_F(Vector2DTest, MultiplyVector2DField3D) { @@ -425,9 +425,9 @@ TEST_F(Vector2DTest, MultiplyVector2DField3D) { Vector3D result = vector * field; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 4.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 8.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 12.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 4.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 8.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 12.0)); } TEST_F(Vector2DTest, DivideEqualsBoutReal) { @@ -440,9 +440,9 @@ TEST_F(Vector2DTest, DivideEqualsBoutReal) { vector /= real; - EXPECT_TRUE(IsField2DEqualBoutReal(vector.x, 0.1)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector.y, 0.2)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector.z, 0.3)); + EXPECT_TRUE(IsFieldEqual(vector.x, 0.1)); + EXPECT_TRUE(IsFieldEqual(vector.y, 0.2)); + EXPECT_TRUE(IsFieldEqual(vector.z, 0.3)); } TEST_F(Vector2DTest, DivideEqualsConstField2D) { @@ -455,9 +455,9 @@ TEST_F(Vector2DTest, DivideEqualsConstField2D) { vector /= field; - EXPECT_TRUE(IsField2DEqualBoutReal(vector.x, 0.2)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector.y, 0.4)); - EXPECT_TRUE(IsField2DEqualBoutReal(vector.z, 0.6)); + EXPECT_TRUE(IsFieldEqual(vector.x, 0.2)); + EXPECT_TRUE(IsFieldEqual(vector.y, 0.4)); + EXPECT_TRUE(IsFieldEqual(vector.z, 0.6)); } TEST_F(Vector2DTest, DivideVector2DBoutReal) { @@ -470,9 +470,9 @@ TEST_F(Vector2DTest, DivideVector2DBoutReal) { Vector2D result = vector / real; - EXPECT_TRUE(IsField2DEqualBoutReal(result.x, 0.5)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.y, 1.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.z, 1.5)); + EXPECT_TRUE(IsFieldEqual(result.x, 0.5)); + EXPECT_TRUE(IsFieldEqual(result.y, 1.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 1.5)); } TEST_F(Vector2DTest, DivideVector2DField2D) { @@ -485,9 +485,9 @@ TEST_F(Vector2DTest, DivideVector2DField2D) { Vector2D result = vector / field; - EXPECT_TRUE(IsField2DEqualBoutReal(result.x, 0.25)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.y, 0.5)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.z, 0.75)); + EXPECT_TRUE(IsFieldEqual(result.x, 0.25)); + EXPECT_TRUE(IsFieldEqual(result.y, 0.5)); + EXPECT_TRUE(IsFieldEqual(result.z, 0.75)); } TEST_F(Vector2DTest, DivideVector2DField3D) { @@ -500,9 +500,9 @@ TEST_F(Vector2DTest, DivideVector2DField3D) { Vector3D result = vector / field; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 1.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 2.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 3.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 1.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 2.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 3.0)); } TEST_F(Vector2DTest, Cross2D3D) { @@ -518,9 +518,9 @@ TEST_F(Vector2DTest, Cross2D3D) { auto result = cross(vector1, vector2); - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 0.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 0.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 0.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 0.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 0.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 0.0)); } TEST_F(Vector2DTest, Cross2D2D) { @@ -536,9 +536,9 @@ TEST_F(Vector2DTest, Cross2D2D) { auto result = cross(vector1, vector2); - EXPECT_TRUE(IsField2DEqualBoutReal(result.x, 0.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.y, 0.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(result.z, 0.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 0.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 0.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 0.0)); } TEST_F(Vector2DTest, Dot2D3DCoCo) { @@ -554,7 +554,7 @@ TEST_F(Vector2DTest, Dot2D3DCoCo) { auto result = vector1 * vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result, 308.0)); + EXPECT_TRUE(IsFieldEqual(result, 308.0)); } TEST_F(Vector2DTest, Dot2D2DCoCo) { @@ -570,7 +570,7 @@ TEST_F(Vector2DTest, Dot2D2DCoCo) { auto result = vector1 * vector2; - EXPECT_TRUE(IsField2DEqualBoutReal(result, 308.0)); + EXPECT_TRUE(IsFieldEqual(result, 308.0)); } TEST_F(Vector2DTest, Dot2D3DCoContra) { @@ -587,7 +587,7 @@ TEST_F(Vector2DTest, Dot2D3DCoContra) { auto result = vector1 * vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result, 28.0)); + EXPECT_TRUE(IsFieldEqual(result, 28.0)); } TEST_F(Vector2DTest, Dot2D2DCoContra) { @@ -604,7 +604,7 @@ TEST_F(Vector2DTest, Dot2D2DCoContra) { auto result = vector1 * vector2; - EXPECT_TRUE(IsField2DEqualBoutReal(result, 28.0)); + EXPECT_TRUE(IsFieldEqual(result, 28.0)); } TEST_F(Vector2DTest, Dot2D3DContraContra) { @@ -622,7 +622,7 @@ TEST_F(Vector2DTest, Dot2D3DContraContra) { auto result = vector1 * vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result, 308.0)); + EXPECT_TRUE(IsFieldEqual(result, 308.0)); } TEST_F(Vector2DTest, Dot2D2DContraContra) { @@ -640,7 +640,7 @@ TEST_F(Vector2DTest, Dot2D2DContraContra) { auto result = vector1 * vector2; - EXPECT_TRUE(IsField2DEqualBoutReal(result, 308.0)); + EXPECT_TRUE(IsFieldEqual(result, 308.0)); } TEST_F(Vector2DTest, AbsCo) { @@ -651,7 +651,7 @@ TEST_F(Vector2DTest, AbsCo) { auto result = abs(vector1); - EXPECT_TRUE(IsField2DEqualBoutReal(result, 24.819347291981714)); + EXPECT_TRUE(IsFieldEqual(result, 24.819347291981714)); } TEST_F(Vector2DTest, AbsContra) { @@ -663,5 +663,5 @@ TEST_F(Vector2DTest, AbsContra) { auto result = abs(vector1); - EXPECT_TRUE(IsField2DEqualBoutReal(result, 24.819347291981714)); + EXPECT_TRUE(IsFieldEqual(result, 24.819347291981714)); } diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index eae149755d..994c24257a 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -190,9 +190,9 @@ TEST_F(Vector3DTest, AssignFromBoutReal) { vector = 0.0; - EXPECT_TRUE(IsField3DEqualBoutReal(vector.x, 0.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.y, 0.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.z, 0.0)); + EXPECT_TRUE(IsFieldEqual(vector.x, 0.0)); + EXPECT_TRUE(IsFieldEqual(vector.y, 0.0)); + EXPECT_TRUE(IsFieldEqual(vector.z, 0.0)); } TEST_F(Vector3DTest, AssignFromVector2D) { @@ -208,9 +208,9 @@ TEST_F(Vector3DTest, AssignFromVector2D) { vector2 = vector1; - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.x, 1.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.y, 2.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.z, 3.0)); + EXPECT_TRUE(IsFieldEqual(vector2.x, 1.0)); + EXPECT_TRUE(IsFieldEqual(vector2.y, 2.0)); + EXPECT_TRUE(IsFieldEqual(vector2.z, 3.0)); EXPECT_EQ(vector1.getLocation(), vector2.getLocation()); } @@ -226,9 +226,9 @@ TEST_F(Vector3DTest, AssignFromVector3D) { vector2 = vector1; - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.x, 1.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.y, 2.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.z, 3.0)); + EXPECT_TRUE(IsFieldEqual(vector2.x, 1.0)); + EXPECT_TRUE(IsFieldEqual(vector2.y, 2.0)); + EXPECT_TRUE(IsFieldEqual(vector2.z, 3.0)); EXPECT_EQ(vector1.getLocation(), vector2.getLocation()); } @@ -244,9 +244,9 @@ TEST_F(Vector3DTest, CreateFromVector3D) { Vector3D vector2{vector1}; - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.x, 4.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.y, 5.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.z, 6.0)); + EXPECT_TRUE(IsFieldEqual(vector2.x, 4.0)); + EXPECT_TRUE(IsFieldEqual(vector2.y, 5.0)); + EXPECT_TRUE(IsFieldEqual(vector2.z, 6.0)); EXPECT_EQ(vector1.getLocation(), vector2.getLocation()); } @@ -260,9 +260,9 @@ TEST_F(Vector3DTest, UnaryMinus) { vector2 = -vector1; - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.x, -7.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.y, -8.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.z, -9.0)); + EXPECT_TRUE(IsFieldEqual(vector2.x, -7.0)); + EXPECT_TRUE(IsFieldEqual(vector2.y, -8.0)); + EXPECT_TRUE(IsFieldEqual(vector2.z, -9.0)); } TEST_F(Vector3DTest, AddEqualsVector3D) { @@ -278,9 +278,9 @@ TEST_F(Vector3DTest, AddEqualsVector3D) { vector2 += vector1; - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.x, 11.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.y, 13.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.z, 15.0)); + EXPECT_TRUE(IsFieldEqual(vector2.x, 11.0)); + EXPECT_TRUE(IsFieldEqual(vector2.y, 13.0)); + EXPECT_TRUE(IsFieldEqual(vector2.z, 15.0)); } TEST_F(Vector3DTest, AddVector3DVector2D) { @@ -296,9 +296,9 @@ TEST_F(Vector3DTest, AddVector3DVector2D) { Vector3D result = vector1 + vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 17.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 19.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 21.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 17.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 19.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 21.0)); } TEST_F(Vector3DTest, AddVector3DVector3D) { @@ -314,9 +314,9 @@ TEST_F(Vector3DTest, AddVector3DVector3D) { Vector3D result = vector1 + vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 7.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 9.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 11.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 7.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 9.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 11.0)); } TEST_F(Vector3DTest, MinusEqualsVector3D) { @@ -332,9 +332,9 @@ TEST_F(Vector3DTest, MinusEqualsVector3D) { vector2 -= vector1; - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.x, -97.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.y, -99.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector2.z, -101.0)); + EXPECT_TRUE(IsFieldEqual(vector2.x, -97.0)); + EXPECT_TRUE(IsFieldEqual(vector2.y, -99.0)); + EXPECT_TRUE(IsFieldEqual(vector2.z, -101.0)); } TEST_F(Vector3DTest, MinusVector3DVector2D) { @@ -350,9 +350,9 @@ TEST_F(Vector3DTest, MinusVector3DVector2D) { Vector3D result = vector1 - vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, -3.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, -1.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 1.0)); + EXPECT_TRUE(IsFieldEqual(result.x, -3.0)); + EXPECT_TRUE(IsFieldEqual(result.y, -1.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 1.0)); } TEST_F(Vector3DTest, MinusVector3DVector3D) { @@ -368,9 +368,9 @@ TEST_F(Vector3DTest, MinusVector3DVector3D) { Vector3D result = vector1 - vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 7.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 9.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 11.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 7.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 9.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 11.0)); } TEST_F(Vector3DTest, MultiplyEqualsBoutReal) { @@ -383,9 +383,9 @@ TEST_F(Vector3DTest, MultiplyEqualsBoutReal) { vector *= real; - EXPECT_TRUE(IsField3DEqualBoutReal(vector.x, 16.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.y, 20.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.z, 24.0)); + EXPECT_TRUE(IsFieldEqual(vector.x, 16.0)); + EXPECT_TRUE(IsFieldEqual(vector.y, 20.0)); + EXPECT_TRUE(IsFieldEqual(vector.z, 24.0)); } TEST_F(Vector3DTest, MultiplyEqualsField2D) { @@ -398,9 +398,9 @@ TEST_F(Vector3DTest, MultiplyEqualsField2D) { vector *= field; - EXPECT_TRUE(IsField3DEqualBoutReal(vector.x, 160.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.y, 200.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.z, 240.0)); + EXPECT_TRUE(IsFieldEqual(vector.x, 160.0)); + EXPECT_TRUE(IsFieldEqual(vector.y, 200.0)); + EXPECT_TRUE(IsFieldEqual(vector.z, 240.0)); } TEST_F(Vector3DTest, MultiplyVector3DBoutReal) { @@ -413,9 +413,9 @@ TEST_F(Vector3DTest, MultiplyVector3DBoutReal) { Vector3D result = vector * real; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 2.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 4.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 6.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 2.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 4.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 6.0)); } TEST_F(Vector3DTest, MultiplyVector3DField2D) { @@ -428,9 +428,9 @@ TEST_F(Vector3DTest, MultiplyVector3DField2D) { Vector3D result = vector * field; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 3.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 6.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 9.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 3.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 6.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 9.0)); } TEST_F(Vector3DTest, MultiplyVector3DField3D) { @@ -443,9 +443,9 @@ TEST_F(Vector3DTest, MultiplyVector3DField3D) { Vector3D result = vector * field; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 4.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 8.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 12.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 4.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 8.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 12.0)); } TEST_F(Vector3DTest, DivideEqualsBoutReal) { @@ -458,9 +458,9 @@ TEST_F(Vector3DTest, DivideEqualsBoutReal) { vector /= real; - EXPECT_TRUE(IsField3DEqualBoutReal(vector.x, 0.1)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.y, 0.2)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.z, 0.3)); + EXPECT_TRUE(IsFieldEqual(vector.x, 0.1)); + EXPECT_TRUE(IsFieldEqual(vector.y, 0.2)); + EXPECT_TRUE(IsFieldEqual(vector.z, 0.3)); } TEST_F(Vector3DTest, DivideEqualsConstField2D) { @@ -473,9 +473,9 @@ TEST_F(Vector3DTest, DivideEqualsConstField2D) { vector /= field; - EXPECT_TRUE(IsField3DEqualBoutReal(vector.x, 0.2)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.y, 0.4)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.z, 0.6)); + EXPECT_TRUE(IsFieldEqual(vector.x, 0.2)); + EXPECT_TRUE(IsFieldEqual(vector.y, 0.4)); + EXPECT_TRUE(IsFieldEqual(vector.z, 0.6)); } TEST_F(Vector3DTest, DivideVector3DBoutReal) { @@ -488,9 +488,9 @@ TEST_F(Vector3DTest, DivideVector3DBoutReal) { Vector3D result = vector / real; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 0.5)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 1.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 1.5)); + EXPECT_TRUE(IsFieldEqual(result.x, 0.5)); + EXPECT_TRUE(IsFieldEqual(result.y, 1.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 1.5)); } TEST_F(Vector3DTest, DivideVector3DField2D) { @@ -503,9 +503,9 @@ TEST_F(Vector3DTest, DivideVector3DField2D) { Vector3D result = vector / field; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 0.25)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 0.5)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 0.75)); + EXPECT_TRUE(IsFieldEqual(result.x, 0.25)); + EXPECT_TRUE(IsFieldEqual(result.y, 0.5)); + EXPECT_TRUE(IsFieldEqual(result.z, 0.75)); } TEST_F(Vector3DTest, DivideVector3DField3D) { @@ -518,9 +518,9 @@ TEST_F(Vector3DTest, DivideVector3DField3D) { Vector3D result = vector / field; - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 1.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 2.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 3.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 1.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 2.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 3.0)); } TEST_F(Vector3DTest, ToCovariant) { @@ -532,9 +532,9 @@ TEST_F(Vector3DTest, ToCovariant) { vector.toCovariant(); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.x, 48.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.y, 52.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.z, 52.0)); + EXPECT_TRUE(IsFieldEqual(vector.x, 48.0)); + EXPECT_TRUE(IsFieldEqual(vector.y, 52.0)); + EXPECT_TRUE(IsFieldEqual(vector.z, 52.0)); } TEST_F(Vector3DTest, ToContravariant) { @@ -546,9 +546,9 @@ TEST_F(Vector3DTest, ToContravariant) { vector.toContravariant(); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.x, 48.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.y, 52.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(vector.z, 52.0)); + EXPECT_TRUE(IsFieldEqual(vector.x, 48.0)); + EXPECT_TRUE(IsFieldEqual(vector.y, 52.0)); + EXPECT_TRUE(IsFieldEqual(vector.z, 52.0)); } TEST_F(Vector3DTest, Cross3D3D) { @@ -564,9 +564,9 @@ TEST_F(Vector3DTest, Cross3D3D) { auto result = cross(vector1, vector2); - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 0.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 0.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 0.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 0.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 0.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 0.0)); } TEST_F(Vector3DTest, Cross3D2D) { @@ -582,9 +582,9 @@ TEST_F(Vector3DTest, Cross3D2D) { auto result = cross(vector1, vector2); - EXPECT_TRUE(IsField3DEqualBoutReal(result.x, 0.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.y, 0.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(result.z, 0.0)); + EXPECT_TRUE(IsFieldEqual(result.x, 0.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 0.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 0.0)); } TEST_F(Vector3DTest, Dot3D3DCoContra) { @@ -601,7 +601,7 @@ TEST_F(Vector3DTest, Dot3D3DCoContra) { auto result = vector1 * vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result, 28.0)); + EXPECT_TRUE(IsFieldEqual(result, 28.0)); } TEST_F(Vector3DTest, Dot3D2DCoContra) { @@ -618,7 +618,7 @@ TEST_F(Vector3DTest, Dot3D2DCoContra) { auto result = vector1 * vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result, 28.0)); + EXPECT_TRUE(IsFieldEqual(result, 28.0)); } TEST_F(Vector3DTest, Dot3D3DCoCo) { @@ -634,7 +634,7 @@ TEST_F(Vector3DTest, Dot3D3DCoCo) { auto result = vector1 * vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result, 308.0)); + EXPECT_TRUE(IsFieldEqual(result, 308.0)); } TEST_F(Vector3DTest, Dot3D2DCoCo) { @@ -650,7 +650,7 @@ TEST_F(Vector3DTest, Dot3D2DCoCo) { auto result = vector1 * vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result, 308.0)); + EXPECT_TRUE(IsFieldEqual(result, 308.0)); } TEST_F(Vector3DTest, Dot3D3DContraContra) { @@ -668,7 +668,7 @@ TEST_F(Vector3DTest, Dot3D3DContraContra) { auto result = vector1 * vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result, 308.0)); + EXPECT_TRUE(IsFieldEqual(result, 308.0)); } TEST_F(Vector3DTest, Dot3D2DContraContra) { @@ -686,7 +686,7 @@ TEST_F(Vector3DTest, Dot3D2DContraContra) { auto result = vector1 * vector2; - EXPECT_TRUE(IsField3DEqualBoutReal(result, 308.0)); + EXPECT_TRUE(IsFieldEqual(result, 308.0)); } TEST_F(Vector3DTest, AbsCo) { @@ -697,7 +697,7 @@ TEST_F(Vector3DTest, AbsCo) { auto result = abs(vector1); - EXPECT_TRUE(IsField3DEqualBoutReal(result, 24.819347291981714)); + EXPECT_TRUE(IsFieldEqual(result, 24.819347291981714)); } TEST_F(Vector3DTest, AbsContra) { @@ -709,5 +709,5 @@ TEST_F(Vector3DTest, AbsContra) { auto result = abs(vector1); - EXPECT_TRUE(IsField3DEqualBoutReal(result, 24.819347291981714)); + EXPECT_TRUE(IsFieldEqual(result, 24.819347291981714)); } diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index dadd9e8910..6f3f34d4aa 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -229,12 +229,12 @@ INSTANTIATE_TEST_CASE_P(FourthZ, DerivativesTest, // single test, just instantiate it for each direction/order combination TEST_P(DerivativesTest, Sanity) { auto derivative = DerivativeStore::getInstance().getStandardDerivative( - std::get<2>(GetParam()), std::get<0>(GetParam()), STAGGER::None, std::get<1>(GetParam())); + std::get<2>(GetParam()), std::get<0>(GetParam()), STAGGER::None, + std::get<1>(GetParam())); Field3D result{mesh}; result.allocate(); derivative(input, result, region); - EXPECT_TRUE(IsField3DEqualField3D(result, expected, "RGN_NOBNDRY", - derivatives_tolerance)); + EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_NOBNDRY", derivatives_tolerance)); } diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 4d8c2885a7..de58c30abf 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -84,7 +84,7 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { {5., 6., 7., 1., 2., 3., 4.}, {6., 7., 1., 2., 3., 4., 5.}}}); - EXPECT_TRUE(IsField3DEqualField3D(shifted.toFieldAligned(input), expected)); + EXPECT_TRUE(IsFieldEqual(shifted.toFieldAligned(input), expected)); } TEST_F(ShiftedMetricTest, FromFieldAligned) { @@ -131,8 +131,7 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { {3., 4., 5., 6., 7., 1., 2.}}}); // Loosen tolerance a bit due to FFTs - EXPECT_TRUE(IsField3DEqualField3D(shifted.fromFieldAligned(input), expected, "RGN_ALL", - 1.e-12)); + EXPECT_TRUE(IsFieldEqual(shifted.fromFieldAligned(input), expected, "RGN_ALL", 1.e-12)); } TEST_F(ShiftedMetricTest, CalcYUpDown) { @@ -212,6 +211,6 @@ TEST_F(ShiftedMetricTest, CalcYUpDown) { {7., 1., 2., 3., 4., 5., 6.}, {0., 0., 0., 0., 0., 0., 0.}}}); - EXPECT_TRUE(IsField3DEqualField3D(input.yup(), expected_up, "RGN_YUP")); - EXPECT_TRUE(IsField3DEqualField3D(input.ydown(), expected_down, "RGN_YDOWN")); + EXPECT_TRUE(IsFieldEqual(input.yup(), expected_up, "RGN_YUP")); + EXPECT_TRUE(IsFieldEqual(input.ydown(), expected_down, "RGN_YDOWN")); } diff --git a/tests/unit/mesh/test_coordinates.cxx b/tests/unit/mesh/test_coordinates.cxx index 91781334b9..d968a6976b 100644 --- a/tests/unit/mesh/test_coordinates.cxx +++ b/tests/unit/mesh/test_coordinates.cxx @@ -30,8 +30,8 @@ TEST_F(CoordinatesTest, Jacobian) { EXPECT_NO_THROW(coords.jacobian()); - EXPECT_TRUE(IsField3DEqualBoutReal(coords.J, 1.0)); - EXPECT_TRUE(IsField3DEqualBoutReal(coords.Bxy, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.J, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.Bxy, 1.0)); } TEST_F(CoordinatesTest, CalcContravariant) { @@ -45,12 +45,12 @@ TEST_F(CoordinatesTest, CalcContravariant) { coords.calcCovariant(); output_info.enable(); - EXPECT_TRUE(IsField2DEqualBoutReal(coords.g_11, 1.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(coords.g_22, 1.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(coords.g_33, 1.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(coords.g_12, 0.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(coords.g_13, 0.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(coords.g_23, 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_11, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_22, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_33, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_12, 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_13, 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g_23, 0.0)); } TEST_F(CoordinatesTest, CalcCovariant) { @@ -64,10 +64,10 @@ TEST_F(CoordinatesTest, CalcCovariant) { coords.calcContravariant(); output_info.enable(); - EXPECT_TRUE(IsField2DEqualBoutReal(coords.g11, 1.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(coords.g22, 1.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(coords.g33, 1.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(coords.g12, 0.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(coords.g13, 0.0)); - EXPECT_TRUE(IsField2DEqualBoutReal(coords.g23, 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g11, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g22, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g33, 1.0)); + EXPECT_TRUE(IsFieldEqual(coords.g12, 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g13, 0.0)); + EXPECT_TRUE(IsFieldEqual(coords.g23, 0.0)); } diff --git a/tests/unit/test_extras.cxx b/tests/unit/test_extras.cxx index 1766f177b5..8d34359418 100644 --- a/tests/unit/test_extras.cxx +++ b/tests/unit/test_extras.cxx @@ -17,78 +17,6 @@ ::testing::AssertionResult IsSubString(const std::string &str, } } -::testing::AssertionResult IsField3DEqualBoutReal(const Field3D &field, BoutReal number, - BoutReal tolerance) { - const auto ®ion = field.getMesh()->getRegion3D("RGN_ALL"); - BOUT_FOR_SERIAL(i, region) { - if (fabs(field[i] - number) > tolerance) { - return ::testing::AssertionFailure() - << "Field3D(" << i.x() << ", " << i.y() << ", " << i.z() - << ") == " << field[i] << "; Expected: " << number; - } - } - - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult IsField3DEqualField3D(const Field3D& lhs, const Field3D& rhs, - const std::string& region_name, - BoutReal tolerance) { - const auto& region = lhs.getMesh()->getRegion3D(region_name); - BOUT_FOR_SERIAL(i, region) { - if (std::abs(lhs[i] - rhs[i]) > tolerance) { - return ::testing::AssertionFailure() - << "Field3D(" << i.x() << ", " << i.y() << ", " << i.z() << ") == " << lhs[i] - << "; Expected: " << rhs[i]; - } - } - - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult IsField2DEqualBoutReal(const Field2D &field, BoutReal number, - BoutReal tolerance) { - const auto ®ion = field.getMesh()->getRegion2D("RGN_ALL"); - BOUT_FOR_SERIAL(i, region) { - if (fabs(field[i] - number) > tolerance) { - return ::testing::AssertionFailure() - << "Field2D(" << i.x() << ", " << i.y() << ") == " << field[i] - << "; Expected: " << number; - } - } - - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult IsField2DEqualField2D(const Field2D& lhs, const Field2D& rhs, - const std::string& region_name, - BoutReal tolerance) { - const auto& region = lhs.getMesh()->getRegion2D(region_name); - BOUT_FOR_SERIAL(i, region) { - if (std::abs(lhs[i] - rhs[i]) > tolerance) { - return ::testing::AssertionFailure() - << "Field2D(" << i.x() << ", " << i.y() << ") == " << lhs[i] - << "; Expected: " << rhs[i]; - } - } - - return ::testing::AssertionSuccess(); -} - -::testing::AssertionResult IsFieldPerpEqualBoutReal(const FieldPerp &field, - BoutReal number, BoutReal tolerance) { - const auto ®ion = field.getMesh()->getRegionPerp("RGN_ALL"); - BOUT_FOR_SERIAL(i, region) { - if (fabs(field[i] - number) > tolerance) { - return ::testing::AssertionFailure() - << "FieldPerp(" << i.x() << ", " << i.z() << ") == " << field[i] - << "; Expected: " << number; - } - } - - return ::testing::AssertionSuccess(); -} - void fillField(Field3D& f, std::vector>> values) { f.allocate(); Ind3D i{0}; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 0dd4a91b1f..d566f64cd0 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -19,26 +19,6 @@ const BoutReal BoutRealTolerance = 1e-15; ::testing::AssertionResult IsSubString(const std::string &str, const std::string &substring); -/// Is \p field equal to \p number, with a tolerance of \p tolerance? -::testing::AssertionResult IsField3DEqualBoutReal(const Field3D &field, BoutReal number, - BoutReal tolerance = BoutRealTolerance); - -::testing::AssertionResult IsField3DEqualField3D(const Field3D &lhs, const Field3D &rhs, - const std::string& region = "RGN_ALL", - BoutReal tolerance = BoutRealTolerance); - -/// Is \p field equal to \p number, with a tolerance of \p tolerance? -::testing::AssertionResult IsField2DEqualBoutReal(const Field2D &field, BoutReal number, - BoutReal tolerance = BoutRealTolerance); - -::testing::AssertionResult IsField2DEqualField2D(const Field2D &lhs, const Field2D &rhs, - const std::string& region = "RGN_ALL", - BoutReal tolerance = BoutRealTolerance); - -/// Is \p field equal to \p number, with a tolerance of \p tolerance? -::testing::AssertionResult IsFieldPerpEqualBoutReal(const FieldPerp &field, BoutReal number, - BoutReal tolerance = BoutRealTolerance); - void fillField(Field3D& f, std::vector>> values); void fillField(Field2D& f, std::vector> values); @@ -66,6 +46,66 @@ inline std::ostream& operator<< (std::ostream &out, const SpecificInd &index) return out << index.ind; } +/// Helpers to get the type of a Field as a string +auto inline getFieldType(MAYBE_UNUSED(const Field2D& field)) -> std::string { + return "Field2D"; +} +auto inline getFieldType(MAYBE_UNUSED(const Field3D& field)) -> std::string { + return "Field3D"; +} +auto inline getFieldType(MAYBE_UNUSED(const FieldPerp& field)) -> std::string { + return "FieldPerp"; +} + +/// Helpers to get the (x, y, z) index values, along with the +/// single-index of a Field index +auto inline getIndexXYZ(const Ind2D& index) -> std::string { + std::stringstream ss; + ss << index.x() << ", " << index.y() << "; [" << index.ind << "]"; + return ss.str(); +} +auto inline getIndexXYZ(const Ind3D& index) -> std::string { + std::stringstream ss; + ss << index.x() << ", " << index.y() << ", " << index.z() << "; [" << index.ind << "]"; + return ss.str(); +} +auto inline getIndexXYZ(const IndPerp& index) -> std::string { + std::stringstream ss; + ss << index.x() << ", " << index.y() << ", " << index.z() << "; [" << index.ind << "]"; + return ss.str(); +} + +/// Is \p field equal to \p reference, with a tolerance of \p tolerance? +template , typename = EnableIfField> +auto IsFieldEqual(const T& field, const U& reference, + const std::string& region = "RGN_ALL", + BoutReal tolerance = BoutRealTolerance) -> ::testing::AssertionResult { + for (auto i : field.getRegion(region)) { + if (fabs(field[i] - reference[i]) > tolerance) { + return ::testing::AssertionFailure() + << getFieldType(field) << "(" << getIndexXYZ(i) << ") == " << field[i] + << "; Expected: " << reference[i]; + } + } + return ::testing::AssertionSuccess(); +} + +/// Is \p field equal to \p reference, with a tolerance of \p tolerance? +/// Overload for BoutReals +template > +auto IsFieldEqual(const T& field, BoutReal reference, + const std::string& region = "RGN_ALL", + BoutReal tolerance = BoutRealTolerance) -> ::testing::AssertionResult { + for (auto i : field.getRegion(region)) { + if (fabs(field[i] - reference) > tolerance) { + return ::testing::AssertionFailure() + << getFieldType(field) << "(" << getIndexXYZ(i) << ") == " << field[i] + << "; Expected: " << reference; + } + } + return ::testing::AssertionSuccess(); +} + class Options; /// FakeMesh has just enough information to create fields From f7a04627278e9ceb14c289b14af4a4314e64f9ad Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 6 Feb 2019 11:39:08 +0000 Subject: [PATCH 0706/1783] Remove the non-local_1d example case See issue #1457 for some related discussion --- examples/non-local_1d/ELM_BOUT.inp | 192 -- examples/non-local_1d/analyseTe | 40 - examples/non-local_1d/analyseTi | 36 - examples/non-local_1d/analyseV | 38 - .../non-local_1d/analyse_V_and_sound-speed | 49 - .../analyse_check_q_boundary_condition.py | 62 - .../non-local_1d/analyse_compare_2slices_Te | 47 - .../non-local_1d/analyse_compare_3slices_Te | 57 - .../non-local_1d/analyse_compare_slices_Ti | 44 - .../non-local_1d/analyse_compare_slices_V | 42 - .../non-local_1d/analyse_effective_alpha-e.py | 78 - .../non-local_1d/analyse_heatflux_limits.py | 114 - examples/non-local_1d/analyse_sliceTe | 31 - examples/non-local_1d/analyse_sliceTi | 32 - examples/non-local_1d/analyse_sliceV | 30 - examples/non-local_1d/analyse_slicej | 26 - examples/non-local_1d/analyse_slicen | 30 - examples/non-local_1d/analyse_slicepi | 34 - examples/non-local_1d/analyse_sliceq | 55 - examples/non-local_1d/analyse_slicer | 32 - examples/non-local_1d/analyse_slices_Te | 76 - .../non-local_1d/analyse_target_heatflux.py | 146 -- examples/non-local_1d/analyseboundary-Ts.py | 59 - examples/non-local_1d/analysen | 41 - examples/non-local_1d/analyseq | 39 - examples/non-local_1d/analyser | 58 - examples/non-local_1d/conduct_grid.nc | Bin 21352 -> 0 bytes examples/non-local_1d/cubic_spline_local.cxx | 126 - examples/non-local_1d/cubic_spline_local.hxx | 59 - examples/non-local_1d/data/BOUT.inp | 189 -- examples/non-local_1d/generate.py | 37 - .../non-local_1d/heat_flux_integration.cxx | 576 ----- .../non-local_1d/heat_flux_integration.hxx | 77 - examples/non-local_1d/makefile | 10 - examples/non-local_1d/non-local_1d.cxx | 616 ----- examples/non-local_1d/non-local_parallel.cxx | 2030 ----------------- examples/non-local_1d/non-local_parallel.hxx | 250 -- .../non-local_parallel_integration.cxx | 585 ----- .../non-local_parallel_integration.hxx | 77 - .../nonlocal_coefficients/frictionbc10 | 48 - .../nonlocal_coefficients/frictioncoeffs10 | 98 - .../nonlocal_coefficients/heatfluxbc10 | 49 - .../nonlocal_coefficients/heatfluxcoeffs10 | 97 - .../nonlocal_coefficients/viscositybc10 | 49 - .../nonlocal_coefficients/viscositycoeffs10 | 98 - examples/non-local_1d/profile-setup_BOUT.inp | 189 -- examples/non-local_1d/sin-single-sources.cxx | 168 -- 47 files changed, 6916 deletions(-) delete mode 100644 examples/non-local_1d/ELM_BOUT.inp delete mode 100755 examples/non-local_1d/analyseTe delete mode 100755 examples/non-local_1d/analyseTi delete mode 100755 examples/non-local_1d/analyseV delete mode 100755 examples/non-local_1d/analyse_V_and_sound-speed delete mode 100755 examples/non-local_1d/analyse_check_q_boundary_condition.py delete mode 100755 examples/non-local_1d/analyse_compare_2slices_Te delete mode 100755 examples/non-local_1d/analyse_compare_3slices_Te delete mode 100755 examples/non-local_1d/analyse_compare_slices_Ti delete mode 100755 examples/non-local_1d/analyse_compare_slices_V delete mode 100755 examples/non-local_1d/analyse_effective_alpha-e.py delete mode 100755 examples/non-local_1d/analyse_heatflux_limits.py delete mode 100755 examples/non-local_1d/analyse_sliceTe delete mode 100755 examples/non-local_1d/analyse_sliceTi delete mode 100755 examples/non-local_1d/analyse_sliceV delete mode 100755 examples/non-local_1d/analyse_slicej delete mode 100755 examples/non-local_1d/analyse_slicen delete mode 100755 examples/non-local_1d/analyse_slicepi delete mode 100755 examples/non-local_1d/analyse_sliceq delete mode 100755 examples/non-local_1d/analyse_slicer delete mode 100755 examples/non-local_1d/analyse_slices_Te delete mode 100755 examples/non-local_1d/analyse_target_heatflux.py delete mode 100755 examples/non-local_1d/analyseboundary-Ts.py delete mode 100755 examples/non-local_1d/analysen delete mode 100755 examples/non-local_1d/analyseq delete mode 100755 examples/non-local_1d/analyser delete mode 100644 examples/non-local_1d/conduct_grid.nc delete mode 100644 examples/non-local_1d/cubic_spline_local.cxx delete mode 100644 examples/non-local_1d/cubic_spline_local.hxx delete mode 100644 examples/non-local_1d/data/BOUT.inp delete mode 100755 examples/non-local_1d/generate.py delete mode 100644 examples/non-local_1d/heat_flux_integration.cxx delete mode 100644 examples/non-local_1d/heat_flux_integration.hxx delete mode 100644 examples/non-local_1d/makefile delete mode 100644 examples/non-local_1d/non-local_1d.cxx delete mode 100644 examples/non-local_1d/non-local_parallel.cxx delete mode 100644 examples/non-local_1d/non-local_parallel.hxx delete mode 100644 examples/non-local_1d/non-local_parallel_integration.cxx delete mode 100644 examples/non-local_1d/non-local_parallel_integration.hxx delete mode 100644 examples/non-local_1d/nonlocal_coefficients/frictionbc10 delete mode 100644 examples/non-local_1d/nonlocal_coefficients/frictioncoeffs10 delete mode 100644 examples/non-local_1d/nonlocal_coefficients/heatfluxbc10 delete mode 100644 examples/non-local_1d/nonlocal_coefficients/heatfluxcoeffs10 delete mode 100644 examples/non-local_1d/nonlocal_coefficients/viscositybc10 delete mode 100644 examples/non-local_1d/nonlocal_coefficients/viscositycoeffs10 delete mode 100644 examples/non-local_1d/profile-setup_BOUT.inp delete mode 100644 examples/non-local_1d/sin-single-sources.cxx diff --git a/examples/non-local_1d/ELM_BOUT.inp b/examples/non-local_1d/ELM_BOUT.inp deleted file mode 100644 index 8ba752c349..0000000000 --- a/examples/non-local_1d/ELM_BOUT.inp +++ /dev/null @@ -1,192 +0,0 @@ -# -# Input file for conduction case -# - -restart=true - -nout = 1001 # Number of output timesteps -timestep = 1.0e-6 # Time between outputs - -#MZ = 1 # Number of points in z -MZ = 1 - -dump_format="nc" # Write NetCDF format files - -grid="conduct_grid.nc" - -StaggerGrids = true - -################################################## -[mesh] - -type = bout - -################################################## -[ddy] # Methods used for parallel (y) derivative terms - -first = C4 -second = C4 -upwind = W3 -flux = U1 - -################################################## -[solver] # Solver settings - -archive=10 - -# CVODE # -type = cvode # Which solver to use - -max_timestep = 4.0e-8 -start_timestep = 1.e-9 -mxstep = 2000 - -#atol = 1.0e-10 # absolute tolerance -#rtol = 1.0e-5 # relative tolerance -atol = 1.0e-10 # absolute tolerance -rtol = 1.0e-7 # relative tolerance -use_vector_abstol=true - -################################################## -[output] # Output settings -#low_prec = false -floats = false - -################################################## -[non_local_parallel] # Settings for the heat flux model -moments_number = 10 -#NONLOCAL_PARALLEL_TAGBASE = 12381 -#NONLOCAL_PARALLEL_INTEGRATION_TAGBASE = 16381 - -################################################## -[sources] # Settings for the sources - -# the sources have a sine envelope around the centre of the domain, extending until it first reaches zero at +/- source_extent/2. -# the base amplitude is increased between on_time and off_time to *_amplitude + *_transient_amplitude -sources.source_length = 25. # in m - -# 40eV, 1e19m^-3 -#sources.particle_amplitude = 2.97190780803271e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 1.78314468481962e24 # in eV/m^3/s -#sources.ion_heat_amplitude = 1.78314468481962e24 # in eV/m^3/s - -# 100eV, 0.5e19m^-3 -#sources.particle_amplitude = 2.349499417355458e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 3.5242491260331873e24 # in eV/m^3/s -#sources.ion_heat_amplitude = 3.5242491260331873e24 # in eV/m^3/s - -# 100eV, 1e19m^-3 -#sources.particle_amplitude = 4.69899883471091617650831789566e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 7.0484982520663742647624768435e24 # in eV/m^3/s -#sources.ion_heat_amplitude = 7.0484982520663742647624768435e24 # in eV/m^3/s - -# 140eV, 1e19m^-3 -#sources.particle_amplitude = 5.5599304013683811018381815397e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 1.16758538428736003138601812334e25 # in eV/m^3/s -#sources.ion_heat_amplitude = 1.16758538428736003138601812334e25 # in eV/m^3/s - -# 200eV, 1e19m^-3 -#sources.particle_amplitude = 6.6453878816235472058187966917e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 1.99361636448706416174563900752e25 # in eV/m^3/s -#sources.ion_heat_amplitude = 1.99361636448706416174563900752e25 # in eV/m^3/s - -# 250eV, 1e19m^-3 -sources.particle_amplitude = 7.4297695200817885339785368656e22 # in m^-3 s^-1 -sources.electron_heat_amplitude = 2.78616357003067070024195132459e25 # in eV/m^3/s -#sources.electron_heat_amplitude = 7.e25 # in eV/m^3/s -sources.ion_heat_amplitude = 2.78616357003067070024195132459e25 # in eV/m^3/s - -# 300eV, 1e19m^-3 -#sources.particle_amplitude = 8.1389047264262557146095566295e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 3.6625071268918150715743004833e25 # in eV/m^3/s -#sources.ion_heat_amplitude = 3.6625071268918150715743004833e25 # in eV/m^3/s - -# 200eV, 1e17m^-3 -#sources.particle_amplitude = 6.6453878816235472058187966917e20 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 1.99361636448706416174563900752e23 # in eV/m^3/s -#sources.ion_heat_amplitude = 1.99361636448706416174563900752e23 # in eV/m^3/s - -sources.on_time = 1.e-6 # in s -sources.off_time = 201.e-6 # in s - -# 500eV, 2e19m^-3 -#sources.particle_transient_amplitude = 2.10145616412118138312975179139e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 1.57609212309088603734731384354e26 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 1.57609212309088603734731384354e26 # in eV/m^3/s - -# 750eV, 5e19m^-3 -#sources.particle_transient_amplitude = 6.434369148654145856198856725e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 7.2386652922359140882237138157e26 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 7.2386652922359140882237138157e26 # in eV/m^3/s - -# 1000eV, 5e19m^-3 -#sources.particle_transient_amplitude = 7.4297695200817885339785368656e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 1.11446542801226828009678052983e27 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 1.11446542801226828009678052983e27 # in eV/m^3/s - -# 1200eV, 5e19m^-3 -#sources.particle_transient_amplitude = 8.1389047264262557146095566295e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 1.46500285075672602862972019332e27 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 1.46500285075672602862972019332e27 # in eV/m^3/s - -# 1500eV, 5e19m^-3 -sources.particle_transient_amplitude = 9.09957211534171e23 # in m^-3 s^-1 -sources.electron_heat_transient_amplitude = 2.04740372595188e27 # in eV/m^3/s -sources.ion_heat_transient_amplitude = 2.04740372595188e27 # in eV/m^3/s - -# 1500eV, 5e19m^-3, 3:1 ion:electron split -#sources.particle_transient_amplitude = 9.09957211534171e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 1.02370186297594331874986893053e27 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 3.07110558892782995624960679159e27 # in eV/m^3/s - -# 1500eV, 1.5e19m^-3 -#sources.particle_transient_amplitude = 2.729871634602515e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 6.142211177855659e26 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 6.142211177855659e26 # in eV/m^3/s - -################################################## -[all] # Settings for all variables - -scale=1.0 -bndry_target = none -#bndry_target = neumann - -################################################## -[Vpar_ion] # Settings for the Vpar_ion variable - -atol = 1.0e-6 - -#function = 0. -function = 107000.*(y-pi+pi/256)/pi # 0 # -cos(y/2)*sqrt((2*10.)/(3.34358348e-27/1.602176565e-19)) - -################################################## -[j_parallel] # Settings for the j_parallel variable - -atol = 1.0e-6 - -function = 0. -#function = 1.e3*sin(127*y) -bndry_target = neumann - -################################################## -[T_electron] # Settings for the T_electron variable - -atol = 1.0e-10 - -#function = (1.0 + 1.0*gauss(y-pi, (2*pi/10)))*1.0e-19/1.0e-20 # The form of the initial perturbation. y from 0 to 2*pi, in J/energyunit -function = (100.0 + 0.0*gauss(y-pi+pi/256, (2*pi/10))) # The form of the initial perturbation. y from 0 to 2*pi, in eV -#function = (30.0 + 10.*cos((y-pi+pi/128))) # The form of the initial perturbation. y from 0 to 2*pi, in eV - -################################################## -[n_ion] # Settings for the n_ion variable - -atol = 1.0e9 - -function = 1.e19*(1. + 0.*gauss(y-pi)) - -################################################## -[T_ion] # Settings for the T_ion variable - -atol = 1.0e-10 - -function = (150.0 + 0.0*gauss(y-pi, (2*pi/10))) # The form of the initial perturbation. y from 0 to 2*pi, in eV diff --git a/examples/non-local_1d/analyseTe b/examples/non-local_1d/analyseTe deleted file mode 100755 index 28d14baba5..0000000000 --- a/examples/non-local_1d/analyseTe +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function -from builtins import str -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv - -if len(argv)==1: - end_index = -1 - data_path = "data" -elif len(argv)==2: - try: - end_index = int(argv[1]) - data_path = "data" - except ValueError: - end_index = -1 - data_path = str(argv[1]) -elif len(argv)==3: - end_index = int(argv[1]) - data_path = str(argv[2]) -else: - print("Arguments: [end_index][data_path] or [data_path]") - Exit(1) - -# Collect the data -Te = collect("T_electron", path=data_path, xind=2, info=True, yguards=True) - -if end_index<0: - end_index = len(Te[:,0,0,0]) - -# Te has dimensions [Time, X, Y, Z] -# Make contour plot -if len(argv)>1: - plotdata(Te[:end_index,0,:,0],title="Te") -else: - plotdata(Te[:,0,:,0],title="Te") -#print(Te[204,:,:,:]) diff --git a/examples/non-local_1d/analyseTi b/examples/non-local_1d/analyseTi deleted file mode 100755 index 862d68335c..0000000000 --- a/examples/non-local_1d/analyseTi +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function -from builtins import str -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv - -if len(argv)==1: - end_index = -1 - data_path = "data" -elif len(argv)==2: - try: - end_index = int(argv[1]) - data_path = "data" - except ValueError: - end_index = -1 - data_path = str(argv[1]) -elif len(argv)==3: - end_index = int(argv[1]) - data_path = str(argv[2]) -else: - print("Arguments: [end_index][data_path] or [data_path]") - Exit(1) - -# Collect the data -Ti = collect("T_ion", path=data_path, xind=2, info=True, yguards=True) - -if end_index<0: - end_index = len(Ti[:,0,0,0]) - -# Ti has dimensions [Time, X, Y, Z] -# Make contour plot -plotdata(Ti[:end_index,0,:,0],title="Ti") diff --git a/examples/non-local_1d/analyseV b/examples/non-local_1d/analyseV deleted file mode 100755 index 5d9e156598..0000000000 --- a/examples/non-local_1d/analyseV +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function -from builtins import str -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv - -if len(argv)==1: - end_index = -1 - data_path = "data" -elif len(argv)==2: - try: - end_index = int(argv[1]) - data_path = "data" - except ValueError: - end_index = -1 - data_path = str(argv[1]) -elif len(argv)==3: - end_index = int(argv[1]) - data_path = str(argv[2]) -else: - print("Arguments: [end_index][data_path] or [data_path]") - Exit(1) - -# Collect the data -V = collect("Vpar_ion", path=data_path, xind=2, info=True, yguards=True) - -if end_index<0: - end_index = len(V[:,0,0,0]) - -# V has dimensions [Time, X, Y, Z] -# Make contour plot -plotdata(V[:end_index,0,:,0],title="V") - -#print(V[204,:,:,:]) diff --git a/examples/non-local_1d/analyse_V_and_sound-speed b/examples/non-local_1d/analyse_V_and_sound-speed deleted file mode 100755 index 65940e2eda..0000000000 --- a/examples/non-local_1d/analyse_V_and_sound-speed +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python - -# -# Runs the conduction example, produces some output -# - -from __future__ import print_function -from builtins import str -from builtins import range -nproc = 1 # Number of processors to use -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv -from math import sqrt -from matplotlib import pyplot - -slice_index = int(argv[1]) -try: - data_path = str(argv[2]) -except: - data_path = "data" - -# Collect the data -V = collect("Vpar_ion", path=data_path, xind=2, info=True, yguards=True) -Te = collect("T_electron", path=data_path, xind=2, info=True, yguards=True) -Ti = collect("T_ion", path=data_path, xind=2, info=True, yguards=True) - -ion_mass = 3.34358348e-27 -elementary_charge = 1.602176565e-19 - -cellcentreposition=[] -sound_speed = [] -minus_sound_speed = [] -for i in range(2,len(V[0,0,:,0])-3): - print(i) - cellcentreposition.append(i-1.5) - sound_speed.append(sqrt((Te[slice_index,0,i,0]+3.*Ti[slice_index,0,i,0])*elementary_charge/ion_mass)) - minus_sound_speed.append(-sqrt((Te[slice_index,0,i,0]+3.*Ti[slice_index,0,i,0])*elementary_charge/ion_mass)) - -# V has dimensions [Time, X, Y, Z] -for index, item in enumerate(V[slice_index,0,:,0]): - print(index, item) -# Make contour plot -#plotdata(V[slice_index,0,2:-2,0],title="Velocity Profile and (collisionless, adiabatic) Sound Speed at t="+str(argv[1])) -pyplot.plot(V[slice_index,0,2:-2,0],'b',cellcentreposition,sound_speed,'r',cellcentreposition,minus_sound_speed,'r') -pyplot.title("Velocity Profile and (collisionless, adiabatic) Sound Speed at t="+str(argv[1])) -pyplot.show() diff --git a/examples/non-local_1d/analyse_check_q_boundary_condition.py b/examples/non-local_1d/analyse_check_q_boundary_condition.py deleted file mode 100755 index b7fa25bcb4..0000000000 --- a/examples/non-local_1d/analyse_check_q_boundary_condition.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Runs the conduction example, produces some output -# - -from __future__ import division -from builtins import str, range -from past.utils import old_div - -from boutdata.collect import collect -from sys import argv -from math import log, pi -from matplotlib import pyplot - -nproc = 1 # Number of processors to use - -gamma = 3. -if len(argv)>1: - data_path = str(argv[1]) -else: - data_path = "data" - -electron_mass = 9.10938291e-31 -ion_mass = 3.34358348e-27 - -# Collect the data -Te = collect("T_electron", path=data_path, info=True, yguards=True) -Ti = collect("T_ion", path=data_path, info=True, yguards=True) -n = collect("n_ion", path=data_path, info=True, yguards=True) -V = collect("Vpar_ion", path=data_path, info=True, yguards=True) -q = collect("heat_flux", path=data_path, info=True, yguards=True) - -q_electron_left = [] -q_electron_right = [] -right_index = len(Te[0,2,:,0])-4 - -for i in range(len(Te[:,2,0,0])): - Te_left = old_div((Te[i,2,2,0]+Te[i,2,1,0]),2.) - Ti_left = old_div((Ti[i,2,2,0]+Ti[i,2,1,0]),2.) - n_left = old_div((n[i,2,2,0]+n[i,2,1,0]),2.) - Te_right = old_div((Te[i,2,right_index,0]+Te[i,2,right_index+1,0]),2) - Ti_right = old_div((Ti[i,2,right_index,0]+Ti[i,2,right_index+1,0]),2) - n_right = old_div((n[i,2,right_index,0]+n[i,2,right_index+1,0]),2) - sheath_potential = 0.5*Te_left*log(2*pi*electron_mass/ion_mass*(1+gamma*Ti_left/Te_left)) - q_electron_left.append((2.0*Te_left-sheath_potential)*n_left*V[i,2,2,0]) # in W/m^2 - - sheath_potential = 0.5*Te_right*log(2*pi*electron_mass/ion_mass*(1+gamma*Ti_right/Te_right)) - q_electron_right.append((2.0*Te_right-sheath_potential)*n_right*V[i,2,right_index+1,0]) # in W/m^2 - -pyplot.figure(1) -pyplot.plot(q_electron_left,'r',q[:,2,2,0],'b',q_electron_right,'r',q[:,2,right_index+1,0],'b') -pyplot.title("Electron heat flux at the boundaries (blue) and calculated boundary value (red)\n\n") -pyplot.xlabel(u"t/μs") -pyplot.ylabel("Q/eV.m$^{-2}$") -pyplot.figure(2) -pyplot.plot(q[:,2,2,0]-q_electron_left,'b',q[:,2,right_index+1,0]-q_electron_right,'r') -pyplot.title("Difference between heat flux and its calculated boundary value at the left (blue) and right (red) boundaries\n\n") -pyplot.xlabel(u"t/μs") -pyplot.ylabel("dQ/eV.m$^{-2}$") -pyplot.show() diff --git a/examples/non-local_1d/analyse_compare_2slices_Te b/examples/non-local_1d/analyse_compare_2slices_Te deleted file mode 100755 index 4dece3e41d..0000000000 --- a/examples/non-local_1d/analyse_compare_2slices_Te +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Runs the conduction example, produces some output -# - -from __future__ import division -from builtins import str -from builtins import range -from past.utils import old_div -nproc = 1 # Number of processors to use - -from boutdata.collect import collect -import numpy as np -from sys import argv -from matplotlib import pyplot, rc - -rc('text', usetex=True) -rc('font',**{'family':'serif','serif':['Computer Modern']}) - - -data_path1 = str(argv[1]) -slice_index1 = int(argv[2]) -data_path2 = str(argv[3]) -slice_index2 = int(argv[4]) - -# Collect the data -T1 = collect("T_electron", path=data_path1, xind=2, info=True, yguards=True) -T2 = collect("T_electron", path=data_path2, xind=2, info=True, yguards=True) - -# T has dimensions [Time, X, Y, Z] -#for index, item in enumerate(T[slice_index,0,:,0]): -# print index, item -# Make contour plot -#plotdata(T[slice_index,0,:,0],title="Electron Temperature Profile at t="+str(argv[1]),ytitle="T/eV") - -positions=[] -totalgridpoints = len(T1[0,0,2:-3,0]) -for i in range(totalgridpoints): - positions.append(80./float(totalgridpoints)*(float(i)+0.5-old_div(float(totalgridpoints),2.))) - -pyplot.figure(dpi=80, facecolor='w') -pyplot.plot(positions,T1[slice_index1,0,2:-3,0],'b-',positions,T2[slice_index2,0,2:-3,0],'r--') -pyplot.xlabel("Position / m") -pyplot.ylabel("Electron Temperature / eV") -pyplot.show() diff --git a/examples/non-local_1d/analyse_compare_3slices_Te b/examples/non-local_1d/analyse_compare_3slices_Te deleted file mode 100755 index cc8b45e4b4..0000000000 --- a/examples/non-local_1d/analyse_compare_3slices_Te +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Runs the conduction example, produces some output -# - -from __future__ import division -from builtins import str -from builtins import range -from past.utils import old_div -nproc = 1 # Number of processors to use - -from boutdata.collect import collect -import numpy as np -from sys import argv -from matplotlib import pyplot, rc - -rc('text', usetex=True) -#rc('font',**{'family':'serif','serif':['Computer Modern']}) -rc('font',**{'family':'serif','serif':['Computer Modern'],'size':20}) - -data_path1 = str(argv[1]) -slice_index1 = int(argv[2]) -data_path2 = str(argv[3]) -slice_index2 = int(argv[4]) -data_path3 = str(argv[5]) -slice_index3 = int(argv[6]) - -# Collect the data -T1 = collect("T_electron", path=data_path1, xind=2, info=True, yguards=True) -T2 = collect("T_electron", path=data_path2, xind=2, info=True, yguards=True) -T3 = collect("T_electron", path=data_path3, xind=2, info=True, yguards=True) - -# T has dimensions [Time, X, Y, Z] -#for index, item in enumerate(T[slice_index,0,:,0]): -# print index, item -# Make contour plot -#plotdata(T[slice_index,0,:,0],title="Electron Temperature Profile at t="+str(argv[1]),ytitle="T/eV") - -positions=[] -totalgridpoints = len(T1[0,0,2:-3,0]) -for i in range(totalgridpoints): - positions.append(80./float(totalgridpoints)*(float(i)+0.5-old_div(float(totalgridpoints),2.))) - -pyplot.figure(facecolor='w') -#pyplot.figure(dpi=800, facecolor='w') -pyplot.plot(positions,T1[slice_index1,0,2:-3,0],'b-',positions,T2[slice_index2,0,2:-3,0],'r--',positions,T3[slice_index3,0,2:-3,0],'g:') -#pyplot.plot(positions,T1[slice_index1,0,2:-3,0],'k',positions,T2[slice_index2,0,2:-3,0],'b',positions,T3[slice_index3,0,2:-3,0],'r') -pyplot.xlabel("Position / m") -pyplot.ylabel("Electron Temperature / eV") -pyplot.tight_layout(pad=0.1) - -pyplot.savefig('fig.pdf') -pyplot.savefig('fig.eps') - -pyplot.show() diff --git a/examples/non-local_1d/analyse_compare_slices_Ti b/examples/non-local_1d/analyse_compare_slices_Ti deleted file mode 100755 index 9ec9557287..0000000000 --- a/examples/non-local_1d/analyse_compare_slices_Ti +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Runs the conduction example, produces some output -# - -from __future__ import division -from builtins import str -from builtins import range -from past.utils import old_div -nproc = 1 # Number of processors to use - -from boutdata.collect import collect -from boutdata.collect import collect -import numpy as np -from sys import argv -from matplotlib import pyplot - -data_path1 = str(argv[1]) -slice_index1 = int(argv[2]) -data_path2 = str(argv[3]) -slice_index2 = int(argv[4]) - -# Collect the data -T1 = collect("T_ion", path=data_path1, xind=2, info=True, yguards=True) -T2 = collect("T_ion", path=data_path2, xind=2, info=True, yguards=True) - -# T has dimensions [Time, X, Y, Z] -#for index, item in enumerate(T[slice_index,0,:,0]): -# print index, item -# Make contour plot -#plotdata(T[slice_index,0,:,0],title="Electron Temperature Profile at t="+str(argv[1]),ytitle="T/eV") - -positions=[] -totalgridpoints = len(T1[0,0,2:-3,0]) -for i in range(totalgridpoints): - positions.append(80./float(totalgridpoints)*(float(i)+0.5-old_div(float(totalgridpoints),2.))) - -pyplot.figure(dpi=80, facecolor='w') -pyplot.plot(positions,T1[slice_index1,0,2:-3,0],'b-',positions,T2[slice_index2,0,2:-3,0],'r--') -pyplot.xlabel("Position / m") -pyplot.ylabel("Electron Temperature / eV") -pyplot.show() diff --git a/examples/non-local_1d/analyse_compare_slices_V b/examples/non-local_1d/analyse_compare_slices_V deleted file mode 100755 index 078abfa486..0000000000 --- a/examples/non-local_1d/analyse_compare_slices_V +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Runs the conduction example, produces some output -# - -from __future__ import division -from builtins import str -from builtins import range -from past.utils import old_div -nproc = 1 # Number of processors to use - -from boutdata.collect import collect -import numpy as np -from sys import argv -from matplotlib import pyplot - -slice_index = int(argv[1]) -data_path1 = str(argv[2]) -data_path2 = str(argv[3]) - -# Collect the data -V1 = collect("Vpar_ion", path=data_path1, xind=2, info=True, yguards=True) -V2 = collect("Vpar_ion", path=data_path2, xind=2, info=True, yguards=True) - -# T has dimensions [Time, X, Y, Z] -#for index, item in enumerate(T[slice_index,0,:,0]): -# print index, item -# Make contour plot -#plotdata(T[slice_index,0,:,0],title="Electron Temperature Profile at t="+str(argv[1]),ytitle="T/eV") - -positions=[] -totalgridpoints = len(V1[0,0,2:-3,0]) -for i in range(totalgridpoints): - positions.append(80./float(totalgridpoints)*(float(i)+0.5-old_div(float(totalgridpoints),2.))) - -pyplot.figure(dpi=80, facecolor='w') -pyplot.plot(positions,V1[slice_index,0,2:-3,0],'b',positions,V2[slice_index,0,2:-3,0],'r-') -pyplot.xlabel("Position / m") -pyplot.ylabel("Electron Temperature / eV") -pyplot.show() diff --git a/examples/non-local_1d/analyse_effective_alpha-e.py b/examples/non-local_1d/analyse_effective_alpha-e.py deleted file mode 100755 index bada29e07c..0000000000 --- a/examples/non-local_1d/analyse_effective_alpha-e.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from __future__ import print_function -from __future__ import division -from builtins import str, range -from past.utils import old_div - -from boutdata.collect import collect - -from sys import argv -from matplotlib import pyplot, ticker, rc - -rc('text', usetex=True) -#rc('font',**{'family':'serif','serif':['Computer Modern']}) -rc('font',**{'family':'serif','serif':['Computer Modern'],'size':20}) - - -if len(argv)==1: - end_index = -1 - data_path = "data" -elif len(argv)==2: - try: - end_index = int(argv[1]) - data_path = "data" - except ValueError: - end_index = -1 - data_path = str(argv[1]) -elif len(argv)==3: - end_index = int(argv[1]) - data_path = str(argv[2]) -else: - print("Arguments: '[end_index] [data_path]' or '[data_path]'") - Exit(1) - -electron_mass = 9.10938291e-31 -ion_mass = 3.34358348e-27 - -# Collect the data -f = collect("effective_alpha_e", path=data_path, info=True) -#Te = collect("T_electron", path=data_path, xind=2, info=True, yguards=True) -#Ti = collect("T_ion", path=data_path, xind=2, info=True, yguards=True) -#n = collect("n_ion", path="data", xind=2, info=True, yguards=True) - -if end_index<0: - end_index = len(f[:]) - -alpha0 = 1 -alphaoveralpha0 = [] -for i in range(end_index): - alphaoveralpha0.append(old_div(f[i],alpha0)) - print(i,alphaoveralpha0[i]) - -# Make plot -pyplot.figure(1, facecolor='w') -#pyplot.figure(1,dpi=800, facecolor='w') - -if len(argv)>2: -# pyplot.semilogy(f[:end_index],'k') - pyplot.semilogy(alphaoveralpha0[:end_index],'k') -else: -# pyplot.semilogy(f[:],'k') - pyplot.semilogy(alphaoveralpha0[:],'k') - -#pyplot.title("Effective electron heat-flux limiter") -pyplot.axes().xaxis.set_major_formatter(ticker.FormatStrFormatter("$%g$")) -pyplot.axes().grid(color='grey', which='both') -#pyplot.xlabel(u"t/μs") -pyplot.xlabel("$t/\mu\mathrm{s}$") -#pyplot.ylabel(u"α_e") -pyplot.ylabel("$\langle \\alpha_e \\rangle$") -#pyplot.ylabel("$\langle \\alpha_{\\mathrm{e}} \\rangle$") -pyplot.tight_layout(pad=.1) - -pyplot.savefig('fig.pdf') -pyplot.savefig('fig.eps',dpi=1200) - -pyplot.show() diff --git a/examples/non-local_1d/analyse_heatflux_limits.py b/examples/non-local_1d/analyse_heatflux_limits.py deleted file mode 100755 index 9ba99fee12..0000000000 --- a/examples/non-local_1d/analyse_heatflux_limits.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Runs the conduction example, produces some output -# - -from __future__ import print_function -from __future__ import division -from builtins import range -from past.utils import old_div - -from boutdata.collect import collect -from math import sqrt, pow, pi -from matplotlib import pyplot - -nproc = 1 # Number of processors to use - -def sign(x): - if x>=0.: - return 1. - else: - return -1. - -massunit = 1.602176565e-19 -electron_mass = old_div(9.10938291e-31,massunit) -electron_charge = -1.602176565e-19 -ion_mass = old_div(3.34358348e-27,massunit) -ion_charge = 1.602176565e-19 -epsilon_0 = old_div(8.85418781762039e-12,pow(massunit,-1)) -logLambda = 16.0 - -stagger = True -t_interval = 10 - -# Collect the data -Te = collect("T_electron", path="data", info=True, yguards=True) -Ti = collect("T_ion", path="data", info=True, yguards=True) -n = collect("n_ion", path="data", info=True, yguards=True) - -ylength = len(Te[0,2,:,0]) -tlength = len(Te[:,2,0,0]) - -try: dy = collect("dy", path="data", info=True, yguards=True) -except TypeError: - print("Warning, could not find dy, setting to 1.0") - dy=[[1.]*ylength]*5 - -try: g_22 = collect("g_22", path="data", info=True, yguards=True) -except TypeError: - print("Warning, could not find g_22, setting to (80./256)^2") - g_22=[[pow(old_div(80.,256),2)]*ylength]*5 - -try: - qin = collect("heat_flux", path="data", info=True, yguards=True) - q = [[0.]*ylength for i in range(0,old_div(tlength,t_interval)+1)] - for i in range(0,tlength,t_interval): - for j in range(2,ylength-2): - q[old_div(i,t_interval)][j] = qin[i,2,j,0] -except TypeError: - print("Calculating Braginskii heat flux") - q = [[0.]*ylength for i in range(0,old_div(tlength,t_interval)+1)] - tau_ei = 0 - gradT = 0 - for i in range(0,tlength,t_interval): - for j in range(2,ylength-2): - tau_ei = 3 * pow(pi,1.5) * pow(epsilon_0,2) * sqrt(electron_mass) * pow(2.,1.5) * pow(Te[i,2,j,0],1.5) / n[i,2,j,0] / pow(electron_charge,2) / pow(ion_charge,2) / logLambda - gradT = (Te[i,2,j-2,0] - 8.*Te[i,2,j-1,0] + 8.*Te[i,2,j+1,0] - Te[i,2,j+2,0])/12./dy[2][j]/sqrt(g_22[2][j]) - q[old_div(i,t_interval)][j] = -3.16*n[i,2,j,0]*Te[i,2,j,0]*tau_ei/electron_mass*gradT - stagger = False - -Temax = [0.]*(old_div(tlength,t_interval)+1) -for i in range(0,tlength,t_interval): - Temax[old_div(i,t_interval)] = max(Te[i,2,:,0]) -Timax = [0.]*(old_div(tlength,t_interval)+1) -for i in range(0,tlength,t_interval): - Timax[old_div(i,t_interval)] = max(Ti[i,2,:,0]) -nmax = [0.]*(old_div(tlength,t_interval)+1) -for i in range(0,tlength,t_interval): - nmax[old_div(i,t_interval)] = max(n[i,2,:,0]) -freestreammax = [0.]*(old_div(tlength,t_interval)+1) -for i in range(old_div(tlength,t_interval)+1): - freestreammax[i]=3./2.*nmax[i]*Temax[i]*sqrt(old_div((Temax[i]+Timax[i]),ion_mass)) - #freestreammax[i]=3./2.*nmax[i]*Temax[i]*sqrt(2*Temax[i]/electron_mass) - -#freestream = [[i]*ylength for i in range(tlength/t_interval+1)] -#for i in range(0,tlength,t_interval): - #for j in range(2,ylength-2): - #freestream[i/t_interval][j] = sign(j-ylength/2)*3./2.*n[i,2,j,0]*Te[i,2,j,0]*sqrt((Te[i,2,j,0]+Ti[i,2,j,0])/ion_mass) - -#freestream = [[i]*ylength for i in range(tlength/t_interval+1)] -#for i in range(0,tlength,t_interval): - #for j in range(2,ylength-2): - #freestream[i/t_interval][j] = sign(j-ylength/2)*3./2.*n[i,2,j,0]*Te[i,2,j,0]*sqrt(2*Te[i,2,j,0]/electron_mass) - -#for i in range(0,tlength,t_interval): - #pyplot.figure(i) - #pyplot.plot(range(2,ylength-2),q[i/t_interval][2:-2],'k', range(2,ylength-2),freestream[i/t_interval][2:-2], 'r') - -for i in range(0,tlength,t_interval): - pyplot.figure(i) - pyplot.plot(list(range(2,ylength-2)),q[old_div(i,t_interval)][2:-2],'k', list(range(2,ylength-2)),[freestreammax[old_div(i,t_interval)]]*(ylength-4), 'r',[-freestreammax[old_div(i,t_interval)]]*(ylength-4), 'r') - -pyplot.show() - -#pyplot.figure(5) -#pyplot.plot(logtime,q_electron_left,'r',logtime,q_ion_left,'b',logtime,q_total_left,'k') -#pyplot.title("Electron (red), Ion (blue) and Total (black) Heat Flux vs log(t)") -#pyplot.figure(6) -#pyplot.plot(q_electron_left,'r',q_ion_left,'b',q_total_left,'k') -#pyplot.title("Electron (red), Ion (blue) and Total (black) Heat Flux") -#pyplot.xlabel(u"t/μs") -#pyplot.ylabel("Q/W.m$^{-2}$") -#pyplot.show() diff --git a/examples/non-local_1d/analyse_sliceTe b/examples/non-local_1d/analyse_sliceTe deleted file mode 100755 index aa054fd2b4..0000000000 --- a/examples/non-local_1d/analyse_sliceTe +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Runs the conduction example, produces some output -# - -from __future__ import print_function -from builtins import str -nproc = 1 # Number of processors to use - -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv - -slice_index = int(argv[1]) -try: - data_path = str(argv[2]) -except: - data_path = "data" - -# Collect the data -T = collect("T_electron", path=data_path, xind=2, info=True, yguards=True) - -# T has dimensions [Time, X, Y, Z] -for index, item in enumerate(T[slice_index,0,:,0]): - print(index, item) -# Make contour plot -plotdata(T[slice_index,0,:,0],title="Electron Temperature Profile at t="+str(argv[1]),ytitle="T/eV") diff --git a/examples/non-local_1d/analyse_sliceTi b/examples/non-local_1d/analyse_sliceTi deleted file mode 100755 index e60b04c304..0000000000 --- a/examples/non-local_1d/analyse_sliceTi +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -# -# Runs the conduction example, produces some output -# - -from __future__ import print_function -from builtins import str -nproc = 1 # Number of processors to use - -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv - -slice_index = int(argv[1]) -try: - data_path = str(argv[2]) -except: - data_path = "data" - -# Collect the data -T = collect("T_ion", path=data_path, xind=2, info=True, yguards=True) -#chi = collect("chi", path="data", xind=2, info=True, yguards=True) -#integral = collect("integral", path="data", xind=2, info=True, yguards=True) -#q = collect("heat_flux", path="data", xind=2, info=True, yguards=True) - -# T has dimensions [Time, X, Y, Z] -print(T[slice_index,0,:,0]) -# Make contour plot -plotdata(T[slice_index,0,2:-3,0],title="Ion Temperature Profile at t="+str(argv[1]),ytitle="T/eV") diff --git a/examples/non-local_1d/analyse_sliceV b/examples/non-local_1d/analyse_sliceV deleted file mode 100755 index 7ef3b42123..0000000000 --- a/examples/non-local_1d/analyse_sliceV +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -# -# Runs the conduction example, produces some output -# - -from __future__ import print_function -from builtins import str -nproc = 1 # Number of processors to use - -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv - -slice_index = int(argv[1]) -try: - data_path = str(argv[2]) -except: - data_path = "data" - -# Collect the data -T = collect("Vpar_ion", path=data_path, xind=2, info=True, yguards=True) - -# T has dimensions [Time, X, Y, Z] -for index, item in enumerate(T[slice_index,0,:,0]): - print(index, item) -# Make contour plot -plotdata(T[slice_index,0,:,0],title="Velocity Profile at t="+str(argv[1])) diff --git a/examples/non-local_1d/analyse_slicej b/examples/non-local_1d/analyse_slicej deleted file mode 100755 index 0ef45644e4..0000000000 --- a/examples/non-local_1d/analyse_slicej +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from __future__ import print_function -from builtins import str - -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv - -slice_index = int(argv[1]) -try: - data_path = str(argv[2]) -except: - data_path = "data" - -# Collect the data -j = collect("j_parallel", path=data_path, xind=2, info=True, yguards=True) - -# j has dimensions [Time, X, Y, Z] -for index, item in enumerate(j[slice_index,0,:,0]): - print(index, item) -# Make contour plot -plotdata(j[slice_index,0,:,0],title="Parallel Current Profile at t="+str(argv[1]),ytitle="j/Am^-2") diff --git a/examples/non-local_1d/analyse_slicen b/examples/non-local_1d/analyse_slicen deleted file mode 100755 index 48c2ed8e12..0000000000 --- a/examples/non-local_1d/analyse_slicen +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -# -# Runs the conduction example, produces some output -# - -from __future__ import print_function -from builtins import str -nproc = 1 # Number of processors to use - -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv - -slice_index = int(argv[1]) -try: - data_path = str(argv[2]) -except: - data_path = "data" - -# Collect the data -T = collect("n_ion", path=data_path, xind=2, info=True, yguards=True) - -# T has dimensions [Time, X, Y, Z] -print(T[slice_index,0,:,0]) -# Make contour plot -#plotdata(T[:,0,:,0]) -plotdata(T[slice_index,0,:,0]) diff --git a/examples/non-local_1d/analyse_slicepi b/examples/non-local_1d/analyse_slicepi deleted file mode 100755 index cb5ee2f103..0000000000 --- a/examples/non-local_1d/analyse_slicepi +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python - -# -# Runs the conduction example, produces some output -# - -from __future__ import print_function -from builtins import str -nproc = 1 # Number of processors to use - -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv - -slice_index = int(argv[1]) -try: - data_path = str(argv[2]) -except: - data_path = "data" - -# Collect the data -pi = collect("viscosity", path=data_path, xind=2, info=True, yguards=True) - -# pi has dimensions [Time, X, Y, Z] -length=len(pi[0,0,:,0]) -for index, item in enumerate(pi[slice_index,0,:,0]): - print(index, item) - -print("data_path is",data_path) - -# Make plot -plotdata(pi[slice_index,0,:,0],title="Electron Viscosity Profile at t="+str(argv[1])) diff --git a/examples/non-local_1d/analyse_sliceq b/examples/non-local_1d/analyse_sliceq deleted file mode 100755 index c650a8f99b..0000000000 --- a/examples/non-local_1d/analyse_sliceq +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python - -# -# Runs the conduction example, produces some output -# - -from __future__ import print_function -from __future__ import division -from builtins import str -from builtins import range -from past.utils import old_div -nproc = 1 # Number of processors to use - -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv - -slice_index = int(argv[1]) -try: - data_path = str(argv[2]) -except: - data_path = "data" - -# Collect the data -q = collect("heat_flux", path=data_path, xind=2, info=True, yguards=True) - -# q has dimensions [Time, X, Y, Z] -length=len(q[0,0,:,0]) -for index, item in enumerate(q[slice_index,0,:,0]): - print(index, item) - -print("minimum_q =", min(q[slice_index,0,3:length-3,0]), " maximum_q =", max(q[slice_index,0,3:length-3,0])) -print(" ") -print("data_path is",data_path) - -localminq=0 -for i in range(old_div(length,2)-1,0,-1): - test=q[slice_index,0,i,0] - if test>localminq: - break - localminq=test - -localmaxq=0 -for i in range(old_div(length,2)+1,length): - test=q[slice_index,0,i,0] - if test0: logtime.append(log10(i)) - else: logtime.append(0) - Te_here = 0.5*(Te[i,2,2,0]+Te[i,2,3,0]) - n_here = 0.5*(n[i,2,2,0]+n[i,2,3,0]) - Ti_here = 0.5*(Ti[i,2,2,0]+Ti[i,2,3,0]) - sheath_potential = 0.5*Te_here*log(2*pi*electron_mass/ion_mass*(1+gamma*Ti_here/Te_here)) - q_electron_left.append((2.0*Te_here-sheath_potential)*n_here*1.602176565e-19*sqrt((Te_here+gamma*Ti_here)/3.34358348e-27*1.602176565e-19)) # in W/m^2 - q_ion_left.append(n_here*((2.5+0.5*gamma)*Ti_here+0.5*Te_here)*1.602176565e-19*sqrt((Te_here+gamma*Ti_here)/3.34358348e-27*1.602176565e-19)) # in W/m^2 - q_total_left.append(q_electron_left[i]+q_ion_left[i]) # in W/m^2 - - q_target_electron_left.append((2.0*Te_here)*n_here*1.602176565e-19*sqrt((Te_here+gamma*Ti_here)/3.34358348e-27*1.602176565e-19)) # in W/m^2 - q_target_ion_left.append(n_here*((2.5+0.5*gamma)*Ti_here+0.5*Te_here-sheath_potential)*1.602176565e-19*sqrt((Te_here+gamma*Ti_here)/3.34358348e-27*1.602176565e-19)) # in W/m^2 - q_target_total_left.append(q_target_electron_left[i]+q_target_ion_left[i]) # in W/m^2 - - Te_here = (Te[i,2,right_index,0]+Te[i,2,right_index+1,0]) - n_here = (n[i,2,right_index,0]+n[i,2,right_index+1,0]) - Ti_here = (Ti[i,2,right_index,0]+Ti[i,2,right_index+1,0]) - sheath_potential = 0.5*Te_here*log(2*pi*electron_mass/ion_mass*(1+gamma*Ti_here/Te_here)) - q_electron_right.append((2.0*Te_here-sheath_potential)*n_here*1.602176565e-19*sqrt((Te_here+gamma*Ti_here)/3.34358348e-27*1.602176565e-19)) # in W/m^2 - q_ion_right.append(n_here*((2.5+0.5*gamma)*Ti_here+0.5*Te_here)*1.602176565e-19*sqrt((Te_here+gamma*Ti_here)/3.34358348e-27*1.602176565e-19)) # in W/m^2 - q_total_right.append(q_electron_right[i]+q_ion_right[i]) # in W/m^2 - - q_target_electron_right.append((2.0*Te_here)*n_here*1.602176565e-19*sqrt((Te_here+gamma*Ti_here)/3.34358348e-27*1.602176565e-19)) # in W/m^2 - q_target_ion_right.append(n_here*((2.5+0.5*gamma)*Ti_here+0.5*Te_here-sheath_potential)*1.602176565e-19*sqrt((Te_here+gamma*Ti_here)/3.34358348e-27*1.602176565e-19)) # in W/m^2 - q_target_total_right.append(q_target_electron_right[i]+q_target_ion_right[i]) # in W/m^2 - -#pyplot.figure(1) -#pyplot.plot(logtime,q_electron_left) -#pyplot.axes().set_aspect('auto') -#pyplot.title("Electron Heat Flux (lower boundary)") -#pyplot.figure(2) -#pyplot.plot(q_electron_right) -#pyplot.axes().set_aspect('auto') -#pyplot.title("Electron Heat Flux (upper boundary)") -#pyplot.figure(3) -#pyplot.plot(q_total_left) -#pyplot.axes().set_aspect('auto') -#pyplot.title("Total Heat Flux (lower boundary)") -#pyplot.figure(4) -#pyplot.plot(q_total_right) -#pyplot.axes().set_aspect('auto') -#pyplot.title("Total Heat Flux (upper boundary)") -pyplot.figure(5,dpi=80, facecolor='w') -#pyplot.plot(logtime,q_electron_left,'r',logtime,q_ion_left,'b',logtime,q_total_left,'k') -#pyplot.title("Electron (red), Ion (blue) and Total (black) Sheath Edge Heat Flux vs log(t)") -pyplot.semilogx(q_electron_left,'r',q_ion_left,'b',q_total_left,'k') -pyplot.title("Electron (red), Ion (blue) and Total (black) Sheath Edge Heat Flux\\ \\") -pyplot.xlabel("$t/\mu\mathrm{s}$") -pyplot.ylabel(r"$Q\mathrm{/W.m}^{-2}$") -pyplot.axes().xaxis.set_major_formatter(ticker.FormatStrFormatter("$%g$")) -pyplot.axes().grid(color='grey', which='both') -#pyplot.tight_layout(pad=20) -pyplot.figure(6) -pyplot.plot(q_electron_right,'r',q_ion_right,'b',q_total_right,'k') -pyplot.title("Electron (red), Ion (blue) and Total (black) Sheath Edge Heat Flux\\ \\") -pyplot.xlabel("$t/\mu\mathrm{s}$") -pyplot.ylabel(r"$Q\mathrm{/W.m}^{-2}$") -#pyplot.figure(7,dpi=80, facecolor='w') -pyplot.figure(7,dpi=800, facecolor='w') -#pyplot.plot(logtime,q_target_electron_left,'r',logtime,q_target_ion_left,'b',logtime,q_target_total_left,'k') -#pyplot.title("Electron (red), Ion (blue) and Total (black) Target Heat Flux vs log(t)") -#pyplot.semilogx(q_target_electron_left,'r',q_target_ion_left,'b',q_target_total_left,'k') -#pyplot.semilogx(q_target_electron_left,'k',q_target_ion_left,'r',q_target_total_left,'b') -pyplot.semilogx(q_target_electron_left,'r--',q_target_ion_left,'b:',q_target_total_left,'k') -#pyplot.title("Electron (red), Ion (blue) and Total (black) Target Heat Flux\\ \\") -pyplot.xlabel("$t/\mu\mathrm{s}$") -pyplot.ylabel(r"$Q\mathrm{/W.m}^{-2}$") -pyplot.ylim(0,5e9) -pyplot.axes().xaxis.set_major_formatter(ticker.FormatStrFormatter("$%g$")) -pyplot.axes().grid(color='grey', which='both') -pyplot.tight_layout(pad=20) -pyplot.figure(8) -pyplot.plot(q_target_electron_right,'r',q_target_ion_right,'b',q_target_total_right,'k') -pyplot.rc('text', usetex=True) -pyplot.title("Electron (red), Ion (blue) and Total (black) Target Heat Flux") -pyplot.xlabel("$t/\mu\mathrm{s}$") -pyplot.ylabel(r"$Q\mathrm{/W.m}^{-2}$") -pyplot.show() diff --git a/examples/non-local_1d/analyseboundary-Ts.py b/examples/non-local_1d/analyseboundary-Ts.py deleted file mode 100755 index 63ca8e5a76..0000000000 --- a/examples/non-local_1d/analyseboundary-Ts.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function -from __future__ import division -from builtins import str -from builtins import range -from past.utils import old_div -from boutdata.collect import collect -from sys import argv -from matplotlib import pyplot, ticker, rc - -rc('text', usetex=True) -rc('font',**{'family':'serif','serif':['Computer Modern']}) - - - -if len(argv)==1: - end_index = -1 - data_path = "data" -elif len(argv)==2: - try: - end_index = int(argv[1]) - data_path = "data" - except ValueError: - end_index = -1 - data_path = str(argv[1]) -elif len(argv)==3: - end_index = int(argv[1]) - data_path = str(argv[2]) -else: - print("Arguments: '[end_index] [data_path]' or 'gamma [data_path]'") - Exit(1) - -# Collect the data -Te = collect("T_electron", path=data_path, xind=2, info=True, yguards=True) -Ti = collect("T_ion", path=data_path, xind=2, info=True, yguards=True) - -if end_index<0: - end_index = len(Te[:,0,0,0]) - -Te_left = [] -Ti_left = [] -for i in range(end_index): - Te_left.append(old_div((Te[i,0,2,0]+Te[i,0,3,0]),2)) - Ti_left.append(old_div((Ti[i,0,2,0]+Ti[i,0,3,0]),2)) - -# Make plot -if len(argv)>2: - pyplot.semilogx(Te_left[:end_index],'r',Ti_left[:end_index],'b') - pyplot.title("Te (red) and Ti (blue) at the (left) boundary") - pyplot.axes().xaxis.set_major_formatter(ticker.FormatStrFormatter("%g")) - pyplot.axes().grid(color='grey', which='both') -else: - pyplot.semilogx(Te_left[:],'r',Ti_left[:],'b') - pyplot.title("Te (red) and Ti (blue) at the (left) boundary") - pyplot.axes().xaxis.set_major_formatter(ticker.FormatStrFormatter(r"$%g$")) - pyplot.axes().grid(color='grey', which='both') - -pyplot.show() diff --git a/examples/non-local_1d/analysen b/examples/non-local_1d/analysen deleted file mode 100755 index 7a3e5bceb0..0000000000 --- a/examples/non-local_1d/analysen +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function -from builtins import str -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv - -if len(argv)==1: - end_index = -1 - data_path = "data" -elif len(argv)==2: - try: - end_index = int(argv[1]) - data_path = "data" - except ValueError: - end_index = -1 - data_path = str(argv[1]) -elif len(argv)==3: - end_index = int(argv[1]) - data_path = str(argv[2]) -else: - print("Arguments: [end_index][data_path] or [data_path]") - Exit(1) - -# Collect the data -n = collect("n_ion", path=data_path, xind=2, info=True, yguards=True) - -if end_index<0: - end_index = len(n[:,0,0,0]) - -# n has dimensions [Time, X, Y, Z] -# Make contour plot -if len(argv)>1: - plotdata(n[:end_index,0,:,0],title="n") -else: - plotdata(n[:,0,:,0],title="n") - -#print(n[204,:,:,:]) diff --git a/examples/non-local_1d/analyseq b/examples/non-local_1d/analyseq deleted file mode 100755 index 68d91fc57c..0000000000 --- a/examples/non-local_1d/analyseq +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function -from builtins import str -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv - -if len(argv)==1: - end_index = -1 - data_path = "data" -elif len(argv)==2: - try: - end_index = int(argv[1]) - data_path = "data" - except ValueError: - end_index = -1 - data_path = str(argv[1]) -elif len(argv)==3: - end_index = int(argv[1]) - data_path = str(argv[2]) -else: - print("Arguments: [end_index][data_path] or [data_path]") - Exit(1) - -# Collect the data -q = collect("heat_flux", path="data", xind=2, info=True, yguards=True) - -if end_index<0: - end_index = len(q[:,0,0,0]) - -# q has dimensions [Time, X, Y, Z] -# Make contour plot -if len(argv)>1: - plotdata(q[:end_index,0,:,0],title="q") -else: - plotdata(q[:,0,:,0],title="q") diff --git a/examples/non-local_1d/analyser b/examples/non-local_1d/analyser deleted file mode 100755 index ec36aeaa8c..0000000000 --- a/examples/non-local_1d/analyser +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python - -#NOTE: THIS FILE WAS NOT COMPLETED WHEN PORTING TO PYTHON 3 - -from __future__ import print_function -from builtins import str -from builtins import range -from boututils.run_wrapper import shell, launch -from boutdata.plotdata import plotdata -from boutdata.collect import collect -import numpy as np -from sys import argv -from math import log10 - -maxval = -1 -end_index = -1 -data_path = "data" - -if len(argv)==1: - print("len(argv)==1...was something supposed to happen???") -elif len(argv)==2: - try: - end_index = int(argv[1]) - except ValueError: - data_path = str(argv[1]) -elif len(argv)==3: - try: - end_index = int(argv[1]) - data_path = str(argv[2]) - except ValueError: - data_path = str(argv[1]) - maxval = float(argv[2]) -elif len(argv)==4: - end_index = int(argv[1]) - data_path = str(argv[2]) - maxval = float(argv[3]) -else: - raise RuntimeError("Arguments: [end_index][data_path] or [data_path]") - -# Collect the data -r = collect("local_non-local_ratio", path="data", xind=2, info=True, yguards=True) - -if end_index<0: - end_index = len(r[:,0,0,0]) - -# Te has dimensions [Time, X, Y, Z] -# Make contour plot -if maxval>0: - for i in range(len(r[:end_index,0,0,0])): - for j in range(2,len(r[0,0,:,0])-2): - #print(r[i,0,j,0]) - #print(r[i,0,j,0]) - if r[i,0,j,0]>0: - r[i,0,j,0]=min((r[i,0,j,0]),maxval) - else: - r[i,0,j,0]=0 - -plotdata(r[:end_index,0,2:-2,0]) diff --git a/examples/non-local_1d/conduct_grid.nc b/examples/non-local_1d/conduct_grid.nc deleted file mode 100644 index 5714fba67bc797085d7982d07f2c3047fdfa3b65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21352 zcmeI&u};G<5P;z{0g8Z;2k_7ViKVuHp$n0U5TZj7Ft9 z`txK|CS!B`l$hZ|Y3z})2R(b(b6w-Q)|vaIInSq=89wIaC`TYS4|)5V*G?Bj zGApc1zqR@|T{Uw2_coJOId}1HwH(jtv2*DsF(dmRJ3t+99`qnk2h;&|z&XGH9KZn_ zzyTb<0UW>q9KZn_zyTb<0UW>q9KZn_zyTb<0UW>q9KZn_zyTb(^b diff --git a/examples/non-local_1d/cubic_spline_local.cxx b/examples/non-local_1d/cubic_spline_local.cxx deleted file mode 100644 index cc4dac9ac3..0000000000 --- a/examples/non-local_1d/cubic_spline_local.cxx +++ /dev/null @@ -1,126 +0,0 @@ -/************************************************************************** - * Calculate the coefficients for a 1d cubic spline interpolation (in index space) - * by using the 4th order derivatives at the points - * - ************************************************************************** - * Copyright 2012 J.T.Omotani - * - * Contact: John Omotani, john.omotani@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - **************************************************************************/ - -#include -#include - -#include "cubic_spline_local.hxx" - -CubicSpline::CubicSpline() { -} - -CubicSpline::~CubicSpline() { - delete [] coeffs; -} - -void CubicSpline::initialise(const char &inputdirection, const bool pass_include_boundary_guard_cells, const bool pass_upper_boundary_offset) { - direction = inputdirection; - if (direction == 'y'){ - - } - else throw BoutException("CubicSpline: direction is not valid"); - include_boundary_guard_cells = pass_include_boundary_guard_cells; - upper_boundary_offset=pass_upper_boundary_offset; - coeffs = new BoutReal[4]; - for (int i=0; i<4; i++) coeffs[i] = 1./0.; -} - -void CubicSpline::initialise(const CubicSpline &clone_from) { - direction = clone_from.direction; - include_boundary_guard_cells = clone_from.include_boundary_guard_cells; - upper_boundary_offset = clone_from.upper_boundary_offset; - coeffs = new BoutReal[4]; - for (int i=0; i<4; i++) coeffs[i] = NAN; -} - -void CubicSpline::calculate(const Field3D &pass_input) { - if (direction=='y') { - input = pass_input; - if (!include_boundary_guard_cells) { - for (RangeIterator rlow = mesh->iterateBndryLowerY(); !rlow.isDone(); rlow++) - for (int jz=0; jzLocalNz; jz++) - for (int jy=mesh->ystart-1; jy>=0; jy--) - input(rlow.ind,jy,jz) = 0.; - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) -// for (int jy=mesh->yend+1-staggered; jyLocalNy; jy++) - for (int jy=mesh->yend+1-upper_boundary_offset; jyLocalNy; jy++) - input(rup.ind,jy,jz) = 0.; - - grad_input = mesh->indexDDY(input,input.getLocation(), DIFF_DEFAULT); // derivative in index space - - // values of grad_input that depended on the guard cells are wrong, replace them with forward/backward derivatives - for (RangeIterator rlow = mesh->iterateBndryLowerY(); !rlow.isDone(); rlow++) - for (int jz=0; jzLocalNz; jz++) - for (int jy=mesh->ystart+1; jy>=0; jy--) { - grad_input(rlow.ind,jy,jz) = (-11.*input(rlow.ind,jy,jz) + 18.*input(rlow.ind,jy+1,jz) - 9.*input(rlow.ind,jy+2,jz) + 2.*input(rlow.ind,jy+3,jz)) / 6.; - } - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) -// for (int jy=mesh->yend-1-staggered; jyLocalNy; jy++) { - for (int jy=mesh->yend-1-upper_boundary_offset; jyLocalNy; jy++) { - grad_input(rup.ind,jy,jz) = (11.*input(rup.ind,jy,jz) - 18.*input(rup.ind,jy-1,jz) + 9.*input(rup.ind,jy-2,jz) - 2.*input(rup.ind,jy-3,jz)) / 6.; - } - } - else { - grad_input = mesh->indexDDY(input,input.getLocation(), DIFF_DEFAULT); // derivative in index space - - // May need values in the guard cells as well, calculate with forward/backward derivatives - for (RangeIterator rlow = mesh->iterateBndryLowerY(); !rlow.isDone(); rlow++) - for (int jz=0; jzLocalNz; jz++) - for (int jy=mesh->ystart-1; jy>=0; jy--) { - grad_input(rlow.ind,jy,jz) = (-11.*input(rlow.ind,jy,jz) + 18.*input(rlow.ind,jy+1,jz) - 9.*input(rlow.ind,jy+2,jz) + 2.*input(rlow.ind,jy+3,jz)) / 6.; - } - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) -// for (int jy=mesh->yend+1-staggered; jyLocalNy; jy++) { - for (int jy=mesh->yend+1-upper_boundary_offset; jyLocalNy; jy++) { - grad_input(rup.ind,jy,jz) = (11.*input(rup.ind,jy,jz) - 18.*input(rup.ind,jy-1,jz) + 9.*input(rup.ind,jy-2,jz) - 2.*input(rup.ind,jy-3,jz)) / 6.; - } - } - mesh->communicate(grad_input); - } -} - -BoutReal* CubicSpline::coefficients (bindex* position) { - coeffs[0] = input(position->jx,position->jy,position->jz); - coeffs[1] = grad_input(position->jx,position->jy,position->jz); - coeffs[2] = 3.*(input(position->jx,position->jyp,position->jz)-input(position->jx,position->jy,position->jz)) - - 2.*grad_input(position->jx,position->jy,position->jz) - grad_input(position->jx,position->jyp,position->jz); - coeffs[3] = 2.*(input(position->jx,position->jy,position->jz)-input(position->jx,position->jyp,position->jz)) - + grad_input(position->jx,position->jy,position->jz) + grad_input(position->jx,position->jyp,position->jz); - return coeffs; -} - -BoutReal* CubicSpline::coefficients (const int &jx, const int &jy, const int &jz) { - coeffs[0] = input(jx,jy,jz); - coeffs[1] = grad_input(jx,jy,jz); - coeffs[2] = 3.*(input(jx,jy+1,jz)-input(jx,jy,jz)) - - 2.*grad_input(jx,jy,jz) - grad_input(jx,jy+1,jz); - coeffs[3] = 2.*(input(jx,jy,jz)-input(jx,jy+1,jz)) - + grad_input(jx,jy,jz) + grad_input(jx,jy+1,jz); - return coeffs; -} diff --git a/examples/non-local_1d/cubic_spline_local.hxx b/examples/non-local_1d/cubic_spline_local.hxx deleted file mode 100644 index f73baa7c1e..0000000000 --- a/examples/non-local_1d/cubic_spline_local.hxx +++ /dev/null @@ -1,59 +0,0 @@ -/************************************************************************** - * Calculate the coefficients for a 1d cubic spline interpolation - * by using the 4th order derivatives at the points - * - ************************************************************************** - * Copyright 2012 J.T.Omotani - * - * Contact: John Omotani, john.omotani@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - **************************************************************************/ - -#ifndef __CUBICSPLINE_H__ -#define __CUBICSPLINE_H__ - -#include -#include -#include -#include -#include - -struct bindex{ - int jx, jy, jz; -}; - -class CubicSpline { -public: - CubicSpline(); - ~CubicSpline(); - void initialise(const char &direction, const bool pass_include_boundary_guard_cells=true, const bool pass_staggered=false); - void initialise(const CubicSpline &clone_from); - void calculate(const Field3D &pass_input); - BoutReal * coefficients(bindex* position); - BoutReal * coefficients(const int &jx, const int &jy, const int &jz); - -private: - char direction; - bool include_boundary_guard_cells; - bool upper_boundary_offset; - Field3D input; - Field3D grad_input; - BoutReal * coeffs; -}; - -#endif // __CUBICSPLINE_H__ diff --git a/examples/non-local_1d/data/BOUT.inp b/examples/non-local_1d/data/BOUT.inp deleted file mode 100644 index b02427a85c..0000000000 --- a/examples/non-local_1d/data/BOUT.inp +++ /dev/null @@ -1,189 +0,0 @@ -# -# Input file for conduction case -# - -nout = 1002 # Number of output timesteps -timestep = 1.0e-5 # Time between outputs - -#MZ = 1 # Number of points in z -MZ = 1 - -dump_format="nc" # Write NetCDF format files - -grid="conduct_grid.nc" - -StaggerGrids = true - -################################################## -[mesh] - -type = bout - -################################################## -[mesh:ddy] # Methods used for parallel (y) derivative terms - -first = C4 -second = C4 -upwind = W3 -flux = U1 - -################################################## -[solver] # Solver settings - -# CVODE # -type = cvode # Which solver to use - -max_timestep = 4.0e-7 -start_timestep = 1.e-9 -mxstep = 2000 - -#atol = 1.0e-10 # absolute tolerance -#rtol = 1.0e-5 # relative tolerance -atol = 1.0e-10 # absolute tolerance -rtol = 1.0e-7 # relative tolerance -use_vector_abstol=true - -################################################## -[output] # Output settings -#low_prec = false -floats = false - -################################################## -[non_local_parallel] # Settings for the non-local model -moments_number = 10 -#NONLOCAL_PARALLEL__TAGBASE = 12381 -#NONLOCAL_PARALLEL_INTEGRATION_TAGBASE = 16381 - -################################################## -[sources] # Settings for the sources - -# the sources have a sine envelope around the centre of the domain, extending until it first reaches zero at +/- source_extent/2. -# the base amplitude is increased between on_time and off_time to *_amplitude + *_transient_amplitude -sources.source_length = 25. # in m - -# 40eV, 1e19m^-3 -#sources.particle_amplitude = 2.97190780803271e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 1.78314468481962e24 # in eV/m^3/s -#sources.ion_heat_amplitude = 1.78314468481962e24 # in eV/m^3/s - -# 100eV, 0.5e19m^-3 -#sources.particle_amplitude = 2.349499417355458e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 3.5242491260331873e24 # in eV/m^3/s -#sources.ion_heat_amplitude = 3.5242491260331873e24 # in eV/m^3/s - -# 100eV, 1e19m^-3 -#sources.particle_amplitude = 4.69899883471091617650831789566e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 7.0484982520663742647624768435e24 # in eV/m^3/s -#sources.ion_heat_amplitude = 7.0484982520663742647624768435e24 # in eV/m^3/s - -# 140eV, 1e19m^-3 -#sources.particle_amplitude = 5.5599304013683811018381815397e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 1.16758538428736003138601812334e25 # in eV/m^3/s -#sources.ion_heat_amplitude = 1.16758538428736003138601812334e25 # in eV/m^3/s - -# 200eV, 1e19m^-3 -#sources.particle_amplitude = 6.6453878816235472058187966917e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 1.99361636448706416174563900752e25 # in eV/m^3/s -#sources.ion_heat_amplitude = 1.99361636448706416174563900752e25 # in eV/m^3/s - -# 250eV, 1e19m^-3 -sources.particle_amplitude = 7.4297695200817885339785368656e22 # in m^-3 s^-1 -sources.electron_heat_amplitude = 2.78616357003067070024195132459e25 # in eV/m^3/s -#sources.electron_heat_amplitude = 7.e25 # in eV/m^3/s -sources.ion_heat_amplitude = 2.78616357003067070024195132459e25 # in eV/m^3/s - -# 300eV, 1e19m^-3 -#sources.particle_amplitude = 8.1389047264262557146095566295e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 3.6625071268918150715743004833e25 # in eV/m^3/s -#sources.ion_heat_amplitude = 3.6625071268918150715743004833e25 # in eV/m^3/s - -# 200eV, 1e17m^-3 -#sources.particle_amplitude = 6.6453878816235472058187966917e20 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 1.99361636448706416174563900752e23 # in eV/m^3/s -#sources.ion_heat_amplitude = 1.99361636448706416174563900752e23 # in eV/m^3/s - -sources.on_time = 0#2e-6 # in s -sources.off_time = -200e-6#0202.e-6 # in s - -# 500eV, 2e19m^-3 -#sources.particle_transient_amplitude = 2.10145616412118138312975179139e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 1.57609212309088603734731384354e26 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 1.57609212309088603734731384354e26 # in eV/m^3/s - -# 750eV, 5e19m^-3 -#sources.particle_transient_amplitude = 6.434369148654145856198856725e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 7.2386652922359140882237138157e26 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 7.2386652922359140882237138157e26 # in eV/m^3/s - -# 1000eV, 5e19m^-3 -#sources.particle_transient_amplitude = 7.4297695200817885339785368656e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 1.11446542801226828009678052983e27 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 1.11446542801226828009678052983e27 # in eV/m^3/s - -# 1200eV, 5e19m^-3 -#sources.particle_transient_amplitude = 8.1389047264262557146095566295e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 1.46500285075672602862972019332e27 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 1.46500285075672602862972019332e27 # in eV/m^3/s - -# 1500eV, 5e19m^-3 -sources.particle_transient_amplitude = 9.09957211534171e23 # in m^-3 s^-1 -sources.electron_heat_transient_amplitude = 2.04740372595188e27 # in eV/m^3/s -sources.ion_heat_transient_amplitude = 2.04740372595188e27 # in eV/m^3/s - -# 1500eV, 5e19m^-3, 3:1 ion:electron split -#sources.particle_transient_amplitude = 9.09957211534171e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 1.02370186297594331874986893053e27 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 3.07110558892782995624960679159e27 # in eV/m^3/s - -# 1500eV, 1.5e19m^-3 -#sources.particle_transient_amplitude = 2.729871634602515e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 6.142211177855659e26 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 6.142211177855659e26 # in eV/m^3/s - -################################################## -[all] # Settings for all variables - -scale=1.0 -bndry_target = none -#bndry_target = neumann - -################################################## -[Vpar_ion] # Settings for the Vpar_ion variable - -atol = 1.0e-6 - -#function = 0. -#function = 107000.*(y-pi+pi/256)/pi # 0 # -cos(y/2)*sqrt((2*10.)/(3.34358348e-27/1.602176565e-19)) -function = 107000.*(y-pi)/pi # 0 - -################################################## -[j_parallel] # Settings for the j_parallel variable - -atol = 1.0e-6 - -#function = 0. -function = 1.e6*sin(13*y) -bndry_target = neumann - -################################################## -[T_electron] # Settings for the T_electron variable - -atol = 1.0e-10 - -#function = (1.0 + 1.0*gauss(y-pi, (2*pi/10)))*1.0e-19/1.0e-20 # The form of the initial perturbation. y from 0 to 2*pi, in J/energyunit -function = (100.0 + 0.0*gauss(y-pi+pi/256, (2*pi/10))) # The form of the initial perturbation. y from 0 to 2*pi, in eV -#function = (30.0 + 10.*cos((y-pi+pi/128))) # The form of the initial perturbation. y from 0 to 2*pi, in eV - -################################################## -[n_ion] # Settings for the n_ion variable - -atol = 1.0e9 - -function = 1.e19*(1. + 0.*gauss(y-pi)) - -################################################## -[T_ion] # Settings for the T_ion variable - -atol = 1.0e-10 - -function = (150.0 + 0.0*gauss(y-pi, (2*pi/10))) # The form of the initial perturbation. y from 0 to 2*pi, in eV diff --git a/examples/non-local_1d/generate.py b/examples/non-local_1d/generate.py deleted file mode 100755 index 5402034d57..0000000000 --- a/examples/non-local_1d/generate.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python - -# -# Generate an input mesh -# - -from __future__ import division -from past.utils import old_div -from boututils.datafile import DataFile # Wrapper around NetCDF4 libraries -from math import pow -from sys import argv - -length = 80. # Length of the domain in m - -nx = 5 # Minimum is 5: 2 boundary, one evolved -if len(argv)>1: - ny = int(argv[1]) # Minimum 5. Should be divisible by number of processors (so powers of 2 nice) -else: - ny = 256 # Minimum 5. Should be divisible by number of processors (so powers of 2 nice) -#dy = [[1.]*ny]*nx # distance between points in y, in m/g22/lengthunit -g22 = [[pow(old_div(float(ny-1),length),2)]*ny]*nx -g_22 = [[pow(old_div(length,float(ny-1)),2)]*ny]*nx -ixseps1 = -1 -ixseps2 = 0 - -f = DataFile() -f.open("conduct_grid.nc", create=True) - -f.write("nx", nx) -f.write("ny", ny) -#f.write("dy", dy) -f.write("g22",g22) -f.write("g_22", g_22) -f.write("ixseps1", ixseps1) -f.write("ixseps2", ixseps2) - -f.close() diff --git a/examples/non-local_1d/heat_flux_integration.cxx b/examples/non-local_1d/heat_flux_integration.cxx deleted file mode 100644 index 6efc5e65bb..0000000000 --- a/examples/non-local_1d/heat_flux_integration.cxx +++ /dev/null @@ -1,576 +0,0 @@ -/*! - * \file heat_flux_integration.cxx - * - * \brief Perform the integral needed to calculate the non-local heat flux - * - * - ************************************************************************** - * Copyright 2012 J.T.Omotani - * - * Contact: John Omotani, john.omotani@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - */ - -#include "heat_flux_integration.hxx" - -/********************************************************************************** - * INTEGRATION INITIALISATION AND CREATION - **********************************************************************************/ - -HeatFluxIntegration::HeatFluxIntegration() { - position = new bindex; - deltal = new BoutReal; - integral_coeffs = new BoutReal[4]; - integral_parts = new BoutReal[4]; - } - -HeatFluxIntegration::~HeatFluxIntegration() { - delete position; - delete deltal; - delete [] integral_coeffs; - delete [] integral_parts; -} - -void HeatFluxIntegration::initialise(const bool pass_electron_heat_flux_location_is_ylow=false) { - electron_heat_flux_location_is_ylow = pass_electron_heat_flux_location_is_ylow; - - if (electron_heat_flux_location_is_ylow) { - integral_below.setLocation(CELL_YLOW); - integral_above.setLocation(CELL_YLOW); - } - - *deltal = 0.; - for (int i=0; i<4; i++) { - integral_coeffs[i]=0.; - integral_parts[i]=0.; - } - integral_below = 0.0; - integral_above = 0.0; - - // Get the options for the model - Options *options = Options::getRoot()->getSection("electron_heat_flux"); - OPTION(options, HEATFLUX_INTEGRATION_TAGBASE, 16381); -} - - -/********************************************************************************** - * INTEGRATION ROUTINES - **********************************************************************************/ - -void HeatFluxIntegration::calculateIntegralBelow_cell_centre(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, const int &counter) { - TRACE("HeatFluxIntegration::calculateIntegralBelow()"); - - start_index(position); - do { - position->jy=mesh->ystart-1; - calc_index(position); - if (mesh->firstY()) - next_index_y(position); - else { - // Set the value at ystart-1 equal to the value at yend on the previous processor. - if (position->jxDownXSplitIndex()) { - mesh->wait(mesh->irecvYInIndest(&integral_below[*position],1,HEATFLUX_INTEGRATION_TAGBASE + mesh->DownXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz)); - } - else { - mesh->wait(mesh->irecvYInOutdest(&integral_below[*position],1,HEATFLUX_INTEGRATION_TAGBASE + (mesh->LocalNx-mesh->DownXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->DownXSplitIndex()) + position->jz)); - } - } - do { - *deltal = mesh->dy[position->jx][position->jyp]*sqrt((mesh->g_22[position->jx][position->jy]+mesh->g_22[position->jx][position->jyp])/2.); - - interp_coeffs_drive_term = cubic_spline_drive_term.coefficients(position); - interp_coeffs_lambdaC_inverse = cubic_spline_inverse_lambdaC.coefficients(position); - - //calculate the coefficients of drive_term expanded in z rather than l (from the expansion of drive_term in l and l in z [inverted from z in l to third order]) - integral_coeffs[0] = interp_coeffs_drive_term[0]; - integral_coeffs[1] = interp_coeffs_drive_term[1] / *deltal/interp_coeffs_lambdaC_inverse[0]; - integral_coeffs[2] = interp_coeffs_drive_term[2] / pow(*deltal*interp_coeffs_lambdaC_inverse[0],2) - - interp_coeffs_drive_term[1] * interp_coeffs_lambdaC_inverse[1]/2./pow(*deltal,2)/pow(interp_coeffs_lambdaC_inverse[0],3); - integral_coeffs[3] = interp_coeffs_drive_term[3] / pow(*deltal*interp_coeffs_lambdaC_inverse[0],3) - - interp_coeffs_drive_term[2] * interp_coeffs_lambdaC_inverse[1]/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4) - + interp_coeffs_drive_term[1] * (0.5*pow(interp_coeffs_lambdaC_inverse[1],2)/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],5) - interp_coeffs_lambdaC_inverse[2]/3./pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4)); - - // Calculate analytically the integral from jy to jyp of z^n*exp( (zupper-z)/zeta ), firstly allowing for zeta to be large and secondly allowing for it to be small. - BoutReal exp_delta_over_eigenvalue = exp(dimensionless_length_deltas_above[*position]/eigenvalue); - if (dimensionless_length_deltas_above[*position]>abs(eigenvalue)) { - integral_parts[0] = eigenvalue * (exp_delta_over_eigenvalue-1); - integral_parts[1] = pow(eigenvalue,2) * (exp_delta_over_eigenvalue-1) - - eigenvalue * dimensionless_length_deltas_above[*position]; - integral_parts[2] = 2*pow(eigenvalue,3) * (exp_delta_over_eigenvalue-1) - - 2*pow(eigenvalue,2) * dimensionless_length_deltas_above[*position] - eigenvalue * pow(dimensionless_length_deltas_above[*position],2); - integral_parts[3] = 6*pow(eigenvalue,4) * (exp_delta_over_eigenvalue-1) - - 6*pow(eigenvalue,3) * dimensionless_length_deltas_above[*position] - 3*pow(eigenvalue,2) * pow(dimensionless_length_deltas_above[*position],2) - eigenvalue * pow(dimensionless_length_deltas_above[*position],3); - } - else { - BoutReal exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue = exp(dimensionless_length_deltas_above[*position]/eigenvalue/2.) * 2.*sinh(dimensionless_length_deltas_above[*position]/eigenvalue/2.); - integral_parts[0] = eigenvalue * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue; - integral_parts[1] = pow(eigenvalue,2) * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - eigenvalue* dimensionless_length_deltas_above[*position]; - integral_parts[2] = 2*pow(eigenvalue,3) * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - 2*pow(eigenvalue,2) * dimensionless_length_deltas_above[*position] - eigenvalue * pow(dimensionless_length_deltas_above[*position],2); - integral_parts[3] = 6*pow(eigenvalue,4) * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - 6*pow(eigenvalue,3) * dimensionless_length_deltas_above[*position] - 3*pow(eigenvalue,2) * pow(dimensionless_length_deltas_above[*position],2) - eigenvalue * pow(dimensionless_length_deltas_above[*position],3); - } - - //add up the contributions to the integral at jy first from the integral at jy-1 and then from the expansion of the integral between jy-1 and jy - integral_below[position->jx][position->jyp][position->jz] = integral_below[*position] * exp_delta_over_eigenvalue; - for (int i=0; i<4; i++) integral_below[position->jx][position->jyp][position->jz] += integral_coeffs[i]*integral_parts[i]; - - next_index_y(position); - } while (position->jy < mesh->yend); - - // Send the value at yend to the next processor. - if (position->jx < mesh->UpXSplitIndex()) { - Timer timer("comms"); - mesh->sendYOutIndest(&integral_below[*position],1,HEATFLUX_INTEGRATION_TAGBASE + mesh->UpXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz); - } - else { - Timer timer("comms"); - mesh->sendYOutOutdest(&integral_below[*position],1,HEATFLUX_INTEGRATION_TAGBASE + (mesh->LocalNx-mesh->UpXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->UpXSplitIndex()) + position->jz); - } - - } while (next_indexperp(position)); -} - -void HeatFluxIntegration::calculateIntegralAbove_cell_centre(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, const int &counter) { - TRACE("HeatFluxIntegration::calculateIntegralAbove()"); - - start_index_lasty(position); - do { - position->jy=mesh->yend; - calc_index(position); - if (mesh->lastY()) - previous_index_y(position); - else { - // Set the value at yend+1 to the value at ystart on the previous processor. - if (position->jxUpXSplitIndex()) { - mesh->wait(mesh->irecvYOutIndest(&integral_above[position->jx][position->jyp][position->jz],1,HEATFLUX_INTEGRATION_TAGBASE + mesh->UpXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz)); - } - else { - mesh->wait(mesh->irecvYOutOutdest(&integral_above[position->jx][position->jyp][position->jz],1,HEATFLUX_INTEGRATION_TAGBASE + (mesh->LocalNx - mesh->UpXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->UpXSplitIndex()) + position->jz)); - } - } - do { - *deltal = mesh->dy[position->jx][position->jy]*sqrt((mesh->g_22[position->jx][position->jy]+mesh->g_22[position->jx][position->jyp])/2.); - - interp_coeffs_drive_term = cubic_spline_drive_term.coefficients(position); - interp_coeffs_lambdaC_inverse = cubic_spline_inverse_lambdaC.coefficients(position); - - //calculate the coefficients of drive_term expanded in z rather than l (from the expansion of drive_term in l and l in z [inverted from z in l to third order]) - integral_coeffs[0] = interp_coeffs_drive_term[0]; - integral_coeffs[1] = interp_coeffs_drive_term[1] / *deltal/interp_coeffs_lambdaC_inverse[0]; - integral_coeffs[2] = interp_coeffs_drive_term[2] / pow(*deltal*interp_coeffs_lambdaC_inverse[0],2) - - interp_coeffs_drive_term[1] * interp_coeffs_lambdaC_inverse[1]/2./pow(*deltal,2)/pow(interp_coeffs_lambdaC_inverse[0],3); - integral_coeffs[3] = interp_coeffs_drive_term[3] / pow(*deltal*interp_coeffs_lambdaC_inverse[0],3) - - interp_coeffs_drive_term[2] * interp_coeffs_lambdaC_inverse[1]/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4) - + interp_coeffs_drive_term[1] * (0.5*pow(interp_coeffs_lambdaC_inverse[1],2)/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],5) - interp_coeffs_lambdaC_inverse[2]/3./pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4)); - - // Calculate analytically the integral from jyp to jy of z^n*exp( (zupper-z)/zeta ), firstly allowing for zeta to be large and secondly allowing for it to be small. - BoutReal exp_delta_over_eigenvalue = exp(dimensionless_length_deltas_above[*position]/eigenvalue); - if (dimensionless_length_deltas_above[*position]>abs(eigenvalue)) { - integral_parts[0] = -eigenvalue * (exp_delta_over_eigenvalue-1); - integral_parts[1] = pow(eigenvalue,2) * (exp_delta_over_eigenvalue-1) - - eigenvalue* dimensionless_length_deltas_above[*position] * exp_delta_over_eigenvalue; - integral_parts[2] = -2*pow(eigenvalue,3) * (exp_delta_over_eigenvalue-1) - + 2*pow(eigenvalue,2) * dimensionless_length_deltas_above[*position] * exp_delta_over_eigenvalue - - eigenvalue * pow(dimensionless_length_deltas_above[*position],2) * exp_delta_over_eigenvalue; - integral_parts[3] = 6*pow(eigenvalue,4) * (exp_delta_over_eigenvalue-1) - - 6*pow(eigenvalue,3) * dimensionless_length_deltas_above[*position] * exp_delta_over_eigenvalue - + 3*pow(eigenvalue,2) * pow(dimensionless_length_deltas_above[*position],2) * exp_delta_over_eigenvalue - - eigenvalue * pow(dimensionless_length_deltas_above[*position],3) * exp_delta_over_eigenvalue; - } - else { - BoutReal exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue = exp(dimensionless_length_deltas_above[*position]/eigenvalue/2.) * 2.*sinh(dimensionless_length_deltas_above[*position]/eigenvalue/2.); - integral_parts[0] = -eigenvalue * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue; - integral_parts[1] = pow(eigenvalue,2) * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - eigenvalue* dimensionless_length_deltas_above[*position] * exp_delta_over_eigenvalue; - integral_parts[2] = -2*pow(eigenvalue,3) * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + 2*pow(eigenvalue,2) * dimensionless_length_deltas_above[*position] * exp_delta_over_eigenvalue - - eigenvalue * pow(dimensionless_length_deltas_above[*position],2) * exp_delta_over_eigenvalue; - integral_parts[3] = 6*pow(eigenvalue,4) * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - 6*pow(eigenvalue,3) * dimensionless_length_deltas_above[*position] * exp_delta_over_eigenvalue - + 3*pow(eigenvalue,2) * pow(dimensionless_length_deltas_above[*position],2) * exp_delta_over_eigenvalue - - eigenvalue * pow(dimensionless_length_deltas_above[*position],3) * exp_delta_over_eigenvalue; - } - - //add up the contributions to the integral at jy first from the integral at jy-1 and then from the expansion of the integral between jy-1 and jy - integral_above[*position] = integral_above[position->jx][position->jyp][position->jz] * exp_delta_over_eigenvalue; - for (int i=0; i<4; i++) integral_above[*position] += integral_coeffs[i]*integral_parts[i]; - - } while (previous_index_y(position)); - - // Send the value at ystart to the next processor. - if (position->jx < mesh->DownXSplitIndex()) { - Timer timer("comms"); - mesh->sendYInIndest(&integral_above[*position],1,HEATFLUX_INTEGRATION_TAGBASE + mesh->DownXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz); - } - else { - Timer timer("comms"); - mesh->sendYInOutdest(&integral_above[*position],1,HEATFLUX_INTEGRATION_TAGBASE + (mesh->LocalNx - mesh->DownXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->DownXSplitIndex()) + position->jz); - } - - } while (next_indexperp(position)); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void HeatFluxIntegration::calculateIntegralBelow_cell_ylow(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_below, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, CubicSpline &cubic_spline_gradT, const int &counter) { - TRACE("HeatFluxIntegration::calculateIntegralBelow()"); - - start_index(position); - do { - position->jy=mesh->ystart; - calc_index(position); - if (!mesh->firstY()) { - // Set the value at ystart to the value at yend+1 of the previous processor. - if (position->jxDownXSplitIndex()) { - mesh->wait(mesh->irecvYInIndest(&integral_below[*position],1,HEATFLUX_INTEGRATION_TAGBASE + mesh->DownXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz)); - } - else { - mesh->wait(mesh->irecvYInOutdest(&integral_below[*position],1,HEATFLUX_INTEGRATION_TAGBASE + (mesh->LocalNx-mesh->DownXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->DownXSplitIndex()) + position->jz)); - } - } - do { - *deltal = mesh->dy[position->jx][position->jy]*sqrt(mesh->g_22[position->jx][position->jy]); - - BoutReal deltazbelow = dimensionless_length_deltas_below[*position]; - BoutReal deltazabove = dimensionless_length_deltas_above[*position]; - BoutReal deltaz = dimensionless_length_deltas_below[*position] + dimensionless_length_deltas_above[*position]; - - interp_coeffs_gradT = cubic_spline_gradT.coefficients(position); - - // Contribution to the integral at jy from points up to jy-1 - integral_below[position->jx][position->jyp][position->jz] = integral_below[*position] * exp(deltaz/eigenvalue); - - // Calculate the contribution from the lower part of the interval (below CELL_CENTRE) - // The integration variable ('z-prime') goes from (dimensionless_length_deltas_above[jy-1]) to (dimensionless_length_deltas_above[jy-1]+dimensionless_length_deltas_below[jy]) with the final z-value (that goes into the exponential) being (dimensionless_length_deltas_above[jy-1]+dimensionless_length_deltas_below[jy]+dimensionless_length_deltas_above[jy]) - BoutReal deltazabovefromjym = dimensionless_length_deltas_above[position->jx][position->jym][position->jz]; - interp_coeffs_drive_term = cubic_spline_drive_term.coefficients(position->jx,position->jym,position->jz); - interp_coeffs_lambdaC_inverse = cubic_spline_inverse_lambdaC.coefficients(position->jx,position->jym,position->jz); - - BoutReal integrand_coefficient0 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient1 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient2 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient3 = interp_coeffs_drive_term[0]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient4 = interp_coeffs_drive_term[1]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient5 = interp_coeffs_drive_term[2]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient6 = interp_coeffs_drive_term[3]*interp_coeffs_gradT[3]; - - // Approximate the sixth order polynomial by the least-squares-fit cubic between t=1/2 and t=1 - BoutReal cubic_integrand_coefficient0 = integrand_coefficient0 - 321./1120.*integrand_coefficient4 - 97./112.*integrand_coefficient5 - 2225./1344.*integrand_coefficient6; - BoutReal cubic_integrand_coefficient1 = integrand_coefficient1 + 45./28.*integrand_coefficient4 + 3065./672.*integrand_coefficient5 + 939./112.*integrand_coefficient6; - BoutReal cubic_integrand_coefficient2 = integrand_coefficient2 - 93./28.*integrand_coefficient4 - 235./28.*integrand_coefficient5 - 3245./224.*integrand_coefficient6; - BoutReal cubic_integrand_coefficient3 = integrand_coefficient3 + 3.*integrand_coefficient4 + 205./36.*integrand_coefficient5 + 35./4.*integrand_coefficient6; - - //calculate the coefficients of the integrand expanded in z rather than l (from the expansion of drive_term in l and l in z [inverted from z in l to third order]) - integral_coeffs[0] = cubic_integrand_coefficient0; - integral_coeffs[1] = cubic_integrand_coefficient1 / *deltal/interp_coeffs_lambdaC_inverse[0]; - integral_coeffs[2] = cubic_integrand_coefficient2 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],2) - - cubic_integrand_coefficient1 * interp_coeffs_lambdaC_inverse[1]/2./pow(*deltal,2)/pow(interp_coeffs_lambdaC_inverse[0],3); - integral_coeffs[3] = cubic_integrand_coefficient3 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],3) - - cubic_integrand_coefficient2 * interp_coeffs_lambdaC_inverse[1]/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4) - + cubic_integrand_coefficient1 * (0.5*pow(interp_coeffs_lambdaC_inverse[1],2)/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],5) - interp_coeffs_lambdaC_inverse[2]/3./pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4)); - - // Calculate analytically the integral from jy-1/2 to jy of z^n*exp( (deltaz+dimensionless_length_deltas_above[jy-1]-z)/zeta ), firstly allowing for zeta to be large and secondly allowing for it to be small. - BoutReal exp_deltaabove_over_eigenvalue = exp(deltazabove/eigenvalue); - if (deltazbelow>abs(eigenvalue)) { - BoutReal exp_deltabelow_over_eigenvalue = exp(deltazbelow/eigenvalue); - integral_parts[0] = exp_deltaabove_over_eigenvalue * eigenvalue * (exp_deltabelow_over_eigenvalue-1); - integral_parts[1] = exp_deltaabove_over_eigenvalue * eigenvalue * ((eigenvalue + deltazabovefromjym) * (exp_deltabelow_over_eigenvalue-1) - - deltazbelow); - integral_parts[2] = exp_deltaabove_over_eigenvalue * eigenvalue * ((pow(deltazabovefromjym,2) + 2.*eigenvalue*(deltazabovefromjym+eigenvalue)) * (exp_deltabelow_over_eigenvalue-1) - - pow(deltazbelow,2)-2.*deltazabovefromjym*deltazbelow - 2.*eigenvalue*deltazbelow); - integral_parts[3] = exp_deltaabove_over_eigenvalue * eigenvalue * ((pow(deltazabovefromjym,3) + 3.*eigenvalue*pow(deltazabovefromjym,2) + 6.*pow(eigenvalue,2)*deltazabovefromjym + 6.*pow(eigenvalue,3)) * (exp_deltabelow_over_eigenvalue-1) - - 3.*pow(deltazabovefromjym,2)*deltazbelow - 3.*deltazabovefromjym*pow(deltazbelow,2) - pow(deltazbelow,3) - 3.*eigenvalue*(2.*deltazabovefromjym*deltazbelow + pow(deltazbelow,2)) - 6.*pow(eigenvalue,2)*deltazbelow); - } - else { - BoutReal exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue = exp(deltazbelow/2./eigenvalue) * 2.*sinh(deltazbelow/eigenvalue/2.); - integral_parts[0] = exp_deltaabove_over_eigenvalue * eigenvalue * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue; - integral_parts[1] = exp_deltaabove_over_eigenvalue * eigenvalue * ((eigenvalue + deltazabovefromjym) * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - deltazbelow); - integral_parts[2] = exp_deltaabove_over_eigenvalue * eigenvalue * ((pow(deltazabovefromjym,2) + 2.*eigenvalue*(deltazabovefromjym+eigenvalue)) * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - pow(deltazbelow,2)-2.*deltazabovefromjym*deltazbelow - 2.*eigenvalue*deltazbelow); - integral_parts[3] = exp_deltaabove_over_eigenvalue * eigenvalue * ((pow(deltazabovefromjym,3) + 3.*eigenvalue*pow(deltazabovefromjym,2) + 6.*pow(eigenvalue,2)*deltazabovefromjym + 6.*pow(eigenvalue,3)) * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - 3.*pow(deltazabovefromjym,2)*deltazbelow - 3.*deltazabovefromjym*pow(deltazbelow,2) - pow(deltazbelow,3) - 3.*eigenvalue*(2.*deltazabovefromjym*deltazbelow + pow(deltazbelow,2)) - 6.*pow(eigenvalue,2)*deltazbelow); - } - - //add on the contributions to the integral at jy from between jy-1 and jy-1/2 - for (int i=0; i<4; i++) integral_below[position->jx][position->jyp][position->jz] += integral_coeffs[i]*integral_parts[i]; - - // Calculate the contribution from the upper part of the interval (above CELL_CENTRE) - // The integration variable ('z-prime') goes from 0 to (dimensionless_length_deltas_above[jy]) with the final z-value (that goes into the exponential) being (dimensionless_length_deltas_above[jy]) - interp_coeffs_drive_term = cubic_spline_drive_term.coefficients(position); - interp_coeffs_lambdaC_inverse = cubic_spline_inverse_lambdaC.coefficients(position); - - integrand_coefficient0 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient1 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient2 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient3 = interp_coeffs_drive_term[0]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient4 = interp_coeffs_drive_term[1]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]); - integrand_coefficient5 = interp_coeffs_drive_term[2]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]); - integrand_coefficient6 = interp_coeffs_drive_term[3]*interp_coeffs_gradT[3]; - - // Approximate the sixth order polynomial by the least-squares-fit cubic between t=0 and t=1/2 - cubic_integrand_coefficient0 = integrand_coefficient0 - 1./1120.*integrand_coefficient4 - 1./1008.*integrand_coefficient5 - 1./1344.*integrand_coefficient6; - cubic_integrand_coefficient1 = integrand_coefficient1 + 1./28.*integrand_coefficient4 + 25./672.*integrand_coefficient5 + 3./112.*integrand_coefficient6; - cubic_integrand_coefficient2 = integrand_coefficient2 - 9./28.*integrand_coefficient4 - 25./84.*integrand_coefficient5 - 45./224.*integrand_coefficient6; - cubic_integrand_coefficient3 = integrand_coefficient3 + integrand_coefficient4 + 25./36.*integrand_coefficient5 + 5./12.*integrand_coefficient6; - - //calculate the coefficients of the integrand expanded in z rather than l (from the expansion of drive_term in l and l in z [inverted from z in l to third order]) - integral_coeffs[0] = cubic_integrand_coefficient0; - integral_coeffs[1] = cubic_integrand_coefficient1 / *deltal/interp_coeffs_lambdaC_inverse[0]; - integral_coeffs[2] = cubic_integrand_coefficient2 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],2) - - cubic_integrand_coefficient1 * interp_coeffs_lambdaC_inverse[1]/2./pow(*deltal,2)/pow(interp_coeffs_lambdaC_inverse[0],3); - integral_coeffs[3] = cubic_integrand_coefficient3 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],3) - - cubic_integrand_coefficient2 * interp_coeffs_lambdaC_inverse[1]/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4) - + cubic_integrand_coefficient1 * (0.5*pow(interp_coeffs_lambdaC_inverse[1],2)/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],5) - interp_coeffs_lambdaC_inverse[2]/3./pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4)); - - // Calculate analytically the integral from jy to jy+1/2 of z^n*exp( (deltazabove-z)/zeta ), firstly allowing for zeta to be large and secondly allowing for it to be small. - if (deltazabove>abs(eigenvalue)) { - BoutReal exp_deltaabove_over_eigenvalue = exp(deltazabove/eigenvalue); - integral_parts[0] = eigenvalue * (exp_deltaabove_over_eigenvalue-1); - integral_parts[1] = eigenvalue * ( eigenvalue*(exp_deltaabove_over_eigenvalue-1) - - deltazabove); - integral_parts[2] = eigenvalue * (2.*pow(eigenvalue,2) * (exp_deltaabove_over_eigenvalue-1) - - pow(deltazabove,2) - 2.*deltazabove*eigenvalue); - integral_parts[3] = eigenvalue*(6.*pow(eigenvalue,3) * (exp_deltaabove_over_eigenvalue-1) - - pow(deltazabove,3) - 3.*pow(deltazabove,2)*eigenvalue - 6.*deltazabove*pow(eigenvalue,2)); - } - else { - BoutReal exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue = exp(deltazabove/2./eigenvalue) * 2.*sinh(deltazabove/eigenvalue/2.); - integral_parts[0] = eigenvalue * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue; - integral_parts[1] = eigenvalue * ( eigenvalue*exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - deltazabove); - integral_parts[2] = eigenvalue * (2.*pow(eigenvalue,2) * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - pow(deltazabove,2) - 2.*deltazabove*eigenvalue); - integral_parts[3] = eigenvalue*(6.*pow(eigenvalue,3) * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - pow(deltazabove,3) - 3.*pow(deltazabove,2)*eigenvalue - 6.*deltazabove*pow(eigenvalue,2)); - } - - //add on the contributions to the integral at jy from the expansion of the integral between jy-1/2 and jy - for (int i=0; i<4; i++) integral_below[position->jx][position->jyp][position->jz] += integral_coeffs[i]*integral_parts[i]; - - position->jy++; - calc_index(position); - } while (position->jy < mesh->yend+1); - - // Send the value at yend+1 to the next processor. - if (position->jx < mesh->UpXSplitIndex()) { - Timer timer("comms"); - mesh->sendYOutIndest(&integral_below[*position],1,HEATFLUX_INTEGRATION_TAGBASE + mesh->UpXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz); - } - else { - Timer timer("comms"); - mesh->sendYOutOutdest(&integral_below[*position],1,HEATFLUX_INTEGRATION_TAGBASE + (mesh->LocalNx-mesh->UpXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->UpXSplitIndex()) + position->jz); - } - - } while (next_indexperp(position)); -} - -void HeatFluxIntegration::calculateIntegralAbove_cell_ylow(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_below, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, CubicSpline &cubic_spline_gradT, const int &counter) { - TRACE("HeatFluxIntegration::calculateIntegralAbove()"); - - start_index_lasty(position); - do { - position->jy=mesh->yend; - calc_index(position); - if (!mesh->lastY()) { - // Set the value at yend+1 equal to the value at ystart of the previous processor. - if (position->jxUpXSplitIndex()) { - mesh->wait(mesh->irecvYOutIndest(&integral_above[position->jx][position->jyp][position->jz],1,HEATFLUX_INTEGRATION_TAGBASE + mesh->UpXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz)); - } - else { - mesh->wait(mesh->irecvYOutOutdest(&integral_above[position->jx][position->jyp][position->jz],1,HEATFLUX_INTEGRATION_TAGBASE + (mesh->LocalNx - mesh->UpXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->UpXSplitIndex()) + position->jz)); - } - } - else { - // Last grid point for CELL_YLOW quantities is mesh->yend on the last y-processor, so start the calculation from mesh->yend-1 if mesh->lastY() - position->jy=mesh->yend-1; - calc_index(position); - } - do { - *deltal = mesh->dy[position->jx][position->jy]*sqrt(mesh->g_22[position->jx][position->jy]); - - BoutReal deltazbelow = dimensionless_length_deltas_below[*position]; - BoutReal deltazabove = dimensionless_length_deltas_above[*position]; - BoutReal deltaz = dimensionless_length_deltas_below[*position] + dimensionless_length_deltas_above[*position]; - - interp_coeffs_gradT = cubic_spline_gradT.coefficients(position); - - // Contribution to the integral at jy from points up to jy+1 - integral_above[*position] = integral_above[position->jx][position->jyp][position->jz] * exp(deltaz/eigenvalue); - - // Calculate the contribution from the lower part of the interval (below CELL_CENTRE) - // The integration variable ('z-prime') goes from (dimensionless_length_deltas_above[jy-1]+dimensionless_length_deltas_below[jy]) to (dimensionless_length_deltas_above[jy-1]) with the final z-value (that goes into the exponential) being (dimensionless_length_deltas_above[jy-1]) - BoutReal deltazabovefromjym = dimensionless_length_deltas_above[position->jx][position->jym][position->jz]; - interp_coeffs_drive_term = cubic_spline_drive_term.coefficients(position->jx,position->jym,position->jz); - interp_coeffs_lambdaC_inverse = cubic_spline_inverse_lambdaC.coefficients(position->jx,position->jym,position->jz); - - BoutReal integrand_coefficient0 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient1 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient2 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient3 = interp_coeffs_drive_term[0]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient4 = interp_coeffs_drive_term[1]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient5 = interp_coeffs_drive_term[2]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient6 = interp_coeffs_drive_term[3]*interp_coeffs_gradT[3]; - - // Approximate the sixth order polynomial by the least-squares-fit cubic between t=1/2 and t=1 - BoutReal cubic_integrand_coefficient0 = integrand_coefficient0 - 321./1120.*integrand_coefficient4 - 97./112.*integrand_coefficient5 - 2225./1344.*integrand_coefficient6; - BoutReal cubic_integrand_coefficient1 = integrand_coefficient1 + 45./28.*integrand_coefficient4 + 3065./672.*integrand_coefficient5 + 939./112.*integrand_coefficient6; - BoutReal cubic_integrand_coefficient2 = integrand_coefficient2 - 93./28.*integrand_coefficient4 - 235./28.*integrand_coefficient5 - 3245./224.*integrand_coefficient6; - BoutReal cubic_integrand_coefficient3 = integrand_coefficient3 + 3.*integrand_coefficient4 + 205./36.*integrand_coefficient5 + 35./4.*integrand_coefficient6; - - //calculate the coefficients of the integrand expanded in z rather than l (from the expansion of drive_term in l and l in z [inverted from z in l to third order]) - integral_coeffs[0] = cubic_integrand_coefficient0; - integral_coeffs[1] = cubic_integrand_coefficient1 / *deltal/interp_coeffs_lambdaC_inverse[0]; - integral_coeffs[2] = cubic_integrand_coefficient2 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],2) - - cubic_integrand_coefficient1 * interp_coeffs_lambdaC_inverse[1]/2./pow(*deltal,2)/pow(interp_coeffs_lambdaC_inverse[0],3); - integral_coeffs[3] = cubic_integrand_coefficient3 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],3) - - cubic_integrand_coefficient2 * interp_coeffs_lambdaC_inverse[1]/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4) - + cubic_integrand_coefficient1 * (0.5*pow(interp_coeffs_lambdaC_inverse[1],2)/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],5) - interp_coeffs_lambdaC_inverse[2]/3./pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4)); - - // Calculate analytically the integral from jy+1/2 to jy of z^n*exp( -(deltazabovefromjym-z)/zeta ), firstly allowing for zeta to be large and secondly allowing for it to be small. - if (deltazbelow>abs(eigenvalue)) { - BoutReal exp_deltabelow_over_eigenvalue = exp(deltazbelow/eigenvalue); - integral_parts[0] = -eigenvalue * (exp_deltabelow_over_eigenvalue-1); - integral_parts[1] = -eigenvalue * ((-eigenvalue + deltazabovefromjym) * (exp_deltabelow_over_eigenvalue-1) - + deltazbelow*exp_deltabelow_over_eigenvalue); - integral_parts[2] = -eigenvalue * ((pow(deltazabovefromjym,2) - 2.*eigenvalue*(deltazabovefromjym-eigenvalue)) * (exp_deltabelow_over_eigenvalue-1) - + (pow(deltazbelow,2)+2.*deltazabovefromjym*deltazbelow - 2.*eigenvalue*deltazbelow)*exp_deltabelow_over_eigenvalue); - integral_parts[3] = -eigenvalue * ((pow(deltazabovefromjym,3) - 3.*eigenvalue*pow(deltazabovefromjym,2) + 6.*pow(eigenvalue,2)*deltazabovefromjym - 6.*pow(eigenvalue,3)) * (exp_deltabelow_over_eigenvalue-1) - + (3.*pow(deltazabovefromjym,2)*deltazbelow + 3.*deltazabovefromjym*pow(deltazbelow,2) + pow(deltazbelow,3) - 3.*eigenvalue*(2.*deltazabovefromjym*deltazbelow + pow(deltazbelow,2)) + 6.*pow(eigenvalue,2)*deltazbelow)*exp_deltabelow_over_eigenvalue); - } - else { - BoutReal exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue = exp(deltazbelow/2./eigenvalue) * 2.*sinh(deltazbelow/eigenvalue/2.); - integral_parts[0] = -eigenvalue * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue; - integral_parts[1] = -eigenvalue * ((-eigenvalue + deltazbelow + deltazabovefromjym) * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + deltazbelow); - integral_parts[2] = -eigenvalue * ((pow(deltazabovefromjym+deltazbelow,2) - 2.*eigenvalue*(deltazabovefromjym+deltazbelow-eigenvalue)) * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + pow(deltazbelow,2)+2.*deltazabovefromjym*deltazbelow - 2.*eigenvalue*deltazbelow); - integral_parts[3] = -eigenvalue * ((pow(deltazabovefromjym + deltazbelow,3) - 3.*eigenvalue*pow(deltazabovefromjym + deltazbelow,2) + 6.*pow(eigenvalue,2)*(deltazabovefromjym + deltazbelow) - 6.*pow(eigenvalue,3)) * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + 3.*pow(deltazabovefromjym,2)*deltazbelow + 3.*deltazabovefromjym*pow(deltazbelow,2) + pow(deltazbelow,3) - 3.*eigenvalue*(2.*deltazabovefromjym*deltazbelow + pow(deltazbelow,2)) + 6.*pow(eigenvalue,2)*deltazbelow); - } - - //add on the contributions to the integral at jy from between jy and jy+1/2 - for (int i=0; i<4; i++) integral_above[*position] += integral_coeffs[i]*integral_parts[i]; - - - // Calculate the contribution from the upper part of the interval (above CELL_CENTRE) - // The integration variable ('z-prime') goes from (dimensionless_length_deltas_above[jy]) to 0 with the final z-value (that goes into the exponential) being (-dimensionless_length_deltas_below[jy]) - interp_coeffs_drive_term = cubic_spline_drive_term.coefficients(position); - interp_coeffs_lambdaC_inverse = cubic_spline_inverse_lambdaC.coefficients(position); - - integrand_coefficient0 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient1 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient2 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient3 = interp_coeffs_drive_term[0]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient4 = interp_coeffs_drive_term[1]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]); - integrand_coefficient5 = interp_coeffs_drive_term[2]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]); - integrand_coefficient6 = interp_coeffs_drive_term[3]*interp_coeffs_gradT[3]; - - // Approximate the sixth order polynomial by the least-squares-fit cubic between t=0 and t=1/2 - cubic_integrand_coefficient0 = integrand_coefficient0 - 1./1120.*integrand_coefficient4 - 1./1008.*integrand_coefficient5 - 1./1344.*integrand_coefficient6; - cubic_integrand_coefficient1 = integrand_coefficient1 + 1./28.*integrand_coefficient4 + 25./672.*integrand_coefficient5 + 3./112.*integrand_coefficient6; - cubic_integrand_coefficient2 = integrand_coefficient2 - 9./28.*integrand_coefficient4 - 25./84.*integrand_coefficient5 - 45./224.*integrand_coefficient6; - cubic_integrand_coefficient3 = integrand_coefficient3 + integrand_coefficient4 + 25./36.*integrand_coefficient5 + 5./12.*integrand_coefficient6; - - //calculate the coefficients of the integrand expanded in z rather than l (from the expansion of drive_term in l and l in z [inverted from z in l to third order]) - integral_coeffs[0] = cubic_integrand_coefficient0; - integral_coeffs[1] = cubic_integrand_coefficient1 / *deltal/interp_coeffs_lambdaC_inverse[0]; - integral_coeffs[2] = cubic_integrand_coefficient2 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],2) - - cubic_integrand_coefficient1 * interp_coeffs_lambdaC_inverse[1]/2./pow(*deltal,2)/pow(interp_coeffs_lambdaC_inverse[0],3); - integral_coeffs[3] = cubic_integrand_coefficient3 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],3) - - cubic_integrand_coefficient2 * interp_coeffs_lambdaC_inverse[1]/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4) - + cubic_integrand_coefficient1 * (0.5*pow(interp_coeffs_lambdaC_inverse[1],2)/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],5) - interp_coeffs_lambdaC_inverse[2]/3./pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4)); - - // Calculate analytically the integral from jy+1 to jy+1/2 of z^n*exp( -(-deltazbelow-z)/zeta ), firstly allowing for zeta to be large and secondly allowing for it to be small. - BoutReal exp_deltabelow_over_eigenvalue = exp(deltazbelow/eigenvalue); - if (deltazabove>abs(eigenvalue)) { - BoutReal exp_deltaabove_over_eigenvalue = exp(deltazabove/eigenvalue); - integral_parts[0] = -exp_deltabelow_over_eigenvalue * eigenvalue * (exp_deltaabove_over_eigenvalue-1); - integral_parts[1] = -exp_deltabelow_over_eigenvalue * eigenvalue * (-eigenvalue * (exp_deltaabove_over_eigenvalue-1) - + deltazabove*exp_deltaabove_over_eigenvalue); - integral_parts[2] = -exp_deltabelow_over_eigenvalue * eigenvalue * (2.*pow(eigenvalue,2) * (exp_deltaabove_over_eigenvalue-1) - + (pow(deltazabove,2) - 2.*eigenvalue*deltazabove)*exp_deltaabove_over_eigenvalue); - integral_parts[3] = -exp_deltabelow_over_eigenvalue * eigenvalue * (-6.*pow(eigenvalue,3) * (exp_deltaabove_over_eigenvalue-1) - + (pow(deltazabove,3) - 3.*eigenvalue*pow(deltazabove,2) + 6.*pow(eigenvalue,2)*deltazabove)*exp_deltaabove_over_eigenvalue); - } - else { - BoutReal exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue = exp(deltazabove/2./eigenvalue) * 2.*sinh(deltazabove/eigenvalue/2.); - integral_parts[0] = -exp_deltabelow_over_eigenvalue * eigenvalue * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue; - integral_parts[1] = -exp_deltabelow_over_eigenvalue * eigenvalue * ((-eigenvalue + deltazabove) * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + deltazabove); - integral_parts[2] = -exp_deltabelow_over_eigenvalue * eigenvalue * ((pow(deltazabove,2) - 2.*eigenvalue*deltazabove + 2.*pow(eigenvalue,2)) * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + pow(deltazabove,2) - 2.*eigenvalue*deltazabove); - integral_parts[3] = -exp_deltabelow_over_eigenvalue * eigenvalue * ((pow(deltazabove,3) - 3.*eigenvalue*pow(deltazabove,2) + 6.*pow(eigenvalue,2)*deltazabove - 6.*pow(eigenvalue,3)) * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + pow(deltazabove,3) - 3.*eigenvalue*pow(deltazabove,2) + 6.*pow(eigenvalue,2)*deltazabove); - } - - //add on the contributions to the integral at jy from the expansion of the integral between jy+1 and jy+1/2 - for (int i=0; i<4; i++) integral_above[*position] += integral_coeffs[i]*integral_parts[i]; - - } while (previous_index_y(position)); - - // Send the value at ystart to the next processor - if (position->jx < mesh->DownXSplitIndex()) { - Timer timer("comms"); - mesh->sendYInIndest(&integral_above[*position],1,HEATFLUX_INTEGRATION_TAGBASE + mesh->DownXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz); - } - else { - Timer timer("comms"); - mesh->sendYInOutdest(&integral_above[*position],1,HEATFLUX_INTEGRATION_TAGBASE + (mesh->LocalNx - mesh->DownXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->DownXSplitIndex()) + position->jz); - } - - } while (next_indexperp(position)); -} diff --git a/examples/non-local_1d/heat_flux_integration.hxx b/examples/non-local_1d/heat_flux_integration.hxx deleted file mode 100644 index ede5d4ac0d..0000000000 --- a/examples/non-local_1d/heat_flux_integration.hxx +++ /dev/null @@ -1,77 +0,0 @@ -/************************************************************************** - * Perform the integral needed to calculate the non-local heat flux - * - ************************************************************************** - * Copyright 2012 J.T.Omotani - * - * Contact: John Omotani, john.omotani@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - **************************************************************************/ - -#ifndef __HEATFLUXINTEGRATION_H__ -#define __HEATFLUXINTEGRATION_H__ - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// #include "cubic_spline.hxx" -#include "cubic_spline_local.hxx" - -/// Class for non-local heat flux integration -class HeatFluxIntegration { -public: - HeatFluxIntegration(); - ~HeatFluxIntegration(); - void initialise(const bool pass_electron_heat_flux_location_is_ylow); - - Field3D integral_below; - Field3D integral_above; - void calculateIntegralBelow_cell_centre(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, const int &counter); - void calculateIntegralAbove_cell_centre(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, const int &counter); - void calculateIntegralBelow_cell_ylow(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_below, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, CubicSpline &cubic_spline_gradT, const int &counter); - void calculateIntegralAbove_cell_ylow(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_below, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, CubicSpline &cubic_spline_gradT, const int &counter); - -private: - bindex * position; - BoutReal * deltal; - BoutReal * interp_coeffs_lambdaC_inverse; - BoutReal * interp_coeffs_drive_term; - BoutReal * interp_coeffs_gradT; - BoutReal * integral_coeffs; - BoutReal * integral_parts; - int HEATFLUX_INTEGRATION_TAGBASE; - bool electron_heat_flux_location_is_ylow; -}; - -#endif diff --git a/examples/non-local_1d/makefile b/examples/non-local_1d/makefile deleted file mode 100644 index 795cb02288..0000000000 --- a/examples/non-local_1d/makefile +++ /dev/null @@ -1,10 +0,0 @@ - -BOUT_TOP = ../.. - -SOURCEC = cubic_spline_local.cxx non-local_parallel.cxx non-local_parallel_integration.cxx non-local_1d.cxx -SOURCEH = cubic_spline_local.hxx non-local_parallel.hxx non-local_parallel_integration.hxx -TARGET = non-local_1d - -CXXFLAGS += -g - -include $(BOUT_TOP)/make.config diff --git a/examples/non-local_1d/non-local_1d.cxx b/examples/non-local_1d/non-local_1d.cxx deleted file mode 100644 index 40bddc1943..0000000000 --- a/examples/non-local_1d/non-local_1d.cxx +++ /dev/null @@ -1,616 +0,0 @@ -/* - * 1D parallel transport problem - * - */ - -#include -#include - -#include -#include -#include - -#include "non-local_parallel.hxx" - -#include "sin-single-sources.cxx" - -// #include - -#define CUSTOMBCS -// #define CALCULATE_EFFECTIVE_ALPHAE -// #define LOCALHEATFLUX -// #define FLUXLIMITER -#define IONFLUXLIMITER -#define IONVISCOSITYLIMITER - -#ifdef CALCULATE_EFFECTIVE_ALPHAE - #ifdef LOCALHEATFLUX - throw BoutException("Cannot calculate effective_alpha_e without non-local heat-flux"); - #endif - FieldPerp effective_alpha_e; -#endif - -#ifdef FLUXLIMITER - #ifndef LOCALHEATFLUX - throw BoutException("FLUXLIMITER can only be defined if LOCALHEATFLUX is also defined"); - #endif - BoutReal electron_flux_limiter = 0.3; - Field3D grad_par_T_electron; - Field3D qSH_electron; - Field3D qFS_electron; - Field3D grad_par_electron_heat_flux; -#endif - -#ifdef IONFLUXLIMITER - BoutReal ion_flux_limiter = 0.1; - Field3D grad_par_T_ion; - Field3D qSH_ion; - Field3D qFS_ion; - Field3D grad_par_ion_heat_flux; -#endif - -#ifdef IONVISCOSITYLIMITER - BoutReal ion_viscosity_limiter = 0.5; -// BoutReal ion_viscosity_limiter = 1.; - Field3D grad_par_viscosity; - Field3D viscosity; - Field3D grad_par_V_centre; - Field3D nTtau_ion_ylow; - Field3D pi_Brag_ylow; - Field3D pi_Brag_centre; -#endif - -// BoutReal gamma_factor = 1.; -// BoutReal gamma_factor = 5./3.; - BoutReal gamma_factor = 3.; - -/********************************************************************************************************************************/ - -Field3D T_electron; // Electron temperature -// Ambipolarity: Assume that the electron density and velocity are equal to the ion density and velocity -Field3D n_ion; // Ion density -Field3D Vpar_ion; // Ion fluid velocity (parallel component since this is a 1d model) -Field3D T_ion; // Evolve the ion temperature separately (using Braginskii closure for ion heat flux) -Field3D j_parallel; // Parallel current electron_charge*n_ion*(Vpar_ion-Vpar_electron) - -Field3D tau_ii; //Ion-ion collision time -Field3D tau_ei; //Electron-ion collision time -Field3D nTtau_ion; //used in calculating the viscosity tensor (parallel components) and ion heat flux -// Field3D VeminusVi; - -BoutReal massunit; -BoutReal energyunit; -// Physical constants -BoutReal electron_charge; -BoutReal electron_mass; -BoutReal ion_charge; -BoutReal ion_mass; -BoutReal epsilon_0; -BoutReal logLambda; -int boundary_gradient_smoothing_length; -BoutReal boundary_condition_smoothing_range; - -bindex position; - -Sources sources; - -NonLocalParallel nonlocal_parallel; -#ifndef LOCALHEATFLUX - Field3D heat_flux_boundary_condition; -#endif - -Field3D ratio; - -/**********************************************************************************************************************************************/ - -int physics_init(bool restarting) { - - boundary_gradient_smoothing_length = mesh->GlobalNy/256; // Number of grid points to average over for the gradient used to extrapolate to the guard cells - boundary_condition_smoothing_range = BoutReal(mesh->GlobalNy)/64.; - - // Physical constants - electron_charge = -1.602176565e-19; //C - // Scale factors for units relative to SI (temperatures will be in energy units). All units apart from mass and energy are SI (i.e. m, s, C). - massunit = abs(electron_charge); //the internal mass unit is 1.602176565e-19kg so that energy will be in eV - energyunit = massunit; //internal energy unit is 1.602176565e-19J so that energies/temperatures are stored in eV - electron_mass = 9.10938291e-31/massunit; //kg - ion_charge = 1.602176565e-19; //C - ion_mass = 3.34358348e-27/massunit;// kg - epsilon_0 = 8.85418781762039e-12/pow(massunit,-1); //C^2 s^2 kg^-1 m^-3 - logLambda = 16.0; //Coulomb Logarithm --- logLambda=16.1 for (n = 10^18 m^-3) and (T = 100eV) - //Recall: logLambda~25.3-1.15*log10(n/cm^3)+2.3*log10(T_e/eV) for T_e>50eV; logLambda~23.4-1.15*log10(n/cm^3)+3.45*log10(T_e/eV) for T_e<50eV -- Hazeltine+Meiss (2003) - - // Get the options for the model - Options *options = Options::getRoot()->getSection("conduction"); - - // Get the options for the sources - options = Options::getRoot()->getSection("sources"); -// OPTION(options, sources.lower_source_yindex, 0); -// OPTION(options, sources.upper_source_yindex, 0); - OPTION(options, sources.source_length, 0); - OPTION(options, sources.particle_amplitude ,0); - OPTION(options, sources.electron_heat_amplitude ,0); - OPTION(options, sources.ion_heat_amplitude ,0); - OPTION(options, sources.on_time ,0); - OPTION(options, sources.off_time ,0); - OPTION(options, sources.particle_transient_amplitude ,0); - OPTION(options, sources.electron_heat_transient_amplitude ,0); - OPTION(options, sources.ion_heat_transient_amplitude ,0); - - sources.initialise(); - - // Initialise nonlocal_parallel object -// #ifndef LOCALHEATFLUX - nonlocal_parallel.initialise(electron_charge, electron_mass, ion_mass, epsilon_0, logLambda, mesh->StaggerGrids, gamma_factor); -// #endif - #ifndef LOCALHEATFLUX - heat_flux_boundary_condition.setLocation(CELL_YLOW); - heat_flux_boundary_condition = 0.; - #endif - tau_ei = 0.; - tau_ii = 0.; - - // Set non-default cell locations - Vpar_ion.setLocation(CELL_YLOW); // Staggered relative to n_ion, etc. - j_parallel.setLocation(CELL_YLOW); - ratio.setLocation(CELL_YLOW); - #ifdef IONVISCOSITYLIMITER - grad_par_viscosity.setLocation(CELL_YLOW); - pi_Brag_ylow.setLocation(CELL_YLOW); - #endif - - // Tell BOUT++ which fields to evolve - SOLVE_FOR(T_electron); - SOLVE_FOR(n_ion); - SOLVE_FOR(Vpar_ion); - SOLVE_FOR(T_ion); - SOLVE_FOR(j_parallel); - -// dump.add(mesh->dy,"dy",0); -// dump.add(mesh->g_22,"g_22",0); - #ifdef CALCULATE_HEATFLUX - dump.add(nonlocal_parallel.electron_heat_flux,"heat_flux",1); - #endif - #ifdef CALCULATE_VISCOSITY - dump.add(nonlocal_parallel.electron_viscosity,"viscosity",1); - #endif - #ifdef CALCULATE_FRICTION - dump.add(nonlocal_parallel.electron_friction,"friction",1); - #endif - dump.add(ratio,"local_non-local_ratio",1); - #ifdef CALCULATE_EFFECTIVE_ALPHAE - effective_alpha_e = 0.; - dump.add(effective_alpha_e[2][0],"effective_alpha_e",1); - #endif - - output<communicate(T_electron, n_ion, Vpar_ion, T_ion);// Communicate guard cells - - // Done like this so we can deal with T_ion<0 at mesh->yend (which is a 'guard cell' for the staggered grid case) without throwing an exception - for (int jx=mesh->xstart; jx<=mesh->xend; jx++) - for (int jz=0; jzLocalNz; jz++) - for (int jy=0; jyLocalNy; jy++) { - tau_ii(jx,jy,jz) = 3 * pow(PI,1.5) * pow(epsilon_0,2) * sqrt(ion_mass) * pow(2.,1.5) * pow(T_ion(jx,jy,jz),1.5) / n_ion(jx,jy,jz) / pow(ion_charge,4) / logLambda; - tau_ei(jx,jy,jz) = 3 * pow(PI,1.5) * pow(epsilon_0,2) * sqrt(electron_mass) * pow(2.,1.5) * pow(T_electron(jx,jy,jz),1.5) / n_ion(jx,jy,jz) / pow(electron_charge,2) / pow(ion_charge,2) / logLambda; - } - - #ifdef CUSTOMBCS - // Fix the temperature to continue with the gradient given by the 4-point forward/backward difference estimate // and electron temperature gradient to give electron heat flux = 5.0 T_electron n_ion Vpar_ion at the boundaries, assuming that it were highly collisional (this is not actually used because the boundary condition is applied to the heat flux explicitly) - - for (RangeIterator rlow = mesh->iterateBndryLowerY(); !rlow.isDone(); rlow++) - for (int jz=0; jzLocalNz; jz++) { - position.jx = rlow.ind; - position.jy = mesh->ystart; - position.jz = jz; - calc_index(&position); - BoutReal n_here = nonlocal_parallel.interp_to_point_YLOW(n_ion,position); - BoutReal Te_here = nonlocal_parallel.interp_to_point_YLOW(T_electron,position); - BoutReal Ti_here = nonlocal_parallel.interp_to_point_YLOW(T_ion,position); - BoutReal tauei_here = nonlocal_parallel.interp_to_point_YLOW(tau_ei,position); - #ifdef LOCALHEATFLUX - BoutReal sheath_potential = 0.5*Te_here*log(2*PI*electron_mass/ion_mass*(1+gamma_factor*Ti_here/Te_here)); - #ifdef FLUXLIMITER - // Include the flux limiter in the boundary condition: i.e. find the gradient needed to give the right boundary heat-flux AFTER applying the flux-limiter - BoutReal qbc_over_n = -((2.0-2.5)*Te_here-sheath_potential) - *sqrt((Te_here+gamma_factor*Ti_here)/ion_mass); // -2.5*Te so that we subtract off the convective heat flux to leave just the conductive heat flux, not the total - BoutReal qBrag_over_n = 1./(1./qbc_over_n-1./electron_flux_limiter/( -sqrt(2./electron_mass)*pow(Te_here,1.5) )); - BoutReal gradient_T_electron = qBrag_over_n - /(-3.16*Te_here*tauei_here/electron_mass) - *coord->dy(rlow.ind,mesh->ystart)*sqrt(coord->g_22(rlow.ind,mesh->ystart)); -#else - BoutReal gradient_T_electron = -((2.0-2.5)*Te_here-sheath_potential) - *sqrt((Te_here+gamma_factor*Ti_here)/ion_mass) - /(-3.16*Te_here*tauei_here/electron_mass) - *coord->dy(rlow.ind,mesh->ystart)*sqrt(coord->g_22(rlow.ind,mesh->ystart)); // -2.5*Te so that we subtract off the convective heat flux to leave just the conductive heat flux, not the total - #endif - #else - // BoutReal gradient_T_electron = (-11.*T_electron[rlow.ind][mesh->ystart][jz] + 18.*T_electron[rlow.ind][mesh->ystart+1][jz] - 9.*T_electron[rlow.ind][mesh->ystart+2][jz] + 2.*T_electron[rlow.ind][mesh->ystart+3][jz]) / 6. / mesh->dy[rlow.ind][mesh->ystart] / sqrt((mesh->g_22[rlow.ind][mesh->ystart]+mesh->g_22[rlow.ind][mesh->ystart+1]+mesh->g_22[rlow.ind][mesh->ystart+2]+mesh->g_22[rlow.ind][mesh->ystart+3])/4.); - BoutReal gradient_T_electron = (-T_electron(rlow.ind,mesh->ystart,jz) + T_electron(rlow.ind,mesh->ystart+boundary_gradient_smoothing_length,jz))/BoutReal(boundary_gradient_smoothing_length); - #endif - // BoutReal gradient_n = (-11.*n_ion[rlow.ind][mesh->ystart][jz] + 18.*n_ion[rlow.ind][mesh->ystart+1][jz] - 9.*n_ion[rlow.ind][mesh->ystart+2][jz] + 2.*n_ion[rlow.ind][mesh->ystart+3][jz]) / 6. / mesh->dy[rlow.ind][mesh->ystart] / sqrt((mesh->g_22[rlow.ind][mesh->ystart]+mesh->g_22[rlow.ind][mesh->ystart+1]+mesh->g_22[rlow.ind][mesh->ystart+2]+mesh->g_22[rlow.ind][mesh->ystart+3])/4.); - BoutReal gradient_n = (-n_ion(rlow.ind,mesh->ystart,jz) + n_ion(rlow.ind,mesh->ystart+boundary_gradient_smoothing_length,jz))/BoutReal(boundary_gradient_smoothing_length); - // BoutReal gradient_T_ion = (-11.*T_ion[rlow.ind][mesh->ystart][jz] + 18.*T_ion[rlow.ind][mesh->ystart+1][jz] - 9.*T_ion[rlow.ind][mesh->ystart+2][jz] + 2.*T_ion[rlow.ind][mesh->ystart+3][jz]) / 6. / mesh->dy[rlow.ind][mesh->ystart] / sqrt((mesh->g_22[rlow.ind][mesh->ystart]+mesh->g_22[rlow.ind][mesh->ystart+1]+mesh->g_22[rlow.ind][mesh->ystart+2]+mesh->g_22[rlow.ind][mesh->ystart+3])/4.); - BoutReal gradient_T_ion = (-T_ion(rlow.ind,mesh->ystart,jz) + T_ion(rlow.ind,mesh->ystart+boundary_gradient_smoothing_length,jz))/BoutReal(boundary_gradient_smoothing_length); - for (int jy=mesh->ystart-1; jy>=0; jy--) { - n_ion(rlow.ind,jy,jz) = n_ion(rlow.ind,jy+1,jz) - gradient_n; - // n_ion(rlow.ind,jy,jz) = n_ion(rlow.ind,jy+1,jz); - T_ion(rlow.ind,jy,jz) = T_ion(rlow.ind,jy+1,jz) - gradient_T_ion; - #ifndef LOCALHEATFLUX - T_electron(rlow.ind,jy,jz) = T_electron(rlow.ind,jy+1,jz) - gradient_T_electron; - #endif - } - #ifdef LOCALHEATFLUX - // Set it up so that the fourth-order central finite difference derivative at CELL_YLOW of mesh->ystart is gradient_T_electron - T_electron(rlow.ind,mesh->ystart-1,jz) = T_electron(rlow.ind,mesh->ystart,jz) - gradient_T_electron; - T_electron(rlow.ind,mesh->ystart-2,jz) = T_electron(rlow.ind,mesh->ystart+1,jz) - 3.*gradient_T_electron; - for (int jy=mesh->ystart-3; jy>=0; jy--) - T_electron(rlow.ind,jy,jz) = T_electron(rlow.ind,jy+1,jz) - gradient_T_electron; - #endif - } - - if (mesh->StaggerGrids) - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) { - position.jx = rup.ind; - position.jy = mesh->yend; - position.jz = jz; - calc_index(&position); - BoutReal n_here = nonlocal_parallel.interp_to_point_YLOW(n_ion,position); - BoutReal Te_here = nonlocal_parallel.interp_to_point_YLOW(T_electron,position); - BoutReal Ti_here = nonlocal_parallel.interp_to_point_YLOW(T_ion,position); - BoutReal tauei_here = nonlocal_parallel.interp_to_point_YLOW(tau_ei,position); - #ifdef LOCALHEATFLUX - BoutReal sheath_potential = 0.5*Te_here*log(2*PI*electron_mass/ion_mass*(1+gamma_factor*Ti_here/Te_here)); - #ifdef FLUXLIMITER - // Include the flux limiter in the boundary condition: i.e. find the gradient needed to give the right boundary heat-flux AFTER applying the flux-limiter - BoutReal qbc_over_n = ((2.0-2.5)*Te_here-sheath_potential) - *sqrt((Te_here+gamma_factor*Ti_here)/ion_mass); // -2.5*Te so that we subtract off the convective heat flux to leave just the conductive heat flux, not the total - BoutReal qBrag_over_n = 1./(1./qbc_over_n-1./electron_flux_limiter/( sqrt(2./electron_mass)*pow(Te_here,1.5) )); - BoutReal gradient_T_electron = qBrag_over_n - /(-3.16*Te_here*tauei_here/electron_mass) - *mesh->dy[rup.ind][mesh->yend-1]*sqrt(mesh->g_22[rup.ind][mesh->yend-1]); - #else - BoutReal gradient_T_electron = ((2.0-2.5)*Te_here-sheath_potential) - *sqrt((Te_here+gamma_factor*Ti_here)/ion_mass) - /(-3.16*Te_here*tauei_here/electron_mass) - *mesh->dy[rup.ind][mesh->yend-1]*sqrt(mesh->g_22[rup.ind][mesh->yend-1]); // -2.5*Te so that we subtract off the convective heat flux to leave just the conductive heat flux, not the total - #endif - #else - // BoutReal gradient_T_electron = (11.*T_electron[rup.ind][mesh->yend-1][jz] - 18.*T_electron[rup.ind][mesh->yend-2][jz] + 9.*T_electron[rup.ind][mesh->yend-3][jz] - 2.*T_electron[rup.ind][mesh->yend-4][jz]) / 6. / mesh->dy[rup.ind][mesh->yend] / sqrt((mesh->g_22[rup.ind][mesh->yend-1]+mesh->g_22[rup.ind][mesh->yend-2]+mesh->g_22[rup.ind][mesh->yend-3]+mesh->g_22[rup.ind][mesh->yend-4])/4.); - BoutReal gradient_T_electron = (-T_electron[rup.ind][mesh->yend-1-boundary_gradient_smoothing_length][jz] + T_electron[rup.ind][mesh->yend-1][jz])/BoutReal(boundary_gradient_smoothing_length); - #endif - // BoutReal gradient_n = (11.*n_ion[rup.ind][mesh->yend-1][jz] - 18.*n_ion[rup.ind][mesh->yend-2][jz] + 9.*n_ion[rup.ind][mesh->yend-3][jz] - 2.*n_ion[rup.ind][mesh->yend-4][jz]) / 6. / mesh->dy[rup.ind][mesh->yend] / sqrt((mesh->g_22[rup.ind][mesh->yend-1]+mesh->g_22[rup.ind][mesh->yend-2]+mesh->g_22[rup.ind][mesh->yend-3]+mesh->g_22[rup.ind][mesh->yend-4])/4.); - BoutReal gradient_n = (-n_ion[rup.ind][mesh->yend-1-boundary_gradient_smoothing_length][jz] + n_ion[rup.ind][mesh->yend-1][jz])/BoutReal(boundary_gradient_smoothing_length); - // BoutReal gradient_T_ion = (11.*T_ion[rup.ind][mesh->yend-1][jz] - 18.*T_ion[rup.ind][mesh->yend-2][jz] + 9.*T_ion[rup.ind][mesh->yend-3][jz] - 2.*T_ion[rup.ind][mesh->yend-4][jz]) / 6. / mesh->dy[rup.ind][mesh->yend] / sqrt((mesh->g_22[rup.ind][mesh->yend-1]+mesh->g_22[rup.ind][mesh->yend-2]+mesh->g_22[rup.ind][mesh->yend-3]+mesh->g_22[rup.ind][mesh->yend-4])/4.); - BoutReal gradient_T_ion = (-T_ion[rup.ind][mesh->yend-1-boundary_gradient_smoothing_length][jz] + T_ion[rup.ind][mesh->yend-1][jz])/BoutReal(boundary_gradient_smoothing_length); - for (int jy=mesh->yend; jyLocalNy; jy++) { - n_ion[rup.ind][jy][jz] = n_ion[rup.ind][jy-1][jz] + gradient_n; - T_ion[rup.ind][jy][jz] = T_ion[rup.ind][jy-1][jz] + gradient_T_ion; - #ifndef LOCALHEATFLUX - T_electron[rup.ind][jy][jz] = T_electron[rup.ind][jy-1][jz] + gradient_T_electron; - #endif - } - #ifdef LOCALHEATFLUX - // Set it up so that the fourth-order central finite difference derivative at CELL_YLOW of mesh->ystart is gradient_T_electron - T_electron[rup.ind][mesh->yend][jz] = T_electron[rup.ind][mesh->yend-1][jz] + gradient_T_electron; - T_electron[rup.ind][mesh->yend+1][jz] = T_electron[rup.ind][mesh->yend-2][jz] + 3.*gradient_T_electron; - for (int jy=mesh->yend+2; jyLocalNy; jy++) - T_electron[rup.ind][jy][jz] = T_electron[rup.ind][jy-1][jz] + gradient_T_electron; - #endif - } - else - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) { - #ifdef LOCALHEATFLUX - BoutReal sheath_potential = 0.5*T_electron[rup.ind][mesh->yend][jz]*log(2*PI*electron_mass/ion_mass*(1+gamma_factor*T_ion[rup.ind][mesh->yend][jz]/T_electron[rup.ind][mesh->yend][jz])); - #ifdef FLUXLIMITER - // Include the flux limiter in the boundary condition: i.e. find the gradient needed to give the right boundary heat-flux AFTER applying the flux-limiter - BoutReal qbc_over_n = ((2.0-2.5)*T_electron[rup.ind][mesh->yend][jz]-sheath_potential) - *sqrt((T_electron[rup.ind][mesh->yend][jz]+gamma_factor*T_ion[rup.ind][mesh->yend][jz])/ion_mass); // -2.5*Te so that we subtract off the convective heat flux to leave just the conductive heat flux, not the total - BoutReal qBrag_over_n = 1./(1./qbc_over_n-1./electron_flux_limiter/( sqrt(2./electron_mass)*pow(T_electron[rup.ind][mesh->yend][jz],1.5) )); - BoutReal gradient_T_electron = qBrag_over_n - /(-3.16*T_electron[rup.ind][mesh->yend][jz]*tau_ei[rup.ind][mesh->yend][jz]/electron_mass) - *mesh->dy[rup.ind][mesh->yend-1]*sqrt(mesh->g_22[rup.ind][mesh->yend-1]); - #else - BoutReal gradient_T_electron = ((2.0-2.5)*T_electron[rup.ind][mesh->yend][jz]-sheath_potential) - *sqrt((T_electron[rup.ind][mesh->yend][jz]+gamma_factor*T_ion[rup.ind][mesh->yend][jz])/ion_mass) - /(-3.16*T_electron[rup.ind][mesh->yend][jz]*tau_ei[rup.ind][mesh->yend][jz]/electron_mass) - *mesh->dy[rup.ind][mesh->yend]*sqrt(mesh->g_22[rup.ind][mesh->yend]); // -2.5*Te so that we subtract off the convective heat flux to leave just the conductive heat flux, not the total - #endif - #else - // BoutReal gradient_T_electron = (11.*T_electron[rup.ind][mesh->yend][jz] - 18.*T_electron[rup.ind][mesh->yend-1][jz] + 9.*T_electron[rup.ind][mesh->yend-2][jz] - 2.*T_electron[rup.ind][mesh->yend-3][jz]) / 6. / mesh->dy[rup.ind][mesh->yend] / sqrt((mesh->g_22[rup.ind][mesh->yend]+mesh->g_22[rup.ind][mesh->yend-1]+mesh->g_22[rup.ind][mesh->yend-2]+mesh->g_22[rup.ind][mesh->yend-3])/4.); - BoutReal gradient_T_electron = (-T_electron[rup.ind][mesh->yend-boundary_gradient_smoothing_length][jz] + T_electron[rup.ind][mesh->yend][jz])/BoutReal(boundary_gradient_smoothing_length); - #endif - // BoutReal gradient_n = (11.*n_ion[rup.ind][mesh->yend][jz] - 18.*n_ion[rup.ind][mesh->yend-1][jz] + 9.*n_ion[rup.ind][mesh->yend-2][jz] - 2.*n_ion[rup.ind][mesh->yend-3][jz]) / 6. / mesh->dy[rup.ind][mesh->yend] / sqrt((mesh->g_22[rup.ind][mesh->yend]+mesh->g_22[rup.ind][mesh->yend-1]+mesh->g_22[rup.ind][mesh->yend-2]+mesh->g_22[rup.ind][mesh->yend-3])/4.); - BoutReal gradient_n = (-n_ion[rup.ind][mesh->yend-boundary_gradient_smoothing_length][jz] + n_ion[rup.ind][mesh->yend][jz])/BoutReal(boundary_gradient_smoothing_length); - // BoutReal gradient_T_ion = (11.*T_ion[rup.ind][mesh->yend][jz] - 18.*T_ion[rup.ind][mesh->yend-1][jz] + 9.*T_ion[rup.ind][mesh->yend-2][jz] - 2.*T_ion[rup.ind][mesh->yend-3][jz]) / 6. / mesh->dy[rup.ind][mesh->yend] / sqrt((mesh->g_22[rup.ind][mesh->yend]+mesh->g_22[rup.ind][mesh->yend-1]+mesh->g_22[rup.ind][mesh->yend-2]+mesh->g_22[rup.ind][mesh->yend-3])/4.); - BoutReal gradient_T_ion = (-T_ion[rup.ind][mesh->yend-boundary_gradient_smoothing_length][jz] + T_ion[rup.ind][mesh->yend][jz])/BoutReal(boundary_gradient_smoothing_length); - for (int jy=mesh->yend+1; jyLocalNy; jy++) { - n_ion[rup.ind][jy][jz] = n_ion[rup.ind][jy-1][jz] + gradient_n; - T_ion[rup.ind][jy][jz] = T_ion[rup.ind][jy-1][jz] + gradient_T_ion; - #ifndef LOCALHEATFLUX - T_electron[rup.ind][jy][jz] = T_electron[rup.ind][jy-1][jz] + gradient_T_electron; - #endif - } - #ifdef LOCALHEATFLUX - // Set it up so that the fourth-order central finite difference derivative at CELL_YLOW of mesh->ystart is gradient_T_electron - T_electron[rup.ind][mesh->yend+1][jz] = T_electron[rup.ind][mesh->yend][jz] + gradient_T_electron; - T_electron[rup.ind][mesh->yend+2][jz] = T_electron[rup.ind][mesh->yend-1][jz] + 3.*gradient_T_electron; - for (int jy=mesh->yend+3; jyLocalNy; jy++) - T_electron[rup.ind][jy][jz] = T_electron[rup.ind][jy-1][jz] + gradient_T_electron; - #endif - } - // Enforce Vpar_ion=c_s at the boundaries, but only if it tends to increase the magnitude of the velocity (i.e. allow (hopefully temporary) supersonic velocities). - // Apply the test at the point just inside the boundary so that the boundary point never needs to be evolved by the solver. - for (RangeIterator rlow = mesh->iterateBndryLowerY(); !rlow.isDone(); rlow++) - for (int jz=0; jzLocalNz; jz++) { - BoutReal boundarygradient; - position.jx=rlow.ind; - position.jy=mesh->ystart; - position.jz=jz; - calc_index(&position); - BoutReal boundary_value_Vpar = -sqrt(nonlocal_parallel.interp_to_point_YLOW(T_electron,position)+gamma_factor*nonlocal_parallel.interp_to_point_YLOW(T_ion,position))/sqrt(ion_mass); - Vpar_ion[rlow.ind][mesh->ystart][jz] = boundary_value_Vpar; - // BoutReal boundarygradient = (-11.*Vpar_ion[rlow.ind][mesh->ystart][jz] + 18.*Vpar_ion[rlow.ind][mesh->ystart+1][jz] - 9.*Vpar_ion[rlow.ind][mesh->ystart+2][jz] + 2.*Vpar_ion[rlow.ind][mesh->ystart+3][jz]) / 6. / mesh->dy[rlow.ind][mesh->ystart] / sqrt((mesh->g_22[rlow.ind][mesh->ystart]+mesh->g_22[rlow.ind][mesh->ystart+1]+mesh->g_22[rlow.ind][mesh->ystart+2]+mesh->g_22[rlow.ind][mesh->ystart+3])/4.); - boundarygradient = (-Vpar_ion[rlow.ind][mesh->ystart][jz] + Vpar_ion[rlow.ind][mesh->ystart+boundary_gradient_smoothing_length][jz])/BoutReal(boundary_gradient_smoothing_length); - for (int jy=mesh->ystart-1; jy>=0; jy--) - Vpar_ion[rlow.ind][jy][jz] = Vpar_ion[rlow.ind][jy+1][jz] - boundarygradient; - // Vpar_ion[rlow.ind][jy][jz] = Vpar_ion[rlow.ind][jy+1][jz]; - } - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) { - BoutReal boundarygradient; - position.jx=rup.ind; - position.jy=mesh->yend; - position.jz=jz; - calc_index(&position); - BoutReal boundary_value_Vpar = sqrt(nonlocal_parallel.interp_to_point_YLOW(T_electron,position)+gamma_factor*nonlocal_parallel.interp_to_point_YLOW(T_ion,position))/sqrt(ion_mass); - Vpar_ion[rup.ind][mesh->yend][jz] = boundary_value_Vpar; - // BoutReal boundarygradient = (11.*Vpar_ion[rup.ind][mesh->yend][jz] - 18.*Vpar_ion[rup.ind][mesh->yend-1][jz] + 9.*Vpar_ion[rup.ind][mesh->yend-2][jz] - 2.*Vpar_ion[rup.ind][mesh->yend-3][jz]) / 6. / mesh->dy[rup.ind][mesh->yend] / sqrt((mesh->g_22[rup.ind][mesh->yend]+mesh->g_22[rup.ind][mesh->yend-1]+mesh->g_22[rup.ind][mesh->yend-2]+mesh->g_22[rup.ind][mesh->yend-3])/4.); - boundarygradient = (-Vpar_ion[rup.ind][mesh->yend-boundary_gradient_smoothing_length][jz] + Vpar_ion[rup.ind][mesh->yend][jz])/BoutReal(boundary_gradient_smoothing_length); - for (int jy=mesh->yend+1; jyLocalNy; jy++) - Vpar_ion[rup.ind][jy][jz] = Vpar_ion[rup.ind][jy-1][jz] + boundarygradient; - // Vpar_ion[rup.ind][jy][jz] = Vpar_ion[rup.ind][jy-1][jz]; - } - #endif - // The boundary condition on the temperature gradient sometimes makes the temperature in the guard cells negative. - // If this happens set the temperature to zero there and also replace tau with an extrapolated version using forward/backward finite difference derivatives - for (RangeIterator rlow = mesh->iterateBndryLowerY(); !rlow.isDone(); rlow++) - for (int jz=0; jzLocalNz; jz++) - for (int jy=mesh->ystart-1; jy>=0; jy--) { - if (T_ion[rlow.ind][jy][jz]<0.) { - T_ion[rlow.ind][jy][jz] = 0.; - tau_ii[rlow.ind][jy][jz] = tau_ii[rlow.ind][jy+1][jz]-(-11.*tau_ii[rlow.ind][jy+1][jz] + 18.*tau_ii[rlow.ind][jy+2][jz] - 9.*tau_ii[rlow.ind][jy+3][jz] + 2.*tau_ii[rlow.ind][jy+4][jz])/ 6.; - } - if (T_electron[rlow.ind][jy][jz]<0.) { - T_electron[rlow.ind][jy][jz] = 0.; - tau_ei[rlow.ind][jy][jz] = tau_ei[rlow.ind][jy+1][jz]-(-11.*tau_ei[rlow.ind][jy+1][jz] + 18.*tau_ei[rlow.ind][jy+2][jz] - 9.*tau_ei[rlow.ind][jy+3][jz] + 2.*tau_ei[rlow.ind][jy+4][jz])/ 6.; - } - } - if (mesh->StaggerGrids) - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) - for (int jy=mesh->yend; jyLocalNy; jy++) { - if (T_ion[rup.ind][jy][jz]<0.) { - T_ion[rup.ind][jy][jz] = 0.; - tau_ii[rup.ind][jy][jz] = tau_ii[rup.ind][jy-1][jz] + (11.*tau_ii[rup.ind][jy-1][jz] - 18.*tau_ii[rup.ind][jy-2][jz] + 9.*tau_ii[rup.ind][jy-3][jz] - 2.*tau_ii[rup.ind][jy-4][jz])/ 6.; - } - if (T_electron[rup.ind][jy][jz]<0.) { - T_electron[rup.ind][jy][jz] = 0.; - tau_ei[rup.ind][jy][jz] = tau_ei[rup.ind][jy-1][jz] + (11.*tau_ei[rup.ind][jy-1][jz] - 18.*tau_ei[rup.ind][jy-2][jz] + 9.*tau_ei[rup.ind][jy-3][jz] - 2.*tau_ei[rup.ind][jy-4][jz])/ 6.; - } - } - else - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) - for (int jy=mesh->yend+1; jyLocalNy; jy++) { - if (T_ion(rup.ind,jy,jz)<0.) { - T_ion(rup.ind,jy,jz) = 0.; - tau_ii(rup.ind,jy,jz) = tau_ii(rup.ind,jy-1,jz) + (11.*tau_ii(rup.ind,jy-1,jz) - 18.*tau_ii(rup.ind,jy-2,jz) + 9.*tau_ii(rup.ind,jy-3,jz) - 2.*tau_ii(rup.ind,jy-4,jz))/ 6.; - } - if (T_electron(rup.ind,jy,jz)<0.) { - T_electron(rup.ind,jy,jz) = 0.; - tau_ei(rup.ind,jy,jz) = tau_ei(rup.ind,jy-1,jz) + (11.*tau_ei(rup.ind,jy-1,jz) - 18.*tau_ei(rup.ind,jy-2,jz) + 9.*tau_ei(rup.ind,jy-3,jz) - 2.*tau_ei(rup.ind,jy-4,jz))/ 6.; - } - } - - nTtau_ion = n_ion * T_ion * sqrt(2) * tau_ii; - - #ifndef LOCALHEATFLUX - for (RangeIterator rlow = mesh->iterateBndryLowerY(); !rlow.isDone(); rlow++) - for (int jz=0; jzLocalNz; jz++) { - position.jx=rlow.ind; - position.jy=mesh->ystart; - position.jz=jz; - calc_index(&position); - BoutReal Te_here = nonlocal_parallel.interp_to_point_YLOW(T_electron,position); - BoutReal V_here = Vpar_ion[rlow.ind][mesh->ystart][jz]; - BoutReal n_here = nonlocal_parallel.interp_to_point_YLOW(n_ion,position); - BoutReal sheath_potential = 0.5*Te_here*log(2*PI*electron_mass*pow(V_here,2)/Te_here); - heat_flux_boundary_condition[rlow.ind][mesh->ystart][jz] = ((2.0-2.5)*Te_here-sheath_potential)*n_here*V_here; // -2.5*Te so that we subtract off the convective heat flux to leave just the conductive heat flux, not the total - } - - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) { - position.jx=rup.ind; - position.jy=mesh->yend; - position.jz=jz; - calc_index(&position); - BoutReal Te_here = nonlocal_parallel.interp_to_point_YLOW(T_electron,position); - BoutReal V_here = Vpar_ion[rup.ind][mesh->yend][jz]; - BoutReal n_here = nonlocal_parallel.interp_to_point_YLOW(n_ion,position); - BoutReal sheath_potential = 0.5*Te_here*log(2*PI*electron_mass*pow(V_here,2)/Te_here); - heat_flux_boundary_condition[rup.ind][mesh->yend][jz] = ((2.0-2.5)*Te_here-sheath_potential)*n_here*V_here; // -2.5*Te so that we subtract off the convective heat flux to leave just the conductive heat flux, not the total - } - -// VeminusVi = -j_parallel/n_ion/electron_charge; - Field3D zero = 0.; - nonlocal_parallel.calculate_nonlocal_closures(n_ion, T_electron, Vpar_ion+j_parallel/electron_charge/interp_to(n_ion,CELL_YLOW), j_parallel, heat_flux_boundary_condition, zero); -// nonlocal_parallel.calculate_nonlocal_closures(n_ion, T_electron, Vpar_ion+VeminusVi, VeminusVi, heat_flux_boundary_condition); - - #ifdef CUSTOMBCS - nonlocal_parallel.set_boundary_gradients(); - #else - nonlocal_parallel.set_neumann_boundary_conditions(); - #endif - #endif - - #ifndef LOCALHEATFLUX - try { - ratio = (-3.16*interp_to(n_ion*T_electron*tau_ei/electron_mass,CELL_YLOW)*Grad_par(T_electron,CELL_YLOW))/nonlocal_parallel.electron_heat_flux; - } catch (BoutException &error) { - // Don't really care if there are errors in the calculation of ratio as it is only a diagnostic variable: IGNORE - } - #endif - - #ifdef CALCULATE_EFFECTIVE_ALPHAE - Field3D q_Brag = -3.16*interp_to(n_ion*T_electron*tau_ei,CELL_YLOW)/electron_mass*Grad_par(T_electron,CELL_YLOW); - Field3D q_FS = interp_to(sqrt(2./electron_mass)*n_ion*(T_electron^1.5),CELL_YLOW); - nonlocal_parallel.mean_over_y( 1./q_FS/abs( 1./nonlocal_parallel.electron_heat_flux-1./q_Brag) , effective_alpha_e); - #endif - - #if defined FLUXLIMITER - grad_par_T_electron = Grad_par(T_electron,CELL_CENTRE); - qSH_electron = -3.16/electron_mass*n_ion*T_electron*tau_ei*grad_par_T_electron; - qFS_electron = sqrt(2./electron_mass)*n_ion*(T_electron^1.5); - grad_par_electron_heat_flux = electron_flux_limiter / ((abs(qSH_electron)/qFS_electron+electron_flux_limiter)^2) - * (qSH_electron*abs(qSH_electron)/(qFS_electron^2)*sqrt(2./electron_mass)*Grad_par(n_ion*(T_electron^1.5),CELL_CENTRE) - - electron_flux_limiter*3.16/electron_mass*(Grad_par(n_ion*T_electron*tau_ei,CELL_CENTRE)*grad_par_T_electron + n_ion*T_electron*tau_ei*Grad2_par2(T_electron,CELL_CENTRE))); - ddt(T_electron) = -Vpar_Grad_par(Vpar_ion,T_electron,CELL_CENTRE) - - 2./3.*T_electron*Grad_par(Vpar_ion,CELL_CENTRE) - - 2./3./n_ion*grad_par_electron_heat_flux - + 2./3./n_ion * sources.electron_heat_source(t) - T_electron/n_ion*sources.particle_source(t); - #elif defined LOCALHEATFLUX - ddt(T_electron) = -Vpar_Grad_par(Vpar_ion,T_electron,CELL_CENTRE) - - 2./3.*T_electron*Grad_par(Vpar_ion,CELL_CENTRE) - - 2./3./n_ion*(-3.16/electron_mass*(Grad_par(n_ion*T_electron*tau_ei,CELL_CENTRE)*Grad_par(T_electron,CELL_CENTRE)+n_ion*T_electron*tau_ei*Grad2_par2(T_electron,CELL_CENTRE))) - + 2./3./n_ion * sources.electron_heat_source(t) - T_electron/n_ion*sources.particle_source(t); - #else - ddt(T_electron) = -Vpar_Grad_par(Vpar_ion,T_electron,CELL_CENTRE) - - 2./3.*T_electron*Grad_par(Vpar_ion,CELL_CENTRE) - - 2./3./n_ion*Grad_par(nonlocal_parallel.electron_heat_flux,CELL_CENTRE) - + 2./3./n_ion * sources.electron_heat_source(t) - T_electron/n_ion*sources.particle_source(t); - #endif - ddt(n_ion) = -Vpar_Grad_par(Vpar_ion,n_ion,CELL_CENTRE) - - n_ion*Grad_par(Vpar_ion,CELL_CENTRE) - + sources.particle_source(t); - - #ifdef IONVISCOSITYLIMITER - nTtau_ion_ylow = interp_to(nTtau_ion,CELL_YLOW); - pi_Brag_ylow = -4./3.*0.96*nTtau_ion_ylow*Grad_par(Vpar_ion,CELL_YLOW); - grad_par_viscosity = ion_viscosity_limiter / (( abs(pi_Brag_ylow)/interp_to(n_ion*T_ion,CELL_YLOW) + ion_viscosity_limiter )^2) - * ( -ion_viscosity_limiter*4./3.*0.96*(Grad_par(nTtau_ion,CELL_YLOW)*Grad_par(Vpar_ion,CELL_YLOW) + nTtau_ion_ylow*Grad2_par2(Vpar_ion,CELL_YLOW)) - +pi_Brag_ylow*abs(pi_Brag_ylow)/interp_to((n_ion*T_ion)^2,CELL_YLOW)*Grad_par(n_ion*T_ion,CELL_YLOW) ); - #endif - ddt(Vpar_ion) = -Vpar_Grad_par(Vpar_ion,Vpar_ion,CELL_YLOW) - + interp_to(1./(ion_mass*n_ion),CELL_YLOW) * (-Grad_par(n_ion*(T_ion+T_electron),CELL_YLOW) - #ifdef IONVISCOSITYLIMITER - - grad_par_viscosity) - #else - + 4./3.*0.96*Grad_par(nTtau_ion,CELL_YLOW)*Grad_par(Vpar_ion,CELL_YLOW)) - + 1./ion_mass * 4./3.*0.96*interp_to(T_ion * sqrt(2) * tau_ii,CELL_YLOW) * Grad2_par2(Vpar_ion,CELL_YLOW) - #endif - - Vpar_ion*interp_to(sources.particle_source(t)/n_ion,CELL_YLOW); // The sources of heat and particles do not add any momentum, so V decreases in proportion to the increase in n. - - #ifdef IONFLUXLIMITER - grad_par_T_ion = Grad_par(T_ion,CELL_CENTRE); - qSH_ion = -3.9/ion_mass*nTtau_ion*grad_par_T_ion; - qFS_ion = sqrt(2./ion_mass)*n_ion*(T_ion^1.5); - grad_par_ion_heat_flux = ion_flux_limiter / ((abs(qSH_ion)/qFS_ion+ion_flux_limiter)^2) - * (qSH_ion*abs(qSH_ion)/(qFS_ion^2)*sqrt(2./ion_mass)*Grad_par(n_ion*(T_ion^1.5),CELL_CENTRE) - - ion_flux_limiter*3.9/ion_mass*(Grad_par(nTtau_ion,CELL_CENTRE)*grad_par_T_ion + nTtau_ion*Grad2_par2(T_ion,CELL_CENTRE))); - #endif - #ifdef IONVISCOSITYLIMITER - grad_par_V_centre = Grad_par(Vpar_ion,CELL_CENTRE); - pi_Brag_centre = -4./3.*0.96*nTtau_ion*grad_par_V_centre; - viscosity = ion_viscosity_limiter*pi_Brag_centre / ( abs(pi_Brag_centre)/n_ion/T_ion + ion_viscosity_limiter ); - #endif - ddt(T_ion) = -Vpar_Grad_par(Vpar_ion,T_ion,CELL_CENTRE) - - 2./3.*T_ion*Grad_par(Vpar_ion,CELL_CENTRE) - #ifdef IONFLUXLIMITER - - 2./3./n_ion * grad_par_ion_heat_flux - #else - + 2./3./n_ion * 3.9/ion_mass*(Grad_par(nTtau_ion,CELL_CENTRE)*Grad_par(T_ion,CELL_CENTRE) - + nTtau_ion * Grad2_par2(T_ion,CELL_CENTRE)) - #endif - #ifdef IONVISCOSITYLIMITER - - 2./3./n_ion * viscosity*grad_par_V_centre - #else - + 2./3./n_ion * 4./3.*0.96*nTtau_ion*(Grad_par(Vpar_ion,CELL_CENTRE)^2) - #endif - + 2./3./n_ion * sources.ion_heat_source(t) - T_ion/n_ion*sources.particle_source(t); - - ddt(j_parallel) = 0.; - - #ifdef CUSTOMBCS - for (RangeIterator rlow = mesh->iterateBndryLowerY(); !rlow.isDone(); rlow++) - for (int jz=0; jzLocalNz; jz++) { - for (int jy=mesh->ystart-1; jy>=0; jy--) { - ddt(n_ion)(rlow.ind,jy,jz) = 0.; - ddt(T_ion)(rlow.ind,jy,jz) = 0.; - ddt(T_electron)(rlow.ind,jy,jz) = 0.; - } - } - if (mesh->StaggerGrids) - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) { - for (int jy=mesh->yend; jyLocalNy; jy++) { - ddt(n_ion)(rup.ind,jy,jz) = 0.; - ddt(T_ion)(rup.ind,jy,jz) = 0.; - ddt(T_electron)(rup.ind,jy,jz) = 0.; - } - } - else - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) { - for (int jy=mesh->yend+1; jyLocalNy; jy++) { - ddt(n_ion)(rup.ind,jy,jz) = 0.; - ddt(T_ion)(rup.ind,jy,jz) = 0.; - ddt(T_electron)(rup.ind,jy,jz) = 0.; - } - } - - for (RangeIterator rlow = mesh->iterateBndryLowerY(); !rlow.isDone(); rlow++) - for (int jz=0; jzLocalNz; jz++) { - for (int jy=mesh->ystart; jy>=0; jy--) - ddt(Vpar_ion)(rlow.ind,jy,jz) = 0.; - } - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) { - for (int jy=mesh->yend; jyLocalNy; jy++) - ddt(Vpar_ion)(rup.ind,jy,jz) = 0.; - } - #endif - - return 0; -} diff --git a/examples/non-local_1d/non-local_parallel.cxx b/examples/non-local_1d/non-local_parallel.cxx deleted file mode 100644 index 8bdae31f52..0000000000 --- a/examples/non-local_1d/non-local_parallel.cxx +++ /dev/null @@ -1,2030 +0,0 @@ -/*! - * \file heat_flux_integration.cxx - * - * \brief Calculate non-local electron closures - * - * - ************************************************************************** - * Copyright 2012 J.T.Omotani - * - * Contact: John Omotani, john.omotani@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - */ - -#include "non-local_parallel.hxx" - -// #include - -// #define NOEDGETERMS - -BoutReal NonLocalParallelgamma_factor = 3.; - -/********************************************************************************** - * HEAT FLUX INITIALISATION AND CREATION * - **********************************************************************************/ - - -NonLocalParallel::~NonLocalParallel() { - delete [] eigenvalues; - #ifdef CALCULATE_HEATFLUX - #ifdef DRIVE_GRADT - delete [] heatflux_gradT_coefficients; - #endif - #ifdef DRIVE_GRADV - delete [] heatflux_gradV_coefficients; - #endif - #ifdef DRIVE_VEMINUSVI - delete [] heatflux_VeminusVi_coefficients; - #endif - delete [] heatflux_lower_boundary_transients; - delete [] heatflux_upper_boundary_transients; - #endif - #ifdef BC_HEATFLUX - delete [] heatflux_transients_factors; - delete [] W11_B_times_WinverseB_11; - #ifdef BC_VISCOSITY - delete [] W11_B_times_WinverseB_20; - #endif - #endif - #ifdef CALCULATE_VISCOSITY - #ifdef DRIVE_GRADT - delete [] viscosity_gradT_coefficients; - #endif - #ifdef DRIVE_GRADV - delete [] viscosity_gradV_coefficients; - #endif - #ifdef DRIVE_VEMINUSVI - delete [] viscosity_VeminusVi_coefficients; - #endif - delete [] viscosity_lower_boundary_transients; - delete [] viscosity_upper_boundary_transients; - #endif - #ifdef BC_VISCOSITY - delete [] viscosity_transients_factors; - delete [] W20_B_times_WinverseB_20; - #ifdef BC_HEATFLUX - delete [] W20_B_times_WinverseB_11; - #endif - #endif - #ifdef CALCULATE_FRICTION - #ifdef DRIVE_GRADT - delete [] friction_gradT_coefficients; - #endif - #ifdef DRIVE_GRADV - delete [] friction_gradV_coefficients; - #endif - #ifdef DRIVE_VEMINUSVI - delete [] friction_VeminusVi_coefficients; - #endif - delete [] friction_lower_boundary_transients; - delete [] friction_upper_boundary_transients; - #ifdef BC_HEATFLUX - delete [] C10_1k_dot_W1k_B_times_WinverseB_11; - #endif - #ifdef BC_VISCOSITY - delete [] C10_1k_dot_W1k_B_times_WinverseB_20; - #endif - #endif - if (is_lower_boundary) { - delete [] exp_total_dimensionless_length_over_eigenvalue; - } - MPI_Comm_free(&comm_yprocs_minusone); -} - -void NonLocalParallel::initialise(BoutReal pass_electron_charge, BoutReal pass_electron_mass, BoutReal pass_ion_mass, BoutReal pass_epsilon_0, BoutReal pass_logLambda, const bool pass_fluxes_location_is_ylow, BoutReal pass_gamma_factor) { - fluxes_location_is_ylow = pass_fluxes_location_is_ylow; - #if CHECK > 0 - calculated_before_setting_bcs=false; - #endif - is_lower_boundary=mesh->firstY(); - is_upper_boundary=mesh->lastY(); - boundary_gradient_smoothing_length = mesh->GlobalNy/256; // Number of grid points to average over for the gradient used to extrapolate to the guard cells - boundary_condition_smoothing_range = BoutReal(mesh->GlobalNy)/64.; // Scale length of the exponential decay used to smoothly apply the boundary condition - if (boundary_gradient_smoothing_length==0) - boundary_gradient_smoothing_length = 1; - - if (fluxes_location_is_ylow && !mesh->StaggerGrids) - throw BoutException("Trying to calculate the heat flux at CELL_YLOW while StaggerGrids=false is an error."); - - cubic_spline_inverse_lambdaC.initialise('y',true,fluxes_location_is_ylow); - if (fluxes_location_is_ylow) { - #ifdef DRIVE_GRADT - cubic_spline_gradT_driveterm.initialise('y',true,true); // CELL_CENTRE quantity, so must be adjusted when the grids are staggered. - cubic_spline_gradT.initialise('y',true,false); // will fix up the boundary guard cells with forward/backward derivatives, since at least one guard cell value will be needed - #endif - #ifdef DRIVE_GRADV - cubic_spline_gradV_driveterm.initialise('y',false,true); // CELL_CENTRE quantity, so must be adjusted when the grids are staggered. - cubic_spline_one.initialise('y',true,false); - Field3D one = 1.; - cubic_spline_one.calculate(one); - #endif - #ifdef DRIVE_VEMINUSVI - cubic_spline_VeminusVi_driveterm.initialise('y',true,true); - cubic_spline_jpar.initialise('y',true,false); - #endif - } - else { - #ifdef DRIVE_GRADT - cubic_spline_gradT_driveterm.initialise('y',false,false); // false because gradT_driveterm includes a derivative, so we don't know it in the guard cells, hence calculate the interpolation excluding the guard cells at the target boundaries. - #endif - #ifdef DRIVE_GRADV - cubic_spline_gradV_driveterm.initialise('y',false,false); // false because gradT_driveterm includes a derivative, so we don't know it in the guard cells, hence calculate the interpolation excluding the guard cells at the target boundaries. - #endif - #ifdef DRIVE_VEMINUSVI - cubic_spline_VeminusVi_driveterm.initialise('y',true,false); - #endif - } - - // Get the options for the model - Options *options = Options::getRoot()->getSection("non_local_parallel"); - OPTION(options, moments_number, 10); - OPTION(options, NONLOCAL_PARALLEL_TAGBASE, 12381); - - position = new bindex; - broadcast_request = MPI_REQUEST_NULL; - - electron_charge = pass_electron_charge; - electron_mass = pass_electron_mass; - ion_mass = pass_ion_mass; - epsilon_0 = pass_epsilon_0; - logLambda = pass_logLambda; - NonLocalParallelgamma_factor = pass_gamma_factor; - - if (fluxes_location_is_ylow) { - increasing_dimensionless_length.setLocation(CELL_YLOW); - decreasing_dimensionless_length.setLocation(CELL_YLOW); - #ifdef CALCULATE_HEATFLUX - electron_heat_flux.setLocation(CELL_YLOW); - #endif - #ifdef CALCULATE_VISCOSITY - electron_viscosity.setLocation(CELL_YLOW); // should really have this as CELL_CENTRE quantity, but then would have to calculate the integrals on both CELL_CENTRE and CELL_YLOW which is perfectly possible but has not been implemented yet - #endif - #ifdef CALCULATE_FRICTION - electron_friction.setLocation(CELL_YLOW); - #endif - #ifdef DRIVE_GRADT - gradT_electron.setLocation(CELL_YLOW); - gradT_electron=0.; - #endif - #ifdef DRIVE_GRADV - // No CELL_YLOW drive terms here - #endif - #ifdef DRIVE_VEMINUSVI - // VeminusVi already CELL_YLOW - #endif - } - - #ifdef CALCULATE_HEATFLUX - electron_heat_flux = 0.; - #endif - #ifdef CALCULATE_VISCOSITY - electron_viscosity = 0.; - #endif - #ifdef CALCULATE_FRICTION - electron_friction = 0.; - #endif - #ifdef DRIVE_GRADT - gradT_driveterm = 0.; - #endif - #ifdef DRIVE_GRADV - gradV_driveterm = 0.; - #endif - #ifdef DRIVE_VEMINUSVI - VeminusVi_driveterm = 0.; - #endif - lambdaC_inverse = 0.; - increasing_dimensionless_length = 0.; - decreasing_dimensionless_length = 0.; - dimensionless_length_deltas_above = 0.; - if (fluxes_location_is_ylow) - dimensionless_length_deltas_below=0.; - total_dimensionless_length = 1./0.; - - integration.initialise(fluxes_location_is_ylow); - - // Get model's eigenvalues and coefficients from files - BoutReal junk; - #ifdef CALCULATE_HEATFLUX - std::stringstream heatflux_infilename; - heatflux_infilename<<"nonlocal_coefficients/heatfluxcoeffs"<>number_of_negative_eigenvalues; - #ifndef ALLOCATED_EIGENVALUES - #define ALLOCATED_EIGENVALUES - eigenvalues = new BoutReal[number_of_negative_eigenvalues]; - #endif - #ifdef DRIVE_GRADT - heatflux_gradT_coefficients = new BoutReal[number_of_negative_eigenvalues]; - #endif - #ifdef DRIVE_GRADV - heatflux_gradV_coefficients = new BoutReal[number_of_negative_eigenvalues]; - #endif - #ifdef DRIVE_VEMINUSVI - heatflux_VeminusVi_coefficients = new BoutReal[number_of_negative_eigenvalues]; - #endif - #ifdef DRIVE_GRADT - heatflux_infile>>heatflux_gradT_zerocoeff; - #else - heatflux_infile>>junk; - #endif - #ifdef DRIVE_GRADV - heatflux_infile>>junk; // the zero eigenvector has only odd-l components, so the gradV drive (which is (2,0)) does not contribute - #else - heatflux_infile>>junk; - #endif - #ifdef DRIVE_VEMINUSVI - heatflux_infile>>heatflux_VeminusVi_zerocoeff; - #else - heatflux_infile>>junk; - #endif - for (int i=0; i>eigenvalues[i]; - #ifdef DRIVE_GRADT - heatflux_infile>>heatflux_gradT_coefficients[i]; - #else - heatflux_infile>>junk; - #endif - #ifdef DRIVE_GRADV - heatflux_infile>>heatflux_gradV_coefficients[i]; - #else - heatflux_infile>>junk; - #endif - #ifdef DRIVE_VEMINUSVI - heatflux_infile>>heatflux_VeminusVi_coefficients[i]; - #else - heatflux_infile>>junk; - #endif - } - heatflux_infile.close(); - std::stringstream heatfluxbc_infilename; - heatfluxbc_infilename<<"nonlocal_coefficients/heatfluxbc"<>W11_dot_W11; - #else - heatfluxbc_infile>>junk; - #endif - #ifdef BC_VISCOSITY - heatfluxbc_infile>>W11_dot_W20; - #else - heatfluxbc_infile>>junk; - #endif - for (int i=0; i>W11_B_times_WinverseB_11[i]; - #else - heatfluxbc_infile>>junk; - #endif - #ifdef BC_VISCOSITY - heatfluxbc_infile>>W11_B_times_WinverseB_20[i]; - #else - heatfluxbc_infile>>junk; - #endif - } - heatfluxbc_infile.close(); - #endif - #ifdef BC_HEATFLUX - if (is_lower_boundary || is_upper_boundary) { - pass_interim_upper_boundary_n11 = 0.; - upper_boundary_condition_n11 = 0.; - } - #endif - #ifdef CALCULATE_VISCOSITY - std::stringstream viscosity_infilename; - viscosity_infilename<<"nonlocal_coefficients/viscositycoeffs"<>number_of_negative_eigenvalues; - #ifndef ALLOCATED_EIGENVALUES - #define ALLOCATED_EIGENVALUES - eigenvalues = new BoutReal[number_of_negative_eigenvalues]; - #endif - #ifdef DRIVE_GRADT - viscosity_gradT_coefficients = new BoutReal[number_of_negative_eigenvalues]; - #endif - #ifdef DRIVE_GRADV - viscosity_gradV_coefficients = new BoutReal[number_of_negative_eigenvalues]; - #endif - #ifdef DRIVE_VEMINUSVI - viscosity_VeminusVi_coefficients = new BoutReal[number_of_negative_eigenvalues]; - #endif - #ifdef DRIVE_GRADT - viscosity_infile>>junk; // the zero eigenvector has only odd-l components, so does not contribute to the viscosity (2,0) - #else - viscosity_infile>>junk; - #endif - #ifdef DRIVE_GRADV - viscosity_infile>>junk; // the zero eigenvector has only odd-l components, so does not contribute to the viscosity (2,0) - #else - viscosity_infile>>junk; - #endif - #ifdef DRIVE_GRADV - viscosity_infile>>junk; // the zero eigenvector has only odd-l components, so does not contribute to the viscosity (2,0) - #else - viscosity_infile>>junk; - #endif - for (int i=0; i>eigenvalues[i]; - #ifdef DRIVE_GRADT - viscosity_infile>>viscosity_gradT_coefficients[i]; - #else - viscosity_infile>>junk; - #endif - #ifdef DRIVE_GRADV - viscosity_infile>>viscosity_gradV_coefficients[i]; - #else - viscosity_infile>>junk; - #endif - #ifdef DRIVE_VEMINUSVI - viscosity_infile>>viscosity_VeminusVi_coefficients[i]; - #else - viscosity_infile>>junk; - #endif - } - viscosity_infile.close(); - std::stringstream viscositybc_infilename; - viscositybc_infilename<<"nonlocal_coefficients/viscositybc"<>W20_dot_W20; - #else - viscositybc_infile>>junk; - #endif - #ifdef BC_HEATFLUX - viscositybc_infile>>W20_dot_W11; - #else - viscositybc_infile>>junk; - #endif - for (int i=0; i>W20_B_times_WinverseB_20[i]; - #else - viscositybc_infile>>junk; - #endif - #ifdef BC_HEATFLUX - viscositybc_infile>>W20_B_times_WinverseB_11[i]; - #else - viscositybc_infile>>junk; - #endif - } - viscositybc_infile.close(); - #endif - #ifdef BC_VISCOSITY - if (is_lower_boundary || is_upper_boundary) { - pass_interim_upper_boundary_n20 = 0.; - upper_boundary_condition_n20 = 0.; - } - #endif - #ifdef CALCULATE_FRICTION - std::stringstream friction_infilename; - friction_infilename<<"nonlocal_coefficients/frictioncoeffs"<>number_of_negative_eigenvalues; - #ifndef ALLOCATED_EIGENVALUES - #define ALLOCATED_EIGENVALUES - eigenvalues = new BoutReal[number_of_negative_eigenvalues]; - #endif - #ifdef DRIVE_GRADT - friction_gradT_coefficients = new BoutReal[number_of_negative_eigenvalues]; - #endif - #ifdef DRIVE_GRADV - friction_gradV_coefficients = new BoutReal[number_of_negative_eigenvalues]; - #endif - #ifdef DRIVE_VEMINUSVI - friction_VeminusVi_coefficients = new BoutReal[number_of_negative_eigenvalues]; - #endif - #ifdef DRIVE_GRADT - friction_infile>>friction_gradT_zerocoeff; - #else - friction_infile>>junk; - #endif - #ifdef DRIVE_GRADV - friction_infile>>junk; // the zero eigenvector has only odd-l components, so the gradV drive (which is (2,0)) does not contribute - #else - friction_infile>>junk; - #endif - #ifdef DRIVE_VEMINUSVI - friction_infile>>friction_VeminusVi_zerocoeff; - #else - friction_infile>>junk; - #endif - for (int i=0; i>eigenvalues[i]; - #ifdef DRIVE_GRADT - friction_infile>>friction_gradT_coefficients[i]; - #else - friction_infile>>junk; - #endif - #ifdef DRIVE_GRADV - friction_infile>>friction_gradV_coefficients[i]; - #else - friction_infile>>junk; - #endif - #ifdef DRIVE_VEMINUSVI - friction_infile>>friction_VeminusVi_coefficients[i]; - #else - friction_infile>>junk; - #endif - } - friction_infile.close(); - std::stringstream frictionbc_infilename; - frictionbc_infilename<<"nonlocal_coefficients/frictionbc"<>C10_1k_dot_W1k_B_times_WinverseB_11[i]; - #else - frictionbc_infile>>junk; - #endif - #ifdef BC_VISCOSITY - frictionbc_infile>>C10_1k_dot_W1k_B_times_WinverseB_20[i]; - #else - frictionbc_infile>>junk; - #endif - } - frictionbc_infile.close(); - #endif - - if (is_lower_boundary) { - exp_total_dimensionless_length_over_eigenvalue = new BoutReal[number_of_negative_eigenvalues]; - } - - #ifdef CALCULATE_HEATFLUX - heatflux_lower_boundary_transients = new FieldPerp[number_of_negative_eigenvalues]; - heatflux_upper_boundary_transients = new FieldPerp[number_of_negative_eigenvalues]; - for (int i=0; ixend-mesh->xstart+1)*(mesh->LocalNz)]; - #endif - #ifdef CALCULATE_VISCOSITY - viscosity_lower_boundary_transients = new FieldPerp[number_of_negative_eigenvalues]; - viscosity_upper_boundary_transients = new FieldPerp[number_of_negative_eigenvalues]; - for (int i=0; ixend-mesh->xstart+1)*(mesh->LocalNz)]; - #endif - #ifdef CALCULATE_FRICTION - friction_lower_boundary_transients = new FieldPerp[number_of_negative_eigenvalues]; - friction_upper_boundary_transients = new FieldPerp[number_of_negative_eigenvalues]; - for (int i=0; igetNYPE()-1; - int * indices_yprocs = new int[n_yprocs]; - for (int i=0; igetNXPE() + mesh->getXProcIndex(); - - MPI_Group group_world; - MPI_Comm_group(BoutComm::get(), &group_world); // Get the entire group - MPI_Group_incl(group_world, n_yprocs, indices_yprocs, &group_yprocs); - MPI_Group_free(&group_world); - delete [] indices_yprocs; - - MPI_Comm_create(BoutComm::get(), group_yprocs, &comm_yprocs_minusone); - MPI_Group_free(&group_yprocs); - } - -} - -/********************************************************************************** - * HEAT FLUX CALCULATION ROUTINES - **********************************************************************************/ - -void NonLocalParallel::calculate_nonlocal_closures(const Field3D &n_electron, const Field3D &T_electron - #ifdef DRIVE_GRADV - , const Field3D &V_electron - #endif - #ifdef DRIVE_VEMINUSVI - , const Field3D &jpar - #endif - #ifdef BC_HEATFLUX - , const Field3D &heat_flux_boundary_condition - #endif - #ifdef BC_VISCOSITY - , const Field3D &viscosity_boundary_condition - #endif - ) { - if (fluxes_location_is_ylow) - calculate_nonlocal_closures_cell_ylow(n_electron, T_electron - #ifdef DRIVE_GRADV - , V_electron - #endif - #ifdef DRIVE_VEMINUSVI - , jpar - #endif - #ifdef BC_HEATFLUX - , heat_flux_boundary_condition - #endif - #ifdef BC_VISCOSITY - , viscosity_boundary_condition - #endif - ); - else - calculate_nonlocal_closures_cell_centre(n_electron, T_electron - #ifdef DRIVE_GRADV - , V_electron - #endif - #ifdef DRIVE_VEMINUSVI - , jpar - #endif - #ifdef BC_HEATFLUX - , heat_flux_boundary_condition - #endif - #ifdef BC_VISCOSITY - , viscosity_boundary_condition - #endif - ); - #if CHECK > 0 - calculated_before_setting_bcs=true; - #endif -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void NonLocalParallel::calculate_nonlocal_closures_cell_centre(const Field3D &n_electron, const Field3D &T_electron - #ifdef DRIVE_GRADV - , const Field3D &V_electron - #endif - #ifdef DRIVE_VEMINUSVI - , const Field3D &jpar - #endif - #ifdef BC_HEATFLUX - , const Field3D &heat_flux_boundary_condition - #endif - #ifdef BC_VISCOSITY - , const Field3D &viscosity_boundary_condition - #endif - ) { - - lambdaC_inverse = n_electron * pow(electron_charge,4) * logLambda / 12 / pow(PI,1.5) / pow(epsilon_0,2) / (T_electron^2); - - #ifdef DRIVE_GRADT - gradT_driveterm = 5./4. * n_electron / T_electron * Grad_par(T_electron) / lambdaC_inverse; //g^(1,1) - mesh->communicate(gradT_driveterm); - #endif - #ifdef DRIVE_GRADV - gradV_driveterm = -0.5 * n_electron / sqrt(2.*T_electron/electron_mass) * Grad_par(V_electron) / lambdaC_inverse; - mesh->communicate(gradV_driveterm); - #endif - #ifdef DRIVE_VEMINUSVI - VeminusVi_driveterm = -2./sqrt(PI) * (-jpar/electron_charge) / sqrt(2.*T_electron/electron_mass); - mesh->communicate(VeminusVi_driveterm); - #endif - - // Now calculate z and deltaz everywhere - cubic_spline_inverse_lambdaC.calculate(lambdaC_inverse); - - start_index(position); - - if (mesh->UpXSplitIndex()!=0 || mesh->DownXSplitIndex()!=0) throw BoutException("This code cannot currently handle x-splitting of processors."); - if (!is_lower_boundary) { - FieldPerp pass_dimensionless_length; - pass_dimensionless_length.allocate(); - { - mesh->wait(mesh->irecvYInOutdest(*pass_dimensionless_length.getData(),mesh->LocalNx*(mesh->LocalNz), - NONLOCAL_PARALLEL_TAGBASE + position->jx*mesh->LocalNz+position->jz)); - } - pass_dimensionless_length.setIndex(mesh->ystart); - increasing_dimensionless_length = pass_dimensionless_length; - } - - do { - position->jy = mesh->ystart-1; - calc_index(position); - interp_coefficients = cubic_spline_inverse_lambdaC.coefficients(position); - // d/dy(delta) = 1/lambdaC = a + b*t + c*t^2 + d*t^3; t=(ind-jy)=(y-y0)/(sqrt(g_22)*dy); ind is a notional continuous variable equal to jy at the gridpoints so at jy+1 t=1 - - // Fetch coordinate system - Coordinates *coord = mesh->coordinates(); - dimensionless_length_deltas_above[*position] /* = dy/dt*(a + 1/2*b + 1/3*c + 1/4*d) */ - = coord->dy(position->jx,position->jy)*sqrt(0.5*(coord->g_22(position->jx,position->jy)+coord->g_22(position->jx,position->jyp))) - *(interp_coefficients[0] + interp_coefficients[1]/2. + interp_coefficients[2]/3. + interp_coefficients[3]/4.); - next_index_y(position); - - do{ - interp_coefficients = cubic_spline_inverse_lambdaC.coefficients(position); - // d/dy(delta) = 1/lambdaC = a + b*t + c*t^2 + d*t^3; t=(ind-jy)=(y-y0)/(sqrt(g_22)*dy); ind is a notional continuous variable equal to jy at the gridpoints so at jy+1 t=1 - dimensionless_length_deltas_above[*position] /* = dy/dt*(a + 1/2*b + 1/3*c + 1/4*d) */ - = coord->dy(position->jx,position->jy)*sqrt(0.5*(coord->g_22(position->jx,position->jy)+coord->g_22(position->jx,position->jyp))) - *(interp_coefficients[0] + interp_coefficients[1]/2. + interp_coefficients[2]/3. + interp_coefficients[3]/4.); - increasing_dimensionless_length(position->jx,position->jyp,position->jz) = increasing_dimensionless_length[*position] + dimensionless_length_deltas_above[*position]; - } while (next_index_y(position)); - - } while (next_indexperp(position)); - - { - Timer timer("comms"); - mesh->sendYOutOutdest(*increasing_dimensionless_length.slice(mesh->yend+1).getData(),mesh->LocalNx*(mesh->LocalNz), - NONLOCAL_PARALLEL_TAGBASE + position->jx*mesh->LocalNz+position->jz); - } - - // Send the total dimensionless_length at the upper boundary back to the other processors. - if (is_upper_boundary) - total_dimensionless_length = increasing_dimensionless_length.slice(mesh->yend); - - y_broadcast(*total_dimensionless_length.getData(), mesh->LocalNx*mesh->LocalNz, mesh->getNYPE()-1); - - decreasing_dimensionless_length = -increasing_dimensionless_length; - for (int jy=mesh->ystart; jy<=mesh->yend; jy++) { - total_dimensionless_length.setIndex(jy); - decreasing_dimensionless_length += total_dimensionless_length; - } - - #ifdef CALCULATE_HEATFLUX - electron_heat_flux = 0.; - #endif - #ifdef CALCULATE_VISCOSITY - electron_viscosity = 0.; - #endif - #ifdef CALCULATE_FRICTION - electron_friction = 0.; - #endif - #ifdef DRIVE_GRADT - #ifdef CALCULATE_HEATFLUX - electron_heat_flux += -heatflux_gradT_zerocoeff * gradT_driveterm; //zero eigenvalue contribution to n^(1,1) //zero eigenvalue contribution to n^(1,1)/T^1. - #endif - // viscosity gets no zero eigenvalue contribution - #ifdef CALCULATE_FRICTION - electron_friction += -friction_gradT_zerocoeff * gradT_driveterm; - #endif - cubic_spline_gradT_driveterm.calculate(gradT_driveterm); - #endif - #ifdef DRIVE_GRADV - // gradV drive has no zero eigenvalue contribution - cubic_spline_gradV_driveterm.calculate(gradV_driveterm); - #endif - #ifdef DRIVE_VEMINUSVI - #ifdef CALCULATE_HEATFLUX - electron_heat_flux += -heatflux_VeminusVi_zerocoeff * VeminusVi_driveterm; - #endif - // viscosity gets no zero eigenvalue contribution - #ifdef CALCULATE_FRICTION - electron_friction += -friction_VeminusVi_zerocoeff * VeminusVi_driveterm; - #endif - cubic_spline_VeminusVi_driveterm.calculate(VeminusVi_driveterm); - #endif - - for (int i=0; iiterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) { - position->jx=rup.ind; - position->jy=mesh->yend; - position->jz=jz; - calc_index(position); - BoutReal Te_here = interp_to_point_YLOW(T_electron,*position); - #ifdef BC_HEATFLUX - pass_interim_upper_boundary_n11[rup.ind][jz] = electron_heat_flux[rup.ind][mesh->yend][jz]; - upper_boundary_condition_n11[rup.ind][jz] = -4./5.*sqrt(electron_mass/2.)/pow(Te_here,1.5)*heat_flux_boundary_condition[rup.ind][mesh->yend][jz]; - #endif - #ifdef BC_VISCOSITY - pass_interim_upper_boundary_n20[rup.ind][jz] = electron_viscosity[rup.ind][mesh->yend][jz]; - upper_boundary_condition_n20[rup.ind][jz] = viscosity_boundary_condition[rup.ind][mesh->yend][jz]/Te_here; - #endif - } - if (is_upper_boundary && mesh->getNYPE()>1) { - #ifdef BC_HEATFLUX - MPI_Request request1 = mesh->sendToProc(mesh->getXProcIndex(),0, - *pass_interim_upper_boundary_n11.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex()); - MPI_Request request2 = mesh->sendToProc(mesh->getXProcIndex(),0, - *upper_boundary_condition_n11.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex() + 1); - MPI_Waitall(1,&request1,MPI_STATUSES_IGNORE); - MPI_Waitall(1,&request2,MPI_STATUSES_IGNORE); - #endif - #ifdef BC_VISCOSITY - MPI_Request request3 = mesh->sendToProc(mesh->getXProcIndex(),0, - *pass_interim_upper_boundary_n20.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex() + 3); - MPI_Request request4 = mesh->sendToProc(mesh->getXProcIndex(),0, - *upper_boundary_condition_n20.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex() + 4); - MPI_Waitall(1,&request3,MPI_STATUSES_IGNORE); - MPI_Waitall(1,&request4,MPI_STATUSES_IGNORE); - #endif - } - if (is_lower_boundary && mesh->getNYPE()>1) { - #ifdef BC_HEATFLUX - mesh->wait(mesh->receiveFromProc(mesh->getXProcIndex(), mesh->getNYPE()-1, - *pass_interim_upper_boundary_n11.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex()) ); - mesh->wait(mesh->receiveFromProc(mesh->getXProcIndex(), mesh->getNYPE()-1, - *upper_boundary_condition_n11.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex() + 1) ); - #endif - #ifdef BC_VISCOSITY - mesh->wait(mesh->receiveFromProc(mesh->getXProcIndex(), mesh->getNYPE()-1, - *pass_interim_upper_boundary_n20.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex() + 3) ); - mesh->wait(mesh->receiveFromProc(mesh->getXProcIndex(), mesh->getNYPE()-1, - *upper_boundary_condition_n20.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex() + 4) ); - #endif - } - - if (is_lower_boundary) { - for (int jx=mesh->xstart; jx<=mesh->xend; jx++) - for (int jz=0; jzLocalNz; jz++) { - position->jx=jx; - position->jy=mesh->ystart; - position->jz=jz; - calc_index(position); - BoutReal Te_here = interp_to_point_YLOW(T_electron,*position); - #if defined(BC_HEATFLUX) && !defined(BC_VISCOSITY) - BoutReal lower_boundary_n11 = -4./5.*sqrt(electron_mass/2.)/pow(Te_here,1.5)*heat_flux_boundary_condition[jx][mesh->ystart][jz]; - BoutReal upper_boundary_n11 = upper_boundary_condition_n11[jx][jz]; - BoutReal interim_lower_boundary_n11 = electron_heat_flux[jx][mesh->ystart][jz]; - BoutReal interim_upper_boundary_n11 = pass_interim_upper_boundary_n11[jx][jz]; - /* - electron_heat_flux is, at this point, the contribution to n11 from nhat_plus. - We want the actual heat flux at mesh->ystart to be boundary_heat_flux. - Thus the remainder must come from nhat_minus, which we will construct here just to give the right 1,1 component (could set number_of_negative_eigenvalues-1 more components if desired) - However, the transients from the other boundary do not necessarily decay to vanishing by the time they get to this boundary, so we must solve for both. - Fortunately this reduces to a single algebraic equation which makes it surprisingly easy to do (in the case of just a single condition being imposed at least). - */ - - BoutReal sum_decayed_W11_W11_term = 0.; - for (int i=0; ixstart)*(mesh->LocalNz)+jz] = ( (lower_boundary_n11 - interim_lower_boundary_n11)*W11_dot_W11 - - sum_decayed_W11_W11_term*(upper_boundary_n11 - interim_upper_boundary_n11) ) - / ( pow(W11_dot_W11,2) - pow(sum_decayed_W11_W11_term,2) ); - heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] = ( (upper_boundary_n11 - interim_upper_boundary_n11)*W11_dot_W11 - - sum_decayed_W11_W11_term*(lower_boundary_n11 - interim_lower_boundary_n11) ) - / ( pow(W11_dot_W11,2) - pow(sum_decayed_W11_W11_term,2) ); - #elif defined(BC_VISCOSITY) && !defined(BC_HEATFLUX) - BoutReal lower_boundary_n20 = viscosity_boundary_condition[jx][mesh->ystart][jz]/Te_here; - BoutReal upper_boundary_n20 = upper_boundary_condition_n20[jx][jz]; - BoutReal interim_lower_boundary_n20 = electron_viscosity[jx][mesh->ystart][jz]; - BoutReal interim_upper_boundary_n20 = pass_interim_upper_boundary_n20[jx][jz]; - /* - electron_viscosity is, at this point, the contribution to n20 from nhat_plus. - We want the actual viscosity at mesh->ystart to be boundary_viscosity. - Thus the remainder must come from nhat_minus, which we will construct here just to give the right 2,0 component (could set number_of_negative_eigenvalues-1 more components if desired) - However, the transients from the other boundary do not necessarily decay to vanishing by the time they get to this boundary, so we must solve for both. - Fortunately this reduces to a single algebraic equation which makes it surprisingly easy to do (in the case of just a single condition being imposed at least). - */ - - BoutReal sum_decayed_W20_W20_term = 0.; - for (int i=0; ixstart)*(mesh->LocalNz)+jz] = ( (lower_boundary_n20 - interim_lower_boundary_n20)*W20_dot_W20 - - sum_decayed_W20_W20_term*(upper_boundary_n20 - interim_upper_boundary_n20) ) - / ( pow(W20_dot_W20,2) - pow(sum_decayed_W20_W20_term,2) ); - viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] = ( (upper_boundary_n20 - interim_upper_boundary_n20)*W20_dot_W20 - - sum_decayed_W20_W20_term*(lower_boundary_n20 - interim_lower_boundary_n20) ) - / ( pow(W20_dot_W20,2) - pow(sum_decayed_W20_W20_term,2)); - #elif defined(BC_HEATFLUX) && defined(BC_VISCOSITY) - BoutReal lower_boundary_n11 = -4./5.*sqrt(electron_mass/2.)/pow(Te_here,1.5)*heat_flux_boundary_condition[jx][mesh->ystart][jz]; - BoutReal upper_boundary_n11 = upper_boundary_condition_n11[jx][jz]; - BoutReal interim_lower_boundary_n11 = electron_heat_flux[jx][mesh->ystart][jz]; - BoutReal interim_upper_boundary_n11 = pass_interim_upper_boundary_n11[jx][jz]; - BoutReal lower_boundary_n20 = viscosity_boundary_condition[jx][mesh->ystart][jz]/Te_here; - BoutReal upper_boundary_n20 = upper_boundary_condition_n20[jx][jz]; - BoutReal interim_lower_boundary_n20 = electron_viscosity[jx][mesh->ystart][jz]; - BoutReal interim_upper_boundary_n20 = pass_interim_upper_boundary_n20[jx][jz]; - BoutReal sum_decayed_W11_W11_term = 0.; - BoutReal sum_decayed_W20_W20_term = 0.; - BoutReal sum_decayed_W11_W20_term = 0.; - BoutReal sum_decayed_W20_W11_term = 0.; - for (int i=0; ixstart)*(mesh->LocalNz)+jz] = ( (upper_boundary_n11-interim_upper_boundary_n11)*( -sum_decayed_W11_W20_term*sum_decayed_W20_W11_term*sum_decayed_W20_W20_term - + sum_decayed_W11_W11_term*pow(sum_decayed_W20_W20_term,2) - + sum_decayed_W20_W20_term*W11_dot_W20*W20_dot_W11 - - sum_decayed_W20_W11_term*W11_dot_W20*W20_dot_W20 - + sum_decayed_W11_W20_term*W20_dot_W11*W20_dot_W20 - - sum_decayed_W11_W11_term*pow(W20_dot_W20,2) ) - + (upper_boundary_n20-interim_upper_boundary_n20)*( pow(sum_decayed_W11_W20_term,2)*sum_decayed_W20_W11_term - - sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*sum_decayed_W20_W20_term - + sum_decayed_W20_W20_term*W11_dot_W11*W11_dot_W20 - - sum_decayed_W20_W11_term*pow(W11_dot_W20,2) - + sum_decayed_W11_W20_term*W11_dot_W11*W20_dot_W20 - - sum_decayed_W11_W11_term*W11_dot_W20*W20_dot_W20 ) - + (lower_boundary_n11-interim_lower_boundary_n11)*( -pow(sum_decayed_W20_W20_term,2)*W11_dot_W11 - + sum_decayed_W20_W11_term*sum_decayed_W20_W20_term*W11_dot_W20 - - sum_decayed_W11_W20_term*sum_decayed_W20_W20_term*W20_dot_W11 - + sum_decayed_W11_W20_term*sum_decayed_W20_W11_term*W20_dot_W20 - - W11_dot_W20*W20_dot_W11*W20_dot_W20 + W11_dot_W11*pow(W20_dot_W20,2) ) - + (lower_boundary_n20-interim_lower_boundary_n20)*( -sum_decayed_W11_W20_term*sum_decayed_W20_W20_term*W11_dot_W11 - + sum_decayed_W11_W11_term*sum_decayed_W20_W20_term*W11_dot_W20 - - pow(sum_decayed_W11_W20_term,2)*W20_dot_W11 - + pow(W11_dot_W20,2)*W20_dot_W11 - + sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*W20_dot_W20 - - W11_dot_W11*W11_dot_W20*W20_dot_W20 ) - ) / det; - heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] = ( (upper_boundary_n11-interim_upper_boundary_n11)*( -pow(sum_decayed_W20_W20_term,2)*W11_dot_W11 - + sum_decayed_W20_W11_term*sum_decayed_W20_W20_term*W11_dot_W20 - - sum_decayed_W11_W20_term*sum_decayed_W20_W20_term*W20_dot_W11 - + sum_decayed_W11_W20_term*sum_decayed_W20_W11_term*W20_dot_W20 - - W11_dot_W20*W20_dot_W11*W20_dot_W20 - + W11_dot_W11*pow(W20_dot_W20,2) ) - + (upper_boundary_n20-interim_upper_boundary_n20)*( sum_decayed_W11_W20_term*sum_decayed_W20_W20_term*W11_dot_W11 - - sum_decayed_W11_W11_term*sum_decayed_W20_W20_term*W11_dot_W20 - + pow(sum_decayed_W11_W20_term,2)*W20_dot_W11 - - pow(W11_dot_W20,2)*W20_dot_W11 - - sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*W20_dot_W20 - + W11_dot_W11*W11_dot_W20*W20_dot_W20 ) - + (lower_boundary_n11-interim_lower_boundary_n11)*( -sum_decayed_W11_W20_term*sum_decayed_W20_W11_term*sum_decayed_W20_W20_term - + sum_decayed_W11_W11_term*pow(sum_decayed_W20_W20_term,2) - + sum_decayed_W20_W20_term*W11_dot_W20*W20_dot_W11 - - sum_decayed_W20_W11_term*W11_dot_W20*W20_dot_W20 - + sum_decayed_W11_W20_term*W20_dot_W11*W20_dot_W20 - - sum_decayed_W11_W11_term*pow(W20_dot_W20,2) ) - + (lower_boundary_n20-interim_lower_boundary_n20)*( -pow(sum_decayed_W11_W20_term,2)*sum_decayed_W20_W11_term - + sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*sum_decayed_W20_W20_term - - sum_decayed_W20_W20_term*W11_dot_W11*W11_dot_W20 - + sum_decayed_W20_W11_term*pow(W11_dot_W20,2) - - sum_decayed_W11_W20_term*W11_dot_W11*W20_dot_W20 - + sum_decayed_W11_W11_term*W11_dot_W20*W20_dot_W20 ) - ) / det; - viscosity_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz] = ( (upper_boundary_n11-interim_upper_boundary_n11)*( sum_decayed_W11_W20_term*pow(sum_decayed_W20_W11_term,2) - - sum_decayed_W11_W11_term*sum_decayed_W20_W11_term*sum_decayed_W20_W20_term - - sum_decayed_W20_W20_term*W11_dot_W11*W20_dot_W11 - - sum_decayed_W11_W20_term*pow(W20_dot_W11,2) - + sum_decayed_W20_W11_term*W11_dot_W11*W20_dot_W20 - + sum_decayed_W11_W11_term*W20_dot_W11*W20_dot_W20 ) - + (upper_boundary_n20-interim_upper_boundary_n20)*( -sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*sum_decayed_W20_W11_term - + pow(sum_decayed_W11_W11_term,2)*sum_decayed_W20_W20_term - - sum_decayed_W20_W20_term*pow(W11_dot_W11,2) - + sum_decayed_W20_W11_term*W11_dot_W11*W11_dot_W20 - - sum_decayed_W11_W20_term*W11_dot_W11*W20_dot_W11 - + sum_decayed_W11_W11_term*W11_dot_W20*W20_dot_W11 ) - + (lower_boundary_n11-interim_lower_boundary_n11)*( sum_decayed_W20_W11_term*sum_decayed_W20_W20_term*W11_dot_W11 - - pow(sum_decayed_W20_W11_term,2)*W11_dot_W20 - + sum_decayed_W11_W11_term*sum_decayed_W20_W20_term*W20_dot_W11 - + W11_dot_W20*pow(W20_dot_W11,2) - - sum_decayed_W11_W11_term*sum_decayed_W20_W11_term*W20_dot_W20 - - W11_dot_W11*W20_dot_W11*W20_dot_W20 ) - + (lower_boundary_n20-interim_lower_boundary_n20)*( sum_decayed_W11_W20_term*sum_decayed_W20_W11_term*W11_dot_W11 - - sum_decayed_W11_W11_term*sum_decayed_W20_W11_term*W11_dot_W20 - + sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*W20_dot_W11 - - W11_dot_W11*W11_dot_W20*W20_dot_W11 - - pow(sum_decayed_W11_W11_term,2)*W20_dot_W20 - + pow(W11_dot_W11,2)*W20_dot_W20 ) - ) / det; - viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] = ( (upper_boundary_n11-interim_upper_boundary_n11)*( -sum_decayed_W20_W11_term*sum_decayed_W20_W20_term*W11_dot_W11 - + pow(sum_decayed_W20_W11_term,2)*W11_dot_W20 - - sum_decayed_W11_W11_term*sum_decayed_W20_W20_term*W20_dot_W11 - - W11_dot_W20*pow(W20_dot_W11,2) - + sum_decayed_W11_W11_term*sum_decayed_W20_W11_term*W20_dot_W20 - + W11_dot_W11*W20_dot_W11*W20_dot_W20 ) - + (upper_boundary_n20-interim_upper_boundary_n20)*( sum_decayed_W11_W20_term*sum_decayed_W20_W11_term*W11_dot_W11 - - sum_decayed_W11_W11_term*sum_decayed_W20_W11_term*W11_dot_W20 - + sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*W20_dot_W11 - - W11_dot_W11*W11_dot_W20*W20_dot_W11 - - pow(sum_decayed_W11_W11_term,2)*W20_dot_W20 - + pow(W11_dot_W11,2)*W20_dot_W20 ) - + (lower_boundary_n11-interim_lower_boundary_n11)*( -sum_decayed_W11_W20_term*pow(sum_decayed_W20_W11_term,2) - + sum_decayed_W11_W11_term*sum_decayed_W20_W11_term*sum_decayed_W20_W20_term - + sum_decayed_W20_W20_term*W11_dot_W11*W20_dot_W11 - + sum_decayed_W11_W20_term*pow(W20_dot_W11,2) - - sum_decayed_W20_W11_term*W11_dot_W11*W20_dot_W20 - - sum_decayed_W11_W11_term*W20_dot_W11*W20_dot_W20 ) - + (lower_boundary_n20-interim_lower_boundary_n20)*( -sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*sum_decayed_W20_W11_term - + pow(sum_decayed_W11_W11_term,2)*sum_decayed_W20_W20_term - - sum_decayed_W20_W20_term*pow(W11_dot_W11,2) - + sum_decayed_W20_W11_term*W11_dot_W11*W11_dot_W20 - - sum_decayed_W11_W20_term*W11_dot_W11*W20_dot_W11 - + sum_decayed_W11_W11_term*W11_dot_W20*W20_dot_W11 ) - ) / det; - #endif - } - } - - #ifdef BC_HEATFLUX - y_broadcast(heatflux_transients_factors, (mesh->xend-mesh->xstart+1)*(mesh->LocalNz)*2, 0); - #endif - #ifdef BC_VISCOSITY - y_broadcast(viscosity_transients_factors, (mesh->xend-mesh->xstart+1)*(mesh->LocalNz)*2, 0); - #endif - - for (int jx=mesh->xstart; jx<=mesh->xend; jx++) - for (int jz=0; jzLocalNz; jz++) { - #if defined(BC_HEATFLUX) && !defined(BC_VISCOSITY) - for (int i=0; ixstart)*(mesh->LocalNz)+jz]; - heatflux_upper_boundary_transients[i][jx][jz] = W11_B_times_WinverseB_11[i]*heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - #ifdef CALCULATE_VISCOSITY - viscosity_lower_boundary_transients[i][jx][jz] = W20_B_times_WinverseB_11[i]*heatflux_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - viscosity_upper_boundary_transients[i][jx][jz] = -W20_B_times_WinverseB_11[i]*heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - #ifdef CALCULATE_FRICTION - friction_lower_boundary_transients[i][jx][jz] = C10_1k_dot_W1k_B_times_WinverseB_11[i]*heatflux_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - friction_upper_boundary_transients[i][jx][jz] = C10_1k_dot_W1k_B_times_WinverseB_11[i]*heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - } - #elif defined(BC_VISCOSITY) && !defined(BC_HEATFLUX) - for (int i=0; ixstart)*(mesh->LocalNz)+jz]; - heatflux_upper_boundary_transients[i][jx][jz] = -W11_B_times_WinverseB_20[i]*viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - #ifdef CALCULATE_VISCOSITY - viscosity_lower_boundary_transients[i][jx][jz] = W20_B_times_WinverseB_20[i]*viscosity_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - viscosity_upper_boundary_transients[i][jx][jz] = W20_B_times_WinverseB_20[i]*viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - #ifdef CALCULATE_FRICTION - friction_lower_boundary_transients[i][jx][jz] = C10_1k_dot_W1k_B_times_WinverseB_20[i]*viscosity_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - friction_upper_boundary_transients[i][jx][jz] = -C10_1k_dot_W1k_B_times_WinverseB_20[i]*viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - } - #elif defined(BC_HEATFLUX) && defined(BC_VISCOSITY) - for (int i=0; ixstart)*(mesh->LocalNz)+jz] - + W11_B_times_WinverseB_20[i]*viscosity_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - heatflux_upper_boundary_transients[i][jx][jz] = W11_B_times_WinverseB_11[i]*heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] - - W11_B_times_WinverseB_20[i]*viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - #ifdef CALCULATE_VISCOSITY - viscosity_lower_boundary_transients[i][jx][jz] = W20_B_times_WinverseB_11[i]*heatflux_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz] - + W20_B_times_WinverseB_20[i]*viscosity_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - viscosity_upper_boundary_transients[i][jx][jz] = -W20_B_times_WinverseB_11[i]*heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] - + W20_B_times_WinverseB_20[i]*viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - #ifdef CALCULATE_FRICTION - friction_lower_boundary_transients[i][jx][jz] = C10_1k_dot_W1k_B_times_WinverseB_11[i]*heatflux_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz] - + C10_1k_dot_W1k_B_times_WinverseB_20[i]*viscosity_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - friction_upper_boundary_transients[i][jx][jz] = C10_1k_dot_W1k_B_times_WinverseB_11[i]*heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] - - C10_1k_dot_W1k_B_times_WinverseB_20[i]*viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - } - #else - for (int i=0; ijy=mesh->ystart; - calc_index(position); - do { - for (int i=0; ijx][position->jz] * exp_increasing - + heatflux_upper_boundary_transients[i][position->jx][position->jz] * exp_decreasing; - #endif - #ifdef CALCULATE_VISCOSITY - electron_viscosity[*position] += viscosity_lower_boundary_transients[i][position->jx][position->jz] * exp_increasing - + viscosity_upper_boundary_transients[i][position->jx][position->jz] * exp_decreasing; - #endif - #ifdef CALCULATE_FRICTION - electron_friction[*position] += friction_lower_boundary_transients[i][position->jx][position->jz] * exp_increasing - + friction_upper_boundary_transients[i][position->jx][position->jz] * exp_decreasing; - #endif - } - position->jy++; - calc_index(position); - } while (position->jyyend+1); - } while (next_indexperp(position)); - #endif - - #ifdef CALCULATE_HEATFLUX - electron_heat_flux *= -5./4.*sqrt(2./electron_mass)*(T_electron^1.5); //now we have q=-5/4*v_Telectron*T_electron*n^(1,1) - mesh->communicate(electron_heat_flux); - #endif - #ifdef CALCULATE_VISCOSITY - electron_viscosity *= T_electron; - mesh->communicate(electron_viscosity); - #endif - #ifdef CALCULATE_FRICTION - electron_friction *= 2.*T_electron/3.*lambdaC_inverse; - electron_friction += -2.*sqrt(2.*electron_mass*T_electron)*lambdaC_inverse*(-jpar/electron_charge); // Need to include also the friction due directly to the Maxwellian part of the distribution function - mesh->communicate(electron_friction); - #endif -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void NonLocalParallel::calculate_nonlocal_closures_cell_ylow(const Field3D &n_electron, const Field3D &T_electron - #ifdef DRIVE_GRADV - , const Field3D &V_electron - #endif - #ifdef DRIVE_VEMINUSVI - , const Field3D &jpar - #endif - #ifdef BC_HEATFLUX - , const Field3D &heat_flux_boundary_condition - #endif - #ifdef BC_VISCOSITY - , const Field3D &viscosity_boundary_condition - #endif - ) { - - Coordinates *coord = mesh->coordinates(); - - lambdaC_inverse = n_electron * pow(electron_charge,4) * logLambda / 12 / pow(PI,1.5) / pow(epsilon_0,2) / (T_electron^2); - - #ifdef DRIVE_GRADT - gradT_driveterm = 5./4. * n_electron / T_electron / lambdaC_inverse; //g^(1,1) - gradT_electron = Grad_par(T_electron,CELL_YLOW); - #endif - #ifdef DRIVE_GRADV - gradV_driveterm = -0.5 * n_electron / sqrt(2.*T_electron/electron_mass) * Grad_par(V_electron,CELL_CENTRE) / lambdaC_inverse; -// gradV_electron = Grad_par(V_electron,CELL_YLOW); // would be more consistent to put this on CELL_CENTRE, but that would make imposing a boundary condition a pain. - #endif - #ifdef DRIVE_VEMINUSVI - VeminusVi_driveterm = -2./sqrt(PI) * (-1./electron_charge) / sqrt(2.*T_electron/electron_mass); - // jpar is already CELL_YLOW. - #endif - // Calculate target boundary guard cell derivitives (at YLOW) for gradT_electron with 4th order forward/backward differences from T_electron (at CENTRE) - // Also check for unphysical lambdaC_inverse - for (RangeIterator rlow = mesh->iterateBndryLowerY(); !rlow.isDone(); rlow++) - for (int jz=0; jzLocalNz; jz++) { - for (int jy=mesh->ystart-1; jy>=0; jy--) { - #ifdef DRIVE_GRADT - gradT_electron(rlow.ind,jy,jz)=(-93.*T_electron(rlow.ind,jy,jz) + 229.*T_electron(rlow.ind,jy+1,jz) - 225.*T_electron(rlow.ind,jy+2,jz) + 111.*T_electron(rlow.ind,jy+3,jz) - 22.*T_electron(rlow.ind,jy+4,jz))/48./coord->dy(rlow.ind,jy)/sqrt((coord->g_22(rlow.ind,jy) + coord->g_22(rlow.ind,jy+1) + coord->g_22(rlow.ind,jy+2) + coord->g_22(rlow.ind,jy+3) + coord->g_22(rlow.ind,jy+4))/5.); - if (abs(gradT_driveterm(rlow.ind,jy,jz))>1.e37 || gradT_driveterm(rlow.ind,jy,jz)!=gradT_driveterm(rlow.ind,jy,jz)) gradT_driveterm(rlow.ind,jy,jz) = 1.e37; - #endif - #ifdef DRIVE_GRADV - // Nothing to be done here: gradV_driveterm is CELL_CENTRE and the guard cell values are not used - #endif - #ifdef DRIVE_VEMINUSVI - if (abs(VeminusVi_driveterm[rlow.ind][jy][jz])>1.e37 || VeminusVi_driveterm[rlow.ind][jy][jz]!=VeminusVi_driveterm[rlow.ind][jy][jz]) VeminusVi_driveterm[rlow.ind][jy][jz] = 1.e37; - #endif - if (abs(lambdaC_inverse[rlow.ind][jy][jz])>1.e37 || lambdaC_inverse[rlow.ind][jy][jz]!=lambdaC_inverse[rlow.ind][jy][jz]) lambdaC_inverse[rlow.ind][jy][jz] = 1.e37; - } - } - - - - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) { - #ifdef DRIVE_GRADT - gradT_electron[rup.ind][mesh->yend][jz] = (T_electron[rup.ind][mesh->yend-2][jz]-27.*T_electron[rup.ind][mesh->yend-1][jz]+27.*T_electron[rup.ind][mesh->yend][jz]-T_electron[rup.ind][mesh->yend+1][jz])/24./coord->dy[rup.ind][mesh->yend+1]/sqrt((coord->g_22[rup.ind][mesh->yend-1] + coord->g_22[rup.ind][mesh->yend] + coord->g_22[rup.ind][mesh->yend+1] + coord->g_22[rup.ind][mesh->yend+2])/4.); - #endif - for (int jy=mesh->yend+1; jyLocalNy; jy++) { - #ifdef DRIVE_GRADT - gradT_electron[rup.ind][jy][jz]=(93.*T_electron(rup.ind,jy-1,jz) - 229.*T_electron(rup.ind,jy-2,jz) + 225.*T_electron(rup.ind,jy-3,jz) - 111.*T_electron(rup.ind,jy-4,jz) + 22.*T_electron(rup.ind,jy-5,jz))/48./coord->dy(rup.ind,jy-1)/sqrt((coord->g_22[rup.ind][jy-1] + coord->g_22[rup.ind][jy-2] + coord->g_22[rup.ind][jy-3] + coord->g_22[rup.ind][jy-4] + coord->g_22[rup.ind][jy-5])/5.); - if (abs(gradT_driveterm[rup.ind][jy][jz])>1.e37 || gradT_driveterm[rup.ind][jy][jz]!=gradT_driveterm[rup.ind][jy][jz]) gradT_driveterm[rup.ind][jy][jz] = 1.e37; - #endif - #ifdef DRIVE_GRADV - // Nothing to be done here: gradV_driveterm is CELL_CENTRE and the guard cell values are not used - #endif - #ifdef DRIVE_VEMINUSVI - if (abs(VeminusVi_driveterm[rup.ind][jy][jz])>1.e37 || VeminusVi_driveterm[rup.ind][jy][jz]!=VeminusVi_driveterm[rup.ind][jy][jz]) VeminusVi_driveterm[rup.ind][jy][jz] = 1.e37; - #endif - if (abs(lambdaC_inverse[rup.ind][jy][jz])>1.e37 || lambdaC_inverse[rup.ind][jy][jz]!=lambdaC_inverse[rup.ind][jy][jz]) lambdaC_inverse[rup.ind][jy][jz] = 1.e37; - } - } - - #ifdef DRIVE_GRADT - mesh->communicate(gradT_electron); - #endif - #ifdef DRIVE_GRADV - mesh->communicate(gradV_driveterm); - #endif - // No gradient term to communicate for VeminusVi - - // Now calculate z and deltaz everywhere - cubic_spline_inverse_lambdaC.calculate(lambdaC_inverse); - - start_index(position); - - if (mesh->UpXSplitIndex()!=0 || mesh->DownXSplitIndex()!=0) throw BoutException("This code cannot currently handle x-splitting of processors."); - if (!is_lower_boundary) { - FieldPerp pass_dimensionless_length; - pass_dimensionless_length.allocate(); - { - mesh->wait(mesh->irecvYInOutdest(*pass_dimensionless_length.getData(),mesh->LocalNx*(mesh->LocalNz), - NONLOCAL_PARALLEL_TAGBASE + position->jx*mesh->LocalNz+position->jz)); - } - pass_dimensionless_length.setIndex(mesh->ystart); - increasing_dimensionless_length = pass_dimensionless_length; - } - - do { - position->jy = mesh->ystart-1; - calc_index(position); - interp_coefficients = cubic_spline_inverse_lambdaC.coefficients(position); - // dimensionless_length_deltas_above[jy] and dimensionless_length_deltas_below[jy] are the deltaz's for the half-step above and below, respectively, the CELL_CENTRE at jy - // deltaz between position[jy](CELL_CENTRE), where t=0, and position[jyp](CELL_YLOW), where t=0.5 - - Coordinates *coord = mesh->coordinates(); - - dimensionless_length_deltas_above[position->jx][position->jy][position->jz] = coord->dy(position->jx,position->jy)*sqrt(coord->g_22(position->jx,position->jy)) - *(interp_coefficients[0]/2. + interp_coefficients[1]/2./4. + interp_coefficients[2]/3./8. + interp_coefficients[3]/4./16.); - // deltaz between position[jyp](CELL_YLOW), where t=0.5, and position[jyp](CELL_CENTRE), where t=1 - dimensionless_length_deltas_below[position->jx][position->jyp][position->jz] = coord->dy(position->jx,position->jy)*sqrt(coord->g_22(position->jx,position->jyp)) - *(interp_coefficients[0]/2. + interp_coefficients[1]/2.*3./4. + interp_coefficients[2]/3.*7./8. + interp_coefficients[3]/4.*15./16.); - next_index_y(position); - - do{ - interp_coefficients = cubic_spline_inverse_lambdaC.coefficients(position); - // deltaz between position[jy](CELL_CENTRE), where t=0, and position[jyp](CELL_YLOW), where t=0.5 - - dimensionless_length_deltas_above[position->jx][position->jy][position->jz] = coord->dy(position->jx,position->jy)*sqrt(coord->g_22(position->jx,position->jy)) - *(interp_coefficients[0]/2. + interp_coefficients[1]/2./4. + interp_coefficients[2]/3./8. + interp_coefficients[3]/4./16.); - // deltaz between position[jyp](CELL_YLOW), where t=0.5, and position[jyp](CELL_CENTRE), where t=1 - dimensionless_length_deltas_below[position->jx][position->jyp][position->jz] = coord->dy(position->jx,position->jyp)*sqrt(coord->g_22(position->jx,position->jyp)) - *(interp_coefficients[0]/2. + interp_coefficients[1]/2.*3./4. + interp_coefficients[2]/3.*7./8. + interp_coefficients[3]/4.*15./16.); - increasing_dimensionless_length[position->jx][position->jyp][position->jz] = increasing_dimensionless_length[*position] + dimensionless_length_deltas_below[*position] + dimensionless_length_deltas_above[*position]; - } while (next_index_y(position)); - - } while (next_indexperp(position)); - - { - Timer timer("comms"); - mesh->sendYOutOutdest(*increasing_dimensionless_length.slice(mesh->yend+1).getData(),mesh->LocalNx*(mesh->LocalNz), - NONLOCAL_PARALLEL_TAGBASE + position->jx*mesh->LocalNz+position->jz); - } - - // Send the total dimensionless_length at the upper boundary back to the other processors. - if (is_upper_boundary) { - total_dimensionless_length = increasing_dimensionless_length.slice(mesh->yend); - } - - y_broadcast(*total_dimensionless_length.getData(), mesh->LocalNx*mesh->LocalNz, mesh->getNYPE()-1); - - decreasing_dimensionless_length = -increasing_dimensionless_length; - for (int jy=mesh->ystart; jy<=mesh->yend; jy++) { - total_dimensionless_length.setIndex(jy); - decreasing_dimensionless_length += total_dimensionless_length; - } - - #ifdef CALCULATE_HEATFLUX - electron_heat_flux = 0.; - #endif - #ifdef CALCULATE_VISCOSITY - electron_viscosity = 0.; - #endif - #ifdef CALCULATE_FRICTION - electron_friction = 0.; - #endif - #ifdef DRIVE_GRADT - #ifdef CALCULATE_HEATFLUX - electron_heat_flux += -heatflux_gradT_zerocoeff * interp_to(gradT_driveterm,CELL_YLOW) * gradT_electron; //zero eigenvalue contribution to n^(1,1)/T^1.5 - #endif - // viscosity gets no zero eigenvalue contribution - #ifdef CALCULATE_FRICTION - electron_friction += -friction_gradT_zerocoeff * interp_to(gradT_driveterm,CELL_YLOW) * gradT_electron; //zero eigenvalue contribution - #endif - cubic_spline_gradT_driveterm.calculate(gradT_driveterm); - cubic_spline_gradT.calculate(gradT_electron); - #endif - #ifdef DRIVE_GRADV - // gradV drive gives no zero eigenvalue contribution - cubic_spline_gradV_driveterm.calculate(gradV_driveterm); - #endif - #ifdef DRIVE_VEMINUSVI - #ifdef CALCULATE_HEATFLUX - electron_heat_flux += -heatflux_VeminusVi_zerocoeff * interp_to(VeminusVi_driveterm,CELL_YLOW)*jpar; - #endif - // viscosity gets no zero eigenvalue contribution - #ifdef CALCULATE_FRICTION - electron_friction += -friction_VeminusVi_zerocoeff * interp_to(VeminusVi_driveterm,CELL_YLOW)*jpar; - #endif - cubic_spline_VeminusVi_driveterm.calculate(VeminusVi_driveterm); - cubic_spline_jpar.calculate(jpar); - #endif - - for (int i=0; iiterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) { - position->jx=rup.ind; - position->jy=mesh->yend; - position->jz=jz; - calc_index(position); - BoutReal Te_here = interp_to_point_YLOW(T_electron,*position); - #ifdef BC_HEATFLUX - pass_interim_upper_boundary_n11[rup.ind][jz] = electron_heat_flux[rup.ind][mesh->yend][jz]; - upper_boundary_condition_n11[rup.ind][jz] = -4./5.*sqrt(electron_mass/2.)/pow(Te_here,1.5)*heat_flux_boundary_condition[rup.ind][mesh->yend][jz]; - #endif - #ifdef BC_VISCOSITY - pass_interim_upper_boundary_n20[rup.ind][jz] = electron_viscosity[rup.ind][mesh->yend][jz]; - upper_boundary_condition_n20[rup.ind][jz] = viscosity_boundary_condition[rup.ind][mesh->yend][jz]/Te_here; - #endif - } - if (is_upper_boundary && mesh->getNYPE()>1) { - #ifdef BC_HEATFLUX - MPI_Request request1 = mesh->sendToProc(mesh->getXProcIndex(),0, - *pass_interim_upper_boundary_n11.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex()); - MPI_Request request2 = mesh->sendToProc(mesh->getXProcIndex(),0, - *upper_boundary_condition_n11.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex() + 1); - MPI_Waitall(1,&request1,MPI_STATUSES_IGNORE); - MPI_Waitall(1,&request2,MPI_STATUSES_IGNORE); - #endif - #ifdef BC_VISCOSITY - MPI_Request request3 = mesh->sendToProc(mesh->getXProcIndex(),0, - *pass_interim_upper_boundary_n20.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex() + 3); - MPI_Request request4 = mesh->sendToProc(mesh->getXProcIndex(),0, - *upper_boundary_condition_n20.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex() + 4); - MPI_Waitall(1,&request3,MPI_STATUSES_IGNORE); - MPI_Waitall(1,&request4,MPI_STATUSES_IGNORE); - #endif - } - if (is_lower_boundary && mesh->getNYPE()>1) { - #ifdef BC_HEATFLUX - mesh->wait(mesh->receiveFromProc(mesh->getXProcIndex(), mesh->getNYPE()-1, - *pass_interim_upper_boundary_n11.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex()) ); - mesh->wait(mesh->receiveFromProc(mesh->getXProcIndex(), mesh->getNYPE()-1, - *upper_boundary_condition_n11.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex() + 1) ); - #endif - #ifdef BC_VISCOSITY - mesh->wait(mesh->receiveFromProc(mesh->getXProcIndex(), mesh->getNYPE()-1, - *pass_interim_upper_boundary_n20.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex() + 3) ); - mesh->wait(mesh->receiveFromProc(mesh->getXProcIndex(), mesh->getNYPE()-1, - *upper_boundary_condition_n20.getData(), - mesh->LocalNx*mesh->LocalNz, - NONLOCAL_PARALLEL_TAGBASE + mesh->getXProcIndex() + 4) ); - #endif - } - - if (is_lower_boundary) { - for (int jx=mesh->xstart; jx<=mesh->xend; jx++) - for (int jz=0; jzLocalNz; jz++) { - position->jx=jx; - position->jy=mesh->ystart; - position->jz=jz; - calc_index(position); - BoutReal Te_here = interp_to_point_YLOW(T_electron,*position); - #if defined(BC_HEATFLUX) && !defined(BC_VISCOSITY) - BoutReal lower_boundary_n11 = -4./5.*sqrt(electron_mass/2.)/pow(Te_here,1.5)*heat_flux_boundary_condition[jx][mesh->ystart][jz]; - BoutReal upper_boundary_n11 = upper_boundary_condition_n11[jx][jz]; - BoutReal interim_lower_boundary_n11 = electron_heat_flux[jx][mesh->ystart][jz]; - BoutReal interim_upper_boundary_n11 = pass_interim_upper_boundary_n11[jx][jz]; - /* - electron_heat_flux is, at this point, the contribution to n11 from nhat_plus. - We want the actual heat flux at mesh->ystart to be boundary_heat_flux. - Thus the remainder must come from nhat_minus, which we will construct here just to give the right 1,1 component (could set number_of_negative_eigenvalues-1 more components if desired) - However, the transients from the other boundary do not necessarily decay to vanishing by the time they get to this boundary, so we must solve for both. - Fortunately this reduces to a single algebraic equation which makes it surprisingly easy to do (in the case of just a single condition being imposed at least). - */ - - BoutReal sum_decayed_W11_W11_term = 0.; - for (int i=0; ixstart)*(mesh->LocalNz)+jz] = ( (lower_boundary_n11 - interim_lower_boundary_n11)*W11_dot_W11 - - sum_decayed_W11_W11_term*(upper_boundary_n11 - interim_upper_boundary_n11) ) - / ( pow(W11_dot_W11,2) - pow(sum_decayed_W11_W11_term,2) ); - heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] = ( (upper_boundary_n11 - interim_upper_boundary_n11)*W11_dot_W11 - - sum_decayed_W11_W11_term*(lower_boundary_n11 - interim_lower_boundary_n11) ) - / ( pow(W11_dot_W11,2) - pow(sum_decayed_W11_W11_term,2) ); - #elif defined(BC_VISCOSITY) && !defined(BC_HEATFLUX) - BoutReal lower_boundary_n20 = viscosity_boundary_condition[jx][mesh->ystart][jz]/Te_here; - BoutReal upper_boundary_n20 = upper_boundary_condition_n20[jx][jz]; - BoutReal interim_lower_boundary_n20 = electron_viscosity[jx][mesh->ystart][jz]; - BoutReal interim_upper_boundary_n20 = pass_interim_upper_boundary_n20[jx][jz]; - /* - electron_viscosity is, at this point, the contribution to n20 from nhat_plus. - We want the actual viscosity at mesh->ystart to be boundary_viscosity. - Thus the remainder must come from nhat_minus, which we will construct here just to give the right 2,0 component (could set number_of_negative_eigenvalues-1 more components if desired) - However, the transients from the other boundary do not necessarily decay to vanishing by the time they get to this boundary, so we must solve for both. - Fortunately this reduces to a single algebraic equation which makes it surprisingly easy to do (in the case of just a single condition being imposed at least). - */ - - BoutReal sum_decayed_W20_W20_term = 0.; - for (int i=0; ixstart)*(mesh->LocalNz)+jz] = ( (lower_boundary_n20 - interim_lower_boundary_n20)*W20_dot_W20 - - sum_decayed_W20_W20_term*(upper_boundary_n20 - interim_upper_boundary_n20) ) - / ( pow(W20_dot_W20,2) - pow(sum_decayed_W20_W20_term,2) ); - viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] = ( (upper_boundary_n20 - interim_upper_boundary_n20)*W20_dot_W20 - - sum_decayed_W20_W20_term*(lower_boundary_n20 - interim_lower_boundary_n20) ) - / ( pow(W20_dot_W20,2) - pow(sum_decayed_W20_W20_term,2)); - #elif defined(BC_HEATFLUX) && defined(BC_VISCOSITY) - BoutReal lower_boundary_n11 = -4./5.*sqrt(electron_mass/2.)/pow(Te_here,1.5)*heat_flux_boundary_condition[jx][mesh->ystart][jz]; - BoutReal upper_boundary_n11 = upper_boundary_condition_n11[jx][jz]; - BoutReal interim_lower_boundary_n11 = electron_heat_flux[jx][mesh->ystart][jz]; - BoutReal interim_upper_boundary_n11 = pass_interim_upper_boundary_n11[jx][jz]; - BoutReal lower_boundary_n20 = viscosity_boundary_condition[jx][mesh->ystart][jz]/Te_here; - BoutReal upper_boundary_n20 = upper_boundary_condition_n20[jx][jz]; - BoutReal interim_lower_boundary_n20 = electron_viscosity[jx][mesh->ystart][jz]; - BoutReal interim_upper_boundary_n20 = pass_interim_upper_boundary_n20[jx][jz]; - BoutReal sum_decayed_W11_W11_term = 0.; - BoutReal sum_decayed_W20_W20_term = 0.; - BoutReal sum_decayed_W11_W20_term = 0.; - BoutReal sum_decayed_W20_W11_term = 0.; - for (int i=0; ixstart)*(mesh->LocalNz)+jz] = ( (upper_boundary_n11-interim_upper_boundary_n11)*( -sum_decayed_W11_W20_term*sum_decayed_W20_W11_term*sum_decayed_W20_W20_term - + sum_decayed_W11_W11_term*pow(sum_decayed_W20_W20_term,2) - + sum_decayed_W20_W20_term*W11_dot_W20*W20_dot_W11 - - sum_decayed_W20_W11_term*W11_dot_W20*W20_dot_W20 - + sum_decayed_W11_W20_term*W20_dot_W11*W20_dot_W20 - - sum_decayed_W11_W11_term*pow(W20_dot_W20,2) ) - + (upper_boundary_n20-interim_upper_boundary_n20)*( pow(sum_decayed_W11_W20_term,2)*sum_decayed_W20_W11_term - - sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*sum_decayed_W20_W20_term - + sum_decayed_W20_W20_term*W11_dot_W11*W11_dot_W20 - - sum_decayed_W20_W11_term*pow(W11_dot_W20,2) - + sum_decayed_W11_W20_term*W11_dot_W11*W20_dot_W20 - - sum_decayed_W11_W11_term*W11_dot_W20*W20_dot_W20 ) - + (lower_boundary_n11-interim_lower_boundary_n11)*( -pow(sum_decayed_W20_W20_term,2)*W11_dot_W11 - + sum_decayed_W20_W11_term*sum_decayed_W20_W20_term*W11_dot_W20 - - sum_decayed_W11_W20_term*sum_decayed_W20_W20_term*W20_dot_W11 - + sum_decayed_W11_W20_term*sum_decayed_W20_W11_term*W20_dot_W20 - - W11_dot_W20*W20_dot_W11*W20_dot_W20 + W11_dot_W11*pow(W20_dot_W20,2) ) - + (lower_boundary_n20-interim_lower_boundary_n20)*( -sum_decayed_W11_W20_term*sum_decayed_W20_W20_term*W11_dot_W11 - + sum_decayed_W11_W11_term*sum_decayed_W20_W20_term*W11_dot_W20 - - pow(sum_decayed_W11_W20_term,2)*W20_dot_W11 - + pow(W11_dot_W20,2)*W20_dot_W11 - + sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*W20_dot_W20 - - W11_dot_W11*W11_dot_W20*W20_dot_W20 ) - ) / det; - heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] = ( (upper_boundary_n11-interim_upper_boundary_n11)*( -pow(sum_decayed_W20_W20_term,2)*W11_dot_W11 - + sum_decayed_W20_W11_term*sum_decayed_W20_W20_term*W11_dot_W20 - - sum_decayed_W11_W20_term*sum_decayed_W20_W20_term*W20_dot_W11 - + sum_decayed_W11_W20_term*sum_decayed_W20_W11_term*W20_dot_W20 - - W11_dot_W20*W20_dot_W11*W20_dot_W20 - + W11_dot_W11*pow(W20_dot_W20,2) ) - + (upper_boundary_n20-interim_upper_boundary_n20)*( sum_decayed_W11_W20_term*sum_decayed_W20_W20_term*W11_dot_W11 - - sum_decayed_W11_W11_term*sum_decayed_W20_W20_term*W11_dot_W20 - + pow(sum_decayed_W11_W20_term,2)*W20_dot_W11 - - pow(W11_dot_W20,2)*W20_dot_W11 - - sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*W20_dot_W20 - + W11_dot_W11*W11_dot_W20*W20_dot_W20 ) - + (lower_boundary_n11-interim_lower_boundary_n11)*( -sum_decayed_W11_W20_term*sum_decayed_W20_W11_term*sum_decayed_W20_W20_term - + sum_decayed_W11_W11_term*pow(sum_decayed_W20_W20_term,2) - + sum_decayed_W20_W20_term*W11_dot_W20*W20_dot_W11 - - sum_decayed_W20_W11_term*W11_dot_W20*W20_dot_W20 - + sum_decayed_W11_W20_term*W20_dot_W11*W20_dot_W20 - - sum_decayed_W11_W11_term*pow(W20_dot_W20,2) ) - + (lower_boundary_n20-interim_lower_boundary_n20)*( -pow(sum_decayed_W11_W20_term,2)*sum_decayed_W20_W11_term - + sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*sum_decayed_W20_W20_term - - sum_decayed_W20_W20_term*W11_dot_W11*W11_dot_W20 - + sum_decayed_W20_W11_term*pow(W11_dot_W20,2) - - sum_decayed_W11_W20_term*W11_dot_W11*W20_dot_W20 - + sum_decayed_W11_W11_term*W11_dot_W20*W20_dot_W20 ) - ) / det; - viscosity_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz] = ( (upper_boundary_n11-interim_upper_boundary_n11)*( sum_decayed_W11_W20_term*pow(sum_decayed_W20_W11_term,2) - - sum_decayed_W11_W11_term*sum_decayed_W20_W11_term*sum_decayed_W20_W20_term - - sum_decayed_W20_W20_term*W11_dot_W11*W20_dot_W11 - - sum_decayed_W11_W20_term*pow(W20_dot_W11,2) - + sum_decayed_W20_W11_term*W11_dot_W11*W20_dot_W20 - + sum_decayed_W11_W11_term*W20_dot_W11*W20_dot_W20 ) - + (upper_boundary_n20-interim_upper_boundary_n20)*( -sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*sum_decayed_W20_W11_term - + pow(sum_decayed_W11_W11_term,2)*sum_decayed_W20_W20_term - - sum_decayed_W20_W20_term*pow(W11_dot_W11,2) - + sum_decayed_W20_W11_term*W11_dot_W11*W11_dot_W20 - - sum_decayed_W11_W20_term*W11_dot_W11*W20_dot_W11 - + sum_decayed_W11_W11_term*W11_dot_W20*W20_dot_W11 ) - + (lower_boundary_n11-interim_lower_boundary_n11)*( sum_decayed_W20_W11_term*sum_decayed_W20_W20_term*W11_dot_W11 - - pow(sum_decayed_W20_W11_term,2)*W11_dot_W20 - + sum_decayed_W11_W11_term*sum_decayed_W20_W20_term*W20_dot_W11 - + W11_dot_W20*pow(W20_dot_W11,2) - - sum_decayed_W11_W11_term*sum_decayed_W20_W11_term*W20_dot_W20 - - W11_dot_W11*W20_dot_W11*W20_dot_W20 ) - + (lower_boundary_n20-interim_lower_boundary_n20)*( sum_decayed_W11_W20_term*sum_decayed_W20_W11_term*W11_dot_W11 - - sum_decayed_W11_W11_term*sum_decayed_W20_W11_term*W11_dot_W20 - + sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*W20_dot_W11 - - W11_dot_W11*W11_dot_W20*W20_dot_W11 - - pow(sum_decayed_W11_W11_term,2)*W20_dot_W20 - + pow(W11_dot_W11,2)*W20_dot_W20 ) - ) / det; - viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] = ( (upper_boundary_n11-interim_upper_boundary_n11)*( -sum_decayed_W20_W11_term*sum_decayed_W20_W20_term*W11_dot_W11 - + pow(sum_decayed_W20_W11_term,2)*W11_dot_W20 - - sum_decayed_W11_W11_term*sum_decayed_W20_W20_term*W20_dot_W11 - - W11_dot_W20*pow(W20_dot_W11,2) - + sum_decayed_W11_W11_term*sum_decayed_W20_W11_term*W20_dot_W20 - + W11_dot_W11*W20_dot_W11*W20_dot_W20 ) - + (upper_boundary_n20-interim_upper_boundary_n20)*( sum_decayed_W11_W20_term*sum_decayed_W20_W11_term*W11_dot_W11 - - sum_decayed_W11_W11_term*sum_decayed_W20_W11_term*W11_dot_W20 - + sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*W20_dot_W11 - - W11_dot_W11*W11_dot_W20*W20_dot_W11 - - pow(sum_decayed_W11_W11_term,2)*W20_dot_W20 - + pow(W11_dot_W11,2)*W20_dot_W20 ) - + (lower_boundary_n11-interim_lower_boundary_n11)*( -sum_decayed_W11_W20_term*pow(sum_decayed_W20_W11_term,2) - + sum_decayed_W11_W11_term*sum_decayed_W20_W11_term*sum_decayed_W20_W20_term - + sum_decayed_W20_W20_term*W11_dot_W11*W20_dot_W11 - + sum_decayed_W11_W20_term*pow(W20_dot_W11,2) - - sum_decayed_W20_W11_term*W11_dot_W11*W20_dot_W20 - - sum_decayed_W11_W11_term*W20_dot_W11*W20_dot_W20 ) - + (lower_boundary_n20-interim_lower_boundary_n20)*( -sum_decayed_W11_W11_term*sum_decayed_W11_W20_term*sum_decayed_W20_W11_term - + pow(sum_decayed_W11_W11_term,2)*sum_decayed_W20_W20_term - - sum_decayed_W20_W20_term*pow(W11_dot_W11,2) - + sum_decayed_W20_W11_term*W11_dot_W11*W11_dot_W20 - - sum_decayed_W11_W20_term*W11_dot_W11*W20_dot_W11 - + sum_decayed_W11_W11_term*W11_dot_W20*W20_dot_W11 ) - ) / det; - #endif - } - } - - #ifdef BC_HEATFLUX - y_broadcast(heatflux_transients_factors, (mesh->xend-mesh->xstart+1)*(mesh->LocalNz)*2, 0); - #endif - #ifdef BC_VISCOSITY - y_broadcast(viscosity_transients_factors, (mesh->xend-mesh->xstart+1)*(mesh->LocalNz)*2, 0); - #endif - - for (int jx=mesh->xstart; jx<=mesh->xend; jx++) - for (int jz=0; jzLocalNz; jz++) { - #if defined(BC_HEATFLUX) && !defined(BC_VISCOSITY) - for (int i=0; ixstart)*(mesh->LocalNz)+jz]; - heatflux_upper_boundary_transients[i][jx][jz] = W11_B_times_WinverseB_11[i]*heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - #ifdef CALCULATE_VISCOSITY - viscosity_lower_boundary_transients[i][jx][jz] = W20_B_times_WinverseB_11[i]*heatflux_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - viscosity_upper_boundary_transients[i][jx][jz] = -W20_B_times_WinverseB_11[i]*heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - #ifdef CALCULATE_FRICTION - friction_lower_boundary_transients[i][jx][jz] = C10_1k_dot_W1k_B_times_WinverseB_11[i]*heatflux_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - friction_upper_boundary_transients[i][jx][jz] = C10_1k_dot_W1k_B_times_WinverseB_11[i]*heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - } - #elif defined(BC_VISCOSITY) && !defined(BC_HEATFLUX) - for (int i=0; ixstart)*(mesh->LocalNz)+jz]; - heatflux_upper_boundary_transients[i][jx][jz] = -W11_B_times_WinverseB_20[i]*viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - #ifdef CALCULATE_VISCOSITY - viscosity_lower_boundary_transients[i][jx][jz] = W20_B_times_WinverseB_20[i]*viscosity_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - viscosity_upper_boundary_transients[i][jx][jz] = W20_B_times_WinverseB_20[i]*viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - #ifdef CALCULATE_FRICTION - friction_lower_boundary_transients[i][jx][jz] = C10_1k_dot_W1k_B_times_WinverseB_20[i]*viscosity_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - friction_upper_boundary_transients[i][jx][jz] = -C10_1k_dot_W1k_B_times_WinverseB_20[i]*viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - } - #elif defined(BC_HEATFLUX) && defined(BC_VISCOSITY) - for (int i=0; ixstart)*(mesh->LocalNz)+jz] - + W11_B_times_WinverseB_20[i]*viscosity_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - heatflux_upper_boundary_transients[i][jx][jz] = W11_B_times_WinverseB_11[i]*heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] - - W11_B_times_WinverseB_20[i]*viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - #ifdef CALCULATE_VISCOSITY - viscosity_lower_boundary_transients[i][jx][jz] = W20_B_times_WinverseB_11[i]*heatflux_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz] - + W20_B_times_WinverseB_20[i]*viscosity_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - viscosity_upper_boundary_transients[i][jx][jz] = -W20_B_times_WinverseB_11[i]*heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] - + W20_B_times_WinverseB_20[i]*viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - #ifdef CALCULATE_FRICTION - friction_lower_boundary_transients[i][jx][jz] = C10_1k_dot_W1k_B_times_WinverseB_11[i]*heatflux_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz] - + C10_1k_dot_W1k_B_times_WinverseB_20[i]*viscosity_transients_factors[(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - friction_upper_boundary_transients[i][jx][jz] = C10_1k_dot_W1k_B_times_WinverseB_11[i]*heatflux_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz] - - C10_1k_dot_W1k_B_times_WinverseB_20[i]*viscosity_transients_factors[(mesh->xend-mesh->xstart+1)*(mesh->LocalNz)+(jx-mesh->xstart)*(mesh->LocalNz)+jz]; - #endif - } - #else - for (int i=0; ijy=mesh->ystart; - calc_index(position); - do { - for (int i=0; ijx][position->jz] * exp_increasing - + heatflux_upper_boundary_transients[i][position->jx][position->jz] * exp_decreasing; - #endif - #ifdef CALCULATE_VISCOSITY - electron_viscosity[*position] += viscosity_lower_boundary_transients[i][position->jx][position->jz] * exp_increasing - + viscosity_upper_boundary_transients[i][position->jx][position->jz] * exp_decreasing; - #endif - #ifdef CALCULATE_FRICTION - electron_friction[*position] += friction_lower_boundary_transients[i][position->jx][position->jz] * exp_increasing - + friction_upper_boundary_transients[i][position->jx][position->jz] * exp_decreasing; - #endif - } - position->jy++; - calc_index(position); - } while (position->jyyend+1); - } while (next_indexperp(position)); - #endif - - #ifdef CALCULATE_HEATFLUX - electron_heat_flux *= -5./4.*sqrt(2./electron_mass)*interp_to(T_electron^1.5,CELL_YLOW); //now we have q=-5/4*v_Telectron*T_electron*n^(1,1) - mesh->communicate(electron_heat_flux); - #endif - #ifdef CALCULATE_VISCOSITY - electron_viscosity *= T_electron; - mesh->communicate(electron_viscosity); - #endif - #ifdef CALCULATE_FRICTION - electron_friction *= 2.*T_electron/3.*lambdaC_inverse; - electron_friction += -2.*sqrt(2.*electron_mass*T_electron)*lambdaC_inverse*(-jpar/electron_charge); - #endif -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void NonLocalParallel::set_boundary_gradients() { - for (RangeIterator rlow = mesh->iterateBndryLowerY(); !rlow.isDone(); rlow++) - for (int jz=0; jzLocalNz; jz++) { - #ifdef CALCULATE_HEATFLUX -// BoutReal heat_flux_boundarygradient = (electron_heat_flux[rlow.ind][mesh->ystart][jz]-27.*electron_heat_flux[rlow.ind][mesh->ystart+1][jz]+27.*electron_heat_flux[rlow.ind][mesh->ystart+2][jz]-electron_heat_flux[rlow.ind][mesh->ystart+3][jz])/24.; // NB gradient in index space -// BoutReal heat_flux_boundarygradient = (-11.*electron_heat_flux[rlow.ind][mesh->ystart][jz] + 18.*electron_heat_flux[rlow.ind][mesh->ystart+1][jz] - 9.*electron_heat_flux[rlow.ind][mesh->ystart+2][jz] + 2.*electron_heat_flux[rlow.ind][mesh->ystart+3][jz]) / 6. / coord->dy[rlow.ind][mesh->ystart] / sqrt((coord->g_22[rlow.ind][mesh->ystart]+coord->g_22[rlow.ind][mesh->ystart+1]+coord->g_22[rlow.ind][mesh->ystart+2]+coord->g_22[rlow.ind][mesh->ystart+3])/4.); - BoutReal heat_flux_boundarygradient = (-electron_heat_flux[rlow.ind][mesh->ystart][jz] + electron_heat_flux[rlow.ind][mesh->ystart+boundary_gradient_smoothing_length][jz])/BoutReal(boundary_gradient_smoothing_length); // NB gradient in index space - #endif - #ifdef CALCULATE_VISCOSITY -// BoutReal viscosity_boundarygradient = (electron_viscosity[rlow.ind][mesh->ystart][jz]-27.*electron_viscosity[rlow.ind][mesh->ystart+1][jz]+27.*electron_viscosity[rlow.ind][mesh->ystart+2][jz]-electron_viscosity[rlow.ind][mesh->ystart+3][jz])/24.; // NB gradient in index space -// BoutReal viscosity_boundarygradient = (-11.*electron_viscosity[rlow.ind][mesh->ystart][jz] + 18.*electron_viscosity[rlow.ind][mesh->ystart+1][jz] - 9.*electron_viscosity[rlow.ind][mesh->ystart+2][jz] + 2.*electron_viscosity[rlow.ind][mesh->ystart+3][jz]) / 6. / coord->dy[rlow.ind][mesh->ystart] / sqrt((coord->g_22[rlow.ind][mesh->ystart]+coord->g_22[rlow.ind][mesh->ystart+1]+coord->g_22[rlow.ind][mesh->ystart+2]+coord->g_22[rlow.ind][mesh->ystart+3])/4.); - BoutReal viscosity_boundarygradient = (-electron_viscosity[rlow.ind][mesh->ystart][jz] + electron_viscosity[rlow.ind][mesh->ystart+boundary_gradient_smoothing_length][jz])/BoutReal(boundary_gradient_smoothing_length); // NB gradient in index space - #endif - #ifdef CALCULATE_FRICTION -// BoutReal friction_boundarygradient = (electron_friction[rlow.ind][mesh->ystart][jz]-27.*electron_friction[rlow.ind][mesh->ystart+1][jz]+27.*electron_friction[rlow.ind][mesh->ystart+2][jz]-electron_friction[rlow.ind][mesh->ystart+3][jz])/24.; // NB gradient in index space -// BoutReal friction_boundarygradient = (-11.*electron_friction[rlow.ind][mesh->ystart][jz] + 18.*electron_friction[rlow.ind][mesh->ystart+1][jz] - 9.*electron_friction[rlow.ind][mesh->ystart+2][jz] + 2.*electron_friction[rlow.ind][mesh->ystart+3][jz]) / 6. / coord->dy[rlow.ind][mesh->ystart] / sqrt((coord->g_22[rlow.ind][mesh->ystart]+coord->g_22[rlow.ind][mesh->ystart+1]+coord->g_22[rlow.ind][mesh->ystart+2]+coord->g_22[rlow.ind][mesh->ystart+3])/4.); - BoutReal friction_boundarygradient = (-electron_friction[rlow.ind][mesh->ystart][jz] + electron_friction[rlow.ind][mesh->ystart+boundary_gradient_smoothing_length][jz])/BoutReal(boundary_gradient_smoothing_length); // NB gradient in index space - #endif - for (int jy=mesh->ystart-1; jy>=0; jy--) { - #ifdef CALCULATE_HEATFLUX - electron_heat_flux[rlow.ind][jy][jz] = electron_heat_flux[rlow.ind][jy+1][jz] - heat_flux_boundarygradient; - #endif - #ifdef CALCULATE_VISCOSITY - electron_viscosity[rlow.ind][jy][jz] = electron_viscosity[rlow.ind][jy+1][jz] - viscosity_boundarygradient; - #endif - #ifdef CALCULATE_FRICTION - electron_friction[rlow.ind][jy][jz] = electron_friction[rlow.ind][jy+1][jz] - friction_boundarygradient; - #endif - } - } - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jz=0; jzLocalNz; jz++) { - #ifdef CALCULATE_HEATFLUX -// BoutReal heat_flux_boundarygradient = (electron_heat_flux[rup.ind][mesh->yend-3][jz]-27.*electron_heat_flux[rup.ind][mesh->yend-2][jz]+27.*electron_heat_flux[rup.ind][mesh->yend-1][jz]-electron_heat_flux[rup.ind][mesh->yend][jz])/24.; // NB gradient in index space -// BoutReal heat_flux_boundarygradient = (11.*electron_heat_flux[rup.ind][mesh->yend][jz] - 18.*electron_heat_flux[rup.ind][mesh->yend-1][jz] + 9.*electron_heat_flux[rup.ind][mesh->yend-2][jz] - 2.*electron_heat_flux[rup.ind][mesh->yend-3][jz]) / 6. / coord->dy[rup.ind][mesh->yend] / sqrt((coord->g_22[rup.ind][mesh->yend]+coord->g_22[rup.ind][mesh->yend-1]+coord->g_22[rup.ind][mesh->yend-2]+coord->g_22[rup.ind][mesh->yend-3])/4.); - BoutReal heat_flux_boundarygradient = (-electron_heat_flux[rup.ind][mesh->yend-boundary_gradient_smoothing_length][jz] + electron_heat_flux[rup.ind][mesh->yend][jz])/BoutReal(boundary_gradient_smoothing_length); // NB gradient in index space - #endif - #ifdef CALCULATE_VISCOSITY -// BoutReal viscosity_boundarygradient = (electron_viscosity[rup.ind][mesh->yend-3][jz]-27.*electron_viscosity[rup.ind][mesh->yend-2][jz]+27.*electron_viscosity[rup.ind][mesh->yend-1][jz]-electron_viscosity[rup.ind][mesh->yend][jz])/24.; // NB gradient in index space -// BoutReal viscosity_boundarygradient = (11.*electron_viscosity[rup.ind][mesh->yend][jz] - 18.*electron_viscosity[rup.ind][mesh->yend-1][jz] + 9.*electron_viscosity[rup.ind][mesh->yend-2][jz] - 2.*electron_viscosity[rup.ind][mesh->yend-3][jz]) / 6. / coord->dy[rup.ind][mesh->yend] / sqrt((coord->g_22[rup.ind][mesh->yend]+coord->g_22[rup.ind][mesh->yend-1]+coord->g_22[rup.ind][mesh->yend-2]+coord->g_22[rup.ind][mesh->yend-3])/4.); - BoutReal viscosity_boundarygradient = (-electron_viscosity[rup.ind][mesh->yend-boundary_gradient_smoothing_length][jz] + electron_viscosity[rup.ind][mesh->yend][jz])/BoutReal(boundary_gradient_smoothing_length); // NB gradient in index space - #endif - #ifdef CALCULATE_FRICTION -// BoutReal friction_boundarygradient = (electron_friction[rup.ind][mesh->yend-3][jz]-27.*electron_friction[rup.ind][mesh->yend-2][jz]+27.*electron_friction[rup.ind][mesh->yend-1][jz]-electron_friction[rup.ind][mesh->yend][jz])/24.; // NB gradient in index space -// BoutReal friction_boundarygradient = (11.*electron_friction[rup.ind][mesh->yend][jz] - 18.*electron_friction[rup.ind][mesh->yend-1][jz] + 9.*electron_friction[rup.ind][mesh->yend-2][jz] - 2.*electron_friction[rup.ind][mesh->yend-3][jz]) / 6. / coord->dy[rup.ind][mesh->yend] / sqrt((coord->g_22[rup.ind][mesh->yend]+coord->g_22[rup.ind][mesh->yend-1]+coord->g_22[rup.ind][mesh->yend-2]+coord->g_22[rup.ind][mesh->yend-3])/4.); - BoutReal friction_boundarygradient = (-electron_friction[rup.ind][mesh->yend-boundary_gradient_smoothing_length][jz] + electron_friction[rup.ind][mesh->yend][jz])/BoutReal(boundary_gradient_smoothing_length); // NB gradient in index space - #endif - for (int jy=mesh->yend+1; jyLocalNy; jy++) { - #ifdef CALCULATE_HEATFLUX - electron_heat_flux[rup.ind][jy][jz] = electron_heat_flux[rup.ind][jy-1][jz] + heat_flux_boundarygradient; - #endif - #ifdef CALCULATE_VISCOSITY - electron_viscosity[rup.ind][jy][jz] = electron_viscosity[rup.ind][jy-1][jz] + viscosity_boundarygradient; - #endif - #ifdef CALCULATE_FRICTION - electron_friction[rup.ind][jy][jz] = electron_friction[rup.ind][jy-1][jz] + friction_boundarygradient; - #endif - } - } -} - -void NonLocalParallel::set_neumann_boundary_conditions() { - for (RangeIterator rlow = mesh->iterateBndryLowerY(); !rlow.isDone(); rlow++) - for (int jy=0; jyystart; jy++) - for (int jz=0; jzLocalNz; jz++) { - #ifdef CALCULATE_HEATFLUX - electron_heat_flux[rlow.ind][jy][jz]= electron_heat_flux[rlow.ind][mesh->ystart][jz]; - #endif - #ifdef CALCULATE_VISCOSITY - electron_viscosity[rlow.ind][jy][jz]= electron_viscosity[rlow.ind][mesh->ystart][jz]; - #endif - #ifdef CALCULATE_FRICTION - electron_friction[rlow.ind][jy][jz]= electron_friction[rlow.ind][mesh->ystart][jz]; - #endif - } - for (RangeIterator rup = mesh->iterateBndryUpperY(); !rup.isDone(); rup++) - for (int jy=mesh->yend+1; jyLocalNy; jy++) - for (int jz=0; jzLocalNz; jz++) { - #ifdef CALCULATE_HEATFLUX - electron_heat_flux[rup.ind][jy][jz]= electron_heat_flux[rup.ind][mesh->yend][jz]; - #endif - #ifdef CALCULATE_VISCOSITY - electron_viscosity[rup.ind][jy][jz]= electron_viscosity[rup.ind][mesh->yend][jz]; - #endif - #ifdef CALCULATE_FRICTION - electron_friction[rup.ind][jy][jz]= electron_friction[rup.ind][mesh->yend][jz]; - #endif - } -} - -void NonLocalParallel::y_broadcast(void* input_buffer, const int &size, const int &root_processor) { - // NB Assumes that the mesh is BoutMesh - Timer timer("comms"); - - /// NOTE: This only works if there are no branch-cuts - MPI_Comm comm_inner = mesh->getYcomm(0); - -// MPI_Bcast(input_buffer, size, PVEC_REAL_MPI_TYPE, root_processor, comm_yprocs); - MPI_Bcast(input_buffer, size, MPI_DOUBLE, root_processor, comm_inner); -// Should use commented out version if method is transferred to boutmesh.cxx -} - -void NonLocalParallel::rms_over_y(const Field3D &input_field, FieldPerp &output_field) { - FieldPerp tempsum; - tempsum = 0.; - int ye = mesh->yend; - if (mesh->StaggerGrids && input_field.getLocation()==CELL_CENTRE) ye--; - for (int jx=mesh->xstart; jx<=mesh->xend; jx++) - for (int jz=0; jzLocalNz; jz++) - for (int jy=mesh->ystart; jy<=ye; jy++) { - tempsum(jx,jz) += SQ(input_field(jx,jy,jz)); - } - - /// NOTE: This only works if there are no branch-cuts - MPI_Comm comm_inner = mesh->getYcomm(0); - - MPI_Reduce(*tempsum.getData(), - *output_field.getData(), - mesh->LocalNx*mesh->LocalNz, - MPI_DOUBLE, - MPI_SUM, - mesh->getXProcIndex(), // Why? - comm_inner); - - // Don't really understand what this bit is supposed to do. - if (mesh->getYProcIndex()==0) { - int ny = mesh->GlobalNy; - if (mesh->StaggerGrids && input_field.getLocation()==CELL_CENTRE) ny--; - for (int jx=mesh->xstart; jx<=mesh->xend; jx++) - for (int jz=0; jzLocalNz;jz++) - output_field[jx][jz] = sqrt(output_field[jx][jz]/ny); - mesh->sendToProc(mesh->getXProcIndex(),mesh->getNYPE()-1,*output_field.getData(),mesh->LocalNx*mesh->LocalNz,NONLOCAL_PARALLEL_TAGBASE); - } - else if (mesh->getYProcIndex()==mesh->getNYPE()-1) { - mesh->wait(mesh->receiveFromProc(mesh->getXProcIndex(),0,*output_field.getData(),mesh->LocalNx*mesh->LocalNz,NONLOCAL_PARALLEL_TAGBASE)); - } -} - -/* - Calculates a mean over the Y (parallel) direction. - - Should probably be replaced by a call to averageY (src/physics/smoothing.cxx) - */ -void NonLocalParallel::mean_over_y(const Field3D &input_field, FieldPerp &output_field, int exclude_edgecells) { - FieldPerp tempsum; - tempsum = 0.; - int ys = mesh->ystart+exclude_edgecells; - int ye = mesh->yend-exclude_edgecells; - - if (mesh->StaggerGrids && input_field.getLocation()==CELL_CENTRE && mesh->lastY()) ye--; - - for (int jx=mesh->xstart; jx<=mesh->xend; jx++) - for (int jz=0; jzLocalNz; jz++) - for (int jy=ys; jy<=ye; jy++) { - tempsum(jx,jz)+=input_field(jx,jy,jz); - } - - /// NOTE: This only works if there are no branch-cuts - MPI_Comm comm_inner = mesh->getYcomm(0); - - MPI_Reduce(*tempsum.getData(), - *output_field.getData(), - mesh->LocalNx*mesh->LocalNz, - MPI_DOUBLE, - MPI_SUM, - mesh->getXProcIndex(), // Why? - comm_inner); - if (mesh->getYProcIndex()==0) { - int ny = mesh->GlobalNy; - if (mesh->StaggerGrids && input_field.getLocation()==CELL_CENTRE) ny--; - ny-=2*exclude_edgecells; - for (int jx=mesh->xstart; jx<=mesh->xend; jx++) - for (int jz=0; jzLocalNz;jz++) - output_field[jx][jz] = output_field[jx][jz]/ny; - mesh->sendToProc(mesh->getXProcIndex(),mesh->getNYPE()-1,*output_field.getData(),mesh->LocalNx*mesh->LocalNz,NONLOCAL_PARALLEL_TAGBASE); - } - else if (mesh->getYProcIndex()==mesh->getNYPE()-1) { - mesh->wait(mesh->receiveFromProc(mesh->getXProcIndex(),0,*output_field.getData(),mesh->LocalNx*mesh->LocalNz,NONLOCAL_PARALLEL_TAGBASE)); - } -} - -BoutReal NonLocalParallel::interp_to_point_YLOW(const Field3D &input, bindex &position) { - if(mesh->StaggerGrids) - return (9.*(input(position.jx,position.jym,position.jz)+input(position.jx,position.jy,position.jz))-(input(position.jx,position.jy2m,position.jz)+input(position.jx,position.jyp,position.jz)))/16.; - else - return input[position]; -} diff --git a/examples/non-local_1d/non-local_parallel.hxx b/examples/non-local_1d/non-local_parallel.hxx deleted file mode 100644 index 183aecdfb3..0000000000 --- a/examples/non-local_1d/non-local_parallel.hxx +++ /dev/null @@ -1,250 +0,0 @@ -/************************************************************************** - * Calculate non-local electron closures - * - ************************************************************************** - * Copyright 2012 J.T.Omotani - * - * Contact: John Omotani, john.omotani@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - **************************************************************************/ - -#ifndef __NONLOCALPARALLEL_H__ -#define __NONLOCALPARALLEL_H__ - -#define CALCULATE_HEATFLUX -#define CALCULATE_VISCOSITY -#define CALCULATE_FRICTION - -#define BC_HEATFLUX -#define BC_VISCOSITY - -#define DRIVE_GRADT -#define DRIVE_GRADV -#define DRIVE_VEMINUSVI - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cubic_spline_local.hxx" -#include "non-local_parallel_integration.hxx" - -class NonLocalParallel { -public: -// NonLocalParallel(); - ~NonLocalParallel(); - int moments_number; - void initialise(BoutReal pass_electron_charge, BoutReal pass_electron_mass, BoutReal pass_ion_mass, BoutReal pass_epsilon_0, BoutReal pass_logLambda, const bool pass_fluxes_location_is_ylow=false, BoutReal pass_gamma_factor=5./3.); - #ifdef CALCULATE_HEATFLUX - Field3D electron_heat_flux; - #endif - #ifdef CALCULATE_VISCOSITY - Field3D electron_viscosity; - #endif - #ifdef CALCULATE_FRICTION - Field3D electron_friction; - #endif - void calculate_nonlocal_closures(const Field3D &n_electron, const Field3D &T_electron - #ifdef DRIVE_GRADV - , const Field3D &V_electron - #endif - #ifdef DRIVE_VEMINUSVI - , const Field3D &jpar - #endif - #ifdef BC_HEATFLUX - , const Field3D &heat_flux_boundary_condition - #endif - #ifdef BC_VISCOSITY - , const Field3D &viscosity_boundary_condition - #endif - ); - void set_boundary_gradients(); - void set_neumann_boundary_conditions(); - - // Bit of a hack: should put the method somewhere more sensible (like in boutmesh.cxx) - void y_broadcast(void* input_buffer, const int &size, const int &root_processor); // NB Assumes that the mesh is BoutMesh - - void rms_over_y(const Field3D &input_field, FieldPerp &output_field); - void mean_over_y(const Field3D &input_field, FieldPerp &output_field, int exclude_edgecells=0); - BoutReal interp_to_point_YLOW(const Field3D &input, bindex &position); - -private: - Field3D lambdaC_inverse; // inverse collision length, i.e. 1/lambdaC - Field3D increasing_dimensionless_length; // d/dl(increasing_dimensionless_length)=1/lambdaC - Field3D decreasing_dimensionless_length; - Field3D dimensionless_length_deltas_above; // change in dimensionless_length between jy and jy+1, used in calculating integrals. (More accurate than first adding up and then taking differences) - Field3D dimensionless_length_deltas_below; - FieldPerp total_dimensionless_length; - NonLocalParallelIntegration integration; - int number_of_negative_eigenvalues; - BoutReal * eigenvalues; - BoutReal * exp_total_dimensionless_length_over_eigenvalue; - BoutReal electron_charge; - BoutReal electron_mass; - BoutReal ion_mass; - BoutReal epsilon_0; - BoutReal logLambda; - int boundary_gradient_smoothing_length; - BoutReal boundary_condition_smoothing_range; - CubicSpline cubic_spline_inverse_lambdaC; - BoutReal * interp_coefficients; - #ifdef DRIVE_GRADT - Field3D gradT_driveterm; // drive from Maxwellian moments for heat flux calculation. g^(1,1)/T^1.5 as a function of l. - // NB slightly bad notation: drive_term will INCLUDE grad(T) for cell-centred version but EXCLUDE grad(T) (i.e. be only the cell-centred prefactor) for the ylow staggered version, so that grad(T) can be interpolated separately - Field3D gradT_electron; // only used for staggered-grids case - CubicSpline cubic_spline_gradT_driveterm; - CubicSpline cubic_spline_gradT; - #endif - #ifdef DRIVE_GRADV - Field3D gradV_driveterm; - Field3D gradV_electron; - CubicSpline cubic_spline_gradV_driveterm; - CubicSpline cubic_spline_one; - #endif - #ifdef DRIVE_VEMINUSVI - Field3D VeminusVi_driveterm; - CubicSpline cubic_spline_VeminusVi_driveterm; - CubicSpline cubic_spline_jpar; - #endif - #ifdef CALCULATE_HEATFLUX - #ifdef DRIVE_GRADT - BoutReal heatflux_gradT_zerocoeff; - BoutReal * heatflux_gradT_coefficients; - #endif - #ifdef DRIVE_GRADV - BoutReal * heatflux_gradV_coefficients; - #endif - #ifdef DRIVE_VEMINUSVI - BoutReal heatflux_VeminusVi_zerocoeff; - BoutReal * heatflux_VeminusVi_coefficients; - #endif - FieldPerp * heatflux_lower_boundary_transients; - FieldPerp * heatflux_upper_boundary_transients; - #ifdef BC_VISCOSITY - BoutReal * W11_B_times_WinverseB_20; - BoutReal W11_dot_W20; - #endif - #endif - #ifdef BC_HEATFLUX - BoutReal * W11_B_times_WinverseB_11; - BoutReal W11_dot_W11; - BoutReal * heatflux_transients_factors; - FieldPerp pass_interim_upper_boundary_n11; - FieldPerp upper_boundary_condition_n11; - #endif - #ifdef CALCULATE_VISCOSITY - #ifdef DRIVE_GRADT - BoutReal * viscosity_gradT_coefficients; - #endif - #ifdef DRIVE_GRADV - BoutReal * viscosity_gradV_coefficients; - #endif - #ifdef DRIVE_VEMINUSVI - BoutReal * viscosity_VeminusVi_coefficients; - #endif - FieldPerp * viscosity_lower_boundary_transients; - FieldPerp * viscosity_upper_boundary_transients; - #ifdef BC_HEATFLUX - BoutReal * W20_B_times_WinverseB_11; - BoutReal W20_dot_W11; - #endif - #endif - #ifdef BC_VISCOSITY - BoutReal * W20_B_times_WinverseB_20; - BoutReal W20_dot_W20; - BoutReal * viscosity_transients_factors; - FieldPerp pass_interim_upper_boundary_n20; - FieldPerp upper_boundary_condition_n20; - #endif - #ifdef CALCULATE_FRICTION - #ifdef DRIVE_GRADT - BoutReal friction_gradT_zerocoeff; - BoutReal * friction_gradT_coefficients; - #endif - #ifdef DRIVE_GRADV - BoutReal * friction_gradV_coefficients; - #endif - #ifdef DRIVE_VEMINUSVI - BoutReal friction_VeminusVi_zerocoeff; - BoutReal * friction_VeminusVi_coefficients; - #endif - #ifdef BC_HEATFLUX - BoutReal * C10_1k_dot_W1k_B_times_WinverseB_11; - #endif - #ifdef BC_VISCOSITY - BoutReal * C10_1k_dot_W1k_B_times_WinverseB_20; - #endif - FieldPerp * friction_lower_boundary_transients; - FieldPerp * friction_upper_boundary_transients; - #endif - int NONLOCAL_PARALLEL_TAGBASE; - MPI_Request broadcast_request; - MPI_Comm comm_yprocs_minusone; - bindex* position; - bool fluxes_location_is_ylow; - bool is_lower_boundary; - bool is_upper_boundary; - void calculate_nonlocal_closures_cell_centre(const Field3D &n_electron, const Field3D &T_electron - #ifdef DRIVE_GRADV - , const Field3D &V_electron - #endif - #ifdef DRIVE_VEMINUSVI - , const Field3D &jpar - #endif - #ifdef BC_HEATFLUX - , const Field3D &heat_flux_boundary_condition - #endif - #ifdef BC_VISCOSITY - , const Field3D &viscosity_boundary_condition - #endif - ); - void calculate_nonlocal_closures_cell_ylow(const Field3D &n_electron, const Field3D &T_electron - #ifdef DRIVE_GRADV - , const Field3D &V_electron - #endif - #ifdef DRIVE_VEMINUSVI - , const Field3D &jpar - #endif - #ifdef BC_HEATFLUX - , const Field3D &heat_flux_boundary_condition - #endif - #ifdef BC_VISCOSITY - , const Field3D &viscosity_boundary_condition - #endif - ); - #if CHECK > 0 - bool calculated_before_setting_bcs; - #endif -}; - -#endif // __NONLOCALPARALLEL_H__ diff --git a/examples/non-local_1d/non-local_parallel_integration.cxx b/examples/non-local_1d/non-local_parallel_integration.cxx deleted file mode 100644 index f3538f0914..0000000000 --- a/examples/non-local_1d/non-local_parallel_integration.cxx +++ /dev/null @@ -1,585 +0,0 @@ -/*! - * \file heat_flux_integration.cxx - * - * \brief Perform integral needed to calculate non-local electron closures - * - * - ************************************************************************** - * Copyright 2012 J.T.Omotani - * - * Contact: John Omotani, john.omotani@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - */ - -#include "non-local_parallel_integration.hxx" - -/********************************************************************************** - * INTEGRATION INITIALISATION AND CREATION - **********************************************************************************/ - -NonLocalParallelIntegration::NonLocalParallelIntegration() { - position = new bindex; - deltal = new BoutReal; - integral_coeffs = new BoutReal[4]; - integral_parts = new BoutReal[4]; - } - -NonLocalParallelIntegration::~NonLocalParallelIntegration() { - delete position; - delete deltal; - delete [] integral_coeffs; - delete [] integral_parts; -} - -void NonLocalParallelIntegration::initialise(const bool pass_electron_heat_flux_location_is_ylow=false) { - electron_heat_flux_location_is_ylow = pass_electron_heat_flux_location_is_ylow; - - if (electron_heat_flux_location_is_ylow) { - integral_below.setLocation(CELL_YLOW); - integral_above.setLocation(CELL_YLOW); - } - - *deltal = 0.; - for (int i=0; i<4; i++) { - integral_coeffs[i]=0.; - integral_parts[i]=0.; - } - integral_below = 0.0; - integral_above = 0.0; - - // Get the options for the model - Options *options = Options::getRoot()->getSection("non_local_parallel"); - OPTION(options, NONLOCAL_PARALLEL_INTEGRATION_TAGBASE, 16381); -} - - -/********************************************************************************** - * INTEGRATION ROUTINES - **********************************************************************************/ - -void NonLocalParallelIntegration::calculateIntegralBelow_cell_centre(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, const int &counter) { - TRACE("NonLocalParallelIntegration::calculateIntegralBelow()"); - - Coordinates *coord = mesh->coordinates(); - - start_index(position); - do { - position->jy=mesh->ystart-1; - calc_index(position); - if (mesh->firstY()) - next_index_y(position); - else { - // Set the value at ystart-1 equal to the value at yend on the previous processor. - if (position->jxDownXSplitIndex()) { - mesh->wait(mesh->irecvYInIndest(&integral_below[*position],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + mesh->DownXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz)); - } - else { - mesh->wait(mesh->irecvYInOutdest(&integral_below[*position],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + (mesh->LocalNx-mesh->DownXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->DownXSplitIndex()) + position->jz)); - } - } - do { - *deltal = coord->dy(position->jx,position->jyp)*sqrt((coord->g_22(position->jx,position->jy)+coord->g_22(position->jx,position->jyp))/2.); - - interp_coeffs_drive_term = cubic_spline_drive_term.coefficients(position); - interp_coeffs_lambdaC_inverse = cubic_spline_inverse_lambdaC.coefficients(position); - - //calculate the coefficients of drive_term expanded in z rather than l (from the expansion of drive_term in l and l in z [inverted from z in l to third order]) - integral_coeffs[0] = interp_coeffs_drive_term[0]; - integral_coeffs[1] = interp_coeffs_drive_term[1] / *deltal/interp_coeffs_lambdaC_inverse[0]; - integral_coeffs[2] = interp_coeffs_drive_term[2] / pow(*deltal*interp_coeffs_lambdaC_inverse[0],2) - - interp_coeffs_drive_term[1] * interp_coeffs_lambdaC_inverse[1]/2./pow(*deltal,2)/pow(interp_coeffs_lambdaC_inverse[0],3); - integral_coeffs[3] = interp_coeffs_drive_term[3] / pow(*deltal*interp_coeffs_lambdaC_inverse[0],3) - - interp_coeffs_drive_term[2] * interp_coeffs_lambdaC_inverse[1]/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4) - + interp_coeffs_drive_term[1] * (0.5*pow(interp_coeffs_lambdaC_inverse[1],2)/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],5) - interp_coeffs_lambdaC_inverse[2]/3./pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4)); - - // Calculate analytically the integral from jy to jyp of z^n*exp( (zupper-z)/zeta ), firstly allowing for zeta to be large and secondly allowing for it to be small. - BoutReal exp_delta_over_eigenvalue = exp(dimensionless_length_deltas_above[*position]/eigenvalue); - if (dimensionless_length_deltas_above[*position]>abs(eigenvalue)) { - integral_parts[0] = eigenvalue * (exp_delta_over_eigenvalue-1); - integral_parts[1] = pow(eigenvalue,2) * (exp_delta_over_eigenvalue-1) - - eigenvalue * dimensionless_length_deltas_above[*position]; - integral_parts[2] = 2*pow(eigenvalue,3) * (exp_delta_over_eigenvalue-1) - - 2*pow(eigenvalue,2) * dimensionless_length_deltas_above[*position] - eigenvalue * pow(dimensionless_length_deltas_above[*position],2); - integral_parts[3] = 6*pow(eigenvalue,4) * (exp_delta_over_eigenvalue-1) - - 6*pow(eigenvalue,3) * dimensionless_length_deltas_above[*position] - 3*pow(eigenvalue,2) * pow(dimensionless_length_deltas_above[*position],2) - eigenvalue * pow(dimensionless_length_deltas_above[*position],3); - } - else { - BoutReal exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue = exp(dimensionless_length_deltas_above[*position]/eigenvalue/2.) * 2.*sinh(dimensionless_length_deltas_above[*position]/eigenvalue/2.); - integral_parts[0] = eigenvalue * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue; - integral_parts[1] = pow(eigenvalue,2) * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - eigenvalue* dimensionless_length_deltas_above[*position]; - integral_parts[2] = 2*pow(eigenvalue,3) * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - 2*pow(eigenvalue,2) * dimensionless_length_deltas_above[*position] - eigenvalue * pow(dimensionless_length_deltas_above[*position],2); - integral_parts[3] = 6*pow(eigenvalue,4) * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - 6*pow(eigenvalue,3) * dimensionless_length_deltas_above[*position] - 3*pow(eigenvalue,2) * pow(dimensionless_length_deltas_above[*position],2) - eigenvalue * pow(dimensionless_length_deltas_above[*position],3); - } - - //add up the contributions to the integral at jy first from the integral at jy-1 and then from the expansion of the integral between jy-1 and jy - integral_below[position->jx][position->jyp][position->jz] = integral_below[*position] * exp_delta_over_eigenvalue; - for (int i=0; i<4; i++) integral_below[position->jx][position->jyp][position->jz] += integral_coeffs[i]*integral_parts[i]; - - next_index_y(position); - } while (position->jy < mesh->yend); - - // Send the value at yend to the next processor. - if (position->jx < mesh->UpXSplitIndex()) { - Timer timer("comms"); - mesh->sendYOutIndest(&integral_below[*position],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + mesh->UpXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz); - } - else { - Timer timer("comms"); - mesh->sendYOutOutdest(&integral_below[*position],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + (mesh->LocalNx-mesh->UpXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->UpXSplitIndex()) + position->jz); - } - - } while (next_indexperp(position)); - -} - -void NonLocalParallelIntegration::calculateIntegralAbove_cell_centre(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, const int &counter) { - TRACE("NonLocalParallelIntegration::calculateIntegralAbove()"); - - Coordinates *coord = mesh->coordinates(); - - start_index_lasty(position); - do { - position->jy=mesh->yend; - calc_index(position); - if (mesh->lastY()) - previous_index_y(position); - else { - // Set the value at yend+1 to the value at ystart on the previous processor. - if (position->jxUpXSplitIndex()) { - mesh->wait(mesh->irecvYOutIndest(&integral_above[position->jx][position->jyp][position->jz],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + mesh->UpXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz)); - } - else { - mesh->wait(mesh->irecvYOutOutdest(&integral_above[position->jx][position->jyp][position->jz],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + (mesh->LocalNx - mesh->UpXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->UpXSplitIndex()) + position->jz)); - } - } - do { - *deltal = coord->dy(position->jx,position->jy)*sqrt((coord->g_22(position->jx,position->jy)+coord->g_22(position->jx,position->jyp))/2.); - - interp_coeffs_drive_term = cubic_spline_drive_term.coefficients(position); - interp_coeffs_lambdaC_inverse = cubic_spline_inverse_lambdaC.coefficients(position); - - //calculate the coefficients of drive_term expanded in z rather than l (from the expansion of drive_term in l and l in z [inverted from z in l to third order]) - integral_coeffs[0] = interp_coeffs_drive_term[0]; - integral_coeffs[1] = interp_coeffs_drive_term[1] / *deltal/interp_coeffs_lambdaC_inverse[0]; - integral_coeffs[2] = interp_coeffs_drive_term[2] / pow(*deltal*interp_coeffs_lambdaC_inverse[0],2) - - interp_coeffs_drive_term[1] * interp_coeffs_lambdaC_inverse[1]/2./pow(*deltal,2)/pow(interp_coeffs_lambdaC_inverse[0],3); - integral_coeffs[3] = interp_coeffs_drive_term[3] / pow(*deltal*interp_coeffs_lambdaC_inverse[0],3) - - interp_coeffs_drive_term[2] * interp_coeffs_lambdaC_inverse[1]/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4) - + interp_coeffs_drive_term[1] * (0.5*pow(interp_coeffs_lambdaC_inverse[1],2)/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],5) - interp_coeffs_lambdaC_inverse[2]/3./pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4)); - - // Calculate analytically the integral from jyp to jy of z^n*exp( (zupper-z)/zeta ), firstly allowing for zeta to be large and secondly allowing for it to be small. - BoutReal exp_delta_over_eigenvalue = exp(dimensionless_length_deltas_above[*position]/eigenvalue); - if (dimensionless_length_deltas_above[*position]>abs(eigenvalue)) { - integral_parts[0] = -eigenvalue * (exp_delta_over_eigenvalue-1); - integral_parts[1] = pow(eigenvalue,2) * (exp_delta_over_eigenvalue-1) - - eigenvalue* dimensionless_length_deltas_above[*position] * exp_delta_over_eigenvalue; - integral_parts[2] = -2*pow(eigenvalue,3) * (exp_delta_over_eigenvalue-1) - + 2*pow(eigenvalue,2) * dimensionless_length_deltas_above[*position] * exp_delta_over_eigenvalue - - eigenvalue * pow(dimensionless_length_deltas_above[*position],2) * exp_delta_over_eigenvalue; - integral_parts[3] = 6*pow(eigenvalue,4) * (exp_delta_over_eigenvalue-1) - - 6*pow(eigenvalue,3) * dimensionless_length_deltas_above[*position] * exp_delta_over_eigenvalue - + 3*pow(eigenvalue,2) * pow(dimensionless_length_deltas_above[*position],2) * exp_delta_over_eigenvalue - - eigenvalue * pow(dimensionless_length_deltas_above[*position],3) * exp_delta_over_eigenvalue; - } - else { - BoutReal exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue = exp(dimensionless_length_deltas_above[*position]/eigenvalue/2.) * 2.*sinh(dimensionless_length_deltas_above[*position]/eigenvalue/2.); - integral_parts[0] = -eigenvalue * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue; - integral_parts[1] = pow(eigenvalue,2) * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - eigenvalue* dimensionless_length_deltas_above[*position] * exp_delta_over_eigenvalue; - integral_parts[2] = -2*pow(eigenvalue,3) * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + 2*pow(eigenvalue,2) * dimensionless_length_deltas_above[*position] * exp_delta_over_eigenvalue - - eigenvalue * pow(dimensionless_length_deltas_above[*position],2) * exp_delta_over_eigenvalue; - integral_parts[3] = 6*pow(eigenvalue,4) * exp_half_delta_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - 6*pow(eigenvalue,3) * dimensionless_length_deltas_above[*position] * exp_delta_over_eigenvalue - + 3*pow(eigenvalue,2) * pow(dimensionless_length_deltas_above[*position],2) * exp_delta_over_eigenvalue - - eigenvalue * pow(dimensionless_length_deltas_above[*position],3) * exp_delta_over_eigenvalue; - } - - //add up the contributions to the integral at jy first from the integral at jy-1 and then from the expansion of the integral between jy-1 and jy - integral_above[*position] = integral_above[position->jx][position->jyp][position->jz] * exp_delta_over_eigenvalue; - for (int i=0; i<4; i++) integral_above[*position] += integral_coeffs[i]*integral_parts[i]; - - } while (previous_index_y(position)); - - // Send the value at ystart to the next processor. - if (position->jx < mesh->DownXSplitIndex()) { - Timer timer("comms"); - mesh->sendYInIndest(&integral_above[*position],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + mesh->DownXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz); - } - else { - Timer timer("comms"); - mesh->sendYInOutdest(&integral_above[*position],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + (mesh->LocalNx - mesh->DownXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->DownXSplitIndex()) + position->jz); - } - - } while (next_indexperp(position)); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void NonLocalParallelIntegration::calculateIntegralBelow_cell_ylow(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_below, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, CubicSpline &cubic_spline_gradT, const int &counter) { - TRACE("NonLocalParallelIntegration::calculateIntegralBelow()"); - - Coordinates *coord = mesh->coordinates(); - - start_index(position); - do { - position->jy=mesh->ystart; - calc_index(position); - if (!mesh->firstY()) { - // Set the value at ystart to the value at yend+1 of the previous processor. - if (position->jxDownXSplitIndex()) { - mesh->wait(mesh->irecvYInIndest(&integral_below[*position],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + mesh->DownXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz)); - } - else { - mesh->wait(mesh->irecvYInOutdest(&integral_below[*position],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + (mesh->LocalNx-mesh->DownXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->DownXSplitIndex()) + position->jz)); - } - } - do { - *deltal = coord->dy(position->jx,position->jy)*sqrt(coord->g_22(position->jx,position->jy)); - - BoutReal deltazbelow = dimensionless_length_deltas_below[*position]; - BoutReal deltazabove = dimensionless_length_deltas_above[*position]; - BoutReal deltaz = dimensionless_length_deltas_below[*position] + dimensionless_length_deltas_above[*position]; - - interp_coeffs_gradT = cubic_spline_gradT.coefficients(position); - - // Contribution to the integral at jy from points up to jy-1 - integral_below[position->jx][position->jyp][position->jz] = integral_below[*position] * exp(deltaz/eigenvalue); - - // Calculate the contribution from the lower part of the interval (below CELL_CENTRE) - // The integration variable ('z-prime') goes from (dimensionless_length_deltas_above[jy-1]) to (dimensionless_length_deltas_above[jy-1]+dimensionless_length_deltas_below[jy]) with the final z-value (that goes into the exponential) being (dimensionless_length_deltas_above[jy-1]+dimensionless_length_deltas_below[jy]+dimensionless_length_deltas_above[jy]) - BoutReal deltazabovefromjym = dimensionless_length_deltas_above[position->jx][position->jym][position->jz]; - interp_coeffs_drive_term = cubic_spline_drive_term.coefficients(position->jx,position->jym,position->jz); - interp_coeffs_lambdaC_inverse = cubic_spline_inverse_lambdaC.coefficients(position->jx,position->jym,position->jz); - - BoutReal integrand_coefficient0 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient1 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient2 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient3 = interp_coeffs_drive_term[0]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient4 = interp_coeffs_drive_term[1]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient5 = interp_coeffs_drive_term[2]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient6 = interp_coeffs_drive_term[3]*interp_coeffs_gradT[3]; - - // Approximate the sixth order polynomial by the least-squares-fit cubic between t=1/2 and t=1 - BoutReal cubic_integrand_coefficient0 = integrand_coefficient0 - 321./1120.*integrand_coefficient4 - 97./112.*integrand_coefficient5 - 2225./1344.*integrand_coefficient6; - BoutReal cubic_integrand_coefficient1 = integrand_coefficient1 + 45./28.*integrand_coefficient4 + 3065./672.*integrand_coefficient5 + 939./112.*integrand_coefficient6; - BoutReal cubic_integrand_coefficient2 = integrand_coefficient2 - 93./28.*integrand_coefficient4 - 235./28.*integrand_coefficient5 - 3245./224.*integrand_coefficient6; - BoutReal cubic_integrand_coefficient3 = integrand_coefficient3 + 3.*integrand_coefficient4 + 205./36.*integrand_coefficient5 + 35./4.*integrand_coefficient6; - - //calculate the coefficients of the integrand expanded in z rather than l (from the expansion of drive_term in l and l in z [inverted from z in l to third order]) - integral_coeffs[0] = cubic_integrand_coefficient0; - integral_coeffs[1] = cubic_integrand_coefficient1 / *deltal/interp_coeffs_lambdaC_inverse[0]; - integral_coeffs[2] = cubic_integrand_coefficient2 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],2) - - cubic_integrand_coefficient1 * interp_coeffs_lambdaC_inverse[1]/2./pow(*deltal,2)/pow(interp_coeffs_lambdaC_inverse[0],3); - integral_coeffs[3] = cubic_integrand_coefficient3 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],3) - - cubic_integrand_coefficient2 * interp_coeffs_lambdaC_inverse[1]/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4) - + cubic_integrand_coefficient1 * (0.5*pow(interp_coeffs_lambdaC_inverse[1],2)/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],5) - interp_coeffs_lambdaC_inverse[2]/3./pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4)); - - // Calculate analytically the integral from jy-1/2 to jy of z^n*exp( (deltaz+dimensionless_length_deltas_above[jy-1]-z)/zeta ), firstly allowing for zeta to be large and secondly allowing for it to be small. - BoutReal exp_deltaabove_over_eigenvalue = exp(deltazabove/eigenvalue); - if (deltazbelow>abs(eigenvalue)) { - BoutReal exp_deltabelow_over_eigenvalue = exp(deltazbelow/eigenvalue); - integral_parts[0] = exp_deltaabove_over_eigenvalue * eigenvalue * (exp_deltabelow_over_eigenvalue-1); - integral_parts[1] = exp_deltaabove_over_eigenvalue * eigenvalue * ((eigenvalue + deltazabovefromjym) * (exp_deltabelow_over_eigenvalue-1) - - deltazbelow); - integral_parts[2] = exp_deltaabove_over_eigenvalue * eigenvalue * ((pow(deltazabovefromjym,2) + 2.*eigenvalue*(deltazabovefromjym+eigenvalue)) * (exp_deltabelow_over_eigenvalue-1) - - pow(deltazbelow,2)-2.*deltazabovefromjym*deltazbelow - 2.*eigenvalue*deltazbelow); - integral_parts[3] = exp_deltaabove_over_eigenvalue * eigenvalue * ((pow(deltazabovefromjym,3) + 3.*eigenvalue*pow(deltazabovefromjym,2) + 6.*pow(eigenvalue,2)*deltazabovefromjym + 6.*pow(eigenvalue,3)) * (exp_deltabelow_over_eigenvalue-1) - - 3.*pow(deltazabovefromjym,2)*deltazbelow - 3.*deltazabovefromjym*pow(deltazbelow,2) - pow(deltazbelow,3) - 3.*eigenvalue*(2.*deltazabovefromjym*deltazbelow + pow(deltazbelow,2)) - 6.*pow(eigenvalue,2)*deltazbelow); - } - else { - BoutReal exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue = exp(deltazbelow/2./eigenvalue) * 2.*sinh(deltazbelow/eigenvalue/2.); - integral_parts[0] = exp_deltaabove_over_eigenvalue * eigenvalue * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue; - integral_parts[1] = exp_deltaabove_over_eigenvalue * eigenvalue * ((eigenvalue + deltazabovefromjym) * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - deltazbelow); - integral_parts[2] = exp_deltaabove_over_eigenvalue * eigenvalue * ((pow(deltazabovefromjym,2) + 2.*eigenvalue*(deltazabovefromjym+eigenvalue)) * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - pow(deltazbelow,2)-2.*deltazabovefromjym*deltazbelow - 2.*eigenvalue*deltazbelow); - integral_parts[3] = exp_deltaabove_over_eigenvalue * eigenvalue * ((pow(deltazabovefromjym,3) + 3.*eigenvalue*pow(deltazabovefromjym,2) + 6.*pow(eigenvalue,2)*deltazabovefromjym + 6.*pow(eigenvalue,3)) * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - 3.*pow(deltazabovefromjym,2)*deltazbelow - 3.*deltazabovefromjym*pow(deltazbelow,2) - pow(deltazbelow,3) - 3.*eigenvalue*(2.*deltazabovefromjym*deltazbelow + pow(deltazbelow,2)) - 6.*pow(eigenvalue,2)*deltazbelow); - } - - //add on the contributions to the integral at jy from between jy-1 and jy-1/2 - for (int i=0; i<4; i++) integral_below[position->jx][position->jyp][position->jz] += integral_coeffs[i]*integral_parts[i]; - - // Calculate the contribution from the upper part of the interval (above CELL_CENTRE) - // The integration variable ('z-prime') goes from 0 to (dimensionless_length_deltas_above[jy]) with the final z-value (that goes into the exponential) being (dimensionless_length_deltas_above[jy]) - interp_coeffs_drive_term = cubic_spline_drive_term.coefficients(position); - interp_coeffs_lambdaC_inverse = cubic_spline_inverse_lambdaC.coefficients(position); - - integrand_coefficient0 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient1 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient2 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient3 = interp_coeffs_drive_term[0]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient4 = interp_coeffs_drive_term[1]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]); - integrand_coefficient5 = interp_coeffs_drive_term[2]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]); - integrand_coefficient6 = interp_coeffs_drive_term[3]*interp_coeffs_gradT[3]; - - // Approximate the sixth order polynomial by the least-squares-fit cubic between t=0 and t=1/2 - cubic_integrand_coefficient0 = integrand_coefficient0 - 1./1120.*integrand_coefficient4 - 1./1008.*integrand_coefficient5 - 1./1344.*integrand_coefficient6; - cubic_integrand_coefficient1 = integrand_coefficient1 + 1./28.*integrand_coefficient4 + 25./672.*integrand_coefficient5 + 3./112.*integrand_coefficient6; - cubic_integrand_coefficient2 = integrand_coefficient2 - 9./28.*integrand_coefficient4 - 25./84.*integrand_coefficient5 - 45./224.*integrand_coefficient6; - cubic_integrand_coefficient3 = integrand_coefficient3 + integrand_coefficient4 + 25./36.*integrand_coefficient5 + 5./12.*integrand_coefficient6; - - //calculate the coefficients of the integrand expanded in z rather than l (from the expansion of drive_term in l and l in z [inverted from z in l to third order]) - integral_coeffs[0] = cubic_integrand_coefficient0; - integral_coeffs[1] = cubic_integrand_coefficient1 / *deltal/interp_coeffs_lambdaC_inverse[0]; - integral_coeffs[2] = cubic_integrand_coefficient2 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],2) - - cubic_integrand_coefficient1 * interp_coeffs_lambdaC_inverse[1]/2./pow(*deltal,2)/pow(interp_coeffs_lambdaC_inverse[0],3); - integral_coeffs[3] = cubic_integrand_coefficient3 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],3) - - cubic_integrand_coefficient2 * interp_coeffs_lambdaC_inverse[1]/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4) - + cubic_integrand_coefficient1 * (0.5*pow(interp_coeffs_lambdaC_inverse[1],2)/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],5) - interp_coeffs_lambdaC_inverse[2]/3./pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4)); - - // Calculate analytically the integral from jy to jy+1/2 of z^n*exp( (deltazabove-z)/zeta ), firstly allowing for zeta to be large and secondly allowing for it to be small. - if (deltazabove>abs(eigenvalue)) { - BoutReal exp_deltaabove_over_eigenvalue = exp(deltazabove/eigenvalue); - integral_parts[0] = eigenvalue * (exp_deltaabove_over_eigenvalue-1); - integral_parts[1] = eigenvalue * ( eigenvalue*(exp_deltaabove_over_eigenvalue-1) - - deltazabove); - integral_parts[2] = eigenvalue * (2.*pow(eigenvalue,2) * (exp_deltaabove_over_eigenvalue-1) - - pow(deltazabove,2) - 2.*deltazabove*eigenvalue); - integral_parts[3] = eigenvalue*(6.*pow(eigenvalue,3) * (exp_deltaabove_over_eigenvalue-1) - - pow(deltazabove,3) - 3.*pow(deltazabove,2)*eigenvalue - 6.*deltazabove*pow(eigenvalue,2)); - } - else { - BoutReal exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue = exp(deltazabove/2./eigenvalue) * 2.*sinh(deltazabove/eigenvalue/2.); - integral_parts[0] = eigenvalue * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue; - integral_parts[1] = eigenvalue * ( eigenvalue*exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - deltazabove); - integral_parts[2] = eigenvalue * (2.*pow(eigenvalue,2) * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - pow(deltazabove,2) - 2.*deltazabove*eigenvalue); - integral_parts[3] = eigenvalue*(6.*pow(eigenvalue,3) * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - - pow(deltazabove,3) - 3.*pow(deltazabove,2)*eigenvalue - 6.*deltazabove*pow(eigenvalue,2)); - } - - //add on the contributions to the integral at jy from the expansion of the integral between jy-1/2 and jy - for (int i=0; i<4; i++) integral_below[position->jx][position->jyp][position->jz] += integral_coeffs[i]*integral_parts[i]; - - position->jy++; - calc_index(position); - } while (position->jy < mesh->yend+1); - - // Send the value at yend+1 to the next processor. - if (position->jx < mesh->UpXSplitIndex()) { - Timer timer("comms"); - mesh->sendYOutIndest(&integral_below[*position],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + mesh->UpXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz); - } - else { - Timer timer("comms"); - mesh->sendYOutOutdest(&integral_below[*position],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + (mesh->LocalNx-mesh->UpXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->UpXSplitIndex()) + position->jz); - } - - } while (next_indexperp(position)); -} - -void NonLocalParallelIntegration::calculateIntegralAbove_cell_ylow(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_below, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, CubicSpline &cubic_spline_gradT, const int &counter) { - TRACE("NonLocalParallelIntegration::calculateIntegralAbove()"); - - Coordinates *coord = mesh->coordinates(); - - start_index_lasty(position); - do { - position->jy=mesh->yend; - calc_index(position); - if (!mesh->lastY()) { - // Set the value at yend+1 equal to the value at ystart of the previous processor. - if (position->jxUpXSplitIndex()) { - mesh->wait(mesh->irecvYOutIndest(&integral_above[position->jx][position->jyp][position->jz],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + mesh->UpXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz)); - } - else { - mesh->wait(mesh->irecvYOutOutdest(&integral_above[position->jx][position->jyp][position->jz],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + (mesh->LocalNx - mesh->UpXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->UpXSplitIndex()) + position->jz)); - } - } - else { - // Last grid point for CELL_YLOW quantities is mesh->yend on the last y-processor, so start the calculation from mesh->yend-1 if mesh->lastY() - position->jy=mesh->yend-1; - calc_index(position); - } - do { - *deltal = coord->dy(position->jx,position->jy)*sqrt(coord->g_22(position->jx,position->jy)); - - BoutReal deltazbelow = dimensionless_length_deltas_below[*position]; - BoutReal deltazabove = dimensionless_length_deltas_above[*position]; - BoutReal deltaz = dimensionless_length_deltas_below[*position] + dimensionless_length_deltas_above[*position]; - - interp_coeffs_gradT = cubic_spline_gradT.coefficients(position); - - // Contribution to the integral at jy from points up to jy+1 - integral_above[*position] = integral_above[position->jx][position->jyp][position->jz] * exp(deltaz/eigenvalue); - - // Calculate the contribution from the lower part of the interval (below CELL_CENTRE) - // The integration variable ('z-prime') goes from (dimensionless_length_deltas_above[jy-1]+dimensionless_length_deltas_below[jy]) to (dimensionless_length_deltas_above[jy-1]) with the final z-value (that goes into the exponential) being (dimensionless_length_deltas_above[jy-1]) - BoutReal deltazabovefromjym = dimensionless_length_deltas_above[position->jx][position->jym][position->jz]; - interp_coeffs_drive_term = cubic_spline_drive_term.coefficients(position->jx,position->jym,position->jz); - interp_coeffs_lambdaC_inverse = cubic_spline_inverse_lambdaC.coefficients(position->jx,position->jym,position->jz); - - BoutReal integrand_coefficient0 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient1 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient2 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient3 = interp_coeffs_drive_term[0]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[0] - 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] - 0.125*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient4 = interp_coeffs_drive_term[1]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[1] - interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient5 = interp_coeffs_drive_term[2]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[2] - 1.5*interp_coeffs_gradT[3]); - BoutReal integrand_coefficient6 = interp_coeffs_drive_term[3]*interp_coeffs_gradT[3]; - - // Approximate the sixth order polynomial by the least-squares-fit cubic between t=1/2 and t=1 - BoutReal cubic_integrand_coefficient0 = integrand_coefficient0 - 321./1120.*integrand_coefficient4 - 97./112.*integrand_coefficient5 - 2225./1344.*integrand_coefficient6; - BoutReal cubic_integrand_coefficient1 = integrand_coefficient1 + 45./28.*integrand_coefficient4 + 3065./672.*integrand_coefficient5 + 939./112.*integrand_coefficient6; - BoutReal cubic_integrand_coefficient2 = integrand_coefficient2 - 93./28.*integrand_coefficient4 - 235./28.*integrand_coefficient5 - 3245./224.*integrand_coefficient6; - BoutReal cubic_integrand_coefficient3 = integrand_coefficient3 + 3.*integrand_coefficient4 + 205./36.*integrand_coefficient5 + 35./4.*integrand_coefficient6; - - //calculate the coefficients of the integrand expanded in z rather than l (from the expansion of drive_term in l and l in z [inverted from z in l to third order]) - integral_coeffs[0] = cubic_integrand_coefficient0; - integral_coeffs[1] = cubic_integrand_coefficient1 / *deltal/interp_coeffs_lambdaC_inverse[0]; - integral_coeffs[2] = cubic_integrand_coefficient2 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],2) - - cubic_integrand_coefficient1 * interp_coeffs_lambdaC_inverse[1]/2./pow(*deltal,2)/pow(interp_coeffs_lambdaC_inverse[0],3); - integral_coeffs[3] = cubic_integrand_coefficient3 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],3) - - cubic_integrand_coefficient2 * interp_coeffs_lambdaC_inverse[1]/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4) - + cubic_integrand_coefficient1 * (0.5*pow(interp_coeffs_lambdaC_inverse[1],2)/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],5) - interp_coeffs_lambdaC_inverse[2]/3./pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4)); - - // Calculate analytically the integral from jy+1/2 to jy of z^n*exp( -(deltazabovefromjym-z)/zeta ), firstly allowing for zeta to be large and secondly allowing for it to be small. - if (deltazbelow>abs(eigenvalue)) { - BoutReal exp_deltabelow_over_eigenvalue = exp(deltazbelow/eigenvalue); - integral_parts[0] = -eigenvalue * (exp_deltabelow_over_eigenvalue-1); - integral_parts[1] = -eigenvalue * ((-eigenvalue + deltazabovefromjym) * (exp_deltabelow_over_eigenvalue-1) - + deltazbelow*exp_deltabelow_over_eigenvalue); - integral_parts[2] = -eigenvalue * ((pow(deltazabovefromjym,2) - 2.*eigenvalue*(deltazabovefromjym-eigenvalue)) * (exp_deltabelow_over_eigenvalue-1) - + (pow(deltazbelow,2)+2.*deltazabovefromjym*deltazbelow - 2.*eigenvalue*deltazbelow)*exp_deltabelow_over_eigenvalue); - integral_parts[3] = -eigenvalue * ((pow(deltazabovefromjym,3) - 3.*eigenvalue*pow(deltazabovefromjym,2) + 6.*pow(eigenvalue,2)*deltazabovefromjym - 6.*pow(eigenvalue,3)) * (exp_deltabelow_over_eigenvalue-1) - + (3.*pow(deltazabovefromjym,2)*deltazbelow + 3.*deltazabovefromjym*pow(deltazbelow,2) + pow(deltazbelow,3) - 3.*eigenvalue*(2.*deltazabovefromjym*deltazbelow + pow(deltazbelow,2)) + 6.*pow(eigenvalue,2)*deltazbelow)*exp_deltabelow_over_eigenvalue); - } - else { - BoutReal exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue = exp(deltazbelow/2./eigenvalue) * 2.*sinh(deltazbelow/eigenvalue/2.); - integral_parts[0] = -eigenvalue * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue; - integral_parts[1] = -eigenvalue * ((-eigenvalue + deltazbelow + deltazabovefromjym) * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + deltazbelow); - integral_parts[2] = -eigenvalue * ((pow(deltazabovefromjym+deltazbelow,2) - 2.*eigenvalue*(deltazabovefromjym+deltazbelow-eigenvalue)) * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + pow(deltazbelow,2)+2.*deltazabovefromjym*deltazbelow - 2.*eigenvalue*deltazbelow); - integral_parts[3] = -eigenvalue * ((pow(deltazabovefromjym + deltazbelow,3) - 3.*eigenvalue*pow(deltazabovefromjym + deltazbelow,2) + 6.*pow(eigenvalue,2)*(deltazabovefromjym + deltazbelow) - 6.*pow(eigenvalue,3)) * exp_half_deltabelow_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + 3.*pow(deltazabovefromjym,2)*deltazbelow + 3.*deltazabovefromjym*pow(deltazbelow,2) + pow(deltazbelow,3) - 3.*eigenvalue*(2.*deltazabovefromjym*deltazbelow + pow(deltazbelow,2)) + 6.*pow(eigenvalue,2)*deltazbelow); - } - - //add on the contributions to the integral at jy from between jy and jy+1/2 - for (int i=0; i<4; i++) integral_above[*position] += integral_coeffs[i]*integral_parts[i]; - - - // Calculate the contribution from the upper part of the interval (above CELL_CENTRE) - // The integration variable ('z-prime') goes from (dimensionless_length_deltas_above[jy]) to 0 with the final z-value (that goes into the exponential) being (-dimensionless_length_deltas_below[jy]) - interp_coeffs_drive_term = cubic_spline_drive_term.coefficients(position); - interp_coeffs_lambdaC_inverse = cubic_spline_inverse_lambdaC.coefficients(position); - - integrand_coefficient0 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient1 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient2 = interp_coeffs_drive_term[0]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient3 = interp_coeffs_drive_term[0]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[1]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[0] + 0.5*interp_coeffs_gradT[1] + 0.25*interp_coeffs_gradT[2] + 0.125*interp_coeffs_gradT[3]); - integrand_coefficient4 = interp_coeffs_drive_term[1]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[2]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]) - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[1] + interp_coeffs_gradT[2] + 0.75*interp_coeffs_gradT[3]); - integrand_coefficient5 = interp_coeffs_drive_term[2]*interp_coeffs_gradT[3] - + interp_coeffs_drive_term[3]*(interp_coeffs_gradT[2] + 1.5*interp_coeffs_gradT[3]); - integrand_coefficient6 = interp_coeffs_drive_term[3]*interp_coeffs_gradT[3]; - - // Approximate the sixth order polynomial by the least-squares-fit cubic between t=0 and t=1/2 - cubic_integrand_coefficient0 = integrand_coefficient0 - 1./1120.*integrand_coefficient4 - 1./1008.*integrand_coefficient5 - 1./1344.*integrand_coefficient6; - cubic_integrand_coefficient1 = integrand_coefficient1 + 1./28.*integrand_coefficient4 + 25./672.*integrand_coefficient5 + 3./112.*integrand_coefficient6; - cubic_integrand_coefficient2 = integrand_coefficient2 - 9./28.*integrand_coefficient4 - 25./84.*integrand_coefficient5 - 45./224.*integrand_coefficient6; - cubic_integrand_coefficient3 = integrand_coefficient3 + integrand_coefficient4 + 25./36.*integrand_coefficient5 + 5./12.*integrand_coefficient6; - - //calculate the coefficients of the integrand expanded in z rather than l (from the expansion of drive_term in l and l in z [inverted from z in l to third order]) - integral_coeffs[0] = cubic_integrand_coefficient0; - integral_coeffs[1] = cubic_integrand_coefficient1 / *deltal/interp_coeffs_lambdaC_inverse[0]; - integral_coeffs[2] = cubic_integrand_coefficient2 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],2) - - cubic_integrand_coefficient1 * interp_coeffs_lambdaC_inverse[1]/2./pow(*deltal,2)/pow(interp_coeffs_lambdaC_inverse[0],3); - integral_coeffs[3] = cubic_integrand_coefficient3 / pow(*deltal*interp_coeffs_lambdaC_inverse[0],3) - - cubic_integrand_coefficient2 * interp_coeffs_lambdaC_inverse[1]/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4) - + cubic_integrand_coefficient1 * (0.5*pow(interp_coeffs_lambdaC_inverse[1],2)/pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],5) - interp_coeffs_lambdaC_inverse[2]/3./pow(*deltal,3)/pow(interp_coeffs_lambdaC_inverse[0],4)); - - // Calculate analytically the integral from jy+1 to jy+1/2 of z^n*exp( -(-deltazbelow-z)/zeta ), firstly allowing for zeta to be large and secondly allowing for it to be small. - BoutReal exp_deltabelow_over_eigenvalue = exp(deltazbelow/eigenvalue); - if (deltazabove>abs(eigenvalue)) { - BoutReal exp_deltaabove_over_eigenvalue = exp(deltazabove/eigenvalue); - integral_parts[0] = -exp_deltabelow_over_eigenvalue * eigenvalue * (exp_deltaabove_over_eigenvalue-1); - integral_parts[1] = -exp_deltabelow_over_eigenvalue * eigenvalue * (-eigenvalue * (exp_deltaabove_over_eigenvalue-1) - + deltazabove*exp_deltaabove_over_eigenvalue); - integral_parts[2] = -exp_deltabelow_over_eigenvalue * eigenvalue * (2.*pow(eigenvalue,2) * (exp_deltaabove_over_eigenvalue-1) - + (pow(deltazabove,2) - 2.*eigenvalue*deltazabove)*exp_deltaabove_over_eigenvalue); - integral_parts[3] = -exp_deltabelow_over_eigenvalue * eigenvalue * (-6.*pow(eigenvalue,3) * (exp_deltaabove_over_eigenvalue-1) - + (pow(deltazabove,3) - 3.*eigenvalue*pow(deltazabove,2) + 6.*pow(eigenvalue,2)*deltazabove)*exp_deltaabove_over_eigenvalue); - } - else { - BoutReal exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue = exp(deltazabove/2./eigenvalue) * 2.*sinh(deltazabove/eigenvalue/2.); - integral_parts[0] = -exp_deltabelow_over_eigenvalue * eigenvalue * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue; - integral_parts[1] = -exp_deltabelow_over_eigenvalue * eigenvalue * ((-eigenvalue + deltazabove) * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + deltazabove); - integral_parts[2] = -exp_deltabelow_over_eigenvalue * eigenvalue * ((pow(deltazabove,2) - 2.*eigenvalue*deltazabove + 2.*pow(eigenvalue,2)) * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + pow(deltazabove,2) - 2.*eigenvalue*deltazabove); - integral_parts[3] = -exp_deltabelow_over_eigenvalue * eigenvalue * ((pow(deltazabove,3) - 3.*eigenvalue*pow(deltazabove,2) + 6.*pow(eigenvalue,2)*deltazabove - 6.*pow(eigenvalue,3)) * exp_half_deltaabove_over_eigenvalue_times_two_sinh_half_delta_over_eigenvalue - + pow(deltazabove,3) - 3.*eigenvalue*pow(deltazabove,2) + 6.*pow(eigenvalue,2)*deltazabove); - } - - //add on the contributions to the integral at jy from the expansion of the integral between jy+1 and jy+1/2 - for (int i=0; i<4; i++) integral_above[*position] += integral_coeffs[i]*integral_parts[i]; - - } while (previous_index_y(position)); - - // Send the value at ystart to the next processor - if (position->jx < mesh->DownXSplitIndex()) { - Timer timer("comms"); - mesh->sendYInIndest(&integral_above[*position],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + mesh->DownXSplitIndex()*mesh->LocalNz*counter + mesh->LocalNz*position->jx + position->jz); - } - else { - Timer timer("comms"); - mesh->sendYInOutdest(&integral_above[*position],1,NONLOCAL_PARALLEL_INTEGRATION_TAGBASE + (mesh->LocalNx - mesh->DownXSplitIndex())*mesh->LocalNz*counter + mesh->LocalNz*(position->jx-mesh->DownXSplitIndex()) + position->jz); - } - - } while (next_indexperp(position)); -} diff --git a/examples/non-local_1d/non-local_parallel_integration.hxx b/examples/non-local_1d/non-local_parallel_integration.hxx deleted file mode 100644 index 3d315215e7..0000000000 --- a/examples/non-local_1d/non-local_parallel_integration.hxx +++ /dev/null @@ -1,77 +0,0 @@ -/************************************************************************** - * Perform integral needed to calculate non-local electron closures - * - ************************************************************************** - * Copyright 2012 J.T.Omotani - * - * Contact: John Omotani, john.omotani@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - **************************************************************************/ - -#ifndef __NONLOCALPARALLELINTEGRATION_H__ -#define __NONLOCALPARALLELINTEGRATION_H__ - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// #include "cubic_spline.hxx" -#include "cubic_spline_local.hxx" - -/// Class for non-local heat flux integration -class NonLocalParallelIntegration { -public: - NonLocalParallelIntegration(); - ~NonLocalParallelIntegration(); - void initialise(const bool pass_electron_heat_flux_location_is_ylow); - - Field3D integral_below; - Field3D integral_above; - void calculateIntegralBelow_cell_centre(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, const int &counter); - void calculateIntegralAbove_cell_centre(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, const int &counter); - void calculateIntegralBelow_cell_ylow(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_below, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, CubicSpline &cubic_spline_gradT, const int &counter); - void calculateIntegralAbove_cell_ylow(BoutReal eigenvalue, const Field3D &dimensionless_length_deltas_below, const Field3D &dimensionless_length_deltas_above, CubicSpline &cubic_spline_inverse_lambdaC, CubicSpline &cubic_spline_drive_term, CubicSpline &cubic_spline_gradT, const int &counter); - -private: - bindex * position; - BoutReal * deltal; - BoutReal * interp_coeffs_lambdaC_inverse; - BoutReal * interp_coeffs_drive_term; - BoutReal * interp_coeffs_gradT; - BoutReal * integral_coeffs; - BoutReal * integral_parts; - int NONLOCAL_PARALLEL_INTEGRATION_TAGBASE; - bool electron_heat_flux_location_is_ylow; -}; - -#endif //__NONLOCALPARALLELINTEGRATION_H__ diff --git a/examples/non-local_1d/nonlocal_coefficients/frictionbc10 b/examples/non-local_1d/nonlocal_coefficients/frictionbc10 deleted file mode 100644 index 2fadb94799..0000000000 --- a/examples/non-local_1d/nonlocal_coefficients/frictionbc10 +++ /dev/null @@ -1,48 +0,0 @@ --2.4807401378542503e-7 1.1741600797414194e-8 --1.3043200784485268e-6 2.2770864580220653e-7 --6.510264270314584e-6 1.1753988206326143e-6 --1.6312154363349994e-6 3.266392575160382e-7 --0.00016167401480351 0.000029456151398818145 --0.0002418685842150466 0.00004846266124908845 --0.00009045784345468808 0.000018411919367689604 --1.5678379708838777e-7 -1.0679928015377518e-7 --0.0014620589323983562 0.0003200958333228404 --0.00010446185084557347 0.000025121404148548594 --0.0018890125645407165 0.0005019299977918738 --0.00016242528586420517 0.000014578535532117998 --0.0015012293199549592 0.00026695550609723783 --0.0009987143211253671 0.00027683457148806135 --0.006413919204256284 0.002168436483260373 --0.0017958568240180705 0.000358186729522741 --0.00011147641191077068 0.00019880424150907876 --0.000020698865389608915 0.000033466631056901275 --0.011644707668070707 0.004191018801213201 --0.00008921829929907157 0.0001254529179320961 --0.004636349211437851 0.0007741214401383274 --0.002638567729139601 0.0013746164138255486 --0.0033625899829071767 0.003917289323652846 --7.479627461640935e-7 -3.2766859418078903e-6 --0.012483320435281341 0.006547718309532014 --0.00005449623643789861 0.00011875121470806043 --0.012732908764248306 0.0008656472023904798 --0.003730941973991054 0.007848163479933926 --0.001651199475187155 0.0013674341861869943 --0.0057851422733918 0.004950117847553726 --0.0028625460251229962 0.004262813244576952 --0.011464285565088399 0.013683565971773393 --0.02061859036350942 -0.009046026567997996 -0.000019566888953964444 0.000278005911914547 --0.006659458333286221 0.004058270297399383 --0.004441586154969828 0.007011095282393203 --0.002027013640613282 0.008225492363202438 --0.00030088363809045076 0.0025717576360976178 --0.017554186197230648 -0.0004723308508308695 --0.011084258703403916 -0.008915205921295754 --0.000527930910273698 -0.0030497540494061103 --0.036353499365218596 0.015811791421953207 --0.0057374331156836555 -0.01122902536959296 -0.00012684301964484645 0.0008534930948332186 --0.0057048577608756305 0.0018143668120205094 --0.0004300614893221976 -0.0018424251833023993 --0.05467866296627437 -0.02073038080999386 --0.00570479496671954 -0.014604064090202913 diff --git a/examples/non-local_1d/nonlocal_coefficients/frictioncoeffs10 b/examples/non-local_1d/nonlocal_coefficients/frictioncoeffs10 deleted file mode 100644 index f782a03e13..0000000000 --- a/examples/non-local_1d/nonlocal_coefficients/frictioncoeffs10 +++ /dev/null @@ -1,98 +0,0 @@ -48 -0.026669123283992395 2.815724871729616e-115 0.15023661324695003 --30.636269375719603 -1.0312158650919817e-8 1.3115650679152823e-8 - -3.439696741391227e-8 --21.13128472212754 -3.8583946110841886e-7 7.05845689211256e-8 - -1.617437447035112e-8 --18.26918886055369 -1.9538505198381702e-6 4.119935340824775e-7 - -1.3469170946473937e-7 --14.160963277332186 -4.837656085697105e-7 1.3744179260146738e-7 - -6.358092383522401e-8 --13.369826934433009 -0.000049108119982541295 0.000012225196049943268 - -7.251170076292257e-6 --11.243123095526482 -0.00007726778846635106 0.000021359868811932045 - -0.000011992274494871655 --9.624878279875212 -0.00003143160706411396 8.25306993863108e-6 - -4.730868299935623e-6 --8.62142781223786 -1.3773244260634355e-7 -8.009742475649044e-8 - -5.8194307281708276e-9 --8.075728087309695 -0.000539449618711369 0.00015418076315451809 - -0.0000870496689585936 --6.475639623525028 -0.000041007632588948816 0.000013249707550307718 - -7.747840923230205e-6 --6.317211937215521 -0.000720022685122544 0.0002798133226039362 - -0.00014416525731442243 --5.620423869129757 -0.00007888033449783518 3.551127059615868e-6 - -0.000014805488908456405 --4.749989954481883 -0.0007016877859909763 0.00014612556832180226 - -0.000158166338906397 --4.28785944965079 -0.00043605273425982783 0.00017508687753974266 - -0.000115314702282844 --3.9626214940750613 -0.0026679826295633664 0.0015130033553314164 - -0.0007957260118056112 --3.486031643693317 -0.0009449700556349265 0.00021151567028805283 - -0.00024880375442991326 --2.927957911451817 0.00003060554037750489 0.00016820027185840208 - -0.000018588627528469196 --2.7696402461801886 5.4588821862957576e-6 0.00003246339064366476 - -3.510912784709089e-6 --2.3439167689602876 -0.006322095216426263 0.003574731703369322 - -0.0022673952511717043 --2.248487532286778 0.000013509680772071659 0.00013681161842127488 - -0.00001923411549166038 --1.8030986943308447 -0.0033469935448881376 0.0007194223161386336 - -0.001157942535264767 --1.7702843339604837 -0.001537514218656668 0.0011892301102941233 - -0.000675517904799221 --1.6764333245315457 -0.0007085359211031001 0.004055579687952288 - -0.0009542909080315443 --1.347557014152367 -4.468154815862511e-6 -6.890877282494717e-6 - -4.823053931872828e-8 --1.2166018308683488 -0.007927324678095045 0.00813275178768016 - -0.004873656666485574 --1.0848802045388513 -0.000035488478682475836 0.0000668243515473671 - -0.00002486512492702042 --0.9366668832293218 -0.012446212158978148 0.002027777897502625 - -0.006293508299614966 --0.8735346903561486 0.0004755335085672642 0.010866274299888248 - -0.002427654616169127 --0.7383714462517489 -0.0018024217726091286 0.0010208678606014295 - -0.0010792705964842164 --0.6619924821999006 -0.003292377666511077 0.00950994974317114 - -0.004505270050768607 --0.6066543730235356 -0.002222659749785507 0.0053754502979323415 - -0.002416522932512007 --0.4713487171250126 -0.007185280065897441 0.029300946518258913 - -0.01287464686029952 --0.3903166031784771 -0.03143846944797162 -0.006469857490561333 - -0.025034763951708366 --0.3629086970308222 0.00025156227969279094 0.0006900933356494672 - -0.000017029332578986553 --0.3468927042304547 -0.009237275898878348 0.009915910632885107 - -0.009541462779082127 --0.29335280937373287 -0.00904684126665019 0.010130182345528678 - -0.007175544245653537 --0.22788161284757552 0.0010877934234041473 0.024823090733262814 - -0.006151409044863437 --0.17925345221257785 0.001506387438270089 0.00935087759129544 - -0.0016536745552335 --0.15839797216185614 -0.025151339158974342 0.041532536744003784 - -0.06267690340155002 --0.14716803607892 -0.02521811182800083 -0.00943043742299567 - -0.0392105477424055 --0.09412685178369819 -0.003247934413581498 -0.014358710326655115 - -0.002161268517067183 --0.08797936012584812 -0.1377293557598613 0.10953308038275592 - -0.2215112703720869 --0.07480832797584315 -0.01458065811642037 -0.04132409774608616 - -0.045363533099995745 --0.056583465227307526 0.005119938461633398 0.010489375553213396 - -0.0010414627473223097 --0.04523592818481314 0.00746492145253619 0.06602067770517454 - -0.09331374536024897 --0.02684603214651508 -0.005227985490502127 -0.02469092976693051 - -0.008781399547379016 --0.02047513315966905 -0.21266606778566835 0.1044604695954468 - -1.7940482707489185 --0.016252832428901517 -0.026548537212899688 -0.2768368206805615 - -0.23580922443376906 diff --git a/examples/non-local_1d/nonlocal_coefficients/heatfluxbc10 b/examples/non-local_1d/nonlocal_coefficients/heatfluxbc10 deleted file mode 100644 index 76542e4fe5..0000000000 --- a/examples/non-local_1d/nonlocal_coefficients/heatfluxbc10 +++ /dev/null @@ -1,49 +0,0 @@ -0.463746907728502 -0.07717762359651917 -1.3182131534583088e-7 -6.239239804938137e-9 -0.000055149079091656066 -9.627945106953567e-6 -0.00016738788595369944 -0.00003022112706473247 -0.000021998568218840366 -4.4050563949802166e-6 -0.0019407088044163384 -0.0003535868917054067 -0.0027621758275734264 -0.0005534509240898097 -0.0010652385986883112 -0.0002168201942181431 -6.577060869698737e-6 4.480216575029059e-6 -0.016059187966343768 -0.003515917888578209 -0.0009799787424803162 -0.0002356692117510729 -0.016722274610012123 -0.004443279740767217 -0.0015338206006141985 -0.00013766857793707897 -0.01180461504697859 -0.0020991509706483652 -0.006693766301805068 -0.0018554514405214166 -0.03811692553973112 -0.012886681190998266 -0.012089483944083823 -0.0024112683470280363 --0.00032531991083327455 0.0005801673826098584 --0.00005704336763893527 0.00009222966105059045 -0.057548939693204765 -0.020712300825329856 --0.00011107127167403668 0.0001561811336845498 -0.023753025964411333 -0.003965992600783986 -0.010644504722844115 -0.005545474822371306 -0.0044251697807880215 -0.005155154338098984 -0.00012281771071200102 0.0005380415911874212 -0.03598957926303347 -0.018877159191308304 -0.00013785997130455788 -0.00030040678259846956 -0.044632062239368185 -0.003034312153630492 --0.0012953515721583389 0.002724816138433046 -0.004887655163914988 -0.0040476919123737035 -0.007493380730437589 -0.006411790054474629 -0.004666695653233744 -0.006949495960736469 -0.011340450487474563 -0.013535758640515977 -0.04589356560222917 0.020134956193351622 -0.0005123238939422744 0.007279086198430953 -0.01142727811219791 -0.006963777085451087 -0.009925563009263191 -0.015667616378774122 --0.0006353359489531729 0.0025781528508121744 --0.0004858029519123803 0.004152327654466365 -0.01248559429327764 0.00033595014371006496 -0.012635465521127784 0.010162860687985678 -0.0014062111934607594 0.00812340819247312 -0.04006377302066737 -0.01742555829949493 -0.0032686079081712103 0.0063971606089447625 -0.0011052550546626512 0.007436968623305801 --0.0008089084611599912 0.00025726437492562494 -0.0004538121580029341 0.0019441753543456772 -0.011488329937738753 0.004355582992712755 -0.0011383997291868316 0.0029142611964675467 diff --git a/examples/non-local_1d/nonlocal_coefficients/heatfluxcoeffs10 b/examples/non-local_1d/nonlocal_coefficients/heatfluxcoeffs10 deleted file mode 100644 index b16c06ccac..0000000000 --- a/examples/non-local_1d/nonlocal_coefficients/heatfluxcoeffs10 +++ /dev/null @@ -1,97 +0,0 @@ -48 --0.008391056194226176 -8.859273465635475e-116 -0.04726979026498628 --30.636269375719603 5.4796643012957336e-9 -6.969381023672314e-9 - 1.827782531197146e-8 --21.13128472212754 0.000016314010118329927 -2.9844468688329124e-6 - 6.838826386729261e-7 --18.26918886055369 0.000050236195399398815 -0.000010592922780587361 - 3.463109877980909e-6 --14.160963277332186 6.524062061330351e-6 -1.853539749143322e-6 - 8.57452215845034e-7 --13.369826934433009 0.0005894859537834815 -0.00014674928211979833 - 0.00008704187637378544 --11.243123095526482 0.0008824098352601778 -0.00024393293367939536 - 0.00013695358921813675 --9.624878279875212 0.0003701410489657559 -0.00009718879337100059 - 0.00005571107298093782 --8.62142781223786 5.777858908746273e-6 3.3600770482205026e-6 - 2.441243982922366e-7 --8.075728087309695 0.005925289763147506 -0.0016935144004291843 - 0.0009561495540544784 --6.475639623525028 0.0003847012846442954 -0.00012429831214246304 - 0.00007268413629880087 --6.317211937215521 0.006373921112051951 -0.002477016462439775 - 0.001276206980984783 --5.620423869129757 0.0007448857571183226 -0.000033534137314008526 - 0.00013981175264140321 --4.749989954481883 0.005517580883005061 -0.0011490290388223951 - 0.0012437092184130714 --4.28785944965079 0.0029225926139813496 -0.0011734993841313725 - 0.0007728833480367115 --3.9626214940750613 0.015855406342642694 -0.008991543921891061 - 0.004728876085918614 --3.486031643693317 0.0063614204442410975 -0.0014238970867110794 - 0.0016749158141005254 --2.927957911451817 0.00008931568119167355 0.0004908562852463054 - -0.000054246907901152806 --2.7696402461801886 0.000015043965820794543 0.00008946486159683793 - -9.675616752739439e-6 --2.3439167689602876 0.03124422585054834 -0.01766656794491022 - 0.01120562201214607 --2.248487532286778 0.000016818718077490814 0.00017032201417441944 - -0.000023945285708962618 --1.8030986943308447 0.01714737629734963 -0.0036857570850057537 - 0.0059323915975928836 --1.7702843339604837 0.006202636824967014 -0.004797589762724061 - 0.002725172997679997 --1.6764333245315457 0.0009324335594307264 -0.005337144513583592 - 0.0012558472218640766 --1.347557014152367 0.0007336843290730462 0.0011315025741237435 - 7.919598209817534e-6 --1.2166018308683488 0.022854582747052026 -0.02344683184307731 - 0.014050817153067894 --1.0848802045388513 0.00008977575283356919 -0.00016904659457105345 - 0.0000629016907035326 --0.9366668832293218 0.043627118202844366 -0.007107873856998869 - 0.022060336670367876 --0.8735346903561486 0.00016510122168360842 0.00377267874868797 - -0.0008428611984946586 --0.7383714462517489 0.005335282754645552 -0.0030218336097629097 - 0.0031947094118169963 --0.6619924821999006 0.004264551880950142 -0.012318050410042577 - 0.0058355874736428755 --0.6066543730235356 0.003623514347684925 -0.008763384175965182 - 0.003939561832760013 --0.4713487171250126 0.007107666008781906 -0.028984443150853523 - 0.01273557732263456 --0.3903166031784771 0.06997682356586599 0.01440083070400608 - 0.05572323623963272 --0.3629086970308222 0.006586707115496434 0.01806885630798835 - -0.0004458825313840578 --0.3468927042304547 0.015850676648576163 -0.017015177941921724 - 0.01637264523884364 --0.29335280937373287 0.020216875209425916 -0.0226378054275418 - 0.016035108641605067 --0.22788161284757552 0.000340951956650077 0.00778041232233477 - -0.0019280636423023754 --0.17925345221257785 0.002432194282413403 0.015097809790032671 - -0.002670002215917514 --0.15839797216185614 0.017889146961487842 -0.02954044111928614 - 0.044579587947754774 --0.14716803607892 0.028747306521526402 0.01075019720270713 0.04469793942210601 --0.09412685178369819 0.008651286823946091 0.03824625304575384 - 0.005756813858841075 --0.08797936012584812 0.15178614834326418 -0.12071213355894382 - 0.24411892699930202 --0.07480832797584315 0.008306581264606781 0.02354228275387965 - 0.025843543627186053 --0.056583465227307526 0.04461292296672272 0.0913998687740558 - -0.009074854642721382 --0.04523592818481314 0.0010584730378841952 0.009361264915925874 - -0.013231228775254969 --0.02684603214651508 0.005516707346179811 0.02605451638622521 - 0.009266363015118658 --0.02047513315966905 0.04468247430977267 -0.021947799654571356 - 0.3769407908036414 --0.016252832428901517 0.005297797335361683 0.0552431706187887 - 0.047056057018912446 diff --git a/examples/non-local_1d/nonlocal_coefficients/viscositybc10 b/examples/non-local_1d/nonlocal_coefficients/viscositybc10 deleted file mode 100644 index 3eb2c72fbb..0000000000 --- a/examples/non-local_1d/nonlocal_coefficients/viscositybc10 +++ /dev/null @@ -1,49 +0,0 @@ -0.5 -0.3316218963992326 -7.935456828695613e-9 -1.6765862344332242e-7 -1.7613137676957783e-6 -0.000010088843590282184 -6.372498211575571e-6 -0.00003529580487169061 -1.2515127919627524e-6 -6.249974361762429e-6 -0.00008802350962173737 -0.00048312877011531997 -0.00015299569674559845 -0.0007635745047647078 -0.000056930981077099814 -0.0002797021685328142 -2.6054414139508164e-6 3.8248478583599085e-6 -0.001004888843085182 -0.004589896387743156 -0.00007614553528639341 -0.00031663451225130446 -0.001726735689322386 -0.006498566387983418 -6.197724889016719e-6 -0.00006905132786406766 -0.00043714545799889397 -0.002458295722111982 -0.0007450135582774196 -0.0026877268474263345 -0.007307990563738245 -0.02161597140756842 -0.0005397219071913517 -0.0027060278625986867 -0.0031884524917612745 -0.0017878755535166554 -0.0005484799659414912 -0.00033923082860110845 -0.011711452592117533 -0.03254016464068351 -0.0015816357193594991 -0.0011248112145808933 -0.0008524735839429465 -0.005105613956357071 -0.0042892908271143365 -0.00823326729077942 -0.029507521918301072 -0.025329172656149274 -0.0008297784500636239 0.00018941191778511958 -0.019366338127118007 -0.03692220603731187 -0.0005656621301573676 -0.00025958856307116906 -0.0004943601346870069 -0.007271602650905062 -0.06226396046449713 -0.02959969222836164 -0.0022925591810717366 -0.002768303260851406 -0.018520293647367052 -0.02164444100011901 -0.016807192435200877 -0.011286293613746197 -0.055197645237546215 -0.046245369725188695 -0.004143659008758939 0.009444633736751697 -0.01996821177359989 0.0014054225670689048 -0.007475384734914205 -0.012266805687966686 -0.017543781985194695 -0.011114129252662426 -0.0588326062311132 -0.014498158903750651 -0.0257755120823732 -0.003015614589855714 --0.0005547562139574208 -0.020617526584911432 -0.0038004519295634126 0.004725094714470589 -0.03591256788103604 0.006216683163481118 -0.013858157307152858 -0.031861823839214806 -0.018130655570596867 0.00926379808184257 -0.015236346579531334 0.002264370057827869 -0.0022752775752539678 -0.007154085297051365 -0.009182025699182996 0.0021432814113555273 --0.0021394397776671433 -0.005643008086147036 -0.03038867255823045 0.011870746744516141 diff --git a/examples/non-local_1d/nonlocal_coefficients/viscositycoeffs10 b/examples/non-local_1d/nonlocal_coefficients/viscositycoeffs10 deleted file mode 100644 index 03fe295258..0000000000 --- a/examples/non-local_1d/nonlocal_coefficients/viscositycoeffs10 +++ /dev/null @@ -1,98 +0,0 @@ -48 --7.418610115318523e-102 -7.832565320175089e-215 -4.179165722309307e-101 --30.636269375719603 -6.969381023672314e-9 8.864096262546274e-9 - -2.3246885553395966e-8 --21.13128472212754 -2.9844468688329124e-6 5.459677325367738e-7 - -1.2510789099875487e-7 --18.26918886055369 -0.000010592922780587361 2.2336487097275192e-6 - -7.302395260326601e-7 --14.160963277332186 -1.853539749143322e-6 5.266059043211675e-7 - -2.436092345718281e-7 --13.369826934433009 -0.00014674928211979833 0.000036532425691327174 - -0.00002166859581679685 --11.243123095526482 -0.00024393293367939536 0.00006743269822677329 - -0.00003785938173054558 --9.624878279875212 -0.00009718879337100059 0.00002551908680029954 - -0.000014628185594519208 --8.62142781223786 3.3600770482205026e-6 1.9540314064934526e-6 - 1.4196898895725631e-7 --8.075728087309695 -0.0016935144004291843 0.00048402544670449107 - -0.0002732782873887769 --6.475639623525028 -0.00012429831214246304 0.00004016121343538195 - -0.000023484495170914804 --6.317211937215521 -0.002477016462439775 0.0009626116243573065 - -0.0004959562011840142 --5.620423869129757 -0.000033534137314008526 1.5096789737867811e-6 - -6.294208831870928e-6 --4.749989954481883 -0.0011490290388223951 0.0002392838020959024 - -0.0002590008262877355 --4.28785944965079 -0.0011734993841313725 0.000471191502356099 - -0.0003103334103383394 --3.9626214940750613 -0.008991543921891061 0.005099072225090687 - -0.0026817286235901357 --3.486031643693317 -0.0014238970867110794 0.0003187154396279137 - -0.00037490176432892065 --2.927957911451817 0.0004908562852463054 0.002697621398069391 - -0.00029812721957877945 --2.7696402461801886 0.00008946486159683793 0.0005320379982170578 - -0.0000575398617598137 --2.3439167689602876 -0.01766656794491022 0.009989289683317656 - -0.006336046973590989 --2.248487532286778 0.00017032201417441944 0.0017248394543966981 - -0.00024249227991940468 --1.8030986943308447 -0.0036857570850057537 0.0007922381275186593 - -0.0012751428546672865 --1.7702843339604837 -0.004797589762724061 0.0037108197982423565 - -0.0021078554886036108 --1.6764333245315457 -0.005337144513583592 0.030549213153874783 - -0.007188327835565225 --1.347557014152367 0.0011315025741237435 0.0017450257890422932 - 0.000012213761975475099 --1.2166018308683488 -0.02344683184307731 0.024054428363976844 - -0.014414927224532418 --1.0848802045388513 -0.00016904659457105345 0.00031831257588056254 - -0.00011844307923439479 --0.9366668832293218 -0.007107873856998869 0.001158038230536027 - -0.0035941427432096182 --0.8735346903561486 0.00377267874868797 0.08620835627780772 - -0.019259969727832563 --0.7383714462517489 -0.0030218336097629097 0.0017115266022483537 - -0.0018094411707886792 --0.6619924821999006 -0.012318050410042577 0.03558037752621823 - -0.016855947044201607 --0.6066543730235356 -0.008763384175965182 0.02119403839662529 - -0.009527737580921384 --0.4713487171250126 -0.028984443150853523 0.11819603562225253 - -0.05193457549146458 --0.3903166031784771 0.01440083070400608 0.0029636087263984374 - 0.011467523823955333 --0.3629086970308222 0.01806885630798835 0.04956703897014307 - -0.001223158590256131 --0.3468927042304547 -0.017015177941921724 0.018265231624749995 - -0.01757549398649216 --0.29335280937373287 -0.0226378054275418 0.025348637178920056 - -0.017955280708707378 --0.22788161284757552 0.00778041232233477 0.17754646871748656 - -0.043997782761548705 --0.17925345221257785 0.015097809790032671 0.09371942944863089 - -0.0165739989960377 --0.15839797216185614 -0.02954044111928614 0.048780283565261415 - -0.07361450468978435 --0.14716803607892 0.01075019720270713 0.004020089318995995 - 0.016715015126112166 --0.09412685178369819 0.03824625304575384 0.1690818836327313 - 0.025450151412516657 --0.08797936012584812 -0.12071213355894382 0.09599966365441362 - -0.19414233012595916 --0.07480832797584315 0.02354228275387965 0.06672288630042746 - 0.07324505618524638 --0.056583465227307526 0.0913998687740558 0.18725372507302235 - -0.01859193409288726 --0.04523592818481314 0.009361264915925874 0.08279217107061768 - -0.11701860443792857 --0.02684603214651508 0.02605451638622521 0.12305126618510172 - 0.04376353354783362 --0.02047513315966905 -0.021947799654571356 0.010780645367524934 - -0.18515136160184825 --0.016252832428901517 0.0552431706187887 0.5760522169556059 - 0.49068048888770094 diff --git a/examples/non-local_1d/profile-setup_BOUT.inp b/examples/non-local_1d/profile-setup_BOUT.inp deleted file mode 100644 index bce9a96d71..0000000000 --- a/examples/non-local_1d/profile-setup_BOUT.inp +++ /dev/null @@ -1,189 +0,0 @@ -# -# Input file for conduction case -# - -nout = 1002 # Number of output timesteps -timestep = 1.0e-5 # Time between outputs - -#MZ = 1 # Number of points in z -MZ = 1 - -dump_format="nc" # Write NetCDF format files - -grid="conduct_grid.nc" - -StaggerGrids = true - -################################################## -[mesh] - -type = bout - -################################################## -[ddy] # Methods used for parallel (y) derivative terms - -first = C4 -second = C4 -upwind = W3 -flux = U1 - -################################################## -[solver] # Solver settings - -# CVODE # -type = cvode # Which solver to use - -max_timestep = 4.0e-7 -start_timestep = 1.e-9 -mxstep = 2000 - -#atol = 1.0e-10 # absolute tolerance -#rtol = 1.0e-5 # relative tolerance -atol = 1.0e-10 # absolute tolerance -rtol = 1.0e-7 # relative tolerance -use_vector_abstol=true - -################################################## -[output] # Output settings -#low_prec = false -floats = false - -################################################## -[non_local_parallel] # Settings for the non-local model -moments_number = 10 -#NONLOCAL_PARALLEL__TAGBASE = 12381 -#NONLOCAL_PARALLEL_INTEGRATION_TAGBASE = 16381 - -################################################## -[sources] # Settings for the sources - -# the sources have a sine envelope around the centre of the domain, extending until it first reaches zero at +/- source_extent/2. -# the base amplitude is increased between on_time and off_time to *_amplitude + *_transient_amplitude -sources.source_length = 25. # in m - -# 40eV, 1e19m^-3 -#sources.particle_amplitude = 2.97190780803271e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 1.78314468481962e24 # in eV/m^3/s -#sources.ion_heat_amplitude = 1.78314468481962e24 # in eV/m^3/s - -# 100eV, 0.5e19m^-3 -#sources.particle_amplitude = 2.349499417355458e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 3.5242491260331873e24 # in eV/m^3/s -#sources.ion_heat_amplitude = 3.5242491260331873e24 # in eV/m^3/s - -# 100eV, 1e19m^-3 -#sources.particle_amplitude = 4.69899883471091617650831789566e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 7.0484982520663742647624768435e24 # in eV/m^3/s -#sources.ion_heat_amplitude = 7.0484982520663742647624768435e24 # in eV/m^3/s - -# 140eV, 1e19m^-3 -#sources.particle_amplitude = 5.5599304013683811018381815397e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 1.16758538428736003138601812334e25 # in eV/m^3/s -#sources.ion_heat_amplitude = 1.16758538428736003138601812334e25 # in eV/m^3/s - -# 200eV, 1e19m^-3 -#sources.particle_amplitude = 6.6453878816235472058187966917e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 1.99361636448706416174563900752e25 # in eV/m^3/s -#sources.ion_heat_amplitude = 1.99361636448706416174563900752e25 # in eV/m^3/s - -# 250eV, 1e19m^-3 -sources.particle_amplitude = 7.4297695200817885339785368656e22 # in m^-3 s^-1 -sources.electron_heat_amplitude = 2.78616357003067070024195132459e25 # in eV/m^3/s -#sources.electron_heat_amplitude = 7.e25 # in eV/m^3/s -sources.ion_heat_amplitude = 2.78616357003067070024195132459e25 # in eV/m^3/s - -# 300eV, 1e19m^-3 -#sources.particle_amplitude = 8.1389047264262557146095566295e22 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 3.6625071268918150715743004833e25 # in eV/m^3/s -#sources.ion_heat_amplitude = 3.6625071268918150715743004833e25 # in eV/m^3/s - -# 200eV, 1e17m^-3 -#sources.particle_amplitude = 6.6453878816235472058187966917e20 # in m^-3 s^-1 -#sources.electron_heat_amplitude = 1.99361636448706416174563900752e23 # in eV/m^3/s -#sources.ion_heat_amplitude = 1.99361636448706416174563900752e23 # in eV/m^3/s - -sources.on_time = 0#2e-6 # in s -sources.off_time = -200e-6#0202.e-6 # in s - -# 500eV, 2e19m^-3 -#sources.particle_transient_amplitude = 2.10145616412118138312975179139e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 1.57609212309088603734731384354e26 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 1.57609212309088603734731384354e26 # in eV/m^3/s - -# 750eV, 5e19m^-3 -#sources.particle_transient_amplitude = 6.434369148654145856198856725e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 7.2386652922359140882237138157e26 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 7.2386652922359140882237138157e26 # in eV/m^3/s - -# 1000eV, 5e19m^-3 -#sources.particle_transient_amplitude = 7.4297695200817885339785368656e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 1.11446542801226828009678052983e27 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 1.11446542801226828009678052983e27 # in eV/m^3/s - -# 1200eV, 5e19m^-3 -#sources.particle_transient_amplitude = 8.1389047264262557146095566295e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 1.46500285075672602862972019332e27 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 1.46500285075672602862972019332e27 # in eV/m^3/s - -# 1500eV, 5e19m^-3 -sources.particle_transient_amplitude = 9.09957211534171e23 # in m^-3 s^-1 -sources.electron_heat_transient_amplitude = 2.04740372595188e27 # in eV/m^3/s -sources.ion_heat_transient_amplitude = 2.04740372595188e27 # in eV/m^3/s - -# 1500eV, 5e19m^-3, 3:1 ion:electron split -#sources.particle_transient_amplitude = 9.09957211534171e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 1.02370186297594331874986893053e27 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 3.07110558892782995624960679159e27 # in eV/m^3/s - -# 1500eV, 1.5e19m^-3 -#sources.particle_transient_amplitude = 2.729871634602515e23 # in m^-3 s^-1 -#sources.electron_heat_transient_amplitude = 6.142211177855659e26 # in eV/m^3/s -#sources.ion_heat_transient_amplitude = 6.142211177855659e26 # in eV/m^3/s - -################################################## -[all] # Settings for all variables - -scale=1.0 -bndry_target = none -#bndry_target = neumann - -################################################## -[Vpar_ion] # Settings for the Vpar_ion variable - -atol = 1.0e-6 - -#function = 0. -#function = 107000.*(y-pi+pi/256)/pi # 0 # -cos(y/2)*sqrt((2*10.)/(3.34358348e-27/1.602176565e-19)) -function = 107000.*(y-pi)/pi # 0 - -################################################## -[j_parallel] # Settings for the j_parallel variable - -atol = 1.0e-6 - -#function = 0. -function = 1.e6*sin(13*y) -bndry_target = neumann - -################################################## -[T_electron] # Settings for the T_electron variable - -atol = 1.0e-10 - -#function = (1.0 + 1.0*gauss(y-pi, (2*pi/10)))*1.0e-19/1.0e-20 # The form of the initial perturbation. y from 0 to 2*pi, in J/energyunit -function = (100.0 + 0.0*gauss(y-pi+pi/256, (2*pi/10))) # The form of the initial perturbation. y from 0 to 2*pi, in eV -#function = (30.0 + 10.*cos((y-pi+pi/128))) # The form of the initial perturbation. y from 0 to 2*pi, in eV - -################################################## -[n_ion] # Settings for the n_ion variable - -atol = 1.0e9 - -function = 1.e19*(1. + 0.*gauss(y-pi)) - -################################################## -[T_ion] # Settings for the T_ion variable - -atol = 1.0e-10 - -function = (150.0 + 0.0*gauss(y-pi, (2*pi/10))) # The form of the initial perturbation. y from 0 to 2*pi, in eV diff --git a/examples/non-local_1d/sin-single-sources.cxx b/examples/non-local_1d/sin-single-sources.cxx deleted file mode 100644 index 23a34aec78..0000000000 --- a/examples/non-local_1d/sin-single-sources.cxx +++ /dev/null @@ -1,168 +0,0 @@ -// Class to deal with sources and source parameters -class Sources { -public: - Sources(); - ~Sources(); - void initialise(); - Field3D particle_source(BoutReal &t); - Field3D electron_heat_source(BoutReal &t); - Field3D ion_heat_source(BoutReal &t); -// int lower_source_yindex; -// int upper_source_yindex; - BoutReal source_length; - BoutReal particle_amplitude; - BoutReal electron_heat_amplitude; - BoutReal ion_heat_amplitude; - BoutReal on_time; - BoutReal off_time; - BoutReal particle_transient_amplitude; - BoutReal electron_heat_transient_amplitude; - BoutReal ion_heat_transient_amplitude; -private: - bindex* position; - int lower_source_yindex; - int upper_source_yindex; - bool particle_during_transient; - bool particle_started; - bool electron_heat_during_transient; - bool electron_heat_started; - bool ion_heat_during_transient; - bool ion_heat_started; - Field3D particle_source_field; - Field3D electron_heat_source_field; - Field3D ion_heat_source_field; -}; - -Sources::Sources() { - position = new bindex; - particle_during_transient = false; - particle_started = false; - electron_heat_during_transient = false; - electron_heat_started = false; - ion_heat_during_transient = false; - ion_heat_started = false; -} - -Sources::~Sources() { - delete position; -} - -void Sources::initialise() { - // NB This assumes that the metric is CONSTANT! - - Coordinates *coord = mesh->coordinates(); - - lower_source_yindex = (mesh->GlobalNy+1)/2-3 - int(source_length/2./sqrt(coord->g_22(2,2))/coord->dy(2,2)); // GlobalNy+1 in case GlobalNy is odd for some strange reason, then the source is still symmetrical and vanishes if source_length=0 - upper_source_yindex = mesh->GlobalNy/2-3 + int(source_length/2./sqrt(coord->g_22(2,2))/coord->dy(2,2)); -} - -Field3D Sources::particle_source(BoutReal &t) { - if (t>on_time && tYGLOBAL(position->jy)>=lower_source_yindex && mesh->YGLOBAL(position->jy)<=upper_source_yindex) { - particle_source_field[*position] = (particle_amplitude + particle_transient_amplitude) * sin(PI*(1.*(mesh->YGLOBAL(position->jy)-lower_source_yindex))/(1.*(upper_source_yindex-lower_source_yindex))); -// particle_source_field[*position] = (particle_amplitude + particle_transient_amplitude*PI/2*sin(PI*(t-on_time)/(off_time-on_time))) * sin(PI*(1.*(mesh->YGLOBAL(position->jy)-lower_source_yindex))/(1.*(upper_source_yindex-lower_source_yindex))); - } - else { - particle_source_field[*position] = 0.; - } - } while (next_index3(position)); - particle_during_transient = true; - particle_started = true; - } - } - else { - if (particle_during_transient || !particle_started) { - particle_source_field = 0.; - start_index(position); - do { - if (mesh->YGLOBAL(position->jy)>=lower_source_yindex && mesh->YGLOBAL(position->jy)<=upper_source_yindex) { - particle_source_field[*position] = particle_amplitude * sin(PI*(1.*(mesh->YGLOBAL(position->jy)-lower_source_yindex))/(1.*(upper_source_yindex-lower_source_yindex))); - } - else { - particle_source_field[*position] = 0.; - } - } while (next_index3(position)); - particle_during_transient = false; - particle_started = true; - } - } - return particle_source_field; -} - -Field3D Sources::electron_heat_source(BoutReal &t) { - if (t>on_time && tYGLOBAL(position->jy)>=lower_source_yindex && mesh->YGLOBAL(position->jy)<=upper_source_yindex) { - electron_heat_source_field[*position] = (electron_heat_amplitude + electron_heat_transient_amplitude) * sin(PI*(1.*(mesh->YGLOBAL(position->jy)-lower_source_yindex))/(1.*(upper_source_yindex-lower_source_yindex))); -// electron_heat_source_field[*position] = (electron_heat_amplitude + electron_heat_transient_amplitude*PI/2*sin(PI*(t-on_time)/(off_time-on_time))) * sin(PI*(1.*(mesh->YGLOBAL(position->jy)-lower_source_yindex))/(1.*(upper_source_yindex-lower_source_yindex))); - } - else { - electron_heat_source_field[*position] = 0.; - } - } while (next_index3(position)); - electron_heat_during_transient = true; - electron_heat_started = true; - } - } - else { - if (electron_heat_during_transient || !electron_heat_started) { - electron_heat_source_field = 0.; - start_index(position); - do { - if (mesh->YGLOBAL(position->jy)>=lower_source_yindex && mesh->YGLOBAL(position->jy)<=upper_source_yindex) { - electron_heat_source_field[*position] = electron_heat_amplitude * sin(PI*(1.*(mesh->YGLOBAL(position->jy)-lower_source_yindex))/(1.*(upper_source_yindex-lower_source_yindex))); - } - else { - electron_heat_source_field[*position] = 0.; - } - } while (next_index3(position)); - electron_heat_during_transient = false; - electron_heat_started = true; - } - } - return electron_heat_source_field; -} - -Field3D Sources::ion_heat_source(BoutReal &t) { - if (t>on_time && tYGLOBAL(position->jy)>=lower_source_yindex && mesh->YGLOBAL(position->jy)<=upper_source_yindex) { - ion_heat_source_field[*position] = (ion_heat_amplitude + ion_heat_transient_amplitude) * sin(PI*(1.*(mesh->YGLOBAL(position->jy)-lower_source_yindex))/(1.*(upper_source_yindex-lower_source_yindex))); -// ion_heat_source_field[*position] = (ion_heat_amplitude + ion_heat_transient_amplitude*PI/2*sin(PI*(t-on_time)/(off_time-on_time))) * sin(PI*(1.*(mesh->YGLOBAL(position->jy)-lower_source_yindex))/(1.*(upper_source_yindex-lower_source_yindex))); - } - else { - ion_heat_source_field[*position] = 0.; - } - } while (next_index3(position)); - ion_heat_during_transient = true; - ion_heat_started = true; - } - } - else { - if (ion_heat_during_transient || !ion_heat_started) { - ion_heat_source_field = 0; - start_index(position); - do { - if (mesh->YGLOBAL(position->jy)>=lower_source_yindex && mesh->YGLOBAL(position->jy)<=upper_source_yindex) { - ion_heat_source_field[*position] = ion_heat_amplitude * sin(PI*(1.*(mesh->YGLOBAL(position->jy)-lower_source_yindex))/(1.*(upper_source_yindex-lower_source_yindex))); - } - else { - ion_heat_source_field[*position] = 0.; - } - } while (next_index3(position)); - ion_heat_during_transient = false; - ion_heat_started = true; - } - } - return ion_heat_source_field; -} From a9c92cf120376884d462e8f0cd7d656761af7c54 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 6 Feb 2019 12:52:36 +0000 Subject: [PATCH 0707/1783] Remove use of the OPTIONS macro from the examples --- examples/2Dturbulence_multigrid/esel.cxx | 22 +- examples/6field-simple/elm_6f.cxx | 227 +++++++++-------- examples/IMEX/advection-diffusion/imex.cxx | 8 +- .../advection-reaction/split_operator.cxx | 6 +- examples/IMEX/diffusion-nl/diffusion-nl.cxx | 6 +- examples/blob2d-laplacexz/blob2d.cxx | 13 +- examples/blob2d/blob2d.cxx | 12 +- examples/conducting-wall-mode/cwm.cxx | 18 +- examples/conduction/conduction.cxx | 2 +- examples/constraints/alfven-wave/alfven.cxx | 20 +- .../constraints/laplace-dae/laplace_dae.cxx | 8 +- examples/dalf3/dalf3.cxx | 48 ++-- examples/elm-pb/elm_pb.cxx | 232 ++++++++++-------- examples/em-drift/2fluid.cxx | 24 +- examples/fci-wave/fci-wave.cxx | 6 +- examples/finite-volume/fluid/fluid.cxx | 6 +- examples/gravity_reduced/gravity_reduced.cxx | 26 +- examples/gyro-gem/gem.cxx | 90 +++---- examples/hasegawa-wakatani/hw.cxx | 18 +- examples/jorek-compare/jorek_compare.cxx | 28 +-- examples/lapd-drift/lapd_drift.cxx | 146 +++++------ examples/laplacexy/alfven-wave/alfven.cxx | 21 +- examples/laplacexy/laplace_perp/test.cxx | 2 +- examples/orszag-tang/mhd.cxx | 8 +- examples/performance/bracket/bracket.cxx | 14 +- examples/performance/ddx/ddx.cxx | 10 +- examples/performance/ddy/ddy.cxx | 10 +- examples/performance/ddz/ddz.cxx | 10 +- .../iterator-offsets/iterator-offsets.cxx | 10 +- examples/performance/iterator/iterator.cxx | 10 +- .../tuning_regionblocksize.cxx | 8 +- examples/reconnect-2field/2field.cxx | 20 +- examples/shear-alfven-wave/2fluid.cxx | 16 +- examples/subsampling/monitor.cxx | 26 +- examples/tokamak-2fluid/2fluid.cxx | 58 ++--- examples/uedge-benchmark/ue_bmark.cxx | 10 +- 36 files changed, 636 insertions(+), 563 deletions(-) diff --git a/examples/2Dturbulence_multigrid/esel.cxx b/examples/2Dturbulence_multigrid/esel.cxx index a2af1225a0..9bab3856ab 100644 --- a/examples/2Dturbulence_multigrid/esel.cxx +++ b/examples/2Dturbulence_multigrid/esel.cxx @@ -20,17 +20,17 @@ class ESEL : public PhysicsModel { protected: int init(bool restart) { - - Options *options = Options::getRoot()->getSection("esel"); - - OPTION(options, zeta, 2.15e-3) ; - OPTION(options, D, 1.97e-3) ; - // OPTION(options, chi, 4.61e-3) ; - OPTION(options, mu, 3.88e-2) ; - int bracket; - OPTION(options, bracket, 2); - OPTION(options, test_laplacian, false); - + + auto options = Options::root()["esel"]; + + zeta = options["zeta"].withDefault(2.15e-3); + D = options["D"].withDefault(1.97e-3); + // chi = options["chi"].withDefault(4.61e-3) ; + mu = options["mu"].withDefault(3.88e-2); + int bracket; + bracket = options["bracket"].withDefault(2); + test_laplacian = options["test_laplacian"].withDefault(false); + // Set sources and sinks from input profile initial_profile("sigma_n", sigma_n); initial_profile("sigma_T", sigma_T); diff --git a/examples/6field-simple/elm_6f.cxx b/examples/6field-simple/elm_6f.cxx index 66c009c948..d740f12019 100644 --- a/examples/6field-simple/elm_6f.cxx +++ b/examples/6field-simple/elm_6f.cxx @@ -383,45 +383,62 @@ int physics_init(bool restarting) { auto globalOptions = Options::root(); auto options = globalOptions["highbeta"]; - OPTION(options, n0_fake_prof, false); // use the hyperbolic profile of n0. If both n0_fake_prof and - // T0_fake_prof are false, use the profiles from grid file - OPTION(options, n0_height, 0.4); // the total height of profile of N0, in percentage of Ni_x - OPTION(options, n0_ave, 0.01); // the center or average of N0, in percentage of Ni_x - OPTION(options, n0_width, 0.1); // the width of the gradient of N0,in percentage of x - OPTION(options, n0_center, 0.633); // the grid number of the center of N0, in percentage of x - OPTION(options, n0_bottom_x, 0.81); // the start of flat region of N0 on SOL side, in percentage of x - OPTION(options, T0_fake_prof, false); - OPTION(options, Tconst, -1.0); // the amplitude of constant temperature, in percentage - - OPTION(options, experiment_Er, false); - - OPTION(options, laplace_alpha, 1.0); // test parameter for the cross term of invert Lapalace - OPTION(options, Low_limit, 1.0e-10); // limit the negative value of total quantities - OPTION(options, q95_input, 5.0); // input q95 as a constant, if <0 use profile from grid - OPTION(options, local_q, false); // using magnetic field to calculate q profile - OPTION(options, q_alpha, 1.0); // flux-limiting coefficient, typical value is [0.03, 3] - - OPTION(options, gamma_i_BC, -1.0); // sheath energy transmission factor for ion - OPTION(options, gamma_e_BC, -1.0); // sheath energy transmission factor for electron - OPTION(options, Sheath_width, 1); // Sheath boundary width in grid number - - OPTION(options, density, 1.0e19); // Number density [m^-3] - OPTION(options, Zi, 1); // ion charge number - OPTION(options, continuity, false); // use continuity equation - - OPTION(options, evolve_jpar, false); // If true, evolve J raher than Psi - OPTION(options, phi_constraint, false); // Use solver constraint for phi + n0_fake_prof = options["n0_fake_prof"].withDefault( + false); // use the hyperbolic profile of n0. If both n0_fake_prof and + // T0_fake_prof are false, use the profiles from grid file + n0_height = options["n0_height"].withDefault( + 0.4); // the total height of profile of N0, in percentage of Ni_x + n0_ave = options["n0_ave"].withDefault( + 0.01); // the center or average of N0, in percentage of Ni_x + n0_width = options["n0_width"].withDefault( + 0.1); // the width of the gradient of N0,in percentage of x + n0_center = options["n0_center"].withDefault( + 0.633); // the grid number of the center of N0, in percentage of x + n0_bottom_x = options["n0_bottom_x"].withDefault( + 0.81); // the start of flat region of N0 on SOL side, in percentage of x + T0_fake_prof = options["T0_fake_prof"].withDefault(false); + Tconst = options["Tconst"].withDefault( + -1.0); // the amplitude of constant temperature, in percentage + + experiment_Er = options["experiment_Er"].withDefault(false); + + laplace_alpha = options["laplace_alpha"].withDefault( + 1.0); // test parameter for the cross term of invert Lapalace + Low_limit = options["Low_limit"].withDefault( + 1.0e-10); // limit the negative value of total quantities + q95_input = options["q95_input"].withDefault( + 5.0); // input q95 as a constant, if <0 use profile from grid + local_q = options["local_q"].withDefault( + false); // using magnetic field to calculate q profile + q_alpha = options["q_alpha"].withDefault( + 1.0); // flux-limiting coefficient, typical value is [0.03, 3] + + gamma_i_BC = options["gamma_i_BC"].withDefault( + -1.0); // sheath energy transmission factor for ion + gamma_e_BC = options["gamma_e_BC"].withDefault( + -1.0); // sheath energy transmission factor for electron + Sheath_width = + options["Sheath_width"].withDefault(1); // Sheath boundary width in grid number + + density = options["density"].withDefault(1.0e19); // Number density [m^-3] + Zi = options["Zi"].withDefault(1); // ion charge number + continuity = options["continuity"].withDefault(false); // use continuity equation + + evolve_jpar = + options["evolve_jpar"].withDefault(false); // If true, evolve J raher than Psi + phi_constraint = + options["phi_constraint"].withDefault(false); // Use solver constraint for phi // Effects to include/exclude - OPTION(options, include_curvature, true); - OPTION(options, include_jpar0, true); - OPTION(options, evolve_pressure, true); + include_curvature = options["include_curvature"].withDefault(true); + include_jpar0 = options["include_jpar0"].withDefault(true); + evolve_pressure = options["evolve_pressure"].withDefault(true); - OPTION(options, compress0, false); - OPTION(options, nonlinear, false); + compress0 = options["compress0"].withDefault(false); + nonlinear = options["nonlinear"].withDefault(false); // int bracket_method; - OPTION(options, bracket_method_exb, 0); + bracket_method_exb = options["bracket_method_exb"].withDefault(0); switch (bracket_method_exb) { case 0: { bm_exb = BRACKET_STD; @@ -449,7 +466,7 @@ int physics_init(bool restarting) { } // int bracket_method; - OPTION(options, bracket_method_mag, 2); + bracket_method_mag = options["bracket_method_mag"].withDefault(2); switch (bracket_method_mag) { case 0: { bm_mag = BRACKET_STD; @@ -476,106 +493,124 @@ int physics_init(bool restarting) { return 1; } - OPTION(options, AA, 1.0); // ion mass in units of proton mass + AA = options["AA"].withDefault(1.0); // ion mass in units of proton mass Mi *= AA; - OPTION(options, emass, false); // including electron inertial, electron mass - OPTION(options, emass_inv, 1.0); // inverse of electron mass + emass = + options["emass"].withDefault(false); // including electron inertial, electron mass + emass_inv = options["emass_inv"].withDefault(1.0); // inverse of electron mass - OPTION(options, diamag, false); // Diamagnetic effects? - OPTION(options, diamag_phi0, diamag); // Include equilibrium phi0 - OPTION(options, dia_fact, 1.0); // Scale diamagnetic effects by this factor + diamag = options["diamag"].withDefault(false); // Diamagnetic effects? + diamag_phi0 = options["diamag_phi0"].withDefault(diamag); // Include equilibrium phi0 + dia_fact = + options["dia_fact"].withDefault(1.0); // Scale diamagnetic effects by this factor - OPTION(options, noshear, false); + noshear = options["noshear"].withDefault(false); - OPTION(options, relax_j_vac, false); // Relax vacuum current to zero - OPTION(options, relax_j_tconst, 0.1); + relax_j_vac = options["relax_j_vac"].withDefault(false); // Relax vacuum current to zero + relax_j_tconst = options["relax_j_tconst"].withDefault(0.1); // Toroidal filtering - OPTION(options, filter_z, false); // Filter a single n - OPTION(options, filter_z_mode, 1); - OPTION(options, low_pass_z, -1); // Low-pass filter - OPTION(options, zonal_flow, -1); // zonal flow filter - OPTION(options, zonal_field, -1); // zonal field filter - OPTION(options, zonal_bkgd, -1); // zonal background P filter + filter_z = options["filter_z"].withDefault(false); // Filter a single n + filter_z_mode = options["filter_z_mode"].withDefault(1); + low_pass_z = options["low_pass_z"].withDefault(-1); // Low-pass filter + zonal_flow = options["zonal_flow"].withDefault(-1); // zonal flow filter + zonal_field = options["zonal_field"].withDefault(-1); // zonal field filter + zonal_bkgd = options["zonal_bkgd"].withDefault(-1); // zonal background P filter - OPTION(options, filter_nl, -1); // zonal background P filter + filter_nl = options["filter_nl"].withDefault(-1); // zonal background P filter // Radial smoothing - OPTION(options, smooth_j_x, false); // Smooth Jpar in x + smooth_j_x = options["smooth_j_x"].withDefault(false); // Smooth Jpar in x // Jpar boundary region - OPTION(options, jpar_bndry_width, -1); + jpar_bndry_width = options["jpar_bndry_width"].withDefault(-1); // Parallel differencing - OPTION(options, parallel_lr_diff, false); + parallel_lr_diff = options["parallel_lr_diff"].withDefault(false); OPTION(options, parallel_lagrange, false); // Use a (semi-) Lagrangian method for Grad_parP - OPTION(options, parallel_project, false); + parallel_project = options["parallel_project"].withDefault(false); // Vacuum region control - OPTION(options, vacuum_pressure, 0.02); // Fraction of peak pressure - OPTION(options, vacuum_trans, 0.005); // Transition width in pressure + vacuum_pressure = + options["vacuum_pressure"].withDefault(0.02); // Fraction of peak pressure + vacuum_trans = + options["vacuum_trans"].withDefault(0.005); // Transition width in pressure // Resistivity and hyper-resistivity options - OPTION(options, vac_lund, 0.0); // Lundquist number in vacuum region - OPTION(options, core_lund, 0.0); // Lundquist number in core region - OPTION(options, hyperresist, -1.0); - OPTION(options, ehyperviscos, -1.0); - OPTION(options, spitzer_resist, false); // Use Spitzer resistivity + vac_lund = options["vac_lund"].withDefault(0.0); // Lundquist number in vacuum region + core_lund = options["core_lund"].withDefault(0.0); // Lundquist number in core region + hyperresist = options["hyperresist"].withDefault(-1.0); + ehyperviscos = options["ehyperviscos"].withDefault(-1.0); + spitzer_resist = + options["spitzer_resist"].withDefault(false); // Use Spitzer resistivity // Inner boundary damping - OPTION(options, damp_width, 0); - OPTION(options, damp_t_const, 0.1); + damp_width = options["damp_width"].withDefault(0); + damp_t_const = options["damp_t_const"].withDefault(0.1); // Viscosity and hyper-viscosity - OPTION(options, viscos_par, -1.0); // Parallel viscosity - OPTION(options, viscos_perp, -1.0); // Perpendicular viscosity - OPTION(options, hyperviscos, -1.0); // Radial hyperviscosity - - OPTION(options, diffusion_par, -1.0); // Parallel temperature diffusion - OPTION(options, diffusion_n4, -1.0); // M: 4th Parallel density diffusion - OPTION(options, diffusion_ti4, -1.0); // M: 4th Parallel ion temperature diffusion - OPTION(options, diffusion_te4, -1.0); // M: 4th Parallel electron temperature diffusion - OPTION(options, diffusion_v4, -1.0); // M: 4th Parallel ion parallel velocity diffusion + viscos_par = options["viscos_par"].withDefault(-1.0); // Parallel viscosity + viscos_perp = options["viscos_perp"].withDefault(-1.0); // Perpendicular viscosity + hyperviscos = options["hyperviscos"].withDefault(-1.0); // Radial hyperviscosity + + diffusion_par = + options["diffusion_par"].withDefault(-1.0); // Parallel temperature diffusion + diffusion_n4 = + options["diffusion_n4"].withDefault(-1.0); // M: 4th Parallel density diffusion + diffusion_ti4 = options["diffusion_ti4"].withDefault( + -1.0); // M: 4th Parallel ion temperature diffusion + diffusion_te4 = options["diffusion_te4"].withDefault( + -1.0); // M: 4th Parallel electron temperature diffusion + diffusion_v4 = options["diffusion_v4"].withDefault( + -1.0); // M: 4th Parallel ion parallel velocity diffusion OPTION(options, diffusion_u4, -1.0); // xqx: parallel hyper-viscous diffusion for vorticity // heating factor in pressure - OPTION(options, heating_P, -1.0); // heating power in pressure - OPTION(options, hp_width, 0.1); // the percentage of radial grid points for heating - // profile radial width in pressure - OPTION(options, hp_length, 0.04); // the percentage of radial grid points for heating - // profile radial domain in pressure + heating_P = options["heating_P"].withDefault(-1.0); // heating power in pressure + hp_width = options["hp_width"].withDefault( + 0.1); // the percentage of radial grid points for heating + // profile radial width in pressure + hp_length = options["hp_length"].withDefault( + 0.04); // the percentage of radial grid points for heating + // profile radial domain in pressure // sink factor in pressure - OPTION(options, sink_vp, -1.0); // sink in pressure - OPTION(options, sp_width, 0.05); // the percentage of radial grid points for sink - // profile radial width in pressure - OPTION(options, sp_length, 0.04); // the percentage of radial grid points for sink - // profile radial domain in pressure + sink_vp = options["sink_vp"].withDefault(-1.0); // sink in pressure + sp_width = options["sp_width"].withDefault( + 0.05); // the percentage of radial grid points for sink + // profile radial width in pressure + sp_length = options["sp_length"].withDefault( + 0.04); // the percentage of radial grid points for sink + // profile radial domain in pressure // left edge sink factor in vorticity - OPTION(options, sink_Ul, -1.0); // left edge sink in vorticity - OPTION(options, su_widthl, 0.06); // the percentage of left edge radial grid points for - // sink profile radial width in vorticity - OPTION(options, su_lengthl, 0.15); // the percentage of left edge radial grid points - // for sink profile radial domain in vorticity + sink_Ul = options["sink_Ul"].withDefault(-1.0); // left edge sink in vorticity + su_widthl = options["su_widthl"].withDefault( + 0.06); // the percentage of left edge radial grid points for + // sink profile radial width in vorticity + su_lengthl = options["su_lengthl"].withDefault( + 0.15); // the percentage of left edge radial grid points + // for sink profile radial domain in vorticity // right edge sink factor in vorticity - OPTION(options, sink_Ur, -1.0); // right edge sink in vorticity - OPTION(options, su_widthr, 0.06); // the percentage of right edge radial grid points - // for sink profile radial width in vorticity - OPTION(options, su_lengthr, 0.15); // the percentage of right edge radial grid points - // for sink profile radial domain in vorticity + sink_Ur = options["sink_Ur"].withDefault(-1.0); // right edge sink in vorticity + su_widthr = options["su_widthr"].withDefault( + 0.06); // the percentage of right edge radial grid points + // for sink profile radial width in vorticity + su_lengthr = options["su_lengthr"].withDefault( + 0.15); // the percentage of right edge radial grid points + // for sink profile radial domain in vorticity // Compressional terms - OPTION(options, phi_curv, true); + phi_curv = options["phi_curv"].withDefault(true); g = options["gamma"].withDefault(5.0 / 3.0); // Field inversion flags - OPTION(options, phi_flags, 0); - OPTION(options, apar_flags, 0); + phi_flags = options["phi_flags"].withDefault(0); + apar_flags = options["apar_flags"].withDefault(0); if (!include_curvature) b0xcv = 0.0; diff --git a/examples/IMEX/advection-diffusion/imex.cxx b/examples/IMEX/advection-diffusion/imex.cxx index fe3fb2a0ba..4df83f93ec 100644 --- a/examples/IMEX/advection-diffusion/imex.cxx +++ b/examples/IMEX/advection-diffusion/imex.cxx @@ -27,10 +27,10 @@ int physics_init(bool restarting) { solver->setSplitOperator(physics_run,diffusive); // Get options - Options *options = Options::getRoot(); - options = options->getSection("imex"); - OPTION(options, cz, 100.0); - OPTION(options, cx, 1.0); + auto globalOptions = Options::root(); + auto options = globalOptions["imex"]; + cz = options["cz"].withDefault(100.0); + cx = options["cx"].withDefault(1.0); SOLVE_FOR(U); diff --git a/examples/IMEX/advection-reaction/split_operator.cxx b/examples/IMEX/advection-reaction/split_operator.cxx index cfda39fdfe..1fcd5e8c23 100644 --- a/examples/IMEX/advection-reaction/split_operator.cxx +++ b/examples/IMEX/advection-reaction/split_operator.cxx @@ -36,9 +36,9 @@ int physics_init(bool restarting) { solver->setSplitOperator(physics_run, reaction); // Get options - Options *options = Options::getRoot(); - options = options->getSection("split"); - OPTION(options, rate, 1.0); + auto globalOptions = Options::root(); + auto options = globalOptions["split"]; + rate = options["rate"].withDefault(1.0); // Get phi settings from BOUT.inp phi.setBoundary("phi"); diff --git a/examples/IMEX/diffusion-nl/diffusion-nl.cxx b/examples/IMEX/diffusion-nl/diffusion-nl.cxx index 6a3ed38e95..920a43b94c 100644 --- a/examples/IMEX/diffusion-nl/diffusion-nl.cxx +++ b/examples/IMEX/diffusion-nl/diffusion-nl.cxx @@ -23,9 +23,9 @@ class DiffusionNL : public PhysicsModel { protected: int init(bool restarting) { // Get the input parameter alpha - Options *opt = Options::getRoot(); - OPTION(opt, alpha, 2.5); - + auto opt = Options::root(); + alpha = opt["alpha"].withDefault(2.5); + // Specify that the operator is split // into convective and diffusive parts setSplitOperator(); diff --git a/examples/blob2d-laplacexz/blob2d.cxx b/examples/blob2d-laplacexz/blob2d.cxx index a22f72adf8..7fc57dbe27 100644 --- a/examples/blob2d-laplacexz/blob2d.cxx +++ b/examples/blob2d-laplacexz/blob2d.cxx @@ -56,15 +56,18 @@ class Blob2D : public PhysicsModel { R_c = options["R_c"].withDefault(1.5); // Radius of curvature L_par = options["L_par"].withDefault(10); // Parallel connection length - OPTION(options, B0, 0.35); // Value of magnetic field strength + B0 = options["B0"].withDefault(0.35); // Value of magnetic field strength // System option switches - OPTION(options, compressible, false); // Include compressible ExB term in density equation - OPTION(options, boussinesq, true); // Use Boussinesq approximation in vorticity - OPTION(options, sheath, true); // Sheath closure + compressible = options["compressible"].withDefault( + false); // Include compressible ExB term in density equation + boussinesq = options["boussinesq"].withDefault( + true); // Use Boussinesq approximation in vorticity + sheath = options["sheath"].withDefault(true); // Sheath closure - OPTION(options, boussinesq_reuse, 0); // How many times to reuse n in vorticity? + boussinesq_reuse = options["boussinesq_reuse"].withDefault( + 0); // How many times to reuse n in vorticity? boussinesq_used = boussinesq_reuse + 1; // Ensure updated first time /***************Calculate the Parameters **********/ diff --git a/examples/blob2d/blob2d.cxx b/examples/blob2d/blob2d.cxx index bb4b08f38c..bab001e62c 100644 --- a/examples/blob2d/blob2d.cxx +++ b/examples/blob2d/blob2d.cxx @@ -65,14 +65,16 @@ class Blob2D : public PhysicsModel { R_c = options["R_c"].withDefault(1.5); // Radius of curvature L_par = options["L_par"].withDefault(10); // Parallel connection length - - OPTION(options, B0, 0.35); // Value of magnetic field strength + + B0 = options["B0"].withDefault(0.35); // Value of magnetic field strength // System option switches - OPTION(options, compressible, false); // Compressible ExB term in density equation - OPTION(options, boussinesq, true); // Use Boussinesq approximation in vorticity - OPTION(options, sheath, true); // Sheath closure + compressible = options["compressible"].withDefault( + false); // Compressible ExB term in density equation + boussinesq = options["boussinesq"].withDefault( + true); // Use Boussinesq approximation in vorticity + sheath = options["sheath"].withDefault(true); // Sheath closure /***************Calculate the Parameters **********/ diff --git a/examples/conducting-wall-mode/cwm.cxx b/examples/conducting-wall-mode/cwm.cxx index f99a5f884b..25f5c2f914 100644 --- a/examples/conducting-wall-mode/cwm.cxx +++ b/examples/conducting-wall-mode/cwm.cxx @@ -111,19 +111,19 @@ class CWM : public PhysicsModel { auto globalOptions = Options::root(); auto options = globalOptions["2fluid"]; - OPTION(options, AA, 4.0); // <=> options.get("AA", AA, 1.0); - OPTION(options, ZZ, 1.0); + AA = options["AA"].withDefault(4.0); // <=> options["AA"].withDefault(1.0); + ZZ = options["ZZ"].withDefault(1.0); - OPTION(options, zeff, 1.0); - OPTION(options, nu_perp, 0.0); - OPTION(options, ShearFactor, 1.0); - OPTION(options, bout_exb, false); + zeff = options["zeff"].withDefault(1.0); + nu_perp = options["nu_perp"].withDefault(0.0); + ShearFactor = options["ShearFactor"].withDefault(1.0); + bout_exb = options["bout_exb"].withDefault(false); - OPTION(options, phi_flags, 0); + phi_flags = options["phi_flags"].withDefault(0); // Toroidal filtering - OPTION(options, filter_z, false); // Filter a single n - OPTION(options, filter_z_mode, 1); + filter_z = options["filter_z"].withDefault(false); // Filter a single n + filter_z_mode = options["filter_z_mode"].withDefault(1); /************* SHIFTED RADIAL COORDINATES ************/ // Check type of parallel transform diff --git a/examples/conduction/conduction.cxx b/examples/conduction/conduction.cxx index 81513a82f3..2c8cf0858c 100644 --- a/examples/conduction/conduction.cxx +++ b/examples/conduction/conduction.cxx @@ -21,7 +21,7 @@ class Conduction : public PhysicsModel { auto options = Options::root()["conduction"]; // Read from BOUT.inp, setting default to 1.0 - OPTION(options, chi, 1.0); + chi = options["chi"].withDefault(1.0); // Tell BOUT++ to solve T SOLVE_FOR(T); diff --git a/examples/constraints/alfven-wave/alfven.cxx b/examples/constraints/alfven-wave/alfven.cxx index 33d3f64699..0838c3b046 100644 --- a/examples/constraints/alfven-wave/alfven.cxx +++ b/examples/constraints/alfven-wave/alfven.cxx @@ -35,12 +35,12 @@ class Alfven : public PhysicsModel { int init(bool restarting) { // Normalisation - Options *opt = Options::getRoot()->getSection("alfven"); - OPTION(opt, Tnorm, 100); // Reference temperature [eV] - OPTION(opt, Nnorm, 1e19); // Reference density [m^-3] - OPTION(opt, Bnorm, 1.0); // Reference magnetic field [T] - OPTION(opt, AA, 2.0); // Ion mass - + auto opt = Options::root()["alfven"]; + Tnorm = opt["Tnorm"].withDefault(100); // Reference temperature [eV] + Nnorm = opt["Nnorm"].withDefault(1e19); // Reference density [m^-3] + Bnorm = opt["Bnorm"].withDefault(1.0); // Reference magnetic field [T] + AA = opt["AA"].withDefault(2.0); // Ion mass + output.write("Normalisation Te=%e, Ne=%e, B=%e\n", Tnorm, Nnorm, Bnorm); SAVE_ONCE4(Tnorm, Nnorm, Bnorm, AA); // Save @@ -56,11 +56,11 @@ class Alfven : public PhysicsModel { output.write("\t Cs=%e, rho_s=%e, Omega_ci=%e\n", Cs0, rho_s0, Omega_ci); SAVE_ONCE3(Cs0, rho_s0, Omega_ci); - - OPTION(opt, mu_epar, -1e7); // Electron parallel viscosity [m^2/s] + + mu_epar = opt["mu_epar"].withDefault(-1e7); // Electron parallel viscosity [m^2/s] mu_epar /= rho_s0*rho_s0*Omega_ci * mi_me; // Normalise - OPTION(opt, resistivity, 1e-7); + resistivity = opt["resistivity"].withDefault(1e-7); // Load metric tensor from the mesh, passing length and B field normalisations LoadMetric(rho_s0, Bnorm); @@ -77,7 +77,7 @@ class Alfven : public PhysicsModel { setPrecon( (preconfunc) &Alfven::precon ); // Create an XZ solver - OPTION(opt, newXZsolver, false); + newXZsolver = opt["newXZsolver"].withDefault(false); if(newXZsolver) { // Test new LaplaceXZ solver newSolver = LaplaceXZ::create(mesh); diff --git a/examples/constraints/laplace-dae/laplace_dae.cxx b/examples/constraints/laplace-dae/laplace_dae.cxx index fbadf53c03..801b1ceda6 100644 --- a/examples/constraints/laplace-dae/laplace_dae.cxx +++ b/examples/constraints/laplace-dae/laplace_dae.cxx @@ -30,10 +30,10 @@ int physics_init(bool UNUSED(restarting)) { // Give the solver two RHS functions // Get options - Options *options = Options::getRoot(); - options = options->getSection("dae"); - OPTION(options, constraint, true); - OPTION(options, flags, 0); + auto globalOptions = Options::root(); + auto options = globalOptions["dae"]; + constraint = options["constraint"].withDefault(true); + flags = options["flags"].withDefault(0); // Create a solver for the Laplacian phiSolver = Laplacian::create(); diff --git a/examples/dalf3/dalf3.cxx b/examples/dalf3/dalf3.cxx index a18e7c65d7..0587bdd868 100644 --- a/examples/dalf3/dalf3.cxx +++ b/examples/dalf3/dalf3.cxx @@ -117,31 +117,31 @@ class DALF3 : public PhysicsModel { ////////////////////////////////////////////////////////////// // Options - - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("dalf3"); - - OPTION(options, phi_flags, 0); - OPTION(options, apar_flags, 0); - OPTION(options, split_n0, false); - OPTION(options, estatic, false); - OPTION(options, ZeroElMass, false); - OPTION(options, jpar_noderiv, true); - OPTION(options, curv_kappa, false); - OPTION(options, flat_resist, false); - OPTION(options, mul_resist, 1.0); - OPTION(options, viscosity, -1.0); - OPTION(options, hyper_viscosity, -1.0); - OPTION(options, viscosity_par, -1.0); - OPTION(options, smooth_separatrix, false); - - OPTION(options, filter_z, false); - - OPTION(options, parallel_lc, true); - OPTION(options, nonlinear, true); - + + auto globalOptions = Options::root(); + auto options = globalOptions["dalf3"]; + + phi_flags = options["phi_flags"].withDefault(0); + apar_flags = options["apar_flags"].withDefault(0); + split_n0 = options["split_n0"].withDefault(false); + estatic = options["estatic"].withDefault(false); + ZeroElMass = options["ZeroElMass"].withDefault(false); + jpar_noderiv = options["jpar_noderiv"].withDefault(true); + curv_kappa = options["curv_kappa"].withDefault(false); + flat_resist = options["flat_resist"].withDefault(false); + mul_resist = options["mul_resist"].withDefault(1.0); + viscosity = options["viscosity"].withDefault(-1.0); + hyper_viscosity = options["hyper_viscosity"].withDefault(-1.0); + viscosity_par = options["viscosity_par"].withDefault(-1.0); + smooth_separatrix = options["smooth_separatrix"].withDefault(false); + + filter_z = options["filter_z"].withDefault(false); + + parallel_lc = options["parallel_lc"].withDefault(true); + nonlinear = options["nonlinear"].withDefault(true); + int bracket_method; - OPTION(options, bracket_method, 0); + bracket_method = options["bracket_method"].withDefault(0); switch(bracket_method) { case 0: { bm = BRACKET_STD; diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index 7d3e6bcd40..f1d3c8dd66 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -346,34 +346,43 @@ int physics_init(bool restarting) { auto globalOptions = Options::root(); auto options = globalOptions["highbeta"]; - OPTION(options, constn0, true); - OPTION(options, n0_fake_prof, false); // use the hyperbolic profile of n0. If both n0_fake_prof and - // T0_fake_prof are false, use the profiles from grid file - OPTION(options, n0_height, 0.4); // the total height of profile of N0, in percentage of Ni_x - OPTION(options, n0_ave, 0.01); // the center or average of N0, in percentage of Ni_x - OPTION(options, n0_width, 0.1); // the width of the gradient of N0,in percentage of x - OPTION(options, n0_center, 0.633); // the grid number of the center of N0, in percentage of x - OPTION(options, n0_bottom_x, 0.81); // the start of flat region of N0 on SOL side, in percentage of x - OPTION(options, T0_fake_prof, false); - OPTION(options, Tconst, -1.0); // the amplitude of constant temperature, in percentage - - OPTION(options, density, 1.0e19); // Number density [m^-3] - - OPTION(options, evolve_jpar, false); // If true, evolve J raher than Psi - OPTION(options, phi_constraint, false); // Use solver constraint for phi + constn0 = options["constn0"].withDefault(true); + n0_fake_prof = options["n0_fake_prof"].withDefault( + false); // use the hyperbolic profile of n0. If both n0_fake_prof and + // T0_fake_prof are false, use the profiles from grid file + n0_height = options["n0_height"].withDefault( + 0.4); // the total height of profile of N0, in percentage of Ni_x + n0_ave = options["n0_ave"].withDefault( + 0.01); // the center or average of N0, in percentage of Ni_x + n0_width = options["n0_width"].withDefault( + 0.1); // the width of the gradient of N0,in percentage of x + n0_center = options["n0_center"].withDefault( + 0.633); // the grid number of the center of N0, in percentage of x + n0_bottom_x = options["n0_bottom_x"].withDefault( + 0.81); // the start of flat region of N0 on SOL side, in percentage of x + T0_fake_prof = options["T0_fake_prof"].withDefault(false); + Tconst = options["Tconst"].withDefault( + -1.0); // the amplitude of constant temperature, in percentage + + density = options["density"].withDefault(1.0e19); // Number density [m^-3] + + evolve_jpar = + options["evolve_jpar"].withDefault(false); // If true, evolve J raher than Psi + phi_constraint = + options["phi_constraint"].withDefault(false); // Use solver constraint for phi // Effects to include/exclude - OPTION(options, include_curvature, true); - OPTION(options, include_jpar0, true); - OPTION(options, evolve_pressure, true); - OPTION(options, nogradparj, false); + include_curvature = options["include_curvature"].withDefault(true); + include_jpar0 = options["include_jpar0"].withDefault(true); + evolve_pressure = options["evolve_pressure"].withDefault(true); + nogradparj = options["nogradparj"].withDefault(false); - OPTION(options, compress0, false); - OPTION(options, gyroviscous, false); - OPTION(options, nonlinear, false); + compress0 = options["compress0"].withDefault(false); + gyroviscous = options["gyroviscous"].withDefault(false); + nonlinear = options["nonlinear"].withDefault(false); // option for ExB Poisson Bracket - OPTION(options, bm_exb_flag, 0); + bm_exb_flag = options["bm_exb_flag"].withDefault(0); switch (bm_exb_flag) { case 0: { bm_exb = BRACKET_STD; @@ -401,7 +410,7 @@ int physics_init(bool restarting) { } // option for magnetic flutter Poisson Bracket - OPTION(options, bm_mag_flag, 0); + bm_mag_flag = options["bm_mag_flag"].withDefault(0); switch (bm_mag_flag) { case 0: { bm_mag = BRACKET_STD; @@ -428,119 +437,138 @@ int physics_init(bool restarting) { return 1; } - OPTION(options, eHall, false); // electron Hall or electron parallel pressue gradient effects? - OPTION(options, AA, 1.0); // ion mass in units of proton mass + eHall = options["eHall"].withDefault( + false); // electron Hall or electron parallel pressue gradient effects? + AA = options["AA"].withDefault(1.0); // ion mass in units of proton mass - OPTION(options, diamag, false); // Diamagnetic effects? - OPTION(options, diamag_grad_t, diamag); // Grad_par(Te) term in Psi equation - OPTION(options, diamag_phi0, diamag); // Include equilibrium phi0 - OPTION(options, dia_fact, 1.0); // Scale diamagnetic effects by this factor + diamag = options["diamag"].withDefault(false); // Diamagnetic effects? + diamag_grad_t = + options["diamag_grad_t"].withDefault(diamag); // Grad_par(Te) term in Psi equation + diamag_phi0 = options["diamag_phi0"].withDefault(diamag); // Include equilibrium phi0 + dia_fact = + options["dia_fact"].withDefault(1.0); // Scale diamagnetic effects by this factor - OPTION(options, withflow, false); // withflow or not - OPTION(options, K_H_term, true); // keep K-H term - OPTION(options, D_0, 0.0); // velocity magnitude - OPTION(options, D_s, 0.0); // flowshear - OPTION(options, x0, 0.0); // flow location - OPTION(options, sign, 1.0); // flow direction, -1 means negative electric field - OPTION(options, D_min, 3000.0); // a constant + withflow = options["withflow"].withDefault(false); // withflow or not + K_H_term = options["K_H_term"].withDefault(true); // keep K-H term + D_0 = options["D_0"].withDefault(0.0); // velocity magnitude + D_s = options["D_s"].withDefault(0.0); // flowshear + x0 = options["x0"].withDefault(0.0); // flow location + sign = options["sign"].withDefault( + 1.0); // flow direction, -1 means negative electric field + D_min = options["D_min"].withDefault(3000.0); // a constant - OPTION(options, experiment_Er, false); + experiment_Er = options["experiment_Er"].withDefault(false); - OPTION(options, noshear, false); + noshear = options["noshear"].withDefault(false); - OPTION(options, relax_j_vac, false); // Relax vacuum current to zero - OPTION(options, relax_j_tconst, 0.1); + relax_j_vac = options["relax_j_vac"].withDefault(false); // Relax vacuum current to zero + relax_j_tconst = options["relax_j_tconst"].withDefault(0.1); // Toroidal filtering - OPTION(options, filter_z, false); // Filter a single n - OPTION(options, filter_z_mode, 1); - OPTION(options, low_pass_z, -1); // Low-pass filter - OPTION(options, zonal_flow, -1); // zonal flow filter - OPTION(options, zonal_field, -1); // zonal field filter - OPTION(options, zonal_bkgd, -1); // zonal background P filter + filter_z = options["filter_z"].withDefault(false); // Filter a single n + filter_z_mode = options["filter_z_mode"].withDefault(1); + low_pass_z = options["low_pass_z"].withDefault(-1); // Low-pass filter + zonal_flow = options["zonal_flow"].withDefault(-1); // zonal flow filter + zonal_field = options["zonal_field"].withDefault(-1); // zonal field filter + zonal_bkgd = options["zonal_bkgd"].withDefault(-1); // zonal background P filter // Radial smoothing - OPTION(options, smooth_j_x, false); // Smooth Jpar in x + smooth_j_x = options["smooth_j_x"].withDefault(false); // Smooth Jpar in x // Jpar boundary region - OPTION(options, jpar_bndry_width, -1); + jpar_bndry_width = options["jpar_bndry_width"].withDefault(-1); - OPTION(options, sheath_boundaries, false); + sheath_boundaries = options["sheath_boundaries"].withDefault(false); // Parallel differencing - OPTION(options, parallel_lr_diff, false); + parallel_lr_diff = options["parallel_lr_diff"].withDefault(false); // RMP-related options - OPTION(options, include_rmp, false); // Read RMP data from grid + include_rmp = options["include_rmp"].withDefault(false); // Read RMP data from grid - OPTION(options, simple_rmp, false); // Include a simple RMP model - OPTION(options, rmp_factor, 1.0); - OPTION(options, rmp_ramp, -1.0); - OPTION(options, rmp_freq, -1.0); - OPTION(options, rmp_rotate, 0.0); + simple_rmp = options["simple_rmp"].withDefault(false); // Include a simple RMP model + rmp_factor = options["rmp_factor"].withDefault(1.0); + rmp_ramp = options["rmp_ramp"].withDefault(-1.0); + rmp_freq = options["rmp_freq"].withDefault(-1.0); + rmp_rotate = options["rmp_rotate"].withDefault(0.0); // Vacuum region control - OPTION(options, vacuum_pressure, 0.02); // Fraction of peak pressure - OPTION(options, vacuum_trans, 0.005); // Transition width in pressure + vacuum_pressure = + options["vacuum_pressure"].withDefault(0.02); // Fraction of peak pressure + vacuum_trans = + options["vacuum_trans"].withDefault(0.005); // Transition width in pressure // Resistivity and hyper-resistivity options - OPTION(options, vac_lund, 0.0); // Lundquist number in vacuum region - OPTION(options, core_lund, 0.0); // Lundquist number in core region - OPTION(options, hyperresist, -1.0); - OPTION(options, ehyperviscos, -1.0); - OPTION(options, spitzer_resist, false); // Use Spitzer resistivity - OPTION(options, Zeff, 2.0); // Z effective + vac_lund = options["vac_lund"].withDefault(0.0); // Lundquist number in vacuum region + core_lund = options["core_lund"].withDefault(0.0); // Lundquist number in core region + hyperresist = options["hyperresist"].withDefault(-1.0); + ehyperviscos = options["ehyperviscos"].withDefault(-1.0); + spitzer_resist = + options["spitzer_resist"].withDefault(false); // Use Spitzer resistivity + Zeff = options["Zeff"].withDefault(2.0); // Z effective // Inner boundary damping - OPTION(options, damp_width, 0); - OPTION(options, damp_t_const, 0.1); + damp_width = options["damp_width"].withDefault(0); + damp_t_const = options["damp_t_const"].withDefault(0.1); // Viscosity and hyper-viscosity - OPTION(options, viscos_par, -1.0); // Parallel viscosity - OPTION(options, viscos_perp, -1.0); // Perpendicular viscosity - OPTION(options, hyperviscos, -1.0); // Radial hyperviscosity + viscos_par = options["viscos_par"].withDefault(-1.0); // Parallel viscosity + viscos_perp = options["viscos_perp"].withDefault(-1.0); // Perpendicular viscosity + hyperviscos = options["hyperviscos"].withDefault(-1.0); // Radial hyperviscosity // parallel pressure diffusion - OPTION(options, diffusion_par, -1.0); // Parallel pressure diffusion - OPTION(options, diffusion_p4, -1.0); // xqx: parallel hyper-viscous diffusion for pressure - OPTION(options, diffusion_u4, -1.0); // xqx: parallel hyper-viscous diffusion for vorticity - OPTION(options, diffusion_a4, -1.0); // xqx: parallel hyper-viscous diffusion for vector potential + diffusion_par = + options["diffusion_par"].withDefault(-1.0); // Parallel pressure diffusion + diffusion_p4 = options["diffusion_p4"].withDefault( + -1.0); // xqx: parallel hyper-viscous diffusion for pressure + diffusion_u4 = options["diffusion_u4"].withDefault( + -1.0); // xqx: parallel hyper-viscous diffusion for vorticity + diffusion_a4 = options["diffusion_a4"].withDefault( + -1.0); // xqx: parallel hyper-viscous diffusion for vector potential // heating factor in pressure - OPTION(options, heating_P, -1.0); // heating power in pressure - OPTION(options, hp_width, 0.1); // the percentage of radial grid points for heating - // profile radial width in pressure - OPTION(options, hp_length, 0.04); // the percentage of radial grid points for heating - // profile radial domain in pressure + heating_P = options["heating_P"].withDefault(-1.0); // heating power in pressure + hp_width = options["hp_width"].withDefault( + 0.1); // the percentage of radial grid points for heating + // profile radial width in pressure + hp_length = options["hp_length"].withDefault( + 0.04); // the percentage of radial grid points for heating + // profile radial domain in pressure // sink factor in pressure - OPTION(options, sink_P, -1.0); // sink in pressure - OPTION(options, sp_width, 0.05); // the percentage of radial grid points for sink - // profile radial width in pressure - OPTION(options, sp_length, 0.04); // the percentage of radial grid points for sink - // profile radial domain in pressure + sink_P = options["sink_P"].withDefault(-1.0); // sink in pressure + sp_width = options["sp_width"].withDefault( + 0.05); // the percentage of radial grid points for sink + // profile radial width in pressure + sp_length = options["sp_length"].withDefault( + 0.04); // the percentage of radial grid points for sink + // profile radial domain in pressure // left edge sink factor in vorticity - OPTION(options, sink_Ul, -1.0); // left edge sink in vorticity - OPTION(options, su_widthl, 0.06); // the percentage of left edge radial grid points for - // sink profile radial width in vorticity - OPTION(options, su_lengthl, 0.15); // the percentage of left edge radial grid points - // for sink profile radial domain in vorticity + sink_Ul = options["sink_Ul"].withDefault(-1.0); // left edge sink in vorticity + su_widthl = options["su_widthl"].withDefault( + 0.06); // the percentage of left edge radial grid points for + // sink profile radial width in vorticity + su_lengthl = options["su_lengthl"].withDefault( + 0.15); // the percentage of left edge radial grid points + // for sink profile radial domain in vorticity // right edge sink factor in vorticity - OPTION(options, sink_Ur, -1.0); // right edge sink in vorticity - OPTION(options, su_widthr, 0.06); // the percentage of right edge radial grid points - // for sink profile radial width in vorticity - OPTION(options, su_lengthr, 0.15); // the percentage of right edge radial grid points - // for sink profile radial domain in vorticity + sink_Ur = options["sink_Ur"].withDefault(-1.0); // right edge sink in vorticity + su_widthr = options["su_widthr"].withDefault( + 0.06); // the percentage of right edge radial grid points + // for sink profile radial width in vorticity + su_lengthr = options["su_lengthr"].withDefault( + 0.15); // the percentage of right edge radial grid points + // for sink profile radial domain in vorticity // Compressional terms - OPTION(options, phi_curv, true); + phi_curv = options["phi_curv"].withDefault(true); g = options["gamma"].withDefault(5.0 / 3.0); // Field inversion flags - OPTION(options, phi_flags, 0); - OPTION(options, apar_flags, 0); + phi_flags = options["phi_flags"].withDefault(0); + apar_flags = options["apar_flags"].withDefault(0); x = (Psixy - Psiaxis) / (Psibndry - Psiaxis); @@ -570,11 +598,11 @@ int physics_init(bool restarting) { output_warn.write(" ***WARNING: need poloidal angle for simple RMP\n"); include_rmp = false; } else { - OPTION(options, rmp_n, 3); - OPTION(options, rmp_m, 9); - OPTION(options, rmp_polwid, -1.0); - OPTION(options, rmp_polpeak, 0.5); - OPTION(options, rmp_vac_mask, true); + rmp_n = options["rmp_n"].withDefault(3); + rmp_m = options["rmp_m"].withDefault(9); + rmp_polwid = options["rmp_polwid"].withDefault(-1.0); + rmp_polpeak = options["rmp_polpeak"].withDefault(0.5); + rmp_vac_mask = options["rmp_vac_mask"].withDefault(true); // Divide n by the size of the domain int zperiod = globalOptions["zperiod"].withDefault(1); if ((rmp_n % zperiod) != 0) diff --git a/examples/em-drift/2fluid.cxx b/examples/em-drift/2fluid.cxx index c3763ec521..961567672a 100644 --- a/examples/em-drift/2fluid.cxx +++ b/examples/em-drift/2fluid.cxx @@ -91,20 +91,20 @@ class EMdrift : public PhysicsModel { auto globalOptions = Options::root(); auto options = globalOptions["2fluid"]; - OPTION(options, AA, 2.0); - OPTION(options, ZZ, 1.0); - - OPTION(options, estatic, false); - OPTION(options, ZeroElMass, false); - OPTION(options, AparInEpar, true); + AA = options["AA"].withDefault(2.0); + ZZ = options["ZZ"].withDefault(1.0); + + estatic = options["estatic"].withDefault(false); + ZeroElMass = options["ZeroElMass"].withDefault(false); + AparInEpar = options["AparInEpar"].withDefault(true); - OPTION(options, zeff, 1.0); - OPTION(options, nu_perp, 0.0); - OPTION(options, ShearFactor, 1.0); - OPTION(options, nu_factor, 1.0); + zeff = options["zeff"].withDefault(1.0); + nu_perp = options["nu_perp"].withDefault(0.0); + ShearFactor = options["ShearFactor"].withDefault(1.0); + nu_factor = options["nu_factor"].withDefault(1.0); - OPTION(options, phi_flags, 0); - OPTION(options, apar_flags, 0); + phi_flags = options["phi_flags"].withDefault(0); + apar_flags = options["apar_flags"].withDefault(0); evolve_ajpar = globalOptions["Ajpar"]["evolve"].withDefault(true); diff --git a/examples/fci-wave/fci-wave.cxx b/examples/fci-wave/fci-wave.cxx index a922b92407..5380d73360 100644 --- a/examples/fci-wave/fci-wave.cxx +++ b/examples/fci-wave/fci-wave.cxx @@ -62,9 +62,9 @@ class FCIwave : public PhysicsModel { mesh->get(Bxyz, "B"); auto options = Options::root()["fciwave"]; - OPTION(options, div_integrate, true); - OPTION(options, log_density, false); - OPTION(options, background, false); + div_integrate = options["div_integrate"].withDefault(true); + log_density = options["log_density"].withDefault(false); + background = options["background"].withDefault(false); log_background = log(background); // Neumann boundaries simplifies parallel derivatives diff --git a/examples/finite-volume/fluid/fluid.cxx b/examples/finite-volume/fluid/fluid.cxx index bb09b5dd2a..6de380db4b 100644 --- a/examples/finite-volume/fluid/fluid.cxx +++ b/examples/finite-volume/fluid/fluid.cxx @@ -11,11 +11,11 @@ class Fluid : public PhysicsModel { protected: int init(bool restart) override { - Options *opt = Options::getRoot()->getSection("fluid"); + auto opt = Options::root()["fluid"]; // Adiabatic index (ratio of specific heats) - OPTION(opt, gamma, 5./3); - + gamma = opt["gamma"].withDefault(5. / 3); + SOLVE_FOR3(n, p, nv); return 0; diff --git a/examples/gravity_reduced/gravity_reduced.cxx b/examples/gravity_reduced/gravity_reduced.cxx index 53b0437d77..0370d88a11 100644 --- a/examples/gravity_reduced/gravity_reduced.cxx +++ b/examples/gravity_reduced/gravity_reduced.cxx @@ -90,31 +90,31 @@ class GravityReduced : public PhysicsModel { auto globalOptions = Options::root(); auto options = globalOptions["gravity"]; - - OPTION(options, nonlinear, false); - + + nonlinear = options["nonlinear"].withDefault(false); + if (nonlinear) { output <<"Solving WITH nonlinear terms\n"; } else { output <<"Solving WITHOUT nonlinear terms\n"; } - - OPTION(options, phi_flags, 0); + + phi_flags = options["phi_flags"].withDefault(0); phi.setBoundary("phi"); - OPTION(options, viscos_par, 0.); - OPTION(options, viscos_perp, 0.); - OPTION(options, mu_0, 1.); - OPTION(options, Gamma, 5./3.); - + viscos_par = options["viscos_par"].withDefault(0.); + viscos_perp = options["viscos_perp"].withDefault(0.); + mu_0 = options["mu_0"].withDefault(1.); + Gamma = options["Gamma"].withDefault(5. / 3.); + // load metric tensor components coord = mesh->getCoordinates(); BoutReal Lz; // Size of the Z box - - OPTION(options, Lz, 1.); - + + Lz = options["Lz"].withDefault(1.); + // Set the metric tensor components to get Lz coord->g33 = SQ(2.*PI/Lz); coord->g_33 = 1. / coord->g33; diff --git a/examples/gyro-gem/gem.cxx b/examples/gyro-gem/gem.cxx index 79de3dc07f..44ace1c516 100644 --- a/examples/gyro-gem/gem.cxx +++ b/examples/gyro-gem/gem.cxx @@ -161,29 +161,31 @@ class GEM : public PhysicsModel { auto globalOptions = Options::root(); auto options = globalOptions["gem"]; - - OPTION(options, adiabatic_electrons, false); - OPTION(options, small_rho_e, true); - OPTION(options, include_grad_par_B, true); - - OPTION(options, Landau, 1.0); - - OPTION(options, nu_perp, 0.01); // Artificial perpendicular dissipation - OPTION(options, nu_par, 3e-3); // Artificial parallel dissipation - - OPTION(options, phi_flags, 0); - OPTION(options, apar_flags, 0); - - OPTION(options, low_pass_z, -1); // Default is no filtering - OPTION(options, curv_logB, false); // Read in a separate logB variable - - OPTION(options, fix_profiles, false); // Subtract DC components - - OPTION(options, nonlinear, true); - OPTION(options, flat_temp, -1.0); - OPTION(options, flat_dens, -1.0); - + adiabatic_electrons = options["adiabatic_electrons"].withDefault(false); + small_rho_e = options["small_rho_e"].withDefault(true); + include_grad_par_B = options["include_grad_par_B"].withDefault(true); + + Landau = options["Landau"].withDefault(1.0); + + nu_perp = + options["nu_perp"].withDefault(0.01); // Artificial perpendicular dissipation + nu_par = options["nu_par"].withDefault(3e-3); // Artificial parallel dissipation + + phi_flags = options["phi_flags"].withDefault(0); + apar_flags = options["apar_flags"].withDefault(0); + + low_pass_z = options["low_pass_z"].withDefault(-1); // Default is no filtering + + curv_logB = + options["curv_logB"].withDefault(false); // Read in a separate logB variable + + fix_profiles = options["fix_profiles"].withDefault(false); // Subtract DC components + + nonlinear = options["nonlinear"].withDefault(true); + flat_temp = options["flat_temp"].withDefault(-1.0); + flat_dens = options["flat_dens"].withDefault(-1.0); + ////////////////////////////////// // Read profiles @@ -229,21 +231,21 @@ class GEM : public PhysicsModel { Lbar = 1.0; } } - OPTION(options, Lbar, Lbar); // Override in options file + Lbar = options["Lbar"].withDefault(Lbar); // Override in options file SAVE_ONCE(Lbar); // Save in output file BoutReal AA; // Ion atomic mass BoutReal ZZ; // Ion charge - OPTION(options, AA, 2.0); // Deuterium by default - OPTION(options, ZZ, 1.0); - + AA = options["AA"].withDefault(2.0); // Deuterium by default + ZZ = options["ZZ"].withDefault(1.0); + Tenorm = max(Te0,true); SAVE_ONCE(Tenorm); // Maximum value over the grid Ninorm = max(Ni0, true); SAVE_ONCE(Ninorm); Cs = sqrt(qe*Tenorm / (AA*Mp)); SAVE_ONCE(Cs); // Sound speed in m/s - Tbar = Lbar / Cs; - OPTION(options, Tbar, Tbar); // Override in options file + Tbar = Lbar / Cs; + Tbar = options["Tbar"].withDefault(Tbar); // Override in options file SAVE_ONCE(Tbar); // Timescale in seconds if (mesh->get(Bbar, "Bbar")) { @@ -251,7 +253,7 @@ class GEM : public PhysicsModel { Bbar = max(Bxy, true); } } - OPTION(options, Bbar, Bbar); // Override in options file + Bbar = options["Bbar"].withDefault(Bbar); // Override in options file SAVE_ONCE(Bbar); beta_e = 4.e-7*PI * max(p_e,true) / (Bbar*Bbar); SAVE_ONCE(beta_e); @@ -273,28 +275,28 @@ class GEM : public PhysicsModel { //////////////////////////////////////////////////// // Terms in equations - - OPTION(options, jpar_bndry_width, -1); - + + jpar_bndry_width = options["jpar_bndry_width"].withDefault(-1); + OPTION4(options, ne_ddt, ne_te0, ne_ue, ne_curv, true); // Linear OPTION2(options, ne_ne1, ne_te1, nonlinear); // Nonlinear OPTION6(options, apue_ddt, apue_phi1, apue_pet, apue_curv, apue_gradB, apue_Rei, true); OPTION4(options, apue_ue1_phi1, apue_qe1_phi1, apue_apar1_phi1, apue_apar1_pe1, nonlinear); - - OPTION(options, tepar_ddt, true); - OPTION(options, teperp_ddt, true); - OPTION(options, qepar_ddt, true); - OPTION(options, qeperp_ddt, true); - + + tepar_ddt = options["tepar_ddt"].withDefault(true); + teperp_ddt = options["teperp_ddt"].withDefault(true); + qepar_ddt = options["qepar_ddt"].withDefault(true); + qeperp_ddt = options["qeperp_ddt"].withDefault(true); + OPTION4(options, ni_ddt, ni_ti0, ni_ui, ni_curv, true); // Linear OPTION2(options, ni_ni1, ni_ti1, nonlinear); // Nonlinear OPTION6(options, apui_ddt, apui_phi1, apui_pit, apui_curv, apui_gradB, apui_Rei, true); OPTION4(options, apui_ui1_phi1, apui_qi1_phi1, apui_apar1_phi1, apui_apar1_pi1, nonlinear); - OPTION(options, tipar_ddt, true); - OPTION(options, tiperp_ddt, true); - OPTION(options, qipar_ddt, true); - OPTION(options, qiperp_ddt, true); - + tipar_ddt = options["tipar_ddt"].withDefault(true); + tiperp_ddt = options["tiperp_ddt"].withDefault(true); + qipar_ddt = options["qipar_ddt"].withDefault(true); + qiperp_ddt = options["qiperp_ddt"].withDefault(true); + //////////////////////////////////////////////////// // Collisional parameters @@ -462,7 +464,7 @@ class GEM : public PhysicsModel { } bool output_ddt; - OPTION(options, output_ddt, false); + output_ddt = options["output_ddt"].withDefault(false); if (output_ddt) { // Output the time derivatives diff --git a/examples/hasegawa-wakatani/hw.cxx b/examples/hasegawa-wakatani/hw.cxx index e55987fa99..2940084e31 100644 --- a/examples/hasegawa-wakatani/hw.cxx +++ b/examples/hasegawa-wakatani/hw.cxx @@ -34,14 +34,14 @@ class HW : public PhysicsModel { protected: int init(bool restart) { - - Options *options = Options::getRoot()->getSection("hw"); - OPTION(options, alpha, 1.0); - OPTION(options, kappa, 0.1); - OPTION(options, Dvort, 1e-2); - OPTION(options, Dn, 1e-2); - - OPTION(options, modified, false); + + auto options = Options::root()["hw"]; + alpha = options["alpha"].withDefault(1.0); + kappa = options["kappa"].withDefault(0.1); + Dvort = options["Dvort"].withDefault(1e-2); + Dn = options["Dn"].withDefault(1e-2); + + modified = options["modified"].withDefault(false); SOLVE_FOR2(n, vort); SAVE_REPEAT(phi); @@ -56,7 +56,7 @@ class HW : public PhysicsModel { // Choose method to use for Poisson bracket advection terms int bracket; - OPTION(options, bracket, 0); + bracket = options["bracket"].withDefault(0); switch(bracket) { case 0: { bm = BRACKET_STD; diff --git a/examples/jorek-compare/jorek_compare.cxx b/examples/jorek-compare/jorek_compare.cxx index 6c1ee0bc34..331902e118 100644 --- a/examples/jorek-compare/jorek_compare.cxx +++ b/examples/jorek-compare/jorek_compare.cxx @@ -162,7 +162,7 @@ class Jorek : public PhysicsModel { } else mesh->get(viscos_par, "viscos_par"); - OPTION(options, viscos_coll, -1.0); + viscos_coll = options["viscos_coll"].withDefault(-1.0); // Load curvature term b0xcv.covariant = false; // Read contravariant components @@ -187,26 +187,26 @@ class Jorek : public PhysicsModel { mesh->get(hthe, "hthe"); // m mesh->get(I, "sinty"); // m^-2 T^-1 - OPTION(options, nonlinear, false); - OPTION(options, full_bfield, false); - OPTION(options, flux_method, false); + nonlinear = options["nonlinear"].withDefault(false); + full_bfield = options["full_bfield"].withDefault(false); + flux_method = options["flux_method"].withDefault(false); - OPTION(options, jpar_bndry_width, -1); + jpar_bndry_width = options["jpar_bndry_width"].withDefault(-1); - OPTION(options, hyperresist, -1); + hyperresist = options["hyperresist"].withDefault(-1); - OPTION(options, electron_density, false); - OPTION(options, vorticity_momentum, false); - OPTION(options, include_profiles, false); - OPTION(options, parallel_lc, true); + electron_density = options["electron_density"].withDefault(false); + vorticity_momentum = options["vorticity_momentum"].withDefault(false); + include_profiles = options["include_profiles"].withDefault(false); + parallel_lc = options["parallel_lc"].withDefault(true); - OPTION(options, phi_flags, 0); + phi_flags = options["phi_flags"].withDefault(0); - OPTION(options, low_pass_z, -1); // Default is no filtering + low_pass_z = options["low_pass_z"].withDefault(-1); // Default is no filtering - OPTION(options, Wei, 1.0); + Wei = options["Wei"].withDefault(1.0); - OPTION(options, ohmic_heating, true); + ohmic_heating = options["ohmic_heating"].withDefault(true); switch (options["bracket_method"].withDefault(0)) { case 0: { diff --git a/examples/lapd-drift/lapd_drift.cxx b/examples/lapd-drift/lapd_drift.cxx index eb90490146..96b3cf4125 100644 --- a/examples/lapd-drift/lapd_drift.cxx +++ b/examples/lapd-drift/lapd_drift.cxx @@ -166,86 +166,86 @@ class LAPDdrift : public PhysicsModel { time_step = globalOptions["TIMESTEP"].withDefault(1.0); auto options = globalOptions["2fluid"]; - OPTION(options, AA, 4.0); // <=> AA = options["AA"].withDefault(1.0); - OPTION(options, ZZ, 1.0); - - OPTION(options, estatic, false); - OPTION(options, ZeroElMass, false); - OPTION(options, zeff, 1.0); - OPTION(options, nu_perp, 0.0); - OPTION(options, ShearFactor, 1.0); - OPTION(options, nuIonNeutral, -1.); - OPTION(options, arakawa, false); - OPTION(options, bout_exb, false); - - OPTION(options, niprofile, false); - OPTION(options, evolve_source_ni, false); - OPTION(options, evolve_source_te, false); - OPTION(options, source_response, 1.0); - OPTION(options, source_converge, -1); - - OPTION(options, ni_perpdiff, 0.0); - OPTION(options, rho_perpdiff, 0.0); - OPTION(options, te_perpdiff, 0.0); - - OPTION(options, input_source, false); - OPTION(options, remove_tor_av_ni, false); - OPTION(options, remove_tor_av_te, false); - - OPTION(options, phi_flags, 0); - OPTION(options, apar_flags, 0); - - OPTION(options, nonlinear, true); - + AA = options["AA"].withDefault(4.0); // <=> AA = options["AA"].withDefault(1.0); + ZZ = options["ZZ"].withDefault(1.0); + + estatic = options["estatic"].withDefault(false); + ZeroElMass = options["ZeroElMass"].withDefault(false); + zeff = options["zeff"].withDefault(1.0); + nu_perp = options["nu_perp"].withDefault(0.0); + ShearFactor = options["ShearFactor"].withDefault(1.0); + nuIonNeutral = options["nuIonNeutral"].withDefault(-1.); + arakawa = options["arakawa"].withDefault(false); + bout_exb = options["bout_exb"].withDefault(false); + + niprofile = options["niprofile"].withDefault(false); + evolve_source_ni = options["evolve_source_ni"].withDefault(false); + evolve_source_te = options["evolve_source_te"].withDefault(false); + source_response = options["source_response"].withDefault(1.0); + source_converge = options["source_converge"].withDefault(-1); + + ni_perpdiff = options["ni_perpdiff"].withDefault(0.0); + rho_perpdiff = options["rho_perpdiff"].withDefault(0.0); + te_perpdiff = options["te_perpdiff"].withDefault(0.0); + + input_source = options["input_source"].withDefault(false); + remove_tor_av_ni = options["remove_tor_av_ni"].withDefault(false); + remove_tor_av_te = options["remove_tor_av_te"].withDefault(false); + + phi_flags = options["phi_flags"].withDefault(0); + apar_flags = options["apar_flags"].withDefault(0); + + nonlinear = options["nonlinear"].withDefault(true); + // Toroidal filtering - OPTION(options, filter_z, false); // Filter a single n - OPTION(options, filter_z_mode, 1); - + filter_z = options["filter_z"].withDefault(false); // Filter a single n + filter_z_mode = options["filter_z_mode"].withDefault(1); + // Set default values for terms in each equation // Allows default to be overridden in BOUT.inp file auto option_rho = globalOptions["rho"]; - OPTION(option_rho, evolve_rho, true); - OPTION(option_rho, rho_jpar1, false); - OPTION(option_rho, rho_nuin_rho1, false); - OPTION(option_rho, rho_rho1, false); - OPTION(option_rho, rho_rho0_phi1, false); - OPTION(option_rho, rho_rho1_phi0, false); - OPTION(option_rho, rho_ve2lin, false); - OPTION(option_rho, rho_rho1_phi1, false); - OPTION(option_rho, rho_ve2t, false); - OPTION(option_rho, rho_diff, false); - + evolve_rho = option_rho["evolve_rho"].withDefault(true); + rho_jpar1 = option_rho["rho_jpar1"].withDefault(false); + rho_nuin_rho1 = option_rho["rho_nuin_rho1"].withDefault(false); + rho_rho1 = option_rho["rho_rho1"].withDefault(false); + rho_rho0_phi1 = option_rho["rho_rho0_phi1"].withDefault(false); + rho_rho1_phi0 = option_rho["rho_rho1_phi0"].withDefault(false); + rho_ve2lin = option_rho["rho_ve2lin"].withDefault(false); + rho_rho1_phi1 = option_rho["rho_rho1_phi1"].withDefault(false); + rho_ve2t = option_rho["rho_ve2t"].withDefault(false); + rho_diff = option_rho["rho_diff"].withDefault(false); + auto option_ni = globalOptions["ni"]; - OPTION(option_ni, evolve_ni, true); - OPTION(option_ni, ni_jpar1, false); - OPTION(option_ni, ni_ni0_phi1, false); - OPTION(option_ni, ni_ni1_phi0, false); - OPTION(option_ni, ni_ni1_phi1, false); - OPTION(option_ni, ni_src_ni0, false); - OPTION(option_ni, ni_diff, false); - + evolve_ni = option_ni["evolve_ni"].withDefault(true); + ni_jpar1 = option_ni["ni_jpar1"].withDefault(false); + ni_ni0_phi1 = option_ni["ni_ni0_phi1"].withDefault(false); + ni_ni1_phi0 = option_ni["ni_ni1_phi0"].withDefault(false); + ni_ni1_phi1 = option_ni["ni_ni1_phi1"].withDefault(false); + ni_src_ni0 = option_ni["ni_src_ni0"].withDefault(false); + ni_diff = option_ni["ni_diff"].withDefault(false); + auto option_ajpar = globalOptions["ajpar"]; - OPTION(option_ajpar, evolve_ajpar, true); - OPTION(option_ajpar, ajpar_phi1, false); - OPTION(option_ajpar, ajpar_jpar1, false); - OPTION(option_ajpar, ajpar_te_ni, false); - OPTION(option_ajpar, ajpar_te, false); - OPTION(option_ajpar, ajpar_ajpar1_phi0,false); - OPTION(option_ajpar, ajpar_ajpar1_phi1,false); - OPTION(option_ajpar, ajpar_ve1_ve1, false); - + evolve_ajpar = option_ajpar["evolve_ajpar"].withDefault(true); + ajpar_phi1 = option_ajpar["ajpar_phi1"].withDefault(false); + ajpar_jpar1 = option_ajpar["ajpar_jpar1"].withDefault(false); + ajpar_te_ni = option_ajpar["ajpar_te_ni"].withDefault(false); + ajpar_te = option_ajpar["ajpar_te"].withDefault(false); + ajpar_ajpar1_phi0 = option_ajpar["ajpar_ajpar1_phi0"].withDefault(false); + ajpar_ajpar1_phi1 = option_ajpar["ajpar_ajpar1_phi1"].withDefault(false); + ajpar_ve1_ve1 = option_ajpar["ajpar_ve1_ve1"].withDefault(false); + auto option_te = globalOptions["te"]; - OPTION(option_te, evolve_te, true); - OPTION(option_te, te_te1_phi0, false); - OPTION(option_te, te_te0_phi1, false); - OPTION(option_te, te_te1_phi1, false); - OPTION(option_te, te_ajpar_te, false); - OPTION(option_te, te_te_ajpar, false); - OPTION(option_te, te_nu_te1, false); - OPTION(option_te, te_nu_tet, false); - OPTION(option_te, te_jpar, false); - OPTION(option_te, te_diff, false); - + evolve_te = option_te["evolve_te"].withDefault(true); + te_te1_phi0 = option_te["te_te1_phi0"].withDefault(false); + te_te0_phi1 = option_te["te_te0_phi1"].withDefault(false); + te_te1_phi1 = option_te["te_te1_phi1"].withDefault(false); + te_ajpar_te = option_te["te_ajpar_te"].withDefault(false); + te_te_ajpar = option_te["te_te_ajpar"].withDefault(false); + te_nu_te1 = option_te["te_nu_te1"].withDefault(false); + te_nu_tet = option_te["te_nu_tet"].withDefault(false); + te_jpar = option_te["te_jpar"].withDefault(false); + te_diff = option_te["te_diff"].withDefault(false); + if (ZeroElMass) { evolve_ajpar = false; // Don't need ajpar - calculated from ohm's law } diff --git a/examples/laplacexy/alfven-wave/alfven.cxx b/examples/laplacexy/alfven-wave/alfven.cxx index 8bac88f844..86a690a157 100644 --- a/examples/laplacexy/alfven-wave/alfven.cxx +++ b/examples/laplacexy/alfven-wave/alfven.cxx @@ -39,11 +39,11 @@ class Alfven : public PhysicsModel { int init(bool restarting) { // Normalisation - Options *opt = Options::getRoot()->getSection("alfven"); - OPTION(opt, Tnorm, 100); // Reference temperature [eV] - OPTION(opt, Nnorm, 1e19); // Reference density [m^-3] - OPTION(opt, Bnorm, 1.0); // Reference magnetic field [T] - OPTION(opt, AA, 2.0); // Ion mass + auto opt = Options::root()["alfven"]; + Tnorm = opt["Tnorm"].withDefault(100); // Reference temperature [eV] + Nnorm = opt["Nnorm"].withDefault(1e19); // Reference density [m^-3] + Bnorm = opt["Bnorm"].withDefault(1.0); // Reference magnetic field [T] + AA = opt["AA"].withDefault(2.0); // Ion mass output.write("Normalisation Te=%e, Ne=%e, B=%e\n", Tnorm, Nnorm, Bnorm); SAVE_ONCE4(Tnorm, Nnorm, Bnorm, AA); // Save @@ -61,10 +61,10 @@ class Alfven : public PhysicsModel { output.write("\t Cs=%e, rho_s=%e, Omega_ci=%e\n", Cs0, rho_s0, Omega_ci); SAVE_ONCE3(Cs0, rho_s0, Omega_ci); - OPTION(opt, mu_epar, -1e7); // Electron parallel viscosity [m^2/s] + mu_epar = opt["mu_epar"].withDefault(-1e7); // Electron parallel viscosity [m^2/s] mu_epar /= rho_s0 * rho_s0 * Omega_ci * mi_me; // Normalise - OPTION(opt, resistivity, 1e-7); + resistivity = opt["resistivity"].withDefault(1e-7); // Load metric tensor from the mesh, passing length and B field normalisations LoadMetric(rho_s0, Bnorm); @@ -72,8 +72,9 @@ class Alfven : public PhysicsModel { // Specify evolving variables SOLVE_FOR2(Vort, Apar); - OPTION(opt, laplace_perp, true); // Use Laplace_perp rather than Delp2 - OPTION(opt, split_n0, true); // Split into n=0 and n~=0 + laplace_perp = + opt["laplace_perp"].withDefault(true); // Use Laplace_perp rather than Delp2 + split_n0 = opt["split_n0"].withDefault(true); // Split into n=0 and n~=0 if (split_n0) { // Create an XY solver for n=0 component @@ -82,7 +83,7 @@ class Alfven : public PhysicsModel { } // Create an XZ solver - OPTION(opt, newXZsolver, false); + newXZsolver = opt["newXZsolver"].withDefault(false); if (newXZsolver) { // Test new LaplaceXZ solver newSolver = LaplaceXZ::create(mesh); diff --git a/examples/laplacexy/laplace_perp/test.cxx b/examples/laplacexy/laplace_perp/test.cxx index 0ed64932b6..d81936a599 100644 --- a/examples/laplacexy/laplace_perp/test.cxx +++ b/examples/laplacexy/laplace_perp/test.cxx @@ -9,7 +9,7 @@ int main(int argc, char** argv) { /////////////////////////////////////// bool calc_metric; - OPTION(Options::getRoot(), calc_metric, false); + calc_metric = Options::root()["calc_metric"].withDefault(false); if(calc_metric) { // Read metric tensor Field2D Rxy, Btxy, Bpxy, B0, hthe, I; diff --git a/examples/orszag-tang/mhd.cxx b/examples/orszag-tang/mhd.cxx index eee6c16205..330926b551 100644 --- a/examples/orszag-tang/mhd.cxx +++ b/examples/orszag-tang/mhd.cxx @@ -26,9 +26,9 @@ class MHD : public PhysicsModel { // read options auto globalOptions = Options::root(); auto options = globalOptions["mhd"]; - OPTION(options, g, 5.0 / 3.0); - OPTION(options, include_viscos, false); - OPTION(options, viscos, 0.1); + g = options["g"].withDefault(5.0 / 3.0); + include_viscos = options["include_viscos"].withDefault(false); + viscos = options["viscos"].withDefault(0.1); // Read 2D initial profiles GRID_LOAD(rho0); @@ -65,7 +65,7 @@ class MHD : public PhysicsModel { // Added this for modifying the Orszag-Tang vortex problem BoutReal v_fact; - OPTION(options, v_fact, 1.0); + v_fact = options["v_fact"].withDefault(1.0); v *= v_fact; } diff --git a/examples/performance/bracket/bracket.cxx b/examples/performance/bracket/bracket.cxx index 5d2ff49b6e..d468da331e 100644 --- a/examples/performance/bracket/bracket.cxx +++ b/examples/performance/bracket/bracket.cxx @@ -39,15 +39,15 @@ int main(int argc, char **argv) { std::vector times; // Get options root - Options *globalOptions = Options::getRoot(); - Options *modelOpts = globalOptions->getSection("performance"); + auto globalOptions = Options::root(); + auto modelOpts = globalOptions["performance"]; int NUM_LOOPS; - OPTION(modelOpts, NUM_LOOPS, 100); + NUM_LOOPS = modelOpts["NUM_LOOPS"].withDefault(100); bool profileMode, includeHeader, do2D3D, do3D3D; - OPTION(modelOpts, profileMode, false); - OPTION(modelOpts, includeHeader, false); - OPTION(modelOpts, do2D3D, false); - OPTION(modelOpts, do3D3D, false); + profileMode = modelOpts["profileMode"].withDefault(false); + includeHeader = modelOpts["includeHeader"].withDefault(false); + do2D3D = modelOpts["do2D3D"].withDefault(false); + do3D3D = modelOpts["do3D3D"].withDefault(false); ConditionalOutput time_output(Output::getInstance()); time_output.enable(true); diff --git a/examples/performance/ddx/ddx.cxx b/examples/performance/ddx/ddx.cxx index a895ada0bd..9102994533 100644 --- a/examples/performance/ddx/ddx.cxx +++ b/examples/performance/ddx/ddx.cxx @@ -44,13 +44,13 @@ int main(int argc, char **argv) { std::vector times; //Get options root - Options *globalOptions = Options::getRoot(); - Options *modelOpts = globalOptions->getSection("performanceIterator"); + auto globalOptions = Options::root(); + auto modelOpts = globalOptions["performanceIterator"]; int NUM_LOOPS; - OPTION(modelOpts, NUM_LOOPS, 100); + NUM_LOOPS = modelOpts["NUM_LOOPS"].withDefault(100); bool profileMode, includeHeader; - OPTION(modelOpts, profileMode, false); - OPTION(modelOpts, includeHeader, false); + profileMode = modelOpts["profileMode"].withDefault(false); + includeHeader = modelOpts["includeHeader"].withDefault(false); ConditionalOutput time_output{Output::getInstance()}; time_output.enable(true); diff --git a/examples/performance/ddy/ddy.cxx b/examples/performance/ddy/ddy.cxx index 7ca7c08e53..f3d23c5bc1 100644 --- a/examples/performance/ddy/ddy.cxx +++ b/examples/performance/ddy/ddy.cxx @@ -44,13 +44,13 @@ int main(int argc, char **argv) { std::vector times; //Get options root - Options *globalOptions = Options::getRoot(); - Options *modelOpts = globalOptions->getSection("performanceIterator"); + auto globalOptions = Options::root(); + auto modelOpts = globalOptions["performanceIterator"]; int NUM_LOOPS; - OPTION(modelOpts, NUM_LOOPS, 100); + NUM_LOOPS = modelOpts["NUM_LOOPS"].withDefault(100); bool profileMode, includeHeader; - OPTION(modelOpts, profileMode, false); - OPTION(modelOpts, includeHeader, false); + profileMode = modelOpts["profileMode"].withDefault(false); + includeHeader = modelOpts["includeHeader"].withDefault(false); ConditionalOutput time_output{Output::getInstance()}; time_output.enable(true); diff --git a/examples/performance/ddz/ddz.cxx b/examples/performance/ddz/ddz.cxx index be532a4849..8bbee408f4 100644 --- a/examples/performance/ddz/ddz.cxx +++ b/examples/performance/ddz/ddz.cxx @@ -44,13 +44,13 @@ int main(int argc, char **argv) { std::vector times; //Get options root - Options *globalOptions = Options::getRoot(); - Options *modelOpts = globalOptions->getSection("performanceIterator"); + auto globalOptions = Options::root(); + auto modelOpts = globalOptions["performanceIterator"]; int NUM_LOOPS; - OPTION(modelOpts, NUM_LOOPS, 100); + NUM_LOOPS = modelOpts["NUM_LOOPS"].withDefault(100); bool profileMode, includeHeader; - OPTION(modelOpts, profileMode, false); - OPTION(modelOpts, includeHeader, false); + profileMode = modelOpts["profileMode"].withDefault(false); + includeHeader = modelOpts["includeHeader"].withDefault(false); ConditionalOutput time_output{Output::getInstance()}; time_output.enable(true); diff --git a/examples/performance/iterator-offsets/iterator-offsets.cxx b/examples/performance/iterator-offsets/iterator-offsets.cxx index a64eccf580..5ebba9da5e 100644 --- a/examples/performance/iterator-offsets/iterator-offsets.cxx +++ b/examples/performance/iterator-offsets/iterator-offsets.cxx @@ -43,13 +43,13 @@ int main(int argc, char **argv) { std::vector times; //Get options root - Options *globalOptions = Options::getRoot(); - Options *modelOpts = globalOptions->getSection("performanceIterator"); + auto globalOptions = Options::root(); + auto modelOpts = globalOptions["performanceIterator"]; int NUM_LOOPS; - OPTION(modelOpts, NUM_LOOPS, 100); + NUM_LOOPS = modelOpts["NUM_LOOPS"].withDefault(100); bool profileMode, includeHeader; - OPTION(modelOpts, profileMode, false); - OPTION(modelOpts, includeHeader, false); + profileMode = modelOpts["profileMode"].withDefault(false); + includeHeader = modelOpts["includeHeader"].withDefault(false); ConditionalOutput time_output{Output::getInstance()}; time_output.enable(true); diff --git a/examples/performance/iterator/iterator.cxx b/examples/performance/iterator/iterator.cxx index 7c1033ca21..7ac20792fb 100644 --- a/examples/performance/iterator/iterator.cxx +++ b/examples/performance/iterator/iterator.cxx @@ -35,13 +35,13 @@ int main(int argc, char **argv) { std::vector times; //Get options root - Options *globalOptions = Options::getRoot(); - Options *modelOpts = globalOptions->getSection("performanceIterator"); + auto globalOptions = Options::root(); + auto modelOpts = globalOptions["performanceIterator"]; int NUM_LOOPS; - OPTION(modelOpts, NUM_LOOPS, 100); + NUM_LOOPS = modelOpts["NUM_LOOPS"].withDefault(100); bool profileMode, includeHeader; - OPTION(modelOpts, profileMode, false); - OPTION(modelOpts, includeHeader, false); + profileMode = modelOpts["profileMode"].withDefault(false); + includeHeader = modelOpts["includeHeader"].withDefault(false); ConditionalOutput time_output(Output::getInstance()); time_output.enable(true); diff --git a/examples/performance/tuning_regionblocksize/tuning_regionblocksize.cxx b/examples/performance/tuning_regionblocksize/tuning_regionblocksize.cxx index ca3f834ba0..29b3238606 100644 --- a/examples/performance/tuning_regionblocksize/tuning_regionblocksize.cxx +++ b/examples/performance/tuning_regionblocksize/tuning_regionblocksize.cxx @@ -37,11 +37,11 @@ int main(int argc, char **argv) { std::vector times; // Get options root - Options *globalOptions = Options::getRoot(); - Options *modelOpts = globalOptions->getSection("tuningRegionBlockSize"); + auto globalOptions = Options::root(); + auto modelOpts = globalOptions["tuningRegionBlockSize"]; int NUM_LOOPS, numSteps; - OPTION(modelOpts, NUM_LOOPS, 100); - OPTION(modelOpts, numSteps, 16); + NUM_LOOPS = modelOpts["NUM_LOOPS"].withDefault(100); + numSteps = modelOpts["numSteps"].withDefault(16); ConditionalOutput time_output(Output::getInstance()); time_output.enable(true); diff --git a/examples/reconnect-2field/2field.cxx b/examples/reconnect-2field/2field.cxx index 29e1ca6fa9..ae68c08065 100644 --- a/examples/reconnect-2field/2field.cxx +++ b/examples/reconnect-2field/2field.cxx @@ -74,22 +74,22 @@ class TwoField : public PhysicsModel { mesh->get(coord->Bxy, "Bxy"); // Read some parameters - Options *globalOptions = Options::getRoot(); - Options *options = globalOptions->getSection("2field"); + auto globalOptions = Options::root(); + auto options = globalOptions["2field"]; // normalisation values - OPTION(options, nonlinear, false); - OPTION(options, parallel_lc, true); - OPTION(options, include_jpar0, true); - OPTION(options, jpar_bndry, 0); + nonlinear = options["nonlinear"].withDefault(false); + parallel_lc = options["parallel_lc"].withDefault(true); + include_jpar0 = options["include_jpar0"].withDefault(true); + jpar_bndry = options["jpar_bndry"].withDefault(0); - OPTION(options, eta, 1e-3); // Normalised resistivity - OPTION(options, mu, 1.e-3); // Normalised vorticity + eta = options["eta"].withDefault(1e-3); // Normalised resistivity + mu = options["mu"].withDefault(1.e-3); // Normalised vorticity - OPTION(options, phi_flags, 0); + phi_flags = options["phi_flags"].withDefault(0); int bracket_method; - OPTION(options, bracket_method, 0); + bracket_method = options["bracket_method"].withDefault(0); switch (bracket_method) { case 0: { bm = BRACKET_STD; diff --git a/examples/shear-alfven-wave/2fluid.cxx b/examples/shear-alfven-wave/2fluid.cxx index ae36c9f794..6c4df2d83d 100644 --- a/examples/shear-alfven-wave/2fluid.cxx +++ b/examples/shear-alfven-wave/2fluid.cxx @@ -100,16 +100,16 @@ class ShearAlfven : public PhysicsModel { // Read some parameters auto globalOptions = Options::root(); auto options = globalOptions["2fluid"]; - OPTION(options, AA, 2.0); - OPTION(options, ZZ, 1.0); + AA = options["AA"].withDefault(2.0); + ZZ = options["ZZ"].withDefault(1.0); - OPTION(options, ZeroElMass, false); - OPTION(options, zeff, 1.0); - OPTION(options, nu_perp, 0.0); - OPTION(options, ShearFactor, 1.0); + ZeroElMass = options["ZeroElMass"].withDefault(false); + zeff = options["zeff"].withDefault(1.0); + nu_perp = options["nu_perp"].withDefault(0.0); + ShearFactor = options["ShearFactor"].withDefault(1.0); - OPTION(options, phi_flags, 0); - OPTION(options, apar_flags, 0); + phi_flags = options["phi_flags"].withDefault(0); + apar_flags = options["apar_flags"].withDefault(0); /************* SHIFTED RADIAL COORDINATES ************/ diff --git a/examples/subsampling/monitor.cxx b/examples/subsampling/monitor.cxx index d077b79b2f..0de09dd654 100644 --- a/examples/subsampling/monitor.cxx +++ b/examples/subsampling/monitor.cxx @@ -11,24 +11,26 @@ // correct folder, and should throw if it possible to detect the error. class SimpleDatafile: public Datafile{ public: - SimpleDatafile(std::string section):SimpleDatafile(Options::getRoot()->getSection(section.c_str()) - ,section){}; - SimpleDatafile(Options* ops,std::string section="Default"):Datafile(ops){ + SimpleDatafile(std::string section) + : SimpleDatafile(Options::root()[section], section){}; + SimpleDatafile(Options& ops, std::string section = "Default") : Datafile(&ops) { // Open a file for the output - std::string datadir; - if (ops->isSet("path")){ - ops->get("path",datadir,"data");// default never needed + std::string datadir = "data"; + if (ops.isSet("path")) { + datadir = ops["path"].withDefault(datadir); // default never needed } else { - OPTION(Options::getRoot(),datadir,"data"); // I need to know data is default :( + datadir = Options::root()["datadir"].withDefault( + datadir); // I need to know data is default :( } std::string file; file = section+".dmp"; - OPTION(ops,file,file); + file = ops["file"].withDefault(file); bool append; - if (ops->isSet("append")){ - OPTION(ops,append,false); + if (ops.isSet("append")) { + append = ops["append"].withDefault(false); } else { - OPTION(Options::getRoot(),append,false); // I hope that is the correct default + append = Options::root()["append"].withDefault( + false); // I hope that is the correct default } std::string dump_ext="nc"; // bad style, but I only use nc @@ -80,7 +82,7 @@ class MonitorExample : public PhysicsModel { // In case the monitor should be relative to the timestep, the // timestep needs to be read first: BoutReal timestep; - OPTION(Options::getRoot(),timestep,-1); + timestep = Options::root()["timestep"].withDefault(-1); // There is no 'slow' section in BOUT.inp, therfore it will write // to data/slow.dmp.0.nc Monitor1dDump * slow=new Monitor1dDump(timestep*2,"slow"); diff --git a/examples/tokamak-2fluid/2fluid.cxx b/examples/tokamak-2fluid/2fluid.cxx index 47bd464bac..84d118f327 100644 --- a/examples/tokamak-2fluid/2fluid.cxx +++ b/examples/tokamak-2fluid/2fluid.cxx @@ -160,22 +160,22 @@ class TwoFluid : public PhysicsModel { // Read some parameters auto globalOptions = Options::root(); auto options = globalOptions["2fluid"]; - - OPTION(options, AA, 2.0); - OPTION(options, ZZ, 1.0); - - OPTION(options, estatic, false); - OPTION(options, ZeroElMass, false); - OPTION(options, zeff, 1.0); - OPTION(options, nu_perp, 0.0); - OPTION(options, ShearFactor, 1.0); - OPTION(options, OhmPe, true); - OPTION(options, bout_jpar, false); - OPTION(options, curv_upwind, false); - + + AA = options["AA"].withDefault(2.0); + ZZ = options["ZZ"].withDefault(1.0); + + estatic = options["estatic"].withDefault(false); + ZeroElMass = options["ZeroElMass"].withDefault(false); + zeff = options["zeff"].withDefault(1.0); + nu_perp = options["nu_perp"].withDefault(0.0); + ShearFactor = options["ShearFactor"].withDefault(1.0); + OhmPe = options["OhmPe"].withDefault(true); + bout_jpar = options["bout_jpar"].withDefault(false); + curv_upwind = options["curv_upwind"].withDefault(false); + // Choose method to use for Poisson bracket advection terms int bracket_method; - OPTION(options, bracket_method, 0); + bracket_method = options["bracket_method"].withDefault(0); switch(bracket_method) { case 0: { bm = BRACKET_STD; @@ -201,21 +201,21 @@ class TwoFluid : public PhysicsModel { output << "ERROR: Invalid choice of bracket method. Must be 0 - 3\n"; return 1; } - - OPTION(options, nuIonNeutral, -1.); - - OPTION(options, bkgd, 2); - OPTION(options, iTe_dc, 2); - - OPTION(options, stagger, false); - - OPTION(options, laplace_extra_rho_term, false); - OPTION(options, vort_include_pi, false); - - OPTION(options, lowPass_z, -1); - - OPTION(options, phi_flags, 0); - OPTION(options, apar_flags, 0); + + nuIonNeutral = options["nuIonNeutral"].withDefault(-1.); + + bkgd = options["bkgd"].withDefault(2); + iTe_dc = options["iTe_dc"].withDefault(2); + + stagger = options["stagger"].withDefault(false); + + laplace_extra_rho_term = options["laplace_extra_rho_term"].withDefault(false); + vort_include_pi = options["vort_include_pi"].withDefault(false); + + lowPass_z = options["lowPass_z"].withDefault(-1); + + phi_flags = options["phi_flags"].withDefault(0); + apar_flags = options["apar_flags"].withDefault(0); evolve_ni = globalOptions["Ni"]["evolve"].withDefault(true); evolve_rho = globalOptions["rho"]["evolve"].withDefault(true); diff --git a/examples/uedge-benchmark/ue_bmark.cxx b/examples/uedge-benchmark/ue_bmark.cxx index 7717fe39d7..56cd3b10af 100644 --- a/examples/uedge-benchmark/ue_bmark.cxx +++ b/examples/uedge-benchmark/ue_bmark.cxx @@ -73,12 +73,12 @@ class UedgeBenchmark : public PhysicsModel { // Read some parameters auto& globalOptions = Options::root(); auto& options = globalOptions["uedge"]; - OPTION(options, AA, 2.0); - OPTION(options, ZZ, 1.0); + AA = options["AA"].withDefault(2.0); + ZZ = options["ZZ"].withDefault(1.0); - OPTION(options, chi_perp, 0.6); // Read in m^2 / s - OPTION(options, D_perp, 0.6); - OPTION(options, mu_perp, 0.6); + chi_perp = options["chi_perp"].withDefault(0.6); // Read in m^2 / s + D_perp = options["D_perp"].withDefault(0.6); + mu_perp = options["mu_perp"].withDefault(0.6); ////////////// CALCULATE PARAMETERS /////////////////// From 3b331451d23f20558e365a5cec2c89e2b16ec96e Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 6 Feb 2019 12:54:15 +0000 Subject: [PATCH 0708/1783] Remove test-difops performance example See #1457 for some related discussion --- examples/performance/difops/data/BOUT.inp | 13 -- examples/performance/difops/makefile | 6 - examples/performance/difops/test-difops.cxx | 209 -------------------- 3 files changed, 228 deletions(-) delete mode 100644 examples/performance/difops/data/BOUT.inp delete mode 100644 examples/performance/difops/makefile delete mode 100644 examples/performance/difops/test-difops.cxx diff --git a/examples/performance/difops/data/BOUT.inp b/examples/performance/difops/data/BOUT.inp deleted file mode 100644 index 7de709fbed..0000000000 --- a/examples/performance/difops/data/BOUT.inp +++ /dev/null @@ -1,13 +0,0 @@ - -[mesh] -nx = 100 -ny = 100 -nz = 128 - -R_c = 100 -L_par = 1e4 - -phi = sin(x-z) - -n = mixmode(z)*gauss(x-0.5) -vort = cos(2*x+z) diff --git a/examples/performance/difops/makefile b/examples/performance/difops/makefile deleted file mode 100644 index 6cbc7da962..0000000000 --- a/examples/performance/difops/makefile +++ /dev/null @@ -1,6 +0,0 @@ - -BOUT_TOP = ../../.. - -SOURCEC = test-difops.cxx - -include $(BOUT_TOP)/make.config diff --git a/examples/performance/difops/test-difops.cxx b/examples/performance/difops/test-difops.cxx deleted file mode 100644 index a7bfc94747..0000000000 --- a/examples/performance/difops/test-difops.cxx +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Test case for differential operators on single - * index, performance comparison against current operators - * which contain individual loops over the domain. - * - * The equations tested are a subset of those in the 2D blob - * simulations (examples/blob2d) - * - * New operators seem to be slightly faster: - * - * Inner loops : 0.353403 - * Outer loop : 0.186931 - * - */ - -#include -#include - -#include -#include - -///////////////////////////////////////////////////////////////////////////// -// 2nd order central differencing - -/*! - * 2nd order central differencing in X - * Performs operation over RGN_NOBNDRY - */ -const Field3D DDX_C2(const Field3D &f) { - Field3D result; - result.allocate(); - for(auto i : result.getRegion(RGN_NOBNDRY)) { - result[i] = DDX_C2(f, i); - } - return result; -} - -/*! - * 2nd order central differencing in Y - * Performs operation over RGN_NOBNDRY - */ -const Field3D DDY_C2(const Field3D &f) { - Field3D result; - result.allocate(); - for(auto i : result.getRegion(RGN_NOBNDRY)) { - result[i] = DDY_C2(f, i); - } - return result; -} - -/*! - * 2nd order central differencing in Z - * Performs operation over RGN_NOBNDRY - */ -const Field3D DDZ_C2(const Field3D &f) { - Field3D result; - result.allocate(); - for(auto i : result.getRegion(RGN_NOBNDRY)) { - result[i] = DDZ_C2(f, i); - } - return result; -} - -///////////////////////////////////////////////////////////////////////////// -// 4th order central differencing - -/*! - * 4th order central differencing in X - * Performs operation over RGN_NOBNDRY - */ -const Field3D DDX_C4(const Field3D &f) { - Field3D result; - result.allocate(); - for(auto i : result.getRegion(RGN_NOBNDRY)) { - result[i] = DDX_C4(f, i); - } - return result; -} - -/*! - * 4th order central differencing in X - * Performs operation over RGN_NOBNDRY - */ -const Field3D DDZ_C4(const Field3D &f) { - Field3D result; - result.allocate(); - for(auto i : result.getRegion(RGN_NOBNDRY)) { - result[i] = DDZ_C4(f, i); - } - return result; -} - -///////////////////////////////////////////////////////////////////////////// -// First derivatives - -const Field3D DDX_test(const Field3D &f) { - // This could be done with a static function - // but a) this has another "if" to check the function, and - // b) is not thread safe (OpenMP) - static const Field3D (*func)(const Field3D &f) = nullptr; - - if(!func) { - // Not defined yet - std::string setting; - Options::getRoot()->getSection("operators")->get("ddx", setting, "c2"); - setting = lowercase(setting); - - if(setting == "c2") { - func = &DDX_C2; - }else if(setting == "c4") { - func = &DDX_C4; - }else { - throw BoutException("Unrecognised option for DDX: '%s'", setting.c_str()); - } - } - // Call the function - return (*func)(f); -} - - - -///////////////////////////////////////////////////////////////////////////// -// Arakawa brackets - -const Field3D bracket_arakawa(const Field3D &f, const Field3D &g) { - Field3D result; - result.allocate(); - for(auto i : result.getRegion(RGN_NOBNDRY)) { - result[i] = bracket_arakawa(f, g, i); - } - return result; -} - -int main(int argc, char **argv) { - BoutInitialise(argc, argv); - - typedef std::chrono::time_point SteadyClock; - typedef std::chrono::duration Duration; - using namespace std::chrono; - - Field3D phi, n, vort; - GRID_LOAD3(phi, n, vort); - - BoutReal R_c, L_par; - GRID_LOAD2(R_c, L_par); - - ///////////////////////////////////////////////// - // Single loop over domain - - SteadyClock start2 = steady_clock::now(); - // Note: Need to allocate ddt() fields before [] access - ddt(n).allocate(); - ddt(vort).allocate(); - for(auto i : n.getRegion(RGN_NOBNDRY)) { - - ddt(n)[i] = - - bracket_arakawa(phi, n, i) - + (2./R_c)*DDZ_C2(n, i) - + n[i]*phi[i]/L_par - ; - - ddt(vort)[i] = - - bracket_arakawa(phi, vort, i) - + (2./R_c)*DDZ_C2(n, i) - + phi[i]/L_par; - - } - Duration elapsed2 = steady_clock::now() - start2; - // Save ddt values for comparison later - Field3D dn_2 = ddt(n); - Field3D dvort_2 = ddt(vort); - - ///////////////////////////////////////////////// - // Using several internal loops over domain - - SteadyClock start1 = steady_clock::now(); - ddt(n) = - - bracket_arakawa(phi, n) //bracket(phi, n, BRACKET_ARAKAWA) - + (2./R_c)*DDZ(n) - + n*phi/L_par - ; - - ddt(vort) = - - bracket_arakawa(phi, vort)//bracket(phi, vort, BRACKET_ARAKAWA) - + (2./R_c)*DDZ(n) - + phi/L_par; - Duration elapsed1 = steady_clock::now() - start1; - - ///////////////////////////////////////////////// - // Check results - - for(auto i : n.getRegion(RGN_NOBNDRY)) { - if(abs(ddt(n)[i] - dn_2[i]) > 1e-5) { - output.write("Difference in ddt(n) at (%d,%d,%d): %e, %e\n", - i.x, i.y, i.z, ddt(n)[i], dn_2[i]); - } - if(abs(ddt(vort)[i] - dvort_2[i]) > 1e-5) { - output.write("Difference in ddt(vort) at (%d,%d,%d): %e, %e\n", - i.x, i.y, i.z, ddt(vort)[i], dvort_2[i]); - } - } - - output << "TIMING\n======\n"; - output << "Inner loops : " << elapsed1.count() << std::endl; - output << "Outer loop : " << elapsed2.count() << std::endl; - - BoutFinalise(); - return 0; -} From b7255becac4db6d3592688175b1b3cc4c6d362f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Mon, 4 Feb 2019 14:44:24 +0000 Subject: [PATCH 0709/1783] Auto: update libbout.pot --- locale/libbout.pot | 91 ++++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/locale/libbout.pot b/locale/libbout.pot index 8f66cc21be..b44af86df4 100644 --- a/locale/libbout.pot +++ b/locale/libbout.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-11-01 17:55+0000\n" +"POT-Creation-Date: 2019-02-04 14:41+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -30,18 +30,23 @@ msgstr "" msgid "\tCandidate value: %d\n" msgstr "" -#: ../src/bout++.cxx:370 +#: ../src/bout++.cxx:385 msgid "\tChecking disabled\n" msgstr "" -#: ../src/bout++.cxx:368 +#: ../src/bout++.cxx:383 #, c-format msgid "\tChecking enabled, level %d\n" msgstr "" +#. Print command line options +#: ../src/bout++.cxx:429 +msgid "\tCommand line options for this run : " +msgstr "" + #. The stringify is needed here as BOUT_FLAGS_STRING may already contain quoted strings #. which could cause problems (e.g. terminate strings). -#: ../src/bout++.cxx:411 +#: ../src/bout++.cxx:426 #, c-format msgid "\tCompiled with flags : %s\n" msgstr "" @@ -89,21 +94,21 @@ msgstr "" msgid "\tMultiple '=' in command-line argument '%s'\n" msgstr "" -#: ../src/bout++.cxx:398 +#: ../src/bout++.cxx:413 msgid "\tOpenMP parallelisation disabled\n" msgstr "" -#: ../src/bout++.cxx:396 +#: ../src/bout++.cxx:411 #, c-format msgid "\tOpenMP parallelisation enabled, using %d threads\n" msgstr "" #. Mark the option as used #. Option not found +#: ../include/options.hxx:298 ../include/options.hxx:319 #: ../src/sys/options.cxx:96 ../src/sys/options.cxx:136 #: ../src/sys/options.cxx:172 ../src/sys/options.cxx:200 #: ../src/sys/options.cxx:221 ../src/sys/options.cxx:224 -#: ../include/options.hxx:298 ../include/options.hxx:319 msgid "\tOption " msgstr "" @@ -117,11 +122,11 @@ msgstr "" msgid "\tOptions file '%s' not found\n" msgstr "" -#: ../src/bout++.cxx:392 +#: ../src/bout++.cxx:407 msgid "\tParallel NetCDF support disabled\n" msgstr "" -#: ../src/bout++.cxx:390 +#: ../src/bout++.cxx:405 msgid "\tParallel NetCDF support enabled\n" msgstr "" @@ -137,31 +142,31 @@ msgstr "" msgid "\tReading covariant vector " msgstr "" -#: ../src/bout++.cxx:376 +#: ../src/bout++.cxx:391 msgid "\tSignal handling disabled\n" msgstr "" -#: ../src/bout++.cxx:374 +#: ../src/bout++.cxx:389 msgid "\tSignal handling enabled\n" msgstr "" -#: ../src/mesh/impls/bout/boutmesh.cxx:842 +#: ../src/mesh/impls/bout/boutmesh.cxx:857 msgid "\tdone\n" msgstr "" -#: ../src/bout++.cxx:385 +#: ../src/bout++.cxx:400 msgid "\tnetCDF support disabled\n" msgstr "" -#: ../src/bout++.cxx:380 +#: ../src/bout++.cxx:395 msgid "\tnetCDF support enabled\n" msgstr "" -#: ../src/bout++.cxx:383 +#: ../src/bout++.cxx:398 msgid "\tnetCDF4 support enabled\n" msgstr "" -#: ../src/bout++.cxx:172 +#: ../src/bout++.cxx:164 #, c-format msgid "" "\n" @@ -187,12 +192,12 @@ msgid "" "Run started at : %s\n" msgstr "" -#: ../src/bout++.cxx:181 +#: ../src/bout++.cxx:173 #, c-format msgid " -c, --color\t\tColor output using bout-log-color\n" msgstr "" -#: ../src/bout++.cxx:184 +#: ../src/bout++.cxx:176 #, c-format msgid "" " -h, --help\t\tThis message\n" @@ -213,7 +218,7 @@ msgid "All options used\n" msgstr "" #. / Print intro -#: ../src/bout++.cxx:348 +#: ../src/bout++.cxx:363 #, c-format msgid "BOUT++ version %s\n" msgstr "" @@ -227,7 +232,7 @@ msgstr "" msgid "Cannot split %d X points equally between %d processors\n" msgstr "" -#: ../src/bout++.cxx:355 +#: ../src/bout++.cxx:370 #, c-format msgid "" "Code compiled on %s at %s\n" @@ -239,7 +244,7 @@ msgid "Command line" msgstr "" #. / Print compile-time options -#: ../src/bout++.cxx:365 +#: ../src/bout++.cxx:380 msgid "Compile-time options:\n" msgstr "" @@ -264,7 +269,7 @@ msgid "Could not read integer array '%s'\n" msgstr "" #. Failed . Probably not important enough to stop the simulation -#: ../src/bout++.cxx:308 +#: ../src/bout++.cxx:322 #, c-format msgid "Could not run bout-log-color. Make sure it is in your PATH\n" msgstr "" @@ -299,12 +304,12 @@ msgstr "" msgid "Couldn't get integer from option %s = '%s'" msgstr "" -#: ../src/bout++.cxx:261 +#: ../src/bout++.cxx:279 #, c-format msgid "DataDir \"%s\" does not exist or is not accessible\n" msgstr "" -#: ../src/bout++.cxx:258 +#: ../src/bout++.cxx:276 #, c-format msgid "DataDir \"%s\" is not a directory\n" msgstr "" @@ -313,16 +318,16 @@ msgstr "" msgid "ERROR: Solver is already initialised\n" msgstr "" -#: ../src/bout++.cxx:441 +#: ../src/bout++.cxx:468 msgid "Error encountered during initialisation\n" msgstr "" -#: ../src/bout++.cxx:486 +#: ../src/bout++.cxx:513 #, c-format msgid "Error encountered during initialisation: %s\n" msgstr "" -#: ../src/bout++.cxx:525 +#: ../src/bout++.cxx:552 msgid "Error whilst writing settings" msgstr "" @@ -339,7 +344,7 @@ msgstr "" msgid "Initialising solver\n" msgstr "" -#: ../src/bout++.cxx:250 +#: ../src/bout++.cxx:268 msgid "" "Input and output file for settings must be different.\n" "Provide -o to avoid this issue.\n" @@ -381,7 +386,7 @@ msgid "Number of processors (%d) not divisible by NPs in x direction (%d)\n" msgstr "" #. Less than 1 time-step left -#: ../src/bout++.cxx:675 +#: ../src/bout++.cxx:702 #, c-format msgid "Only %e seconds left. Quitting\n" msgstr "" @@ -410,26 +415,26 @@ msgid "" "was '%s'." msgstr "" -#: ../src/bout++.cxx:359 +#: ../src/bout++.cxx:374 #, c-format msgid "" "Processor number: %d of %d\n" "\n" msgstr "" -#: ../src/mesh/mesh.cxx:376 +#: ../src/mesh/mesh.cxx:388 msgid "Registered region 2D " msgstr "" -#: ../src/mesh/mesh.cxx:367 +#: ../src/mesh/mesh.cxx:379 msgid "Registered region 3D " msgstr "" -#: ../src/mesh/mesh.cxx:385 +#: ../src/mesh/mesh.cxx:397 msgid "Registered region Perp " msgstr "" -#: ../src/bout++.cxx:350 +#: ../src/bout++.cxx:365 #, c-format msgid "Revision: %s\n" msgstr "" @@ -445,13 +450,13 @@ msgid "" "\n" msgstr "" -#: ../src/bout++.cxx:636 +#: ../src/bout++.cxx:663 msgid "" "Sim Time | RHS evals | Wall Time | Calc Inv Comm I/O SOLVER\n" "\n" msgstr "" -#: ../src/bout++.cxx:639 +#: ../src/bout++.cxx:666 msgid "" "Sim Time | RHS_e evals | RHS_I evals | Wall Time | Calc Inv " "Comm I/O SOLVER\n" @@ -487,17 +492,17 @@ msgstr "" msgid "Time derivative for variable '%s' not set" msgstr "" -#: ../src/mesh/mesh.cxx:373 +#: ../src/mesh/mesh.cxx:385 #, c-format msgid "Trying to add an already existing region %s to regionMap2D" msgstr "" -#: ../src/mesh/mesh.cxx:364 +#: ../src/mesh/mesh.cxx:376 #, c-format msgid "Trying to add an already existing region %s to regionMap3D" msgstr "" -#: ../src/mesh/mesh.cxx:382 +#: ../src/mesh/mesh.cxx:394 #, c-format msgid "Trying to add an already existing region %s to regionMapPerp" msgstr "" @@ -517,23 +522,23 @@ msgstr "" msgid "Usage is %s -d \n" msgstr "" -#: ../src/bout++.cxx:209 +#: ../src/bout++.cxx:212 #, c-format msgid "Usage is %s -f \n" msgstr "" -#: ../src/bout++.cxx:226 +#: ../src/bout++.cxx:235 #, c-format msgid "Usage is %s -l \n" msgstr "" -#: ../src/bout++.cxx:218 +#: ../src/bout++.cxx:224 #, c-format msgid "Usage is %s -o \n" msgstr "" #. Print help message -- note this will be displayed once per processor as we've not started MPI yet. -#: ../src/bout++.cxx:170 +#: ../src/bout++.cxx:162 #, c-format msgid "" "Usage: %s [-d ] [-f ] [restart [append]] " From ce1ae11b1ae486e2a75618095cd753e755f1e623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Wed, 6 Feb 2019 17:35:55 +0000 Subject: [PATCH 0710/1783] String changes for translation * use write (printf style) to allow more flexible translations * Add _() - to enable translation of strings --- src/mesh/impls/bout/boutmesh.cxx | 30 +++++++++++++++--------------- src/mesh/mesh.cxx | 12 ++++++------ src/sys/options.cxx | 8 ++++---- src/sys/optionsreader.cxx | 2 +- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 8ed15a1cc6..9fd1ca673c 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -301,7 +301,7 @@ int BoutMesh::load() { BoutReal ideal = sqrt(MX * NPES / static_cast(ny)); // Results in square domains - output_info.write("Finding value for NXPE (ideal = %f)\n", ideal); + output_info.write(_("Finding value for NXPE (ideal = %f)\n"), ideal); for (int i = 1; i <= NPES; i++) { // Loop over all possibilities if ((NPES % i == 0) && // Processors divide equally @@ -315,14 +315,14 @@ int BoutMesh::load() { // Check size of Y mesh if (ysub < MYG) { - output_info.write("\t -> ny/NYPE (%d/%d = %d) must be >= MYG (%d)\n", ny, nyp, + output_info.write(_("\t -> ny/NYPE (%d/%d = %d) must be >= MYG (%d)\n"), ny, nyp, ysub, MYG); continue; } // Check branch cuts if ((jyseps1_1 + 1) % ysub != 0) { output_info.write( - "\t -> Leg region jyseps1_1+1 (%d) must be a multiple of MYSUB (%d)\n", + _("\t -> Leg region jyseps1_1+1 (%d) must be a multiple of MYSUB (%d)\n"), jyseps1_1 + 1, ysub); continue; } @@ -331,45 +331,45 @@ int BoutMesh::load() { // Double Null if ((jyseps2_1 - jyseps1_1) % ysub != 0) { - output_info.write("\t -> Core region jyseps2_1-jyseps1_1 (%d-%d = %d) must " - "be a multiple of MYSUB (%d)\n", + output_info.write(_("\t -> Core region jyseps2_1-jyseps1_1 (%d-%d = %d) must " + "be a multiple of MYSUB (%d)\n"), jyseps2_1, jyseps1_1, jyseps2_1 - jyseps1_1, ysub); continue; } if ((jyseps2_2 - jyseps1_2) % ysub != 0) { - output_info.write("\t -> Core region jyseps2_2-jyseps1_2 (%d-%d = %d) must " - "be a multiple of MYSUB (%d)\n", + output_info.write(_("\t -> Core region jyseps2_2-jyseps1_2 (%d-%d = %d) must " + "be a multiple of MYSUB (%d)\n"), jyseps2_2, jyseps1_2, jyseps2_2 - jyseps1_2, ysub); continue; } // Check upper legs if ((ny_inner - jyseps2_1 - 1) % ysub != 0) { - output_info.write("\t -> leg region ny_inner-jyseps2_1-1 (%d-%d-1 = %d) must " - "be a multiple of MYSUB (%d)\n", + output_info.write(_("\t -> leg region ny_inner-jyseps2_1-1 (%d-%d-1 = %d) must " + "be a multiple of MYSUB (%d)\n"), ny_inner, jyseps2_1, ny_inner - jyseps2_1 - 1, ysub); continue; } if ((jyseps1_2 - ny_inner + 1) % ysub != 0) { - output_info.write("\t -> leg region jyseps1_2-ny_inner+1 (%d-%d+1 = %d) must " - "be a multiple of MYSUB (%d)\n", + output_info.write(_("\t -> leg region jyseps1_2-ny_inner+1 (%d-%d+1 = %d) must " + "be a multiple of MYSUB (%d)\n"), jyseps1_2, ny_inner, jyseps1_2 - ny_inner + 1, ysub); continue; } } else { // Single Null if ((jyseps2_2 - jyseps1_1) % ysub != 0) { - output_info.write("\t -> Core region jyseps2_2-jyseps1_1 (%d-%d = %d) must " - "be a multiple of MYSUB (%d)\n", + output_info.write(_("\t -> Core region jyseps2_2-jyseps1_1 (%d-%d = %d) must " + "be a multiple of MYSUB (%d)\n"), jyseps2_2, jyseps1_1, jyseps2_2 - jyseps1_1, ysub); continue; } } if ((ny - jyseps2_2 - 1) % ysub != 0) { - output_info.write("\t -> leg region ny-jyseps2_2-1 (%d-%d-1 = %d) must be a " - "multiple of MYSUB (%d)\n", + output_info.write(_("\t -> leg region ny-jyseps2_2-1 (%d-%d-1 = %d) must be a " + "multiple of MYSUB (%d)\n"), ny, jyseps2_2, ny - jyseps2_2 - 1, ysub); continue; } diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 941bfc6580..65b19df8fa 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -376,8 +376,8 @@ void Mesh::addRegion3D(const std::string ®ion_name, const Region<> ®ion) { throw BoutException(_("Trying to add an already existing region %s to regionMap3D"), region_name.c_str()); } regionMap3D[region_name] = region; - output_verbose << _("Registered region 3D ") << region_name << ": \n" - << "\t" << region.getStats() << "\n"; + output_verbose.write(_("Registered region 3D %s"),region_name.c_str()); + output_verbose << "\n:\t" << region.getStats() << "\n"; } void Mesh::addRegion2D(const std::string ®ion_name, const Region ®ion) { @@ -385,8 +385,8 @@ void Mesh::addRegion2D(const std::string ®ion_name, const Region ®i throw BoutException(_("Trying to add an already existing region %s to regionMap2D"), region_name.c_str()); } regionMap2D[region_name] = region; - output_verbose << _("Registered region 2D ") << region_name << ": \n" - << "\t" << region.getStats() << "\n"; + output_verbose.write(_("Registered region 2D %s"),region_name.c_str()); + output_verbose << "\n:\t" << region.getStats() << "\n"; } void Mesh::addRegionPerp(const std::string ®ion_name, const Region ®ion) { @@ -394,8 +394,8 @@ void Mesh::addRegionPerp(const std::string ®ion_name, const Region & throw BoutException(_("Trying to add an already existing region %s to regionMapPerp"), region_name.c_str()); } regionMapPerp[region_name] = region; - output_verbose << _("Registered region Perp ") << region_name << ": \n" - << "\t" << region.getStats() << "\n"; + output_verbose.write(_("Registered region Perp %s"),region_name.c_str()); + output_verbose << "\n:\t" << region.getStats() << "\n"; } void Mesh::createDefaultRegions(){ diff --git a/src/sys/options.cxx b/src/sys/options.cxx index ede54a01d7..f5169f47e3 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -93,10 +93,10 @@ void Options::_set(std::string val, std::string source, bool force) { // Check if current value the same as new value if (value.value != val) { if (force or value.source != source) { - output_warn << _("\tOption ") << full_name << " = " << value.value << " (" - << value.source << _(") overwritten with:") - << "\n" - << "\t\t" << full_name << " = " << val << " (" << source << ")\n"; + output_warn.write( + _("\tOption %s = %s (%s) overwritten with:\n\t\t%s = %s (%s)\n"), + full_name.c_str(), value.value.c_str(), value.source.c_str(), + full_name.c_str(), val.c_str(), source.c_str()); } else { throw BoutException(_("Options: Setting a value from same source (%s) to new value " "'%s' - old value was '%s'."), diff --git a/src/sys/optionsreader.cxx b/src/sys/optionsreader.cxx index 5fde50e3d9..34b4747cf6 100644 --- a/src/sys/optionsreader.cxx +++ b/src/sys/optionsreader.cxx @@ -57,7 +57,7 @@ void OptionsReader::write(Options *options, const char *file, ...) { bout_vsnprintf(filename,buf_len, file); - output_info << _("Writing options to file ") << filename << "\n"; + output_info.write(_("Writing options to file %s\n"),filename); // Need to decide what file format to use OptionParser *parser = new OptionINI(); From 0dcb7d67c3111fa859990a96648a8748e2fa6fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Wed, 6 Feb 2019 17:39:21 +0000 Subject: [PATCH 0711/1783] Extend README Add some things I learned during translation, which might be useful for the next translator. --- locale/README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/locale/README.md b/locale/README.md index 9b0ed60967..8ace1f9bd3 100644 --- a/locale/README.md +++ b/locale/README.md @@ -22,6 +22,15 @@ Start a new translation: make locale-XX where XX is the language e.g. "de" for German, or a language_country code e.g. "de_DE". -This will update a .po file if it already exists. -Edit the .po file, translating or deleting new entries, then remake the .mo files. - +Edit the .po file, translating or deleting new entries: + * Make sure to set the charset (around line 16) to utf-8. + * msgid is the original text. Write in msgstr the translated string. + * You can reorder arguments using %n$s like this:: + msgid "" + "Options: Setting a value from same source (%s) to new value '%s' - old value " + "was '%s'." + msgstr "" + "Options: The Value %3$s is overwritten with %2$s from the same source (%1%s)" +There are also editors for editing .po files, e.g. poeditor. + +Calling `make locale-XX` again will update the .po file. From 917633d84231973df2ee66362019bbf8da951806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Wed, 6 Feb 2019 17:39:58 +0000 Subject: [PATCH 0712/1783] Update generated file --- locale/libbout.pot | 190 ++++++++++++++++++++++++++++++--------------- 1 file changed, 126 insertions(+), 64 deletions(-) diff --git a/locale/libbout.pot b/locale/libbout.pot index b44af86df4..595771f856 100644 --- a/locale/libbout.pot +++ b/locale/libbout.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-02-04 14:41+0000\n" +"POT-Creation-Date: 2019-02-06 17:31+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,47 +17,99 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: ../src/mesh/impls/bout/boutmesh.cxx:376 +#: ../src/mesh/impls/bout/boutmesh.cxx:335 +#, c-format +msgid "" +"\t -> Core region jyseps2_1-jyseps1_1 (%d-%d = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:364 +#, c-format +msgid "" +"\t -> Core region jyseps2_2-jyseps1_1 (%d-%d = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:342 +#, c-format +msgid "" +"\t -> Core region jyseps2_2-jyseps1_2 (%d-%d = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:377 msgid "\t -> Good value\n" msgstr "" +#: ../src/mesh/impls/bout/boutmesh.cxx:326 +#, c-format +msgid "\t -> Leg region jyseps1_1+1 (%d) must be a multiple of MYSUB (%d)\n" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:356 +#, c-format +msgid "" +"\t -> leg region jyseps1_2-ny_inner+1 (%d-%d+1 = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:372 +#, c-format +msgid "" +"\t -> leg region ny-jyseps2_2-1 (%d-%d-1 = %d) must be a multiple of MYSUB " +"(%d)\n" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:350 +#, c-format +msgid "" +"\t -> leg region ny_inner-jyseps2_1-1 (%d-%d-1 = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" + +#: ../src/mesh/impls/bout/boutmesh.cxx:319 +#, c-format +msgid "\t -> ny/NYPE (%d/%d = %d) must be >= MYG (%d)\n" +msgstr "" + #. Loop over all possibilities #. Processors divide equally #. Mesh in X divides equally #. Mesh in Y divides equally -#: ../src/mesh/impls/bout/boutmesh.cxx:311 +#: ../src/mesh/impls/bout/boutmesh.cxx:312 #, c-format msgid "\tCandidate value: %d\n" msgstr "" -#: ../src/bout++.cxx:385 +#: ../src/bout++.cxx:387 msgid "\tChecking disabled\n" msgstr "" -#: ../src/bout++.cxx:383 +#: ../src/bout++.cxx:385 #, c-format msgid "\tChecking enabled, level %d\n" msgstr "" #. Print command line options -#: ../src/bout++.cxx:429 +#: ../src/bout++.cxx:431 msgid "\tCommand line options for this run : " msgstr "" #. The stringify is needed here as BOUT_FLAGS_STRING may already contain quoted strings #. which could cause problems (e.g. terminate strings). -#: ../src/bout++.cxx:426 +#: ../src/bout++.cxx:428 #, c-format msgid "\tCompiled with flags : %s\n" msgstr "" -#: ../src/mesh/impls/bout/boutmesh.cxx:390 +#: ../src/mesh/impls/bout/boutmesh.cxx:391 #, c-format msgid "" "\tDomain split (NXPE=%d, NYPE=%d) into domains (localNx=%d, localNy=%d)\n" msgstr "" -#: ../src/mesh/impls/bout/boutmesh.cxx:415 +#: ../src/mesh/impls/bout/boutmesh.cxx:416 #, c-format msgid "\tERROR: Cannot split %d Y points equally between %d processors\n" msgstr "" @@ -94,11 +146,11 @@ msgstr "" msgid "\tMultiple '=' in command-line argument '%s'\n" msgstr "" -#: ../src/bout++.cxx:413 +#: ../src/bout++.cxx:415 msgid "\tOpenMP parallelisation disabled\n" msgstr "" -#: ../src/bout++.cxx:411 +#: ../src/bout++.cxx:413 #, c-format msgid "\tOpenMP parallelisation enabled, using %d threads\n" msgstr "" @@ -106,12 +158,19 @@ msgstr "" #. Mark the option as used #. Option not found #: ../include/options.hxx:298 ../include/options.hxx:319 -#: ../src/sys/options.cxx:96 ../src/sys/options.cxx:136 -#: ../src/sys/options.cxx:172 ../src/sys/options.cxx:200 -#: ../src/sys/options.cxx:221 ../src/sys/options.cxx:224 +#: ../src/sys/options.cxx:136 ../src/sys/options.cxx:172 +#: ../src/sys/options.cxx:200 ../src/sys/options.cxx:221 +#: ../src/sys/options.cxx:224 msgid "\tOption " msgstr "" +#: ../src/sys/options.cxx:97 +#, c-format +msgid "" +"\tOption %s = %s (%s) overwritten with:\n" +"\t\t%s = %s (%s)\n" +msgstr "" + #: ../src/sys/options.cxx:226 #, c-format msgid "\tOption '%s': Boolean expected. Got '%s'\n" @@ -122,11 +181,11 @@ msgstr "" msgid "\tOptions file '%s' not found\n" msgstr "" -#: ../src/bout++.cxx:407 +#: ../src/bout++.cxx:409 msgid "\tParallel NetCDF support disabled\n" msgstr "" -#: ../src/bout++.cxx:405 +#: ../src/bout++.cxx:407 msgid "\tParallel NetCDF support enabled\n" msgstr "" @@ -142,31 +201,31 @@ msgstr "" msgid "\tReading covariant vector " msgstr "" -#: ../src/bout++.cxx:391 +#: ../src/bout++.cxx:393 msgid "\tSignal handling disabled\n" msgstr "" -#: ../src/bout++.cxx:389 +#: ../src/bout++.cxx:391 msgid "\tSignal handling enabled\n" msgstr "" -#: ../src/mesh/impls/bout/boutmesh.cxx:857 +#: ../src/mesh/impls/bout/boutmesh.cxx:858 msgid "\tdone\n" msgstr "" -#: ../src/bout++.cxx:400 +#: ../src/bout++.cxx:402 msgid "\tnetCDF support disabled\n" msgstr "" -#: ../src/bout++.cxx:395 +#: ../src/bout++.cxx:397 msgid "\tnetCDF support enabled\n" msgstr "" -#: ../src/bout++.cxx:398 +#: ../src/bout++.cxx:400 msgid "\tnetCDF4 support enabled\n" msgstr "" -#: ../src/bout++.cxx:164 +#: ../src/bout++.cxx:166 #, c-format msgid "" "\n" @@ -192,12 +251,12 @@ msgid "" "Run started at : %s\n" msgstr "" -#: ../src/bout++.cxx:173 +#: ../src/bout++.cxx:175 #, c-format msgid " -c, --color\t\tColor output using bout-log-color\n" msgstr "" -#: ../src/bout++.cxx:176 +#: ../src/bout++.cxx:178 #, c-format msgid "" " -h, --help\t\tThis message\n" @@ -209,30 +268,26 @@ msgid "" "model source (e.g. %s.cxx)\n" msgstr "" -#: ../src/sys/options.cxx:97 -msgid ") overwritten with:" -msgstr "" - #: ../src/sys/options.cxx:248 msgid "All options used\n" msgstr "" #. / Print intro -#: ../src/bout++.cxx:363 +#: ../src/bout++.cxx:365 #, c-format msgid "BOUT++ version %s\n" msgstr "" -#: ../src/mesh/impls/bout/boutmesh.cxx:827 +#: ../src/mesh/impls/bout/boutmesh.cxx:828 msgid "Boundary regions in this processor: " msgstr "" -#: ../src/mesh/impls/bout/boutmesh.cxx:406 +#: ../src/mesh/impls/bout/boutmesh.cxx:407 #, c-format msgid "Cannot split %d X points equally between %d processors\n" msgstr "" -#: ../src/bout++.cxx:370 +#: ../src/bout++.cxx:372 #, c-format msgid "" "Code compiled on %s at %s\n" @@ -244,15 +299,15 @@ msgid "Command line" msgstr "" #. / Print compile-time options -#: ../src/bout++.cxx:380 +#: ../src/bout++.cxx:382 msgid "Compile-time options:\n" msgstr "" -#: ../src/mesh/impls/bout/boutmesh.cxx:836 +#: ../src/mesh/impls/bout/boutmesh.cxx:837 msgid "Constructing default regions" msgstr "" -#: ../src/mesh/impls/bout/boutmesh.cxx:384 +#: ../src/mesh/impls/bout/boutmesh.cxx:385 msgid "" "Could not find a valid value for NXPE. Try a different number of processors." msgstr "" @@ -269,7 +324,7 @@ msgid "Could not read integer array '%s'\n" msgstr "" #. Failed . Probably not important enough to stop the simulation -#: ../src/bout++.cxx:322 +#: ../src/bout++.cxx:324 #, c-format msgid "Could not run bout-log-color. Make sure it is in your PATH\n" msgstr "" @@ -304,12 +359,12 @@ msgstr "" msgid "Couldn't get integer from option %s = '%s'" msgstr "" -#: ../src/bout++.cxx:279 +#: ../src/bout++.cxx:281 #, c-format msgid "DataDir \"%s\" does not exist or is not accessible\n" msgstr "" -#: ../src/bout++.cxx:276 +#: ../src/bout++.cxx:278 #, c-format msgid "DataDir \"%s\" is not a directory\n" msgstr "" @@ -318,16 +373,16 @@ msgstr "" msgid "ERROR: Solver is already initialised\n" msgstr "" -#: ../src/bout++.cxx:468 +#: ../src/bout++.cxx:470 msgid "Error encountered during initialisation\n" msgstr "" -#: ../src/bout++.cxx:513 +#: ../src/bout++.cxx:515 #, c-format msgid "Error encountered during initialisation: %s\n" msgstr "" -#: ../src/bout++.cxx:552 +#: ../src/bout++.cxx:554 msgid "Error whilst writing settings" msgstr "" @@ -340,11 +395,18 @@ msgstr "" msgid "Failed to initialise solver-> Aborting\n" msgstr "" +#. Best option +#. Results in square domains +#: ../src/mesh/impls/bout/boutmesh.cxx:305 +#, c-format +msgid "Finding value for NXPE (ideal = %f)\n" +msgstr "" + #: ../src/solver/solver.cxx:599 msgid "Initialising solver\n" msgstr "" -#: ../src/bout++.cxx:268 +#: ../src/bout++.cxx:270 msgid "" "Input and output file for settings must be different.\n" "Provide -o to avoid this issue.\n" @@ -368,25 +430,21 @@ msgstr "" msgid "Missing integer array %s\n" msgstr "" -#: ../src/solver/solver.cxx:696 -msgid "Monitor signalled to quit" -msgstr "" - -#: ../src/solver/solver.cxx:703 +#: ../src/solver/solver.cxx:696 ../src/solver/solver.cxx:703 msgid "Monitor signalled to quit\n" msgstr "" -#: ../src/mesh/impls/bout/boutmesh.cxx:833 +#: ../src/mesh/impls/bout/boutmesh.cxx:834 msgid "No boundary regions in this processor" msgstr "" -#: ../src/mesh/impls/bout/boutmesh.cxx:234 +#: ../src/mesh/impls/bout/boutmesh.cxx:235 #, c-format msgid "Number of processors (%d) not divisible by NPs in x direction (%d)\n" msgstr "" #. Less than 1 time-step left -#: ../src/bout++.cxx:702 +#: ../src/bout++.cxx:704 #, c-format msgid "Only %e seconds left. Quitting\n" msgstr "" @@ -415,7 +473,7 @@ msgid "" "was '%s'." msgstr "" -#: ../src/bout++.cxx:374 +#: ../src/bout++.cxx:376 #, c-format msgid "" "Processor number: %d of %d\n" @@ -423,18 +481,21 @@ msgid "" msgstr "" #: ../src/mesh/mesh.cxx:388 -msgid "Registered region 2D " +#, c-format +msgid "Registered region 2D %s" msgstr "" #: ../src/mesh/mesh.cxx:379 -msgid "Registered region 3D " +#, c-format +msgid "Registered region 3D %s" msgstr "" #: ../src/mesh/mesh.cxx:397 -msgid "Registered region Perp " +#, c-format +msgid "Registered region Perp %s" msgstr "" -#: ../src/bout++.cxx:365 +#: ../src/bout++.cxx:367 #, c-format msgid "Revision: %s\n" msgstr "" @@ -450,13 +511,13 @@ msgid "" "\n" msgstr "" -#: ../src/bout++.cxx:663 +#: ../src/bout++.cxx:665 msgid "" "Sim Time | RHS evals | Wall Time | Calc Inv Comm I/O SOLVER\n" "\n" msgstr "" -#: ../src/bout++.cxx:666 +#: ../src/bout++.cxx:668 msgid "" "Sim Time | RHS_e evals | RHS_I evals | Wall Time | Calc Inv " "Comm I/O SOLVER\n" @@ -517,28 +578,28 @@ msgstr "" msgid "Unused options:\n" msgstr "" -#: ../src/bout++.cxx:200 +#: ../src/bout++.cxx:202 #, c-format msgid "Usage is %s -d \n" msgstr "" -#: ../src/bout++.cxx:212 +#: ../src/bout++.cxx:214 #, c-format msgid "Usage is %s -f \n" msgstr "" -#: ../src/bout++.cxx:235 +#: ../src/bout++.cxx:237 #, c-format msgid "Usage is %s -l \n" msgstr "" -#: ../src/bout++.cxx:224 +#: ../src/bout++.cxx:226 #, c-format msgid "Usage is %s -o \n" msgstr "" #. Print help message -- note this will be displayed once per processor as we've not started MPI yet. -#: ../src/bout++.cxx:162 +#: ../src/bout++.cxx:164 #, c-format msgid "" "Usage: %s [-d ] [-f ] [restart [append]] " @@ -563,7 +624,8 @@ msgid "" msgstr "" #: ../src/sys/optionsreader.cxx:60 -msgid "Writing options to file " +#, c-format +msgid "Writing options to file %s\n" msgstr "" #. / The source label given to default values From 1dd98b484c1cf7327e7f9f546c5385c3f68b65eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Wed, 6 Feb 2019 17:40:48 +0000 Subject: [PATCH 0713/1783] Add German translation --- locale/de/libbout.po | 727 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 727 insertions(+) create mode 100644 locale/de/libbout.po diff --git a/locale/de/libbout.po b/locale/de/libbout.po new file mode 100644 index 0000000000..109d394322 --- /dev/null +++ b/locale/de/libbout.po @@ -0,0 +1,727 @@ +# German translations for BOUT++ package. +# Copyright (C) 2019 THE BOUT++'S COPYRIGHT HOLDER +# This file is distributed under the same license as the BOUT++ package. +# David , 2019. +# +msgid "" +msgstr "" +"Project-Id-Version: BOUT++ 4.2.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-02-06 17:31+0000\n" +"PO-Revision-Date: 2019-02-06 17:32+0000\n" +"Last-Translator: David \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 2.2.1\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:335 +#, c-format +msgid "" +"\t -> Core region jyseps2_1-jyseps1_1 (%d-%d = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" +"\t -> `Core` Region iyseps2_1-iyseps1_1 (%d-%d = %d) muss ein Vielfachesvon " +"MYSUB (%d) sein\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:364 +#, c-format +msgid "" +"\t -> Core region jyseps2_2-jyseps1_1 (%d-%d = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" +"\t -> `Core` Region jyseps2_2-jyseps1_1 (%d-%d = %d) muss ein Vielfachesvon " +"MYSUB (%d) sein\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:342 +#, c-format +msgid "" +"\t -> Core region jyseps2_2-jyseps1_2 (%d-%d = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" +"\t -> `Core` Region jyseps2_2-jyseps1_2 (%d-%d = %d) muss ein Vielfacesvon " +"MYSUB (%d) sein\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:377 +msgid "\t -> Good value\n" +msgstr "\t -> Wert OK\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:326 +#, c-format +msgid "\t -> Leg region jyseps1_1+1 (%d) must be a multiple of MYSUB (%d)\n" +msgstr "" +"\t -> `Leg` Region jyseps1_1+1 (%d) muss ein Vielfaches von MYSUB (%d) sein\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:356 +#, c-format +msgid "" +"\t -> leg region jyseps1_2-ny_inner+1 (%d-%d+1 = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" +"\t -> `Leg` Region jyseps1_2-ny_inner+1 (%d-%d+1 = %d) muss ein Vielfaches " +"von MYSUB (%d) sein\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:372 +#, c-format +msgid "" +"\t -> leg region ny-jyseps2_2-1 (%d-%d-1 = %d) must be a multiple of MYSUB " +"(%d)\n" +msgstr "" +"\t -> `Leg` Region ny-jyseps2_2-1 (%d-%d-1 = %d) muss ein Vielfaches von " +"MYSUB (%d) sein\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:350 +#, c-format +msgid "" +"\t -> leg region ny_inner-jyseps2_1-1 (%d-%d-1 = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" +"\t -> `Leg` Region ny_inner-jyseps2_1-1 (%d-%d-1 = %d) muss ein Vielfaches " +"von MYSUB (%d) sein\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:319 +#, c-format +msgid "\t -> ny/NYPE (%d/%d = %d) must be >= MYG (%d)\n" +msgstr "\t -> ny/NYPE (%d/%d = %d) muss >= MYG (%d) sein\n" + +#. Loop over all possibilities +#. Processors divide equally +#. Mesh in X divides equally +#. Mesh in Y divides equally +#: ../src/mesh/impls/bout/boutmesh.cxx:312 +#, c-format +msgid "\tCandidate value: %d\n" +msgstr "\tMöglicher Wert: %d\n" + +#: ../src/bout++.cxx:387 +msgid "\tChecking disabled\n" +msgstr "\tChecks deaktiviert\n" + +#: ../src/bout++.cxx:385 +#, c-format +msgid "\tChecking enabled, level %d\n" +msgstr "\tChecks aktiviert, Stufe %d\n" + +#. Print command line options +#: ../src/bout++.cxx:431 +msgid "\tCommand line options for this run : " +msgstr "\tBefehlszeilen Optionen für diese Ausführung: " + +#. The stringify is needed here as BOUT_FLAGS_STRING may already contain quoted strings +#. which could cause problems (e.g. terminate strings). +#: ../src/bout++.cxx:428 +#, c-format +msgid "\tCompiled with flags : %s\n" +msgstr "\tKompiliert mit den Optionen : %s\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:391 +#, c-format +msgid "" +"\tDomain split (NXPE=%d, NYPE=%d) into domains (localNx=%d, localNy=%d)\n" +msgstr "" +"\tDie Region wird in NXPE=%d mal NYPE=%d gebiete der Größe localNx=%d mal " +"localNy=%d aufgeteilt\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:416 +#, c-format +msgid "\tERROR: Cannot split %d Y points equally between %d processors\n" +msgstr "" +"\tFEHLER: %d Punkte in der Y-Richtung können nicht gleichmässig zwischen %d " +"Prozessen verteilt werden\n" + +#: ../src/sys/options/options_ini.cxx:173 +#, c-format +msgid "" +"\tEmpty key\n" +"\tLine: %s" +msgstr "" +"\tUngesetzter Schlüssel (Key)\n" +"\tZeile: %s" + +#: ../src/sys/optionsreader.cxx:140 +#, c-format +msgid "\tEmpty key or value in command line '%s'\n" +msgstr "\tSchlüssel (Key) oder Wert nicht gesetzt in der Befehlszeile '%s'\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:127 +msgid "\tGrid size: " +msgstr "\tGittergröße: " + +#: ../src/mesh/impls/bout/boutmesh.cxx:143 +msgid "\tGuard cells (x,y): " +msgstr "\tGuardzellen (x,y): " + +#: ../src/sys/options/options_ini.cxx:177 +#, c-format +msgid "" +"\tKey must not contain ':' character\n" +"\tLine: %s" +msgstr "" +"\tDer Schlüssel darf nicht ':' enthaleten\n" +"\tZeile: %s" + +#: ../src/sys/optionsreader.cxx:127 +#, c-format +msgid "\tMultiple '=' in command-line argument '%s'\n" +msgstr "\t'=' darf nicht mehrfach vorkommen: '%s'\n" + +#: ../src/bout++.cxx:415 +msgid "\tOpenMP parallelisation disabled\n" +msgstr "\tOpenMP Parallelisierung deaktiviert\n" + +#: ../src/bout++.cxx:413 +#, c-format +msgid "\tOpenMP parallelisation enabled, using %d threads\n" +msgstr "\tOpenMP Parallelisierung aktiviert mit %d Threads\n" + +#. Mark the option as used +#. Option not found +#: ../include/options.hxx:298 ../include/options.hxx:319 +#: ../src/sys/options.cxx:136 ../src/sys/options.cxx:172 +#: ../src/sys/options.cxx:200 ../src/sys/options.cxx:221 +#: ../src/sys/options.cxx:224 +msgid "\tOption " +msgstr "\tOption " + +#: ../src/sys/options.cxx:97 +#, c-format +msgid "" +"\tOption %s = %s (%s) overwritten with:\n" +"\t\t%s = %s (%s)\n" +msgstr "" +"\tOption %s = %s (%s) mit\n" +"\t\t%s = %s (%s) überschrieben\n" + +#: ../src/sys/options.cxx:226 +#, c-format +msgid "\tOption '%s': Boolean expected. Got '%s'\n" +msgstr "\tOption '%s': Boolscherwert erwartet, aber '%s' gefunden\n" + +#: ../src/sys/options/options_ini.cxx:74 +#, c-format +msgid "\tOptions file '%s' not found\n" +msgstr "\tDie Optionendatei '%s' konnte nicht gefunden werden\n" + +#: ../src/bout++.cxx:409 +msgid "\tParallel NetCDF support disabled\n" +msgstr "\tParallele-NetCDF unterstützung deaktiviert\n" + +#: ../src/bout++.cxx:407 +msgid "\tParallel NetCDF support enabled\n" +msgstr "\tParllele-NetCDF Unterstützung aktiviert\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:124 +msgid "\tRead nz from input grid file\n" +msgstr "\tnz wird von der Griddatei gelesen\n" + +#: ../src/mesh/mesh.cxx:124 +msgid "\tReading contravariant vector " +msgstr "\tContravariantevektoren werden gelesen " + +#: ../src/mesh/mesh.cxx:117 ../src/mesh/mesh.cxx:138 +msgid "\tReading covariant vector " +msgstr "\tCovariantevektoren werden gelesen " + +#: ../src/bout++.cxx:393 +msgid "\tSignal handling disabled\n" +msgstr "\tSignalhandler deaktiviert\n" + +#: ../src/bout++.cxx:391 +msgid "\tSignal handling enabled\n" +msgstr "\tSignalhandler aktiviert\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:858 +msgid "\tdone\n" +msgstr "\tfertig\n" + +#: ../src/bout++.cxx:402 +msgid "\tnetCDF support disabled\n" +msgstr "\tNetCDF Unterstützung deaktiviert\n" + +#: ../src/bout++.cxx:397 +msgid "\tnetCDF support enabled\n" +msgstr "\tNetCDF Unterstützung aktiviert\n" + +#: ../src/bout++.cxx:400 +msgid "\tnetCDF4 support enabled\n" +msgstr "\tNetCDF4 Unterstützung aktiviert\n" + +#: ../src/bout++.cxx:166 +#, c-format +msgid "" +"\n" +" -d \tLook in for input/output files\n" +" -f \tUse OPTIONS given in \n" +" -o \tSave used OPTIONS given to \n" +" -l, --log \tPrint log to \n" +" -v, --verbose\t\tIncrease verbosity\n" +" -q, --quiet\t\tDecrease verbosity\n" +msgstr "" +"\n" +" -d \tEin- und Ausgabedateien sind im \n" +" -f \tOptinen werden aus der gelesen\n" +" -o \tDie genutzten Optionen werden in der " +" gespeichert\n" +" -l, --log \tSchreibe das Log in die \n" +" -v, --verbose\t\tWortreicherer Ausgabe\n" +" -q, --quiet\t\tNur wichtigere Ausgaben anzeigen\n" + +#: ../src/solver/solver.cxx:563 +#, c-format +msgid "" +"\n" +"Run finished at : %s\n" +msgstr "" +"\n" +"Simulation beendet um %s\n" + +#: ../src/solver/solver.cxx:534 +#, c-format +msgid "" +"\n" +"Run started at : %s\n" +msgstr "" +"\n" +"Simulation gestartet um %s\n" + +#: ../src/bout++.cxx:175 +#, c-format +msgid " -c, --color\t\tColor output using bout-log-color\n" +msgstr " -c, --color\t\tFarbliche Ausgabe mit bout-log-color\n" + +#: ../src/bout++.cxx:178 +#, c-format +msgid "" +" -h, --help\t\tThis message\n" +" restart [append]\tRestart the simulation. If append is specified, append " +"to the existing output files, otherwise overwrite them\n" +" VAR=VALUE\t\tSpecify a VALUE for input parameter VAR\n" +"\n" +"For all possible input parameters, see the user manual and/or the physics " +"model source (e.g. %s.cxx)\n" +msgstr "" +" -h, --help\t\tDiese Information\n" +" restart \t\tDie Simulation fortsetzen.\n" +" append \t\tDie dump Dateien weiter schreiben, ansonsten werden sie " +"Überschrieben. Benötigt `restart`\n" +" VAR=WERT \t\tSetzt den Wert WERT für die Variable VAR\n" +"\n" +"Weitere Eingabeparameter sind in dem Manual und dem Quellcode (z.B. %s.cxx) " +"des Physikmoduls definiert.\n" + +#: ../src/sys/options.cxx:248 +msgid "All options used\n" +msgstr "Alle genutzten Optionen\n" + +#. / Print intro +#: ../src/bout++.cxx:365 +#, c-format +msgid "BOUT++ version %s\n" +msgstr "BOUT++ Version %s\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:828 +msgid "Boundary regions in this processor: " +msgstr "Randbedingungsgegenden auf diesem Prozessor: " + +#: ../src/mesh/impls/bout/boutmesh.cxx:407 +#, c-format +msgid "Cannot split %d X points equally between %d processors\n" +msgstr "" +"%d Punkte in der X-Richtung können nicht gleichmässig zwischen %d Prozessen " +"verteilt werden\n" + +#: ../src/bout++.cxx:372 +#, c-format +msgid "" +"Code compiled on %s at %s\n" +"\n" +msgstr "" +"Der Code wurde auf %s um %s kompiliert\n" +"\n" + +#: ../src/sys/optionsreader.cxx:142 +msgid "Command line" +msgstr "Befehlszeile" + +#. / Print compile-time options +#: ../src/bout++.cxx:382 +msgid "Compile-time options:\n" +msgstr "Kompilierzeit Optionen:\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:837 +msgid "Constructing default regions" +msgstr "Standardregionen werden erstellt" + +#: ../src/mesh/impls/bout/boutmesh.cxx:385 +msgid "" +"Could not find a valid value for NXPE. Try a different number of processors." +msgstr "" +"Es konnte kein geeigneter Anzahl an Prozesooren in X Richtung gefunden " +"werden (NXPE). Versuche es mit einer anderen Zahl an Prozessoren." + +#: ../src/sys/options/options_ini.cxx:132 +#, c-format +msgid "Could not open output file '%s'\n" +msgstr "Die Ausgabedatei '%s' konnte nicht geöffnet werden\n" + +#. Error reading +#: ../src/mesh/mesh.cxx:278 +#, c-format +msgid "Could not read integer array '%s'\n" +msgstr "Der Ganzzahlen-Array '%s' konnte nicht gelesen werden\n" + +#. Failed . Probably not important enough to stop the simulation +#: ../src/bout++.cxx:324 +#, c-format +msgid "Could not run bout-log-color. Make sure it is in your PATH\n" +msgstr "" +"Der Befehl 'bout-log-color' konnte nicht ausgeführt werden. Stellen sie " +"sicher das er sich in $PATH befindet.\n" + +#: ../src/solver/solver.cxx:642 +#, c-format +msgid "Couldn't add Monitor: %g is not a multiple of %g!" +msgstr "" +"Der 'Monitor' konnte nicht hinzugefügt werden: %g ist nicht ein Vielfaches " +"von %g!" + +#: ../src/mesh/mesh.cxx:349 +#, c-format +msgid "Couldn't find region %s in regionMap2D" +msgstr "Die Region '%s' ist nicht in regionMap2D" + +#: ../src/mesh/mesh.cxx:341 +#, c-format +msgid "Couldn't find region %s in regionMap3D" +msgstr "Die Region '%s' ist nicht in regionMap3D" + +#: ../src/mesh/mesh.cxx:357 +#, c-format +msgid "Couldn't find region %s in regionMapPerp" +msgstr "Die Region '%s' ist nicht in regionMapPerp" + +#: ../src/sys/options.cxx:192 +#, c-format +msgid "Couldn't get BoutReal from option %s = '%s'" +msgstr "" +"Die Option %s = '%s' konnte nicht als Gleitkommazahl interpretiert werden." + +#: ../src/sys/options.cxx:156 +#, c-format +msgid "Couldn't get integer from option %s = '%s'" +msgstr "Die Option %s = '%s' konnte nicht als ganze Zahl interpretiert werden." + +#: ../src/bout++.cxx:281 +#, c-format +msgid "DataDir \"%s\" does not exist or is not accessible\n" +msgstr "Der Datenordner \"%s\" existiert nicht oder ist nicht lesbar\n" + +#: ../src/bout++.cxx:278 +#, c-format +msgid "DataDir \"%s\" is not a directory\n" +msgstr "\"%s\" soll als Datenordner verwendet werden, ist jedoch kein Ordner\n" + +#: ../src/solver/solver.cxx:597 +msgid "ERROR: Solver is already initialised\n" +msgstr "FEHLER: Der Integrator ist bereit initialisiert.\n" + +#: ../src/bout++.cxx:470 +msgid "Error encountered during initialisation\n" +msgstr "Es wurde ein Fehler während der Initialisierung bemerkt\n" + +#: ../src/bout++.cxx:515 +#, c-format +msgid "Error encountered during initialisation: %s\n" +msgstr "Es wurde ein Fehler während der Initialisierung bemerkt: %s\n" + +#: ../src/bout++.cxx:554 +msgid "Error whilst writing settings" +msgstr "Es wurde ein Fehler beim schreiben der Einstellungsdatei bemerkt" + +#: ../src/mesh/impls/bout/boutmesh.cxx:147 +#, c-format +msgid "Error: nx must be greater than 2 times MXG (2 * %d)" +msgstr "Fehler: nx muss größer als 2 mal MXG sein (2 * %d)" + +#: ../src/solver/solver.cxx:526 +msgid "Failed to initialise solver-> Aborting\n" +msgstr "Der Integrator konnte nicht initialisiert werden.\n" + +#. Best option +#. Results in square domains +#: ../src/mesh/impls/bout/boutmesh.cxx:305 +#, c-format +msgid "Finding value for NXPE (ideal = %f)\n" +msgstr "Suche NXPE Wert (optimal = %f)\n" + +#: ../src/solver/solver.cxx:599 +msgid "Initialising solver\n" +msgstr "Integrator wird initialisiert\n" + +#: ../src/bout++.cxx:270 +msgid "" +"Input and output file for settings must be different.\n" +"Provide -o to avoid this issue.\n" +msgstr "" +"Optionendatei (Eingabe) und Einstellungsdatei (Ausgabe) müssen verschieden " +"sein.\n" +"Verwende -o .\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:91 +msgid "Loading mesh" +msgstr "Lade das Gitter" + +#: ../src/mesh/impls/bout/boutmesh.cxx:106 +msgid "Mesh must contain nx" +msgstr "Das Gitter muss nx enthalten" + +#: ../src/mesh/impls/bout/boutmesh.cxx:109 +msgid "Mesh must contain ny" +msgstr "Das Gitter muss ny enthalten" + +#. Not found +#: ../src/mesh/mesh.cxx:282 +#, c-format +msgid "Missing integer array %s\n" +msgstr "Ganzzahlen-Array '%s' nicht gesetzt\n" + +#: ../src/solver/solver.cxx:696 ../src/solver/solver.cxx:703 +msgid "Monitor signalled to quit\n" +msgstr "Der Monitor signaliserte die Beendigung\n" + +#: ../src/mesh/impls/bout/boutmesh.cxx:834 +msgid "No boundary regions in this processor" +msgstr "Keine Randbedingungsregionen auf deisem Prozessor" + +#: ../src/mesh/impls/bout/boutmesh.cxx:235 +#, c-format +msgid "Number of processors (%d) not divisible by NPs in x direction (%d)\n" +msgstr "" +"Anzahl an Prozessoren (%d) nicht teilbar durch Anzahl in x Richtung (%d)\n" + +#. Less than 1 time-step left +#: ../src/bout++.cxx:704 +#, c-format +msgid "Only %e seconds left. Quitting\n" +msgstr "Nur noch %e Sekunden verfügbar. Abbruch\n" + +#: ../src/sys/options.cxx:130 ../src/sys/options.cxx:148 +#: ../src/sys/options.cxx:184 ../src/sys/options.cxx:212 +#, c-format +msgid "Option %s has no value" +msgstr "Der Option '%s' wurde kein Wert zugewiesen" + +#: ../src/sys/options.cxx:59 +#, c-format +msgid "Option %s is not a section" +msgstr "Die Option '%s' ist keine Gruppierung" + +#. Doesn't exist +#: ../src/sys/options.cxx:70 +#, c-format +msgid "Option %s:%s does not exist" +msgstr "Die Option %s:%s exisitiert nicht" + +#: ../src/sys/options.cxx:101 +#, c-format +msgid "" +"Options: Setting a value from same source (%s) to new value '%s' - old value " +"was '%s'." +msgstr "" +"Optionen: Es wird der Wert %3$s mit dem Wert %2$s gleichen Ursprungs (%1$s) " +"überschrieben." + +#: ../src/bout++.cxx:376 +#, c-format +msgid "" +"Processor number: %d of %d\n" +"\n" +msgstr "" +"Prozessor Number: %d von %d\n" +"\n" + +#: ../src/mesh/mesh.cxx:388 +#, c-format +msgid "Registered region 2D %s" +msgstr "2D Region '%s' hinzugefügt" + +#: ../src/mesh/mesh.cxx:379 +#, c-format +msgid "Registered region 3D %s" +msgstr "3D Region '%s' hinzugefügt" + +#: ../src/mesh/mesh.cxx:397 +#, c-format +msgid "Registered region Perp %s" +msgstr "Perp Region '%s' hinzugefügt" + +#: ../src/bout++.cxx:367 +#, c-format +msgid "Revision: %s\n" +msgstr "Revision: %s\n" + +#: ../src/solver/solver.cxx:564 +msgid "Run time : " +msgstr "Dauer: " + +#. / Run the solver +#: ../src/solver/solver.cxx:531 +msgid "" +"Running simulation\n" +"\n" +msgstr "" +"Starte die Simulation\n" +"\n" + +#: ../src/bout++.cxx:665 +msgid "" +"Sim Time | RHS evals | Wall Time | Calc Inv Comm I/O SOLVER\n" +"\n" +msgstr "" +"Simu Zeit | RHS Berech. | Tot. Zeit | Rechnen Inver Komm I/O " +"Integrator\n" +"\n" + +#: ../src/bout++.cxx:668 +msgid "" +"Sim Time | RHS_e evals | RHS_I evals | Wall Time | Calc Inv " +"Comm I/O SOLVER\n" +"\n" +msgstr "" +"Sim Zeit | #expl RHS | #impl RHS | Echtdauer | Berech Inv " +"Komm I/O Integrator\n" +"\n" + +#: ../src/solver/solver.cxx:521 +#, c-format +msgid "Solver running for %d outputs with monitor timestep of %e\n" +msgstr "" +"Integriere %d `Monitor`-Aufrufe mit einem `Monitor`-Zeitschritt von %e\n" + +#: ../src/solver/solver.cxx:519 +#, c-format +msgid "Solver running for %d outputs with output timestep of %e\n" +msgstr "Integriere %d Zeitschritte von je %e\n" + +#: ../src/solver/solver.cxx:648 +#, c-format +msgid "" +"Solver::addMonitor: Cannot reduce timestep (from %g to %g) after init is " +"called!" +msgstr "" +"Der Integrator kann den Zeitschritt nicht von %g auf %g reduzieren, nachdem " +"er initialisiert wurde!" + +#: ../src/solver/solver.cxx:1061 +#, c-format +msgid "" +"Time derivative at wrong location - Field is at %s, derivative is at %s for " +"field '%s'\n" +msgstr "" +"Die zeitliche Ableitung ist an der falschen Stelle. Das Feld '%3$s' ist an " +"Position %1$s während die Ableitung an Position %2$s ist.\n" + +#: ../src/solver/solver.cxx:1267 +#, c-format +msgid "Time derivative for variable '%s' not set" +msgstr "Zeitliche Ableitung für Variable '%s' nicht gesetzt" + +#: ../src/mesh/mesh.cxx:385 +#, c-format +msgid "Trying to add an already existing region %s to regionMap2D" +msgstr "Die Region '%s' existiert schon in der regionMap2D" + +#: ../src/mesh/mesh.cxx:376 +#, c-format +msgid "Trying to add an already existing region %s to regionMap3D" +msgstr "Die Region '%s' existiert schon in der regionMap3D" + +#: ../src/mesh/mesh.cxx:394 +#, c-format +msgid "Trying to add an already existing region %s to regionMapPerp" +msgstr "Die Region '%s' existiert schon in der regionMapPerp" + +#: ../src/mesh/mesh.cxx:313 +msgid "" +"Unrecognised paralleltransform option.\n" +"Valid choices are 'identity', 'shifted', 'fci'" +msgstr "" +"Unbekannte ParalleleTransormation\n" +"Gültige Optionen sind 'identity', 'shifted', 'fci'" + +#: ../src/sys/options.cxx:250 +msgid "Unused options:\n" +msgstr "Ungenutzte Optionen:\n" + +#: ../src/bout++.cxx:202 +#, c-format +msgid "Usage is %s -d \n" +msgstr "Benutzung: %s -d \n" + +#: ../src/bout++.cxx:214 +#, c-format +msgid "Usage is %s -f \n" +msgstr "Benutzung: %s -f \n" + +#: ../src/bout++.cxx:237 +#, c-format +msgid "Usage is %s -l \n" +msgstr "Benutzung: %s -f \n" + +#: ../src/bout++.cxx:226 +#, c-format +msgid "Usage is %s -o \n" +msgstr "Benutzung: %s -f \n" + +#. Print help message -- note this will be displayed once per processor as we've not started MPI yet. +#: ../src/bout++.cxx:164 +#, c-format +msgid "" +"Usage: %s [-d ] [-f ] [restart [append]] " +"[VAR=VALUE]\n" +msgstr "" +"Benutzung: %s [-d ] [-f ] [restart [append]] " +"[VAR=WERT]\n" + +#: ../src/sys/options.cxx:166 +#, c-format +msgid "Value for option %s = %e is not an integer" +msgstr "Wert der Option %s = %e ist keine Ganzzahl" + +#: ../src/solver/solver.cxx:1020 ../src/solver/solver.cxx:1024 +#, c-format +msgid "Variable '%s' not initialised" +msgstr "Variable '%s' ist nicht initialisiert" + +#. Should be a power of 2 for efficient FFTs +#: ../src/mesh/impls/bout/boutmesh.cxx:119 +msgid "" +"WARNING: Number of toroidal points should be 2^n for efficient FFT " +"performance -- consider changing MZ if using FFTs\n" +msgstr "" +"Anzahl der toroidalen Punkte sollte 2^n für effiziente FFTs sein. Ändere MZ " +"falls FFTs verwendet werden\n" + +#: ../src/sys/optionsreader.cxx:60 +#, c-format +msgid "Writing options to file %s\n" +msgstr "Optionen werden in %s gespeichert\n" + +#. / The source label given to default values +#: ../src/sys/options.cxx:11 +msgid "default" +msgstr "Vorgabe" + +#: ../src/mesh/impls/bout/boutmesh.cxx:156 +msgid "nx must be greater than 2*MXG" +msgstr "nx muss größer als 2*MXG sein" + +#, fuzzy +#~ msgid ") overwritten with:" +#~ msgstr ") überschrieben mit %s" + +#~ msgid "Monitor signalled to quit" +#~ msgstr "Der Monitor signaliserte die Beendigung" From e0323ebd2c250dd6255518eb7d562f3f839c2afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Wed, 6 Feb 2019 18:00:22 +0000 Subject: [PATCH 0714/1783] Put debug info in error message --- examples/make-script/makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/make-script/makefile b/examples/make-script/makefile index cc76a53288..36e029d2ef 100644 --- a/examples/make-script/makefile +++ b/examples/make-script/makefile @@ -13,9 +13,8 @@ TARGET ?= $(SOURCEC:%.cxx=%) CXX:=$(shell bout-config --cxx) ifneq "$(.SHELLSTATUS)" "0" -which=$(shell which bout-config) -$(info Output of which bout-config: $(which)) -$(error Failed to run bout-config.) +which=$(shell which bout-config 2>&1 ) +$(error Is bout-config in $$PATH? $(which)) endif CFLAGS:=$(shell bout-config --cflags) From 2f313dc4b3785450eae7c30a9643dad6899c640c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 6 Feb 2019 20:16:41 +0000 Subject: [PATCH 0715/1783] Update name pf helper function --- tests/unit/include/test_derivs.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index 0fd4a24a45..65f0fc503a 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -299,5 +299,5 @@ TEST_P(DerivativesTestAdvection, Sanity) { derivative(velocity, input, result, region); EXPECT_TRUE( - IsField3DEqualField3D(result, expected, "RGN_NOBNDRY", derivatives_tolerance)); + IsFieldEqual(result, expected, "RGN_NOBNDRY", derivatives_tolerance)); } From bcb437e670b3381e3f5bce427850a177b28afa7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 7 Feb 2019 08:51:06 +0000 Subject: [PATCH 0716/1783] Improve translation --- locale/de/libbout.po | 88 ++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/locale/de/libbout.po b/locale/de/libbout.po index 109d394322..cb36753027 100644 --- a/locale/de/libbout.po +++ b/locale/de/libbout.po @@ -24,7 +24,7 @@ msgid "" "\t -> Core region jyseps2_1-jyseps1_1 (%d-%d = %d) must be a multiple of " "MYSUB (%d)\n" msgstr "" -"\t -> `Core` Region iyseps2_1-iyseps1_1 (%d-%d = %d) muss ein Vielfachesvon " +"\t -> `Core` Region iyseps2_1-iyseps1_1 (%d-%d = %d) muss ein Vielfaches von " "MYSUB (%d) sein\n" #: ../src/mesh/impls/bout/boutmesh.cxx:364 @@ -33,7 +33,7 @@ msgid "" "\t -> Core region jyseps2_2-jyseps1_1 (%d-%d = %d) must be a multiple of " "MYSUB (%d)\n" msgstr "" -"\t -> `Core` Region jyseps2_2-jyseps1_1 (%d-%d = %d) muss ein Vielfachesvon " +"\t -> `Core` Region jyseps2_2-jyseps1_1 (%d-%d = %d) muss ein Vielfaches von " "MYSUB (%d) sein\n" #: ../src/mesh/impls/bout/boutmesh.cxx:342 @@ -42,7 +42,7 @@ msgid "" "\t -> Core region jyseps2_2-jyseps1_2 (%d-%d = %d) must be a multiple of " "MYSUB (%d)\n" msgstr "" -"\t -> `Core` Region jyseps2_2-jyseps1_2 (%d-%d = %d) muss ein Vielfacesvon " +"\t -> `Core` Region jyseps2_2-jyseps1_2 (%d-%d = %d) muss ein Vielfaches von " "MYSUB (%d) sein\n" #: ../src/mesh/impls/bout/boutmesh.cxx:377 @@ -94,7 +94,7 @@ msgstr "\t -> ny/NYPE (%d/%d = %d) muss >= MYG (%d) sein\n" #: ../src/mesh/impls/bout/boutmesh.cxx:312 #, c-format msgid "\tCandidate value: %d\n" -msgstr "\tMöglicher Wert: %d\n" +msgstr "\tzu überprüfender Wert: %d\n" #: ../src/bout++.cxx:387 msgid "\tChecking disabled\n" @@ -108,21 +108,21 @@ msgstr "\tChecks aktiviert, Stufe %d\n" #. Print command line options #: ../src/bout++.cxx:431 msgid "\tCommand line options for this run : " -msgstr "\tBefehlszeilen Optionen für diese Ausführung: " +msgstr "\tKommandozeilenoptionen für diese Ausführung: " #. The stringify is needed here as BOUT_FLAGS_STRING may already contain quoted strings #. which could cause problems (e.g. terminate strings). #: ../src/bout++.cxx:428 #, c-format msgid "\tCompiled with flags : %s\n" -msgstr "\tKompiliert mit den Optionen : %s\n" +msgstr "\tWurde kompiliert mit den Optionen : %s\n" #: ../src/mesh/impls/bout/boutmesh.cxx:391 #, c-format msgid "" "\tDomain split (NXPE=%d, NYPE=%d) into domains (localNx=%d, localNy=%d)\n" msgstr "" -"\tDie Region wird in NXPE=%d mal NYPE=%d gebiete der Größe localNx=%d mal " +"\tDas Gebiet wird in NXPE=%d mal NYPE=%d Gebiete der Größe localNx=%d mal " "localNy=%d aufgeteilt\n" #: ../src/mesh/impls/bout/boutmesh.cxx:416 @@ -160,7 +160,7 @@ msgid "" "\tKey must not contain ':' character\n" "\tLine: %s" msgstr "" -"\tDer Schlüssel darf nicht ':' enthaleten\n" +"\tDer Schlüssel darf nicht ':' enthalten\n" "\tZeile: %s" #: ../src/sys/optionsreader.cxx:127 @@ -192,13 +192,13 @@ msgid "" "\tOption %s = %s (%s) overwritten with:\n" "\t\t%s = %s (%s)\n" msgstr "" -"\tOption %s = %s (%s) mit\n" +"\tOption %s = %s (%s) wird mit\n" "\t\t%s = %s (%s) überschrieben\n" #: ../src/sys/options.cxx:226 #, c-format msgid "\tOption '%s': Boolean expected. Got '%s'\n" -msgstr "\tOption '%s': Boolscherwert erwartet, aber '%s' gefunden\n" +msgstr "\tOption '%s': Boolscherwert erwartet, '%s' gefunden\n" #: ../src/sys/options/options_ini.cxx:74 #, c-format @@ -207,11 +207,11 @@ msgstr "\tDie Optionendatei '%s' konnte nicht gefunden werden\n" #: ../src/bout++.cxx:409 msgid "\tParallel NetCDF support disabled\n" -msgstr "\tParallele-NetCDF unterstützung deaktiviert\n" +msgstr "\tParallele-NetCDF Unterstützung ist deaktiviert\n" #: ../src/bout++.cxx:407 msgid "\tParallel NetCDF support enabled\n" -msgstr "\tParllele-NetCDF Unterstützung aktiviert\n" +msgstr "\tParllele-NetCDF Unterstützung ist aktiviert\n" #: ../src/mesh/impls/bout/boutmesh.cxx:124 msgid "\tRead nz from input grid file\n" @@ -219,19 +219,19 @@ msgstr "\tnz wird von der Griddatei gelesen\n" #: ../src/mesh/mesh.cxx:124 msgid "\tReading contravariant vector " -msgstr "\tContravariantevektoren werden gelesen " +msgstr "\tKontravariantevektoren werden gelesen " #: ../src/mesh/mesh.cxx:117 ../src/mesh/mesh.cxx:138 msgid "\tReading covariant vector " -msgstr "\tCovariantevektoren werden gelesen " +msgstr "\tKovariantevektoren werden gelesen " #: ../src/bout++.cxx:393 msgid "\tSignal handling disabled\n" -msgstr "\tSignalhandler deaktiviert\n" +msgstr "\tSignalverarbeitung deaktiviert\n" #: ../src/bout++.cxx:391 msgid "\tSignal handling enabled\n" -msgstr "\tSignalhandler aktiviert\n" +msgstr "\tSignalverarbeitung aktiviert\n" #: ../src/mesh/impls/bout/boutmesh.cxx:858 msgid "\tdone\n" @@ -263,7 +263,7 @@ msgstr "" "\n" " -d \tEin- und Ausgabedateien sind im \n" " -f \tOptinen werden aus der gelesen\n" -" -o \tDie genutzten Optionen werden in der " +" -o \tGenutzte Optionen werden in der " " gespeichert\n" " -l, --log \tSchreibe das Log in die \n" " -v, --verbose\t\tWortreicherer Ausgabe\n" @@ -306,7 +306,7 @@ msgstr "" " -h, --help\t\tDiese Information\n" " restart \t\tDie Simulation fortsetzen.\n" " append \t\tDie dump Dateien weiter schreiben, ansonsten werden sie " -"Überschrieben. Benötigt `restart`\n" +"überschrieben. Benötigt `restart`\n" " VAR=WERT \t\tSetzt den Wert WERT für die Variable VAR\n" "\n" "Weitere Eingabeparameter sind in dem Manual und dem Quellcode (z.B. %s.cxx) " @@ -324,7 +324,7 @@ msgstr "BOUT++ Version %s\n" #: ../src/mesh/impls/bout/boutmesh.cxx:828 msgid "Boundary regions in this processor: " -msgstr "Randbedingungsgegenden auf diesem Prozessor: " +msgstr "Randgebiete auf diesem Prozessor: " #: ../src/mesh/impls/bout/boutmesh.cxx:407 #, c-format @@ -349,7 +349,7 @@ msgstr "Befehlszeile" #. / Print compile-time options #: ../src/bout++.cxx:382 msgid "Compile-time options:\n" -msgstr "Kompilierzeit Optionen:\n" +msgstr "Kompiliert mit:\n" #: ../src/mesh/impls/bout/boutmesh.cxx:837 msgid "Constructing default regions" @@ -359,7 +359,7 @@ msgstr "Standardregionen werden erstellt" msgid "" "Could not find a valid value for NXPE. Try a different number of processors." msgstr "" -"Es konnte kein geeigneter Anzahl an Prozesooren in X Richtung gefunden " +"Es konnte keine gültige Anzahl an Prozessoren in X Richtung gefunden " "werden (NXPE). Versuche es mit einer anderen Zahl an Prozessoren." #: ../src/sys/options/options_ini.cxx:132 @@ -378,14 +378,14 @@ msgstr "Der Ganzzahlen-Array '%s' konnte nicht gelesen werden\n" #, c-format msgid "Could not run bout-log-color. Make sure it is in your PATH\n" msgstr "" -"Der Befehl 'bout-log-color' konnte nicht ausgeführt werden. Stellen sie " -"sicher das er sich in $PATH befindet.\n" +"Der Befehl 'bout-log-color' konnte nicht ausgeführt werden. Stellen Sie " +"sicher, dass er sich in $PATH befindet.\n" #: ../src/solver/solver.cxx:642 #, c-format msgid "Couldn't add Monitor: %g is not a multiple of %g!" msgstr "" -"Der 'Monitor' konnte nicht hinzugefügt werden: %g ist nicht ein Vielfaches " +"'Monitor' konnte nicht hinzugefügt werden: %g ist nicht ein Vielfaches " "von %g!" #: ../src/mesh/mesh.cxx:349 @@ -426,20 +426,20 @@ msgstr "\"%s\" soll als Datenordner verwendet werden, ist jedoch kein Ordner\n" #: ../src/solver/solver.cxx:597 msgid "ERROR: Solver is already initialised\n" -msgstr "FEHLER: Der Integrator ist bereit initialisiert.\n" +msgstr "FEHLER: Der Integrator ist bereits initialisiert.\n" #: ../src/bout++.cxx:470 msgid "Error encountered during initialisation\n" -msgstr "Es wurde ein Fehler während der Initialisierung bemerkt\n" +msgstr "Es wurde ein Fehler während der Initialisierung gefunden\n" #: ../src/bout++.cxx:515 #, c-format msgid "Error encountered during initialisation: %s\n" -msgstr "Es wurde ein Fehler während der Initialisierung bemerkt: %s\n" +msgstr "Es wurde ein Fehler während der Initialisierung gefunden: %s\n" #: ../src/bout++.cxx:554 msgid "Error whilst writing settings" -msgstr "Es wurde ein Fehler beim schreiben der Einstellungsdatei bemerkt" +msgstr "Es wurde ein Fehler beim Schreiben der Einstellungsdatei gefunden" #: ../src/mesh/impls/bout/boutmesh.cxx:147 #, c-format @@ -448,7 +448,7 @@ msgstr "Fehler: nx muss größer als 2 mal MXG sein (2 * %d)" #: ../src/solver/solver.cxx:526 msgid "Failed to initialise solver-> Aborting\n" -msgstr "Der Integrator konnte nicht initialisiert werden.\n" +msgstr "Der Integrator konnte nicht initialisiert werden. Der Prozess wird abgebrochen\n" #. Best option #. Results in square domains @@ -459,7 +459,7 @@ msgstr "Suche NXPE Wert (optimal = %f)\n" #: ../src/solver/solver.cxx:599 msgid "Initialising solver\n" -msgstr "Integrator wird initialisiert\n" +msgstr "initialisiere den Integrator\n" #: ../src/bout++.cxx:270 msgid "" @@ -490,11 +490,11 @@ msgstr "Ganzzahlen-Array '%s' nicht gesetzt\n" #: ../src/solver/solver.cxx:696 ../src/solver/solver.cxx:703 msgid "Monitor signalled to quit\n" -msgstr "Der Monitor signaliserte die Beendigung\n" +msgstr "Beendigung durch Monitor\n" #: ../src/mesh/impls/bout/boutmesh.cxx:834 msgid "No boundary regions in this processor" -msgstr "Keine Randbedingungsregionen auf deisem Prozessor" +msgstr "Keine Randregionen auf diesem Prozessor" #: ../src/mesh/impls/bout/boutmesh.cxx:235 #, c-format @@ -531,7 +531,7 @@ msgid "" "Options: Setting a value from same source (%s) to new value '%s' - old value " "was '%s'." msgstr "" -"Optionen: Es wird der Wert %3$s mit dem Wert %2$s gleichen Ursprungs (%1$s) " +"Optionen: Der Wert %3$s wird mit dem Wert %2$s gleichen Ursprungs (%1$s) " "überschrieben." #: ../src/bout++.cxx:376 @@ -540,7 +540,7 @@ msgid "" "Processor number: %d of %d\n" "\n" msgstr "" -"Prozessor Number: %d von %d\n" +"Prozessorennummer: %d von %d\n" "\n" #: ../src/mesh/mesh.cxx:388 @@ -573,7 +573,7 @@ msgid "" "Running simulation\n" "\n" msgstr "" -"Starte die Simulation\n" +"Simulation wird gestartet\n" "\n" #: ../src/bout++.cxx:665 @@ -581,7 +581,7 @@ msgid "" "Sim Time | RHS evals | Wall Time | Calc Inv Comm I/O SOLVER\n" "\n" msgstr "" -"Simu Zeit | RHS Berech. | Tot. Zeit | Rechnen Inver Komm I/O " +"Simu Zeit | RHS Berech. | Echtdauer | Rechnen Inver Komm I/O " "Integrator\n" "\n" @@ -591,7 +591,7 @@ msgid "" "Comm I/O SOLVER\n" "\n" msgstr "" -"Sim Zeit | #expl RHS | #impl RHS | Echtdauer | Berech Inv " +"Simu Zeit | #expl RHS | #impl RHS | Echtdauer | Rechnen Inv " "Komm I/O Integrator\n" "\n" @@ -599,7 +599,7 @@ msgstr "" #, c-format msgid "Solver running for %d outputs with monitor timestep of %e\n" msgstr "" -"Integriere %d `Monitor`-Aufrufe mit einem `Monitor`-Zeitschritt von %e\n" +"Integriere mit einem `Monitor`-Zeitschritt von %2$e für %1$d Aufrufe.\n" #: ../src/solver/solver.cxx:519 #, c-format @@ -622,7 +622,7 @@ msgid "" "field '%s'\n" msgstr "" "Die zeitliche Ableitung ist an der falschen Stelle. Das Feld '%3$s' ist an " -"Position %1$s während die Ableitung an Position %2$s ist.\n" +"Position %1$s, während die Ableitung an Position %2$s ist.\n" #: ../src/solver/solver.cxx:1267 #, c-format @@ -632,24 +632,24 @@ msgstr "Zeitliche Ableitung für Variable '%s' nicht gesetzt" #: ../src/mesh/mesh.cxx:385 #, c-format msgid "Trying to add an already existing region %s to regionMap2D" -msgstr "Die Region '%s' existiert schon in der regionMap2D" +msgstr "Die Region '%s' ist bereits vorhanden in der regionMap2D" #: ../src/mesh/mesh.cxx:376 #, c-format msgid "Trying to add an already existing region %s to regionMap3D" -msgstr "Die Region '%s' existiert schon in der regionMap3D" +msgstr "Die Region '%s' ist bereits vorhanden in der regionMap3D" #: ../src/mesh/mesh.cxx:394 #, c-format msgid "Trying to add an already existing region %s to regionMapPerp" -msgstr "Die Region '%s' existiert schon in der regionMapPerp" +msgstr "Die Region '%s' ist bereits vorhanden in der regionMapPerp" #: ../src/mesh/mesh.cxx:313 msgid "" "Unrecognised paralleltransform option.\n" "Valid choices are 'identity', 'shifted', 'fci'" msgstr "" -"Unbekannte ParalleleTransormation\n" +"Unbekannte Paralleltransformation\n" "Gültige Optionen sind 'identity', 'shifted', 'fci'" #: ../src/sys/options.cxx:250 @@ -702,7 +702,7 @@ msgid "" "WARNING: Number of toroidal points should be 2^n for efficient FFT " "performance -- consider changing MZ if using FFTs\n" msgstr "" -"Anzahl der toroidalen Punkte sollte 2^n für effiziente FFTs sein. Ändere MZ " +"WARNUNG: Anzahl der toroidalen Punkte sollte 2^n für effiziente FFTs sein. Ändere MZ " "falls FFTs verwendet werden\n" #: ../src/sys/optionsreader.cxx:60 From 6733f3d48bb1614bd0c90187f4c9a16134bf6c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 7 Feb 2019 09:37:40 +0000 Subject: [PATCH 0717/1783] Fix expr.hxx --- include/bout/expr.hxx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/bout/expr.hxx b/include/bout/expr.hxx index ef14cb84af..4cbe31cb9f 100644 --- a/include/bout/expr.hxx +++ b/include/bout/expr.hxx @@ -12,6 +12,8 @@ #ifndef __EXPR_H__ #define __EXPR_H__ +#warning expr.hxx is deprecated. Do not use! + #include #include #include @@ -33,7 +35,7 @@ public: typedef Field3D type; Field3DExpr(const Field3D &f) : data(&f(0,0,0)) {} - const BoutReal& operator()(int x, int y, int z) const { return data[(x*mesh->LocalNy + y)*mesh->LocalNz + z]; } + const BoutReal& operator()(int x, int y, int z) const { return data[(x*bout::globals::mesh->LocalNy + y)*bout::globals::mesh->LocalNz + z]; } private: const BoutReal *data; }; @@ -43,7 +45,7 @@ public: typedef Field2D type; Field2DExpr(const Field2D &f) : data(&f(0,0)) {} - const BoutReal& operator()(int x, int y, int z) const { return data[x*mesh->LocalNy + y]; } + const BoutReal& operator()(int x, int y, int z) const { return data[x*bout::globals::mesh->LocalNy + y]; } private: const BoutReal *data; }; @@ -186,9 +188,9 @@ template const Field3D eval3D(Expr e) { Field3D result; result.allocate(); - for(int i=0;iLocalNx;i++) - for(int j=0;jLocalNy;j++) - for(int k=0;kLocalNz;k++) + for(int i=0;iLocalNx;i++) + for(int j=0;jLocalNy;j++) + for(int k=0;kLocalNz;k++) result(i,j,k) = e(i,j,k); return result; } From a0445a8f70ff11245e3469f12a20d445e500892b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 7 Feb 2019 10:41:19 +0000 Subject: [PATCH 0718/1783] Make messages(de) more consistent --- locale/de/libbout.po | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/locale/de/libbout.po b/locale/de/libbout.po index cb36753027..8e1069a418 100644 --- a/locale/de/libbout.po +++ b/locale/de/libbout.po @@ -98,12 +98,12 @@ msgstr "\tzu überprüfender Wert: %d\n" #: ../src/bout++.cxx:387 msgid "\tChecking disabled\n" -msgstr "\tChecks deaktiviert\n" +msgstr "\tChecks sind deaktiviert\n" #: ../src/bout++.cxx:385 #, c-format msgid "\tChecking enabled, level %d\n" -msgstr "\tChecks aktiviert, Stufe %d\n" +msgstr "\tChecks der Stufe %d sind aktiviert\n" #. Print command line options #: ../src/bout++.cxx:431 @@ -170,12 +170,12 @@ msgstr "\t'=' darf nicht mehrfach vorkommen: '%s'\n" #: ../src/bout++.cxx:415 msgid "\tOpenMP parallelisation disabled\n" -msgstr "\tOpenMP Parallelisierung deaktiviert\n" +msgstr "\tOpenMP Parallelisierung ist deaktiviert\n" #: ../src/bout++.cxx:413 #, c-format msgid "\tOpenMP parallelisation enabled, using %d threads\n" -msgstr "\tOpenMP Parallelisierung aktiviert mit %d Threads\n" +msgstr "\tOpenMP Parallelisierung mit %d Threads ist aktiviert\n" #. Mark the option as used #. Option not found @@ -227,11 +227,11 @@ msgstr "\tKovariantevektoren werden gelesen " #: ../src/bout++.cxx:393 msgid "\tSignal handling disabled\n" -msgstr "\tSignalverarbeitung deaktiviert\n" +msgstr "\tSignalverarbeitung ist deaktiviert\n" #: ../src/bout++.cxx:391 msgid "\tSignal handling enabled\n" -msgstr "\tSignalverarbeitung aktiviert\n" +msgstr "\tSignalverarbeitung ist aktiviert\n" #: ../src/mesh/impls/bout/boutmesh.cxx:858 msgid "\tdone\n" @@ -239,15 +239,15 @@ msgstr "\tfertig\n" #: ../src/bout++.cxx:402 msgid "\tnetCDF support disabled\n" -msgstr "\tNetCDF Unterstützung deaktiviert\n" +msgstr "\tNetCDF Unterstützung ist deaktiviert\n" #: ../src/bout++.cxx:397 msgid "\tnetCDF support enabled\n" -msgstr "\tNetCDF Unterstützung aktiviert\n" +msgstr "\tNetCDF Unterstützung ist aktiviert\n" #: ../src/bout++.cxx:400 msgid "\tnetCDF4 support enabled\n" -msgstr "\tNetCDF4 Unterstützung aktiviert\n" +msgstr "\tNetCDF4 Unterstützung ist aktiviert\n" #: ../src/bout++.cxx:166 #, c-format @@ -339,7 +339,7 @@ msgid "" "Code compiled on %s at %s\n" "\n" msgstr "" -"Der Code wurde auf %s um %s kompiliert\n" +"Der Code wurde am %s um %s kompiliert\n" "\n" #: ../src/sys/optionsreader.cxx:142 From 1b469c2f59c13a31ddba11226ef359591c3afc79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 7 Feb 2019 10:42:50 +0000 Subject: [PATCH 0719/1783] Prevent data corruption Returning 1 throws an exception, which can cause to corrupted data --- src/bout++.cxx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 53a5e45c39..5c155b89fd 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -702,11 +702,10 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { // Check if enough time left BoutReal t_remain = mpi_start_time + wall_limit - MPI_Wtime(); - if (t_remain < wtime) { + if (t_remain < wtime*2) { // Less than 1 time-step left - output_warn.write(_("Only %e seconds left. Quitting\n"), t_remain); - - return 1; // Return an error code to quit + output_warn.write(_("Only %e seconds (%.2f steps) left. Quitting\n"), t_remain,t_remain/wtime); + user_requested_exit=true; } else { output_progress.print(" Wall %s", (time_to_hms(t_remain)).c_str()); } @@ -718,7 +717,7 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { if (f.good()) { output << "\n" << "File " << stopCheckName << " exists -- triggering exit." << endl; - return 1; + user_requested_exit=true; } } From 9111e2df3386a1dd739fd315f5472e42769e73df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 7 Feb 2019 11:30:40 +0000 Subject: [PATCH 0720/1783] Check after monitor-calls again for user_requested_exit --- src/solver/solver.cxx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index d9f4e84686..4e242cf519 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -706,7 +706,10 @@ int Solver::call_monitors(BoutReal simtime, int iter, int NOUT) { throw; } - if ( iter == NOUT ){ + // Check if any of the monitors has asked to quit + MPI_Allreduce(&user_requested_exit,&abort,1,MPI_C_BOOL,MPI_LOR,MPI_COMM_WORLD); + + if ( iter == NOUT || abort ){ for (const auto &it : monitors){ it->cleanup(); } @@ -714,10 +717,10 @@ int Solver::call_monitors(BoutReal simtime, int iter, int NOUT) { if (abort) { // restart file should be written by physics model - output.write("User signalled to quit. Returning\n"); + output.write(_("User signalled to quit. Returning\n")); return 1; } - + return 0; } From b60061be1a0a20213148b83a746193165e64ee87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 7 Feb 2019 11:58:29 +0000 Subject: [PATCH 0721/1783] Inform about gettext's license --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index f44e67b889..f3d474db6d 100644 --- a/README.md +++ b/README.md @@ -181,3 +181,9 @@ used in the creation of [configure](configure) from [configure.ac](configure.ac), and are provided as a courtesy to developers. You are free to substitute them with other autoconf macros that provide equivalent functionality. + +The natural language support (NLS) extension uses gettext, which is +licensed as GPL. Thus if you compile BOUT++ with NLS, BOUT++ is +automatically licensed as GPL. Thus if you want to use BOUT++ with +non-GPL compatible code, make sure to compile without NLS by +configuring as: `./configure --disable-nls` From cd0d88a8ec4e23b1624ab81d48476e46e966fbaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 7 Feb 2019 15:31:18 +0000 Subject: [PATCH 0722/1783] fftw is als GPL I haven't checked the other dependencies - if anybody needs a LGPL version, the README informs them, that they need to check with what BOUT++ links, and make sure to disable or replace any GPLed code. --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f3d474db6d..f77c398285 100644 --- a/README.md +++ b/README.md @@ -182,8 +182,8 @@ used in the creation of [configure](configure) from developers. You are free to substitute them with other autoconf macros that provide equivalent functionality. -The natural language support (NLS) extension uses gettext, which is -licensed as GPL. Thus if you compile BOUT++ with NLS, BOUT++ is -automatically licensed as GPL. Thus if you want to use BOUT++ with -non-GPL compatible code, make sure to compile without NLS by -configuring as: `./configure --disable-nls` +BOUT++ links by default with gettext and fftw, both are licensed as +GPL. Thus if you compile BOUT++ with ether of them, or any other GPLed +code, BOUT++ will automatically be licensed as GPL. Thus if you want +to use BOUT++ with non-GPL compatible code, make sure to compile +without GPLed code. From 4c221c9b763a8d7d20b47876611fa9dffdfea2c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 7 Feb 2019 15:35:29 +0000 Subject: [PATCH 0723/1783] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f77c398285..19f1d14826 100644 --- a/README.md +++ b/README.md @@ -185,5 +185,5 @@ that provide equivalent functionality. BOUT++ links by default with gettext and fftw, both are licensed as GPL. Thus if you compile BOUT++ with ether of them, or any other GPLed code, BOUT++ will automatically be licensed as GPL. Thus if you want -to use BOUT++ with non-GPL compatible code, make sure to compile +to use BOUT++ with GPL non-compatible code, make sure to compile without GPLed code. From 3f8614cfcd2b8b72e111f4e6e6f5ddf736f46db3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 7 Feb 2019 18:11:21 +0000 Subject: [PATCH 0724/1783] Hypnotoad: handle case when break of contour is very close to x-point --- .../tokamak_grids/gridgen/leg_separatrix2.pro | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/tools/tokamak_grids/gridgen/leg_separatrix2.pro b/tools/tokamak_grids/gridgen/leg_separatrix2.pro index 2d7c6caf00..d7b47f6de6 100644 --- a/tools/tokamak_grids/gridgen/leg_separatrix2.pro +++ b/tools/tokamak_grids/gridgen/leg_separatrix2.pro @@ -75,9 +75,10 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ oplot, bndry[0,*], bndry[1,*], color=2, thick=2 ENDIF - cpos = line_crossings(sep_ri, sep_zi, 0, $ + cpos = line_crossings(sep_ri, sep_zi, info[i].type, $ ri, zi, 1, $ ncross=ncross, inds1=inds) + PRINT, "Intersections: ", ncross FOR j = 0, ncross-1 DO BEGIN ; Intersection. Get location @@ -100,10 +101,19 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ si = [inds[j]] IF dir GT 0 THEN BEGIN in = CEIL(si[0]) - si = [si, in + indgen(N_ELEMENTS(sep_ri) - in)] + IF in LT N_ELEMENTS(sep_ri) THEN BEGIN + ; normal case + si = [si, in + indgen(N_ELEMENTS(sep_ri) - in), indgen(in - 1)] + ENDIF ELSE BEGIN + ; can't call indgen(0) so handle this specially + si = [si, indgen(in - 1)] + ENDELSE ENDIF ELSE BEGIN in = FLOOR(si[0]) - si = [si, reverse(indgen(in+1))] + ; contour is closed, so we can loop around: start at si, add elements + ; until the beginning of the contour, then add elements starting from the + ; end of the contour + si = [si, reverse(indgen(in+1)), reverse(indgen(N_ELEMENTS(sep_ri)-in-1)) + in + 1] ENDELSE sepri = INTERPOLATE(sep_ri, si) sepzi = INTERPOLATE(sep_zi, si) @@ -124,8 +134,11 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ dz = dz[1:*] * dz[0:(n-2)] in = MIN(WHERE((dr[1:*] LE 0.0) OR (dz[1:*] LE 0.0))) + 1 - sepri = sepri[0:in] - sepzi = sepzi[0:in] + if in GT 0 THEN BEGIN + ; if in<=0 then there is no extremum, so don't truncate sepri/sepzi + sepri = sepri[0:in] + sepzi = sepzi[0:in] + ENDIF IF KEYWORD_SET(debug) THEN OPLOT, sepri, sepzi, color=4 From e0d331d3d0d39b698c4ace4f921bbae58205c701 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 8 Feb 2019 00:13:31 +0000 Subject: [PATCH 0725/1783] Enable communications for simulations with no core, only divertor legs --- src/mesh/impls/bout/boutmesh.cxx | 38 ++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index eccea69cc2..ff91d3d9cf 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -201,9 +201,9 @@ int BoutMesh::load() { jyseps1_1 = -1; } - if (jyseps2_1 <= jyseps1_1) { + if (jyseps2_1 < jyseps1_1) { output_warn.write( - "\tWARNING: jyseps2_1 (%d) must be > jyseps1_1 (%d). Setting to %d\n", jyseps2_1, + "\tWARNING: jyseps2_1 (%d) must be >= jyseps1_1 (%d). Setting to %d\n", jyseps2_1, jyseps1_1, jyseps1_1 + 1); jyseps2_1 = jyseps1_1 + 1; } @@ -689,24 +689,34 @@ int BoutMesh::load() { // Core region TRACE("Creating core communicators"); - proc[0] = PROC_NUM(i, YPROC(jyseps1_1 + 1)); - proc[1] = PROC_NUM(i, YPROC(jyseps2_1)); + if (jyseps2_1 > jyseps1_1) { + proc[0] = PROC_NUM(i, YPROC(jyseps1_1 + 1)); + proc[1] = PROC_NUM(i, YPROC(jyseps2_1)); - output_debug << "CORE1 " << proc[0] << ", " << proc[1] << endl; + output_debug << "CORE1 " << proc[0] << ", " << proc[1] << endl; - if ((proc[0] < 0) || (proc[1] < 0)) - throw BoutException("Invalid processor range for core processors"); - MPI_Group_range_incl(group_world, 1, &proc, &group_tmp1); + if ((proc[0] < 0) || (proc[1] < 0)) + throw BoutException("Invalid processor range for core processors"); + MPI_Group_range_incl(group_world, 1, &proc, &group_tmp1); + } else { + // no core region between jyseps1_1 and jyseps2_1 + group_tmp1 = MPI_GROUP_EMPTY; + } - proc[0] = PROC_NUM(i, YPROC(jyseps1_2 + 1)); - proc[1] = PROC_NUM(i, YPROC(jyseps2_2)); + if (jyseps2_2 > jyseps1_2) { + proc[0] = PROC_NUM(i, YPROC(jyseps1_2 + 1)); + proc[1] = PROC_NUM(i, YPROC(jyseps2_2)); - output_debug << "CORE2 " << proc[0] << ", " << proc[1] << endl; + output_debug << "CORE2 " << proc[0] << ", " << proc[1] << endl; - if ((proc[0] < 0) || (proc[1] < 0)) { - group_tmp2 = MPI_GROUP_EMPTY; + if ((proc[0] < 0) || (proc[1] < 0)) { + group_tmp2 = MPI_GROUP_EMPTY; + } else { + MPI_Group_range_incl(group_world, 1, &proc, &group_tmp2); + } } else { - MPI_Group_range_incl(group_world, 1, &proc, &group_tmp2); + // no core region between jyseps1_2 and jyseps2_2 + group_tmp2 = MPI_GROUP_EMPTY; } MPI_Group_union(group_tmp1, group_tmp2, &group); From 0064e702ed385ef91929fd9c1dfef3c5eda2aead Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 7 Feb 2019 17:02:58 +0000 Subject: [PATCH 0726/1783] Hypnotoad: add checkbox to output metrics for orthogonal coordinates Add a checkbox to the 'Output' tab, which if selected outputs metrics for orthogonal coordinates (i.e. using ShiftedMetric), by setting the integrated shear to zero, I=0, when calculating the metric components. --- tools/tokamak_grids/gridgen/hypnotoad.pro | 19 ++++++++++++++++++- tools/tokamak_grids/gridgen/process_grid.pro | 17 ++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/tools/tokamak_grids/gridgen/hypnotoad.pro b/tools/tokamak_grids/gridgen/hypnotoad.pro index d8fd5818a6..9c871863a9 100644 --- a/tools/tokamak_grids/gridgen/hypnotoad.pro +++ b/tools/tokamak_grids/gridgen/hypnotoad.pro @@ -445,7 +445,8 @@ PRO event_handler, event IF info.rz_grid_valid AND info.flux_mesh_valid THEN BEGIN ; Get settings settings = {calcp:info.calcp, calcbt:info.calcbt, $ - calchthe:info.calchthe, calcjpar:info.calcjpar} + calchthe:info.calchthe, calcjpar:info.calcjpar, $ + orthogonal_coordinates_output:info.orthogonal_coordinates_output} process_grid, *(info.rz_grid), *(info.flux_mesh), $ output=filename, poorquality=poorquality, /gui, parent=info.draw, $ @@ -545,6 +546,10 @@ PRO event_handler, event info.calcjpar = event.select widget_control, event.top, set_UVALUE=info END + 'orthogonal_coordinates_output' : BEGIN + info.orthogonal_coordinates_output = event.select + widget_control, event.top, set_UVALUE=info + END 'fast': BEGIN info.fast = event.select widget_control, event.top, set_UVALUE=info @@ -850,6 +855,10 @@ PRO event_handler, event str_set, info, "calcjpar", oldinfo.calcjpar Widget_Control, info.calcjpar_check, Set_Button=info.calcjpar + str_set, info, "orthogonal_coordinates_output_check", oldinfo.orthogonal_coordinates_output_check, /over + str_set, info, "orthogonal_coordinates_output", oldinfo.orthogonal_coordinates_output + Widget_Control, info.orthogonal_coordinates_output_check, Set_Button=info.orthogonal_coordinates_output + str_set, info, "radgrid_check", oldinfo.radgrid_check, /over str_set, info, "single_rad_grid", oldinfo.single_rad_grid Widget_Control, info.radgrid_check, Set_Button=info.single_rad_grid @@ -1097,6 +1106,12 @@ PRO hypnotoad tooltip="Recalculate Jpar") Widget_Control, calcjpar_check, Set_Button=calcjpar_default + orthogonal_coordinates_output_default = 0 + orthogonal_coordinates_output_check = WIDGET_BUTTON(checkboxbase, $ + VALUE="Output for orthogonal coords", uvalue='orthogonal_coordinates_output', $ + tooltip="Output metrics for simulations in orthogonal coordinates using ShiftedMetric (i.e. with zero integrated shear, I=0, when calculating metric terms).") + Widget_Control, orthogonal_coordinates_output_check, Set_Button=orthogonal_coordinates_output_default + process_button = WIDGET_BUTTON(tab2, VALUE='Output mesh', $ uvalue='process', tooltip="Process mesh and output to file") @@ -1161,6 +1176,8 @@ PRO hypnotoad calchthe:calchthe_default, $ calcjpar_check:calcjpar_check, $ calcjpar:calcjpar_default, $ + orthogonal_coordinates_output_check:orthogonal_coordinates_output_check, $ + orthogonal_coordinates_output:orthogonal_coordinates_output_default, $ fast_check:fast_check, $ fast:0, $ $;;; diff --git a/tools/tokamak_grids/gridgen/process_grid.pro b/tools/tokamak_grids/gridgen/process_grid.pro index 89068d376f..8817e8f352 100644 --- a/tools/tokamak_grids/gridgen/process_grid.pro +++ b/tools/tokamak_grids/gridgen/process_grid.pro @@ -633,6 +633,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ str_check_present, settings, 'calcbt', -1 str_check_present, settings, 'calchthe', -1 str_check_present, settings, 'calcjpar', -1 + str_check_present, settings, 'orthogonal_coordinates_output', -1 ;CATCH, err ;IF err NE 0 THEN BEGIN @@ -1139,7 +1140,21 @@ retrybetacalc: ENDREP UNTIL last ; Calculate metrics - check jacobian - I = sinty + + orthogonal_coordinates_output = settings.orthogonal_coordinates_output + IF orthogonal_coordinates_output EQ -1 THEN orthogonal_coordinates_output = get_yesno("Output for simulations in orthogonal coordinates using ShiftedMetric?", gui=gui, dialog_parent=parent) + IF orthogonal_coordinates_output EQ 1 THEN BEGIN + print,"" + print,"*******************WARNING****************************************" + print,"Calculating metrics for ShiftedMetric style orthogonal coordinates" + print,"******************************************************************" + print,"" + ; for orthogonal coordinates + I = 0. + ENDIF ELSE BEGIN + ; for field-aligned coordinates + I = sinty + ENDELSE g11 = (Rxy*Bpxy)^2; g22 = G^2/hthe^2 + eta^2*g11; From c8ceeb6f1c09755cf51860f136797d365a2bf55b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 8 Feb 2019 17:12:57 +0000 Subject: [PATCH 0727/1783] Allow Coordinates on staggered grids to be read from grid files If grid files contain fields with names like "g11_xlow" for CELL_XLOW or "g11_ylow" for CELL_YLOW then the staggered fields can be loaded from the grid file instead of being interpolated. Also adds a bool argument to Coordinates::geometry() to turn off recalculation of staggered Coordinates by interpolation, in case a user needs to, e.g., renormalize Coordinates and will do all the locations explicitly. --- include/bout/coordinates.hxx | 10 +- include/bout/mesh.hxx | 10 +- src/mesh/coordinates.cxx | 165 ++++++++++++++++++++++++------- src/mesh/impls/bout/boutmesh.cxx | 4 +- src/mesh/mesh.cxx | 7 +- 5 files changed, 155 insertions(+), 41 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index 8f1420bca4..e677689856 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -51,7 +51,13 @@ public: Coordinates(Mesh *mesh); /// Constructor interpolating from another Coordinates object - Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coords_in); + /// By default attempts to read staggered Coordinates from grid data source, + /// interpolating from CELL_CENTRE if not present. Set + /// force_interpolate_from_centre argument to true to always interpolate + /// (useful if CELL_CENTRE Coordinates have been changed, so reading from file + /// would not be correct). + Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coords_in, + bool force_interpolate_from_centre=false); /// A constructor useful for testing purposes. To use it, inherit /// from Coordinates. If \p calculate_geometry is true (default), @@ -102,7 +108,7 @@ public: Field2D IntShiftTorsion; ///< Integrated shear (I in BOUT notation) /// Calculate differential geometry quantities from the metric tensor - int geometry(); + int geometry(bool recalculate_staggered = true); int calcCovariant(); ///< Inverts contravatiant metric to get covariant int calcContravariant(); ///< Invert covariant metric to get contravariant int jacobian(); ///< Calculate J and Bxy diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index bfa3ad205c..51be2cca8b 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -513,7 +513,7 @@ class Mesh { continue; } - i.second = createDefaultCoordinates(location); + i.second = createDefaultCoordinates(location, true); } } @@ -823,7 +823,13 @@ class Mesh { private: /// Allocates default Coordinates objects - std::shared_ptr createDefaultCoordinates(const CELL_LOC location); + /// By default attempts to read staggered Coordinates from grid data source, + /// interpolating from CELL_CENTRE if not present. Set + /// force_interpolate_from_centre argument to true to always interpolate + /// (useful if CELL_CENTRE Coordinates have been changed, so reading from file + /// would not be correct). + std::shared_ptr createDefaultCoordinates(const CELL_LOC location, + bool force_interpolate_from_centre=false); //Internal region related information std::map> regionMap3D; diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 7a4121a2d2..d88acdab99 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -238,7 +238,8 @@ namespace { } } -Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coords_in) +Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coords_in, + bool force_interpolate_from_centre) : dx(1, mesh), dy(1, mesh), dz(1), d1_dx(mesh), d1_dy(mesh), J(1, mesh), Bxy(1, mesh), // Identity metric tensor g11(1, mesh), g22(1, mesh), g33(1, mesh), g12(0, mesh), g13(0, mesh), g23(0, mesh), @@ -249,57 +250,155 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor G3_23(mesh), G1(mesh), G2(mesh), G3(mesh), ShiftTorsion(mesh), IntShiftTorsion(mesh), localmesh(mesh), location(loc) { - dx = interpolateAndNeumann(coords_in->dx, location); - dy = interpolateAndNeumann(coords_in->dy, location); + std::string suffix = ""; + switch (location) { + case CELL_XLOW: { + suffix = "_xlow"; + break; + } + case CELL_YLOW: { + suffix = "_ylow"; + break; + } + case CELL_ZLOW: { + // geometrical quantities are Field2D, so CELL_ZLOW version is the same + // as CELL_CENTRE + suffix = ""; + break; + } + default: { + throw BoutException("Incorrect location passed to " + "Coordinates(Mesh*,const CELL_LOC,const Coordinates*) constructor."); + } + } - nz = mesh->LocalNz; + if (!force_interpolate_from_centre && mesh->sourceHasVar("dx"+suffix)) { + // grid data source has staggered fields, so read instead of interpolating + // Diagonal components of metric tensor g^{ij} (default to 1) + mesh->get(g11, "g11"+suffix, 1.0); + g11.setLocation(location); + mesh->get(g22, "g22"+suffix, 1.0); + g22.setLocation(location); + mesh->get(g33, "g33"+suffix, 1.0); + g33.setLocation(location); + + // Off-diagonal elements. Default to 0 + mesh->get(g12, "g12"+suffix, 0.0); + g12.setLocation(location); + mesh->get(g13, "g13"+suffix, 0.0); + g13.setLocation(location); + mesh->get(g23, "g23"+suffix, 0.0); + g23.setLocation(location); + + /// Find covariant metric components + // Check if any of the components are present + if (mesh->sourceHasVar("g_11"+suffix) or mesh->sourceHasVar("g_22"+suffix) or + mesh->sourceHasVar("g_33"+suffix) or mesh->sourceHasVar("g_12"+suffix) or + mesh->sourceHasVar("g_13"+suffix) or mesh->sourceHasVar("g_23"+suffix)) { + // Check that all components are present + if (mesh->sourceHasVar("g_11"+suffix) and mesh->sourceHasVar("g_22"+suffix) and + mesh->sourceHasVar("g_33"+suffix) and mesh->sourceHasVar("g_12"+suffix) and + mesh->sourceHasVar("g_13"+suffix) and mesh->sourceHasVar("g_23"+suffix)) { + mesh->get(g_11, "g_11"+suffix); + g_11.setLocation(location); + mesh->get(g_22, "g_22"+suffix); + g_22.setLocation(location); + mesh->get(g_33, "g_33"+suffix); + g_33.setLocation(location); + mesh->get(g_12, "g_12"+suffix); + g_12.setLocation(location); + mesh->get(g_13, "g_13"+suffix); + g_13.setLocation(location); + mesh->get(g_23, "g_23"+suffix); + g_23.setLocation(location); + + output_warn.write("\tWARNING! Staggered covariant components of metric tensor set manually. " + "Contravariant components NOT recalculated\n"); + + } else { + output_warn.write("Not all staggered covariant components of metric tensor found. " + "Calculating all from the contravariant tensor\n"); + /// Calculate contravariant metric components if not found + if (calcCovariant()) { + throw BoutException("Error in staggered calcCovariant call"); + } + } + } else { + /// Calculate contravariant metric components if not found + if (calcCovariant()) { + throw BoutException("Error in staggered calcCovariant call"); + } + } + + if (mesh->get(ShiftTorsion, "ShiftTorsion"+suffix)) { + output_warn.write("\tWARNING: No Torsion specified for zShift. Derivatives may not be correct\n"); + ShiftTorsion = 0.0; + } + ShiftTorsion.setLocation(location); + + ////////////////////////////////////////////////////// + + if (mesh->IncIntShear) { + if (mesh->get(IntShiftTorsion, "IntShiftTorsion"+suffix)) { + output_warn.write("\tWARNING: No Integrated torsion specified\n"); + IntShiftTorsion = 0.0; + } + IntShiftTorsion.setLocation(location); + } + } else { + // Interpolate fields from coords_in + + dx = interpolateAndNeumann(coords_in->dx, location); + dy = interpolateAndNeumann(coords_in->dy, location); + + nz = mesh->LocalNz; + + dz = coords_in->dz; + + // Diagonal components of metric tensor g^{ij} + g11 = interpolateAndNeumann(coords_in->g11, location); + g22 = interpolateAndNeumann(coords_in->g22, location); + g33 = interpolateAndNeumann(coords_in->g33, location); - dz = coords_in->dz; + // Off-diagonal elements. + g12 = interpolateAndNeumann(coords_in->g12, location); + g13 = interpolateAndNeumann(coords_in->g13, location); + g23 = interpolateAndNeumann(coords_in->g23, location); - // Diagonal components of metric tensor g^{ij} - g11 = interpolateAndNeumann(coords_in->g11, location); - g22 = interpolateAndNeumann(coords_in->g22, location); - g33 = interpolateAndNeumann(coords_in->g33, location); + ShiftTorsion = interpolateAndNeumann(coords_in->ShiftTorsion, location); - // Off-diagonal elements. - g12 = interpolateAndNeumann(coords_in->g12, location); - g13 = interpolateAndNeumann(coords_in->g13, location); - g23 = interpolateAndNeumann(coords_in->g23, location); + if (mesh->IncIntShear) { + IntShiftTorsion = interpolateAndNeumann(coords_in->IntShiftTorsion, location); + } + + /// Always calculate contravariant metric components so that they are + /// consistent with the interpolated covariant components + if (calcCovariant()) { + throw BoutException("Error in calcCovariant call while constructing staggered Coordinates"); + } + } // Check input metrics if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) || (!finite(g33, RGN_NOBNDRY))) { - throw BoutException("\tERROR: Interpolated diagonal metrics are not finite!\n"); + throw BoutException("\tERROR: Staggered diagonal metrics are not finite!\n"); } if ((min(g11) <= 0.0) || (min(g22) <= 0.0) || (min(g33) <= 0.0)) { - throw BoutException("\tERROR: Interpolated diagonal metrics are negative!\n"); + throw BoutException("\tERROR: Staggered diagonal metrics are negative!\n"); } if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) || (!finite(g23, RGN_NOBNDRY))) { - throw BoutException("\tERROR: Interpolated off-diagonal metrics are not finite!\n"); - } - - /// Always calculate contravariant metric components so that they are - /// consistent with the interpolated covariant components - if (calcCovariant()) { - throw BoutException("Error in calcCovariant call"); + throw BoutException("\tERROR: Staggered off-diagonal metrics are not finite!\n"); } /// Calculate Jacobian and Bxy if (jacobian()) - throw BoutException("Error in jacobian call"); + throw BoutException("Error in jacobian call while constructing staggered Coordinates"); ////////////////////////////////////////////////////// /// Calculate Christoffel symbols. Needs communication if (geometry()) { - throw BoutException("Differential geometry failed\n"); + throw BoutException("Differential geometry failed while constructing staggered Coordinates"); } - ShiftTorsion = interpolateAndNeumann(coords_in->ShiftTorsion, location); - - ////////////////////////////////////////////////////// - - if (mesh->IncIntShear) { - IntShiftTorsion = interpolateAndNeumann(coords_in->IntShiftTorsion, location); - } } void Coordinates::outputVars(Datafile &file) { @@ -324,7 +423,7 @@ void Coordinates::outputVars(Datafile &file) { file.add(J, "J", false); } -int Coordinates::geometry() { +int Coordinates::geometry(bool recalculate_staggered) { TRACE("Coordinates::geometry"); output_progress.write("Calculating differential geometry terms\n"); @@ -486,7 +585,7 @@ int Coordinates::geometry() { d1_dy = -d2y / (dy * dy); } - if (location == CELL_CENTRE) { + if (location == CELL_CENTRE && recalculate_staggered) { // Re-calculate interpolated Coordinates at staggered locations localmesh->recalculateStaggeredCoordinates(); } diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index eccea69cc2..1ac4e3fb97 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -844,13 +844,13 @@ int BoutMesh::load() { getCoordinates(CELL_CENTRE); if (StaggerGrids) { if (xstart >= 2) { - getCoordinates(CELL_XLOW); + //getCoordinates(CELL_XLOW); } if (ystart >= 2) { getCoordinates(CELL_YLOW); } if (LocalNz > 3) { - getCoordinates(CELL_ZLOW); + //getCoordinates(CELL_ZLOW); } } diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 65b19df8fa..3bd03a3ac3 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -325,13 +325,16 @@ ParallelTransform& Mesh::getParallelTransform() { return *transform; } -std::shared_ptr Mesh::createDefaultCoordinates(const CELL_LOC location) { +std::shared_ptr Mesh::createDefaultCoordinates(const CELL_LOC location, + bool force_interpolate_from_centre) { + if (location == CELL_CENTRE || location == CELL_DEFAULT) // Initialize coordinates from input return std::make_shared(this); else // Interpolate coordinates from CELL_CENTRE version - return std::make_shared(this, location, getCoordinates(CELL_CENTRE)); + return std::make_shared(this, location, getCoordinates(CELL_CENTRE), + force_interpolate_from_centre); } From 84e9c0b028da82e9f821f000e0a2b7f4a5070ddc Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 9 Feb 2019 23:14:19 +0000 Subject: [PATCH 0728/1783] Hypnotoad: add 'coordinates_type' field to output Records whether metric components were calculated and saved for a 'field_aligned' or 'orthogonal' coordinate system. --- tools/tokamak_grids/gridgen/process_grid.pro | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/tokamak_grids/gridgen/process_grid.pro b/tools/tokamak_grids/gridgen/process_grid.pro index 8817e8f352..8897972425 100644 --- a/tools/tokamak_grids/gridgen/process_grid.pro +++ b/tools/tokamak_grids/gridgen/process_grid.pro @@ -1597,6 +1597,17 @@ retrybetacalc: s = file_write(handle, "bxcvy", bxcvy) s = file_write(handle, "bxcvz", bxcvz) + ; type of coordinate system used to calculate metric tensor terms + IF orthogonal_coordinates_output EQ 0 THEN BEGIN + coordinates_type = "field_aligned" + ENDIF ELSE IF orthogonal_coordinates_output EQ 1 THEN BEGIN + coordinates_type = "orthogonal" + ENDIF ELSE BEGIN + PRINT, "ERROR: Unrecognized orthogonal_coordinates_output value", $ + orthogonal_coordinates_output + ENDELSE + s = file_write(handle, "coordinates_type", coordinates_type) + ; Metric tensor terms s = file_write(handle, "g11", g11) s = file_write(handle, "g22", g22) From de9c92bf96eabeaf6d2cc641b0956ee0824c97f7 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 10 Feb 2019 00:12:05 +0000 Subject: [PATCH 0729/1783] Check coordinates_type from grid in ParallelTransform constructors New enough grid generators write 'coordinates_type' to the grid file so that ParallelTransforms can check if the metric components in the grid file were calculated for the right type of coordinate system: "field_aligned", "orthogonal" or "fci". --- include/bout/paralleltransform.hxx | 20 ++++++++++++++++++-- src/mesh/mesh.cxx | 4 ++-- src/mesh/parallel/fci.cxx | 20 ++++++++++++++++++++ src/mesh/parallel/fci.hxx | 10 +++++----- src/mesh/parallel/identity.cxx | 24 ++++++++++++++++++++++++ src/mesh/parallel/makefile | 2 +- src/mesh/parallel/shiftedmetric.cxx | 23 +++++++++++++++++++++-- 7 files changed, 91 insertions(+), 12 deletions(-) create mode 100644 src/mesh/parallel/identity.cxx diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 2f85136be4..978369611e 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -25,6 +25,7 @@ class Mesh; */ class ParallelTransform { public: + ParallelTransform(Mesh& mesh_in) : mesh(mesh_in) {} virtual ~ParallelTransform() {} /// Given a 3D field, calculate and set the Y up down fields @@ -45,6 +46,13 @@ public: virtual const Field3D fromFieldAligned(const Field3D &f) = 0; virtual bool canToFromFieldAligned() = 0; + +protected: + /// This method should be called in the constructor to check that if the grid + /// has a 'coordinates_type' variable, it has the correct value + virtual void checkInputGrid() = 0; + + Mesh &mesh; ///< The mesh this paralleltransform is part of }; @@ -55,6 +63,11 @@ public: */ class ParallelTransformIdentity : public ParallelTransform { public: + ParallelTransformIdentity(Mesh& mesh_in) : ParallelTransform(mesh_in) { + // check the coordinate system used for the grid data source + checkInputGrid(); + } + /*! * Merges the yup and ydown() fields of f, so that * f.yup() = f.ydown() = f @@ -80,6 +93,8 @@ public: bool canToFromFieldAligned() override{ return true; } +protected: + void checkInputGrid() override; }; /*! @@ -126,9 +141,10 @@ public: /// A 3D array, implemented as nested vectors using arr3Dvec = std::vector>>; -private: - Mesh &mesh; ///< The mesh this paralleltransform is part of +protected: + void checkInputGrid() override; +private: /// This is the shift in toroidal angle (z) which takes a point from /// X-Z orthogonal to field-aligned along Y. Field2D zShift; diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 941bfc6580..e90f5ac38a 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -295,11 +295,11 @@ void Mesh::setParallelTransform() { if(ptstr == "identity") { // Identity method i.e. no transform needed - transform = bout::utils::make_unique(); + transform = bout::utils::make_unique(*this); }else if(ptstr == "shifted") { // Shifted metric method - transform = bout::utils::make_unique(*this); + transform = bout::utils::make_unique(*this); }else if(ptstr == "fci") { diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index eb62510406..46639012ee 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -294,6 +294,26 @@ const Field3D FCIMap::integrate(Field3D &f) const { return result; } +FCITransform::FCITransform(Mesh &mesh, bool zperiodic) + : ParallelTransform(mesh), forward_map(mesh, +1, zperiodic), backward_map(mesh, -1, zperiodic), + zperiodic(zperiodic) { + // check the coordinate system used for the grid data source + checkInputGrid(); +} + +void FCITransform::checkInputGrid() { + std::string coordinates_type = ""; + if (mesh.get(coordinates_type, "coordinates_type")) { + // coordinate_system variable not found in grid input + return; + } else { + if (coordinates_type != "fci") { + throw BoutException("Incorrect coordinate system type "+coordinates_type+" used " + "to generate metric components for FCITransform. Should be 'fci."); + } + } +} + void FCITransform::calcYUpDown(Field3D &f) { TRACE("FCITransform::calcYUpDown"); diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index 293113b91d..6f18d678af 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -65,9 +65,7 @@ public: */ class FCITransform : public ParallelTransform { public: - FCITransform(Mesh &mesh, bool zperiodic = true) - : mesh(mesh), forward_map(mesh, +1, zperiodic), backward_map(mesh, -1, zperiodic), - zperiodic(zperiodic) {} + FCITransform(Mesh &mesh, bool zperiodic = true); void calcYUpDown(Field3D &f) override; @@ -84,11 +82,13 @@ public: bool canToFromFieldAligned() override{ return false; } + +protected: + void checkInputGrid() override; + private: FCITransform(); - Mesh& mesh; - FCIMap forward_map; /**< FCI map for field lines in +ve y */ FCIMap backward_map; /**< FCI map for field lines in -ve y */ diff --git a/src/mesh/parallel/identity.cxx b/src/mesh/parallel/identity.cxx new file mode 100644 index 0000000000..ed3fcd83e4 --- /dev/null +++ b/src/mesh/parallel/identity.cxx @@ -0,0 +1,24 @@ +/* + * Implements the identity transform for parallel derivatives + * + * By default fields are stored so that Y is field aligned, so X-Z are not + * orthogonal. + * + */ + +#include +#include + +void ParallelTransformIdentity::checkInputGrid() { + std::string coordinates_type = ""; + if (mesh.get(coordinates_type, "coordinates_type")) { + // coordinate_system variable not found in grid input + return; + } else { + if (coordinates_type != "field_aligned") { + throw BoutException("Incorrect coordinate system type "+coordinates_type+" used " + "to generate metric components for ParallelTransformIdentity. Should be " + "'field_aligned."); + } + } +} diff --git a/src/mesh/parallel/makefile b/src/mesh/parallel/makefile index 9c4817b008..6090fafeaa 100644 --- a/src/mesh/parallel/makefile +++ b/src/mesh/parallel/makefile @@ -2,7 +2,7 @@ BOUT_TOP = ../../.. DIRS = -SOURCEC = shiftedmetric.cxx fci.cxx +SOURCEC = identity.cxx shiftedmetric.cxx fci.cxx TARGET = lib include $(BOUT_TOP)/make.config diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 55eee670bd..d9a47aba66 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -15,7 +15,10 @@ #include -ShiftedMetric::ShiftedMetric(Mesh &m) : mesh(m), zShift(&m) { +ShiftedMetric::ShiftedMetric(Mesh &m) : ParallelTransform(m), zShift(&m) { + // check the coordinate system used for the grid data source + checkInputGrid(); + // Read the zShift angle from the mesh if (mesh.get(zShift, "zShift")) { // No zShift variable. Try qinty in BOUT grid files @@ -35,10 +38,26 @@ ShiftedMetric::ShiftedMetric(Mesh &m) : mesh(m), zShift(&m) { cachePhases(); } -ShiftedMetric::ShiftedMetric(Mesh &m, Field2D zShift_) : mesh(m), zShift(std::move(zShift_)) { +ShiftedMetric::ShiftedMetric(Mesh &m, Field2D zShift_) : ParallelTransform(m), zShift(std::move(zShift_)) { + // check the coordinate system used for the grid data source + checkInputGrid(); + cachePhases(); } +void ShiftedMetric::checkInputGrid() { + std::string coordinates_type = ""; + if (mesh.get(coordinates_type, "coordinates_type")) { + // coordinate_system variable not found in grid input + return; + } else { + if (coordinates_type != "orthogonal") { + throw BoutException("Incorrect coordinate system type "+coordinates_type+" used " + "to generate metric components for ShiftedMetric. Should be 'orthogonal."); + } + } +} + void ShiftedMetric::cachePhases() { // If we wanted to be efficient we could move the following cached phase setup // into the relevant shifting routines (with static bool first protection) From 422078789364d309e1ac99736c18b6484b6573fd Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 10 Feb 2019 01:36:23 +0000 Subject: [PATCH 0730/1783] Add methods to get strings from grid files Strings are stored as attributes of the top-level in grid files. --- include/bout/griddata.hxx | 14 +++++++++++ include/bout/mesh.hxx | 8 ++++++ src/mesh/data/gridfromfile.cxx | 41 +++++++++++++++++++++++++++++++ src/mesh/data/gridfromoptions.cxx | 10 ++++++++ src/mesh/mesh.cxx | 10 ++++++++ 5 files changed, 83 insertions(+) diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index 42ca1c9f97..5954b56cd6 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -52,6 +52,7 @@ public: virtual bool hasVar(const std::string &name) = 0; ///< Test if source can supply a variable + virtual bool get(Mesh *m, std::string &sval, const std::string &name) = 0; ///< Get a string virtual bool get(Mesh *m, int &ival, const std::string &name) = 0; ///< Get an integer virtual bool get(Mesh *m, BoutReal &rval, const std::string &name) = 0; ///< Get a BoutReal number @@ -78,6 +79,7 @@ public: bool hasVar(const std::string &name) override; + bool get(Mesh *m, std::string &sval, const std::string &name) override; ///< Get a string bool get(Mesh *m, int &ival, const std::string &name) override; ///< Get an integer bool get(Mesh *m, BoutReal &rval, const std::string &name) override; ///< Get a BoutReal number @@ -120,6 +122,18 @@ public: */ bool hasVar(const std::string &name) override; + /*! + * Reads strings from options. Uses Options::get to handle + * expressions + * + * @param[in] mesh Not used + * @param[in] name Name of variable + * @param[out] sval Always given a value, defaults to 0 + * + * @return True if option is set, false if ival is default (0) + */ + bool get(Mesh *mesh, std::string &sval, const std::string &name) override; + /*! * Reads integers from options. Uses Options::get to handle * expressions diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 326c2f2fa3..8e0d902018 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -124,6 +124,14 @@ class Mesh { // Get routines to request data from mesh file + /// Get a string from the input source + /// + /// @param[out] sval The value will be put into this variable + /// @param[in] name The name of the variable to read + /// + /// @returns zero if successful, non-zero on failure + int get(std::string &sval, const std::string &name); + /// Get an integer from the input source /// /// @param[out] ival The value will be put into this variable diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index e9b1c417f8..39bb73bc67 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -58,6 +58,47 @@ bool GridFile::hasVar(const std::string &name) { return s.size() != 0; } +/*! + * Read a string from file. If the string is not + * found, then string is set to "" and false is returned. + * + * Inputs + * ------ + * + * m Pointer to mesh, not used + * name String containing name of variable + * + * Outputs + * ------- + * + * sval Reference to string + * + * Returns + * ------- + * + * Boolean. True on success. + * + */ +bool GridFile::get(Mesh *UNUSED(m), std::string &sval, const std::string &name) { + Timer timer("io"); + TRACE("GridFile::get(std::string)"); + + if (!file->is_valid()) { + throw BoutException("File cannot be read"); + } + + // strings must be written as attributes, so read from attribute + bool success = file->getAttribute("", name, sval); + if (success) { + output_info << "\tOption " << name << " = " << sval << " (" << filename <<")" << endl; + } else { + sval = ""; + } + + return success; + +} + /*! * Read a single integer from file. If the integer is not * found, then ival is set to zero and false is returned. diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index f5e2158b68..6e2a855902 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -15,6 +15,16 @@ bool GridFromOptions::hasVar(const std::string &name) { return options->isSet(name); } +bool GridFromOptions::get(Mesh *UNUSED(m), std::string &sval, const std::string &name) { + if(!hasVar(name)) { + sval = ""; + return false; + } + + options->get(name, sval, ""); + return true; +} + bool GridFromOptions::get(Mesh *UNUSED(m), int &ival, const std::string &name) { if(!hasVar(name)) { ival = 0; diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index e90f5ac38a..71ea062bc9 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -48,6 +48,16 @@ Mesh::~Mesh() { * which may then read from a file, options, or other sources. **************************************************************************/ +/// Get a string +int Mesh::get(std::string &sval, const std::string &name) { + TRACE("Mesh::get(sval, %s)", name.c_str()); + + if (source == nullptr or !source->get(this, sval, name)) + return 1; + + return 0; +} + /// Get an integer int Mesh::get(int &ival, const std::string &name) { TRACE("Mesh::get(ival, %s)", name.c_str()); From 24ab816cfb8b0a9e9daac50b6eac0f617efc9473 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 10 Feb 2019 12:14:27 +0000 Subject: [PATCH 0731/1783] Hypnotoad: write 'coordinates_type' as an attribute rather than variable netCDF recommends storing strings as attributes rather than variables, and BOUT++ already has methods to read string attributes, so storing 'coordinates_type' as an attribute rather than a variable is more convenient. --- tools/idllib/file_write_string.pro | 36 ++++++++++++++++++++ tools/tokamak_grids/gridgen/process_grid.pro | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 tools/idllib/file_write_string.pro diff --git a/tools/idllib/file_write_string.pro b/tools/idllib/file_write_string.pro new file mode 100644 index 0000000000..15d235bc03 --- /dev/null +++ b/tools/idllib/file_write_string.pro @@ -0,0 +1,36 @@ +; Write a string to a file as an attribute +FUNCTION file_write_string, handle, varname, data + + CATCH, errcode + + IF errcode NE 0 THEN BEGIN + ; error occurred + PRINT, "Error occurred in file_write: "+!ERROR_STATE.MSG + PRINT, "=> Couldn't write variable '"+varname+"'" + RETURN, 1 + ENDIF + + IF handle.type EQ 1 THEN BEGIN + ; PDB + status = CALL_FUNCTION('pdb_open', handle.name, /write) + + status = CALL_FUNCTION('pdb_write_var', varname, data) + + CALL_PROCEDURE, 'pdb_close' + + CATCH, /CANCEL + RETURN, status + ENDIF + + ; NetCDF + + NCDF_CONTROL, handle.id, /REDEF + + NCDF_ATTPUT, handle.id, /GLOBAL, varname, data + + NCDF_CONTROL, handle.id, /ENDEF + + CATCH, /CANCEL + + RETURN, 0 +END diff --git a/tools/tokamak_grids/gridgen/process_grid.pro b/tools/tokamak_grids/gridgen/process_grid.pro index 8897972425..0115308bf9 100644 --- a/tools/tokamak_grids/gridgen/process_grid.pro +++ b/tools/tokamak_grids/gridgen/process_grid.pro @@ -1606,7 +1606,7 @@ retrybetacalc: PRINT, "ERROR: Unrecognized orthogonal_coordinates_output value", $ orthogonal_coordinates_output ENDELSE - s = file_write(handle, "coordinates_type", coordinates_type) + s = file_write_string(handle, "coordinates_type", coordinates_type) ; Metric tensor terms s = file_write(handle, "g11", g11) From e3f19a4179ede86f31079ee85dc81ad75c3a0d1c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 10 Feb 2019 13:52:21 +0000 Subject: [PATCH 0732/1783] Fix unit tests - ParallelTransformIdentity constructor needs to be passed the Mesh - FakeGridDataSource needs a get method for strings --- tests/unit/mesh/test_boutmesh.cxx | 3 +++ tests/unit/mesh/test_interpolation.cxx | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unit/mesh/test_boutmesh.cxx b/tests/unit/mesh/test_boutmesh.cxx index 3891227e48..3a5ec6295f 100644 --- a/tests/unit/mesh/test_boutmesh.cxx +++ b/tests/unit/mesh/test_boutmesh.cxx @@ -10,6 +10,9 @@ class FakeGridDataSource : public GridDataSource { FakeGridDataSource(){}; ~FakeGridDataSource(){}; bool hasVar(const std::string &UNUSED(name)) { return false; }; + bool get(Mesh *UNUSED(m), std::string &UNUSED(sval), const std::string &UNUSED(name)) { + return true; + }; bool get(Mesh *UNUSED(m), int &UNUSED(ival), const std::string &UNUSED(name)) { return true; }; diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index f48b5c5c52..db212bf763 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -54,7 +54,7 @@ class Field3DInterpToTest : public ::testing::Test { mesh->ystart = 2; mesh->xend = nx - 3; mesh->yend = ny - 3; - mesh->setParallelTransform(bout::utils::make_unique()); + mesh->setParallelTransform(bout::utils::make_unique(*mesh)); output_info.disable(); mesh->createDefaultRegions(); output_info.enable(); From f6340d7c4d41897a00b26d8b57b5186a26d4ebb0 Mon Sep 17 00:00:00 2001 From: Marta Estarellas Date: Mon, 11 Feb 2019 14:08:34 +0900 Subject: [PATCH 0733/1783] First round of spanish comments added --- locale/spa/libbout.po | 704 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 704 insertions(+) create mode 100644 locale/spa/libbout.po diff --git a/locale/spa/libbout.po b/locale/spa/libbout.po new file mode 100644 index 0000000000..f8e7cd7576 --- /dev/null +++ b/locale/spa/libbout.po @@ -0,0 +1,704 @@ +# Language spa translations for BOUT++ package. +# Copyright (C) 2019 THE BOUT++'S COPYRIGHT HOLDER +# This file is distributed under the same license as the BOUT++ package. +# Marta , 2019. +# +msgid "" +msgstr "" +"Project-Id-Version: BOUT++ 4.2.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-02-11 12:46+0900\n" +"PO-Revision-Date: 2019-02-11 12:46+0900\n" +"Last-Translator: Marta \n" +"Language-Team: Spanish\n" +"Language: spa\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:334 +#, c-format +msgid "" +"\t -> Core region jyseps2_1-jyseps1_1 (%d-%d = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" +"\t -> La región `Core` jyseps2_1-jyseps1_1 (%d-%d = %d) debe ser un múltiplo de " +"MYSUB (%d)\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:363 +#, c-format +msgid "" +"\t -> Core region jyseps2_2-jyseps1_1 (%d-%d = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" +"\t -> La región `Core` jyseps2_2-jyseps1_1 (%d-%d = %d) debe ser un múltiplo de " +"MYSUB (%d)\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:341 +#, c-format +msgid "" +"\t -> Core region jyseps2_2-jyseps1_2 (%d-%d = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" +"\t -> La región `Core` jyseps2_2-jyseps1_2 (%d-%d = %d) debe ser un múltiplo de " +"MYSUB (%d)\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:376 +msgid "\t -> Good value\n" +msgstr "\t -> El valor es bueno\n" + + +#: ..//src/mesh/impls/bout/boutmesh.cxx:325 +#, c-format +msgid "\t -> Leg region jyseps1_1+1 (%d) must be a multiple of MYSUB (%d)\n" +msgstr "\t -> La región `Leg` jyseps1_1+1 (%d) debe ser un múltiplo de MYSUB (%d)\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:355 +#, c-format +msgid "" +"\t -> leg region jyseps1_2-ny_inner+1 (%d-%d+1 = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" +"\t -> La región `Leg` jyseps1_2-ny_inner+1 (%d-%d+1 = %d) debe ser un múltiplo de " +"MYSUB (%d)\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:371 +#, c-format +msgid "" +"\t -> leg region ny-jyseps2_2-1 (%d-%d-1 = %d) must be a multiple of MYSUB " +"(%d)\n" +msgstr "" +"\t -> La región `Leg` ny-jyseps2_2-1 (%d-%d-1 = %d) debe ser un múltiplo de MYSUB " +"(%d)\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:349 +#, c-format +msgid "" +"\t -> leg region ny_inner-jyseps2_1-1 (%d-%d-1 = %d) must be a multiple of " +"MYSUB (%d)\n" +msgstr "" +"\t -> La región `Leg` nyi_inner--jyseps2_1-1 (%d-%d-1 = %d) debe ser un múltiplo de " +"MYSUB (%d)\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:318 +#, c-format +msgid "\t -> ny/NYPE (%d/%d = %d) must be >= MYG (%d)\n" +msgstr "\t -> ny/NYPE (%d/%d = %d) debe ser >= MYG (%d)\n" + +#. Loop over all possibilities +#. Processors divide equally +#. Mesh in X divides equally +#. Mesh in Y divides equally +#: ..//src/mesh/impls/bout/boutmesh.cxx:311 +#, c-format +msgid "\tCandidate value: %d\n" +msgstr "\tValor candidat: %d\n" + +#: ..//src/bout++.cxx:390 +msgid "\tChecking disabled\n" +msgstr "\tComprobación desactivada\n" + +#: ..//src/bout++.cxx:388 +#, c-format +msgid "\tChecking enabled, level %d\n" +msgstr "\tComprobación activada, nivel %d\n" + +#. Print command line options +#: ..//src/bout++.cxx:434 +msgid "\tCommand line options for this run : " +msgstr "\tParámetros de línea de comandos para esta ejecución :" + +#. The stringify is needed here as BOUT_FLAGS_STRING may already contain quoted strings +#. which could cause problems (e.g. terminate strings). +#: ..//src/bout++.cxx:431 +#, c-format +msgid "\tCompiled with flags : %s\n" +msgstr "\tCompilado con los `flags` : %s\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:390 +#, c-format +msgid "" +"\tDomain split (NXPE=%d, NYPE=%d) into domains (localNx=%d, localNy=%d)\n" +msgstr "" +"\tDominio separado (NXPE=%d, NYPE=%d) en los dominios (localNx=%d, localNy=%d)\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:415 +#, c-format +msgid "\tERROR: Cannot split %d Y points equally between %d processors\n" +msgstr "\tERROR: No se pueden separar %d Y puntos entre %d procesadores por igual\n" + +#: ..//src/sys/options/options_ini.cxx:173 +#, c-format +msgid "" +"\tEmpty key\n" +"\tLine: %s" +msgstr "" +"\tEntrada vacía\n" +"\tLínea: %s" + +#: ..//src/sys/optionsreader.cxx:140 +#, c-format +msgid "\tEmpty key or value in command line '%s'\n" +msgstr "\tEntrada o valor vacío en la línea de comandos '%s'\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:127 +msgid "\tGrid size: " +msgstr "\tTamaño de la malla (`grid`): " + +#: ..//src/mesh/impls/bout/boutmesh.cxx:143 +msgid "\tGuard cells (x,y): " +msgstr "\tProteger celdas (x,y): " + +#: ..//src/sys/options/options_ini.cxx:177 +#, c-format +msgid "" +"\tKey must not contain ':' character\n" +"\tLine: %s" +msgstr "" +"\tLa entrada no debe contener el carácter ':'\n" +"\tLínea: %s" + +#: ..//src/sys/optionsreader.cxx:127 +#, c-format +msgid "\tMultiple '=' in command-line argument '%s'\n" +msgstr "\tMutilples '=' en el argumento de la línea de comandos '%s'\n" + +#: ..//src/bout++.cxx:418 +msgid "\tOpenMP parallelisation disabled\n" +msgstr "\tParalelización en OpenMP desactivada\n" + +#: ..//src/bout++.cxx:416 +#, c-format +msgid "\tOpenMP parallelisation enabled, using %d threads\n" +msgstr "\tParalelización en OpenMP activada, usando %d procesos (`threads`)\n" + +#. Mark the option as used +#. Option not found +#: ..//include/options.hxx:298 ..//include/options.hxx:319 +#: ..//src/sys/options.cxx:136 ..//src/sys/options.cxx:172 +#: ..//src/sys/options.cxx:200 ..//src/sys/options.cxx:221 +#: ..//src/sys/options.cxx:224 +msgid "\tOption " +msgstr "\tOpción " + +#: ..//src/sys/options.cxx:97 +#, c-format +msgid "" +"\tOption %s = %s (%s) overwritten with:\n" +"\t\t%s = %s (%s)\n" +msgstr "" +"\tOpción %s = %s (%s) sobreescrita with:\n" +"\t\t%s = %s (%s)\n" + +#: ..//src/sys/options.cxx:226 +#, c-format +msgid "\tOption '%s': Boolean expected. Got '%s'\n" +msgstr "\tOpción '%s': valor Booleano esperado. Se obtuvo '%s'\n" + +#: ..//src/sys/options/options_ini.cxx:74 +#, c-format +msgid "\tOptions file '%s' not found\n" +msgstr "\tOpciones de archivo '%s' no encontrados\n" + +#: ..//src/bout++.cxx:412 +msgid "\tParallel NetCDF support disabled\n" +msgstr "\tSoporte para NetCDF paralelo desactivado\n" + +#: ..//src/bout++.cxx:410 +msgid "\tParallel NetCDF support enabled\n" +msgstr "\tSoporte para NetCDF paralelo activado\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:124 +msgid "\tRead nz from input grid file\n" +msgstr "\tLeer nz del archivo malla `grid`de entrada\n" + +#: ..//src/mesh/mesh.cxx:124 +msgid "\tReading contravariant vector " +msgstr "\tLeyendo vector contravariante " + +#: ..//src/mesh/mesh.cxx:117 ..//src/mesh/mesh.cxx:138 +msgid "\tReading covariant vector " +msgstr "\tLeyendo vector covariante " + +#: ..//src/bout++.cxx:396 +msgid "\tSignal handling disabled\n" +msgstr "\tGestión de señal desactivada\n" + +#: ..//src/bout++.cxx:394 +msgid "\tSignal handling enabled\n" +msgstr "\tGestión de señal activada\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:857 +msgid "\tdone\n" +msgstr "\tlisto\n" + +#: ..//src/bout++.cxx:405 +msgid "\tnetCDF support disabled\n" +msgstr "\tSoporte netCDF desactivado\n" + +#: ..//src/bout++.cxx:400 +msgid "\tnetCDF support enabled\n" +msgstr "\tSoporte netCDF activado\n" + +#: ..//src/bout++.cxx:403 +msgid "\tnetCDF4 support enabled\n" +msgstr "\tSoporte netCDF4 activado\n" + +#: ..//src/bout++.cxx:169 +#, c-format +msgid "" +"\n" +" -d \tLook in for input/output files\n" +" -f \tUse OPTIONS given in \n" +" -o \tSave used OPTIONS given to \n" +" -l, --log \tPrint log to \n" +" -v, --verbose\t\tIncrease verbosity\n" +" -q, --quiet\t\tDecrease verbosity\n" +msgstr "" +"\n" +" -d \tBuscar en los archivos input/output\n" +" -f \tUsar OPCIONES descritas en \n" +" -o \tGuardar OPCIONES usadas descritas en \n" +" -l, --log \tImprimir registro `log` en \n" +" -v, --verbose\t\tAumentar verbosidad\n" +" -q, --quiet\t\tDisminuir verbosidad\n" + +#: ..//src/solver/solver.cxx:565 +#, c-format +msgid "" +"\n" +"Run finished at : %s\n" +msgstr "" +"\n" +"Ejecución finalizada en : %s\n" + +#: ..//src/solver/solver.cxx:536 +#, c-format +msgid "" +"\n" +"Run started at : %s\n" +msgstr "" +"\n" +"Ejecución iniciada en : %s\n" + +#: ..//src/bout++.cxx:178 +#, c-format +msgid " -c, --color\t\tColor output using bout-log-color\n" +msgstr " -c, --color\t\tSalida de color usando bout-log-color\n" + +#: ..//src/bout++.cxx:181 +#, c-format +msgid "" +" -h, --help\t\tThis message\n" +" restart [append]\tRestart the simulation. If append is specified, append " +"to the existing output files, otherwise overwrite them\n" +" VAR=VALUE\t\tSpecify a VALUE for input parameter VAR\n" +"\n" +"For all possible input parameters, see the user manual and/or the physics " +"model source (e.g. %s.cxx)\n" +msgstr "" +" -h, --help\t\tEste mensaje\n" +" restart [append]\tReiniciar la simulación. Si se especificó `append`, " +"agregar a los archivos de salida existentes, de lo contrario sobreescribirlos\n" +" VAR=VALUE\t\tEspecificar un VALOR para el parámetro input VAR\n" +"\n" +"Para todos los possibles parámetros input, vea el manual de usuario y/o el modelo " +"físico fuente (ej. %s.cxx)\n" + +#: ..//src/sys/options.cxx:248 +msgid "All options used\n" +msgstr "Todas las opciones usadas\n" + +#. / Print intro +#: ..//src/bout++.cxx:368 +#, c-format +msgid "BOUT++ version %s\n" +msgstr "Versión de BOUT++ %s\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:827 +msgid "Boundary regions in this processor: " +msgstr "Regiones frontera en este procesador: " + +#: ..//src/mesh/impls/bout/boutmesh.cxx:406 +#, c-format +msgid "Cannot split %d X points equally between %d processors\n" +msgstr "No se pueden dividir %d X points entre %d procesadores por igual\n" + +#: ..//src/bout++.cxx:375 +#, c-format +msgid "" +"Code compiled on %s at %s\n" +"\n" +msgstr "" +"Código compilado en %s a %s\n" +"\n" + +#: ..//src/sys/optionsreader.cxx:142 +msgid "Command line" +msgstr "Línea de comandos" + +#. / Print compile-time options +#: ..//src/bout++.cxx:385 +msgid "Compile-time options:\n" +msgstr "Opciones de tiempo de compilación:\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:836 +msgid "Constructing default regions" +msgstr "Construyendo regiones por defecto" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:384 +msgid "" +"Could not find a valid value for NXPE. Try a different number of processors." +msgstr "" +"No se pudo encontrar un valor válido para NXPE. Intente usar un número diferente de procesadores." + +#: ..//src/sys/options/options_ini.cxx:132 +#, c-format +msgid "Could not open output file '%s'\n" +msgstr "No se pudo abrir el archivo de salida `output` '%s'\n" + +#. Error reading +#: ..//src/mesh/mesh.cxx:278 +#, c-format +msgid "Could not read integer array '%s'\n" +msgstr "No se pudo leer la matriz de enteros '%s'\n" + +#. Failed . Probably not important enough to stop the simulation +#: ..//src/bout++.cxx:327 +#, c-format +msgid "Could not run bout-log-color. Make sure it is in your PATH\n" +msgstr "No se pudo ejecutar bout-log-color. Asegúrese de que se encuentre en su PATH\n" + +#: ..//src/solver/solver.cxx:644 +#, c-format +msgid "Couldn't add Monitor: %g is not a multiple of %g!" +msgstr "No se pudo añadir el Monitor: %g no és multiplo de %g!" + +#: ..//src/mesh/mesh.cxx:349 +#, c-format +msgid "Couldn't find region %s in regionMap2D" +msgstr "No se pudo encontrar la región %s en regionMap2D" + +#: ..//src/mesh/mesh.cxx:341 +#, c-format +msgid "Couldn't find region %s in regionMap3D" +msgstr "No se pudo encontrar la región %s en regionMap2D" + +#: ..//src/mesh/mesh.cxx:357 +#, c-format +msgid "Couldn't find region %s in regionMapPerp" +msgstr "No se pudo encontrar la región %s en regionMapPerp" + +#: ..//src/sys/options.cxx:192 +#, c-format +msgid "Couldn't get BoutReal from option %s = '%s'" +msgstr "No se pudo recuperar BoutReal de la opción %s = '%s'" + +#: ..//src/sys/options.cxx:156 +#, c-format +msgid "Couldn't get integer from option %s = '%s'" +msgstr "No se pudo recuperar el entero de la opción %s = '%s'" + +#: ..//src/bout++.cxx:284 +#, c-format +msgid "DataDir \"%s\" does not exist or is not accessible\n" +msgstr "DataDir \"%s\" no existe o no es accessible\n" + +#: ..//src/bout++.cxx:281 +#, c-format +msgid "DataDir \"%s\" is not a directory\n" +msgstr "DataDir \"%s\" no es un directorio\n" + +#: ..//src/solver/solver.cxx:599 +msgid "ERROR: Solver is already initialised\n" +msgstr "ERROR: el Solver ya se encuentra inicializado\n" + +#: ..//src/bout++.cxx:473 +msgid "Error encountered during initialisation\n" +msgstr "Error encontrado durante la inicialización\n" + +#: ..//src/bout++.cxx:518 +#, c-format +msgid "Error encountered during initialisation: %s\n" +msgstr "Error encontrado durante la inicialización:%s\n" + +#: ..//src/bout++.cxx:557 +msgid "Error whilst writing settings" +msgstr "Error durante el paso de opciones" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:147 +#, c-format +msgid "Error: nx must be greater than 2 times MXG (2 * %d)" +msgstr "Error: nx debe mayor que 2 veces MXG (2 * %d)" + +#: ..//src/solver/solver.cxx:528 +msgid "Failed to initialise solver-> Aborting\n" +msgstr "Fallo en inicializar el solver-> Abortando\n" + +#. Best option +#. Results in square domains +#: ..//src/mesh/impls/bout/boutmesh.cxx:304 +#, c-format +msgid "Finding value for NXPE (ideal = %f)\n" +msgstr "Encontrando valor para NXPE (ideal = %f)\n" + +#: ..//src/solver/solver.cxx:601 +msgid "Initialising solver\n" +msgstr "Initializando el solver\n" + +#: ..//src/bout++.cxx:273 +msgid "" +"Input and output file for settings must be different.\n" +"Provide -o to avoid this issue.\n" +msgstr "" +"Archivos de entrada y salida (`input/output`) para las opciones deben ser diferentes.\n" +"Añada -o para evitar este problema.\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:91 +msgid "Loading mesh" +msgstr "Cargando malla `mesh`" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:106 +msgid "Mesh must contain nx" +msgstr "La malla `mesh` debe contener nx" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:109 +msgid "Mesh must contain ny" +msgstr "La malla `mesh` debe contener ny" + +#. Not found +#: ..//src/mesh/mesh.cxx:282 +#, c-format +msgid "Missing integer array %s\n" +msgstr "Fala la matriz entera %s\n" + +#: ..//src/solver/solver.cxx:698 +msgid "Monitor signalled to quit" +msgstr "Monitor indicó salir" + +#: ..//src/solver/solver.cxx:705 +msgid "Monitor signalled to quit\n" +msgstr "Monitor indicó salir\n" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:833 +msgid "No boundary regions in this processor" +msgstr "Sin regiones de frontera en este procesador" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:234 +#, c-format +msgid "Number of processors (%d) not divisible by NPs in x direction (%d)\n" +msgstr "Número de procesadores (%d) no divisible para NPs in la dirección x (%d)\n" + +#. Less than 1 time-step left +#: ..//src/bout++.cxx:707 +#, c-format +msgid "Only %e seconds left. Quitting\n" +msgstr "Solo faltan %e segundos. Suspendiendo\n" + +#: ..//src/sys/options.cxx:130 ..//src/sys/options.cxx:148 +#: ..//src/sys/options.cxx:184 ..//src/sys/options.cxx:212 +#, c-format +msgid "Option %s has no value" +msgstr "Opción %s sin valor" + +#: ..//src/sys/options.cxx:59 +#, c-format +msgid "Option %s is not a section" +msgstr "Opción %s no es una sección" + +#. Doesn't exist +#: ..//src/sys/options.cxx:70 +#, c-format +msgid "Option %s:%s does not exist" +msgstr "Opción %s:%s no existe" + +#: ..//src/sys/options.cxx:101 +#, c-format +msgid "" +"Options: Setting a value from same source (%s) to new value '%s' - old value " +"was '%s'." +msgstr "" +"Opciones: Cambiando valor de la misma fuente (%s) al valor nuevo '%s' - valor anterior era '%s'." + +#: ..//src/bout++.cxx:379 +#, c-format +msgid "" +"Processor number: %d of %d\n" +"\n" +msgstr "" +"Procesador número: %d de %d\n" +"\n" + +#: ..//src/mesh/mesh.cxx:388 +#, c-format +msgid "Registered region 2D %s" +msgstr "Región 2D registrada %s" + +#: ..//src/mesh/mesh.cxx:379 +#, c-format +msgid "Registered region 3D %s" +msgstr "Región 3D registrada %s" + +#: ..//src/mesh/mesh.cxx:397 +#, c-format +msgid "Registered region Perp %s" +msgstr "Región Perp registrada %s" + +#: ..//src/bout++.cxx:370 +#, c-format +msgid "Revision: %s\n" +msgstr "Revisión: %s\n" + +#: ..//src/solver/solver.cxx:566 +msgid "Run time : " +msgstr "Tiempo de ejecución : " + +#. / Run the solver +#: ..//src/solver/solver.cxx:533 +msgid "" +"Running simulation\n" +"\n" +msgstr "" +"Ejecutando simulación\n" +"\n" + +#: ..//src/bout++.cxx:668 +msgid "" +"Sim Time | RHS evals | Wall Time | Calc Inv Comm I/O SOLVER\n" +"\n" +msgstr "" +"Tiempo Sim | RHS eval. | Tiempo Wall | Calc Inv Com I/O SOLVER\n" +"\n" + +#: ..//src/bout++.cxx:671 +msgid "" +"Sim Time | RHS_e evals | RHS_I evals | Wall Time | Calc Inv " +"Comm I/O SOLVER\n" +"\n" +msgstr "" +"Tiempo Sim | RHS_e eval. | RHS_I eval. | Tiempo Wall | Calc Inv " +"Com I/O SOLVER\n" +"\n" + +#: ..//src/solver/solver.cxx:523 +#, c-format +msgid "Solver running for %d outputs with monitor timestep of %e\n" +msgstr "Solver corriendo para %d outputs con intervalos de tiempo de monitor de %e\n" + +#: ..//src/solver/solver.cxx:521 +#, c-format +msgid "Solver running for %d outputs with output timestep of %e\n" +msgstr "Solver corriendo para %d outputs con intervalos de tiempo de output de %e\n" + +#: ..//src/solver/solver.cxx:650 +#, c-format +msgid "" +"Solver::addMonitor: Cannot reduce timestep (from %g to %g) after init is " +"called!" +msgstr "" +"Solver::addMonitor: No se puedo reducir el intervalo de tiempo (de %g a %g) después de que init fuera " +"llamado!" + +#: ..//src/solver/solver.cxx:1072 +#, c-format +msgid "" +"Time derivative at wrong location - Field is at %s, derivative is at %s for " +"field '%s'\n" +msgstr "" +"Derivada del tiempo en lugar erróneo - El field se encuentra en %s, la derivada se encuentra en %s para " +"el field '%s'\n" + +#: ..//src/solver/solver.cxx:1281 +#, c-format +msgid "Time derivative for variable '%s' not set" +msgstr "Derivada del tiempo para la variable '%s' no fijada" + +#: ..//src/mesh/mesh.cxx:385 +#, c-format +msgid "Trying to add an already existing region %s to regionMap2D" +msgstr "Intentando añadir una región ya existente %s a regionMap2D" + +#: ..//src/mesh/mesh.cxx:376 +#, c-format +msgid "Trying to add an already existing region %s to regionMap3D" +msgstr "Intentando añadir una región ya existente %s a regionMap3D" + +#: ..//src/mesh/mesh.cxx:394 +#, c-format +msgid "Trying to add an already existing region %s to regionMapPerp" +msgstr "Intentando añadir una región ya existente %s a regionMapPerp" + +#: ..//src/mesh/mesh.cxx:313 +msgid "" +"Unrecognised paralleltransform option.\n" +"Valid choices are 'identity', 'shifted', 'fci'" +msgstr "" +"Opción paralleltransform desconocida.\n" +"Opciones válidas son 'identity', 'shifted', 'fci'" + +#: ..//src/sys/options.cxx:250 +msgid "Unused options:\n" +msgstr "Opciones sin usar:\n" + +#: ..//src/bout++.cxx:205 +#, c-format +msgid "Usage is %s -d \n" +msgstr "Correcto uso es %s -d \n" + +#: ..//src/bout++.cxx:217 +#, c-format +msgid "Usage is %s -f \n" +msgstr "Correcto uso es %s -f \n" + +#: ..//src/bout++.cxx:240 +#, c-format +msgid "Usage is %s -l \n" +msgstr "Correcto uso es %s -l \n" + +#: ..//src/bout++.cxx:229 +#, c-format +msgid "Usage is %s -o \n" +msgstr "Correcto uso es %s -o \n" + +#. Print help message -- note this will be displayed once per processor as we've not started MPI yet. +#: ..//src/bout++.cxx:167 +#, c-format +msgid "" +"Usage: %s [-d ] [-f ] [restart [append]] " +"[VAR=VALUE]\n" +msgstr "" +"Uso: %s [-d ] [-f ] [restart [append]] " +"[VAR=VALUE]\n" + +#: ..//src/sys/options.cxx:166 +#, c-format +msgid "Value for option %s = %e is not an integer" +msgstr "Valor para la opción %s = %e no es un entero" + +#: ..//src/solver/solver.cxx:1031 ..//src/solver/solver.cxx:1035 +#, c-format +msgid "Variable '%s' not initialised" +msgstr "Variable '%s' sin inicializar" + +#. Should be a power of 2 for efficient FFTs +#: ..//src/mesh/impls/bout/boutmesh.cxx:119 +msgid "" +"WARNING: Number of toroidal points should be 2^n for efficient FFT " +"performance -- consider changing MZ if using FFTs\n" +msgstr "" +"WARNING: el número de puntos toroidales debería ser 2^n para una FFT eficiente " +"-- considere cambiar MZ si se usan FFTs\n" + +#: ..//src/sys/optionsreader.cxx:60 +#, c-format +msgid "Writing options to file %s\n" +msgstr "Escribiendo opciones a archivo %s\n" + +#. / The source label given to default values +#: ..//src/sys/options.cxx:11 +msgid "default" +msgstr "por defecto" + +#: ..//src/mesh/impls/bout/boutmesh.cxx:156 +msgid "nx must be greater than 2*MXG" +msgstr "nx debe ser mayor que 2*MXG" From dbc5077a96b8af44907fac9888a28745d77f0fc6 Mon Sep 17 00:00:00 2001 From: Marta Estarellas Date: Mon, 11 Feb 2019 14:29:46 +0900 Subject: [PATCH 0734/1783] Revised comments --- locale/spa/libbout.po | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/locale/spa/libbout.po b/locale/spa/libbout.po index f8e7cd7576..28125c4de1 100644 --- a/locale/spa/libbout.po +++ b/locale/spa/libbout.po @@ -68,7 +68,7 @@ msgid "" "\t -> leg region ny-jyseps2_2-1 (%d-%d-1 = %d) must be a multiple of MYSUB " "(%d)\n" msgstr "" -"\t -> La región `Leg` ny-jyseps2_2-1 (%d-%d-1 = %d) debe ser un múltiplo de MYSUB " +"\t -> La región `Leg` ny-jyseps2_2-1 (%d-%d-1 = %d) debe ser un múltiplo de MYSUB " "(%d)\n" #: ..//src/mesh/impls/bout/boutmesh.cxx:349 @@ -77,7 +77,7 @@ msgid "" "\t -> leg region ny_inner-jyseps2_1-1 (%d-%d-1 = %d) must be a multiple of " "MYSUB (%d)\n" msgstr "" -"\t -> La región `Leg` nyi_inner--jyseps2_1-1 (%d-%d-1 = %d) debe ser un múltiplo de " +"\t -> La región `Leg` nyi_inner-jyseps2_1-1 (%d-%d-1 = %d) debe ser un múltiplo de " "MYSUB (%d)\n" #: ..//src/mesh/impls/bout/boutmesh.cxx:318 @@ -92,7 +92,7 @@ msgstr "\t -> ny/NYPE (%d/%d = %d) debe ser >= MYG (%d)\n" #: ..//src/mesh/impls/bout/boutmesh.cxx:311 #, c-format msgid "\tCandidate value: %d\n" -msgstr "\tValor candidat: %d\n" +msgstr "\tValor candidato: %d\n" #: ..//src/bout++.cxx:390 msgid "\tChecking disabled\n" @@ -113,7 +113,7 @@ msgstr "\tParámetros de línea de comandos para esta ejecución :" #: ..//src/bout++.cxx:431 #, c-format msgid "\tCompiled with flags : %s\n" -msgstr "\tCompilado con los `flags` : %s\n" +msgstr "\tCompilado con las opciones `flags` : %s\n" #: ..//src/mesh/impls/bout/boutmesh.cxx:390 #, c-format @@ -187,7 +187,7 @@ msgid "" "\tOption %s = %s (%s) overwritten with:\n" "\t\t%s = %s (%s)\n" msgstr "" -"\tOpción %s = %s (%s) sobreescrita with:\n" +"\tOpción %s = %s (%s) sobreescrita con:\n" "\t\t%s = %s (%s)\n" #: ..//src/sys/options.cxx:226 @@ -210,7 +210,7 @@ msgstr "\tSoporte para NetCDF paralelo activado\n" #: ..//src/mesh/impls/bout/boutmesh.cxx:124 msgid "\tRead nz from input grid file\n" -msgstr "\tLeer nz del archivo malla `grid`de entrada\n" +msgstr "\tLeer nz del archivo input de la malla `grid`\n" #: ..//src/mesh/mesh.cxx:124 msgid "\tReading contravariant vector " @@ -307,7 +307,7 @@ msgstr "" #: ..//src/sys/options.cxx:248 msgid "All options used\n" -msgstr "Todas las opciones usadas\n" +msgstr "Usando todas las opciones\n" #. / Print intro #: ..//src/bout++.cxx:368 @@ -330,7 +330,7 @@ msgid "" "Code compiled on %s at %s\n" "\n" msgstr "" -"Código compilado en %s a %s\n" +"Código compilado en %s en %s\n" "\n" #: ..//src/sys/optionsreader.cxx:142 @@ -429,7 +429,7 @@ msgstr "Error durante el paso de opciones" #: ..//src/mesh/impls/bout/boutmesh.cxx:147 #, c-format msgid "Error: nx must be greater than 2 times MXG (2 * %d)" -msgstr "Error: nx debe mayor que 2 veces MXG (2 * %d)" +msgstr "Error: nx debe ser mayor que 2 veces MXG (2 * %d)" #: ..//src/solver/solver.cxx:528 msgid "Failed to initialise solver-> Aborting\n" @@ -487,13 +487,13 @@ msgstr "Sin regiones de frontera en este procesador" #: ..//src/mesh/impls/bout/boutmesh.cxx:234 #, c-format msgid "Number of processors (%d) not divisible by NPs in x direction (%d)\n" -msgstr "Número de procesadores (%d) no divisible para NPs in la dirección x (%d)\n" +msgstr "Número de procesadores (%d) no divisible para NPs en la dirección x (%d)\n" #. Less than 1 time-step left #: ..//src/bout++.cxx:707 #, c-format msgid "Only %e seconds left. Quitting\n" -msgstr "Solo faltan %e segundos. Suspendiendo\n" +msgstr "Solo faltan %e segundos. Saliendo\n" #: ..//src/sys/options.cxx:130 ..//src/sys/options.cxx:148 #: ..//src/sys/options.cxx:184 ..//src/sys/options.cxx:212 @@ -518,7 +518,8 @@ msgid "" "Options: Setting a value from same source (%s) to new value '%s' - old value " "was '%s'." msgstr "" -"Opciones: Cambiando valor de la misma fuente (%s) al valor nuevo '%s' - valor anterior era '%s'." +"Opciones: Cambiando valor de la misma fuente (%s) al valor nuevo '%s' - valor anterior " +"era '%s'." #: ..//src/bout++.cxx:379 #, c-format From b7dbe1c8a2e996f8f6329d2a4979b8798cd76aa2 Mon Sep 17 00:00:00 2001 From: Marta Estarellas Date: Mon, 11 Feb 2019 15:55:10 +0900 Subject: [PATCH 0735/1783] Error on file corrected --- locale/spa/libbout.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locale/spa/libbout.po b/locale/spa/libbout.po index 28125c4de1..87fe2dd7ee 100644 --- a/locale/spa/libbout.po +++ b/locale/spa/libbout.po @@ -77,7 +77,7 @@ msgid "" "\t -> leg region ny_inner-jyseps2_1-1 (%d-%d-1 = %d) must be a multiple of " "MYSUB (%d)\n" msgstr "" -"\t -> La región `Leg` nyi_inner-jyseps2_1-1 (%d-%d-1 = %d) debe ser un múltiplo de " +"\t -> La región `Leg` ny_inner-jyseps2_1-1 (%d-%d-1 = %d) debe ser un múltiplo de " "MYSUB (%d)\n" #: ..//src/mesh/impls/bout/boutmesh.cxx:318 From 21c297a11c456c31787fc6b66ca87fe5b53ce895 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 11 Feb 2019 17:10:29 +0000 Subject: [PATCH 0736/1783] A couple of experimental codecov tweaks - `-a '-r'`: don't generate coverage for system headers. Might make the coverage a little bit faster - `-X fix`: don't apply fixes -- might improve accuracy of reports? Note for Travis: build coverage --- .travis_script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis_script.sh b/.travis_script.sh index b8595e086e..05226830d1 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -116,7 +116,7 @@ then find . -name "*.gcno" -exec sh -c 'touch -a "${1%.gcno}.gcda"' _ {} \; #Upload for codecov - bash <(curl -s https://codecov.io/bash) + bash <(curl -s https://codecov.io/bash) -a '-r' -X fix #For codacy bash ./.codacy_coverage.sh From a585b1a8f7fda492d5539871b334b05f44f84994 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 11 Feb 2019 17:30:09 +0000 Subject: [PATCH 0737/1783] Update Travis to xenial --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 479c4a94c2..8e4296d07a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ sudo: required -dist: trusty +dist: xenial language: cpp compiler: gcc From 285624ab0d40f076b16eb12476a19e00c732fc08 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 11 Feb 2019 17:38:41 +0000 Subject: [PATCH 0738/1783] Use latest numpy --- .pip_install_for_travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pip_install_for_travis.sh b/.pip_install_for_travis.sh index 59b0392757..4bec6b4f00 100755 --- a/.pip_install_for_travis.sh +++ b/.pip_install_for_travis.sh @@ -1,7 +1,7 @@ #!/bin/bash export PATH=${HOME}/.local/bin:${PATH} pip3 install --user --upgrade pip==18.1 setuptools==40.6.3 -pip3 install --user --upgrade scipy==1.2.0 numpy==1.15 +pip3 install --user --upgrade scipy==1.2 numpy==1.16 for package in $@ do if test $package == "cython" From f8932cb0e1404062c738113c40bb875f58bd0455 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 11 Feb 2019 17:38:52 +0000 Subject: [PATCH 0739/1783] Install NetCDF C++ API --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 8e4296d07a..77a6b8f7d6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ addons: packages: &standard_packages - libfftw3-dev - libnetcdf-dev + - libnetcdf-c++4-dev - netcdf-bin - hdf5-tools - python3 From 466c93e08f75ffdb98903d4625caaf924aae1caa Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 12 Feb 2019 10:07:51 +0000 Subject: [PATCH 0740/1783] Remove CXXFLAGS specialisation from gcc-7 build Now using more recent openmpi version so we don't get spurious warnings any more --- .travis.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 77a6b8f7d6..efc137923e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,11 +45,6 @@ matrix: - CONFIGURE_OPTIONS='--enable-debug' - CC=gcc-7 CXX=g++-7 - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" - #The -Wno-literal-suffix flag in CXXFLAGS above is a temporary workaround to - #disable a noisy message arising from the relatively old version of openmpi - #in use in combination with the relatively new version of gcc. We should be able - #to remove this if a newer openmpi version is introduced. - - CXXFLAGS="-Wno-literal-suffix -Wall -Wextra" - env: - *default_env - CONFIGURE_OPTIONS='--enable-shared' From acaf5beec0674afbac32321ad362e5a82b969305 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 12 Feb 2019 10:09:38 +0000 Subject: [PATCH 0741/1783] Install PETSc and SLEPc by default, build with them for most jobs --- .travis.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index efc137923e..6f18e078c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,14 +25,20 @@ addons: - libhdf5-mpi-dev - openmpi-bin - libopenmpi-dev + - libpetsc3.6.2-dev + - libslepc3.6.2-dev matrix: fast_finish: true include: - env: &default_env - - CONFIGURE_OPTIONS='--enable-checks=no --enable-optimize=3 --disable-signal --disable-track --disable-backtrace' + - CONFIGURE_OPTIONS='--enable-checks=no --enable-optimize=3 --disable-signal --disable-track --disable-backtrace --with-petsc --with-slepc' - SCRIPT_FLAGS='-uim' - PIP_PACKAGES='cython netcdf4 sympy' + - PETSC_DIR=/usr/lib/petscdir/3.6.2 + - PETSC_ARCH=x86_64-linux-gnu-real + - SLEPC_DIR=/usr/lib/slepcdir/3.6.2 + - SLEPC_ARCH=x86_64-linux-gnu-real - addons: apt: sources: @@ -42,21 +48,21 @@ matrix: - *standard_packages env: - *default_env - - CONFIGURE_OPTIONS='--enable-debug' + - CONFIGURE_OPTIONS='--enable-debug --with-petsc --with-slepc' - CC=gcc-7 CXX=g++-7 - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" - env: - *default_env - - CONFIGURE_OPTIONS='--enable-shared' + - CONFIGURE_OPTIONS='--enable-shared --with-petsc --with-slepc' - SCRIPT_FLAGS="-uim -t python -t shared" - env: - *default_env - - CONFIGURE_OPTIONS='--enable-openmp' + - CONFIGURE_OPTIONS='--enable-openmp --with-petsc --with-slepc' - OMP_NUM_THREADS=2 #CLANG - env: - *default_env - - CONFIGURE_OPTIONS='--enable-debug' + - CONFIGURE_OPTIONS='--enable-debug --with-petsc --with-slepc' - MPICH_CC=clang MPICH_CXX=clang++ - OMPI_CC=clang OMPI_CXX=clang++ compiler: clang @@ -66,18 +72,12 @@ matrix: apt: packages: - *standard_packages - - libpetsc3.4.2-dev - - libslepc3.4.2-dev - liblapack-dev - libparpack2-dev - jq env: - CONFIGURE_OPTIONS='--enable-code-coverage --enable-debug --enable-track --enable-checks=3 --with-petsc --with-lapack --with-slepc --enable-openmp' - OMP_NUM_THREADS=2 - - PETSC_DIR=/usr/lib/petscdir/3.4.2 - - PETSC_ARCH=linux-gnu-c-opt - - SLEPC_DIR=/usr/lib/slepcdir/3.4.2 - - SLEPC_ARCH=linux-gnu-c-opt - SCRIPT_FLAGS='-cu' - PIP_PACKAGES='gcovr' - secure: "M5U3I81hzK41Kw7KB+DpEMxP/sgkWkFI4uiRZQDMDFRlhcitsJQQ/YGeBt3a0vo153m2P2PmmeKUl/lTo5WS5SfAVFI8BkcyBjpxZQXV3OD8ru7JsMgVc5pGwl2dvR8Qz02gUIbrIpAlf3YDnNVb6F1C9ofDaCnZU3GUTLH5Fy5z5Z8OpuTaLmTVMMnT2ZEcRawHbmlVhIB/9PUQUa+fM7iC+dtszFxZ2ma5LOHxPS2sGpRCKE5Sae1/xAFWjo4oO0ZqYu5JFvKdb+/2yWKTg/1aTyxCdqAzLg4ldzDlX759zXgtWn+k3TLiVyQ+gsvF8QZkh4BKvl/w2KZ20vRP3blzmxvdsSH+ZP92MZIIK9EkNPGd+UJJd5Hu+zwecEFyfO8bXB9l00kzUsVx+lo7VHbANuNO3b5a6FRiihTCgk+dfOxxrow/fci+lQ9BkmJg0680SIj2e6UM/P9lFgfQLH3IoacN1PtkyqnpJqdHUdbWmpqMtmitmQhXHjnJ+wDb5+i9b1fy5yEsB64rjgF9PBr1/Nos1XD4oGWAknXmQTgWhNyy6f+e0wBNcSUd5nrReLTOAscyXYpcTqONp1W999JSFQEH+YTwBfXytdkWaAGAFEhaaAXQ2jCwHO7jl/TODPfSeZgXkQiT5jgg63i5tlPB4Xn0MTSCX74bYIi16Tk=" From 31f8b056b320e7f576804b3baf8f466b1ff75e45 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 12 Feb 2019 10:14:23 +0000 Subject: [PATCH 0742/1783] Fix slepc version --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6f18e078c5..6e4aef5e37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ addons: - openmpi-bin - libopenmpi-dev - libpetsc3.6.2-dev - - libslepc3.6.2-dev + - libslepc3.6.1-dev matrix: fast_finish: true From ad84d86c487a26ab465df56930757db1ec2def70 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 12 Feb 2019 10:25:51 +0000 Subject: [PATCH 0743/1783] Fix petsc/slepc paths --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6e4aef5e37..136aad4f14 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,10 +35,10 @@ matrix: - CONFIGURE_OPTIONS='--enable-checks=no --enable-optimize=3 --disable-signal --disable-track --disable-backtrace --with-petsc --with-slepc' - SCRIPT_FLAGS='-uim' - PIP_PACKAGES='cython netcdf4 sympy' - - PETSC_DIR=/usr/lib/petscdir/3.6.2 - - PETSC_ARCH=x86_64-linux-gnu-real - - SLEPC_DIR=/usr/lib/slepcdir/3.6.2 - - SLEPC_ARCH=x86_64-linux-gnu-real + - PETSC_DIR=/usr/lib/petscdir/3.6.2/x86_64-linux-gnu-real + - PETSC_ARCH= + - SLEPC_DIR=/usr/lib/slepcdir/3.6.1/x86_64-linux-gnu-real + - SLEPC_ARCH= - addons: apt: sources: From 65aee4b233fab27e2d5548cf094c8a3e5c8ee78c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 12 Feb 2019 10:38:58 +0000 Subject: [PATCH 0744/1783] Always install lapack/parpack --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 136aad4f14..8efce85a6c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,8 @@ addons: - libopenmpi-dev - libpetsc3.6.2-dev - libslepc3.6.1-dev + - liblapack-dev + - libparpack2-dev matrix: fast_finish: true @@ -72,8 +74,6 @@ matrix: apt: packages: - *standard_packages - - liblapack-dev - - libparpack2-dev - jq env: - CONFIGURE_OPTIONS='--enable-code-coverage --enable-debug --enable-track --enable-checks=3 --with-petsc --with-lapack --with-slepc --enable-openmp' From 938c4657f14139ffcbee2a5a313d4db9c2fe214c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Mon, 11 Feb 2019 12:53:16 +0000 Subject: [PATCH 0745/1783] Avoid out-of-range access for invalid regions --- src/sys/bout_types.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index 319be896a0..8a5a1f675e 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -1,5 +1,5 @@ #include - +#include #include const std::string& CELL_LOC_STRING(CELL_LOC location) { @@ -20,6 +20,7 @@ const std::string& DIFF_METHOD_STRING(DIFF_METHOD location) { } const std::string& REGION_STRING(REGION region) { + ASSERT2(region >= 0 && region <= 4); const static std::map REGIONtoString = { ENUMSTR(RGN_ALL), ENUMSTR(RGN_NOBNDRY), ENUMSTR(RGN_NOX), ENUMSTR(RGN_NOY), ENUMSTR(RGN_NOZ)}; From de0a8c64b002e02d567bb969ce9bcd255a5dfee2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 12 Feb 2019 11:55:57 +0000 Subject: [PATCH 0746/1783] Make gcov files for unit test files correctly Involves abusing the codecov "gcov_args" argument build coverage --- .travis_script.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.travis_script.sh b/.travis_script.sh index 05226830d1..1bc214edeb 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -115,8 +115,15 @@ then # It still won't include, e.g. any solvers we don't build with though find . -name "*.gcno" -exec sh -c 'touch -a "${1%.gcno}.gcda"' _ {} \; - #Upload for codecov - bash <(curl -s https://codecov.io/bash) -a '-r' -X fix + # Upload for codecov. Slightly hacky: for each source file, + # codecov runs gcov in that directory (i.e. essentially `cd + # src/sys && gcov utils.cxx`). This is mostly fine, but it seems + # we also need to run it just in the unit tests directory for each + # for of the unit test sources (i.e. `cd tests/unit/; gcov + # sys/test_utils.cxx`). This is the difference between the + # `-execdir` and `-exec` arguments to `find` + bash <(curl -s https://codecov.io/bash) -X fix |\ + -a '-r {} +; find ./tests/unit -type f -name '*.gcno' -exec gcov -pbr {} +' #For codacy bash ./.codacy_coverage.sh From e9938224a5739749cb9832e3723ab825c5d216b9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 12 Feb 2019 12:43:56 +0000 Subject: [PATCH 0747/1783] Fix typo in codecov uploader build coverage --- .travis_script.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis_script.sh b/.travis_script.sh index 1bc214edeb..3b206002a2 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -122,8 +122,8 @@ then # for of the unit test sources (i.e. `cd tests/unit/; gcov # sys/test_utils.cxx`). This is the difference between the # `-execdir` and `-exec` arguments to `find` - bash <(curl -s https://codecov.io/bash) -X fix |\ - -a '-r {} +; find ./tests/unit -type f -name '*.gcno' -exec gcov -pbr {} +' + bash <(curl -s https://codecov.io/bash) -X fix \ + -a '-r {} +; find ./tests/unit -type f -name "*.gcno" -exec gcov -pbr {} +' #For codacy bash ./.codacy_coverage.sh From c85466c87b83f20ac25106f629a7c0ec5c4acf64 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 12 Feb 2019 14:39:58 +0000 Subject: [PATCH 0748/1783] Use lcov to generate report for codecov.io; gcov for codacy build coverage --- .codacy_coverage.sh | 7 +++++++ .travis_script.sh | 12 +++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.codacy_coverage.sh b/.codacy_coverage.sh index c2c95088b7..91424eeaa1 100644 --- a/.codacy_coverage.sh +++ b/.codacy_coverage.sh @@ -1,6 +1,13 @@ #First install the reporter tool wget -q -O ~/codacy-coverage-reporter-assembly-latest.jar https://oss.sonatype.org/service/local/repositories/releases/content/com/codacy/codacy-coverage-reporter/4.0.1/codacy-coverage-reporter-4.0.1-assembly.jar > /dev/null +# Create all the .gcov files +# Run gcov in the same directory as the source file for the main +# library (because we used recursive make) +find . -type f -name *.gcno -execdir gcov -pb -r {} + +# but just in the unit tests top-level dir as we ran make from there +find tests/unit -type f -name *.gcno -exec gcov -pb -r {} + + #Analyse the existing gcov files and output in compatible xml format #The -g option says to use the existing gcov files, the -k options says to not delete the gcov files #The -j option is like make's -j diff --git a/.travis_script.sh b/.travis_script.sh index 3b206002a2..74d75e1ef7 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -115,15 +115,9 @@ then # It still won't include, e.g. any solvers we don't build with though find . -name "*.gcno" -exec sh -c 'touch -a "${1%.gcno}.gcda"' _ {} \; - # Upload for codecov. Slightly hacky: for each source file, - # codecov runs gcov in that directory (i.e. essentially `cd - # src/sys && gcov utils.cxx`). This is mostly fine, but it seems - # we also need to run it just in the unit tests directory for each - # for of the unit test sources (i.e. `cd tests/unit/; gcov - # sys/test_utils.cxx`). This is the difference between the - # `-execdir` and `-exec` arguments to `find` - bash <(curl -s https://codecov.io/bash) -X fix \ - -a '-r {} +; find ./tests/unit -type f -name "*.gcno" -exec gcov -pbr {} +' + # Use lcov to generate a report, upload it to codecov.io + make code-coverage-capture + bash <(curl -s https://codecov.io/bash) -f bout-coverage.info #For codacy bash ./.codacy_coverage.sh From d0dd4493e71bada01a98eea0dbecf8496823e555 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Feb 2019 17:01:28 +0000 Subject: [PATCH 0749/1783] Delete removed test from .gitignore --- tests/integrated/.gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/integrated/.gitignore b/tests/integrated/.gitignore index aa89de85ca..83c02288ce 100644 --- a/tests/integrated/.gitignore +++ b/tests/integrated/.gitignore @@ -36,4 +36,3 @@ BOUT.settings /test-stopCheck/test_stopCheck /test-yupdown/test_yupdown /test-coordinates-initialization/test-coordinates-initialization -/test-coordinates-initialization2/test-coordinates-initialization From 43745f64b00621e3764014f6cb5fa1f6221f0988 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Feb 2019 17:26:44 +0000 Subject: [PATCH 0750/1783] Revert commenting-out of staggered coordinates initialization Change to BoutMesh::load() should not have been committed. --- src/mesh/impls/bout/boutmesh.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 1ac4e3fb97..eccea69cc2 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -844,13 +844,13 @@ int BoutMesh::load() { getCoordinates(CELL_CENTRE); if (StaggerGrids) { if (xstart >= 2) { - //getCoordinates(CELL_XLOW); + getCoordinates(CELL_XLOW); } if (ystart >= 2) { getCoordinates(CELL_YLOW); } if (LocalNz > 3) { - //getCoordinates(CELL_ZLOW); + getCoordinates(CELL_ZLOW); } } From 1cb55e13e6732f23d9f1c34bb818848c6a5d4885 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Feb 2019 18:51:14 +0000 Subject: [PATCH 0751/1783] Fix ShiftedMetric unit test Need to set number of y-guard cells to 2 before creating default regions. Otherwise BOUT_FOR loops go out of bounds. --- tests/unit/mesh/parallel/test_shiftedmetric.cxx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 37d13f6179..9904344eef 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -22,6 +22,11 @@ class ShiftedMetricTest : public ::testing::Test { mesh = nullptr; } mesh = new FakeMesh(nx, ny, nz); + + // Use two y-guards to test multiple parallel slices + mesh->ystart = 2; + mesh->yend = mesh->LocalNy - 3; + output_info.disable(); mesh->createDefaultRegions(); output_info.enable(); @@ -151,10 +156,6 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { } TEST_F(ShiftedMetricTest, CalcYUpDown) { - // Use two y-guards to test multiple parallel slices - mesh->ystart = 2; - mesh->yend = mesh->LocalNy - 3; - // We don't shift in the guard cells, and the parallel slices are // stored offset in y, therefore we need to make new regions that we // can compare the expected and actual outputs over From 2804b2857a0835002d7a55da3b2f1ebe751ee70c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Feb 2019 19:38:34 +0000 Subject: [PATCH 0752/1783] Read dx and dy when reading staggered Coordinates from grid Also set nz and dz from coords_in for both cases: reading from file or interpolating. nz and dz are scalars, so don't depend on staggering. --- src/mesh/coordinates.cxx | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index d88acdab99..80bde6fbbd 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -272,7 +272,30 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor } } + nz = mesh->LocalNz; + + dz = coords_in->dz; + if (!force_interpolate_from_centre && mesh->sourceHasVar("dx"+suffix)) { + + if (mesh->get(dx, "dx"+suffix)) { + output_warn.write( + "\tWARNING: differencing quantity 'dx%s' not found. Set to 1.0\n", suffix); + dx = 1.0; + } + dx.setLocation(location); + + if (mesh->periodicX) { + mesh->communicate(dx); + } + + if (mesh->get(dy, "dy"+suffix)) { + output_warn.write( + "\tWARNING: differencing quantity 'dy%s' not found. Set to 1.0\n", suffix); + dy = 1.0; + } + dy.setLocation(location); + // grid data source has staggered fields, so read instead of interpolating // Diagonal components of metric tensor g^{ij} (default to 1) mesh->get(g11, "g11"+suffix, 1.0); @@ -351,10 +374,6 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor dx = interpolateAndNeumann(coords_in->dx, location); dy = interpolateAndNeumann(coords_in->dy, location); - nz = mesh->LocalNz; - - dz = coords_in->dz; - // Diagonal components of metric tensor g^{ij} g11 = interpolateAndNeumann(coords_in->g11, location); g22 = interpolateAndNeumann(coords_in->g22, location); From 8dbb7f0c6915b256710500454f9628e9adef2a18 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Feb 2019 19:55:39 +0000 Subject: [PATCH 0753/1783] Check consistency of grid file when reading staggered fields If reading staggered fields for Coordinates from a grid, all fields that are there for CELL_CENTRE must be present for the staggered location (same name but with suffix "_xlow" or "_ylow"). --- src/mesh/coordinates.cxx | 61 +++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 80bde6fbbd..482c718896 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -236,6 +236,24 @@ namespace { return result; } + + // If the CELL_CENTRE variable was read, the staggered version is required to + // also exist for consistency + void checkStaggeredGet(Mesh* mesh, std::string name, std::string suffix) { + if (mesh->sourceHasVar(name) != mesh->sourceHasVar(name+suffix)) { + throw BoutException("Attempting to read staggered fields from grid, but " + name + + " is not present in both CELL_CENTRE and staggered versions."); + } + } + + // convenience function for repeated code + void getAtLoc(Mesh* mesh, Field2D &var, std::string name, std::string suffix, + CELL_LOC location, BoutReal default_value = 0.) { + + checkStaggeredGet(mesh, name, suffix); + mesh->get(var, name+suffix, default_value); + var.setLocation(location); + } } Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coords_in, @@ -278,6 +296,7 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor if (!force_interpolate_from_centre && mesh->sourceHasVar("dx"+suffix)) { + checkStaggeredGet(mesh, "dx", suffix); if (mesh->get(dx, "dx"+suffix)) { output_warn.write( "\tWARNING: differencing quantity 'dx%s' not found. Set to 1.0\n", suffix); @@ -289,6 +308,7 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor mesh->communicate(dx); } + checkStaggeredGet(mesh, "dy", suffix); if (mesh->get(dy, "dy"+suffix)) { output_warn.write( "\tWARNING: differencing quantity 'dy%s' not found. Set to 1.0\n", suffix); @@ -298,20 +318,12 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor // grid data source has staggered fields, so read instead of interpolating // Diagonal components of metric tensor g^{ij} (default to 1) - mesh->get(g11, "g11"+suffix, 1.0); - g11.setLocation(location); - mesh->get(g22, "g22"+suffix, 1.0); - g22.setLocation(location); - mesh->get(g33, "g33"+suffix, 1.0); - g33.setLocation(location); - - // Off-diagonal elements. Default to 0 - mesh->get(g12, "g12"+suffix, 0.0); - g12.setLocation(location); - mesh->get(g13, "g13"+suffix, 0.0); - g13.setLocation(location); - mesh->get(g23, "g23"+suffix, 0.0); - g23.setLocation(location); + getAtLoc(mesh, g11, "g11", suffix, location, 1.0); + getAtLoc(mesh, g22, "g22", suffix, location, 1.0); + getAtLoc(mesh, g33, "g33", suffix, location, 1.0); + getAtLoc(mesh, g12, "g12", suffix, location, 0.0); + getAtLoc(mesh, g13, "g13", suffix, location, 0.0); + getAtLoc(mesh, g23, "g23", suffix, location, 0.0); /// Find covariant metric components // Check if any of the components are present @@ -322,18 +334,13 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor if (mesh->sourceHasVar("g_11"+suffix) and mesh->sourceHasVar("g_22"+suffix) and mesh->sourceHasVar("g_33"+suffix) and mesh->sourceHasVar("g_12"+suffix) and mesh->sourceHasVar("g_13"+suffix) and mesh->sourceHasVar("g_23"+suffix)) { - mesh->get(g_11, "g_11"+suffix); - g_11.setLocation(location); - mesh->get(g_22, "g_22"+suffix); - g_22.setLocation(location); - mesh->get(g_33, "g_33"+suffix); - g_33.setLocation(location); - mesh->get(g_12, "g_12"+suffix); - g_12.setLocation(location); - mesh->get(g_13, "g_13"+suffix); - g_13.setLocation(location); - mesh->get(g_23, "g_23"+suffix); - g_23.setLocation(location); + + getAtLoc(mesh, g_11, "g_11", suffix, location); + getAtLoc(mesh, g_22, "g_22", suffix, location); + getAtLoc(mesh, g_33, "g_33", suffix, location); + getAtLoc(mesh, g_12, "g_12", suffix, location); + getAtLoc(mesh, g_13, "g_13", suffix, location); + getAtLoc(mesh, g_23, "g_23", suffix, location); output_warn.write("\tWARNING! Staggered covariant components of metric tensor set manually. " "Contravariant components NOT recalculated\n"); @@ -353,6 +360,7 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor } } + checkStaggeredGet(mesh, "ShiftTorsion", suffix); if (mesh->get(ShiftTorsion, "ShiftTorsion"+suffix)) { output_warn.write("\tWARNING: No Torsion specified for zShift. Derivatives may not be correct\n"); ShiftTorsion = 0.0; @@ -362,6 +370,7 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor ////////////////////////////////////////////////////// if (mesh->IncIntShear) { + checkStaggeredGet(mesh, "IntShiftTorsion", suffix); if (mesh->get(IntShiftTorsion, "IntShiftTorsion"+suffix)) { output_warn.write("\tWARNING: No Integrated torsion specified\n"); IntShiftTorsion = 0.0; From dfb5215ebdc5695a757ee473edb6a72f9724f40c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Feb 2019 20:03:55 +0000 Subject: [PATCH 0754/1783] Move Mesh checks to FCIMap methods FCITransform does not store a Mesh reference, so don't check the mesh of the input field in FCITransform methods. The mesh of the field is checked in the FCIMap methods that are called by the FCITransform methods anyway. --- src/mesh/parallel/fci.cxx | 6 +----- src/mesh/parallel/fci.hxx | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index ff6435ae1c..825eb1dfca 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -256,7 +256,7 @@ FCIMap::FCIMap(Mesh& mesh, int offset_, BoundaryRegionPar* boundary, bool zperio Field3D FCIMap::integrate(Field3D &f) const { TRACE("FCIMap::integrate"); - ASSERT3(&map_mesh == f.getMesh()); + ASSERT1(&map_mesh == f.getMesh()); // Cell centre values Field3D centre = interp->interpolate(f); @@ -316,8 +316,6 @@ Field3D FCIMap::integrate(Field3D &f) const { void FCITransform::calcYUpDown(Field3D& f) { TRACE("FCITransform::calcYUpDown"); - ASSERT1(f.getMesh() == &mesh); - // Only have forward_map/backward_map for CELL_CENTRE, so can only deal with // CELL_CENTRE inputs ASSERT1(f.getLocation() == CELL_CENTRE); @@ -334,8 +332,6 @@ void FCITransform::calcYUpDown(Field3D& f) { void FCITransform::integrateYUpDown(Field3D& f) { TRACE("FCITransform::integrateYUpDown"); - ASSERT1(f.getMesh() == &mesh); - // Only have forward_map/backward_map for CELL_CENTRE, so can only deal with // CELL_CENTRE inputs ASSERT1(f.getLocation() == CELL_CENTRE); diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index 37a87a96e6..5d987c20e0 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -58,7 +58,7 @@ public: BoutMask corner_boundary_mask; Field3D interpolate(Field3D& f) const { - ASSERT3(&map_mesh == f.getMesh()); + ASSERT1(&map_mesh == f.getMesh()); return interp->interpolate(f); } From 70c270fd8b7f544b7c72b0d8fb28d04a83a4d4b3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Feb 2019 20:55:59 +0000 Subject: [PATCH 0755/1783] Pass const char* instead of std::string to output_warn.write() --- src/mesh/coordinates.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 482c718896..1315750718 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -299,7 +299,7 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor checkStaggeredGet(mesh, "dx", suffix); if (mesh->get(dx, "dx"+suffix)) { output_warn.write( - "\tWARNING: differencing quantity 'dx%s' not found. Set to 1.0\n", suffix); + "\tWARNING: differencing quantity 'dx%s' not found. Set to 1.0\n", suffix.c_str()); dx = 1.0; } dx.setLocation(location); @@ -311,7 +311,7 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor checkStaggeredGet(mesh, "dy", suffix); if (mesh->get(dy, "dy"+suffix)) { output_warn.write( - "\tWARNING: differencing quantity 'dy%s' not found. Set to 1.0\n", suffix); + "\tWARNING: differencing quantity 'dy%s' not found. Set to 1.0\n", suffix.c_str()); dy = 1.0; } dy.setLocation(location); From e1857ec05183461f9a819645011c9fb845058819 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Feb 2019 21:02:03 +0000 Subject: [PATCH 0756/1783] Fix ShiftedMetric unit test: use RGN_ALL explicitly RGN_ALL is no longer the default for toFieldAligned/fromFieldAligned. Force it to be used for the unit test. --- tests/unit/mesh/parallel/test_shiftedmetric.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 9904344eef..cf164f0fd9 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -117,7 +117,7 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { {4., 5., 1., 2., 3.}, {2., 3., 4., 5., 1.}}}); - EXPECT_TRUE(IsFieldEqual(shifted.toFieldAligned(input), expected, "RGN_ALL", + EXPECT_TRUE(IsFieldEqual(shifted.toFieldAligned(input, RGN_ALL), expected, "RGN_ALL", FFTTolerance)); } @@ -151,7 +151,7 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { {5., 1., 2., 3., 4.}}}); // Loosen tolerance a bit due to FFTs - EXPECT_TRUE(IsFieldEqual(shifted.fromFieldAligned(input), expected, "RGN_ALL", + EXPECT_TRUE(IsFieldEqual(shifted.fromFieldAligned(input, RGN_ALL), expected, "RGN_ALL", FFTTolerance)); } From 52b6b7edd41e79f450daf0677347fa6658c7bc40 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 13 Feb 2019 10:16:49 +0000 Subject: [PATCH 0757/1783] Use Matrix> instead of Tensor for f_fft Prevents errors with OpenMP. --- src/mesh/parallel/shiftedmetric.cxx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 9ca5f79c96..6c6670133c 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -182,10 +182,12 @@ ShiftedMetric::shiftZ(const Field3D& f, const int nmodes = mesh.LocalNz / 2 + 1; // FFT in Z of input field at each (x, y) point - Tensor f_fft(mesh.LocalNx, mesh.LocalNy, nmodes); + Matrix< Array > f_fft(mesh.LocalNx, mesh.LocalNy); + f_fft = Array(nmodes); BOUT_FOR(i, mesh.getRegion2D("RGN_ALL")) { - rfft(&f(i, 0), mesh.LocalNz, &f_fft(i.x(), i.y(), 0)); + f_fft(i.x(), i.y()).ensureUnique(); + rfft(&f(i, 0), mesh.LocalNz, f_fft(i.x(), i.y()).begin()); } std::vector results{}; @@ -200,11 +202,11 @@ ShiftedMetric::shiftZ(const Field3D& f, BOUT_FOR(i, mesh.getRegion2D("RGN_NOY")) { // Deep copy the FFT'd field - Array shifted_temp(nmodes); + Array shifted_temp(f_fft(i.x(), i.y())); + shifted_temp.ensureUnique(); for (int jz = 1; jz < nmodes; ++jz) { - shifted_temp[jz] = f_fft(i.x(), i.y() + phase.y_offset, jz) - * phase.phase_shift(i.x(), i.y(), jz); + shifted_temp[jz] *= phase.phase_shift(i.x(), i.y(), jz); } irfft(shifted_temp.begin(), mesh.LocalNz, From d2e06beae591bb2e8cc5e2b95781f34ac818066f Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 13 Feb 2019 11:37:43 +0000 Subject: [PATCH 0758/1783] Move specific derivative methods from header into source file This allows the header to be included more than once across the project --- include/bout/index_derivs.hxx | 491 --------------------------------- src/mesh/index_derivs.cxx | 492 ++++++++++++++++++++++++++++++++++ 2 files changed, 492 insertions(+), 491 deletions(-) diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index a86ca1c67e..801adde70b 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -312,496 +312,5 @@ struct registerMethod { #define REGISTER_FLUX_DERIVATIVE_STAGGERED(name, key, nGuards, type) \ REGISTER_FLUX_STAGGERED_DERIVATIVE(name, key, nGuards, type) -////////////////////// FIRST DERIVATIVES ///////////////////// - -/// central, 2nd order -REGISTER_STANDARD_DERIVATIVE(DDX_C2, "C2", 1, DERIV::Standard) { - return 0.5 * (f.p - f.m); -}; - -/// central, 4th order -REGISTER_STANDARD_DERIVATIVE(DDX_C4, "C4", 2, DERIV::Standard) { - return (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; -} - -/// Central WENO method, 2nd order (reverts to 1st order near shocks) -REGISTER_STANDARD_DERIVATIVE(DDX_CWENO2, "W2", 1, DERIV::Standard) { - BoutReal isl, isr, isc; // Smoothness indicators - BoutReal al, ar, ac, sa; // Un-normalised weights - BoutReal dl, dr, dc; // Derivatives using different stencils - - dc = 0.5 * (f.p - f.m); - dl = f.c - f.m; - dr = f.p - f.c; - - isl = SQ(dl); - isr = SQ(dr); - isc = (13. / 3.) * SQ(f.p - 2. * f.c + f.m) + 0.25 * SQ(f.p - f.m); - - al = 0.25 / SQ(WENO_SMALL + isl); - ar = 0.25 / SQ(WENO_SMALL + isr); - ac = 0.5 / SQ(WENO_SMALL + isc); - sa = al + ar + ac; - - return (al * dl + ar * dr + ac * dc) / sa; -} - -// Smoothing 2nd order derivative -REGISTER_STANDARD_DERIVATIVE(DDX_S2, "S2", 2, DERIV::Standard) { - - // 4th-order differencing - BoutReal result = (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; - - result += SIGN(f.c) * (f.pp - 4. * f.p + 6. * f.c - 4. * f.m + f.mm) / 12.; - - return result; -} - -/// Also CWENO3 but needs an upwind op so define later. - -////////////////////////////// -//--- Second order derivatives -////////////////////////////// - -/// Second derivative: Central, 2nd order -REGISTER_STANDARD_DERIVATIVE(D2DX2_C2, "C2", 1, DERIV::StandardSecond) { - return f.p + f.m - 2. * f.c; -} - -/// Second derivative: Central, 4th order -REGISTER_STANDARD_DERIVATIVE(D2DX2_C4, "C4", 2, DERIV::StandardSecond) { - return (-f.pp + 16. * f.p - 30. * f.c + 16. * f.m - f.mm) / 12.; -} - -////////////////////////////// -//--- Fourth order derivatives -////////////////////////////// -REGISTER_STANDARD_DERIVATIVE(D4DX4_C2, "C2", 2, DERIV::StandardFourth) { - return (f.pp - 4. * f.p + 6. * f.c - 4. * f.m + f.mm); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Upwind non-staggered methods -/// -/// Basic derivative methods. -/// All expect to have an input grid cell at the same location as the output -/// Hence convert cell centred values -> centred values, or left -> left -/// -//////////////////////////////////////////////////////////////////////////////// -std::tuple vUpDown(BoutReal v) { - return std::tuple{0.5 * (v + fabs(v)), 0.5 * (v - fabs(v))}; -} - -/// Upwinding: Central, 2nd order -REGISTER_UPWIND_DERIVATIVE(VDDX_C2, "C2", 1, DERIV::Upwind) { - return vc * 0.5 * (f.p - f.m); -} - -/// Upwinding: Central, 4th order -REGISTER_UPWIND_DERIVATIVE(VDDX_C4, "C4", 2, DERIV::Upwind) { - return vc * (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; -} - -/// upwind, 1st order -REGISTER_UPWIND_DERIVATIVE(VDDX_U1, "U1", 1, DERIV::Upwind) { // No vec - // Existing form doesn't vectorise due to branching - return vc >= 0.0 ? vc * (f.c - f.m) : vc * (f.p - f.c); - // Alternative form would but may involve more operations - const auto vSplit = vUpDown(vc); - return (std::get<0>(vSplit) * (f.p - f.c) + std::get<1>(vSplit) * (f.c - f.m)); -} - -/// upwind, 2nd order -REGISTER_UPWIND_DERIVATIVE(VDDX_U2, "U2", 2, DERIV::Upwind) { // No vec - // Existing form doesn't vectorise due to branching - return vc >= 0.0 ? vc * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) - : vc * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c); - // Alternative form would but may involve more operations - const auto vSplit = vUpDown(vc); - return (std::get<0>(vSplit) * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) - + std::get<1>(vSplit) * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c)); -} - -/// upwind, 3rd order -REGISTER_UPWIND_DERIVATIVE(VDDX_U3, "U3", 2, DERIV::Upwind) { // No vec - // Existing form doesn't vectorise due to branching - return vc >= 0.0 ? vc * (4. * f.p - 12. * f.m + 2. * f.mm + 6. * f.c) / 12. - : vc * (-4. * f.m + 12. * f.p - 2. * f.pp - 6. * f.c) / 12.; - // Alternative form would but may involve more operations - const auto vSplit = vUpDown(vc); - return (std::get<0>(vSplit) * (4. * f.p - 12. * f.m + 2. * f.mm + 6. * f.c) - + std::get<1>(vSplit) * (-4. * f.m + 12. * f.p - 2. * f.pp - 6. * f.c)) - / 12.; -} - -/// 3rd-order WENO scheme -REGISTER_UPWIND_DERIVATIVE(VDDX_WENO3, "W3", 2, DERIV::Upwind) { // No vec - BoutReal deriv, w, r; - // Existing form doesn't vectorise due to branching - - if (vc > 0.0) { - // Left-biased stencil - - r = (WENO_SMALL + SQ(f.c - 2.0 * f.m + f.mm)) - / (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); - - deriv = (-f.mm + 3. * f.m - 3. * f.c + f.p); - - } else { - // Right-biased - - r = (WENO_SMALL + SQ(f.pp - 2.0 * f.p + f.c)) - / (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); - - deriv = (-f.m + 3. * f.c - 3. * f.p + f.pp); - } - - w = 1.0 / (1.0 + 2.0 * r * r); - deriv = 0.5 * ((f.p - f.m) - w * deriv); - - return vc * deriv; -} - -///----------------------------------------------------------------- -/// 3rd-order CWENO. Uses the upwinding code and split flux -REGISTER_STANDARD_DERIVATIVE(DDX_CWENO3, "W3", 2, DERIV::Standard) { - BoutReal a, ma = fabs(f.c); - // Split flux - a = fabs(f.m); - if (a > ma) - ma = a; - a = fabs(f.p); - if (a > ma) - ma = a; - a = fabs(f.mm); - if (a > ma) - ma = a; - a = fabs(f.pp); - if (a > ma) - ma = a; - - stencil sp, sm; - - sp.mm = f.mm + ma; - sp.m = f.m + ma; - sp.c = f.c + ma; - sp.p = f.p + ma; - sp.pp = f.pp + ma; - - sm.mm = ma - f.mm; - sm.m = ma - f.m; - sm.c = ma - f.c; - sm.p = ma - f.p; - sm.pp = ma - f.pp; - - const VDDX_WENO3 upwindOp{}; - return upwindOp(0.5, sp) + upwindOp(-0.5, sm); -} - -//////////////////////////////////////////////////////////////////////////////// -/// Flux non-staggered methods -/// -/// Basic derivative methods. -/// All expect to have an input grid cell at the same location as the output -/// Hence convert cell centred values -> centred values, or left -> left -/// -//////////////////////////////////////////////////////////////////////////////// - -REGISTER_FLUX_DERIVATIVE(FDDX_U1, "U1", 1, DERIV::Flux) { // No vec - - // Velocity at lower end - BoutReal vs = 0.5 * (v.m + v.c); - BoutReal result = (vs >= 0.0) ? vs * f.m : vs * f.c; - // and at upper - vs = 0.5 * (v.c + v.p); - // Existing form doesn't vectorise due to branching - result -= (vs >= 0.0) ? vs * f.c : vs * f.p; - return -result; - - // Alternative form would but may involve more operations - const auto vSplit = vUpDown(vs); - return result - std::get<0>(vSplit) * f.c + std::get<1>(vSplit) * f.p; -} - -REGISTER_FLUX_DERIVATIVE(FDDX_C2, "C2", 2, DERIV::Flux) { - return 0.5 * (v.p * f.p - v.m * f.m); -} - -REGISTER_FLUX_DERIVATIVE(FDDX_C4, "C4", 2, DERIV::Flux) { - return (8. * v.p * f.p - 8. * v.m * f.m + v.mm * f.mm - v.pp * f.pp) / 12.; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Staggered methods -/// -/// Map Centre -> Low or Low -> Centre -/// -/// These expect the output grid cell to be at a different location to the input -/// -/// The stencil no longer has a value in 'C' (centre) -/// instead, points are shifted as follows: -/// -/// mm -> -3/2 h -/// m -> -1/2 h -/// p -> +1/2 h -/// pp -? +3/2 h -/// -/// NOTE: Cell widths (dx, dy, dz) are currently defined as centre->centre -/// for the methods above. This is currently not taken account of, so large -/// variations in cell size will cause issues. -//////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////// -/// Standard methods -- first order -//////////////////////////////////////////////////////////////////////////////// -REGISTER_STANDARD_DERIVATIVE_STAGGERED(DDX_C2_stag, "C2", 1, DERIV::Standard) { - return f.p - f.m; -} - -REGISTER_STANDARD_DERIVATIVE_STAGGERED(DDX_C4_stag, "C4", 2, DERIV::Standard) { - return (27. * (f.p - f.m) - (f.pp - f.mm)) / 24.; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Standard methods -- second order -//////////////////////////////////////////////////////////////////////////////// -REGISTER_STANDARD_DERIVATIVE_STAGGERED(D2DX2_C2_stag, "C2", 2, DERIV::StandardSecond) { - return (f.pp + f.mm - f.p - f.m) / 2.; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Upwind methods -//////////////////////////////////////////////////////////////////////////////// -REGISTER_UPWIND_DERIVATIVE_STAGGERED(VDDX_U1_stag, "U1", 1, DERIV::Upwind) { - // Lower cell boundary - BoutReal result = (v.m >= 0) ? v.m * f.m : v.m * f.c; - - // Upper cell boundary - result -= (v.p >= 0) ? v.p * f.c : v.p * f.p; - result *= -1; - - // result is now d/dx(v*f), but want v*d/dx(f) so subtract f*d/dx(v) - result -= f.c * (v.p - v.m); - return result; -} - -REGISTER_UPWIND_DERIVATIVE_STAGGERED(VDDX_U2_stag, "U2", 2, DERIV::Upwind) { - // Calculate d(v*f)/dx = (v*f)[i+1/2] - (v*f)[i-1/2] - - // Upper cell boundary - BoutReal result = - (v.p >= 0.) ? v.p * (1.5 * f.c - 0.5 * f.m) : v.p * (1.5 * f.p - 0.5 * f.pp); - - // Lower cell boundary - result -= (v.m >= 0.) ? v.m * (1.5 * f.m - 0.5 * f.mm) : v.m * (1.5 * f.c - 0.5 * f.p); - - // result is now d/dx(v*f), but want v*d/dx(f) so subtract f*d/dx(v) - result -= f.c * (v.p - v.m); - - return result; -} - -REGISTER_UPWIND_DERIVATIVE_STAGGERED(VDDX_C2_stag, "C2", 1, DERIV::Upwind) { - // Result is needed at location of f: interpolate v to f's location and take an - // unstaggered derivative of f - return 0.5 * (v.p + v.m) * 0.5 * (f.p - f.m); -} - -REGISTER_UPWIND_DERIVATIVE_STAGGERED(VDDX_C4_stag, "C4", 2, DERIV::Upwind) { - // Result is needed at location of f: interpolate v to f's location and take an - // unstaggered derivative of f - return (9. * (v.m + v.p) - v.mm - v.pp) / 16. * (8. * f.p - 8. * f.m + f.mm - f.pp) - / 12.; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Flux methods -//////////////////////////////////////////////////////////////////////////////// -REGISTER_FLUX_DERIVATIVE_STAGGERED(FDDX_U1_stag, "U1", 1, DERIV::Flux) { - // Lower cell boundary - BoutReal result = (v.m >= 0) ? v.m * f.m : v.m * f.c; - - // Upper cell boundary - result -= (v.p >= 0) ? v.p * f.c : v.p * f.p; - - return -result; -} - -///////////////////////////////////////////////////////////////////////////////////// -/// Here's an example of defining and registering a custom method that doesn't fit -/// into the standard stencil based approach. -// ///////////////////////////////////////////////////////////////////////////////// - -class FFTDerivativeType { -public: - template - void standard(const T& var, T& result, REGION region) const { - AUTO_TRACE(); - ASSERT2(meta.derivType == DERIV::Standard) - ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); - ASSERT2(direction == DIRECTION::Z); // Only in Z for now - ASSERT2(stagger == STAGGER::None); // Staggering not currently supported - ASSERT2((std::is_base_of::value)); // Should never need to call this with Field2D - - const auto region_str = REGION_STRING(region); - - // Only allow a whitelist of regions for now - ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" - || region_str == "RGN_NOX" || region_str == "RGN_NOY"); - - auto* theMesh = var.getMesh(); - - // Calculate how many Z wavenumbers will be removed - const int ncz = theMesh->getNpoints(direction); - - int kfilter = static_cast(theMesh->fft_derivs_filter * ncz - / 2); // truncates, rounding down - if (kfilter < 0) - kfilter = 0; - if (kfilter > (ncz / 2)) - kfilter = ncz / 2; - const int kmax = ncz / 2 - kfilter; // Up to and including this wavenumber index - - BOUT_OMP(parallel) { - Array cv(ncz / 2 + 1); - const BoutReal kwaveFac = TWOPI / ncz; - - // Note we lookup a 2D region here even though we're operating on a Field3D - // as we only want to loop over {x, y} and then handle z differently. The - // Region blocks are constructed for elements contiguous assuming nz=1, - // as that isn't the case for Field3D (in general) this shouldn't be expected - // to vectorise (not that it would anyway) but it should still OpenMP parallelise - // ok. - // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro - // here, - // but should be ok for now. - BOUT_FOR_INNER(i, theMesh->getRegion2D(region_str)) { - auto i3D = theMesh->ind2Dto3D(i, 0); - rfft(&var[i3D], ncz, cv.begin()); // Forward FFT - - for (int jz = 0; jz <= kmax; jz++) { - const BoutReal kwave = jz * kwaveFac; // wave number is 1/[rad] - cv[jz] *= dcomplex(0, kwave); - } - for (int jz = kmax + 1; jz <= ncz / 2; jz++) { - cv[jz] = 0.0; - } - - irfft(cv.begin(), ncz, &result[i3D]); // Reverse FFT - } - } - - return; - } - - template - void upwindOrFlux(const T& UNUSED(vel), const T& UNUSED(var), T& UNUSED(result), - REGION UNUSED(region)) const { - AUTO_TRACE(); - throw BoutException("The FFT METHOD isn't available in upwind/Flux"); - } - metaData meta{"FFT", 0, DERIV::Standard}; -}; - -class FFT2ndDerivativeType { -public: - template - void standard(const T& var, T& result, REGION region) const { - AUTO_TRACE(); - ASSERT2(meta.derivType == DERIV::StandardSecond); - ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); - ASSERT2(direction == DIRECTION::Z); // Only in Z for now - ASSERT2(stagger == STAGGER::None); // Staggering not currently supported - ASSERT2((std::is_base_of::value)); // Should never need to call this with Field2D - - const auto region_str = REGION_STRING(region); - - // Only allow a whitelist of regions for now - ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" - || region_str == "RGN_NOX" || region_str == "RGN_NOY"); - - auto* theMesh = var.getMesh(); - - // Calculate how many Z wavenumbers will be removed - const int ncz = theMesh->getNpoints(direction); - const int kmax = ncz / 2; - - BOUT_OMP(parallel) { - Array cv(ncz / 2 + 1); - const BoutReal kwaveFac = TWOPI / ncz; - - // Note we lookup a 2D region here even though we're operating on a Field3D - // as we only want to loop over {x, y} and then handle z differently. The - // Region blocks are constructed for elements contiguous assuming nz=1, - // as that isn't the case for Field3D (in general) this shouldn't be expected - // to vectorise (not that it would anyway) but it should still OpenMP parallelise - // ok. - // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro - // here, - // but should be ok for now. - BOUT_FOR_INNER(i, theMesh->getRegion2D(region_str)) { - auto i3D = theMesh->ind2Dto3D(i, 0); - rfft(&var[i3D], ncz, cv.begin()); // Forward FFT - - for (int jz = 0; jz <= kmax; jz++) { - const BoutReal kwave = jz * kwaveFac; // wave number is 1/[rad] - cv[jz] *= -kwave * kwave; - } - for (int jz = kmax + 1; jz <= ncz / 2; jz++) { - cv[jz] = 0.0; - } - - irfft(cv.begin(), ncz, &result[i3D]); // Reverse FFT - } - } - - return; - } - - template - void upwindOrFlux(const T& UNUSED(vel), const T& UNUSED(var), T& UNUSED(result), - REGION UNUSED(region)) const { - AUTO_TRACE(); - throw BoutException("The FFT METHOD isn't available in upwind/Flux"); - } - metaData meta{"FFT", 0, DERIV::StandardSecond}; -}; - -produceCombinations, Set, - Set>, - Set> - registerFFTDerivative(registerMethod{}); - -class SplitFluxDerivativeType { -public: - template - void standard(const T&, T&, REGION) const { - AUTO_TRACE(); - throw BoutException("The SPLIT method isn't available for standard"); - } - - template - void upwindOrFlux(const T& vel, const T& var, T& result, REGION region) const { - AUTO_TRACE(); - // Split into an upwind and a central differencing part - // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) - result = bout::derivatives::index::flowDerivative( - vel, var, result.getLocation(), "DEFAULT", region); - result += bout::derivatives::index::standardDerivative( - vel, result.getLocation(), "DEFAULT", region) - * interp_to(var, result.getLocation()); - return; - } - metaData meta{"SPLIT", 2, DERIV::Flux}; -}; - -produceCombinations, - Set, - Set, TypeContainer>, - Set> - registerSplitDerivative(registerMethod{}); #endif diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index ea06fa66e7..2d0f637152 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -62,3 +62,495 @@ STAGGER Mesh::getStagger(const CELL_LOC vloc, MAYBE_UNUSED(const CELL_LOC inloc) || (vloc == allowedStaggerLoc && inloc == CELL_CENTRE)); return getStagger(vloc, outloc, allowedStaggerLoc); } + +////////////////////// FIRST DERIVATIVES ///////////////////// + +/// central, 2nd order +REGISTER_STANDARD_DERIVATIVE(DDX_C2, "C2", 1, DERIV::Standard) { + return 0.5 * (f.p - f.m); +}; + +/// central, 4th order +REGISTER_STANDARD_DERIVATIVE(DDX_C4, "C4", 2, DERIV::Standard) { + return (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; +} + +/// Central WENO method, 2nd order (reverts to 1st order near shocks) +REGISTER_STANDARD_DERIVATIVE(DDX_CWENO2, "W2", 1, DERIV::Standard) { + BoutReal isl, isr, isc; // Smoothness indicators + BoutReal al, ar, ac, sa; // Un-normalised weights + BoutReal dl, dr, dc; // Derivatives using different stencils + + dc = 0.5 * (f.p - f.m); + dl = f.c - f.m; + dr = f.p - f.c; + + isl = SQ(dl); + isr = SQ(dr); + isc = (13. / 3.) * SQ(f.p - 2. * f.c + f.m) + 0.25 * SQ(f.p - f.m); + + al = 0.25 / SQ(WENO_SMALL + isl); + ar = 0.25 / SQ(WENO_SMALL + isr); + ac = 0.5 / SQ(WENO_SMALL + isc); + sa = al + ar + ac; + + return (al * dl + ar * dr + ac * dc) / sa; +} + +// Smoothing 2nd order derivative +REGISTER_STANDARD_DERIVATIVE(DDX_S2, "S2", 2, DERIV::Standard) { + + // 4th-order differencing + BoutReal result = (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; + + result += SIGN(f.c) * (f.pp - 4. * f.p + 6. * f.c - 4. * f.m + f.mm) / 12.; + + return result; +} + +/// Also CWENO3 but needs an upwind op so define later. + +////////////////////////////// +//--- Second order derivatives +////////////////////////////// + +/// Second derivative: Central, 2nd order +REGISTER_STANDARD_DERIVATIVE(D2DX2_C2, "C2", 1, DERIV::StandardSecond) { + return f.p + f.m - 2. * f.c; +} + +/// Second derivative: Central, 4th order +REGISTER_STANDARD_DERIVATIVE(D2DX2_C4, "C4", 2, DERIV::StandardSecond) { + return (-f.pp + 16. * f.p - 30. * f.c + 16. * f.m - f.mm) / 12.; +} + +////////////////////////////// +//--- Fourth order derivatives +////////////////////////////// +REGISTER_STANDARD_DERIVATIVE(D4DX4_C2, "C2", 2, DERIV::StandardFourth) { + return (f.pp - 4. * f.p + 6. * f.c - 4. * f.m + f.mm); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Upwind non-staggered methods +/// +/// Basic derivative methods. +/// All expect to have an input grid cell at the same location as the output +/// Hence convert cell centred values -> centred values, or left -> left +/// +//////////////////////////////////////////////////////////////////////////////// +std::tuple vUpDown(BoutReal v) { + return std::tuple{0.5 * (v + fabs(v)), 0.5 * (v - fabs(v))}; +} + +/// Upwinding: Central, 2nd order +REGISTER_UPWIND_DERIVATIVE(VDDX_C2, "C2", 1, DERIV::Upwind) { + return vc * 0.5 * (f.p - f.m); +} + +/// Upwinding: Central, 4th order +REGISTER_UPWIND_DERIVATIVE(VDDX_C4, "C4", 2, DERIV::Upwind) { + return vc * (8. * f.p - 8. * f.m + f.mm - f.pp) / 12.; +} + +/// upwind, 1st order +REGISTER_UPWIND_DERIVATIVE(VDDX_U1, "U1", 1, DERIV::Upwind) { // No vec + // Existing form doesn't vectorise due to branching + return vc >= 0.0 ? vc * (f.c - f.m) : vc * (f.p - f.c); + // Alternative form would but may involve more operations + const auto vSplit = vUpDown(vc); + return (std::get<0>(vSplit) * (f.p - f.c) + std::get<1>(vSplit) * (f.c - f.m)); +} + +/// upwind, 2nd order +REGISTER_UPWIND_DERIVATIVE(VDDX_U2, "U2", 2, DERIV::Upwind) { // No vec + // Existing form doesn't vectorise due to branching + return vc >= 0.0 ? vc * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) + : vc * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c); + // Alternative form would but may involve more operations + const auto vSplit = vUpDown(vc); + return (std::get<0>(vSplit) * (1.5 * f.c - 2.0 * f.m + 0.5 * f.mm) + + std::get<1>(vSplit) * (-0.5 * f.pp + 2.0 * f.p - 1.5 * f.c)); +} + +/// upwind, 3rd order +REGISTER_UPWIND_DERIVATIVE(VDDX_U3, "U3", 2, DERIV::Upwind) { // No vec + // Existing form doesn't vectorise due to branching + return vc >= 0.0 ? vc * (4. * f.p - 12. * f.m + 2. * f.mm + 6. * f.c) / 12. + : vc * (-4. * f.m + 12. * f.p - 2. * f.pp - 6. * f.c) / 12.; + // Alternative form would but may involve more operations + const auto vSplit = vUpDown(vc); + return (std::get<0>(vSplit) * (4. * f.p - 12. * f.m + 2. * f.mm + 6. * f.c) + + std::get<1>(vSplit) * (-4. * f.m + 12. * f.p - 2. * f.pp - 6. * f.c)) + / 12.; +} + +/// 3rd-order WENO scheme +REGISTER_UPWIND_DERIVATIVE(VDDX_WENO3, "W3", 2, DERIV::Upwind) { // No vec + BoutReal deriv, w, r; + // Existing form doesn't vectorise due to branching + + if (vc > 0.0) { + // Left-biased stencil + + r = (WENO_SMALL + SQ(f.c - 2.0 * f.m + f.mm)) + / (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); + + deriv = (-f.mm + 3. * f.m - 3. * f.c + f.p); + + } else { + // Right-biased + + r = (WENO_SMALL + SQ(f.pp - 2.0 * f.p + f.c)) + / (WENO_SMALL + SQ(f.p - 2.0 * f.c + f.m)); + + deriv = (-f.m + 3. * f.c - 3. * f.p + f.pp); + } + + w = 1.0 / (1.0 + 2.0 * r * r); + deriv = 0.5 * ((f.p - f.m) - w * deriv); + + return vc * deriv; +} + +///----------------------------------------------------------------- +/// 3rd-order CWENO. Uses the upwinding code and split flux +REGISTER_STANDARD_DERIVATIVE(DDX_CWENO3, "W3", 2, DERIV::Standard) { + BoutReal a, ma = fabs(f.c); + // Split flux + a = fabs(f.m); + if (a > ma) + ma = a; + a = fabs(f.p); + if (a > ma) + ma = a; + a = fabs(f.mm); + if (a > ma) + ma = a; + a = fabs(f.pp); + if (a > ma) + ma = a; + + stencil sp, sm; + + sp.mm = f.mm + ma; + sp.m = f.m + ma; + sp.c = f.c + ma; + sp.p = f.p + ma; + sp.pp = f.pp + ma; + + sm.mm = ma - f.mm; + sm.m = ma - f.m; + sm.c = ma - f.c; + sm.p = ma - f.p; + sm.pp = ma - f.pp; + + const VDDX_WENO3 upwindOp{}; + return upwindOp(0.5, sp) + upwindOp(-0.5, sm); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Flux non-staggered methods +/// +/// Basic derivative methods. +/// All expect to have an input grid cell at the same location as the output +/// Hence convert cell centred values -> centred values, or left -> left +/// +//////////////////////////////////////////////////////////////////////////////// + +REGISTER_FLUX_DERIVATIVE(FDDX_U1, "U1", 1, DERIV::Flux) { // No vec + + // Velocity at lower end + BoutReal vs = 0.5 * (v.m + v.c); + BoutReal result = (vs >= 0.0) ? vs * f.m : vs * f.c; + // and at upper + vs = 0.5 * (v.c + v.p); + // Existing form doesn't vectorise due to branching + result -= (vs >= 0.0) ? vs * f.c : vs * f.p; + return -result; + + // Alternative form would but may involve more operations + const auto vSplit = vUpDown(vs); + return result - std::get<0>(vSplit) * f.c + std::get<1>(vSplit) * f.p; +} + +REGISTER_FLUX_DERIVATIVE(FDDX_C2, "C2", 2, DERIV::Flux) { + return 0.5 * (v.p * f.p - v.m * f.m); +} + +REGISTER_FLUX_DERIVATIVE(FDDX_C4, "C4", 2, DERIV::Flux) { + return (8. * v.p * f.p - 8. * v.m * f.m + v.mm * f.mm - v.pp * f.pp) / 12.; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Staggered methods +/// +/// Map Centre -> Low or Low -> Centre +/// +/// These expect the output grid cell to be at a different location to the input +/// +/// The stencil no longer has a value in 'C' (centre) +/// instead, points are shifted as follows: +/// +/// mm -> -3/2 h +/// m -> -1/2 h +/// p -> +1/2 h +/// pp -? +3/2 h +/// +/// NOTE: Cell widths (dx, dy, dz) are currently defined as centre->centre +/// for the methods above. This is currently not taken account of, so large +/// variations in cell size will cause issues. +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// Standard methods -- first order +//////////////////////////////////////////////////////////////////////////////// +REGISTER_STANDARD_DERIVATIVE_STAGGERED(DDX_C2_stag, "C2", 1, DERIV::Standard) { + return f.p - f.m; +} + +REGISTER_STANDARD_DERIVATIVE_STAGGERED(DDX_C4_stag, "C4", 2, DERIV::Standard) { + return (27. * (f.p - f.m) - (f.pp - f.mm)) / 24.; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Standard methods -- second order +//////////////////////////////////////////////////////////////////////////////// +REGISTER_STANDARD_DERIVATIVE_STAGGERED(D2DX2_C2_stag, "C2", 2, DERIV::StandardSecond) { + return (f.pp + f.mm - f.p - f.m) / 2.; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Upwind methods +//////////////////////////////////////////////////////////////////////////////// +REGISTER_UPWIND_DERIVATIVE_STAGGERED(VDDX_U1_stag, "U1", 1, DERIV::Upwind) { + // Lower cell boundary + BoutReal result = (v.m >= 0) ? v.m * f.m : v.m * f.c; + + // Upper cell boundary + result -= (v.p >= 0) ? v.p * f.c : v.p * f.p; + result *= -1; + + // result is now d/dx(v*f), but want v*d/dx(f) so subtract f*d/dx(v) + result -= f.c * (v.p - v.m); + return result; +} + +REGISTER_UPWIND_DERIVATIVE_STAGGERED(VDDX_U2_stag, "U2", 2, DERIV::Upwind) { + // Calculate d(v*f)/dx = (v*f)[i+1/2] - (v*f)[i-1/2] + + // Upper cell boundary + BoutReal result = + (v.p >= 0.) ? v.p * (1.5 * f.c - 0.5 * f.m) : v.p * (1.5 * f.p - 0.5 * f.pp); + + // Lower cell boundary + result -= (v.m >= 0.) ? v.m * (1.5 * f.m - 0.5 * f.mm) : v.m * (1.5 * f.c - 0.5 * f.p); + + // result is now d/dx(v*f), but want v*d/dx(f) so subtract f*d/dx(v) + result -= f.c * (v.p - v.m); + + return result; +} + +REGISTER_UPWIND_DERIVATIVE_STAGGERED(VDDX_C2_stag, "C2", 1, DERIV::Upwind) { + // Result is needed at location of f: interpolate v to f's location and take an + // unstaggered derivative of f + return 0.5 * (v.p + v.m) * 0.5 * (f.p - f.m); +} + +REGISTER_UPWIND_DERIVATIVE_STAGGERED(VDDX_C4_stag, "C4", 2, DERIV::Upwind) { + // Result is needed at location of f: interpolate v to f's location and take an + // unstaggered derivative of f + return (9. * (v.m + v.p) - v.mm - v.pp) / 16. * (8. * f.p - 8. * f.m + f.mm - f.pp) + / 12.; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Flux methods +//////////////////////////////////////////////////////////////////////////////// +REGISTER_FLUX_DERIVATIVE_STAGGERED(FDDX_U1_stag, "U1", 1, DERIV::Flux) { + // Lower cell boundary + BoutReal result = (v.m >= 0) ? v.m * f.m : v.m * f.c; + + // Upper cell boundary + result -= (v.p >= 0) ? v.p * f.c : v.p * f.p; + + return -result; +} + +///////////////////////////////////////////////////////////////////////////////////// +/// Here's an example of defining and registering a custom method that doesn't fit +/// into the standard stencil based approach. +// ///////////////////////////////////////////////////////////////////////////////// + +class FFTDerivativeType { +public: + template + void standard(const T& var, T& result, REGION region) const { + AUTO_TRACE(); + ASSERT2(meta.derivType == DERIV::Standard) + ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); + ASSERT2(direction == DIRECTION::Z); // Only in Z for now + ASSERT2(stagger == STAGGER::None); // Staggering not currently supported + ASSERT2((std::is_base_of::value)); // Should never need to call this with Field2D + + const auto region_str = REGION_STRING(region); + + // Only allow a whitelist of regions for now + ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" + || region_str == "RGN_NOX" || region_str == "RGN_NOY"); + + auto* theMesh = var.getMesh(); + + // Calculate how many Z wavenumbers will be removed + const int ncz = theMesh->getNpoints(direction); + + int kfilter = static_cast(theMesh->fft_derivs_filter * ncz + / 2); // truncates, rounding down + if (kfilter < 0) + kfilter = 0; + if (kfilter > (ncz / 2)) + kfilter = ncz / 2; + const int kmax = ncz / 2 - kfilter; // Up to and including this wavenumber index + + BOUT_OMP(parallel) { + Array cv(ncz / 2 + 1); + const BoutReal kwaveFac = TWOPI / ncz; + + // Note we lookup a 2D region here even though we're operating on a Field3D + // as we only want to loop over {x, y} and then handle z differently. The + // Region blocks are constructed for elements contiguous assuming nz=1, + // as that isn't the case for Field3D (in general) this shouldn't be expected + // to vectorise (not that it would anyway) but it should still OpenMP parallelise + // ok. + // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro + // here, + // but should be ok for now. + BOUT_FOR_INNER(i, theMesh->getRegion2D(region_str)) { + auto i3D = theMesh->ind2Dto3D(i, 0); + rfft(&var[i3D], ncz, cv.begin()); // Forward FFT + + for (int jz = 0; jz <= kmax; jz++) { + const BoutReal kwave = jz * kwaveFac; // wave number is 1/[rad] + cv[jz] *= dcomplex(0, kwave); + } + for (int jz = kmax + 1; jz <= ncz / 2; jz++) { + cv[jz] = 0.0; + } + + irfft(cv.begin(), ncz, &result[i3D]); // Reverse FFT + } + } + + return; + } + + template + void upwindOrFlux(const T& UNUSED(vel), const T& UNUSED(var), T& UNUSED(result), + REGION UNUSED(region)) const { + AUTO_TRACE(); + throw BoutException("The FFT METHOD isn't available in upwind/Flux"); + } + metaData meta{"FFT", 0, DERIV::Standard}; +}; + +class FFT2ndDerivativeType { +public: + template + void standard(const T& var, T& result, REGION region) const { + AUTO_TRACE(); + ASSERT2(meta.derivType == DERIV::StandardSecond); + ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); + ASSERT2(direction == DIRECTION::Z); // Only in Z for now + ASSERT2(stagger == STAGGER::None); // Staggering not currently supported + ASSERT2((std::is_base_of::value)); // Should never need to call this with Field2D + + const auto region_str = REGION_STRING(region); + + // Only allow a whitelist of regions for now + ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" + || region_str == "RGN_NOX" || region_str == "RGN_NOY"); + + auto* theMesh = var.getMesh(); + + // Calculate how many Z wavenumbers will be removed + const int ncz = theMesh->getNpoints(direction); + const int kmax = ncz / 2; + + BOUT_OMP(parallel) { + Array cv(ncz / 2 + 1); + const BoutReal kwaveFac = TWOPI / ncz; + + // Note we lookup a 2D region here even though we're operating on a Field3D + // as we only want to loop over {x, y} and then handle z differently. The + // Region blocks are constructed for elements contiguous assuming nz=1, + // as that isn't the case for Field3D (in general) this shouldn't be expected + // to vectorise (not that it would anyway) but it should still OpenMP parallelise + // ok. + // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro + // here, + // but should be ok for now. + BOUT_FOR_INNER(i, theMesh->getRegion2D(region_str)) { + auto i3D = theMesh->ind2Dto3D(i, 0); + rfft(&var[i3D], ncz, cv.begin()); // Forward FFT + + for (int jz = 0; jz <= kmax; jz++) { + const BoutReal kwave = jz * kwaveFac; // wave number is 1/[rad] + cv[jz] *= -kwave * kwave; + } + for (int jz = kmax + 1; jz <= ncz / 2; jz++) { + cv[jz] = 0.0; + } + + irfft(cv.begin(), ncz, &result[i3D]); // Reverse FFT + } + } + + return; + } + + template + void upwindOrFlux(const T& UNUSED(vel), const T& UNUSED(var), T& UNUSED(result), + REGION UNUSED(region)) const { + AUTO_TRACE(); + throw BoutException("The FFT METHOD isn't available in upwind/Flux"); + } + metaData meta{"FFT", 0, DERIV::StandardSecond}; +}; + +produceCombinations, Set, + Set>, + Set> + registerFFTDerivative(registerMethod{}); + +class SplitFluxDerivativeType { +public: + template + void standard(const T&, T&, REGION) const { + AUTO_TRACE(); + throw BoutException("The SPLIT method isn't available for standard"); + } + + template + void upwindOrFlux(const T& vel, const T& var, T& result, REGION region) const { + AUTO_TRACE(); + // Split into an upwind and a central differencing part + // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) + result = bout::derivatives::index::flowDerivative( + vel, var, result.getLocation(), "DEFAULT", region); + result += bout::derivatives::index::standardDerivative( + vel, result.getLocation(), "DEFAULT", region) + * interp_to(var, result.getLocation()); + return; + } + metaData meta{"SPLIT", 2, DERIV::Flux}; +}; + +produceCombinations, + Set, + Set, TypeContainer>, + Set> + registerSplitDerivative(registerMethod{}); From e7ea1c0f425dde78f7eb569c34d437133d9453ad Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 13 Feb 2019 13:01:23 +0000 Subject: [PATCH 0759/1783] Ensure default derivative methods at set at construction time --- include/bout/deriv_store.hxx | 45 +++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 92ae5fa846..c3c520d3b4 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -322,6 +322,45 @@ struct DerivativeStore { return getFlowDerivative(name, direction, stagger, DERIV::Flux); }; + void setDefaults() { + std::map initialDefaultMethods = {{DERIV::Standard, "C2"}, + {DERIV::StandardSecond, "C2"}, + {DERIV::StandardFourth, "C2"}, + {DERIV::Upwind, "U1"}, + {DERIV::Flux, "U1"}}; + + std::map directions = {{DIRECTION::X, "ddx"}, + {DIRECTION::Y, "ddy"}, + {DIRECTION::YOrthogonal, "ddy"}, + {DIRECTION::Z, "ddz"}}; + + std::map derivTypes = {{DERIV::Standard, "First"}, + {DERIV::StandardSecond, "Second"}, + {DERIV::StandardFourth, "Fourth"}, + {DERIV::Upwind, "Upwind"}, + {DERIV::Flux, "Flux"}}; + + for (const auto& direction : directions) { + for (const auto& deriv : derivTypes) { + const auto theDirection = direction.first; + const auto theDerivTypeString = DERIV_STRING(deriv.first); + const std::string theDefault{uppercase(initialDefaultMethods[deriv.first])}; + + //------------------------------------------------------------- + // Unstaggered and Staggered -- both get same default currently + //------------------------------------------------------------- + + // Now we have the default method we should store it in defaultMethods + defaultMethods[getKey(theDirection, STAGGER::None, theDerivTypeString)] = + theDefault; + defaultMethods[getKey(theDirection, STAGGER::L2C, theDerivTypeString)] = + theDefault; + defaultMethods[getKey(theDirection, STAGGER::C2L, theDerivTypeString)] = + theDefault; + } + } + }; + void initialise(Options* options) { AUTO_TRACE(); @@ -431,7 +470,11 @@ struct DerivativeStore { private: // Make empty constructor private so we can't make instances outside // of the struct - DerivativeStore() = default; + DerivativeStore() { + // Ensure the default methods are set on construction + // This populates the defaultMethods map + setDefaults(); + } storageType standard; storageType standardSecond; From 87e1be453bcff3dccbca602029d3cbad07da90b2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Feb 2019 13:13:59 +0000 Subject: [PATCH 0760/1783] Tweak settings for PETSc < 3.7 in test-solver --- tests/integrated/test-solver/data/BOUT.inp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/integrated/test-solver/data/BOUT.inp b/tests/integrated/test-solver/data/BOUT.inp index 7051ad3cd4..b248ee4ea2 100644 --- a/tests/integrated/test-solver/data/BOUT.inp +++ b/tests/integrated/test-solver/data/BOUT.inp @@ -37,8 +37,10 @@ adaptRtol = 1.e-5 nout = 100 timestep = end / (NOUT * 10000) [petsc] -# This solver currently fails this test without adaptive timestepping -adaptive = true +# For PETSc < 3.7, there are issues with the RK solvers not +# interpolating at the final step if they are adaptive +nout = 10000 +output_step = end / nout [power] [pvode] [rk3ssp] From 9da3964a9c53b9066e100febf063aaaf4b3ca0ba Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 13 Feb 2019 14:02:45 +0000 Subject: [PATCH 0761/1783] Remove some duplication in default methods --- include/bout/deriv_store.hxx | 94 +++++++++++++++++------------------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index c3c520d3b4..aec60fd8e1 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -322,45 +322,6 @@ struct DerivativeStore { return getFlowDerivative(name, direction, stagger, DERIV::Flux); }; - void setDefaults() { - std::map initialDefaultMethods = {{DERIV::Standard, "C2"}, - {DERIV::StandardSecond, "C2"}, - {DERIV::StandardFourth, "C2"}, - {DERIV::Upwind, "U1"}, - {DERIV::Flux, "U1"}}; - - std::map directions = {{DIRECTION::X, "ddx"}, - {DIRECTION::Y, "ddy"}, - {DIRECTION::YOrthogonal, "ddy"}, - {DIRECTION::Z, "ddz"}}; - - std::map derivTypes = {{DERIV::Standard, "First"}, - {DERIV::StandardSecond, "Second"}, - {DERIV::StandardFourth, "Fourth"}, - {DERIV::Upwind, "Upwind"}, - {DERIV::Flux, "Flux"}}; - - for (const auto& direction : directions) { - for (const auto& deriv : derivTypes) { - const auto theDirection = direction.first; - const auto theDerivTypeString = DERIV_STRING(deriv.first); - const std::string theDefault{uppercase(initialDefaultMethods[deriv.first])}; - - //------------------------------------------------------------- - // Unstaggered and Staggered -- both get same default currently - //------------------------------------------------------------- - - // Now we have the default method we should store it in defaultMethods - defaultMethods[getKey(theDirection, STAGGER::None, theDerivTypeString)] = - theDefault; - defaultMethods[getKey(theDirection, STAGGER::L2C, theDerivTypeString)] = - theDefault; - defaultMethods[getKey(theDirection, STAGGER::C2L, theDerivTypeString)] = - theDefault; - } - } - }; - void initialise(Options* options) { AUTO_TRACE(); @@ -368,12 +329,6 @@ struct DerivativeStore { //"dd?" and if the option isn't in there we search a section called "diff" auto backupSection = options->getSection("diff"); - std::map initialDefaultMethods = {{DERIV::Standard, "C2"}, - {DERIV::StandardSecond, "C2"}, - {DERIV::StandardFourth, "C2"}, - {DERIV::Upwind, "U1"}, - {DERIV::Flux, "U1"}}; - std::map directions = {{DIRECTION::X, "ddx"}, {DIRECTION::Y, "ddy"}, {DIRECTION::YOrthogonal, "ddy"}, @@ -387,8 +342,6 @@ struct DerivativeStore { for (const auto& direction : directions) { for (const auto& deriv : derivTypes) { - std::string theDefault; - // This corresponds to the key in the input file auto derivName = deriv.second; @@ -396,6 +349,10 @@ struct DerivativeStore { const auto theDerivType = deriv.first; const auto theDerivTypeString = DERIV_STRING(theDerivType); + // Note both staggered and unstaggered have the same fallback default currently + std::string theDefault{ + defaultMethods[getKey(theDirection, STAGGER::None, theDerivTypeString)]}; + //------------------------------------------------------------- // Unstaggered //------------------------------------------------------------- @@ -406,12 +363,12 @@ struct DerivativeStore { // Find the appropriate value for theDefault either from // the input file or if not found then use the value in // initialDefaultMethods + // If neither branch matched (i.e. not in options) then we use + // the hard-coded default already in the defaultMethods section if (specificSection->isSet(derivName)) { specificSection->get(derivName, theDefault, ""); } else if (backupSection->isSet(derivName)) { backupSection->get(derivName, theDefault, ""); - } else { - theDefault = initialDefaultMethods[theDerivType]; } // Now we have the default method we should store it in defaultMethods @@ -492,6 +449,45 @@ private: /// it might be useful to relax this assumption! storageType defaultMethods; + void setDefaults() { + std::map initialDefaultMethods = {{DERIV::Standard, "C2"}, + {DERIV::StandardSecond, "C2"}, + {DERIV::StandardFourth, "C2"}, + {DERIV::Upwind, "U1"}, + {DERIV::Flux, "U1"}}; + + std::map directions = {{DIRECTION::X, "ddx"}, + {DIRECTION::Y, "ddy"}, + {DIRECTION::YOrthogonal, "ddy"}, + {DIRECTION::Z, "ddz"}}; + + std::map derivTypes = {{DERIV::Standard, "First"}, + {DERIV::StandardSecond, "Second"}, + {DERIV::StandardFourth, "Fourth"}, + {DERIV::Upwind, "Upwind"}, + {DERIV::Flux, "Flux"}}; + + for (const auto& direction : directions) { + for (const auto& deriv : derivTypes) { + const auto theDirection = direction.first; + const auto theDerivTypeString = DERIV_STRING(deriv.first); + const std::string theDefault{uppercase(initialDefaultMethods[deriv.first])}; + + //------------------------------------------------------------- + // Unstaggered and Staggered -- both get same default currently + //------------------------------------------------------------- + + // Now we have the default method we should store it in defaultMethods + defaultMethods[getKey(theDirection, STAGGER::None, theDerivTypeString)] = + theDefault; + defaultMethods[getKey(theDirection, STAGGER::L2C, theDerivTypeString)] = + theDefault; + defaultMethods[getKey(theDirection, STAGGER::C2L, theDerivTypeString)] = + theDefault; + } + } + }; + std::string getMethodName(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { AUTO_TRACE(); From c2f9eff07183fa0aafa150513843b42fba13ca5a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 13 Feb 2019 21:16:59 +0000 Subject: [PATCH 0762/1783] Restore missing y_offset in ShiftedMetric::shiftZ --- src/mesh/parallel/shiftedmetric.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 6c6670133c..56cb2c6649 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -202,7 +202,7 @@ ShiftedMetric::shiftZ(const Field3D& f, BOUT_FOR(i, mesh.getRegion2D("RGN_NOY")) { // Deep copy the FFT'd field - Array shifted_temp(f_fft(i.x(), i.y())); + Array shifted_temp(f_fft(i.x(), i.y() + phase.y_offset)); shifted_temp.ensureUnique(); for (int jz = 1; jz < nmodes; ++jz) { From a308542974a52a57fc8b89d88f39fadb799ecae6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 13 Feb 2019 21:40:45 +0000 Subject: [PATCH 0763/1783] Make input for ShiftedMetric unit tests not constant in y Swap some array entries around so that 'input' in ShiftedMetricTest is not constant in x or y. Being constant could mask errors. --- .../unit/mesh/parallel/test_shiftedmetric.cxx | 160 +++++++++--------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index cf164f0fd9..d8c801aed0 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -43,28 +43,28 @@ class ShiftedMetricTest : public ::testing::Test { Field3D input_temp{mesh}; fillField(input_temp, {{{1., 2., 3., 4., 5.}, + {2., 1., 3., 4., 5.}, + {1., 3., 2., 4., 5.}, + {1., 2., 4., 3., 5.}, + {1., 2., 3., 5., 4.}, {1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}}, + {2., 1., 3., 4., 5.}}, - {{1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}, + {{2., 1., 3., 4., 5.}, + {1., 3., 2., 4., 5.}, + {1., 2., 4., 3., 5.}, + {1., 2., 3., 5., 4.}, {1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}}, + {2., 1., 3., 4., 5.}, + {1., 3., 2., 4., 5.}}, - {{1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}, + {{1., 3., 2., 4., 5.}, + {1., 2., 4., 3., 5.}, + {1., 2., 3., 5., 4.}, {1., 2., 3., 4., 5.}, - {1., 2., 3., 4., 5.}}}); + {2., 1., 3., 4., 5.}, + {1., 3., 2., 4., 5.}, + {1., 2., 4., 3., 5.}}}); input = std::move(input_temp); @@ -94,28 +94,28 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { Field3D expected{mesh}; fillField(expected, {{{2., 3., 4., 5., 1.}, - {3., 4., 5., 1., 2.}, - {4., 5., 1., 2., 3.}, - {5., 1., 2., 3., 4.}, - {1., 2., 3., 4., 5.}, + {3., 4., 5., 2., 1.}, + {4., 5., 1., 3., 2.}, + {5., 1., 2., 4., 3.}, + {1., 2., 3., 5., 4.}, {2., 3., 4., 5., 1.}, - {3., 4., 5., 1., 2.}}, + {3., 4., 5., 2., 1.}}, - {{3., 4., 5., 1., 2.}, - {5., 1., 2., 3., 4.}, - {2., 3., 4., 5., 1.}, - {4., 5., 1., 2., 3.}, + {{3., 4., 5., 2., 1.}, + {5., 1., 3., 2., 4.}, + {2., 4., 3., 5., 1.}, + {5., 4., 1., 2., 3.}, {1., 2., 3., 4., 5.}, - {3., 4., 5., 1., 2.}, - {5., 1., 2., 3., 4.}}, + {3., 4., 5., 2., 1.}, + {5., 1., 3., 2., 4.}}, - {{4., 5., 1., 2., 3.}, - {2., 3., 4., 5., 1.}, - {5., 1., 2., 3., 4.}, + {{4., 5., 1., 3., 2.}, + {2., 4., 3., 5., 1.}, + {4., 1., 2., 3., 5.}, {3., 4., 5., 1., 2.}, - {1., 2., 3., 4., 5.}, - {4., 5., 1., 2., 3.}, - {2., 3., 4., 5., 1.}}}); + {2., 1., 3., 4., 5.}, + {4., 5., 1., 3., 2.}, + {2., 4., 3., 5., 1.}}}); EXPECT_TRUE(IsFieldEqual(shifted.toFieldAligned(input, RGN_ALL), expected, "RGN_ALL", FFTTolerance)); @@ -127,28 +127,28 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { Field3D expected{mesh}; fillField(expected, {{{5., 1., 2., 3., 4.}, - {4., 5., 1., 2., 3.}, - {3., 4., 5., 1., 2.}, - {2., 3., 4., 5., 1.}, - {1., 2., 3., 4., 5.}, + {4., 5., 2., 1., 3.}, + {2., 4., 5., 1., 3.}, + {2., 4., 3., 5., 1.}, + {1., 2., 3., 5., 4.}, {5., 1., 2., 3., 4.}, - {4., 5., 1., 2., 3.}}, + {4., 5., 2., 1., 3.}}, - {{4., 5., 1., 2., 3.}, - {2., 3., 4., 5., 1.}, - {5., 1., 2., 3., 4.}, - {3., 4., 5., 1., 2.}, + {{4., 5., 2., 1., 3.}, + {3., 2., 4., 5., 1.}, + {5., 1., 2., 4., 3.}, + {3., 5., 4., 1., 2.}, {1., 2., 3., 4., 5.}, - {4., 5., 1., 2., 3.}, - {2., 3., 4., 5., 1.}}, + {4., 5., 2., 1., 3.}, + {3., 2., 4., 5., 1.}}, - {{3., 4., 5., 1., 2.}, - {5., 1., 2., 3., 4.}, - {2., 3., 4., 5., 1.}, + {{2., 4., 5., 1., 3.}, + {5., 1., 2., 4., 3.}, + {2., 3., 5., 4., 1.}, {4., 5., 1., 2., 3.}, - {1., 2., 3., 4., 5.}, - {3., 4., 5., 1., 2.}, - {5., 1., 2., 3., 4.}}}); + {2., 1., 3., 4., 5.}, + {2., 4., 5., 1., 3.}, + {5., 1., 2., 4., 3.}}}); // Loosen tolerance a bit due to FFTs EXPECT_TRUE(IsFieldEqual(shifted.fromFieldAligned(input, RGN_ALL), expected, "RGN_ALL", @@ -187,25 +187,25 @@ TEST_F(ShiftedMetricTest, CalcYUpDown) { fillField(expected_up_1, {{{0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, - {2., 3., 4., 5., 1.}, - {2., 3., 4., 5., 1.}, + {2., 4., 3., 5., 1.}, + {2., 3., 5., 4., 1.}, {2., 3., 4., 5., 1.}, {0., 0., 0., 0., 0.}}, {{0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, + {3., 5., 4., 1., 2.}, {3., 4., 5., 1., 2.}, - {3., 4., 5., 1., 2.}, - {3., 4., 5., 1., 2.}, + {3., 4., 5., 2., 1.}, {0., 0., 0., 0., 0.}}, {{0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {4., 5., 1., 2., 3.}, - {4., 5., 1., 2., 3.}, - {4., 5., 1., 2., 3.}, + {4., 5., 2., 1., 3.}, + {4., 5., 1., 3., 2.}, {0., 0., 0., 0., 0.}}}); Field3D expected_up_2{mesh}; @@ -214,47 +214,47 @@ TEST_F(ShiftedMetricTest, CalcYUpDown) { {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, + {3., 5., 4., 1., 2.}, {3., 4., 5., 1., 2.}, - {3., 4., 5., 1., 2.}, - {3., 4., 5., 1., 2.}}, + {3., 4., 5., 2., 1.}}, {{0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {5., 1., 2., 3., 4.}, - {5., 1., 2., 3., 4.}, - {5., 1., 2., 3., 4.}}, + {5., 2., 1., 3., 4.}, + {5., 1., 3., 2., 4.}}, {{0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, - {2., 3., 4., 5., 1.}, - {2., 3., 4., 5., 1.}, - {2., 3., 4., 5., 1.}}}); + {1., 3., 4., 5., 2.}, + {3., 2., 4., 5., 1.}, + {2., 4., 3., 5., 1.}}}); Field3D expected_down_1{mesh}; fillField(expected_down_1, {{{0., 0., 0., 0., 0.}, - {5., 1., 2., 3., 4.}, - {5., 1., 2., 3., 4.}, - {5., 1., 2., 3., 4.}, + {5., 2., 1., 3., 4.}, + {5., 1., 3., 2., 4.}, + {5., 1., 2., 4., 3.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}}, {{0., 0., 0., 0., 0.}, - {4., 5., 1., 2., 3.}, - {4., 5., 1., 2., 3.}, - {4., 5., 1., 2., 3.}, + {4., 5., 1., 3., 2.}, + {3., 5., 1., 2., 4.}, + {5., 4., 1., 2., 3.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}}, {{0., 0., 0., 0., 0.}, - {3., 4., 5., 1., 2.}, - {3., 4., 5., 1., 2.}, + {4., 3., 5., 1., 2.}, + {3., 5., 4., 1., 2.}, {3., 4., 5., 1., 2.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, @@ -263,24 +263,24 @@ TEST_F(ShiftedMetricTest, CalcYUpDown) { Field3D expected_down2{mesh}; fillField(expected_down2, {{{4., 5., 1., 2., 3.}, - {4., 5., 1., 2., 3.}, - {4., 5., 1., 2., 3.}, + {4., 5., 2., 1., 3.}, + {4., 5., 1., 3., 2.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}}, - {{2., 3., 4., 5., 1.}, - {2., 3., 4., 5., 1.}, - {2., 3., 4., 5., 1.}, + {{1., 3., 4., 5., 2.}, + {3., 2., 4., 5., 1.}, + {2., 4., 3., 5., 1.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}}, - {{5., 1., 2., 3., 4.}, - {5., 1., 2., 3., 4.}, - {5., 1., 2., 3., 4.}, + {{5., 1., 3., 2., 4.}, + {5., 1., 2., 4., 3.}, + {4., 1., 2., 3., 5.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}, From e7385b498b58ea8f743d680290a2c3b1f8b2dc0e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 14 Feb 2019 11:25:08 +0000 Subject: [PATCH 0764/1783] Reverse conditionals to avoid empty branch --- src/mesh/parallel/fci.cxx | 8 +++----- src/mesh/parallel/identity.cxx | 8 +++----- src/mesh/parallel/shiftedmetric.cxx | 8 +++----- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 46639012ee..cec42e041a 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -303,15 +303,13 @@ FCITransform::FCITransform(Mesh &mesh, bool zperiodic) void FCITransform::checkInputGrid() { std::string coordinates_type = ""; - if (mesh.get(coordinates_type, "coordinates_type")) { - // coordinate_system variable not found in grid input - return; - } else { + if (!mesh.get(coordinates_type, "coordinates_type")) { if (coordinates_type != "fci") { throw BoutException("Incorrect coordinate system type "+coordinates_type+" used " "to generate metric components for FCITransform. Should be 'fci."); } - } + } // else: coordinate_system variable not found in grid input, indicates older input + // file so must rely on the user having ensured the type is correct } void FCITransform::calcYUpDown(Field3D &f) { diff --git a/src/mesh/parallel/identity.cxx b/src/mesh/parallel/identity.cxx index ed3fcd83e4..862c3f6826 100644 --- a/src/mesh/parallel/identity.cxx +++ b/src/mesh/parallel/identity.cxx @@ -11,14 +11,12 @@ void ParallelTransformIdentity::checkInputGrid() { std::string coordinates_type = ""; - if (mesh.get(coordinates_type, "coordinates_type")) { - // coordinate_system variable not found in grid input - return; - } else { + if (!mesh.get(coordinates_type, "coordinates_type")) { if (coordinates_type != "field_aligned") { throw BoutException("Incorrect coordinate system type "+coordinates_type+" used " "to generate metric components for ParallelTransformIdentity. Should be " "'field_aligned."); } - } + } // else: coordinate_system variable not found in grid input, indicates older input + // file so must rely on the user having ensured the type is correct } diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index d9a47aba66..aaaab8446f 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -47,15 +47,13 @@ ShiftedMetric::ShiftedMetric(Mesh &m, Field2D zShift_) : ParallelTransform(m), z void ShiftedMetric::checkInputGrid() { std::string coordinates_type = ""; - if (mesh.get(coordinates_type, "coordinates_type")) { - // coordinate_system variable not found in grid input - return; - } else { + if (!mesh.get(coordinates_type, "coordinates_type")) { if (coordinates_type != "orthogonal") { throw BoutException("Incorrect coordinate system type "+coordinates_type+" used " "to generate metric components for ShiftedMetric. Should be 'orthogonal."); } - } + } // else: coordinate_system variable not found in grid input, indicates older input + // file so must rely on the user having ensured the type is correct } void ShiftedMetric::cachePhases() { From 95e20b7aa7082d0e65d2add74bc9bdc032691122 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Feb 2019 11:26:19 +0000 Subject: [PATCH 0765/1783] Update codacy-coverage-reporter tool for Travis --- .codacy_coverage.sh | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.codacy_coverage.sh b/.codacy_coverage.sh index c2c95088b7..284445784d 100644 --- a/.codacy_coverage.sh +++ b/.codacy_coverage.sh @@ -1,5 +1,5 @@ #First install the reporter tool -wget -q -O ~/codacy-coverage-reporter-assembly-latest.jar https://oss.sonatype.org/service/local/repositories/releases/content/com/codacy/codacy-coverage-reporter/4.0.1/codacy-coverage-reporter-4.0.1-assembly.jar > /dev/null +wget -q -O ~/codacy-coverage-reporter-assembly-latest.jar https://oss.sonatype.org/service/local/repositories/releases/content/com/codacy/codacy-coverage-reporter/4.0.5/codacy-coverage-reporter-4.0.5-assembly.jar > /dev/null #Analyse the existing gcov files and output in compatible xml format #The -g option says to use the existing gcov files, the -k options says to not delete the gcov files diff --git a/.travis.yml b/.travis.yml index 8efce85a6c..a56e58922f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -104,7 +104,7 @@ matrix: - SCRIPT_FLAGS='-cu' - PIP_PACKAGES='gcovr' - secure: "M5U3I81hzK41Kw7KB+DpEMxP/sgkWkFI4uiRZQDMDFRlhcitsJQQ/YGeBt3a0vo153m2P2PmmeKUl/lTo5WS5SfAVFI8BkcyBjpxZQXV3OD8ru7JsMgVc5pGwl2dvR8Qz02gUIbrIpAlf3YDnNVb6F1C9ofDaCnZU3GUTLH5Fy5z5Z8OpuTaLmTVMMnT2ZEcRawHbmlVhIB/9PUQUa+fM7iC+dtszFxZ2ma5LOHxPS2sGpRCKE5Sae1/xAFWjo4oO0ZqYu5JFvKdb+/2yWKTg/1aTyxCdqAzLg4ldzDlX759zXgtWn+k3TLiVyQ+gsvF8QZkh4BKvl/w2KZ20vRP3blzmxvdsSH+ZP92MZIIK9EkNPGd+UJJd5Hu+zwecEFyfO8bXB9l00kzUsVx+lo7VHbANuNO3b5a6FRiihTCgk+dfOxxrow/fci+lQ9BkmJg0680SIj2e6UM/P9lFgfQLH3IoacN1PtkyqnpJqdHUdbWmpqMtmitmQhXHjnJ+wDb5+i9b1fy5yEsB64rjgF9PBr1/Nos1XD4oGWAknXmQTgWhNyy6f+e0wBNcSUd5nrReLTOAscyXYpcTqONp1W999JSFQEH+YTwBfXytdkWaAGAFEhaaAXQ2jCwHO7jl/TODPfSeZgXkQiT5jgg63i5tlPB4Xn0MTSCX74bYIi16Tk=" - script: wget -q -O ~/codacy-coverage-reporter-assembly-latest.jar https://oss.sonatype.org/service/local/repositories/releases/content/com/codacy/codacy-coverage-reporter/4.0.1/codacy-coverage-reporter-4.0.1-assembly.jar ; java -jar ~/codacy-coverage-reporter-assembly-latest.jar final + script: wget -q -O ~/codacy-coverage-reporter-assembly-latest.jar https://oss.sonatype.org/service/local/repositories/releases/content/com/codacy/codacy-coverage-reporter/4.0.5/codacy-coverage-reporter-4.0.5-assembly.jar ; java -jar ~/codacy-coverage-reporter-assembly-latest.jar final before_install: ################################################## From 80171b00a807efc0940c9f5aa72d086584d292ae Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Feb 2019 11:33:56 +0000 Subject: [PATCH 0766/1783] Cut down on repeated config in Travis yaml by using more aliases --- .travis.yml | 62 +++++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/.travis.yml b/.travis.yml index a56e58922f..15f7fadc57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,10 +6,29 @@ compiler: gcc git: depth: 3 +# Define some aliases for some repeated config variables +# Note & creates a reference that we can refer to later using +# *, see https://en.wikipedia.org/wiki/YAML#Syntax +aliases: + - &petsc_vars + - PETSC_DIR=/usr/lib/petscdir/3.6.2/x86_64-linux-gnu-real + - PETSC_ARCH="" + - SLEPC_DIR=/usr/lib/slepcdir/3.6.1/x86_64-linux-gnu-real + - SLEPC_ARCH="" + - &codecov_secure + - secure: "M5U3I81hzK41Kw7KB+DpEMxP/sgkWkFI4uiRZQDMDFRlhcitsJQQ/YGeBt3a0vo153m2P2PmmeKUl/lTo5WS5SfAVFI8BkcyBjpxZQXV3OD8ru7JsMgVc5pGwl2dvR8Qz02gUIbrIpAlf3YDnNVb6F1C9ofDaCnZU3GUTLH5Fy5z5Z8OpuTaLmTVMMnT2ZEcRawHbmlVhIB/9PUQUa+fM7iC+dtszFxZ2ma5LOHxPS2sGpRCKE5Sae1/xAFWjo4oO0ZqYu5JFvKdb+/2yWKTg/1aTyxCdqAzLg4ldzDlX759zXgtWn+k3TLiVyQ+gsvF8QZkh4BKvl/w2KZ20vRP3blzmxvdsSH+ZP92MZIIK9EkNPGd+UJJd5Hu+zwecEFyfO8bXB9l00kzUsVx+lo7VHbANuNO3b5a6FRiihTCgk+dfOxxrow/fci+lQ9BkmJg0680SIj2e6UM/P9lFgfQLH3IoacN1PtkyqnpJqdHUdbWmpqMtmitmQhXHjnJ+wDb5+i9b1fy5yEsB64rjgF9PBr1/Nos1XD4oGWAknXmQTgWhNyy6f+e0wBNcSUd5nrReLTOAscyXYpcTqONp1W999JSFQEH+YTwBfXytdkWaAGAFEhaaAXQ2jCwHO7jl/TODPfSeZgXkQiT5jgg63i5tlPB4Xn0MTSCX74bYIi16Tk=" + - &coverage_packages + addons: + apt: + packages: + - *standard_packages + - jq + - &coverage_vars + - SCRIPT_FLAGS='-cu' + - PIP_PACKAGES='gcovr' + addons: apt: - # Note & creates a reference that we can refer to later using - # *, see https://en.wikipedia.org/wiki/YAML#Syntax packages: &standard_packages - libfftw3-dev - libnetcdf-dev @@ -37,10 +56,7 @@ matrix: - CONFIGURE_OPTIONS='--enable-checks=no --enable-optimize=3 --disable-signal --disable-track --disable-backtrace --with-petsc --with-slepc' - SCRIPT_FLAGS='-uim' - PIP_PACKAGES='cython netcdf4 sympy' - - PETSC_DIR=/usr/lib/petscdir/3.6.2/x86_64-linux-gnu-real - - PETSC_ARCH= - - SLEPC_DIR=/usr/lib/slepcdir/3.6.1/x86_64-linux-gnu-real - - SLEPC_ARCH= + - *petsc_vars - addons: apt: sources: @@ -70,40 +86,26 @@ matrix: compiler: clang #COVERAGE - if: branch IN (master, next) OR commit_message =~ /build coverage/ - addons: - apt: - packages: - - *standard_packages - - jq + *coverage_packages env: - CONFIGURE_OPTIONS='--enable-code-coverage --enable-debug --enable-track --enable-checks=3 --with-petsc --with-lapack --with-slepc --enable-openmp' - OMP_NUM_THREADS=2 - - SCRIPT_FLAGS='-cu' - - PIP_PACKAGES='gcovr' - - secure: "M5U3I81hzK41Kw7KB+DpEMxP/sgkWkFI4uiRZQDMDFRlhcitsJQQ/YGeBt3a0vo153m2P2PmmeKUl/lTo5WS5SfAVFI8BkcyBjpxZQXV3OD8ru7JsMgVc5pGwl2dvR8Qz02gUIbrIpAlf3YDnNVb6F1C9ofDaCnZU3GUTLH5Fy5z5Z8OpuTaLmTVMMnT2ZEcRawHbmlVhIB/9PUQUa+fM7iC+dtszFxZ2ma5LOHxPS2sGpRCKE5Sae1/xAFWjo4oO0ZqYu5JFvKdb+/2yWKTg/1aTyxCdqAzLg4ldzDlX759zXgtWn+k3TLiVyQ+gsvF8QZkh4BKvl/w2KZ20vRP3blzmxvdsSH+ZP92MZIIK9EkNPGd+UJJd5Hu+zwecEFyfO8bXB9l00kzUsVx+lo7VHbANuNO3b5a6FRiihTCgk+dfOxxrow/fci+lQ9BkmJg0680SIj2e6UM/P9lFgfQLH3IoacN1PtkyqnpJqdHUdbWmpqMtmitmQhXHjnJ+wDb5+i9b1fy5yEsB64rjgF9PBr1/Nos1XD4oGWAknXmQTgWhNyy6f+e0wBNcSUd5nrReLTOAscyXYpcTqONp1W999JSFQEH+YTwBfXytdkWaAGAFEhaaAXQ2jCwHO7jl/TODPfSeZgXkQiT5jgg63i5tlPB4Xn0MTSCX74bYIi16Tk=" + - *coverage_vars + - *petsc_vars + - *codecov_secure - if: branch IN (master, next) OR commit_message =~ /build coverage/ - addons: - apt: - packages: - - *standard_packages - - jq + *coverage_packages env: - CONFIGURE_OPTIONS='--enable-code-coverage --disable-debug --disable-checks' - - SCRIPT_FLAGS='-cu' - - PIP_PACKAGES='gcovr' - - secure: "M5U3I81hzK41Kw7KB+DpEMxP/sgkWkFI4uiRZQDMDFRlhcitsJQQ/YGeBt3a0vo153m2P2PmmeKUl/lTo5WS5SfAVFI8BkcyBjpxZQXV3OD8ru7JsMgVc5pGwl2dvR8Qz02gUIbrIpAlf3YDnNVb6F1C9ofDaCnZU3GUTLH5Fy5z5Z8OpuTaLmTVMMnT2ZEcRawHbmlVhIB/9PUQUa+fM7iC+dtszFxZ2ma5LOHxPS2sGpRCKE5Sae1/xAFWjo4oO0ZqYu5JFvKdb+/2yWKTg/1aTyxCdqAzLg4ldzDlX759zXgtWn+k3TLiVyQ+gsvF8QZkh4BKvl/w2KZ20vRP3blzmxvdsSH+ZP92MZIIK9EkNPGd+UJJd5Hu+zwecEFyfO8bXB9l00kzUsVx+lo7VHbANuNO3b5a6FRiihTCgk+dfOxxrow/fci+lQ9BkmJg0680SIj2e6UM/P9lFgfQLH3IoacN1PtkyqnpJqdHUdbWmpqMtmitmQhXHjnJ+wDb5+i9b1fy5yEsB64rjgF9PBr1/Nos1XD4oGWAknXmQTgWhNyy6f+e0wBNcSUd5nrReLTOAscyXYpcTqONp1W999JSFQEH+YTwBfXytdkWaAGAFEhaaAXQ2jCwHO7jl/TODPfSeZgXkQiT5jgg63i5tlPB4Xn0MTSCX74bYIi16Tk=" + - *coverage_vars + - *codecov_secure - stage: Finalise Coverage if: branch IN (master, next) OR commit_message =~ /build coverage/ - addons: - apt: - packages: - - *standard_packages - - jq + *coverage_packages env: - - SCRIPT_FLAGS='-cu' - - PIP_PACKAGES='gcovr' - - secure: "M5U3I81hzK41Kw7KB+DpEMxP/sgkWkFI4uiRZQDMDFRlhcitsJQQ/YGeBt3a0vo153m2P2PmmeKUl/lTo5WS5SfAVFI8BkcyBjpxZQXV3OD8ru7JsMgVc5pGwl2dvR8Qz02gUIbrIpAlf3YDnNVb6F1C9ofDaCnZU3GUTLH5Fy5z5Z8OpuTaLmTVMMnT2ZEcRawHbmlVhIB/9PUQUa+fM7iC+dtszFxZ2ma5LOHxPS2sGpRCKE5Sae1/xAFWjo4oO0ZqYu5JFvKdb+/2yWKTg/1aTyxCdqAzLg4ldzDlX759zXgtWn+k3TLiVyQ+gsvF8QZkh4BKvl/w2KZ20vRP3blzmxvdsSH+ZP92MZIIK9EkNPGd+UJJd5Hu+zwecEFyfO8bXB9l00kzUsVx+lo7VHbANuNO3b5a6FRiihTCgk+dfOxxrow/fci+lQ9BkmJg0680SIj2e6UM/P9lFgfQLH3IoacN1PtkyqnpJqdHUdbWmpqMtmitmQhXHjnJ+wDb5+i9b1fy5yEsB64rjgF9PBr1/Nos1XD4oGWAknXmQTgWhNyy6f+e0wBNcSUd5nrReLTOAscyXYpcTqONp1W999JSFQEH+YTwBfXytdkWaAGAFEhaaAXQ2jCwHO7jl/TODPfSeZgXkQiT5jgg63i5tlPB4Xn0MTSCX74bYIi16Tk=" + - *coverage_vars + - *codecov_secure script: wget -q -O ~/codacy-coverage-reporter-assembly-latest.jar https://oss.sonatype.org/service/local/repositories/releases/content/com/codacy/codacy-coverage-reporter/4.0.5/codacy-coverage-reporter-4.0.5-assembly.jar ; java -jar ~/codacy-coverage-reporter-assembly-latest.jar final before_install: From 49c0f25c75a665d800ab7263f66cce02f08a5b2b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Feb 2019 11:47:35 +0000 Subject: [PATCH 0767/1783] Partly revert use of aliases in Travis yaml --- .travis.yml | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 15f7fadc57..923051d0ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,12 +17,6 @@ aliases: - SLEPC_ARCH="" - &codecov_secure - secure: "M5U3I81hzK41Kw7KB+DpEMxP/sgkWkFI4uiRZQDMDFRlhcitsJQQ/YGeBt3a0vo153m2P2PmmeKUl/lTo5WS5SfAVFI8BkcyBjpxZQXV3OD8ru7JsMgVc5pGwl2dvR8Qz02gUIbrIpAlf3YDnNVb6F1C9ofDaCnZU3GUTLH5Fy5z5Z8OpuTaLmTVMMnT2ZEcRawHbmlVhIB/9PUQUa+fM7iC+dtszFxZ2ma5LOHxPS2sGpRCKE5Sae1/xAFWjo4oO0ZqYu5JFvKdb+/2yWKTg/1aTyxCdqAzLg4ldzDlX759zXgtWn+k3TLiVyQ+gsvF8QZkh4BKvl/w2KZ20vRP3blzmxvdsSH+ZP92MZIIK9EkNPGd+UJJd5Hu+zwecEFyfO8bXB9l00kzUsVx+lo7VHbANuNO3b5a6FRiihTCgk+dfOxxrow/fci+lQ9BkmJg0680SIj2e6UM/P9lFgfQLH3IoacN1PtkyqnpJqdHUdbWmpqMtmitmQhXHjnJ+wDb5+i9b1fy5yEsB64rjgF9PBr1/Nos1XD4oGWAknXmQTgWhNyy6f+e0wBNcSUd5nrReLTOAscyXYpcTqONp1W999JSFQEH+YTwBfXytdkWaAGAFEhaaAXQ2jCwHO7jl/TODPfSeZgXkQiT5jgg63i5tlPB4Xn0MTSCX74bYIi16Tk=" - - &coverage_packages - addons: - apt: - packages: - - *standard_packages - - jq - &coverage_vars - SCRIPT_FLAGS='-cu' - PIP_PACKAGES='gcovr' @@ -86,7 +80,11 @@ matrix: compiler: clang #COVERAGE - if: branch IN (master, next) OR commit_message =~ /build coverage/ - *coverage_packages + addons: + apt: + packages: + - *standard_packages + - jq env: - CONFIGURE_OPTIONS='--enable-code-coverage --enable-debug --enable-track --enable-checks=3 --with-petsc --with-lapack --with-slepc --enable-openmp' - OMP_NUM_THREADS=2 @@ -94,7 +92,11 @@ matrix: - *petsc_vars - *codecov_secure - if: branch IN (master, next) OR commit_message =~ /build coverage/ - *coverage_packages + addons: + apt: + packages: + - *standard_packages + - jq env: - CONFIGURE_OPTIONS='--enable-code-coverage --disable-debug --disable-checks' - *coverage_vars @@ -102,7 +104,11 @@ matrix: - stage: Finalise Coverage if: branch IN (master, next) OR commit_message =~ /build coverage/ - *coverage_packages + addons: + apt: + packages: + - *standard_packages + - jq env: - *coverage_vars - *codecov_secure From ab1c36caba4d197b1393183e97471f53e2e014e9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Feb 2019 14:24:04 +0000 Subject: [PATCH 0768/1783] Expand exception message in FCI Trying to diagnose issue on Travis --- src/mesh/parallel/fci.cxx | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 1d37b1fe7a..f44b7d4547 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -165,6 +165,19 @@ FCIMap::FCIMap(Mesh &mesh_in, int dir, bool zperiodic) t_x = xt_prime(x, y, z) - static_cast(i_corner(x, y, z)); t_z = zt_prime(x, y, z) - static_cast(k_corner(x, y, z)); + // Check that t_x and t_z are in range + if ((t_x < 0.0) || (t_x > 1.0)) { + throw BoutException( + "t_x=%e out of range at (%d,%d,%d) (xt_prime=%e, i_corner=%d)", t_x, x, y, + z, xt_prime(x, y, z), i_corner(x, y, z)); + } + + if ((t_z < 0.0) || (t_z > 1.0)) { + throw BoutException( + "t_z=%e out of range at (%d,%d,%d) (zt_prime=%e, k_corner=%d)", t_z, x, y, + z, zt_prime(x, y, z), k_corner(x, y, z)); + } + //---------------------------------------- // Boundary stuff // @@ -221,15 +234,6 @@ FCIMap::FCIMap(Mesh &mesh_in, int dir, bool zperiodic) PI // Right-angle intersection ); } - - //---------------------------------------- - - // Check that t_x and t_z are in range - if ((t_x < 0.0) || (t_x > 1.0)) - throw BoutException("t_x=%e out of range at (%d,%d,%d)", t_x, x, y, z); - - if ((t_z < 0.0) || (t_z > 1.0)) - throw BoutException("t_z=%e out of range at (%d,%d,%d)", t_z, x, y, z); } } } From 2b96b2215b65a4f823bc9f67630117ee99864771 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 14 Feb 2019 13:57:38 +0000 Subject: [PATCH 0769/1783] Make application of INVERT_SET at outer boundary clearer in cyclic solver The condition at the outer boundary was (xe - ix < outbndry) && (outer_boundary_flags & INVERT_SET) && mesh->lastX()) This form is misleading, as the inner boundary condition does not depend on 'xs'. This commit changes the expression to: (mesh->LocalNx - ix - 1 < outbndry) && (outer_boundary_flags & INVERT_SET) && mesh->lastX()) Both are correct, as xe=mesh->LocalNx-1. However, it is possible this will change in future because solving in more than one guard cell is not necessary, and if the value of xe was changed (e.g. to mesh->xend+1) then the condition on the outer boundary would not be correct. --- src/invert/laplace/impls/cyclic/cyclic_laplace.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index 4370184bf0..3b907b4956 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -126,7 +126,7 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) // Take DST in Z direction and put result in k1d if (((ix < inbndry) && (inner_boundary_flags & INVERT_SET) && localmesh->firstX()) || - ((xe - ix < outbndry) && (outer_boundary_flags & INVERT_SET) && + ((localmesh->LocalNx - ix - 1 < outbndry) && (outer_boundary_flags & INVERT_SET) && localmesh->lastX())) { // Use the values in x0 in the boundary DST(x0[ix] + 1, localmesh->LocalNz - 2, std::begin(k1d)); @@ -194,7 +194,7 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) // Take FFT in Z direction, apply shift, and put result in k1d if (((ix < inbndry) && (inner_boundary_flags & INVERT_SET) && localmesh->firstX()) || - ((xe - ix < outbndry) && (outer_boundary_flags & INVERT_SET) && + ((localmesh->LocalNx - ix - 1 < outbndry) && (outer_boundary_flags & INVERT_SET) && localmesh->lastX())) { // Use the values in x0 in the boundary rfft(x0[ix], localmesh->LocalNz, std::begin(k1d)); @@ -319,7 +319,7 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { // Take DST in Z direction and put result in k1d if (((ix < inbndry) && (inner_boundary_flags & INVERT_SET) && localmesh->firstX()) || - ((xe - ix < outbndry) && (outer_boundary_flags & INVERT_SET) && + ((localmesh->LocalNx - ix - 1 < outbndry) && (outer_boundary_flags & INVERT_SET) && localmesh->lastX())) { // Use the values in x0 in the boundary DST(x0(ix, iy) + 1, localmesh->LocalNz - 2, std::begin(k1d)); @@ -401,7 +401,7 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { // Take FFT in Z direction, apply shift, and put result in k1d if (((ix < inbndry) && (inner_boundary_flags & INVERT_SET) && localmesh->firstX()) || - ((xe - ix < outbndry) && (outer_boundary_flags & INVERT_SET) && + ((localmesh->LocalNx - ix - 1 < outbndry) && (outer_boundary_flags & INVERT_SET) && localmesh->lastX())) { // Use the values in x0 in the boundary rfft(x0(ix, iy), localmesh->LocalNz, std::begin(k1d)); From ec808b10f89bd4472b79e5e1b69ce850fd6bb661 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Feb 2019 17:01:12 +0000 Subject: [PATCH 0770/1783] Expand error messages for interpolation methods --- src/mesh/interpolation/bilinear.cxx | 16 +++++++++++----- src/mesh/interpolation/hermite_spline.cxx | 14 ++++++++++---- src/mesh/interpolation/lagrange_4pt.cxx | 15 ++++++++++----- src/mesh/parallel/fci.cxx | 20 +++++++++++++++----- 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/mesh/interpolation/bilinear.cxx b/src/mesh/interpolation/bilinear.cxx index 0060cc12a0..3bb2073c63 100644 --- a/src/mesh/interpolation/bilinear.cxx +++ b/src/mesh/interpolation/bilinear.cxx @@ -61,11 +61,17 @@ void Bilinear::calcWeights(const Field3D &delta_x, const Field3D &delta_z) { BoutReal t_z1 = 1.0 - t_z; // Check that t_x and t_z are in range - if( (t_x < 0.0) || (t_x > 1.0) ) - throw BoutException("t_x=%e out of range at (%d,%d,%d)", t_x, x,y,z); - - if( (t_z < 0.0) || (t_z > 1.0) ) - throw BoutException("t_z=%e out of range at (%d,%d,%d)", t_z, x,y,z); + if ((t_x < 0.0) || (t_x > 1.0)) { + throw BoutException( + "t_x=%e out of range at (%d,%d,%d) (delta_x=%e, i_corner=%d)", t_x, x, y, + z, delta_x(x, y, z), i_corner(x, y, z)); + } + + if ((t_z < 0.0) || (t_z > 1.0)) { + throw BoutException( + "t_z=%e out of range at (%d,%d,%d) (delta_z=%e, k_corner=%d)", t_z, x, y, + z, delta_z(x, y, z), k_corner(x, y, z)); + } w0(x,y,z) = t_x1 * t_z1; w1(x,y,z) = t_x * t_z1; diff --git a/src/mesh/interpolation/hermite_spline.cxx b/src/mesh/interpolation/hermite_spline.cxx index b0c425470a..84d8298318 100644 --- a/src/mesh/interpolation/hermite_spline.cxx +++ b/src/mesh/interpolation/hermite_spline.cxx @@ -79,11 +79,17 @@ void HermiteSpline::calcWeights(const Field3D &delta_x, const Field3D &delta_z) } // Check that t_x and t_z are in range - if ((t_x < 0.0) || (t_x > 1.0)) - throw BoutException("t_x=%e out of range at (%d,%d,%d)", t_x, x, y, z); + if ((t_x < 0.0) || (t_x > 1.0)) { + throw BoutException( + "t_x=%e out of range at (%d,%d,%d) (delta_x=%e, i_corner=%d)", t_x, x, y, + z, delta_x(x, y, z), i_corner(x, y, z)); + } - if ((t_z < 0.0) || (t_z > 1.0)) - throw BoutException("t_z=%e out of range at (%d,%d,%d)", t_z, x, y, z); + if ((t_z < 0.0) || (t_z > 1.0)) { + throw BoutException( + "t_z=%e out of range at (%d,%d,%d) (delta_z=%e, k_corner=%d)", t_z, x, y, + z, delta_z(x, y, z), k_corner(x, y, z)); + } h00_x(x, y, z) = (2. * t_x * t_x * t_x) - (3. * t_x * t_x) + 1.; h00_z(x, y, z) = (2. * t_z * t_z * t_z) - (3. * t_z * t_z) + 1.; diff --git a/src/mesh/interpolation/lagrange_4pt.cxx b/src/mesh/interpolation/lagrange_4pt.cxx index c942976bc3..f1dd258a59 100644 --- a/src/mesh/interpolation/lagrange_4pt.cxx +++ b/src/mesh/interpolation/lagrange_4pt.cxx @@ -63,11 +63,16 @@ void Lagrange4pt::calcWeights(const Field3D &delta_x, const Field3D &delta_z) { } // Check that t_x and t_z are in range - if ((t_x(x, y, z) < 0.0) || (t_x(x, y, z) > 1.0)) - throw BoutException("t_x=%e out of range at (%d,%d,%d)", t_x(x, y, z), x, y, z); - - if ((t_z(x, y, z) < 0.0) || (t_z(x, y, z) > 1.0)) - throw BoutException("t_z=%e out of range at (%d,%d,%d)", t_z(x, y, z), x, y, z); + if ((t_x(x, y, z) < 0.0) || (t_x(x, y, z) > 1.0)) { + throw BoutException( + "t_x=%e out of range at (%d,%d,%d) (delta_x=%e, i_corner=%d)", t_x(x, y, z), x, y, + z, delta_x(x, y, z), i_corner(x, y, z)); + } + if ((t_z(x, y, z) < 0.0) || (t_z(x, y, z) > 1.0)) { + throw BoutException( + "t_z=%e out of range at (%d,%d,%d) (delta_z=%e, k_corner=%d)", t_z(x, y, z), x, y, + z, delta_z(x, y, z), k_corner(x, y, z)); + } } } } diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index f44b7d4547..7279dd7200 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -129,12 +129,22 @@ FCIMap::FCIMap(Mesh &mesh_in, int dir, bool zperiodic) } } } - + interp_corner->setMask(corner_boundary_mask); - interp_corner->calcWeights(xt_prime_corner, zt_prime_corner); - - interp->calcWeights(xt_prime, zt_prime); - + try { + interp_corner->calcWeights(xt_prime_corner, zt_prime_corner); + } catch (BoutException& e) { + output_error << "Error while calculating corner interpolation weights for FCI\n"; + throw; + } + + try { + interp->calcWeights(xt_prime, zt_prime); + } catch (BoutException& e) { + output_error << "Error while calculating interpolation weights for FCI\n"; + throw; + } + int ncz = mesh.LocalNz; BoutReal t_x, t_z; From ffd4836b04c05a33904911cdf6131e53960f6a88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 14 Feb 2019 17:35:48 +0000 Subject: [PATCH 0771/1783] Disable version dependent clang-format --- bin/bout_4to5 | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/bin/bout_4to5 b/bin/bout_4to5 index b6e8890a4a..dce3cc136d 100755 --- a/bin/bout_4to5 +++ b/bin/bout_4to5 @@ -201,19 +201,19 @@ then fi -# clang-format everything -if test $# -eq 0 -then - for dir in $work - do - files=$(find $dir|grep xx\$ ) - if test "$files" - then - verbose " Running clang-format on all files in $dir" - clang-format -i $files - fi - done -fi +# # clang-format everything - disabled due to issue https://github.com/boutproject/BOUT-dev/issues/1017 +# if test $# -eq 0 +# then +# for dir in $work +# do +# files=$(find $dir|grep xx\$ ) +# if test "$files" +# then +# verbose " Running clang-format on all files in $dir" +# clang-format -i $files +# fi +# done +# fi #Further changes: From 1d065f0158ad2aa7adbb1b6925e8c17316115496 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 15 Feb 2019 09:58:40 +0000 Subject: [PATCH 0772/1783] Renaming directory spa -> en --- locale/{spa => es}/libbout.po | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename locale/{spa => es}/libbout.po (100%) diff --git a/locale/spa/libbout.po b/locale/es/libbout.po similarity index 100% rename from locale/spa/libbout.po rename to locale/es/libbout.po From dcf797b08963f04336dd80eb41e97e084d1d0945 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 15 Feb 2019 11:01:19 +0000 Subject: [PATCH 0773/1783] Change spa->es in libbout.po file --- locale/es/libbout.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locale/es/libbout.po b/locale/es/libbout.po index 87fe2dd7ee..c0758ca19d 100644 --- a/locale/es/libbout.po +++ b/locale/es/libbout.po @@ -11,7 +11,7 @@ msgstr "" "PO-Revision-Date: 2019-02-11 12:46+0900\n" "Last-Translator: Marta \n" "Language-Team: Spanish\n" -"Language: spa\n" +"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" From 45949910fdd67adf83a2853f2108eaddef66ae69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Sat, 16 Feb 2019 16:40:03 +0000 Subject: [PATCH 0774/1783] better default for runcmd Allows to change mpirun with the environement varibale MPIRUN --- tools/pylib/boututils/run_wrapper.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/pylib/boututils/run_wrapper.py b/tools/pylib/boututils/run_wrapper.py index 985b98157b..a639196dbb 100644 --- a/tools/pylib/boututils/run_wrapper.py +++ b/tools/pylib/boututils/run_wrapper.py @@ -184,7 +184,7 @@ def determineNumberOfCPUs(): raise Exception('Can not determine number of CPUs on this system') -def launch(command, runcmd="mpirun -np", nproc=None, mthread=None, +def launch(command, runcmd=None, nproc=None, mthread=None, output=None, pipe=False, verbose=False): """Launch parallel MPI jobs @@ -195,7 +195,7 @@ def launch(command, runcmd="mpirun -np", nproc=None, mthread=None, command : str The command to run runcmd : str, optional - Command for running parallel job; defaults to "mpirun -np" + Command for running parallel job; defaults to what getmpirun() returns" nproc : int, optional Number of processors (default: all available processors) mthread : int, optional @@ -215,6 +215,9 @@ def launch(command, runcmd="mpirun -np", nproc=None, mthread=None, """ + if runcmd is None: + runcmd = getmpirun() + if nproc is None: # Determine number of CPUs on this machine nproc = determineNumberOfCPUs() From 13739dc1cd697f3b82d1e05687fb7188f6842c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Sat, 16 Feb 2019 17:44:23 +0000 Subject: [PATCH 0775/1783] Cleanup and fixes to use $MPIRUN * With the changed default for launch, we can get rid of all the getmpirun() calls etc * Fixes for bash to default to $MPIRUN if set --- examples/conduction/run | 4 ++-- examples/elm-pb/runexample | 6 +++--- examples/fci-wave/compare-density.py | 8 +++----- examples/finite-volume/fluid/runtest | 4 ++-- examples/laplacexy/laplace_perp/runtest | 4 ++-- tests/MMS/GBS/runtest-slab2d | 6 +++--- tests/MMS/GBS/runtest-slab3d | 6 +++--- tests/MMS/advection/runtest | 6 +++--- tests/MMS/diffusion/runtest | 6 +++--- tests/MMS/diffusion2/runtest | 6 +++--- tests/MMS/elm-pb/runtest | 6 +++--- tests/MMS/fieldalign/runtest | 6 +++--- tests/MMS/hw/runtest | 6 +++--- tests/MMS/laplace/runtest | 6 +++--- tests/MMS/spatial/advection/runtest | 6 +++--- tests/MMS/spatial/d2dx2/runtest | 6 +++--- tests/MMS/spatial/d2dz2/runtest | 6 +++--- tests/MMS/spatial/diffusion/runtest | 6 +++--- tests/MMS/spatial/fci/runtest | 6 +++--- tests/MMS/time/runtest | 6 +++--- tests/MMS/tokamak/runtest | 6 +++--- tests/MMS/wave-1d-y/runtest | 6 +++--- tests/MMS/wave-1d/runtest | 6 +++--- tests/integrated/test-cyclic/runtest | 6 +++--- tests/integrated/test-delp2/runtest | 8 ++++---- .../integrated/test-drift-instability/runcase.sh | 11 ++++------- .../integrated/test-drift-instability/runtest.py | 6 +++--- tests/integrated/test-fieldfactory/runtest | 6 +++--- tests/integrated/test-fieldgroupComm/runtest | 6 +++--- tests/integrated/test-griddata/runtest | 6 +++--- tests/integrated/test-gyro/runtest | 6 +++--- tests/integrated/test-initial/runtest | 6 +++--- .../test-interchange-instability/runcase.sh | 15 ++++++--------- .../test-interchange-instability/runtest | 6 +++--- tests/integrated/test-interpolate/runtest | 6 +++--- tests/integrated/test-invertable-operator/runtest | 6 +++--- tests/integrated/test-invpar/runtest | 6 +++--- tests/integrated/test-io/runtest | 6 +++--- tests/integrated/test-io_hdf5/runtest | 6 +++--- tests/integrated/test-laplace/runtest | 6 +++--- tests/integrated/test-multigrid_laplace/runtest | 6 +++--- .../test-multigrid_laplace/runtest_multiple_grids | 6 +++--- .../test-multigrid_laplace/runtest_unsheared | 6 +++--- tests/integrated/test-naulin-laplace/runtest | 6 +++--- .../test-naulin-laplace/runtest_multiple_grids | 6 +++--- .../test-naulin-laplace/runtest_unsheared | 6 +++--- tests/integrated/test-petsc_laplace/runtest | 6 +++--- .../test-petsc_laplace_MAST-grid/runtest | 6 +++--- tests/integrated/test-region-iterator/runtest | 6 +++--- tests/integrated/test-restarting/runtest | 14 +++++++------- tests/integrated/test-simple-diffusion/runcase.sh | 12 +++++------- tests/integrated/test-smooth/runtest | 6 +++--- tests/integrated/test-solver/runtest | 6 +++--- tests/integrated/test-stopCheck-file/runtest | 6 +++--- tests/integrated/test-subdir/runtest | 4 +++- tests/integrated/test-vec/runtest | 4 +++- tests/integrated/test-yupdown/runtest | 6 +++--- 57 files changed, 179 insertions(+), 185 deletions(-) diff --git a/examples/conduction/run b/examples/conduction/run index b2f95fb013..5bb0d7c197 100755 --- a/examples/conduction/run +++ b/examples/conduction/run @@ -11,12 +11,12 @@ from boutdata.collect import collect import numpy as np nproc = 2 # Number of processors to use -MPIRUN = getmpirun() + print("Making conduction example") shell("make > make.log") -s, out = launch("./conduction ", runcmd=MPIRUN, nproc=nproc, pipe=True) +s, out = launch("./conduction ", nproc=nproc, pipe=True) f = open("run.log", "w") # Save the output in a log file f.write(out) f.close() diff --git a/examples/elm-pb/runexample b/examples/elm-pb/runexample index 01bd050601..f7ebc01028 100755 --- a/examples/elm-pb/runexample +++ b/examples/elm-pb/runexample @@ -2,7 +2,7 @@ from __future__ import print_function from builtins import str -from boututils.run_wrapper import shell, launch, getmpirun +from boututils.run_wrapper import shell, launch from boutdata.collect import collect import numpy as np @@ -12,8 +12,8 @@ shell("make > make.log") # Run simulation nproc = 2 -MPIRUN = getmpirun() -s, out = launch("./elm_pb ", runcmd=MPIRUN, nproc=nproc, pipe=True) + +s, out = launch("./elm_pb ", nproc=nproc, pipe=True) with open("run.log", "w") as f: f.write(out) diff --git a/examples/fci-wave/compare-density.py b/examples/fci-wave/compare-density.py index 9ddf0123c4..c039c250b6 100644 --- a/examples/fci-wave/compare-density.py +++ b/examples/fci-wave/compare-density.py @@ -25,13 +25,11 @@ data = data_noboundary if run: - from boututils.run_wrapper import shell_safe, launch_safe, getmpirun - + from boututils.run_wrapper import shell_safe, launch_safe shell_safe("make > make.log") - MPIRUN=getmpirun() - + for path,label in data: - launch_safe("./fci-wave -d "+path, runcmd=MPIRUN, nproc=nproc, pipe=False) + launch_safe("./fci-wave -d "+path, nproc=nproc, pipe=False) # Collect the results into a dictionary sum_n_B = {} diff --git a/examples/finite-volume/fluid/runtest b/examples/finite-volume/fluid/runtest index 24a1dcd303..e1b4088c53 100755 --- a/examples/finite-volume/fluid/runtest +++ b/examples/finite-volume/fluid/runtest @@ -15,7 +15,7 @@ from boutdata.collect import collect from numpy import sqrt, max, abs, mean, array, log, concatenate -MPIRUN = getmpirun() + print("Making fluid model MMS test") shell("make > make.log") @@ -45,7 +45,7 @@ for ny in nylist: # Command to run cmd = "./fluid -d mms "+args # Launch using MPI - s, out = launch(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(ny), "w") diff --git a/examples/laplacexy/laplace_perp/runtest b/examples/laplacexy/laplace_perp/runtest index 54fd465b39..ffaf48bff0 100755 --- a/examples/laplacexy/laplace_perp/runtest +++ b/examples/laplacexy/laplace_perp/runtest @@ -2,7 +2,7 @@ from __future__ import print_function -from boututils.run_wrapper import shell, launch, getmpirun +from boututils.run_wrapper import shell, launch from boutdata.collect import collect from sys import stdout, exit @@ -18,7 +18,7 @@ print("Making test") shell("make > make.log") print("Running test") -s, out = launch("./test -d "+path, runcmd=getmpirun(), nproc=1, pipe=True) +s, out = launch("./test -d "+path, nproc=1, pipe=True) # Analyse data diff --git a/tests/MMS/GBS/runtest-slab2d b/tests/MMS/GBS/runtest-slab2d index f9a4857574..037988b0fc 100755 --- a/tests/MMS/GBS/runtest-slab2d +++ b/tests/MMS/GBS/runtest-slab2d @@ -6,12 +6,12 @@ from __future__ import division from __future__ import print_function from builtins import str -from boututils.run_wrapper import shell, launch_safe, getmpirun +from boututils.run_wrapper import shell, launch_safe from boutdata.collect import collect from numpy import sqrt, max, abs, mean, array, log, concatenate -MPIRUN = getmpirun() + print("Making MMS test") shell("make > make.log") @@ -46,7 +46,7 @@ for nx in nxlist: # Command to run cmd = "./gbs "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open(path+"/run.log."+str(nx), "w") diff --git a/tests/MMS/GBS/runtest-slab3d b/tests/MMS/GBS/runtest-slab3d index 23f24b187e..ff95aa3f5e 100755 --- a/tests/MMS/GBS/runtest-slab3d +++ b/tests/MMS/GBS/runtest-slab3d @@ -7,14 +7,14 @@ from __future__ import print_function from builtins import zip from builtins import str -from boututils.run_wrapper import shell, launch_safe, getmpirun +from boututils.run_wrapper import shell, launch_safe from boutdata.collect import collect from numpy import sqrt, max, abs, mean, array, log, concatenate import pickle -MPIRUN = getmpirun() + print("Making MMS test") shell("make > make.log") @@ -51,7 +51,7 @@ for nx in nxlist: # Command to run cmd = "./gbs "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open(path+"/run.log."+str(nx), "w") diff --git a/tests/MMS/advection/runtest b/tests/MMS/advection/runtest index 939fee497e..b5798a03f6 100755 --- a/tests/MMS/advection/runtest +++ b/tests/MMS/advection/runtest @@ -8,7 +8,7 @@ #requires: all_tests #requires: make -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from numpy import sqrt, max, abs, mean, array, log, pi @@ -19,7 +19,7 @@ import pickle import time -MPIRUN = getmpirun() + if __name__ == "__main__": print("Making MMS advection test") @@ -64,7 +64,7 @@ def run_mms(options,exit=True): # Launch using MPI start_time_ = time.time() - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(nx), "w") diff --git a/tests/MMS/diffusion/runtest b/tests/MMS/diffusion/runtest index 5c8b35eb85..d19f9b8457 100755 --- a/tests/MMS/diffusion/runtest +++ b/tests/MMS/diffusion/runtest @@ -9,12 +9,12 @@ try: except: pass -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from numpy import sqrt, max, abs, mean, array, log -MPIRUN = getmpirun() + print("Making MMS diffusion test") shell_safe("make > make.log") @@ -41,7 +41,7 @@ for nx in nxlist: # Command to run cmd = "./cyto "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(nx), "w") diff --git a/tests/MMS/diffusion2/runtest b/tests/MMS/diffusion2/runtest index aca3f829d0..3278974f77 100755 --- a/tests/MMS/diffusion2/runtest +++ b/tests/MMS/diffusion2/runtest @@ -12,14 +12,14 @@ from __future__ import division from __future__ import print_function from builtins import str -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from numpy import sqrt, max, abs, mean, array, log from os.path import join -MPIRUN = getmpirun() + print("Making MMS diffusion test") shell_safe("make > make.log") @@ -63,7 +63,7 @@ for dir,sizes in inputs: # Command to run cmd = "./cyto "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(nx), "w") diff --git a/tests/MMS/elm-pb/runtest b/tests/MMS/elm-pb/runtest index a49d080f45..6890ac0cdc 100755 --- a/tests/MMS/elm-pb/runtest +++ b/tests/MMS/elm-pb/runtest @@ -12,7 +12,7 @@ from __future__ import print_function from builtins import zip from builtins import str -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boututils.datafile import DataFile from boutdata.collect import collect @@ -51,7 +51,7 @@ shape.add(P0, "pressure") shape.add(J0, "Jpar0") shape.add(bxcvz, "bxcvz") -MPIRUN = getmpirun() + print("Making MMS elm-pb test") shell_safe("make > make.log") @@ -107,7 +107,7 @@ for nx,nproc in zip(nxlist, nprocs): # Command to run cmd = "./elm_pb "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(nx), "w") diff --git a/tests/MMS/fieldalign/runtest b/tests/MMS/fieldalign/runtest index 53296d3b5b..23b9bb7c44 100755 --- a/tests/MMS/fieldalign/runtest +++ b/tests/MMS/fieldalign/runtest @@ -8,7 +8,7 @@ from __future__ import division from __future__ import print_function from builtins import str -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import pickle @@ -17,7 +17,7 @@ from numpy import sqrt, max, abs, mean, array, log, zeros from os.path import join import time -MPIRUN = getmpirun() + print("Making MMS test") shell_safe("make > make.log") @@ -60,7 +60,7 @@ for dir in inputs: cmd = "./fieldalign "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(nx), "w") diff --git a/tests/MMS/hw/runtest b/tests/MMS/hw/runtest index 1d3c03af7d..9569532be2 100755 --- a/tests/MMS/hw/runtest +++ b/tests/MMS/hw/runtest @@ -8,12 +8,12 @@ from __future__ import division from __future__ import print_function from builtins import str -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from numpy import sqrt, max, abs, mean, array, log, concatenate -MPIRUN = getmpirun() + print("Making MMS test") shell_safe("make > make.log") @@ -42,7 +42,7 @@ for nx in nxlist: # Command to run cmd = "./hw "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(nx), "w") diff --git a/tests/MMS/laplace/runtest b/tests/MMS/laplace/runtest index 166ce0db47..78a684e357 100755 --- a/tests/MMS/laplace/runtest +++ b/tests/MMS/laplace/runtest @@ -8,12 +8,12 @@ from __future__ import division from __future__ import print_function from builtins import str -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from numpy import sqrt, max, abs, mean, array, log, concatenate -MPIRUN = getmpirun() + print("Making MMS test") shell_safe("make > make.log") @@ -40,7 +40,7 @@ for nx in nxlist: # Command to run cmd = "./laplace "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(nx), "w") diff --git a/tests/MMS/spatial/advection/runtest b/tests/MMS/spatial/advection/runtest index 0a7bab42e9..4364c291a8 100755 --- a/tests/MMS/spatial/advection/runtest +++ b/tests/MMS/spatial/advection/runtest @@ -12,7 +12,7 @@ from __future__ import print_function from builtins import str from builtins import range -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from numpy import sqrt, max, abs, mean, array, log, pi @@ -23,7 +23,7 @@ import matplotlib.pyplot as plt import pickle -MPIRUN = getmpirun() + print("Making MMS steady-state advection test") shell_safe("make > make.log") @@ -65,7 +65,7 @@ for opts,label,sym,exp_ord in options: # Command to run cmd = "./advection "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(nx), "w") diff --git a/tests/MMS/spatial/d2dx2/runtest b/tests/MMS/spatial/d2dx2/runtest index 08a7c575e7..f9c5b508d0 100755 --- a/tests/MMS/spatial/d2dx2/runtest +++ b/tests/MMS/spatial/d2dx2/runtest @@ -4,7 +4,7 @@ from __future__ import division from __future__ import print_function from builtins import str -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from numpy import sqrt, max, abs, mean, array, log @@ -16,7 +16,7 @@ except: #requires: all_tests -MPIRUN = getmpirun() + print("Making MMS d2dx2 test") shell_safe("make > make.log") @@ -39,7 +39,7 @@ for nx in nxlist: cmd = "./test_d2dx2 "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(nx), "w") diff --git a/tests/MMS/spatial/d2dz2/runtest b/tests/MMS/spatial/d2dz2/runtest index 7526d8ba63..3e843785f0 100755 --- a/tests/MMS/spatial/d2dz2/runtest +++ b/tests/MMS/spatial/d2dz2/runtest @@ -4,7 +4,7 @@ from __future__ import division from __future__ import print_function from builtins import str -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from numpy import sqrt, max, abs, mean, array, log @@ -16,7 +16,7 @@ except: #requires: all_tests -MPIRUN = getmpirun() + print("Making MMS d2dz2 test") shell_safe("make > make.log") @@ -39,7 +39,7 @@ for mz in mzlist: cmd = "./test_d2dz2 "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(mz), "w") diff --git a/tests/MMS/spatial/diffusion/runtest b/tests/MMS/spatial/diffusion/runtest index c28a3cf3a4..0de6897a21 100755 --- a/tests/MMS/spatial/diffusion/runtest +++ b/tests/MMS/spatial/diffusion/runtest @@ -13,7 +13,7 @@ from __future__ import division from __future__ import print_function from builtins import str -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from numpy import sqrt, max, abs, mean, array, log @@ -22,7 +22,7 @@ from os.path import join import matplotlib.pyplot as plt -MPIRUN = getmpirun() + print("Making MMS diffusion test") shell_safe("make > make.log") @@ -63,7 +63,7 @@ for dir,sizes in inputs: # Command to run cmd = "./diffusion "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(nx), "w") diff --git a/tests/MMS/spatial/fci/runtest b/tests/MMS/spatial/fci/runtest index 99ec92edc2..dfbca4e505 100755 --- a/tests/MMS/spatial/fci/runtest +++ b/tests/MMS/spatial/fci/runtest @@ -5,7 +5,7 @@ from __future__ import division from __future__ import print_function -from boututils.run_wrapper import shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell_safe, launch_safe from boutdata.collect import collect from numpy import array, log, polyfit, linspace, arange @@ -29,7 +29,7 @@ directory = "data" nproc = 2 mthread = 2 -MPIRUN = getmpirun() + success = True @@ -86,7 +86,7 @@ for nslice in nslices: print("Running command: "+cmd) # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, mthread=mthread, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, mthread=mthread, pipe=True) # Save output to log file with open("run.log."+str(n), "w") as f: diff --git a/tests/MMS/time/runtest b/tests/MMS/time/runtest index 61fc3a9f8c..d570688227 100755 --- a/tests/MMS/time/runtest +++ b/tests/MMS/time/runtest @@ -9,7 +9,7 @@ from __future__ import division from __future__ import print_function from builtins import str -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect #requires: all_tests @@ -27,7 +27,7 @@ try: except: plt=None -MPIRUN = getmpirun() + print("Making MMS time integration test") shell_safe("make > make.log") @@ -73,7 +73,7 @@ for opts,label,sym,expected_order in options: # Command to run cmd = "./time "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+label+"."+str(nt), "w") diff --git a/tests/MMS/tokamak/runtest b/tests/MMS/tokamak/runtest index 0ba58b4e8b..3fb542250f 100755 --- a/tests/MMS/tokamak/runtest +++ b/tests/MMS/tokamak/runtest @@ -12,7 +12,7 @@ from __future__ import print_function from builtins import zip from builtins import str -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boututils.datafile import DataFile from boutdata.collect import collect @@ -29,7 +29,7 @@ from sys import stdout from boutdata.mms import SimpleTokamak shape = SimpleTokamak() -MPIRUN = getmpirun() + print("Making MMS tokamak geometry test") shell_safe("make > make.log") @@ -74,7 +74,7 @@ for nx,nproc in zip(nxlist, nprocs): # Command to run cmd = "./tokamak "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(nx), "w") diff --git a/tests/MMS/wave-1d-y/runtest b/tests/MMS/wave-1d-y/runtest index 168cea6807..ea332f79cd 100755 --- a/tests/MMS/wave-1d-y/runtest +++ b/tests/MMS/wave-1d-y/runtest @@ -10,7 +10,7 @@ try: except: pass -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import pickle @@ -19,7 +19,7 @@ from sys import stdout from numpy import sqrt, max, abs, mean, array, log, concatenate, pi -MPIRUN = getmpirun() + print("Making MMS wave test") shell_safe("make > make.log") @@ -54,7 +54,7 @@ for ny in nylist: # Command to run cmd = "./wave "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file with open("run.log."+str(ny), "w") as f: diff --git a/tests/MMS/wave-1d/runtest b/tests/MMS/wave-1d/runtest index f400d919c2..39278d500a 100755 --- a/tests/MMS/wave-1d/runtest +++ b/tests/MMS/wave-1d/runtest @@ -10,12 +10,12 @@ try: except: pass -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from numpy import sqrt, max, abs, mean, array, log, concatenate -MPIRUN = getmpirun() + print("Making MMS wave test") shell_safe("make > make.log") @@ -42,7 +42,7 @@ for nx in nxlist: # Command to run cmd = "./wave "+args # Launch using MPI - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) # Save output to log file f = open("run.log."+str(nx), "w") diff --git a/tests/integrated/test-cyclic/runtest b/tests/integrated/test-cyclic/runtest index b9043f71ec..e64a78abda 100755 --- a/tests/integrated/test-cyclic/runtest +++ b/tests/integrated/test-cyclic/runtest @@ -9,11 +9,11 @@ try: from builtins import str except: pass -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from sys import stdout, exit -MPIRUN=getmpirun() + print("Making Cyclic Reduction test") shell_safe("make > make.log") @@ -32,7 +32,7 @@ for nproc in [1,2,4]: shell("rm data/BOUT.dmp.* 2> err.log") # Run the case - s, out = launch_safe(cmd+" "+f, runcmd=MPIRUN, nproc=nproc, mthread=1, pipe=True) + s, out = launch_safe(cmd+" "+f, nproc=nproc, mthread=1, pipe=True) with open("run.log."+str(nproc)+"."+str(r), "w") as f: f.write(out) diff --git a/tests/integrated/test-delp2/runtest b/tests/integrated/test-delp2/runtest index 6925b2f0c1..fb98b4b6a4 100755 --- a/tests/integrated/test-delp2/runtest +++ b/tests/integrated/test-delp2/runtest @@ -8,14 +8,14 @@ except: #requires: fftw -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import numpy as np from sys import stdout, exit tol = 1e-10 # Absolute tolerance -MPIRUN=getmpirun() + print("Making Delp2 operator test") shell_safe("make > make.log") @@ -36,7 +36,7 @@ for i, opts in enumerate(settings): print("Args: " + opts) cmd = exefile + " " + opts - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=1, pipe=True) + s, out = launch_safe(cmd, nproc=1, pipe=True) with open("run.log."+str(i)+".1", "w") as f: f.write(out) @@ -46,7 +46,7 @@ for i, opts in enumerate(settings): shell("rm data/BOUT.dmp.*.nc") stdout.write(" %d processor...." % (nproc)) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, mthread=1, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, mthread=1, pipe=True) with open("run.log."+str(i)+"."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-drift-instability/runcase.sh b/tests/integrated/test-drift-instability/runcase.sh index 1b05db59fb..9e78c7cdc1 100755 --- a/tests/integrated/test-drift-instability/runcase.sh +++ b/tests/integrated/test-drift-instability/runcase.sh @@ -3,19 +3,16 @@ NO_ARGS=0 OPTERROR=65 -if [ $# -eq "$NO_ARGS" ] # Script invoked with no command-line args? -then - NP=4 - MPIEXEC="mpirun -np" +test ".$MPIRUN" = . && MPIRUN="mpirun -np" +NP=4 -fi # Usage: scriptname -options # Note: dash (-) necessary while getopts ":n:np" Option do case $Option in - n ) MPIEXEC="mpirun -np";NP=$OPTARG;; + n ) NP=$OPTARG;; * ) ;; # DEFAULT esac done @@ -42,7 +39,7 @@ do mv -f data/tmp data/BOUT.inp fi - $MPIEXEC $NP ./2fluid + $MPIRUN $NP ./2fluid rm -f data done diff --git a/tests/integrated/test-drift-instability/runtest.py b/tests/integrated/test-drift-instability/runtest.py index bf5b686a63..d632e4ddab 100755 --- a/tests/integrated/test-drift-instability/runtest.py +++ b/tests/integrated/test-drift-instability/runtest.py @@ -17,7 +17,7 @@ omega_tol = 1e-2 gamma_tol = 1e-2 -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boututils.file_import import file_import from boututils.calculus import deriv from boututils.linear_regression import linear_regression @@ -27,7 +27,7 @@ from sys import exit ,argv nthreads=1 -MPIRUN = getmpirun() + print("Making resistive drift instability test") shell_safe("make > make.log") @@ -80,7 +80,7 @@ print("Running drift instability test, zeff = ", zeff) # Run the case - s, out = launch_safe("./2fluid timestep="+str(timestep), runcmd=MPIRUN, nproc=nproc, mthread=nthreads, pipe=True) + s, out = launch_safe("./2fluid timestep="+str(timestep), nproc=nproc, mthread=nthreads, pipe=True) f = open("run.log."+str(zeff), "w") f.write(out) f.close() diff --git a/tests/integrated/test-fieldfactory/runtest b/tests/integrated/test-fieldfactory/runtest index e06d71de79..511240a6cd 100755 --- a/tests/integrated/test-fieldfactory/runtest +++ b/tests/integrated/test-fieldfactory/runtest @@ -15,12 +15,12 @@ except: vars = ['a', 'b', 'c', 'd'] # Variables to compare tol = 1e-10 # Absolute tolerance -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import numpy as np from sys import stdout, exit -MPIRUN=getmpirun() + print("Making FieldFactory test") shell_safe("make > make.log") @@ -40,7 +40,7 @@ for nproc in [1,2,4]: shell("rm data/BOUT.dmp.*.nc") print(" %d processor...." % (nproc)) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-fieldgroupComm/runtest b/tests/integrated/test-fieldgroupComm/runtest index 34be7bcfed..b1e75767eb 100755 --- a/tests/integrated/test-fieldgroupComm/runtest +++ b/tests/integrated/test-fieldgroupComm/runtest @@ -13,7 +13,7 @@ try: except: pass -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from numpy import abs, seterr from sys import stdout, exit @@ -28,7 +28,7 @@ name = "FieldGroup comm" exeName = "test" tol = 1e-10 # Relative tolerance -MPIRUN=getmpirun() + print("Making {nm} test".format(nm=name)) shell_safe("make > make.log") @@ -46,7 +46,7 @@ for nproc in [1,2,4]: shell("rm data/BOUT.dmp.*.nc") print(" %d processors ...." % (nproc)) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-griddata/runtest b/tests/integrated/test-griddata/runtest index 8a6a667a90..19e3906527 100755 --- a/tests/integrated/test-griddata/runtest +++ b/tests/integrated/test-griddata/runtest @@ -7,13 +7,13 @@ try: except: pass -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import numpy as np from sys import stdout, exit -MPIRUN=getmpirun() + print("Making griddata test") shell_safe("make > make.log") @@ -22,7 +22,7 @@ for nproc in [1]: stdout.write("Checking %d processors ... " % (nproc)) shell("rm ./data*nc") - s, out = launch_safe("./test_griddata -d screw", runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe("./test_griddata -d screw", nproc=nproc, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-gyro/runtest b/tests/integrated/test-gyro/runtest index 516467759c..dcb4bd3a0c 100755 --- a/tests/integrated/test-gyro/runtest +++ b/tests/integrated/test-gyro/runtest @@ -15,12 +15,12 @@ vars = ['pade1', 'pade2'] tol = 1e-10 # Absolute tolerance -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import numpy as np from sys import stdout, exit -MPIRUN=getmpirun() + print("Making Gyro-average inversion test") shell_safe("make > make.log") @@ -44,7 +44,7 @@ for nproc in [1,2,4]: shell("rm data/BOUT.dmp.*.nc") print(" %d processors (nxpe = %d)...." % (nproc, nxpe)) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-initial/runtest b/tests/integrated/test-initial/runtest index 0f5c6c83eb..cffeb872eb 100755 --- a/tests/integrated/test-initial/runtest +++ b/tests/integrated/test-initial/runtest @@ -2,7 +2,7 @@ # Test initial conditions -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import configparser @@ -155,7 +155,7 @@ tolerance = 1e-13 cmd = "./test_initial" datadir = "data" inputfile = os.path.join(datadir, "BOUT.inp") -MPIRUN = getmpirun() + # Read the input file config = configparser.ConfigParser() @@ -185,7 +185,7 @@ shell_safe("make > make.log") nprocs = [1, 2, 3, 4] for nproc in nprocs: - status, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True, verbose=True) + status, out = launch_safe(cmd, nproc=nproc, pipe=True, verbose=True) with open("run.log.{}".format(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-interchange-instability/runcase.sh b/tests/integrated/test-interchange-instability/runcase.sh index ed911bc6a6..450542bd67 100755 --- a/tests/integrated/test-interchange-instability/runcase.sh +++ b/tests/integrated/test-interchange-instability/runcase.sh @@ -9,7 +9,7 @@ OPTERROR=65 ##-setting defaults -MPIEXEC="mpirun -np " +test ".$MPIRUN" = . && MPIRUN="mpirun -np" NP=4 @@ -19,30 +19,27 @@ n) NP=$OPTARG; ;; m) - MPIEXEC=$OPTARG; + MPIRUN=$OPTARG; ;; esac done -echo "Running command: " $MPIEXEC $NP +echo "Running command: " $MPIRUN $NP #-compile/build local executable make -#-run the case +#-run the cases echo Running with NP = $NP -ln -s data_1 data -$MPIEXEC $NP ./2fluid +$MPIRUN $NP ./2fluid -d data_1 rm -f data -ln -s data_10 data -$MPIEXEC $NP ./2fluid +$MPIRUN $NP ./2fluid -d data_10 rm -f data #-check the result idl runidl.pro - diff --git a/tests/integrated/test-interchange-instability/runtest b/tests/integrated/test-interchange-instability/runtest index 4a7242d52d..a54cd78361 100755 --- a/tests/integrated/test-interchange-instability/runtest +++ b/tests/integrated/test-interchange-instability/runtest @@ -9,13 +9,13 @@ from __future__ import division nproc = 2 # Number of processors to run on reltol = 1.e-3 # Allowed relative tolerance in growth-rate -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import numpy as np from sys import stdout, exit nthreads=1 -MPIRUN = getmpirun() + print("Making interchange instability test") shell_safe("make > make.log") @@ -28,7 +28,7 @@ def growth_rate(path, nproc, log=False): pipe = False if log != False: pipe = True - s, out = launch_safe("./2fluid -d "+path, runcmd=MPIRUN, nproc=nproc, mthread=nthreads, pipe=pipe) + s, out = launch_safe("./2fluid -d "+path, nproc=nproc, mthread=nthreads, pipe=pipe) if pipe: f = open(log, "w") f.write(out) diff --git a/tests/integrated/test-interpolate/runtest b/tests/integrated/test-interpolate/runtest index bc6e5957fe..5ca1259e17 100755 --- a/tests/integrated/test-interpolate/runtest +++ b/tests/integrated/test-interpolate/runtest @@ -4,7 +4,7 @@ # Run the test, compare results against the benchmark # -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata import collect from numpy import sqrt, max, abs, mean, array, log, polyfit from sys import stdout, exit @@ -29,7 +29,7 @@ methods = { "bilinear": 2, } -MPIRUN = getmpirun() + print("Making Interpolation test") shell_safe("make > make.log") @@ -57,7 +57,7 @@ for method in methods: shell("rm data/BOUT.dmp.*.nc") - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) with open("run.log.{}.{}".format(method, nx), "w") as f: f.write(out) diff --git a/tests/integrated/test-invertable-operator/runtest b/tests/integrated/test-invertable-operator/runtest index c83c902f86..11b366f804 100755 --- a/tests/integrated/test-invertable-operator/runtest +++ b/tests/integrated/test-invertable-operator/runtest @@ -9,7 +9,7 @@ from __future__ import print_function from __future__ import division -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import numpy as np from sys import stdout, exit @@ -17,7 +17,7 @@ from sys import stdout, exit nprocs = [1,2] # Number of processors to run on reltol = 1.e-3 # Allowed relative tolerance nthreads=1 -MPIRUN = getmpirun() + print("Making invertable operator test") shell_safe("make > make.log") @@ -29,7 +29,7 @@ def run(path, nproc, log=False): pipe = False if log != False: pipe = True - s, out = launch_safe("./invertable_operator -d "+path, runcmd=MPIRUN, nproc=nproc, mthread=nthreads, pipe=pipe) + s, out = launch_safe("./invertable_operator -d "+path, nproc=nproc, mthread=nthreads, pipe=pipe) if pipe: f = open(log, "w") f.write(out) diff --git a/tests/integrated/test-invpar/runtest b/tests/integrated/test-invpar/runtest index ed2b2a1487..6ef833d631 100755 --- a/tests/integrated/test-invpar/runtest +++ b/tests/integrated/test-invpar/runtest @@ -9,11 +9,11 @@ try: from builtins import str except: pass -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from sys import stdout, exit -MPIRUN=getmpirun() + print("Making parallel inversion test") @@ -35,7 +35,7 @@ for nproc in [1,2,4]: shell("rm data/BOUT.dmp.* 2> err.log") # Run the case - s, out = launch_safe(cmd+" "+f, runcmd=MPIRUN, nproc=nproc, mthread=1, pipe=True) + s, out = launch_safe(cmd+" "+f, nproc=nproc, mthread=1, pipe=True) with open("run.log."+str(nproc)+"."+str(r), "w") as f: f.write(out) diff --git a/tests/integrated/test-io/runtest b/tests/integrated/test-io/runtest index 091de2e570..eac4068c4d 100755 --- a/tests/integrated/test-io/runtest +++ b/tests/integrated/test-io/runtest @@ -11,12 +11,12 @@ try: except: pass -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import numpy as np from sys import stdout, exit -MPIRUN=getmpirun() + print("Making I/O test") shell_safe("make > make.log") @@ -46,7 +46,7 @@ for nproc in [1,2,4]: # Run test case print(" %d processor...." % (nproc)) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-io_hdf5/runtest b/tests/integrated/test-io_hdf5/runtest index f568caa1da..c6789d7248 100755 --- a/tests/integrated/test-io_hdf5/runtest +++ b/tests/integrated/test-io_hdf5/runtest @@ -7,12 +7,12 @@ #requires: all_tests #Requires: hdf5 -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import numpy as np from sys import stdout, exit -MPIRUN=getmpirun() + print("Making I/O test") shell_safe("make > make.log") @@ -42,7 +42,7 @@ for nproc in [1,2,4]: # Run test case print(" %d processor...." % (nproc)) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-laplace/runtest b/tests/integrated/test-laplace/runtest index d19cbe536d..35cb484a73 100755 --- a/tests/integrated/test-laplace/runtest +++ b/tests/integrated/test-laplace/runtest @@ -17,12 +17,12 @@ vars = ['flag0', 'flag3', 'flagis', 'flagos', 'flag0ad', 'flag3ad', 'flagisad', 'flagosad'] tol = 1e-10 # Absolute tolerance -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import numpy as np from sys import stdout, exit -MPIRUN = getmpirun() + print("Making Laplacian inversion test") shell("rm test_laplace") @@ -47,7 +47,7 @@ for nproc in [1,2,4]: shell("rm data/BOUT.dmp.*.nc") print(" %d processors (nxpe = %d)...." % (nproc, nxpe)) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, mthread=1, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, mthread=1, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-multigrid_laplace/runtest b/tests/integrated/test-multigrid_laplace/runtest index c9eb8c7522..3c0b0e19f6 100755 --- a/tests/integrated/test-multigrid_laplace/runtest +++ b/tests/integrated/test-multigrid_laplace/runtest @@ -13,11 +13,11 @@ except: tol = 2e-7 # Absolute tolerance numTests = 4 # We test 4 different boundary conditions (with slightly different inputs for each) -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from sys import exit -MPIRUN = getmpirun() + print("Making multigrid Laplacian inversion test") shell("rm test_multigrid_laplace") @@ -40,7 +40,7 @@ for nproc in [1,3]: shell("rm data/BOUT.dmp.*.nc") print(" %d processors..." %nproc) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, mthread=mthread, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, mthread=mthread, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-multigrid_laplace/runtest_multiple_grids b/tests/integrated/test-multigrid_laplace/runtest_multiple_grids index 1ab7786716..0fa04ac26a 100755 --- a/tests/integrated/test-multigrid_laplace/runtest_multiple_grids +++ b/tests/integrated/test-multigrid_laplace/runtest_multiple_grids @@ -13,11 +13,11 @@ except: tol = 2e-6 # Absolute tolerance numTests = 4 # We test 4 different boundary conditions (with slightly different inputs for each) -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from sys import exit -MPIRUN = getmpirun() + print("Making multigrid Laplacian inversion test") shell("rm test_multigrid_laplace") @@ -35,7 +35,7 @@ for nproc in [1,2,4]: shell("rm data/BOUT.dmp.*.nc") print(" %d processors, input file is %s" %(nproc,inputfile)) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-multigrid_laplace/runtest_unsheared b/tests/integrated/test-multigrid_laplace/runtest_unsheared index 69f07c2c78..cd99d6d9d9 100755 --- a/tests/integrated/test-multigrid_laplace/runtest_unsheared +++ b/tests/integrated/test-multigrid_laplace/runtest_unsheared @@ -13,11 +13,11 @@ except: tol = 1e-9 # Absolute tolerance numTests = 4 # We test 4 different boundary conditions (with slightly different inputs for each) -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from sys import exit -MPIRUN = getmpirun() + print("Making multigrid Laplacian inversion test") shell("rm test_multigrid_laplace") @@ -40,7 +40,7 @@ for nproc in [1,3]: shell("rm data/BOUT.dmp.*.nc") print(" %d processors..." %nproc) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, mthread=mthread, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, mthread=mthread, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-naulin-laplace/runtest b/tests/integrated/test-naulin-laplace/runtest index b318fb5ded..e9ac4bc300 100755 --- a/tests/integrated/test-naulin-laplace/runtest +++ b/tests/integrated/test-naulin-laplace/runtest @@ -13,11 +13,11 @@ except: tol = 2e-7 # Absolute tolerance numTests = 4 # We test 4 different boundary conditions (with slightly different inputs for each) -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from sys import exit -MPIRUN = getmpirun() + print("Making LaplaceNaulin inversion test") shell("rm test_naulin_laplace") @@ -40,7 +40,7 @@ for nproc in [1,3]: shell("rm data/BOUT.dmp.*.nc") print(" %d processors..." %nproc) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, mthread=mthread, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, mthread=mthread, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-naulin-laplace/runtest_multiple_grids b/tests/integrated/test-naulin-laplace/runtest_multiple_grids index 3fc3647649..e3327a43a7 100755 --- a/tests/integrated/test-naulin-laplace/runtest_multiple_grids +++ b/tests/integrated/test-naulin-laplace/runtest_multiple_grids @@ -13,11 +13,11 @@ except: tol = 2e-6 # Absolute tolerance numTests = 4 # We test 4 different boundary conditions (with slightly different inputs for each) -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from sys import exit -MPIRUN = getmpirun() + print("Making LaplaceNaulin inversion test") shell("rm test_naulin_laplace") @@ -35,7 +35,7 @@ for nproc in [1,2,4]: shell("rm data/BOUT.dmp.*.nc") print(" %d processors, input file is %s" %(nproc,inputfile)) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-naulin-laplace/runtest_unsheared b/tests/integrated/test-naulin-laplace/runtest_unsheared index 9abc4dafb7..0478f2e849 100755 --- a/tests/integrated/test-naulin-laplace/runtest_unsheared +++ b/tests/integrated/test-naulin-laplace/runtest_unsheared @@ -13,11 +13,11 @@ except: tol = 1e-9 # Absolute tolerance numTests = 4 # We test 4 different boundary conditions (with slightly different inputs for each) -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from sys import exit -MPIRUN = getmpirun() + print("Making LaplaceNaulin inversion test") shell("rm test_naulin_laplace") @@ -40,7 +40,7 @@ for nproc in [1,3]: shell("rm data/BOUT.dmp.*.nc") print(" %d processors..." %nproc) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, mthread=mthread, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, mthread=mthread, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-petsc_laplace/runtest b/tests/integrated/test-petsc_laplace/runtest index b017286a2b..57a369f735 100755 --- a/tests/integrated/test-petsc_laplace/runtest +++ b/tests/integrated/test-petsc_laplace/runtest @@ -20,12 +20,12 @@ vars = [('max_error1',2.e-4), ('max_error8',2.e-5)] #tol = 1e-4 # Absolute (?) tolerance -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect #import numpy as np from sys import stdout, exit -MPIRUN=getmpirun() + print("Making PETSc Laplacian inversion test") shell_safe("make > make.log") @@ -43,7 +43,7 @@ for nproc in [1,2,4]: shell("rm data/BOUT.dmp.*.nc") print(" %d processors...." % nproc) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True,verbose=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True,verbose=True) f = open("run.log."+str(nproc), "w") f.write(out) f.close() diff --git a/tests/integrated/test-petsc_laplace_MAST-grid/runtest b/tests/integrated/test-petsc_laplace_MAST-grid/runtest index 9a57064cd0..9b2fa2c73b 100755 --- a/tests/integrated/test-petsc_laplace_MAST-grid/runtest +++ b/tests/integrated/test-petsc_laplace_MAST-grid/runtest @@ -20,11 +20,11 @@ vars = [['max_error1',2.e-4], ['max_error8',1.e-4]] #tol = 1e-4 # Absolute (?) tolerance -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from sys import stdout, exit -MPIRUN=getmpirun() + print("Making PETSc Laplacian inversion test with non-identity metric (taken from grid for MAST SOL)") shell_safe("make > make.log") @@ -44,7 +44,7 @@ for nproc in [1,2,4]: shell("rm data/BOUT.dmp.*.nc") print(" %d processors...." % nproc) - s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) f = open("run.log."+str(nproc), "w") f.write(out) f.close() diff --git a/tests/integrated/test-region-iterator/runtest b/tests/integrated/test-region-iterator/runtest index bc9245e15f..34d651dbd8 100755 --- a/tests/integrated/test-region-iterator/runtest +++ b/tests/integrated/test-region-iterator/runtest @@ -9,11 +9,11 @@ try: from builtins import str except: pass -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from sys import exit -MPIRUN=getmpirun() + print("Making Region Iterator test") s, out = shell_safe("make > make.log",pipe=True) @@ -29,7 +29,7 @@ for nproc in [1,2]:#Number of mpi procs for f in flags: # Run the case - s, out = launch_safe(cmd+" "+f, runcmd=MPIRUN, nproc=nproc, pipe=pipe) + s, out = launch_safe(cmd+" "+f, nproc=nproc, pipe=pipe) if pipe: f = open("run.log."+str(nproc)+"."+str(mthread), "w") f.write(out) diff --git a/tests/integrated/test-restarting/runtest b/tests/integrated/test-restarting/runtest index 578562aa55..6181398094 100755 --- a/tests/integrated/test-restarting/runtest +++ b/tests/integrated/test-restarting/runtest @@ -1,17 +1,17 @@ #!/usr/bin/env python3 -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import numpy as np from sys import stdout, exit -MPIRUN=getmpirun() + print("-> Making restart test") shell_safe("make > make.log") # Run once for 10 timesteps -s, out = launch_safe("./test_restarting nout=10", runcmd=MPIRUN, nproc=1, pipe=True) +s, out = launch_safe("./test_restarting nout=10", nproc=1, pipe=True) # Read reference data f3d_0 = collect("f3d", path="data", info=False); @@ -23,8 +23,8 @@ f2d_0 = collect("f2d", path="data", info=False); print("-> Testing restart append") shell("rm data/BOUT.dmp.0.nc") -s, out = launch_safe("./test_restarting nout=5", runcmd=MPIRUN, nproc=1, pipe=True) -s, out = launch_safe("./test_restarting nout=5 restart append", runcmd=MPIRUN, nproc=1, pipe=True) +s, out = launch_safe("./test_restarting nout=5", nproc=1, pipe=True) +s, out = launch_safe("./test_restarting nout=5 restart append", nproc=1, pipe=True) f3d_1 = collect("f3d", path="data", info=False); f2d_1 = collect("f2d", path="data", info=False); @@ -50,8 +50,8 @@ if np.max(np.abs(f2d_1 - f2d_0)) > 1e-10: print("-> Testing restart") shell("rm data/BOUT.dmp.0.nc") -s, out = launch_safe("./test_restarting nout=5", runcmd=MPIRUN, nproc=1, pipe=True) -s, out = launch_safe("./test_restarting nout=5 restart", runcmd=MPIRUN, nproc=1, pipe=True) +s, out = launch_safe("./test_restarting nout=5", nproc=1, pipe=True) +s, out = launch_safe("./test_restarting nout=5 restart", nproc=1, pipe=True) f3d_1 = collect("f3d", path="data", info=False); f2d_1 = collect("f2d", path="data", info=False); diff --git a/tests/integrated/test-simple-diffusion/runcase.sh b/tests/integrated/test-simple-diffusion/runcase.sh index a7e6cdf827..b03602cfa2 100755 --- a/tests/integrated/test-simple-diffusion/runcase.sh +++ b/tests/integrated/test-simple-diffusion/runcase.sh @@ -3,11 +3,9 @@ NO_ARGS=0 OPTERROR=65 -if [ $# -eq "$NO_ARGS" ] # Script invoked with no command-line args? -then - MPIEXEC="mpirun -np " - NP=4 -fi +NP=4 +test ".$MPIRUN" = . && MPIRUN="mpirun -np" + # Usage: scriptname -options # Note: dash (-) necessary @@ -15,7 +13,7 @@ fi while getopts ":n:np" Option do case $Option in - n ) MPIEXEC="mpiexec -np";NP=$OPTARG;; + n ) NP=$OPTARG;; * ) ;; # DEFAULT esac done @@ -25,6 +23,6 @@ make #-run the case echo Running with NP = $NP -$MPIEXEC $NP ./simple_diff +$MPIRUN $NP ./simple_diff diff --git a/tests/integrated/test-smooth/runtest b/tests/integrated/test-smooth/runtest index 32ae76bf9c..0d578c0de3 100755 --- a/tests/integrated/test-smooth/runtest +++ b/tests/integrated/test-smooth/runtest @@ -13,12 +13,12 @@ except: vars = ['yavg2d', 'yavg3d', 'sm3d'] tol = 1e-10 # Absolute tolerance -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect import numpy as np from sys import stdout, exit -MPIRUN=getmpirun() + print("Making smoothing operator test") shell_safe("make > make.log") @@ -40,7 +40,7 @@ for nype in [1,2]: shell("rm data/BOUT.dmp.*.nc") print(" %d processor (%d x %d)...." % (nproc, nxpe, nype)) - s, out = launch_safe(cmd+" nxpe="+str(nxpe), runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch_safe(cmd+" nxpe="+str(nxpe), nproc=nproc, pipe=True) with open("run.log."+str(nproc), "w") as f: f.write(out) diff --git a/tests/integrated/test-solver/runtest b/tests/integrated/test-solver/runtest index 37d731c7e1..d065bf92c7 100755 --- a/tests/integrated/test-solver/runtest +++ b/tests/integrated/test-solver/runtest @@ -1,18 +1,18 @@ #!/usr/bin/env python3 -from boututils.run_wrapper import shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell_safe, launch_safe from sys import exit nthreads = 1 nproc = 1 -MPIRUN = getmpirun() + print("Making solver test") shell_safe("make > make.log") print("Running solver test") -status, out = launch_safe("./test_solver", runcmd=MPIRUN, nproc=nproc, mthread=nthreads, pipe=True) +status, out = launch_safe("./test_solver", nproc=nproc, mthread=nthreads, pipe=True) with open("run.log", "w") as f: f.write(out) diff --git a/tests/integrated/test-stopCheck-file/runtest b/tests/integrated/test-stopCheck-file/runtest index 7530d4845f..7e8aa140b9 100755 --- a/tests/integrated/test-stopCheck-file/runtest +++ b/tests/integrated/test-stopCheck-file/runtest @@ -12,14 +12,14 @@ try: except: pass -from boututils.run_wrapper import shell, launch, getmpirun +from boututils.run_wrapper import shell, launch from boutdata.collect import collect import numpy as np from sys import stdout, exit nproc = 1 -MPIRUN=getmpirun() + print("Making stopCheck test") shell("make > make.log") @@ -38,7 +38,7 @@ for j, dat in enumerate(dats): for i, check in enumerate(checkVal): cmd = "./test_stopCheck" - s, out = launch(cmd+" -d "+dat+" stopCheck="+str(check)+" stopCheckName="+datStopFiles[j], runcmd=MPIRUN, nproc=nproc, pipe=True) + s, out = launch(cmd+" -d "+dat+" stopCheck="+str(check)+" stopCheckName="+datStopFiles[j], nproc=nproc, pipe=True) f = open("run.log."+dat+"."+str(check).lower(), "w") f.write(out) f.close() diff --git a/tests/integrated/test-subdir/runtest b/tests/integrated/test-subdir/runtest index 614241d285..f98268f279 100755 --- a/tests/integrated/test-subdir/runtest +++ b/tests/integrated/test-subdir/runtest @@ -2,4 +2,6 @@ make || exit -mpirun -n 1 ./subdirs +test ".$MPIRUN" = . && MPIRUN="mpirun -np" + +$MPIRUN 1 ./subdirs diff --git a/tests/integrated/test-vec/runtest b/tests/integrated/test-vec/runtest index 02e2636c6f..7ef43c75b8 100755 --- a/tests/integrated/test-vec/runtest +++ b/tests/integrated/test-vec/runtest @@ -2,7 +2,9 @@ make -mpirun -np 4 ./testVec > log.4 +test ".$MPIRUN" = . && MPIRUN="mpirun -np" + +$MPIRUN 4 ./testVec > log.4 exit=$? diff --git a/tests/integrated/test-yupdown/runtest b/tests/integrated/test-yupdown/runtest index dc6859090e..6599c259d3 100755 --- a/tests/integrated/test-yupdown/runtest +++ b/tests/integrated/test-yupdown/runtest @@ -1,17 +1,17 @@ #!/usr/bin/env python3 -from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect from sys import exit from numpy import max, abs -MPIRUN=getmpirun() + shell_safe("make > make.log") -s, out = launch_safe("./test_yupdown", runcmd=MPIRUN, nproc=1, pipe=True, verbose=True) +s, out = launch_safe("./test_yupdown", nproc=1, pipe=True, verbose=True) with open("run.log", "w") as f: f.write(out) From e4e6a9fa127bbca1039a9f07ae7e6bec77a979f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Sat, 16 Feb 2019 17:46:12 +0000 Subject: [PATCH 0776/1783] Threat empty global variable as if it wouldn't exist otherwise `export MPIRUN=` would not lead to the expected result --- tools/pylib/boututils/run_wrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pylib/boututils/run_wrapper.py b/tools/pylib/boututils/run_wrapper.py index a639196dbb..5e05052758 100644 --- a/tools/pylib/boututils/run_wrapper.py +++ b/tools/pylib/boututils/run_wrapper.py @@ -28,7 +28,7 @@ def getmpirun(default="mpirun -np"): """ MPIRUN = os.getenv("MPIRUN") - if MPIRUN is None: + if MPIRUN is None or MPIRUN == "": MPIRUN = default print("getmpirun: using the default " + str(default)) From ab3769307df6030e47ad5deb326632abe2f38e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Sun, 17 Feb 2019 20:15:39 +0000 Subject: [PATCH 0777/1783] Check buffer length Not doing so can trigger an assert error in the stl library. --- src/sys/optionsreader.cxx | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/sys/optionsreader.cxx b/src/sys/optionsreader.cxx index 34b4747cf6..fa94fa250a 100644 --- a/src/sys/optionsreader.cxx +++ b/src/sys/optionsreader.cxx @@ -74,46 +74,50 @@ void OptionsReader::write(Options *options, const char *file, ...) { delete parser; } -void OptionsReader::parseCommandLine(Options *options, int argc, char **argv) { +void OptionsReader::parseCommandLine(Options* options, int argc, char** argv) { // A key/value pair, separated by a '=' or a switch // and sections separated with an '_' but don't start with a '-' std::string buffer; // Go through command-line arguments - for (int i=1;igetRoot(); buffer = argv[i]; + if (buffer.length() == 0) { + continue; + } // Test if name starts with a '-', and remove if found - if (buffer[0] == '-') - buffer = buffer.substr(1); // Remove the first character (-) - + if (buffer[0] == '-') { + buffer = buffer.substr(1); // Remove the first character (-) + if (buffer.length() == 0) { + throw BoutException(_("single `-` found - do not know what to do")); + } + } // Test to see if the user put spaces around the '=' sign - if (i < argc-1) { - if(buffer[buffer.length()-1] == '=') { + if (i < argc - 1) { + if (buffer[buffer.length() - 1] == '=') { // Space after '=' sign - + i++; buffer.append(argv[i]); - - }else if(argv[i+1][0] == '=') { + } else if (argv[i + 1][0] == '=') { // Space before '=' sign - + i++; buffer.append(argv[i]); - - if((argv[i][1] == 0) && (i < argc-1)) { + + if ((argv[i][1] == 0) && (i < argc - 1)) { // End of string, so space after '=' sign too - i++; buffer.append(argv[i]); } } } - + size_t startpos = buffer.find_first_of('='); if (startpos == std::string::npos) { From 32c2262ab167151450c747f5093e67e206b9ef4a Mon Sep 17 00:00:00 2001 From: dschwoerer Date: Mon, 18 Feb 2019 11:31:27 +0000 Subject: [PATCH 0778/1783] Better error message --- src/sys/optionsreader.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/optionsreader.cxx b/src/sys/optionsreader.cxx index fa94fa250a..05bf0a83ef 100644 --- a/src/sys/optionsreader.cxx +++ b/src/sys/optionsreader.cxx @@ -94,7 +94,7 @@ void OptionsReader::parseCommandLine(Options* options, int argc, char** argv) { if (buffer[0] == '-') { buffer = buffer.substr(1); // Remove the first character (-) if (buffer.length() == 0) { - throw BoutException(_("single `-` found - do not know what to do")); + throw BoutException(_("Invalid command line option '-' found - maybe check whitespace?")); } } // Test to see if the user put spaces around the '=' sign From 41e2eff8ff9506e4fd02c6c6afdf3b46727d136b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 19 Feb 2019 11:46:18 +0000 Subject: [PATCH 0779/1783] Pass location straight through to setLocation --- src/field/field_factory.cxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 83f99cd141..883c092237 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -119,9 +119,6 @@ const Field2D FieldFactory::create2D(FieldGeneratorPtr gen, Mesh* localmesh, CEL Field2D result(0., localmesh); - if (localmesh->StaggerGrids == false) { - loc = CELL_CENTRE; - } result.setLocation(loc); switch(loc) { From 2662d2da6818bcb5eb3aaf98f95a471e110600e9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 19 Feb 2019 11:50:12 +0000 Subject: [PATCH 0780/1783] Only allocate create2D result rather than initialising to zero --- src/field/field_factory.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 883c092237..a71e7f7ef6 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -117,8 +117,9 @@ const Field2D FieldFactory::create2D(FieldGeneratorPtr gen, Mesh* localmesh, CEL throw BoutException("Couldn't create 2D field from null generator"); } - Field2D result(0., localmesh); + Field2D result{localmesh}; + result.allocate(); result.setLocation(loc); switch(loc) { From fc5aa226729a4d513a7d7709ab94031dbcacdc57 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 19 Feb 2019 15:17:52 +0000 Subject: [PATCH 0781/1783] Throw ParseException rather than BoutException in FieldRound::clone --- src/field/fieldgenerators.hxx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/field/fieldgenerators.hxx b/src/field/fieldgenerators.hxx index 1da1cbfc3d..a6fddafacd 100644 --- a/src/field/fieldgenerators.hxx +++ b/src/field/fieldgenerators.hxx @@ -262,9 +262,10 @@ class FieldRound : public FieldGenerator { public: FieldRound(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const std::list args) { - if(args.size() != 1) - throw BoutException("round function must have one input"); + FieldGeneratorPtr clone(const std::list args) { + if (args.size() != 1) { + throw ParseException("round function must have one input"); + } return std::make_shared(args.front()); } BoutReal generate(double x, double y, double z, double t) { @@ -274,6 +275,7 @@ public: } return static_cast(val - 0.5); } + private: FieldGeneratorPtr gen; }; From 8a0eb69aaf3d9f49daa3ed897f2f706e938502c9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 19 Feb 2019 15:57:06 +0000 Subject: [PATCH 0782/1783] Make FakeMesh::GlobalX/Y return something useful for tests --- tests/unit/test_extras.hxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 734edd6e10..7dc5990a16 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -225,10 +225,10 @@ public: void addBoundary(BoundaryRegion* region) {boundaries.push_back(region);} std::vector getBoundaries() { return boundaries; } std::vector getBoundariesPar() { return std::vector(); } - BoutReal GlobalX(int UNUSED(jx)) const { return 0; } - BoutReal GlobalY(int UNUSED(jy)) const { return 0; } - BoutReal GlobalX(BoutReal UNUSED(jx)) const { return 0; } - BoutReal GlobalY(BoutReal UNUSED(jy)) const { return 0; } + BoutReal GlobalX(int jx) const { return jx; } + BoutReal GlobalY(int jy) const { return jy; } + BoutReal GlobalX(BoutReal jx) const { return jx; } + BoutReal GlobalY(BoutReal jy) const { return jy; } int XGLOBAL(int UNUSED(xloc)) const { return 0; } int YGLOBAL(int UNUSED(yloc)) const { return 0; } From a6b423c61e62aff85ab58193edf6da2ed3154296 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 19 Feb 2019 15:57:47 +0000 Subject: [PATCH 0783/1783] Add tests for FieldFactory and FieldGenerators --- tests/unit/field/test_field_factory.cxx | 695 ++++++++++++++++++++++++ 1 file changed, 695 insertions(+) create mode 100644 tests/unit/field/test_field_factory.cxx diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx new file mode 100644 index 0000000000..8fa5ac644d --- /dev/null +++ b/tests/unit/field/test_field_factory.cxx @@ -0,0 +1,695 @@ +#include "gtest/gtest.h" + +#include "boutexception.hxx" +#include "field2d.hxx" +#include "field3d.hxx" +#include "field_factory.hxx" +#include "output.hxx" +#include "test_extras.hxx" +#include "bout/constants.hxx" +#include "bout/mesh.hxx" + +/// Global mesh +namespace bout { +namespace globals { +extern Mesh* mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; + +// Reuse the "standard" fixture for FakeMesh +template +class FieldFactoryCreationTest : public FakeMeshFixture { +public: + FieldFactoryCreationTest() : FakeMeshFixture{}, factory{mesh} { + // We need a parallel transform as FieldFactory::create3D wants to + // un-field-align the result + mesh->setParallelTransform( + bout::utils::make_unique(*mesh)); + } + + FieldFactory factory; + + // We can't just decide which FieldFactory::create?D function to + // call with + // + // if (std::is_base_of::value) { + // return factory.create3D(...); + // } else { + // return factory.create2D(...); + // } + // + // as this is *runtime* so the compiler still needs to evaluate both + // branches -- until C++17 when we can use `if constexpr ...` + template + T createDispatch(std::true_type, Args&&... args) { + return factory.create3D(std::forward(args)...); + } + + template + T createDispatch(std::false_type, Args&&... args) { + return factory.create2D(std::forward(args)...); + } + + // Generic way of calling either FieldFactory::create2D or + // FieldFactory::create3D + template + T create(Args&&... args) { + return createDispatch(std::is_base_of{}, std::forward(args)...); + } +}; + +using Fields = ::testing::Types; + +TYPED_TEST_CASE(FieldFactoryCreationTest, Fields); + +TYPED_TEST(FieldFactoryCreationTest, CreateFromValueGenerator) { + auto value = BoutReal{4.}; + auto output = this->create(generator(value)); + + EXPECT_TRUE(IsFieldEqual(output, value)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateFromPointerGenerator) { + auto value = BoutReal{5.}; + auto output = this->create(generator(&value)); + + EXPECT_TRUE(IsFieldEqual(output, value)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreatePi) { + auto output = this->create("pi"); + + EXPECT_TRUE(IsFieldEqual(output, PI)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreatePiSymbol) { + auto output = this->create("π"); + + EXPECT_TRUE(IsFieldEqual(output, PI)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateAddition) { + auto output = this->create("1 + 1"); + + EXPECT_TRUE(IsFieldEqual(output, 2.)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateSubtraction) { + auto output = this->create("11 - 1"); + + EXPECT_TRUE(IsFieldEqual(output, 10.)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateMultiplication) { + auto output = this->create("3 * 1"); + + EXPECT_TRUE(IsFieldEqual(output, 3.)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateDivision) { + auto output = this->create("12 / 2"); + + EXPECT_TRUE(IsFieldEqual(output, 6.)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateNested) { + auto output = this->create("1 + (12 / (2 * 3))"); + + EXPECT_TRUE(IsFieldEqual(output, 3.)); +} + +TYPED_TEST(FieldFactoryCreationTest, ParseThenCreateNested) { + auto generator = this->factory.parse("1 + (12 / (2 * 3))"); + auto output = this->create(generator); + + EXPECT_TRUE(IsFieldEqual(output, 3.)); +} + +TYPED_TEST(FieldFactoryCreationTest, ParseNull) { + EXPECT_THROW(this->create(FieldGeneratorPtr{nullptr}), BoutException); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateX) { + auto output = this->create("x"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { return index.x(); }, mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateY) { + auto output = this->create("y"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { return TWOPI * index.y(); }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateZ) { + auto output = this->create("z"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + return TWOPI * index.z() / FieldFactoryCreationTest::nz; + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateXStaggered) { + bout::globals::mesh->StaggerGrids = true; + auto output = this->create("x", nullptr, bout::globals::mesh, CELL_XLOW); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { return index.x() - 0.5; }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); + EXPECT_EQ(output.getLocation(), CELL_XLOW); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateYStaggered) { + bout::globals::mesh->StaggerGrids = true; + auto output = this->create("y", nullptr, bout::globals::mesh, CELL_YLOW); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + return TWOPI * (index.y() - 0.5); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); + EXPECT_EQ(output.getLocation(), CELL_YLOW); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateZStaggered) { + bout::globals::mesh->StaggerGrids = true; + auto output = this->create("z", nullptr, bout::globals::mesh, CELL_ZLOW); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + + auto offset = BoutReal{0.0}; + if (std::is_base_of::value) { + offset = 0.5; + } + + return TWOPI * (index.z() - offset) / FieldFactoryCreationTest::nz; + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); + EXPECT_EQ(output.getLocation(), CELL_ZLOW); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateT) { + auto time = BoutReal{77.0}; + auto output = this->create("t", nullptr, nullptr, CELL_CENTRE, time); + + EXPECT_TRUE(IsFieldEqual(output, time)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateSinX) { + auto output = this->create("sin(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { return std::sin(index.x()); }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateCosX) { + auto output = this->create("cos(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { return std::cos(index.x()); }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateTanX) { + auto output = this->create("tan(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { return std::tan(index.x()); }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateAsinX) { + auto output = this->create("asin(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + return std::asin(index.x()); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateAcosX) { + auto output = this->create("acos(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + return std::acos(index.x()); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateAtanX) { + auto output = this->create("atan(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + return std::atan(index.x()); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateSinhX) { + auto output = this->create("sinh(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + return std::sinh(index.x()); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateCoshX) { + auto output = this->create("cosh(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + return std::cosh(index.x()); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateTanhX) { + auto output = this->create("tanh(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + return std::tanh(index.x()); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateExpX) { + auto output = this->create("exp(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { return std::exp(index.x()); }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateLogX) { + auto output = this->create("log(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { return std::log(index.x()); }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateGaussX) { + auto output = this->create("gauss(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + return std::exp(-std::pow(index.x(), 2) / 2.) / std::sqrt(TWOPI); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateGaussWithWidthX) { + auto output = this->create("gauss(x, 4.)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + constexpr auto width = BoutReal{4.}; + return std::exp(-std::pow(index.x() / width, 2) / 2.) + / (std::sqrt(TWOPI) * width); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateAbsX) { + auto output = this->create("abs(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { return std::abs(index.x()); }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateSqrtX) { + auto output = this->create("sqrt(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + return std::sqrt(index.x()); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateHeavisideXPi) { + auto output = this->create("h(x - pi)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + if (index.x() > PI) { + return 1.0; + } else { + return 0.0; + } + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateErfX) { + auto output = this->create("erf(x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { return std::erf(index.x()); }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateFmodX) { + auto output = this->create("fmod(pi, x)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + return std::fmod(PI, index.x()); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateMinX) { + auto output = this->create("min(2, 3, 1, 4)"); + + EXPECT_TRUE(IsFieldEqual(output, 1.)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateMaxX) { + auto output = this->create("max(2, 3, 1, 4)"); + + EXPECT_TRUE(IsFieldEqual(output, 4.)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreatePowX) { + auto output = this->create("power(x, 2)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + return std::pow(index.x(), 2); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateTanhHatX) { + auto output = this->create("tanhhat(x, 1, 2, 3)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + constexpr auto width = BoutReal{1.}; + constexpr auto centre = BoutReal{2.}; + constexpr auto steepness = BoutReal{3.}; + + return 0.5 + * (std::tanh(steepness * (index.x() - (centre - 0.5 * width))) + - std::tanh(steepness * (index.x() - (centre + 0.5 * width)))); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateRoundX) { + auto output = this->create("round(pi)"); + + EXPECT_TRUE(IsFieldEqual(output, 3.)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateWithLookup) { + auto a_value = int{6}; + + output_info.disable(); + auto options = Options{}; + options["a"] = a_value; + auto output = this->create("x + a", &options); + output_info.enable(); + + auto expected = makeField( + [&a_value](typename TypeParam::ind_type& index) -> BoutReal { + return index.x() + a_value; + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, ParseFromCache) { + auto a_value = int{6}; + + output_info.disable(); + auto options = Options{}; + options["a"] = a_value; + this->factory.parse("x + a", &options); + output_info.enable(); + + auto output = this->create("x + a"); + + auto expected = makeField( + [&a_value](typename TypeParam::ind_type& index) -> BoutReal { + return index.x() + a_value; + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateOnMesh) { + constexpr auto nx = int{1}; + constexpr auto ny = int{1}; + constexpr auto nz = int{1}; + + FakeMesh localmesh{nx, ny, nz}; + localmesh.createDefaultRegions(); + localmesh.setParallelTransform( + bout::utils::make_unique(localmesh)); + + auto output = this->create("x", nullptr, &localmesh); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { return index.x(); }, + &localmesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); + EXPECT_EQ(output.getNx(), nx); + EXPECT_EQ(output.getNy(), ny); + EXPECT_EQ(output.getNz(), nz); +} + +// The following tests still use the FieldFactory, but don't need to +// be typed and make take longer as they check that exceptions get +// thrown. Doing these twice will slow down the test unnecessarily + +class FieldFactoryTest : public FakeMeshFixture { +public: + FieldFactoryTest() : FakeMeshFixture{}, factory{mesh} {} + + FieldFactory factory; +}; + +TEST_F(FieldFactoryTest, CleanCache) { + + auto a_value = int{6}; + + output_info.disable(); + auto options = Options{}; + options["a"] = a_value; + factory.parse("x + a", &options); + output_info.enable(); + + factory.cleanCache(); + + EXPECT_THROW(factory.parse("x + a"), ParseException); +} + +TEST_F(FieldFactoryTest, ParseSelfReference) { + // This one doesn't need to be typed, but easier than creating a + // whole new test suite for this one test + + output.disable(); + output_info.disable(); + + auto options = Options{}; + options["a"] = "a"; + + EXPECT_THROW(factory.parse("a", &options), BoutException); + + output_info.enable(); + output.enable(); +} + +TEST_F(FieldFactoryTest, SinArgs) { + EXPECT_THROW(factory.parse("sin()"), ParseException); + EXPECT_THROW(factory.parse("sin(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, CosArgs) { + EXPECT_THROW(factory.parse("cos()"), ParseException); + EXPECT_THROW(factory.parse("cos(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, TanArgs) { + EXPECT_THROW(factory.parse("tan()"), ParseException); + EXPECT_THROW(factory.parse("tan(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, SinhArgs) { + EXPECT_THROW(factory.parse("sinh()"), ParseException); + EXPECT_THROW(factory.parse("sinh(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, CoshArgs) { + EXPECT_THROW(factory.parse("cosh()"), ParseException); + EXPECT_THROW(factory.parse("cosh(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, TanhArgs) { + EXPECT_THROW(factory.parse("tanh()"), ParseException); + EXPECT_THROW(factory.parse("tanh(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, ASinArgs) { + EXPECT_THROW(factory.parse("asin()"), ParseException); + EXPECT_THROW(factory.parse("asin(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, ACosArgs) { + EXPECT_THROW(factory.parse("acos()"), ParseException); + EXPECT_THROW(factory.parse("acos(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, ATanArgs) { + EXPECT_THROW(factory.parse("atan()"), ParseException); + EXPECT_THROW(factory.parse("atan(x, x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, ExpArgs) { + EXPECT_THROW(factory.parse("exp()"), ParseException); + EXPECT_THROW(factory.parse("exp(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, LogArgs) { + EXPECT_THROW(factory.parse("log()"), ParseException); + EXPECT_THROW(factory.parse("log(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, GaussArgs) { + EXPECT_THROW(factory.parse("gauss()"), ParseException); + EXPECT_THROW(factory.parse("gauss(x, x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, AbsArgs) { + EXPECT_THROW(factory.parse("abs()"), ParseException); + EXPECT_THROW(factory.parse("abs(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, SqrtArgs) { + EXPECT_THROW(factory.parse("sqrt()"), ParseException); + EXPECT_THROW(factory.parse("sqrt(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, HeavisideArgs) { + EXPECT_THROW(factory.parse("h()"), ParseException); + EXPECT_THROW(factory.parse("h(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, ErfArgs) { + EXPECT_THROW(factory.parse("erf()"), ParseException); + EXPECT_THROW(factory.parse("erf(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, FmodArgs) { + EXPECT_THROW(factory.parse("fmod()"), ParseException); + EXPECT_THROW(factory.parse("fmod(x)"), ParseException); + EXPECT_THROW(factory.parse("fmod(x, x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, MinArgs) { + EXPECT_THROW(factory.parse("min()"), ParseException); +} + +TEST_F(FieldFactoryTest, MaxArgs) { + EXPECT_THROW(factory.parse("max()"), ParseException); +} + +TEST_F(FieldFactoryTest, PowerArgs) { + EXPECT_THROW(factory.parse("power()"), ParseException); + EXPECT_THROW(factory.parse("power(x)"), ParseException); + EXPECT_THROW(factory.parse("power(x, x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, RoundArgs) { + EXPECT_THROW(factory.parse("round()"), ParseException); + EXPECT_THROW(factory.parse("round(x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, BallooningArgs) { + EXPECT_THROW(factory.parse("ballooning()"), ParseException); + EXPECT_THROW(factory.parse("ballooning(x, x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, MixmodeArgs) { + EXPECT_THROW(factory.parse("mixmode()"), ParseException); + EXPECT_THROW(factory.parse("mixmode(x, x, x)"), ParseException); +} + +TEST_F(FieldFactoryTest, TanhhatArgs) { + EXPECT_THROW(factory.parse("tanhhat()"), ParseException); + EXPECT_THROW(factory.parse("tanhhat(x, x, x, x, x)"), ParseException); +} From 9aeb162dcf715ea6acaf8bc81cbce55961d677fd Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Feb 2019 10:37:58 +0000 Subject: [PATCH 0784/1783] Add tests for Timer --- tests/unit/sys/test_timer.cxx | 147 ++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 tests/unit/sys/test_timer.cxx diff --git a/tests/unit/sys/test_timer.cxx b/tests/unit/sys/test_timer.cxx new file mode 100644 index 0000000000..7f0a31d9e9 --- /dev/null +++ b/tests/unit/sys/test_timer.cxx @@ -0,0 +1,147 @@ +#include "gtest/gtest.h" + +#include "bout/sys/timer.hxx" + +#include +#include + +namespace bout { +namespace testing { +using ms = std::chrono::duration; +using seconds = std::chrono::duration; +constexpr double TimerTolerance{1e-3}; +constexpr auto sleep_length = ms(0.5); +constexpr auto sleep_length_seconds = seconds(sleep_length); +} // namespace testing +} // namespace bout + +TEST(TimerTest, GetTime) { + using namespace bout::testing; + + Timer timer{}; + + std::this_thread::sleep_for(sleep_length); + + EXPECT_NEAR(timer.getTime(), sleep_length_seconds.count(), TimerTolerance); +} + +TEST(TimerTest, GetUnknownTimeLabel) { + EXPECT_DOUBLE_EQ(Timer::getTime("Does not exist"), 0.0); +} + +TEST(TimerTest, GetTimeLabelInScope) { + using namespace bout::testing; + + Timer timer{"GetTimeLabelInScope test"}; + + std::this_thread::sleep_for(sleep_length); + + EXPECT_NEAR(Timer::getTime("GetTimeLabelInScope test"), sleep_length_seconds.count(), + TimerTolerance); +} + +TEST(TimerTest, GetTimeLabelOutOfScope) { + using namespace bout::testing; + + { + Timer timer{"GetTimeLabelOutOfScope test"}; + + std::this_thread::sleep_for(sleep_length); + } + + EXPECT_NEAR(Timer::getTime("GetTimeLabelOutOfScope test"), sleep_length_seconds.count(), + TimerTolerance); +} + +TEST(TimerTest, GetTimeLabelRepeat) { + using namespace bout::testing; + + { + Timer timer{"GetTimeLabelRepeat test"}; + + std::this_thread::sleep_for(sleep_length); + } + + EXPECT_NEAR(Timer::getTime("GetTimeLabelRepeat test"), sleep_length_seconds.count(), + TimerTolerance); + + { + Timer timer{"GetTimeLabelRepeat test"}; + + std::this_thread::sleep_for(sleep_length); + } + + EXPECT_NEAR(Timer::getTime("GetTimeLabelRepeat test"), 2 * sleep_length_seconds.count(), + TimerTolerance); +} + +TEST(TimerTest, ResetTime) { + using namespace bout::testing; + + Timer timer{"ResetTime test"}; + + std::this_thread::sleep_for(sleep_length); + + timer.resetTime(); + + std::this_thread::sleep_for(sleep_length); + + EXPECT_NEAR(timer.getTime(), sleep_length_seconds.count(), TimerTolerance); +} + +TEST(TimerTest, ResetTimeLabelInScope) { + using namespace bout::testing; + + Timer timer{"ResetTimeLabelInScope test"}; + + std::this_thread::sleep_for(sleep_length); + + Timer::resetTime("ResetTimeLabelInScope test"); + + std::this_thread::sleep_for(sleep_length); + + EXPECT_NEAR(Timer::getTime("ResetTimeLabelInScope test"), sleep_length_seconds.count(), + TimerTolerance); +} + +TEST(TimerTest, ResetTimeLabelOutOfScope) { + using namespace bout::testing; + + { + Timer timer{"ResetTimeLabelOutOfScope test"}; + + std::this_thread::sleep_for(sleep_length); + } + + Timer::resetTime("ResetTimeLabelOutOfScope test"); + + { + Timer timer{"ResetTimeLabelOutOfScope test"}; + + std::this_thread::sleep_for(sleep_length); + } + + EXPECT_NEAR(Timer::getTime("ResetTimeLabelOutOfScope test"), + sleep_length_seconds.count(), TimerTolerance); +} + +TEST(TimerTest, Cleanup) { + using namespace bout::testing; + + { + Timer timer{"Cleanup test"}; + + std::this_thread::sleep_for(sleep_length); + } + + Timer::cleanup(); + + { + Timer timer{"Cleanup test"}; + + std::this_thread::sleep_for(sleep_length); + } + + EXPECT_NEAR(Timer::getTime("Cleanup test"), sleep_length_seconds.count(), + TimerTolerance); +} From 8ec6bef52b0a65f817b3c93d622b14093b52fab9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Feb 2019 10:51:18 +0000 Subject: [PATCH 0785/1783] Small refactor of Timer to store values rather than pointers in map --- include/bout/sys/timer.hxx | 6 +-- src/sys/timer.cxx | 85 +++++++++++++++++--------------------- 2 files changed, 41 insertions(+), 50 deletions(-) diff --git a/include/bout/sys/timer.hxx b/include/bout/sys/timer.hxx index b850580784..13ab627514 100644 --- a/include/bout/sys/timer.hxx +++ b/include/bout/sys/timer.hxx @@ -83,11 +83,11 @@ private: double started; ///< Start time }; - static std::map info; + static std::map info; - static timer_info *getInfo(const std::string &label); + static timer_info& getInfo(const std::string &label); - timer_info* timing; + timer_info& timing; }; #endif // __TIMER_H__ diff --git a/src/sys/timer.cxx b/src/sys/timer.cxx index 80ba127834..e2a140a38d 100644 --- a/src/sys/timer.cxx +++ b/src/sys/timer.cxx @@ -1,82 +1,73 @@ -#include #include +#include using namespace std; -Timer::Timer() { - timing = getInfo(""); - timing->started = MPI_Wtime(); - timing->running = true; +Timer::Timer() : timing{getInfo("")} { + timing.started = MPI_Wtime(); + timing.running = true; } -Timer::Timer(const std::string &label) { - timing = getInfo(label); - timing->started = MPI_Wtime(); - timing->running = true; +Timer::Timer(const std::string& label) : timing{getInfo(label)} { + timing.started = MPI_Wtime(); + timing.running = true; } Timer::~Timer() { double finished = MPI_Wtime(); - timing->running = false; - timing->time += finished - timing->started; + timing.running = false; + timing.time += finished - timing.started; } double Timer::getTime() { - if(timing->running) - return timing->time + (MPI_Wtime() - timing->started); - return timing->time; + if (timing.running) + return timing.time + (MPI_Wtime() - timing.started); + return timing.time; } double Timer::resetTime() { - double val = timing->time; - timing->time = 0.0; - if(timing->running) { + double val = timing.time; + timing.time = 0.0; + if (timing.running) { double cur_time = MPI_Wtime(); - val += cur_time - timing->started; - timing->started = cur_time; + val += cur_time - timing.started; + timing.started = cur_time; } return val; } -double Timer::getTime(const std::string &label) { - timer_info* t = getInfo(label); - if(t->running) - return t->time + (MPI_Wtime() - t->started); - return t->time; +double Timer::getTime(const std::string& label) { + timer_info& t = getInfo(label); + if (t.running) + return t.time + (MPI_Wtime() - t.started); + return t.time; } -double Timer::resetTime(const std::string &label) { - timer_info* t = getInfo(label); - double val = t->time; - t->time = 0.0; - if(t->running) { +double Timer::resetTime(const std::string& label) { + timer_info& t = getInfo(label); + double val = t.time; + t.time = 0.0; + if (t.running) { double cur_time = MPI_Wtime(); - val += cur_time - t->started; - t->started = cur_time; + val += cur_time - t.started; + t.started = cur_time; } return val; } // Static method to clean up all memory -void Timer::cleanup() { - // Iterate over map - for(const auto& it : info) { - delete it.second; - } - info.clear(); -} +void Timer::cleanup() { info.clear(); } -map Timer::info; +map Timer::info; -Timer::timer_info* Timer::getInfo(const std::string &label) { - auto it = info.find(label); - if(it == info.end()) { +Timer::timer_info& Timer::getInfo(const std::string& label) { + auto it = info.find(label); + if (it == info.end()) { // Not in map, so create it - timer_info *t = new timer_info; - t->time = 0.0; - t->running = false; - info[label] = t; - return t; + auto timer = info.emplace(label, timer_info{0.0, false, 0.0}); + // timer is a pair of an iterator and bool + // The iterator is a pair of key, value + return timer.first->second; } return it->second; } From cad063eb8d31f9487bcb9dd838182534cb91a231 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Feb 2019 10:52:14 +0000 Subject: [PATCH 0786/1783] Remove unreachable code in Timer In order to call `Timer::getTime`, we must have an actual value of a `Timer`. There's no functionality to stop a `Timer` without destroying it, so it must be running when we call `getTime` --- src/sys/timer.cxx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sys/timer.cxx b/src/sys/timer.cxx index e2a140a38d..ba8f812111 100644 --- a/src/sys/timer.cxx +++ b/src/sys/timer.cxx @@ -20,9 +20,8 @@ Timer::~Timer() { } double Timer::getTime() { - if (timing.running) - return timing.time + (MPI_Wtime() - timing.started); - return timing.time; + // If we've got a Timer by value, it must be running + return timing.time + (MPI_Wtime() - timing.started); } double Timer::resetTime() { From b0b82d6b2e24db3598297bf5385452817453c79e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Feb 2019 17:44:12 +0000 Subject: [PATCH 0787/1783] Make FakeMeshFixture destructor virtual so it can be subclassed --- tests/unit/test_extras.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 734edd6e10..f297a6d507 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -259,7 +259,7 @@ public: output_info.enable(); } - ~FakeMeshFixture() { + virtual ~FakeMeshFixture() { delete bout::globals::mesh; bout::globals::mesh = nullptr; } From 5c1d5c13d683a6f1a01f337a973430988ecc069d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Feb 2019 17:44:39 +0000 Subject: [PATCH 0788/1783] Add some basic tests for InterpolationFactory --- .../include/test_interpolation_factory.cxx | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 tests/unit/include/test_interpolation_factory.cxx diff --git a/tests/unit/include/test_interpolation_factory.cxx b/tests/unit/include/test_interpolation_factory.cxx new file mode 100644 index 0000000000..23424b770d --- /dev/null +++ b/tests/unit/include/test_interpolation_factory.cxx @@ -0,0 +1,110 @@ +#include "gtest/gtest.h" + +#include "interpolation.hxx" +#include "interpolation_factory.hxx" +#include "unused.hxx" +#include "bout/mesh.hxx" +#include "options.hxx" + +#include "test_extras.hxx" + +namespace bout { +namespace testing { +// Some variable so we can check if a function was called +bool sentinel_set{false}; +} // namespace testing +} // namespace bout + +class InterpolationFactoryTest : public FakeMeshFixture { +public: + InterpolationFactoryTest() : FakeMeshFixture() {} + ~InterpolationFactoryTest() { + InterpolationFactory::getInstance()->cleanup(); + bout::testing::sentinel_set = false; + } +}; + +class TestInterpolation : public Interpolation { +public: + TestInterpolation(Mesh* mesh = nullptr) : Interpolation(0, mesh) {} + + /// Callback function for InterpolationFactory + static Interpolation* CreateTestInterpolation(Mesh* mesh) { return new Bilinear(mesh); } + + void calcWeights(MAYBE_UNUSED(const Field3D& delta_x), + MAYBE_UNUSED(const Field3D& delta_z)) override { + bout::testing::sentinel_set = true; + }; + void calcWeights(MAYBE_UNUSED(const Field3D& delta_x), + MAYBE_UNUSED(const Field3D& delta_z), + MAYBE_UNUSED(const BoutMask& mask)) override { + bout::testing::sentinel_set = true; + }; + + Field3D interpolate(MAYBE_UNUSED(const Field3D& f)) const override { + return Field3D{-1, localmesh}; + } + Field3D interpolate(MAYBE_UNUSED(const Field3D& f), + MAYBE_UNUSED(const Field3D& delta_x), + MAYBE_UNUSED(const Field3D& delta_z)) override { + return Field3D{-1, localmesh}; + }; + Field3D interpolate(MAYBE_UNUSED(const Field3D& f), + MAYBE_UNUSED(const Field3D& delta_x), + MAYBE_UNUSED(const Field3D& delta_z), + MAYBE_UNUSED(const BoutMask& mask)) override { + return Field3D{-1, localmesh}; + }; +}; + +TEST_F(InterpolationFactoryTest, GetInstance) { + EXPECT_NE(InterpolationFactory::getInstance(), nullptr); +} + +TEST_F(InterpolationFactoryTest, GetDefaultInterpType) { + EXPECT_NE(InterpolationFactory::getInstance()->getDefaultInterpType(), ""); +} + +TEST_F(InterpolationFactoryTest, AddInterpolation) { + EXPECT_NO_THROW(InterpolationFactory::getInstance()->add( + [](Mesh* mesh) -> Interpolation* { return new TestInterpolation(mesh); }, + "test_interpolation")); +} + +TEST_F(InterpolationFactoryTest, CreateInterpolation) { + InterpolationFactory::getInstance()->add( + [](Mesh* mesh) -> Interpolation* { return new TestInterpolation(mesh); }, + "test_interpolation"); + + Interpolation* interpolation{nullptr}; + EXPECT_NO_THROW(interpolation = InterpolationFactory::getInstance()->create("test_interpolation")); + + EXPECT_TRUE(IsFieldEqual(interpolation->interpolate(Field3D{}), -1)); +} + +TEST_F(InterpolationFactoryTest, CreateInterpolationFromOptions) { + InterpolationFactory::getInstance()->add( + [](Mesh* mesh) -> Interpolation* { return new TestInterpolation(mesh); }, + "test_interpolation"); + + Options::root()["interpolation"]["type"] = "test_interpolation"; + + Interpolation* interpolation{nullptr}; + EXPECT_NO_THROW(interpolation = InterpolationFactory::getInstance()->create()); + + EXPECT_TRUE(IsFieldEqual(interpolation->interpolate(Field3D{}), -1)); +} + +TEST_F(InterpolationFactoryTest, CreateUnknownInterpolation) { + EXPECT_THROW(InterpolationFactory::getInstance()->create("nonsense"), BoutException); +} + +TEST_F(InterpolationFactoryTest, Cleanup) { + InterpolationFactory::getInstance()->add( + [](Mesh* mesh) -> Interpolation* { return new TestInterpolation(mesh); }, + "to be removed"); + + InterpolationFactory::getInstance()->cleanup(); + + EXPECT_THROW(InterpolationFactory::getInstance()->create("to be removed"), BoutException); +} From d452771e74bd997b8a26bc1cc8c7419214a6fd03 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Feb 2019 17:44:51 +0000 Subject: [PATCH 0789/1783] Use type alias rather than typedef in InterpolationFactory --- include/interpolation_factory.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/interpolation_factory.hxx b/include/interpolation_factory.hxx index 60b5b2065f..43e9c092d1 100644 --- a/include/interpolation_factory.hxx +++ b/include/interpolation_factory.hxx @@ -12,7 +12,7 @@ class Mesh; class InterpolationFactory { public: /// Callback function definition for creating Interpolation objects - typedef Interpolation* (*CreateInterpCallback)(Mesh*); + using CreateInterpCallback = Interpolation* (*)(Mesh*); private: /// Add the available interpolation methods to the internal map /// From e034c53816bc5fe93da1f89c41533502bd14f261 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 15 Feb 2019 17:27:42 +0000 Subject: [PATCH 0790/1783] Silence interpolation factory test --- tests/unit/include/test_interpolation_factory.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unit/include/test_interpolation_factory.cxx b/tests/unit/include/test_interpolation_factory.cxx index 23424b770d..59e1817826 100644 --- a/tests/unit/include/test_interpolation_factory.cxx +++ b/tests/unit/include/test_interpolation_factory.cxx @@ -17,8 +17,11 @@ bool sentinel_set{false}; class InterpolationFactoryTest : public FakeMeshFixture { public: - InterpolationFactoryTest() : FakeMeshFixture() {} + InterpolationFactoryTest() : FakeMeshFixture() { + output_info.disable(); + } ~InterpolationFactoryTest() { + output_info.enable(); InterpolationFactory::getInstance()->cleanup(); bout::testing::sentinel_set = false; } From 55b49e7a587e547a5bdebfc3b6b16c6cd65fd120 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Feb 2019 16:55:51 +0000 Subject: [PATCH 0791/1783] Add tests for filter/lowPass --- tests/unit/field/test_field3d.cxx | 116 ++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index f7260739c8..627e5a1d80 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -2054,5 +2054,121 @@ TEST_F(Field3DTest, FillField) { EXPECT_TRUE(IsFieldEqual(f, g)); } +namespace bout { +namespace testing { + +// Amplitudes for the nth wavenumber +constexpr int k0{1}; +constexpr int k1{2}; +constexpr int k2{3}; + +const auto box_size{TWOPI / Field3DTest::nz}; + +// Helper function for the filter and lowpass tests +BoutReal zWaves(Field3D::ind_type& i) { + return 1.0 + std::sin(k0 * i.z() * box_size) + std::cos(k1 * i.z() * box_size) + + std::sin(k2 * i.z() * box_size); +} +} // namespace testing +} // namespace bout + +TEST_F(Field3DTest, Filter) { + + using namespace bout::testing; + + auto input = makeField(zWaves, bout::globals::mesh); + + auto expected = makeField( + [&](Field3D::ind_type& i) { return std::cos(k1 * i.z() * box_size); }, + bout::globals::mesh); + + auto output = filter(input, 2); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TEST_F(Field3DTest, LowPassOneArg) { + + using namespace bout::testing; + + auto input = makeField(zWaves, bout::globals::mesh); + + auto expected = makeField( + [&](Field3D::ind_type& i) { + return 1.0 + std::sin(k0 * i.z() * box_size) + std::cos(k1 * i.z() * box_size); + }, + bout::globals::mesh); + + auto output = lowPass(input, 2); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TEST_F(Field3DTest, LowPassOneArgNothing) { + + using namespace bout::testing; + + auto input = makeField(zWaves, bout::globals::mesh); + + auto output = lowPass(input, 20); + + EXPECT_TRUE(IsFieldEqual(output, input)); +} + +TEST_F(Field3DTest, LowPassTwoArg) { + + using namespace bout::testing; + + auto input = makeField(zWaves, bout::globals::mesh); + + auto expected = makeField( + [&](Field3D::ind_type& i) { + return std::sin(k0 * i.z() * box_size) + std::cos(k1 * i.z() * box_size); + }, + bout::globals::mesh); + + auto output = lowPass(input, 2, false); + + EXPECT_TRUE(IsFieldEqual(output, expected)); + + // Check passing int still works + auto output2 = lowPass(input, 2, 0); + + EXPECT_TRUE(IsFieldEqual(output2, expected)); +} + +TEST_F(Field3DTest, LowPassTwoArgKeepZonal) { + + using namespace bout::testing; + + auto input = makeField(zWaves, bout::globals::mesh); + + auto expected = makeField( + [&](Field3D::ind_type& i) { + return 1.0 + std::sin(k0 * i.z() * box_size) + std::cos(k1 * i.z() * box_size); + }, + bout::globals::mesh); + + auto output = lowPass(input, 2, true); + + EXPECT_TRUE(IsFieldEqual(output, expected)); + + // Check passing int still works + auto output2 = lowPass(input, 2, 1); + + EXPECT_TRUE(IsFieldEqual(output2, expected)); +} + +TEST_F(Field3DTest, LowPassTwoArgNothing) { + + using namespace bout::testing; + + auto input = makeField(zWaves, bout::globals::mesh); + + auto output = lowPass(input, 20, true); + + EXPECT_TRUE(IsFieldEqual(output, input)); +} + // Restore compiler warnings #pragma GCC diagnostic pop From ff37bac76896bb9a3136108d79906c84964f0220 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Feb 2019 16:56:10 +0000 Subject: [PATCH 0792/1783] Add test for indexing a const Field3D with Ind2D --- tests/unit/field/test_field3d.cxx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 627e5a1d80..0bbc3783dd 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -754,6 +754,18 @@ TEST_F(Field3DTest, IndexingInd2D) { EXPECT_DOUBLE_EQ(field(ix, iy, iz), -sentinel); } +TEST_F(Field3DTest, ConstIndexingInd2D) { + Field3D field(0.0); + const BoutReal sentinel = 2.0; + int ix = 1, iy = 2, iz = 3; + field(ix, iy, iz) = sentinel; + + Ind2D ind{iy + ny * ix, ny, 1}; + const Field3D field2{field}; + + EXPECT_DOUBLE_EQ(field2(ind, iz), sentinel); +} + TEST_F(Field3DTest, IndexingIndPerp) { Field3D field(0.0); const BoutReal sentinel = 2.0; From 0497a742b95cb529e880830d303665f32f07dda3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Feb 2019 16:59:04 +0000 Subject: [PATCH 0793/1783] Reduce code duplication in lowPass functions Just call the two arg overload from the one arg overload --- include/field3d.hxx | 14 +++++++------ src/field/field3d.cxx | 47 ------------------------------------------- 2 files changed, 8 insertions(+), 53 deletions(-) diff --git a/include/field3d.hxx b/include/field3d.hxx index f9b23400ba..3399992a25 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -705,21 +705,23 @@ const Field3D floor(const Field3D &var, BoutReal f, REGION rgn = RGN_ALL); /// @param[in] rgn The region to calculate the result over const Field3D filter(const Field3D &var, int N0, REGION rgn = RGN_ALL); -/// Fourier low pass filtering. Removes modes higher than \p zmax +/// Fourier low pass filtering. Removes modes +/// lower than \p zmin and higher than \p zmax /// /// @param[in] var Variable to apply filter to +/// @param[in] zmin Minimum mode in Z /// @param[in] zmax Maximum mode in Z /// @param[in] rgn The region to calculate the result over -const Field3D lowPass(const Field3D &var, int zmax, REGION rgn = RGN_ALL); +const Field3D lowPass(const Field3D &var, int zmax, int zmin, REGION rgn = RGN_ALL); -/// Fourier low pass filtering. Removes modes -/// lower than \p zmin and higher than \p zmax +/// Fourier low pass filtering. Removes modes higher than \p zmax /// /// @param[in] var Variable to apply filter to -/// @param[in] zmin Minimum mode in Z /// @param[in] zmax Maximum mode in Z /// @param[in] rgn The region to calculate the result over -const Field3D lowPass(const Field3D &var, int zmax, int zmin, REGION rgn = RGN_ALL); +inline Field3D lowPass(const Field3D &var, int zmax, REGION rgn = RGN_ALL) { + return lowPass(var, zmax, true, rgn); +} /// Perform a shift by a given angle in Z /// diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 9333032543..e6d78aa525 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -855,53 +855,6 @@ const Field3D filter(const Field3D &var, int N0, REGION rgn) { return result; } -// Fourier filter in z -const Field3D lowPass(const Field3D &var, int zmax, REGION rgn) { - TRACE("lowPass(Field3D, %d)", zmax); - - checkData(var); - - Mesh *localmesh = var.getMesh(); - const int ncz = localmesh->LocalNz; - - if ((zmax >= ncz / 2) || (zmax < 0)) { - // Removing nothing - return var; - } - - Field3D result(localmesh); - result.allocate(); - - const auto region_str = REGION_STRING(rgn); - - // Only allow a whitelist of regions for now - ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" || - region_str == "RGN_NOX" || region_str == "RGN_NOY"); - - const Region ®ion = localmesh->getRegion2D(region_str); - - BOUT_OMP(parallel) { - Array f(ncz / 2 + 1); - - BOUT_FOR_INNER(i, region) { - // Take FFT in the Z direction - rfft(var(i.x(), i.y()), ncz, f.begin()); - - // Filter in z - for (int jz = zmax + 1; jz <= ncz / 2; jz++) { - f[jz] = 0.0; - } - - // Reverse FFT - irfft(f.begin(), ncz, result(i.x(), i.y())); - } - } - result.setLocation(var.getLocation()); - - checkData(result); - return result; -} - // Fourier filter in z with zmin const Field3D lowPass(const Field3D &var, int zmax, int zmin, REGION rgn) { TRACE("lowPass(Field3D, %d, %d)", zmax, zmin); From c1276e7d50f451504698c1eb8770a0047c7c25aa Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Feb 2019 17:01:43 +0000 Subject: [PATCH 0794/1783] Update lowPass docs -- zmin is really keep_zonal Also make keep_zonal a bool -- this shouldn't affect calling sites though --- include/field3d.hxx | 6 +++--- src/field/field3d.cxx | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/field3d.hxx b/include/field3d.hxx index 3399992a25..04b42793d9 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -706,13 +706,13 @@ const Field3D floor(const Field3D &var, BoutReal f, REGION rgn = RGN_ALL); const Field3D filter(const Field3D &var, int N0, REGION rgn = RGN_ALL); /// Fourier low pass filtering. Removes modes -/// lower than \p zmin and higher than \p zmax +/// higher than \p zmax and optionally the zonal component /// /// @param[in] var Variable to apply filter to -/// @param[in] zmin Minimum mode in Z /// @param[in] zmax Maximum mode in Z +/// @param[in] keep_zonal Keep the zonal component if true /// @param[in] rgn The region to calculate the result over -const Field3D lowPass(const Field3D &var, int zmax, int zmin, REGION rgn = RGN_ALL); +const Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn = RGN_ALL); /// Fourier low pass filtering. Removes modes higher than \p zmax /// diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index e6d78aa525..019ad0ce19 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -856,14 +856,14 @@ const Field3D filter(const Field3D &var, int N0, REGION rgn) { } // Fourier filter in z with zmin -const Field3D lowPass(const Field3D &var, int zmax, int zmin, REGION rgn) { - TRACE("lowPass(Field3D, %d, %d)", zmax, zmin); +const Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn) { + TRACE("lowPass(Field3D, %d, %d)", zmax, keep_zonal); checkData(var); Mesh *localmesh = var.getMesh(); int ncz = localmesh->LocalNz; - if (((zmax >= ncz / 2) || (zmax < 0)) && (zmin < 0)) { + if (((zmax >= ncz / 2) || (zmax < 0)) && keep_zonal) { // Removing nothing return var; } @@ -891,7 +891,7 @@ const Field3D lowPass(const Field3D &var, int zmax, int zmin, REGION rgn) { f[jz] = 0.0; // Filter zonal mode - if (zmin == 0) { + if (!keep_zonal) { f[0] = 0.0; } // Reverse FFT From b138d109f9de97debcec5c9897a7c745013c186a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Feb 2019 17:02:52 +0000 Subject: [PATCH 0795/1783] Don't return const Field3D from free functions --- include/field3d.hxx | 28 ++++++++++++++-------------- src/field/field3d.cxx | 10 +++++----- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/field3d.hxx b/include/field3d.hxx index 04b42793d9..40c2ab425d 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -580,14 +580,14 @@ Field3D pow(BoutReal lhs, const Field3D &rhs, REGION rgn = RGN_ALL); /// This loops over the entire domain, including guard/boundary cells by /// default (can be changed using the \p rgn argument). /// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field3D sqrt(const Field3D &f, REGION rgn = RGN_ALL); +Field3D sqrt(const Field3D &f, REGION rgn = RGN_ALL); /// Absolute value (modulus, |f|) of \p f over region \p rgn /// /// This loops over the entire domain, including guard/boundary cells by /// default (can be changed using the \p rgn argument). /// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field3D abs(const Field3D &f, REGION rgn = RGN_ALL); +Field3D abs(const Field3D &f, REGION rgn = RGN_ALL); /// Exponential: \f$\exp(f)\f$ is e to the power of \p f, over region /// \p rgn @@ -595,7 +595,7 @@ const Field3D abs(const Field3D &f, REGION rgn = RGN_ALL); /// This loops over the entire domain, including guard/boundary cells by /// default (can be changed using the \p rgn argument). /// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field3D exp(const Field3D &f, REGION rgn = RGN_ALL); +Field3D exp(const Field3D &f, REGION rgn = RGN_ALL); /// Natural logarithm of \p f over region \p rgn, inverse of /// exponential @@ -606,7 +606,7 @@ const Field3D exp(const Field3D &f, REGION rgn = RGN_ALL); /// default (can be changed using the rgn argument) /// If CHECK >= 3 then the result will be checked for non-finite numbers /// -const Field3D log(const Field3D &f, REGION rgn = RGN_ALL); +Field3D log(const Field3D &f, REGION rgn = RGN_ALL); /// Sine trigonometric function. /// @@ -616,7 +616,7 @@ const Field3D log(const Field3D &f, REGION rgn = RGN_ALL); /// This loops over the entire domain, including guard/boundary cells by /// default (can be changed using the \p rgn argument). /// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field3D sin(const Field3D &f, REGION rgn = RGN_ALL); +Field3D sin(const Field3D &f, REGION rgn = RGN_ALL); /// Cosine trigonometric function. /// @@ -626,7 +626,7 @@ const Field3D sin(const Field3D &f, REGION rgn = RGN_ALL); /// This loops over the entire domain, including guard/boundary cells by /// default (can be changed using the \p rgn argument). /// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field3D cos(const Field3D &f, REGION rgn = RGN_ALL); +Field3D cos(const Field3D &f, REGION rgn = RGN_ALL); /// Tangent trigonometric function. /// @@ -636,7 +636,7 @@ const Field3D cos(const Field3D &f, REGION rgn = RGN_ALL); /// This loops over the entire domain, including guard/boundary cells by /// default (can be changed using the \p rgn argument). /// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field3D tan(const Field3D &f, REGION rgn = RGN_ALL); +Field3D tan(const Field3D &f, REGION rgn = RGN_ALL); /// Hyperbolic sine trigonometric function. /// @@ -646,7 +646,7 @@ const Field3D tan(const Field3D &f, REGION rgn = RGN_ALL); /// This loops over the entire domain, including guard/boundary cells by /// default (can be changed using the \p rgn argument). /// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field3D sinh(const Field3D &f, REGION rgn = RGN_ALL); +Field3D sinh(const Field3D &f, REGION rgn = RGN_ALL); /// Hyperbolic cosine trigonometric function. /// @@ -656,7 +656,7 @@ const Field3D sinh(const Field3D &f, REGION rgn = RGN_ALL); /// This loops over the entire domain, including guard/boundary cells by /// default (can be changed using the \p rgn argument). /// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field3D cosh(const Field3D &f, REGION rgn = RGN_ALL); +Field3D cosh(const Field3D &f, REGION rgn = RGN_ALL); /// Hyperbolic tangent trigonometric function. /// @@ -666,7 +666,7 @@ const Field3D cosh(const Field3D &f, REGION rgn = RGN_ALL); /// This loops over the entire domain, including guard/boundary cells by /// default (can be changed using the \p rgn argument). /// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field3D tanh(const Field3D &f, REGION rgn = RGN_ALL); +Field3D tanh(const Field3D &f, REGION rgn = RGN_ALL); /// Check if all values of a field \p var are finite. /// Loops over all points including the boundaries by @@ -688,7 +688,7 @@ inline void checkData(const Field3D &UNUSED(f), REGION UNUSED(region) = RGN_NOBN /// Makes a copy of a field \p f, ensuring that the underlying data is /// not shared. -const Field3D copy(const Field3D &f); +Field3D copy(const Field3D &f); /// Apply a floor value \p f to a field \p var. Any value lower than /// the floor is set to the floor. @@ -696,14 +696,14 @@ const Field3D copy(const Field3D &f); /// @param[in] var Variable to apply floor to /// @param[in] f The floor value /// @param[in] rgn The region to calculate the result over -const Field3D floor(const Field3D &var, BoutReal f, REGION rgn = RGN_ALL); +Field3D floor(const Field3D &var, BoutReal f, REGION rgn = RGN_ALL); /// Fourier filtering, removes all except one mode /// /// @param[in] var Variable to apply filter to /// @param[in] N0 The component to keep /// @param[in] rgn The region to calculate the result over -const Field3D filter(const Field3D &var, int N0, REGION rgn = RGN_ALL); +Field3D filter(const Field3D &var, int N0, REGION rgn = RGN_ALL); /// Fourier low pass filtering. Removes modes /// higher than \p zmax and optionally the zonal component @@ -712,7 +712,7 @@ const Field3D filter(const Field3D &var, int N0, REGION rgn = RGN_ALL); /// @param[in] zmax Maximum mode in Z /// @param[in] keep_zonal Keep the zonal component if true /// @param[in] rgn The region to calculate the result over -const Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn = RGN_ALL); +Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn = RGN_ALL); /// Fourier low pass filtering. Removes modes higher than \p zmax /// diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 019ad0ce19..d352fea086 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -778,7 +778,7 @@ BoutReal mean(const Field3D &f, bool allpe, REGION rgn) { * */ #define F3D_FUNC(name, func) \ - const Field3D name(const Field3D &f, REGION rgn) { \ + Field3D name(const Field3D &f, REGION rgn) { \ TRACE(#name "(Field3D)"); \ /* Check if the input is allocated */ \ checkData(f); \ @@ -805,7 +805,7 @@ F3D_FUNC(sinh, ::sinh); F3D_FUNC(cosh, ::cosh); F3D_FUNC(tanh, ::tanh); -const Field3D filter(const Field3D &var, int N0, REGION rgn) { +Field3D filter(const Field3D &var, int N0, REGION rgn) { TRACE("filter(Field3D, int)"); checkData(var); @@ -856,7 +856,7 @@ const Field3D filter(const Field3D &var, int N0, REGION rgn) { } // Fourier filter in z with zmin -const Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn) { +Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn) { TRACE("lowPass(Field3D, %d, %d)", zmax, keep_zonal); checkData(var); @@ -992,13 +992,13 @@ void checkData(const Field3D &f, REGION region) { } #endif -const Field3D copy(const Field3D &f) { +Field3D copy(const Field3D &f) { Field3D result = f; result.allocate(); return result; } -const Field3D floor(const Field3D &var, BoutReal f, REGION rgn) { +Field3D floor(const Field3D &var, BoutReal f, REGION rgn) { checkData(var); Field3D result = copy(var); From 52bf50fc2acd3a31693a65904709ef8c81624564 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Feb 2019 17:05:18 +0000 Subject: [PATCH 0796/1783] Add some very basic Field tests --- tests/unit/field/test_field.cxx | 47 +++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 tests/unit/field/test_field.cxx diff --git a/tests/unit/field/test_field.cxx b/tests/unit/field/test_field.cxx new file mode 100644 index 0000000000..f2934f6d45 --- /dev/null +++ b/tests/unit/field/test_field.cxx @@ -0,0 +1,47 @@ +#include "gtest/gtest.h" + +#include "bout/constants.hxx" +#include "bout/mesh.hxx" +#include "boutexception.hxx" +#include "field.hxx" +#include "output.hxx" +#include "test_extras.hxx" + +/// Global mesh +namespace bout{ +namespace globals{ +extern Mesh *mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; + +// Reuse the "standard" fixture for FakeMesh +using FieldTest = FakeMeshFixture; + + +TEST_F(FieldTest, GetGlobalMesh) { + Field field; + + auto localmesh = field.getMesh(); + + EXPECT_EQ(localmesh, mesh); +} + +TEST_F(FieldTest, GetLocalMesh) { + FakeMesh myMesh{nx + 1, ny + 2, nz + 3}; + Field field(&myMesh); + + auto localmesh = field.getMesh(); + + EXPECT_EQ(localmesh, &myMesh); +} + +TEST_F(FieldTest, GetGridSizes) { + Field field; + + EXPECT_EQ(field.getNx(), nx); + EXPECT_EQ(field.getNy(), ny); + EXPECT_EQ(field.getNz(), nz); +} From 175463d060a5da7595cfb5f96de2e34acc9bdabe Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Feb 2019 10:03:02 +0000 Subject: [PATCH 0797/1783] Don't use auto and uniform initialisation --- tests/unit/field/test_field3d.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 0bbc3783dd..414d295323 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -2074,7 +2074,7 @@ constexpr int k0{1}; constexpr int k1{2}; constexpr int k2{3}; -const auto box_size{TWOPI / Field3DTest::nz}; +const BoutReal box_size{TWOPI / Field3DTest::nz}; // Helper function for the filter and lowpass tests BoutReal zWaves(Field3D::ind_type& i) { From ea8c8e6834c4963489aa7cd4889c13f72329afdd Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Feb 2019 17:51:25 +0000 Subject: [PATCH 0798/1783] Add explicit tests for Field2D set/getLocation --- tests/unit/field/test_field2d.cxx | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index ce27ae2203..0d76e524f7 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -186,6 +186,43 @@ TEST_F(Field2DTest, TimeDeriv) { EXPECT_EQ(&(ddt(field)), deriv); } +TEST_F(Field2DTest, SetGetLocation) { + Field2D field; + + field.getMesh()->StaggerGrids = true; + + field.setLocation(CELL_XLOW); + EXPECT_EQ(field.getLocation(), CELL_XLOW); + + field.setLocation(CELL_DEFAULT); + EXPECT_EQ(field.getLocation(), CELL_CENTRE); + + EXPECT_THROW(field.setLocation(CELL_VSHIFT), BoutException); +} + +TEST_F(Field2DTest, SetGetLocationNonStaggered) { + Field2D field; + + field.getMesh()->StaggerGrids = false; + +#if CHECK > 0 + EXPECT_THROW(field.setLocation(CELL_XLOW), BoutException); + EXPECT_THROW(field.setLocation(CELL_VSHIFT), BoutException); + + field.setLocation(CELL_DEFAULT); + EXPECT_EQ(field.getLocation(), CELL_CENTRE); +#else + field.setLocation(CELL_XLOW); + EXPECT_EQ(field.getLocation(), CELL_CENTRE); + + field.setLocation(CELL_DEFAULT); + EXPECT_EQ(field.getLocation(), CELL_CENTRE); + + field.setLocation(CELL_VSHIFT); + EXPECT_EQ(field.getLocation(), CELL_CENTRE); +#endif +} + /// This test is split into two parts: a very basic sanity check first /// (do we visit the right number of elements?), followed by a /// slightly more complex check one which checks certain indices are From 321d6241e1703b3d020340c2677dedb0ca25a1a5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 15 Feb 2019 09:55:34 +0000 Subject: [PATCH 0799/1783] Add some missing vector tests --- tests/unit/field/test_vector2d.cxx | 59 ++++++++++++++++++++++++++++++ tests/unit/field/test_vector3d.cxx | 59 ++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index 7e5e032885..2bf4b8be07 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -124,6 +124,20 @@ TEST_F(Vector2DTest, TimeDeriv) { EXPECT_EQ(&(ddt(vector)), deriv); } +TEST_F(Vector2DTest, TimeDerivComponents) { + Vector2D vector; + + // Make time derivatives for components first, then check we rectify + vector.x.timeDeriv(); + vector.y.timeDeriv(); + vector.z.timeDeriv(); + vector.timeDeriv(); + + EXPECT_EQ(&(ddt(vector).x), &(ddt(vector.x))); + EXPECT_EQ(&(ddt(vector).y), &(ddt(vector.y))); + EXPECT_EQ(&(ddt(vector).z), &(ddt(vector.z))); +} + TEST_F(Vector2DTest, SetLocationNonStaggered) { Vector2D vector; EXPECT_EQ(vector.getLocation(), CELL_CENTRE); @@ -437,6 +451,51 @@ TEST_F(Vector2DTest, MultiplyVector2DField3D) { EXPECT_TRUE(IsFieldEqual(result.z, 12.0)); } +TEST_F(Vector2DTest, MultiplyBoutRealVector2D) { + Vector2D vector; + vector.x = 1.0; + vector.y = 2.0; + vector.z = 3.0; + + BoutReal real {2.0}; + + Vector2D result = real * vector; + + EXPECT_TRUE(IsFieldEqual(result.x, 2.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 4.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 6.0)); +} + +TEST_F(Vector2DTest, MultiplyField2DVector2D) { + Vector2D vector; + vector.x = 1.0; + vector.y = 2.0; + vector.z = 3.0; + + Field2D field{3.0}; + + Vector2D result = field * vector; + + EXPECT_TRUE(IsFieldEqual(result.x, 3.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 6.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 9.0)); +} + +TEST_F(Vector2DTest, MultiplyField3DVector2D) { + Vector2D vector; + vector.x = 1.0; + vector.y = 2.0; + vector.z = 3.0; + + Field3D field{4.0}; + + Vector3D result = field * vector; + + EXPECT_TRUE(IsFieldEqual(result.x, 4.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 8.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 12.0)); +} + TEST_F(Vector2DTest, DivideEqualsBoutReal) { Vector2D vector; vector.x = 1.0; diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index d67fd2f085..4556661f22 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -123,6 +123,20 @@ TEST_F(Vector3DTest, TimeDeriv) { EXPECT_EQ(&(ddt(vector)), deriv); } +TEST_F(Vector3DTest, TimeDerivComponents) { + Vector3D vector; + + // Make time derivatives for components first, then check we rectify + vector.x.timeDeriv(); + vector.y.timeDeriv(); + vector.z.timeDeriv(); + vector.timeDeriv(); + + EXPECT_EQ(&(ddt(vector).x), &(ddt(vector.x))); + EXPECT_EQ(&(ddt(vector).y), &(ddt(vector.y))); + EXPECT_EQ(&(ddt(vector).z), &(ddt(vector.z))); +} + TEST_F(Vector3DTest, SetLocationNonStaggered) { Vector3D vector; EXPECT_EQ(vector.getLocation(), CELL_CENTRE); @@ -455,6 +469,51 @@ TEST_F(Vector3DTest, MultiplyVector3DField3D) { EXPECT_TRUE(IsFieldEqual(result.z, 12.0)); } +TEST_F(Vector3DTest, MultiplyBoutRealVector3D) { + Vector3D vector; + vector.x = 1.0; + vector.y = 2.0; + vector.z = 3.0; + + BoutReal real {2.0}; + + Vector3D result = real * vector; + + EXPECT_TRUE(IsFieldEqual(result.x, 2.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 4.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 6.0)); +} + +TEST_F(Vector3DTest, MultiplyField2DVector3D) { + Vector3D vector; + vector.x = 1.0; + vector.y = 2.0; + vector.z = 3.0; + + Field2D field{3.0}; + + Vector3D result = field * vector; + + EXPECT_TRUE(IsFieldEqual(result.x, 3.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 6.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 9.0)); +} + +TEST_F(Vector3DTest, MultiplyField3DVector3D) { + Vector3D vector; + vector.x = 1.0; + vector.y = 2.0; + vector.z = 3.0; + + Field3D field{4.0}; + + Vector3D result = field * vector; + + EXPECT_TRUE(IsFieldEqual(result.x, 4.0)); + EXPECT_TRUE(IsFieldEqual(result.y, 8.0)); + EXPECT_TRUE(IsFieldEqual(result.z, 12.0)); +} + TEST_F(Vector3DTest, DivideEqualsBoutReal) { Vector3D vector; vector.x = 1.0; From a19b9ef949f9d162ff4bbd107b0b13829b9d5ba5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 15 Feb 2019 17:27:21 +0000 Subject: [PATCH 0800/1783] Move setting fft_init to test driver --- tests/unit/bout_test_main.cxx | 8 +++++++- tests/unit/include/test_derivs.cxx | 4 ---- tests/unit/invert/test_fft.cxx | 3 --- tests/unit/mesh/parallel/test_shiftedmetric.cxx | 3 --- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/tests/unit/bout_test_main.cxx b/tests/unit/bout_test_main.cxx index 0daaebcfb7..40c9fb3f01 100644 --- a/tests/unit/bout_test_main.cxx +++ b/tests/unit/bout_test_main.cxx @@ -2,8 +2,14 @@ #include "gtest/gtest.h" #include "bout/array.hxx" +#include "fft.hxx" + +GTEST_API_ int main(int argc, char** argv) { + + // Make sure fft functions are both quiet and deterministic by + // setting fft_measure to false + bout::fft::fft_init(false); -GTEST_API_ int main(int argc, char **argv) { printf("Running main() from bout_test_main.cxx\n"); testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS(); diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index a21d17ca9c..34dc7dabc3 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -45,10 +45,6 @@ class DerivativesTest public: DerivativesTest() : input{mesh}, expected{mesh} { - // Make sure fft functions are both quiet and deterministic by - // setting fft_measure to false - bout::fft::fft_init(false); - using Index = Field3D::ind_type; // Pointer to index method that converts single-index to 3-index space diff --git a/tests/unit/invert/test_fft.cxx b/tests/unit/invert/test_fft.cxx index 735fcedb93..29c3b38d02 100644 --- a/tests/unit/invert/test_fft.cxx +++ b/tests/unit/invert/test_fft.cxx @@ -15,9 +15,6 @@ class FFTTest : public ::testing::TestWithParam { FFTTest() : size(GetParam()), nmodes((size / 2) + 1), real_signal(size), fft_signal(nmodes) { - // Make sure fft functions are quiet by setting fft_measure to false - bout::fft::fft_init(false); - // Make grid indices from [0, size - 1] Array indices{size}; std::iota(indices.begin(), indices.end(), 0.0); diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 37d13f6179..ca2da59bee 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -26,9 +26,6 @@ class ShiftedMetricTest : public ::testing::Test { mesh->createDefaultRegions(); output_info.enable(); - // Make sure fft functions are quiet by setting fft_measure to false - bout::fft::fft_init(false); - zShift = Field2D{mesh}; fillField(zShift, {{1., 2., 3., 4., 5., 6., 7.}, From 8d96dae115e06a9c03a75cb95756362339a16c90 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 19 Feb 2019 17:00:22 +0000 Subject: [PATCH 0801/1783] Add destructor to DerivativesTest --- tests/unit/include/test_derivs.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index a21d17ca9c..a7fdef06b5 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -94,11 +94,6 @@ class DerivativesTest throw BoutException("bad direction"); } - if (mesh != nullptr) { - delete mesh; - mesh = nullptr; - } - mesh = new FakeMesh(nx, ny, nz); mesh->xstart = x_guards; @@ -155,6 +150,11 @@ class DerivativesTest DerivativeStore::getInstance().initialise(Options::getRoot()); }; + ~DerivativesTest() { + delete mesh; + mesh = nullptr; + } + Field3D input, velocity; Field3D expected; From 4ccbfe0fec7eeb7515b98545017242c344f0e547 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 15 Feb 2019 17:59:52 +0000 Subject: [PATCH 0802/1783] Add tests for index derivatives interface --- tests/unit/include/test_derivs.cxx | 193 +++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index a7fdef06b5..efe069f89f 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -6,6 +6,7 @@ #include "test_extras.hxx" #include "bout/constants.hxx" #include "bout/deriv_store.hxx" +#include "bout/index_derivs_interface.hxx" #include "bout/paralleltransform.hxx" #include @@ -145,6 +146,7 @@ class DerivativesTest // We need the parallel slices for the y-direction ParallelTransformIdentity identity{*mesh}; identity.calcYUpDown(input); + identity.calcYUpDown(velocity); // FIXME: remove when defaults are set in the DerivativeStore ctor DerivativeStore::getInstance().initialise(Options::getRoot()); @@ -301,3 +303,194 @@ TEST_P(DerivativesTestAdvection, Sanity) { EXPECT_TRUE( IsFieldEqual(result, expected, "RGN_NOBNDRY", derivatives_tolerance)); } + +///////////////////////////////////////////////////////////////////// +// The following tests are essentially identical to the above, expect +// that we test the derivatives through the actual (index) derivative +// interface. This makes things a little more awkward to do completely +// generically, so let's not bother + +using FirstDerivativesInterfaceTest = DerivativesTest; + +INSTANTIATE_TEST_CASE_P(X, FirstDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, + DIRECTION::X)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(FirstY, FirstDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, + DIRECTION::Y)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(FirstZ, FirstDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, + DIRECTION::Z)), + methodDirectionTupleToString); + +TEST_P(FirstDerivativesInterfaceTest, Sanity) { + Field3D result; + switch (std::get<0>(GetParam())) { + case DIRECTION::X: + result = bout::derivatives::index::DDX(input); + break; + case DIRECTION::Y: + result = bout::derivatives::index::DDY(input); + break; + case DIRECTION::Z: + result = bout::derivatives::index::DDZ(input); + break; + default: + break; + } + + EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_NOBNDRY", derivatives_tolerance)); +} + +using SecondDerivativesInterfaceTest = DerivativesTest; + +INSTANTIATE_TEST_CASE_P(X, SecondDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, + DIRECTION::X)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(Y, SecondDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, + DIRECTION::Y)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(Z, SecondDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, + DIRECTION::Z)), + methodDirectionTupleToString); + +TEST_P(SecondDerivativesInterfaceTest, Sanity) { + Field3D result; + switch (std::get<0>(GetParam())) { + case DIRECTION::X: + result = bout::derivatives::index::D2DX2(input); + break; + case DIRECTION::Y: + result = bout::derivatives::index::D2DY2(input); + break; + case DIRECTION::Z: + result = bout::derivatives::index::D2DZ2(input); + break; + default: + break; + } + + EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_NOBNDRY", derivatives_tolerance)); +} + +using FourthDerivativesInterfaceTest = DerivativesTest; + +INSTANTIATE_TEST_CASE_P(X, FourthDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardFourth, + DIRECTION::X)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(Y, FourthDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardFourth, + DIRECTION::Y)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(Z, FourthDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardFourth, + DIRECTION::Z)), + methodDirectionTupleToString); + +TEST_P(FourthDerivativesInterfaceTest, Sanity) { + Field3D result; + switch (std::get<0>(GetParam())) { + case DIRECTION::X: + result = bout::derivatives::index::D4DX4(input); + break; + case DIRECTION::Y: + result = bout::derivatives::index::D4DY4(input); + break; + case DIRECTION::Z: + result = bout::derivatives::index::D4DZ4(input); + break; + default: + break; + } + + EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_NOBNDRY", derivatives_tolerance)); +} + + +using UpwindDerivativesInterfaceTest = DerivativesTest; + +// Instantiate the test for X, Y, Z for upwind derivatives +INSTANTIATE_TEST_CASE_P(X, UpwindDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Upwind, + DIRECTION::X)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(Y, UpwindDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Upwind, + DIRECTION::Y)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(Z, UpwindDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Upwind, + DIRECTION::Z)), + methodDirectionTupleToString); + +TEST_P(UpwindDerivativesInterfaceTest, Sanity) { + Field3D result; + + switch (std::get<0>(GetParam())) { + case DIRECTION::X: + result = bout::derivatives::index::VDDX(velocity, input); + break; + case DIRECTION::Y: + result = bout::derivatives::index::VDDY(velocity, input); + break; + case DIRECTION::Z: + result = bout::derivatives::index::VDDZ(velocity, input); + break; + default: + break; + } + + EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_NOBNDRY", derivatives_tolerance)); +} + +using FluxDerivativesInterfaceTest = DerivativesTest; + +// Instantiate the test for X, Y, Z for flux derivatives +INSTANTIATE_TEST_CASE_P(X, FluxDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Flux, + DIRECTION::X)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(Y, FluxDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Flux, + DIRECTION::Y)), + methodDirectionTupleToString); + +INSTANTIATE_TEST_CASE_P(Z, FluxDerivativesInterfaceTest, + ::testing::ValuesIn(getMethodsForDirection(DERIV::Flux, + DIRECTION::Z)), + methodDirectionTupleToString); + +TEST_P(FluxDerivativesInterfaceTest, Sanity) { + Field3D result; + + switch (std::get<0>(GetParam())) { + case DIRECTION::X: + result = bout::derivatives::index::FDDX(velocity, input); + break; + case DIRECTION::Y: + result = bout::derivatives::index::FDDY(velocity, input); + break; + case DIRECTION::Z: + result = bout::derivatives::index::FDDZ(velocity, input); + break; + default: + break; + } + + EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_NOBNDRY", derivatives_tolerance)); +} From 81d2bf46a44f369a3fd524cfa95f2f708ff87861 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 15 Feb 2019 18:06:57 +0000 Subject: [PATCH 0803/1783] Add some more deriv store tests --- tests/unit/include/bout/test_deriv_store.cxx | 36 ++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/unit/include/bout/test_deriv_store.cxx b/tests/unit/include/bout/test_deriv_store.cxx index ea00f6468a..c5c963ee4c 100644 --- a/tests/unit/include/bout/test_deriv_store.cxx +++ b/tests/unit/include/bout/test_deriv_store.cxx @@ -123,6 +123,24 @@ TEST(DerivativeStoreTest, RegisterStandardSecond) { store.reset(); } +TEST(DerivativeStoreTest, RegisterMatchingMethodStandardSecondMethodTwice) { + auto& store = DerivativeStore::getInstance(); + + store.registerDerivative(standardType{}, DERIV::StandardSecond, DIRECTION::X, + STAGGER::None, "SecondStandard"); + + // Try to register another method with the same key + EXPECT_THROW(store.registerDerivative(standardType{}, DERIV::StandardSecond, + DIRECTION::X, STAGGER::None, "SecondStandard"), + BoutException); + + auto methods = store.getAvailableMethods(DERIV::StandardSecond, DIRECTION::X); + EXPECT_EQ(methods.size(), 1); + EXPECT_NE(methods.find("SecondStandard"), methods.end()); + + store.reset(); +} + TEST(DerivativeStoreTest, RegisterStandardFourth) { auto& store = DerivativeStore::getInstance(); const DERIV type = DERIV::StandardFourth; @@ -135,6 +153,24 @@ TEST(DerivativeStoreTest, RegisterStandardFourth) { store.reset(); } +TEST(DerivativeStoreTest, RegisterMatchingMethodStandardFourthMethodTwice) { + auto& store = DerivativeStore::getInstance(); + + store.registerDerivative(standardType{}, DERIV::StandardFourth, DIRECTION::X, + STAGGER::None, "FourthStandard"); + + // Try to register another method with the same key + EXPECT_THROW(store.registerDerivative(standardType{}, DERIV::StandardFourth, + DIRECTION::X, STAGGER::None, "FourthStandard"), + BoutException); + + auto methods = store.getAvailableMethods(DERIV::StandardFourth, DIRECTION::X); + EXPECT_EQ(methods.size(), 1); + EXPECT_NE(methods.find("FourthStandard"), methods.end()); + + store.reset(); +} + TEST(DerivativeStoreTest, RegisterUpwind) { auto& store = DerivativeStore::getInstance(); const DERIV type = DERIV::Upwind; From c37eb9b2c5a73133565750cf789f47843cf9d57d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 18 Feb 2019 15:38:29 +0000 Subject: [PATCH 0804/1783] Add more derivative store tests --- tests/unit/include/bout/test_deriv_store.cxx | 129 ++++++++++++++++++- 1 file changed, 122 insertions(+), 7 deletions(-) diff --git a/tests/unit/include/bout/test_deriv_store.cxx b/tests/unit/include/bout/test_deriv_store.cxx index c5c963ee4c..60071bad3b 100644 --- a/tests/unit/include/bout/test_deriv_store.cxx +++ b/tests/unit/include/bout/test_deriv_store.cxx @@ -171,6 +171,34 @@ TEST(DerivativeStoreTest, RegisterMatchingMethodStandardFourthMethodTwice) { store.reset(); } +TEST(DerivativeStoreTest, RegisterUpwindAsStandard) { + auto& store = DerivativeStore::getInstance(); + const DERIV type = DERIV::Standard; + const DIRECTION dir = DIRECTION::X; + + EXPECT_THROW( + store.registerDerivative(flowType{}, type, dir, STAGGER::None, "BadSignature"), + BoutException); + auto methods = store.getAvailableMethods(type, dir); + EXPECT_EQ(methods.size(), 0); + EXPECT_EQ(methods.find("BadSignature"), methods.end()); + store.reset(); +} + +TEST(DerivativeStoreTest, RegisterStandardAsUpwind) { + auto& store = DerivativeStore::getInstance(); + const DERIV type = DERIV::Upwind; + const DIRECTION dir = DIRECTION::X; + + EXPECT_THROW( + store.registerDerivative(standardType{}, type, dir, STAGGER::None, "BadSignature"), + BoutException); + auto methods = store.getAvailableMethods(type, dir); + EXPECT_EQ(methods.size(), 0); + EXPECT_EQ(methods.find("BadSignature"), methods.end()); + store.reset(); +} + TEST(DerivativeStoreTest, RegisterUpwind) { auto& store = DerivativeStore::getInstance(); const DERIV type = DERIV::Upwind; @@ -183,6 +211,23 @@ TEST(DerivativeStoreTest, RegisterUpwind) { store.reset(); } +TEST(DerivativeStoreTest, RegisterUpwindTwice) { + auto& store = DerivativeStore::getInstance(); + const DERIV type = DERIV::Upwind; + const DIRECTION dir = DIRECTION::X; + + store.registerDerivative(flowType{}, type, dir, STAGGER::None, "FirstStandard"); + + EXPECT_THROW( + store.registerDerivative(flowType{}, type, dir, STAGGER::None, "FirstStandard"), + BoutException); + + auto methods = store.getAvailableMethods(type, dir); + EXPECT_EQ(methods.size(), 1); + EXPECT_NE(methods.find("FirstStandard"), methods.end()); + store.reset(); +} + TEST(DerivativeStoreTest, RegisterFlux) { auto& store = DerivativeStore::getInstance(); const DERIV type = DERIV::Flux; @@ -195,6 +240,23 @@ TEST(DerivativeStoreTest, RegisterFlux) { store.reset(); } +TEST(DerivativeStoreTest, RegisterFluxTwice) { + auto& store = DerivativeStore::getInstance(); + const DERIV type = DERIV::Flux; + const DIRECTION dir = DIRECTION::X; + + store.registerDerivative(flowType{}, type, dir, STAGGER::None, "FirstStandard"); + + EXPECT_THROW( + store.registerDerivative(flowType{}, type, dir, STAGGER::None, "FirstStandard"), + BoutException); + + auto methods = store.getAvailableMethods(type, dir); + EXPECT_EQ(methods.size(), 1); + EXPECT_NE(methods.find("FirstStandard"), methods.end()); + store.reset(); +} + TEST(DerivativeStoreTest, RegisterStandardAndGetBack) { auto& store = DerivativeStore::getInstance(); const DERIV type = DERIV::Standard; @@ -214,7 +276,7 @@ TEST(DerivativeStoreTest, RegisterStandardAndGetBack) { standardType returned = store.getStandardDerivative(firstName, dir); FieldType inOrig, outOrig; - standardReturnTenSetToOne(inOrig, outOrig); + standardReturnTenSetToOne({}, outOrig); FieldType outRet; returned(inOrig, outRet, RGN_ALL); @@ -222,9 +284,7 @@ TEST(DerivativeStoreTest, RegisterStandardAndGetBack) { EXPECT_EQ(outOrig.size(), 10); ASSERT_EQ(outRet.size(), outOrig.size()); - for (unsigned int i = 0; i < outOrig.size(); i++) { - EXPECT_EQ(outOrig[i], outRet[i]); - }; + EXPECT_EQ(outOrig, outRet); store.reset(); } @@ -255,9 +315,64 @@ TEST(DerivativeStoreTest, RegisterFlowAndGetBack) { EXPECT_EQ(outOrig.size(), 6); ASSERT_EQ(outRet.size(), outOrig.size()); - for (unsigned int i = 0; i < outOrig.size(); i++) { - EXPECT_EQ(outOrig[i], outRet[i]); - }; + EXPECT_EQ(outOrig, outRet); + + store.reset(); +} + +TEST(DerivativeStoreTest, GetUnknownDerivativeFromStandard) { + auto& store = DerivativeStore::getInstance(); + // Register something we're not just throwing because the store is empty + store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, + "something"); + EXPECT_THROW(store.getStandardDerivative("unknown", DIRECTION::X), BoutException); + store.reset(); +} + +TEST(DerivativeStoreTest, GetUnknownDerivativeFromFlow) { + auto& store = DerivativeStore::getInstance(); + // Register something we're not just throwing because the store is empty + store.registerDerivative(flowType{}, DERIV::Flux, DIRECTION::X, STAGGER::None, + "something"); + EXPECT_THROW(store.getFlowDerivative("unknown", DIRECTION::X), BoutException); + store.reset(); +} +TEST(DerivativeStoreTest, GetUpwindFromStandardDerivative) { + auto& store = DerivativeStore::getInstance(); + // Register something we're not just throwing because the store is empty + store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, + "bad type"); + store.registerDerivative(flowType{}, DERIV::Flux, DIRECTION::X, STAGGER::None, + "bad type"); + EXPECT_THROW( + store.getStandardDerivative("bad type", DIRECTION::X, STAGGER::None, DERIV::Upwind), + BoutException); + store.reset(); +} + +TEST(DerivativeStoreTest, GetFluxFromStandardDerivative) { + auto& store = DerivativeStore::getInstance(); + // Register something we're not just throwing because the store is empty + store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, + "bad type"); + store.registerDerivative(flowType{}, DERIV::Flux, DIRECTION::X, STAGGER::None, + "bad type"); + EXPECT_THROW( + store.getStandardDerivative("bad type", DIRECTION::X, STAGGER::None, DERIV::Flux), + BoutException); + store.reset(); +} + +TEST(DerivativeStoreTest, GetStandardFromFlowDerivative) { + auto& store = DerivativeStore::getInstance(); + // Register something we're not just throwing because the store is empty + store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, + "bad type"); + store.registerDerivative(flowType{}, DERIV::Flux, DIRECTION::X, STAGGER::None, + "bad type"); + EXPECT_THROW( + store.getFlowDerivative("bad type", DIRECTION::X, STAGGER::None, DERIV::Standard), + BoutException); store.reset(); } From dbca660ffb7ae2f52c1750707372339e4a92b09a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 18 Feb 2019 15:39:01 +0000 Subject: [PATCH 0805/1783] Fix bug when registering methods Method name was registered before checking if we could register it --- include/bout/deriv_store.hxx | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index aec60fd8e1..56ac1ef4c1 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -136,10 +136,6 @@ struct DerivativeStore { AUTO_TRACE(); const auto key = getKey(direction, stagger, methodName); - // Register this method name in lookup of known methods - registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))].insert( - methodName); - switch (derivType) { case (DERIV::Standard): if (standard.count(key) != 0) { @@ -149,7 +145,7 @@ struct DerivativeStore { STAGGER_STRING(stagger).c_str(), methodName.c_str()); } standard[key] = func; - return; + break; case (DERIV::StandardSecond): if (standardSecond.count(key) != 0) { throw BoutException("Trying to override standardSecond derivative : " @@ -158,7 +154,7 @@ struct DerivativeStore { STAGGER_STRING(stagger).c_str(), methodName.c_str()); } standardSecond[key] = func; - return; + break; case (DERIV::StandardFourth): if (standardFourth.count(key) != 0) { throw BoutException("Trying to override standardFourth derivative : " @@ -167,13 +163,17 @@ struct DerivativeStore { STAGGER_STRING(stagger).c_str(), methodName.c_str()); } standardFourth[key] = func; - return; + break; default: throw BoutException("Invalid function signature in registerDerivative : Function " "signature 'standard' but derivative type %s passed", DERIV_STRING(derivType).c_str()); }; - return; + + // Register this method name in lookup of known methods + registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))].insert( + methodName); + }; /// Register a function with upwindFunc/fluxFunc interface. Which map is used @@ -183,10 +183,6 @@ struct DerivativeStore { AUTO_TRACE(); const auto key = getKey(direction, stagger, methodName); - // Register this method name in lookup of known methods - registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))].insert( - methodName); - switch (derivType) { case (DERIV::Upwind): if (upwind.count(key) != 0) { @@ -196,7 +192,7 @@ struct DerivativeStore { STAGGER_STRING(stagger).c_str(), methodName.c_str()); } upwind[key] = func; - return; + break; case (DERIV::Flux): if (flux.count(key) != 0) { throw BoutException("Trying to override flux derivative : " @@ -205,13 +201,16 @@ struct DerivativeStore { STAGGER_STRING(stagger).c_str(), methodName.c_str()); } flux[key] = func; - return; + break; default: throw BoutException("Invalid function signature in registerDerivative : Function " "signature 'upwind/flux' but derivative type %s passed", DERIV_STRING(derivType).c_str()); }; - return; + + // Register this method name in lookup of known methods + registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))].insert( + methodName); }; /// Templated versions of the above registration routines. From 289d00d071eea373d82c3fbc6b2e9957e39b4514 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 18 Feb 2019 15:39:42 +0000 Subject: [PATCH 0806/1783] Distinguish between clearing and resetting DerivativeStore - `reset` reverts back to the initial state (i.e. initial defaults) - `clear` does what `reset` used to do --- include/bout/deriv_store.hxx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 56ac1ef4c1..6c4c38e27d 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -413,7 +413,7 @@ struct DerivativeStore { } /// Empty all member storage - void reset() { + void clear() { defaultMethods.clear(); standard.clear(); standardSecond.clear(); @@ -423,6 +423,13 @@ struct DerivativeStore { registeredMethods.clear(); } + /// Reset to initial state + void reset() { + clear(); + + setDefaults(); + } + private: // Make empty constructor private so we can't make instances outside // of the struct From 100da06d45a6a06593e67fd8dd879c14fc801dae Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 18 Feb 2019 15:47:11 +0000 Subject: [PATCH 0807/1783] Use a fixture for DerivativeStoreTest --- tests/unit/include/bout/test_deriv_store.cxx | 112 ++++++------------- 1 file changed, 34 insertions(+), 78 deletions(-) diff --git a/tests/unit/include/bout/test_deriv_store.cxx b/tests/unit/include/bout/test_deriv_store.cxx index 60071bad3b..9fc364e6a6 100644 --- a/tests/unit/include/bout/test_deriv_store.cxx +++ b/tests/unit/include/bout/test_deriv_store.cxx @@ -23,40 +23,38 @@ void flowReturnSixSetToTwo(const FieldType& UNUSED(vel), const FieldType& UNUSED out.resize(6, 2.0); } -TEST(DerivativeStoreTest, CanGetInstance) { +class DerivativeStoreTest : public ::testing::Test { +public: + DerivativeStoreTest() : store{DerivativeStore::getInstance()} {} + ~DerivativeStoreTest() { store.reset(); } + + DerivativeStore& store; +}; + +TEST_F(DerivativeStoreTest, CanGetInstance) { EXPECT_NO_THROW(DerivativeStore::getInstance()); } -TEST(DerivativeStoreTest, IsAllEmpty) { - auto& store = DerivativeStore::getInstance(); - EXPECT_TRUE(store.isEmpty()); -} +TEST_F(DerivativeStoreTest, IsAllEmpty) { EXPECT_TRUE(store.isEmpty()); } -TEST(DerivativeStoreTest, IsEmptySpecificType) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, IsEmptySpecificType) { EXPECT_TRUE(store.isEmpty(DERIV::Standard, DIRECTION::X, STAGGER::None)); } -TEST(DerivativeStoreTest, GetAvailableMethodsEmpty) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, GetAvailableMethodsEmpty) { EXPECT_TRUE(store.isEmpty()); const auto methods = store.getAvailableMethods(DERIV::Standard, DIRECTION::X); EXPECT_EQ(methods.size(), 0); } -TEST(DerivativeStoreTest, RegisterStandardMethod) { - auto& store = DerivativeStore::getInstance(); - +TEST_F(DerivativeStoreTest, RegisterStandardMethod) { store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, "FirstStandard"); const auto methods = store.getAvailableMethods(DERIV::Standard, DIRECTION::X); EXPECT_EQ(methods.size(), 1); - - store.reset(); } -TEST(DerivativeStoreTest, RegisterStandardMethodAndClear) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterStandardMethodAndClear) { store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, "FirstStandard"); @@ -66,12 +64,12 @@ TEST(DerivativeStoreTest, RegisterStandardMethodAndClear) { EXPECT_NE(methods.find("FirstStandard"), methods.end()); store.reset(); + methods = store.getAvailableMethods(DERIV::Standard, DIRECTION::X); EXPECT_EQ(methods.size(), 0); } -TEST(DerivativeStoreTest, RegisterMatchingMethodStandardMethodTwice) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterMatchingMethodStandardMethodTwice) { store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, "FirstStandard"); @@ -87,12 +85,9 @@ TEST(DerivativeStoreTest, RegisterMatchingMethodStandardMethodTwice) { methods = store.getAvailableMethods(DERIV::Standard, DIRECTION::X); EXPECT_EQ(methods.size(), 1); EXPECT_NE(methods.find("FirstStandard"), methods.end()); - - store.reset(); } -TEST(DerivativeStoreTest, RegisterMatchingMethodStandardMethodTwo) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterMatchingMethodStandardMethodTwo) { store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, "FirstStandard"); @@ -108,11 +103,9 @@ TEST(DerivativeStoreTest, RegisterMatchingMethodStandardMethodTwo) { EXPECT_NE(methods.find("FirstStandard"), methods.end()); EXPECT_NE(methods.find("SecondStandard"), methods.end()); - store.reset(); } -TEST(DerivativeStoreTest, RegisterStandardSecond) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterStandardSecond) { const DERIV type = DERIV::StandardSecond; const DIRECTION dir = DIRECTION::X; @@ -120,11 +113,9 @@ TEST(DerivativeStoreTest, RegisterStandardSecond) { auto methods = store.getAvailableMethods(type, dir); EXPECT_EQ(methods.size(), 1); EXPECT_NE(methods.find("FirstStandard"), methods.end()); - store.reset(); } -TEST(DerivativeStoreTest, RegisterMatchingMethodStandardSecondMethodTwice) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterMatchingMethodStandardSecondMethodTwice) { store.registerDerivative(standardType{}, DERIV::StandardSecond, DIRECTION::X, STAGGER::None, "SecondStandard"); @@ -137,12 +128,9 @@ TEST(DerivativeStoreTest, RegisterMatchingMethodStandardSecondMethodTwice) { auto methods = store.getAvailableMethods(DERIV::StandardSecond, DIRECTION::X); EXPECT_EQ(methods.size(), 1); EXPECT_NE(methods.find("SecondStandard"), methods.end()); - - store.reset(); } -TEST(DerivativeStoreTest, RegisterStandardFourth) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterStandardFourth) { const DERIV type = DERIV::StandardFourth; const DIRECTION dir = DIRECTION::X; @@ -150,11 +138,9 @@ TEST(DerivativeStoreTest, RegisterStandardFourth) { auto methods = store.getAvailableMethods(type, dir); EXPECT_EQ(methods.size(), 1); EXPECT_NE(methods.find("FirstStandard"), methods.end()); - store.reset(); } -TEST(DerivativeStoreTest, RegisterMatchingMethodStandardFourthMethodTwice) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterMatchingMethodStandardFourthMethodTwice) { store.registerDerivative(standardType{}, DERIV::StandardFourth, DIRECTION::X, STAGGER::None, "FourthStandard"); @@ -167,12 +153,9 @@ TEST(DerivativeStoreTest, RegisterMatchingMethodStandardFourthMethodTwice) { auto methods = store.getAvailableMethods(DERIV::StandardFourth, DIRECTION::X); EXPECT_EQ(methods.size(), 1); EXPECT_NE(methods.find("FourthStandard"), methods.end()); - - store.reset(); } -TEST(DerivativeStoreTest, RegisterUpwindAsStandard) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterUpwindAsStandard) { const DERIV type = DERIV::Standard; const DIRECTION dir = DIRECTION::X; @@ -182,11 +165,9 @@ TEST(DerivativeStoreTest, RegisterUpwindAsStandard) { auto methods = store.getAvailableMethods(type, dir); EXPECT_EQ(methods.size(), 0); EXPECT_EQ(methods.find("BadSignature"), methods.end()); - store.reset(); } -TEST(DerivativeStoreTest, RegisterStandardAsUpwind) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterStandardAsUpwind) { const DERIV type = DERIV::Upwind; const DIRECTION dir = DIRECTION::X; @@ -196,11 +177,9 @@ TEST(DerivativeStoreTest, RegisterStandardAsUpwind) { auto methods = store.getAvailableMethods(type, dir); EXPECT_EQ(methods.size(), 0); EXPECT_EQ(methods.find("BadSignature"), methods.end()); - store.reset(); } -TEST(DerivativeStoreTest, RegisterUpwind) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterUpwind) { const DERIV type = DERIV::Upwind; const DIRECTION dir = DIRECTION::X; @@ -208,11 +187,9 @@ TEST(DerivativeStoreTest, RegisterUpwind) { auto methods = store.getAvailableMethods(type, dir); EXPECT_EQ(methods.size(), 1); EXPECT_NE(methods.find("FirstStandard"), methods.end()); - store.reset(); } -TEST(DerivativeStoreTest, RegisterUpwindTwice) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterUpwindTwice) { const DERIV type = DERIV::Upwind; const DIRECTION dir = DIRECTION::X; @@ -225,11 +202,9 @@ TEST(DerivativeStoreTest, RegisterUpwindTwice) { auto methods = store.getAvailableMethods(type, dir); EXPECT_EQ(methods.size(), 1); EXPECT_NE(methods.find("FirstStandard"), methods.end()); - store.reset(); } -TEST(DerivativeStoreTest, RegisterFlux) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterFlux) { const DERIV type = DERIV::Flux; const DIRECTION dir = DIRECTION::X; @@ -237,11 +212,9 @@ TEST(DerivativeStoreTest, RegisterFlux) { auto methods = store.getAvailableMethods(type, dir); EXPECT_EQ(methods.size(), 1); EXPECT_NE(methods.find("FirstStandard"), methods.end()); - store.reset(); } -TEST(DerivativeStoreTest, RegisterFluxTwice) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterFluxTwice) { const DERIV type = DERIV::Flux; const DIRECTION dir = DIRECTION::X; @@ -254,11 +227,9 @@ TEST(DerivativeStoreTest, RegisterFluxTwice) { auto methods = store.getAvailableMethods(type, dir); EXPECT_EQ(methods.size(), 1); EXPECT_NE(methods.find("FirstStandard"), methods.end()); - store.reset(); } -TEST(DerivativeStoreTest, RegisterStandardAndGetBack) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterStandardAndGetBack) { const DERIV type = DERIV::Standard; const DIRECTION dir = DIRECTION::X; const std::string firstName = "FIRSTSTANDARD"; @@ -285,12 +256,9 @@ TEST(DerivativeStoreTest, RegisterStandardAndGetBack) { ASSERT_EQ(outRet.size(), outOrig.size()); EXPECT_EQ(outOrig, outRet); - - store.reset(); } -TEST(DerivativeStoreTest, RegisterFlowAndGetBack) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, RegisterFlowAndGetBack) { const DERIV type = DERIV::Upwind; const DIRECTION dir = DIRECTION::X; const std::string firstName = "FIRSTSTANDARD"; @@ -316,30 +284,23 @@ TEST(DerivativeStoreTest, RegisterFlowAndGetBack) { ASSERT_EQ(outRet.size(), outOrig.size()); EXPECT_EQ(outOrig, outRet); - - store.reset(); } -TEST(DerivativeStoreTest, GetUnknownDerivativeFromStandard) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, GetUnknownDerivativeFromStandard) { // Register something we're not just throwing because the store is empty store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, "something"); EXPECT_THROW(store.getStandardDerivative("unknown", DIRECTION::X), BoutException); - store.reset(); } -TEST(DerivativeStoreTest, GetUnknownDerivativeFromFlow) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, GetUnknownDerivativeFromFlow) { // Register something we're not just throwing because the store is empty store.registerDerivative(flowType{}, DERIV::Flux, DIRECTION::X, STAGGER::None, "something"); EXPECT_THROW(store.getFlowDerivative("unknown", DIRECTION::X), BoutException); - store.reset(); } -TEST(DerivativeStoreTest, GetUpwindFromStandardDerivative) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, GetUpwindFromStandardDerivative) { // Register something we're not just throwing because the store is empty store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, "bad type"); @@ -348,11 +309,9 @@ TEST(DerivativeStoreTest, GetUpwindFromStandardDerivative) { EXPECT_THROW( store.getStandardDerivative("bad type", DIRECTION::X, STAGGER::None, DERIV::Upwind), BoutException); - store.reset(); } -TEST(DerivativeStoreTest, GetFluxFromStandardDerivative) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, GetFluxFromStandardDerivative) { // Register something we're not just throwing because the store is empty store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, "bad type"); @@ -361,11 +320,9 @@ TEST(DerivativeStoreTest, GetFluxFromStandardDerivative) { EXPECT_THROW( store.getStandardDerivative("bad type", DIRECTION::X, STAGGER::None, DERIV::Flux), BoutException); - store.reset(); } -TEST(DerivativeStoreTest, GetStandardFromFlowDerivative) { - auto& store = DerivativeStore::getInstance(); +TEST_F(DerivativeStoreTest, GetStandardFromFlowDerivative) { // Register something we're not just throwing because the store is empty store.registerDerivative(standardType{}, DERIV::Standard, DIRECTION::X, STAGGER::None, "bad type"); @@ -374,5 +331,4 @@ TEST(DerivativeStoreTest, GetStandardFromFlowDerivative) { EXPECT_THROW( store.getFlowDerivative("bad type", DIRECTION::X, STAGGER::None, DERIV::Standard), BoutException); - store.reset(); } From f11a5782b501fd6f3f7d6aae4bd21c2652e21429 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 19 Feb 2019 17:19:50 +0000 Subject: [PATCH 0808/1783] Fix Timer initialisation for bug in C++11 This is actually a bug in the C++11 standard that was fixed in C++14. It was backported to some compilers even in -std=c++11 mode. But unfortunately, not GCC 4.x --- src/sys/timer.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/timer.cxx b/src/sys/timer.cxx index ba8f812111..e3a7d4fea2 100644 --- a/src/sys/timer.cxx +++ b/src/sys/timer.cxx @@ -3,12 +3,12 @@ using namespace std; -Timer::Timer() : timing{getInfo("")} { +Timer::Timer() : timing(getInfo("")) { timing.started = MPI_Wtime(); timing.running = true; } -Timer::Timer(const std::string& label) : timing{getInfo(label)} { +Timer::Timer(const std::string& label) : timing(getInfo(label)) { timing.started = MPI_Wtime(); timing.running = true; } From 4dfad0f3859753c9bb2d7442269cc52b705f26a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Wed, 20 Feb 2019 07:15:39 +0000 Subject: [PATCH 0809/1783] throw BoutException if we cannot change enum to string --- src/sys/bout_types.cxx | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index 8a5a1f675e..aabcb92ba8 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -1,13 +1,22 @@ -#include #include +#include #include +template +const std::string& saveat(const std::map& mymap, T t) { + auto found = mymap.find(t); + if (found == mymap.end()) { + throw BoutException("Did not find enum %d", static_cast(t)); + } + return found->second; +} + const std::string& CELL_LOC_STRING(CELL_LOC location) { const static std::map CELL_LOCtoString = { ENUMSTR(CELL_DEFAULT), ENUMSTR(CELL_CENTRE), ENUMSTR(CELL_XLOW), ENUMSTR(CELL_YLOW), ENUMSTR(CELL_ZLOW), ENUMSTR(CELL_VSHIFT)}; - return CELL_LOCtoString.at(location); + return saveat(CELL_LOCtoString, location); } const std::string& DIFF_METHOD_STRING(DIFF_METHOD location) { @@ -16,16 +25,14 @@ const std::string& DIFF_METHOD_STRING(DIFF_METHOD location) { {DIFF_C2, "C2"}, {DIFF_C4, "C4"}, {DIFF_S2, "S2"}, {DIFF_W2, "W2"}, {DIFF_W3, "W3"}, {DIFF_FFT, "FFT"}, {DIFF_SPLIT, "SPLIT"}}; - return DIFF_METHODtoString.at(location); + return saveat(DIFF_METHODtoString, location); } const std::string& REGION_STRING(REGION region) { - ASSERT2(region >= 0 && region <= 4); const static std::map REGIONtoString = { ENUMSTR(RGN_ALL), ENUMSTR(RGN_NOBNDRY), ENUMSTR(RGN_NOX), ENUMSTR(RGN_NOY), ENUMSTR(RGN_NOZ)}; - - return REGIONtoString.at(region); + return saveat(REGIONtoString, region); } const std::string& DIRECTION_STRING(DIRECTION direction) { @@ -36,7 +43,7 @@ const std::string& DIRECTION_STRING(DIRECTION direction) { {DIRECTION::YAligned, "Y - field aligned"}, {DIRECTION::YOrthogonal, "Y - orthogonal"}}; - return DIRECTIONtoString.at(direction); + return saveat(DIRECTIONtoString, direction); } const std::string& STAGGER_STRING(STAGGER stagger) { @@ -45,7 +52,7 @@ const std::string& STAGGER_STRING(STAGGER stagger) { {STAGGER::C2L, "Centre to Low"}, {STAGGER::L2C, "Low to Centre"}}; - return STAGGERtoString.at(stagger); + return saveat(STAGGERtoString, stagger); } const std::string& DERIV_STRING(DERIV deriv) { @@ -56,5 +63,5 @@ const std::string& DERIV_STRING(DERIV deriv) { {DERIV::Upwind, "Upwind"}, {DERIV::Flux, "Flux"}}; - return DERIVtoString.at(deriv); + return saveat(DERIVtoString, deriv); } From 75311c242e28f58bd49ff28182481d35d7891e59 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 20 Feb 2019 09:56:53 +0000 Subject: [PATCH 0810/1783] Fix DerivatireStoreTest initialisation for bug in C++11 This is actually a bug in the C++11 standard that was fixed in C++14. It was backported to some compilers even in -std=c++11 mode. But unfortunately, not GCC 4.x --- tests/unit/include/bout/test_deriv_store.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/include/bout/test_deriv_store.cxx b/tests/unit/include/bout/test_deriv_store.cxx index 9fc364e6a6..58688cd259 100644 --- a/tests/unit/include/bout/test_deriv_store.cxx +++ b/tests/unit/include/bout/test_deriv_store.cxx @@ -25,7 +25,7 @@ void flowReturnSixSetToTwo(const FieldType& UNUSED(vel), const FieldType& UNUSED class DerivativeStoreTest : public ::testing::Test { public: - DerivativeStoreTest() : store{DerivativeStore::getInstance()} {} + DerivativeStoreTest() : store(DerivativeStore::getInstance()) {} ~DerivativeStoreTest() { store.reset(); } DerivativeStore& store; From 7e3efca6f0aae91f93fe55863a456392ae1698e5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 20 Feb 2019 11:19:03 +0000 Subject: [PATCH 0811/1783] Compare Timer to std::chrono::high_resolution_clock in tests `std::this_thread::sleep_for(n)` sleeps for *at least* n seconds, and this may be significantly higher on systems with lots of resource contention (e.g. Travis!) --- tests/unit/sys/test_timer.cxx | 62 +++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/tests/unit/sys/test_timer.cxx b/tests/unit/sys/test_timer.cxx index 7f0a31d9e9..704206442f 100644 --- a/tests/unit/sys/test_timer.cxx +++ b/tests/unit/sys/test_timer.cxx @@ -11,18 +11,22 @@ using ms = std::chrono::duration; using seconds = std::chrono::duration; constexpr double TimerTolerance{1e-3}; constexpr auto sleep_length = ms(0.5); -constexpr auto sleep_length_seconds = seconds(sleep_length); } // namespace testing } // namespace bout TEST(TimerTest, GetTime) { using namespace bout::testing; + auto start = std::chrono::high_resolution_clock::now(); + Timer timer{}; std::this_thread::sleep_for(sleep_length); - EXPECT_NEAR(timer.getTime(), sleep_length_seconds.count(), TimerTolerance); + auto end = std::chrono::high_resolution_clock::now(); + seconds elapsed = end - start; + + EXPECT_NEAR(timer.getTime(), elapsed.count(), TimerTolerance); } TEST(TimerTest, GetUnknownTimeLabel) { @@ -32,37 +36,52 @@ TEST(TimerTest, GetUnknownTimeLabel) { TEST(TimerTest, GetTimeLabelInScope) { using namespace bout::testing; + auto start = std::chrono::high_resolution_clock::now(); + Timer timer{"GetTimeLabelInScope test"}; std::this_thread::sleep_for(sleep_length); - EXPECT_NEAR(Timer::getTime("GetTimeLabelInScope test"), sleep_length_seconds.count(), + auto end = std::chrono::high_resolution_clock::now(); + seconds elapsed = end - start; + + EXPECT_NEAR(Timer::getTime("GetTimeLabelInScope test"), elapsed.count(), TimerTolerance); } TEST(TimerTest, GetTimeLabelOutOfScope) { using namespace bout::testing; + auto start = std::chrono::high_resolution_clock::now(); + { Timer timer{"GetTimeLabelOutOfScope test"}; std::this_thread::sleep_for(sleep_length); } - EXPECT_NEAR(Timer::getTime("GetTimeLabelOutOfScope test"), sleep_length_seconds.count(), + auto end = std::chrono::high_resolution_clock::now(); + seconds elapsed = end - start; + + EXPECT_NEAR(Timer::getTime("GetTimeLabelOutOfScope test"), elapsed.count(), TimerTolerance); } TEST(TimerTest, GetTimeLabelRepeat) { using namespace bout::testing; + auto start = std::chrono::high_resolution_clock::now(); + { Timer timer{"GetTimeLabelRepeat test"}; std::this_thread::sleep_for(sleep_length); } - EXPECT_NEAR(Timer::getTime("GetTimeLabelRepeat test"), sleep_length_seconds.count(), + auto end = std::chrono::high_resolution_clock::now(); + seconds elapsed = end - start; + + EXPECT_NEAR(Timer::getTime("GetTimeLabelRepeat test"), elapsed.count(), TimerTolerance); { @@ -71,7 +90,10 @@ TEST(TimerTest, GetTimeLabelRepeat) { std::this_thread::sleep_for(sleep_length); } - EXPECT_NEAR(Timer::getTime("GetTimeLabelRepeat test"), 2 * sleep_length_seconds.count(), + auto end2 = std::chrono::high_resolution_clock::now(); + seconds elapsed2 = end2 - start; + + EXPECT_NEAR(Timer::getTime("GetTimeLabelRepeat test"), elapsed2.count(), TimerTolerance); } @@ -84,9 +106,14 @@ TEST(TimerTest, ResetTime) { timer.resetTime(); + auto start = std::chrono::high_resolution_clock::now(); + std::this_thread::sleep_for(sleep_length); - EXPECT_NEAR(timer.getTime(), sleep_length_seconds.count(), TimerTolerance); + auto end = std::chrono::high_resolution_clock::now(); + seconds elapsed = end - start; + + EXPECT_NEAR(timer.getTime(), elapsed.count(), TimerTolerance); } TEST(TimerTest, ResetTimeLabelInScope) { @@ -98,9 +125,14 @@ TEST(TimerTest, ResetTimeLabelInScope) { Timer::resetTime("ResetTimeLabelInScope test"); + auto start = std::chrono::high_resolution_clock::now(); + std::this_thread::sleep_for(sleep_length); - EXPECT_NEAR(Timer::getTime("ResetTimeLabelInScope test"), sleep_length_seconds.count(), + auto end = std::chrono::high_resolution_clock::now(); + seconds elapsed = end - start; + + EXPECT_NEAR(Timer::getTime("ResetTimeLabelInScope test"), elapsed.count(), TimerTolerance); } @@ -115,14 +147,19 @@ TEST(TimerTest, ResetTimeLabelOutOfScope) { Timer::resetTime("ResetTimeLabelOutOfScope test"); + auto start = std::chrono::high_resolution_clock::now(); + { Timer timer{"ResetTimeLabelOutOfScope test"}; std::this_thread::sleep_for(sleep_length); } + auto end = std::chrono::high_resolution_clock::now(); + seconds elapsed = end - start; + EXPECT_NEAR(Timer::getTime("ResetTimeLabelOutOfScope test"), - sleep_length_seconds.count(), TimerTolerance); + elapsed.count(), TimerTolerance); } TEST(TimerTest, Cleanup) { @@ -136,12 +173,17 @@ TEST(TimerTest, Cleanup) { Timer::cleanup(); + auto start = std::chrono::high_resolution_clock::now(); + { Timer timer{"Cleanup test"}; std::this_thread::sleep_for(sleep_length); } - EXPECT_NEAR(Timer::getTime("Cleanup test"), sleep_length_seconds.count(), + auto end = std::chrono::high_resolution_clock::now(); + seconds elapsed = end - start; + + EXPECT_NEAR(Timer::getTime("Cleanup test"), elapsed.count(), TimerTolerance); } From c82eb100030deb50c01bcf09b976d754d3505d3a Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Wed, 20 Feb 2019 14:36:03 +0000 Subject: [PATCH 0812/1783] Working version with current next --- src/bout++.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 255682ad6f..8f8832a458 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -509,7 +509,7 @@ int BoutInitialise(int &argc, char **&argv) { /// Add book-keeping variables to the output files bout::globals::dump.add(const_cast(BOUT_VERSION), "BOUT_VERSION", false); bout::globals::dump.add(simtime, "t_array", true); // Appends the time of dumps into an array - //run_data.outputVars(dump); // Add wall clock time etc to dump file + run_data.outputVars(bout::globals::dump); // Add wall clock time etc to dump file bout::globals::dump.add(iteration, "iteration", false); //////////////////////////////////////////// From b0e383075ea2407fa92665403750a57ae7b5b618 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 20 Feb 2019 14:55:05 +0000 Subject: [PATCH 0813/1783] Possibly set global mesh/options in FieldFactory constructor Also use default destructor --- include/field_factory.hxx | 4 ++-- src/field/field_factory.cxx | 11 +++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/include/field_factory.hxx b/include/field_factory.hxx index ff372d59fd..f38297e8eb 100644 --- a/include/field_factory.hxx +++ b/include/field_factory.hxx @@ -54,8 +54,8 @@ FieldGeneratorPtr generator(BoutReal *ptr); class FieldFactory : public ExpressionParser { public: - FieldFactory(Mesh *m, Options *opt = nullptr); - ~FieldFactory() override; + FieldFactory(Mesh* mesh = nullptr, Options* opt = nullptr); + ~FieldFactory() override = default; /// Create a 2D field by parsing a string and evaluating the expression /// using the given options \p opt, over Mesh \p m at time \p t. diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index a71e7f7ef6..e13c1376cf 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -46,10 +46,9 @@ FieldGeneratorPtr generator(BoutReal *ptr) { ////////////////////////////////////////////////////////// // FieldFactory public functions -FieldFactory::FieldFactory(Mesh * localmesh, Options *opt) : fieldmesh(localmesh), options(opt) { - - if (options == nullptr) - options = Options::getRoot(); +FieldFactory::FieldFactory(Mesh* localmesh, Options* opt) + : fieldmesh(localmesh == nullptr ? bout::globals::mesh : localmesh), + options(opt == nullptr ? Options::getRoot() : opt) { // Useful values addGenerator("pi", std::make_shared(PI)); @@ -95,10 +94,6 @@ FieldFactory::FieldFactory(Mesh * localmesh, Options *opt) : fieldmesh(localmesh std::make_shared(nullptr, nullptr, nullptr, nullptr)); } -FieldFactory::~FieldFactory() { - -} - const Field2D FieldFactory::create2D(const std::string& value, const Options* opt, Mesh* localmesh, CELL_LOC loc, BoutReal t) { return create2D(parse(value, opt), localmesh, loc, t); From 236dcd53a3fd06786acd08841f4f4c948e4933a5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 20 Feb 2019 14:56:17 +0000 Subject: [PATCH 0814/1783] Don't return const Fields from FieldFactory --- include/field_factory.hxx | 28 ++++++++++++++-------------- src/field/field_factory.cxx | 8 ++++---- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/field_factory.hxx b/include/field_factory.hxx index f38297e8eb..d5d14d2e0b 100644 --- a/include/field_factory.hxx +++ b/include/field_factory.hxx @@ -60,28 +60,28 @@ public: /// Create a 2D field by parsing a string and evaluating the expression /// using the given options \p opt, over Mesh \p m at time \p t. /// The resulting field is at cell location \p loc. - const Field2D create2D(const std::string &value, const Options *opt = nullptr, - Mesh *m = nullptr, CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); - + Field2D create2D(const std::string& value, const Options* opt = nullptr, + Mesh* m = nullptr, CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); + /// Create a 3D field by parsing a string and evaluating the expression /// using the given options \p opt, over Mesh \p m at time \p t. /// The resulting field is at cell location \p loc. - const Field3D create3D(const std::string &value, const Options *opt = nullptr, - Mesh *m = nullptr, CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); + Field3D create3D(const std::string& value, const Options* opt = nullptr, + Mesh* m = nullptr, CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); /// Parse a string into a tree of generators - FieldGeneratorPtr parse(const std::string &input, const Options *opt = nullptr); + FieldGeneratorPtr parse(const std::string& input, const Options* opt = nullptr); /// Create a 2D field from a generator, over a given mesh - /// at a given cell location and time. - const Field2D create2D(FieldGeneratorPtr generator, Mesh* m = nullptr, - CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); - + /// at a given cell location and time. + Field2D create2D(FieldGeneratorPtr generator, Mesh* m = nullptr, + CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); + /// Create a 3D field from a generator, over a given mesh - /// at a given cell location and time. - const Field3D create3D(FieldGeneratorPtr generator, Mesh* m = nullptr, - CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); - + /// at a given cell location and time. + Field3D create3D(FieldGeneratorPtr generator, Mesh* m = nullptr, + CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); + /// Get the Singleton object static FieldFactory* get(); diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index e13c1376cf..ab0a4389a0 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -94,12 +94,12 @@ FieldFactory::FieldFactory(Mesh* localmesh, Options* opt) std::make_shared(nullptr, nullptr, nullptr, nullptr)); } -const Field2D FieldFactory::create2D(const std::string& value, const Options* opt, +Field2D FieldFactory::create2D(const std::string& value, const Options* opt, Mesh* localmesh, CELL_LOC loc, BoutReal t) { return create2D(parse(value, opt), localmesh, loc, t); } -const Field2D FieldFactory::create2D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC loc, +Field2D FieldFactory::create2D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC loc, BoutReal t) { AUTO_TRACE(); @@ -152,13 +152,13 @@ const Field2D FieldFactory::create2D(FieldGeneratorPtr gen, Mesh* localmesh, CEL return result; } -const Field3D FieldFactory::create3D(const std::string &value, const Options *opt, +Field3D FieldFactory::create3D(const std::string &value, const Options *opt, Mesh *localmesh, CELL_LOC loc, BoutReal t) { return create3D(parse(value, opt), localmesh, loc, t); } -const Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC loc, +Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC loc, BoutReal t) { AUTO_TRACE(); From dab4f8ec7e1c9f5b72330542e714d21b53616447 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 20 Feb 2019 14:57:03 +0000 Subject: [PATCH 0815/1783] Clarify docstring for FieldFactory::options --- include/field_factory.hxx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/field_factory.hxx b/include/field_factory.hxx index d5d14d2e0b..d2ee10ffd4 100644 --- a/include/field_factory.hxx +++ b/include/field_factory.hxx @@ -93,8 +93,11 @@ protected: FieldGeneratorPtr resolve(std::string &name) override; private: - Mesh *fieldmesh; ///< The default mesh for create functions. - const Options *options; ///< Set in parse() and used in resolve() + /// The default mesh for create functions. + Mesh* fieldmesh; + /// The default options used in resolve(), can be overridden in + /// parse()/create2D()/create3D() + const Options* options; std::list lookup; // Names currently being parsed From 6c049a5aeb5c2bbcefc856feab613d0805dc0b00 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 20 Feb 2019 15:02:10 +0000 Subject: [PATCH 0816/1783] Simplify logic for checking FieldFactory has a valid mesh --- src/field/field_factory.cxx | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index ab0a4389a0..3ca4b15119 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -102,12 +102,14 @@ Field2D FieldFactory::create2D(const std::string& value, const Options* opt, Field2D FieldFactory::create2D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC loc, BoutReal t) { AUTO_TRACE(); - - if (localmesh == nullptr) + + if (localmesh == nullptr) { + if (fieldmesh == nullptr) { + throw BoutException("FieldFactory not created with mesh and no mesh passed in"); + } localmesh = fieldmesh; - if (localmesh == nullptr) - throw BoutException("Not a valid mesh"); - + } + if (!gen) { throw BoutException("Couldn't create 2D field from null generator"); } @@ -161,12 +163,14 @@ Field3D FieldFactory::create3D(const std::string &value, const Options *opt, Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC loc, BoutReal t) { AUTO_TRACE(); - - if(localmesh == nullptr) + + if (localmesh == nullptr) { + if (fieldmesh == nullptr) { + throw BoutException("FieldFactory not created with mesh and no mesh passed in"); + } localmesh = fieldmesh; - if(localmesh == nullptr) - throw BoutException("Not a valid mesh"); - + } + if (!gen) { throw BoutException("Couldn't create 3D field from null generator"); } From 59dedfaa424401cd3678a084a745f4179cef8db0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 17 Feb 2019 13:07:36 +0000 Subject: [PATCH 0817/1783] Use minimum of number of points in leg or core segments of separatrix Previously was using number of points in leg segment, could cause error if the number of points in the core segment happened to be less. --- tools/tokamak_grids/gridgen/create_nonorthogonal.pro | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index 998d45539c..2f8e2afd5a 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -1325,8 +1325,10 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ;; oplot, centerliner, centerlinez, thick=5 ;; stop - nflux_leg1 = n_elements(legsep.leg1[*,0]) - nflux_leg2 = n_elements(legsep.leg2[*,0]) + ;; set nflux_* here to the minimum of the number of points in the leg and core + ;; lines, because we need elements from both at each step when we loop below + nflux_leg1 = min([n_elements(legsep.leg1[*,0]), n_elements(legsep.core2[*,0])]) + nflux_leg2 = min([n_elements(legsep.leg2[*,0]), n_elements(legsep.core1[*,0])]) meanr1 = fltarr(nflux_leg1) meanz1 = fltarr(nflux_leg1) From 15094b03119f15bc5cea45db27b41d79fcb395cf Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 17 Feb 2019 13:09:01 +0000 Subject: [PATCH 0818/1783] Call create_nonorthogonal rather than create_grid if restarting If the grid creation needs to be restarted from create_nonorthogonal, it should restart the nonorthogonal procedure rather than the orthogonal one. --- tools/tokamak_grids/gridgen/create_nonorthogonal.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index 2f8e2afd5a..d18806a356 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -1558,7 +1558,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ new_settings = {psi_inner:psi_inner, psi_outer:(max(xpt_psi)+0.02), $ nrad:nrad, npol:settings.npol, $ rad_peaking:settings.rad_peaking, pol_peaking:settings.pol_peaking} - RETURN, create_grid(F, R, Z, new_settings, critical=critical, $ + RETURN, create_nonorthogonal(F, R, Z, new_settings, critical=critical, $ boundary=boundary, iter=iter+1, nrad_flexible=nrad_flexible, $ single_rad_grid=single_rad_grid, fast=fast, simple=simple) ENDIF From 4a97ae2f5873401aa2adf55507d5358db419bcc4 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 17 Feb 2019 13:10:30 +0000 Subject: [PATCH 0819/1783] Use xdist estimate rather than hard-coded 0.03 for X-point spacing --- tools/tokamak_grids/gridgen/create_nonorthogonal.pro | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index d18806a356..efdb2bf2ea 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -1794,7 +1794,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ poldist = line_dist(R, Z, (*pf_info[xpt]).ri0, (*pf_info[xpt]).zi0) ; Poloidal distance along line xdist = MAX(poldist) * 0.5 / FLOAT(npol[3*i]) ; Equal spacing - xpt_dist[xpt, 0] = 0.03 ;;xdist + xpt_dist[xpt, 0] = xdist ; SOL solid = (*pf_info[xpt]).sol[0] @@ -1804,8 +1804,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ xpt2 = (*sol_info[solid]).xpt2 - xpt_dist[xpt, 1] = 0.03 ;;xdist - xpt_dist[xpt2, 2] =0.03 ;;xdist + xpt_dist[xpt, 1] = xdist + xpt_dist[xpt2, 2] = xdist ; Second PF region xpt = xpt2 @@ -1813,7 +1813,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ poldist = line_dist(R, Z, (*pf_info[xpt]).ri0, (*pf_info[xpt]).zi0) xdist = MAX(poldist) * 0.5 / FLOAT(npol[3*i]) - xpt_dist[xpt, 3] = 0.03 ;;xdist + xpt_dist[xpt, 3] = xdist ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; From 5ab06a64640656bfd67a5a28979c0eb1516f295a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 17 Feb 2019 13:12:52 +0000 Subject: [PATCH 0820/1783] Fix normalization of unit vectors Length of z-component was calculated incorrectly because the original length of the vector was not stored, and the calculation for the z-component used the normalized r-component. --- .../gridgen/create_nonorthogonal.pro | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index efdb2bf2ea..d23e0f870a 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -1979,8 +1979,9 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ IF i EQ 0 THEN BEGIN vec_in_down_r = boundary[0,bndrycrossi+1] -boundary[0,bndrycrossi] vec_in_down_z = boundary[1,bndrycrossi+1] -boundary[1,bndrycrossi] - vec_in_down_r = vec_in_down_r / SQRT(vec_in_down_r^2 + vec_in_down_z^2) - vec_in_down_z = vec_in_down_z / SQRT(vec_in_down_r^2 + vec_in_down_z^2) + vec_length = SQRT(vec_in_down_r^2 + vec_in_down_z^2) + vec_in_down_r = vec_in_down_r / vec_length + vec_in_down_z = vec_in_down_z / vec_length vec_in_down1 = [vec_in_down_r, vec_in_down_z] vec_out_down1= -vec_in_down1 ;; [-1,1]/(SQRT(2.)) vec_in_up1 = TRANSPOSE(-vecpvt[0,*]) @@ -1989,8 +1990,9 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ENDIF ELSE BEGIN vec_in_down_r = boundary[0,bndrycrossi+1] -boundary[0,bndrycrossi] vec_in_down_z = boundary[1,bndrycrossi+1] -boundary[1,bndrycrossi] - vec_in_down_r = vec_in_down_r / SQRT(vec_in_down_r^2 + vec_in_down_z^2) - vec_in_down_z = vec_in_down_z / SQRT(vec_in_down_r^2 + vec_in_down_z^2) + vec_length = SQRT(vec_in_down_r^2 + vec_in_down_z^2) + vec_in_down_r = vec_in_down_r / vec_length + vec_in_down_z = vec_in_down_z / vec_length vec_in_down1 = [-1,0] ;;[vec_in_down_r, vec_in_down_z] vec_out_down1= -vec_in_down1 ;;[1,0] vec_in_up1 = TRANSPOSE(-vecpvt[i,*]) @@ -2181,8 +2183,9 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ IF i EQ 0 THEN BEGIN vec_in_up_r = boundary[0,bndrycrossi+1] -boundary[0,bndrycrossi] vec_in_up_z = boundary[1,bndrycrossi+1] -boundary[1,bndrycrossi] - vec_in_up_r = vec_in_up_r / SQRT(vec_in_up_r^2 + vec_in_up_z^2) - vec_in_up_z = vec_in_up_z / SQRT(vec_in_up_r^2 + vec_in_up_z^2) + veclength = SQRT(vec_in_up_r^2 + vec_in_up_z^2) + vec_in_up_r = vec_in_up_r / veclength + vec_in_up_z = vec_in_up_z / veclength vec_in_up3 = [vec_in_up_r, vec_in_down_z] vec_in_down3 = TRANSPOSE(-vecpvt[1,*]) vec_out_down3 = TRANSPOSE(vec1[1,*]) @@ -2195,8 +2198,9 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ vec_out_down3 = TRANSPOSE(vec1[0,*]) vec_in_up_r = boundary[0,bndrycrossi+1] -boundary[0,bndrycrossi] vec_in_up_z = boundary[1,bndrycrossi+1] -boundary[1,bndrycrossi] - vec_in_up_r = vec_in_up_r / SQRT(vec_in_up_r^2 + vec_in_up_z^2) - vec_in_up_z = vec_in_up_z / SQRT(vec_in_up_r^2 + vec_in_up_z^2) + veclength = SQRT(vec_in_up_r^2 + vec_in_up_z^2) + vec_in_up_r = vec_in_up_r / veclength + vec_in_up_z = vec_in_up_z / veclength vec_in_up3 = [vec_in_up_r, vec_in_up_z] ;; vec_in_up3 = [1,0] ;;TRANSPOSE(veccore[0,*]) From a47c9fdd51a8562e14759a1070a16aa46e99e062 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 17 Feb 2019 13:14:33 +0000 Subject: [PATCH 0821/1783] Add numbering to indicate where error messages came from --- tools/tokamak_grids/gridgen/create_nonorthogonal.pro | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index d23e0f870a..c6979d8a38 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -2037,7 +2037,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ IF (flast1 - faxis)/fnorm LT xpt_psi_max THEN BEGIN PRINT, "WARNING: Due to intersections with the boundary," - PRINT, " the SOL can't cover both x-points" + PRINT, " the SOL can't cover both x-points. (1)" IF KEYWORD_SET(strictbndry) THEN BEGIN PRINT, "** Switching off strict boundary" strictbndry = 0 @@ -2134,7 +2134,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ IF (flast2 - faxis)/fnorm LT xpt_psi_max THEN BEGIN PRINT, "WARNING: Due to intersections with the boundary," - PRINT, " the SOL can't cover both x-points" + PRINT, " the SOL can't cover both x-points. (2)" IF KEYWORD_SET(strictbndry) THEN BEGIN PRINT, "** Switching off strict boundary" strictbndry = 0 @@ -2245,7 +2245,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ IF (flast3 - faxis)/fnorm LT xpt_psi_max THEN BEGIN PRINT, "WARNING: Due to intersections with the boundary," - PRINT, " the SOL can't cover both x-points" + PRINT, " the SOL can't cover both x-points. (3)" IF KEYWORD_SET(strictbndry) THEN BEGIN PRINT, "** Switching off strict boundary" strictbndry = 0 From 27bc2a47531c868ef339a011e406438b30b4869f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 17 Feb 2019 13:17:28 +0000 Subject: [PATCH 0822/1783] Handle case where wall crossing of separatrix is in last segment of wall If the intersection point is in the last segment of the wall, after the last point in the 'boundary' array, then the index needs to be wrapped around to the beginning of the array. --- .../gridgen/create_nonorthogonal.pro | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index c6979d8a38..67f1eb8298 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -818,6 +818,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ strictbndry=0 + nboundary = N_ELEMENTS(boundary[0,*]) IF SIZE(nrad_flexible, /TYPE) EQ 0 THEN nrad_flexible = 0 @@ -904,6 +905,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ IF (N_ELEMENTS(s) NE 2) OR (s[0] NE 2) THEN BEGIN PRINT, "WARNING: boundary must be a 2D array: [2, n]. Ignoring" boundary = 0 + nboundary = 0 ENDIF ELSE BEGIN ; Calculate indices @@ -1977,8 +1979,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ bndcrosspos = line_crossings( boundary[0,*], boundary[1,*], 1, pvtfluxliner, pvtfluxlinez, 0, ncross=ncross, inds1=bndrycrossi) IF i EQ 0 THEN BEGIN - vec_in_down_r = boundary[0,bndrycrossi+1] -boundary[0,bndrycrossi] - vec_in_down_z = boundary[1,bndrycrossi+1] -boundary[1,bndrycrossi] + vec_in_down_r = boundary[0,(bndrycrossi+1) MOD nboundary] -boundary[0,bndrycrossi] + vec_in_down_z = boundary[1,(bndrycrossi+1) MOD nboundary] -boundary[1,bndrycrossi] vec_length = SQRT(vec_in_down_r^2 + vec_in_down_z^2) vec_in_down_r = vec_in_down_r / vec_length vec_in_down_z = vec_in_down_z / vec_length @@ -1988,8 +1990,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ vec_out_up1 = TRANSPOSE(vec2[0,*]) sp_loc = -1 ENDIF ELSE BEGIN - vec_in_down_r = boundary[0,bndrycrossi+1] -boundary[0,bndrycrossi] - vec_in_down_z = boundary[1,bndrycrossi+1] -boundary[1,bndrycrossi] + vec_in_down_r = boundary[0,(bndrycrossi+1) MOD nboundary] -boundary[0,bndrycrossi] + vec_in_down_z = boundary[1,(bndrycrossi+1) MOD nboundary] -boundary[1,bndrycrossi] vec_length = SQRT(vec_in_down_r^2 + vec_in_down_z^2) vec_in_down_r = vec_in_down_r / vec_length vec_in_down_z = vec_in_down_z / vec_length @@ -2181,8 +2183,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ vec_out_up3 = [1,0] ENDIF ELSE BEGIN IF i EQ 0 THEN BEGIN - vec_in_up_r = boundary[0,bndrycrossi+1] -boundary[0,bndrycrossi] - vec_in_up_z = boundary[1,bndrycrossi+1] -boundary[1,bndrycrossi] + vec_in_up_r = boundary[0,(bndrycrossi+1) MOD nboundary] -boundary[0,bndrycrossi] + vec_in_up_z = boundary[1,(bndrycrossi+1) MOD nboundary] -boundary[1,bndrycrossi] veclength = SQRT(vec_in_up_r^2 + vec_in_up_z^2) vec_in_up_r = vec_in_up_r / veclength vec_in_up_z = vec_in_up_z / veclength @@ -2196,8 +2198,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ IF i EQ 1 THEN BEGIN vec_in_down3 = TRANSPOSE(-vecpvt[0,*]) vec_out_down3 = TRANSPOSE(vec1[0,*]) - vec_in_up_r = boundary[0,bndrycrossi+1] -boundary[0,bndrycrossi] - vec_in_up_z = boundary[1,bndrycrossi+1] -boundary[1,bndrycrossi] + vec_in_up_r = boundary[0,(bndrycrossi+1) MOD nboundary] -boundary[0,bndrycrossi] + vec_in_up_z = boundary[1,(bndrycrossi+1) MOD nboundary] -boundary[1,bndrycrossi] veclength = SQRT(vec_in_up_r^2 + vec_in_up_z^2) vec_in_up_r = vec_in_up_r / veclength vec_in_up_z = vec_in_up_z / veclength From ee71d087b42512e644c7c5d803c89fa71f87304b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 17 Feb 2019 13:19:39 +0000 Subject: [PATCH 0823/1783] Fix wall intersection of second leg with one X-point The vector that is supposed to be parallel to the wall was hard-coded to [1,0] for the second wall intersection in the case with only one X-point. --- tools/tokamak_grids/gridgen/create_nonorthogonal.pro | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index 67f1eb8298..af4797b8b0 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -2176,11 +2176,18 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ bndcrosspos = line_crossings( boundary[0,*], boundary[1,*], 1,pvtfluxliner, pvtfluxlinez, 0, ncross=ncross, inds1=bndrycrossi) + ; vec_in_down3 and vec_out_down3 are unit vectors parallel to the boundaries of this section of the grid at the X-point + ; vec_in_up3 and vec_out_up3 are unit vectors parallel to the wall where the separatrix meets the wall IF critical.n_xpoint EQ 1 THEN BEGIN vec_in_down3 = TRANSPOSE(-vecpvt[0,*]) vec_out_down3 = TRANSPOSE(vec1[0,*]) - vec_in_up3 = [1,0] - vec_out_up3 = [1,0] + vec_in_up_r = boundary[0,(bndrycrossi+1) MOD nboundary] -boundary[0,bndrycrossi] + vec_in_up_z = boundary[1,(bndrycrossi+1) MOD nboundary] -boundary[1,bndrycrossi] + veclength = SQRT(vec_in_up_r^2 + vec_in_up_z^2) + vec_in_up_r = vec_in_up_r / veclength + vec_in_up_z = vec_in_up_z / veclength + vec_in_up3 = [vec_in_up_r, vec_in_up_z] + vec_out_up3 = vec_in_up3 ENDIF ELSE BEGIN IF i EQ 0 THEN BEGIN vec_in_up_r = boundary[0,(bndrycrossi+1) MOD nboundary] -boundary[0,bndrycrossi] From 09a0075365dfb9c92ac2c3c29c9437200b41bd6b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 17 Feb 2019 13:48:06 +0000 Subject: [PATCH 0824/1783] More comments for nonorthogonal grid generation --- .../gridgen/create_nonorthogonal.pro | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index af4797b8b0..9478633710 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -10,7 +10,8 @@ ; o Automatic default settings when not ; supplied. ; -; Author: Ben Dudson, University of York, Nov 2009 +; Author: Jarrod Leddy, Brendan Shanahan, Ben Dudson, University of York, +; 2015-2016 ; ; ; NOTE: Throughout, "F" means un-normalised psi, @@ -1963,6 +1964,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ypos = 0 rerun = 0 ; Flag. If 1 then have to re-run the grid generator FOR i=0, critical.n_xpoint-1 DO BEGIN + ; This section grids the first divertor leg associated with this X-point + pvtfluxliner = [R[(*pf_info[i]).ri0[N_ELEMENTS((*pf_info[i]).ri0)-1]], R[(*pf_info[i]).ri0[0]]] pvtfluxlinez = [Z[(*pf_info[i]).zi0[N_ELEMENTS((*pf_info[i]).zi0)-1]], Z[(*pf_info[i]).zi0[0]]] @@ -1978,6 +1981,13 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ bndcrosspos = line_crossings( boundary[0,*], boundary[1,*], 1, pvtfluxliner, pvtfluxlinez, 0, ncross=ncross, inds1=bndrycrossi) + ; vec_in_down1 and vec_out_down1 are a unit vector parallel to the wall + ; where the separatrix intersects the wall, it gives the angle of the + ; line where this section of grid begins. + ; vec_in_up1 is a unit vector along the line from the X-point into the + ; private flux region where this section of the grid ends + ; vec_out_up1 is a unit vector along the line from the X-point into the + ; SOL where this section of the grid ends IF i EQ 0 THEN BEGIN vec_in_down_r = boundary[0,(bndrycrossi+1) MOD nboundary] -boundary[0,bndrycrossi] vec_in_down_z = boundary[1,(bndrycrossi+1) MOD nboundary] -boundary[1,bndrycrossi] @@ -2069,6 +2079,9 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ rerun = 1 ; Signal that the grid needs to be rerun ENDIF + ; This part grids the region around the core, including SOL field lines + ; radially outside the core + ; SOL region solid = (*pf_info[xpt]).sol[0] @@ -2094,6 +2107,14 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ sep_line_up[1,*] = (*sep_info[xpt2]).core1_zi + ; vec_in_down2 is a unit vector along the line from the X-point into the + ; core where this section of the grid begins + ; vec_out_down2 is a unit vector along the line from the X-point into the + ; SOL where this section of the grid begins + ; vec_in_up2 is a unit vector along the line from the X-point into the + ; core where this section of the grid ends + ; vec_out_up2 is a unit vector along the line from the X-point into the + ; SOL where this section of the grid ends vec_in_down2 = TRANSPOSE(veccore[xpt,*]) vec_out_down2 = TRANSPOSE(vec2[xpt,*]) vec_in_up2 = TRANSPOSE(veccore[xpt2,*]) @@ -2158,7 +2179,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ vec_in_up1=[1,0] vec_out_up1=[1,0] END - ; Second PF region + ; This section grids the second divertor leg associated with this X-point xpt = (*sol_info[solid]).xpt2 pvtfluxliner = [R[(*pf_info[xpt]).ri1[N_ELEMENTS((*pf_info[xpt]).ri1)-1]], R[(*pf_info[xpt]).ri1[0]]] @@ -2176,8 +2197,13 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ bndcrosspos = line_crossings( boundary[0,*], boundary[1,*], 1,pvtfluxliner, pvtfluxlinez, 0, ncross=ncross, inds1=bndrycrossi) - ; vec_in_down3 and vec_out_down3 are unit vectors parallel to the boundaries of this section of the grid at the X-point - ; vec_in_up3 and vec_out_up3 are unit vectors parallel to the wall where the separatrix meets the wall + ; vec_in_down3 is a unit vector along the line from the X-point into the + ; private flux region where this section of the grid begins + ; vec_out_down3 is a unit vector along the line from the X-point into the + ; SOL where this section of the grid begins + ; vec_in_up3 and vec_out_up3 are a unit vector parallel to the wall + ; where the separatrix intersects the wall, it gives the angle of the + ; line where this section of grid ends. IF critical.n_xpoint EQ 1 THEN BEGIN vec_in_down3 = TRANSPOSE(-vecpvt[0,*]) vec_out_down3 = TRANSPOSE(vec1[0,*]) From a45c3e24bde4f446f778713023a67694126fdc42 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 18 Feb 2019 23:40:35 +0000 Subject: [PATCH 0825/1783] Hypnotoad: handle closed boundary contours Add first point on boundary to end so that contour is treated as closed. --- tools/tokamak_grids/gridgen/create_grid.pro | 5 +++-- tools/tokamak_grids/gridgen/create_nonorthogonal.pro | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_grid.pro b/tools/tokamak_grids/gridgen/create_grid.pro index aae915b10e..b15d7ec7fe 100644 --- a/tools/tokamak_grids/gridgen/create_grid.pro +++ b/tools/tokamak_grids/gridgen/create_grid.pro @@ -1125,16 +1125,17 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ opt_ri[primary_opt], opt_zi[primary_opt], boundary=bndryi) ; Go a little way along each core separatrix and follow + ; Note: add starting point to end of 'boundary' so we find intersections with a closed contour follow_gradient, interp_data, R, Z, $ legsep.core1[2,0], legsep.core1[2,1], $ 0.95 * f_cont + 0.05*opt_f[primary_opt], $ rhit, zhit, $ - boundary=TRANSPOSE([[start_ri], [start_zi]]), ibndry=hit_ind1 + boundary=TRANSPOSE([[start_ri, start_ri[0]], [start_zi, start_zi[0]]]), ibndry=hit_ind1 follow_gradient, interp_data, R, Z, $ legsep.core2[2,0], legsep.core2[2,1], $ 0.95 * f_cont + 0.05*opt_f[primary_opt], $ rhit, zhit, $ - boundary=TRANSPOSE([[start_ri], [start_zi]]), ibndry=hit_ind2 + boundary=TRANSPOSE([[start_ri, start_ri[0]], [start_zi, start_zi[0]]]), ibndry=hit_ind2 ni = N_ELEMENTS(start_ri) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index 9478633710..fcbf53ee34 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -1399,16 +1399,17 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ;; stop ; Go a little way along each core separatrix and follow + ; Note: add starting point to end of 'boundary' so we find intersections with a closed contour follow_gradient, interp_data, R, Z, $ legsep.core1[2,0], legsep.core1[2,1], $ 0.95 * f_cont + 0.05*opt_f[primary_opt], $ rhit, zhit, $ - boundary=TRANSPOSE([[start_ri], [start_zi]]), ibndry=hit_ind1 + boundary=TRANSPOSE([[start_ri, start_ri[0]], [start_zi, start_zi[0]]]), ibndry=hit_ind1 follow_gradient, interp_data, R, Z, $ legsep.core2[2,0], legsep.core2[2,1], $ 0.95 * f_cont + 0.05*opt_f[primary_opt], $ rhit, zhit, $ - boundary=TRANSPOSE([[start_ri], [start_zi]]), ibndry=hit_ind2 + boundary=TRANSPOSE([[start_ri, start_ri[0]], [start_zi, start_zi[0]]]), ibndry=hit_ind2 ni = N_ELEMENTS(start_ri) From eade7010196dc43ed378d449d99b209f17d2f51b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 18 Feb 2019 23:44:05 +0000 Subject: [PATCH 0826/1783] Hypnotoad: wrap around arrays before passing to DERIV DERIV is inaccurate at the first/last points where it uses one-sided differences. Wrapping around is not correct for open contours, but the ends of these should not be close to an X-point. --- tools/tokamak_grids/gridgen/leg_separatrix2.pro | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/tokamak_grids/gridgen/leg_separatrix2.pro b/tools/tokamak_grids/gridgen/leg_separatrix2.pro index d7b47f6de6..708190bc30 100644 --- a/tools/tokamak_grids/gridgen/leg_separatrix2.pro +++ b/tools/tokamak_grids/gridgen/leg_separatrix2.pro @@ -88,8 +88,16 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ IF KEYWORD_SET(debug) THEN oplot, [cri], [czi], psym=2 ;Get direction of line - drdi = INTERPOLATE(DERIV(sep_ri), inds[j]) - dzdi = INTERPOLATE(DERIV(sep_zi), inds[j]) + ; DERIV uses one-sided differences at the ends of the array. These may be + ; very inaccurate because the separatrix points are not evenly spaced. + ; Therefore extend the ends of the array by cycling around a couple of + ; points from the other end. This is incorrect for the leg contours, + ; which are open, but since they are open they should not have ends near + ; the X-point, so this should not affect them. + ; Need to add +2 to inds[j] because we added two points onto the + ; beginning of sep_ri/sep_zi. + drdi = INTERPOLATE(DERIV([sep_ri[-2:*],sep_ri,sep_ri[0:2]]), inds[j]+2) + dzdi = INTERPOLATE(DERIV([sep_zi[-2:*],sep_zi,sep_zi[0:2]]), inds[j]+2) ; First check if this is towards or away from the X-point dir = 1 ; direction to go away from x-point From 936c49b13f4b26685f5fb9aa0986cddfedc938ec Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 18 Feb 2019 23:49:05 +0000 Subject: [PATCH 0827/1783] Hypnotoad: handle case when found index is at end of array --- tools/tokamak_grids/gridgen/leg_separatrix2.pro | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/tokamak_grids/gridgen/leg_separatrix2.pro b/tools/tokamak_grids/gridgen/leg_separatrix2.pro index 708190bc30..a394da2055 100644 --- a/tools/tokamak_grids/gridgen/leg_separatrix2.pro +++ b/tools/tokamak_grids/gridgen/leg_separatrix2.pro @@ -121,7 +121,13 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ ; contour is closed, so we can loop around: start at si, add elements ; until the beginning of the contour, then add elements starting from the ; end of the contour - si = [si, reverse(indgen(in+1)), reverse(indgen(N_ELEMENTS(sep_ri)-in-1)) + in + 1] + IF in LT N_ELEMENTS(sep_ri)-1 THEN BEGIN + ; normal case + si = [si, reverse(indgen(in+1)), reverse(indgen(N_ELEMENTS(sep_ri)-in-1)) + in + 1] + ENDIF ELSE BEGIN + ; can't call indgen(0) so handle this specially + si = [si, reverse(indgen(in+1))] + ENDELSE ENDELSE sepri = INTERPOLATE(sep_ri, si) sepzi = INTERPOLATE(sep_zi, si) From fa27475af20883ba4be5d994a233564548da59b2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 18 Feb 2019 23:51:41 +0000 Subject: [PATCH 0828/1783] Hypnotoad follow separatrix further from X-point When following lines along separatrix away from the X-point, continue until both R and Z have reached an extremum. This should take the line at least a quarter and at most half way around a closed contour. The previous behaviour risked stopping after a very short distance if the X-point was not at the top or bottom of the contour. --- tools/tokamak_grids/gridgen/leg_separatrix2.pro | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/tokamak_grids/gridgen/leg_separatrix2.pro b/tools/tokamak_grids/gridgen/leg_separatrix2.pro index a394da2055..eb98bfe351 100644 --- a/tools/tokamak_grids/gridgen/leg_separatrix2.pro +++ b/tools/tokamak_grids/gridgen/leg_separatrix2.pro @@ -140,13 +140,21 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ IF d GT 0 THEN BEGIN ; Core - ; find where either ri or zi has an extrema + ; Find where both ri and zi have had an extrema. + ; This will take the contour at most half way around the closed part of + ; the separatrix. + ; Taking the first extremum in ri or zi (old behaviour) risks having a + ; very short contour on one leg if the X-point is not quite at the + ; bottom or top of the core region n = N_ELEMENTS(sepri) dr = DERIV(sepri) dr = dr[1:*] * dr[0:(n-2)] dz = DERIV(sepzi) dz = dz[1:*] * dz[0:(n-2)] - in = MIN(WHERE((dr[1:*] LE 0.0) OR (dz[1:*] LE 0.0))) + 1 + + inr = MIN(WHERE(dr[1:*] LE 0.0)) + 1 + inz = MIN(WHERE(dz[1:*] LE 0.0)) + 1 + in = MAX([inr, inz]) if in GT 0 THEN BEGIN ; if in<=0 then there is no extremum, so don't truncate sepri/sepzi From c078abcd450878946596c9a0b1c3ebf20f7204be Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 19 Feb 2019 12:27:34 +0000 Subject: [PATCH 0829/1783] Increase npt to 30: make yup_dist calculation consistent with ydown_dist --- tools/tokamak_grids/gridgen/create_grid.pro | 2 +- tools/tokamak_grids/gridgen/create_nonorthogonal.pro | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_grid.pro b/tools/tokamak_grids/gridgen/create_grid.pro index b15d7ec7fe..f19da18fe9 100644 --- a/tools/tokamak_grids/gridgen/create_grid.pro +++ b/tools/tokamak_grids/gridgen/create_grid.pro @@ -1614,7 +1614,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ line = get_line(interp_data, R, Z, $ INTERPOLATE((*sep_info[xpt2]).core1_ri, sepi), $ INTERPOLATE((*sep_info[xpt2]).core1_zi, sepi), $ - 0.95*f_cont + 0.05*faxis, npt=20) + 0.95*f_cont + 0.05*faxis, npt=30) ; Find intersection of this line with starting line cpos = line_crossings((*sol_info[solid]).ri, (*sol_info[solid]).zi, 0, $ line[*,0], line[*,1], 0, ncross=ncross, inds1=start_ind) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index fcbf53ee34..d55173b2bb 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -1902,7 +1902,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ line = get_line_nonorth(interp_data, R, Z, $ INTERPOLATE((*sep_info[xpt2]).core1_ri, sepi), $ INTERPOLATE((*sep_info[xpt2]).core1_zi, sepi), $ - 0.95*f_cont + 0.05*faxis, npt=20, $ + 0.95*f_cont + 0.05*faxis, npt=30, $ vec=vec_in_up2, weight=1) OPLOT, INTERPOLATE(R, line[*,0]), INTERPOLATE(Z, line[*,1]), $ From 7a3ee4bfee7bd08f7ab8e0b2c3830a8265d39abb Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 19 Feb 2019 15:06:38 +0000 Subject: [PATCH 0830/1783] Hypnotoad: make line_dist more robust Finding distance by integrating index derivatives along contours is not accurate, as the contour points may be very unevenly spaced. The algorithm from poloidal_grid which directly adds up the distance between grid points is more robust: this commit copies that algorithm to line_dist. --- tools/tokamak_grids/gridgen/create_grid.pro | 22 +++++++++++++++---- .../gridgen/create_nonorthogonal.pro | 22 +++++++++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_grid.pro b/tools/tokamak_grids/gridgen/create_grid.pro index f19da18fe9..e1c340d6a4 100644 --- a/tools/tokamak_grids/gridgen/create_grid.pro +++ b/tools/tokamak_grids/gridgen/create_grid.pro @@ -386,10 +386,24 @@ PRO oplot_line, interp_data, R, Z, ri0, zi0, fto, npt=npt, color=color, _extra=_ END FUNCTION line_dist, R, Z, ri, zi - drdi = DERIV(INTERPOLATE(R, ri)) - dzdi = DERIV(INTERPOLATE(Z, zi)) - dldi = SQRT(drdi^2 + dzdi^2) - RETURN, int_func(findgen(N_ELEMENTS(dldi)), dldi, /simple) + IF 0 THEN BEGIN + ; derivatives drdi and dzdi may be very inaccurate because the contour + ; given by ri and zi is not necessarily uniformly spaced, it may not even + ; have a smoothly varying grid spacing. Therefore don't use this branch + drdi = DERIV(INTERPOLATE(R, ri)) + dzdi = DERIV(INTERPOLATE(Z, zi)) + dldi = SQRT(drdi^2 + dzdi^2) + RETURN, int_func(findgen(N_ELEMENTS(dldi)), dldi, /simple) + ENDIF ELSE BEGIN + np = N_ELEMENTS(ri) + rpos = INTERPOLATE(R, ri) + zpos = INTERPOLATE(Z, zi) + dd = SQRT((zpos[1:*] - zpos[0:(np-2)])^2 + (rpos[1:*] - rpos[0:(np-2)])^2) + dd = [dd, SQRT((zpos[0] - zpos[np-1])^2 + (rpos[0] - rpos[np-1])^2)] + result = FLTARR(np) + FOR i=1,np-1 DO result[i] = result[i-1] + dd[i-1] + RETURN, result + ENDELSE END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index d55173b2bb..c26b5e1624 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -566,10 +566,24 @@ PRO oplot_line, interp_data, R, Z, ri0, zi0, fto, npt=npt, color=color, _extra=_ END FUNCTION line_dist, R, Z, ri, zi - drdi = DERIV(INTERPOLATE(R, ri)) - dzdi = DERIV(INTERPOLATE(Z, zi)) - dldi = SQRT(drdi^2 + dzdi^2) - RETURN, int_func(findgen(N_ELEMENTS(dldi)), dldi, /simple) + IF 0 THEN BEGIN + ; derivatives drdi and dzdi may be very inaccurate because the contour + ; given by ri and zi is not necessarily uniformly spaced, it may not even + ; have a smoothly varying grid spacing. Therefore don't use this branch + drdi = DERIV(INTERPOLATE(R, ri)) + dzdi = DERIV(INTERPOLATE(Z, zi)) + dldi = SQRT(drdi^2 + dzdi^2) + RETURN, int_func(findgen(N_ELEMENTS(dldi)), dldi, /simple) + ENDIF ELSE BEGIN + np = N_ELEMENTS(ri) + rpos = INTERPOLATE(R, ri) + zpos = INTERPOLATE(Z, zi) + dd = SQRT((zpos[1:*] - zpos[0:(np-2)])^2 + (rpos[1:*] - rpos[0:(np-2)])^2) + dd = [dd, SQRT((zpos[0] - zpos[np-1])^2 + (rpos[0] - rpos[np-1])^2)] + result = FLTARR(np) + FOR i=1,np-1 DO result[i] = result[i-1] + dd[i-1] + RETURN, result + ENDELSE END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; From 9764aa428901ec380f9ab04c1cb282efc4f67033 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 19 Feb 2019 15:14:08 +0000 Subject: [PATCH 0831/1783] Hypnotoad: use INTERPOLATE instead of fft_interp on contours Using INTERPOLATE is consistent with how contours are treated elsewhere, which can prevent errors (for example the projected poloidal location of the X-point being slightly different when calculated when fft_interp or INTERPOLATE is used to find the starting position, leading to a position being found on the wrong side of the X-point). Also, fft_interp is likely to be inaccurate on contours, as their points can be very unevenly spaced. INTERPOLATE uses linear interpolation which is more robust. --- tools/tokamak_grids/gridgen/create_grid.pro | 31 +++++++++---------- .../gridgen/create_nonorthogonal.pro | 31 +++++++++---------- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_grid.pro b/tools/tokamak_grids/gridgen/create_grid.pro index e1c340d6a4..bc3c10c397 100644 --- a/tools/tokamak_grids/gridgen/create_grid.pro +++ b/tools/tokamak_grids/gridgen/create_grid.pro @@ -1124,9 +1124,6 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; now have (start_ri, start_zi). For each x-point, find the radial ; line going through the x-point - fri = FFT(start_ri) ; for interpolating periodic functions - fzi = FFT(start_zi) - xpt_ind = FLTARR(critical.n_xpoint) ; index into start_*i pf_info = PTRARR(critical.n_xpoint) ; Pointers to PF for each X-point @@ -1196,9 +1193,9 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; Plot the line to the x-point oplot_line, interp_data, R, Z, $ - fft_interp(fri, mini), fft_interp(fzi, mini), critical.xpt_f[i] + INTERPOLATE(start_ri, mini), INTERPOLATE(start_zi, mini), critical.xpt_f[i] oplot_line, interp_data, R, Z, $ - fft_interp(fri, mini), fft_interp(fzi, mini), f_inner + INTERPOLATE(start_ri, mini), INTERPOLATE(start_zi, mini), f_inner ; Get tangent vector drdi = INTERPOLATE((DERIV(INTERPOLATE(R, start_ri))), mini) @@ -1217,34 +1214,34 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ sol_info = PTRARR(critical.n_xpoint) FOR i=0, critical.n_xpoint-1 DO BEGIN IF i NE (critical.n_xpoint-1) THEN BEGIN - ri = [ fft_interp(fri,xpt_ind[ci[i]]), $ + ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]]), $ start_ri[FIX(xpt_ind[ci[i]]+1.0):FIX(xpt_ind[ci[i+1]])], $ - fft_interp(fri,xpt_ind[ci[i+1]]) ] + INTERPOLATE(start_ri,xpt_ind[ci[i+1]]) ] - zi = [ fft_interp(fzi,xpt_ind[ci[i]]), $ + zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]]), $ start_zi[FIX(xpt_ind[ci[i]]+1.0):FIX(xpt_ind[ci[i+1]])], $ - fft_interp(fzi,xpt_ind[ci[i+1]]) ] + INTERPOLATE(start_zi,xpt_ind[ci[i+1]]) ] ENDIF ELSE BEGIN ; Index wraps around IF xpt_ind[ci[i]] GT N_ELEMENTS(start_ri)-2 THEN BEGIN - ri = [ fft_interp(fri,xpt_ind[ci[i]]), $ + ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]]), $ start_ri[0:FIX(xpt_ind[ci[0]])], $ - fft_interp(fri,xpt_ind[ci[0]]) ] + INTERPOLATE(start_ri,xpt_ind[ci[0]]) ] - zi = [ fft_interp(fzi,xpt_ind[ci[i]]), $ + zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]]), $ start_zi[0:FIX(xpt_ind[ci[0]])], $ - fft_interp(fzi,xpt_ind[ci[0]]) ] + INTERPOLATE(start_zi,xpt_ind[ci[0]]) ] ENDIF ELSE BEGIN - ri = [ fft_interp(fri,xpt_ind[ci[i]]), $ + ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]]), $ start_ri[FIX(xpt_ind[ci[i]]+1.0):*], $ start_ri[0:FIX(xpt_ind[ci[0]])], $ - fft_interp(fri,xpt_ind[ci[0]]) ] + INTERPOLATE(start_ri,xpt_ind[ci[0]]) ] - zi = [ fft_interp(fzi,xpt_ind[ci[i]]), $ + zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]]), $ start_zi[FIX(xpt_ind[ci[i]]+1.0):*], $ start_zi[0:FIX(xpt_ind[ci[0]])], $ - fft_interp(fzi,xpt_ind[ci[0]]) ] + INTERPOLATE(start_zi,xpt_ind[ci[0]]) ] ENDELSE ENDELSE diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index c26b5e1624..0cd05b7a17 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -1318,9 +1318,6 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; now have (start_ri, start_zi). For each x-point, find the radial ; line going through the x-point - fri = FFT(start_ri) ; for interpolating periodic functions - fzi = FFT(start_zi) - xpt_ind = FLTARR(critical.n_xpoint) ; index into start_*i pf_info = PTRARR(critical.n_xpoint) @@ -1484,9 +1481,9 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; Plot the line to the x-point oplot_line, interp_data, R, Z, $ - fft_interp(fri, mini), fft_interp(fzi, mini), critical.xpt_f[i], color=125 + INTERPOLATE(start_ri, mini), INTERPOLATE(start_zi, mini), critical.xpt_f[i], color=125 oplot_line, interp_data, R, Z, $ - fft_interp(fri, mini), fft_interp(fzi, mini), f_inner, color=125 + INTERPOLATE(start_ri, mini), INTERPOLATE(start_zi, mini), f_inner, color=125 ; Get tangent vector @@ -1506,34 +1503,34 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ sol_info = PTRARR(critical.n_xpoint) FOR i=0, critical.n_xpoint-1 DO BEGIN IF i NE (critical.n_xpoint-1) THEN BEGIN - ri = [ fft_interp(fri,xpt_ind[ci[i]]), $ + ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]]), $ start_ri[FIX(xpt_ind[ci[i]]+1.0):FIX(xpt_ind[ci[i+1]])], $ - fft_interp(fri,xpt_ind[ci[i+1]]) ] + INTERPOLATE(start_ri,xpt_ind[ci[i+1]]) ] - zi = [ fft_interp(fzi,xpt_ind[ci[i]]), $ + zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]]), $ start_zi[FIX(xpt_ind[ci[i]]+1.0):FIX(xpt_ind[ci[i+1]])], $ - fft_interp(fzi,xpt_ind[ci[i+1]]) ] + INTERPOLATE(start_zi,xpt_ind[ci[i+1]]) ] ENDIF ELSE BEGIN ; Index wraps around IF xpt_ind[ci[i]] GT N_ELEMENTS(start_ri)-2 THEN BEGIN - ri = [ fft_interp(fri,xpt_ind[ci[i]]), $ + ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]]), $ start_ri[0:FIX(xpt_ind[ci[0]])], $ - fft_interp(fri,xpt_ind[ci[0]]) ] + INTERPOLATE(start_ri,xpt_ind[ci[0]]) ] - zi = [ fft_interp(fzi,xpt_ind[ci[i]]), $ + zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]]), $ start_zi[0:FIX(xpt_ind[ci[0]])], $ - fft_interp(fzi,xpt_ind[ci[0]]) ] + INTERPOLATE(start_zi,xpt_ind[ci[0]]) ] ENDIF ELSE BEGIN - ri = [ fft_interp(fri,xpt_ind[ci[i]]), $ + ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]]), $ start_ri[FIX(xpt_ind[ci[i]]+1.0):*], $ start_ri[0:FIX(xpt_ind[ci[0]])], $ - fft_interp(fri,xpt_ind[ci[0]]) ] + INTERPOLATE(start_ri,xpt_ind[ci[0]]) ] - zi = [ fft_interp(fzi,xpt_ind[ci[i]]), $ + zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]]), $ start_zi[FIX(xpt_ind[ci[i]]+1.0):*], $ start_zi[0:FIX(xpt_ind[ci[0]])], $ - fft_interp(fzi,xpt_ind[ci[0]]) ] + INTERPOLATE(start_zi,xpt_ind[ci[0]]) ] ENDELSE ENDELSE From 185ab4bf2365b726612285cfbd063504563823ac Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 19 Feb 2019 23:41:20 +0000 Subject: [PATCH 0832/1783] Hypnotoad: rename function to radial_differential_nonorth Function is defined in follow_gradient_nonorth.pro Previously was radial_differential, which is a name conflict with the function defined in follow_gradient.pro, and caused Hypnotoad to crash when re-running non-orthogonal grid generation. --- tools/tokamak_grids/gridgen/follow_gradient_nonorth.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/tokamak_grids/gridgen/follow_gradient_nonorth.pro b/tools/tokamak_grids/gridgen/follow_gradient_nonorth.pro index 0b98d50a79..c9504b352e 100644 --- a/tools/tokamak_grids/gridgen/follow_gradient_nonorth.pro +++ b/tools/tokamak_grids/gridgen/follow_gradient_nonorth.pro @@ -5,7 +5,7 @@ ; Calculate dR/df and dZ/df for use by LSODE ; Input: pos[0] = R, pos[1] = Z ; Output [0] = dR/df = -Bz/B^2 , [1] = dZ/df = Br/B^2 -FUNCTION radial_differential, fcur, pos +FUNCTION radial_differential_nonorth, fcur, pos COMMON rd_com_no, idata, lastgoodf, lastgoodpos, R, Z, ood, boundary, ri0, zi0, tol, vec, weightc, bndry_periodic local_gradient, idata, pos[0], pos[1], status=status, dfdr=dfdr, dfdz=dfdz @@ -120,7 +120,7 @@ PRO follow_gradient_nonorth, interp_data, R, Z, ri0, zi0, ftarget, ri, zi, statu rzold = [ri0, zi0] rcount = 0 REPEAT BEGIN - rznew = LSODE(rzold,f0,ftarget - f0,'radial_differential', lstat) + rznew = LSODE(rzold,f0,ftarget - f0,'radial_differential_nonorth', lstat) IF lstat EQ -1 THEN BEGIN PRINT, " -> Excessive work "+STR(f0)+" to "+STR(ftarget)+" Trying to continue..." lstat = 2 ; continue From d756f6038f4da2470f5f49c93ee9b358dc9db96c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 19 Feb 2019 17:59:31 +0000 Subject: [PATCH 0833/1783] Hypnotoad: more flexible transitions in nonorthogonal grid generation Previously, the nonorthogonal grid generator changed the radial grid direction from the boundary vector at one end of a region, to the normal to flux surfaces half way through the region, and then to the other boundary vector at the far end of the region. This could cause issues, for example if the line normal to the flux surfaces half way through the region intersects with one of the region boundaries. Instead, use both vectors with separate weights. The weights are now set to decay with the power 2.7 instead of 1.35, because the parameter under the power now increases/decreases half as quickly (but extends the full length of the region, not just half). --- .../gridgen/create_nonorthogonal.pro | 54 +++++++++++-------- .../gridgen/follow_gradient_nonorth.pro | 45 +++++++++++----- .../gridgen/get_line_nonorth.pro | 7 ++- 3 files changed, 70 insertions(+), 36 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index 0cd05b7a17..98e1d8c96b 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -351,9 +351,6 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ FOR i=0, npar-1 DO BEGIN IF i GE npar/2 THEN BEGIN - IF KEYWORD_SET(vec_in_up) THEN vec_in = vec_in_up - IF KEYWORD_SET(vec_out_up) THEN vec_out = vec_out_up - IF KEYWORD_SET(sep_up) THEN BEGIN sep = sep_up ENDIF ELSE sep = fvals[nin] @@ -363,13 +360,8 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ INTERPOLATE(Z, REFORM(sep_line_up[1,*])), $ thick=2,color=3 ENDIF ELSE sep_line = FLTARR(2,2) - IF NOT KEYWORD_SET(orthup) THEN orthup=0 - IF orthup EQ 1 THEN weight = 0 ELSE weight = ((2.*i/(npar-1))-1)^1.35 ENDIF ELSE BEGIN ; PRINT, "***** DOWN *****" - IF KEYWORD_SET(vec_in_down) THEN vec_in = vec_in_down - IF KEYWORD_SET(vec_out_down) THEN vec_out = vec_out_down - IF KEYWORD_SET(sep_down) THEN BEGIN sep = sep_down ENDIF ELSE sep = fvals[nin] @@ -380,9 +372,13 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ INTERPOLATE(Z, REFORM(sep_line_down[1,*])), $ thick=2,color=2 ENDIF ELSE sep_line = FLTARR(2,2) - IF NOT KEYWORD_SET(orthdown) THEN orthdown=0 - IF orthdown EQ 1 THEN weight = 0 ELSE weight = (1-(2.*i)/(npar-1))^1.35 ENDELSE + + IF NOT KEYWORD_SET(orthup) THEN orthup=0 + IF orthup EQ 1 THEN weight_up = 0 ELSE weight_up = (i/(npar-1.))^2.7 + + IF NOT KEYWORD_SET(orthdown) THEN orthdown=0 + IF orthdown EQ 1 THEN weight_down = 0 ELSE weight_down = (1.-i/(npar-1.))^2.7 ; Refine the location of the starting point ; follow_gradient_nonorth, interp_data, R, Z, rii[i], zii[i], f0, ri1, zi1, vec=vec_in, weight=weight @@ -397,7 +393,8 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ftarg = fvals[nin] follow_gradient_nonorth, interp_data, R, Z, rii[i], zii[i], $ ftarg, rinext, zinext, status=status, $ - vec=vec_in, weight=weight + vec_up=vec_in_up, weight_up=weight_up, $ + vec_down=vec_in_down, weight_down=weight_down rixy[nin, i] = rinext zixy[nin, i] = zinext ENDELSE @@ -409,7 +406,9 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ; PRINT, "FOLLOWING INNER i, j = ", i, j follow_gradient_nonorth, interp_data, R, Z, rixy[nin+j, i], zixy[nin+j, i], $ sep, rinext, zinext, status=status, $ - boundary=sep_line, fbndry=fbndry, vec=vec_in, weight=weight, /bndry_noperiodic + boundary=sep_line, fbndry=fbndry, $ + vec_up=vec_in_up, weight_up=weight_up, $ + vec_down=vec_in_down, weight_down=weight_down, /bndry_noperiodic ; If hits the separatrix, should now continue from ; the separatrix line OPLOT, [INTERPOLATE(R, rinext)], [INTERPOLATE(Z, zinext)], psym=4, color=5 @@ -417,18 +416,24 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ; PRINT, "FOLLOWING OUTER" follow_gradient_nonorth, interp_data, R, Z, rinext, zinext, $ ftarg, rinext, zinext, status=status, $ - boundary=boundary, fbndry=fbndry, vec=vec_out, weight=weight + boundary=boundary, fbndry=fbndry, $ + vec_up=vec_out_up, weight_up=weight_up, $ + vec_down=vec_out_down, weight_down=weight_down ENDIF ELSE BEGIN IF fvals[nin+j] GT sep THEN BEGIN - vec = vec_out + vec_down = vec_out_down + vec_up = vec_out_up ENDIF ELSE BEGIN - vec = vec_in + vec_down = vec_in_down + vec_up = vec_in_up ENDELSE follow_gradient_nonorth, interp_data, R, Z, rixy[nin+j, i], zixy[nin+j, i], $ ftarg, rinext, zinext, status=status, $ - boundary=boundary, fbndry=fbndry, vec=vec, weight=weight + boundary=boundary, fbndry=fbndry, $ + vec_up=vec_up, weight_up=weight_up, $ + vec_down=vec_down, weight_down=weight_down ENDELSE IF status EQ 1 THEN BEGIN @@ -453,15 +458,18 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ftarg = fvals[nin-j-1] IF ftarg GT sep THEN BEGIN - vec = vec_out + vec_down = vec_out_down + vec_up = vec_out_up ENDIF ELSE BEGIN - vec = vec_in + vec_down = vec_in_down + vec_up = vec_in_up ENDELSE follow_gradient_nonorth, interp_data, R, Z, rixy[nin-j, i], zixy[nin-j, i], $ ftarg, rinext, zinext, status=status, $ boundary=boundary, fbndry=fbndry, $ - vec=vec, weight=weight + vec_up=vec_up, weight_up=weight_up, $ + vec_down=vec_down, weight_down=weight_down IF status EQ 1 THEN BEGIN rixy[nin-j-1, i] = -1.0 @@ -520,7 +528,9 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ENDIF ENDIF ELSE BEGIN ; Probably not near an X-point. Follow gradient to refine location - follow_gradient_nonorth, interp_data, R, Z, rixy[nin,i], zixy[nin,i], f0, ri1, zi1, vec=vec_in, weight=weight + follow_gradient_nonorth, interp_data, R, Z, rixy[nin,i], zixy[nin,i], f0, ri1, zi1, $ + vec_up=vec_in_up, weight_up=weight_up, $ + vec_down=vec_in_down, weight_down=weight_down rixy[nin,i] = ri1 zixy[nin,i] = zi1 ENDELSE @@ -1882,7 +1892,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ line = get_line_nonorth(interp_data, R, Z, $ INTERPOLATE((*sep_info[xpt]).core2_ri, sepi), $ INTERPOLATE((*sep_info[xpt]).core2_zi, sepi), $ - 0.95*f_cont + 0.05*faxis, npt=30, vec=vec_in_down2, weight=1) + 0.95*f_cont + 0.05*faxis, npt=30, vec_down=vec_in_down2, weight_down=1) OPLOT, INTERPOLATE(R, line[*,0]), INTERPOLATE(Z, line[*,1]), $ color=4, _extra=_extra @@ -1914,7 +1924,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ INTERPOLATE((*sep_info[xpt2]).core1_ri, sepi), $ INTERPOLATE((*sep_info[xpt2]).core1_zi, sepi), $ 0.95*f_cont + 0.05*faxis, npt=30, $ - vec=vec_in_up2, weight=1) + vec_up=vec_in_up2, weight_up=1) OPLOT, INTERPOLATE(R, line[*,0]), INTERPOLATE(Z, line[*,1]), $ color=2, _extra=_extra diff --git a/tools/tokamak_grids/gridgen/follow_gradient_nonorth.pro b/tools/tokamak_grids/gridgen/follow_gradient_nonorth.pro index c9504b352e..8dc1594322 100644 --- a/tools/tokamak_grids/gridgen/follow_gradient_nonorth.pro +++ b/tools/tokamak_grids/gridgen/follow_gradient_nonorth.pro @@ -6,7 +6,7 @@ ; Input: pos[0] = R, pos[1] = Z ; Output [0] = dR/df = -Bz/B^2 , [1] = dZ/df = Br/B^2 FUNCTION radial_differential_nonorth, fcur, pos - COMMON rd_com_no, idata, lastgoodf, lastgoodpos, R, Z, ood, boundary, ri0, zi0, tol, vec, weightc, bndry_periodic + COMMON rd_com_no, idata, lastgoodf, lastgoodpos, R, Z, ood, boundary, ri0, zi0, tol, vec_comm_up, weightc_up, vec_comm_down, weightc_down, bndry_periodic local_gradient, idata, pos[0], pos[1], status=status, dfdr=dfdr, dfdz=dfdz @@ -44,12 +44,22 @@ FUNCTION radial_differential_nonorth, fcur, pos Bz = -dfdr/dRdi B2 = Br^2 + Bz^2 - IF KEYWORD_SET(vec) THEN BEGIN + IF KEYWORD_SET(vec_comm_up) AND KEYWORD_SET(vec_comm_down) THEN BEGIN ;; V*mod(R)/mod(V) w + (1-w) vec(r) - newvec = vec * SQRT((-Bz/B2/dRdi)^2 + (Br/B2/dZdi)^2) * weightc + (1-weightc)*[-Bz/B2/dRdi, Br/B2/dZdi] + newvec = vec_comm_up * SQRT((-Bz/B2/dRdi)^2 + (Br/B2/dZdi)^2) * weightc_up $ + + vec_comm_down * SQRT((-Bz/B2/dRdi)^2 + (Br/B2/dZdi)^2) * weightc_down $ + + (1-weightc_up-weightc_down)*[-Bz/B2/dRdi, Br/B2/dZdi] RETURN, newvec ;;RETURN, [-Bz/B2/dRdi, Br/B2/dZdi] + ENDIF ELSE IF KEYWORD_SET(vec_comm_up) THEN BEGIN + newvec = vec_comm_up * SQRT((-Bz/B2/dRdi)^2 + (Br/B2/dZdi)^2) * weightc_up $ + + (1-weightc_up)*[-Bz/B2/dRdi, Br/B2/dZdi] + RETURN, newvec + ENDIF ELSE IF KEYWORD_SET(vec_comm_down) THEN BEGIN + newvec = vec_comm_down * SQRT((-Bz/B2/dRdi)^2 + (Br/B2/dZdi)^2) * weightc_down $ + + (1-weightc_down)*[-Bz/B2/dRdi, Br/B2/dZdi] + RETURN, newvec ENDIF ELSE BEGIN ;; stop RETURN, [-Bz/B2/dRdi, Br/B2/dZdi] @@ -70,8 +80,10 @@ END ; PRO follow_gradient_nonorth, interp_data, R, Z, ri0, zi0, ftarget, ri, zi, status=status, $ boundary=boundary, fbndry=fbndry, ibndry=ibndry, $ - vec=vec, weight=weight, bndry_noperiodic=bndry_noperiodic - COMMON rd_com_no, idata, lastgoodf, lastgoodpos, Rpos, Zpos, ood, bndry, ri0c, zi0c, tol, vec_comm, weightc, bndry_periodic + vec_up=vec_up, weight_up=weight_up, $ + vec_down=vec_down, weight_down=weight_down, $ + bndry_noperiodic=bndry_noperiodic + COMMON rd_com_no, idata, lastgoodf, lastgoodpos, Rpos, Zpos, ood, bndry, ri0c, zi0c, tol, vec_comm_up, weightc_up, vec_comm_down, weightc_down, bndry_periodic tol = 0.1 @@ -92,14 +104,23 @@ PRO follow_gradient_nonorth, interp_data, R, Z, ri0, zi0, ftarget, ri, zi, statu bndry_periodic = 1 IF KEYWORD_SET(bndry_noperiodic) THEN bndry_periodic = 0 - IF NOT KEYWORD_SET(weight) THEN BEGIN - weight = 0. + IF NOT KEYWORD_SET(weight_up) THEN BEGIN + weight_up = 0. + weightc_up = weight_up*1.0 + ENDIF + IF NOT KEYWORD_SET(weight_down) THEN BEGIN + weight_down = 0. + weightc_down = weight_down*1.0 + ENDIF + + IF KEYWORD_SET(vec_up) THEN BEGIN + vec_comm_up = vec_up + weightc_up = weight_up*1.0 + ENDIF + IF KEYWORD_SET(vec_down) THEN BEGIN + vec_comm_down = vec_down + weightc_down = weight_down*1.0 ENDIF - - IF KEYWORD_SET(vec) THEN BEGIN - vec_comm = vec - weightc = weight*1.0 - ENDIF IF SIZE(ftarget, /TYPE) EQ 0 THEN PRINT, ftarget diff --git a/tools/tokamak_grids/gridgen/get_line_nonorth.pro b/tools/tokamak_grids/gridgen/get_line_nonorth.pro index 2a52927595..afbd031e35 100644 --- a/tools/tokamak_grids/gridgen/get_line_nonorth.pro +++ b/tools/tokamak_grids/gridgen/get_line_nonorth.pro @@ -1,4 +1,4 @@ -FUNCTION get_line_nonorth, interp_data, R, Z, ri0, zi0, fto, npt=npt, vec=vec, weight=weight +FUNCTION get_line_nonorth, interp_data, R, Z, ri0, zi0, fto, npt=npt, vec_up=vec_up, weight_up=weight_up, vec_down=vec_down, weight_down=weight_down IF NOT KEYWORD_SET(npt) THEN npt=10 ; Get starting f @@ -8,6 +8,8 @@ FUNCTION get_line_nonorth, interp_data, R, Z, ri0, zi0, fto, npt=npt, vec=vec, w RETURN, [[ri0,ri0],[zi0,zi0]] ENDIF + IF NOT KEYWORD_SET(weight_up) THEN weight_up = 0. + IF NOT KEYWORD_SET(weight_down) THEN weight_down = 0. rixpt = FLTARR(npt+1) zixpt = rixpt rixpt[0] = ri0 @@ -16,7 +18,8 @@ FUNCTION get_line_nonorth, interp_data, R, Z, ri0, zi0, fto, npt=npt, vec=vec, w d = FLOAT(j+1)/FLOAT(npt) ftarg = d*fto + (1.0 - d)*ffrom follow_gradient_nonorth, interp_data, R, Z, rixpt[j], zixpt[j], $ - ftarg, rinext, zinext, vec=vec, weight=weight + ftarg, rinext, zinext, vec_up=vec_up, weight_up=weight_up, $ + vec_down=vec_down, weight_down=weight_down rixpt[j+1] = rinext zixpt[j+1] = zinext ENDFOR From 7148974950c619d14b1fd2c778e37eb793cd45fb Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 20 Feb 2019 15:39:00 +0000 Subject: [PATCH 0834/1783] Explicitly check for nullptr --- src/field/field_factory.cxx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 3ca4b15119..172a41e770 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -281,7 +281,7 @@ const Options* FieldFactory::findOption(const Options *opt, const std::string &n } FieldGeneratorPtr FieldFactory::resolve(std::string &name) { - if (options) { + if (options != nullptr) { // Check if in cache std::string key; if(name.find(':') != std::string::npos) { @@ -343,8 +343,9 @@ FieldGeneratorPtr FieldFactory::parse(const std::string &input, const Options *o // Check if in the cache std::string key = "#" + input; - if (opt) + if (opt != nullptr) { key = opt->str() + key; // Include options context in key + } auto it = cache.find(key); if (it != cache.end()) { @@ -356,8 +357,9 @@ FieldGeneratorPtr FieldFactory::parse(const std::string &input, const Options *o const Options *oldoptions = options; // Store the options tree for token lookups - if (opt) + if (opt != nullptr) { options = opt; + } // Parse FieldGeneratorPtr expr = parseString(input); From f67b91e3b5e1c317da581c5edab8176fc58d872c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 20 Feb 2019 16:50:25 +0000 Subject: [PATCH 0835/1783] Remove some extraneous comments --- src/field/field_factory.cxx | 68 ++++++++++++++----------------------- 1 file changed, 25 insertions(+), 43 deletions(-) diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 172a41e770..710af1dd7a 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -113,19 +113,19 @@ Field2D FieldFactory::create2D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC if (!gen) { throw BoutException("Couldn't create 2D field from null generator"); } - + Field2D result{localmesh}; result.allocate(); result.setLocation(loc); - + + constexpr BoutReal z_position{0.0}; + switch(loc) { case CELL_XLOW: { BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal xpos = 0.5 * (localmesh->GlobalX(i.x() - 1) + localmesh->GlobalX(i.x())); - result[i] = gen->generate(xpos, TWOPI * localmesh->GlobalY(i.y()), - 0.0, // Z - t); // T + result[i] = gen->generate(xpos, TWOPI * localmesh->GlobalY(i.y()), z_position, t); } break; } @@ -133,24 +133,18 @@ Field2D FieldFactory::create2D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal ypos = TWOPI * 0.5 * (localmesh->GlobalY(i.y() - 1) + localmesh->GlobalY(i.y())); - result[i] = gen->generate(localmesh->GlobalX(i.x()), ypos, - 0.0, // Z - t); // T + result[i] = gen->generate(localmesh->GlobalX(i.x()), ypos, z_position, t); } break; } - default: {// CELL_CENTRE or CELL_ZLOW + default: { // CELL_CENTRE or CELL_ZLOW BOUT_FOR(i, result.getRegion("RGN_ALL")) { - result[i] = - gen->generate(localmesh->GlobalX(i.x()), TWOPI * localmesh->GlobalY(i.y()), - 0.0, // Z - t); // T + result[i] = gen->generate(localmesh->GlobalX(i.x()), + TWOPI * localmesh->GlobalY(i.y()), z_position, t); } } }; - // Don't delete the generator, as will be cached - return result; } @@ -174,13 +168,9 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC if (!gen) { throw BoutException("Couldn't create 3D field from null generator"); } - - // Create a Field3D over mesh "localmesh" + Field3D result(localmesh); - - // Ensure that data is allocated and unique result.allocate(); - result.setLocation(loc); switch(loc) { @@ -188,9 +178,9 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal xpos = 0.5 * (localmesh->GlobalX(i.x() - 1) + localmesh->GlobalX(i.x())); result[i] = gen->generate(xpos, TWOPI * localmesh->GlobalY(i.y()), - TWOPI * static_cast(i.z()) / - static_cast(localmesh->LocalNz), // Z - t); // T + TWOPI * static_cast(i.z()) + / static_cast(localmesh->LocalNz), + t); } break; } @@ -199,9 +189,9 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC BoutReal ypos = TWOPI * 0.5 * (localmesh->GlobalY(i.y() - 1) + localmesh->GlobalY(i.y())); result[i] = gen->generate(localmesh->GlobalX(i.x()), ypos, - TWOPI * static_cast(i.z()) / - static_cast(localmesh->LocalNz), // Z - t); // T + TWOPI * static_cast(i.z()) + / static_cast(localmesh->LocalNz), + t); } break; } @@ -209,24 +199,24 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = gen->generate(localmesh->GlobalX(i.x()), TWOPI * localmesh->GlobalY(i.y()), - TWOPI * (static_cast(i.z()) - 0.5) / - static_cast(localmesh->LocalNz), // Z - t); // T + TWOPI * (static_cast(i.z()) - 0.5) + / static_cast(localmesh->LocalNz), + t); } break; } - default: {// CELL_CENTRE + default: { // CELL_CENTRE BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = gen->generate(localmesh->GlobalX(i.x()), TWOPI * localmesh->GlobalY(i.y()), - TWOPI * static_cast(i.z()) / - static_cast(localmesh->LocalNz), // Z - t); // T + TWOPI * static_cast(i.z()) + / static_cast(localmesh->LocalNz), + t); } } }; - - if (localmesh->canToFromFieldAligned()){ // Ask wheter it is possible + + if (localmesh->canToFromFieldAligned()) { // Transform from field aligned coordinates, to be compatible with // older BOUT++ inputs. This is not a particularly "nice" solution. result = localmesh->fromFieldAligned(result); @@ -321,16 +311,12 @@ FieldGeneratorPtr FieldFactory::resolve(std::string &name) { std::string value; const Options *section = findOption(options, name, value); - // Add to lookup list lookup.push_back(key); - // Parse FieldGeneratorPtr g = parse(value, section); - // Cache cache[key] = g; - // Remove from lookup list lookup.pop_back(); return g; @@ -349,7 +335,6 @@ FieldGeneratorPtr FieldFactory::parse(const std::string &input, const Options *o auto it = cache.find(key); if (it != cache.end()) { - // Found in cache return it->second; } @@ -361,13 +346,10 @@ FieldGeneratorPtr FieldFactory::parse(const std::string &input, const Options *o options = opt; } - // Parse FieldGeneratorPtr expr = parseString(input); - // Add to cache cache[key] = expr; - // Restore the old options options = oldoptions; return expr; From 56ff2934832b642dc0fb93b605ee412be3a6a579 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 20 Feb 2019 16:51:56 +0000 Subject: [PATCH 0836/1783] Clang-format FieldFactory --- include/field_factory.hxx | 31 ++++++++++-------- src/field/field_factory.cxx | 65 ++++++++++++++++++------------------- 2 files changed, 49 insertions(+), 47 deletions(-) diff --git a/include/field_factory.hxx b/include/field_factory.hxx index d2ee10ffd4..0e1a5843fb 100644 --- a/include/field_factory.hxx +++ b/include/field_factory.hxx @@ -1,12 +1,12 @@ /************************************************************************** * Generate a field with specified values, mainly for creating * initial perturbations - * - * + * + * * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -24,7 +24,6 @@ * **************************************************************************/ - class FieldFactory; #ifndef __FIELD_FACTORY_H__ @@ -40,14 +39,14 @@ class FieldFactory; #include "unused.hxx" -#include -#include #include +#include +#include // Utility routines to create generators from values FieldGeneratorPtr generator(BoutReal value); -FieldGeneratorPtr generator(BoutReal *ptr); +FieldGeneratorPtr generator(BoutReal* ptr); ////////////////////////////////////////////////////////// // Create a tree of generators from an input string @@ -87,10 +86,11 @@ public: /// clean the cache of parsed strings void cleanCache(); + protected: /// These functions called by the parser to resolve unknown symbols. /// This is used to enable options to be referred to in expressions. - FieldGeneratorPtr resolve(std::string &name) override; + FieldGeneratorPtr resolve(std::string& name) override; private: /// The default mesh for create functions. @@ -100,12 +100,13 @@ private: const Options* options; std::list lookup; // Names currently being parsed - + /// Cache parsed strings so repeated evaluations /// don't result in allocating more generators. - std::map cache; - - const Options* findOption(const Options *opt, const std::string &name, std::string &val); + std::map cache; + + const Options* findOption(const Options* opt, const std::string& name, + std::string& val); }; ////////////////////////////////////////////////////////// @@ -118,12 +119,13 @@ public: double generate(double x, double y, double z, double t) override { return func(t, x, y, z); } + private: FuncPtr func; }; ////////////////////////////////////////////////////////// -// Null generator +// Null generator class FieldNull : public FieldGenerator { public: @@ -138,10 +140,11 @@ public: static FieldGeneratorPtr get() { static FieldGeneratorPtr instance = nullptr; - if(!instance) + if (!instance) instance = std::make_shared(); return instance; } + private: }; diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 710af1dd7a..46d1e7eda0 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -25,8 +25,8 @@ #include -#include #include +#include #include #include "bout/constants.hxx" @@ -39,7 +39,7 @@ FieldGeneratorPtr generator(BoutReal value) { } /// Helper function to create a FieldValuePtr from a pointer to BoutReal -FieldGeneratorPtr generator(BoutReal *ptr) { +FieldGeneratorPtr generator(BoutReal* ptr) { return std::make_shared(ptr); } @@ -53,7 +53,7 @@ FieldFactory::FieldFactory(Mesh* localmesh, Options* opt) // Useful values addGenerator("pi", std::make_shared(PI)); addGenerator("π", std::make_shared(PI)); - + // Some standard functions addGenerator("sin", std::make_shared(nullptr)); addGenerator("cos", std::make_shared(nullptr)); @@ -95,12 +95,12 @@ FieldFactory::FieldFactory(Mesh* localmesh, Options* opt) } Field2D FieldFactory::create2D(const std::string& value, const Options* opt, - Mesh* localmesh, CELL_LOC loc, BoutReal t) { + Mesh* localmesh, CELL_LOC loc, BoutReal t) { return create2D(parse(value, opt), localmesh, loc, t); } Field2D FieldFactory::create2D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC loc, - BoutReal t) { + BoutReal t) { AUTO_TRACE(); if (localmesh == nullptr) { @@ -148,14 +148,13 @@ Field2D FieldFactory::create2D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC return result; } -Field3D FieldFactory::create3D(const std::string &value, const Options *opt, - Mesh *localmesh, CELL_LOC loc, - BoutReal t) { +Field3D FieldFactory::create3D(const std::string& value, const Options* opt, + Mesh* localmesh, CELL_LOC loc, BoutReal t) { return create3D(parse(value, opt), localmesh, loc, t); } Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC loc, - BoutReal t) { + BoutReal t) { AUTO_TRACE(); if (localmesh == nullptr) { @@ -172,8 +171,8 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC Field3D result(localmesh); result.allocate(); result.setLocation(loc); - - switch(loc) { + + switch (loc) { case CELL_XLOW: { BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal xpos = 0.5 * (localmesh->GlobalX(i.x() - 1) + localmesh->GlobalX(i.x())); @@ -225,41 +224,42 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC return result; } -const Options* FieldFactory::findOption(const Options *opt, const std::string &name, std::string &val) { +const Options* FieldFactory::findOption(const Options* opt, const std::string& name, + std::string& val) { // Find an Options object which contains the given name - const Options *result = opt; + const Options* result = opt; // Check if name contains a section separator ':' size_t pos = name.find(':'); - if(pos == std::string::npos) { + if (pos == std::string::npos) { // No separator. Try this section, and then go through parents - while(!result->isSet(name)) { + while (!result->isSet(name)) { result = result->getParent(); if (result == nullptr) throw ParseException("Cannot find variable '%s'", name.c_str()); } result->get(name, val, ""); - }else { + } else { // Go to the root, and go up through sections result = Options::getRoot(); size_t lastpos = 0; - while(pos != std::string::npos) { - std::string sectionname = name.substr(lastpos,pos); - if( sectionname.length() > 0 ) { + while (pos != std::string::npos) { + std::string sectionname = name.substr(lastpos, pos); + if (sectionname.length() > 0) { result = result->getSection(sectionname); } - lastpos = pos+1; + lastpos = pos + 1; pos = name.find(':', lastpos); } // Now look for the name in this section std::string varname = name.substr(lastpos); - if(!result->isSet(varname)) { + if (!result->isSet(varname)) { // Not in this section throw ParseException("Cannot find variable '%s'", name.c_str()); } @@ -270,17 +270,18 @@ const Options* FieldFactory::findOption(const Options *opt, const std::string &n return result; } -FieldGeneratorPtr FieldFactory::resolve(std::string &name) { +FieldGeneratorPtr FieldFactory::resolve(std::string& name) { if (options != nullptr) { // Check if in cache std::string key; - if(name.find(':') != std::string::npos) { + if (name.find(':') != std::string::npos) { // Already has section key = name; - }else { + } else { key = options->str(); - if(key.length() > 0) + if (key.length() > 0) { key += ":"; + } key += name; } @@ -293,11 +294,11 @@ FieldGeneratorPtr FieldFactory::resolve(std::string &name) { // Look up in options // Check if already looking up this symbol - for (const auto &lookup_value : lookup) { + for (const auto& lookup_value : lookup) { if (key.compare(lookup_value) == 0) { // Name matches, so already looking up output << "ExpressionParser lookup stack:\n"; - for (const auto &stack_value : lookup) { + for (const auto& stack_value : lookup) { output << stack_value << " -> "; } output << name << endl; @@ -309,7 +310,7 @@ FieldGeneratorPtr FieldFactory::resolve(std::string &name) { // Find the option, including traversing sections. // Throws exception if not found std::string value; - const Options *section = findOption(options, name, value); + const Options* section = findOption(options, name, value); lookup.push_back(key); @@ -325,7 +326,7 @@ FieldGeneratorPtr FieldFactory::resolve(std::string &name) { return nullptr; } -FieldGeneratorPtr FieldFactory::parse(const std::string &input, const Options *opt) { +FieldGeneratorPtr FieldFactory::parse(const std::string& input, const Options* opt) { // Check if in the cache std::string key = "#" + input; @@ -339,7 +340,7 @@ FieldGeneratorPtr FieldFactory::parse(const std::string &input, const Options *o } // Save the current options - const Options *oldoptions = options; + const Options* oldoptions = options; // Store the options tree for token lookups if (opt != nullptr) { @@ -361,6 +362,4 @@ FieldFactory* FieldFactory::get() { return &instance; } -void FieldFactory::cleanCache() { - cache.clear(); -} +void FieldFactory::cleanCache() { cache.clear(); } From bca2ca6b1317425060d5fe4b616af3927f9de554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 21 Feb 2019 09:46:45 +0000 Subject: [PATCH 0837/1783] Be more generic --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 19f1d14826..b943add765 100644 --- a/README.md +++ b/README.md @@ -182,8 +182,7 @@ used in the creation of [configure](configure) from developers. You are free to substitute them with other autoconf macros that provide equivalent functionality. -BOUT++ links by default with gettext and fftw, both are licensed as -GPL. Thus if you compile BOUT++ with ether of them, or any other GPLed -code, BOUT++ will automatically be licensed as GPL. Thus if you want -to use BOUT++ with GPL non-compatible code, make sure to compile -without GPLed code. +BOUT++ links by default with some GPL licensed libraries. Thus if you +compile BOUT++ with any of them, BOUT++ will automatically be licensed +as GPL. Thus if you want to use BOUT++ with GPL non-compatible code, +make sure to compile without GPLed code. From ca3fd141f754b12802eaf1248948c3cd0fbbdcdf Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 09:52:31 +0000 Subject: [PATCH 0838/1783] Don't return const values; make FieldGenerator::str const --- include/bout/sys/expressionparser.hxx | 10 +++++----- src/field/fieldgenerators.hxx | 17 ++++++++++++----- src/sys/expressionparser.cxx | 8 ++++---- tests/unit/sys/test_expressionparser.cxx | 4 ++-- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/include/bout/sys/expressionparser.hxx b/include/bout/sys/expressionparser.hxx index 986120314b..d9d4f350f2 100644 --- a/include/bout/sys/expressionparser.hxx +++ b/include/bout/sys/expressionparser.hxx @@ -67,7 +67,7 @@ public: virtual double generate(double x, double y, double z, double t) = 0; /// Create a string representation of the generator, for debugging output - virtual const std::string str() {return std::string("?");} + virtual std::string str() const { return std::string("?"); } }; /*! @@ -163,9 +163,9 @@ public: FieldGeneratorPtr clone(const std::list args) override; double generate(double x, double y, double z, double t) override; - const std::string str() override { - return std::string("(") + lhs->str() + std::string(1, op) + rhs->str() + - std::string(")"); + std::string str() const override { + return std::string("(") + lhs->str() + std::string(1, op) + rhs->str() + + std::string(")"); } private: @@ -186,7 +186,7 @@ public: double UNUSED(t)) override { return value; } - const std::string str() override { + std::string str() const override { std::stringstream ss; ss << value; return ss.str(); diff --git a/src/field/fieldgenerators.hxx b/src/field/fieldgenerators.hxx index a6fddafacd..58b51b8202 100644 --- a/src/field/fieldgenerators.hxx +++ b/src/field/fieldgenerators.hxx @@ -39,7 +39,8 @@ public: FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); - const std::string str() {return std::string("sin(")+gen->str()+std::string(")");} + std::string str() const { return std::string("sin(") + gen->str() + std::string(")"); } + private: FieldGeneratorPtr gen; }; @@ -52,7 +53,8 @@ public: FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); - const std::string str() {return std::string("cos(")+gen->str()+std::string(")");} + std::string str() const { return std::string("cos(") + gen->str() + std::string(")"); } + private: FieldGeneratorPtr gen; }; @@ -72,7 +74,8 @@ public: BoutReal generate(double x, double y, double z, double t) { return Op(gen->generate(x,y,z,t)); } - const std::string str() {return std::string("func(")+gen->str()+std::string(")");} + std::string str() const { return std::string("func(") + gen->str() + std::string(")"); } + private: FieldGeneratorPtr gen; }; @@ -92,7 +95,10 @@ public: BoutReal generate(double x, double y, double z, double t) { return Op(A->generate(x,y,z,t), B->generate(x,y,z,t)); } - const std::string str() {return std::string("cos(")+A->str()+","+B->str()+std::string(")");} + std::string str() const { + return std::string("cos(") + A->str() + "," + B->str() + std::string(")"); + } + private: FieldGeneratorPtr A, B; }; @@ -191,7 +197,8 @@ public: FieldGeneratorPtr clone(const std::list args); BoutReal generate(double x, double y, double z, double t); - const std::string str() {return std::string("H(")+gen->str()+std::string(")");} + std::string str() const { return std::string("H(") + gen->str() + std::string(")"); } + private: FieldGeneratorPtr gen; }; diff --git a/src/sys/expressionparser.cxx b/src/sys/expressionparser.cxx index dc14c22815..d8645bf828 100644 --- a/src/sys/expressionparser.cxx +++ b/src/sys/expressionparser.cxx @@ -44,7 +44,7 @@ namespace { // These classes only visible in this file double UNUSED(t)) override { return x; } - const std::string str() override { return std::string("x"); } + std::string str() const override { return std::string("x"); } }; class FieldY : public FieldGenerator { @@ -56,7 +56,7 @@ namespace { // These classes only visible in this file double UNUSED(t)) override { return y; } - const std::string str() override { return std::string("y"); } + std::string str() const override { return std::string("y"); } }; class FieldZ : public FieldGenerator { @@ -68,7 +68,7 @@ namespace { // These classes only visible in this file double UNUSED(t)) override { return z; } - const std::string str() override { return std::string("z"); } + std::string str() const override { return std::string("z"); } }; class FieldT : public FieldGenerator { @@ -80,7 +80,7 @@ namespace { // These classes only visible in this file double t) override { return t; } - const std::string str() override { return std::string("t"); } + std::string str() const override { return std::string("t"); } }; } diff --git a/tests/unit/sys/test_expressionparser.cxx b/tests/unit/sys/test_expressionparser.cxx index 04015de7b1..9cd2b4e850 100644 --- a/tests/unit/sys/test_expressionparser.cxx +++ b/tests/unit/sys/test_expressionparser.cxx @@ -43,7 +43,7 @@ class BinaryGenerator : public FieldGenerator { BoutReal generate(BoutReal x, BoutReal y, BoutReal z, BoutReal t) { return a->generate(x, y, z, t) + b->generate(x, y, z, t); } - const std::string str() { + std::string str() const { return std::string{"add(" + a->str() + ", " + b->str() + ")"}; } @@ -69,7 +69,7 @@ class IncrementGenerator : public FieldGenerator { BoutReal generate(BoutReal x, BoutReal y, BoutReal z, BoutReal t) { return gen->generate(x, y, z, t) + 1; } - const std::string str() { return std::string{"increment(" + gen->str() + ")"}; } + std::string str() const { return std::string{"increment(" + gen->str() + ")"}; } private: std::shared_ptr gen; From 25e44dd156b41844ac355b6e6a7c6fcca9857f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 21 Feb 2019 10:00:25 +0000 Subject: [PATCH 0839/1783] Add AUTO_TRACE and rename function * saveAt - a `save` version of at - it throws a BoutException, rather then calling throwing a different exception. * AUTO_TRACE makes sure we have enough information in the msg_stack so that the exception is usefull * Include the required header files --- src/sys/bout_types.cxx | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index aabcb92ba8..f42ab34d1f 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -1,9 +1,11 @@ -#include +#include +#include #include #include template -const std::string& saveat(const std::map& mymap, T t) { +const std::string& saveAt(const std::map& mymap, T t) { + AUTO_TRACE(); auto found = mymap.find(t); if (found == mymap.end()) { throw BoutException("Did not find enum %d", static_cast(t)); @@ -12,30 +14,34 @@ const std::string& saveat(const std::map& mymap, T t) { } const std::string& CELL_LOC_STRING(CELL_LOC location) { + AUTO_TRACE(); const static std::map CELL_LOCtoString = { ENUMSTR(CELL_DEFAULT), ENUMSTR(CELL_CENTRE), ENUMSTR(CELL_XLOW), ENUMSTR(CELL_YLOW), ENUMSTR(CELL_ZLOW), ENUMSTR(CELL_VSHIFT)}; - return saveat(CELL_LOCtoString, location); + return saveAt(CELL_LOCtoString, location); } const std::string& DIFF_METHOD_STRING(DIFF_METHOD location) { + AUTO_TRACE(); const static std::map DIFF_METHODtoString = { {DIFF_DEFAULT, "DEFAULT"}, {DIFF_U1, "U1"}, {DIFF_U2, "U2"}, {DIFF_U3, "U3"}, {DIFF_C2, "C2"}, {DIFF_C4, "C4"}, {DIFF_S2, "S2"}, {DIFF_W2, "W2"}, {DIFF_W3, "W3"}, {DIFF_FFT, "FFT"}, {DIFF_SPLIT, "SPLIT"}}; - return saveat(DIFF_METHODtoString, location); + return saveAt(DIFF_METHODtoString, location); } const std::string& REGION_STRING(REGION region) { + AUTO_TRACE(); const static std::map REGIONtoString = { ENUMSTR(RGN_ALL), ENUMSTR(RGN_NOBNDRY), ENUMSTR(RGN_NOX), ENUMSTR(RGN_NOY), ENUMSTR(RGN_NOZ)}; - return saveat(REGIONtoString, region); + return saveAt(REGIONtoString, region); } const std::string& DIRECTION_STRING(DIRECTION direction) { + AUTO_TRACE(); const static std::map DIRECTIONtoString = { {DIRECTION::X, "X"}, {DIRECTION::Y, "Y"}, @@ -43,19 +49,21 @@ const std::string& DIRECTION_STRING(DIRECTION direction) { {DIRECTION::YAligned, "Y - field aligned"}, {DIRECTION::YOrthogonal, "Y - orthogonal"}}; - return saveat(DIRECTIONtoString, direction); + return saveAt(DIRECTIONtoString, direction); } const std::string& STAGGER_STRING(STAGGER stagger) { + AUTO_TRACE(); const static std::map STAGGERtoString = { {STAGGER::None, "No staggering"}, {STAGGER::C2L, "Centre to Low"}, {STAGGER::L2C, "Low to Centre"}}; - return saveat(STAGGERtoString, stagger); + return saveAt(STAGGERtoString, stagger); } const std::string& DERIV_STRING(DERIV deriv) { + AUTO_TRACE(); const static std::map DERIVtoString = { {DERIV::Standard, "Standard"}, {DERIV::StandardSecond, "Standard -- second order"}, @@ -63,5 +71,5 @@ const std::string& DERIV_STRING(DERIV deriv) { {DERIV::Upwind, "Upwind"}, {DERIV::Flux, "Flux"}}; - return saveat(DERIVtoString, deriv); + return saveAt(DERIVtoString, deriv); } From d042384a846a5d949c309f2e0f7c187beec5c67e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 10:43:48 +0000 Subject: [PATCH 0840/1783] Use override consistently in FieldGenerators --- src/field/fieldgenerators.hxx | 152 ++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 64 deletions(-) diff --git a/src/field/fieldgenerators.hxx b/src/field/fieldgenerators.hxx index 58b51b8202..67adc82c6f 100644 --- a/src/field/fieldgenerators.hxx +++ b/src/field/fieldgenerators.hxx @@ -20,11 +20,15 @@ /// WARNING: The value pointed to must remain in scope until this generator is finished class FieldValuePtr : public FieldGenerator { public: - FieldValuePtr(BoutReal *val) : ptr(val) {} - FieldGeneratorPtr clone(const std::list UNUSED(args)) { + FieldValuePtr(BoutReal* val) : ptr(val) {} + FieldGeneratorPtr clone(const std::list UNUSED(args)) override { return std::make_shared(ptr); } - BoutReal generate(double UNUSED(x), double UNUSED(y), double UNUSED(z), double UNUSED(t)) { return *ptr; } + BoutReal generate(double UNUSED(x), double UNUSED(y), double UNUSED(z), + double UNUSED(t)) override { + return *ptr; + } + private: BoutReal *ptr; }; @@ -37,9 +41,11 @@ class FieldSin : public FieldGenerator { public: FieldSin(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const std::list args); - BoutReal generate(double x, double y, double z, double t); - std::string str() const { return std::string("sin(") + gen->str() + std::string(")"); } + FieldGeneratorPtr clone(const std::list args) override; + BoutReal generate(double x, double y, double z, double t) override; + std::string str() const override { + return std::string("sin(") + gen->str() + std::string(")"); + } private: FieldGeneratorPtr gen; @@ -50,10 +56,12 @@ class FieldCos : public FieldGenerator { public: FieldCos(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const std::list args); - BoutReal generate(double x, double y, double z, double t); + FieldGeneratorPtr clone(const std::list args) override; + BoutReal generate(double x, double y, double z, double t) override; - std::string str() const { return std::string("cos(") + gen->str() + std::string(")"); } + std::string str() const override { + return std::string("cos(") + gen->str() + std::string(")"); + } private: FieldGeneratorPtr gen; @@ -65,37 +73,40 @@ template class FieldGenOneArg : public FieldGenerator { ///< Template for single-argument function public: FieldGenOneArg(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const std::list args) { + FieldGeneratorPtr clone(const std::list args) override { if(args.size() != 1) { throw ParseException("Incorrect number of arguments to function. Expecting 1, got %d", args.size()); } return std::make_shared>(args.front()); } - BoutReal generate(double x, double y, double z, double t) { - return Op(gen->generate(x,y,z,t)); + BoutReal generate(double x, double y, double z, double t) override { + return Op(gen->generate(x, y, z, t)); + } + std::string str() const override { + return std::string("func(") + gen->str() + std::string(")"); } - std::string str() const { return std::string("func(") + gen->str() + std::string(")"); } private: FieldGeneratorPtr gen; }; /// Template for a FieldGenerator with two input arguments -typedef BoutReal(*double_arg_op)(BoutReal, BoutReal); -template +typedef BoutReal (*double_arg_op)(BoutReal, BoutReal); +template class FieldGenTwoArg : public FieldGenerator { ///< Template for two-argument function public: FieldGenTwoArg(FieldGeneratorPtr a, FieldGeneratorPtr b) : A(a), B(b) {} - FieldGeneratorPtr clone(const std::list args) { - if(args.size() != 2) { - throw ParseException("Incorrect number of arguments to function. Expecting 2, got %d", args.size()); + FieldGeneratorPtr clone(const std::list args) override { + if (args.size() != 2) { + throw ParseException( + "Incorrect number of arguments to function. Expecting 2, got %d", args.size()); } return std::make_shared>(args.front(), args.back()); } - BoutReal generate(double x, double y, double z, double t) { - return Op(A->generate(x,y,z,t), B->generate(x,y,z,t)); + BoutReal generate(double x, double y, double z, double t) override { + return Op(A->generate(x, y, z, t), B->generate(x, y, z, t)); } - std::string str() const { + std::string str() const override { return std::string("cos(") + A->str() + "," + B->str() + std::string(")"); } @@ -106,20 +117,21 @@ private: /// Arc (Inverse) tangent. Either one or two argument versions class FieldATan : public FieldGenerator { public: - FieldATan(FieldGeneratorPtr a, FieldGeneratorPtr b=nullptr) : A(a), B(b) {} - FieldGeneratorPtr clone(const std::list args) { - if(args.size() == 1) { + FieldATan(FieldGeneratorPtr a, FieldGeneratorPtr b = nullptr) : A(a), B(b) {} + FieldGeneratorPtr clone(const std::list args) override { + if (args.size() == 1) { return std::make_shared(args.front()); }else if(args.size() == 2) { return std::make_shared(args.front(), args.back()); } throw ParseException("Incorrect number of arguments to atan function. Expecting 1 or 2, got %d", args.size()); } - BoutReal generate(double x, double y, double z, double t) { - if(B == nullptr) - return atan(A->generate(x,y,z,t)); - return atan2(A->generate(x,y,z,t), B->generate(x,y,z,t)); + BoutReal generate(double x, double y, double z, double t) override { + if (B == nullptr) + return atan(A->generate(x, y, z, t)); + return atan2(A->generate(x, y, z, t), B->generate(x, y, z, t)); } + private: FieldGeneratorPtr A, B; }; @@ -129,8 +141,9 @@ class FieldSinh : public FieldGenerator { public: FieldSinh(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const std::list args); - BoutReal generate(double x, double y, double z, double t); + FieldGeneratorPtr clone(const std::list args) override; + BoutReal generate(double x, double y, double z, double t) override; + private: FieldGeneratorPtr gen; }; @@ -140,8 +153,9 @@ class FieldCosh : public FieldGenerator { public: FieldCosh(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const std::list args); - BoutReal generate(double x, double y, double z, double t); + FieldGeneratorPtr clone(const std::list args) override; + BoutReal generate(double x, double y, double z, double t) override; + private: FieldGeneratorPtr gen; }; @@ -149,10 +163,11 @@ private: /// Hyperbolic tangent class FieldTanh : public FieldGenerator { public: - FieldTanh(FieldGeneratorPtr g=nullptr) : gen(g) {} + FieldTanh(FieldGeneratorPtr g = nullptr) : gen(g) {} + + FieldGeneratorPtr clone(const std::list args) override; + BoutReal generate(double x, double y, double z, double t) override; - FieldGeneratorPtr clone(const std::list args); - BoutReal generate(double x, double y, double z, double t); private: FieldGeneratorPtr gen; }; @@ -162,8 +177,9 @@ class FieldGaussian : public FieldGenerator { public: FieldGaussian(FieldGeneratorPtr xin, FieldGeneratorPtr sin) : X(xin), s(sin) {} - FieldGeneratorPtr clone(const std::list args); - BoutReal generate(double x, double y, double z, double t); + FieldGeneratorPtr clone(const std::list args) override; + BoutReal generate(double x, double y, double z, double t) override; + private: FieldGeneratorPtr X, s; }; @@ -173,8 +189,9 @@ class FieldAbs : public FieldGenerator { public: FieldAbs(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const std::list args); - BoutReal generate(double x, double y, double z, double t); + FieldGeneratorPtr clone(const std::list args) override; + BoutReal generate(double x, double y, double z, double t) override; + private: FieldGeneratorPtr gen; }; @@ -184,8 +201,9 @@ class FieldSqrt : public FieldGenerator { public: FieldSqrt(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const std::list args); - BoutReal generate(double x, double y, double z, double t); + FieldGeneratorPtr clone(const std::list args) override; + BoutReal generate(double x, double y, double z, double t) override; + private: FieldGeneratorPtr gen; }; @@ -195,9 +213,11 @@ class FieldHeaviside : public FieldGenerator { public: FieldHeaviside(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const std::list args); - BoutReal generate(double x, double y, double z, double t); - std::string str() const { return std::string("H(") + gen->str() + std::string(")"); } + FieldGeneratorPtr clone(const std::list args) override; + BoutReal generate(double x, double y, double z, double t) override; + std::string str() const override { + return std::string("H(") + gen->str() + std::string(")"); + } private: FieldGeneratorPtr gen; @@ -208,8 +228,9 @@ class FieldErf : public FieldGenerator { public: FieldErf(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const std::list args); - BoutReal generate(double x, double y, double z, double t); + FieldGeneratorPtr clone(const std::list args) override; + BoutReal generate(double x, double y, double z, double t) override; + private: FieldGeneratorPtr gen; }; @@ -218,14 +239,14 @@ private: class FieldMin : public FieldGenerator { public: FieldMin() {} - FieldMin(const std::list args) : input(args) {} - FieldGeneratorPtr clone(const std::list args) { - if(args.size() == 0) { + FieldMin(const std::list args) : input(args) {} + FieldGeneratorPtr clone(const std::list args) override { + if (args.size() == 0) { throw ParseException("min function must have some inputs"); } return std::make_shared(args); } - BoutReal generate(double x, double y, double z, double t) { + BoutReal generate(double x, double y, double z, double t) override { auto it = input.begin(); BoutReal result = (*it)->generate(x,y,z,t); for(;it != input.end(); it++) { @@ -243,14 +264,14 @@ private: class FieldMax : public FieldGenerator { public: FieldMax() {} - FieldMax(const std::list args) : input(args) {} - FieldGeneratorPtr clone(const std::list args) { - if(args.size() == 0) { + FieldMax(const std::list args) : input(args) {} + FieldGeneratorPtr clone(const std::list args) override { + if (args.size() == 0) { throw ParseException("max function must have some inputs"); } return std::make_shared(args); } - BoutReal generate(double x, double y, double z, double t) { + BoutReal generate(double x, double y, double z, double t) override { auto it = input.begin(); BoutReal result = (*it)->generate(x,y,z,t); for(;it != input.end(); it++) { @@ -269,15 +290,15 @@ class FieldRound : public FieldGenerator { public: FieldRound(FieldGeneratorPtr g) : gen(g) {} - FieldGeneratorPtr clone(const std::list args) { + FieldGeneratorPtr clone(const std::list args) override { if (args.size() != 1) { throw ParseException("round function must have one input"); } return std::make_shared(args.front()); } - BoutReal generate(double x, double y, double z, double t) { - BoutReal val = gen->generate(x,y,z,t); - if(val > 0.0) { + BoutReal generate(double x, double y, double z, double t) override { + BoutReal val = gen->generate(x, y, z, t); + if (val > 0.0) { return static_cast(val + 0.5); } return static_cast(val - 0.5); @@ -297,8 +318,9 @@ private: class FieldBallooning : public FieldGenerator { public: FieldBallooning(Mesh *m, FieldGeneratorPtr a = nullptr, int n = 3) : mesh(m), arg(a), ball_n(n) {} - FieldGeneratorPtr clone(const std::list args); - BoutReal generate(double x, double y, double z, double t); + FieldGeneratorPtr clone(const std::list args) override; + BoutReal generate(double x, double y, double z, double t) override; + private: Mesh *mesh; FieldGeneratorPtr arg; @@ -312,8 +334,9 @@ private: class FieldMixmode : public FieldGenerator { public: FieldMixmode(FieldGeneratorPtr a = nullptr, BoutReal seed = 0.5); - FieldGeneratorPtr clone(const std::list args); - BoutReal generate(double x, double y, double z, double t); + FieldGeneratorPtr clone(const std::list args) override; + BoutReal generate(double x, double y, double z, double t) override; + private: /// Generate a random number between 0 and 1 (exclusive) /// given an arbitrary seed value @@ -337,8 +360,9 @@ public: FieldGeneratorPtr steepnessin) : X(xin), width(widthin), center(centerin), steepness(steepnessin) {}; // Clone containing the list of arguments - FieldGeneratorPtr clone(const std::list args); - BoutReal generate(double x, double y, double z, double t); + FieldGeneratorPtr clone(const std::list args) override; + BoutReal generate(double x, double y, double z, double t) override; + private: // The (x,y,z,t) field FieldGeneratorPtr X; From 8db26e66f13d258287a201a85388531bd02f5ba3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 10:53:48 +0000 Subject: [PATCH 0841/1783] Use `using` instead of `typedef` --- src/field/fieldgenerators.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/field/fieldgenerators.hxx b/src/field/fieldgenerators.hxx index 67adc82c6f..4af7d7ff83 100644 --- a/src/field/fieldgenerators.hxx +++ b/src/field/fieldgenerators.hxx @@ -68,7 +68,7 @@ private: }; /// Template class to define generators around a C function -typedef BoutReal(*single_arg_op)(BoutReal); +using single_arg_op = BoutReal (*)(BoutReal); template class FieldGenOneArg : public FieldGenerator { ///< Template for single-argument function public: @@ -91,7 +91,7 @@ private: }; /// Template for a FieldGenerator with two input arguments -typedef BoutReal (*double_arg_op)(BoutReal, BoutReal); +using double_arg_op = BoutReal (*)(BoutReal, BoutReal); template class FieldGenTwoArg : public FieldGenerator { ///< Template for two-argument function public: From 9958588348a77aa9c117816e30c55982de52e552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 21 Feb 2019 11:12:29 +0000 Subject: [PATCH 0842/1783] fix name --- src/sys/bout_types.cxx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index f42ab34d1f..280dfcb957 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -4,7 +4,7 @@ #include template -const std::string& saveAt(const std::map& mymap, T t) { +const std::string& safeAt(const std::map& mymap, T t) { AUTO_TRACE(); auto found = mymap.find(t); if (found == mymap.end()) { @@ -19,7 +19,7 @@ const std::string& CELL_LOC_STRING(CELL_LOC location) { ENUMSTR(CELL_DEFAULT), ENUMSTR(CELL_CENTRE), ENUMSTR(CELL_XLOW), ENUMSTR(CELL_YLOW), ENUMSTR(CELL_ZLOW), ENUMSTR(CELL_VSHIFT)}; - return saveAt(CELL_LOCtoString, location); + return safeAt(CELL_LOCtoString, location); } const std::string& DIFF_METHOD_STRING(DIFF_METHOD location) { @@ -29,7 +29,7 @@ const std::string& DIFF_METHOD_STRING(DIFF_METHOD location) { {DIFF_C2, "C2"}, {DIFF_C4, "C4"}, {DIFF_S2, "S2"}, {DIFF_W2, "W2"}, {DIFF_W3, "W3"}, {DIFF_FFT, "FFT"}, {DIFF_SPLIT, "SPLIT"}}; - return saveAt(DIFF_METHODtoString, location); + return safeAt(DIFF_METHODtoString, location); } const std::string& REGION_STRING(REGION region) { @@ -37,7 +37,7 @@ const std::string& REGION_STRING(REGION region) { const static std::map REGIONtoString = { ENUMSTR(RGN_ALL), ENUMSTR(RGN_NOBNDRY), ENUMSTR(RGN_NOX), ENUMSTR(RGN_NOY), ENUMSTR(RGN_NOZ)}; - return saveAt(REGIONtoString, region); + return safeAt(REGIONtoString, region); } const std::string& DIRECTION_STRING(DIRECTION direction) { @@ -49,7 +49,7 @@ const std::string& DIRECTION_STRING(DIRECTION direction) { {DIRECTION::YAligned, "Y - field aligned"}, {DIRECTION::YOrthogonal, "Y - orthogonal"}}; - return saveAt(DIRECTIONtoString, direction); + return safeAt(DIRECTIONtoString, direction); } const std::string& STAGGER_STRING(STAGGER stagger) { @@ -59,7 +59,7 @@ const std::string& STAGGER_STRING(STAGGER stagger) { {STAGGER::C2L, "Centre to Low"}, {STAGGER::L2C, "Low to Centre"}}; - return saveAt(STAGGERtoString, stagger); + return safeAt(STAGGERtoString, stagger); } const std::string& DERIV_STRING(DERIV deriv) { @@ -71,5 +71,5 @@ const std::string& DERIV_STRING(DERIV deriv) { {DERIV::Upwind, "Upwind"}, {DERIV::Flux, "Flux"}}; - return saveAt(DERIVtoString, deriv); + return safeAt(DERIVtoString, deriv); } From a4475ba10cc1375099c6a58bbe6d1b8260c36974 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 11:24:49 +0000 Subject: [PATCH 0843/1783] Clang-tidy fieldgenerators --- src/field/fieldgenerators.hxx | 53 ++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/field/fieldgenerators.hxx b/src/field/fieldgenerators.hxx index 4af7d7ff83..182ed2e8fe 100644 --- a/src/field/fieldgenerators.hxx +++ b/src/field/fieldgenerators.hxx @@ -1,14 +1,14 @@ /*! * \file fieldgenerators.hxx - * + * * These classes are used by FieldFactory */ #ifndef __FIELDGENERATORS_H__ #define __FIELDGENERATORS_H__ -#include #include +#include #include #include @@ -30,7 +30,7 @@ public: } private: - BoutReal *ptr; + BoutReal* ptr; }; ////////////////////////////////////////////////////////// @@ -115,16 +115,18 @@ private: }; /// Arc (Inverse) tangent. Either one or two argument versions -class FieldATan : public FieldGenerator { +class FieldATan : public FieldGenerator { public: FieldATan(FieldGeneratorPtr a, FieldGeneratorPtr b = nullptr) : A(a), B(b) {} FieldGeneratorPtr clone(const std::list args) override { if (args.size() == 1) { return std::make_shared(args.front()); - }else if(args.size() == 2) { + } else if (args.size() == 2) { return std::make_shared(args.front(), args.back()); } - throw ParseException("Incorrect number of arguments to atan function. Expecting 1 or 2, got %d", args.size()); + throw ParseException( + "Incorrect number of arguments to atan function. Expecting 1 or 2, got %d", + args.size()); } BoutReal generate(double x, double y, double z, double t) override { if (B == nullptr) @@ -248,16 +250,17 @@ public: } BoutReal generate(double x, double y, double z, double t) override { auto it = input.begin(); - BoutReal result = (*it)->generate(x,y,z,t); - for(;it != input.end(); it++) { - BoutReal val = (*it)->generate(x,y,z,t); - if(val < result) + BoutReal result = (*it)->generate(x, y, z, t); + for (; it != input.end(); it++) { + BoutReal val = (*it)->generate(x, y, z, t); + if (val < result) result = val; } return result; } + private: - std::list input; + std::list input; }; /// Maximum @@ -273,16 +276,17 @@ public: } BoutReal generate(double x, double y, double z, double t) override { auto it = input.begin(); - BoutReal result = (*it)->generate(x,y,z,t); - for(;it != input.end(); it++) { - BoutReal val = (*it)->generate(x,y,z,t); - if(val > result) + BoutReal result = (*it)->generate(x, y, z, t); + for (; it != input.end(); it++) { + BoutReal val = (*it)->generate(x, y, z, t); + if (val > result) result = val; } return result; } + private: - std::list input; + std::list input; }; /// Generator to round to the nearest integer @@ -317,14 +321,15 @@ private: class FieldBallooning : public FieldGenerator { public: - FieldBallooning(Mesh *m, FieldGeneratorPtr a = nullptr, int n = 3) : mesh(m), arg(a), ball_n(n) {} + FieldBallooning(Mesh* m, FieldGeneratorPtr a = nullptr, int n = 3) + : mesh(m), arg(a), ball_n(n) {} FieldGeneratorPtr clone(const std::list args) override; BoutReal generate(double x, double y, double z, double t) override; private: - Mesh *mesh; + Mesh* mesh; FieldGeneratorPtr arg; - int ball_n; // How many times around in each direction + int ball_n; // How many times around in each direction }; ////////////////////////////////////////////////////////// @@ -341,7 +346,7 @@ private: /// Generate a random number between 0 and 1 (exclusive) /// given an arbitrary seed value /// - /// This PRNG has no memory, i.e. you need to call it + /// This PRNG has no memory, i.e. you need to call it /// with a different seed each time. BoutReal genRand(BoutReal seed); @@ -354,11 +359,9 @@ private: class FieldTanhHat : public FieldGenerator { public: // Constructor - FieldTanhHat(FieldGeneratorPtr xin, - FieldGeneratorPtr widthin, - FieldGeneratorPtr centerin, - FieldGeneratorPtr steepnessin) - : X(xin), width(widthin), center(centerin), steepness(steepnessin) {}; + FieldTanhHat(FieldGeneratorPtr xin, FieldGeneratorPtr widthin, + FieldGeneratorPtr centerin, FieldGeneratorPtr steepnessin) + : X(xin), width(widthin), center(centerin), steepness(steepnessin) {}; // Clone containing the list of arguments FieldGeneratorPtr clone(const std::list args) override; BoutReal generate(double x, double y, double z, double t) override; From 8884a1b5c8ff1a825c60747328ca275e59281c4e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 11:30:41 +0000 Subject: [PATCH 0844/1783] Use equals default on empty constructors/destructors --- include/bout/sys/expressionparser.hxx | 6 +++--- src/field/fieldgenerators.hxx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/bout/sys/expressionparser.hxx b/include/bout/sys/expressionparser.hxx index d9d4f350f2..7fbb55a5de 100644 --- a/include/bout/sys/expressionparser.hxx +++ b/include/bout/sys/expressionparser.hxx @@ -51,7 +51,7 @@ using FieldGeneratorPtr = std::shared_ptr; */ class FieldGenerator { public: - virtual ~FieldGenerator() { } + virtual ~FieldGenerator() = default; /// Virtual constructor. Makes a copy of this FieldGenerator, /// initialised with the given list of arguments. It is up to the implementations @@ -80,7 +80,7 @@ public: class ExpressionParser { public: ExpressionParser(); - virtual ~ExpressionParser() {}; + virtual ~ExpressionParser() = default; /// Add a generator to the parser, which can then be recognised and used /// in expressions. @@ -200,7 +200,7 @@ private: class ParseException : public std::exception { public: ParseException(const char *, ...); - ~ParseException() override {} + ~ParseException() override = default; const char *what() const noexcept override; diff --git a/src/field/fieldgenerators.hxx b/src/field/fieldgenerators.hxx index 182ed2e8fe..f1ba98c16b 100644 --- a/src/field/fieldgenerators.hxx +++ b/src/field/fieldgenerators.hxx @@ -240,7 +240,7 @@ private: /// Minimum class FieldMin : public FieldGenerator { public: - FieldMin() {} + FieldMin() = default; FieldMin(const std::list args) : input(args) {} FieldGeneratorPtr clone(const std::list args) override { if (args.size() == 0) { @@ -266,7 +266,7 @@ private: /// Maximum class FieldMax : public FieldGenerator { public: - FieldMax() {} + FieldMax() = default; FieldMax(const std::list args) : input(args) {} FieldGeneratorPtr clone(const std::list args) override { if (args.size() == 0) { From d932120d72e76a1008bc3f178cafd1ef862a13d2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 11:42:40 +0000 Subject: [PATCH 0845/1783] Make FieldFactory and ExpressionParser const correct FieldFactory::options is a hidden argument to FieldFactory::resolve and can be overridden during a call to parse/create2D/create3D, which is why it needs to be marked `mutable`. Note that it is a mutable pointer to a const Options -- it's the pointer that's mutable, and the object that is const! --- include/bout/sys/expressionparser.hxx | 14 +++++++------- include/field_factory.hxx | 26 ++++++++++++++------------ src/field/field_factory.cxx | 14 +++++++------- src/sys/expressionparser.cxx | 12 ++++++------ 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/include/bout/sys/expressionparser.hxx b/include/bout/sys/expressionparser.hxx index 7fbb55a5de..bc6566ff14 100644 --- a/include/bout/sys/expressionparser.hxx +++ b/include/bout/sys/expressionparser.hxx @@ -109,10 +109,10 @@ public: void addBinaryOp(char sym, FieldGeneratorPtr b, int precedence); protected: /// This will be called to resolve any unknown symbols - virtual FieldGeneratorPtr resolve(std::string &UNUSED(name)) { return nullptr; } + virtual FieldGeneratorPtr resolve(std::string &UNUSED(name)) const { return nullptr; } /// Parses a given string into a tree of FieldGenerator objects - FieldGeneratorPtr parseString(const std::string &input); + FieldGeneratorPtr parseString(const std::string &input) const; /// Characters which cannot be used in symbols; all other allowed /// In addition, whitespace cannot be used @@ -138,8 +138,8 @@ private: char nextToken(); ///< Get the next token in the string }; - FieldGeneratorPtr parseIdentifierExpr(LexInfo &lex); - FieldGeneratorPtr parseParenExpr(LexInfo &lex); + FieldGeneratorPtr parseIdentifierExpr(LexInfo &lex) const; + FieldGeneratorPtr parseParenExpr(LexInfo &lex) const; /// Parse a primary expression, one of: /// - number @@ -148,9 +148,9 @@ private: /// - [ ... ] /// - a unary '-', which is converted to '0 -' /// A ParseException is thrown if none of these is found - FieldGeneratorPtr parsePrimary(LexInfo &lex); - FieldGeneratorPtr parseBinOpRHS(LexInfo &lex, int prec, FieldGeneratorPtr lhs); - FieldGeneratorPtr parseExpression(LexInfo &lex); + FieldGeneratorPtr parsePrimary(LexInfo &lex) const; + FieldGeneratorPtr parseBinOpRHS(LexInfo &lex, int prec, FieldGeneratorPtr lhs) const; + FieldGeneratorPtr parseExpression(LexInfo &lex) const; }; ////////////////////////////////////////////////////// diff --git a/include/field_factory.hxx b/include/field_factory.hxx index 0e1a5843fb..256b1ed4fd 100644 --- a/include/field_factory.hxx +++ b/include/field_factory.hxx @@ -60,26 +60,26 @@ public: /// using the given options \p opt, over Mesh \p m at time \p t. /// The resulting field is at cell location \p loc. Field2D create2D(const std::string& value, const Options* opt = nullptr, - Mesh* m = nullptr, CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); + Mesh* m = nullptr, CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0) const; /// Create a 3D field by parsing a string and evaluating the expression /// using the given options \p opt, over Mesh \p m at time \p t. /// The resulting field is at cell location \p loc. Field3D create3D(const std::string& value, const Options* opt = nullptr, - Mesh* m = nullptr, CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); + Mesh* m = nullptr, CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0) const; /// Parse a string into a tree of generators - FieldGeneratorPtr parse(const std::string& input, const Options* opt = nullptr); + FieldGeneratorPtr parse(const std::string& input, const Options* opt = nullptr) const; /// Create a 2D field from a generator, over a given mesh /// at a given cell location and time. Field2D create2D(FieldGeneratorPtr generator, Mesh* m = nullptr, - CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); + CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0) const; /// Create a 3D field from a generator, over a given mesh /// at a given cell location and time. Field3D create3D(FieldGeneratorPtr generator, Mesh* m = nullptr, - CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0); + CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0) const; /// Get the Singleton object static FieldFactory* get(); @@ -90,23 +90,25 @@ public: protected: /// These functions called by the parser to resolve unknown symbols. /// This is used to enable options to be referred to in expressions. - FieldGeneratorPtr resolve(std::string& name) override; + FieldGeneratorPtr resolve(std::string& name) const override; private: /// The default mesh for create functions. Mesh* fieldmesh; - /// The default options used in resolve(), can be overridden in - /// parse()/create2D()/create3D() - const Options* options; - std::list lookup; // Names currently being parsed + /// The default options used in resolve(), can be *temporarily* + /// overridden in parse()/create2D()/create3D() + mutable const Options* options; + + /// Names currently being parsed + mutable std::list lookup; /// Cache parsed strings so repeated evaluations /// don't result in allocating more generators. - std::map cache; + mutable std::map cache; const Options* findOption(const Options* opt, const std::string& name, - std::string& val); + std::string& val) const; }; ////////////////////////////////////////////////////////// diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 46d1e7eda0..0d2861ce9d 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -95,12 +95,12 @@ FieldFactory::FieldFactory(Mesh* localmesh, Options* opt) } Field2D FieldFactory::create2D(const std::string& value, const Options* opt, - Mesh* localmesh, CELL_LOC loc, BoutReal t) { + Mesh* localmesh, CELL_LOC loc, BoutReal t) const { return create2D(parse(value, opt), localmesh, loc, t); } Field2D FieldFactory::create2D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC loc, - BoutReal t) { + BoutReal t) const { AUTO_TRACE(); if (localmesh == nullptr) { @@ -149,12 +149,12 @@ Field2D FieldFactory::create2D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC } Field3D FieldFactory::create3D(const std::string& value, const Options* opt, - Mesh* localmesh, CELL_LOC loc, BoutReal t) { + Mesh* localmesh, CELL_LOC loc, BoutReal t) const { return create3D(parse(value, opt), localmesh, loc, t); } Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC loc, - BoutReal t) { + BoutReal t) const { AUTO_TRACE(); if (localmesh == nullptr) { @@ -225,7 +225,7 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC } const Options* FieldFactory::findOption(const Options* opt, const std::string& name, - std::string& val) { + std::string& val) const { // Find an Options object which contains the given name const Options* result = opt; @@ -270,7 +270,7 @@ const Options* FieldFactory::findOption(const Options* opt, const std::string& n return result; } -FieldGeneratorPtr FieldFactory::resolve(std::string& name) { +FieldGeneratorPtr FieldFactory::resolve(std::string& name) const { if (options != nullptr) { // Check if in cache std::string key; @@ -326,7 +326,7 @@ FieldGeneratorPtr FieldFactory::resolve(std::string& name) { return nullptr; } -FieldGeneratorPtr FieldFactory::parse(const std::string& input, const Options* opt) { +FieldGeneratorPtr FieldFactory::parse(const std::string& input, const Options* opt) const { // Check if in the cache std::string key = "#" + input; diff --git a/src/sys/expressionparser.cxx b/src/sys/expressionparser.cxx index d8645bf828..e07d640285 100644 --- a/src/sys/expressionparser.cxx +++ b/src/sys/expressionparser.cxx @@ -132,7 +132,7 @@ void ExpressionParser::addBinaryOp(char sym, FieldGeneratorPtr b, int precedence reserved_chars += sym; } -FieldGeneratorPtr ExpressionParser::parseString(const string &input) { +FieldGeneratorPtr ExpressionParser::parseString(const string &input) const { // Allocate a new lexer LexInfo lex(input, reserved_chars); @@ -143,7 +143,7 @@ FieldGeneratorPtr ExpressionParser::parseString(const string &input) { ////////////////////////////////////////////////////////// // Private functions -FieldGeneratorPtr ExpressionParser::parseIdentifierExpr(LexInfo &lex) { +FieldGeneratorPtr ExpressionParser::parseIdentifierExpr(LexInfo &lex) const { string name = lowercase(lex.curident); lex.nextToken(); @@ -196,7 +196,7 @@ FieldGeneratorPtr ExpressionParser::parseIdentifierExpr(LexInfo &lex) { } } -FieldGeneratorPtr ExpressionParser::parseParenExpr(LexInfo &lex) { +FieldGeneratorPtr ExpressionParser::parseParenExpr(LexInfo &lex) const { lex.nextToken(); // eat '(' FieldGeneratorPtr g = parseExpression(lex); @@ -209,7 +209,7 @@ FieldGeneratorPtr ExpressionParser::parseParenExpr(LexInfo &lex) { return g; } -FieldGeneratorPtr ExpressionParser::parsePrimary(LexInfo &lex) { +FieldGeneratorPtr ExpressionParser::parsePrimary(LexInfo &lex) const { switch(lex.curtok) { case -1: { // a number lex.nextToken(); // Eat number @@ -231,7 +231,7 @@ FieldGeneratorPtr ExpressionParser::parsePrimary(LexInfo &lex) { static_cast(lex.curtok), lex.curtok); } -FieldGeneratorPtr ExpressionParser::parseBinOpRHS(LexInfo &lex, int ExprPrec, FieldGeneratorPtr lhs) { +FieldGeneratorPtr ExpressionParser::parseBinOpRHS(LexInfo &lex, int ExprPrec, FieldGeneratorPtr lhs) const { while(true) { // Check for end of input @@ -282,7 +282,7 @@ FieldGeneratorPtr ExpressionParser::parseBinOpRHS(LexInfo &lex, int ExprPrec, Fi } } -FieldGeneratorPtr ExpressionParser::parseExpression(LexInfo &lex) { +FieldGeneratorPtr ExpressionParser::parseExpression(LexInfo &lex) const { FieldGeneratorPtr lhs = parsePrimary(lex); return parseBinOpRHS(lex, 0, lhs); } From 346dce955ccc59d587c33e5f01945882c3d161dc Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 11:48:54 +0000 Subject: [PATCH 0846/1783] Clang-format expressionparser --- include/bout/sys/expressionparser.hxx | 72 ++++--- src/sys/expressionparser.cxx | 287 +++++++++++++------------- 2 files changed, 177 insertions(+), 182 deletions(-) diff --git a/include/bout/sys/expressionparser.hxx b/include/bout/sys/expressionparser.hxx index bc6566ff14..9b885781c6 100644 --- a/include/bout/sys/expressionparser.hxx +++ b/include/bout/sys/expressionparser.hxx @@ -1,12 +1,12 @@ /*!************************************************************************ * \file expressionparser.hxx - * + * * Parses strings containing expressions, returning a tree of generators - * + * * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -24,23 +24,20 @@ * **************************************************************************/ -class FieldGenerator; -class ExpressionParser; -class ParseException; - #ifndef __EXPRESSION_PARSER_H__ #define __EXPRESSION_PARSER_H__ #include "unused.hxx" -#include -#include +#include #include -#include -#include +#include #include -#include +#include +#include +#include +class FieldGenerator; using FieldGeneratorPtr = std::shared_ptr; ////////////////////////////////////////////////////////// @@ -91,7 +88,7 @@ public: /// @param[in] g The class inheriting from FieldGenerator. When recognised /// in an expression, the clone() function will be called /// to build a tree of generators - void addGenerator(const std::string &name, FieldGeneratorPtr g); + void addGenerator(const std::string& name, FieldGeneratorPtr g); /// Add a binary operator such as +,-,*,/,^ /// @@ -105,41 +102,42 @@ public: /// +, - precedence = 10 /// *, / precedence = 20 /// ^ precedence = 30 - /// + /// void addBinaryOp(char sym, FieldGeneratorPtr b, int precedence); + protected: /// This will be called to resolve any unknown symbols - virtual FieldGeneratorPtr resolve(std::string &UNUSED(name)) const { return nullptr; } + virtual FieldGeneratorPtr resolve(std::string& UNUSED(name)) const { return nullptr; } /// Parses a given string into a tree of FieldGenerator objects - FieldGeneratorPtr parseString(const std::string &input) const; + FieldGeneratorPtr parseString(const std::string& input) const; /// Characters which cannot be used in symbols; all other allowed /// In addition, whitespace cannot be used /// Adding a binary operator adds its symbol to this string std::string reserved_chars = "+-*/^[](){},"; - + private: - - std::map gen; ///< Generators, addressed by name + std::map gen; ///< Generators, addressed by name std::map> bin_op; ///< Binary operations - + /// Lexing info, used when splitting input into tokens struct LexInfo { - - LexInfo(const std::string &input, const std::string &reserved_chars=""); - - signed char curtok = 0; ///< Current token. -1 for number, -2 for string, 0 for "end of input" + + LexInfo(const std::string& input, const std::string& reserved_chars = ""); + + /// Current token. -1 for number, -2 for string, 0 for "end of input" + signed char curtok = 0; double curval; ///< Value if a number - std::string curident; ///< Identifier, variable or function name - signed char LastChar; ///< The last character read from the string - std::stringstream ss; ///< Used to read values from the input string + std::string curident; ///< Identifier, variable or function name + signed char LastChar; ///< The last character read from the string + std::stringstream ss; ///< Used to read values from the input string std::string reserved_chars; ///< Reserved characters, not in symbols - char nextToken(); ///< Get the next token in the string + char nextToken(); ///< Get the next token in the string }; - - FieldGeneratorPtr parseIdentifierExpr(LexInfo &lex) const; - FieldGeneratorPtr parseParenExpr(LexInfo &lex) const; + + FieldGeneratorPtr parseIdentifierExpr(LexInfo& lex) const; + FieldGeneratorPtr parseParenExpr(LexInfo& lex) const; /// Parse a primary expression, one of: /// - number @@ -148,9 +146,9 @@ private: /// - [ ... ] /// - a unary '-', which is converted to '0 -' /// A ParseException is thrown if none of these is found - FieldGeneratorPtr parsePrimary(LexInfo &lex) const; - FieldGeneratorPtr parseBinOpRHS(LexInfo &lex, int prec, FieldGeneratorPtr lhs) const; - FieldGeneratorPtr parseExpression(LexInfo &lex) const; + FieldGeneratorPtr parsePrimary(LexInfo& lex) const; + FieldGeneratorPtr parseBinOpRHS(LexInfo& lex, int prec, FieldGeneratorPtr lhs) const; + FieldGeneratorPtr parseExpression(LexInfo& lex) const; }; ////////////////////////////////////////////////////// @@ -191,6 +189,7 @@ public: ss << value; return ss.str(); } + private: double value; }; @@ -199,14 +198,13 @@ private: class ParseException : public std::exception { public: - ParseException(const char *, ...); + ParseException(const char*, ...); ~ParseException() override = default; - const char *what() const noexcept override; + const char* what() const noexcept override; protected: std::string message; }; - #endif // __EXPRESSION_PARSER_H__ diff --git a/src/sys/expressionparser.cxx b/src/sys/expressionparser.cxx index e07d640285..37bdab53f7 100644 --- a/src/sys/expressionparser.cxx +++ b/src/sys/expressionparser.cxx @@ -1,10 +1,10 @@ /************************************************************************** * Parses strings containing expressions, returning a tree of generators - * + * * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -26,74 +26,74 @@ #include // for lowercase -using std::string; using std::list; +using std::string; using std::stringstream; ///////////////////////////////////////////// namespace { // These classes only visible in this file - - // Basic generators: Numerical value, 'x', 'y' and 'z' - - class FieldX : public FieldGenerator { - public: - FieldGeneratorPtr clone(const list UNUSED(args)) override { - return std::make_shared(); - } - double generate(double x, double UNUSED(y), double UNUSED(z), - double UNUSED(t)) override { - return x; - } - std::string str() const override { return std::string("x"); } - }; - - class FieldY : public FieldGenerator { - public: - FieldGeneratorPtr clone(const list UNUSED(args)) override { - return std::make_shared(); - } - double generate(double UNUSED(x), double y, double UNUSED(z), - double UNUSED(t)) override { - return y; - } - std::string str() const override { return std::string("y"); } - }; - class FieldZ : public FieldGenerator { - public: - FieldGeneratorPtr clone(const list UNUSED(args)) override { - return std::make_shared(); - } - double generate(double UNUSED(x), double UNUSED(y), double z, - double UNUSED(t)) override { - return z; - } - std::string str() const override { return std::string("z"); } - }; - - class FieldT : public FieldGenerator { - public: - FieldGeneratorPtr clone(const list UNUSED(args)) override { - return std::make_shared(); - } - double generate(double UNUSED(x), double UNUSED(y), double UNUSED(z), - double t) override { - return t; - } - std::string str() const override { return std::string("t"); } - }; -} +// Basic generators: Numerical value, 'x', 'y' and 'z' + +class FieldX : public FieldGenerator { +public: + FieldGeneratorPtr clone(const list UNUSED(args)) override { + return std::make_shared(); + } + double generate(double x, double UNUSED(y), double UNUSED(z), + double UNUSED(t)) override { + return x; + } + std::string str() const override { return std::string("x"); } +}; + +class FieldY : public FieldGenerator { +public: + FieldGeneratorPtr clone(const list UNUSED(args)) override { + return std::make_shared(); + } + double generate(double UNUSED(x), double y, double UNUSED(z), + double UNUSED(t)) override { + return y; + } + std::string str() const override { return std::string("y"); } +}; + +class FieldZ : public FieldGenerator { +public: + FieldGeneratorPtr clone(const list UNUSED(args)) override { + return std::make_shared(); + } + double generate(double UNUSED(x), double UNUSED(y), double z, + double UNUSED(t)) override { + return z; + } + std::string str() const override { return std::string("z"); } +}; + +class FieldT : public FieldGenerator { +public: + FieldGeneratorPtr clone(const list UNUSED(args)) override { + return std::make_shared(); + } + double generate(double UNUSED(x), double UNUSED(y), double UNUSED(z), + double t) override { + return t; + } + std::string str() const override { return std::string("t"); } +}; +} // namespace FieldGeneratorPtr FieldBinary::clone(const list args) { - if(args.size() != 2) + if (args.size() != 2) throw ParseException("Binary operator expecting 2 arguments. Got '%d'", args.size()); - + return std::make_shared(args.front(), args.back(), op); } BoutReal FieldBinary::generate(double x, double y, double z, double t) { - BoutReal lval = lhs->generate(x,y,z,t); - BoutReal rval = rhs->generate(x,y,z,t); + BoutReal lval = lhs->generate(x, y, z, t); + BoutReal rval = rhs->generate(x, y, z, t); switch(op) { case '+': return lval + rval; case '-': return lval - rval; @@ -114,7 +114,7 @@ ExpressionParser::ExpressionParser() { addBinaryOp('*', std::make_shared(nullptr, nullptr, '*'), 20); addBinaryOp('/', std::make_shared(nullptr, nullptr, '/'), 20); addBinaryOp('^', std::make_shared(nullptr, nullptr, '^'), 30); - + // Add standard generators addGenerator("x", std::make_shared()); addGenerator("y", std::make_shared()); @@ -122,17 +122,17 @@ ExpressionParser::ExpressionParser() { addGenerator("t", std::make_shared()); } -void ExpressionParser::addGenerator(const string &name, FieldGeneratorPtr g) { +void ExpressionParser::addGenerator(const string& name, FieldGeneratorPtr g) { gen[name] = g; } void ExpressionParser::addBinaryOp(char sym, FieldGeneratorPtr b, int precedence) { bin_op[sym] = std::make_pair(b, precedence); // Add to string of reserved characters - reserved_chars += sym; + reserved_chars += sym; } -FieldGeneratorPtr ExpressionParser::parseString(const string &input) const { +FieldGeneratorPtr ExpressionParser::parseString(const string& input) const { // Allocate a new lexer LexInfo lex(input, reserved_chars); @@ -143,51 +143,51 @@ FieldGeneratorPtr ExpressionParser::parseString(const string &input) const { ////////////////////////////////////////////////////////// // Private functions -FieldGeneratorPtr ExpressionParser::parseIdentifierExpr(LexInfo &lex) const { +FieldGeneratorPtr ExpressionParser::parseIdentifierExpr(LexInfo& lex) const { string name = lowercase(lex.curident); lex.nextToken(); - - if(lex.curtok == '(') { + + if (lex.curtok == '(') { // Argument list. Find if a generator or function - + auto it = gen.find(name); - if(it == gen.end()) + if (it == gen.end()) throw ParseException("Couldn't find generator '%s'", name.c_str()); - + // Parse arguments (if any) list args; - + lex.nextToken(); - if(lex.curtok == ')') { + if (lex.curtok == ')') { // Empty list lex.nextToken(); return it->second->clone(args); } - do{ + do { // Should be an expression args.push_back(parseExpression(lex)); - + // Now either a comma or ')' - - if(lex.curtok == ')') { + + if (lex.curtok == ')') { // Finished list lex.nextToken(); return it->second->clone(args); } - if(lex.curtok != ',') { + if (lex.curtok != ',') { throw ParseException("Expecting ',' or ')' in function argument list (%s)\n", name.c_str()); } lex.nextToken(); - }while(true); - - }else { + } while (true); + + } else { // No arguments. Search in generator list auto it = gen.find(name); - if(it == gen.end()) { + if (it == gen.end()) { // Not in internal map. Try to resolve FieldGeneratorPtr g = resolve(name); - if(g == nullptr) + if (g == nullptr) throw ParseException("Couldn't find generator '%s'", name.c_str()); return g; } @@ -196,9 +196,9 @@ FieldGeneratorPtr ExpressionParser::parseIdentifierExpr(LexInfo &lex) const { } } -FieldGeneratorPtr ExpressionParser::parseParenExpr(LexInfo &lex) const { +FieldGeneratorPtr ExpressionParser::parseParenExpr(LexInfo& lex) const { lex.nextToken(); // eat '(' - + FieldGeneratorPtr g = parseExpression(lex); if ((lex.curtok != ')') && (lex.curtok != ']')) @@ -209,9 +209,9 @@ FieldGeneratorPtr ExpressionParser::parseParenExpr(LexInfo &lex) const { return g; } -FieldGeneratorPtr ExpressionParser::parsePrimary(LexInfo &lex) const { - switch(lex.curtok) { - case -1: { // a number +FieldGeneratorPtr ExpressionParser::parsePrimary(LexInfo& lex) const { + switch (lex.curtok) { + case -1: { // a number lex.nextToken(); // Eat number return std::make_shared(lex.curval); } @@ -227,53 +227,54 @@ FieldGeneratorPtr ExpressionParser::parsePrimary(LexInfo &lex) const { case '[': return parseParenExpr(lex); } - throw ParseException("Unexpected token %d (%c)", - static_cast(lex.curtok), lex.curtok); + throw ParseException("Unexpected token %d (%c)", static_cast(lex.curtok), + lex.curtok); } -FieldGeneratorPtr ExpressionParser::parseBinOpRHS(LexInfo &lex, int ExprPrec, FieldGeneratorPtr lhs) const { - - while(true) { +FieldGeneratorPtr ExpressionParser::parseBinOpRHS(LexInfo& lex, int ExprPrec, + FieldGeneratorPtr lhs) const { + + while (true) { // Check for end of input - if((lex.curtok == 0) || (lex.curtok == ')') || (lex.curtok == ',')) + if ((lex.curtok == 0) || (lex.curtok == ')') || (lex.curtok == ',')) return lhs; - + // Next token should be a binary operator auto it = bin_op.find(lex.curtok); - - if(it == bin_op.end()) + + if (it == bin_op.end()) throw ParseException("Unexpected binary operator '%c'", lex.curtok); - + FieldGeneratorPtr op = it->second.first; int TokPrec = it->second.second; - + if (TokPrec < ExprPrec) return lhs; - + lex.nextToken(); // Eat binop - + FieldGeneratorPtr rhs = parsePrimary(lex); - - if((lex.curtok == 0) || (lex.curtok == ')') || (lex.curtok == ',')) { + + if ((lex.curtok == 0) || (lex.curtok == ')') || (lex.curtok == ',')) { // Done - + list args; args.push_front(lhs); args.push_back(rhs); return op->clone(args); } - + // Find next binop it = bin_op.find(lex.curtok); - - if(it == bin_op.end()) + + if (it == bin_op.end()) throw ParseException("Unexpected character '%c'", lex.curtok); - + int NextPrec = it->second.second; if (TokPrec < NextPrec) { - rhs = parseBinOpRHS(lex, TokPrec+1, rhs); + rhs = parseBinOpRHS(lex, TokPrec + 1, rhs); } - + // Merge lhs and rhs into new lhs list args; args.push_front(lhs); @@ -282,7 +283,7 @@ FieldGeneratorPtr ExpressionParser::parseBinOpRHS(LexInfo &lex, int ExprPrec, Fi } } -FieldGeneratorPtr ExpressionParser::parseExpression(LexInfo &lex) const { +FieldGeneratorPtr ExpressionParser::parseExpression(LexInfo& lex) const { FieldGeneratorPtr lhs = parsePrimary(lex); return parseBinOpRHS(lex, 0, lhs); } @@ -290,8 +291,8 @@ FieldGeneratorPtr ExpressionParser::parseExpression(LexInfo &lex) const { ////////////////////////////////////////////////////////// // LexInfo -ExpressionParser::LexInfo::LexInfo(const std::string &input, - const std::string &reserved_chars) +ExpressionParser::LexInfo::LexInfo(const std::string& input, + const std::string& reserved_chars) : reserved_chars(reserved_chars) { ss.clear(); ss.str(input); // Set the input stream @@ -304,49 +305,50 @@ ExpressionParser::LexInfo::LexInfo(const std::string &input, char ExpressionParser::LexInfo::nextToken() { while (isspace(LastChar)) LastChar = static_cast(ss.get()); - - if(!ss.good()) { + + if (!ss.good()) { curtok = 0; return 0; } // Handle numbers - if (isdigit(LastChar) || (LastChar == '.')) { // Number: [0-9.]+ + if (isdigit(LastChar) || (LastChar == '.')) { // Number: [0-9.]+ bool gotdecimal = false, gotexponent = false; std::string NumStr; - - while(true) { - if(LastChar == '.') { - if(gotdecimal || gotexponent) { + + while (true) { + if (LastChar == '.') { + if (gotdecimal || gotexponent) { throw ParseException("Unexpected '.' in number expression"); } gotdecimal = true; - }else if((LastChar == 'E') || (LastChar == 'e')) { - if(gotexponent) { - throw ParseException("ExpressionParser error: Unexpected extra 'e' in number expression"); + } else if ((LastChar == 'E') || (LastChar == 'e')) { + if (gotexponent) { + throw ParseException( + "ExpressionParser error: Unexpected extra 'e' in number expression"); } gotexponent = true; // Next character should be a '+' or '-' or digit NumStr += 'e'; LastChar = static_cast(ss.get()); - if((LastChar != '+') && (LastChar != '-') && !isdigit(LastChar)) { - throw ParseException("ExpressionParser error: Expecting '+', '-' or number after 'e'"); + if ((LastChar != '+') && (LastChar != '-') && !isdigit(LastChar)) { + throw ParseException( + "ExpressionParser error: Expecting '+', '-' or number after 'e'"); } - }else if(!isdigit(LastChar)) + } else if (!isdigit(LastChar)) break; - + NumStr += LastChar; LastChar = static_cast(ss.get()); } - + curval = std::stod(NumStr); curtok = -1; return curtok; } - + // Symbols can contain anything else which is not reserved - if ((LastChar == '`') || - (reserved_chars.find(LastChar) == std::string::npos)) { + if ((LastChar == '`') || (reserved_chars.find(LastChar) == std::string::npos)) { // Special case: If the last token returned was a number // then insert a multiplication ("*") @@ -354,7 +356,7 @@ char ExpressionParser::LexInfo::nextToken() { curtok = '*'; return curtok; } - + curident.clear(); do { if (LastChar == '\\') { @@ -367,7 +369,7 @@ char ExpressionParser::LexInfo::nextToken() { if (LastChar == EOF) { throw ParseException("Unexpected end of input after \\ character"); } - + curident += LastChar; } else if (LastChar == '`') { // An escaped symbol @@ -385,10 +387,9 @@ char ExpressionParser::LexInfo::nextToken() { curident += LastChar; } LastChar = static_cast(ss.get()); - } while ( (LastChar != EOF && - !isspace(LastChar) && - (reserved_chars.find(LastChar) == std::string::npos)) - || (LastChar == '\\') || (LastChar == '`')); + } while ((LastChar != EOF && !isspace(LastChar) + && (reserved_chars.find(LastChar) == std::string::npos)) + || (LastChar == '\\') || (LastChar == '`')); curtok = -2; return curtok; } @@ -401,7 +402,7 @@ char ExpressionParser::LexInfo::nextToken() { return curtok; } } - + // LastChar is unsigned, explicitly cast curtok = LastChar; LastChar = static_cast(ss.get()); @@ -411,20 +412,16 @@ char ExpressionParser::LexInfo::nextToken() { ////////////////////////////////////////////////////////// // ParseException - -ParseException::ParseException(const char *s, ...) { - if(s == nullptr) +ParseException::ParseException(const char* s, ...) { + if (s == nullptr) return; - int buf_len=1024; - char * buffer= new char[buf_len]; - bout_vsnprintf(buffer,buf_len, s); - + int buf_len = 1024; + char* buffer = new char[buf_len]; + bout_vsnprintf(buffer, buf_len, s); + message.assign(buffer); delete[] buffer; } -const char* ParseException::what() const noexcept { - return message.c_str(); -} - +const char* ParseException::what() const noexcept { return message.c_str(); } From 96f6c81632f07f5a1ab237fbcc3e87771ff34922 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 11:49:09 +0000 Subject: [PATCH 0847/1783] Move function docstring to declaration --- include/field_factory.hxx | 1 + src/field/field_factory.cxx | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/field_factory.hxx b/include/field_factory.hxx index 256b1ed4fd..92599b2c89 100644 --- a/include/field_factory.hxx +++ b/include/field_factory.hxx @@ -107,6 +107,7 @@ private: /// don't result in allocating more generators. mutable std::map cache; + /// Find an Options object which contains the given \p name const Options* findOption(const Options* opt, const std::string& name, std::string& val) const; }; diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 0d2861ce9d..b83b9ee20c 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -226,8 +226,6 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC const Options* FieldFactory::findOption(const Options* opt, const std::string& name, std::string& val) const { - // Find an Options object which contains the given name - const Options* result = opt; // Check if name contains a section separator ':' From 208e7b6916a6da1a9f44f2d99e04967951e6c707 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 11:49:18 +0000 Subject: [PATCH 0848/1783] Use output_error instead of output for error message --- src/field/field_factory.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index b83b9ee20c..46f15e47f8 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -295,11 +295,11 @@ FieldGeneratorPtr FieldFactory::resolve(std::string& name) const { for (const auto& lookup_value : lookup) { if (key.compare(lookup_value) == 0) { // Name matches, so already looking up - output << "ExpressionParser lookup stack:\n"; + output_error << "ExpressionParser lookup stack:\n"; for (const auto& stack_value : lookup) { - output << stack_value << " -> "; + output_error << stack_value << " -> "; } - output << name << endl; + output_error << name << endl; throw BoutException("ExpressionParser: Infinite recursion in parsing '%s'", name.c_str()); } From ebdbc77d98f6f0b234877dc462914860b17597fd Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 21 Feb 2019 12:42:36 +0000 Subject: [PATCH 0849/1783] Set the default REGION of toFieldAligned and fromFieldAligned to RGN_ALL --- include/bout/fv_ops.hxx | 8 ++++---- include/bout/index_derivs_interface.hxx | 14 +++++++------- include/bout/mesh.hxx | 8 ++++---- include/bout/paralleltransform.hxx | 8 ++++---- include/interpolation.hxx | 2 +- src/invert/parderiv/impls/cyclic/cyclic.cxx | 2 +- src/mesh/difops.cxx | 8 ++++---- src/mesh/fv_ops.cxx | 10 +++++----- 8 files changed, 30 insertions(+), 30 deletions(-) diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index 9a6070238f..96d701a8af 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -189,8 +189,8 @@ namespace FV { CellEdges cellboundary; - Field3D f = mesh->toFieldAligned(f_in); - Field3D v = mesh->toFieldAligned(v_in); + Field3D f = mesh->toFieldAligned(f_in, RGN_NOX); + Field3D v = mesh->toFieldAligned(v_in, RGN_NOX); Coordinates *coord = f_in.getCoordinates(); @@ -471,8 +471,8 @@ namespace FV { // Currently just using simple centered differences // so no fluxes need to be exchanged - n = mesh->toFieldAligned(n_in); - Field3D vy = mesh->toFieldAligned(v.y); + n = mesh->toFieldAligned(n_in, RGN_NOX); + Field3D vy = mesh->toFieldAligned(v.y, RGN_NOX); Field3D yresult = 0.0; for(int i=mesh->xstart;i<=mesh->xend;i++) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index c20b23f1c2..aa8177189b 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -211,7 +211,7 @@ T DDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "D return standardDerivative(f, outloc, method, region); } else { - const T f_aligned = f.getMesh()->toFieldAligned(f); + const T f_aligned = f.getMesh()->toFieldAligned(f, RGN_NOX); T result = standardDerivative(f_aligned, outloc, method, region); return f.getMesh()->fromFieldAligned(result, region); @@ -226,7 +226,7 @@ T D2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = return standardDerivative( f, outloc, method, region); } else { - const T f_aligned = f.getMesh()->toFieldAligned(f); + const T f_aligned = f.getMesh()->toFieldAligned(f, RGN_NOX); T result = standardDerivative( f_aligned, outloc, method, region); return f.getMesh()->fromFieldAligned(result, region); @@ -241,7 +241,7 @@ T D4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = return standardDerivative( f, outloc, method, region); } else { - const T f_aligned = f.getMesh()->toFieldAligned(f); + const T f_aligned = f.getMesh()->toFieldAligned(f, RGN_NOX); T result = standardDerivative( f_aligned, outloc, method, region); return f.getMesh()->fromFieldAligned(result, region); @@ -315,8 +315,8 @@ T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, return flowDerivative(vel, f, outloc, method, region); } else { - const T f_aligned = f.getMesh()->toFieldAligned(f); - const T vel_aligned = vel.getMesh()->toFieldAligned(vel); + const T f_aligned = f.getMesh()->toFieldAligned(f, RGN_NOX); + const T vel_aligned = vel.getMesh()->toFieldAligned(vel, RGN_NOX); T result = flowDerivative(vel_aligned, f_aligned, outloc, method, region); return f.getMesh()->fromFieldAligned(result, region); @@ -333,8 +333,8 @@ T FDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, return flowDerivative(vel, f, outloc, method, region); } else { - const T f_aligned = f.getMesh()->toFieldAligned(f); - const T vel_aligned = vel.getMesh()->toFieldAligned(vel); + const T f_aligned = f.getMesh()->toFieldAligned(f, RGN_NOX); + const T vel_aligned = vel.getMesh()->toFieldAligned(vel, RGN_NOX); T result = flowDerivative(vel_aligned, f_aligned, outloc, method, region); return f.getMesh()->fromFieldAligned(result, region); diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 8f5cd93594..9ad19d4251 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -702,18 +702,18 @@ class Mesh { /////////////////////////////////////////////////////////// /// Transform a field into field-aligned coordinates - const Field3D toFieldAligned(const Field3D &f, const REGION region = RGN_NOX) { + const Field3D toFieldAligned(const Field3D &f, const REGION region = RGN_ALL) { return getParallelTransform().toFieldAligned(f, region); } - const Field2D toFieldAligned(const Field2D &f, const REGION UNUSED(region) = RGN_NOX) { + const Field2D toFieldAligned(const Field2D &f, const REGION UNUSED(region) = RGN_ALL) { return f; } /// Convert back into standard form - const Field3D fromFieldAligned(const Field3D &f, const REGION region = RGN_NOX) { + const Field3D fromFieldAligned(const Field3D &f, const REGION region = RGN_ALL) { return getParallelTransform().fromFieldAligned(f, region); } - const Field2D fromFieldAligned(const Field2D &f, const REGION UNUSED(region) = RGN_NOX) { + const Field2D fromFieldAligned(const Field2D &f, const REGION UNUSED(region) = RGN_ALL) { return f; } diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 5e75e3422c..c533abc887 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -38,11 +38,11 @@ public: /// Convert a 3D field into field-aligned coordinates /// so that the y index is along the magnetic field - virtual const Field3D toFieldAligned(const Field3D &f, const REGION region = RGN_NOX) = 0; + virtual const Field3D toFieldAligned(const Field3D &f, const REGION region = RGN_ALL) = 0; /// Convert back from field-aligned coordinates /// into standard form - virtual const Field3D fromFieldAligned(const Field3D &f, const REGION region = RGN_NOX) = 0; + virtual const Field3D fromFieldAligned(const Field3D &f, const REGION region = RGN_ALL) = 0; virtual bool canToFromFieldAligned() = 0; @@ -126,13 +126,13 @@ public: * in X-Z, and the metric tensor will need to be changed * if X derivatives are used. */ - const Field3D toFieldAligned(const Field3D &f, const REGION region=RGN_NOX) override; + const Field3D toFieldAligned(const Field3D &f, const REGION region=RGN_ALL) override; /*! * Converts a field back to X-Z orthogonal coordinates * from field aligned coordinates. */ - const Field3D fromFieldAligned(const Field3D &f, const REGION region=RGN_NOX) override; + const Field3D fromFieldAligned(const Field3D &f, const REGION region=RGN_ALL) override; bool canToFromFieldAligned() override{ return true; diff --git a/include/interpolation.hxx b/include/interpolation.hxx index 17979f49ea..9ecd3a069e 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -121,7 +121,7 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { // We can't interpolate in y unless we're field-aligned // FIXME: Add check once we label fields as orthogonal/aligned - const T var_fa = fieldmesh->toFieldAligned(var); + const T var_fa = fieldmesh->toFieldAligned(var, RGN_NOX); if (region != RGN_NOBNDRY) { // repeat the hack above for boundary points // this avoids a duplicate toFieldAligned call if we had called diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index 57537519d4..202341d87e 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -67,7 +67,7 @@ const Field3D InvertParCR::solve(const Field3D &f) { Coordinates *coord = f.getCoordinates(); - Field3D alignedField = localmesh->toFieldAligned(f); + Field3D alignedField = localmesh->toFieldAligned(f, RGN_NOX); // Create cyclic reduction object CyclicReduce *cr = diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index 40e1a08f20..c4738c4531 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -296,7 +296,7 @@ const Field3D Grad_par_CtoL(const Field3D &var) { } } else { // No yup/ydown fields, so transform to cell centred - Field3D var_fa = mesh->toFieldAligned(var); + Field3D var_fa = mesh->toFieldAligned(var, RGN_NOX); for(int jx=0; jxLocalNx;jx++) { for(int jy=1;jyLocalNy;jy++) { @@ -368,8 +368,8 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg // (even if one of v and f has yup/ydown fields, it doesn't make sense to // multiply them with one in field-aligned and one in non-field-aligned // coordinates) - Field3D v_fa = vMesh->toFieldAligned(v); - Field3D f_fa = vMesh->toFieldAligned(f); + Field3D v_fa = vMesh->toFieldAligned(v, RGN_NOX); + Field3D f_fa = vMesh->toFieldAligned(f, RGN_NOX); BOUT_OMP(parallel) { stencil fval, vval; @@ -415,7 +415,7 @@ const Field3D Grad_par_LtoC(const Field3D &var) { } else { // No yup/ydown field, so transform to field aligned - Field3D var_fa = varMesh->toFieldAligned(var); + Field3D var_fa = varMesh->toFieldAligned(var, RGN_NOX); BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { result[i] = (var_fa[i.yp()] - var_fa[i]) / (metric->dy[i]*sqrt(metric->g_22[i])); diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index 3ad5f79075..2ecebed966 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -124,8 +124,8 @@ namespace FV { bool use_yup_ydown = (Kin.hasYupYdown() && fin.hasYupYdown()); - const auto& K = use_yup_ydown ? Kin : mesh->toFieldAligned(Kin); - const auto& f = use_yup_ydown ? fin : mesh->toFieldAligned(fin); + const auto& K = use_yup_ydown ? Kin : mesh->toFieldAligned(Kin, RGN_NOX); + const auto& f = use_yup_ydown ? fin : mesh->toFieldAligned(fin, RGN_NOX); // K and f fields in yup and ydown directions const auto& Kup = use_yup_ydown ? Kin.yup() : K; @@ -189,8 +189,8 @@ namespace FV { Coordinates *coord = f_in.getCoordinates(); // Convert to field aligned coordinates - Field3D d = mesh->toFieldAligned(d_in); - Field3D f = mesh->toFieldAligned(f_in); + Field3D d = mesh->toFieldAligned(d_in, RGN_NOX); + Field3D f = mesh->toFieldAligned(f_in, RGN_NOX); for(int i=mesh->xstart;i<=mesh->xend;i++) for(int j=mesh->ystart;j<=mesh->yend;j++) { @@ -239,7 +239,7 @@ namespace FV { Mesh* mesh = f_in.getMesh(); // Convert to field aligned coordinates - Field3D f = mesh->toFieldAligned(f_in); + Field3D f = mesh->toFieldAligned(f_in, RGN_NOX); Coordinates *coord = f_in.getCoordinates(); From be9cd55532abae29832b3c0c91ff309287bb920b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 21 Feb 2019 12:47:23 +0000 Subject: [PATCH 0850/1783] Add comment on shuffling input for ShiftedMetric unit test --- tests/unit/mesh/parallel/test_shiftedmetric.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index d8c801aed0..a823397bc8 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -42,6 +42,10 @@ class ShiftedMetricTest : public ::testing::Test { Field3D input_temp{mesh}; + // input values have been slightly shuffled to ensure that input is not + // constant in y, as this can hide bugs. Shuffling also means the rows are + // different by something that is not a shift in the z-direction to ensure + // that this also cannot hide bugs. fillField(input_temp, {{{1., 2., 3., 4., 5.}, {2., 1., 3., 4., 5.}, {1., 3., 2., 4., 5.}, From adf7c66f7143f1911206e896c6986236cc1cbb4a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 21 Feb 2019 12:55:42 +0000 Subject: [PATCH 0851/1783] Cache i.x() and i.y() outside z-loops in ShiftedMetric --- src/mesh/parallel/shiftedmetric.cxx | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index b1acac51b9..40d0fd3382 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -75,11 +75,13 @@ void ShiftedMetric::cachePhases() { //To/From field aligned phases BOUT_FOR(i, mesh.getRegion2D("RGN_ALL")) { + int ix = i.x(); + int iy = i.y(); for(int jz=0;jz(nmodes); BOUT_FOR(i, mesh.getRegion2D("RGN_ALL")) { - f_fft(i.x(), i.y()).ensureUnique(); - rfft(&f(i, 0), mesh.LocalNz, f_fft(i.x(), i.y()).begin()); + int ix = i.x(); + int iy = i.y(); + f_fft(ix, iy).ensureUnique(); + rfft(&f(i, 0), mesh.LocalNz, f_fft(ix, iy).begin()); } std::vector results{}; @@ -223,11 +229,14 @@ ShiftedMetric::shiftZ(const Field3D& f, BOUT_FOR(i, mesh.getRegion2D("RGN_NOY")) { // Deep copy the FFT'd field - Array shifted_temp(f_fft(i.x(), i.y() + phase.y_offset)); + int ix = i.x(); + int iy = i.y(); + + Array shifted_temp(f_fft(ix, iy + phase.y_offset)); shifted_temp.ensureUnique(); for (int jz = 1; jz < nmodes; ++jz) { - shifted_temp[jz] *= phase.phase_shift(i.x(), i.y(), jz); + shifted_temp[jz] *= phase.phase_shift(ix, iy, jz); } irfft(shifted_temp.begin(), mesh.LocalNz, From 33801cedb1dc671da13cfc87ebca1586e50f8451 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 21 Feb 2019 13:04:32 +0000 Subject: [PATCH 0852/1783] Clang formatting --- src/mesh/parallel/shiftedmetric.cxx | 59 ++++++++++--------- .../unit/mesh/parallel/test_shiftedmetric.cxx | 22 +++---- 2 files changed, 40 insertions(+), 41 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 40d0fd3382..3a33deafe7 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -1,21 +1,21 @@ /* * Implements the shifted metric method for parallel derivatives - * + * * By default fields are stored so that X-Z are orthogonal, * and so not aligned in Y. * */ -#include +#include #include +#include #include -#include #include #include -ShiftedMetric::ShiftedMetric(Mesh &m) : ParallelTransform(m), zShift(&m) { +ShiftedMetric::ShiftedMetric(Mesh& m) : ParallelTransform(m), zShift(&m) { // check the coordinate system used for the grid data source checkInputGrid(); @@ -38,7 +38,8 @@ ShiftedMetric::ShiftedMetric(Mesh &m) : ParallelTransform(m), zShift(&m) { cachePhases(); } -ShiftedMetric::ShiftedMetric(Mesh &m, Field2D zShift_) : ParallelTransform(m), zShift(std::move(zShift_)) { +ShiftedMetric::ShiftedMetric(Mesh& m, Field2D zShift_) + : ParallelTransform(m), zShift(std::move(zShift_)) { // check the coordinate system used for the grid data source checkInputGrid(); @@ -49,8 +50,9 @@ void ShiftedMetric::checkInputGrid() { std::string coordinates_type = ""; if (!mesh.get(coordinates_type, "coordinates_type")) { if (coordinates_type != "orthogonal") { - throw BoutException("Incorrect coordinate system type "+coordinates_type+" used " - "to generate metric components for ShiftedMetric. Should be 'orthogonal."); + throw BoutException("Incorrect coordinate system type " + coordinates_type + + " used to generate metric components for ShiftedMetric. " + "Should be 'orthogonal."); } } // else: coordinate_system variable not found in grid input, indicates older input // file so must rely on the user having ensured the type is correct @@ -73,16 +75,15 @@ void ShiftedMetric::cachePhases() { fromAlignedPhs = Tensor(mesh.LocalNx, mesh.LocalNy, nmodes); toAlignedPhs = Tensor(mesh.LocalNx, mesh.LocalNy, nmodes); - //To/From field aligned phases + // To/From field aligned phases BOUT_FOR(i, mesh.getRegion2D("RGN_ALL")) { int ix = i.x(); int iy = i.y(); - for(int jz=0;jz& phs, const REGION region) const { ASSERT1(&mesh == f.getMesh()); - ASSERT1(f.getLocation() == CELL_CENTRE); // only have zShift for CELL_CENTRE, so can only deal with CELL_CENTRE inputs - if(mesh.LocalNz == 1) + // only have zShift for CELL_CENTRE, so can only deal with CELL_CENTRE inputs + ASSERT1(f.getLocation() == CELL_CENTRE); + + if (mesh.LocalNz == 1) return f; // Shifting makes no difference Field3D result(&mesh); @@ -160,9 +163,8 @@ const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Tensor& ph BOUT_FOR(i, mesh.getRegion2D(REGION_STRING(region))) { shiftZ(&f(i, 0), &phs(i.x(), i.y(), 0), &result(i, 0)); } - - return result; + return result; } void ShiftedMetric::shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* out) const { @@ -183,11 +185,11 @@ void ShiftedMetric::shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* ou irfft(&cmplx[0], mesh.LocalNz, out); // Reverse FFT } - void ShiftedMetric::calcYUpDown(Field3D& f) { ASSERT1(&mesh == f.getMesh()); - ASSERT1(f.getLocation() == CELL_CENTRE); // only have zShift for CELL_CENTRE, so can only deal with CELL_CENTRE inputs + // only have zShift for CELL_CENTRE, so can only deal with CELL_CENTRE inputs + ASSERT1(f.getLocation() == CELL_CENTRE); auto results = shiftZ(f, parallel_slice_phases); @@ -207,7 +209,7 @@ ShiftedMetric::shiftZ(const Field3D& f, const int nmodes = mesh.LocalNz / 2 + 1; // FFT in Z of input field at each (x, y) point - Matrix< Array > f_fft(mesh.LocalNx, mesh.LocalNy); + Matrix> f_fft(mesh.LocalNx, mesh.LocalNy); f_fft = Array(nmodes); BOUT_FOR(i, mesh.getRegion2D("RGN_ALL")) { @@ -239,19 +241,19 @@ ShiftedMetric::shiftZ(const Field3D& f, shifted_temp[jz] *= phase.phase_shift(ix, iy, jz); } - irfft(shifted_temp.begin(), mesh.LocalNz, - ¤t_result(i.yp(phase.y_offset), 0)); + irfft(shifted_temp.begin(), mesh.LocalNz, ¤t_result(i.yp(phase.y_offset), 0)); } } return results; } -//Old approach retained so we can still specify a general zShift -const Field3D ShiftedMetric::shiftZ(const Field3D &f, const Field2D &zangle, const REGION region) const { +// Old approach retained so we can still specify a general zShift +const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Field2D& zangle, + const REGION region) const { ASSERT1(&mesh == f.getMesh()); ASSERT1(f.getLocation() == zangle.getLocation()); - if(mesh.LocalNz == 1) + if (mesh.LocalNz == 1) return f; // Shifting makes no difference Field3D result(&mesh); @@ -267,11 +269,12 @@ const Field3D ShiftedMetric::shiftZ(const Field3D &f, const Field2D &zangle, con BOUT_FOR(i, mesh.getRegion2D(REGION_STRING(region))) { shiftZ(&f(i, 0), mesh.LocalNz, zangle[i], &result(i, 0)); } - + return result; } -void ShiftedMetric::shiftZ(const BoutReal* in, int len, BoutReal zangle, BoutReal* out) const { +void ShiftedMetric::shiftZ(const BoutReal* in, int len, BoutReal zangle, + BoutReal* out) const { int nmodes = len / 2 + 1; // Complex array used for FFTs diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index a823397bc8..aa13aced2b 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -7,9 +7,9 @@ // The unit tests use the global mesh using namespace bout::globals; -namespace bout{ -namespace globals{ -extern Mesh *mesh; +namespace bout { +namespace globals { +extern Mesh* mesh; } // namespace globals } // namespace bout @@ -122,7 +122,7 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { {2., 4., 3., 5., 1.}}}); EXPECT_TRUE(IsFieldEqual(shifted.toFieldAligned(input, RGN_ALL), expected, "RGN_ALL", - FFTTolerance)); + FFTTolerance)); } TEST_F(ShiftedMetricTest, FromFieldAligned) { @@ -156,7 +156,7 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { // Loosen tolerance a bit due to FFTs EXPECT_TRUE(IsFieldEqual(shifted.fromFieldAligned(input, RGN_ALL), expected, "RGN_ALL", - FFTTolerance)); + FFTTolerance)); } TEST_F(ShiftedMetricTest, CalcYUpDown) { @@ -290,12 +290,8 @@ TEST_F(ShiftedMetricTest, CalcYUpDown) { {0., 0., 0., 0., 0.}, {0., 0., 0., 0., 0.}}}); - EXPECT_TRUE( - IsFieldEqual(input.ynext(1), expected_up_1, "RGN_YUP", FFTTolerance)); - EXPECT_TRUE( - IsFieldEqual(input.ynext(2), expected_up_2, "RGN_YUP2", FFTTolerance)); - EXPECT_TRUE( - IsFieldEqual(input.ynext(-1), expected_down_1, "RGN_YDOWN", FFTTolerance)); - EXPECT_TRUE( - IsFieldEqual(input.ynext(-2), expected_down2, "RGN_YDOWN2", FFTTolerance)); + EXPECT_TRUE(IsFieldEqual(input.ynext(1), expected_up_1, "RGN_YUP", FFTTolerance)); + EXPECT_TRUE(IsFieldEqual(input.ynext(2), expected_up_2, "RGN_YUP2", FFTTolerance)); + EXPECT_TRUE(IsFieldEqual(input.ynext(-1), expected_down_1, "RGN_YDOWN", FFTTolerance)); + EXPECT_TRUE(IsFieldEqual(input.ynext(-2), expected_down2, "RGN_YDOWN2", FFTTolerance)); } From ea4feb2dbc56556df3bfe56f9449bc33d5980181 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 13:20:06 +0000 Subject: [PATCH 0853/1783] Reduce repeated code in Timer with get/resetTime(timer_info) Also make the public overloads inline --- include/bout/sys/timer.hxx | 26 ++++++++++++------- src/sys/timer.cxx | 53 +++++++++++++------------------------- 2 files changed, 34 insertions(+), 45 deletions(-) diff --git a/include/bout/sys/timer.hxx b/include/bout/sys/timer.hxx index 13ab627514..d7f84a8f23 100644 --- a/include/bout/sys/timer.hxx +++ b/include/bout/sys/timer.hxx @@ -53,28 +53,28 @@ public: * output << timer.getTime(); * // timer still counting */ - double getTime(); - + double getTime() { return getTime(timing); } + /*! * Get the time in seconds, reset timer to zero */ - double resetTime(); - + double resetTime() { return resetTime(timing); } + /*! - * The total time in seconds + * The total time in seconds */ - static double getTime(const std::string &label); - + static double getTime(const std::string& label) { return getTime(getInfo(label)); } + /*! * The total time in seconds, resets the timer to zero */ - static double resetTime(const std::string &label); - + static double resetTime(const std::string& label) { return resetTime(getInfo(label)); } + /*! * Clears all timers, freeing memory */ static void cleanup(); - + private: /// Structure to contain timing information struct timer_info { @@ -88,6 +88,12 @@ private: static timer_info& getInfo(const std::string &label); timer_info& timing; + + /// Get the elapsed time in seconds for timing info + static double getTime(const timer_info& info); + + /// Get the elapsed time, reset timing info to zero + static double resetTime(timer_info& info); }; #endif // __TIMER_H__ diff --git a/src/sys/timer.cxx b/src/sys/timer.cxx index e3a7d4fea2..f5213c2b06 100644 --- a/src/sys/timer.cxx +++ b/src/sys/timer.cxx @@ -19,41 +19,6 @@ Timer::~Timer() { timing.time += finished - timing.started; } -double Timer::getTime() { - // If we've got a Timer by value, it must be running - return timing.time + (MPI_Wtime() - timing.started); -} - -double Timer::resetTime() { - double val = timing.time; - timing.time = 0.0; - if (timing.running) { - double cur_time = MPI_Wtime(); - val += cur_time - timing.started; - timing.started = cur_time; - } - return val; -} - -double Timer::getTime(const std::string& label) { - timer_info& t = getInfo(label); - if (t.running) - return t.time + (MPI_Wtime() - t.started); - return t.time; -} - -double Timer::resetTime(const std::string& label) { - timer_info& t = getInfo(label); - double val = t.time; - t.time = 0.0; - if (t.running) { - double cur_time = MPI_Wtime(); - val += cur_time - t.started; - t.started = cur_time; - } - return val; -} - // Static method to clean up all memory void Timer::cleanup() { info.clear(); } @@ -70,3 +35,21 @@ Timer::timer_info& Timer::getInfo(const std::string& label) { } return it->second; } + +double Timer::getTime(const Timer::timer_info& info) { + if (info.running) { + return info.time + (MPI_Wtime() - info.started); + } + return info.time; +} + +double Timer::resetTime(Timer::timer_info& info) { + double val = info.time; + info.time = 0.0; + if (info.running) { + double cur_time = MPI_Wtime(); + val += cur_time - info.started; + info.started = cur_time; + } + return val; +} From 1617db379f981ab4485adee405ef856c80bf75a6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 13:21:59 +0000 Subject: [PATCH 0854/1783] Clang-format Timer header --- include/bout/sys/timer.hxx | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/include/bout/sys/timer.hxx b/include/bout/sys/timer.hxx index d7f84a8f23..7a6f95a682 100644 --- a/include/bout/sys/timer.hxx +++ b/include/bout/sys/timer.hxx @@ -12,19 +12,19 @@ class Timer; * * To record the time spent in a particular function, create a Timer object * when you wish to start timing - * + * * void someFunction() { * Timer timer("test"); // Starts timer - * + * * } // Timer stops when goes out of scope * * Each time this function is called, the total time spent in someFunction * will be accumulated. To get the total time spent use getTime() - * + * * Timer::getTime("test"); // Returns time in seconds as double * * To reset the timer, use resetTime - * + * * Timer::resetTime("test"); // Timer reset to zero, returning time as double */ class Timer { @@ -33,18 +33,18 @@ public: * Create a timer. This constructor is equivalent to Timer("") */ Timer(); - + /*! * Create a timer, continuing from last time if the same label * has already been used */ - Timer(const std::string &label); - + Timer(const std::string& label); + /*! * Stop the timer */ ~Timer(); - + /*! * Get the time in seconds for time particular Timer object * @@ -82,11 +82,14 @@ private: bool running; ///< Is the timer currently running? double started; ///< Start time }; - + + /// Store of existing timing info objects static std::map info; - - static timer_info& getInfo(const std::string &label); - + + /// Get a timing info object by name or return a new instance + static timer_info& getInfo(const std::string& label); + + /// The current timing information timer_info& timing; /// Get the elapsed time in seconds for timing info From 168b2e6fb88769463f6e0bcc83d250fbfd6ef238 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 13:22:10 +0000 Subject: [PATCH 0855/1783] Remove using namespace::std Only used for a single line! --- src/sys/timer.cxx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sys/timer.cxx b/src/sys/timer.cxx index f5213c2b06..9fa7493267 100644 --- a/src/sys/timer.cxx +++ b/src/sys/timer.cxx @@ -1,8 +1,6 @@ #include #include -using namespace std; - Timer::Timer() : timing(getInfo("")) { timing.started = MPI_Wtime(); timing.running = true; @@ -22,7 +20,7 @@ Timer::~Timer() { // Static method to clean up all memory void Timer::cleanup() { info.clear(); } -map Timer::info; +std::map Timer::info; Timer::timer_info& Timer::getInfo(const std::string& label) { auto it = info.find(label); From 0edb976b1d013029228b9bfbe28a877bcd364218 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 14:16:48 +0000 Subject: [PATCH 0856/1783] Replace MPI_Wtime with standard C++ chrono clock --- include/bout/sys/timer.hxx | 17 +++-- src/sys/timer.cxx | 24 +++---- tests/unit/sys/test_timer.cxx | 117 +++++++++++++++------------------- 3 files changed, 73 insertions(+), 85 deletions(-) diff --git a/include/bout/sys/timer.hxx b/include/bout/sys/timer.hxx index 7a6f95a682..71075a0493 100644 --- a/include/bout/sys/timer.hxx +++ b/include/bout/sys/timer.hxx @@ -1,11 +1,10 @@ - -class Timer; - #ifndef __TIMER_H__ #define __TIMER_H__ +#include #include #include +#include /*! * Timing class for performance benchmarking and diagnosis @@ -29,6 +28,12 @@ class Timer; */ class Timer { public: + using clock_type = + typename std::conditional::type; + using seconds = std::chrono::duration; + /*! * Create a timer. This constructor is equivalent to Timer("") */ @@ -78,9 +83,9 @@ public: private: /// Structure to contain timing information struct timer_info { - double time; ///< Total time - bool running; ///< Is the timer currently running? - double started; ///< Start time + seconds time; ///< Total time + bool running; ///< Is the timer currently running? + clock_type::time_point started; ///< Start time }; /// Store of existing timing info objects diff --git a/src/sys/timer.cxx b/src/sys/timer.cxx index 9fa7493267..ba19560ca0 100644 --- a/src/sys/timer.cxx +++ b/src/sys/timer.cxx @@ -1,18 +1,17 @@ -#include -#include +#include "bout/sys/timer.hxx" Timer::Timer() : timing(getInfo("")) { - timing.started = MPI_Wtime(); + timing.started = clock_type::now(); timing.running = true; } Timer::Timer(const std::string& label) : timing(getInfo(label)) { - timing.started = MPI_Wtime(); + timing.started = clock_type::now(); timing.running = true; } Timer::~Timer() { - double finished = MPI_Wtime(); + auto finished = clock_type::now(); timing.running = false; timing.time += finished - timing.started; } @@ -26,7 +25,8 @@ Timer::timer_info& Timer::getInfo(const std::string& label) { auto it = info.find(label); if (it == info.end()) { // Not in map, so create it - auto timer = info.emplace(label, timer_info{0.0, false, 0.0}); + auto timer = info.emplace( + label, timer_info{seconds{0}, false, clock_type::now()}); // timer is a pair of an iterator and bool // The iterator is a pair of key, value return timer.first->second; @@ -36,18 +36,18 @@ Timer::timer_info& Timer::getInfo(const std::string& label) { double Timer::getTime(const Timer::timer_info& info) { if (info.running) { - return info.time + (MPI_Wtime() - info.started); + return seconds{info.time + (clock_type::now() - info.started)}.count(); } - return info.time; + return seconds{info.time}.count(); } double Timer::resetTime(Timer::timer_info& info) { - double val = info.time; - info.time = 0.0; + auto val = info.time; + info.time = clock_type::duration{0}; if (info.running) { - double cur_time = MPI_Wtime(); + auto cur_time = clock_type::now(); val += cur_time - info.started; info.started = cur_time; } - return val; + return seconds{val}.count(); } diff --git a/tests/unit/sys/test_timer.cxx b/tests/unit/sys/test_timer.cxx index 704206442f..2e5a307f71 100644 --- a/tests/unit/sys/test_timer.cxx +++ b/tests/unit/sys/test_timer.cxx @@ -8,25 +8,22 @@ namespace bout { namespace testing { using ms = std::chrono::duration; -using seconds = std::chrono::duration; constexpr double TimerTolerance{1e-3}; constexpr auto sleep_length = ms(0.5); } // namespace testing } // namespace bout TEST(TimerTest, GetTime) { - using namespace bout::testing; - - auto start = std::chrono::high_resolution_clock::now(); + auto start = Timer::clock_type::now(); Timer timer{}; - std::this_thread::sleep_for(sleep_length); + std::this_thread::sleep_for(bout::testing::sleep_length); - auto end = std::chrono::high_resolution_clock::now(); - seconds elapsed = end - start; + auto end = Timer::clock_type::now(); + Timer::seconds elapsed = end - start; - EXPECT_NEAR(timer.getTime(), elapsed.count(), TimerTolerance); + EXPECT_NEAR(timer.getTime(), elapsed.count(), bout::testing::TimerTolerance); } TEST(TimerTest, GetUnknownTimeLabel) { @@ -34,156 +31,142 @@ TEST(TimerTest, GetUnknownTimeLabel) { } TEST(TimerTest, GetTimeLabelInScope) { - using namespace bout::testing; - - auto start = std::chrono::high_resolution_clock::now(); + auto start = Timer::clock_type::now(); Timer timer{"GetTimeLabelInScope test"}; - std::this_thread::sleep_for(sleep_length); + std::this_thread::sleep_for(bout::testing::sleep_length); - auto end = std::chrono::high_resolution_clock::now(); - seconds elapsed = end - start; + auto end = Timer::clock_type::now(); + Timer::seconds elapsed = end - start; EXPECT_NEAR(Timer::getTime("GetTimeLabelInScope test"), elapsed.count(), - TimerTolerance); + bout::testing::TimerTolerance); } TEST(TimerTest, GetTimeLabelOutOfScope) { - using namespace bout::testing; - - auto start = std::chrono::high_resolution_clock::now(); + auto start = Timer::clock_type::now(); { Timer timer{"GetTimeLabelOutOfScope test"}; - std::this_thread::sleep_for(sleep_length); + std::this_thread::sleep_for(bout::testing::sleep_length); } - auto end = std::chrono::high_resolution_clock::now(); - seconds elapsed = end - start; - + auto end = Timer::clock_type::now(); + Timer::seconds elapsed = end - start; + EXPECT_NEAR(Timer::getTime("GetTimeLabelOutOfScope test"), elapsed.count(), - TimerTolerance); + bout::testing::TimerTolerance); } TEST(TimerTest, GetTimeLabelRepeat) { - using namespace bout::testing; - - auto start = std::chrono::high_resolution_clock::now(); + auto start = Timer::clock_type::now(); { Timer timer{"GetTimeLabelRepeat test"}; - std::this_thread::sleep_for(sleep_length); + std::this_thread::sleep_for(bout::testing::sleep_length); } - auto end = std::chrono::high_resolution_clock::now(); - seconds elapsed = end - start; + auto end = Timer::clock_type::now(); + Timer::seconds elapsed = end - start; EXPECT_NEAR(Timer::getTime("GetTimeLabelRepeat test"), elapsed.count(), - TimerTolerance); + bout::testing::TimerTolerance); { Timer timer{"GetTimeLabelRepeat test"}; - std::this_thread::sleep_for(sleep_length); + std::this_thread::sleep_for(bout::testing::sleep_length); } - auto end2 = std::chrono::high_resolution_clock::now(); - seconds elapsed2 = end2 - start; + auto end2 = Timer::clock_type::now(); + Timer::seconds elapsed2 = end2 - start; EXPECT_NEAR(Timer::getTime("GetTimeLabelRepeat test"), elapsed2.count(), - TimerTolerance); + bout::testing::TimerTolerance); } TEST(TimerTest, ResetTime) { - using namespace bout::testing; - Timer timer{"ResetTime test"}; - std::this_thread::sleep_for(sleep_length); + std::this_thread::sleep_for(bout::testing::sleep_length); timer.resetTime(); - auto start = std::chrono::high_resolution_clock::now(); + auto start = Timer::clock_type::now(); - std::this_thread::sleep_for(sleep_length); + std::this_thread::sleep_for(bout::testing::sleep_length); - auto end = std::chrono::high_resolution_clock::now(); - seconds elapsed = end - start; + auto end = Timer::clock_type::now(); + Timer::seconds elapsed = end - start; - EXPECT_NEAR(timer.getTime(), elapsed.count(), TimerTolerance); + EXPECT_NEAR(timer.getTime(), elapsed.count(), bout::testing::TimerTolerance); } TEST(TimerTest, ResetTimeLabelInScope) { - using namespace bout::testing; - Timer timer{"ResetTimeLabelInScope test"}; - std::this_thread::sleep_for(sleep_length); + std::this_thread::sleep_for(bout::testing::sleep_length); Timer::resetTime("ResetTimeLabelInScope test"); - auto start = std::chrono::high_resolution_clock::now(); + auto start = Timer::clock_type::now(); - std::this_thread::sleep_for(sleep_length); + std::this_thread::sleep_for(bout::testing::sleep_length); - auto end = std::chrono::high_resolution_clock::now(); - seconds elapsed = end - start; + auto end = Timer::clock_type::now(); + Timer::seconds elapsed = end - start; EXPECT_NEAR(Timer::getTime("ResetTimeLabelInScope test"), elapsed.count(), - TimerTolerance); + bout::testing::TimerTolerance); } TEST(TimerTest, ResetTimeLabelOutOfScope) { - using namespace bout::testing; - { Timer timer{"ResetTimeLabelOutOfScope test"}; - std::this_thread::sleep_for(sleep_length); + std::this_thread::sleep_for(bout::testing::sleep_length); } Timer::resetTime("ResetTimeLabelOutOfScope test"); - auto start = std::chrono::high_resolution_clock::now(); + auto start = Timer::clock_type::now(); { Timer timer{"ResetTimeLabelOutOfScope test"}; - std::this_thread::sleep_for(sleep_length); + std::this_thread::sleep_for(bout::testing::sleep_length); } - auto end = std::chrono::high_resolution_clock::now(); - seconds elapsed = end - start; + auto end = Timer::clock_type::now(); + Timer::seconds elapsed = end - start; - EXPECT_NEAR(Timer::getTime("ResetTimeLabelOutOfScope test"), - elapsed.count(), TimerTolerance); + EXPECT_NEAR(Timer::getTime("ResetTimeLabelOutOfScope test"), elapsed.count(), + bout::testing::TimerTolerance); } TEST(TimerTest, Cleanup) { - using namespace bout::testing; - { Timer timer{"Cleanup test"}; - std::this_thread::sleep_for(sleep_length); + std::this_thread::sleep_for(bout::testing::sleep_length); } Timer::cleanup(); - auto start = std::chrono::high_resolution_clock::now(); + auto start = Timer::clock_type::now(); { Timer timer{"Cleanup test"}; - std::this_thread::sleep_for(sleep_length); + std::this_thread::sleep_for(bout::testing::sleep_length); } - auto end = std::chrono::high_resolution_clock::now(); - seconds elapsed = end - start; + auto end = Timer::clock_type::now(); + Timer::seconds elapsed = end - start; EXPECT_NEAR(Timer::getTime("Cleanup test"), elapsed.count(), - TimerTolerance); + bout::testing::TimerTolerance); } From e8b4a7d80df0bc4094db38c356f42c25fee3a0ae Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 14:19:05 +0000 Subject: [PATCH 0857/1783] Remove some extraneous comments --- src/sys/timer.cxx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sys/timer.cxx b/src/sys/timer.cxx index ba19560ca0..bc16140a3f 100644 --- a/src/sys/timer.cxx +++ b/src/sys/timer.cxx @@ -16,7 +16,6 @@ Timer::~Timer() { timing.time += finished - timing.started; } -// Static method to clean up all memory void Timer::cleanup() { info.clear(); } std::map Timer::info; @@ -24,11 +23,8 @@ std::map Timer::info; Timer::timer_info& Timer::getInfo(const std::string& label) { auto it = info.find(label); if (it == info.end()) { - // Not in map, so create it auto timer = info.emplace( label, timer_info{seconds{0}, false, clock_type::now()}); - // timer is a pair of an iterator and bool - // The iterator is a pair of key, value return timer.first->second; } return it->second; From 2a337ce36d0989960c1df55ac9da391e88e79e63 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Thu, 21 Feb 2019 15:07:06 +0000 Subject: [PATCH 0858/1783] Remove duplicate write --- src/bout++.cxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 8f8832a458..7ad21fa08c 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -625,9 +625,6 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { simtime = t; iteration = iter; - /// Write dump file - bout::globals::dump.write(); - /// Collect timing information run_data.wtime = Timer::resetTime("run"); run_data.ncalls = solver->resetRHSCounter(); From e35e9f0f9536bfcd756b2039d9fb398fd1561624 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 15:28:41 +0000 Subject: [PATCH 0859/1783] Delete Field2D move assignment operator Currently causes problems in Solver::add by (potentially) clobbering ddt(f) --- include/field2d.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/field2d.hxx b/include/field2d.hxx index eae5befe62..a00b5d5aba 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -142,7 +142,7 @@ class Field2D : public Field, public FieldData { * function. */ Field2D & operator=(const Field2D &rhs); - Field2D & operator=(Field2D &&rhs) = default; + Field2D & operator=(Field2D &&rhs) = delete; /*! * Allocates data if not already allocated, then From 8d9f3242a02063250ca564eee08b34a4615bd039 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 16:14:43 +0000 Subject: [PATCH 0860/1783] Make Timer(std::string) constructor explicit --- include/bout/sys/timer.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/sys/timer.hxx b/include/bout/sys/timer.hxx index 71075a0493..04838dbda3 100644 --- a/include/bout/sys/timer.hxx +++ b/include/bout/sys/timer.hxx @@ -43,7 +43,7 @@ public: * Create a timer, continuing from last time if the same label * has already been used */ - Timer(const std::string& label); + explicit Timer(const std::string& label); /*! * Stop the timer From 4a428aa09687f4fca5cf6fc45019d1581693f20a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 17:12:59 +0000 Subject: [PATCH 0861/1783] Add command line arguments for plotting graphs --- tests/MMS/spatial/advection/runtest | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tests/MMS/spatial/advection/runtest b/tests/MMS/spatial/advection/runtest index e0ebfcb9c9..2e31b76c55 100755 --- a/tests/MMS/spatial/advection/runtest +++ b/tests/MMS/spatial/advection/runtest @@ -17,8 +17,17 @@ from boutdata.collect import collect from numpy import array, log, pi +import argparse import pickle +parser = argparse.ArgumentParser(description="Check the error scaling of bracket operators") +parser.add_argument("-p", "--plot", action="store_true", + help="Plot graphs of the errors") +parser.add_argument("-n", "--no-show", action="store_false", dest="show", + help="Don't show the plots, just save to file") + +cli_args = parser.parse_args() + MPIRUN = getmpirun() print("Making MMS steady-state advection test") @@ -104,7 +113,7 @@ for opts, label, sym, exp_ord in options: print("... Success") # plot errors - if False: + if cli_args.plot: import matplotlib.pyplot as plt plt.figure() @@ -123,7 +132,9 @@ for opts, label, sym, exp_ord in options: plt.xlabel(r'Mesh spacing $\delta x$') plt.ylabel("Error norm") - plt.show() + if cli_args.show: + plt.show() + plt.savefig("{}_error_scaling.png".format(label.replace(" ", "_"))) plt.close() # Save the data @@ -132,7 +143,7 @@ with open("advection.pkl", "wb") as output: pickle.dump(err_inf_all, output) # Plot all errors -if False: +if cli_args.plot: import matplotlib.pyplot as plt # Plot all results for comparison plt.figure() @@ -147,6 +158,8 @@ if False: plt.xlabel(r'Mesh spacing $\delta x$') plt.ylabel(r'$l_2$ error norm') plt.savefig("advection_norm_l2.png") + if cli_args.show: + plt.show() plt.close() ### @@ -163,6 +176,8 @@ if False: plt.xlabel(r'Mesh spacing $\delta x$') plt.ylabel(r'$l_\infty$ error norm') plt.savefig("advection_norm_linf.png") + if cli_args.show: + plt.show() plt.close() From 922473a4775ec6d1b258ec8124d6d58eddb8cb28 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Feb 2019 17:15:10 +0000 Subject: [PATCH 0862/1783] Delete deleted move assignment operator --- include/field2d.hxx | 1 - 1 file changed, 1 deletion(-) diff --git a/include/field2d.hxx b/include/field2d.hxx index a00b5d5aba..486c111bca 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -142,7 +142,6 @@ class Field2D : public Field, public FieldData { * function. */ Field2D & operator=(const Field2D &rhs); - Field2D & operator=(Field2D &&rhs) = delete; /*! * Allocates data if not already allocated, then From 64277471f8d62995915aeaf271cbc0426072d5fc Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 22 Feb 2019 11:34:30 +0000 Subject: [PATCH 0863/1783] Deprecate lowPass(Field3D, int, int, REGION) Also throw an error if the third argument is not 0 or 1 --- examples/6field-simple/elm_6f.cxx | 12 ++++++------ examples/elm-pb/elm_pb.cxx | 12 ++++++------ include/field3d.hxx | 8 ++++++++ tests/MMS/elm-pb/elm_pb.cxx | 14 +++++++------- tests/unit/field/test_field3d.cxx | 4 ++++ 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/examples/6field-simple/elm_6f.cxx b/examples/6field-simple/elm_6f.cxx index 66c009c948..1444bbe33e 100644 --- a/examples/6field-simple/elm_6f.cxx +++ b/examples/6field-simple/elm_6f.cxx @@ -161,9 +161,9 @@ bool nogradparj; bool filter_z; int filter_z_mode; int low_pass_z; -int zonal_flow; -int zonal_field; -int zonal_bkgd; +bool zonal_flow; +bool zonal_field; +bool zonal_bkgd; bool relax_j_vac; BoutReal relax_j_tconst; // Time-constant for j relax Field3D Psitarget; // The (moving) target to relax to @@ -495,9 +495,9 @@ int physics_init(bool restarting) { OPTION(options, filter_z, false); // Filter a single n OPTION(options, filter_z_mode, 1); OPTION(options, low_pass_z, -1); // Low-pass filter - OPTION(options, zonal_flow, -1); // zonal flow filter - OPTION(options, zonal_field, -1); // zonal field filter - OPTION(options, zonal_bkgd, -1); // zonal background P filter + OPTION(options, zonal_flow, false); // zonal flow filter + OPTION(options, zonal_field, false); // zonal field filter + OPTION(options, zonal_bkgd, false); // zonal background P filter OPTION(options, filter_nl, -1); // zonal background P filter diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index 7d3e6bcd40..33a61a7f78 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -161,9 +161,9 @@ bool nogradparj; bool filter_z; int filter_z_mode; int low_pass_z; -int zonal_flow; -int zonal_field; -int zonal_bkgd; +bool zonal_flow; +bool zonal_field; +bool zonal_bkgd; bool relax_j_vac; BoutReal relax_j_tconst; // Time-constant for j relax Field3D Psitarget; // The (moving) target to relax to @@ -455,9 +455,9 @@ int physics_init(bool restarting) { OPTION(options, filter_z, false); // Filter a single n OPTION(options, filter_z_mode, 1); OPTION(options, low_pass_z, -1); // Low-pass filter - OPTION(options, zonal_flow, -1); // zonal flow filter - OPTION(options, zonal_field, -1); // zonal field filter - OPTION(options, zonal_bkgd, -1); // zonal background P filter + OPTION(options, zonal_flow, false); // zonal flow filter + OPTION(options, zonal_field, false); // zonal field filter + OPTION(options, zonal_bkgd, false); // zonal background P filter // Radial smoothing OPTION(options, smooth_j_x, false); // Smooth Jpar in x diff --git a/include/field3d.hxx b/include/field3d.hxx index 40c2ab425d..419a368c3c 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -714,6 +714,14 @@ Field3D filter(const Field3D &var, int N0, REGION rgn = RGN_ALL); /// @param[in] rgn The region to calculate the result over Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn = RGN_ALL); +/// The argument \p keep_zonal used to be integer "zmin" -- this was a +/// misnomer. Please use the version above which uses a bool instead +DEPRECATED(inline Field3D lowPass(const Field3D& var, int zmax, int keep_zonal, + REGION rgn = RGN_ALL)) { + ASSERT0(static_cast(keep_zonal) == keep_zonal); + return lowPass(var, zmax, static_cast(keep_zonal), rgn); +} + /// Fourier low pass filtering. Removes modes higher than \p zmax /// /// @param[in] var Variable to apply filter to diff --git a/tests/MMS/elm-pb/elm_pb.cxx b/tests/MMS/elm-pb/elm_pb.cxx index e89d2a63eb..6ac7b072ec 100644 --- a/tests/MMS/elm-pb/elm_pb.cxx +++ b/tests/MMS/elm-pb/elm_pb.cxx @@ -99,9 +99,9 @@ BoutReal AA; // ion mass in units of the proton mass; AA=Mi/Mp bool filter_z; int filter_z_mode; int low_pass_z; -int zonal_flow; -int zonal_field; -int zonal_bkgd; +bool zonal_flow; +bool zonal_field; +bool zonal_bkgd; BoutReal vac_lund, core_lund; // Lundquist number S = (Tau_R / Tau_A). -ve -> infty BoutReal vac_resist, core_resist; // The resistivities (just 1 / S) @@ -245,12 +245,12 @@ int physics_init(bool restarting) { OPTION(options, dia_fact, 1.0); // Scale diamagnetic effects by this factor // Toroidal filtering - OPTION(options, filter_z, false); // Filter a single n + OPTION(options, filter_z, false); // Filter a single n OPTION(options, filter_z_mode, 1); OPTION(options, low_pass_z, -1); // Low-pass filter - OPTION(options, zonal_flow, -1); // zonal flow filter - OPTION(options, zonal_field, -1); // zonal field filter - OPTION(options, zonal_bkgd, -1); // zonal background P filter + OPTION(options, zonal_flow, false); // zonal flow filter + OPTION(options, zonal_field, false); // zonal field filter + OPTION(options, zonal_bkgd, false); // zonal background P filter // Vacuum region control OPTION(options, vacuum_pressure, 0.02); // Fraction of peak pressure diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 414d295323..fc9647a078 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -2147,6 +2147,10 @@ TEST_F(Field3DTest, LowPassTwoArg) { auto output2 = lowPass(input, 2, 0); EXPECT_TRUE(IsFieldEqual(output2, expected)); + + // Calling lowPass with an int that is not 0 or 1 is an error + EXPECT_THROW(lowPass(input, 2, -1), BoutException); + EXPECT_THROW(lowPass(input, 2, 2), BoutException); } TEST_F(Field3DTest, LowPassTwoArgKeepZonal) { From 1bead00a6ce8f889ceebc1830167e52c42a70800 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Feb 2019 11:38:34 +0000 Subject: [PATCH 0864/1783] Fix unit tests - Initialize ParallelTransform in mesh_staggered for FieldFactoryCreationTest - Add CELL_YLOW and CELL_ZLOW nullptr entries for mesh_staggered coords_map - Use mesh_staggered for CreateXStaggered, CreateYStaggered and CreateZStaggered tests --- tests/unit/field/test_field_factory.cxx | 17 +++++++++++------ tests/unit/test_extras.hxx | 4 +++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index 8fa5ac644d..c043f6c302 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -28,6 +28,8 @@ class FieldFactoryCreationTest : public FakeMeshFixture { // un-field-align the result mesh->setParallelTransform( bout::utils::make_unique(*mesh)); + mesh_staggered->setParallelTransform( + bout::utils::make_unique(*mesh_staggered)); } FieldFactory factory; @@ -164,8 +166,9 @@ TYPED_TEST(FieldFactoryCreationTest, CreateZ) { } TYPED_TEST(FieldFactoryCreationTest, CreateXStaggered) { - bout::globals::mesh->StaggerGrids = true; - auto output = this->create("x", nullptr, bout::globals::mesh, CELL_XLOW); + // Need this->mesh_staggered to access member of base FakeMeshFixture because + // derived FieldFactoryCreationTest is a template clas + auto output = this->create("x", nullptr, this->mesh_staggered, CELL_XLOW); auto expected = makeField( [](typename TypeParam::ind_type& index) -> BoutReal { return index.x() - 0.5; }, @@ -176,8 +179,9 @@ TYPED_TEST(FieldFactoryCreationTest, CreateXStaggered) { } TYPED_TEST(FieldFactoryCreationTest, CreateYStaggered) { - bout::globals::mesh->StaggerGrids = true; - auto output = this->create("y", nullptr, bout::globals::mesh, CELL_YLOW); + // Need this->mesh_staggered to access member of base FakeMeshFixture because + // derived FieldFactoryCreationTest is a template clas + auto output = this->create("y", nullptr, this->mesh_staggered, CELL_YLOW); auto expected = makeField( [](typename TypeParam::ind_type& index) -> BoutReal { @@ -190,8 +194,9 @@ TYPED_TEST(FieldFactoryCreationTest, CreateYStaggered) { } TYPED_TEST(FieldFactoryCreationTest, CreateZStaggered) { - bout::globals::mesh->StaggerGrids = true; - auto output = this->create("z", nullptr, bout::globals::mesh, CELL_ZLOW); + // Need this->mesh_staggered to access member of base FakeMeshFixture because + // derived FieldFactoryCreationTest is a template clas + auto output = this->create("z", nullptr, this->mesh_staggered, CELL_ZLOW); auto expected = makeField( [](typename TypeParam::ind_type& index) -> BoutReal { diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 6438a62012..5fbec54c5b 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -268,8 +268,10 @@ public: } mesh_staggered = new FakeMesh(nx, ny, nz); mesh_staggered->StaggerGrids = true; - output_info.disable(); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); + static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_YLOW); + static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_ZLOW); + output_info.disable(); mesh_staggered->createDefaultRegions(); output_info.enable(); } From ae0ddc0645e9f854b4ef82c8e171e5ef6d39e6aa Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Feb 2019 17:03:52 +0000 Subject: [PATCH 0865/1783] Hypnotoad: detailed settings for non-orthogonal grids Add a button to the 'Detailed settings' popup to generate a non-orthogonal grid. Allows more control of settings for non-orthogonal grid generation. --- tools/tokamak_grids/gridgen/hypnotoad.pro | 31 ++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/tools/tokamak_grids/gridgen/hypnotoad.pro b/tools/tokamak_grids/gridgen/hypnotoad.pro index 7cc39c9919..ff498299fa 100644 --- a/tools/tokamak_grids/gridgen/hypnotoad.pro +++ b/tools/tokamak_grids/gridgen/hypnotoad.pro @@ -57,8 +57,8 @@ PRO popup_event, event IF N_ELEMENTS(uvalue) EQ 0 THEN RETURN ; Undefined - CASE uvalue OF - 'mesh': BEGIN + CASE 1 OF + uvalue EQ 'mesh' OR uvalue EQ 'mesh2': BEGIN IF base_info.rz_grid_valid EQ 0 THEN BEGIN PRINT, "ERROR: No valid equilibrium data. Read from file first" a = DIALOG_MESSAGE("No valid equilibrium data. Read from file first", /error) @@ -109,7 +109,7 @@ PRO popup_event, event ; Delete the window, as number of fields may change WIDGET_CONTROL, event.top, /destroy - + ; Check if a simplified boundary should be used IF base_info.simple_bndry THEN BEGIN ; Simplify the boundary to a square box @@ -118,7 +118,13 @@ PRO popup_event, event [MIN(boundary[1,*]), MIN(boundary[1,*]), $ MAX(boundary[1,*]), MAX(boundary[1,*])] ]) ENDIF + END + ENDCASE + CASE uvalue OF + 'mesh': BEGIN + ; Orthogonal mesh button was pushed + ; Create the mesh mesh = create_grid((*(base_info.rz_grid)).psi, (*(base_info.rz_grid)).r, (*(base_info.rz_grid)).z, $ settings, $ @@ -126,7 +132,23 @@ PRO popup_event, event single_rad_grid=base_info.single_rad_grid, $ critical=(*(base_info.rz_grid)).critical, $ fast=base_info.fast, xpt_mul=xpt_mul, /simple) + END + 'mesh2': BEGIN + ; Non-orthogonal mesh button was pushed + + ; Create the mesh + mesh = create_nonorthogonal((*(base_info.rz_grid)).psi, (*(base_info.rz_grid)).r, $ + (*(base_info.rz_grid)).z, settings, $ + boundary=boundary, strict=base_info.strict_bndry, $ + /nrad_flexible, $ + single_rad_grid=base_info.single_rad_grid, $ + critical=(*(base_info.rz_grid)).critical, $ + xpt_only=base_info.xpt_only, /simple) + END + ENDCASE + CASE 1 OF + uvalue EQ 'mesh' OR uvalue EQ 'mesh2': BEGIN IF mesh.error EQ 0 THEN BEGIN PRINT, "Successfully generated mesh" WIDGET_CONTROL, base_info.status, set_value="Successfully generated mesh. All glory to the Hypnotoad!" @@ -767,6 +789,9 @@ PRO event_handler, event mesh_button = WIDGET_BUTTON(popup, VALUE='Generate mesh', $ uvalue='mesh', tooltip="Generate a new mesh") + mesh2_button = WIDGET_BUTTON(popup, VALUE='Generate non-orthogonal mesh', $ + uvalue='mesh2', tooltip="Generate a new non-orthogonal mesh") + popup_info = {info:info, $ ; Store the main info too nrad_field:nrad_field, $ in_psi_field:in_psi_field, $ From d5ff53f3ef1dcab03b2d97704a3e5359fad9df71 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Feb 2019 19:06:50 +0000 Subject: [PATCH 0866/1783] Hypnotoad: add setting to change power of nonorthogonality decay The radial direction of the nonorthogonal grid is calculated by taking a weighted average of the two vectors defining the directions of the ends of the grid section and the vector orthogonal to the flux surface. The weight of each end vector reduces as a power of the fraction of the poloidal index-space distance remaining in the grid. The new setting allows this power to be changed, so that the grid approaches orthogonal faster or slower. --- .../gridgen/create_nonorthogonal.pro | 18 ++++++++----- tools/tokamak_grids/gridgen/hypnotoad.pro | 27 ++++++++++++++++--- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index 98e1d8c96b..8346415382 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -288,7 +288,8 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ sep_down=sep_down, sep_line_down=sep_line_down, $ ;Separatrix location and line vec_in_up=vec_in_up, vec_out_up=vec_out_up, $ ; sep_up=sep_up, sep_line_up=sep_line_up, $ ; - sp_loc=sp_loc, orthdown=orthdown, orthup=orthup + sp_loc=sp_loc, orthdown=orthdown, orthup=orthup, $ + nonorthogonal_weight_decay_power=nonorthogonal_weight_decay_power nsurf = N_ELEMENTS(fvals) @@ -374,11 +375,12 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ENDIF ELSE sep_line = FLTARR(2,2) ENDELSE + IF NOT KEYWORD_SET(nonorthogonal_weight_decay_power) THEN nonorthogonal_weight_decay_power = 0 IF NOT KEYWORD_SET(orthup) THEN orthup=0 - IF orthup EQ 1 THEN weight_up = 0 ELSE weight_up = (i/(npar-1.))^2.7 + IF orthup EQ 1 THEN weight_up = 0 ELSE weight_up = (i/(npar-1.))^nonorthogonal_weight_decay_power IF NOT KEYWORD_SET(orthdown) THEN orthdown=0 - IF orthdown EQ 1 THEN weight_down = 0 ELSE weight_down = (1.-i/(npar-1.))^2.7 + IF orthdown EQ 1 THEN weight_down = 0 ELSE weight_down = (1.-i/(npar-1.))^nonorthogonal_weight_decay_power ; Refine the location of the starting point ; follow_gradient_nonorth, interp_data, R, Z, rii[i], zii[i], f0, ri1, zi1, vec=vec_in, weight=weight @@ -889,6 +891,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ str_check_present, settings, 'rad_peaking', 0.0 str_check_present, settings, 'pol_peaking', 0.0 str_check_present, settings, 'parweight', 0.0 + str_check_present, settings, 'nororthogonal_weight_decay_power', 2.7 ENDELSE s = SIZE(F, /DIMENSION) @@ -2053,7 +2056,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ffirst=ffirst, flast=flast1, fpsi=fpsi, yup_dist=xpt_dist[xpt, 0], /oplot, $ vec_in_up=vec_in_up1, vec_out_up=vec_out_up1, sep_up=critical.xpt_f[xpt], $ vec_in_down=-vec_in_down1, vec_out_down=vec_out_down1, $ - ydown_dist=0,orthup=orthup,orthdown=orthdown) + ydown_dist=0,orthup=orthup,orthdown=orthdown, $ + nonorthogonal_weight_decay_power=settings.nonorthogonal_weight_decay_power) Rxy[*, ypos:(ypos+npol[3*i]-1)] = a.Rxy Zxy[*, ypos:(ypos+npol[3*i]-1)] = a.Zxy Rixy[*, ypos:(ypos+npol[3*i]-1)] = a.Rixy @@ -2161,7 +2165,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ sep_down=critical.xpt_f[xpt], $ sep_line_down=sep_line_down, $ vec_in_up=vec_in_up2, vec_out_up=vec_out_up2, $ - sep_up=critical.xpt_f[xpt2], sep_line_up=sep_line_up) + sep_up=critical.xpt_f[xpt2], sep_line_up=sep_line_up, $ + nonorthogonal_weight_decay_power=settings.nonorthogonal_weight_decay_power) Rxy[*, ypos:(ypos+npol[3*i+1]-1)] = a.Rxy Zxy[*, ypos:(ypos+npol[3*i+1]-1)] = a.Zxy @@ -2284,7 +2289,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ydown_dist=xpt_dist[xpt, 3], /oplot, $ vec_in_down=vec_in_down3, vec_out_down=vec_out_down3, sep_down=critical.xpt_f[xpt], $ vec_in_up=vec_in_up3, vec_out_up=vec_out_up3, $ - yup_dist=0,orthup=orthup,orthdown=orthdown) + yup_dist=0,orthup=orthup,orthdown=orthdown, $ + nonorthogonal_weight_decay_power=settings.nonorthogonal_weight_decay_power) Rxy[*, ypos:(ypos+npol[3*i+2]-1)] = a.Rxy Zxy[*, ypos:(ypos+npol[3*i+2]-1)] = a.Zxy Rixy[*, ypos:(ypos+npol[3*i+2]-1)] = a.Rixy diff --git a/tools/tokamak_grids/gridgen/hypnotoad.pro b/tools/tokamak_grids/gridgen/hypnotoad.pro index ff498299fa..00216cdb29 100644 --- a/tools/tokamak_grids/gridgen/hypnotoad.pro +++ b/tools/tokamak_grids/gridgen/hypnotoad.pro @@ -101,9 +101,13 @@ PRO popup_event, event widget_control, base_info.xpt_dist_field, get_value=xpt_mul + widget_control, info.nonorthogonal_weight_decay_power, get_value=nonorthogonal_weight_decay_power + PRINT, "HYP: psi_inner =", psi_inner - settings = {nrad:nrad, npol:npol, psi_inner:psi_inner, psi_outer:psi_outer, rad_peaking:rad_peak} + settings = {nrad:nrad, npol:npol, psi_inner:psi_inner, psi_outer:psi_outer, $ + rad_peaking:rad_peak, $ + nonorthogonal_weight_decay_power:nonorthogonal_weight_decay_power} WIDGET_CONTROL, base_info.status, set_value="Generating mesh ..." @@ -417,7 +421,9 @@ PRO event_handler, event widget_control, info.parweight_field, get_value=parweight - settings = {nrad:nrad, npol:npol, psi_inner:psi_inner, psi_outer:psi_outer, rad_peaking:rad_peak, parweight:parweight} + settings = {nrad:nrad, npol:npol, psi_inner:psi_inner, psi_outer:psi_outer, $ + rad_peaking:rad_peak, parweight:parweight, $ + nonorthogonal_weight_decay_power:info.nonorthogonal_weight_decay_power} ENDELSE @@ -430,8 +436,6 @@ PRO event_handler, event MAX(boundary[1,*]), MAX(boundary[1,*])] ]) ENDIF - IF info.xptonly_check EQ 0 THEN xpt_only = 0 ELSE xpt_only = 1 - WIDGET_CONTROL, info.status, set_value="Generating non-orthogonal mesh ..." mesh = create_nonorthogonal((*(info.rz_grid)).psi, (*(info.rz_grid)).r, (*(info.rz_grid)).z, settings, $ @@ -785,6 +789,18 @@ PRO event_handler, event xsize=8 $ ) ENDELSE + + l = WIDGET_LABEL(popup, value='Strength of decay of non-orthogonality away from grid section boundary') + l = WIDGET_LABEL(popup, value='(Larger exponent pushes the grid back toward orthogonality faster)') + nonorthogonal_decay_base = WIDGET_BASE(popup, /ROW, EVENT_PRO='popup_event') + nonorthogonal_weight_decay_power = $ + CW_FIELD( nonorthogonal_decay_base, $ + title = 'Exponent: ', $ + uvalue = 'nonorthogonal_weight_decay_power', $ + /double, $ + value = 2.7, $ + xsize = 8 $ + ) mesh_button = WIDGET_BUTTON(popup, VALUE='Generate mesh', $ uvalue='mesh', tooltip="Generate a new mesh") @@ -797,6 +813,7 @@ PRO event_handler, event in_psi_field:in_psi_field, $ out_psi_field:out_psi_field, $ npol_field:npol_field, $ + nonorthogonal_weight_decay_power:nonorthogonal_weight_decay_power, $ top:event.top} WIDGET_CONTROL, popup, set_uvalue=popup_info @@ -835,6 +852,7 @@ PRO event_handler, event str_set, info, "psi_outer_field", oldinfo.psi_outer_field, /over str_set, info, "rad_peak_field", oldinfo.rad_peak_field, /over str_set, info, "xpt_dist_field", oldinfo.xpt_dist_field, /over + str_set, info, "nonorthogonal_weight_decay_power", oldinfo.nonorthogonal_weight_decay_power, /over str_set, info, "status", oldinfo.status, /over str_set, info, "leftbargeom", oldinfo.leftbargeom, /over @@ -1185,6 +1203,7 @@ PRO hypnotoad simple_bndry:0, $ ; Use simplified boundary? xptonly_check:xptonly_check, $ ; xpt_only:0, $ ; x-point only non-orthogonal + nonorthogonal_weight_decay_power:2.7, $ ; how fast to decay towards orthogonal mesh radgrid_check:radgrid_check, $ single_rad_grid:1, $ smoothP_check:smoothP_check, $ From 611c08b9c707fed1804136271b5d776bc0964556 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Feb 2019 15:16:18 +0000 Subject: [PATCH 0867/1783] Allow passing arguments to unit tests, turning off quiet script --- tests/unit/makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unit/makefile b/tests/unit/makefile index dc971e959c..7eb3f77713 100644 --- a/tests/unit/makefile +++ b/tests/unit/makefile @@ -86,13 +86,16 @@ serial_tests: makefile $(BOUT_TOP)/make.config $(OBJ) $(LIB) $(SUB_LIBS) $(TEST_ @echo " Linking tests" @$(LD) -o $@ $(TEST_OBJECTS) bout_test_main.a $(LDFLAGS) $(BOUT_LIBS) $(SUB_LIBS) +# Override this on the command line to print full output from the unit tests +QUIET ?= ./quiet.sh + # Note: This depends on GTEST_SENTINEL, which checks out Google Test if not present # The correct behaviour relies on the dependencies being checked in left-to-right order # The GTEST_SENTINEL dependency cannot be added to the %.o target, since this results in the %.o # target in make.config being used instead. check: $(GTEST_SENTINEL) serial_tests @echo "Running unit test" - @./quiet.sh ./serial_tests + @$(QUIET) ./serial_tests $(GTEST_ARGS) # This is the same target as a make rule in make.config. Adding unmet dependencies here # results in makefile reverting to the make.config version. From c4f645a0697e105c16b889169618ecedfd1866c2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Feb 2019 15:16:47 +0000 Subject: [PATCH 0868/1783] Remove dependency on libbout from unit test source files No need to recompile all the test sources if implementation files have changed, just relink. Still need to recompile if a header changes --- tests/unit/makefile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/unit/makefile b/tests/unit/makefile index 7eb3f77713..9ab8c4ed0f 100644 --- a/tests/unit/makefile +++ b/tests/unit/makefile @@ -79,10 +79,8 @@ $(TARGET): makefile $(BOUT_TOP)/make.config $(OBJ) $(SUB_LIBS) bout_test_main.a TEST_SOURCES = $(shell find $(BOUT_TEST_DIR) -type f -name "test_*.cxx" 2> /dev/null) TEST_OBJECTS = $(TEST_SOURCES:%.cxx=%.o) -$(TEST_SOURCES): checklib -$(TEST_OBJECTS): $(LIB) $(GTEST_SENTINEL) - -serial_tests: makefile $(BOUT_TOP)/make.config $(OBJ) $(LIB) $(SUB_LIBS) $(TEST_OBJECTS) bout_test_main.a +serial_tests: makefile $(BOUT_TOP)/make.config $(OBJ) $(LIB) checklib \ + $(SUB_LIBS) $(TEST_OBJECTS) bout_test_main.a @echo " Linking tests" @$(LD) -o $@ $(TEST_OBJECTS) bout_test_main.a $(LDFLAGS) $(BOUT_LIBS) $(SUB_LIBS) From cdbe1b3642009f9cbd4b6c1fad7d653f29b21fe4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Feb 2019 15:18:22 +0000 Subject: [PATCH 0869/1783] Clean the unit tests with `make clean` --- make.config.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make.config.in b/make.config.in index 4fee8499e3..3323447936 100644 --- a/make.config.in +++ b/make.config.in @@ -313,7 +313,7 @@ endif # http://owen.sj.ca.us/~rk/howto/slides/make/slides/makecolon.html #################################################################### -clean:: +clean:: clean-unit-tests -@$(RM) -rf $(OBJ) $(DEPS) $(TARGET) @for pp in $(DIRS); do echo " " $$pp cleaned; $(MAKE) --no-print-directory -C $$pp clean; done @$(RM) -f $(SUB_LIBS) From 1c21f13e7b1302575903298c06fe57cc8c6d82da Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Feb 2019 15:46:07 +0000 Subject: [PATCH 0870/1783] Add some basic tests for initial_profile --- tests/unit/field/test_initialprofiles.cxx | 136 ++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 tests/unit/field/test_initialprofiles.cxx diff --git a/tests/unit/field/test_initialprofiles.cxx b/tests/unit/field/test_initialprofiles.cxx new file mode 100644 index 0000000000..4772b15b55 --- /dev/null +++ b/tests/unit/field/test_initialprofiles.cxx @@ -0,0 +1,136 @@ +#include "gtest/gtest.h" + +#include "boutexception.hxx" +#include "field.hxx" +#include "initialprofiles.hxx" +#include "output.hxx" +#include "test_extras.hxx" +#include "bout/constants.hxx" +#include "bout/mesh.hxx" + +/// Global mesh +namespace bout { +namespace globals { +extern Mesh* mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; + +class InitialProfileTest : public FakeMeshFixture { +public: + InitialProfileTest() : FakeMeshFixture() { + // We need a parallel transform as FieldFactory::create3D wants to + // un-field-align the result + mesh->setParallelTransform( + bout::utils::make_unique(*mesh)); + + output_info.disable(); + } + + ~InitialProfileTest() { + Options::cleanup(); + output_info.enable(); + } +}; + +TEST_F(InitialProfileTest, Field2D) { + Field2D result{mesh}; + + Options::root()["f"]["function"] = "pi"; + initial_profile("f", result); + + EXPECT_TRUE(IsFieldEqual(result, PI)); +} + +TEST_F(InitialProfileTest, Field3D) { + Field3D result{mesh}; + + Options::root()["g"]["function"] = "2*pi"; + initial_profile("g", result); + + EXPECT_TRUE(IsFieldEqual(result, TWOPI)); +} + +TEST_F(InitialProfileTest, Vector2D) { + Vector2D result{mesh}; + + Options::root()["f_x"]["function"] = "1"; + Options::root()["f_y"]["function"] = "2"; + Options::root()["f_z"]["function"] = "3"; + + initial_profile("f", result); + + EXPECT_TRUE(IsFieldEqual(result.x, 1)); + EXPECT_TRUE(IsFieldEqual(result.y, 2)); + EXPECT_TRUE(IsFieldEqual(result.z, 3)); +} + +TEST_F(InitialProfileTest, Vector3D) { + Vector3D result{mesh}; + + Options::root()["g_x"]["function"] = "4"; + Options::root()["g_y"]["function"] = "5"; + Options::root()["g_z"]["function"] = "6"; + + initial_profile("g", result); + + EXPECT_TRUE(IsFieldEqual(result.x, 4)); + EXPECT_TRUE(IsFieldEqual(result.y, 5)); + EXPECT_TRUE(IsFieldEqual(result.z, 6)); +} + +TEST_F(InitialProfileTest, Field2DWithScale) { + Field2D result{mesh}; + + Options::root()["f"]["function"] = "pi"; + Options::root()["f"]["scale"] = 2; + initial_profile("f", result); + + EXPECT_TRUE(IsFieldEqual(result, TWOPI)); +} + +TEST_F(InitialProfileTest, Field3DWithScale) { + Field3D result{mesh}; + + Options::root()["g"]["function"] = "2*pi"; + Options::root()["g"]["scale"] = 3; + initial_profile("g", result); + + EXPECT_TRUE(IsFieldEqual(result, 3 * TWOPI)); +} + +TEST_F(InitialProfileTest, Vector2DWithScale) { + Vector2D result{mesh}; + + Options::root()["f_x"]["function"] = "1"; + Options::root()["f_x"]["scale"] = 4; + Options::root()["f_y"]["function"] = "2"; + Options::root()["f_y"]["scale"] = 5; + Options::root()["f_z"]["function"] = "3"; + Options::root()["f_z"]["scale"] = 6; + + initial_profile("f", result); + + EXPECT_TRUE(IsFieldEqual(result.x, 4)); + EXPECT_TRUE(IsFieldEqual(result.y, 10)); + EXPECT_TRUE(IsFieldEqual(result.z, 18)); +} + +TEST_F(InitialProfileTest, Vector3DWithScale) { + Vector3D result{mesh}; + + Options::root()["g_x"]["function"] = "4"; + Options::root()["g_x"]["scale"] = 7; + Options::root()["g_y"]["function"] = "5"; + Options::root()["g_y"]["scale"] = 8; + Options::root()["g_z"]["function"] = "6"; + Options::root()["g_z"]["scale"] = 9; + + initial_profile("g", result); + + EXPECT_TRUE(IsFieldEqual(result.x, 28)); + EXPECT_TRUE(IsFieldEqual(result.y, 40)); + EXPECT_TRUE(IsFieldEqual(result.z, 54)); +} From 9cdc31e005eacbae60f819f70f22ca7957d5af28 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Feb 2019 15:53:17 +0000 Subject: [PATCH 0871/1783] Add initial profile tests for contravariant vectors --- tests/unit/field/test_initialprofiles.cxx | 34 +++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/tests/unit/field/test_initialprofiles.cxx b/tests/unit/field/test_initialprofiles.cxx index 4772b15b55..e2ae609c5d 100644 --- a/tests/unit/field/test_initialprofiles.cxx +++ b/tests/unit/field/test_initialprofiles.cxx @@ -53,7 +53,7 @@ TEST_F(InitialProfileTest, Field3D) { EXPECT_TRUE(IsFieldEqual(result, TWOPI)); } -TEST_F(InitialProfileTest, Vector2D) { +TEST_F(InitialProfileTest, Vector2DCovariant) { Vector2D result{mesh}; Options::root()["f_x"]["function"] = "1"; @@ -67,7 +67,7 @@ TEST_F(InitialProfileTest, Vector2D) { EXPECT_TRUE(IsFieldEqual(result.z, 3)); } -TEST_F(InitialProfileTest, Vector3D) { +TEST_F(InitialProfileTest, Vector3DCovariant) { Vector3D result{mesh}; Options::root()["g_x"]["function"] = "4"; @@ -81,6 +81,36 @@ TEST_F(InitialProfileTest, Vector3D) { EXPECT_TRUE(IsFieldEqual(result.z, 6)); } +TEST_F(InitialProfileTest, Vector2DContravariant) { + Vector2D result{mesh}; + result.covariant = false; + + Options::root()["fx"]["function"] = "7"; + Options::root()["fy"]["function"] = "8"; + Options::root()["fz"]["function"] = "9"; + + initial_profile("f", result); + + EXPECT_TRUE(IsFieldEqual(result.x, 7)); + EXPECT_TRUE(IsFieldEqual(result.y, 8)); + EXPECT_TRUE(IsFieldEqual(result.z, 9)); +} + +TEST_F(InitialProfileTest, Vector3DContravariant) { + Vector3D result{mesh}; + result.covariant = false; + + Options::root()["gx"]["function"] = "10"; + Options::root()["gy"]["function"] = "11"; + Options::root()["gz"]["function"] = "12"; + + initial_profile("g", result); + + EXPECT_TRUE(IsFieldEqual(result.x, 10)); + EXPECT_TRUE(IsFieldEqual(result.y, 11)); + EXPECT_TRUE(IsFieldEqual(result.z, 12)); +} + TEST_F(InitialProfileTest, Field2DWithScale) { Field2D result{mesh}; From a486a47f364d81de882a1a1a48ebfd1ef16561d3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Feb 2019 15:53:42 +0000 Subject: [PATCH 0872/1783] Add AUTO_TRACE to all initial_profile functions --- src/field/initialprofiles.cxx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/field/initialprofiles.cxx b/src/field/initialprofiles.cxx index 5fa35f98bb..4823f1ec52 100644 --- a/src/field/initialprofiles.cxx +++ b/src/field/initialprofiles.cxx @@ -50,7 +50,7 @@ void initial_profile(const std::string &name, Field3D &var) { - TRACE("initial_profile(string, Field3D)"); + AUTO_TRACE(); Mesh *localmesh = var.getMesh(); @@ -80,6 +80,7 @@ void initial_profile(const std::string &name, Field3D &var) { // For 2D variables almost identical, just no z dependence void initial_profile(const std::string &name, Field2D &var) { + AUTO_TRACE(); CELL_LOC loc = var.getLocation(); @@ -105,6 +106,8 @@ void initial_profile(const std::string &name, Field2D &var) { } void initial_profile(const std::string &name, Vector2D &var) { + AUTO_TRACE(); + if(var.covariant) { initial_profile(name + "_x", var.x); initial_profile(name + "_y", var.y); @@ -117,6 +120,8 @@ void initial_profile(const std::string &name, Vector2D &var) { } void initial_profile(const std::string &name, Vector3D &var) { + AUTO_TRACE(); + if(var.covariant) { initial_profile(name + "_x", var.x); initial_profile(name + "_y", var.y); From f90b4037b8e4f0a44a089d8d2b2fc903ce428729 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Feb 2019 15:57:43 +0000 Subject: [PATCH 0873/1783] Simplify staggered grids logic in initial profiles --- src/field/initialprofiles.cxx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/field/initialprofiles.cxx b/src/field/initialprofiles.cxx index 4823f1ec52..bc5a0a9286 100644 --- a/src/field/initialprofiles.cxx +++ b/src/field/initialprofiles.cxx @@ -54,11 +54,6 @@ void initial_profile(const std::string &name, Field3D &var) { Mesh *localmesh = var.getMesh(); - CELL_LOC loc = CELL_DEFAULT; - if (localmesh->StaggerGrids) { - loc = var.getLocation(); - } - // Get the section for this specific variable Options *varOpts = Options::getRoot()->getSection(name); @@ -70,7 +65,7 @@ void initial_profile(const std::string &name, Field3D &var) { VAROPTION(varOpts, function, "0.0"); // Create a 3D variable - var = f.create3D(function, varOpts, nullptr, loc); + var = f.create3D(function, varOpts, nullptr, var.getLocation()); // Optionally scale the variable BoutReal scale; @@ -82,8 +77,6 @@ void initial_profile(const std::string &name, Field3D &var) { void initial_profile(const std::string &name, Field2D &var) { AUTO_TRACE(); - CELL_LOC loc = var.getLocation(); - Mesh *localmesh = var.getMesh(); // Get the section for this variable @@ -97,7 +90,7 @@ void initial_profile(const std::string &name, Field2D &var) { std::string function; VAROPTION(varOpts, function, "0.0"); - var = f.create2D(function, varOpts, nullptr, loc); + var = f.create2D(function, varOpts, nullptr, var.getLocation()); // Optionally scale the variable BoutReal scale; From d4b02469f14cdde1c9dadaff618db94bae61c889 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Feb 2019 15:59:25 +0000 Subject: [PATCH 0874/1783] Remove left-over debugging output --- src/field/initialprofiles.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/field/initialprofiles.cxx b/src/field/initialprofiles.cxx index bc5a0a9286..11a67d0da7 100644 --- a/src/field/initialprofiles.cxx +++ b/src/field/initialprofiles.cxx @@ -81,7 +81,6 @@ void initial_profile(const std::string &name, Field2D &var) { // Get the section for this variable Options *varOpts = Options::getRoot()->getSection(name); - output << name; // Use FieldFactory to generate values From f4b22530422c44414f9aa09b7a30e7cd93186921 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Feb 2019 16:06:42 +0000 Subject: [PATCH 0875/1783] Remove some extraneous comments --- src/field/initialprofiles.cxx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/field/initialprofiles.cxx b/src/field/initialprofiles.cxx index 11a67d0da7..cd6eec3eab 100644 --- a/src/field/initialprofiles.cxx +++ b/src/field/initialprofiles.cxx @@ -54,17 +54,13 @@ void initial_profile(const std::string &name, Field3D &var) { Mesh *localmesh = var.getMesh(); - // Get the section for this specific variable Options *varOpts = Options::getRoot()->getSection(name); - // Use FieldFactory to generate values - FieldFactory f(localmesh); std::string function; VAROPTION(varOpts, function, "0.0"); - // Create a 3D variable var = f.create3D(function, varOpts, nullptr, var.getLocation()); // Optionally scale the variable @@ -73,17 +69,13 @@ void initial_profile(const std::string &name, Field3D &var) { var *= scale; } -// For 2D variables almost identical, just no z dependence void initial_profile(const std::string &name, Field2D &var) { AUTO_TRACE(); Mesh *localmesh = var.getMesh(); - // Get the section for this variable Options *varOpts = Options::getRoot()->getSection(name); - // Use FieldFactory to generate values - FieldFactory f(localmesh); std::string function; From f65e1483be20c8701d9838cd805209e931578d08 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Feb 2019 16:21:06 +0000 Subject: [PATCH 0876/1783] Tidy initial_profile headers; forward declare Field/Vectors --- include/initialprofiles.hxx | 8 ++++---- src/field/initialprofiles.cxx | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/include/initialprofiles.hxx b/include/initialprofiles.hxx index fe133b0c2e..c43fc3f6e7 100644 --- a/include/initialprofiles.hxx +++ b/include/initialprofiles.hxx @@ -26,10 +26,10 @@ #ifndef __INITIALPROF_H__ #define __INITIALPROF_H__ -#include "field3d.hxx" -#include "field2d.hxx" -#include "vector2d.hxx" -#include "vector3d.hxx" +class Field3D; +class Field2D; +class Vector2D; +class Vector3D; /*! * Set a field from options diff --git a/src/field/initialprofiles.cxx b/src/field/initialprofiles.cxx index cd6eec3eab..bb2b8b7ffa 100644 --- a/src/field/initialprofiles.cxx +++ b/src/field/initialprofiles.cxx @@ -41,12 +41,8 @@ #include #include #include -#include #include -#include -#include #include -#include "unused.hxx" void initial_profile(const std::string &name, Field3D &var) { From 5fbaed54a4845208594028aea49f82f287fa78fd Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Feb 2019 16:26:31 +0000 Subject: [PATCH 0877/1783] Clang-format initial profiles --- include/initialprofiles.hxx | 46 +++++++++++++++++------------------ src/field/initialprofiles.cxx | 43 ++++++++++++++++---------------- 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/include/initialprofiles.hxx b/include/initialprofiles.hxx index c43fc3f6e7..143c44544c 100644 --- a/include/initialprofiles.hxx +++ b/include/initialprofiles.hxx @@ -5,7 +5,7 @@ * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -33,9 +33,9 @@ class Vector3D; /*! * Set a field from options - * + * * This is called by Solver for each evolving field at the beginning - * of a simulation. + * of a simulation. * * * @param[in] name The name of the field. This will be used @@ -45,70 +45,70 @@ class Vector3D; * * * To create the value, it looks for a setting "function" - * in a section called name. If that is not found, then it looks + * in a section called name. If that is not found, then it looks * for "function" in a section called "All". If that is also not * found, then the value defaults to zero. - * + * * A second variable, "scale", can be used to multiply the function, * and defaults to 1.0 - * + * * Example * ------- * Given the input file: * - * [All] + * [All] * function = sin(y) - * + * * [pressure] * * [density] * scale = 0.2 - * + * * [vorticity] * function = cos(y) - * + * * initial_profile would generate: - * + * * o pressure -> sin(y) * o density -> 0.2*sin(y) * o vorticity -> cos(y) - * - */ -void initial_profile(const std::string &name, Field3D &var); + * + */ +void initial_profile(const std::string& name, Field3D& var); /*! * Set a Field2D from options * * @param[in] name The name of the field, used as a section name - * + * * @param[out] var The field which will be set to a value */ -void initial_profile(const std::string &name, Field2D &var); +void initial_profile(const std::string& name, Field2D& var); /*! * Set a vector to a value. The options used depend * on whether the vector is covariant or contravariant. - * + * * If covariant, then each component will be initialised * by adding "_x", "_y", "_z" to the name. - * + * * If contravariant, then each component will be initialised * by adding "x", "y" and "z" to the name. */ -void initial_profile(const std::string &name, Vector2D &var); +void initial_profile(const std::string& name, Vector2D& var); /*! * Set a vector to a value. The options used depend * on whether the vector is covariant or contravariant. - * + * * If covariant, then each component will be initialised * by adding "_x", "_y", "_z" to the name. - * + * * If contravariant, then each component will be initialised * by adding "x", "y" and "z" to the name. * - * + * */ -void initial_profile(const std::string &name, Vector3D &var); +void initial_profile(const std::string& name, Vector3D& var); #endif // __INITIALPROF_H__ diff --git a/src/field/initialprofiles.cxx b/src/field/initialprofiles.cxx index bb2b8b7ffa..36f382cfb0 100644 --- a/src/field/initialprofiles.cxx +++ b/src/field/initialprofiles.cxx @@ -3,22 +3,22 @@ * * ChangeLog * ========= - * + * * 2011-02-12 Ben Dudson * * Changed to use new options system. For now the structure of the * options is the same, but this could be modified more easily in future * * 2010-05-12 Ben Dudson - * + * * * Changed random numbers to use a hash of the parameters * so that the phase doesn't vary with number of processors or grid size * User can vary phase to give a different random sequence - * + * ************************************************************************** * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -39,24 +39,23 @@ #include #include #include +#include #include #include -#include #include - -void initial_profile(const std::string &name, Field3D &var) { +void initial_profile(const std::string& name, Field3D& var) { AUTO_TRACE(); - Mesh *localmesh = var.getMesh(); + Mesh* localmesh = var.getMesh(); + + Options* varOpts = Options::getRoot()->getSection(name); - Options *varOpts = Options::getRoot()->getSection(name); - FieldFactory f(localmesh); std::string function; VAROPTION(varOpts, function, "0.0"); - + var = f.create3D(function, varOpts, nullptr, var.getLocation()); // Optionally scale the variable @@ -65,13 +64,13 @@ void initial_profile(const std::string &name, Field3D &var) { var *= scale; } -void initial_profile(const std::string &name, Field2D &var) { +void initial_profile(const std::string& name, Field2D& var) { AUTO_TRACE(); - - Mesh *localmesh = var.getMesh(); - Options *varOpts = Options::getRoot()->getSection(name); - + Mesh* localmesh = var.getMesh(); + + Options* varOpts = Options::getRoot()->getSection(name); + FieldFactory f(localmesh); std::string function; @@ -85,28 +84,28 @@ void initial_profile(const std::string &name, Field2D &var) { var *= scale; } -void initial_profile(const std::string &name, Vector2D &var) { +void initial_profile(const std::string& name, Vector2D& var) { AUTO_TRACE(); - if(var.covariant) { + if (var.covariant) { initial_profile(name + "_x", var.x); initial_profile(name + "_y", var.y); initial_profile(name + "_z", var.z); - }else { + } else { initial_profile(name + "x", var.x); initial_profile(name + "y", var.y); initial_profile(name + "z", var.z); } } -void initial_profile(const std::string &name, Vector3D &var) { +void initial_profile(const std::string& name, Vector3D& var) { AUTO_TRACE(); - if(var.covariant) { + if (var.covariant) { initial_profile(name + "_x", var.x); initial_profile(name + "_y", var.y); initial_profile(name + "_z", var.z); - }else { + } else { initial_profile(name + "x", var.x); initial_profile(name + "y", var.y); initial_profile(name + "z", var.z); From 1ef58a4108143444cbbdc8beb8c5a96032137161 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Feb 2019 16:35:37 +0000 Subject: [PATCH 0878/1783] Remove clean-unit-tests from main clean recipe --- make.config.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make.config.in b/make.config.in index 3323447936..4fee8499e3 100644 --- a/make.config.in +++ b/make.config.in @@ -313,7 +313,7 @@ endif # http://owen.sj.ca.us/~rk/howto/slides/make/slides/makecolon.html #################################################################### -clean:: clean-unit-tests +clean:: -@$(RM) -rf $(OBJ) $(DEPS) $(TARGET) @for pp in $(DIRS); do echo " " $$pp cleaned; $(MAKE) --no-print-directory -C $$pp clean; done @$(RM) -f $(SUB_LIBS) From 0ca56f76039ed916d8f875fa44587b0ec18e7003 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 11:32:11 +0000 Subject: [PATCH 0879/1783] Add tests for BoutMask --- tests/unit/include/test_mask.cxx | 203 +++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 tests/unit/include/test_mask.cxx diff --git a/tests/unit/include/test_mask.cxx b/tests/unit/include/test_mask.cxx new file mode 100644 index 0000000000..d8f3c69529 --- /dev/null +++ b/tests/unit/include/test_mask.cxx @@ -0,0 +1,203 @@ +#include "gtest/gtest.h" + +#include "mask.hxx" +#include "boutexception.hxx" +#include "test_extras.hxx" + +/// Global mesh +namespace bout{ +namespace globals{ +extern Mesh *mesh; +} // namespace globals +} // namespace bout + +using MaskTest = FakeMeshFixture; + +TEST_F(MaskTest, Indexing) { + constexpr int nx{2}; + constexpr int ny{2}; + constexpr int nz{2}; + + BoutMask mask{nx, ny, nz}; + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_FALSE(mask(i, j, k)); + } + } + } + + mask(0, 1, 0) = true; + EXPECT_TRUE(mask(0, 1, 0)); +} + +TEST_F(MaskTest, ConstIndexing) { + constexpr int nx{2}; + constexpr int ny{2}; + constexpr int nz{2}; + + const BoutMask mask{nx, ny, nz}; + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_FALSE(mask(i, j, k)); + } + } + } +} + +#if CHECK >= 2 +TEST_F(MaskTest, BoundsChecking) { + constexpr int nx{2}; + constexpr int ny{2}; + constexpr int nz{2}; + + BoutMask mask{nx, ny, nz}; + + EXPECT_THROW(mask(nx + 1, 0, 0), BoutException); + EXPECT_THROW(mask(0, ny + 1, 0), BoutException); + EXPECT_THROW(mask(0, 0, nz + 1), BoutException); + EXPECT_THROW(mask(-1, 0, 0), BoutException); + EXPECT_THROW(mask(0, -1, 0), BoutException); + EXPECT_THROW(mask(0, 0, -1), BoutException); +} + +TEST_F(MaskTest, ConstBoundsChecking) { + constexpr int nx{2}; + constexpr int ny{2}; + constexpr int nz{2}; + + const BoutMask mask{nx, ny, nz}; + + EXPECT_THROW(mask(nx + 1, 0, 0), BoutException); + EXPECT_THROW(mask(0, ny + 1, 0), BoutException); + EXPECT_THROW(mask(0, 0, nz + 1), BoutException); + EXPECT_THROW(mask(-1, 0, 0), BoutException); + EXPECT_THROW(mask(0, -1, 0), BoutException); + EXPECT_THROW(mask(0, 0, -1), BoutException); +} +#endif + +TEST_F(MaskTest, Assignment) { + constexpr int nx{2}; + constexpr int ny{2}; + constexpr int nz{2}; + + BoutMask mask{nx, ny, nz}; + + mask = true; + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_TRUE(mask(i, j, k)); + } + } + } +} + +TEST_F(MaskTest, CreateOnGlobalMesh) { + BoutMask mask{}; + + for (int i = 0; i < MaskTest::nx; ++i) { + for (int j = 0; j < MaskTest::ny; ++j) { + for (int k = 0; k < MaskTest::nz; ++k) { + EXPECT_FALSE(mask(i, j, k)); + } + } + } +} + +TEST_F(MaskTest, CreateOnMesh) { + constexpr int nx{2}; + constexpr int ny{3}; + constexpr int nz{4}; + + FakeMesh mesh{nx, ny, nz}; + + BoutMask mask{mesh}; + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_FALSE(mask(i, j, k)); + } + } + } +} + +TEST_F(MaskTest, CreateOnMeshWithValueTrue) { + constexpr int nx{2}; + constexpr int ny{3}; + constexpr int nz{4}; + + FakeMesh mesh{nx, ny, nz}; + + BoutMask mask{mesh, true}; + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_TRUE(mask(i, j, k)); + } + } + } +} + +TEST_F(MaskTest, CreateOnMeshWithValueFalse) { + constexpr int nx{2}; + constexpr int ny{3}; + constexpr int nz{4}; + + FakeMesh mesh{nx, ny, nz}; + + BoutMask mask{mesh, false}; + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_FALSE(mask(i, j, k)); + } + } + } +} + +TEST_F(MaskTest, CreateFromIndicesWithValueTrue) { + constexpr int nx{2}; + constexpr int ny{2}; + constexpr int nz{2}; + + BoutMask mask{nx, ny, nz, true}; + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_TRUE(mask(i, j, k)); + } + } + } + + mask(0, 1, 0) = false; + EXPECT_FALSE(mask(0, 1, 0)); +} + +TEST_F(MaskTest, CreateFromIndicesWithValueFalse) { + constexpr int nx{2}; + constexpr int ny{2}; + constexpr int nz{2}; + + BoutMask mask{nx, ny, nz, false}; + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + for (int k = 0; k < nz; ++k) { + EXPECT_FALSE(mask(i, j, k)); + } + } + } + + mask(0, 1, 0) = true; + EXPECT_TRUE(mask(0, 1, 0)); +} From eca388a68aa4edac71954819672f60da04c825a2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 11:32:30 +0000 Subject: [PATCH 0880/1783] Silence FieldFactoryTest parse error test --- tests/unit/field/test_field_factory.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index 8fa5ac644d..dcd516f242 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -564,12 +564,14 @@ TEST_F(FieldFactoryTest, ParseSelfReference) { output.disable(); output_info.disable(); + output_error.disable(); auto options = Options{}; options["a"] = "a"; EXPECT_THROW(factory.parse("a", &options), BoutException); + output_error.enable(); output_info.enable(); output.enable(); } From 7673cc7842b513b1d01618934f2f07589d2547b3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 11:32:59 +0000 Subject: [PATCH 0881/1783] Add tests for FieldFunction, FieldNull generators --- tests/unit/field/test_field_factory.cxx | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index dcd516f242..04ac9f9ab6 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -79,6 +79,29 @@ TYPED_TEST(FieldFactoryCreationTest, CreateFromPointerGenerator) { EXPECT_TRUE(IsFieldEqual(output, value)); } +TYPED_TEST(FieldFactoryCreationTest, CreateFromFunction) { + FuncPtr function = [](BoutReal, BoutReal x, BoutReal, BoutReal) -> BoutReal { + return x + 1.; + }; + + auto generator = std::make_shared(FieldFunction{function}); + + auto output = this->create(generator); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { return index.x() + 1.; }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TYPED_TEST(FieldFactoryCreationTest, CreateNull) { + FieldNull null{}; + auto output = this->create(null.clone({})); + + EXPECT_TRUE(IsFieldEqual(output, 0.0)); +} + TYPED_TEST(FieldFactoryCreationTest, CreatePi) { auto output = this->create("pi"); From 3c823a11ab9255be58b1f65086b610f55139c6e8 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 11:33:24 +0000 Subject: [PATCH 0882/1783] Tidy FieldFunction, FieldNull --- include/field_factory.hxx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/include/field_factory.hxx b/include/field_factory.hxx index 92599b2c89..b9d8b42df0 100644 --- a/include/field_factory.hxx +++ b/include/field_factory.hxx @@ -119,7 +119,7 @@ class FieldFunction : public FieldGenerator { public: FieldFunction() = delete; FieldFunction(FuncPtr userfunc) : func(userfunc) {} - double generate(double x, double y, double z, double t) override { + BoutReal generate(BoutReal x, BoutReal y, BoutReal z, BoutReal t) override { return func(t, x, y, z); } @@ -132,8 +132,9 @@ private: class FieldNull : public FieldGenerator { public: - double generate(double UNUSED(x), double UNUSED(y), double UNUSED(z), - double UNUSED(t)) override { + FieldNull() = default; + BoutReal generate(BoutReal UNUSED(x), BoutReal UNUSED(y), BoutReal UNUSED(z), + BoutReal UNUSED(t)) override { return 0.0; } FieldGeneratorPtr clone(const std::list UNUSED(args)) override { @@ -141,14 +142,9 @@ public: } /// Singeton static FieldGeneratorPtr get() { - static FieldGeneratorPtr instance = nullptr; - - if (!instance) - instance = std::make_shared(); + static FieldGeneratorPtr instance = std::make_shared(); return instance; } - -private: }; #endif // __FIELD_FACTORY_H__ From 9b8eddea9eeb3a06be866878e3971237a027b106 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 11:33:36 +0000 Subject: [PATCH 0883/1783] Use using-declaration instead of typedef for FuncPtr --- include/bout_types.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 219341d770..9859bbb14b 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -75,6 +75,6 @@ struct enumWrapper { }; /// Boundary condition function -typedef BoutReal (*FuncPtr)(BoutReal t, BoutReal x, BoutReal y, BoutReal z); +using FuncPtr = BoutReal(*)(BoutReal t, BoutReal x, BoutReal y, BoutReal z); #endif // __BOUT_TYPES_H__ From 0783386d2b43fbf452f021e2fd522d7f53df4ce0 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 13:33:33 +0000 Subject: [PATCH 0884/1783] Fix some memory leaks in unit tests --- tests/unit/bout_test_main.cxx | 2 ++ .../include/bout/test_generic_factory.cxx | 22 +++++++++---------- .../include/test_interpolation_factory.cxx | 8 +++---- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/tests/unit/bout_test_main.cxx b/tests/unit/bout_test_main.cxx index 40c9fb3f01..a8a113ff6e 100644 --- a/tests/unit/bout_test_main.cxx +++ b/tests/unit/bout_test_main.cxx @@ -17,5 +17,7 @@ GTEST_API_ int main(int argc, char** argv) { // Clean up the array store, so valgrind doesn't report false // positives Array::cleanup(); + Array::cleanup(); + Array::cleanup(); return result; } diff --git a/tests/unit/include/bout/test_generic_factory.cxx b/tests/unit/include/bout/test_generic_factory.cxx index 5a34864b21..50d1065f18 100644 --- a/tests/unit/include/bout/test_generic_factory.cxx +++ b/tests/unit/include/bout/test_generic_factory.cxx @@ -73,25 +73,25 @@ RegisterInFactory TEST(GenericFactory, RegisterAndCreate) { - auto base_ = Factory::getInstance().create("base"); + std::unique_ptr base_{Factory::getInstance().create("base")}; EXPECT_EQ(base_->foo(), "Base"); - auto derived1_ = Factory::getInstance().create("derived1"); + std::unique_ptr derived1_{Factory::getInstance().create("derived1")}; EXPECT_EQ(derived1_->foo(), "Derived1"); - auto derived2_ = Factory::getInstance().create("derived2"); + std::unique_ptr derived2_{Factory::getInstance().create("derived2")}; EXPECT_EQ(derived2_->foo(), "Derived2"); } TEST(GenericFactory, ListAvailable) { - auto available = Factory::getInstance().listAvailable(); + auto available{Factory::getInstance().listAvailable()}; std::vector expected{"base", "derived1", "derived2"}; EXPECT_EQ(available, expected); } TEST(GenericFactory, Remove) { - auto available = Factory::getInstance().listAvailable(); + auto available{Factory::getInstance().listAvailable()}; std::vector expected{"base", "derived1", "derived2"}; EXPECT_EQ(available, expected); @@ -118,15 +118,15 @@ TEST(GenericFactory, GetUnknownType) { TEST(GenericFactory, Complicated) { - auto base_ = - ComplicatedFactory::getInstance().create("basecomplicated", "BaseComplicated"); + std::unique_ptr base_{ + ComplicatedFactory::getInstance().create("basecomplicated", "BaseComplicated")}; EXPECT_EQ(base_->foo(), "BaseComplicated"); - auto derived1_ = ComplicatedFactory::getInstance().create("derivedcomplicated1", - "DerivedComplicated1"); + std::unique_ptr derived1_{ComplicatedFactory::getInstance().create( + "derivedcomplicated1", "DerivedComplicated1")}; EXPECT_EQ(derived1_->foo(), "DerivedComplicated1"); - auto derived2_ = ComplicatedFactory::getInstance().create("derivedcomplicated2", - "DerivedComplicated2"); + std::unique_ptr derived2_{ComplicatedFactory::getInstance().create( + "derivedcomplicated2", "DerivedComplicated2")}; EXPECT_EQ(derived2_->foo(), "DerivedComplicated2"); } diff --git a/tests/unit/include/test_interpolation_factory.cxx b/tests/unit/include/test_interpolation_factory.cxx index 59e1817826..531c7484d8 100644 --- a/tests/unit/include/test_interpolation_factory.cxx +++ b/tests/unit/include/test_interpolation_factory.cxx @@ -79,8 +79,8 @@ TEST_F(InterpolationFactoryTest, CreateInterpolation) { [](Mesh* mesh) -> Interpolation* { return new TestInterpolation(mesh); }, "test_interpolation"); - Interpolation* interpolation{nullptr}; - EXPECT_NO_THROW(interpolation = InterpolationFactory::getInstance()->create("test_interpolation")); + std::unique_ptr interpolation{nullptr}; + EXPECT_NO_THROW(interpolation.reset(InterpolationFactory::getInstance()->create("test_interpolation"))); EXPECT_TRUE(IsFieldEqual(interpolation->interpolate(Field3D{}), -1)); } @@ -92,8 +92,8 @@ TEST_F(InterpolationFactoryTest, CreateInterpolationFromOptions) { Options::root()["interpolation"]["type"] = "test_interpolation"; - Interpolation* interpolation{nullptr}; - EXPECT_NO_THROW(interpolation = InterpolationFactory::getInstance()->create()); + std::unique_ptr interpolation{nullptr}; + EXPECT_NO_THROW(interpolation.reset(InterpolationFactory::getInstance()->create())); EXPECT_TRUE(IsFieldEqual(interpolation->interpolate(Field3D{}), -1)); } From f5ee06977183b4a8cfae8690c5407f57297a5707 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 14:44:10 +0000 Subject: [PATCH 0885/1783] Replace lambda in InterpolationFactoryTest with free function --- .../include/test_interpolation_factory.cxx | 56 ++++++++++--------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/tests/unit/include/test_interpolation_factory.cxx b/tests/unit/include/test_interpolation_factory.cxx index 531c7484d8..b2654abe3d 100644 --- a/tests/unit/include/test_interpolation_factory.cxx +++ b/tests/unit/include/test_interpolation_factory.cxx @@ -2,9 +2,9 @@ #include "interpolation.hxx" #include "interpolation_factory.hxx" +#include "options.hxx" #include "unused.hxx" #include "bout/mesh.hxx" -#include "options.hxx" #include "test_extras.hxx" @@ -15,18 +15,6 @@ bool sentinel_set{false}; } // namespace testing } // namespace bout -class InterpolationFactoryTest : public FakeMeshFixture { -public: - InterpolationFactoryTest() : FakeMeshFixture() { - output_info.disable(); - } - ~InterpolationFactoryTest() { - output_info.enable(); - InterpolationFactory::getInstance()->cleanup(); - bout::testing::sentinel_set = false; - } -}; - class TestInterpolation : public Interpolation { public: TestInterpolation(Mesh* mesh = nullptr) : Interpolation(0, mesh) {} @@ -60,6 +48,24 @@ class TestInterpolation : public Interpolation { }; }; +class InterpolationFactoryTest : public FakeMeshFixture { +public: + InterpolationFactoryTest() : FakeMeshFixture() { + output_info.disable(); + output_warn.disable(); + } + ~InterpolationFactoryTest() { + output_warn.enable(); + output_info.enable(); + InterpolationFactory::getInstance()->cleanup(); + bout::testing::sentinel_set = false; + } +}; + +auto test_interpolation(Mesh* mesh) -> Interpolation* { + return new TestInterpolation(mesh); +}; + TEST_F(InterpolationFactoryTest, GetInstance) { EXPECT_NE(InterpolationFactory::getInstance(), nullptr); } @@ -69,26 +75,23 @@ TEST_F(InterpolationFactoryTest, GetDefaultInterpType) { } TEST_F(InterpolationFactoryTest, AddInterpolation) { - EXPECT_NO_THROW(InterpolationFactory::getInstance()->add( - [](Mesh* mesh) -> Interpolation* { return new TestInterpolation(mesh); }, - "test_interpolation")); + EXPECT_NO_THROW( + InterpolationFactory::getInstance()->add(test_interpolation, "test_interpolation")); +} } TEST_F(InterpolationFactoryTest, CreateInterpolation) { - InterpolationFactory::getInstance()->add( - [](Mesh* mesh) -> Interpolation* { return new TestInterpolation(mesh); }, - "test_interpolation"); + InterpolationFactory::getInstance()->add(test_interpolation, "test_interpolation"); std::unique_ptr interpolation{nullptr}; - EXPECT_NO_THROW(interpolation.reset(InterpolationFactory::getInstance()->create("test_interpolation"))); + EXPECT_NO_THROW(interpolation.reset( + InterpolationFactory::getInstance()->create("test_interpolation"))); EXPECT_TRUE(IsFieldEqual(interpolation->interpolate(Field3D{}), -1)); } TEST_F(InterpolationFactoryTest, CreateInterpolationFromOptions) { - InterpolationFactory::getInstance()->add( - [](Mesh* mesh) -> Interpolation* { return new TestInterpolation(mesh); }, - "test_interpolation"); + InterpolationFactory::getInstance()->add(test_interpolation, "test_interpolation"); Options::root()["interpolation"]["type"] = "test_interpolation"; @@ -103,11 +106,10 @@ TEST_F(InterpolationFactoryTest, CreateUnknownInterpolation) { } TEST_F(InterpolationFactoryTest, Cleanup) { - InterpolationFactory::getInstance()->add( - [](Mesh* mesh) -> Interpolation* { return new TestInterpolation(mesh); }, - "to be removed"); + InterpolationFactory::getInstance()->add(test_interpolation, "to be removed"); InterpolationFactory::getInstance()->cleanup(); - EXPECT_THROW(InterpolationFactory::getInstance()->create("to be removed"), BoutException); + EXPECT_THROW(InterpolationFactory::getInstance()->create("to be removed"), + BoutException); } From 9a6b4e32e3a93f8b7e78fc7bdbadc868aacd87db Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 14:44:41 +0000 Subject: [PATCH 0886/1783] Add InterpolationFactory tests for missing functions --- .../include/test_interpolation_factory.cxx | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/unit/include/test_interpolation_factory.cxx b/tests/unit/include/test_interpolation_factory.cxx index b2654abe3d..307eebc080 100644 --- a/tests/unit/include/test_interpolation_factory.cxx +++ b/tests/unit/include/test_interpolation_factory.cxx @@ -78,6 +78,12 @@ TEST_F(InterpolationFactoryTest, AddInterpolation) { EXPECT_NO_THROW( InterpolationFactory::getInstance()->add(test_interpolation, "test_interpolation")); } + +TEST_F(InterpolationFactoryTest, AddInterpolationTwice) { + EXPECT_NO_THROW( + InterpolationFactory::getInstance()->add(test_interpolation, "test_interpolation")); + EXPECT_NO_THROW( + InterpolationFactory::getInstance()->add(test_interpolation, "test_interpolation")); } TEST_F(InterpolationFactoryTest, CreateInterpolation) { @@ -101,6 +107,21 @@ TEST_F(InterpolationFactoryTest, CreateInterpolationFromOptions) { EXPECT_TRUE(IsFieldEqual(interpolation->interpolate(Field3D{}), -1)); } +TEST_F(InterpolationFactoryTest, CreateInterpolationOnMesh) { + InterpolationFactory::getInstance()->add(test_interpolation, "test_interpolation"); + + Options::root()["interpolation"]["type"] = "test_interpolation"; + + FakeMesh localmesh{2, 2, 2}; + std::unique_ptr interpolation{nullptr}; + EXPECT_NO_THROW( + interpolation.reset(InterpolationFactory::getInstance()->create(&localmesh))); + + interpolation->calcWeights({}, {}); + + EXPECT_TRUE(bout::testing::sentinel_set); +} + TEST_F(InterpolationFactoryTest, CreateUnknownInterpolation) { EXPECT_THROW(InterpolationFactory::getInstance()->create("nonsense"), BoutException); } From ba112a645ac0abe780d2765fb74814fbc10e0adb Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 14:46:29 +0000 Subject: [PATCH 0887/1783] Use output_warn in InterpolationFactory --- src/mesh/interpolation/interpolation_factory.cxx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mesh/interpolation/interpolation_factory.cxx b/src/mesh/interpolation/interpolation_factory.cxx index f77d2f2658..c09da0bbd5 100644 --- a/src/mesh/interpolation/interpolation_factory.cxx +++ b/src/mesh/interpolation/interpolation_factory.cxx @@ -65,9 +65,8 @@ Interpolation* InterpolationFactory::create(const std::string &name, Options *op } void InterpolationFactory::add(CreateInterpCallback interp, const std::string &name) { - if ((findInterpolation(name)) != nullptr) { - // error - already exists - output << "ERROR: Trying to add an already existing interpolation: " << name << endl; + if (findInterpolation(name) != nullptr) { + output_warn << "ERROR: Trying to add an already existing interpolation: " << name << endl; return; } interp_map[lowercase(name)] = interp; From 5188a86bebbdbeba0d692fc23f87901ee6ea343c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 14:46:39 +0000 Subject: [PATCH 0888/1783] Remove useless InterpolationFactory::create overload Already covered by create(Options*, Mesh*) --- include/interpolation_factory.hxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/interpolation_factory.hxx b/include/interpolation_factory.hxx index 43e9c092d1..1529ddcfa5 100644 --- a/include/interpolation_factory.hxx +++ b/include/interpolation_factory.hxx @@ -47,9 +47,6 @@ public: Interpolation *create(Mesh *mesh) { return create(nullptr, mesh); } - Interpolation *create(Options *options) { - return create(options, nullptr); - } Interpolation *create(Options *options = nullptr, Mesh *mesh = nullptr); /// Create an Interpolation object From deefc57190b5be841a6465832b00b6d2eab1c853 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 14:47:40 +0000 Subject: [PATCH 0889/1783] Clang-format InterpolationFactory --- include/interpolation_factory.hxx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/interpolation_factory.hxx b/include/interpolation_factory.hxx index 1529ddcfa5..d76f2d5854 100644 --- a/include/interpolation_factory.hxx +++ b/include/interpolation_factory.hxx @@ -13,6 +13,7 @@ class InterpolationFactory { public: /// Callback function definition for creating Interpolation objects using CreateInterpCallback = Interpolation* (*)(Mesh*); + private: /// Add the available interpolation methods to the internal map /// @@ -30,9 +31,10 @@ private: /// @param name Name of the interpolation method /// /// @return A pointer to the Interpolation object in the map - CreateInterpCallback findInterpolation(const std::string &name); + CreateInterpCallback findInterpolation(const std::string& name); + public: - ~InterpolationFactory() {}; + ~InterpolationFactory(){}; /// Create or get the singleton instance of the factory static InterpolationFactory* getInstance(); @@ -44,10 +46,8 @@ public: inline std::string getDefaultInterpType() { return "hermitespline"; } /// Create an interpolation object - Interpolation *create(Mesh *mesh) { - return create(nullptr, mesh); - } - Interpolation *create(Options *options = nullptr, Mesh *mesh = nullptr); + Interpolation* create(Mesh* mesh) { return create(nullptr, mesh); } + Interpolation* create(Options* options = nullptr, Mesh* mesh = nullptr); /// Create an Interpolation object /// @@ -56,11 +56,11 @@ public: /// @param mesh A Mesh object to construct the interpolation on /// /// @return A new copy of an Interpolation object - Interpolation *create(const std::string &name, Options *options = nullptr, - Mesh *mesh = nullptr); + Interpolation* create(const std::string& name, Options* options = nullptr, + Mesh* mesh = nullptr); /// Add available interpolations to database - void add(CreateInterpCallback interp, const std::string &name); + void add(CreateInterpCallback interp, const std::string& name); }; #endif //__INTERP_FACTORY_H__ From b48b933b134e896014a383ab191ab2a622004a13 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 15:17:06 +0000 Subject: [PATCH 0890/1783] Add some missing FieldFactory tests --- tests/unit/field/test_field_factory.cxx | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index 04ac9f9ab6..47273d006c 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -305,6 +305,18 @@ TYPED_TEST(FieldFactoryCreationTest, CreateAtanX) { EXPECT_TRUE(IsFieldEqual(output, expected)); } +TYPED_TEST(FieldFactoryCreationTest, CreateAtanX2) { + auto output = this->create("atan(x, 2)"); + + auto expected = makeField( + [](typename TypeParam::ind_type& index) -> BoutReal { + return std::atan2(index.x(), 2.); + }, + mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + TYPED_TEST(FieldFactoryCreationTest, CreateSinhX) { auto output = this->create("sinh(x)"); @@ -566,6 +578,16 @@ class FieldFactoryTest : public FakeMeshFixture { FieldFactory factory; }; +TEST_F(FieldFactoryTest, RequireMesh) { + delete bout::globals::mesh; + bout::globals::mesh = nullptr; + + FieldFactory local_factory{nullptr, nullptr}; + + EXPECT_THROW(local_factory.create2D("x", nullptr, nullptr), BoutException); + EXPECT_THROW(local_factory.create3D("x", nullptr, nullptr), BoutException); +} + TEST_F(FieldFactoryTest, CleanCache) { auto a_value = int{6}; From d5c9a57b45c03ef21223bccc9af3e2b9547c5d77 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 15:33:30 +0000 Subject: [PATCH 0891/1783] Add tests for GridDataFromOptions --- .../mesh/data/test_griddatafromoptions.cxx | 228 ++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 tests/unit/mesh/data/test_griddatafromoptions.cxx diff --git a/tests/unit/mesh/data/test_griddatafromoptions.cxx b/tests/unit/mesh/data/test_griddatafromoptions.cxx new file mode 100644 index 0000000000..39eb43b59e --- /dev/null +++ b/tests/unit/mesh/data/test_griddatafromoptions.cxx @@ -0,0 +1,228 @@ +#include "gtest/gtest.h" + +#include "options.hxx" +#include "output.hxx" +#include "test_extras.hxx" +#include "bout/constants.hxx" +#include "bout/griddata.hxx" +#include "bout/mesh.hxx" + +#include +#include +#include + +/// Global mesh +namespace bout { +namespace globals { +extern Mesh* mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; + +class GridFromOptionsTest : public FakeMeshFixture { +public: + GridFromOptionsTest() : FakeMeshFixture(), options(), griddata(&options) { + // We need a parallel transform as FieldFactory::create3D wants to + // un-field-align the result + mesh->setParallelTransform( + bout::utils::make_unique(*mesh)); + + output_info.disable(); + output_warn.disable(); + options["f"] = expected_string; + } + + ~GridFromOptionsTest() { + Options::cleanup(); + output_info.enable(); + output_warn.enable(); + } + + Options options; + GridFromOptions griddata; + std::string expected_string{"x + y + z + 3"}; +}; + +TEST_F(GridFromOptionsTest, HasVar) { + EXPECT_TRUE(griddata.hasVar("f")); + EXPECT_FALSE(griddata.hasVar("non-existent")); +} + +TEST_F(GridFromOptionsTest, GetString) { + std::string result{"wrong"}; + + EXPECT_TRUE(griddata.get(mesh, result, "f")); + EXPECT_EQ(result, expected_string); +} + +TEST_F(GridFromOptionsTest, GetStringNone) { + std::string result{"wrong"}; + + EXPECT_FALSE(griddata.get(mesh, result, "non-existent")); + EXPECT_EQ(result, std::string{}); +} + +TEST_F(GridFromOptionsTest, GetInt) { + int result{-1}; + int expected{3}; + + EXPECT_TRUE(griddata.get(mesh, result, "f")); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetIntNone) { + int result{-1}; + int expected{0}; + + EXPECT_FALSE(griddata.get(mesh, result, "non-existent")); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetBoutReal) { + BoutReal result{-1.}; + BoutReal expected{3.}; + + EXPECT_TRUE(griddata.get(mesh, result, "f")); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetBoutRealNone) { + BoutReal result{-1.}; + BoutReal expected{0}; + + EXPECT_FALSE(griddata.get(mesh, result, "non-existent")); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetField2D) { + Field2D result{mesh}; + Field2D expected{makeField( + [](Field2D::ind_type& index) { + return index.x() + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; + }, + mesh)}; + + EXPECT_TRUE(griddata.get(mesh, result, "f")); + EXPECT_TRUE(IsFieldEqual(result, expected)); +} + +TEST_F(GridFromOptionsTest, GetField2DNone) { + Field2D result{mesh}; + BoutReal expected{0.}; + + EXPECT_FALSE(griddata.get(mesh, result, "non-existent")); + EXPECT_TRUE(IsFieldEqual(result, expected)); +} + +TEST_F(GridFromOptionsTest, GetField2DNoneWithDefault) { + Field2D result{mesh}; + BoutReal default_value{-32}; + + EXPECT_FALSE(griddata.get(mesh, result, "non-existent", default_value)); + EXPECT_TRUE(IsFieldEqual(result, default_value)); +} + +TEST_F(GridFromOptionsTest, GetField3D) { + Field3D result{mesh}; + Field3D expected{makeField( + [](Field3D::ind_type& index) { + return index.x() + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; + }, + mesh)}; + + EXPECT_TRUE(griddata.get(mesh, result, "f")); + EXPECT_TRUE(IsFieldEqual(result, expected)); + + EXPECT_FALSE(griddata.get(mesh, result, "non-existent")); + EXPECT_TRUE(IsFieldEqual(result, 0.)); + + BoutReal default_value{-64}; + EXPECT_FALSE(griddata.get(mesh, result, "non-existent", default_value)); + EXPECT_TRUE(IsFieldEqual(result, default_value)); +} + +TEST_F(GridFromOptionsTest, GetField3DNone) { + Field3D result{mesh}; + BoutReal expected{0.}; + + EXPECT_FALSE(griddata.get(mesh, result, "non-existent")); + EXPECT_TRUE(IsFieldEqual(result, expected)); +} + +TEST_F(GridFromOptionsTest, GetField3DNoneWithDefault) { + Field3D result{mesh}; + BoutReal default_value{-64}; + + EXPECT_FALSE(griddata.get(mesh, result, "non-existent", default_value)); + EXPECT_TRUE(IsFieldEqual(result, default_value)); +} + +TEST_F(GridFromOptionsTest, GetVectorInt) { + std::vector result{}; + std::vector expected{3, 3, 3}; + + EXPECT_TRUE(griddata.get(mesh, result, "f", 3)); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetVectorIntNone) { + std::vector result{-1, -1, -1}; + std::vector expected{}; + + EXPECT_FALSE(griddata.get(mesh, result, "non-existent", 3)); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetVectorBoutRealX) { + std::vector result{}; + std::vector expected{3., 4., 5.}; + + EXPECT_TRUE(griddata.get(mesh, result, "f", nx)); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetVectorBoutRealXNone) { + std::vector result{}; + std::vector default_expected{}; + EXPECT_FALSE(griddata.get(mesh, result, "non-existent", nx)); + EXPECT_EQ(result, default_expected); +} + +TEST_F(GridFromOptionsTest, GetVectorBoutRealY) { + std::vector result{}; + std::vector expected{3., 3. + TWOPI, 3. + 2. * TWOPI, 3. + 3. * TWOPI, + 3. + 4. * TWOPI}; + + EXPECT_TRUE(griddata.get(mesh, result, "f", ny, 0., GridDataSource::Direction::Y)); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetVectorBoutRealYNone) { + std::vector result{}; + std::vector default_expected{}; + EXPECT_FALSE(griddata.get(mesh, result, "non-existent", ny)); + EXPECT_EQ(result, default_expected); +} + +TEST_F(GridFromOptionsTest, GetVectorBoutRealZ) { + std::vector result{}; + std::vector expected{3., + 3. + (1. * TWOPI / nz), + 3. + (2. * TWOPI / nz), + 3. + (3. * TWOPI / nz), + 3. + (4. * TWOPI / nz), + 3. + (5. * TWOPI / nz), + 3. + (6. * TWOPI / nz)}; + + EXPECT_TRUE(griddata.get(mesh, result, "f", nz, 0., GridDataSource::Direction::Z)); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetVectorBoutRealZNone) { + std::vector result{}; + std::vector default_expected{}; + EXPECT_FALSE(griddata.get(mesh, result, "non-existent", nz)); + EXPECT_EQ(result, default_expected); +} From 36ca115f07f506cb73a336dcb17956b09a95132a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 15:36:46 +0000 Subject: [PATCH 0892/1783] Return empty vectors from GridFromOptions::get(Mesh, vector<>) Previously would leave `var` unchanged, in contrast to the other overloads --- src/mesh/data/gridfromoptions.cxx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index 6e2a855902..0db79e6c66 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -77,10 +77,16 @@ bool GridFromOptions::get(Mesh *m, std::vector &var, const std::string &nam int UNUSED(offset), GridDataSource::Direction UNUSED(dir)) { // Integers not expressions yet - int ival; - if(!get(m, ival, name)) + if (!hasVar(name)) { + std::vector def{}; + output_warn.write("Variable '%s' not in mesh options. Setting to empty vector\n", + name.c_str()); + var = def; return false; + } + int ival; + get(m, ival, name); var.resize(len, ival); return true; @@ -90,6 +96,10 @@ bool GridFromOptions::get(Mesh *m, std::vector &var, const std::string int offset, GridDataSource::Direction dir) { if(!hasVar(name)) { + std::vector def{}; + output_warn.write("Variable '%s' not in mesh options. Setting to empty vector\n", + name.c_str()); + var = def; return false; } From 25df06c3308f1cbb0d1c409cf351a95e0edafed3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 15:39:39 +0000 Subject: [PATCH 0893/1783] Be more consistent with warning when variables not found Some `GridFromOptions::get` overloads would warn. Now all warn consistently --- src/mesh/data/gridfromoptions.cxx | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index 0db79e6c66..8620fbcd19 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -16,8 +16,11 @@ bool GridFromOptions::hasVar(const std::string &name) { } bool GridFromOptions::get(Mesh *UNUSED(m), std::string &sval, const std::string &name) { - if(!hasVar(name)) { - sval = ""; + if (!hasVar(name)) { + const std::string def{}; + output_warn.write("Variable '%s' not in mesh options. Setting to \"%s\"\n", + name.c_str(), def.c_str()); + sval = def; return false; } @@ -26,8 +29,11 @@ bool GridFromOptions::get(Mesh *UNUSED(m), std::string &sval, const std::string } bool GridFromOptions::get(Mesh *UNUSED(m), int &ival, const std::string &name) { - if(!hasVar(name)) { - ival = 0; + if (!hasVar(name)) { + constexpr int def{0}; + output_warn.write("Variable '%s' not in mesh options. Setting to %d\n", name.c_str(), + def); + ival = def; return false; } @@ -36,8 +42,11 @@ bool GridFromOptions::get(Mesh *UNUSED(m), int &ival, const std::string &name) { } bool GridFromOptions::get(Mesh *UNUSED(m), BoutReal &rval, const std::string &name) { - if(!hasVar(name)) { - rval = 0.0; + if (!hasVar(name)) { + constexpr BoutReal def{0.0}; + output_warn.write("Variable '%s' not in mesh options. Setting to %e\n", name.c_str(), + def); + rval = def; return false; } @@ -64,7 +73,9 @@ bool GridFromOptions::get(Mesh *m, Field2D &var, const std::string &name, BoutRe } bool GridFromOptions::get(Mesh *m, Field3D &var, const std::string &name, BoutReal def) { - if(!hasVar(name)) { + if (!hasVar(name)) { + output_warn.write("Variable '%s' not in mesh options. Setting to %e\n", name.c_str(), + def); var = def; return false; } From d2bf30bb4958a90ce4c47e91fa5e08ef79640d24 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 15:42:55 +0000 Subject: [PATCH 0894/1783] Use new Options interface, auto in GridFromOptions --- src/mesh/data/gridfromoptions.cxx | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index 8620fbcd19..54dd4ddba5 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -49,13 +49,9 @@ bool GridFromOptions::get(Mesh *UNUSED(m), BoutReal &rval, const std::string &na rval = def; return false; } - - // Fetch expression as a string - std::string expr; - options->get(name, expr, "0"); - // Parse, and evaluate with x,y,z,t = 0 - std::shared_ptr gen = FieldFactory::get()->parse(expr, options); + auto expr = (*options)[name].withDefault(std::string{"0"}); + auto gen = FieldFactory::get()->parse(expr, options); rval = gen->generate(0.0, 0.0, 0.0, 0.0); return true; @@ -114,12 +110,8 @@ bool GridFromOptions::get(Mesh *m, std::vector &var, const std::string return false; } - // Fetch expression as a string - std::string expr; - options->get(name, expr, "0"); - - // Parse, and evaluate with x,y,z,t = 0 - std::shared_ptr gen = FieldFactory::get()->parse(expr, options); + auto expr = (*options)[name].withDefault(std::string{"0"}); + auto gen = FieldFactory::get()->parse(expr, options); var.resize(len); From dea66da140826fa9af28fca5587f539ace31bb21 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 15:43:12 +0000 Subject: [PATCH 0895/1783] Clang-format GridFromOptions --- src/mesh/data/gridfromoptions.cxx | 58 ++++++++++++++----------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index 54dd4ddba5..8b9e2f902c 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -11,11 +11,9 @@ #include -bool GridFromOptions::hasVar(const std::string &name) { - return options->isSet(name); -} +bool GridFromOptions::hasVar(const std::string& name) { return options->isSet(name); } -bool GridFromOptions::get(Mesh *UNUSED(m), std::string &sval, const std::string &name) { +bool GridFromOptions::get(Mesh* UNUSED(m), std::string& sval, const std::string& name) { if (!hasVar(name)) { const std::string def{}; output_warn.write("Variable '%s' not in mesh options. Setting to \"%s\"\n", @@ -23,12 +21,12 @@ bool GridFromOptions::get(Mesh *UNUSED(m), std::string &sval, const std::string sval = def; return false; } - + options->get(name, sval, ""); return true; } -bool GridFromOptions::get(Mesh *UNUSED(m), int &ival, const std::string &name) { +bool GridFromOptions::get(Mesh* UNUSED(m), int& ival, const std::string& name) { if (!hasVar(name)) { constexpr int def{0}; output_warn.write("Variable '%s' not in mesh options. Setting to %d\n", name.c_str(), @@ -36,12 +34,12 @@ bool GridFromOptions::get(Mesh *UNUSED(m), int &ival, const std::string &name) { ival = def; return false; } - + options->get(name, ival, 0); return true; } -bool GridFromOptions::get(Mesh *UNUSED(m), BoutReal &rval, const std::string &name) { +bool GridFromOptions::get(Mesh* UNUSED(m), BoutReal& rval, const std::string& name) { if (!hasVar(name)) { constexpr BoutReal def{0.0}; output_warn.write("Variable '%s' not in mesh options. Setting to %e\n", name.c_str(), @@ -57,9 +55,10 @@ bool GridFromOptions::get(Mesh *UNUSED(m), BoutReal &rval, const std::string &na return true; } -bool GridFromOptions::get(Mesh *m, Field2D &var, const std::string &name, BoutReal def) { +bool GridFromOptions::get(Mesh* m, Field2D& var, const std::string& name, BoutReal def) { if (!hasVar(name)) { - output_warn.write("Variable '%s' not in mesh options. Setting to %e\n", name.c_str(), def); + output_warn.write("Variable '%s' not in mesh options. Setting to %e\n", name.c_str(), + def); var = def; return false; } @@ -68,7 +67,7 @@ bool GridFromOptions::get(Mesh *m, Field2D &var, const std::string &name, BoutRe return true; } -bool GridFromOptions::get(Mesh *m, Field3D &var, const std::string &name, BoutReal def) { +bool GridFromOptions::get(Mesh* m, Field3D& var, const std::string& name, BoutReal def) { if (!hasVar(name)) { output_warn.write("Variable '%s' not in mesh options. Setting to %e\n", name.c_str(), def); @@ -80,10 +79,9 @@ bool GridFromOptions::get(Mesh *m, Field3D &var, const std::string &name, BoutRe return true; } -bool GridFromOptions::get(Mesh *m, std::vector &var, const std::string &name, int len, - int UNUSED(offset), GridDataSource::Direction UNUSED(dir)) { - // Integers not expressions yet - +bool GridFromOptions::get(Mesh* m, std::vector& var, const std::string& name, + int len, int UNUSED(offset), + GridDataSource::Direction UNUSED(dir)) { if (!hasVar(name)) { std::vector def{}; output_warn.write("Variable '%s' not in mesh options. Setting to empty vector\n", @@ -92,6 +90,7 @@ bool GridFromOptions::get(Mesh *m, std::vector &var, const std::string &nam return false; } + // FIXME: actually implement this! int ival; get(m, ival, name); var.resize(len, ival); @@ -99,10 +98,9 @@ bool GridFromOptions::get(Mesh *m, std::vector &var, const std::string &nam return true; } -bool GridFromOptions::get(Mesh *m, std::vector &var, const std::string &name, int len, - int offset, GridDataSource::Direction dir) { - - if(!hasVar(name)) { +bool GridFromOptions::get(Mesh* m, std::vector& var, const std::string& name, + int len, int offset, GridDataSource::Direction dir) { + if (!hasVar(name)) { std::vector def{}; output_warn.write("Variable '%s' not in mesh options. Setting to empty vector\n", name.c_str()); @@ -115,29 +113,27 @@ bool GridFromOptions::get(Mesh *m, std::vector &var, const std::string var.resize(len); - switch(dir) { + switch (dir) { case GridDataSource::X: { - for(int x=0;xgenerate(m->GlobalX(x - m->OffsetX + offset), 0.0, 0.0, 0.0); } break; } - case GridDataSource::Y : { - for(int y=0;ygenerate(0.0, TWOPI*m->GlobalY(y - m->OffsetY + offset), 0.0, 0.0); + case GridDataSource::Y: { + for (int y = 0; y < len; y++) { + var[y] = gen->generate(0.0, TWOPI * m->GlobalY(y - m->OffsetY + offset), 0.0, 0.0); } break; } - case GridDataSource::Z : { - for(int z=0;zgenerate(0.0, 0.0, TWOPI*(static_cast(z) + offset) / static_cast(m->LocalNz), 0.0); + case GridDataSource::Z: { + for (int z = 0; z < len; z++) { + var[z] = gen->generate( + 0.0, 0.0, (TWOPI * (z + offset)) / static_cast(m->LocalNz), 0.0); } break; } - default: { - throw BoutException("Invalid direction argument"); - } + default: { throw BoutException("Invalid direction argument"); } } return true; } - From c3c08964528b2e6bda375d0d76398816ac73a334 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 15:47:34 +0000 Subject: [PATCH 0896/1783] Rename test file according to actual type name --- .../{test_griddatafromoptions.cxx => test_gridfromoptions.cxx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/unit/mesh/data/{test_griddatafromoptions.cxx => test_gridfromoptions.cxx} (100%) diff --git a/tests/unit/mesh/data/test_griddatafromoptions.cxx b/tests/unit/mesh/data/test_gridfromoptions.cxx similarity index 100% rename from tests/unit/mesh/data/test_griddatafromoptions.cxx rename to tests/unit/mesh/data/test_gridfromoptions.cxx From fbf2bc5c9ea98b43de81eb73761996e788c00157 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 15:53:26 +0000 Subject: [PATCH 0897/1783] Include header for std::unique_ptr in generic factory tests --- tests/unit/include/bout/test_generic_factory.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/include/bout/test_generic_factory.cxx b/tests/unit/include/bout/test_generic_factory.cxx index 50d1065f18..6cd83d9da3 100644 --- a/tests/unit/include/bout/test_generic_factory.cxx +++ b/tests/unit/include/bout/test_generic_factory.cxx @@ -4,6 +4,7 @@ #include "bout/generic_factory.hxx" #include +#include #include #include From da14fc79377860ae68291beb5a9d1572c186fa6e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 15:53:53 +0000 Subject: [PATCH 0898/1783] Don't mix auto and braces in initialisation --- tests/unit/include/bout/test_generic_factory.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/include/bout/test_generic_factory.cxx b/tests/unit/include/bout/test_generic_factory.cxx index 6cd83d9da3..eede1b0e91 100644 --- a/tests/unit/include/bout/test_generic_factory.cxx +++ b/tests/unit/include/bout/test_generic_factory.cxx @@ -85,14 +85,14 @@ TEST(GenericFactory, RegisterAndCreate) { } TEST(GenericFactory, ListAvailable) { - auto available{Factory::getInstance().listAvailable()}; + auto available = Factory::getInstance().listAvailable(); std::vector expected{"base", "derived1", "derived2"}; EXPECT_EQ(available, expected); } TEST(GenericFactory, Remove) { - auto available{Factory::getInstance().listAvailable()}; + auto available = Factory::getInstance().listAvailable(); std::vector expected{"base", "derived1", "derived2"}; EXPECT_EQ(available, expected); From 9c5e96b74afd8fb5a907c4d39ddf6752633789bc Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 17:31:22 +0000 Subject: [PATCH 0899/1783] Set local offsets for FakeMesh --- tests/unit/test_extras.hxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index f950761941..ccebee0ebd 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -133,6 +133,10 @@ public: LocalNx = nx; LocalNy = ny; LocalNz = nz; + OffsetX = 0; + OffsetY = 0; + OffsetZ = 0; + // Small "inner" region xstart = 1; xend = nx - 2; From a81eee6852bd4ba4b65d346711d08fe0ea05b506 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 17:31:57 +0000 Subject: [PATCH 0900/1783] Explicitly test offsets for GridFromOptions::get(vector) --- tests/unit/mesh/data/test_gridfromoptions.cxx | 76 ++++++++++++++++++- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/tests/unit/mesh/data/test_gridfromoptions.cxx b/tests/unit/mesh/data/test_gridfromoptions.cxx index 39eb43b59e..ed3fe5ca32 100644 --- a/tests/unit/mesh/data/test_gridfromoptions.cxx +++ b/tests/unit/mesh/data/test_gridfromoptions.cxx @@ -183,6 +183,26 @@ TEST_F(GridFromOptionsTest, GetVectorBoutRealX) { EXPECT_EQ(result, expected); } +TEST_F(GridFromOptionsTest, GetVectorBoutRealXOffset) { + std::vector result{}; + std::vector expected{4., 5., 6.}; + + EXPECT_TRUE(griddata.get(mesh, result, "f", nx, 1, GridDataSource::Direction::X)); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetVectorBoutRealXMeshOffset) { + std::vector result{}; + std::vector expected{2., 3., 4.}; + + mesh->OffsetX = 1; + mesh->OffsetY = 100; + mesh->OffsetZ = 100; + + EXPECT_TRUE(griddata.get(mesh, result, "f", nx, 0, GridDataSource::Direction::X)); + EXPECT_EQ(result, expected); +} + TEST_F(GridFromOptionsTest, GetVectorBoutRealXNone) { std::vector result{}; std::vector default_expected{}; @@ -192,10 +212,32 @@ TEST_F(GridFromOptionsTest, GetVectorBoutRealXNone) { TEST_F(GridFromOptionsTest, GetVectorBoutRealY) { std::vector result{}; - std::vector expected{3., 3. + TWOPI, 3. + 2. * TWOPI, 3. + 3. * TWOPI, - 3. + 4. * TWOPI}; + std::vector expected{3., 3. + TWOPI, 3. + (2. * TWOPI), 3. + (3. * TWOPI), + 3. + (4. * TWOPI)}; + + EXPECT_TRUE(griddata.get(mesh, result, "f", ny, 0, GridDataSource::Direction::Y)); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetVectorBoutRealYOffset) { + std::vector result{}; + std::vector expected{3. + TWOPI, 3. + (2. * TWOPI), 3. + (3. * TWOPI), + 3. + (4. * TWOPI), 3. + (5. * TWOPI)}; - EXPECT_TRUE(griddata.get(mesh, result, "f", ny, 0., GridDataSource::Direction::Y)); + EXPECT_TRUE(griddata.get(mesh, result, "f", ny, 1, GridDataSource::Direction::Y)); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetVectorBoutRealYMeshOffset) { + std::vector result{}; + std::vector expected{3. - TWOPI, 3., 3. + TWOPI, 3. + (2. * TWOPI), + 3. + (3. * TWOPI)}; + + mesh->OffsetX = 100; + mesh->OffsetY = 1; + mesh->OffsetZ = 100; + + EXPECT_TRUE(griddata.get(mesh, result, "f", ny, 0, GridDataSource::Direction::Y)); EXPECT_EQ(result, expected); } @@ -216,7 +258,33 @@ TEST_F(GridFromOptionsTest, GetVectorBoutRealZ) { 3. + (5. * TWOPI / nz), 3. + (6. * TWOPI / nz)}; - EXPECT_TRUE(griddata.get(mesh, result, "f", nz, 0., GridDataSource::Direction::Z)); + EXPECT_TRUE(griddata.get(mesh, result, "f", nz, 0, GridDataSource::Direction::Z)); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetVectorBoutRealZOffset) { + std::vector result{}; + std::vector expected{3. + (1. * TWOPI / nz), 3. + (2. * TWOPI / nz), + 3. + (3. * TWOPI / nz), 3. + (4. * TWOPI / nz), + 3. + (5. * TWOPI / nz), 3. + (6. * TWOPI / nz), + 3. + (7. * TWOPI / nz)}; + + EXPECT_TRUE(griddata.get(mesh, result, "f", nz, 1, GridDataSource::Direction::Z)); + EXPECT_EQ(result, expected); +} + +TEST_F(GridFromOptionsTest, GetVectorBoutRealZMeshOffset) { + std::vector result{}; + std::vector expected{3. + (-1. * TWOPI / nz), 3., + 3. + (1. * TWOPI / nz), 3. + (2. * TWOPI / nz), + 3. + (3. * TWOPI / nz), 3. + (4. * TWOPI / nz), + 3. + (5. * TWOPI / nz)}; + + mesh->OffsetX = 100; + mesh->OffsetY = 100; + mesh->OffsetZ = 1; + + EXPECT_TRUE(griddata.get(mesh, result, "f", nz, 0, GridDataSource::Direction::Z)); EXPECT_EQ(result, expected); } From 395d92255aba2fcee2b8fffc92f56f3ee732c24f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Feb 2019 17:32:39 +0000 Subject: [PATCH 0901/1783] Use Mesh::OffsetZ in GridFromOptions::get(vector) Currently nothing actually sets OffsetZ, but this will somewhat future-proof this function --- src/mesh/data/gridfromoptions.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index 8b9e2f902c..51f4f7762c 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -129,7 +129,8 @@ bool GridFromOptions::get(Mesh* m, std::vector& var, const std::string case GridDataSource::Z: { for (int z = 0; z < len; z++) { var[z] = gen->generate( - 0.0, 0.0, (TWOPI * (z + offset)) / static_cast(m->LocalNz), 0.0); + 0.0, 0.0, + (TWOPI * (z - m->OffsetZ + offset)) / static_cast(m->LocalNz), 0.0); } break; } From 017533812be567c55d17f9ca19d986645af29377 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 1 Mar 2019 10:25:19 +0000 Subject: [PATCH 0902/1783] Simplify BoutReal generation in GridFromOptions::get --- src/mesh/data/gridfromoptions.cxx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index 51f4f7762c..b2ad75ec4f 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -48,9 +48,7 @@ bool GridFromOptions::get(Mesh* UNUSED(m), BoutReal& rval, const std::string& na return false; } - auto expr = (*options)[name].withDefault(std::string{"0"}); - auto gen = FieldFactory::get()->parse(expr, options); - rval = gen->generate(0.0, 0.0, 0.0, 0.0); + rval = (*options)[name].withDefault(0.0); return true; } From edc9dc306e993a2b07a1d0e9029e9fd65a34e4f9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 1 Mar 2019 10:26:02 +0000 Subject: [PATCH 0903/1783] Clang-tidy gridfromoptions headers --- src/mesh/data/gridfromoptions.cxx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index b2ad75ec4f..3cd8f88fc3 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -1,14 +1,8 @@ - -#include - -#include - #include - +#include #include - +#include #include - #include bool GridFromOptions::hasVar(const std::string& name) { return options->isSet(name); } From e4e3254cdb24f0b11584f0a5c391ae97285c8c71 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 28 Feb 2019 12:43:19 +0000 Subject: [PATCH 0904/1783] Add U2 option for Flux derivatives --- src/mesh/index_derivs.cxx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 2d0f637152..c5563ed501 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -274,6 +274,18 @@ REGISTER_FLUX_DERIVATIVE(FDDX_U1, "U1", 1, DERIV::Flux) { // No vec return result - std::get<0>(vSplit) * f.c + std::get<1>(vSplit) * f.p; } +REGISTER_FLUX_DERIVATIVE(FDDX_U2, "U2", 2, DERIV::Flux) { // No vec + + // Velocity at lower end + BoutReal vs = 0.5 * (v.m + v.c); + BoutReal result = (vs >= 0.0) ? vs * (1.5*f.m - 0.5*f.mm) : vs * (1.5*f.c - 0.5*f.p); + // and at upper + vs = 0.5 * (v.c + v.p); + // Existing form doesn't vectorise due to branching + result -= (vs >= 0.0) ? vs * (1.5*f.c - 0.5*f.m) : vs * (1.5*f.p - 0.5*f.pp); + return -result; +} + REGISTER_FLUX_DERIVATIVE(FDDX_C2, "C2", 2, DERIV::Flux) { return 0.5 * (v.p * f.p - v.m * f.m); } @@ -378,6 +390,19 @@ REGISTER_FLUX_DERIVATIVE_STAGGERED(FDDX_U1_stag, "U1", 1, DERIV::Flux) { return -result; } +REGISTER_FLUX_DERIVATIVE_STAGGERED(FDDX_U2_stag, "U2", 2, DERIV::Flux) { + // Calculate d(v*f)/dx = (v*f)[i+1/2] - (v*f)[i-1/2] + + // Upper cell boundary + BoutReal result = + (v.p >= 0.) ? v.p * (1.5 * f.c - 0.5 * f.m) : v.p * (1.5 * f.p - 0.5 * f.pp); + + // Lower cell boundary + result -= (v.m >= 0.) ? v.m * (1.5 * f.m - 0.5 * f.mm) : v.m * (1.5 * f.c - 0.5 * f.p); + + return result; +} + ///////////////////////////////////////////////////////////////////////////////////// /// Here's an example of defining and registering a custom method that doesn't fit /// into the standard stencil based approach. From 9bba707f1a9b1356474a59012d47f7e233457d44 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 28 Feb 2019 16:23:49 +0000 Subject: [PATCH 0905/1783] Fetch input derivType in getFlowDerivative Previously DERIV::Upwind was hard-coded. --- include/bout/deriv_store.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 6c4c38e27d..03a2408f77 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -284,7 +284,7 @@ struct DerivativeStore { DERIV derivType = DERIV::Upwind) const { AUTO_TRACE(); const auto realName = nameLookup( - name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(DERIV::Upwind)))); + name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(derivType)))); const auto key = getKey(direction, stagger, realName); const storageType* theMap = nullptr; From 15ad43abd1d3d4c8f9020fbec0ddcf3aaa25ada8 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 28 Feb 2019 17:13:52 +0000 Subject: [PATCH 0906/1783] Add missing location check for upwind/flux derivatives The Upwind and Flux derivatives require that the result is at the same location as the input field. Only the velocity field can be staggered relative to the other two. This requires an extra ASSERT1(inloc == outloc) in getStagger(vloc,inloc,outloc,allowedStaggerLoc). --- src/mesh/index_derivs.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index c5563ed501..8a3b31c871 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -58,6 +58,7 @@ STAGGER Mesh::getStagger(const CELL_LOC inloc, const CELL_LOC outloc, STAGGER Mesh::getStagger(const CELL_LOC vloc, MAYBE_UNUSED(const CELL_LOC inloc), const CELL_LOC outloc, const CELL_LOC allowedStaggerLoc) const { TRACE("Mesh::getStagger -- four arguments"); + ASSERT1(inloc == outloc); ASSERT1(vloc == inloc || (vloc == CELL_CENTRE && inloc == allowedStaggerLoc) || (vloc == allowedStaggerLoc && inloc == CELL_CENTRE)); return getStagger(vloc, outloc, allowedStaggerLoc); From ec4aeda34921af9d873c9232a2d8c3a0aad70854 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 1 Mar 2019 12:52:56 +0000 Subject: [PATCH 0907/1783] Set location for result of Field2D VDDZ, FDDZ to outloc Make the location of the result of these Field2D operators that return zero consistent with the rest of the operators: the result should be at outloc, and if outloc==CELL_DEFAULT then the location is the same as 'f' (which can't be staggered) rather than the velocity (which can be staggered). --- src/sys/derivs.cxx | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 33c60544c5..10b94f879d 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -401,20 +401,24 @@ const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const st ////////////// Z DERIVATIVE ///////////////// // special case where both are 2D -const Field2D VDDZ(const Field2D &v, const Field2D &UNUSED(f), CELL_LOC UNUSED(outloc), +const Field2D VDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), REGION UNUSED(region)) { - // Should we take location from v or f? - auto tmp = Field2D(0., v.getMesh()); - tmp.setLocation(v.getLocation()); + auto tmp = Field2D(0., f.getMesh()); + if (outloc == CELL_DEFAULT) { + outloc = f.getLocation(); + } + tmp.setLocation(outloc); return tmp; } // Note that this is zero because no compression is included -const Field2D VDDZ(const Field3D &v, const Field2D &UNUSED(f), CELL_LOC UNUSED(outloc), +const Field2D VDDZ(const Field3D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), REGION UNUSED(region)) { - // Should we take location from v or f? - auto tmp = Field2D(0., v.getMesh()); - tmp.setLocation(v.getLocation()); + auto tmp = Field2D(0., f.getMesh()); + if (outloc == CELL_DEFAULT) { + outloc = f.getLocation(); + } + tmp.setLocation(outloc); return tmp; } @@ -451,11 +455,13 @@ const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const st ///////////////////////////////////////////////////////////////////////// -const Field2D FDDZ(const Field2D &v, const Field2D &UNUSED(f), CELL_LOC UNUSED(outloc), +const Field2D FDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), REGION UNUSED(region)) { - // Should we take location from v or f? - auto tmp = Field2D(0., v.getMesh()); - tmp.setLocation(v.getLocation()); + auto tmp = Field2D(0., f.getMesh()); + if (outloc == CELL_DEFAULT) { + outloc = f.getLocation(); + } + tmp.setLocation(outloc); return tmp; } From e71cd7d01759505cf144290d360dc7070bdeae5f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Mar 2019 13:23:08 +0000 Subject: [PATCH 0908/1783] Fix missing default argument to Div(Vector2D, Field2D) from merge --- include/vecops.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/vecops.hxx b/include/vecops.hxx index 1072d8f9aa..4e52641b81 100644 --- a/include/vecops.hxx +++ b/include/vecops.hxx @@ -81,8 +81,8 @@ const Field2D Div(const Vector2D& v, CELL_LOC outloc = CELL_DEFAULT, const Field3D Div(const Vector3D& v, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); -const Field2D Div(const Vector2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT); - +const Field2D Div(const Vector2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); const Field3D Div(const Vector3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); DEPRECATED(inline const Field3D Div(const Vector3D& v, const Field3D& f, From 7d4468d374730bcd6c135f03d41540bc2c0bde11 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Mar 2019 15:39:21 +0000 Subject: [PATCH 0909/1783] Fix printf format specifier in printLocation clobbered by merge --- src/mesh/interpolation.cxx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/mesh/interpolation.cxx b/src/mesh/interpolation.cxx index 2cd432791c..e74630844a 100644 --- a/src/mesh/interpolation.cxx +++ b/src/mesh/interpolation.cxx @@ -29,10 +29,14 @@ #include #include -void printLocation(const Field3D &var) { output.write(strLocation(var.getLocation())); } -void printLocation(const Field2D &var) { output.write(strLocation(var.getLocation())); } +void printLocation(const Field3D& var) { + output.write("%s", strLocation(var.getLocation())); +} +void printLocation(const Field2D& var) { + output.write("%s", strLocation(var.getLocation())); +} -const char *strLocation(CELL_LOC loc) { return CELL_LOC_STRING(loc).c_str(); } +const char* strLocation(CELL_LOC loc) { return CELL_LOC_STRING(loc).c_str(); } const Field3D interpolate(const Field3D &f, const Field3D &delta_x, const Field3D &delta_z) { From 21056f7bf8a0c89b2dfbc872291baa2ea57dab9f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Mar 2019 15:41:54 +0000 Subject: [PATCH 0910/1783] Fix name shadowing in FCI constructor from merge --- src/mesh/parallel/fci.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index c27e1db73a..2686759503 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -157,7 +157,7 @@ FCIMap::FCIMap(Mesh& mesh, int offset_, BoundaryRegionPar* boundary, bool zperio interp->calcWeights(xt_prime, zt_prime); } - int ncz = mesh.LocalNz; + int ncz = map_mesh.LocalNz; BoutReal t_x, t_z; Coordinates &coord = *(map_mesh.getCoordinates()); From b3a4037818052d102d06f0693dad86b049335922 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 4 Mar 2019 17:03:25 +0000 Subject: [PATCH 0911/1783] Use std::map::find to avoid double lookup in getCoordinates Following pattern used elsewhere in BOUT++, in getCoordinates replace check of 'coords_map.count(location)' followed by 'return coords_map[location]' with 'auto found = coords_map.find(location)', followed by checking 'found != coords_map.end()' and 'return found->second'. This avoids searching coords_map twice. --- include/bout/mesh.hxx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index e782440f03..bf448825bc 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -456,15 +456,17 @@ class Mesh { ASSERT1(location != CELL_DEFAULT); ASSERT1(location != CELL_VSHIFT); - if (coords_map.count(location)) { // True branch most common, returns immediately - return coords_map[location]; - } else { - // No coordinate system set. Create default - // Note that this can't be allocated here due to incomplete type - // (circular dependency between Mesh and Coordinates) - coords_map.emplace(location, createDefaultCoordinates(location)); - return coords_map[location]; + auto found = coords_map.find(location); + if (found != coords_map.end()) { + // True branch most common, returns immediately + return found->second; } + + // No coordinate system set. Create default + // Note that this can't be allocated here due to incomplete type + // (circular dependency between Mesh and Coordinates) + auto inserted = coords_map.emplace(location, createDefaultCoordinates(location)); + return inserted.first->second; } /// Returns the non-CELL_CENTRE location From 5446526b8195fc0536d7faece25fe4426c21a247 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 5 Mar 2019 10:04:24 +0000 Subject: [PATCH 0912/1783] Fix printf formats in Ncxx4/H5Format::setAttribute(..., BoutReal) --- src/fileio/impls/hdf5/h5_format.cxx | 2 +- src/fileio/impls/netcdf4/ncxx4.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fileio/impls/hdf5/h5_format.cxx b/src/fileio/impls/hdf5/h5_format.cxx index a52f118b1e..c9ac9a155a 100644 --- a/src/fileio/impls/hdf5/h5_format.cxx +++ b/src/fileio/impls/hdf5/h5_format.cxx @@ -879,7 +879,7 @@ void H5Format::setAttribute(const std::string &varname, const std::string &attrn BoutReal existing_att; if (getAttribute(varname, attrname, existing_att)) { if (value != existing_att) { - output_warn.write("Overwriting attribute '%s' of variable '%s' with '%d', was previously '%d'", + output_warn.write("Overwriting attribute '%s' of variable '%s' with '%f', was previously '%f'", attrname.c_str(), varname.c_str(), value, existing_att); } } diff --git a/src/fileio/impls/netcdf4/ncxx4.cxx b/src/fileio/impls/netcdf4/ncxx4.cxx index a1c5c0e6e3..3078e3c6b6 100644 --- a/src/fileio/impls/netcdf4/ncxx4.cxx +++ b/src/fileio/impls/netcdf4/ncxx4.cxx @@ -817,7 +817,7 @@ void Ncxx4::setAttribute(const std::string &varname, const std::string &attrname BoutReal existing_att; if (getAttribute(varname, attrname, existing_att)) { if (value != existing_att) { - output_warn.write("Overwriting attribute '%s' of variable '%s' with '%d', was previously '%d'", + output_warn.write("Overwriting attribute '%s' of variable '%s' with '%f', was previously '%f'", attrname.c_str(), varname.c_str(), value, existing_att); } } From 96fd8eddb5c9fb652ca0ee3171b58d4b36dcfa6c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 5 Mar 2019 10:22:51 +0000 Subject: [PATCH 0913/1783] Pin pip packages on Travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 479c4a94c2..30014efba9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ matrix: - env: &default_env - CONFIGURE_OPTIONS='--enable-checks=no --enable-optimize=3 --disable-signal --disable-track --disable-backtrace' - SCRIPT_FLAGS='-uim' - - PIP_PACKAGES='cython netcdf4 sympy' + - PIP_PACKAGES='cython==0.29.6 netcdf4==1.4.2 sympy==1.3' - addons: apt: sources: From 45accfc1834dd120a7f8432858ff0cf70de4466d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Tue, 5 Mar 2019 10:20:01 +0000 Subject: [PATCH 0914/1783] Make all errors in travis_script.sh fatal --- .pip_install_for_travis.sh | 3 +++ .travis_script.sh | 21 +++++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.pip_install_for_travis.sh b/.pip_install_for_travis.sh index 59b0392757..a3f3f9e7c5 100755 --- a/.pip_install_for_travis.sh +++ b/.pip_install_for_travis.sh @@ -1,4 +1,7 @@ #!/bin/bash + +set -e + export PATH=${HOME}/.local/bin:${PATH} pip3 install --user --upgrade pip==18.1 setuptools==40.6.3 pip3 install --user --upgrade scipy==1.2.0 numpy==1.15 diff --git a/.travis_script.sh b/.travis_script.sh index 74d75e1ef7..55b51a70f9 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -1,5 +1,7 @@ #!/bin/bash +set -e + #Default flags COVERAGE=0 UNIT=0 @@ -45,8 +47,8 @@ done export MAKEFLAGS="-j 2 -k" echo "Configuring with $CONFIGURE_OPTIONS" -time ./configure $CONFIGURE_OPTIONS MAKEFLAGS="$MAKEFLAGS" -conf=$? +conf=0 +time ./configure $CONFIGURE_OPTIONS MAKEFLAGS="$MAKEFLAGS" || conf=$? if test $conf -gt 0 then RED_FG="\033[031m" @@ -72,8 +74,8 @@ export PYTHONPATH=$(pwd)/tools/pylib/:$PYTHONPATH for target in ${MAIN_TARGET[@]} do - time make $target - make_exit=$? + make_exit=0 + time make $target || make_exit=$? if [[ $make_exit -gt 0 ]]; then make clean > /dev/null echo -e $RED_FG @@ -89,23 +91,23 @@ done if [[ ${TESTS} == 1 ]] then - time make build-check || exit + time make build-check fi if [[ ${UNIT} == 1 ]] then - time make check-unit-tests || exit + time make check-unit-tests fi if [[ ${INTEGRATED} == 1 ]] then - time make check-integrated-tests || exit - time py.test-3 tools/pylib/ || exit + time make check-integrated-tests + time py.test-3 tools/pylib/ fi if [[ ${MMS} == 1 ]] then - time make check-mms-tests || exit + time make check-mms-tests fi if [[ ${COVERAGE} == 1 ]] @@ -121,5 +123,4 @@ then #For codacy bash ./.codacy_coverage.sh - fi From 8bb3848693b978366f1c59847a62d03ddf0b5682 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 5 Mar 2019 10:33:54 +0000 Subject: [PATCH 0915/1783] Add gitignore for MMS advection --- tests/MMS/spatial/advection/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/MMS/spatial/advection/.gitignore diff --git a/tests/MMS/spatial/advection/.gitignore b/tests/MMS/spatial/advection/.gitignore new file mode 100644 index 0000000000..4773540382 --- /dev/null +++ b/tests/MMS/spatial/advection/.gitignore @@ -0,0 +1,2 @@ +*.png +*.pkl From 17be2f94600198bbdeff29b4ceda119706afc71f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 5 Mar 2019 10:44:55 +0000 Subject: [PATCH 0916/1783] Add item to check pinned pip packages in release checklist --- manual/RELEASE_HOWTO.md | 1 + 1 file changed, 1 insertion(+) diff --git a/manual/RELEASE_HOWTO.md b/manual/RELEASE_HOWTO.md index 4508faafe4..01a72c9ba4 100644 --- a/manual/RELEASE_HOWTO.md +++ b/manual/RELEASE_HOWTO.md @@ -19,6 +19,7 @@ releases - [ ] Run `make check-all` - Raise issues for any tests that fail - Possibly run `clang-tidy`, `clang-check`, `coverity`, etc. +- [ ] Review pinned pip package versions for Travis Before merging PR: From 983c32eb9ae20dfdb30b6720657f64404ed2a12f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 5 Mar 2019 11:34:51 +0000 Subject: [PATCH 0917/1783] Add boututils module for checking error scaling Provides consistent way of checking error scaling in MMS/MES tests --- tools/pylib/boututils/check_scaling.py | 70 ++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 tools/pylib/boututils/check_scaling.py diff --git a/tools/pylib/boututils/check_scaling.py b/tools/pylib/boututils/check_scaling.py new file mode 100644 index 0000000000..f1375ba32c --- /dev/null +++ b/tools/pylib/boututils/check_scaling.py @@ -0,0 +1,70 @@ +"""Functions for checking the error scaling of MMS or MES results + +""" + +from numpy import array, isclose, log, polyfit + + +def get_order(grid_spacing, errors): + """Get the convergence order of errors over the full range of + grid_spacing, and at small spacings + + Parameters + ---------- + grid_spacing : list of float + The grid spacing or inverse of number of grid points + errors : list of float + The error at each grid spacing + + Returns + ------- + tuple of float + The first value is the error scaling over the full range of + grid spacings; the second value is the scaling over the last + two points + + """ + full_range = polyfit(log(grid_spacing), log(errors), 1) + + small_spacing = log(errors[-2] / errors[-1]) / log(grid_spacing[-2] / grid_spacing[-1]) + + return (full_range[0], small_spacing) + + +def check_order(actual_order, expected_order, tolerance=2.e-1): + """Check if the actual_order is sufficiently close to the + expected_order within a given tolerance + + """ + return isclose(actual_order, expected_order, rtol=tolerance) + + +def error_rate_table(errors, grid_sizes, label): + """Create a nicely formatted table of the error convergence rate over + the grid_sizes + + The error rate is calculated between adjacent points + + Parameters + ---------- + errors : list of float + The errors at each grid size + grid_sizes : list of int + The number of grid points + label : string + What the error is measuring + + Returns + ------- + string + + """ + dx = 1. / array(grid_sizes) + message = "{}:\nGrid points | Error | Rate\n".format(label) + for i in range(len(grid_sizes)): + message += "{:<11} | {:f} | ".format(grid_sizes[i], errors[i]) + if i > 0: + message += "{:f} \n".format(log(errors[i] / errors[i-1]) / log(dx[i] / dx[i-1])) + else: + message += "--\n" + return message From 49d4222e2732fb0925cf50633c9b8722fdb26430 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 5 Mar 2019 11:35:49 +0000 Subject: [PATCH 0918/1783] Use new check_scaling module in spatial/advection scaling test --- tests/MMS/spatial/advection/runtest | 50 +++++++++-------------------- 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/tests/MMS/spatial/advection/runtest b/tests/MMS/spatial/advection/runtest index 2e31b76c55..566180fe94 100755 --- a/tests/MMS/spatial/advection/runtest +++ b/tests/MMS/spatial/advection/runtest @@ -13,6 +13,7 @@ from builtins import str from builtins import range from boututils.run_wrapper import shell, shell_safe, launch_safe, getmpirun +from boututils import check_scaling from boutdata.collect import collect from numpy import array, log, pi @@ -64,23 +65,16 @@ for opts, label, sym, exp_ord in options: error_inf = [] # The maximum error for nx in nxlist: + shell("rm data/BOUT.dmp.*.nc") + # Set the X and Z mesh size dx = 2.*pi / (nx) - args = opts + " mesh:nx="+str(nx+4)+" mesh:dx="+str(dx)+" MZ="+str(nx) - print(" Running with " + args) - - # Delete old data - shell("rm data/BOUT.dmp.*.nc") - - # Command to run cmd = "./advection "+args - # Launch using MPI s, out = launch_safe(cmd, runcmd=MPIRUN, nproc=nproc, mthread=mthread, pipe=True) - # Save output to log file with open("run.log."+str(nx), "w") as f: f.write(out) @@ -94,23 +88,19 @@ for opts, label, sym, exp_ord in options: print(" -> Error norm: l-2 %f l-inf %f" % (l2, linf)) - # Append to list of all results err_2_all.append((error_2, label, sym)) err_inf_all.append((error_inf, label, sym)) - # Calculate grid spacing dx = 1. / array(nxlist) - # Calculate convergence order - - order = log(error_2[-1] / error_2[-2]) / log(dx[-1] / dx[-2]) - print("Convergence order = %f" % (order)) + order = check_scaling.get_order(dx, error_2) + print("Convergence order = {:f} ({:f} at small spacing)".format(*order)) - if not (exp_ord + .2 > order > exp_ord - .2): - success = False - print("... Failure") - else: + success = check_scaling.check_order(order[0], exp_ord) + if success: print("... Success") + else: + print("... Failure") # plot errors if cli_args.plot: @@ -181,23 +171,13 @@ if cli_args.plot: plt.close() -def print_error_rate(e, nxlist, dx): - print("{}: {:>4} points | Error: {:f}".format(label, nxlist[i], e[i]), end="") - if i > 0: - print(" -> Rate {:f} ".format(log(e[i] / e[i-1]) / log(dx[i] / dx[i-1]))) - else: - print() - - -print("\n\n==== l-infinity norm ====") -for e, label, sym in err_inf_all: - for i in range(len(dx)): - print_error_rate(e, nxlist, dx) +print("\n==== l-infinity norm ====") +for e, label, _ in err_inf_all: + print(check_scaling.error_rate_table(e, nxlist, label)) -print("\n\n==== l-2 norm ====") -for e, label, sym in err_2_all: - for i in range(len(dx)): - print_error_rate(e, nxlist, dx) +print("==== l-2 norm ====") +for e, label, _ in err_2_all: + print(check_scaling.error_rate_table(e, nxlist, label)) if success: print(" => All tests passed") From 574b89e52f98db7bdb12e6dd24ca38c2843de3ef Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 5 Mar 2019 13:01:34 +0000 Subject: [PATCH 0919/1783] Use mesh_staggered in Field2DTest.SetGetLocation Otherwise get segfault due to trying to initialize CELL_XLOW Coordinates object when CELL_CENTRE is nullptr. --- tests/unit/field/test_field2d.cxx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index 811be2e426..dbf95ce69a 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -187,9 +187,7 @@ TEST_F(Field2DTest, TimeDeriv) { } TEST_F(Field2DTest, SetGetLocation) { - Field2D field; - - field.getMesh()->StaggerGrids = true; + Field2D field(mesh_staggered); field.setLocation(CELL_XLOW); EXPECT_EQ(field.getLocation(), CELL_XLOW); From c2f9e41e195ddbbe435d2da44144a3c43e6dbbae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Tue, 5 Mar 2019 14:38:14 +0000 Subject: [PATCH 0920/1783] Check absolute tolerance, rather then relative one --- tools/pylib/boututils/check_scaling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pylib/boututils/check_scaling.py b/tools/pylib/boututils/check_scaling.py index f1375ba32c..1291293156 100644 --- a/tools/pylib/boututils/check_scaling.py +++ b/tools/pylib/boututils/check_scaling.py @@ -36,7 +36,7 @@ def check_order(actual_order, expected_order, tolerance=2.e-1): expected_order within a given tolerance """ - return isclose(actual_order, expected_order, rtol=tolerance) + return isclose(actual_order, expected_order, atol=tolerance, rtol=0) def error_rate_table(errors, grid_sizes, label): From c486aeddecb078b27727d68ca97879423ee0b5d5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 5 Mar 2019 14:56:11 +0000 Subject: [PATCH 0921/1783] Fix bug in tracking failures; print all failures --- tests/MMS/spatial/advection/runtest | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/MMS/spatial/advection/runtest b/tests/MMS/spatial/advection/runtest index b91e61ec43..966457a618 100755 --- a/tests/MMS/spatial/advection/runtest +++ b/tests/MMS/spatial/advection/runtest @@ -54,7 +54,7 @@ nxlist = [16, 32, 64, 128, 256] nproc = 2 mthread = 2 -success = True +failures = [] err_2_all = [] err_inf_all = [] @@ -93,10 +93,10 @@ for opts, label, sym, exp_ord in options: order = check_scaling.get_order(dx, error_2) print("Convergence order = {:f} ({:f} at small spacing)".format(*order)) - success = check_scaling.check_order(order[0], exp_ord) - if success: + if check_scaling.check_order(order[0], exp_ord): print("... Success") else: + failures.append(label) print("... Failure") # plot errors @@ -176,9 +176,11 @@ print("==== l-2 norm ====") for e, label, _ in err_2_all: print(check_scaling.error_rate_table(e, nxlist, label)) -if success: +if not failures: print(" => All tests passed") exit(0) else: print(" => Some failed tests") + for failure in failures: + print(" -", failure) exit(1) From 5be59a39fb54e7a4c8e806157b1a39f88ee03468 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 5 Mar 2019 14:56:42 +0000 Subject: [PATCH 0922/1783] Add error checking to check_scaling arguments --- tools/pylib/boututils/check_scaling.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/pylib/boututils/check_scaling.py b/tools/pylib/boututils/check_scaling.py index 1291293156..f0ee93ce37 100644 --- a/tools/pylib/boututils/check_scaling.py +++ b/tools/pylib/boututils/check_scaling.py @@ -24,6 +24,10 @@ def get_order(grid_spacing, errors): two points """ + if len(errors) != len(grid_spacing): + raise ValueError("errors (len: {}) and grid_spacing (len: {}) should be the same length" + .format(len(errors), len(grid_spacing))) + full_range = polyfit(log(grid_spacing), log(errors), 1) small_spacing = log(errors[-2] / errors[-1]) / log(grid_spacing[-2] / grid_spacing[-1]) @@ -59,10 +63,14 @@ def error_rate_table(errors, grid_sizes, label): string """ + if len(errors) != len(grid_sizes): + raise ValueError("errors (len: {}) and grid_sizes (len: {}) should be the same length" + .format(len(errors), len(grid_sizes))) + dx = 1. / array(grid_sizes) message = "{}:\nGrid points | Error | Rate\n".format(label) - for i in range(len(grid_sizes)): - message += "{:<11} | {:f} | ".format(grid_sizes[i], errors[i]) + for i, grid_size in enumerate(grid_sizes): + message += "{:<11} | {:f} | ".format(grid_size, errors[i]) if i > 0: message += "{:f} \n".format(log(errors[i] / errors[i-1]) / log(dx[i] / dx[i-1])) else: From 7be54648964709e53fb18f9411f4013a24235b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Tue, 5 Mar 2019 15:09:40 +0000 Subject: [PATCH 0923/1783] Check point-to-point error Doing the error calculation in the check allows to do the full point-to-point comparison, for maximising the strictness of the test. --- tests/MMS/spatial/advection/runtest | 2 +- tools/pylib/boututils/check_scaling.py | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/MMS/spatial/advection/runtest b/tests/MMS/spatial/advection/runtest index 966457a618..c71e67a008 100755 --- a/tests/MMS/spatial/advection/runtest +++ b/tests/MMS/spatial/advection/runtest @@ -93,7 +93,7 @@ for opts, label, sym, exp_ord in options: order = check_scaling.get_order(dx, error_2) print("Convergence order = {:f} ({:f} at small spacing)".format(*order)) - if check_scaling.check_order(order[0], exp_ord): + if check_scaling.check_order(error_2, exp_ord): print("... Success") else: failures.append(label) diff --git a/tools/pylib/boututils/check_scaling.py b/tools/pylib/boututils/check_scaling.py index f0ee93ce37..be22fc074a 100644 --- a/tools/pylib/boututils/check_scaling.py +++ b/tools/pylib/boututils/check_scaling.py @@ -35,12 +35,25 @@ def get_order(grid_spacing, errors): return (full_range[0], small_spacing) -def check_order(actual_order, expected_order, tolerance=2.e-1): +def check_order(error_list, expected_order, tolerance=2.e-1, spacing=None): """Check if the actual_order is sufficiently close to the expected_order within a given tolerance """ - return isclose(actual_order, expected_order, atol=tolerance, rtol=0) + + if len(error_list) < 2: + raise RuntimeError("Expected at least 2 data points to calculate error") + + success=True + for i in range(len(error_list)-1): + if spacing is None: + actual_order = log(errors[i] / errors[i+1]) / log(2) + else: + actual_order = log(errors[i] / errors[i+1]) / log(grid_spacing[i] / grid_spacing[i+1]) + + if not isclose(actual_order, expected_order, atol=tolerance, rtol=0): + success=False + return success def error_rate_table(errors, grid_sizes, label): From 0afc5da49cc1131214af956ab2ed5ff581ec89b7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 5 Mar 2019 15:10:42 +0000 Subject: [PATCH 0924/1783] Document that Matrix/Tensor are empty if any of their sizes are zero --- include/utils.hxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/utils.hxx b/include/utils.hxx index d3d1f7f12e..6825f51be3 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -88,6 +88,9 @@ using std::make_unique; /// Helper class for 2D arrays /// /// Allows bounds checking through `operator()` with CHECK > 1 +/// +/// If either \p n1 or \p n2 are 0, the Matrix is empty and should not +/// be indexed template class Matrix { public: @@ -173,6 +176,9 @@ private: /// Helper class for 3D arrays /// /// Allows bounds checking through `operator()` with CHECK > 1 +/// +/// If any of \p n1, \p n2 or \p n3 are 0, the Tensor is empty and +/// should not be indexed template class Tensor { public: From 9741b5a23022de6a7a1dfc0c6448754cbfdf26eb Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 24 Jan 2019 12:42:37 +0000 Subject: [PATCH 0925/1783] Add special direction ENUM --- include/bout_types.hxx | 2 +- src/sys/bout_types.cxx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 9859bbb14b..ae96ade76e 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -49,7 +49,7 @@ enum REGION {RGN_ALL, RGN_NOBNDRY, RGN_NOX, RGN_NOY, RGN_NOZ}; const std::string& REGION_STRING(REGION region); /// To identify particular directions (in index space) -enum class DIRECTION { X = 0, Y = 1, Z = 3, YAligned = 4, YOrthogonal = 5 }; +enum class DIRECTION { X = 0, Y = 1, Z = 3, YAligned = 4, YOrthogonal = 5, Special = 6 }; const std::string& DIRECTION_STRING(DIRECTION direction); diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index 280dfcb957..6b5463c366 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -47,7 +47,8 @@ const std::string& DIRECTION_STRING(DIRECTION direction) { {DIRECTION::Y, "Y"}, {DIRECTION::Z, "Z"}, {DIRECTION::YAligned, "Y - field aligned"}, - {DIRECTION::YOrthogonal, "Y - orthogonal"}}; + {DIRECTION::YOrthogonal, "Y - orthogonal"}, + {DIRECTION::Special, "Special"}}; return safeAt(DIRECTIONtoString, direction); } From 9758233df1593447edcc89f7d8c673a64bd87035 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Feb 2019 12:49:49 +0000 Subject: [PATCH 0926/1783] Add variables to be used for denoting what direction types a field has --- include/field.hxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/field.hxx b/include/field.hxx index da156d54f1..1e9ae3ceb3 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -124,6 +124,11 @@ class Field { protected: Mesh* fieldmesh{nullptr}; mutable std::shared_ptr fieldCoordinates{nullptr}; + +private: + DIRECTION xDirectionType{DIRECTION::X}; + DIRECTION yDirectionType{DIRECTION::Y}; + DIRECTION zDirectionType{DIRECTION::Z}; }; /// Unary + operator. This doesn't do anything From 8712e50f25ffcd47310fa7439398f4b07c78cdbf Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Fri, 25 Jan 2019 12:44:45 +0000 Subject: [PATCH 0927/1783] Provide routines for checking compatibility of Fields --- include/bout_types.hxx | 5 +++ include/field.hxx | 16 ++++++++ src/sys/bout_types.cxx | 86 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index ae96ade76e..8c5b12ddfe 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -77,4 +77,9 @@ struct enumWrapper { /// Boundary condition function using FuncPtr = BoutReal(*)(BoutReal t, BoutReal x, BoutReal y, BoutReal z); +bool compatibleDirections(DIRECTION d1, DIRECTION d2); +bool isXDirectionType(DIRECTION x); +bool isYDirectionType(DIRECTION y); +bool isZDirectionType(DIRECTION z); + #endif // __BOUT_TYPES_H__ diff --git a/include/field.hxx b/include/field.hxx index 1e9ae3ceb3..f5bd229481 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -121,6 +121,22 @@ class Field { */ virtual int getNz() const; + friend bool fieldsCompatible(const Field& field1, const Field& field2) { + return + // The following is a possible alternative to + // checking the two meshes and location are the same + // It is slightly stricter if we decide that coordinates + // could differ in more than just location. + field1.getCoordinates() == field2.getCoordinates() && + // In the unit tests fieldCoordinates get set to nullptr, so we still + // need to check fieldmesh and location, at least for now + field1.getMesh() == field2.getMesh() && + field1.getLocation() == field2.getLocation() && + // Compatible directions + compatibleDirections(field1.xDirectionType, field2.xDirectionType) + && compatibleDirections(field1.yDirectionType, field2.yDirectionType) + && compatibleDirections(field1.zDirectionType, field2.zDirectionType); + } protected: Mesh* fieldmesh{nullptr}; mutable std::shared_ptr fieldCoordinates{nullptr}; diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index 6b5463c366..d331276c1d 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -1,6 +1,7 @@ #include #include #include +#include #include template @@ -74,3 +75,88 @@ const std::string& DERIV_STRING(DERIV deriv) { return safeAt(DERIVtoString, deriv); } + +bool isXDirectionType(DIRECTION x) { + switch (x) { + case (DIRECTION::X): + return true; + default: + return false; + } +} + +bool isYDirectionType(DIRECTION y) { + switch (y) { + case (DIRECTION::Y): + case (DIRECTION::YAligned): + case (DIRECTION::YOrthogonal): + return true; + default: + return false; + } +} + +bool isZDirectionType(DIRECTION z) { + switch (z) { + case (DIRECTION::Z): + return true; + default: + return false; + } +} + +bool compatibleDirections(DIRECTION d1, DIRECTION d2) { + switch (d1) { + case (DIRECTION::X): { + switch (d2) { + case (DIRECTION::X): + case (DIRECTION::Special): + return true; + default: + return false; + } + } + case (DIRECTION::Y): + switch (d2) { + case (DIRECTION::Y): + case (DIRECTION::YAligned): + case (DIRECTION::YOrthogonal): + case (DIRECTION::Special): + return true; + default: + return false; + } + case (DIRECTION::YAligned): + switch (d2) { + case (DIRECTION::Y): + case (DIRECTION::YAligned): + case (DIRECTION::Special): + return true; + default: + return false; + } + case (DIRECTION::YOrthogonal): + switch (d2) { + case (DIRECTION::Y): + case (DIRECTION::YOrthogonal): + case (DIRECTION::Special): + return true; + default: + return false; + } + case (DIRECTION::Z): + switch (d2) { + case (DIRECTION::Z): + case (DIRECTION::Special): + return true; + default: + return false; + } + case (DIRECTION::Special): + return true; + default: + // Shouldn't reach this due to checks at start but in case + // of future changes good to handle here. + throw BoutException("Invalid y direction value"); + } +} From 5e4b7b24a3570eacf9f09a4fda4eddbaa19d53ac Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 21 Feb 2019 22:33:36 +0000 Subject: [PATCH 0928/1783] Add DIRECTION::Null to use as a default value --- include/bout_types.hxx | 2 +- include/field.hxx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 8c5b12ddfe..bb2d60b68c 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -49,7 +49,7 @@ enum REGION {RGN_ALL, RGN_NOBNDRY, RGN_NOX, RGN_NOY, RGN_NOZ}; const std::string& REGION_STRING(REGION region); /// To identify particular directions (in index space) -enum class DIRECTION { X = 0, Y = 1, Z = 3, YAligned = 4, YOrthogonal = 5, Special = 6 }; +enum class DIRECTION { X = 0, Y = 1, Z = 3, YAligned = 4, YOrthogonal = 5, Special = 6, Null = 7 }; const std::string& DIRECTION_STRING(DIRECTION direction); diff --git a/include/field.hxx b/include/field.hxx index f5bd229481..69f15a98d1 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -142,9 +142,9 @@ protected: mutable std::shared_ptr fieldCoordinates{nullptr}; private: - DIRECTION xDirectionType{DIRECTION::X}; - DIRECTION yDirectionType{DIRECTION::Y}; - DIRECTION zDirectionType{DIRECTION::Z}; + DIRECTION xDirectionType{DIRECTION::Null}; + DIRECTION yDirectionType{DIRECTION::Null}; + DIRECTION zDirectionType{DIRECTION::Null}; }; /// Unary + operator. This doesn't do anything From a677e33cb598b95e24563ee8a803e1f5cae06e4b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 21 Feb 2019 22:53:35 +0000 Subject: [PATCH 0929/1783] Extend Field constructors to set Direction types Move 'location' member variable to base Field class, and update getLocation/setLocation methods. Add methods to get and set xDirectionType/yDirectionType/zDirectionType. Update copy/swap methods/functions to handle members of Field more consistently. Add method to get the default yDirectionType from ParallelTransforms. --- include/bout/paralleltransform.hxx | 11 ++++ include/bout_types.hxx | 2 + include/field.hxx | 82 ++++++++++++++++++++++++++---- include/field2d.hxx | 24 +++------ include/field3d.hxx | 24 +++------ include/fieldperp.hxx | 22 +++----- src/field/field.cxx | 73 +++++++++++++++++++++++--- src/field/field2d.cxx | 48 +++++------------ src/field/field3d.cxx | 72 +++++++++----------------- src/field/fieldperp.cxx | 52 ++++++------------- src/mesh/parallel/fci.hxx | 4 ++ src/sys/bout_types.cxx | 6 +++ tests/unit/field/test_field.cxx | 2 +- 13 files changed, 237 insertions(+), 185 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index c533abc887..9bea6a2aa3 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -46,6 +46,8 @@ public: virtual bool canToFromFieldAligned() = 0; + virtual DIRECTION getDefaultYDirectionType() const = 0; + protected: /// This method should be called in the constructor to check that if the grid /// has a 'coordinates_type' variable, it has the correct value @@ -92,6 +94,11 @@ public: bool canToFromFieldAligned() override{ return true; } + + DIRECTION getDefaultYDirectionType() const override { + return DIRECTION::YAligned; + } + protected: void checkInputGrid() override; }; @@ -138,6 +145,10 @@ public: return true; } + DIRECTION getDefaultYDirectionType() const override { + return DIRECTION::YOrthogonal; + } + protected: void checkInputGrid() override; diff --git a/include/bout_types.hxx b/include/bout_types.hxx index bb2d60b68c..a770f87096 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -53,6 +53,8 @@ enum class DIRECTION { X = 0, Y = 1, Z = 3, YAligned = 4, YOrthogonal = 5, Speci const std::string& DIRECTION_STRING(DIRECTION direction); +void swap(DIRECTION& first, DIRECTION& second); + /// To identify valid staggering combinations enum class STAGGER { None = 0, C2L = 1, L2C = 2}; diff --git a/include/field.hxx b/include/field.hxx index 69f15a98d1..4c86378294 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -56,18 +56,37 @@ class Coordinates; class Field { public: Field() = default; - Field(Mesh * localmesh); + + Field(Mesh* localmesh, CELL_LOC location_in, DIRECTION xDirectionType_in, + DIRECTION yDirectionType_in, DIRECTION zDirectionType_in); + + // Copy constructor + Field(const Field& f) + : name(f.name), fieldmesh(f.fieldmesh), + fieldCoordinates(f.fieldCoordinates), location(f.location), + xDirectionType(f.xDirectionType), yDirectionType(f.yDirectionType), + zDirectionType(f.zDirectionType) {} + virtual ~Field() { } - virtual void setLocation(CELL_LOC UNUSED(loc)) { - AUTO_TRACE(); - throw BoutException( - "Calling Field::setLocation which is intentionally not fully implemented."); + /// Set variable location for staggered grids to @param new_location + /// + /// Throws BoutException if new_location is not `CELL_CENTRE` and + /// staggered grids are turned off and checks are on. If checks are + /// off, silently sets location to ``CELL_CENTRE`` instead. + void setLocation(CELL_LOC new_location); + /// Get variable location + CELL_LOC getLocation() const; + + /// Getters for DIRECTION types + DIRECTION getDirectionX() const { + return xDirectionType; } - virtual CELL_LOC getLocation() const { - AUTO_TRACE(); - throw BoutException( - "Calling Field::getLocation which is intentionally not fully implemented."); + DIRECTION getDirectionY() const { + return yDirectionType; + } + DIRECTION getDirectionZ() const { + return zDirectionType; } std::string name; @@ -95,6 +114,11 @@ class Field { if (fieldmesh){ return fieldmesh; } else { + // Don't set fieldmesh=mesh here, so that fieldmesh==nullptr until + // allocate() is called in one of the derived classes. fieldmesh==nullptr + // indicates that some initialization that would be done in the + // constructor if fieldmesh was a valid Mesh object still needs to be + // done. return bout::globals::mesh; } } @@ -121,6 +145,17 @@ class Field { */ virtual int getNz() const; + friend void swap(Field& first, Field& second) noexcept { + using std::swap; + swap(first.name, second.name); + swap(first.fieldmesh, second.fieldmesh); + swap(first.fieldCoordinates, second.fieldCoordinates); + swap(first.location, second.location); + swap(first.xDirectionType, second.xDirectionType); + swap(first.yDirectionType, second.yDirectionType); + swap(first.zDirectionType, second.zDirectionType); + } + friend bool fieldsCompatible(const Field& field1, const Field& field2) { return // The following is a possible alternative to @@ -141,6 +176,35 @@ protected: Mesh* fieldmesh{nullptr}; mutable std::shared_ptr fieldCoordinates{nullptr}; + /// Location of the variable in the cell + CELL_LOC location{CELL_CENTRE}; + + /// Set any direction types which are DIRECTION::Null to default values from + /// fieldmesh. + void setNullDirectionTypesToDefault(); + + /// Copy the members from another Field + void copyFieldMembers(const Field& f) { + name = f.name; + fieldmesh = f.fieldmesh; + fieldCoordinates = f.fieldCoordinates; + location = f.location; + xDirectionType = f.xDirectionType; + yDirectionType = f.yDirectionType; + zDirectionType = f.zDirectionType; + } + + /// Setters for *DirectionType + void setDirectionX(DIRECTION d) { + xDirectionType = d; + } + void setDirectionY(DIRECTION d) { + yDirectionType = d; + } + void setDirectionZ(DIRECTION d) { + zDirectionType = d; + } + private: DIRECTION xDirectionType{DIRECTION::Null}; DIRECTION yDirectionType{DIRECTION::Null}; diff --git a/include/field2d.hxx b/include/field2d.hxx index 486c111bca..f337fb9b47 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -63,7 +63,10 @@ class Field2D : public Field, public FieldData { * * By default the global Mesh pointer (mesh) is used. */ - Field2D(Mesh *localmesh = nullptr); + Field2D(Mesh *localmesh = nullptr, CELL_LOC location_in=CELL_CENTRE, + DIRECTION xDirectionType_in=DIRECTION::Null, + DIRECTION yDirectionType_in=DIRECTION::Y, + DIRECTION zDirectionType_in=DIRECTION::Special); /*! * Copy constructor. After this both fields @@ -149,15 +152,6 @@ class Field2D : public Field, public FieldData { */ Field2D & operator=(BoutReal rhs); - /// Set variable location for staggered grids to @param new_location - /// - /// Throws BoutException if new_location is not `CELL_CENTRE` and - /// staggered grids are turned off and checks are on. If checks are - /// off, silently sets location to ``CELL_CENTRE`` instead. - void setLocation(CELL_LOC new_location) override; - /// Get variable location - CELL_LOC getLocation() const override; - ///////////////////////////////////////////////////////// // Data access @@ -259,12 +253,13 @@ class Field2D : public Field, public FieldData { friend void swap(Field2D& first, Field2D& second) noexcept { using std::swap; + + // Swap base class members + swap(static_cast(first), static_cast(second)); + swap(first.data, second.data); - swap(first.fieldmesh, second.fieldmesh); - swap(first.fieldCoordinates, second.fieldCoordinates); swap(first.nx, second.nx); swap(first.ny, second.ny); - swap(first.location, second.location); swap(first.deriv, second.deriv); swap(first.bndry_op, second.bndry_op); swap(first.boundaryIsCopy, second.boundaryIsCopy); @@ -279,9 +274,6 @@ private: /// Internal data array. Handles allocation/freeing of memory Array data; - - /// Location of the variable in the cell - CELL_LOC location{CELL_CENTRE}; /// Time-derivative, can be nullptr Field2D *deriv{nullptr}; diff --git a/include/field3d.hxx b/include/field3d.hxx index 419a368c3c..5f81050e8a 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -167,7 +167,10 @@ class Field3D : public Field, public FieldData { * Note: the global "mesh" can't be passed here because * fields may be created before the mesh is. */ - Field3D(Mesh *localmesh = nullptr); + Field3D(Mesh *localmesh = nullptr, CELL_LOC location_in=CELL_CENTRE, + DIRECTION xDirectionType_in=DIRECTION::Null, + DIRECTION yDirectionType_in=DIRECTION::Null, + DIRECTION zDirectionType_in=DIRECTION::Null); /*! * Copy constructor @@ -262,15 +265,6 @@ class Field3D : public Field, public FieldData { Field3D& ynext(int offset); const Field3D& ynext(int offset) const; - /// Set variable location for staggered grids to @param new_location - /// - /// Throws BoutException if new_location is not `CELL_CENTRE` and - /// staggered grids are turned off and checks are on. If checks are - /// off, silently sets location to ``CELL_CENTRE`` instead. - void setLocation(CELL_LOC new_location) override; - /// Get variable location - CELL_LOC getLocation() const override; - ///////////////////////////////////////////////////////// // Data access @@ -457,14 +451,15 @@ class Field3D : public Field, public FieldData { friend void swap(Field3D& first, Field3D& second) noexcept { using std::swap; + + // Swap base class members + swap(static_cast(first), static_cast(second)); + swap(first.data, second.data); - swap(first.fieldmesh, second.fieldmesh); - swap(first.fieldCoordinates, second.fieldCoordinates); swap(first.background, second.background); swap(first.nx, second.nx); swap(first.ny, second.ny); swap(first.nz, second.nz); - swap(first.location, second.location); swap(first.deriv, second.deriv); swap(first.yup_fields, second.yup_fields); swap(first.ydown_fields, second.ydown_fields); @@ -484,9 +479,6 @@ private: /// Internal data array. Handles allocation/freeing of memory Array data; - - /// Location of the variable in the cell - CELL_LOC location{CELL_CENTRE}; /// Time derivative (may be nullptr) Field3D *deriv{nullptr}; diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 10763158cd..207e41b5dd 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -52,15 +52,17 @@ class FieldPerp : public Field { /*! * Constructor */ - FieldPerp(Mesh * fieldmesh = nullptr); + FieldPerp(Mesh * fieldmesh = nullptr, CELL_LOC location_in=CELL_CENTRE, + int yindex_in=-1, DIRECTION xDirectionType_in=DIRECTION::Null, + DIRECTION yDirectionType_in=DIRECTION::Null, + DIRECTION zDirectionType_in=DIRECTION::Null); /*! * Copy constructor. After this the data * will be shared (non unique) */ FieldPerp(const FieldPerp& f) - : Field(f.fieldmesh), yindex(f.yindex), nx(f.nx), nz(f.nz), data(f.data), - location(f.location) {} + : Field(f), yindex(f.yindex), nx(f.nx), nz(f.nz), data(f.data) {} /*! * Move constructor @@ -83,15 +85,6 @@ class FieldPerp : public Field { FieldPerp &operator=(FieldPerp &&rhs) = default; FieldPerp &operator=(BoutReal rhs); - /// Set variable location for staggered grids to @param new_location - /// - /// Throws BoutException if new_location is not `CELL_CENTRE` and - /// staggered grids are turned off and checks are on. If checks are - /// off, silently sets location to ``CELL_CENTRE`` instead. - void setLocation(CELL_LOC new_location) override; - /// Get variable location - CELL_LOC getLocation() const override; - /// Return a Region reference to use to iterate over this field const Region& getRegion(REGION region) const; const Region& getRegion(const std::string ®ion_name) const; @@ -254,16 +247,13 @@ class FieldPerp : public Field { private: /// The Y index at which this FieldPerp is defined - int yindex{-1}; + int yindex; /// The size of the data array int nx{-1}, nz{-1}; /// The underlying data array Array data; - - /// Location of the variable in the cell - CELL_LOC location{CELL_CENTRE}; }; // Non-member overloaded operators diff --git a/src/field/field.cxx b/src/field/field.cxx index e3d99dc444..da5e590a59 100644 --- a/src/field/field.cxx +++ b/src/field/field.cxx @@ -32,14 +32,58 @@ #include #include -Field::Field(Mesh *localmesh) - : fieldmesh(localmesh==nullptr ? bout::globals::mesh : localmesh) { - -// Note we would like to do `fieldCoordinates = getCoordinates();` here but can't -// currently as this would lead to circular/recursive behaviour (getCoordinates would -// call fieldmesh->coordinates, which would create fields, which would then call -// getCoordinates again etc.). This also requires care in the derived class -// constructors. +Field::Field(Mesh *localmesh, CELL_LOC location_in, + DIRECTION xDirectionType_in, DIRECTION yDirectionType_in, + DIRECTION zDirectionType_in) + : fieldmesh(localmesh==nullptr ? bout::globals::mesh : localmesh), + location(location_in), xDirectionType(xDirectionType_in), + yDirectionType(yDirectionType_in), zDirectionType(zDirectionType_in) { + + // Need to check for nullptr again, because the fieldmesh might still be + // nullptr if the global mesh hasn't been initialized yet + if (fieldmesh != nullptr) { + // get Coordinates for our location from fieldmesh + getCoordinates(); + + // Get default values for xDirectionType, yDirectionType and + // zDirectionType, if explicit values have not been passed to the + // constructor + setNullDirectionTypesToDefault(); + } +} + +void Field::setLocation(CELL_LOC new_location) { + AUTO_TRACE(); + if (getMesh()->StaggerGrids) { + if (new_location == CELL_VSHIFT) { + throw BoutException( + "Field: CELL_VSHIFT cell location only makes sense for vectors"); + } + if (new_location == CELL_DEFAULT) { + new_location = CELL_CENTRE; + } + + location = new_location; + } else { +#if CHECK > 0 + if (new_location != CELL_CENTRE && new_location != CELL_DEFAULT) { + throw BoutException("Field: Trying to set off-centre location on " + "non-staggered grid\n" + " Did you mean to enable staggered grids?"); + } +#endif + location = CELL_CENTRE; + } + + fieldCoordinates = nullptr; + // Sets correct Coordinates pointer and ensures Coordinates object is + // initialized for this Field's location + getCoordinates(); +} + +CELL_LOC Field::getLocation() const { + AUTO_TRACE(); + return location; } Coordinates *Field::getCoordinates() const { @@ -68,3 +112,16 @@ int Field::getNz() const{ return getMesh()->LocalNz; }; +void Field::setNullDirectionTypesToDefault() { + ASSERT1(fieldmesh != nullptr); + + if (xDirectionType == DIRECTION::Null) { + xDirectionType = DIRECTION::X; + } + if (yDirectionType == DIRECTION::Null) { + yDirectionType = fieldmesh->getParallelTransform().getDefaultYDirectionType(); + } + if (zDirectionType == DIRECTION::Null) { + zDirectionType = DIRECTION::Z; + } +} diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index d404f9af1e..c3bb9d54e0 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -46,7 +46,11 @@ #include -Field2D::Field2D(Mesh* localmesh) : Field(localmesh) { +Field2D::Field2D(Mesh* localmesh, CELL_LOC location_in, + DIRECTION xDirectionType_in, DIRECTION yDirectionType_in, DIRECTION + zDirectionType_in) + : Field(localmesh, location_in, xDirectionType_in, yDirectionType_in, + zDirectionType_in) { if (fieldmesh) { nx = fieldmesh->LocalNx; @@ -58,7 +62,7 @@ Field2D::Field2D(Mesh* localmesh) : Field(localmesh) { #endif } -Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), data(f.data) { +Field2D::Field2D(const Field2D& f) : Field(f), data(f.data) { TRACE("Field2D(Field2D&)"); #ifdef TRACK @@ -74,7 +78,7 @@ Field2D::Field2D(const Field2D& f) : Field(f.fieldmesh), data(f.data) { fieldCoordinates = f.fieldCoordinates; } -Field2D::Field2D(BoutReal val, Mesh* localmesh) : Field(localmesh) { +Field2D::Field2D(BoutReal val, Mesh* localmesh) : Field2D(localmesh) { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; @@ -89,10 +93,13 @@ Field2D::~Field2D() { void Field2D::allocate() { if(data.empty()) { if(!fieldmesh) { - /// If no mesh, use the global + // fieldmesh was not initialized when this field was initialized, so use + // the global mesh and set some members to default values fieldmesh = bout::globals::mesh; nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; + + setNullDirectionTypesToDefault(); } data = Array(nx*ny); #if CHECK > 2 @@ -117,36 +124,9 @@ const Region &Field2D::getRegion(const std::string ®ion_name) const { return fieldmesh->getRegion2D(region_name); }; -void Field2D::setLocation(CELL_LOC new_location) { - if (getMesh()->StaggerGrids) { - if (new_location == CELL_VSHIFT) { - throw BoutException( - "Field2D: CELL_VSHIFT cell location only makes sense for vectors"); - } - if (new_location == CELL_DEFAULT) { - new_location = CELL_CENTRE; - } - - location = new_location; - } else { -#if CHECK > 0 - if (new_location != CELL_CENTRE && new_location != CELL_DEFAULT) { - throw BoutException("Field2D: Trying to set off-centre location on " - "non-staggered grid\n" - " Did you mean to enable staggerGrids?"); - } -#endif - location = CELL_CENTRE; - } // Ensures Coordinates object is initialized for this Field's location getCoordinates(); -} - -CELL_LOC Field2D::getLocation() const { - return location; -} - // Not in header because we need to access fieldmesh BoutReal& Field2D::operator[](const Ind3D &d) { return operator[](fieldmesh->map3Dto2D(d)); @@ -169,17 +149,15 @@ Field2D &Field2D::operator=(const Field2D &rhs) { name = rhs.name; #endif + copyFieldMembers(rhs); + // Copy the data and data sizes - fieldmesh = rhs.fieldmesh; nx = rhs.nx; ny = rhs.ny; // Copy reference to data data = rhs.data; - // Copy location - setLocation(rhs.location); - return *this; } diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 622be971b3..b30fee49e4 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -44,7 +44,11 @@ #include /// Constructor -Field3D::Field3D(Mesh* localmesh) : Field(localmesh) { +Field3D::Field3D(Mesh* localmesh, CELL_LOC location_in, + DIRECTION xDirectionType_in, DIRECTION yDirectionType_in, + DIRECTION zDirectionType_in) + : Field(localmesh, location_in, xDirectionType_in, yDirectionType_in, + zDirectionType_in) { #ifdef TRACK name = ""; #endif @@ -58,7 +62,7 @@ Field3D::Field3D(Mesh* localmesh) : Field(localmesh) { /// Doesn't copy any data, just create a new reference to the same data (copy on change /// later) -Field3D::Field3D(const Field3D& f) : Field(f.fieldmesh), data(f.data) { +Field3D::Field3D(const Field3D& f) : Field(f), data(f.data) { TRACE("Field3D(Field3D&)"); @@ -72,7 +76,7 @@ Field3D::Field3D(const Field3D& f) : Field(f.fieldmesh), data(f.data) { fieldCoordinates = f.fieldCoordinates; } -Field3D::Field3D(const Field2D& f) : Field(f.getMesh()) { +Field3D::Field3D(const Field2D& f) : Field(f) { TRACE("Field3D: Copy constructor from Field2D"); @@ -80,13 +84,10 @@ Field3D::Field3D(const Field2D& f) : Field(f.getMesh()) { ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; - location = f.getLocation(); - fieldCoordinates = nullptr; - *this = f; } -Field3D::Field3D(const BoutReal val, Mesh* localmesh) : Field(localmesh) { +Field3D::Field3D(const BoutReal val, Mesh* localmesh) : Field3D(localmesh) { TRACE("Field3D: Copy constructor from value"); @@ -107,11 +108,14 @@ Field3D::~Field3D() { void Field3D::allocate() { if(data.empty()) { if(!fieldmesh) { - /// If no mesh, use the global + // fieldmesh was not initialized when this field was initialized, so use + // the global mesh and set some members to default values fieldmesh = bout::globals::mesh; nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; + + setNullDirectionTypesToDefault(); } data = Array(nx*ny*nz); #if CHECK > 2 @@ -194,38 +198,9 @@ Field3D &Field3D::ynext(int dir) { return const_cast(static_cast(*this).ynext(dir)); } -void Field3D::setLocation(CELL_LOC new_location) { - AUTO_TRACE(); - if (getMesh()->StaggerGrids) { - if (new_location == CELL_VSHIFT) { - throw BoutException( - "Field3D: CELL_VSHIFT cell location only makes sense for vectors"); - } - if (new_location == CELL_DEFAULT) { - new_location = CELL_CENTRE; - } - - location = new_location; - } else { -#if CHECK > 0 - if (new_location != CELL_CENTRE && new_location != CELL_DEFAULT) { - throw BoutException("Field3D: Trying to set off-centre location on " - "non-staggered grid\n" - " Did you mean to enable staggered grids?"); - } -#endif - location = CELL_CENTRE; - } // Ensures Coordinates object is initialized for this Field's location getCoordinates(); -} - -CELL_LOC Field3D::getLocation() const { - AUTO_TRACE(); - return location; -} - // Not in header because we need to access fieldmesh BoutReal &Field3D::operator()(const IndPerp &d, int jy) { return operator[](fieldmesh->indPerpto3D(d, jy)); @@ -263,13 +238,16 @@ Field3D & Field3D::operator=(const Field3D &rhs) { TRACE("Field3D: Assignment from Field3D"); + copyFieldMembers(rhs); + // Copy the data and data sizes - fieldmesh = rhs.fieldmesh; - nx = rhs.nx; ny = rhs.ny; nz = rhs.nz; - - data = rhs.data; + nx = rhs.nx; + ny = rhs.ny; + nz = rhs.nz; - setLocation(rhs.location); + ASSERT1(fieldsCompatible(*this, rhs)); + + data = rhs.data; return *this; } @@ -280,28 +258,28 @@ Field3D & Field3D::operator=(const Field2D &rhs) { /// Check that the data is allocated ASSERT1(rhs.isAllocated()); + setLocation(rhs.getLocation()); + /// Make sure there's a unique array to copy data into allocate(); + ASSERT1(fieldsCompatible(*this, rhs)); /// Copy data BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] = rhs[i]; } - setLocation(rhs.getLocation()); - return *this; } void Field3D::operator=(const FieldPerp &rhs) { TRACE("Field3D = FieldPerp"); - ASSERT1(location == rhs.getLocation()); ASSERT1(getMesh() == rhs.getMesh()); - /// Check that the data is allocated ASSERT1(rhs.isAllocated()); /// Make sure there's a unique array to copy data into allocate(); + ASSERT1(fieldsCompatible(*this, rhs)); /// Copy data BOUT_FOR(i, rhs.getRegion("RGN_ALL")) { (*this)(i, rhs.getIndex()) = rhs[i]; } @@ -595,7 +573,7 @@ Field3D operator-(const Field3D &f) { return -1.0 * f; } Field3D pow(const Field3D &lhs, const Field3D &rhs, REGION rgn) { TRACE("pow(Field3D, Field3D)"); - ASSERT1(lhs.getLocation() == rhs.getLocation()); + ASSERT1(fieldsCompatible(lhs, rhs)); ASSERT1(lhs.getMesh() == rhs.getMesh()); Field3D result(lhs.getMesh()); diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 063949fcde..5fbb157f2c 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -34,26 +34,32 @@ #include #include -FieldPerp::FieldPerp(Mesh *localmesh) : Field(localmesh) { +FieldPerp::FieldPerp(Mesh *localmesh, CELL_LOC location_in, int yindex_in, + DIRECTION xDirectionType_in, DIRECTION yDirectionType_in, + DIRECTION zDirectionType_in) + : Field(localmesh, location_in, xDirectionType_in, yDirectionType_in, + zDirectionType_in), + yindex(yindex_in) { if (fieldmesh) { nx = fieldmesh->LocalNx; nz = fieldmesh->LocalNz; } } -FieldPerp::FieldPerp(BoutReal val, Mesh *localmesh) : Field(localmesh) { - nx = fieldmesh->LocalNx; - nz = fieldmesh->LocalNz; +FieldPerp::FieldPerp(BoutReal val, Mesh *localmesh) : FieldPerp(localmesh) { *this = val; } void FieldPerp::allocate() { if (data.empty()) { if (!fieldmesh) { - /// If no mesh, use the global + // fieldmesh was not initialized when this field was initialized, so use + // the global mesh and set some members to default values fieldmesh = bout::globals::mesh; nx = fieldmesh->LocalNx; nz = fieldmesh->LocalNz; + + setNullDirectionTypesToDefault(); } data = Array(nx * nz); #if CHECK > 2 @@ -61,38 +67,7 @@ void FieldPerp::allocate() { #endif } else data.ensureUnique(); -} -void FieldPerp::setLocation(CELL_LOC new_location) { - AUTO_TRACE(); - if (getMesh()->StaggerGrids) { - if (new_location == CELL_VSHIFT) { - throw BoutException( - "FieldPerp: CELL_VSHIFT cell location only makes sense for vectors"); - } - if (new_location == CELL_DEFAULT) { - new_location = CELL_CENTRE; - } - - location = new_location; - } else { -#if CHECK > 0 - if (new_location != CELL_CENTRE && new_location != CELL_DEFAULT) { - throw BoutException("FieldPerp: Trying to set off-centre location on " - "non-staggered grid\n" - " Did you mean to enable staggered grids?"); - } -#endif - location = CELL_CENTRE; - } - - // Ensures Coordinates object is initialized for this Field's location - getCoordinates(); -} - -CELL_LOC FieldPerp::getLocation() const { - AUTO_TRACE(); - return location; } /*************************************************************** @@ -105,12 +80,15 @@ FieldPerp &FieldPerp::operator=(const FieldPerp &rhs) { return (*this); // skip this assignment } + copyFieldMembers(rhs); + nx = rhs.nx; nz = rhs.nz; yindex = rhs.yindex; data = rhs.data; - setLocation(rhs.location); + ASSERT1(fieldsCompatible(*this, rhs)); + return *this; } diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index a4bd0aa2f5..f2e22c241d 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -107,6 +107,10 @@ protected: void checkInputGrid() override; + DIRECTION getDefaultYDirectionType() const override { + return DIRECTION::YOrthogonal; + } + private: /// FCI maps for each of the parallel slices std::vector field_line_maps; diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index d331276c1d..efef63968c 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -54,6 +54,12 @@ const std::string& DIRECTION_STRING(DIRECTION direction) { return safeAt(DIRECTIONtoString, direction); } +void swap(DIRECTION& first, DIRECTION& second) { + DIRECTION temp = first; + first = second; + second = temp; +} + const std::string& STAGGER_STRING(STAGGER stagger) { AUTO_TRACE(); const static std::map STAGGERtoString = { diff --git a/tests/unit/field/test_field.cxx b/tests/unit/field/test_field.cxx index f2934f6d45..061895e981 100644 --- a/tests/unit/field/test_field.cxx +++ b/tests/unit/field/test_field.cxx @@ -31,7 +31,7 @@ TEST_F(FieldTest, GetGlobalMesh) { TEST_F(FieldTest, GetLocalMesh) { FakeMesh myMesh{nx + 1, ny + 2, nz + 3}; - Field field(&myMesh); + Field field(&myMesh, CELL_CENTRE, DIRECTION::X, DIRECTION::Y, DIRECTION::Z); auto localmesh = field.getMesh(); From aae2c477f78381e27e82e99f2214ac8199dfb0e0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 21 Feb 2019 23:04:09 +0000 Subject: [PATCH 0930/1783] Add emptyFrom function to construct a shell Field with copied metadata emptyFrom(f) returns a Field3D/Field2D/FieldPerp with metadata copied from f, and with its data array allocated, but without copying or initializing the data array. setLocation, setDirectionY and allocate methods now return an object instead of void to allow method chaining, e.g. Field3D result{emptyFrom(f).setLocation(CELL_YLOW)}; --- include/bout/empty_from.hxx | 21 +++++++++++++++++++++ include/field2d.hxx | 13 ++++++++++++- include/field3d.hxx | 13 ++++++++++++- include/fieldperp.hxx | 12 +++++++++++- src/field/field2d.cxx | 7 +++---- src/field/field3d.cxx | 7 +++---- src/field/fieldperp.cxx | 3 ++- 7 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 include/bout/empty_from.hxx diff --git a/include/bout/empty_from.hxx b/include/bout/empty_from.hxx new file mode 100644 index 0000000000..140407ccf4 --- /dev/null +++ b/include/bout/empty_from.hxx @@ -0,0 +1,21 @@ +#ifndef __NEW_EMPTY_FIELD_H__ +#define __NEW_EMPTY_FIELD_H__ + +#include "field.hxx" +#include "fieldperp.hxx" + +/// Return an empty shell field of some type derived from Field, with metadata +/// copied but empty data array +template +inline T emptyFrom(const T& f) { + static_assert(std::is_base_of::value, "emptyFrom only works on Fields"); + return T(f.getMesh(), f.getLocation(), f.getDirectionX(), f.getDirectionY(), f.getDirectionZ()).allocate(); +} + +// Specialize newEmptyField templates for FieldPerp +template<> +inline FieldPerp emptyFrom(const FieldPerp& f) { + return FieldPerp(f.getMesh(), f.getLocation(), f.getIndex(), f.getDirectionX(), f.getDirectionY(), f.getDirectionZ()).allocate(); +} + +#endif // __NEW_EMPTY_FIELD_H__ diff --git a/include/field2d.hxx b/include/field2d.hxx index f337fb9b47..7d55dcf251 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -40,6 +40,7 @@ class Field3D; //#include "field3d.hxx" #include "bout/field_visitor.hxx" #include "bout/array.hxx" +#include "bout/empty_from.hxx" #include "bout/region.hxx" #include "unused.hxx" @@ -95,7 +96,7 @@ class Field2D : public Field, public FieldData { using value_type = BoutReal; /// Ensure data is allocated - void allocate(); + Field2D& allocate(); bool isAllocated() const { return !data.empty(); } ///< Test if data is allocated /// Return a pointer to the time-derivative field @@ -114,6 +115,16 @@ class Field2D : public Field, public FieldData { */ int getNz() const override {return 1;}; + // these methods return Field2D to allow method chaining + Field2D& setLocation(CELL_LOC location) { + Field::setLocation(location); + return *this; + } + Field2D& setDirectionY(DIRECTION d) { + Field::setDirectionY(d); + return *this; + } + /// Check if this field has yup and ydown fields bool hasYupYdown() const { return true; diff --git a/include/field3d.hxx b/include/field3d.hxx index 5f81050e8a..298ebc0d3e 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -34,6 +34,7 @@ class Mesh; // #include "bout/mesh.hxx" #include "bout_types.hxx" #include "bout/array.hxx" +#include "bout/empty_from.hxx" #include "bout/region.hxx" #include "bout/assert.hxx" @@ -192,7 +193,7 @@ class Field3D : public Field, public FieldData { /*! * Ensures that memory is allocated and unique */ - void allocate(); + Field3D& allocate(); /*! * Test if data is allocated @@ -220,6 +221,16 @@ class Field3D : public Field, public FieldData { */ int getNz() const override {return nz;}; + // these methods return Field3D to allow method chaining + Field3D& setLocation(CELL_LOC location) { + Field::setLocation(location); + return *this; + } + Field3D& setDirectionY(DIRECTION d) { + Field::setDirectionY(d); + return *this; + } + /*! * Ensure that this field has separate fields * for yup and ydown. diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 207e41b5dd..68d5132008 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -120,10 +120,20 @@ class FieldPerp : public Field { */ void setIndex(int y) { yindex = y; } + // these methods return FieldPerp to allow method chaining + FieldPerp& setLocation(CELL_LOC location) { + Field::setLocation(location); + return *this; + } + FieldPerp& setDirectionY(DIRECTION d) { + Field::setDirectionY(d); + return *this; + } + /*! * Ensure that data array is allocated and unique */ - void allocate(); + FieldPerp& allocate(); /*! * True if the underlying data array is allocated. diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index c3bb9d54e0..0945d2d64e 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -90,7 +90,7 @@ Field2D::~Field2D() { delete deriv; } -void Field2D::allocate() { +Field2D& Field2D::allocate() { if(data.empty()) { if(!fieldmesh) { // fieldmesh was not initialized when this field was initialized, so use @@ -107,6 +107,8 @@ void Field2D::allocate() { #endif }else data.ensureUnique(); + + return *this; } Field2D* Field2D::timeDeriv() { @@ -124,9 +126,6 @@ const Region &Field2D::getRegion(const std::string ®ion_name) const { return fieldmesh->getRegion2D(region_name); }; - - // Ensures Coordinates object is initialized for this Field's location - getCoordinates(); // Not in header because we need to access fieldmesh BoutReal& Field2D::operator[](const Ind3D &d) { return operator[](fieldmesh->map3Dto2D(d)); diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index b30fee49e4..f19b03bf34 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -105,7 +105,7 @@ Field3D::~Field3D() { } } -void Field3D::allocate() { +Field3D& Field3D::allocate() { if(data.empty()) { if(!fieldmesh) { // fieldmesh was not initialized when this field was initialized, so use @@ -123,6 +123,8 @@ void Field3D::allocate() { #endif } else data.ensureUnique(); + + return *this; } Field3D* Field3D::timeDeriv() { @@ -198,9 +200,6 @@ Field3D &Field3D::ynext(int dir) { return const_cast(static_cast(*this).ynext(dir)); } - - // Ensures Coordinates object is initialized for this Field's location - getCoordinates(); // Not in header because we need to access fieldmesh BoutReal &Field3D::operator()(const IndPerp &d, int jy) { return operator[](fieldmesh->indPerpto3D(d, jy)); diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 5fbb157f2c..e878e40770 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -50,7 +50,7 @@ FieldPerp::FieldPerp(BoutReal val, Mesh *localmesh) : FieldPerp(localmesh) { *this = val; } -void FieldPerp::allocate() { +FieldPerp& FieldPerp::allocate() { if (data.empty()) { if (!fieldmesh) { // fieldmesh was not initialized when this field was initialized, so use @@ -68,6 +68,7 @@ void FieldPerp::allocate() { } else data.ensureUnique(); + return *this; } /*************************************************************** From 0ce90a7e9c07523bc51a046305b1ee06efd27d2f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Feb 2019 12:13:58 +0000 Subject: [PATCH 0931/1783] Explicitly set yDirectionType for Field3Ds in FCIMap and Interpolations FCITransform is being constructed, so has not yet been set as 'transform' in the Mesh, so Field3Ds cannot get a default yDirectionType. --- src/mesh/interpolation/bilinear.cxx | 6 +++++- src/mesh/interpolation/hermite_spline.cxx | 12 +++++++++--- src/mesh/interpolation/lagrange_4pt.cxx | 4 +++- src/mesh/parallel/fci.cxx | 16 ++++++++++------ 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/mesh/interpolation/bilinear.cxx b/src/mesh/interpolation/bilinear.cxx index 0060cc12a0..3e50000d5a 100644 --- a/src/mesh/interpolation/bilinear.cxx +++ b/src/mesh/interpolation/bilinear.cxx @@ -28,7 +28,11 @@ #include Bilinear::Bilinear(int y_offset, Mesh *mesh) - : Interpolation(y_offset, mesh), w0(localmesh), w1(localmesh), w2(localmesh), w3(localmesh) { + : Interpolation(y_offset, mesh), + w0(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), + w1(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), + w2(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), + w3(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z) { // Index arrays contain guard cells in order to get subscripts right i_corner = Tensor(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); diff --git a/src/mesh/interpolation/hermite_spline.cxx b/src/mesh/interpolation/hermite_spline.cxx index b0c425470a..f11daff31e 100644 --- a/src/mesh/interpolation/hermite_spline.cxx +++ b/src/mesh/interpolation/hermite_spline.cxx @@ -28,9 +28,15 @@ #include HermiteSpline::HermiteSpline(int y_offset, Mesh *mesh) - : Interpolation(y_offset, mesh), h00_x(localmesh), h01_x(localmesh), h10_x(localmesh), - h11_x(localmesh), h00_z(localmesh), h01_z(localmesh), h10_z(localmesh), - h11_z(localmesh) { + : Interpolation(y_offset, mesh), + h00_x(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), + h01_x(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), + h10_x(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), + h11_x(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), + h00_z(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), + h01_z(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), + h10_z(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), + h11_z(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z) { // Index arrays contain guard cells in order to get subscripts right i_corner = Tensor(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); diff --git a/src/mesh/interpolation/lagrange_4pt.cxx b/src/mesh/interpolation/lagrange_4pt.cxx index c942976bc3..80ccfd442b 100644 --- a/src/mesh/interpolation/lagrange_4pt.cxx +++ b/src/mesh/interpolation/lagrange_4pt.cxx @@ -27,7 +27,9 @@ #include Lagrange4pt::Lagrange4pt(int y_offset, Mesh *mesh) - : Interpolation(y_offset, mesh), t_x(localmesh), t_z(localmesh) { + : Interpolation(y_offset, mesh), + t_x(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), + t_z(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z) { // Index arrays contain guard cells in order to get subscripts right i_corner = Tensor(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 2686759503..1d64bbf09d 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -73,11 +73,16 @@ FCIMap::FCIMap(Mesh& mesh, int offset_, BoundaryRegionPar* boundary, bool zperio auto k_corner = Tensor(map_mesh.LocalNx, map_mesh.LocalNy, map_mesh.LocalNz); // Index-space coordinates of forward/backward points - Field3D xt_prime(&map_mesh), zt_prime(&map_mesh); + Field3D xt_prime(&map_mesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z); + Field3D zt_prime{emptyFrom(xt_prime)}; + // Real-space coordinates of grid points - Field3D R(&map_mesh), Z(&map_mesh); + Field3D R{emptyFrom(xt_prime)}; + Field3D Z{emptyFrom(xt_prime)}; + // Real-space coordinates of forward/backward points - Field3D R_prime(&map_mesh), Z_prime(&map_mesh); + Field3D R_prime{emptyFrom(xt_prime)}; + Field3D Z_prime{emptyFrom(xt_prime)}; map_mesh.get(R, "R", 0.0, false); map_mesh.get(Z, "Z", 0.0, false); @@ -116,9 +121,8 @@ FCIMap::FCIMap(Mesh& mesh, int offset_, BoundaryRegionPar* boundary, bool zperio } // Cell corners - Field3D xt_prime_corner(&map_mesh), zt_prime_corner(&map_mesh); - xt_prime_corner.allocate(); - zt_prime_corner.allocate(); + Field3D xt_prime_corner{emptyFrom(xt_prime)}; + Field3D zt_prime_corner{emptyFrom(xt_prime)}; BOUT_FOR(i, xt_prime_corner.getRegion("RGN_NOBNDRY")) { // Point interpolated from (x+1/2, z+1/2) From e985947489d7d8f70efd0d0e0a5d63e43ad2581f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 21 Feb 2019 23:08:38 +0000 Subject: [PATCH 0932/1783] Use yDirectionType in ShiftedMetric and FCITransform Make toFieldAligned and fromFieldAligned check the yDirectionType of their input: toFieldAligned does nothing if the input is YAligned; fromFieldAligned does nothing if the input is YOrthogonal. Also set the yDirectionType of the output appropriately. Add checks that yDirectionType is YOrthogonal in FCITransform. --- include/bout/paralleltransform.hxx | 2 ++ src/mesh/parallel/fci.cxx | 3 +++ src/mesh/parallel/shiftedmetric.cxx | 42 +++++++++++++++++++++++------ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 9bea6a2aa3..cf6c0325c8 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -206,8 +206,10 @@ private: * * @param[in] f The field to shift * @param[in] phs The phase to shift by + * @param[in] y_direction_out The value to set yDirectionType of the result to */ const Field3D shiftZ(const Field3D& f, const Tensor& phs, + const DIRECTION y_direction_out, const REGION region = RGN_NOX) const; /*! diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 1d64bbf09d..2aefaeb2cb 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -266,6 +266,7 @@ FCIMap::FCIMap(Mesh& mesh, int offset_, BoundaryRegionPar* boundary, bool zperio Field3D FCIMap::integrate(Field3D &f) const { TRACE("FCIMap::integrate"); + ASSERT1(f.getDirectionY() == DIRECTION::YOrthogonal); ASSERT1(&map_mesh == f.getMesh()); // Cell centre values @@ -337,6 +338,7 @@ void FCITransform::checkInputGrid() { void FCITransform::calcYUpDown(Field3D& f) { TRACE("FCITransform::calcYUpDown"); + ASSERT1(f.getDirectionY() == DIRECTION::YOrthogonal); // Only have forward_map/backward_map for CELL_CENTRE, so can only deal with // CELL_CENTRE inputs ASSERT1(f.getLocation() == CELL_CENTRE); @@ -353,6 +355,7 @@ void FCITransform::calcYUpDown(Field3D& f) { void FCITransform::integrateYUpDown(Field3D& f) { TRACE("FCITransform::integrateYUpDown"); + ASSERT1(f.getDirectionY() == DIRECTION::YOrthogonal); // Only have forward_map/backward_map for CELL_CENTRE, so can only deal with // CELL_CENTRE inputs ASSERT1(f.getLocation() == CELL_CENTRE); diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 3a33deafe7..672ed51ec7 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -136,7 +136,21 @@ void ShiftedMetric::cachePhases() { * and Y is then field aligned. */ const Field3D ShiftedMetric::toFieldAligned(const Field3D& f, const REGION region) { - return shiftZ(f, toAlignedPhs, region); + switch (f.getDirectionY()) { + case (DIRECTION::YOrthogonal): + return shiftZ(f, toAlignedPhs, DIRECTION::YOrthogonal, region); + case (DIRECTION::YAligned): + // f is already in field-aligned coordinates + return f; + default: +#if CHECK > 0 + throw BoutException("Unrecognized y-direction type for Field3D passed to " + "ShiftedMetric::toFieldAligned"); +#else + // This should never happen, but use 'return f' to avoid compiler warnings + return f; +#endif + } } /*! @@ -144,10 +158,25 @@ const Field3D ShiftedMetric::toFieldAligned(const Field3D& f, const REGION regio * but Y is not field aligned. */ const Field3D ShiftedMetric::fromFieldAligned(const Field3D& f, const REGION region) { - return shiftZ(f, fromAlignedPhs, region); + switch (f.getDirectionY()) { + case (DIRECTION::YAligned): + return shiftZ(f, fromAlignedPhs, DIRECTION::YOrthogonal, region); + case (DIRECTION::YOrthogonal): + // f is already in orthogonal coordinates + return f; + default: +#if CHECK > 0 + throw BoutException("Unrecognized y-direction type for Field3D passed to " + "ShiftedMetric::toFieldAligned"); +#else + // This should never happen, but use 'return f' to avoid compiler warnings + return f; +#endif + } } const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Tensor& phs, + const DIRECTION y_direction_out, const REGION region) const { ASSERT1(&mesh == f.getMesh()); // only have zShift for CELL_CENTRE, so can only deal with CELL_CENTRE inputs @@ -156,9 +185,7 @@ const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Tensor& ph if (mesh.LocalNz == 1) return f; // Shifting makes no difference - Field3D result(&mesh); - result.allocate(); - result.setLocation(f.getLocation()); + Field3D result{emptyFrom(f).setDirectionY(y_direction_out)}; BOUT_FOR(i, mesh.getRegion2D(REGION_STRING(region))) { shiftZ(&f(i, 0), &phs(i.x(), i.y(), 0), &result(i, 0)); @@ -187,6 +214,7 @@ void ShiftedMetric::shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* ou void ShiftedMetric::calcYUpDown(Field3D& f) { + ASSERT1(f.getDirectionY() == DIRECTION::YOrthogonal); ASSERT1(&mesh == f.getMesh()); // only have zShift for CELL_CENTRE, so can only deal with CELL_CENTRE inputs ASSERT1(f.getLocation() == CELL_CENTRE); @@ -256,9 +284,7 @@ const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Field2D& zangle, if (mesh.LocalNz == 1) return f; // Shifting makes no difference - Field3D result(&mesh); - result.allocate(); - result.setLocation(f.getLocation()); + Field3D result{emptyFrom(f)}; // We only use methods in ShiftedMetric to get fields for parallel operations // like interp_to or DDY. From 8187860a1751ace9417aa4b60ffd8a27faf44ea9 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 21 Feb 2019 23:34:19 +0000 Subject: [PATCH 0933/1783] Add ParallelTransform to FakeMesh in unit tests Avoids segfault when getParallelTransform() is called, since the ParallelTransform cannot be set from options in the unit tests. --- tests/unit/test_extras.hxx | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 5fbec54c5b..dc2bac0b60 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -149,6 +149,7 @@ public: maxregionblocksize = MAXREGIONBLOCKSIZE; setCoordinates(nullptr); + setParallelTransform(PTptr(new ParallelTransformIdentity(*this))); } void setCoordinates(std::shared_ptr coords, CELL_LOC location = CELL_CENTRE) { From a434e436991a431eb92aafe5a105ff016a1676e0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 21 Feb 2019 23:46:52 +0000 Subject: [PATCH 0934/1783] Update ShiftedMetric unit tests Include updates using yDirectionType. --- .../unit/mesh/parallel/test_shiftedmetric.cxx | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index e7552dfcea..1e967e2f1a 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -37,6 +37,14 @@ class ShiftedMetricTest : public ::testing::Test { {2., 4., 6., 8., 10., 12., 14.}, {3., 6., 9., 12., 15., 18., 21.}}); + static_cast(mesh)->setCoordinates(std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false)); + + mesh->setParallelTransform(Mesh::PTptr(new ShiftedMetric(*mesh, zShift))); + Field3D input_temp{mesh}; // input values have been slightly shuffled to ensure that input is not @@ -68,12 +76,6 @@ class ShiftedMetricTest : public ::testing::Test { {1., 2., 4., 3., 5.}}}); input = std::move(input_temp); - - static_cast(mesh)->setCoordinates(std::make_shared( - mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false)); } ~ShiftedMetricTest() { @@ -90,8 +92,6 @@ class ShiftedMetricTest : public ::testing::Test { }; TEST_F(ShiftedMetricTest, ToFieldAligned) { - ShiftedMetric shifted{*mesh, zShift}; - Field3D expected{mesh}; fillField(expected, {{{2., 3., 4., 5., 1.}, @@ -118,14 +118,17 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { {4., 5., 1., 3., 2.}, {2., 4., 3., 5., 1.}}}); - EXPECT_TRUE(IsFieldEqual(shifted.toFieldAligned(input, RGN_ALL), expected, "RGN_ALL", + EXPECT_TRUE(IsFieldEqual(mesh->toFieldAligned(input), expected, "RGN_ALL", FFTTolerance)); } TEST_F(ShiftedMetricTest, FromFieldAligned) { - ShiftedMetric shifted{*mesh, zShift}; + // reset input.yDirectionType so that fromFieldAligned is not a null + // operation + input.setDirectionY(DIRECTION::YAligned); - Field3D expected{mesh}; + Field3D expected{mesh, CELL_CENTRE}; + expected.setDirectionY(DIRECTION::YOrthogonal); fillField(expected, {{{5., 1., 2., 3., 4.}, {4., 5., 2., 1., 3.}, @@ -151,9 +154,13 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { {2., 4., 5., 1., 3.}, {5., 1., 2., 4., 3.}}}); + Field3D result = mesh->fromFieldAligned(input); + // Loosen tolerance a bit due to FFTs - EXPECT_TRUE(IsFieldEqual(shifted.fromFieldAligned(input, RGN_ALL), expected, "RGN_ALL", + EXPECT_TRUE(IsFieldEqual(mesh->fromFieldAligned(input), expected, "RGN_ALL", FFTTolerance)); + EXPECT_TRUE(fieldsCompatible(result, expected)); + EXPECT_FALSE(fieldsCompatible(result, input)); } TEST_F(ShiftedMetricTest, CalcYUpDown) { @@ -177,9 +184,7 @@ TEST_F(ShiftedMetricTest, CalcYUpDown) { output_info.enable(); // Actual interesting bit here! - ShiftedMetric shifted{*mesh, zShift}; - shifted.calcYUpDown(input); - + mesh->getParallelTransform().calcYUpDown(input); // Expected output values Field3D expected_up_1{mesh}; From e195604babcf0fac9897ff413e0f611f82e3d34b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Feb 2019 15:12:24 +0000 Subject: [PATCH 0935/1783] Move do-nothing case to early-exit at top of interp_to When the location of the input is already the output location, can return early from interp_to and don't need to allocate 'result'. --- include/interpolation.hxx | 222 +++++++++++++++++++------------------- 1 file changed, 112 insertions(+), 110 deletions(-) diff --git a/include/interpolation.hxx b/include/interpolation.hxx index 9ecd3a069e..246131abcf 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -62,138 +62,140 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { AUTO_TRACE(); static_assert(std::is_base_of::value || std::is_base_of::value, "interp_to must be templated with one of Field2D or Field3D."); + ASSERT1(loc != CELL_DEFAULT); // doesn't make sense to interplote to CELL_DEFAULT Mesh* fieldmesh = var.getMesh(); - T result(fieldmesh); - if ((loc != CELL_CENTRE && loc != CELL_DEFAULT) && (fieldmesh->StaggerGrids == false)) { + if ((loc != CELL_CENTRE) && (fieldmesh->StaggerGrids == false)) { throw BoutException("Asked to interpolate, but StaggerGrids is disabled!"); } - if (fieldmesh->StaggerGrids && (var.getLocation() != loc)) { + if (var.getLocation() == loc) { + // Nothing to do - just return unchanged + // Copying into result to return as returning var may increase the number of + // references to the var data whilst returning result doesn't + T result = var; + return result; + } - // Staggered grids enabled, and need to perform interpolation - TRACE("Interpolating %s -> %s", CELL_LOC_STRING(var.getLocation()).c_str(), - CELL_LOC_STRING(loc).c_str()); - if (region != RGN_NOBNDRY) { - // result is requested in some boundary region(s) - result = var; // NOTE: This is just for boundaries. FIX! - } - // NOTE: invalidateGuards() is called in Field3D::alloctate() if the data - // block is not already allocated, so will be called here if - // region==RGN_NOBNDRY + // NOTE: invalidateGuards() is called in Field3D::alloctate() if the data + // block is not already allocated, so will be called here if + // region==RGN_NOBNDRY + T result{emptyFrom(var).setLocation(loc)}; + + // Staggered grids enabled, and need to perform interpolation + TRACE("Interpolating %s -> %s", CELL_LOC_STRING(var.getLocation()).c_str(), + CELL_LOC_STRING(loc).c_str()); + + if (region != RGN_NOBNDRY) { + // result is requested in some boundary region(s) + result = var; // NOTE: This is just for boundaries. FIX! + result.setLocation(loc); // location gets reset when assigning from var result.allocate(); - result.setLocation(loc); - - // Cell location of the input field - const CELL_LOC location = var.getLocation(); - - if ((location == CELL_CENTRE) || (loc == CELL_CENTRE)) { - // Going between centred and shifted - - // Get the non-centre location for interpolation direction - const CELL_LOC dir = (loc == CELL_CENTRE) ? location : loc; - - switch (dir) { - case CELL_XLOW: { - // At least 2 boundary cells needed for interpolation in x-direction - ASSERT0(fieldmesh->xstart >= 2); - - if ((location == CELL_CENTRE) && (loc == CELL_XLOW)) { // C2L - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - // Producing a stencil centred around a lower X value - result[i] = interp(populateStencil(var, i)); - } - } else if (location == CELL_XLOW) { // L2C - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - // Stencil centred around a cell centre - result[i] = interp(populateStencil(var, i)); - } - } + } - break; - } - case CELL_YLOW: { - // At least 2 boundary cells needed for interpolation in y-direction - ASSERT0(fieldmesh->ystart >= 2); - - // We can't interpolate in y unless we're field-aligned - // FIXME: Add check once we label fields as orthogonal/aligned - - const T var_fa = fieldmesh->toFieldAligned(var, RGN_NOX); - if (region != RGN_NOBNDRY) { - // repeat the hack above for boundary points - // this avoids a duplicate toFieldAligned call if we had called - // result = toFieldAligned(result) - // to get the boundary cells - // - // result is requested in some boundary region(s) - result = var_fa; // NOTE: This is just for boundaries. FIX! - result.allocate(); - result.setLocation(loc); - } + // Cell location of the input field + const CELL_LOC location = var.getLocation(); - if ((location == CELL_CENTRE) && (loc == CELL_YLOW)) { // C2L - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - // Producing a stencil centred around a lower X value - result[i] = - interp(populateStencil(var_fa, i)); - } - } else if (location == CELL_YLOW) { // L2C - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - // Stencil centred around a cell centre - result[i] = - interp(populateStencil(var_fa, i)); - } - } + if ((location == CELL_CENTRE) || (loc == CELL_CENTRE)) { + // Going between centred and shifted - result = fieldmesh->fromFieldAligned(result, RGN_NOBNDRY); + // Get the non-centre location for interpolation direction + const CELL_LOC dir = (loc == CELL_CENTRE) ? location : loc; - break; - } - case CELL_ZLOW: { - - if ((location == CELL_CENTRE) && (loc == CELL_ZLOW)) { // C2L - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - // Producing a stencil centred around a lower X value - result[i] = interp(populateStencil(var, i)); - } - } else if (location == CELL_ZLOW) { // L2C - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - // Stencil centred around a cell centre - result[i] = interp(populateStencil(var, i)); - } + switch (dir) { + case CELL_XLOW: { + // At least 2 boundary cells needed for interpolation in x-direction + ASSERT0(fieldmesh->xstart >= 2); + + if ((location == CELL_CENTRE) && (loc == CELL_XLOW)) { // C2L + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Producing a stencil centred around a lower X value + result[i] = interp(populateStencil(var, i)); + } + } else if (location == CELL_XLOW) { // L2C + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Stencil centred around a cell centre + result[i] = interp(populateStencil(var, i)); } - break; } - default: { - // This should never happen - throw BoutException("Unsupported direction of interpolation\n" - " - don't know how to interpolate to %s", - CELL_LOC_STRING(loc).c_str()); + + break; + } + case CELL_YLOW: { + // At least 2 boundary cells needed for interpolation in y-direction + ASSERT0(fieldmesh->ystart >= 2); + + // We can't interpolate in y unless we're field-aligned + // FIXME: Add check once we label fields as orthogonal/aligned + + const T var_fa = fieldmesh->toFieldAligned(var, RGN_NOX); + if (region != RGN_NOBNDRY) { + // repeat the hack above for boundary points + // this avoids a duplicate toFieldAligned call if we had called + // result = toFieldAligned(result) + // to get the boundary cells + // + // result is requested in some boundary region(s) + result = var_fa; // NOTE: This is just for boundaries. FIX! + result.setLocation(loc); // location gets reset when assigning from var + result.allocate(); } - }; - if ((dir != CELL_ZLOW) && (region != RGN_NOBNDRY)) { - fieldmesh->communicate(result); + if ((location == CELL_CENTRE) && (loc == CELL_YLOW)) { // C2L + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Producing a stencil centred around a lower X value + result[i] = + interp(populateStencil(var_fa, i)); + } + } else if (location == CELL_YLOW) { // L2C + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Stencil centred around a cell centre + result[i] = + interp(populateStencil(var_fa, i)); + } } - } else { - // Shifted -> shifted - // For now, shift to centre then to final location loc - // We probably should not rely on this, but it might work if one of the - // shifts is in the z-direction where guard cells aren't needed. - result = interp_to(interp_to(var, CELL_CENTRE), loc, region); + result = fieldmesh->fromFieldAligned(result, RGN_NOBNDRY); + + break; } - return result; + case CELL_ZLOW: { + + if ((location == CELL_CENTRE) && (loc == CELL_ZLOW)) { // C2L + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Producing a stencil centred around a lower X value + result[i] = interp(populateStencil(var, i)); + } + } else if (location == CELL_ZLOW) { // L2C + BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { + // Stencil centred around a cell centre + result[i] = interp(populateStencil(var, i)); + } + } + break; + } + default: { + // This should never happen + throw BoutException("Unsupported direction of interpolation\n" + " - don't know how to interpolate to %s", + CELL_LOC_STRING(loc).c_str()); + } + }; + + if ((dir != CELL_ZLOW) && (region != RGN_NOBNDRY)) { + fieldmesh->communicate(result); + } + } else { - // Nothing to do - just return unchanged - // Copying into result to return as returning var may increase the number of - // references to the var data whilst returning result doesn't - result = var; - return result; + // Shifted -> shifted + // For now, shift to centre then to final location loc + // We probably should not rely on this, but it might work if one of the + // shifts is in the z-direction where guard cells aren't needed. + result = interp_to(interp_to(var, CELL_CENTRE), loc, region); } + return result; } /// Print out the cell location (for debugging) From 1b47299026d4d3456a4683595904406a8a25751e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Feb 2019 13:50:52 +0000 Subject: [PATCH 0936/1783] Use emptyFrom to create Fields wherever possible --- include/bout/fv_ops.hxx | 6 +- include/bout/index_derivs_interface.hxx | 16 +- include/bout/invertable_operator.hxx | 3 +- src/field/field2d.cxx | 21 +- src/field/field3d.cxx | 51 +-- src/field/fieldperp.cxx | 45 +-- src/field/gen_fieldops.jinja | 11 +- src/field/generated_fieldops.cxx | 328 +++++++----------- src/field/vecops.cxx | 32 +- src/field/vector2d.cxx | 9 +- src/field/vector3d.cxx | 11 +- src/field/where.cxx | 40 +-- src/fileio/datafile.cxx | 2 +- .../laplace/impls/cyclic/cyclic_laplace.cxx | 7 +- .../impls/multigrid/multigrid_laplace.cxx | 5 +- .../impls/multigrid/multigrid_laplace.hxx | 4 +- .../laplace/impls/naulin/naulin_laplace.hxx | 5 +- src/invert/laplace/impls/pdd/pdd.cxx | 6 +- .../laplace/impls/serial_band/serial_band.cxx | 5 +- .../laplace/impls/serial_tri/serial_tri.cxx | 5 +- .../laplace/impls/shoot/shoot_laplace.cxx | 5 +- src/invert/laplace/impls/spt/spt.cxx | 9 +- src/invert/laplace/invert_laplace.cxx | 10 +- .../impls/cyclic/laplacexz-cyclic.cxx | 4 +- .../laplacexz/impls/petsc/laplacexz-petsc.cxx | 4 +- src/invert/parderiv/impls/cyclic/cyclic.cxx | 4 +- src/mesh/coordinates.cxx | 21 +- src/mesh/difops.cxx | 71 +--- src/mesh/fv_ops.cxx | 13 +- src/mesh/impls/bout/boutmesh.cxx | 2 +- src/mesh/interpolation.cxx | 3 +- src/mesh/interpolation/bilinear.cxx | 3 +- src/mesh/interpolation/hermite_spline.cxx | 3 +- src/mesh/interpolation/lagrange_4pt.cxx | 3 +- src/mesh/parallel/fci.cxx | 4 +- src/physics/smoothing.cxx | 28 +- src/physics/sourcex.cxx | 14 +- src/solver/solver.cxx | 5 +- src/sys/derivs.cxx | 26 +- 39 files changed, 272 insertions(+), 572 deletions(-) diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index 96d701a8af..a9d0f6f91f 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -194,7 +194,8 @@ namespace FV { Coordinates *coord = f_in.getCoordinates(); - Field3D result = 0.0; + Field3D result{emptyFrom(f_in)}; + result = 0.0; // Only need one guard cell, so no need to communicate fluxes // Instead calculate in guard cells to preserve fluxes @@ -358,7 +359,8 @@ namespace FV { throw BoutException("Div_f_v_XPPM passed a covariant v"); } - Field3D result = 0.0; + Field3D result{emptyFrom(n_in)}; + result = 0.0; Field3D vx = v.x; Field3D vz = v.z; diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index aa8177189b..6c23c1c1f4 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -83,8 +83,8 @@ T flowDerivative(const T& vel, const T& f, CELL_LOC outloc, const std::string& m const int nPoint = localmesh->getNpoints(direction); if (nPoint == 1) { - auto tmp = T(0., localmesh); - tmp.setLocation(outloc); + T tmp{emptyFrom(f).setLocation(outloc)}; + tmp = 0.; return tmp; } @@ -93,9 +93,7 @@ T flowDerivative(const T& vel, const T& f, CELL_LOC outloc, const std::string& m method, direction, stagger, derivType); // Create the result field - T result(localmesh); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); + T result{emptyFrom(f).setLocation(outloc)}; // Apply method derivativeMethod(vel, f, result, region); @@ -149,8 +147,8 @@ T standardDerivative(const T& f, CELL_LOC outloc, const std::string& method, const int nPoint = localmesh->getNpoints(direction); if (nPoint == 1) { - auto tmp = T(0., localmesh); - tmp.setLocation(outloc); + T tmp{emptyFrom(f).setLocation(outloc)}; + tmp = 0.; return tmp; } @@ -159,9 +157,7 @@ T standardDerivative(const T& f, CELL_LOC outloc, const std::string& method, method, direction, stagger, derivType); // Create the result field - T result(localmesh); - result.allocate(); // Make sure data allocated - result.setLocation(outloc); + T result{emptyFrom(f).setLocation(outloc)}; // Apply method derivativeMethod(f, result, region); diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index e5650f70c3..f128468c85 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -427,8 +427,7 @@ public: output_debug << "KSPSolve finished with converged reason : " << reason << endl; // lhs to lhsField -- first make the output field and ensure it has space allocated - T lhsField(localmesh); - lhsField.allocate(); + T lhsField{emptyFrom(rhsField)}; ierr = petscVecToField(lhs, lhsField); CHKERRQ(ierr); diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 0945d2d64e..529b74e25f 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -113,7 +113,7 @@ Field2D& Field2D::allocate() { Field2D* Field2D::timeDeriv() { if(deriv == nullptr) - deriv = new Field2D(fieldmesh); + deriv = new Field2D{emptyFrom(*this)}; return deriv; } @@ -393,10 +393,8 @@ bool finite(const Field2D &f, REGION rgn) { /* Check if the input is allocated */ \ checkData(f); \ /* Define and allocate the output result */ \ - Field2D result(f.getMesh()); \ - result.allocate(); \ + Field2D result{emptyFrom(f)}; \ BOUT_FOR(d, result.getRegion(rgn)) { result[d] = func(f[d]); } \ - result.setLocation(f.getLocation()); \ checkData(result); \ return result; \ } @@ -445,13 +443,10 @@ Field2D pow(const Field2D &lhs, const Field2D &rhs, REGION rgn) { // Define and allocate the output result ASSERT1(lhs.getMesh() == rhs.getMesh()); - Field2D result(lhs.getMesh()); - result.allocate(); + Field2D result{emptyFrom(lhs)}; BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } - result.setLocation(lhs.getLocation()); - checkData(result); return result; } @@ -463,13 +458,10 @@ Field2D pow(const Field2D &lhs, BoutReal rhs, REGION rgn) { checkData(rhs); // Define and allocate the output result - Field2D result(lhs.getMesh()); - result.allocate(); + Field2D result{emptyFrom(lhs)}; BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs); } - result.setLocation(lhs.getLocation()); - checkData(result); return result; } @@ -481,13 +473,10 @@ Field2D pow(BoutReal lhs, const Field2D &rhs, REGION rgn) { checkData(rhs); // Define and allocate the output result - Field2D result(rhs.getMesh()); - result.allocate(); + Field2D result{emptyFrom(rhs)}; BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs, rhs[i]); } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index f19b03bf34..ae9723f94e 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -129,7 +129,7 @@ Field3D& Field3D::allocate() { Field3D* Field3D::timeDeriv() { if(deriv == nullptr) { - deriv = new Field3D(fieldmesh); + deriv = new Field3D{emptyFrom(*this)}; } return deriv; } @@ -149,8 +149,8 @@ void Field3D::splitYupYdown() { } for (int i = 0; i < fieldmesh->ystart; ++i) { - yup_fields.emplace_back(fieldmesh); - ydown_fields.emplace_back(fieldmesh); + yup_fields.emplace_back(emptyFrom(*this)); + ydown_fields.emplace_back(emptyFrom(*this)); } } @@ -574,14 +574,10 @@ Field3D pow(const Field3D &lhs, const Field3D &rhs, REGION rgn) { ASSERT1(fieldsCompatible(lhs, rhs)); - ASSERT1(lhs.getMesh() == rhs.getMesh()); - Field3D result(lhs.getMesh()); - result.allocate(); + Field3D result{emptyFrom(lhs)}; BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } - result.setLocation( lhs.getLocation() ); - checkData(result); return result; } @@ -594,13 +590,10 @@ Field3D pow(const Field3D &lhs, const Field2D &rhs, REGION rgn) { ASSERT1(lhs.getMesh() == rhs.getMesh()); // Define and allocate the output result - Field3D result(lhs.getMesh()); - result.allocate(); + Field3D result{emptyFrom(lhs)}; BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } - result.setLocation( lhs.getLocation() ); - checkData(result); return result; } @@ -613,10 +606,9 @@ FieldPerp pow(const Field3D &lhs, const FieldPerp &rhs, REGION rgn) { ASSERT1(lhs.getMesh() == rhs.getMesh()); ASSERT1(lhs.getLocation() == rhs.getLocation()); - FieldPerp result{rhs.getMesh()}; + FieldPerp result{rhs.getMesh(), rhs.getLocation(), rhs.getIndex(), rhs.getDirectionX(), + rhs.getDirectionY(), rhs.getDirectionZ()}; result.allocate(); - result.setIndex(rhs.getIndex()); - result.setLocation(rhs.getLocation()); BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs(i, rhs.getIndex()), rhs[i]); @@ -632,13 +624,10 @@ Field3D pow(const Field3D &lhs, BoutReal rhs, REGION rgn) { checkData(lhs); checkData(rhs); - Field3D result(lhs.getMesh()); - result.allocate(); + Field3D result{emptyFrom(lhs)}; BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs); } - result.setLocation( lhs.getLocation() ); - checkData(result); return result; } @@ -650,13 +639,10 @@ Field3D pow(BoutReal lhs, const Field3D &rhs, REGION rgn) { checkData(rhs); // Define and allocate the output result - Field3D result(rhs.getMesh()); - result.allocate(); + Field3D result{emptyFrom(rhs)}; BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs, rhs[i]); } - result.setLocation( rhs.getLocation() ); - checkData(result); return result; } @@ -752,15 +738,13 @@ BoutReal mean(const Field3D &f, bool allpe, REGION rgn) { * */ #define F3D_FUNC(name, func) \ - Field3D name(const Field3D &f, REGION rgn) { \ + Field3D name(const Field3D &f, REGION rgn) { \ TRACE(#name "(Field3D)"); \ /* Check if the input is allocated */ \ checkData(f); \ /* Define and allocate the output result */ \ - Field3D result(f.getMesh()); \ - result.allocate(); \ + Field3D result{emptyFrom(f)}; \ BOUT_FOR(d, result.getRegion(rgn)) { result[d] = func(f[d]); } \ - result.setLocation(f.getLocation()); \ checkData(result); \ return result; \ } @@ -788,8 +772,7 @@ Field3D filter(const Field3D &var, int N0, REGION rgn) { int ncz = localmesh->LocalNz; - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(var)}; const auto region_str = REGION_STRING(rgn); @@ -823,8 +806,6 @@ Field3D filter(const Field3D &var, int N0, REGION rgn) { result.name = "filter(" + var.name + ")"; #endif - result.setLocation(var.getLocation()); - checkData(result); return result; } @@ -842,8 +823,7 @@ Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn) { return var; } - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(var)}; const auto region_str = REGION_STRING(rgn); @@ -873,8 +853,6 @@ Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn) { } } - result.setLocation(var.getLocation()); - checkData(result); return result; } @@ -991,9 +969,8 @@ Field2D DC(const Field3D &f, REGION rgn) { checkData(f); Mesh *localmesh = f.getMesh(); - Field2D result(localmesh); + Field2D result(localmesh, f.getLocation()); result.allocate(); - result.setLocation(f.getLocation()); BOUT_FOR(i, result.getRegion(rgn)) { result[i] = 0.0; diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index e878e40770..99db153dd6 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -197,10 +197,7 @@ FieldPerp operator-(const FieldPerp &f) { return -1.0 * f; } ASSERT1(rhs.getLocation() == rhs.getLocation()); \ checkData(lhs); \ checkData(rhs); \ - FieldPerp result(lhs.getMesh()); \ - result.allocate(); \ - result.setIndex(lhs.getIndex()); \ - result.setLocation(rhs.getLocation()); \ + FieldPerp result{emptyFrom(lhs)}; \ \ BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs[i] op rhs[i]; } \ checkData(result); \ @@ -219,10 +216,7 @@ FPERP_FPERP_OP_FPERP(/); ASSERT1(rhs.getLocation() == rhs.getLocation()); \ checkData(lhs); \ checkData(rhs); \ - FieldPerp result(lhs.getMesh()); \ - result.allocate(); \ - result.setIndex(lhs.getIndex()); \ - result.setLocation(rhs.getLocation()); \ + FieldPerp result{emptyFrom(lhs)}; \ \ BOUT_FOR(i, result.getRegion("RGN_ALL")) { \ result[i] = lhs[i] op rhs(i.x(), lhs.getIndex(), i.z()); \ @@ -248,10 +242,7 @@ FPERP_FPERP_OP_FIELD(/, Field2D); const FieldPerp operator op(const FieldPerp& lhs, BoutReal rhs) { \ checkData(lhs); \ checkData(rhs); \ - FieldPerp result(lhs.getMesh()); \ - result.allocate(); \ - result.setIndex(lhs.getIndex()); \ - result.setLocation(lhs.getLocation()); \ + FieldPerp result{emptyFrom(lhs)}; \ \ BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs[i] op rhs; } \ \ @@ -268,10 +259,7 @@ FPERP_FPERP_OP_REAL(/); const FieldPerp operator op(BoutReal lhs, const FieldPerp& rhs) { \ checkData(lhs); \ checkData(rhs); \ - FieldPerp result(rhs.getMesh()); \ - result.allocate(); \ - result.setIndex(rhs.getIndex()); \ - result.setLocation(rhs.getLocation()); \ + FieldPerp result{emptyFrom(rhs)}; \ \ BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs op rhs[i]; } \ \ @@ -309,10 +297,7 @@ FPERP_REAL_OP_FPERP(/); /* Check if the input is allocated */ \ ASSERT1(f.isAllocated()); \ /* Define and allocate the output result */ \ - FieldPerp result(f.getMesh()); \ - result.allocate(); \ - result.setIndex(f.getIndex()); \ - result.setLocation(f.getLocation()); \ + FieldPerp result{emptyFrom(f)}; \ BOUT_FOR(d, result.getRegion(rgn)) { result[d] = func(f[d]); } \ checkData(result); \ return result; \ @@ -357,12 +342,11 @@ const FieldPerp sliceXZ(const Field3D& f, int y) { // Source field should be valid checkData(f); - FieldPerp result(f.getMesh()); + FieldPerp result(f.getMesh(), f.getLocation(), y, f.getDirectionX(), + f.getDirectionY(), f.getDirectionZ()); // Allocate memory result.allocate(); - result.setIndex(y); - result.setLocation(f.getLocation()); BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = f(i, y); } checkData(result); @@ -441,10 +425,7 @@ FieldPerp pow(const FieldPerp &lhs, const FieldPerp &rhs, REGION rgn) { ASSERT1(lhs.getMesh() == rhs.getMesh()); ASSERT1(lhs.getIndex() == rhs.getIndex()); ASSERT1(lhs.getLocation() == rhs.getLocation()); - FieldPerp result(lhs.getMesh()); - result.allocate(); - result.setIndex(lhs.getIndex()); - result.setLocation(lhs.getLocation()); + FieldPerp result{emptyFrom(lhs)}; BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } checkData(result); @@ -458,10 +439,7 @@ FieldPerp pow(const FieldPerp &lhs, BoutReal rhs, REGION rgn) { checkData(rhs); // Define and allocate the output result - FieldPerp result(lhs.getMesh()); - result.allocate(); - result.setIndex(lhs.getIndex()); - result.setLocation(lhs.getLocation()); + FieldPerp result{emptyFrom(lhs)}; BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs); } checkData(result); @@ -475,10 +453,7 @@ FieldPerp pow(BoutReal lhs, const FieldPerp &rhs, REGION rgn) { checkData(rhs); // Define and allocate the output result - FieldPerp result(rhs.getMesh()); - result.allocate(); - result.setIndex(rhs.getIndex()); - result.setLocation(rhs.getLocation()); + FieldPerp result{emptyFrom(rhs)}; BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs, rhs[i]); } checkData(result); diff --git a/src/field/gen_fieldops.jinja b/src/field/gen_fieldops.jinja index 58f07d0796..dbe27111d7 100644 --- a/src/field/gen_fieldops.jinja +++ b/src/field/gen_fieldops.jinja @@ -16,8 +16,11 @@ ASSERT1(localmesh == {{rhs.name}}.getMesh()); {% endif %} - {{out.field_type}} {{out.name}}(localmesh); - {{out.name}}.allocate(); + {% if lhs.field_type == out.field_type %} + {{out.field_type}} {{out.name}}{emptyFrom(lhs)}; + {% else %} + {{out.field_type}} {{out.name}}{emptyFrom(rhs)}; + {% endif %} checkData({{lhs.name}}); checkData({{rhs.name}}); @@ -44,10 +47,6 @@ } {% endif %} - {% if out in ['Field3D','Field2D'] %} - {{out.name}}.setLocation({{rhs.name if rhs in ["Field3D","Field2D"] else lhs.name}}.getLocation()); - {% endif %} - checkData({{out.name}}); return {{out.name}}; } diff --git a/src/field/generated_fieldops.cxx b/src/field/generated_fieldops.cxx index 0aa552060f..efc1f3ef77 100644 --- a/src/field/generated_fieldops.cxx +++ b/src/field/generated_fieldops.cxx @@ -7,7 +7,7 @@ #include // Provide the C++ wrapper for multiplication of Field3D and Field3D -Field3D operator*(const Field3D &lhs, const Field3D &rhs) { +Field3D operator*(const Field3D& lhs, const Field3D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator*(Field3D, Field3D): fields at different " @@ -16,12 +16,11 @@ Field3D operator*(const Field3D &lhs, const Field3D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -29,14 +28,12 @@ Field3D operator*(const Field3D &lhs, const Field3D &rhs) { result[index] = lhs[index] * rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field3D by multiplication with Field3D -Field3D &Field3D::operator*=(const Field3D &rhs) { +Field3D& Field3D::operator*=(const Field3D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -66,7 +63,7 @@ Field3D &Field3D::operator*=(const Field3D &rhs) { } // Provide the C++ wrapper for division of Field3D and Field3D -Field3D operator/(const Field3D &lhs, const Field3D &rhs) { +Field3D operator/(const Field3D& lhs, const Field3D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator/(Field3D, Field3D): fields at different " @@ -75,12 +72,11 @@ Field3D operator/(const Field3D &lhs, const Field3D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -88,14 +84,12 @@ Field3D operator/(const Field3D &lhs, const Field3D &rhs) { result[index] = lhs[index] / rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field3D by division with Field3D -Field3D &Field3D::operator/=(const Field3D &rhs) { +Field3D& Field3D::operator/=(const Field3D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -125,7 +119,7 @@ Field3D &Field3D::operator/=(const Field3D &rhs) { } // Provide the C++ wrapper for addition of Field3D and Field3D -Field3D operator+(const Field3D &lhs, const Field3D &rhs) { +Field3D operator+(const Field3D& lhs, const Field3D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator+(Field3D, Field3D): fields at different " @@ -134,12 +128,11 @@ Field3D operator+(const Field3D &lhs, const Field3D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -147,14 +140,12 @@ Field3D operator+(const Field3D &lhs, const Field3D &rhs) { result[index] = lhs[index] + rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field3D by addition with Field3D -Field3D &Field3D::operator+=(const Field3D &rhs) { +Field3D& Field3D::operator+=(const Field3D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -184,7 +175,7 @@ Field3D &Field3D::operator+=(const Field3D &rhs) { } // Provide the C++ wrapper for subtraction of Field3D and Field3D -Field3D operator-(const Field3D &lhs, const Field3D &rhs) { +Field3D operator-(const Field3D& lhs, const Field3D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator-(Field3D, Field3D): fields at different " @@ -193,12 +184,11 @@ Field3D operator-(const Field3D &lhs, const Field3D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -206,14 +196,12 @@ Field3D operator-(const Field3D &lhs, const Field3D &rhs) { result[index] = lhs[index] - rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field3D by subtraction with Field3D -Field3D &Field3D::operator-=(const Field3D &rhs) { +Field3D& Field3D::operator-=(const Field3D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -243,7 +231,7 @@ Field3D &Field3D::operator-=(const Field3D &rhs) { } // Provide the C++ wrapper for multiplication of Field3D and Field2D -Field3D operator*(const Field3D &lhs, const Field2D &rhs) { +Field3D operator*(const Field3D& lhs, const Field2D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator*(Field3D, Field2D): fields at different " @@ -252,12 +240,11 @@ Field3D operator*(const Field3D &lhs, const Field2D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -268,14 +255,12 @@ Field3D operator*(const Field3D &lhs, const Field2D &rhs) { } } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field3D by multiplication with Field2D -Field3D &Field3D::operator*=(const Field2D &rhs) { +Field3D& Field3D::operator*=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -310,7 +295,7 @@ Field3D &Field3D::operator*=(const Field2D &rhs) { } // Provide the C++ wrapper for division of Field3D and Field2D -Field3D operator/(const Field3D &lhs, const Field2D &rhs) { +Field3D operator/(const Field3D& lhs, const Field2D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator/(Field3D, Field2D): fields at different " @@ -319,12 +304,11 @@ Field3D operator/(const Field3D &lhs, const Field2D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -336,14 +320,12 @@ Field3D operator/(const Field3D &lhs, const Field2D &rhs) { } } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field3D by division with Field2D -Field3D &Field3D::operator/=(const Field2D &rhs) { +Field3D& Field3D::operator/=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -379,7 +361,7 @@ Field3D &Field3D::operator/=(const Field2D &rhs) { } // Provide the C++ wrapper for addition of Field3D and Field2D -Field3D operator+(const Field3D &lhs, const Field2D &rhs) { +Field3D operator+(const Field3D& lhs, const Field2D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator+(Field3D, Field2D): fields at different " @@ -388,12 +370,11 @@ Field3D operator+(const Field3D &lhs, const Field2D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -404,14 +385,12 @@ Field3D operator+(const Field3D &lhs, const Field2D &rhs) { } } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field3D by addition with Field2D -Field3D &Field3D::operator+=(const Field2D &rhs) { +Field3D& Field3D::operator+=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -446,7 +425,7 @@ Field3D &Field3D::operator+=(const Field2D &rhs) { } // Provide the C++ wrapper for subtraction of Field3D and Field2D -Field3D operator-(const Field3D &lhs, const Field2D &rhs) { +Field3D operator-(const Field3D& lhs, const Field2D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator-(Field3D, Field2D): fields at different " @@ -455,12 +434,11 @@ Field3D operator-(const Field3D &lhs, const Field2D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -471,14 +449,12 @@ Field3D operator-(const Field3D &lhs, const Field2D &rhs) { } } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field3D by subtraction with Field2D -Field3D &Field3D::operator-=(const Field2D &rhs) { +Field3D& Field3D::operator-=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -513,25 +489,22 @@ Field3D &Field3D::operator-=(const Field2D &rhs) { } // Provide the C++ wrapper for multiplication of Field3D and BoutReal -Field3D operator*(const Field3D &lhs, const BoutReal rhs) { +Field3D operator*(const Field3D& lhs, const BoutReal rhs) { - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] * rhs; } - result.setLocation(lhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field3D by multiplication with BoutReal -Field3D &Field3D::operator*=(const BoutReal rhs) { +Field3D& Field3D::operator*=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -550,25 +523,22 @@ Field3D &Field3D::operator*=(const BoutReal rhs) { } // Provide the C++ wrapper for division of Field3D and BoutReal -Field3D operator/(const Field3D &lhs, const BoutReal rhs) { +Field3D operator/(const Field3D& lhs, const BoutReal rhs) { - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] / rhs; } - result.setLocation(lhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field3D by division with BoutReal -Field3D &Field3D::operator/=(const BoutReal rhs) { +Field3D& Field3D::operator/=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -587,25 +557,22 @@ Field3D &Field3D::operator/=(const BoutReal rhs) { } // Provide the C++ wrapper for addition of Field3D and BoutReal -Field3D operator+(const Field3D &lhs, const BoutReal rhs) { +Field3D operator+(const Field3D& lhs, const BoutReal rhs) { - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] + rhs; } - result.setLocation(lhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field3D by addition with BoutReal -Field3D &Field3D::operator+=(const BoutReal rhs) { +Field3D& Field3D::operator+=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -624,25 +591,22 @@ Field3D &Field3D::operator+=(const BoutReal rhs) { } // Provide the C++ wrapper for subtraction of Field3D and BoutReal -Field3D operator-(const Field3D &lhs, const BoutReal rhs) { +Field3D operator-(const Field3D& lhs, const BoutReal rhs) { - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] - rhs; } - result.setLocation(lhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field3D by subtraction with BoutReal -Field3D &Field3D::operator-=(const BoutReal rhs) { +Field3D& Field3D::operator-=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -661,7 +625,7 @@ Field3D &Field3D::operator-=(const BoutReal rhs) { } // Provide the C++ wrapper for multiplication of Field2D and Field3D -Field3D operator*(const Field2D &lhs, const Field3D &rhs) { +Field3D operator*(const Field2D& lhs, const Field3D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator*(Field2D, Field3D): fields at different " @@ -670,12 +634,11 @@ Field3D operator*(const Field2D &lhs, const Field3D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); @@ -686,14 +649,12 @@ Field3D operator*(const Field2D &lhs, const Field3D &rhs) { } } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ wrapper for division of Field2D and Field3D -Field3D operator/(const Field2D &lhs, const Field3D &rhs) { +Field3D operator/(const Field2D& lhs, const Field3D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator/(Field2D, Field3D): fields at different " @@ -702,12 +663,11 @@ Field3D operator/(const Field2D &lhs, const Field3D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); @@ -718,14 +678,12 @@ Field3D operator/(const Field2D &lhs, const Field3D &rhs) { } } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ wrapper for addition of Field2D and Field3D -Field3D operator+(const Field2D &lhs, const Field3D &rhs) { +Field3D operator+(const Field2D& lhs, const Field3D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator+(Field2D, Field3D): fields at different " @@ -734,12 +692,11 @@ Field3D operator+(const Field2D &lhs, const Field3D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); @@ -750,14 +707,12 @@ Field3D operator+(const Field2D &lhs, const Field3D &rhs) { } } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ wrapper for subtraction of Field2D and Field3D -Field3D operator-(const Field2D &lhs, const Field3D &rhs) { +Field3D operator-(const Field2D& lhs, const Field3D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator-(Field2D, Field3D): fields at different " @@ -766,12 +721,11 @@ Field3D operator-(const Field2D &lhs, const Field3D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); @@ -782,14 +736,12 @@ Field3D operator-(const Field2D &lhs, const Field3D &rhs) { } } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ wrapper for multiplication of Field2D and Field2D -Field2D operator*(const Field2D &lhs, const Field2D &rhs) { +Field2D operator*(const Field2D& lhs, const Field2D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator*(Field2D, Field2D): fields at different " @@ -798,12 +750,11 @@ Field2D operator*(const Field2D &lhs, const Field2D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field2D result(localmesh); - result.allocate(); + Field2D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -811,14 +762,12 @@ Field2D operator*(const Field2D &lhs, const Field2D &rhs) { result[index] = lhs[index] * rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field2D by multiplication with Field2D -Field2D &Field2D::operator*=(const Field2D &rhs) { +Field2D& Field2D::operator*=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -848,7 +797,7 @@ Field2D &Field2D::operator*=(const Field2D &rhs) { } // Provide the C++ wrapper for division of Field2D and Field2D -Field2D operator/(const Field2D &lhs, const Field2D &rhs) { +Field2D operator/(const Field2D& lhs, const Field2D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator/(Field2D, Field2D): fields at different " @@ -857,12 +806,11 @@ Field2D operator/(const Field2D &lhs, const Field2D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field2D result(localmesh); - result.allocate(); + Field2D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -870,14 +818,12 @@ Field2D operator/(const Field2D &lhs, const Field2D &rhs) { result[index] = lhs[index] / rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field2D by division with Field2D -Field2D &Field2D::operator/=(const Field2D &rhs) { +Field2D& Field2D::operator/=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -907,7 +853,7 @@ Field2D &Field2D::operator/=(const Field2D &rhs) { } // Provide the C++ wrapper for addition of Field2D and Field2D -Field2D operator+(const Field2D &lhs, const Field2D &rhs) { +Field2D operator+(const Field2D& lhs, const Field2D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator+(Field2D, Field2D): fields at different " @@ -916,12 +862,11 @@ Field2D operator+(const Field2D &lhs, const Field2D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field2D result(localmesh); - result.allocate(); + Field2D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -929,14 +874,12 @@ Field2D operator+(const Field2D &lhs, const Field2D &rhs) { result[index] = lhs[index] + rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field2D by addition with Field2D -Field2D &Field2D::operator+=(const Field2D &rhs) { +Field2D& Field2D::operator+=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -966,7 +909,7 @@ Field2D &Field2D::operator+=(const Field2D &rhs) { } // Provide the C++ wrapper for subtraction of Field2D and Field2D -Field2D operator-(const Field2D &lhs, const Field2D &rhs) { +Field2D operator-(const Field2D& lhs, const Field2D& rhs) { #if CHECK > 0 if (lhs.getLocation() != rhs.getLocation()) { throw BoutException("Error in operator-(Field2D, Field2D): fields at different " @@ -975,12 +918,11 @@ Field2D operator-(const Field2D &lhs, const Field2D &rhs) { } #endif - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); ASSERT1(localmesh == rhs.getMesh()); - Field2D result(localmesh); - result.allocate(); + Field2D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -988,14 +930,12 @@ Field2D operator-(const Field2D &lhs, const Field2D &rhs) { result[index] = lhs[index] - rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field2D by subtraction with Field2D -Field2D &Field2D::operator-=(const Field2D &rhs) { +Field2D& Field2D::operator-=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1025,25 +965,22 @@ Field2D &Field2D::operator-=(const Field2D &rhs) { } // Provide the C++ wrapper for multiplication of Field2D and BoutReal -Field2D operator*(const Field2D &lhs, const BoutReal rhs) { +Field2D operator*(const Field2D& lhs, const BoutReal rhs) { - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); - Field2D result(localmesh); - result.allocate(); + Field2D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] * rhs; } - result.setLocation(lhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field2D by multiplication with BoutReal -Field2D &Field2D::operator*=(const BoutReal rhs) { +Field2D& Field2D::operator*=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1062,25 +999,22 @@ Field2D &Field2D::operator*=(const BoutReal rhs) { } // Provide the C++ wrapper for division of Field2D and BoutReal -Field2D operator/(const Field2D &lhs, const BoutReal rhs) { +Field2D operator/(const Field2D& lhs, const BoutReal rhs) { - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); - Field2D result(localmesh); - result.allocate(); + Field2D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] / rhs; } - result.setLocation(lhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field2D by division with BoutReal -Field2D &Field2D::operator/=(const BoutReal rhs) { +Field2D& Field2D::operator/=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1099,25 +1033,22 @@ Field2D &Field2D::operator/=(const BoutReal rhs) { } // Provide the C++ wrapper for addition of Field2D and BoutReal -Field2D operator+(const Field2D &lhs, const BoutReal rhs) { +Field2D operator+(const Field2D& lhs, const BoutReal rhs) { - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); - Field2D result(localmesh); - result.allocate(); + Field2D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] + rhs; } - result.setLocation(lhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field2D by addition with BoutReal -Field2D &Field2D::operator+=(const BoutReal rhs) { +Field2D& Field2D::operator+=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1136,25 +1067,22 @@ Field2D &Field2D::operator+=(const BoutReal rhs) { } // Provide the C++ wrapper for subtraction of Field2D and BoutReal -Field2D operator-(const Field2D &lhs, const BoutReal rhs) { +Field2D operator-(const Field2D& lhs, const BoutReal rhs) { - Mesh *localmesh = lhs.getMesh(); + Mesh* localmesh = lhs.getMesh(); - Field2D result(localmesh); - result.allocate(); + Field2D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] - rhs; } - result.setLocation(lhs.getLocation()); - checkData(result); return result; } // Provide the C++ operator to update Field2D by subtraction with BoutReal -Field2D &Field2D::operator-=(const BoutReal rhs) { +Field2D& Field2D::operator-=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1173,145 +1101,121 @@ Field2D &Field2D::operator-=(const BoutReal rhs) { } // Provide the C++ wrapper for multiplication of BoutReal and Field3D -Field3D operator*(const BoutReal lhs, const Field3D &rhs) { +Field3D operator*(const BoutReal lhs, const Field3D& rhs) { - Mesh *localmesh = rhs.getMesh(); + Mesh* localmesh = rhs.getMesh(); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs * rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ wrapper for division of BoutReal and Field3D -Field3D operator/(const BoutReal lhs, const Field3D &rhs) { +Field3D operator/(const BoutReal lhs, const Field3D& rhs) { - Mesh *localmesh = rhs.getMesh(); + Mesh* localmesh = rhs.getMesh(); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs / rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ wrapper for addition of BoutReal and Field3D -Field3D operator+(const BoutReal lhs, const Field3D &rhs) { +Field3D operator+(const BoutReal lhs, const Field3D& rhs) { - Mesh *localmesh = rhs.getMesh(); + Mesh* localmesh = rhs.getMesh(); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs + rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ wrapper for subtraction of BoutReal and Field3D -Field3D operator-(const BoutReal lhs, const Field3D &rhs) { +Field3D operator-(const BoutReal lhs, const Field3D& rhs) { - Mesh *localmesh = rhs.getMesh(); + Mesh* localmesh = rhs.getMesh(); - Field3D result(localmesh); - result.allocate(); + Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs - rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ wrapper for multiplication of BoutReal and Field2D -Field2D operator*(const BoutReal lhs, const Field2D &rhs) { +Field2D operator*(const BoutReal lhs, const Field2D& rhs) { - Mesh *localmesh = rhs.getMesh(); + Mesh* localmesh = rhs.getMesh(); - Field2D result(localmesh); - result.allocate(); + Field2D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs * rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ wrapper for division of BoutReal and Field2D -Field2D operator/(const BoutReal lhs, const Field2D &rhs) { +Field2D operator/(const BoutReal lhs, const Field2D& rhs) { - Mesh *localmesh = rhs.getMesh(); + Mesh* localmesh = rhs.getMesh(); - Field2D result(localmesh); - result.allocate(); + Field2D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs / rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ wrapper for addition of BoutReal and Field2D -Field2D operator+(const BoutReal lhs, const Field2D &rhs) { +Field2D operator+(const BoutReal lhs, const Field2D& rhs) { - Mesh *localmesh = rhs.getMesh(); + Mesh* localmesh = rhs.getMesh(); - Field2D result(localmesh); - result.allocate(); + Field2D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs + rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } // Provide the C++ wrapper for subtraction of BoutReal and Field2D -Field2D operator-(const BoutReal lhs, const Field2D &rhs) { +Field2D operator-(const BoutReal lhs, const Field2D& rhs) { - Mesh *localmesh = rhs.getMesh(); + Mesh* localmesh = rhs.getMesh(); - Field2D result(localmesh); - result.allocate(); + Field2D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs - rhs[index]; } - result.setLocation(rhs.getLocation()); - checkData(result); return result; } diff --git a/src/field/vecops.cxx b/src/field/vecops.cxx index e61a711e64..991eacabb5 100644 --- a/src/field/vecops.cxx +++ b/src/field/vecops.cxx @@ -132,7 +132,6 @@ const Field2D Div(const Vector2D& v, CELL_LOC outloc, const std::string& method) ASSERT1(outloc != CELL_VSHIFT); Mesh *localmesh = v.x.getMesh(); - Field2D result(localmesh); Coordinates *metric = localmesh->getCoordinates(outloc); @@ -140,7 +139,7 @@ const Field2D Div(const Vector2D& v, CELL_LOC outloc, const std::string& method) Vector2D vcn = v; vcn.toContravariant(); - result = DDX(metric->J*vcn.x, outloc, method); + Field2D result = DDX(metric->J*vcn.x, outloc, method); result += DDY(metric->J*vcn.y, outloc, method); result += DDZ(metric->J*vcn.z, outloc, method); result /= metric->J; @@ -159,7 +158,6 @@ const Field3D Div(const Vector3D& v, CELL_LOC outloc, const std::string& method) ASSERT1(outloc != CELL_VSHIFT); Mesh *localmesh = v.x.getMesh(); - Field3D result(localmesh); Coordinates *metric = localmesh->getCoordinates(outloc); @@ -167,7 +165,7 @@ const Field3D Div(const Vector3D& v, CELL_LOC outloc, const std::string& method) Vector3D vcn = v; vcn.toContravariant(); - result = DDX(vcn.x.getCoordinates()->J * vcn.x, outloc, method); + Field3D result = DDX(vcn.x.getCoordinates()->J * vcn.x, outloc, method); result += DDY(vcn.y.getCoordinates()->J * vcn.y, outloc, method); result += DDZ(vcn.z.getCoordinates()->J * vcn.z, outloc, method); result /= metric->J; @@ -197,8 +195,7 @@ const Field2D Div(const Vector2D& v, const Field2D& f, CELL_LOC outloc, Vector2D vcn = v; vcn.toContravariant(); - Field2D result(localmesh); - result = FDDX(vcn.x.getCoordinates()->J * vcn.x, f, outloc, method); + Field2D result = FDDX(vcn.x.getCoordinates()->J * vcn.x, f, outloc, method); result += FDDY(vcn.y.getCoordinates()->J * vcn.y, f, outloc, method); result += FDDZ(vcn.z.getCoordinates()->J * vcn.z, f, outloc, method); result /= metric->J; @@ -223,8 +220,7 @@ const Field3D Div(const Vector3D& v, const Field3D& f, CELL_LOC outloc, Vector3D vcn = v; vcn.toContravariant(); - Field3D result(localmesh); - result = FDDX(vcn.x.getCoordinates()->J * vcn.x, f, outloc, method); + Field3D result = FDDX(vcn.x.getCoordinates()->J * vcn.x, f, outloc, method); result += FDDY(vcn.y.getCoordinates()->J * vcn.y, f, outloc, method); result += FDDZ(vcn.z.getCoordinates()->J * vcn.z, f, outloc, method); result /= metric->J; @@ -298,57 +294,45 @@ const Vector3D Curl(const Vector3D &v) { const Field2D V_dot_Grad(const Vector2D &v, const Field2D &f) { TRACE("V_dot_Grad( Vector2D , Field2D )"); SCOREP0(); - Field2D result(f.getMesh()); // Get contravariant components of v auto vcn = v; vcn.toContravariant(); - result = VDDX(vcn.x, f) + VDDY(vcn.y, f) + VDDZ(vcn.z, f); - - return result; + return VDDX(vcn.x, f) + VDDY(vcn.y, f) + VDDZ(vcn.z, f); } const Field3D V_dot_Grad(const Vector2D &v, const Field3D &f) { TRACE("V_dot_Grad( Vector2D , Field3D )"); SCOREP0(); - Field3D result(f.getMesh()); // Get contravariant components of v auto vcn = v; vcn.toContravariant(); - result = VDDX(vcn.x, f) + VDDY(vcn.y, f) + VDDZ(vcn.z, f); - - return result; + return VDDX(vcn.x, f) + VDDY(vcn.y, f) + VDDZ(vcn.z, f); } const Field3D V_dot_Grad(const Vector3D &v, const Field2D &f) { TRACE("V_dot_Grad( Vector3D , Field2D )"); SCOREP0(); - Field3D result(f.getMesh()); // Get contravariant components of v auto vcn = v; vcn.toContravariant(); - result = VDDX(vcn.x, f) + VDDY(vcn.y, f) + VDDZ(vcn.z, f); - - return result; + return VDDX(vcn.x, f) + VDDY(vcn.y, f) + VDDZ(vcn.z, f); } const Field3D V_dot_Grad(const Vector3D &v, const Field3D &f) { TRACE("V_dot_Grad( Vector3D , Field3D )"); SCOREP0(); - Field3D result(f.getMesh()); // Get contravariant components of v auto vcn = v; vcn.toContravariant(); - result = VDDX(vcn.x, f) + VDDY(vcn.y, f) + VDDZ(vcn.z, f); - - return result; + return VDDX(vcn.x, f) + VDDY(vcn.y, f) + VDDZ(vcn.z, f); } // Here R is the deduced return type based on a promoting diff --git a/src/field/vector2d.cxx b/src/field/vector2d.cxx index 473805aaa7..93abef985a 100644 --- a/src/field/vector2d.cxx +++ b/src/field/vector2d.cxx @@ -89,8 +89,7 @@ void Vector2D::toCovariant() { const auto metric = localmesh->getCoordinates(location); // Need to use temporary arrays to store result - Field2D gx(localmesh), gy(localmesh), gz(localmesh); - gx.allocate(); gy.allocate(); gz.allocate(); + Field2D gx{emptyFrom(x)}, gy{emptyFrom(y)}, gz{emptyFrom(z)}; BOUT_FOR(i, localmesh->getRegion2D("RGN_ALL")){ gx[i] = metric->g_11[i]*x[i] + metric->g_12[i]*y[i] + metric->g_13[i]*z[i]; @@ -111,7 +110,6 @@ void Vector2D::toContravariant() { if(covariant) { // multiply by g^{ij} Mesh *localmesh = x.getMesh(); - Field2D gx(localmesh), gy(localmesh), gz(localmesh); if (location == CELL_VSHIFT) { Coordinates *metric_x, *metric_y, *metric_z; @@ -143,8 +141,7 @@ void Vector2D::toContravariant() { const auto metric = localmesh->getCoordinates(location); // Need to use temporary arrays to store result - Field2D gx(localmesh), gy(localmesh), gz(localmesh); - gx.allocate(); gy.allocate(); gz.allocate(); + Field2D gx{emptyFrom(x)}, gy{emptyFrom(y)}, gz{emptyFrom(z)}; BOUT_FOR(i, localmesh->getRegion2D("RGN_ALL")){ gx[i] = metric->g11[i]*x[i] + metric->g12[i]*y[i] + metric->g13[i]*z[i]; @@ -373,7 +370,7 @@ const Field2D Vector2D::operator*(const Vector2D &rhs) const { ASSERT2(location == rhs.getLocation()); Mesh *localmesh = x.getMesh(); - Field2D result(localmesh); + Field2D result{emptyFrom(x)}; if(rhs.covariant ^ covariant) { // Both different - just multiply components diff --git a/src/field/vector3d.cxx b/src/field/vector3d.cxx index 80081d1931..f785e9f250 100644 --- a/src/field/vector3d.cxx +++ b/src/field/vector3d.cxx @@ -90,8 +90,7 @@ void Vector3D::toCovariant() { const auto metric = localmesh->getCoordinates(location); // Need to use temporary arrays to store result - Field3D gx(localmesh), gy(localmesh), gz(localmesh); - gx.allocate(); gy.allocate(); gz.allocate(); + Field3D gx{emptyFrom(x)}, gy{emptyFrom(y)}, gz{emptyFrom(z)}; BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")){ gx[i] = metric->g_11[i]*x[i] + metric->g_12[i]*y[i] + metric->g_13[i]*z[i]; @@ -112,7 +111,6 @@ void Vector3D::toContravariant() { if(covariant) { // multiply by g^{ij} Mesh *localmesh = x.getMesh(); - Field3D gx(localmesh), gy(localmesh), gz(localmesh); if (location == CELL_VSHIFT) { Coordinates *metric_x, *metric_y, *metric_z; @@ -144,8 +142,7 @@ void Vector3D::toContravariant() { const auto metric = localmesh->getCoordinates(location); // Need to use temporary arrays to store result - Field3D gx(localmesh), gy(localmesh), gz(localmesh); - gx.allocate(); gy.allocate(); gz.allocate(); + Field3D gx{emptyFrom(x)}, gy{emptyFrom(y)}, gz{emptyFrom(z)}; BOUT_FOR(i, localmesh->getRegion3D("RGN_ALL")){ gx[i] = metric->g11[i]*x[i] + metric->g12[i]*y[i] + metric->g13[i]*z[i]; @@ -474,7 +471,7 @@ const Vector3D Vector3D::operator/(const Field3D &rhs) const { const Field3D Vector3D::operator*(const Vector3D &rhs) const { Mesh* mesh = x.getMesh(); - Field3D result(mesh); + Field3D result{emptyFrom(x)}; ASSERT2(location == rhs.getLocation()) if(rhs.covariant ^ covariant) { @@ -507,7 +504,7 @@ const Field3D Vector3D::operator*(const Vector2D &rhs) const { ASSERT2(location == rhs.getLocation()); - Field3D result(x.getMesh()); + Field3D result{emptyFrom(x)}; if(rhs.covariant ^ covariant) { // Both different - just multiply components diff --git a/src/field/where.cxx b/src/field/where.cxx index 3871f82c76..c0ae43add4 100644 --- a/src/field/where.cxx +++ b/src/field/where.cxx @@ -30,9 +30,7 @@ // Versions taking Field2D and returning Field3D const Field3D where(const Field2D &test, const Field3D >0, const Field3D &le0) { - const auto testMesh = test.getMesh(); - Field3D result(testMesh); - result.allocate(); + Field3D result{emptyFrom(gt0)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { @@ -45,9 +43,7 @@ const Field3D where(const Field2D &test, const Field3D >0, const Field3D &le0) } const Field3D where(const Field2D &test, const Field3D >0, BoutReal le0) { - const auto testMesh = test.getMesh(); - Field3D result(testMesh); - result.allocate(); + Field3D result{emptyFrom(gt0)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { @@ -60,9 +56,7 @@ const Field3D where(const Field2D &test, const Field3D >0, BoutReal le0) { } const Field3D where(const Field2D &test, BoutReal gt0, const Field3D &le0) { - const auto testMesh = test.getMesh(); - Field3D result(testMesh); - result.allocate(); + Field3D result{emptyFrom(le0)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { @@ -76,9 +70,7 @@ const Field3D where(const Field2D &test, BoutReal gt0, const Field3D &le0) { } const Field3D where(const Field2D &test, const Field3D >0, const Field2D &le0) { - const auto testMesh = test.getMesh(); - Field3D result(testMesh); - result.allocate(); + Field3D result{emptyFrom(gt0)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { @@ -92,9 +84,7 @@ const Field3D where(const Field2D &test, const Field3D >0, const Field2D &le0) } const Field3D where(const Field2D &test, const Field2D >0, const Field3D &le0) { - const auto testMesh = test.getMesh(); - Field3D result(testMesh); - result.allocate(); + Field3D result{emptyFrom(le0)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { @@ -111,9 +101,7 @@ const Field3D where(const Field2D &test, const Field2D >0, const Field3D &le0) // Versions taking Field2D and returning Field2D const Field2D where(const Field2D &test, const Field2D >0, const Field2D &le0) { - const auto testMesh = test.getMesh(); - Field2D result(testMesh); - result.allocate(); + Field2D result{emptyFrom(test)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { @@ -127,9 +115,7 @@ const Field2D where(const Field2D &test, const Field2D >0, const Field2D &le0) } const Field2D where(const Field2D &test, const Field2D >0, BoutReal le0) { - const auto testMesh = test.getMesh(); - Field2D result(testMesh); - result.allocate(); + Field2D result{emptyFrom(test)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { @@ -143,9 +129,7 @@ const Field2D where(const Field2D &test, const Field2D >0, BoutReal le0) { } const Field2D where(const Field2D &test, BoutReal gt0, const Field2D &le0) { - const auto testMesh = test.getMesh(); - Field2D result(testMesh); - result.allocate(); + Field2D result{emptyFrom(test)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { @@ -159,9 +143,7 @@ const Field2D where(const Field2D &test, BoutReal gt0, const Field2D &le0) { } const Field2D where(const Field2D &test, BoutReal gt0, BoutReal le0) { - const auto testMesh = test.getMesh(); - Field2D result(testMesh); - result.allocate(); + Field2D result{emptyFrom(test)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { @@ -178,9 +160,7 @@ const Field2D where(const Field2D &test, BoutReal gt0, BoutReal le0) { // Versions taking Field3D and returning Field3D const Field3D where(const Field3D &test, BoutReal gt0, const Field3D &le0) { - const auto testMesh = test.getMesh(); - Field3D result(testMesh); - result.allocate(); + Field3D result{emptyFrom(test)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { if(test[i] > 0.0) { diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 475bb0c5f1..1a7a45529e 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -1200,7 +1200,7 @@ bool Datafile::write_f3d(const std::string &name, Field3D *f, bool save_repeat) } //Deal with shifting the output - Field3D f_out(f->getMesh()); + Field3D f_out{emptyFrom(*f)}; if(shiftOutput) { f_out = mesh->toFieldAligned(*f); }else { diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index 3b907b4956..010cf45993 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -95,8 +95,7 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) ASSERT1(rhs.getLocation() == location); ASSERT1(x0.getLocation() == location); - FieldPerp x(localmesh); // Result - x.allocate(); + FieldPerp x{emptyFrom(rhs)}; // Result int jy = rhs.getIndex(); // Get the Y index x.setIndex(jy); @@ -256,9 +255,7 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { Timer timer("invert"); - Field3D x(localmesh); // Result - x.allocate(); - x.setLocation(location); + Field3D x{emptyFrom(rhs)}; // Result // Get the width of the boundary diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index 86b912154f..601f4d4026 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -425,10 +425,7 @@ BOUT_OMP(for) } } - FieldPerp result(localmesh); - result.setLocation(location); - result.allocate(); - result.setIndex(yindex); + FieldPerp result{emptyFrom(b_in)}; #if CHECK > 2 // Make any unused elements NaN so that user does not try to do calculations with them diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx index e0e05328eb..5f440f2d5d 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx @@ -195,10 +195,8 @@ public: const FieldPerp solve(const FieldPerp &b) override { ASSERT1(localmesh == b.getMesh()); - FieldPerp zero(localmesh); + FieldPerp zero{emptyFrom(b)}; zero = 0.; - zero.setLocation(location); - zero.setIndex(b.getIndex()); return solve(b, zero); } const FieldPerp solve(const FieldPerp &b_in, const FieldPerp &x0) override; diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.hxx b/src/invert/laplace/impls/naulin/naulin_laplace.hxx index d1088722ab..40c8d6e9ad 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.hxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.hxx @@ -110,10 +110,9 @@ public: } const Field3D solve(const Field3D &b, const Field3D &x0) override; const Field3D solve(const Field3D &b) override { - Field3D x0(b.getMesh()); + Field3D x0{emptyFrom(b)}; x0 = 0.; - x0.setLocation(b.getLocation()); - return solve(b, Field3D(0.)); + return solve(b, x0); } // Override flag-setting methods to set delp2solver's flags as well diff --git a/src/invert/laplace/impls/pdd/pdd.cxx b/src/invert/laplace/impls/pdd/pdd.cxx index dc792e18cf..48caccf6a1 100644 --- a/src/invert/laplace/impls/pdd/pdd.cxx +++ b/src/invert/laplace/impls/pdd/pdd.cxx @@ -44,8 +44,7 @@ const FieldPerp LaplacePDD::solve(const FieldPerp &b) { PDD_data data; - FieldPerp x(localmesh); - x.allocate(); + FieldPerp x{emptyFrom(b)}; start(b, data); next(data); @@ -58,8 +57,7 @@ const Field3D LaplacePDD::solve(const Field3D &b) { ASSERT1(localmesh == b.getMesh()); ASSERT1(b.getLocation() == location); - Field3D x(localmesh); - x.allocate(); + Field3D x{emptyFrom(b)}; FieldPerp xperp(localmesh); xperp.allocate(); diff --git a/src/invert/laplace/impls/serial_band/serial_band.cxx b/src/invert/laplace/impls/serial_band/serial_band.cxx index 38c0e3ffa3..c230e31c09 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.cxx +++ b/src/invert/laplace/impls/serial_band/serial_band.cxx @@ -85,12 +85,9 @@ const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0 ASSERT1(b.getLocation() == location); ASSERT1(x0.getLocation() == location); - FieldPerp x(localmesh); - x.setLocation(location); - x.allocate(); + FieldPerp x{emptyFrom(b)}; int jy = b.getIndex(); - x.setIndex(jy); int ncz = localmesh->LocalNz; int ncx = localmesh->LocalNx-1; diff --git a/src/invert/laplace/impls/serial_tri/serial_tri.cxx b/src/invert/laplace/impls/serial_tri/serial_tri.cxx index efc40e7126..c8292262b8 100644 --- a/src/invert/laplace/impls/serial_tri/serial_tri.cxx +++ b/src/invert/laplace/impls/serial_tri/serial_tri.cxx @@ -78,12 +78,9 @@ const FieldPerp LaplaceSerialTri::solve(const FieldPerp &b, const FieldPerp &x0) ASSERT1(b.getLocation() == location); ASSERT1(x0.getLocation() == location); - FieldPerp x(localmesh); - x.setLocation(location); - x.allocate(); + FieldPerp x{emptyFrom(b)}; int jy = b.getIndex(); - x.setIndex(jy); int ncz = localmesh->LocalNz; // No of z pnts int ncx = localmesh->LocalNx; // No of x pnts diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.cxx b/src/invert/laplace/impls/shoot/shoot_laplace.cxx index 6a813409ef..0cf9f87a61 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.cxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.cxx @@ -73,12 +73,9 @@ const FieldPerp LaplaceShoot::solve(const FieldPerp &rhs) { ASSERT1(localmesh = rhs.getMesh()); ASSERT1(rhs.getLocation() == location); - FieldPerp x(localmesh); // Result - x.setLocation(location); - x.allocate(); + FieldPerp x{emptyFrom(rhs)}; // Result int jy = rhs.getIndex(); // Get the Y index - x.setIndex(jy); // Get the width of the boundary diff --git a/src/invert/laplace/impls/spt/spt.cxx b/src/invert/laplace/impls/spt/spt.cxx index 9b4d9e7452..b4a16d370c 100644 --- a/src/invert/laplace/impls/spt/spt.cxx +++ b/src/invert/laplace/impls/spt/spt.cxx @@ -85,9 +85,7 @@ const FieldPerp LaplaceSPT::solve(const FieldPerp &b, const FieldPerp &x0) { ASSERT1(b.getLocation() == location); ASSERT1(x0.getLocation() == location); - FieldPerp x(localmesh); - x.setLocation(location); - x.allocate(); + FieldPerp x{emptyFrom(b)}; if( (inner_boundary_flags & INVERT_SET) || (outer_boundary_flags & INVERT_SET) ) { FieldPerp bs = copy(b); @@ -128,8 +126,7 @@ const Field3D LaplaceSPT::solve(const Field3D &b) { ASSERT1(localmesh = b.getMesh()); Timer timer("invert"); - Field3D x(localmesh); - x.allocate(); + Field3D x{emptyFrom(b)}; for(int jy=ys; jy <= ye; jy++) { // And start another one going @@ -157,8 +154,6 @@ const Field3D LaplaceSPT::solve(const Field3D &b) { x = xperp; } - x.setLocation(b.getLocation()); - return x; } diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index 5d5fde2518..ce41620fdd 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -157,8 +157,7 @@ const Field3D Laplacian::solve(const Field3D &b) { ye -= extra_yguards_upper; } - Field3D x(localmesh); - x.allocate(); + Field3D x{emptyFrom(b)}; int status = 0; try { @@ -172,8 +171,6 @@ const Field3D Laplacian::solve(const Field3D &b) { } BoutParallelThrowRhsFail(status, "Laplacian inversion took too many iterations."); - x.setLocation(b.getLocation()); - return x; } @@ -212,8 +209,7 @@ const Field3D Laplacian::solve(const Field3D &b, const Field3D &x0) { if(localmesh->hasBndryUpperY() && include_yguards) ye = localmesh->LocalNy-1; // Contains upper boundary - Field3D x(localmesh); - x.allocate(); + Field3D x{emptyFrom(b)}; int status = 0; try { @@ -227,8 +223,6 @@ const Field3D Laplacian::solve(const Field3D &b, const Field3D &x0) { } BoutParallelThrowRhsFail(status, "Laplacian inversion took too many iterations."); - x.setLocation(b.getLocation()); - return x; // Return the result of the inversion } diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx index b1f763b6eb..7131789916 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx @@ -250,9 +250,7 @@ Field3D LaplaceXZcyclic::solve(const Field3D &rhs, const Field3D &x0) { // FFT back to real space - Field3D result(localmesh); - result.allocate(); - result.setLocation(location); + Field3D result{emptyFrom(rhs)}; ind = 0; for(int y=localmesh->ystart; y <= localmesh->yend; y++) { diff --git a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx index 8b94d4fe03..7c85fdefb2 100644 --- a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx +++ b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx @@ -597,9 +597,7 @@ Field3D LaplaceXZpetsc::solve(const Field3D &bin, const Field3D &x0in) { Field3D b = bin; Field3D x0 = x0in; - Field3D result; - result.allocate(); - result.setLocation(location); + Field3D result{emptyFrom(bin)}; for (auto &it : slice) { /// Get y index diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index 202341d87e..3f0d955618 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -61,9 +61,7 @@ const Field3D InvertParCR::solve(const Field3D &f) { TRACE("InvertParCR::solve(Field3D)"); ASSERT1(localmesh == f.getMesh()); - Field3D result(localmesh); - result.allocate(); - result.setLocation(f.getLocation()); + Field3D result{emptyFrom(f)}; Coordinates *coord = f.getCoordinates(); diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 1244692136..1007438cd8 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -672,8 +672,8 @@ const Field2D Coordinates::DDZ(MAYBE_UNUSED(const Field2D &f), MAYBE_UNUSED(CELL const std::string &UNUSED(method), REGION UNUSED(region)) { ASSERT1(location == loc || loc == CELL_DEFAULT); ASSERT1(f.getMesh() == localmesh); - auto result = Field2D(0.0, localmesh); - result.setLocation(location); + Field2D result{emptyFrom(f)}; + result = 0.; return result; } @@ -780,16 +780,13 @@ const Field3D Coordinates::Grad2_par2(const Field3D &f, CELL_LOC outloc, const s } ASSERT1(location == outloc); - Field2D sg(localmesh); - Field3D result(localmesh), r2(localmesh); - - sg = sqrt(g_22); + Field2D sg = sqrt(g_22); sg = DDY(1. / sg, outloc, method) / sg; - result = ::DDY(f, outloc, method); + Field3D result = ::DDY(f, outloc, method); - r2 = D2DY2(f, outloc, method) / g_22; + Field3D r2 = D2DY2(f, outloc, method) / g_22; result = sg * result + r2; @@ -828,9 +825,7 @@ const Field3D Coordinates::Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) } ASSERT2(localmesh->xstart > 0); // Need at least one guard cell - Field3D result(localmesh); - result.allocate(); - result.setLocation(outloc); + Field3D result{emptyFrom(f).setLocation(outloc)}; if (useFFT) { int ncz = localmesh->LocalNz; @@ -893,9 +888,7 @@ const FieldPerp Coordinates::Delp2(const FieldPerp& f, CELL_LOC outloc, bool use } ASSERT2(localmesh->xstart > 0); // Need at least one guard cell - FieldPerp result(localmesh); - result.allocate(); - result.setLocation(outloc); + FieldPerp result{emptyFrom(f).setLocation(outloc)}; int jy = f.getIndex(); result.setIndex(jy); diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index c4738c4531..d314e99314 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -78,15 +78,13 @@ const Field3D Grad_parP(const Field3D &apar, const Field3D &f) { Mesh *mesh = apar.getMesh(); - Field3D result(mesh); - result.allocate(); + Field3D result{emptyFrom(f)}; int ncz = mesh->LocalNz; Coordinates *metric = apar.getCoordinates(); - Field3D gys(mesh); - gys.allocate(); + Field3D gys{emptyFrom(f)}; // Need Y derivative everywhere for(int x=1;x<=mesh->LocalNx-2;x++) @@ -210,8 +208,7 @@ const Field3D Div_par(const Field3D &f, const Field3D &v) { // Note: Not guaranteed to be flux conservative Mesh *mesh = f.getMesh(); - Field3D result(mesh); - result.allocate(); + Field3D result{emptyFrom(f)}; Coordinates *coord = f.getCoordinates(); @@ -236,8 +233,6 @@ const Field3D Div_par(const Field3D &f, const Field3D &v) { } } - result.setLocation(f.getLocation()); - return result; } @@ -280,8 +275,7 @@ const Field3D Grad_par_CtoL(const Field3D &var) { ASSERT1(var.getLocation() == CELL_CENTRE); Mesh *mesh = var.getMesh(); - Field3D result(mesh); - result.allocate(); + Field3D result{emptyFrom(var).setLocation(CELL_YLOW)}; Coordinates *metric = var.getCoordinates(CELL_YLOW); @@ -309,14 +303,11 @@ const Field3D Grad_par_CtoL(const Field3D &var) { result = mesh->fromFieldAligned(result, RGN_NOBNDRY); } - result.setLocation(CELL_YLOW); return result; } const Field2D Grad_par_CtoL(const Field2D &var) { - const auto varMesh = var.getMesh(); - Field2D result(varMesh); - result.allocate(); + Field2D result{emptyFrom(var).setLocation(CELL_YLOW)}; Coordinates *metric = var.getCoordinates(CELL_YLOW); @@ -324,8 +315,6 @@ const Field2D Grad_par_CtoL(const Field2D &var) { result[i] = (var[i] - var[i.ym()]) / (metric->dy[i] * sqrt(metric->g_22[i])); } - result.setLocation(CELL_YLOW); - return result; } @@ -336,9 +325,7 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg ASSERT1(f.getLocation() == CELL_CENTRE); const auto vMesh = v.getMesh(); - Field3D result(vMesh); - - result.allocate(); + Field3D result{emptyFrom(f).setLocation(CELL_CENTRE)}; bool vUseUpDown = v.hasYupYdown(); bool fUseUpDown = f.hasYupYdown(); @@ -388,11 +375,10 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg result[i] -= (vval.p >= 0.0) ? vval.p * fval.c : vval.p * fval.p; } - result = vMesh->fromFieldAligned(result, region); + result = vMesh->fromFieldAligned(result, region); } } - result.setLocation(CELL_CENTRE); return result; } @@ -403,8 +389,7 @@ const Field3D Grad_par_LtoC(const Field3D &var) { ASSERT1(var.getLocation() == CELL_YLOW); } - Field3D result(varMesh); - result.allocate(); + Field3D result{emptyFrom(var).setLocation(CELL_CENTRE)}; Coordinates *metric = var.getCoordinates(CELL_CENTRE); @@ -423,14 +408,11 @@ const Field3D Grad_par_LtoC(const Field3D &var) { result = varMesh->fromFieldAligned(result, RGN_NOBNDRY); } - result.setLocation(CELL_CENTRE); return result; } const Field2D Grad_par_LtoC(const Field2D &var) { - const auto varMesh = var.getMesh(); - Field2D result(varMesh); - result.allocate(); + Field2D result{emptyFrom(var).setLocation(CELL_CENTRE)}; Coordinates *metric = var.getCoordinates(CELL_CENTRE); @@ -438,8 +420,6 @@ const Field2D Grad_par_LtoC(const Field2D &var) { result[i] = (var[i.yp()] - var[i]) / (metric->dy[i] * sqrt(metric->g_22[i])); } - result.setLocation(CELL_CENTRE); - return result; } @@ -451,8 +431,7 @@ const Field2D Div_par_LtoC(const Field2D &var) { const Field3D Div_par_LtoC(const Field3D &var) { Mesh* mesh = var.getMesh(); - Field3D result(mesh); - result.allocate(); + Field3D result{emptyFrom(var).setLocation(CELL_CENTRE)}; Coordinates *metric = var.getCoordinates(CELL_CENTRE); @@ -469,8 +448,6 @@ const Field3D Div_par_LtoC(const Field3D &var) { } } - result.setLocation(CELL_CENTRE); - return result; } @@ -482,8 +459,7 @@ const Field2D Div_par_CtoL(const Field2D &var) { const Field3D Div_par_CtoL(const Field3D &var) { Mesh* mesh = var.getMesh(); - Field3D result(mesh); - result.allocate(); + Field3D result{emptyFrom(var).setLocation(CELL_CENTRE)}; Coordinates *metric = var.getCoordinates(CELL_CENTRE); @@ -500,8 +476,6 @@ const Field3D Div_par_CtoL(const Field3D &var) { } } - result.setLocation(CELL_CENTRE); - return result; } @@ -775,7 +749,7 @@ const Field2D bracket(const Field2D &f, const Field2D &g, BRACKET_METHOD method, } ASSERT1(f.getLocation() == g.getLocation() && outloc == f.getLocation()) - Field2D result(f.getMesh()); + Field2D result{emptyFrom(f)}; if( (method == BRACKET_SIMPLE) || (method == BRACKET_ARAKAWA)) { // Use a subset of terms for comparison to BOUT-06 @@ -800,7 +774,7 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, Mesh *mesh = f.getMesh(); - Field3D result(mesh); + Field3D result{emptyFrom(f).setLocation(outloc)}; Coordinates *metric = f.getCoordinates(outloc); @@ -812,9 +786,6 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, if(!solver) throw BoutException("CTU method requires access to the solver"); - result.allocate(); - result.setLocation(outloc); - int ncz = mesh->LocalNz; for(int x=mesh->xstart;x<=mesh->xend;x++) for(int y=mesh->ystart;y<=mesh->yend;y++) { @@ -850,9 +821,6 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, case BRACKET_ARAKAWA: { // Arakawa scheme for perpendicular flow. Here as a test - result.allocate(); - result.setLocation(outloc); - const BoutReal fac = 1.0 / (12 * metric->dz); const int ncz = mesh->LocalNz; @@ -921,8 +889,6 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, break; } case BRACKET_ARAKAWA_OLD: { - result.allocate(); - result.setLocation(outloc); const int ncz = mesh->LocalNz; const BoutReal partialFactor = 1.0/(12 * metric->dz); BOUT_OMP(parallel for) @@ -1022,7 +988,7 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, Mesh *mesh = f.getMesh(); - Field3D result(mesh); + Field3D result{emptyFrom(f).setLocation(outloc)}; Coordinates *metric = f.getCoordinates(outloc); @@ -1043,9 +1009,6 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, // Get current timestep BoutReal dt = solver->getCurrentTimestep(); - result.allocate(); - result.setLocation(outloc); - FieldPerp vx(mesh), vz(mesh); vx.allocate(); vx.setLocation(outloc); @@ -1136,9 +1099,6 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, case BRACKET_ARAKAWA: { // Arakawa scheme for perpendicular flow - result.allocate(); - result.setLocation(outloc); - const int ncz = mesh->LocalNz; const BoutReal partialFactor = 1.0/(12 * metric->dz); @@ -1230,9 +1190,6 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, case BRACKET_ARAKAWA_OLD: { // Arakawa scheme for perpendicular flow - result.allocate(); - result.setLocation(outloc); - const int ncz = mesh->LocalNz; const BoutReal partialFactor = 1.0 / (12 * metric->dz); diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index be0ba12797..c4a9157b08 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -14,7 +14,7 @@ namespace FV { Mesh *mesh = a.getMesh(); - Field3D result(mesh); + Field3D result{emptyFrom(f)}; result = 0.0; Coordinates *coord = f.getCoordinates(); @@ -170,7 +170,8 @@ namespace FV { ASSERT2(Kin.getLocation() == fin.getLocation()); Mesh *mesh = Kin.getMesh(); - Field3D result(0.0, mesh); + Field3D result{emptyFrom(fin)}; + result = 0.; bool use_yup_ydown = (Kin.hasYupYdown() && fin.hasYupYdown()); @@ -233,8 +234,8 @@ namespace FV { Mesh* mesh = d_in.getMesh(); ASSERT1(mesh = f_in.getMesh()); - Field3D result = 0.0; - result.setLocation(f_in.getLocation()); + Field3D result{emptyFrom(f_in)}; + result = 0.0; Coordinates *coord = f_in.getCoordinates(); @@ -283,8 +284,8 @@ namespace FV { } const Field3D D4DY4_Index(const Field3D &f_in, bool bndry_flux) { - Field3D result = 0.0; - result.setLocation(f_in.getLocation()); + Field3D result{emptyFrom(f_in)}; + result = 0.0; Mesh* mesh = f_in.getMesh(); diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 99da8e5a24..b7745ea148 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2402,7 +2402,7 @@ void BoutMesh::addBoundaryPar(BoundaryRegionPar *bndry) { } const Field3D BoutMesh::smoothSeparatrix(const Field3D &f) { - Field3D result(f); + Field3D result{emptyFrom(f)}; if ((ixseps_inner > 0) && (ixseps_inner < nx - 1)) { result.allocate(); if (XPROC(ixseps_inner) == PE_XIND) { diff --git a/src/mesh/interpolation.cxx b/src/mesh/interpolation.cxx index e74630844a..e84dc5e169 100644 --- a/src/mesh/interpolation.cxx +++ b/src/mesh/interpolation.cxx @@ -55,8 +55,7 @@ const Field3D interpolate(const Field2D &f, const Field3D &delta_x) { Mesh *mesh = f.getMesh(); ASSERT1(mesh == delta_x.getMesh()); - Field3D result(mesh); - result.allocate(); + Field3D result{emptyFrom(delta_x)}; // Loop over output grid points for (int jx = 0; jx < mesh->LocalNx; jx++) { diff --git a/src/mesh/interpolation/bilinear.cxx b/src/mesh/interpolation/bilinear.cxx index 3e50000d5a..af1a2fc092 100644 --- a/src/mesh/interpolation/bilinear.cxx +++ b/src/mesh/interpolation/bilinear.cxx @@ -88,8 +88,7 @@ void Bilinear::calcWeights(const Field3D &delta_x, const Field3D &delta_z, const Field3D Bilinear::interpolate(const Field3D& f) const { ASSERT1(f.getMesh() == localmesh); - Field3D f_interp(f.getMesh()); - f_interp.allocate(); + Field3D f_interp{emptyFrom(f)}; for(int x=localmesh->xstart;x<=localmesh->xend;x++) { for(int y=localmesh->ystart; y<=localmesh->yend;y++) { diff --git a/src/mesh/interpolation/hermite_spline.cxx b/src/mesh/interpolation/hermite_spline.cxx index f11daff31e..241e98756a 100644 --- a/src/mesh/interpolation/hermite_spline.cxx +++ b/src/mesh/interpolation/hermite_spline.cxx @@ -115,8 +115,7 @@ void HermiteSpline::calcWeights(const Field3D &delta_x, const Field3D &delta_z, Field3D HermiteSpline::interpolate(const Field3D &f) const { ASSERT1(f.getMesh() == localmesh); - Field3D f_interp(f.getMesh()); - f_interp.allocate(); + Field3D f_interp{emptyFrom(f)}; // Derivatives are used for tension and need to be on dimensionless // coordinates diff --git a/src/mesh/interpolation/lagrange_4pt.cxx b/src/mesh/interpolation/lagrange_4pt.cxx index 80ccfd442b..ffd861fa2c 100644 --- a/src/mesh/interpolation/lagrange_4pt.cxx +++ b/src/mesh/interpolation/lagrange_4pt.cxx @@ -84,8 +84,7 @@ void Lagrange4pt::calcWeights(const Field3D &delta_x, const Field3D &delta_z, Field3D Lagrange4pt::interpolate(const Field3D &f) const { ASSERT1(f.getMesh() == localmesh); - Field3D f_interp(f.getMesh()); - f_interp.allocate(); + Field3D f_interp{emptyFrom(f)}; for (int x = localmesh->xstart; x <= localmesh->xend; x++) { for (int y = localmesh->ystart; y <= localmesh->yend; y++) { diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 2aefaeb2cb..724b4f77f7 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -275,9 +275,7 @@ Field3D FCIMap::integrate(Field3D &f) const { // Cell corner values (x+1/2, z+1/2) Field3D corner = interp_corner->interpolate(f); - Field3D result; - result.allocate(); - result.setLocation(f.getLocation()); + Field3D result{emptyFrom(f)}; int nz = map_mesh.LocalNz; diff --git a/src/physics/smoothing.cxx b/src/physics/smoothing.cxx index 77326e2cb8..abe7423842 100644 --- a/src/physics/smoothing.cxx +++ b/src/physics/smoothing.cxx @@ -45,7 +45,7 @@ const Field3D smooth_x(const Field3D &f) { TRACE("smooth_x"); Mesh *mesh = f.getMesh(); - Field3D result(mesh); + Field3D result{emptyFrom(f)}; result.allocate(); // Copy boundary region @@ -73,7 +73,7 @@ const Field3D smooth_x(const Field3D &f) { const Field3D smooth_y(const Field3D &f) { TRACE("smooth_y"); Mesh *mesh = f.getMesh(); - Field3D result(mesh); + Field3D result{emptyFrom(f)}; result.allocate(); // Copy boundary region @@ -126,8 +126,7 @@ const Field2D averageX(const Field2D &f) { input[y] /= (mesh->xend - mesh->xstart + 1); } - Field2D r(mesh); - r.allocate(); + Field2D r{emptyFrom(f)}; MPI_Comm comm_x = mesh->getXcomm(); @@ -186,8 +185,7 @@ const Field3D averageX(const Field3D &f) { input(y, z) /= (mesh->xend - mesh->xstart + 1); } - Field3D r(mesh); - r.allocate(); + Field3D r{emptyFrom(f)}; MPI_Comm comm_x = mesh->getXcomm(); @@ -231,8 +229,7 @@ const Field2D averageY(const Field2D &f) { input[x] /= (mesh->yend - mesh->ystart + 1); } - Field2D r(mesh); - r.allocate(); + Field2D r{emptyFrom(f)}; /// NOTE: This only works if there are no branch-cuts MPI_Comm comm_inner = mesh->getYcomm(0); @@ -277,8 +274,7 @@ const Field3D averageY(const Field3D &f) { input(x, z) /= (mesh->yend - mesh->ystart + 1); } - Field3D r(mesh); - r.allocate(); + Field3D r{emptyFrom(f)}; /// NOTE: This only works if there are no branch-cuts MPI_Comm comm_inner = mesh->getYcomm(0); @@ -340,8 +336,7 @@ BoutReal Vol_Integral(const Field2D &var) { const Field3D smoothXY(const Field3D &f) { Mesh *mesh = f.getMesh(); - Field3D result(mesh); - result.allocate(); + Field3D result{emptyFrom(f)}; for(int x=2;xLocalNx-2;x++) for(int y=2;yLocalNy-2;y++) @@ -387,8 +382,7 @@ const Field3D nl_filter_x(const Field3D &f, BoutReal w) { TRACE("nl_filter_x( Field3D )"); Mesh *mesh = f.getMesh(); - Field3D result(mesh); - result.allocate(); + Field3D result{emptyFrom(f)}; rvec v(mesh->LocalNx); for (int jy=0;jyLocalNy;jy++) { @@ -410,8 +404,7 @@ const Field3D nl_filter_y(const Field3D &f, BoutReal w) { TRACE("nl_filter_x( Field3D )"); Mesh *mesh = f.getMesh(); - Field3D result(mesh); - result.allocate(); + Field3D result{emptyFrom(f)}; rvec v(mesh->LocalNy); // Temporary array @@ -438,8 +431,7 @@ const Field3D nl_filter_z(const Field3D &fs, BoutReal w) { TRACE("nl_filter_z( Field3D )"); Mesh *mesh = fs.getMesh(); - Field3D result(mesh); - result.allocate(); + Field3D result{emptyFrom(fs)}; rvec v(mesh->LocalNz); diff --git a/src/physics/sourcex.cxx b/src/physics/sourcex.cxx index 1a549e50dc..3fc10228f3 100644 --- a/src/physics/sourcex.cxx +++ b/src/physics/sourcex.cxx @@ -21,7 +21,7 @@ BoutReal TanH(BoutReal a) { const Field2D source_tanhx(const Field2D &f, BoutReal swidth, BoutReal slength) { Mesh* localmesh = f.getMesh(); - Field2D result(localmesh); + Field2D result{emptyFrom(f)}; result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary @@ -41,7 +41,7 @@ const Field2D source_tanhx(const Field2D &f, BoutReal swidth, BoutReal slength) const Field2D source_expx2(const Field2D &f, BoutReal swidth, BoutReal slength) { Mesh* localmesh = f.getMesh(); - Field2D result(localmesh); + Field2D result{emptyFrom(f)}; result.allocate(); @@ -63,7 +63,7 @@ const Field3D sink_tanhx(const Field2D &UNUSED(f0), const Field3D &f, BoutReal s BoutReal slength, bool UNUSED(BoutRealspace)) { Mesh* localmesh = f.getMesh(); - Field3D result(localmesh); + Field3D result{emptyFrom(f)}; result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary @@ -85,7 +85,7 @@ const Field3D mask_x(const Field3D &f, bool UNUSED(BoutRealspace)) { Mesh* localmesh = f.getMesh(); - Field3D result(localmesh); + Field3D result{emptyFrom(f)}; result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary @@ -110,7 +110,7 @@ const Field3D sink_tanhxl(const Field2D &UNUSED(f0), const Field3D &f, BoutReal Mesh* localmesh = f.getMesh(); - Field3D result(localmesh); + Field3D result{emptyFrom(f)}; result.allocate(); @@ -134,7 +134,7 @@ const Field3D sink_tanhxr(const Field2D &UNUSED(f0), const Field3D &f, BoutReal Mesh* localmesh = f.getMesh(); - Field3D result(localmesh); + Field3D result{emptyFrom(f)}; result.allocate(); BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -156,7 +156,7 @@ const Field3D buff_x(const Field3D &f, bool UNUSED(BoutRealspace)) { Mesh* localmesh = f.getMesh(); - Field3D result(localmesh); + Field3D result{emptyFrom(f)}; result.allocate(); const BoutReal dampl = 1.e0; diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 4e242cf519..5cd81be85c 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -165,7 +165,8 @@ void Solver::add(Field2D &v, const std::string name) { if (mms) { // Allocate storage for error variable - d.MMS_err = new Field2D(0.0); + d.MMS_err = new Field2D{emptyFrom(v)}; + (*d.MMS_err) = 0.; } else { d.MMS_err = nullptr; } @@ -227,7 +228,7 @@ void Solver::add(Field3D &v, const std::string name) { } if (mms) { - d.MMS_err = new Field3D(v.getMesh()); + d.MMS_err = new Field3D{emptyFrom(v)}; (*d.MMS_err) = 0.0; } else { d.MMS_err = nullptr; diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 10b94f879d..64286b09e7 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -229,8 +229,8 @@ const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc, const std::string &method const Field2D D2DZ2(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), REGION UNUSED(region)) { - auto tmp = Field2D(0., f.getMesh()); - tmp.setLocation(f.getLocation()); + Field2D tmp{emptyFrom(f)}; + tmp = 0.; return tmp; } @@ -300,8 +300,8 @@ const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, const std::string &metho const Field2D D2DXDZ(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), REGION UNUSED(region)) { - auto tmp = Field2D(0., f.getMesh()); - tmp.setLocation(f.getLocation()); + Field2D tmp{emptyFrom(f)}; + tmp = 0.; return tmp; } @@ -331,8 +331,8 @@ const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, const std::string &metho const Field2D D2DYDZ(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), REGION UNUSED(region)) { - auto tmp = Field2D(0., f.getMesh()); - tmp.setLocation(f.getLocation()); + Field2D tmp{emptyFrom(f)}; + tmp = 0.; return tmp; } @@ -340,7 +340,7 @@ const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, MAYBE_UNUSED(const std::string& method), REGION UNUSED(region)) { Coordinates *coords = f.getCoordinates(outloc); - Field3D result(f.getMesh()); + Field3D result{emptyFrom(f)}; ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); result.allocate(); result.setLocation(f.getLocation()); @@ -403,22 +403,22 @@ const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const st // special case where both are 2D const Field2D VDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), REGION UNUSED(region)) { - auto tmp = Field2D(0., f.getMesh()); if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } - tmp.setLocation(outloc); + Field2D tmp{emptyFrom(f).setLocation(outloc)}; + tmp = 0.; return tmp; } // Note that this is zero because no compression is included const Field2D VDDZ(const Field3D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), REGION UNUSED(region)) { - auto tmp = Field2D(0., f.getMesh()); if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } - tmp.setLocation(outloc); + Field2D tmp{emptyFrom(f).setLocation(outloc)}; + tmp = 0.; return tmp; } @@ -457,11 +457,11 @@ const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const st const Field2D FDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), REGION UNUSED(region)) { - auto tmp = Field2D(0., f.getMesh()); if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } - tmp.setLocation(outloc); + Field2D tmp{emptyFrom(f).setLocation(outloc)}; + tmp = 0.; return tmp; } From f9bab0e626d3b0f7b7273e86bd661cfff733f1cd Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Feb 2019 13:55:58 +0000 Subject: [PATCH 0937/1783] Use fieldsCompatible for ASSERT1 checks Replaces separate checks of fieldmesh, location, etc. of input Fields. --- include/bout/fv_ops.hxx | 9 +- src/field/field2d.cxx | 3 +- src/field/field3d.cxx | 8 +- src/field/fieldperp.cxx | 16 +- src/field/gen_fieldops.jinja | 28 +-- src/field/generated_fieldops.cxx | 384 ++++--------------------------- src/field/where.cxx | 22 ++ src/mesh/difops.cxx | 22 +- src/mesh/fv_ops.cxx | 3 +- src/solver/solver.cxx | 5 +- 10 files changed, 96 insertions(+), 404 deletions(-) diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index a9d0f6f91f..e5bc6934ce 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -181,11 +181,10 @@ namespace FV { const Field3D Div_par(const Field3D &f_in, const Field3D &v_in, const Field3D &wave_speed, bool fixflux=true) { - ASSERT2(f_in.getLocation() == v_in.getLocation()); + ASSERT1(fieldsCompatible(f_in, v_in)); + ASSERT1(fieldsCompatible(f_in, wave_speed)); Mesh* mesh = f_in.getMesh(); - ASSERT1(mesh == v_in.getMesh()); - ASSERT1(mesh == wave_speed.getMesh()); CellEdges cellboundary; @@ -345,10 +344,10 @@ namespace FV { */ template const Field3D Div_f_v(const Field3D &n_in, const Vector3D &v, bool bndry_flux) { - ASSERT2(n_in.getLocation() == v.getLocation()); + ASSERT1(n_in.getLocation() == v.getLocation()); + ASSERT1(fieldsCompatible(n_in, v.x)); Mesh* mesh = n_in.getMesh(); - ASSERT1(mesh == v.x.getMesh()); CellEdges cellboundary; diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 529b74e25f..077d3b83d2 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -439,10 +439,9 @@ Field2D pow(const Field2D &lhs, const Field2D &rhs, REGION rgn) { // Check if the inputs are allocated checkData(lhs); checkData(rhs); - ASSERT1(lhs.getLocation() == rhs.getLocation()); + ASSERT1(fieldsCompatible(lhs, rhs)); // Define and allocate the output result - ASSERT1(lhs.getMesh() == rhs.getMesh()); Field2D result{emptyFrom(lhs)}; BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index ae9723f94e..7daba4863e 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -272,13 +272,12 @@ Field3D & Field3D::operator=(const Field2D &rhs) { void Field3D::operator=(const FieldPerp &rhs) { TRACE("Field3D = FieldPerp"); - ASSERT1(getMesh() == rhs.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); /// Check that the data is allocated ASSERT1(rhs.isAllocated()); /// Make sure there's a unique array to copy data into allocate(); - ASSERT1(fieldsCompatible(*this, rhs)); /// Copy data BOUT_FOR(i, rhs.getRegion("RGN_ALL")) { (*this)(i, rhs.getIndex()) = rhs[i]; } @@ -587,7 +586,7 @@ Field3D pow(const Field3D &lhs, const Field2D &rhs, REGION rgn) { // Check if the inputs are allocated checkData(lhs); checkData(rhs); - ASSERT1(lhs.getMesh() == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); // Define and allocate the output result Field3D result{emptyFrom(lhs)}; @@ -603,8 +602,7 @@ FieldPerp pow(const Field3D &lhs, const FieldPerp &rhs, REGION rgn) { checkData(lhs); checkData(rhs); - ASSERT1(lhs.getMesh() == rhs.getMesh()); - ASSERT1(lhs.getLocation() == rhs.getLocation()); + ASSERT1(fieldsCompatible(lhs, rhs)); FieldPerp result{rhs.getMesh(), rhs.getLocation(), rhs.getIndex(), rhs.getDirectionX(), rhs.getDirectionY(), rhs.getDirectionZ()}; diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 99db153dd6..b6f2a724e6 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -109,8 +109,7 @@ FieldPerp & FieldPerp::operator=(const BoutReal rhs) { #define FPERP_OP_FPERP(op, bop) \ FieldPerp& FieldPerp::operator op(const FieldPerp& rhs) { \ - ASSERT1(getMesh() == rhs.getMesh()); \ - ASSERT1(location == rhs.getLocation()); \ + ASSERT1(fieldsCompatible(*this, rhs)); \ if (data.unique()) { \ checkData(rhs); \ /* Only reference to the data */ \ @@ -130,8 +129,7 @@ FPERP_OP_FPERP(/=, /); #define FPERP_OP_FIELD(op, bop, ftype) \ FieldPerp& FieldPerp::operator op(const ftype& rhs) { \ - ASSERT1(getMesh() == rhs.getMesh()); \ - ASSERT1(location == rhs.getLocation()); \ + ASSERT1(fieldsCompatible(*this, rhs)); \ if (data.unique()) { \ checkData(*this); \ checkData(rhs); \ @@ -193,8 +191,7 @@ FieldPerp operator-(const FieldPerp &f) { return -1.0 * f; } // Operator on FieldPerp and another field #define FPERP_FPERP_OP_FPERP(op) \ const FieldPerp operator op(const FieldPerp& lhs, const FieldPerp& rhs) { \ - ASSERT1(lhs.getMesh() == rhs.getMesh()); \ - ASSERT1(rhs.getLocation() == rhs.getLocation()); \ + ASSERT1(fieldsCompatible(lhs, rhs)); \ checkData(lhs); \ checkData(rhs); \ FieldPerp result{emptyFrom(lhs)}; \ @@ -212,8 +209,7 @@ FPERP_FPERP_OP_FPERP(/); // Operator on FieldPerp and another field #define FPERP_FPERP_OP_FIELD(op, ftype) \ const FieldPerp operator op(const FieldPerp& lhs, const ftype& rhs) { \ - ASSERT1(lhs.getMesh() == rhs.getMesh()); \ - ASSERT1(rhs.getLocation() == rhs.getLocation()); \ + ASSERT1(fieldsCompatible(lhs, rhs)); \ checkData(lhs); \ checkData(rhs); \ FieldPerp result{emptyFrom(lhs)}; \ @@ -422,9 +418,7 @@ FieldPerp pow(const FieldPerp &lhs, const FieldPerp &rhs, REGION rgn) { checkData(rhs); // Define and allocate the output result - ASSERT1(lhs.getMesh() == rhs.getMesh()); - ASSERT1(lhs.getIndex() == rhs.getIndex()); - ASSERT1(lhs.getLocation() == rhs.getLocation()); + ASSERT1(fieldsCompatible(lhs, rhs)); FieldPerp result{emptyFrom(lhs)}; BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } diff --git a/src/field/gen_fieldops.jinja b/src/field/gen_fieldops.jinja index dbe27111d7..2b67921e85 100644 --- a/src/field/gen_fieldops.jinja +++ b/src/field/gen_fieldops.jinja @@ -1,19 +1,7 @@ // Provide the C++ wrapper for {{operator_name}} of {{lhs}} and {{rhs}} {{out}} operator{{operator}}(const {{lhs.passByReference}}, const {{rhs.passByReference}}) { - {% if ((lhs in ["Field3D", "Field2D"]) and (rhs in ["Field3D", "Field2D"])) %} -#if CHECK > 0 - if ({{lhs.name}}.getLocation() != {{rhs.name}}.getLocation()) { - throw BoutException( - "Error in operator{{operator}}({{lhs}}, {{rhs}}): fields at different locations. lhs is at %s, rhs is at %s!", - strLocation({{lhs.name}}.getLocation()), strLocation({{rhs.name}}.getLocation())); - } -#endif - {% endif %} - - Mesh *localmesh = {{lhs.name if lhs.field_type != "BoutReal" else rhs.name}}.getMesh(); - {% if lhs != "BoutReal" and rhs != "BoutReal" %} - ASSERT1(localmesh == {{rhs.name}}.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); {% endif %} {% if lhs.field_type == out.field_type %} @@ -25,6 +13,8 @@ checkData({{rhs.name}}); {% if (out == "Field3D") and ((lhs == "Field2D") or (rhs =="Field2D")) %} + Mesh *localmesh = {{lhs.name if lhs.field_type != "BoutReal" else rhs.name}}.getMesh(); + {% if (lhs == "Field2D") %} {{region_loop}}({{index_var}}, {{lhs.name}}.getRegion({{region_name}})) { {% else %} @@ -57,18 +47,8 @@ // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - {% if ((lhs in ["Field3D", "Field2D"]) and (rhs in ["Field3D", "Field2D"])) %} -#if CHECK > 0 - if (this->getLocation() != rhs.getLocation()) { - throw BoutException( - "Error in {{lhs}}::operator{{operator}}=({{rhs}}): fields at different locations. lhs is at %s, rhs is at %s!", - strLocation(this->getLocation()), strLocation({{rhs.name}}.getLocation())); - } -#endif - {% endif %} - {% if lhs != "BoutReal" and rhs != "BoutReal" %} - ASSERT1(fieldmesh == {{rhs.name}}.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); {% endif %} checkData(*this); diff --git a/src/field/generated_fieldops.cxx b/src/field/generated_fieldops.cxx index efc1f3ef77..c009bb5d7c 100644 --- a/src/field/generated_fieldops.cxx +++ b/src/field/generated_fieldops.cxx @@ -8,17 +8,7 @@ // Provide the C++ wrapper for multiplication of Field3D and Field3D Field3D operator*(const Field3D& lhs, const Field3D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator*(Field3D, Field3D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -37,17 +27,7 @@ Field3D& Field3D::operator*=(const Field3D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - -#if CHECK > 0 - if (this->getLocation() != rhs.getLocation()) { - throw BoutException("Error in Field3D::operator*=(Field3D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(this->getLocation()), - strLocation(rhs.getLocation())); - } -#endif - - ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -64,17 +44,7 @@ Field3D& Field3D::operator*=(const Field3D& rhs) { // Provide the C++ wrapper for division of Field3D and Field3D Field3D operator/(const Field3D& lhs, const Field3D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator/(Field3D, Field3D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -93,17 +63,7 @@ Field3D& Field3D::operator/=(const Field3D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - -#if CHECK > 0 - if (this->getLocation() != rhs.getLocation()) { - throw BoutException("Error in Field3D::operator/=(Field3D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(this->getLocation()), - strLocation(rhs.getLocation())); - } -#endif - - ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -120,17 +80,7 @@ Field3D& Field3D::operator/=(const Field3D& rhs) { // Provide the C++ wrapper for addition of Field3D and Field3D Field3D operator+(const Field3D& lhs, const Field3D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator+(Field3D, Field3D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -149,17 +99,7 @@ Field3D& Field3D::operator+=(const Field3D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - -#if CHECK > 0 - if (this->getLocation() != rhs.getLocation()) { - throw BoutException("Error in Field3D::operator+=(Field3D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(this->getLocation()), - strLocation(rhs.getLocation())); - } -#endif - - ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -176,17 +116,7 @@ Field3D& Field3D::operator+=(const Field3D& rhs) { // Provide the C++ wrapper for subtraction of Field3D and Field3D Field3D operator-(const Field3D& lhs, const Field3D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator-(Field3D, Field3D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -205,17 +135,7 @@ Field3D& Field3D::operator-=(const Field3D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - -#if CHECK > 0 - if (this->getLocation() != rhs.getLocation()) { - throw BoutException("Error in Field3D::operator-=(Field3D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(this->getLocation()), - strLocation(rhs.getLocation())); - } -#endif - - ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -232,22 +152,14 @@ Field3D& Field3D::operator-=(const Field3D& rhs) { // Provide the C++ wrapper for multiplication of Field3D and Field2D Field3D operator*(const Field3D& lhs, const Field2D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator*(Field3D, Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); + Mesh* localmesh = lhs.getMesh(); + BOUT_FOR(index, rhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { @@ -264,17 +176,7 @@ Field3D& Field3D::operator*=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - -#if CHECK > 0 - if (this->getLocation() != rhs.getLocation()) { - throw BoutException("Error in Field3D::operator*=(Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(this->getLocation()), - strLocation(rhs.getLocation())); - } -#endif - - ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -296,22 +198,14 @@ Field3D& Field3D::operator*=(const Field2D& rhs) { // Provide the C++ wrapper for division of Field3D and Field2D Field3D operator/(const Field3D& lhs, const Field2D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator/(Field3D, Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); + Mesh* localmesh = lhs.getMesh(); + BOUT_FOR(index, rhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); const auto tmp = 1.0 / rhs[index]; @@ -329,17 +223,7 @@ Field3D& Field3D::operator/=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - -#if CHECK > 0 - if (this->getLocation() != rhs.getLocation()) { - throw BoutException("Error in Field3D::operator/=(Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(this->getLocation()), - strLocation(rhs.getLocation())); - } -#endif - - ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -362,22 +246,14 @@ Field3D& Field3D::operator/=(const Field2D& rhs) { // Provide the C++ wrapper for addition of Field3D and Field2D Field3D operator+(const Field3D& lhs, const Field2D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator+(Field3D, Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); + Mesh* localmesh = lhs.getMesh(); + BOUT_FOR(index, rhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { @@ -394,17 +270,7 @@ Field3D& Field3D::operator+=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - -#if CHECK > 0 - if (this->getLocation() != rhs.getLocation()) { - throw BoutException("Error in Field3D::operator+=(Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(this->getLocation()), - strLocation(rhs.getLocation())); - } -#endif - - ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -426,22 +292,14 @@ Field3D& Field3D::operator+=(const Field2D& rhs) { // Provide the C++ wrapper for subtraction of Field3D and Field2D Field3D operator-(const Field3D& lhs, const Field2D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator-(Field3D, Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); + Mesh* localmesh = lhs.getMesh(); + BOUT_FOR(index, rhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { @@ -458,17 +316,7 @@ Field3D& Field3D::operator-=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - -#if CHECK > 0 - if (this->getLocation() != rhs.getLocation()) { - throw BoutException("Error in Field3D::operator-=(Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(this->getLocation()), - strLocation(rhs.getLocation())); - } -#endif - - ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -491,8 +339,6 @@ Field3D& Field3D::operator-=(const Field2D& rhs) { // Provide the C++ wrapper for multiplication of Field3D and BoutReal Field3D operator*(const Field3D& lhs, const BoutReal rhs) { - Mesh* localmesh = lhs.getMesh(); - Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -525,8 +371,6 @@ Field3D& Field3D::operator*=(const BoutReal rhs) { // Provide the C++ wrapper for division of Field3D and BoutReal Field3D operator/(const Field3D& lhs, const BoutReal rhs) { - Mesh* localmesh = lhs.getMesh(); - Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -559,8 +403,6 @@ Field3D& Field3D::operator/=(const BoutReal rhs) { // Provide the C++ wrapper for addition of Field3D and BoutReal Field3D operator+(const Field3D& lhs, const BoutReal rhs) { - Mesh* localmesh = lhs.getMesh(); - Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -593,8 +435,6 @@ Field3D& Field3D::operator+=(const BoutReal rhs) { // Provide the C++ wrapper for subtraction of Field3D and BoutReal Field3D operator-(const Field3D& lhs, const BoutReal rhs) { - Mesh* localmesh = lhs.getMesh(); - Field3D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -626,22 +466,14 @@ Field3D& Field3D::operator-=(const BoutReal rhs) { // Provide the C++ wrapper for multiplication of Field2D and Field3D Field3D operator*(const Field2D& lhs, const Field3D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator*(Field2D, Field3D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); + Mesh* localmesh = lhs.getMesh(); + BOUT_FOR(index, lhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { @@ -655,22 +487,14 @@ Field3D operator*(const Field2D& lhs, const Field3D& rhs) { // Provide the C++ wrapper for division of Field2D and Field3D Field3D operator/(const Field2D& lhs, const Field3D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator/(Field2D, Field3D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); + Mesh* localmesh = lhs.getMesh(); + BOUT_FOR(index, lhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { @@ -684,22 +508,14 @@ Field3D operator/(const Field2D& lhs, const Field3D& rhs) { // Provide the C++ wrapper for addition of Field2D and Field3D Field3D operator+(const Field2D& lhs, const Field3D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator+(Field2D, Field3D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); + Mesh* localmesh = lhs.getMesh(); + BOUT_FOR(index, lhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { @@ -713,22 +529,14 @@ Field3D operator+(const Field2D& lhs, const Field3D& rhs) { // Provide the C++ wrapper for subtraction of Field2D and Field3D Field3D operator-(const Field2D& lhs, const Field3D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator-(Field2D, Field3D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); + Mesh* localmesh = lhs.getMesh(); + BOUT_FOR(index, lhs.getRegion("RGN_ALL")) { const auto base_ind = localmesh->ind2Dto3D(index); for (int jz = 0; jz < localmesh->LocalNz; ++jz) { @@ -742,17 +550,7 @@ Field3D operator-(const Field2D& lhs, const Field3D& rhs) { // Provide the C++ wrapper for multiplication of Field2D and Field2D Field2D operator*(const Field2D& lhs, const Field2D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator*(Field2D, Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -771,17 +569,7 @@ Field2D& Field2D::operator*=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - -#if CHECK > 0 - if (this->getLocation() != rhs.getLocation()) { - throw BoutException("Error in Field2D::operator*=(Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(this->getLocation()), - strLocation(rhs.getLocation())); - } -#endif - - ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -798,17 +586,7 @@ Field2D& Field2D::operator*=(const Field2D& rhs) { // Provide the C++ wrapper for division of Field2D and Field2D Field2D operator/(const Field2D& lhs, const Field2D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator/(Field2D, Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -827,17 +605,7 @@ Field2D& Field2D::operator/=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - -#if CHECK > 0 - if (this->getLocation() != rhs.getLocation()) { - throw BoutException("Error in Field2D::operator/=(Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(this->getLocation()), - strLocation(rhs.getLocation())); - } -#endif - - ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -854,17 +622,7 @@ Field2D& Field2D::operator/=(const Field2D& rhs) { // Provide the C++ wrapper for addition of Field2D and Field2D Field2D operator+(const Field2D& lhs, const Field2D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator+(Field2D, Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -883,17 +641,7 @@ Field2D& Field2D::operator+=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - -#if CHECK > 0 - if (this->getLocation() != rhs.getLocation()) { - throw BoutException("Error in Field2D::operator+=(Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(this->getLocation()), - strLocation(rhs.getLocation())); - } -#endif - - ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -910,17 +658,7 @@ Field2D& Field2D::operator+=(const Field2D& rhs) { // Provide the C++ wrapper for subtraction of Field2D and Field2D Field2D operator-(const Field2D& lhs, const Field2D& rhs) { -#if CHECK > 0 - if (lhs.getLocation() != rhs.getLocation()) { - throw BoutException("Error in operator-(Field2D, Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(lhs.getLocation()), strLocation(rhs.getLocation())); - } -#endif - - Mesh* localmesh = lhs.getMesh(); - - ASSERT1(localmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(lhs, rhs)); Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -939,17 +677,7 @@ Field2D& Field2D::operator-=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - -#if CHECK > 0 - if (this->getLocation() != rhs.getLocation()) { - throw BoutException("Error in Field2D::operator-=(Field2D): fields at different " - "locations. lhs is at %s, rhs is at %s!", - strLocation(this->getLocation()), - strLocation(rhs.getLocation())); - } -#endif - - ASSERT1(fieldmesh == rhs.getMesh()); + ASSERT1(fieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -967,8 +695,6 @@ Field2D& Field2D::operator-=(const Field2D& rhs) { // Provide the C++ wrapper for multiplication of Field2D and BoutReal Field2D operator*(const Field2D& lhs, const BoutReal rhs) { - Mesh* localmesh = lhs.getMesh(); - Field2D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -1001,8 +727,6 @@ Field2D& Field2D::operator*=(const BoutReal rhs) { // Provide the C++ wrapper for division of Field2D and BoutReal Field2D operator/(const Field2D& lhs, const BoutReal rhs) { - Mesh* localmesh = lhs.getMesh(); - Field2D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -1035,8 +759,6 @@ Field2D& Field2D::operator/=(const BoutReal rhs) { // Provide the C++ wrapper for addition of Field2D and BoutReal Field2D operator+(const Field2D& lhs, const BoutReal rhs) { - Mesh* localmesh = lhs.getMesh(); - Field2D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -1069,8 +791,6 @@ Field2D& Field2D::operator+=(const BoutReal rhs) { // Provide the C++ wrapper for subtraction of Field2D and BoutReal Field2D operator-(const Field2D& lhs, const BoutReal rhs) { - Mesh* localmesh = lhs.getMesh(); - Field2D result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); @@ -1103,8 +823,6 @@ Field2D& Field2D::operator-=(const BoutReal rhs) { // Provide the C++ wrapper for multiplication of BoutReal and Field3D Field3D operator*(const BoutReal lhs, const Field3D& rhs) { - Mesh* localmesh = rhs.getMesh(); - Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); @@ -1118,8 +836,6 @@ Field3D operator*(const BoutReal lhs, const Field3D& rhs) { // Provide the C++ wrapper for division of BoutReal and Field3D Field3D operator/(const BoutReal lhs, const Field3D& rhs) { - Mesh* localmesh = rhs.getMesh(); - Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); @@ -1133,8 +849,6 @@ Field3D operator/(const BoutReal lhs, const Field3D& rhs) { // Provide the C++ wrapper for addition of BoutReal and Field3D Field3D operator+(const BoutReal lhs, const Field3D& rhs) { - Mesh* localmesh = rhs.getMesh(); - Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); @@ -1148,8 +862,6 @@ Field3D operator+(const BoutReal lhs, const Field3D& rhs) { // Provide the C++ wrapper for subtraction of BoutReal and Field3D Field3D operator-(const BoutReal lhs, const Field3D& rhs) { - Mesh* localmesh = rhs.getMesh(); - Field3D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); @@ -1163,8 +875,6 @@ Field3D operator-(const BoutReal lhs, const Field3D& rhs) { // Provide the C++ wrapper for multiplication of BoutReal and Field2D Field2D operator*(const BoutReal lhs, const Field2D& rhs) { - Mesh* localmesh = rhs.getMesh(); - Field2D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); @@ -1178,8 +888,6 @@ Field2D operator*(const BoutReal lhs, const Field2D& rhs) { // Provide the C++ wrapper for division of BoutReal and Field2D Field2D operator/(const BoutReal lhs, const Field2D& rhs) { - Mesh* localmesh = rhs.getMesh(); - Field2D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); @@ -1193,8 +901,6 @@ Field2D operator/(const BoutReal lhs, const Field2D& rhs) { // Provide the C++ wrapper for addition of BoutReal and Field2D Field2D operator+(const BoutReal lhs, const Field2D& rhs) { - Mesh* localmesh = rhs.getMesh(); - Field2D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); @@ -1208,8 +914,6 @@ Field2D operator+(const BoutReal lhs, const Field2D& rhs) { // Provide the C++ wrapper for subtraction of BoutReal and Field2D Field2D operator-(const BoutReal lhs, const Field2D& rhs) { - Mesh* localmesh = rhs.getMesh(); - Field2D result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); diff --git a/src/field/where.cxx b/src/field/where.cxx index c0ae43add4..d3408dbd00 100644 --- a/src/field/where.cxx +++ b/src/field/where.cxx @@ -30,6 +30,9 @@ // Versions taking Field2D and returning Field3D const Field3D where(const Field2D &test, const Field3D >0, const Field3D &le0) { + ASSERT1(fieldsCompatible(test, gt0)); + ASSERT1(fieldsCompatible(test, le0)); + Field3D result{emptyFrom(gt0)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -43,6 +46,8 @@ const Field3D where(const Field2D &test, const Field3D >0, const Field3D &le0) } const Field3D where(const Field2D &test, const Field3D >0, BoutReal le0) { + ASSERT1(fieldsCompatible(test, gt0)); + Field3D result{emptyFrom(gt0)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -56,6 +61,8 @@ const Field3D where(const Field2D &test, const Field3D >0, BoutReal le0) { } const Field3D where(const Field2D &test, BoutReal gt0, const Field3D &le0) { + ASSERT1(fieldsCompatible(test, le0)); + Field3D result{emptyFrom(le0)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -70,6 +77,9 @@ const Field3D where(const Field2D &test, BoutReal gt0, const Field3D &le0) { } const Field3D where(const Field2D &test, const Field3D >0, const Field2D &le0) { + ASSERT1(fieldsCompatible(test, gt0)); + ASSERT1(fieldsCompatible(test, le0)); + Field3D result{emptyFrom(gt0)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -84,6 +94,9 @@ const Field3D where(const Field2D &test, const Field3D >0, const Field2D &le0) } const Field3D where(const Field2D &test, const Field2D >0, const Field3D &le0) { + ASSERT1(fieldsCompatible(test, gt0)); + ASSERT1(fieldsCompatible(test, le0)); + Field3D result{emptyFrom(le0)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -101,6 +114,9 @@ const Field3D where(const Field2D &test, const Field2D >0, const Field3D &le0) // Versions taking Field2D and returning Field2D const Field2D where(const Field2D &test, const Field2D >0, const Field2D &le0) { + ASSERT1(fieldsCompatible(test, gt0)); + ASSERT1(fieldsCompatible(test, le0)); + Field2D result{emptyFrom(test)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -115,6 +131,8 @@ const Field2D where(const Field2D &test, const Field2D >0, const Field2D &le0) } const Field2D where(const Field2D &test, const Field2D >0, BoutReal le0) { + ASSERT1(fieldsCompatible(test, gt0)); + Field2D result{emptyFrom(test)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -129,6 +147,8 @@ const Field2D where(const Field2D &test, const Field2D >0, BoutReal le0) { } const Field2D where(const Field2D &test, BoutReal gt0, const Field2D &le0) { + ASSERT1(fieldsCompatible(test, le0)); + Field2D result{emptyFrom(test)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -160,6 +180,8 @@ const Field2D where(const Field2D &test, BoutReal gt0, BoutReal le0) { // Versions taking Field3D and returning Field3D const Field3D where(const Field3D &test, BoutReal gt0, const Field3D &le0) { + ASSERT1(fieldsCompatible(test, le0)); + Field3D result{emptyFrom(test)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index d314e99314..ff7081536e 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -73,8 +73,7 @@ const Field3D Grad_par(const Field3D &var, const std::string &method, CELL_LOC o *******************************************************************************/ const Field3D Grad_parP(const Field3D &apar, const Field3D &f) { - ASSERT1(apar.getMesh() == f.getMesh()); - ASSERT2(apar.getLocation() == f.getLocation()); + ASSERT1(fieldsCompatible(apar, f)); Mesh *mesh = apar.getMesh(); @@ -201,8 +200,7 @@ const Field3D Div_par(const Field3D &f, const std::string &method, CELL_LOC outl } const Field3D Div_par(const Field3D &f, const Field3D &v) { - ASSERT1(f.getMesh() == v.getMesh()); - ASSERT2(v.getLocation() == f.getLocation()); + ASSERT1(fieldsCompatible(f, v)); // Parallel divergence, using velocities at cell boundaries // Note: Not guaranteed to be flux conservative @@ -743,11 +741,11 @@ const Field2D bracket(const Field2D &f, const Field2D &g, BRACKET_METHOD method, CELL_LOC outloc, Solver *UNUSED(solver)) { TRACE("bracket(Field2D, Field2D)"); - ASSERT1(f.getMesh() == g.getMesh()); + ASSERT1(fieldsCompatible(f, g)); if (outloc == CELL_DEFAULT) { outloc = g.getLocation(); } - ASSERT1(f.getLocation() == g.getLocation() && outloc == f.getLocation()) + ASSERT1(outloc == g.getLocation()); Field2D result{emptyFrom(f)}; @@ -766,11 +764,11 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, CELL_LOC outloc, Solver *solver) { TRACE("bracket(Field3D, Field2D)"); - ASSERT1(f.getMesh() == g.getMesh()); + ASSERT1(fieldsCompatible(f, g)); if (outloc == CELL_DEFAULT) { outloc = g.getLocation(); } - ASSERT1(f.getLocation() == g.getLocation() && outloc == f.getLocation()) + ASSERT1(outloc == g.getLocation()); Mesh *mesh = f.getMesh(); @@ -943,11 +941,11 @@ const Field3D bracket(const Field2D &f, const Field3D &g, BRACKET_METHOD method, CELL_LOC outloc, Solver *solver) { TRACE("bracket(Field2D, Field3D)"); - ASSERT1(f.getMesh() == g.getMesh()); + ASSERT1(fieldsCompatible(f, g)); if (outloc == CELL_DEFAULT) { outloc = g.getLocation(); } - ASSERT1(f.getLocation() == g.getLocation() && outloc == f.getLocation()) + ASSERT1(outloc == g.getLocation()) Mesh *mesh = f.getMesh(); @@ -980,11 +978,11 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, CELL_LOC outloc, Solver *solver) { TRACE("Field3D, Field3D"); - ASSERT1(f.getMesh() == g.getMesh()); + ASSERT1(fieldsCompatible(f, g)); if (outloc == CELL_DEFAULT) { outloc = g.getLocation(); } - ASSERT1(f.getLocation() == g.getLocation() && outloc == f.getLocation()) + ASSERT1(outloc == g.getLocation()); Mesh *mesh = f.getMesh(); diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index c4a9157b08..d431da8036 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -229,10 +229,9 @@ namespace FV { } const Field3D D4DY4(const Field3D &d_in, const Field3D &f_in) { - ASSERT2(d_in.getLocation() == f_in.getLocation()); + ASSERT1(fieldsCompatible(d_in, f_in)); Mesh* mesh = d_in.getMesh(); - ASSERT1(mesh = f_in.getMesh()); Field3D result{emptyFrom(f_in)}; result = 0.0; diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 5cd81be85c..765a559018 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -1299,10 +1299,9 @@ void Solver::post_rhs(BoutReal UNUSED(t)) { v.F_var->toContravariant(); } - // Make sure 3D fields are at the correct cell location + // Make sure 3D fields are at the correct cell location, etc. for (MAYBE_UNUSED(const auto& f) : f3d) { - ASSERT1(f.var->getLocation() == f.F_var->getLocation()); - ASSERT1(f.var->getMesh() == f.F_var->getMesh()); + ASSERT1(fieldsCompatible(*f.var, *f.F_var)); } // Apply boundary conditions to the time-derivatives From d8d1ea1b2901903f257285c27639debd74d2f92f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Feb 2019 15:13:50 +0000 Subject: [PATCH 0938/1783] Add option flag to switch off calcYUpDown call in Mesh::communicate() If we only want to use field-aligned parallel derivatives, then we don't need to calculate yup/ydown fields. Therefore add an option mesh:calcyupdown_on_communicate (defaults to true) which if set to false skips the calls to calcYUpDown in Mesh::communicate(). --- include/bout/mesh.hxx | 3 +++ src/mesh/mesh.cxx | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index be6ab6891e..fd0d1ab845 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -822,6 +822,9 @@ protected: /// Mesh options section Options *options{nullptr}; + /// Set whether to call calcYUpDown on all communicated fields (true) or not (false) + bool calcYUpDown_on_communicate{true}; + /// Handles calculation of yup and ydown PTptr transform{nullptr}; diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 30b7afa92f..2460895078 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -31,6 +31,7 @@ Mesh::Mesh(GridDataSource *s, Options* opt) : source(s), options(opt) { /// Get mesh options OPTION(options, StaggerGrids, false); // Stagger grids OPTION(options, maxregionblocksize, MAXREGIONBLOCKSIZE); + OPTION(options, calcYUpDown_on_communicate, true); // Initialise derivatives derivs_init(options); // in index_derivs.cxx for now } @@ -193,8 +194,11 @@ void Mesh::communicate(FieldGroup &g) { wait(h); // Calculate yup and ydown fields for 3D fields - for(const auto& fptr : g.field3d()) - getParallelTransform().calcYUpDown(*fptr); + if (calcYUpDown_on_communicate) { + for(const auto& fptr : g.field3d()) { + getParallelTransform().calcYUpDown(*fptr); + } + } } /// This is a bit of a hack for now to get FieldPerp communications From 752edbdb96c7244cffe7613ed6b62ee051d32d9f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Feb 2019 15:14:47 +0000 Subject: [PATCH 0939/1783] Remove unused variable n3d in petsc.cxx --- src/solver/impls/petsc/petsc.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/solver/impls/petsc/petsc.cxx b/src/solver/impls/petsc/petsc.cxx index c1ae7c8c1d..ed54809ca0 100644 --- a/src/solver/impls/petsc/petsc.cxx +++ b/src/solver/impls/petsc/petsc.cxx @@ -125,7 +125,6 @@ int PetscSolver::init(int NOUT, BoutReal TIMESTEP) { nout = NOUT; tstep = TIMESTEP; - PetscInt n3d = n3Dvars(); // Number of 3D variables PetscInt local_N = getLocalN(); // Number of evolving variables on this processor /********** Get total problem size **********/ From bca4caf5af6c0a2a0d469b2ee1c0cbb193c924d6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Feb 2019 15:24:11 +0000 Subject: [PATCH 0940/1783] Call createDefaultRegions() on new mesh in Field3DTest.MultipleYupYdown --- tests/unit/field/test_field3d.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 0b3ffaaff2..94899497f6 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -256,6 +256,7 @@ TEST_F(Field3DTest, SplitThenMergeYupYDown) { TEST_F(Field3DTest, MultipleYupYdown) { FakeMesh newmesh{3, 5, 7}; newmesh.ystart = 2; + newmesh.createDefaultRegions(); Field3D field{&newmesh}; From e809b51b0227873687b3c30052409e19ba989faa Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 5 Mar 2019 15:49:49 +0000 Subject: [PATCH 0941/1783] Rename Array/Matrix/Tensor::resize -> reallocate --- include/bout/array.hxx | 4 +-- include/cyclic_reduction.hxx | 18 +++++------ include/utils.hxx | 16 +++++----- src/field/field2d.cxx | 2 +- src/field/field3d.cxx | 2 +- src/field/fieldperp.cxx | 2 +- src/field/globalfield.cxx | 2 +- .../laplace/impls/cyclic/cyclic_laplace.cxx | 10 +++--- .../laplace/impls/multigrid/multigrid_alg.cxx | 8 ++--- .../impls/multigrid/multigrid_laplace.cxx | 4 +-- src/invert/laplace/impls/pdd/pdd.cxx | 20 ++++++------ .../laplace/impls/serial_band/serial_band.cxx | 10 +++--- .../laplace/impls/shoot/shoot_laplace.cxx | 10 +++--- src/invert/laplace/impls/spt/spt.cxx | 16 +++++----- src/invert/laplacexy/laplacexy.cxx | 10 +++--- .../impls/cyclic/laplacexz-cyclic.cxx | 16 +++++----- src/mesh/impls/bout/boutmesh.cxx | 32 +++++++++---------- src/mesh/interpolation/bilinear.cxx | 4 +-- src/mesh/interpolation/hermite_spline.cxx | 4 +-- src/mesh/interpolation/lagrange_4pt.cxx | 4 +-- src/solver/impls/euler/euler.cxx | 4 +-- src/solver/impls/imex-bdf2/imex-bdf2.cxx | 8 ++--- src/solver/impls/karniadakis/karniadakis.cxx | 16 +++++----- src/solver/impls/power/power.cxx | 2 +- src/solver/impls/rk3-ssp/rk3-ssp.cxx | 10 +++--- src/solver/impls/rk4/rk4.cxx | 16 +++++----- .../rkgeneric/impls/cashkarp/cashkarp.cxx | 6 ++-- .../rkgeneric/impls/rk4simple/rk4simple.cxx | 6 ++-- .../impls/rkgeneric/impls/rkf34/rkf34.cxx | 6 ++-- .../impls/rkgeneric/impls/rkf45/rkf45.cxx | 6 ++-- src/solver/impls/rkgeneric/rkgeneric.cxx | 6 ++-- src/solver/impls/rkgeneric/rkscheme.cxx | 4 +-- src/solver/impls/slepc/slepc.cxx | 4 +-- tests/integrated/test-cyclic/test_cyclic.cxx | 10 +++--- tests/unit/include/bout/test_array.cxx | 14 ++++---- tests/unit/sys/test_utils.cxx | 12 +++---- 36 files changed, 162 insertions(+), 162 deletions(-) diff --git a/include/bout/array.hxx b/include/bout/array.hxx index 3c8c31a8bd..67dd80823c 100644 --- a/include/bout/array.hxx +++ b/include/bout/array.hxx @@ -146,11 +146,11 @@ public: } /*! - * Resize the array to \p new_size + * Reallocate the array with size = \p new_size * * Note that this invalidates the existing data! */ - void resize(size_type new_size) { + void reallocate(size_type new_size) { release(ptr); ptr = get(new_size); } diff --git a/include/cyclic_reduction.hxx b/include/cyclic_reduction.hxx index e74b4959d7..be0262185e 100644 --- a/include/cyclic_reduction.hxx +++ b/include/cyclic_reduction.hxx @@ -488,8 +488,8 @@ private: sys0 += nsextra; } - coefs.resize(Nsys, 4 * N); - myif.resize(Nsys, 8); + coefs.reallocate(Nsys, 4 * N); + myif.reallocate(Nsys, 8); // Note: The recvbuffer is used to receive data in both stages of the solve: // 1. In the gather step, this processor will receive myns interface equations @@ -498,22 +498,22 @@ private: // from each processor. The number of systems of equations received will // vary from myns to myns+1 (if myproc >= nsextra). // The size of the array reserved is therefore (myns+1) - recvbuffer.resize(nprocs, (myns + 1) * 8); + recvbuffer.reallocate(nprocs, (myns + 1) * 8); // Some interface systems to be solved on this processor // Note that the interface equations are organised by system (myns as first argument) // but communication buffers are organised by processor (nprocs first). - ifcs.resize(myns, 2 * 4 * nprocs); // Coefficients for interface solve + ifcs.reallocate(myns, 2 * 4 * nprocs); // Coefficients for interface solve if (nprocs > 1) { - if2x2.resize(myns, 2 * 4); // 2x2 interface equations on this processor + if2x2.reallocate(myns, 2 * 4); // 2x2 interface equations on this processor } - ifx.resize(myns, 2 * nprocs); // Solution of interface equations - ifp.resize(myns * 2); // Solution to be sent to processor p + ifx.reallocate(myns, 2 * nprocs); // Solution of interface equations + ifp.reallocate(myns * 2); // Solution to be sent to processor p // Each system to be solved on this processor has two interface equations from each // processor - x1.resize(Nsys); - xn.resize(Nsys); + x1.reallocate(Nsys); + xn.reallocate(Nsys); } /// Calculate interface equations diff --git a/include/utils.hxx b/include/utils.hxx index 6825f51be3..98c6138298 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -102,23 +102,23 @@ public: ASSERT2(n1 >= 0); ASSERT2(n2 >= 0); - data.resize(n1 * n2); + data.reallocate(n1 * n2); } Matrix(const Matrix &other) : n1(other.n1), n2(other.n2), data(other.data) { // Prevent copy on write for Matrix data.ensureUnique(); } - /// Resize the Matrix to \p new_size_1 by \p new_size_2 + /// Reallocate the Matrix to shape \p new_size_1 by \p new_size_2 /// /// Note that this invalidates the existing data! - void resize(size_type new_size_1, size_type new_size_2) { + void reallocate(size_type new_size_1, size_type new_size_2) { ASSERT2(new_size_1 >= 0); ASSERT2(new_size_2 >= 0); n1 = new_size_1; n2 = new_size_2; - data.resize(new_size_1 * new_size_2); + data.reallocate(new_size_1 * new_size_2); } Matrix& operator=(const Matrix &other) { @@ -190,17 +190,17 @@ public: ASSERT2(n1 >= 0); ASSERT2(n2 >= 0); ASSERT2(n3 >= 0); - data.resize(n1 * n2 * n3); + data.reallocate(n1 * n2 * n3); } Tensor(const Tensor &other) : n1(other.n1), n2(other.n2), n3(other.n3), data(other.data) { // Prevent copy on write for Tensor data.ensureUnique(); } - /// Resize the Tensor to \p new_size_1 by \p new_size_2 by \p new_size_3 + /// Reallocate the Tensor with shape \p new_size_1 by \p new_size_2 by \p new_size_3 /// /// Note that this invalidates the existing data! - void resize(size_type new_size_1, size_type new_size_2, size_type new_size_3) { + void reallocate(size_type new_size_1, size_type new_size_2, size_type new_size_3) { ASSERT2(new_size_1 >= 0); ASSERT2(new_size_2 >= 0); ASSERT2(new_size_3 >= 0); @@ -208,7 +208,7 @@ public: n1 = new_size_1; n2 = new_size_2; n3 = new_size_3; - data.resize(new_size_1 * new_size_2 * new_size_3); + data.reallocate(new_size_1 * new_size_2 * new_size_3); } Tensor& operator=(const Tensor &other) { diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 77d4c188ca..a966d082b5 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -94,7 +94,7 @@ void Field2D::allocate() { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; } - data.resize(nx*ny); + data.reallocate(nx*ny); #if CHECK > 2 invalidateGuards(*this); #endif diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 0b118f8ed1..b49926e8f8 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -113,7 +113,7 @@ void Field3D::allocate() { ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; } - data.resize(nx*ny*nz); + data.reallocate(nx * ny * nz); #if CHECK > 2 invalidateGuards(*this); #endif diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 29fef94019..1d42b938c3 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -55,7 +55,7 @@ void FieldPerp::allocate() { nx = fieldmesh->LocalNx; nz = fieldmesh->LocalNz; } - data.resize(nx * nz); + data.reallocate(nx * nz); #if CHECK > 2 invalidateGuards(*this); #endif diff --git a/src/field/globalfield.cxx b/src/field/globalfield.cxx index 37cc01f571..a9991c1e65 100644 --- a/src/field/globalfield.cxx +++ b/src/field/globalfield.cxx @@ -16,7 +16,7 @@ GlobalField::GlobalField(Mesh *m, int proc, int xsize, int ysize, int zsize) if(mype == proc) { // Allocate memory - data.resize(nx * ny * nz); + data.reallocate(nx * ny * nz); } } diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index de2e779b8d..88f87629ef 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -74,11 +74,11 @@ LaplaceCyclic::LaplaceCyclic(Options *opt, const CELL_LOC loc, Mesh *mesh_in) int n = xe - xs + 1; // Number of X points on this processor, // including boundaries but not guard cells - a.resize(nmode, n); - b.resize(nmode, n); - c.resize(nmode, n); - xcmplx.resize(nmode, n); - bcmplx.resize(nmode, n); + a.reallocate(nmode, n); + b.reallocate(nmode, n); + c.reallocate(nmode, n); + xcmplx.reallocate(nmode, n); + bcmplx.reallocate(nmode, n); // Create a cyclic reduction object, operating on dcomplex values cr = new CyclicReduce(localmesh->getXcomm(), n); diff --git a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx index a2b9f3038e..1c1d94315e 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx @@ -40,10 +40,10 @@ MultigridAlg::MultigridAlg(int level, int lx, int lz, int gx, int gz, MPI_Comm c if(pcheck > 0) output<<"Construct MG "<LocalNx); + data.bk.reallocate(maxmode + 1, localmesh->LocalNx); // Matrix to be solved - data.avec.resize(maxmode + 1, localmesh->LocalNx); - data.bvec.resize(maxmode + 1, localmesh->LocalNx); - data.cvec.resize(maxmode + 1, localmesh->LocalNx); + data.avec.reallocate(maxmode + 1, localmesh->LocalNx); + data.bvec.reallocate(maxmode + 1, localmesh->LocalNx); + data.cvec.reallocate(maxmode + 1, localmesh->LocalNx); // Working vectors - data.v.resize(maxmode + 1, localmesh->LocalNx); - data.w.resize(maxmode + 1, localmesh->LocalNx); + data.v.reallocate(maxmode + 1, localmesh->LocalNx); + data.w.reallocate(maxmode + 1, localmesh->LocalNx); // Result - data.xk.resize(maxmode + 1, localmesh->LocalNx); + data.xk.reallocate(maxmode + 1, localmesh->LocalNx); // Communication buffers. Space for 2 complex values for each kz - data.snd.resize(4 * (maxmode + 1)); - data.rcv.resize(4 * (maxmode + 1)); + data.snd.reallocate(4 * (maxmode + 1)); + data.rcv.reallocate(4 * (maxmode + 1)); - data.y2i.resize(maxmode + 1); + data.y2i.reallocate(maxmode + 1); } /// Take FFTs of data diff --git a/src/invert/laplace/impls/serial_band/serial_band.cxx b/src/invert/laplace/impls/serial_band/serial_band.cxx index 83b7c73394..a96e405157 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.cxx +++ b/src/invert/laplace/impls/serial_band/serial_band.cxx @@ -53,8 +53,8 @@ LaplaceSerialBand::LaplaceSerialBand(Options *opt, const CELL_LOC loc, Mesh *mes // Allocate memory int ncz = localmesh->LocalNz; - bk.resize(localmesh->LocalNx, ncz / 2 + 1); - bk1d.resize(localmesh->LocalNx); + bk.reallocate(localmesh->LocalNx, ncz / 2 + 1); + bk1d.reallocate(localmesh->LocalNx); //Initialise bk to 0 as we only visit 0<= kz <= maxmode in solve for(int kz=maxmode+1; kz < ncz/2 + 1; kz++){ @@ -63,8 +63,8 @@ LaplaceSerialBand::LaplaceSerialBand(Options *opt, const CELL_LOC loc, Mesh *mes } } - xk.resize(localmesh->LocalNx, ncz / 2 + 1); - xk1d.resize(localmesh->LocalNx); + xk.reallocate(localmesh->LocalNx, ncz / 2 + 1); + xk1d.reallocate(localmesh->LocalNx); // Initialise xk to 0 as we only visit 0<= kz <= maxmode in solve for (int kz = maxmode + 1; kz < ncz / 2 + 1; kz++) { @@ -73,7 +73,7 @@ LaplaceSerialBand::LaplaceSerialBand(Options *opt, const CELL_LOC loc, Mesh *mes } } - A.resize(localmesh->LocalNx, 5); + A.reallocate(localmesh->LocalNx, 5); } const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b) { diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.cxx b/src/invert/laplace/impls/shoot/shoot_laplace.cxx index 306b35024f..0fb88bc69f 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.cxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.cxx @@ -54,9 +54,9 @@ LaplaceShoot::LaplaceShoot(Options *opt, const CELL_LOC loc, Mesh *mesh_in) // Allocate memory int size = (localmesh->LocalNz)/2 + 1; - km.resize(size); - kc.resize(size); - kp.resize(size); + km.reallocate(size); + kc.reallocate(size); + kp.reallocate(size); for(int i=0;iLocalNz; - dc1d.resize(ncz / 2 + 1); + dc1d.reallocate(ncz / 2 + 1); } LaplaceSPT::~LaplaceSPT() { @@ -511,16 +511,16 @@ void LaplaceSPT::finish(SPT_data &data, FieldPerp &x) { // SPT_data helper class void LaplaceSPT::SPT_data::allocate(int mm, int nx) { - bk.resize(mm, nx); - xk.resize(mm, nx); + bk.reallocate(mm, nx); + xk.reallocate(mm, nx); - gam.resize(mm, nx); + gam.reallocate(mm, nx); // Matrix to be solved - avec.resize(mm, nx); - bvec.resize(mm, nx); - cvec.resize(mm, nx); + avec.reallocate(mm, nx); + bvec.reallocate(mm, nx); + cvec.reallocate(mm, nx); - buffer.resize(4 * mm); + buffer.reallocate(4 * mm); } diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index f7a840a4f9..88c661c76c 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -87,11 +87,11 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) nloc = xend - xstart + 1; // Number of X points on this processor nsys = localmesh->yend - localmesh->ystart + 1; // Number of separate Y slices - acoef.resize(nsys, nloc); - bcoef.resize(nsys, nloc); - ccoef.resize(nsys, nloc); - xvals.resize(nsys, nloc); - bvals.resize(nsys, nloc); + acoef.reallocate(nsys, nloc); + bcoef.reallocate(nsys, nloc); + ccoef.reallocate(nsys, nloc); + xvals.reallocate(nsys, nloc); + bvals.reallocate(nsys, nloc); // Create a cyclic reduction object cr = bout::utils::make_unique>(localmesh->getXcomm(), nloc); diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx index 6bb3206695..e74d136c98 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx @@ -31,14 +31,14 @@ LaplaceXZcyclic::LaplaceXZcyclic(Mesh *m, Options *options, const CELL_LOC loc) // including boundaries but not guard cells nloc = xend - xstart + 1; - acoef.resize(nsys, nloc); - bcoef.resize(nsys, nloc); - ccoef.resize(nsys, nloc); - xcmplx.resize(nsys, nloc); - rhscmplx.resize(nsys, nloc); - - k1d.resize((m->LocalNz) / 2 + 1); - k1d_2.resize((m->LocalNz) / 2 + 1); + acoef.reallocate(nsys, nloc); + bcoef.reallocate(nsys, nloc); + ccoef.reallocate(nsys, nloc); + xcmplx.reallocate(nsys, nloc); + rhscmplx.reallocate(nsys, nloc); + + k1d.reallocate((m->LocalNz) / 2 + 1); + k1d_2.reallocate((m->LocalNz) / 2 + 1); // Create a cyclic reduction object, operating on dcomplex values cr = bout::utils::make_unique>(localmesh->getXcomm(), nloc); diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 356e0cd7df..0bb8c75d14 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -1869,17 +1869,17 @@ BoutMesh::CommHandle *BoutMesh::get_handle(int xlen, int ylen) { i = MPI_REQUEST_NULL; if (ylen > 0) { - ch->umsg_sendbuff.resize(ylen); - ch->dmsg_sendbuff.resize(ylen); - ch->umsg_recvbuff.resize(ylen); - ch->dmsg_recvbuff.resize(ylen); + ch->umsg_sendbuff.reallocate(ylen); + ch->dmsg_sendbuff.reallocate(ylen); + ch->umsg_recvbuff.reallocate(ylen); + ch->dmsg_recvbuff.reallocate(ylen); } if (xlen > 0) { - ch->imsg_sendbuff.resize(xlen); - ch->omsg_sendbuff.resize(xlen); - ch->imsg_recvbuff.resize(xlen); - ch->omsg_recvbuff.resize(xlen); + ch->imsg_sendbuff.reallocate(xlen); + ch->omsg_sendbuff.reallocate(xlen); + ch->imsg_recvbuff.reallocate(xlen); + ch->omsg_recvbuff.reallocate(xlen); } ch->xbufflen = xlen; @@ -1896,18 +1896,18 @@ BoutMesh::CommHandle *BoutMesh::get_handle(int xlen, int ylen) { // Check that the buffers are big enough (NOTE: Could search list for bigger buffers) if (ch->ybufflen < ylen) { - ch->umsg_sendbuff.resize(ylen); - ch->dmsg_sendbuff.resize(ylen); - ch->umsg_recvbuff.resize(ylen); - ch->dmsg_recvbuff.resize(ylen); + ch->umsg_sendbuff.reallocate(ylen); + ch->dmsg_sendbuff.reallocate(ylen); + ch->umsg_recvbuff.reallocate(ylen); + ch->dmsg_recvbuff.reallocate(ylen); ch->ybufflen = ylen; } if (ch->xbufflen < xlen) { - ch->imsg_sendbuff.resize(xlen); - ch->omsg_sendbuff.resize(xlen); - ch->imsg_recvbuff.resize(xlen); - ch->omsg_recvbuff.resize(xlen); + ch->imsg_sendbuff.reallocate(xlen); + ch->omsg_sendbuff.reallocate(xlen); + ch->imsg_recvbuff.reallocate(xlen); + ch->omsg_recvbuff.reallocate(xlen); ch->xbufflen = xlen; } diff --git a/src/mesh/interpolation/bilinear.cxx b/src/mesh/interpolation/bilinear.cxx index ddfbc37586..306068051d 100644 --- a/src/mesh/interpolation/bilinear.cxx +++ b/src/mesh/interpolation/bilinear.cxx @@ -31,8 +31,8 @@ Bilinear::Bilinear(int y_offset, Mesh *mesh) : Interpolation(y_offset, mesh), w0(localmesh), w1(localmesh), w2(localmesh), w3(localmesh) { // Index arrays contain guard cells in order to get subscripts right - i_corner.resize(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); - k_corner.resize(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); + i_corner.reallocate(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); + k_corner.reallocate(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); // Allocate Field3D members w0.allocate(); diff --git a/src/mesh/interpolation/hermite_spline.cxx b/src/mesh/interpolation/hermite_spline.cxx index 3fc0976a34..d1e5291836 100644 --- a/src/mesh/interpolation/hermite_spline.cxx +++ b/src/mesh/interpolation/hermite_spline.cxx @@ -33,8 +33,8 @@ HermiteSpline::HermiteSpline(int y_offset, Mesh *mesh) h11_z(localmesh) { // Index arrays contain guard cells in order to get subscripts right - i_corner.resize(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); - k_corner.resize(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); + i_corner.reallocate(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); + k_corner.reallocate(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); // Allocate Field3D members h00_x.allocate(); diff --git a/src/mesh/interpolation/lagrange_4pt.cxx b/src/mesh/interpolation/lagrange_4pt.cxx index a15fa5ded4..a0d1eb9f13 100644 --- a/src/mesh/interpolation/lagrange_4pt.cxx +++ b/src/mesh/interpolation/lagrange_4pt.cxx @@ -30,8 +30,8 @@ Lagrange4pt::Lagrange4pt(int y_offset, Mesh *mesh) : Interpolation(y_offset, mesh), t_x(localmesh), t_z(localmesh) { // Index arrays contain guard cells in order to get subscripts right - i_corner.resize(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); - k_corner.resize(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); + i_corner.reallocate(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); + k_corner.reallocate(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); t_x.allocate(); t_z.allocate(); diff --git a/src/solver/impls/euler/euler.cxx b/src/solver/impls/euler/euler.cxx index 485bfa7b05..fac4297b7d 100644 --- a/src/solver/impls/euler/euler.cxx +++ b/src/solver/impls/euler/euler.cxx @@ -49,8 +49,8 @@ int EulerSolver::init(int nout, BoutReal tstep) { n3Dvars(), n2Dvars(), neq, nlocal); // Allocate memory - f0.resize(nlocal); - f1.resize(nlocal); + f0.reallocate(nlocal); + f1.reallocate(nlocal); // Put starting values into f0 save_vars(std::begin(f0)); diff --git a/src/solver/impls/imex-bdf2/imex-bdf2.cxx b/src/solver/impls/imex-bdf2/imex-bdf2.cxx index 8c8a6279d1..b78cc10e49 100644 --- a/src/solver/impls/imex-bdf2/imex-bdf2.cxx +++ b/src/solver/impls/imex-bdf2/imex-bdf2.cxx @@ -128,7 +128,7 @@ int IMEXBDF2::init(int nout, BoutReal tstep) { } if (have_constraints) { - is_dae.resize(nlocal); + is_dae.reallocate(nlocal); // Call the Solver function, which sets the array // to zero when not a constraint, one for constraint set_id(std::begin(is_dae)); @@ -154,7 +154,7 @@ int IMEXBDF2::init(int nout, BoutReal tstep) { } // Allocate memory and initialise structures - u.resize(nlocal); + u.reallocate(nlocal); for(int i=0;i{nlocal}); fV.emplace_back(Array{nlocal}); @@ -164,7 +164,7 @@ int IMEXBDF2::init(int nout, BoutReal tstep) { gFac.push_back(0.0); } - rhs.resize(nlocal); + rhs.reallocate(nlocal); OPTION(options, adaptive, true); //Do we try to estimate the error? OPTION(options, nadapt, 4); //How often do we check the error @@ -172,7 +172,7 @@ int IMEXBDF2::init(int nout, BoutReal tstep) { OPTION(options, dtMax, out_timestep); OPTION(options, dtMin, dtMinFatal); if(adaptive){ - err.resize(nlocal); + err.reallocate(nlocal); OPTION(options, adaptRtol, 1.0e-3); //Target relative error OPTION(options, mxstepAdapt, mxstep); //Maximum no. consecutive times we try to reduce timestep OPTION(options, scaleCushUp, 1.5); diff --git a/src/solver/impls/karniadakis/karniadakis.cxx b/src/solver/impls/karniadakis/karniadakis.cxx index a714320334..0cefc82647 100644 --- a/src/solver/impls/karniadakis/karniadakis.cxx +++ b/src/solver/impls/karniadakis/karniadakis.cxx @@ -74,16 +74,16 @@ int KarniadakisSolver::init(int nout, BoutReal tstep) { // Allocate memory - f1.resize(nlocal); - f0.resize(nlocal); - fm1.resize(nlocal); - fm2.resize(nlocal); + f1.reallocate(nlocal); + f0.reallocate(nlocal); + fm1.reallocate(nlocal); + fm2.reallocate(nlocal); - S0.resize(nlocal); - Sm1.resize(nlocal); - Sm2.resize(nlocal); + S0.reallocate(nlocal); + Sm1.reallocate(nlocal); + Sm2.reallocate(nlocal); - D0.resize(nlocal); + D0.reallocate(nlocal); first_time = true; diff --git a/src/solver/impls/power/power.cxx b/src/solver/impls/power/power.cxx index 8f6b288ef2..0d2156dd42 100644 --- a/src/solver/impls/power/power.cxx +++ b/src/solver/impls/power/power.cxx @@ -35,7 +35,7 @@ int PowerSolver::init(int nout, BoutReal tstep) { n3Dvars(), n2Dvars(), nglobal, nlocal); // Allocate memory - f0.resize(nlocal); + f0.reallocate(nlocal); eigenvalue = 0.0; diff --git a/src/solver/impls/rk3-ssp/rk3-ssp.cxx b/src/solver/impls/rk3-ssp/rk3-ssp.cxx index 6c6b3f8525..29f266a339 100644 --- a/src/solver/impls/rk3-ssp/rk3-ssp.cxx +++ b/src/solver/impls/rk3-ssp/rk3-ssp.cxx @@ -47,13 +47,13 @@ int RK3SSP::init(int nout, BoutReal tstep) { n3Dvars(), n2Dvars(), neq, nlocal); // Allocate memory - f.resize(nlocal); + f.reallocate(nlocal); // memory for taking a single time step - u1.resize(nlocal); - u2.resize(nlocal); - u3.resize(nlocal); - L.resize(nlocal); + u1.reallocate(nlocal); + u2.reallocate(nlocal); + u3.reallocate(nlocal); + L.reallocate(nlocal); // Put starting values into f save_vars(std::begin(f)); diff --git a/src/solver/impls/rk4/rk4.cxx b/src/solver/impls/rk4/rk4.cxx index b910af96a3..418d45a2e8 100644 --- a/src/solver/impls/rk4/rk4.cxx +++ b/src/solver/impls/rk4/rk4.cxx @@ -52,16 +52,16 @@ int RK4Solver::init(int nout, BoutReal tstep) { n3Dvars(), n2Dvars(), neq, nlocal); // Allocate memory - f0.resize(nlocal); - f1.resize(nlocal); - f2.resize(nlocal); + f0.reallocate(nlocal); + f1.reallocate(nlocal); + f2.reallocate(nlocal); // memory for taking a single time step - k1.resize(nlocal); - k2.resize(nlocal); - k3.resize(nlocal); - k4.resize(nlocal); - k5.resize(nlocal); + k1.reallocate(nlocal); + k2.reallocate(nlocal); + k3.reallocate(nlocal); + k4.reallocate(nlocal); + k5.reallocate(nlocal); // Put starting values into f0 save_vars(std::begin(f0)); diff --git a/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx b/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx index 3aea8540b5..69ecf37a7a 100644 --- a/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx +++ b/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx @@ -11,9 +11,9 @@ CASHKARPScheme::CASHKARPScheme(Options *options):RKScheme(options){ OPTION(options, followHighOrder, followHighOrder); //Allocate coefficient arrays - stageCoeffs.resize(numStages, numStages); - resultCoeffs.resize(numStages, numOrders); - timeCoeffs.resize(numStages); + stageCoeffs.reallocate(numStages, numStages); + resultCoeffs.reallocate(numStages, numOrders); + timeCoeffs.reallocate(numStages); //Zero out arrays (shouldn't be needed, but do for testing) for(int i=0;i a{}; ASSERT_TRUE(a.empty()); - // Resize from empty - a.resize(15); + // Reallocate from empty + a.reallocate(15); std::iota(a.begin(), a.end(), 0); ASSERT_FALSE(a.empty()); @@ -135,16 +135,16 @@ TEST_F(ArrayTest, Resize) { EXPECT_DOUBLE_EQ(a[5], 5); EXPECT_TRUE(a.unique()); - // Resize to smaller - a.resize(7); + // Reallocate to smaller + a.reallocate(7); std::iota(a.begin(), a.end(), 10); ASSERT_FALSE(a.empty()); EXPECT_EQ(a.size(), 7); EXPECT_DOUBLE_EQ(a[5], 15); - // Resize to larger - a.resize(30); + // Reallocate to larger + a.reallocate(30); std::iota(a.begin(), a.end(), 20); ASSERT_FALSE(a.empty()); diff --git a/tests/unit/sys/test_utils.cxx b/tests/unit/sys/test_utils.cxx index e2fa8ce05b..8cca3b5de6 100644 --- a/tests/unit/sys/test_utils.cxx +++ b/tests/unit/sys/test_utils.cxx @@ -21,12 +21,12 @@ TEST(MatrixTest, CreateGivenSize) { EXPECT_EQ(shape1, 5); } -TEST(MatrixTest, Resize) { +TEST(MatrixTest, Reallocate) { Matrix matrix{}; ASSERT_TRUE(matrix.empty()); - matrix.resize(3, 5); + matrix.reallocate(3, 5); int shape0, shape1; std::tie(shape0, shape1) = matrix.shape(); @@ -34,7 +34,7 @@ TEST(MatrixTest, Resize) { EXPECT_EQ(shape0, 3); EXPECT_EQ(shape1, 5); - matrix.resize(5, 3); + matrix.reallocate(5, 3); std::tie(shape0, shape1) = matrix.shape(); EXPECT_EQ(shape0, 5); @@ -183,12 +183,12 @@ TEST(TensorTest, CreateGivenSize) { EXPECT_EQ(shape2, 7); } -TEST(TensorTest, Resize) { +TEST(TensorTest, Reallocate) { Tensor tensor{}; ASSERT_TRUE(tensor.empty()); - tensor.resize(3, 5, 7); + tensor.reallocate(3, 5, 7); int shape0, shape1, shape2; std::tie(shape0, shape1, shape2) = tensor.shape(); @@ -197,7 +197,7 @@ TEST(TensorTest, Resize) { EXPECT_EQ(shape1, 5); EXPECT_EQ(shape2, 7); - tensor.resize(5, 7, 3); + tensor.reallocate(5, 7, 3); std::tie(shape0, shape1, shape2) = tensor.shape(); EXPECT_EQ(shape0, 5); From 0a375946588efd1dfc4a0f217bb850c37da324a1 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 5 Mar 2019 16:40:50 +0000 Subject: [PATCH 0942/1783] Restore default value for FieldPerp::yindex The default value given at the declaration of FieldPerp::yindex was removed in error. --- include/fieldperp.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 68d5132008..8b58650714 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -257,7 +257,7 @@ class FieldPerp : public Field { private: /// The Y index at which this FieldPerp is defined - int yindex; + int yindex{-1}; /// The size of the data array int nx{-1}, nz{-1}; From 0cc696311415365d915e9a6ca0021dbe8b67f493 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Mar 2019 16:47:34 +0000 Subject: [PATCH 0943/1783] Add basic serial unit test for CyclicReduce --- tests/unit/include/test_cyclic_reduction.cxx | 105 +++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 tests/unit/include/test_cyclic_reduction.cxx diff --git a/tests/unit/include/test_cyclic_reduction.cxx b/tests/unit/include/test_cyclic_reduction.cxx new file mode 100644 index 0000000000..f682785732 --- /dev/null +++ b/tests/unit/include/test_cyclic_reduction.cxx @@ -0,0 +1,105 @@ +#include "gtest/gtest.h" + +#include "boutcomm.hxx" +#include "cyclic_reduction.hxx" +#include "test_extras.hxx" +#include "bout/array.hxx" + +#include +#include + +namespace bout { +namespace testing { +constexpr int reduction_size{5}; +} +} // namespace bout + +Array makeArrayFromVector(const std::vector& values) { + using std::begin; + using std::end; + + Array array{static_cast::size_type>(values.size())}; + std::copy(begin(values), end(values), begin(array)); + return array; +} + +Matrix makeMatrixFromVector(const std::vector>& values) { + using std::begin; + using std::end; + + Matrix matrix{static_cast::size_type>(values.size()), + static_cast::size_type>(values[0].size())}; + auto start = begin(matrix); + for (const auto& sub_values : values) { + start = std::copy(begin(sub_values), end(sub_values), start); + } + return matrix; +} + +TEST(CyclicReduction, SerialSolveSingleArray) { + CyclicReduce reduce{BoutComm::get(), bout::testing::reduction_size}; + + auto a = makeArrayFromVector({0., 1., 1., 1., 1.}); + auto b = makeArrayFromVector({5., 4., 3., 2., 1.}); + auto c = makeArrayFromVector({2., 2., 2., 2., 0.}); + + reduce.setCoefs(a, b, c); + + auto rhs = makeArrayFromVector({0., 1., 2., 2., 3.}); + Array x{bout::testing::reduction_size}; + + reduce.solve(rhs, x); + + EXPECT_NEAR(x[0], -1., BoutRealTolerance); + EXPECT_NEAR(x[1], 2.5, BoutRealTolerance); + EXPECT_NEAR(x[2], -4., BoutRealTolerance); + EXPECT_NEAR(x[3], 5.75, BoutRealTolerance); + EXPECT_NEAR(x[4], -2.75, BoutRealTolerance); +} + +TEST(CyclicReduction, SerialSolveSingleMatrix) { + CyclicReduce reduce{BoutComm::get(), bout::testing::reduction_size}; + + auto a = makeMatrixFromVector({{0., 1., 1., 1., 1.}}); + auto b = makeMatrixFromVector({{5., 4., 3., 2., 1.}}); + auto c = makeMatrixFromVector({{2., 2., 2., 2., 0.}}); + + reduce.setCoefs(a, b, c); + + auto rhs = makeMatrixFromVector({{0., 1., 2., 2., 3.}}); + Matrix x{1, bout::testing::reduction_size}; + + reduce.solve(rhs, x); + + EXPECT_NEAR(x(0, 0), -1., BoutRealTolerance); + EXPECT_NEAR(x(0, 1), 2.5, BoutRealTolerance); + EXPECT_NEAR(x(0, 2), -4., BoutRealTolerance); + EXPECT_NEAR(x(0, 3), 5.75, BoutRealTolerance); + EXPECT_NEAR(x(0, 4), -2.75, BoutRealTolerance); +} + +TEST(CyclicReduction, SerialSolveDoubleMatrix) { + CyclicReduce reduce{BoutComm::get(), bout::testing::reduction_size}; + + auto a = makeMatrixFromVector({{0., 1., 1., 1., 1.}, {0., -2., -2., -2., -2.}}); + auto b = makeMatrixFromVector({{5., 4., 3., 2., 1.}, {1., 1., 1., 1., 1.}}); + auto c = makeMatrixFromVector({{2., 2., 2., 2., 0.}, {2., 2., 2., 2., 0.}}); + + reduce.setCoefs(a, b, c); + + auto rhs = makeMatrixFromVector({{0., 1., 2., 2., 3.}, {5., 4., 5., 4., 5.}}); + Matrix x{2, bout::testing::reduction_size}; + + reduce.solve(rhs, x); + + EXPECT_NEAR(x(0, 0), -1., BoutRealTolerance); + EXPECT_NEAR(x(0, 1), 2.5, BoutRealTolerance); + EXPECT_NEAR(x(0, 2), -4., BoutRealTolerance); + EXPECT_NEAR(x(0, 3), 5.75, BoutRealTolerance); + EXPECT_NEAR(x(0, 4), -2.75, BoutRealTolerance); + EXPECT_NEAR(x(1, 0), 3.4, BoutRealTolerance); + EXPECT_NEAR(x(1, 1), 0.8, BoutRealTolerance); + EXPECT_NEAR(x(1, 2), 5., BoutRealTolerance); + EXPECT_NEAR(x(1, 3), 0.8, BoutRealTolerance); + EXPECT_NEAR(x(1, 4), 6.6, BoutRealTolerance); +} From c87fc2adb05cc3174bd270a63053c9f9a8aa2d46 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Mar 2019 16:56:33 +0000 Subject: [PATCH 0944/1783] Fix bug in CyclicReduce: only index Arrays once --- include/cyclic_reduction.hxx | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/include/cyclic_reduction.hxx b/include/cyclic_reduction.hxx index 307b87061e..48270957f6 100644 --- a/include/cyclic_reduction.hxx +++ b/include/cyclic_reduction.hxx @@ -146,27 +146,22 @@ public: ASSERT2(rhs.size() == x.size()); ASSERT2(rhs.size() == N); - int nrhs = rhs.size(); Matrix rhsMatrix(1, N); Matrix xMatrix(1, N); // Copy input data into matrix - BOUT_OMP(parallel for) - for (int j = 0; j < nrhs; ++j) { - for (int i = 0; i < N; ++i) { - rhsMatrix(j, i) = rhs[j][i]; - } + BOUT_OMP(parallel for) + for (int i = 0; i < N; ++i) { + rhsMatrix(0, i) = rhs[i]; } // Solve solve(rhsMatrix, xMatrix); // Copy result back into argument - BOUT_OMP(parallel for) - for (int j = 0; j < nrhs; ++j) { - for (int i = 0; i < N; ++i) { - x[j][i] = xMatrix(j, i); - } + BOUT_OMP(parallel for) + for (int i = 0; i < N; ++i) { + x[i] = xMatrix(0, i); } }; From 861ce4e54444fe153326f626c3ca12218955fbd2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Mar 2019 16:57:38 +0000 Subject: [PATCH 0945/1783] Remove needless assignment in CyclicReduce destructor --- include/cyclic_reduction.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/cyclic_reduction.hxx b/include/cyclic_reduction.hxx index 48270957f6..df05bd69e3 100644 --- a/include/cyclic_reduction.hxx +++ b/include/cyclic_reduction.hxx @@ -85,7 +85,7 @@ public: myproc = myp; } - ~CyclicReduce() { N = Nsys = 0; } + ~CyclicReduce() = default; /// Specify that the tridiagonal system is periodic /// By default not periodic From b4a3792b5b146879ef86517ab86480d3f44c2af7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Mar 2019 17:13:10 +0000 Subject: [PATCH 0946/1783] Use default values to simplify CyclicReduce constructors --- include/cyclic_reduction.hxx | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/include/cyclic_reduction.hxx b/include/cyclic_reduction.hxx index df05bd69e3..11179b6c22 100644 --- a/include/cyclic_reduction.hxx +++ b/include/cyclic_reduction.hxx @@ -56,14 +56,9 @@ template class CyclicReduce { public: - CyclicReduce() { - nprocs = 0; - myproc = -1; - N = 0; - Nsys = 0; - } + CyclicReduce() = default; - CyclicReduce(MPI_Comm c, int size) : comm(c), N(size), Nsys(0), periodic(false) { + CyclicReduce(MPI_Comm c, int size) : comm(c), N(size), Nsys(0) { MPI_Comm_size(c, &nprocs); MPI_Comm_rank(c, &myproc); } @@ -438,15 +433,15 @@ public: } private: - MPI_Comm comm; ///< Communicator - int nprocs, myproc; ///< Number of processors and ID of my processor + MPI_Comm comm; ///< Communicator + int nprocs{0}, myproc{-1}; ///< Number of processors and ID of my processor - int N; ///< Total size of the problem - int Nsys; ///< Number of independent systems to solve - int myns; ///< Number of systems for interface solve on this processor - int sys0; ///< Starting system index for interface solve + int N{0}; ///< Total size of the problem + int Nsys{0}; ///< Number of independent systems to solve + int myns; ///< Number of systems for interface solve on this processor + int sys0; ///< Starting system index for interface solve - bool periodic; ///< Is the domain periodic? + bool periodic{false}; ///< Is the domain periodic? Matrix coefs; ///< Starting coefficients, rhs [Nsys, {3*coef,rhs}*N] Matrix myif; ///< Interface equations for this processor From 31cd227b3770c1a51de222339ecaa6640feb66c4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Mar 2019 17:21:46 +0000 Subject: [PATCH 0947/1783] Ensure const-correctness on Matrix/Tensor::shape/empty --- include/utils.hxx | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/include/utils.hxx b/include/utils.hxx index a574c27264..dc610f518e 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -135,11 +135,9 @@ public: T* end() { return std::end(data);}; const T* end() const { return std::end(data);}; - std::tuple shape() { return std::make_tuple(n1, n2);}; + std::tuple shape() const { return std::make_tuple(n1, n2); }; - bool empty(){ - return n1*n2 == 0; - } + bool empty() const { return n1 * n2 == 0; } /*! * Ensures that this Matrix does not share data with another @@ -207,13 +205,13 @@ public: const T* begin() const { return std::begin(data);}; T* end() { return std::end(data);}; const T* end() const { return std::end(data);}; - - std::tuple shape() { return std::make_tuple(n1, n2, n3);}; - - bool empty(){ - return n1*n2*n3 == 0; - } - + + std::tuple shape() const { + return std::make_tuple(n1, n2, n3); + }; + + bool empty() const { return n1 * n2 * n3 == 0; } + /*! * Ensures that this Tensor does not share data with another * This should be called before performing any write operations From 4a01dc3769fbb2ff896b279e8ca33e9ebfe3261a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 4 Mar 2019 17:30:17 +0000 Subject: [PATCH 0948/1783] Ensure const-correctness on CyclicReduce arguments --- include/cyclic_reduction.hxx | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/include/cyclic_reduction.hxx b/include/cyclic_reduction.hxx index 11179b6c22..8eb6c744e6 100644 --- a/include/cyclic_reduction.hxx +++ b/include/cyclic_reduction.hxx @@ -86,7 +86,7 @@ public: /// By default not periodic void setPeriodic(bool p = true) { periodic = p; } - void setCoefs(Array &a, Array &b, Array &c) { + void setCoefs(const Array &a, const Array &b, const Array &c) { ASSERT2(a.size() == b.size()); ASSERT2(a.size() == c.size()); ASSERT2(a.size() == N); @@ -95,7 +95,6 @@ public: Matrix bMatrix(1, N); Matrix cMatrix(1, N); - // Copy data into matrices BOUT_OMP(parallel for) for (int i = 0; i < N; ++i) { aMatrix(0, i) = a[i]; @@ -104,8 +103,6 @@ public: } setCoefs(aMatrix, bMatrix, cMatrix); - // Don't copy ?Matrix back into ? as setCoefs - // doesn't modify these. Could copy out if we really wanted. } /// Set the entries in the matrix to be inverted @@ -114,7 +111,7 @@ public: /// where N is set in the constructor or setup /// @param[in] b Diagonal values. Should have size [nsys][N] /// @param[in] c Right diagonal. Should have size [nsys][N] - void setCoefs(Matrix &a, Matrix &b, Matrix &c) { + void setCoefs(const Matrix& a, const Matrix& b, const Matrix& c) { TRACE("CyclicReduce::setCoefs"); int nsys = std::get<0>(a.shape()); @@ -124,20 +121,21 @@ public: // Fill coefficient array BOUT_OMP(parallel for) - for (int j = 0; j < Nsys; j++) + for (int j = 0; j < Nsys; j++) { for (int i = 0; i < N; i++) { coefs(j, 4 * i) = a(j, i); coefs(j, 4 * i + 1) = b(j, i); coefs(j, 4 * i + 2) = c(j, i); // 4*i + 3 will contain RHS } + } } /// Solve a set of tridiagonal systems /// /// @param[in] rhs Array storing Values of the rhs for a single system /// @param[out] x Array storing the result for a single system - void solve(Array &rhs, Array &x) { + void solve(const Array &rhs, Array &x) { ASSERT2(rhs.size() == x.size()); ASSERT2(rhs.size() == N); @@ -164,7 +162,7 @@ public: /// /// @param[in] rhs Matrix storing Values of the rhs for each system /// @param[out] x Matrix storing the result for each system - void solve(Matrix &rhs, Matrix &x) { + void solve(const Matrix &rhs, Matrix &x) { TRACE("CyclicReduce::solve"); ASSERT2(static_cast(std::get<0>(rhs.shape())) == Nsys); ASSERT2(static_cast(std::get<0>(x.shape())) == Nsys); @@ -179,11 +177,12 @@ public: // Insert RHS into coefs array. Ordered to allow efficient partitioning // for MPI send/receives - BOUT_OMP(parallel for) - for (int j = 0; j < Nsys; j++) + BOUT_OMP(parallel for) + for (int j = 0; j < Nsys; j++) { for (int i = 0; i < N; i++) { coefs(j, 4 * i + 3) = rhs(j, i); } + } /////////////////////////////////////// // Reduce local part of the matrix to interface equations @@ -591,8 +590,8 @@ private: /// Back-solve from x at ends (x1, xn) to obtain remaining values /// Coefficients ordered [ns, nloc*(a,b,c,r)] - void back_solve(int ns, int nloc, Matrix &co, Array &x1, Array &xn, - Matrix &xa) { + void back_solve(int ns, int nloc, const Matrix& co, const Array& x1, + const Array& xn, Matrix& xa) { xa.ensureUnique(); // Going to be modified, so call this outside parallel region From aefbf79b09e283b5888a3cd5d8dade223622802a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 5 Mar 2019 18:41:51 +0000 Subject: [PATCH 0949/1783] Move emptyFrom to field.hxx and fieldperp.hxx instead of separate file --- include/bout/empty_from.hxx | 21 --------------------- include/field.hxx | 8 ++++++++ include/field2d.hxx | 1 - include/field3d.hxx | 1 - include/fieldperp.hxx | 8 ++++++++ 5 files changed, 16 insertions(+), 23 deletions(-) delete mode 100644 include/bout/empty_from.hxx diff --git a/include/bout/empty_from.hxx b/include/bout/empty_from.hxx deleted file mode 100644 index 140407ccf4..0000000000 --- a/include/bout/empty_from.hxx +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __NEW_EMPTY_FIELD_H__ -#define __NEW_EMPTY_FIELD_H__ - -#include "field.hxx" -#include "fieldperp.hxx" - -/// Return an empty shell field of some type derived from Field, with metadata -/// copied but empty data array -template -inline T emptyFrom(const T& f) { - static_assert(std::is_base_of::value, "emptyFrom only works on Fields"); - return T(f.getMesh(), f.getLocation(), f.getDirectionX(), f.getDirectionY(), f.getDirectionZ()).allocate(); -} - -// Specialize newEmptyField templates for FieldPerp -template<> -inline FieldPerp emptyFrom(const FieldPerp& f) { - return FieldPerp(f.getMesh(), f.getLocation(), f.getIndex(), f.getDirectionX(), f.getDirectionY(), f.getDirectionZ()).allocate(); -} - -#endif // __NEW_EMPTY_FIELD_H__ diff --git a/include/field.hxx b/include/field.hxx index 4c86378294..9cf07828fb 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -211,6 +211,14 @@ private: DIRECTION zDirectionType{DIRECTION::Null}; }; +/// Return an empty shell field of some type derived from Field, with metadata +/// copied but empty data array +template +inline T emptyFrom(const T& f) { + static_assert(std::is_base_of::value, "emptyFrom only works on Fields"); + return T(f.getMesh(), f.getLocation(), f.getDirectionX(), f.getDirectionY(), f.getDirectionZ()).allocate(); +} + /// Unary + operator. This doesn't do anything template T operator+(const T& f) {return f;} diff --git a/include/field2d.hxx b/include/field2d.hxx index 7d55dcf251..ccc481b1b1 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -40,7 +40,6 @@ class Field3D; //#include "field3d.hxx" #include "bout/field_visitor.hxx" #include "bout/array.hxx" -#include "bout/empty_from.hxx" #include "bout/region.hxx" #include "unused.hxx" diff --git a/include/field3d.hxx b/include/field3d.hxx index 298ebc0d3e..c43a5cb9b6 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -34,7 +34,6 @@ class Mesh; // #include "bout/mesh.hxx" #include "bout_types.hxx" #include "bout/array.hxx" -#include "bout/empty_from.hxx" #include "bout/region.hxx" #include "bout/assert.hxx" diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 8b58650714..43db0ba7b8 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -418,6 +418,14 @@ BoutReal max(const FieldPerp &f, bool allpe=false, REGION rgn=RGN_NOX); /// default (can be changed using the \p rgn argument) bool finite(const FieldPerp &f, REGION rgn=RGN_ALL); +// Specialize newEmptyField templates for FieldPerp +/// Return an empty shell field of some type derived from Field, with metadata +/// copied but empty data array +template<> +inline FieldPerp emptyFrom(const FieldPerp& f) { + return FieldPerp(f.getMesh(), f.getLocation(), f.getIndex(), f.getDirectionX(), f.getDirectionY(), f.getDirectionZ()).allocate(); +} + #if CHECK > 0 void checkData(const FieldPerp &f, REGION region = RGN_NOX); #else From c2c9c1edda1653c631f677818c26b81c7b93bfea Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 5 Mar 2019 18:48:31 +0000 Subject: [PATCH 0950/1783] Comments to document the meaning of DIRECTION enum class values --- include/bout_types.hxx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index a770f87096..dd4a0fda5b 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -48,7 +48,17 @@ enum REGION {RGN_ALL, RGN_NOBNDRY, RGN_NOX, RGN_NOY, RGN_NOZ}; const std::string& REGION_STRING(REGION region); -/// To identify particular directions (in index space) +/// To identify particular directions (in index space): +/// - X, Y, Z are the coordinate directions +/// - YAligned is a special case of Y, indicating a field-aligned grid, where +/// the x- and z- axes are not necessarily orthogonal +/// - YOrthogonal is a special case of Y, indicating a grid where the x and z +/// axes are orthogonal but the y-direction is not necessarily +/// field-aligned +/// - Special is used when the DIRECTION is an attribute of a Field, +/// indicating that that field does not have that direction, e.g. Field2D +/// does not have a z-direction +/// - Null indicates an uninitialized DIRECTION enum class DIRECTION { X = 0, Y = 1, Z = 3, YAligned = 4, YOrthogonal = 5, Special = 6, Null = 7 }; const std::string& DIRECTION_STRING(DIRECTION direction); From 75007a784b8ea4710491320bd56cfa5a06d96b62 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 5 Mar 2019 19:22:32 +0000 Subject: [PATCH 0951/1783] Clearer comments on why getCoordinates() is called in field.hxx --- src/field/field.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/field/field.cxx b/src/field/field.cxx index da5e590a59..d2aa21b15f 100644 --- a/src/field/field.cxx +++ b/src/field/field.cxx @@ -42,7 +42,8 @@ Field::Field(Mesh *localmesh, CELL_LOC location_in, // Need to check for nullptr again, because the fieldmesh might still be // nullptr if the global mesh hasn't been initialized yet if (fieldmesh != nullptr) { - // get Coordinates for our location from fieldmesh + // sets fieldCoordinates by getting Coordinates for our location from + // fieldmesh getCoordinates(); // Get default values for xDirectionType, yDirectionType and @@ -76,7 +77,7 @@ void Field::setLocation(CELL_LOC new_location) { } fieldCoordinates = nullptr; - // Sets correct Coordinates pointer and ensures Coordinates object is + // Sets correct fieldCoordinates pointer and ensures Coordinates object is // initialized for this Field's location getCoordinates(); } From 945002f12d87bd99d539ed2d276518ce8fda01b2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 5 Mar 2019 23:37:09 +0000 Subject: [PATCH 0952/1783] Use emptyFrom in pow(Field3D,FieldPerp) --- src/field/field3d.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 7daba4863e..853511f6d2 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -604,8 +604,7 @@ FieldPerp pow(const Field3D &lhs, const FieldPerp &rhs, REGION rgn) { checkData(rhs); ASSERT1(fieldsCompatible(lhs, rhs)); - FieldPerp result{rhs.getMesh(), rhs.getLocation(), rhs.getIndex(), rhs.getDirectionX(), - rhs.getDirectionY(), rhs.getDirectionZ()}; + FieldPerp result{emptyFrom(rhs)}; result.allocate(); BOUT_FOR(i, result.getRegion(rgn)) { From 940928807c39763afe42894f2bbeb4915c2bfb45 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 5 Mar 2019 23:42:42 +0000 Subject: [PATCH 0953/1783] Tidy conditional in gen_fieldops.jinja --- src/field/gen_fieldops.jinja | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/field/gen_fieldops.jinja b/src/field/gen_fieldops.jinja index 2b67921e85..4dcc9bc7c9 100644 --- a/src/field/gen_fieldops.jinja +++ b/src/field/gen_fieldops.jinja @@ -4,11 +4,7 @@ ASSERT1(fieldsCompatible(lhs, rhs)); {% endif %} - {% if lhs.field_type == out.field_type %} - {{out.field_type}} {{out.name}}{emptyFrom(lhs)}; - {% else %} - {{out.field_type}} {{out.name}}{emptyFrom(rhs)}; - {% endif %} + {{out.field_type}} {{out.name}}{emptyFrom({{lhs.name if lhs.field_type == out.field_type else rhs.name}})}; checkData({{lhs.name}}); checkData({{rhs.name}}); From 8772f9b0c5bc04bb16d8338ed3ffbf79f469e929 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 5 Mar 2019 23:49:55 +0000 Subject: [PATCH 0954/1783] Remove unnecessary #if CHECK > 0 Just always throw from a default switch case that we should never enter. --- src/mesh/parallel/shiftedmetric.cxx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 672ed51ec7..369b4608a6 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -143,13 +143,10 @@ const Field3D ShiftedMetric::toFieldAligned(const Field3D& f, const REGION regio // f is already in field-aligned coordinates return f; default: -#if CHECK > 0 throw BoutException("Unrecognized y-direction type for Field3D passed to " "ShiftedMetric::toFieldAligned"); -#else // This should never happen, but use 'return f' to avoid compiler warnings return f; -#endif } } @@ -165,13 +162,10 @@ const Field3D ShiftedMetric::fromFieldAligned(const Field3D& f, const REGION reg // f is already in orthogonal coordinates return f; default: -#if CHECK > 0 throw BoutException("Unrecognized y-direction type for Field3D passed to " "ShiftedMetric::toFieldAligned"); -#else // This should never happen, but use 'return f' to avoid compiler warnings return f; -#endif } } From ea6d7cf6e872a9163ea3ba6a1233ceab0a5881d1 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 00:03:00 +0000 Subject: [PATCH 0955/1783] Use bout::utils::make_unique for ParallelTransforms in unit tests --- tests/unit/mesh/parallel/test_shiftedmetric.cxx | 2 +- tests/unit/test_extras.hxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 1e967e2f1a..138dc7d845 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -43,7 +43,7 @@ class ShiftedMetricTest : public ::testing::Test { Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false)); - mesh->setParallelTransform(Mesh::PTptr(new ShiftedMetric(*mesh, zShift))); + mesh->setParallelTransform(bout::utils::make_unique(*mesh, zShift)); Field3D input_temp{mesh}; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index dc2bac0b60..015b9d49b0 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -149,7 +149,7 @@ public: maxregionblocksize = MAXREGIONBLOCKSIZE; setCoordinates(nullptr); - setParallelTransform(PTptr(new ParallelTransformIdentity(*this))); + setParallelTransform(bout::utils::make_unique(*this)); } void setCoordinates(std::shared_ptr coords, CELL_LOC location = CELL_CENTRE) { From 2752a0971a6eb78f41470c8ea3f2b682c1673e2f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 6 Mar 2019 10:12:37 +0000 Subject: [PATCH 0956/1783] Fix some missed resize -> reallocate renames in mumps laplace --- src/invert/laplace/impls/mumps/mumps_laplace.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/invert/laplace/impls/mumps/mumps_laplace.cxx b/src/invert/laplace/impls/mumps/mumps_laplace.cxx index 62adc88e58..853c214fcc 100644 --- a/src/invert/laplace/impls/mumps/mumps_laplace.cxx +++ b/src/invert/laplace/impls/mumps/mumps_laplace.cxx @@ -211,21 +211,21 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc, Mesh *mesh_in = mes localrhssize += localmesh->xstart*(localmesh->LocalNz); int nxpe = localmesh->NXPE; - localrhs_size_array.resize(nxpe); + localrhs_size_array.reallocate(nxpe); localrhs_size_array[0] = localrhssize; if (nxpe>1) { for (int i=1; ixend-localmesh->xstart+1)*(localmesh->LocalNz); localrhs_size_array[nxpe-1] = (localmesh->LocalNx-localmesh->xstart)*(localmesh->LocalNz); } - rhs_positions.resize(nxpe); + rhs_positions.reallocate(nxpe); rhs_positions[0] = 0; for (int i=1; i Date: Wed, 6 Mar 2019 11:39:33 +0000 Subject: [PATCH 0957/1783] In interp_to, just return 'var' if there is no interpolation to do See discussion at https://github.com/boutproject/BOUT-dev/pull/1624#discussion_r --- include/interpolation.hxx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/interpolation.hxx b/include/interpolation.hxx index 246131abcf..e35976d02f 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -72,10 +72,7 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { if (var.getLocation() == loc) { // Nothing to do - just return unchanged - // Copying into result to return as returning var may increase the number of - // references to the var data whilst returning result doesn't - T result = var; - return result; + return var; } From e26cbe04b8ff90e0e54a17a0033fd2a9450efa57 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 12:02:18 +0000 Subject: [PATCH 0958/1783] Result of toFieldAligned should have yDirectionType=YAligned --- src/mesh/parallel/shiftedmetric.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 369b4608a6..84c74a8fea 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -138,7 +138,7 @@ void ShiftedMetric::cachePhases() { const Field3D ShiftedMetric::toFieldAligned(const Field3D& f, const REGION region) { switch (f.getDirectionY()) { case (DIRECTION::YOrthogonal): - return shiftZ(f, toAlignedPhs, DIRECTION::YOrthogonal, region); + return shiftZ(f, toAlignedPhs, DIRECTION::YAligned, region); case (DIRECTION::YAligned): // f is already in field-aligned coordinates return f; From 989465a071c9445f45ca22f2bd6c728432365e65 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 12:09:16 +0000 Subject: [PATCH 0959/1783] Remove explicit initialization of enum classes in bout_types.hxx Explicit initialization to int values is not required, so don't do it. --- include/bout_types.hxx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index dd4a0fda5b..563c397d25 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -59,20 +59,19 @@ const std::string& REGION_STRING(REGION region); /// indicating that that field does not have that direction, e.g. Field2D /// does not have a z-direction /// - Null indicates an uninitialized DIRECTION -enum class DIRECTION { X = 0, Y = 1, Z = 3, YAligned = 4, YOrthogonal = 5, Special = 6, Null = 7 }; +enum class DIRECTION { X, Y, Z, YAligned, YOrthogonal, Special, Null }; const std::string& DIRECTION_STRING(DIRECTION direction); void swap(DIRECTION& first, DIRECTION& second); /// To identify valid staggering combinations -enum class STAGGER { None = 0, C2L = 1, L2C = 2}; +enum class STAGGER { None, C2L, L2C }; const std::string& STAGGER_STRING(STAGGER stagger); /// To identify types of derivative method combinations -enum class DERIV { Standard = 0, StandardSecond = 1, StandardFourth = 2, - Upwind = 3, Flux = 4 }; +enum class DERIV { Standard, StandardSecond, StandardFourth, Upwind, Flux }; const std::string& DERIV_STRING(DERIV deriv); From 598342727dd9d7f6709d8af038dcbc81534c79ee Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 6 Mar 2019 13:07:43 +0000 Subject: [PATCH 0960/1783] Loosen tolerance in CyclicReduce unit tests to 1e-14 --- tests/unit/include/test_cyclic_reduction.cxx | 43 ++++++++++---------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/tests/unit/include/test_cyclic_reduction.cxx b/tests/unit/include/test_cyclic_reduction.cxx index f682785732..d2d6eadca6 100644 --- a/tests/unit/include/test_cyclic_reduction.cxx +++ b/tests/unit/include/test_cyclic_reduction.cxx @@ -11,7 +11,8 @@ namespace bout { namespace testing { constexpr int reduction_size{5}; -} +constexpr BoutReal CyclicReduceTolerance{1.e-14}; +} // namespace testing } // namespace bout Array makeArrayFromVector(const std::vector& values) { @@ -50,11 +51,11 @@ TEST(CyclicReduction, SerialSolveSingleArray) { reduce.solve(rhs, x); - EXPECT_NEAR(x[0], -1., BoutRealTolerance); - EXPECT_NEAR(x[1], 2.5, BoutRealTolerance); - EXPECT_NEAR(x[2], -4., BoutRealTolerance); - EXPECT_NEAR(x[3], 5.75, BoutRealTolerance); - EXPECT_NEAR(x[4], -2.75, BoutRealTolerance); + EXPECT_NEAR(x[0], -1., bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x[1], 2.5, bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x[2], -4., bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x[3], 5.75, bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x[4], -2.75, bout::testing::CyclicReduceTolerance); } TEST(CyclicReduction, SerialSolveSingleMatrix) { @@ -71,11 +72,11 @@ TEST(CyclicReduction, SerialSolveSingleMatrix) { reduce.solve(rhs, x); - EXPECT_NEAR(x(0, 0), -1., BoutRealTolerance); - EXPECT_NEAR(x(0, 1), 2.5, BoutRealTolerance); - EXPECT_NEAR(x(0, 2), -4., BoutRealTolerance); - EXPECT_NEAR(x(0, 3), 5.75, BoutRealTolerance); - EXPECT_NEAR(x(0, 4), -2.75, BoutRealTolerance); + EXPECT_NEAR(x(0, 0), -1., bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(0, 1), 2.5, bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(0, 2), -4., bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(0, 3), 5.75, bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(0, 4), -2.75, bout::testing::CyclicReduceTolerance); } TEST(CyclicReduction, SerialSolveDoubleMatrix) { @@ -92,14 +93,14 @@ TEST(CyclicReduction, SerialSolveDoubleMatrix) { reduce.solve(rhs, x); - EXPECT_NEAR(x(0, 0), -1., BoutRealTolerance); - EXPECT_NEAR(x(0, 1), 2.5, BoutRealTolerance); - EXPECT_NEAR(x(0, 2), -4., BoutRealTolerance); - EXPECT_NEAR(x(0, 3), 5.75, BoutRealTolerance); - EXPECT_NEAR(x(0, 4), -2.75, BoutRealTolerance); - EXPECT_NEAR(x(1, 0), 3.4, BoutRealTolerance); - EXPECT_NEAR(x(1, 1), 0.8, BoutRealTolerance); - EXPECT_NEAR(x(1, 2), 5., BoutRealTolerance); - EXPECT_NEAR(x(1, 3), 0.8, BoutRealTolerance); - EXPECT_NEAR(x(1, 4), 6.6, BoutRealTolerance); + EXPECT_NEAR(x(0, 0), -1., bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(0, 1), 2.5, bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(0, 2), -4., bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(0, 3), 5.75, bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(0, 4), -2.75, bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(1, 0), 3.4, bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(1, 1), 0.8, bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(1, 2), 5., bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(1, 3), 0.8, bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(1, 4), 6.6, bout::testing::CyclicReduceTolerance); } From fb8b141e5e96297b526b39b02f4f4302bdfdccaf Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 6 Mar 2019 13:11:32 +0000 Subject: [PATCH 0961/1783] Use bout::testing namespace in CyclicReduce unit tests --- tests/unit/include/test_cyclic_reduction.cxx | 55 +++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/tests/unit/include/test_cyclic_reduction.cxx b/tests/unit/include/test_cyclic_reduction.cxx index d2d6eadca6..930fb4ae52 100644 --- a/tests/unit/include/test_cyclic_reduction.cxx +++ b/tests/unit/include/test_cyclic_reduction.cxx @@ -38,7 +38,8 @@ Matrix makeMatrixFromVector(const std::vector>& } TEST(CyclicReduction, SerialSolveSingleArray) { - CyclicReduce reduce{BoutComm::get(), bout::testing::reduction_size}; + using namespace bout::testing; + CyclicReduce reduce{BoutComm::get(), reduction_size}; auto a = makeArrayFromVector({0., 1., 1., 1., 1.}); auto b = makeArrayFromVector({5., 4., 3., 2., 1.}); @@ -47,19 +48,20 @@ TEST(CyclicReduction, SerialSolveSingleArray) { reduce.setCoefs(a, b, c); auto rhs = makeArrayFromVector({0., 1., 2., 2., 3.}); - Array x{bout::testing::reduction_size}; + Array x{reduction_size}; reduce.solve(rhs, x); - EXPECT_NEAR(x[0], -1., bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x[1], 2.5, bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x[2], -4., bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x[3], 5.75, bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x[4], -2.75, bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x[0], -1., CyclicReduceTolerance); + EXPECT_NEAR(x[1], 2.5, CyclicReduceTolerance); + EXPECT_NEAR(x[2], -4., CyclicReduceTolerance); + EXPECT_NEAR(x[3], 5.75, CyclicReduceTolerance); + EXPECT_NEAR(x[4], -2.75, CyclicReduceTolerance); } TEST(CyclicReduction, SerialSolveSingleMatrix) { - CyclicReduce reduce{BoutComm::get(), bout::testing::reduction_size}; + using namespace bout::testing; + CyclicReduce reduce{BoutComm::get(), reduction_size}; auto a = makeMatrixFromVector({{0., 1., 1., 1., 1.}}); auto b = makeMatrixFromVector({{5., 4., 3., 2., 1.}}); @@ -68,19 +70,20 @@ TEST(CyclicReduction, SerialSolveSingleMatrix) { reduce.setCoefs(a, b, c); auto rhs = makeMatrixFromVector({{0., 1., 2., 2., 3.}}); - Matrix x{1, bout::testing::reduction_size}; + Matrix x{1, reduction_size}; reduce.solve(rhs, x); - EXPECT_NEAR(x(0, 0), -1., bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x(0, 1), 2.5, bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x(0, 2), -4., bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x(0, 3), 5.75, bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x(0, 4), -2.75, bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(0, 0), -1., CyclicReduceTolerance); + EXPECT_NEAR(x(0, 1), 2.5, CyclicReduceTolerance); + EXPECT_NEAR(x(0, 2), -4., CyclicReduceTolerance); + EXPECT_NEAR(x(0, 3), 5.75, CyclicReduceTolerance); + EXPECT_NEAR(x(0, 4), -2.75, CyclicReduceTolerance); } TEST(CyclicReduction, SerialSolveDoubleMatrix) { - CyclicReduce reduce{BoutComm::get(), bout::testing::reduction_size}; + using namespace bout::testing; + CyclicReduce reduce{BoutComm::get(), reduction_size}; auto a = makeMatrixFromVector({{0., 1., 1., 1., 1.}, {0., -2., -2., -2., -2.}}); auto b = makeMatrixFromVector({{5., 4., 3., 2., 1.}, {1., 1., 1., 1., 1.}}); @@ -89,18 +92,18 @@ TEST(CyclicReduction, SerialSolveDoubleMatrix) { reduce.setCoefs(a, b, c); auto rhs = makeMatrixFromVector({{0., 1., 2., 2., 3.}, {5., 4., 5., 4., 5.}}); - Matrix x{2, bout::testing::reduction_size}; + Matrix x{2, reduction_size}; reduce.solve(rhs, x); - EXPECT_NEAR(x(0, 0), -1., bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x(0, 1), 2.5, bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x(0, 2), -4., bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x(0, 3), 5.75, bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x(0, 4), -2.75, bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x(1, 0), 3.4, bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x(1, 1), 0.8, bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x(1, 2), 5., bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x(1, 3), 0.8, bout::testing::CyclicReduceTolerance); - EXPECT_NEAR(x(1, 4), 6.6, bout::testing::CyclicReduceTolerance); + EXPECT_NEAR(x(0, 0), -1., CyclicReduceTolerance); + EXPECT_NEAR(x(0, 1), 2.5, CyclicReduceTolerance); + EXPECT_NEAR(x(0, 2), -4., CyclicReduceTolerance); + EXPECT_NEAR(x(0, 3), 5.75, CyclicReduceTolerance); + EXPECT_NEAR(x(0, 4), -2.75, CyclicReduceTolerance); + EXPECT_NEAR(x(1, 0), 3.4, CyclicReduceTolerance); + EXPECT_NEAR(x(1, 1), 0.8, CyclicReduceTolerance); + EXPECT_NEAR(x(1, 2), 5., CyclicReduceTolerance); + EXPECT_NEAR(x(1, 3), 0.8, CyclicReduceTolerance); + EXPECT_NEAR(x(1, 4), 6.6, CyclicReduceTolerance); } From fa4c5e4510359c4be6374d92367852213403ac58 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 15:47:05 +0000 Subject: [PATCH 0962/1783] Dedicated enum classes for direction types of Fields Also always use the same default types (directions.y == YDirectionType::Standard) so Field initialization does not depend on the ParallelTransform. --- include/bout/paralleltransform.hxx | 12 +- include/bout_types.hxx | 36 ++++-- include/field.hxx | 50 +++----- include/field2d.hxx | 9 +- include/field3d.hxx | 7 +- include/fieldperp.hxx | 10 +- src/field/field.cxx | 25 +--- src/field/field2d.cxx | 8 +- src/field/field3d.cxx | 10 +- src/field/fieldperp.cxx | 12 +- src/mesh/interpolation/bilinear.cxx | 5 +- src/mesh/interpolation/hermite_spline.cxx | 10 +- src/mesh/interpolation/lagrange_4pt.cxx | 4 +- src/mesh/parallel/fci.cxx | 8 +- src/mesh/parallel/fci.hxx | 4 - src/mesh/parallel/shiftedmetric.cxx | 16 +-- src/sys/bout_types.cxx | 116 ++++-------------- tests/unit/field/test_field.cxx | 2 +- .../unit/mesh/parallel/test_shiftedmetric.cxx | 4 +- 19 files changed, 108 insertions(+), 240 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index cf6c0325c8..09b654f544 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -46,8 +46,6 @@ public: virtual bool canToFromFieldAligned() = 0; - virtual DIRECTION getDefaultYDirectionType() const = 0; - protected: /// This method should be called in the constructor to check that if the grid /// has a 'coordinates_type' variable, it has the correct value @@ -95,10 +93,6 @@ public: return true; } - DIRECTION getDefaultYDirectionType() const override { - return DIRECTION::YAligned; - } - protected: void checkInputGrid() override; }; @@ -145,10 +139,6 @@ public: return true; } - DIRECTION getDefaultYDirectionType() const override { - return DIRECTION::YOrthogonal; - } - protected: void checkInputGrid() override; @@ -209,7 +199,7 @@ private: * @param[in] y_direction_out The value to set yDirectionType of the result to */ const Field3D shiftZ(const Field3D& f, const Tensor& phs, - const DIRECTION y_direction_out, + const YDirectionType y_direction_out, const REGION region = RGN_NOX) const; /*! diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 563c397d25..d7935c9ef5 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -55,15 +55,34 @@ const std::string& REGION_STRING(REGION region); /// - YOrthogonal is a special case of Y, indicating a grid where the x and z /// axes are orthogonal but the y-direction is not necessarily /// field-aligned -/// - Special is used when the DIRECTION is an attribute of a Field, -/// indicating that that field does not have that direction, e.g. Field2D -/// does not have a z-direction -/// - Null indicates an uninitialized DIRECTION -enum class DIRECTION { X, Y, Z, YAligned, YOrthogonal, Special, Null }; +enum class DIRECTION { X, Y, Z, YAligned, YOrthogonal }; const std::string& DIRECTION_STRING(DIRECTION direction); -void swap(DIRECTION& first, DIRECTION& second); +/// Identify kind of a field's y-direction +/// - Standard is the default for the Mesh/Coordinates/ParallelTransform +/// - Aligned indicates that the field has been transformed to field-aligned +/// coordinates +enum class YDirectionType { Standard, Aligned }; + +/// Identify kind of a field's z-direction +/// - Standard is the default +/// - Average indicates that the field represents an average over the +/// z-direction, rather than having a particular z-position (i.e. is a +/// Field2D) +enum class ZDirectionType { Standard, Average }; + +/// Container for direction types +struct DirectionTypes { + YDirectionType y; + ZDirectionType z; +}; + +/// Check whether direction types are compatible, so two fields with attributes +/// d1 and d2 respectively can be added, subtracted, etc. +bool compatibleDirections(const DirectionTypes& d1, const DirectionTypes& d2); + +void swap(const DirectionTypes& first, const DirectionTypes& second); /// To identify valid staggering combinations enum class STAGGER { None, C2L, L2C }; @@ -88,9 +107,4 @@ struct enumWrapper { /// Boundary condition function using FuncPtr = BoutReal(*)(BoutReal t, BoutReal x, BoutReal y, BoutReal z); -bool compatibleDirections(DIRECTION d1, DIRECTION d2); -bool isXDirectionType(DIRECTION x); -bool isYDirectionType(DIRECTION y); -bool isZDirectionType(DIRECTION z); - #endif // __BOUT_TYPES_H__ diff --git a/include/field.hxx b/include/field.hxx index 9cf07828fb..c6e24b56b5 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -57,15 +57,13 @@ class Field { public: Field() = default; - Field(Mesh* localmesh, CELL_LOC location_in, DIRECTION xDirectionType_in, - DIRECTION yDirectionType_in, DIRECTION zDirectionType_in); + Field(Mesh* localmesh, CELL_LOC location_in, DirectionTypes directions_in); // Copy constructor Field(const Field& f) : name(f.name), fieldmesh(f.fieldmesh), fieldCoordinates(f.fieldCoordinates), location(f.location), - xDirectionType(f.xDirectionType), yDirectionType(f.yDirectionType), - zDirectionType(f.zDirectionType) {} + directions(f.directions) {} virtual ~Field() { } @@ -79,14 +77,11 @@ class Field { CELL_LOC getLocation() const; /// Getters for DIRECTION types - DIRECTION getDirectionX() const { - return xDirectionType; + YDirectionType getDirectionY() const { + return directions.y; } - DIRECTION getDirectionY() const { - return yDirectionType; - } - DIRECTION getDirectionZ() const { - return zDirectionType; + ZDirectionType getDirectionZ() const { + return directions.z; } std::string name; @@ -151,9 +146,7 @@ class Field { swap(first.fieldmesh, second.fieldmesh); swap(first.fieldCoordinates, second.fieldCoordinates); swap(first.location, second.location); - swap(first.xDirectionType, second.xDirectionType); - swap(first.yDirectionType, second.yDirectionType); - swap(first.zDirectionType, second.zDirectionType); + swap(first.directions, second.directions); } friend bool fieldsCompatible(const Field& field1, const Field& field2) { @@ -168,9 +161,7 @@ class Field { field1.getMesh() == field2.getMesh() && field1.getLocation() == field2.getLocation() && // Compatible directions - compatibleDirections(field1.xDirectionType, field2.xDirectionType) - && compatibleDirections(field1.yDirectionType, field2.yDirectionType) - && compatibleDirections(field1.zDirectionType, field2.zDirectionType); + compatibleDirections(field1.directions, field2.directions); } protected: Mesh* fieldmesh{nullptr}; @@ -179,36 +170,25 @@ protected: /// Location of the variable in the cell CELL_LOC location{CELL_CENTRE}; - /// Set any direction types which are DIRECTION::Null to default values from - /// fieldmesh. - void setNullDirectionTypesToDefault(); - /// Copy the members from another Field void copyFieldMembers(const Field& f) { name = f.name; fieldmesh = f.fieldmesh; fieldCoordinates = f.fieldCoordinates; location = f.location; - xDirectionType = f.xDirectionType; - yDirectionType = f.yDirectionType; - zDirectionType = f.zDirectionType; + directions = f.directions; } /// Setters for *DirectionType - void setDirectionX(DIRECTION d) { - xDirectionType = d; - } - void setDirectionY(DIRECTION d) { - yDirectionType = d; + void setDirectionY(YDirectionType y_type) { + directions.y = y_type; } - void setDirectionZ(DIRECTION d) { - zDirectionType = d; + void setDirectionZ(ZDirectionType z_type) { + directions.z = z_type; } private: - DIRECTION xDirectionType{DIRECTION::Null}; - DIRECTION yDirectionType{DIRECTION::Null}; - DIRECTION zDirectionType{DIRECTION::Null}; + DirectionTypes directions{YDirectionType::Standard, ZDirectionType::Standard}; }; /// Return an empty shell field of some type derived from Field, with metadata @@ -216,7 +196,7 @@ private: template inline T emptyFrom(const T& f) { static_assert(std::is_base_of::value, "emptyFrom only works on Fields"); - return T(f.getMesh(), f.getLocation(), f.getDirectionX(), f.getDirectionY(), f.getDirectionZ()).allocate(); + return T(f.getMesh(), f.getLocation(), {f.getDirectionY(), f.getDirectionZ()}).allocate(); } /// Unary + operator. This doesn't do anything diff --git a/include/field2d.hxx b/include/field2d.hxx index ccc481b1b1..8cab6ff4ba 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -64,9 +64,8 @@ class Field2D : public Field, public FieldData { * By default the global Mesh pointer (mesh) is used. */ Field2D(Mesh *localmesh = nullptr, CELL_LOC location_in=CELL_CENTRE, - DIRECTION xDirectionType_in=DIRECTION::Null, - DIRECTION yDirectionType_in=DIRECTION::Y, - DIRECTION zDirectionType_in=DIRECTION::Special); + DirectionTypes directions_in = + {YDirectionType::Standard, ZDirectionType::Average}); /*! * Copy constructor. After this both fields @@ -119,10 +118,6 @@ class Field2D : public Field, public FieldData { Field::setLocation(location); return *this; } - Field2D& setDirectionY(DIRECTION d) { - Field::setDirectionY(d); - return *this; - } /// Check if this field has yup and ydown fields bool hasYupYdown() const { diff --git a/include/field3d.hxx b/include/field3d.hxx index c43a5cb9b6..a4f5fcb582 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -168,9 +168,8 @@ class Field3D : public Field, public FieldData { * fields may be created before the mesh is. */ Field3D(Mesh *localmesh = nullptr, CELL_LOC location_in=CELL_CENTRE, - DIRECTION xDirectionType_in=DIRECTION::Null, - DIRECTION yDirectionType_in=DIRECTION::Null, - DIRECTION zDirectionType_in=DIRECTION::Null); + DirectionTypes directions_in = + {YDirectionType::Standard, ZDirectionType::Standard}); /*! * Copy constructor @@ -225,7 +224,7 @@ class Field3D : public Field, public FieldData { Field::setLocation(location); return *this; } - Field3D& setDirectionY(DIRECTION d) { + Field3D& setDirectionY(YDirectionType d) { Field::setDirectionY(d); return *this; } diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 43db0ba7b8..d862283e19 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -53,9 +53,9 @@ class FieldPerp : public Field { * Constructor */ FieldPerp(Mesh * fieldmesh = nullptr, CELL_LOC location_in=CELL_CENTRE, - int yindex_in=-1, DIRECTION xDirectionType_in=DIRECTION::Null, - DIRECTION yDirectionType_in=DIRECTION::Null, - DIRECTION zDirectionType_in=DIRECTION::Null); + int yindex_in=-1, + DirectionTypes directions_in = + {YDirectionType::Standard, ZDirectionType::Standard}); /*! * Copy constructor. After this the data @@ -125,7 +125,7 @@ class FieldPerp : public Field { Field::setLocation(location); return *this; } - FieldPerp& setDirectionY(DIRECTION d) { + FieldPerp& setDirectionY(YDirectionType d) { Field::setDirectionY(d); return *this; } @@ -423,7 +423,7 @@ bool finite(const FieldPerp &f, REGION rgn=RGN_ALL); /// copied but empty data array template<> inline FieldPerp emptyFrom(const FieldPerp& f) { - return FieldPerp(f.getMesh(), f.getLocation(), f.getIndex(), f.getDirectionX(), f.getDirectionY(), f.getDirectionZ()).allocate(); + return FieldPerp(f.getMesh(), f.getLocation(), f.getIndex(), {f.getDirectionY(), f.getDirectionZ()}).allocate(); } #if CHECK > 0 diff --git a/src/field/field.cxx b/src/field/field.cxx index d2aa21b15f..adc7c11985 100644 --- a/src/field/field.cxx +++ b/src/field/field.cxx @@ -33,11 +33,9 @@ #include Field::Field(Mesh *localmesh, CELL_LOC location_in, - DIRECTION xDirectionType_in, DIRECTION yDirectionType_in, - DIRECTION zDirectionType_in) + DirectionTypes directions_in) : fieldmesh(localmesh==nullptr ? bout::globals::mesh : localmesh), - location(location_in), xDirectionType(xDirectionType_in), - yDirectionType(yDirectionType_in), zDirectionType(zDirectionType_in) { + location(location_in), directions(directions_in) { // Need to check for nullptr again, because the fieldmesh might still be // nullptr if the global mesh hasn't been initialized yet @@ -45,11 +43,6 @@ Field::Field(Mesh *localmesh, CELL_LOC location_in, // sets fieldCoordinates by getting Coordinates for our location from // fieldmesh getCoordinates(); - - // Get default values for xDirectionType, yDirectionType and - // zDirectionType, if explicit values have not been passed to the - // constructor - setNullDirectionTypesToDefault(); } } @@ -112,17 +105,3 @@ int Field::getNy() const{ int Field::getNz() const{ return getMesh()->LocalNz; }; - -void Field::setNullDirectionTypesToDefault() { - ASSERT1(fieldmesh != nullptr); - - if (xDirectionType == DIRECTION::Null) { - xDirectionType = DIRECTION::X; - } - if (yDirectionType == DIRECTION::Null) { - yDirectionType = fieldmesh->getParallelTransform().getDefaultYDirectionType(); - } - if (zDirectionType == DIRECTION::Null) { - zDirectionType = DIRECTION::Z; - } -} diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 077d3b83d2..5652b1e92f 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -47,10 +47,8 @@ #include Field2D::Field2D(Mesh* localmesh, CELL_LOC location_in, - DIRECTION xDirectionType_in, DIRECTION yDirectionType_in, DIRECTION - zDirectionType_in) - : Field(localmesh, location_in, xDirectionType_in, yDirectionType_in, - zDirectionType_in) { + DirectionTypes directions_in) + : Field(localmesh, location_in, directions_in) { if (fieldmesh) { nx = fieldmesh->LocalNx; @@ -98,8 +96,6 @@ Field2D& Field2D::allocate() { fieldmesh = bout::globals::mesh; nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; - - setNullDirectionTypesToDefault(); } data = Array(nx*ny); #if CHECK > 2 diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 853511f6d2..7d5504f4bc 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -45,10 +45,8 @@ /// Constructor Field3D::Field3D(Mesh* localmesh, CELL_LOC location_in, - DIRECTION xDirectionType_in, DIRECTION yDirectionType_in, - DIRECTION zDirectionType_in) - : Field(localmesh, location_in, xDirectionType_in, yDirectionType_in, - zDirectionType_in) { + DirectionTypes directions_in) + : Field(localmesh, location_in, directions_in) { #ifdef TRACK name = ""; #endif @@ -114,8 +112,6 @@ Field3D& Field3D::allocate() { nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; - - setNullDirectionTypesToDefault(); } data = Array(nx*ny*nz); #if CHECK > 2 @@ -257,7 +253,7 @@ Field3D & Field3D::operator=(const Field2D &rhs) { /// Check that the data is allocated ASSERT1(rhs.isAllocated()); - setLocation(rhs.getLocation()); + setLocation(rhs.getLocation()); /// Make sure there's a unique array to copy data into allocate(); diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index b6f2a724e6..dacc6e9e81 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -35,10 +35,8 @@ #include FieldPerp::FieldPerp(Mesh *localmesh, CELL_LOC location_in, int yindex_in, - DIRECTION xDirectionType_in, DIRECTION yDirectionType_in, - DIRECTION zDirectionType_in) - : Field(localmesh, location_in, xDirectionType_in, yDirectionType_in, - zDirectionType_in), + DirectionTypes directions) + : Field(localmesh, location_in, directions), yindex(yindex_in) { if (fieldmesh) { nx = fieldmesh->LocalNx; @@ -58,8 +56,6 @@ FieldPerp& FieldPerp::allocate() { fieldmesh = bout::globals::mesh; nx = fieldmesh->LocalNx; nz = fieldmesh->LocalNz; - - setNullDirectionTypesToDefault(); } data = Array(nx * nz); #if CHECK > 2 @@ -338,8 +334,8 @@ const FieldPerp sliceXZ(const Field3D& f, int y) { // Source field should be valid checkData(f); - FieldPerp result(f.getMesh(), f.getLocation(), y, f.getDirectionX(), - f.getDirectionY(), f.getDirectionZ()); + FieldPerp result(f.getMesh(), f.getLocation(), y, + {f.getDirectionY(), f.getDirectionZ()}); // Allocate memory result.allocate(); diff --git a/src/mesh/interpolation/bilinear.cxx b/src/mesh/interpolation/bilinear.cxx index af1a2fc092..926f78db94 100644 --- a/src/mesh/interpolation/bilinear.cxx +++ b/src/mesh/interpolation/bilinear.cxx @@ -29,10 +29,7 @@ Bilinear::Bilinear(int y_offset, Mesh *mesh) : Interpolation(y_offset, mesh), - w0(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), - w1(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), - w2(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), - w3(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z) { + w0(localmesh), w1(localmesh), w2(localmesh), w3(localmesh) { // Index arrays contain guard cells in order to get subscripts right i_corner = Tensor(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); diff --git a/src/mesh/interpolation/hermite_spline.cxx b/src/mesh/interpolation/hermite_spline.cxx index 241e98756a..8b40ed5802 100644 --- a/src/mesh/interpolation/hermite_spline.cxx +++ b/src/mesh/interpolation/hermite_spline.cxx @@ -29,14 +29,8 @@ HermiteSpline::HermiteSpline(int y_offset, Mesh *mesh) : Interpolation(y_offset, mesh), - h00_x(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), - h01_x(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), - h10_x(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), - h11_x(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), - h00_z(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), - h01_z(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), - h10_z(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), - h11_z(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z) { + h00_x(localmesh), h01_x(localmesh), h10_x(localmesh), h11_x(localmesh), + h00_z(localmesh), h01_z(localmesh), h10_z(localmesh), h11_z(localmesh) { // Index arrays contain guard cells in order to get subscripts right i_corner = Tensor(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); diff --git a/src/mesh/interpolation/lagrange_4pt.cxx b/src/mesh/interpolation/lagrange_4pt.cxx index ffd861fa2c..b288653445 100644 --- a/src/mesh/interpolation/lagrange_4pt.cxx +++ b/src/mesh/interpolation/lagrange_4pt.cxx @@ -27,9 +27,7 @@ #include Lagrange4pt::Lagrange4pt(int y_offset, Mesh *mesh) - : Interpolation(y_offset, mesh), - t_x(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z), - t_z(localmesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z) { + : Interpolation(y_offset, mesh), t_x(localmesh), t_z(localmesh) { // Index arrays contain guard cells in order to get subscripts right i_corner = Tensor(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz); diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 724b4f77f7..c39e38540a 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -73,7 +73,7 @@ FCIMap::FCIMap(Mesh& mesh, int offset_, BoundaryRegionPar* boundary, bool zperio auto k_corner = Tensor(map_mesh.LocalNx, map_mesh.LocalNy, map_mesh.LocalNz); // Index-space coordinates of forward/backward points - Field3D xt_prime(&map_mesh, CELL_CENTRE, DIRECTION::X, DIRECTION::YOrthogonal, DIRECTION::Z); + Field3D xt_prime(&map_mesh); Field3D zt_prime{emptyFrom(xt_prime)}; // Real-space coordinates of grid points @@ -266,7 +266,7 @@ FCIMap::FCIMap(Mesh& mesh, int offset_, BoundaryRegionPar* boundary, bool zperio Field3D FCIMap::integrate(Field3D &f) const { TRACE("FCIMap::integrate"); - ASSERT1(f.getDirectionY() == DIRECTION::YOrthogonal); + ASSERT1(f.getDirectionY() == YDirectionType::Standard); ASSERT1(&map_mesh == f.getMesh()); // Cell centre values @@ -336,7 +336,7 @@ void FCITransform::checkInputGrid() { void FCITransform::calcYUpDown(Field3D& f) { TRACE("FCITransform::calcYUpDown"); - ASSERT1(f.getDirectionY() == DIRECTION::YOrthogonal); + ASSERT1(f.getDirectionY() == YDirectionType::Standard); // Only have forward_map/backward_map for CELL_CENTRE, so can only deal with // CELL_CENTRE inputs ASSERT1(f.getLocation() == CELL_CENTRE); @@ -353,7 +353,7 @@ void FCITransform::calcYUpDown(Field3D& f) { void FCITransform::integrateYUpDown(Field3D& f) { TRACE("FCITransform::integrateYUpDown"); - ASSERT1(f.getDirectionY() == DIRECTION::YOrthogonal); + ASSERT1(f.getDirectionY() == YDirectionType::Standard); // Only have forward_map/backward_map for CELL_CENTRE, so can only deal with // CELL_CENTRE inputs ASSERT1(f.getLocation() == CELL_CENTRE); diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index f2e22c241d..a4bd0aa2f5 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -107,10 +107,6 @@ protected: void checkInputGrid() override; - DIRECTION getDefaultYDirectionType() const override { - return DIRECTION::YOrthogonal; - } - private: /// FCI maps for each of the parallel slices std::vector field_line_maps; diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 84c74a8fea..670f38dce5 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -137,9 +137,9 @@ void ShiftedMetric::cachePhases() { */ const Field3D ShiftedMetric::toFieldAligned(const Field3D& f, const REGION region) { switch (f.getDirectionY()) { - case (DIRECTION::YOrthogonal): - return shiftZ(f, toAlignedPhs, DIRECTION::YAligned, region); - case (DIRECTION::YAligned): + case (YDirectionType::Standard): + return shiftZ(f, toAlignedPhs, YDirectionType::Aligned, region); + case (YDirectionType::Aligned): // f is already in field-aligned coordinates return f; default: @@ -156,9 +156,9 @@ const Field3D ShiftedMetric::toFieldAligned(const Field3D& f, const REGION regio */ const Field3D ShiftedMetric::fromFieldAligned(const Field3D& f, const REGION region) { switch (f.getDirectionY()) { - case (DIRECTION::YAligned): - return shiftZ(f, fromAlignedPhs, DIRECTION::YOrthogonal, region); - case (DIRECTION::YOrthogonal): + case (YDirectionType::Aligned): + return shiftZ(f, fromAlignedPhs, YDirectionType::Standard, region); + case (YDirectionType::Standard): // f is already in orthogonal coordinates return f; default: @@ -170,7 +170,7 @@ const Field3D ShiftedMetric::fromFieldAligned(const Field3D& f, const REGION reg } const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Tensor& phs, - const DIRECTION y_direction_out, + const YDirectionType y_direction_out, const REGION region) const { ASSERT1(&mesh == f.getMesh()); // only have zShift for CELL_CENTRE, so can only deal with CELL_CENTRE inputs @@ -208,7 +208,7 @@ void ShiftedMetric::shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* ou void ShiftedMetric::calcYUpDown(Field3D& f) { - ASSERT1(f.getDirectionY() == DIRECTION::YOrthogonal); + ASSERT1(f.getDirectionY() == YDirectionType::Standard); ASSERT1(&mesh == f.getMesh()); // only have zShift for CELL_CENTRE, so can only deal with CELL_CENTRE inputs ASSERT1(f.getLocation() == CELL_CENTRE); diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index efef63968c..0a57c9279a 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -48,18 +48,41 @@ const std::string& DIRECTION_STRING(DIRECTION direction) { {DIRECTION::Y, "Y"}, {DIRECTION::Z, "Z"}, {DIRECTION::YAligned, "Y - field aligned"}, - {DIRECTION::YOrthogonal, "Y - orthogonal"}, - {DIRECTION::Special, "Special"}}; + {DIRECTION::YOrthogonal, "Y - orthogonal"}}; return safeAt(DIRECTIONtoString, direction); } -void swap(DIRECTION& first, DIRECTION& second) { - DIRECTION temp = first; +void swap(DirectionTypes& first, DirectionTypes& second) { + DirectionTypes temp = first; first = second; second = temp; } +bool compatibleDirections(const DirectionTypes& d1, const DirectionTypes& d2) { + if (d1.y == d2.y && d1.z == d2.z) { + // direction types are the same, most common case, return immediately + return true; + } + + if (d2.z == ZDirectionType::Average && d2.y == YDirectionType::Standard + && (d1.y == YDirectionType::Standard || d1.y == YDirectionType::Aligned)) { + // If a field has ZDirectionType::Average, then it's compatible with + // YDirectionType::Aligned as well as YDirectionType::Standard + return true; + } + + if (d1.z == ZDirectionType::Average && d1.y == YDirectionType::Standard + && (d2.y == YDirectionType::Standard || d2.y == YDirectionType::Aligned)) { + // If a field has ZDirectionType::Average, then it's compatible with + // YDirectionType::Aligned as well as YDirectionType::Standard + return true; + } + + // No compatible cases found + return false; +} + const std::string& STAGGER_STRING(STAGGER stagger) { AUTO_TRACE(); const static std::map STAGGERtoString = { @@ -81,88 +104,3 @@ const std::string& DERIV_STRING(DERIV deriv) { return safeAt(DERIVtoString, deriv); } - -bool isXDirectionType(DIRECTION x) { - switch (x) { - case (DIRECTION::X): - return true; - default: - return false; - } -} - -bool isYDirectionType(DIRECTION y) { - switch (y) { - case (DIRECTION::Y): - case (DIRECTION::YAligned): - case (DIRECTION::YOrthogonal): - return true; - default: - return false; - } -} - -bool isZDirectionType(DIRECTION z) { - switch (z) { - case (DIRECTION::Z): - return true; - default: - return false; - } -} - -bool compatibleDirections(DIRECTION d1, DIRECTION d2) { - switch (d1) { - case (DIRECTION::X): { - switch (d2) { - case (DIRECTION::X): - case (DIRECTION::Special): - return true; - default: - return false; - } - } - case (DIRECTION::Y): - switch (d2) { - case (DIRECTION::Y): - case (DIRECTION::YAligned): - case (DIRECTION::YOrthogonal): - case (DIRECTION::Special): - return true; - default: - return false; - } - case (DIRECTION::YAligned): - switch (d2) { - case (DIRECTION::Y): - case (DIRECTION::YAligned): - case (DIRECTION::Special): - return true; - default: - return false; - } - case (DIRECTION::YOrthogonal): - switch (d2) { - case (DIRECTION::Y): - case (DIRECTION::YOrthogonal): - case (DIRECTION::Special): - return true; - default: - return false; - } - case (DIRECTION::Z): - switch (d2) { - case (DIRECTION::Z): - case (DIRECTION::Special): - return true; - default: - return false; - } - case (DIRECTION::Special): - return true; - default: - // Shouldn't reach this due to checks at start but in case - // of future changes good to handle here. - throw BoutException("Invalid y direction value"); - } -} diff --git a/tests/unit/field/test_field.cxx b/tests/unit/field/test_field.cxx index 061895e981..a82d5599ff 100644 --- a/tests/unit/field/test_field.cxx +++ b/tests/unit/field/test_field.cxx @@ -31,7 +31,7 @@ TEST_F(FieldTest, GetGlobalMesh) { TEST_F(FieldTest, GetLocalMesh) { FakeMesh myMesh{nx + 1, ny + 2, nz + 3}; - Field field(&myMesh, CELL_CENTRE, DIRECTION::X, DIRECTION::Y, DIRECTION::Z); + Field field(&myMesh, CELL_CENTRE, {YDirectionType::Standard, ZDirectionType::Standard}); auto localmesh = field.getMesh(); diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 138dc7d845..28a75c8dc2 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -125,10 +125,10 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { TEST_F(ShiftedMetricTest, FromFieldAligned) { // reset input.yDirectionType so that fromFieldAligned is not a null // operation - input.setDirectionY(DIRECTION::YAligned); + input.setDirectionY(YDirectionType::Aligned); Field3D expected{mesh, CELL_CENTRE}; - expected.setDirectionY(DIRECTION::YOrthogonal); + expected.setDirectionY(YDirectionType::Standard); fillField(expected, {{{5., 1., 2., 3., 4.}, {4., 5., 2., 1., 3.}, From 0cce881a52ff9cc77ed3f7e6fde9bbbe029e04c0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 16:39:53 +0000 Subject: [PATCH 0963/1783] More unit tests for to/fromFieldAligned Check that fromFieldAligned does nothing on a standard field, and toFieldAligned does nothing on an already-aligned field. Check that fromFieldAligned(toFieldAligned(input))~input; and toFieldAligned(fromFieldAligned(input))~input. Helps to check that YDirectionTypes are being set consistently. --- .../unit/mesh/parallel/test_shiftedmetric.cxx | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 28a75c8dc2..d2a276ae31 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -93,6 +93,7 @@ class ShiftedMetricTest : public ::testing::Test { TEST_F(ShiftedMetricTest, ToFieldAligned) { Field3D expected{mesh}; + expected.setDirectionY(YDirectionType::Aligned); fillField(expected, {{{2., 3., 4., 5., 1.}, {3., 4., 5., 2., 1.}, @@ -118,8 +119,13 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { {4., 5., 1., 3., 2.}, {2., 4., 3., 5., 1.}}}); - EXPECT_TRUE(IsFieldEqual(mesh->toFieldAligned(input), expected, "RGN_ALL", + Field3D result = mesh->toFieldAligned(input); + + EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_ALL", FFTTolerance)); + EXPECT_TRUE(IsFieldEqual(mesh->fromFieldAligned(input), input)); + EXPECT_TRUE(fieldsCompatible(result, expected)); + EXPECT_FALSE(fieldsCompatible(result, input)); } TEST_F(ShiftedMetricTest, FromFieldAligned) { @@ -157,12 +163,25 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { Field3D result = mesh->fromFieldAligned(input); // Loosen tolerance a bit due to FFTs - EXPECT_TRUE(IsFieldEqual(mesh->fromFieldAligned(input), expected, "RGN_ALL", + EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_ALL", FFTTolerance)); + EXPECT_TRUE(IsFieldEqual(mesh->toFieldAligned(input), input)); EXPECT_TRUE(fieldsCompatible(result, expected)); EXPECT_FALSE(fieldsCompatible(result, input)); } +TEST_F(ShiftedMetricTest, FromToFieldAligned) { + EXPECT_TRUE(IsFieldEqual(mesh->fromFieldAligned(mesh->toFieldAligned(input)), input, "RGN_ALL", + FFTTolerance)); +} + +TEST_F(ShiftedMetricTest, ToFromFieldAligned) { + input.setDirectionY(YDirectionType::Aligned); + + EXPECT_TRUE(IsFieldEqual(mesh->toFieldAligned(mesh->fromFieldAligned(input)), input, "RGN_ALL", + FFTTolerance)); +} + TEST_F(ShiftedMetricTest, CalcYUpDown) { // We don't shift in the guard cells, and the parallel slices are // stored offset in y, therefore we need to make new regions that we From fc6530608312f7606dfe666dfafc45877870f4e4 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 17:00:39 +0000 Subject: [PATCH 0964/1783] Rename compatibleDirections -> areDirectionsCompatible Makes function name verb-like. --- include/bout_types.hxx | 2 +- include/field.hxx | 2 +- src/sys/bout_types.cxx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index d7935c9ef5..bb8e49d7c7 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -80,7 +80,7 @@ struct DirectionTypes { /// Check whether direction types are compatible, so two fields with attributes /// d1 and d2 respectively can be added, subtracted, etc. -bool compatibleDirections(const DirectionTypes& d1, const DirectionTypes& d2); +bool areDirectionsCompatible(const DirectionTypes& d1, const DirectionTypes& d2); void swap(const DirectionTypes& first, const DirectionTypes& second); diff --git a/include/field.hxx b/include/field.hxx index c6e24b56b5..88680e5924 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -161,7 +161,7 @@ class Field { field1.getMesh() == field2.getMesh() && field1.getLocation() == field2.getLocation() && // Compatible directions - compatibleDirections(field1.directions, field2.directions); + areDirectionsCompatible(field1.directions, field2.directions); } protected: Mesh* fieldmesh{nullptr}; diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index 0a57c9279a..a8774784a6 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -59,7 +59,7 @@ void swap(DirectionTypes& first, DirectionTypes& second) { second = temp; } -bool compatibleDirections(const DirectionTypes& d1, const DirectionTypes& d2) { +bool areDirectionsCompatible(const DirectionTypes& d1, const DirectionTypes& d2) { if (d1.y == d2.y && d1.z == d2.z) { // direction types are the same, most common case, return immediately return true; From a1c89a8e605c4f24ea64a4ae00c5b306480e832d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 17:09:02 +0000 Subject: [PATCH 0965/1783] Make fieldsCompatible non-friend, rename to areFieldsCompatible Rename to make the function name a verb. Move outside the Field class as we have enough getters so areFieldsCompatible does not need to be a friend function. --- include/bout/fv_ops.hxx | 6 +- include/field.hxx | 27 ++++----- src/field/field2d.cxx | 2 +- src/field/field3d.cxx | 12 ++-- src/field/fieldperp.cxx | 12 ++-- src/field/gen_fieldops.jinja | 4 +- src/field/generated_fieldops.cxx | 56 +++++++++---------- src/field/where.cxx | 26 ++++----- src/mesh/difops.cxx | 12 ++-- src/mesh/fv_ops.cxx | 2 +- src/solver/solver.cxx | 2 +- .../unit/mesh/parallel/test_shiftedmetric.cxx | 8 +-- 12 files changed, 83 insertions(+), 86 deletions(-) diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index e5bc6934ce..44febce590 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -181,8 +181,8 @@ namespace FV { const Field3D Div_par(const Field3D &f_in, const Field3D &v_in, const Field3D &wave_speed, bool fixflux=true) { - ASSERT1(fieldsCompatible(f_in, v_in)); - ASSERT1(fieldsCompatible(f_in, wave_speed)); + ASSERT1(areFieldsCompatible(f_in, v_in)); + ASSERT1(areFieldsCompatible(f_in, wave_speed)); Mesh* mesh = f_in.getMesh(); @@ -345,7 +345,7 @@ namespace FV { template const Field3D Div_f_v(const Field3D &n_in, const Vector3D &v, bool bndry_flux) { ASSERT1(n_in.getLocation() == v.getLocation()); - ASSERT1(fieldsCompatible(n_in, v.x)); + ASSERT1(areFieldsCompatible(n_in, v.x)); Mesh* mesh = n_in.getMesh(); diff --git a/include/field.hxx b/include/field.hxx index 88680e5924..577d8f1c6d 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -77,6 +77,9 @@ class Field { CELL_LOC getLocation() const; /// Getters for DIRECTION types + DirectionTypes getDirections() const { + return directions; + } YDirectionType getDirectionY() const { return directions.y; } @@ -148,21 +151,6 @@ class Field { swap(first.location, second.location); swap(first.directions, second.directions); } - - friend bool fieldsCompatible(const Field& field1, const Field& field2) { - return - // The following is a possible alternative to - // checking the two meshes and location are the same - // It is slightly stricter if we decide that coordinates - // could differ in more than just location. - field1.getCoordinates() == field2.getCoordinates() && - // In the unit tests fieldCoordinates get set to nullptr, so we still - // need to check fieldmesh and location, at least for now - field1.getMesh() == field2.getMesh() && - field1.getLocation() == field2.getLocation() && - // Compatible directions - areDirectionsCompatible(field1.directions, field2.directions); - } protected: Mesh* fieldmesh{nullptr}; mutable std::shared_ptr fieldCoordinates{nullptr}; @@ -191,6 +179,15 @@ private: DirectionTypes directions{YDirectionType::Standard, ZDirectionType::Standard}; }; +/// Check if Fields have compatible meta-data +inline bool areFieldsCompatible(const Field& field1, const Field& field2) { + return + field1.getCoordinates() == field2.getCoordinates() && + field1.getMesh() == field2.getMesh() && + field1.getLocation() == field2.getLocation() && + areDirectionsCompatible(field1.getDirections(), field2.getDirections()); +} + /// Return an empty shell field of some type derived from Field, with metadata /// copied but empty data array template diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 3420eec945..7d2ca6747f 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -435,7 +435,7 @@ Field2D pow(const Field2D &lhs, const Field2D &rhs, REGION rgn) { // Check if the inputs are allocated checkData(lhs); checkData(rhs); - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); // Define and allocate the output result Field2D result{emptyFrom(lhs)}; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index b8792e70b3..99bf28f966 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -240,7 +240,7 @@ Field3D & Field3D::operator=(const Field3D &rhs) { ny = rhs.ny; nz = rhs.nz; - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); data = rhs.data; @@ -257,7 +257,7 @@ Field3D & Field3D::operator=(const Field2D &rhs) { /// Make sure there's a unique array to copy data into allocate(); - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); /// Copy data BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] = rhs[i]; } @@ -268,7 +268,7 @@ Field3D & Field3D::operator=(const Field2D &rhs) { void Field3D::operator=(const FieldPerp &rhs) { TRACE("Field3D = FieldPerp"); - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); /// Check that the data is allocated ASSERT1(rhs.isAllocated()); @@ -567,7 +567,7 @@ Field3D operator-(const Field3D &f) { return -1.0 * f; } Field3D pow(const Field3D &lhs, const Field3D &rhs, REGION rgn) { TRACE("pow(Field3D, Field3D)"); - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; @@ -582,7 +582,7 @@ Field3D pow(const Field3D &lhs, const Field2D &rhs, REGION rgn) { // Check if the inputs are allocated checkData(lhs); checkData(rhs); - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); // Define and allocate the output result Field3D result{emptyFrom(lhs)}; @@ -598,7 +598,7 @@ FieldPerp pow(const Field3D &lhs, const FieldPerp &rhs, REGION rgn) { checkData(lhs); checkData(rhs); - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); FieldPerp result{emptyFrom(rhs)}; result.allocate(); diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 9fad24c288..937c0080bb 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -84,7 +84,7 @@ FieldPerp &FieldPerp::operator=(const FieldPerp &rhs) { yindex = rhs.yindex; data = rhs.data; - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); return *this; } @@ -105,7 +105,7 @@ FieldPerp & FieldPerp::operator=(const BoutReal rhs) { #define FPERP_OP_FPERP(op, bop) \ FieldPerp& FieldPerp::operator op(const FieldPerp& rhs) { \ - ASSERT1(fieldsCompatible(*this, rhs)); \ + ASSERT1(areFieldsCompatible(*this, rhs)); \ if (data.unique()) { \ checkData(rhs); \ /* Only reference to the data */ \ @@ -125,7 +125,7 @@ FPERP_OP_FPERP(/=, /); #define FPERP_OP_FIELD(op, bop, ftype) \ FieldPerp& FieldPerp::operator op(const ftype& rhs) { \ - ASSERT1(fieldsCompatible(*this, rhs)); \ + ASSERT1(areFieldsCompatible(*this, rhs)); \ if (data.unique()) { \ checkData(*this); \ checkData(rhs); \ @@ -187,7 +187,7 @@ FieldPerp operator-(const FieldPerp &f) { return -1.0 * f; } // Operator on FieldPerp and another field #define FPERP_FPERP_OP_FPERP(op) \ const FieldPerp operator op(const FieldPerp& lhs, const FieldPerp& rhs) { \ - ASSERT1(fieldsCompatible(lhs, rhs)); \ + ASSERT1(areFieldsCompatible(lhs, rhs)); \ checkData(lhs); \ checkData(rhs); \ FieldPerp result{emptyFrom(lhs)}; \ @@ -205,7 +205,7 @@ FPERP_FPERP_OP_FPERP(/); // Operator on FieldPerp and another field #define FPERP_FPERP_OP_FIELD(op, ftype) \ const FieldPerp operator op(const FieldPerp& lhs, const ftype& rhs) { \ - ASSERT1(fieldsCompatible(lhs, rhs)); \ + ASSERT1(areFieldsCompatible(lhs, rhs)); \ checkData(lhs); \ checkData(rhs); \ FieldPerp result{emptyFrom(lhs)}; \ @@ -414,7 +414,7 @@ FieldPerp pow(const FieldPerp &lhs, const FieldPerp &rhs, REGION rgn) { checkData(rhs); // Define and allocate the output result - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); FieldPerp result{emptyFrom(lhs)}; BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } diff --git a/src/field/gen_fieldops.jinja b/src/field/gen_fieldops.jinja index 4dcc9bc7c9..2f3c9d156c 100644 --- a/src/field/gen_fieldops.jinja +++ b/src/field/gen_fieldops.jinja @@ -1,7 +1,7 @@ // Provide the C++ wrapper for {{operator_name}} of {{lhs}} and {{rhs}} {{out}} operator{{operator}}(const {{lhs.passByReference}}, const {{rhs.passByReference}}) { {% if lhs != "BoutReal" and rhs != "BoutReal" %} - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); {% endif %} {{out.field_type}} {{out.name}}{emptyFrom({{lhs.name if lhs.field_type == out.field_type else rhs.name}})}; @@ -44,7 +44,7 @@ // otherwise just call the non-inplace version if (data.unique()) { {% if lhs != "BoutReal" and rhs != "BoutReal" %} - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); {% endif %} checkData(*this); diff --git a/src/field/generated_fieldops.cxx b/src/field/generated_fieldops.cxx index c009bb5d7c..50fa45796a 100644 --- a/src/field/generated_fieldops.cxx +++ b/src/field/generated_fieldops.cxx @@ -8,7 +8,7 @@ // Provide the C++ wrapper for multiplication of Field3D and Field3D Field3D operator*(const Field3D& lhs, const Field3D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -27,7 +27,7 @@ Field3D& Field3D::operator*=(const Field3D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -44,7 +44,7 @@ Field3D& Field3D::operator*=(const Field3D& rhs) { // Provide the C++ wrapper for division of Field3D and Field3D Field3D operator/(const Field3D& lhs, const Field3D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -63,7 +63,7 @@ Field3D& Field3D::operator/=(const Field3D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -80,7 +80,7 @@ Field3D& Field3D::operator/=(const Field3D& rhs) { // Provide the C++ wrapper for addition of Field3D and Field3D Field3D operator+(const Field3D& lhs, const Field3D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -99,7 +99,7 @@ Field3D& Field3D::operator+=(const Field3D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -116,7 +116,7 @@ Field3D& Field3D::operator+=(const Field3D& rhs) { // Provide the C++ wrapper for subtraction of Field3D and Field3D Field3D operator-(const Field3D& lhs, const Field3D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -135,7 +135,7 @@ Field3D& Field3D::operator-=(const Field3D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -152,7 +152,7 @@ Field3D& Field3D::operator-=(const Field3D& rhs) { // Provide the C++ wrapper for multiplication of Field3D and Field2D Field3D operator*(const Field3D& lhs, const Field2D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -176,7 +176,7 @@ Field3D& Field3D::operator*=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -198,7 +198,7 @@ Field3D& Field3D::operator*=(const Field2D& rhs) { // Provide the C++ wrapper for division of Field3D and Field2D Field3D operator/(const Field3D& lhs, const Field2D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -223,7 +223,7 @@ Field3D& Field3D::operator/=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -246,7 +246,7 @@ Field3D& Field3D::operator/=(const Field2D& rhs) { // Provide the C++ wrapper for addition of Field3D and Field2D Field3D operator+(const Field3D& lhs, const Field2D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -270,7 +270,7 @@ Field3D& Field3D::operator+=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -292,7 +292,7 @@ Field3D& Field3D::operator+=(const Field2D& rhs) { // Provide the C++ wrapper for subtraction of Field3D and Field2D Field3D operator-(const Field3D& lhs, const Field2D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -316,7 +316,7 @@ Field3D& Field3D::operator-=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -466,7 +466,7 @@ Field3D& Field3D::operator-=(const BoutReal rhs) { // Provide the C++ wrapper for multiplication of Field2D and Field3D Field3D operator*(const Field2D& lhs, const Field3D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(rhs)}; checkData(lhs); @@ -487,7 +487,7 @@ Field3D operator*(const Field2D& lhs, const Field3D& rhs) { // Provide the C++ wrapper for division of Field2D and Field3D Field3D operator/(const Field2D& lhs, const Field3D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(rhs)}; checkData(lhs); @@ -508,7 +508,7 @@ Field3D operator/(const Field2D& lhs, const Field3D& rhs) { // Provide the C++ wrapper for addition of Field2D and Field3D Field3D operator+(const Field2D& lhs, const Field3D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(rhs)}; checkData(lhs); @@ -529,7 +529,7 @@ Field3D operator+(const Field2D& lhs, const Field3D& rhs) { // Provide the C++ wrapper for subtraction of Field2D and Field3D Field3D operator-(const Field2D& lhs, const Field3D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field3D result{emptyFrom(rhs)}; checkData(lhs); @@ -550,7 +550,7 @@ Field3D operator-(const Field2D& lhs, const Field3D& rhs) { // Provide the C++ wrapper for multiplication of Field2D and Field2D Field2D operator*(const Field2D& lhs, const Field2D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -569,7 +569,7 @@ Field2D& Field2D::operator*=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -586,7 +586,7 @@ Field2D& Field2D::operator*=(const Field2D& rhs) { // Provide the C++ wrapper for division of Field2D and Field2D Field2D operator/(const Field2D& lhs, const Field2D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -605,7 +605,7 @@ Field2D& Field2D::operator/=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -622,7 +622,7 @@ Field2D& Field2D::operator/=(const Field2D& rhs) { // Provide the C++ wrapper for addition of Field2D and Field2D Field2D operator+(const Field2D& lhs, const Field2D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -641,7 +641,7 @@ Field2D& Field2D::operator+=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); @@ -658,7 +658,7 @@ Field2D& Field2D::operator+=(const Field2D& rhs) { // Provide the C++ wrapper for subtraction of Field2D and Field2D Field2D operator-(const Field2D& lhs, const Field2D& rhs) { - ASSERT1(fieldsCompatible(lhs, rhs)); + ASSERT1(areFieldsCompatible(lhs, rhs)); Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -677,7 +677,7 @@ Field2D& Field2D::operator-=(const Field2D& rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { - ASSERT1(fieldsCompatible(*this, rhs)); + ASSERT1(areFieldsCompatible(*this, rhs)); checkData(*this); checkData(rhs); diff --git a/src/field/where.cxx b/src/field/where.cxx index d3408dbd00..6f2a8c028e 100644 --- a/src/field/where.cxx +++ b/src/field/where.cxx @@ -30,8 +30,8 @@ // Versions taking Field2D and returning Field3D const Field3D where(const Field2D &test, const Field3D >0, const Field3D &le0) { - ASSERT1(fieldsCompatible(test, gt0)); - ASSERT1(fieldsCompatible(test, le0)); + ASSERT1(areFieldsCompatible(test, gt0)); + ASSERT1(areFieldsCompatible(test, le0)); Field3D result{emptyFrom(gt0)}; @@ -46,7 +46,7 @@ const Field3D where(const Field2D &test, const Field3D >0, const Field3D &le0) } const Field3D where(const Field2D &test, const Field3D >0, BoutReal le0) { - ASSERT1(fieldsCompatible(test, gt0)); + ASSERT1(areFieldsCompatible(test, gt0)); Field3D result{emptyFrom(gt0)}; @@ -61,7 +61,7 @@ const Field3D where(const Field2D &test, const Field3D >0, BoutReal le0) { } const Field3D where(const Field2D &test, BoutReal gt0, const Field3D &le0) { - ASSERT1(fieldsCompatible(test, le0)); + ASSERT1(areFieldsCompatible(test, le0)); Field3D result{emptyFrom(le0)}; @@ -77,8 +77,8 @@ const Field3D where(const Field2D &test, BoutReal gt0, const Field3D &le0) { } const Field3D where(const Field2D &test, const Field3D >0, const Field2D &le0) { - ASSERT1(fieldsCompatible(test, gt0)); - ASSERT1(fieldsCompatible(test, le0)); + ASSERT1(areFieldsCompatible(test, gt0)); + ASSERT1(areFieldsCompatible(test, le0)); Field3D result{emptyFrom(gt0)}; @@ -94,8 +94,8 @@ const Field3D where(const Field2D &test, const Field3D >0, const Field2D &le0) } const Field3D where(const Field2D &test, const Field2D >0, const Field3D &le0) { - ASSERT1(fieldsCompatible(test, gt0)); - ASSERT1(fieldsCompatible(test, le0)); + ASSERT1(areFieldsCompatible(test, gt0)); + ASSERT1(areFieldsCompatible(test, le0)); Field3D result{emptyFrom(le0)}; @@ -114,8 +114,8 @@ const Field3D where(const Field2D &test, const Field2D >0, const Field3D &le0) // Versions taking Field2D and returning Field2D const Field2D where(const Field2D &test, const Field2D >0, const Field2D &le0) { - ASSERT1(fieldsCompatible(test, gt0)); - ASSERT1(fieldsCompatible(test, le0)); + ASSERT1(areFieldsCompatible(test, gt0)); + ASSERT1(areFieldsCompatible(test, le0)); Field2D result{emptyFrom(test)}; @@ -131,7 +131,7 @@ const Field2D where(const Field2D &test, const Field2D >0, const Field2D &le0) } const Field2D where(const Field2D &test, const Field2D >0, BoutReal le0) { - ASSERT1(fieldsCompatible(test, gt0)); + ASSERT1(areFieldsCompatible(test, gt0)); Field2D result{emptyFrom(test)}; @@ -147,7 +147,7 @@ const Field2D where(const Field2D &test, const Field2D >0, BoutReal le0) { } const Field2D where(const Field2D &test, BoutReal gt0, const Field2D &le0) { - ASSERT1(fieldsCompatible(test, le0)); + ASSERT1(areFieldsCompatible(test, le0)); Field2D result{emptyFrom(test)}; @@ -180,7 +180,7 @@ const Field2D where(const Field2D &test, BoutReal gt0, BoutReal le0) { // Versions taking Field3D and returning Field3D const Field3D where(const Field3D &test, BoutReal gt0, const Field3D &le0) { - ASSERT1(fieldsCompatible(test, le0)); + ASSERT1(areFieldsCompatible(test, le0)); Field3D result{emptyFrom(test)}; diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index ff7081536e..018ff1ccb6 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -73,7 +73,7 @@ const Field3D Grad_par(const Field3D &var, const std::string &method, CELL_LOC o *******************************************************************************/ const Field3D Grad_parP(const Field3D &apar, const Field3D &f) { - ASSERT1(fieldsCompatible(apar, f)); + ASSERT1(areFieldsCompatible(apar, f)); Mesh *mesh = apar.getMesh(); @@ -200,7 +200,7 @@ const Field3D Div_par(const Field3D &f, const std::string &method, CELL_LOC outl } const Field3D Div_par(const Field3D &f, const Field3D &v) { - ASSERT1(fieldsCompatible(f, v)); + ASSERT1(areFieldsCompatible(f, v)); // Parallel divergence, using velocities at cell boundaries // Note: Not guaranteed to be flux conservative @@ -741,7 +741,7 @@ const Field2D bracket(const Field2D &f, const Field2D &g, BRACKET_METHOD method, CELL_LOC outloc, Solver *UNUSED(solver)) { TRACE("bracket(Field2D, Field2D)"); - ASSERT1(fieldsCompatible(f, g)); + ASSERT1(areFieldsCompatible(f, g)); if (outloc == CELL_DEFAULT) { outloc = g.getLocation(); } @@ -764,7 +764,7 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, CELL_LOC outloc, Solver *solver) { TRACE("bracket(Field3D, Field2D)"); - ASSERT1(fieldsCompatible(f, g)); + ASSERT1(areFieldsCompatible(f, g)); if (outloc == CELL_DEFAULT) { outloc = g.getLocation(); } @@ -941,7 +941,7 @@ const Field3D bracket(const Field2D &f, const Field3D &g, BRACKET_METHOD method, CELL_LOC outloc, Solver *solver) { TRACE("bracket(Field2D, Field3D)"); - ASSERT1(fieldsCompatible(f, g)); + ASSERT1(areFieldsCompatible(f, g)); if (outloc == CELL_DEFAULT) { outloc = g.getLocation(); } @@ -978,7 +978,7 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, CELL_LOC outloc, Solver *solver) { TRACE("Field3D, Field3D"); - ASSERT1(fieldsCompatible(f, g)); + ASSERT1(areFieldsCompatible(f, g)); if (outloc == CELL_DEFAULT) { outloc = g.getLocation(); } diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index d431da8036..0e8b79c175 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -229,7 +229,7 @@ namespace FV { } const Field3D D4DY4(const Field3D &d_in, const Field3D &f_in) { - ASSERT1(fieldsCompatible(d_in, f_in)); + ASSERT1(areFieldsCompatible(d_in, f_in)); Mesh* mesh = d_in.getMesh(); diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 765a559018..9b7decff4f 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -1301,7 +1301,7 @@ void Solver::post_rhs(BoutReal UNUSED(t)) { // Make sure 3D fields are at the correct cell location, etc. for (MAYBE_UNUSED(const auto& f) : f3d) { - ASSERT1(fieldsCompatible(*f.var, *f.F_var)); + ASSERT1(areFieldsCompatible(*f.var, *f.F_var)); } // Apply boundary conditions to the time-derivatives diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index d2a276ae31..80f9c75041 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -124,8 +124,8 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_ALL", FFTTolerance)); EXPECT_TRUE(IsFieldEqual(mesh->fromFieldAligned(input), input)); - EXPECT_TRUE(fieldsCompatible(result, expected)); - EXPECT_FALSE(fieldsCompatible(result, input)); + EXPECT_TRUE(areFieldsCompatible(result, expected)); + EXPECT_FALSE(areFieldsCompatible(result, input)); } TEST_F(ShiftedMetricTest, FromFieldAligned) { @@ -166,8 +166,8 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_ALL", FFTTolerance)); EXPECT_TRUE(IsFieldEqual(mesh->toFieldAligned(input), input)); - EXPECT_TRUE(fieldsCompatible(result, expected)); - EXPECT_FALSE(fieldsCompatible(result, input)); + EXPECT_TRUE(areFieldsCompatible(result, expected)); + EXPECT_FALSE(areFieldsCompatible(result, input)); } TEST_F(ShiftedMetricTest, FromToFieldAligned) { From a48a0fe50334d53b649ff2d4eb43e71f37417f79 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 17:19:59 +0000 Subject: [PATCH 0966/1783] Comments for emptyFrom note it allocates data but does not initialise --- include/field.hxx | 2 +- include/fieldperp.hxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index 577d8f1c6d..ac9b70ee89 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -189,7 +189,7 @@ inline bool areFieldsCompatible(const Field& field1, const Field& field2) { } /// Return an empty shell field of some type derived from Field, with metadata -/// copied but empty data array +/// copied and a data array that is allocated but not initialised. template inline T emptyFrom(const T& f) { static_assert(std::is_base_of::value, "emptyFrom only works on Fields"); diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index d862283e19..ef1f8b4aa5 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -420,7 +420,7 @@ bool finite(const FieldPerp &f, REGION rgn=RGN_ALL); // Specialize newEmptyField templates for FieldPerp /// Return an empty shell field of some type derived from Field, with metadata -/// copied but empty data array +/// copied and a data array that is allocated but not initialised. template<> inline FieldPerp emptyFrom(const FieldPerp& f) { return FieldPerp(f.getMesh(), f.getLocation(), f.getIndex(), {f.getDirectionY(), f.getDirectionZ()}).allocate(); From c220542ca177d15bc38b11be3560d0b53e015822 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 17:24:30 +0000 Subject: [PATCH 0967/1783] Remove unnecessary lines from Field3D, Field2D ctors from BoutReal These constructors now delegate to the basic Field3D/Field2D constructor, so do not need to set {nx, ny, nz} themselves. --- src/field/field2d.cxx | 3 --- src/field/field3d.cxx | 4 ---- 2 files changed, 7 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 7d2ca6747f..ea41fadfe1 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -77,9 +77,6 @@ Field2D::Field2D(const Field2D& f) : Field(f), data(f.data) { } Field2D::Field2D(BoutReal val, Mesh* localmesh) : Field2D(localmesh) { - nx = fieldmesh->LocalNx; - ny = fieldmesh->LocalNy; - *this = val; } diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 99bf28f966..6de63f5280 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -89,10 +89,6 @@ Field3D::Field3D(const BoutReal val, Mesh* localmesh) : Field3D(localmesh) { TRACE("Field3D: Copy constructor from value"); - nx = fieldmesh->LocalNx; - ny = fieldmesh->LocalNy; - nz = fieldmesh->LocalNz; - *this = val; } From 1c5cbbcf0e7bd4b48df019ee6d86259d030451d6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 17:32:50 +0000 Subject: [PATCH 0968/1783] Don't use emptyFrom in splitYupYdown() The fields do not fully constructing in splitYupYdown() as their contents will be copied from allocated fields in the ParallelTransforms. So use the Field3D constructor with only a Mesh* argument rather than emptyFrom. --- src/field/field3d.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 6de63f5280..99651a725f 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -141,8 +141,10 @@ void Field3D::splitYupYdown() { } for (int i = 0; i < fieldmesh->ystart; ++i) { - yup_fields.emplace_back(emptyFrom(*this)); - ydown_fields.emplace_back(emptyFrom(*this)); + // Note the fields constructed here will be fully overwritten by the + // ParallelTransform, so we don't need a full constructor + yup_fields.emplace_back(fieldmesh); + ydown_fields.emplace_back(fieldmesh); } } From db3282d57aedf1ba7707312edeabdba7e9f83dd5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 6 Mar 2019 17:43:14 +0000 Subject: [PATCH 0969/1783] Move run_data into BoutMonitor --- include/bout.hxx | 11 +++++++++-- src/bout++.cxx | 2 -- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index 278a2a7fa2..ae4a09903a 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -116,8 +116,15 @@ int bout_run(Solver *solver, rhsfunc physics_run); * This is added to the solver in bout_run (for C-style models) * or in bout/physicsmodel.hxx */ -class BoutMonitor: public Monitor{ - int call(Solver *solver, BoutReal t, int iter, int NOUT) override; +class BoutMonitor: public Monitor { +public: + BoutMonitor(BoutReal timestep = -1) : Monitor(timestep) { + // Add wall clock time etc to dump file + run_data.outputVars(bout::globals::dump); + } +private: + int call(Solver* solver, BoutReal t, int iter, int NOUT) override; + RunMetrics run_data; }; /*! diff --git a/src/bout++.cxx b/src/bout++.cxx index 7ad21fa08c..0e8d6cd03c 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -87,7 +87,6 @@ void bout_signal_handler(int sig); // Handles signals #include BoutReal simtime; -RunMetrics run_data; int iteration; bool user_requested_exit=false; @@ -509,7 +508,6 @@ int BoutInitialise(int &argc, char **&argv) { /// Add book-keeping variables to the output files bout::globals::dump.add(const_cast(BOUT_VERSION), "BOUT_VERSION", false); bout::globals::dump.add(simtime, "t_array", true); // Appends the time of dumps into an array - run_data.outputVars(bout::globals::dump); // Add wall clock time etc to dump file bout::globals::dump.add(iteration, "iteration", false); //////////////////////////////////////////// From b136cfefa08194f53f8035132394215ef8e46f01 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 6 Mar 2019 17:43:27 +0000 Subject: [PATCH 0970/1783] Clang-format RunMetrics --- src/bout++.cxx | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 0e8d6cd03c..b2dee790bd 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -793,7 +793,6 @@ char get_spin() { * Adds variables to the output file, for post-processing */ void RunMetrics::outputVars(Datafile &file) { - file.add(t_elapsed, "wall_time", true); file.add(wtime, "wtime", true); file.add(ncalls, "ncalls", true); @@ -809,30 +808,29 @@ void RunMetrics::outputVars(Datafile &file) { } void RunMetrics::calculateDerivedMetrics() { - wtime_per_rhs = wtime / ncalls; wtime_per_rhs_e = wtime / ncalls_e; wtime_per_rhs_i = wtime / ncalls_i; } void RunMetrics::writeProgress(BoutReal simtime, bool output_split) { - if (!output_split) { - output_progress.write("%.3e %5d %.2e %5.1f %5.1f %5.1f %5.1f %5.1f\n", - simtime, ncalls, wtime, - 100.0*(wtime_rhs - wtime_comms - wtime_invert)/wtime, - 100.*wtime_invert/wtime, // Inversions - 100.0*wtime_comms/wtime, // Communications - 100.* wtime_io / wtime, // I/O - 100.*(wtime - wtime_io - wtime_rhs)/wtime); // Everything else + output_progress.write( + "%.3e %5d %.2e %5.1f %5.1f %5.1f %5.1f %5.1f\n", simtime, ncalls, + wtime, 100. * (wtime_rhs - wtime_comms - wtime_invert) / wtime, + 100. * wtime_invert / wtime, // Inversions + 100. * wtime_comms / wtime, // Communications + 100. * wtime_io / wtime, // I/O + 100. * (wtime - wtime_io - wtime_rhs) / wtime); // Everything else } else { - output_progress.write("%.3e %5d %5d %.2e %5.1f %5.1f %5.1f %5.1f %5.1f\n", - simtime, ncalls_e, ncalls_i, wtime, - 100.0*(wtime_rhs - wtime_comms - wtime_invert)/wtime, - 100.*wtime_invert/wtime, // Inversions - 100.0*wtime_comms/wtime, // Communications - 100.* wtime_io / wtime, // I/O - 100.*(wtime - wtime_io - wtime_rhs)/wtime); // Everything else + output_progress.write( + "%.3e %5d %5d %.2e %5.1f %5.1f %5.1f %5.1f %5.1f\n", + simtime, ncalls_e, ncalls_i, wtime, + 100. * (wtime_rhs - wtime_comms - wtime_invert) / wtime, + 100. * wtime_invert / wtime, // Inversions + 100. * wtime_comms / wtime, // Communications + 100. * wtime_io / wtime, // I/O + 100. * (wtime - wtime_io - wtime_rhs) / wtime); // Everything else } } From 3b005b3c598cedd32baba3e6b3f287d8f148d9e3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 19:49:37 +0000 Subject: [PATCH 0971/1783] Unit tests for areFieldsCompatible Add checks on 'areFieldsCompatible' for Field, Field3D, Field2D and FieldPerp. Also add tests of 'operator=' for Field3D, Field2D and FieldPerp so that we test the 'copyFieldMembers' method. --- tests/unit/field/test_field.cxx | 102 ++++++++++++++++++++++++++++ tests/unit/field/test_field2d.cxx | 19 ++++++ tests/unit/field/test_field3d.cxx | 19 ++++++ tests/unit/field/test_fieldperp.cxx | 21 ++++++ 4 files changed, 161 insertions(+) diff --git a/tests/unit/field/test_field.cxx b/tests/unit/field/test_field.cxx index a82d5599ff..c84185696d 100644 --- a/tests/unit/field/test_field.cxx +++ b/tests/unit/field/test_field.cxx @@ -45,3 +45,105 @@ TEST_F(FieldTest, GetGridSizes) { EXPECT_EQ(field.getNy(), ny); EXPECT_EQ(field.getNz(), nz); } + +TEST_F(FieldTest, AreFieldsCompatibleTrue) { + // Create a field with non-default members + Field field{mesh_staggered, CELL_XLOW, {YDirectionType::Aligned, ZDirectionType::Average}}; + + Field field2{field}; + + EXPECT_TRUE(areFieldsCompatible(field, field2)); + EXPECT_EQ(field.getMesh(), field2.getMesh()); + EXPECT_EQ(field.getLocation(), field2.getLocation()); + EXPECT_EQ(field.getDirectionY(), field2.getDirectionY()); + EXPECT_EQ(field.getDirectionZ(), field2.getDirectionZ()); +} + +TEST_F(FieldTest, AreFieldsCompatibleFalseMesh) { + // Create a field with default members + Field field; + + FakeMesh myMesh{nx + 1, ny + 2, nz + 3}; + + // Create a field with all members set explicitly, and a non-default mesh + Field field2{&myMesh, CELL_CENTRE, {YDirectionType::Standard, ZDirectionType::Standard}}; + + EXPECT_FALSE(areFieldsCompatible(field, field2)); + EXPECT_NE(field.getMesh(), field2.getMesh()); + EXPECT_EQ(field.getLocation(), field2.getLocation()); + EXPECT_EQ(field.getDirectionY(), field2.getDirectionY()); + EXPECT_EQ(field.getDirectionZ(), field2.getDirectionZ()); +} + +TEST_F(FieldTest, AreFieldsCompatibleFalseLocation) { + // Create a field with default members + Field field{mesh_staggered, CELL_CENTRE, {YDirectionType::Standard, ZDirectionType::Standard}}; + + // Create a field with all members set explicitly, and a non-default location + Field field2{mesh_staggered, CELL_XLOW, {YDirectionType::Standard, ZDirectionType::Standard}}; + + EXPECT_FALSE(areFieldsCompatible(field, field2)); + EXPECT_EQ(field.getMesh(), field2.getMesh()); + EXPECT_NE(field.getLocation(), field2.getLocation()); + EXPECT_EQ(field.getDirectionY(), field2.getDirectionY()); + EXPECT_EQ(field.getDirectionZ(), field2.getDirectionZ()); +} + +TEST_F(FieldTest, AreFieldsCompatibleFalseDirectionY) { + // Create a field with default members + Field field; + + // Create a field with all members set explicitly, and a non-default mesh + Field field2{mesh, CELL_CENTRE, {YDirectionType::Aligned, ZDirectionType::Standard}}; + + EXPECT_FALSE(areFieldsCompatible(field, field2)); + EXPECT_EQ(field.getMesh(), field2.getMesh()); + EXPECT_EQ(field.getLocation(), field2.getLocation()); + EXPECT_NE(field.getDirectionY(), field2.getDirectionY()); + EXPECT_EQ(field.getDirectionZ(), field2.getDirectionZ()); +} + +TEST_F(FieldTest, AreFieldsCompatibleTrueZAverage) { + // Create a field with default members + Field field; + + // Create a field with all members set explicitly, and a non-default mesh + Field field2{mesh, CELL_CENTRE, {YDirectionType::Standard, ZDirectionType::Average}}; + + EXPECT_TRUE(areFieldsCompatible(field, field2)); + EXPECT_EQ(field.getMesh(), field2.getMesh()); + EXPECT_EQ(field.getLocation(), field2.getLocation()); + EXPECT_EQ(field.getDirectionY(), field2.getDirectionY()); + EXPECT_NE(field.getDirectionZ(), field2.getDirectionZ()); +} + +TEST_F(FieldTest, AreFieldsCompatibleTrueYAlignedZAverage) { + // Create a field with y aligned + Field field{mesh, CELL_CENTRE, {YDirectionType::Aligned, ZDirectionType::Standard}}; + + // Create a field with all members set explicitly, and a non-default mesh + Field field2{mesh, CELL_CENTRE, {YDirectionType::Standard, ZDirectionType::Average}}; + + EXPECT_TRUE(areFieldsCompatible(field, field2)); + EXPECT_EQ(field.getMesh(), field2.getMesh()); + EXPECT_EQ(field.getLocation(), field2.getLocation()); + EXPECT_NE(field.getDirectionY(), field2.getDirectionY()); + EXPECT_NE(field.getDirectionZ(), field2.getDirectionZ()); +} + +TEST_F(FieldTest, AreFieldsCompatibleFalseYAlignedZAverage2) { + // Create a field with default members + Field field; + + // Create a field with all members set explicitly, and a non-default mesh + // Note it doesn't make sense for a field to be y-aligned and z-average, + // because for a z-average field there is no difference between y-standard + // and y-aligned. + Field field2{mesh, CELL_CENTRE, {YDirectionType::Aligned, ZDirectionType::Average}}; + + EXPECT_FALSE(areFieldsCompatible(field, field2)); + EXPECT_EQ(field.getMesh(), field2.getMesh()); + EXPECT_EQ(field.getLocation(), field2.getLocation()); + EXPECT_NE(field.getDirectionY(), field2.getDirectionY()); + EXPECT_NE(field.getDirectionZ(), field2.getDirectionZ()); +} diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index dbf95ce69a..a1342af432 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -118,6 +118,7 @@ TEST_F(Field2DTest, CopyCheckFieldmesh) { EXPECT_EQ(field2.getNx(), test_nx); EXPECT_EQ(field2.getNy(), test_ny); EXPECT_EQ(field2.getNz(), 1); + EXPECT_TRUE(areFieldsCompatible(field, field2)); } #if CHECK > 0 @@ -1223,4 +1224,22 @@ TEST_F(Field2DTest, FillField) { EXPECT_TRUE(IsFieldEqual(f, g)); } +TEST_F(Field2DTest, OperatorEqualsField2D) { + Field2D field; + + // Create field with non-default arguments so we can check they get copied + // to 'field'. + // Note that Aligned y-direction type is not really allowed for Field2D, but + // we don't check anywhere at the moment. + Field2D field2{mesh_staggered, CELL_XLOW, {YDirectionType::Aligned, ZDirectionType::Average}}; + + field = field2; + + EXPECT_TRUE(areFieldsCompatible(field, field2)); + EXPECT_EQ(field.getMesh(), field2.getMesh()); + EXPECT_EQ(field.getLocation(), field2.getLocation()); + EXPECT_EQ(field.getDirectionY(), field2.getDirectionY()); + EXPECT_EQ(field.getDirectionZ(), field2.getDirectionZ()); +} + #pragma GCC diagnostic pop diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 94899497f6..f8780e9ce9 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -119,6 +119,7 @@ TEST_F(Field3DTest, CopyCheckFieldmesh) { EXPECT_EQ(field2.getNx(), test_nx); EXPECT_EQ(field2.getNy(), test_ny); EXPECT_EQ(field2.getNz(), test_nz); + EXPECT_TRUE(areFieldsCompatible(field, field2)); } #if CHECK > 0 @@ -2161,5 +2162,23 @@ TEST_F(Field3DTest, LowPassTwoArgNothing) { EXPECT_TRUE(IsFieldEqual(output, input)); } +TEST_F(Field3DTest, OperatorEqualsField3D) { + Field3D field; + + // Create field with non-default arguments so we can check they get copied + // to 'field'. + // Note that Average z-direction type is not really allowed for Field3D, but + // we don't check anywhere at the moment. + Field3D field2{mesh_staggered, CELL_XLOW, {YDirectionType::Aligned, ZDirectionType::Average}}; + + field = field2; + + EXPECT_TRUE(areFieldsCompatible(field, field2)); + EXPECT_EQ(field.getMesh(), field2.getMesh()); + EXPECT_EQ(field.getLocation(), field2.getLocation()); + EXPECT_EQ(field.getDirectionY(), field2.getDirectionY()); + EXPECT_EQ(field.getDirectionZ(), field2.getDirectionZ()); +} + // Restore compiler warnings #pragma GCC diagnostic pop diff --git a/tests/unit/field/test_fieldperp.cxx b/tests/unit/field/test_fieldperp.cxx index 502e44dc6d..c99d56cdb1 100644 --- a/tests/unit/field/test_fieldperp.cxx +++ b/tests/unit/field/test_fieldperp.cxx @@ -72,6 +72,7 @@ TEST_F(FieldPerpTest, SliceXZ) { auto result = sliceXZ(masterField, yindex); EXPECT_EQ(result.getIndex(), yindex); + EXPECT_TRUE(areFieldsCompatible(masterField, result)); for (const auto &i : result) { EXPECT_EQ(result[i], 1.0); @@ -141,6 +142,7 @@ TEST_F(FieldPerpTest, CopyCheckFieldmesh) { EXPECT_EQ(field2.getNx(), test_nx); EXPECT_EQ(field2.getNy(), 1); EXPECT_EQ(field2.getNz(), test_nz); + EXPECT_TRUE(areFieldsCompatible(field, field2)); } #if CHECK > 0 @@ -1434,4 +1436,23 @@ TEST_F(FieldPerpTest, Max) { EXPECT_EQ(max(field, false, RGN_ALL), 99.0); EXPECT_EQ(max(field, true, RGN_ALL), 99.0); } + +TEST_F(FieldPerpTest, OperatorEqualsFieldPerp) { + FieldPerp field; + + // Create field with non-default arguments so we can check they get copied + // to 'field'. + // Note that Average z-direction type is not really allowed for FieldPerp, but + // we don't check anywhere at the moment. + FieldPerp field2{mesh_staggered, CELL_XLOW, 2, {YDirectionType::Aligned, ZDirectionType::Average}}; + + field = field2; + + EXPECT_TRUE(areFieldsCompatible(field, field2)); + EXPECT_EQ(field.getMesh(), field2.getMesh()); + EXPECT_EQ(field.getLocation(), field2.getLocation()); + EXPECT_EQ(field.getDirectionY(), field2.getDirectionY()); + EXPECT_EQ(field.getDirectionZ(), field2.getDirectionZ()); +} + #pragma GCC diagnostic pop From de5d52de0ca98a01d36a09073a51e2e0e8303be6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 19:51:42 +0000 Subject: [PATCH 0972/1783] Remove redundant checks of areFieldsCompatible These checks in 'operator=' followed calls to 'copyFieldMembers' which ensure that check will always pass. --- src/field/field3d.cxx | 2 -- src/field/fieldperp.cxx | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 99651a725f..11f1ca995d 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -238,8 +238,6 @@ Field3D & Field3D::operator=(const Field3D &rhs) { ny = rhs.ny; nz = rhs.nz; - ASSERT1(areFieldsCompatible(*this, rhs)); - data = rhs.data; return *this; diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 937c0080bb..8a20156928 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -84,8 +84,6 @@ FieldPerp &FieldPerp::operator=(const FieldPerp &rhs) { yindex = rhs.yindex; data = rhs.data; - ASSERT1(areFieldsCompatible(*this, rhs)); - return *this; } From 8e81546d32cea1c1e7fbe82bb83ab7748f4e9e64 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 20:00:03 +0000 Subject: [PATCH 0973/1783] Simplify declaration of variables in fci.cxx It's not useful to use 'emptyFrom' any more, since we no longer pass a lot of non-default arguments. --- src/mesh/parallel/fci.cxx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index c546ec7e7e..272947950a 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -73,16 +73,13 @@ FCIMap::FCIMap(Mesh& mesh, int offset_, BoundaryRegionPar* boundary, bool zperio auto k_corner = Tensor(map_mesh.LocalNx, map_mesh.LocalNy, map_mesh.LocalNz); // Index-space coordinates of forward/backward points - Field3D xt_prime(&map_mesh); - Field3D zt_prime{emptyFrom(xt_prime)}; + Field3D xt_prime{&map_mesh}, zt_prime{&map_mesh}; // Real-space coordinates of grid points - Field3D R{emptyFrom(xt_prime)}; - Field3D Z{emptyFrom(xt_prime)}; + Field3D R{&map_mesh}, Z{&map_mesh}; // Real-space coordinates of forward/backward points - Field3D R_prime{emptyFrom(xt_prime)}; - Field3D Z_prime{emptyFrom(xt_prime)}; + Field3D R_prime{&map_mesh}, Z_prime{&map_mesh}; map_mesh.get(R, "R", 0.0, false); map_mesh.get(Z, "Z", 0.0, false); From 5f786afa9bde2b47dc0721eeeba0e2a1fc5353e6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 20:10:14 +0000 Subject: [PATCH 0974/1783] Make areDirectionsCompatible check slightly stricter In the two cases that allow for ZDirectionType::Average, we can assert that the other field has ZDirectionType::Standard, or else it should have been caught in the first conditional. --- src/sys/bout_types.cxx | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index a8774784a6..d7dda8063c 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -66,16 +66,28 @@ bool areDirectionsCompatible(const DirectionTypes& d1, const DirectionTypes& d2) } if (d2.z == ZDirectionType::Average && d2.y == YDirectionType::Standard - && (d1.y == YDirectionType::Standard || d1.y == YDirectionType::Aligned)) { - // If a field has ZDirectionType::Average, then it's compatible with - // YDirectionType::Aligned as well as YDirectionType::Standard + && (d1.y == YDirectionType::Standard || d1.y == YDirectionType::Aligned) + && d1.z == ZDirectionType::Standard) { + // If d2 has ZDirectionType::Average, then it's compatible with d1 having + // YDirectionType::Aligned as well as YDirectionType::Standard. If d1 has + // YDirectionType::Aligned, it should always have ZDirectionType::Standard, + // and if d1 has ZDirectionType::Average it must have + // YDirectionType::Standard and have been caught in the first condition + // where d1 and d2 are identical, so only allow + // 'd1.z == ZDirectionType::Standard' here. return true; } if (d1.z == ZDirectionType::Average && d1.y == YDirectionType::Standard - && (d2.y == YDirectionType::Standard || d2.y == YDirectionType::Aligned)) { - // If a field has ZDirectionType::Average, then it's compatible with - // YDirectionType::Aligned as well as YDirectionType::Standard + && (d2.y == YDirectionType::Standard || d2.y == YDirectionType::Aligned) + && d2.z == ZDirectionType::Standard) { + // If d1 has ZDirectionType::Average, then it's compatible with d2 having + // YDirectionType::Aligned as well as YDirectionType::Standard. If d2 has + // YDirectionType::Aligned, it should always have ZDirectionType::Standard, + // and if d2 has ZDirectionType::Average it must have + // YDirectionType::Standard and have been caught in the first condition + // where d1 and d2 are identical, so only allow + // 'd2.z == ZDirectionType::Standard' here. return true; } From 6715cdb9cca7f5dfab152ce92e8f27d827acfaeb Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 6 Mar 2019 20:17:26 +0000 Subject: [PATCH 0975/1783] Fix setting of parallel transform in test_extras.hxx Shouldn't set in the FakeMesh constructor, because we shouldn't derefernce the 'this' pointer before the FakeMesh has finished being constructed. --- tests/unit/test_extras.hxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index d1393709b6..e468321539 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -153,7 +153,6 @@ public: maxregionblocksize = MAXREGIONBLOCKSIZE; setCoordinates(nullptr); - setParallelTransform(bout::utils::make_unique(*this)); } void setCoordinates(std::shared_ptr coords, CELL_LOC location = CELL_CENTRE) { @@ -262,6 +261,8 @@ public: bout::globals::mesh = nullptr; } bout::globals::mesh = new FakeMesh(nx, ny, nz); + bout::globals::mesh->setParallelTransform( + bout::utils::make_unique(*bout::globals::mesh)); output_info.disable(); bout::globals::mesh->createDefaultRegions(); output_info.enable(); @@ -273,6 +274,8 @@ public: } mesh_staggered = new FakeMesh(nx, ny, nz); mesh_staggered->StaggerGrids = true; + mesh_staggered->setParallelTransform( + bout::utils::make_unique(*mesh_staggered)); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_YLOW); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_ZLOW); From 5f821bde29434e7174b77b2e52f6e0cba1a742e7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 11:19:36 +0000 Subject: [PATCH 0976/1783] Remove commented out code in esel --- examples/2Dturbulence_multigrid/esel.cxx | 33 +++++------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/examples/2Dturbulence_multigrid/esel.cxx b/examples/2Dturbulence_multigrid/esel.cxx index 9bab3856ab..92e12881ad 100644 --- a/examples/2Dturbulence_multigrid/esel.cxx +++ b/examples/2Dturbulence_multigrid/esel.cxx @@ -6,11 +6,11 @@ class ESEL : public PhysicsModel { private: - Field3D n/*, T*/, vort; // Evolving density, temp and vorticity + Field3D n, vort; // Evolving density, temp and vorticity Field3D N; // ln(n) Field3D phi ; Field2D B ; // Magnetic field - BoutReal D/*, chi*/, mu ; // Diffusion coefficients + BoutReal D, mu ; // Diffusion coefficients Field2D sigma_n, sigma_T, sigma_vort; // dissipation terms BoutReal zeta ; // rho/R0 BRACKET_METHOD bm; // Bracket method for advection terms @@ -25,10 +25,8 @@ class ESEL : public PhysicsModel { zeta = options["zeta"].withDefault(2.15e-3); D = options["D"].withDefault(1.97e-3); - // chi = options["chi"].withDefault(4.61e-3) ; mu = options["mu"].withDefault(3.88e-2); - int bracket; - bracket = options["bracket"].withDefault(2); + int bracket = options["bracket"].withDefault(2); test_laplacian = options["test_laplacian"].withDefault(false); // Set sources and sinks from input profile @@ -72,7 +70,6 @@ class ESEL : public PhysicsModel { Coordinates *coord = mesh->getCoordinates(); // generate coordinate system - // coord->J = R0/B0 ; coord->Bxy = 1 ; coord->g11 = 1.0 ; @@ -91,8 +88,6 @@ class ESEL : public PhysicsModel { coord->geometry(); - // SOLVE_FOR3(n, T, vort); - // SOLVE_FOR(n); SOLVE_FOR(N); SOLVE_FOR(vort); SAVE_REPEAT(phi); @@ -110,19 +105,11 @@ class ESEL : public PhysicsModel { } int rhs(BoutReal time) { - // output<<"\r"<communicate(N, vort); - // mesh->communicate(n/*, T*/, vort); - mesh->communicate(N/*, T*/, vort); - - // Solve for potential - // phiSolver->setCoefC(n); phiSolver->setCoefC2(N); phi = phiSolver->solve(vort, phi); - // Communicate variables mesh->communicate(phi); if (test_laplacian) { @@ -134,20 +121,14 @@ class ESEL : public PhysicsModel { MPI_Barrier(BoutComm::get()); - return 1; // Abort execution + return 1; } // Continuity equation: - // ddt(n) = bracket(phi,n,bm) + n*C(phi) - C(n/**T*/) + D*Delp2(n) - sigma_n*n ; - ddt(N) = bracket(phi,N,bm) + C(phi) - C(N/**T*/) + D*Delp2(N) - sigma_n ; - - // Energy equation: - // ddt(T) = bracket(phi,T,bm) + (2/3)*T*C(phi) - (7/3)*T*C(T) - (2/3)*(T*T/n)*C(n) + chi*Delp2(T) - sigma_T*T ; + ddt(N) = bracket(phi,N,bm) + C(phi) - C(N) + D*Delp2(N) - sigma_n ; // Vorticity equation: - // ddt(vort) = bracket(phi, vort, bm) - C(n/**T*/) + mu*Delp2(vort) - sigma_vort*vort ; - ddt(vort) = bracket(phi, vort, bm) - C(exp(N)/**T*/) + mu*Delp2(vort) - sigma_vort*vort ; - // ddt(vort) += phi/1.e4; // Sheath dissipation term to try to stop potential getting too large... + ddt(vort) = bracket(phi, vort, bm) - C(exp(N)) + mu*Delp2(vort) - sigma_vort*vort ; // n.b bracket terms do not have minus sign before them because // B is pointing in -ve y direction in BOUT coordinates. From e392f9e1d8abf930ad02af483fe77d7319abadd8 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 11:20:26 +0000 Subject: [PATCH 0977/1783] Clang-format esel --- examples/2Dturbulence_multigrid/esel.cxx | 126 +++++++++++------------ 1 file changed, 62 insertions(+), 64 deletions(-) diff --git a/examples/2Dturbulence_multigrid/esel.cxx b/examples/2Dturbulence_multigrid/esel.cxx index 92e12881ad..34e880b96e 100644 --- a/examples/2Dturbulence_multigrid/esel.cxx +++ b/examples/2Dturbulence_multigrid/esel.cxx @@ -1,20 +1,20 @@ #include -#include -#include -#include #include +#include +#include +#include class ESEL : public PhysicsModel { private: - Field3D n, vort; // Evolving density, temp and vorticity - Field3D N; // ln(n) - Field3D phi ; - Field2D B ; // Magnetic field - BoutReal D, mu ; // Diffusion coefficients - Field2D sigma_n, sigma_T, sigma_vort; // dissipation terms - BoutReal zeta ; // rho/R0 - BRACKET_METHOD bm; // Bracket method for advection terms - class Laplacian* phiSolver; // Laplacian solver for vort -> phi + Field3D n, vort; // Evolving density, temp and vorticity + Field3D N; // ln(n) + Field3D phi; + Field2D B; // Magnetic field + BoutReal D, mu; // Diffusion coefficients + Field2D sigma_n, sigma_T, sigma_vort; // dissipation terms + BoutReal zeta; // rho/R0 + BRACKET_METHOD bm; // Bracket method for advection terms + Laplacian* phiSolver; // Laplacian solver for vort -> phi bool test_laplacian; // If true, compute the error on the Laplacian inversion and abort Field3D vort_error; @@ -33,32 +33,32 @@ class ESEL : public PhysicsModel { initial_profile("sigma_n", sigma_n); initial_profile("sigma_T", sigma_T); initial_profile("sigma_vort", sigma_vort); - initial_profile("B", B) ; - - SAVE_ONCE(sigma_n) ; - + initial_profile("B", B); + + SAVE_ONCE(sigma_n); + // Poisson brackets: b_hat x Grad(f) dot Grad(g) / B = [f, g] // Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE // Choose method to use for Poisson bracket advection terms - - switch(bracket) { + + switch (bracket) { case 0: { - bm = BRACKET_STD; + bm = BRACKET_STD; output << "\tBrackets: default differencing\n"; break; } case 1: { - bm = BRACKET_SIMPLE; + bm = BRACKET_SIMPLE; output << "\tBrackets: simplified operator\n"; break; } case 2: { - bm = BRACKET_ARAKAWA; + bm = BRACKET_ARAKAWA; output << "\tBrackets: Arakawa scheme\n"; break; } case 3: { - bm = BRACKET_CTU; + bm = BRACKET_CTU; output << "\tBrackets: Corner Transport Upwind method\n"; break; } @@ -67,27 +67,27 @@ class ESEL : public PhysicsModel { return 1; } - Coordinates *coord = mesh->getCoordinates(); - - // generate coordinate system - coord->Bxy = 1 ; - - coord->g11 = 1.0 ; - coord->g22 = 1.0 ; - coord->g33 = 1.0 ; - coord->g12 = 0.0 ; - coord->g13 = 0.0 ; - coord->g23 = 0.0 ; - - coord->g_11 = 1.0 ; - coord->g_22 = 1.0 ; - coord->g_33 = 1.0 ; + Coordinates* coord = mesh->getCoordinates(); + + // generate coordinate system + coord->Bxy = 1; + + coord->g11 = 1.0; + coord->g22 = 1.0; + coord->g33 = 1.0; + coord->g12 = 0.0; + coord->g13 = 0.0; + coord->g23 = 0.0; + + coord->g_11 = 1.0; + coord->g_22 = 1.0; + coord->g_33 = 1.0; coord->g_12 = 0.0; coord->g_13 = 0.0; coord->g_23 = 0.0; - + coord->geometry(); - + SOLVE_FOR(N); SOLVE_FOR(vort); SAVE_REPEAT(phi); @@ -95,45 +95,43 @@ class ESEL : public PhysicsModel { SAVE_REPEAT(vort_error); } phiSolver = Laplacian::create(); - phi = 0.0 ; // Starting phi - + phi = 0.0; // Starting phi + return 0; } - - Field3D C(const Field3D &f) { - return zeta * DDZ(f) ; - } - + + Field3D C(const Field3D& f) { return zeta * DDZ(f); } + int rhs(BoutReal time) { mesh->communicate(N, vort); - + phiSolver->setCoefC2(N); phi = phiSolver->solve(vort, phi); - + mesh->communicate(phi); - + if (test_laplacian) { - - Field3D vort2 = D2DX2(phi) + D2DZ2(phi) + DDX(N)*DDX(phi) + DDZ(N)*DDZ(phi); - vort_error = (vort-vort2); - + + Field3D vort2 = D2DX2(phi) + D2DZ2(phi) + DDX(N) * DDX(phi) + DDZ(N) * DDZ(phi); + vort_error = (vort - vort2); + dump.write(); - + MPI_Barrier(BoutComm::get()); - + return 1; } - - // Continuity equation: - ddt(N) = bracket(phi,N,bm) + C(phi) - C(N) + D*Delp2(N) - sigma_n ; - + + // Continuity equation: + ddt(N) = bracket(phi, N, bm) + C(phi) - C(N) + D * Delp2(N) - sigma_n; + // Vorticity equation: - ddt(vort) = bracket(phi, vort, bm) - C(exp(N)) + mu*Delp2(vort) - sigma_vort*vort ; - - // n.b bracket terms do not have minus sign before them because - // B is pointing in -ve y direction in BOUT coordinates. + ddt(vort) = bracket(phi, vort, bm) - C(exp(N)) + mu * Delp2(vort) - sigma_vort * vort; + + // n.b bracket terms do not have minus sign before them because + // B is pointing in -ve y direction in BOUT coordinates. //// This may be wrong, but it is probably consistently wrong - + return 0; } }; From 9b9efc01ebbb93150195f95c29c6ab6c7a0e70d9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 11:31:49 +0000 Subject: [PATCH 0978/1783] Move some trailing comments to previous line for nicer clang-format --- examples/6field-simple/elm_6f.cxx | 191 ++++++++++++++++-------------- 1 file changed, 99 insertions(+), 92 deletions(-) diff --git a/examples/6field-simple/elm_6f.cxx b/examples/6field-simple/elm_6f.cxx index d740f12019..8d8a005477 100644 --- a/examples/6field-simple/elm_6f.cxx +++ b/examples/6field-simple/elm_6f.cxx @@ -383,51 +383,51 @@ int physics_init(bool restarting) { auto globalOptions = Options::root(); auto options = globalOptions["highbeta"]; - n0_fake_prof = options["n0_fake_prof"].withDefault( - false); // use the hyperbolic profile of n0. If both n0_fake_prof and - // T0_fake_prof are false, use the profiles from grid file - n0_height = options["n0_height"].withDefault( - 0.4); // the total height of profile of N0, in percentage of Ni_x - n0_ave = options["n0_ave"].withDefault( - 0.01); // the center or average of N0, in percentage of Ni_x - n0_width = options["n0_width"].withDefault( - 0.1); // the width of the gradient of N0,in percentage of x - n0_center = options["n0_center"].withDefault( - 0.633); // the grid number of the center of N0, in percentage of x - n0_bottom_x = options["n0_bottom_x"].withDefault( - 0.81); // the start of flat region of N0 on SOL side, in percentage of x + // use the hyperbolic profile of n0. If both n0_fake_prof and + // T0_fake_prof are false, use the profiles from grid file + n0_fake_prof = options["n0_fake_prof"].withDefault(false); + // the total height of profile of N0, in percentage of Ni_x + n0_height = options["n0_height"].withDefault(0.4); + // the center or average of N0, in percentage of Ni_x + n0_ave = options["n0_ave"].withDefault(0.01); + // the width of the gradient of N0,in percentage of x + n0_width = options["n0_width"].withDefault(0.1); + // the grid number of the center of N0, in percentage of x + n0_center = options["n0_center"].withDefault(0.633); + // the start of flat region of N0 on SOL side, in percentage of x + n0_bottom_x = options["n0_bottom_x"].withDefault(0.81); T0_fake_prof = options["T0_fake_prof"].withDefault(false); - Tconst = options["Tconst"].withDefault( - -1.0); // the amplitude of constant temperature, in percentage + // the amplitude of constant temperature, in percentage + Tconst = options["Tconst"].withDefault(-1.0); experiment_Er = options["experiment_Er"].withDefault(false); - laplace_alpha = options["laplace_alpha"].withDefault( - 1.0); // test parameter for the cross term of invert Lapalace - Low_limit = options["Low_limit"].withDefault( - 1.0e-10); // limit the negative value of total quantities - q95_input = options["q95_input"].withDefault( - 5.0); // input q95 as a constant, if <0 use profile from grid - local_q = options["local_q"].withDefault( - false); // using magnetic field to calculate q profile - q_alpha = options["q_alpha"].withDefault( - 1.0); // flux-limiting coefficient, typical value is [0.03, 3] - - gamma_i_BC = options["gamma_i_BC"].withDefault( - -1.0); // sheath energy transmission factor for ion - gamma_e_BC = options["gamma_e_BC"].withDefault( - -1.0); // sheath energy transmission factor for electron - Sheath_width = - options["Sheath_width"].withDefault(1); // Sheath boundary width in grid number + // test parameter for the cross term of invert Lapalace + laplace_alpha = options["laplace_alpha"].withDefault(1.0); + // limit the negative value of total quantities + Low_limit = options["Low_limit"].withDefault(1.0e-10); + // input q95 as a constant, if <0 use profile from grid + q95_input = options["q95_input"].withDefault(5.0); + // using magnetic field to calculate q profile + local_q = options["local_q"].withDefault(false); + // flux-limiting coefficient, typical value is [0.03, 3] + q_alpha = options["q_alpha"].withDefault(1.0); + + // sheath energy transmission factor for ion + gamma_i_BC = options["gamma_i_BC"].withDefault(-1.0); + // sheath energy transmission factor for electron + gamma_e_BC = options["gamma_e_BC"].withDefault(-1.0); + // Sheath boundary width in grid number + Sheath_width = options["Sheath_width"].withDefault(1); density = options["density"].withDefault(1.0e19); // Number density [m^-3] Zi = options["Zi"].withDefault(1); // ion charge number continuity = options["continuity"].withDefault(false); // use continuity equation - evolve_jpar = - options["evolve_jpar"].withDefault(false); // If true, evolve J raher than Psi - phi_constraint = - options["phi_constraint"].withDefault(false); // Use solver constraint for phi + // If true, evolve J raher than Psi + evolve_jpar = options["evolve_jpar"].withDefault(false); + // Use solver constraint for phi + phi_constraint = options["phi_constraint"].withDefault(false); // Effects to include/exclude include_curvature = options["include_curvature"].withDefault(true); @@ -496,14 +496,17 @@ int physics_init(bool restarting) { AA = options["AA"].withDefault(1.0); // ion mass in units of proton mass Mi *= AA; - emass = - options["emass"].withDefault(false); // including electron inertial, electron mass - emass_inv = options["emass_inv"].withDefault(1.0); // inverse of electron mass + // including electron inertial, electron mass + emass = options["emass"].withDefault(false); + // inverse of electron mass + emass_inv = options["emass_inv"].withDefault(1.0); - diamag = options["diamag"].withDefault(false); // Diamagnetic effects? - diamag_phi0 = options["diamag_phi0"].withDefault(diamag); // Include equilibrium phi0 - dia_fact = - options["dia_fact"].withDefault(1.0); // Scale diamagnetic effects by this factor + // Diamagnetic effects? + diamag = options["diamag"].withDefault(false); + // Include equilibrium phi0 + diamag_phi0 = options["diamag_phi0"].withDefault(diamag); + // Scale diamagnetic effects by this factor + dia_fact = options["dia_fact"].withDefault(1.0); noshear = options["noshear"].withDefault(false); @@ -528,23 +531,23 @@ int physics_init(bool restarting) { // Parallel differencing parallel_lr_diff = options["parallel_lr_diff"].withDefault(false); - OPTION(options, parallel_lagrange, - false); // Use a (semi-) Lagrangian method for Grad_parP + // Use a (semi-) Lagrangian method for Grad_parP + OPTION(options, parallel_lagrange, false); parallel_project = options["parallel_project"].withDefault(false); // Vacuum region control - vacuum_pressure = - options["vacuum_pressure"].withDefault(0.02); // Fraction of peak pressure - vacuum_trans = - options["vacuum_trans"].withDefault(0.005); // Transition width in pressure + // Fraction of peak pressure + vacuum_pressure = options["vacuum_pressure"].withDefault(0.02); + // Transition width in pressure + vacuum_trans = options["vacuum_trans"].withDefault(0.005); // Resistivity and hyper-resistivity options vac_lund = options["vac_lund"].withDefault(0.0); // Lundquist number in vacuum region core_lund = options["core_lund"].withDefault(0.0); // Lundquist number in core region hyperresist = options["hyperresist"].withDefault(-1.0); ehyperviscos = options["ehyperviscos"].withDefault(-1.0); - spitzer_resist = - options["spitzer_resist"].withDefault(false); // Use Spitzer resistivity + // Use Spitzer resistivity + spitzer_resist = options["spitzer_resist"].withDefault(false); // Inner boundary damping damp_width = options["damp_width"].withDefault(0); @@ -555,54 +558,58 @@ int physics_init(bool restarting) { viscos_perp = options["viscos_perp"].withDefault(-1.0); // Perpendicular viscosity hyperviscos = options["hyperviscos"].withDefault(-1.0); // Radial hyperviscosity - diffusion_par = - options["diffusion_par"].withDefault(-1.0); // Parallel temperature diffusion - diffusion_n4 = - options["diffusion_n4"].withDefault(-1.0); // M: 4th Parallel density diffusion - diffusion_ti4 = options["diffusion_ti4"].withDefault( - -1.0); // M: 4th Parallel ion temperature diffusion - diffusion_te4 = options["diffusion_te4"].withDefault( - -1.0); // M: 4th Parallel electron temperature diffusion - diffusion_v4 = options["diffusion_v4"].withDefault( - -1.0); // M: 4th Parallel ion parallel velocity diffusion - OPTION(options, diffusion_u4, - -1.0); // xqx: parallel hyper-viscous diffusion for vorticity + // Parallel temperature diffusion + diffusion_par = options["diffusion_par"].withDefault(-1.0); + // M: 4th Parallel density diffusion + diffusion_n4 = options["diffusion_n4"].withDefault(-1.0); + // M: 4th Parallel ion temperature diffusion + diffusion_ti4 = options["diffusion_ti4"].withDefault(-1.0); + // M: 4th Parallel electron temperature diffusion + diffusion_te4 = options["diffusion_te4"].withDefault(-1.0); + // M: 4th Parallel ion parallel velocity diffusion + diffusion_v4 = options["diffusion_v4"].withDefault(-1.0); + // xqx: parallel hyper-viscous diffusion for vorticity + diffusion_u4 = options["diffusion_u4"].withDefault(-1.0); // heating factor in pressure - heating_P = options["heating_P"].withDefault(-1.0); // heating power in pressure - hp_width = options["hp_width"].withDefault( - 0.1); // the percentage of radial grid points for heating - // profile radial width in pressure - hp_length = options["hp_length"].withDefault( - 0.04); // the percentage of radial grid points for heating - // profile radial domain in pressure + // heating power in pressure + heating_P = options["heating_P"].withDefault(-1.0); + // the percentage of radial grid points for heating profile radial + // width in pressure + hp_width = options["hp_width"].withDefault(0.1); + // the percentage of radial grid points for heating profile radial + // domain in pressure + hp_length = options["hp_length"].withDefault(0.04); // sink factor in pressure - sink_vp = options["sink_vp"].withDefault(-1.0); // sink in pressure - sp_width = options["sp_width"].withDefault( - 0.05); // the percentage of radial grid points for sink - // profile radial width in pressure - sp_length = options["sp_length"].withDefault( - 0.04); // the percentage of radial grid points for sink - // profile radial domain in pressure + // sink in pressure + sink_vp = options["sink_vp"].withDefault(-1.0); + // the percentage of radial grid points for sink profile radial + // width in pressure + sp_width = options["sp_width"].withDefault(0.05); + // the percentage of radial grid points for sink profile radial + // domain in pressure + sp_length = options["sp_length"].withDefault(0.04); // left edge sink factor in vorticity - sink_Ul = options["sink_Ul"].withDefault(-1.0); // left edge sink in vorticity - su_widthl = options["su_widthl"].withDefault( - 0.06); // the percentage of left edge radial grid points for - // sink profile radial width in vorticity - su_lengthl = options["su_lengthl"].withDefault( - 0.15); // the percentage of left edge radial grid points - // for sink profile radial domain in vorticity + // left edge sink in vorticity + sink_Ul = options["sink_Ul"].withDefault(-1.0); + // the percentage of left edge radial grid points for sink profile + // radial width in vorticity + su_widthl = options["su_widthl"].withDefault(0.06); + // the percentage of left edge radial grid points for sink profile + // radial domain in vorticity + su_lengthl = options["su_lengthl"].withDefault(0.15); // right edge sink factor in vorticity - sink_Ur = options["sink_Ur"].withDefault(-1.0); // right edge sink in vorticity - su_widthr = options["su_widthr"].withDefault( - 0.06); // the percentage of right edge radial grid points - // for sink profile radial width in vorticity - su_lengthr = options["su_lengthr"].withDefault( - 0.15); // the percentage of right edge radial grid points - // for sink profile radial domain in vorticity + // right edge sink in vorticity + sink_Ur = options["sink_Ur"].withDefault(-1.0); + // the percentage of right edge radial grid points for sink profile + // radial width in vorticity + su_widthr = options["su_widthr"].withDefault(0.06); + // the percentage of right edge radial grid points for sink profile + // radial domain in vorticity + su_lengthr = options["su_lengthr"].withDefault(0.15); // Compressional terms phi_curv = options["phi_curv"].withDefault(true); @@ -1129,7 +1136,7 @@ int physics_init(bool restarting) { aparSolver = Laplacian::create(); aparSolver->setFlags(apar_flags); - + /////////////// CHECK VACUUM /////////////////////// // In vacuum region, initial vorticity should equal zero From b5cad28f25704206a5ae5e3b3fc30ddf9dd5b1af Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 7 Mar 2019 11:32:18 +0000 Subject: [PATCH 0979/1783] Add zeroFrom function Used when we want to create a zero-initialized field with meta-data copied from another field. 'Field3D result{zeroFrom(f)};' is equivalent to 'Field3D result{emptyFrom(f)}; result = 0.;'. --- include/bout/fv_ops.hxx | 6 ++---- include/bout/index_derivs_interface.hxx | 6 ++---- include/field.hxx | 10 ++++++++++ .../impls/multigrid/multigrid_laplace.hxx | 4 +--- .../laplace/impls/naulin/naulin_laplace.hxx | 4 +--- src/mesh/coordinates.cxx | 3 +-- src/mesh/fv_ops.cxx | 12 ++++-------- src/mesh/impls/bout/boutmesh.cxx | 2 -- src/solver/solver.cxx | 6 ++---- src/sys/derivs.cxx | 18 ++++++------------ 10 files changed, 29 insertions(+), 42 deletions(-) diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index 44febce590..a5751ef98b 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -193,8 +193,7 @@ namespace FV { Coordinates *coord = f_in.getCoordinates(); - Field3D result{emptyFrom(f_in)}; - result = 0.0; + Field3D result{zeroFrom(f_in)}; // Only need one guard cell, so no need to communicate fluxes // Instead calculate in guard cells to preserve fluxes @@ -358,8 +357,7 @@ namespace FV { throw BoutException("Div_f_v_XPPM passed a covariant v"); } - Field3D result{emptyFrom(n_in)}; - result = 0.0; + Field3D result{zeroFrom(n_in)}; Field3D vx = v.x; Field3D vz = v.z; diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 6c23c1c1f4..ebd73eb5ad 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -83,8 +83,7 @@ T flowDerivative(const T& vel, const T& f, CELL_LOC outloc, const std::string& m const int nPoint = localmesh->getNpoints(direction); if (nPoint == 1) { - T tmp{emptyFrom(f).setLocation(outloc)}; - tmp = 0.; + T tmp{zeroFrom(f).setLocation(outloc)}; return tmp; } @@ -147,8 +146,7 @@ T standardDerivative(const T& f, CELL_LOC outloc, const std::string& method, const int nPoint = localmesh->getNpoints(direction); if (nPoint == 1) { - T tmp{emptyFrom(f).setLocation(outloc)}; - tmp = 0.; + T tmp{zeroFrom(f).setLocation(outloc)}; return tmp; } diff --git a/include/field.hxx b/include/field.hxx index ac9b70ee89..cb8067cd56 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -196,6 +196,16 @@ inline T emptyFrom(const T& f) { return T(f.getMesh(), f.getLocation(), {f.getDirectionY(), f.getDirectionZ()}).allocate(); } +/// Return a field of some type derived from Field, with metadata copied from +/// another field and a data array allocated and initialised to zero. +template +inline T zeroFrom(const T& f) { + static_assert(std::is_base_of::value, "emptyFrom only works on Fields"); + T result{emptyFrom(f)}; + result = 0.; + return result; +} + /// Unary + operator. This doesn't do anything template T operator+(const T& f) {return f;} diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx index 5f440f2d5d..0d9b2ae8dc 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx @@ -195,9 +195,7 @@ public: const FieldPerp solve(const FieldPerp &b) override { ASSERT1(localmesh == b.getMesh()); - FieldPerp zero{emptyFrom(b)}; - zero = 0.; - return solve(b, zero); + return solve(b, zeroFrom(b)); } const FieldPerp solve(const FieldPerp &b_in, const FieldPerp &x0) override; diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.hxx b/src/invert/laplace/impls/naulin/naulin_laplace.hxx index 40c8d6e9ad..673f7bd858 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.hxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.hxx @@ -110,9 +110,7 @@ public: } const Field3D solve(const Field3D &b, const Field3D &x0) override; const Field3D solve(const Field3D &b) override { - Field3D x0{emptyFrom(b)}; - x0 = 0.; - return solve(b, x0); + return solve(b, zeroFrom(b)); } // Override flag-setting methods to set delp2solver's flags as well diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 1007438cd8..e410b6cf37 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -672,8 +672,7 @@ const Field2D Coordinates::DDZ(MAYBE_UNUSED(const Field2D &f), MAYBE_UNUSED(CELL const std::string &UNUSED(method), REGION UNUSED(region)) { ASSERT1(location == loc || loc == CELL_DEFAULT); ASSERT1(f.getMesh() == localmesh); - Field2D result{emptyFrom(f)}; - result = 0.; + Field2D result{zeroFrom(f)}; return result; } diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index 0e8b79c175..3da9accce8 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -14,8 +14,7 @@ namespace FV { Mesh *mesh = a.getMesh(); - Field3D result{emptyFrom(f)}; - result = 0.0; + Field3D result{zeroFrom(f)}; Coordinates *coord = f.getCoordinates(); @@ -170,8 +169,7 @@ namespace FV { ASSERT2(Kin.getLocation() == fin.getLocation()); Mesh *mesh = Kin.getMesh(); - Field3D result{emptyFrom(fin)}; - result = 0.; + Field3D result{zeroFrom(fin)}; bool use_yup_ydown = (Kin.hasYupYdown() && fin.hasYupYdown()); @@ -233,8 +231,7 @@ namespace FV { Mesh* mesh = d_in.getMesh(); - Field3D result{emptyFrom(f_in)}; - result = 0.0; + Field3D result{zeroFrom(f_in)}; Coordinates *coord = f_in.getCoordinates(); @@ -283,8 +280,7 @@ namespace FV { } const Field3D D4DY4_Index(const Field3D &f_in, bool bndry_flux) { - Field3D result{emptyFrom(f_in)}; - result = 0.0; + Field3D result{zeroFrom(f_in)}; Mesh* mesh = f_in.getMesh(); diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 90d51fcde7..f67fbe6b8d 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2404,7 +2404,6 @@ void BoutMesh::addBoundaryPar(BoundaryRegionPar *bndry) { const Field3D BoutMesh::smoothSeparatrix(const Field3D &f) { Field3D result{emptyFrom(f)}; if ((ixseps_inner > 0) && (ixseps_inner < nx - 1)) { - result.allocate(); if (XPROC(ixseps_inner) == PE_XIND) { int x = XLOCAL(ixseps_inner); for (int y = 0; y < LocalNy; y++) @@ -2421,7 +2420,6 @@ const Field3D BoutMesh::smoothSeparatrix(const Field3D &f) { } } if ((ixseps_outer > 0) && (ixseps_outer < nx - 1) && (ixseps_outer != ixseps_inner)) { - result.allocate(); if (XPROC(ixseps_outer) == PE_XIND) { int x = XLOCAL(ixseps_outer); for (int y = 0; y < LocalNy; y++) diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 9b7decff4f..16f959a637 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -165,8 +165,7 @@ void Solver::add(Field2D &v, const std::string name) { if (mms) { // Allocate storage for error variable - d.MMS_err = new Field2D{emptyFrom(v)}; - (*d.MMS_err) = 0.; + d.MMS_err = new Field2D{zeroFrom(v)}; } else { d.MMS_err = nullptr; } @@ -228,8 +227,7 @@ void Solver::add(Field3D &v, const std::string name) { } if (mms) { - d.MMS_err = new Field3D{emptyFrom(v)}; - (*d.MMS_err) = 0.0; + d.MMS_err = new Field3D{zeroFrom(v)}; } else { d.MMS_err = nullptr; } diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 64286b09e7..4319928b28 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -229,8 +229,7 @@ const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc, const std::string &method const Field2D D2DZ2(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), REGION UNUSED(region)) { - Field2D tmp{emptyFrom(f)}; - tmp = 0.; + Field2D tmp{zeroFrom(f)}; return tmp; } @@ -300,8 +299,7 @@ const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, const std::string &metho const Field2D D2DXDZ(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), REGION UNUSED(region)) { - Field2D tmp{emptyFrom(f)}; - tmp = 0.; + Field2D tmp{zeroFrom(f)}; return tmp; } @@ -331,8 +329,7 @@ const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, const std::string &metho const Field2D D2DYDZ(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), REGION UNUSED(region)) { - Field2D tmp{emptyFrom(f)}; - tmp = 0.; + Field2D tmp{zeroFrom(f)}; return tmp; } @@ -406,8 +403,7 @@ const Field2D VDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } - Field2D tmp{emptyFrom(f).setLocation(outloc)}; - tmp = 0.; + Field2D tmp{zeroFrom(f).setLocation(outloc)}; return tmp; } @@ -417,8 +413,7 @@ const Field2D VDDZ(const Field3D &UNUSED(v), const Field2D &f, CELL_LOC outloc, if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } - Field2D tmp{emptyFrom(f).setLocation(outloc)}; - tmp = 0.; + Field2D tmp{zeroFrom(f).setLocation(outloc)}; return tmp; } @@ -460,8 +455,7 @@ const Field2D FDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } - Field2D tmp{emptyFrom(f).setLocation(outloc)}; - tmp = 0.; + Field2D tmp{zeroFrom(f).setLocation(outloc)}; return tmp; } From c25429ff06074fc338b5c49f6fb03d58a6c65639 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 11:39:07 +0000 Subject: [PATCH 0980/1783] Move some trailing comments to previous line for nicer clang-format --- examples/elm-pb/elm_pb.cxx | 170 ++++++++++++++++++++----------------- 1 file changed, 91 insertions(+), 79 deletions(-) diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index bc82e58963..13d5ea31e7 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -347,29 +347,29 @@ int physics_init(bool restarting) { auto options = globalOptions["highbeta"]; constn0 = options["constn0"].withDefault(true); - n0_fake_prof = options["n0_fake_prof"].withDefault( - false); // use the hyperbolic profile of n0. If both n0_fake_prof and - // T0_fake_prof are false, use the profiles from grid file - n0_height = options["n0_height"].withDefault( - 0.4); // the total height of profile of N0, in percentage of Ni_x - n0_ave = options["n0_ave"].withDefault( - 0.01); // the center or average of N0, in percentage of Ni_x - n0_width = options["n0_width"].withDefault( - 0.1); // the width of the gradient of N0,in percentage of x - n0_center = options["n0_center"].withDefault( - 0.633); // the grid number of the center of N0, in percentage of x - n0_bottom_x = options["n0_bottom_x"].withDefault( - 0.81); // the start of flat region of N0 on SOL side, in percentage of x + // use the hyperbolic profile of n0. If both n0_fake_prof and + // T0_fake_prof are false, use the profiles from grid file + n0_fake_prof = options["n0_fake_prof"].withDefault(false); + // the total height of profile of N0, in percentage of Ni_x + n0_height = options["n0_height"].withDefault(0.4); + // the center or average of N0, in percentage of Ni_x + n0_ave = options["n0_ave"].withDefault(0.01); + // the width of the gradient of N0,in percentage of x + n0_width = options["n0_width"].withDefault(0.1); + // the grid number of the center of N0, in percentage of x + n0_center = options["n0_center"].withDefault(0.633); + // the start of flat region of N0 on SOL side, in percentage of x + n0_bottom_x = options["n0_bottom_x"].withDefault(0.81); T0_fake_prof = options["T0_fake_prof"].withDefault(false); - Tconst = options["Tconst"].withDefault( - -1.0); // the amplitude of constant temperature, in percentage + // the amplitude of constant temperature, in percentage + Tconst = options["Tconst"].withDefault(-1.0); density = options["density"].withDefault(1.0e19); // Number density [m^-3] - evolve_jpar = - options["evolve_jpar"].withDefault(false); // If true, evolve J raher than Psi - phi_constraint = - options["phi_constraint"].withDefault(false); // Use solver constraint for phi + // If true, evolve J raher than Psi + evolve_jpar = options["evolve_jpar"].withDefault(false); + // Use solver constraint for phi + phi_constraint = options["phi_constraint"].withDefault(false); // Effects to include/exclude include_curvature = options["include_curvature"].withDefault(true); @@ -437,25 +437,33 @@ int physics_init(bool restarting) { return 1; } - eHall = options["eHall"].withDefault( - false); // electron Hall or electron parallel pressue gradient effects? + // electron Hall or electron parallel pressue gradient effects? + eHall = options["eHall"].withDefault(false); AA = options["AA"].withDefault(1.0); // ion mass in units of proton mass - diamag = options["diamag"].withDefault(false); // Diamagnetic effects? - diamag_grad_t = - options["diamag_grad_t"].withDefault(diamag); // Grad_par(Te) term in Psi equation - diamag_phi0 = options["diamag_phi0"].withDefault(diamag); // Include equilibrium phi0 - dia_fact = - options["dia_fact"].withDefault(1.0); // Scale diamagnetic effects by this factor - - withflow = options["withflow"].withDefault(false); // withflow or not - K_H_term = options["K_H_term"].withDefault(true); // keep K-H term - D_0 = options["D_0"].withDefault(0.0); // velocity magnitude - D_s = options["D_s"].withDefault(0.0); // flowshear - x0 = options["x0"].withDefault(0.0); // flow location - sign = options["sign"].withDefault( - 1.0); // flow direction, -1 means negative electric field - D_min = options["D_min"].withDefault(3000.0); // a constant + // Diamagnetic effects? + diamag = options["diamag"].withDefault(false); + // Grad_par(Te) term in Psi equation + diamag_grad_t = options["diamag_grad_t"].withDefault(diamag); + // Include equilibrium phi0 + diamag_phi0 = options["diamag_phi0"].withDefault(diamag); + // Scale diamagnetic effects by this factor + dia_fact = options["dia_fact"].withDefault(1.0); + + // withflow or not + withflow = options["withflow"].withDefault(false); + // keep K-H term + K_H_term = options["K_H_term"].withDefault(true); + // velocity magnitude + D_0 = options["D_0"].withDefault(0.0); + // flowshear + D_s = options["D_s"].withDefault(0.0); + // flow location + x0 = options["x0"].withDefault(0.0); + // flow direction, -1 means negative electric field + sign = options["sign"].withDefault(1.0); + // a constant + D_min = options["D_min"].withDefault(3000.0); experiment_Er = options["experiment_Er"].withDefault(false); @@ -493,19 +501,19 @@ int physics_init(bool restarting) { rmp_rotate = options["rmp_rotate"].withDefault(0.0); // Vacuum region control - vacuum_pressure = - options["vacuum_pressure"].withDefault(0.02); // Fraction of peak pressure - vacuum_trans = - options["vacuum_trans"].withDefault(0.005); // Transition width in pressure + // Fraction of peak pressure + vacuum_pressure = options["vacuum_pressure"].withDefault(0.02); + // Transition width in pressure + vacuum_trans = options["vacuum_trans"].withDefault(0.005); // Resistivity and hyper-resistivity options vac_lund = options["vac_lund"].withDefault(0.0); // Lundquist number in vacuum region core_lund = options["core_lund"].withDefault(0.0); // Lundquist number in core region hyperresist = options["hyperresist"].withDefault(-1.0); ehyperviscos = options["ehyperviscos"].withDefault(-1.0); - spitzer_resist = - options["spitzer_resist"].withDefault(false); // Use Spitzer resistivity - Zeff = options["Zeff"].withDefault(2.0); // Z effective + // Use Spitzer resistivity + spitzer_resist = options["spitzer_resist"].withDefault(false); + Zeff = options["Zeff"].withDefault(2.0); // Z effective // Inner boundary damping damp_width = options["damp_width"].withDefault(0); @@ -517,50 +525,54 @@ int physics_init(bool restarting) { hyperviscos = options["hyperviscos"].withDefault(-1.0); // Radial hyperviscosity // parallel pressure diffusion - diffusion_par = - options["diffusion_par"].withDefault(-1.0); // Parallel pressure diffusion - diffusion_p4 = options["diffusion_p4"].withDefault( - -1.0); // xqx: parallel hyper-viscous diffusion for pressure - diffusion_u4 = options["diffusion_u4"].withDefault( - -1.0); // xqx: parallel hyper-viscous diffusion for vorticity - diffusion_a4 = options["diffusion_a4"].withDefault( - -1.0); // xqx: parallel hyper-viscous diffusion for vector potential + // Parallel pressure diffusion + diffusion_par = options["diffusion_par"].withDefault(-1.0); + // xqx: parallel hyper-viscous diffusion for pressure + diffusion_p4 = options["diffusion_p4"].withDefault(-1.0); + // xqx: parallel hyper-viscous diffusion for vorticity + diffusion_u4 = options["diffusion_u4"].withDefault(-1.0); + // xqx: parallel hyper-viscous diffusion for vector potential + diffusion_a4 = options["diffusion_a4"].withDefault(-1.0); // heating factor in pressure - heating_P = options["heating_P"].withDefault(-1.0); // heating power in pressure - hp_width = - options["hp_width"].withDefault(0.1); // the percentage of radial grid points for - // heating profile radial width in pressure - hp_length = options["hp_length"].withDefault( - 0.04); // the percentage of radial grid points for heating - // profile radial domain in pressure + // heating power in pressure + heating_P = options["heating_P"].withDefault(-1.0); + // the percentage of radial grid points for heating profile radial + // width in pressure + hp_width = options["hp_width"].withDefault(0.1); + // the percentage of radial grid points for heating profile radial + // domain in pressure + hp_length = options["hp_length"].withDefault(0.04); // sink factor in pressure - sink_P = options["sink_P"].withDefault(-1.0); // sink in pressure - sp_width = - options["sp_width"].withDefault(0.05); // the percentage of radial grid points for - // sink profile radial width in pressure - sp_length = - options["sp_length"].withDefault(0.04); // the percentage of radial grid points for - // sink profile radial domain in pressure + // sink in pressure + sink_P = options["sink_P"].withDefault(-1.0); + // the percentage of radial grid points for sink profile radial + // width in pressure + sp_width = options["sp_width"].withDefault(0.05); + // the percentage of radial grid points for sink profile radial + // domain in pressure + sp_length = options["sp_length"].withDefault(0.04); // left edge sink factor in vorticity - sink_Ul = options["sink_Ul"].withDefault(-1.0); // left edge sink in vorticity - su_widthl = options["su_widthl"].withDefault( - 0.06); // the percentage of left edge radial grid points for - // sink profile radial width in vorticity - su_lengthl = options["su_lengthl"].withDefault( - 0.15); // the percentage of left edge radial grid points - // for sink profile radial domain in vorticity + // left edge sink in vorticity + sink_Ul = options["sink_Ul"].withDefault(-1.0); + // the percentage of left edge radial grid points for sink profile + // radial width in vorticity + su_widthl = options["su_widthl"].withDefault(0.06); + // the percentage of left edge radial grid points for sink profile + // radial domain in vorticity + su_lengthl = options["su_lengthl"].withDefault(0.15); // right edge sink factor in vorticity - sink_Ur = options["sink_Ur"].withDefault(-1.0); // right edge sink in vorticity - su_widthr = options["su_widthr"].withDefault( - 0.06); // the percentage of right edge radial grid points - // for sink profile radial width in vorticity - su_lengthr = options["su_lengthr"].withDefault( - 0.15); // the percentage of right edge radial grid points - // for sink profile radial domain in vorticity + // right edge sink in vorticity + sink_Ur = options["sink_Ur"].withDefault(-1.0); + // the percentage of right edge radial grid points for sink profile + // radial width in vorticity + su_widthr = options["su_widthr"].withDefault(0.06); + // the percentage of right edge radial grid points for sink profile + // radial domain in vorticity + su_lengthr = options["su_lengthr"].withDefault(0.15); // Compressional terms phi_curv = options["phi_curv"].withDefault(true); From 40a2f0b2bcbab8b2ee9dbbecec421e13f16e34c2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 11:42:32 +0000 Subject: [PATCH 0981/1783] Fix some printf format warnings --- examples/6field-simple/elm_6f.cxx | 7 +++---- examples/elm-pb/elm_pb.cxx | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/examples/6field-simple/elm_6f.cxx b/examples/6field-simple/elm_6f.cxx index 4cf1c751fa..c4984369c7 100644 --- a/examples/6field-simple/elm_6f.cxx +++ b/examples/6field-simple/elm_6f.cxx @@ -772,10 +772,10 @@ int physics_init(bool restarting) { output.write(" sink_vp(rate): %e\n", sink_vp); dump.add(sink_vp, "sink_vp", 1); - output.write(" sp_width(%): %e\n", sp_width); + output.write(" sp_width(%%): %e\n", sp_width); dump.add(sp_width, "sp_width", 1); - output.write(" sp_length(%): %e\n", sp_length); + output.write(" sp_length(%%): %e\n", sp_length); dump.add(sp_length, "sp_length", 1); } @@ -966,8 +966,7 @@ int physics_init(bool restarting) { if (spitzer_resist) { // Use Spitzer resistivity - output.write(""); - output.write("\tSpizter parameters"); + output.write("\n\tSpizter parameters"); // output.write("\tTemperature: %e -> %e [eV]\n", min(Te), max(Te)); eta_spitzer = 0.51 * 1.03e-4 * Zi * LnLambda * pow(Te0 * Tebar, -1.5); // eta in Ohm-m. NOTE: ln(Lambda) = 20 diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index 13d5ea31e7..af287d9da3 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -781,10 +781,10 @@ int physics_init(bool restarting) { output.write(" heating_P(watts): %e\n", heating_P); dump.add(heating_P, "heating_P", 1); - output.write(" hp_width(%): %e\n", hp_width); + output.write(" hp_width(%%): %e\n", hp_width); dump.add(hp_width, "hp_width", 1); - output.write(" hp_length(%): %e\n", hp_length); + output.write(" hp_length(%%): %e\n", hp_length); dump.add(hp_length, "hp_length", 1); } @@ -792,10 +792,10 @@ int physics_init(bool restarting) { output.write(" sink_P(rate): %e\n", sink_P); dump.add(sink_P, "sink_P", 1); - output.write(" sp_width(%): %e\n", sp_width); + output.write(" sp_width(%%): %e\n", sp_width); dump.add(sp_width, "sp_width", 1); - output.write(" sp_length(%): %e\n", sp_length); + output.write(" sp_length(%%): %e\n", sp_length); dump.add(sp_length, "sp_length", 1); } From 9680d3cd6979cf280362229f24b883289f6a8e5a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 7 Mar 2019 12:08:03 +0000 Subject: [PATCH 0982/1783] Unit tests for emptyFrom and zeroFrom --- tests/unit/field/test_field2d.cxx | 32 +++++++++++++++++++++++++++ tests/unit/field/test_field3d.cxx | 32 +++++++++++++++++++++++++++ tests/unit/field/test_fieldperp.cxx | 34 +++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index a1342af432..74cd18c6b0 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -1242,4 +1242,36 @@ TEST_F(Field2DTest, OperatorEqualsField2D) { EXPECT_EQ(field.getDirectionZ(), field2.getDirectionZ()); } +TEST_F(Field2DTest, EmptyFrom) { + // Create field with non-default arguments so we can check they get copied + // to 'field2'. + // Note that Aligned y-direction type is not really allowed for Field2D, but + // we don't check anywhere at the moment. + Field2D field{mesh_staggered, CELL_XLOW, {YDirectionType::Aligned, ZDirectionType::Average}}; + field = 5.; + + Field2D field2{emptyFrom(field)}; + EXPECT_EQ(field2.getMesh(), mesh_staggered); + EXPECT_EQ(field2.getLocation(), CELL_XLOW); + EXPECT_EQ(field2.getDirectionY(), YDirectionType::Aligned); + EXPECT_EQ(field2.getDirectionZ(), ZDirectionType::Average); + EXPECT_TRUE(field2.isAllocated()); +} + +TEST_F(Field2DTest, ZeroFrom) { + // Create field with non-default arguments so we can check they get copied + // to 'field2'. + // Note that Aligned y-direction type is not really allowed for Field2D, but + // we don't check anywhere at the moment. + Field2D field{mesh_staggered, CELL_XLOW, {YDirectionType::Aligned, ZDirectionType::Average}}; + field = 5.; + + Field2D field2{zeroFrom(field)}; + EXPECT_EQ(field2.getMesh(), mesh_staggered); + EXPECT_EQ(field2.getLocation(), CELL_XLOW); + EXPECT_EQ(field2.getDirectionY(), YDirectionType::Aligned); + EXPECT_EQ(field2.getDirectionZ(), ZDirectionType::Average); + EXPECT_TRUE(field2.isAllocated()); + EXPECT_TRUE(IsFieldEqual(field2, 0.)); +} #pragma GCC diagnostic pop diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index f8780e9ce9..0b6743b679 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -2180,5 +2180,37 @@ TEST_F(Field3DTest, OperatorEqualsField3D) { EXPECT_EQ(field.getDirectionZ(), field2.getDirectionZ()); } +TEST_F(Field3DTest, EmptyFrom) { + // Create field with non-default arguments so we can check they get copied + // to 'field2'. + // Note that Average z-direction type is not really allowed for Field3D, but + // we don't check anywhere at the moment. + Field3D field{mesh_staggered, CELL_XLOW, {YDirectionType::Aligned, ZDirectionType::Average}}; + field = 5.; + + Field3D field2{emptyFrom(field)}; + EXPECT_EQ(field2.getMesh(), mesh_staggered); + EXPECT_EQ(field2.getLocation(), CELL_XLOW); + EXPECT_EQ(field2.getDirectionY(), YDirectionType::Aligned); + EXPECT_EQ(field2.getDirectionZ(), ZDirectionType::Average); + EXPECT_TRUE(field2.isAllocated()); +} + +TEST_F(Field3DTest, ZeroFrom) { + // Create field with non-default arguments so we can check they get copied + // to 'field2'. + // Note that Average z-direction type is not really allowed for Field3D, but + // we don't check anywhere at the moment. + Field3D field{mesh_staggered, CELL_XLOW, {YDirectionType::Aligned, ZDirectionType::Average}}; + field = 5.; + + Field3D field2{zeroFrom(field)}; + EXPECT_EQ(field2.getMesh(), mesh_staggered); + EXPECT_EQ(field2.getLocation(), CELL_XLOW); + EXPECT_EQ(field2.getDirectionY(), YDirectionType::Aligned); + EXPECT_EQ(field2.getDirectionZ(), ZDirectionType::Average); + EXPECT_TRUE(field2.isAllocated()); + EXPECT_TRUE(IsFieldEqual(field2, 0.)); +} // Restore compiler warnings #pragma GCC diagnostic pop diff --git a/tests/unit/field/test_fieldperp.cxx b/tests/unit/field/test_fieldperp.cxx index c99d56cdb1..559d66da45 100644 --- a/tests/unit/field/test_fieldperp.cxx +++ b/tests/unit/field/test_fieldperp.cxx @@ -1455,4 +1455,38 @@ TEST_F(FieldPerpTest, OperatorEqualsFieldPerp) { EXPECT_EQ(field.getDirectionZ(), field2.getDirectionZ()); } +TEST_F(FieldPerpTest, EmptyFrom) { + // Create field with non-default arguments so we can check they get copied + // to 'field2'. + // Note that Average z-direction type is not really allowed for FieldPerp, but + // we don't check anywhere at the moment. + FieldPerp field{mesh_staggered, CELL_XLOW, 3, {YDirectionType::Aligned, ZDirectionType::Average}}; + field = 5.; + + FieldPerp field2{emptyFrom(field)}; + EXPECT_EQ(field2.getMesh(), mesh_staggered); + EXPECT_EQ(field2.getLocation(), CELL_XLOW); + EXPECT_EQ(field2.getIndex(), 3); + EXPECT_EQ(field2.getDirectionY(), YDirectionType::Aligned); + EXPECT_EQ(field2.getDirectionZ(), ZDirectionType::Average); + EXPECT_TRUE(field2.isAllocated()); +} + +TEST_F(FieldPerpTest, ZeroFrom) { + // Create field with non-default arguments so we can check they get copied + // to 'field2'. + // Note that Average z-direction type is not really allowed for FieldPerp, but + // we don't check anywhere at the moment. + FieldPerp field{mesh_staggered, CELL_XLOW, 3, {YDirectionType::Aligned, ZDirectionType::Average}}; + field = 5.; + + FieldPerp field2{zeroFrom(field)}; + EXPECT_EQ(field2.getMesh(), mesh_staggered); + EXPECT_EQ(field2.getLocation(), CELL_XLOW); + EXPECT_EQ(field2.getIndex(), 3); + EXPECT_EQ(field2.getDirectionY(), YDirectionType::Aligned); + EXPECT_EQ(field2.getDirectionZ(), ZDirectionType::Average); + EXPECT_TRUE(field2.isAllocated()); + EXPECT_TRUE(IsFieldEqual(field2, 0.)); +} #pragma GCC diagnostic pop From 5e3bc9ac40e565693b1c8f78daeb1ed251a5de85 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 7 Mar 2019 13:44:11 +0000 Subject: [PATCH 0983/1783] Return zeroFrom directly rather than declaring intermediate variable In several places, using zeroFrom has made an intermediate temporary variable unnecessary. --- include/bout/index_derivs_interface.hxx | 6 ++--- src/mesh/coordinates.cxx | 8 +++--- src/sys/derivs.cxx | 33 ++++++++++++++----------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index ebd73eb5ad..1f32d9f0c8 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -83,8 +83,7 @@ T flowDerivative(const T& vel, const T& f, CELL_LOC outloc, const std::string& m const int nPoint = localmesh->getNpoints(direction); if (nPoint == 1) { - T tmp{zeroFrom(f).setLocation(outloc)}; - return tmp; + return zeroFrom(f).setLocation(outloc); } // Lookup the method @@ -146,8 +145,7 @@ T standardDerivative(const T& f, CELL_LOC outloc, const std::string& method, const int nPoint = localmesh->getNpoints(direction); if (nPoint == 1) { - T tmp{zeroFrom(f).setLocation(outloc)}; - return tmp; + return zeroFrom(f).setLocation(outloc); } // Lookup the method diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index e410b6cf37..b39816cf4e 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -668,12 +668,14 @@ const Field2D Coordinates::DDY(const Field2D &f, CELL_LOC loc, const std::string return bout::derivatives::index::DDY(f, loc, method, region) / dy; } -const Field2D Coordinates::DDZ(MAYBE_UNUSED(const Field2D &f), MAYBE_UNUSED(CELL_LOC loc), +const Field2D Coordinates::DDZ(MAYBE_UNUSED(const Field2D &f), CELL_LOC loc, const std::string &UNUSED(method), REGION UNUSED(region)) { ASSERT1(location == loc || loc == CELL_DEFAULT); ASSERT1(f.getMesh() == localmesh); - Field2D result{zeroFrom(f)}; - return result; + if (loc == CELL_DEFAULT) { + loc = f.getLocation(); + } + return zeroFrom(f).setLocation(loc); } #include diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 4319928b28..5a889525f1 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -227,10 +227,12 @@ const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc, const std::string &method / SQ(f.getCoordinates(outloc)->dz); } -const Field2D D2DZ2(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), +const Field2D D2DZ2(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), REGION UNUSED(region)) { - Field2D tmp{zeroFrom(f)}; - return tmp; + if (outloc == CELL_DEFAULT) { + outloc = f.getLocation(); + } + return zeroFrom(f).setLocation(outloc); } /******************************************************************************* @@ -297,10 +299,12 @@ const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, const std::string &metho return DDX(dfdy, outloc, method, region); } -const Field2D D2DXDZ(const Field2D &f, CELL_LOC UNUSED(outloc), +const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), REGION UNUSED(region)) { - Field2D tmp{zeroFrom(f)}; - return tmp; + if (outloc == CELL_DEFAULT) { + outloc = f.getLocation(); + } + return zeroFrom(f).setLocation(outloc); } /// X-Z mixed derivative @@ -327,10 +331,12 @@ const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, const std::string &metho return DDX(DDZ(f, outloc,method, region_inner),outloc,method,region);; } -const Field2D D2DYDZ(const Field2D &f, CELL_LOC UNUSED(outloc), +const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), REGION UNUSED(region)) { - Field2D tmp{zeroFrom(f)}; - return tmp; + if (outloc == CELL_DEFAULT) { + outloc = f.getLocation(); + } + return zeroFrom(f).setLocation(outloc); } const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, @@ -403,8 +409,7 @@ const Field2D VDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } - Field2D tmp{zeroFrom(f).setLocation(outloc)}; - return tmp; + return zeroFrom(f).setLocation(outloc); } // Note that this is zero because no compression is included @@ -413,8 +418,7 @@ const Field2D VDDZ(const Field3D &UNUSED(v), const Field2D &f, CELL_LOC outloc, if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } - Field2D tmp{zeroFrom(f).setLocation(outloc)}; - return tmp; + return zeroFrom(f).setLocation(outloc); } // general case @@ -455,8 +459,7 @@ const Field2D FDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } - Field2D tmp{zeroFrom(f).setLocation(outloc)}; - return tmp; + return zeroFrom(f).setLocation(outloc); } const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { From 8a6073b05a23a445a364bc75f9de4c0792800b26 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 15:11:08 +0000 Subject: [PATCH 0984/1783] Add WithQuietOutput helper class for disabling output in a scope --- tests/unit/test_extras.hxx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 674a54ae18..e867eb9469 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -109,6 +109,16 @@ auto IsFieldEqual(const T& field, BoutReal reference, return ::testing::AssertionSuccess(); } +class WithQuietOutput { +public: + explicit WithQuietOutput(ConditionalOutput& output_in) : output(output_in) { + output.disable(); + } + + ~WithQuietOutput() { output.enable(); } + ConditionalOutput& output; +}; + class Options; /// FakeMesh has just enough information to create fields From 966285f88afad6736f3a917f2384547266201921 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 15:14:29 +0000 Subject: [PATCH 0985/1783] Use WithQuietOutput in unit tests --- tests/unit/field/test_field2d.cxx | 8 +++----- tests/unit/field/test_field3d.cxx | 8 ++++---- tests/unit/field/test_field_factory.cxx | 20 ++++--------------- tests/unit/field/test_fieldperp.cxx | 8 ++++---- tests/unit/field/test_initialprofiles.cxx | 8 ++------ tests/unit/field/test_vector2d.cxx | 4 +--- tests/unit/field/test_vector3d.cxx | 4 +--- tests/unit/include/bout/test_region.cxx | 3 +-- tests/unit/include/test_derivs.cxx | 3 +-- .../unit/mesh/parallel/test_shiftedmetric.cxx | 3 +-- tests/unit/mesh/test_interpolation.cxx | 3 +-- tests/unit/sys/test_options.cxx | 15 ++++---------- tests/unit/sys/test_optionsreader.cxx | 5 ++--- tests/unit/test_extras.hxx | 5 +---- 14 files changed, 30 insertions(+), 67 deletions(-) diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index dbf95ce69a..3971ff3003 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -108,9 +108,8 @@ TEST_F(Field2DTest, CopyCheckFieldmesh) { FakeMesh fieldmesh{test_nx, test_ny, test_nz}; // createDefaultRegions is noisy - output_info.disable(); + WithQuietOutput quiet{output_info}; fieldmesh.createDefaultRegions(); - output_info.enable(); Field2D field{1.0, &fieldmesh}; Field2D field2{field}; @@ -1122,7 +1121,8 @@ TEST_F(Field2DTest, Max) { } TEST_F(Field2DTest, Swap) { - // First field + WithQuietOutput quiet{output_info}; + Field2D first(1., mesh_staggered); first.setLocation(CELL_XLOW); @@ -1136,9 +1136,7 @@ TEST_F(Field2DTest, Swap) { FakeMesh second_mesh{second_nx, second_ny, second_nz}; second_mesh.StaggerGrids = false; - output_info.disable(); second_mesh.createDefaultRegions(); - output_info.enable(); // Second field Field2D second(2., &second_mesh); diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 0b3ffaaff2..5f65fc8160 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -103,14 +103,14 @@ TEST_F(Field3DTest, CreateOnGivenMesh) { } TEST_F(Field3DTest, CopyCheckFieldmesh) { + WithQuietOutput quiet{output_info}; + int test_nx = Field3DTest::nx + 2; int test_ny = Field3DTest::ny + 2; int test_nz = Field3DTest::nz + 2; FakeMesh fieldmesh{test_nx, test_ny, test_nz}; - output_info.disable(); fieldmesh.createDefaultRegions(); - output_info.enable(); Field3D field{0.0, &fieldmesh}; @@ -1886,6 +1886,8 @@ TEST_F(Field3DTest, DC) { } TEST_F(Field3DTest, Swap) { + WithQuietOutput quiet{output_info}; + // First field Field3D first(1., mesh_staggered); @@ -1904,9 +1906,7 @@ TEST_F(Field3DTest, Swap) { FakeMesh second_mesh{second_nx, second_ny, second_nz}; second_mesh.StaggerGrids = false; - output_info.disable(); second_mesh.createDefaultRegions(); - output_info.enable(); // Second field Field3D second(2., &second_mesh); diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index 86842e40c6..64907d0718 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -61,6 +61,8 @@ class FieldFactoryCreationTest : public FakeMeshFixture { T create(Args&&... args) { return createDispatch(std::is_base_of{}, std::forward(args)...); } + + WithQuietOutput quiet{output_info}; }; using Fields = ::testing::Types; @@ -515,11 +517,9 @@ TYPED_TEST(FieldFactoryCreationTest, CreateRoundX) { TYPED_TEST(FieldFactoryCreationTest, CreateWithLookup) { auto a_value = int{6}; - output_info.disable(); auto options = Options{}; options["a"] = a_value; auto output = this->create("x + a", &options); - output_info.enable(); auto expected = makeField( [&a_value](typename TypeParam::ind_type& index) -> BoutReal { @@ -533,11 +533,9 @@ TYPED_TEST(FieldFactoryCreationTest, CreateWithLookup) { TYPED_TEST(FieldFactoryCreationTest, ParseFromCache) { auto a_value = int{6}; - output_info.disable(); auto options = Options{}; options["a"] = a_value; this->factory.parse("x + a", &options); - output_info.enable(); auto output = this->create("x + a"); @@ -581,6 +579,8 @@ class FieldFactoryTest : public FakeMeshFixture { FieldFactoryTest() : FakeMeshFixture{}, factory{mesh} {} FieldFactory factory; + + WithQuietOutput quiet_info{output_info}, quiet{output}, quiet_error{output_error}; }; TEST_F(FieldFactoryTest, RequireMesh) { @@ -594,14 +594,11 @@ TEST_F(FieldFactoryTest, RequireMesh) { } TEST_F(FieldFactoryTest, CleanCache) { - auto a_value = int{6}; - output_info.disable(); auto options = Options{}; options["a"] = a_value; factory.parse("x + a", &options); - output_info.enable(); factory.cleanCache(); @@ -611,19 +608,10 @@ TEST_F(FieldFactoryTest, CleanCache) { TEST_F(FieldFactoryTest, ParseSelfReference) { // This one doesn't need to be typed, but easier than creating a // whole new test suite for this one test - - output.disable(); - output_info.disable(); - output_error.disable(); - auto options = Options{}; options["a"] = "a"; EXPECT_THROW(factory.parse("a", &options), BoutException); - - output_error.enable(); - output_info.enable(); - output.enable(); } TEST_F(FieldFactoryTest, SinArgs) { diff --git a/tests/unit/field/test_fieldperp.cxx b/tests/unit/field/test_fieldperp.cxx index 502e44dc6d..1e20bc646a 100644 --- a/tests/unit/field/test_fieldperp.cxx +++ b/tests/unit/field/test_fieldperp.cxx @@ -105,14 +105,14 @@ TEST_F(FieldPerpTest, GetSetIndex) { } TEST_F(FieldPerpTest, CreateOnGivenMesh) { + WithQuietOutput quiet{output_info}; + int test_nx = FieldPerpTest::nx + 2; int test_ny = FieldPerpTest::ny + 2; int test_nz = FieldPerpTest::nz + 2; FakeMesh fieldmesh{test_nx, test_ny, test_nz}; - output_info.disable(); fieldmesh.createDefaultRegions(); - output_info.enable(); FieldPerp field{&fieldmesh}; @@ -124,14 +124,14 @@ TEST_F(FieldPerpTest, CreateOnGivenMesh) { } TEST_F(FieldPerpTest, CopyCheckFieldmesh) { + WithQuietOutput quiet{output_info}; + int test_nx = FieldPerpTest::nx + 2; int test_ny = FieldPerpTest::ny + 2; int test_nz = FieldPerpTest::nz + 2; FakeMesh fieldmesh{test_nx, test_ny, test_nz}; - output_info.disable(); fieldmesh.createDefaultRegions(); - output_info.enable(); FieldPerp field{&fieldmesh}; field = 1.0; diff --git a/tests/unit/field/test_initialprofiles.cxx b/tests/unit/field/test_initialprofiles.cxx index e2ae609c5d..02fa6d971b 100644 --- a/tests/unit/field/test_initialprofiles.cxx +++ b/tests/unit/field/test_initialprofiles.cxx @@ -25,14 +25,10 @@ class InitialProfileTest : public FakeMeshFixture { // un-field-align the result mesh->setParallelTransform( bout::utils::make_unique(*mesh)); - - output_info.disable(); } - ~InitialProfileTest() { - Options::cleanup(); - output_info.enable(); - } + ~InitialProfileTest() { Options::cleanup(); } + WithQuietOutput quiet{output_info}; }; TEST_F(InitialProfileTest, Field2D) { diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index 076103b60f..3736497aab 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -23,6 +23,7 @@ using namespace bout::globals; class Vector2DTest : public ::testing::Test { protected: Vector2DTest() { + WithQuietOutput quiet{output_info}; // Delete any existing mesh if (mesh != nullptr) { // Delete boundary regions @@ -34,9 +35,7 @@ class Vector2DTest : public ::testing::Test { mesh = nullptr; } mesh = new FakeMesh(nx, ny, nz); - output_info.disable(); mesh->createDefaultRegions(); - output_info.enable(); mesh->addBoundary(new BoundaryRegionXIn("core", 1, ny - 2, mesh)); mesh->addBoundary(new BoundaryRegionXOut("sol", 1, ny - 2, mesh)); @@ -55,7 +54,6 @@ class Vector2DTest : public ::testing::Test { } mesh_staggered = new FakeMesh(nx, ny, nz); mesh_staggered->StaggerGrids = true; - output_info.disable(); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); mesh_staggered->createDefaultRegions(); } diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index 2aa25e12f2..4948600749 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -22,6 +22,7 @@ using namespace bout::globals; class Vector3DTest : public ::testing::Test { protected: Vector3DTest() { + WithQuietOutput quiet{output_info}; // Delete any existing mesh if (mesh != nullptr) { // Delete boundary regions @@ -33,9 +34,7 @@ class Vector3DTest : public ::testing::Test { mesh = nullptr; } mesh = new FakeMesh(nx, ny, nz); - output_info.disable(); mesh->createDefaultRegions(); - output_info.enable(); mesh->addBoundary(new BoundaryRegionXIn("core", 1, ny - 2, mesh)); mesh->addBoundary(new BoundaryRegionXOut("sol", 1, ny - 2, mesh)); @@ -54,7 +53,6 @@ class Vector3DTest : public ::testing::Test { } mesh_staggered = new FakeMesh(nx, ny, nz); mesh_staggered->StaggerGrids = true; - output_info.disable(); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); mesh_staggered->createDefaultRegions(); } diff --git a/tests/unit/include/bout/test_region.cxx b/tests/unit/include/bout/test_region.cxx index 4e7d59be02..3781349573 100644 --- a/tests/unit/include/bout/test_region.cxx +++ b/tests/unit/include/bout/test_region.cxx @@ -1670,10 +1670,9 @@ class IndexOffsetTest : public ::testing::Test { delete mesh; mesh = nullptr; } + WithQuietOutput quiet{output_info}; mesh = new FakeMesh(nx, ny, nz); - output_info.disable(); mesh->createDefaultRegions(); - output_info.enable(); } ~IndexOffsetTest() { diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index e8a2dbc49c..4218706419 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -45,6 +45,7 @@ class DerivativesTest : public ::testing::TestWithParam> { public: DerivativesTest() : input{mesh}, expected{mesh} { + WithQuietOutput quiet{output_info}; using Index = Field3D::ind_type; @@ -98,9 +99,7 @@ class DerivativesTest mesh->ystart = y_guards; mesh->yend = ny - (y_guards + 1); - output_info.disable(); mesh->createDefaultRegions(); - output_info.enable(); // Make the input and expected output fields // Weird `(i.*dir)()` syntax here in order to call the direction method diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index e7552dfcea..f8dd4a6b94 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -21,15 +21,14 @@ class ShiftedMetricTest : public ::testing::Test { delete mesh; mesh = nullptr; } + WithQuietOutput quiet{output_info}; mesh = new FakeMesh(nx, ny, nz); // Use two y-guards to test multiple parallel slices mesh->ystart = 2; mesh->yend = mesh->LocalNy - 3; - output_info.disable(); mesh->createDefaultRegions(); - output_info.enable(); zShift = Field2D{mesh}; diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index 56d6286fec..118070c2bf 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -55,6 +55,7 @@ class Field3DInterpToTest : public ::testing::Test { delete mesh; mesh = nullptr; } + WithQuietOutput quiet{output_info}; mesh = new FakeMesh(nx, ny, nz); mesh->StaggerGrids = true; mesh->xstart = 2; @@ -65,9 +66,7 @@ class Field3DInterpToTest : public ::testing::Test { static_cast(mesh)->setCoordinates(nullptr, CELL_YLOW); static_cast(mesh)->setCoordinates(nullptr, CELL_ZLOW); mesh->setParallelTransform(bout::utils::make_unique(*mesh)); - output_info.disable(); mesh->createDefaultRegions(); - output_info.enable(); } static void TearDownTestCase() { diff --git a/tests/unit/sys/test_options.cxx b/tests/unit/sys/test_options.cxx index 732c5c5016..c477bff9fd 100644 --- a/tests/unit/sys/test_options.cxx +++ b/tests/unit/sys/test_options.cxx @@ -9,15 +9,9 @@ class OptionsTest : public ::testing::Test { public: - OptionsTest() { - output_info.disable(); - output_warn.disable(); - } - - ~OptionsTest() { - output_info.enable(); - output_warn.enable(); - } + virtual ~OptionsTest() = default; + WithQuietOutput quiet_info{output_info}; + WithQuietOutput quiet_warn{output_warn}; }; TEST_F(OptionsTest, IsSet) { @@ -365,11 +359,10 @@ TEST_F(OptionsTest, SetSameOptionTwice) { Options options; options.set("key", "value", "code"); EXPECT_THROW(options.set("key", "new value", "code"),BoutException); - output_warn.disable(); + options.set("key", "value", "code"); EXPECT_NO_THROW(options.forceSet("key", "new value", "code")); EXPECT_NO_THROW(options.set("key", "value", "code",true)); - output_warn.enable(); } /// New interface diff --git a/tests/unit/sys/test_optionsreader.cxx b/tests/unit/sys/test_optionsreader.cxx index 8cbdcc73da..47755ce880 100644 --- a/tests/unit/sys/test_optionsreader.cxx +++ b/tests/unit/sys/test_optionsreader.cxx @@ -18,7 +18,6 @@ class OptionsReaderTest : public ::testing::Test { OptionsReaderTest() : sbuf(std::cout.rdbuf()) { // Redirect cout to our stringstream buffer or any other ostream std::cout.rdbuf(buffer.rdbuf()); - output_info.disable(); } ~OptionsReaderTest() { @@ -29,14 +28,14 @@ class OptionsReaderTest : public ::testing::Test { // Make sure options singleton is clean Options::cleanup(); - - output_info.enable(); } // Write cout to buffer instead of stdout std::stringstream buffer; // Save cout's buffer here std::streambuf *sbuf; + + WithQuietOutput quiet{output_info}; }; TEST_F(OptionsReaderTest, BadFilename) { diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index e867eb9469..03539527a6 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -270,10 +270,9 @@ public: delete bout::globals::mesh; bout::globals::mesh = nullptr; } + WithQuietOutput quiet{output_info}; bout::globals::mesh = new FakeMesh(nx, ny, nz); - output_info.disable(); bout::globals::mesh->createDefaultRegions(); - output_info.enable(); // Delete any existing mesh_staggered if (mesh_staggered != nullptr) { @@ -285,9 +284,7 @@ public: static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_YLOW); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_ZLOW); - output_info.disable(); mesh_staggered->createDefaultRegions(); - output_info.enable(); } virtual ~FakeMeshFixture() { From 693bbfc3865abcc53fed0fc71b4841545eb09be1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 15:14:46 +0000 Subject: [PATCH 0986/1783] Explicitly enable outputs in OutputTest All tests now use WithQuietOutput to turn off outputs during a scope, but this is defensive against potential future bugs --- tests/unit/sys/test_output.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/sys/test_output.cxx b/tests/unit/sys/test_output.cxx index f4b7456033..3e32db3897 100644 --- a/tests/unit/sys/test_output.cxx +++ b/tests/unit/sys/test_output.cxx @@ -194,18 +194,22 @@ TEST_F(OutputTest, ConditionalJustStdOutGlobalInstances) { EXPECT_EQ(buffer.str(), "warn output\n"); buffer.str(""); + output_info.enable(); output_info << "info output\n"; EXPECT_EQ(buffer.str(), "info output\n"); buffer.str(""); + output_progress.enable(); output_progress << "progress output\n"; EXPECT_EQ(buffer.str(), "progress output\n"); buffer.str(""); + output_error.enable(); output_error << "error output\n"; EXPECT_EQ(buffer.str(), "error output\n"); buffer.str(""); + output_debug.enable(); output_debug << "debug output\n"; #ifdef DEBUG_ENABLED EXPECT_EQ(buffer.str(), "debug output\n"); From edadae1243f31ff84ccdc763c0aedefef725ef30 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 15:16:34 +0000 Subject: [PATCH 0987/1783] Ensure all unit test fixtures have virtual destructors --- tests/unit/field/test_field_factory.cxx | 1 + tests/unit/field/test_vector2d.cxx | 2 +- tests/unit/field/test_vector3d.cxx | 2 +- tests/unit/include/bout/test_array.cxx | 2 +- tests/unit/include/bout/test_deriv_store.cxx | 2 +- tests/unit/include/bout/test_region.cxx | 12 ++++-------- tests/unit/include/test_derivs.cxx | 2 +- tests/unit/invert/test_fft.cxx | 2 ++ tests/unit/mesh/parallel/test_shiftedmetric.cxx | 2 +- tests/unit/mesh/test_boundary_factory.cxx | 2 +- tests/unit/sys/test_expressionparser.cxx | 1 + tests/unit/sys/test_optionsreader.cxx | 2 +- tests/unit/sys/test_output.cxx | 2 +- 13 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index 64907d0718..8d920d9c89 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -577,6 +577,7 @@ TYPED_TEST(FieldFactoryCreationTest, CreateOnMesh) { class FieldFactoryTest : public FakeMeshFixture { public: FieldFactoryTest() : FakeMeshFixture{}, factory{mesh} {} + virtual ~FieldFactoryTest() {} FieldFactory factory; diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index 3736497aab..dfd4a57f56 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -58,7 +58,7 @@ class Vector2DTest : public ::testing::Test { mesh_staggered->createDefaultRegions(); } - ~Vector2DTest() { + virtual ~Vector2DTest() { if (mesh != nullptr) { // Delete boundary regions for (auto &r : mesh->getBoundaries()) { diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index 4948600749..37ead1a666 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -57,7 +57,7 @@ class Vector3DTest : public ::testing::Test { mesh_staggered->createDefaultRegions(); } - ~Vector3DTest() { + virtual ~Vector3DTest() { if (mesh != nullptr) { // Delete boundary regions for (auto &r : mesh->getBoundaries()) { diff --git a/tests/unit/include/bout/test_array.cxx b/tests/unit/include/bout/test_array.cxx index cb40ed6975..40d635a79e 100644 --- a/tests/unit/include/bout/test_array.cxx +++ b/tests/unit/include/bout/test_array.cxx @@ -14,7 +14,7 @@ class ArrayTest : public ::testing::Test { public: ArrayTest() { Array::useStore(true); } // Note: Calling cleanup() disables the store - ~ArrayTest() { } + virtual ~ArrayTest() = default; }; TEST_F(ArrayTest, ArraySize) { diff --git a/tests/unit/include/bout/test_deriv_store.cxx b/tests/unit/include/bout/test_deriv_store.cxx index 58688cd259..bb815cb2ad 100644 --- a/tests/unit/include/bout/test_deriv_store.cxx +++ b/tests/unit/include/bout/test_deriv_store.cxx @@ -26,7 +26,7 @@ void flowReturnSixSetToTwo(const FieldType& UNUSED(vel), const FieldType& UNUSED class DerivativeStoreTest : public ::testing::Test { public: DerivativeStoreTest() : store(DerivativeStore::getInstance()) {} - ~DerivativeStoreTest() { store.reset(); } + virtual ~DerivativeStoreTest() { store.reset(); } DerivativeStore& store; }; diff --git a/tests/unit/include/bout/test_region.cxx b/tests/unit/include/bout/test_region.cxx index 3781349573..b63fb05041 100644 --- a/tests/unit/include/bout/test_region.cxx +++ b/tests/unit/include/bout/test_region.cxx @@ -1170,9 +1170,7 @@ TEST(RegionIndex3DTest, NonMemberSize) { template class RegionIndexTest : public ::testing::Test { public: - typedef std::list List; - static T shared_; - T value_; + virtual ~RegionIndexTest() = default; }; typedef ::testing::Types RegionIndexTypes; @@ -1490,10 +1488,8 @@ TYPED_TEST(RegionIndexTest, RangeBasedForLoop) { template class FieldIndexTest : public ::testing::Test { - public: - typedef std::list List; - static T shared_; - T value_; +public: + virtual ~FieldIndexTest() = default; }; typedef ::testing::Types FieldIndexTypes; @@ -1675,7 +1671,7 @@ class IndexOffsetTest : public ::testing::Test { mesh->createDefaultRegions(); } - ~IndexOffsetTest() { + virtual ~IndexOffsetTest() { delete mesh; mesh = nullptr; } diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index 4218706419..83de38f0b4 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -147,7 +147,7 @@ class DerivativesTest DerivativeStore::getInstance().initialise(Options::getRoot()); }; - ~DerivativesTest() { + virtual ~DerivativesTest() { delete mesh; mesh = nullptr; } diff --git a/tests/unit/invert/test_fft.cxx b/tests/unit/invert/test_fft.cxx index 29c3b38d02..c8343008ce 100644 --- a/tests/unit/invert/test_fft.cxx +++ b/tests/unit/invert/test_fft.cxx @@ -31,6 +31,8 @@ class FFTTest : public ::testing::TestWithParam { fft_signal[2] = dcomplex{0.5, 0.}; }; + virtual ~FFTTest() = default; + const int size; const int nmodes; diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index f8dd4a6b94..592a9f64e7 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -75,7 +75,7 @@ class ShiftedMetricTest : public ::testing::Test { Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false)); } - ~ShiftedMetricTest() { + virtual ~ShiftedMetricTest() { delete mesh; mesh = nullptr; } diff --git a/tests/unit/mesh/test_boundary_factory.cxx b/tests/unit/mesh/test_boundary_factory.cxx index 15f69686f6..9b07801622 100644 --- a/tests/unit/mesh/test_boundary_factory.cxx +++ b/tests/unit/mesh/test_boundary_factory.cxx @@ -45,7 +45,7 @@ class BoundaryFactoryTest : public ::testing::Test { region = new BoundaryRegionXIn{"test_region", 0, 1, mesh}; } - ~BoundaryFactoryTest() { + virtual ~BoundaryFactoryTest() { delete mesh; mesh = nullptr; diff --git a/tests/unit/sys/test_expressionparser.cxx b/tests/unit/sys/test_expressionparser.cxx index ed6c4b91bd..90eed694a1 100644 --- a/tests/unit/sys/test_expressionparser.cxx +++ b/tests/unit/sys/test_expressionparser.cxx @@ -15,6 +15,7 @@ class ExpressionParserSubClass : public ExpressionParser { class ExpressionParserTest : public ::testing::Test { public: + virtual ~ExpressionParserTest() = default; ExpressionParserSubClass parser; std::vector x_array = {-1., 0., 1., 5., 10., 3.14e8}; std::vector y_array = {-1., 0., 1., 5., 10., 3.14e8}; diff --git a/tests/unit/sys/test_optionsreader.cxx b/tests/unit/sys/test_optionsreader.cxx index 47755ce880..d291a7cfd1 100644 --- a/tests/unit/sys/test_optionsreader.cxx +++ b/tests/unit/sys/test_optionsreader.cxx @@ -20,7 +20,7 @@ class OptionsReaderTest : public ::testing::Test { std::cout.rdbuf(buffer.rdbuf()); } - ~OptionsReaderTest() { + virtual ~OptionsReaderTest() { // Clear buffer buffer.str(""); // When done redirect cout to its old self diff --git a/tests/unit/sys/test_output.cxx b/tests/unit/sys/test_output.cxx index 3e32db3897..2d00d0f801 100644 --- a/tests/unit/sys/test_output.cxx +++ b/tests/unit/sys/test_output.cxx @@ -13,7 +13,7 @@ class OutputTest : public ::testing::Test { std::cout.rdbuf(buffer.rdbuf()); } - ~OutputTest() { + virtual ~OutputTest() { // Clear buffer buffer.str(""); // When done redirect cout to its old self From 49441429728ba619493bdf720bad5d0aac47cacd Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 15:17:00 +0000 Subject: [PATCH 0988/1783] Be more confident in deleting mesh in test fixtures --- tests/unit/field/test_vector2d.cxx | 5 +---- tests/unit/field/test_vector3d.cxx | 5 +---- tests/unit/include/bout/test_region.cxx | 6 +----- tests/unit/mesh/parallel/test_shiftedmetric.cxx | 7 ++----- tests/unit/mesh/test_boundary_factory.cxx | 11 ++--------- tests/unit/mesh/test_interpolation.cxx | 7 +------ tests/unit/test_extras.hxx | 13 +++---------- 7 files changed, 11 insertions(+), 43 deletions(-) diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index dfd4a57f56..7e091f01cb 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -48,10 +48,7 @@ class Vector2DTest : public ::testing::Test { Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{0.0}, Field2D{0.0}, false)); - if (mesh_staggered != nullptr) { - delete mesh_staggered; - mesh_staggered = nullptr; - } + delete mesh_staggered; mesh_staggered = new FakeMesh(nx, ny, nz); mesh_staggered->StaggerGrids = true; static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index 37ead1a666..8b4af337c9 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -47,10 +47,7 @@ class Vector3DTest : public ::testing::Test { Field2D{6.0}, Field2D{1.0}, Field2D{2.0}, Field2D{3.0}, Field2D{4.0}, Field2D{5.0}, Field2D{6.0}, Field2D{0.0}, Field2D{0.0}, false)); - if (mesh_staggered != nullptr) { - delete mesh_staggered; - mesh_staggered = nullptr; - } + delete mesh_staggered; mesh_staggered = new FakeMesh(nx, ny, nz); mesh_staggered->StaggerGrids = true; static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); diff --git a/tests/unit/include/bout/test_region.cxx b/tests/unit/include/bout/test_region.cxx index b63fb05041..5eeda0b349 100644 --- a/tests/unit/include/bout/test_region.cxx +++ b/tests/unit/include/bout/test_region.cxx @@ -1661,12 +1661,8 @@ TYPED_TEST(FieldIndexTest, Modulus) { class IndexOffsetTest : public ::testing::Test { protected: IndexOffsetTest() { - // Delete any existing mesh - if (mesh != nullptr) { - delete mesh; - mesh = nullptr; - } WithQuietOutput quiet{output_info}; + delete mesh; mesh = new FakeMesh(nx, ny, nz); mesh->createDefaultRegions(); } diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 592a9f64e7..53b9b0e0b1 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -16,12 +16,9 @@ extern Mesh* mesh; class ShiftedMetricTest : public ::testing::Test { public: ShiftedMetricTest() { - // Delete any existing mesh - if (mesh != nullptr) { - delete mesh; - mesh = nullptr; - } WithQuietOutput quiet{output_info}; + + delete mesh; mesh = new FakeMesh(nx, ny, nz); // Use two y-guards to test multiple parallel slices diff --git a/tests/unit/mesh/test_boundary_factory.cxx b/tests/unit/mesh/test_boundary_factory.cxx index 9b07801622..fced8be432 100644 --- a/tests/unit/mesh/test_boundary_factory.cxx +++ b/tests/unit/mesh/test_boundary_factory.cxx @@ -34,10 +34,7 @@ class TestBoundary : public BoundaryOp { class BoundaryFactoryTest : public ::testing::Test { public: BoundaryFactoryTest() { - if (mesh != nullptr) { - delete mesh; - mesh = nullptr; - } + delete mesh; mesh = new FakeMesh(3, 3, 3); fac->add(new TestBoundary(), "testboundary"); @@ -50,13 +47,9 @@ class BoundaryFactoryTest : public ::testing::Test { mesh = nullptr; delete region; - BoundaryFactory::cleanup(); - if (boundary != nullptr) { - delete boundary; - boundary = nullptr; - } + delete boundary; } BoundaryFactory* fac{BoundaryFactory::getInstance()}; diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index 118070c2bf..79fce6e5c6 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -49,13 +49,8 @@ class Field3DInterpToTest : public ::testing::Test { } static void SetUpTestCase() { - - // Delete any existing mesh - if (mesh != nullptr) { - delete mesh; - mesh = nullptr; - } WithQuietOutput quiet{output_info}; + delete mesh; mesh = new FakeMesh(nx, ny, nz); mesh->StaggerGrids = true; mesh->xstart = 2; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 03539527a6..697ee4f418 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -265,20 +265,13 @@ private: class FakeMeshFixture : public ::testing::Test { public: FakeMeshFixture() { - // Delete any existing mesh - if (bout::globals::mesh != nullptr) { - delete bout::globals::mesh; - bout::globals::mesh = nullptr; - } WithQuietOutput quiet{output_info}; + + delete bout::globals::mesh; bout::globals::mesh = new FakeMesh(nx, ny, nz); bout::globals::mesh->createDefaultRegions(); - // Delete any existing mesh_staggered - if (mesh_staggered != nullptr) { - delete mesh_staggered; - mesh_staggered = nullptr; - } + delete mesh_staggered; mesh_staggered = new FakeMesh(nx, ny, nz); mesh_staggered->StaggerGrids = true; static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); From dc9a2e631f1c4cebf88d48d309bea0a6b872bf13 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 15:17:16 +0000 Subject: [PATCH 0989/1783] Fix printf format warning in expressionparser test --- tests/unit/sys/test_expressionparser.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/sys/test_expressionparser.cxx b/tests/unit/sys/test_expressionparser.cxx index 90eed694a1..5d4e48c75e 100644 --- a/tests/unit/sys/test_expressionparser.cxx +++ b/tests/unit/sys/test_expressionparser.cxx @@ -34,7 +34,7 @@ class BinaryGenerator : public FieldGenerator { clone(const std::list> args) { if (args.size() != 2) { throw ParseException( - "Incorrect number of arguments to increment function. Expecting 2, got %d", + "Incorrect number of arguments to increment function. Expecting 2, got %zu", args.size()); } From 80a3aed88f8a17eee2a2a6b714dd7d10a8250afc Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 15:17:28 +0000 Subject: [PATCH 0990/1783] Remove unnecessary DerivativeStore initialisation in tests Now done in ctor --- tests/unit/include/test_derivs.cxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index 83de38f0b4..5252c390a9 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -142,9 +142,6 @@ class DerivativesTest ParallelTransformIdentity identity{*mesh}; identity.calcYUpDown(input); identity.calcYUpDown(velocity); - - // FIXME: remove when defaults are set in the DerivativeStore ctor - DerivativeStore::getInstance().initialise(Options::getRoot()); }; virtual ~DerivativesTest() { From 6f67da374618906b6d82efb4a81f6757b61b8a86 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 15:18:07 +0000 Subject: [PATCH 0991/1783] Update googletest to current HEAD --- externalpackages/googletest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externalpackages/googletest b/externalpackages/googletest index 4bab34d208..8b6d3f9c4a 160000 --- a/externalpackages/googletest +++ b/externalpackages/googletest @@ -1 +1 @@ -Subproject commit 4bab34d2084259cba67f3bfb51217c10d606e175 +Subproject commit 8b6d3f9c4a774bef3081195d422993323b6bb2e0 From bfaf8cd2a8e80f56257473ee63302e50a6d6c573 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 15:45:37 +0000 Subject: [PATCH 0992/1783] Add missing virtual dtor --- tests/unit/field/test_initialprofiles.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/field/test_initialprofiles.cxx b/tests/unit/field/test_initialprofiles.cxx index 02fa6d971b..d519fb26e0 100644 --- a/tests/unit/field/test_initialprofiles.cxx +++ b/tests/unit/field/test_initialprofiles.cxx @@ -27,7 +27,7 @@ class InitialProfileTest : public FakeMeshFixture { bout::utils::make_unique(*mesh)); } - ~InitialProfileTest() { Options::cleanup(); } + virtual ~InitialProfileTest() { Options::cleanup(); } WithQuietOutput quiet{output_info}; }; From e80762add28b710a53c0f53b3e583b5685e56ee3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 15:45:45 +0000 Subject: [PATCH 0993/1783] Fix more printf format warnings in unit tests --- tests/unit/sys/test_optionsreader.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/sys/test_optionsreader.cxx b/tests/unit/sys/test_optionsreader.cxx index d291a7cfd1..04825d3d58 100644 --- a/tests/unit/sys/test_optionsreader.cxx +++ b/tests/unit/sys/test_optionsreader.cxx @@ -423,7 +423,7 @@ test6 = h2`+`:on`e-`more # Escape sequences in the middle test_file.close(); OptionsReader reader; - reader.read(Options::getRoot(), filename); + reader.read(Options::getRoot(), "%s", filename); std::remove(filename); auto options = Options::root()["tests"]; @@ -451,7 +451,7 @@ some:value = 3 OptionsReader reader; - EXPECT_THROW(reader.read(Options::getRoot(), filename), BoutException); + EXPECT_THROW(reader.read(Options::getRoot(), "%s", filename), BoutException); std::remove(filename); } @@ -473,7 +473,7 @@ twopi = 2 * π # Unicode symbol defined for pi test_file.close(); OptionsReader reader; - reader.read(Options::getRoot(), filename); + reader.read(Options::getRoot(), "%s", filename); std::remove(filename); auto options = Options::root()["tests"]; From 526f033111e1dd0d8ec1852d0bad37bb2ecf4cf1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 15:46:11 +0000 Subject: [PATCH 0994/1783] Update deprecated googletest macro --- tests/unit/field/test_field_factory.cxx | 2 +- tests/unit/include/bout/test_region.cxx | 4 +- tests/unit/include/test_derivs.cxx | 60 ++++++++++++------------- tests/unit/invert/test_fft.cxx | 2 +- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index 8d920d9c89..1a943a7410 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -67,7 +67,7 @@ class FieldFactoryCreationTest : public FakeMeshFixture { using Fields = ::testing::Types; -TYPED_TEST_CASE(FieldFactoryCreationTest, Fields); +TYPED_TEST_SUITE(FieldFactoryCreationTest, Fields); TYPED_TEST(FieldFactoryCreationTest, CreateFromValueGenerator) { auto value = BoutReal{4.}; diff --git a/tests/unit/include/bout/test_region.cxx b/tests/unit/include/bout/test_region.cxx index 5eeda0b349..07f119c6e9 100644 --- a/tests/unit/include/bout/test_region.cxx +++ b/tests/unit/include/bout/test_region.cxx @@ -1174,7 +1174,7 @@ template class RegionIndexTest : public ::testing::Test { }; typedef ::testing::Types RegionIndexTypes; -TYPED_TEST_CASE(RegionIndexTest, RegionIndexTypes); +TYPED_TEST_SUITE(RegionIndexTest, RegionIndexTypes); TYPED_TEST(RegionIndexTest, Begin) { typename Region::RegionIndices region{ @@ -1493,7 +1493,7 @@ class FieldIndexTest : public ::testing::Test { }; typedef ::testing::Types FieldIndexTypes; -TYPED_TEST_CASE(FieldIndexTest, FieldIndexTypes); +TYPED_TEST_SUITE(FieldIndexTest, FieldIndexTypes); TYPED_TEST(FieldIndexTest, Constructor) { TypeParam index(1); diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index 5252c390a9..7bcb73e759 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -188,81 +188,81 @@ auto methodDirectionTupleToString( } // Instantiate the test for X, Y, Z for first derivatives -INSTANTIATE_TEST_CASE_P(FirstX, DerivativesTest, +INSTANTIATE_TEST_SUITE_P(FirstX, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, DIRECTION::X)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(FirstY, DerivativesTest, +INSTANTIATE_TEST_SUITE_P(FirstY, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, DIRECTION::Y)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(FirstZ, DerivativesTest, +INSTANTIATE_TEST_SUITE_P(FirstZ, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, DIRECTION::Z)), methodDirectionTupleToString); // Instantiate the test for X, Y, Z for second derivatives -INSTANTIATE_TEST_CASE_P(SecondX, DerivativesTest, +INSTANTIATE_TEST_SUITE_P(SecondX, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, DIRECTION::X)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(SecondY, DerivativesTest, +INSTANTIATE_TEST_SUITE_P(SecondY, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, DIRECTION::Y)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(SecondZ, DerivativesTest, +INSTANTIATE_TEST_SUITE_P(SecondZ, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, DIRECTION::Z)), methodDirectionTupleToString); // Instantiate the test for X, Y, Z for fourth derivatives -INSTANTIATE_TEST_CASE_P(FourthX, DerivativesTest, +INSTANTIATE_TEST_SUITE_P(FourthX, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardFourth, DIRECTION::X)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(FourthY, DerivativesTest, +INSTANTIATE_TEST_SUITE_P(FourthY, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardFourth, DIRECTION::Y)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(FourthZ, DerivativesTest, +INSTANTIATE_TEST_SUITE_P(FourthZ, DerivativesTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardFourth, DIRECTION::Z)), methodDirectionTupleToString); // Instantiate the test for X, Y, Z for upwind derivatives -INSTANTIATE_TEST_CASE_P(UpwindX, DerivativesTestAdvection, +INSTANTIATE_TEST_SUITE_P(UpwindX, DerivativesTestAdvection, ::testing::ValuesIn(getMethodsForDirection(DERIV::Upwind, DIRECTION::X)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(UpwindY, DerivativesTestAdvection, +INSTANTIATE_TEST_SUITE_P(UpwindY, DerivativesTestAdvection, ::testing::ValuesIn(getMethodsForDirection(DERIV::Upwind, DIRECTION::Y)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(UpwindZ, DerivativesTestAdvection, +INSTANTIATE_TEST_SUITE_P(UpwindZ, DerivativesTestAdvection, ::testing::ValuesIn(getMethodsForDirection(DERIV::Upwind, DIRECTION::Z)), methodDirectionTupleToString); // Instantiate the test for X, Y, Z for flux derivatives -INSTANTIATE_TEST_CASE_P(FluxX, DerivativesTestAdvection, +INSTANTIATE_TEST_SUITE_P(FluxX, DerivativesTestAdvection, ::testing::ValuesIn(getMethodsForDirection(DERIV::Flux, DIRECTION::X)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(FluxY, DerivativesTestAdvection, +INSTANTIATE_TEST_SUITE_P(FluxY, DerivativesTestAdvection, ::testing::ValuesIn(getMethodsForDirection(DERIV::Flux, DIRECTION::Y)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(FluxZ, DerivativesTestAdvection, +INSTANTIATE_TEST_SUITE_P(FluxZ, DerivativesTestAdvection, ::testing::ValuesIn(getMethodsForDirection(DERIV::Flux, DIRECTION::Z)), methodDirectionTupleToString); @@ -304,17 +304,17 @@ TEST_P(DerivativesTestAdvection, Sanity) { using FirstDerivativesInterfaceTest = DerivativesTest; -INSTANTIATE_TEST_CASE_P(X, FirstDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(X, FirstDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, DIRECTION::X)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(FirstY, FirstDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(FirstY, FirstDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, DIRECTION::Y)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(FirstZ, FirstDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(FirstZ, FirstDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Standard, DIRECTION::Z)), methodDirectionTupleToString); @@ -340,17 +340,17 @@ TEST_P(FirstDerivativesInterfaceTest, Sanity) { using SecondDerivativesInterfaceTest = DerivativesTest; -INSTANTIATE_TEST_CASE_P(X, SecondDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(X, SecondDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, DIRECTION::X)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(Y, SecondDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(Y, SecondDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, DIRECTION::Y)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(Z, SecondDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(Z, SecondDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardSecond, DIRECTION::Z)), methodDirectionTupleToString); @@ -376,17 +376,17 @@ TEST_P(SecondDerivativesInterfaceTest, Sanity) { using FourthDerivativesInterfaceTest = DerivativesTest; -INSTANTIATE_TEST_CASE_P(X, FourthDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(X, FourthDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardFourth, DIRECTION::X)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(Y, FourthDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(Y, FourthDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardFourth, DIRECTION::Y)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(Z, FourthDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(Z, FourthDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::StandardFourth, DIRECTION::Z)), methodDirectionTupleToString); @@ -414,17 +414,17 @@ TEST_P(FourthDerivativesInterfaceTest, Sanity) { using UpwindDerivativesInterfaceTest = DerivativesTest; // Instantiate the test for X, Y, Z for upwind derivatives -INSTANTIATE_TEST_CASE_P(X, UpwindDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(X, UpwindDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Upwind, DIRECTION::X)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(Y, UpwindDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(Y, UpwindDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Upwind, DIRECTION::Y)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(Z, UpwindDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(Z, UpwindDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Upwind, DIRECTION::Z)), methodDirectionTupleToString); @@ -452,17 +452,17 @@ TEST_P(UpwindDerivativesInterfaceTest, Sanity) { using FluxDerivativesInterfaceTest = DerivativesTest; // Instantiate the test for X, Y, Z for flux derivatives -INSTANTIATE_TEST_CASE_P(X, FluxDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(X, FluxDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Flux, DIRECTION::X)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(Y, FluxDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(Y, FluxDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Flux, DIRECTION::Y)), methodDirectionTupleToString); -INSTANTIATE_TEST_CASE_P(Z, FluxDerivativesInterfaceTest, +INSTANTIATE_TEST_SUITE_P(Z, FluxDerivativesInterfaceTest, ::testing::ValuesIn(getMethodsForDirection(DERIV::Flux, DIRECTION::Z)), methodDirectionTupleToString); diff --git a/tests/unit/invert/test_fft.cxx b/tests/unit/invert/test_fft.cxx index c8343008ce..61b25cef87 100644 --- a/tests/unit/invert/test_fft.cxx +++ b/tests/unit/invert/test_fft.cxx @@ -41,7 +41,7 @@ class FFTTest : public ::testing::TestWithParam { }; // Test the FFT functions with both even- and odd-length real signals -INSTANTIATE_TEST_CASE_P(FFTEvenAndOddSamples, FFTTest, ::testing::Values(8, 9)); +INSTANTIATE_TEST_SUITE_P(FFTEvenAndOddSamples, FFTTest, ::testing::Values(8, 9)); TEST_P(FFTTest, rfft) { From d48eba754d42963e8fd982edb09e978c2d918df6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 7 Mar 2019 15:49:29 +0000 Subject: [PATCH 0995/1783] Add documentation for WithQuietOutput --- tests/unit/test_extras.hxx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 697ee4f418..1dcddedefe 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -109,6 +109,14 @@ auto IsFieldEqual(const T& field, BoutReal reference, return ::testing::AssertionSuccess(); } +/// Disable a ConditionalOutput during a scope; reenable it on +/// exit. You must give the variable a name! +/// +/// { +/// WithQuietoutput quiet{output}; +/// // output disabled during this scope +/// } +/// // output now enabled class WithQuietOutput { public: explicit WithQuietOutput(ConditionalOutput& output_in) : output(output_in) { From 41365355cd62b2537f12292fedf7c60c6a82f0e2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 7 Mar 2019 14:25:56 +0000 Subject: [PATCH 0996/1783] Write YDirectionType and ZDirectionType as attributes in output file Requires adding functions to convert YDirectionType and ZDirectionType to strings. Also add a utility template method to write all meta-data of fields as attributes, which will make it simpler to add more meta-data in future. --- include/bout_types.hxx | 4 ++++ include/datafile.hxx | 5 +++++ src/fileio/datafile.cxx | 35 ++++++++++++++++++----------------- src/sys/bout_types.cxx | 18 ++++++++++++++++++ 4 files changed, 45 insertions(+), 17 deletions(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index bb8e49d7c7..1aa0e9a83e 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -65,6 +65,8 @@ const std::string& DIRECTION_STRING(DIRECTION direction); /// coordinates enum class YDirectionType { Standard, Aligned }; +const std::string& convertYDirectionTypeToString(YDirectionType d); + /// Identify kind of a field's z-direction /// - Standard is the default /// - Average indicates that the field represents an average over the @@ -72,6 +74,8 @@ enum class YDirectionType { Standard, Aligned }; /// Field2D) enum class ZDirectionType { Standard, Average }; +const std::string& convertZDirectionTypeToString(ZDirectionType d); + /// Container for direction types struct DirectionTypes { YDirectionType y; diff --git a/include/datafile.hxx b/include/datafile.hxx index a71892d487..c88f798fb8 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -135,6 +135,11 @@ class Datafile { bool write_f2d(const std::string &name, Field2D *f, bool save_repeat); bool write_f3d(const std::string &name, Field3D *f, bool save_repeat); + /// Write out the meta-data of a field as attributes of the variable in + /// 'file'. + template + void writeFieldAttributes(const std::string name, T* f); + /// Check if a variable has already been added bool varAdded(const std::string &name); diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 1a7a45529e..9504f07275 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -849,6 +849,13 @@ bool Datafile::read() { return true; } +template +void Datafile::writeFieldAttributes(const std::string name, T* f) { + file->setAttribute(name, "cell_location", CELL_LOC_STRING(f->getLocation())); + file->setAttribute(name, "direction_y", convertYDirectionTypeToString(f->getDirectionY())); + file->setAttribute(name, "direction_z", convertZDirectionTypeToString(f->getDirectionZ())); +} + bool Datafile::write() { if(!enabled) return true; // Just pretend it worked @@ -881,39 +888,33 @@ bool Datafile::write() { if (first_time) { first_time = false; - // Set the cell location attributes. - // Location must have been set for all fields before the first time output - // is written, since this happens after the first rhs evaluation + // Set the field attributes from field meta-data. + // Attributes must have been set for all fields before the first time + // output is written, since this happens after the first rhs evaluation // 2D fields for (const auto& var : f2d_arr) { - file->setAttribute(var.name, "cell_location", CELL_LOC_STRING(var.ptr->getLocation())); + writeFieldAttributes(var.name, var.ptr); } // 3D fields for (const auto& var : f3d_arr) { - file->setAttribute(var.name, "cell_location", CELL_LOC_STRING(var.ptr->getLocation())); + writeFieldAttributes(var.name, var.ptr); } // 2D vectors for(const auto& var : v2d_arr) { Vector2D v = *(var.ptr); - file->setAttribute(var.name+"_x", "cell_location", - CELL_LOC_STRING(v.x.getLocation())); - file->setAttribute(var.name+"_y", "cell_location", - CELL_LOC_STRING(v.y.getLocation())); - file->setAttribute(var.name+"_z", "cell_location", - CELL_LOC_STRING(v.z.getLocation())); + writeFieldAttributes(var.name+"_x", &v.x); + writeFieldAttributes(var.name+"_y", &v.y); + writeFieldAttributes(var.name+"_z", &v.z); } // 3D vectors for(const auto& var : v3d_arr) { Vector3D v = *(var.ptr); - file->setAttribute(var.name+"_x", "cell_location", - CELL_LOC_STRING(v.x.getLocation())); - file->setAttribute(var.name+"_y", "cell_location", - CELL_LOC_STRING(v.y.getLocation())); - file->setAttribute(var.name+"_z", "cell_location", - CELL_LOC_STRING(v.z.getLocation())); + writeFieldAttributes(var.name+"_x", &v.x); + writeFieldAttributes(var.name+"_y", &v.y); + writeFieldAttributes(var.name+"_z", &v.z); } } diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index d7dda8063c..c3da044c25 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -116,3 +116,21 @@ const std::string& DERIV_STRING(DERIV deriv) { return safeAt(DERIVtoString, deriv); } + +const std::string& convertYDirectionTypeToString(YDirectionType d) { + AUTO_TRACE(); + const static std::map YDirectionTypeToString = { + {YDirectionType::Standard, "Standard"}, + {YDirectionType::Aligned, "Aligned"}}; + + return safeAt(YDirectionTypeToString, d); +} + +const std::string& convertZDirectionTypeToString(ZDirectionType d) { + AUTO_TRACE(); + const static std::map ZDirectionTypeToString = { + {ZDirectionType::Standard, "Standard"}, + {ZDirectionType::Average, "Average"}}; + + return safeAt(ZDirectionTypeToString, d); +} From 1e12b4055f6e40a96d4f9398d478d1032e0db094 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 7 Mar 2019 17:17:43 +0000 Subject: [PATCH 0997/1783] Add direction types and emptyFrom/zeroFrom to the manual --- manual/sphinx/developer_docs/data_types.rst | 41 +++++++++++++++++++ .../sphinx/user_docs/parallel-transforms.rst | 4 +- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/manual/sphinx/developer_docs/data_types.rst b/manual/sphinx/developer_docs/data_types.rst index 6bfffff328..cdba1d87d0 100644 --- a/manual/sphinx/developer_docs/data_types.rst +++ b/manual/sphinx/developer_docs/data_types.rst @@ -61,6 +61,47 @@ which returns a pointer to the field holding the time-derivative of this variable. This function ensures that this field is unique using a singleton pattern. +A `Field` has meta-data members, which give: + - ``location`` is the location of the field values in a grid cell. May be + unstaggered, ``CELL_CENTRE`` or staggered to one of the cell faces, + ``CELL_XLOW``, ``CELL_YLOW`` or ``CELL_ZLOW``. + - ``directions`` gives the type of grid that the `Field` is defined on + - ``directions.y`` is ``YDirectionType::Standard`` by default, but can be + ``YDirectionType::Aligned`` if the `Field` has been transformed from an + 'orthogonal' to a 'field-aligned' coordinate system. + - ``directions.z`` is ``ZDirectionType::Standard`` by default, but can be + ``ZDirectionType::Average`` if the `Field` represents a quantity that + is averaged or constant in the z-direction (i.e. is a `Field2D`). +The meta-data members are written to the output files as attributes of the variables. + +To create a new `Field` with meta-data, plus ``Mesh`` and ``Coordinates`` +pointers copied from another one, and data allocated (so that the Field is +ready to use) but not initialized, use the function ``emptyFrom(const T& f)`` +which can act on `Field3D`, `Field2D` or `FieldPerp`. This is often used for +example to create a ``result`` variable that will be returned from a function +from the `Field` which is given as input, e.g. + +:: + + Field3D exampleFunction(const Field3D& f) { + Field3D result{emptyFrom(f)}; + ... + < do things to calculate result > + ... + return result; + } + +To zero-initialise the `Field` as well, use ``zeroFrom`` in place of +``emptyFrom``. If a few of the meta-data members need to be changed, you can +also chain setter methods to a `Field`. At the moment the available methods are +``setLocation(CELL_LOC)``, ``setDirectionY(YDirectionType)`` and +``setDirectionZ(ZDirectionType)``; also ``setIndex(int)`` for `FieldPerp`. For +example, to set the location of ``result`` explicitly you could use + +:: + + Field3D result{emptyFrom(f).setLocation(CELL_YLOW)}; + ``Vector`` ---------- diff --git a/manual/sphinx/user_docs/parallel-transforms.rst b/manual/sphinx/user_docs/parallel-transforms.rst index 5c6f6cd612..af2aca34cf 100644 --- a/manual/sphinx/user_docs/parallel-transforms.rst +++ b/manual/sphinx/user_docs/parallel-transforms.rst @@ -91,9 +91,9 @@ location :math:`\theta_0`: .. math:: - zShift = \int_{\theta_0}^\theta \frac{B_\phi h_\theta}{B_\theta R} d\theta + \mathtt{zShift} = \int_{\theta_0}^\theta \frac{B_\phi h_\theta}{B_\theta R} d\theta -Note that here :math:`theta_0` does not need to be constant in X +Note that here :math:`\theta_0` does not need to be constant in X (radius), since it is only the relative shifts between Y locations which matters. From 1285c91fd8ae30f9e541baa3b96687c214048121 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 7 Mar 2019 17:36:51 +0000 Subject: [PATCH 0998/1783] Allow method chaining with FieldPerp::setIndex Make FieldPerp::setIndex return FieldPerp& instead of void so we can do things like 'return result.setIndex(jy);'. --- include/fieldperp.hxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index ef1f8b4aa5..abf0ad35de 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -118,7 +118,10 @@ class FieldPerp : public Field { * * This is used in arithmetic operations */ - void setIndex(int y) { yindex = y; } + FieldPerp& setIndex(int y) { + yindex = y; + return *this; + } // these methods return FieldPerp to allow method chaining FieldPerp& setLocation(CELL_LOC location) { From 65fc340d3ecedc2f6321eab62ae06f3f84466d2b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 7 Mar 2019 18:25:31 +0000 Subject: [PATCH 0999/1783] Move parallel transform class declarations to .hxx in src/mesh/parallel --- include/bout/paralleltransform.hxx | 188 +----------------- src/mesh/mesh.cxx | 2 + src/mesh/parallel/identity.cxx | 5 +- src/mesh/parallel/identity.hxx | 73 +++++++ src/mesh/parallel/shiftedmetric.cxx | 3 +- src/mesh/parallel/shiftedmetric.hxx | 170 ++++++++++++++++ .../integrated/test-yupdown/test_yupdown.cxx | 2 +- .../unit/mesh/parallel/test_shiftedmetric.cxx | 2 +- tests/unit/test_extras.hxx | 1 + 9 files changed, 255 insertions(+), 191 deletions(-) create mode 100644 src/mesh/parallel/identity.hxx create mode 100644 src/mesh/parallel/shiftedmetric.hxx diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 09b654f544..c2ecea12f7 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -6,12 +6,9 @@ #ifndef __PARALLELTRANSFORM_H__ #define __PARALLELTRANSFORM_H__ -#include -#include -#include -#include -#include +#include "bout_types.hxx" +class Field3D; class Mesh; /*! @@ -54,185 +51,4 @@ protected: Mesh &mesh; ///< The mesh this paralleltransform is part of }; - -/*! - * This class implements the simplest form of ParallelTransform - * where the domain is a logically rectangular domain, and - * yup() and ydown() refer to the same field. - */ -class ParallelTransformIdentity : public ParallelTransform { -public: - ParallelTransformIdentity(Mesh& mesh_in) : ParallelTransform(mesh_in) { - // check the coordinate system used for the grid data source - checkInputGrid(); - } - - /*! - * Merges the yup and ydown() fields of f, so that - * f.yup() = f.ydown() = f - */ - void calcYUpDown(Field3D &f) override; - - /*! - * The field is already aligned in Y, so this - * does nothing - */ - const Field3D toFieldAligned(const Field3D &f, const REGION UNUSED(region)) override { - return f; - } - - /*! - * The field is already aligned in Y, so this - * does nothing - */ - const Field3D fromFieldAligned(const Field3D &f, const REGION UNUSED(region)) override { - return f; - } - - bool canToFromFieldAligned() override{ - return true; - } - -protected: - void checkInputGrid() override; -}; - -/*! - * Shifted metric method - * Each Y location is shifted in Z with respect to its neighbours - * so that the grid is orthogonal in X-Z, but requires interpolation - * to calculate the values of points along field-lines. - * - * In this implementation the interpolation is done using FFTs in Z - */ -class ShiftedMetric : public ParallelTransform { -public: - ShiftedMetric() = delete; - /// Read zShift from the mesh - ShiftedMetric(Mesh &mesh); - /// Use an existing zShift - ShiftedMetric(Mesh &mesh, Field2D zShift); - - /*! - * Calculates the yup() and ydown() fields of f - * by taking FFTs in Z and applying a phase shift. - */ - void calcYUpDown(Field3D &f) override; - - /*! - * Uses FFTs and a phase shift to align the grid points - * with the y coordinate (along magnetic field usually). - * - * Note that the returned field will no longer be orthogonal - * in X-Z, and the metric tensor will need to be changed - * if X derivatives are used. - */ - const Field3D toFieldAligned(const Field3D &f, const REGION region=RGN_ALL) override; - - /*! - * Converts a field back to X-Z orthogonal coordinates - * from field aligned coordinates. - */ - const Field3D fromFieldAligned(const Field3D &f, const REGION region=RGN_ALL) override; - - bool canToFromFieldAligned() override{ - return true; - } - -protected: - void checkInputGrid() override; - -private: - /// This is the shift in toroidal angle (z) which takes a point from - /// X-Z orthogonal to field-aligned along Y. - Field2D zShift; - - int nmodes; - - Tensor toAlignedPhs; ///< Cache of phase shifts for transforming from X-Z - ///orthogonal coordinates to field-aligned coordinates - Tensor fromAlignedPhs; ///< Cache of phase shifts for transforming from - ///field-aligned coordinates to X-Z orthogonal - ///coordinates - - /// Helper POD for parallel slice phase shifts - struct ParallelSlicePhase { - Tensor phase_shift; - int y_offset; - }; - - /// Cache of phase shifts for the parallel slices. Slices are stored - /// in the following order: - /// {+1, ..., +n, -1, ..., -n} - /// slice[i] stores offset i+1 - /// slice[2*i + 1] stores offset -(i+1) - /// where i goes from 0 to (n-1), with n the number of y guard cells - std::vector parallel_slice_phases; - - /*! - * Shift a 2D field in Z. - * Since 2D fields are constant in Z, this has no effect - */ - const Field2D shiftZ(const Field2D &f, const Field2D &UNUSED(zangle), - const REGION UNUSED(region)=RGN_NOX) const { - return f; - }; - - /*! - * Shift a 3D field \p f in Z by the given \p zangle - * - * @param[in] f The field to shift - * @param[in] zangle Toroidal angle (z) - * - */ - const Field3D shiftZ(const Field3D &f, const Field2D &zangle, - const REGION region=RGN_NOX) const; - - /*! - * Shift a 3D field \p f by the given phase \p phs in Z - * - * Calculates FFT in Z, multiplies by the complex phase - * and inverse FFTS. - * - * @param[in] f The field to shift - * @param[in] phs The phase to shift by - * @param[in] y_direction_out The value to set yDirectionType of the result to - */ - const Field3D shiftZ(const Field3D& f, const Tensor& phs, - const YDirectionType y_direction_out, - const REGION region = RGN_NOX) const; - - /*! - * Shift a given 1D array, assumed to be in Z, by the given \p zangle - * - * @param[in] in A 1D array of length \p len - * @param[in] len Length of the in and out arrays - * @param[in] zangle The angle (z coordinate) to shift by - * @param[out] out A 1D array of length \p len, already allocated - */ - void shiftZ(const BoutReal *in, int len, BoutReal zangle, BoutReal *out) const; - - /*! - * Shift a given 1D array, assumed to be in Z, by the given \p zangle - * - * @param[in] in A 1D array of length mesh.LocalNz - * @param[in] phs Phase shift, assumed to have length (mesh.LocalNz/2 + 1) i.e. the number of modes - * @param[out] out A 1D array of length mesh.LocalNz, already allocated - */ - void shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* out) const; - - /// Calculate and store the phases for to/from field aligned and for - /// the parallel slices using zShift - void cachePhases(); - - /// Shift a 3D field \p f in Z to all the parallel slices in \p phases - /// - /// @param[in] f The field to shift - /// @param[in] phases The phase and offset information for each parallel slice - /// @return The shifted parallel slices - std::vector shiftZ(const Field3D& f, - const std::vector& phases) const; -}; - - #endif // __PARALLELTRANSFORM_H__ diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 2460895078..f6758d6036 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -12,6 +12,8 @@ #include +#include "parallel/identity.hxx" +#include "parallel/shiftedmetric.hxx" #include "parallel/fci.hxx" Mesh* Mesh::create(GridDataSource *s, Options *opt) { diff --git a/src/mesh/parallel/identity.cxx b/src/mesh/parallel/identity.cxx index ca4a78b7f2..1f725837ea 100644 --- a/src/mesh/parallel/identity.cxx +++ b/src/mesh/parallel/identity.cxx @@ -6,8 +6,9 @@ * */ -#include -#include +#include "identity.hxx" + +#include "bout/mesh.hxx" void ParallelTransformIdentity::calcYUpDown(Field3D& f) { f.splitYupYdown(); diff --git a/src/mesh/parallel/identity.hxx b/src/mesh/parallel/identity.hxx new file mode 100644 index 0000000000..b71ee82a36 --- /dev/null +++ b/src/mesh/parallel/identity.hxx @@ -0,0 +1,73 @@ +/************************************************************************** + * Parallel derivatives without any transform + * + ************************************************************************** + * Copyright 2015, 2016 B.D.Dudson, D. Dickinson + * + * Contact: Ben Dudson, bd512@york.ac.uk + * + * This file is part of BOUT++. + * + * BOUT++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BOUT++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with BOUT++. If not, see . + * + **************************************************************************/ + +#ifndef __IDENTITYTRANSFORM_H__ +#define __IDENTITYTRANSFORM_H__ + +#include "bout/paralleltransform.hxx" +#include "field3d.hxx" +#include "unused.hxx" + +/*! + * This class implements the simplest form of ParallelTransform + * where the domain is a logically rectangular domain, and + * yup() and ydown() refer to the same field. + */ +class ParallelTransformIdentity : public ParallelTransform { +public: + ParallelTransformIdentity(Mesh& mesh_in) : ParallelTransform(mesh_in) { + // check the coordinate system used for the grid data source + checkInputGrid(); + } + + /*! + * Merges the yup and ydown() fields of f, so that + * f.yup() = f.ydown() = f + */ + void calcYUpDown(Field3D& f) override; + + /*! + * The field is already aligned in Y, so this + * does nothing + */ + const Field3D toFieldAligned(const Field3D& f, const REGION UNUSED(region)) override { + return f; + } + + /*! + * The field is already aligned in Y, so this + * does nothing + */ + const Field3D fromFieldAligned(const Field3D& f, const REGION UNUSED(region)) override { + return f; + } + + bool canToFromFieldAligned() override { return true; } + +protected: + void checkInputGrid() override; +}; + +#endif // __IDENTITYTRANSFORM_H__ diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 670f38dce5..432c384b8d 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -6,9 +6,10 @@ * */ +#include "shiftedmetric.hxx" + #include #include -#include #include #include diff --git a/src/mesh/parallel/shiftedmetric.hxx b/src/mesh/parallel/shiftedmetric.hxx new file mode 100644 index 0000000000..baa111ceea --- /dev/null +++ b/src/mesh/parallel/shiftedmetric.hxx @@ -0,0 +1,170 @@ +/************************************************************************** + * Shifted-metric parallel derivatives + * + ************************************************************************** + * Copyright 2015, 2016 B.D.Dudson, D. Dickinson + * + * Contact: Ben Dudson, bd512@york.ac.uk + * + * This file is part of BOUT++. + * + * BOUT++ is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BOUT++ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with BOUT++. If not, see . + * + **************************************************************************/ + +#ifndef __SHIFTEDMETRIC_H__ +#define __SHIFTEDMETRIC_H__ + +#include "bout/paralleltransform.hxx" + +#include "field2d.hxx" + +/*! + * Shifted metric method + * Each Y location is shifted in Z with respect to its neighbours + * so that the grid is orthogonal in X-Z, but requires interpolation + * to calculate the values of points along field-lines. + * + * In this implementation the interpolation is done using FFTs in Z + */ +class ShiftedMetric : public ParallelTransform { +public: + ShiftedMetric() = delete; + /// Read zShift from the mesh + ShiftedMetric(Mesh& mesh); + /// Use an existing zShift + ShiftedMetric(Mesh& mesh, Field2D zShift); + + /*! + * Calculates the yup() and ydown() fields of f + * by taking FFTs in Z and applying a phase shift. + */ + void calcYUpDown(Field3D& f) override; + + /*! + * Uses FFTs and a phase shift to align the grid points + * with the y coordinate (along magnetic field usually). + * + * Note that the returned field will no longer be orthogonal + * in X-Z, and the metric tensor will need to be changed + * if X derivatives are used. + */ + const Field3D toFieldAligned(const Field3D& f, const REGION region = RGN_ALL) override; + + /*! + * Converts a field back to X-Z orthogonal coordinates + * from field aligned coordinates. + */ + const Field3D fromFieldAligned(const Field3D& f, + const REGION region = RGN_ALL) override; + + bool canToFromFieldAligned() override { return true; } + +protected: + void checkInputGrid() override; + +private: + /// This is the shift in toroidal angle (z) which takes a point from + /// X-Z orthogonal to field-aligned along Y. + Field2D zShift; + + int nmodes; + + Tensor toAlignedPhs; ///< Cache of phase shifts for transforming from X-Z + /// orthogonal coordinates to field-aligned coordinates + Tensor fromAlignedPhs; ///< Cache of phase shifts for transforming from + /// field-aligned coordinates to X-Z orthogonal + /// coordinates + + /// Helper POD for parallel slice phase shifts + struct ParallelSlicePhase { + Tensor phase_shift; + int y_offset; + }; + + /// Cache of phase shifts for the parallel slices. Slices are stored + /// in the following order: + /// {+1, ..., +n, -1, ..., -n} + /// slice[i] stores offset i+1 + /// slice[2*i + 1] stores offset -(i+1) + /// where i goes from 0 to (n-1), with n the number of y guard cells + std::vector parallel_slice_phases; + + /*! + * Shift a 2D field in Z. + * Since 2D fields are constant in Z, this has no effect + */ + const Field2D shiftZ(const Field2D& f, const Field2D& UNUSED(zangle), + const REGION UNUSED(region) = RGN_NOX) const { + return f; + }; + + /*! + * Shift a 3D field \p f in Z by the given \p zangle + * + * @param[in] f The field to shift + * @param[in] zangle Toroidal angle (z) + * + */ + const Field3D shiftZ(const Field3D& f, const Field2D& zangle, + const REGION region = RGN_NOX) const; + + /*! + * Shift a 3D field \p f by the given phase \p phs in Z + * + * Calculates FFT in Z, multiplies by the complex phase + * and inverse FFTS. + * + * @param[in] f The field to shift + * @param[in] phs The phase to shift by + * @param[in] y_direction_out The value to set yDirectionType of the result to + */ + const Field3D shiftZ(const Field3D& f, const Tensor& phs, + const YDirectionType y_direction_out, + const REGION region = RGN_NOX) const; + + /*! + * Shift a given 1D array, assumed to be in Z, by the given \p zangle + * + * @param[in] in A 1D array of length \p len + * @param[in] len Length of the in and out arrays + * @param[in] zangle The angle (z coordinate) to shift by + * @param[out] out A 1D array of length \p len, already allocated + */ + void shiftZ(const BoutReal* in, int len, BoutReal zangle, BoutReal* out) const; + + /*! + * Shift a given 1D array, assumed to be in Z, by the given \p zangle + * + * @param[in] in A 1D array of length mesh.LocalNz + * @param[in] phs Phase shift, assumed to have length (mesh.LocalNz/2 + 1) i.e. the + * number of modes + * @param[out] out A 1D array of length mesh.LocalNz, already allocated + */ + void shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* out) const; + + /// Calculate and store the phases for to/from field aligned and for + /// the parallel slices using zShift + void cachePhases(); + + /// Shift a 3D field \p f in Z to all the parallel slices in \p phases + /// + /// @param[in] f The field to shift + /// @param[in] phases The phase and offset information for each parallel slice + /// @return The shifted parallel slices + std::vector shiftZ(const Field3D& f, + const std::vector& phases) const; +}; + +#endif // __SHIFTEDMETRIC_H__ diff --git a/tests/integrated/test-yupdown/test_yupdown.cxx b/tests/integrated/test-yupdown/test_yupdown.cxx index dbadc6372f..a3642caa03 100644 --- a/tests/integrated/test-yupdown/test_yupdown.cxx +++ b/tests/integrated/test-yupdown/test_yupdown.cxx @@ -1,6 +1,6 @@ #include -#include +#include <../src/mesh/parallel/shiftedmetric.hxx> #include diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 80f9c75041..0e3d192f7e 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -2,7 +2,7 @@ #include "fft.hxx" #include "test_extras.hxx" -#include "bout/paralleltransform.hxx" +#include "../src/mesh/parallel/shiftedmetric.hxx" // The unit tests use the global mesh using namespace bout::globals; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index e468321539..cbe136bd7f 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -12,6 +12,7 @@ #include "bout/coordinates.hxx" #include "field3d.hxx" #include "unused.hxx" +#include "../src/mesh/parallel/identity.hxx" static constexpr BoutReal BoutRealTolerance{1e-15}; // FFTs have a slightly looser tolerance than other functions From 7a01bd592a9ad2e3981a36934bd30eee66d9c0d0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 8 Mar 2019 08:05:07 +0000 Subject: [PATCH 1000/1783] Use move assignment instead of swap to replace Coordinates in coords_map We can use the default move assignment operator for Coordinates. Using move assignment instead of swap will allow having std::unique_ptr members of Coordinates more easily: the std::swap template that was used to swap Coordinates objects uses the copy constructor, but std::unique_ptr cannot be copied. --- include/bout/coordinates.hxx | 2 ++ src/mesh/mesh.cxx | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index bc04da7165..700a3004c1 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -63,6 +63,8 @@ public: Field2D g_13, Field2D g_23, Field2D ShiftTorsion, Field2D IntShiftTorsion, bool calculate_geometry = true); + Coordinates& operator=(Coordinates&&) = default; + ~Coordinates() = default; /*! diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index f6758d6036..70618ffa3d 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -466,6 +466,6 @@ void Mesh::recalculateStaggeredCoordinates() { continue; } - std::swap(*coords_map[location], *createDefaultCoordinates(location)); + *coords_map[location] = std::move(*createDefaultCoordinates(location)); } } From 8571ef241cd51c7dca7ac05819effb3417607d83 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 8 Mar 2019 08:12:27 +0000 Subject: [PATCH 1001/1783] Move ParallelTransform ownership from Mesh to Coordinates This means the ParallelTransform objects naturally have a specific location, defined by their owning Coordinates object. Also, require zShift and zlength to be passed to the ShiftedMetric constructor, so Coordinates is responsible for getting zShift from the grid (at the correct location). Passing zlength means that the ShiftedMetric constructor does not require a Coordinates object, and therefore can be created in the Coordinates constructor. Need to pass an Options* pointer to the Coordinates constructor from the owning Mesh object, so Coordinates can use it to initialize the ParallelTransform. --- include/bout/coordinates.hxx | 40 +++++++++++++- include/bout/mesh.hxx | 50 ----------------- src/bout++.cxx | 1 - src/mesh/coordinates.cxx | 86 ++++++++++++++++++++++++++++- src/mesh/mesh.cxx | 48 +--------------- src/mesh/parallel/shiftedmetric.cxx | 21 ++----- src/mesh/parallel/shiftedmetric.hxx | 10 ++-- 7 files changed, 134 insertions(+), 122 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index 700a3004c1..fee264bf70 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -33,6 +33,7 @@ #ifndef __COORDINATES_H__ #define __COORDINATES_H__ +#include "bout/paralleltransform.hxx" #include "datafile.hxx" #include "utils.hxx" #include @@ -49,10 +50,10 @@ class Mesh; class Coordinates { public: /// Standard constructor from input - Coordinates(Mesh *mesh); + Coordinates(Mesh *mesh, Options* options); /// Constructor interpolating from another Coordinates object - Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coords_in); + Coordinates(Mesh *mesh, Options* options, const CELL_LOC loc, const Coordinates* coords_in); /// A constructor useful for testing purposes. To use it, inherit /// from Coordinates. If \p calculate_geometry is true (default), @@ -110,7 +111,35 @@ public: int calcContravariant(); ///< Invert covariant metric to get contravariant int jacobian(); ///< Calculate J and Bxy + + /////////////////////////////////////////////////////////// + // Parallel transforms + /////////////////////////////////////////////////////////// + + /// Set the parallel (y) transform for this mesh. + /// Unique pointer used so that ParallelTransform will be deleted. + /// Mostly useful for tests. + void setParallelTransform(std::unique_ptr pt) { + transform = std::move(pt); + } + + /// Return the parallel transform, setting it if need be + ParallelTransform& getParallelTransform(); + + /// Transform a field into field-aligned coordinates + const Field3D toFieldAligned(const Field3D &f, const REGION region = RGN_ALL); + const Field2D toFieldAligned(const Field2D &f, const REGION UNUSED(region) = RGN_ALL); + + /// Convert back into standard form + const Field3D fromFieldAligned(const Field3D &f, const REGION region = RGN_ALL); + const Field2D fromFieldAligned(const Field2D &f, const REGION UNUSED(region) = RGN_ALL); + + bool canToFromFieldAligned(); + + + /////////////////////////////////////////////////////////// // Operators + /////////////////////////////////////////////////////////// const Field2D DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); @@ -212,6 +241,13 @@ private: int nz; // Size of mesh in Z. This is mesh->ngz-1 Mesh * localmesh; CELL_LOC location; + + /// Handles calculation of yup and ydown + std::unique_ptr transform{nullptr}; + + /// Set the parallel (y) transform from the options file. + /// Usual way to create the transform object. + void setParallelTransform(Options* options); }; /* diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index fd0d1ab845..0743b9dfd1 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -67,8 +67,6 @@ class Mesh; #include "coordinates.hxx" // Coordinates class -#include "paralleltransform.hxx" // ParallelTransform class - #include "unused.hxx" #include @@ -700,52 +698,7 @@ class Mesh { return bout::derivatives::index::FDDZ(vel, f, outloc, method, region); } - /////////////////////////////////////////////////////////// - // PARALLEL TRANSFORMS - /////////////////////////////////////////////////////////// - - /// Transform a field into field-aligned coordinates - const Field3D toFieldAligned(const Field3D &f, const REGION region = RGN_ALL) { - return getParallelTransform().toFieldAligned(f, region); - } - const Field2D toFieldAligned(const Field2D &f, const REGION UNUSED(region) = RGN_ALL) { - return f; - } - - /// Convert back into standard form - const Field3D fromFieldAligned(const Field3D &f, const REGION region = RGN_ALL) { - return getParallelTransform().fromFieldAligned(f, region); - } - const Field2D fromFieldAligned(const Field2D &f, const REGION UNUSED(region) = RGN_ALL) { - return f; - } - - bool canToFromFieldAligned() { - return getParallelTransform().canToFromFieldAligned(); - } - - /*! - * Unique pointer to ParallelTransform object - */ - typedef std::unique_ptr PTptr; - - /*! - * Set the parallel (y) transform for this mesh. - * Unique pointer used so that ParallelTransform will be deleted - */ - void setParallelTransform(PTptr pt) { - transform = std::move(pt); - } - /*! - * Set the parallel (y) transform from the options file - */ - void setParallelTransform(); - /*! - * Return the parallel transform, setting it if need be - */ - ParallelTransform& getParallelTransform(); - /////////////////////////////////////////////////////////// // REGION RELATED ROUTINES /////////////////////////////////////////////////////////// @@ -825,9 +778,6 @@ protected: /// Set whether to call calcYUpDown on all communicated fields (true) or not (false) bool calcYUpDown_on_communicate{true}; - /// Handles calculation of yup and ydown - PTptr transform{nullptr}; - /// Read a 1D array of integers const std::vector readInts(const std::string &name, int n); diff --git a/src/bout++.cxx b/src/bout++.cxx index c855105e64..32c323b981 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -480,7 +480,6 @@ int BoutInitialise(int &argc, char **&argv) { bout::globals::mesh = Mesh::create(); ///< Create the mesh bout::globals::mesh->load(); ///< Load from sources. Required for Field initialisation - bout::globals::mesh->setParallelTransform(); ///< Set the parallel transform from options ///////////////////////////////////////////// /// Get some settings diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index b39816cf4e..663d2e1965 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -17,6 +17,10 @@ #include +#include "parallel/identity.hxx" +#include "parallel/shiftedmetric.hxx" +#include "parallel/fci.hxx" + Coordinates::Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2D J, Field2D Bxy, Field2D g11, Field2D g22, Field2D g33, Field2D g12, Field2D g13, Field2D g23, Field2D g_11, Field2D g_22, @@ -37,7 +41,7 @@ Coordinates::Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2 } } -Coordinates::Coordinates(Mesh *mesh) +Coordinates::Coordinates(Mesh *mesh, Options* options) : dx(1, mesh), dy(1, mesh), dz(1), d1_dx(mesh), d1_dy(mesh), J(1, mesh), Bxy(1, mesh), // Identity metric tensor g11(1, mesh), g22(1, mesh), g33(1, mesh), g12(0, mesh), g13(0, mesh), g23(0, mesh), @@ -189,6 +193,8 @@ Coordinates::Coordinates(Mesh *mesh) // IntShiftTorsion will not be used, but set to zero to avoid uninitialized field IntShiftTorsion = 0.; } + + setParallelTransform(options); } // use anonymous namespace so this utility function is not available outside this file @@ -239,7 +245,7 @@ namespace { } } -Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coords_in) +Coordinates::Coordinates(Mesh *mesh, Options* options, const CELL_LOC loc, const Coordinates* coords_in) : dx(1, mesh), dy(1, mesh), dz(1), d1_dx(mesh), d1_dy(mesh), J(1, mesh), Bxy(1, mesh), // Identity metric tensor g11(1, mesh), g22(1, mesh), g33(1, mesh), g12(0, mesh), g13(0, mesh), g23(0, mesh), @@ -304,6 +310,8 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor // IntShiftTorsion will not be used, but set to zero to avoid uninitialized field IntShiftTorsion = 0.; } + + setParallelTransform(options); } void Coordinates::outputVars(Datafile &file) { @@ -653,6 +661,80 @@ int Coordinates::jacobian() { return 0; } +void Coordinates::setParallelTransform(Options* options) { + + std::string ptstr; + options->get("paralleltransform", ptstr, "identity"); + + // Convert to lower case for comparison + ptstr = lowercase(ptstr); + + if(ptstr == "identity") { + // Identity method i.e. no transform needed + transform = bout::utils::make_unique(*localmesh); + + } else if (ptstr == "shifted") { + // Shifted metric method + + Field2D zShift{localmesh}; + + // Read the zShift angle from the mesh + if (localmesh->get(zShift, "zShift")) { + // No zShift variable. Try qinty in BOUT grid files + localmesh->get(zShift, "qinty"); + } + + zShift = interpolateAndNeumann(zShift, location); + + // make sure zShift has been communicated + localmesh->communicate(zShift); + + transform = bout::utils::make_unique(*localmesh, location, zShift, + zlength()); + + } else if (ptstr == "fci") { + + if (location != CELL_CENTRE) { + throw BoutException("FCITransform is not available on staggered grids."); + } + + Options *fci_options = Options::getRoot()->getSection("fci"); + // Flux Coordinate Independent method + bool fci_zperiodic; + fci_options->get("z_periodic", fci_zperiodic, true); + transform = bout::utils::make_unique(*localmesh, fci_zperiodic); + + } else { + throw BoutException(_("Unrecognised paralleltransform option.\n" + "Valid choices are 'identity', 'shifted', 'fci'")); + } +} + +ParallelTransform& Coordinates::getParallelTransform() { + // Return a reference to the ParallelTransform object + return *transform; +} + +/// Transform a field into field-aligned coordinates +const Field3D Coordinates::toFieldAligned(const Field3D &f, const REGION region) { + return getParallelTransform().toFieldAligned(f, region); +} +const Field2D Coordinates::toFieldAligned(const Field2D &f, const REGION UNUSED(region)) { + return f; +} + +/// Convert back into standard form +const Field3D Coordinates::fromFieldAligned(const Field3D &f, const REGION region) { + return getParallelTransform().fromFieldAligned(f, region); +} +const Field2D Coordinates::fromFieldAligned(const Field2D &f, const REGION UNUSED(region)) { + return f; +} + +bool Coordinates::canToFromFieldAligned() { + return getParallelTransform().canToFromFieldAligned(); +} + /******************************************************************************* * Operators * diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 70618ffa3d..bf884e6eaf 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -12,10 +12,6 @@ #include -#include "parallel/identity.hxx" -#include "parallel/shiftedmetric.hxx" -#include "parallel/fci.hxx" - Mesh* Mesh::create(GridDataSource *s, Options *opt) { return MeshFactory::getInstance()->createMesh(s, opt); } @@ -301,53 +297,13 @@ const std::vector Mesh::readInts(const std::string &name, int n) { return result; } -void Mesh::setParallelTransform() { - - std::string ptstr; - options->get("paralleltransform", ptstr, "identity"); - - // Convert to lower case for comparison - ptstr = lowercase(ptstr); - - if(ptstr == "identity") { - // Identity method i.e. no transform needed - transform = bout::utils::make_unique(*this); - - }else if(ptstr == "shifted") { - // Shifted metric method - transform = bout::utils::make_unique(*this); - - }else if(ptstr == "fci") { - - Options *fci_options = Options::getRoot()->getSection("fci"); - // Flux Coordinate Independent method - bool fci_zperiodic; - fci_options->get("z_periodic", fci_zperiodic, true); - transform = bout::utils::make_unique(*this, fci_zperiodic); - - }else { - throw BoutException(_("Unrecognised paralleltransform option.\n" - "Valid choices are 'identity', 'shifted', 'fci'")); - } -} - -ParallelTransform& Mesh::getParallelTransform() { - if(!transform) { - // No ParallelTransform object yet. Set from options - setParallelTransform(); - } - - // Return a reference to the ParallelTransform object - return *transform; -} - std::shared_ptr Mesh::createDefaultCoordinates(const CELL_LOC location) { if (location == CELL_CENTRE || location == CELL_DEFAULT) { // Initialize coordinates from input - return std::make_shared(this); + return std::make_shared(this, options); } else { // Interpolate coordinates from CELL_CENTRE version - return std::make_shared(this, location, getCoordinates(CELL_CENTRE)); + return std::make_shared(this, options, location, getCoordinates(CELL_CENTRE)); } } diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 432c384b8d..61b993b2ab 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -16,16 +16,13 @@ #include -ShiftedMetric::ShiftedMetric(Mesh& m) : ParallelTransform(m), zShift(&m) { +ShiftedMetric::ShiftedMetric(Mesh& m, CELL_LOC location_in, Field2D zShift_, + BoutReal zlength_in) + : ParallelTransform(m), location(location_in), zShift(std::move(zShift_)), + zlength(zlength_in) { // check the coordinate system used for the grid data source checkInputGrid(); - // Read the zShift angle from the mesh - if (mesh.get(zShift, "zShift")) { - // No zShift variable. Try qinty in BOUT grid files - mesh.get(zShift, "qinty"); - } - // TwistShift needs to be set for derivatives to be correct at the jump where // poloidal angle theta goes 2pi->0 bool twistshift = Options::root()["TwistShift"].withDefault(false); @@ -39,14 +36,6 @@ ShiftedMetric::ShiftedMetric(Mesh& m) : ParallelTransform(m), zShift(&m) { cachePhases(); } -ShiftedMetric::ShiftedMetric(Mesh& m, Field2D zShift_) - : ParallelTransform(m), zShift(std::move(zShift_)) { - // check the coordinate system used for the grid data source - checkInputGrid(); - - cachePhases(); -} - void ShiftedMetric::checkInputGrid() { std::string coordinates_type = ""; if (!mesh.get(coordinates_type, "coordinates_type")) { @@ -70,7 +59,6 @@ void ShiftedMetric::cachePhases() { // not change once we've been created so precalculate the complex // phases used in transformations nmodes = mesh.LocalNz / 2 + 1; - BoutReal zlength = mesh.getCoordinates()->zlength(); // Allocate storage for our 3d phase information. fromAlignedPhs = Tensor(mesh.LocalNx, mesh.LocalNy, nmodes); @@ -305,7 +293,6 @@ void ShiftedMetric::shiftZ(const BoutReal* in, int len, BoutReal zangle, rfft(in, len, &cmplxLoc[0]); // Apply phase shift - BoutReal zlength = mesh.getCoordinates()->zlength(); for (int jz = 1; jz < nmodes; jz++) { BoutReal kwave = jz * 2.0 * PI / zlength; // wave number is 1/[rad] cmplxLoc[jz] *= dcomplex(cos(kwave * zangle), -sin(kwave * zangle)); diff --git a/src/mesh/parallel/shiftedmetric.hxx b/src/mesh/parallel/shiftedmetric.hxx index baa111ceea..ecf0a42de9 100644 --- a/src/mesh/parallel/shiftedmetric.hxx +++ b/src/mesh/parallel/shiftedmetric.hxx @@ -41,10 +41,7 @@ class ShiftedMetric : public ParallelTransform { public: ShiftedMetric() = delete; - /// Read zShift from the mesh - ShiftedMetric(Mesh& mesh); - /// Use an existing zShift - ShiftedMetric(Mesh& mesh, Field2D zShift); + ShiftedMetric(Mesh& mesh, CELL_LOC location, Field2D zShift, BoutReal zlength_in); /*! * Calculates the yup() and ydown() fields of f @@ -75,10 +72,15 @@ protected: void checkInputGrid() override; private: + CELL_LOC location{CELL_CENTRE}; + /// This is the shift in toroidal angle (z) which takes a point from /// X-Z orthogonal to field-aligned along Y. Field2D zShift; + /// Length of the z-domain in radians + BoutReal zlength{0.}; + int nmodes; Tensor toAlignedPhs; ///< Cache of phase shifts for transforming from X-Z From d938963657076c9fd9f1d5654ecdb5d5a603150f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 8 Mar 2019 10:04:13 +0000 Subject: [PATCH 1002/1783] Update boutcore: don't need to include Mesh::setParallelTransform Mesh::setParallelTransform no longer exists since ownership of ParallelTransforms moved to Coordinates, and a replacement is not needed as the ParallelTransforms are created within the Coordinates constructor. --- tools/pylib/_boutcore_build/boutcore.pyx.in | 1 - tools/pylib/_boutcore_build/boutcpp.pxd.in | 1 - 2 files changed, 2 deletions(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 1f9c99770d..b7f6c782f9 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -712,7 +712,6 @@ cdef class Mesh: if self.cobj == NULL: raise MemoryError('Not enough memory, allocation failed.') self.cobj.load() - self.cobj.setParallelTransform() @classmethod def getGlobal(cls): diff --git a/tools/pylib/_boutcore_build/boutcpp.pxd.in b/tools/pylib/_boutcore_build/boutcpp.pxd.in index 18986ea16e..a06d4f321e 100755 --- a/tools/pylib/_boutcore_build/boutcpp.pxd.in +++ b/tools/pylib/_boutcore_build/boutcpp.pxd.in @@ -68,7 +68,6 @@ cdef extern from "bout/mesh.hxx": @staticmethod Mesh * create(Options * option) void load() - void setParallelTransform() void communicate(FieldGroup&) int getNXPE() int getNYPE() From da9771d17048b0bf6e8bb0891b1f73a9291ff30e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 8 Mar 2019 10:06:58 +0000 Subject: [PATCH 1003/1783] Make calls to toFieldAligned/fromFieldAligned through Coordinates Update uses of toFieldAligned and fromFieldAligned to reflect the change in ownership of ParallelTransform objects from Mesh to Coordinates. --- include/bout/fv_ops.hxx | 12 +++--- include/bout/index_derivs_interface.hxx | 24 ++++++------ include/interpolation.hxx | 5 +-- src/field/field_factory.cxx | 5 ++- src/fileio/datafile.cxx | 4 +- src/invert/parderiv/impls/cyclic/cyclic.cxx | 4 +- src/mesh/boundary_standard.cxx | 43 ++++++++++++--------- src/mesh/difops.cxx | 15 ++++--- src/mesh/fv_ops.cxx | 22 +++++------ src/mesh/mesh.cxx | 2 +- src/physics/smoothing.cxx | 6 ++- 11 files changed, 75 insertions(+), 67 deletions(-) diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index a5751ef98b..14cd7f2cf8 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -188,8 +188,8 @@ namespace FV { CellEdges cellboundary; - Field3D f = mesh->toFieldAligned(f_in, RGN_NOX); - Field3D v = mesh->toFieldAligned(v_in, RGN_NOX); + Field3D f = f_in.getCoordinates()->toFieldAligned(f_in, RGN_NOX); + Field3D v = v_in.getCoordinates()->toFieldAligned(v_in, RGN_NOX); Coordinates *coord = f_in.getCoordinates(); @@ -326,7 +326,7 @@ namespace FV { } } } - return mesh->fromFieldAligned(result, RGN_NOBNDRY); + return result.getCoordinates()->fromFieldAligned(result, RGN_NOBNDRY); } /*! @@ -470,8 +470,8 @@ namespace FV { // Currently just using simple centered differences // so no fluxes need to be exchanged - n = mesh->toFieldAligned(n_in, RGN_NOX); - Field3D vy = mesh->toFieldAligned(v.y, RGN_NOX); + n = n_in.getCoordinates()->toFieldAligned(n_in, RGN_NOX); + Field3D vy = v.y.getCoordinates()->toFieldAligned(v.y, RGN_NOX); Field3D yresult = 0.0; for(int i=mesh->xstart;i<=mesh->xend;i++) @@ -490,7 +490,7 @@ namespace FV { yresult(i,j,k) = (nU*vU - nD*vD) / (coord->J(i,j)*coord->dy(i,j)); } - return result + mesh->fromFieldAligned(yresult, RGN_NOBNDRY); + return result + yresult.getCoordinates()->fromFieldAligned(yresult, RGN_NOBNDRY); } } diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 1f32d9f0c8..0b54fba135 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -203,10 +203,10 @@ T DDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "D return standardDerivative(f, outloc, method, region); } else { - const T f_aligned = f.getMesh()->toFieldAligned(f, RGN_NOX); + const T f_aligned = f.getCoordinates()->toFieldAligned(f, RGN_NOX); T result = standardDerivative(f_aligned, outloc, method, region); - return f.getMesh()->fromFieldAligned(result, region); + return result.getCoordinates()->fromFieldAligned(result, region); } } @@ -218,10 +218,10 @@ T D2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = return standardDerivative( f, outloc, method, region); } else { - const T f_aligned = f.getMesh()->toFieldAligned(f, RGN_NOX); + const T f_aligned = f.getCoordinates()->toFieldAligned(f, RGN_NOX); T result = standardDerivative( f_aligned, outloc, method, region); - return f.getMesh()->fromFieldAligned(result, region); + return result.getCoordinates()->fromFieldAligned(result, region); } } @@ -233,10 +233,10 @@ T D4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = return standardDerivative( f, outloc, method, region); } else { - const T f_aligned = f.getMesh()->toFieldAligned(f, RGN_NOX); + const T f_aligned = f.getCoordinates()->toFieldAligned(f, RGN_NOX); T result = standardDerivative( f_aligned, outloc, method, region); - return f.getMesh()->fromFieldAligned(result, region); + return result.getCoordinates()->fromFieldAligned(result, region); } } @@ -307,11 +307,11 @@ T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, return flowDerivative(vel, f, outloc, method, region); } else { - const T f_aligned = f.getMesh()->toFieldAligned(f, RGN_NOX); - const T vel_aligned = vel.getMesh()->toFieldAligned(vel, RGN_NOX); + const T f_aligned = f.getCoordinates()->toFieldAligned(f, RGN_NOX); + const T vel_aligned = vel.getCoordinates()->toFieldAligned(vel, RGN_NOX); T result = flowDerivative(vel_aligned, f_aligned, outloc, method, region); - return f.getMesh()->fromFieldAligned(result, region); + return result.getCoordinates()->fromFieldAligned(result, region); } } @@ -325,11 +325,11 @@ T FDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, return flowDerivative(vel, f, outloc, method, region); } else { - const T f_aligned = f.getMesh()->toFieldAligned(f, RGN_NOX); - const T vel_aligned = vel.getMesh()->toFieldAligned(vel, RGN_NOX); + const T f_aligned = f.getCoordinates()->toFieldAligned(f, RGN_NOX); + const T vel_aligned = vel.getCoordinates()->toFieldAligned(vel, RGN_NOX); T result = flowDerivative(vel_aligned, f_aligned, outloc, method, region); - return f.getMesh()->fromFieldAligned(result, region); + return result.getCoordinates()->fromFieldAligned(result, region); } } diff --git a/include/interpolation.hxx b/include/interpolation.hxx index e35976d02f..3f91bdc366 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -75,7 +75,6 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { return var; } - // NOTE: invalidateGuards() is called in Field3D::alloctate() if the data // block is not already allocated, so will be called here if // region==RGN_NOBNDRY @@ -127,7 +126,7 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { // We can't interpolate in y unless we're field-aligned // FIXME: Add check once we label fields as orthogonal/aligned - const T var_fa = fieldmesh->toFieldAligned(var, RGN_NOX); + const T var_fa = var.getCoordinates()->toFieldAligned(var, RGN_NOX); if (region != RGN_NOBNDRY) { // repeat the hack above for boundary points // this avoids a duplicate toFieldAligned call if we had called @@ -154,7 +153,7 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { } } - result = fieldmesh->fromFieldAligned(result, RGN_NOBNDRY); + result = result.getCoordinates()->fromFieldAligned(result, RGN_NOBNDRY); break; } diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 807abcc77a..dc810779e2 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -215,10 +215,11 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC } }; - if (localmesh->canToFromFieldAligned()) { + Coordinates* coords = result.getCoordinates(); + if (coords->canToFromFieldAligned()) { // Transform from field aligned coordinates, to be compatible with // older BOUT++ inputs. This is not a particularly "nice" solution. - result = localmesh->fromFieldAligned(result, RGN_ALL); + result = coords->fromFieldAligned(result, RGN_ALL); } return result; diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 1a7a45529e..748ab0985a 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -1156,7 +1156,7 @@ bool Datafile::read_f3d(const std::string &name, Field3D *f, bool save_repeat) { if (shiftInput) { // Input file is in field-aligned coordinates e.g. BOUT++ 3.x restart file - *f = mesh->fromFieldAligned(*f, RGN_ALL); + *f = f->getCoordinates()->fromFieldAligned(*f, RGN_ALL); } return true; @@ -1202,7 +1202,7 @@ bool Datafile::write_f3d(const std::string &name, Field3D *f, bool save_repeat) //Deal with shifting the output Field3D f_out{emptyFrom(*f)}; if(shiftOutput) { - f_out = mesh->toFieldAligned(*f); + f_out = f->getCoordinates()->toFieldAligned(*f); }else { f_out = *f; } diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index 3f0d955618..644cdf4047 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -65,7 +65,7 @@ const Field3D InvertParCR::solve(const Field3D &f) { Coordinates *coord = f.getCoordinates(); - Field3D alignedField = localmesh->toFieldAligned(f, RGN_NOX); + Field3D alignedField = coord->toFieldAligned(f, RGN_NOX); // Create cyclic reduction object CyclicReduce *cr = @@ -214,6 +214,6 @@ const Field3D InvertParCR::solve(const Field3D &f) { // Delete cyclic reduction object delete cr; - return localmesh->fromFieldAligned(result, RGN_NOBNDRY); + return coord->fromFieldAligned(result, RGN_NOBNDRY); } diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 4e12c09ddd..fce769073f 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -3314,17 +3314,18 @@ void BoundaryToFieldAligned::apply(Field2D &f, BoutReal t) { } void BoundaryToFieldAligned::apply(Field3D &f, BoutReal t) { - Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(bndry->localmesh = f.getMesh()); + + auto coords = f.getCoordinates(); //NOTE: This is not very efficient... updating entire field - f = mesh->fromFieldAligned(f); + f = coords->fromFieldAligned(f); // Apply the boundary to shifted field op->apply(f, t); //Shift back - f = mesh->toFieldAligned(f); + f = coords->toFieldAligned(f); //This is inefficient -- could instead use the shiftZ just in the bndry //but this is not portable to other parallel transforms -- we could instead @@ -3336,12 +3337,14 @@ void BoundaryToFieldAligned::apply_ddt(Field2D &f) { } void BoundaryToFieldAligned::apply_ddt(Field3D &f) { - Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); - f = mesh->fromFieldAligned(f); - ddt(f) = mesh->fromFieldAligned(ddt(f)); + ASSERT1(bndry->localmesh = f.getMesh()); + + auto coords = f.getCoordinates(); + + f = coords->fromFieldAligned(f); + ddt(f) = coords->fromFieldAligned(ddt(f)); op->apply_ddt(f); - ddt(f) = mesh->toFieldAligned(ddt(f)); + ddt(f) = coords->toFieldAligned(ddt(f)); } @@ -3362,16 +3365,18 @@ void BoundaryFromFieldAligned::apply(Field2D &f, BoutReal t) { } void BoundaryFromFieldAligned::apply(Field3D &f, BoutReal t) { - Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(bndry->localmesh = f.getMesh()); + + auto coords = f.getCoordinates(); + //NOTE: This is not very efficient... shifting entire field - f = mesh->toFieldAligned(f); + f = coords->toFieldAligned(f); // Apply the boundary to shifted field op->apply(f, t); //Shift back - f = mesh->fromFieldAligned(f); + f = coords->fromFieldAligned(f); //This is inefficient -- could instead use the shiftZ just in the bndry //but this is not portable to other parallel transforms -- we could instead @@ -3383,10 +3388,12 @@ void BoundaryFromFieldAligned::apply_ddt(Field2D &f) { } void BoundaryFromFieldAligned::apply_ddt(Field3D &f) { - Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); - f = mesh->toFieldAligned(f); - ddt(f) = mesh->toFieldAligned(ddt(f)); + ASSERT1(bndry->localmesh = f.getMesh()); + + auto coords = f.getCoordinates(); + + f = coords->toFieldAligned(f); + ddt(f) = coords->toFieldAligned(ddt(f)); op->apply_ddt(f); - ddt(f) = mesh->fromFieldAligned(ddt(f)); + ddt(f) = coords->fromFieldAligned(ddt(f)); } diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index 018ff1ccb6..e5783bc245 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -288,7 +288,7 @@ const Field3D Grad_par_CtoL(const Field3D &var) { } } else { // No yup/ydown fields, so transform to cell centred - Field3D var_fa = mesh->toFieldAligned(var, RGN_NOX); + Field3D var_fa = var.getCoordinates()->toFieldAligned(var, RGN_NOX); for(int jx=0; jxLocalNx;jx++) { for(int jy=1;jyLocalNy;jy++) { @@ -298,7 +298,7 @@ const Field3D Grad_par_CtoL(const Field3D &var) { } } - result = mesh->fromFieldAligned(result, RGN_NOBNDRY); + result = metric->fromFieldAligned(result, RGN_NOBNDRY); } return result; @@ -322,7 +322,6 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg ASSERT1(v.getLocation() == CELL_YLOW); ASSERT1(f.getLocation() == CELL_CENTRE); - const auto vMesh = v.getMesh(); Field3D result{emptyFrom(f).setLocation(CELL_CENTRE)}; bool vUseUpDown = v.hasYupYdown(); @@ -353,8 +352,8 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg // (even if one of v and f has yup/ydown fields, it doesn't make sense to // multiply them with one in field-aligned and one in non-field-aligned // coordinates) - Field3D v_fa = vMesh->toFieldAligned(v, RGN_NOX); - Field3D f_fa = vMesh->toFieldAligned(f, RGN_NOX); + Field3D v_fa = v.getCoordinates()->toFieldAligned(v, RGN_NOX); + Field3D f_fa = f.getCoordinates()->toFieldAligned(f, RGN_NOX); BOUT_OMP(parallel) { stencil fval, vval; @@ -373,7 +372,7 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg result[i] -= (vval.p >= 0.0) ? vval.p * fval.c : vval.p * fval.p; } - result = vMesh->fromFieldAligned(result, region); + result = result.getCoordinates()->fromFieldAligned(result, region); } } @@ -398,12 +397,12 @@ const Field3D Grad_par_LtoC(const Field3D &var) { } else { // No yup/ydown field, so transform to field aligned - Field3D var_fa = varMesh->toFieldAligned(var, RGN_NOX); + Field3D var_fa = var.getCoordinates()->toFieldAligned(var, RGN_NOX); BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { result[i] = (var_fa[i.yp()] - var_fa[i]) / (metric->dy[i]*sqrt(metric->g_22[i])); } - result = varMesh->fromFieldAligned(result, RGN_NOBNDRY); + result = result.getCoordinates()->fromFieldAligned(result, RGN_NOBNDRY); } return result; diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index 3da9accce8..ff223beb03 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -73,8 +73,8 @@ namespace FV { // At least one input doesn't have yup/ydown fields. // Need to shift to/from field aligned coordinates - fup = fdown = fc = mesh->toFieldAligned(f); - aup = adown = ac = mesh->toFieldAligned(a); + fup = fdown = fc = f.getCoordinates()->toFieldAligned(f); + aup = adown = ac = a.getCoordinates()->toFieldAligned(a); } // Y flux @@ -157,7 +157,7 @@ namespace FV { if (f.hasYupYdown() && a.hasYupYdown()) { result += yzresult; } else { - result += mesh->fromFieldAligned(yzresult); + result += yzresult.getCoordinates()->fromFieldAligned(yzresult); } return result; @@ -173,8 +173,8 @@ namespace FV { bool use_yup_ydown = (Kin.hasYupYdown() && fin.hasYupYdown()); - const auto& K = use_yup_ydown ? Kin : mesh->toFieldAligned(Kin, RGN_NOX); - const auto& f = use_yup_ydown ? fin : mesh->toFieldAligned(fin, RGN_NOX); + const auto& K = use_yup_ydown ? Kin : Kin.getCoordinates()->toFieldAligned(Kin, RGN_NOX); + const auto& f = use_yup_ydown ? fin : fin.getCoordinates()->toFieldAligned(fin, RGN_NOX); // K and f fields in yup and ydown directions const auto& Kup = use_yup_ydown ? Kin.yup() : K; @@ -220,7 +220,7 @@ namespace FV { if (!use_yup_ydown) { // Shifted to field aligned coordinates, so need to shift back - result = mesh->fromFieldAligned(result, RGN_NOBNDRY); + result = result.getCoordinates()->fromFieldAligned(result, RGN_NOBNDRY); } return result; @@ -236,8 +236,8 @@ namespace FV { Coordinates *coord = f_in.getCoordinates(); // Convert to field aligned coordinates - Field3D d = mesh->toFieldAligned(d_in, RGN_NOX); - Field3D f = mesh->toFieldAligned(f_in, RGN_NOX); + Field3D d = d_in.getCoordinates()->toFieldAligned(d_in, RGN_NOX); + Field3D f = f_in.getCoordinates()->toFieldAligned(f_in, RGN_NOX); for(int i=mesh->xstart;i<=mesh->xend;i++) for(int j=mesh->ystart;j<=mesh->yend;j++) { @@ -276,7 +276,7 @@ namespace FV { } // Convert result back to non-aligned coordinates - return mesh->fromFieldAligned(result, RGN_NOBNDRY); + return result.getCoordinates()->fromFieldAligned(result, RGN_NOBNDRY); } const Field3D D4DY4_Index(const Field3D &f_in, bool bndry_flux) { @@ -285,7 +285,7 @@ namespace FV { Mesh* mesh = f_in.getMesh(); // Convert to field aligned coordinates - Field3D f = mesh->toFieldAligned(f_in, RGN_NOX); + Field3D f = f_in.getCoordinates()->toFieldAligned(f_in, RGN_NOX); Coordinates *coord = f_in.getCoordinates(); @@ -386,7 +386,7 @@ namespace FV { } // Convert result back to non-aligned coordinates - return mesh->fromFieldAligned(result, RGN_NOBNDRY); + return result.getCoordinates()->fromFieldAligned(result, RGN_NOBNDRY); } void communicateFluxes(Field3D &f) { diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index bf884e6eaf..0f3e02552e 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -194,7 +194,7 @@ void Mesh::communicate(FieldGroup &g) { // Calculate yup and ydown fields for 3D fields if (calcYUpDown_on_communicate) { for(const auto& fptr : g.field3d()) { - getParallelTransform().calcYUpDown(*fptr); + fptr->getCoordinates()->getParallelTransform().calcYUpDown(*fptr); } } } diff --git a/src/physics/smoothing.cxx b/src/physics/smoothing.cxx index abe7423842..dba2e001cd 100644 --- a/src/physics/smoothing.cxx +++ b/src/physics/smoothing.cxx @@ -404,12 +404,14 @@ const Field3D nl_filter_y(const Field3D &f, BoutReal w) { TRACE("nl_filter_x( Field3D )"); Mesh *mesh = f.getMesh(); + auto coords = f.getCoordinates(); + Field3D result{emptyFrom(f)}; rvec v(mesh->LocalNy); // Temporary array // Transform into field-aligned coordinates - Field3D fs = mesh->toFieldAligned(f); + Field3D fs = coords->toFieldAligned(f); for (int jx=0;jxLocalNx;jx++) { for (int jz=0;jzLocalNz;jz++) { @@ -424,7 +426,7 @@ const Field3D nl_filter_y(const Field3D &f, BoutReal w) { } // Tranform the field back from field aligned coordinates - return mesh->fromFieldAligned(result); + return coords->fromFieldAligned(result); } const Field3D nl_filter_z(const Field3D &fs, BoutReal w) { From 87db30f8542f6fbfb2b4270d54ebcfa2595e85a8 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 8 Mar 2019 10:08:24 +0000 Subject: [PATCH 1004/1783] Update tests for ParallelTransforms belonging to Coordinates Now need to create full Coordinates objects in several places in the unit tests, instead of just having a nullptr in coords_map, because the ParallelTransform needs to be accessed through a Coordinates object. --- tests/integrated/test-smooth/test_smooth.cxx | 2 +- .../integrated/test-yupdown/test_yupdown.cxx | 9 +++-- tests/unit/field/test_field_factory.cxx | 34 +++++++++++++++---- tests/unit/field/test_initialprofiles.cxx | 12 +++++-- tests/unit/mesh/data/test_gridfromoptions.cxx | 12 +++++-- .../unit/mesh/parallel/test_shiftedmetric.cxx | 26 +++++++++----- tests/unit/mesh/test_interpolation.cxx | 22 +++++++++--- tests/unit/test_extras.hxx | 4 --- 8 files changed, 89 insertions(+), 32 deletions(-) diff --git a/tests/integrated/test-smooth/test_smooth.cxx b/tests/integrated/test-smooth/test_smooth.cxx index c4670656c1..d837f89a3a 100644 --- a/tests/integrated/test-smooth/test_smooth.cxx +++ b/tests/integrated/test-smooth/test_smooth.cxx @@ -17,7 +17,7 @@ int main(int argc, char **argv) { Field2D input2d = f.create2D("1 + sin(2*y)"); Field3D input3d = f.create3D("gauss(x-0.5,0.2)*gauss(y-pi)*sin(3*y - z)"); - mesh->getParallelTransform().calcYUpDown(input3d); + input3d.getCoordinates()->getParallelTransform().calcYUpDown(input3d); SAVE_ONCE2(input2d, input3d); diff --git a/tests/integrated/test-yupdown/test_yupdown.cxx b/tests/integrated/test-yupdown/test_yupdown.cxx index a3642caa03..6163353aae 100644 --- a/tests/integrated/test-yupdown/test_yupdown.cxx +++ b/tests/integrated/test-yupdown/test_yupdown.cxx @@ -37,7 +37,10 @@ int main(int argc, char** argv) { BoutInitialise(argc, argv); - ShiftedMetric s(*mesh); + Field2D zShift; + mesh->get(zShift, "zShift"); + + ShiftedMetric s(*mesh, CELL_CENTRE, zShift, mesh->getCoordinates()->zlength()); // Read variable from mesh Field3D var; @@ -58,13 +61,13 @@ int main(int argc, char** argv) { Field3D ddy2 = DDY(var2); // Change into field-aligned coordinates - Field3D var_aligned = mesh->toFieldAligned(var); + Field3D var_aligned = var.getCoordinates()->toFieldAligned(var); // var now field aligned Field3D ddy_check = DDY_aligned(var_aligned); // Shift back to orthogonal X-Z coordinates - ddy_check = mesh->fromFieldAligned(ddy_check); + ddy_check = var.getCoordinates()->fromFieldAligned(ddy_check); SAVE_ONCE3(ddy, ddy2, ddy_check); dump.write(); diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index 86842e40c6..b4521a7e99 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -24,12 +24,28 @@ template class FieldFactoryCreationTest : public FakeMeshFixture { public: FieldFactoryCreationTest() : FakeMeshFixture{}, factory{mesh} { - // We need a parallel transform as FieldFactory::create3D wants to - // un-field-align the result - mesh->setParallelTransform( + // We need Coordinates so a parallel transform is available as + // FieldFactory::create3D wants to un-field-align the result + static_cast(mesh)->setCoordinates(std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false)); + + mesh->getCoordinates()->setParallelTransform( bout::utils::make_unique(*mesh)); - mesh_staggered->setParallelTransform( - bout::utils::make_unique(*mesh_staggered)); + + for (const auto& location : std::list{CELL_CENTRE, CELL_XLOW, CELL_YLOW, CELL_ZLOW}) { + static_cast(mesh_staggered)->setCoordinates(std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false), + location); + + mesh_staggered->getCoordinates(location)->setParallelTransform( + bout::utils::make_unique(*mesh_staggered)); + } } FieldFactory factory; @@ -557,7 +573,13 @@ TYPED_TEST(FieldFactoryCreationTest, CreateOnMesh) { FakeMesh localmesh{nx, ny, nz}; localmesh.createDefaultRegions(); - localmesh.setParallelTransform( + localmesh.setCoordinates(std::make_shared( + &localmesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false)); + + localmesh.getCoordinates()->setParallelTransform( bout::utils::make_unique(localmesh)); auto output = this->create("x", nullptr, &localmesh); diff --git a/tests/unit/field/test_initialprofiles.cxx b/tests/unit/field/test_initialprofiles.cxx index e2ae609c5d..b383c8aeb8 100644 --- a/tests/unit/field/test_initialprofiles.cxx +++ b/tests/unit/field/test_initialprofiles.cxx @@ -21,9 +21,15 @@ using namespace bout::globals; class InitialProfileTest : public FakeMeshFixture { public: InitialProfileTest() : FakeMeshFixture() { - // We need a parallel transform as FieldFactory::create3D wants to - // un-field-align the result - mesh->setParallelTransform( + // We need Coordinates so a parallel transform is available as + // FieldFactory::create3D wants to un-field-align the result + static_cast(mesh)->setCoordinates(std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false)); + + mesh->getCoordinates()->setParallelTransform( bout::utils::make_unique(*mesh)); output_info.disable(); diff --git a/tests/unit/mesh/data/test_gridfromoptions.cxx b/tests/unit/mesh/data/test_gridfromoptions.cxx index ed3fe5ca32..467bda5100 100644 --- a/tests/unit/mesh/data/test_gridfromoptions.cxx +++ b/tests/unit/mesh/data/test_gridfromoptions.cxx @@ -24,9 +24,15 @@ using namespace bout::globals; class GridFromOptionsTest : public FakeMeshFixture { public: GridFromOptionsTest() : FakeMeshFixture(), options(), griddata(&options) { - // We need a parallel transform as FieldFactory::create3D wants to - // un-field-align the result - mesh->setParallelTransform( + // We need Coordinates so a parallel transform is available as + // FieldFactory::create3D wants to un-field-align the result + static_cast(mesh)->setCoordinates(std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false)); + + mesh->getCoordinates()->setParallelTransform( bout::utils::make_unique(*mesh)); output_info.disable(); diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 0e3d192f7e..036c315607 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -16,6 +16,7 @@ extern Mesh* mesh; class ShiftedMetricTest : public ::testing::Test { public: ShiftedMetricTest() { + Options::root()["TwistShift"] = true; // Delete any existing mesh if (mesh != nullptr) { delete mesh; @@ -43,7 +44,10 @@ class ShiftedMetricTest : public ::testing::Test { Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false)); - mesh->setParallelTransform(bout::utils::make_unique(*mesh, zShift)); + auto coords = mesh->getCoordinates(); + coords->setParallelTransform( + bout::utils::make_unique(*mesh, CELL_CENTRE, zShift, + coords->zlength())); Field3D input_temp{mesh}; @@ -119,11 +123,13 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { {4., 5., 1., 3., 2.}, {2., 4., 3., 5., 1.}}}); - Field3D result = mesh->toFieldAligned(input); + auto coords = expected.getCoordinates(); + + Field3D result = coords->toFieldAligned(input); EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_ALL", FFTTolerance)); - EXPECT_TRUE(IsFieldEqual(mesh->fromFieldAligned(input), input)); + EXPECT_TRUE(IsFieldEqual(coords->fromFieldAligned(input), input)); EXPECT_TRUE(areFieldsCompatible(result, expected)); EXPECT_FALSE(areFieldsCompatible(result, input)); } @@ -160,25 +166,29 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { {2., 4., 5., 1., 3.}, {5., 1., 2., 4., 3.}}}); - Field3D result = mesh->fromFieldAligned(input); + auto coords = input.getCoordinates(); + + Field3D result = coords->fromFieldAligned(input); // Loosen tolerance a bit due to FFTs EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_ALL", FFTTolerance)); - EXPECT_TRUE(IsFieldEqual(mesh->toFieldAligned(input), input)); + EXPECT_TRUE(IsFieldEqual(coords->toFieldAligned(input), input)); EXPECT_TRUE(areFieldsCompatible(result, expected)); EXPECT_FALSE(areFieldsCompatible(result, input)); } TEST_F(ShiftedMetricTest, FromToFieldAligned) { - EXPECT_TRUE(IsFieldEqual(mesh->fromFieldAligned(mesh->toFieldAligned(input)), input, "RGN_ALL", + auto coords = input.getCoordinates(); + EXPECT_TRUE(IsFieldEqual(coords->fromFieldAligned(coords->toFieldAligned(input)), input, "RGN_ALL", FFTTolerance)); } TEST_F(ShiftedMetricTest, ToFromFieldAligned) { + auto coords = input.getCoordinates(); input.setDirectionY(YDirectionType::Aligned); - EXPECT_TRUE(IsFieldEqual(mesh->toFieldAligned(mesh->fromFieldAligned(input)), input, "RGN_ALL", + EXPECT_TRUE(IsFieldEqual(coords->toFieldAligned(coords->fromFieldAligned(input)), input, "RGN_ALL", FFTTolerance)); } @@ -203,7 +213,7 @@ TEST_F(ShiftedMetricTest, CalcYUpDown) { output_info.enable(); // Actual interesting bit here! - mesh->getParallelTransform().calcYUpDown(input); + input.getCoordinates()->getParallelTransform().calcYUpDown(input); // Expected output values Field3D expected_up_1{mesh}; diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index 56d6286fec..3d2a887f6e 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -61,13 +61,27 @@ class Field3DInterpToTest : public ::testing::Test { mesh->ystart = 2; mesh->xend = nx - 3; mesh->yend = ny - 3; - static_cast(mesh)->setCoordinates(nullptr, CELL_XLOW); - static_cast(mesh)->setCoordinates(nullptr, CELL_YLOW); - static_cast(mesh)->setCoordinates(nullptr, CELL_ZLOW); - mesh->setParallelTransform(bout::utils::make_unique(*mesh)); + output_info.disable(); mesh->createDefaultRegions(); output_info.enable(); + + static_cast(mesh)->setCoordinates(nullptr, CELL_XLOW); + static_cast(mesh)->setCoordinates(nullptr, CELL_YLOW); + static_cast(mesh)->setCoordinates(nullptr, CELL_ZLOW); + + // We need Coordinates so a parallel transform is available as + // FieldFactory::create3D wants to un-field-align the result + for (const auto& location : std::list{CELL_CENTRE, CELL_XLOW, CELL_YLOW, CELL_ZLOW}) { + static_cast(mesh)->setCoordinates(std::make_shared( + mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false), + location); + mesh->getCoordinates(location)->setParallelTransform( + bout::utils::make_unique(*mesh)); + } } static void TearDownTestCase() { diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index cbe136bd7f..8b65ebd1a4 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -262,8 +262,6 @@ public: bout::globals::mesh = nullptr; } bout::globals::mesh = new FakeMesh(nx, ny, nz); - bout::globals::mesh->setParallelTransform( - bout::utils::make_unique(*bout::globals::mesh)); output_info.disable(); bout::globals::mesh->createDefaultRegions(); output_info.enable(); @@ -275,8 +273,6 @@ public: } mesh_staggered = new FakeMesh(nx, ny, nz); mesh_staggered->StaggerGrids = true; - mesh_staggered->setParallelTransform( - bout::utils::make_unique(*mesh_staggered)); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_YLOW); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_ZLOW); From a4d3039c5ec4b8b8c88539a7a54e4e0506d7ee42 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 8 Mar 2019 13:14:10 +0000 Subject: [PATCH 1005/1783] Fix location checks in ShiftedMetric ShiftedMetric now handles non-CELL_CENTRE locations; update the location checking to reflect this. --- src/mesh/parallel/shiftedmetric.cxx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 61b993b2ab..a27df7118e 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -20,6 +20,7 @@ ShiftedMetric::ShiftedMetric(Mesh& m, CELL_LOC location_in, Field2D zShift_, BoutReal zlength_in) : ParallelTransform(m), location(location_in), zShift(std::move(zShift_)), zlength(zlength_in) { + ASSERT1(zShift.getLocation() == location); // check the coordinate system used for the grid data source checkInputGrid(); @@ -161,9 +162,8 @@ const Field3D ShiftedMetric::fromFieldAligned(const Field3D& f, const REGION reg const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Tensor& phs, const YDirectionType y_direction_out, const REGION region) const { - ASSERT1(&mesh == f.getMesh()); - // only have zShift for CELL_CENTRE, so can only deal with CELL_CENTRE inputs - ASSERT1(f.getLocation() == CELL_CENTRE); + ASSERT1(f.getMesh() == &mesh); + ASSERT1(f.getLocation() == location); if (mesh.LocalNz == 1) return f; // Shifting makes no difference @@ -197,11 +197,6 @@ void ShiftedMetric::shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* ou void ShiftedMetric::calcYUpDown(Field3D& f) { - ASSERT1(f.getDirectionY() == YDirectionType::Standard); - ASSERT1(&mesh == f.getMesh()); - // only have zShift for CELL_CENTRE, so can only deal with CELL_CENTRE inputs - ASSERT1(f.getLocation() == CELL_CENTRE); - auto results = shiftZ(f, parallel_slice_phases); ASSERT3(results.size() == parallel_slice_phases.size()); @@ -216,6 +211,9 @@ void ShiftedMetric::calcYUpDown(Field3D& f) { std::vector ShiftedMetric::shiftZ(const Field3D& f, const std::vector& phases) const { + ASSERT1(f.getMesh() == &mesh); + ASSERT1(f.getLocation() == location); + ASSERT1(f.getDirectionY() == YDirectionType::Standard); const int nmodes = mesh.LocalNz / 2 + 1; From c67ecb6c2d0c1bb0a47c72b9ce7a962fa130e2d7 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 8 Mar 2019 13:37:11 +0000 Subject: [PATCH 1006/1783] Rename *YUpDown to *ParallelSlices ParallelSlices is a clearer naming convention since yup and ydown were generalized to allow multiple slices in each direction. --- include/bout/index_derivs_interface.hxx | 14 +++---- include/bout/mesh.hxx | 4 +- include/bout/paralleltransform.hxx | 6 +-- include/field2d.hxx | 2 +- include/field3d.hxx | 14 +++---- src/field/field3d.cxx | 10 ++--- src/mesh/coordinates.cxx | 14 ++----- src/mesh/difops.cxx | 28 ++++++------- src/mesh/fv_ops.cxx | 20 ++++----- src/mesh/mesh.cxx | 6 +-- src/mesh/parallel/fci.cxx | 12 +++--- src/mesh/parallel/fci.hxx | 4 +- src/mesh/parallel/identity.cxx | 4 +- src/mesh/parallel/identity.hxx | 2 +- src/mesh/parallel/shiftedmetric.cxx | 4 +- src/mesh/parallel/shiftedmetric.hxx | 2 +- tests/integrated/test-smooth/test_smooth.cxx | 2 +- .../integrated/test-yupdown/test_yupdown.cxx | 2 +- tests/unit/field/test_field3d.cxx | 42 +++++++++---------- tests/unit/include/test_derivs.cxx | 4 +- .../unit/mesh/parallel/test_shiftedmetric.cxx | 4 +- tests/unit/mesh/test_paralleltransform.cxx | 8 ++-- 22 files changed, 100 insertions(+), 108 deletions(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 0b54fba135..9b856d5167 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -199,7 +199,7 @@ template T DDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - if (std::is_base_of::value && f.hasYupYdown()) { + if (std::is_base_of::value && f.hasParallelSlices()) { return standardDerivative(f, outloc, method, region); } else { @@ -214,7 +214,7 @@ template T D2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - if (std::is_base_of::value && f.hasYupYdown()) { + if (std::is_base_of::value && f.hasParallelSlices()) { return standardDerivative( f, outloc, method, region); } else { @@ -229,7 +229,7 @@ template T D4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - if (std::is_base_of::value && f.hasYupYdown()) { + if (std::is_base_of::value && f.hasParallelSlices()) { return standardDerivative( f, outloc, method, region); } else { @@ -301,8 +301,8 @@ template T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown()); - bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown()); + bool fHasParallelSlices = (std::is_base_of::value && f.hasParallelSlices()); + bool velHasParallelSlices = (std::is_base_of::value && vel.hasParallelSlices()); if (fHasParallelSlices && velHasParallelSlices) { return flowDerivative(vel, f, outloc, method, region); @@ -319,8 +319,8 @@ template T FDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - bool fHasParallelSlices = (std::is_base_of::value && f.hasYupYdown()); - bool velHasParallelSlices = (std::is_base_of::value && vel.hasYupYdown()); + bool fHasParallelSlices = (std::is_base_of::value && f.hasParallelSlices()); + bool velHasParallelSlices = (std::is_base_of::value && vel.hasParallelSlices()); if (fHasParallelSlices && velHasParallelSlices) { return flowDerivative(vel, f, outloc, method, region); diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 0743b9dfd1..3a892c8afa 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -775,8 +775,8 @@ protected: /// Mesh options section Options *options{nullptr}; - /// Set whether to call calcYUpDown on all communicated fields (true) or not (false) - bool calcYUpDown_on_communicate{true}; + /// Set whether to call calcParallelSlices on all communicated fields (true) or not (false) + bool calcParallelSlices_on_communicate{true}; /// Read a 1D array of integers const std::vector readInts(const std::string &name, int n); diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index c2ecea12f7..e4a7f280b0 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -25,12 +25,12 @@ public: virtual ~ParallelTransform() {} /// Given a 3D field, calculate and set the Y up down fields - virtual void calcYUpDown(Field3D &f) = 0; + virtual void calcParallelSlices(Field3D &f) = 0; /// Calculate Yup and Ydown fields by integrating over mapped points /// This should be used for parallel divergence operators - virtual void integrateYUpDown(Field3D &f) { - return calcYUpDown(f); + virtual void integrateParallelSlices(Field3D &f) { + return calcParallelSlices(f); } /// Convert a 3D field into field-aligned coordinates diff --git a/include/field2d.hxx b/include/field2d.hxx index 8cab6ff4ba..dbd7b5ae04 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -120,7 +120,7 @@ class Field2D : public Field, public FieldData { } /// Check if this field has yup and ydown fields - bool hasYupYdown() const { + bool hasParallelSlices() const { return true; } diff --git a/include/field3d.hxx b/include/field3d.hxx index a4f5fcb582..ce1ee1cc51 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -142,12 +142,12 @@ class Mesh; // #include "bout/mesh.hxx" f.yup() // error; f.yup not allocated - f.mergeYupYdown(); // f.yup() and f.ydown() now point to f - f.yup()(0,1,0) // ok, gives value of f at (0,1,0) + f.clearParallelSlices(); // f.yup_fields and f.ydown_fields are now empty + f.yup() // error; f.yup not allocated To have separate fields for yup and ydown, first call - f.splitYupYdown(); // f.yup() and f.ydown() separate + f.splitParallelSlices(); // f.yup() and f.ydown() separate f.yup(); // ok f.yup()(0,1,0) // error; f.yup not allocated @@ -233,15 +233,15 @@ class Field3D : public Field, public FieldData { * Ensure that this field has separate fields * for yup and ydown. */ - void splitYupYdown(); + void splitParallelSlices(); /*! - * Ensure that yup and ydown refer to this field + * Clear the parallel slices, yup and ydown */ - void mergeYupYdown(); + void clearParallelSlices(); /// Check if this field has yup and ydown fields - bool hasYupYdown() const { + bool hasParallelSlices() const { return !yup_fields.empty() and !ydown_fields.empty(); } diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 11f1ca995d..aedcfd32d4 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -126,12 +126,12 @@ Field3D* Field3D::timeDeriv() { return deriv; } -void Field3D::splitYupYdown() { - TRACE("Field3D::splitYupYdown"); +void Field3D::splitParallelSlices() { + TRACE("Field3D::splitParallelSlices"); #if CHECK > 2 if (yup_fields.size() != ydown_fields.size()) { - throw BoutException("Field3D::splitYupYdown: forward/backward parallel slices not in sync.\n" + throw BoutException("Field3D::splitParallelSlices: forward/backward parallel slices not in sync.\n" " This is an internal library error"); } #endif @@ -148,8 +148,8 @@ void Field3D::splitYupYdown() { } } -void Field3D::mergeYupYdown() { - TRACE("Field3D::mergeYupYdown"); +void Field3D::clearParallelSlices() { + TRACE("Field3D::clearParallelSlices"); #if CHECK > 2 if (yup_fields.size() != ydown_fields.size()) { diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 663d2e1965..a703e5f9cd 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -822,7 +822,7 @@ const Field3D Coordinates::Div_par(const Field3D &f, CELL_LOC outloc, // Coordinates object Field2D Bxy_floc = f.getCoordinates()->Bxy; - if (!f.hasYupYdown()) { + if (!f.hasParallelSlices()) { // No yup/ydown fields. The Grad_par operator will // shift to field aligned coordinates return Bxy * Grad_par(f / Bxy_floc, outloc, method); @@ -830,15 +830,9 @@ const Field3D Coordinates::Div_par(const Field3D &f, CELL_LOC outloc, // Need to modify yup and ydown fields Field3D f_B = f / Bxy_floc; - if (&f.yup() == &f) { - // Identity, yup and ydown point to same field - f_B.mergeYupYdown(); - } else { - // Distinct fields - f_B.splitYupYdown(); - f_B.yup() = f.yup() / Bxy_floc; - f_B.ydown() = f.ydown() / Bxy_floc; - } + f_B.splitParallelSlices(); + f_B.yup() = f.yup() / Bxy_floc; + f_B.ydown() = f.ydown() / Bxy_floc; return Bxy * Grad_par(f_B, outloc, method); } diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index e5783bc245..dc49d03e8d 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -74,6 +74,7 @@ const Field3D Grad_par(const Field3D &var, const std::string &method, CELL_LOC o const Field3D Grad_parP(const Field3D &apar, const Field3D &f) { ASSERT1(areFieldsCompatible(apar, f)); + ASSERT1(f.hasParallelSlices()); Mesh *mesh = apar.getMesh(); @@ -201,6 +202,8 @@ const Field3D Div_par(const Field3D &f, const std::string &method, CELL_LOC outl const Field3D Div_par(const Field3D &f, const Field3D &v) { ASSERT1(areFieldsCompatible(f, v)); + ASSERT1(f.hasParallelSlices()); + ASSERT1(v.hasParallelSlices()); // Parallel divergence, using velocities at cell boundaries // Note: Not guaranteed to be flux conservative @@ -241,21 +244,16 @@ const Field3D Div_par_flux(const Field3D &v, const Field3D &f, CELL_LOC outloc, Field2D Bxy_floc = f.getCoordinates()->Bxy; - if (!f.hasYupYdown()) { + if (!f.hasParallelSlices()) { return metric->Bxy*FDDY(v, f/Bxy_floc, outloc, method)/sqrt(metric->g_22); } // Need to modify yup and ydown fields Field3D f_B = f / Bxy_floc; - if (&f.yup() == &f) { - // Identity, yup and ydown point to same field - f_B.mergeYupYdown(); - } else { - // Distinct fields - f_B.splitYupYdown(); - f_B.yup() = f.yup() / Bxy_floc; - f_B.ydown() = f.ydown() / Bxy_floc; - } + // Distinct fields + f_B.splitParallelSlices(); + f_B.yup() = f.yup() / Bxy_floc; + f_B.ydown() = f.ydown() / Bxy_floc; return metric->Bxy*FDDY(v, f_B, outloc, method)/sqrt(metric->g_22); } @@ -277,7 +275,7 @@ const Field3D Grad_par_CtoL(const Field3D &var) { Coordinates *metric = var.getCoordinates(CELL_YLOW); - if (var.hasYupYdown()) { + if (var.hasParallelSlices()) { // NOTE: Need to calculate one more point than centred vars for(int jx=0; jxLocalNx;jx++) { for(int jy=1;jyLocalNy;jy++) { @@ -324,10 +322,10 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg Field3D result{emptyFrom(f).setLocation(CELL_CENTRE)}; - bool vUseUpDown = v.hasYupYdown(); - bool fUseUpDown = f.hasYupYdown(); + bool vUseParallelSlices = v.hasParallelSlices(); + bool fUseParallelSlices = f.hasParallelSlices(); - if (vUseUpDown && fUseUpDown) { + if (vUseParallelSlices && fUseParallelSlices) { // Both v and f have up/down fields BOUT_OMP(parallel) { stencil fval, vval; @@ -390,7 +388,7 @@ const Field3D Grad_par_LtoC(const Field3D &var) { Coordinates *metric = var.getCoordinates(CELL_CENTRE); - if (var.hasYupYdown()) { + if (var.hasParallelSlices()) { BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { result[i] = (var.yup()[i.yp()] - var[i]) / (metric->dy[i]*sqrt(metric->g_22[i])); } diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index ff223beb03..03b62f7384 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -61,7 +61,7 @@ namespace FV { Field3D yzresult(mesh); yzresult.allocate(); - if (f.hasYupYdown() && a.hasYupYdown()) { + if (f.hasParallelSlices() && a.hasParallelSlices()) { // Both inputs have yup and ydown fup = f.yup(); @@ -154,7 +154,7 @@ namespace FV { } } // Check if we need to transform back - if (f.hasYupYdown() && a.hasYupYdown()) { + if (f.hasParallelSlices() && a.hasParallelSlices()) { result += yzresult; } else { result += yzresult.getCoordinates()->fromFieldAligned(yzresult); @@ -171,16 +171,16 @@ namespace FV { Mesh *mesh = Kin.getMesh(); Field3D result{zeroFrom(fin)}; - bool use_yup_ydown = (Kin.hasYupYdown() && fin.hasYupYdown()); + bool use_parallel_slices = (Kin.hasParallelSlices() && fin.hasParallelSlices()); - const auto& K = use_yup_ydown ? Kin : Kin.getCoordinates()->toFieldAligned(Kin, RGN_NOX); - const auto& f = use_yup_ydown ? fin : fin.getCoordinates()->toFieldAligned(fin, RGN_NOX); + const auto& K = use_parallel_slices ? Kin : Kin.getCoordinates()->toFieldAligned(Kin, RGN_NOX); + const auto& f = use_parallel_slices ? fin : fin.getCoordinates()->toFieldAligned(fin, RGN_NOX); // K and f fields in yup and ydown directions - const auto& Kup = use_yup_ydown ? Kin.yup() : K; - const auto& Kdown = use_yup_ydown ? Kin.ydown() : K; - const auto& fup = use_yup_ydown ? fin.yup() : f; - const auto& fdown = use_yup_ydown ? fin.ydown() : f; + const auto& Kup = use_parallel_slices ? Kin.yup() : K; + const auto& Kdown = use_parallel_slices ? Kin.ydown() : K; + const auto& fup = use_parallel_slices ? fin.yup() : f; + const auto& fdown = use_parallel_slices ? fin.ydown() : f; Coordinates *coord = fin.getCoordinates(); @@ -218,7 +218,7 @@ namespace FV { } } - if (!use_yup_ydown) { + if (!use_parallel_slices) { // Shifted to field aligned coordinates, so need to shift back result = result.getCoordinates()->fromFieldAligned(result, RGN_NOBNDRY); } diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 0f3e02552e..7ac78706af 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -29,7 +29,7 @@ Mesh::Mesh(GridDataSource *s, Options* opt) : source(s), options(opt) { /// Get mesh options OPTION(options, StaggerGrids, false); // Stagger grids OPTION(options, maxregionblocksize, MAXREGIONBLOCKSIZE); - OPTION(options, calcYUpDown_on_communicate, true); + OPTION(options, calcParallelSlices_on_communicate, true); // Initialise derivatives derivs_init(options); // in index_derivs.cxx for now } @@ -192,9 +192,9 @@ void Mesh::communicate(FieldGroup &g) { wait(h); // Calculate yup and ydown fields for 3D fields - if (calcYUpDown_on_communicate) { + if (calcParallelSlices_on_communicate) { for(const auto& fptr : g.field3d()) { - fptr->getCoordinates()->getParallelTransform().calcYUpDown(*fptr); + fptr->getCoordinates()->getParallelTransform().calcParallelSlices(*fptr); } } } diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 272947950a..add19f64cd 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -335,8 +335,8 @@ void FCITransform::checkInputGrid() { // file so must rely on the user having ensured the type is correct } -void FCITransform::calcYUpDown(Field3D& f) { - TRACE("FCITransform::calcYUpDown"); +void FCITransform::calcParallelSlices(Field3D& f) { + TRACE("FCITransform::calcParallelSlices"); ASSERT1(f.getDirectionY() == YDirectionType::Standard); // Only have forward_map/backward_map for CELL_CENTRE, so can only deal with @@ -344,7 +344,7 @@ void FCITransform::calcYUpDown(Field3D& f) { ASSERT1(f.getLocation() == CELL_CENTRE); // Ensure that yup and ydown are different fields - f.splitYupYdown(); + f.splitParallelSlices(); // Interpolate f onto yup and ydown fields for (const auto& map : field_line_maps) { @@ -352,8 +352,8 @@ void FCITransform::calcYUpDown(Field3D& f) { } } -void FCITransform::integrateYUpDown(Field3D& f) { - TRACE("FCITransform::integrateYUpDown"); +void FCITransform::integrateParallelSlices(Field3D& f) { + TRACE("FCITransform::integrateParallelSlices"); ASSERT1(f.getDirectionY() == YDirectionType::Standard); // Only have forward_map/backward_map for CELL_CENTRE, so can only deal with @@ -361,7 +361,7 @@ void FCITransform::integrateYUpDown(Field3D& f) { ASSERT1(f.getLocation() == CELL_CENTRE); // Ensure that yup and ydown are different fields - f.splitYupYdown(); + f.splitParallelSlices(); // Integrate f onto yup and ydown fields for (const auto& map : field_line_maps) { diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index a4bd0aa2f5..f50b4b130a 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -89,9 +89,9 @@ public: } } - void calcYUpDown(Field3D &f) override; + void calcParallelSlices(Field3D &f) override; - void integrateYUpDown(Field3D &f) override; + void integrateParallelSlices(Field3D &f) override; const Field3D toFieldAligned(const Field3D &UNUSED(f), const REGION UNUSED(region)) override { throw BoutException("FCI method cannot transform into field aligned grid"); diff --git a/src/mesh/parallel/identity.cxx b/src/mesh/parallel/identity.cxx index 1f725837ea..df70edbec1 100644 --- a/src/mesh/parallel/identity.cxx +++ b/src/mesh/parallel/identity.cxx @@ -10,8 +10,8 @@ #include "bout/mesh.hxx" -void ParallelTransformIdentity::calcYUpDown(Field3D& f) { - f.splitYupYdown(); +void ParallelTransformIdentity::calcParallelSlices(Field3D& f) { + f.splitParallelSlices(); for (int i = 0; i < f.getMesh()->ystart; ++i) { f.yup(i) = f; diff --git a/src/mesh/parallel/identity.hxx b/src/mesh/parallel/identity.hxx index b71ee82a36..5d8dd5cfae 100644 --- a/src/mesh/parallel/identity.hxx +++ b/src/mesh/parallel/identity.hxx @@ -46,7 +46,7 @@ public: * Merges the yup and ydown() fields of f, so that * f.yup() = f.ydown() = f */ - void calcYUpDown(Field3D& f) override; + void calcParallelSlices(Field3D& f) override; /*! * The field is already aligned in Y, so this diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index a27df7118e..3b0afacbe6 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -195,13 +195,13 @@ void ShiftedMetric::shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* ou irfft(&cmplx[0], mesh.LocalNz, out); // Reverse FFT } -void ShiftedMetric::calcYUpDown(Field3D& f) { +void ShiftedMetric::calcParallelSlices(Field3D& f) { auto results = shiftZ(f, parallel_slice_phases); ASSERT3(results.size() == parallel_slice_phases.size()); - f.splitYupYdown(); + f.splitParallelSlices(); for (std::size_t i = 0; i < results.size(); ++i) { f.ynext(parallel_slice_phases[i].y_offset) = std::move(results[i]); diff --git a/src/mesh/parallel/shiftedmetric.hxx b/src/mesh/parallel/shiftedmetric.hxx index ecf0a42de9..41e9da0960 100644 --- a/src/mesh/parallel/shiftedmetric.hxx +++ b/src/mesh/parallel/shiftedmetric.hxx @@ -47,7 +47,7 @@ public: * Calculates the yup() and ydown() fields of f * by taking FFTs in Z and applying a phase shift. */ - void calcYUpDown(Field3D& f) override; + void calcParallelSlices(Field3D& f) override; /*! * Uses FFTs and a phase shift to align the grid points diff --git a/tests/integrated/test-smooth/test_smooth.cxx b/tests/integrated/test-smooth/test_smooth.cxx index d837f89a3a..6c8c52e635 100644 --- a/tests/integrated/test-smooth/test_smooth.cxx +++ b/tests/integrated/test-smooth/test_smooth.cxx @@ -17,7 +17,7 @@ int main(int argc, char **argv) { Field2D input2d = f.create2D("1 + sin(2*y)"); Field3D input3d = f.create3D("gauss(x-0.5,0.2)*gauss(y-pi)*sin(3*y - z)"); - input3d.getCoordinates()->getParallelTransform().calcYUpDown(input3d); + input3d.getCoordinates()->getParallelTransform().calcParallelSlices(input3d); SAVE_ONCE2(input2d, input3d); diff --git a/tests/integrated/test-yupdown/test_yupdown.cxx b/tests/integrated/test-yupdown/test_yupdown.cxx index 6163353aae..9f17ca9743 100644 --- a/tests/integrated/test-yupdown/test_yupdown.cxx +++ b/tests/integrated/test-yupdown/test_yupdown.cxx @@ -51,7 +51,7 @@ int main(int argc, char** argv) { // Var starts in orthogonal X-Z coordinates // Calculate yup and ydown - s.calcYUpDown(var); + s.calcParallelSlices(var); // Calculate d/dy using yup() and ydown() fields Field3D ddy = DDY(var); diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 0b6743b679..9985434dc7 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -188,16 +188,16 @@ TEST_F(Field3DTest, TimeDeriv) { EXPECT_EQ(&(ddt(field)), deriv); } -TEST_F(Field3DTest, SplitYupYDown) { +TEST_F(Field3DTest, SplitParallelSlices) { Field3D field; field = 0.; - EXPECT_FALSE(field.hasYupYdown()); + EXPECT_FALSE(field.hasParallelSlices()); - field.splitYupYdown(); + field.splitParallelSlices(); - EXPECT_TRUE(field.hasYupYdown()); + EXPECT_TRUE(field.hasParallelSlices()); auto& yup = field.yup(); EXPECT_NE(&field, &yup); @@ -205,7 +205,7 @@ TEST_F(Field3DTest, SplitYupYDown) { EXPECT_NE(&field, &ydown); // Should be able to split again without any problems - field.splitYupYdown(); + field.splitParallelSlices(); // Would be nice to check yup2 != yup, but not sure this is possible // to do in general @@ -215,16 +215,16 @@ TEST_F(Field3DTest, SplitYupYDown) { EXPECT_NE(&field, &ydown2); } -TEST_F(Field3DTest, MergeYupYDown) { +TEST_F(Field3DTest, ClearParallelSlices) { Field3D field; field = 0.; - EXPECT_FALSE(field.hasYupYdown()); + EXPECT_FALSE(field.hasParallelSlices()); - field.mergeYupYdown(); + field.clearParallelSlices(); - EXPECT_FALSE(field.hasYupYdown()); + EXPECT_FALSE(field.hasParallelSlices()); #if CHECK > 2 EXPECT_THROW(field.yup(), BoutException); @@ -232,21 +232,21 @@ TEST_F(Field3DTest, MergeYupYDown) { #endif // Should be able to merge again without any problems - EXPECT_NO_THROW(field.mergeYupYdown()); + EXPECT_NO_THROW(field.clearParallelSlices()); } -TEST_F(Field3DTest, SplitThenMergeYupYDown) { +TEST_F(Field3DTest, SplitThenClearParallelSlices) { Field3D field; field = 0.; - field.splitYupYdown(); + field.splitParallelSlices(); auto& yup = field.yup(); EXPECT_NE(&field, &yup); auto& ydown = field.ydown(); EXPECT_NE(&field, &ydown); - field.mergeYupYdown(); + field.clearParallelSlices(); #if CHECK > 2 EXPECT_THROW(field.yup(), BoutException); @@ -254,16 +254,16 @@ TEST_F(Field3DTest, SplitThenMergeYupYDown) { #endif } -TEST_F(Field3DTest, MultipleYupYdown) { +TEST_F(Field3DTest, MultipleParallelSlices) { FakeMesh newmesh{3, 5, 7}; newmesh.ystart = 2; newmesh.createDefaultRegions(); Field3D field{&newmesh}; - field.splitYupYdown(); + field.splitParallelSlices(); - EXPECT_TRUE(field.hasYupYdown()); + EXPECT_TRUE(field.hasParallelSlices()); auto &yup = field.yup(); EXPECT_NE(&field, &yup); @@ -285,7 +285,7 @@ TEST_F(Field3DTest, Ynext) { Field3D field; field = 0.; - field.splitYupYdown(); + field.splitParallelSlices(); auto& yup = field.ynext(1); EXPECT_NE(&field, &yup); @@ -301,7 +301,7 @@ TEST_F(Field3DTest, Ynext) { TEST_F(Field3DTest, ConstYnext) { Field3D field(0.); - field.splitYupYdown(); + field.splitParallelSlices(); const Field3D& field2 = field; @@ -1893,7 +1893,7 @@ TEST_F(Field3DTest, Swap) { first.setLocation(CELL_XLOW); - first.splitYupYdown(); + first.splitParallelSlices(); first.yup() = 1.5; first.ydown() = 0.5; @@ -1913,7 +1913,7 @@ TEST_F(Field3DTest, Swap) { // Second field Field3D second(2., &second_mesh); - second.splitYupYdown(); + second.splitParallelSlices(); second.yup() = 2.2; second.ydown() = 1.2; @@ -1964,7 +1964,7 @@ TEST_F(Field3DTest, MoveCtor) { first.setLocation(CELL_XLOW); - first.splitYupYdown(); + first.splitParallelSlices(); first.yup() = 1.5; first.ydown() = 0.5; diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index e8a2dbc49c..abce2e0dc3 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -141,8 +141,8 @@ class DerivativesTest // We need the parallel slices for the y-direction ParallelTransformIdentity identity{*mesh}; - identity.calcYUpDown(input); - identity.calcYUpDown(velocity); + identity.calcParallelSlices(input); + identity.calcParallelSlices(velocity); // FIXME: remove when defaults are set in the DerivativeStore ctor DerivativeStore::getInstance().initialise(Options::getRoot()); diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 036c315607..e24b0f3e9d 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -192,7 +192,7 @@ TEST_F(ShiftedMetricTest, ToFromFieldAligned) { FFTTolerance)); } -TEST_F(ShiftedMetricTest, CalcYUpDown) { +TEST_F(ShiftedMetricTest, CalcParallelSlices) { // We don't shift in the guard cells, and the parallel slices are // stored offset in y, therefore we need to make new regions that we // can compare the expected and actual outputs over @@ -213,7 +213,7 @@ TEST_F(ShiftedMetricTest, CalcYUpDown) { output_info.enable(); // Actual interesting bit here! - input.getCoordinates()->getParallelTransform().calcYUpDown(input); + input.getCoordinates()->getParallelTransform().calcParallelSlices(input); // Expected output values Field3D expected_up_1{mesh}; diff --git a/tests/unit/mesh/test_paralleltransform.cxx b/tests/unit/mesh/test_paralleltransform.cxx index 863d6233ef..25854c1f70 100644 --- a/tests/unit/mesh/test_paralleltransform.cxx +++ b/tests/unit/mesh/test_paralleltransform.cxx @@ -11,19 +11,19 @@ extern Mesh* mesh; using ParallelTransformTest = FakeMeshFixture; -TEST_F(ParallelTransformTest, IdentityCalcYUpDown) { +TEST_F(ParallelTransformTest, IdentityCalcParallelSlices) { ParallelTransformIdentity transform{*bout::globals::mesh}; Field3D field{1.0}; - transform.calcYUpDown(field); + transform.calcParallelSlices(field); EXPECT_TRUE(IsFieldEqual(field.yup(), 1.0)); EXPECT_TRUE(IsFieldEqual(field.ydown(), 1.0)); } -TEST_F(ParallelTransformTest, IdentityCalcYUpDownTwoSlices) { +TEST_F(ParallelTransformTest, IdentityCalcTwoParallelSlices) { ParallelTransformIdentity transform{*bout::globals::mesh}; @@ -31,7 +31,7 @@ TEST_F(ParallelTransformTest, IdentityCalcYUpDownTwoSlices) { Field3D field{1.0}; - transform.calcYUpDown(field); + transform.calcParallelSlices(field); EXPECT_TRUE(IsFieldEqual(field.yup(0), 1.0)); EXPECT_TRUE(IsFieldEqual(field.yup(1), 1.0)); From c3bef6600d5c02d013f8a880975811b2ee3b32f1 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 8 Mar 2019 14:40:01 +0000 Subject: [PATCH 1007/1783] Simplify calling calcParallelSlices and to/fromFieldAligned Make calcParallelSlices a method of Field3D, that then calls the ParallelTransform through fieldCoordinates->getParallelTransform(). Returns a reference to the field itself, in case we want to use it while method-chaining. Make toFieldAligned and fromFieldAligned free functions, with Field3D and Field2D versions. Remove calcParallelSlices, toFieldAligned and fromFieldAligned from the Coordinates class, since those methods are no longer needed. Also remove canToFromFieldAligned() method, as this was used only in one place, and can be accessed through getParallelTransform() anyway. --- include/bout/coordinates.hxx | 10 ------- include/bout/fv_ops.hxx | 12 ++++---- include/bout/index_derivs_interface.hxx | 24 ++++++++-------- include/field2d.hxx | 3 ++ include/field3d.hxx | 5 ++++ include/interpolation.hxx | 4 +-- src/field/field3d.cxx | 13 +++++++++ src/field/field_factory.cxx | 5 ++-- src/fileio/datafile.cxx | 4 +-- src/invert/parderiv/impls/cyclic/cyclic.cxx | 4 +-- src/mesh/boundary_standard.cxx | 28 +++++++------------ src/mesh/coordinates.cxx | 19 ------------- src/mesh/difops.cxx | 14 +++++----- src/mesh/fv_ops.cxx | 22 +++++++-------- src/physics/smoothing.cxx | 5 ++-- .../integrated/test-yupdown/test_yupdown.cxx | 4 +-- .../unit/mesh/parallel/test_shiftedmetric.cxx | 18 ++++-------- 17 files changed, 85 insertions(+), 109 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index fee264bf70..b514873461 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -126,16 +126,6 @@ public: /// Return the parallel transform, setting it if need be ParallelTransform& getParallelTransform(); - /// Transform a field into field-aligned coordinates - const Field3D toFieldAligned(const Field3D &f, const REGION region = RGN_ALL); - const Field2D toFieldAligned(const Field2D &f, const REGION UNUSED(region) = RGN_ALL); - - /// Convert back into standard form - const Field3D fromFieldAligned(const Field3D &f, const REGION region = RGN_ALL); - const Field2D fromFieldAligned(const Field2D &f, const REGION UNUSED(region) = RGN_ALL); - - bool canToFromFieldAligned(); - /////////////////////////////////////////////////////////// // Operators diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index 14cd7f2cf8..3c8379b132 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -188,8 +188,8 @@ namespace FV { CellEdges cellboundary; - Field3D f = f_in.getCoordinates()->toFieldAligned(f_in, RGN_NOX); - Field3D v = v_in.getCoordinates()->toFieldAligned(v_in, RGN_NOX); + Field3D f = toFieldAligned(f_in, RGN_NOX); + Field3D v = toFieldAligned(v_in, RGN_NOX); Coordinates *coord = f_in.getCoordinates(); @@ -326,7 +326,7 @@ namespace FV { } } } - return result.getCoordinates()->fromFieldAligned(result, RGN_NOBNDRY); + return fromFieldAligned(result, RGN_NOBNDRY); } /*! @@ -470,8 +470,8 @@ namespace FV { // Currently just using simple centered differences // so no fluxes need to be exchanged - n = n_in.getCoordinates()->toFieldAligned(n_in, RGN_NOX); - Field3D vy = v.y.getCoordinates()->toFieldAligned(v.y, RGN_NOX); + n = toFieldAligned(n_in, RGN_NOX); + Field3D vy = toFieldAligned(v.y, RGN_NOX); Field3D yresult = 0.0; for(int i=mesh->xstart;i<=mesh->xend;i++) @@ -490,7 +490,7 @@ namespace FV { yresult(i,j,k) = (nU*vU - nD*vD) / (coord->J(i,j)*coord->dy(i,j)); } - return result + yresult.getCoordinates()->fromFieldAligned(yresult, RGN_NOBNDRY); + return result + fromFieldAligned(yresult, RGN_NOBNDRY); } } diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 9b856d5167..3c68ab4e34 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -203,10 +203,10 @@ T DDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "D return standardDerivative(f, outloc, method, region); } else { - const T f_aligned = f.getCoordinates()->toFieldAligned(f, RGN_NOX); + const T f_aligned = toFieldAligned(f, RGN_NOX); T result = standardDerivative(f_aligned, outloc, method, region); - return result.getCoordinates()->fromFieldAligned(result, region); + return fromFieldAligned(result, region); } } @@ -218,10 +218,10 @@ T D2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = return standardDerivative( f, outloc, method, region); } else { - const T f_aligned = f.getCoordinates()->toFieldAligned(f, RGN_NOX); + const T f_aligned = toFieldAligned(f, RGN_NOX); T result = standardDerivative( f_aligned, outloc, method, region); - return result.getCoordinates()->fromFieldAligned(result, region); + return fromFieldAligned(result, region); } } @@ -233,10 +233,10 @@ T D4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = return standardDerivative( f, outloc, method, region); } else { - const T f_aligned = f.getCoordinates()->toFieldAligned(f, RGN_NOX); + const T f_aligned = toFieldAligned(f, RGN_NOX); T result = standardDerivative( f_aligned, outloc, method, region); - return result.getCoordinates()->fromFieldAligned(result, region); + return fromFieldAligned(result, region); } } @@ -307,11 +307,11 @@ T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, return flowDerivative(vel, f, outloc, method, region); } else { - const T f_aligned = f.getCoordinates()->toFieldAligned(f, RGN_NOX); - const T vel_aligned = vel.getCoordinates()->toFieldAligned(vel, RGN_NOX); + const T f_aligned = toFieldAligned(f, RGN_NOX); + const T vel_aligned = toFieldAligned(vel, RGN_NOX); T result = flowDerivative(vel_aligned, f_aligned, outloc, method, region); - return result.getCoordinates()->fromFieldAligned(result, region); + return fromFieldAligned(result, region); } } @@ -325,11 +325,11 @@ T FDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, return flowDerivative(vel, f, outloc, method, region); } else { - const T f_aligned = f.getCoordinates()->toFieldAligned(f, RGN_NOX); - const T vel_aligned = vel.getCoordinates()->toFieldAligned(vel, RGN_NOX); + const T f_aligned = toFieldAligned(f, RGN_NOX); + const T vel_aligned = toFieldAligned(vel, RGN_NOX); T result = flowDerivative(vel_aligned, f_aligned, outloc, method, region); - return result.getCoordinates()->fromFieldAligned(result, region); + return fromFieldAligned(result, region); } } diff --git a/include/field2d.hxx b/include/field2d.hxx index dbd7b5ae04..b08cff49bd 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -314,6 +314,9 @@ Field2D operator-(const Field2D &f); // Non-member functions +inline Field2D toFieldAligned(const Field2D& f, const REGION UNUSED(region)) { return f; } +inline Field2D fromFieldAligned(const Field2D& f, const REGION UNUSED(region)) { return f; } + /// Square root of \p f over region \p rgn /// /// This loops over the entire domain, including guard/boundary cells by diff --git a/include/field3d.hxx b/include/field3d.hxx index ce1ee1cc51..a8357e2707 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -438,6 +438,8 @@ class Field3D : public Field, public FieldData { friend class Vector3D; + Field3D& calcParallelSlices(); + void applyBoundary(bool init=false) override; void applyBoundary(BoutReal t); void applyBoundary(const std::string &condition); @@ -532,6 +534,9 @@ Field3D operator-(const Field3D &f); // Non-member functions +Field3D toFieldAligned(const Field3D& f, const REGION region = RGN_ALL); +Field3D fromFieldAligned(const Field3D& f, const REGION region = RGN_ALL); + /// Calculates the minimum of a field, excluding the boundary/guard /// cells by default (can be changed with \p rgn argument). /// diff --git a/include/interpolation.hxx b/include/interpolation.hxx index 3f91bdc366..be5b5c82ba 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -126,7 +126,7 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { // We can't interpolate in y unless we're field-aligned // FIXME: Add check once we label fields as orthogonal/aligned - const T var_fa = var.getCoordinates()->toFieldAligned(var, RGN_NOX); + const T var_fa = toFieldAligned(var, RGN_NOX); if (region != RGN_NOBNDRY) { // repeat the hack above for boundary points // this avoids a duplicate toFieldAligned call if we had called @@ -153,7 +153,7 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { } } - result = result.getCoordinates()->fromFieldAligned(result, RGN_NOBNDRY); + result = fromFieldAligned(result, RGN_NOBNDRY); break; } diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index aedcfd32d4..3b3186586c 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -285,6 +285,11 @@ Field3D & Field3D::operator=(const BoutReal val) { return *this; } +Field3D& Field3D::calcParallelSlices() { + fieldCoordinates->getParallelTransform().calcParallelSlices(*this); + return *this; +} + ///////////////////// BOUNDARY CONDITIONS ////////////////// void Field3D::applyBoundary(bool init) { @@ -560,6 +565,14 @@ Field3D operator-(const Field3D &f) { return -1.0 * f; } //////////////// NON-MEMBER FUNCTIONS ////////////////// +Field3D toFieldAligned(const Field3D& f, const REGION region) { + return f.getCoordinates()->getParallelTransform().toFieldAligned(f, region); +} + +Field3D fromFieldAligned(const Field3D& f, const REGION region) { + return f.getCoordinates()->getParallelTransform().fromFieldAligned(f, region); +} + Field3D pow(const Field3D &lhs, const Field3D &rhs, REGION rgn) { TRACE("pow(Field3D, Field3D)"); diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index dc810779e2..8b36d81b27 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -215,11 +215,10 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC } }; - Coordinates* coords = result.getCoordinates(); - if (coords->canToFromFieldAligned()) { + if (result.getCoordinates()->getParallelTransform().canToFromFieldAligned()) { // Transform from field aligned coordinates, to be compatible with // older BOUT++ inputs. This is not a particularly "nice" solution. - result = coords->fromFieldAligned(result, RGN_ALL); + result = fromFieldAligned(result, RGN_ALL); } return result; diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 748ab0985a..ad2d9b2e55 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -1156,7 +1156,7 @@ bool Datafile::read_f3d(const std::string &name, Field3D *f, bool save_repeat) { if (shiftInput) { // Input file is in field-aligned coordinates e.g. BOUT++ 3.x restart file - *f = f->getCoordinates()->fromFieldAligned(*f, RGN_ALL); + *f = fromFieldAligned(*f, RGN_ALL); } return true; @@ -1202,7 +1202,7 @@ bool Datafile::write_f3d(const std::string &name, Field3D *f, bool save_repeat) //Deal with shifting the output Field3D f_out{emptyFrom(*f)}; if(shiftOutput) { - f_out = f->getCoordinates()->toFieldAligned(*f); + f_out = toFieldAligned(*f); }else { f_out = *f; } diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index 644cdf4047..3fd8eaeb61 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -65,7 +65,7 @@ const Field3D InvertParCR::solve(const Field3D &f) { Coordinates *coord = f.getCoordinates(); - Field3D alignedField = coord->toFieldAligned(f, RGN_NOX); + Field3D alignedField = toFieldAligned(f, RGN_NOX); // Create cyclic reduction object CyclicReduce *cr = @@ -214,6 +214,6 @@ const Field3D InvertParCR::solve(const Field3D &f) { // Delete cyclic reduction object delete cr; - return coord->fromFieldAligned(result, RGN_NOBNDRY); + return fromFieldAligned(result, RGN_NOBNDRY); } diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index fce769073f..bff082d020 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -3316,16 +3316,14 @@ void BoundaryToFieldAligned::apply(Field2D &f, BoutReal t) { void BoundaryToFieldAligned::apply(Field3D &f, BoutReal t) { ASSERT1(bndry->localmesh = f.getMesh()); - auto coords = f.getCoordinates(); - //NOTE: This is not very efficient... updating entire field - f = coords->fromFieldAligned(f); + f = fromFieldAligned(f); // Apply the boundary to shifted field op->apply(f, t); //Shift back - f = coords->toFieldAligned(f); + f = toFieldAligned(f); //This is inefficient -- could instead use the shiftZ just in the bndry //but this is not portable to other parallel transforms -- we could instead @@ -3339,12 +3337,10 @@ void BoundaryToFieldAligned::apply_ddt(Field2D &f) { void BoundaryToFieldAligned::apply_ddt(Field3D &f) { ASSERT1(bndry->localmesh = f.getMesh()); - auto coords = f.getCoordinates(); - - f = coords->fromFieldAligned(f); - ddt(f) = coords->fromFieldAligned(ddt(f)); + f = fromFieldAligned(f); + ddt(f) = fromFieldAligned(ddt(f)); op->apply_ddt(f); - ddt(f) = coords->toFieldAligned(ddt(f)); + ddt(f) = toFieldAligned(ddt(f)); } @@ -3367,16 +3363,14 @@ void BoundaryFromFieldAligned::apply(Field2D &f, BoutReal t) { void BoundaryFromFieldAligned::apply(Field3D &f, BoutReal t) { ASSERT1(bndry->localmesh = f.getMesh()); - auto coords = f.getCoordinates(); - //NOTE: This is not very efficient... shifting entire field - f = coords->toFieldAligned(f); + f = toFieldAligned(f); // Apply the boundary to shifted field op->apply(f, t); //Shift back - f = coords->fromFieldAligned(f); + f = fromFieldAligned(f); //This is inefficient -- could instead use the shiftZ just in the bndry //but this is not portable to other parallel transforms -- we could instead @@ -3390,10 +3384,8 @@ void BoundaryFromFieldAligned::apply_ddt(Field2D &f) { void BoundaryFromFieldAligned::apply_ddt(Field3D &f) { ASSERT1(bndry->localmesh = f.getMesh()); - auto coords = f.getCoordinates(); - - f = coords->toFieldAligned(f); - ddt(f) = coords->toFieldAligned(ddt(f)); + f = toFieldAligned(f); + ddt(f) = toFieldAligned(ddt(f)); op->apply_ddt(f); - ddt(f) = coords->fromFieldAligned(ddt(f)); + ddt(f) = fromFieldAligned(ddt(f)); } diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index a703e5f9cd..ea4478ef4a 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -715,25 +715,6 @@ ParallelTransform& Coordinates::getParallelTransform() { return *transform; } -/// Transform a field into field-aligned coordinates -const Field3D Coordinates::toFieldAligned(const Field3D &f, const REGION region) { - return getParallelTransform().toFieldAligned(f, region); -} -const Field2D Coordinates::toFieldAligned(const Field2D &f, const REGION UNUSED(region)) { - return f; -} - -/// Convert back into standard form -const Field3D Coordinates::fromFieldAligned(const Field3D &f, const REGION region) { - return getParallelTransform().fromFieldAligned(f, region); -} -const Field2D Coordinates::fromFieldAligned(const Field2D &f, const REGION UNUSED(region)) { - return f; -} - -bool Coordinates::canToFromFieldAligned() { - return getParallelTransform().canToFromFieldAligned(); -} /******************************************************************************* * Operators diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index dc49d03e8d..6ab67c4881 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -286,7 +286,7 @@ const Field3D Grad_par_CtoL(const Field3D &var) { } } else { // No yup/ydown fields, so transform to cell centred - Field3D var_fa = var.getCoordinates()->toFieldAligned(var, RGN_NOX); + Field3D var_fa = toFieldAligned(var, RGN_NOX); for(int jx=0; jxLocalNx;jx++) { for(int jy=1;jyLocalNy;jy++) { @@ -296,7 +296,7 @@ const Field3D Grad_par_CtoL(const Field3D &var) { } } - result = metric->fromFieldAligned(result, RGN_NOBNDRY); + result = fromFieldAligned(result, RGN_NOBNDRY); } return result; @@ -350,8 +350,8 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg // (even if one of v and f has yup/ydown fields, it doesn't make sense to // multiply them with one in field-aligned and one in non-field-aligned // coordinates) - Field3D v_fa = v.getCoordinates()->toFieldAligned(v, RGN_NOX); - Field3D f_fa = f.getCoordinates()->toFieldAligned(f, RGN_NOX); + Field3D v_fa = toFieldAligned(v, RGN_NOX); + Field3D f_fa = toFieldAligned(f, RGN_NOX); BOUT_OMP(parallel) { stencil fval, vval; @@ -370,7 +370,7 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg result[i] -= (vval.p >= 0.0) ? vval.p * fval.c : vval.p * fval.p; } - result = result.getCoordinates()->fromFieldAligned(result, region); + result = fromFieldAligned(result, region); } } @@ -395,12 +395,12 @@ const Field3D Grad_par_LtoC(const Field3D &var) { } else { // No yup/ydown field, so transform to field aligned - Field3D var_fa = var.getCoordinates()->toFieldAligned(var, RGN_NOX); + Field3D var_fa = toFieldAligned(var, RGN_NOX); BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { result[i] = (var_fa[i.yp()] - var_fa[i]) / (metric->dy[i]*sqrt(metric->g_22[i])); } - result = result.getCoordinates()->fromFieldAligned(result, RGN_NOBNDRY); + result = fromFieldAligned(result, RGN_NOBNDRY); } return result; diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index 03b62f7384..86d3d17b01 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -73,8 +73,8 @@ namespace FV { // At least one input doesn't have yup/ydown fields. // Need to shift to/from field aligned coordinates - fup = fdown = fc = f.getCoordinates()->toFieldAligned(f); - aup = adown = ac = a.getCoordinates()->toFieldAligned(a); + fup = fdown = fc = toFieldAligned(f); + aup = adown = ac = toFieldAligned(a); } // Y flux @@ -157,7 +157,7 @@ namespace FV { if (f.hasParallelSlices() && a.hasParallelSlices()) { result += yzresult; } else { - result += yzresult.getCoordinates()->fromFieldAligned(yzresult); + result += fromFieldAligned(yzresult); } return result; @@ -173,8 +173,8 @@ namespace FV { bool use_parallel_slices = (Kin.hasParallelSlices() && fin.hasParallelSlices()); - const auto& K = use_parallel_slices ? Kin : Kin.getCoordinates()->toFieldAligned(Kin, RGN_NOX); - const auto& f = use_parallel_slices ? fin : fin.getCoordinates()->toFieldAligned(fin, RGN_NOX); + const auto& K = use_parallel_slices ? Kin : toFieldAligned(Kin, RGN_NOX); + const auto& f = use_parallel_slices ? fin : toFieldAligned(fin, RGN_NOX); // K and f fields in yup and ydown directions const auto& Kup = use_parallel_slices ? Kin.yup() : K; @@ -220,7 +220,7 @@ namespace FV { if (!use_parallel_slices) { // Shifted to field aligned coordinates, so need to shift back - result = result.getCoordinates()->fromFieldAligned(result, RGN_NOBNDRY); + result = fromFieldAligned(result, RGN_NOBNDRY); } return result; @@ -236,8 +236,8 @@ namespace FV { Coordinates *coord = f_in.getCoordinates(); // Convert to field aligned coordinates - Field3D d = d_in.getCoordinates()->toFieldAligned(d_in, RGN_NOX); - Field3D f = f_in.getCoordinates()->toFieldAligned(f_in, RGN_NOX); + Field3D d = toFieldAligned(d_in, RGN_NOX); + Field3D f = toFieldAligned(f_in, RGN_NOX); for(int i=mesh->xstart;i<=mesh->xend;i++) for(int j=mesh->ystart;j<=mesh->yend;j++) { @@ -276,7 +276,7 @@ namespace FV { } // Convert result back to non-aligned coordinates - return result.getCoordinates()->fromFieldAligned(result, RGN_NOBNDRY); + return fromFieldAligned(result, RGN_NOBNDRY); } const Field3D D4DY4_Index(const Field3D &f_in, bool bndry_flux) { @@ -285,7 +285,7 @@ namespace FV { Mesh* mesh = f_in.getMesh(); // Convert to field aligned coordinates - Field3D f = f_in.getCoordinates()->toFieldAligned(f_in, RGN_NOX); + Field3D f = toFieldAligned(f_in, RGN_NOX); Coordinates *coord = f_in.getCoordinates(); @@ -386,7 +386,7 @@ namespace FV { } // Convert result back to non-aligned coordinates - return result.getCoordinates()->fromFieldAligned(result, RGN_NOBNDRY); + return fromFieldAligned(result, RGN_NOBNDRY); } void communicateFluxes(Field3D &f) { diff --git a/src/physics/smoothing.cxx b/src/physics/smoothing.cxx index dba2e001cd..021b0f42d3 100644 --- a/src/physics/smoothing.cxx +++ b/src/physics/smoothing.cxx @@ -404,14 +404,13 @@ const Field3D nl_filter_y(const Field3D &f, BoutReal w) { TRACE("nl_filter_x( Field3D )"); Mesh *mesh = f.getMesh(); - auto coords = f.getCoordinates(); Field3D result{emptyFrom(f)}; rvec v(mesh->LocalNy); // Temporary array // Transform into field-aligned coordinates - Field3D fs = coords->toFieldAligned(f); + Field3D fs = toFieldAligned(f); for (int jx=0;jxLocalNx;jx++) { for (int jz=0;jzLocalNz;jz++) { @@ -426,7 +425,7 @@ const Field3D nl_filter_y(const Field3D &f, BoutReal w) { } // Tranform the field back from field aligned coordinates - return coords->fromFieldAligned(result); + return fromFieldAligned(result); } const Field3D nl_filter_z(const Field3D &fs, BoutReal w) { diff --git a/tests/integrated/test-yupdown/test_yupdown.cxx b/tests/integrated/test-yupdown/test_yupdown.cxx index 9f17ca9743..805545b766 100644 --- a/tests/integrated/test-yupdown/test_yupdown.cxx +++ b/tests/integrated/test-yupdown/test_yupdown.cxx @@ -61,13 +61,13 @@ int main(int argc, char** argv) { Field3D ddy2 = DDY(var2); // Change into field-aligned coordinates - Field3D var_aligned = var.getCoordinates()->toFieldAligned(var); + Field3D var_aligned = toFieldAligned(var); // var now field aligned Field3D ddy_check = DDY_aligned(var_aligned); // Shift back to orthogonal X-Z coordinates - ddy_check = var.getCoordinates()->fromFieldAligned(ddy_check); + ddy_check = fromFieldAligned(ddy_check); SAVE_ONCE3(ddy, ddy2, ddy_check); dump.write(); diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index e24b0f3e9d..6c8b30cb2c 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -123,13 +123,11 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { {4., 5., 1., 3., 2.}, {2., 4., 3., 5., 1.}}}); - auto coords = expected.getCoordinates(); - - Field3D result = coords->toFieldAligned(input); + Field3D result = toFieldAligned(input); EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_ALL", FFTTolerance)); - EXPECT_TRUE(IsFieldEqual(coords->fromFieldAligned(input), input)); + EXPECT_TRUE(IsFieldEqual(fromFieldAligned(input), input)); EXPECT_TRUE(areFieldsCompatible(result, expected)); EXPECT_FALSE(areFieldsCompatible(result, input)); } @@ -166,29 +164,25 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { {2., 4., 5., 1., 3.}, {5., 1., 2., 4., 3.}}}); - auto coords = input.getCoordinates(); - - Field3D result = coords->fromFieldAligned(input); + Field3D result = fromFieldAligned(input); // Loosen tolerance a bit due to FFTs EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_ALL", FFTTolerance)); - EXPECT_TRUE(IsFieldEqual(coords->toFieldAligned(input), input)); + EXPECT_TRUE(IsFieldEqual(toFieldAligned(input), input)); EXPECT_TRUE(areFieldsCompatible(result, expected)); EXPECT_FALSE(areFieldsCompatible(result, input)); } TEST_F(ShiftedMetricTest, FromToFieldAligned) { - auto coords = input.getCoordinates(); - EXPECT_TRUE(IsFieldEqual(coords->fromFieldAligned(coords->toFieldAligned(input)), input, "RGN_ALL", + EXPECT_TRUE(IsFieldEqual(fromFieldAligned(toFieldAligned(input)), input, "RGN_ALL", FFTTolerance)); } TEST_F(ShiftedMetricTest, ToFromFieldAligned) { - auto coords = input.getCoordinates(); input.setDirectionY(YDirectionType::Aligned); - EXPECT_TRUE(IsFieldEqual(coords->toFieldAligned(coords->fromFieldAligned(input)), input, "RGN_ALL", + EXPECT_TRUE(IsFieldEqual(toFieldAligned(fromFieldAligned(input)), input, "RGN_ALL", FFTTolerance)); } From 7994dd1c320156e628712f1f7aecec70f6b59788 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 8 Mar 2019 15:44:55 +0000 Subject: [PATCH 1008/1783] Correct zShift in guard cells so ShiftedMetric doesn't need TwistShift To make zShift continuous into the guard cells where there is a branch cut in the poloidal domain from theta=0->theta=2pi, we need to add/subtract ShiftAngle (which is the total zShift for a 2pi poloidal circuit). Add methods to Mesh/BoutMesh to indicate where there is a branch cut and get the value of ShiftAngle. --- include/bout/mesh.hxx | 14 +++++ src/mesh/coordinates.cxx | 15 ++++++ src/mesh/impls/bout/boutmesh.cxx | 53 ++++++++++++++++--- src/mesh/impls/bout/boutmesh.hxx | 14 +++++ src/mesh/parallel/shiftedmetric.cxx | 12 ++--- tests/integrated/test-yupdown/data/BOUT.inp | 1 + .../unit/mesh/parallel/test_shiftedmetric.cxx | 1 - tests/unit/test_extras.hxx | 8 +++ 8 files changed, 103 insertions(+), 15 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 3a892c8afa..58cbb81f1c 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -330,6 +330,20 @@ class Mesh { /// \param[in] jx The local (on this processor) index in X /// \param[out] ts The Twist-Shift angle if periodic virtual bool periodicY(int jx, BoutReal &ts) const = 0; + + /// Is there a branch cut at this processor's lower boundary? + /// + /// @param[in] jx The local (on this processor) index in X + /// @param[out] global_shift The total zShift for a 2pi poloidal circuit, + /// non-zero if there is a branch-cut + virtual bool hasBranchCutLower(int jx, BoutReal& global_shift) const = 0; + + /// Is there a branch cut at this processor's upper boundary? + /// + /// @param[in] jx The local (on this processor) index in X + /// @param[out] global_shift The total zShift for a 2pi poloidal circuit, + /// non-zero if there is a branch-cut + virtual bool hasBranchCutUpper(int jx, BoutReal& global_shift) const = 0; virtual int ySize(int jx) const; ///< The number of points in Y at fixed X index \p jx diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index ea4478ef4a..a1d88ed0da 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -689,6 +689,21 @@ void Coordinates::setParallelTransform(Options* options) { // make sure zShift has been communicated localmesh->communicate(zShift); + // Correct guard cells for discontinuity of zShift at poloidal branch cut + for (int x = 0; x < localmesh->LocalNx; x++) { + BoutReal global_shift = 0.; + if (localmesh->hasBranchCutLower(x, global_shift)) { + for (int y = 0; y < localmesh->ystart; y++) { + zShift(x, y) -= global_shift; + } + } + if (localmesh->hasBranchCutUpper(x, global_shift)) { + for (int y = localmesh->yend + 1; y < localmesh->LocalNy; y++) { + zShift(x, y) += global_shift; + } + } + } + transform = bout::utils::make_unique(*localmesh, location, zShift, zlength()); diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index f67fbe6b8d..6413a1aed2 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -457,16 +457,22 @@ int BoutMesh::load() { OPTION(options, TwistShift, false); - if (TwistShift) { - output_info.write("Applying Twist-Shift condition. Interpolation: FFT\n"); + // Try to read the shift angle from the grid file + // NOTE: All processors should know the twist-shift angle (for invert_parderiv) + // NOTE: Always read ShiftAngle as Coordinates will use hasBranchCutLower and + // hasBranchCutUpper to set zShift for ShiftedMetric - // Try to read the shift angle from the grid file - // NOTE: All processors should know the twist-shift angle (for invert_parderiv) + ShiftAngle.resize(LocalNx); - ShiftAngle.resize(LocalNx); + if (!source->get(this, ShiftAngle, "ShiftAngle", LocalNx, XGLOBAL(0))) { + ShiftAngle.clear(); + } - if (!source->get(this, ShiftAngle, "ShiftAngle", LocalNx, XGLOBAL(0))) { - throw BoutException("ERROR: Twist-shift angle 'ShiftAngle' not found."); + if (TwistShift) { + output_info.write("Applying Twist-Shift condition. Interpolation: FFT\n"); + if (ShiftAngle.empty()) { + throw BoutException("ERROR: Twist-shift angle 'ShiftAngle' not found. " + "Required when TwistShift==true."); } } @@ -2020,6 +2026,39 @@ bool BoutMesh::periodicY(int jx, BoutReal &ts) const { return false; } +bool BoutMesh::hasBranchCutLower(int jx, BoutReal& global_shift) const { + if ( (TS_down_in and DDATA_INDEST != -1 and jx < DDATA_XSPLIT) + or (TS_down_out and DDATA_OUTDEST != -1 and jx >= DDATA_XSPLIT) ) { + // this processor has branch cut at lower boundary for jx + if (ShiftAngle.empty()) { + // This function should only be called during initialization, so always check + throw BoutException("BoutMesh failed to read ShiftAngle from the grid"); + } + global_shift = ShiftAngle[jx]; + return true; + } + + global_shift = 0.; + return false; +} + + +bool BoutMesh::hasBranchCutUpper(int jx, BoutReal& global_shift) const { + if ( (TS_up_in and UDATA_INDEST != -1 and jx < UDATA_XSPLIT) + or (TS_up_out and UDATA_OUTDEST != -1 and jx >= UDATA_XSPLIT) ) { + // this processor has branch cut at upper boundary for jx + if (ShiftAngle.empty()) { + // This function should only be called during initialization, so always check + throw BoutException("BoutMesh failed to read ShiftAngle from the grid"); + } + global_shift = ShiftAngle[jx]; + return true; + } + + global_shift = 0.; + return false; +} + int BoutMesh::ySize(int xpos) const { int xglobal = XGLOBAL(xpos); int yglobal = YGLOBAL(MYG); diff --git a/src/mesh/impls/bout/boutmesh.hxx b/src/mesh/impls/bout/boutmesh.hxx index 6964ebf2dc..96f97a9ee7 100644 --- a/src/mesh/impls/bout/boutmesh.hxx +++ b/src/mesh/impls/bout/boutmesh.hxx @@ -105,6 +105,20 @@ class BoutMesh : public Mesh { /// \param[in] jx The local (on this processor) index in X bool periodicY(int jx) const; + /// Is there a branch cut at this processor's lower boundary? + /// + /// @param[in] jx The local (on this processor) index in X + /// @param[out] global_shift The total zShift for a 2pi poloidal circuit, + /// non-zero if there is a branch-cut + bool hasBranchCutLower(int jx, BoutReal& global_shift) const override; + + /// Is there a branch cut at this processor's upper boundary? + /// + /// @param[in] jx The local (on this processor) index in X + /// @param[out] global_shift The total zShift for a 2pi poloidal circuit, + /// non-zero if there is a branch-cut + bool hasBranchCutUpper(int jx, BoutReal& global_shift) const override; + int ySize(int jx) const; ///< The number of points in Y at fixed X index \p jx ///////////////////////////////////////////// diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 3b0afacbe6..67ddd16cff 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -24,14 +24,12 @@ ShiftedMetric::ShiftedMetric(Mesh& m, CELL_LOC location_in, Field2D zShift_, // check the coordinate system used for the grid data source checkInputGrid(); - // TwistShift needs to be set for derivatives to be correct at the jump where - // poloidal angle theta goes 2pi->0 + // TwistShift should not be set for derivatives to be correct at the jump where + // poloidal angle theta goes 2pi->0. zShift has been corrected for the jump + // already in Coordinates::Coordinates bool twistshift = Options::root()["TwistShift"].withDefault(false); - bool shift_without_twist = Options::root()["ShiftWithoutTwist"].withDefault(false); - if (!twistshift and !shift_without_twist) { - throw BoutException( - "ShiftedMetric usually requires the option TwistShift=true\n" - " Set ShiftWithoutTwist=true to use ShiftedMetric without TwistShift"); + if (twistshift) { + throw BoutException("ShiftedMetric requires the option TwistShift=false"); } cachePhases(); diff --git a/tests/integrated/test-yupdown/data/BOUT.inp b/tests/integrated/test-yupdown/data/BOUT.inp index 46604e38e7..a7b9791c77 100644 --- a/tests/integrated/test-yupdown/data/BOUT.inp +++ b/tests/integrated/test-yupdown/data/BOUT.inp @@ -5,6 +5,7 @@ nx = 12 ny = 12 zShift = y +ShiftAngle = 2.*pi var = sin(y - z) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 6c8b30cb2c..b804e2bb41 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -16,7 +16,6 @@ extern Mesh* mesh; class ShiftedMetricTest : public ::testing::Test { public: ShiftedMetricTest() { - Options::root()["TwistShift"] = true; // Delete any existing mesh if (mesh != nullptr) { delete mesh; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 8b65ebd1a4..9a0d05e576 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -189,6 +189,14 @@ public: MPI_Comm getYcomm(int UNUSED(jx)) const { return MPI_COMM_NULL; } bool periodicY(int UNUSED(jx)) const { return true; } bool periodicY(int UNUSED(jx), BoutReal &UNUSED(ts)) const { return true; } + bool hasBranchCutLower(int UNUSED(jx), BoutReal& global_shift) const { + global_shift = 0.; + return false; + } + bool hasBranchCutUpper(int UNUSED(jx), BoutReal& global_shift) const { + global_shift = 0.; + return false; + } bool firstY() const { return true; } bool lastY() const { return true; } bool firstY(int UNUSED(xpos)) const { return true; } From 06b44a0d6337cae41600c2b83e2f7d7d8bb2049d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 8 Mar 2019 16:52:46 +0000 Subject: [PATCH 1009/1783] Replace ENUM_STRING functions with toString overloads Deprecated: - CELL_LOC_STRING - DIFF_METHOD_STRING - REGION_STRING - DIRECITON_STRING - STAGGER_STRING - DERIV_STRING --- include/bout/coordinates.hxx | 22 ++++---- include/bout/deriv_store.hxx | 68 ++++++++++++------------- include/bout/index_derivs.hxx | 2 +- include/bout_types.hxx | 32 +++++++++--- include/derivs.hxx | 78 ++++++++++++++--------------- include/difops.hxx | 32 ++++++------ include/interpolation.hxx | 6 +-- include/vecops.hxx | 6 +-- src/field/field2d.cxx | 2 +- src/field/field3d.cxx | 8 +-- src/field/fieldperp.cxx | 2 +- src/fileio/datafile.cxx | 16 +++--- src/mesh/index_derivs.cxx | 4 +- src/mesh/interpolation.cxx | 2 +- src/mesh/parallel/shiftedmetric.cxx | 4 +- src/sys/bout_types.cxx | 15 +++--- 16 files changed, 157 insertions(+), 142 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index bc04da7165..7ccafa0ae4 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -114,34 +114,34 @@ public: const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); const Field2D DDX(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return DDX(f, outloc, DIFF_METHOD_STRING(method), region); + return DDX(f, outloc, toString(method), region); }; const Field2D DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); const Field2D DDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return DDY(f, outloc, DIFF_METHOD_STRING(method), region); + return DDY(f, outloc, toString(method), region); }; const Field2D DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); const Field2D DDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); + return DDZ(f, outloc, toString(method), region); }; /// Gradient along magnetic field b.Grad(f) const Field2D Grad_par(const Field2D& var, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); const Field2D Grad_par(const Field2D& var, CELL_LOC outloc, DIFF_METHOD method) { - return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); + return Grad_par(var, outloc, toString(method)); }; const Field3D Grad_par(const Field3D& var, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); const Field3D Grad_par(const Field3D& var, CELL_LOC outloc, DIFF_METHOD method) { - return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); + return Grad_par(var, outloc, toString(method)); }; /// Advection along magnetic field V*b.Grad(f) @@ -150,7 +150,7 @@ public: const std::string& method = "DEFAULT"); const Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); + return Vpar_Grad_par(v, f, outloc, toString(method)); }; const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, @@ -158,33 +158,33 @@ public: const std::string& method = "DEFAULT"); const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); + return Vpar_Grad_par(v, f, outloc, toString(method)); }; /// Divergence along magnetic field Div(b*f) = B.Grad(f/B) const Field2D Div_par(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); const Field2D Div_par(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Div_par(f, outloc, DIFF_METHOD_STRING(method)); + return Div_par(f, outloc, toString(method)); }; const Field3D Div_par(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); const Field3D Div_par(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Div_par(f, outloc, DIFF_METHOD_STRING(method)); + return Div_par(f, outloc, toString(method)); }; // Second derivative along magnetic field const Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); const Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Grad2_par2(f, outloc, DIFF_METHOD_STRING(method)); + return Grad2_par2(f, outloc, toString(method)); }; const Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); const Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Grad2_par2(f, outloc, DIFF_METHOD_STRING(method)); + return Grad2_par2(f, outloc, toString(method)); }; // Perpendicular Laplacian operator, using only X-Z derivatives diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index 03a2408f77..ec0ae63eb3 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -91,7 +91,7 @@ struct DerivativeStore { AUTO_TRACE(); // Get the key - auto key = getKey(direction, stagger, DERIV_STRING(derivType)); + auto key = getKey(direction, stagger, toString(derivType)); return isEmpty(key); } @@ -102,7 +102,7 @@ struct DerivativeStore { AUTO_TRACE(); // Get the key - auto key = getKey(direction, stagger, DERIV_STRING(derivType)); + auto key = getKey(direction, stagger, toString(derivType)); if (isEmpty(key)) { return std::set{}; } else { @@ -118,11 +118,11 @@ struct DerivativeStore { // Introductory information output_info << "Available methods for derivative type '"; - output_info << DERIV_STRING(derivType); + output_info << toString(derivType); output_info << "' in direction "; - output_info << DIRECTION_STRING(direction); + output_info << toString(direction); output_info << " ( Staggering : "; - output_info << STAGGER_STRING(stagger) << " ) : \n"; + output_info << toString(stagger) << " ) : \n"; for (const auto& i : getAvailableMethods(derivType, direction, stagger)) { output_info << "\t" << i << "\n"; @@ -141,8 +141,8 @@ struct DerivativeStore { if (standard.count(key) != 0) { throw BoutException("Trying to override standard derivative : " "direction %s, stagger %s, key %s", - DIRECTION_STRING(direction).c_str(), - STAGGER_STRING(stagger).c_str(), methodName.c_str()); + toString(direction).c_str(), + toString(stagger).c_str(), methodName.c_str()); } standard[key] = func; break; @@ -150,8 +150,8 @@ struct DerivativeStore { if (standardSecond.count(key) != 0) { throw BoutException("Trying to override standardSecond derivative : " "direction %s, stagger %s, key %s", - DIRECTION_STRING(direction).c_str(), - STAGGER_STRING(stagger).c_str(), methodName.c_str()); + toString(direction).c_str(), + toString(stagger).c_str(), methodName.c_str()); } standardSecond[key] = func; break; @@ -159,19 +159,19 @@ struct DerivativeStore { if (standardFourth.count(key) != 0) { throw BoutException("Trying to override standardFourth derivative : " "direction %s, stagger %s, key %s", - DIRECTION_STRING(direction).c_str(), - STAGGER_STRING(stagger).c_str(), methodName.c_str()); + toString(direction).c_str(), + toString(stagger).c_str(), methodName.c_str()); } standardFourth[key] = func; break; default: throw BoutException("Invalid function signature in registerDerivative : Function " "signature 'standard' but derivative type %s passed", - DERIV_STRING(derivType).c_str()); + toString(derivType).c_str()); }; // Register this method name in lookup of known methods - registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))].insert( + registeredMethods[getKey(direction, stagger, toString(derivType))].insert( methodName); }; @@ -188,8 +188,8 @@ struct DerivativeStore { if (upwind.count(key) != 0) { throw BoutException("Trying to override upwind derivative : " "direction %s, stagger %s, key %s", - DIRECTION_STRING(direction).c_str(), - STAGGER_STRING(stagger).c_str(), methodName.c_str()); + toString(direction).c_str(), + toString(stagger).c_str(), methodName.c_str()); } upwind[key] = func; break; @@ -197,19 +197,19 @@ struct DerivativeStore { if (flux.count(key) != 0) { throw BoutException("Trying to override flux derivative : " "direction %s, stagger %s, key %s", - DIRECTION_STRING(direction).c_str(), - STAGGER_STRING(stagger).c_str(), methodName.c_str()); + toString(direction).c_str(), + toString(stagger).c_str(), methodName.c_str()); } flux[key] = func; break; default: throw BoutException("Invalid function signature in registerDerivative : Function " "signature 'upwind/flux' but derivative type %s passed", - DERIV_STRING(derivType).c_str()); + toString(derivType).c_str()); }; // Register this method name in lookup of known methods - registeredMethods[getKey(direction, stagger, DERIV_STRING(derivType))].insert( + registeredMethods[getKey(direction, stagger, toString(derivType))].insert( methodName); }; @@ -240,7 +240,7 @@ struct DerivativeStore { AUTO_TRACE(); const auto realName = nameLookup( - name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(derivType)))); + name, defaultMethods.at(getKey(direction, stagger, toString(derivType)))); const auto key = getKey(direction, stagger, realName); const storageType* theMap = nullptr; @@ -254,7 +254,7 @@ struct DerivativeStore { } else { throw BoutException("getStandardDerivative only works for derivType in {Standard, " "StandardSecond, StandardFourth} but receieved %s", - DERIV_STRING(derivType).c_str()); + toString(derivType).c_str()); }; const auto resultOfFind = theMap->find(key); @@ -264,7 +264,7 @@ struct DerivativeStore { throw BoutException( "Couldn't find requested method %s in map for standard derivative of type %s.", getMethodName(realName, direction, stagger).c_str(), - DERIV_STRING(derivType).c_str()); + toString(derivType).c_str()); }; standardFunc getStandard2ndDerivative(std::string name, DIRECTION direction, @@ -284,7 +284,7 @@ struct DerivativeStore { DERIV derivType = DERIV::Upwind) const { AUTO_TRACE(); const auto realName = nameLookup( - name, defaultMethods.at(getKey(direction, stagger, DERIV_STRING(derivType)))); + name, defaultMethods.at(getKey(direction, stagger, toString(derivType)))); const auto key = getKey(direction, stagger, realName); const storageType* theMap = nullptr; @@ -296,7 +296,7 @@ struct DerivativeStore { } else { throw BoutException( "getFlowDerivative only works for derivType in {Upwind, Flux} but receieved %s", - DERIV_STRING(derivType).c_str()); + toString(derivType).c_str()); }; const auto resultOfFind = theMap->find(key); @@ -306,7 +306,7 @@ struct DerivativeStore { throw BoutException( "Couldn't find requested method %s in map for standard flow of type %s.", getMethodName(realName, direction, stagger).c_str(), - DERIV_STRING(derivType).c_str()); + toString(derivType).c_str()); } upwindFunc getUpwindDerivative(std::string name, DIRECTION direction, @@ -346,7 +346,7 @@ struct DerivativeStore { const auto theDirection = direction.first; const auto theDerivType = deriv.first; - const auto theDerivTypeString = DERIV_STRING(theDerivType); + const auto theDerivTypeString = toString(theDerivType); // Note both staggered and unstaggered have the same fallback default currently std::string theDefault{ @@ -375,7 +375,7 @@ struct DerivativeStore { defaultMethods[getKey(theDirection, STAGGER::None, theDerivTypeString)] = theDefault; output_verbose << "The default method for derivative type " << theDerivTypeString - << " in direction " << DIRECTION_STRING(theDirection) << " is " + << " in direction " << toString(theDirection) << " is " << theDefault << "\n"; //------------------------------------------------------------- @@ -400,7 +400,7 @@ struct DerivativeStore { theDefault; output_verbose << "The default method for staggered derivative type " << theDerivTypeString << " in direction " - << DIRECTION_STRING(theDirection) << " is " << theDefault << "\n"; + << toString(theDirection) << " is " << theDefault << "\n"; } } } @@ -408,7 +408,7 @@ struct DerivativeStore { /// Provide a method to override/force a specific default method void forceDefaultMethod(std::string methodName, DERIV deriv, DIRECTION direction, STAGGER stagger = STAGGER::None) { - const auto key = getKey(direction, stagger, DERIV_STRING(deriv)); + const auto key = getKey(direction, stagger, toString(deriv)); defaultMethods[key] = uppercase(methodName); } @@ -476,7 +476,7 @@ private: for (const auto& direction : directions) { for (const auto& deriv : derivTypes) { const auto theDirection = direction.first; - const auto theDerivTypeString = DERIV_STRING(deriv.first); + const auto theDerivTypeString = toString(deriv.first); const std::string theDefault{uppercase(initialDefaultMethods[deriv.first])}; //------------------------------------------------------------- @@ -497,12 +497,12 @@ private: std::string getMethodName(std::string name, DIRECTION direction, STAGGER stagger = STAGGER::None) const { AUTO_TRACE(); - return name + " (" + DIRECTION_STRING(direction) + ", " + STAGGER_STRING(stagger) + return name + " (" + toString(direction) + ", " + toString(stagger) + ")"; }; std::string nameLookup(const std::string name, const std::string defaultName) const { - return name != DIFF_METHOD_STRING(DIFF_DEFAULT) ? name : defaultName; + return name != toString(DIFF_DEFAULT) ? name : defaultName; } /// Provides a routine to produce a unique key given information @@ -519,8 +519,8 @@ private: // maps to store the different field types as the signature is // different. std::size_t result; - result = std::hash{}(DIRECTION_STRING(direction)); - result = result ^ std::hash{}(STAGGER_STRING(stagger)); + result = std::hash{}(toString(direction)); + result = result ^ std::hash{}(toString(stagger)); result = result ^ std::hash{}(key); return result; } diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index 801adde70b..b43118429e 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -69,7 +69,7 @@ inline std::ostream& operator<<(std::ostream& out, const metaData& meta) { out << ", "; out << "nGuards : " << meta.nGuards; out << ", "; - out << "type : " << DERIV_STRING(meta.derivType); + out << "type : " << toString(meta.derivType); return out; } diff --git a/include/bout_types.hxx b/include/bout_types.hxx index bb8e49d7c7..e3e2a7fa65 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -22,8 +22,10 @@ #ifndef __BOUT_TYPES_H__ #define __BOUT_TYPES_H__ -#include +#include "bout/deprecated.hxx" + #include +#include /// Size of real numbers typedef double BoutReal; @@ -36,17 +38,24 @@ const BoutReal BoutNaN = std::numeric_limits::quiet_NaN(); /// 4 possible variable locations. Default is for passing to functions enum CELL_LOC {CELL_DEFAULT=0, CELL_CENTRE=1, CELL_CENTER=1, CELL_XLOW=2, CELL_YLOW=3, CELL_ZLOW=4, CELL_VSHIFT=5}; -const std::string& CELL_LOC_STRING(CELL_LOC location); +std::string toString(CELL_LOC location); +DEPRECATED(inline std::string CELL_LOC_STRING(CELL_LOC location)) { + return toString(location); +} /// Differential methods. Both central and upwind enum DIFF_METHOD {DIFF_DEFAULT, DIFF_U1, DIFF_U2, DIFF_C2, DIFF_W2, DIFF_W3, DIFF_C4, DIFF_U3, DIFF_FFT, DIFF_SPLIT, DIFF_S2}; -const std::string& DIFF_METHOD_STRING(DIFF_METHOD location); +std::string toString(DIFF_METHOD location); +DEPRECATED(inline std::string DIFF_METHOD_STRING(DIFF_METHOD location)) { + return toString(location); +} /// Specify grid region for looping -enum REGION {RGN_ALL, RGN_NOBNDRY, RGN_NOX, RGN_NOY, RGN_NOZ}; +enum REGION { RGN_ALL, RGN_NOBNDRY, RGN_NOX, RGN_NOY, RGN_NOZ }; -const std::string& REGION_STRING(REGION region); +std::string toString(REGION region); +DEPRECATED(inline std::string REGION_STRING(REGION region)) { return toString(region); } /// To identify particular directions (in index space): /// - X, Y, Z are the coordinate directions @@ -57,7 +66,10 @@ const std::string& REGION_STRING(REGION region); /// field-aligned enum class DIRECTION { X, Y, Z, YAligned, YOrthogonal }; -const std::string& DIRECTION_STRING(DIRECTION direction); +std::string toString(DIRECTION direction); +DEPRECATED(inline std::string DIRECTION_STRING(DIRECTION direction)) { + return toString(direction); +} /// Identify kind of a field's y-direction /// - Standard is the default for the Mesh/Coordinates/ParallelTransform @@ -87,12 +99,16 @@ void swap(const DirectionTypes& first, const DirectionTypes& second); /// To identify valid staggering combinations enum class STAGGER { None, C2L, L2C }; -const std::string& STAGGER_STRING(STAGGER stagger); +std::string toString(STAGGER stagger); +DEPRECATED(inline std::string STAGGER_STRING(STAGGER stagger)) { + return toString(stagger); +} /// To identify types of derivative method combinations enum class DERIV { Standard, StandardSecond, StandardFourth, Upwind, Flux }; -const std::string& DERIV_STRING(DERIV deriv); +std::string toString(DERIV deriv); +DEPRECATED(inline std::string DERIV_STRING(DERIV deriv)) { return toString(deriv); } // A small struct that can be used to wrap a specific enum value, giving // it a unique type that can be passed as a valid type to templates and diff --git a/include/derivs.hxx b/include/derivs.hxx index c167385a19..93cdbc6a61 100644 --- a/include/derivs.hxx +++ b/include/derivs.hxx @@ -54,7 +54,7 @@ const Field3D DDX(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D DDX(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return DDX(f, outloc, DIFF_METHOD_STRING(method), region); + return DDX(f, outloc, toString(method), region); }; /// Calculate first partial derivative in X @@ -73,7 +73,7 @@ const Field2D DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D DDX(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return DDX(f, outloc, DIFF_METHOD_STRING(method), region); + return DDX(f, outloc, toString(method), region); }; /// Calculate first partial derivative in Y @@ -92,7 +92,7 @@ const Field3D DDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D DDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return DDY(f, outloc, DIFF_METHOD_STRING(method), region); + return DDY(f, outloc, toString(method), region); }; /// Calculate first partial derivative in Y @@ -111,7 +111,7 @@ const Field2D DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D DDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return DDY(f, outloc, DIFF_METHOD_STRING(method), region); + return DDY(f, outloc, toString(method), region); }; /// Calculate first partial derivative in Z @@ -130,7 +130,7 @@ const Field3D DDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D DDZ(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); + return DDZ(f, outloc, toString(method), region); }; /// Calculate first partial derivative in Z @@ -149,7 +149,7 @@ const Field2D DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D DDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); + return DDZ(f, outloc, toString(method), region); }; /// Calculate first partial derivative in Z @@ -168,7 +168,7 @@ const Vector3D DDZ(const Vector3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Vector3D DDZ(const Vector3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); + return DDZ(f, outloc, toString(method), region); }; /// Calculate first partial derivative in Z @@ -187,7 +187,7 @@ const Vector2D DDZ(const Vector2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Vector2D DDZ(const Vector2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return DDZ(f, outloc, DIFF_METHOD_STRING(method), region); + return DDZ(f, outloc, toString(method), region); }; ////////// SECOND DERIVATIVES ////////// @@ -208,7 +208,7 @@ const Field3D D2DX2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D D2DX2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D2DX2(f, outloc, DIFF_METHOD_STRING(method), region); + return D2DX2(f, outloc, toString(method), region); }; /// Calculate second partial derivative in X @@ -227,7 +227,7 @@ const Field2D D2DX2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D D2DX2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D2DX2(f, outloc, DIFF_METHOD_STRING(method), region); + return D2DX2(f, outloc, toString(method), region); }; /// Calculate second partial derivative in Y @@ -246,7 +246,7 @@ const Field3D D2DY2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D D2DY2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D2DY2(f, outloc, DIFF_METHOD_STRING(method), region); + return D2DY2(f, outloc, toString(method), region); }; /// Calculate second partial derivative in Y @@ -265,7 +265,7 @@ const Field2D D2DY2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D D2DY2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D2DY2(f, outloc, DIFF_METHOD_STRING(method), region); + return D2DY2(f, outloc, toString(method), region); }; /// Calculate second partial derivative in Z @@ -284,7 +284,7 @@ const Field3D D2DZ2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D D2DZ2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D2DZ2(f, outloc, DIFF_METHOD_STRING(method), region); + return D2DZ2(f, outloc, toString(method), region); }; /// Calculate second partial derivative in Z @@ -303,7 +303,7 @@ const Field2D D2DZ2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D D2DZ2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D2DZ2(f, outloc, DIFF_METHOD_STRING(method), region); + return D2DZ2(f, outloc, toString(method), region); }; ////////// FOURTH DERIVATIVES ////////// @@ -324,7 +324,7 @@ const Field3D D4DX4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D D4DX4(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D4DX4(f, outloc, DIFF_METHOD_STRING(method), region); + return D4DX4(f, outloc, toString(method), region); }; /// Calculate forth partial derivative in X @@ -343,7 +343,7 @@ const Field2D D4DX4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D D4DX4(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D4DX4(f, outloc, DIFF_METHOD_STRING(method), region); + return D4DX4(f, outloc, toString(method), region); }; /// Calculate forth partial derivative in Y @@ -362,7 +362,7 @@ const Field3D D4DY4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D D4DY4(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D4DY4(f, outloc, DIFF_METHOD_STRING(method), region); + return D4DY4(f, outloc, toString(method), region); }; /// Calculate forth partial derivative in Y @@ -381,7 +381,7 @@ const Field2D D4DY4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D D4DY4(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D4DY4(f, outloc, DIFF_METHOD_STRING(method), region); + return D4DY4(f, outloc, toString(method), region); }; /// Calculate forth partial derivative in Z @@ -400,7 +400,7 @@ const Field3D D4DZ4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D D4DZ4(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D4DZ4(f, outloc, DIFF_METHOD_STRING(method), region); + return D4DZ4(f, outloc, toString(method), region); }; /// Calculate forth partial derivative in Z @@ -419,7 +419,7 @@ const Field2D D4DZ4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D D4DZ4(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D4DZ4(f, outloc, DIFF_METHOD_STRING(method), region); + return D4DZ4(f, outloc, toString(method), region); }; /// For terms of form v * grad(f) @@ -439,7 +439,7 @@ const Field3D VDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DE const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D VDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDX(v, f, outloc, DIFF_METHOD_STRING(method), region); + return VDDX(v, f, outloc, toString(method), region); }; /// For terms of form v * grad(f) @@ -459,7 +459,7 @@ const Field2D VDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DE const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D VDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDX(v, f, outloc, DIFF_METHOD_STRING(method), region); + return VDDX(v, f, outloc, toString(method), region); }; /// For terms of form v * grad(f) @@ -479,7 +479,7 @@ const Field3D VDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DE const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D VDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDY(v, f, outloc, DIFF_METHOD_STRING(method), region); + return VDDY(v, f, outloc, toString(method), region); }; /// For terms of form v * grad(f) @@ -499,7 +499,7 @@ const Field2D VDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DE const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D VDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDY(v, f, outloc, DIFF_METHOD_STRING(method), region); + return VDDY(v, f, outloc, toString(method), region); }; /// For terms of form v * grad(f) @@ -519,7 +519,7 @@ const Field3D VDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DE const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D VDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); + return VDDZ(v, f, outloc, toString(method), region); }; /// For terms of form v * grad(f) @@ -539,7 +539,7 @@ const Field2D VDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DE const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D VDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); + return VDDZ(v, f, outloc, toString(method), region); }; /// For terms of form v * grad(f) @@ -559,7 +559,7 @@ const Field2D VDDZ(const Field3D& v, const Field2D& f, CELL_LOC outloc = CELL_DE const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D VDDZ(const Field3D& v, const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); + return VDDZ(v, f, outloc, toString(method), region); }; /// for terms of form div(v * f) @@ -579,7 +579,7 @@ const Field3D FDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DE const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D FDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return FDDX(v, f, outloc, DIFF_METHOD_STRING(method), region); + return FDDX(v, f, outloc, toString(method), region); }; /// for terms of form div(v * f) @@ -599,7 +599,7 @@ const Field2D FDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DE const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D FDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return FDDX(v, f, outloc, DIFF_METHOD_STRING(method), region); + return FDDX(v, f, outloc, toString(method), region); }; /// for terms of form div(v * f) @@ -619,7 +619,7 @@ const Field3D FDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DE const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D FDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return FDDY(v, f, outloc, DIFF_METHOD_STRING(method), region); + return FDDY(v, f, outloc, toString(method), region); }; /// for terms of form div(v * f) @@ -639,7 +639,7 @@ const Field2D FDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DE const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D FDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return FDDY(v, f, outloc, DIFF_METHOD_STRING(method), region); + return FDDY(v, f, outloc, toString(method), region); }; /// for terms of form div(v * f) @@ -659,7 +659,7 @@ const Field3D FDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DE const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D FDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return FDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); + return FDDZ(v, f, outloc, toString(method), region); }; /// for terms of form div(v * f) @@ -679,7 +679,7 @@ const Field2D FDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DE const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D FDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return FDDZ(v, f, outloc, DIFF_METHOD_STRING(method), region); + return FDDZ(v, f, outloc, toString(method), region); }; /// Calculate mixed partial derivative in x and y @@ -698,7 +698,7 @@ const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D2DXDY(f, outloc, DIFF_METHOD_STRING(method), region); + return D2DXDY(f, outloc, toString(method), region); }; /// Calculate mixed partial derivative in x and y @@ -717,7 +717,7 @@ const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D2DXDY(f, outloc, DIFF_METHOD_STRING(method), region); + return D2DXDY(f, outloc, toString(method), region); }; /// Calculate mixed partial derivative in x and z @@ -736,7 +736,7 @@ const Field3D D2DXDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D D2DXDZ(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D2DXDZ(f, outloc, DIFF_METHOD_STRING(method), region); + return D2DXDZ(f, outloc, toString(method), region); }; /// Calculate mixed partial derivative in x and z @@ -755,7 +755,7 @@ const Field2D D2DXDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D D2DXDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D2DXDZ(f, outloc, DIFF_METHOD_STRING(method), region); + return D2DXDZ(f, outloc, toString(method), region); }; /// Calculate mixed partial derivative in y and z @@ -774,7 +774,7 @@ const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D2DYDZ(f, outloc, DIFF_METHOD_STRING(method), region); + return D2DYDZ(f, outloc, toString(method), region); }; /// Calculate mixed partial derivative in y and z @@ -793,7 +793,7 @@ const Field2D D2DYDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); inline const Field2D D2DYDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return D2DYDZ(f, outloc, DIFF_METHOD_STRING(method), region); + return D2DYDZ(f, outloc, toString(method), region); }; #endif // __DERIVS_H__ diff --git a/include/difops.hxx b/include/difops.hxx index f636b06fb0..5578cb3b1b 100644 --- a/include/difops.hxx +++ b/include/difops.hxx @@ -58,11 +58,11 @@ const Field2D Grad_par(const Field2D& var, CELL_LOC outloc = CELL_DEFAULT, DEPRECATED(const Field2D Grad_par(const Field2D& var, const std::string& method, CELL_LOC outloc = CELL_DEFAULT)); inline const Field2D Grad_par(const Field2D& var, CELL_LOC outloc, DIFF_METHOD method) { - return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); + return Grad_par(var, outloc, toString(method)); }; DEPRECATED(inline const Field2D Grad_par(const Field2D& var, DIFF_METHOD method, CELL_LOC outloc)) { - return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); + return Grad_par(var, outloc, toString(method)); }; const Field3D Grad_par(const Field3D& var, CELL_LOC outloc = CELL_DEFAULT, @@ -71,11 +71,11 @@ DEPRECATED(const Field3D Grad_par(const Field3D& var, const std::string& method, CELL_LOC outloc = CELL_DEFAULT)); inline const DEPRECATED(Field3D Grad_par(const Field3D& var, CELL_LOC outloc, DIFF_METHOD method)) { - return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); + return Grad_par(var, outloc, toString(method)); }; DEPRECATED(inline const DEPRECATED( Field3D Grad_par(const Field3D& var, DIFF_METHOD method, CELL_LOC outloc))) { - return Grad_par(var, outloc, DIFF_METHOD_STRING(method)); + return Grad_par(var, outloc, toString(method)); }; /*! @@ -112,11 +112,11 @@ DEPRECATED(const Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT)); inline const Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); + return Vpar_Grad_par(v, f, outloc, toString(method)); }; DEPRECATED(inline const Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, DIFF_METHOD method, CELL_LOC outloc)) { - return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); + return Vpar_Grad_par(v, f, outloc, toString(method)); }; const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, @@ -127,11 +127,11 @@ DEPRECATED(const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT)); inline const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); + return Vpar_Grad_par(v, f, outloc, toString(method)); }; DEPRECATED(inline const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, DIFF_METHOD method, CELL_LOC outloc)) { - return Vpar_Grad_par(v, f, outloc, DIFF_METHOD_STRING(method)); + return Vpar_Grad_par(v, f, outloc, toString(method)); }; /*! @@ -151,11 +151,11 @@ const Field2D Div_par(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, DEPRECATED(const Field2D Div_par(const Field2D& f, const std::string& method, CELL_LOC outloc = CELL_DEFAULT)); inline const Field2D Div_par(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Div_par(f, outloc, DIFF_METHOD_STRING(method)); + return Div_par(f, outloc, toString(method)); }; DEPRECATED(inline const Field2D Div_par(const Field2D& f, DIFF_METHOD method, CELL_LOC outloc)) { - return Div_par(f, outloc, DIFF_METHOD_STRING(method)); + return Div_par(f, outloc, toString(method)); }; const Field3D Div_par(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, @@ -163,11 +163,11 @@ const Field3D Div_par(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, DEPRECATED(const Field3D Div_par(const Field3D& f, const std::string& method, CELL_LOC outloc = CELL_DEFAULT)); inline const Field3D Div_par(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Div_par(f, outloc, DIFF_METHOD_STRING(method)); + return Div_par(f, outloc, toString(method)); }; DEPRECATED(inline const Field3D Div_par(const Field3D& f, DIFF_METHOD method, CELL_LOC outloc)) { - return Div_par(f, outloc, DIFF_METHOD_STRING(method)); + return Div_par(f, outloc, toString(method)); }; // Divergence of a parallel flow: Div(f*v) @@ -186,12 +186,12 @@ DEPRECATED(const Field3D Div_par_flux(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT)); inline const Field3D Div_par_flux(const Field3D& v, const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Div_par_flux(v, f, outloc, DIFF_METHOD_STRING(method)); + return Div_par_flux(v, f, outloc, toString(method)); }; DEPRECATED(inline const Field3D Div_par_flux(const Field3D& v, const Field3D& f, DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT)) { - return Div_par_flux(v, f, outloc, DIFF_METHOD_STRING(method)); + return Div_par_flux(v, f, outloc, toString(method)); }; /*! @@ -208,13 +208,13 @@ DEPRECATED(inline const Field3D Div_par_flux(const Field3D& v, const Field3D& f, const Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); inline const Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Grad2_par2(f, outloc, DIFF_METHOD_STRING(method)); + return Grad2_par2(f, outloc, toString(method)); }; const Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); inline const Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Grad2_par2(f, outloc, DIFF_METHOD_STRING(method)); + return Grad2_par2(f, outloc, toString(method)); }; /*! diff --git a/include/interpolation.hxx b/include/interpolation.hxx index e35976d02f..1983416359 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -82,8 +82,8 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { T result{emptyFrom(var).setLocation(loc)}; // Staggered grids enabled, and need to perform interpolation - TRACE("Interpolating %s -> %s", CELL_LOC_STRING(var.getLocation()).c_str(), - CELL_LOC_STRING(loc).c_str()); + TRACE("Interpolating %s -> %s", toString(var.getLocation()).c_str(), + toString(loc).c_str()); if (region != RGN_NOBNDRY) { // result is requested in some boundary region(s) @@ -177,7 +177,7 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { // This should never happen throw BoutException("Unsupported direction of interpolation\n" " - don't know how to interpolate to %s", - CELL_LOC_STRING(loc).c_str()); + toString(loc).c_str()); } }; diff --git a/include/vecops.hxx b/include/vecops.hxx index 4e52641b81..c8a815181d 100644 --- a/include/vecops.hxx +++ b/include/vecops.hxx @@ -64,7 +64,7 @@ const Vector3D Grad(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const Vector3D Grad_perp(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); inline const Vector3D Grad_perp(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Grad_perp(f, outloc, DIFF_METHOD_STRING(method)); + return Grad_perp(f, outloc, toString(method)); } /// Divergence of a vector \p v, returning a scalar @@ -92,11 +92,11 @@ DEPRECATED(inline const Field3D Div(const Vector3D& v, const Field3D& f, } inline const Field3D Div(const Vector3D& v, const Field3D& f, CELL_LOC outloc, DIFF_METHOD method = DIFF_DEFAULT) { - return Div(v, f, outloc, DIFF_METHOD_STRING(method)); + return Div(v, f, outloc, toString(method)); }; DEPRECATED(inline const Field3D Div(const Vector3D& v, const Field3D& f, DIFF_METHOD method, CELL_LOC outloc = CELL_DEFAULT)) { - return Div(v, f, outloc, DIFF_METHOD_STRING(method)); + return Div(v, f, outloc, toString(method)); }; /// Curl of a vector diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index ea41fadfe1..874b0a92eb 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -113,7 +113,7 @@ Field2D* Field2D::timeDeriv() { ////////////// Indexing /////////////////// const Region &Field2D::getRegion(REGION region) const { - return fieldmesh->getRegion2D(REGION_STRING(region)); + return fieldmesh->getRegion2D(toString(region)); }; const Region &Field2D::getRegion(const std::string ®ion_name) const { return fieldmesh->getRegion2D(region_name); diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 11f1ca995d..b37e218475 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -212,7 +212,7 @@ const BoutReal &Field3D::operator()(const Ind2D &d, int jz) const { } const Region &Field3D::getRegion(REGION region) const { - return fieldmesh->getRegion3D(REGION_STRING(region)); + return fieldmesh->getRegion3D(toString(region)); }; const Region &Field3D::getRegion(const std::string ®ion_name) const { return fieldmesh->getRegion3D(region_name); @@ -763,7 +763,7 @@ Field3D filter(const Field3D &var, int N0, REGION rgn) { Field3D result{emptyFrom(var)}; - const auto region_str = REGION_STRING(rgn); + const auto region_str = toString(rgn); // Only allow a whitelist of regions for now ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" || @@ -814,7 +814,7 @@ Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn) { Field3D result{emptyFrom(var)}; - const auto region_str = REGION_STRING(rgn); + const auto region_str = toString(rgn); // Only allow a whitelist of regions for now ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" || @@ -875,7 +875,7 @@ void shiftZ(Field3D &var, int jx, int jy, double zangle) { } void shiftZ(Field3D &var, double zangle, REGION rgn) { - const auto region_str = REGION_STRING(rgn); + const auto region_str = toString(rgn); // Only allow a whitelist of regions for now ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" || diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 8a20156928..7990027b7b 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -169,7 +169,7 @@ FPERP_OP_REAL(*=, *); FPERP_OP_REAL(/=, /); const Region &FieldPerp::getRegion(REGION region) const { - return fieldmesh->getRegionPerp(REGION_STRING(region)); + return fieldmesh->getRegionPerp(toString(region)); }; const Region &FieldPerp::getRegion(const std::string ®ion_name) const { return fieldmesh->getRegionPerp(region_name); diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 1a7a45529e..6f25a6df92 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -886,34 +886,34 @@ bool Datafile::write() { // is written, since this happens after the first rhs evaluation // 2D fields for (const auto& var : f2d_arr) { - file->setAttribute(var.name, "cell_location", CELL_LOC_STRING(var.ptr->getLocation())); + file->setAttribute(var.name, "cell_location", toString(var.ptr->getLocation())); } // 3D fields for (const auto& var : f3d_arr) { - file->setAttribute(var.name, "cell_location", CELL_LOC_STRING(var.ptr->getLocation())); + file->setAttribute(var.name, "cell_location", toString(var.ptr->getLocation())); } // 2D vectors for(const auto& var : v2d_arr) { Vector2D v = *(var.ptr); file->setAttribute(var.name+"_x", "cell_location", - CELL_LOC_STRING(v.x.getLocation())); + toString(v.x.getLocation())); file->setAttribute(var.name+"_y", "cell_location", - CELL_LOC_STRING(v.y.getLocation())); + toString(v.y.getLocation())); file->setAttribute(var.name+"_z", "cell_location", - CELL_LOC_STRING(v.z.getLocation())); + toString(v.z.getLocation())); } // 3D vectors for(const auto& var : v3d_arr) { Vector3D v = *(var.ptr); file->setAttribute(var.name+"_x", "cell_location", - CELL_LOC_STRING(v.x.getLocation())); + toString(v.x.getLocation())); file->setAttribute(var.name+"_y", "cell_location", - CELL_LOC_STRING(v.y.getLocation())); + toString(v.y.getLocation())); file->setAttribute(var.name+"_z", "cell_location", - CELL_LOC_STRING(v.z.getLocation())); + toString(v.z.getLocation())); } } diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 8a3b31c871..737469ac9e 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -421,7 +421,7 @@ class FFTDerivativeType { ASSERT2((std::is_base_of::value)); // Should never need to call this with Field2D - const auto region_str = REGION_STRING(region); + const auto region_str = toString(region); // Only allow a whitelist of regions for now ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" @@ -493,7 +493,7 @@ class FFT2ndDerivativeType { ASSERT2((std::is_base_of::value)); // Should never need to call this with Field2D - const auto region_str = REGION_STRING(region); + const auto region_str = toString(region); // Only allow a whitelist of regions for now ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" diff --git a/src/mesh/interpolation.cxx b/src/mesh/interpolation.cxx index e84dc5e169..4e01a7e6dd 100644 --- a/src/mesh/interpolation.cxx +++ b/src/mesh/interpolation.cxx @@ -36,7 +36,7 @@ void printLocation(const Field2D& var) { output.write("%s", strLocation(var.getLocation())); } -const char* strLocation(CELL_LOC loc) { return CELL_LOC_STRING(loc).c_str(); } +const char* strLocation(CELL_LOC loc) { return toString(loc).c_str(); } const Field3D interpolate(const Field3D &f, const Field3D &delta_x, const Field3D &delta_z) { diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 670f38dce5..fb0d96a879 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -181,7 +181,7 @@ const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Tensor& ph Field3D result{emptyFrom(f).setDirectionY(y_direction_out)}; - BOUT_FOR(i, mesh.getRegion2D(REGION_STRING(region))) { + BOUT_FOR(i, mesh.getRegion2D(toString(region))) { shiftZ(&f(i, 0), &phs(i.x(), i.y(), 0), &result(i, 0)); } @@ -286,7 +286,7 @@ const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Field2D& zangle, // (Note valgrind complains about corner guard cells if we try to loop over // the whole grid, because zShift is not initialized in the corner guard // cells.) - BOUT_FOR(i, mesh.getRegion2D(REGION_STRING(region))) { + BOUT_FOR(i, mesh.getRegion2D(toString(region))) { shiftZ(&f(i, 0), mesh.LocalNz, zangle[i], &result(i, 0)); } diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index d7dda8063c..c7e03abc13 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -1,8 +1,7 @@ -#include -#include #include #include #include +#include template const std::string& safeAt(const std::map& mymap, T t) { @@ -14,7 +13,7 @@ const std::string& safeAt(const std::map& mymap, T t) { return found->second; } -const std::string& CELL_LOC_STRING(CELL_LOC location) { +std::string toString(CELL_LOC location) { AUTO_TRACE(); const static std::map CELL_LOCtoString = { ENUMSTR(CELL_DEFAULT), ENUMSTR(CELL_CENTRE), ENUMSTR(CELL_XLOW), @@ -23,7 +22,7 @@ const std::string& CELL_LOC_STRING(CELL_LOC location) { return safeAt(CELL_LOCtoString, location); } -const std::string& DIFF_METHOD_STRING(DIFF_METHOD location) { +std::string toString(DIFF_METHOD location) { AUTO_TRACE(); const static std::map DIFF_METHODtoString = { {DIFF_DEFAULT, "DEFAULT"}, {DIFF_U1, "U1"}, {DIFF_U2, "U2"}, {DIFF_U3, "U3"}, @@ -33,7 +32,7 @@ const std::string& DIFF_METHOD_STRING(DIFF_METHOD location) { return safeAt(DIFF_METHODtoString, location); } -const std::string& REGION_STRING(REGION region) { +std::string toString(REGION region) { AUTO_TRACE(); const static std::map REGIONtoString = { ENUMSTR(RGN_ALL), ENUMSTR(RGN_NOBNDRY), ENUMSTR(RGN_NOX), ENUMSTR(RGN_NOY), @@ -41,7 +40,7 @@ const std::string& REGION_STRING(REGION region) { return safeAt(REGIONtoString, region); } -const std::string& DIRECTION_STRING(DIRECTION direction) { +std::string toString(DIRECTION direction) { AUTO_TRACE(); const static std::map DIRECTIONtoString = { {DIRECTION::X, "X"}, @@ -95,7 +94,7 @@ bool areDirectionsCompatible(const DirectionTypes& d1, const DirectionTypes& d2) return false; } -const std::string& STAGGER_STRING(STAGGER stagger) { +std::string toString(STAGGER stagger) { AUTO_TRACE(); const static std::map STAGGERtoString = { {STAGGER::None, "No staggering"}, @@ -105,7 +104,7 @@ const std::string& STAGGER_STRING(STAGGER stagger) { return safeAt(STAGGERtoString, stagger); } -const std::string& DERIV_STRING(DERIV deriv) { +std::string toString(DERIV deriv) { AUTO_TRACE(); const static std::map DERIVtoString = { {DERIV::Standard, "Standard"}, From 083b0166dbbedb662766fdb6ea986f474f3d42fa Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 8 Mar 2019 17:00:03 +0000 Subject: [PATCH 1010/1783] Use overloads rather than specialisation for function templates --- include/utils.hxx | 9 +++------ src/sys/utils.cxx | 3 +-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/include/utils.hxx b/include/utils.hxx index 31166311d4..408a2f6767 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -420,14 +420,12 @@ std::string toString(const T& val) { /// Simple case where input is already a string /// This is so that toString can be used in templates /// where the type may be std::string. -template <> -inline std::string toString<>(const std::string& val) { +inline std::string toString(const std::string& val) { return val; } /// Convert a bool to "true" or "false" -template <> -inline std::string toString<>(const bool& val) { +inline std::string toString(const bool& val) { if (val) { return "true"; } @@ -436,8 +434,7 @@ inline std::string toString<>(const bool& val) { /// Convert a time stamp to a string /// This uses std::localtime and std::put_time -template <> -std::string toString<>(const time_t& time); +std::string toString(const time_t& time); /*! * Convert a string to lower case diff --git a/src/sys/utils.cxx b/src/sys/utils.cxx index 89a883418a..161849e963 100644 --- a/src/sys/utils.cxx +++ b/src/sys/utils.cxx @@ -138,8 +138,7 @@ std::string trimComments(const std::string &s, const std::string &c) { return s.substr(0, s.find_first_of(c)); } -template <> -std::string toString<>(const time_t& time) { +std::string toString(const time_t& time) { // Get local time std::tm *tm = std::localtime(&time); From 9c9230fab7488dde5bd3c103ba64565031ed6063 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 8 Mar 2019 17:03:43 +0000 Subject: [PATCH 1011/1783] Rename convert*DirectionTypeToString to toString --- include/bout_types.hxx | 4 ++-- src/fileio/datafile.cxx | 4 ++-- src/sys/bout_types.cxx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 1aa0e9a83e..9c54f6e2e3 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -65,7 +65,7 @@ const std::string& DIRECTION_STRING(DIRECTION direction); /// coordinates enum class YDirectionType { Standard, Aligned }; -const std::string& convertYDirectionTypeToString(YDirectionType d); +std::string toString(YDirectionType d); /// Identify kind of a field's z-direction /// - Standard is the default @@ -74,7 +74,7 @@ const std::string& convertYDirectionTypeToString(YDirectionType d); /// Field2D) enum class ZDirectionType { Standard, Average }; -const std::string& convertZDirectionTypeToString(ZDirectionType d); +std::string toString(ZDirectionType d); /// Container for direction types struct DirectionTypes { diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 9504f07275..81005cfb90 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -852,8 +852,8 @@ bool Datafile::read() { template void Datafile::writeFieldAttributes(const std::string name, T* f) { file->setAttribute(name, "cell_location", CELL_LOC_STRING(f->getLocation())); - file->setAttribute(name, "direction_y", convertYDirectionTypeToString(f->getDirectionY())); - file->setAttribute(name, "direction_z", convertZDirectionTypeToString(f->getDirectionZ())); + file->setAttribute(name, "direction_y", toString(f->getDirectionY())); + file->setAttribute(name, "direction_z", toString(f->getDirectionZ())); } bool Datafile::write() { diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index c3da044c25..f8f58ba397 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -117,7 +117,7 @@ const std::string& DERIV_STRING(DERIV deriv) { return safeAt(DERIVtoString, deriv); } -const std::string& convertYDirectionTypeToString(YDirectionType d) { +std::string toString(YDirectionType d) { AUTO_TRACE(); const static std::map YDirectionTypeToString = { {YDirectionType::Standard, "Standard"}, @@ -126,7 +126,7 @@ const std::string& convertYDirectionTypeToString(YDirectionType d) { return safeAt(YDirectionTypeToString, d); } -const std::string& convertZDirectionTypeToString(ZDirectionType d) { +std::string toString(ZDirectionType d) { AUTO_TRACE(); const static std::map ZDirectionTypeToString = { {ZDirectionType::Standard, "Standard"}, From f0d55cd749587143008a770e3db6495416483a38 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 9 Mar 2019 23:33:22 +0000 Subject: [PATCH 1012/1783] Restore ParallelTransform related methods to Mesh as DEPRECATED Restore the ParallelTransform related methods deleted in 8571ef241cd51c7dca7ac05819effb3417607d83 to the Mesh class, implemented by calling through Coordinates. Mark those methods as DEPRECATED so we can remove them in future. --- include/bout/mesh.hxx | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 58cbb81f1c..6f9c7ec430 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -712,6 +712,43 @@ class Mesh { return bout::derivatives::index::FDDZ(vel, f, outloc, method, region); } + const DEPRECATED(Field3D toFieldAligned(const Field3D &f, + const REGION region = RGN_ALL)) { + return ::toFieldAligned(f, region); + } + + const DEPRECATED(Field3D fromFieldAligned(const Field3D &f, + const REGION region = RGN_ALL)) { + return ::fromFieldAligned(f, region); + } + + const DEPRECATED(Field2D toFieldAligned(const Field2D &f, + const REGION region = RGN_ALL)) { + return ::toFieldAligned(f, region); + } + + const DEPRECATED(Field2D fromFieldAligned(const Field2D &f, + const REGION region = RGN_ALL)) { + return ::fromFieldAligned(f, region); + } + + bool DEPRECATED(canToFromFieldAligned()) { + return getCoordinates()->getParallelTransform().canToFromFieldAligned(); + } + + void DEPRECATED(setParallelTransform(std::unique_ptr pt)) { + getCoordinates()->setParallelTransform(std::move(pt)); + } + + void DEPRECATED(setParallelTransform()) { + // The ParallelTransform is set from options in the Coordinates + // constructor, so this method doesn't need to do anything + } + + ParallelTransform& DEPRECATED(getParallelTransform()) { + return getCoordinates()->getParallelTransform(); + } + /////////////////////////////////////////////////////////// // REGION RELATED ROUTINES From 2bac35662528dda9d9c5e00d1798ff03b22b9d2a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 11 Mar 2019 10:18:10 +0000 Subject: [PATCH 1013/1783] Bump Hypnotoad version number Include summary of changes in next from last 6 pull requests involving Hypnotoad. --- .../gridgen/hypnotoad_version.pro | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tools/tokamak_grids/gridgen/hypnotoad_version.pro b/tools/tokamak_grids/gridgen/hypnotoad_version.pro index f36647c026..38267447d9 100644 --- a/tools/tokamak_grids/gridgen/hypnotoad_version.pro +++ b/tools/tokamak_grids/gridgen/hypnotoad_version.pro @@ -10,10 +10,27 @@ FUNCTION hypnotoad_version ; 1.1.0 - non-orthogonal grid generation added ; 1.1.1 - Hypnotoad version number added here, and now saved to grid files ; 1.1.2 - Fixed bug in calculation of qloop. Should be only in closed regions + ; 1.1.3 - Handle case when break of contour is very close to X-point. + ; Add checkbox to write metrics for orthogonal coordinates (i.e. + ; metrics with integrated shear I=0); include attribute in output + ; file labelling the 'coordinates_type', either 'field_aligned' or + ; 'orthogonal'. + ; Various small fixes to make non-orthogonal grid generation more + ; robust. + ; Better handling of closed contours + ; Make transitions of non-orthogonal coordinates between X-point and + ; wall more flexible: instead of forcing coordinates to be orthogonal + ; half-way through the poloidal region, have separate weights for the + ; boundary vectors at either end to make the transition between the + ; two continuous (with dominant weighting of the orthogonal direction + ; in the middle of the region). + ; Enable 'Detailed settings' dialog for non-orthogonal grids, add + ; setting to change the exponent of the power-law decrease of the + ; weight of non-orthogonal vectors. major_version = 1 minor_version = 1 - patch_number = 2 + patch_number = 3 RETURN, LONG([major_version, minor_version, patch_number]) From 60305ea54bb405e4ffec7ca1913c2ca92bf37300 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 14:47:18 +0000 Subject: [PATCH 1014/1783] writeFieldAttributes takes 'const Field& var' instead of being template Also take name as a reference. --- include/datafile.hxx | 4 ++-- src/fileio/datafile.cxx | 25 ++++++++++++------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/include/datafile.hxx b/include/datafile.hxx index c88f798fb8..9163498ae3 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -24,6 +24,7 @@ class Datafile; #include #include class Mesh; +class Field; class Field2D; class Field3D; class Vector2D; @@ -137,8 +138,7 @@ class Datafile { /// Write out the meta-data of a field as attributes of the variable in /// 'file'. - template - void writeFieldAttributes(const std::string name, T* f); + void writeFieldAttributes(const std::string& name, const Field& f); /// Check if a variable has already been added bool varAdded(const std::string &name); diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index f6b3c261c1..e40d31ee4f 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -849,11 +849,10 @@ bool Datafile::read() { return true; } -template -void Datafile::writeFieldAttributes(const std::string name, T* f) { - file->setAttribute(name, "cell_location", toString(f->getLocation())); - file->setAttribute(name, "direction_y", toString(f->getDirectionY())); - file->setAttribute(name, "direction_z", toString(f->getDirectionZ())); +void Datafile::writeFieldAttributes(const std::string& name, const Field& f) { + file->setAttribute(name, "cell_location", toString(f.getLocation())); + file->setAttribute(name, "direction_y", toString(f.getDirectionY())); + file->setAttribute(name, "direction_z", toString(f.getDirectionZ())); } bool Datafile::write() { @@ -893,28 +892,28 @@ bool Datafile::write() { // output is written, since this happens after the first rhs evaluation // 2D fields for (const auto& var : f2d_arr) { - writeFieldAttributes(var.name, var.ptr); + writeFieldAttributes(var.name, *var.ptr); } // 3D fields for (const auto& var : f3d_arr) { - writeFieldAttributes(var.name, var.ptr); + writeFieldAttributes(var.name, *var.ptr); } // 2D vectors for(const auto& var : v2d_arr) { Vector2D v = *(var.ptr); - writeFieldAttributes(var.name+"_x", &v.x); - writeFieldAttributes(var.name+"_y", &v.y); - writeFieldAttributes(var.name+"_z", &v.z); + writeFieldAttributes(var.name+"_x", v.x); + writeFieldAttributes(var.name+"_y", v.y); + writeFieldAttributes(var.name+"_z", v.z); } // 3D vectors for(const auto& var : v3d_arr) { Vector3D v = *(var.ptr); - writeFieldAttributes(var.name+"_x", &v.x); - writeFieldAttributes(var.name+"_y", &v.y); - writeFieldAttributes(var.name+"_z", &v.z); + writeFieldAttributes(var.name+"_x", v.x); + writeFieldAttributes(var.name+"_y", v.y); + writeFieldAttributes(var.name+"_z", v.z); } } From eb53887036ea0b1a7bf6ce7f80a87c6dacc2f5b6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 16:19:31 +0000 Subject: [PATCH 1015/1783] ParallelTransformIdentity, ShiftedMetric back to paralleltransform.hxx Leave these class declarations as part of the 'public' API. --- include/bout/paralleltransform.hxx | 182 +++++++++++++++++- src/mesh/coordinates.cxx | 2 - src/mesh/parallel/identity.cxx | 3 +- src/mesh/parallel/identity.hxx | 73 ------- src/mesh/parallel/shiftedmetric.cxx | 3 +- src/mesh/parallel/shiftedmetric.hxx | 172 ----------------- .../integrated/test-yupdown/test_yupdown.cxx | 3 +- .../unit/mesh/parallel/test_shiftedmetric.cxx | 1 - tests/unit/test_extras.hxx | 1 - 9 files changed, 184 insertions(+), 256 deletions(-) delete mode 100644 src/mesh/parallel/identity.hxx delete mode 100644 src/mesh/parallel/shiftedmetric.hxx diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index e4a7f280b0..2cb727197e 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -7,8 +7,9 @@ #define __PARALLELTRANSFORM_H__ #include "bout_types.hxx" +#include "field3d.hxx" +#include "unused.hxx" -class Field3D; class Mesh; /*! @@ -51,4 +52,183 @@ protected: Mesh &mesh; ///< The mesh this paralleltransform is part of }; +/*! + * This class implements the simplest form of ParallelTransform + * where the domain is a logically rectangular domain, and + * yup() and ydown() refer to the same field. + */ +class ParallelTransformIdentity : public ParallelTransform { +public: + ParallelTransformIdentity(Mesh& mesh_in) : ParallelTransform(mesh_in) { + // check the coordinate system used for the grid data source + checkInputGrid(); + } + + /*! + * Merges the yup and ydown() fields of f, so that + * f.yup() = f.ydown() = f + */ + void calcParallelSlices(Field3D& f) override; + + /*! + * The field is already aligned in Y, so this + * does nothing + */ + const Field3D toFieldAligned(const Field3D& f, const REGION UNUSED(region)) override { + return f; + } + + /*! + * The field is already aligned in Y, so this + * does nothing + */ + const Field3D fromFieldAligned(const Field3D& f, const REGION UNUSED(region)) override { + return f; + } + + bool canToFromFieldAligned() override { return true; } + +protected: + void checkInputGrid() override; +}; + +/*! + * Shifted metric method + * Each Y location is shifted in Z with respect to its neighbours + * so that the grid is orthogonal in X-Z, but requires interpolation + * to calculate the values of points along field-lines. + * + * In this implementation the interpolation is done using FFTs in Z + */ +class ShiftedMetric : public ParallelTransform { +public: + ShiftedMetric() = delete; + ShiftedMetric(Mesh& mesh, CELL_LOC location, Field2D zShift, BoutReal zlength_in); + + /*! + * Calculates the yup() and ydown() fields of f + * by taking FFTs in Z and applying a phase shift. + */ + void calcParallelSlices(Field3D& f) override; + + /*! + * Uses FFTs and a phase shift to align the grid points + * with the y coordinate (along magnetic field usually). + * + * Note that the returned field will no longer be orthogonal + * in X-Z, and the metric tensor will need to be changed + * if X derivatives are used. + */ + const Field3D toFieldAligned(const Field3D& f, const REGION region = RGN_ALL) override; + + /*! + * Converts a field back to X-Z orthogonal coordinates + * from field aligned coordinates. + */ + const Field3D fromFieldAligned(const Field3D& f, + const REGION region = RGN_ALL) override; + + bool canToFromFieldAligned() override { return true; } + +protected: + void checkInputGrid() override; + +private: + CELL_LOC location{CELL_CENTRE}; + + /// This is the shift in toroidal angle (z) which takes a point from + /// X-Z orthogonal to field-aligned along Y. + Field2D zShift; + + /// Length of the z-domain in radians + BoutReal zlength{0.}; + + int nmodes; + + Tensor toAlignedPhs; ///< Cache of phase shifts for transforming from X-Z + /// orthogonal coordinates to field-aligned coordinates + Tensor fromAlignedPhs; ///< Cache of phase shifts for transforming from + /// field-aligned coordinates to X-Z orthogonal + /// coordinates + + /// Helper POD for parallel slice phase shifts + struct ParallelSlicePhase { + Tensor phase_shift; + int y_offset; + }; + + /// Cache of phase shifts for the parallel slices. Slices are stored + /// in the following order: + /// {+1, ..., +n, -1, ..., -n} + /// slice[i] stores offset i+1 + /// slice[2*i + 1] stores offset -(i+1) + /// where i goes from 0 to (n-1), with n the number of y guard cells + std::vector parallel_slice_phases; + + /*! + * Shift a 2D field in Z. + * Since 2D fields are constant in Z, this has no effect + */ + const Field2D shiftZ(const Field2D& f, const Field2D& UNUSED(zangle), + const REGION UNUSED(region) = RGN_NOX) const { + return f; + }; + + /*! + * Shift a 3D field \p f in Z by the given \p zangle + * + * @param[in] f The field to shift + * @param[in] zangle Toroidal angle (z) + * + */ + const Field3D shiftZ(const Field3D& f, const Field2D& zangle, + const REGION region = RGN_NOX) const; + + /*! + * Shift a 3D field \p f by the given phase \p phs in Z + * + * Calculates FFT in Z, multiplies by the complex phase + * and inverse FFTS. + * + * @param[in] f The field to shift + * @param[in] phs The phase to shift by + * @param[in] y_direction_out The value to set yDirectionType of the result to + */ + const Field3D shiftZ(const Field3D& f, const Tensor& phs, + const YDirectionType y_direction_out, + const REGION region = RGN_NOX) const; + + /*! + * Shift a given 1D array, assumed to be in Z, by the given \p zangle + * + * @param[in] in A 1D array of length \p len + * @param[in] len Length of the in and out arrays + * @param[in] zangle The angle (z coordinate) to shift by + * @param[out] out A 1D array of length \p len, already allocated + */ + void shiftZ(const BoutReal* in, int len, BoutReal zangle, BoutReal* out) const; + + /*! + * Shift a given 1D array, assumed to be in Z, by the given \p zangle + * + * @param[in] in A 1D array of length mesh.LocalNz + * @param[in] phs Phase shift, assumed to have length (mesh.LocalNz/2 + 1) i.e. the + * number of modes + * @param[out] out A 1D array of length mesh.LocalNz, already allocated + */ + void shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* out) const; + + /// Calculate and store the phases for to/from field aligned and for + /// the parallel slices using zShift + void cachePhases(); + + /// Shift a 3D field \p f in Z to all the parallel slices in \p phases + /// + /// @param[in] f The field to shift + /// @param[in] phases The phase and offset information for each parallel slice + /// @return The shifted parallel slices + std::vector shiftZ(const Field3D& f, + const std::vector& phases) const; +}; + #endif // __PARALLELTRANSFORM_H__ diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index a1d88ed0da..0775f2faf3 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -17,8 +17,6 @@ #include -#include "parallel/identity.hxx" -#include "parallel/shiftedmetric.hxx" #include "parallel/fci.hxx" Coordinates::Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2D J, diff --git a/src/mesh/parallel/identity.cxx b/src/mesh/parallel/identity.cxx index df70edbec1..63eaceb6d6 100644 --- a/src/mesh/parallel/identity.cxx +++ b/src/mesh/parallel/identity.cxx @@ -6,9 +6,8 @@ * */ -#include "identity.hxx" - #include "bout/mesh.hxx" +#include "bout/paralleltransform.hxx" void ParallelTransformIdentity::calcParallelSlices(Field3D& f) { f.splitParallelSlices(); diff --git a/src/mesh/parallel/identity.hxx b/src/mesh/parallel/identity.hxx deleted file mode 100644 index 5d8dd5cfae..0000000000 --- a/src/mesh/parallel/identity.hxx +++ /dev/null @@ -1,73 +0,0 @@ -/************************************************************************** - * Parallel derivatives without any transform - * - ************************************************************************** - * Copyright 2015, 2016 B.D.Dudson, D. Dickinson - * - * Contact: Ben Dudson, bd512@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - **************************************************************************/ - -#ifndef __IDENTITYTRANSFORM_H__ -#define __IDENTITYTRANSFORM_H__ - -#include "bout/paralleltransform.hxx" -#include "field3d.hxx" -#include "unused.hxx" - -/*! - * This class implements the simplest form of ParallelTransform - * where the domain is a logically rectangular domain, and - * yup() and ydown() refer to the same field. - */ -class ParallelTransformIdentity : public ParallelTransform { -public: - ParallelTransformIdentity(Mesh& mesh_in) : ParallelTransform(mesh_in) { - // check the coordinate system used for the grid data source - checkInputGrid(); - } - - /*! - * Merges the yup and ydown() fields of f, so that - * f.yup() = f.ydown() = f - */ - void calcParallelSlices(Field3D& f) override; - - /*! - * The field is already aligned in Y, so this - * does nothing - */ - const Field3D toFieldAligned(const Field3D& f, const REGION UNUSED(region)) override { - return f; - } - - /*! - * The field is already aligned in Y, so this - * does nothing - */ - const Field3D fromFieldAligned(const Field3D& f, const REGION UNUSED(region)) override { - return f; - } - - bool canToFromFieldAligned() override { return true; } - -protected: - void checkInputGrid() override; -}; - -#endif // __IDENTITYTRANSFORM_H__ diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 67ddd16cff..09c9cda642 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -6,10 +6,9 @@ * */ -#include "shiftedmetric.hxx" - #include #include +#include "bout/paralleltransform.hxx" #include #include diff --git a/src/mesh/parallel/shiftedmetric.hxx b/src/mesh/parallel/shiftedmetric.hxx deleted file mode 100644 index 41e9da0960..0000000000 --- a/src/mesh/parallel/shiftedmetric.hxx +++ /dev/null @@ -1,172 +0,0 @@ -/************************************************************************** - * Shifted-metric parallel derivatives - * - ************************************************************************** - * Copyright 2015, 2016 B.D.Dudson, D. Dickinson - * - * Contact: Ben Dudson, bd512@york.ac.uk - * - * This file is part of BOUT++. - * - * BOUT++ is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * BOUT++ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with BOUT++. If not, see . - * - **************************************************************************/ - -#ifndef __SHIFTEDMETRIC_H__ -#define __SHIFTEDMETRIC_H__ - -#include "bout/paralleltransform.hxx" - -#include "field2d.hxx" - -/*! - * Shifted metric method - * Each Y location is shifted in Z with respect to its neighbours - * so that the grid is orthogonal in X-Z, but requires interpolation - * to calculate the values of points along field-lines. - * - * In this implementation the interpolation is done using FFTs in Z - */ -class ShiftedMetric : public ParallelTransform { -public: - ShiftedMetric() = delete; - ShiftedMetric(Mesh& mesh, CELL_LOC location, Field2D zShift, BoutReal zlength_in); - - /*! - * Calculates the yup() and ydown() fields of f - * by taking FFTs in Z and applying a phase shift. - */ - void calcParallelSlices(Field3D& f) override; - - /*! - * Uses FFTs and a phase shift to align the grid points - * with the y coordinate (along magnetic field usually). - * - * Note that the returned field will no longer be orthogonal - * in X-Z, and the metric tensor will need to be changed - * if X derivatives are used. - */ - const Field3D toFieldAligned(const Field3D& f, const REGION region = RGN_ALL) override; - - /*! - * Converts a field back to X-Z orthogonal coordinates - * from field aligned coordinates. - */ - const Field3D fromFieldAligned(const Field3D& f, - const REGION region = RGN_ALL) override; - - bool canToFromFieldAligned() override { return true; } - -protected: - void checkInputGrid() override; - -private: - CELL_LOC location{CELL_CENTRE}; - - /// This is the shift in toroidal angle (z) which takes a point from - /// X-Z orthogonal to field-aligned along Y. - Field2D zShift; - - /// Length of the z-domain in radians - BoutReal zlength{0.}; - - int nmodes; - - Tensor toAlignedPhs; ///< Cache of phase shifts for transforming from X-Z - /// orthogonal coordinates to field-aligned coordinates - Tensor fromAlignedPhs; ///< Cache of phase shifts for transforming from - /// field-aligned coordinates to X-Z orthogonal - /// coordinates - - /// Helper POD for parallel slice phase shifts - struct ParallelSlicePhase { - Tensor phase_shift; - int y_offset; - }; - - /// Cache of phase shifts for the parallel slices. Slices are stored - /// in the following order: - /// {+1, ..., +n, -1, ..., -n} - /// slice[i] stores offset i+1 - /// slice[2*i + 1] stores offset -(i+1) - /// where i goes from 0 to (n-1), with n the number of y guard cells - std::vector parallel_slice_phases; - - /*! - * Shift a 2D field in Z. - * Since 2D fields are constant in Z, this has no effect - */ - const Field2D shiftZ(const Field2D& f, const Field2D& UNUSED(zangle), - const REGION UNUSED(region) = RGN_NOX) const { - return f; - }; - - /*! - * Shift a 3D field \p f in Z by the given \p zangle - * - * @param[in] f The field to shift - * @param[in] zangle Toroidal angle (z) - * - */ - const Field3D shiftZ(const Field3D& f, const Field2D& zangle, - const REGION region = RGN_NOX) const; - - /*! - * Shift a 3D field \p f by the given phase \p phs in Z - * - * Calculates FFT in Z, multiplies by the complex phase - * and inverse FFTS. - * - * @param[in] f The field to shift - * @param[in] phs The phase to shift by - * @param[in] y_direction_out The value to set yDirectionType of the result to - */ - const Field3D shiftZ(const Field3D& f, const Tensor& phs, - const YDirectionType y_direction_out, - const REGION region = RGN_NOX) const; - - /*! - * Shift a given 1D array, assumed to be in Z, by the given \p zangle - * - * @param[in] in A 1D array of length \p len - * @param[in] len Length of the in and out arrays - * @param[in] zangle The angle (z coordinate) to shift by - * @param[out] out A 1D array of length \p len, already allocated - */ - void shiftZ(const BoutReal* in, int len, BoutReal zangle, BoutReal* out) const; - - /*! - * Shift a given 1D array, assumed to be in Z, by the given \p zangle - * - * @param[in] in A 1D array of length mesh.LocalNz - * @param[in] phs Phase shift, assumed to have length (mesh.LocalNz/2 + 1) i.e. the - * number of modes - * @param[out] out A 1D array of length mesh.LocalNz, already allocated - */ - void shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* out) const; - - /// Calculate and store the phases for to/from field aligned and for - /// the parallel slices using zShift - void cachePhases(); - - /// Shift a 3D field \p f in Z to all the parallel slices in \p phases - /// - /// @param[in] f The field to shift - /// @param[in] phases The phase and offset information for each parallel slice - /// @return The shifted parallel slices - std::vector shiftZ(const Field3D& f, - const std::vector& phases) const; -}; - -#endif // __SHIFTEDMETRIC_H__ diff --git a/tests/integrated/test-yupdown/test_yupdown.cxx b/tests/integrated/test-yupdown/test_yupdown.cxx index 805545b766..57d4b9e41a 100644 --- a/tests/integrated/test-yupdown/test_yupdown.cxx +++ b/tests/integrated/test-yupdown/test_yupdown.cxx @@ -1,7 +1,6 @@ #include -#include <../src/mesh/parallel/shiftedmetric.hxx> - +#include #include // Y derivative using yup() and ydown() fields diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index b804e2bb41..d18834ff4d 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -2,7 +2,6 @@ #include "fft.hxx" #include "test_extras.hxx" -#include "../src/mesh/parallel/shiftedmetric.hxx" // The unit tests use the global mesh using namespace bout::globals; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 9a0d05e576..9f535c225c 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -12,7 +12,6 @@ #include "bout/coordinates.hxx" #include "field3d.hxx" #include "unused.hxx" -#include "../src/mesh/parallel/identity.hxx" static constexpr BoutReal BoutRealTolerance{1e-15}; // FFTs have a slightly looser tolerance than other functions From 5cf77f6d4ce1a5805690bace957723775dbe7ab4 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 16:42:02 +0000 Subject: [PATCH 1016/1783] Default argument 'options = nullptr' for Coordinates constructor --- include/bout/coordinates.hxx | 2 +- src/mesh/coordinates.cxx | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index b514873461..1680f6a780 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -50,7 +50,7 @@ class Mesh; class Coordinates { public: /// Standard constructor from input - Coordinates(Mesh *mesh, Options* options); + Coordinates(Mesh *mesh, Options* options = nullptr); /// Constructor interpolating from another Coordinates object Coordinates(Mesh *mesh, Options* options, const CELL_LOC loc, const Coordinates* coords_in); diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 0775f2faf3..3e09480b7c 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -50,6 +50,10 @@ Coordinates::Coordinates(Mesh *mesh, Options* options) G3_23(mesh), G1(mesh), G2(mesh), G3(mesh), ShiftTorsion(mesh), IntShiftTorsion(mesh), localmesh(mesh), location(CELL_CENTRE) { + if (options == nullptr) { + options = Options::getRoot()->getSection("mesh"); + } + if (mesh->get(dx, "dx")) { output_warn.write("\tWARNING: differencing quantity 'dx' not found. Set to 1.0\n"); dx = 1.0; From 24dc303d0a8c1c8a3c3191853d98ac0d2bea8df9 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 16:58:09 +0000 Subject: [PATCH 1017/1783] Can remove checks for Field3D in index_derivs_interface.hxx The affected branches all support Field2D now. Also make some intermediate bool variables const. --- include/bout/index_derivs_interface.hxx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 3c68ab4e34..39b52cc112 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -199,7 +199,7 @@ template T DDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - if (std::is_base_of::value && f.hasParallelSlices()) { + if (f.hasParallelSlices()) { return standardDerivative(f, outloc, method, region); } else { @@ -214,7 +214,7 @@ template T D2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - if (std::is_base_of::value && f.hasParallelSlices()) { + if (f.hasParallelSlices()) { return standardDerivative( f, outloc, method, region); } else { @@ -229,7 +229,7 @@ template T D4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - if (std::is_base_of::value && f.hasParallelSlices()) { + if (f.hasParallelSlices()) { return standardDerivative( f, outloc, method, region); } else { @@ -301,8 +301,8 @@ template T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - bool fHasParallelSlices = (std::is_base_of::value && f.hasParallelSlices()); - bool velHasParallelSlices = (std::is_base_of::value && vel.hasParallelSlices()); + const bool fHasParallelSlices = (f.hasParallelSlices()); + const bool velHasParallelSlices = (vel.hasParallelSlices()); if (fHasParallelSlices && velHasParallelSlices) { return flowDerivative(vel, f, outloc, method, region); @@ -319,8 +319,8 @@ template T FDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { AUTO_TRACE(); - bool fHasParallelSlices = (std::is_base_of::value && f.hasParallelSlices()); - bool velHasParallelSlices = (std::is_base_of::value && vel.hasParallelSlices()); + const bool fHasParallelSlices = (f.hasParallelSlices()); + const bool velHasParallelSlices = (vel.hasParallelSlices()); if (fHasParallelSlices && velHasParallelSlices) { return flowDerivative(vel, f, outloc, method, region); From 867c5af5b70a2318d5ec6a35b82b256840d41248 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 17:04:30 +0000 Subject: [PATCH 1018/1783] Add index arguments to Field2D::yup() and Field2D::ydown() These are not used, since these methods for Field2D just return the field itself, but make the interface identical to the Field3D version, which is useful for template functions. --- include/field2d.hxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/field2d.hxx b/include/field2d.hxx index b08cff49bd..03ddb6dd79 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -124,17 +124,17 @@ class Field2D : public Field, public FieldData { return true; } - Field2D& yup() { + Field2D& yup(std::vector::size_type UNUSED(index) = 0) { return *this; } - const Field2D& yup() const { + const Field2D& yup(std::vector::size_type UNUSED(index) = 0) const { return *this; } - Field2D& ydown() { + Field2D& ydown(std::vector::size_type UNUSED(index) = 0) { return *this; } - const Field2D& ydown() const { + const Field2D& ydown(std::vector::size_type UNUSED(index) = 0) const { return *this; } From b1b98e62a9a75dc9b9e8144f98a1f22ffb43f864 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 17:51:36 +0000 Subject: [PATCH 1019/1783] Keep but deprecate *YupYdown methods Keep old names of methods, having them call the replacement versions, but mark as deprecated. Use [[gnu::deprecated(message)]] to mark methods as deprecated, since this allows us to give a helpful error message saying what to use instead. Do this as well for some other DEPRECATED ParallelTransform-related methods. --- include/bout/mesh.hxx | 29 +++++++++++++++++------------ include/bout/paralleltransform.hxx | 10 ++++++++++ include/field2d.hxx | 5 +++++ include/field3d.hxx | 16 ++++++++++++++++ 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 6f9c7ec430..a076c1d7b8 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -712,40 +712,45 @@ class Mesh { return bout::derivatives::index::FDDZ(vel, f, outloc, method, region); } - const DEPRECATED(Field3D toFieldAligned(const Field3D &f, - const REGION region = RGN_ALL)) { + [[gnu::deprecated("Please use free function toFieldAligned instead")]] + const Field3D toFieldAligned(const Field3D &f, const REGION region = RGN_ALL) { return ::toFieldAligned(f, region); } - const DEPRECATED(Field3D fromFieldAligned(const Field3D &f, - const REGION region = RGN_ALL)) { + [[gnu::deprecated("Please use free function fromFieldAligned instead")]] + const Field3D fromFieldAligned(const Field3D &f, const REGION region = RGN_ALL) { return ::fromFieldAligned(f, region); } - const DEPRECATED(Field2D toFieldAligned(const Field2D &f, - const REGION region = RGN_ALL)) { + [[gnu::deprecated("Please use free function toFieldAligned instead")]] + const Field2D toFieldAligned(const Field2D &f, const REGION region = RGN_ALL) { return ::toFieldAligned(f, region); } - const DEPRECATED(Field2D fromFieldAligned(const Field2D &f, - const REGION region = RGN_ALL)) { + [[gnu::deprecated("Please use free function fromFieldAligned instead")]] + const Field2D fromFieldAligned(const Field2D &f, const REGION region = RGN_ALL) { return ::fromFieldAligned(f, region); } - bool DEPRECATED(canToFromFieldAligned()) { + [[gnu::deprecated("Please use " + "Coordinates::getParallelTransform().canToFromFieldAligned instead")]] + bool canToFromFieldAligned() { return getCoordinates()->getParallelTransform().canToFromFieldAligned(); } - void DEPRECATED(setParallelTransform(std::unique_ptr pt)) { + [[gnu::deprecated("Please use Coordinates::setParallelTransform instead")]] + void setParallelTransform(std::unique_ptr pt) { getCoordinates()->setParallelTransform(std::move(pt)); } - void DEPRECATED(setParallelTransform()) { + [[gnu::deprecated("This call is now unnecessary")]] + void setParallelTransform() { // The ParallelTransform is set from options in the Coordinates // constructor, so this method doesn't need to do anything } - ParallelTransform& DEPRECATED(getParallelTransform()) { + [[gnu::deprecated("Please use Coordinates::getParallelTransform instead")]] + ParallelTransform& getParallelTransform() { return getCoordinates()->getParallelTransform(); } diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 2cb727197e..dd15a1f4d8 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -28,11 +28,21 @@ public: /// Given a 3D field, calculate and set the Y up down fields virtual void calcParallelSlices(Field3D &f) = 0; + [[gnu::deprecated("Please use ParallelTransform::calcParallelSlices instead")]] + void calcYupYdown(Field3D& f) { + calcParallelSlices(f); + } + /// Calculate Yup and Ydown fields by integrating over mapped points /// This should be used for parallel divergence operators virtual void integrateParallelSlices(Field3D &f) { return calcParallelSlices(f); } + + [[gnu::deprecated("Please use ParallelTransform::integrateParallelSlices instead")]] + void integrateYupYdown(Field3D& f) { + integrateParallelSlices(f); + } /// Convert a 3D field into field-aligned coordinates /// so that the y index is along the magnetic field diff --git a/include/field2d.hxx b/include/field2d.hxx index 03ddb6dd79..ebf7909214 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -123,6 +123,11 @@ class Field2D : public Field, public FieldData { bool hasParallelSlices() const { return true; } + + [[gnu::deprecated("Please use Field2D::hasParallelSlices instead")]] + bool hasYupYdown() const { + return hasParallelSlices(); + } Field2D& yup(std::vector::size_type UNUSED(index) = 0) { return *this; diff --git a/include/field3d.hxx b/include/field3d.hxx index a8357e2707..250fe1041f 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -235,16 +235,32 @@ class Field3D : public Field, public FieldData { */ void splitParallelSlices(); + [[gnu::deprecated("Please use Field3D::splitParallelSlices instead")]] + void splitYupYdown() { + splitParallelSlices(); + } + /*! * Clear the parallel slices, yup and ydown */ void clearParallelSlices(); + [[gnu::deprecated("Please use Field3D::clearParallelSlices instead")]] + void mergeYupYdown() { + clearParallelSlices(); + } + /// Check if this field has yup and ydown fields bool hasParallelSlices() const { return !yup_fields.empty() and !ydown_fields.empty(); } + [[gnu::deprecated("Please use Field3D::hasParallelSlices instead")]] + bool hasYupYdown() const { + return hasParallelSlices(); + } + + /// Check if this field has yup and ydown fields /// Return reference to yup field Field3D &yup(std::vector::size_type index = 0) { ASSERT2(index < yup_fields.size()); From dd39c1a8f44185b51eab2bc64dc6819d96ebe09d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 18:06:36 +0000 Subject: [PATCH 1020/1783] Tidy up getting 'fci_zperiodic' in Coordinates::setParallelTransform --- src/mesh/coordinates.cxx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 3e09480b7c..e353f114d7 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -715,10 +715,8 @@ void Coordinates::setParallelTransform(Options* options) { throw BoutException("FCITransform is not available on staggered grids."); } - Options *fci_options = Options::getRoot()->getSection("fci"); // Flux Coordinate Independent method - bool fci_zperiodic; - fci_options->get("z_periodic", fci_zperiodic, true); + const bool fci_zperiodic = Options::root()["fci"]["z_periodic"].withDefault(true); transform = bout::utils::make_unique(*localmesh, fci_zperiodic); } else { From b844be1695c020e5dee1e6e62797980933e9d10d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 18:07:43 +0000 Subject: [PATCH 1021/1783] Use Field3D::calcParallelSlices method to tidy up test_smooth.cxx --- tests/integrated/test-smooth/test_smooth.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integrated/test-smooth/test_smooth.cxx b/tests/integrated/test-smooth/test_smooth.cxx index 6c8c52e635..c6584e01c7 100644 --- a/tests/integrated/test-smooth/test_smooth.cxx +++ b/tests/integrated/test-smooth/test_smooth.cxx @@ -17,7 +17,7 @@ int main(int argc, char **argv) { Field2D input2d = f.create2D("1 + sin(2*y)"); Field3D input3d = f.create3D("gauss(x-0.5,0.2)*gauss(y-pi)*sin(3*y - z)"); - input3d.getCoordinates()->getParallelTransform().calcParallelSlices(input3d); + input3d.calcParallelSlices(); SAVE_ONCE2(input2d, input3d); From b168f82efba9c5791f63ab2df535ae7754b1f7b5 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 18:08:07 +0000 Subject: [PATCH 1022/1783] Make Coordinates objects once in FakeMeshFixture Instead of using the Coordinates constructor each time setCoordinates is called. --- tests/unit/field/test_field_factory.cxx | 18 ++++++------------ tests/unit/field/test_initialprofiles.cxx | 6 +----- tests/unit/mesh/data/test_gridfromoptions.cxx | 6 +----- tests/unit/mesh/test_interpolation.cxx | 8 +++----- tests/unit/test_extras.hxx | 16 ++++++++++++++++ 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index b4521a7e99..443a4ca830 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -26,22 +26,16 @@ class FieldFactoryCreationTest : public FakeMeshFixture { FieldFactoryCreationTest() : FakeMeshFixture{}, factory{mesh} { // We need Coordinates so a parallel transform is available as // FieldFactory::create3D wants to un-field-align the result - static_cast(mesh)->setCoordinates(std::make_shared( - mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false)); + static_cast(mesh)->setCoordinates(test_coords); mesh->getCoordinates()->setParallelTransform( bout::utils::make_unique(*mesh)); - for (const auto& location : std::list{CELL_CENTRE, CELL_XLOW, CELL_YLOW, CELL_ZLOW}) { - static_cast(mesh_staggered)->setCoordinates(std::make_shared( - mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false), - location); + for (const auto& location + : std::list{CELL_CENTRE, CELL_XLOW, CELL_YLOW, CELL_ZLOW}) { + + static_cast(mesh_staggered)->setCoordinates(test_coords_staggered, + location); mesh_staggered->getCoordinates(location)->setParallelTransform( bout::utils::make_unique(*mesh_staggered)); diff --git a/tests/unit/field/test_initialprofiles.cxx b/tests/unit/field/test_initialprofiles.cxx index b383c8aeb8..4f8f8ee6a2 100644 --- a/tests/unit/field/test_initialprofiles.cxx +++ b/tests/unit/field/test_initialprofiles.cxx @@ -23,11 +23,7 @@ class InitialProfileTest : public FakeMeshFixture { InitialProfileTest() : FakeMeshFixture() { // We need Coordinates so a parallel transform is available as // FieldFactory::create3D wants to un-field-align the result - static_cast(mesh)->setCoordinates(std::make_shared( - mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false)); + static_cast(mesh)->setCoordinates(test_coords); mesh->getCoordinates()->setParallelTransform( bout::utils::make_unique(*mesh)); diff --git a/tests/unit/mesh/data/test_gridfromoptions.cxx b/tests/unit/mesh/data/test_gridfromoptions.cxx index 467bda5100..11d15d5c2c 100644 --- a/tests/unit/mesh/data/test_gridfromoptions.cxx +++ b/tests/unit/mesh/data/test_gridfromoptions.cxx @@ -26,11 +26,7 @@ class GridFromOptionsTest : public FakeMeshFixture { GridFromOptionsTest() : FakeMeshFixture(), options(), griddata(&options) { // We need Coordinates so a parallel transform is available as // FieldFactory::create3D wants to un-field-align the result - static_cast(mesh)->setCoordinates(std::make_shared( - mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false)); + static_cast(mesh)->setCoordinates(test_coords); mesh->getCoordinates()->setParallelTransform( bout::utils::make_unique(*mesh)); diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index 3d2a887f6e..89750d95f6 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -66,13 +66,11 @@ class Field3DInterpToTest : public ::testing::Test { mesh->createDefaultRegions(); output_info.enable(); - static_cast(mesh)->setCoordinates(nullptr, CELL_XLOW); - static_cast(mesh)->setCoordinates(nullptr, CELL_YLOW); - static_cast(mesh)->setCoordinates(nullptr, CELL_ZLOW); - // We need Coordinates so a parallel transform is available as // FieldFactory::create3D wants to un-field-align the result - for (const auto& location : std::list{CELL_CENTRE, CELL_XLOW, CELL_YLOW, CELL_ZLOW}) { + for (const auto& location + : std::list{CELL_CENTRE, CELL_XLOW, CELL_YLOW, CELL_ZLOW}) { + static_cast(mesh)->setCoordinates(std::make_shared( mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 9f535c225c..75fa039edc 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -286,6 +286,19 @@ public: output_info.disable(); mesh_staggered->createDefaultRegions(); output_info.enable(); + + test_coords = std::make_shared( + bout::globals::mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, + Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + false); + test_coords_staggered = std::make_shared( + mesh_staggered, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, + Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + false); } virtual ~FakeMeshFixture() { @@ -300,6 +313,9 @@ public: static constexpr int nz = 7; Mesh* mesh_staggered = nullptr; + + std::shared_ptr test_coords{nullptr}; + std::shared_ptr test_coords_staggered{nullptr}; }; #endif // TEST_EXTRAS_H__ From 089a43c1ceea93ea11875da2e88b153754188ad2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 18:28:01 +0000 Subject: [PATCH 1023/1783] hasBranchCutLower, hasBranchCutUpper return std::pair --- include/bout/mesh.hxx | 18 ++++++++++-------- src/mesh/coordinates.cxx | 11 ++++++----- src/mesh/impls/bout/boutmesh.cxx | 16 ++++++---------- src/mesh/impls/bout/boutmesh.hxx | 14 ++++++++------ tests/unit/test_extras.hxx | 10 ++++------ 5 files changed, 34 insertions(+), 35 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index a076c1d7b8..c996bdce79 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -331,19 +331,21 @@ class Mesh { /// \param[out] ts The Twist-Shift angle if periodic virtual bool periodicY(int jx, BoutReal &ts) const = 0; - /// Is there a branch cut at this processor's lower boundary? + /// Is there a branch cut at this processor's lower y-boundary? /// /// @param[in] jx The local (on this processor) index in X - /// @param[out] global_shift The total zShift for a 2pi poloidal circuit, - /// non-zero if there is a branch-cut - virtual bool hasBranchCutLower(int jx, BoutReal& global_shift) const = 0; + /// @returns pair - bool is true if there is a branch cut, + /// BoutReal gives the total zShift for a 2pi + /// poloidal circuit if there is a branch cut + virtual std::pair hasBranchCutLower(int jx) const = 0; - /// Is there a branch cut at this processor's upper boundary? + /// Is there a branch cut at this processor's upper y-boundary? /// /// @param[in] jx The local (on this processor) index in X - /// @param[out] global_shift The total zShift for a 2pi poloidal circuit, - /// non-zero if there is a branch-cut - virtual bool hasBranchCutUpper(int jx, BoutReal& global_shift) const = 0; + /// @returns pair - bool is true if there is a branch cut, + /// BoutReal gives the total zShift for a 2pi + /// poloidal circuit if there is a branch cut + virtual std::pair hasBranchCutUpper(int jx) const = 0; virtual int ySize(int jx) const; ///< The number of points in Y at fixed X index \p jx diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index e353f114d7..3540691101 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -693,15 +693,16 @@ void Coordinates::setParallelTransform(Options* options) { // Correct guard cells for discontinuity of zShift at poloidal branch cut for (int x = 0; x < localmesh->LocalNx; x++) { - BoutReal global_shift = 0.; - if (localmesh->hasBranchCutLower(x, global_shift)) { + const auto lower = localmesh->hasBranchCutLower(x); + if (lower.first) { for (int y = 0; y < localmesh->ystart; y++) { - zShift(x, y) -= global_shift; + zShift(x, y) -= lower.second; } } - if (localmesh->hasBranchCutUpper(x, global_shift)) { + const auto upper = localmesh->hasBranchCutUpper(x); + if (upper.first) { for (int y = localmesh->yend + 1; y < localmesh->LocalNy; y++) { - zShift(x, y) += global_shift; + zShift(x, y) += upper.second; } } } diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 6413a1aed2..04c61cde59 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2026,7 +2026,7 @@ bool BoutMesh::periodicY(int jx, BoutReal &ts) const { return false; } -bool BoutMesh::hasBranchCutLower(int jx, BoutReal& global_shift) const { +std::pair BoutMesh::hasBranchCutLower(int jx) const { if ( (TS_down_in and DDATA_INDEST != -1 and jx < DDATA_XSPLIT) or (TS_down_out and DDATA_OUTDEST != -1 and jx >= DDATA_XSPLIT) ) { // this processor has branch cut at lower boundary for jx @@ -2034,16 +2034,14 @@ bool BoutMesh::hasBranchCutLower(int jx, BoutReal& global_shift) const { // This function should only be called during initialization, so always check throw BoutException("BoutMesh failed to read ShiftAngle from the grid"); } - global_shift = ShiftAngle[jx]; - return true; + return std::make_pair(true, ShiftAngle[jx]); } - global_shift = 0.; - return false; + return std::make_pair(false, 0.); } -bool BoutMesh::hasBranchCutUpper(int jx, BoutReal& global_shift) const { +std::pair BoutMesh::hasBranchCutUpper(int jx) const { if ( (TS_up_in and UDATA_INDEST != -1 and jx < UDATA_XSPLIT) or (TS_up_out and UDATA_OUTDEST != -1 and jx >= UDATA_XSPLIT) ) { // this processor has branch cut at upper boundary for jx @@ -2051,12 +2049,10 @@ bool BoutMesh::hasBranchCutUpper(int jx, BoutReal& global_shift) const { // This function should only be called during initialization, so always check throw BoutException("BoutMesh failed to read ShiftAngle from the grid"); } - global_shift = ShiftAngle[jx]; - return true; + return std::make_pair(true, ShiftAngle[jx]); } - global_shift = 0.; - return false; + return std::make_pair(false, 0.); } int BoutMesh::ySize(int xpos) const { diff --git a/src/mesh/impls/bout/boutmesh.hxx b/src/mesh/impls/bout/boutmesh.hxx index 96f97a9ee7..251ac627de 100644 --- a/src/mesh/impls/bout/boutmesh.hxx +++ b/src/mesh/impls/bout/boutmesh.hxx @@ -108,16 +108,18 @@ class BoutMesh : public Mesh { /// Is there a branch cut at this processor's lower boundary? /// /// @param[in] jx The local (on this processor) index in X - /// @param[out] global_shift The total zShift for a 2pi poloidal circuit, - /// non-zero if there is a branch-cut - bool hasBranchCutLower(int jx, BoutReal& global_shift) const override; + /// @returns pair - bool is true if there is a branch cut, + /// BoutReal gives the total zShift for a 2pi + /// poloidal circuit if there is a branch cut + std::pair hasBranchCutLower(int jx) const override; /// Is there a branch cut at this processor's upper boundary? /// /// @param[in] jx The local (on this processor) index in X - /// @param[out] global_shift The total zShift for a 2pi poloidal circuit, - /// non-zero if there is a branch-cut - bool hasBranchCutUpper(int jx, BoutReal& global_shift) const override; + /// @returns pair - bool is true if there is a branch cut, + /// BoutReal gives the total zShift for a 2pi + /// poloidal circuit if there is a branch cut + std::pair hasBranchCutUpper(int jx) const override; int ySize(int jx) const; ///< The number of points in Y at fixed X index \p jx diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 75fa039edc..9a98d923ad 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -188,13 +188,11 @@ public: MPI_Comm getYcomm(int UNUSED(jx)) const { return MPI_COMM_NULL; } bool periodicY(int UNUSED(jx)) const { return true; } bool periodicY(int UNUSED(jx), BoutReal &UNUSED(ts)) const { return true; } - bool hasBranchCutLower(int UNUSED(jx), BoutReal& global_shift) const { - global_shift = 0.; - return false; + std::pair hasBranchCutLower(int UNUSED(jx)) const { + return std::make_pair(false, 0.); } - bool hasBranchCutUpper(int UNUSED(jx), BoutReal& global_shift) const { - global_shift = 0.; - return false; + std::pair hasBranchCutUpper(int UNUSED(jx)) const { + return std::make_pair(false, 0.); } bool firstY() const { return true; } bool lastY() const { return true; } From 8ad17579f3c609828159653627d548c75b01f2ec Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 22:01:16 +0000 Subject: [PATCH 1024/1783] Change variable names for output from staggered Coordinates Previously, the variables in Coordinates would be output with names that did not change if the Coordinates object was at a staggered location. This could have resulted in variables being over-written if Coordinates::outputVars was called on two different Coordinates objects. This commit adds a suffix "_"+toString(location) if location is not CELL_CENTRE. --- src/mesh/coordinates.cxx | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index b39816cf4e..2b6da37af6 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -307,25 +307,27 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor } void Coordinates::outputVars(Datafile &file) { - file.add(dx, "dx", false); - file.add(dy, "dy", false); - file.add(dz, "dz", false); - - file.add(g11, "g11", false); - file.add(g22, "g22", false); - file.add(g33, "g33", false); - file.add(g12, "g12", false); - file.add(g13, "g13", false); - file.add(g23, "g23", false); - - file.add(g_11, "g_11", false); - file.add(g_22, "g_22", false); - file.add(g_33, "g_33", false); - file.add(g_12, "g_12", false); - file.add(g_13, "g_13", false); - file.add(g_23, "g_23", false); - - file.add(J, "J", false); + const std::string loc_string = (location == CELL_CENTRE) ? "" : "_"+toString(location); + + file.addOnce(dx, "dx" + loc_string); + file.addOnce(dy, "dy" + loc_string); + file.addOnce(dz, "dz" + loc_string); + + file.addOnce(g11, "g11" + loc_string); + file.addOnce(g22, "g22" + loc_string); + file.addOnce(g33, "g33" + loc_string); + file.addOnce(g12, "g12" + loc_string); + file.addOnce(g13, "g13" + loc_string); + file.addOnce(g23, "g23" + loc_string); + + file.addOnce(g_11, "g_11" + loc_string); + file.addOnce(g_22, "g_22" + loc_string); + file.addOnce(g_33, "g_33" + loc_string); + file.addOnce(g_12, "g_12" + loc_string); + file.addOnce(g_13, "g_13" + loc_string); + file.addOnce(g_23, "g_23" + loc_string); + + file.addOnce(J, "J" + loc_string); } int Coordinates::geometry() { From 42dd70743f12cd5b69c0969014eb825e562fb72e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 13 Mar 2019 12:50:09 +0000 Subject: [PATCH 1025/1783] Make check for all covariant metric components clearer When checking in the Coordinates constructor that if any covariant component is provided in the grid file, then all of them should be, replace long conditionals (for 6 metric components) with std::any_of and std::all_of. --- src/mesh/coordinates.cxx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 98baa76e27..f6229a4423 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -327,14 +327,16 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor getAtLoc(mesh, g23, "g23", suffix, location, 0.0); /// Find covariant metric components + auto covariant_component_names = {"g_11", "g_22", "g_33", "g_12", "g_13", "g_23"}; + auto source_has_component = [&suffix, &mesh] (const std::string& name) { + return mesh->sourceHasVar(name + suffix); + }; // Check if any of the components are present - if (mesh->sourceHasVar("g_11"+suffix) or mesh->sourceHasVar("g_22"+suffix) or - mesh->sourceHasVar("g_33"+suffix) or mesh->sourceHasVar("g_12"+suffix) or - mesh->sourceHasVar("g_13"+suffix) or mesh->sourceHasVar("g_23"+suffix)) { + if (std::any_of(begin(covariant_component_names), end(covariant_component_names), + source_has_component)) { // Check that all components are present - if (mesh->sourceHasVar("g_11"+suffix) and mesh->sourceHasVar("g_22"+suffix) and - mesh->sourceHasVar("g_33"+suffix) and mesh->sourceHasVar("g_12"+suffix) and - mesh->sourceHasVar("g_13"+suffix) and mesh->sourceHasVar("g_23"+suffix)) { + if (std::all_of(begin(covariant_component_names), end(covariant_component_names), + source_has_component)) { getAtLoc(mesh, g_11, "g_11", suffix, location); getAtLoc(mesh, g_22, "g_22", suffix, location); From 1b351f973d51ff9c247276d11c91bbb943b547dc Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 15:43:15 +0000 Subject: [PATCH 1026/1783] Resolve circular dependency by forward-declaring Options --- include/datafile.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/datafile.hxx b/include/datafile.hxx index 9163498ae3..a784876695 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -15,7 +15,6 @@ class Datafile; #define __DATAFILE_H__ #include "bout_types.hxx" -#include "options.hxx" #include "bout/macro_for_each.hxx" #include "dataformat.hxx" @@ -27,6 +26,7 @@ class Mesh; class Field; class Field2D; class Field3D; +class Options; class Vector2D; class Vector3D; From 38fa20ab32089e19e43cc2c5d12e6e746f1253b5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 15:43:54 +0000 Subject: [PATCH 1027/1783] Add new ctor arguments for Field to new Field2D/3D ctors --- include/field2d.hxx | 6 ++++-- include/field3d.hxx | 4 +++- src/field/field2d.cxx | 6 ++++-- src/field/field3d.cxx | 8 +++++--- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/field2d.hxx b/include/field2d.hxx index bbb7b8b7dd..78ff610715 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -87,8 +87,10 @@ class Field2D : public Field, public FieldData { Field2D(BoutReal val, Mesh *localmesh = nullptr); /// Constructor from Array and Mesh - Field2D(Array data, Mesh *localmesh, CELL_LOC location = CELL_CENTRE); - + Field2D(Array data, Mesh* localmesh, CELL_LOC location = CELL_CENTRE, + DirectionTypes directions_in = {YDirectionType::Standard, + ZDirectionType::Average}); + /*! * Destructor */ diff --git a/include/field3d.hxx b/include/field3d.hxx index 634908473f..7257f68f41 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -186,7 +186,9 @@ class Field3D : public Field, public FieldData { /// Constructor from value Field3D(BoutReal val, Mesh *localmesh = nullptr); /// Constructor from Array and Mesh - Field3D(Array data, Mesh *localmesh, CELL_LOC location = CELL_CENTRE); + Field3D(Array data, Mesh* localmesh, CELL_LOC location = CELL_CENTRE, + DirectionTypes directions_in = {YDirectionType::Standard, + ZDirectionType::Standard}); /// Destructor ~Field3D() override; diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index affc71f613..d0d85a9d64 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -80,10 +80,12 @@ Field2D::Field2D(BoutReal val, Mesh* localmesh) : Field2D(localmesh) { *this = val; } -Field2D::Field2D(Array data, Mesh *localmesh, CELL_LOC datalocation) : Field(localmesh), data(data) { +Field2D::Field2D(Array data, Mesh* localmesh, CELL_LOC datalocation, + DirectionTypes directions_in) + : Field(localmesh, datalocation, directions_in), data(data) { ASSERT1(fieldmesh != nullptr); - + nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 42cf08d626..39f2bc3a55 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -92,15 +92,17 @@ Field3D::Field3D(const BoutReal val, Mesh* localmesh) : Field3D(localmesh) { *this = val; } -Field3D::Field3D(Array data, Mesh *localmesh, CELL_LOC datalocation) : Field(localmesh), data(data) { +Field3D::Field3D(Array data, Mesh* localmesh, CELL_LOC datalocation, + DirectionTypes directions_in) + : Field(localmesh, datalocation, directions_in), data(data) { TRACE("Field3D: Copy constructor from Array and Mesh"); nx = fieldmesh->LocalNx; ny = fieldmesh->LocalNy; nz = fieldmesh->LocalNz; - ASSERT1( data.size() == nx * ny * nz ); - + ASSERT1(data.size() == nx * ny * nz); + setLocation(datalocation); } From 2cb550b40f5dfad65659d3e49dbf09c5c6c56005 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 15:46:41 +0000 Subject: [PATCH 1028/1783] Use bout::globals::mesh in new tests --- tests/unit/sys/test_options_fields.cxx | 14 +++++++++----- tests/unit/sys/test_options_netcdf.cxx | 12 +++++++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/tests/unit/sys/test_options_fields.cxx b/tests/unit/sys/test_options_fields.cxx index c1b47eeb6e..9fcf55ec7a 100644 --- a/tests/unit/sys/test_options_fields.cxx +++ b/tests/unit/sys/test_options_fields.cxx @@ -8,7 +8,11 @@ #include "test_extras.hxx" /// Global mesh -extern Mesh *mesh; +namespace bout { +namespace globals { +extern Mesh* mesh; +} +} // namespace bout // Reuse the "standard" fixture for FakeMesh using OptionsFieldTest = FakeMeshFixture; @@ -71,7 +75,7 @@ TEST_F(OptionsFieldTest, RetrieveField2DfromField3D) { Field3D field = 1.2; options = field; - EXPECT_THROW(Field2D value = options.as(mesh), BoutException); + EXPECT_THROW(Field2D value = options.as(bout::globals::mesh), BoutException); } TEST_F(OptionsFieldTest, RetrieveStringfromField3D) { @@ -94,7 +98,7 @@ TEST_F(OptionsFieldTest, RetrieveField3DfromString) { Options options; options = "1 + 2"; - Field3D other = options.as(mesh); + Field3D other = options.as(bout::globals::mesh); EXPECT_DOUBLE_EQ(other(0,1,0), 3.0); EXPECT_DOUBLE_EQ(other(0,0,1), 3.0); @@ -104,7 +108,7 @@ TEST_F(OptionsFieldTest, RetrieveField2DfromString) { Options options; options = "1 + 2"; - Field2D other = options.as(mesh); + Field2D other = options.as(bout::globals::mesh); EXPECT_DOUBLE_EQ(other(0,1,0), 3.0); EXPECT_DOUBLE_EQ(other(0,0,1), 3.0); @@ -114,6 +118,6 @@ TEST_F(OptionsFieldTest, RetrieveField2DfromBadString) { Options options; options = "1 + "; - EXPECT_THROW(Field2D other = options.as(mesh), ParseException); + EXPECT_THROW(Field2D other = options.as(bout::globals::mesh), ParseException); } diff --git a/tests/unit/sys/test_options_netcdf.cxx b/tests/unit/sys/test_options_netcdf.cxx index e5c3ce00c0..bf117dd425 100644 --- a/tests/unit/sys/test_options_netcdf.cxx +++ b/tests/unit/sys/test_options_netcdf.cxx @@ -10,13 +10,15 @@ #include "options_netcdf.hxx" /// Global mesh -extern Mesh *mesh; +namespace bout { +namespace globals { +extern Mesh* mesh; +} +} // namespace bout // Reuse the "standard" fixture for FakeMesh using OptionsNetCDFTest = FakeMeshFixture; - - TEST_F(OptionsNetCDFTest, ReadWriteInt) { // Temporary file OptionsNetCDF file(std::tmpnam(nullptr)); @@ -66,7 +68,7 @@ TEST_F(OptionsNetCDFTest, ReadWriteField2D) { // Read file Options data = OptionsNetCDF(filename).read(); - Field2D value = data["test"].as(mesh); + Field2D value = data["test"].as(bout::globals::mesh); EXPECT_DOUBLE_EQ(value(0,1), 1.0); EXPECT_DOUBLE_EQ(value(1,0), 1.0); @@ -86,7 +88,7 @@ TEST_F(OptionsNetCDFTest, ReadWriteField3D) { // Read file Options data = OptionsNetCDF(filename).read(); - Field3D value = data["test"].as(mesh); + Field3D value = data["test"].as(bout::globals::mesh); EXPECT_DOUBLE_EQ(value(0,1,0), 2.4); EXPECT_DOUBLE_EQ(value(1,0,1), 2.4); From 2bbcafed9d6af53ef4ec0d96b79c3e98aec54426 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 15:47:18 +0000 Subject: [PATCH 1029/1783] Replace uses of deprecated CELL_LOC_STRING with toString --- src/sys/options/options_netcdf.cxx | 4 ++-- tests/unit/sys/test_options_netcdf.cxx | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index c1caa3bba4..fc7c61d915 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -269,7 +269,7 @@ void NcPutVarVisitor::operator()(const Field2D& value) { // Pointer to data. Assumed to be contiguous array var.putVar(&value(0, 0)); // Set cell location attribute - var.putAtt("cell_location", CELL_LOC_STRING(value.getLocation())); + var.putAtt("cell_location", toString(value.getLocation())); } /// In addition to writing the data, set the "cell_location" attribute @@ -279,7 +279,7 @@ void NcPutVarVisitor::operator()(const Field3D& value) { var.putVar(&value(0, 0, 0)); // Set cell location attribute - var.putAtt("cell_location", CELL_LOC_STRING(value.getLocation())); + var.putAtt("cell_location", toString(value.getLocation())); } /// Visit a variant type, and put the data into a NcVar diff --git a/tests/unit/sys/test_options_netcdf.cxx b/tests/unit/sys/test_options_netcdf.cxx index bf117dd425..f4cc629eec 100644 --- a/tests/unit/sys/test_options_netcdf.cxx +++ b/tests/unit/sys/test_options_netcdf.cxx @@ -176,7 +176,7 @@ TEST_F(OptionsNetCDFTest, Field2DWriteCellCentre) { // Read file Options data = OptionsNetCDF(filename).read(); - EXPECT_EQ(data["f2d"].attributes["cell_location"].as(), CELL_LOC_STRING(CELL_CENTRE)); + EXPECT_EQ(data["f2d"].attributes["cell_location"].as(), toString(CELL_CENTRE)); } TEST_F(OptionsNetCDFTest, Field2DWriteCellYLow) { @@ -199,7 +199,7 @@ TEST_F(OptionsNetCDFTest, Field2DWriteCellYLow) { // Read file Options data = OptionsNetCDF(filename).read(); - EXPECT_EQ(data["f2d"].attributes["cell_location"].as(), CELL_LOC_STRING(CELL_YLOW)); + EXPECT_EQ(data["f2d"].attributes["cell_location"].as(), toString(CELL_YLOW)); } TEST_F(OptionsNetCDFTest, Field3DWriteCellCentre) { @@ -216,7 +216,7 @@ TEST_F(OptionsNetCDFTest, Field3DWriteCellCentre) { // Read file Options data = OptionsNetCDF(filename).read(); - EXPECT_EQ(data["f3d"].attributes["cell_location"].as(), CELL_LOC_STRING(CELL_CENTRE)); + EXPECT_EQ(data["f3d"].attributes["cell_location"].as(), toString(CELL_CENTRE)); } TEST_F(OptionsNetCDFTest, Field3DWriteCellYLow) { @@ -239,7 +239,7 @@ TEST_F(OptionsNetCDFTest, Field3DWriteCellYLow) { // Read file Options data = OptionsNetCDF(filename).read(); - EXPECT_EQ(data["f3d"].attributes["cell_location"].as(), CELL_LOC_STRING(CELL_YLOW)); + EXPECT_EQ(data["f3d"].attributes["cell_location"].as(), toString(CELL_YLOW)); } From 8e6eb01ab321014cfb9576207de39259879c564a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 15:48:18 +0000 Subject: [PATCH 1030/1783] Use round-bracket initialisation to avoid narrowing error --- src/sys/options/options_netcdf.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index fc7c61d915..9aa65b3906 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -52,7 +52,7 @@ void readGroup(const std::string& filename, NcGroup group, Options& result) { } case 1: { if (var_type == ncDouble) { - Array value{dims[0].getSize()}; + Array value(dims[0].getSize()); var.getVar(value.begin()); result[var_name] = value; result[var_name].attributes["source"] = filename; @@ -61,7 +61,7 @@ void readGroup(const std::string& filename, NcGroup group, Options& result) { } case 2: { if (var_type == ncDouble) { - Matrix value{dims[0].getSize(), dims[1].getSize()}; + Matrix value(dims[0].getSize(), dims[1].getSize()); var.getVar(value.begin()); result[var_name] = value; result[var_name].attributes["source"] = filename; @@ -70,7 +70,7 @@ void readGroup(const std::string& filename, NcGroup group, Options& result) { } case 3: { if (var_type == ncDouble) { - Tensor value{dims[0].getSize(), dims[1].getSize(), dims[2].getSize()}; + Tensor value(dims[0].getSize(), dims[1].getSize(), dims[2].getSize()); var.getVar(value.begin()); result[var_name] = value; result[var_name].attributes["source"] = filename; From 02f0bbb2991e3aef92308def77f7ee135319ee74 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 15:48:45 +0000 Subject: [PATCH 1031/1783] Fix printf format warning --- src/sys/options/options_netcdf.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 9aa65b3906..cc6ff98214 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -406,8 +406,8 @@ void writeGroup(const Options& options, NcGroup group, // Same number of dimensions? if (var_dims.size() != dims.size()) { - throw BoutException("Changed dimensions for variable '%s'\nIn file has %d " - "dimensions, now writing %d\n", + throw BoutException("Changed dimensions for variable '%s'\nIn file has %zu " + "dimensions, now writing %zu\n", name.c_str(), var_dims.size(), dims.size()); } // Dimensions compatible? From c4171cf04c55f94b29c17ee7dc2989b75e7753a4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 15:48:57 +0000 Subject: [PATCH 1032/1783] Mark variable unused in assignment statement test --- tests/unit/sys/test_options_fields.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/sys/test_options_fields.cxx b/tests/unit/sys/test_options_fields.cxx index 9fcf55ec7a..7f85b00651 100644 --- a/tests/unit/sys/test_options_fields.cxx +++ b/tests/unit/sys/test_options_fields.cxx @@ -6,6 +6,7 @@ #include "bout/mesh.hxx" #include "field3d.hxx" #include "test_extras.hxx" +#include "unused.hxx" /// Global mesh namespace bout { @@ -67,7 +68,7 @@ TEST_F(OptionsFieldTest, RetrieveBoutRealfromField3D) { Field3D field = 1.2; options = field; - EXPECT_THROW(BoutReal value = options, BoutException); + EXPECT_THROW(BoutReal UNUSED(value) = options, BoutException); } TEST_F(OptionsFieldTest, RetrieveField2DfromField3D) { From 6f0d72c9468ba0b76d1f4a7482cee1e1dbd05dd1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 15:49:30 +0000 Subject: [PATCH 1033/1783] Use pre-setup staggered mesh for staggered tests Also use function chaining to remove local variable --- tests/unit/sys/test_options_netcdf.cxx | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/tests/unit/sys/test_options_netcdf.cxx b/tests/unit/sys/test_options_netcdf.cxx index f4cc629eec..c770cb5eec 100644 --- a/tests/unit/sys/test_options_netcdf.cxx +++ b/tests/unit/sys/test_options_netcdf.cxx @@ -182,15 +182,9 @@ TEST_F(OptionsNetCDFTest, Field2DWriteCellCentre) { TEST_F(OptionsNetCDFTest, Field2DWriteCellYLow) { std::string filename = std::tmpnam(nullptr); - // Enable staggered grids - mesh->StaggerGrids = true; - { - Field2D f(2.0); - f.setLocation(CELL_YLOW); - Options options; - options["f2d"] = f; + options["f2d"] = Field2D(2.0, mesh_staggered).setLocation(CELL_YLOW); // Write file OptionsNetCDF(filename).write(options); @@ -222,15 +216,9 @@ TEST_F(OptionsNetCDFTest, Field3DWriteCellCentre) { TEST_F(OptionsNetCDFTest, Field3DWriteCellYLow) { std::string filename = std::tmpnam(nullptr); - // Enable staggered grids - mesh->StaggerGrids = true; - { - Field3D f(2.0); - f.setLocation(CELL_YLOW); - Options options; - options["f3d"] = f; + options["f3d"] = Field3D(2.0, mesh_staggered).setLocation(CELL_YLOW); // Write file OptionsNetCDF(filename).write(options); From 766a4e794addf6464fed13555a91cc4276ffb71d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 16:19:53 +0000 Subject: [PATCH 1034/1783] Replace _StaticCastOrThrow with overloads on std::true/false_type --- include/bout/sys/variant.hxx | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/include/bout/sys/variant.hxx b/include/bout/sys/variant.hxx index 09f37f12e7..fca149f866 100644 --- a/include/bout/sys/variant.hxx +++ b/include/bout/sys/variant.hxx @@ -88,26 +88,6 @@ bool variantEqualTo(const Variant& v, const T& t) { // Variant casting namespace details { - -/// Helper class for casting between two types -/// The general case is that casting can't be done -/// -/// Note: This must be a class/struct because partial -/// specialisation is not allowed for functions -template -struct _StaticCastOrThrow { - Target operator()(Source&& UNUSED(source)) { throw std::bad_cast{}; } -}; - -/// Specialised case (bool = true) -/// This version is used when casting can be done -template -struct _StaticCastOrThrow { - Target operator()(Source&& source) { - return static_cast(std::forward(source)); - } -}; - /// Functor to perform static casting with std::visit /// If the Target cannot be constructed from the Source /// then an exception (std::bad_cast) will be thrown at run time. @@ -118,9 +98,16 @@ template struct StaticCastOrThrow { template Target operator()(Source&& source) const { - return _StaticCastOrThrow::value>()( - std::forward(source)); + return StaticCastOrThrow()(std::forward(source), + std::is_constructible{}); + } + template + Target operator()(Source&& UNUSED(source), std::false_type) { + throw std::bad_cast{}; + } + template + Target operator()(Source&& source, std::true_type) { + return static_cast(std::forward(source)); } }; } // namespace details From fe238324958ae0fc06841c1e5bd8491f0b8355ac Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 16:23:25 +0000 Subject: [PATCH 1035/1783] Use =default on empty ctor/dtor, move argument for move ctor --- include/options.hxx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index 0c692cf634..2a95c2dadd 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -153,7 +153,7 @@ class Options; class Options { public: /// Constructor. This is called to create the root object - Options() {} + Options() = default; /// Constructor used to create non-root objects /// @@ -165,6 +165,8 @@ public: /// Copy constructor Options(const Options& other); + ~Options() = default; + /// Get a reference to the only root instance static Options &root(); @@ -189,14 +191,14 @@ public: using Base = bout::utils::variant; /// Constructor - AttributeType() {} + AttributeType() = default; /// Copy constructor AttributeType(const AttributeType& other) : Base(other) {} /// Move constructor - AttributeType(AttributeType&& other) : Base(other) {} + AttributeType(AttributeType&& other) : Base(std::move(other)) {} /// Destructor - ~AttributeType() {} + ~AttributeType() = default; /// Assignment operator, including move assignment using Base::operator=; From 23f330adea3f5673312ea8fbaff906252e45fb11 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 16:56:13 +0000 Subject: [PATCH 1036/1783] Silence output during some options-related tests --- tests/unit/sys/test_options_fields.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/sys/test_options_fields.cxx b/tests/unit/sys/test_options_fields.cxx index 7f85b00651..895096ad97 100644 --- a/tests/unit/sys/test_options_fields.cxx +++ b/tests/unit/sys/test_options_fields.cxx @@ -84,6 +84,7 @@ TEST_F(OptionsFieldTest, RetrieveStringfromField3D) { Field3D field = 1.2; options = field; + WithQuietOutput quiet{output_info}; EXPECT_EQ(options.as(), ""); } @@ -92,6 +93,7 @@ TEST_F(OptionsFieldTest, RetrieveStringfromField2D) { Field2D field = 1.2; options = field; + WithQuietOutput quiet{output_info}; EXPECT_EQ(options.as(), ""); } From 7e18343da85ebf533ea9d74dd67ee05ab0f91c14 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 16:56:42 +0000 Subject: [PATCH 1037/1783] Clean up temporary files created during tests in the test fixtures --- tests/unit/sys/test_options_netcdf.cxx | 38 +++++++-------------- tests/unit/sys/test_optionsreader.cxx | 47 ++++++++++---------------- tests/unit/sys/test_output.cxx | 40 ++++++---------------- 3 files changed, 40 insertions(+), 85 deletions(-) diff --git a/tests/unit/sys/test_options_netcdf.cxx b/tests/unit/sys/test_options_netcdf.cxx index c770cb5eec..7fa714faa1 100644 --- a/tests/unit/sys/test_options_netcdf.cxx +++ b/tests/unit/sys/test_options_netcdf.cxx @@ -9,6 +9,8 @@ #include "test_extras.hxx" #include "options_netcdf.hxx" +#include + /// Global mesh namespace bout { namespace globals { @@ -17,11 +19,19 @@ extern Mesh* mesh; } // namespace bout // Reuse the "standard" fixture for FakeMesh -using OptionsNetCDFTest = FakeMeshFixture; +class OptionsNetCDFTest: public FakeMeshFixture { +public: + OptionsNetCDFTest() : FakeMeshFixture() {} + virtual ~OptionsNetCDFTest() { std::remove(filename.c_str()); } + + // A temporary filename + std::string filename{std::tmpnam(nullptr)}; + WithQuietOutput quiet{output_info}; +}; TEST_F(OptionsNetCDFTest, ReadWriteInt) { // Temporary file - OptionsNetCDF file(std::tmpnam(nullptr)); + OptionsNetCDF file(filename); { Options options; @@ -38,8 +48,6 @@ TEST_F(OptionsNetCDFTest, ReadWriteInt) { } TEST_F(OptionsNetCDFTest, ReadWriteString) { - std::string filename = std::tmpnam(nullptr); - { Options options; options["test"] = "hello"; @@ -55,8 +63,6 @@ TEST_F(OptionsNetCDFTest, ReadWriteString) { } TEST_F(OptionsNetCDFTest, ReadWriteField2D) { - std::string filename = std::tmpnam(nullptr); - { Options options; options["test"] = Field2D(1.0); @@ -75,9 +81,7 @@ TEST_F(OptionsNetCDFTest, ReadWriteField2D) { } TEST_F(OptionsNetCDFTest, ReadWriteField3D) { - std::string filename = std::tmpnam(nullptr); - - { + { Options options; options["test"] = Field3D(2.4); @@ -96,8 +100,6 @@ TEST_F(OptionsNetCDFTest, ReadWriteField3D) { } TEST_F(OptionsNetCDFTest, Groups) { - std::string filename = std::tmpnam(nullptr); - { Options options; options["test"]["key"] = 42; @@ -112,8 +114,6 @@ TEST_F(OptionsNetCDFTest, Groups) { } TEST_F(OptionsNetCDFTest, AttributeInt) { - std::string filename = std::tmpnam(nullptr); - { Options options; options["test"] = 3; @@ -129,8 +129,6 @@ TEST_F(OptionsNetCDFTest, AttributeInt) { } TEST_F(OptionsNetCDFTest, AttributeBoutReal) { - std::string filename = std::tmpnam(nullptr); - { Options options; options["test"] = 3; @@ -146,8 +144,6 @@ TEST_F(OptionsNetCDFTest, AttributeBoutReal) { } TEST_F(OptionsNetCDFTest, AttributeString) { - std::string filename = std::tmpnam(nullptr); - { Options options; options["test"] = 3; @@ -163,8 +159,6 @@ TEST_F(OptionsNetCDFTest, AttributeString) { } TEST_F(OptionsNetCDFTest, Field2DWriteCellCentre) { - std::string filename = std::tmpnam(nullptr); - { Options options; options["f2d"] = Field2D(2.0); @@ -180,8 +174,6 @@ TEST_F(OptionsNetCDFTest, Field2DWriteCellCentre) { } TEST_F(OptionsNetCDFTest, Field2DWriteCellYLow) { - std::string filename = std::tmpnam(nullptr); - { Options options; options["f2d"] = Field2D(2.0, mesh_staggered).setLocation(CELL_YLOW); @@ -197,8 +189,6 @@ TEST_F(OptionsNetCDFTest, Field2DWriteCellYLow) { } TEST_F(OptionsNetCDFTest, Field3DWriteCellCentre) { - std::string filename = std::tmpnam(nullptr); - { Options options; options["f3d"] = Field3D(2.0); @@ -214,8 +204,6 @@ TEST_F(OptionsNetCDFTest, Field3DWriteCellCentre) { } TEST_F(OptionsNetCDFTest, Field3DWriteCellYLow) { - std::string filename = std::tmpnam(nullptr); - { Options options; options["f3d"] = Field3D(2.0, mesh_staggered).setLocation(CELL_YLOW); diff --git a/tests/unit/sys/test_optionsreader.cxx b/tests/unit/sys/test_optionsreader.cxx index 27c58cc393..5df3b32a18 100644 --- a/tests/unit/sys/test_optionsreader.cxx +++ b/tests/unit/sys/test_optionsreader.cxx @@ -28,6 +28,8 @@ class OptionsReaderTest : public ::testing::Test { // Make sure options singleton is clean Options::cleanup(); + + std::remove(filename.c_str()); } // Write cout to buffer instead of stdout @@ -36,6 +38,8 @@ class OptionsReaderTest : public ::testing::Test { std::streambuf *sbuf; WithQuietOutput quiet{output_info}; + // A temporary filename + std::string filename{std::tmpnam(nullptr)}; }; TEST_F(OptionsReaderTest, BadFilename) { @@ -251,14 +255,13 @@ real_key = 42.34e-67 bool_key = false )"; - char *filename = std::tmpnam(nullptr); std::ofstream test_file(filename, std::ios::out); test_file << text; test_file.close(); OptionsReader reader; Options *options = Options::getRoot(); - reader.read(options, "%s", filename); + reader.read(options, "%s", filename.c_str()); ASSERT_TRUE(options->isSet("flag")); @@ -293,15 +296,12 @@ bool_key = false subsection2->get("bool_key", bool_value, true); EXPECT_FALSE(bool_value); - - std::remove(filename); } TEST_F(OptionsReaderTest, ReadBadFile) { - char *filename = std::tmpnam(nullptr); OptionsReader reader; Options *options = Options::getRoot(); - EXPECT_THROW(reader.read(options, "%s", filename), BoutException); + EXPECT_THROW(reader.read(options, "%s", filename.c_str()), BoutException); } TEST_F(OptionsReaderTest, ReadBadFileSectionIncomplete) { @@ -310,14 +310,13 @@ TEST_F(OptionsReaderTest, ReadBadFileSectionIncomplete) { int_key = 34 )"; - char *filename = std::tmpnam(nullptr); - std::ofstream test_file(filename, std::ios::out); + std::ofstream test_file(filename.c_str(), std::ios::out); test_file << text; test_file.close(); OptionsReader reader; Options *options = Options::getRoot(); - EXPECT_THROW(reader.read(options, "%s", filename), BoutException); + EXPECT_THROW(reader.read(options, "%s", filename.c_str()), BoutException); }; TEST_F(OptionsReaderTest, ReadBadFileSectionEmptyName) { @@ -326,18 +325,16 @@ TEST_F(OptionsReaderTest, ReadBadFileSectionEmptyName) { int_key = 34 )"; - char *filename = std::tmpnam(nullptr); std::ofstream test_file(filename, std::ios::out); test_file << text; test_file.close(); OptionsReader reader; Options *options = Options::getRoot(); - EXPECT_THROW(reader.read(options, "%s", filename), BoutException); + EXPECT_THROW(reader.read(options, "%s", filename.c_str()), BoutException); }; TEST_F(OptionsReaderTest, WriteFile) { - char *filename = std::tmpnam(nullptr); OptionsReader reader; Options *options = Options::getRoot(); @@ -348,7 +345,7 @@ TEST_F(OptionsReaderTest, WriteFile) { Options *subsection2 = section1->getSection("subsection2"); subsection2->set("string_key", "BOUT++", "test"); - reader.write(options, "%s", filename); + reader.write(options, "%s", filename.c_str()); std::ifstream test_file(filename); std::stringstream test_buffer; @@ -362,13 +359,10 @@ TEST_F(OptionsReaderTest, WriteFile) { for (auto &result : expected) { EXPECT_TRUE(IsSubString(test_buffer.str(), result)); } - - std::remove(filename); } TEST_F(OptionsReaderTest, WriteBadFile) { - std::string filename1 = std::tmpnam(nullptr); - std::string filename = filename1 + std::tmpnam(nullptr); + std::string filename1 = filename + std::tmpnam(nullptr); OptionsReader reader; Options *options = Options::getRoot(); @@ -376,9 +370,9 @@ TEST_F(OptionsReaderTest, WriteBadFile) { Options *section1 = options->getSection("section1"); section1->set("int_key", 17, "test"); - EXPECT_THROW(reader.write(options, "%s", filename.c_str()), BoutException); + EXPECT_THROW(reader.write(options, "%s", filename1.c_str()), BoutException); - std::remove(filename.c_str()); + std::remove(filename1.c_str()); } TEST_F(OptionsReaderTest, ReadEmptyString) { @@ -386,7 +380,6 @@ const std::string text = R"( value = )"; - char *filename = std::tmpnam(nullptr); std::ofstream test_file(filename, std::ios::out); test_file << text; test_file.close(); @@ -394,7 +387,7 @@ value = Options opt; OptionsReader reader; - reader.read(&opt, "%s", filename); + reader.read(&opt, "%s", filename.c_str()); std::string val = opt["value"]; EXPECT_TRUE(val.empty()); @@ -417,14 +410,12 @@ test5 = `h2+`:another # Escape only start of sequence test6 = h2`+`:on`e-`more # Escape sequences in the middle )"; - char *filename = std::tmpnam(nullptr); std::ofstream test_file(filename, std::ios::out); test_file << text; test_file.close(); OptionsReader reader; - reader.read(Options::getRoot(), "%s", filename); - std::remove(filename); + reader.read(Options::getRoot(), "%s", filename.c_str()); auto options = Options::root()["tests"]; @@ -444,15 +435,13 @@ TEST_F(OptionsReaderTest, ReadFileVariablesNoColons) { some:value = 3 )"; - char *filename = std::tmpnam(nullptr); std::ofstream test_file(filename, std::ios::out); test_file << text; test_file.close(); OptionsReader reader; - EXPECT_THROW(reader.read(Options::getRoot(), "%s", filename), BoutException); - std::remove(filename); + EXPECT_THROW(reader.read(Options::getRoot(), "%s", filename.c_str()), BoutException); } TEST_F(OptionsReaderTest, ReadUnicodeNames) { @@ -467,14 +456,12 @@ value = α*(1 + 重要的數字) twopi = 2 * π # Unicode symbol defined for pi )"; - char *filename = std::tmpnam(nullptr); std::ofstream test_file(filename, std::ios::out); test_file << text; test_file.close(); OptionsReader reader; - reader.read(Options::getRoot(), "%s", filename); - std::remove(filename); + reader.read(Options::getRoot(), "%s", filename.c_str()); auto options = Options::root()["tests"]; diff --git a/tests/unit/sys/test_output.cxx b/tests/unit/sys/test_output.cxx index 2d00d0f801..c25c201511 100644 --- a/tests/unit/sys/test_output.cxx +++ b/tests/unit/sys/test_output.cxx @@ -18,12 +18,16 @@ class OutputTest : public ::testing::Test { buffer.str(""); // When done redirect cout to its old self std::cout.rdbuf(sbuf); + + std::remove(filename.c_str()); } // Write cout to buffer instead of stdout std::stringstream buffer; // Save cout's buffer here std::streambuf *sbuf; + // A temporary filename + std::string filename{std::tmpnam(nullptr)}; }; TEST_F(OutputTest, JustStdOutCpp) { @@ -49,12 +53,9 @@ TEST_F(OutputTest, JustStdOutGlobalInstance) { TEST_F(OutputTest, OpenFile) { Output local_output; - // Get a filename for a temporary file - char *filename = std::tmpnam(nullptr); - std::string test_output = "To stdout and file\n"; - local_output.open("%s", filename); + local_output.open("%s", filename.c_str()); local_output << test_output; std::ifstream test_file(filename); @@ -64,19 +65,14 @@ TEST_F(OutputTest, OpenFile) { EXPECT_EQ(test_output, test_buffer.str()); EXPECT_EQ(test_output, buffer.str()); - - std::remove(filename); } TEST_F(OutputTest, JustPrint) { Output local_output; - // Get a filename for a temporary file - char *filename = std::tmpnam(nullptr); - std::string test_output = "To stdout only\n"; - local_output.open("%s", filename); + local_output.open("%s", filename.c_str()); local_output.print("%s",test_output.c_str()); std::ifstream test_file(filename); @@ -86,21 +82,16 @@ TEST_F(OutputTest, JustPrint) { EXPECT_EQ("", test_buffer.str()); EXPECT_EQ(test_output, buffer.str()); - - std::remove(filename); } TEST_F(OutputTest, DisableEnableStdout) { Output local_output; - // Get a filename for a temporary file - char *filename = std::tmpnam(nullptr); - - std::string file_only = "To file only\n"; + std::string file_only = "To file only\n"; std::string file_and_stdout = "To stdout and file\n"; // Open temporary file and close stdout - local_output.open("%s", filename); + local_output.open("%s", filename.c_str()); local_output.disable(); local_output << file_only; @@ -123,7 +114,6 @@ TEST_F(OutputTest, DisableEnableStdout) { EXPECT_EQ(file_and_stdout, buffer.str()); test_file.close(); - std::remove(filename); } TEST_F(OutputTest, GetInstance) { @@ -222,12 +212,9 @@ TEST_F(OutputTest, ConditionalJustPrint) { Output local_output_base; ConditionalOutput local_output(&local_output_base); - // Get a filename for a temporary file - char *filename = std::tmpnam(nullptr); - std::string test_output = "To stdout only\n"; - local_output.open("%s", filename); + local_output.open("%s", filename.c_str()); local_output.print("%s", test_output.c_str()); std::ifstream test_file(filename); @@ -237,8 +224,6 @@ TEST_F(OutputTest, ConditionalJustPrint) { EXPECT_EQ("", test_buffer.str()); EXPECT_EQ(test_output, buffer.str()); - - std::remove(filename); } TEST_F(OutputTest, ConditionalMultipleLayersGetBase) { @@ -296,12 +281,9 @@ TEST_F(OutputTest, DummyOutputStdOut) { TEST_F(OutputTest, DummyJustPrint) { DummyOutput dummy; - // Get a filename for a temporary file - char *filename = std::tmpnam(nullptr); - std::string test_output = "To stdout only\n"; - dummy.open("%s", filename); + dummy.open("%s", filename.c_str()); dummy.print("%s", test_output.c_str()); std::ifstream test_file(filename); @@ -311,6 +293,4 @@ TEST_F(OutputTest, DummyJustPrint) { EXPECT_EQ("", test_buffer.str()); EXPECT_EQ("", buffer.str()); - - std::remove(filename); } From 9a348aaa4f76e6274bfaf49f7bb0ba2adbd7f2af Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 17:11:35 +0000 Subject: [PATCH 1038/1783] Add mpark.variant as a submodule --- .gitmodules | 3 +++ externalpackages/mpark.variant | 1 + 2 files changed, 4 insertions(+) create mode 160000 externalpackages/mpark.variant diff --git a/.gitmodules b/.gitmodules index c696c41a66..27c98fc7be 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "externalpackages/git-archive-all.sh"] path = externalpackages/git-archive-all.sh url = https://github.com/meitar/git-archive-all.sh/ +[submodule "mpark.variant"] + path = externalpackages/mpark.variant + url = https://github.com/mpark/variant.git diff --git a/externalpackages/mpark.variant b/externalpackages/mpark.variant new file mode 160000 index 0000000000..0b488da9be --- /dev/null +++ b/externalpackages/mpark.variant @@ -0,0 +1 @@ +Subproject commit 0b488da9bebac980e7ba0e158a959c956a449676 From b9d642252cb89e76255043115a5213cbc2f3a94e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 17:11:45 +0000 Subject: [PATCH 1039/1783] Don't ignore externalpackages --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index ace943d4ef..90f0ec37c7 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,6 @@ autom4te.cache/ aclocal.m4 /bin/bout-config -/externalpackages/ /include/pvode /lib/ /manual/*.pdf From 9e36a4021f781f787abf5bd298574a170c115238 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 13 Mar 2019 17:57:51 +0000 Subject: [PATCH 1040/1783] Remove previously included mpark package --- include/bout/sys/variant.hxx | 2 +- include/external/mpark/config.hpp | 79 -- include/external/mpark/in_place.hpp | 35 - include/external/mpark/lib.hpp | 446 ------- include/external/mpark/variant.hpp | 1930 --------------------------- 5 files changed, 1 insertion(+), 2491 deletions(-) delete mode 100644 include/external/mpark/config.hpp delete mode 100644 include/external/mpark/in_place.hpp delete mode 100644 include/external/mpark/lib.hpp delete mode 100644 include/external/mpark/variant.hpp diff --git a/include/bout/sys/variant.hxx b/include/bout/sys/variant.hxx index fca149f866..0b00d887cc 100644 --- a/include/bout/sys/variant.hxx +++ b/include/bout/sys/variant.hxx @@ -21,7 +21,7 @@ // std::variant added in C++17 //#include -#include "external/mpark/variant.hpp" +#include "mpark/variant.hpp" #include "utils.hxx" diff --git a/include/external/mpark/config.hpp b/include/external/mpark/config.hpp deleted file mode 100644 index 4c93412f4b..0000000000 --- a/include/external/mpark/config.hpp +++ /dev/null @@ -1,79 +0,0 @@ -// MPark.Variant -// -// Copyright Michael Park, 2015-2017 -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -#ifndef MPARK_CONFIG_HPP -#define MPARK_CONFIG_HPP - -// MSVC 2015 Update 3. -#if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) -#error "MPark.Variant requires C++11 support." -#endif - -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif - -#ifndef __has_include -#define __has_include(x) 0 -#endif - -#ifndef __has_feature -#define __has_feature(x) 0 -#endif - -#if __has_builtin(__builtin_addressof) || \ - (defined(__GNUC__) && __GNUC__ >= 7) || defined(_MSC_VER) -#define MPARK_BUILTIN_ADDRESSOF -#endif - -#if __has_builtin(__builtin_unreachable) -#define MPARK_BUILTIN_UNREACHABLE __builtin_unreachable() -#elif defined(_MSC_VER) -#define MPARK_BUILTIN_UNREACHABLE __assume(false) -#else -#define MPARK_BUILTIN_UNREACHABLE -#endif - -#if __has_builtin(__type_pack_element) -#define MPARK_TYPE_PACK_ELEMENT -#endif - -#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 && \ - !(defined(_MSC_VER) && _MSC_VER <= 1915) -#define MPARK_CPP14_CONSTEXPR -#endif - -#if __has_feature(cxx_exceptions) || defined(__cpp_exceptions) || \ - (defined(_MSC_VER) && defined(_CPPUNWIND)) -#define MPARK_EXCEPTIONS -#endif - -#if defined(__cpp_generic_lambdas) || defined(_MSC_VER) -#define MPARK_GENERIC_LAMBDAS -#endif - -#if defined(__cpp_lib_integer_sequence) -#define MPARK_INTEGER_SEQUENCE -#endif - -#if defined(__cpp_return_type_deduction) || defined(_MSC_VER) -#define MPARK_RETURN_TYPE_DEDUCTION -#endif - -#if defined(__cpp_lib_transparent_operators) || defined(_MSC_VER) -#define MPARK_TRANSPARENT_OPERATORS -#endif - -#if defined(__cpp_variable_templates) || defined(_MSC_VER) -#define MPARK_VARIABLE_TEMPLATES -#endif - -#if !defined(__GLIBCXX__) || __has_include() // >= libstdc++-5 -#define MPARK_TRIVIALITY_TYPE_TRAITS -#endif - -#endif // MPARK_CONFIG_HPP diff --git a/include/external/mpark/in_place.hpp b/include/external/mpark/in_place.hpp deleted file mode 100644 index 56cae13113..0000000000 --- a/include/external/mpark/in_place.hpp +++ /dev/null @@ -1,35 +0,0 @@ -// MPark.Variant -// -// Copyright Michael Park, 2015-2017 -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -#ifndef MPARK_IN_PLACE_HPP -#define MPARK_IN_PLACE_HPP - -#include - -#include "config.hpp" - -namespace mpark { - - struct in_place_t { explicit in_place_t() = default; }; - - template - struct in_place_index_t { explicit in_place_index_t() = default; }; - - template - struct in_place_type_t { explicit in_place_type_t() = default; }; - -#ifdef MPARK_VARIABLE_TEMPLATES - constexpr in_place_t in_place{}; - - template constexpr in_place_index_t in_place_index{}; - - template constexpr in_place_type_t in_place_type{}; -#endif - -} // namespace mpark - -#endif // MPARK_IN_PLACE_HPP diff --git a/include/external/mpark/lib.hpp b/include/external/mpark/lib.hpp deleted file mode 100644 index 81ffabf289..0000000000 --- a/include/external/mpark/lib.hpp +++ /dev/null @@ -1,446 +0,0 @@ -// MPark.Variant -// -// Copyright Michael Park, 2015-2017 -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -#ifndef MPARK_LIB_HPP -#define MPARK_LIB_HPP - -#include -#include -#include -#include - -#include "config.hpp" - -#define MPARK_RETURN(...) -> decltype(__VA_ARGS__) { return __VA_ARGS__; } - -namespace mpark { - namespace lib { - template - struct identity { using type = T; }; - - inline namespace cpp14 { - template - struct array { - constexpr const T &operator[](std::size_t index) const { - return data[index]; - } - - T data[N == 0 ? 1 : N]; - }; - - template - using add_pointer_t = typename std::add_pointer::type; - - template - using common_type_t = typename std::common_type::type; - - template - using decay_t = typename std::decay::type; - - template - using enable_if_t = typename std::enable_if::type; - - template - using remove_const_t = typename std::remove_const::type; - - template - using remove_reference_t = typename std::remove_reference::type; - - template - inline constexpr T &&forward(remove_reference_t &t) noexcept { - return static_cast(t); - } - - template - inline constexpr T &&forward(remove_reference_t &&t) noexcept { - static_assert(!std::is_lvalue_reference::value, - "can not forward an rvalue as an lvalue"); - return static_cast(t); - } - - template - inline constexpr remove_reference_t &&move(T &&t) noexcept { - return static_cast &&>(t); - } - -#ifdef MPARK_INTEGER_SEQUENCE - using std::integer_sequence; - using std::index_sequence; - using std::make_index_sequence; - using std::index_sequence_for; -#else - template - struct integer_sequence { - using value_type = T; - static constexpr std::size_t size() noexcept { return sizeof...(Is); } - }; - - template - using index_sequence = integer_sequence; - - template - struct make_index_sequence_concat; - - template - struct make_index_sequence_concat, - index_sequence> - : identity> {}; - - template - struct make_index_sequence_impl; - - template - using make_index_sequence = typename make_index_sequence_impl::type; - - template - struct make_index_sequence_impl - : make_index_sequence_concat, - make_index_sequence> {}; - - template <> - struct make_index_sequence_impl<0> : identity> {}; - - template <> - struct make_index_sequence_impl<1> : identity> {}; - - template - using index_sequence_for = make_index_sequence; -#endif - - // -#ifdef MPARK_TRANSPARENT_OPERATORS - using equal_to = std::equal_to<>; -#else - struct equal_to { - template - inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const - MPARK_RETURN(lib::forward(lhs) == lib::forward(rhs)) - }; -#endif - -#ifdef MPARK_TRANSPARENT_OPERATORS - using not_equal_to = std::not_equal_to<>; -#else - struct not_equal_to { - template - inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const - MPARK_RETURN(lib::forward(lhs) != lib::forward(rhs)) - }; -#endif - -#ifdef MPARK_TRANSPARENT_OPERATORS - using less = std::less<>; -#else - struct less { - template - inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const - MPARK_RETURN(lib::forward(lhs) < lib::forward(rhs)) - }; -#endif - -#ifdef MPARK_TRANSPARENT_OPERATORS - using greater = std::greater<>; -#else - struct greater { - template - inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const - MPARK_RETURN(lib::forward(lhs) > lib::forward(rhs)) - }; -#endif - -#ifdef MPARK_TRANSPARENT_OPERATORS - using less_equal = std::less_equal<>; -#else - struct less_equal { - template - inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const - MPARK_RETURN(lib::forward(lhs) <= lib::forward(rhs)) - }; -#endif - -#ifdef MPARK_TRANSPARENT_OPERATORS - using greater_equal = std::greater_equal<>; -#else - struct greater_equal { - template - inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const - MPARK_RETURN(lib::forward(lhs) >= lib::forward(rhs)) - }; -#endif - } // namespace cpp14 - - inline namespace cpp17 { - - // - template - using bool_constant = std::integral_constant; - - template - struct voider : identity {}; - - template - using void_t = typename voider::type; - - namespace detail { - namespace swappable { - - using std::swap; - - template - struct is_swappable { - private: - template (), - std::declval()))> - inline static std::true_type test(int); - - template - inline static std::false_type test(...); - - public: - static constexpr bool value = decltype(test(0))::value; - }; - - template ::value> - struct is_nothrow_swappable { -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnoexcept" -#endif - static constexpr bool value = - noexcept(swap(std::declval(), std::declval())); -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif - }; - - template - struct is_nothrow_swappable : std::false_type {}; - - } // namespace swappable - } // namespace detail - - using detail::swappable::is_swappable; - using detail::swappable::is_nothrow_swappable; - - // -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4100) -#endif - template - inline constexpr auto invoke(F &&f, As &&... as) - MPARK_RETURN(lib::forward(f)(lib::forward(as)...)) -#ifdef _MSC_VER -#pragma warning(pop) -#endif - - template - inline constexpr auto invoke(T B::*pmv, D &&d) - MPARK_RETURN(lib::forward(d).*pmv) - - template - inline constexpr auto invoke(Pmv pmv, Ptr &&ptr) - MPARK_RETURN((*lib::forward(ptr)).*pmv) - - template - inline constexpr auto invoke(T B::*pmf, D &&d, As &&... as) - MPARK_RETURN((lib::forward(d).*pmf)(lib::forward(as)...)) - - template - inline constexpr auto invoke(Pmf pmf, Ptr &&ptr, As &&... as) - MPARK_RETURN(((*lib::forward(ptr)).*pmf)(lib::forward(as)...)) - - namespace detail { - - template - struct invoke_result {}; - - template - struct invoke_result(), std::declval()...))>, - F, - Args...> - : identity(), std::declval()...))> {}; - - } // namespace detail - - template - using invoke_result = detail::invoke_result; - - template - using invoke_result_t = typename invoke_result::type; - - namespace detail { - - template - struct is_invocable : std::false_type {}; - - template - struct is_invocable>, F, Args...> - : std::true_type {}; - - template - struct is_invocable_r : std::false_type {}; - - template - struct is_invocable_r>, - R, - F, - Args...> - : std::is_convertible, R> {}; - - } // namespace detail - - template - using is_invocable = detail::is_invocable; - - template - using is_invocable_r = detail::is_invocable_r; - - // -#ifdef MPARK_BUILTIN_ADDRESSOF - template - inline constexpr T *addressof(T &arg) noexcept { - return __builtin_addressof(arg); - } -#else - namespace detail { - - namespace has_addressof_impl { - - struct fail; - - template - inline fail operator&(T &&); - - template - inline static constexpr bool impl() { - return (std::is_class::value || std::is_union::value) && - !std::is_same()), fail>::value; - } - - } // namespace has_addressof_impl - - template - using has_addressof = bool_constant()>; - - template - inline constexpr T *addressof(T &arg, std::true_type) noexcept { - return std::addressof(arg); - } - - template - inline constexpr T *addressof(T &arg, std::false_type) noexcept { - return &arg; - } - - } // namespace detail - - template - inline constexpr T *addressof(T &arg) noexcept { - return detail::addressof(arg, detail::has_addressof{}); - } -#endif - - template - inline constexpr T *addressof(const T &&) = delete; - - } // namespace cpp17 - - template - struct remove_all_extents : identity {}; - - template - struct remove_all_extents> : remove_all_extents {}; - - template - using remove_all_extents_t = typename remove_all_extents::type; - - template - using size_constant = std::integral_constant; - - template - struct indexed_type : size_constant { using type = T; }; - - template - using all = std::is_same, - integer_sequence>; - -#ifdef MPARK_TYPE_PACK_ELEMENT - template - using type_pack_element_t = __type_pack_element; -#else - template - struct type_pack_element_impl { - private: - template - struct set; - - template - struct set> : indexed_type... {}; - - template - inline static std::enable_if impl(indexed_type); - - inline static std::enable_if impl(...); - - public: - using type = decltype(impl(set>{})); - }; - - template - using type_pack_element = typename type_pack_element_impl::type; - - template - using type_pack_element_t = typename type_pack_element::type; -#endif - -#ifdef MPARK_TRIVIALITY_TYPE_TRAITS - using std::is_trivially_copy_constructible; - using std::is_trivially_move_constructible; - using std::is_trivially_copy_assignable; - using std::is_trivially_move_assignable; -#else - template - struct is_trivially_copy_constructible - : bool_constant< - std::is_copy_constructible::value && __has_trivial_copy(T)> {}; - - template - struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {}; - - template - struct is_trivially_copy_assignable - : bool_constant< - std::is_copy_assignable::value && __has_trivial_assign(T)> {}; - - template - struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {}; -#endif - - template - struct dependent_type : T {}; - - template - struct push_back; - - template - using push_back_t = typename push_back::type; - - template - struct push_back, J> { - using type = index_sequence; - }; - - } // namespace lib -} // namespace mpark - -#undef MPARK_RETURN - -#endif // MPARK_LIB_HPP diff --git a/include/external/mpark/variant.hpp b/include/external/mpark/variant.hpp deleted file mode 100644 index bc7dd87d63..0000000000 --- a/include/external/mpark/variant.hpp +++ /dev/null @@ -1,1930 +0,0 @@ -// MPark.Variant -// -// Copyright Michael Park, 2015-2017 -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) - -#ifndef MPARK_VARIANT_HPP -#define MPARK_VARIANT_HPP - -/* - variant synopsis - -namespace std { - - // 20.7.2, class template variant - template - class variant { - public: - - // 20.7.2.1, constructors - constexpr variant() noexcept(see below); - variant(const variant&); - variant(variant&&) noexcept(see below); - - template constexpr variant(T&&) noexcept(see below); - - template - constexpr explicit variant(in_place_type_t, Args&&...); - - template - constexpr explicit variant( - in_place_type_t, initializer_list, Args&&...); - - template - constexpr explicit variant(in_place_index_t, Args&&...); - - template - constexpr explicit variant( - in_place_index_t, initializer_list, Args&&...); - - // 20.7.2.2, destructor - ~variant(); - - // 20.7.2.3, assignment - variant& operator=(const variant&); - variant& operator=(variant&&) noexcept(see below); - - template variant& operator=(T&&) noexcept(see below); - - // 20.7.2.4, modifiers - template - T& emplace(Args&&...); - - template - T& emplace(initializer_list, Args&&...); - - template - variant_alternative& emplace(Args&&...); - - template - variant_alternative& emplace(initializer_list, Args&&...); - - // 20.7.2.5, value status - constexpr bool valueless_by_exception() const noexcept; - constexpr size_t index() const noexcept; - - // 20.7.2.6, swap - void swap(variant&) noexcept(see below); - }; - - // 20.7.3, variant helper classes - template struct variant_size; // undefined - - template - constexpr size_t variant_size_v = variant_size::value; - - template struct variant_size; - template struct variant_size; - template struct variant_size; - - template - struct variant_size>; - - template struct variant_alternative; // undefined - - template - using variant_alternative_t = typename variant_alternative::type; - - template struct variant_alternative; - template struct variant_alternative; - template struct variant_alternative; - - template - struct variant_alternative>; - - constexpr size_t variant_npos = -1; - - // 20.7.4, value access - template - constexpr bool holds_alternative(const variant&) noexcept; - - template - constexpr variant_alternative_t>& - get(variant&); - - template - constexpr variant_alternative_t>&& - get(variant&&); - - template - constexpr variant_alternative_t> const& - get(const variant&); - - template - constexpr variant_alternative_t> const&& - get(const variant&&); - - template - constexpr T& get(variant&); - - template - constexpr T&& get(variant&&); - - template - constexpr const T& get(const variant&); - - template - constexpr const T&& get(const variant&&); - - template - constexpr add_pointer_t>> - get_if(variant*) noexcept; - - template - constexpr add_pointer_t>> - get_if(const variant*) noexcept; - - template - constexpr add_pointer_t - get_if(variant*) noexcept; - - template - constexpr add_pointer_t - get_if(const variant*) noexcept; - - // 20.7.5, relational operators - template - constexpr bool operator==(const variant&, const variant&); - - template - constexpr bool operator!=(const variant&, const variant&); - - template - constexpr bool operator<(const variant&, const variant&); - - template - constexpr bool operator>(const variant&, const variant&); - - template - constexpr bool operator<=(const variant&, const variant&); - - template - constexpr bool operator>=(const variant&, const variant&); - - // 20.7.6, visitation - template - constexpr see below visit(Visitor&&, Variants&&...); - - // 20.7.7, class monostate - struct monostate; - - // 20.7.8, monostate relational operators - constexpr bool operator<(monostate, monostate) noexcept; - constexpr bool operator>(monostate, monostate) noexcept; - constexpr bool operator<=(monostate, monostate) noexcept; - constexpr bool operator>=(monostate, monostate) noexcept; - constexpr bool operator==(monostate, monostate) noexcept; - constexpr bool operator!=(monostate, monostate) noexcept; - - // 20.7.9, specialized algorithms - template - void swap(variant&, variant&) noexcept(see below); - - // 20.7.10, class bad_variant_access - class bad_variant_access; - - // 20.7.11, hash support - template struct hash; - template struct hash>; - template <> struct hash; - -} // namespace std - -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "config.hpp" -#include "in_place.hpp" -#include "lib.hpp" - -namespace mpark { - -#ifdef MPARK_RETURN_TYPE_DEDUCTION - -#define AUTO auto -#define AUTO_RETURN(...) { return __VA_ARGS__; } - -#define AUTO_REFREF auto && -#define AUTO_REFREF_RETURN(...) { return __VA_ARGS__; } - -#define DECLTYPE_AUTO decltype(auto) -#define DECLTYPE_AUTO_RETURN(...) { return __VA_ARGS__; } - -#else - -#define AUTO auto -#define AUTO_RETURN(...) \ - -> lib::decay_t { return __VA_ARGS__; } - -#define AUTO_REFREF auto -#define AUTO_REFREF_RETURN(...) \ - -> decltype((__VA_ARGS__)) { \ - static_assert(std::is_reference::value, ""); \ - return __VA_ARGS__; \ - } - -#define DECLTYPE_AUTO auto -#define DECLTYPE_AUTO_RETURN(...) \ - -> decltype(__VA_ARGS__) { return __VA_ARGS__; } - -#endif - - class bad_variant_access : public std::exception { - public: - virtual const char *what() const noexcept override { return "bad_variant_access"; } - }; - - [[noreturn]] inline void throw_bad_variant_access() { -#ifdef MPARK_EXCEPTIONS - throw bad_variant_access{}; -#else - std::terminate(); - MPARK_BUILTIN_UNREACHABLE; -#endif - } - - template - class variant; - - template - struct variant_size; - -#ifdef MPARK_VARIABLE_TEMPLATES - template - constexpr std::size_t variant_size_v = variant_size::value; -#endif - - template - struct variant_size : variant_size {}; - - template - struct variant_size : variant_size {}; - - template - struct variant_size : variant_size {}; - - template - struct variant_size> : lib::size_constant {}; - - template - struct variant_alternative; - - template - using variant_alternative_t = typename variant_alternative::type; - - template - struct variant_alternative - : std::add_const> {}; - - template - struct variant_alternative - : std::add_volatile> {}; - - template - struct variant_alternative - : std::add_cv> {}; - - template - struct variant_alternative> { - static_assert(I < sizeof...(Ts), - "index out of bounds in `std::variant_alternative<>`"); - using type = lib::type_pack_element_t; - }; - - constexpr std::size_t variant_npos = static_cast(-1); - - namespace detail { - - constexpr std::size_t not_found = static_cast(-1); - constexpr std::size_t ambiguous = static_cast(-2); - -#ifdef MPARK_CPP14_CONSTEXPR - template - inline constexpr std::size_t find_index() { - constexpr lib::array matches = { - {std::is_same::value...} - }; - std::size_t result = not_found; - for (std::size_t i = 0; i < sizeof...(Ts); ++i) { - if (matches[i]) { - if (result != not_found) { - return ambiguous; - } - result = i; - } - } - return result; - } -#else - inline constexpr std::size_t find_index_impl(std::size_t result, - std::size_t) { - return result; - } - - template - inline constexpr std::size_t find_index_impl(std::size_t result, - std::size_t idx, - bool b, - Bs... bs) { - return b ? (result != not_found ? ambiguous - : find_index_impl(idx, idx + 1, bs...)) - : find_index_impl(result, idx + 1, bs...); - } - - template - inline constexpr std::size_t find_index() { - return find_index_impl(not_found, 0, std::is_same::value...); - } -#endif - - template - using find_index_sfinae_impl = - lib::enable_if_t>; - - template - using find_index_sfinae = find_index_sfinae_impl()>; - - template - struct find_index_checked_impl : lib::size_constant { - static_assert(I != not_found, "the specified type is not found."); - static_assert(I != ambiguous, "the specified type is ambiguous."); - }; - - template - using find_index_checked = find_index_checked_impl()>; - - struct valueless_t {}; - - enum class Trait { TriviallyAvailable, Available, Unavailable }; - - template class IsTriviallyAvailable, - template class IsAvailable> - inline constexpr Trait trait() { - return IsTriviallyAvailable::value - ? Trait::TriviallyAvailable - : IsAvailable::value ? Trait::Available - : Trait::Unavailable; - } - -#ifdef MPARK_CPP14_CONSTEXPR - template - inline constexpr Trait common_trait(Traits... traits) { - Trait result = Trait::TriviallyAvailable; - for (Trait t : {traits...}) { - if (static_cast(t) > static_cast(result)) { - result = t; - } - } - return result; - } -#else - inline constexpr Trait common_trait_impl(Trait result) { return result; } - - template - inline constexpr Trait common_trait_impl(Trait result, - Trait t, - Traits... ts) { - return static_cast(t) > static_cast(result) - ? common_trait_impl(t, ts...) - : common_trait_impl(result, ts...); - } - - template - inline constexpr Trait common_trait(Traits... ts) { - return common_trait_impl(Trait::TriviallyAvailable, ts...); - } -#endif - - template - struct traits { - static constexpr Trait copy_constructible_trait = - common_trait(trait()...); - - static constexpr Trait move_constructible_trait = - common_trait(trait()...); - - static constexpr Trait copy_assignable_trait = - common_trait(copy_constructible_trait, - trait()...); - - static constexpr Trait move_assignable_trait = - common_trait(move_constructible_trait, - trait()...); - - static constexpr Trait destructible_trait = - common_trait(trait()...); - }; - - namespace access { - - struct recursive_union { -#ifdef MPARK_RETURN_TYPE_DEDUCTION - template - inline static constexpr auto &&get_alt(V &&v, in_place_index_t<0>) { - return lib::forward(v).head_; - } - - template - inline static constexpr auto &&get_alt(V &&v, in_place_index_t) { - return get_alt(lib::forward(v).tail_, in_place_index_t{}); - } -#else - template - struct get_alt_impl { - template - inline constexpr AUTO_REFREF operator()(V &&v) const - AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v).tail_)) - }; - - template - struct get_alt_impl<0, Dummy> { - template - inline constexpr AUTO_REFREF operator()(V &&v) const - AUTO_REFREF_RETURN(lib::forward(v).head_) - }; - - template - inline static constexpr AUTO_REFREF get_alt(V &&v, in_place_index_t) - AUTO_REFREF_RETURN(get_alt_impl{}(lib::forward(v))) -#endif - }; - - struct base { - template - inline static constexpr AUTO_REFREF get_alt(V &&v) - AUTO_REFREF_RETURN(recursive_union::get_alt( - data(lib::forward(v)), in_place_index_t{})) - }; - - struct variant { - template - inline static constexpr AUTO_REFREF get_alt(V &&v) - AUTO_REFREF_RETURN(base::get_alt(lib::forward(v).impl_)) - }; - - } // namespace access - - namespace visitation { - - struct base { - template - inline static constexpr const T &at(const T &elem) noexcept { - return elem; - } - - template - inline static constexpr const lib::remove_all_extents_t &at( - const lib::array &elems, std::size_t i, Is... is) noexcept { - return at(elems[i], is...); - } - - template - inline static constexpr int visit_visitor_return_type_check() { - static_assert(lib::all::value...>::value, - "`mpark::visit` requires the visitor to have a single " - "return type."); - return 0; - } - - template - inline static constexpr lib::array< - lib::common_type_t...>, - sizeof...(Fs)> - make_farray(Fs &&... fs) { - using result = lib::array...>, - sizeof...(Fs)>; - return visit_visitor_return_type_check...>(), - result{{lib::forward(fs)...}}; - } - - template - struct dispatcher { - template - struct impl { - inline static constexpr DECLTYPE_AUTO dispatch(F f, Vs... vs) - DECLTYPE_AUTO_RETURN(lib::invoke( - static_cast(f), - access::base::get_alt(static_cast(vs))...)) - }; - }; - - template - inline static constexpr AUTO make_dispatch(lib::index_sequence) - AUTO_RETURN(&dispatcher::template impl::dispatch) - - template - inline static constexpr AUTO make_fdiagonal_impl() - AUTO_RETURN(make_dispatch( - lib::index_sequence::value...>{})) - - template - inline static constexpr AUTO make_fdiagonal_impl( - lib::index_sequence) - AUTO_RETURN(make_farray(make_fdiagonal_impl()...)) - - template - inline static constexpr /* auto * */ auto make_fdiagonal() - -> decltype(make_fdiagonal_impl( - lib::make_index_sequence::size()>{})) { - static_assert(lib::all<(lib::decay_t::size() == - lib::decay_t::size())...>::value, - "all of the variants must be the same size."); - return make_fdiagonal_impl( - lib::make_index_sequence::size()>{}); - } - -#ifdef MPARK_RETURN_TYPE_DEDUCTION - template - inline static constexpr auto make_fmatrix_impl(Is is) { - return make_dispatch(is); - } - - template - inline static constexpr auto make_fmatrix_impl( - Is, lib::index_sequence, Ls... ls) { - return make_farray(make_fmatrix_impl( - lib::push_back_t{}, ls...)...); - } - - template - inline static constexpr auto make_fmatrix() { - return make_fmatrix_impl( - lib::index_sequence<>{}, - lib::make_index_sequence::size()>{}...); - } -#else - template - struct make_fmatrix_impl { - template - struct impl; - - template - struct impl { - inline constexpr AUTO operator()() const - AUTO_RETURN(make_dispatch(Is{})) - }; - - template - struct impl, Ls...> { - inline constexpr AUTO operator()() const - AUTO_RETURN( - make_farray(impl, Ls...>{}()...)) - }; - }; - - template - inline static constexpr AUTO make_fmatrix() - AUTO_RETURN( - typename make_fmatrix_impl::template impl< - lib::index_sequence<>, - lib::make_index_sequence::size()>...>{}()) -#endif - }; // namespace base - - template - using FDiagonal = decltype(base::make_fdiagonal()); - - template - struct fdiagonal { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4268) -#endif - static constexpr FDiagonal value = - base::make_fdiagonal(); -#ifdef _MSC_VER -#pragma warning(pop) -#endif - }; - - template - constexpr FDiagonal fdiagonal::value; - - template - using FMatrix = decltype(base::make_fmatrix()); - - template - struct fmatrix { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4268) -#endif - static constexpr FMatrix value = - base::make_fmatrix(); -#ifdef _MSC_VER -#pragma warning(pop) -#endif - }; - - template - constexpr FMatrix fmatrix::value; - - struct alt { - template - inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, - Visitor &&visitor, - Vs &&... vs) - DECLTYPE_AUTO_RETURN(base::at( - fdiagonal(vs)))...>::value, - index)(lib::forward(visitor), - as_base(lib::forward(vs))...)) - - template - inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, - Vs &&... vs) - DECLTYPE_AUTO_RETURN(base::at( - fmatrix(vs)))...>::value, - vs.index()...)(lib::forward(visitor), - as_base(lib::forward(vs))...)) - }; - - struct variant { - private: - template - struct visit_exhaustive_visitor_check { - static_assert( - lib::is_invocable::value, - "`mpark::visit` requires the visitor to be exhaustive."); - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4100) -#endif - inline constexpr DECLTYPE_AUTO operator()(Visitor &&visitor, - Values &&... values) const - DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward(visitor), - lib::forward(values)...)) -#ifdef _MSC_VER -#pragma warning(pop) -#endif - }; - - template - struct value_visitor { - Visitor &&visitor_; - - template - inline constexpr DECLTYPE_AUTO operator()(Alts &&... alts) const - DECLTYPE_AUTO_RETURN( - visit_exhaustive_visitor_check< - Visitor, - decltype((lib::forward(alts).value))...>{}( - lib::forward(visitor_), - lib::forward(alts).value...)) - }; - - template - inline static constexpr AUTO make_value_visitor(Visitor &&visitor) - AUTO_RETURN(value_visitor{lib::forward(visitor)}) - - public: - template - inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, - Visitor &&visitor, - Vs &&... vs) - DECLTYPE_AUTO_RETURN( - alt::visit_alt_at(index, - lib::forward(visitor), - lib::forward(vs).impl_...)) - - template - inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, - Vs &&... vs) - DECLTYPE_AUTO_RETURN(alt::visit_alt(lib::forward(visitor), - lib::forward(vs).impl_...)) - - template - inline static constexpr DECLTYPE_AUTO visit_value_at(std::size_t index, - Visitor &&visitor, - Vs &&... vs) - DECLTYPE_AUTO_RETURN( - visit_alt_at(index, - make_value_visitor(lib::forward(visitor)), - lib::forward(vs)...)) - - template - inline static constexpr DECLTYPE_AUTO visit_value(Visitor &&visitor, - Vs &&... vs) - DECLTYPE_AUTO_RETURN( - visit_alt(make_value_visitor(lib::forward(visitor)), - lib::forward(vs)...)) - }; - - } // namespace visitation - - template - struct alt { - using value_type = T; - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4244) -#endif - template - inline explicit constexpr alt(in_place_t, Args &&... args) - : value(lib::forward(args)...) {} -#ifdef _MSC_VER -#pragma warning(pop) -#endif - - T value; - }; - - template - union recursive_union; - - template - union recursive_union {}; - -#define MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ - template \ - union recursive_union { \ - public: \ - inline explicit constexpr recursive_union(valueless_t) noexcept \ - : dummy_{} {} \ - \ - template \ - inline explicit constexpr recursive_union(in_place_index_t<0>, \ - Args &&... args) \ - : head_(in_place_t{}, lib::forward(args)...) {} \ - \ - template \ - inline explicit constexpr recursive_union(in_place_index_t, \ - Args &&... args) \ - : tail_(in_place_index_t{}, lib::forward(args)...) {} \ - \ - recursive_union(const recursive_union &) = default; \ - recursive_union(recursive_union &&) = default; \ - \ - destructor \ - \ - recursive_union &operator=(const recursive_union &) = default; \ - recursive_union &operator=(recursive_union &&) = default; \ - \ - private: \ - char dummy_; \ - alt head_; \ - recursive_union tail_; \ - \ - friend struct access::recursive_union; \ - } - - MPARK_VARIANT_RECURSIVE_UNION(Trait::TriviallyAvailable, - ~recursive_union() = default;); - MPARK_VARIANT_RECURSIVE_UNION(Trait::Available, - ~recursive_union() {}); - MPARK_VARIANT_RECURSIVE_UNION(Trait::Unavailable, - ~recursive_union() = delete;); - -#undef MPARK_VARIANT_RECURSIVE_UNION - - using index_t = unsigned int; - - template - class base { - public: - inline explicit constexpr base(valueless_t tag) noexcept - : data_(tag), index_(static_cast(-1)) {} - - template - inline explicit constexpr base(in_place_index_t, Args &&... args) - : data_(in_place_index_t{}, lib::forward(args)...), - index_(I) {} - - inline constexpr bool valueless_by_exception() const noexcept { - return index_ == static_cast(-1); - } - - inline constexpr std::size_t index() const noexcept { - return valueless_by_exception() ? variant_npos : index_; - } - - protected: - using data_t = recursive_union; - - friend inline constexpr base &as_base(base &b) { return b; } - friend inline constexpr const base &as_base(const base &b) { return b; } - friend inline constexpr base &&as_base(base &&b) { return lib::move(b); } - friend inline constexpr const base &&as_base(const base &&b) { return lib::move(b); } - - friend inline constexpr data_t &data(base &b) { return b.data_; } - friend inline constexpr const data_t &data(const base &b) { return b.data_; } - friend inline constexpr data_t &&data(base &&b) { return lib::move(b).data_; } - friend inline constexpr const data_t &&data(const base &&b) { return lib::move(b).data_; } - - inline static constexpr std::size_t size() { return sizeof...(Ts); } - - data_t data_; - index_t index_; - - friend struct access::base; - friend struct visitation::base; - }; - - struct dtor { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4100) -#endif - template - inline void operator()(Alt &alt) const noexcept { alt.~Alt(); } -#ifdef _MSC_VER -#pragma warning(pop) -#endif - }; - -#if defined(_MSC_VER) && _MSC_VER < 1910 -#define MPARK_INHERITING_CTOR(type, base) \ - template \ - inline explicit constexpr type(Args &&... args) \ - : base(lib::forward(args)...) {} -#else -#define MPARK_INHERITING_CTOR(type, base) using base::base; -#endif - - template - class destructor; - -#define MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ - template \ - class destructor, destructible_trait> \ - : public base { \ - using super = base; \ - \ - public: \ - MPARK_INHERITING_CTOR(destructor, super) \ - using super::operator=; \ - \ - destructor(const destructor &) = default; \ - destructor(destructor &&) = default; \ - definition \ - destructor &operator=(const destructor &) = default; \ - destructor &operator=(destructor &&) = default; \ - \ - protected: \ - destroy \ - } - - MPARK_VARIANT_DESTRUCTOR( - Trait::TriviallyAvailable, - ~destructor() = default;, - inline void destroy() noexcept { - this->index_ = static_cast(-1); - }); - - MPARK_VARIANT_DESTRUCTOR( - Trait::Available, - ~destructor() { destroy(); }, - inline void destroy() noexcept { - if (!this->valueless_by_exception()) { - visitation::alt::visit_alt(dtor{}, *this); - } - this->index_ = static_cast(-1); - }); - - MPARK_VARIANT_DESTRUCTOR( - Trait::Unavailable, - ~destructor() = delete;, - inline void destroy() noexcept = delete;); - -#undef MPARK_VARIANT_DESTRUCTOR - - template - class constructor : public destructor { - using super = destructor; - - public: - MPARK_INHERITING_CTOR(constructor, super) - using super::operator=; - - protected: -#ifndef MPARK_GENERIC_LAMBDAS - struct ctor { - template - inline void operator()(LhsAlt &lhs_alt, RhsAlt &&rhs_alt) const { - constructor::construct_alt(lhs_alt, - lib::forward(rhs_alt).value); - } - }; -#endif - - template - inline static T &construct_alt(alt &a, Args &&... args) { - ::new (static_cast(lib::addressof(a))) - alt(in_place_t{}, lib::forward(args)...); - return a.value; - } - - template - inline static void generic_construct(constructor &lhs, Rhs &&rhs) { - lhs.destroy(); - if (!rhs.valueless_by_exception()) { - visitation::alt::visit_alt_at( - rhs.index(), -#ifdef MPARK_GENERIC_LAMBDAS - [](auto &lhs_alt, auto &&rhs_alt) { - constructor::construct_alt( - lhs_alt, lib::forward(rhs_alt).value); - } -#else - ctor{} -#endif - , - lhs, - lib::forward(rhs)); - lhs.index_ = rhs.index_; - } - } - }; - - template - class move_constructor; - -#define MPARK_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, definition) \ - template \ - class move_constructor, move_constructible_trait> \ - : public constructor> { \ - using super = constructor>; \ - \ - public: \ - MPARK_INHERITING_CTOR(move_constructor, super) \ - using super::operator=; \ - \ - move_constructor(const move_constructor &) = default; \ - definition \ - ~move_constructor() = default; \ - move_constructor &operator=(const move_constructor &) = default; \ - move_constructor &operator=(move_constructor &&) = default; \ - } - - MPARK_VARIANT_MOVE_CONSTRUCTOR( - Trait::TriviallyAvailable, - move_constructor(move_constructor &&that) = default;); - - MPARK_VARIANT_MOVE_CONSTRUCTOR( - Trait::Available, - move_constructor(move_constructor &&that) noexcept( - lib::all::value...>::value) - : move_constructor(valueless_t{}) { - this->generic_construct(*this, lib::move(that)); - }); - - MPARK_VARIANT_MOVE_CONSTRUCTOR( - Trait::Unavailable, - move_constructor(move_constructor &&) = delete;); - -#undef MPARK_VARIANT_MOVE_CONSTRUCTOR - - template - class copy_constructor; - -#define MPARK_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, definition) \ - template \ - class copy_constructor, copy_constructible_trait> \ - : public move_constructor> { \ - using super = move_constructor>; \ - \ - public: \ - MPARK_INHERITING_CTOR(copy_constructor, super) \ - using super::operator=; \ - \ - definition \ - copy_constructor(copy_constructor &&) = default; \ - ~copy_constructor() = default; \ - copy_constructor &operator=(const copy_constructor &) = default; \ - copy_constructor &operator=(copy_constructor &&) = default; \ - } - - MPARK_VARIANT_COPY_CONSTRUCTOR( - Trait::TriviallyAvailable, - copy_constructor(const copy_constructor &that) = default;); - - MPARK_VARIANT_COPY_CONSTRUCTOR( - Trait::Available, - copy_constructor(const copy_constructor &that) - : copy_constructor(valueless_t{}) { - this->generic_construct(*this, that); - }); - - MPARK_VARIANT_COPY_CONSTRUCTOR( - Trait::Unavailable, - copy_constructor(const copy_constructor &) = delete;); - -#undef MPARK_VARIANT_COPY_CONSTRUCTOR - - template - class assignment : public copy_constructor { - using super = copy_constructor; - - public: - MPARK_INHERITING_CTOR(assignment, super) - using super::operator=; - - template - inline /* auto & */ auto emplace(Args &&... args) - -> decltype(this->construct_alt(access::base::get_alt(*this), - lib::forward(args)...)) { - this->destroy(); - auto &result = this->construct_alt(access::base::get_alt(*this), - lib::forward(args)...); - this->index_ = I; - return result; - } - - protected: -#ifndef MPARK_GENERIC_LAMBDAS - template - struct assigner { - template - inline void operator()(ThisAlt &this_alt, ThatAlt &&that_alt) const { - self->assign_alt(this_alt, lib::forward(that_alt).value); - } - assignment *self; - }; -#endif - - template - inline void assign_alt(alt &a, Arg &&arg) { - if (this->index() == I) { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4244) -#endif - a.value = lib::forward(arg); -#ifdef _MSC_VER -#pragma warning(pop) -#endif - } else { - struct { - void operator()(std::true_type) const { - this_->emplace(lib::forward(arg_)); - } - void operator()(std::false_type) const { - this_->emplace(T(lib::forward(arg_))); - } - assignment *this_; - Arg &&arg_; - } impl{this, lib::forward(arg)}; - impl(lib::bool_constant< - std::is_nothrow_constructible::value || - !std::is_nothrow_move_constructible::value>{}); - } - } - - template - inline void generic_assign(That &&that) { - if (this->valueless_by_exception() && that.valueless_by_exception()) { - // do nothing. - } else if (that.valueless_by_exception()) { - this->destroy(); - } else { - visitation::alt::visit_alt_at( - that.index(), -#ifdef MPARK_GENERIC_LAMBDAS - [this](auto &this_alt, auto &&that_alt) { - this->assign_alt( - this_alt, lib::forward(that_alt).value); - } -#else - assigner{this} -#endif - , - *this, - lib::forward(that)); - } - } - }; - - template - class move_assignment; - -#define MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ - template \ - class move_assignment, move_assignable_trait> \ - : public assignment> { \ - using super = assignment>; \ - \ - public: \ - MPARK_INHERITING_CTOR(move_assignment, super) \ - using super::operator=; \ - \ - move_assignment(const move_assignment &) = default; \ - move_assignment(move_assignment &&) = default; \ - ~move_assignment() = default; \ - move_assignment &operator=(const move_assignment &) = default; \ - definition \ - } - - MPARK_VARIANT_MOVE_ASSIGNMENT( - Trait::TriviallyAvailable, - move_assignment &operator=(move_assignment &&that) = default;); - - MPARK_VARIANT_MOVE_ASSIGNMENT( - Trait::Available, - move_assignment & - operator=(move_assignment &&that) noexcept( - lib::all<(std::is_nothrow_move_constructible::value && - std::is_nothrow_move_assignable::value)...>::value) { - this->generic_assign(lib::move(that)); - return *this; - }); - - MPARK_VARIANT_MOVE_ASSIGNMENT( - Trait::Unavailable, - move_assignment &operator=(move_assignment &&) = delete;); - -#undef MPARK_VARIANT_MOVE_ASSIGNMENT - - template - class copy_assignment; - -#define MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ - template \ - class copy_assignment, copy_assignable_trait> \ - : public move_assignment> { \ - using super = move_assignment>; \ - \ - public: \ - MPARK_INHERITING_CTOR(copy_assignment, super) \ - using super::operator=; \ - \ - copy_assignment(const copy_assignment &) = default; \ - copy_assignment(copy_assignment &&) = default; \ - ~copy_assignment() = default; \ - definition \ - copy_assignment &operator=(copy_assignment &&) = default; \ - } - - MPARK_VARIANT_COPY_ASSIGNMENT( - Trait::TriviallyAvailable, - copy_assignment &operator=(const copy_assignment &that) = default;); - - MPARK_VARIANT_COPY_ASSIGNMENT( - Trait::Available, - copy_assignment &operator=(const copy_assignment &that) { - this->generic_assign(that); - return *this; - }); - - MPARK_VARIANT_COPY_ASSIGNMENT( - Trait::Unavailable, - copy_assignment &operator=(const copy_assignment &) = delete;); - -#undef MPARK_VARIANT_COPY_ASSIGNMENT - - template - class impl : public copy_assignment> { - using super = copy_assignment>; - - public: - MPARK_INHERITING_CTOR(impl, super) - using super::operator=; - - template - inline void assign(Arg &&arg) { - this->assign_alt(access::base::get_alt(*this), - lib::forward(arg)); - } - - inline void swap(impl &that) { - if (this->valueless_by_exception() && that.valueless_by_exception()) { - // do nothing. - } else if (this->index() == that.index()) { - visitation::alt::visit_alt_at(this->index(), -#ifdef MPARK_GENERIC_LAMBDAS - [](auto &this_alt, auto &that_alt) { - using std::swap; - swap(this_alt.value, - that_alt.value); - } -#else - swapper{} -#endif - , - *this, - that); - } else { - impl *lhs = this; - impl *rhs = lib::addressof(that); - if (lhs->move_nothrow() && !rhs->move_nothrow()) { - std::swap(lhs, rhs); - } - impl tmp(lib::move(*rhs)); -#ifdef MPARK_EXCEPTIONS - // EXTENSION: When the move construction of `lhs` into `rhs` throws - // and `tmp` is nothrow move constructible then we move `tmp` back - // into `rhs` and provide the strong exception safety guarantee. - try { - this->generic_construct(*rhs, lib::move(*lhs)); - } catch (...) { - if (tmp.move_nothrow()) { - this->generic_construct(*rhs, lib::move(tmp)); - } - throw; - } -#else - this->generic_construct(*rhs, lib::move(*lhs)); -#endif - this->generic_construct(*lhs, lib::move(tmp)); - } - } - - private: -#ifndef MPARK_GENERIC_LAMBDAS - struct swapper { - template - inline void operator()(ThisAlt &this_alt, ThatAlt &that_alt) const { - using std::swap; - swap(this_alt.value, that_alt.value); - } - }; -#endif - - inline constexpr bool move_nothrow() const { - return this->valueless_by_exception() || - lib::array{ - {std::is_nothrow_move_constructible::value...} - }[this->index()]; - } - }; - -#undef MPARK_INHERITING_CTOR - - template - struct overload_leaf { - using F = lib::size_constant (*)(T); - operator F() const { return nullptr; } - }; - - template - struct overload_impl { - private: - template - struct impl; - - template - struct impl> : overload_leaf... {}; - - public: - using type = impl>; - }; - - template - using overload = typename overload_impl::type; - - template - using best_match = lib::invoke_result_t, T &&>; - - template - struct is_in_place_index : std::false_type {}; - - template - struct is_in_place_index> : std::true_type {}; - - template - struct is_in_place_type : std::false_type {}; - - template - struct is_in_place_type> : std::true_type {}; - - } // detail - - template - class variant { - static_assert(0 < sizeof...(Ts), - "variant must consist of at least one alternative."); - - static_assert(lib::all::value...>::value, - "variant can not have an array type as an alternative."); - - static_assert(lib::all::value...>::value, - "variant can not have a reference type as an alternative."); - - static_assert(lib::all::value...>::value, - "variant can not have a void type as an alternative."); - - public: - template < - typename Front = lib::type_pack_element_t<0, Ts...>, - lib::enable_if_t::value, int> = 0> - inline constexpr variant() noexcept( - std::is_nothrow_default_constructible::value) - : impl_(in_place_index_t<0>{}) {} - - variant(const variant &) = default; - variant(variant &&) = default; - - template < - typename Arg, - typename Decayed = lib::decay_t, - lib::enable_if_t::value, int> = 0, - lib::enable_if_t::value, int> = 0, - lib::enable_if_t::value, int> = 0, - std::size_t I = detail::best_match::value, - typename T = lib::type_pack_element_t, - lib::enable_if_t::value, int> = 0> - inline constexpr variant(Arg &&arg) noexcept( - std::is_nothrow_constructible::value) - : impl_(in_place_index_t{}, lib::forward(arg)) {} - - template < - std::size_t I, - typename... Args, - typename T = lib::type_pack_element_t, - lib::enable_if_t::value, int> = 0> - inline explicit constexpr variant( - in_place_index_t, - Args &&... args) noexcept(std::is_nothrow_constructible::value) - : impl_(in_place_index_t{}, lib::forward(args)...) {} - - template < - std::size_t I, - typename Up, - typename... Args, - typename T = lib::type_pack_element_t, - lib::enable_if_t &, - Args...>::value, - int> = 0> - inline explicit constexpr variant( - in_place_index_t, - std::initializer_list il, - Args &&... args) noexcept(std:: - is_nothrow_constructible< - T, - std::initializer_list &, - Args...>::value) - : impl_(in_place_index_t{}, il, lib::forward(args)...) {} - - template < - typename T, - typename... Args, - std::size_t I = detail::find_index_sfinae::value, - lib::enable_if_t::value, int> = 0> - inline explicit constexpr variant( - in_place_type_t, - Args &&... args) noexcept(std::is_nothrow_constructible::value) - : impl_(in_place_index_t{}, lib::forward(args)...) {} - - template < - typename T, - typename Up, - typename... Args, - std::size_t I = detail::find_index_sfinae::value, - lib::enable_if_t &, - Args...>::value, - int> = 0> - inline explicit constexpr variant( - in_place_type_t, - std::initializer_list il, - Args &&... args) noexcept(std:: - is_nothrow_constructible< - T, - std::initializer_list &, - Args...>::value) - : impl_(in_place_index_t{}, il, lib::forward(args)...) {} - - ~variant() = default; - - variant &operator=(const variant &) = default; - variant &operator=(variant &&) = default; - - template , variant>::value, - int> = 0, - std::size_t I = detail::best_match::value, - typename T = lib::type_pack_element_t, - lib::enable_if_t<(std::is_assignable::value && - std::is_constructible::value), - int> = 0> - inline variant &operator=(Arg &&arg) noexcept( - (std::is_nothrow_assignable::value && - std::is_nothrow_constructible::value)) { - impl_.template assign(lib::forward(arg)); - return *this; - } - - template < - std::size_t I, - typename... Args, - typename T = lib::type_pack_element_t, - lib::enable_if_t::value, int> = 0> - inline T &emplace(Args &&... args) { - return impl_.template emplace(lib::forward(args)...); - } - - template < - std::size_t I, - typename Up, - typename... Args, - typename T = lib::type_pack_element_t, - lib::enable_if_t &, - Args...>::value, - int> = 0> - inline T &emplace(std::initializer_list il, Args &&... args) { - return impl_.template emplace(il, lib::forward(args)...); - } - - template < - typename T, - typename... Args, - std::size_t I = detail::find_index_sfinae::value, - lib::enable_if_t::value, int> = 0> - inline T &emplace(Args &&... args) { - return impl_.template emplace(lib::forward(args)...); - } - - template < - typename T, - typename Up, - typename... Args, - std::size_t I = detail::find_index_sfinae::value, - lib::enable_if_t &, - Args...>::value, - int> = 0> - inline T &emplace(std::initializer_list il, Args &&... args) { - return impl_.template emplace(il, lib::forward(args)...); - } - - inline constexpr bool valueless_by_exception() const noexcept { - return impl_.valueless_by_exception(); - } - - inline constexpr std::size_t index() const noexcept { - return impl_.index(); - } - - template , - Dummy>::value && - lib::dependent_type, - Dummy>::value)...>::value, - int> = 0> - inline void swap(variant &that) noexcept( - lib::all<(std::is_nothrow_move_constructible::value && - lib::is_nothrow_swappable::value)...>::value) { - impl_.swap(that.impl_); - } - - private: - detail::impl impl_; - - friend struct detail::access::variant; - friend struct detail::visitation::variant; - }; - - template - inline constexpr bool holds_alternative(const variant &v) noexcept { - return v.index() == I; - } - - template - inline constexpr bool holds_alternative(const variant &v) noexcept { - return holds_alternative::value>(v); - } - - namespace detail { - template - struct generic_get_impl { - constexpr generic_get_impl(int) noexcept {} - - constexpr AUTO_REFREF operator()(V &&v) const - AUTO_REFREF_RETURN( - access::variant::get_alt(lib::forward(v)).value) - }; - - template - inline constexpr AUTO_REFREF generic_get(V &&v) - AUTO_REFREF_RETURN(generic_get_impl( - holds_alternative(v) ? 0 : (throw_bad_variant_access(), 0))( - lib::forward(v))) - } // namespace detail - - template - inline constexpr variant_alternative_t> &get( - variant &v) { - return detail::generic_get(v); - } - - template - inline constexpr variant_alternative_t> &&get( - variant &&v) { - return detail::generic_get(lib::move(v)); - } - - template - inline constexpr const variant_alternative_t> &get( - const variant &v) { - return detail::generic_get(v); - } - - template - inline constexpr const variant_alternative_t> &&get( - const variant &&v) { - return detail::generic_get(lib::move(v)); - } - - template - inline constexpr T &get(variant &v) { - return get::value>(v); - } - - template - inline constexpr T &&get(variant &&v) { - return get::value>(lib::move(v)); - } - - template - inline constexpr const T &get(const variant &v) { - return get::value>(v); - } - - template - inline constexpr const T &&get(const variant &&v) { - return get::value>(lib::move(v)); - } - - namespace detail { - - template - inline constexpr /* auto * */ AUTO generic_get_if(V *v) noexcept - AUTO_RETURN(v && holds_alternative(*v) - ? lib::addressof(access::variant::get_alt(*v).value) - : nullptr) - - } // namespace detail - - template - inline constexpr lib::add_pointer_t>> - get_if(variant *v) noexcept { - return detail::generic_get_if(v); - } - - template - inline constexpr lib::add_pointer_t< - const variant_alternative_t>> - get_if(const variant *v) noexcept { - return detail::generic_get_if(v); - } - - template - inline constexpr lib::add_pointer_t - get_if(variant *v) noexcept { - return get_if::value>(v); - } - - template - inline constexpr lib::add_pointer_t - get_if(const variant *v) noexcept { - return get_if::value>(v); - } - - namespace detail { - template - struct convert_to_bool { - template - inline constexpr bool operator()(Lhs &&lhs, Rhs &&rhs) const { - static_assert(std::is_convertible, - bool>::value, - "relational operators must return a type" - " implicitly convertible to bool"); - return lib::invoke( - RelOp{}, lib::forward(lhs), lib::forward(rhs)); - } - }; - } // namespace detail - - template - inline constexpr bool operator==(const variant &lhs, - const variant &rhs) { - using detail::visitation::variant; - using equal_to = detail::convert_to_bool; -#ifdef MPARK_CPP14_CONSTEXPR - if (lhs.index() != rhs.index()) return false; - if (lhs.valueless_by_exception()) return true; - return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); -#else - return lhs.index() == rhs.index() && - (lhs.valueless_by_exception() || - variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); -#endif - } - - template - inline constexpr bool operator!=(const variant &lhs, - const variant &rhs) { - using detail::visitation::variant; - using not_equal_to = detail::convert_to_bool; -#ifdef MPARK_CPP14_CONSTEXPR - if (lhs.index() != rhs.index()) return true; - if (lhs.valueless_by_exception()) return false; - return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); -#else - return lhs.index() != rhs.index() || - (!lhs.valueless_by_exception() && - variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); -#endif - } - - template - inline constexpr bool operator<(const variant &lhs, - const variant &rhs) { - using detail::visitation::variant; - using less = detail::convert_to_bool; -#ifdef MPARK_CPP14_CONSTEXPR - if (rhs.valueless_by_exception()) return false; - if (lhs.valueless_by_exception()) return true; - if (lhs.index() < rhs.index()) return true; - if (lhs.index() > rhs.index()) return false; - return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); -#else - return !rhs.valueless_by_exception() && - (lhs.valueless_by_exception() || lhs.index() < rhs.index() || - (lhs.index() == rhs.index() && - variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); -#endif - } - - template - inline constexpr bool operator>(const variant &lhs, - const variant &rhs) { - using detail::visitation::variant; - using greater = detail::convert_to_bool; -#ifdef MPARK_CPP14_CONSTEXPR - if (lhs.valueless_by_exception()) return false; - if (rhs.valueless_by_exception()) return true; - if (lhs.index() > rhs.index()) return true; - if (lhs.index() < rhs.index()) return false; - return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); -#else - return !lhs.valueless_by_exception() && - (rhs.valueless_by_exception() || lhs.index() > rhs.index() || - (lhs.index() == rhs.index() && - variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); -#endif - } - - template - inline constexpr bool operator<=(const variant &lhs, - const variant &rhs) { - using detail::visitation::variant; - using less_equal = detail::convert_to_bool; -#ifdef MPARK_CPP14_CONSTEXPR - if (lhs.valueless_by_exception()) return true; - if (rhs.valueless_by_exception()) return false; - if (lhs.index() < rhs.index()) return true; - if (lhs.index() > rhs.index()) return false; - return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); -#else - return lhs.valueless_by_exception() || - (!rhs.valueless_by_exception() && - (lhs.index() < rhs.index() || - (lhs.index() == rhs.index() && - variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); -#endif - } - - template - inline constexpr bool operator>=(const variant &lhs, - const variant &rhs) { - using detail::visitation::variant; - using greater_equal = detail::convert_to_bool; -#ifdef MPARK_CPP14_CONSTEXPR - if (rhs.valueless_by_exception()) return true; - if (lhs.valueless_by_exception()) return false; - if (lhs.index() > rhs.index()) return true; - if (lhs.index() < rhs.index()) return false; - return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); -#else - return rhs.valueless_by_exception() || - (!lhs.valueless_by_exception() && - (lhs.index() > rhs.index() || - (lhs.index() == rhs.index() && - variant::visit_value_at( - lhs.index(), greater_equal{}, lhs, rhs)))); -#endif - } - - struct monostate {}; - - inline constexpr bool operator<(monostate, monostate) noexcept { - return false; - } - - inline constexpr bool operator>(monostate, monostate) noexcept { - return false; - } - - inline constexpr bool operator<=(monostate, monostate) noexcept { - return true; - } - - inline constexpr bool operator>=(monostate, monostate) noexcept { - return true; - } - - inline constexpr bool operator==(monostate, monostate) noexcept { - return true; - } - - inline constexpr bool operator!=(monostate, monostate) noexcept { - return false; - } - -#ifdef MPARK_CPP14_CONSTEXPR - namespace detail { - - inline constexpr bool all(std::initializer_list bs) { - for (bool b : bs) { - if (!b) { - return false; - } - } - return true; - } - - } // namespace detail - - template - inline constexpr decltype(auto) visit(Visitor &&visitor, Vs &&... vs) { - return (detail::all({!vs.valueless_by_exception()...}) - ? (void)0 - : throw_bad_variant_access()), - detail::visitation::variant::visit_value( - lib::forward(visitor), lib::forward(vs)...); - } -#else - namespace detail { - - template - inline constexpr bool all_impl(const lib::array &bs, - std::size_t idx) { - return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); - } - - template - inline constexpr bool all(const lib::array &bs) { - return all_impl(bs, 0); - } - - } // namespace detail - - template - inline constexpr DECLTYPE_AUTO visit(Visitor &&visitor, Vs &&... vs) - DECLTYPE_AUTO_RETURN( - (detail::all( - lib::array{{!vs.valueless_by_exception()...}}) - ? (void)0 - : throw_bad_variant_access()), - detail::visitation::variant::visit_value(lib::forward(visitor), - lib::forward(vs)...)) -#endif - -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnoexcept" -#endif - template - inline auto swap(variant &lhs, - variant &rhs) noexcept(noexcept(lhs.swap(rhs))) - -> decltype(lhs.swap(rhs)) { - lhs.swap(rhs); - } -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif - - namespace detail { - - template - using enabled_type = T; - - namespace hash { - - template - constexpr bool meets_requirements() noexcept { - return std::is_copy_constructible::value && - std::is_move_constructible::value && - lib::is_invocable_r::value; - } - - template - constexpr bool is_enabled() noexcept { - using H = std::hash; - return meets_requirements() && - std::is_default_constructible::value && - std::is_copy_assignable::value && - std::is_move_assignable::value; - } - - } // namespace hash - - } // namespace detail - -#undef AUTO -#undef AUTO_RETURN - -#undef AUTO_REFREF -#undef AUTO_REFREF_RETURN - -#undef DECLTYPE_AUTO -#undef DECLTYPE_AUTO_RETURN - -} // namespace mpark - -namespace std { - - template - struct hash, - mpark::lib::enable_if_t>()...>::value>>> { - using argument_type = mpark::variant; - using result_type = std::size_t; - - inline result_type operator()(const argument_type &v) const { - using mpark::detail::visitation::variant; - std::size_t result = - v.valueless_by_exception() - ? 299792458 // Random value chosen by the universe upon creation - : variant::visit_alt( -#ifdef MPARK_GENERIC_LAMBDAS - [](const auto &alt) { - using alt_type = mpark::lib::decay_t; - using value_type = mpark::lib::remove_const_t< - typename alt_type::value_type>; - return hash{}(alt.value); - } -#else - hasher{} -#endif - , - v); - return hash_combine(result, hash{}(v.index())); - } - - private: -#ifndef MPARK_GENERIC_LAMBDAS - struct hasher { - template - inline std::size_t operator()(const Alt &alt) const { - using alt_type = mpark::lib::decay_t; - using value_type = - mpark::lib::remove_const_t; - return hash{}(alt.value); - } - }; -#endif - - static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { - return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); - } - }; - - template <> - struct hash { - using argument_type = mpark::monostate; - using result_type = std::size_t; - - inline result_type operator()(const argument_type &) const noexcept { - return 66740831; // return a fundamentally attractive random value. - } - }; - -} // namespace std - -#endif // MPARK_VARIANT_HPP From 9b36933c163641d40437bdfef69d4d3a3572a586 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 13 Mar 2019 16:21:51 +0000 Subject: [PATCH 1041/1783] Don't call setCoordinates(nullptr) in FakeMesh constructor Call in test fixtures/bodies instead. This allows the CELL_CENTRE Coordinates to be fully constructed in GridFromOptionsTest. --- tests/unit/field/test_field.cxx | 2 ++ tests/unit/field/test_field2d.cxx | 3 +++ tests/unit/field/test_field3d.cxx | 6 ++++++ tests/unit/field/test_field_factory.cxx | 1 + tests/unit/field/test_fieldperp.cxx | 2 ++ tests/unit/field/test_vector2d.cxx | 5 +++++ tests/unit/field/test_vector3d.cxx | 5 +++++ tests/unit/include/test_derivs.cxx | 1 + tests/unit/mesh/parallel/test_shiftedmetric.cxx | 1 + tests/unit/mesh/test_interpolation.cxx | 1 + tests/unit/test_extras.hxx | 4 ++-- 11 files changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/unit/field/test_field.cxx b/tests/unit/field/test_field.cxx index c84185696d..6ab0025627 100644 --- a/tests/unit/field/test_field.cxx +++ b/tests/unit/field/test_field.cxx @@ -31,6 +31,7 @@ TEST_F(FieldTest, GetGlobalMesh) { TEST_F(FieldTest, GetLocalMesh) { FakeMesh myMesh{nx + 1, ny + 2, nz + 3}; + myMesh.setCoordinates(nullptr); Field field(&myMesh, CELL_CENTRE, {YDirectionType::Standard, ZDirectionType::Standard}); auto localmesh = field.getMesh(); @@ -64,6 +65,7 @@ TEST_F(FieldTest, AreFieldsCompatibleFalseMesh) { Field field; FakeMesh myMesh{nx + 1, ny + 2, nz + 3}; + myMesh.setCoordinates(nullptr); // Create a field with all members set explicitly, and a non-default mesh Field field2{&myMesh, CELL_CENTRE, {YDirectionType::Standard, ZDirectionType::Standard}}; diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index 324851e8e5..3c06cda286 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -92,6 +92,7 @@ TEST_F(Field2DTest, CreateOnGivenMesh) { int test_nz = Field2DTest::nz + 2; FakeMesh fieldmesh{test_nx, test_ny, test_nz}; + fieldmesh.setCoordinates(nullptr); Field2D field{&fieldmesh}; @@ -106,6 +107,7 @@ TEST_F(Field2DTest, CopyCheckFieldmesh) { int test_nz = Field2DTest::nz + 2; FakeMesh fieldmesh{test_nx, test_ny, test_nz}; + fieldmesh.setCoordinates(nullptr); // createDefaultRegions is noisy WithQuietOutput quiet{output_info}; @@ -1136,6 +1138,7 @@ TEST_F(Field2DTest, Swap) { constexpr int second_nz = Field2DTest::nz + 2; FakeMesh second_mesh{second_nx, second_ny, second_nz}; + second_mesh.setCoordinates(nullptr); second_mesh.StaggerGrids = false; second_mesh.createDefaultRegions(); diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index a4d4c6d1b3..db567150d4 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -94,6 +94,7 @@ TEST_F(Field3DTest, CreateOnGivenMesh) { int test_nz = Field3DTest::nz + 2; FakeMesh fieldmesh{test_nx, test_ny, test_nz}; + fieldmesh.setCoordinates(nullptr); Field3D field{&fieldmesh}; @@ -110,6 +111,7 @@ TEST_F(Field3DTest, CopyCheckFieldmesh) { int test_nz = Field3DTest::nz + 2; FakeMesh fieldmesh{test_nx, test_ny, test_nz}; + fieldmesh.setCoordinates(nullptr); fieldmesh.createDefaultRegions(); Field3D field{0.0, &fieldmesh}; @@ -256,6 +258,7 @@ TEST_F(Field3DTest, SplitThenMergeYupYDown) { TEST_F(Field3DTest, MultipleYupYdown) { FakeMesh newmesh{3, 5, 7}; + newmesh.setCoordinates(nullptr); newmesh.ystart = 2; newmesh.createDefaultRegions(); @@ -326,6 +329,8 @@ TEST_F(Field3DTest, GetGlobalMesh) { TEST_F(Field3DTest, GetLocalMesh) { FakeMesh myMesh{nx + 1, ny + 2, nz + 3}; + myMesh.setCoordinates(nullptr); + Field3D field(&myMesh); auto localmesh = field.getMesh(); @@ -1907,6 +1912,7 @@ TEST_F(Field3DTest, Swap) { constexpr int second_nz = Field3DTest::nz + 2; FakeMesh second_mesh{second_nx, second_ny, second_nz}; + second_mesh.setCoordinates(nullptr); second_mesh.StaggerGrids = false; second_mesh.createDefaultRegions(); diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index 1a943a7410..910512ca2e 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -554,6 +554,7 @@ TYPED_TEST(FieldFactoryCreationTest, CreateOnMesh) { constexpr auto nz = int{1}; FakeMesh localmesh{nx, ny, nz}; + localmesh.setCoordinates(nullptr); localmesh.createDefaultRegions(); localmesh.setParallelTransform( bout::utils::make_unique(localmesh)); diff --git a/tests/unit/field/test_fieldperp.cxx b/tests/unit/field/test_fieldperp.cxx index b89d698707..47412fb1ba 100644 --- a/tests/unit/field/test_fieldperp.cxx +++ b/tests/unit/field/test_fieldperp.cxx @@ -113,6 +113,7 @@ TEST_F(FieldPerpTest, CreateOnGivenMesh) { int test_nz = FieldPerpTest::nz + 2; FakeMesh fieldmesh{test_nx, test_ny, test_nz}; + fieldmesh.setCoordinates(nullptr); fieldmesh.createDefaultRegions(); FieldPerp field{&fieldmesh}; @@ -132,6 +133,7 @@ TEST_F(FieldPerpTest, CopyCheckFieldmesh) { int test_nz = FieldPerpTest::nz + 2; FakeMesh fieldmesh{test_nx, test_ny, test_nz}; + fieldmesh.setCoordinates(nullptr); fieldmesh.createDefaultRegions(); FieldPerp field{&fieldmesh}; diff --git a/tests/unit/field/test_vector2d.cxx b/tests/unit/field/test_vector2d.cxx index 7e091f01cb..ed9cc3a239 100644 --- a/tests/unit/field/test_vector2d.cxx +++ b/tests/unit/field/test_vector2d.cxx @@ -35,6 +35,7 @@ class Vector2DTest : public ::testing::Test { mesh = nullptr; } mesh = new FakeMesh(nx, ny, nz); + static_cast(mesh)->setCoordinates(nullptr); mesh->createDefaultRegions(); mesh->addBoundary(new BoundaryRegionXIn("core", 1, ny - 2, mesh)); @@ -51,6 +52,7 @@ class Vector2DTest : public ::testing::Test { delete mesh_staggered; mesh_staggered = new FakeMesh(nx, ny, nz); mesh_staggered->StaggerGrids = true; + static_cast(mesh_staggered)->setCoordinates(nullptr); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); mesh_staggered->createDefaultRegions(); } @@ -170,6 +172,7 @@ TEST_F(Vector2DTest, SetLocationXLOW) { TEST_F(Vector2DTest, SetLocationYLOW) { FakeMesh local_mesh{Vector2DTest::nx,Vector2DTest::ny,Vector2DTest::nz}; + local_mesh.setCoordinates(nullptr); local_mesh.StaggerGrids = true; local_mesh.setCoordinates(nullptr, CELL_YLOW); Vector2D vector(&local_mesh); @@ -184,6 +187,7 @@ TEST_F(Vector2DTest, SetLocationYLOW) { TEST_F(Vector2DTest, SetLocationZLOW) { FakeMesh local_mesh{Vector2DTest::nx,Vector2DTest::ny,Vector2DTest::nz}; + local_mesh.setCoordinates(nullptr); local_mesh.StaggerGrids = true; local_mesh.setCoordinates(nullptr, CELL_ZLOW); Vector2D vector(&local_mesh); @@ -198,6 +202,7 @@ TEST_F(Vector2DTest, SetLocationZLOW) { TEST_F(Vector2DTest, SetLocationVSHIFT) { FakeMesh local_mesh{Vector2DTest::nx,Vector2DTest::ny,Vector2DTest::nz}; + local_mesh.setCoordinates(nullptr); local_mesh.StaggerGrids = true; local_mesh.setCoordinates(nullptr, CELL_XLOW); local_mesh.setCoordinates(nullptr, CELL_YLOW); diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index 8b4af337c9..1e437012d6 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -34,6 +34,7 @@ class Vector3DTest : public ::testing::Test { mesh = nullptr; } mesh = new FakeMesh(nx, ny, nz); + static_cast(mesh)->setCoordinates(nullptr); mesh->createDefaultRegions(); mesh->addBoundary(new BoundaryRegionXIn("core", 1, ny - 2, mesh)); @@ -50,6 +51,7 @@ class Vector3DTest : public ::testing::Test { delete mesh_staggered; mesh_staggered = new FakeMesh(nx, ny, nz); mesh_staggered->StaggerGrids = true; + static_cast(mesh_staggered)->setCoordinates(nullptr); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); mesh_staggered->createDefaultRegions(); } @@ -169,6 +171,7 @@ TEST_F(Vector3DTest, SetLocationXLOW) { TEST_F(Vector3DTest, SetLocationYLOW) { FakeMesh local_mesh{Vector3DTest::nx,Vector3DTest::ny,Vector3DTest::nz}; + local_mesh.setCoordinates(nullptr); local_mesh.StaggerGrids = true; local_mesh.setCoordinates(nullptr, CELL_YLOW); Vector3D vector(&local_mesh); @@ -183,6 +186,7 @@ TEST_F(Vector3DTest, SetLocationYLOW) { TEST_F(Vector3DTest, SetLocationZLOW) { FakeMesh local_mesh{Vector3DTest::nx,Vector3DTest::ny,Vector3DTest::nz}; + local_mesh.setCoordinates(nullptr); local_mesh.StaggerGrids = true; local_mesh.setCoordinates(nullptr, CELL_ZLOW); Vector3D vector(&local_mesh); @@ -197,6 +201,7 @@ TEST_F(Vector3DTest, SetLocationZLOW) { TEST_F(Vector3DTest, SetLocationVSHIFT) { FakeMesh local_mesh{Vector3DTest::nx,Vector3DTest::ny,Vector3DTest::nz}; + local_mesh.setCoordinates(nullptr); local_mesh.StaggerGrids = true; local_mesh.setCoordinates(nullptr, CELL_XLOW); local_mesh.setCoordinates(nullptr, CELL_YLOW); diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index 7bcb73e759..14a260d340 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -93,6 +93,7 @@ class DerivativesTest } mesh = new FakeMesh(nx, ny, nz); + static_cast(mesh)->setCoordinates(nullptr); mesh->xstart = x_guards; mesh->xend = nx - (x_guards + 1); diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index e9a5d99d79..fef7bdbfe1 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -20,6 +20,7 @@ class ShiftedMetricTest : public ::testing::Test { delete mesh; mesh = new FakeMesh(nx, ny, nz); + static_cast(mesh)->setCoordinates(nullptr); // Use two y-guards to test multiple parallel slices mesh->ystart = 2; diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index 79fce6e5c6..e73b57ce1b 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -57,6 +57,7 @@ class Field3DInterpToTest : public ::testing::Test { mesh->ystart = 2; mesh->xend = nx - 3; mesh->yend = ny - 3; + static_cast(mesh)->setCoordinates(nullptr); static_cast(mesh)->setCoordinates(nullptr, CELL_XLOW); static_cast(mesh)->setCoordinates(nullptr, CELL_YLOW); static_cast(mesh)->setCoordinates(nullptr, CELL_ZLOW); diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 8888d8d789..27e0a041db 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -169,8 +169,6 @@ public: StaggerGrids = false; IncIntShear = false; maxregionblocksize = MAXREGIONBLOCKSIZE; - - setCoordinates(nullptr); } void setCoordinates(std::shared_ptr coords, CELL_LOC location = CELL_CENTRE) { @@ -277,6 +275,7 @@ public: delete bout::globals::mesh; bout::globals::mesh = new FakeMesh(nx, ny, nz); + static_cast(bout::globals::mesh)->setCoordinates(nullptr); bout::globals::mesh->setParallelTransform( bout::utils::make_unique(*bout::globals::mesh)); bout::globals::mesh->createDefaultRegions(); @@ -286,6 +285,7 @@ public: mesh_staggered->StaggerGrids = true; mesh_staggered->setParallelTransform( bout::utils::make_unique(*mesh_staggered)); + static_cast(mesh_staggered)->setCoordinates(nullptr); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_YLOW); static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_ZLOW); From 2895893353498cd5b751acea591b651de8bc1874 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 13 Mar 2019 20:38:11 +0000 Subject: [PATCH 1042/1783] Extend test_gridfromoptions.cxx: test staggered Coordinates init --- tests/unit/mesh/data/test_gridfromoptions.cxx | 359 ++++++++++++++---- tests/unit/test_extras.hxx | 12 + 2 files changed, 290 insertions(+), 81 deletions(-) diff --git a/tests/unit/mesh/data/test_gridfromoptions.cxx b/tests/unit/mesh/data/test_gridfromoptions.cxx index ed3fe5ca32..add3ae8d3b 100644 --- a/tests/unit/mesh/data/test_gridfromoptions.cxx +++ b/tests/unit/mesh/data/test_gridfromoptions.cxx @@ -11,56 +11,98 @@ #include #include -/// Global mesh -namespace bout { -namespace globals { -extern Mesh* mesh; -} // namespace globals -} // namespace bout - // The unit tests use the global mesh using namespace bout::globals; class GridFromOptionsTest : public FakeMeshFixture { public: - GridFromOptionsTest() : FakeMeshFixture(), options(), griddata(&options) { + GridFromOptionsTest() : FakeMeshFixture(), options(), griddata(nullptr) { + + mesh_from_options.StaggerGrids = true; + mesh_from_options.xstart = 2; + mesh_from_options.xend = nx - 3; + mesh_from_options.ystart = 2; + mesh_from_options.yend = ny - 3; + + mesh_from_options.createDefaultRegions(); + // We need a parallel transform as FieldFactory::create3D wants to // un-field-align the result - mesh->setParallelTransform( - bout::utils::make_unique(*mesh)); + mesh_from_options.setParallelTransform( + bout::utils::make_unique(mesh_from_options)); + + griddata = new GridFromOptions(&options); + mesh_from_options.setGridDataSource(griddata); output_info.disable(); + output_progress.disable(); output_warn.disable(); options["f"] = expected_string; + + // modify mesh section in global options + options["dx"] = "1."; + options["dy"] = "1."; + options["g11"] = expected_string + " + 5."; + options["g22"] = expected_string + " + 4."; + options["g33"] = expected_string + " + 3."; + options["g12"] = expected_string + " + 2."; + options["g13"] = expected_string + " + 1."; + options["g23"] = expected_string; + + mesh_from_options.getCoordinates(); + + expected_2d = {makeField( + [](Field2D::ind_type& index) { + return index.x() + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; + }, + &mesh_from_options)}; + + expected_3d = {makeField( + [](Field3D::ind_type& index) { + return index.x() + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; + }, + &mesh_from_options)}; } ~GridFromOptionsTest() { Options::cleanup(); output_info.enable(); + output_progress.enable(); output_warn.enable(); + // note GridFromOptions* griddata will be deleted by the ~Mesh() destructor } + static const int nx{9}; + static const int ny{11}; + static const int nz{5}; + Options options; - GridFromOptions griddata; + GridFromOptions* griddata; std::string expected_string{"x + y + z + 3"}; + Field2D expected_2d; + Field3D expected_3d; + FakeMesh mesh_from_options{nx, ny, nz}; }; +// higher tolerance used when field values are ~50 +static constexpr BoutReal this_tolerance{1e-13}; + TEST_F(GridFromOptionsTest, HasVar) { - EXPECT_TRUE(griddata.hasVar("f")); - EXPECT_FALSE(griddata.hasVar("non-existent")); + EXPECT_TRUE(griddata->hasVar("f")); + EXPECT_FALSE(griddata->hasVar("non-existent")); } TEST_F(GridFromOptionsTest, GetString) { std::string result{"wrong"}; - EXPECT_TRUE(griddata.get(mesh, result, "f")); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f")); EXPECT_EQ(result, expected_string); } TEST_F(GridFromOptionsTest, GetStringNone) { std::string result{"wrong"}; - EXPECT_FALSE(griddata.get(mesh, result, "non-existent")); + EXPECT_FALSE(griddata->get(&mesh_from_options, result, "non-existent")); EXPECT_EQ(result, std::string{}); } @@ -68,7 +110,7 @@ TEST_F(GridFromOptionsTest, GetInt) { int result{-1}; int expected{3}; - EXPECT_TRUE(griddata.get(mesh, result, "f")); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f")); EXPECT_EQ(result, expected); } @@ -76,7 +118,7 @@ TEST_F(GridFromOptionsTest, GetIntNone) { int result{-1}; int expected{0}; - EXPECT_FALSE(griddata.get(mesh, result, "non-existent")); + EXPECT_FALSE(griddata->get(&mesh_from_options, result, "non-existent")); EXPECT_EQ(result, expected); } @@ -84,7 +126,7 @@ TEST_F(GridFromOptionsTest, GetBoutReal) { BoutReal result{-1.}; BoutReal expected{3.}; - EXPECT_TRUE(griddata.get(mesh, result, "f")); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f")); EXPECT_EQ(result, expected); } @@ -92,70 +134,60 @@ TEST_F(GridFromOptionsTest, GetBoutRealNone) { BoutReal result{-1.}; BoutReal expected{0}; - EXPECT_FALSE(griddata.get(mesh, result, "non-existent")); + EXPECT_FALSE(griddata->get(&mesh_from_options, result, "non-existent")); EXPECT_EQ(result, expected); } TEST_F(GridFromOptionsTest, GetField2D) { - Field2D result{mesh}; - Field2D expected{makeField( - [](Field2D::ind_type& index) { - return index.x() + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; - }, - mesh)}; + Field2D result{&mesh_from_options}; - EXPECT_TRUE(griddata.get(mesh, result, "f")); - EXPECT_TRUE(IsFieldEqual(result, expected)); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f")); + EXPECT_TRUE(IsFieldEqual(result, expected_2d)); } TEST_F(GridFromOptionsTest, GetField2DNone) { - Field2D result{mesh}; + Field2D result{&mesh_from_options}; BoutReal expected{0.}; - EXPECT_FALSE(griddata.get(mesh, result, "non-existent")); + EXPECT_FALSE(griddata->get(&mesh_from_options, result, "non-existent")); EXPECT_TRUE(IsFieldEqual(result, expected)); } TEST_F(GridFromOptionsTest, GetField2DNoneWithDefault) { - Field2D result{mesh}; + Field2D result{&mesh_from_options}; BoutReal default_value{-32}; - EXPECT_FALSE(griddata.get(mesh, result, "non-existent", default_value)); + EXPECT_FALSE(griddata->get(&mesh_from_options, result, "non-existent", default_value)); EXPECT_TRUE(IsFieldEqual(result, default_value)); } TEST_F(GridFromOptionsTest, GetField3D) { - Field3D result{mesh}; - Field3D expected{makeField( - [](Field3D::ind_type& index) { - return index.x() + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; - }, - mesh)}; + Field3D result{&mesh_from_options}; - EXPECT_TRUE(griddata.get(mesh, result, "f")); - EXPECT_TRUE(IsFieldEqual(result, expected)); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f")); + EXPECT_TRUE(IsFieldEqual(result, expected_3d)); - EXPECT_FALSE(griddata.get(mesh, result, "non-existent")); + EXPECT_FALSE(griddata->get(&mesh_from_options, result, "non-existent")); EXPECT_TRUE(IsFieldEqual(result, 0.)); BoutReal default_value{-64}; - EXPECT_FALSE(griddata.get(mesh, result, "non-existent", default_value)); + EXPECT_FALSE(griddata->get(&mesh_from_options, result, "non-existent", default_value)); EXPECT_TRUE(IsFieldEqual(result, default_value)); } TEST_F(GridFromOptionsTest, GetField3DNone) { - Field3D result{mesh}; + Field3D result{&mesh_from_options}; BoutReal expected{0.}; - EXPECT_FALSE(griddata.get(mesh, result, "non-existent")); + EXPECT_FALSE(griddata->get(&mesh_from_options, result, "non-existent")); EXPECT_TRUE(IsFieldEqual(result, expected)); } TEST_F(GridFromOptionsTest, GetField3DNoneWithDefault) { - Field3D result{mesh}; + Field3D result{&mesh_from_options}; BoutReal default_value{-64}; - EXPECT_FALSE(griddata.get(mesh, result, "non-existent", default_value)); + EXPECT_FALSE(griddata->get(&mesh_from_options, result, "non-existent", default_value)); EXPECT_TRUE(IsFieldEqual(result, default_value)); } @@ -163,7 +195,7 @@ TEST_F(GridFromOptionsTest, GetVectorInt) { std::vector result{}; std::vector expected{3, 3, 3}; - EXPECT_TRUE(griddata.get(mesh, result, "f", 3)); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f", 3)); EXPECT_EQ(result, expected); } @@ -171,80 +203,86 @@ TEST_F(GridFromOptionsTest, GetVectorIntNone) { std::vector result{-1, -1, -1}; std::vector expected{}; - EXPECT_FALSE(griddata.get(mesh, result, "non-existent", 3)); + EXPECT_FALSE(griddata->get(&mesh_from_options, result, "non-existent", 3)); EXPECT_EQ(result, expected); } TEST_F(GridFromOptionsTest, GetVectorBoutRealX) { std::vector result{}; - std::vector expected{3., 4., 5.}; + std::vector expected{3., 4., 5., 6., 7., 8., 9., 10., 11.}; - EXPECT_TRUE(griddata.get(mesh, result, "f", nx)); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f", nx)); EXPECT_EQ(result, expected); } TEST_F(GridFromOptionsTest, GetVectorBoutRealXOffset) { std::vector result{}; - std::vector expected{4., 5., 6.}; + std::vector expected{4., 5., 6., 7., 8., 9., 10., 11., 12.}; - EXPECT_TRUE(griddata.get(mesh, result, "f", nx, 1, GridDataSource::Direction::X)); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f", nx, 1, GridDataSource::Direction::X)); EXPECT_EQ(result, expected); } TEST_F(GridFromOptionsTest, GetVectorBoutRealXMeshOffset) { std::vector result{}; - std::vector expected{2., 3., 4.}; + std::vector expected{2., 3., 4., 5., 6., 7., 8., 9., 10.}; - mesh->OffsetX = 1; - mesh->OffsetY = 100; - mesh->OffsetZ = 100; + mesh_from_options.OffsetX = 1; + mesh_from_options.OffsetY = 100; + mesh_from_options.OffsetZ = 100; - EXPECT_TRUE(griddata.get(mesh, result, "f", nx, 0, GridDataSource::Direction::X)); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f", nx, 0, GridDataSource::Direction::X)); EXPECT_EQ(result, expected); } TEST_F(GridFromOptionsTest, GetVectorBoutRealXNone) { std::vector result{}; std::vector default_expected{}; - EXPECT_FALSE(griddata.get(mesh, result, "non-existent", nx)); + EXPECT_FALSE(griddata->get(&mesh_from_options, result, "non-existent", nx)); EXPECT_EQ(result, default_expected); } TEST_F(GridFromOptionsTest, GetVectorBoutRealY) { std::vector result{}; std::vector expected{3., 3. + TWOPI, 3. + (2. * TWOPI), 3. + (3. * TWOPI), - 3. + (4. * TWOPI)}; + 3. + (4. * TWOPI), 3. + (5. * TWOPI), 3. + (6. * TWOPI), + 3. + (7. * TWOPI), 3. + (8. * TWOPI), 3. + (9. * TWOPI), + 3. + (10. * TWOPI)}; - EXPECT_TRUE(griddata.get(mesh, result, "f", ny, 0, GridDataSource::Direction::Y)); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f", ny, 0, GridDataSource::Direction::Y)); EXPECT_EQ(result, expected); } TEST_F(GridFromOptionsTest, GetVectorBoutRealYOffset) { std::vector result{}; std::vector expected{3. + TWOPI, 3. + (2. * TWOPI), 3. + (3. * TWOPI), - 3. + (4. * TWOPI), 3. + (5. * TWOPI)}; + 3. + (4. * TWOPI), 3. + (5. * TWOPI), 3. + (6. * TWOPI), + 3. + (7. * TWOPI), 3. + (8. * TWOPI), 3. + (9. * TWOPI), + 3. + (10. * TWOPI), 3. + (11. * TWOPI)}; - EXPECT_TRUE(griddata.get(mesh, result, "f", ny, 1, GridDataSource::Direction::Y)); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f", ny, 1, GridDataSource::Direction::Y)); EXPECT_EQ(result, expected); } TEST_F(GridFromOptionsTest, GetVectorBoutRealYMeshOffset) { std::vector result{}; std::vector expected{3. - TWOPI, 3., 3. + TWOPI, 3. + (2. * TWOPI), - 3. + (3. * TWOPI)}; + 3. + (3. * TWOPI), 3. + (4. * TWOPI), 3. + (5. * TWOPI), + 3. + (6. * TWOPI), 3. + (7. * TWOPI), 3. + (8. * TWOPI), + 3. + (9. * TWOPI)}; - mesh->OffsetX = 100; - mesh->OffsetY = 1; - mesh->OffsetZ = 100; + mesh_from_options.OffsetX = 100; + mesh_from_options.OffsetY = 1; + mesh_from_options.OffsetZ = 100; - EXPECT_TRUE(griddata.get(mesh, result, "f", ny, 0, GridDataSource::Direction::Y)); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f", ny, 0, GridDataSource::Direction::Y)); EXPECT_EQ(result, expected); } TEST_F(GridFromOptionsTest, GetVectorBoutRealYNone) { std::vector result{}; std::vector default_expected{}; - EXPECT_FALSE(griddata.get(mesh, result, "non-existent", ny)); + EXPECT_FALSE(griddata->get(&mesh_from_options, result, "non-existent", ny)); EXPECT_EQ(result, default_expected); } @@ -254,11 +292,9 @@ TEST_F(GridFromOptionsTest, GetVectorBoutRealZ) { 3. + (1. * TWOPI / nz), 3. + (2. * TWOPI / nz), 3. + (3. * TWOPI / nz), - 3. + (4. * TWOPI / nz), - 3. + (5. * TWOPI / nz), - 3. + (6. * TWOPI / nz)}; + 3. + (4. * TWOPI / nz)}; - EXPECT_TRUE(griddata.get(mesh, result, "f", nz, 0, GridDataSource::Direction::Z)); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f", nz, 0, GridDataSource::Direction::Z)); EXPECT_EQ(result, expected); } @@ -266,10 +302,9 @@ TEST_F(GridFromOptionsTest, GetVectorBoutRealZOffset) { std::vector result{}; std::vector expected{3. + (1. * TWOPI / nz), 3. + (2. * TWOPI / nz), 3. + (3. * TWOPI / nz), 3. + (4. * TWOPI / nz), - 3. + (5. * TWOPI / nz), 3. + (6. * TWOPI / nz), - 3. + (7. * TWOPI / nz)}; + 3. + (5. * TWOPI / nz)}; - EXPECT_TRUE(griddata.get(mesh, result, "f", nz, 1, GridDataSource::Direction::Z)); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f", nz, 1, GridDataSource::Direction::Z)); EXPECT_EQ(result, expected); } @@ -277,20 +312,182 @@ TEST_F(GridFromOptionsTest, GetVectorBoutRealZMeshOffset) { std::vector result{}; std::vector expected{3. + (-1. * TWOPI / nz), 3., 3. + (1. * TWOPI / nz), 3. + (2. * TWOPI / nz), - 3. + (3. * TWOPI / nz), 3. + (4. * TWOPI / nz), - 3. + (5. * TWOPI / nz)}; + 3. + (3. * TWOPI / nz)}; - mesh->OffsetX = 100; - mesh->OffsetY = 100; - mesh->OffsetZ = 1; + mesh_from_options.OffsetX = 100; + mesh_from_options.OffsetY = 100; + mesh_from_options.OffsetZ = 1; - EXPECT_TRUE(griddata.get(mesh, result, "f", nz, 0, GridDataSource::Direction::Z)); + EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f", nz, 0, GridDataSource::Direction::Z)); EXPECT_EQ(result, expected); } TEST_F(GridFromOptionsTest, GetVectorBoutRealZNone) { std::vector result{}; std::vector default_expected{}; - EXPECT_FALSE(griddata.get(mesh, result, "non-existent", nz)); + EXPECT_FALSE(griddata->get(&mesh_from_options, result, "non-existent", nz)); EXPECT_EQ(result, default_expected); } + +TEST_F(GridFromOptionsTest, CoordinatesCentre) { + auto coords = mesh_from_options.getCoordinates(); + + mesh_from_options.communicate(expected_2d); + + EXPECT_TRUE(IsFieldEqual(coords->g11, expected_2d + 5.)); + EXPECT_TRUE(IsFieldEqual(coords->g22, expected_2d + 4.)); + EXPECT_TRUE(IsFieldEqual(coords->g33, expected_2d + 3.)); + EXPECT_TRUE(IsFieldEqual(coords->g12, expected_2d + 2.)); + EXPECT_TRUE(IsFieldEqual(coords->g13, expected_2d + 1.)); + EXPECT_TRUE(IsFieldEqual(coords->g23, expected_2d)); +} + +TEST_F(GridFromOptionsTest, CoordinatesZlow) { + auto coords = mesh_from_options.getCoordinates(CELL_ZLOW); + + mesh_from_options.communicate(expected_2d); + + EXPECT_TRUE(IsFieldEqual(coords->g11, expected_2d + 5.)); + EXPECT_TRUE(IsFieldEqual(coords->g22, expected_2d + 4.)); + EXPECT_TRUE(IsFieldEqual(coords->g33, expected_2d + 3.)); + EXPECT_TRUE(IsFieldEqual(coords->g12, expected_2d + 2.)); + EXPECT_TRUE(IsFieldEqual(coords->g13, expected_2d + 1.)); + EXPECT_TRUE(IsFieldEqual(coords->g23, expected_2d)); +} + +TEST_F(GridFromOptionsTest, CoordinatesXlowInterp) { + // *_xlow fields not present in options, Coordinates will be interpolated + // from CELL_CENTRE + + // make the mesh have boundaries to avoid NaNs in guard cells after interpolating + mesh_from_options.createBoundaries(); + + auto coords = mesh_from_options.getCoordinates(CELL_XLOW); + + Field2D expected_xlow = {makeField( + [](Field2D::ind_type& index) { + return index.x() - 0.5 + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; + }, + &mesh_from_options)}; + + mesh_from_options.communicate(expected_xlow); + + EXPECT_TRUE(IsFieldEqual(coords->g11, expected_xlow + 5., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g22, expected_xlow + 4., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g33, expected_xlow + 3., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g12, expected_xlow + 2., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g13, expected_xlow + 1., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g23, expected_xlow, "RGN_NOBNDRY", this_tolerance)); +} + +TEST_F(GridFromOptionsTest, CoordinatesXlowRead) { + // *_xlow fields added to options, will be read to initialise Coordinates + + // Note '(9 - x)' here because FakeMesh::GlobalX(int jx) returns jx, not a + // global position between 0 and 1 (in grid cells, <0 or >1 in boundaries), + // like a Mesh is supposed to. + std::string expected_string_xlow{"(9 - x) + y + 3"}; + + // modify mesh section in global options + options["dx_xlow"] = "1."; + options["dy_xlow"] = "1."; + options["g11_xlow"] = expected_string_xlow + " + 5."; + options["g22_xlow"] = expected_string_xlow + " + 4."; + options["g33_xlow"] = expected_string_xlow + " + 3."; + options["g12_xlow"] = expected_string_xlow + " + 2."; + options["g13_xlow"] = expected_string_xlow + " + 1."; + options["g23_xlow"] = expected_string_xlow; + + auto coords = mesh_from_options.getCoordinates(CELL_XLOW); + + Field2D expected_xlow = {makeField( + [](Field2D::ind_type& index) { + return (nx - index.x()) + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; + }, + &mesh_from_options)}; + + mesh_from_options.communicate(expected_xlow); + + EXPECT_TRUE(IsFieldEqual(coords->g11, expected_xlow + 5.)); + EXPECT_TRUE(IsFieldEqual(coords->g22, expected_xlow + 4.)); + EXPECT_TRUE(IsFieldEqual(coords->g33, expected_xlow + 3.)); + EXPECT_TRUE(IsFieldEqual(coords->g12, expected_xlow + 2.)); + EXPECT_TRUE(IsFieldEqual(coords->g13, expected_xlow + 1.)); + EXPECT_TRUE(IsFieldEqual(coords->g23, expected_xlow)); +} + +TEST_F(GridFromOptionsTest, CoordinatesYlowInterp) { + // *_ylow fields not present in options, Coordinates will be interpolated + // from CELL_CENTRE + + // make the mesh have boundaries to avoid NaNs in guard cells after interpolating + mesh_from_options.createBoundaries(); + + auto coords = mesh_from_options.getCoordinates(CELL_XLOW); + + Field2D expected_ylow = {makeField( + [](Field2D::ind_type& index) { + return index.x() + (TWOPI * index.y() - 0.5) + (TWOPI * index.z() / nz) + 3; + }, + &mesh_from_options)}; + + mesh_from_options.communicate(expected_ylow); + + EXPECT_TRUE(IsFieldEqual(coords->g11, expected_ylow + 5., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g22, expected_ylow + 4., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g33, expected_ylow + 3., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g12, expected_ylow + 2., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g13, expected_ylow + 1., "RGN_NOBNDRY", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g23, expected_ylow, "RGN_NOBNDRY", this_tolerance)); +} + +TEST_F(GridFromOptionsTest, CoordinatesYlowRead) { + // *_ylow fields added to options, will be read to initialise Coordinates + + // Note '(2*pi*11 - y)' here because FakeMesh::GlobalY(int jy) returns jy, not a + // global position between 0 and 1 (in grid cells, <0 or >1 in boundaries), + // like a Mesh is supposed to. That means 'y' in input expressions varies + // between 0 and 2*pi*ny. + std::string expected_string_ylow{"x + (2*pi*11 - y) + 3"}; + + // modify mesh section in global options + options["dx_ylow"] = "1."; + options["dy_ylow"] = "1."; + options["g11_ylow"] = expected_string_ylow + " + 5."; + options["g22_ylow"] = expected_string_ylow + " + 4."; + options["g33_ylow"] = expected_string_ylow + " + 3."; + options["g12_ylow"] = expected_string_ylow + " + 2."; + options["g13_ylow"] = expected_string_ylow + " + 1."; + options["g23_ylow"] = expected_string_ylow; + + auto coords = mesh_from_options.getCoordinates(CELL_YLOW); + + Field2D expected_ylow = {makeField( + [](Field2D::ind_type& index) { + return index.x() + (TWOPI * (ny - index.y())) + (TWOPI * index.z() / nz) + 3; + }, + &mesh_from_options)}; + + mesh_from_options.communicate(expected_ylow); + + EXPECT_TRUE(IsFieldEqual(coords->g11, expected_ylow + 5., "RGN_ALL", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g22, expected_ylow + 4., "RGN_ALL", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g33, expected_ylow + 3., "RGN_ALL", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g12, expected_ylow + 2., "RGN_ALL", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g13, expected_ylow + 1., "RGN_ALL", this_tolerance)); + EXPECT_TRUE(IsFieldEqual(coords->g23, expected_ylow, "RGN_ALL", this_tolerance)); +} + +TEST_F(GridFromOptionsTest, CoordinatesZlowRead) { + // Grids are axisymmetric, so CELL_ZLOW Coordinates will be read from + // CELL_CENTRE variables + + auto coords = mesh_from_options.getCoordinates(CELL_ZLOW); + + EXPECT_TRUE(IsFieldEqual(coords->g11, expected_2d + 5.)); + EXPECT_TRUE(IsFieldEqual(coords->g22, expected_2d + 4.)); + EXPECT_TRUE(IsFieldEqual(coords->g33, expected_2d + 3.)); + EXPECT_TRUE(IsFieldEqual(coords->g12, expected_2d + 2.)); + EXPECT_TRUE(IsFieldEqual(coords->g13, expected_2d + 1.)); + EXPECT_TRUE(IsFieldEqual(coords->g23, expected_2d)); +} diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 27e0a041db..0a4b375860 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -175,6 +175,18 @@ public: coords_map[location] = coords; } + void setGridDataSource(GridDataSource* source_in) { + source = source_in; + } + + // Use this if the FakeMesh needs x- and y-boundaries + void createBoundaries() { + addBoundary(new BoundaryRegionXIn("core", ystart, yend, this)); + addBoundary(new BoundaryRegionXOut("sol", ystart, yend, this)); + addBoundary(new BoundaryRegionYUp("upper_target", xstart, xend, this)); + addBoundary(new BoundaryRegionYDown("lower_target", xstart, xend, this)); + } + comm_handle send(FieldGroup &UNUSED(g)) { return nullptr; }; int wait(comm_handle UNUSED(handle)) { return 0; } MPI_Request sendToProc(int UNUSED(xproc), int UNUSED(yproc), BoutReal *UNUSED(buffer), From bd08e7297f85e6913602853bc9af060258cd81b6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Mar 2019 10:21:48 +0000 Subject: [PATCH 1043/1783] Add mpark.variant include path to include flags and install command --- bin/bout-config.in | 2 +- configure | 3 +++ configure.ac | 2 ++ make.config.in | 8 ++++++-- output.make | 1 + 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/bin/bout-config.in b/bin/bout-config.in index 96f6692144..9ebbf87c5f 100755 --- a/bin/bout-config.in +++ b/bin/bout-config.in @@ -12,7 +12,7 @@ BOUT_LIB_PATH=@BOUT_LIB_PATH@ BOUT_INCLUDE_PATH=@BOUT_INCLUDE_PATH@ - +MPARK_VARIANT_INCLUDE_PATH=@MPARK_VARIANT_INCLUDE_PATH@ BOUT_CONFIG_FILE=@PREFIX@/make.config cc="@MPICXX@" diff --git a/configure b/configure index b9c4c04706..030eed486c 100755 --- a/configure +++ b/configure @@ -649,6 +649,7 @@ BOUT_VERSION PYTHONCONFIGPATH IDLCONFIGPATH PREFIX +MPARK_VARIANT_INCLUDE_PATH BOUT_INCLUDE_PATH BOUT_LIB_PATH CONFIG_LDFLAGS @@ -15887,6 +15888,8 @@ CONFIG_LDFLAGS=`$MAKE ldflags -f output.make` # If make install is run then that replaces these paths BOUT_LIB_PATH=$PWD/lib BOUT_INCLUDE_PATH=$PWD/include +MPARK_VARIANT_INCLUDE_PATH=$PWD/externalpackages/mpark.variant/include + diff --git a/configure.ac b/configure.ac index a4239a59d8..7733aca171 100644 --- a/configure.ac +++ b/configure.ac @@ -1267,8 +1267,10 @@ AC_SUBST(CONFIG_LDFLAGS) # If make install is run then that replaces these paths BOUT_LIB_PATH=$PWD/lib BOUT_INCLUDE_PATH=$PWD/include +MPARK_VARIANT_INCLUDE_PATH=$PWD/externalpackages/mpark.variant/include AC_SUBST(BOUT_LIB_PATH) AC_SUBST(BOUT_INCLUDE_PATH) +AC_SUBST(MPARK_VARIANT_INCLUDE_PATH) AC_SUBST(PREFIX) AC_SUBST(IDLCONFIGPATH) diff --git a/make.config.in b/make.config.in index 4fee8499e3..52c56e0a56 100644 --- a/make.config.in +++ b/make.config.in @@ -88,7 +88,8 @@ LIB = $(BOUT_LIB_PATH)/libbout++.a LIB_SO = $(BOUT_LIB_PATH)/libbout++.so endif -BOUT_INCLUDE = -I$(BOUT_INCLUDE_PATH) $(CXXINCLUDE) $(EXTRA_INCS) +MPARK_VARIANT_INCLUDE_PATH=@MPARK_VARIANT_INCLUDE_PATH@ +BOUT_INCLUDE = -I$(BOUT_INCLUDE_PATH) $(CXXINCLUDE) $(EXTRA_INCS) -I$(MPARK_VARIANT_INCLUDE_PATH) BOUT_LIBS = -lm -L$(BOUT_LIB_PATH) -lbout++ $(EXTRA_LIBS) CHANGED = $(shell find -f $(BOUT_TOP)/include $(BOUT_TOP)/src -type f \( -name \*.cxx -or -name \*.h \) -newer $(LIB) -print 2> /dev/null) @@ -161,10 +162,11 @@ install: libfast $(PRE_INSTALL) # Pre-install commands follow. $(NORMAL_INSTALL) # Normal commands follow. - $(MKDIR) $(INSTALL_INCLUDE_PATH)/{,pvode,bout/sys,bout/invert} + $(MKDIR) $(INSTALL_INCLUDE_PATH)/{,pvode,bout/sys,bout/invert,mpark} $(MKDIR) $(DESTDIR)/{@libdir@,@bindir@,@datadir@/bout++/idllib} $(MKDIR) $(DESTDIR)/@datadir@/bout++/pylib/{boutdata,boututils} $(INSTALL_DATA) include/*.hxx $(INSTALL_INCLUDE_PATH) + $(INSTALL_DATA) $(MPARK_VARIANT_INCLUDE_PATH)/mpark/*.hpp $(INSTALL_INCLUDE_PATH)/mpark $(INSTALL_DATA) include/pvode/*.h $(INSTALL_INCLUDE_PATH)/pvode/ $(INSTALL_DATA) include/bout/*.hxx $(INSTALL_INCLUDE_PATH)/bout/ $(INSTALL_DATA) include/bout/sys/*.hxx $(INSTALL_INCLUDE_PATH)/bout/sys/ @@ -188,11 +190,13 @@ install: libfast sed -i "s|^BOUT_CONFIG_FILE=.*|BOUT_CONFIG_FILE=@datadir@/bout++/make.config|" $(DESTDIR)@bindir@/bout-config sed -i "s|^idlpath=.*|idlpath=@datadir@/bout++/idllib/|" $(DESTDIR)@bindir@/bout-config sed -i "s|^pythonpath=.*|pythonpath=@datadir@/bout++/pylib/|" $(DESTDIR)@bindir@/bout-config + sed -i "s|^MPARK_VARIANT_INCLUDE_PATH=.*|MPARK_VARIANT_INCLUDE_PATH=@includedir@/bout++|" $(DESTDIR)@bindir@/bout-config @# Modify paths in the make.config file sed -i "s|^BOUT_INCLUDE_PATH=.*|BOUT_INCLUDE_PATH=@includedir@/bout++|" $(DESTDIR)@datadir@/bout++/make.config sed -i "s|^BOUT_LIB_PATH=.*|BOUT_LIB_PATH=@libdir@|" $(DESTDIR)@datadir@/bout++/make.config sed -i "s|^BOUT_CONFIG_FILE=.*|BOUT_CONFIG_FILE=@datadir@/bout++/make.config|" $(DESTDIR)@datadir@/bout++/make.config + sed -i "s|^MPARK_VARIANT_INCLUDE_PATH=.*|MPARK_VARIANT_INCLUDE_PATH=@includedir@/bout++|" $(DESTDIR)@datadir@/bout++/make.config uninstall: $(PRE_UNINSTALL) # Pre-uninstall commands follow. diff --git a/output.make b/output.make index 0fa72ba693..84e7b9ca18 100644 --- a/output.make +++ b/output.make @@ -8,6 +8,7 @@ include make.config BOUT_INCLUDE_PATH="\$$BOUT_INCLUDE_PATH" BOUT_LIB_PATH="\$$BOUT_LIB_PATH" +MPARK_VARIANT_INCLUDE_PATH="\$$MPARK_VARIANT_INCLUDE_PATH" .PHONY: cflags cflags: From c9e72c0c9a03963d8a771dca5fc80107083931de Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Mar 2019 11:12:04 +0000 Subject: [PATCH 1044/1783] Provide getter for Matrix/Tensor::data; revert making `data` public --- include/utils.hxx | 20 ++++++++++++++------ src/sys/options.cxx | 4 ++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/utils.hxx b/include/utils.hxx index c34eb02242..fcc85a4a2b 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -104,7 +104,7 @@ public: data.reallocate(n1 * n2); } - Matrix(const Matrix &other) : data(other.data), n1(other.n1), n2(other.n2) { + Matrix(const Matrix &other) : n1(other.n1), n2(other.n2), data(other.data) { // Prevent copy on write for Matrix data.ensureUnique(); } @@ -166,10 +166,14 @@ public: data.ensureUnique(); } - /// Underlying 1D storage array - Array data; + /// Access the underlying storage + Array& getData() { return data; } + const Array& getData() const { return data; } + private: size_type n1, n2; + /// Underlying 1D storage array + Array data; }; /// Helper class for 3D arrays @@ -191,7 +195,7 @@ public: ASSERT2(n3 >= 0); data.reallocate(n1 * n2 * n3); } - Tensor(const Tensor &other) : data(other.data), n1(other.n1), n2(other.n2), n3(other.n3) { + Tensor(const Tensor &other) : n1(other.n1), n2(other.n2), n3(other.n3), data(other.data) { // Prevent copy on write for Tensor data.ensureUnique(); } @@ -260,10 +264,14 @@ public: data.ensureUnique(); } - /// Underlying 1D storage array - Array data; + /// Access the underlying storage + Array& getData() { return data; } + const Array& getData() const { return data; } + private: size_type n1, n2, n3; + /// Underlying 1D storage array + Array data; }; diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 2fb44883fb..b947ab46af 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -336,7 +336,7 @@ template <> Field3D Options::as(Mesh* localmesh) const { if (tensor.shape() == std::make_tuple(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz)) { - return Field3D(tensor.data, localmesh); + return Field3D(tensor.getData(), localmesh); } // If dimension sizes not the same, may be able // to select a region from it using Mesh e.g. if this @@ -371,7 +371,7 @@ template <> Field2D Options::as(Mesh* localmesh) const { // Check if the dimension sizes are the same as a Field3D if (matrix.shape() == std::make_tuple(localmesh->LocalNx, localmesh->LocalNy)) { - return Field2D(matrix.data, localmesh); + return Field2D(matrix.getData(), localmesh); } } } From 3375c9ba59efe95057f68c718714ccf3681472fb Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Mar 2019 11:37:57 +0000 Subject: [PATCH 1045/1783] Add unit tests for `Matrix/Tensor::getData` --- tests/unit/sys/test_utils.cxx | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/unit/sys/test_utils.cxx b/tests/unit/sys/test_utils.cxx index 8cca3b5de6..a5e9d43b4b 100644 --- a/tests/unit/sys/test_utils.cxx +++ b/tests/unit/sys/test_utils.cxx @@ -163,6 +163,29 @@ TEST(MatrixTest, ConstIndexing) { EXPECT_EQ(matrix2(1, 1), 3); } +TEST(MatrixTest, GetData) { + Matrix matrix(3, 5); + matrix = 3; + + auto data = matrix.getData(); + + EXPECT_TRUE(std::all_of(std::begin(data), std::end(data), [](int a) { return a == 3; })); + + data[0] = 4; + + EXPECT_EQ(matrix(0, 0), 4); +} + +TEST(MatrixTest, ConstGetData) { + Matrix matrix(3, 5); + matrix = 3; + + const auto data = matrix.getData(); + + EXPECT_TRUE(std::all_of(std::begin(data), std::end(data), [](int a) { return a == 3; })); + EXPECT_TRUE(std::all_of(std::begin(matrix), std::end(matrix), [](int a) { return a == 3; })); +} + TEST(TensorTest, DefaultShape) { Tensor tensor; @@ -333,6 +356,29 @@ TEST(TensorTest, ConstIndexing) { EXPECT_EQ(tensor2(1, 1, 1), 3); } +TEST(TensorTest, GetData) { + Tensor tensor(3, 5, 7); + tensor = 3; + + auto data = tensor.getData(); + + EXPECT_TRUE(std::all_of(std::begin(data), std::end(data), [](int a) { return a == 3; })); + + data[0] = 4; + + EXPECT_EQ(tensor(0, 0, 0), 4); +} + +TEST(TensorTest, ConstGetData) { + Tensor tensor(3, 5, 7); + tensor = 3; + + const auto data = tensor.getData(); + + EXPECT_TRUE(std::all_of(std::begin(data), std::end(data), [](int a) { return a == 3; })); + EXPECT_TRUE(std::all_of(std::begin(tensor), std::end(tensor), [](int a) { return a == 3; })); +} + TEST(Invert3x3Test, Identity) { Matrix input(3, 3); input = 0; From 5f0d0103f5246dd2f5ede45ce4f1b8da429e3a23 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Mar 2019 11:44:02 +0000 Subject: [PATCH 1046/1783] Write explicit string in Options NetCDF test --- tests/unit/sys/test_options_netcdf.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/sys/test_options_netcdf.cxx b/tests/unit/sys/test_options_netcdf.cxx index 7fa714faa1..d811652d03 100644 --- a/tests/unit/sys/test_options_netcdf.cxx +++ b/tests/unit/sys/test_options_netcdf.cxx @@ -50,7 +50,7 @@ TEST_F(OptionsNetCDFTest, ReadWriteInt) { TEST_F(OptionsNetCDFTest, ReadWriteString) { { Options options; - options["test"] = "hello"; + options["test"] = std::string{"hello"}; // Write file OptionsNetCDF(filename).write(options); From c9324c2892eef3806d8774dc7979abf4f0b981cf Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Mar 2019 11:44:22 +0000 Subject: [PATCH 1047/1783] Don't reuse OptionsNetCDF file in test --- tests/unit/sys/test_options_netcdf.cxx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/unit/sys/test_options_netcdf.cxx b/tests/unit/sys/test_options_netcdf.cxx index d811652d03..212538a475 100644 --- a/tests/unit/sys/test_options_netcdf.cxx +++ b/tests/unit/sys/test_options_netcdf.cxx @@ -30,19 +30,16 @@ class OptionsNetCDFTest: public FakeMeshFixture { }; TEST_F(OptionsNetCDFTest, ReadWriteInt) { - // Temporary file - OptionsNetCDF file(filename); - { Options options; options["test"] = 42; - + // Write the file - file.write(options); + OptionsNetCDF(filename).write(options); } // Read again - Options data = file.read(); + Options data = OptionsNetCDF(filename).read(); EXPECT_EQ(data["test"], 42); } From fe842613479cb34dd7ba2cd90ac28e955b2aec25 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Mar 2019 15:54:28 +0000 Subject: [PATCH 1048/1783] Workaround for bug in NetCDF 4.4.0 and NetCDF-CXX4 4.2.0 i.e. versions on Travis/Xenial --- src/sys/options/options_netcdf.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index cc6ff98214..2ad893220b 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -390,7 +390,8 @@ void writeGroup(const Options& options, NcGroup group, if (var.isNull()) { // Variable doesn't exist yet // Create variable - var = group.addVar(name, nctype, dims); + // Temporary NcType as a workaround for bug in NetCDF 4.4.0 and NetCDF-CXX4 4.2.0 + var = group.addVar(name, NcType{group, nctype.getId()}, dims); } else { // Variable does exist From 8fba5a58443dab141c73c646e398ce8b5231d8d8 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Mar 2019 16:46:01 +0000 Subject: [PATCH 1049/1783] Fix typo in Z-processor split --- src/mesh/impls/bout/boutmesh.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 07fb140cf5..e67ad93879 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -426,7 +426,7 @@ int BoutMesh::load() { } MZSUB = MZ / NZPE; - if ((MY % NYPE) != 0) { + if ((MZ % NZPE) != 0) { throw BoutException( _("\tERROR: Cannot split %d Z points equally between %d processors\n"), MZ, NZPE); } From e9610d59365149254f4e0e342adee1bc563c38e3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Mar 2019 16:50:03 +0000 Subject: [PATCH 1050/1783] Dump nz/MZ instead of just LocalNz --- src/mesh/impls/bout/boutmesh.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index e67ad93879..b59af9cb2a 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2571,8 +2571,8 @@ void BoutMesh::outputVars(Datafile &file) { file.add(MYG, "MYG", false); file.add(nx, "nx", false); file.add(ny, "ny", false); - file.add(LocalNz, "nz", false); - file.add(LocalNz, "MZ", false); + file.add(nz, "nz", false); + file.add(MZ, "MZ", false); file.add(NXPE, "NXPE", false); file.add(NYPE, "NYPE", false); file.add(ZMAX, "ZMAX", false); From f71f2b24b4f6f5e90379ac2ad014e13d767f269f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Mar 2019 16:50:20 +0000 Subject: [PATCH 1051/1783] Add missing Z-grid related variables to outputVars --- src/mesh/impls/bout/boutmesh.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index b59af9cb2a..4342dbafce 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2567,14 +2567,17 @@ void BoutMesh::outputVars(Datafile &file) { file.add(zperiod, "zperiod", false); file.add(MXSUB, "MXSUB", false); file.add(MYSUB, "MYSUB", false); + file.add(MZSUB, "MZSUB", false); file.add(MXG, "MXG", false); file.add(MYG, "MYG", false); + file.add(MZG, "MZG", false); file.add(nx, "nx", false); file.add(ny, "ny", false); file.add(nz, "nz", false); file.add(MZ, "MZ", false); file.add(NXPE, "NXPE", false); file.add(NYPE, "NYPE", false); + file.add(NZPE, "NZPE", false); file.add(ZMAX, "ZMAX", false); file.add(ZMIN, "ZMIN", false); file.add(ixseps1, "ixseps1", false); From 30fcf78504791618717a75750ff5270a70343937 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 14 Mar 2019 16:51:14 +0000 Subject: [PATCH 1052/1783] Clang-format Div_par --- src/mesh/difops.cxx | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index 58cd59fa63..1caac33aaa 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -199,35 +199,36 @@ const Field3D Div_par(const Field3D &f, const std::string &method, CELL_LOC outl return f.getCoordinates(outloc)->Div_par(f, outloc, method); } -const Field3D Div_par(const Field3D &f, const Field3D &v) { +const Field3D Div_par(const Field3D& f, const Field3D& v) { ASSERT1(areFieldsCompatible(f, v)); // Parallel divergence, using velocities at cell boundaries // Note: Not guaranteed to be flux conservative - Mesh *mesh = f.getMesh(); + Mesh* mesh = f.getMesh(); Field3D result{emptyFrom(f)}; - Coordinates *coord = f.getCoordinates(); - - for(int i=mesh->xstart;i<=mesh->xend;i++) - for(int j=mesh->ystart;j<=mesh->yend;j++) { - for (int k = mesh->zstart; k <= mesh->zend; k++) { + Coordinates* coord = f.getCoordinates(); + for (int i = mesh->xstart; i <= mesh->xend; i++) + for (int j = mesh->ystart; j <= mesh->yend; j++) { + for (int k = mesh->zstart; k <= mesh->zend; k++) { // Value of f and v at left cell face - BoutReal fL = 0.5*(f(i,j,k) + f.ydown()(i,j-1,k)); - BoutReal vL = 0.5*(v(i,j,k) + v.ydown()(i,j-1,k)); - - BoutReal fR = 0.5*(f(i,j,k) + f.yup()(i,j+1,k)); - BoutReal vR = 0.5*(v(i,j,k) + v.yup()(i,j+1,k)); - + BoutReal fL = 0.5 * (f(i, j, k) + f.ydown()(i, j - 1, k)); + BoutReal vL = 0.5 * (v(i, j, k) + v.ydown()(i, j - 1, k)); + + BoutReal fR = 0.5 * (f(i, j, k) + f.yup()(i, j + 1, k)); + BoutReal vR = 0.5 * (v(i, j, k) + v.yup()(i, j + 1, k)); + // Calculate flux at right boundary (y+1/2) - BoutReal fluxRight = fR * vR * (coord->J(i,j) + coord->J(i,j+1)) / (sqrt(coord->g_22(i,j))+ sqrt(coord->g_22(i,j+1))); - + BoutReal fluxRight = fR * vR * (coord->J(i, j) + coord->J(i, j + 1)) + / (sqrt(coord->g_22(i, j)) + sqrt(coord->g_22(i, j + 1))); + // Calculate at left boundary (y-1/2) - BoutReal fluxLeft = fL * vL * (coord->J(i,j) + coord->J(i,j-1)) / (sqrt(coord->g_22(i,j)) + sqrt(coord->g_22(i,j-1))); - - result(i,j,k) = (fluxRight - fluxLeft) / (coord->dy(i,j)*coord->J(i,j)); + BoutReal fluxLeft = fL * vL * (coord->J(i, j) + coord->J(i, j - 1)) + / (sqrt(coord->g_22(i, j)) + sqrt(coord->g_22(i, j - 1))); + + result(i, j, k) = (fluxRight - fluxLeft) / (coord->dy(i, j) * coord->J(i, j)); } } From d0b02e33ea751541cc912c0c65d0c4de6e429da2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 14 Mar 2019 17:36:09 +0000 Subject: [PATCH 1053/1783] GridFromOptionsTest doesn't need to inherit from FakeMeshFixture --- tests/unit/mesh/data/test_gridfromoptions.cxx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/unit/mesh/data/test_gridfromoptions.cxx b/tests/unit/mesh/data/test_gridfromoptions.cxx index add3ae8d3b..126efd9379 100644 --- a/tests/unit/mesh/data/test_gridfromoptions.cxx +++ b/tests/unit/mesh/data/test_gridfromoptions.cxx @@ -14,9 +14,9 @@ // The unit tests use the global mesh using namespace bout::globals; -class GridFromOptionsTest : public FakeMeshFixture { +class GridFromOptionsTest : public ::testing::Test { public: - GridFromOptionsTest() : FakeMeshFixture(), options(), griddata(nullptr) { + GridFromOptionsTest() : options(), griddata(nullptr) { mesh_from_options.StaggerGrids = true; mesh_from_options.xstart = 2; @@ -51,17 +51,17 @@ class GridFromOptionsTest : public FakeMeshFixture { mesh_from_options.getCoordinates(); - expected_2d = {makeField( + expected_2d = makeField( [](Field2D::ind_type& index) { return index.x() + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; }, - &mesh_from_options)}; + &mesh_from_options); - expected_3d = {makeField( + expected_3d = makeField( [](Field3D::ind_type& index) { return index.x() + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; }, - &mesh_from_options)}; + &mesh_from_options); } ~GridFromOptionsTest() { @@ -364,11 +364,11 @@ TEST_F(GridFromOptionsTest, CoordinatesXlowInterp) { auto coords = mesh_from_options.getCoordinates(CELL_XLOW); - Field2D expected_xlow = {makeField( + Field2D expected_xlow = makeField( [](Field2D::ind_type& index) { return index.x() - 0.5 + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; }, - &mesh_from_options)}; + &mesh_from_options); mesh_from_options.communicate(expected_xlow); @@ -400,11 +400,11 @@ TEST_F(GridFromOptionsTest, CoordinatesXlowRead) { auto coords = mesh_from_options.getCoordinates(CELL_XLOW); - Field2D expected_xlow = {makeField( + Field2D expected_xlow = makeField( [](Field2D::ind_type& index) { return (nx - index.x()) + (TWOPI * index.y()) + (TWOPI * index.z() / nz) + 3; }, - &mesh_from_options)}; + &mesh_from_options); mesh_from_options.communicate(expected_xlow); @@ -425,11 +425,11 @@ TEST_F(GridFromOptionsTest, CoordinatesYlowInterp) { auto coords = mesh_from_options.getCoordinates(CELL_XLOW); - Field2D expected_ylow = {makeField( + Field2D expected_ylow = makeField( [](Field2D::ind_type& index) { return index.x() + (TWOPI * index.y() - 0.5) + (TWOPI * index.z() / nz) + 3; }, - &mesh_from_options)}; + &mesh_from_options); mesh_from_options.communicate(expected_ylow); @@ -462,11 +462,11 @@ TEST_F(GridFromOptionsTest, CoordinatesYlowRead) { auto coords = mesh_from_options.getCoordinates(CELL_YLOW); - Field2D expected_ylow = {makeField( + Field2D expected_ylow = makeField( [](Field2D::ind_type& index) { return index.x() + (TWOPI * (ny - index.y())) + (TWOPI * index.z() / nz) + 3; }, - &mesh_from_options)}; + &mesh_from_options); mesh_from_options.communicate(expected_ylow); From c697221455f0a0f7130c81e66185f674092d29e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 15 Mar 2019 11:31:33 +0000 Subject: [PATCH 1054/1783] Update list of header files. Also add check to travis script that the list is up to date --- .travis_script.sh | 3 +++ bin/bout_4to5 | 20 +-------------- bin/bout_4to5_header_file_list | 46 ++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 bin/bout_4to5_header_file_list diff --git a/.travis_script.sh b/.travis_script.sh index bf9b09e435..446ef056c2 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -51,6 +51,9 @@ done if test $UPDATE_SCRIPT -gt 0 then + # Make sure the header list is up to date + diff <(cd include/;ls *xx|grep -v ^bout.hxx|sort) bin/bout_4to5_header_file_list + bin/bout_4to5 -f fi diff --git a/bin/bout_4to5 b/bin/bout_4to5 index dce3cc136d..ae37146fbe 100755 --- a/bin/bout_4to5 +++ b/bin/bout_4to5 @@ -136,25 +136,7 @@ do done done -headerfilelist="boundary_factory.hxx boundary_op.hxx boundary_region.hxx \ - boundary_standard.hxx boutcomm.hxx \ - boutexception.hxx boutmain.hxx bout_types.hxx \ - comm_group.hxx cyclic_reduction.hxx \ - datafile.hxx dataformat.hxx dcomplex.hxx \ - derivs.hxx difops.hxx fft.hxx field2d.hxx \ - field3d.hxx field_data.hxx field_factory.hxx \ - field.hxx fieldperp.hxx globals.hxx \ - gyro_average.hxx initialprofiles.hxx \ - interpolation_factory.hxx interpolation.hxx \ - invert_laplace.hxx invert_parderiv.hxx \ - lapack_routines.hxx mask.hxx msg_stack.hxx \ - multiostream.hxx options.hxx \ - optionsreader.hxx output.hxx \ - parallel_boundary_op.hxx \ - parallel_boundary_region.hxx smoothing.hxx \ - sourcex.hxx stencils.hxx unused.hxx utils.hxx \ - vecops.hxx vector2d.hxx vector3d.hxx where.hxx - " +headerfilelist="$(cat ${0}_header_file_list)" include=$DIR/../include/ function gen_compat() { diff --git a/bin/bout_4to5_header_file_list b/bin/bout_4to5_header_file_list new file mode 100644 index 0000000000..211cc1b177 --- /dev/null +++ b/bin/bout_4to5_header_file_list @@ -0,0 +1,46 @@ +boundary_factory.hxx +boundary_op.hxx +boundary_region.hxx +boundary_standard.hxx +boutcomm.hxx +boutexception.hxx +boutmain.hxx +bout_types.hxx +cyclic_reduction.hxx +datafile.hxx +dataformat.hxx +dcomplex.hxx +derivs.hxx +difops.hxx +fft.hxx +field2d.hxx +field3d.hxx +field_data.hxx +field_factory.hxx +field.hxx +fieldperp.hxx +globals.hxx +gyro_average.hxx +initialprofiles.hxx +interpolation_factory.hxx +interpolation.hxx +invert_laplace.hxx +invert_parderiv.hxx +lapack_routines.hxx +mask.hxx +msg_stack.hxx +multiostream.hxx +options.hxx +optionsreader.hxx +output.hxx +parallel_boundary_op.hxx +parallel_boundary_region.hxx +smoothing.hxx +sourcex.hxx +stencils.hxx +unused.hxx +utils.hxx +vecops.hxx +vector2d.hxx +vector3d.hxx +where.hxx From 210b950a8509f076fe18e0bae1d360b716b853ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 15 Mar 2019 19:34:55 +0000 Subject: [PATCH 1055/1783] Update boutcore as well As boutcore is parsing hxx files by hand, it needs some hacks to update properly. `bout_types.hxx` needs to be in a comment, so that the reference in the code is update. As this is only run on boutcore, the code does not need to be particularly reliable ... --- bin/bout_4to5 | 14 ++++++++++++++ .../pylib/_boutcore_build/resolve_enum_inv.pyx.in | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/bin/bout_4to5 b/bin/bout_4to5 index ae37146fbe..3523c607aa 100755 --- a/bin/bout_4to5 +++ b/bin/bout_4to5 @@ -180,6 +180,20 @@ then $printordo sed -i "s|\.\./||" $f fi done + + pydir=$DIR/../tools/pylib/_boutcore_build + for f in $pydir/*in + do + matched=$(grep '[/_a-z$A-Z0-9]*.hxx' -o $f|sort -u) + for h in $matched + do + test -f $pydir/$h && continue + #test b=${h::5} = bout/ && continue + test $h = bout.hxx && continue + echo "$h" | $GREP -q '/' && continue + sed -i "s|$h|bout/$h|" $f + done + done fi diff --git a/tools/pylib/_boutcore_build/resolve_enum_inv.pyx.in b/tools/pylib/_boutcore_build/resolve_enum_inv.pyx.in index 2e16bf9373..5b93412ba5 100644 --- a/tools/pylib/_boutcore_build/resolve_enum_inv.pyx.in +++ b/tools/pylib/_boutcore_build/resolve_enum_inv.pyx.in @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# We are trying to parse bout_types, to translate the list of enums to +# We are trying to parse bout_types.hxx, to translate the list of enums to # a python dictionary. for file in ../../../include/bout_types.hxx other_enums.hxx From 43a6049ba97be3ef9acdeb5318230b3a5c7e4796 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 18 Mar 2019 15:32:23 +0000 Subject: [PATCH 1056/1783] Add order-only dependency on gtest sentinel to unit test objects Fixes #1642 #1638 --- tests/unit/makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/unit/makefile b/tests/unit/makefile index 7914701adb..6bc5bd1fe5 100644 --- a/tests/unit/makefile +++ b/tests/unit/makefile @@ -43,7 +43,7 @@ clean :: # Download Google Test $(GTEST_SENTINEL) : - echo "Downloading Google Test" + @echo "Downloading Google Test" git submodule update --init --recursive # For simplicity and to avoid depending on Google Test's @@ -79,6 +79,8 @@ $(TARGET): makefile $(BOUT_TOP)/make.config $(OBJ) $(SUB_LIBS) bout_test_main.a TEST_SOURCES = $(shell find $(BOUT_TEST_DIR) -type f -name "test_*.cxx" 2> /dev/null) TEST_OBJECTS = $(TEST_SOURCES:%.cxx=%.o) +$(TEST_OBJECTS): | $(GTEST_SENTINEL) + serial_tests: makefile $(BOUT_TOP)/make.config $(OBJ) $(LIB) checklib \ $(SUB_LIBS) $(TEST_OBJECTS) bout_test_main.a @echo " Linking tests" From 072b3e99c0f10a9d56f50ee37e5946125a80ed92 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 19 Mar 2019 16:38:37 +0000 Subject: [PATCH 1057/1783] Update configure SUNDIALS version check to allow versions > 2.6 --- configure | 80 ++++++++++++++++++++++++++-------------------------- configure.ac | 40 +++++++++++++------------- 2 files changed, 61 insertions(+), 59 deletions(-) diff --git a/configure b/configure index b9c4c04706..2b87036e7b 100755 --- a/configure +++ b/configure @@ -10238,38 +10238,6 @@ See \`config.log' for more details" "$LINENO" 5; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - # Version 3.0.0 changed the name of this define to just SUNDIALS_VERSION - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SUNDIALS major version" >&5 -$as_echo_n "checking for SUNDIALS major version... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include "sundials/sundials_config.h" - #ifdef SUNDIALS_PACKAGE_VERSION - yes - #endif - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1; then : - sundials_major_ver=2 -else - sundials_major_ver=3 -fi -rm -f conftest* - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sundials_major_ver" >&5 -$as_echo "$sundials_major_ver" >&6; } - - if test $sundials_major_ver = 3; then : - - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "*** Unsupported SUNDIALS version: Only 2.6-2.7 are supported currently -See \`config.log' for more details" "$LINENO" 5; } - -fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SUNDIALS minor version" >&5 $as_echo_n "checking for SUNDIALS minor version... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10282,10 +10250,10 @@ $as_echo_n "checking for SUNDIALS minor version... " >&6; } _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "^ *\"? *2\.[67]\." >/dev/null 2>&1; then : - sundials_minor_ver=ok -else + $EGREP "^ *\"? *[12]\.[0-5]\." >/dev/null 2>&1; then : sundials_minor_ver="too low" +else + sundials_minor_ver=ok fi rm -f conftest* @@ -10298,7 +10266,7 @@ $as_echo "$sundials_minor_ver" >&6; } { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "*** Unsupported SUNDIALS version: Only 2.6-2.7 are supported currently +as_fn_error $? "*** Unsupported SUNDIALS version: Requires at least 2.6 See \`config.log' for more details" "$LINENO" 5; } fi @@ -10994,7 +10962,13 @@ $as_echo_n "checking if we can compile with SUNDIALS $module_upper... " >&6; } int main () { -CVodeCreate(0, 0); + + #if SUNDIALS_VERSION_MAJOR >= 4 + CVodeCreate(0); + #else + CVodeCreate(0, 0); + #endif + ; return 0; } @@ -11358,7 +11332,13 @@ $as_echo_n "checking if SUNDIALS $module_upper library path is $sundials_module_ int main () { -CVodeCreate(0, 0); + + #if SUNDIALS_VERSION_MAJOR >= 4 + CVodeCreate(0); + #else + CVodeCreate(0, 0); + #endif + ; return 0; } @@ -11564,14 +11544,24 @@ $as_echo_n "checking if we can compile with SUNDIALS $module_upper... " >&6; } #include + #if SUNDIALS_VERSION_MAJOR >= 4 + #include + #else #include + #endif extern void foo(N_Vector); int main () { -ARKodeCreate(); + + #if SUNDIALS_VERSION_MAJOR >= 4 + ARKStepCreate(0, 0, 0, 0); + #else + ARKodeCreate(); + #endif + ; return 0; } @@ -11928,14 +11918,24 @@ $as_echo_n "checking if SUNDIALS $module_upper library path is $sundials_module_ #include + #if SUNDIALS_VERSION_MAJOR >= 4 + #include + #else #include + #endif extern void foo(N_Vector); int main () { -ARKodeCreate(); + + #if SUNDIALS_VERSION_MAJOR >= 4 + ARKStepCreate(0, 0, 0, 0); + #else + ARKodeCreate(); + #endif + ; return 0; } diff --git a/configure.ac b/configure.ac index a4239a59d8..020c4413a8 100644 --- a/configure.ac +++ b/configure.ac @@ -993,33 +993,19 @@ AS_IF([test "x$with_sundials" != "x" && test "x$with_sundials" != "xno"], [ [AC_MSG_RESULT([no]) AC_MSG_FAILURE([*** Could not determine SUNDIALS version])]) - # Version 3.0.0 changed the name of this define to just SUNDIALS_VERSION - AC_MSG_CHECKING([for SUNDIALS major version]) - AC_EGREP_CPP([yes], [ - #include "sundials/sundials_config.h" - #ifdef SUNDIALS_PACKAGE_VERSION - yes - #endif - ], [sundials_major_ver=2], [sundials_major_ver=3]) - AC_MSG_RESULT([$sundials_major_ver]) - - AS_IF([test $sundials_major_ver = 3], [ - AC_MSG_FAILURE([*** Unsupported SUNDIALS version: Only 2.6-2.7 are supported currently]) - ]) - AC_MSG_CHECKING([for SUNDIALS minor version]) - AC_EGREP_CPP([^ *\"? *2\.[67]\.], [ + AC_EGREP_CPP([^ *\"? *[12]\.[0-5]\.], [ #include "sundials/sundials_config.h" #ifdef SUNDIALS_PACKAGE_VERSION SUNDIALS_PACKAGE_VERSION #endif - ], [sundials_minor_ver=ok], [sundials_minor_ver="too low"]) + ], [sundials_minor_ver="too low"], [sundials_minor_ver=ok]) AC_MSG_RESULT([$sundials_minor_ver]) CPPFLAGS=$save_CPPFLAGS AS_IF([test "$sundials_minor_ver" = "too low"], [ - AC_MSG_FAILURE([*** Unsupported SUNDIALS version: Only 2.6-2.7 are supported currently]) + AC_MSG_FAILURE([*** Unsupported SUNDIALS version: Requires at least 2.6]) ]) # Set both IDA and CVODE if not set already @@ -1052,7 +1038,13 @@ AS_IF([test "x$with_cvode" != "x" && test "x$with_cvode" != "xno"], [ #include #include extern void foo(N_Vector); - ], [CVodeCreate(0, 0);], [ + ], [ + #if SUNDIALS_VERSION_MAJOR >= 4 + CVodeCreate(0); + #else + CVodeCreate(0, 0); + #endif + ], [ #include extern int cvode_bbd_rhs(CVODEINT, double, N_Vector, N_Vector, void *); ], [CVBBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, cvode_bbd_rhs, nullptr);]) @@ -1061,9 +1053,19 @@ AS_IF([test "x$with_cvode" != "x" && test "x$with_cvode" != "xno"], [ AS_IF([test "x$with_arkode" != "x" && test "x$with_arkode" != "xno"], [ BOUT_FIND_SUNDIALS_MODULE([arkode], [ #include + #if SUNDIALS_VERSION_MAJOR >= 4 + #include + #else #include + #endif extern void foo(N_Vector); - ], [ARKodeCreate();], [ + ], [ + #if SUNDIALS_VERSION_MAJOR >= 4 + ARKStepCreate(0, 0, 0, 0); + #else + ARKodeCreate(); + #endif + ], [ #include extern int arkode_bbd_rhs(ARKODEINT, double, N_Vector, N_Vector, void *); ], [ARKBBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, arkode_bbd_rhs, nullptr);]) From 9ce88973c1be9d14b2ade8243ca8f402b5693524 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 19 Mar 2019 16:55:08 +0000 Subject: [PATCH 1058/1783] Update ARKODE, CVODE, IDA interfaces to support SUNDIALS 3.x --- src/solver/impls/arkode/arkode.cxx | 69 ++++++++++++++++++++++++------ src/solver/impls/arkode/arkode.hxx | 20 ++++++--- src/solver/impls/cvode/cvode.cxx | 66 +++++++++++++++++++++++----- src/solver/impls/cvode/cvode.hxx | 19 +++++--- src/solver/impls/ida/ida.cxx | 46 ++++++++++++++++---- src/solver/impls/ida/ida.hxx | 11 ++++- 6 files changed, 184 insertions(+), 47 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index 884f64fc4e..b2674efc58 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -34,7 +34,18 @@ #include #include +#if SUNDIALS_VERSION_MAJOR >= 4 +#include +#else #include +#endif + +#if SUNDIALS_VERSION_MAJOR >= 3 +#include +#else +#include +#endif + #include #include #include @@ -57,15 +68,31 @@ static int arkode_rhs(BoutReal t, N_Vector u, N_Vector du, void *user_data); static int arkode_bbd_rhs(ARKODEINT Nlocal, BoutReal t, N_Vector u, N_Vector du, void *user_data); +static int arkode_pre(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rvec, N_Vector zvec, + BoutReal gamma, BoutReal delta, int lr, void* user_data); +#if SUNDIALS_VERSION_MAJOR < 3 +// Shim for earlier versions +inline static int arkode_pre_shim(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rvec, + N_Vector zvec, BoutReal gamma, BoutReal delta, int lr, + void* user_data, N_Vector UNUSED(tmp)) { + return arkode_pre(t, yy, yp, rvec, zvec, gamma, delta, lr, user_data); +} +#else +// Alias for newer versions +constexpr auto& arkode_pre_shim = arkode_pre; +#endif -static int arkode_pre(BoutReal t, N_Vector yy, N_Vector yp, - N_Vector rvec, N_Vector zvec, - BoutReal gamma, BoutReal delta, int lr, - void *user_data, N_Vector tmp); static int arkode_jac(N_Vector v, N_Vector Jv, realtype t, N_Vector y, N_Vector fy, void *user_data, N_Vector tmp); +#if SUNDIALS_VERSION_MAJOR < 3 +// Shim for earlier versions +inline int ARKSpilsSetJacTimes(void* arkode_mem, std::nullptr_t, + ARKSpilsJacTimesVecFn jtimes) { + return ARKSpilsSetJacTimesVecFn(arkode_mem, jtimes); +} +#endif ArkodeSolver::ArkodeSolver(Options *opts) : Solver(opts) { has_constraints = false; ///< This solver doesn't have constraints @@ -74,9 +101,12 @@ ArkodeSolver::ArkodeSolver(Options *opts) : Solver(opts) { } ArkodeSolver::~ArkodeSolver() { - if(initialised) { + if (initialised) { N_VDestroy_Parallel(uvec); ARKodeFree(&arkode_mem); +#if SUNDIALS_VERSION_MAJOR >= 3 + SUNLinSolFree(sun_solver); +#endif } } @@ -354,9 +384,16 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { options->get("rightprec", rightprec, false); if(rightprec) prectype = PREC_RIGHT; - - if( ARKSpgmr(arkode_mem, prectype, maxl) != ARKSPILS_SUCCESS ) + +#if SUNDIALS_VERSION_MAJOR >= 3 + if ((sun_solver = SUNSPGMR(static_cast(uvec), prectype, maxl)) == nullptr) + throw BoutException("ERROR: SUNSPGMR failed\n"); + if (ARKSpilsSetLinearSolver(arkode_mem, sun_solver) != ARKSPILS_SUCCESS) + throw BoutException("ERROR: ARKSpilsSetLinearSolver failed\n"); +#else + if (ARKSpgmr(arkode_mem, prectype, maxl) != ARKSPILS_SUCCESS) throw BoutException("ERROR: ARKSpgmr failed\n"); +#endif if(!have_user_precon()) { output.write("\tUsing BBD preconditioner\n"); @@ -368,7 +405,7 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { } else { output.write("\tUsing user-supplied preconditioner\n"); - if (ARKSpilsSetPreconditioner(arkode_mem, nullptr, arkode_pre) != + if (ARKSpilsSetPreconditioner(arkode_mem, nullptr, arkode_pre_shim) != ARKSPILS_SUCCESS) throw BoutException("ERROR: ARKSpilsSetPreconditioner failed\n"); } @@ -377,17 +414,25 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { output.write("\tNo preconditioning\n"); - if( ARKSpgmr(arkode_mem, PREC_NONE, maxl) != ARKSPILS_SUCCESS ) +#if SUNDIALS_VERSION_MAJOR >= 3 + if ((sun_solver = SUNSPGMR(static_cast(uvec), PREC_NONE, maxl)) + == nullptr) + throw BoutException("ERROR: SUNSPGMR failed\n"); + if (ARKSpilsSetLinearSolver(arkode_mem, sun_solver) != ARKSPILS_SUCCESS) + throw BoutException("ERROR: ARKSpilsSetLinearSolver failed\n"); +#else + if (ARKSpgmr(arkode_mem, PREC_NONE, maxl) != ARKSPILS_SUCCESS) throw BoutException("ERROR: ARKSpgmr failed\n"); +#endif } - + /// Set Jacobian-vector multiplication function if (use_jacobian && jacfunc) { output.write("\tUsing user-supplied Jacobian function\n"); TRACE("Setting Jacobian-vector multiply"); - if( ARKSpilsSetJacTimesVecFn(arkode_mem, arkode_jac) != ARKSPILS_SUCCESS ) + if (ARKSpilsSetJacTimes(arkode_mem, nullptr, arkode_jac) != ARKSPILS_SUCCESS) throw BoutException("ERROR: ARKSpilsSetJacTimesVecFn failed\n"); }else output.write("\tUsing difference quotient approximation for Jacobian\n"); @@ -686,7 +731,7 @@ static int arkode_bbd_rhs(ARKODEINT UNUSED(Nlocal), BoutReal t, N_Vector u, N_Ve /// Preconditioner function static int arkode_pre(BoutReal t, N_Vector yy, N_Vector UNUSED(yp), N_Vector rvec, N_Vector zvec, BoutReal gamma, BoutReal delta, int UNUSED(lr), - void *user_data, N_Vector UNUSED(tmp)) { + void *user_data) { BoutReal *udata = NV_DATA_P(yy); BoutReal *rdata = NV_DATA_P(rvec); BoutReal *zdata = NV_DATA_P(zvec); diff --git a/src/solver/impls/arkode/arkode.hxx b/src/solver/impls/arkode/arkode.hxx index 69f86ec6cd..56bd96d528 100644 --- a/src/solver/impls/arkode/arkode.hxx +++ b/src/solver/impls/arkode/arkode.hxx @@ -33,9 +33,6 @@ class ArkodeSolver; #ifndef __ARKODE_SOLVER_H__ #define __ARKODE_SOLVER_H__ -// NOTE: MPI must be included before SUNDIALS, otherwise complains -#include "mpi.h" - #include "bout_types.hxx" #include "field2d.hxx" #include "field3d.hxx" @@ -44,12 +41,15 @@ class ArkodeSolver; #include "bout/solver.hxx" -#include -#include -#include - #include +#include +#if SUNDIALS_VERSION_MAJOR >= 3 +#include +#endif + +#include + #include namespace { RegisterSolver registersolverarkode("arkode"); @@ -94,6 +94,12 @@ class ArkodeSolver : public Solver { void loop_abstol_values_op(Ind2D i2d, BoutReal *abstolvec_data, int &p, std::vector &f2dtols, std::vector &f3dtols, bool bndry); + +#if SUNDIALS_VERSION_MAJOR >= 3 + /// SPGMR solver structure + SUNLinearSolver sun_solver{nullptr}; +#endif + }; #endif // __ARKODE_SOLVER_H__ diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index 0fa02c71c6..8cb5674180 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -33,6 +33,15 @@ #include #include +#include + +#if SUNDIALS_VERSION_MAJOR >= 3 +#include +#include +#else +#include +#endif + #include #include #include @@ -54,15 +63,33 @@ static int cvode_rhs(BoutReal t, N_Vector u, N_Vector du, void *user_data); static int cvode_bbd_rhs(CVODEINT Nlocal, BoutReal t, N_Vector u, N_Vector du, void *user_data); -static int cvode_pre(BoutReal t, N_Vector yy, N_Vector yp, - N_Vector rvec, N_Vector zvec, - BoutReal gamma, BoutReal delta, int lr, - void *user_data, N_Vector tmp); +static int cvode_pre(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rvec, N_Vector zvec, + BoutReal gamma, BoutReal delta, int lr, void* user_data); + +#if SUNDIALS_VERSION_MAJOR < 3 +// Shim for earlier versions +inline static int cvode_pre_shim(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rvec, + N_Vector zvec, BoutReal gamma, BoutReal delta, int lr, + void* user_data, N_Vector UNUSED(tmp)) { + return cvode_pre(t, yy, yp, rvec, zvec, gamma, delta, lr, user_data); +} +#else +// Alias for newer versions +constexpr auto& cvode_pre_shim = cvode_pre; +#endif static int cvode_jac(N_Vector v, N_Vector Jv, realtype t, N_Vector y, N_Vector fy, void *user_data, N_Vector tmp); +#if SUNDIALS_VERSION_MAJOR < 3 +// Shim for earlier versions +inline int CVSpilsSetJacTimes(void* arkode_mem, std::nullptr_t, + CVSpilsJacTimesVecFn jtimes) { + return CVSpilsSetJacTimesVecFn(arkode_mem, jtimes); +} +#endif + CvodeSolver::CvodeSolver(Options *opts) : Solver(opts) { has_constraints = false; ///< This solver doesn't have constraints @@ -75,6 +102,9 @@ CvodeSolver::~CvodeSolver() { if(initialised) { N_VDestroy_Parallel(uvec); CVodeFree(&cvode_mem); +#if SUNDIALS_VERSION_MAJOR >= 3 + SUNLinSolFree(sun_solver); +#endif } } @@ -279,8 +309,16 @@ int CvodeSolver::init(int nout, BoutReal tstep) { if (rightprec) prectype = PREC_RIGHT; - if ( CVSpgmr(cvode_mem, prectype, maxl) != CVSPILS_SUCCESS ) +#if SUNDIALS_VERSION_MAJOR >= 3 + if ((sun_solver = SUNSPGMR(static_cast(uvec), prectype, maxl)) + == nullptr) + throw BoutException("ERROR: SUNSPGMR failed\n"); + if (CVSpilsSetLinearSolver(cvode_mem, sun_solver) != CVSPILS_SUCCESS) + throw BoutException("ERROR: CVSpilsSetLinearSolver failed\n"); +#else + if (CVSpgmr(cvode_mem, prectype, maxl) != CVSPILS_SUCCESS) throw BoutException("ERROR: CVSpgmr failed\n"); +#endif if (!have_user_precon()) { output_info.write("\tUsing BBD preconditioner\n"); @@ -292,7 +330,7 @@ int CvodeSolver::init(int nout, BoutReal tstep) { } else { output_info.write("\tUsing user-supplied preconditioner\n"); - if (CVSpilsSetPreconditioner(cvode_mem, nullptr, cvode_pre)) + if (CVSpilsSetPreconditioner(cvode_mem, nullptr, cvode_pre_shim)) throw BoutException("ERROR: CVSpilsSetPreconditioner failed\n"); } }else { @@ -300,8 +338,16 @@ int CvodeSolver::init(int nout, BoutReal tstep) { output_info.write("\tNo preconditioning\n"); - if( CVSpgmr(cvode_mem, PREC_NONE, maxl) != CVSPILS_SUCCESS ) +#if SUNDIALS_VERSION_MAJOR >= 3 + if ((sun_solver = SUNSPGMR(static_cast(uvec), PREC_NONE, maxl)) + == nullptr) + throw BoutException("ERROR: SUNSPGMR failed\n"); + if (CVSpilsSetLinearSolver(cvode_mem, sun_solver) != CVSPILS_SUCCESS) + throw BoutException("ERROR: CVSpilsSetLinearSolver failed\n"); +#else + if (CVSpgmr(cvode_mem, PREC_NONE, maxl) != CVSPILS_SUCCESS) throw BoutException("ERROR: CVSpgmr failed\n"); +#endif } /// Set Jacobian-vector multiplication function @@ -310,9 +356,9 @@ int CvodeSolver::init(int nout, BoutReal tstep) { output_info.write("\tUsing user-supplied Jacobian function\n"); TRACE("Setting Jacobian-vector multiply"); - if( CVSpilsSetJacTimesVecFn(cvode_mem, cvode_jac) != CVSPILS_SUCCESS ) + if (CVSpilsSetJacTimes(cvode_mem, nullptr, cvode_jac) != CVSPILS_SUCCESS) throw BoutException("ERROR: CVSpilsSetJacTimesVecFn failed\n"); - }else + } else output_info.write("\tUsing difference quotient approximation for Jacobian\n"); }else { output_info.write("\tUsing Functional iteration\n"); @@ -557,7 +603,7 @@ static int cvode_bbd_rhs(CVODEINT UNUSED(Nlocal), BoutReal t, N_Vector u, N_Vect /// Preconditioner function static int cvode_pre(BoutReal t, N_Vector yy, N_Vector UNUSED(yp), N_Vector rvec, N_Vector zvec, BoutReal gamma, BoutReal delta, int UNUSED(lr), - void *user_data, N_Vector UNUSED(tmp)) { + void *user_data) { BoutReal *udata = NV_DATA_P(yy); BoutReal *rdata = NV_DATA_P(rvec); BoutReal *zdata = NV_DATA_P(zvec); diff --git a/src/solver/impls/cvode/cvode.hxx b/src/solver/impls/cvode/cvode.hxx index 4bf8124b39..e73c028a6d 100644 --- a/src/solver/impls/cvode/cvode.hxx +++ b/src/solver/impls/cvode/cvode.hxx @@ -32,9 +32,6 @@ class CvodeSolver; #ifndef __SUNDIAL_SOLVER_H__ #define __SUNDIAL_SOLVER_H__ -// NOTE: MPI must be included before SUNDIALS, otherwise complains -#include "mpi.h" - #include "bout_types.hxx" #include "field2d.hxx" #include "field3d.hxx" @@ -43,12 +40,15 @@ class CvodeSolver; #include "bout/solver.hxx" -#include -#include -#include - #include +#include +#if SUNDIALS_VERSION_MAJOR >= 3 +#include +#endif + +#include + #include namespace { RegisterSolver registersolvercvode("cvode"); @@ -93,6 +93,11 @@ class CvodeSolver : public Solver { void loop_abstol_values_op(Ind2D i2d, BoutReal *abstolvec_data, int &p, std::vector &f2dtols, std::vector &f3dtols, bool bndry); +#if SUNDIALS_VERSION_MAJOR >= 3 + /// SPGMR solver structure + SUNLinearSolver sun_solver{nullptr}; +#endif + }; #endif // __SUNDIAL_SOLVER_H__ diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index 706ca47246..ca63c7111d 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -37,7 +37,14 @@ #include #include + +#if SUNDIALS_VERSION_MAJOR >= 3 +#include +#include +#else #include +#endif + #include #include #include @@ -58,17 +65,31 @@ typedef int IDAINT; static int idares(BoutReal t, N_Vector u, N_Vector du, N_Vector rr, void *user_data); static int ida_bbd_res(IDAINT Nlocal, BoutReal t, N_Vector u, N_Vector du, N_Vector rr, void *user_data); -static int ida_pre(BoutReal t, N_Vector yy, - N_Vector yp, N_Vector rr, - N_Vector rvec, N_Vector zvec, - BoutReal cj, BoutReal delta, - void *user_data, N_Vector tmp); + +static int ida_pre(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rr, N_Vector rvec, + N_Vector zvec, BoutReal cj, BoutReal delta, void* user_data); + +#if SUNDIALS_VERSION_MAJOR < 3 +// Shim for earlier versions +inline static int ida_pre_shim(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rr, + N_Vector rvec, N_Vector zvec, BoutReal cj, + BoutReal delta, void* user_data, N_Vector UNUSED(tmp)) { + return ida_pre(t, yy, yp, rr, rvec, zvec, cj, delta, user_data); +} +#else +// Alias for newer versions +constexpr auto& ida_pre_shim = ida_pre; +#endif IdaSolver::IdaSolver(Options *opts) : Solver(opts) { has_constraints = true; ///< This solver has constraints } -IdaSolver::~IdaSolver() { } +IdaSolver::~IdaSolver() { +#if SUNDIALS_VERSION_MAJOR >= 3 + SUNLinSolFree(sun_solver); +#endif +} /************************************************************************** * Initialise @@ -175,8 +196,15 @@ IdaSolver::~IdaSolver() { } IDASetMaxNumSteps(idamem, mxsteps); // Call IDASpgmr to specify the IDA linear solver IDASPGMR - if( IDASpgmr(idamem, maxl) ) +#if SUNDIALS_VERSION_MAJOR >= 3 + if ((sun_solver = SUNSPGMR(static_cast(uvec), PREC_NONE, maxl)) == nullptr) + throw BoutException("ERROR: SUNSPGMR failed\n"); + if (IDASpilsSetLinearSolver(idamem, sun_solver) != IDASPILS_SUCCESS) + throw BoutException("ERROR: IDASpilsSetLinearSolver failed\n"); +#else + if (IDASpgmr(idamem, maxl)) throw BoutException("ERROR: IDASpgmr failed\n"); +#endif if(use_precon) { if(!have_user_precon()) { @@ -186,7 +214,7 @@ IdaSolver::~IdaSolver() { } throw BoutException("ERROR: IDABBDPrecInit failed\n"); }else { output.write("\tUsing user-supplied preconditioner\n"); - if (IDASpilsSetPreconditioner(idamem, nullptr, ida_pre)) + if (IDASpilsSetPreconditioner(idamem, nullptr, ida_pre_shim)) throw BoutException("ERROR: IDASpilsSetPreconditioner failed\n"); } } @@ -346,7 +374,7 @@ static int ida_bbd_res(IDAINT UNUSED(Nlocal), BoutReal t, N_Vector u, N_Vector d // Preconditioner function static int ida_pre(BoutReal t, N_Vector yy, N_Vector UNUSED(yp), N_Vector UNUSED(rr), N_Vector rvec, N_Vector zvec, BoutReal cj, BoutReal delta, - void *user_data, N_Vector UNUSED(tmp)) { + void* user_data) { BoutReal *udata = NV_DATA_P(yy); BoutReal *rdata = NV_DATA_P(rvec); BoutReal *zdata = NV_DATA_P(zvec); diff --git a/src/solver/impls/ida/ida.hxx b/src/solver/impls/ida/ida.hxx index 575218f806..e1c4ecad8f 100644 --- a/src/solver/impls/ida/ida.hxx +++ b/src/solver/impls/ida/ida.hxx @@ -42,8 +42,10 @@ class IdaSolver; #include #include -// NOTE: MPI must be included before SUNDIALS, otherwise complains -#include "mpi.h" +#include +#if SUNDIALS_VERSION_MAJOR >= 3 +#include +#endif #include @@ -76,6 +78,11 @@ class IdaSolver : public Solver { BoutReal pre_Wtime; // Time in preconditioner BoutReal pre_ncalls; // Number of calls to preconditioner + +#if SUNDIALS_VERSION_MAJOR >= 3 + /// SPGMR solver structure + SUNLinearSolver sun_solver{nullptr}; +#endif }; #endif // __IDA_SOLVER_H__ From 5ce480cbc5185dbf64109c5b622551a7a524f652 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 20 Mar 2019 16:06:47 +0000 Subject: [PATCH 1059/1783] Clarify comment about setParallelTransform --- include/bout/coordinates.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index f65a91f76e..12ebc58e45 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -242,7 +242,7 @@ private: std::unique_ptr transform{nullptr}; /// Set the parallel (y) transform from the options file. - /// Usual way to create the transform object. + /// Used in the constructor to create the transform object. void setParallelTransform(Options* options); }; From 2a461cd6a7f9fab98df651a73a711524a3f5af01 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 4 Oct 2018 14:51:18 +0100 Subject: [PATCH 1060/1783] Bugfix: extrapolate geometric quantities into guard cells Previously used Neumann boundary conditions for metric components (and a couple of other geometric quantities) to set the guard cells when interpolating to staggered grids. This caused things that depend on derivatives of the metric, like G1/G2/G3 to have very different, and wrong, values at the boundaries. Now extrapolate instead, with the same stencil as free_o3 boundary conditions, but extrapolating only the points past the boundary. An extra interpolation has to be added after calling interp_to to get the interpolated field at the upper/outer boundary. --- src/mesh/coordinates.cxx | 71 ++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 4375cbbecc..1aa282c725 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -195,33 +195,46 @@ Coordinates::Coordinates(Mesh *mesh) namespace { /// Interpolate a Field2D to a new CELL_LOC with interp_to. /// Communicates to set internal guard cells. - /// Boundary guard cells are set equal to the nearest grid point (equivalent to - /// 2nd order accurate Neumann boundary condition). + /// Boundary guard cells are set by extrapolating from the grid, like + /// 'free_o3' boundary conditions /// Corner guard cells are set to BoutNaN - Field2D interpolateAndNeumann(const Field2D &f, CELL_LOC location) { + Field2D interpolateAndExtrapolate(const Field2D &f, CELL_LOC location) { Mesh* localmesh = f.getMesh(); Field2D result = interp_to(f, location, RGN_NOBNDRY); localmesh->communicate(result); - // Copy nearest value into boundaries so that differential geometry terms can - // be interpolated if necessary - // Note: cannot use applyBoundary("neumann") here because applyBoundary() + // Extrapolate into boundaries so that differential geometry terms can be + // interpolated if necessary + // Note: cannot use applyBoundary("free_o3") here because applyBoundary() // would try to create a new Coordinates object since we have not finished - // initializing yet, leading to an infinite recursion + // initializing yet, leading to an infinite recursion. + // Also, here we interpolate for the boundary points at xstart/ystart and + // (xend+1)/(yend+1) instead of extrapolating. for (auto bndry : localmesh->getBoundaries()) { - if (bndry->bx != 0) { - // If bx!=0 we are on an x-boundary, inner if bx>0 and outer if bx<0 - for(bndry->first(); !bndry->isDone(); bndry->next1d()) { - for (int i=0; ixstart; i++) - result(bndry->x+i*bndry->bx,bndry->y) = result(bndry->x+(i-1)*bndry->bx, bndry->y-bndry->by); - } - } - if (bndry->by != 0) { - // If by!=0 we are on a y-boundary, upper if by>0 and lower if by<0 - for(bndry->first(); !bndry->isDone(); bndry->next1d()) { - for (int i=0; iystart; i++) - result(bndry->x,bndry->y+i*bndry->by) = result(bndry->x-bndry->bx, bndry->y+(i-1)*bndry->by); + int extrap_start = 0; + if ( (location == CELL_XLOW) && (bndry->bx>0) ) + extrap_start = 1; + else if ( (location == CELL_YLOW) && (bndry->by>0) ) + extrap_start = 1; + for(bndry->first(); !bndry->isDone(); bndry->next1d()) { + // interpolate extra boundary point that is missed by interp_to, if + // necessary + if (extrap_start>0) { + // note that either bx or by is >0 here + result(bndry->x, bndry->y) = + ( 9.*(f(bndry->x-bndry->bx, bndry->y-bndry->by) + + f(bndry->x, bndry->y)) + - f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by) + - f(bndry->x+bndry->bx, bndry->y+bndry->by) + )/16.; } + + // extrapolate into boundary guard cells + for(int i=extrap_start;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + result(xi, yi) = 3.0*result(xi - bndry->bx, yi - bndry->by) - 3.0*result(xi - 2*bndry->bx, yi - 2*bndry->by) + result(xi - 3*bndry->bx, yi - 3*bndry->by); + } } } @@ -386,23 +399,23 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor } else { // Interpolate fields from coords_in - dx = interpolateAndNeumann(coords_in->dx, location); - dy = interpolateAndNeumann(coords_in->dy, location); + dx = interpolateAndExtrapolate(coords_in->dx, location); + dy = interpolateAndExtrapolate(coords_in->dy, location); // Diagonal components of metric tensor g^{ij} - g11 = interpolateAndNeumann(coords_in->g11, location); - g22 = interpolateAndNeumann(coords_in->g22, location); - g33 = interpolateAndNeumann(coords_in->g33, location); + g11 = interpolateAndExtrapolate(coords_in->g11, location); + g22 = interpolateAndExtrapolate(coords_in->g22, location); + g33 = interpolateAndExtrapolate(coords_in->g33, location); // Off-diagonal elements. - g12 = interpolateAndNeumann(coords_in->g12, location); - g13 = interpolateAndNeumann(coords_in->g13, location); - g23 = interpolateAndNeumann(coords_in->g23, location); + g12 = interpolateAndExtrapolate(coords_in->g12, location); + g13 = interpolateAndExtrapolate(coords_in->g13, location); + g23 = interpolateAndExtrapolate(coords_in->g23, location); - ShiftTorsion = interpolateAndNeumann(coords_in->ShiftTorsion, location); + ShiftTorsion = interpolateAndExtrapolate(coords_in->ShiftTorsion, location); if (mesh->IncIntShear) { - IntShiftTorsion = interpolateAndNeumann(coords_in->IntShiftTorsion, location); + IntShiftTorsion = interpolateAndExtrapolate(coords_in->IntShiftTorsion, location); } /// Always calculate contravariant metric components so that they are From dacb1dc94397c52b3403980fbe1465a95309fb70 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 7 Oct 2018 14:44:21 +0100 Subject: [PATCH 1061/1783] Fix extrapolation of metric when there are not enough grid cells When metrics are calculated on staggered grids, they are extrapolated into the boundary cells. Extrapolation requires 3 grid points. If there are fewer than 3, just copy the nearest value into the guard cells, since probably derivatives aren't being taken in that direction anyway. If only 1 guard cell and 1 grid point per processor in a certain direction are being used, then only have 2 points to extrapolate from on a processor, so cannot extrapolate to guard cells with 3rd order accuracy. In this case throw an exception because the user needs to change MXG/MYG or NXPE. --- src/mesh/coordinates.cxx | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 1aa282c725..199dbe732a 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -229,12 +229,32 @@ namespace { )/16.; } - // extrapolate into boundary guard cells - for(int i=extrap_start;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - result(xi, yi) = 3.0*result(xi - bndry->bx, yi - bndry->by) - 3.0*result(xi - 2*bndry->bx, yi - 2*bndry->by) + result(xi - 3*bndry->bx, yi - 3*bndry->by); - } + // set boundary guard cells + if ((bndry->bx != 0 && localmesh->GlobalNx-2*bndry->width >= 3) || (bndry->by != 0 && localmesh->GlobalNy-2*bndry->width >= 3)) { + if (bndry->bx != 0 && localmesh->LocalNx == 1 && bndry->width == 1) { + throw BoutException("Not enough points in the x-direction on this " + "processor for extrapolation needed to use staggered grids. " + "Increase number of x-guard cells MXG or decrease number of " + "processors in the x-direction NXPE."); + } + if (bndry->by != 0 && localmesh->LocalNy == 1 && bndry->width == 1) { + throw BoutException("Not enough points in the y-direction on this " + "processor for extrapolation needed to use staggered grids. " + "Increase number of y-guard cells MYG or decrease number of " + "processors in the y-direction NYPE."); + } + // extrapolate into boundary guard cells if there are enough grid points + for(int i=extrap_start;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + result(xi, yi) = 3.0*result(xi - bndry->bx, yi - bndry->by) - 3.0*result(xi - 2*bndry->bx, yi - 2*bndry->by) + result(xi - 3*bndry->bx, yi - 3*bndry->by); + } + } else { + // not enough grid points to extrapolate, set equal to last grid point + for(int i=extrap_start;iwidth;i++) { + result(bndry->x + i*bndry->bx, bndry->y + i*bndry->by) = result(bndry->x - bndry->bx, bndry->y - bndry->by); + } + } } } From 31ee8ad67a57d89fd56c9c76796d91d8dc265e5b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 7 Oct 2018 23:47:06 +0100 Subject: [PATCH 1062/1783] interpolateAndExtrapolate: don't communicate original field We have 'result = interp_to(f, location, RGN_NOBNDRY)' but then communicate result. Need to ensure result's data is unique. Otherwise result might be a duplicate of f (if no interpolation is needed, e.g. if interpolation is in the z-direction); then f would be communicated. Since this function is used on geometrical quantities that might not be periodic in y even on closed field lines (due to dependence on integrated shear), we don't want to communicate f. We will sort out result's boundary guard cells, but not f's so we don't want to change f. --- src/mesh/coordinates.cxx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 199dbe732a..177a5c9c5c 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -201,6 +201,14 @@ namespace { Field2D interpolateAndExtrapolate(const Field2D &f, CELL_LOC location) { Mesh* localmesh = f.getMesh(); Field2D result = interp_to(f, location, RGN_NOBNDRY); + // Ensure result's data is unique. Otherwise result might be a duplicate of + // f (if no interpolation is needed, e.g. if interpolation is in the + // z-direction); then f would be communicated. Since this function is used + // on geometrical quantities that might not be periodic in y even on closed + // field lines (due to dependence on integrated shear), we don't want to + // communicate f. We will sort out result's boundary guard cells below, but + // not f's so we don't want to change f. + result.allocate(); localmesh->communicate(result); // Extrapolate into boundaries so that differential geometry terms can be From 4136f358e1d2e6f7a50ebb5454ef9eb66a8b4d2f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 27 Feb 2019 12:52:56 +0000 Subject: [PATCH 1063/1783] Extrapolate metrics into the boundary instead of using Neumann bc --- src/mesh/coordinates.cxx | 235 +++++++++++++++++++++------------------ 1 file changed, 125 insertions(+), 110 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 177a5c9c5c..8201d5390a 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -17,6 +17,115 @@ #include +// use anonymous namespace so this utility function is not available outside this file +namespace { +/// Interpolate a Field2D to a new CELL_LOC with interp_to. +/// Communicates to set internal guard cells. +/// Boundary guard cells are set by extrapolating from the grid, like +/// 'free_o3' boundary conditions +/// Corner guard cells are set to BoutNaN +Field2D interpolateAndExtrapolate(const Field2D &f, CELL_LOC location) { + Mesh* localmesh = f.getMesh(); + Field2D result = interp_to(f, location, RGN_NOBNDRY); + // Ensure result's data is unique. Otherwise result might be a duplicate of + // f (if no interpolation is needed, e.g. if interpolation is in the + // z-direction); then f would be communicated. Since this function is used + // on geometrical quantities that might not be periodic in y even on closed + // field lines (due to dependence on integrated shear), we don't want to + // communicate f. We will sort out result's boundary guard cells below, but + // not f's so we don't want to change f. + result.allocate(); + localmesh->communicate(result); + + // Extrapolate into boundaries so that differential geometry terms can be + // interpolated if necessary + // Note: cannot use applyBoundary("free_o3") here because applyBoundary() + // would try to create a new Coordinates object since we have not finished + // initializing yet, leading to an infinite recursion. + // Also, here we interpolate for the boundary points at xstart/ystart and + // (xend+1)/(yend+1) instead of extrapolating. + for (auto bndry : localmesh->getBoundaries()) { + int extrap_start = 0; + if ( (location == CELL_XLOW) && (bndry->bx>0) ) { + extrap_start = 1; + } + else if ( (location == CELL_YLOW) && (bndry->by>0) ) { + extrap_start = 1; + } + for(bndry->first(); !bndry->isDone(); bndry->next1d()) { + // interpolate extra boundary point that is missed by interp_to, if + // necessary + if (extrap_start>0) { + // note that either bx or by is >0 here + result(bndry->x, bndry->y) = + ( 9.*(f(bndry->x-bndry->bx, bndry->y-bndry->by) + + f(bndry->x, bndry->y)) + - f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by) + - f(bndry->x+bndry->bx, bndry->y+bndry->by) + )/16.; + } + + // set boundary guard cells + if ((bndry->bx != 0 && localmesh->GlobalNx-2*bndry->width >= 3) || (bndry->by != 0 && localmesh->GlobalNy-2*bndry->width >= 3)) { + if (bndry->bx != 0 && localmesh->LocalNx == 1 && bndry->width == 1) { + throw BoutException("Not enough points in the x-direction on this " + "processor for extrapolation needed to use staggered grids. " + "Increase number of x-guard cells MXG or decrease number of " + "processors in the x-direction NXPE."); + } + if (bndry->by != 0 && localmesh->LocalNy == 1 && bndry->width == 1) { + throw BoutException("Not enough points in the y-direction on this " + "processor for extrapolation needed to use staggered grids. " + "Increase number of y-guard cells MYG or decrease number of " + "processors in the y-direction NYPE."); + } + // extrapolate into boundary guard cells if there are enough grid points + for(int i=extrap_start;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + result(xi, yi) = 3.0*result(xi - bndry->bx, yi - bndry->by) - 3.0*result(xi - 2*bndry->bx, yi - 2*bndry->by) + result(xi - 3*bndry->bx, yi - 3*bndry->by); + } + } else { + // not enough grid points to extrapolate, set equal to last grid point + for(int i=extrap_start;iwidth;i++) { + result(bndry->x + i*bndry->bx, bndry->y + i*bndry->by) = result(bndry->x - bndry->bx, bndry->y - bndry->by); + } + } + } + } + + // Set corner guard cells + for (int i=0; ixstart; i++) { + for (int j=0; jystart; j++) { + result(i, j) = BoutNaN; + result(i, localmesh->LocalNy-1-j) = BoutNaN; + result(localmesh->LocalNx-1-i, j) = BoutNaN; + result(localmesh->LocalNx-1-i, localmesh->LocalNy-1-j) = BoutNaN; + } + } + + return result; +} + +// If the CELL_CENTRE variable was read, the staggered version is required to +// also exist for consistency +void checkStaggeredGet(Mesh* mesh, std::string name, std::string suffix) { + if (mesh->sourceHasVar(name) != mesh->sourceHasVar(name+suffix)) { + throw BoutException("Attempting to read staggered fields from grid, but " + name + + " is not present in both CELL_CENTRE and staggered versions."); + } +} + +// convenience function for repeated code +void getAtLoc(Mesh* mesh, Field2D &var, std::string name, std::string suffix, + CELL_LOC location, BoutReal default_value = 0.) { + + checkStaggeredGet(mesh, name, suffix); + mesh->get(var, name+suffix, default_value); + var.setLocation(location); +} +} + Coordinates::Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2D J, Field2D Bxy, Field2D g11, Field2D g22, Field2D g33, Field2D g12, Field2D g13, Field2D g23, Field2D g_11, Field2D g_22, @@ -48,10 +157,14 @@ Coordinates::Coordinates(Mesh *mesh) G3_23(mesh), G1(mesh), G2(mesh), G3(mesh), ShiftTorsion(mesh), IntShiftTorsion(mesh), localmesh(mesh), location(CELL_CENTRE) { + // Note: use 'interpolateAndExtrapolate' to set the boundary cells of the + // loaded fields. Ensures that derivatives are smooth at all the boundaries. + if (mesh->get(dx, "dx")) { output_warn.write("\tWARNING: differencing quantity 'dx' not found. Set to 1.0\n"); dx = 1.0; } + dx = interpolateAndExtrapolate(dx, location); if (mesh->periodicX) { mesh->communicate(dx); @@ -61,6 +174,7 @@ Coordinates::Coordinates(Mesh *mesh) output_warn.write("\tWARNING: differencing quantity 'dy' not found. Set to 1.0\n"); dy = 1.0; } + dy = interpolateAndExtrapolate(dy, location); nz = mesh->LocalNz; @@ -83,22 +197,28 @@ Coordinates::Coordinates(Mesh *mesh) // Diagonal components of metric tensor g^{ij} (default to 1) mesh->get(g11, "g11", 1.0); + g11 = interpolateAndExtrapolate(g11, location); mesh->get(g22, "g22", 1.0); + g22 = interpolateAndExtrapolate(g22, location); mesh->get(g33, "g33", 1.0); + g33 = interpolateAndExtrapolate(g33, location); // Off-diagonal elements. Default to 0 mesh->get(g12, "g12", 0.0); + g12 = interpolateAndExtrapolate(g12, location); mesh->get(g13, "g13", 0.0); + g13 = interpolateAndExtrapolate(g13, location); mesh->get(g23, "g23", 0.0); + g23 = interpolateAndExtrapolate(g23, location); // Check input metrics - if ((!finite(g11)) || (!finite(g22)) || (!finite(g33))) { + if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) || (!finite(g33, RGN_NOBNDRY))) { throw BoutException("\tERROR: Diagonal metrics are not finite!\n"); } - if ((min(g11) <= 0.0) || (min(g22) <= 0.0) || (min(g33) <= 0.0)) { + if ((min(g11, RGN_NOBNDRY) <= 0.0) || (min(g22, RGN_NOBNDRY) <= 0.0) || (min(g33, RGN_NOBNDRY) <= 0.0)) { throw BoutException("\tERROR: Diagonal metrics are negative!\n"); } - if ((!finite(g12)) || (!finite(g13)) || (!finite(g23))) { + if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) || (!finite(g23, RGN_NOBNDRY))) { throw BoutException("\tERROR: Off-diagonal metrics are not finite!\n"); } @@ -177,6 +297,7 @@ Coordinates::Coordinates(Mesh *mesh) output_warn.write("\tWARNING: No Torsion specified for zShift. Derivatives may not be correct\n"); ShiftTorsion = 0.0; } + ShiftTorsion = interpolateAndExtrapolate(ShiftTorsion, location); ////////////////////////////////////////////////////// @@ -185,119 +306,13 @@ Coordinates::Coordinates(Mesh *mesh) output_warn.write("\tWARNING: No Integrated torsion specified\n"); IntShiftTorsion = 0.0; } + IntShiftTorsion = interpolateAndExtrapolate(IntShiftTorsion, location); } else { // IntShiftTorsion will not be used, but set to zero to avoid uninitialized field IntShiftTorsion = 0.; } } -// use anonymous namespace so this utility function is not available outside this file -namespace { - /// Interpolate a Field2D to a new CELL_LOC with interp_to. - /// Communicates to set internal guard cells. - /// Boundary guard cells are set by extrapolating from the grid, like - /// 'free_o3' boundary conditions - /// Corner guard cells are set to BoutNaN - Field2D interpolateAndExtrapolate(const Field2D &f, CELL_LOC location) { - Mesh* localmesh = f.getMesh(); - Field2D result = interp_to(f, location, RGN_NOBNDRY); - // Ensure result's data is unique. Otherwise result might be a duplicate of - // f (if no interpolation is needed, e.g. if interpolation is in the - // z-direction); then f would be communicated. Since this function is used - // on geometrical quantities that might not be periodic in y even on closed - // field lines (due to dependence on integrated shear), we don't want to - // communicate f. We will sort out result's boundary guard cells below, but - // not f's so we don't want to change f. - result.allocate(); - localmesh->communicate(result); - - // Extrapolate into boundaries so that differential geometry terms can be - // interpolated if necessary - // Note: cannot use applyBoundary("free_o3") here because applyBoundary() - // would try to create a new Coordinates object since we have not finished - // initializing yet, leading to an infinite recursion. - // Also, here we interpolate for the boundary points at xstart/ystart and - // (xend+1)/(yend+1) instead of extrapolating. - for (auto bndry : localmesh->getBoundaries()) { - int extrap_start = 0; - if ( (location == CELL_XLOW) && (bndry->bx>0) ) - extrap_start = 1; - else if ( (location == CELL_YLOW) && (bndry->by>0) ) - extrap_start = 1; - for(bndry->first(); !bndry->isDone(); bndry->next1d()) { - // interpolate extra boundary point that is missed by interp_to, if - // necessary - if (extrap_start>0) { - // note that either bx or by is >0 here - result(bndry->x, bndry->y) = - ( 9.*(f(bndry->x-bndry->bx, bndry->y-bndry->by) - + f(bndry->x, bndry->y)) - - f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by) - - f(bndry->x+bndry->bx, bndry->y+bndry->by) - )/16.; - } - - // set boundary guard cells - if ((bndry->bx != 0 && localmesh->GlobalNx-2*bndry->width >= 3) || (bndry->by != 0 && localmesh->GlobalNy-2*bndry->width >= 3)) { - if (bndry->bx != 0 && localmesh->LocalNx == 1 && bndry->width == 1) { - throw BoutException("Not enough points in the x-direction on this " - "processor for extrapolation needed to use staggered grids. " - "Increase number of x-guard cells MXG or decrease number of " - "processors in the x-direction NXPE."); - } - if (bndry->by != 0 && localmesh->LocalNy == 1 && bndry->width == 1) { - throw BoutException("Not enough points in the y-direction on this " - "processor for extrapolation needed to use staggered grids. " - "Increase number of y-guard cells MYG or decrease number of " - "processors in the y-direction NYPE."); - } - // extrapolate into boundary guard cells if there are enough grid points - for(int i=extrap_start;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - result(xi, yi) = 3.0*result(xi - bndry->bx, yi - bndry->by) - 3.0*result(xi - 2*bndry->bx, yi - 2*bndry->by) + result(xi - 3*bndry->bx, yi - 3*bndry->by); - } - } else { - // not enough grid points to extrapolate, set equal to last grid point - for(int i=extrap_start;iwidth;i++) { - result(bndry->x + i*bndry->bx, bndry->y + i*bndry->by) = result(bndry->x - bndry->bx, bndry->y - bndry->by); - } - } - } - } - - // Set corner guard cells - for (int i=0; ixstart; i++) { - for (int j=0; jystart; j++) { - result(i, j) = BoutNaN; - result(i, localmesh->LocalNy-1-j) = BoutNaN; - result(localmesh->LocalNx-1-i, j) = BoutNaN; - result(localmesh->LocalNx-1-i, localmesh->LocalNy-1-j) = BoutNaN; - } - } - - return result; - } - - // If the CELL_CENTRE variable was read, the staggered version is required to - // also exist for consistency - void checkStaggeredGet(Mesh* mesh, std::string name, std::string suffix) { - if (mesh->sourceHasVar(name) != mesh->sourceHasVar(name+suffix)) { - throw BoutException("Attempting to read staggered fields from grid, but " + name - + " is not present in both CELL_CENTRE and staggered versions."); - } - } - - // convenience function for repeated code - void getAtLoc(Mesh* mesh, Field2D &var, std::string name, std::string suffix, - CELL_LOC location, BoutReal default_value = 0.) { - - checkStaggeredGet(mesh, name, suffix); - mesh->get(var, name+suffix, default_value); - var.setLocation(location); - } -} - Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coords_in, bool force_interpolate_from_centre) : dx(1, mesh), dy(1, mesh), dz(1), d1_dx(mesh), d1_dy(mesh), J(1, mesh), Bxy(1, mesh), From 32284a1ff610f9d81a6d464c34b2816684fe2a0f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 26 Feb 2019 15:02:56 +0000 Subject: [PATCH 1064/1783] Extrapolate calculated g_**, J, Bxy Extrapolating the derived fields seems to be more robust than calculating them from extrapolated covariant metric components. --- src/mesh/coordinates.cxx | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 8201d5390a..062ba3fa8f 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -255,6 +255,14 @@ Coordinates::Coordinates(Mesh *mesh) throw BoutException("Error in calcCovariant call"); } } + // More robust to extrapolate derived quantities directly, rather than + // deriving from extrapolated covariant metric components + g_11 = interpolateAndExtrapolate(g_11, location); + g_22 = interpolateAndExtrapolate(g_22, location); + g_33 = interpolateAndExtrapolate(g_33, location); + g_12 = interpolateAndExtrapolate(g_12, location); + g_13 = interpolateAndExtrapolate(g_13, location); + g_23 = interpolateAndExtrapolate(g_23, location); /// Calculate Jacobian and Bxy if (jacobian()) @@ -286,6 +294,10 @@ Coordinates::Coordinates(Mesh *mesh) throw BoutException("\tERROR: Bxy not finite everywhere!\n"); } } + // More robust to extrapolate derived quantities directly, rather than + // deriving from extrapolated covariant metric components + J = interpolateAndExtrapolate(J, location); + Bxy = interpolateAndExtrapolate(Bxy, location); ////////////////////////////////////////////////////// /// Calculate Christoffel symbols. Needs communication @@ -479,9 +491,21 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor throw BoutException("\tERROR: Staggered off-diagonal metrics are not finite!\n"); } + // More robust to extrapolate derived quantities directly, rather than + // deriving from extrapolated covariant metric components + g_11 = interpolateAndExtrapolate(g_11, location); + g_22 = interpolateAndExtrapolate(g_22, location); + g_33 = interpolateAndExtrapolate(g_33, location); + g_12 = interpolateAndExtrapolate(g_12, location); + g_13 = interpolateAndExtrapolate(g_13, location); + g_23 = interpolateAndExtrapolate(g_23, location); /// Calculate Jacobian and Bxy if (jacobian()) throw BoutException("Error in jacobian call while constructing staggered Coordinates"); + // More robust to extrapolate derived quantities directly, rather than + // deriving from extrapolated covariant metric components + J = interpolateAndExtrapolate(J, location); + Bxy = interpolateAndExtrapolate(Bxy, location); ////////////////////////////////////////////////////// /// Calculate Christoffel symbols. Needs communication From 6a6208072ac1b1d4bd3d2c1d613e63f3dc7108f0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 20 Mar 2019 16:13:18 +0000 Subject: [PATCH 1065/1783] Simplify call to calcParallelSlices in Mesh::communicate() --- src/mesh/mesh.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index c078cd3e42..9f2f1d1866 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -194,7 +194,7 @@ void Mesh::communicate(FieldGroup &g) { // Calculate yup and ydown fields for 3D fields if (calcParallelSlices_on_communicate) { for(const auto& fptr : g.field3d()) { - fptr->getCoordinates()->getParallelTransform().calcParallelSlices(*fptr); + fptr->calcParallelSlices(); } } } From 7e6aec14412be5dff4f537aa90df845a279ce511 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 20 Mar 2019 17:30:32 +0000 Subject: [PATCH 1066/1783] Use getCoordinates() in Field3D::calcParallelSlices() Avoids a potential segfault if the fieldCoordinates pointer has not been initialized yet. --- src/field/field3d.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 9e86799f41..f536a3fcdc 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -300,7 +300,7 @@ Field3D & Field3D::operator=(const BoutReal val) { } Field3D& Field3D::calcParallelSlices() { - fieldCoordinates->getParallelTransform().calcParallelSlices(*this); + getCoordinates()->getParallelTransform().calcParallelSlices(*this); return *this; } From 0612be31fb304990301a1d3a33140046fa498360 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 20 Mar 2019 17:32:57 +0000 Subject: [PATCH 1067/1783] Update ARKODE, CVODE, IDA interfaces to support SUNDIALS 4.x --- src/solver/impls/arkode/arkode.cxx | 207 +++++++++++++++++++---------- src/solver/impls/arkode/arkode.hxx | 8 ++ src/solver/impls/cvode/cvode.cxx | 39 ++++-- src/solver/impls/cvode/cvode.hxx | 8 ++ src/solver/impls/ida/ida.cxx | 2 +- 5 files changed, 184 insertions(+), 80 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index b2674efc58..88ab0e9365 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -36,15 +36,16 @@ #if SUNDIALS_VERSION_MAJOR >= 4 #include +#include +#include #else #include -#endif - #if SUNDIALS_VERSION_MAJOR >= 3 #include #else #include #endif +#endif #include #include @@ -86,14 +87,73 @@ constexpr auto& arkode_pre_shim = arkode_pre; static int arkode_jac(N_Vector v, N_Vector Jv, realtype t, N_Vector y, N_Vector fy, void *user_data, N_Vector tmp); -#if SUNDIALS_VERSION_MAJOR < 3 +#if SUNDIALS_VERSION_MAJOR < 4 // Shim for earlier versions -inline int ARKSpilsSetJacTimes(void* arkode_mem, std::nullptr_t, - ARKSpilsJacTimesVecFn jtimes) { +inline int ARKStepSetJacTimes(void* arkode_mem, std::nullptr_t, + ARKSpilsJacTimesVecFn jtimes) { +#if SUNDIALS_VERSION_MAJOR < 3 return ARKSpilsSetJacTimesVecFn(arkode_mem, jtimes); +#else + return ARKSpilsSetJacTimes(arkode_mem, nullptr, jtimes); +#endif } #endif +#if SUNDIALS_VERSION_MAJOR < 4 +void* ARKStepCreate(ARKRhsFn fe, ARKRhsFn fi, BoutReal t0, N_Vector y0) { + auto arkode_mem = ARKodeCreate(); + + if (arkode_mem == nullptr) + throw BoutException("ARKodeCreate failed\n"); + if (ARKodeInit(arkode_mem, fe, fi, t0, y0) != ARK_SUCCESS) + throw BoutException("ARKodeInit failed\n"); + return arkode_mem; +} + +#if SUNDIALS_VERSION_MAJOR == 3 +int ARKStepSetLinearSolver(void* arkode_mem, SUNLinearSolver LS, std::nullptr_t) { + return ARKSpilsSetLinearSolver(arkode_mem, LS); +} + +namespace { +constexpr auto& SUNLinSol_SPGMR = SUNSPGMR; +} +#endif + +// Aliases for older versions +// In SUNDIALS 4, ARKode has become ARKStep, hence all the renames +constexpr auto& ARKStepEvolve = ARKode; +constexpr auto& ARKStepFree = ARKodeFree; +constexpr auto& ARKStepGetCurrentTime = ARKodeGetCurrentTime; +constexpr auto& ARKStepGetDky = ARKodeGetDky; +constexpr auto& ARKStepGetLastStep = ARKodeGetLastStep; +constexpr auto& ARKStepGetNumLinIters = ARKSpilsGetNumLinIters; +constexpr auto& ARKStepGetNumNonlinSolvIters = ARKodeGetNumNonlinSolvIters; +constexpr auto& ARKStepGetNumPrecEvals = ARKSpilsGetNumPrecEvals; +constexpr auto& ARKStepGetNumRhsEvals = ARKodeGetNumRhsEvals; +constexpr auto& ARKStepGetNumSteps = ARKodeGetNumSteps; +constexpr auto& ARKStepReInit = ARKodeReInit; +constexpr auto& ARKStepSStolerances = ARKodeSStolerances; +constexpr auto& ARKStepSVtolerances = ARKodeSVtolerances; +constexpr auto& ARKStepSetAdaptivityMethod = ARKodeSetAdaptivityMethod; +constexpr auto& ARKStepSetCFLFraction = ARKodeSetCFLFraction; +constexpr auto& ARKStepSetEpsLin = ARKSpilsSetEpsLin; +constexpr auto& ARKStepSetExplicit = ARKodeSetExplicit; +constexpr auto& ARKStepSetFixedPoint = ARKodeSetFixedPoint; +constexpr auto& ARKStepSetFixedStep = ARKodeSetFixedStep; +constexpr auto& ARKStepSetImEx = ARKodeSetImEx; +constexpr auto& ARKStepSetImplicit = ARKodeSetImplicit; +constexpr auto& ARKStepSetInitStep = ARKodeSetInitStep; +constexpr auto& ARKStepSetLinear = ARKodeSetLinear; +constexpr auto& ARKStepSetMaxNumSteps = ARKodeSetMaxNumSteps; +constexpr auto& ARKStepSetMaxStep = ARKodeSetMaxStep; +constexpr auto& ARKStepSetMinStep = ARKodeSetMinStep; +constexpr auto& ARKStepSetOptimalParams = ARKodeSetOptimalParams; +constexpr auto& ARKStepSetOrder = ARKodeSetOrder; +constexpr auto& ARKStepSetPreconditioner = ARKSpilsSetPreconditioner; +constexpr auto& ARKStepSetUserData = ARKodeSetUserData; +#endif + ArkodeSolver::ArkodeSolver(Options *opts) : Solver(opts) { has_constraints = false; ///< This solver doesn't have constraints @@ -103,9 +163,12 @@ ArkodeSolver::ArkodeSolver(Options *opts) : Solver(opts) { ArkodeSolver::~ArkodeSolver() { if (initialised) { N_VDestroy_Parallel(uvec); - ARKodeFree(&arkode_mem); + ARKStepFree(&arkode_mem); #if SUNDIALS_VERSION_MAJOR >= 3 SUNLinSolFree(sun_solver); +#endif +#if SUNDIALS_VERSION_MAJOR >= 4 + SUNNonlinSolFree(nonlinear_solver); #endif } } @@ -227,67 +290,65 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { options->get("implicit",impl,true);//Solve only implicit part } - {TRACE("Calling ARKodeCreate"); - if ((arkode_mem = ARKodeCreate()) == nullptr) - throw BoutException("ARKodeCreate failed\n"); - } - - {TRACE("Calling ARKodeSetUserData"); - if( ARKodeSetUserData(arkode_mem, this) != ARK_SUCCESS ) // For callbacks, need pointer to solver object - throw BoutException("ARKodeSetUserData failed\n"); - } - if(imex) { //Use ImEx solver output.write("\tUsing ARKode ImEx solver \n"); - {TRACE("Calling ARKodeInit"); - if( ARKodeInit(arkode_mem, arkode_rhs_e, arkode_rhs_i, simtime, uvec) != ARK_SUCCESS ) //arkode_rhs_e holds the explicit part, arkode_rhs_i holds the implicit part - throw BoutException("ARKodeInit failed\n"); + {TRACE("Calling ARKStepCreate"); + //arkode_rhs_e holds the explicit part, arkode_rhs_i holds the implicit part + if ((arkode_mem = ARKStepCreate(arkode_rhs_e, arkode_rhs_i, simtime, uvec)) + == nullptr) + throw BoutException("ARKStepCreate failed\n"); } - + if(expl && impl){ TRACE("Calling ARKodeSetImEx"); - if( ARKodeSetImEx(arkode_mem) != ARK_SUCCESS ) + if( ARKStepSetImEx(arkode_mem) != ARK_SUCCESS ) throw BoutException("ARKodeSetImEx failed\n"); } else if(expl){ TRACE("Calling ARKodeSetExplicit"); - if( ARKodeSetExplicit(arkode_mem) != ARK_SUCCESS ) + if( ARKStepSetExplicit(arkode_mem) != ARK_SUCCESS ) throw BoutException("ARKodeSetExplicit failed\n"); } else { TRACE("Calling ARKodeSetImplicit"); - if( ARKodeSetImplicit(arkode_mem) != ARK_SUCCESS ) + if( ARKStepSetImplicit(arkode_mem) != ARK_SUCCESS ) throw BoutException("ARKodeSetExplicit failed\n"); } } else { if(expl){ //Use purely explicit solver output.write("\tUsing ARKode Explicit solver \n"); - {TRACE("Calling ARKodeInit"); - if (ARKodeInit(arkode_mem, arkode_rhs, nullptr, simtime, uvec) != - ARK_SUCCESS) // arkode_rhs_e holds the explicit part, arkode_rhs_i holds the - // implicit part - throw BoutException("ARKodeInit failed\n"); + {TRACE("Calling ARKStepCreate"); + // arkode_rhs_e holds the explicit part, arkode_rhs_i holds + // the implicit part + if ((arkode_mem = ARKStepCreate(arkode_rhs, nullptr, simtime, uvec)) == nullptr) + throw BoutException("ARKStepCreate failed\n"); } TRACE("Calling ARKodeSetExplicit"); - if( ARKodeSetExplicit(arkode_mem) != ARK_SUCCESS ) + if( ARKStepSetExplicit(arkode_mem) != ARK_SUCCESS ) throw BoutException("ARKodeSetExplicit failed\n"); } else { //Use purely implicit solver output.write("\tUsing ARKode Implicit solver \n"); - {TRACE("Calling ARKodeInit"); + {TRACE("Calling ARKStepCreate"); // arkode_rhs_e holds the explicit part, arkode_rhs_i holds // the implicit part - if (ARKodeInit(arkode_mem, nullptr, arkode_rhs, simtime, uvec) != ARK_SUCCESS) - throw BoutException("ARKodeInit failed\n"); + if ((arkode_mem = ARKStepCreate(nullptr, arkode_rhs, simtime, uvec)) == nullptr) + throw BoutException("ARKStepCreate failed\n"); } TRACE("Calling ARKodeSetImplicit"); - if( ARKodeSetImplicit(arkode_mem) != ARK_SUCCESS ) + if( ARKStepSetImplicit(arkode_mem) != ARK_SUCCESS ) throw BoutException("ARKodeSetExplicit failed\n"); } } + {TRACE("Calling ARKodeSetUserData"); + // For callbacks, need pointer to solver object + if (ARKStepSetUserData(arkode_mem, this) != ARK_SUCCESS) + throw BoutException("ARKodeSetUserData failed\n"); + } + OPTION(options,set_linear,false); if(set_linear){ //Use linear implicit solver (only evaluates jacobian inversion once output.write("\tSetting ARKode implicit solver to Linear\n"); - if( ARKodeSetLinear(arkode_mem,1) != ARK_SUCCESS ) + if( ARKStepSetLinear(arkode_mem,1) != ARK_SUCCESS ) throw BoutException("ARKodeSetLinear failed\n"); } @@ -296,17 +357,17 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { if(fixed_step){ options->get("timestep",fixed_timestep,0.0); //If not given, default to adaptive timestepping TRACE("Calling ARKodeSetFixedStep"); - if( ARKodeSetFixedStep(arkode_mem,fixed_timestep) != ARK_SUCCESS ) + if( ARKStepSetFixedStep(arkode_mem,fixed_timestep) != ARK_SUCCESS ) throw BoutException("ARKodeSetFixedStep failed\n"); } {TRACE("Calling ARKodeSetOrder"); - if ( ARKodeSetOrder(arkode_mem, order) != ARK_SUCCESS) + if ( ARKStepSetOrder(arkode_mem, order) != ARK_SUCCESS) throw BoutException("ARKodeSetOrder failed\n"); } {TRACE("Calling ARKodeSetCFLFraction"); - if( ARKodeSetCFLFraction(arkode_mem, cfl_frac) != ARK_SUCCESS) + if( ARKStepSetCFLFraction(arkode_mem, cfl_frac) != ARK_SUCCESS) throw BoutException("ARKodeSetCFLFraction failed\n"); } @@ -321,41 +382,41 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { // 5 -> ImEx Gustafsson {TRACE("Calling ARKodeSetAdaptivityMethod"); - if (ARKodeSetAdaptivityMethod(arkode_mem, adap_method, 1, 1, nullptr) != ARK_SUCCESS) + if (ARKStepSetAdaptivityMethod(arkode_mem, adap_method, 1, 1, nullptr) != ARK_SUCCESS) throw BoutException("ARKodeSetAdaptivityMethod failed\n"); } if (use_vector_abstol) { TRACE("Calling ARKodeSVtolerances"); - if( ARKodeSVtolerances(arkode_mem, reltol, abstolvec) != ARK_SUCCESS ) + if( ARKStepSVtolerances(arkode_mem, reltol, abstolvec) != ARK_SUCCESS ) throw BoutException("ARKodeSVtolerances failed\n"); } else { TRACE("Calling ARKodeSStolerances"); - if( ARKodeSStolerances(arkode_mem, reltol, abstol) != ARK_SUCCESS ) + if( ARKStepSStolerances(arkode_mem, reltol, abstol) != ARK_SUCCESS ) throw BoutException("ARKodeSStolerances failed\n"); } {TRACE("Calling ARKodeSetMaxNumSteps"); - if( ARKodeSetMaxNumSteps(arkode_mem, mxsteps) != ARK_SUCCESS ) + if( ARKStepSetMaxNumSteps(arkode_mem, mxsteps) != ARK_SUCCESS ) throw BoutException("ARKodeSetMaxNumSteps failed\n"); } if(max_timestep > 0.0) { TRACE("Calling ARKodeSetMaxStep"); - if( ARKodeSetMaxStep(arkode_mem, max_timestep) != ARK_SUCCESS ) + if( ARKStepSetMaxStep(arkode_mem, max_timestep) != ARK_SUCCESS ) throw BoutException("ARKodeSetMaxStep failed\n"); } if(min_timestep > 0.0) { TRACE("Calling ARKodeSetMinStep"); - if( ARKodeSetMinStep(arkode_mem, min_timestep) != ARK_SUCCESS ) + if( ARKStepSetMinStep(arkode_mem, min_timestep) != ARK_SUCCESS ) throw BoutException("ARKodeSetMinStep failed\n"); } if(start_timestep > 0.0) { TRACE("Calling ARKodeSetInitStep"); - if( ARKodeSetInitStep(arkode_mem, start_timestep) != ARK_SUCCESS ) + if( ARKStepSetInitStep(arkode_mem, start_timestep) != ARK_SUCCESS ) throw BoutException("ARKodeSetInitStep failed"); } @@ -365,6 +426,7 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { bool fixed_point; OPTION(options,fixed_point,false); +#if SUNDIALS_VERSION_MAJOR < 4 if(fixed_point){ //Use accellerated fixed point output.write("\tUsing accellerated fixed point solver\n"); if( ARKodeSetFixedPoint(arkode_mem, 3.0) ) @@ -374,7 +436,19 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { if( ARKodeSetNewton(arkode_mem) ) throw BoutException("ARKodeSetNewton failed\n"); } - +#else + if (fixed_point) { + output.write("\tUsing accelerated fixed point solver\n"); + if ((nonlinear_solver = SUNNonlinSol_FixedPoint(uvec, 3)) == nullptr) + throw BoutException("ARKodeSetFixedPoint failed\n"); + } else { + output.write("\tUsing Newton iteration\n"); + if ((nonlinear_solver = SUNNonlinSol_Newton(uvec)) == nullptr) + throw BoutException("ARKodeSetNewton failed\n"); + } + if (ARKStepSetNonlinearSolver(arkode_mem, nonlinear_solver) != ARK_SUCCESS) + throw BoutException("ARKStepSetNonlinearSolver failed\n"); +#endif /// Set Preconditioner TRACE("Setting preconditioner"); if(use_precon) { @@ -386,9 +460,9 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { prectype = PREC_RIGHT; #if SUNDIALS_VERSION_MAJOR >= 3 - if ((sun_solver = SUNSPGMR(static_cast(uvec), prectype, maxl)) == nullptr) + if ((sun_solver = SUNLinSol_SPGMR(uvec, prectype, maxl)) == nullptr) throw BoutException("ERROR: SUNSPGMR failed\n"); - if (ARKSpilsSetLinearSolver(arkode_mem, sun_solver) != ARKSPILS_SUCCESS) + if (ARKStepSetLinearSolver(arkode_mem, sun_solver, nullptr) != ARK_SUCCESS) throw BoutException("ERROR: ARKSpilsSetLinearSolver failed\n"); #else if (ARKSpgmr(arkode_mem, prectype, maxl) != ARKSPILS_SUCCESS) @@ -399,14 +473,14 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { output.write("\tUsing BBD preconditioner\n"); if (ARKBBDPrecInit(arkode_mem, local_N, mudq, mldq, mukeep, mlkeep, ZERO, - arkode_bbd_rhs, nullptr) != ARKSPILS_SUCCESS) + arkode_bbd_rhs, nullptr) != ARK_SUCCESS) throw BoutException("ERROR: ARKBBDPrecInit failed\n"); } else { output.write("\tUsing user-supplied preconditioner\n"); - if (ARKSpilsSetPreconditioner(arkode_mem, nullptr, arkode_pre_shim) != - ARKSPILS_SUCCESS) + if (ARKStepSetPreconditioner(arkode_mem, nullptr, arkode_pre_shim) != + ARK_SUCCESS) throw BoutException("ERROR: ARKSpilsSetPreconditioner failed\n"); } }else { @@ -415,10 +489,9 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { output.write("\tNo preconditioning\n"); #if SUNDIALS_VERSION_MAJOR >= 3 - if ((sun_solver = SUNSPGMR(static_cast(uvec), PREC_NONE, maxl)) - == nullptr) + if ((sun_solver = SUNLinSol_SPGMR(uvec, PREC_NONE, maxl)) == nullptr) throw BoutException("ERROR: SUNSPGMR failed\n"); - if (ARKSpilsSetLinearSolver(arkode_mem, sun_solver) != ARKSPILS_SUCCESS) + if (ARKStepSetLinearSolver(arkode_mem, sun_solver, nullptr) != ARK_SUCCESS) throw BoutException("ERROR: ARKSpilsSetLinearSolver failed\n"); #else if (ARKSpgmr(arkode_mem, PREC_NONE, maxl) != ARKSPILS_SUCCESS) @@ -432,7 +505,7 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { output.write("\tUsing user-supplied Jacobian function\n"); TRACE("Setting Jacobian-vector multiply"); - if (ARKSpilsSetJacTimes(arkode_mem, nullptr, arkode_jac) != ARKSPILS_SUCCESS) + if (ARKStepSetJacTimes(arkode_mem, nullptr, arkode_jac) != ARK_SUCCESS) throw BoutException("ERROR: ARKSpilsSetJacTimesVecFn failed\n"); }else output.write("\tUsing difference quotient approximation for Jacobian\n"); @@ -443,7 +516,7 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { if(optimize){ TRACE("Calling ARKodeSetOptimialParams"); output.write("\tUsing ARKode inbuilt optimization\n"); - if( ARKodeSetOptimalParams(arkode_mem) != ARK_SUCCESS ) + if( ARKStepSetOptimalParams(arkode_mem) != ARK_SUCCESS ) throw BoutException("ARKodeSetOptimalParams failed"); } return 0; @@ -478,11 +551,11 @@ int ArkodeSolver::run() { // Print additional diagnostics long int nsteps, nfe_evals, nfi_evals, nniters, npevals, nliters; - ARKodeGetNumSteps(arkode_mem, &nsteps); - ARKodeGetNumRhsEvals(arkode_mem, &nfe_evals, &nfi_evals); - ARKodeGetNumNonlinSolvIters(arkode_mem, &nniters); - ARKSpilsGetNumPrecEvals(arkode_mem, &npevals); - ARKSpilsGetNumLinIters(arkode_mem, &nliters); + ARKStepGetNumSteps(arkode_mem, &nsteps); + ARKStepGetNumRhsEvals(arkode_mem, &nfe_evals, &nfi_evals); + ARKStepGetNumNonlinSolvIters(arkode_mem, &nniters); + ARKStepGetNumPrecEvals(arkode_mem, &npevals); + ARKStepGetNumLinIters(arkode_mem, &nliters); output.write("\nARKODE: nsteps %ld, nfe_evals %ld, nfi_evals %ld, nniters %ld, npevals %ld, nliters %ld\n", nsteps, nfe_evals, nfi_evals, nniters, npevals, nliters); @@ -517,15 +590,15 @@ BoutReal ArkodeSolver::run(BoutReal tout) { int flag; if(!monitor_timestep) { // Run in normal mode - flag = ARKode(arkode_mem, tout, uvec, &simtime, ARK_NORMAL); + flag = ARKStepEvolve(arkode_mem, tout, uvec, &simtime, ARK_NORMAL); }else { // Run in single step mode, to call timestep monitors BoutReal internal_time; - ARKodeGetCurrentTime(arkode_mem, &internal_time); + ARKStepGetCurrentTime(arkode_mem, &internal_time); while(internal_time < tout) { // Run another step BoutReal last_time = internal_time; - flag = ARKode(arkode_mem, tout, uvec, &internal_time, ARK_ONE_STEP); + flag = ARKStepEvolve(arkode_mem, tout, uvec, &internal_time, ARK_ONE_STEP); if(flag != ARK_SUCCESS) { output_error.write("ERROR ARKODE solve failed at t = %e, flag = %d\n", internal_time, flag); @@ -536,7 +609,7 @@ BoutReal ArkodeSolver::run(BoutReal tout) { call_timestep_monitors(internal_time, internal_time - last_time); } // Get output at the desired time - flag = ARKodeGetDky(arkode_mem, tout, 0, uvec); + flag = ARKStepGetDky(arkode_mem, tout, 0, uvec); simtime = tout; } @@ -565,7 +638,7 @@ void ArkodeSolver::rhs_e(BoutReal t, BoutReal *udata, BoutReal *dudata) { // Get the current timestep // Note: ARKodeGetCurrentStep updated too late in older versions - ARKodeGetLastStep(arkode_mem, &hcur); + ARKStepGetLastStep(arkode_mem, &hcur); // Call RHS function run_convective(t); @@ -583,7 +656,7 @@ void ArkodeSolver::rhs_i(BoutReal t, BoutReal *udata, BoutReal *dudata) { TRACE("Running RHS: ArkodeSolver::rhs_i(%e)", t); load_vars(udata); - ARKodeGetLastStep(arkode_mem, &hcur); + ARKStepGetLastStep(arkode_mem, &hcur); // Call Implicit RHS function run_diffusive(t); save_derivs(dudata); @@ -597,7 +670,7 @@ void ArkodeSolver::rhs(BoutReal t, BoutReal *udata, BoutReal *dudata) { TRACE("Running RHS: ArkodeSolver::rhs(%e)", t); load_vars(udata); - ARKodeGetLastStep(arkode_mem, &hcur); + ARKStepGetLastStep(arkode_mem, &hcur); // Call Implicit RHS function run_rhs(t); save_derivs(dudata); diff --git a/src/solver/impls/arkode/arkode.hxx b/src/solver/impls/arkode/arkode.hxx index 56bd96d528..1044cc6cc6 100644 --- a/src/solver/impls/arkode/arkode.hxx +++ b/src/solver/impls/arkode/arkode.hxx @@ -48,6 +48,10 @@ class ArkodeSolver; #include #endif +#if SUNDIALS_VERSION_MAJOR >= 4 +#include +#endif + #include #include @@ -99,6 +103,10 @@ class ArkodeSolver : public Solver { /// SPGMR solver structure SUNLinearSolver sun_solver{nullptr}; #endif +#if SUNDIALS_VERSION_MAJOR >= 4 + /// Solver for functional iterations for Adams-Moulton + SUNNonlinearSolver nonlinear_solver{nullptr}; +#endif }; diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index 8cb5674180..2b3cf78a75 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -42,7 +42,6 @@ #include #endif -#include #include #include #include @@ -90,6 +89,17 @@ inline int CVSpilsSetJacTimes(void* arkode_mem, std::nullptr_t, } #endif +#if SUNDIALS_VERSION_MAJOR >= 4 +// Shim for newer versions +inline void* CVodeCreate(int lmm, int UNUSED(iter)) { return CVodeCreate(lmm); } +constexpr auto CV_FUNCTIONAL = 0; +constexpr auto CV_NEWTON = 0; +#elif SUNDIALS_VERSION_MAJOR == 3 +namespace { +constexpr auto& SUNLinSol_SPGMR = SUNSPGMR; +} +#endif + CvodeSolver::CvodeSolver(Options *opts) : Solver(opts) { has_constraints = false; ///< This solver doesn't have constraints @@ -104,6 +114,9 @@ CvodeSolver::~CvodeSolver() { CVodeFree(&cvode_mem); #if SUNDIALS_VERSION_MAJOR >= 3 SUNLinSolFree(sun_solver); +#endif +#if SUNDIALS_VERSION_MAJOR >= 4 + SUNNonlinSolFree(nonlinear_solver); #endif } } @@ -176,7 +189,6 @@ int CvodeSolver::init(int nout, BoutReal tstep) { int mxsteps; // Maximum number of steps to take between outputs int mxorder; // Maximum lmm order to be used by the solver int lmm = CV_BDF; - int iter = CV_NEWTON; {TRACE("Getting options"); options->get("mudq", mudq, band_width_default); @@ -231,12 +243,10 @@ int CvodeSolver::init(int nout, BoutReal tstep) { options->get("func_iter", func_iter, false); } - if(func_iter) - iter = CV_FUNCTIONAL; }//End of options TRACE - // Call CVodeCreate {TRACE("Calling CVodeCreate"); + const auto iter = func_iter ? CV_FUNCTIONAL : CV_NEWTON; if ((cvode_mem = CVodeCreate(lmm, iter)) == nullptr) throw BoutException("CVodeCreate failed\n"); } @@ -251,6 +261,13 @@ int CvodeSolver::init(int nout, BoutReal tstep) { throw BoutException("CVodeInit failed\n"); } +#if SUNDIALS_VERSION_MAJOR >= 4 + if ((nonlinear_solver = SUNNonlinSol_FixedPoint(uvec, 0)) == nullptr) + throw BoutException("SUNNonlinSol_FixedPoint failed\n"); + + if (CVodeSetNonlinearSolver(cvode_mem, nonlinear_solver)) + throw BoutException("CVodeSetNonlinearSolver failed\n"); +#endif if (max_order>0) { TRACE("Calling CVodeSetMaxOrder"); @@ -310,10 +327,9 @@ int CvodeSolver::init(int nout, BoutReal tstep) { prectype = PREC_RIGHT; #if SUNDIALS_VERSION_MAJOR >= 3 - if ((sun_solver = SUNSPGMR(static_cast(uvec), prectype, maxl)) - == nullptr) + if ((sun_solver = SUNLinSol_SPGMR(uvec, prectype, maxl)) == nullptr) throw BoutException("ERROR: SUNSPGMR failed\n"); - if (CVSpilsSetLinearSolver(cvode_mem, sun_solver) != CVSPILS_SUCCESS) + if (CVSpilsSetLinearSolver(cvode_mem, sun_solver) != CV_SUCCESS) throw BoutException("ERROR: CVSpilsSetLinearSolver failed\n"); #else if (CVSpgmr(cvode_mem, prectype, maxl) != CVSPILS_SUCCESS) @@ -339,10 +355,9 @@ int CvodeSolver::init(int nout, BoutReal tstep) { output_info.write("\tNo preconditioning\n"); #if SUNDIALS_VERSION_MAJOR >= 3 - if ((sun_solver = SUNSPGMR(static_cast(uvec), PREC_NONE, maxl)) - == nullptr) + if ((sun_solver = SUNLinSol_SPGMR(uvec, PREC_NONE, maxl)) == nullptr) throw BoutException("ERROR: SUNSPGMR failed\n"); - if (CVSpilsSetLinearSolver(cvode_mem, sun_solver) != CVSPILS_SUCCESS) + if (CVSpilsSetLinearSolver(cvode_mem, sun_solver) != CV_SUCCESS) throw BoutException("ERROR: CVSpilsSetLinearSolver failed\n"); #else if (CVSpgmr(cvode_mem, PREC_NONE, maxl) != CVSPILS_SUCCESS) @@ -356,7 +371,7 @@ int CvodeSolver::init(int nout, BoutReal tstep) { output_info.write("\tUsing user-supplied Jacobian function\n"); TRACE("Setting Jacobian-vector multiply"); - if (CVSpilsSetJacTimes(cvode_mem, nullptr, cvode_jac) != CVSPILS_SUCCESS) + if (CVSpilsSetJacTimes(cvode_mem, nullptr, cvode_jac) != CV_SUCCESS) throw BoutException("ERROR: CVSpilsSetJacTimesVecFn failed\n"); } else output_info.write("\tUsing difference quotient approximation for Jacobian\n"); diff --git a/src/solver/impls/cvode/cvode.hxx b/src/solver/impls/cvode/cvode.hxx index e73c028a6d..081fbcc88c 100644 --- a/src/solver/impls/cvode/cvode.hxx +++ b/src/solver/impls/cvode/cvode.hxx @@ -47,6 +47,10 @@ class CvodeSolver; #include #endif +#if SUNDIALS_VERSION_MAJOR >= 4 +#include +#endif + #include #include @@ -97,6 +101,10 @@ class CvodeSolver : public Solver { /// SPGMR solver structure SUNLinearSolver sun_solver{nullptr}; #endif +#if SUNDIALS_VERSION_MAJOR >= 4 + /// Solver for functional iterations for Adams-Moulton + SUNNonlinearSolver nonlinear_solver{nullptr}; +#endif }; diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index ca63c7111d..fa50671dbb 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -199,7 +199,7 @@ IdaSolver::~IdaSolver() { #if SUNDIALS_VERSION_MAJOR >= 3 if ((sun_solver = SUNSPGMR(static_cast(uvec), PREC_NONE, maxl)) == nullptr) throw BoutException("ERROR: SUNSPGMR failed\n"); - if (IDASpilsSetLinearSolver(idamem, sun_solver) != IDASPILS_SUCCESS) + if (IDASpilsSetLinearSolver(idamem, sun_solver) != IDA_SUCCESS) throw BoutException("ERROR: IDASpilsSetLinearSolver failed\n"); #else if (IDASpgmr(idamem, maxl)) From 5c426007d5a59379bf67586d64f9201ea8b64e75 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 20 Mar 2019 17:43:18 +0000 Subject: [PATCH 1068/1783] Clang-format sundials solvers headers --- src/solver/impls/arkode/arkode.hxx | 95 +++++++++++++++--------------- src/solver/impls/cvode/cvode.hxx | 95 +++++++++++++++--------------- src/solver/impls/ida/ida.hxx | 41 ++++++------- 3 files changed, 115 insertions(+), 116 deletions(-) diff --git a/src/solver/impls/arkode/arkode.hxx b/src/solver/impls/arkode/arkode.hxx index 1044cc6cc6..89e177b053 100644 --- a/src/solver/impls/arkode/arkode.hxx +++ b/src/solver/impls/arkode/arkode.hxx @@ -1,14 +1,14 @@ /************************************************************************** * Interface to ARKODE solver * NOTE: ARKode is currently in beta testing so use with cautious optimism - * + * * NOTE: Only one solver can currently be compiled in * ************************************************************************** * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -26,13 +26,13 @@ * **************************************************************************/ +#ifndef __ARKODE_SOLVER_H__ +#define __ARKODE_SOLVER_H__ + #ifdef BOUT_HAS_ARKODE class ArkodeSolver; -#ifndef __ARKODE_SOLVER_H__ -#define __ARKODE_SOLVER_H__ - #include "bout_types.hxx" #include "field2d.hxx" #include "field3d.hxx" @@ -60,44 +60,46 @@ RegisterSolver registersolverarkode("arkode"); } class ArkodeSolver : public Solver { - public: - ArkodeSolver(Options *opts = nullptr); - ~ArkodeSolver(); - - void setJacobian(Jacobian j) override { jacfunc = j; } - - BoutReal getCurrentTimestep() override { return hcur; } - - int init(int nout, BoutReal tstep) override; - - int run() override; - BoutReal run(BoutReal tout); - - // These functions used internally (but need to be public) - void rhs_e(BoutReal t, BoutReal *udata, BoutReal *dudata); - void rhs_i(BoutReal t, BoutReal *udata, BoutReal *dudata); - void rhs(BoutReal t, BoutReal *udata, BoutReal *dudata); - void pre(BoutReal t, BoutReal gamma, BoutReal delta, BoutReal *udata, BoutReal *rvec, BoutReal *zvec); - void jac(BoutReal t, BoutReal *ydata, BoutReal *vdata, BoutReal *Jvdata); - private: - int NOUT; // Number of outputs. Specified in init, needed in run - BoutReal TIMESTEP; // Time between outputs - BoutReal hcur; // Current internal timestep - - Jacobian jacfunc; // Jacobian - vector function - bool diagnose; // Output additional diagnostics - - N_Vector uvec; // Values - void *arkode_mem; - - BoutReal pre_Wtime; // Time in preconditioner - BoutReal pre_ncalls; // Number of calls to preconditioner - - void set_abstol_values(BoutReal *abstolvec_data, std::vector &f2dtols, - std::vector &f3dtols); - void loop_abstol_values_op(Ind2D i2d, BoutReal *abstolvec_data, int &p, - std::vector &f2dtols, - std::vector &f3dtols, bool bndry); +public: + ArkodeSolver(Options* opts = nullptr); + ~ArkodeSolver(); + + void setJacobian(Jacobian j) override { jacfunc = j; } + + BoutReal getCurrentTimestep() override { return hcur; } + + int init(int nout, BoutReal tstep) override; + + int run() override; + BoutReal run(BoutReal tout); + + // These functions used internally (but need to be public) + void rhs_e(BoutReal t, BoutReal* udata, BoutReal* dudata); + void rhs_i(BoutReal t, BoutReal* udata, BoutReal* dudata); + void rhs(BoutReal t, BoutReal* udata, BoutReal* dudata); + void pre(BoutReal t, BoutReal gamma, BoutReal delta, BoutReal* udata, BoutReal* rvec, + BoutReal* zvec); + void jac(BoutReal t, BoutReal* ydata, BoutReal* vdata, BoutReal* Jvdata); + +private: + int NOUT; // Number of outputs. Specified in init, needed in run + BoutReal TIMESTEP; // Time between outputs + BoutReal hcur; // Current internal timestep + + Jacobian jacfunc; // Jacobian - vector function + bool diagnose; // Output additional diagnostics + + N_Vector uvec; // Values + void* arkode_mem; + + BoutReal pre_Wtime; // Time in preconditioner + BoutReal pre_ncalls; // Number of calls to preconditioner + + void set_abstol_values(BoutReal* abstolvec_data, std::vector& f2dtols, + std::vector& f3dtols); + void loop_abstol_values_op(Ind2D i2d, BoutReal* abstolvec_data, int& p, + std::vector& f2dtols, + std::vector& f3dtols, bool bndry); #if SUNDIALS_VERSION_MAJOR >= 3 /// SPGMR solver structure @@ -107,10 +109,7 @@ class ArkodeSolver : public Solver { /// Solver for functional iterations for Adams-Moulton SUNNonlinearSolver nonlinear_solver{nullptr}; #endif - }; -#endif // __ARKODE_SOLVER_H__ - -#endif - +#endif // BOUT_HAS_ARKODE +#endif // __ARKODE_SOLVER_H__ diff --git a/src/solver/impls/cvode/cvode.hxx b/src/solver/impls/cvode/cvode.hxx index 081fbcc88c..79bb0307d7 100644 --- a/src/solver/impls/cvode/cvode.hxx +++ b/src/solver/impls/cvode/cvode.hxx @@ -1,13 +1,13 @@ /************************************************************************** * Interface to SUNDIALS CVODE - * + * * NOTE: Only one solver can currently be compiled in * ************************************************************************** * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -25,13 +25,13 @@ * **************************************************************************/ +#ifndef __SUNDIAL_SOLVER_H__ +#define __SUNDIAL_SOLVER_H__ + #ifdef BOUT_HAS_CVODE class CvodeSolver; -#ifndef __SUNDIAL_SOLVER_H__ -#define __SUNDIAL_SOLVER_H__ - #include "bout_types.hxx" #include "field2d.hxx" #include "field3d.hxx" @@ -59,44 +59,46 @@ RegisterSolver registersolvercvode("cvode"); } class CvodeSolver : public Solver { - public: - CvodeSolver(Options *opts = nullptr); - ~CvodeSolver(); - - void setJacobian(Jacobian j) override { jacfunc = j; } - - BoutReal getCurrentTimestep() override { return hcur; } - - int init(int nout, BoutReal tstep) override; - - int run() override; - BoutReal run(BoutReal tout); - - void resetInternalFields() override; - - // These functions used internally (but need to be public) - void rhs(BoutReal t, BoutReal *udata, BoutReal *dudata); - void pre(BoutReal t, BoutReal gamma, BoutReal delta, BoutReal *udata, BoutReal *rvec, BoutReal *zvec); - void jac(BoutReal t, BoutReal *ydata, BoutReal *vdata, BoutReal *Jvdata); - private: - int NOUT; // Number of outputs. Specified in init, needed in run - BoutReal TIMESTEP; // Time between outputs - BoutReal hcur; // Current internal timestep - - Jacobian jacfunc; // Jacobian - vector function - bool diagnose; // Output additional diagnostics - - N_Vector uvec; // Values - void *cvode_mem; - - BoutReal pre_Wtime; // Time in preconditioner - BoutReal pre_ncalls; // Number of calls to preconditioner - - void set_abstol_values(BoutReal *abstolvec_data, std::vector &f2dtols, - std::vector &f3dtols); - void loop_abstol_values_op(Ind2D i2d, BoutReal *abstolvec_data, int &p, - std::vector &f2dtols, - std::vector &f3dtols, bool bndry); +public: + CvodeSolver(Options* opts = nullptr); + ~CvodeSolver(); + + void setJacobian(Jacobian j) override { jacfunc = j; } + + BoutReal getCurrentTimestep() override { return hcur; } + + int init(int nout, BoutReal tstep) override; + + int run() override; + BoutReal run(BoutReal tout); + + void resetInternalFields() override; + + // These functions used internally (but need to be public) + void rhs(BoutReal t, BoutReal* udata, BoutReal* dudata); + void pre(BoutReal t, BoutReal gamma, BoutReal delta, BoutReal* udata, BoutReal* rvec, + BoutReal* zvec); + void jac(BoutReal t, BoutReal* ydata, BoutReal* vdata, BoutReal* Jvdata); + +private: + int NOUT; // Number of outputs. Specified in init, needed in run + BoutReal TIMESTEP; // Time between outputs + BoutReal hcur; // Current internal timestep + + Jacobian jacfunc; // Jacobian - vector function + bool diagnose; // Output additional diagnostics + + N_Vector uvec; // Values + void* cvode_mem; + + BoutReal pre_Wtime; // Time in preconditioner + BoutReal pre_ncalls; // Number of calls to preconditioner + + void set_abstol_values(BoutReal* abstolvec_data, std::vector& f2dtols, + std::vector& f3dtols); + void loop_abstol_values_op(Ind2D i2d, BoutReal* abstolvec_data, int& p, + std::vector& f2dtols, + std::vector& f3dtols, bool bndry); #if SUNDIALS_VERSION_MAJOR >= 3 /// SPGMR solver structure SUNLinearSolver sun_solver{nullptr}; @@ -105,10 +107,7 @@ class CvodeSolver : public Solver { /// Solver for functional iterations for Adams-Moulton SUNNonlinearSolver nonlinear_solver{nullptr}; #endif - }; -#endif // __SUNDIAL_SOLVER_H__ - -#endif - +#endif // BOUT_HAS_CVODE +#endif // __SUNDIAL_SOLVER_H__ diff --git a/src/solver/impls/ida/ida.hxx b/src/solver/impls/ida/ida.hxx index e1c4ecad8f..b14caba3e8 100644 --- a/src/solver/impls/ida/ida.hxx +++ b/src/solver/impls/ida/ida.hxx @@ -1,6 +1,6 @@ /************************************************************************** * Interface to SUNDIALS IDA - * + * * IdaSolver for DAE systems (so can handle constraints) * * NOTE: Only one solver can currently be compiled in @@ -9,7 +9,7 @@ * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -27,13 +27,13 @@ * **************************************************************************/ +#ifndef __IDA_SOLVER_H__ +#define __IDA_SOLVER_H__ + #ifdef BOUT_HAS_IDA class IdaSolver; -#ifndef __IDA_SOLVER_H__ -#define __IDA_SOLVER_H__ - #include #include @@ -57,26 +57,28 @@ RegisterSolver registersolverida("ida"); } class IdaSolver : public Solver { - public: - IdaSolver(Options *opts = nullptr); +public: + IdaSolver(Options* opts = nullptr); ~IdaSolver(); - + int init(int nout, BoutReal tstep) override; - + int run() override; BoutReal run(BoutReal tout); // These functions used internally (but need to be public) - void res(BoutReal t, BoutReal *udata, BoutReal *dudata, BoutReal *rdata); - void pre(BoutReal t, BoutReal cj, BoutReal delta, BoutReal *udata, BoutReal *rvec, BoutReal *zvec); - private: - int NOUT; // Number of outputs. Specified in init, needed in run + void res(BoutReal t, BoutReal* udata, BoutReal* dudata, BoutReal* rdata); + void pre(BoutReal t, BoutReal cj, BoutReal delta, BoutReal* udata, BoutReal* rvec, + BoutReal* zvec); + +private: + int NOUT; // Number of outputs. Specified in init, needed in run BoutReal TIMESTEP; // Time between outputs - + N_Vector uvec, duvec, id; // Values, time-derivatives, and equation type - void *idamem; - - BoutReal pre_Wtime; // Time in preconditioner + void* idamem; + + BoutReal pre_Wtime; // Time in preconditioner BoutReal pre_ncalls; // Number of calls to preconditioner #if SUNDIALS_VERSION_MAJOR >= 3 @@ -85,6 +87,5 @@ class IdaSolver : public Solver { #endif }; -#endif // __IDA_SOLVER_H__ - -#endif +#endif // BOUT_HAS_IDA +#endif // __IDA_SOLVER_H__ From 1da387da2ece3748826e88b0251e56419dec2eee Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 20 Mar 2019 17:43:39 +0000 Subject: [PATCH 1069/1783] Fix weird typo in solver header --- include/bout/solver.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 5d0108f588..b7990b1c1d 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -349,7 +349,7 @@ protected: std::vector> v2d; std::vector> v3d; - bool has_constraints; ///< Can this solver.hxxandle constraints? Set to true if so. + bool has_constraints; ///< Can this solver handle constraints? Set to true if so. bool initialised; ///< Has init been called yet? BoutReal simtime; ///< Current simulation time From d4535facfc0e067ce58530b1587d41da18937261 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 20 Mar 2019 17:54:09 +0000 Subject: [PATCH 1070/1783] Give initial values to some variables in sundials solvers headers Also change type of pre_ncalls to int --- src/solver/impls/arkode/arkode.cxx | 9 +++------ src/solver/impls/arkode/arkode.hxx | 16 ++++++++-------- src/solver/impls/cvode/cvode.cxx | 7 ++----- src/solver/impls/cvode/cvode.hxx | 16 ++++++++-------- src/solver/impls/ida/ida.cxx | 4 ++-- src/solver/impls/ida/ida.hxx | 14 ++++++++------ 6 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index 88ab0e9365..bfac9597ed 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -155,9 +155,7 @@ constexpr auto& ARKStepSetUserData = ARKodeSetUserData; #endif ArkodeSolver::ArkodeSolver(Options *opts) : Solver(opts) { - has_constraints = false; ///< This solver doesn't have constraints - - jacfunc = nullptr; + has_constraints = false; // This solver doesn't have constraints } ArkodeSolver::~ArkodeSolver() { @@ -585,7 +583,7 @@ BoutReal ArkodeSolver::run(BoutReal tout) { MPI_Barrier(BoutComm::get()); pre_Wtime = 0.0; - pre_ncalls = 0.0; + pre_ncalls = 0; int flag; if(!monitor_timestep) { @@ -698,8 +696,7 @@ void ArkodeSolver::pre(BoutReal t, BoutReal gamma, BoutReal delta, BoutReal *uda // Load state from udata (as with res function) load_vars(udata); - // Load vector t:q - // o be inverted into F_vars + // Load vector to be inverted into F_vars load_derivs(rvec); run_precon(t, gamma, delta); diff --git a/src/solver/impls/arkode/arkode.hxx b/src/solver/impls/arkode/arkode.hxx index 89e177b053..0743db84f3 100644 --- a/src/solver/impls/arkode/arkode.hxx +++ b/src/solver/impls/arkode/arkode.hxx @@ -86,14 +86,14 @@ private: BoutReal TIMESTEP; // Time between outputs BoutReal hcur; // Current internal timestep - Jacobian jacfunc; // Jacobian - vector function - bool diagnose; // Output additional diagnostics + Jacobian jacfunc{nullptr}; // Jacobian - vector function + bool diagnose{false}; // Output additional diagnostics - N_Vector uvec; // Values - void* arkode_mem; + N_Vector uvec{nullptr}; // Values + void* arkode_mem{nullptr}; // ARKODE internal memory block - BoutReal pre_Wtime; // Time in preconditioner - BoutReal pre_ncalls; // Number of calls to preconditioner + BoutReal pre_Wtime{0.0}; // Time in preconditioner + int pre_ncalls{0}; // Number of calls to preconditioner void set_abstol_values(BoutReal* abstolvec_data, std::vector& f2dtols, std::vector& f3dtols); @@ -111,5 +111,5 @@ private: #endif }; -#endif // BOUT_HAS_ARKODE -#endif // __ARKODE_SOLVER_H__ +#endif // BOUT_HAS_ARKODE +#endif // __ARKODE_SOLVER_H__ diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index 2b3cf78a75..1fa8f2fce3 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -101,10 +101,7 @@ constexpr auto& SUNLinSol_SPGMR = SUNSPGMR; #endif CvodeSolver::CvodeSolver(Options *opts) : Solver(opts) { - has_constraints = false; ///< This solver doesn't have constraints - - jacfunc = nullptr; - + has_constraints = false; // This solver doesn't have constraints canReset = true; } @@ -470,7 +467,7 @@ BoutReal CvodeSolver::run(BoutReal tout) { MPI_Barrier(BoutComm::get()); pre_Wtime = 0.0; - pre_ncalls = 0.0; + pre_ncalls = 0; int flag; if (!monitor_timestep) { diff --git a/src/solver/impls/cvode/cvode.hxx b/src/solver/impls/cvode/cvode.hxx index 79bb0307d7..d29daa155f 100644 --- a/src/solver/impls/cvode/cvode.hxx +++ b/src/solver/impls/cvode/cvode.hxx @@ -85,14 +85,14 @@ private: BoutReal TIMESTEP; // Time between outputs BoutReal hcur; // Current internal timestep - Jacobian jacfunc; // Jacobian - vector function - bool diagnose; // Output additional diagnostics + Jacobian jacfunc{nullptr}; // Jacobian - vector function + bool diagnose{false}; // Output additional diagnostics - N_Vector uvec; // Values - void* cvode_mem; + N_Vector uvec{nullptr}; // Values + void* cvode_mem{nullptr}; // CVODE internal memory block - BoutReal pre_Wtime; // Time in preconditioner - BoutReal pre_ncalls; // Number of calls to preconditioner + BoutReal pre_Wtime{0.0}; // Time in preconditioner + int pre_ncalls{0}; // Number of calls to preconditioner void set_abstol_values(BoutReal* abstolvec_data, std::vector& f2dtols, std::vector& f3dtols); @@ -109,5 +109,5 @@ private: #endif }; -#endif // BOUT_HAS_CVODE -#endif // __SUNDIAL_SOLVER_H__ +#endif // BOUT_HAS_CVODE +#endif // __SUNDIAL_SOLVER_H__ diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index fa50671dbb..014853ad75 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -82,7 +82,7 @@ constexpr auto& ida_pre_shim = ida_pre; #endif IdaSolver::IdaSolver(Options *opts) : Solver(opts) { - has_constraints = true; ///< This solver has constraints + has_constraints = true; // This solver has constraints } IdaSolver::~IdaSolver() { @@ -268,7 +268,7 @@ BoutReal IdaSolver::run(BoutReal tout) { throw BoutException("ERROR: Running IDA solver without initialisation\n"); pre_Wtime = 0.0; - pre_ncalls = 0.0; + pre_ncalls = 0; int flag = IDASolve(idamem, tout, &simtime, uvec, duvec, IDA_NORMAL); diff --git a/src/solver/impls/ida/ida.hxx b/src/solver/impls/ida/ida.hxx index b14caba3e8..ff9f70eeff 100644 --- a/src/solver/impls/ida/ida.hxx +++ b/src/solver/impls/ida/ida.hxx @@ -75,11 +75,13 @@ private: int NOUT; // Number of outputs. Specified in init, needed in run BoutReal TIMESTEP; // Time between outputs - N_Vector uvec, duvec, id; // Values, time-derivatives, and equation type - void* idamem; + N_Vector uvec{nullptr}; // Values + N_Vector duvec{nullptr}; // Time-derivatives + N_Vector id{nullptr}; // Equation type + void* idamem{nullptr}; // IDA internal memory block - BoutReal pre_Wtime; // Time in preconditioner - BoutReal pre_ncalls; // Number of calls to preconditioner + BoutReal pre_Wtime{0.0}; // Time in preconditioner + int pre_ncalls{0}; // Number of calls to preconditioner #if SUNDIALS_VERSION_MAJOR >= 3 /// SPGMR solver structure @@ -87,5 +89,5 @@ private: #endif }; -#endif // BOUT_HAS_IDA -#endif // __IDA_SOLVER_H__ +#endif // BOUT_HAS_IDA +#endif // __IDA_SOLVER_H__ From 8c04fbc81c123e13620cf10b78884f8097b9f495 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 27 Feb 2019 11:51:50 +0000 Subject: [PATCH 1071/1783] Interpolate g_** components instead of calculating from g** 3x3 matrix inversion can exaggerate interpolation or extrapolation errors, so interpolate/extrapolate the contravariant metric components g_** instead of calculating from interpolated/extrapolated covariant components g**. --- src/mesh/coordinates.cxx | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 062ba3fa8f..a813e6ab69 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -467,17 +467,22 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor g13 = interpolateAndExtrapolate(coords_in->g13, location); g23 = interpolateAndExtrapolate(coords_in->g23, location); + // 3x3 matrix inversion can exaggerate small interpolation errors, so it is + // more robust to interpolate and extrapolate derived quantities directly, + // rather than deriving from interpolated/extrapolated covariant metric + // components + g_11 = interpolateAndExtrapolate(coords_in->g_11, location); + g_22 = interpolateAndExtrapolate(coords_in->g_22, location); + g_33 = interpolateAndExtrapolate(coords_in->g_33, location); + g_12 = interpolateAndExtrapolate(coords_in->g_12, location); + g_13 = interpolateAndExtrapolate(coords_in->g_13, location); + g_23 = interpolateAndExtrapolate(coords_in->g_23, location); + ShiftTorsion = interpolateAndExtrapolate(coords_in->ShiftTorsion, location); if (mesh->IncIntShear) { IntShiftTorsion = interpolateAndExtrapolate(coords_in->IntShiftTorsion, location); } - - /// Always calculate contravariant metric components so that they are - /// consistent with the interpolated covariant components - if (calcCovariant()) { - throw BoutException("Error in calcCovariant call while constructing staggered Coordinates"); - } } // Check input metrics @@ -491,14 +496,6 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor throw BoutException("\tERROR: Staggered off-diagonal metrics are not finite!\n"); } - // More robust to extrapolate derived quantities directly, rather than - // deriving from extrapolated covariant metric components - g_11 = interpolateAndExtrapolate(g_11, location); - g_22 = interpolateAndExtrapolate(g_22, location); - g_33 = interpolateAndExtrapolate(g_33, location); - g_12 = interpolateAndExtrapolate(g_12, location); - g_13 = interpolateAndExtrapolate(g_13, location); - g_23 = interpolateAndExtrapolate(g_23, location); /// Calculate Jacobian and Bxy if (jacobian()) throw BoutException("Error in jacobian call while constructing staggered Coordinates"); From 6bb2211a8f68beab49fe9a773e870108df5438dc Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 27 Feb 2019 13:42:17 +0000 Subject: [PATCH 1072/1783] clang-format coordinates.cxx --- src/mesh/coordinates.cxx | 248 +++++++++++++++++++++------------------ 1 file changed, 135 insertions(+), 113 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index a813e6ab69..84182f56a0 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -24,7 +24,7 @@ namespace { /// Boundary guard cells are set by extrapolating from the grid, like /// 'free_o3' boundary conditions /// Corner guard cells are set to BoutNaN -Field2D interpolateAndExtrapolate(const Field2D &f, CELL_LOC location) { +Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location) { Mesh* localmesh = f.getMesh(); Field2D result = interp_to(f, location, RGN_NOBNDRY); // Ensure result's data is unique. Otherwise result might be a duplicate of @@ -46,61 +46,65 @@ Field2D interpolateAndExtrapolate(const Field2D &f, CELL_LOC location) { // (xend+1)/(yend+1) instead of extrapolating. for (auto bndry : localmesh->getBoundaries()) { int extrap_start = 0; - if ( (location == CELL_XLOW) && (bndry->bx>0) ) { + if ((location == CELL_XLOW) && (bndry->bx > 0)) { extrap_start = 1; - } - else if ( (location == CELL_YLOW) && (bndry->by>0) ) { + } else if ((location == CELL_YLOW) && (bndry->by > 0)) { extrap_start = 1; } - for(bndry->first(); !bndry->isDone(); bndry->next1d()) { + for (bndry->first(); !bndry->isDone(); bndry->next1d()) { // interpolate extra boundary point that is missed by interp_to, if // necessary - if (extrap_start>0) { + if (extrap_start > 0) { // note that either bx or by is >0 here result(bndry->x, bndry->y) = - ( 9.*(f(bndry->x-bndry->bx, bndry->y-bndry->by) - + f(bndry->x, bndry->y)) - - f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by) - - f(bndry->x+bndry->bx, bndry->y+bndry->by) - )/16.; + (9. * (f(bndry->x - bndry->bx, bndry->y - bndry->by) + f(bndry->x, bndry->y)) + - f(bndry->x - 2 * bndry->bx, bndry->y - 2 * bndry->by) + - f(bndry->x + bndry->bx, bndry->y + bndry->by)) + / 16.; } // set boundary guard cells - if ((bndry->bx != 0 && localmesh->GlobalNx-2*bndry->width >= 3) || (bndry->by != 0 && localmesh->GlobalNy-2*bndry->width >= 3)) { + if ((bndry->bx != 0 && localmesh->GlobalNx - 2 * bndry->width >= 3) + || (bndry->by != 0 && localmesh->GlobalNy - 2 * bndry->width >= 3)) { if (bndry->bx != 0 && localmesh->LocalNx == 1 && bndry->width == 1) { - throw BoutException("Not enough points in the x-direction on this " + throw BoutException( + "Not enough points in the x-direction on this " "processor for extrapolation needed to use staggered grids. " "Increase number of x-guard cells MXG or decrease number of " "processors in the x-direction NXPE."); } if (bndry->by != 0 && localmesh->LocalNy == 1 && bndry->width == 1) { - throw BoutException("Not enough points in the y-direction on this " + throw BoutException( + "Not enough points in the y-direction on this " "processor for extrapolation needed to use staggered grids. " "Increase number of y-guard cells MYG or decrease number of " "processors in the y-direction NYPE."); } // extrapolate into boundary guard cells if there are enough grid points - for(int i=extrap_start;iwidth;i++) { - int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->by; - result(xi, yi) = 3.0*result(xi - bndry->bx, yi - bndry->by) - 3.0*result(xi - 2*bndry->bx, yi - 2*bndry->by) + result(xi - 3*bndry->bx, yi - 3*bndry->by); + for (int i = extrap_start; i < bndry->width; i++) { + int xi = bndry->x + i * bndry->bx; + int yi = bndry->y + i * bndry->by; + result(xi, yi) = 3.0 * result(xi - bndry->bx, yi - bndry->by) + - 3.0 * result(xi - 2 * bndry->bx, yi - 2 * bndry->by) + + result(xi - 3 * bndry->bx, yi - 3 * bndry->by); } } else { // not enough grid points to extrapolate, set equal to last grid point - for(int i=extrap_start;iwidth;i++) { - result(bndry->x + i*bndry->bx, bndry->y + i*bndry->by) = result(bndry->x - bndry->bx, bndry->y - bndry->by); + for (int i = extrap_start; i < bndry->width; i++) { + result(bndry->x + i * bndry->bx, bndry->y + i * bndry->by) = + result(bndry->x - bndry->bx, bndry->y - bndry->by); } } } } // Set corner guard cells - for (int i=0; ixstart; i++) { - for (int j=0; jystart; j++) { + for (int i = 0; i < localmesh->xstart; i++) { + for (int j = 0; j < localmesh->ystart; j++) { result(i, j) = BoutNaN; - result(i, localmesh->LocalNy-1-j) = BoutNaN; - result(localmesh->LocalNx-1-i, j) = BoutNaN; - result(localmesh->LocalNx-1-i, localmesh->LocalNy-1-j) = BoutNaN; + result(i, localmesh->LocalNy - 1 - j) = BoutNaN; + result(localmesh->LocalNx - 1 - i, j) = BoutNaN; + result(localmesh->LocalNx - 1 - i, localmesh->LocalNy - 1 - j) = BoutNaN; } } @@ -146,7 +150,7 @@ Coordinates::Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2 } } -Coordinates::Coordinates(Mesh *mesh) +Coordinates::Coordinates(Mesh* mesh) : dx(1, mesh), dy(1, mesh), dz(1), d1_dx(mesh), d1_dy(mesh), J(1, mesh), Bxy(1, mesh), // Identity metric tensor g11(1, mesh), g22(1, mesh), g33(1, mesh), g12(0, mesh), g13(0, mesh), g23(0, mesh), @@ -181,7 +185,7 @@ Coordinates::Coordinates(Mesh *mesh) if (mesh->get(dz, "dz")) { // Couldn't read dz from input BoutReal ZMIN, ZMAX; - Options *options = Options::getRoot(); + Options* options = Options::getRoot(); if (options->isSet("zperiod")) { int zperiod; OPTION(options, zperiod, 1); @@ -212,25 +216,28 @@ Coordinates::Coordinates(Mesh *mesh) g23 = interpolateAndExtrapolate(g23, location); // Check input metrics - if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) || (!finite(g33, RGN_NOBNDRY))) { + if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) + || (!finite(g33, RGN_NOBNDRY))) { throw BoutException("\tERROR: Diagonal metrics are not finite!\n"); } - if ((min(g11, RGN_NOBNDRY) <= 0.0) || (min(g22, RGN_NOBNDRY) <= 0.0) || (min(g33, RGN_NOBNDRY) <= 0.0)) { + if ((min(g11, RGN_NOBNDRY) <= 0.0) || (min(g22, RGN_NOBNDRY) <= 0.0) + || (min(g33, RGN_NOBNDRY) <= 0.0)) { throw BoutException("\tERROR: Diagonal metrics are negative!\n"); } - if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) || (!finite(g23, RGN_NOBNDRY))) { + if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) + || (!finite(g23, RGN_NOBNDRY))) { throw BoutException("\tERROR: Off-diagonal metrics are not finite!\n"); } /// Find covariant metric components // Check if any of the components are present - if (mesh->sourceHasVar("g_11") or mesh->sourceHasVar("g_22") or - mesh->sourceHasVar("g_33") or mesh->sourceHasVar("g_12") or - mesh->sourceHasVar("g_13") or mesh->sourceHasVar("g_23")) { + if (mesh->sourceHasVar("g_11") or mesh->sourceHasVar("g_22") + or mesh->sourceHasVar("g_33") or mesh->sourceHasVar("g_12") + or mesh->sourceHasVar("g_13") or mesh->sourceHasVar("g_23")) { // Check that all components are present - if (mesh->sourceHasVar("g_11") and mesh->sourceHasVar("g_22") and - mesh->sourceHasVar("g_33") and mesh->sourceHasVar("g_12") and - mesh->sourceHasVar("g_13") and mesh->sourceHasVar("g_23")) { + if (mesh->sourceHasVar("g_11") and mesh->sourceHasVar("g_22") + and mesh->sourceHasVar("g_33") and mesh->sourceHasVar("g_12") + and mesh->sourceHasVar("g_13") and mesh->sourceHasVar("g_23")) { mesh->get(g_11, "g_11"); mesh->get(g_22, "g_22"); mesh->get(g_33, "g_33"); @@ -271,7 +278,8 @@ Coordinates::Coordinates(Mesh *mesh) // Attempt to read J from the grid file Field2D Jcalc = J; if (mesh->get(J, "J")) { - output_warn.write("\tWARNING: Jacobian 'J' not found. Calculating from metric tensor\n"); + output_warn.write( + "\tWARNING: Jacobian 'J' not found. Calculating from metric tensor\n"); J = Jcalc; } else { // Compare calculated and loaded values @@ -306,7 +314,8 @@ Coordinates::Coordinates(Mesh *mesh) } if (mesh->get(ShiftTorsion, "ShiftTorsion")) { - output_warn.write("\tWARNING: No Torsion specified for zShift. Derivatives may not be correct\n"); + output_warn.write( + "\tWARNING: No Torsion specified for zShift. Derivatives may not be correct\n"); ShiftTorsion = 0.0; } ShiftTorsion = interpolateAndExtrapolate(ShiftTorsion, location); @@ -325,7 +334,7 @@ Coordinates::Coordinates(Mesh *mesh) } } -Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coords_in, +Coordinates::Coordinates(Mesh* mesh, const CELL_LOC loc, const Coordinates* coords_in, bool force_interpolate_from_centre) : dx(1, mesh), dy(1, mesh), dz(1), d1_dx(mesh), d1_dy(mesh), J(1, mesh), Bxy(1, mesh), // Identity metric tensor @@ -486,13 +495,15 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor } // Check input metrics - if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) || (!finite(g33, RGN_NOBNDRY))) { + if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) + || (!finite(g33, RGN_NOBNDRY))) { throw BoutException("\tERROR: Staggered diagonal metrics are not finite!\n"); } if ((min(g11) <= 0.0) || (min(g22) <= 0.0) || (min(g33) <= 0.0)) { throw BoutException("\tERROR: Staggered diagonal metrics are negative!\n"); } - if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) || (!finite(g23, RGN_NOBNDRY))) { + if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) + || (!finite(g23, RGN_NOBNDRY))) { throw BoutException("\tERROR: Staggered off-diagonal metrics are not finite!\n"); } @@ -511,7 +522,7 @@ Coordinates::Coordinates(Mesh *mesh, const CELL_LOC loc, const Coordinates* coor } } -void Coordinates::outputVars(Datafile &file) { +void Coordinates::outputVars(Datafile& file) { const std::string loc_string = (location == CELL_CENTRE) ? "" : "_"+toString(location); file.addOnce(dx, "dx" + loc_string); @@ -550,23 +561,27 @@ int Coordinates::geometry(bool recalculate_staggered) { throw BoutException("dz magnitude less than 1e-8"); // Check input metrics - if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) || (!finite(g33, RGN_NOBNDRY))) { + if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) + || (!finite(g33, RGN_NOBNDRY))) { throw BoutException("\tERROR: Diagonal metrics are not finite!\n"); } if ((min(g11) <= 0.0) || (min(g22) <= 0.0) || (min(g33) <= 0.0)) { throw BoutException("\tERROR: Diagonal metrics are negative!\n"); } - if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) || (!finite(g23, RGN_NOBNDRY))) { + if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) + || (!finite(g23, RGN_NOBNDRY))) { throw BoutException("\tERROR: Off-diagonal metrics are not finite!\n"); } - if ((!finite(g_11, RGN_NOBNDRY)) || (!finite(g_22, RGN_NOBNDRY)) || (!finite(g_33, RGN_NOBNDRY))) { + if ((!finite(g_11, RGN_NOBNDRY)) || (!finite(g_22, RGN_NOBNDRY)) + || (!finite(g_33, RGN_NOBNDRY))) { throw BoutException("\tERROR: Diagonal g_ij metrics are not finite!\n"); } if ((min(g_11) <= 0.0) || (min(g_22) <= 0.0) || (min(g_33) <= 0.0)) { throw BoutException("\tERROR: Diagonal g_ij metrics are negative!\n"); } - if ((!finite(g_12, RGN_NOBNDRY)) || (!finite(g_13, RGN_NOBNDRY)) || (!finite(g_23, RGN_NOBNDRY))) { + if ((!finite(g_12, RGN_NOBNDRY)) || (!finite(g_13, RGN_NOBNDRY)) + || (!finite(g_23, RGN_NOBNDRY))) { throw BoutException("\tERROR: Off-diagonal g_ij metrics are not finite!\n"); } @@ -574,30 +589,30 @@ int Coordinates::geometry(bool recalculate_staggered) { // Note: This calculation is completely general: metric // tensor can be 2D or 3D. For 2D, all DDZ terms are zero - G1_11 = 0.5 * g11 * DDX(g_11) + g12 * (DDX(g_12) - 0.5 * DDY(g_11)) + - g13 * (DDX(g_13) - 0.5 * DDZ(g_11)); - G1_22 = g11 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g12 * DDY(g_22) + - g13 * (DDY(g_23) - 0.5 * DDZ(g_22)); - G1_33 = g11 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g12 * (DDZ(g_23) - 0.5 * DDY(g_33)) + - 0.5 * g13 * DDZ(g_33); - G1_12 = 0.5 * g11 * DDY(g_11) + 0.5 * g12 * DDX(g_22) + - 0.5 * g13 * (DDY(g_13) + DDX(g_23) - DDZ(g_12)); - G1_13 = 0.5 * g11 * DDZ(g_11) + 0.5 * g12 * (DDZ(g_12) + DDX(g_23) - DDY(g_13)) + - 0.5 * g13 * DDX(g_33); - G1_23 = 0.5 * g11 * (DDZ(g_12) + DDY(g_13) - DDX(g_23)) + - 0.5 * g12 * (DDZ(g_22) + DDY(g_23) - DDY(g_23)) + G1_11 = 0.5 * g11 * DDX(g_11) + g12 * (DDX(g_12) - 0.5 * DDY(g_11)) + + g13 * (DDX(g_13) - 0.5 * DDZ(g_11)); + G1_22 = g11 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g12 * DDY(g_22) + + g13 * (DDY(g_23) - 0.5 * DDZ(g_22)); + G1_33 = g11 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g12 * (DDZ(g_23) - 0.5 * DDY(g_33)) + + 0.5 * g13 * DDZ(g_33); + G1_12 = 0.5 * g11 * DDY(g_11) + 0.5 * g12 * DDX(g_22) + + 0.5 * g13 * (DDY(g_13) + DDX(g_23) - DDZ(g_12)); + G1_13 = 0.5 * g11 * DDZ(g_11) + 0.5 * g12 * (DDZ(g_12) + DDX(g_23) - DDY(g_13)) + + 0.5 * g13 * DDX(g_33); + G1_23 = 0.5 * g11 * (DDZ(g_12) + DDY(g_13) - DDX(g_23)) + + 0.5 * g12 * (DDZ(g_22) + DDY(g_23) - DDY(g_23)) // + 0.5 *g13*(DDZ(g_32) + DDY(g_33) - DDZ(g_23)); // which equals + 0.5 * g13 * DDY(g_33); - G2_11 = 0.5 * g12 * DDX(g_11) + g22 * (DDX(g_12) - 0.5 * DDY(g_11)) + - g23 * (DDX(g_13) - 0.5 * DDZ(g_11)); - G2_22 = g12 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g22 * DDY(g_22) + - g23 * (DDY(g23) - 0.5 * DDZ(g_22)); - G2_33 = g12 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g22 * (DDZ(g_23) - 0.5 * DDY(g_33)) + - 0.5 * g23 * DDZ(g_33); - G2_12 = 0.5 * g12 * DDY(g_11) + 0.5 * g22 * DDX(g_22) + - 0.5 * g23 * (DDY(g_13) + DDX(g_23) - DDZ(g_12)); + G2_11 = 0.5 * g12 * DDX(g_11) + g22 * (DDX(g_12) - 0.5 * DDY(g_11)) + + g23 * (DDX(g_13) - 0.5 * DDZ(g_11)); + G2_22 = g12 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g22 * DDY(g_22) + + g23 * (DDY(g23) - 0.5 * DDZ(g_22)); + G2_33 = g12 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g22 * (DDZ(g_23) - 0.5 * DDY(g_33)) + + 0.5 * g23 * DDZ(g_33); + G2_12 = 0.5 * g12 * DDY(g_11) + 0.5 * g22 * DDX(g_22) + + 0.5 * g23 * (DDY(g_13) + DDX(g_23) - DDZ(g_12)); G2_13 = // 0.5 *g21*(DDZ(g_11) + DDX(g_13) - DDX(g_13)) // which equals @@ -608,15 +623,15 @@ int Coordinates::geometry(bool recalculate_staggered) { // + 0.5 *g23*(DDZ(g_31) + DDX(g_33) - DDZ(g_13)); // which equals + 0.5 * g23 * DDX(g_33); - G2_23 = 0.5 * g12 * (DDZ(g_12) + DDY(g_13) - DDX(g_23)) + 0.5 * g22 * DDZ(g_22) + - 0.5 * g23 * DDY(g_33); - - G3_11 = 0.5 * g13 * DDX(g_11) + g23 * (DDX(g_12) - 0.5 * DDY(g_11)) + - g33 * (DDX(g_13) - 0.5 * DDZ(g_11)); - G3_22 = g13 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g23 * DDY(g_22) + - g33 * (DDY(g_23) - 0.5 * DDZ(g_22)); - G3_33 = g13 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g23 * (DDZ(g_23) - 0.5 * DDY(g_33)) + - 0.5 * g33 * DDZ(g_33); + G2_23 = 0.5 * g12 * (DDZ(g_12) + DDY(g_13) - DDX(g_23)) + 0.5 * g22 * DDZ(g_22) + + 0.5 * g23 * DDY(g_33); + + G3_11 = 0.5 * g13 * DDX(g_11) + g23 * (DDX(g_12) - 0.5 * DDY(g_11)) + + g33 * (DDX(g_13) - 0.5 * DDZ(g_11)); + G3_22 = g13 * (DDY(g_12) - 0.5 * DDX(g_22)) + 0.5 * g23 * DDY(g_22) + + g33 * (DDY(g_23) - 0.5 * DDZ(g_22)); + G3_33 = g13 * (DDZ(g_13) - 0.5 * DDX(g_33)) + g23 * (DDZ(g_23) - 0.5 * DDY(g_33)) + + 0.5 * g33 * DDZ(g_33); G3_12 = // 0.5 *g31*(DDY(g_11) + DDX(g_12) - DDX(g_12)) // which equals to @@ -627,10 +642,10 @@ int Coordinates::geometry(bool recalculate_staggered) { //+ 0.5 *g33*(DDY(g_31) + DDX(g_32) - DDZ(g_12)); // which equals to + 0.5 * g33 * (DDY(g_13) + DDX(g_23) - DDZ(g_12)); - G3_13 = 0.5 * g13 * DDZ(g_11) + 0.5 * g23 * (DDZ(g_12) + DDX(g_23) - DDY(g_13)) + - 0.5 * g33 * DDX(g_33); - G3_23 = 0.5 * g13 * (DDZ(g_12) + DDY(g_13) - DDX(g_23)) + 0.5 * g23 * DDZ(g_22) + - 0.5 * g33 * DDY(g_33); + G3_13 = 0.5 * g13 * DDZ(g_11) + 0.5 * g23 * (DDZ(g_12) + DDX(g_23) - DDY(g_13)) + + 0.5 * g33 * DDX(g_33); + G3_23 = 0.5 * g13 * (DDZ(g_12) + DDY(g_13) - DDX(g_23)) + 0.5 * g23 * DDZ(g_22) + + 0.5 * g33 * DDY(g_33); G1 = (DDX(J * g11) + DDY(J * g12) + DDZ(J * g13)) / J; G2 = (DDX(J * g12) + DDY(J * g22) + DDZ(J * g23)) / J; @@ -835,8 +850,8 @@ int Coordinates::jacobian() { TRACE("Coordinates::jacobian"); // calculate Jacobian using g^-1 = det[g^ij], J = sqrt(g) - Field2D g = g11 * g22 * g33 + 2.0 * g12 * g13 * g23 - g11 * g23 * g23 - - g22 * g13 * g13 - g33 * g12 * g12; + Field2D g = g11 * g22 * g33 + 2.0 * g12 * g13 * g23 - g11 * g23 * g23 - g22 * g13 * g13 + - g33 * g12 * g12; // Check that g is positive if (min(g) < 0.0) { @@ -865,18 +880,20 @@ int Coordinates::jacobian() { * *******************************************************************************/ -const Field2D Coordinates::DDX(const Field2D &f, CELL_LOC loc, const std::string &method, REGION region) { +const Field2D Coordinates::DDX(const Field2D& f, CELL_LOC loc, const std::string& method, + REGION region) { ASSERT1(location == loc || loc == CELL_DEFAULT); return bout::derivatives::index::DDX(f, loc, method, region) / dx; } -const Field2D Coordinates::DDY(const Field2D &f, CELL_LOC loc, const std::string &method, REGION region) { +const Field2D Coordinates::DDY(const Field2D& f, CELL_LOC loc, const std::string& method, + REGION region) { ASSERT1(location == loc || loc == CELL_DEFAULT); return bout::derivatives::index::DDY(f, loc, method, region) / dy; } -const Field2D Coordinates::DDZ(MAYBE_UNUSED(const Field2D &f), CELL_LOC loc, - const std::string &UNUSED(method), REGION UNUSED(region)) { +const Field2D Coordinates::DDZ(MAYBE_UNUSED(const Field2D& f), CELL_LOC loc, + const std::string& UNUSED(method), REGION UNUSED(region)) { ASSERT1(location == loc || loc == CELL_DEFAULT); ASSERT1(f.getMesh() == localmesh); if (loc == CELL_DEFAULT) { @@ -890,16 +907,17 @@ const Field2D Coordinates::DDZ(MAYBE_UNUSED(const Field2D &f), CELL_LOC loc, ///////////////////////////////////////////////////////// // Parallel gradient -const Field2D Coordinates::Grad_par(const Field2D &var, MAYBE_UNUSED(CELL_LOC outloc), - const std::string &UNUSED(method)) { +const Field2D Coordinates::Grad_par(const Field2D& var, MAYBE_UNUSED(CELL_LOC outloc), + const std::string& UNUSED(method)) { TRACE("Coordinates::Grad_par( Field2D )"); - ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == var.getLocation())); + ASSERT1(location == outloc + || (outloc == CELL_DEFAULT && location == var.getLocation())); return DDY(var) / sqrt(g_22); } -const Field3D Coordinates::Grad_par(const Field3D &var, CELL_LOC outloc, - const std::string &method) { +const Field3D Coordinates::Grad_par(const Field3D& var, CELL_LOC outloc, + const std::string& method) { TRACE("Coordinates::Grad_par( Field3D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); @@ -910,15 +928,15 @@ const Field3D Coordinates::Grad_par(const Field3D &var, CELL_LOC outloc, // Vpar_Grad_par // vparallel times the parallel derivative along unperturbed B-field -const Field2D Coordinates::Vpar_Grad_par(const Field2D &v, const Field2D &f, +const Field2D Coordinates::Vpar_Grad_par(const Field2D& v, const Field2D& f, MAYBE_UNUSED(CELL_LOC outloc), - const std::string &UNUSED(method)) { + const std::string& UNUSED(method)) { ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == f.getLocation())); return VDDY(v, f) / sqrt(g_22); } -const Field3D Coordinates::Vpar_Grad_par(const Field3D &v, const Field3D &f, CELL_LOC outloc, - const std::string &method) { +const Field3D Coordinates::Vpar_Grad_par(const Field3D& v, const Field3D& f, + CELL_LOC outloc, const std::string& method) { ASSERT1(location == outloc || outloc == CELL_DEFAULT); return VDDY(v, f, outloc, method) / sqrt(g_22); } @@ -926,8 +944,8 @@ const Field3D Coordinates::Vpar_Grad_par(const Field3D &v, const Field3D &f, CEL ///////////////////////////////////////////////////////// // Parallel divergence -const Field2D Coordinates::Div_par(const Field2D &f, CELL_LOC outloc, - const std::string &method) { +const Field2D Coordinates::Div_par(const Field2D& f, CELL_LOC outloc, + const std::string& method) { TRACE("Coordinates::Div_par( Field2D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); @@ -938,11 +956,11 @@ const Field2D Coordinates::Div_par(const Field2D &f, CELL_LOC outloc, return Bxy * Grad_par(f / Bxy_floc, outloc, method); } -const Field3D Coordinates::Div_par(const Field3D &f, CELL_LOC outloc, - const std::string &method) { +const Field3D Coordinates::Div_par(const Field3D& f, CELL_LOC outloc, + const std::string& method) { TRACE("Coordinates::Div_par( Field3D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); - + // Need Bxy at location of f, which might be different from location of this // Coordinates object Field2D Bxy_floc = f.getCoordinates()->Bxy; @@ -971,17 +989,20 @@ const Field3D Coordinates::Div_par(const Field3D &f, CELL_LOC outloc, // second parallel derivative (b dot Grad)(b dot Grad) // Note: For parallel Laplacian use Laplace_par -const Field2D Coordinates::Grad2_par2(const Field2D &f, CELL_LOC outloc, const std::string &method) { +const Field2D Coordinates::Grad2_par2(const Field2D& f, CELL_LOC outloc, + const std::string& method) { TRACE("Coordinates::Grad2_par2( Field2D )"); ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == f.getLocation())); Field2D sg = sqrt(g_22); - Field2D result = DDY(1. / sg, outloc, method) * DDY(f, outloc, method) / sg + D2DY2(f, outloc, method) / g_22; + Field2D result = DDY(1. / sg, outloc, method) * DDY(f, outloc, method) / sg + + D2DY2(f, outloc, method) / g_22; return result; } -const Field3D Coordinates::Grad2_par2(const Field3D &f, CELL_LOC outloc, const std::string &method) { +const Field3D Coordinates::Grad2_par2(const Field3D& f, CELL_LOC outloc, + const std::string& method) { TRACE("Coordinates::Grad2_par2( Field3D )"); if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); @@ -991,7 +1012,6 @@ const Field3D Coordinates::Grad2_par2(const Field3D &f, CELL_LOC outloc, const s Field2D sg = sqrt(g_22); sg = DDY(1. / sg, outloc, method) / sg; - Field3D result = ::DDY(f, outloc, method); Field3D r2 = D2DY2(f, outloc, method) / g_22; @@ -1029,7 +1049,7 @@ const Field3D Coordinates::Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) if (localmesh->GlobalNx == 1 && localmesh->GlobalNz == 1) { // copy mesh, location, etc - return f*0; + return f * 0; } ASSERT2(localmesh->xstart > 0); // Need at least one guard cell @@ -1142,37 +1162,39 @@ const FieldPerp Coordinates::Delp2(const FieldPerp& f, CELL_LOC outloc, bool use return result; } -const Field2D Coordinates::Laplace_par(const Field2D &f, CELL_LOC outloc) { +const Field2D Coordinates::Laplace_par(const Field2D& f, CELL_LOC outloc) { ASSERT1(location == outloc || outloc == CELL_DEFAULT); return D2DY2(f, outloc) / g_22 + DDY(J / g_22, outloc) * DDY(f, outloc) / J; } -const Field3D Coordinates::Laplace_par(const Field3D &f, CELL_LOC outloc) { +const Field3D Coordinates::Laplace_par(const Field3D& f, CELL_LOC outloc) { ASSERT1(location == outloc || outloc == CELL_DEFAULT); return D2DY2(f, outloc) / g_22 + DDY(J / g_22, outloc) * ::DDY(f, outloc) / J; } // Full Laplacian operator on scalar field -const Field2D Coordinates::Laplace(const Field2D &f, CELL_LOC outloc) { +const Field2D Coordinates::Laplace(const Field2D& f, CELL_LOC outloc) { TRACE("Coordinates::Laplace( Field2D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); - Field2D result = - G1 * DDX(f, outloc) + G2 * DDY(f, outloc) + g11 * D2DX2(f, outloc) + g22 * D2DY2(f, outloc) + 2.0 * g12 * D2DXDY(f, outloc); + Field2D result = G1 * DDX(f, outloc) + G2 * DDY(f, outloc) + g11 * D2DX2(f, outloc) + + g22 * D2DY2(f, outloc) + 2.0 * g12 * D2DXDY(f, outloc); ASSERT2(result.getLocation() == outloc); return result; } -const Field3D Coordinates::Laplace(const Field3D &f, CELL_LOC outloc) { +const Field3D Coordinates::Laplace(const Field3D& f, CELL_LOC outloc) { TRACE("Coordinates::Laplace( Field3D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); - Field3D result = G1 * ::DDX(f, outloc) + G2 * ::DDY(f, outloc) + G3 * ::DDZ(f, outloc) + g11 * D2DX2(f, outloc) + - g22 * D2DY2(f, outloc) + g33 * D2DZ2(f, outloc) + - 2.0 * (g12 * D2DXDY(f, outloc) + g13 * D2DXDZ(f, outloc) + g23 * D2DYDZ(f, outloc)); + Field3D result = G1 * ::DDX(f, outloc) + G2 * ::DDY(f, outloc) + G3 * ::DDZ(f, outloc) + + g11 * D2DX2(f, outloc) + g22 * D2DY2(f, outloc) + + g33 * D2DZ2(f, outloc) + + 2.0 * (g12 * D2DXDY(f, outloc) + g13 * D2DXDZ(f, outloc) + + g23 * D2DYDZ(f, outloc)); ASSERT2(result.getLocation() == f.getLocation()); From d0cb2b26b7329044192be30d0979be409830cb16 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 27 Feb 2019 22:34:52 +0000 Subject: [PATCH 1073/1783] Fix extrapolation of staggered Coordinates quantities There is a fix in interpolateAndExtrapolate to interpolate the xend+1 (at CELL_XLOW) or yend+1 (at CELL_YLOW) boundary point. However, this causes a bug when interpolateAndExtrapolate is used just to extrapolate the boundary cells, as it is for J and Bxy. In this case (if the location of the field is the same as the location argument) the extra interpolation must be skipped, leaving just the extrapolation (note the extrapolation does and should still skip the xend+1 or yend+1 point where interpolation would have been done, because the field, e.g. J, given as input has been calculated correctly from metric components that were interpolated to that position). --- src/mesh/coordinates.cxx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 84182f56a0..8f131ba2dc 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -53,8 +53,12 @@ Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location) { } for (bndry->first(); !bndry->isDone(); bndry->next1d()) { // interpolate extra boundary point that is missed by interp_to, if - // necessary - if (extrap_start > 0) { + // necessary. + // Only interpolate this point if we are actually changing location. E.g. + // when we use this function to extrapolate J and Bxy on staggered grids, + // this point should already be set correctly because the metric + // components have been interpolated to here. + if (extrap_start > 0 and f.getLocation() != location) { // note that either bx or by is >0 here result(bndry->x, bndry->y) = (9. * (f(bndry->x - bndry->bx, bndry->y - bndry->by) + f(bndry->x, bndry->y)) From 347ffb7155a3a59928cd7ddd45b50f788bb207e3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 00:07:54 +0000 Subject: [PATCH 1074/1783] GridFile reads y-boundary guard cells if they are present --- include/bout/griddata.hxx | 2 ++ include/bout/mesh.hxx | 2 ++ src/mesh/data/gridfromfile.cxx | 59 +++++++++++++++++++++++++++----- src/mesh/impls/bout/boutmesh.cxx | 8 +++++ 4 files changed, 62 insertions(+), 9 deletions(-) diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index 5954b56cd6..3731bf9844 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -94,6 +94,8 @@ public: private: std::unique_ptr file; std::string filename; + int grid_yguards{0}; + int ny_inner{0}; bool readgrid_3dvar_fft(Mesh *m, const std::string &name, int yread, int ydest, int ysize, int xge, int xlt, Field3D &var); diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 3c2d3d5859..dfe00b7656 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -446,6 +446,8 @@ class Mesh { /// Include integrated shear (if shifting X) bool IncIntShear{false}; + int numberOfXPoints{0}; + /// Coordinate system Coordinates *getCoordinates(const CELL_LOC location = CELL_CENTRE) { return getCoordinatesSmart(location).get(); diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index b45e27d25f..09b0261f86 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -34,6 +34,19 @@ GridFile::GridFile(std::unique_ptr format, std::string gridfilename) file->setGlobalOrigin(); // Set default global origin + // Get number of y-boundary guard cells saved in the grid file + if (!file->read(&grid_yguards, "y_boundary_guards", 1, 1)) { + // not found in file, default to zero + grid_yguards = 0; + } + + // Get number ny_inner from the grid file. + // Is already read in BoutMesh, but this way we don't have to the Mesh API to + // get it from there. + if (!file->read(&ny_inner, "ny_inner", 1, 1)) { + // not found in file, default to zero + ny_inner = 0; + } } GridFile::~GridFile() { @@ -206,7 +219,19 @@ bool GridFile::get(Mesh *m, Field2D &var, const std::string &name, BoutReal de // Index offsets into source array int xs = m->OffsetX; + // Need to increase offset by 2*(# boundary guards) for each target position + // we pass int ys = m->OffsetY; + if (m->numberOfXPoints > 1) { + ASSERT1(m->numberOfXPoints == 2); + // Need to check if we are before or after the target in the middle of the + // y-domain, and increase ys for the extra boundary guard cells at that + // target if we are after it. + if (m->OffsetY >= ny_inner) { + // Note: neither ny_inner nor OffsetY include guard cells + ys += 2*grid_yguards; + } + } // Index offsets into destination int xd = -1; @@ -227,26 +252,31 @@ bool GridFile::get(Mesh *m, Field2D &var, const std::string &name, BoutReal de int ny_to_read = -1; ///Check if field dimensions are correct. x-direction - if (field_dimensions[0] == m->GlobalNx) { ///including ghostpoints + if (field_dimensions[0] >= m->GlobalNx) { ///including ghostpoints + ASSERT1( (field_dimensions[0] - (m->GlobalNx - 2*mxg)) % 2 == 0 ); + int grid_xguards = (field_dimensions[0] - (m->GlobalNx - 2*mxg)) / 2; + nx_to_read = m->LocalNx; - xd = 0; - } else if ( field_dimensions[0] == m->GlobalNx - 2*mxg ) {///including ghostpoints + xd = grid_xguards - mxg; + ASSERT1(xd >= 0); + } else if (field_dimensions[0] == m->GlobalNx - 2*mxg) { ///excluding ghostpoints nx_to_read = m->LocalNx - 2*mxg; xd = mxg; } else { - throw BoutException("Could not read '%s' from file: x-dimension = %i do neither match nx = %i" + throw BoutException("Could not read '%s' from file: x-dimension = %i neither matches nx <= %i" "nor nx-2*mxg = %i ", name.c_str(), field_dimensions[0], m->GlobalNx, m->GlobalNx-2*mxg); } ///Check if field dimensions are correct. y-direction - if (field_dimensions[1] == m->GlobalNy) { ///including ghostpoints + if (field_dimensions[1] >= m->GlobalNy) { ///including ghostpoints ny_to_read = m->LocalNy; - yd = 0; - } else if ( field_dimensions[1] == m->GlobalNy - 2*myg ) {///including ghostpoints + yd = grid_yguards - myg; + ASSERT1(yd >= 0); + } else if (field_dimensions[1] == m->GlobalNy - 2*myg) { ///excluding ghostpoints ny_to_read = m->LocalNy - 2*myg; yd = myg; } else { - throw BoutException("Could not read '%s' from file: y-dimension = %i do neither match ny = %i" + throw BoutException("Could not read '%s' from file: y-dimension = %i neither matches ny <= %i" "nor ny-2*myg = %i ", name.c_str(), field_dimensions[1], m->GlobalNy, m->GlobalNy-2*myg); } @@ -258,9 +288,20 @@ bool GridFile::get(Mesh *m, Field2D &var, const std::string &name, BoutReal de } } + ///If field does not include ghost points in x-direction -> + ///Upper and lower X boundaries copied from nearest point + if (field_dimensions[0] == m->GlobalNx - 2*mxg ) { + for(int y=0;yLocalNy;y++) { + for(int x=0;xxstart;x++) + var(x, y) = var(m->xstart, y); + for(int x=m->xend+1;xLocalNx;x++) + var(x, y) = var(m->xend, y); + } + } + ///If field does not include ghost points in y-direction -> ///Upper and lower Y boundaries copied from nearest point - if (field_dimensions[1] == m->GlobalNy - 2*myg ) { + if (grid_yguards == 0) { for(int x=0;xLocalNx;x++) { for(int y=0;yystart;y++) var(x, y) = var(x, m->ystart); diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 4342dbafce..1ffd5d994a 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -237,6 +237,14 @@ int BoutMesh::load() { // For now don't parallelise z NZPE = 1; + if (jyseps1_1 < 0 and jyseps2_2 >= ny - 1) { + numberOfXPoints = 0; + } else if (jyseps2_1 == jyseps1_2) { + numberOfXPoints = 1; + } else { + numberOfXPoints = 2; + } + if (options->isSet("NXPE")) { // Specified NXPE options->get("NXPE", NXPE, 1); // Decomposition in the radial direction if ((NPES % NXPE) != 0) { From 469df278520ae551f96bbc279d636da3a3d3e049 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 19:16:09 +0000 Subject: [PATCH 1075/1783] Merge functions to get Field2D and Field3D from grid files Implement using a shared, private template method of GridFile. Reading Field3Ds from gridfile now has support for y-guards saved in the gridfile, and support for x-guards not being saved in the gridfile --- include/bout/griddata.hxx | 26 +++- src/mesh/data/gridfromfile.cxx | 250 +++++++++++++++------------------ 2 files changed, 130 insertions(+), 146 deletions(-) diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index 3731bf9844..0b82be64af 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -83,8 +83,12 @@ public: bool get(Mesh *m, int &ival, const std::string &name) override; ///< Get an integer bool get(Mesh *m, BoutReal &rval, const std::string &name) override; ///< Get a BoutReal number - bool get(Mesh *m, Field2D &var, const std::string &name, BoutReal def = 0.0) override; - bool get(Mesh *m, Field3D &var, const std::string &name, BoutReal def = 0.0) override; + bool get(Mesh *m, Field2D &var, const std::string &name, BoutReal def = 0.0) override { + return getField(m, var, name, def); + } + bool get(Mesh *m, Field3D &var, const std::string &name, BoutReal def = 0.0) override { + return getField(m, var, name, def); + } bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, GridDataSource::Direction dir = GridDataSource::X) override; @@ -98,10 +102,20 @@ private: int ny_inner{0}; bool readgrid_3dvar_fft(Mesh *m, const std::string &name, int yread, int ydest, int ysize, - int xge, int xlt, Field3D &var); - - bool readgrid_3dvar_real(Mesh *m, const std::string &name, int yread, int ydest, int ysize, - int xge, int xlt, Field3D &var); + int xread, int xdest, int xsize, Field3D &var); + + bool readgrid_3dvar_real(const std::string &name, int yread, int ydest, int ysize, + int xread, int xdest, int xsize, Field3D &var); + + // convenience template method to remove code duplication between Field2D and + // Field3D versions of get + template + bool getField(Mesh* m, T& var, const std::string& name, BoutReal def = 0.0); + // utility method with specializations for Field2D and Field3D to implement + // unshared parts of getField + template + void readField(Mesh* m, const std::string& name, int ys, int yd, int ny_to_read, + int xs, int xd, int nx_to_read, const std::vector& size, T& var); }; /*! diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 09b0261f86..d50a091a4b 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -171,11 +171,16 @@ bool GridFile::get(Mesh *UNUSED(m), BoutReal &rval, const std::string &name) { } /*! - * Reads a 2D field variable from a file + * Reads a 2D or 3D field variable from a file * - * Succeeds if the variable in the file is 0-D or 2-D + * Successfully reads Field2D if the variable in the file is 0-D or 2-D. + * Successfully reads Field3D if the variable in the file is 0-D, 2-D or 3-D. */ -bool GridFile::get(Mesh *m, Field2D &var, const std::string &name, BoutReal def) { +template +bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) { + static_assert(std::is_base_of::value || std::is_base_of::value, + "templated GridFile::get only works for Field2D or Field3D"); + Timer timer("io"); TRACE("GridFile::get(Field2D)"); @@ -207,6 +212,16 @@ bool GridFile::get(Mesh *m, Field2D &var, const std::string &name, BoutReal de // Check size break; } + case 3: { + // Check size if getting Field3D + if (std::is_base_of::value) { + output_warn.write("WARNING: Variable '%s' should be 2D, but has %lu dimensions. Ignored\n", + name.c_str(), static_cast(size.size())); + var = def; + return false; + } + break; + } default: { output_warn.write("WARNING: Variable '%s' should be 2D, but has %lu dimensions. Ignored\n", name.c_str(), static_cast(size.size())); @@ -217,6 +232,13 @@ bool GridFile::get(Mesh *m, Field2D &var, const std::string &name, BoutReal de var.allocate(); // Make sure data allocated + ///Ghost region widths. + int mxg = (m->LocalNx - (m->xend - m->xstart + 1)) / 2; + int myg = (m->LocalNy - (m->yend - m->ystart + 1)) / 2; + ///Check that ghost region widths are in fact integers + ASSERT1((m->LocalNx - (m->xend - m->xstart + 1)) % 2 == 0); + ASSERT1((m->LocalNy - (m->yend - m->ystart + 1)) % 2 == 0); + // Index offsets into source array int xs = m->OffsetX; // Need to increase offset by 2*(# boundary guards) for each target position @@ -237,13 +259,6 @@ bool GridFile::get(Mesh *m, Field2D &var, const std::string &name, BoutReal de int xd = -1; int yd = -1; - ///Ghost region widths. - int mxg = (m->LocalNx - (m->xend - m->xstart + 1)) / 2; - int myg = (m->LocalNy - (m->yend - m->ystart + 1)) / 2; - ///Check that ghost region widths are in fact integers - ASSERT1((m->LocalNx - (m->xend - m->xstart + 1)) % 2 == 0); - ASSERT1((m->LocalNy - (m->yend - m->ystart + 1)) % 2 == 0); - ///Global (x,y) dimensions of field const std::vector field_dimensions = file->getSize(name); @@ -280,137 +295,94 @@ bool GridFile::get(Mesh *m, Field2D &var, const std::string &name, BoutReal de "nor ny-2*myg = %i ", name.c_str(), field_dimensions[1], m->GlobalNy, m->GlobalNy-2*myg); } - ///Now read data from file - for(int x=xs;x < xs+nx_to_read; x++) { - file->setGlobalOrigin(x,ys,0); - if (!file->read(&var(x-xs+xd, yd), name, 1, ny_to_read) ) { - throw BoutException("Could not fetch data for '%s'", name.c_str()); - } - } + // Now read data from file + readField(m, name, ys, yd, ny_to_read, xs, xd, nx_to_read, size, var); ///If field does not include ghost points in x-direction -> ///Upper and lower X boundaries copied from nearest point if (field_dimensions[0] == m->GlobalNx - 2*mxg ) { - for(int y=0;yLocalNy;y++) { - for(int x=0;xxstart;x++) - var(x, y) = var(m->xstart, y); - for(int x=m->xend+1;xLocalNx;x++) - var(x, y) = var(m->xend, y); + for (int y=0; yLocalNy; y++) { + for (int z=0; zxstart; x++) { + var(x, y, z) = var(m->xstart, y, z); + } + for (int x=m->xend+1;xLocalNx;x++) { + var(x, y, z) = var(m->xend, y, z); + } + } } } ///If field does not include ghost points in y-direction -> ///Upper and lower Y boundaries copied from nearest point if (grid_yguards == 0) { - for(int x=0;xLocalNx;x++) { - for(int y=0;yystart;y++) - var(x, y) = var(x, m->ystart); - for(int y=m->yend+1;yLocalNy;y++) - var(x, y) = var(x, m->yend); + for(int x=0; xLocalNx; x++) { + for (int z=0; zystart; y++) { + var(x, y, z) = var(x, m->ystart, z); + } + for(int y=m->yend+1; yLocalNy; y++) { + var(x, y, z) = var(x, m->yend, z); + } + } } } - file->setGlobalOrigin(); return true; } -/*! - * Reads a 3D variable from a file - * - * - */ -bool GridFile::get(Mesh *m, Field3D &var, const std::string &name, BoutReal def) { - Timer timer("io"); - TRACE("GridFile::get(Field3D)"); +template<> +void GridFile::readField<>(Mesh* UNUSED(m), const std::string& name, int ys, int yd, + int ny_to_read, int xs, int xd, int nx_to_read, const std::vector& UNUSED(size), + Field2D& var) { - // Check that the file can be read - - if (!file->is_valid()) { - throw BoutException("Could not read '%s' from file: File cannot be read", name.c_str()); + for(int x = xs; x < xs+nx_to_read; x++) { + file->setGlobalOrigin(x,ys,0); + if (!file->read(&var(x-xs+xd, yd), name, 1, ny_to_read) ) { + throw BoutException("Could not fetch data for '%s'", name.c_str()); + } } + file->setGlobalOrigin(); +} - // Check the size of the variable in the file - - std::vector size = file->getSize(name); - switch(size.size()) { - case 0: { - // Variable not found - output_warn.write("\tWARNING: Could not read '%s' from grid. Setting to %le\n", name.c_str(), def); - var = def; - return false; - } - case 1: { - // 0 or 1 dimension - if (size[0] != 1) { - throw BoutException("Expecting a 3D variable, but '%s' is 1D with %d elements\n", name.c_str(), size[0]); +template<> +void GridFile::readField<>(Mesh* m, const std::string& name, int ys, int yd, + int ny_to_read, int xs, int xd, int nx_to_read, const std::vector& size, + Field3D& var) { + + // Check whether "nz" is defined + if (hasVar("nz")) { + // Check the array is the right size + if (size[2] != m->LocalNz) { + throw BoutException("3D variable '%s' has incorrect size %d (expecting %d)", + name.c_str(), size[2], m->LocalNz); } - BoutReal rval; - if (!file->read(&rval, name)) { - throw BoutException("Couldn't read 0D variable '%s'\n", name.c_str()); - } - var = rval; - return true; - } - case 2: { - // Read as 2D - Field2D var2d(m); - if (!get(m, var2d, name, def)) { - throw BoutException("Couldn't read 2D variable '%s'\n", name.c_str()); + if (!readgrid_3dvar_real(name, + ys,// Start reading at global y-index + yd,// Insert data starting from y=yd + ny_to_read,// Length of data in Y + xs,// Start reading at global x-index + xd,// Insert data starting from x=xd + nx_to_read, // Length of data in X + var) ) { + throw BoutException("\tWARNING: Could not read '%s' from grid. Setting to zero\n", + name.c_str()); } - var = var2d; - return true; - } - case 3: { - // Check whether "nz" is defined - if (hasVar("nz")) { - // Read directly into arrays - - // Check the array is the right size - - if (size[2] != m->LocalNz) { - throw BoutException("3D variable '%s' has incorrect size %d (expecting %d)", name.c_str(), size[2], m->LocalNz); - } - - if (! readgrid_3dvar_real(m, name, - m->OffsetY,// Start reading at global index - m->ystart,// Insert data starting from y=ystart - m->yend-m->ystart+1, // Length of data in Y - 0, m->LocalNx, // All x indices (local indices) - var) ) { - throw BoutException("\tWARNING: Could not read '%s' from grid. Setting to zero\n", name.c_str()); - } - } else { - // No Z size specified in file. Assume FFT format - if (! readgrid_3dvar_fft(m, name, - m->OffsetY,// Start reading at global index - m->ystart,// Insert data starting from y=ystart - m->yend-m->ystart+1, // Length of data in Y - 0, m->LocalNx, // All x indices (local indices) - var) ) { - throw BoutException("\tWARNING: Could not read '%s' from grid. Setting to zero\n", name.c_str()); - } + } else { + // No Z size specified in file. Assume FFT format + if (!readgrid_3dvar_fft(m, name, + ys,// Start reading at global y-index + yd,// Insert data starting from y=yd + ny_to_read,// Length of data in Y + xs,// Start reading at global x-index + xd,// Insert data starting from x=xd + nx_to_read, // Length of data in X + var) ) { + throw BoutException("\tWARNING: Could not read '%s' from grid. Setting to zero\n", + name.c_str()); } - - break; - } - default: { - throw BoutException("Error: Variable '%s' should be 3D, but has %lu dimensions\n", - name.c_str(), static_cast(size.size())); - } - }; - - // Upper and lower Y boundaries copied from nearest point - for(int x=0;xLocalNx;x++) { - for(int y=0;yystart;y++) - for(int z=0;zLocalNz;z++) - var(x, y, z) = var(x, m->ystart, z); - for(int y=m->yend+1;yLocalNy;y++) - for(int z=0;zLocalNz;z++) - var(x, y, z) = var(x, m->yend, z); } - - return true; } bool GridFile::get(Mesh *UNUSED(m), std::vector &var, const std::string &name, @@ -466,9 +438,10 @@ bool GridFile::get(Mesh *UNUSED(m), std::vector &var, const std::strin */ bool GridFile::readgrid_3dvar_fft(Mesh *m, const std::string &name, int yread, int ydest, int ysize, - int xge, int xlt, Field3D &var) { + int xread, int xdest, int xsize, Field3D &var) { /// Check the arguments make sense - if ((yread < 0) || (ydest < 0) || (ysize < 0) || (xge < 0) || (xlt < 0)) { + if ((yread < 0) || (ydest < 0) || (ysize < 0) || (xread < 0) || (xdest < 0) + || (xsize < 0)) { return false; } @@ -514,17 +487,15 @@ bool GridFile::readgrid_3dvar_fft(Mesh *m, const std::string &name, Array fdata(ncz / 2 + 1); Array zdata(size[2]); - for(int jx=xge;jxsetGlobalOrigin(jx + m->OffsetX, yind); + file->setGlobalOrigin(jx, jy); if (!file->read(std::begin(zdata), name, 1, 1, size[2])) { - return true; + return false; } /// Load into dcomplex array @@ -541,7 +512,7 @@ bool GridFile::readgrid_3dvar_fft(Mesh *m, const std::string &name, fdata[i] = 0.0; } } - irfft(std::begin(fdata), ncz, &var(jx, ydest + jy, 0)); + irfft(std::begin(fdata), ncz, &var(jx-xread+xdest, jy-yread+ydest, 0)); } } @@ -554,11 +525,12 @@ bool GridFile::readgrid_3dvar_fft(Mesh *m, const std::string &name, * Reads a 3D variable directly from the file, without * any processing */ -bool GridFile::readgrid_3dvar_real(Mesh *m, const std::string &name, +bool GridFile::readgrid_3dvar_real(const std::string &name, int yread, int ydest, int ysize, - int xge, int xlt, Field3D &var) { + int xread, int xdest, int xsize, Field3D &var) { /// Check the arguments make sense - if ((yread < 0) || (ydest < 0) || (ysize < 0) || (xge < 0) || (xlt < 0)) { + if ((yread < 0) || (ydest < 0) || (ysize < 0) || (xread < 0) || (xdest < 0) + || (xsize < 0)) { return false; } @@ -570,16 +542,14 @@ bool GridFile::readgrid_3dvar_real(Mesh *m, const std::string &name, return false; } - for(int jx=xge;jxsetGlobalOrigin(jx + m->OffsetX, yind); - if (!file->read(&var(jx,ydest+jy,0), name, 1, 1, size[2])) { + file->setGlobalOrigin(jx, jy); + if (!file->read(&var(jx-xread+xdest, jy-yread+ydest, 0), name, 1, 1, size[2])) { return false; } } From 873ae6b17ee2699e8a4d527c538206b229482234 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 20:23:47 +0000 Subject: [PATCH 1076/1783] Methods to test whether a GridDataSource loads x- or y-boundary guard cells --- include/bout/griddata.hxx | 18 ++++++++++++++++++ include/bout/mesh.hxx | 6 ++++++ src/mesh/data/gridfromfile.cxx | 13 +++++++++++++ src/mesh/mesh.cxx | 10 ++++++++++ tests/unit/mesh/test_boutmesh.cxx | 2 ++ 5 files changed, 49 insertions(+) diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index 0b82be64af..8147382ed1 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -64,6 +64,12 @@ public: Direction dir = GridDataSource::X) = 0; virtual bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, Direction dir = GridDataSource::X) = 0; + + /// Are x-boundary guard cells read from the source? + virtual bool hasXBoundaryGuards(Mesh* m) = 0; + + /// Are y-boundary guard cells read from the source? + virtual bool hasYBoundaryGuards() = 0; }; /// Interface to grid data in a file @@ -95,6 +101,12 @@ public: bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, GridDataSource::Direction dir = GridDataSource::X) override; + /// Are x-boundary guard cells read from the source? + bool hasXBoundaryGuards(Mesh* m) override; + + /// Are y-boundary guard cells read from the source? + bool hasYBoundaryGuards() override { return grid_yguards > 0; } + private: std::unique_ptr file; std::string filename; @@ -226,6 +238,12 @@ public: bool get(Mesh *mesh, std::vector &var, const std::string &name, int len, int offset = 0, GridDataSource::Direction dir = GridDataSource::X) override; + /// Are x-boundary guard cells read from the source? + bool hasXBoundaryGuards(Mesh* UNUSED(m)) override { return true; } + + /// Are y-boundary guard cells read from the source? + bool hasYBoundaryGuards() override { return true; } + private: /// The options section to use. Could be nullptr Options *options; diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index dfe00b7656..5ec9a247b6 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -196,6 +196,12 @@ class Mesh { /// Wrapper for GridDataSource::hasVar bool sourceHasVar(const std::string &name); + + /// Wrapper for GridDataSource::hasXBoundaryGuards + bool sourceHasXBoundaryGuards(); + + /// Wrapper for GridDataSource::hasYBoundaryGuards + bool sourceHasYBoundaryGuards(); // Communications /*! diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index d50a091a4b..049af59c19 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -421,6 +421,19 @@ bool GridFile::get(Mesh *UNUSED(m), std::vector &var, const std::strin return true; } +bool GridFile::hasXBoundaryGuards(Mesh* m) { + // Global (x,y) dimensions of some field + // a grid file should always contain "dx" + const auto field_dimensions = file->getSize("dx"); + + if (field_dimensions.empty()) { + // handle case where "dx" is not present - non-standard grid file + // - e.g. for tests + return false; + } + + return field_dimensions[0] > m->GlobalNx - 2*m->xstart; +} ///////////////////////////////////////////////////////////// // Private routines diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 8766cb5c32..9ee1285071 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -170,6 +170,16 @@ bool Mesh::sourceHasVar(const std::string &name) { return source->hasVar(name); } +/// Wrapper for GridDataSource::hasXBoundaryGuards +bool Mesh::sourceHasXBoundaryGuards() { + return source->hasXBoundaryGuards(this); +} + +/// Wrapper for GridDataSource::hasYBoundaryGuards +bool Mesh::sourceHasYBoundaryGuards() { + return source->hasYBoundaryGuards(); +} + /************************************************************************** * Communications **************************************************************************/ diff --git a/tests/unit/mesh/test_boutmesh.cxx b/tests/unit/mesh/test_boutmesh.cxx index 3a5ec6295f..885fbcb901 100644 --- a/tests/unit/mesh/test_boutmesh.cxx +++ b/tests/unit/mesh/test_boutmesh.cxx @@ -37,6 +37,8 @@ class FakeGridDataSource : public GridDataSource { Direction UNUSED(dir) = GridDataSource::X) { return true; } + bool hasXBoundaryGuards(Mesh* UNUSED(m)) { return false; } + bool hasYBoundaryGuards() { return false; } }; TEST(BoutMeshTest, NullOptionsCheck) { From 01e5e4641035a20140eef0a89ed6615f6b083747 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 20:41:23 +0000 Subject: [PATCH 1077/1783] When loading from grid, only extrapolate if boundary cells were not read When initializing geometrical quantities in the Coordinates constructor, check if the boundary cells were read from the grid file. Only if they were not read, extrapolate them from the grid (which ensures the geometrical quantities are smooth at the boundaries). --- src/mesh/coordinates.cxx | 207 ++++++++++++++++++++++++--------------- 1 file changed, 130 insertions(+), 77 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 8f131ba2dc..1c4e85bd9e 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -24,7 +24,9 @@ namespace { /// Boundary guard cells are set by extrapolating from the grid, like /// 'free_o3' boundary conditions /// Corner guard cells are set to BoutNaN -Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location) { +Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location, + bool extrapolate_x = true, bool extrapolate_y = true) { + Mesh* localmesh = f.getMesh(); Field2D result = interp_to(f, location, RGN_NOBNDRY); // Ensure result's data is unique. Otherwise result might be a duplicate of @@ -37,66 +39,68 @@ Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location) { result.allocate(); localmesh->communicate(result); - // Extrapolate into boundaries so that differential geometry terms can be - // interpolated if necessary + // Extrapolate into boundaries (if requested) so that differential geometry + // terms can be interpolated if necessary // Note: cannot use applyBoundary("free_o3") here because applyBoundary() // would try to create a new Coordinates object since we have not finished // initializing yet, leading to an infinite recursion. // Also, here we interpolate for the boundary points at xstart/ystart and // (xend+1)/(yend+1) instead of extrapolating. for (auto bndry : localmesh->getBoundaries()) { - int extrap_start = 0; - if ((location == CELL_XLOW) && (bndry->bx > 0)) { - extrap_start = 1; - } else if ((location == CELL_YLOW) && (bndry->by > 0)) { - extrap_start = 1; - } - for (bndry->first(); !bndry->isDone(); bndry->next1d()) { - // interpolate extra boundary point that is missed by interp_to, if - // necessary. - // Only interpolate this point if we are actually changing location. E.g. - // when we use this function to extrapolate J and Bxy on staggered grids, - // this point should already be set correctly because the metric - // components have been interpolated to here. - if (extrap_start > 0 and f.getLocation() != location) { - // note that either bx or by is >0 here - result(bndry->x, bndry->y) = - (9. * (f(bndry->x - bndry->bx, bndry->y - bndry->by) + f(bndry->x, bndry->y)) - - f(bndry->x - 2 * bndry->bx, bndry->y - 2 * bndry->by) - - f(bndry->x + bndry->bx, bndry->y + bndry->by)) - / 16.; + if ((extrapolate_x and bndry->bx != 0) or (extrapolate_y and bndry->by != 0)) { + int extrap_start = 0; + if ((location == CELL_XLOW) && (bndry->bx > 0)) { + extrap_start = 1; + } else if ((location == CELL_YLOW) && (bndry->by > 0)) { + extrap_start = 1; } - - // set boundary guard cells - if ((bndry->bx != 0 && localmesh->GlobalNx - 2 * bndry->width >= 3) - || (bndry->by != 0 && localmesh->GlobalNy - 2 * bndry->width >= 3)) { - if (bndry->bx != 0 && localmesh->LocalNx == 1 && bndry->width == 1) { - throw BoutException( - "Not enough points in the x-direction on this " - "processor for extrapolation needed to use staggered grids. " - "Increase number of x-guard cells MXG or decrease number of " - "processors in the x-direction NXPE."); - } - if (bndry->by != 0 && localmesh->LocalNy == 1 && bndry->width == 1) { - throw BoutException( - "Not enough points in the y-direction on this " - "processor for extrapolation needed to use staggered grids. " - "Increase number of y-guard cells MYG or decrease number of " - "processors in the y-direction NYPE."); - } - // extrapolate into boundary guard cells if there are enough grid points - for (int i = extrap_start; i < bndry->width; i++) { - int xi = bndry->x + i * bndry->bx; - int yi = bndry->y + i * bndry->by; - result(xi, yi) = 3.0 * result(xi - bndry->bx, yi - bndry->by) - - 3.0 * result(xi - 2 * bndry->bx, yi - 2 * bndry->by) - + result(xi - 3 * bndry->bx, yi - 3 * bndry->by); + for (bndry->first(); !bndry->isDone(); bndry->next1d()) { + // interpolate extra boundary point that is missed by interp_to, if + // necessary. + // Only interpolate this point if we are actually changing location. E.g. + // when we use this function to extrapolate J and Bxy on staggered grids, + // this point should already be set correctly because the metric + // components have been interpolated to here. + if (extrap_start > 0 and f.getLocation() != location) { + // note that either bx or by is >0 here + result(bndry->x, bndry->y) = + (9. * (f(bndry->x - bndry->bx, bndry->y - bndry->by) + f(bndry->x, bndry->y)) + - f(bndry->x - 2 * bndry->bx, bndry->y - 2 * bndry->by) + - f(bndry->x + bndry->bx, bndry->y + bndry->by)) + / 16.; } - } else { - // not enough grid points to extrapolate, set equal to last grid point - for (int i = extrap_start; i < bndry->width; i++) { - result(bndry->x + i * bndry->bx, bndry->y + i * bndry->by) = - result(bndry->x - bndry->bx, bndry->y - bndry->by); + + // set boundary guard cells + if ((bndry->bx != 0 && localmesh->GlobalNx - 2 * bndry->width >= 3) + || (bndry->by != 0 && localmesh->GlobalNy - 2 * bndry->width >= 3)) { + if (bndry->bx != 0 && localmesh->LocalNx == 1 && bndry->width == 1) { + throw BoutException( + "Not enough points in the x-direction on this " + "processor for extrapolation needed to use staggered grids. " + "Increase number of x-guard cells MXG or decrease number of " + "processors in the x-direction NXPE."); + } + if (bndry->by != 0 && localmesh->LocalNy == 1 && bndry->width == 1) { + throw BoutException( + "Not enough points in the y-direction on this " + "processor for extrapolation needed to use staggered grids. " + "Increase number of y-guard cells MYG or decrease number of " + "processors in the y-direction NYPE."); + } + // extrapolate into boundary guard cells if there are enough grid points + for (int i = extrap_start; i < bndry->width; i++) { + int xi = bndry->x + i * bndry->bx; + int yi = bndry->y + i * bndry->by; + result(xi, yi) = 3.0 * result(xi - bndry->bx, yi - bndry->by) + - 3.0 * result(xi - 2 * bndry->bx, yi - 2 * bndry->by) + + result(xi - 3 * bndry->bx, yi - 3 * bndry->by); + } + } else { + // not enough grid points to extrapolate, set equal to last grid point + for (int i = extrap_start; i < bndry->width; i++) { + result(bndry->x + i * bndry->bx, bndry->y + i * bndry->by) = + result(bndry->x - bndry->bx, bndry->y - bndry->by); + } } } } @@ -165,24 +169,38 @@ Coordinates::Coordinates(Mesh* mesh) G3_23(mesh), G1(mesh), G2(mesh), G3(mesh), ShiftTorsion(mesh), IntShiftTorsion(mesh), localmesh(mesh), location(CELL_CENTRE) { - // Note: use 'interpolateAndExtrapolate' to set the boundary cells of the - // loaded fields. Ensures that derivatives are smooth at all the boundaries. + // Note: If boundary cells were not loaded from the grid file, use + // 'interpolateAndExtrapolate' to set them. Ensures that derivatives are + // smooth at all the boundaries. + + const bool extrapolate_x = not mesh->sourceHasXBoundaryGuards(); + const bool extrapolate_y = not mesh->sourceHasYBoundaryGuards(); + + if (extrapolate_x) { + output_warn.write(_("WARNING: extrapolating input mesh quantities into x-boundary " + "cells\n")); + } + + if (extrapolate_y) { + output_warn.write(_("WARNING: extrapolating input mesh quantities into y-boundary " + "cells\n")); + } if (mesh->get(dx, "dx")) { - output_warn.write("\tWARNING: differencing quantity 'dx' not found. Set to 1.0\n"); + output_warn.write(_("\tWARNING: differencing quantity 'dx' not found. Set to 1.0\n")); dx = 1.0; } - dx = interpolateAndExtrapolate(dx, location); + dx = interpolateAndExtrapolate(dx, location, extrapolate_x, extrapolate_y); if (mesh->periodicX) { mesh->communicate(dx); } if (mesh->get(dy, "dy")) { - output_warn.write("\tWARNING: differencing quantity 'dy' not found. Set to 1.0\n"); + output_warn.write(_("\tWARNING: differencing quantity 'dy' not found. Set to 1.0\n")); dy = 1.0; } - dy = interpolateAndExtrapolate(dy, location); + dy = interpolateAndExtrapolate(dy, location, extrapolate_x, extrapolate_y); nz = mesh->LocalNz; @@ -205,19 +223,19 @@ Coordinates::Coordinates(Mesh* mesh) // Diagonal components of metric tensor g^{ij} (default to 1) mesh->get(g11, "g11", 1.0); - g11 = interpolateAndExtrapolate(g11, location); + g11 = interpolateAndExtrapolate(g11, location, extrapolate_x, extrapolate_y); mesh->get(g22, "g22", 1.0); - g22 = interpolateAndExtrapolate(g22, location); + g22 = interpolateAndExtrapolate(g22, location, extrapolate_x, extrapolate_y); mesh->get(g33, "g33", 1.0); - g33 = interpolateAndExtrapolate(g33, location); + g33 = interpolateAndExtrapolate(g33, location, extrapolate_x, extrapolate_y); // Off-diagonal elements. Default to 0 mesh->get(g12, "g12", 0.0); - g12 = interpolateAndExtrapolate(g12, location); + g12 = interpolateAndExtrapolate(g12, location, extrapolate_x, extrapolate_y); mesh->get(g13, "g13", 0.0); - g13 = interpolateAndExtrapolate(g13, location); + g13 = interpolateAndExtrapolate(g13, location, extrapolate_x, extrapolate_y); mesh->get(g23, "g23", 0.0); - g23 = interpolateAndExtrapolate(g23, location); + g23 = interpolateAndExtrapolate(g23, location, extrapolate_x, extrapolate_y); // Check input metrics if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) @@ -268,12 +286,12 @@ Coordinates::Coordinates(Mesh* mesh) } // More robust to extrapolate derived quantities directly, rather than // deriving from extrapolated covariant metric components - g_11 = interpolateAndExtrapolate(g_11, location); - g_22 = interpolateAndExtrapolate(g_22, location); - g_33 = interpolateAndExtrapolate(g_33, location); - g_12 = interpolateAndExtrapolate(g_12, location); - g_13 = interpolateAndExtrapolate(g_13, location); - g_23 = interpolateAndExtrapolate(g_23, location); + g_11 = interpolateAndExtrapolate(g_11, location, extrapolate_x, extrapolate_y); + g_22 = interpolateAndExtrapolate(g_22, location, extrapolate_x, extrapolate_y); + g_33 = interpolateAndExtrapolate(g_33, location, extrapolate_x, extrapolate_y); + g_12 = interpolateAndExtrapolate(g_12, location, extrapolate_x, extrapolate_y); + g_13 = interpolateAndExtrapolate(g_13, location, extrapolate_x, extrapolate_y); + g_23 = interpolateAndExtrapolate(g_23, location, extrapolate_x, extrapolate_y); /// Calculate Jacobian and Bxy if (jacobian()) @@ -308,8 +326,8 @@ Coordinates::Coordinates(Mesh* mesh) } // More robust to extrapolate derived quantities directly, rather than // deriving from extrapolated covariant metric components - J = interpolateAndExtrapolate(J, location); - Bxy = interpolateAndExtrapolate(Bxy, location); + J = interpolateAndExtrapolate(J, location, extrapolate_x, extrapolate_y); + Bxy = interpolateAndExtrapolate(Bxy, location, extrapolate_x, extrapolate_y); ////////////////////////////////////////////////////// /// Calculate Christoffel symbols. Needs communication @@ -322,7 +340,7 @@ Coordinates::Coordinates(Mesh* mesh) "\tWARNING: No Torsion specified for zShift. Derivatives may not be correct\n"); ShiftTorsion = 0.0; } - ShiftTorsion = interpolateAndExtrapolate(ShiftTorsion, location); + ShiftTorsion = interpolateAndExtrapolate(ShiftTorsion, location, extrapolate_x, extrapolate_y); ////////////////////////////////////////////////////// @@ -331,7 +349,7 @@ Coordinates::Coordinates(Mesh* mesh) output_warn.write("\tWARNING: No Integrated torsion specified\n"); IntShiftTorsion = 0.0; } - IntShiftTorsion = interpolateAndExtrapolate(IntShiftTorsion, location); + IntShiftTorsion = interpolateAndExtrapolate(IntShiftTorsion, location, extrapolate_x, extrapolate_y); } else { // IntShiftTorsion will not be used, but set to zero to avoid uninitialized field IntShiftTorsion = 0.; @@ -376,8 +394,25 @@ Coordinates::Coordinates(Mesh* mesh, const CELL_LOC loc, const Coordinates* coor dz = coords_in->dz; + // Default to true in case staggered quantities are not read from file + bool extrapolate_x = true; + bool extrapolate_y = true; + if (!force_interpolate_from_centre && mesh->sourceHasVar("dx"+suffix)) { + extrapolate_x = not mesh->sourceHasXBoundaryGuards(); + extrapolate_y = not mesh->sourceHasYBoundaryGuards(); + + if (extrapolate_x) { + output_warn.write(_("WARNING: extrapolating input mesh quantities into x-boundary " + "cells\n")); + } + + if (extrapolate_y) { + output_warn.write(_("WARNING: extrapolating input mesh quantities into y-boundary " + "cells\n")); + } + checkStaggeredGet(mesh, "dx", suffix); if (mesh->get(dx, "dx"+suffix)) { output_warn.write( @@ -385,6 +420,7 @@ Coordinates::Coordinates(Mesh* mesh, const CELL_LOC loc, const Coordinates* coor dx = 1.0; } dx.setLocation(location); + dx = interpolateAndExtrapolate(dx, location, extrapolate_x, extrapolate_y); if (mesh->periodicX) { mesh->communicate(dx); @@ -397,15 +433,22 @@ Coordinates::Coordinates(Mesh* mesh, const CELL_LOC loc, const Coordinates* coor dy = 1.0; } dy.setLocation(location); + dy = interpolateAndExtrapolate(dy, location, extrapolate_x, extrapolate_y); // grid data source has staggered fields, so read instead of interpolating // Diagonal components of metric tensor g^{ij} (default to 1) getAtLoc(mesh, g11, "g11", suffix, location, 1.0); + g11 = interpolateAndExtrapolate(g11, location, extrapolate_x, extrapolate_y); getAtLoc(mesh, g22, "g22", suffix, location, 1.0); + g22 = interpolateAndExtrapolate(g22, location, extrapolate_x, extrapolate_y); getAtLoc(mesh, g33, "g33", suffix, location, 1.0); + g33 = interpolateAndExtrapolate(g33, location, extrapolate_x, extrapolate_y); getAtLoc(mesh, g12, "g12", suffix, location, 0.0); + g12 = interpolateAndExtrapolate(g12, location, extrapolate_x, extrapolate_y); getAtLoc(mesh, g13, "g13", suffix, location, 0.0); + g13 = interpolateAndExtrapolate(g13, location, extrapolate_x, extrapolate_y); getAtLoc(mesh, g23, "g23", suffix, location, 0.0); + g23 = interpolateAndExtrapolate(g23, location, extrapolate_x, extrapolate_y); /// Find covariant metric components auto covariant_component_names = {"g_11", "g_22", "g_33", "g_12", "g_13", "g_23"}; @@ -443,6 +486,14 @@ Coordinates::Coordinates(Mesh* mesh, const CELL_LOC loc, const Coordinates* coor throw BoutException("Error in staggered calcCovariant call"); } } + // More robust to extrapolate derived quantities directly, rather than + // deriving from extrapolated covariant metric components + g_11 = interpolateAndExtrapolate(g_11, location, extrapolate_x, extrapolate_y); + g_22 = interpolateAndExtrapolate(g_22, location, extrapolate_x, extrapolate_y); + g_33 = interpolateAndExtrapolate(g_33, location, extrapolate_x, extrapolate_y); + g_12 = interpolateAndExtrapolate(g_12, location, extrapolate_x, extrapolate_y); + g_13 = interpolateAndExtrapolate(g_13, location, extrapolate_x, extrapolate_y); + g_23 = interpolateAndExtrapolate(g_23, location, extrapolate_x, extrapolate_y); checkStaggeredGet(mesh, "ShiftTorsion", suffix); if (mesh->get(ShiftTorsion, "ShiftTorsion"+suffix)) { @@ -450,6 +501,7 @@ Coordinates::Coordinates(Mesh* mesh, const CELL_LOC loc, const Coordinates* coor ShiftTorsion = 0.0; } ShiftTorsion.setLocation(location); + ShiftTorsion = interpolateAndExtrapolate(ShiftTorsion, location, extrapolate_x, extrapolate_y); ////////////////////////////////////////////////////// @@ -460,6 +512,7 @@ Coordinates::Coordinates(Mesh* mesh, const CELL_LOC loc, const Coordinates* coor IntShiftTorsion = 0.0; } IntShiftTorsion.setLocation(location); + IntShiftTorsion = interpolateAndExtrapolate(IntShiftTorsion, location, extrapolate_x, extrapolate_y); } else { // IntShiftTorsion will not be used, but set to zero to avoid uninitialized field IntShiftTorsion = 0.; @@ -516,8 +569,8 @@ Coordinates::Coordinates(Mesh* mesh, const CELL_LOC loc, const Coordinates* coor throw BoutException("Error in jacobian call while constructing staggered Coordinates"); // More robust to extrapolate derived quantities directly, rather than // deriving from extrapolated covariant metric components - J = interpolateAndExtrapolate(J, location); - Bxy = interpolateAndExtrapolate(Bxy, location); + J = interpolateAndExtrapolate(J, location, extrapolate_x, extrapolate_y); + Bxy = interpolateAndExtrapolate(Bxy, location, extrapolate_x, extrapolate_y); ////////////////////////////////////////////////////// /// Calculate Christoffel symbols. Needs communication From c46a5e91a1b072c6e60e2ee14331b7849a8da041 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 14 Mar 2019 18:57:55 +0000 Subject: [PATCH 1078/1783] Fix string comparison in ParallelTransform::checkInput Apparently strings returned from Mesh::get have a length 1 greater than if you just type in a string literal, so the operator== comparison was failing. Converting to c_str and using strcmp gets around this (as strcmp just compares up to the first null byte, so does not see the different lengths). --- src/mesh/parallel/fci.cxx | 2 +- src/mesh/parallel/identity.cxx | 2 +- src/mesh/parallel/shiftedmetric.cxx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 272947950a..fd3031fbce 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -327,7 +327,7 @@ Field3D FCIMap::integrate(Field3D &f) const { void FCITransform::checkInputGrid() { std::string coordinates_type = ""; if (!mesh.get(coordinates_type, "coordinates_type")) { - if (coordinates_type != "fci") { + if (strcmp(coordinates_type.c_str(), "fci") != 0) { throw BoutException("Incorrect coordinate system type "+coordinates_type+" used " "to generate metric components for FCITransform. Should be 'fci."); } diff --git a/src/mesh/parallel/identity.cxx b/src/mesh/parallel/identity.cxx index ca4a78b7f2..0dd95969a2 100644 --- a/src/mesh/parallel/identity.cxx +++ b/src/mesh/parallel/identity.cxx @@ -21,7 +21,7 @@ void ParallelTransformIdentity::calcYUpDown(Field3D& f) { void ParallelTransformIdentity::checkInputGrid() { std::string coordinates_type = ""; if (!mesh.get(coordinates_type, "coordinates_type")) { - if (coordinates_type != "field_aligned") { + if (strcmp(coordinates_type.c_str(), "field_aligned") != 0) { throw BoutException("Incorrect coordinate system type "+coordinates_type+" used " "to generate metric components for ParallelTransformIdentity. Should be " "'field_aligned."); diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index fb0d96a879..c2403b3c83 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -49,7 +49,7 @@ ShiftedMetric::ShiftedMetric(Mesh& m, Field2D zShift_) void ShiftedMetric::checkInputGrid() { std::string coordinates_type = ""; if (!mesh.get(coordinates_type, "coordinates_type")) { - if (coordinates_type != "orthogonal") { + if (strcmp(coordinates_type.c_str(), "orthogonal") != 0) { throw BoutException("Incorrect coordinate system type " + coordinates_type + " used to generate metric components for ShiftedMetric. " "Should be 'orthogonal."); From f4b8f2529552e298456fa2afd962c23bc4e46add Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 20 Mar 2019 12:18:24 +0000 Subject: [PATCH 1079/1783] Write out ny_inner in BoutMesh::outputVars() This specifies where (in index space) the upper divertor target plates are, if they are present. --- src/mesh/impls/bout/boutmesh.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 1ffd5d994a..8ca70d5cbc 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2594,6 +2594,7 @@ void BoutMesh::outputVars(Datafile &file) { file.add(jyseps1_2, "jyseps1_2", false); file.add(jyseps2_1, "jyseps2_1", false); file.add(jyseps2_2, "jyseps2_2", false); + file.add(ny_inner, "ny_inner", false); getCoordinates()->outputVars(file); } From dc57ed4b271bb89167c5d41f151dc1aad5be7474 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 11 Mar 2019 18:14:44 +0000 Subject: [PATCH 1080/1783] Hypnotoad: better refinement of starting locations in nonorthogonal Previously, for nonorthogonal grids the starting positions (points along the separatrix) were refined only when the grid was being created in the core. This commit moves the refinement to a position (previously commented-out) in grid_region_nonorth which ensures it is done in every case. This makes non-orthogonal grid generation more robust, especially around x-points. --- .../gridgen/create_nonorthogonal.pro | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index 8346415382..b282227f40 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -383,9 +383,11 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ IF orthdown EQ 1 THEN weight_down = 0 ELSE weight_down = (1.-i/(npar-1.))^nonorthogonal_weight_decay_power ; Refine the location of the starting point -; follow_gradient_nonorth, interp_data, R, Z, rii[i], zii[i], f0, ri1, zi1, vec=vec_in, weight=weight -; rii[i] = ri1 -; zii[i] = zi1 + follow_gradient_nonorth, interp_data, R, Z, rii[i], zii[i], f0, ri1, zi1, $ + vec_up=vec_in_up, weight_up=weight_up, $ + vec_down=vec_in_down, weight_down=weight_down + rii[i] = ri1 + zii[i] = zi1 IF sind GE 0 THEN BEGIN rixy[nin, i] = rii[i] @@ -1080,11 +1082,11 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ start_ri = (SMOOTH([start_ri[(np-s):(np-1)], start_ri, start_ri[0:(s-1)]], s))[s:(np-1+s)] start_zi = (SMOOTH([start_zi[(np-s):(np-1)], start_zi, start_zi[0:(s-1)]], s))[s:(np-1+s)] - FOR i=0, np-1 DO BEGIN - follow_gradient_nonorth, interp_data, R, Z, start_ri[i], start_zi[i], start_f, ri1, zi1 - start_ri[i] = ri1 - start_zi[i] = zi1 - ENDFOR + ;FOR i=0, np-1 DO BEGIN + ; follow_gradient_nonorth, interp_data, R, Z, start_ri[i], start_zi[i], start_f, ri1, zi1 + ; start_ri[i] = ri1 + ; start_zi[i] = zi1 + ;ENDFOR oplot_contour, info, xy, R, Z, /periodic, color=2, thick=1.5 From 98089fd721a77e5317d982c7df8d45e42607cfe9 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 11 Mar 2019 14:07:53 +0000 Subject: [PATCH 1081/1783] Hypnotoad: pass 'simple' setting to create_grid re-tries When create_grid fails, sometimes it changes some options and tries calling create_grid again. Previously the 'simple' setting was not being passed through to the new calls. --- tools/tokamak_grids/gridgen/create_grid.pro | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_grid.pro b/tools/tokamak_grids/gridgen/create_grid.pro index bc3c10c397..a462bdfb86 100644 --- a/tools/tokamak_grids/gridgen/create_grid.pro +++ b/tools/tokamak_grids/gridgen/create_grid.pro @@ -1286,7 +1286,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ rad_peaking:settings.rad_peaking, pol_peaking:settings.pol_peaking} RETURN, create_grid(F, R, Z, new_settings, critical=critical, $ boundary=boundary, iter=iter+1, nrad_flexible=nrad_flexible, $ - single_rad_grid=single_rad_grid, fast=fast) + single_rad_grid=single_rad_grid, fast=fast, simple=simple) ENDIF dpsi = sol_psi_vals[i,TOTAL(nrad,/int)-nsol-1] - sol_psi_vals[i,TOTAL(nrad,/int)-nsol-2] sol_psi_vals[i,(TOTAL(nrad,/int)-nsol):*] = radial_grid(nsol, $ @@ -1893,7 +1893,8 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ RETURN, create_grid(F, R, Z, new_settings, critical=critical, $ boundary=boundary, strictbndry=strictbndry, $ iter=iter+1, nrad_flexible=nrad_flexible, $ - single_rad_grid=single_rad_grid, fast=fast) + single_rad_grid=single_rad_grid, fast=fast, $ + simple=simple) ENDIF From 1a1eb268da7bb96812a49708dac63512cfaa3224 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 11 Mar 2019 14:07:53 +0000 Subject: [PATCH 1082/1783] Hypnotoad: rename gen_surface->gen_surface_hypnotoad to avoid name clash Previously Hypnotoad would use the version from idllib if that was in the $IDL_PATH. --- tools/tokamak_grids/gridgen/adjust_jpar.pro | 8 +-- tools/tokamak_grids/gridgen/curvature.pro | 4 +- tools/tokamak_grids/gridgen/ddy.pro | 4 +- ..._surface.pro => gen_surface_hypnotoad.pro} | 6 +- tools/tokamak_grids/gridgen/int_y.pro | 4 +- tools/tokamak_grids/gridgen/plot_mesh.pro | 4 +- tools/tokamak_grids/gridgen/process_grid.pro | 68 +++++++++---------- tools/tokamak_grids/gridgen/smooth_nl.pro | 8 +-- 8 files changed, 53 insertions(+), 53 deletions(-) rename tools/tokamak_grids/gridgen/{gen_surface.pro => gen_surface_hypnotoad.pro} (92%) diff --git a/tools/tokamak_grids/gridgen/adjust_jpar.pro b/tools/tokamak_grids/gridgen/adjust_jpar.pro index d6d0b16681..261d895749 100644 --- a/tools/tokamak_grids/gridgen/adjust_jpar.pro +++ b/tools/tokamak_grids/gridgen/adjust_jpar.pro @@ -45,9 +45,9 @@ PRO adjust_jpar, grid, smoothp=smoothp, jpar=jpar, noplot=noplot ; Matching here rather than outboard produces more realistic results ; (current doesn't reverse direction at edge) mid_ind = -1 - status = gen_surface(mesh=data) ; Start generator + status = gen_surface_hypnotoad(mesh=data) ; Start generator REPEAT BEGIN - yi = gen_surface(last=last, xi=xi, period=period) + yi = gen_surface_hypnotoad(last=last, xi=xi, period=period) IF period THEN BEGIN mr = MIN(data.rxy[xi, yi], mid_ind) @@ -89,9 +89,9 @@ PRO adjust_jpar, grid, smoothp=smoothp, jpar=jpar, noplot=noplot IF count GT 0 THEN dj[w] = 0.0 ; just zero in this region jpar = ps - status = gen_surface(mesh=data) ; Start generator + status = gen_surface_hypnotoad(mesh=data) ; Start generator REPEAT BEGIN - yi = gen_surface(last=last, xi=xi, period=period) + yi = gen_surface_hypnotoad(last=last, xi=xi, period=period) IF NOT period THEN BEGIN ; Due to multi-point differencing, dp/dx can be non-zero outside separatrix diff --git a/tools/tokamak_grids/gridgen/curvature.pro b/tools/tokamak_grids/gridgen/curvature.pro index 1c264531c1..80ed9424d5 100644 --- a/tools/tokamak_grids/gridgen/curvature.pro +++ b/tools/tokamak_grids/gridgen/curvature.pro @@ -112,9 +112,9 @@ PRO curvature, nx, ny, Rxy, Zxy, BRxy, BZxy, BPHIxy, PSIxy, THETAxy, HTHExy, $ vec2={psi:0.,theta:0.,phi:0.} bxcv=REPLICATE(vec2,nx,ny) - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN - yi = gen_surface(last=last, xi=x, period=period) + yi = gen_surface_hypnotoad(last=last, xi=x, period=period) nys = N_ELEMENTS(yi) ; Get vector along the surface diff --git a/tools/tokamak_grids/gridgen/ddy.pro b/tools/tokamak_grids/gridgen/ddy.pro index 3d3eb81722..7692596a21 100644 --- a/tools/tokamak_grids/gridgen/ddy.pro +++ b/tools/tokamak_grids/gridgen/ddy.pro @@ -4,9 +4,9 @@ FUNCTION ddy, var, mesh dtheta = 2.*!PI / FLOAT(TOTAL(mesh.npol)) - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN - yi = gen_surface(last=last, xi=xi, period=period) + yi = gen_surface_hypnotoad(last=last, xi=xi, period=period) IF period THEN BEGIN f[xi,yi] = fft_deriv(var[xi,yi]) ENDIF ELSE f[xi,yi] = DERIV(var[xi,yi]) diff --git a/tools/tokamak_grids/gridgen/gen_surface.pro b/tools/tokamak_grids/gridgen/gen_surface_hypnotoad.pro similarity index 92% rename from tools/tokamak_grids/gridgen/gen_surface.pro rename to tools/tokamak_grids/gridgen/gen_surface_hypnotoad.pro index a92e0d1cc7..1fea3fc4cf 100644 --- a/tools/tokamak_grids/gridgen/gen_surface.pro +++ b/tools/tokamak_grids/gridgen/gen_surface_hypnotoad.pro @@ -2,9 +2,9 @@ ; Generator of continuous surfaces ; ; First call: -; status = gen_surface(mesh=mesh) - Initialisation +; status = gen_surface_hypnotoad(mesh=mesh) - Initialisation ; Subsequent calls -; yi = gen_surface(period=period, last=last, xi=xi) +; yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) ; ; period - Set to 1 if the surface is periodic, 0 otherwise ; last - Set to 1 if this is the last surface @@ -19,7 +19,7 @@ FUNCTION range, first, last ENDELSE END -FUNCTION gen_surface, mesh=mesh, period=period, last=last, xi=xi +FUNCTION gen_surface_hypnotoad, mesh=mesh, period=period, last=last, xi=xi COMMON gen_surf_com, m, ys, xind, nd, domain, visited IF KEYWORD_SET(mesh) THEN BEGIN ; Starting diff --git a/tools/tokamak_grids/gridgen/int_y.pro b/tools/tokamak_grids/gridgen/int_y.pro index f9f543b62b..23601f0565 100644 --- a/tools/tokamak_grids/gridgen/int_y.pro +++ b/tools/tokamak_grids/gridgen/int_y.pro @@ -6,9 +6,9 @@ FUNCTION int_y, var, mesh, loop=loop, nosmooth=nosmooth, simple=simple nx = s[0] loop = FLTARR(nx) - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN - yi = gen_surface(last=last, xi=xi, period=period) + yi = gen_surface_hypnotoad(last=last, xi=xi, period=period) IF period THEN BEGIN ; Add first point onto the end so wraps around for integration diff --git a/tools/tokamak_grids/gridgen/plot_mesh.pro b/tools/tokamak_grids/gridgen/plot_mesh.pro index 2dd1da4f95..4ae7265663 100644 --- a/tools/tokamak_grids/gridgen/plot_mesh.pro +++ b/tools/tokamak_grids/gridgen/plot_mesh.pro @@ -6,9 +6,9 @@ PRO plot_mesh, mesh, overplot=overplot, _extra=_extra IF KEYWORD_SET(overplot) THEN over = 1 ; Plot flux surfaces - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN - yi = gen_surface(last=last, xi=xi, period=period) + yi = gen_surface_hypnotoad(last=last, xi=xi, period=period) IF period THEN yi = [yi, yi[0]] IF over EQ 0 THEN BEGIN PLOT, mesh.Rxy[xi, yi], mesh.Zxy[xi, yi], $ diff --git a/tools/tokamak_grids/gridgen/process_grid.pro b/tools/tokamak_grids/gridgen/process_grid.pro index 9fa26042e5..24b70a0f8b 100644 --- a/tools/tokamak_grids/gridgen/process_grid.pro +++ b/tools/tokamak_grids/gridgen/process_grid.pro @@ -29,9 +29,9 @@ FUNCTION surface_average, var, mesh f = var - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN - yi = gen_surface(last=last, xi=xi) + yi = gen_surface_hypnotoad(last=last, xi=xi) f[xi,yi] = MEAN(var[xi,yi]) ; Average over this surface ENDREP UNTIL last RETURN, f @@ -119,9 +119,9 @@ function calc_beta, Rxy, Zxy, mesh, rz_grid, method endif else if(method EQ 1) then begin npol = round(total(mesh.npol,/cumulative)) Nnpol = n_elements(npol) - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN - yi = gen_surface(last=last, xi=xi, period=period) + yi = gen_surface_hypnotoad(last=last, xi=xi, period=period) ; find beta using one field line at xi, with y range yi ; for better angle calculation, need to split yi into sections based on gridding if (xi GE mesh.nrad[0]) then begin ; if outside the separatrix @@ -290,9 +290,9 @@ FUNCTION my_int_y, var, yaxis, mesh, loop=loop, nosmooth=nosmooth, simple=simple loop = FLTARR(nx) loop[*] = !VALUES.F_NAN ; Prevent accidental use of unset values - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN - yi = gen_surface(last=last, xi=xi, period=period) + yi = gen_surface_hypnotoad(last=last, xi=xi, period=period) f[xi,yi] = inty(yaxis[xi,yi],var[xi,yi], /simple) IF NOT KEYWORD_SET(nosmooth) THEN BEGIN @@ -318,9 +318,9 @@ function dfdy, f, y, mesh ny = s[1] result = dblarr(nx,ny) - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN - yi = gen_surface(last=last, xi=xi) + yi = gen_surface_hypnotoad(last=last, xi=xi) result[xi,yi] = DERIV(y[xi,yi],f[xi,yi]) ENDREP UNTIL last return, result @@ -445,10 +445,10 @@ FUNCTION fit_profiles, mesh, psixy, Rxy, hthe, Bpxy, Btxy, dpdx ; Map between location in xy and surface number indxy = INTARR(nx, ny) - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator i = 0 REPEAT BEGIN - yi = gen_surface(last=last, xi=xi, period=period) + yi = gen_surface_hypnotoad(last=last, xi=xi, period=period) indxy[xi,yi] = i IF i EQ 0 THEN BEGIN @@ -477,10 +477,10 @@ FUNCTION fit_profiles, mesh, psixy, Rxy, hthe, Bpxy, Btxy, dpdx Btxy2 = FLTARR(nx, ny) dpdx2 = FLTARR(nx, ny) - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator i = 0 REPEAT BEGIN - yi = gen_surface(last=last, xi=xi, period=period) + yi = gen_surface_hypnotoad(last=last, xi=xi, period=period) Btxy2[xi, yi] = profiles[nsurf+i] / Rxy[xi,yi] dpdx2[xi, yi] = profiles[i] i = i + 1 @@ -678,9 +678,9 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ; Find the midplane ymid = 0 - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN - yi = gen_surface(period=period, last=last, xi=xi) + yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) IF period THEN BEGIN rm = MAX(mesh.Rxy[xi,yi], ymid) ymid = yi[ymid] @@ -700,10 +700,10 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ pressure = FLTARR(nx, ny) ; Use splines to interpolate pressure profile - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain - yi = gen_surface(period=period, last=last, xi=xi) + yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) IF period AND (psixy_eq[xi,yi[0]] GE 0) AND (psixy_eq[xi,yi[0]] LE 1) THEN BEGIN ; Pressure only given on core surfaces ; Since psi normalised differently, it might go out of range @@ -734,10 +734,10 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ p2 = pressure FOR i=0, 5 DO BEGIN - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain - yi = gen_surface(period=period, last=last, xi=xi) + yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) IF (xi GT 0) AND (xi LT (nx-1)) THEN BEGIN FOR j=0,N_ELEMENTS(yi)-1 DO BEGIN @@ -820,10 +820,10 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ Btxy = FLTARR(nx, ny) fprime = Btxy fp = DERIV(rz_grid.npsigrid*(rz_grid.sibdry - rz_grid.simagx), rz_grid.fpol) - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain - yi = gen_surface(period=period, last=last, xi=xi) + yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) IF period AND (psixy_eq[xi,yi[0]] GE 0) AND (psixy_eq[xi,yi[0]] LE 1) THEN BEGIN ; In the core @@ -847,10 +847,10 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ hthe = FLTARR(nx, ny) ; Pick a midplane index - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain - yi = gen_surface(period=period, last=last, xi=xi) + yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) IF period THEN BEGIN ; In the core @@ -860,10 +860,10 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ENDIF ENDREP UNTIL last - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain - yi = gen_surface(period=period, last=last, xi=xi) + yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) n = N_ELEMENTS(yi) @@ -940,10 +940,10 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ pres[*,i] = pres[*,i] - pres[nx-1,i] ENDFOR - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain - yi = gen_surface(period=period, last=last, xi=xi) + yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) ma = MAX(pres[xi,yi]) FOR i=0, N_ELEMENTS(yi)-1 DO BEGIN @@ -1048,10 +1048,10 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ hthe[*,i] = SMOOTH(SMOOTH(hthe[*,i],10),10) ENDFOR - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain - yi = gen_surface(period=period, last=last, xi=xi) + yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) n = N_ELEMENTS(yi) @@ -1066,10 +1066,10 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ; Need yxy values at all points for nonorthogonal calculations yxy = FLTARR(nx, ny) - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain - yi = gen_surface(period=period, last=last, xi=xi) + yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) yxy[xi,yi] = DINDGEN(N_ELEMENTS(yi))*dtheta ENDREP UNTIL last @@ -1143,10 +1143,10 @@ retrybetacalc: PRINT, "MIDPLANE INDEX = ", ymidplane - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain - yi = gen_surface(period=period, last=last, xi=xi) + yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) w = WHERE(yi EQ ymidplane, count) IF count GT 0 THEN BEGIN @@ -1323,10 +1323,10 @@ retrybetacalc: jpar0 = - Bxy * fprime / MU - Rxy*Btxy * dpdpsi / Bxy ; Set to zero in PF and SOL - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain - yi = gen_surface(period=period, last=last, xi=xi) + yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) IF NOT period THEN jpar0[xi,yi] = 0.0 ENDREP UNTIL last diff --git a/tools/tokamak_grids/gridgen/smooth_nl.pro b/tools/tokamak_grids/gridgen/smooth_nl.pro index 54ff6b8aa1..e029518524 100644 --- a/tools/tokamak_grids/gridgen/smooth_nl.pro +++ b/tools/tokamak_grids/gridgen/smooth_nl.pro @@ -20,10 +20,10 @@ FUNCTION smooth_nl, input, mesh, iter=iter it = 0 REPEAT BEGIN - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain - yi = gen_surface(period=period, last=last, x=x) + yi = gen_surface_hypnotoad(period=period, last=last, x=x) IF x GT 0 AND x LT nx-1 THEN BEGIN n = N_ELEMENTS(yi) @@ -63,10 +63,10 @@ FUNCTION smooth_nl, input, mesh, iter=iter markx = (0.5*mxn / MEAN(mxn)) < 1.0 marky = (0.5*myn / MEAN(myn)) < 1.0 - status = gen_surface(mesh=mesh) ; Start generator + status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain - yi = gen_surface(period=period, last=last, x=x) + yi = gen_surface_hypnotoad(period=period, last=last, x=x) IF x GT 0 AND x LT nx-1 THEN BEGIN n = N_ELEMENTS(yi) From e642121161e91cbe6b6fb3ddd01fcd44b973a13f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 19 Mar 2019 19:33:53 +0000 Subject: [PATCH 1083/1783] Hypnotoad: 'H' is derivative of integral The quantity 'H' is the y-derivative of qinty, but qinty is an integral in y. Instead of calculating numerically the integral and derivative, just set 'H' equal to the integrand. This removes errors at the y-boundaries. --- tools/tokamak_grids/gridgen/process_grid.pro | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/tokamak_grids/gridgen/process_grid.pro b/tools/tokamak_grids/gridgen/process_grid.pro index 24b70a0f8b..29a4bbe798 100644 --- a/tools/tokamak_grids/gridgen/process_grid.pro +++ b/tools/tokamak_grids/gridgen/process_grid.pro @@ -1131,8 +1131,11 @@ retrybetacalc: ; Calculate zshift (qinty), sinty = d(zshift)/dpsi, and H = d(zshift)/dtheta qinty = my_int_y(pitch*(1.+dyshiftdy), yxy, mesh, /nosmooth, loop=qloop) sinty = DDX(psixy,qinty) - H = dfdy_seps(qinty,thetaxy,mesh) -; H = dfdy(qinty,thetaxy,mesh) + + ; original calculation for H was: + ; H = dfdy_seps(qinty,thetaxy,mesh) + ; but qinty is an integral in y, so H is just the integrand + H = pitch*(1.D + dyshiftdy) ; NOTE: This is only valid in the core pol_angle = FLTARR(nx,ny) From e801fbe093434ca648e1ceccd1e960428face6aa Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 19 Mar 2019 19:40:57 +0000 Subject: [PATCH 1084/1783] Hypnotoad: use I instead of sinty to calculate curvature When calculating 'bxcvz' the integrated shear 'sinty' was used. This commit updates to use 'I' instead, so that when 'I' is set to zero for orthogonal coordinates the curvature is calculated consistently. --- tools/tokamak_grids/gridgen/process_grid.pro | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/tokamak_grids/gridgen/process_grid.pro b/tools/tokamak_grids/gridgen/process_grid.pro index 29a4bbe798..41595993c6 100644 --- a/tools/tokamak_grids/gridgen/process_grid.pro +++ b/tools/tokamak_grids/gridgen/process_grid.pro @@ -1235,7 +1235,7 @@ retrybetacalc: bxcvx = bpsign*bxcv.psi bxcvy = bxcv.theta - bxcvz = bpsign*(bxcv.phi - sinty*bxcv.psi - pitch*bxcv.theta) + bxcvz = bpsign*(bxcv.phi - I*bxcv.psi - pitch*bxcv.theta) ; x borders bxcvx[0,*] = bxcvx[1,*] @@ -1264,13 +1264,13 @@ retrybetacalc: ; If Bp is reversed, then Grad x = - Grad psi bxcvx = bpsign*bxcv_psi bxcvy = bxcv_theta - bxcvz = bpsign*(bxcv_phi - sinty*bxcv_psi - pitch*bxcv_theta) + bxcvz = bpsign*(bxcv_phi - I*bxcv_psi - pitch*bxcv_theta) ENDIF ELSE IF curv EQ 2 THEN BEGIN ; Curvature from Curl(b/B) bxcvx = bpsign*(Bpxy * Btxy*Rxy * DDY(1. / Bxy, mesh) / hthe) bxcvy = -bpsign*Bxy*Bpxy * DDX(xcoord, Btxy*Rxy/Bxy^2) / (2.*hthe) - bxcvz = Bpxy^3 * DDX(xcoord, hthe/Bpxy) / (2.*hthe*Bxy) - Btxy*Rxy*DDX(xcoord, Btxy/Rxy) / (2.*Bxy) - sinty*bxcvx + bxcvz = Bpxy^3 * DDX(xcoord, hthe/Bpxy) / (2.*hthe*Bxy) - Btxy*Rxy*DDX(xcoord, Btxy/Rxy) / (2.*Bxy) - I*bxcvx ENDIF ELSE BEGIN ; calculate in flux coordinates. @@ -1286,7 +1286,7 @@ retrybetacalc: bxcvx = bpsign*(Bpxy * Btxy*Rxy * DDY(1. / Bxy, mesh) / hthe) bxcvy = bpsign*(Bpxy*Btxy*Rxy*dpb / (hthe*Bxy^2)) - bxcvz = -dpb - sinty*bxcvx + bxcvz = -dpb - I*bxcvx ENDELSE @@ -1296,7 +1296,7 @@ retrybetacalc: ; Nonlinear smoothing. Tries to smooth only regions with large ; changes in gradient - bz = bxcvz + sinty * bxcvx + bz = bxcvz + I * bxcvx PRINT, "Smoothing bxcvx..." bxcvx = smooth_nl(bxcvx, mesh) @@ -1305,7 +1305,7 @@ retrybetacalc: PRINT, "Smoothing bxcvz..." bz = smooth_nl(bz, mesh) - bxcvz = bz - sinty * bxcvx + bxcvz = bz - I * bxcvx ENDIF ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; From d1902c53621bae5f223be03a2a5288fd0e4108a3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 18 Mar 2019 11:40:54 +0000 Subject: [PATCH 1085/1783] Hypnotoad: fix 'nnpol' update --- tools/tokamak_grids/gridgen/create_grid.pro | 6 +++--- tools/tokamak_grids/gridgen/create_nonorthogonal.pro | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_grid.pro b/tools/tokamak_grids/gridgen/create_grid.pro index a462bdfb86..4cfca27fe7 100644 --- a/tools/tokamak_grids/gridgen/create_grid.pro +++ b/tools/tokamak_grids/gridgen/create_grid.pro @@ -1458,9 +1458,9 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ PRINT, " => Increasing npol to "+ STR(npol) ENDIF - nnpol = npol + n_update = npol - 6*critical.n_xpoint ; Extra points to divide up npol = LONARR(3*critical.n_xpoint) + 2 - nnpol = nnpol - 6*critical.n_xpoint ; Extra points to divide up + nnpol = N_ELEMENTS(npol) ; Get lengths length = FLTARR(3*critical.n_xpoint) @@ -1472,7 +1472,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ length[2*critical.n_xpoint + i] = (*sol_info[i]).length ENDFOR - FOR i=0, nnpol-1 DO BEGIN + FOR i=0, n_update-1 DO BEGIN ; Add an extra point to the longest length dl = length / FLOAT(npol) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index b282227f40..7f95b5298d 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -1761,9 +1761,9 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ PRINT, " => Increasing npol to "+ STR(npol) ENDIF - nnpol = npol + n_update = npol - 6*critical.n_xpoint ; Extra points to divide up npol = LONARR(3*critical.n_xpoint) + 2 - nnpol = nnpol - 6*critical.n_xpoint ; Extra points to divide up + nnpol = N_ELEMENTS(npol) ; Get lengths length = FLTARR(3*critical.n_xpoint) @@ -1775,7 +1775,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ length[2*critical.n_xpoint + i] = (*sol_info[i]).length ENDFOR - FOR i=0, nnpol-1 DO BEGIN + FOR i=0, n_update-1 DO BEGIN ; Add an extra point to the longest length dl = length / FLOAT(npol) From 45fa5b3ad1729af42986b3613db3e91a8283cfda Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 10 Mar 2019 18:39:16 +0000 Subject: [PATCH 1086/1783] Hypnotoad: option to save boundary guard cells at the y-boundary Calculate and save values at user-chosen number of guard cells beyond the end of the grid at the divertor targets. Default value is 0 to ensure compatibility with older versions of BOUT++ that don't check the (newly added) 'y_boundary_guards' value in grid files. --- tools/tokamak_grids/gridgen/create_grid.pro | 201 +++++++++++---- .../gridgen/create_nonorthogonal.pro | 233 +++++++++++++----- .../gridgen/gen_surface_hypnotoad.pro | 6 +- tools/tokamak_grids/gridgen/hypnotoad.pro | 57 +++-- .../tokamak_grids/gridgen/leg_separatrix2.pro | 35 ++- tools/tokamak_grids/gridgen/process_grid.pro | 66 +++-- 6 files changed, 430 insertions(+), 168 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_grid.pro b/tools/tokamak_grids/gridgen/create_grid.pro index 4cfca27fe7..b94991018f 100644 --- a/tools/tokamak_grids/gridgen/create_grid.pro +++ b/tools/tokamak_grids/gridgen/create_grid.pro @@ -114,12 +114,37 @@ END FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parweight, $ ydown_dist=ydown_dist, yup_dist=yup_dist, $ - ydown_space=ydown_space, yup_space=yup_space + ydown_space=ydown_space, yup_space=yup_space, $ + y_boundary_guards=y_boundary_guards, $ + ydown_firstind=ydown_firstind, $ + yup_lastind=yup_lastind IF NOT KEYWORD_SET(parweight) THEN parweight = 0.0 ; Default is poloidal distance np = N_ELEMENTS(ri) + IF NOT KEYWORD_SET(y_boundary_guards) THEN y_boundary_guards = 0 + + IF NOT KEYWORD_SET(ydown_firstind) THEN BEGIN + ; Index of location of wall not given => no wall at ydown end + ; Default to starting at beginning of ri, zi arrays. + ydown_firstind = 0 + boundary_guards_ydown = 0 + ENDIF ELSE BEGIN + ; There is a wall at ydown + boundary_guards_ydown = y_boundary_guards + ENDELSE + + IF NOT KEYWORD_SET(yup_lastind) THEN BEGIN + ; Index of location of wall not given => no wall at yup end + ; Default to finishing at end of ri, zi arrays. + yup_lastind = np - 1 + boundary_guards_yup = 0 + ENDIF ELSE BEGIN + ; There is a wall at yup + boundary_guards_yup = y_boundary_guards + ENDELSE + IF 0 THEN BEGIN ; Calculate poloidal distance along starting line drdi = DERIV(INTERPOLATE(R, ri)) @@ -127,6 +152,9 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe dldi = SQRT(drdi^2 + dzdi^2) poldist = int_func(findgen(np), dldi, /simple) ; Poloidal distance along line + + ; reset poldist to start at zero at the ydown wall (if one is present) + poldist = poldist - poldist[ydown_firstind] ENDIF ELSE BEGIN rpos = INTERPOLATE(R, ri) zpos = INTERPOLATE(Z, zi) @@ -134,6 +162,9 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe dd = [dd, SQRT((zpos[0] - zpos[np-1])^2 + (rpos[0] - rpos[np-1])^2)] poldist = FLTARR(np) FOR i=1,np-1 DO poldist[i] = poldist[i-1] + dd[i-1] + + ; reset poldist to start at zero at the ydown wall (if one is present) + poldist = poldist - poldist[ydown_firstind] ENDELSE IF SIZE(fpsi, /n_dim) EQ 2 THEN BEGIN @@ -166,6 +197,9 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe ip = (i + 1) MOD np pardist[i] = pardist[i-1] + ddpar[i] ;0.5*(ddpar[i-1] + ddpar[ip]) ENDFOR + + ; reset pardist to start at zero at the ydown wall (if one is present) + pardist = pardist - pardist[ydown_firstind] ENDIF ELSE pardist = poldist ; Just use the same poloidal distance PRINT, "PARWEIGHT: ", parweight @@ -174,8 +208,10 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe ; Divide up distance. No points at the end (could be x-point) IF n GE 2 THEN BEGIN - IF SIZE(ydown_dist, /TYPE) EQ 0 THEN ydown_dist = dist[np-1]* 0.5 / FLOAT(n) - IF SIZE(yup_dist, /TYPE) EQ 0 THEN yup_dist = dist[np-1] * 0.5 / FLOAT(n) + ; note dist[ydown_firstind] should be 0., but include here anyway + total_dist = dist[yup_lastind] - dist[ydown_firstind] + IF SIZE(ydown_dist, /TYPE) EQ 0 THEN ydown_dist = total_dist * 0.5 / FLOAT(n) + IF SIZE(yup_dist, /TYPE) EQ 0 THEN yup_dist = total_dist * 0.5 / FLOAT(n) IF SIZE(ydown_space, /TYPE) EQ 0 THEN ydown_space = ydown_dist IF SIZE(yup_space, /TYPE) EQ 0 THEN yup_space = ydown_dist @@ -183,8 +219,11 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe fn = FLOAT(n-1) - d = (dist[np-1] - ydown_dist - yup_dist) ; Distance between first and last - i = FINDGEN(n) + d = (total_dist - ydown_dist - yup_dist) ; Distance between first and last + i = FINDGEN(n + boundary_guards_ydown + boundary_guards_yup) + + ; igrid starts at zero in the first grid cell (excludes boundary guard cells) + igrid = i - boundary_guards_ydown yd = ydown_space < 0.5*d/fn yu = yup_space < 0.5*d/fn @@ -192,8 +231,8 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe a = yd*2. b = (2.*yu - a) / fn c = d/fn - a - 0.5*b*fn - dloc = ydown_dist + a*i + 0.5*b*i^2 + c*[i - SIN(2.*!PI*i / fn)*fn/(2.*!PI)] - ddloc = a + b*i + c*[1 - COS(2.*!PI*i / fn)] + dloc = ydown_dist + a*igrid + 0.5*b*igrid^2 + c*[igrid - SIN(2.*!PI*igrid / fn)*fn/(2.*!PI)] + ddloc = a + b*igrid + c*[1 - COS(2.*!PI*igrid / fn)] ; Fit to dist = a*i^3 + b*i^2 + c*i ;c = ydown_dist*2. @@ -236,8 +275,21 @@ FUNCTION grid_region, interp_data, R, Z, $ fpsi=fpsi, $ ; f(psi) = R*Bt optional current function parweight=parweight, $ ; Space equally in parallel (1) or poloidal (0) distance ydown_dist=ydown_dist, yup_dist=yup_dist, $ - ydown_space=ydown_space, yup_space=yup_space + ydown_space=ydown_space, yup_space=yup_space, $ + y_boundary_guards=y_boundary_guards, $ ; number of guard cells at y-boundaries + ydown_firstind=ydown_firstind, $ ; if given, include y_boundary_guards before this point + yup_lastind=yup_lastind ; if given, include y_boundary_guards after this point + npar_total = npar + IF KEYWORD_SET(ydown_firstind) THEN BEGIN + ; add boundary guard cells at ydown + npar_total = npar_total + y_boundary_guards + ENDIF + IF KEYWORD_SET(yup_lastind) THEN BEGIN + ; add boundary guard cells at yup + npar_total = npar_total + y_boundary_guards + ENDIF + nsurf = N_ELEMENTS(fvals) IF sind GE 0 THEN BEGIN @@ -271,7 +323,10 @@ FUNCTION grid_region, interp_data, R, Z, $ ind = poloidal_grid(interp_data, R, Z, ri, zi, npar, fpsi=fpsi, $ ydown_dist=ydown_dist, yup_dist=yup_dist, $ ydown_space=ydown_space, yup_space=yup_space, $ - parweight=parweight) + parweight=parweight, $ + y_boundary_guards=y_boundary_guards, $ + ydown_firstind=ydown_firstind, $ + yup_lastind=yup_lastind) rii = INTERPOLATE(ri, ind) zii = INTERPOLATE(zi, ind) @@ -281,7 +336,7 @@ FUNCTION grid_region, interp_data, R, Z, $ ;STOP ; Refine the location of the starting point - FOR i=0, npar-1 DO BEGIN + FOR i=0, npar_total-1 DO BEGIN follow_gradient, interp_data, R, Z, rii[i], zii[i], f0, ri1, zi1 rii[i] = ri1 zii[i] = zi1 @@ -289,9 +344,9 @@ FUNCTION grid_region, interp_data, R, Z, $ ; From each starting point, follow gradient in both directions - rixy = FLTARR(nsurf, npar) - zixy = FLTARR(nsurf, npar) - FOR i=0, npar-1 DO BEGIN + rixy = FLTARR(nsurf, npar_total) + zixy = FLTARR(nsurf, npar_total) + FOR i=0, npar_total-1 DO BEGIN IF sind GE 0 THEN BEGIN rixy[nin, i] = rii[i] zixy[nin, i] = zii[i] @@ -649,7 +704,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ nrad_flexible=nrad_flexible, $ single_rad_grid=single_rad_grid, fast=fast, $ xpt_mindist=xpt_mindist, xpt_mul=xpt_mul, $ - simple=simple + simple=simple, y_boundary_guards=y_boundary_guards IF SIZE(nrad_flexible, /TYPE) EQ 0 THEN nrad_flexible = 0 @@ -1286,7 +1341,8 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ rad_peaking:settings.rad_peaking, pol_peaking:settings.pol_peaking} RETURN, create_grid(F, R, Z, new_settings, critical=critical, $ boundary=boundary, iter=iter+1, nrad_flexible=nrad_flexible, $ - single_rad_grid=single_rad_grid, fast=fast, simple=simple) + single_rad_grid=single_rad_grid, fast=fast, simple=simple, $ + y_boundary_guards=y_boundary_guards) ENDIF dpsi = sol_psi_vals[i,TOTAL(nrad,/int)-nsol-1] - sol_psi_vals[i,TOTAL(nrad,/int)-nsol-2] sol_psi_vals[i,(TOTAL(nrad,/int)-nsol):*] = radial_grid(nsol, $ @@ -1361,6 +1417,10 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ pf_ri = [REVERSE(legsep.leg1[*,0]), xpt_ri[i], legsep.leg2[*,0]] pf_zi = [REVERSE(legsep.leg1[*,1]), xpt_zi[i], legsep.leg2[*,1]] mini = N_ELEMENTS(legsep.leg1[*,0]) + ; need to take account of reversing leg1 in calculating pf_wallind1 + pf_wallind1 = mini - 1 - legsep.leg1_lastind + ; need to take account of extra array elements before leg2 + pf_wallind2 = mini + 1 + legsep.leg2_lastind ; Use the tangent vector to determine direction ; relative to core and so get direction of positive theta @@ -1373,15 +1433,23 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ pf_ri = REVERSE(pf_ri) pf_zi = REVERSE(pf_zi) mini = N_ELEMENTS(pf_ri) - 1. - mini + temp = N_ELEMENTS(pf_ri) - 1 - pf_wallind2 + pf_wallind2 = N_ELEMENTS(pf_ri) - 1 - pf_wallind1 + pf_wallind1 = temp ; Structure for x-point grid spacing info - xpt_sep = {leg1_ri:[xpt_ri[i], legsep.leg2[*,0]], leg1_zi:[xpt_zi[i], legsep.leg2[*,1]], $ - leg2_ri:[xpt_ri[i], legsep.leg1[*,0]], leg2_zi:[xpt_zi[i], legsep.leg1[*,1]], $ + ; don't keep boundary points here, this structure will only be used for + ; calculating the lengths of divertor legs + xpt_sep = {leg1_ri:[xpt_ri[i], legsep.leg2[0:legsep.leg2_lastind,0]], leg1_zi:[xpt_zi[i], legsep.leg2[0:legsep.leg2_lastind,1]], $ + leg2_ri:[xpt_ri[i], legsep.leg1[0:legsep.leg1_lastind,0]], leg2_zi:[xpt_zi[i], legsep.leg1[0:legsep.leg1_lastind,1]], $ core1_ri:[xpt_ri[i], legsep.core2[*,0]], core1_zi:[xpt_zi[i], legsep.core2[*,1]], $ core2_ri:[xpt_ri[i], legsep.core1[*,0]], core2_zi:[xpt_zi[i], legsep.core1[*,1]]} ENDIF ELSE BEGIN - xpt_sep = {leg1_ri:[xpt_ri[i], legsep.leg1[*,0]], leg1_zi:[xpt_zi[i], legsep.leg1[*,1]], $ - leg2_ri:[xpt_ri[i], legsep.leg2[*,0]], leg2_zi:[xpt_zi[i], legsep.leg2[*,1]], $ + ; Structure for x-point grid spacing info + ; don't keep boundary points here, this structure will only be used for + ; calculating the lengths of divertor legs + xpt_sep = {leg1_ri:[xpt_ri[i], legsep.leg1[0:legsep.leg1_lastind,0]], leg1_zi:[xpt_zi[i], legsep.leg1[0:legsep.leg1_lastind,1]], $ + leg2_ri:[xpt_ri[i], legsep.leg2[0:legsep.leg2_lastind,0]], leg2_zi:[xpt_zi[i], legsep.leg2[0:legsep.leg2_lastind,1]], $ core1_ri:[xpt_ri[i], legsep.core1[*,0]], core1_zi:[xpt_zi[i], legsep.core1[*,1]], $ core2_ri:[xpt_ri[i], legsep.core2[*,0]], core2_zi:[xpt_zi[i], legsep.core2[*,1]]} ENDELSE @@ -1414,17 +1482,19 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ 'npf', npf, $ ; Number of radial points in this PF region 'ri0', [pf_ri[0:mini], INTERPOLATE(pf_ri, mini)], $ 'zi0', [pf_zi[0:mini], INTERPOLATE(pf_zi, mini)], $ + 'wallind0', pf_wallind1, $ 'ri1', [INTERPOLATE(pf_ri, mini), pf_ri[(mini+1):*]], $ - 'zi1', [INTERPOLATE(pf_zi, mini), pf_zi[(mini+1):*]]) + 'zi1', [INTERPOLATE(pf_zi, mini), pf_zi[(mini+1):*]], $ + 'wallind1', pf_wallind2 - mini) ; Calculate length of each section - dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri0))^2 + DERIV(INTERPOLATE(Z, tmp.zi0))^2) + dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri0[tmp.wallind0:*]))^2 + DERIV(INTERPOLATE(Z, tmp.zi0[tmp.wallind0:*]))^2) IF KEYWORD_SET(simple) THEN BEGIN len0 = INT_TRAPEZOID(FINDGEN(N_ELEMENTS(dldi)), dldi) ENDIF ELSE BEGIN len0 = INT_TABULATED(FINDGEN(N_ELEMENTS(dldi)), dldi) ENDELSE - dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri1))^2 + DERIV(INTERPOLATE(Z, tmp.zi1))^2) + dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri1[0:tmp.wallind1]))^2 + DERIV(INTERPOLATE(Z, tmp.zi1[0:tmp.wallind1]))^2) IF KEYWORD_SET(simple) THEN BEGIN len1 = INT_TRAPEZOID(FINDGEN(N_ELEMENTS(dldi)), dldi) ENDIF ELSE BEGIN @@ -1443,9 +1513,21 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ npol = settings.npol nnpol = N_ELEMENTS(npol) - IF nnpol EQ 1 THEN npol = npol[0] + n_y_boundary_guards = LONARR(nnpol) + IF nnpol EQ 1 THEN BEGIN + npol = npol[0] + ; single poloidal domain, not in the core, so must have a boundary at both ends + ; => total number of boundary guard cells is 2*y_boundary_guards + n_y_boundary_guards = 2*y_boundary_guards + ENDIF - IF nnpol NE 3*critical.n_xpoint THEN BEGIN + IF nnpol EQ 3*critical.n_xpoint THEN BEGIN + ; Get number of y-boundary guard cells where necessary + FOR i=0, critical.n_xpoint-1 DO BEGIN + n_y_boundary_guards[3*i] = y_boundary_guards ; PF part 0 + n_y_boundary_guards[3*i+2] = y_boundary_guards ; PF part 1 + ENDFOR + ENDIF ELSE BEGIN IF nnpol GT 1 THEN BEGIN PRINT, "WARNING: npol has wrong number of elements ("+STR(nnpol)+")" PRINT, " Should have 1 or "+STR(3*critical.n_xpoint)+" elements" @@ -1461,6 +1543,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ n_update = npol - 6*critical.n_xpoint ; Extra points to divide up npol = LONARR(3*critical.n_xpoint) + 2 nnpol = N_ELEMENTS(npol) + n_y_boundary_guards = LONARR(3*critical.n_xpoint) ; Get lengths length = FLTARR(3*critical.n_xpoint) @@ -1490,6 +1573,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ xpt = si[0] ; X-point index to start with FOR i=0, critical.n_xpoint-1 DO BEGIN npol2[3*i] = npol[xpt] ; PF part 0 + n_y_boundary_guards[3*i] = y_boundary_guards ; PF part 0 ; Get the SOL ID solid = (*pf_info[xpt]).sol[0] @@ -1502,10 +1586,13 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; Get the next x-point xpt = (*sol_info[solid]).xpt2 npol2[3*i+2] = npol[critical.n_xpoint + xpt] ; PF part 1 + n_y_boundary_guards[3*i+2] = y_boundary_guards ; PF part 1 ENDFOR npol = npol2 - ENDIF + ENDELSE + + npol_total = TOTAL(npol+n_y_boundary_guards,/int) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Poloidal spacing. Need to ensure regular spacing @@ -1520,7 +1607,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; For the lower x-point, ; 0 = inner leg, 1 = inner SOL, 2 = outer sol, 3 = outer leg ; For the upper x-point (if any) - ; 0 = outer leg, 1 = outer sol, 2 = iner sol, 3 = inner leg + ; 0 = outer leg, 1 = outer sol, 2 = inner sol, 3 = inner leg FOR i=0, critical.n_xpoint-1 DO BEGIN ; Grid the lower PF region @@ -1532,7 +1619,8 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; lower inner leg. ; - If xpt is the upper x-point then this is the upper outer leg - poldist = line_dist(R, Z, (*pf_info[xpt]).ri0, (*pf_info[xpt]).zi0) ; Poloidal distance along line + wallind = (*pf_info[xpt]).wallind0 + poldist = line_dist(R, Z, (*pf_info[xpt]).ri0[wallind:*], (*pf_info[xpt]).zi0[wallind:*]) ; Poloidal distance along line xdist = MAX(poldist) * 0.5 / FLOAT(npol[3*i]) ; Equal spacing xpt_dist[xpt, 0] = xdist @@ -1553,7 +1641,8 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; Second PF region xpt = xpt2 - poldist = line_dist(R, Z, (*pf_info[xpt]).ri1, (*pf_info[xpt]).zi1) + wallind = (*pf_info[xpt]).wallind1 + poldist = line_dist(R, Z, (*pf_info[xpt]).ri1[0:wallind], (*pf_info[xpt]).zi1[0:wallind]) xdist = MAX(poldist) * 0.5 / FLOAT(npol[3*i+2]) xpt_dist[xpt, 3] = xdist @@ -1664,7 +1753,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ENDIF ; Create 2D arrays for the grid - Rxy = FLTARR(TOTAL(nrad,/int), TOTAL(npol,/int)) + Rxy = FLTARR(TOTAL(nrad,/int), npol_total) Zxy = Rxy Rixy = Rxy Zixy = Rxy @@ -1696,13 +1785,15 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ sfirst=sfirst1, $ slast=slast1, $ boundary=gridbndry, $ - ffirst=ffirst, flast=flast1, fpsi=fpsi, yup_dist=xpt_dist[xpt, 0], /oplot) - Rxy[*, ypos:(ypos+npol[3*i]-1)] = a.Rxy - Zxy[*, ypos:(ypos+npol[3*i]-1)] = a.Zxy - Rixy[*, ypos:(ypos+npol[3*i]-1)] = a.Rixy - Zixy[*, ypos:(ypos+npol[3*i]-1)] = a.Zixy - FOR j=ypos, ypos+npol[3*i]-1 DO Psixy[*, j] = pf_psi_vals[xpt,0,*] - ypos = ypos + npol[3*i] + ffirst=ffirst, flast=flast1, fpsi=fpsi, yup_dist=xpt_dist[xpt, 0], /oplot, $ + y_boundary_guards=y_boundary_guards, $ + ydown_firstind=(*pf_info[xpt]).wallind0) + Rxy[*, ypos:(ypos+npol[3*i]+n_y_boundary_guards[3*i]-1)] = a.Rxy + Zxy[*, ypos:(ypos+npol[3*i]+n_y_boundary_guards[3*i]-1)] = a.Zxy + Rixy[*, ypos:(ypos+npol[3*i]+n_y_boundary_guards[3*i]-1)] = a.Rixy + Zixy[*, ypos:(ypos+npol[3*i]+n_y_boundary_guards[3*i]-1)] = a.Zixy + FOR j=ypos, ypos+npol[3*i]+n_y_boundary_guards[3*i]-1 DO Psixy[*, j] = pf_psi_vals[xpt,0,*] + ypos = ypos + npol[3*i]+n_y_boundary_guards[3*i] ; Set topology ydown_xsplit[3*i] = (*pf_info[xpt]).npf @@ -1770,12 +1861,12 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ydown_dist=ydown_dist, yup_dist=yup_dist, $ ydown_space=ydown_space, yup_space=yup_space, /oplot) - Rxy[*, ypos:(ypos+npol[3*i+1]-1)] = a.Rxy - Zxy[*, ypos:(ypos+npol[3*i+1]-1)] = a.Zxy - Rixy[*, ypos:(ypos+npol[3*i+1]-1)] = a.Rixy - Zixy[*, ypos:(ypos+npol[3*i+1]-1)] = a.Zixy - FOR j=ypos, ypos+npol[3*i+1]-1 DO Psixy[*, j] = sol_psi_vals[solid,*] - ypos = ypos + npol[3*i+1] + Rxy[*, ypos:(ypos+npol[3*i+1]+n_y_boundary_guards[3*i+1]-1)] = a.Rxy + Zxy[*, ypos:(ypos+npol[3*i+1]+n_y_boundary_guards[3*i+1]-1)] = a.Zxy + Rixy[*, ypos:(ypos+npol[3*i+1]+n_y_boundary_guards[3*i+1]-1)] = a.Rixy + Zixy[*, ypos:(ypos+npol[3*i+1]+n_y_boundary_guards[3*i+1]-1)] = a.Zixy + FOR j=ypos, ypos+npol[3*i+1]+n_y_boundary_guards[3*i+1]-1 DO Psixy[*, j] = sol_psi_vals[solid,*] + ypos = ypos + npol[3*i+1]+n_y_boundary_guards[3*i+1] ydown_xsplit[3*i+1] = (*pf_info[xpt]).npf yup_xsplit[3*i+1] = (*pf_info[(*sol_info[solid]).xpt2]).npf @@ -1813,13 +1904,15 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ slast=slast3, $ boundary=gridbndry, $ ffirst=ffirst, flast=flast3, fpsi=fpsi, $ - ydown_dist=xpt_dist[xpt, 3], /oplot) - Rxy[*, ypos:(ypos+npol[3*i+2]-1)] = a.Rxy - Zxy[*, ypos:(ypos+npol[3*i+2]-1)] = a.Zxy - Rixy[*, ypos:(ypos+npol[3*i+2]-1)] = a.Rixy - Zixy[*, ypos:(ypos+npol[3*i+2]-1)] = a.Zixy - FOR j=ypos, ypos+npol[3*i+2]-1 DO Psixy[*, j] = pf_psi_vals[xpt,1,*] - ypos = ypos + npol[3*i+2] + ydown_dist=xpt_dist[xpt, 3], /oplot, $ + y_boundary_guards=y_boundary_guards, $ + yup_lastind=(*pf_info[xpt]).wallind1) + Rxy[*, ypos:(ypos+npol[3*i+2]+n_y_boundary_guards[3*i+2]-1)] = a.Rxy + Zxy[*, ypos:(ypos+npol[3*i+2]+n_y_boundary_guards[3*i+2]-1)] = a.Zxy + Rixy[*, ypos:(ypos+npol[3*i+2]+n_y_boundary_guards[3*i+2]-1)] = a.Rixy + Zixy[*, ypos:(ypos+npol[3*i+2]+n_y_boundary_guards[3*i+2]-1)] = a.Zixy + FOR j=ypos, ypos+npol[3*i+2]+n_y_boundary_guards[3*i+2]-1 DO Psixy[*, j] = pf_psi_vals[xpt,1,*] + ypos = ypos + npol[3*i+2]+n_y_boundary_guards[3*i+2] ; Set topology ydown_xsplit[3*i+2] = (*pf_info[xpt]).npf @@ -1894,7 +1987,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ boundary=boundary, strictbndry=strictbndry, $ iter=iter+1, nrad_flexible=nrad_flexible, $ single_rad_grid=single_rad_grid, fast=fast, $ - simple=simple) + simple=simple, y_boundary_guards=y_boundary_guards) ENDIF @@ -1905,13 +1998,13 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ rad_peaking:settings.rad_peaking, pol_peaking:settings.pol_peaking} ; Calculate magnetic field components - dpsidR = FLTARR(TOTAL(nrad, /int), TOTAL(npol, /int)) + dpsidR = FLTARR(TOTAL(nrad, /int), npol_total) dpsidZ = dpsidR interp_data.method = 2 FOR i=0,TOTAL(nrad,/int)-1 DO BEGIN - FOR j=0,TOTAL(npol,/int)-1 DO BEGIN + FOR j=0,npol_total-1 DO BEGIN local_gradient, interp_data, Rixy[i,j], Zixy[i,j], status=status, $ dfdr=dfdr, dfdz=dfdz ; dfd* are derivatives wrt the indices. Need to multiply by dr/di etc @@ -1922,7 +2015,9 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ result = {error:0, $ ; Signals success psi_inner:psi_inner, psi_outer:psi_outer, $ ; Range of psi - nrad:nrad, npol:npol, $ ; Number of points in each domain + nrad:nrad, npol:npol, $ ; Number of points in each domain + n_y_boundary_guards:n_y_boundary_guards, $ ; Number of y-boundary cells in each domain + y_boundary_guards:y_boundary_guards, $ ; Number of boundary cells included at y-boundaries Rixy:Rixy, Zixy:Zixy, $ ; Indices into R and Z of each point Rxy:Rxy, Zxy:Zxy, $ ; Location of each grid point psixy:psixy, $ ; Normalised psi for each point diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index 7f95b5298d..20013c0229 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -153,12 +153,37 @@ END FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parweight, $ ydown_dist=ydown_dist, yup_dist=yup_dist, $ ydown_space=ydown_space, yup_space=yup_space, $ - sp_loc=sp_loc + sp_loc=sp_loc, $ + y_boundary_guards=y_boundary_guards, $ + ydown_firstind=ydown_firstind, $ + yup_lastind=yup_lastind IF NOT KEYWORD_SET(parweight) THEN parweight = 0.0 ; Default is poloidal distance np = N_ELEMENTS(ri) + IF NOT KEYWORD_SET(y_boundary_guards) THEN y_boundary_guards = 0 + + IF NOT KEYWORD_SET(ydown_firstind) THEN BEGIN + ; Index of location of wall not given => no wall at ydown end + ; Default to starting at beginning of ri, zi arrays. + ydown_firstind = 0 + boundary_guards_ydown = 0 + ENDIF ELSE BEGIN + ; There is a wall at ydown + boundary_guards_ydown = y_boundary_guards + ENDELSE + + IF NOT KEYWORD_SET(yup_lastind) THEN BEGIN + ; Index of location of wall not given => no wall at yup end + ; Default to finishing at end of ri, zi arrays. + yup_lastind = np - 1 + boundary_guards_yup = 0 + ENDIF ELSE BEGIN + ; There is a wall at yup + boundary_guards_yup = y_boundary_guards + ENDELSE + IF 0 THEN BEGIN ; Always false ; Calculate poloidal distance along starting line drdi = DERIV(INTERPOLATE(R, ri)) @@ -166,6 +191,9 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe dldi = SQRT(drdi^2 + dzdi^2) poldist = int_func(findgen(np), dldi, /simple) ; Poloidal distance along line + + ; reset poldist to start at zero at the ydown wall (if one is present) + poldist = poldist - poldist[ydown_firstind] ENDIF ELSE BEGIN rpos = INTERPOLATE(R, ri) zpos = INTERPOLATE(Z, zi) @@ -173,6 +201,9 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe dd = [dd, SQRT((zpos[0] - zpos[np-1])^2 + (rpos[0] - rpos[np-1])^2)] poldist = FLTARR(np) FOR i=1,np-1 DO poldist[i] = poldist[i-1] + dd[i-1] + + ; reset poldist to start at zero at the ydown wall (if one is present) + poldist = poldist - poldist[ydown_firstind] ENDELSE IF SIZE(fpsi, /n_dim) EQ 2 THEN BEGIN @@ -205,6 +236,9 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe ip = (i + 1) MOD np pardist[i] = pardist[i-1] + ddpar[i] ;0.5*(ddpar[i-1] + ddpar[ip]) ENDFOR + + ; reset pardist to start at zero at the ydown wall (if one is present) + pardist = pardist - pardist[ydown_firstind] ENDIF ELSE pardist = poldist ; Just use the same poloidal distance PRINT, "PARWEIGHT: ", parweight @@ -213,8 +247,10 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe ; Divide up distance. No points at the end (could be x-point) IF n GE 2 THEN BEGIN - IF SIZE(ydown_dist, /TYPE) EQ 0 THEN ydown_dist = dist[np-1]* 0.5 / FLOAT(n) - IF SIZE(yup_dist, /TYPE) EQ 0 THEN yup_dist = dist[np-1] * 0.5 / FLOAT(n) + ; note dist[ydown_firstind] should be 0., but include here anyway + total_dist = dist[yup_lastind] - dist[ydown_firstind] + IF SIZE(ydown_dist, /TYPE) EQ 0 THEN ydown_dist = total_dist * 0.5 / FLOAT(n) + IF SIZE(yup_dist, /TYPE) EQ 0 THEN yup_dist = total_dist * 0.5 / FLOAT(n) IF SIZE(ydown_space, /TYPE) EQ 0 THEN BEGIN IF ydown_dist LT 1e-5 THEN BEGIN @@ -230,8 +266,11 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe ;dloc = (dist[np-1] - ydown_dist - yup_dist) * FINDGEN(n)/FLOAT(n-1) + ydown_dist ; Distance locations fn = FLOAT(n-1) - d = (dist[np-1] - ydown_dist - yup_dist) ; Distance between first and last - i = FINDGEN(n) + d = (total_dist - ydown_dist - yup_dist) ; Distance between first and last + i = FINDGEN(n + boundary_guards_ydown + boundary_guards_yup) + + ; igrid starts at zero in the first grid cell (excludes boundary guard cells) + igrid = i - boundary_guards_ydown yd = ydown_space < 0.5*d/fn yu = yup_space < 0.5*d/fn @@ -239,8 +278,9 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe a = yd*2. b = (2.*yu - a) / fn c = d/fn - a - 0.5*b*fn - dloc = ydown_dist + a*i + 0.5*b*i^2 + c*[i - SIN(2.*!PI*i / fn)*fn/(2.*!PI)] - ddloc = a + b*i + c*[1 - COS(2.*!PI*i / fn)] + dloc = ydown_dist + a*igrid + 0.5*b*igrid^2 + c*[igrid - SIN(2.*!PI*igrid / fn)*fn/(2.*!PI)] + ddloc = a + b*igrid + c*[1 - COS(2.*!PI*igrid / fn)] + ; Fit to dist = a*i^3 + b*i^2 + c*i ;; c = ydown_dist*2. @@ -289,9 +329,21 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ vec_in_up=vec_in_up, vec_out_up=vec_out_up, $ ; sep_up=sep_up, sep_line_up=sep_line_up, $ ; sp_loc=sp_loc, orthdown=orthdown, orthup=orthup, $ - nonorthogonal_weight_decay_power=nonorthogonal_weight_decay_power - + nonorthogonal_weight_decay_power=nonorthogonal_weight_decay_power, $ + y_boundary_guards=y_boundary_guards, $ ; number of guard cells at y-boundaries + ydown_firstind=ydown_firstind, $ ; if given, include y_boundary_guards before this point + yup_lastind=yup_lastind ; if given, include y_boundary_guards after this point + IF KEYWORD_SET(ydown_firstind) THEN BEGIN + ; add boundary guard cells at ydown + nguards_ydown = y_boundary_guards + ENDIF ELSE nguards_ydown = 0 + IF KEYWORD_SET(yup_lastind) THEN BEGIN + ; add boundary guard cells at yup + nguards_yup = y_boundary_guards + ENDIF ELSE nguards_yup = 0 + npar_total = npar + nguards_ydown + nguards_yup + nsurf = N_ELEMENTS(fvals) IF sind GE 0 THEN BEGIN @@ -329,7 +381,10 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ind = poloidal_grid(interp_data, R, Z, ri, zi, npar, fpsi=fpsi, $ ydown_dist=ydown_dist, yup_dist=yup_dist, $ ydown_space=ydown_space, yup_space=yup_space, $ - parweight=parweight) + parweight=parweight, $ + y_boundary_guards=y_boundary_guards, $ + ydown_firstind=ydown_firstind, $ + yup_lastind=yup_lastind) rii = INTERPOLATE(ri, ind) zii = INTERPOLATE(zi, ind) @@ -339,7 +394,7 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ;STOP ; Refine the location of the starting point - ;FOR i=0, npar-1 DO BEGIN + ;FOR i=0, npar_total-1 DO BEGIN ; follow_gradient_nonorth, interp_data, R, Z, rii[i], zii[i], f0, ri1, zi1 ; rii[i] = ri1 ; zii[i] = zi1 @@ -347,11 +402,15 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ; From each starting point, follow gradient in both directions - rixy = FLTARR(nsurf, npar) - zixy = FLTARR(nsurf, npar) - FOR i=0, npar-1 DO BEGIN + rixy = FLTARR(nsurf, npar_total) + zixy = FLTARR(nsurf, npar_total) + FOR i=0, npar_total-1 DO BEGIN + + ; igrid is the index starting from zero on the first grid point after any + ; guard cells + igrid = i - nguards_ydown - IF i GE npar/2 THEN BEGIN + IF igrid GE npar/2 THEN BEGIN IF KEYWORD_SET(sep_up) THEN BEGIN sep = sep_up ENDIF ELSE sep = fvals[nin] @@ -375,12 +434,17 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ENDIF ELSE sep_line = FLTARR(2,2) ENDELSE + ; 0 <= iweight <= npar-1 + iweight = igrid + IF iweight LT 0 THEN iweight = 0 + IF iweight GT npar - 1 THEN iweight = npar - 1 + IF NOT KEYWORD_SET(nonorthogonal_weight_decay_power) THEN nonorthogonal_weight_decay_power = 0 IF NOT KEYWORD_SET(orthup) THEN orthup=0 - IF orthup EQ 1 THEN weight_up = 0 ELSE weight_up = (i/(npar-1.))^nonorthogonal_weight_decay_power + IF orthup EQ 1 THEN weight_up = 0 ELSE weight_up = (iweight/(npar-1.))^nonorthogonal_weight_decay_power IF NOT KEYWORD_SET(orthdown) THEN orthdown=0 - IF orthdown EQ 1 THEN weight_down = 0 ELSE weight_down = (1.-i/(npar-1.))^nonorthogonal_weight_decay_power + IF orthdown EQ 1 THEN weight_down = 0 ELSE weight_down = (1.-iweight/(npar-1.))^nonorthogonal_weight_decay_power ; Refine the location of the starting point follow_gradient_nonorth, interp_data, R, Z, rii[i], zii[i], f0, ri1, zi1, $ @@ -843,7 +907,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ nrad_flexible=nrad_flexible, $ single_rad_grid=single_rad_grid, fast=fast, $ xpt_mindist=xpt_mindist, xpt_mul=xpt_mul, xpt_only=xpt_only, $ - simple = simple + simple=simple, y_boundary_guards=y_boundary_guards strictbndry=0 @@ -1356,8 +1420,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ;; set nflux_* here to the minimum of the number of points in the leg and core ;; lines, because we need elements from both at each step when we loop below - nflux_leg1 = min([n_elements(legsep.leg1[*,0]), n_elements(legsep.core2[*,0])]) - nflux_leg2 = min([n_elements(legsep.leg2[*,0]), n_elements(legsep.core1[*,0])]) + nflux_leg1 = min([n_elements(legsep.leg1[0:legsep.leg1_lastind,0]), n_elements(legsep.core2[*,0])]) + nflux_leg2 = min([n_elements(legsep.leg2[0:legsep.leg2_lastind,0]), n_elements(legsep.core1[*,0])]) meanr1 = fltarr(nflux_leg1) meanz1 = fltarr(nflux_leg1) @@ -1590,7 +1654,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ rad_peaking:settings.rad_peaking, pol_peaking:settings.pol_peaking} RETURN, create_nonorthogonal(F, R, Z, new_settings, critical=critical, $ boundary=boundary, iter=iter+1, nrad_flexible=nrad_flexible, $ - single_rad_grid=single_rad_grid, fast=fast, simple=simple) + single_rad_grid=single_rad_grid, fast=fast, simple=simple, $ + y_boundary_guards=y_boundary_guards) ENDIF dpsi = sol_psi_vals[i,TOTAL(nrad,/int)-nsol-1] - sol_psi_vals[i,TOTAL(nrad,/int)-nsol-2] sol_psi_vals[i,(TOTAL(nrad,/int)-nsol):*] = radial_grid(nsol, $ @@ -1664,6 +1729,10 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ pf_ri = [REVERSE(legsep.leg1[*,0]), xpt_ri[i], legsep.leg2[*,0]] pf_zi = [REVERSE(legsep.leg1[*,1]), xpt_zi[i], legsep.leg2[*,1]] mini = N_ELEMENTS(legsep.leg1[*,0]) + ; need to take account of reversing leg1 in calculating pf_wallind1 + pf_wallind1 = mini - 1 - legsep.leg1_lastind + ; need to take account of extra array elements before leg2 + pf_wallind2 = mini + 1 + legsep.leg2_lastind ; Use the tangent vector to determine direction ; relative to core and so get direction of positive theta @@ -1676,15 +1745,23 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ pf_ri = REVERSE(pf_ri) pf_zi = REVERSE(pf_zi) mini = N_ELEMENTS(pf_ri) - 1. - mini + temp = N_ELEMENTS(pf_ri) - 1 - pf_wallind2 + pf_wallind2 = N_ELEMENTS(pf_ri) - 1 - pf_wallind1 + pf_wallind1 = temp ; Structure for x-point grid spacing info - xpt_sep = {leg1_ri:[xpt_ri[i], legsep.leg2[*,0]], leg1_zi:[xpt_zi[i], legsep.leg2[*,1]], $ - leg2_ri:[xpt_ri[i], legsep.leg1[*,0]], leg2_zi:[xpt_zi[i], legsep.leg1[*,1]], $ + ; don't keep boundary points here, this structure will only be used for + ; calculating the lengths of divertor legs + xpt_sep = {leg1_ri:[xpt_ri[i], legsep.leg2[0:legsep.leg2_lastind,0]], leg1_zi:[xpt_zi[i], legsep.leg2[0:legsep.leg2_lastind,1]], $ + leg2_ri:[xpt_ri[i], legsep.leg1[0:legsep.leg1_lastind,0]], leg2_zi:[xpt_zi[i], legsep.leg1[0:legsep.leg1_lastind,1]], $ core1_ri:[xpt_ri[i], legsep.core2[*,0]], core1_zi:[xpt_zi[i], legsep.core2[*,1]], $ core2_ri:[xpt_ri[i], legsep.core1[*,0]], core2_zi:[xpt_zi[i], legsep.core1[*,1]]} ENDIF ELSE BEGIN - xpt_sep = {leg1_ri:[xpt_ri[i], legsep.leg1[*,0]], leg1_zi:[xpt_zi[i], legsep.leg1[*,1]], $ - leg2_ri:[xpt_ri[i], legsep.leg2[*,0]], leg2_zi:[xpt_zi[i], legsep.leg2[*,1]], $ + ; Structure for x-point grid spacing info + ; don't keep boundary points here, this structure will only be used for + ; calculating the lengths of divertor legs + xpt_sep = {leg1_ri:[xpt_ri[i], legsep.leg1[0:legsep.leg1_lastind,0]], leg1_zi:[xpt_zi[i], legsep.leg1[0:legsep.leg1_lastind,1]], $ + leg2_ri:[xpt_ri[i], legsep.leg2[0:legsep.leg2_lastind,0]], leg2_zi:[xpt_zi[i], legsep.leg2[0:legsep.leg2_lastind,1]], $ core1_ri:[xpt_ri[i], legsep.core1[*,0]], core1_zi:[xpt_zi[i], legsep.core1[*,1]], $ core2_ri:[xpt_ri[i], legsep.core2[*,0]], core2_zi:[xpt_zi[i], legsep.core2[*,1]]} ENDELSE @@ -1717,17 +1794,19 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ 'npf', npf, $ ; Number of radial points in this PF region 'ri0', [pf_ri[0:mini], INTERPOLATE(pf_ri, mini)], $ 'zi0', [pf_zi[0:mini], INTERPOLATE(pf_zi, mini)], $ + 'wallind0', pf_wallind1, $ 'ri1', [INTERPOLATE(pf_ri, mini), pf_ri[(mini+1):*]], $ - 'zi1', [INTERPOLATE(pf_zi, mini), pf_zi[(mini+1):*]]) + 'zi1', [INTERPOLATE(pf_zi, mini), pf_zi[(mini+1):*]], $ + 'wallind1', pf_wallind2 - mini) ; Calculate length of each section - dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri0))^2 + DERIV(INTERPOLATE(Z, tmp.zi0))^2) + dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri0[tmp.wallind0:*]))^2 + DERIV(INTERPOLATE(Z, tmp.zi0[tmp.wallind0:*]))^2) IF KEYWORD_SET(simple) THEN BEGIN len0 = INT_TRAPEZOID(FINDGEN(N_ELEMENTS(dldi)), dldi) ENDIF ELSE BEGIN len0 = INT_TABULATED(FINDGEN(N_ELEMENTS(dldi)), dldi) ENDELSE - dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri1))^2 + DERIV(INTERPOLATE(Z, tmp.zi1))^2) + dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri1[0:tmp.wallind1]))^2 + DERIV(INTERPOLATE(Z, tmp.zi1[0:tmp.wallind1]))^2) IF KEYWORD_SET(simple) THEN BEGIN len1 = INT_TRAPEZOID(FINDGEN(N_ELEMENTS(dldi)), dldi) ENDIF ELSE BEGIN @@ -1746,9 +1825,19 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ npol = settings.npol nnpol = N_ELEMENTS(npol) - IF nnpol EQ 1 THEN npol = npol[0] + n_y_boundary_guards = LONARR(nnpol) + IF nnpol EQ 1 THEN BEGIN + npol = npol[0] + n_y_boundary_guards = 2*y_boundary_guards + ENDIF - IF nnpol NE 3*critical.n_xpoint THEN BEGIN + IF nnpol EQ 3*critical.n_xpoint THEN BEGIN + ; Get number of y-boundary guard cells where necessary + FOR i=0, critical.n_xpoint-1 DO BEGIN + n_y_boundary_guards[3*i] = y_boundary_guards ; PF part 0 + n_y_boundary_guards[3*i+2] = y_boundary_guards ; PF part 1 + ENDFOR + ENDIF ELSE BEGIN IF nnpol GT 1 THEN BEGIN PRINT, "WARNING: npol has wrong number of elements ("+STR(nnpol)+")" PRINT, " Should have 1 or "+STR(3*critical.n_xpoint)+" elements" @@ -1764,6 +1853,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ n_update = npol - 6*critical.n_xpoint ; Extra points to divide up npol = LONARR(3*critical.n_xpoint) + 2 nnpol = N_ELEMENTS(npol) + n_y_boundary_guards = LONARR(3*critical.n_xpoint) ; Get lengths length = FLTARR(3*critical.n_xpoint) @@ -1793,6 +1883,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ xpt = si[0] ; X-point index to start with FOR i=0, critical.n_xpoint-1 DO BEGIN npol2[3*i] = npol[xpt] ; PF part 0 + n_y_boundary_guards[3*i] = y_boundary_guards ; PF part 0 ; Get the SOL ID solid = (*pf_info[xpt]).sol[0] @@ -1805,10 +1896,13 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; Get the next x-point xpt = (*sol_info[solid]).xpt2 npol2[3*i+2] = npol[critical.n_xpoint + xpt] ; PF part 1 + n_y_boundary_guards[3*i+2] = y_boundary_guards ; PF part 1 ENDFOR npol = npol2 - ENDIF + ENDELSE + + npol_total = TOTAL(npol+n_y_boundary_guards, /int) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Poloidal spacing. Need to ensure regular spacing @@ -1819,9 +1913,16 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ xpt_dist = FLTARR(critical.n_xpoint, 4) ; Distance between x-point and first grid point FOR i=0, critical.n_xpoint-1 DO BEGIN ; Grid the lower PF region - + ; Calculate poloidal distance along starting line - poldist = line_dist(R, Z, (*pf_info[xpt]).ri0, (*pf_info[xpt]).zi0) ; Poloidal distance along line + ; NOTE: (ri0, zi0) is the line going from x-point down the leg + ; to the left, if the core is at the top. + ; - If xpt is the lower x-point, then this corresponds to the + ; lower inner leg. + ; - If xpt is the upper x-point then this is the upper outer leg + + wallind = (*pf_info[xpt]).wallind0 + poldist = line_dist(R, Z, (*pf_info[xpt]).ri0[wallind:*], (*pf_info[xpt]).zi0[wallind:*]) ; Poloidal distance along line xdist = MAX(poldist) * 0.5 / FLOAT(npol[3*i]) ; Equal spacing xpt_dist[xpt, 0] = xdist @@ -1840,7 +1941,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; Second PF region xpt = xpt2 - poldist = line_dist(R, Z, (*pf_info[xpt]).ri0, (*pf_info[xpt]).zi0) + wallind = (*pf_info[xpt]).wallind1 + poldist = line_dist(R, Z, (*pf_info[xpt]).ri1[0:wallind], (*pf_info[xpt]).zi1[0:wallind]) xdist = MAX(poldist) * 0.5 / FLOAT(npol[3*i]) xpt_dist[xpt, 3] = xdist @@ -1972,7 +2074,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ENDIF ; Create 2D arrays for the grid - Rxy = FLTARR(TOTAL(nrad,/int), TOTAL(npol,/int)) + Rxy = FLTARR(TOTAL(nrad,/int), npol_total) Zxy = Rxy Rixy = Rxy Zixy = Rxy @@ -1993,8 +2095,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ FOR i=0, critical.n_xpoint-1 DO BEGIN ; This section grids the first divertor leg associated with this X-point - pvtfluxliner = [R[(*pf_info[i]).ri0[N_ELEMENTS((*pf_info[i]).ri0)-1]], R[(*pf_info[i]).ri0[0]]] - pvtfluxlinez = [Z[(*pf_info[i]).zi0[N_ELEMENTS((*pf_info[i]).zi0)-1]], Z[(*pf_info[i]).zi0[0]]] + pvtfluxliner = [R[(*pf_info[i]).ri0[-1]], R[(*pf_info[i]).ri0[(*pf_info[i]).wallind0]]] + pvtfluxlinez = [Z[(*pf_info[i]).zi0[-1]], Z[(*pf_info[i]).zi0[(*pf_info[i]).wallind0]]] pvtr1 = pvtfluxliner[1] pvtz1 = pvtfluxlinez[1] @@ -2059,13 +2161,15 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ vec_in_up=vec_in_up1, vec_out_up=vec_out_up1, sep_up=critical.xpt_f[xpt], $ vec_in_down=-vec_in_down1, vec_out_down=vec_out_down1, $ ydown_dist=0,orthup=orthup,orthdown=orthdown, $ - nonorthogonal_weight_decay_power=settings.nonorthogonal_weight_decay_power) - Rxy[*, ypos:(ypos+npol[3*i]-1)] = a.Rxy - Zxy[*, ypos:(ypos+npol[3*i]-1)] = a.Zxy - Rixy[*, ypos:(ypos+npol[3*i]-1)] = a.Rixy - Zixy[*, ypos:(ypos+npol[3*i]-1)] = a.Zixy - FOR j=ypos, ypos+npol[3*i]-1 DO Psixy[*, j] = pf_psi_vals[xpt,0,*] - ypos = ypos + npol[3*i] + nonorthogonal_weight_decay_power=settings.nonorthogonal_weight_decay_power, $ + y_boundary_guards=y_boundary_guards, $ + ydown_firstind=(*pf_info[xpt]).wallind0) + Rxy[*, ypos:(ypos+npol[3*i]+n_y_boundary_guards[3*i]-1)] = a.Rxy + Zxy[*, ypos:(ypos+npol[3*i]+n_y_boundary_guards[3*i]-1)] = a.Zxy + Rixy[*, ypos:(ypos+npol[3*i]+n_y_boundary_guards[3*i]-1)] = a.Rixy + Zixy[*, ypos:(ypos+npol[3*i]+n_y_boundary_guards[3*i]-1)] = a.Zixy + FOR j=ypos, ypos+npol[3*i]+n_y_boundary_guards[3*i]-1 DO Psixy[*, j] = pf_psi_vals[xpt,0,*] + ypos = ypos + npol[3*i]+n_y_boundary_guards[3*i] ; Set topology ydown_xsplit[3*i] = (*pf_info[xpt]).npf @@ -2170,12 +2274,12 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ sep_up=critical.xpt_f[xpt2], sep_line_up=sep_line_up, $ nonorthogonal_weight_decay_power=settings.nonorthogonal_weight_decay_power) - Rxy[*, ypos:(ypos+npol[3*i+1]-1)] = a.Rxy - Zxy[*, ypos:(ypos+npol[3*i+1]-1)] = a.Zxy - Rixy[*, ypos:(ypos+npol[3*i+1]-1)] = a.Rixy - Zixy[*, ypos:(ypos+npol[3*i+1]-1)] = a.Zixy - FOR j=ypos, ypos+npol[3*i+1]-1 DO Psixy[*, j] = sol_psi_vals[solid,*] - ypos = ypos + npol[3*i+1] + Rxy[*, ypos:(ypos+npol[3*i+1]+n_y_boundary_guards[3*i+1]-1)] = a.Rxy + Zxy[*, ypos:(ypos+npol[3*i+1]+n_y_boundary_guards[3*i+1]-1)] = a.Zxy + Rixy[*, ypos:(ypos+npol[3*i+1]+n_y_boundary_guards[3*i+1]-1)] = a.Rixy + Zixy[*, ypos:(ypos+npol[3*i+1]+n_y_boundary_guards[3*i+1]-1)] = a.Zixy + FOR j=ypos, ypos+npol[3*i+1]+n_y_boundary_guards[3*i+1]-1 DO Psixy[*, j] = sol_psi_vals[solid,*] + ypos = ypos + npol[3*i+1]+n_y_boundary_guards[3*i+1] ydown_xsplit[3*i+1] = (*pf_info[xpt]).npf yup_xsplit[3*i+1] = (*pf_info[(*sol_info[solid]).xpt2]).npf @@ -2211,8 +2315,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; This section grids the second divertor leg associated with this X-point xpt = (*sol_info[solid]).xpt2 - pvtfluxliner = [R[(*pf_info[xpt]).ri1[N_ELEMENTS((*pf_info[xpt]).ri1)-1]], R[(*pf_info[xpt]).ri1[0]]] - pvtfluxlinez = [Z[(*pf_info[xpt]).zi1[N_ELEMENTS((*pf_info[xpt]).zi1)-1]], Z[(*pf_info[xpt]).zi1[0]]] + pvtfluxliner = [R[(*pf_info[xpt]).ri1[(*pf_info[xpt]).wallind1]], R[(*pf_info[xpt]).ri1[0]]] + pvtfluxlinez = [Z[(*pf_info[xpt]).zi1[(*pf_info[xpt]).wallind1]], Z[(*pf_info[xpt]).zi1[0]]] pvtr1 = pvtfluxliner[1] pvtz1 = pvtfluxlinez[1] @@ -2292,13 +2396,15 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ vec_in_down=vec_in_down3, vec_out_down=vec_out_down3, sep_down=critical.xpt_f[xpt], $ vec_in_up=vec_in_up3, vec_out_up=vec_out_up3, $ yup_dist=0,orthup=orthup,orthdown=orthdown, $ - nonorthogonal_weight_decay_power=settings.nonorthogonal_weight_decay_power) - Rxy[*, ypos:(ypos+npol[3*i+2]-1)] = a.Rxy - Zxy[*, ypos:(ypos+npol[3*i+2]-1)] = a.Zxy - Rixy[*, ypos:(ypos+npol[3*i+2]-1)] = a.Rixy - Zixy[*, ypos:(ypos+npol[3*i+2]-1)] = a.Zixy - FOR j=ypos, ypos+npol[3*i+2]-1 DO Psixy[*, j] = pf_psi_vals[xpt,1,*] - ypos = ypos + npol[3*i+2] + nonorthogonal_weight_decay_power=settings.nonorthogonal_weight_decay_power, $ + y_boundary_guards=y_boundary_guards, $ + yup_lastind=(*pf_info[xpt]).wallind1) + Rxy[*, ypos:(ypos+npol[3*i+2]+n_y_boundary_guards[3*i+2]-1)] = a.Rxy + Zxy[*, ypos:(ypos+npol[3*i+2]+n_y_boundary_guards[3*i+2]-1)] = a.Zxy + Rixy[*, ypos:(ypos+npol[3*i+2]+n_y_boundary_guards[3*i+2]-1)] = a.Rixy + Zixy[*, ypos:(ypos+npol[3*i+2]+n_y_boundary_guards[3*i+2]-1)] = a.Zixy + FOR j=ypos, ypos+npol[3*i+2]+n_y_boundary_guards[3*i+2]-1 DO Psixy[*, j] = pf_psi_vals[xpt,1,*] + ypos = ypos + npol[3*i+2]+n_y_boundary_guards[3*i+2] ; Set topology ydown_xsplit[3*i+2] = (*pf_info[xpt]).npf @@ -2372,7 +2478,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ RETURN, create_grid(F, R, Z, new_settings, critical=critical, $ boundary=boundary, strictbndry=strictbndry, $ iter=iter+1, nrad_flexible=nrad_flexible, $ - single_rad_grid=single_rad_grid, fast=fast, simple=simple) + single_rad_grid=single_rad_grid, fast=fast, simple=simple, $ + y_boundary_guards=y_boundary_guards) ENDIF @@ -2383,13 +2490,13 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ rad_peaking:settings.rad_peaking, pol_peaking:settings.pol_peaking} ; Calculate magnetic field components - dpsidR = FLTARR(TOTAL(nrad, /int), TOTAL(npol, /int)) + dpsidR = FLTARR(TOTAL(nrad, /int), npol_total) dpsidZ = dpsidR interp_data.method = 2 FOR i=0,TOTAL(nrad,/int)-1 DO BEGIN - FOR j=0,TOTAL(npol,/int)-1 DO BEGIN + FOR j=0,npol_total-1 DO BEGIN local_gradient, interp_data, Rixy[i,j], Zixy[i,j], status=status, $ dfdr=dfdr, dfdz=dfdz ; dfd* are derivatives wrt the indices. Need to multiply by dr/di etc @@ -2401,6 +2508,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ result = {error:0, $ ; Signals success psi_inner:psi_inner, psi_outer:psi_outer, $ ; Range of psi nrad:nrad, npol:npol, $ ; Number of points in each domain + n_y_boundary_guards:n_y_boundary_guards, $ ; Number of y-boundary cells in each domain + y_boundary_guards:y_boundary_guards, $ ; Number of boundary cells included at y-boundaries Rixy:Rixy, Zixy:Zixy, $ ; Indices into R and Z of each point Rxy:Rxy, Zxy:Zxy, $ ; Location of each grid point psixy:psixy, $ ; Normalised psi for each point diff --git a/tools/tokamak_grids/gridgen/gen_surface_hypnotoad.pro b/tools/tokamak_grids/gridgen/gen_surface_hypnotoad.pro index 1fea3fc4cf..0d668a1660 100644 --- a/tools/tokamak_grids/gridgen/gen_surface_hypnotoad.pro +++ b/tools/tokamak_grids/gridgen/gen_surface_hypnotoad.pro @@ -30,7 +30,7 @@ FUNCTION gen_surface_hypnotoad, mesh=mesh, period=period, last=last, xi=xi ; Running total of npol to get starting y index ys = LONARR(nd) - FOR i=1, nd-1 DO ys[i] = ys[i-1] + mesh.npol[i-1] + FOR i=1, nd-1 DO ys[i] = ys[i-1] + mesh.npol[i-1] + mesh.n_y_boundary_guards[i-1] ; visited marks which domains have been used visited = INTARR(nd) @@ -56,9 +56,9 @@ FUNCTION gen_surface_hypnotoad, mesh=mesh, period=period, last=last, xi=xi ENDIF ; Get the range of indices for this domain - yi = [range(ys[domain], ys[domain]+m.npol[domain]-1)] + yi = [range(ys[domain], ys[domain] + m.npol[domain] + m.n_y_boundary_guards[domain] - 1)] IF ny EQ 0 THEN yinds = yi ELSE yinds = [yinds, yi] - ny = ny + m.npol[domain] + ny = ny + m.npol[domain] + m.n_y_boundary_guards[domain] visited[domain] = 1 ; Mark domain as visited diff --git a/tools/tokamak_grids/gridgen/hypnotoad.pro b/tools/tokamak_grids/gridgen/hypnotoad.pro index 00216cdb29..62bd4db38e 100644 --- a/tools/tokamak_grids/gridgen/hypnotoad.pro +++ b/tools/tokamak_grids/gridgen/hypnotoad.pro @@ -37,8 +37,8 @@ PRO oplot_mesh, rz_mesh, flux_mesh ypos = 0 FOR i=0, N_ELEMENTS(flux_mesh.npol)-1 DO BEGIN - plot_region, flux_mesh.rxy, flux_mesh.zxy, ypos, ypos+flux_mesh.npol[i]-1, color=i+1 - ypos = ypos + flux_mesh.npol[i] + plot_region, flux_mesh.rxy, flux_mesh.zxy, ypos, ypos+flux_mesh.npol[i]+flux_mesh.n_y_boundary_guards[i]-1, color=i+1 + ypos = ypos + flux_mesh.npol[i]+flux_mesh.n_y_boundary_guards[i] ENDFOR END @@ -103,6 +103,8 @@ PRO popup_event, event widget_control, info.nonorthogonal_weight_decay_power, get_value=nonorthogonal_weight_decay_power + widget_control, base_info.y_boundary_guards_field, get_value=y_boundary_guards + PRINT, "HYP: psi_inner =", psi_inner settings = {nrad:nrad, npol:npol, psi_inner:psi_inner, psi_outer:psi_outer, $ @@ -135,7 +137,8 @@ PRO popup_event, event boundary=boundary, strict=base_info.strict_bndry, $ single_rad_grid=base_info.single_rad_grid, $ critical=(*(base_info.rz_grid)).critical, $ - fast=base_info.fast, xpt_mul=xpt_mul, /simple) + fast=base_info.fast, xpt_mul=xpt_mul, /simple, $ + y_boundary_guards=y_boundary_guards) END 'mesh2': BEGIN ; Non-orthogonal mesh button was pushed @@ -147,7 +150,8 @@ PRO popup_event, event /nrad_flexible, $ single_rad_grid=base_info.single_rad_grid, $ critical=(*(base_info.rz_grid)).critical, $ - xpt_only=base_info.xpt_only, /simple) + xpt_only=base_info.xpt_only, /simple, $ + y_boundary_guards=y_boundary_guards) END ENDCASE @@ -362,6 +366,9 @@ PRO event_handler, event widget_control, info.xpt_dist_field, get_value=xpt_mul PRINT, "xpt_mul = ", xpt_mul + + widget_control, info.y_boundary_guards_field, get_value=y_boundary_guards + ; Check if a simplified boundary should be used IF info.simple_bndry THEN BEGIN ; Simplify the boundary to a square box @@ -383,7 +390,7 @@ PRO event_handler, event single_rad_grid=info.single_rad_grid, $ critical=(*(info.rz_grid)).critical, $ fast=info.fast, xpt_mul=xpt_mul, $ - fpsi = fpsi, /simple) + fpsi = fpsi, /simple, y_boundary_guards=y_boundary_guards) IF mesh.error EQ 0 THEN BEGIN PRINT, "Successfully generated mesh" WIDGET_CONTROL, info.status, set_value="Successfully generated mesh. All glory to the Hypnotoad!" @@ -426,6 +433,7 @@ PRO event_handler, event nonorthogonal_weight_decay_power:info.nonorthogonal_weight_decay_power} ENDELSE + widget_control, info.y_boundary_guards_field, get_value=y_boundary_guards ; Check if a simplified boundary should be used IF info.simple_bndry THEN BEGIN @@ -442,7 +450,8 @@ PRO event_handler, event boundary=boundary, strict=info.strict_bndry, $ /nrad_flexible, $ single_rad_grid=info.single_rad_grid, $ - critical=(*(info.rz_grid)).critical, xpt_only=info.xpt_only, /simple) + critical=(*(info.rz_grid)).critical, xpt_only=info.xpt_only, /simple, $ + y_boundary_guards=y_boundary_guards) IF mesh.error EQ 0 THEN BEGIN PRINT, "Successfully generated non-orthogonal mesh" WIDGET_CONTROL, info.status, set_value="Successfully generated mesh. All glory to the Hypnotoad!" @@ -472,7 +481,8 @@ PRO event_handler, event ; Get settings settings = {calcp:info.calcp, calcbt:info.calcbt, $ calchthe:info.calchthe, calcjpar:info.calcjpar, $ - orthogonal_coordinates_output:info.orthogonal_coordinates_output} + orthogonal_coordinates_output:info.orthogonal_coordinates_output, $ + y_boundary_guards:(*info.flux_mesh).y_boundary_guards} process_grid, *(info.rz_grid), *(info.flux_mesh), $ output=filename, poorquality=poorquality, /gui, parent=info.draw, $ @@ -590,8 +600,8 @@ PRO event_handler, event m = MIN( (REFORM((*info.flux_mesh).rxy - r))^2 + $ (REFORM((*info.flux_mesh).zxy - r))^2 , ind) - xi = FIX(ind / TOTAL((*info.flux_mesh).npol)) - yi = FIX(ind MOD TOTAL((*info.flux_mesh).npol)) + xi = FIX(ind / TOTAL((*info.flux_mesh).npol + (*info.flux_mesh).n_y_boundary_guards)) + yi = FIX(ind MOD TOTAL((*info.flux_mesh).npol + (*info.flux_mesh).n_y_boundary_guards)) PRINT, xi, yi END 'detail': BEGIN @@ -767,12 +777,12 @@ PRO event_handler, event ENDIF ELSE BEGIN FOR i=0, nnpol-1 DO BEGIN IF i MOD 3 EQ 1 THEN title='Core: ' ELSE title = 'Private Flux: ' - npol_field[i] = CW_FIELD( pol_base, $ - title = title, $ - uvalue = 'npol', $ - /long, $ - value = (*info.flux_mesh).npol[i], $ - xsize=8 $ + npol_field[i] = CW_FIELD( pol_base, $ + title = title, $ + uvalue = 'npol', $ + /long, $ + value = (*info.flux_mesh).npol[i], $ + xsize=8 $ ) ENDFOR ENDELSE @@ -853,7 +863,8 @@ PRO event_handler, event str_set, info, "rad_peak_field", oldinfo.rad_peak_field, /over str_set, info, "xpt_dist_field", oldinfo.xpt_dist_field, /over str_set, info, "nonorthogonal_weight_decay_power", oldinfo.nonorthogonal_weight_decay_power, /over - + str_set, info, "y_boundary_guards_field", oldinfo.y_boundary_guards_field, /over + str_set, info, "status", oldinfo.status, /over str_set, info, "leftbargeom", oldinfo.leftbargeom, /over @@ -1049,6 +1060,19 @@ PRO hypnotoad value = 1, $ xsize=8 $ ) + + y_boundary_guards_field = CW_FIELD( tab1, $ + title = '# y-boundary guard cells', $ + uvalue = 'y_boundary_guards', $ + /long, $ + value = 0, $ + xsize = 3 $ + ) + + l = WIDGET_LABEL(tab1, value = '(default 0 for backward compatibility,' + STRING(10B) $ + + 'recommended to set to number of' + STRING(10B) $ + + 'y-guards in your simulation, e.g. 2)', $ + /ALIGN_LEFT) detail_button = WIDGET_BUTTON(tab1, VALUE='Detailed settings', $ uvalue='detail', $ @@ -1192,6 +1216,7 @@ PRO hypnotoad rad_peak_field:rad_peak_field, $ parweight_field:parweight_field, $ xpt_dist_field:xpt_dist_field, $ + y_boundary_guards_field:y_boundary_guards_field, $ status:status_box, $ leftbargeom:leftbargeom, $ $;;; Options tab diff --git a/tools/tokamak_grids/gridgen/leg_separatrix2.pro b/tools/tokamak_grids/gridgen/leg_separatrix2.pro index eb98bfe351..788a60c1c5 100644 --- a/tools/tokamak_grids/gridgen/leg_separatrix2.pro +++ b/tools/tokamak_grids/gridgen/leg_separatrix2.pro @@ -180,18 +180,39 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ cpos = line_crossings(sepri, sepzi, 0, $ bndry[0,*], bndry[1,*], 1, $ ncross=ncross, inds1=in) + + ; Find where it crosses the edge of the grid + cpos = line_crossings(sepri, sepzi, 0, $ + [0, 0, nr, nr], [0, nz, nz, 0], 1, $ + ncross=ncrossgrid, inds1=ingrid) IF ncross GT 0 THEN BEGIN - sepri = [sepri[0:FLOOR(in[0])], INTERPOLATE(sepri, in[0])] - sepzi = [sepzi[0:FLOOR(in[0])], INTERPOLATE(sepzi, in[0])] - ENDIF + ; Keep points past the boundary in case we want to include y-boundary + ; guard cells + IF ncrossgrid GT 0 THEN BEGIN + ; never go further than the edge of the grid + lastgridind = FLOOR(ingrid[0]) + ENDIF ELSE BEGIN + lastgridind = N_ELEMENTS(sepri)-1 + ENDELSE + + lastind = FLOOR(in[0]) + sepri = [sepri[0:lastind], INTERPOLATE(sepri, in[0]), sepri[lastind+1:lastgridind]] + sepzi = [sepzi[0:lastind], INTERPOLATE(sepzi, in[0]), sepzi[lastind+1:lastgridind]] + ENDIF ELSE BEGIN + lastind = N_ELEMENTS(sepri)-1 + ENDELSE IF KEYWORD_SET(debug) THEN OPLOT, sepri, sepzi, color=3 IF npf EQ 0 THEN BEGIN pf1 = [[sepri], [sepzi]] + pf1_lastind = lastind+1 npf = 1 - ENDIF ELSE pf2 = [[sepri], [sepzi]] + ENDIF ELSE BEGIN + pf2 = [[sepri], [sepzi]] + pf2_lastind = lastind+1 + ENDELSE ENDELSE ENDFOR @@ -208,12 +229,12 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ IF KEYWORD_SET(debug) THEN BEGIN STOP ENDIF ELSE BEGIN - OPLOT, INTERPOLATE(R, pf1[*,0]), INTERPOLATE(Z, pf1[*,1]), color=3, thick=2 - OPLOT, INTERPOLATE(R, pf2[*,0]), INTERPOLATE(Z, pf2[*,1]), color=4, thick=2 + OPLOT, INTERPOLATE(R, pf1[0:pf1_lastind,0]), INTERPOLATE(Z, pf1[0:pf1_lastind,1]), color=3, thick=2 + OPLOT, INTERPOLATE(R, pf2[0:pf2_lastind,0]), INTERPOLATE(Z, pf2[0:pf2_lastind,1]), color=4, thick=2 OPLOT, INTERPOLATE(R, core1[*,0]), INTERPOLATE(Z, core1[*,1]), color=3, thick=2 OPLOT, INTERPOLATE(R, core2[*,0]), INTERPOLATE(Z, core2[*,1]), color=4, thick=2 ENDELSE - RETURN, {leg1:pf1, leg2:pf2, core1:core1, core2:core2, ri:xpt_ri, zi:xpt_zi} + RETURN, {leg1:pf1, leg1_lastind:pf1_lastind, leg2:pf2, leg2_lastind:pf2_lastind, core1:core1, core2:core2, ri:xpt_ri, zi:xpt_zi} END diff --git a/tools/tokamak_grids/gridgen/process_grid.pro b/tools/tokamak_grids/gridgen/process_grid.pro index 41595993c6..4ef46bcdfd 100644 --- a/tools/tokamak_grids/gridgen/process_grid.pro +++ b/tools/tokamak_grids/gridgen/process_grid.pro @@ -117,7 +117,8 @@ function calc_beta, Rxy, Zxy, mesh, rz_grid, method endfor endif else if(method EQ 1) then begin - npol = round(total(mesh.npol,/cumulative)) + npol_withguards = mesh.npol + mesh.n_y_boundary_guards + npol = round(total(npol_withguards,/cumulative)) Nnpol = n_elements(npol) status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN @@ -132,7 +133,7 @@ function calc_beta, Rxy, Zxy, mesh, rz_grid, method beta[xi,yi_curr] = !PI/2. - calc_beta_withgrid(Rxy[*,yi_curr], Zxy[*,yi_curr], xi) endif endfor - loc = where(yi LT mesh.npol[0]) + loc = where(yi LT npol_withguards[0]) if(total(loc) NE -1) then begin yi_curr = yi[loc] beta[xi,yi_curr] = !PI/2. - calc_beta_withgrid(Rxy[*,yi_curr], Zxy[*,yi_curr], xi) @@ -338,9 +339,9 @@ function dfdy_seps, f, y, mesh for j=0,nx-1 do begin ylow = 0 for i=0,N_ints-1 do begin - ylocs = indgen(mesh.npol[i])+ylow + ylocs = indgen(mesh.npol[i] + mesh.n_y_boundary_guards[i])+ylow result[j,ylocs] = DERIV(y[j,ylocs],f[j,ylocs]) - ylow += mesh.npol[i] + ylow += mesh.npol[i] + mesh.n_y_boundary_guards[i] endfor endfor return, result @@ -657,6 +658,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ str_check_present, settings, 'calchthe', -1 str_check_present, settings, 'calcjpar', -1 str_check_present, settings, 'orthogonal_coordinates_output', -1 + ; settings.y_boundary_guards is required, so don't set default value ;CATCH, err ;IF err NE 0 THEN BEGIN @@ -675,6 +677,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ; Size of the mesh nx = FIX(TOTAL(mesh.nrad)) ny = FIX(TOTAL(mesh.npol)) + ny_total = FIX(TOTAL(mesh.npol+mesh.n_y_boundary_guards)) ; including y-boundary cells ; Find the midplane ymid = 0 @@ -697,7 +700,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ psixy = mesh.psixy*mesh.fnorm + mesh.faxis ; Non-normalised psi psixy_eq = (psixy - rz_grid.simagx) / (rz_grid.sibdry - rz_grid.simagx) ; Normalised using EQDSK file conventions - pressure = FLTARR(nx, ny) + pressure = FLTARR(nx, ny_total) ; Use splines to interpolate pressure profile status = gen_surface_hypnotoad(mesh=mesh) ; Start generator @@ -774,8 +777,8 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ;ENDIF ; Grid spacing - dx = FLTARR(nx, ny) - FOR y=0, ny-1 DO BEGIN + dx = FLTARR(nx, ny_total) + FOR y=0, ny_total-1 DO BEGIN dx[0:(nx-2),y] = psixy[1:*,y] - psixy[0:(nx-2),y] dx[nx-1,y] = dx[nx-2,y] ENDFOR @@ -790,7 +793,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ENDIF dtheta = 2.*!PI / FLOAT(ny) - dy = FLTARR(nx, ny) + dtheta + dy = FLTARR(nx, ny_total) + dtheta ; B field components ; Following signs mean that psi increasing outwards from @@ -817,7 +820,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ENDELSE ; Get toroidal field from poloidal current function fpol - Btxy = FLTARR(nx, ny) + Btxy = FLTARR(nx, ny_total) fprime = Btxy fp = DERIV(rz_grid.npsigrid*(rz_grid.sibdry - rz_grid.simagx), rz_grid.fpol) status = gen_surface_hypnotoad(mesh=mesh) ; Start generator @@ -844,7 +847,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Go through the domains to get a starting estimate ; of hthe - hthe = FLTARR(nx, ny) + hthe = FLTARR(nx, ny_total) ; Pick a midplane index status = gen_surface_hypnotoad(mesh=mesh) ; Start generator @@ -933,9 +936,9 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ; Surface average dpdx2 = surface_average(dpdx, mesh) - pres = FLTARR(nx, ny) + pres = FLTARR(nx, ny_total) ; Integrate to get pressure - FOR i=0, ny-1 DO BEGIN + FOR i=0, ny_total-1 DO BEGIN pres[*,i] = int_func(psixy[*,i], dpdx2[*,i], /simple) pres[*,i] = pres[*,i] - pres[nx-1,i] ENDFOR @@ -1044,7 +1047,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ENDIF ELSE BEGIN ; Just use smooth in both directions - FOR i=0, ny-1 DO BEGIN + FOR i=0, ny_total-1 DO BEGIN hthe[*,i] = SMOOTH(SMOOTH(hthe[*,i],10),10) ENDFOR @@ -1065,18 +1068,24 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ENDIF ; Need yxy values at all points for nonorthogonal calculations - yxy = FLTARR(nx, ny) + yxy = FLTARR(nx, ny_total) status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) - yxy[xi,yi] = DINDGEN(N_ELEMENTS(yi))*dtheta + IF period EQ 0 THEN BEGIN + ; not periodic, set yxy to zero after y-boundary guard cells + yxy[xi,yi] = (DINDGEN(N_ELEMENTS(yi)) - settings.y_boundary_guards)*dtheta + ENDIF ELSE BEGIN + ; periodic, no y-boundary guard cells + yxy[xi,yi] = (DINDGEN(N_ELEMENTS(yi)))*dtheta + ENDELSE ENDREP UNTIL last ; Calculate hrad and dhrad for thetaxy calculation - hrad = dblarr(nx,ny) - dhrad = dblarr(nx,ny) - for j=0,ny-1 do begin + hrad = dblarr(nx,ny_total) + dhrad = dblarr(nx,ny_total) + for j=0,ny_total-1 do begin for i=0, nx-1 do begin if(i eq 0) then begin r2 = Rxy[i,j] @@ -1138,7 +1147,7 @@ retrybetacalc: H = pitch*(1.D + dyshiftdy) ; NOTE: This is only valid in the core - pol_angle = FLTARR(nx,ny) + pol_angle = FLTARR(nx,ny_total) FOR i=0, nx-1 DO pol_angle[i, *] = 2.0*!PI * qinty[i,*] / qloop[i] ;;;;;;;;;;;;;;;;;;;; THETA_ZERO ;;;;;;;;;;;;;;;;;;;;;; @@ -1229,7 +1238,7 @@ retrybetacalc: PRINT, "*** Calculating curvature in toroidal coordinates" - curvature, nx, ny, FLOAT(Rxy), FLOAT(Zxy), FLOAT(brxy), FLOAT(bzxy), FLOAT(btxy), $ + curvature, nx, ny_total, FLOAT(Rxy), FLOAT(Zxy), FLOAT(brxy), FLOAT(bzxy), FLOAT(btxy), $ FLOAT(psixy), FLOAT(thetaxy), hthe, $ bxcv=bxcv, mesh=mesh @@ -1277,9 +1286,9 @@ retrybetacalc: PRINT, "*** Calculating curvature in flux coordinates" - dpb = DBLARR(nx, ny) ; quantity used for y and z components + dpb = DBLARR(nx, ny_total) ; quantity used for y and z components - FOR i=0, ny-1 DO BEGIN + FOR i=0, ny_total-1 DO BEGIN dpb[*,i] = MU*dpdpsi/Bxy[*,i] ENDFOR dpb = dpb + DDX(xcoord, Bxy) @@ -1373,7 +1382,7 @@ retrybetacalc: ; Try smoothing jpar0 in psi, preserving zero points and maxima jps = jpar0 - FOR y=0,ny-1 DO BEGIN + FOR y=0,ny_total-1 DO BEGIN j = jpar0[*,y] js = j ma = MAX(ABS(j), ip) @@ -1505,7 +1514,7 @@ retrybetacalc: done = get_yesno("Is this ok?") ENDREP UNTIL done EQ 1 - Te = FLTARR(nx, ny)+Te_x + Te = FLTARR(nx, ny_total)+Te_x Ti = Te Ni_x = MAX(Ni) Ti_x = Te_x @@ -1522,7 +1531,7 @@ retrybetacalc: ENDREP UNTIL get_yesno("Is this ok?") EQ 1 Ti = Te - Ni = FLTARR(nx, ny) + ni_x + Ni = FLTARR(nx, ny_total) + ni_x Te_x = MAX(Te) Ti_x = Te_x ENDIF ELSE BEGIN @@ -1542,10 +1551,12 @@ retrybetacalc: Ti_x = Te_x ENDELSE - rmag = MAX(ABS(Rxy)) + ; excluding y-boundary guard cells + rmag = MAX(ABS([[Rxy[*,settings.y_boundary_guards:ny_inner+settings.y_boundary_guards-1]], [Rxy[*,ny_inner+3*settings.y_boundary_guards:-settings.y_boundary_guards-1]]])) PRINT, "Setting rmag = ", rmag - bmag = MAX(ABS(Bxy)) + ; excluding y-boundary guard cells + bmag = MAX(ABS([[Bxy[*,settings.y_boundary_guards:ny_inner+settings.y_boundary_guards-1]], [Bxy[*,ny_inner+3*settings.y_boundary_guards:-settings.y_boundary_guards-1]]])) PRINT, "Setting bmag = ", bmag ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1559,6 +1570,7 @@ retrybetacalc: s = file_write(handle, "nx", nx) s = file_write(handle, "ny", ny) + s = file_write(handle, "y_boundary_guards", settings.y_boundary_guards) ; Topology for original scheme s = file_write(handle, "ixseps1", ixseps1) From 6edec8445ae4f0931229373414f3c5e6ca5911bc Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 18 Mar 2019 22:24:38 +0000 Subject: [PATCH 1087/1783] Hypnotoad: Make y-integrals consistent when changing y_boundary_guards Change my_int_y to make its result zero at the first grid point, i.e. subtract the contribution of the lower y-boundary guard cells (which then have negative values in the result). Make qinty, sinty consistent on open surfaces, by setting them to zero at the first y-grid point in the domain for open flux-surface regions. This makes the results the same when the number of y-boundary guard cells is changed. --- tools/tokamak_grids/gridgen/process_grid.pro | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/tokamak_grids/gridgen/process_grid.pro b/tools/tokamak_grids/gridgen/process_grid.pro index 4ef46bcdfd..b9ad89e78e 100644 --- a/tools/tokamak_grids/gridgen/process_grid.pro +++ b/tools/tokamak_grids/gridgen/process_grid.pro @@ -296,6 +296,13 @@ FUNCTION my_int_y, var, yaxis, mesh, loop=loop, nosmooth=nosmooth, simple=simple yi = gen_surface_hypnotoad(last=last, xi=xi, period=period) f[xi,yi] = inty(yaxis[xi,yi],var[xi,yi], /simple) + + IF ~period THEN BEGIN + ; reset integral to zero at the first grid point, subtracting intgral + ; through y-boundary guard cells + f[xi,yi] = f[xi,yi] - f[xi,yi[mesh.y_boundary_guards]] + ENDIF + IF NOT KEYWORD_SET(nosmooth) THEN BEGIN f[xi,yi] = SMOOTH(SMOOTH(f[xi,yi], 5, /edge_truncate), 5, /edge_truncate) ENDIF @@ -1168,8 +1175,9 @@ retrybetacalc: ; H[xi, yi] = H[xi, yi] - H[xi, ymidplane] ENDIF ELSE BEGIN ; Doesn't include a point at the midplane - qinty[xi, yi] = qinty[xi, yi] - qinty[xi,yi[0]] - sinty[xi, yi] = sinty[xi, yi] - sinty[xi,yi[0]] + ; Set the value at the first grid-point to zero + qinty[xi, yi] = qinty[xi, yi] - qinty[xi,yi[settings.y_boundary_guards]] + sinty[xi, yi] = sinty[xi, yi] - sinty[xi,yi[settings.y_boundary_guards]] ; H[xi, yi] = H[xi, yi] - H[xi,yi[0]] ENDELSE ENDREP UNTIL last From c77eb7cd769a89f1584d5fd2b1397b5c1ca48e8c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 12 Mar 2019 19:53:14 +0000 Subject: [PATCH 1088/1783] Bump Hypnotoad version number 1.1.4 --- .../gridgen/hypnotoad_version.pro | 52 ++++++++++++------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/tools/tokamak_grids/gridgen/hypnotoad_version.pro b/tools/tokamak_grids/gridgen/hypnotoad_version.pro index 38267447d9..8b9aaaee76 100644 --- a/tools/tokamak_grids/gridgen/hypnotoad_version.pro +++ b/tools/tokamak_grids/gridgen/hypnotoad_version.pro @@ -10,27 +10,41 @@ FUNCTION hypnotoad_version ; 1.1.0 - non-orthogonal grid generation added ; 1.1.1 - Hypnotoad version number added here, and now saved to grid files ; 1.1.2 - Fixed bug in calculation of qloop. Should be only in closed regions - ; 1.1.3 - Handle case when break of contour is very close to X-point. - ; Add checkbox to write metrics for orthogonal coordinates (i.e. - ; metrics with integrated shear I=0); include attribute in output - ; file labelling the 'coordinates_type', either 'field_aligned' or - ; 'orthogonal'. - ; Various small fixes to make non-orthogonal grid generation more - ; robust. - ; Better handling of closed contours - ; Make transitions of non-orthogonal coordinates between X-point and - ; wall more flexible: instead of forcing coordinates to be orthogonal - ; half-way through the poloidal region, have separate weights for the - ; boundary vectors at either end to make the transition between the - ; two continuous (with dominant weighting of the orthogonal direction - ; in the middle of the region). - ; Enable 'Detailed settings' dialog for non-orthogonal grids, add - ; setting to change the exponent of the power-law decrease of the - ; weight of non-orthogonal vectors. + ; 1.1.3 - * Handle case when break of contour is very close to X-point. + ; * Add checkbox to write metrics for orthogonal coordinates (i.e. + ; metrics with integrated shear I=0); include attribute in output ; + ; file labelling the 'coordinates_type', either 'field_aligned' or + ; 'orthogonal'. + ; * Various small fixes to make non-orthogonal grid generation more + ; robust. + ; * Better handling of closed contours + ; * Make transitions of non-orthogonal coordinates between X-point and + ; wall more flexible: instead of forcing coordinates to be + ; orthogonal half-way through the poloidal region, have separate + ; weights for the boundary vectors at either end to make the + ; transition between the two continuous (with dominant weighting of + ; the orthogonal direction in the middle of the region). + ; * Enable 'Detailed settings' dialog for non-orthogonal grids, add + ; setting to change the exponent of the power-law decrease of the + ; weight of non-orthogonal vectors. + ; 1.1.4 - * For non-orthogonal, always refine of starting locations (previously + ; was only done for grids with only closed field lines) - improves + ; robustness especially around X-points. + ; * Pass 'simple' setting through when restarting grid generation. + ; * Rename gen_surface->gen_surface_hypnotoad to avoid name clash. + ; * Simplify expression for 'H' which is y-derivative of y-integral. + ; * Use 'I' instead of 'sinty' when calculating curvature + ; bxcvx/bxcvy/bxcvz - makes curvature output consistent with + ; non-field-aligned (x-z orthogonal) grids. + ; * Fix an update of 'nnpol' which could make some output arrays be + ; larger than they need to be (not a bug as the extra entries were + ; harmlessly filled with zeros). + ; * Option to save y-boundary guard cells (defaults to 0 for backward + ; compatibility with versions of BOUT++ before 4.3). major_version = 1 - minor_version = 1 - patch_number = 3 + minor_version = 2 + patch_number = 0 RETURN, LONG([major_version, minor_version, patch_number]) From 3eac427309d0382dc29b3445d34cdb3bb20e25f5 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 17 Mar 2019 16:49:26 +0000 Subject: [PATCH 1089/1783] Hypnotoad: use double precision everywhere Previously Hypnotoad used single precision floats in most places. Using double precision improves reproducibility of grids by reducing rouding errors. In particular rounding errors due to limited precision (e.g. in interpolations) are amplified by numerical derivatives; there are some quantities, e.g. zShift (aka qinty) that require interpolation, then differentiation, then integration so that errors can accumulate quite badly. To ensure double precision: - pass /DOUBLE argument to all calls to INTERPOLATE - use double precision for constants, by entering them with a 'D', e.g. 1.5D*f... - use DBLARR instead of FLTARR to create arrays --- tools/idllib/read_2d.pro | 2 +- tools/idllib/read_neqdsk.pro | 2 +- tools/tokamak_grids/gridgen/adjust_jpar.pro | 14 +- tools/tokamak_grids/gridgen/analyse_equil.pro | 70 +-- tools/tokamak_grids/gridgen/bfield/dct2d.pro | 72 +-- tools/tokamak_grids/gridgen/create_grid.pro | 396 +++++++------- .../gridgen/create_nonorthogonal.pro | 510 +++++++++--------- tools/tokamak_grids/gridgen/curvature.pro | 12 +- tools/tokamak_grids/gridgen/dct.pro | 20 +- tools/tokamak_grids/gridgen/dct2d.pro | 4 +- tools/tokamak_grids/gridgen/dct2dslow.pro | 4 +- tools/tokamak_grids/gridgen/ddy.pro | 2 +- tools/tokamak_grids/gridgen/evalcosp.pro | 40 +- tools/tokamak_grids/gridgen/evalcospfast.pro | 22 +- tools/tokamak_grids/gridgen/flux_tube.pro | 112 ++-- .../tokamak_grids/gridgen/follow_gradient.pro | 16 +- .../gridgen/follow_gradient_nonorth.pro | 24 +- tools/tokamak_grids/gridgen/get_line.pro | 6 +- .../gridgen/get_line_nonorth.pro | 10 +- tools/tokamak_grids/gridgen/gridgen.pro | 16 +- tools/tokamak_grids/gridgen/hypnotoad.pro | 42 +- tools/tokamak_grids/gridgen/int_y.pro | 2 +- .../tokamak_grids/gridgen/leg_separatrix.pro | 42 +- .../tokamak_grids/gridgen/leg_separatrix2.pro | 42 +- .../tokamak_grids/gridgen/line_crossings.pro | 20 +- .../tokamak_grids/gridgen/local_gradient.pro | 10 +- tools/tokamak_grids/gridgen/oplot_contour.pro | 2 +- .../tokamak_grids/gridgen/oplot_critical.pro | 4 +- tools/tokamak_grids/gridgen/plot_mesh.pro | 6 +- tools/tokamak_grids/gridgen/plot_rz_equil.pro | 4 +- tools/tokamak_grids/gridgen/process_grid.pro | 190 +++---- tools/tokamak_grids/gridgen/prof_write.pro | 42 +- tools/tokamak_grids/gridgen/radial_grid.pro | 26 +- tools/tokamak_grids/gridgen/run_test.pro | 6 +- tools/tokamak_grids/gridgen/rz_curvature.pro | 8 +- tools/tokamak_grids/gridgen/smooth_nl.pro | 24 +- tools/tokamak_grids/gridgen/sol_flux_tube.pro | 116 ++-- tools/tokamak_grids/gridgen/test.pro | 2 +- tools/tokamak_grids/gridgen/theta_line.pro | 4 +- 39 files changed, 973 insertions(+), 973 deletions(-) diff --git a/tools/idllib/read_2d.pro b/tools/idllib/read_2d.pro index 3317044f37..1d0cdb4540 100644 --- a/tools/idllib/read_2d.pro +++ b/tools/idllib/read_2d.pro @@ -1,7 +1,7 @@ FUNCTION read_2d, nx, ny, fid=fid IF KEYWORD_SET(fid) THEN status = next_double(fid=fid) - d = FLTARR(nx, ny) + d = DBLARR(nx, ny) FOR i=0, ny-1 DO d[*,i] = read_1d(nx) diff --git a/tools/idllib/read_neqdsk.pro b/tools/idllib/read_neqdsk.pro index fad4442d92..7707b80f8f 100644 --- a/tools/idllib/read_neqdsk.pro +++ b/tools/idllib/read_neqdsk.pro @@ -115,7 +115,7 @@ FUNCTION read_neqdsk, file FOR i=0,nxefit-1 DO BEGIN FOR j=0,nyefit-1 DO BEGIN r[i,j] = rgrid1 + xdim*i/(nxefit-1) - z[i,j] = (zmid-0.5*zdim) + zdim*j/(nyefit-1) + z[i,j] = (zmid-0.5D*zdim) + zdim*j/(nyefit-1) ENDFOR ENDFOR diff --git a/tools/tokamak_grids/gridgen/adjust_jpar.pro b/tools/tokamak_grids/gridgen/adjust_jpar.pro index 261d895749..d408944800 100644 --- a/tools/tokamak_grids/gridgen/adjust_jpar.pro +++ b/tools/tokamak_grids/gridgen/adjust_jpar.pro @@ -23,7 +23,7 @@ FUNCTION grad_par, var, mesh - dtheta = 2.*!PI / FLOAT(TOTAL(mesh.npol)) + dtheta = 2.D*!DPI / DOUBLE(TOTAL(mesh.npol)) RETURN, (mesh.Bpxy / (mesh.Bxy * mesh.hthe)) * ddy(var, mesh)*dtheta / mesh.dy END @@ -62,7 +62,7 @@ PRO adjust_jpar, grid, smoothp=smoothp, jpar=jpar, noplot=noplot ; Calculate 2*b0xk dot Grad P - kp = 2.*data.bxcvx*DDX(data.psixy, data.pressure) + kp = 2.D*data.bxcvx*DDX(data.psixy, data.pressure) ; Calculate B^2 Grad_par(Jpar0) @@ -85,8 +85,8 @@ PRO adjust_jpar, grid, smoothp=smoothp, jpar=jpar, noplot=noplot m = MAX(ABS(dj), ind) s = SIGN(dj[ind]) - w = WHERE(dj * s LT 0.0, count) ; find where contribution reverses - IF count GT 0 THEN dj[w] = 0.0 ; just zero in this region + w = WHERE(dj * s LT 0.0D, count) ; find where contribution reverses + IF count GT 0 THEN dj[w] = 0.0D ; just zero in this region jpar = ps status = gen_surface_hypnotoad(mesh=data) ; Start generator @@ -95,8 +95,8 @@ PRO adjust_jpar, grid, smoothp=smoothp, jpar=jpar, noplot=noplot IF NOT period THEN BEGIN ; Due to multi-point differencing, dp/dx can be non-zero outside separatrix - ps[xi,yi] = 0.0 - jpar[xi,yi] = 0.0 + ps[xi,yi] = 0.0D + jpar[xi,yi] = 0.0D ENDIF w = WHERE(yi EQ mid_ind, count) @@ -113,7 +113,7 @@ PRO adjust_jpar, grid, smoothp=smoothp, jpar=jpar, noplot=noplot !P.multi=[0,2,2,0,0] SURFACE, data.jpar0, tit="Input Jpar0", chars=2 SURFACE, jpar, tit="New Jpar0", chars=2 - PLOT, data.jpar0[0,*], tit="jpar at x=0. Solid=input", yr=[MIN([data.jpar0[0,*],jpar[0,*]]), $ + PLOT, data.jpar0[0,*], tit="jpar at x=0.D Solid=input", yr=[MIN([data.jpar0[0,*],jpar[0,*]]), $ MAX([data.jpar0[0,*],jpar[0,*]])] OPLOT, jpar[0,*], psym=1 diff --git a/tools/tokamak_grids/gridgen/analyse_equil.pro b/tools/tokamak_grids/gridgen/analyse_equil.pro index 8e9812f13e..43b69fcd19 100644 --- a/tools/tokamak_grids/gridgen/analyse_equil.pro +++ b/tools/tokamak_grids/gridgen/analyse_equil.pro @@ -39,22 +39,22 @@ FUNCTION analyse_equil, F, R, Z ; and X-points (saddle points) ; - dfdr = FLTARR(nx, ny) + dfdr = DBLARR(nx, ny) FOR j=0, ny-1 DO BEGIN dfdr[*,j] = diff(f[*,j]) ENDFOR - dfdz = FLTARR(nx, ny) + dfdz = DBLARR(nx, ny) FOR i=0, nx-1 DO BEGIN dfdz[i,*] = diff(f[i,*]) ENDFOR ; Use contour to get crossing-points where dfdr = dfdz = 0 - contour_lines, dfdr, findgen(nx), findgen(ny), levels=[0.0], $ + contour_lines, dfdr, findgen(nx), findgen(ny), levels=[0.0D], $ path_info=rinfo, path_xy=rxy - contour_lines, dfdz, findgen(nx), findgen(ny), levels=[0.0], $ + contour_lines, dfdz, findgen(nx), findgen(ny), levels=[0.0D], $ path_info=zinfo, path_xy=zxy ; Find where these two cross @@ -109,7 +109,7 @@ FUNCTION analyse_equil, F, R, Z zio = [ 0,-1, 0, 1, 0, 1] ; Z index offsets ; Fitting a + br + cz + drz + er^2 + fz^2 - A = TRANSPOSE([[FLTARR(6)+1], $ + A = TRANSPOSE([[DBLARR(6)+1], $ [rio], $ [zio], $ [rio*zio], $ @@ -124,7 +124,7 @@ FUNCTION analyse_equil, F, R, Z valid = 1 - localf = FLTARR(6) + localf = DBLARR(6) FOR i=0, 5 DO BEGIN ; Get the f value in a stencil around this point xi = ((rex[e]+rio[i]) > 0) < (nx-1) ; Zero-gradient at edges @@ -137,9 +137,9 @@ FUNCTION analyse_equil, F, R, Z ; [0,1,2,3,4,5] ; This determines whether saddle or extremum - det = 4.*res[4]*res[5] - res[3]^2 + det = 4.D*res[4]*res[5] - res[3]^2 - IF det LT 0.0 THEN BEGIN + IF det LT 0.0D THEN BEGIN PRINT, " X-point" ENDIF ELSE BEGIN PRINT, " O-point" @@ -147,15 +147,15 @@ FUNCTION analyse_equil, F, R, Z ; Get location (2x2 matrix of coefficients) - rinew = (res[3]*res[2] - 2.*res[1]*res[5]) / det - zinew = (res[3]*res[1] - 2.*res[4]*res[2]) / det + rinew = (res[3]*res[2] - 2.D*res[1]*res[5]) / det + zinew = (res[3]*res[1] - 2.D*res[4]*res[2]) / det - IF (ABS(rinew) GT 1.) OR (ABS(zinew) GT 1.0) THEN BEGIN + IF (ABS(rinew) GT 1.D) OR (ABS(zinew) GT 1.0D) THEN BEGIN ; Method has gone slightly wrong. Try a different method. ; Get a contour line starting at this point. Should ; produce a circle around the real o-point. PRINT, " Fitted location deviates too much" - IF det LT 0.0 THEN BEGIN + IF det LT 0.0D THEN BEGIN PRINT, " => X-point probably not valid" PRINT, " deviation = "+STR(rinew)+","+STR(zinew) ;valid = 0 @@ -170,15 +170,15 @@ FUNCTION analyse_equil, F, R, Z info = info[ind] ENDIF ELSE info = info[0] - rinew = 0.5*(MAX(xy[0, info.offset:(info.offset + info.n - 1)]) + $ + rinew = 0.5D*(MAX(xy[0, info.offset:(info.offset + info.n - 1)]) + $ MIN(xy[0, info.offset:(info.offset + info.n - 1)])) - rex[e] - zinew = 0.5*(MAX(xy[1, info.offset:(info.offset + info.n - 1)]) + $ + zinew = 0.5D*(MAX(xy[1, info.offset:(info.offset + info.n - 1)]) + $ MIN(xy[1, info.offset:(info.offset + info.n - 1)])) - zex[e] - IF (ABS(rinew) GT 2.) OR (ABS(zinew) GT 2.0) THEN BEGIN + IF (ABS(rinew) GT 2.D) OR (ABS(zinew) GT 2.0D) THEN BEGIN PRINT, " Backup method also failed. Keeping initial guess" - rinew = 0. - zinew = 0. + rinew = 0.D + zinew = 0.D ENDIF ENDELSE ENDIF @@ -193,13 +193,13 @@ FUNCTION analyse_equil, F, R, Z PRINT, " Starting index: " + STR(rex[e])+", "+STR(zex[e]) PRINT, " Refined index: " + STR(rinew)+", "+STR(zinew) - rnew = INTERPOLATE(R, rinew) - znew = INTERPOLATE(Z, zinew) + rnew = INTERPOLATE(R, rinew, /DOUBLE) + znew = INTERPOLATE(Z, zinew, /DOUBLE) PRINT, " Position: " + STR(rnew)+", "+STR(znew) PRINT, " F = "+STR(fnew) - IF det LT 0.0 THEN BEGIN + IF det LT 0.0D THEN BEGIN IF n_xpoint EQ 0 THEN BEGIN xpt_ri = [rinew] @@ -210,7 +210,7 @@ FUNCTION analyse_equil, F, R, Z ; Check if this duplicates an existing point m = MIN((xpt_ri - rinew)^2 + (xpt_zi - zinew)^2, ind) - IF m LT 2. THEN BEGIN + IF m LT 2.D THEN BEGIN PRINT, " Duplicates existing X-point." ENDIF ELSE BEGIN xpt_ri = [xpt_ri, rinew] @@ -231,7 +231,7 @@ FUNCTION analyse_equil, F, R, Z ; Check if this duplicates an existing point m = MIN((opt_ri - rinew)^2 + (opt_zi - zinew)^2, ind) - IF m LT 2. THEN BEGIN + IF m LT 2.D THEN BEGIN PRINT, " Duplicates existing O-point" ENDIF ELSE BEGIN opt_ri = [opt_ri, rinew] @@ -256,10 +256,10 @@ FUNCTION analyse_equil, F, R, Z ; Find the O-point closest to the middle of the grid dR = R[1] - R[0] dZ = Z[1] - Z[0] - mind = dR^2 * (opt_ri[0] - (FLOAT(nx)/2.))^2 + dZ^2*(opt_zi[0] - (FLOAT(ny)/2.))^2 + mind = dR^2 * (opt_ri[0] - (DOUBLE(nx)/2.D))^2 + dZ^2*(opt_zi[0] - (DOUBLE(ny)/2.D))^2 ind = 0 FOR i=1, n_opoint-1 DO BEGIN - d = dR^2*(opt_ri[i] - (FLOAT(nx)/2.))^2 + dZ^2*(opt_zi[i] - (FLOAT(ny)/2.))^2 + d = dR^2*(opt_ri[i] - (DOUBLE(nx)/2.D))^2 + dZ^2*(opt_zi[i] - (DOUBLE(ny)/2.D))^2 IF d LT mind THEN BEGIN ind = i mind = d @@ -267,8 +267,8 @@ FUNCTION analyse_equil, F, R, Z ENDFOR primary_opt = ind - PRINT, "Primary O-point is at "+STR(INTERPOLATE(R, opt_ri[ind])) + $ - ", " + STR(INTERPOLATE(Z, opt_zi[ind])) + PRINT, "Primary O-point is at "+STR(INTERPOLATE(R, opt_ri[ind], /DOUBLE)) + $ + ", " + STR(INTERPOLATE(Z, opt_zi[ind], /DOUBLE)) PRINT, "" IF n_xpoint GT 0 THEN BEGIN @@ -281,16 +281,16 @@ FUNCTION analyse_equil, F, R, Z ; Draw a line between the O-point and X-point n = 100 ; Number of points - farr = FLTARR(n) - dr = (xpt_ri[i] - opt_ri[primary_opt]) / FLOAT(n) - dz = (xpt_zi[i] - opt_zi[primary_opt]) / FLOAT(n) + farr = DBLARR(n) + dr = (xpt_ri[i] - opt_ri[primary_opt]) / DOUBLE(n) + dz = (xpt_zi[i] - opt_zi[primary_opt]) / DOUBLE(n) FOR j=0, n-1 DO BEGIN ; interpolate f at this location - farr[j] = INTERPOLATE(F, opt_ri[primary_opt] + dr*FLOAT(j), opt_zi[primary_opt] + dz*FLOAT(j)) + farr[j] = INTERPOLATE(F, opt_ri[primary_opt] + dr*DOUBLE(j), opt_zi[primary_opt] + dz*DOUBLE(j), /DOUBLE) ENDFOR IF farr[n-1] LT farr[0] THEN BEGIN - farr *= -1.0 ; Reverse, so maximum is always at the X-point + farr *= -1.0D ; Reverse, so maximum is always at the X-point ENDIF ; farr should be monotonic, and shouldn't cross any other separatrices @@ -300,8 +300,8 @@ FUNCTION analyse_equil, F, R, Z ; Discard if there is more than a 5% discrepancy in normalised ; psi between the maximum and the X-point, or the minimum and ; the O-point. - IF (ma - farr[n-1])/(ma - farr[0]) GT 0.05 THEN continue - IF (farr[0] - mi)/(farr[n-1] - mi) GT 0.05 THEN continue + IF (ma - farr[n-1])/(ma - farr[0]) GT 0.05D THEN continue + IF (farr[0] - mi)/(farr[n-1] - mi) GT 0.05D THEN continue ; Monotonic, so add this to a list of x-points to keep IF nkeep EQ 0 THEN keep = [i] ELSE keep = [keep, i] @@ -323,7 +323,7 @@ FUNCTION analyse_equil, F, R, Z REPEAT BEGIN ; note here MIN() sets the value of 'ind' to the index where the minimum was found m = MIN((xpt_ri[0:(i-1)] - xpt_ri[i])^2 + (xpt_zi[0:(i-1)] - xpt_zi[i])^2, ind) - IF m LT 4. THEN BEGIN + IF m LT 4.D THEN BEGIN PRINT, "Duplicates: ", i, ind IF ABS(opt_f[primary_opt] - xpt_f[i]) LT ABS(opt_f[primary_opt] - xpt_f[ind]) THEN BEGIN @@ -356,7 +356,7 @@ FUNCTION analyse_equil, F, R, Z ENDIF ELSE BEGIN ; No x-points. Pick mid-point in f - xpt_f = 0.5*(MAX(F) + MIN(F)) + xpt_f = 0.5D*(MAX(F) + MIN(F)) PRINT, "WARNING: No X-points. Setting separatrix to F = "+STR(xpt_f) diff --git a/tools/tokamak_grids/gridgen/bfield/dct2d.pro b/tools/tokamak_grids/gridgen/bfield/dct2d.pro index 3afe44976a..04cdf90217 100644 --- a/tools/tokamak_grids/gridgen/bfield/dct2d.pro +++ b/tools/tokamak_grids/gridgen/bfield/dct2d.pro @@ -9,53 +9,53 @@ ny=nsig IF NOT KEYWORD_SET(INVERSE) THEN BEGIN ;---direct transform--- - fsig=fltarr(nx,ny) + fsig=dblarr(nx,ny) for iu=0,Nx-1 do begin for jv=0,Ny-1 do begin - if (iu eq 0) then cu=0.707107 else cu=1. - if (jv eq 0) then cv=0.707107 else cv=1. + if (iu eq 0) then cu=0.707107D else cu=1.D + if (jv eq 0) then cv=0.707107D else cv=1.D - sum=0.0 + sum=0.0D for jy=0,Ny-1 do begin for ix=0,Nx-1 do begin ; - sum=sum + sig[ix,jy]*cos(jv*!PI*(2*jy+1)/(2*Ny))*$ - cos(iu*!PI*(2*ix+1)/(2*Nx)) + sum=sum + sig[ix,jy]*cos(jv*!DPI*(2*jy+1)/(2*Ny))*$ + cos(iu*!DPI*(2*ix+1)/(2*Nx)) ; endfor endfor - fsig[iu,jv]=(2./nsig)*cv*cu*sum + fsig[iu,jv]=(2.D/nsig)*cv*cu*sum endfor endfor ENDIF ELSE BEGIN ;---inverse transform--- - sig=fltarr(nx,ny) + sig=dblarr(nx,ny) for ix=0,Nx-1 do begin for jy=0,Ny-1 do begin - sum=0.0 + sum=0.0D for iu=0,Nx-1 do begin for jv=0,Ny-1 do begin ; - if (iu eq 0) then cu=0.707107 else cu=1. - if (jv eq 0) then cv=0.707107 else cv=1. + if (iu eq 0) then cu=0.707107D else cu=1.D + if (jv eq 0) then cv=0.707107D else cv=1.D - sum=sum + cv*cu*fsig[iu,jv]*cos(jv*!PI*(2*jy+1)/(2*Ny))*$ - cos(iu*!PI*(2*ix+1)/(2*Nx)) + sum=sum + cv*cu*fsig[iu,jv]*cos(jv*!DPI*(2*jy+1)/(2*Ny))*$ + cos(iu*!DPI*(2*ix+1)/(2*Nx)) ; endfor endfor - sig[ix,jy]=(2./nsig)*sum + sig[ix,jy]=(2.D/nsig)*sum ;STOP endfor @@ -80,32 +80,32 @@ function EvalCosP, fsig, nsig, x0=x0,y0=y0 nx=nsig ny=nsig - sum=0.0 - sumx=0.0 - sumy=0.0 + sum=0.0D + sumx=0.0D + sumy=0.0D for iu=0,Nx-1 do begin for jv=0,Ny-1 do begin ; - if (iu eq 0) then cu=0.707107 else cu=1. - if (jv eq 0) then cv=0.707107 else cv=1. + if (iu eq 0) then cu=0.707107D else cu=1.D + if (jv eq 0) then cv=0.707107D else cv=1.D sum=sum + cv*cu*fsig[iu,jv]*$ - COS(jv*!PI*(2*y0+1)/(2*Ny))*COS(iu*!PI*(2*x0+1)/(2*Nx)) + COS(jv*!DPI*(2*y0+1)/(2*Ny))*COS(iu*!DPI*(2*x0+1)/(2*Nx)) sumx=sumx + cv*cu*fsig[iu,jv]*$ - COS(jv*!PI*(2*y0+1)/(2*Ny))*SIN(iu*!PI*(2*x0+1)/(2*Nx))*$ - (-iu*!PI/Nx) + COS(jv*!DPI*(2*y0+1)/(2*Ny))*SIN(iu*!DPI*(2*x0+1)/(2*Nx))*$ + (-iu*!DPI/Nx) sumy=sumy + cv*cu*fsig[iu,jv]*$ - SIN(jv*!PI*(2*y0+1)/(2*Ny))*COS(iu*!PI*(2*x0+1)/(2*Nx))*$ - (-jv*!PI/Ny) + SIN(jv*!DPI*(2*y0+1)/(2*Ny))*COS(iu*!DPI*(2*x0+1)/(2*Nx))*$ + (-jv*!DPI/Ny) ; endfor endfor - res=(2./nsig)*[sum,sumx,sumy] + res=(2.D/nsig)*[sum,sumx,sumy] ; ; @@ -120,30 +120,30 @@ function EvalCosPfast, fsig, nsig, x0=x0,y0=y0 ;and the partial derivatives ;-------------------------------------------- - cuvec=fltarr(nsig)+1. - cuvec[0]=0.707107 + cuvec=dblarr(nsig)+1.D + cuvec[0]=0.707107D - cvvec=fltarr(nsig)+1. - cvvec[0]=0.707107 + cvvec=dblarr(nsig)+1.D + cvvec[0]=0.707107D uvec=findgen(nsig) - uvec=COS(!PI*findgen(nsig)*(x0+0.5)/nsig) - uvex=(-findgen(nsig)*!PI/nsig)*SIN(!PI*findgen(nsig)*(x0+0.5)/nsig) + uvec=COS(!DPI*findgen(nsig)*(x0+0.5D)/nsig) + uvex=(-findgen(nsig)*!DPI/nsig)*SIN(!DPI*findgen(nsig)*(x0+0.5D)/nsig) vvec=findgen(nsig) - vvec=COS(!PI*vvec*(y0+0.5)/nsig) - vvey=(-findgen(nsig)*!PI/nsig)*SIN(!PI*findgen(nsig)*(y0+0.5)/nsig) + vvec=COS(!DPI*vvec*(y0+0.5D)/nsig) + vvey=(-findgen(nsig)*!DPI/nsig)*SIN(!DPI*findgen(nsig)*(y0+0.5D)/nsig) ;-value - res=(2./nsig) * TOTAL(((cuvec # cvvec) * fsig) * (uvec # vvec)) + res=(2.D/nsig) * TOTAL(((cuvec # cvvec) * fsig) * (uvec # vvec)) ;d/dx - rex=(2./nsig) * TOTAL(((cuvec # cvvec) * fsig) * (uvex # vvec)) + rex=(2.D/nsig) * TOTAL(((cuvec # cvvec) * fsig) * (uvex # vvec)) ;d/dy - rey=(2./nsig) * TOTAL(((cuvec # cvvec) * fsig) * (uvec # vvey)) + rey=(2.D/nsig) * TOTAL(((cuvec # cvvec) * fsig) * (uvec # vvey)) ; ; diff --git a/tools/tokamak_grids/gridgen/create_grid.pro b/tools/tokamak_grids/gridgen/create_grid.pro index b94991018f..a6a23aa15a 100644 --- a/tools/tokamak_grids/gridgen/create_grid.pro +++ b/tools/tokamak_grids/gridgen/create_grid.pro @@ -119,7 +119,7 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe ydown_firstind=ydown_firstind, $ yup_lastind=yup_lastind - IF NOT KEYWORD_SET(parweight) THEN parweight = 0.0 ; Default is poloidal distance + IF NOT KEYWORD_SET(parweight) THEN parweight = 0.0D ; Default is poloidal distance np = N_ELEMENTS(ri) @@ -147,8 +147,8 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe IF 0 THEN BEGIN ; Calculate poloidal distance along starting line - drdi = DERIV(INTERPOLATE(R, ri)) - dzdi = DERIV(INTERPOLATE(Z, zi)) + drdi = DERIV(INTERPOLATE(R, ri, /DOUBLE)) + dzdi = DERIV(INTERPOLATE(Z, zi, /DOUBLE)) dldi = SQRT(drdi^2 + dzdi^2) poldist = int_func(findgen(np), dldi, /simple) ; Poloidal distance along line @@ -156,11 +156,11 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe ; reset poldist to start at zero at the ydown wall (if one is present) poldist = poldist - poldist[ydown_firstind] ENDIF ELSE BEGIN - rpos = INTERPOLATE(R, ri) - zpos = INTERPOLATE(Z, zi) + rpos = INTERPOLATE(R, ri, /DOUBLE) + zpos = INTERPOLATE(Z, zi, /DOUBLE) dd = SQRT((zpos[1:*] - zpos[0:(np-2)])^2 + (rpos[1:*] - rpos[0:(np-2)])^2) dd = [dd, SQRT((zpos[0] - zpos[np-1])^2 + (rpos[0] - rpos[np-1])^2)] - poldist = FLTARR(np) + poldist = DBLARR(np) FOR i=1,np-1 DO poldist[i] = poldist[i-1] + dd[i-1] ; reset poldist to start at zero at the ydown wall (if one is present) @@ -171,31 +171,31 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe ; Parallel distance along line ; Need poloidal and toroidal field ni = N_ELEMENTS(ri) - bp = FLTARR(ni) - bt = FLTARR(ni) + bp = DBLARR(ni) + bt = DBLARR(ni) m = interp_data.method interp_data.method = 2 FOR i=0, ni-1 DO BEGIN local_gradient, interp_data, ri[i], zi[i], status=status, $ f=f, dfdr=dfdr, dfdz=dfdz ; dfd* are derivatives wrt the indices. Need to multiply by dr/di etc - dfdr /= INTERPOLATE(DERIV(R),ri[i]) - dfdz /= INTERPOLATE(DERIV(Z),zi[i]) + dfdr /= INTERPOLATE(DERIV(R),ri[i], /DOUBLE) + dfdz /= INTERPOLATE(DERIV(Z),zi[i], /DOUBLE) IF i EQ 0 THEN BEGIN btr = INTERPOL(REFORM(fpsi[1,*]), REFORM(fpsi[0,*]), f) ENDIF - bp[i] = SQRT(dfdr^2 + dfdz^2) / INTERPOLATE(R, ri[i]) - bt[i] = ABS( btr / INTERPOLATE(R, ri[i])) + bp[i] = SQRT(dfdr^2 + dfdz^2) / INTERPOLATE(R, ri[i], /DOUBLE) + bt[i] = ABS( btr / INTERPOLATE(R, ri[i], /DOUBLE)) ENDFOR interp_data.method = m b = SQRT(bt^2 + bp^2) ddpar = dd * b / bp - pardist = FLTARR(np) + pardist = DBLARR(np) FOR i=1,np-1 DO BEGIN ip = (i + 1) MOD np - pardist[i] = pardist[i-1] + ddpar[i] ;0.5*(ddpar[i-1] + ddpar[ip]) + pardist[i] = pardist[i-1] + ddpar[i] ;0.5D*(ddpar[i-1] + ddpar[ip]) ENDFOR ; reset pardist to start at zero at the ydown wall (if one is present) @@ -204,39 +204,39 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe PRINT, "PARWEIGHT: ", parweight - dist = parweight*pardist + (1. - parweight)*poldist + dist = parweight*pardist + (1.D - parweight)*poldist ; Divide up distance. No points at the end (could be x-point) IF n GE 2 THEN BEGIN ; note dist[ydown_firstind] should be 0., but include here anyway total_dist = dist[yup_lastind] - dist[ydown_firstind] - IF SIZE(ydown_dist, /TYPE) EQ 0 THEN ydown_dist = total_dist * 0.5 / FLOAT(n) - IF SIZE(yup_dist, /TYPE) EQ 0 THEN yup_dist = total_dist * 0.5 / FLOAT(n) + IF SIZE(ydown_dist, /TYPE) EQ 0 THEN ydown_dist = total_dist * 0.5D / DOUBLE(n) + IF SIZE(yup_dist, /TYPE) EQ 0 THEN yup_dist = total_dist * 0.5D / DOUBLE(n) IF SIZE(ydown_space, /TYPE) EQ 0 THEN ydown_space = ydown_dist IF SIZE(yup_space, /TYPE) EQ 0 THEN yup_space = ydown_dist - ;dloc = (dist[np-1] - ydown_dist - yup_dist) * FINDGEN(n)/FLOAT(n-1) + ydown_dist ; Distance locations + ;dloc = (dist[np-1] - ydown_dist - yup_dist) * FINDGEN(n)/DOUBLE(n-1) + ydown_dist ; Distance locations - fn = FLOAT(n-1) + fn = DOUBLE(n-1) d = (total_dist - ydown_dist - yup_dist) ; Distance between first and last i = FINDGEN(n + boundary_guards_ydown + boundary_guards_yup) ; igrid starts at zero in the first grid cell (excludes boundary guard cells) igrid = i - boundary_guards_ydown - yd = ydown_space < 0.5*d/fn - yu = yup_space < 0.5*d/fn + yd = ydown_space < 0.5D*d/fn + yu = yup_space < 0.5D*d/fn ; Fit to ai + bi^2 + c[i-sin(2pi*i/(n-1))*(n-1)/(2pi)] - a = yd*2. - b = (2.*yu - a) / fn - c = d/fn - a - 0.5*b*fn - dloc = ydown_dist + a*igrid + 0.5*b*igrid^2 + c*[igrid - SIN(2.*!PI*igrid / fn)*fn/(2.*!PI)] - ddloc = a + b*igrid + c*[1 - COS(2.*!PI*igrid / fn)] + a = yd*2.D + b = (2.D*yu - a) / fn + c = d/fn - a - 0.5D*b*fn + dloc = ydown_dist + a*igrid + 0.5D*b*igrid^2 + c*[igrid - SIN(2.D*!DPI*igrid / fn)*fn/(2.D*!DPI)] + ddloc = a + b*igrid + c*[1.D - COS(2.D*!DPI*igrid / fn)] ; Fit to dist = a*i^3 + b*i^2 + c*i - ;c = ydown_dist*2. - ;b = 3.*(d/fn^2 - c/fn) - 2.*yup_dist/fn + c/fn + ;c = ydown_dist*2.D + ;b = 3.D*(d/fn^2 - c/fn) - 2.D*yup_dist/fn + c/fn ;a = d/fn^3 - c/fn^2 - b/fn ;dloc = ydown_dist + c*i + b*i^2 + a*i^3 @@ -328,8 +328,8 @@ FUNCTION grid_region, interp_data, R, Z, $ ydown_firstind=ydown_firstind, $ yup_lastind=yup_lastind) - rii = INTERPOLATE(ri, ind) - zii = INTERPOLATE(zi, ind) + rii = INTERPOLATE(ri, ind, /DOUBLE) + zii = INTERPOLATE(zi, ind, /DOUBLE) ;rii = int_func(SMOOTH(deriv(rii), 3), /simple) + rii[0] ;zii = int_func(SMOOTH(deriv(zii), 3), /simple) + zii[0] @@ -344,8 +344,8 @@ FUNCTION grid_region, interp_data, R, Z, $ ; From each starting point, follow gradient in both directions - rixy = FLTARR(nsurf, npar_total) - zixy = FLTARR(nsurf, npar_total) + rixy = DBLARR(nsurf, npar_total) + zixy = DBLARR(nsurf, npar_total) FOR i=0, npar_total-1 DO BEGIN IF sind GE 0 THEN BEGIN rixy[nin, i] = rii[i] @@ -366,17 +366,17 @@ FUNCTION grid_region, interp_data, R, Z, $ boundary=boundary, fbndry=fbndry IF status EQ 1 THEN BEGIN - rixy[nin+j+1, i] = -1.0 + rixy[nin+j+1, i] = -1.0D IF nin+j LT slast THEN slast = nin+j ; last good surface index fbndry = fvals[slast] - IF (fvals[1] - fvals[0])*(flast - fbndry) GT 0 THEN flast = 0.95*fbndry + 0.05*f0 + IF (fvals[1] - fvals[0])*(flast - fbndry) GT 0 THEN flast = 0.95D*fbndry + 0.05D*f0 BREAK ENDIF ELSE IF status EQ 2 THEN BEGIN ; Hit a boundary rixy[nin+j+1, i] = rinext zixy[nin+j+1, i] = zinext IF nin+j LT slast THEN slast = nin+j ; Set the last point - IF (fvals[1] - fvals[0])*(flast - fbndry) GT 0 THEN flast = 0.95*fbndry + 0.05*f0 + IF (fvals[1] - fvals[0])*(flast - fbndry) GT 0 THEN flast = 0.95D*fbndry + 0.05D*f0 BREAK ENDIF ELSE BEGIN rixy[nin+j+1, i] = rinext @@ -391,10 +391,10 @@ FUNCTION grid_region, interp_data, R, Z, $ boundary=boundary, fbndry=fbndry IF status EQ 1 THEN BEGIN - rixy[nin-j-1, i] = -1.0 + rixy[nin-j-1, i] = -1.0D IF nin-j GT sfirst THEN sfirst = nin-j fbndry = fvals[sfirst] - IF (fvals[1] - fvals[0])*(ffirst - fbndry) LT 0 THEN ffirst = 0.95*fbndry + 0.05*f0 + IF (fvals[1] - fvals[0])*(ffirst - fbndry) LT 0 THEN ffirst = 0.95D*fbndry + 0.05D*f0 BREAK ENDIF @@ -403,16 +403,16 @@ FUNCTION grid_region, interp_data, R, Z, $ IF status EQ 2 THEN BEGIN IF nin-j GT sfirst THEN sfirst = nin-j - IF (fvals[1] - fvals[0])*(ffirst - fbndry) LT 0 THEN ffirst = 0.95*fbndry + 0.05*f0 + IF (fvals[1] - fvals[0])*(ffirst - fbndry) LT 0 THEN ffirst = 0.95D*fbndry + 0.05D*f0 BREAK ENDIF ENDFOR IF KEYWORD_SET(oplot) THEN BEGIN - OPLOT, INTERPOLATE(R, rixy[*, i]), INTERPOLATE(Z, zixy[*, i]), color=4 + OPLOT, INTERPOLATE(R, rixy[*, i], /DOUBLE), INTERPOLATE(Z, zixy[*, i], /DOUBLE), color=4 ENDIF ENDFOR - RETURN, {rixy:rixy, zixy:zixy, rxy:INTERPOLATE(R, rixy), zxy:INTERPOLATE(Z, zixy)} + RETURN, {rixy:rixy, zixy:zixy, rxy:INTERPOLATE(R, rixy, /DOUBLE), zxy:INTERPOLATE(Z, zixy, /DOUBLE)} END PRO plot_grid_section, a, _extra=_extra @@ -436,7 +436,7 @@ PRO oplot_line, interp_data, R, Z, ri0, zi0, fto, npt=npt, color=color, _extra=_ pos = get_line(interp_data, R, Z, ri0, zi0, fto, npt=npt) - OPLOT, INTERPOLATE(R, pos[*,0]), INTERPOLATE(Z, pos[*,1]), $ + OPLOT, INTERPOLATE(R, pos[*,0], /DOUBLE), INTERPOLATE(Z, pos[*,1], /DOUBLE), $ color=color, _extra=_extra END @@ -445,17 +445,17 @@ FUNCTION line_dist, R, Z, ri, zi ; derivatives drdi and dzdi may be very inaccurate because the contour ; given by ri and zi is not necessarily uniformly spaced, it may not even ; have a smoothly varying grid spacing. Therefore don't use this branch - drdi = DERIV(INTERPOLATE(R, ri)) - dzdi = DERIV(INTERPOLATE(Z, zi)) + drdi = DERIV(INTERPOLATE(R, ri, /DOUBLE)) + dzdi = DERIV(INTERPOLATE(Z, zi, /DOUBLE)) dldi = SQRT(drdi^2 + dzdi^2) RETURN, int_func(findgen(N_ELEMENTS(dldi)), dldi, /simple) ENDIF ELSE BEGIN np = N_ELEMENTS(ri) - rpos = INTERPOLATE(R, ri) - zpos = INTERPOLATE(Z, zi) + rpos = INTERPOLATE(R, ri, /DOUBLE) + zpos = INTERPOLATE(Z, zi, /DOUBLE) dd = SQRT((zpos[1:*] - zpos[0:(np-2)])^2 + (rpos[1:*] - rpos[0:(np-2)])^2) dd = [dd, SQRT((zpos[0] - zpos[np-1])^2 + (rpos[0] - rpos[np-1])^2)] - result = FLTARR(np) + result = DBLARR(np) FOR i=1,np-1 DO result[i] = result[i-1] + dd[i-1] RETURN, result ENDELSE @@ -471,8 +471,8 @@ FUNCTION xpt_hthe, dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f darr = sep_info.leg1_dist ind = INTERPOL(FINDGEN(N_ELEMENTS(darr)), darr, dist[0]) - ri = INTERPOLATE(sep_info.leg1_ri, ind) - zi = INTERPOLATE(sep_info.leg1_zi, ind) + ri = INTERPOLATE(sep_info.leg1_ri, ind, /DOUBLE) + zi = INTERPOLATE(sep_info.leg1_zi, ind, /DOUBLE) ; Go inwards to PF follow_gradient, dctF, R, Z, ri, zi, $ @@ -488,8 +488,8 @@ FUNCTION xpt_hthe, dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f darr = sep_info.leg2_dist ind = INTERPOL(FINDGEN(N_ELEMENTS(darr)), darr, dist[3]) - ri = INTERPOLATE(sep_info.leg2_ri, ind) - zi = INTERPOLATE(sep_info.leg2_zi, ind) + ri = INTERPOLATE(sep_info.leg2_ri, ind, /DOUBLE) + zi = INTERPOLATE(sep_info.leg2_zi, ind, /DOUBLE) ; Go inwards to PF follow_gradient, dctF, R, Z, ri, zi, $ @@ -503,8 +503,8 @@ FUNCTION xpt_hthe, dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f darr = sep_info.core1_dist ind = INTERPOL(FINDGEN(N_ELEMENTS(darr)), darr, dist[2]) - ri = INTERPOLATE(sep_info.core1_ri, ind) - zi = INTERPOLATE(sep_info.core1_zi, ind) + ri = INTERPOLATE(sep_info.core1_ri, ind, /DOUBLE) + zi = INTERPOLATE(sep_info.core1_zi, ind, /DOUBLE) ; Go inwards to core follow_gradient, dctF, R, Z, ri, zi, $ @@ -521,8 +521,8 @@ FUNCTION xpt_hthe, dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f darr = sep_info.core2_dist ind = INTERPOL(FINDGEN(N_ELEMENTS(darr)), darr, dist[1]) - ri = INTERPOLATE(sep_info.core2_ri, ind) - zi = INTERPOLATE(sep_info.core2_zi, ind) + ri = INTERPOLATE(sep_info.core2_ri, ind, /DOUBLE) + zi = INTERPOLATE(sep_info.core2_zi, ind, /DOUBLE) ; Go inwards to core follow_gradient, dctF, R, Z, ri, zi, $ @@ -535,29 +535,29 @@ FUNCTION xpt_hthe, dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f ; Get distances between end points - OPLOT, INTERPOLATE(R, [pf_ri1, pf_ri2]), $ - INTERPOLATE(Z, [pf_zi1, pf_zi2]), thick=2, color=1 + OPLOT, INTERPOLATE(R, [pf_ri1, pf_ri2], /DOUBLE), $ + INTERPOLATE(Z, [pf_zi1, pf_zi2], /DOUBLE), thick=2, color=1 - d1 = (INTERPOLATE(R, pf_ri1) - INTERPOLATE(R, pf_ri2))^2 + $ - (INTERPOLATE(Z, pf_zi1) - INTERPOLATE(Z, pf_zi2))^2 + d1 = (INTERPOLATE(R, pf_ri1, /DOUBLE) - INTERPOLATE(R, pf_ri2, /DOUBLE))^2 + $ + (INTERPOLATE(Z, pf_zi1, /DOUBLE) - INTERPOLATE(Z, pf_zi2, /DOUBLE))^2 - d2 = (INTERPOLATE(R, core_ri1) - INTERPOLATE(R, core_ri2))^2 + $ - (INTERPOLATE(Z, core_zi1) - INTERPOLATE(Z, core_zi2))^2 + d2 = (INTERPOLATE(R, core_ri1, /DOUBLE) - INTERPOLATE(R, core_ri2, /DOUBLE))^2 + $ + (INTERPOLATE(Z, core_zi1, /DOUBLE) - INTERPOLATE(Z, core_zi2, /DOUBLE))^2 - OPLOT, INTERPOLATE(R, [core_ri1, core_ri2]), $ - INTERPOLATE(Z, [core_zi1, core_zi2]), thick=2, color=2 + OPLOT, INTERPOLATE(R, [core_ri1, core_ri2], /DOUBLE), $ + INTERPOLATE(Z, [core_zi1, core_zi2], /DOUBLE), thick=2, color=2 - d3 = (INTERPOLATE(R, sol_in_ri1) - INTERPOLATE(R, sol_in_ri2))^2 + $ - (INTERPOLATE(Z, sol_in_zi1) - INTERPOLATE(Z, sol_in_zi2))^2 + d3 = (INTERPOLATE(R, sol_in_ri1, /DOUBLE) - INTERPOLATE(R, sol_in_ri2, /DOUBLE))^2 + $ + (INTERPOLATE(Z, sol_in_zi1, /DOUBLE) - INTERPOLATE(Z, sol_in_zi2, /DOUBLE))^2 - OPLOT, INTERPOLATE(R, [sol_in_ri1, sol_in_ri2]), $ - INTERPOLATE(Z, [sol_in_zi1, sol_in_zi2]), thick=2, color=3 + OPLOT, INTERPOLATE(R, [sol_in_ri1, sol_in_ri2], /DOUBLE), $ + INTERPOLATE(Z, [sol_in_zi1, sol_in_zi2], /DOUBLE), thick=2, color=3 - d4 = (INTERPOLATE(R, sol_out_ri1) - INTERPOLATE(R, sol_out_ri2))^2 + $ - (INTERPOLATE(Z, sol_out_zi1) - INTERPOLATE(Z, sol_out_zi2))^2 + d4 = (INTERPOLATE(R, sol_out_ri1, /DOUBLE) - INTERPOLATE(R, sol_out_ri2, /DOUBLE))^2 + $ + (INTERPOLATE(Z, sol_out_zi1, /DOUBLE) - INTERPOLATE(Z, sol_out_zi2, /DOUBLE))^2 - OPLOT, INTERPOLATE(R, [sol_out_ri1, sol_out_ri2]), $ - INTERPOLATE(Z, [sol_out_zi1, sol_out_zi2]), thick=2, color=4 + OPLOT, INTERPOLATE(R, [sol_out_ri1, sol_out_ri2], /DOUBLE), $ + INTERPOLATE(Z, [sol_out_zi1, sol_out_zi2], /DOUBLE), thick=2, color=4 ;cursor, x, y, /down @@ -592,34 +592,34 @@ FUNCTION solve_xpt_hthe, dctF, R, Z, sep_info, dist0, pf_f, core_f, sol_in_f, so ; Internal error: Bad variable type encountered in no_name_var(). ; when NEWTON is combined with LSODE - dfdx = FLTARR(4,4) + dfdx = DBLARR(4,4) delta = 1e-3 REPEAT BEGIN xp0 = xpt_hthe_newt(dist) - response = FLTARR(4) + response = DBLARR(4) FOR i=0, 3 DO BEGIN ; Calculate partial derivatives using finite-differences - d = FLTARR(4) + d = DBLARR(4) d[i] = delta dfdx[*,i] = (xpt_hthe_newt(dist+d) - xp0) / delta response[i] = MIN([dfdx[i,i], dfdx[(i+1) MOD 4,i]]) ENDFOR - IF MIN(dfdx) LT 0.0 THEN BEGIN + IF MIN(dfdx) LT 0.0D THEN BEGIN PRINT, "WARNING: ILL-BEHAVED FITTING" RETURN, dist0 ; Don't modify ENDIF ; ; Invert using SVD ; SVDC, dfdx, W, U, V -; WP = FLTARR(4, 4) -; for i=0,2 do wp[i,i] = 1.0/w[i] +; WP = DBLARR(4, 4) +; for i=0,2 do wp[i,i] = 1.0D/w[i] ; ddist = V ## WP ## TRANSPOSE(U) # xp0 ; ; ;ddist = INVERT(dfdx) # xp0 -; w = WHERE(ABS(ddist) GT 0.5*dist, count) -; IF count GT 0 THEN ddist[w] = ddist[w] * 0.5*dist[w] / ABS(ddist[w]) +; w = WHERE(ABS(ddist) GT 0.5D*dist, count) +; IF count GT 0 THEN ddist[w] = ddist[w] * 0.5D*dist[w] / ABS(ddist[w]) ; dist = dist - ddist ; PRINT, "DIST =", REFORM(dist) @@ -631,10 +631,10 @@ FUNCTION solve_xpt_hthe, dctF, R, Z, sep_info, dist0, pf_f, core_f, sol_in_f, so ; If too low, move out, too high move in med = MEDIAN(response) - w = WHERE(response LT 0.1*med, count1) - IF count1 GT 0 THEN dist[w] = dist[w] * 2. - w = WHERE(response GT 10.*med, count2) - IF count2 GT 0 THEN dist[w] = dist[w] * 0.75 + w = WHERE(response LT 0.1D*med, count1) + IF count1 GT 0 THEN dist[w] = dist[w] * 2.D + wD = WHERE(response GT 10.D*medD, count2) + IF count2 GT 0 THEN dist[w] = dist[w] * 0.75D ENDREP UNTIL count1+count2 EQ 0 @@ -664,14 +664,14 @@ FUNCTION increase_xpt_hthe, dctF, R, Z, sep_info, dist0, pf_f, core_f, sol_in_f, IF xd[(ind+1) MOD 4] LT xd[(ind+3) MOD 4] THEN BEGIN ; Increase dist[ind] - dist[ind] = dist[ind] * 1.1 + dist[ind] = dist[ind] * 1.1D ENDIF ELSE BEGIN ; Increase dist[ind-1] - dist[(ind+3) MOD 4] = dist[(ind+3) MOD 4] * 1.1 + dist[(ind+3) MOD 4] = dist[(ind+3) MOD 4] * 1.1D ENDELSE ENDIF xd = xpt_hthe(dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f, boundary=boundary, psi=psi) - ENDREP UNTIL (MIN(xd) GE xd_target) OR ( ABS(MIN(xd) - m) LT 1.e-5 ) + ENDREP UNTIL (MIN(xd) GE xd_target) OR ( ABS(MIN(xd) - m) LT 1.d-5 ) ; Reduce spacing until one goes below target REPEAT BEGIN @@ -680,9 +680,9 @@ FUNCTION increase_xpt_hthe, dctF, R, Z, sep_info, dist0, pf_f, core_f, sol_in_f, IF m GT xd_target THEN BEGIN ; Decrease distance IF xd[(ind+1) MOD 4] GT xd[(ind+3) MOD 4] THEN BEGIN - dist[ind] = dist[ind] / 1.1 + dist[ind] = dist[ind] / 1.1D ENDIF ELSE BEGIN - dist[(ind+3) MOD 4] = dist[(ind+3) MOD 4] / 1.1 + dist[(ind+3) MOD 4] = dist[(ind+3) MOD 4] / 1.1D ENDELSE ENDIF xd = xpt_hthe(dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f, boundary=boundary, psi=psi) @@ -733,23 +733,23 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ENDIF ELSE IF N_PARAMS() LT 4 THEN BEGIN ; Settings omitted. Set defaults PRINT, "Settings not given -> using default values" - settings = {psi_inner:0.9, $ - psi_outer:1.1, $ + settings = {psi_inner:0.9D, $ + psi_outer:1.1D, $ nrad:36, $ npol:64, $ - rad_peaking:0.0, $ - pol_peaking:0.0, $ - parweight:0.0} + rad_peaking:0.0D, $ + pol_peaking:0.0D, $ + parweight:0.0D} ENDIF ELSE BEGIN PRINT, "Checking settings" settings = in_settings ; So the input isn't changed - str_check_present, settings, 'psi_inner', 0.9 - str_check_present, settings, 'psi_outer', 1.1 + str_check_present, settings, 'psi_inner', 0.9D + str_check_present, settings, 'psi_outer', 1.1D str_check_present, settings, 'nrad', 36 str_check_present, settings, 'npol', 64 - str_check_present, settings, 'rad_peaking', 0.0 - str_check_present, settings, 'pol_peaking', 0.0 - str_check_present, settings, 'parweight', 0.0 + str_check_present, settings, 'rad_peaking', 0.0D + str_check_present, settings, 'pol_peaking', 0.0D + str_check_present, settings, 'parweight', 0.0D ENDELSE s = SIZE(F, /DIMENSION) @@ -801,7 +801,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ENDIF IF NOT KEYWORD_SET(bndryi) THEN BEGIN - bndryi = FLTARR(2,4) + bndryi = DBLARR(2,4) bndryi[0,*] = [1, nx-2, nx-2, 1] bndryi[1,*] = [1, 1, ny-2, ny-2] ENDIF @@ -822,7 +822,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ nlev = 100 minf = MIN(f) maxf = MAX(f) - levels = findgen(nlev)*(maxf-minf)/FLOAT(nlev-1) + minf + levels = findgen(nlev)*(maxf-minf)/DOUBLE(nlev-1) + minf safe_colors, /first CONTOUR, F, R, Z, levels=levels, color=1, /iso, xstyl=1, ysty=1 @@ -910,8 +910,8 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; Make sure that the line goes clockwise - m = MAX(INTERPOLATE(Z, start_zi), ind) - IF (DERIV(INTERPOLATE(R, start_ri)))[ind] LT 0.0 THEN BEGIN + m = MAX(INTERPOLATE(Z, start_zi, /DOUBLE), ind) + IF (DERIV(INTERPOLATE(R, start_ri, /DOUBLE)))[ind] LT 0.0D THEN BEGIN ; R should be increasing at the top. Need to reverse start_ri = REVERSE(start_ri) start_zi = REVERSE(start_zi) @@ -954,11 +954,11 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ENDFOR ; Get other useful variables - Psixy = FLTARR(nrad, npol) + Psixy = DBLARR(nrad, npol) FOR i=0, npol-1 DO psixy[*,i] = (fvals - faxis)/fnorm ; to get normalised psi ; Calculate magnetic field components - dpsidR = FLTARR(nrad, npol) + dpsidR = DBLARR(nrad, npol) dpsidZ = dpsidR interp_data.method = 2 @@ -968,8 +968,8 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ local_gradient, interp_data, a.Rixy[i,j], a.Zixy[i,j], status=status, $ dfdr=dfdr, dfdz=dfdz ; dfd* are derivatives wrt the indices. Need to multiply by dr/di etc - dpsidR[i,j] = dfdr/INTERPOLATE(DERIV(R),a.Rixy[i,j]) - dpsidZ[i,j] = dfdz/INTERPOLATE(DERIV(Z),a.Zixy[i,j]) + dpsidR[i,j] = dfdr/INTERPOLATE(DERIV(R),a.Rixy[i,j], /DOUBLE) + dpsidZ[i,j] = dfdz/INTERPOLATE(DERIV(Z),a.Zixy[i,j], /DOUBLE) ENDFOR ENDFOR @@ -1018,8 +1018,8 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ primary_xpt = si[0] PRINT, "Primary X-point is number "+STR(primary_xpt) - PRINT, " at R = "+STR(INTERPOLATE(R, critical.xpt_ri[primary_xpt])) $ - +" Z = "+STR(INTERPOLATE(Z, critical.xpt_zi[primary_xpt])) + PRINT, " at R = "+STR(INTERPOLATE(R, critical.xpt_ri[primary_xpt], /DOUBLE)) $ + +" Z = "+STR(INTERPOLATE(Z, critical.xpt_zi[primary_xpt], /DOUBLE)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; work out where to put the surfaces @@ -1043,15 +1043,15 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ PRINT, "Distributing radial points automatically" n = TOTAL(nrad,/int) - fac = 2.*(xpt_f[inner_sep] - f_inner)/(1.+rad_peaking) + fac = 2.D*(xpt_f[inner_sep] - f_inner)/(1.D + rad_peaking) FOR i=1, critical.n_xpoint-1 DO fac = fac + (xpt_f[si[i]] - xpt_f[si[i-1]])/rad_peaking - fac = fac + 2.*(f_outer - xpt_f[si[critical.n_xpoint-1]])/(1.+rad_peaking) - dx0 = fac / FLOAT(n) ; Inner grid spacing + fac = fac + 2.D*(f_outer - xpt_f[si[critical.n_xpoint-1]])/(1.D + rad_peaking) + dx0 = fac / DOUBLE(n) ; Inner grid spacing ; Calculate number of grid points nrad = LONARR(critical.n_xpoint + 1) - nrad[0] = FIX( 2.*(xpt_f[inner_sep] - f_inner) / ( (1.+rad_peaking)*dx0 ) + 0.5) - FOR i=1, critical.n_xpoint-1 DO nrad[i] = FIX((xpt_f[si[i]] - xpt_f[si[i-1]])/(rad_peaking*dx0)-0.5) + nrad[0] = FIX( 2.D*(xpt_f[inner_sep] - f_inner) / ( (1.D + rad_peaking)*dx0 ) + 0.5D) + FOR i=1, critical.n_xpoint-1 DO nrad[i] = FIX((xpt_f[si[i]] - xpt_f[si[i-1]])/(rad_peaking*dx0)-0.5D) nrad[critical.n_xpoint] = n - TOTAL(nrad,/int) ;fvals = radial_grid(TOTAL(nrad), f_inner, f_outer, 1, 1, xpt_f, rad_peaking) @@ -1084,13 +1084,13 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ FOR i=2, critical.n_xpoint-1 DO fvals = [fvals, radial_grid(nrad[i], xpt_f[si[i-1]], xpt_f[si[i]], 0, 0, xpt_f, rad_peaking)] ; Core - fvals = [radial_grid(nrad[0], f_inner, 2.*xpt_f[inner_sep]-fvals[0], $ + fvals = [radial_grid(nrad[0], f_inner, 2.D*xpt_f[inner_sep]-fvals[0], $ 1, 1, xpt_f, rad_peaking, $ - out_dp=2.*(fvals[0]-xpt_f[inner_sep]), $ - in_dp=2.*(fvals[0]-xpt_f[inner_sep])/rad_peaking), fvals] + out_dp=2.D*(fvals[0]-xpt_f[inner_sep]), $ + in_dp=2.D*(fvals[0]-xpt_f[inner_sep])/rad_peaking), fvals] ENDIF ELSE BEGIN ; Only a single separatrix - dp0 = (xpt_f[inner_sep] - f_inner)*2./ (FLOAT(nrad[0])*(1. + rad_peaking)) + dp0 = (xpt_f[inner_sep] - f_inner)*2.D/ (DOUBLE(nrad[0])*(1.D + rad_peaking)) fvals = radial_grid(nrad[0], f_inner, xpt_f[inner_sep], $ 1, 0, xpt_f, rad_peaking, $ out_dp=rad_peaking*dp0, $ @@ -1099,7 +1099,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; SOL n = N_ELEMENTS(fvals) - dpsi = 2.*(xpt_f[si[critical.n_xpoint-1]] - fvals[n-1]) + dpsi = 2.D*(xpt_f[si[critical.n_xpoint-1]] - fvals[n-1]) fvals = [fvals, radial_grid(nrad[critical.n_xpoint], $ fvals[n-1]+dpsi, f_outer, 1, 1, xpt_f, rad_peaking, $ in_dp=dpsi, out_dp=dpsi/rad_peaking)] @@ -1110,8 +1110,8 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Create arrays of psi values for each region - sol_psi_vals = FLTARR(critical.n_xpoint, TOTAL(nrad,/int)) - pf_psi_vals = FLTARR(critical.n_xpoint, 2, TOTAL(nrad,/int)) + sol_psi_vals = DBLARR(critical.n_xpoint, TOTAL(nrad,/int)) + pf_psi_vals = DBLARR(critical.n_xpoint, 2, TOTAL(nrad,/int)) FOR i=0, critical.n_xpoint-1 DO BEGIN sol_psi_vals[i,*] = psi_vals pf_psi_vals[i,0,*] = psi_vals @@ -1127,7 +1127,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ENDIF PRINT, "Keeping same inner psi for all regions" - psi_inner = FLTARR(critical.n_xpoint+1) + MIN(settings.psi_inner) + psi_inner = DBLARR(critical.n_xpoint+1) + MIN(settings.psi_inner) ENDELSE IF N_ELEMENTS(settings.psi_outer) EQ critical.n_xpoint THEN BEGIN @@ -1139,7 +1139,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ENDIF PRINT, "Keeping same outer psi for all regions" - psi_outer = FLTARR(critical.n_xpoint) + MAX(settings.psi_outer) + psi_outer = DBLARR(critical.n_xpoint) + MAX(settings.psi_outer) ENDELSE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1150,7 +1150,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ;sind = FIX(nrad[0]/2) ;nrad[0]-1 ; the last point inside core ;sind = nrad[0]-1 ;f_cont = fvals[sind] - f_cont = faxis + fnorm*(0.1*psi_inner[0] + 0.9) + f_cont = faxis + fnorm*(0.1D*psi_inner[0] + 0.9D) contour_lines, F, findgen(nx), findgen(ny), levels=[f_cont], $ path_info=info, path_xy=xy @@ -1169,8 +1169,8 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; Make sure that the line goes clockwise - m = MAX(INTERPOLATE(Z, start_zi), ind) ; Find the top (maximum Z) - IF (DERIV(INTERPOLATE(R, start_ri)))[ind] LT 0.0 THEN BEGIN + m = MAX(INTERPOLATE(Z, start_zi, /DOUBLE), ind) ; Find the top (maximum Z) + IF (DERIV(INTERPOLATE(R, start_ri, /DOUBLE)))[ind] LT 0.0D THEN BEGIN ; R should be increasing at the top. Need to reverse start_ri = REVERSE(start_ri) start_zi = REVERSE(start_zi) @@ -1179,7 +1179,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; now have (start_ri, start_zi). For each x-point, find the radial ; line going through the x-point - xpt_ind = FLTARR(critical.n_xpoint) ; index into start_*i + xpt_ind = DBLARR(critical.n_xpoint) ; index into start_*i pf_info = PTRARR(critical.n_xpoint) ; Pointers to PF for each X-point @@ -1194,12 +1194,12 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; Note: add starting point to end of 'boundary' so we find intersections with a closed contour follow_gradient, interp_data, R, Z, $ legsep.core1[2,0], legsep.core1[2,1], $ - 0.95 * f_cont + 0.05*opt_f[primary_opt], $ + 0.95D * f_cont + 0.05D*opt_f[primary_opt], $ rhit, zhit, $ boundary=TRANSPOSE([[start_ri, start_ri[0]], [start_zi, start_zi[0]]]), ibndry=hit_ind1 follow_gradient, interp_data, R, Z, $ legsep.core2[2,0], legsep.core2[2,1], $ - 0.95 * f_cont + 0.05*opt_f[primary_opt], $ + 0.95D * f_cont + 0.05D*opt_f[primary_opt], $ rhit, zhit, $ boundary=TRANSPOSE([[start_ri, start_ri[0]], [start_zi, start_zi[0]]]), ibndry=hit_ind2 @@ -1209,22 +1209,22 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ REPEAT BEGIN IF MIN([ni - hit_ind2 + hit_ind1, ni - hit_ind1 + hit_ind2]) LT ABS(hit_ind2 - hit_ind1) THEN BEGIN ; One at the beginning and one at the end (across the join) - mini = (hit_ind2 + hit_ind1 - ni) / 2. - IF mini LT 0. THEN mini = mini + ni - ENDIF ELSE mini = (hit_ind1 + hit_ind2) / 2. + mini = (hit_ind2 + hit_ind1 - ni) / 2.D + IF mini LT 0.D THEN mini = mini + ni + ENDIF ELSE mini = (hit_ind1 + hit_ind2) / 2.D - ;OPLOT, [INTERPOLATE(R[start_ri], hit_ind1)], [INTERPOLATE(Z[start_zi], hit_ind1)], psym=2, color=2 - ;OPLOT, [INTERPOLATE(R[start_ri], hit_ind2)], [INTERPOLATE(Z[start_zi], hit_ind2)], psym=2, color=2 - ;OPLOT, [INTERPOLATE(R[start_ri], mini)], [INTERPOLATE(Z[start_zi], mini)], psym=2, color=4 + ;OPLOT, [INTERPOLATE(R[start_ri], hit_ind1, /DOUBLE)], [INTERPOLATE(Z[start_zi], hit_ind1, /DOUBLE)], psym=2, color=2 + ;OPLOT, [INTERPOLATE(R[start_ri], hit_ind2, /DOUBLE)], [INTERPOLATE(Z[start_zi], hit_ind2, /DOUBLE)], psym=2, color=2 + ;OPLOT, [INTERPOLATE(R[start_ri], mini, /DOUBLE)], [INTERPOLATE(Z[start_zi], mini, /DOUBLE)], psym=2, color=4 PRINT, "Theta location: " + STR(hit_ind1) + "," + STR(hit_ind2) + " -> " + STR(mini) ; Get line a little bit beyond the X-point pos = get_line(interp_data, R, Z, $ - INTERPOLATE(start_ri, mini), INTERPOLATE(start_zi, mini), $ - critical.xpt_f[i] + (critical.xpt_f[i] - opt_f[primary_opt]) * 0.05) + INTERPOLATE(start_ri, mini, /DOUBLE), INTERPOLATE(start_zi, mini, /DOUBLE), $ + critical.xpt_f[i] + (critical.xpt_f[i] - opt_f[primary_opt]) * 0.05D) - ;OPLOT, INTERPOLATE(R, pos[*,0]), INTERPOLATE(Z, pos[*,1]), color=4, thick=2 + ;OPLOT, INTERPOLATE(R, pos[*,0], /DOUBLE), INTERPOLATE(Z, pos[*,1], /DOUBLE), color=4, thick=2 ; Find which separatrix line this intersected with cpos = line_crossings([xpt_ri[i], legsep.core1[*,0]], $ @@ -1237,24 +1237,24 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ hit_ind2 = mini ENDELSE dist = MIN([ni - hit_ind2 + hit_ind1, ni - hit_ind1 + hit_ind2, ABS([hit_ind2 - hit_ind1])]) - ENDREP UNTIL dist LT 0.1 + ENDREP UNTIL dist LT 0.1D IF MIN([ni - hit_ind2 + hit_ind1, ni - hit_ind1 + hit_ind2]) LT ABS(hit_ind2 - hit_ind1) THEN BEGIN ; One at the beginning and one at the end (across the join) - mini = (hit_ind2 + hit_ind1 - ni) / 2. - IF mini LT 0. THEN mini = mini + ni - ENDIF ELSE mini = (hit_ind1 + hit_ind2) / 2. + mini = (hit_ind2 + hit_ind1 - ni) / 2.D + IF mini LT 0.D THEN mini = mini + ni + ENDIF ELSE mini = (hit_ind1 + hit_ind2) / 2.D xpt_ind[i] = mini ; Record the index ; Plot the line to the x-point oplot_line, interp_data, R, Z, $ - INTERPOLATE(start_ri, mini), INTERPOLATE(start_zi, mini), critical.xpt_f[i] + INTERPOLATE(start_ri, mini, /DOUBLE), INTERPOLATE(start_zi, mini, /DOUBLE), critical.xpt_f[i] oplot_line, interp_data, R, Z, $ - INTERPOLATE(start_ri, mini), INTERPOLATE(start_zi, mini), f_inner + INTERPOLATE(start_ri, mini, /DOUBLE), INTERPOLATE(start_zi, mini, /DOUBLE), f_inner ; Get tangent vector - drdi = INTERPOLATE((DERIV(INTERPOLATE(R, start_ri))), mini) - dzdi = INTERPOLATE((DERIV(INTERPOLATE(Z, start_zi))), mini) + drdi = INTERPOLATE((DERIV(INTERPOLATE(R, start_ri, /DOUBLE))), mini, /DOUBLE) + dzdi = INTERPOLATE((DERIV(INTERPOLATE(Z, start_zi, /DOUBLE))), mini, /DOUBLE) tmp = {core_ind:mini, drdi:drdi, dzdi:dzdi, $ ; Core index and tangent vector sol:LONARR(2)} ; Array to store SOL indices @@ -1269,40 +1269,40 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ sol_info = PTRARR(critical.n_xpoint) FOR i=0, critical.n_xpoint-1 DO BEGIN IF i NE (critical.n_xpoint-1) THEN BEGIN - ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]]), $ - start_ri[FIX(xpt_ind[ci[i]]+1.0):FIX(xpt_ind[ci[i+1]])], $ - INTERPOLATE(start_ri,xpt_ind[ci[i+1]]) ] + ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]], /DOUBLE), $ + start_ri[FIX(xpt_ind[ci[i]]+1.0D):FIX(xpt_ind[ci[i+1]])], $ + INTERPOLATE(start_ri,xpt_ind[ci[i+1]], /DOUBLE) ] - zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]]), $ - start_zi[FIX(xpt_ind[ci[i]]+1.0):FIX(xpt_ind[ci[i+1]])], $ - INTERPOLATE(start_zi,xpt_ind[ci[i+1]]) ] + zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]], /DOUBLE), $ + start_zi[FIX(xpt_ind[ci[i]]+1.0D):FIX(xpt_ind[ci[i+1]])], $ + INTERPOLATE(start_zi,xpt_ind[ci[i+1]], /DOUBLE) ] ENDIF ELSE BEGIN ; Index wraps around IF xpt_ind[ci[i]] GT N_ELEMENTS(start_ri)-2 THEN BEGIN - ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]]), $ + ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]], /DOUBLE), $ start_ri[0:FIX(xpt_ind[ci[0]])], $ - INTERPOLATE(start_ri,xpt_ind[ci[0]]) ] + INTERPOLATE(start_ri,xpt_ind[ci[0]], /DOUBLE) ] - zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]]), $ + zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]], /DOUBLE), $ start_zi[0:FIX(xpt_ind[ci[0]])], $ - INTERPOLATE(start_zi,xpt_ind[ci[0]]) ] + INTERPOLATE(start_zi,xpt_ind[ci[0]], /DOUBLE) ] ENDIF ELSE BEGIN - ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]]), $ - start_ri[FIX(xpt_ind[ci[i]]+1.0):*], $ + ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]], /DOUBLE), $ + start_ri[FIX(xpt_ind[ci[i]]+1.0D):*], $ start_ri[0:FIX(xpt_ind[ci[0]])], $ - INTERPOLATE(start_ri,xpt_ind[ci[0]]) ] + INTERPOLATE(start_ri,xpt_ind[ci[0]], /DOUBLE) ] - zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]]), $ - start_zi[FIX(xpt_ind[ci[i]]+1.0):*], $ + zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]], /DOUBLE), $ + start_zi[FIX(xpt_ind[ci[i]]+1.0D):*], $ start_zi[0:FIX(xpt_ind[ci[0]])], $ - INTERPOLATE(start_zi,xpt_ind[ci[0]]) ] + INTERPOLATE(start_zi,xpt_ind[ci[0]], /DOUBLE) ] ENDELSE ENDELSE ; Calculate length of the line - drdi = DERIV(INTERPOLATE(R, ri)) - dzdi = DERIV(INTERPOLATE(Z, zi)) + drdi = DERIV(INTERPOLATE(R, ri, /DOUBLE)) + dzdi = DERIV(INTERPOLATE(Z, zi, /DOUBLE)) dldi = SQRT(drdi^2 + dzdi^2) IF KEYWORD_SET(simple) THEN BEGIN length = INT_TRAPEZOID(findgen(N_ELEMENTS(dldi)), dldi) @@ -1336,7 +1336,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ IF KEYWORD_SET(nrad_flexible) THEN nrad = TOTAL(nrad,/int) ; Allow nrad to change again - new_settings = {psi_inner:psi_inner, psi_outer:(max(xpt_psi)+0.02), $ + new_settings = {psi_inner:psi_inner, psi_outer:(max(xpt_psi)+0.02D), $ nrad:nrad, npol:settings.npol, $ rad_peaking:settings.rad_peaking, pol_peaking:settings.pol_peaking} RETURN, create_grid(F, R, Z, new_settings, critical=critical, $ @@ -1382,14 +1382,14 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; Gridding as one region IF (npf+1) LT TOTAL(nrad,/int) THEN BEGIN dpsi = pf_psi_vals[xind,0,npf+1] - pf_psi_vals[xind,0,npf] - pf_psi_out = (pf_psi_vals[xind,0,npf] - 0.5*dpsi) < xpt_psi[xind] + pf_psi_out = (pf_psi_vals[xind,0,npf] - 0.5D*dpsi) < xpt_psi[xind] pf_psi_vals[xind,0,0:(npf-1)] = radial_grid(npf, psi_inner[id+1], $ pf_psi_out, $ 1, 0, $ [xpt_psi[xind]], settings.rad_peaking, $ out_dp=dpsi) ENDIF ELSE BEGIN - pf_psi_out = (pf_psi_vals[xind,0,npf] - 0.5*dpsi) < xpt_psi[xind] + pf_psi_out = (pf_psi_vals[xind,0,npf] - 0.5D*dpsi) < xpt_psi[xind] pf_psi_vals[xind,0,0:(npf-1)] = radial_grid(npf, psi_inner[id+1], $ pf_psi_out, $ 1, 0, $ @@ -1425,14 +1425,14 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; Use the tangent vector to determine direction ; relative to core and so get direction of positive theta - drdi = INTERPOLATE((DERIV(INTERPOLATE(R, pf_ri))), mini) - dzdi = INTERPOLATE((DERIV(INTERPOLATE(Z, pf_zi))), mini) + drdi = INTERPOLATE((DERIV(INTERPOLATE(R, pf_ri, /DOUBLE))), mini, /DOUBLE) + dzdi = INTERPOLATE((DERIV(INTERPOLATE(Z, pf_zi, /DOUBLE))), mini, /DOUBLE) - IF drdi * (*pf_info[xind]).drdi + dzdi * (*pf_info[xind]).dzdi GT 0.0 THEN BEGIN + IF drdi * (*pf_info[xind]).drdi + dzdi * (*pf_info[xind]).dzdi GT 0.0D THEN BEGIN ; Line is parallel to the core. Need to reverse pf_ri = REVERSE(pf_ri) pf_zi = REVERSE(pf_zi) - mini = N_ELEMENTS(pf_ri) - 1. - mini + mini = N_ELEMENTS(pf_ri) - 1.D - mini temp = N_ELEMENTS(pf_ri) - 1 - pf_wallind2 pf_wallind2 = N_ELEMENTS(pf_ri) - 1 - pf_wallind1 pf_wallind1 = temp @@ -1480,21 +1480,21 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; Put the starting line into the pf_info structure tmp = CREATE_STRUCT(*(pf_info[xind]), $ 'npf', npf, $ ; Number of radial points in this PF region - 'ri0', [pf_ri[0:mini], INTERPOLATE(pf_ri, mini)], $ - 'zi0', [pf_zi[0:mini], INTERPOLATE(pf_zi, mini)], $ + 'ri0', [pf_ri[0:mini], INTERPOLATE(pf_ri, mini, /DOUBLE)], $ + 'zi0', [pf_zi[0:mini], INTERPOLATE(pf_zi, mini, /DOUBLE)], $ 'wallind0', pf_wallind1, $ - 'ri1', [INTERPOLATE(pf_ri, mini), pf_ri[(mini+1):*]], $ - 'zi1', [INTERPOLATE(pf_zi, mini), pf_zi[(mini+1):*]], $ + 'ri1', [INTERPOLATE(pf_ri, mini, /DOUBLE), pf_ri[(mini+1):*]], $ + 'zi1', [INTERPOLATE(pf_zi, mini, /DOUBLE), pf_zi[(mini+1):*]], $ 'wallind1', pf_wallind2 - mini) ; Calculate length of each section - dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri0[tmp.wallind0:*]))^2 + DERIV(INTERPOLATE(Z, tmp.zi0[tmp.wallind0:*]))^2) + dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri0[tmp.wallind0:*], /DOUBLE))^2 + DERIV(INTERPOLATE(Z, tmp.zi0[tmp.wallind0:*], /DOUBLE))^2) IF KEYWORD_SET(simple) THEN BEGIN len0 = INT_TRAPEZOID(FINDGEN(N_ELEMENTS(dldi)), dldi) ENDIF ELSE BEGIN len0 = INT_TABULATED(FINDGEN(N_ELEMENTS(dldi)), dldi) ENDELSE - dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri1[0:tmp.wallind1]))^2 + DERIV(INTERPOLATE(Z, tmp.zi1[0:tmp.wallind1]))^2) + dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri1[0:tmp.wallind1], /DOUBLE))^2 + DERIV(INTERPOLATE(Z, tmp.zi1[0:tmp.wallind1], /DOUBLE))^2) IF KEYWORD_SET(simple) THEN BEGIN len1 = INT_TRAPEZOID(FINDGEN(N_ELEMENTS(dldi)), dldi) ENDIF ELSE BEGIN @@ -1546,7 +1546,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ n_y_boundary_guards = LONARR(3*critical.n_xpoint) ; Get lengths - length = FLTARR(3*critical.n_xpoint) + length = DBLARR(3*critical.n_xpoint) FOR i=0, critical.n_xpoint-1 DO BEGIN ; PF regions length[i] = (*pf_info[i]).len0 @@ -1558,9 +1558,9 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ FOR i=0, n_update-1 DO BEGIN ; Add an extra point to the longest length - dl = length / FLOAT(npol) + dl = length / DOUBLE(npol) dl[0:(2*critical.n_xpoint-1)] = length[0:(2*critical.n_xpoint-1)] $ - / (FLOAT(npol[0:(2*critical.n_xpoint-1)]) - 0.5) + / (DOUBLE(npol[0:(2*critical.n_xpoint-1)]) - 0.5D) m = MAX(dl, ind) npol[ind] = npol[ind] + 1 @@ -1600,7 +1600,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ; Calculate distance for equal spacing in each region xpt = si[0] ; Start with the innermost x-point - xpt_dist = FLTARR(critical.n_xpoint, 4) ; Distance between x-point and first grid point + xpt_dist = DBLARR(critical.n_xpoint, 4) ; Distance between x-point and first grid point ; NOTE: xpt_dist indices go clockwise around the X-point, starting ; from the lower left leg when the core is at the top. @@ -1621,7 +1621,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ wallind = (*pf_info[xpt]).wallind0 poldist = line_dist(R, Z, (*pf_info[xpt]).ri0[wallind:*], (*pf_info[xpt]).zi0[wallind:*]) ; Poloidal distance along line - xdist = MAX(poldist) * 0.5 / FLOAT(npol[3*i]) ; Equal spacing + xdist = MAX(poldist) * 0.5D / DOUBLE(npol[3*i]) ; Equal spacing xpt_dist[xpt, 0] = xdist @@ -1629,7 +1629,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ solid = (*pf_info[xpt]).sol[0] poldist = line_dist(R, Z, (*sol_info[solid]).ri, (*sol_info[solid]).zi) - xdist = MAX(poldist) * 0.5 / FLOAT(npol[3*i+1]) + xdist = MAX(poldist) * 0.5D / DOUBLE(npol[3*i+1]) PRINT, "S :", solid, max(poldist), npol[3*i+1] @@ -1643,7 +1643,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ wallind = (*pf_info[xpt]).wallind1 poldist = line_dist(R, Z, (*pf_info[xpt]).ri1[0:wallind], (*pf_info[xpt]).zi1[0:wallind]) - xdist = MAX(poldist) * 0.5 / FLOAT(npol[3*i+2]) + xdist = MAX(poldist) * 0.5D / DOUBLE(npol[3*i+2]) xpt_dist[xpt, 3] = xdist ENDFOR @@ -1651,7 +1651,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ FOR i=0, critical.n_xpoint-1 DO BEGIN md = MAX(xpt_dist[i,*]) - xpt_dist[i,*] = 0.5*xpt_dist[i,*] + 0.5*md + xpt_dist[i,*] = 0.5D*xpt_dist[i,*] + 0.5D*md ENDFOR ; Try to equalise @@ -1686,9 +1686,9 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ sepi = INTERPOL(findgen(N_ELEMENTS(dist)), dist, ydown_dist) ; Index into separatrix ; Follow from sep_info[i]->core2 to just inside starting f line = get_line(interp_data, R, Z, $ - INTERPOLATE((*sep_info[xpt]).core2_ri, sepi), $ - INTERPOLATE((*sep_info[xpt]).core2_zi, sepi), $ - 0.95*f_cont + 0.05*faxis, npt=30) + INTERPOLATE((*sep_info[xpt]).core2_ri, sepi, /DOUBLE), $ + INTERPOLATE((*sep_info[xpt]).core2_zi, sepi, /DOUBLE), $ + 0.95D*f_cont + 0.05D*faxis, npt=30) ; Find intersection of this line with starting line cpos = line_crossings((*sol_info[solid]).ri, (*sol_info[solid]).zi, 0, $ line[*,0], line[*,1], 0, ncross=ncross, inds1=start_ind) @@ -1699,7 +1699,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ start_ind = start_ind[0] ; Got index into the starting line ; Find out distance along starting line dist = line_dist(R, Z, (*sol_info[solid]).ri, (*sol_info[solid]).zi) - d = INTERPOLATE(dist, start_ind) + d = INTERPOLATE(dist, start_ind, /DOUBLE) ydown_dist = MIN([d, dist[N_ELEMENTS(dist)-1] - d]) ENDELSE @@ -1712,9 +1712,9 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ sepi = INTERPOL(findgen(N_ELEMENTS(dist)), dist, yup_dist) ; Index into separatrix ; Follow from sep_info[i]->core1 to just inside starting f line = get_line(interp_data, R, Z, $ - INTERPOLATE((*sep_info[xpt2]).core1_ri, sepi), $ - INTERPOLATE((*sep_info[xpt2]).core1_zi, sepi), $ - 0.95*f_cont + 0.05*faxis, npt=30) + INTERPOLATE((*sep_info[xpt2]).core1_ri, sepi, /DOUBLE), $ + INTERPOLATE((*sep_info[xpt2]).core1_zi, sepi, /DOUBLE), $ + 0.95D*f_cont + 0.05D*faxis, npt=30) ; Find intersection of this line with starting line cpos = line_crossings((*sol_info[solid]).ri, (*sol_info[solid]).zi, 0, $ line[*,0], line[*,1], 0, ncross=ncross, inds1=start_ind) @@ -1724,7 +1724,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ start_ind = start_ind[0] ; Got index into the starting line ; Find out distance along starting line dist = line_dist(R, Z, (*sol_info[solid]).ri, (*sol_info[solid]).zi) - yup_dist = MAX(dist) - INTERPOLATE(dist, start_ind) + yup_dist = MAX(dist) - INTERPOLATE(dist, start_ind, /DOUBLE) ENDELSE xpt_dist[xpt2, 2] = yup_dist @@ -1746,14 +1746,14 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ gridbndry = bndryi ENDIF ELSE BEGIN ; Grid can leave boundary - gridbndry = FLTARR(2,4) + gridbndry = DBLARR(2,4) gridbndry[0,*] = [0, 0, nx-1, nx-1] gridbndry[1,*] = [0, ny-1, ny-1, 0] ENDELSE ENDIF ; Create 2D arrays for the grid - Rxy = FLTARR(TOTAL(nrad,/int), npol_total) + Rxy = DBLARR(TOTAL(nrad,/int), npol_total) Zxy = Rxy Rixy = Rxy Zixy = Rxy @@ -1846,8 +1846,8 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ ydown_dist = xpt_dist[xpt, 1] yup_dist = xpt_dist[xpt2, 2] ; Grid spacing - ydown_space = MAX([xpt_dist[xpt, 1], xpt_dist[xpt, 2]]) ;0.5*(xpt_dist[xpt, 1] + xpt_dist[xpt, 2]) - yup_space = MAX([xpt_dist[xpt2, 1], xpt_dist[xpt2, 2]]) ;0.5*(xpt_dist[xpt2, 1] + xpt_dist[xpt2, 2]) + ydown_space = MAX([xpt_dist[xpt, 1], xpt_dist[xpt, 2]]) ;0.5D*(xpt_dist[xpt, 1] + xpt_dist[xpt, 2]) + yup_space = MAX([xpt_dist[xpt2, 1], xpt_dist[xpt2, 2]]) ;0.5D*(xpt_dist[xpt2, 1] + xpt_dist[xpt2, 2]) a = grid_region(interp_data, R, Z, $ (*sol_info[solid]).ri, (*sol_info[solid]).zi, $ @@ -1998,7 +1998,7 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ rad_peaking:settings.rad_peaking, pol_peaking:settings.pol_peaking} ; Calculate magnetic field components - dpsidR = FLTARR(TOTAL(nrad, /int), npol_total) + dpsidR = DBLARR(TOTAL(nrad, /int), npol_total) dpsidZ = dpsidR interp_data.method = 2 @@ -2008,8 +2008,8 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ local_gradient, interp_data, Rixy[i,j], Zixy[i,j], status=status, $ dfdr=dfdr, dfdz=dfdz ; dfd* are derivatives wrt the indices. Need to multiply by dr/di etc - dpsidR[i,j] = dfdr/INTERPOLATE(DERIV(R),Rixy[i,j]) - dpsidZ[i,j] = dfdz/INTERPOLATE(DERIV(Z),Zixy[i,j]) + dpsidR[i,j] = dfdr/INTERPOLATE(DERIV(R),Rixy[i,j], /DOUBLE) + dpsidZ[i,j] = dfdz/INTERPOLATE(DERIV(Z),Zixy[i,j], /DOUBLE) ENDFOR ENDFOR diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index 20013c0229..8c68880475 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -118,8 +118,8 @@ PRO lengthen_line, r0, z0, r1, z1 m = (z1 - z0) / (r1 - r0) b = z0 - r0*m - r1 = [1.05*r1] - r0 = [0.95*r0] + r1 = [1.05D*r1] + r0 = [0.95D*r0] z1 = [m*r1 + b] z0 = [m*r0 + b] @@ -158,7 +158,7 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe ydown_firstind=ydown_firstind, $ yup_lastind=yup_lastind - IF NOT KEYWORD_SET(parweight) THEN parweight = 0.0 ; Default is poloidal distance + IF NOT KEYWORD_SET(parweight) THEN parweight = 0.0D ; Default is poloidal distance np = N_ELEMENTS(ri) @@ -186,8 +186,8 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe IF 0 THEN BEGIN ; Always false ; Calculate poloidal distance along starting line - drdi = DERIV(INTERPOLATE(R, ri)) - dzdi = DERIV(INTERPOLATE(Z, zi)) + drdi = DERIV(INTERPOLATE(R, ri, /DOUBLE)) + dzdi = DERIV(INTERPOLATE(Z, zi, /DOUBLE)) dldi = SQRT(drdi^2 + dzdi^2) poldist = int_func(findgen(np), dldi, /simple) ; Poloidal distance along line @@ -195,11 +195,11 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe ; reset poldist to start at zero at the ydown wall (if one is present) poldist = poldist - poldist[ydown_firstind] ENDIF ELSE BEGIN - rpos = INTERPOLATE(R, ri) - zpos = INTERPOLATE(Z, zi) + rpos = INTERPOLATE(R, ri, /DOUBLE) + zpos = INTERPOLATE(Z, zi, /DOUBLE) dd = SQRT((zpos[1:*] - zpos[0:(np-2)])^2 + (rpos[1:*] - rpos[0:(np-2)])^2) dd = [dd, SQRT((zpos[0] - zpos[np-1])^2 + (rpos[0] - rpos[np-1])^2)] - poldist = FLTARR(np) + poldist = DBLARR(np) FOR i=1,np-1 DO poldist[i] = poldist[i-1] + dd[i-1] ; reset poldist to start at zero at the ydown wall (if one is present) @@ -210,31 +210,31 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe ; Parallel distance along line ; Need poloidal and toroidal field ni = N_ELEMENTS(ri) - bp = FLTARR(ni) - bt = FLTARR(ni) + bp = DBLARR(ni) + bt = DBLARR(ni) m = interp_data.method interp_data.method = 2 FOR i=0, ni-1 DO BEGIN local_gradient, interp_data, ri[i], zi[i], status=status, $ f=f, dfdr=dfdr, dfdz=dfdz ; dfd* are derivatives wrt the indices. Need to multiply by dr/di etc - dfdr /= INTERPOLATE(DERIV(R),ri[i]) - dfdz /= INTERPOLATE(DERIV(Z),zi[i]) + dfdr /= INTERPOLATE(DERIV(R),ri[i], /DOUBLE) + dfdz /= INTERPOLATE(DERIV(Z),zi[i], /DOUBLE) IF i EQ 0 THEN BEGIN btr = INTERPOL(REFORM(fpsi[1,*]), REFORM(fpsi[0,*]), f) ENDIF - bp[i] = SQRT(dfdr^2 + dfdz^2) / INTERPOLATE(R, ri[i]) - bt[i] = ABS( btr / INTERPOLATE(R, ri[i])) + bp[i] = SQRT(dfdr^2 + dfdz^2) / INTERPOLATE(R, ri[i], /DOUBLE) + bt[i] = ABS( btr / INTERPOLATE(R, ri[i], /DOUBLE)) ENDFOR interp_data.method = m b = SQRT(bt^2 + bp^2) ddpar = dd * b / bp - pardist = FLTARR(np) + pardist = DBLARR(np) FOR i=1,np-1 DO BEGIN ip = (i + 1) MOD np - pardist[i] = pardist[i-1] + ddpar[i] ;0.5*(ddpar[i-1] + ddpar[ip]) + pardist[i] = pardist[i-1] + ddpar[i] ;0.5D*(ddpar[i-1] + ddpar[ip]) ENDFOR ; reset pardist to start at zero at the ydown wall (if one is present) @@ -243,48 +243,48 @@ FUNCTION poloidal_grid, interp_data, R, Z, ri, zi, n, fpsi=fpsi, parweight=parwe PRINT, "PARWEIGHT: ", parweight - dist = parweight*pardist + (1. - parweight)*poldist + dist = parweight*pardist + (1.D - parweight)*poldist ; Divide up distance. No points at the end (could be x-point) IF n GE 2 THEN BEGIN ; note dist[ydown_firstind] should be 0., but include here anyway total_dist = dist[yup_lastind] - dist[ydown_firstind] - IF SIZE(ydown_dist, /TYPE) EQ 0 THEN ydown_dist = total_dist * 0.5 / FLOAT(n) - IF SIZE(yup_dist, /TYPE) EQ 0 THEN yup_dist = total_dist * 0.5 / FLOAT(n) + IF SIZE(ydown_dist, /TYPE) EQ 0 THEN ydown_dist = total_dist * 0.5D / DOUBLE(n) + IF SIZE(yup_dist, /TYPE) EQ 0 THEN yup_dist = total_dist * 0.5D / DOUBLE(n) IF SIZE(ydown_space, /TYPE) EQ 0 THEN BEGIN - IF ydown_dist LT 1e-5 THEN BEGIN + IF ydown_dist LT 1d-5 THEN BEGIN ; Small (probably zero) dist - ydown_space = dist[np-1]* 0.5 / FLOAT(n-1) + ydown_space = dist[np-1]* 0.5D / DOUBLE(n-1) ENDIF ELSE ydown_space = ydown_dist ENDIF IF SIZE(yup_space, /TYPE) EQ 0 THEN BEGIN - IF yup_dist LT 1e-5 THEN BEGIN - yup_space = dist[np-1] * 0.5 / FLOAT(n-1) + IF yup_dist LT 1d-5 THEN BEGIN + yup_space = dist[np-1] * 0.5D / DOUBLE(n-1) ENDIF ELSE yup_space = yup_dist ENDIF - ;dloc = (dist[np-1] - ydown_dist - yup_dist) * FINDGEN(n)/FLOAT(n-1) + ydown_dist ; Distance locations + ;dloc = (dist[np-1] - ydown_dist - yup_dist) * FINDGEN(n)/DOUBLE(n-1) + ydown_dist ; Distance locations - fn = FLOAT(n-1) + fn = DOUBLE(n-1) d = (total_dist - ydown_dist - yup_dist) ; Distance between first and last i = FINDGEN(n + boundary_guards_ydown + boundary_guards_yup) ; igrid starts at zero in the first grid cell (excludes boundary guard cells) igrid = i - boundary_guards_ydown - yd = ydown_space < 0.5*d/fn - yu = yup_space < 0.5*d/fn + yd = ydown_space < 0.5D*d/fn + yu = yup_space < 0.5D*d/fn ; Fit to ai + bi^2 + c[i-sin(2pi*i/(n-1))*(n-1)/(2pi)] - a = yd*2. - b = (2.*yu - a) / fn - c = d/fn - a - 0.5*b*fn - dloc = ydown_dist + a*igrid + 0.5*b*igrid^2 + c*[igrid - SIN(2.*!PI*igrid / fn)*fn/(2.*!PI)] - ddloc = a + b*igrid + c*[1 - COS(2.*!PI*igrid / fn)] + a = yd*2.D + b = (2.D*yu - a) / fn + c = d/fn - a - 0.5D*b*fn + dloc = ydown_dist + a*igrid + 0.5D*b*igrid^2 + c*[igrid - SIN(2.D*!DPI*igrid / fn)*fn/(2.D*!DPI)] + ddloc = a + b*igrid + c*[1.D - COS(2.D*!DPI*igrid / fn)] ; Fit to dist = a*i^3 + b*i^2 + c*i - ;; c = ydown_dist*2. - ;; b = 3.*(d/fn^2 - c/fn) - 2.*yup_dist/fn + c/fn + ;; c = ydown_dist*2.D + ;; b = 3.D*(d/fn^2 - c/fn) - 2.D*yup_dist/fn + c/fn ;; a = d/fn^3 - c/fn^2 - b/fn ;; dloc = ydown_dist + c*i + b*i^2 + a*i^3 @@ -386,8 +386,8 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ydown_firstind=ydown_firstind, $ yup_lastind=yup_lastind) - rii = INTERPOLATE(ri, ind) - zii = INTERPOLATE(zi, ind) + rii = INTERPOLATE(ri, ind, /DOUBLE) + zii = INTERPOLATE(zi, ind, /DOUBLE) ;rii = int_func(SMOOTH(deriv(rii), 3), /simple) + rii[0] ;zii = int_func(SMOOTH(deriv(zii), 3), /simple) + zii[0] @@ -402,8 +402,8 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ; From each starting point, follow gradient in both directions - rixy = FLTARR(nsurf, npar_total) - zixy = FLTARR(nsurf, npar_total) + rixy = DBLARR(nsurf, npar_total) + zixy = DBLARR(nsurf, npar_total) FOR i=0, npar_total-1 DO BEGIN ; igrid is the index starting from zero on the first grid point after any @@ -416,10 +416,10 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ENDIF ELSE sep = fvals[nin] IF KEYWORD_SET(sep_line_up) THEN BEGIN sep_line = sep_line_up - OPLOT, INTERPOLATE(R, REFORM(sep_line_up[0,*])), $ - INTERPOLATE(Z, REFORM(sep_line_up[1,*])), $ + OPLOT, INTERPOLATE(R, REFORM(sep_line_up[0,*]), /DOUBLE), $ + INTERPOLATE(Z, REFORM(sep_line_up[1,*]), /DOUBLE), $ thick=2,color=3 - ENDIF ELSE sep_line = FLTARR(2,2) + ENDIF ELSE sep_line = DBLARR(2,2) ENDIF ELSE BEGIN ; PRINT, "***** DOWN *****" IF KEYWORD_SET(sep_down) THEN BEGIN @@ -428,10 +428,10 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ IF KEYWORD_SET(sep_line_down) THEN BEGIN sep_line = sep_line_down - OPLOT, INTERPOLATE(R, REFORM(sep_line_down[0,*])), $ - INTERPOLATE(Z, REFORM(sep_line_down[1,*])), $ + OPLOT, INTERPOLATE(R, REFORM(sep_line_down[0,*]), /DOUBLE), $ + INTERPOLATE(Z, REFORM(sep_line_down[1,*]), /DOUBLE), $ thick=2,color=2 - ENDIF ELSE sep_line = FLTARR(2,2) + ENDIF ELSE sep_line = DBLARR(2,2) ENDELSE ; 0 <= iweight <= npar-1 @@ -439,12 +439,12 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ IF iweight LT 0 THEN iweight = 0 IF iweight GT npar - 1 THEN iweight = npar - 1 - IF NOT KEYWORD_SET(nonorthogonal_weight_decay_power) THEN nonorthogonal_weight_decay_power = 0 + IF NOT KEYWORD_SET(nonorthogonal_weight_decay_power) THEN nonorthogonal_weight_decay_power = 0.D IF NOT KEYWORD_SET(orthup) THEN orthup=0 - IF orthup EQ 1 THEN weight_up = 0 ELSE weight_up = (iweight/(npar-1.))^nonorthogonal_weight_decay_power + IF orthup EQ 1 THEN weight_up = 0 ELSE weight_up = (iweight/(npar-1.D))^nonorthogonal_weight_decay_power IF NOT KEYWORD_SET(orthdown) THEN orthdown=0 - IF orthdown EQ 1 THEN weight_down = 0 ELSE weight_down = (1.-iweight/(npar-1.))^nonorthogonal_weight_decay_power + IF orthdown EQ 1 THEN weight_down = 0 ELSE weight_down = (1.D - iweight/(npar-1.D))^nonorthogonal_weight_decay_power ; Refine the location of the starting point follow_gradient_nonorth, interp_data, R, Z, rii[i], zii[i], f0, ri1, zi1, $ @@ -479,7 +479,7 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ vec_down=vec_in_down, weight_down=weight_down, /bndry_noperiodic ; If hits the separatrix, should now continue from ; the separatrix line - OPLOT, [INTERPOLATE(R, rinext)], [INTERPOLATE(Z, zinext)], psym=4, color=5 + OPLOT, [INTERPOLATE(R, rinext, /DOUBLE)], [INTERPOLATE(Z, zinext, /DOUBLE)], psym=4, color=5 ; PRINT, "FOLLOWING OUTER" follow_gradient_nonorth, interp_data, R, Z, rinext, zinext, $ @@ -505,17 +505,17 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ENDELSE IF status EQ 1 THEN BEGIN - rixy[nin+j+1, i] = -1.0 + rixy[nin+j+1, i] = -1.0D IF nin+j LT slast THEN slast = nin+j ; last good surface index fbndry = fvals[slast] - IF (fvals[1] - fvals[0])*(flast - fbndry) GT 0 THEN flast = 0.95*fbndry + 0.05*f0 + IF (fvals[1] - fvals[0])*(flast - fbndry) GT 0 THEN flast = 0.95D*fbndry + 0.05D*f0 BREAK ENDIF ELSE IF status EQ 2 THEN BEGIN ; Hit a boundary rixy[nin+j+1, i] = rinext zixy[nin+j+1, i] = zinext IF nin+j LT slast THEN slast = nin+j ; Set the last point - IF (fvals[1] - fvals[0])*(flast - fbndry) GT 0 THEN flast = 0.95*fbndry + 0.05*f0 + IF (fvals[1] - fvals[0])*(flast - fbndry) GT 0 THEN flast = 0.95D*fbndry + 0.05D*f0 BREAK ENDIF ELSE BEGIN rixy[nin+j+1, i] = rinext @@ -540,10 +540,10 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ vec_down=vec_down, weight_down=weight_down IF status EQ 1 THEN BEGIN - rixy[nin-j-1, i] = -1.0 + rixy[nin-j-1, i] = -1.0D IF nin-j GT sfirst THEN sfirst = nin-j fbndry = fvals[sfirst] - IF (fvals[1] - fvals[0])*(ffirst - fbndry) LT 0 THEN ffirst = 0.95*fbndry + 0.05*f0 + IF (fvals[1] - fvals[0])*(ffirst - fbndry) LT 0 THEN ffirst = 0.95D*fbndry + 0.05D*f0 BREAK ENDIF @@ -552,7 +552,7 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ IF status EQ 2 THEN BEGIN IF nin-j GT sfirst THEN sfirst = nin-j - IF (fvals[1] - fvals[0])*(ffirst - fbndry) LT 0 THEN ffirst = 0.95*fbndry + 0.05*f0 + IF (fvals[1] - fvals[0])*(ffirst - fbndry) LT 0 THEN ffirst = 0.95D*fbndry + 0.05D*f0 BREAK ENDIF ENDFOR @@ -563,17 +563,17 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ dr = rixy[nin-1,i] - rixy[nin-2,i] dz = zixy[nin-1,i] - zixy[nin-2,i] - r1 = [ rixy[nin-1,i] - 1000*dr, rixy[nin-1,i] + 1000*dr ] - z1 = [ zixy[nin-1,i] - 1000*dz, zixy[nin-1,i] + 1000*dz ] + r1 = [ rixy[nin-1,i] - 1000.D*dr, rixy[nin-1,i] + 1000.D*dr ] + z1 = [ zixy[nin-1,i] - 1000.D*dz, zixy[nin-1,i] + 1000.D*dz ] ; Second line going through first point in SOL, along line vec_out - ;r2 = [ rixy[nin+1,i] - 1000*vec_out[0], rixy[nin+1,i] + 1000*vec_out[0] ] - ;z2 = [ zixy[nin+1,i] - 1000*vec_out[1], zixy[nin+1,i] + 1000*vec_out[1] ] + ;r2 = [ rixy[nin+1,i] - 1000.D*vec_out[0], rixy[nin+1,i] + 1000.D*vec_out[0] ] + ;z2 = [ zixy[nin+1,i] - 1000.D*vec_out[1], zixy[nin+1,i] + 1000.D*vec_out[1] ] dr = rixy[nin+1,i] - rixy[nin+2,i] dz = zixy[nin+1,i] - zixy[nin+2,i] - r2 = [ rixy[nin+1,i] - 1000*dr, rixy[nin+1,i] + 1000*dr ] - z2 = [ zixy[nin+1,i] - 1000*dz, zixy[nin+1,i] + 1000*dz ] + r2 = [ rixy[nin+1,i] - 1000.D*dr, rixy[nin+1,i] + 1000.D*dr ] + z2 = [ zixy[nin+1,i] - 1000.D*dz, zixy[nin+1,i] + 1000.D*dz ] ; Check the angle between the two lines dr1 = r1[1] - r1[0] @@ -583,7 +583,7 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ costheta = ABS( dr1*dr2 + dz1*dz2 ) / ( SQRT(dr1^2 + dz1^2)*SQRT(dr2^2 + dz2^2) ) ncross = 0 - IF costheta LT 0.7 THEN BEGIN ; Angle greater than 45 degrees + IF costheta LT 0.7D THEN BEGIN ; Angle greater than 45 degrees ; Find intersection of the two lines cross = line_crossings(r1,z1, 0, r2,z2, 0, ncross=ncross) @@ -591,8 +591,8 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ IF ncross EQ 1 THEN BEGIN ; Set location to be half-way between the intersection ; and the first core point - rixy[nin,i] = 0.5*(cross[0,0] + rixy[nin-1,i]) - zixy[nin,i] = 0.5*(cross[1,0] + zixy[nin-1,i]) + rixy[nin,i] = 0.5D*(cross[0,0] + rixy[nin-1,i]) + zixy[nin,i] = 0.5D*(cross[1,0] + zixy[nin-1,i]) ENDIF ENDIF ELSE BEGIN ; Probably not near an X-point. Follow gradient to refine location @@ -604,18 +604,18 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ ENDELSE IF KEYWORD_SET(oplot) THEN BEGIN - OPLOT, INTERPOLATE(R, rixy[*, i]), INTERPOLATE(Z, zixy[*, i]), color=4 + OPLOT, INTERPOLATE(R, rixy[*, i], /DOUBLE), INTERPOLATE(Z, zixy[*, i], /DOUBLE), color=4 ENDIF - ;PLOT, INTERPOLATE(R, rixy[*, i]), INTERPOLATE(Z, zixy[*, i]), color=1,psym=1 - ;OPLOT, [INTERPOLATE(R, rixy[nin, i])], [INTERPOLATE(Z, zixy[nin, i])], color=4,psym=4 + ;PLOT, INTERPOLATE(R, rixy[*, i], /DOUBLE), INTERPOLATE(Z, zixy[*, i], /DOUBLE), color=1,psym=1 + ;OPLOT, [INTERPOLATE(R, rixy[nin, i], /DOUBLE)], [INTERPOLATE(Z, zixy[nin, i], /DOUBLE)], color=4,psym=4 ;IF ncross EQ 1 THEN BEGIN - ; OPLOT, [INTERPOLATE(R, cross[0,0])], [INTERPOLATE(Z, cross[1,0])],psym=2,color=2 + ; OPLOT, [INTERPOLATE(R, cross[0,0], /DOUBLE)], [INTERPOLATE(Z, cross[1,0], /DOUBLE)],psym=2,color=2 ;ENDIF ;CURSOR, ax,by, /down ENDFOR - RETURN, {rixy:rixy, zixy:zixy, rxy:INTERPOLATE(R, rixy), zxy:INTERPOLATE(Z, zixy)} + RETURN, {rixy:rixy, zixy:zixy, rxy:INTERPOLATE(R, rixy, /DOUBLE), zxy:INTERPOLATE(Z, zixy, /DOUBLE)} END PRO plot_grid_section, a, _extra=_extra @@ -639,7 +639,7 @@ PRO oplot_line, interp_data, R, Z, ri0, zi0, fto, npt=npt, color=color, _extra=_ pos = get_line_nonorth(interp_data, R, Z, ri0, zi0, fto, npt=npt) - OPLOT, INTERPOLATE(R, pos[*,0]), INTERPOLATE(Z, pos[*,1]), $ + OPLOT, INTERPOLATE(R, pos[*,0], /DOUBLE), INTERPOLATE(Z, pos[*,1], /DOUBLE), $ color=color, _extra=_extra END @@ -648,17 +648,17 @@ FUNCTION line_dist, R, Z, ri, zi ; derivatives drdi and dzdi may be very inaccurate because the contour ; given by ri and zi is not necessarily uniformly spaced, it may not even ; have a smoothly varying grid spacing. Therefore don't use this branch - drdi = DERIV(INTERPOLATE(R, ri)) - dzdi = DERIV(INTERPOLATE(Z, zi)) + drdi = DERIV(INTERPOLATE(R, ri, /DOUBLE)) + dzdi = DERIV(INTERPOLATE(Z, zi, /DOUBLE)) dldi = SQRT(drdi^2 + dzdi^2) RETURN, int_func(findgen(N_ELEMENTS(dldi)), dldi, /simple) ENDIF ELSE BEGIN np = N_ELEMENTS(ri) - rpos = INTERPOLATE(R, ri) - zpos = INTERPOLATE(Z, zi) + rpos = INTERPOLATE(R, ri, /DOUBLE) + zpos = INTERPOLATE(Z, zi, /DOUBLE) dd = SQRT((zpos[1:*] - zpos[0:(np-2)])^2 + (rpos[1:*] - rpos[0:(np-2)])^2) dd = [dd, SQRT((zpos[0] - zpos[np-1])^2 + (rpos[0] - rpos[np-1])^2)] - result = FLTARR(np) + result = DBLARR(np) FOR i=1,np-1 DO result[i] = result[i-1] + dd[i-1] RETURN, result ENDELSE @@ -674,8 +674,8 @@ FUNCTION xpt_hthe, dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f darr = sep_info.leg1_dist ind = INTERPOL(FINDGEN(N_ELEMENTS(darr)), darr, dist[0]) - ri = INTERPOLATE(sep_info.leg1_ri, ind) - zi = INTERPOLATE(sep_info.leg1_zi, ind) + ri = INTERPOLATE(sep_info.leg1_ri, ind, /DOUBLE) + zi = INTERPOLATE(sep_info.leg1_zi, ind, /DOUBLE) ; Go inwards to PF follow_gradient_nonorth, dctF, R, Z, ri, zi, $ @@ -691,8 +691,8 @@ FUNCTION xpt_hthe, dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f darr = sep_info.leg2_dist ind = INTERPOL(FINDGEN(N_ELEMENTS(darr)), darr, dist[3]) - ri = INTERPOLATE(sep_info.leg2_ri, ind) - zi = INTERPOLATE(sep_info.leg2_zi, ind) + ri = INTERPOLATE(sep_info.leg2_ri, ind, /DOUBLE) + zi = INTERPOLATE(sep_info.leg2_zi, ind, /DOUBLE) ; Go inwards to PF follow_gradient_nonorth, dctF, R, Z, ri, zi, $ @@ -706,8 +706,8 @@ FUNCTION xpt_hthe, dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f darr = sep_info.core1_dist ind = INTERPOL(FINDGEN(N_ELEMENTS(darr)), darr, dist[2]) - ri = INTERPOLATE(sep_info.core1_ri, ind) - zi = INTERPOLATE(sep_info.core1_zi, ind) + ri = INTERPOLATE(sep_info.core1_ri, ind, /DOUBLE) + zi = INTERPOLATE(sep_info.core1_zi, ind, /DOUBLE) ; Go inwards to core follow_gradient_nonorth, dctF, R, Z, ri, zi, $ @@ -724,8 +724,8 @@ FUNCTION xpt_hthe, dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f darr = sep_info.core2_dist ind = INTERPOL(FINDGEN(N_ELEMENTS(darr)), darr, dist[1]) - ri = INTERPOLATE(sep_info.core2_ri, ind) - zi = INTERPOLATE(sep_info.core2_zi, ind) + ri = INTERPOLATE(sep_info.core2_ri, ind, /DOUBLE) + zi = INTERPOLATE(sep_info.core2_zi, ind, /DOUBLE) ; Go inwards to core follow_gradient_nonorth, dctF, R, Z, ri, zi, $ @@ -738,29 +738,29 @@ FUNCTION xpt_hthe, dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f ; Get distances between end points - OPLOT, INTERPOLATE(R, [pf_ri1, pf_ri2]), $ - INTERPOLATE(Z, [pf_zi1, pf_zi2]), thick=2, color=1 + OPLOT, INTERPOLATE(R, [pf_ri1, pf_ri2], /DOUBLE), $ + INTERPOLATE(Z, [pf_zi1, pf_zi2], /DOUBLE), thick=2, color=1 - d1 = (INTERPOLATE(R, pf_ri1) - INTERPOLATE(R, pf_ri2))^2 + $ - (INTERPOLATE(Z, pf_zi1) - INTERPOLATE(Z, pf_zi2))^2 + d1 = (INTERPOLATE(R, pf_ri1, /DOUBLE) - INTERPOLATE(R, pf_ri2, /DOUBLE))^2 + $ + (INTERPOLATE(Z, pf_zi1, /DOUBLE) - INTERPOLATE(Z, pf_zi2, /DOUBLE))^2 - d2 = (INTERPOLATE(R, core_ri1) - INTERPOLATE(R, core_ri2))^2 + $ - (INTERPOLATE(Z, core_zi1) - INTERPOLATE(Z, core_zi2))^2 + d2 = (INTERPOLATE(R, core_ri1, /DOUBLE) - INTERPOLATE(R, core_ri2, /DOUBLE))^2 + $ + (INTERPOLATE(Z, core_zi1, /DOUBLE) - INTERPOLATE(Z, core_zi2, /DOUBLE))^2 - OPLOT, INTERPOLATE(R, [core_ri1, core_ri2]), $ - INTERPOLATE(Z, [core_zi1, core_zi2]), thick=2, color=2 + OPLOT, INTERPOLATE(R, [core_ri1, core_ri2], /DOUBLE), $ + INTERPOLATE(Z, [core_zi1, core_zi2], /DOUBLE), thick=2, color=2 - d3 = (INTERPOLATE(R, sol_in_ri1) - INTERPOLATE(R, sol_in_ri2))^2 + $ - (INTERPOLATE(Z, sol_in_zi1) - INTERPOLATE(Z, sol_in_zi2))^2 + d3 = (INTERPOLATE(R, sol_in_ri1, /DOUBLE) - INTERPOLATE(R, sol_in_ri2, /DOUBLE))^2 + $ + (INTERPOLATE(Z, sol_in_zi1, /DOUBLE) - INTERPOLATE(Z, sol_in_zi2, /DOUBLE))^2 - OPLOT, INTERPOLATE(R, [sol_in_ri1, sol_in_ri2]), $ - INTERPOLATE(Z, [sol_in_zi1, sol_in_zi2]), thick=2, color=3 + OPLOT, INTERPOLATE(R, [sol_in_ri1, sol_in_ri2], /DOUBLE), $ + INTERPOLATE(Z, [sol_in_zi1, sol_in_zi2], /DOUBLE), thick=2, color=3 - d4 = (INTERPOLATE(R, sol_out_ri1) - INTERPOLATE(R, sol_out_ri2))^2 + $ - (INTERPOLATE(Z, sol_out_zi1) - INTERPOLATE(Z, sol_out_zi2))^2 + d4 = (INTERPOLATE(R, sol_out_ri1, /DOUBLE) - INTERPOLATE(R, sol_out_ri2, /DOUBLE))^2 + $ + (INTERPOLATE(Z, sol_out_zi1, /DOUBLE) - INTERPOLATE(Z, sol_out_zi2, /DOUBLE))^2 - OPLOT, INTERPOLATE(R, [sol_out_ri1, sol_out_ri2]), $ - INTERPOLATE(Z, [sol_out_zi1, sol_out_zi2]), thick=2, color=4 + OPLOT, INTERPOLATE(R, [sol_out_ri1, sol_out_ri2], /DOUBLE), $ + INTERPOLATE(Z, [sol_out_zi1, sol_out_zi2], /DOUBLE), thick=2, color=4 ;cursor, x, y, /down @@ -777,7 +777,7 @@ FUNCTION solve_xpt_hthe, dctF, R, Z, sep_info, dist0, pf_f, core_f, sol_in_f, so dist = dist0 - IF KEYWORD_SET(psi) THEN Fc = psi ELSE Fc = 0 + IF KEYWORD_SET(psi) THEN Fc = psi ELSE Fc = 0.D dctFc = dctF Rc = R Zc = Z @@ -795,34 +795,34 @@ FUNCTION solve_xpt_hthe, dctF, R, Z, sep_info, dist0, pf_f, core_f, sol_in_f, so ; Internal error: Bad variable type encountered in no_name_var(). ; when NEWTON is combined with LSODE - dfdx = FLTARR(4,4) - delta = 1e-3 + dfdx = DBLARR(4,4) + delta = 1d-3 REPEAT BEGIN xp0 = xpt_hthe_newt(dist) - response = FLTARR(4) + response = DBLARR(4) FOR i=0, 3 DO BEGIN ; Calculate partial derivatives using finite-differences - d = FLTARR(4) + d = DBLARR(4) d[i] = delta dfdx[*,i] = (xpt_hthe_newt(dist+d) - xp0) / delta response[i] = MIN([dfdx[i,i], dfdx[(i+1) MOD 4,i]]) ENDFOR - IF MIN(dfdx) LT 0.0 THEN BEGIN + IF MIN(dfdx) LT 0.0D THEN BEGIN PRINT, "WARNING: ILL-BEHAVED FITTING" RETURN, dist0 ; Don't modify ENDIF ; ; Invert using SVD ; SVDC, dfdx, W, U, V -; WP = FLTARR(4, 4) -; for i=0,2 do wp[i,i] = 1.0/w[i] +; WP = DBLARR(4, 4) +; for i=0,2 do wp[i,i] = 1.0D/w[i] ; ddist = V ## WP ## TRANSPOSE(U) # xp0 ; ; ;ddist = INVERT(dfdx) # xp0 -; w = WHERE(ABS(ddist) GT 0.5*dist, count) -; IF count GT 0 THEN ddist[w] = ddist[w] * 0.5*dist[w] / ABS(ddist[w]) +; w = WHERE(ABS(ddist) GT 0.5D*dist, count) +; IF count GT 0 THEN ddist[w] = ddist[w] * 0.5D*dist[w] / ABS(ddist[w]) ; dist = dist - ddist ; PRINT, "DIST =", REFORM(dist) @@ -834,10 +834,10 @@ FUNCTION solve_xpt_hthe, dctF, R, Z, sep_info, dist0, pf_f, core_f, sol_in_f, so ; If too low, move out, too high move in med = MEDIAN(response) - w = WHERE(response LT 0.1*med, count1) - IF count1 GT 0 THEN dist[w] = dist[w] * 2. - w = WHERE(response GT 10.*med, count2) - IF count2 GT 0 THEN dist[w] = dist[w] * 0.75 + w = WHERE(response LT 0.1D*med, count1) + IF count1 GT 0 THEN dist[w] = dist[w] * 2.D + w = WHERE(response GT 10.D*med, count2) + IF count2 GT 0 THEN dist[w] = dist[w] * 0.75D ENDREP UNTIL count1+count2 EQ 0 @@ -867,14 +867,14 @@ FUNCTION increase_xpt_hthe, dctF, R, Z, sep_info, dist0, pf_f, core_f, sol_in_f, IF xd[(ind+1) MOD 4] LT xd[(ind+3) MOD 4] THEN BEGIN ; Increase dist[ind] - dist[ind] = dist[ind] * 1.1 + dist[ind] = dist[ind] * 1.1D ENDIF ELSE BEGIN ; Increase dist[ind-1] - dist[(ind+3) MOD 4] = dist[(ind+3) MOD 4] * 1.1 + dist[(ind+3) MOD 4] = dist[(ind+3) MOD 4] * 1.1D ENDELSE ENDIF xd = xpt_hthe(dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f, boundary=boundary, psi=psi) - ENDREP UNTIL (MIN(xd) GE xd_target) OR ( ABS(MIN(xd) - m) LT 1.e-5 ) + ENDREP UNTIL (MIN(xd) GE xd_target) OR ( ABS(MIN(xd) - m) LT 1.d-5 ) ; Reduce spacing until one goes below target REPEAT BEGIN @@ -883,9 +883,9 @@ FUNCTION increase_xpt_hthe, dctF, R, Z, sep_info, dist0, pf_f, core_f, sol_in_f, IF m GT xd_target THEN BEGIN ; Decrease distance IF xd[(ind+1) MOD 4] GT xd[(ind+3) MOD 4] THEN BEGIN - dist[ind] = dist[ind] / 1.1 + dist[ind] = dist[ind] / 1.1D ENDIF ELSE BEGIN - dist[(ind+3) MOD 4] = dist[(ind+3) MOD 4] / 1.1 + dist[(ind+3) MOD 4] = dist[(ind+3) MOD 4] / 1.1D ENDELSE ENDIF xd = xpt_hthe(dctF, R, Z, sep_info, dist, pf_f, core_f, sol_in_f, sol_out_f, boundary=boundary, psi=psi) @@ -940,24 +940,24 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ENDIF ELSE IF N_PARAMS() LT 4 THEN BEGIN ; Settings omitted. Set defaults PRINT, "Settings not given -> using default values" - settings = {psi_inner:0.9, $ - psi_outer:1.1, $ + settings = {psi_inner:0.9D, $ + psi_outer:1.1D, $ nrad:36, $ npol:64, $ - rad_peaking:0.0, $ - pol_peaking:0.0, $ - parweight:0.0} + rad_peaking:0.0D, $ + pol_peaking:0.0D, $ + parweight:0.0D} ENDIF ELSE BEGIN PRINT, "Checking settings" settings = in_settings ; So the input isn't changed - str_check_present, settings, 'psi_inner', 0.9 - str_check_present, settings, 'psi_outer', 1.1 + str_check_present, settings, 'psi_inner', 0.9D + str_check_present, settings, 'psi_outer', 1.1D str_check_present, settings, 'nrad', 36 str_check_present, settings, 'npol', 64 - str_check_present, settings, 'rad_peaking', 0.0 - str_check_present, settings, 'pol_peaking', 0.0 - str_check_present, settings, 'parweight', 0.0 - str_check_present, settings, 'nororthogonal_weight_decay_power', 2.7 + str_check_present, settings, 'rad_peaking', 0.0D + str_check_present, settings, 'pol_peaking', 0.0D + str_check_present, settings, 'parweight', 0.0D + str_check_present, settings, 'nororthogonal_weight_decay_power', 2.7D ENDELSE s = SIZE(F, /DIMENSION) @@ -1010,7 +1010,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ENDIF IF NOT KEYWORD_SET(bndryi) THEN BEGIN - bndryi = FLTARR(2,4) + bndryi = DBLARR(2,4) bndryi[0,*] = [1, nx-2, nx-2, 1] bndryi[1,*] = [1, 1, ny-2, ny-2] ENDIF @@ -1039,10 +1039,10 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ nlev = 100 minf = MIN(f) maxf = MAX(f) - levels = findgen(nlev)*(maxf-minf)/FLOAT(nlev-1) + minf + levels = findgen(nlev)*(maxf-minf)/DOUBLE(nlev-1) + minf safe_colors, /first - CONTOUR, F, R, Z, levels=levels, color=1, /iso, xstyl=1, ysty=1;;, xrange=[0.5, 1.5] , yrange=[-2., -1.4], font=1,charsize=3 + CONTOUR, F, R, Z, levels=levels, color=1, /iso, xstyl=1, ysty=1;;, xrange=[0.5D, 1.5D] , yrange=[-2.D, -1.4D], font=1,charsize=3 IF KEYWORD_SET(boundary) THEN BEGIN OPLOT, [REFORM(boundary[0,*]), boundary[0,0]], [REFORM(boundary[1,*]), boundary[1,0]], $ @@ -1129,8 +1129,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; Make sure that the line goes clockwise - m = MAX(INTERPOLATE(Z, start_zi), ind) - IF (DERIV(INTERPOLATE(R, start_ri)))[ind] LT 0.0 THEN BEGIN + m = MAX(INTERPOLATE(Z, start_zi, /DOUBLE), ind) + IF (DERIV(INTERPOLATE(R, start_ri, /DOUBLE)))[ind] LT 0.0D THEN BEGIN ; R should be increasing at the top. Need to reverse start_ri = REVERSE(start_ri) start_zi = REVERSE(start_zi) @@ -1152,7 +1152,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; start_zi[i] = zi1 ;ENDFOR - oplot_contour, info, xy, R, Z, /periodic, color=2, thick=1.5 + oplot_contour, info, xy, R, Z, /periodic, color=2, thick=1.5D a = grid_region_nonorth(interp_data, R, Z, $ start_ri, start_zi, $ @@ -1173,11 +1173,11 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ENDFOR ; Get other useful variables - Psixy = FLTARR(nrad, npol) + Psixy = DBLARR(nrad, npol) FOR i=0, npol-1 DO psixy[*,i] = (fvals - faxis)/fnorm ; to get normalised psi ; Calculate magnetic field components - dpsidR = FLTARR(nrad, npol) + dpsidR = DBLARR(nrad, npol) dpsidZ = dpsidR interp_data.method = 2 @@ -1187,8 +1187,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ local_gradient, interp_data, a.Rixy[i,j], a.Zixy[i,j], status=status, $ dfdr=dfdr, dfdz=dfdz ; dfd* are derivatives wrt the indices. Need to multiply by dr/di etc - dpsidR[i,j] = dfdr/INTERPOLATE(DERIV(R),a.Rixy[i,j]) - dpsidZ[i,j] = dfdz/INTERPOLATE(DERIV(Z),a.Zixy[i,j]) + dpsidR[i,j] = dfdr/INTERPOLATE(DERIV(R),a.Rixy[i,j], /DOUBLE) + dpsidZ[i,j] = dfdz/INTERPOLATE(DERIV(Z),a.Zixy[i,j], /DOUBLE) ENDFOR ENDFOR @@ -1237,8 +1237,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ primary_xpt = si[0] PRINT, "Primary X-point is number "+STR(primary_xpt) - PRINT, " at R = "+STR(INTERPOLATE(R, critical.xpt_ri[primary_xpt])) $ - +" Z = "+STR(INTERPOLATE(Z, critical.xpt_zi[primary_xpt])) + PRINT, " at R = "+STR(INTERPOLATE(R, critical.xpt_ri[primary_xpt], /DOUBLE)) $ + +" Z = "+STR(INTERPOLATE(Z, critical.xpt_zi[primary_xpt], /DOUBLE)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; work out where to put the surfaces @@ -1261,15 +1261,15 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ PRINT, "Distributing radial points automatically" n = TOTAL(nrad,/int) - fac = 2.*(xpt_f[inner_sep] - f_inner)/(1.+rad_peaking) + fac = 2.D*(xpt_f[inner_sep] - f_inner)/(1.D + rad_peaking) FOR i=1, critical.n_xpoint-1 DO fac = fac + (xpt_f[si[i]] - xpt_f[si[i-1]])/rad_peaking - fac = fac + 2.*(f_outer - xpt_f[si[critical.n_xpoint-1]])/(1.+rad_peaking) - dx0 = fac / FLOAT(n) ; Inner grid spacing + fac = fac + 2.D*(f_outer - xpt_f[si[critical.n_xpoint-1]])/(1.D + rad_peaking) + dx0 = fac / DOUBLE(n) ; Inner grid spacing ; Calculate number of grid points nrad = LONARR(critical.n_xpoint + 1) - nrad[0] = FIX( 2.*(xpt_f[inner_sep] - f_inner) / ( (1.+rad_peaking)*dx0 ) + 0.5) - FOR i=1, critical.n_xpoint-1 DO nrad[i] = FIX((xpt_f[si[i]] - xpt_f[si[i-1]])/(rad_peaking*dx0)-0.5) + nrad[0] = FIX( 2.D*(xpt_f[inner_sep] - f_inner) / ( (1.D + rad_peaking)*dx0 ) + 0.5D) + FOR i=1, critical.n_xpoint-1 DO nrad[i] = FIX((xpt_f[si[i]] - xpt_f[si[i-1]])/(rad_peaking*dx0)-0.5D) nrad[critical.n_xpoint] = n - TOTAL(nrad,/int) ;fvals = radial_grid(TOTAL(nrad), f_inner, f_outer, 1, 1, xpt_f, rad_peaking) @@ -1302,13 +1302,13 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ FOR i=2, critical.n_xpoint-1 DO fvals = [fvals, radial_grid(nrad[i], xpt_f[si[i-1]], xpt_f[si[i]], 0, 0, xpt_f, rad_peaking)] ; Core - fvals = [radial_grid(nrad[0], f_inner, 2.*xpt_f[inner_sep]-fvals[0], $ + fvals = [radial_grid(nrad[0], f_inner, 2.D*xpt_f[inner_sep]-fvals[0], $ 1, 1, xpt_f, rad_peaking, $ - out_dp=2.*(fvals[0]-xpt_f[inner_sep]), $ - in_dp=2.*(fvals[0]-xpt_f[inner_sep])/rad_peaking), fvals] + out_dp=2.D*(fvals[0]-xpt_f[inner_sep]), $ + in_dp=2.D*(fvals[0]-xpt_f[inner_sep])/rad_peaking), fvals] ENDIF ELSE BEGIN ; Only a single separatrix - dp0 = (xpt_f[inner_sep] - f_inner)*2./ (FLOAT(nrad[0])*(1. + rad_peaking)) + dp0 = (xpt_f[inner_sep] - f_inner)*2.D/ (DOUBLE(nrad[0])*(1.D + rad_peaking)) fvals = radial_grid(nrad[0], f_inner, xpt_f[inner_sep], $ 1, 0, xpt_f, rad_peaking, $ out_dp=rad_peaking*dp0, $ @@ -1317,7 +1317,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; SOL n = N_ELEMENTS(fvals) - dpsi = 2.*(xpt_f[si[critical.n_xpoint-1]] - fvals[n-1]) + dpsi = 2.D*(xpt_f[si[critical.n_xpoint-1]] - fvals[n-1]) fvals = [fvals, radial_grid(nrad[critical.n_xpoint], $ fvals[n-1]+dpsi, f_outer, 1, 1, xpt_f, rad_peaking, $ in_dp=dpsi, out_dp=dpsi/rad_peaking)] @@ -1328,8 +1328,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Create arrays of psi values for each region - sol_psi_vals = FLTARR(critical.n_xpoint, TOTAL(nrad,/int)) - pf_psi_vals = FLTARR(critical.n_xpoint, 2, TOTAL(nrad,/int)) + sol_psi_vals = DBLARR(critical.n_xpoint, TOTAL(nrad,/int)) + pf_psi_vals = DBLARR(critical.n_xpoint, 2, TOTAL(nrad,/int)) FOR i=0, critical.n_xpoint-1 DO BEGIN sol_psi_vals[i,*] = psi_vals pf_psi_vals[i,0,*] = psi_vals @@ -1345,7 +1345,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ENDIF PRINT, "Keeping same inner psi for all regions" - psi_inner = FLTARR(critical.n_xpoint+1) + MIN(settings.psi_inner) + psi_inner = DBLARR(critical.n_xpoint+1) + MIN(settings.psi_inner) ENDELSE IF N_ELEMENTS(settings.psi_outer) EQ critical.n_xpoint THEN BEGIN @@ -1357,7 +1357,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ENDIF PRINT, "Keeping same outer psi for all regions" - psi_outer = FLTARR(critical.n_xpoint) + MAX(settings.psi_outer) + psi_outer = DBLARR(critical.n_xpoint) + MAX(settings.psi_outer) ENDELSE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1368,7 +1368,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ;sind = FIX(nrad[0]/2) ;nrad[0]-1 ; the last point inside core ;sind = nrad[0]-1 ;f_cont = fvals[sind] - f_cont = faxis + fnorm*(0.1*psi_inner[0] + 0.9) + f_cont = faxis + fnorm*(0.1D*psi_inner[0] + 0.9D) contour_lines, F, findgen(nx), findgen(ny), levels=[f_cont], $ path_info=info, path_xy=xy @@ -1380,15 +1380,15 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ critical.opt_ri[critical.primary_opt], critical.opt_zi[critical.primary_opt])] ENDIF ELSE info = info[0] - oplot_contour, info, xy, R, Z, /periodic, color=3, thick=1.5 + oplot_contour, info, xy, R, Z, /periodic, color=3, thick=1.5D start_ri = REFORM(xy[0,info.offset:(info.offset+info.n-1)]) start_zi = REFORM(xy[1,info.offset:(info.offset+info.n-1)]) ; Make sure that the line goes clockwise - m = MAX(INTERPOLATE(Z, start_zi), ind) - IF (DERIV(INTERPOLATE(R, start_ri)))[ind] LT 0.0 THEN BEGIN + m = MAX(INTERPOLATE(Z, start_zi, /DOUBLE), ind) + IF (DERIV(INTERPOLATE(R, start_ri, /DOUBLE)))[ind] LT 0.0D THEN BEGIN ; R should be increasing at the top. Need to reverse start_ri = REVERSE(start_ri) start_zi = REVERSE(start_zi) @@ -1397,14 +1397,14 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; now have (start_ri, start_zi). For each x-point, find the radial ; line going through the x-point - xpt_ind = FLTARR(critical.n_xpoint) ; index into start_*i + xpt_ind = DBLARR(critical.n_xpoint) ; index into start_*i pf_info = PTRARR(critical.n_xpoint) - veccore = fltarr(critical.n_xpoint,2) - vec1 = fltarr(critical.n_xpoint,2) - vec2 = fltarr(critical.n_xpoint,2) - vecpvt = fltarr(critical.n_xpoint,2) + veccore = DBLARR(critical.n_xpoint,2) + vec1 = DBLARR(critical.n_xpoint,2) + vec2 = DBLARR(critical.n_xpoint,2) + vecpvt = DBLARR(critical.n_xpoint,2) FOR i=0, critical.n_xpoint-1 DO BEGIN PRINT, "Finding theta location of x-point "+STR(i) @@ -1413,8 +1413,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ opt_ri[primary_opt], opt_zi[primary_opt], boundary=bndryi) ;; ;BS - centerliner = INTERPOLATE(R, [opt_ri[0],xpt_ri[i]]) - centerlinez = INTERPOLATE(Z, [opt_zi[0],xpt_zi[i]]) + centerliner = INTERPOLATE(R, [opt_ri[0],xpt_ri[i]], /DOUBLE) + centerlinez = INTERPOLATE(Z, [opt_zi[0],xpt_zi[i]], /DOUBLE) ;; oplot, centerliner, centerlinez, thick=5 ;; stop @@ -1422,11 +1422,11 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ;; lines, because we need elements from both at each step when we loop below nflux_leg1 = min([n_elements(legsep.leg1[0:legsep.leg1_lastind,0]), n_elements(legsep.core2[*,0])]) nflux_leg2 = min([n_elements(legsep.leg2[0:legsep.leg2_lastind,0]), n_elements(legsep.core1[*,0])]) - meanr1 = fltarr(nflux_leg1) - meanz1 = fltarr(nflux_leg1) + meanr1 = DBLARR(nflux_leg1) + meanz1 = DBLARR(nflux_leg1) - meanr2 = fltarr(nflux_leg2) - meanz2 = fltarr(nflux_leg2) + meanr2 = DBLARR(nflux_leg2) + meanz2 = DBLARR(nflux_leg2) if nflux_leg2 GT nflux_leg1 THEN BEGIN nflux_pvt = nflux_leg1 @@ -1434,8 +1434,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ nflux_pvt = nflux_leg2 END - meanrpvt = fltarr(nflux_pvt) - meanzpvt = fltarr(nflux_pvt) + meanrpvt = DBLARR(nflux_pvt) + meanzpvt = DBLARR(nflux_pvt) FOR ii = 0, nflux_leg1-1 DO BEGIN IF ii EQ 0 THEN BEGIN @@ -1482,9 +1482,9 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ vecpvt[i,0] = (meanrpvt[nflux_pvt/2]-meanrpvt[0])/lengthpvt vecpvt[i,1] = (meanzpvt[nflux_pvt/2]-meanzpvt[0])/lengthpvt - ;; oplot, INTERPOLATE(R,[meanr1[0],meanr1[nflux_leg1/2]]),INTERPOLATE(Z,[meanz1[0],meanz1[nflux_leg1/2]]), thick=5 - ;; oplot, INTERPOLATE(R,[meanr2[0],meanr2[nflux_leg2/2]]),INTERPOLATE(Z,[meanz2[0],meanz2[nflux_leg2/2]]), thick=5 - ;; oplot, INTERPOLATE(R,[meanrpvt[0],meanrpvt[nflux_pvt/2]]),INTERPOLATE(Z,[meanzpvt[0],meanzpvt[nflux_pvt/2]]), thick=5 + ;; oplot, INTERPOLATE(R,[meanr1[0],meanr1[nflux_leg1/2]], /DOUBLE),INTERPOLATE(Z,[meanz1[0],meanz1[nflux_leg1/2]], /DOUBLE), thick=5 + ;; oplot, INTERPOLATE(R,[meanr2[0],meanr2[nflux_leg2/2]], /DOUBLE),INTERPOLATE(Z,[meanz2[0],meanz2[nflux_leg2/2]], /DOUBLE), thick=5 + ;; oplot, INTERPOLATE(R,[meanrpvt[0],meanrpvt[nflux_pvt/2]], /DOUBLE),INTERPOLATE(Z,[meanzpvt[0],meanzpvt[nflux_pvt/2]], /DOUBLE), thick=5 ;; stop @@ -1492,12 +1492,12 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; Note: add starting point to end of 'boundary' so we find intersections with a closed contour follow_gradient, interp_data, R, Z, $ legsep.core1[2,0], legsep.core1[2,1], $ - 0.95 * f_cont + 0.05*opt_f[primary_opt], $ + 0.95D * f_cont + 0.05D*opt_f[primary_opt], $ rhit, zhit, $ boundary=TRANSPOSE([[start_ri, start_ri[0]], [start_zi, start_zi[0]]]), ibndry=hit_ind1 follow_gradient, interp_data, R, Z, $ legsep.core2[2,0], legsep.core2[2,1], $ - 0.95 * f_cont + 0.05*opt_f[primary_opt], $ + 0.95D * f_cont + 0.05D*opt_f[primary_opt], $ rhit, zhit, $ boundary=TRANSPOSE([[start_ri, start_ri[0]], [start_zi, start_zi[0]]]), ibndry=hit_ind2 @@ -1505,9 +1505,9 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ IF MIN([ni - hit_ind2 + hit_ind1, ni - hit_ind1 + hit_ind2]) LT ABS(hit_ind2 - hit_ind1) THEN BEGIN ; One at the beginning and one at the end (across the join) - mini = (hit_ind2 + hit_ind1 - ni) / 2. - IF mini LT 0. THEN mini = mini + ni - ENDIF ELSE mini = (hit_ind1 + hit_ind2) / 2. + mini = (hit_ind2 + hit_ind1 - ni) / 2.D + IF mini LT 0.D THEN mini = mini + ni + ENDIF ELSE mini = (hit_ind1 + hit_ind2) / 2.D PRINT, hit_ind1, hit_ind2, mini @@ -1516,20 +1516,20 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ;; REPEAT BEGIN ;; IF MIN([ni - hit_ind2 + hit_ind1, ni - hit_ind1 + hit_ind2]) LT ABS(hit_ind2 - hit_ind1) THEN BEGIN ;; ; One at the beginning and one at the end (across the join) - ;; mini = (hit_ind2 + hit_ind1 - ni) / 2. - ;; IF mini LT 0. THEN mini = mini + ni - ;; ENDIF ELSE mini = (hit_ind1 + hit_ind2) / 2. + ;; mini = (hit_ind2 + hit_ind1 - ni) / 2.D + ;; IF mini LT 0.D THEN mini = mini + ni + ;; ENDIF ELSE mini = (hit_ind1 + hit_ind2) / 2.D - ;; OPLOT, [INTERPOLATE(R, INTERPOLATE(start_ri, mini))], [INTERPOLATE(Z, INTERPOLATE(start_zi, mini))], psym=2, color=4 + ;; OPLOT, [INTERPOLATE(R, INTERPOLATE(start_ri, mini, /DOUBLE), /DOUBLE)], [INTERPOLATE(Z, INTERPOLATE(start_zi, mini, /DOUBLE), /DOUBLE)], psym=2, color=4 ;; PRINT, "Theta location: " + STR(hit_ind1) + "," + STR(hit_ind2) + " -> " + STR(mini) ;; ; Get line a little bit beyond the X-point ;; pos = get_line_nonorth(interp_data, R, Z, $ - ;; INTERPOLATE(start_ri, mini), INTERPOLATE(start_zi, mini), $ - ;; critical.xpt_f[i] + (critical.xpt_f[i] - opt_f[primary_opt]) * 0.05) + ;; INTERPOLATE(start_ri, mini, /DOUBLE), INTERPOLATE(start_zi, mini, /DOUBLE), $ + ;; critical.xpt_f[i] + (critical.xpt_f[i] - opt_f[primary_opt]) * 0.05D) - ;; ;OPLOT, INTERPOLATE(R, pos[*,0]), INTERPOLATE(Z, pos[*,1]), color=4, thick=2 + ;; ;OPLOT, INTERPOLATE(R, pos[*,0], /DOUBLE), INTERPOLATE(Z, pos[*,1], /DOUBLE), color=4, thick=2 ;; ; Find which separatrix line this intersected with ;; cpos = line_crossings([xpt_ri[i], legsep.core1[*,0]], $ @@ -1542,12 +1542,12 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ;; hit_ind2 = mini ;; ENDELSE ;; dist = MIN([ni - hit_ind2 + hit_ind1, ni - hit_ind1 + hit_ind2, ABS([hit_ind2 - hit_ind1])]) - ;; ENDREP UNTIL dist LT 0.1 + ;; ENDREP UNTIL dist LT 0.1D ;; IF MIN([ni - hit_ind2 + hit_ind1, ni - hit_ind1 + hit_ind2]) LT ABS(hit_ind2 - hit_ind1) THEN BEGIN ;; ; One at the beginning and one at the end (across the join) - ;; mini = (hit_ind2 + hit_ind1 - ni) / 2. - ;; IF mini LT 0. THEN mini = mini + ni - ;; ENDIF ELSE mini = (hit_ind1 + hit_ind2) / 2. + ;; mini = (hit_ind2 + hit_ind1 - ni) / 2.D + ;; IF mini LT 0.D THEN mini = mini + ni + ;; ENDIF ELSE mini = (hit_ind1 + hit_ind2) / 2.D ;; ENDIF xpt_ind[i] = mini ; Record the index @@ -1560,14 +1560,14 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; Plot the line to the x-point oplot_line, interp_data, R, Z, $ - INTERPOLATE(start_ri, mini), INTERPOLATE(start_zi, mini), critical.xpt_f[i], color=125 + INTERPOLATE(start_ri, mini, /DOUBLE), INTERPOLATE(start_zi, mini, /DOUBLE), critical.xpt_f[i], color=125 oplot_line, interp_data, R, Z, $ - INTERPOLATE(start_ri, mini), INTERPOLATE(start_zi, mini), f_inner, color=125 + INTERPOLATE(start_ri, mini, /DOUBLE), INTERPOLATE(start_zi, mini, /DOUBLE), f_inner, color=125 ; Get tangent vector - drdi = INTERPOLATE((DERIV(INTERPOLATE(R, start_ri))), mini) - dzdi = INTERPOLATE((DERIV(INTERPOLATE(Z, start_zi))), mini) + drdi = INTERPOLATE((DERIV(INTERPOLATE(R, start_ri, /DOUBLE))), mini, /DOUBLE) + dzdi = INTERPOLATE((DERIV(INTERPOLATE(Z, start_zi, /DOUBLE))), mini, /DOUBLE) tmp = {core_ind:mini, drdi:drdi, dzdi:dzdi, $ ; Core index and tangent vector sol:LONARR(2)} ; Array to store SOL indices @@ -1582,40 +1582,40 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ sol_info = PTRARR(critical.n_xpoint) FOR i=0, critical.n_xpoint-1 DO BEGIN IF i NE (critical.n_xpoint-1) THEN BEGIN - ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]]), $ - start_ri[FIX(xpt_ind[ci[i]]+1.0):FIX(xpt_ind[ci[i+1]])], $ - INTERPOLATE(start_ri,xpt_ind[ci[i+1]]) ] + ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]], /DOUBLE), $ + start_ri[FIX(xpt_ind[ci[i]]+1.0D):FIX(xpt_ind[ci[i+1]])], $ + INTERPOLATE(start_ri,xpt_ind[ci[i+1]], /DOUBLE) ] - zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]]), $ - start_zi[FIX(xpt_ind[ci[i]]+1.0):FIX(xpt_ind[ci[i+1]])], $ - INTERPOLATE(start_zi,xpt_ind[ci[i+1]]) ] + zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]], /DOUBLE), $ + start_zi[FIX(xpt_ind[ci[i]]+1.0D):FIX(xpt_ind[ci[i+1]])], $ + INTERPOLATE(start_zi,xpt_ind[ci[i+1]], /DOUBLE) ] ENDIF ELSE BEGIN ; Index wraps around IF xpt_ind[ci[i]] GT N_ELEMENTS(start_ri)-2 THEN BEGIN - ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]]), $ + ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]], /DOUBLE), $ start_ri[0:FIX(xpt_ind[ci[0]])], $ - INTERPOLATE(start_ri,xpt_ind[ci[0]]) ] + INTERPOLATE(start_ri,xpt_ind[ci[0]], /DOUBLE) ] - zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]]), $ + zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]], /DOUBLE), $ start_zi[0:FIX(xpt_ind[ci[0]])], $ - INTERPOLATE(start_zi,xpt_ind[ci[0]]) ] + INTERPOLATE(start_zi,xpt_ind[ci[0]], /DOUBLE) ] ENDIF ELSE BEGIN - ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]]), $ - start_ri[FIX(xpt_ind[ci[i]]+1.0):*], $ + ri = [ INTERPOLATE(start_ri,xpt_ind[ci[i]], /DOUBLE), $ + start_ri[FIX(xpt_ind[ci[i]]+1.0D):*], $ start_ri[0:FIX(xpt_ind[ci[0]])], $ - INTERPOLATE(start_ri,xpt_ind[ci[0]]) ] + INTERPOLATE(start_ri,xpt_ind[ci[0]], /DOUBLE) ] - zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]]), $ - start_zi[FIX(xpt_ind[ci[i]]+1.0):*], $ + zi = [ INTERPOLATE(start_zi,xpt_ind[ci[i]], /DOUBLE), $ + start_zi[FIX(xpt_ind[ci[i]]+1.0D):*], $ start_zi[0:FIX(xpt_ind[ci[0]])], $ - INTERPOLATE(start_zi,xpt_ind[ci[0]]) ] + INTERPOLATE(start_zi,xpt_ind[ci[0]], /DOUBLE) ] ENDELSE ENDELSE ; Calculate length of the line - drdi = DERIV(INTERPOLATE(R, ri)) - dzdi = DERIV(INTERPOLATE(Z, zi)) + drdi = DERIV(INTERPOLATE(R, ri, /DOUBLE)) + dzdi = DERIV(INTERPOLATE(Z, zi, /DOUBLE)) dldi = SQRT(drdi^2 + dzdi^2) IF KEYWORD_SET(simple) THEN BEGIN length = INT_TRAPEZOID(findgen(N_ELEMENTS(dldi)), dldi) @@ -1649,7 +1649,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ IF KEYWORD_SET(nrad_flexible) THEN nrad = TOTAL(nrad,/int) ; Allow nrad to change again - new_settings = {psi_inner:psi_inner, psi_outer:(max(xpt_psi)+0.02), $ + new_settings = {psi_inner:psi_inner, psi_outer:(max(xpt_psi)+0.02D), $ nrad:nrad, npol:settings.npol, $ rad_peaking:settings.rad_peaking, pol_peaking:settings.pol_peaking} RETURN, create_nonorthogonal(F, R, Z, new_settings, critical=critical, $ @@ -1695,7 +1695,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; Gridding as one region IF (npf+1) LT TOTAL(nrad,/int) THEN BEGIN dpsi = pf_psi_vals[xind,0,npf+1] - pf_psi_vals[xind,0,npf] - pf_psi_out = (pf_psi_vals[xind,0,npf] - 0.5*dpsi) < xpt_psi[xind] + pf_psi_out = (pf_psi_vals[xind,0,npf] - 0.5D*dpsi) < xpt_psi[xind] pf_psi_vals[xind,0,0:(npf-1)] = radial_grid(npf, psi_inner[id+1], $ pf_psi_out, $ 1, 0, $ @@ -1709,8 +1709,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ENDELSE ENDIF ELSE BEGIN ; Gridding in multiple regions. Ensure equal spacing around separatrix - dpsi = 2.*(pf_psi_vals[xind,0,npf] - xpt_psi[xind]) - pf_psi_out = xpt_psi[xind] - 0.5*dpsi + dpsi = 2.D*(pf_psi_vals[xind,0,npf] - xpt_psi[xind]) + pf_psi_out = xpt_psi[xind] - 0.5D*dpsi pf_psi_vals[xind,0,0:(npf-1)] = radial_grid(npf, psi_inner[id+1], $ pf_psi_out, $ @@ -1737,14 +1737,14 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; Use the tangent vector to determine direction ; relative to core and so get direction of positive theta - drdi = INTERPOLATE((DERIV(INTERPOLATE(R, pf_ri))), mini) - dzdi = INTERPOLATE((DERIV(INTERPOLATE(Z, pf_zi))), mini) + drdi = INTERPOLATE((DERIV(INTERPOLATE(R, pf_ri, /DOUBLE))), mini, /DOUBLE) + dzdi = INTERPOLATE((DERIV(INTERPOLATE(Z, pf_zi, /DOUBLE))), mini, /DOUBLE) - IF drdi * (*pf_info[xind]).drdi + dzdi * (*pf_info[xind]).dzdi GT 0.0 THEN BEGIN + IF drdi * (*pf_info[xind]).drdi + dzdi * (*pf_info[xind]).dzdi GT 0.0D THEN BEGIN ; Line is parallel to the core. Need to reverse pf_ri = REVERSE(pf_ri) pf_zi = REVERSE(pf_zi) - mini = N_ELEMENTS(pf_ri) - 1. - mini + mini = N_ELEMENTS(pf_ri) - 1 - mini temp = N_ELEMENTS(pf_ri) - 1 - pf_wallind2 pf_wallind2 = N_ELEMENTS(pf_ri) - 1 - pf_wallind1 pf_wallind1 = temp @@ -1792,21 +1792,21 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; Put the starting line into the pf_info structure tmp = CREATE_STRUCT(*(pf_info[xind]), $ 'npf', npf, $ ; Number of radial points in this PF region - 'ri0', [pf_ri[0:mini], INTERPOLATE(pf_ri, mini)], $ - 'zi0', [pf_zi[0:mini], INTERPOLATE(pf_zi, mini)], $ + 'ri0', [pf_ri[0:mini], INTERPOLATE(pf_ri, mini, /DOUBLE)], $ + 'zi0', [pf_zi[0:mini], INTERPOLATE(pf_zi, mini, /DOUBLE)], $ 'wallind0', pf_wallind1, $ - 'ri1', [INTERPOLATE(pf_ri, mini), pf_ri[(mini+1):*]], $ - 'zi1', [INTERPOLATE(pf_zi, mini), pf_zi[(mini+1):*]], $ + 'ri1', [INTERPOLATE(pf_ri, mini, /DOUBLE), pf_ri[(mini+1):*]], $ + 'zi1', [INTERPOLATE(pf_zi, mini, /DOUBLE), pf_zi[(mini+1):*]], $ 'wallind1', pf_wallind2 - mini) ; Calculate length of each section - dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri0[tmp.wallind0:*]))^2 + DERIV(INTERPOLATE(Z, tmp.zi0[tmp.wallind0:*]))^2) + dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri0[tmp.wallind0:*], /DOUBLE))^2 + DERIV(INTERPOLATE(Z, tmp.zi0[tmp.wallind0:*], /DOUBLE))^2) IF KEYWORD_SET(simple) THEN BEGIN len0 = INT_TRAPEZOID(FINDGEN(N_ELEMENTS(dldi)), dldi) ENDIF ELSE BEGIN len0 = INT_TABULATED(FINDGEN(N_ELEMENTS(dldi)), dldi) ENDELSE - dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri1[0:tmp.wallind1]))^2 + DERIV(INTERPOLATE(Z, tmp.zi1[0:tmp.wallind1]))^2) + dldi = SQRT(DERIV(INTERPOLATE(R, tmp.ri1[0:tmp.wallind1], /DOUBLE))^2 + DERIV(INTERPOLATE(Z, tmp.zi1[0:tmp.wallind1], /DOUBLE))^2) IF KEYWORD_SET(simple) THEN BEGIN len1 = INT_TRAPEZOID(FINDGEN(N_ELEMENTS(dldi)), dldi) ENDIF ELSE BEGIN @@ -1856,7 +1856,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ n_y_boundary_guards = LONARR(3*critical.n_xpoint) ; Get lengths - length = FLTARR(3*critical.n_xpoint) + length = DBLARR(3*critical.n_xpoint) FOR i=0, critical.n_xpoint-1 DO BEGIN ; PF regions length[i] = (*pf_info[i]).len0 @@ -1868,9 +1868,9 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ FOR i=0, n_update-1 DO BEGIN ; Add an extra point to the longest length - dl = length / FLOAT(npol) + dl = length / DOUBLE(npol) dl[0:(2*critical.n_xpoint-1)] = length[0:(2*critical.n_xpoint-1)] $ - / (FLOAT(npol[0:(2*critical.n_xpoint-1)]) - 0.5) + / (DOUBLE(npol[0:(2*critical.n_xpoint-1)]) - 0.5D) m = MAX(dl, ind) npol[ind] = npol[ind] + 1 @@ -1910,7 +1910,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; Calculate distance for equal spacing in each region xpt = si[0] ; Start with the innermost x-point - xpt_dist = FLTARR(critical.n_xpoint, 4) ; Distance between x-point and first grid point + xpt_dist = DBLARR(critical.n_xpoint, 4) ; Distance between x-point and first grid point FOR i=0, critical.n_xpoint-1 DO BEGIN ; Grid the lower PF region @@ -1923,7 +1923,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ wallind = (*pf_info[xpt]).wallind0 poldist = line_dist(R, Z, (*pf_info[xpt]).ri0[wallind:*], (*pf_info[xpt]).zi0[wallind:*]) ; Poloidal distance along line - xdist = MAX(poldist) * 0.5 / FLOAT(npol[3*i]) ; Equal spacing + xdist = MAX(poldist) * 0.5D / DOUBLE(npol[3*i]) ; Equal spacing xpt_dist[xpt, 0] = xdist @@ -1931,7 +1931,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ solid = (*pf_info[xpt]).sol[0] poldist = line_dist(R, Z, (*sol_info[solid]).ri, (*sol_info[solid]).zi) - xdist = MAX(poldist) * 0.5 / FLOAT(npol[3*i+1]) + xdist = MAX(poldist) * 0.5D / DOUBLE(npol[3*i+1]) xpt2 = (*sol_info[solid]).xpt2 @@ -1943,7 +1943,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ wallind = (*pf_info[xpt]).wallind1 poldist = line_dist(R, Z, (*pf_info[xpt]).ri1[0:wallind], (*pf_info[xpt]).zi1[0:wallind]) - xdist = MAX(poldist) * 0.5 / FLOAT(npol[3*i]) + xdist = MAX(poldist) * 0.5D / DOUBLE(npol[3*i]) xpt_dist[xpt, 3] = xdist @@ -1957,7 +1957,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ FOR i=0, critical.n_xpoint-1 DO BEGIN md = MAX(xpt_dist[i,*]) - xpt_dist[i,*] = 0.5*xpt_dist[i,*] + 0.5*md + xpt_dist[i,*] = 0.5D*xpt_dist[i,*] + 0.5D*md ENDFOR ; Try to equalise @@ -1997,11 +1997,11 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ vec_in_down2 = TRANSPOSE(veccore[xpt,*]) line = get_line_nonorth(interp_data, R, Z, $ - INTERPOLATE((*sep_info[xpt]).core2_ri, sepi), $ - INTERPOLATE((*sep_info[xpt]).core2_zi, sepi), $ - 0.95*f_cont + 0.05*faxis, npt=30, vec_down=vec_in_down2, weight_down=1) + INTERPOLATE((*sep_info[xpt]).core2_ri, sepi, /DOUBLE), $ + INTERPOLATE((*sep_info[xpt]).core2_zi, sepi, /DOUBLE), $ + 0.95D*f_cont + 0.05D*faxis, npt=30, vec_down=vec_in_down2, weight_down=1) - OPLOT, INTERPOLATE(R, line[*,0]), INTERPOLATE(Z, line[*,1]), $ + OPLOT, INTERPOLATE(R, line[*,0], /DOUBLE), INTERPOLATE(Z, line[*,1], /DOUBLE), $ color=4, _extra=_extra ; Find intersection of this line with starting line @@ -2014,7 +2014,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ start_ind = start_ind[0] ; Got index into the starting line ; Find out distance along starting line dist = line_dist(R, Z, (*sol_info[solid]).ri, (*sol_info[solid]).zi) - d = INTERPOLATE(dist, start_ind) + d = INTERPOLATE(dist, start_ind, /DOUBLE) ydown_dist = MIN([d, dist[N_ELEMENTS(dist)-1] - d]) ENDELSE @@ -2028,12 +2028,12 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ; Follow from sep_info[i]->core1 to just inside starting f vec_in_up2 = TRANSPOSE(veccore[xpt2,*]) line = get_line_nonorth(interp_data, R, Z, $ - INTERPOLATE((*sep_info[xpt2]).core1_ri, sepi), $ - INTERPOLATE((*sep_info[xpt2]).core1_zi, sepi), $ - 0.95*f_cont + 0.05*faxis, npt=30, $ + INTERPOLATE((*sep_info[xpt2]).core1_ri, sepi, /DOUBLE), $ + INTERPOLATE((*sep_info[xpt2]).core1_zi, sepi, /DOUBLE), $ + 0.95D*f_cont + 0.05D*faxis, npt=30, $ vec_up=vec_in_up2, weight_up=1) - OPLOT, INTERPOLATE(R, line[*,0]), INTERPOLATE(Z, line[*,1]), $ + OPLOT, INTERPOLATE(R, line[*,0], /DOUBLE), INTERPOLATE(Z, line[*,1], /DOUBLE), $ color=2, _extra=_extra ; Find intersection of this line with starting line @@ -2045,7 +2045,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ start_ind = start_ind[0] ; Got index into the starting line ; Find out distance along starting line dist = line_dist(R, Z, (*sol_info[solid]).ri, (*sol_info[solid]).zi) - yup_dist = MAX(dist) - INTERPOLATE(dist, start_ind) + yup_dist = MAX(dist) - INTERPOLATE(dist, start_ind, /DOUBLE) ENDELSE xpt_dist[xpt2, 2] = yup_dist @@ -2067,14 +2067,14 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ gridbndry = bndryi ENDIF ELSE BEGIN ; Grid can leave boundary - gridbndry = FLTARR(2,4) + gridbndry = DBLARR(2,4) gridbndry[0,*] = [0, 0, nx-1, nx-1] gridbndry[1,*] = [0, ny-1, ny-1, 0] ENDELSE ENDIF ; Create 2D arrays for the grid - Rxy = FLTARR(TOTAL(nrad,/int), npol_total) + Rxy = DBLARR(TOTAL(nrad,/int), npol_total) Zxy = Rxy Rixy = Rxy Zixy = Rxy @@ -2124,7 +2124,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ vec_in_down_r = vec_in_down_r / vec_length vec_in_down_z = vec_in_down_z / vec_length vec_in_down1 = [vec_in_down_r, vec_in_down_z] - vec_out_down1= -vec_in_down1 ;; [-1,1]/(SQRT(2.)) + vec_out_down1= -vec_in_down1 ;; [-1,1]/(SQRT(2.D)) vec_in_up1 = TRANSPOSE(-vecpvt[0,*]) vec_out_up1 = TRANSPOSE(vec2[0,*]) sp_loc = -1 @@ -2225,16 +2225,16 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ ydown_dist = xpt_dist[xpt, 1] yup_dist = xpt_dist[xpt2, 2] ; Grid spacing - ydown_space = MAX([xpt_dist[xpt, 1], xpt_dist[xpt, 2]]) ;0.5*(xpt_dist[xpt, 1] + xpt_dist[xpt, 2]) - yup_space = MAX([xpt_dist[xpt2, 1], xpt_dist[xpt2, 2]]) ;0.5*(xpt_dist[xpt2, 1] + xpt_dist[xpt2, 2]) + ydown_space = MAX([xpt_dist[xpt, 1], xpt_dist[xpt, 2]]) ;0.5D*(xpt_dist[xpt, 1] + xpt_dist[xpt, 2]) + yup_space = MAX([xpt_dist[xpt2, 1], xpt_dist[xpt2, 2]]) ;0.5D*(xpt_dist[xpt2, 1] + xpt_dist[xpt2, 2]) ; Separatrix lines near X-point. Used for coordinate ; lines passing close to the X-point. - sep_line_down = FLTARR(2, N_ELEMENTS((*sep_info[xpt]).core2_ri)) + sep_line_down = DBLARR(2, N_ELEMENTS((*sep_info[xpt]).core2_ri)) sep_line_down[0,*] = (*sep_info[xpt]).core2_ri sep_line_down[1,*] = (*sep_info[xpt]).core2_zi - sep_line_up = FLTARR(2, N_ELEMENTS((*sep_info[xpt2]).core1_ri)) + sep_line_up = DBLARR(2, N_ELEMENTS((*sep_info[xpt2]).core1_ri)) sep_line_up[0,*] = (*sep_info[xpt2]).core1_ri sep_line_up[1,*] = (*sep_info[xpt2]).core1_zi @@ -2307,7 +2307,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ IF i EQ 0 THEN BEGIN vec_in_up1=[0,-1] - vec_out_up1=[-1,-1]/(SQRT(2.)) + vec_out_up1=[-1,-1]/(SQRT(2.D)) ENDIF ELSE BEGIN vec_in_up1=[1,0] vec_out_up1=[1,0] @@ -2490,7 +2490,7 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ rad_peaking:settings.rad_peaking, pol_peaking:settings.pol_peaking} ; Calculate magnetic field components - dpsidR = FLTARR(TOTAL(nrad, /int), npol_total) + dpsidR = DBLARR(TOTAL(nrad, /int), npol_total) dpsidZ = dpsidR interp_data.method = 2 @@ -2500,8 +2500,8 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ local_gradient, interp_data, Rixy[i,j], Zixy[i,j], status=status, $ dfdr=dfdr, dfdz=dfdz ; dfd* are derivatives wrt the indices. Need to multiply by dr/di etc - dpsidR[i,j] = dfdr/INTERPOLATE(DERIV(R),Rixy[i,j]) - dpsidZ[i,j] = dfdz/INTERPOLATE(DERIV(Z),Zixy[i,j]) + dpsidR[i,j] = dfdr/INTERPOLATE(DERIV(R),Rixy[i,j], /DOUBLE) + dpsidZ[i,j] = dfdz/INTERPOLATE(DERIV(Z),Zixy[i,j], /DOUBLE) ENDFOR ENDFOR diff --git a/tools/tokamak_grids/gridgen/curvature.pro b/tools/tokamak_grids/gridgen/curvature.pro index 80ed9424d5..2db3df6699 100644 --- a/tools/tokamak_grids/gridgen/curvature.pro +++ b/tools/tokamak_grids/gridgen/curvature.pro @@ -15,13 +15,13 @@ FUNCTION pdiff_rz, rxy, zxy, fxy, i, j, jp, jm ;IF j EQ 0 THEN STOP - A=TRANSPOSE([[fltarr(4)+1],[r-r(0)],[z-z(0)]]) + A=TRANSPOSE([[DBLARR(4)+1],[r-r(0)],[z-z(0)]]) SVDC, A,W,U,V res=SVSOL(U,W,V,f) - pdiff={r:res[1],z:res[2],phi:0.0} + pdiff={r:res[1],z:res[2],phi:0.0D} RETURN, pdiff END @@ -103,13 +103,13 @@ PRO curvature, nx, ny, Rxy, Zxy, BRxy, BZxy, BPHIxy, PSIxy, THETAxy, HTHExy, $ PRINT, 'Calculating curvature-related quantities...' ;;-vector quantities are stored as 2D arrays of structures {r,phi,z} - vec={r:0.,phi:0.,z:0.} + vec={r:0.D,phi:0.D,z:0.D} curlb=REPLICATE(vec,nx,ny) jxb=REPLICATE(vec,nx,ny) curvec=REPLICATE(vec,nx,ny) bxcurvec=REPLICATE(vec,nx,ny) - vec2={psi:0.,theta:0.,phi:0.} + vec2={psi:0.D,theta:0.D,phi:0.D} bxcv=REPLICATE(vec2,nx,ny) status = gen_surface_hypnotoad(mesh=mesh) ; Start generator @@ -147,9 +147,9 @@ PRO curvature, nx, ny, Rxy, Zxy, BRxy, BZxy, BPHIxy, PSIxy, THETAxy, HTHExy, $ grad_Psi = pdiff_rz(Rxy, Zxy, PSIxy, x, y, yp, ym) ;grad_Theta = pdiff_rz(Rxy, Zxy, THETAxy, x, y, yp, ym) - grad_Theta = {r:dr[j]/hthexy[x,y], z:dz[j]/hthexy[x,y], phi:0.0} + grad_Theta = {r:dr[j]/hthexy[x,y], z:dz[j]/hthexy[x,y], phi:0.0D} - grad_Phi={r:0.0,z:0.0,phi:1./Rxy[x,y]} ;-gradient of the toroidal angle + grad_Phi={r:0.0D,z:0.0D,phi:1.D/Rxy[x,y]} ;-gradient of the toroidal angle vecR={r:Rxy[x,y],z:Zxy[x,y]} vecB={r:BRxy[x,y],z:BZxy[x,y],phi:BPHIxy[x,y]} diff --git a/tools/tokamak_grids/gridgen/dct.pro b/tools/tokamak_grids/gridgen/dct.pro index ed493a5ac4..f4c6f0dbef 100644 --- a/tools/tokamak_grids/gridgen/dct.pro +++ b/tools/tokamak_grids/gridgen/dct.pro @@ -14,13 +14,13 @@ ; ; NOTE: Inverse not working! FUNCTION DCTany, x, inverse=inverse - j = DCOMPLEX(0.0, 1.0) + j = DCOMPLEX(0.0D, 1.0D) n = N_ELEMENTS(x) data = x IF KEYWORD_SET(inverse) THEN BEGIN - data[0] = data[0] / SQRT(2) + data[0] = data[0] / SQRT(2.D) PRINT, "SORRY, NOT WORKING YET" STOP ENDIF @@ -30,9 +30,9 @@ FUNCTION DCTany, x, inverse=inverse ; Take FFT of 2N f = FFT(x2, /double) - result = REAL_PART(f[0:(N-1)] * EXP(-j*DINDGEN(N)*!PI / (2.*N)) ) + result = REAL_PART(f[0:(N-1)] * EXP(-j*DINDGEN(N)*!DPI / (2.D*N)) ) - IF NOT KEYWORD_SET(inverse) THEN result[0] = result[0] / SQRT(2) + IF NOT KEYWORD_SET(inverse) THEN result[0] = result[0] / SQRT(2.D) RETURN, result END @@ -47,7 +47,7 @@ FUNCTION DCT, x, inverse=inverse RETURN, DCTany(x, inverse=inverse) ENDIF - j = DCOMPLEX(0.0, 1.0) + j = DCOMPLEX(0.0D, 1.0D) IF NOT KEYWORD_SET(inverse) THEN BEGIN @@ -62,24 +62,24 @@ FUNCTION DCT, x, inverse=inverse yf = FFT(DOUBLE(y), /double) ; Multiply by phase - result = REAL_PART(yf * EXP(-j*DINDGEN(n)*!PI/(2.*DOUBLE(n))) ) + result = REAL_PART(yf * EXP(-j*DINDGEN(n)*!DPI/(2.D*DOUBLE(n))) ) result[0] = result[0] / SQRT(2.d) RETURN, result ENDIF ELSE BEGIN - yf = DCOMPLEX(x) * EXP(j*DINDGEN(n)*!PI/(2.*DOUBLE(n))) - yf[0] = yf[0] / SQRT(2.) + yf = DCOMPLEX(x) * EXP(j*DINDGEN(n)*!DPI/(2.D*DOUBLE(n))) + yf[0] = yf[0] / SQRT(2.D) y = REAL_PART(FFT(yf, /inverse, /double)) - result = FLTARR(n) + result = DBLARR(n) FOR i=0, n/2 - 1 DO BEGIN result[2*i] = y[i] result[2*i+1] = y[n-1-i] ENDFOR - RETURN, 2.*result + RETURN, 2.D*result ENDELSE END diff --git a/tools/tokamak_grids/gridgen/dct2d.pro b/tools/tokamak_grids/gridgen/dct2d.pro index ca1c813f5d..c5fe65c67a 100644 --- a/tools/tokamak_grids/gridgen/dct2d.pro +++ b/tools/tokamak_grids/gridgen/dct2d.pro @@ -26,9 +26,9 @@ FUNCTION DCT2D, sig, inverse=inverse ENDFOR IF NOT KEYWORD_SET(inverse) THEN BEGIN - result = result * 2. * SQRT(nx*ny) + result = result * 2.D * SQRT(nx*ny) ENDIF ELSE BEGIN - result = result / (2.* SQRT(nx*ny)) + result = result / (2.D* SQRT(nx*ny)) ENDELSE RETURN, result diff --git a/tools/tokamak_grids/gridgen/dct2dslow.pro b/tools/tokamak_grids/gridgen/dct2dslow.pro index 52e50a6454..7979bbc760 100644 --- a/tools/tokamak_grids/gridgen/dct2dslow.pro +++ b/tools/tokamak_grids/gridgen/dct2dslow.pro @@ -34,7 +34,7 @@ IF NOT KEYWORD_SET(INVERSE) THEN BEGIN ;---direct transform--- endfor endfor - fsig *= 2/SQRT(double(Nx*Ny)) + fsig *= 2.D/SQRT(double(Nx*Ny)) fsig[0,*] *= SQRT(0.5d0) fsig[*,0] *= SQRT(0.5d0) @@ -60,7 +60,7 @@ ENDIF ELSE BEGIN ;---inverse transform--- endfor endfor - sig *= 2/SQRT(double(NX*NY)) + sig *= 2.D/SQRT(double(NX*NY)) ENDELSE diff --git a/tools/tokamak_grids/gridgen/ddy.pro b/tools/tokamak_grids/gridgen/ddy.pro index 7692596a21..a194d4ad2a 100644 --- a/tools/tokamak_grids/gridgen/ddy.pro +++ b/tools/tokamak_grids/gridgen/ddy.pro @@ -2,7 +2,7 @@ FUNCTION ddy, var, mesh f = var - dtheta = 2.*!PI / FLOAT(TOTAL(mesh.npol)) + dtheta = 2.D*!DPI / DOUBLE(TOTAL(mesh.npol)) status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN diff --git a/tools/tokamak_grids/gridgen/evalcosp.pro b/tools/tokamak_grids/gridgen/evalcosp.pro index e272386f16..446c551366 100644 --- a/tools/tokamak_grids/gridgen/evalcosp.pro +++ b/tools/tokamak_grids/gridgen/evalcosp.pro @@ -16,48 +16,48 @@ function EvalCosP, fsig, x0=x0,y0=y0 nx=s[0] ny=s[1] - sum=0.0 + sum=0.0D ; First derivatives - sumx=0.0 - sumy=0.0 + sumx=0.0D + sumy=0.0D ; Second derivatives - sumxx = 0.0 - sumyy = 0.0 - sumxy = 0.0 + sumxx = 0.0D + sumyy = 0.0D + sumxy = 0.0D for iu=0,Nx-1 do begin for jv=0,Ny-1 do begin ; - if (iu eq 0) then cu=0.707107 else cu=1. - if (jv eq 0) then cv=0.707107 else cv=1. + if (iu eq 0) then cu=0.707107D else cu=1.D + if (jv eq 0) then cv=0.707107D else cv=1.D sum=sum + cv*cu*fsig[iu,jv]*$ - COS(jv*!PI*(2*y0+1)/(2*Ny))*COS(iu*!PI*(2*x0+1)/(2*Nx)) + COS(jv*!DPI*(2*y0+1)/(2*Ny))*COS(iu*!DPI*(2*x0+1)/(2*Nx)) sumx=sumx + cv*cu*fsig[iu,jv]*$ - COS(jv*!PI*(2*y0+1)/(2*Ny))*SIN(iu*!PI*(2*x0+1)/(2*Nx))*$ - (-iu*!PI/Nx) + COS(jv*!DPI*(2*y0+1)/(2*Ny))*SIN(iu*!DPI*(2*x0+1)/(2*Nx))*$ + (-iu*!DPI/Nx) sumy=sumy + cv*cu*fsig[iu,jv]*$ - SIN(jv*!PI*(2*y0+1)/(2*Ny))*COS(iu*!PI*(2*x0+1)/(2*Nx))*$ - (-jv*!PI/Ny) + SIN(jv*!DPI*(2*y0+1)/(2*Ny))*COS(iu*!DPI*(2*x0+1)/(2*Nx))*$ + (-jv*!DPI/Ny) sumxx = sumxx - cv*cu*fsig[iu,jv]*$ - COS(jv*!PI*(2*y0+1)/(2*Ny))*COS(iu*!PI*(2*x0+1)/(2*Nx))*$ - (iu*!PI/Nx)^2 + COS(jv*!DPI*(2*y0+1)/(2*Ny))*COS(iu*!DPI*(2*x0+1)/(2*Nx))*$ + (iu*!DPI/Nx)^2 sumyy = sumyy - cv*cu*fsig[iu,jv]*$ - COS(jv*!PI*(2*y0+1)/(2*Ny))*COS(iu*!PI*(2*x0+1)/(2*Nx))*$ - (jv*!PI/Ny)^2 + COS(jv*!DPI*(2*y0+1)/(2*Ny))*COS(iu*!DPI*(2*x0+1)/(2*Nx))*$ + (jv*!DPI/Ny)^2 sumxy = sumxy + cv*cu*fsig[iu,jv]*$ - SIN(jv*!PI*(2*y0+1)/(2*Ny))*SIN(iu*!PI*(2*x0+1)/(2*Nx))*$ - (iu*!PI/Nx)*(jv*!PI/Ny) + SIN(jv*!DPI*(2*y0+1)/(2*Ny))*SIN(iu*!DPI*(2*x0+1)/(2*Nx))*$ + (iu*!DPI/Nx)*(jv*!DPI/Ny) ; endfor endfor - res=SQRT(2./Nx)*SQRT(2./Ny)*[sum, sumx,sumy, sumxx,sumyy,sumxy] + res=SQRT(2.D/Nx)*SQRT(2.D/Ny)*[sum, sumx,sumy, sumxx,sumyy,sumxy] ; ; ; diff --git a/tools/tokamak_grids/gridgen/evalcospfast.pro b/tools/tokamak_grids/gridgen/evalcospfast.pro index 63417b3c67..47e259310f 100644 --- a/tools/tokamak_grids/gridgen/evalcospfast.pro +++ b/tools/tokamak_grids/gridgen/evalcospfast.pro @@ -14,26 +14,26 @@ function EvalCosPfast, fsig, x0=x0,y0=y0 nx=s[0] ny=s[1] - cuvec=fltarr(nx)+1. - cuvec[0]=1./SQRT(2.) + cuvec=DBLARR(nx)+1.D + cuvec[0]=1.D/SQRT(2.D) - cvvec=fltarr(ny)+1. - cvvec[0]=1./SQRT(2.) + cvvec=DBLARR(ny)+1.D + cvvec[0]=1.D/SQRT(2.D) - uvec=COS(!PI*findgen(nx)*(x0+0.5)/nx) - uvex=(-findgen(nx)*!PI/nx)*SIN(!PI*findgen(nx)*(x0+0.5)/nx) + uvec=COS(!DPI*findgen(nx)*(x0+0.5D)/nx) + uvex=(-findgen(nx)*!DPI/nx)*SIN(!DPI*findgen(nx)*(x0+0.5D)/nx) - vvec=COS(!PI*findgen(ny)*(y0+0.5)/ny) - vvey=(-findgen(ny)*!PI/ny)*SIN(!PI*findgen(ny)*(y0+0.5)/ny) + vvec=COS(!DPI*findgen(ny)*(y0+0.5D)/ny) + vvey=(-findgen(ny)*!DPI/ny)*SIN(!DPI*findgen(ny)*(y0+0.5D)/ny) ;-value - res=SQRT(2./nx)*SQRT(2./ny) * TOTAL(((cuvec # cvvec) * fsig) * (uvec # vvec)) + res=SQRT(2.D/nx)*SQRT(2.D/ny) * TOTAL(((cuvec # cvvec) * fsig) * (uvec # vvec)) ;d/dx - rex=SQRT(2./nx)*SQRT(2./ny) * TOTAL(((cuvec # cvvec) * fsig) * (uvex # vvec)) + rex=SQRT(2.D/nx)*SQRT(2.D/ny) * TOTAL(((cuvec # cvvec) * fsig) * (uvex # vvec)) ;d/dy - rey=SQRT(2./nx)*SQRT(2./ny) * TOTAL(((cuvec # cvvec) * fsig) * (uvec # vvey)) + rey=SQRT(2.D/nx)*SQRT(2.D/ny) * TOTAL(((cuvec # cvvec) * fsig) * (uvec # vvey)) ; ; diff --git a/tools/tokamak_grids/gridgen/flux_tube.pro b/tools/tokamak_grids/gridgen/flux_tube.pro index 39381dc9d1..7f00523d21 100644 --- a/tools/tokamak_grids/gridgen/flux_tube.pro +++ b/tools/tokamak_grids/gridgen/flux_tube.pro @@ -3,7 +3,7 @@ ; For example, a DIII-D case. ; Not a particularly good case, as pressure goes negative ; -; IDL> flux_tube, "efit/neqdsk", 0.8 +; IDL> flux_tube, "efit/neqdsk", 0.8D ; ; NOTE: NOT WORKING PROPERLY YET. MAGNETIC SHEAR MUCH TOO LARGE ; @@ -15,7 +15,7 @@ PRO flux_tube, gfile, psinorm, output=output IF NOT KEYWORD_SET(output) THEN output="fluxtube"+STR(psinorm)+".grd.nc" - IF (psinorm LT 0.) OR (psinorm GE 1.) THEN BEGIN + IF (psinorm LT 0.D) OR (psinorm GE 1.D) THEN BEGIN PRINT, "ERROR: input psinorm must be between 0 and 1" RETURN ENDIF @@ -43,7 +43,7 @@ PRO flux_tube, gfile, psinorm, output=output nlev = 100 minf = MIN(rzgrid.psi) maxf = MAX(rzgrid.psi) - levels = findgen(nlev)*(maxf-minf)/FLOAT(nlev-1) + minf + levels = findgen(nlev)*(maxf-minf)/DOUBLE(nlev-1) + minf safe_colors, /first CONTOUR, rzgrid.psi, rzgrid.R, rzgrid.Z, $ @@ -121,26 +121,26 @@ PRO flux_tube, gfile, psinorm, output=output ;zi = REAL_PART(fft_filter(zi, nfreq)) ; Plot the flux surface - OPLOT, INTERPOLATE(rzgrid.R, ri), INTERPOLATE(rzgrid.Z, zi), color=4, thick=2 + OPLOT, INTERPOLATE(rzgrid.R, ri, /DOUBLE), INTERPOLATE(rzgrid.Z, zi, /DOUBLE), color=4, thick=2 ; Get quantities from g-eqdsk ngrid = N_ELEMENTS(g.fpol) gpos = psinorm * ngrid ; Index into the psi grid. CHECK THIS - psigrid = psi_axis + (psi_sep - psi_axis)*FINDGEN(ngrid)/FLOAT(ngrid) - fpol = INTERPOLATE(g.fpol, gpos) ; Poloidal current function - pres = INTERPOLATE(g.pres, gpos) ; Pressure [Pascals] - dpdpsi = INTERPOLATE(DERIV(psigrid, g.pres), gpos) - dfdpsi = INTERPOLATE(DERIV(psigrid, g.fpol), gpos) - qsafe = INTERPOLATE(g.qpsi, gpos) ; q + psigrid = psi_axis + (psi_sep - psi_axis)*FINDGEN(ngrid)/DOUBLE(ngrid) + fpol = INTERPOLATE(g.fpol, gpos, /DOUBLE) ; Poloidal current function + pres = INTERPOLATE(g.pres, gpos, /DOUBLE) ; Pressure [Pascals] + dpdpsi = INTERPOLATE(DERIV(psigrid, g.pres), gpos, /DOUBLE) + dfdpsi = INTERPOLATE(DERIV(psigrid, g.fpol), gpos, /DOUBLE) + qsafe = INTERPOLATE(g.qpsi, gpos, /DOUBLE) ; q PRINT, "Pressure [Pa]: " + STR(pres) PRINT, "Safety factor: " + STR(qsafe) - Rmaj = INTERPOLATE(rzgrid.R, ri) ; Major radius + Rmaj = INTERPOLATE(rzgrid.R, ri, /DOUBLE) ; Major radius ; Use DCT to get local gradients of psi for Bp np = N_ELEMENTS(ri) - Bpol = FLTARR(np) + Bpol = DBLARR(np) FOR i=0, np-1 DO BEGIN grad = local_gradient(dctpsi, ri[i], zi[i], status=status) IF status THEN BEGIN @@ -164,8 +164,8 @@ PRO flux_tube, gfile, psinorm, output=output ; distance along field-line ; Poloidal distance dl/di (i = index) - drdi = REAL_PART(fft_deriv(INTERPOLATE(rzgrid.R, ri))) - dzdi = REAL_PART(fft_deriv(INTERPOLATE(rzgrid.Z, zi))) + drdi = REAL_PART(fft_deriv(INTERPOLATE(rzgrid.R, ri, /DOUBLE))) + dzdi = REAL_PART(fft_deriv(INTERPOLATE(rzgrid.Z, zi, /DOUBLE))) dldi = SQRT(drdi^2 + dzdi^2) ; Integrate to get distance in poloidal direction @@ -184,7 +184,7 @@ PRO flux_tube, gfile, psinorm, output=output s = REAL_PART(fft_integrate(dsdi, loop=pardist)) pardist = REAL_PART(pardist) - PRINT, "Safety factor = "+STR(qloop/(2.*!PI))+" ("+STR(qsafe)+" in g-file)" + PRINT, "Safety factor = "+STR(qloop/(2.D*!DPI))+" ("+STR(qsafe)+" in g-file)" PRINT, "Poloidal distance = "+STR(poldist)+"m" PRINT, "Parallel distance = "+STR(pardist)+"m" @@ -218,33 +218,33 @@ PRO flux_tube, gfile, psinorm, output=output END ENDCASE - pos = tot * FINDGEN(npar)/FLOAT(npar) + pos = tot * FINDGEN(npar)/DOUBLE(npar) inds = INTERPOL(FINDGEN(np), dist, pos) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Interpolate everything onto grid - ri = INTERPOLATE(ri, inds) - zi = INTERPOLATE(zi, inds) - Bpol = INTERPOLATE(Bpol, inds) - Btor = INTERPOLATE(Btor, inds) + ri = INTERPOLATE(ri, inds, /DOUBLE) + zi = INTERPOLATE(zi, inds, /DOUBLE) + Bpol = INTERPOLATE(Bpol, inds, /DOUBLE) + Btor = INTERPOLATE(Btor, inds, /DOUBLE) B = SQRT(Bpol^2 + Btor^2) - Rmaj = INTERPOLATE(rzgrid.R, ri) - Zpos = INTERPOLATE(rzgrid.Z, zi) - qinty = INTERPOLATE(qinty, inds) - s = INTERPOLATE(s, inds) ; parallel distance - l = INTERPOLATE(l, inds) ; poloidal distance - hthe = DERIV(l) / (2.*!PI / FLOAT(npar)) + Rmaj = INTERPOLATE(rzgrid.R, ri, /DOUBLE) + Zpos = INTERPOLATE(rzgrid.Z, zi, /DOUBLE) + qinty = INTERPOLATE(qinty, inds, /DOUBLE) + s = INTERPOLATE(s, inds, /DOUBLE) ; parallel distance + l = INTERPOLATE(l, inds, /DOUBLE) ; poloidal distance + hthe = DERIV(l) / (2.D*!DPI / DOUBLE(npar)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Calculate psi derivatives - dpsidR = FLTARR(npar) - dpsidZ = FLTARR(npar) - dRdpsi = FLTARR(npar) ; dR / dpsi - dZdpsi = FLTARR(npar) ; dZ / dpsi - dBpdR = FLTARR(npar) - dBpdZ = FLTARR(npar) + dpsidR = DBLARR(npar) + dpsidZ = DBLARR(npar) + dRdpsi = DBLARR(npar) ; dR / dpsi + dZdpsi = DBLARR(npar) ; dZ / dpsi + dBpdR = DBLARR(npar) + dBpdZ = DBLARR(npar) FOR i=0, npar-1 DO BEGIN ; Get gradients of psi grad = EvalCosP(dctpsi, x0=ri[i], y0=zi[i]) @@ -275,14 +275,14 @@ PRO flux_tube, gfile, psinorm, output=output ;;;;;;;;;;;;;;;;;; MAGNETIC SHEAR ;;;;;;;;;;;;;;;;;;;; ; Calculate from radial force balance equation - MU0 = 4.e-7 * !PI + MU0 = 4.d-7 * !DPI pitch = hthe * Btor / (Bpol * Rmaj) - dnudpsi = - ( (MU0*hthe*dpdpsi/Bpol) + pitch*( 2.*Rmaj*B*dBdpsi/Bpol + B^2*dRdpsi/Bpol - B^2*Rmaj*dBpdpsi/(Bpol^2) ) ) / (Rmaj*Bpol^2 / Btor) + dnudpsi = - ( (MU0*hthe*dpdpsi/Bpol) + pitch*( 2.D*Rmaj*B*dBdpsi/Bpol + B^2*dRdpsi/Bpol - B^2*Rmaj*dBpdpsi/(Bpol^2) ) ) / (Rmaj*Bpol^2 / Btor) ; Integrate this to get the integrated shear sinty - sinty = REAL_PART(fft_integrate(dnudpsi, loop=sloop)) * 2.*!PI/FLOAT(npar) - sloop = REAL_PART(sloop) * 2.*!PI/FLOAT(npar) + sinty = REAL_PART(fft_integrate(dnudpsi, loop=sloop)) * 2.D*!DPI/DOUBLE(npar) + sloop = REAL_PART(sloop) * 2.D*!DPI/DOUBLE(npar) ; Want this shift to be zero at the outboard midplane, ; and matching location on inboard side @@ -312,7 +312,7 @@ PRO flux_tube, gfile, psinorm, output=output ; Components of curvature (unit vectors) kr = d2r - Rmaj*dp^2 kz = d2z - kp = 2.*dr*dp + Rmaj*d2p + kp = 2.D*dr*dp + Rmaj*d2p ; Calculate bxk in cylindrical coordinates @@ -354,7 +354,7 @@ PRO flux_tube, gfile, psinorm, output=output mri = MAX(Rmaj, rmaxi) ; Get index at outboard midplane CASE opt OF 1: BEGIN - dr = 0.01*get_float("Enter radial size [cm]:") + dr = 0.01D*get_float("Enter radial size [cm]:") dpsi = Bpol[rmaxi]*Rmaj[rmaxi]*dr dpsin = dpsi / (psi_sep - psi_axis) END @@ -376,32 +376,32 @@ PRO flux_tube, gfile, psinorm, output=output PRINT, " Width [cm] "+STR(dr) PRINT, " [psin] "+STR(dpsin) PRINT, " [psi] "+STR(dpsi) - PRINT, " Safety factor variation: +/-"+STR(sloop*dpsi / (2.*!PI) / 2.) + PRINT, " Safety factor variation: +/-"+STR(sloop*dpsi / (2.D*!DPI) / 2.D) PRINT, "" ; Convert into cell width - dr = dr / FLOAT(nrad) - dpsi = dpsi / FLOAT(nrad) - dpsin = dpsin / FLOAT(nrad) + dr = dr / DOUBLE(nrad) + dpsi = dpsi / DOUBLE(nrad) + dpsin = dpsin / DOUBLE(nrad) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Put everything into 2D arrays - rmid = FLOAT(nrad) / 2. + rmid = DOUBLE(nrad) / 2.D rpsi = (FINDGEN(nrad) - rmid) * dpsi ; Pressure profile. Only gradient used as drive term - pressure = FLTARR(nrad, npar) - Jpar0 = FLTARR(nrad, npar) + pressure = DBLARR(nrad, npar) + Jpar0 = DBLARR(nrad, npar) FOR i=0, nrad-1 DO BEGIN pressure[i,*] = pres + rpsi[i]*dpdpsi ; Linear in x Jpar0[i,*] = Jpar ; Constant in x ENDFOR ; B field components - Bpxy = FLTARR(nrad, npar) - Btxy = FLTARR(nrad, npar) - Bxy = FLTARR(nrad, npar) + Bpxy = DBLARR(nrad, npar) + Btxy = DBLARR(nrad, npar) + Bxy = DBLARR(nrad, npar) FOR i=0, nrad-1 DO BEGIN Bpxy[i,*] = Bpol Btxy[i,*] = Btor @@ -409,13 +409,13 @@ PRO flux_tube, gfile, psinorm, output=output ENDFOR ; Grid spacing - dx = FLTARR(nrad, npar) + dpsi - dy = FLTARR(nrad, npar) + 2.*!PI/FLOAT(npar) + dx = DBLARR(nrad, npar) + dpsi + dy = DBLARR(nrad, npar) + 2.D*!DPI/DOUBLE(npar) ; Geometrical quantities - hxy = FLTARR(nrad, npar) - Rxy = FLTARR(nrad, npar) - Zxy = FLTARR(nrad, npar) + hxy = DBLARR(nrad, npar) + Rxy = DBLARR(nrad, npar) + Zxy = DBLARR(nrad, npar) FOR i=0, nrad-1 DO BEGIN hxy[i,*] = hthe Rxy[i,*] = Rmaj @@ -423,7 +423,7 @@ PRO flux_tube, gfile, psinorm, output=output ENDFOR ; Curvature - bxcvx = FLTARR(nrad, npar) + bxcvx = DBLARR(nrad, npar) bxcvy = bxcvx bxcvz = bxcvx FOR i=0, nrad-1 DO BEGIN @@ -437,12 +437,12 @@ PRO flux_tube, gfile, psinorm, output=output ShiftAngle = qloop + rpsi * sloop ; Integrated shear - sinty2 = FLTARR(nrad, npar) + sinty2 = DBLARR(nrad, npar) FOR i=0, nrad-1 DO sinty2[i,*] = sinty ; Toroidal shift for shifted radial derivatives (optional) ; As with twist-shift, this is a linear expansion - zShift = FLTARR(nrad, npar) + zShift = DBLARR(nrad, npar) FOR i=0, nrad-1 DO BEGIN zShift[i,*] = qinty-qinty[rmaxi] + rpsi[i]*sinty ENDFOR diff --git a/tools/tokamak_grids/gridgen/follow_gradient.pro b/tools/tokamak_grids/gridgen/follow_gradient.pro index 0e0da70b23..1b753a6f18 100644 --- a/tools/tokamak_grids/gridgen/follow_gradient.pro +++ b/tools/tokamak_grids/gridgen/follow_gradient.pro @@ -36,8 +36,8 @@ FUNCTION radial_differential, fcur, pos ENDIF ENDIF - dRdi = INTERPOLATE(DERIV(R), pos[0]) - dZdi = INTERPOLATE(DERIV(Z), pos[1]) + dRdi = INTERPOLATE(DERIV(R), pos[0], /DOUBLE) + dZdi = INTERPOLATE(DERIV(Z), pos[1], /DOUBLE) ; Check mismatch between fcur and f ? Br = dfdz/dZdi @@ -63,7 +63,7 @@ PRO follow_gradient, interp_data, R, Z, ri0, zi0, ftarget, ri, zi, status=status boundary=boundary, fbndry=fbndry, ibndry=ibndry COMMON rd_com, idata, lastgoodf, lastgoodpos, Rpos, Zpos, ood, bndry, ri0c, zi0c, tol - tol = 0.1 + tol = 0.1D Rpos = R Zpos = Z @@ -152,7 +152,7 @@ PRO follow_gradient, interp_data, R, Z, ri0, zi0, ftarget, ri, zi, status=status ; Repeat to verify that this does work rzold = [ri0, zi0] CATCH, theError - fbndry = lastgoodf - 0.1*(ftarget - f0) + fbndry = lastgoodf - 0.1D*(ftarget - f0) IF theError NE 0 THEN BEGIN PRINT, " Error again at ", fbndry ENDIF @@ -171,11 +171,11 @@ PRO follow_gradient, interp_data, R, Z, ri0, zi0, ftarget, ri, zi, status=status cpos = line_crossings([ri0, ri], [zi0, zi], 0, $ boundary[0,*], boundary[1,*], 1, ncross=ncross, inds2=inds2) IF (ncross MOD 2) EQ 1 THEN BEGIN ; Odd number of boundary crossings - IF SQRT( (ri - cpos[0,0])^2 + (zi - cpos[1,0])^2 ) GT 0.1 THEN BEGIN + IF SQRT( (ri - cpos[0,0])^2 + (zi - cpos[1,0])^2 ) GT 0.1D THEN BEGIN ;PRINT, "FINDING BOUNDARY", SQRT( (ri - cpos[0,0])^2 + (zi - cpos[1,0])^2 ) ; Use divide-and-conquer to find crossing point - tol = 1e-4 ; Make the boundary crossing stricter + tol = 1d-4 ; Make the boundary crossing stricter ibndry = inds2[0] ; Index in boundary where hit @@ -200,7 +200,7 @@ PRO follow_gradient, interp_data, R, Z, ri0, zi0, ftarget, ri, zi, status=status CATCH, /cancel ENDELSE - ENDREP UNTIL ABS(fmax - fcur) LT 0.01*ABS(ftarget - f0) + ENDREP UNTIL ABS(fmax - fcur) LT 0.01D*ABS(ftarget - f0) ri = rzcur[0] zi = rzcur[1] fbndry = fcur @@ -213,4 +213,4 @@ PRO follow_gradient, interp_data, R, Z, ri0, zi0, ftarget, ri, zi, status=status ENDIF status = 0 -END \ No newline at end of file +END diff --git a/tools/tokamak_grids/gridgen/follow_gradient_nonorth.pro b/tools/tokamak_grids/gridgen/follow_gradient_nonorth.pro index 8dc1594322..1450514280 100644 --- a/tools/tokamak_grids/gridgen/follow_gradient_nonorth.pro +++ b/tools/tokamak_grids/gridgen/follow_gradient_nonorth.pro @@ -36,8 +36,8 @@ FUNCTION radial_differential_nonorth, fcur, pos ENDIF ENDIF - dRdi = INTERPOLATE(DERIV(R), pos[0]) - dZdi = INTERPOLATE(DERIV(Z), pos[1]) + dRdi = INTERPOLATE(DERIV(R), pos[0], /DOUBLE) + dZdi = INTERPOLATE(DERIV(Z), pos[1], /DOUBLE) ; Check mismatch between fcur and f ? Br = dfdz/dZdi @@ -85,7 +85,7 @@ PRO follow_gradient_nonorth, interp_data, R, Z, ri0, zi0, ftarget, ri, zi, statu bndry_noperiodic=bndry_noperiodic COMMON rd_com_no, idata, lastgoodf, lastgoodpos, Rpos, Zpos, ood, bndry, ri0c, zi0c, tol, vec_comm_up, weightc_up, vec_comm_down, weightc_down, bndry_periodic - tol = 0.1 + tol = 0.1D Rpos = R Zpos = Z @@ -105,21 +105,21 @@ PRO follow_gradient_nonorth, interp_data, R, Z, ri0, zi0, ftarget, ri, zi, statu IF KEYWORD_SET(bndry_noperiodic) THEN bndry_periodic = 0 IF NOT KEYWORD_SET(weight_up) THEN BEGIN - weight_up = 0. - weightc_up = weight_up*1.0 + weight_up = 0.D + weightc_up = weight_up*1.0D ENDIF IF NOT KEYWORD_SET(weight_down) THEN BEGIN - weight_down = 0. - weightc_down = weight_down*1.0 + weight_down = 0.D + weightc_down = weight_down*1.0D ENDIF IF KEYWORD_SET(vec_up) THEN BEGIN vec_comm_up = vec_up - weightc_up = weight_up*1.0 + weightc_up = weight_up*1.0D ENDIF IF KEYWORD_SET(vec_down) THEN BEGIN vec_comm_down = vec_down - weightc_down = weight_down*1.0 + weightc_down = weight_down*1.0D ENDIF IF SIZE(ftarget, /TYPE) EQ 0 THEN PRINT, ftarget @@ -195,7 +195,7 @@ PRO follow_gradient_nonorth, interp_data, R, Z, ri0, zi0, ftarget, ri, zi, statu ; Repeat to verify that this does work rzold = [ri0, zi0] CATCH, theError - fbndry = lastgoodf - 0.1*(ftarget - f0) + fbndry = lastgoodf - 0.1D*(ftarget - f0) IF theError NE 0 THEN BEGIN PRINT, " Error again at ", fbndry ENDIF @@ -215,7 +215,7 @@ PRO follow_gradient_nonorth, interp_data, R, Z, ri0, zi0, ftarget, ri, zi, statu boundary[0,*], boundary[1,*], bndry_periodic, ncross=ncross, inds2=inds2) IF (ncross MOD 2) EQ 1 THEN BEGIN ; Odd number of boundary crossings - IF SQRT( (ri - cpos[0,0])^2 + (zi - cpos[1,0])^2 ) GT 0.1 THEN BEGIN + IF SQRT( (ri - cpos[0,0])^2 + (zi - cpos[1,0])^2 ) GT 0.1D THEN BEGIN ;PRINT, "FINDING BOUNDARY", SQRT( (ri - cpos[0,0])^2 + (zi - cpos[1,0])^2 ) ; Use divide-and-conquer to find crossing point @@ -245,7 +245,7 @@ PRO follow_gradient_nonorth, interp_data, R, Z, ri0, zi0, ftarget, ri, zi, statu CATCH, /cancel ENDELSE - ENDREP UNTIL ABS(fmax - fcur) LT 0.01*ABS(ftarget - f0) + ENDREP UNTIL ABS(fmax - fcur) LT 0.01D*ABS(ftarget - f0) ri = rzcur[0] zi = rzcur[1] fbndry = fcur diff --git a/tools/tokamak_grids/gridgen/get_line.pro b/tools/tokamak_grids/gridgen/get_line.pro index eaadeb731c..8fdcb567fc 100644 --- a/tools/tokamak_grids/gridgen/get_line.pro +++ b/tools/tokamak_grids/gridgen/get_line.pro @@ -8,13 +8,13 @@ FUNCTION get_line, interp_data, R, Z, ri0, zi0, fto, npt=npt, vec=vec, weight=we RETURN, [[ri0,ri0],[zi0,zi0]] ENDIF - rixpt = FLTARR(npt+1) + rixpt = DBLARR(npt+1) zixpt = rixpt rixpt[0] = ri0 zixpt[0] = zi0 FOR j=0, npt-1 DO BEGIN - d = FLOAT(j+1)/FLOAT(npt) - ftarg = d*fto + (1.0 - d)*ffrom + d = DOUBLE(j+1)/DOUBLE(npt) + ftarg = d*fto + (1.0D - d)*ffrom follow_gradient, interp_data, R, Z, rixpt[j], zixpt[j], $ ftarg, rinext, zinext rixpt[j+1] = rinext diff --git a/tools/tokamak_grids/gridgen/get_line_nonorth.pro b/tools/tokamak_grids/gridgen/get_line_nonorth.pro index afbd031e35..eaae77555b 100644 --- a/tools/tokamak_grids/gridgen/get_line_nonorth.pro +++ b/tools/tokamak_grids/gridgen/get_line_nonorth.pro @@ -8,15 +8,15 @@ FUNCTION get_line_nonorth, interp_data, R, Z, ri0, zi0, fto, npt=npt, vec_up=vec RETURN, [[ri0,ri0],[zi0,zi0]] ENDIF - IF NOT KEYWORD_SET(weight_up) THEN weight_up = 0. - IF NOT KEYWORD_SET(weight_down) THEN weight_down = 0. - rixpt = FLTARR(npt+1) + IF NOT KEYWORD_SET(weight_up) THEN weight_up = 0.D + IF NOT KEYWORD_SET(weight_down) THEN weight_down = 0.D + rixpt = DBLARR(npt+1) zixpt = rixpt rixpt[0] = ri0 zixpt[0] = zi0 FOR j=0, npt-1 DO BEGIN - d = FLOAT(j+1)/FLOAT(npt) - ftarg = d*fto + (1.0 - d)*ffrom + d = DOUBLE(j+1)/DOUBLE(npt) + ftarg = d*fto + (1.0D - d)*ffrom follow_gradient_nonorth, interp_data, R, Z, rixpt[j], zixpt[j], $ ftarg, rinext, zinext, vec_up=vec_up, weight_up=weight_up, $ vec_down=vec_down, weight_down=weight_down diff --git a/tools/tokamak_grids/gridgen/gridgen.pro b/tools/tokamak_grids/gridgen/gridgen.pro index dcdfab70cd..b0bb65249d 100644 --- a/tools/tokamak_grids/gridgen/gridgen.pro +++ b/tools/tokamak_grids/gridgen/gridgen.pro @@ -2,7 +2,7 @@ FUNCTION simple_psi, r, z, r0, z0, mag nx = N_ELEMENTS(r) ny = N_ELEMENTS(z) - f = FLTARR(nx,ny) + f = DBLARR(nx,ny) mind = 5*SQRT((r[1]-r[0])^2 + (z[1]-z[0])^2) FOR i=0, nx-1 DO BEGIN @@ -19,13 +19,13 @@ PRO gridgen, debug=debug, settings=settings nx = 200 ny = 200 - R = FINDGEN(nx) / FLOAT(nx-1) - Z = (FINDGEN(ny) / FLOAT(ny-1)) - 0.5 + R = FINDGEN(nx) / DOUBLE(nx-1) + Z = (FINDGEN(ny) / DOUBLE(ny-1)) - 0.5D - f = simple_psi(R, Z, 0.5, 0.0, -1.0) $ - + simple_psi(R, Z, 0.3, -0.55, -0.39) $ - + simple_psi(R, Z, 0.8, -0.55, -0.39) $ - + simple_psi(R, Z, 0.4, 0.55, -0.4) + f = simple_psi(R, Z, 0.5D, 0.0D, -1.0D) $ + + simple_psi(R, Z, 0.3D, -0.55D, -0.39D) $ + + simple_psi(R, Z, 0.8D, -0.55D, -0.39D) $ + + simple_psi(R, Z, 0.4D, 0.55D, -0.4D) ;;;;;;;;;;;;;;;; Get input settings ;;;;;;;;;;;;;;; @@ -36,7 +36,7 @@ PRO gridgen, debug=debug, settings=settings REPEAT BEGIN psi_inner = get_float("Core normalised psi: ") - ENDREP UNTIL (psi_inner GE 0.) AND (psi_inner LT 1.0) + ENDREP UNTIL (psi_inner GE 0.D) AND (psi_inner LT 1.0D) REPEAT BEGIN psi_outer = get_float("Outer normalised psi: ") diff --git a/tools/tokamak_grids/gridgen/hypnotoad.pro b/tools/tokamak_grids/gridgen/hypnotoad.pro index 62bd4db38e..7646d077d0 100644 --- a/tools/tokamak_grids/gridgen/hypnotoad.pro +++ b/tools/tokamak_grids/gridgen/hypnotoad.pro @@ -27,12 +27,12 @@ PRO oplot_mesh, rz_mesh, flux_mesh FOR i=0, flux_mesh.critical.n_xpoint-1 DO BEGIN ; plot the separatrix contour CONTOUR, rz_mesh.psi, rz_mesh.R, rz_mesh.Z, levels=[flux_mesh.critical.xpt_f[i]], c_colors=2, /overplot - oplot, [INTERPOLATE(rz_mesh.R, flux_mesh.critical.xpt_ri[i])], [INTERPOLATE(rz_mesh.Z, flux_mesh.critical.xpt_zi[i])], psym=7, color=2 + oplot, [INTERPOLATE(rz_mesh.R, flux_mesh.critical.xpt_ri[i], /DOUBLE)], [INTERPOLATE(rz_mesh.Z, flux_mesh.critical.xpt_zi[i], /DOUBLE)], psym=7, color=2 ENDFOR ; Plot O-points FOR i=0, flux_mesh.critical.n_opoint-1 DO BEGIN - oplot, [INTERPOLATE(rz_mesh.R, flux_mesh.critical.opt_ri[i])], [INTERPOLATE(rz_mesh.Z, flux_mesh.critical.opt_zi[i])], psym=7, color=3 + oplot, [INTERPOLATE(rz_mesh.R, flux_mesh.critical.opt_ri[i], /DOUBLE)], [INTERPOLATE(rz_mesh.Z, flux_mesh.critical.opt_zi[i], /DOUBLE)], psym=7, color=3 ENDFOR ypos = 0 @@ -77,14 +77,14 @@ PRO popup_event, event ENDFOR ninpsi = N_ELEMENTS(info.in_psi_field) - psi_inner = FLTARR(ninpsi) + psi_inner = DBLARR(ninpsi) FOR i=0, ninpsi-1 DO BEGIN widget_control, info.in_psi_field[i], get_value=inp psi_inner[i] = inp ENDFOR noutpsi = N_ELEMENTS(info.out_psi_field) - psi_outer = FLTARR(noutpsi) + psi_outer = DBLARR(noutpsi) FOR i=0, noutpsi-1 DO BEGIN widget_control, info.out_psi_field[i], get_value=inp psi_outer[i] = inp @@ -380,7 +380,7 @@ PRO event_handler, event WIDGET_CONTROL, info.status, set_value="Generating mesh ..." - fpsi = FLTARR(2, N_ELEMENTS((*(info.rz_grid)).fpol)) + fpsi = DBLARR(2, N_ELEMENTS((*(info.rz_grid)).fpol)) fpsi[0,*] = (*(info.rz_grid)).simagx + (*(info.rz_grid)).npsigrid * ( (*(info.rz_grid)).sibdry - (*(info.rz_grid)).simagx ) fpsi[1,*] = (*(info.rz_grid)).fpol @@ -618,7 +618,7 @@ PRO event_handler, event critical = (*(info.rz_grid)).critical IF (*(info.rz_grid)).nlim GT 2 THEN BEGIN ; Check that the critical points are inside the boundary - bndryi = FLTARR(2, (*(info.rz_grid)).nlim) + bndryi = DBLARR(2, (*(info.rz_grid)).nlim) bndryi[0,*] = INTERPOL(FINDGEN((*(info.rz_grid)).nr), (*(info.rz_grid)).R, (*(info.rz_grid)).rlim) bndryi[1,*] = INTERPOL(FINDGEN((*(info.rz_grid)).nz), (*(info.rz_grid)).Z, (*(info.rz_grid)).zlim) critical = critical_bndry(critical, bndryi) @@ -709,13 +709,13 @@ PRO event_handler, event psi_inner = (*info.flux_mesh).psi_inner ENDIF ELSE BEGIN widget_control, info.psi_inner_field, get_value=psi_in - psi_inner = FLTARR(n_xpoint+1) + psi_in + psi_inner = DBLARR(n_xpoint+1) + psi_in ENDELSE in_psi_field[0] = CW_FIELD( in_psi_base, $ title = 'Core: ', $ uvalue = 'in_psi', $ - /float, $ + /double, $ value = psi_inner[0], $ xsize=8 $ ) @@ -723,7 +723,7 @@ PRO event_handler, event in_psi_field[i] = CW_FIELD( in_psi_base, $ title = 'PF '+STRTRIM(STRING(i),2)+': ', $ uvalue = 'in_psi', $ - /float, $ + /double, $ value = psi_inner[i], $ xsize=8 $ ) @@ -739,7 +739,7 @@ PRO event_handler, event psi_outer = (*info.flux_mesh).psi_outer ENDIF ELSE BEGIN widget_control, info.psi_outer_field, get_value=psi_out - psi_outer = FLTARR(n_xpoint) + psi_out + psi_outer = DBLARR(n_xpoint) + psi_out ENDELSE out_psi_field = LONARR(N_ELEMENTS(psi_outer)) @@ -748,7 +748,7 @@ PRO event_handler, event out_psi_field[i] = CW_FIELD( out_psi_base, $ title = 'SOL '+STRTRIM(STRING(i),2)+': ', $ uvalue = 'out_psi', $ - /float, $ + /double, $ value = psi_outer[i], $ xsize=8 $ ) @@ -808,7 +808,7 @@ PRO event_handler, event title = 'Exponent: ', $ uvalue = 'nonorthogonal_weight_decay_power', $ /double, $ - value = 2.7, $ + value = 2.7D, $ xsize = 8 $ ) @@ -1024,15 +1024,15 @@ PRO hypnotoad psi_inner_field = CW_FIELD( tab1, $ title = 'Inner psi:', $ uvalue = 'inner_psi', $ - /floating, $ - value = 0.9, $ + /double, $ + value = 0.9D, $ xsize=8 $ ) psi_outer_field = CW_FIELD( tab1, $ title = 'Outer psi:', $ uvalue = 'outer_psi', $ - /floating, $ - value = 1.1, $ + /double, $ + value = 1.1D, $ xsize=8 $ ) @@ -1040,7 +1040,7 @@ PRO hypnotoad rad_peak_field = CW_FIELD( tab1, $ title = 'Sep. spacing:', $ uvalue = 'rad_peak', $ - /floating, $ + /double, $ value = 1, $ xsize=8 $ ) @@ -1048,15 +1048,15 @@ PRO hypnotoad parweight_field = CW_FIELD( tab1, $ title = 'Par. vs pol:', $ uvalue = 'parweight', $ - /floating, $ - value = 0.0, $ + /double, $ + value = 0.0D, $ xsize=8 $ ) xpt_dist_field = CW_FIELD( tab1, $ title = 'Xpt dist x:', $ uvalue = 'xpt_mul', $ - /floating, $ + /double, $ value = 1, $ xsize=8 $ ) @@ -1228,7 +1228,7 @@ PRO hypnotoad simple_bndry:0, $ ; Use simplified boundary? xptonly_check:xptonly_check, $ ; xpt_only:0, $ ; x-point only non-orthogonal - nonorthogonal_weight_decay_power:2.7, $ ; how fast to decay towards orthogonal mesh + nonorthogonal_weight_decay_power:2.7D, $ ; how fast to decay towards orthogonal mesh radgrid_check:radgrid_check, $ single_rad_grid:1, $ smoothP_check:smoothP_check, $ diff --git a/tools/tokamak_grids/gridgen/int_y.pro b/tools/tokamak_grids/gridgen/int_y.pro index 23601f0565..566a8f7ad7 100644 --- a/tools/tokamak_grids/gridgen/int_y.pro +++ b/tools/tokamak_grids/gridgen/int_y.pro @@ -4,7 +4,7 @@ FUNCTION int_y, var, mesh, loop=loop, nosmooth=nosmooth, simple=simple s = SIZE(var, /dim) nx = s[0] - loop = FLTARR(nx) + loop = DBLARR(nx) status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN diff --git a/tools/tokamak_grids/gridgen/leg_separatrix.pro b/tools/tokamak_grids/gridgen/leg_separatrix.pro index faef3477e9..6781d6963f 100644 --- a/tools/tokamak_grids/gridgen/leg_separatrix.pro +++ b/tools/tokamak_grids/gridgen/leg_separatrix.pro @@ -30,22 +30,22 @@ FUNCTION leg_separatrix, dctF, R, Z, xpt_ri, xpt_zi, $ fyy = d[4] fxy = d[5] - xr = INTERPOLATE(r,xpt_ri) - xz = INTERPOLATE(z,xpt_zi) + xr = INTERPOLATE(r,xpt_ri, /DOUBLE) + xz = INTERPOLATE(z,xpt_zi, /DOUBLE) - drdi = INTERPOLATE(DERIV(R), xpt_ri) - dzdi = INTERPOLATE(DERIV(Z), xpt_zi) + drdi = INTERPOLATE(DERIV(R), xpt_ri, /DOUBLE) + dzdi = INTERPOLATE(DERIV(Z), xpt_zi, /DOUBLE) ; Use finite-differencing - ;di = 2. + ;di = 2.DD ;axp = local_gradient(dctF, xpt_ri + di, xpt_zi) ;axm = local_gradient(dctF, xpt_ri - di, xpt_zi) ;ayp = local_gradient(dctF, xpt_ri, xpt_zi + di) ;aym = local_gradient(dctF, xpt_ri, xpt_zi - di) - ;fxx = 0.5*(axp.dfdr - axm.dfdr)/di - ;fyy = 0.5*(ayp.dfdz - aym.dfdz)/di - ;fxy = 0.25*( (axp.dfdz - axm.dfdz) + (ayp.dfdr - aym.dfdr) ) / di + ;fxx = 0.5D*(axp.dfdr - axm.dfdr)/di + ;fyy = 0.5D*(ayp.dfdz - aym.dfdz)/di + ;fxy = 0.25D*( (axp.dfdz - axm.dfdz) + (ayp.dfdr - aym.dfdr) ) / di IF ABS(fyy) GT 1e-4 THEN BEGIN ; Get gradients 1 and 2 (solutions y = g1 * x and y = g2 * x) @@ -60,7 +60,7 @@ FUNCTION leg_separatrix, dctF, R, Z, xpt_ri, xpt_zi, $ ENDIF ELSE BEGIN ; One of the lines through the x-point is vertical (x = const) v1 = [0, 1] - v2 = [drdi, -fxx / (2.*fxy) * dzdi] + v2 = [drdi, -fxx / (2.D*fxy) * dzdi] ENDELSE ; For each line, work out which direction to go away from the @@ -83,7 +83,7 @@ FUNCTION leg_separatrix, dctF, R, Z, xpt_ri, xpt_zi, $ vp = vp / SQRT(TOTAL(vp^2)) vm = vm / SQRT(TOTAL(vm^2)) - di = 0.1 + di = 0.1D dp = TOTAL(v0*vp) dm = TOTAL(v0*vm) @@ -93,7 +93,7 @@ FUNCTION leg_separatrix, dctF, R, Z, xpt_ri, xpt_zi, $ dp = dm ENDIF ; Either both pointing along core or both along pf - IF dp GT 0. THEN BEGIN + IF dp GT 0.D THEN BEGIN ; Both along core - reverse v1 = -v1 v2 = -v2 @@ -109,9 +109,9 @@ FUNCTION leg_separatrix, dctF, R, Z, xpt_ri, xpt_zi, $ ; Need to decide which direction in theta this is - dt = theta_differential(0., [xpt_ri + di*v1[0], xpt_zi + di*v1[1]]) - sign = 1. - IF TOTAL(dt * v1) LT 0 THEN sign = -1. + dt = theta_differential(0.D, [xpt_ri + di*v1[0], xpt_zi + di*v1[1]]) + sign = 1.D + IF TOTAL(dt * v1) LT 0 THEN sign = -1.D line1 = theta_line( dctF, $ xpt_ri + di*v1[0], xpt_zi + di*v1[1], $ @@ -121,9 +121,9 @@ FUNCTION leg_separatrix, dctF, R, Z, xpt_ri, xpt_zi, $ xpt_ri - di*v1[0], xpt_zi - di*v1[1], $ sign*di, 100, psi=psi) - dt = theta_differential(0., [xpt_ri + di*v2[0], xpt_zi + di*v2[1]]) - sign = 1. - IF TOTAL(dt * v2) LT 0 THEN sign = -1. + dt = theta_differential(0.D, [xpt_ri + di*v2[0], xpt_zi + di*v2[1]]) + sign = 1.D + IF TOTAL(dt * v2) LT 0 THEN sign = -1.D line2 = theta_line( dctF, $ xpt_ri + di*v2[0], xpt_zi + di*v2[1], $ @@ -133,11 +133,11 @@ FUNCTION leg_separatrix, dctF, R, Z, xpt_ri, xpt_zi, $ xpt_ri - di*v2[0], xpt_zi - di*v2[1], $ sign*di, 100, psi=psi) - OPLOT, INTERPOLATE(R, line1[*,0]), INTERPOLATE(Z, line1[*,1]), color=3, thick=2 - OPLOT, INTERPOLATE(R, line2[*,0]), INTERPOLATE(Z, line2[*,1]), color=4, thick=2 + OPLOT, INTERPOLATE(R, line1[*,0], /DOUBLE), INTERPOLATE(Z, line1[*,1], /DOUBLE), color=3, thick=2 + OPLOT, INTERPOLATE(R, line2[*,0], /DOUBLE), INTERPOLATE(Z, line2[*,1], /DOUBLE), color=4, thick=2 - OPLOT, INTERPOLATE(R, core1[*,0]), INTERPOLATE(Z, core1[*,1]), color=3, thick=2 - OPLOT, INTERPOLATE(R, core2[*,0]), INTERPOLATE(Z, core2[*,1]), color=4, thick=2 + OPLOT, INTERPOLATE(R, core1[*,0], /DOUBLE), INTERPOLATE(Z, core1[*,1], /DOUBLE), color=3, thick=2 + OPLOT, INTERPOLATE(R, core2[*,0], /DOUBLE), INTERPOLATE(Z, core2[*,1], /DOUBLE), color=4, thick=2 RETURN, {leg1:line1, leg2:line2, core1:core1, core2:core2, ri:xpt_ri, zi:xpt_zi} END diff --git a/tools/tokamak_grids/gridgen/leg_separatrix2.pro b/tools/tokamak_grids/gridgen/leg_separatrix2.pro index 788a60c1c5..c43933a7ff 100644 --- a/tools/tokamak_grids/gridgen/leg_separatrix2.pro +++ b/tools/tokamak_grids/gridgen/leg_separatrix2.pro @@ -29,7 +29,7 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ nz = interp_data.ny IF NOT KEYWORD_SET(boundary) THEN BEGIN - bndry = FLTARR(2,4) + bndry = DBLARR(2,4) bndry[0,*] = [1, nr-2, nr-2, 1] bndry[1,*] = [1, 1, nz-2, nz-2] ENDIF ELSE bndry = boundary @@ -61,8 +61,8 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ ; Create a circle around the x-point di = 2 ; Radius of 2 grid points - IF (md GT di) AND (md LT 6) THEN di = md * 1.25 - dthe = 2.*!PI*FINDGEN(6)/6. + IF (md GT di) AND (md LT 6) THEN di = md * 1.25D + dthe = 2.D*!DPI*FINDGEN(6)/6.D ri = xpt_ri + di*COS(dthe) zi = xpt_zi + di*SIN(dthe) @@ -82,8 +82,8 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ PRINT, "Intersections: ", ncross FOR j = 0, ncross-1 DO BEGIN ; Intersection. Get location - cri = INTERPOLATE(sep_ri, inds[j]) - czi = INTERPOLATE(sep_zi, inds[j]) + cri = INTERPOLATE(sep_ri, inds[j], /DOUBLE) + czi = INTERPOLATE(sep_zi, inds[j], /DOUBLE) IF KEYWORD_SET(debug) THEN oplot, [cri], [czi], psym=2 @@ -96,14 +96,14 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ ; the X-point, so this should not affect them. ; Need to add +2 to inds[j] because we added two points onto the ; beginning of sep_ri/sep_zi. - drdi = INTERPOLATE(DERIV([sep_ri[-2:*],sep_ri,sep_ri[0:2]]), inds[j]+2) - dzdi = INTERPOLATE(DERIV([sep_zi[-2:*],sep_zi,sep_zi[0:2]]), inds[j]+2) + drdi = INTERPOLATE(DERIV([sep_ri[-2:*],sep_ri,sep_ri[0:2]]), inds[j]+2, /DOUBLE) + dzdi = INTERPOLATE(DERIV([sep_zi[-2:*],sep_zi,sep_zi[0:2]]), inds[j]+2, /DOUBLE) ; First check if this is towards or away from the X-point dir = 1 ; direction to go away from x-point d = drdi*(cri - xpt_ri) + dzdi*(czi - xpt_zi) ; Dot-product - IF d LT 0. THEN dir = -1 + IF d LT 0.D THEN dir = -1 ; Get the indices for a line radiating from the x-point si = [inds[j]] @@ -129,13 +129,13 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ si = [si, reverse(indgen(in+1))] ENDELSE ENDELSE - sepri = INTERPOLATE(sep_ri, si) - sepzi = INTERPOLATE(sep_zi, si) + sepri = INTERPOLATE(sep_ri, si, /DOUBLE) + sepzi = INTERPOLATE(sep_zi, si, /DOUBLE) ; Then check if this is towards the O-point (core) or away (PF) d = drdi*dir * (opt_ri - xpt_ri)*drpdi^2 + dzdi*dir * (opt_zi - xpt_zi) * dzpdi^2 - ;OPLOT, INTERPOLATE(R, xpt_ri) + [0., drdi*dir*drpdi * 100], INTERPOLATE(Z, xpt_zi) + [0., dzdi*dir*dzpdi * 100], color=2 + ;OPLOT, INTERPOLATE(R, xpt_ri, /DOUBLE) + [0.D, drdi*dir*drpdi * 100], INTERPOLATE(Z, xpt_zi, /DOUBLE) + [0.D, dzdi*dir*dzpdi * 100], color=2 IF d GT 0 THEN BEGIN ; Core @@ -152,8 +152,8 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ dz = DERIV(sepzi) dz = dz[1:*] * dz[0:(n-2)] - inr = MIN(WHERE(dr[1:*] LE 0.0)) + 1 - inz = MIN(WHERE(dz[1:*] LE 0.0)) + 1 + inr = MIN(WHERE(dr[1:*] LE 0.0D)) + 1 + inz = MIN(WHERE(dz[1:*] LE 0.0D)) + 1 in = MAX([inr, inz]) if in GT 0 THEN BEGIN @@ -172,8 +172,8 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ ENDIF ELSE BEGIN ; PF - sepri = INTERPOLATE(sep_ri, si) - sepzi = INTERPOLATE(sep_zi, si) + sepri = INTERPOLATE(sep_ri, si, /DOUBLE) + sepzi = INTERPOLATE(sep_zi, si, /DOUBLE) ; Find where it crosses a boundary @@ -197,8 +197,8 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ ENDELSE lastind = FLOOR(in[0]) - sepri = [sepri[0:lastind], INTERPOLATE(sepri, in[0]), sepri[lastind+1:lastgridind]] - sepzi = [sepzi[0:lastind], INTERPOLATE(sepzi, in[0]), sepzi[lastind+1:lastgridind]] + sepri = [sepri[0:lastind], INTERPOLATE(sepri, in[0], /DOUBLE), sepri[lastind+1:lastgridind]] + sepzi = [sepzi[0:lastind], INTERPOLATE(sepzi, in[0], /DOUBLE), sepzi[lastind+1:lastgridind]] ENDIF ELSE BEGIN lastind = N_ELEMENTS(sepri)-1 ENDELSE @@ -229,11 +229,11 @@ FUNCTION leg_separatrix2, interp_data, R, Z, xpt_ri, xpt_zi, $ IF KEYWORD_SET(debug) THEN BEGIN STOP ENDIF ELSE BEGIN - OPLOT, INTERPOLATE(R, pf1[0:pf1_lastind,0]), INTERPOLATE(Z, pf1[0:pf1_lastind,1]), color=3, thick=2 - OPLOT, INTERPOLATE(R, pf2[0:pf2_lastind,0]), INTERPOLATE(Z, pf2[0:pf2_lastind,1]), color=4, thick=2 + OPLOT, INTERPOLATE(R, pf1[0:pf1_lastind,0], /DOUBLE), INTERPOLATE(Z, pf1[0:pf1_lastind,1], /DOUBLE), color=3, thick=2 + OPLOT, INTERPOLATE(R, pf2[0:pf2_lastind,0], /DOUBLE), INTERPOLATE(Z, pf2[0:pf2_lastind,1], /DOUBLE), color=4, thick=2 - OPLOT, INTERPOLATE(R, core1[*,0]), INTERPOLATE(Z, core1[*,1]), color=3, thick=2 - OPLOT, INTERPOLATE(R, core2[*,0]), INTERPOLATE(Z, core2[*,1]), color=4, thick=2 + OPLOT, INTERPOLATE(R, core1[*,0], /DOUBLE), INTERPOLATE(Z, core1[*,1], /DOUBLE), color=3, thick=2 + OPLOT, INTERPOLATE(R, core2[*,0], /DOUBLE), INTERPOLATE(Z, core2[*,1], /DOUBLE), color=4, thick=2 ENDELSE RETURN, {leg1:pf1, leg1_lastind:pf1_lastind, leg2:pf2, leg2_lastind:pf2_lastind, core1:core1, core2:core2, ri:xpt_ri, zi:xpt_zi} diff --git a/tools/tokamak_grids/gridgen/line_crossings.pro b/tools/tokamak_grids/gridgen/line_crossings.pro index 236f9e7edc..7b64462824 100644 --- a/tools/tokamak_grids/gridgen/line_crossings.pro +++ b/tools/tokamak_grids/gridgen/line_crossings.pro @@ -40,36 +40,36 @@ FUNCTION line_crossings, r1, z1, period1, r2, z2, period2, ncross=ncross, $ det = a*d - b*c ; Get location along the line segments - IF ABS(det) GT 1.e-6 THEN BEGIN + IF ABS(det) GT 1.d-6 THEN BEGIN alpha = (d*dr - b*dz)/det beta = (a*dz - c*dr)/det ENDIF ELSE BEGIN - alpha = -1. - beta = -1. + alpha = -1.D + beta = -1.D ENDELSE - IF (alpha GE 0.0) AND (alpha LE 1.0) AND (beta GE 0.0) AND (beta LE 1.0) THEN BEGIN + IF (alpha GE 0.0D) AND (alpha LE 1.0D) AND (beta GE 0.0D) AND (beta LE 1.0D) THEN BEGIN ; Intersection r = r1[i] + alpha * a z = z1[i] + alpha * c IF ncross EQ 0 THEN BEGIN - result = FLTARR(2,1) + result = DBLARR(2,1) result[0,0] = r result[1,0] = z - inds1 = [FLOAT(i)+alpha] - inds2 = [FLOAT(j)+beta] + inds1 = [DOUBLE(i)+alpha] + inds2 = [DOUBLE(j)+beta] ENDIF ELSE BEGIN rold = result - result = FLTARR(2, ncross+1) + result = DBLARR(2, ncross+1) result[*,0:(ncross-1)] = rold result[0,ncross] = r result[1,ncross] = z - inds1 = [inds1, FLOAT(i)+alpha] - inds2 = [inds2, FLOAT(j)+beta] + inds1 = [inds1, DOUBLE(i)+alpha] + inds2 = [inds2, DOUBLE(j)+beta] ENDELSE ncross = ncross + 1 ENDIF diff --git a/tools/tokamak_grids/gridgen/local_gradient.pro b/tools/tokamak_grids/gridgen/local_gradient.pro index c94fa48337..027aea7f01 100644 --- a/tools/tokamak_grids/gridgen/local_gradient.pro +++ b/tools/tokamak_grids/gridgen/local_gradient.pro @@ -49,7 +49,7 @@ PRO local_gradient, interp_data, ri, zi, status=status, $ n = N_ELEMENTS(r) - A = TRANSPOSE([[FLTARR(n)+1.], $ + A = TRANSPOSE([[DBLARR(n)+1.D], $ [r], $ [z], $ [r*r], $ @@ -81,7 +81,7 @@ PRO local_gradient, interp_data, ri, zi, status=status, $ PRINT, "Calculating derivatives for local gradient (method 2)" - ddr = FLTARR(nr, nz) + ddr = DBLARR(nr, nz) ddz = ddr FOR i=0, nz-1 DO ddr[*,i] = DERIV(interp_data.f[*,i]) FOR i=0, nr-1 DO ddz[i,*] = DERIV(interp_data.f[i,*]) @@ -91,9 +91,9 @@ PRO local_gradient, interp_data, ri, zi, status=status, $ interp_data = CREATE_STRUCT(interp_data, "method2", d) ENDIF ELSE d = interp_data.method2 - IF ARG_PRESENT(f) THEN f = INTERPOLATE(interp_data.f, ri, zi, cubic=-0.5) - IF ARG_PRESENT(dfdr) THEN dfdr = INTERPOLATE(d.ddr, ri, zi, cubic=-0.5) - IF ARG_PRESENT(dfdz) THEN dfdz = INTERPOLATE(d.ddz, ri, zi, cubic=-0.5) + IF ARG_PRESENT(f) THEN f = INTERPOLATE(interp_data.f, ri, zi, cubic=-0.5D, /DOUBLE) + IF ARG_PRESENT(dfdr) THEN dfdr = INTERPOLATE(d.ddr, ri, zi, cubic=-0.5D, /DOUBLE) + IF ARG_PRESENT(dfdz) THEN dfdz = INTERPOLATE(d.ddz, ri, zi, cubic=-0.5D, /DOUBLE) END ELSE: BEGIN PRINT, "ERROR: unknown method in local_gradient" diff --git a/tools/tokamak_grids/gridgen/oplot_contour.pro b/tools/tokamak_grids/gridgen/oplot_contour.pro index 142078bb00..c0ad9ebbeb 100644 --- a/tools/tokamak_grids/gridgen/oplot_contour.pro +++ b/tools/tokamak_grids/gridgen/oplot_contour.pro @@ -6,6 +6,6 @@ PRO oplot_contour, info, xy, R, Z, periodic=periodic, _extra=_extra ri = [ri, ri[0]] zi = [zi, zi[0]] ENDIF - OPLOT, INTERPOLATE(R, ri), INTERPOLATE(Z, zi), _extra=_extra + OPLOT, INTERPOLATE(R, ri, /DOUBLE), INTERPOLATE(Z, zi, /DOUBLE), _extra=_extra END diff --git a/tools/tokamak_grids/gridgen/oplot_critical.pro b/tools/tokamak_grids/gridgen/oplot_critical.pro index 23a80ad8f9..5b43ce1d08 100644 --- a/tools/tokamak_grids/gridgen/oplot_critical.pro +++ b/tools/tokamak_grids/gridgen/oplot_critical.pro @@ -5,11 +5,11 @@ PRO oplot_critical, F, R, Z, a FOR i=0, a.n_xpoint-1 DO BEGIN ; plot the separatrix contour CONTOUR, F, R, Z, levels=[a.xpt_f[i]], c_colors=2, /overplot - oplot, [INTERPOLATE(R, a.xpt_ri[i])], [INTERPOLATE(Z, a.xpt_zi[i])], psym=7, color=2 + oplot, [INTERPOLATE(R, a.xpt_ri[i], /DOUBLE)], [INTERPOLATE(Z, a.xpt_zi[i], /DOUBLE)], psym=7, color=2 ENDFOR ; Plot O-points FOR i=0, a.n_opoint-1 DO BEGIN - oplot, [INTERPOLATE(R, a.opt_ri[i])], [INTERPOLATE(Z, a.opt_zi[i])], psym=7, color=3 + oplot, [INTERPOLATE(R, a.opt_ri[i], /DOUBLE)], [INTERPOLATE(Z, a.opt_zi[i], /DOUBLE)], psym=7, color=3 ENDFOR END diff --git a/tools/tokamak_grids/gridgen/plot_mesh.pro b/tools/tokamak_grids/gridgen/plot_mesh.pro index 4ae7265663..1da4ac65df 100644 --- a/tools/tokamak_grids/gridgen/plot_mesh.pro +++ b/tools/tokamak_grids/gridgen/plot_mesh.pro @@ -13,16 +13,16 @@ PRO plot_mesh, mesh, overplot=overplot, _extra=_extra IF over EQ 0 THEN BEGIN PLOT, mesh.Rxy[xi, yi], mesh.Zxy[xi, yi], $ xr=[MIN(mesh.Rxy), MAX(mesh.Rxy)], yr=[MIN(mesh.Zxy), MAX(mesh.Zxy)], $ - /iso, thick=0.5, _extra=_extra + /iso, thick=0.5D, _extra=_extra over = 1 ENDIF ELSE BEGIN - OPLOT, mesh.Rxy[xi, yi], mesh.Zxy[xi, yi], thick=0.5 + OPLOT, mesh.Rxy[xi, yi], mesh.Zxy[xi, yi], thick=0.5D ENDELSE ENDREP UNTIL last ; Plot radial lines FOR i=0,TOTAL(mesh.npol)-1 DO BEGIN - OPLOT, mesh.Rxy[*,i], mesh.Zxy[*,i], thick=1.5 + OPLOT, mesh.Rxy[*,i], mesh.Zxy[*,i], thick=1.5D ENDFOR END diff --git a/tools/tokamak_grids/gridgen/plot_rz_equil.pro b/tools/tokamak_grids/gridgen/plot_rz_equil.pro index dffbac8aa7..bb98ad3880 100644 --- a/tools/tokamak_grids/gridgen/plot_rz_equil.pro +++ b/tools/tokamak_grids/gridgen/plot_rz_equil.pro @@ -4,7 +4,7 @@ PRO plot_rz_equil, data, _extra=_extra nlev = 100 minf = MIN(data.psi) maxf = MAX(data.psi) - levels = findgen(nlev)*(maxf-minf)/FLOAT(nlev-1) + minf + levels = findgen(nlev)*(maxf-minf)/DOUBLE(nlev-1) + minf safe_colors, /first CONTOUR, data.psi, data.r, data.z, levels=levels, /iso, color=1, $ @@ -19,7 +19,7 @@ PRO plot_rz_equil, data, _extra=_extra thick=2,color=2 ; Check that the critical points are inside the boundary - bndryi = FLTARR(2, data.nlim) + bndryi = DBLARR(2, data.nlim) bndryi[0,*] = INTERPOL(FINDGEN(data.nr), data.R, data.rlim) bndryi[1,*] = INTERPOL(FINDGEN(data.nz), data.Z, data.zlim) diff --git a/tools/tokamak_grids/gridgen/process_grid.pro b/tools/tokamak_grids/gridgen/process_grid.pro index b9ad89e78e..634e4a3c7a 100644 --- a/tools/tokamak_grids/gridgen/process_grid.pro +++ b/tools/tokamak_grids/gridgen/process_grid.pro @@ -44,7 +44,7 @@ function calc_angle, x1, x2, x3, y1, y2, y3 P13 = sqrt((x1-x3)^2 + (y1-y3)^2) P23 = sqrt((x2-x3)^2 + (y2-y3)^2) ;calculate angle - return, acos((P12^2 + P13^2 - P23^2)/(2.*P12*P13)) + return, acos((P12^2 + P13^2 - P23^2)/(2.D*P12*P13)) end function calc_beta_withgrid, r, z, x @@ -57,33 +57,33 @@ function calc_beta_withgrid, r, z, x if (x eq 0) then begin for j=1,ny-2 do begin beta[j] = calc_angle(r[x,j],r[x+1,j],r[x,j+1],z[x,j],z[x+1,j],z[x,j+1]) - beta[j] += !PI - calc_angle(r[x,j],r[x+1,j],r[x,j-1],z[x,j],z[x+1,j],z[x,j-1]) - beta[j] /= 2.0 + beta[j] += !DPI - calc_angle(r[x,j],r[x+1,j],r[x,j-1],z[x,j],z[x+1,j],z[x,j-1]) + beta[j] /= 2.0D endfor beta[0] = calc_angle(r[x,0],r[x+1,0],r[x,1],z[x,0],z[x+1,0],z[x,1]) - beta[ny-1] = !PI - calc_angle(r[x,ny-1],r[x+1,ny-1],r[x,ny-2],z[x,ny-1],z[x+1,ny-1],z[x,ny-2]) + beta[ny-1] = !DPI - calc_angle(r[x,ny-1],r[x+1,ny-1],r[x,ny-2],z[x,ny-1],z[x+1,ny-1],z[x,ny-2]) endif else if (x eq nx-1) then begin for j=1,ny-2 do begin ; average angle across the grid point beta[j] = calc_angle(r[x,j],r[x-1,j],r[x,j-1],z[x,j],z[x-1,j],z[x,j-1]) - beta[j] += !PI - calc_angle(r[x,j],r[x-1,j],r[x,j+1],z[x,j],z[x-1,j],z[x,j+1]) - beta[j] /= 2.0 + beta[j] += !DPI - calc_angle(r[x,j],r[x-1,j],r[x,j+1],z[x,j],z[x-1,j],z[x,j+1]) + beta[j] /= 2.0D endfor - beta[0] = !PI - calc_angle(r[x,0],r[x-1,0],r[x,1],z[x,0],z[x-1,0],z[x,1]) + beta[0] = !DPI - calc_angle(r[x,0],r[x-1,0],r[x,1],z[x,0],z[x-1,0],z[x,1]) beta[ny-1] = calc_angle(r[x,ny-1],r[x-1,ny-1],r[x,ny-2],z[x,ny-1],z[x-1,ny-1],z[x,ny-2]) endif else begin for j=1,ny-2 do begin ; average angle across the grid point beta[j] = calc_angle(r[x,j],r[x-1,j],r[x,j-1],z[x,j],z[x-1,j],z[x,j-1]) beta[j] += calc_angle(r[x,j],r[x+1,j],r[x,j+1],z[x,j],z[x+1,j],z[x,j+1]) - beta[j] += !PI - calc_angle(r[x,j],r[x-1,j],r[x,j+1],z[x,j],z[x-1,j],z[x,j+1]) - beta[j] += !PI - calc_angle(r[x,j],r[x+1,j],r[x,j-1],z[x,j],z[x+1,j],z[x,j-1]) - beta[j] /= 4.0 + beta[j] += !DPI - calc_angle(r[x,j],r[x-1,j],r[x,j+1],z[x,j],z[x-1,j],z[x,j+1]) + beta[j] += !DPI - calc_angle(r[x,j],r[x+1,j],r[x,j-1],z[x,j],z[x+1,j],z[x,j-1]) + beta[j] /= 4.0D endfor - beta[0] = 0.5*calc_angle(r[x,0],r[x+1,0],r[x,1],z[x,0],z[x+1,0],z[x,1]) - beta[0] = beta[0] + 0.5*(!PI - calc_angle(r[x,0],r[x-1,0],r[x,1],z[x,0],z[x-1,0],z[x,1])) - beta[ny-1] = 0.5*calc_angle(r[x,ny-1],r[x-1,ny-1],r[x,ny-2],z[x,ny-1],z[x-1,ny-1],z[x,ny-2]) - beta[ny-1] = beta[ny-1] + 0.5*(!PI - calc_angle(r[x,ny-1],r[x+1,ny-1],r[x,ny-2],z[x,ny-1],z[x+1,ny-1],z[x,ny-2])) + beta[0] = 0.5D*calc_angle(r[x,0],r[x+1,0],r[x,1],z[x,0],z[x+1,0],z[x,1]) + beta[0] = beta[0] + 0.5D*(!DPI - calc_angle(r[x,0],r[x-1,0],r[x,1],z[x,0],z[x-1,0],z[x,1])) + beta[ny-1] = 0.5D*calc_angle(r[x,ny-1],r[x-1,ny-1],r[x,ny-2],z[x,ny-1],z[x-1,ny-1],z[x,ny-2]) + beta[ny-1] = beta[ny-1] + 0.5D*(!DPI - calc_angle(r[x,ny-1],r[x+1,ny-1],r[x,ny-2],z[x,ny-1],z[x+1,ny-1],z[x,ny-2])) endelse return, beta @@ -106,13 +106,13 @@ function calc_beta, Rxy, Zxy, mesh, rz_grid, method dZdr = DERIV(Zxy[*,j]) for i=0,nx-1 do begin local_gradient, interp_data, mesh.Rixy[i,j], mesh.Zixy[i,j], status=status, dfdr=dfdr, dfdz=dfdz - dPsidR = dfdr/INTERPOLATE(DERIV(rz_grid.r),i) - dPsidZ = dfdz/INTERPOLATE(DERIV(rz_grid.z),j) + dPsidR = dfdr/INTERPOLATE(DERIV(rz_grid.r),i, /DOUBLE) + dPsidZ = dfdz/INTERPOLATE(DERIV(rz_grid.z),j, /DOUBLE) angle1 = atan(dPsidR,dPsidZ) angle2 = atan(dZdr[i],-dRdr[i]) - beta[i,j] = angle1 - angle2 - !PI/2. + beta[i,j] = angle1 - angle2 - !DPI/2.D endfor endfor @@ -130,22 +130,22 @@ function calc_beta, Rxy, Zxy, mesh, rz_grid, method loc = where((yi GE npol[i-1]) AND (yi LT npol[i])) if(total(loc) NE -1) then begin yi_curr = yi[loc] - beta[xi,yi_curr] = !PI/2. - calc_beta_withgrid(Rxy[*,yi_curr], Zxy[*,yi_curr], xi) + beta[xi,yi_curr] = !DPI/2.D - calc_beta_withgrid(Rxy[*,yi_curr], Zxy[*,yi_curr], xi) endif endfor loc = where(yi LT npol_withguards[0]) if(total(loc) NE -1) then begin yi_curr = yi[loc] - beta[xi,yi_curr] = !PI/2. - calc_beta_withgrid(Rxy[*,yi_curr], Zxy[*,yi_curr], xi) + beta[xi,yi_curr] = !DPI/2.D - calc_beta_withgrid(Rxy[*,yi_curr], Zxy[*,yi_curr], xi) endif endif else begin - beta[xi,yi] = !PI/2. - calc_beta_withgrid(Rxy[*,yi], Zxy[*,yi], xi) + beta[xi,yi] = !DPI/2.D - calc_beta_withgrid(Rxy[*,yi], Zxy[*,yi], xi) endelse ENDREP UNTIL last beta = smooth(beta,5) ; smooth beta, it's ugly endif else begin print,"*** ERROR: UNKNOWN METHOD FOR BETA CALCULATION ***" - beta = 0.0 + beta = 0.0D endelse return, beta @@ -168,7 +168,7 @@ END FUNCTION solve_f, Rxy, psixy, pxy, Bpxy, hthe - MU = 4.e-7*!PI + MU = 4.d-7*!DPI s = SIZE(Rxy, /dim) nx = s[0] @@ -187,7 +187,7 @@ FUNCTION solve_f, Rxy, psixy, pxy, Bpxy, hthe END FUNCTION force_balance, psixy, Rxy, Bpxy, Btxy, hthe, pxy - MU =4.e-7*!PI + MU =4.d-7*!DPI a = DDX(psixy, Rxy) / Rxy b = MU*DDX(psixy, pxy) - Bpxy*DDX(psixy, Bpxy*hthe)/hthe @@ -208,7 +208,7 @@ END FUNCTION newton_Bt, psixy, Rxy, Btxy, Bpxy, pxy, hthe, mesh COMMON fnewt_com, psi, a, b - MU = 4.e-7*!PI + MU = 4.d-7*!DPI s = SIZE(Rxy, /dim) nx = s[0] @@ -217,7 +217,7 @@ FUNCTION newton_Bt, psixy, Rxy, Btxy, Bpxy, pxy, hthe, mesh axy = DDX(psixy, Rxy) / Rxy bxy = MU*DDX(psixy, pxy) - Bpxy*DDX(psixy, Bpxy*hthe)/hthe - Btxy2 = FLTARR(nx, ny) + Btxy2 = DBLARR(nx, ny) FOR i=0, ny-1 DO BEGIN psi = psixy[*,i] a = axy[*,i] @@ -239,11 +239,11 @@ function intx, Rxy, data, simple=simple nx = nx[0] result = dblarr(nx,ny) - result[*,*] = 0.0 + result[*,*] = 0.0D if keyword_set(simple) then begin for i=0, ny-1 do begin for j=1, nx-1 do begin - result[j, i] = result[j-1, i] + 0.5*(Rxy[j, i] - Rxy[j-1, i])*(data[j, i] + data[j-1, i]) + result[j, i] = result[j-1, i] + 0.5D*(Rxy[j, i] - Rxy[j-1, i])*(data[j, i] + data[j-1, i]) endfor endfor endif else begin @@ -264,11 +264,11 @@ function inty, Zxy, data, simple=simple nx = nx[0] result = dblarr(nx,ny) - result[*,*] = 0.0 + result[*,*] = 0.0D if keyword_set(simple) then begin for i=1, ny-1 do begin for j=0, nx-1 do begin - result[j, i] = result[j, i-1] + 0.5*(Zxy[j, i] - Zxy[j, i-1])*(data[j, i] + data[j, i-1]) + result[j, i] = result[j, i-1] + 0.5D*(Zxy[j, i] - Zxy[j, i-1])*(data[j, i] + data[j, i-1]) endfor endfor endif else begin @@ -288,7 +288,7 @@ FUNCTION my_int_y, var, yaxis, mesh, loop=loop, nosmooth=nosmooth, simple=simple s = SIZE(var, /dim) nx = s[0] - loop = FLTARR(nx) + loop = DBLARR(nx) loop[*] = !VALUES.F_NAN ; Prevent accidental use of unset values status = gen_surface_hypnotoad(mesh=mesh) ; Start generator @@ -362,7 +362,7 @@ function dfdx, f, x nx = nx[0] result = dblarr(nx,ny) - result[*,*] = 0.0 + result[*,*] = 0.0D for i=0, ny-1 do begin result[*,i] = DERIV(reform(x[*,i]),reform(f[*,i])); endfor @@ -410,7 +410,7 @@ PRO jxb_funct, X, profiles, force, pder ; Diagonal dependencies (dF / dfi) dFdfi = (hthe/Rxy)*DDX(psixy, Btxy) $ - + 2.*fxy*axy + + 2.D*fxy*axy ; Set the elements of pder FOR x=0, nx-1 DO BEGIN @@ -440,7 +440,7 @@ END FUNCTION fit_profiles, mesh, psixy, Rxy, hthe, Bpxy, Btxy, dpdx COMMON jxb_com, nx, ny, indxy, psi, R, h, axy - MU = 4.e-7*!PI + MU = 4.d-7*!DPI psi = psixy r = Rxy @@ -482,8 +482,8 @@ FUNCTION fit_profiles, mesh, psixy, Rxy, hthe, Bpxy, Btxy, dpdx profiles, $ function_name="jxb_funct", /noder) - Btxy2 = FLTARR(nx, ny) - dpdx2 = FLTARR(nx, ny) + Btxy2 = DBLARR(nx, ny) + dpdx2 = DBLARR(nx, ny) status = gen_surface_hypnotoad(mesh=mesh) ; Start generator i = 0 @@ -531,7 +531,7 @@ FUNCTION correct_hthe, Rxy, psixy, Btxy, Bpxy, hthe, pressure, fixhthe=fixhthe nx = s[0] ny = s[1] - MU = 4.e-7*!PI + MU = 4.d-7*!DPI IF NOT KEYWORD_SET(fixhthe) THEN fixhthe = 0 IF fixhthe LT 0 THEN fixhthe = 0 @@ -575,7 +575,7 @@ FUNCTION correct_hthe, Rxy, psixy, Btxy, Bpxy, hthe, pressure, fixhthe=fixhthe nh[(fixhthe+1):*, i] = htmp[fixhthe:*] ENDELSE - w = WHERE(nh[*,i] LT 0.0, count) + w = WHERE(nh[*,i] LT 0.0D, count) IF count GT 0 THEN BEGIN PRINT, "Error in hthe solver: Negative solution at y = ", i ;STOP @@ -595,7 +595,7 @@ FUNCTION grid_newt, data n = nx*ny dxin = REFORM(data, nx-1, ny) - dx = FLTARR(nx, ny) + dx = DBLARR(nx, ny) IF xfix LE 0 THEN BEGIN dx[1:*,*] = dxin ENDIF ELSE IF xfix GE (nx-1) THEN BEGIN @@ -608,7 +608,7 @@ FUNCTION grid_newt, data xpos = dx FOR i=0, nx-1 DO xpos[i,*] = xpos[i,*] + i - Rxy = FLTARR(nx, ny) + Rxy = DBLARR(nx, ny) Zxy = Rxy FOR y=0, ny-1 DO BEGIN @@ -623,11 +623,11 @@ FUNCTION grid_newt, data hthe = calc_hthe(Rxy, Zxy) Bpxy = calc_bp(psixy, Rxy, Zxy) - F = -1.0*calc_force(psixy, Bpxy, Btxy, hthe, Rxy, dpdpsi) + F = -1.0D*calc_force(psixy, Bpxy, Btxy, hthe, Rxy, dpdpsi) fm = MAX(ABS(F)) - IF (fm LT min_f) OR (min_f LT 0.0) THEN BEGIN + IF (fm LT min_f) OR (min_f LT 0.0D) THEN BEGIN min_f = fm PRINT, MAX(ABS(Rxy - R0)), MAX(ABS(Zxy - Z0)), MAX(ABS(F)) ENDIF @@ -675,7 +675,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ; RETURN ;ENDIF - MU = 4.e-7*!PI + MU = 4.d-7*!DPI poorquality = 0 @@ -707,7 +707,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ psixy = mesh.psixy*mesh.fnorm + mesh.faxis ; Non-normalised psi psixy_eq = (psixy - rz_grid.simagx) / (rz_grid.sibdry - rz_grid.simagx) ; Normalised using EQDSK file conventions - pressure = FLTARR(nx, ny_total) + pressure = DBLARR(nx, ny_total) ; Use splines to interpolate pressure profile status = gen_surface_hypnotoad(mesh=mesh) ; Start generator @@ -724,7 +724,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ENDREP UNTIL last ; Add a minimum amount - IF MIN(pressure) LT 1.0e-2*MAX(pressure) THEN BEGIN + IF MIN(pressure) LT 1.0d-2*MAX(pressure) THEN BEGIN PRINT, "****Minimum pressure is very small:", MIN(pressure) PRINT, "****Setting minimum pressure to 1% of maximum" pressure = pressure + 1e-2*MAX(pressure) @@ -751,8 +751,8 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ IF (xi GT 0) AND (xi LT (nx-1)) THEN BEGIN FOR j=0,N_ELEMENTS(yi)-1 DO BEGIN - p2[xi,yi[j]] = 0.5*pressure[xi,yi[j]] + $ - 0.25*(pressure[xi-1,yi[j]] + pressure[xi+1,yi[j]]) + p2[xi,yi[j]] = 0.5D*pressure[xi,yi[j]] + $ + 0.25D*(pressure[xi-1,yi[j]] + pressure[xi+1,yi[j]]) ENDFOR ENDIF @@ -765,7 +765,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ENDREP UNTIL sm EQ 0 ENDIF - IF MIN(pressure) LT 0.0 THEN BEGIN + IF MIN(pressure) LT 0.0D THEN BEGIN PRINT, "" PRINT, "============= WARNING ==============" PRINT, "Poor quality equilibrium: Pressure is negative" @@ -775,7 +775,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ dpdpsi = DDX(psixy, pressure) - ;IF MAX(dpdpsi)*mesh.fnorm GT 0.0 THEN BEGIN + ;IF MAX(dpdpsi)*mesh.fnorm GT 0.0D THEN BEGIN ; PRINT, "" ; PRINT, "============= WARNING ==============" ; PRINT, "Poor quality equilibrium: Pressure is increasing radially" @@ -784,23 +784,23 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ;ENDIF ; Grid spacing - dx = FLTARR(nx, ny_total) + dx = DBLARR(nx, ny_total) FOR y=0, ny_total-1 DO BEGIN dx[0:(nx-2),y] = psixy[1:*,y] - psixy[0:(nx-2),y] dx[nx-1,y] = dx[nx-2,y] ENDFOR ; Sign - bpsign = 1. + bpsign = 1.D xcoord = psixy - IF MIN(dx) LT 0. THEN BEGIN - bpsign = -1. + IF MIN(dx) LT 0.D THEN BEGIN + bpsign = -1.D dx = -dx ; dx always positive xcoord = -xcoord ENDIF - dtheta = 2.*!PI / FLOAT(ny) - dy = FLTARR(nx, ny_total) + dtheta + dtheta = 2.D*!DPI / DOUBLE(ny) + dy = DBLARR(nx, ny_total) + dtheta ; B field components ; Following signs mean that psi increasing outwards from @@ -816,18 +816,18 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ Bzxy[0,ymid]*(Zxy[0,ymid+1] - Zxy[0,ymid-1]) - IF dot LT 0. THEN BEGIN + IF dot LT 0.D THEN BEGIN PRINT, "**** Poloidal field is in opposite direction to Grad Theta -> Bp negative" Bpxy = -Bpxy IF bpsign GT 0 THEN STOP ; Should be negative - bpsign = -1.0 + bpsign = -1.0D ENDIF ELSE BEGIN IF bpsign LT 0 THEN STOP ; Should be positive - bpsign = 1. + bpsign = 1.D ENDELSE ; Get toroidal field from poloidal current function fpol - Btxy = FLTARR(nx, ny_total) + Btxy = DBLARR(nx, ny_total) fprime = Btxy fp = DERIV(rz_grid.npsigrid*(rz_grid.sibdry - rz_grid.simagx), rz_grid.fpol) status = gen_surface_hypnotoad(mesh=mesh) ; Start generator @@ -843,7 +843,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ENDIF ELSE BEGIN ; Outside core. Could be PF or SOL fpol = rz_grid.fpol[N_ELEMENTS(rz_grid.fpol)-1] - fprime[xi,yi] = 0. + fprime[xi,yi] = 0.D ENDELSE Btxy[xi,yi] = fpol / Rxy[xi,yi] ENDREP UNTIL last @@ -854,7 +854,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Go through the domains to get a starting estimate ; of hthe - hthe = FLTARR(nx, ny_total) + hthe = DBLARR(nx, ny_total) ; Pick a midplane index status = gen_surface_hypnotoad(mesh=mesh) ; Start generator @@ -943,7 +943,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ; Surface average dpdx2 = surface_average(dpdx, mesh) - pres = FLTARR(nx, ny_total) + pres = DBLARR(nx, ny_total) ; Integrate to get pressure FOR i=0, ny_total-1 DO BEGIN pres[*,i] = int_func(psixy[*,i], dpdx2[*,i], /simple) @@ -1025,7 +1025,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ PRINT, "Force imbalance: ", MEAN(ABS(fb0)), MAX(ABS(fb0)) PRINT, "Maximum difference in hthe: ", MAX(ABS(hthe - nh)) - PRINT, "Maximum percentage difference: ", 100.*MAX(ABS((hthe - nh)/hthe)) + PRINT, "Maximum percentage difference: ", 100.D*MAX(ABS((hthe - nh)/hthe)) !P.multi=[0,0,1,0,0] PLOT, hthe[*,0], title="Poloidal arc length at midplane. line is initial estimate", color=1 @@ -1075,7 +1075,7 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ ENDIF ; Need yxy values at all points for nonorthogonal calculations - yxy = FLTARR(nx, ny_total) + yxy = DBLARR(nx, ny_total) status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN ; Get the next domain @@ -1115,8 +1115,8 @@ PRO process_grid, rz_grid, mesh, output=output, poorquality=poorquality, $ z2 = Zxy[i,j] r3 = Rxy[i+1,j] z3 = Zxy[i+1,j] - hrad[i,j] = hrad[i-1,j] + sqrt(((r2-r1)/2. + (r3-r2)/2.)^2+((z2-z1)/2. + (z3-z2)/2.)^2) - dhrad[i,j] = sqrt(((r2-r1)/2. + (r3-r2)/2.)^2+((z2-z1)/2. + (z3-z2)/2.)^2) + hrad[i,j] = hrad[i-1,j] + sqrt(((r2-r1)/2.D + (r3-r2)/2.D)^2+((z2-z1)/2.D + (z3-z2)/2.D)^2) + dhrad[i,j] = sqrt(((r2-r1)/2.D + (r3-r2)/2.D)^2+((z2-z1)/2.D + (z3-z2)/2.D)^2) endelse endfor endfor @@ -1133,9 +1133,9 @@ retrybetacalc: yshift = intx(hrad, eta, /simple) ; b/c angle was calculated real space, integrate in real space as well (hrad instead of psixy) thetaxy = yxy + yshift - G = 1. - dfdy_seps(yshift,thetaxy,mesh) + G = 1.D - dfdy_seps(yshift,thetaxy,mesh) dyshiftdy = dfdy_seps(yshift,yxy,mesh) -; G = 1. - dfdy(yshift,thetaxy,mesh) +; G = 1.D - dfdy(yshift,thetaxy,mesh) ; dyshiftdy = dfdy(yshift,yxy,mesh) ; Calculate field-line pitch @@ -1145,7 +1145,7 @@ retrybetacalc: dqdpsi = DDX(psixy, pitch) ; Calculate zshift (qinty), sinty = d(zshift)/dpsi, and H = d(zshift)/dtheta - qinty = my_int_y(pitch*(1.+dyshiftdy), yxy, mesh, /nosmooth, loop=qloop) + qinty = my_int_y(pitch*(1.D + dyshiftdy), yxy, mesh, /nosmooth, loop=qloop) sinty = DDX(psixy,qinty) ; original calculation for H was: @@ -1154,8 +1154,8 @@ retrybetacalc: H = pitch*(1.D + dyshiftdy) ; NOTE: This is only valid in the core - pol_angle = FLTARR(nx,ny_total) - FOR i=0, nx-1 DO pol_angle[i, *] = 2.0*!PI * qinty[i,*] / qloop[i] + pol_angle = DBLARR(nx,ny_total) + FOR i=0, nx-1 DO pol_angle[i, *] = 2.0D*!DPI * qinty[i,*] / qloop[i] ;;;;;;;;;;;;;;;;;;;; THETA_ZERO ;;;;;;;;;;;;;;;;;;;;;; ; re-set zshift to be zero at the outboard midplane @@ -1193,7 +1193,7 @@ retrybetacalc: print,"******************************************************************" print,"" ; for orthogonal coordinates - I = 0. + I = 0.D ENDIF ELSE BEGIN ; for field-aligned coordinates I = sinty @@ -1201,14 +1201,14 @@ retrybetacalc: g11 = (Rxy*Bpxy)^2; g22 = G^2/hthe^2 + eta^2*g11; - g33 = I^2*g11 + H^2/hthe^2 + 1.0/Rxy^2; + g33 = I^2*g11 + H^2/hthe^2 + 1.0D/Rxy^2; g12 = -eta*g11; g13 = -I*g11; g23 = I*eta*g11 - G*H/hthe^2; J = hthe / Bpxy / G - g_11 = 1.0/g11 + (hthe*eta/G)^2 + (Rxy*H*eta/G + I*Rxy)^2; + g_11 = 1.0D/g11 + (hthe*eta/G)^2 + (Rxy*H*eta/G + I*Rxy)^2; g_22 = hthe^2/G^2 + Rxy^2*H^2/G^2; g_33 = Rxy^2; g_12 = hthe^2*eta/G^2 + Rxy^2*H/G*(H*eta/G + I); @@ -1216,8 +1216,8 @@ retrybetacalc: g_23 = H*Rxy^2/G; ; check to make sure jacobian is good - Jcheck = 1. / sqrt(g11*g22*g33 + 2.0*g12*g13*g23 - g11*g23*g23 - g22*g13*g13 - g33*g12*g12); - whr = where(abs(J-Jcheck) gt 0.01,count) + Jcheck = 1.D / sqrt(g11*g22*g33 + 2.0D*g12*g13*g23 - g11*g23*g23 - g22*g13*g13 - g33*g12*g12); + whr = where(abs(J-Jcheck) gt 0.01D,count) if(count gt 0) then begin if(beta_method EQ 0) then begin print,"" @@ -1246,8 +1246,8 @@ retrybetacalc: PRINT, "*** Calculating curvature in toroidal coordinates" - curvature, nx, ny_total, FLOAT(Rxy), FLOAT(Zxy), FLOAT(brxy), FLOAT(bzxy), FLOAT(btxy), $ - FLOAT(psixy), FLOAT(thetaxy), hthe, $ + curvature, nx, ny_total, DOUBLE(Rxy), DOUBLE(Zxy), DOUBLE(brxy), DOUBLE(bzxy), DOUBLE(btxy), $ + DOUBLE(psixy), DOUBLE(thetaxy), hthe, $ bxcv=bxcv, mesh=mesh bxcvx = bpsign*bxcv.psi @@ -1274,9 +1274,9 @@ retrybetacalc: ; DCT methods cause spurious oscillations ; Linear interpolation seems to be more robust - bxcv_psi = INTERPOLATE(bxcv.psi, mesh.Rixy, mesh.Zixy) - bxcv_theta = INTERPOLATE(bxcv.theta, mesh.Rixy, mesh.Zixy) / hthe - bxcv_phi = INTERPOLATE(bxcv.phi, mesh.Rixy, mesh.Zixy) + bxcv_psi = INTERPOLATE(bxcv.psi, mesh.Rixy, mesh.Zixy, /DOUBLE) + bxcv_theta = INTERPOLATE(bxcv.theta, mesh.Rixy, mesh.Zixy, /DOUBLE) / hthe + bxcv_phi = INTERPOLATE(bxcv.phi, mesh.Rixy, mesh.Zixy, /DOUBLE) ; If Bp is reversed, then Grad x = - Grad psi bxcvx = bpsign*bxcv_psi @@ -1285,9 +1285,9 @@ retrybetacalc: ENDIF ELSE IF curv EQ 2 THEN BEGIN ; Curvature from Curl(b/B) - bxcvx = bpsign*(Bpxy * Btxy*Rxy * DDY(1. / Bxy, mesh) / hthe) - bxcvy = -bpsign*Bxy*Bpxy * DDX(xcoord, Btxy*Rxy/Bxy^2) / (2.*hthe) - bxcvz = Bpxy^3 * DDX(xcoord, hthe/Bpxy) / (2.*hthe*Bxy) - Btxy*Rxy*DDX(xcoord, Btxy/Rxy) / (2.*Bxy) - I*bxcvx + bxcvx = bpsign*(Bpxy * Btxy*Rxy * DDY(1.D / Bxy, mesh) / hthe) + bxcvy = -bpsign*Bxy*Bpxy * DDX(xcoord, Btxy*Rxy/Bxy^2) / (2.D*hthe) + bxcvz = Bpxy^3 * DDX(xcoord, hthe/Bpxy) / (2.D*hthe*Bxy) - Btxy*Rxy*DDX(xcoord, Btxy/Rxy) / (2.D*Bxy) - I*bxcvx ENDIF ELSE BEGIN ; calculate in flux coordinates. @@ -1301,7 +1301,7 @@ retrybetacalc: ENDFOR dpb = dpb + DDX(xcoord, Bxy) - bxcvx = bpsign*(Bpxy * Btxy*Rxy * DDY(1. / Bxy, mesh) / hthe) + bxcvx = bpsign*(Bpxy * Btxy*Rxy * DDY(1.D / Bxy, mesh) / hthe) bxcvy = bpsign*(Bpxy*Btxy*Rxy*dpb / (hthe*Bxy^2)) bxcvz = -dpb - I*bxcvx ENDELSE @@ -1348,7 +1348,7 @@ retrybetacalc: ; Get the next domain yi = gen_surface_hypnotoad(period=period, last=last, xi=xi) - IF NOT period THEN jpar0[xi,yi] = 0.0 + IF NOT period THEN jpar0[xi,yi] = 0.0D ENDREP UNTIL last ; Curl(B) expression for Jpar0 (very noisy usually) @@ -1369,7 +1369,7 @@ retrybetacalc: surface, jpar0, xtitle="X", ytitle="Y", title="Jpar from F' and P'", chars=2, color=1 surface, jpar, xtitle="X", ytitle="Y", title="Jpar from curvature", chars=2, color=1 - PLOT, jpar0[0,*], tit="jpar at x=0. Solid from f' and p'", yr=[MIN([jpar0[0,*],jpar[0,*]]), $ + PLOT, jpar0[0,*], tit="jpar at x=0.D Solid from f' and p'", yr=[MIN([jpar0[0,*],jpar[0,*]]), $ MAX([jpar0[0,*],jpar[0,*]])] OPLOT, jpar[0,*], psym=1 @@ -1394,12 +1394,12 @@ retrybetacalc: j = jpar0[*,y] js = j ma = MAX(ABS(j), ip) - IF (ma LT 1.e-4) OR (ip EQ 0) THEN BEGIN + IF (ma LT 1.d-4) OR (ip EQ 0) THEN BEGIN jps[*,y] = j CONTINUE ENDIF - level = 1. + level = 1.D ;i0 = MAX(WHERE(ABS(j[0:ip]) LT level)) i1 = MIN(WHERE(ABS(j[ip:*]) LT level)) @@ -1419,7 +1419,7 @@ retrybetacalc: ; Calculate spline interpolation of inner part js[0:ip] = spline_mono(inds, j[inds], INDGEN(ip+1), $ - yp0=(j[i0] - j[i0-1]), ypn_1=0.0) + yp0=(j[i0] - j[i0-1]), ypn_1=0.0D) inds = [ip] ; peak point FOR i=ip+div, i1-div, div DO BEGIN @@ -1428,7 +1428,7 @@ retrybetacalc: inds = [inds, i1] ; Last point js[ip:i1] = spline_mono(inds, j[inds], ip+INDGEN(i1-ip+1), $ - yp0=0.0, ypn_1=(j[i1+1]-j[i1])) + yp0=0.0D, ypn_1=(j[i1+1]-j[i1])) jps[*,y] = js ENDFOR @@ -1515,14 +1515,14 @@ retrybetacalc: ; get density - Ni = pressure / (2.*Te_x* 1.602e-19*1.0e20) + Ni = pressure / (2.D*Te_x* 1.602d-19*1.0d20) PRINT, "Maximum density (10^20 m^-3):", MAX(Ni) done = get_yesno("Is this ok?") ENDREP UNTIL done EQ 1 - Te = FLTARR(nx, ny_total)+Te_x + Te = DBLARR(nx, ny_total)+Te_x Ti = Te Ni_x = MAX(Ni) Ti_x = Te_x @@ -1533,13 +1533,13 @@ retrybetacalc: ni_x = get_float("Density [10^20 m^-3]:") ; get temperature - Te = pressure / (2.*ni_x* 1.602e-19*1.0e20) + Te = pressure / (2.D*ni_x* 1.602d-19*1.0d20) PRINT, "Maximum temperature (eV):", MAX(Te) ENDREP UNTIL get_yesno("Is this ok?") EQ 1 Ti = Te - Ni = FLTARR(nx, ny_total) + ni_x + Ni = DBLARR(nx, ny_total) + ni_x Te_x = MAX(Te) Ti_x = Te_x ENDIF ELSE BEGIN @@ -1547,7 +1547,7 @@ retrybetacalc: REPEAT BEGIN te_x = get_float("Maximum temperature [eV]:") - ni_x = max(pressure) / (2.*Te_x* 1.602e-19*1.0e20) + ni_x = max(pressure) / (2.D*Te_x* 1.602d-19*1.0d20) PRINT, "Maximum density [10^20 m^-3]:", ni_x diff --git a/tools/tokamak_grids/gridgen/prof_write.pro b/tools/tokamak_grids/gridgen/prof_write.pro index 1b03176ec5..32ee193e38 100644 --- a/tools/tokamak_grids/gridgen/prof_write.pro +++ b/tools/tokamak_grids/gridgen/prof_write.pro @@ -13,16 +13,16 @@ pro prof_write, height=height, bottom=bottom, filename=filename ON_ERROR, 2 - IF NOT KEYWORD_SET(height) THEN height = 0.3 - IF NOT KEYWORD_SET(bottom) THEN bottom = 0.02 + IF NOT KEYWORD_SET(height) THEN height = 0.3D + IF NOT KEYWORD_SET(bottom) THEN bottom = 0.02D IF NOT KEYWORD_SET(filename) THEN begin print, "Please input grid file name!" endif - kb = 1.38e-23 - sep_circlie = 0.81 - density = 1e20 - ev_k = 11605. + kb = 1.38d-23 + sep_circlie = 0.81D + density = 1d20 + ev_k = 11605.D g=file_import(filename) nx = g.nx @@ -31,7 +31,7 @@ pro prof_write, height=height, bottom=bottom, filename=filename jysep1 = g.jyseps1_1 jysep2 = g.jyseps2_2 - result = fltarr(nx, ny) + result = dblarr(nx, ny) maxr = max(g.rxy[nx-1,*], kk) maxy = kk @@ -39,18 +39,18 @@ pro prof_write, height=height, bottom=bottom, filename=filename maxp = max(dp, k) center = k for i=1, nx-2 do begin - if (dp[i] lt maxp*0.75) and (dp[i+1] gt maxp*0.75) then begin + if (dp[i] lt maxp*0.75D) and (dp[i+1] gt maxp*0.75D) then begin ixsmall = i endif - if (dp[i] gt maxp*0.75) and (dp[i+1] lt maxp*0.75) then begin + if (dp[i] gt maxp*0.75D) and (dp[i+1] lt maxp*0.75D) then begin ixbig = i endif endfor width = ixbig-ixsmall - tmpt = exp(float(-center)/width) - dmpt = (tmpt - 1.0/tmpt) / (tmpt + 1.0/tmpt) - h_real = 2.*(height - bottom) / (1. - dmpt) + tmpt = exp(double(-center)/width) + dmpt = (tmpt - 1.0D/tmpt) / (tmpt + 1.0D/tmpt) + h_real = 2.D*(height - bottom) / (1.D - dmpt) ; print, ixsep, jysep1, jysep2, maxy, center, width @@ -64,35 +64,35 @@ pro prof_write, height=height, bottom=bottom, filename=filename endif ; print,mgx, xlimit, j, jysep1, jysep2 rlx = mgx - center - temp = exp(float(rlx)/width) - dampr = (temp - 1.0/temp) / (temp + 1.0/temp) - result[i,j] = 0.5*(1.0 - dampr) * h_real + bottom -; print,rlx, width, float(rlx)/width, temp, dampr + temp = exp(double(rlx)/width) + dampr = (temp - 1.0D/temp) / (temp + 1.0D/temp) + result[i,j] = 0.5D*(1.0D - dampr) * h_real + bottom +; print,rlx, width, double(rlx)/width, temp, dampr endfor endfor endif else begin ;circular geometry for i=0, nx-1 do begin - mgx = float(i) + mgx = double(i) xlimit = sep_circle * nx if (mgx gt xlimit) then begin mgx =xlimit endif rlx = mgx - center temp = exp(rlx/width) - dampr = (temp - 1.0/temp) / (temp + 1.0/temp) + dampr = (temp - 1.0D/temp) / (temp + 1.0D/temp) for j=0, ny-1 do begin - result[i,j] = 0.5*(1.0 - dampr) * h_real + bottom + result[i,j] = 0.5D*(1.0D - dampr) * h_real + bottom endfor endfor endelse profn = result*density - proft= g.pressure/(kb*profn*ev_k)/2. + proft= g.pressure/(kb*profn*ev_k)/2.D window,0 surface,result,chars=3, title="N!ii0!n (10!e20!n m!e-3!n)" window,1 - ;plot,result[*,maxy],chars=1.5 + ;plot,result[*,maxy],chars=1.5D surface,proft,chars=3, title="T!ii0!n (eV)" handle = file_open(filename, /write) diff --git a/tools/tokamak_grids/gridgen/radial_grid.pro b/tools/tokamak_grids/gridgen/radial_grid.pro index f12e69eab9..a23474f382 100644 --- a/tools/tokamak_grids/gridgen/radial_grid.pro +++ b/tools/tokamak_grids/gridgen/radial_grid.pro @@ -13,17 +13,17 @@ FUNCTION radial_grid, n, pin, pout, include_in, include_out, seps, sep_factor, $ in_dp=in_dp, out_dp=out_dp IF n EQ 1 THEN BEGIN - RETURN, [0.5*(pin+pout)] + RETURN, [0.5D*(pin+pout)] ENDIF x = FINDGEN(n) - m = FLOAT(n-1) + m = DOUBLE(n-1) IF NOT include_in THEN BEGIN - x = x + 0.5 - m = m + 0.5 + x = x + 0.5D + m = m + 0.5D ENDIF - IF NOT include_out THEN m = m + 0.5 + IF NOT include_out THEN m = m + 0.5D x = x / m IF (NOT KEYWORD_SET(in_dp)) AND (NOT KEYWORD_SET(out_dp)) THEN BEGIN @@ -36,24 +36,24 @@ FUNCTION radial_grid, n, pin, pout, include_in, include_out, seps, sep_factor, $ IF KEYWORD_SET(in_dp) AND KEYWORD_SET(out_dp) THEN BEGIN ; Fit to dist = a*i^3 + b*i^2 + c*i c = in_dp/norm - b = 3.*(1. - c) - out_dp/norm + c - a = 1. - c - b + b = 3.D*(1.D - c) - out_dp/norm + c + a = 1.D - c - b ENDIF ELSE IF KEYWORD_SET(in_dp) THEN BEGIN ; Only inner set c = in_dp/norm - a = 0.5*(c-1.) - b = 1. - c - a + a = 0.5D*(c-1.D) + b = 1.D - c - a ;a = 0 ;c = in_dp/norm - ;b = 1. - c + ;b = 1.D - c ENDIF ELSE BEGIN ; Only outer set. Used in PF region ; Fit to (1-b)*x^a + bx for fixed b df = out_dp / norm - b = 0.25 < df ; Make sure a > 0 - a = (df - b) / (1. - b) - vals = pin + (pout - pin)*( (1.-b)*x^a + b*x ) + b = 0.25D < df ; Make sure a > 0 + a = (df - b) / (1.D - b) + vals = pin + (pout - pin)*( (1.D - b)*x^a + b*x ) RETURN, vals ENDELSE diff --git a/tools/tokamak_grids/gridgen/run_test.pro b/tools/tokamak_grids/gridgen/run_test.pro index 96ae45f624..bba78c460e 100644 --- a/tools/tokamak_grids/gridgen/run_test.pro +++ b/tools/tokamak_grids/gridgen/run_test.pro @@ -4,9 +4,9 @@ g = read_neqdsk("efit/neqdsk") R = REFORM(g.r[*,0]) Z = REFORM(g.z[0,*]) -boundary=fltarr(2,4) -boundary[0,*] = [1.0, 1.0, 2.5, 2.5] -boundary[1,*] = [-1.4, 1.4, 1.4, -1.4] +boundary=DBLARR(2,4) +boundary[0,*] = [1.0D, 1.0D, 2.5D, 2.5D] +boundary[1,*] = [-1.4D, 1.4D, 1.4D, -1.4D] ;boundary = TRANSPOSE([[g.xlim], [g.ylim]]) diff --git a/tools/tokamak_grids/gridgen/rz_curvature.pro b/tools/tokamak_grids/gridgen/rz_curvature.pro index dfdd9997e5..eadbc709b6 100644 --- a/tools/tokamak_grids/gridgen/rz_curvature.pro +++ b/tools/tokamak_grids/gridgen/rz_curvature.pro @@ -22,7 +22,7 @@ FUNCTION pdiff, nr, nz, r, z, f ENDFOR ENDFOR - RETURN, {r:dfdR, z:dfdZ, phi:0.0} + RETURN, {r:dfdR, z:dfdZ, phi:0.0D} END FUNCTION pdiff_xy, nr, nz, r, z, f @@ -37,7 +37,7 @@ FUNCTION pdiff_xy, nr, nz, r, z, f dfdZ[i,*] = DERIV(z, f[i,*]) ENDFOR - RETURN, {r:dfdR, z:dfdZ, phi:0.0} + RETURN, {r:dfdR, z:dfdZ, phi:0.0D} END function curlcyl, vecR, vecV, gradVr, gradVphi, gradVz @@ -127,7 +127,7 @@ FUNCTION rz_curvature, mesh, rixy=rixy, zixy=zixy FOR i=0,nr-1 DO BEGIN FOR j=0,nz-1 DO BEGIN psinorm = (mesh.psi[i,j] - mesh.simagx) / (mesh.sibdry - mesh.simagx) - IF psinorm GT 1. THEN BEGIN + IF psinorm GT 1.D THEN BEGIN fpol = mesh.fpol[N_ELEMENTS(mesh.fpol)-1] ENDIF ELSE BEGIN ;fpol = INTERPOL(mesh.fpol, mesh.npsigrid, psinorm, /spline) @@ -153,7 +153,7 @@ FUNCTION rz_curvature, mesh, rixy=rixy, zixy=zixy Rxy = R2D ; Get grad phi - grad_Phi={r:0.0,z:0.0,phi:1./Rxy} ;-gradient of the toroidal angle + grad_Phi={r:0.0D,z:0.0D,phi:1.D/Rxy} ;-gradient of the toroidal angle ; Curl of unit b vector curlb_unit = CurlCyl(vecR, vecB_unit, grad_Br_unit, grad_Bphi_unit, grad_Bz_unit) diff --git a/tools/tokamak_grids/gridgen/smooth_nl.pro b/tools/tokamak_grids/gridgen/smooth_nl.pro index e029518524..fca53894f8 100644 --- a/tools/tokamak_grids/gridgen/smooth_nl.pro +++ b/tools/tokamak_grids/gridgen/smooth_nl.pro @@ -12,7 +12,7 @@ FUNCTION smooth_nl, input, mesh, iter=iter tmp = output - markx = FLTARR(nx, ny) + markx = DBLARR(nx, ny) marky = markx mxn = markx @@ -50,18 +50,18 @@ FUNCTION smooth_nl, input, mesh, iter=iter ;markx[x,y] = ABS - mxn[x,y] = 0.5*(ABS(dxm) + ABS(dxp)) - myn[x,y] = 0.5*(ABS(dym) + ABS(dyp)) + mxn[x,y] = 0.5D*(ABS(dxm) + ABS(dxp)) + myn[x,y] = 0.5D*(ABS(dym) + ABS(dyp)) ENDFOR ENDIF ENDREP UNTIL last - ;markx = (markx / MEAN(mxn)^2) < 1.0 - ;marky = (marky / MEAN(myn)^2) < 1.0 + ;markx = (markx / MEAN(mxn)^2) < 1.0D + ;marky = (marky / MEAN(myn)^2) < 1.0D - markx = (0.5*mxn / MEAN(mxn)) < 1.0 - marky = (0.5*myn / MEAN(myn)) < 1.0 + markx = (0.5D*mxn / MEAN(mxn)) < 1.0D + marky = (0.5D*myn / MEAN(myn)) < 1.0D status = gen_surface_hypnotoad(mesh=mesh) ; Start generator REPEAT BEGIN @@ -83,17 +83,17 @@ FUNCTION smooth_nl, input, mesh, iter=iter yp = yi[jp] ; Smooth the smoothing mask - mx = 0.1*(markx[x,y] + $ + mx = 0.1D*(markx[x,y] + $ markx[x-1,y] + markx[x+1,y] + $ markx[x,ym] + markx[x, yp]) - my = 0.1*(marky[x,y] + $ + my = 0.1D*(marky[x,y] + $ marky[x-1,y] + marky[x+1,y] + $ marky[x,ym] + marky[x, yp]) - tmp[x,y] = (1.0-mx-my)*output[x,y] $ - + mx*0.5*(output[x-1,y] + output[x+1,y]) $ - + my*0.5*(output[x,ym] + output[x,yp]) + tmp[x,y] = (1.0D - mx-my)*output[x,y] $ + + mx*0.5D*(output[x-1,y] + output[x+1,y]) $ + + my*0.5D*(output[x,ym] + output[x,yp]) ENDFOR ENDIF ENDREP UNTIL last diff --git a/tools/tokamak_grids/gridgen/sol_flux_tube.pro b/tools/tokamak_grids/gridgen/sol_flux_tube.pro index 74a166bf1b..4aad3da7cd 100644 --- a/tools/tokamak_grids/gridgen/sol_flux_tube.pro +++ b/tools/tokamak_grids/gridgen/sol_flux_tube.pro @@ -3,20 +3,20 @@ ; Inputs ; ; gfile [string] Name of the file to read -; psinorm [float, optional] Normalised psi of the flux surface +; psinorm [double, optional] Normalised psi of the flux surface ; psinorm = (psi - psi_axis)/(psi_sep - psi_axis) ; ; Keywords ; output [string] Name of the output file ; nx [int] Number of radial grid points ; ny [int] Number of points along field-line -; psiwidth [float] Radial width of the box in normalised psi +; psiwidth [double] Radial width of the box in normalised psi ; /equ [true/false] Force input file to be a .equ file. Normally ; goes on file ending. ; ; wall_file [string] File containing wall coordinates if not given in gfile ; flip_Bt [Bool] Set this to artificially reverse the sign of the toroidal field -; scaleX [float] Linearly scale the x domain. Needed for Zshift calculation +; scaleX [double] Linearly scale the x domain. Needed for Zshift calculation ; ; Features ; Uses derivatives along field line curve to calculate curvature and @@ -41,7 +41,7 @@ PRO sol_flux_tube, gfile, psinorm, output=output, nx=nx, ny=ny, psiwidth=psiwidt RETURN ENDIF ELSE IF N_PARAMS() EQ 1 THEN BEGIN ; No psinorm - psinorm = 1.05 + psinorm = 1.05D ENDIF IF NOT KEYWORD_SET(output) THEN output="fluxtube"+STR(psinorm)+".grd.nc" @@ -49,9 +49,9 @@ PRO sol_flux_tube, gfile, psinorm, output=output, nx=nx, ny=ny, psiwidth=psiwidt IF NOT KEYWORD_SET(nx) THEN nx = 132 IF NOT KEYWORD_SET(ny) THEN ny = 128 - IF NOT KEYWORD_SET(psiwidth) THEN psiwidth = 0.05 + IF NOT KEYWORD_SET(psiwidth) THEN psiwidth = 0.05D - IF psinorm LE 1.0 THEN BEGIN + IF psinorm LE 1.0D THEN BEGIN PRINT, "Error: Normalised psi must be greater than 1" RETURN ENDIF @@ -100,7 +100,7 @@ PRO sol_flux_tube, gfile, psinorm, output=output, nx=nx, ny=ny, psiwidth=psiwidt nlev = 100 minf = MIN(rzgrid.psi) maxf = MAX(rzgrid.psi) - levels = findgen(nlev)*(maxf-minf)/FLOAT(nlev-1) + minf + levels = findgen(nlev)*(maxf-minf)/DOUBLE(nlev-1) + minf safe_colors, /first @@ -180,8 +180,8 @@ PRO sol_flux_tube, gfile, psinorm, output=output, nx=nx, ny=ny, psiwidth=psiwidt ENDFOR - rpos = INTERPOLATE(rzgrid.R, ri) - zpos = INTERPOLATE(rzgrid.Z, zi) + rpos = INTERPOLATE(rzgrid.R, ri, /DOUBLE) + zpos = INTERPOLATE(rzgrid.Z, zi, /DOUBLE) ;Check that indexing is assending in poloidal angle @@ -189,19 +189,19 @@ PRO sol_flux_tube, gfile, psinorm, output=output, nx=nx, ny=ny, psiwidth=psiwidt if zpos[0] LT zpos[N_ELEMENTS(zpos)-1] THEN BEGIN ;Need to reverse indices print,"Reversing indices" - dummy = FLTARR(n_elements(ri)) + dummy = DBLARR(n_elements(ri)) for i=0,n_elements(ri)-1 do begin dummy[i] = ri[n_elements(ri)-1-i] ENDFOR ri = dummy - dummy = FLTARR(n_elements(zi)) + dummy = DBLARR(n_elements(zi)) for i=0,n_elements(zi)-1 do begin dummy[i] = zi[n_elements(zi)-1-i] ENDFOR zi = dummy - rpos = INTERPOLATE(rzgrid.R, ri) - zpos = INTERPOLATE(rzgrid.Z, zi) + rpos = INTERPOLATE(rzgrid.R, ri, /DOUBLE) + zpos = INTERPOLATE(rzgrid.Z, zi, /DOUBLE) ENDIF ; Smooth positions @@ -228,7 +228,7 @@ PRO sol_flux_tube, gfile, psinorm, output=output, nx=nx, ny=ny, psiwidth=psiwidt ENDIF ELSE BEGIN PRINT, "WARNING: No boundary found, please enter boundary indices: " Print, "Total no points: ",n_elements(rpos) - inds = FLTARR(2) + inds = DBLARR(2) inds_ok = 'N' oplot, rpos, zpos, color=4, thick=2 IF KEYWORD_SET(wall_file) THEN BEGIN ;Plot wall @@ -265,21 +265,21 @@ PRO sol_flux_tube, gfile, psinorm, output=output, nx=nx, ny=ny, psiwidth=psiwidt ;;;;;;;;;;; Toroidal field ; f = RBt and f' ngrid = n_elements(rzgrid.fpol) - psigrid = psi_axis + (psi_sep - psi_axis)*FINDGEN(ngrid)/FLOAT(ngrid) + psigrid = psi_axis + (psi_sep - psi_axis)*FINDGEN(ngrid)/DOUBLE(ngrid) - f = INTERPOLATE(rzgrid.fpol, psinorm*ngrid) + f = INTERPOLATE(rzgrid.fpol, psinorm*ngrid, /DOUBLE) ;Term not included in .equ file, needs checking - IF NOT KEYWORD_SET(equ) THEN dfdpsi = INTERPOLATE(DERIV(psigrid,rzgrid.fpol), psinorm*ngrid) + IF NOT KEYWORD_SET(equ) THEN dfdpsi = INTERPOLATE(DERIV(psigrid,rzgrid.fpol), psinorm*ngrid, /DOUBLE) ;;;;;;;;;;; Poloidal field npoints = N_ELEMENTS(ri) - Bpol = FLTARR(npoints) - drposdpsi = FLTARR(npoints) - dzdpsi = FLTARR(npoints) - dBpoldpsi = FLTARR(npoints) - dBpdz = FLTARR(npoints) - dBpdr = FLTARR(npoints) + Bpol = DBLARR(npoints) + drposdpsi = DBLARR(npoints) + dzdpsi = DBLARR(npoints) + dBpoldpsi = DBLARR(npoints) + dBpdz = DBLARR(npoints) + dBpdr = DBLARR(npoints) IF NOT KEYWORD_SET(equ) THEN dfdpsi = dfdpsi FOR i=0, npoints-1 DO BEGIN @@ -363,7 +363,7 @@ PRO sol_flux_tube, gfile, psinorm, output=output, nx=nx, ny=ny, psiwidth=psiwidt s = int_func(dsdi, /simple) ;Calculate hthe, ensuring that theta = 0,2*pi is at the divertor targets - hthe = (L[inds[1]] - L[inds[0]])/(2*!Pi) + hthe = (L[inds[1]] - L[inds[0]])/(2*!DPi) print,"hthe = ",hthe ;;;;;;;;;;;;;;;;;;;; CURVATURE ;;;;;;;;;;;;;;;;;;;;;;; @@ -388,7 +388,7 @@ PRO sol_flux_tube, gfile, psinorm, output=output, nx=nx, ny=ny, psiwidth=psiwidt ; Components of curvature in cylindrical coordinates kr = SMOOTH(d2r - rpos*dp^2,4) kz = SMOOTH(d2z,4) - kp = SMOOTH(2.*dr*dp + rpos*d2p,4) + kp = SMOOTH(2.D*dr*dp + rpos*d2p,4) ;Components of curvature in toroidal coordinates ;Not needed for calculation but useful for diagnostic purposes @@ -436,7 +436,7 @@ PRO sol_flux_tube, gfile, psinorm, output=output, nx=nx, ny=ny, psiwidth=psiwidt ;;;;;;;;;;;;;;;; RADIAL MESH ;;;;;;;;;;;;;;;;;; ; Convert normalised psi to psi - dpsi = (psiwidth * (psi_sep - psi_axis)) / FLOAT(nx-1) + dpsi = (psiwidth * (psi_sep - psi_axis)) / DOUBLE(nx-1) ;;;;;;;;;;;;;;;; INTERPOLATE ALL QUANTITIES ONTO FIELD LINE ;;;;; @@ -465,47 +465,47 @@ PRO sol_flux_tube, gfile, psinorm, output=output, nx=nx, ny=ny, psiwidth=psiwidt kphi = kp[inds[0]:inds[1]] L = int_func(dldi, /simple) - lpos = max(L) * FINDGEN(ny)/FLOAT(ny-1) + lpos = max(L) * FINDGEN(ny)/DOUBLE(ny-1) ;Interpolate onto grid equally spaced in poloidal angle inds = INTERPOL(findgen(N_ELEMENTS(L)), L, lpos) - rpos = INTERPOLATE(rpos, inds) - zpos = INTERPOLATE(zpos, inds) - s = INTERPOLATE(s,inds) - B = INTERPOLATE(B, inds) - Btor = INTERPOLATE(Btor, inds) - Bpol = INTERPOLATE(Bpol, inds) - nu = INTERPOLATE(nu, inds) - sinty = INTERPOLATE(sinty, inds) + rpos = INTERPOLATE(rpos, inds, /DOUBLE) + zpos = INTERPOLATE(zpos, inds, /DOUBLE) + s = INTERPOLATE(s,inds, /DOUBLE) + B = INTERPOLATE(B, inds, /DOUBLE) + Btor = INTERPOLATE(Btor, inds, /DOUBLE) + Bpol = INTERPOLATE(Bpol, inds, /DOUBLE) + nu = INTERPOLATE(nu, inds, /DOUBLE) + sinty = INTERPOLATE(sinty, inds, /DOUBLE) sinty = sinty - sinty[ny/2] ; take theta_0 at outboard midplane - dnudpsi = INTERPOLATE(dnudpsi, inds) - dpsidR = INTERPOLATE(dpsidR, inds) - dpsidZ = INTERPOLATE(dpsidZ,inds) - hthe = MAX(lpos)/(2*!Pi) - qinty = INTERPOLATE(qinty, inds) + dnudpsi = INTERPOLATE(dnudpsi, inds, /DOUBLE) + dpsidR = INTERPOLATE(dpsidR, inds, /DOUBLE) + dpsidZ = INTERPOLATE(dpsidZ,inds, /DOUBLE) + hthe = MAX(lpos)/(2*!DPi) + qinty = INTERPOLATE(qinty, inds, /DOUBLE) qinty = qinty - qinty[FLOOR(ny/2)] - dBdpsi = INTERPOLATE(dBdpsi,inds) - dBdR = INTERPOLATE(dBdR,inds) - dBdZ = INTERPOLATE(dBdZ,inds) + dBdpsi = INTERPOLATE(dBdpsi,inds, /DOUBLE) + dBdR = INTERPOLATE(dBdR,inds, /DOUBLE) + dBdZ = INTERPOLATE(dBdZ,inds, /DOUBLE) ;Add in missing terms in curvature - bxcvx1d = INTERPOLATE(bxcvx1d, inds) - bxcvy1d = INTERPOLATE(bxcvy1d, inds) - bxcvz1d = INTERPOLATE(bxcvz1d, inds) - (sinty*bxcvx1d + nu*bxcvy1d) + bxcvx1d = INTERPOLATE(bxcvx1d, inds, /DOUBLE) + bxcvy1d = INTERPOLATE(bxcvy1d, inds, /DOUBLE) + bxcvz1d = INTERPOLATE(bxcvz1d, inds, /DOUBLE) - (sinty*bxcvx1d + nu*bxcvy1d) - kpsi = INTERPOLATE(kpsi,inds) - ktheta = INTERPOLATE(ktheta,inds) - kphi = INTERPOLATE(kphi,inds) + kpsi = INTERPOLATE(kpsi,inds, /DOUBLE) + ktheta = INTERPOLATE(ktheta,inds, /DOUBLE) + kphi = INTERPOLATE(kphi,inds, /DOUBLE) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Put everything into 2D arrays ; B field components - Bpxy = FLTARR(nx, ny) - Btxy = FLTARR(nx, ny) - Bxy = FLTARR(nx, ny) + Bpxy = DBLARR(nx, ny) + Btxy = DBLARR(nx, ny) + Bxy = DBLARR(nx, ny) FOR i=0, nx-1 DO BEGIN Bpxy[i,*] = Bpol Btxy[i,*] = Btor @@ -513,13 +513,13 @@ PRO sol_flux_tube, gfile, psinorm, output=output, nx=nx, ny=ny, psiwidth=psiwidt ENDFOR ; Grid spacing - dx = FLTARR(nx, ny) + dpsi - dy = FLTARR(nx, ny) + 2.*!PI/FLOAT(ny) + dx = DBLARR(nx, ny) + dpsi + dy = DBLARR(nx, ny) + 2.D*!DPI/DOUBLE(ny) ; Geometrical quantities - hxy = FLTARR(nx, ny) - Rxy = FLTARR(nx, ny) - Zxy = FLTARR(nx, ny) + hxy = DBLARR(nx, ny) + Rxy = DBLARR(nx, ny) + Zxy = DBLARR(nx, ny) FOR i=0, nx-1 DO BEGIN hxy[i,*] = hthe @@ -528,7 +528,7 @@ PRO sol_flux_tube, gfile, psinorm, output=output, nx=nx, ny=ny, psiwidth=psiwidt ENDFOR ; Curvature and other quantities - bxcvx = FLTARR(nx, ny) + bxcvx = DBLARR(nx, ny) bxcvy = bxcvx bxcvz = bxcvx sinty2 = bxcvx diff --git a/tools/tokamak_grids/gridgen/test.pro b/tools/tokamak_grids/gridgen/test.pro index 1229cac996..4b74a7ef00 100644 --- a/tools/tokamak_grids/gridgen/test.pro +++ b/tools/tokamak_grids/gridgen/test.pro @@ -13,7 +13,7 @@ rz_grid = {nr:g.nx, nz:g.ny, $ ; Number of grid points qpsi:g.qpsi, $ ; q values on uniform flux grid nlim:g.nlim, rlim:g.xlim, zlim:g.ylim} ; Wall boundary -settings = {nrad:64, npol:64, psi_inner:0.8, psi_outer:1.1} +settings = {nrad:64, npol:64, psi_inner:0.8D, psi_outer:1.1D} boundary = TRANSPOSE([[rz_grid.rlim], [rz_grid.zlim]]) mesh = create_grid(rz_grid.psi, rz_grid.r, rz_grid.z, settings, boundary=boundary, /strict, /simple) diff --git a/tools/tokamak_grids/gridgen/theta_line.pro b/tools/tokamak_grids/gridgen/theta_line.pro index dc6134ab0e..5d1b8c79a8 100644 --- a/tools/tokamak_grids/gridgen/theta_line.pro +++ b/tools/tokamak_grids/gridgen/theta_line.pro @@ -12,8 +12,8 @@ FUNCTION theta_line, dctF, ri0, zi0, di0, nstep, boundary=boundary, dir=dir, psi IF KEYWORD_SET(dir) THEN BEGIN ; Set direction to go in - dt = theta_differential(0., pos) - IF TOTAL(dt*dir) LT 0. THEN di = -di + dt = theta_differential(0.D, pos) + IF TOTAL(dt*dir) LT 0.D THEN di = -di ENDIF FOR i=1, nstep DO BEGIN From 30bb0cbb4e7357e524f5aa5a658e9d96ebcc3b67 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 20 Mar 2019 21:04:04 +0000 Subject: [PATCH 1090/1783] Bump Hypnotoad version number 1.2.0 --- tools/tokamak_grids/gridgen/hypnotoad_version.pro | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/tokamak_grids/gridgen/hypnotoad_version.pro b/tools/tokamak_grids/gridgen/hypnotoad_version.pro index 8b9aaaee76..c6c38f87a4 100644 --- a/tools/tokamak_grids/gridgen/hypnotoad_version.pro +++ b/tools/tokamak_grids/gridgen/hypnotoad_version.pro @@ -41,6 +41,11 @@ FUNCTION hypnotoad_version ; harmlessly filled with zeros). ; * Option to save y-boundary guard cells (defaults to 0 for backward ; compatibility with versions of BOUT++ before 4.3). + ; 1.2.0 * Use double precision everywhere - significantly reduces numerical + ; errors which may result when for example interpolating, then + ; differentiating, then integrating. Does change the outputs a bit. + ; Less sensitive to small changes in implementation (e.g. changes + ; in indexing due to different number of y-boundary guard cells). major_version = 1 minor_version = 2 From 3049f4a8e3f3cdfb994ea6a35354728ccfac2b79 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 19 Mar 2019 22:38:57 +0000 Subject: [PATCH 1091/1783] Hypnotoad: don't smooth 'beta' Makes results more consistent with/without y-boundary guard cells. --- tools/tokamak_grids/gridgen/hypnotoad_version.pro | 3 ++- tools/tokamak_grids/gridgen/process_grid.pro | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/tokamak_grids/gridgen/hypnotoad_version.pro b/tools/tokamak_grids/gridgen/hypnotoad_version.pro index c6c38f87a4..502227aaf5 100644 --- a/tools/tokamak_grids/gridgen/hypnotoad_version.pro +++ b/tools/tokamak_grids/gridgen/hypnotoad_version.pro @@ -46,10 +46,11 @@ FUNCTION hypnotoad_version ; differentiating, then integrating. Does change the outputs a bit. ; Less sensitive to small changes in implementation (e.g. changes ; in indexing due to different number of y-boundary guard cells). + ; 1.2.1 * Don't smooth 'beta' after calculating major_version = 1 minor_version = 2 - patch_number = 0 + patch_number = 1 RETURN, LONG([major_version, minor_version, patch_number]) diff --git a/tools/tokamak_grids/gridgen/process_grid.pro b/tools/tokamak_grids/gridgen/process_grid.pro index 634e4a3c7a..e40da2b169 100644 --- a/tools/tokamak_grids/gridgen/process_grid.pro +++ b/tools/tokamak_grids/gridgen/process_grid.pro @@ -142,7 +142,7 @@ function calc_beta, Rxy, Zxy, mesh, rz_grid, method beta[xi,yi] = !DPI/2.D - calc_beta_withgrid(Rxy[*,yi], Zxy[*,yi], xi) endelse ENDREP UNTIL last - beta = smooth(beta,5) ; smooth beta, it's ugly + ;beta = smooth(beta,5) ; smooth beta, it's ugly endif else begin print,"*** ERROR: UNKNOWN METHOD FOR BETA CALCULATION ***" beta = 0.0D From f205fa4fba8a36eb895c9ed89bb4a482c3f1e6e5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 11:29:40 +0000 Subject: [PATCH 1092/1783] Add alias for SUNLinSol_SPGMR for sundials v3 for IDA --- src/solver/impls/ida/ida.cxx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index 014853ad75..8dadb94fe2 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -81,6 +81,12 @@ inline static int ida_pre_shim(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rr constexpr auto& ida_pre_shim = ida_pre; #endif +#if SUNDIALS_VERSION_MAJOR == 3 +namespace { +constexpr auto& SUNLinSol_SPGMR = SUNSPGMR; +} +#endif + IdaSolver::IdaSolver(Options *opts) : Solver(opts) { has_constraints = true; // This solver has constraints } @@ -197,7 +203,7 @@ IdaSolver::~IdaSolver() { // Call IDASpgmr to specify the IDA linear solver IDASPGMR #if SUNDIALS_VERSION_MAJOR >= 3 - if ((sun_solver = SUNSPGMR(static_cast(uvec), PREC_NONE, maxl)) == nullptr) + if ((sun_solver = SUNLinSol_SPGMR(uvec, PREC_NONE, maxl)) == nullptr) throw BoutException("ERROR: SUNSPGMR failed\n"); if (IDASpilsSetLinearSolver(idamem, sun_solver) != IDA_SUCCESS) throw BoutException("ERROR: IDASpilsSetLinearSolver failed\n"); From 30ac8f0c91e42656e53098fa2f5cda71767eb659 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 11:32:27 +0000 Subject: [PATCH 1093/1783] Make local variables const in IDA solver --- src/solver/impls/ida/ida.cxx | 59 +++++++++++++++++------------------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index 8dadb94fe2..51783882da 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -55,6 +55,8 @@ #include "unused.hxx" +#include + #define ZERO RCONST(0.) #define ONE RCONST(1.0) @@ -116,9 +118,9 @@ IdaSolver::~IdaSolver() { output.write("Initialising IDA solver\n"); // Calculate number of variables - int n2d = f2d.size(); - int n3d = f3d.size(); - int local_N = getLocalN(); + const int n2d = f2d.size(); + const int n3d = f3d.size(); + const int local_N = getLocalN(); // Get total problem size int neq; @@ -157,30 +159,23 @@ IdaSolver::~IdaSolver() { // Previous implementation was equivalent to: // int MXSUB = mesh->xend - mesh->xstart + 1; // int band_width_default = n3Dvars()*(MXSUB+2); - int band_width_default = 0; - for (auto fvar : f3d) { - Mesh* localmesh = fvar.var->getMesh(); - band_width_default += localmesh->xend - localmesh->xstart + 3; - } - - BoutReal abstol, reltol; - int maxl; - int mudq, mldq; - int mukeep, mlkeep; - bool use_precon; - bool correct_start; - - OPTION(options, mudq, band_width_default); - OPTION(options, mldq, band_width_default); - OPTION(options, mukeep, n3d); - OPTION(options, mlkeep, n3d); - options->get("ATOL", abstol, 1.0e-12); - options->get("RTOL", reltol, 1.0e-5); - OPTION(options, maxl, 6*n3d); - OPTION(options, use_precon, false); - OPTION(options, correct_start, true); - int mxsteps; // Maximum number of steps to take between outputs - options->get("mxstep", mxsteps, 500); + const int band_width_default = + std::accumulate(begin(f3d), end(f3d), 0, [](int a, const VarStr& fvar) { + Mesh* localmesh = fvar.var->getMesh(); + return a + localmesh->xend - localmesh->xstart + 3; + }); + + const auto abstol = (*options)["ATOL"].withDefault(1.0e-12); + const auto reltol = (*options)["RTOL"].withDefault(1.0e-5); + const auto maxl = (*options)["maxl"].withDefault(6 * n3d); + const auto mudq = (*options)["mudq"].withDefault(band_width_default); + const auto mldq = (*options)["mldq"].withDefault(band_width_default); + const auto mukeep = (*options)["mukeep"].withDefault(n3d); + const auto mlkeep = (*options)["mlkeep"].withDefault(n3d); + const auto use_precon = (*options)["use_precon"].withDefault(false); + const auto correct_start = (*options)["correct_start"].withDefault(true); + // Maximum number of steps to take between outputs + const auto mxsteps = (*options)["mxstep"].withDefault(500); // Call IDACreate and IDAMalloc to initialise @@ -276,7 +271,7 @@ BoutReal IdaSolver::run(BoutReal tout) { pre_Wtime = 0.0; pre_ncalls = 0; - int flag = IDASolve(idamem, tout, &simtime, uvec, duvec, IDA_NORMAL); + const int flag = IDASolve(idamem, tout, &simtime, uvec, duvec, IDA_NORMAL); // Copy variables load_vars(NV_DATA_P(uvec)); @@ -310,8 +305,8 @@ void IdaSolver::res(BoutReal t, BoutReal *udata, BoutReal *dudata, BoutReal *rda save_derivs(rdata); // If a differential equation, subtract dudata - int N = NV_LOCLENGTH_P(id); - BoutReal *idd = NV_DATA_P(id); + const int N = NV_LOCLENGTH_P(id); + const BoutReal *idd = NV_DATA_P(id); for(int i=0;i 0.5) // 1 -> differential, 0 -> algebraic rdata[i] -= dudata[i]; @@ -325,9 +320,9 @@ void IdaSolver::res(BoutReal t, BoutReal *udata, BoutReal *dudata, BoutReal *rda void IdaSolver::pre(BoutReal t, BoutReal cj, BoutReal delta, BoutReal *udata, BoutReal *rvec, BoutReal *zvec) { TRACE("Running preconditioner: IdaSolver::pre(%e)", t); - BoutReal tstart = MPI_Wtime(); + const BoutReal tstart = MPI_Wtime(); - int N = NV_LOCLENGTH_P(id); + const int N = NV_LOCLENGTH_P(id); if(!have_user_precon()) { // Identity (but should never happen) From 2ee38c2a5d916c197410e4be567000f679d6c316 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 11:47:27 +0000 Subject: [PATCH 1094/1783] Clang-format IDA solver --- src/solver/impls/ida/ida.cxx | 152 +++++++++++++++++------------------ 1 file changed, 74 insertions(+), 78 deletions(-) diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index 51783882da..24cfe86be5 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -1,6 +1,6 @@ /************************************************************************** * Interface to SUNDIALS IDA - * + * * IdaSolver for DAE systems (so can handle constraints) * * NOTE: Only one solver can currently be compiled in @@ -9,7 +9,7 @@ * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -31,10 +31,12 @@ #ifdef BOUT_HAS_IDA +#include "unused.hxx" #include +#include #include // Cell interpolation #include -#include +#include #include @@ -48,25 +50,21 @@ #include #include #include -#include #include - -#include - -#include "unused.hxx" +#include #include -#define ZERO RCONST(0.) -#define ONE RCONST(1.0) +#define ZERO RCONST(0.) +#define ONE RCONST(1.0) #ifndef IDAINT typedef int IDAINT; #endif -static int idares(BoutReal t, N_Vector u, N_Vector du, N_Vector rr, void *user_data); -static int ida_bbd_res(IDAINT Nlocal, BoutReal t, - N_Vector u, N_Vector du, N_Vector rr, void *user_data); +static int idares(BoutReal t, N_Vector u, N_Vector du, N_Vector rr, void* user_data); +static int ida_bbd_res(IDAINT Nlocal, BoutReal t, N_Vector u, N_Vector du, N_Vector rr, + void* user_data); static int ida_pre(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rr, N_Vector rvec, N_Vector zvec, BoutReal cj, BoutReal delta, void* user_data); @@ -74,8 +72,8 @@ static int ida_pre(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rr, N_Vector r #if SUNDIALS_VERSION_MAJOR < 3 // Shim for earlier versions inline static int ida_pre_shim(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rr, - N_Vector rvec, N_Vector zvec, BoutReal cj, - BoutReal delta, void* user_data, N_Vector UNUSED(tmp)) { + N_Vector rvec, N_Vector zvec, BoutReal cj, BoutReal delta, + void* user_data, N_Vector UNUSED(tmp)) { return ida_pre(t, yy, yp, rr, rvec, zvec, cj, delta, user_data); } #else @@ -89,7 +87,7 @@ constexpr auto& SUNLinSol_SPGMR = SUNSPGMR; } #endif -IdaSolver::IdaSolver(Options *opts) : Solver(opts) { +IdaSolver::IdaSolver(Options* opts) : Solver(opts) { has_constraints = true; // This solver has constraints } @@ -103,18 +101,18 @@ IdaSolver::~IdaSolver() { * Initialise **************************************************************************/ - int IdaSolver::init(int nout, BoutReal tstep) { +int IdaSolver::init(int nout, BoutReal tstep) { TRACE("Initialising IDA solver"); /// Call the generic initialisation first if (Solver::init(nout, tstep)) return 1; - + // Save nout and tstep for use in run NOUT = nout; TIMESTEP = tstep; - + output.write("Initialising IDA solver\n"); // Calculate number of variables @@ -124,13 +122,13 @@ IdaSolver::~IdaSolver() { // Get total problem size int neq; - if(MPI_Allreduce(&local_N, &neq, 1, MPI_INT, MPI_SUM, BoutComm::get())) { + if (MPI_Allreduce(&local_N, &neq, 1, MPI_INT, MPI_SUM, BoutComm::get())) { output_error.write("\tERROR: MPI_Allreduce failed!\n"); return 1; } - - output.write("\t3d fields = %d, 2d fields = %d neq=%d, local_N=%d\n", - n3d, n2d, neq, local_N); + + output.write("\t3d fields = %d, 2d fields = %d neq=%d, local_N=%d\n", n3d, n2d, neq, + local_N); // Allocate memory @@ -140,21 +138,22 @@ IdaSolver::~IdaSolver() { throw BoutException("ERROR: SUNDIALS memory allocation failed\n"); if ((id = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) throw BoutException("ERROR: SUNDIALS memory allocation failed\n"); - + // Put the variables into uvec save_vars(NV_DATA_P(uvec)); - + // Get the starting time derivative run_rhs(simtime); - + // Put the time-derivatives into duvec save_derivs(NV_DATA_P(duvec)); - + // Set the equation type in id(Differential or Algebraic. This is optional) set_id(NV_DATA_P(id)); - + /// Get options - // Compute band_width_default from actually added fields, to allow for multiple Mesh objects + // Compute band_width_default from actually added fields, to allow for multiple Mesh + // objects // // Previous implementation was equivalent to: // int MXSUB = mesh->xend - mesh->xstart + 1; @@ -181,17 +180,17 @@ IdaSolver::~IdaSolver() { if ((idamem = IDACreate()) == nullptr) throw BoutException("ERROR: IDACreate failed\n"); - - if( IDASetUserData(idamem, this) < 0 ) // For callbacks, need pointer to solver object + + if (IDASetUserData(idamem, this) < 0) // For callbacks, need pointer to solver object throw BoutException("ERROR: IDASetUserData failed\n"); - if( IDASetId(idamem, id) < 0) + if (IDASetId(idamem, id) < 0) throw BoutException("ERROR: IDASetID failed\n"); - if( IDAInit(idamem, idares, simtime, uvec, duvec) < 0 ) + if (IDAInit(idamem, idares, simtime, uvec, duvec) < 0) throw BoutException("ERROR: IDAInit failed\n"); - - if( IDASStolerances(idamem, reltol, abstol) < 0 ) + + if (IDASStolerances(idamem, reltol, abstol) < 0) throw BoutException("ERROR: IDASStolerances failed\n"); IDASetMaxNumSteps(idamem, mxsteps); @@ -207,13 +206,13 @@ IdaSolver::~IdaSolver() { throw BoutException("ERROR: IDASpgmr failed\n"); #endif - if(use_precon) { - if(!have_user_precon()) { + if (use_precon) { + if (!have_user_precon()) { output.write("\tUsing BBD preconditioner\n"); if (IDABBDPrecInit(idamem, local_N, mudq, mldq, mukeep, mlkeep, ZERO, ida_bbd_res, nullptr)) throw BoutException("ERROR: IDABBDPrecInit failed\n"); - }else { + } else { output.write("\tUsing user-supplied preconditioner\n"); if (IDASpilsSetPreconditioner(idamem, nullptr, ida_pre_shim)) throw BoutException("ERROR: IDASpilsSetPreconditioner failed\n"); @@ -221,8 +220,8 @@ IdaSolver::~IdaSolver() { } // Call IDACalcIC (with default options) to correct the initial values - if(correct_start) { - if( IDACalcIC(idamem, IDA_YA_YDP_INIT, 1e-6) ) + if (correct_start) { + if (IDACalcIC(idamem, IDA_YA_YDP_INIT, 1e-6)) throw BoutException("ERROR: IDACalcIC failed\n"); } @@ -235,25 +234,25 @@ IdaSolver::~IdaSolver() { int IdaSolver::run() { TRACE("IDA IdaSolver::run()"); - - if(!initialised) + + if (!initialised) throw BoutException("IdaSolver not initialised\n"); - for(int i=0;i 0.5) // 1 -> differential, 0 -> algebraic + const BoutReal* idd = NV_DATA_P(id); + for (int i = 0; i < N; i++) { + if (idd[i] > 0.5) // 1 -> differential, 0 -> algebraic rdata[i] -= dudata[i]; } } @@ -317,16 +315,17 @@ void IdaSolver::res(BoutReal t, BoutReal *udata, BoutReal *dudata, BoutReal *rda * Preconditioner function **************************************************************************/ -void IdaSolver::pre(BoutReal t, BoutReal cj, BoutReal delta, BoutReal *udata, BoutReal *rvec, BoutReal *zvec) { +void IdaSolver::pre(BoutReal t, BoutReal cj, BoutReal delta, BoutReal* udata, + BoutReal* rvec, BoutReal* zvec) { TRACE("Running preconditioner: IdaSolver::pre(%e)", t); const BoutReal tstart = MPI_Wtime(); const int N = NV_LOCLENGTH_P(id); - - if(!have_user_precon()) { + + if (!have_user_precon()) { // Identity (but should never happen) - for(int i=0;i(user_data); + IdaSolver* s = static_cast(user_data); // Calculate residuals s->res(t, udata, dudata, rdata); @@ -368,7 +364,7 @@ static int idares(BoutReal t, /// Residual function for BBD preconditioner static int ida_bbd_res(IDAINT UNUSED(Nlocal), BoutReal t, N_Vector u, N_Vector du, - N_Vector rr, void *user_data) { + N_Vector rr, void* user_data) { return idares(t, u, du, rr, user_data); } @@ -376,11 +372,11 @@ static int ida_bbd_res(IDAINT UNUSED(Nlocal), BoutReal t, N_Vector u, N_Vector d static int ida_pre(BoutReal t, N_Vector yy, N_Vector UNUSED(yp), N_Vector UNUSED(rr), N_Vector rvec, N_Vector zvec, BoutReal cj, BoutReal delta, void* user_data) { - BoutReal *udata = NV_DATA_P(yy); - BoutReal *rdata = NV_DATA_P(rvec); - BoutReal *zdata = NV_DATA_P(zvec); + BoutReal* udata = NV_DATA_P(yy); + BoutReal* rdata = NV_DATA_P(rvec); + BoutReal* zdata = NV_DATA_P(zvec); - IdaSolver *s = static_cast(user_data); + IdaSolver* s = static_cast(user_data); // Calculate residuals s->pre(t, cj, delta, udata, rdata, zdata); From ff433dfeefdd26a5f9e0a7bd742ed52806c399b7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 11:54:01 +0000 Subject: [PATCH 1095/1783] Tidy IDA includes/forward decls --- src/solver/impls/ida/ida.cxx | 11 ++++------- src/solver/impls/ida/ida.hxx | 14 ++++---------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index 24cfe86be5..a951923acb 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -31,12 +31,11 @@ #ifdef BOUT_HAS_IDA +#include "boutcomm.hxx" +#include "boutexception.hxx" +#include "msg_stack.hxx" +#include "output.hxx" #include "unused.hxx" -#include -#include -#include // Cell interpolation -#include -#include #include @@ -49,8 +48,6 @@ #include #include -#include -#include #include #include diff --git a/src/solver/impls/ida/ida.hxx b/src/solver/impls/ida/ida.hxx index ff9f70eeff..808c5abed0 100644 --- a/src/solver/impls/ida/ida.hxx +++ b/src/solver/impls/ida/ida.hxx @@ -32,15 +32,8 @@ #ifdef BOUT_HAS_IDA -class IdaSolver; - -#include - -#include -#include -#include -#include -#include +#include "bout/solver.hxx" +#include "bout_types.hxx" #include #if SUNDIALS_VERSION_MAJOR >= 3 @@ -49,7 +42,8 @@ class IdaSolver; #include -#include +class IdaSolver; +class Options; #include namespace { From e8d2b85a17576ca388582511aadd2cfef111d186 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 11:59:13 +0000 Subject: [PATCH 1096/1783] Use std::copy rather than loop --- src/solver/impls/ida/ida.cxx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index a951923acb..a813799ba3 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -318,12 +318,10 @@ void IdaSolver::pre(BoutReal t, BoutReal cj, BoutReal delta, BoutReal* udata, const BoutReal tstart = MPI_Wtime(); - const int N = NV_LOCLENGTH_P(id); - if (!have_user_precon()) { // Identity (but should never happen) - for (int i = 0; i < N; i++) - zvec[i] = rvec[i]; + const int N = NV_LOCLENGTH_P(id); + std::copy(rvec, rvec + N, zvec); return; } From c4bbd349f1a924787f6b2ecc66eb9b97e5dbb484 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 13:52:32 +0000 Subject: [PATCH 1097/1783] Fix some memory leaks in IDA solver Generally not a problem in real codes as the solver exists for basically the entire lifetime of the simulation --- src/solver/impls/ida/ida.cxx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index a813799ba3..3bf86230ca 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -89,9 +89,15 @@ IdaSolver::IdaSolver(Options* opts) : Solver(opts) { } IdaSolver::~IdaSolver() { + if (initialised) { + N_VDestroy_Parallel(uvec); + N_VDestroy_Parallel(duvec); + N_VDestroy_Parallel(id); + IDAFree(&idamem); #if SUNDIALS_VERSION_MAJOR >= 3 - SUNLinSolFree(sun_solver); + SUNLinSolFree(sun_solver); #endif + } } /************************************************************************** From 307a2e12fcb120efb94247c4e81b35f0ec4e5b47 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 13:53:59 +0000 Subject: [PATCH 1098/1783] Use type alias rather than typedef in SUNDIALS solvers --- src/solver/impls/arkode/arkode.cxx | 2 +- src/solver/impls/cvode/cvode.cxx | 2 +- src/solver/impls/ida/ida.cxx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index bfac9597ed..3ac52c3a1f 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -60,7 +60,7 @@ #define ONE RCONST(1.0) #ifndef ARKODEINT -typedef int ARKODEINT; +using ARKODEINT = int; #endif static int arkode_rhs_e(BoutReal t, N_Vector u, N_Vector du, void *user_data); diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index 1fa8f2fce3..69822e4a4a 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -55,7 +55,7 @@ #define ONE RCONST(1.0) #ifndef CVODEINT -typedef int CVODEINT; +using CVODEINT = int; #endif static int cvode_rhs(BoutReal t, N_Vector u, N_Vector du, void *user_data); diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index 3bf86230ca..1d897f685b 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -56,7 +56,7 @@ #define ONE RCONST(1.0) #ifndef IDAINT -typedef int IDAINT; +using IDAINT = int; #endif static int idares(BoutReal t, N_Vector u, N_Vector du, N_Vector rr, void* user_data); From d241359d45d401362fc1ce8b194f22693c88f469 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 13:58:25 +0000 Subject: [PATCH 1099/1783] Remove lots of extraneous TRACE macros from ARKode solver Make sure exception messages are clear and consistent --- src/solver/impls/arkode/arkode.cxx | 260 ++++++++++++----------------- 1 file changed, 111 insertions(+), 149 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index 3ac52c3a1f..e735ec1609 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -193,27 +193,19 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { // Get total problem size int neq; - {TRACE("Allreduce localN -> GlobalN"); - if(MPI_Allreduce(&local_N, &neq, 1, MPI_INT, MPI_SUM, BoutComm::get())) { - output_error.write("\tERROR: MPI_Allreduce failed!\n"); - return 1; - } + if (MPI_Allreduce(&local_N, &neq, 1, MPI_INT, MPI_SUM, BoutComm::get())) { + throw BoutException("Allreduce localN -> GlobalN failed!\n"); } output.write("\t3d fields = %d, 2d fields = %d neq=%d, local_N=%d\n", n3Dvars(), n2Dvars(), neq, local_N); // Allocate memory - - {TRACE("Allocating memory with N_VNew_Parallel"); - if ((uvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) - throw BoutException("ERROR: SUNDIALS memory allocation failed\n"); - } + if ((uvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) + throw BoutException("SUNDIALS memory allocation failed\n"); // Put the variables into uvec - {TRACE("Saving variables into uvec"); - save_vars(NV_DATA_P(uvec)); - } + save_vars(NV_DATA_P(uvec)); /// Get options BoutReal abstol, reltol; @@ -243,132 +235,114 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { int mxsteps; // Maximum number of steps to take between outputs int mxorder; // Maximum lmm order to be used by the solver - {TRACE("Getting options"); - options->get("mudq", mudq, band_width_default); - options->get("mldq", mldq, band_width_default); - options->get("mukeep", mukeep, n3Dvars()+n2Dvars()); - options->get("mlkeep", mlkeep, n3Dvars()+n2Dvars()); - options->get("ATOL", abstol, 1.0e-12); - options->get("RTOL", reltol, 1.0e-5); - options->get("order", order, 4); - options->get("cfl_frac", cfl_frac, -1.0); - options->get("use_vector_abstol",use_vector_abstol,false); - if (use_vector_abstol) { - Options *abstol_options = Options::getRoot(); - BoutReal tempabstol; - if ((abstolvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) - throw BoutException("ERROR: SUNDIALS memory allocation (abstol vector) failed\n"); - std::vector f2dtols; - std::vector f3dtols; - BoutReal* abstolvec_data = NV_DATA_P(abstolvec); - for (const auto& f2 : f2d) { - abstol_options = Options::getRoot()->getSection(f2.name); - abstol_options->get("abstol", tempabstol, abstol); - f2dtols.push_back(tempabstol); - } - for (const auto& f3: f3d) { - abstol_options = Options::getRoot()->getSection(f3.name); - abstol_options->get("atol", tempabstol, abstol); - f3dtols.push_back(tempabstol); - } - set_abstol_values(abstolvec_data, f2dtols, f3dtols); + options->get("mudq", mudq, band_width_default); + options->get("mldq", mldq, band_width_default); + options->get("mukeep", mukeep, n3Dvars() + n2Dvars()); + options->get("mlkeep", mlkeep, n3Dvars() + n2Dvars()); + options->get("ATOL", abstol, 1.0e-12); + options->get("RTOL", reltol, 1.0e-5); + options->get("order", order, 4); + options->get("cfl_frac", cfl_frac, -1.0); + options->get("use_vector_abstol", use_vector_abstol, false); + if (use_vector_abstol) { + Options* abstol_options = Options::getRoot(); + BoutReal tempabstol; + if ((abstolvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) + throw BoutException("SUNDIALS memory allocation (abstol vector) failed\n"); + std::vector f2dtols; + std::vector f3dtols; + BoutReal* abstolvec_data = NV_DATA_P(abstolvec); + for (const auto& f2 : f2d) { + abstol_options = Options::getRoot()->getSection(f2.name); + abstol_options->get("abstol", tempabstol, abstol); + f2dtols.push_back(tempabstol); } - - options->get("maxl", maxl, 0); - OPTION(options, use_precon, false); - OPTION(options, use_jacobian, false); - OPTION(options, max_timestep, -1.); - OPTION(options, min_timestep, -1.); - OPTION(options, start_timestep, -1); - OPTION(options, diagnose, false); - options->get("mxstep", mxsteps, 500); - options->get("mxorder", mxorder, -1); - options->get("imex", imex, true); //Use ImEx capability - options->get("explicit",expl,true);//Solve only explicit part - options->get("implicit",impl,true);//Solve only implicit part - } + for (const auto& f3 : f3d) { + abstol_options = Options::getRoot()->getSection(f3.name); + abstol_options->get("atol", tempabstol, abstol); + f3dtols.push_back(tempabstol); + } + set_abstol_values(abstolvec_data, f2dtols, f3dtols); + } + + options->get("maxl", maxl, 0); + OPTION(options, use_precon, false); + OPTION(options, use_jacobian, false); + OPTION(options, max_timestep, -1.); + OPTION(options, min_timestep, -1.); + OPTION(options, start_timestep, -1); + OPTION(options, diagnose, false); + options->get("mxstep", mxsteps, 500); + options->get("mxorder", mxorder, -1); + options->get("imex", imex, true); // Use ImEx capability + options->get("explicit", expl, true); // Solve only explicit part + options->get("implicit", impl, true); // Solve only implicit part if(imex) { //Use ImEx solver - output.write("\tUsing ARKode ImEx solver \n"); - {TRACE("Calling ARKStepCreate"); - //arkode_rhs_e holds the explicit part, arkode_rhs_i holds the implicit part - if ((arkode_mem = ARKStepCreate(arkode_rhs_e, arkode_rhs_i, simtime, uvec)) - == nullptr) - throw BoutException("ARKStepCreate failed\n"); - } + TRACE("ARKStep ImEx"); + output.write("\tUsing ARKode ImEx solver \n"); + // arkode_rhs_e holds the explicit part, arkode_rhs_i holds the implicit part + if ((arkode_mem = ARKStepCreate(arkode_rhs_e, arkode_rhs_i, simtime, uvec)) + == nullptr) + throw BoutException("ARKStepCreate failed\n"); if(expl && impl){ - TRACE("Calling ARKodeSetImEx"); - if( ARKStepSetImEx(arkode_mem) != ARK_SUCCESS ) - throw BoutException("ARKodeSetImEx failed\n"); - - } else if(expl){ - TRACE("Calling ARKodeSetExplicit"); + if (ARKStepSetImEx(arkode_mem) != ARK_SUCCESS) + throw BoutException("ARKStepSetImEx failed\n"); + } else if (expl) { if( ARKStepSetExplicit(arkode_mem) != ARK_SUCCESS ) - throw BoutException("ARKodeSetExplicit failed\n"); + throw BoutException("ARKStepSetExplicit failed\n"); } else { - TRACE("Calling ARKodeSetImplicit"); if( ARKStepSetImplicit(arkode_mem) != ARK_SUCCESS ) - throw BoutException("ARKodeSetExplicit failed\n"); + throw BoutException("ARKStepSetImplicit failed\n"); } } else { if(expl){ //Use purely explicit solver - output.write("\tUsing ARKode Explicit solver \n"); - {TRACE("Calling ARKStepCreate"); - // arkode_rhs_e holds the explicit part, arkode_rhs_i holds - // the implicit part - if ((arkode_mem = ARKStepCreate(arkode_rhs, nullptr, simtime, uvec)) == nullptr) - throw BoutException("ARKStepCreate failed\n"); - } - TRACE("Calling ARKodeSetExplicit"); - if( ARKStepSetExplicit(arkode_mem) != ARK_SUCCESS ) - throw BoutException("ARKodeSetExplicit failed\n"); + TRACE("ARKStep Explicit"); + output.write("\tUsing ARKStep Explicit solver \n"); + // arkode_rhs_e holds the explicit part, arkode_rhs_i holds + // the implicit part + if ((arkode_mem = ARKStepCreate(arkode_rhs, nullptr, simtime, uvec)) == nullptr) + throw BoutException("ARKStepCreate failed\n"); + if (ARKStepSetExplicit(arkode_mem) != ARK_SUCCESS) + throw BoutException("ARKStepSetExplicit failed\n"); } else { //Use purely implicit solver - output.write("\tUsing ARKode Implicit solver \n"); - {TRACE("Calling ARKStepCreate"); - // arkode_rhs_e holds the explicit part, arkode_rhs_i holds - // the implicit part - if ((arkode_mem = ARKStepCreate(nullptr, arkode_rhs, simtime, uvec)) == nullptr) - throw BoutException("ARKStepCreate failed\n"); - } - TRACE("Calling ARKodeSetImplicit"); - if( ARKStepSetImplicit(arkode_mem) != ARK_SUCCESS ) - throw BoutException("ARKodeSetExplicit failed\n"); + TRACE("ARKStep Implicit"); + output.write("\tUsing ARKStep Implicit solver \n"); + // arkode_rhs_e holds the explicit part, arkode_rhs_i holds + // the implicit part + if ((arkode_mem = ARKStepCreate(nullptr, arkode_rhs, simtime, uvec)) == nullptr) + throw BoutException("ARKStepCreate failed\n"); + if (ARKStepSetImplicit(arkode_mem) != ARK_SUCCESS) + throw BoutException("ARKStepSetImplicit failed\n"); } - } - - {TRACE("Calling ARKodeSetUserData"); - // For callbacks, need pointer to solver object - if (ARKStepSetUserData(arkode_mem, this) != ARK_SUCCESS) - throw BoutException("ARKodeSetUserData failed\n"); } + // For callbacks, need pointer to solver object + if (ARKStepSetUserData(arkode_mem, this) != ARK_SUCCESS) + throw BoutException("ARKStepSetUserData failed\n"); + OPTION(options,set_linear,false); if(set_linear){ //Use linear implicit solver (only evaluates jacobian inversion once - output.write("\tSetting ARKode implicit solver to Linear\n"); + output.write("\tSetting ARKStep implicit solver to Linear\n"); if( ARKStepSetLinear(arkode_mem,1) != ARK_SUCCESS ) - throw BoutException("ARKodeSetLinear failed\n"); + throw BoutException("ARKStepSetLinear failed\n"); } OPTION(options,fixed_step,false); //Solve explicit portion in fixed timestep mode //NOTE: This is not recommended except for code comparison if(fixed_step){ options->get("timestep",fixed_timestep,0.0); //If not given, default to adaptive timestepping - TRACE("Calling ARKodeSetFixedStep"); if( ARKStepSetFixedStep(arkode_mem,fixed_timestep) != ARK_SUCCESS ) - throw BoutException("ARKodeSetFixedStep failed\n"); + throw BoutException("ARKStepSetFixedStep failed\n"); } - {TRACE("Calling ARKodeSetOrder"); - if ( ARKStepSetOrder(arkode_mem, order) != ARK_SUCCESS) - throw BoutException("ARKodeSetOrder failed\n"); - } + if ( ARKStepSetOrder(arkode_mem, order) != ARK_SUCCESS) + throw BoutException("ARKStepSetOrder failed\n"); + + if( ARKStepSetCFLFraction(arkode_mem, cfl_frac) != ARK_SUCCESS) + throw BoutException("ARKStepSetCFLFraction failed\n"); - {TRACE("Calling ARKodeSetCFLFraction"); - if( ARKStepSetCFLFraction(arkode_mem, cfl_frac) != ARK_SUCCESS) - throw BoutException("ARKodeSetCFLFraction failed\n"); - } - //Set timestep adaptivity function int adap_method; OPTION(options,adap_method,0); @@ -379,46 +353,37 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { // 4 -> implicit Gustafsson // 5 -> ImEx Gustafsson - {TRACE("Calling ARKodeSetAdaptivityMethod"); - if (ARKStepSetAdaptivityMethod(arkode_mem, adap_method, 1, 1, nullptr) != ARK_SUCCESS) - throw BoutException("ARKodeSetAdaptivityMethod failed\n"); - } + if (ARKStepSetAdaptivityMethod(arkode_mem, adap_method, 1, 1, nullptr) != ARK_SUCCESS) + throw BoutException("ARKStepSetAdaptivityMethod failed\n"); if (use_vector_abstol) { - TRACE("Calling ARKodeSVtolerances"); if( ARKStepSVtolerances(arkode_mem, reltol, abstolvec) != ARK_SUCCESS ) - throw BoutException("ARKodeSVtolerances failed\n"); + throw BoutException("ARKStepSVtolerances failed\n"); } else { - TRACE("Calling ARKodeSStolerances"); if( ARKStepSStolerances(arkode_mem, reltol, abstol) != ARK_SUCCESS ) - throw BoutException("ARKodeSStolerances failed\n"); + throw BoutException("ARKStepSStolerances failed\n"); } - {TRACE("Calling ARKodeSetMaxNumSteps"); - if( ARKStepSetMaxNumSteps(arkode_mem, mxsteps) != ARK_SUCCESS ) - throw BoutException("ARKodeSetMaxNumSteps failed\n"); - } + if( ARKStepSetMaxNumSteps(arkode_mem, mxsteps) != ARK_SUCCESS ) + throw BoutException("ARKStepSetMaxNumSteps failed\n"); if(max_timestep > 0.0) { - TRACE("Calling ARKodeSetMaxStep"); if( ARKStepSetMaxStep(arkode_mem, max_timestep) != ARK_SUCCESS ) - throw BoutException("ARKodeSetMaxStep failed\n"); + throw BoutException("ARKStepSetMaxStep failed\n"); } if(min_timestep > 0.0) { - TRACE("Calling ARKodeSetMinStep"); if( ARKStepSetMinStep(arkode_mem, min_timestep) != ARK_SUCCESS ) - throw BoutException("ARKodeSetMinStep failed\n"); + throw BoutException("ARKStepSetMinStep failed\n"); } if(start_timestep > 0.0) { - TRACE("Calling ARKodeSetInitStep"); if( ARKStepSetInitStep(arkode_mem, start_timestep) != ARK_SUCCESS ) - throw BoutException("ARKodeSetInitStep failed"); + throw BoutException("ARKStepSetInitStep failed"); } - //ARKodeSetPredictorMethod(arkode_mem,4); + //ARKStepSetPredictorMethod(arkode_mem,4); /// Newton method can include Preconditioners and Jacobian function bool fixed_point; @@ -438,17 +403,16 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { if (fixed_point) { output.write("\tUsing accelerated fixed point solver\n"); if ((nonlinear_solver = SUNNonlinSol_FixedPoint(uvec, 3)) == nullptr) - throw BoutException("ARKodeSetFixedPoint failed\n"); + throw BoutException("Creating SUNDIALS fixed point nonlinear solver failed\n"); } else { output.write("\tUsing Newton iteration\n"); if ((nonlinear_solver = SUNNonlinSol_Newton(uvec)) == nullptr) - throw BoutException("ARKodeSetNewton failed\n"); + throw BoutException("Creating SUNDIALS Newton nonlinear solver failed\n"); } if (ARKStepSetNonlinearSolver(arkode_mem, nonlinear_solver) != ARK_SUCCESS) throw BoutException("ARKStepSetNonlinearSolver failed\n"); #endif /// Set Preconditioner - TRACE("Setting preconditioner"); if(use_precon) { int prectype = PREC_LEFT; @@ -459,12 +423,12 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { #if SUNDIALS_VERSION_MAJOR >= 3 if ((sun_solver = SUNLinSol_SPGMR(uvec, prectype, maxl)) == nullptr) - throw BoutException("ERROR: SUNSPGMR failed\n"); + throw BoutException("Creating SUNDIALS linear solver failed\n"); if (ARKStepSetLinearSolver(arkode_mem, sun_solver, nullptr) != ARK_SUCCESS) - throw BoutException("ERROR: ARKSpilsSetLinearSolver failed\n"); + throw BoutException("ARKStepSetLinearSolver failed\n"); #else if (ARKSpgmr(arkode_mem, prectype, maxl) != ARKSPILS_SUCCESS) - throw BoutException("ERROR: ARKSpgmr failed\n"); + throw BoutException("ARKSpgmr failed\n"); #endif if(!have_user_precon()) { @@ -472,14 +436,14 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { if (ARKBBDPrecInit(arkode_mem, local_N, mudq, mldq, mukeep, mlkeep, ZERO, arkode_bbd_rhs, nullptr) != ARK_SUCCESS) - throw BoutException("ERROR: ARKBBDPrecInit failed\n"); + throw BoutException("ARKBBDPrecInit failed\n"); } else { output.write("\tUsing user-supplied preconditioner\n"); if (ARKStepSetPreconditioner(arkode_mem, nullptr, arkode_pre_shim) != ARK_SUCCESS) - throw BoutException("ERROR: ARKSpilsSetPreconditioner failed\n"); + throw BoutException("ARKStepSetPreconditioner failed\n"); } }else { // Not using preconditioning @@ -488,12 +452,12 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { #if SUNDIALS_VERSION_MAJOR >= 3 if ((sun_solver = SUNLinSol_SPGMR(uvec, PREC_NONE, maxl)) == nullptr) - throw BoutException("ERROR: SUNSPGMR failed\n"); + throw BoutException("Creating SUNDIALS linear solver failed\n"); if (ARKStepSetLinearSolver(arkode_mem, sun_solver, nullptr) != ARK_SUCCESS) - throw BoutException("ERROR: ARKSpilsSetLinearSolver failed\n"); + throw BoutException("ARKStepSetLinearSolver failed\n"); #else if (ARKSpgmr(arkode_mem, PREC_NONE, maxl) != ARKSPILS_SUCCESS) - throw BoutException("ERROR: ARKSpgmr failed\n"); + throw BoutException("ARKSpgmr failed\n"); #endif } @@ -502,9 +466,8 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { if (use_jacobian && jacfunc) { output.write("\tUsing user-supplied Jacobian function\n"); - TRACE("Setting Jacobian-vector multiply"); if (ARKStepSetJacTimes(arkode_mem, nullptr, arkode_jac) != ARK_SUCCESS) - throw BoutException("ERROR: ARKSpilsSetJacTimesVecFn failed\n"); + throw BoutException("ARKStepSetJacTimesVecFn failed\n"); }else output.write("\tUsing difference quotient approximation for Jacobian\n"); @@ -512,11 +475,10 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { bool optimize; OPTION(options,optimize,false); if(optimize){ - TRACE("Calling ARKodeSetOptimialParams"); - output.write("\tUsing ARKode inbuilt optimization\n"); - if( ARKStepSetOptimalParams(arkode_mem) != ARK_SUCCESS ) - throw BoutException("ARKodeSetOptimalParams failed"); - } + output.write("\tUsing ARKode inbuilt optimization\n"); + if( ARKStepSetOptimalParams(arkode_mem) != ARK_SUCCESS ) + throw BoutException("ARKStepSetOptimalParams failed"); + } return 0; } @@ -716,7 +678,7 @@ void ArkodeSolver::jac(BoutReal t, BoutReal *ydata, BoutReal *vdata, BoutReal *J TRACE("Running Jacobian: ArkodeSolver::jac(%e)", t); if (jacfunc == nullptr) - throw BoutException("ERROR: No jacobian function supplied!\n"); + throw BoutException("No jacobian function supplied!\n"); // Load state from ydate load_vars(ydata); From 28aaeea7656cd740b8e0a6f053206df932e12167 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 15:17:39 +0000 Subject: [PATCH 1100/1783] Make local variables in ARKode solver const Also move to smallest scope and/or where they are actually used --- src/solver/impls/arkode/arkode.cxx | 212 ++++++++++++++--------------- 1 file changed, 104 insertions(+), 108 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index e735ec1609..3b67688675 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -56,6 +56,9 @@ #include "unused.hxx" +#include +#include + #define ZERO RCONST(0.) #define ONE RCONST(1.0) @@ -189,7 +192,7 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { output.write("Initialising SUNDIALS' ARKODE solver\n"); // Calculate number of variables (in generic_solver) - int local_N = getLocalN(); + const int local_N = getLocalN(); // Get total problem size int neq; @@ -207,76 +210,15 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { // Put the variables into uvec save_vars(NV_DATA_P(uvec)); - /// Get options - BoutReal abstol, reltol; - // Initialise abstolvec to nullptr to avoid compiler maybed-uninitialised warning - N_Vector abstolvec = nullptr; - int maxl; - int mudq, mldq; - int mukeep, mlkeep; - int order; - bool use_precon, use_jacobian, use_vector_abstol,set_linear; - BoutReal start_timestep, max_timestep, min_timestep,fixed_timestep; - bool imex,expl,impl; // Time-integration method - - // Compute band_width_default from actually added fields, to allow for multiple Mesh objects - // - // Previous implementation was equivalent to: - // int MXSUB = mesh->xend - mesh->xstart + 1; - // int band_width_default = n3Dvars()*(MXSUB+2); - int band_width_default = 0; - for (auto fvar : f3d) { - Mesh* localmesh = fvar.var->getMesh(); - band_width_default += localmesh->xend - localmesh->xstart + 3; - } - - BoutReal cfl_frac; - bool fixed_step; - int mxsteps; // Maximum number of steps to take between outputs - int mxorder; // Maximum lmm order to be used by the solver - - options->get("mudq", mudq, band_width_default); - options->get("mldq", mldq, band_width_default); - options->get("mukeep", mukeep, n3Dvars() + n2Dvars()); - options->get("mlkeep", mlkeep, n3Dvars() + n2Dvars()); - options->get("ATOL", abstol, 1.0e-12); - options->get("RTOL", reltol, 1.0e-5); - options->get("order", order, 4); - options->get("cfl_frac", cfl_frac, -1.0); - options->get("use_vector_abstol", use_vector_abstol, false); - if (use_vector_abstol) { - Options* abstol_options = Options::getRoot(); - BoutReal tempabstol; - if ((abstolvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) - throw BoutException("SUNDIALS memory allocation (abstol vector) failed\n"); - std::vector f2dtols; - std::vector f3dtols; - BoutReal* abstolvec_data = NV_DATA_P(abstolvec); - for (const auto& f2 : f2d) { - abstol_options = Options::getRoot()->getSection(f2.name); - abstol_options->get("abstol", tempabstol, abstol); - f2dtols.push_back(tempabstol); - } - for (const auto& f3 : f3d) { - abstol_options = Options::getRoot()->getSection(f3.name); - abstol_options->get("atol", tempabstol, abstol); - f3dtols.push_back(tempabstol); - } - set_abstol_values(abstolvec_data, f2dtols, f3dtols); - } - - options->get("maxl", maxl, 0); - OPTION(options, use_precon, false); - OPTION(options, use_jacobian, false); - OPTION(options, max_timestep, -1.); - OPTION(options, min_timestep, -1.); - OPTION(options, start_timestep, -1); - OPTION(options, diagnose, false); - options->get("mxstep", mxsteps, 500); - options->get("mxorder", mxorder, -1); - options->get("imex", imex, true); // Use ImEx capability - options->get("explicit", expl, true); // Solve only explicit part - options->get("implicit", impl, true); // Solve only implicit part + diagnose = (*options)["diagnose"].withDefault(false); + // Maximum number of steps to take between outputs + const auto mxsteps = (*options)["mxstep"].withDefault(500); + // Use ImEx capability + const auto imex = (*options)["imex"].withDefault(true); + // Solve only explicit part + const auto expl = (*options)["explicit"].withDefault(true); + // Solve only implicit part + const auto impl = (*options)["implicit"].withDefault(true); if(imex) { //Use ImEx solver TRACE("ARKStep ImEx"); @@ -322,62 +264,101 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { if (ARKStepSetUserData(arkode_mem, this) != ARK_SUCCESS) throw BoutException("ARKStepSetUserData failed\n"); - OPTION(options,set_linear,false); - if(set_linear){ //Use linear implicit solver (only evaluates jacobian inversion once - output.write("\tSetting ARKStep implicit solver to Linear\n"); - if( ARKStepSetLinear(arkode_mem,1) != ARK_SUCCESS ) - throw BoutException("ARKStepSetLinear failed\n"); + // Use linear implicit solver (only evaluates jacobian inversion once + const auto set_linear = (*options)["set_linear"].withDefault(false); + if (set_linear) { + output.write("\tSetting ARKStep implicit solver to Linear\n"); + if (ARKStepSetLinear(arkode_mem, 1) != ARK_SUCCESS) + throw BoutException("ARKStepSetLinear failed\n"); } - OPTION(options,fixed_step,false); //Solve explicit portion in fixed timestep mode - //NOTE: This is not recommended except for code comparison - if(fixed_step){ - options->get("timestep",fixed_timestep,0.0); //If not given, default to adaptive timestepping - if( ARKStepSetFixedStep(arkode_mem,fixed_timestep) != ARK_SUCCESS ) + // Solve explicit portion in fixed timestep mode + // NOTE: This is not recommended except for code comparison + const auto fixed_step = (*options)["fixed_step"].withDefault(false); + if (fixed_step) { + // If not given, default to adaptive timestepping + const auto fixed_timestep = (*options)["timestep"].withDefault(0.0); + if (ARKStepSetFixedStep(arkode_mem, fixed_timestep) != ARK_SUCCESS) throw BoutException("ARKStepSetFixedStep failed\n"); } - if ( ARKStepSetOrder(arkode_mem, order) != ARK_SUCCESS) + const auto order = (*options)["order"].withDefault(4); + if (ARKStepSetOrder(arkode_mem, order) != ARK_SUCCESS) throw BoutException("ARKStepSetOrder failed\n"); - if( ARKStepSetCFLFraction(arkode_mem, cfl_frac) != ARK_SUCCESS) + const auto cfl_frac = (*options)["cfl_frac"].withDefault(-1.0); + if (ARKStepSetCFLFraction(arkode_mem, cfl_frac) != ARK_SUCCESS) throw BoutException("ARKStepSetCFLFraction failed\n"); - //Set timestep adaptivity function - int adap_method; - OPTION(options,adap_method,0); + // Set timestep adaptivity function + const auto adap_method = (*options)["adap_method"].withDefault(0); // 0 -> PID adaptivity (default) - // 1 -> PI + // 1 -> PI // 2 -> I // 3 -> explicit Gustafsson // 4 -> implicit Gustafsson // 5 -> ImEx Gustafsson - + if (ARKStepSetAdaptivityMethod(arkode_mem, adap_method, 1, 1, nullptr) != ARK_SUCCESS) throw BoutException("ARKStepSetAdaptivityMethod failed\n"); + const auto abstol = (*options)["ATOL"].withDefault(1.0e-12); + const auto reltol = (*options)["RTOL"].withDefault(1.0e-5); + const auto use_vector_abstol = (*options)["use_vector_abstol"].withDefault(false); + if (use_vector_abstol) { - if( ARKStepSVtolerances(arkode_mem, reltol, abstolvec) != ARK_SUCCESS ) + std::vector f2dtols; + f2dtols.reserve(f2d.size()); + std::transform(begin(f2d), end(f2d), std::back_inserter(f2dtols), + [abstol](const VarStr& f2) { + auto f2_options = Options::root()[f2.name]; + const auto wrong_name = f2_options.isSet("abstol"); + if (wrong_name) { + output_warn << "WARNING: Option 'abstol' for field " << f2.name + << " is deprecated. Please use 'atol' instead\n"; + } + const std::string atol_name = wrong_name ? "abstol" : "atol"; + return f2_options[atol_name].withDefault(abstol); + }); + + std::vector f3dtols; + f3dtols.reserve(f3d.size()); + std::transform(begin(f3d), end(f3d), std::back_inserter(f3dtols), + [abstol](const VarStr& f3) { + return Options::root()[f3.name]["atol"].withDefault(abstol); + }); + + N_Vector abstolvec = N_VNew_Parallel(BoutComm::get(), local_N, neq); + if (abstolvec == nullptr) + throw BoutException("SUNDIALS memory allocation (abstol vector) failed\n"); + + set_abstol_values(NV_DATA_P(abstolvec), f2dtols, f3dtols); + + if (ARKStepSVtolerances(arkode_mem, reltol, abstolvec) != ARK_SUCCESS) throw BoutException("ARKStepSVtolerances failed\n"); - } - else { - if( ARKStepSStolerances(arkode_mem, reltol, abstol) != ARK_SUCCESS ) + + N_VDestroy_Parallel(abstolvec); + } else { + if (ARKStepSStolerances(arkode_mem, reltol, abstol) != ARK_SUCCESS) throw BoutException("ARKStepSStolerances failed\n"); } if( ARKStepSetMaxNumSteps(arkode_mem, mxsteps) != ARK_SUCCESS ) throw BoutException("ARKStepSetMaxNumSteps failed\n"); + const auto max_timestep = (*options)["max_timestep"].withDefault(-1.); if(max_timestep > 0.0) { if( ARKStepSetMaxStep(arkode_mem, max_timestep) != ARK_SUCCESS ) throw BoutException("ARKStepSetMaxStep failed\n"); } + const auto min_timestep = (*options)["min_timestep"].withDefault(-1.); if(min_timestep > 0.0) { if( ARKStepSetMinStep(arkode_mem, min_timestep) != ARK_SUCCESS ) throw BoutException("ARKStepSetMinStep failed\n"); } + const auto start_timestep = (*options)["start_timestep"].withDefault(-1); if(start_timestep > 0.0) { if( ARKStepSetInitStep(arkode_mem, start_timestep) != ARK_SUCCESS ) throw BoutException("ARKStepSetInitStep failed"); @@ -386,8 +367,7 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { //ARKStepSetPredictorMethod(arkode_mem,4); /// Newton method can include Preconditioners and Jacobian function - bool fixed_point; - OPTION(options,fixed_point,false); + const auto fixed_point = (*options)["fixed_point"].withDefault(false); #if SUNDIALS_VERSION_MAJOR < 4 if(fixed_point){ //Use accellerated fixed point @@ -412,14 +392,14 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { if (ARKStepSetNonlinearSolver(arkode_mem, nonlinear_solver) != ARK_SUCCESS) throw BoutException("ARKStepSetNonlinearSolver failed\n"); #endif + + const auto use_precon = (*options)["use_precon"].withDefault(false); + const auto maxl = (*options)["maxl"].withDefault(0); + /// Set Preconditioner if(use_precon) { - - int prectype = PREC_LEFT; - bool rightprec; - options->get("rightprec", rightprec, false); - if(rightprec) - prectype = PREC_RIGHT; + const auto rightprec = (*options)["rightprec"].withDefault(false); + const int prectype = rightprec ? PREC_RIGHT : PREC_LEFT; #if SUNDIALS_VERSION_MAJOR >= 3 if ((sun_solver = SUNLinSol_SPGMR(uvec, prectype, maxl)) == nullptr) @@ -434,6 +414,24 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { if(!have_user_precon()) { output.write("\tUsing BBD preconditioner\n"); + /// Get options + // Compute band_width_default from actually added fields, to allow for multiple + // Mesh objects + // + // Previous implementation was equivalent to: + // int MXSUB = mesh->xend - mesh->xstart + 1; + // int band_width_default = n3Dvars()*(MXSUB+2); + const int band_width_default = std::accumulate( + begin(f3d), end(f3d), 0, [](int a, const VarStr& fvar) { + Mesh* localmesh = fvar.var->getMesh(); + return a + localmesh->xend - localmesh->xstart + 3; + }); + + const auto mudq = (*options)["mudq"].withDefault(band_width_default); + const auto mldq = (*options)["mldq"].withDefault(band_width_default); + const auto mukeep = (*options)["mukeep"].withDefault(n3Dvars() + n2Dvars()); + const auto mlkeep = (*options)["mlkeep"].withDefault(n3Dvars() + n2Dvars()); + if (ARKBBDPrecInit(arkode_mem, local_N, mudq, mldq, mukeep, mlkeep, ZERO, arkode_bbd_rhs, nullptr) != ARK_SUCCESS) throw BoutException("ARKBBDPrecInit failed\n"); @@ -463,6 +461,7 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { /// Set Jacobian-vector multiplication function + const auto use_jacobian = (*options)["use_jacobian"].withDefault(false); if (use_jacobian && jacfunc) { output.write("\tUsing user-supplied Jacobian function\n"); @@ -472,8 +471,7 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { output.write("\tUsing difference quotient approximation for Jacobian\n"); //Use ARKode optimal parameters - bool optimize; - OPTION(options,optimize,false); + const auto optimize = (*options)["optimize"].withDefault(false); if(optimize){ output.write("\tUsing ARKode inbuilt optimization\n"); if( ARKStepSetOptimalParams(arkode_mem) != ARK_SUCCESS ) @@ -557,7 +555,7 @@ BoutReal ArkodeSolver::run(BoutReal tout) { ARKStepGetCurrentTime(arkode_mem, &internal_time); while(internal_time < tout) { // Run another step - BoutReal last_time = internal_time; + const BoutReal last_time = internal_time; flag = ARKStepEvolve(arkode_mem, tout, uvec, &internal_time, ARK_ONE_STEP); if(flag != ARK_SUCCESS) { @@ -644,14 +642,12 @@ void ArkodeSolver::rhs(BoutReal t, BoutReal *udata, BoutReal *dudata) { void ArkodeSolver::pre(BoutReal t, BoutReal gamma, BoutReal delta, BoutReal *udata, BoutReal *rvec, BoutReal *zvec) { TRACE("Running preconditioner: ArkodeSolver::pre(%e)", t); - BoutReal tstart = MPI_Wtime(); + const BoutReal tstart = MPI_Wtime(); - int N = NV_LOCLENGTH_P(uvec); - if(!have_user_precon()) { // Identity (but should never happen) - for(int i=0;i Date: Thu, 21 Mar 2019 15:20:55 +0000 Subject: [PATCH 1101/1783] Clang-format ARKode solver --- src/solver/impls/arkode/arkode.cxx | 397 ++++++++++++++--------------- 1 file changed, 192 insertions(+), 205 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index 3b67688675..8d5c26260b 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -1,13 +1,13 @@ /************************************************************************** * Experimental interface to SUNDIALS ARKode IMEX solver * - * NOTE: ARKode is still in beta testing so use with cautious optimism + * NOTE: ARKode is still in beta testing so use with cautious optimism * ************************************************************************** * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Nick Walkden, nick.walkden@ccfe.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -30,8 +30,8 @@ #ifdef BOUT_HAS_ARKODE #include -#include // Cell interpolation #include +#include // Cell interpolation #include #if SUNDIALS_VERSION_MAJOR >= 4 @@ -49,8 +49,8 @@ #include #include -#include #include +#include #include @@ -59,26 +59,26 @@ #include #include -#define ZERO RCONST(0.) -#define ONE RCONST(1.0) +#define ZERO RCONST(0.) +#define ONE RCONST(1.0) #ifndef ARKODEINT using ARKODEINT = int; #endif -static int arkode_rhs_e(BoutReal t, N_Vector u, N_Vector du, void *user_data); -static int arkode_rhs_i(BoutReal t, N_Vector u, N_Vector du, void *user_data); -static int arkode_rhs(BoutReal t, N_Vector u, N_Vector du, void *user_data); +static int arkode_rhs_e(BoutReal t, N_Vector u, N_Vector du, void* user_data); +static int arkode_rhs_i(BoutReal t, N_Vector u, N_Vector du, void* user_data); +static int arkode_rhs(BoutReal t, N_Vector u, N_Vector du, void* user_data); -static int arkode_bbd_rhs(ARKODEINT Nlocal, BoutReal t, N_Vector u, N_Vector du, - void *user_data); +static int arkode_bbd_rhs(ARKODEINT Nlocal, BoutReal t, N_Vector u, N_Vector du, + void* user_data); static int arkode_pre(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rvec, N_Vector zvec, BoutReal gamma, BoutReal delta, int lr, void* user_data); #if SUNDIALS_VERSION_MAJOR < 3 // Shim for earlier versions inline static int arkode_pre_shim(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rvec, - N_Vector zvec, BoutReal gamma, BoutReal delta, int lr, - void* user_data, N_Vector UNUSED(tmp)) { + N_Vector zvec, BoutReal gamma, BoutReal delta, int lr, + void* user_data, N_Vector UNUSED(tmp)) { return arkode_pre(t, yy, yp, rvec, zvec, gamma, delta, lr, user_data); } #else @@ -86,10 +86,8 @@ inline static int arkode_pre_shim(BoutReal t, N_Vector yy, N_Vector yp, N_Vector constexpr auto& arkode_pre_shim = arkode_pre; #endif - -static int arkode_jac(N_Vector v, N_Vector Jv, - realtype t, N_Vector y, N_Vector fy, - void *user_data, N_Vector tmp); +static int arkode_jac(N_Vector v, N_Vector Jv, realtype t, N_Vector y, N_Vector fy, + void* user_data, N_Vector tmp); #if SUNDIALS_VERSION_MAJOR < 4 // Shim for earlier versions inline int ARKStepSetJacTimes(void* arkode_mem, std::nullptr_t, @@ -157,7 +155,7 @@ constexpr auto& ARKStepSetPreconditioner = ARKSpilsSetPreconditioner; constexpr auto& ARKStepSetUserData = ARKodeSetUserData; #endif -ArkodeSolver::ArkodeSolver(Options *opts) : Solver(opts) { +ArkodeSolver::ArkodeSolver(Options* opts) : Solver(opts) { has_constraints = false; // This solver doesn't have constraints } @@ -200,8 +198,8 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { throw BoutException("Allreduce localN -> GlobalN failed!\n"); } - output.write("\t3d fields = %d, 2d fields = %d neq=%d, local_N=%d\n", - n3Dvars(), n2Dvars(), neq, local_N); + output.write("\t3d fields = %d, 2d fields = %d neq=%d, local_N=%d\n", n3Dvars(), + n2Dvars(), neq, local_N); // Allocate memory if ((uvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) @@ -220,7 +218,7 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { // Solve only implicit part const auto impl = (*options)["implicit"].withDefault(true); - if(imex) { //Use ImEx solver + if (imex) { // Use ImEx solver TRACE("ARKStep ImEx"); output.write("\tUsing ARKode ImEx solver \n"); // arkode_rhs_e holds the explicit part, arkode_rhs_i holds the implicit part @@ -228,18 +226,18 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { == nullptr) throw BoutException("ARKStepCreate failed\n"); - if(expl && impl){ + if (expl && impl) { if (ARKStepSetImEx(arkode_mem) != ARK_SUCCESS) throw BoutException("ARKStepSetImEx failed\n"); } else if (expl) { - if( ARKStepSetExplicit(arkode_mem) != ARK_SUCCESS ) - throw BoutException("ARKStepSetExplicit failed\n"); + if (ARKStepSetExplicit(arkode_mem) != ARK_SUCCESS) + throw BoutException("ARKStepSetExplicit failed\n"); } else { - if( ARKStepSetImplicit(arkode_mem) != ARK_SUCCESS ) - throw BoutException("ARKStepSetImplicit failed\n"); + if (ARKStepSetImplicit(arkode_mem) != ARK_SUCCESS) + throw BoutException("ARKStepSetImplicit failed\n"); } - } else { - if(expl){ //Use purely explicit solver + } else { + if (expl) { // Use purely explicit solver TRACE("ARKStep Explicit"); output.write("\tUsing ARKStep Explicit solver \n"); // arkode_rhs_e holds the explicit part, arkode_rhs_i holds @@ -248,7 +246,7 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { throw BoutException("ARKStepCreate failed\n"); if (ARKStepSetExplicit(arkode_mem) != ARK_SUCCESS) throw BoutException("ARKStepSetExplicit failed\n"); - } else { //Use purely implicit solver + } else { // Use purely implicit solver TRACE("ARKStep Implicit"); output.write("\tUsing ARKStep Implicit solver \n"); // arkode_rhs_e holds the explicit part, arkode_rhs_i holds @@ -343,40 +341,40 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { throw BoutException("ARKStepSStolerances failed\n"); } - if( ARKStepSetMaxNumSteps(arkode_mem, mxsteps) != ARK_SUCCESS ) + if (ARKStepSetMaxNumSteps(arkode_mem, mxsteps) != ARK_SUCCESS) throw BoutException("ARKStepSetMaxNumSteps failed\n"); const auto max_timestep = (*options)["max_timestep"].withDefault(-1.); - if(max_timestep > 0.0) { - if( ARKStepSetMaxStep(arkode_mem, max_timestep) != ARK_SUCCESS ) + if (max_timestep > 0.0) { + if (ARKStepSetMaxStep(arkode_mem, max_timestep) != ARK_SUCCESS) throw BoutException("ARKStepSetMaxStep failed\n"); } const auto min_timestep = (*options)["min_timestep"].withDefault(-1.); - if(min_timestep > 0.0) { - if( ARKStepSetMinStep(arkode_mem, min_timestep) != ARK_SUCCESS ) + if (min_timestep > 0.0) { + if (ARKStepSetMinStep(arkode_mem, min_timestep) != ARK_SUCCESS) throw BoutException("ARKStepSetMinStep failed\n"); } - + const auto start_timestep = (*options)["start_timestep"].withDefault(-1); - if(start_timestep > 0.0) { - if( ARKStepSetInitStep(arkode_mem, start_timestep) != ARK_SUCCESS ) + if (start_timestep > 0.0) { + if (ARKStepSetInitStep(arkode_mem, start_timestep) != ARK_SUCCESS) throw BoutException("ARKStepSetInitStep failed"); } - - //ARKStepSetPredictorMethod(arkode_mem,4); + + // ARKStepSetPredictorMethod(arkode_mem,4); /// Newton method can include Preconditioners and Jacobian function const auto fixed_point = (*options)["fixed_point"].withDefault(false); #if SUNDIALS_VERSION_MAJOR < 4 - if(fixed_point){ //Use accellerated fixed point - output.write("\tUsing accellerated fixed point solver\n"); - if( ARKodeSetFixedPoint(arkode_mem, 3.0) ) + if (fixed_point) { // Use accellerated fixed point + output.write("\tUsing accellerated fixed point solver\n"); + if (ARKodeSetFixedPoint(arkode_mem, 3.0)) throw BoutException("ARKodeSetFixedPoint failed\n"); - }else{ + } else { output.write("\tUsing Newton iteration\n"); - if( ARKodeSetNewton(arkode_mem) ) + if (ARKodeSetNewton(arkode_mem)) throw BoutException("ARKodeSetNewton failed\n"); } #else @@ -396,91 +394,90 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { const auto use_precon = (*options)["use_precon"].withDefault(false); const auto maxl = (*options)["maxl"].withDefault(0); - /// Set Preconditioner - if(use_precon) { - const auto rightprec = (*options)["rightprec"].withDefault(false); - const int prectype = rightprec ? PREC_RIGHT : PREC_LEFT; + /// Set Preconditioner + if (use_precon) { + const auto rightprec = (*options)["rightprec"].withDefault(false); + const int prectype = rightprec ? PREC_RIGHT : PREC_LEFT; #if SUNDIALS_VERSION_MAJOR >= 3 - if ((sun_solver = SUNLinSol_SPGMR(uvec, prectype, maxl)) == nullptr) - throw BoutException("Creating SUNDIALS linear solver failed\n"); - if (ARKStepSetLinearSolver(arkode_mem, sun_solver, nullptr) != ARK_SUCCESS) - throw BoutException("ARKStepSetLinearSolver failed\n"); + if ((sun_solver = SUNLinSol_SPGMR(uvec, prectype, maxl)) == nullptr) + throw BoutException("Creating SUNDIALS linear solver failed\n"); + if (ARKStepSetLinearSolver(arkode_mem, sun_solver, nullptr) != ARK_SUCCESS) + throw BoutException("ARKStepSetLinearSolver failed\n"); #else - if (ARKSpgmr(arkode_mem, prectype, maxl) != ARKSPILS_SUCCESS) - throw BoutException("ARKSpgmr failed\n"); + if (ARKSpgmr(arkode_mem, prectype, maxl) != ARKSPILS_SUCCESS) + throw BoutException("ARKSpgmr failed\n"); #endif - if(!have_user_precon()) { - output.write("\tUsing BBD preconditioner\n"); - - /// Get options - // Compute band_width_default from actually added fields, to allow for multiple - // Mesh objects - // - // Previous implementation was equivalent to: - // int MXSUB = mesh->xend - mesh->xstart + 1; - // int band_width_default = n3Dvars()*(MXSUB+2); - const int band_width_default = std::accumulate( - begin(f3d), end(f3d), 0, [](int a, const VarStr& fvar) { - Mesh* localmesh = fvar.var->getMesh(); - return a + localmesh->xend - localmesh->xstart + 3; - }); - - const auto mudq = (*options)["mudq"].withDefault(band_width_default); - const auto mldq = (*options)["mldq"].withDefault(band_width_default); - const auto mukeep = (*options)["mukeep"].withDefault(n3Dvars() + n2Dvars()); - const auto mlkeep = (*options)["mlkeep"].withDefault(n3Dvars() + n2Dvars()); - - if (ARKBBDPrecInit(arkode_mem, local_N, mudq, mldq, mukeep, mlkeep, ZERO, - arkode_bbd_rhs, nullptr) != ARK_SUCCESS) - throw BoutException("ARKBBDPrecInit failed\n"); - - } else { - output.write("\tUsing user-supplied preconditioner\n"); - - if (ARKStepSetPreconditioner(arkode_mem, nullptr, arkode_pre_shim) != - ARK_SUCCESS) - throw BoutException("ARKStepSetPreconditioner failed\n"); - } - }else { - // Not using preconditioning + if (!have_user_precon()) { + output.write("\tUsing BBD preconditioner\n"); + + /// Get options + // Compute band_width_default from actually added fields, to allow for multiple + // Mesh objects + // + // Previous implementation was equivalent to: + // int MXSUB = mesh->xend - mesh->xstart + 1; + // int band_width_default = n3Dvars()*(MXSUB+2); + const int band_width_default = std::accumulate( + begin(f3d), end(f3d), 0, [](int a, const VarStr& fvar) { + Mesh* localmesh = fvar.var->getMesh(); + return a + localmesh->xend - localmesh->xstart + 3; + }); + + const auto mudq = (*options)["mudq"].withDefault(band_width_default); + const auto mldq = (*options)["mldq"].withDefault(band_width_default); + const auto mukeep = (*options)["mukeep"].withDefault(n3Dvars() + n2Dvars()); + const auto mlkeep = (*options)["mlkeep"].withDefault(n3Dvars() + n2Dvars()); + + if (ARKBBDPrecInit(arkode_mem, local_N, mudq, mldq, mukeep, mlkeep, ZERO, + arkode_bbd_rhs, nullptr) + != ARK_SUCCESS) + throw BoutException("ARKBBDPrecInit failed\n"); + + } else { + output.write("\tUsing user-supplied preconditioner\n"); + + if (ARKStepSetPreconditioner(arkode_mem, nullptr, arkode_pre_shim) != ARK_SUCCESS) + throw BoutException("ARKStepSetPreconditioner failed\n"); + } + } else { + // Not using preconditioning - output.write("\tNo preconditioning\n"); + output.write("\tNo preconditioning\n"); #if SUNDIALS_VERSION_MAJOR >= 3 - if ((sun_solver = SUNLinSol_SPGMR(uvec, PREC_NONE, maxl)) == nullptr) - throw BoutException("Creating SUNDIALS linear solver failed\n"); - if (ARKStepSetLinearSolver(arkode_mem, sun_solver, nullptr) != ARK_SUCCESS) - throw BoutException("ARKStepSetLinearSolver failed\n"); + if ((sun_solver = SUNLinSol_SPGMR(uvec, PREC_NONE, maxl)) == nullptr) + throw BoutException("Creating SUNDIALS linear solver failed\n"); + if (ARKStepSetLinearSolver(arkode_mem, sun_solver, nullptr) != ARK_SUCCESS) + throw BoutException("ARKStepSetLinearSolver failed\n"); #else - if (ARKSpgmr(arkode_mem, PREC_NONE, maxl) != ARKSPILS_SUCCESS) - throw BoutException("ARKSpgmr failed\n"); + if (ARKSpgmr(arkode_mem, PREC_NONE, maxl) != ARKSPILS_SUCCESS) + throw BoutException("ARKSpgmr failed\n"); #endif - } + } + + /// Set Jacobian-vector multiplication function - /// Set Jacobian-vector multiplication function + const auto use_jacobian = (*options)["use_jacobian"].withDefault(false); + if (use_jacobian && jacfunc) { + output.write("\tUsing user-supplied Jacobian function\n"); - const auto use_jacobian = (*options)["use_jacobian"].withDefault(false); - if (use_jacobian && jacfunc) { - output.write("\tUsing user-supplied Jacobian function\n"); + if (ARKStepSetJacTimes(arkode_mem, nullptr, arkode_jac) != ARK_SUCCESS) + throw BoutException("ARKStepSetJacTimesVecFn failed\n"); + } else + output.write("\tUsing difference quotient approximation for Jacobian\n"); - if (ARKStepSetJacTimes(arkode_mem, nullptr, arkode_jac) != ARK_SUCCESS) - throw BoutException("ARKStepSetJacTimesVecFn failed\n"); - }else - output.write("\tUsing difference quotient approximation for Jacobian\n"); - -//Use ARKode optimal parameters - const auto optimize = (*options)["optimize"].withDefault(false); - if(optimize){ + // Use ARKode optimal parameters + const auto optimize = (*options)["optimize"].withDefault(false); + if (optimize) { output.write("\tUsing ARKode inbuilt optimization\n"); - if( ARKStepSetOptimalParams(arkode_mem) != ARK_SUCCESS ) + if (ARKStepSetOptimalParams(arkode_mem) != ARK_SUCCESS) throw BoutException("ARKStepSetOptimalParams failed"); } return 0; } - /************************************************************************** * Run - Advance time **************************************************************************/ @@ -488,37 +485,38 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { int ArkodeSolver::run() { TRACE("ArkodeSolver::run()"); - if(!initialised) + if (!initialised) throw BoutException("ArkodeSolver not initialised\n"); - for(int i=0;i Newton iterations per step: %e\n", + + output.write(" -> Newton iterations per step: %e\n", static_cast(nniters) / static_cast(nsteps)); output.write(" -> Linear iterations per Newton iteration: %e\n", static_cast(nliters) / static_cast(nniters)); @@ -528,7 +526,7 @@ int ArkodeSolver::run() { /// Call the monitor function - if(call_monitors(simtime, i, NOUT)) { + if (call_monitors(simtime, i, NOUT)) { // User signalled to quit break; } @@ -546,23 +544,24 @@ BoutReal ArkodeSolver::run(BoutReal tout) { pre_ncalls = 0; int flag; - if(!monitor_timestep) { + if (!monitor_timestep) { // Run in normal mode flag = ARKStepEvolve(arkode_mem, tout, uvec, &simtime, ARK_NORMAL); - }else { + } else { // Run in single step mode, to call timestep monitors BoutReal internal_time; ARKStepGetCurrentTime(arkode_mem, &internal_time); - while(internal_time < tout) { + while (internal_time < tout) { // Run another step const BoutReal last_time = internal_time; flag = ARKStepEvolve(arkode_mem, tout, uvec, &internal_time, ARK_ONE_STEP); - - if(flag != ARK_SUCCESS) { - output_error.write("ERROR ARKODE solve failed at t = %e, flag = %d\n", internal_time, flag); + + if (flag != ARK_SUCCESS) { + output_error.write("ERROR ARKODE solve failed at t = %e, flag = %d\n", + internal_time, flag); return -1.0; } - + // Call timestep monitor call_timestep_monitors(internal_time, internal_time - last_time); } @@ -575,8 +574,8 @@ BoutReal ArkodeSolver::run(BoutReal tout) { load_vars(NV_DATA_P(uvec)); // Call rhs function to get extra variables at this time run_rhs(simtime); - //run_diffusive(simtime); - if(flag != ARK_SUCCESS) { + // run_diffusive(simtime); + if (flag != ARK_SUCCESS) { output_error.write("ERROR ARKODE solve failed at t = %e, flag = %d\n", simtime, flag); return -1.0; } @@ -588,7 +587,7 @@ BoutReal ArkodeSolver::run(BoutReal tout) { * Explicit RHS function du = F_E(t, u) **************************************************************************/ -void ArkodeSolver::rhs_e(BoutReal t, BoutReal *udata, BoutReal *dudata) { +void ArkodeSolver::rhs_e(BoutReal t, BoutReal* udata, BoutReal* dudata) { TRACE("Running RHS: ArkodeSolver::rhs_e(%e)", t); // Load state from udata @@ -597,7 +596,7 @@ void ArkodeSolver::rhs_e(BoutReal t, BoutReal *udata, BoutReal *dudata) { // Get the current timestep // Note: ARKodeGetCurrentStep updated too late in older versions ARKStepGetLastStep(arkode_mem, &hcur); - + // Call RHS function run_convective(t); @@ -605,12 +604,11 @@ void ArkodeSolver::rhs_e(BoutReal t, BoutReal *udata, BoutReal *dudata) { save_derivs(dudata); } - /************************************************************************** * Implicit RHS function du = F_I(t, u) **************************************************************************/ -void ArkodeSolver::rhs_i(BoutReal t, BoutReal *udata, BoutReal *dudata) { +void ArkodeSolver::rhs_i(BoutReal t, BoutReal* udata, BoutReal* dudata) { TRACE("Running RHS: ArkodeSolver::rhs_i(%e)", t); load_vars(udata); @@ -619,12 +617,11 @@ void ArkodeSolver::rhs_i(BoutReal t, BoutReal *udata, BoutReal *dudata) { run_diffusive(t); save_derivs(dudata); } - - + /************************************************************************** * Full RHS function du = F(t, u) **************************************************************************/ -void ArkodeSolver::rhs(BoutReal t, BoutReal *udata, BoutReal *dudata) { +void ArkodeSolver::rhs(BoutReal t, BoutReal* udata, BoutReal* dudata) { TRACE("Running RHS: ArkodeSolver::rhs(%e)", t); load_vars(udata); @@ -634,17 +631,17 @@ void ArkodeSolver::rhs(BoutReal t, BoutReal *udata, BoutReal *dudata) { save_derivs(dudata); } - /************************************************************************** * Preconditioner function **************************************************************************/ -void ArkodeSolver::pre(BoutReal t, BoutReal gamma, BoutReal delta, BoutReal *udata, BoutReal *rvec, BoutReal *zvec) { +void ArkodeSolver::pre(BoutReal t, BoutReal gamma, BoutReal delta, BoutReal* udata, + BoutReal* rvec, BoutReal* zvec) { TRACE("Running preconditioner: ArkodeSolver::pre(%e)", t); const BoutReal tstart = MPI_Wtime(); - if(!have_user_precon()) { + if (!have_user_precon()) { // Identity (but should never happen) const int N = NV_LOCLENGTH_P(uvec); std::copy(rvec, rvec + N, zvec); @@ -656,7 +653,7 @@ void ArkodeSolver::pre(BoutReal t, BoutReal gamma, BoutReal delta, BoutReal *uda // Load vector to be inverted into F_vars load_derivs(rvec); - + run_precon(t, gamma, delta); // Save the solution from F_vars @@ -670,18 +667,18 @@ void ArkodeSolver::pre(BoutReal t, BoutReal gamma, BoutReal delta, BoutReal *uda * Jacobian-vector multiplication function **************************************************************************/ -void ArkodeSolver::jac(BoutReal t, BoutReal *ydata, BoutReal *vdata, BoutReal *Jvdata) { +void ArkodeSolver::jac(BoutReal t, BoutReal* ydata, BoutReal* vdata, BoutReal* Jvdata) { TRACE("Running Jacobian: ArkodeSolver::jac(%e)", t); if (jacfunc == nullptr) throw BoutException("No jacobian function supplied!\n"); - + // Load state from ydate load_vars(ydata); - + // Load vector to be multiplied into F_vars load_derivs(vdata); - + // Call function (*jacfunc)(t); @@ -693,58 +690,49 @@ void ArkodeSolver::jac(BoutReal t, BoutReal *ydata, BoutReal *vdata, BoutReal *J * ARKODE explicit RHS functions **************************************************************************/ -static int arkode_rhs_e(BoutReal t, - N_Vector u, N_Vector du, - void *user_data) { - - BoutReal *udata = NV_DATA_P(u); - BoutReal *dudata = NV_DATA_P(du); - - ArkodeSolver *s = static_cast(user_data); - +static int arkode_rhs_e(BoutReal t, N_Vector u, N_Vector du, void* user_data) { + + BoutReal* udata = NV_DATA_P(u); + BoutReal* dudata = NV_DATA_P(du); + + ArkodeSolver* s = static_cast(user_data); + // Calculate RHS function try { s->rhs_e(t, udata, dudata); - } catch (BoutRhsFail &error) { + } catch (BoutRhsFail& error) { return 1; } return 0; } +static int arkode_rhs_i(BoutReal t, N_Vector u, N_Vector du, void* user_data) { + BoutReal* udata = NV_DATA_P(u); + BoutReal* dudata = NV_DATA_P(du); -static int arkode_rhs_i(BoutReal t, - N_Vector u, N_Vector du, - void *user_data) { - - BoutReal *udata = NV_DATA_P(u); - BoutReal *dudata = NV_DATA_P(du); + ArkodeSolver* s = static_cast(user_data); - ArkodeSolver *s = static_cast(user_data); - - //Calculate RHS function + // Calculate RHS function try { - s->rhs_i(t, udata, dudata); - } catch (BoutRhsFail &error) { + s->rhs_i(t, udata, dudata); + } catch (BoutRhsFail& error) { return 1; } return 0; - } - +} -static int arkode_rhs(BoutReal t, - N_Vector u, N_Vector du, - void *user_data) { +static int arkode_rhs(BoutReal t, N_Vector u, N_Vector du, void* user_data) { - BoutReal *udata = NV_DATA_P(u); - BoutReal *dudata = NV_DATA_P(du); + BoutReal* udata = NV_DATA_P(u); + BoutReal* dudata = NV_DATA_P(du); - ArkodeSolver *s = static_cast(user_data); + ArkodeSolver* s = static_cast(user_data); - //Calculate RHS function + // Calculate RHS function try { s->rhs(t, udata, dudata); - } catch (BoutRhsFail &error) { + } catch (BoutRhsFail& error) { return 1; } return 0; @@ -752,19 +740,19 @@ static int arkode_rhs(BoutReal t, /// RHS function for BBD preconditioner static int arkode_bbd_rhs(ARKODEINT UNUSED(Nlocal), BoutReal t, N_Vector u, N_Vector du, - void *user_data) { + void* user_data) { return arkode_rhs_i(t, u, du, user_data); } /// Preconditioner function static int arkode_pre(BoutReal t, N_Vector yy, N_Vector UNUSED(yp), N_Vector rvec, N_Vector zvec, BoutReal gamma, BoutReal delta, int UNUSED(lr), - void *user_data) { - BoutReal *udata = NV_DATA_P(yy); - BoutReal *rdata = NV_DATA_P(rvec); - BoutReal *zdata = NV_DATA_P(zvec); - - ArkodeSolver *s = static_cast(user_data); + void* user_data) { + BoutReal* udata = NV_DATA_P(yy); + BoutReal* rdata = NV_DATA_P(rvec); + BoutReal* zdata = NV_DATA_P(zvec); + + ArkodeSolver* s = static_cast(user_data); // Calculate residuals s->pre(t, gamma, delta, udata, rdata, zdata); @@ -774,15 +762,15 @@ static int arkode_pre(BoutReal t, N_Vector yy, N_Vector UNUSED(yp), N_Vector rve /// Jacobian-vector multiplication function static int arkode_jac(N_Vector v, N_Vector Jv, realtype t, N_Vector y, - N_Vector UNUSED(fy), void *user_data, N_Vector UNUSED(tmp)) { - BoutReal *ydata = NV_DATA_P(y); ///< System state - BoutReal *vdata = NV_DATA_P(v); ///< Input vector - BoutReal *Jvdata = NV_DATA_P(Jv); ///< Jacobian*vector output - - ArkodeSolver *s = static_cast(user_data); - + N_Vector UNUSED(fy), void* user_data, N_Vector UNUSED(tmp)) { + BoutReal* ydata = NV_DATA_P(y); ///< System state + BoutReal* vdata = NV_DATA_P(v); ///< Input vector + BoutReal* Jvdata = NV_DATA_P(Jv); ///< Jacobian*vector output + + ArkodeSolver* s = static_cast(user_data); + s->jac(t, ydata, vdata, Jvdata); - + return 0; } @@ -790,37 +778,36 @@ static int arkode_jac(N_Vector v, N_Vector Jv, realtype t, N_Vector y, * vector abstol functions **************************************************************************/ -void ArkodeSolver::set_abstol_values(BoutReal *abstolvec_data, - std::vector &f2dtols, - std::vector &f3dtols) { +void ArkodeSolver::set_abstol_values(BoutReal* abstolvec_data, + std::vector& f2dtols, + std::vector& f3dtols) { int p = 0; // Counter for location in abstolvec_data array // All boundaries - for (const auto &i2d : bout::globals::mesh->getRegion2D("RGN_BNDRY")) { + for (const auto& i2d : bout::globals::mesh->getRegion2D("RGN_BNDRY")) { loop_abstol_values_op(i2d, abstolvec_data, p, f2dtols, f3dtols, true); } // Bulk of points - for (const auto &i2d : bout::globals::mesh->getRegion2D("RGN_NOBNDRY")) { + for (const auto& i2d : bout::globals::mesh->getRegion2D("RGN_NOBNDRY")) { loop_abstol_values_op(i2d, abstolvec_data, p, f2dtols, f3dtols, false); } } -void ArkodeSolver::loop_abstol_values_op(Ind2D UNUSED(i2d), - BoutReal *abstolvec_data, int &p, - std::vector &f2dtols, - std::vector &f3dtols, bool bndry) { +void ArkodeSolver::loop_abstol_values_op(Ind2D UNUSED(i2d), BoutReal* abstolvec_data, + int& p, std::vector& f2dtols, + std::vector& f3dtols, bool bndry) { // Loop over 2D variables - for(std::vector::size_type i=0; i::size_type i = 0; i < f2dtols.size(); i++) { + if (bndry && !f2d[i].evolve_bndry) continue; abstolvec_data[p] = f2dtols[i]; p++; } - for (int jz=0; jz < bout::globals::mesh->LocalNz; jz++) { + for (int jz = 0; jz < bout::globals::mesh->LocalNz; jz++) { // Loop over 3D variables - for(std::vector::size_type i=0; i::size_type i = 0; i < f3dtols.size(); i++) { + if (bndry && !f3d[i].evolve_bndry) continue; abstolvec_data[p] = f3dtols[i]; p++; From 579c05e320c65d4e1122c0464a4c6e4105d45dd9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 15:54:01 +0000 Subject: [PATCH 1102/1783] Tidy ARKode solver headers --- src/solver/impls/arkode/arkode.cxx | 18 ++++++++++-------- src/solver/impls/arkode/arkode.hxx | 16 ++++++---------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index 8d5c26260b..29c30c313e 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -29,10 +29,14 @@ #ifdef BOUT_HAS_ARKODE -#include -#include -#include // Cell interpolation -#include +#include "bout/mesh.hxx" +#include "boutcomm.hxx" +#include "boutexception.hxx" +#include "field3d.hxx" +#include "msg_stack.hxx" +#include "options.hxx" +#include "output.hxx" +#include "unused.hxx" #if SUNDIALS_VERSION_MAJOR >= 4 #include @@ -52,13 +56,11 @@ #include #include -#include - -#include "unused.hxx" - #include #include +class Field2D; + #define ZERO RCONST(0.) #define ONE RCONST(1.0) diff --git a/src/solver/impls/arkode/arkode.hxx b/src/solver/impls/arkode/arkode.hxx index 0743db84f3..c74ffad9ea 100644 --- a/src/solver/impls/arkode/arkode.hxx +++ b/src/solver/impls/arkode/arkode.hxx @@ -31,17 +31,9 @@ #ifdef BOUT_HAS_ARKODE -class ArkodeSolver; - #include "bout_types.hxx" -#include "field2d.hxx" -#include "field3d.hxx" -#include "vector2d.hxx" -#include "vector3d.hxx" - #include "bout/solver.hxx" - -#include +#include "bout/solverfactory.hxx" #include #if SUNDIALS_VERSION_MAJOR >= 3 @@ -54,7 +46,11 @@ class ArkodeSolver; #include -#include +#include + +class ArkodeSolver; +class Options; + namespace { RegisterSolver registersolverarkode("arkode"); } From d74501fbbacb8d2df14f89d4198f7c0a5ea899b3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 16:11:43 +0000 Subject: [PATCH 1103/1783] Move IDA option variables to where they are used --- src/solver/impls/ida/ida.cxx | 55 ++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index 1d897f685b..1f729aef89 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -154,37 +154,12 @@ int IdaSolver::init(int nout, BoutReal tstep) { // Set the equation type in id(Differential or Algebraic. This is optional) set_id(NV_DATA_P(id)); - /// Get options - // Compute band_width_default from actually added fields, to allow for multiple Mesh - // objects - // - // Previous implementation was equivalent to: - // int MXSUB = mesh->xend - mesh->xstart + 1; - // int band_width_default = n3Dvars()*(MXSUB+2); - const int band_width_default = - std::accumulate(begin(f3d), end(f3d), 0, [](int a, const VarStr& fvar) { - Mesh* localmesh = fvar.var->getMesh(); - return a + localmesh->xend - localmesh->xstart + 3; - }); - - const auto abstol = (*options)["ATOL"].withDefault(1.0e-12); - const auto reltol = (*options)["RTOL"].withDefault(1.0e-5); - const auto maxl = (*options)["maxl"].withDefault(6 * n3d); - const auto mudq = (*options)["mudq"].withDefault(band_width_default); - const auto mldq = (*options)["mldq"].withDefault(band_width_default); - const auto mukeep = (*options)["mukeep"].withDefault(n3d); - const auto mlkeep = (*options)["mlkeep"].withDefault(n3d); - const auto use_precon = (*options)["use_precon"].withDefault(false); - const auto correct_start = (*options)["correct_start"].withDefault(true); - // Maximum number of steps to take between outputs - const auto mxsteps = (*options)["mxstep"].withDefault(500); - - // Call IDACreate and IDAMalloc to initialise - + // Call IDACreate to initialise if ((idamem = IDACreate()) == nullptr) throw BoutException("ERROR: IDACreate failed\n"); - if (IDASetUserData(idamem, this) < 0) // For callbacks, need pointer to solver object + // For callbacks, need pointer to solver object + if (IDASetUserData(idamem, this) < 0) throw BoutException("ERROR: IDASetUserData failed\n"); if (IDASetId(idamem, id) < 0) @@ -193,12 +168,17 @@ int IdaSolver::init(int nout, BoutReal tstep) { if (IDAInit(idamem, idares, simtime, uvec, duvec) < 0) throw BoutException("ERROR: IDAInit failed\n"); + const auto abstol = (*options)["ATOL"].withDefault(1.0e-12); + const auto reltol = (*options)["RTOL"].withDefault(1.0e-5); if (IDASStolerances(idamem, reltol, abstol) < 0) throw BoutException("ERROR: IDASStolerances failed\n"); + // Maximum number of steps to take between outputs + const auto mxsteps = (*options)["mxstep"].withDefault(500); IDASetMaxNumSteps(idamem, mxsteps); // Call IDASpgmr to specify the IDA linear solver IDASPGMR + const auto maxl = (*options)["maxl"].withDefault(6 * n3d); #if SUNDIALS_VERSION_MAJOR >= 3 if ((sun_solver = SUNLinSol_SPGMR(uvec, PREC_NONE, maxl)) == nullptr) throw BoutException("ERROR: SUNSPGMR failed\n"); @@ -209,9 +189,27 @@ int IdaSolver::init(int nout, BoutReal tstep) { throw BoutException("ERROR: IDASpgmr failed\n"); #endif + const auto use_precon = (*options)["use_precon"].withDefault(false); if (use_precon) { if (!have_user_precon()) { output.write("\tUsing BBD preconditioner\n"); + /// Get options + // Compute band_width_default from actually added fields, to allow for multiple Mesh + // objects + // + // Previous implementation was equivalent to: + // int MXSUB = mesh->xend - mesh->xstart + 1; + // int band_width_default = n3Dvars()*(MXSUB+2); + const int band_width_default = std::accumulate( + begin(f3d), end(f3d), 0, [](int a, const VarStr& fvar) { + Mesh* localmesh = fvar.var->getMesh(); + return a + localmesh->xend - localmesh->xstart + 3; + }); + + const auto mudq = (*options)["mudq"].withDefault(band_width_default); + const auto mldq = (*options)["mldq"].withDefault(band_width_default); + const auto mukeep = (*options)["mukeep"].withDefault(n3d); + const auto mlkeep = (*options)["mlkeep"].withDefault(n3d); if (IDABBDPrecInit(idamem, local_N, mudq, mldq, mukeep, mlkeep, ZERO, ida_bbd_res, nullptr)) throw BoutException("ERROR: IDABBDPrecInit failed\n"); @@ -223,6 +221,7 @@ int IdaSolver::init(int nout, BoutReal tstep) { } // Call IDACalcIC (with default options) to correct the initial values + const auto correct_start = (*options)["correct_start"].withDefault(true); if (correct_start) { if (IDACalcIC(idamem, IDA_YA_YDP_INIT, 1e-6)) throw BoutException("ERROR: IDACalcIC failed\n"); From 63c8aa9bad15d33f9ca58abcd9cde5172b90d694 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 16:14:20 +0000 Subject: [PATCH 1104/1783] Remove extraneous TRACE macros from CVODE --- src/solver/impls/cvode/cvode.cxx | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index 69822e4a4a..9ad8699d75 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -140,25 +140,19 @@ int CvodeSolver::init(int nout, BoutReal tstep) { // Get total problem size int neq; - {TRACE("Allreduce localN -> GlobalN"); if (MPI_Allreduce(&local_N, &neq, 1, MPI_INT, MPI_SUM, BoutComm::get())) { throw BoutException("ERROR: MPI_Allreduce failed!\n"); } - } output_info.write("\t3d fields = %d, 2d fields = %d neq=%d, local_N=%d\n", n3Dvars(), n2Dvars(), neq, local_N); // Allocate memory - {TRACE("Allocating memory with N_VNew_Parallel"); if ((uvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) throw BoutException("ERROR: SUNDIALS memory allocation failed\n"); - } // Put the variables into uvec - {TRACE("Saving variables into uvec"); save_vars(NV_DATA_P(uvec)); - } /// Get options BoutReal abstol, reltol; @@ -187,7 +181,6 @@ int CvodeSolver::init(int nout, BoutReal tstep) { int mxorder; // Maximum lmm order to be used by the solver int lmm = CV_BDF; - {TRACE("Getting options"); options->get("mudq", mudq, band_width_default); options->get("mldq", mldq, band_width_default); options->get("mukeep", mukeep, n3Dvars()+n2Dvars()); @@ -240,23 +233,15 @@ int CvodeSolver::init(int nout, BoutReal tstep) { options->get("func_iter", func_iter, false); } - }//End of options TRACE - - {TRACE("Calling CVodeCreate"); const auto iter = func_iter ? CV_FUNCTIONAL : CV_NEWTON; if ((cvode_mem = CVodeCreate(lmm, iter)) == nullptr) throw BoutException("CVodeCreate failed\n"); - } - {TRACE("Calling CVodeSetUserData"); if( CVodeSetUserData(cvode_mem, this) < 0 ) // For callbacks, need pointer to solver object throw BoutException("CVodeSetUserData failed\n"); - } - {TRACE("Calling CVodeInit"); if( CVodeInit(cvode_mem, cvode_rhs, simtime, uvec) < 0 ) throw BoutException("CVodeInit failed\n"); - } #if SUNDIALS_VERSION_MAJOR >= 4 if ((nonlinear_solver = SUNNonlinSol_FixedPoint(uvec, 0)) == nullptr) @@ -267,24 +252,20 @@ int CvodeSolver::init(int nout, BoutReal tstep) { #endif if (max_order>0) { - TRACE("Calling CVodeSetMaxOrder"); if ( CVodeSetMaxOrd(cvode_mem, max_order) < 0) throw BoutException("CVodeSetMaxOrder failed\n"); } if (stablimdet) { - TRACE("Calling CVodeSetstabLimDet"); if ( CVodeSetStabLimDet(cvode_mem, stablimdet) < 0) throw BoutException("CVodeSetstabLimDet failed\n"); } if (use_vector_abstol) { - TRACE("Calling CVodeSVtolerances"); if( CVodeSVtolerances(cvode_mem, reltol, abstolvec) < 0 ) throw BoutException("CVodeSStolerances failed\n"); } else { - TRACE("Calling CVodeSStolerances"); if( CVodeSStolerances(cvode_mem, reltol, abstol) < 0 ) throw BoutException("CVodeSStolerances failed\n"); } @@ -367,7 +348,6 @@ int CvodeSolver::init(int nout, BoutReal tstep) { if ((use_jacobian) && (jacfunc != nullptr)) { output_info.write("\tUsing user-supplied Jacobian function\n"); - TRACE("Setting Jacobian-vector multiply"); if (CVSpilsSetJacTimes(cvode_mem, nullptr, cvode_jac) != CV_SUCCESS) throw BoutException("ERROR: CVSpilsSetJacTimesVecFn failed\n"); } else From d013ed4e44ef744652890cb6ba2de24f80abf2f1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 16:14:44 +0000 Subject: [PATCH 1105/1783] Clang-format CVODE solver --- src/solver/impls/cvode/cvode.cxx | 332 +++++++++++++++---------------- 1 file changed, 166 insertions(+), 166 deletions(-) diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index 9ad8699d75..c1b48f0ccf 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -1,12 +1,12 @@ /************************************************************************** * Interface to SUNDIALS CVODE - * + * * ************************************************************************** * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -29,8 +29,8 @@ #ifdef BOUT_HAS_CVODE #include -#include // Cell interpolation #include +#include // Cell interpolation #include #include @@ -44,23 +44,23 @@ #include #include -#include #include +#include #include #include "unused.hxx" -#define ZERO RCONST(0.) -#define ONE RCONST(1.0) +#define ZERO RCONST(0.) +#define ONE RCONST(1.0) #ifndef CVODEINT using CVODEINT = int; #endif -static int cvode_rhs(BoutReal t, N_Vector u, N_Vector du, void *user_data); -static int cvode_bbd_rhs(CVODEINT Nlocal, BoutReal t, N_Vector u, N_Vector du, - void *user_data); +static int cvode_rhs(BoutReal t, N_Vector u, N_Vector du, void* user_data); +static int cvode_bbd_rhs(CVODEINT Nlocal, BoutReal t, N_Vector u, N_Vector du, + void* user_data); static int cvode_pre(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rvec, N_Vector zvec, BoutReal gamma, BoutReal delta, int lr, void* user_data); @@ -68,8 +68,8 @@ static int cvode_pre(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rvec, N_Vect #if SUNDIALS_VERSION_MAJOR < 3 // Shim for earlier versions inline static int cvode_pre_shim(BoutReal t, N_Vector yy, N_Vector yp, N_Vector rvec, - N_Vector zvec, BoutReal gamma, BoutReal delta, int lr, - void* user_data, N_Vector UNUSED(tmp)) { + N_Vector zvec, BoutReal gamma, BoutReal delta, int lr, + void* user_data, N_Vector UNUSED(tmp)) { return cvode_pre(t, yy, yp, rvec, zvec, gamma, delta, lr, user_data); } #else @@ -77,9 +77,8 @@ inline static int cvode_pre_shim(BoutReal t, N_Vector yy, N_Vector yp, N_Vector constexpr auto& cvode_pre_shim = cvode_pre; #endif -static int cvode_jac(N_Vector v, N_Vector Jv, - realtype t, N_Vector y, N_Vector fy, - void *user_data, N_Vector tmp); +static int cvode_jac(N_Vector v, N_Vector Jv, realtype t, N_Vector y, N_Vector fy, + void* user_data, N_Vector tmp); #if SUNDIALS_VERSION_MAJOR < 3 // Shim for earlier versions @@ -100,13 +99,13 @@ constexpr auto& SUNLinSol_SPGMR = SUNSPGMR; } #endif -CvodeSolver::CvodeSolver(Options *opts) : Solver(opts) { +CvodeSolver::CvodeSolver(Options* opts) : Solver(opts) { has_constraints = false; // This solver doesn't have constraints canReset = true; } CvodeSolver::~CvodeSolver() { - if(initialised) { + if (initialised) { N_VDestroy_Parallel(uvec); CVodeFree(&cvode_mem); #if SUNDIALS_VERSION_MAJOR >= 3 @@ -126,7 +125,7 @@ int CvodeSolver::init(int nout, BoutReal tstep) { TRACE("Initialising CVODE solver"); /// Call the generic initialisation first - if(Solver::init(nout, tstep)) + if (Solver::init(nout, tstep)) return 1; // Save nout and tstep for use in run @@ -140,19 +139,19 @@ int CvodeSolver::init(int nout, BoutReal tstep) { // Get total problem size int neq; - if (MPI_Allreduce(&local_N, &neq, 1, MPI_INT, MPI_SUM, BoutComm::get())) { - throw BoutException("ERROR: MPI_Allreduce failed!\n"); - } + if (MPI_Allreduce(&local_N, &neq, 1, MPI_INT, MPI_SUM, BoutComm::get())) { + throw BoutException("ERROR: MPI_Allreduce failed!\n"); + } - output_info.write("\t3d fields = %d, 2d fields = %d neq=%d, local_N=%d\n", - n3Dvars(), n2Dvars(), neq, local_N); + output_info.write("\t3d fields = %d, 2d fields = %d neq=%d, local_N=%d\n", n3Dvars(), + n2Dvars(), neq, local_N); // Allocate memory - if ((uvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) - throw BoutException("ERROR: SUNDIALS memory allocation failed\n"); + if ((uvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) + throw BoutException("ERROR: SUNDIALS memory allocation failed\n"); // Put the variables into uvec - save_vars(NV_DATA_P(uvec)); + save_vars(NV_DATA_P(uvec)); /// Get options BoutReal abstol, reltol; @@ -166,7 +165,8 @@ int CvodeSolver::init(int nout, BoutReal tstep) { BoutReal start_timestep, max_timestep; bool adams_moulton, func_iter; // Time-integration method - // Compute band_width_default from actually added fields, to allow for multiple Mesh objects + // Compute band_width_default from actually added fields, to allow for multiple Mesh + // objects // // Previous implementation was equivalent to: // int MXSUB = mesh->xend - mesh->xstart + 1; @@ -181,67 +181,68 @@ int CvodeSolver::init(int nout, BoutReal tstep) { int mxorder; // Maximum lmm order to be used by the solver int lmm = CV_BDF; - options->get("mudq", mudq, band_width_default); - options->get("mldq", mldq, band_width_default); - options->get("mukeep", mukeep, n3Dvars()+n2Dvars()); - options->get("mlkeep", mlkeep, n3Dvars()+n2Dvars()); - options->get("ATOL", abstol, 1.0e-12); - options->get("RTOL", reltol, 1.0e-5); - options->get("cvode_max_order", max_order, -1); - options->get("cvode_stability_limit_detection", stablimdet, false); - options->get("use_vector_abstol",use_vector_abstol,false); - if (use_vector_abstol) { - Options *abstol_options = Options::getRoot(); - BoutReal tempabstol; - if ((abstolvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) - throw BoutException("ERROR: SUNDIALS memory allocation (abstol vector) failed\n"); - std::vector f2dtols; - std::vector f3dtols; - BoutReal* abstolvec_data = NV_DATA_P(abstolvec); - for (const auto& f : f2d) { - abstol_options = Options::getRoot()->getSection(f.name); - abstol_options->get("abstol", tempabstol, abstol); - f2dtols.push_back(tempabstol); - } - for (const auto& f : f3d) { - abstol_options = Options::getRoot()->getSection(f.name); - abstol_options->get("atol", tempabstol, abstol); - f3dtols.push_back(tempabstol); - } - set_abstol_values(abstolvec_data, f2dtols, f3dtols); + options->get("mudq", mudq, band_width_default); + options->get("mldq", mldq, band_width_default); + options->get("mukeep", mukeep, n3Dvars() + n2Dvars()); + options->get("mlkeep", mlkeep, n3Dvars() + n2Dvars()); + options->get("ATOL", abstol, 1.0e-12); + options->get("RTOL", reltol, 1.0e-5); + options->get("cvode_max_order", max_order, -1); + options->get("cvode_stability_limit_detection", stablimdet, false); + options->get("use_vector_abstol", use_vector_abstol, false); + if (use_vector_abstol) { + Options* abstol_options = Options::getRoot(); + BoutReal tempabstol; + if ((abstolvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) + throw BoutException("ERROR: SUNDIALS memory allocation (abstol vector) failed\n"); + std::vector f2dtols; + std::vector f3dtols; + BoutReal* abstolvec_data = NV_DATA_P(abstolvec); + for (const auto& f : f2d) { + abstol_options = Options::getRoot()->getSection(f.name); + abstol_options->get("abstol", tempabstol, abstol); + f2dtols.push_back(tempabstol); } - - options->get("maxl", maxl, 5); - OPTION(options, use_precon, false); - OPTION(options, use_jacobian, false); - OPTION(options, max_timestep, -1.); - OPTION(options, start_timestep, -1); - OPTION(options, diagnose, false); - - options->get("mxstep", mxsteps, 500); - options->get("mxorder", mxorder, -1); - options->get("adams_moulton", adams_moulton, false); - - if(adams_moulton) { - // By default use functional iteration for Adams-Moulton - lmm = CV_ADAMS; - output_info.write("\tUsing Adams-Moulton implicit multistep method\n"); - options->get("func_iter", func_iter, true); - }else { - output_info.write("\tUsing BDF method\n"); - // Use Newton iteration for BDF - options->get("func_iter", func_iter, false); + for (const auto& f : f3d) { + abstol_options = Options::getRoot()->getSection(f.name); + abstol_options->get("atol", tempabstol, abstol); + f3dtols.push_back(tempabstol); } + set_abstol_values(abstolvec_data, f2dtols, f3dtols); + } + + options->get("maxl", maxl, 5); + OPTION(options, use_precon, false); + OPTION(options, use_jacobian, false); + OPTION(options, max_timestep, -1.); + OPTION(options, start_timestep, -1); + OPTION(options, diagnose, false); + + options->get("mxstep", mxsteps, 500); + options->get("mxorder", mxorder, -1); + options->get("adams_moulton", adams_moulton, false); + + if (adams_moulton) { + // By default use functional iteration for Adams-Moulton + lmm = CV_ADAMS; + output_info.write("\tUsing Adams-Moulton implicit multistep method\n"); + options->get("func_iter", func_iter, true); + } else { + output_info.write("\tUsing BDF method\n"); + // Use Newton iteration for BDF + options->get("func_iter", func_iter, false); + } - const auto iter = func_iter ? CV_FUNCTIONAL : CV_NEWTON; - if ((cvode_mem = CVodeCreate(lmm, iter)) == nullptr) - throw BoutException("CVodeCreate failed\n"); + const auto iter = func_iter ? CV_FUNCTIONAL : CV_NEWTON; + if ((cvode_mem = CVodeCreate(lmm, iter)) == nullptr) + throw BoutException("CVodeCreate failed\n"); - if( CVodeSetUserData(cvode_mem, this) < 0 ) // For callbacks, need pointer to solver object - throw BoutException("CVodeSetUserData failed\n"); + if (CVodeSetUserData(cvode_mem, this) + < 0) // For callbacks, need pointer to solver object + throw BoutException("CVodeSetUserData failed\n"); - if( CVodeInit(cvode_mem, cvode_rhs, simtime, uvec) < 0 ) - throw BoutException("CVodeInit failed\n"); + if (CVodeInit(cvode_mem, cvode_rhs, simtime, uvec) < 0) + throw BoutException("CVodeInit failed\n"); #if SUNDIALS_VERSION_MAJOR >= 4 if ((nonlinear_solver = SUNNonlinSol_FixedPoint(uvec, 0)) == nullptr) @@ -250,43 +251,42 @@ int CvodeSolver::init(int nout, BoutReal tstep) { if (CVodeSetNonlinearSolver(cvode_mem, nonlinear_solver)) throw BoutException("CVodeSetNonlinearSolver failed\n"); #endif - - if (max_order>0) { - if ( CVodeSetMaxOrd(cvode_mem, max_order) < 0) + + if (max_order > 0) { + if (CVodeSetMaxOrd(cvode_mem, max_order) < 0) throw BoutException("CVodeSetMaxOrder failed\n"); } - + if (stablimdet) { - if ( CVodeSetStabLimDet(cvode_mem, stablimdet) < 0) + if (CVodeSetStabLimDet(cvode_mem, stablimdet) < 0) throw BoutException("CVodeSetstabLimDet failed\n"); } - + if (use_vector_abstol) { - if( CVodeSVtolerances(cvode_mem, reltol, abstolvec) < 0 ) + if (CVodeSVtolerances(cvode_mem, reltol, abstolvec) < 0) throw BoutException("CVodeSStolerances failed\n"); - } - else { - if( CVodeSStolerances(cvode_mem, reltol, abstol) < 0 ) + } else { + if (CVodeSStolerances(cvode_mem, reltol, abstol) < 0) throw BoutException("CVodeSStolerances failed\n"); } CVodeSetMaxNumSteps(cvode_mem, mxsteps); - if(max_timestep > 0.0) { + if (max_timestep > 0.0) { // Setting a maximum timestep CVodeSetMaxStep(cvode_mem, max_timestep); } - if(start_timestep > 0.0) { + if (start_timestep > 0.0) { // Setting a user-supplied initial guess for the appropriate timestep CVodeSetInitStep(cvode_mem, start_timestep); } - - if(start_timestep > 0.0) { + + if (start_timestep > 0.0) { CVodeSetInitStep(cvode_mem, start_timestep); } - if(mxorder > 0) { + if (mxorder > 0) { // Setting the maximum solver order CVodeSetMaxOrd(cvode_mem, mxorder); } @@ -303,7 +303,7 @@ int CvodeSolver::init(int nout, BoutReal tstep) { options->get("rightprec", rightprec, false); if (rightprec) prectype = PREC_RIGHT; - + #if SUNDIALS_VERSION_MAJOR >= 3 if ((sun_solver = SUNLinSol_SPGMR(uvec, prectype, maxl)) == nullptr) throw BoutException("ERROR: SUNSPGMR failed\n"); @@ -327,7 +327,7 @@ int CvodeSolver::init(int nout, BoutReal tstep) { if (CVSpilsSetPreconditioner(cvode_mem, nullptr, cvode_pre_shim)) throw BoutException("ERROR: CVSpilsSetPreconditioner failed\n"); } - }else { + } else { // Not using preconditioning output_info.write("\tNo preconditioning\n"); @@ -352,14 +352,13 @@ int CvodeSolver::init(int nout, BoutReal tstep) { throw BoutException("ERROR: CVSpilsSetJacTimesVecFn failed\n"); } else output_info.write("\tUsing difference quotient approximation for Jacobian\n"); - }else { + } else { output_info.write("\tUsing Functional iteration\n"); } return 0; } - /************************************************************************** * Run - Advance time **************************************************************************/ @@ -367,33 +366,34 @@ int CvodeSolver::init(int nout, BoutReal tstep) { int CvodeSolver::run() { TRACE("CvodeSolver::run()"); - if(!initialised) + if (!initialised) throw BoutException("CvodeSolver not initialised\n"); - for(int i=0;i Newton iterations per step: %e\n", static_cast(nniters) / static_cast(nsteps)); @@ -411,7 +411,7 @@ int CvodeSolver::run() { CVodeGetLastOrder(cvode_mem, &last_order); output.write(" -> Last step size: %e, order: %d\n", last_step, last_order); - + // Local error test failures long int num_fails; CVodeGetNumErrTestFails(cvode_mem, &num_fails); @@ -419,20 +419,20 @@ int CvodeSolver::run() { // Number of nonlinear convergence failures long int nonlin_fails; CVodeGetNumNonlinSolvConvFails(cvode_mem, &nonlin_fails); - - output.write(" -> Local error fails: %ld, nonlinear convergence fails: %ld\n", num_fails, nonlin_fails); + + output.write(" -> Local error fails: %ld, nonlinear convergence fails: %ld\n", + num_fails, nonlin_fails); // Stability limit order reductions long int stab_lims; CVodeGetNumStabLimOrderReds(cvode_mem, &stab_lims); - + output.write(" -> Stability limit order reductions: %ld\n", stab_lims); - } /// Call the monitor function - if(call_monitors(simtime, i, NOUT)) { + if (call_monitors(simtime, i, NOUT)) { // User signalled to quit break; } @@ -457,15 +457,16 @@ BoutReal CvodeSolver::run(BoutReal tout) { // Run in single step mode, to call timestep monitors BoutReal internal_time; CVodeGetCurrentTime(cvode_mem, &internal_time); - while(internal_time < tout) { + while (internal_time < tout) { // Run another step BoutReal last_time = internal_time; flag = CVode(cvode_mem, tout, uvec, &internal_time, CV_ONE_STEP); - + if (flag < 0) { - throw BoutException("ERROR CVODE solve failed at t = %e, flag = %d\n", internal_time, flag); + throw BoutException("ERROR CVODE solve failed at t = %e, flag = %d\n", + internal_time, flag); } - + // Call timestep monitor call_timestep_monitors(internal_time, internal_time - last_time); } @@ -491,7 +492,7 @@ BoutReal CvodeSolver::run(BoutReal tout) { * RHS function du = F(t, u) **************************************************************************/ -void CvodeSolver::rhs(BoutReal t, BoutReal *udata, BoutReal *dudata) { +void CvodeSolver::rhs(BoutReal t, BoutReal* udata, BoutReal* dudata) { TRACE("Running RHS: CvodeSolver::res(%e)", t); // Load state from udata @@ -500,7 +501,7 @@ void CvodeSolver::rhs(BoutReal t, BoutReal *udata, BoutReal *dudata) { // Get the current timestep // Note: CVodeGetCurrentStep updated too late in older versions CVodeGetLastStep(cvode_mem, &hcur); - + // Call RHS function run_rhs(t); @@ -512,16 +513,17 @@ void CvodeSolver::rhs(BoutReal t, BoutReal *udata, BoutReal *dudata) { * Preconditioner function **************************************************************************/ -void CvodeSolver::pre(BoutReal t, BoutReal gamma, BoutReal delta, BoutReal *udata, BoutReal *rvec, BoutReal *zvec) { +void CvodeSolver::pre(BoutReal t, BoutReal gamma, BoutReal delta, BoutReal* udata, + BoutReal* rvec, BoutReal* zvec) { TRACE("Running preconditioner: CvodeSolver::pre(%e)", t); BoutReal tstart = MPI_Wtime(); int N = NV_LOCLENGTH_P(uvec); - - if(!have_user_precon()) { + + if (!have_user_precon()) { // Identity (but should never happen) - for(int i=0;i(user_data); + BoutReal* udata = NV_DATA_P(u); + BoutReal* dudata = NV_DATA_P(du); + + CvodeSolver* s = static_cast(user_data); // Calculate RHS function try { s->rhs(t, udata, dudata); - } catch (BoutRhsFail &error) { + } catch (BoutRhsFail& error) { return 1; } return 0; @@ -588,19 +588,19 @@ static int cvode_rhs(BoutReal t, /// RHS function for BBD preconditioner static int cvode_bbd_rhs(CVODEINT UNUSED(Nlocal), BoutReal t, N_Vector u, N_Vector du, - void *user_data) { + void* user_data) { return cvode_rhs(t, u, du, user_data); } /// Preconditioner function static int cvode_pre(BoutReal t, N_Vector yy, N_Vector UNUSED(yp), N_Vector rvec, N_Vector zvec, BoutReal gamma, BoutReal delta, int UNUSED(lr), - void *user_data) { - BoutReal *udata = NV_DATA_P(yy); - BoutReal *rdata = NV_DATA_P(rvec); - BoutReal *zdata = NV_DATA_P(zvec); + void* user_data) { + BoutReal* udata = NV_DATA_P(yy); + BoutReal* rdata = NV_DATA_P(rvec); + BoutReal* zdata = NV_DATA_P(zvec); - CvodeSolver *s = static_cast(user_data); + CvodeSolver* s = static_cast(user_data); // Calculate residuals s->pre(t, gamma, delta, udata, rdata, zdata); @@ -610,15 +610,15 @@ static int cvode_pre(BoutReal t, N_Vector yy, N_Vector UNUSED(yp), N_Vector rvec /// Jacobian-vector multiplication function static int cvode_jac(N_Vector v, N_Vector Jv, realtype t, N_Vector y, N_Vector UNUSED(fy), - void *user_data, N_Vector UNUSED(tmp)) { - BoutReal *ydata = NV_DATA_P(y); ///< System state - BoutReal *vdata = NV_DATA_P(v); ///< Input vector - BoutReal *Jvdata = NV_DATA_P(Jv); ///< Jacobian*vector output + void* user_data, N_Vector UNUSED(tmp)) { + BoutReal* ydata = NV_DATA_P(y); ///< System state + BoutReal* vdata = NV_DATA_P(v); ///< Input vector + BoutReal* Jvdata = NV_DATA_P(Jv); ///< Jacobian*vector output - CvodeSolver *s = static_cast(user_data); + CvodeSolver* s = static_cast(user_data); s->jac(t, ydata, vdata, Jvdata); - + return 0; } @@ -626,51 +626,51 @@ static int cvode_jac(N_Vector v, N_Vector Jv, realtype t, N_Vector y, N_Vector U * vector abstol functions **************************************************************************/ -void CvodeSolver::set_abstol_values(BoutReal* abstolvec_data, std::vector &f2dtols, std::vector &f3dtols) { +void CvodeSolver::set_abstol_values(BoutReal* abstolvec_data, + std::vector& f2dtols, + std::vector& f3dtols) { int p = 0; // Counter for location in abstolvec_data array // All boundaries - for (const auto &i2d : bout::globals::mesh->getRegion2D("RGN_BNDRY")) { + for (const auto& i2d : bout::globals::mesh->getRegion2D("RGN_BNDRY")) { loop_abstol_values_op(i2d, abstolvec_data, p, f2dtols, f3dtols, true); } // Bulk of points - for (const auto &i2d : bout::globals::mesh->getRegion2D("RGN_NOBNDRY")) { + for (const auto& i2d : bout::globals::mesh->getRegion2D("RGN_NOBNDRY")) { loop_abstol_values_op(i2d, abstolvec_data, p, f2dtols, f3dtols, false); } } -void CvodeSolver::loop_abstol_values_op(Ind2D UNUSED(i2d), - BoutReal *abstolvec_data, int &p, - std::vector &f2dtols, - std::vector &f3dtols, bool bndry) { +void CvodeSolver::loop_abstol_values_op(Ind2D UNUSED(i2d), BoutReal* abstolvec_data, + int& p, std::vector& f2dtols, + std::vector& f3dtols, bool bndry) { // Loop over 2D variables - for(std::vector::size_type i=0; i::size_type i = 0; i < f2dtols.size(); i++) { + if (bndry && !f2d[i].evolve_bndry) { continue; } abstolvec_data[p] = f2dtols[i]; p++; } - - for (int jz=0; jz < bout::globals::mesh->LocalNz; jz++) { + + for (int jz = 0; jz < bout::globals::mesh->LocalNz; jz++) { // Loop over 3D variables - for(std::vector::size_type i=0; i::size_type i = 0; i < f3dtols.size(); i++) { + if (bndry && !f3d[i].evolve_bndry) { continue; } abstolvec_data[p] = f3dtols[i]; p++; - } + } } } void CvodeSolver::resetInternalFields() { TRACE("CvodeSolver::resetInternalFields"); save_vars(NV_DATA_P(uvec)); - - if ( CVodeReInit(cvode_mem, simtime, uvec) < 0 ) + + if (CVodeReInit(cvode_mem, simtime, uvec) < 0) throw BoutException("CVodeReInit failed\n"); - } #endif From d858bb2d94349a9b713d71af1044ec8e9677e7b3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 16:43:15 +0000 Subject: [PATCH 1106/1783] Make CVODE input variables const and move to smallest scope --- src/solver/impls/cvode/cvode.cxx | 167 +++++++++++++++---------------- 1 file changed, 78 insertions(+), 89 deletions(-) diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index c1b48f0ccf..137c9ac896 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -51,6 +51,9 @@ #include "unused.hxx" +#include +#include + #define ZERO RCONST(0.) #define ONE RCONST(1.0) @@ -135,7 +138,7 @@ int CvodeSolver::init(int nout, BoutReal tstep) { output_progress.write("Initialising SUNDIALS' CVODE solver\n"); // Calculate number of variables (in generic_solver) - int local_N = getLocalN(); + const int local_N = getLocalN(); // Get total problem size int neq; @@ -153,92 +156,26 @@ int CvodeSolver::init(int nout, BoutReal tstep) { // Put the variables into uvec save_vars(NV_DATA_P(uvec)); - /// Get options - BoutReal abstol, reltol; - // Initialise abstolvec to nullptr to avoid compiler maybed-uninitialised warning - N_Vector abstolvec = nullptr; - int maxl; - int mudq, mldq; - int mukeep, mlkeep; - int max_order; - bool use_precon, use_jacobian, use_vector_abstol, stablimdet; - BoutReal start_timestep, max_timestep; - bool adams_moulton, func_iter; // Time-integration method - - // Compute band_width_default from actually added fields, to allow for multiple Mesh - // objects - // - // Previous implementation was equivalent to: - // int MXSUB = mesh->xend - mesh->xstart + 1; - // int band_width_default = n3Dvars()*(MXSUB+2); - int band_width_default = 0; - for (auto fvar : f3d) { - Mesh* localmesh = fvar.var->getMesh(); - band_width_default += localmesh->xend - localmesh->xstart + 3; - } - - int mxsteps; // Maximum number of steps to take between outputs - int mxorder; // Maximum lmm order to be used by the solver - int lmm = CV_BDF; - - options->get("mudq", mudq, band_width_default); - options->get("mldq", mldq, band_width_default); - options->get("mukeep", mukeep, n3Dvars() + n2Dvars()); - options->get("mlkeep", mlkeep, n3Dvars() + n2Dvars()); - options->get("ATOL", abstol, 1.0e-12); - options->get("RTOL", reltol, 1.0e-5); - options->get("cvode_max_order", max_order, -1); - options->get("cvode_stability_limit_detection", stablimdet, false); - options->get("use_vector_abstol", use_vector_abstol, false); - if (use_vector_abstol) { - Options* abstol_options = Options::getRoot(); - BoutReal tempabstol; - if ((abstolvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) - throw BoutException("ERROR: SUNDIALS memory allocation (abstol vector) failed\n"); - std::vector f2dtols; - std::vector f3dtols; - BoutReal* abstolvec_data = NV_DATA_P(abstolvec); - for (const auto& f : f2d) { - abstol_options = Options::getRoot()->getSection(f.name); - abstol_options->get("abstol", tempabstol, abstol); - f2dtols.push_back(tempabstol); - } - for (const auto& f : f3d) { - abstol_options = Options::getRoot()->getSection(f.name); - abstol_options->get("atol", tempabstol, abstol); - f3dtols.push_back(tempabstol); - } - set_abstol_values(abstolvec_data, f2dtols, f3dtols); - } - - options->get("maxl", maxl, 5); - OPTION(options, use_precon, false); - OPTION(options, use_jacobian, false); - OPTION(options, max_timestep, -1.); - OPTION(options, start_timestep, -1); - OPTION(options, diagnose, false); - - options->get("mxstep", mxsteps, 500); - options->get("mxorder", mxorder, -1); - options->get("adams_moulton", adams_moulton, false); + diagnose = (*options)["diagnose"].withDefault(false); + const auto adams_moulton = (*options)["adams_moulton"].withDefault(false); if (adams_moulton) { // By default use functional iteration for Adams-Moulton - lmm = CV_ADAMS; output_info.write("\tUsing Adams-Moulton implicit multistep method\n"); - options->get("func_iter", func_iter, true); } else { - output_info.write("\tUsing BDF method\n"); // Use Newton iteration for BDF - options->get("func_iter", func_iter, false); + output_info.write("\tUsing BDF method\n"); } + const auto lmm = adams_moulton ? CV_ADAMS : CV_BDF; + const auto func_iter = (*options)["func_iter"].withDefault(adams_moulton); const auto iter = func_iter ? CV_FUNCTIONAL : CV_NEWTON; + if ((cvode_mem = CVodeCreate(lmm, iter)) == nullptr) throw BoutException("CVodeCreate failed\n"); - if (CVodeSetUserData(cvode_mem, this) - < 0) // For callbacks, need pointer to solver object + // For callbacks, need pointer to solver object + if (CVodeSetUserData(cvode_mem, this) < 0) throw BoutException("CVodeSetUserData failed\n"); if (CVodeInit(cvode_mem, cvode_rhs, simtime, uvec) < 0) @@ -252,57 +189,93 @@ int CvodeSolver::init(int nout, BoutReal tstep) { throw BoutException("CVodeSetNonlinearSolver failed\n"); #endif + const auto max_order = (*options)["cvode_max_order"].withDefault(-1); if (max_order > 0) { if (CVodeSetMaxOrd(cvode_mem, max_order) < 0) throw BoutException("CVodeSetMaxOrder failed\n"); } + const auto stablimdet = + (*options)["cvode_stability_limit_detection"].withDefault(false); if (stablimdet) { if (CVodeSetStabLimDet(cvode_mem, stablimdet) < 0) throw BoutException("CVodeSetstabLimDet failed\n"); } + const auto abstol = (*options)["ATOL"].withDefault(1.0e-12); + const auto reltol = (*options)["RTOL"].withDefault(1.0e-5); + const auto use_vector_abstol = (*options)["use_vector_abstol"].withDefault(false); if (use_vector_abstol) { + std::vector f2dtols; + f2dtols.reserve(f2d.size()); + std::transform(begin(f2d), end(f2d), std::back_inserter(f2dtols), + [abstol](const VarStr& f2) { + auto f2_options = Options::root()[f2.name]; + const auto wrong_name = f2_options.isSet("abstol"); + if (wrong_name) { + output_warn << "WARNING: Option 'abstol' for field " << f2.name + << " is deprecated. Please use 'atol' instead\n"; + } + const std::string atol_name = wrong_name ? "abstol" : "atol"; + return f2_options[atol_name].withDefault(abstol); + }); + + std::vector f3dtols; + f3dtols.reserve(f3d.size()); + std::transform(begin(f3d), end(f3d), std::back_inserter(f3dtols), + [abstol](const VarStr& f3) { + return Options::root()[f3.name]["atol"].withDefault(abstol); + }); + + N_Vector abstolvec = N_VNew_Parallel(BoutComm::get(), local_N, neq); + if (abstolvec == nullptr) + throw BoutException("SUNDIALS memory allocation (abstol vector) failed\n"); + + set_abstol_values(NV_DATA_P(abstolvec), f2dtols, f3dtols); + if (CVodeSVtolerances(cvode_mem, reltol, abstolvec) < 0) throw BoutException("CVodeSStolerances failed\n"); + + N_VDestroy_Parallel(abstolvec); } else { if (CVodeSStolerances(cvode_mem, reltol, abstol) < 0) throw BoutException("CVodeSStolerances failed\n"); } + const auto mxsteps = (*options)["mxstep"].withDefault(500); CVodeSetMaxNumSteps(cvode_mem, mxsteps); + const auto max_timestep = (*options)["max_timestep"].withDefault(-1.); if (max_timestep > 0.0) { - // Setting a maximum timestep CVodeSetMaxStep(cvode_mem, max_timestep); } - if (start_timestep > 0.0) { - // Setting a user-supplied initial guess for the appropriate timestep - CVodeSetInitStep(cvode_mem, start_timestep); + const auto min_timestep = (*options)["min_timestep"].withDefault(-1); + if (min_timestep > 0.0) { + CVodeSetMinStep(cvode_mem, min_timestep); } + const auto start_timestep = (*options)["start_timestep"].withDefault(-1); if (start_timestep > 0.0) { CVodeSetInitStep(cvode_mem, start_timestep); } + const auto mxorder = (*options)["mxorder"].withDefault(-1); if (mxorder > 0) { - // Setting the maximum solver order CVodeSetMaxOrd(cvode_mem, mxorder); } /// Newton method can include Preconditioners and Jacobian function if (!func_iter) { output_info.write("\tUsing Newton iteration\n"); - /// Set Preconditioner TRACE("Setting preconditioner"); + const auto maxl = (*options)["maxl"].withDefault(5); + const auto use_precon = (*options)["use_precon"].withDefault(false); + if (use_precon) { - int prectype = PREC_LEFT; - bool rightprec; - options->get("rightprec", rightprec, false); - if (rightprec) - prectype = PREC_RIGHT; + const auto rightprec = (*options)["rightprec"].withDefault(false); + const int prectype = rightprec ? PREC_RIGHT : PREC_LEFT; #if SUNDIALS_VERSION_MAJOR >= 3 if ((sun_solver = SUNLinSol_SPGMR(uvec, prectype, maxl)) == nullptr) @@ -317,6 +290,24 @@ int CvodeSolver::init(int nout, BoutReal tstep) { if (!have_user_precon()) { output_info.write("\tUsing BBD preconditioner\n"); + /// Get options + // Compute band_width_default from actually added fields, to allow for multiple + // Mesh objects + // + // Previous implementation was equivalent to: + // int MXSUB = mesh->xend - mesh->xstart + 1; + // int band_width_default = n3Dvars()*(MXSUB+2); + const int band_width_default = std::accumulate( + begin(f3d), end(f3d), 0, [](int a, const VarStr& fvar) { + Mesh* localmesh = fvar.var->getMesh(); + return a + localmesh->xend - localmesh->xstart + 3; + }); + + const auto mudq = (*options)["mudq"].withDefault(band_width_default); + const auto mldq = (*options)["mldq"].withDefault(band_width_default); + const auto mukeep = (*options)["mukeep"].withDefault(n3Dvars() + n2Dvars()); + const auto mlkeep = (*options)["mlkeep"].withDefault(n3Dvars() + n2Dvars()); + if (CVBBDPrecInit(cvode_mem, local_N, mudq, mldq, mukeep, mlkeep, ZERO, cvode_bbd_rhs, nullptr)) throw BoutException("ERROR: CVBBDPrecInit failed\n"); @@ -328,8 +319,6 @@ int CvodeSolver::init(int nout, BoutReal tstep) { throw BoutException("ERROR: CVSpilsSetPreconditioner failed\n"); } } else { - // Not using preconditioning - output_info.write("\tNo preconditioning\n"); #if SUNDIALS_VERSION_MAJOR >= 3 @@ -344,7 +333,7 @@ int CvodeSolver::init(int nout, BoutReal tstep) { } /// Set Jacobian-vector multiplication function - + const auto use_jacobian = (*options)["use_jacobian"].withDefault(false); if ((use_jacobian) && (jacfunc != nullptr)) { output_info.write("\tUsing user-supplied Jacobian function\n"); From a7e6003b99a65362183bf0633083c6c205a66ce5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 16:52:17 +0000 Subject: [PATCH 1107/1783] Make IDA/CVODE exception messages more consistent --- src/solver/impls/cvode/cvode.cxx | 28 ++++++++++++++-------------- src/solver/impls/ida/ida.cxx | 31 +++++++++++++++---------------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index 137c9ac896..c472af3ffe 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -143,7 +143,7 @@ int CvodeSolver::init(int nout, BoutReal tstep) { // Get total problem size int neq; if (MPI_Allreduce(&local_N, &neq, 1, MPI_INT, MPI_SUM, BoutComm::get())) { - throw BoutException("ERROR: MPI_Allreduce failed!\n"); + throw BoutException("Allreduce localN -> GlobalN failed!\n"); } output_info.write("\t3d fields = %d, 2d fields = %d neq=%d, local_N=%d\n", n3Dvars(), @@ -151,7 +151,7 @@ int CvodeSolver::init(int nout, BoutReal tstep) { // Allocate memory if ((uvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) - throw BoutException("ERROR: SUNDIALS memory allocation failed\n"); + throw BoutException("SUNDIALS memory allocation failed\n"); // Put the variables into uvec save_vars(NV_DATA_P(uvec)); @@ -199,7 +199,7 @@ int CvodeSolver::init(int nout, BoutReal tstep) { (*options)["cvode_stability_limit_detection"].withDefault(false); if (stablimdet) { if (CVodeSetStabLimDet(cvode_mem, stablimdet) < 0) - throw BoutException("CVodeSetstabLimDet failed\n"); + throw BoutException("CVodeSetStabLimDet failed\n"); } const auto abstol = (*options)["ATOL"].withDefault(1.0e-12); @@ -234,7 +234,7 @@ int CvodeSolver::init(int nout, BoutReal tstep) { set_abstol_values(NV_DATA_P(abstolvec), f2dtols, f3dtols); if (CVodeSVtolerances(cvode_mem, reltol, abstolvec) < 0) - throw BoutException("CVodeSStolerances failed\n"); + throw BoutException("CVodeSVtolerances failed\n"); N_VDestroy_Parallel(abstolvec); } else { @@ -279,12 +279,12 @@ int CvodeSolver::init(int nout, BoutReal tstep) { #if SUNDIALS_VERSION_MAJOR >= 3 if ((sun_solver = SUNLinSol_SPGMR(uvec, prectype, maxl)) == nullptr) - throw BoutException("ERROR: SUNSPGMR failed\n"); + throw BoutException("Creating SUNDIALS linear solver failed\n"); if (CVSpilsSetLinearSolver(cvode_mem, sun_solver) != CV_SUCCESS) - throw BoutException("ERROR: CVSpilsSetLinearSolver failed\n"); + throw BoutException("CVSpilsSetLinearSolver failed\n"); #else if (CVSpgmr(cvode_mem, prectype, maxl) != CVSPILS_SUCCESS) - throw BoutException("ERROR: CVSpgmr failed\n"); + throw BoutException("CVSpgmr failed\n"); #endif if (!have_user_precon()) { @@ -310,25 +310,25 @@ int CvodeSolver::init(int nout, BoutReal tstep) { if (CVBBDPrecInit(cvode_mem, local_N, mudq, mldq, mukeep, mlkeep, ZERO, cvode_bbd_rhs, nullptr)) - throw BoutException("ERROR: CVBBDPrecInit failed\n"); + throw BoutException("CVBBDPrecInit failed\n"); } else { output_info.write("\tUsing user-supplied preconditioner\n"); if (CVSpilsSetPreconditioner(cvode_mem, nullptr, cvode_pre_shim)) - throw BoutException("ERROR: CVSpilsSetPreconditioner failed\n"); + throw BoutException("CVSpilsSetPreconditioner failed\n"); } } else { output_info.write("\tNo preconditioning\n"); #if SUNDIALS_VERSION_MAJOR >= 3 if ((sun_solver = SUNLinSol_SPGMR(uvec, PREC_NONE, maxl)) == nullptr) - throw BoutException("ERROR: SUNSPGMR failed\n"); + throw BoutException("Creating SUNDIALS linear solver failed\n"); if (CVSpilsSetLinearSolver(cvode_mem, sun_solver) != CV_SUCCESS) - throw BoutException("ERROR: CVSpilsSetLinearSolver failed\n"); + throw BoutException("CVSpilsSetLinearSolver failed\n"); #else if (CVSpgmr(cvode_mem, PREC_NONE, maxl) != CVSPILS_SUCCESS) - throw BoutException("ERROR: CVSpgmr failed\n"); + throw BoutException("CVSpgmr failed\n"); #endif } @@ -338,7 +338,7 @@ int CvodeSolver::init(int nout, BoutReal tstep) { output_info.write("\tUsing user-supplied Jacobian function\n"); if (CVSpilsSetJacTimes(cvode_mem, nullptr, cvode_jac) != CV_SUCCESS) - throw BoutException("ERROR: CVSpilsSetJacTimesVecFn failed\n"); + throw BoutException("CVSpilsSetJacTimesVecFn failed\n"); } else output_info.write("\tUsing difference quotient approximation for Jacobian\n"); } else { @@ -540,7 +540,7 @@ void CvodeSolver::jac(BoutReal t, BoutReal* ydata, BoutReal* vdata, BoutReal* Jv TRACE("Running Jacobian: CvodeSolver::jac(%e)", t); if (jacfunc == nullptr) - throw BoutException("ERROR: No jacobian function supplied!\n"); + throw BoutException("No jacobian function supplied!\n"); // Load state from ydate load_vars(ydata); diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index 1f729aef89..9bbc34dd77 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -134,13 +134,12 @@ int IdaSolver::init(int nout, BoutReal tstep) { local_N); // Allocate memory - if ((uvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) - throw BoutException("ERROR: SUNDIALS memory allocation failed\n"); + throw BoutException("SUNDIALS memory allocation failed\n"); if ((duvec = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) - throw BoutException("ERROR: SUNDIALS memory allocation failed\n"); + throw BoutException("SUNDIALS memory allocation failed\n"); if ((id = N_VNew_Parallel(BoutComm::get(), local_N, neq)) == nullptr) - throw BoutException("ERROR: SUNDIALS memory allocation failed\n"); + throw BoutException("SUNDIALS memory allocation failed\n"); // Put the variables into uvec save_vars(NV_DATA_P(uvec)); @@ -156,22 +155,22 @@ int IdaSolver::init(int nout, BoutReal tstep) { // Call IDACreate to initialise if ((idamem = IDACreate()) == nullptr) - throw BoutException("ERROR: IDACreate failed\n"); + throw BoutException("IDACreate failed\n"); // For callbacks, need pointer to solver object if (IDASetUserData(idamem, this) < 0) - throw BoutException("ERROR: IDASetUserData failed\n"); + throw BoutException("IDASetUserData failed\n"); if (IDASetId(idamem, id) < 0) - throw BoutException("ERROR: IDASetID failed\n"); + throw BoutException("IDASetID failed\n"); if (IDAInit(idamem, idares, simtime, uvec, duvec) < 0) - throw BoutException("ERROR: IDAInit failed\n"); + throw BoutException("IDAInit failed\n"); const auto abstol = (*options)["ATOL"].withDefault(1.0e-12); const auto reltol = (*options)["RTOL"].withDefault(1.0e-5); if (IDASStolerances(idamem, reltol, abstol) < 0) - throw BoutException("ERROR: IDASStolerances failed\n"); + throw BoutException("IDASStolerances failed\n"); // Maximum number of steps to take between outputs const auto mxsteps = (*options)["mxstep"].withDefault(500); @@ -181,12 +180,12 @@ int IdaSolver::init(int nout, BoutReal tstep) { const auto maxl = (*options)["maxl"].withDefault(6 * n3d); #if SUNDIALS_VERSION_MAJOR >= 3 if ((sun_solver = SUNLinSol_SPGMR(uvec, PREC_NONE, maxl)) == nullptr) - throw BoutException("ERROR: SUNSPGMR failed\n"); + throw BoutException("Creating SUNDIALS linear solver failed\n"); if (IDASpilsSetLinearSolver(idamem, sun_solver) != IDA_SUCCESS) - throw BoutException("ERROR: IDASpilsSetLinearSolver failed\n"); + throw BoutException("IDASpilsSetLinearSolver failed\n"); #else if (IDASpgmr(idamem, maxl)) - throw BoutException("ERROR: IDASpgmr failed\n"); + throw BoutException("IDASpgmr failed\n"); #endif const auto use_precon = (*options)["use_precon"].withDefault(false); @@ -212,11 +211,11 @@ int IdaSolver::init(int nout, BoutReal tstep) { const auto mlkeep = (*options)["mlkeep"].withDefault(n3d); if (IDABBDPrecInit(idamem, local_N, mudq, mldq, mukeep, mlkeep, ZERO, ida_bbd_res, nullptr)) - throw BoutException("ERROR: IDABBDPrecInit failed\n"); + throw BoutException("IDABBDPrecInit failed\n"); } else { output.write("\tUsing user-supplied preconditioner\n"); if (IDASpilsSetPreconditioner(idamem, nullptr, ida_pre_shim)) - throw BoutException("ERROR: IDASpilsSetPreconditioner failed\n"); + throw BoutException("IDASpilsSetPreconditioner failed\n"); } } @@ -224,7 +223,7 @@ int IdaSolver::init(int nout, BoutReal tstep) { const auto correct_start = (*options)["correct_start"].withDefault(true); if (correct_start) { if (IDACalcIC(idamem, IDA_YA_YDP_INIT, 1e-6)) - throw BoutException("ERROR: IDACalcIC failed\n"); + throw BoutException("IDACalcIC failed\n"); } return 0; @@ -267,7 +266,7 @@ BoutReal IdaSolver::run(BoutReal tout) { TRACE("Running solver: solver::run(%e)", tout); if (!initialised) - throw BoutException("ERROR: Running IDA solver without initialisation\n"); + throw BoutException("Running IDA solver without initialisation\n"); pre_Wtime = 0.0; pre_ncalls = 0; From dd43180255d18a965871c288d482b25cd8fd13c3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 16:57:38 +0000 Subject: [PATCH 1108/1783] Tidy CVODE headers --- src/solver/impls/cvode/cvode.cxx | 20 +++++++++++--------- src/solver/impls/cvode/cvode.hxx | 16 ++++++---------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index c472af3ffe..b3c0093240 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -28,10 +28,14 @@ #ifdef BOUT_HAS_CVODE -#include -#include -#include // Cell interpolation -#include +#include "boutcomm.hxx" +#include "boutexception.hxx" +#include "field3d.hxx" +#include "msg_stack.hxx" +#include "options.hxx" +#include "output.hxx" +#include "unused.hxx" +#include "bout/mesh.hxx" #include @@ -44,15 +48,13 @@ #include #include -#include #include -#include - -#include "unused.hxx" - #include #include +#include + +class Field2D; #define ZERO RCONST(0.) #define ONE RCONST(1.0) diff --git a/src/solver/impls/cvode/cvode.hxx b/src/solver/impls/cvode/cvode.hxx index d29daa155f..453d1070ef 100644 --- a/src/solver/impls/cvode/cvode.hxx +++ b/src/solver/impls/cvode/cvode.hxx @@ -30,17 +30,9 @@ #ifdef BOUT_HAS_CVODE -class CvodeSolver; - #include "bout_types.hxx" -#include "field2d.hxx" -#include "field3d.hxx" -#include "vector2d.hxx" -#include "vector3d.hxx" - #include "bout/solver.hxx" - -#include +#include "bout/solverfactory.hxx" #include #if SUNDIALS_VERSION_MAJOR >= 3 @@ -53,7 +45,11 @@ class CvodeSolver; #include -#include +#include + +class CvodeSolver; +class Options; + namespace { RegisterSolver registersolvercvode("cvode"); } From fd51d076d99c9eb559ba74e59f2ddadc6c1454ae Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 17:05:43 +0000 Subject: [PATCH 1109/1783] Update SUNDIALS installation instructions --- manual/sphinx/user_docs/advanced_install.rst | 43 ++++++++------------ 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/manual/sphinx/user_docs/advanced_install.rst b/manual/sphinx/user_docs/advanced_install.rst index 51ad8116ad..a050fbaace 100644 --- a/manual/sphinx/user_docs/advanced_install.rst +++ b/manual/sphinx/user_docs/advanced_install.rst @@ -326,40 +326,33 @@ solver. Currently, BOUT++ also supports the SUNDIALS solvers CVODE, IDA and ARKODE which are available from https://computation.llnl.gov/casc/sundials/main.html. -.. note:: SUNDIALS is only downloadable from the home page, as submitting your - name and e-mail is required for the download. As for the date of this - typing, SUNDIALS version :math:`3.0.0` is the newest. In order for a - smooth install it is recommended to install SUNDIALS from an install - directory. The full installation guide is found in the downloaded - ``.tar.gz``, but we will provide a step-by-step guide to install it - and make it compatible with BOUT++ here +.. note:: BOUT++ currently supports SUNDIALS > 2.6, up to 4.1.0 as of + March 2019. It is advisable to use the highest possible + version -.. warning:: BOUT++ currently only supports SUNDIALS 2.6 - 2.7! - Support for versions past 2.7 has yet to be - implemented. It is unlikely that we will support versions - before 2.6. - -:: +In order for a smooth install it is recommended to install SUNDIALS +from an install directory. The full installation guide is found in the +downloaded ``.tar.gz``, but we will provide a step-by-step guide to +install it and make it compatible with BOUT++ here:: $ cd ~ - $ mkdir -p local/examples $ mkdir -p install/sundials-install $ cd install/sundials-install - $ # Move the downloaded sundials-2.6.0.tar.gz to sundials-install - $ tar -xzvf sundials-2.6.0.tar.gz - $ mkdir build - $ cd build + $ # Move the downloaded sundials-4.1.0.tar.gz to sundials-install + $ tar -xzvf sundials-4.1.0.tar.gz + $ mkdir build && cd build $ cmake \ -DCMAKE_INSTALL_PREFIX=$HOME/local \ - -DEXAMPLES_INSTALL_PATH=$HOME/local/examples \ - -DCMAKE_LINKER=$HOME/local/lib \ -DLAPACK_ENABLE=ON \ -DOPENMP_ENABLE=ON \ -DMPI_ENABLE=ON \ - ../sundials-2.6.0 + -DCMAKE_C_COMPILER=$(which mpicc) \ + -DCMAKE_CXX_COMPILER=$(which mpicxx) \ + ../sundials-4.1.0 $ make + $ make test $ make install The SUNDIALS IDA solver is a Differential-Algebraic Equation (DAE) @@ -367,11 +360,11 @@ solver, which evolves a system of the form :math:`\mathbf{f}(\mathbf{u},\dot{\mathbf{u}},t) = 0`. This allows algebraic constraints on variables to be specified. -To configure BOUT++ with SUNDIALS only (see section :ref:`sec-PETSc-install` on how -to build PETSc with SUNDIALS), go to the root directory of BOUT++ and -type:: +To configure BOUT++ with SUNDIALS only (see section +:ref:`sec-PETSc-install` on how to build PETSc with SUNDIALS), go to +the root directory of BOUT++ and type:: - $ ./configure --with-sundials + $ ./configure --with-sundials=/path/to/sundials/install SUNDIALS will allow you to select at run-time which solver to use. See :ref:`sec-timeoptions` for more details on how to do this. From e550818d9b703a1b6ae70a6d5329162b44d5ade6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 21 Mar 2019 15:39:35 +0000 Subject: [PATCH 1110/1783] Make transforming Field3D inputs from field aligned optional The previous behaviour was to transform 3d input expressions from field-aligned coordinates for compatibility with older versions. Make this optional - switch off by setting input:transform_from_field_aligned option to false. --- include/field_factory.hxx | 3 +++ manual/sphinx/user_docs/variable_init.rst | 12 ++++++++++++ src/field/field_factory.cxx | 9 ++++++++- tests/unit/field/test_field_factory.cxx | 8 ++++---- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/include/field_factory.hxx b/include/field_factory.hxx index b9d8b42df0..c24a996bba 100644 --- a/include/field_factory.hxx +++ b/include/field_factory.hxx @@ -96,6 +96,9 @@ private: /// The default mesh for create functions. Mesh* fieldmesh; + /// Should we transform input from field-aligned coordinates (if possible)? + bool transform_from_field_aligned{true}; + /// The default options used in resolve(), can be *temporarily* /// overridden in parse()/create2D()/create3D() mutable const Options* options; diff --git a/manual/sphinx/user_docs/variable_init.rst b/manual/sphinx/user_docs/variable_init.rst index 0553fab60c..b3ec9d0a49 100644 --- a/manual/sphinx/user_docs/variable_init.rst +++ b/manual/sphinx/user_docs/variable_init.rst @@ -109,6 +109,18 @@ To do this, set in BOUT.inp This will change the definition of :math:`x` to ``i / (nx - 1)``, so :math:`x` is then between :math:`0` and :math:`1` everywhere. +By default the expressions are evaluated in a field-aligned coordinate system, +i.e. if you are using the ``[mesh]`` option ``paralleltransform = shifted``, +the input ``f`` will have ``f = fromFieldAligned(f)`` applied before being +returned. To switch off this behaviour and evaluate the input expressions in +coordinates with orthogonal x-z (i.e. toroidal :math:`\{\psi,\theta,\phi\}` +coordinates when using ``paralleltransform = shifted``), set in BOUT.inp + +.. code-block:: cfg + + [input] + transform_from_field_aligned = false + The functions in :numref:`tab-initexprfunc` are also available in expressions. diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 807abcc77a..b5b06dac54 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -50,6 +50,13 @@ FieldFactory::FieldFactory(Mesh* localmesh, Options* opt) : fieldmesh(localmesh == nullptr ? bout::globals::mesh : localmesh), options(opt == nullptr ? Options::getRoot() : opt) { + // Set options + // Note: don't use 'options' here because 'options' is a 'const Options*' + // pointer, so this would fail if the "input" section is not present. + Options nonconst_options{opt == nullptr ? Options::root() : *opt}; + transform_from_field_aligned + = nonconst_options["input"]["transform_from_field_aligned"].withDefault(true); + // Useful values addGenerator("pi", std::make_shared(PI)); addGenerator("π", std::make_shared(PI)); @@ -215,7 +222,7 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC } }; - if (localmesh->canToFromFieldAligned()) { + if (transform_from_field_aligned and localmesh->canToFromFieldAligned()) { // Transform from field aligned coordinates, to be compatible with // older BOUT++ inputs. This is not a particularly "nice" solution. result = localmesh->fromFieldAligned(result, RGN_ALL); diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index 910512ca2e..371625975b 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -32,6 +32,8 @@ class FieldFactoryCreationTest : public FakeMeshFixture { bout::utils::make_unique(*mesh_staggered)); } + WithQuietOutput quiet{output_info}; + FieldFactory factory; // We can't just decide which FieldFactory::create?D function to @@ -61,8 +63,6 @@ class FieldFactoryCreationTest : public FakeMeshFixture { T create(Args&&... args) { return createDispatch(std::is_base_of{}, std::forward(args)...); } - - WithQuietOutput quiet{output_info}; }; using Fields = ::testing::Types; @@ -580,9 +580,9 @@ class FieldFactoryTest : public FakeMeshFixture { FieldFactoryTest() : FakeMeshFixture{}, factory{mesh} {} virtual ~FieldFactoryTest() {} - FieldFactory factory; - WithQuietOutput quiet_info{output_info}, quiet{output}, quiet_error{output_error}; + + FieldFactory factory; }; TEST_F(FieldFactoryTest, RequireMesh) { From a43a009b3ad01751268328b820629dfbb3cc5100 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 17:33:26 +0000 Subject: [PATCH 1111/1783] Reduce repeated code in ARKode solver Also use some more explicit names --- src/solver/impls/arkode/arkode.cxx | 82 ++++++++++++++---------------- 1 file changed, 38 insertions(+), 44 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index 29c30c313e..747288e499 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -29,7 +29,6 @@ #ifdef BOUT_HAS_ARKODE -#include "bout/mesh.hxx" #include "boutcomm.hxx" #include "boutexception.hxx" #include "field3d.hxx" @@ -37,6 +36,7 @@ #include "options.hxx" #include "output.hxx" #include "unused.hxx" +#include "bout/mesh.hxx" #if SUNDIALS_VERSION_MAJOR >= 4 #include @@ -68,8 +68,8 @@ class Field2D; using ARKODEINT = int; #endif -static int arkode_rhs_e(BoutReal t, N_Vector u, N_Vector du, void* user_data); -static int arkode_rhs_i(BoutReal t, N_Vector u, N_Vector du, void* user_data); +static int arkode_rhs_explicit(BoutReal t, N_Vector u, N_Vector du, void* user_data); +static int arkode_rhs_implicit(BoutReal t, N_Vector u, N_Vector du, void* user_data); static int arkode_rhs(BoutReal t, N_Vector u, N_Vector du, void* user_data); static int arkode_bbd_rhs(ARKODEINT Nlocal, BoutReal t, N_Vector u, N_Vector du, @@ -216,48 +216,42 @@ int ArkodeSolver::init(int nout, BoutReal tstep) { // Use ImEx capability const auto imex = (*options)["imex"].withDefault(true); // Solve only explicit part - const auto expl = (*options)["explicit"].withDefault(true); + const auto solve_explicit = (*options)["explicit"].withDefault(true); // Solve only implicit part - const auto impl = (*options)["implicit"].withDefault(true); - - if (imex) { // Use ImEx solver - TRACE("ARKStep ImEx"); - output.write("\tUsing ARKode ImEx solver \n"); - // arkode_rhs_e holds the explicit part, arkode_rhs_i holds the implicit part - if ((arkode_mem = ARKStepCreate(arkode_rhs_e, arkode_rhs_i, simtime, uvec)) - == nullptr) - throw BoutException("ARKStepCreate failed\n"); - - if (expl && impl) { - if (ARKStepSetImEx(arkode_mem) != ARK_SUCCESS) - throw BoutException("ARKStepSetImEx failed\n"); - } else if (expl) { - if (ARKStepSetExplicit(arkode_mem) != ARK_SUCCESS) - throw BoutException("ARKStepSetExplicit failed\n"); + const auto solve_implicit = (*options)["implicit"].withDefault(true); + + ASSERT1(solve_explicit or solve_implicit); + + const auto& explicit_rhs = [imex, solve_explicit]() { + if (imex) { + return arkode_rhs_explicit; } else { - if (ARKStepSetImplicit(arkode_mem) != ARK_SUCCESS) - throw BoutException("ARKStepSetImplicit failed\n"); + return solve_explicit ? arkode_rhs : nullptr; } - } else { - if (expl) { // Use purely explicit solver - TRACE("ARKStep Explicit"); - output.write("\tUsing ARKStep Explicit solver \n"); - // arkode_rhs_e holds the explicit part, arkode_rhs_i holds - // the implicit part - if ((arkode_mem = ARKStepCreate(arkode_rhs, nullptr, simtime, uvec)) == nullptr) - throw BoutException("ARKStepCreate failed\n"); - if (ARKStepSetExplicit(arkode_mem) != ARK_SUCCESS) - throw BoutException("ARKStepSetExplicit failed\n"); - } else { // Use purely implicit solver - TRACE("ARKStep Implicit"); - output.write("\tUsing ARKStep Implicit solver \n"); - // arkode_rhs_e holds the explicit part, arkode_rhs_i holds - // the implicit part - if ((arkode_mem = ARKStepCreate(nullptr, arkode_rhs, simtime, uvec)) == nullptr) - throw BoutException("ARKStepCreate failed\n"); - if (ARKStepSetImplicit(arkode_mem) != ARK_SUCCESS) - throw BoutException("ARKStepSetImplicit failed\n"); + }(); + const auto& implicit_rhs = [imex, solve_implicit]() { + if (imex) { + return arkode_rhs_implicit; + } else { + return solve_implicit ? arkode_rhs : nullptr; } + }(); + + if ((arkode_mem = ARKStepCreate(explicit_rhs, implicit_rhs, simtime, uvec)) == nullptr) + throw BoutException("ARKStepCreate failed\n"); + + if (imex and solve_explicit and solve_implicit) { + output_info.write("\tUsing ARKode ImEx solver \n"); + if (ARKStepSetImEx(arkode_mem) != ARK_SUCCESS) + throw BoutException("ARKStepSetImEx failed\n"); + } else if (solve_explicit) { + output_info.write("\tUsing ARKStep Explicit solver \n"); + if (ARKStepSetExplicit(arkode_mem) != ARK_SUCCESS) + throw BoutException("ARKStepSetExplicit failed\n"); + } else { + output_info.write("\tUsing ARKStep Implicit solver \n"); + if (ARKStepSetImplicit(arkode_mem) != ARK_SUCCESS) + throw BoutException("ARKStepSetImplicit failed\n"); } // For callbacks, need pointer to solver object @@ -692,7 +686,7 @@ void ArkodeSolver::jac(BoutReal t, BoutReal* ydata, BoutReal* vdata, BoutReal* J * ARKODE explicit RHS functions **************************************************************************/ -static int arkode_rhs_e(BoutReal t, N_Vector u, N_Vector du, void* user_data) { +static int arkode_rhs_explicit(BoutReal t, N_Vector u, N_Vector du, void* user_data) { BoutReal* udata = NV_DATA_P(u); BoutReal* dudata = NV_DATA_P(du); @@ -708,7 +702,7 @@ static int arkode_rhs_e(BoutReal t, N_Vector u, N_Vector du, void* user_data) { return 0; } -static int arkode_rhs_i(BoutReal t, N_Vector u, N_Vector du, void* user_data) { +static int arkode_rhs_implicit(BoutReal t, N_Vector u, N_Vector du, void* user_data) { BoutReal* udata = NV_DATA_P(u); BoutReal* dudata = NV_DATA_P(du); @@ -743,7 +737,7 @@ static int arkode_rhs(BoutReal t, N_Vector u, N_Vector du, void* user_data) { /// RHS function for BBD preconditioner static int arkode_bbd_rhs(ARKODEINT UNUSED(Nlocal), BoutReal t, N_Vector u, N_Vector du, void* user_data) { - return arkode_rhs_i(t, u, du, user_data); + return arkode_rhs_implicit(t, u, du, user_data); } /// Preconditioner function From 14decdccae432e3d640eed6760670bbd903c68c8 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 22 Mar 2019 11:39:16 +0000 Subject: [PATCH 1112/1783] Fix setting functional nonlinear solver for CVODE in wrong place --- src/solver/impls/cvode/cvode.cxx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index b3c0093240..8810cd233a 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -183,14 +183,6 @@ int CvodeSolver::init(int nout, BoutReal tstep) { if (CVodeInit(cvode_mem, cvode_rhs, simtime, uvec) < 0) throw BoutException("CVodeInit failed\n"); -#if SUNDIALS_VERSION_MAJOR >= 4 - if ((nonlinear_solver = SUNNonlinSol_FixedPoint(uvec, 0)) == nullptr) - throw BoutException("SUNNonlinSol_FixedPoint failed\n"); - - if (CVodeSetNonlinearSolver(cvode_mem, nonlinear_solver)) - throw BoutException("CVodeSetNonlinearSolver failed\n"); -#endif - const auto max_order = (*options)["cvode_max_order"].withDefault(-1); if (max_order > 0) { if (CVodeSetMaxOrd(cvode_mem, max_order) < 0) @@ -345,6 +337,13 @@ int CvodeSolver::init(int nout, BoutReal tstep) { output_info.write("\tUsing difference quotient approximation for Jacobian\n"); } else { output_info.write("\tUsing Functional iteration\n"); +#if SUNDIALS_VERSION_MAJOR >= 4 + if ((nonlinear_solver = SUNNonlinSol_FixedPoint(uvec, 0)) == nullptr) + throw BoutException("SUNNonlinSol_FixedPoint failed\n"); + + if (CVodeSetNonlinearSolver(cvode_mem, nonlinear_solver)) + throw BoutException("CVodeSetNonlinearSolver failed\n"); +#endif } return 0; From 89881df8ffe54b73ac65d2d09d39f3570fd84a4e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 21 Mar 2019 18:04:04 +0000 Subject: [PATCH 1113/1783] Build, cache and test SUNDIALS on Travis --- .travis.yml | 19 ++++++++++++------- .travis_script.sh | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 23e3d067c2..059d60a691 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,13 +43,18 @@ addons: - liblapack-dev - libparpack2-dev +cache: + directories: + - $HOME/local + matrix: fast_finish: true include: - env: &default_env - - CONFIGURE_OPTIONS='--enable-checks=no --enable-optimize=3 --disable-signal --disable-track --disable-backtrace --with-petsc --with-slepc' + - CONFIGURE_OPTIONS="--enable-checks=no --enable-optimize=3 --disable-signal --disable-track --disable-backtrace --with-petsc --with-slepc --with-sundials=$HOME/local" - SCRIPT_FLAGS='-uim' - PIP_PACKAGES='cython==0.29.6 netcdf4==1.4.2 sympy==1.3' + - LD_LIBRARY_PATH=$HOME/local/lib:$LD_LIBRARY_PATH - *petsc_vars - addons: apt: @@ -60,21 +65,21 @@ matrix: - *standard_packages env: - *default_env - - CONFIGURE_OPTIONS='--enable-debug --with-petsc --with-slepc' + - CONFIGURE_OPTIONS="--enable-debug --with-petsc --with-slepc --with-sundials=$HOME/local" - CC=gcc-7 CXX=g++-7 - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" - env: - *default_env - - CONFIGURE_OPTIONS='--enable-shared --with-petsc --with-slepc' + - CONFIGURE_OPTIONS="--enable-shared --with-petsc --with-slepc --with-sundials=$HOME/local" - SCRIPT_FLAGS="-uim -t python -t shared" - env: - *default_env - - CONFIGURE_OPTIONS='--enable-openmp --with-petsc --with-slepc' + - CONFIGURE_OPTIONS="--enable-openmp --with-petsc --with-slepc --with-sundials=$HOME/local" - OMP_NUM_THREADS=2 #CLANG - env: - *default_env - - CONFIGURE_OPTIONS='--enable-debug --with-petsc --with-slepc' + - CONFIGURE_OPTIONS="--enable-debug --with-petsc --with-slepc --with-sundials=$HOME/local" - MPICH_CC=clang MPICH_CXX=clang++ - OMPI_CC=clang OMPI_CXX=clang++ compiler: clang @@ -86,7 +91,7 @@ matrix: - *standard_packages - jq env: - - CONFIGURE_OPTIONS='--enable-code-coverage --enable-debug --enable-track --enable-checks=3 --with-petsc --with-lapack --with-slepc --enable-openmp' + - CONFIGURE_OPTIONS="--enable-code-coverage --enable-debug --enable-track --enable-checks=3 --with-petsc --with-lapack --with-slepc --enable-openmp --with-sundials=$HOME/local" - OMP_NUM_THREADS=2 - *coverage_vars - *petsc_vars @@ -98,7 +103,7 @@ matrix: - *standard_packages - jq env: - - CONFIGURE_OPTIONS='--enable-code-coverage --disable-debug --disable-checks' + - CONFIGURE_OPTIONS="--enable-code-coverage --disable-debug --disable-checks" - *coverage_vars - *codecov_secure diff --git a/.travis_script.sh b/.travis_script.sh index 55b51a70f9..0dc9fce512 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -45,8 +45,41 @@ do esac done +if [[ ! -d $HOME/local/include/sundials ]]; then + echo "****************************************" + echo "Building SUNDIALS" + echo "****************************************" + sundials_ver=4.1.0 + wget https://computation.llnl.gov/projects/sundials/download/sundials-${sundials_ver}.tar.gz + tar xvf sundials-${sundials_ver}.tar.gz + mkdir -p sundials-${sundials_ver}/build && cd sundials-${sundials_ver}/build + cmake -DCMAKE_INSTALL_PREFIX="$HOME/local" \ + -DEXAMPLES_INSTALL=off \ + -DMPI_ENABLE=on \ + -DOPENMP_ENABLE=off \ + -DBUILD_CVODES=off \ + -DBUILD_IDAS=off \ + -DBUILD_KINSOL=off \ + -DBUILD_TESTING=off \ + -DMPI_C_COMPILER="$(command -v mpicc)" \ + -DMPI_CXX_COMPILER="$(command -v mpic++)" \ + -DMPIEXEC_EXECUTABLE="$(command -v mpiexec)" \ + .. + make && make install + cd "${TRAVIS_BUILD_DIR}" + echo "****************************************" + echo "Finished building SUNDIALS" + echo "****************************************" +else + echo "****************************************" + echo "SUNDIALS already installed" + echo "****************************************" +fi + export MAKEFLAGS="-j 2 -k" +echo "****************************************" echo "Configuring with $CONFIGURE_OPTIONS" +echo "****************************************" conf=0 time ./configure $CONFIGURE_OPTIONS MAKEFLAGS="$MAKEFLAGS" || conf=$? if test $conf -gt 0 From 1558760986faae043a4508115aecd3db9b266ea5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 22 Mar 2019 14:07:07 +0000 Subject: [PATCH 1114/1783] Fix missing LD_LIBRARY_PATH export for coverage job --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 059d60a691..5a8995d613 100644 --- a/.travis.yml +++ b/.travis.yml @@ -93,6 +93,7 @@ matrix: env: - CONFIGURE_OPTIONS="--enable-code-coverage --enable-debug --enable-track --enable-checks=3 --with-petsc --with-lapack --with-slepc --enable-openmp --with-sundials=$HOME/local" - OMP_NUM_THREADS=2 + - LD_LIBRARY_PATH=$HOME/local/lib:$LD_LIBRARY_PATH - *coverage_vars - *petsc_vars - *codecov_secure From cefdeb12db27e64fc7e1fc10f852a309eb9d4f90 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Mar 2019 14:19:36 +0000 Subject: [PATCH 1115/1783] Don't make copy of Options object in FieldFactory constructor --- src/field/field_factory.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index b5b06dac54..7c0ec71c9c 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -53,7 +53,7 @@ FieldFactory::FieldFactory(Mesh* localmesh, Options* opt) // Set options // Note: don't use 'options' here because 'options' is a 'const Options*' // pointer, so this would fail if the "input" section is not present. - Options nonconst_options{opt == nullptr ? Options::root() : *opt}; + Options& nonconst_options{opt == nullptr ? Options::root() : *opt}; transform_from_field_aligned = nonconst_options["input"]["transform_from_field_aligned"].withDefault(true); From bd6f6eb6bc9249a170aae035c65f1b9b80e9fe09 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Mar 2019 14:38:54 +0000 Subject: [PATCH 1116/1783] Suppress more output from FieldFactory constructor in unit tests --- tests/unit/field/test_vector3d.cxx | 2 ++ tests/unit/sys/test_options_fields.cxx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index 1e437012d6..7cb81beddc 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -82,6 +82,8 @@ const int Vector3DTest::ny = 5; const int Vector3DTest::nz = 3; TEST_F(Vector3DTest, ApplyBoundaryString) { + WithQuietOutput quiet{output_info}; + Vector3D v; v = 0.0; v.applyBoundary("dirichlet(1.0)"); diff --git a/tests/unit/sys/test_options_fields.cxx b/tests/unit/sys/test_options_fields.cxx index 895096ad97..5fdfc58645 100644 --- a/tests/unit/sys/test_options_fields.cxx +++ b/tests/unit/sys/test_options_fields.cxx @@ -101,6 +101,8 @@ TEST_F(OptionsFieldTest, RetrieveField3DfromString) { Options options; options = "1 + 2"; + WithQuietOutput quiet{output_info}; + Field3D other = options.as(bout::globals::mesh); EXPECT_DOUBLE_EQ(other(0,1,0), 3.0); From 1c5e34de1a3170790fb6a0d43331729064f9413b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Mar 2019 16:08:32 +0000 Subject: [PATCH 1117/1783] Copy any_of/all_of check to other Coordinates constructor This check was updated to be easier to read in the staggered Coordinates constructor previously. Here do the same thing in the basic Coordinates constructor with no location argument. --- src/mesh/coordinates.cxx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 1c4e85bd9e..d78a49cdfe 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -252,14 +252,16 @@ Coordinates::Coordinates(Mesh* mesh) } /// Find covariant metric components + auto covariant_component_names = {"g_11", "g_22", "g_33", "g_12", "g_13", "g_23"}; + auto source_has_component = [&mesh] (const std::string& name) { + return mesh->sourceHasVar(name); + }; // Check if any of the components are present - if (mesh->sourceHasVar("g_11") or mesh->sourceHasVar("g_22") - or mesh->sourceHasVar("g_33") or mesh->sourceHasVar("g_12") - or mesh->sourceHasVar("g_13") or mesh->sourceHasVar("g_23")) { + if (std::any_of(begin(covariant_component_names), end(covariant_component_names), + source_has_component)) { // Check that all components are present - if (mesh->sourceHasVar("g_11") and mesh->sourceHasVar("g_22") - and mesh->sourceHasVar("g_33") and mesh->sourceHasVar("g_12") - and mesh->sourceHasVar("g_13") and mesh->sourceHasVar("g_23")) { + if (std::all_of(begin(covariant_component_names), end(covariant_component_names), + source_has_component)) { mesh->get(g_11, "g_11"); mesh->get(g_22, "g_22"); mesh->get(g_33, "g_33"); From 77dec16b64cfdd3ce60154c6d00d812e0c26cfd4 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Mar 2019 16:11:14 +0000 Subject: [PATCH 1118/1783] Small improvements to coordinates.cxx Use 'auto&' to avoid making a copy, add ASSERT1s to check there are enough guard cells for interpolation. --- src/mesh/coordinates.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index d78a49cdfe..ff7cf3b97f 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -46,7 +46,7 @@ Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location, // initializing yet, leading to an infinite recursion. // Also, here we interpolate for the boundary points at xstart/ystart and // (xend+1)/(yend+1) instead of extrapolating. - for (auto bndry : localmesh->getBoundaries()) { + for (auto& bndry : localmesh->getBoundaries()) { if ((extrapolate_x and bndry->bx != 0) or (extrapolate_y and bndry->by != 0)) { int extrap_start = 0; if ((location == CELL_XLOW) && (bndry->bx > 0)) { @@ -62,6 +62,8 @@ Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location, // this point should already be set correctly because the metric // components have been interpolated to here. if (extrap_start > 0 and f.getLocation() != location) { + ASSERT1(bndry->bx == 0 or localmesh->xstart > 1); + ASSERT1(bndry->by == 0 or localmesh->ystart > 1); // note that either bx or by is >0 here result(bndry->x, bndry->y) = (9. * (f(bndry->x - bndry->bx, bndry->y - bndry->by) + f(bndry->x, bndry->y)) From 21912fdffb797f1e09f33608f5f1b1f0435691a7 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Mar 2019 16:30:22 +0000 Subject: [PATCH 1119/1783] Clarify checks on number of x- and y-boundary guard cells in grid files --- src/mesh/data/gridfromfile.cxx | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 049af59c19..8dd78fe47a 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -267,32 +267,36 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) int ny_to_read = -1; ///Check if field dimensions are correct. x-direction - if (field_dimensions[0] >= m->GlobalNx) { ///including ghostpoints - ASSERT1( (field_dimensions[0] - (m->GlobalNx - 2*mxg)) % 2 == 0 ); - int grid_xguards = (field_dimensions[0] - (m->GlobalNx - 2*mxg)) / 2; - + int grid_xguards = (field_dimensions[0] - (m->GlobalNx - 2*mxg)) / 2; + // Check there is no rounding in calculation of grid_xguards + ASSERT1( (field_dimensions[0] - (m->GlobalNx - 2*mxg)) % 2 == 0 ); + if (grid_xguards >= 0) { ///including ghostpoints nx_to_read = m->LocalNx; xd = grid_xguards - mxg; ASSERT1(xd >= 0); - } else if (field_dimensions[0] == m->GlobalNx - 2*mxg) { ///excluding ghostpoints + } else if (grid_xguards == 0) { ///excluding ghostpoints nx_to_read = m->LocalNx - 2*mxg; xd = mxg; } else { - throw BoutException("Could not read '%s' from file: x-dimension = %i neither matches nx <= %i" - "nor nx-2*mxg = %i ", name.c_str(), field_dimensions[0], m->GlobalNx, m->GlobalNx-2*mxg); + throw BoutException("Could not read '%s' from file: number of x-boundary guard cells " + "in the grid file grid_xguards=%i neither matches grid_xguards >= mxg=%i " + "nor grid_xguards = 0", name.c_str(), grid_xguards, mxg); } ///Check if field dimensions are correct. y-direction - if (field_dimensions[1] >= m->GlobalNy) { ///including ghostpoints + if (grid_yguards > 0) { ///including ghostpoints + ASSERT1(field_dimensions[1] == m->GlobalNy - 2*myg + grid_yguards); ny_to_read = m->LocalNy; yd = grid_yguards - myg; ASSERT1(yd >= 0); - } else if (field_dimensions[1] == m->GlobalNy - 2*myg) { ///excluding ghostpoints + } else if (grid_yguards == 0) { ///excluding ghostpoints + ASSERT1(field_dimensions[1] == m->GlobalNy - 2*myg); ny_to_read = m->LocalNy - 2*myg; yd = myg; } else { - throw BoutException("Could not read '%s' from file: y-dimension = %i neither matches ny <= %i" - "nor ny-2*myg = %i ", name.c_str(), field_dimensions[1], m->GlobalNy, m->GlobalNy-2*myg); + throw BoutException("Could not read '%s' from file: number of y-boundary guard cells " + "in the grid file grid_yguards=%i neither matches grid_yguards >= myg=%i " + "nor grid_yguards = 0", name.c_str(), grid_yguards, myg); } // Now read data from file From 59799ccbc057ee5fdd28be5c7aeaf41aa428139a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Mar 2019 17:19:16 +0000 Subject: [PATCH 1120/1783] Add comment explaining why coordinates_type check uses strcmp --- src/mesh/parallel/fci.cxx | 4 ++++ src/mesh/parallel/identity.cxx | 4 ++++ src/mesh/parallel/shiftedmetric.cxx | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index fd3031fbce..efb6a593e8 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -327,6 +327,10 @@ Field3D FCIMap::integrate(Field3D &f) const { void FCITransform::checkInputGrid() { std::string coordinates_type = ""; if (!mesh.get(coordinates_type, "coordinates_type")) { + // Note: using strcmp here because coordinates_type may have a length that is one + // greater than it should be (probably due to either IDL's string-attribute writing or + // netCDF's string-attribute reading). This makes the comparison + // operator==(std::string,std::string) fail. if (strcmp(coordinates_type.c_str(), "fci") != 0) { throw BoutException("Incorrect coordinate system type "+coordinates_type+" used " "to generate metric components for FCITransform. Should be 'fci."); diff --git a/src/mesh/parallel/identity.cxx b/src/mesh/parallel/identity.cxx index 0dd95969a2..3d6b96764b 100644 --- a/src/mesh/parallel/identity.cxx +++ b/src/mesh/parallel/identity.cxx @@ -21,6 +21,10 @@ void ParallelTransformIdentity::calcYUpDown(Field3D& f) { void ParallelTransformIdentity::checkInputGrid() { std::string coordinates_type = ""; if (!mesh.get(coordinates_type, "coordinates_type")) { + // Note: using strcmp here because coordinates_type may have a length that is one + // greater than it should be (probably due to either IDL's string-attribute writing or + // netCDF's string-attribute reading). This makes the comparison + // operator==(std::string,std::string) fail. if (strcmp(coordinates_type.c_str(), "field_aligned") != 0) { throw BoutException("Incorrect coordinate system type "+coordinates_type+" used " "to generate metric components for ParallelTransformIdentity. Should be " diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index c2403b3c83..9346c9764a 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -49,6 +49,10 @@ ShiftedMetric::ShiftedMetric(Mesh& m, Field2D zShift_) void ShiftedMetric::checkInputGrid() { std::string coordinates_type = ""; if (!mesh.get(coordinates_type, "coordinates_type")) { + // Note: using strcmp here because coordinates_type may have a length that is one + // greater than it should be (probably due to either IDL's string-attribute writing or + // netCDF's string-attribute reading). This makes the comparison + // operator==(std::string,std::string) fail. if (strcmp(coordinates_type.c_str(), "orthogonal") != 0) { throw BoutException("Incorrect coordinate system type " + coordinates_type + " used to generate metric components for ShiftedMetric. " From d06cebc05b90413cb37d501bfe8402c4389fd446 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 22 Mar 2019 18:50:23 +0000 Subject: [PATCH 1121/1783] Small improvements to GridFile - Use overloads rather than template for readField - only Field2D and Field3D versions are needed. - Use '%zu' to remove static_cast when printing size_t. - Use 'const int mxg = ...' and 'const int myg = ...' since these variables do not change. - Move loop over x-index to the outside of some nested loops. --- include/bout/griddata.hxx | 9 ++++---- src/mesh/data/gridfromfile.cxx | 38 +++++++++++++++++++--------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index 8147382ed1..d269544e58 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -123,11 +123,12 @@ private: // Field3D versions of get template bool getField(Mesh* m, T& var, const std::string& name, BoutReal def = 0.0); - // utility method with specializations for Field2D and Field3D to implement - // unshared parts of getField - template + // utility method for Field2D to implement unshared parts of getField + void readField(Mesh* m, const std::string& name, int ys, int yd, int ny_to_read, + int xs, int xd, int nx_to_read, const std::vector& size, Field2D& var); + // utility method for Field3D to implement unshared parts of getField void readField(Mesh* m, const std::string& name, int ys, int yd, int ny_to_read, - int xs, int xd, int nx_to_read, const std::vector& size, T& var); + int xs, int xd, int nx_to_read, const std::vector& size, Field3D& var); }; /*! diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 8dd78fe47a..64bb84131f 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -215,16 +215,16 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) case 3: { // Check size if getting Field3D if (std::is_base_of::value) { - output_warn.write("WARNING: Variable '%s' should be 2D, but has %lu dimensions. Ignored\n", - name.c_str(), static_cast(size.size())); + output_warn.write("WARNING: Variable '%s' should be 2D, but has %zu dimensions. Ignored\n", + name.c_str(), size.size()); var = def; return false; } break; } default: { - output_warn.write("WARNING: Variable '%s' should be 2D, but has %lu dimensions. Ignored\n", - name.c_str(), static_cast(size.size())); + output_warn.write("WARNING: Variable '%s' should be 2D or 3D, but has %zu dimensions. Ignored\n", + name.c_str(), size.size()); var = def; return false; } @@ -233,8 +233,8 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) var.allocate(); // Make sure data allocated ///Ghost region widths. - int mxg = (m->LocalNx - (m->xend - m->xstart + 1)) / 2; - int myg = (m->LocalNy - (m->yend - m->ystart + 1)) / 2; + const int mxg = (m->LocalNx - (m->xend - m->xstart + 1)) / 2; + const int myg = (m->LocalNy - (m->yend - m->ystart + 1)) / 2; ///Check that ghost region widths are in fact integers ASSERT1((m->LocalNx - (m->xend - m->xstart + 1)) % 2 == 0); ASSERT1((m->LocalNy - (m->yend - m->ystart + 1)) % 2 == 0); @@ -305,12 +305,16 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) ///If field does not include ghost points in x-direction -> ///Upper and lower X boundaries copied from nearest point if (field_dimensions[0] == m->GlobalNx - 2*mxg ) { - for (int y=0; yLocalNy; y++) { - for (int z=0; zxstart; x++) { + for (int x=0; xxstart; x++) { + for (int y=0; yLocalNy; y++) { + for (int z=0; zxstart, y, z); } - for (int x=m->xend+1;xLocalNx;x++) { + } + } + for (int x=m->xend+1;xLocalNx;x++) { + for (int y=0; yLocalNy; y++) { + for (int z=0; zxend, y, z); } } @@ -321,11 +325,13 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) ///Upper and lower Y boundaries copied from nearest point if (grid_yguards == 0) { for(int x=0; xLocalNx; x++) { - for (int z=0; zystart; y++) { + for(int y=0; yystart; y++) { + for (int z=0; zystart, z); } - for(int y=m->yend+1; yLocalNy; y++) { + } + for(int y=m->yend+1; yLocalNy; y++) { + for (int z=0; zyend, z); } } @@ -335,8 +341,7 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) return true; } -template<> -void GridFile::readField<>(Mesh* UNUSED(m), const std::string& name, int ys, int yd, +void GridFile::readField(Mesh* UNUSED(m), const std::string& name, int ys, int yd, int ny_to_read, int xs, int xd, int nx_to_read, const std::vector& UNUSED(size), Field2D& var) { @@ -349,8 +354,7 @@ void GridFile::readField<>(Mesh* UNUSED(m), const std::string& name, int ys, int file->setGlobalOrigin(); } -template<> -void GridFile::readField<>(Mesh* m, const std::string& name, int ys, int yd, +void GridFile::readField(Mesh* m, const std::string& name, int ys, int yd, int ny_to_read, int xs, int xd, int nx_to_read, const std::vector& size, Field3D& var) { From 23bc9455e083d739677f288021809deff98e8ce1 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 24 Mar 2019 21:59:03 +0000 Subject: [PATCH 1122/1783] Name argument to Options::isSection to test for presence of subsection --- include/options.hxx | 4 +--- src/sys/options.cxx | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index 2a95c2dadd..d205b42da1 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -545,9 +545,7 @@ public: bool isValue() const { return is_value; } - bool isSection() const { - return is_section; - } + bool isSection(const std::string name = "") const; private: /// The source label given to default values diff --git a/src/sys/options.cxx b/src/sys/options.cxx index b947ab46af..1af7737348 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -119,6 +119,21 @@ bool Options::isSet() const { return true; } +bool Options::isSection(const std::string name) const { + if (name == "") { + // Test this object + return is_section; + } + + // Is there a child section? + auto it = children.find(name); + if (it == children.end()) { + return false; + } else { + return it->second.isSection(); + } +} + template <> void Options::assign<>(Field2D val, const std::string source) { value = std::move(val); From efe5be611b910313607927123707a49e92816f02 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 24 Mar 2019 22:00:08 +0000 Subject: [PATCH 1123/1783] Unit test for Options::isSection --- tests/unit/sys/test_options.cxx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/unit/sys/test_options.cxx b/tests/unit/sys/test_options.cxx index 8307763edd..c6c63ca413 100644 --- a/tests/unit/sys/test_options.cxx +++ b/tests/unit/sys/test_options.cxx @@ -32,6 +32,20 @@ TEST_F(OptionsTest, IsSetDefault) { ASSERT_FALSE(options.isSet("default_value")); } +TEST_F(OptionsTest, IsSection) { + Options options; + + // make sure options is initialized as a section + options["testkey"] = 1.; + + ASSERT_TRUE(options.isSection("")); + ASSERT_FALSE(options.isSection("subsection")); + + options["subsection"]["testkey"] = 1.; + + ASSERT_TRUE(options.isSection("subsection")); +} + TEST_F(OptionsTest, SetGetInt) { Options options; options.set("int_key", 42, "code"); From c1037293eab5f65b1eb1bec22393afd5563ef5f2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 24 Mar 2019 22:40:47 +0000 Subject: [PATCH 1124/1783] More cases in OptionsTest.IsSection Test the original usage, with no argument. --- tests/unit/sys/test_options.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/sys/test_options.cxx b/tests/unit/sys/test_options.cxx index c6c63ca413..ef9730944b 100644 --- a/tests/unit/sys/test_options.cxx +++ b/tests/unit/sys/test_options.cxx @@ -38,6 +38,8 @@ TEST_F(OptionsTest, IsSection) { // make sure options is initialized as a section options["testkey"] = 1.; + ASSERT_TRUE(options.isSection()); + ASSERT_FALSE(options["testkey"].isSection()); ASSERT_TRUE(options.isSection("")); ASSERT_FALSE(options.isSection("subsection")); From 968c1bce881d11077bc5e9eea134d09564ac479a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 25 Mar 2019 09:49:04 +0000 Subject: [PATCH 1125/1783] Take name argument by reference in Options::isSection --- include/options.hxx | 2 +- src/sys/options.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index d205b42da1..2e49f1356b 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -545,7 +545,7 @@ public: bool isValue() const { return is_value; } - bool isSection(const std::string name = "") const; + bool isSection(const std::string& name = "") const; private: /// The source label given to default values diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 1af7737348..04f526561e 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -119,7 +119,7 @@ bool Options::isSet() const { return true; } -bool Options::isSection(const std::string name) const { +bool Options::isSection(const std::string& name) const { if (name == "") { // Test this object return is_section; From 53d18c8f43732c825ec337723ea67129ccd614b6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 25 Mar 2019 10:20:52 +0000 Subject: [PATCH 1126/1783] Undo change to plot label 0 -> 0.D Don't need double precision specification in a plot label. --- tools/tokamak_grids/gridgen/adjust_jpar.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/tokamak_grids/gridgen/adjust_jpar.pro b/tools/tokamak_grids/gridgen/adjust_jpar.pro index d408944800..088cb0da92 100644 --- a/tools/tokamak_grids/gridgen/adjust_jpar.pro +++ b/tools/tokamak_grids/gridgen/adjust_jpar.pro @@ -113,7 +113,7 @@ PRO adjust_jpar, grid, smoothp=smoothp, jpar=jpar, noplot=noplot !P.multi=[0,2,2,0,0] SURFACE, data.jpar0, tit="Input Jpar0", chars=2 SURFACE, jpar, tit="New Jpar0", chars=2 - PLOT, data.jpar0[0,*], tit="jpar at x=0.D Solid=input", yr=[MIN([data.jpar0[0,*],jpar[0,*]]), $ + PLOT, data.jpar0[0,*], tit="jpar at x=0 Solid=input", yr=[MIN([data.jpar0[0,*],jpar[0,*]]), $ MAX([data.jpar0[0,*],jpar[0,*]])] OPLOT, jpar[0,*], psym=1 From a6da370bdf5b8dfa2250a4cdff01cb417c748d9c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 10:20:15 +0000 Subject: [PATCH 1127/1783] Pull out parsing command line arguments from BoutInitialise --- include/bout.hxx | 19 +++ src/bout++.cxx | 291 +++++++++++++++++---------------- tests/unit/src/test_bout++.cxx | 118 +++++++++++++ 3 files changed, 284 insertions(+), 144 deletions(-) create mode 100644 tests/unit/src/test_bout++.cxx diff --git a/include/bout.hxx b/include/bout.hxx index ae4a09903a..976bf95c50 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -101,6 +101,25 @@ using namespace bout::globals; */ int BoutInitialise(int &argc, char **&argv); +namespace bout { +namespace experimental { +/// Results of parsing the command line arguments +struct CommandLineArgs { + int verbosity{4}; + bool color_output{false}; + std::string data_dir{"data"}; ///< Directory for data input/output + std::string opt_file{"BOUT.inp"}; ///< Filename for the options file + std::string set_file{"BOUT.settings"}; ///< Filename for the options file + std::string log_file{"BOUT.log"}; ///< File name for the log file + /// The original set of command line arguments + std::vector original_argv; +}; + +/// Parse the "fixed" command line arguments, like --help and -d +CommandLineArgs parseCommandLineArgs(int argc, char** argv); +} // namespace experimental +} // namespace bout + /*! * Run the given solver. This function is only used * for old-style physics models with standalone C functions diff --git a/src/bout++.cxx b/src/bout++.cxx index c855105e64..9731486beb 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -26,9 +26,6 @@ **************************************************************************/ const char DEFAULT_DIR[] = "data"; -const char DEFAULT_OPT[] = "BOUT.inp"; -const char DEFAULT_SET[] = "BOUT.settings"; -const char DEFAULT_LOG[] = "BOUT.log"; // Value passed at compile time // Used for MD5SUM, BOUT_LOCALE_PATH, and REVISION @@ -115,11 +112,6 @@ int BoutInitialise(int &argc, char **&argv) { string dump_ext; ///< Extensions for restart and dump files - std::string data_dir{DEFAULT_DIR}; ///< Directory for data input/output - std::string opt_file{DEFAULT_OPT}; ///< Filename for the options file - std::string set_file{DEFAULT_SET}; ///< Filename for the options file - std::string log_file{DEFAULT_LOG}; ///< File name for the log file - #ifdef SIGHANDLE /// Set a signal handler for segmentation faults signal(SIGSEGV, bout_signal_handler); @@ -156,133 +148,25 @@ int BoutInitialise(int &argc, char **&argv) { } #endif // BOUT_HAS_GETTEXT - int verbosity=4; - /// Check command-line arguments - /// NB: "restart" and "append" are now caught by options - /// Check for help flag separately - for (int i=1;i] [-f ] [restart [append]] [VAR=VALUE]\n"), argv[0]); - fprintf(stdout, - _("\n" - " -d \tLook in for input/output files\n" - " -f \tUse OPTIONS given in \n" - " -o \tSave used OPTIONS given to \n" - " -l, --log \tPrint log to \n" - " -v, --verbose\t\tIncrease verbosity\n" - " -q, --quiet\t\tDecrease verbosity\n")); -#ifdef LOGCOLOR - fprintf(stdout, - _(" -c, --color\t\tColor output using bout-log-color\n")); -#endif - fprintf(stdout, - _(" -h, --help\t\tThis message\n" - " restart [append]\tRestart the simulation. If append is specified, " - "append to the existing output files, otherwise overwrite them\n" - " VAR=VALUE\t\tSpecify a VALUE for input parameter VAR\n" - "\nFor all possible input parameters, see the user manual and/or the " - "physics model source (e.g. %s.cxx)\n"), - argv[0]); - - std::exit(EXIT_SUCCESS); - } - } - - bool color_output = false; // Will be set true if -c is in the options - std::vector original_argv; - original_argv.reserve(argc); - - for (int i = 0; i < argc; i++) { - original_argv.emplace_back(argv[i]); - } - - for (int i=1;i= argc) { - fprintf(stderr, _("Usage is %s -d \n"), argv[0]); - return 1; - } - - data_dir = argv[++i]; - - argv[i - 1][0] = 0; - argv[i][0] = 0; - - } else if (string(argv[i]) == "-f") { - // Set options file - if (i+1 >= argc) { - fprintf(stderr, _("Usage is %s -f \n"), argv[0]); - return 1; - } - - opt_file = argv[++i]; - - argv[i - 1][0] = 0; - argv[i][0] = 0; - - } else if (string(argv[i]) == "-o") { - // Set options file - if (i+1 >= argc) { - fprintf(stderr, _("Usage is %s -o \n"), argv[0]); - return 1; - } - - set_file = argv[++i]; - - argv[i - 1][0] = 0; - argv[i][0] = 0; - - } else if ((string(argv[i]) == "-l") || (string(argv[i]) == "--log")) { - if (i + 1 >= argc) { - fprintf(stderr, _("Usage is %s -l \n"), argv[0]); - return 1; - } - - log_file = argv[++i]; - - argv[i - 1][0] = 0; - argv[i][0] = 0; - - } else if ( (string(argv[i]) == "-v") || - (string(argv[i]) == "--verbose") ){ - verbosity++; - - argv[i][0] = 0; - - } else if ( (string(argv[i]) == "-q") || - (string(argv[i]) == "--quiet")) { - verbosity--; - - argv[i][0] = 0; - - } else if ( (string(argv[i]) == "-c") || - (string(argv[i]) == "--color") ) { - // Add color to the output by piping through bout-log-color - // This is done after checking all command-line inputs - // in case -c is set multiple times - color_output = true; - - argv[i][0] = 0; - } - } - - if (std::string(set_file) == std::string(opt_file)){ - throw BoutException(_("Input and output file for settings must be different.\nProvide -o to avoid this issue.\n")); + bout::experimental::CommandLineArgs args; + try { + args = bout::experimental::parseCommandLineArgs(argc, argv); + } catch (BoutException& e) { + output_error << _("Bad command line arguments\n"); + output_error << e.what() << endl; + return 1; } // Check that data_dir exists. We do not check whether we can write, as it is // sufficient that the files we need are writeable ... struct stat test; - if (stat(data_dir.c_str(), &test) == 0) { + if (stat(args.data_dir.c_str(), &test) == 0) { if (!S_ISDIR(test.st_mode)) { - throw BoutException(_("DataDir \"%s\" is not a directory\n"), data_dir.c_str()); + throw BoutException(_("DataDir \"%s\" is not a directory\n"), args.data_dir.c_str()); } } else { throw BoutException(_("DataDir \"%s\" does not exist or is not accessible\n"), - data_dir.c_str()); + args.data_dir.c_str()); } // Set the command-line arguments @@ -295,7 +179,7 @@ int BoutInitialise(int &argc, char **&argv) { int MYPE = BoutComm::rank(); #ifdef LOGCOLOR - if (color_output && (MYPE == 0)) { + if (args.color_output && (MYPE == 0)) { // Color stdout by piping through bout-log-color script // Only done on processor 0, since this is the only processor which writes to stdout // This uses popen, fileno and dup2 functions, which are POSIX @@ -337,25 +221,25 @@ int BoutInitialise(int &argc, char **&argv) { /// Open an output file to echo everything to /// On processor 0 anything written to output will go to stdout and the file - if (output.open("%s/%s.%d", data_dir.c_str(), log_file.c_str(), MYPE)) { + if (output.open("%s/%s.%d", args.data_dir.c_str(), args.log_file.c_str(), MYPE)) { return 1; } } - output_error.enable(verbosity > 0); - output_warn.enable(verbosity > 1); - output_progress.enable(verbosity > 2); - output_info.enable(verbosity > 3); - output_verbose.enable(verbosity > 4); - output_debug.enable(verbosity > 5); // Only actually enabled if also compiled with DEBUG + output_error.enable(args.verbosity > 0); + output_warn.enable(args.verbosity > 1); + output_progress.enable(args.verbosity > 2); + output_info.enable(args.verbosity > 3); + output_verbose.enable(args.verbosity > 4); + output_debug.enable(args.verbosity > 5); // Only actually enabled if also compiled with DEBUG // The backward-compatible output object same as output_progress - output.enable(verbosity>2); + output.enable(args.verbosity>2); // Save the PID of this process to file, so it can be shut down by user signal { std::string filename; - std::stringstream(filename) << data_dir << "/.BOUT.pid." << MYPE; + std::stringstream(filename) << args.data_dir << "/.BOUT.pid." << MYPE; std::ofstream pid_file; pid_file.open(filename, std::ios::out); if (pid_file.is_open()) { @@ -432,7 +316,7 @@ int BoutInitialise(int &argc, char **&argv) { // Print command line options output_info.write(_("\tCommand line options for this run : ")); - for (auto& arg : original_argv) { + for (auto& arg : args.original_argv) { output_info << arg << " "; } output_info.write("\n"); @@ -443,15 +327,15 @@ int BoutInitialise(int &argc, char **&argv) { try { /// Load settings file OptionsReader *reader = OptionsReader::getInstance(); - reader->read(options, "%s/%s", data_dir.c_str(), opt_file.c_str()); + reader->read(options, "%s/%s", args.data_dir.c_str(), args.opt_file.c_str()); // Get options override from command-line reader->parseCommandLine(options, argc, argv); // Override options set from short option from the command-line - Options::root()["datadir"].force(data_dir); - Options::root()["optionfile"].force(opt_file); - Options::root()["settingsfile"].force(set_file); + Options::root()["datadir"].force(args.data_dir); + Options::root()["optionfile"].force(args.opt_file); + Options::root()["settingsfile"].force(args.set_file); // Put some run information in the options. // This is mainly so it can be easily read in post-processing @@ -467,7 +351,7 @@ int BoutInitialise(int &argc, char **&argv) { // Save settings if (BoutComm::rank() == 0) { - reader->write(options, "%s/%s", data_dir.c_str(), set_file.c_str()); + reader->write(options, "%s/%s", args.data_dir.c_str(), args.set_file.c_str()); } } catch (BoutException &e) { output << _("Error encountered during initialisation\n"); @@ -500,9 +384,9 @@ int BoutInitialise(int &argc, char **&argv) { /// Open a file for the output if(append) { - bout::globals::dump.opena("%s/BOUT.dmp.%s", data_dir.c_str(), dump_ext.c_str()); + bout::globals::dump.opena("%s/BOUT.dmp.%s", args.data_dir.c_str(), dump_ext.c_str()); }else { - bout::globals::dump.openw("%s/BOUT.dmp.%s", data_dir.c_str(), dump_ext.c_str()); + bout::globals::dump.openw("%s/BOUT.dmp.%s", args.data_dir.c_str(), dump_ext.c_str()); } /// Add book-keeping variables to the output files @@ -522,6 +406,125 @@ int BoutInitialise(int &argc, char **&argv) { return 0; } +namespace bout { +namespace experimental { +auto parseCommandLineArgs(int argc, char** argv) -> CommandLineArgs { + /// Check command-line arguments + /// NB: "restart" and "append" are now caught by options + /// Check for help flag separately + for (int i = 1; i < argc; i++) { + if (string(argv[i]) == "-h" || string(argv[i]) == "--help") { + // Print help message -- note this will be displayed once per processor as we've not + // started MPI yet. + fprintf(stdout, + _("Usage: %s [-d ] [-f ] [restart " + "[append]] [VAR=VALUE]\n"), + argv[0]); + fprintf( + stdout, + _("\n" + " -d \tLook in for input/output files\n" + " -f \tUse OPTIONS given in \n" + " -o \tSave used OPTIONS given to \n" + " -l, --log \tPrint log to \n" + " -v, --verbose\t\tIncrease verbosity\n" + " -q, --quiet\t\tDecrease verbosity\n")); +#ifdef LOGCOLOR + fprintf(stdout, _(" -c, --color\t\tColor output using bout-log-color\n")); +#endif + fprintf(stdout, + _(" -h, --help\t\tThis message\n" + " restart [append]\tRestart the simulation. If append is specified, " + "append to the existing output files, otherwise overwrite them\n" + " VAR=VALUE\t\tSpecify a VALUE for input parameter VAR\n" + "\nFor all possible input parameters, see the user manual and/or the " + "physics model source (e.g. %s.cxx)\n"), + argv[0]); + + std::exit(EXIT_SUCCESS); + } + } + + CommandLineArgs args; + + args.original_argv.reserve(argc); + std::copy(argv, argv + argc, std::back_inserter(args.original_argv)); + + for (int i = 1; i < argc; i++) { + if (string(argv[i]) == "-d") { + // Set data directory + if (i + 1 >= argc) { + throw BoutException(_("Usage is %s -d \n"), argv[0]); + } + + args.data_dir = argv[++i]; + + argv[i - 1][0] = 0; + argv[i][0] = 0; + + } else if (string(argv[i]) == "-f") { + // Set options file + if (i + 1 >= argc) { + throw BoutException(_("Usage is %s -f \n"), argv[0]); + } + + args.opt_file = argv[++i]; + + argv[i - 1][0] = 0; + argv[i][0] = 0; + + } else if (string(argv[i]) == "-o") { + // Set options file + if (i + 1 >= argc) { + throw BoutException(_("Usage is %s -o \n"), argv[0]); + } + + args.set_file = argv[++i]; + + argv[i - 1][0] = 0; + argv[i][0] = 0; + + } else if ((string(argv[i]) == "-l") || (string(argv[i]) == "--log")) { + if (i + 1 >= argc) { + throw BoutException(_("Usage is %s -l \n"), argv[0]); + } + + args.log_file = argv[++i]; + + argv[i - 1][0] = 0; + argv[i][0] = 0; + + } else if ((string(argv[i]) == "-v") || (string(argv[i]) == "--verbose")) { + args.verbosity++; + + argv[i][0] = 0; + + } else if ((string(argv[i]) == "-q") || (string(argv[i]) == "--quiet")) { + args.verbosity--; + + argv[i][0] = 0; + + } else if ((string(argv[i]) == "-c") || (string(argv[i]) == "--color")) { + // Add color to the output by piping through bout-log-color + // This is done after checking all command-line inputs + // in case -c is set multiple times + args.color_output = true; + + argv[i][0] = 0; + } + } + + if (args.set_file == args.opt_file) { + throw BoutException( + _("Input and output file for settings must be different.\nProvide -o to avoid this issue.\n")); + } + + return args; +} +} // namespace experimental +} // namespace bout + int bout_run(Solver *solver, rhsfunc physics_run) { /// Set the RHS function diff --git a/tests/unit/src/test_bout++.cxx b/tests/unit/src/test_bout++.cxx new file mode 100644 index 0000000000..03867093b2 --- /dev/null +++ b/tests/unit/src/test_bout++.cxx @@ -0,0 +1,118 @@ +#include "gtest/gtest.h" + +#include "bout.hxx" +#include "boutexception.hxx" +#include "utils.hxx" + +#include +#include +#include + +std::vector get_c_string_vector(std::vector& vec_args) { + std::vector c_args{}; + std::transform(begin(vec_args), end(vec_args), std::back_inserter(c_args), + [](std::string& arg) { return &arg.front(); }); + return c_args; +} + +TEST(ParseCommandLineArgs, HelpShortOption) { + std::vector v_args{"test", "-h"}; + auto c_args = get_c_string_vector(v_args); + char** argv = c_args.data(); + + EXPECT_EXIT(bout::experimental::parseCommandLineArgs(c_args.size(), argv), + ::testing::ExitedWithCode(0), ""); +} + +TEST(ParseCommandLineArgs, HelpLongOption) { + std::vector v_args{"test", "--help"}; + auto c_args = get_c_string_vector(v_args); + char** argv = c_args.data(); + + EXPECT_EXIT(bout::experimental::parseCommandLineArgs(c_args.size(), argv), + ::testing::ExitedWithCode(0), ""); +} + +TEST(ParseCommandLineArgs, DataDir) { + std::vector v_args{"test", "-d", "test_data_directory"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_EQ(args.data_dir, "test_data_directory"); + EXPECT_EQ(args.original_argv, v_args); +} + +TEST(ParseCommandLineArgs, DataDirBad) { + std::vector v_args{"test", "-d"}; + auto c_args = get_c_string_vector(v_args); + char** argv = c_args.data(); + + EXPECT_THROW(bout::experimental::parseCommandLineArgs(c_args.size(), argv), + BoutException); +} + +TEST(ParseCommandLineArgs, OptionsFile) { + std::vector v_args{"test", "-f", "test_options_file"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_EQ(args.opt_file, "test_options_file"); + EXPECT_EQ(args.original_argv, v_args); +} + +TEST(ParseCommandLineArgs, OptionsFileBad) { + std::vector v_args{"test", "-f"}; + auto c_args = get_c_string_vector(v_args); + char** argv = c_args.data(); + + EXPECT_THROW(bout::experimental::parseCommandLineArgs(c_args.size(), argv), + BoutException); +} + +TEST(ParseCommandLineArgs, SettingsFile) { + std::vector v_args{"test", "-o", "test_settings_file"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_EQ(args.set_file, "test_settings_file"); + EXPECT_EQ(args.original_argv, v_args); +} + +TEST(ParseCommandLineArgs, SettingsFileBad) { + std::vector v_args{"test", "-o"}; + auto c_args = get_c_string_vector(v_args); + char** argv = c_args.data(); + + EXPECT_THROW(bout::experimental::parseCommandLineArgs(c_args.size(), argv), + BoutException); +} + +TEST(ParseCommandLineArgs, LogFile) { + std::vector v_args{"test", "-l", "test_log_file"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_EQ(args.log_file, "test_log_file"); + EXPECT_EQ(args.original_argv, v_args); +} + +TEST(ParseCommandLineArgs, LogFileBad) { + std::vector v_args{"test", "-l"}; + auto c_args = get_c_string_vector(v_args); + char** argv = c_args.data(); + + EXPECT_THROW(bout::experimental::parseCommandLineArgs(c_args.size(), argv), + BoutException); +} From 59a650c0f210329e32e078091ccac2ba19ad2100 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 11:19:09 +0000 Subject: [PATCH 1128/1783] Use output.write instead of fprintf for help message Allows gtest death test to check usage message is printed --- src/bout++.cxx | 29 +++++++++++++---------------- tests/unit/src/test_bout++.cxx | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 9731486beb..9a095dd50d 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -409,19 +409,16 @@ int BoutInitialise(int &argc, char **&argv) { namespace bout { namespace experimental { auto parseCommandLineArgs(int argc, char** argv) -> CommandLineArgs { - /// Check command-line arguments /// NB: "restart" and "append" are now caught by options /// Check for help flag separately for (int i = 1; i < argc; i++) { if (string(argv[i]) == "-h" || string(argv[i]) == "--help") { // Print help message -- note this will be displayed once per processor as we've not // started MPI yet. - fprintf(stdout, - _("Usage: %s [-d ] [-f ] [restart " - "[append]] [VAR=VALUE]\n"), - argv[0]); - fprintf( - stdout, + output.write(_("Usage: %s [-d ] [-f ] [restart " + "[append]] [VAR=VALUE]\n"), + argv[0]); + output.write( _("\n" " -d \tLook in for input/output files\n" " -f \tUse OPTIONS given in \n" @@ -430,16 +427,16 @@ auto parseCommandLineArgs(int argc, char** argv) -> CommandLineArgs { " -v, --verbose\t\tIncrease verbosity\n" " -q, --quiet\t\tDecrease verbosity\n")); #ifdef LOGCOLOR - fprintf(stdout, _(" -c, --color\t\tColor output using bout-log-color\n")); + output.write(_(" -c, --color\t\tColor output using bout-log-color\n")); #endif - fprintf(stdout, - _(" -h, --help\t\tThis message\n" - " restart [append]\tRestart the simulation. If append is specified, " - "append to the existing output files, otherwise overwrite them\n" - " VAR=VALUE\t\tSpecify a VALUE for input parameter VAR\n" - "\nFor all possible input parameters, see the user manual and/or the " - "physics model source (e.g. %s.cxx)\n"), - argv[0]); + output.write( + _(" -h, --help\t\tThis message\n" + " restart [append]\tRestart the simulation. If append is specified, " + "append to the existing output files, otherwise overwrite them\n" + " VAR=VALUE\t\tSpecify a VALUE for input parameter VAR\n" + "\nFor all possible input parameters, see the user manual and/or the " + "physics model source (e.g. %s.cxx)\n"), + argv[0]); std::exit(EXIT_SUCCESS); } diff --git a/tests/unit/src/test_bout++.cxx b/tests/unit/src/test_bout++.cxx index 03867093b2..a70a00d719 100644 --- a/tests/unit/src/test_bout++.cxx +++ b/tests/unit/src/test_bout++.cxx @@ -5,6 +5,7 @@ #include "utils.hxx" #include +#include #include #include @@ -20,8 +21,13 @@ TEST(ParseCommandLineArgs, HelpShortOption) { auto c_args = get_c_string_vector(v_args); char** argv = c_args.data(); + auto cout_buf = std::cout.rdbuf(); + std::cout.rdbuf(std::cerr.rdbuf()); + EXPECT_EXIT(bout::experimental::parseCommandLineArgs(c_args.size(), argv), - ::testing::ExitedWithCode(0), ""); + ::testing::ExitedWithCode(0), "Usage:"); + + std::cout.rdbuf(cout_buf); } TEST(ParseCommandLineArgs, HelpLongOption) { @@ -29,8 +35,13 @@ TEST(ParseCommandLineArgs, HelpLongOption) { auto c_args = get_c_string_vector(v_args); char** argv = c_args.data(); + auto cout_buf = std::cout.rdbuf(); + std::cout.rdbuf(std::cerr.rdbuf()); + EXPECT_EXIT(bout::experimental::parseCommandLineArgs(c_args.size(), argv), - ::testing::ExitedWithCode(0), ""); + ::testing::ExitedWithCode(0), "Usage:"); + + std::cout.rdbuf(cout_buf); } TEST(ParseCommandLineArgs, DataDir) { From a16f98a66272b7a3cfa15241bf3ddcafd002e4c4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 11:57:26 +0000 Subject: [PATCH 1129/1783] Pull out printing parts of the startup message from BoutInitialise --- include/bout.hxx | 10 +++ src/bout++.cxx | 158 +++++++++++++++++---------------- tests/unit/src/test_bout++.cxx | 51 ++++++++++- 3 files changed, 142 insertions(+), 77 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index 976bf95c50..0da5fdec2a 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -117,6 +117,16 @@ struct CommandLineArgs { /// Parse the "fixed" command line arguments, like --help and -d CommandLineArgs parseCommandLineArgs(int argc, char** argv); + +/// Print the initial header +void printStartupHeader(int MYPE, int NPES); + +/// Print the compile-time options +void printCompileTimeOptions(); + +/// Print the arguments given on the command line +void printCommandLineArguments(const std::vector& original_argv); + } // namespace experimental } // namespace bout diff --git a/src/bout++.cxx b/src/bout++.cxx index 9a095dd50d..1542de6997 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -175,9 +175,8 @@ int BoutInitialise(int &argc, char **&argv) { Solver::setArgs(argc, argv); // Solver initialisation BoutComm::setArgs(argc, argv); // MPI initialisation - int NPES = BoutComm::size(); - int MYPE = BoutComm::rank(); - + const int MYPE = BoutComm::rank(); + #ifdef LOGCOLOR if (args.color_output && (MYPE == 0)) { // Color stdout by piping through bout-log-color script @@ -247,79 +246,11 @@ int BoutInitialise(int &argc, char **&argv) { pid_file.close(); } } - - /// Print intro - output_progress.write(_("BOUT++ version %s\n"), BOUT_VERSION_STRING); -#ifdef REVISION - output_progress.write(_("Revision: %s\n"), BUILDFLAG(REVISION)); -#endif -#ifdef MD5SUM - output_progress.write("MD5 checksum: %s\n", BUILDFLAG(MD5SUM)); -#endif - output_progress.write(_("Code compiled on %s at %s\n\n"), __DATE__, __TIME__); - output_info.write("B.Dudson (University of York), M.Umansky (LLNL) 2007\n"); - output_info.write("Based on BOUT by Xueqiao Xu, 1999\n\n"); - - output_info.write(_("Processor number: %d of %d\n\n"), MYPE, NPES); - - output_info.write("pid: %d\n\n",getpid()); - - /// Print compile-time options - - output_info.write(_("Compile-time options:\n")); - -#if CHECK > 0 - output_info.write(_("\tChecking enabled, level %d\n"), CHECK); -#else - output_info.write(_("\tChecking disabled\n")); -#endif - -#ifdef SIGHANDLE - output_info.write(_("\tSignal handling enabled\n")); -#else - output_info.write(_("\tSignal handling disabled\n")); -#endif - -#ifdef NCDF - output_info.write(_("\tnetCDF support enabled\n")); -#else -#ifdef NCDF4 - output_info.write(_("\tnetCDF4 support enabled\n")); -#else - output_info.write(_("\tnetCDF support disabled\n")); -#endif -#endif -#ifdef PNCDF - output_info.write(_("\tParallel NetCDF support enabled\n")); -#else - output_info.write(_("\tParallel NetCDF support disabled\n")); -#endif - -#ifdef _OPENMP - output_info.write(_("\tOpenMP parallelisation enabled, using %d threads\n"),omp_get_max_threads()); -#else - output_info.write(_("\tOpenMP parallelisation disabled\n")); -#endif - -#ifdef METRIC3D - output_info.write("\tRUNNING IN 3D-METRIC MODE\n"); -#endif - -#ifdef BOUT_FPE - output_info.write("\tFloatingPointExceptions enabled\n"); -#endif - - //The stringify is needed here as BOUT_FLAGS_STRING may already contain quoted strings - //which could cause problems (e.g. terminate strings). - output_info.write(_("\tCompiled with flags : %s\n"),STRINGIFY(BOUT_FLAGS_STRING)); - - // Print command line options - output_info.write(_("\tCommand line options for this run : ")); - for (auto& arg : args.original_argv) { - output_info << arg << " "; - } - output_info.write("\n"); + // Print the different parts of the startup info + bout::experimental::printStartupHeader(MYPE, BoutComm::size()); + bout::experimental::printCompileTimeOptions(); + bout::experimental::printCommandLineArguments(args.original_argv); /// Get the options tree Options *options = Options::getRoot(); @@ -519,6 +450,83 @@ auto parseCommandLineArgs(int argc, char** argv) -> CommandLineArgs { return args; } + +void printStartupHeader(int MYPE, int NPES) { + output_progress.write(_("BOUT++ version %s\n"), BOUT_VERSION_STRING); +#ifdef REVISION + output_progress.write(_("Revision: %s\n"), BUILDFLAG(REVISION)); +#endif +#ifdef MD5SUM + output_progress.write("MD5 checksum: %s\n", BUILDFLAG(MD5SUM)); +#endif + output_progress.write(_("Code compiled on %s at %s\n\n"), __DATE__, __TIME__); + output_info.write("B.Dudson (University of York), M.Umansky (LLNL) 2007\n"); + output_info.write("Based on BOUT by Xueqiao Xu, 1999\n\n"); + + output_info.write(_("Processor number: %d of %d\n\n"), MYPE, NPES); + + output_info.write("pid: %d\n\n", getpid()); +} + +void printCompileTimeOptions() { + output_info.write(_("Compile-time options:\n")); + +#if CHECK > 0 + output_info.write(_("\tChecking enabled, level %d\n"), CHECK); +#else + output_info.write(_("\tChecking disabled\n")); +#endif + +#ifdef SIGHANDLE + output_info.write(_("\tSignal handling enabled\n")); +#else + output_info.write(_("\tSignal handling disabled\n")); +#endif + +#ifdef NCDF + output_info.write(_("\tnetCDF support enabled\n")); +#else +#ifdef NCDF4 + output_info.write(_("\tnetCDF4 support enabled\n")); +#else + output_info.write(_("\tnetCDF support disabled\n")); +#endif +#endif + +#ifdef PNCDF + output_info.write(_("\tParallel NetCDF support enabled\n")); +#else + output_info.write(_("\tParallel NetCDF support disabled\n")); +#endif + +#ifdef _OPENMP + output_info.write(_("\tOpenMP parallelisation enabled, using %d threads\n"), + omp_get_max_threads()); +#else + output_info.write(_("\tOpenMP parallelisation disabled\n")); +#endif + +#ifdef METRIC3D + output_info.write("\tRUNNING IN 3D-METRIC MODE\n"); +#endif + +#ifdef BOUT_FPE + output_info.write("\tFloatingPointExceptions enabled\n"); +#endif + + // The stringify is needed here as BOUT_FLAGS_STRING may already contain quoted strings + // which could cause problems (e.g. terminate strings). + output_info.write(_("\tCompiled with flags : %s\n"), STRINGIFY(BOUT_FLAGS_STRING)); +} + +void printCommandLineArguments(const std::vector& original_argv) { + output_info.write(_("\tCommand line options for this run : ")); + for (auto& arg : original_argv) { + output_info << arg << " "; + } + output_info.write("\n"); +} + } // namespace experimental } // namespace bout diff --git a/tests/unit/src/test_bout++.cxx b/tests/unit/src/test_bout++.cxx index a70a00d719..96379ed824 100644 --- a/tests/unit/src/test_bout++.cxx +++ b/tests/unit/src/test_bout++.cxx @@ -2,6 +2,7 @@ #include "bout.hxx" #include "boutexception.hxx" +#include "test_extras.hxx" #include "utils.hxx" #include @@ -25,7 +26,7 @@ TEST(ParseCommandLineArgs, HelpShortOption) { std::cout.rdbuf(std::cerr.rdbuf()); EXPECT_EXIT(bout::experimental::parseCommandLineArgs(c_args.size(), argv), - ::testing::ExitedWithCode(0), "Usage:"); + ::testing::ExitedWithCode(0), _("Usage:")); std::cout.rdbuf(cout_buf); } @@ -39,7 +40,7 @@ TEST(ParseCommandLineArgs, HelpLongOption) { std::cout.rdbuf(std::cerr.rdbuf()); EXPECT_EXIT(bout::experimental::parseCommandLineArgs(c_args.size(), argv), - ::testing::ExitedWithCode(0), "Usage:"); + ::testing::ExitedWithCode(0), _("Usage:")); std::cout.rdbuf(cout_buf); } @@ -127,3 +128,49 @@ TEST(ParseCommandLineArgs, LogFileBad) { EXPECT_THROW(bout::experimental::parseCommandLineArgs(c_args.size(), argv), BoutException); } + +class PrintStartupTest : public ::testing::Test { +public: + PrintStartupTest() : sbuf(std::cout.rdbuf()) { + // Redirect cout to our stringstream buffer or any other ostream + std::cout.rdbuf(buffer.rdbuf()); + } + + virtual ~PrintStartupTest() { + // Clear buffer + buffer.str(""); + // When done redirect cout to its old self + std::cout.rdbuf(sbuf); + } + + // Write cout to buffer instead of stdout + std::stringstream buffer; + // Save cout's buffer here + std::streambuf* sbuf; +}; + +TEST_F(PrintStartupTest, Header) { + bout::experimental::printStartupHeader(4, 8); + + EXPECT_TRUE(IsSubString(buffer.str(), BOUT_VERSION_STRING)); + EXPECT_TRUE(IsSubString(buffer.str(), _("4 of 8"))); +} + +TEST_F(PrintStartupTest, CompileTimeOptions) { + bout::experimental::printCompileTimeOptions(); + + EXPECT_TRUE(IsSubString(buffer.str(), _("Compile-time options:\n"))); + EXPECT_TRUE(IsSubString(buffer.str(), _("Signal"))); + EXPECT_TRUE(IsSubString(buffer.str(), "netCDF")); + EXPECT_TRUE(IsSubString(buffer.str(), "OpenMP")); + EXPECT_TRUE(IsSubString(buffer.str(), _("Compiled with flags"))); +} + +TEST_F(PrintStartupTest, CommandLineArguments) { + std::vector args{"-d", "test1", "test2", "test3"}; + bout::experimental::printCommandLineArguments(args); + + for (auto& arg : args) { + EXPECT_TRUE(IsSubString(buffer.str(), arg)); + } +} From 4238a7ca9757d2d05a7c59e101d3963aed5d013b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 12:04:11 +0000 Subject: [PATCH 1130/1783] Pull out setting up bout-log-color pipe from BoutInitialise --- include/bout.hxx | 3 ++ src/bout++.cxx | 74 ++++++++++++++++++++++++++---------------------- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index 0da5fdec2a..8511b66e8c 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -127,6 +127,9 @@ void printCompileTimeOptions(); /// Print the arguments given on the command line void printCommandLineArguments(const std::vector& original_argv); +/// Setup the pipe etc and run stdout through bout-log-color. Return +/// true if it was successful +bool setupBoutLogColor(bool color_output, int MYPE); } // namespace experimental } // namespace bout diff --git a/src/bout++.cxx b/src/bout++.cxx index 1542de6997..afe1309e3b 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -177,40 +177,7 @@ int BoutInitialise(int &argc, char **&argv) { const int MYPE = BoutComm::rank(); -#ifdef LOGCOLOR - if (args.color_output && (MYPE == 0)) { - // Color stdout by piping through bout-log-color script - // Only done on processor 0, since this is the only processor which writes to stdout - // This uses popen, fileno and dup2 functions, which are POSIX - bool success = false; - - // Run bout-log-color through the shell. This should share stdout with BOUT++, - // and read stdin from the pipe - FILE *outpipe = popen("bout-log-color", "w"); - - if (outpipe != nullptr) { - // Valid pipe - // Get the integer file descriptor - int fno = fileno(outpipe); - if (fno != -1) { - // Valid file descriptor - - // Note: We can get to here if bout-log-color failed to run - // This seems to cause code to fail later - - // Replace stdout with the pipe. - int status = dup2(fno, STDOUT_FILENO); - if (status != -1) { - success = true; - } - } - } - if (!success) { - // Failed . Probably not important enough to stop the simulation - fprintf(stderr, _("Could not run bout-log-color. Make sure it is in your PATH\n")); - } - } -#endif // LOGCOLOR + bout::experimental::setupBoutLogColor(args.color_output, MYPE); /// Set up the output, accessing underlying Output object { @@ -527,6 +494,45 @@ void printCommandLineArguments(const std::vector& original_argv) { output_info.write("\n"); } +bool setupBoutLogColor(bool color_output, int MYPE) { +#ifdef LOGCOLOR + if (args.color_output && (MYPE == 0)) { + // Color stdout by piping through bout-log-color script + // Only done on processor 0, since this is the only processor which writes to stdout + // This uses popen, fileno and dup2 functions, which are POSIX + bool success = false; + + // Run bout-log-color through the shell. This should share stdout with BOUT++, + // and read stdin from the pipe + FILE* outpipe = popen("bout-log-color", "w"); + + if (outpipe != nullptr) { + // Valid pipe + // Get the integer file descriptor + int fno = fileno(outpipe); + if (fno != -1) { + // Valid file descriptor + + // Note: We can get to here if bout-log-color failed to run + // This seems to cause code to fail later + + // Replace stdout with the pipe. + int status = dup2(fno, STDOUT_FILENO); + if (status != -1) { + success = true; + } + } + } + if (!success) { + // Failed . Probably not important enough to stop the simulation + fprintf(stderr, _("Could not run bout-log-color. Make sure it is in your PATH\n")); + } + return success; + } +#endif // LOGCOLOR + return false; +} + } // namespace experimental } // namespace bout From 12eb9fb0f1c2138f1e2697dc7433bb355b6a7ae7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 12:04:47 +0000 Subject: [PATCH 1131/1783] Use std::cerr rather than fprintf(stderr) --- src/bout++.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index afe1309e3b..6cf62e7fb9 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -525,7 +525,7 @@ bool setupBoutLogColor(bool color_output, int MYPE) { } if (!success) { // Failed . Probably not important enough to stop the simulation - fprintf(stderr, _("Could not run bout-log-color. Make sure it is in your PATH\n")); + std::cerr << _("Could not run bout-log-color. Make sure it is in your PATH\n"); } return success; } From 5db15f7472b6721c21369d56cf37202cbc37b438 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 12:08:40 +0000 Subject: [PATCH 1132/1783] Fix bug in printCommandLineArguments --- src/bout++.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 6cf62e7fb9..6eb252863f 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -496,7 +496,7 @@ void printCommandLineArguments(const std::vector& original_argv) { bool setupBoutLogColor(bool color_output, int MYPE) { #ifdef LOGCOLOR - if (args.color_output && (MYPE == 0)) { + if (color_output && (MYPE == 0)) { // Color stdout by piping through bout-log-color script // Only done on processor 0, since this is the only processor which writes to stdout // This uses popen, fileno and dup2 functions, which are POSIX From dc3d262745c448b3e6dedb0285c5fc4057e5337d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 12:14:12 +0000 Subject: [PATCH 1133/1783] Pull setting signal handler out from BoutInitialise --- include/bout.hxx | 6 ++++++ src/bout++.cxx | 25 ++++++++++++++----------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index 8511b66e8c..4145bcbc14 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -103,6 +103,12 @@ int BoutInitialise(int &argc, char **&argv); namespace bout { namespace experimental { +/// Function type for handling signals +using SignalHandler = void(*)(int); + +/// Set a signal handler for segmentation faults +void setupSignalHandler(SignalHandler signal_handler); + /// Results of parsing the command line arguments struct CommandLineArgs { int verbosity{4}; diff --git a/src/bout++.cxx b/src/bout++.cxx index 6eb252863f..14b26dc5de 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -112,17 +112,7 @@ int BoutInitialise(int &argc, char **&argv) { string dump_ext; ///< Extensions for restart and dump files -#ifdef SIGHANDLE - /// Set a signal handler for segmentation faults - signal(SIGSEGV, bout_signal_handler); -#endif -#ifdef BOUT_FPE - signal(SIGFPE, bout_signal_handler); - feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); -#endif - - /// Trap SIGUSR1 to allow a clean exit after next write - signal(SIGUSR1, bout_signal_handler); + bout::experimental::setupSignalHandler(bout_signal_handler); #if BOUT_HAS_GETTEXT // Setting the i18n environment @@ -306,6 +296,19 @@ int BoutInitialise(int &argc, char **&argv) { namespace bout { namespace experimental { +void setupSignalHandler(SignalHandler signal_handler) { +#ifdef SIGHANDLE + std::signal(SIGSEGV, signal_handler); +#endif +#ifdef BOUT_FPE + std::signal(SIGFPE, signal_handler); + feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); +#endif + + /// Trap SIGUSR1 to allow a clean exit after next write + std::signal(SIGUSR1, signal_handler); +} + auto parseCommandLineArgs(int argc, char** argv) -> CommandLineArgs { /// NB: "restart" and "append" are now caught by options /// Check for help flag separately From 83ca20b78182d99c65f7ad95f04ec800776aca6a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 13:06:46 +0000 Subject: [PATCH 1134/1783] Add test for signal handler, expose alias for bout_signal_handler --- include/bout.hxx | 10 +++++++++- src/bout++.cxx | 5 +++++ tests/unit/src/test_bout++.cxx | 19 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/bout.hxx b/include/bout.hxx index 4145bcbc14..a7efee7936 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -106,9 +106,17 @@ namespace experimental { /// Function type for handling signals using SignalHandler = void(*)(int); -/// Set a signal handler for segmentation faults +/// Set a signal handler for user-requested clean exit, and +/// (optionally) segmentation faults and floating point errors +/// +/// - For segmentation faults, compile with `--enable-signal`. +/// - For floating point errors, compile with `--enable-sigfpe` void setupSignalHandler(SignalHandler signal_handler); +/// The default BOUT++ signal handler: throw an exception with an +/// appropriate message +void defaultSignalHandler(int sig); + /// Results of parsing the command line arguments struct CommandLineArgs { int verbosity{4}; diff --git a/src/bout++.cxx b/src/bout++.cxx index 14b26dc5de..54a3e0e658 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -309,6 +309,11 @@ void setupSignalHandler(SignalHandler signal_handler) { std::signal(SIGUSR1, signal_handler); } +// This is currently just an alias to the existing handler +void defaultSignalHandler(int sig) { + bout_signal_handler(sig); +} + auto parseCommandLineArgs(int argc, char** argv) -> CommandLineArgs { /// NB: "restart" and "append" are now caught by options /// Check for help flag separately diff --git a/tests/unit/src/test_bout++.cxx b/tests/unit/src/test_bout++.cxx index 96379ed824..cf8d7e334e 100644 --- a/tests/unit/src/test_bout++.cxx +++ b/tests/unit/src/test_bout++.cxx @@ -6,6 +6,7 @@ #include "utils.hxx" #include +#include #include #include #include @@ -174,3 +175,21 @@ TEST_F(PrintStartupTest, CommandLineArguments) { EXPECT_TRUE(IsSubString(buffer.str(), arg)); } } + +#ifdef SIGHANDLE +class SignalHandlerTest : public ::testing::Test { +public: + SignalHandlerTest() = default; + virtual ~SignalHandlerTest() { + std::signal(SIGUSR1, SIG_DFL); + std::signal(SIGFPE, SIG_DFL); + std::signal(SIGSEGV, SIG_DFL); + } +}; + +TEST_F(SignalHandlerTest, SegFault) { + bout::experimental::setupSignalHandler(bout::experimental::defaultSignalHandler); + // This test is *incredibly* expensive, maybe as much as 1s, so only test the one signal + EXPECT_DEATH(std::raise(SIGSEGV), "SEGMENTATION FAULT"); +} +#endif From 5bd9a6da3def64d05b7b4a1493ed10fd7e01ee04 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 13:07:08 +0000 Subject: [PATCH 1135/1783] Use BoutComm::rank rather than MPI_Comm_rank in bout_signal_handler Also clang-format --- src/bout++.cxx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 54a3e0e658..55873f0b4f 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -739,15 +739,13 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { /// Signal handler - handles all signals void bout_signal_handler(int sig) { - /// Set signal handler back to default to prevent possible infinite loop + // Set signal handler back to default to prevent possible infinite loop signal(SIGSEGV, SIG_DFL); // print number of process to stderr, so the user knows which log to check - int world_rank; - MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); - fprintf(stderr,"\nSighandler called on process %d with sig %d\n" - ,world_rank,sig); + fprintf(stderr, "\nSighandler called on process %d with sig %d\n", BoutComm::rank(), + sig); - switch (sig){ + switch (sig) { case SIGSEGV: throw BoutException("\n****** SEGMENTATION FAULT CAUGHT ******\n\n"); break; @@ -762,10 +760,10 @@ void bout_signal_handler(int sig) { throw BoutException("\n****** SigKill caught ******\n\n"); break; case SIGUSR1: - user_requested_exit=true; + user_requested_exit = true; break; default: - throw BoutException("\n****** Signal %d caught ******\n\n",sig); + throw BoutException("\n****** Signal %d caught ******\n\n", sig); break; } } From a2c7bf3177e325d64b5a47b0d07c1b7235768c2e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 13:12:19 +0000 Subject: [PATCH 1136/1783] Pull i18n setup out of BoutInitialise --- include/bout.hxx | 3 +++ src/bout++.cxx | 52 ++++++++++++++++++++++++++---------------------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index a7efee7936..417b857210 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -117,6 +117,9 @@ void setupSignalHandler(SignalHandler signal_handler); /// appropriate message void defaultSignalHandler(int sig); +/// Set up the i18n environment +void setupGetText(); + /// Results of parsing the command line arguments struct CommandLineArgs { int verbosity{4}; diff --git a/src/bout++.cxx b/src/bout++.cxx index 55873f0b4f..cc853e6e42 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -114,30 +114,8 @@ int BoutInitialise(int &argc, char **&argv) { bout::experimental::setupSignalHandler(bout_signal_handler); -#if BOUT_HAS_GETTEXT - // Setting the i18n environment - // - // For libraries: - // https://www.gnu.org/software/gettext/manual/html_node/Libraries.html - // - try { - // Note: Would like to use std::locale::global - // std::locale::global(std::locale("")); - // but the Numeric aspect causes problems parsing input strings - // - // Note: Since BOUT++ is a library, it shouldn't really call setlocale; - // that should be part of main(). - std::setlocale(LC_ALL, ""); - std::setlocale(LC_NUMERIC, "C"); - - bindtextdomain (GETTEXT_PACKAGE, BUILDFLAG(BOUT_LOCALE_PATH)); - - fprintf(stderr, "LOCALE_PATH = '%s'\n", BUILDFLAG(BOUT_LOCALE_PATH)); - } catch (const std::runtime_error &e) { - fprintf(stderr, "WARNING: Could not set locale. Try a different LANG setting\n"); - } -#endif // BOUT_HAS_GETTEXT - + bout::experimental::setupGetText(); + bout::experimental::CommandLineArgs args; try { args = bout::experimental::parseCommandLineArgs(argc, argv); @@ -314,6 +292,32 @@ void defaultSignalHandler(int sig) { bout_signal_handler(sig); } +void setupGetText() { +#if BOUT_HAS_GETTEXT + // Setting the i18n environment + // + // For libraries: + // https://www.gnu.org/software/gettext/manual/html_node/Libraries.html + // + try { + // Note: Would like to use std::locale::global + // std::locale::global(std::locale("")); + // but the Numeric aspect causes problems parsing input strings + // + // Note: Since BOUT++ is a library, it shouldn't really call setlocale; + // that should be part of main(). + std::setlocale(LC_ALL, ""); + std::setlocale(LC_NUMERIC, "C"); + + bindtextdomain(GETTEXT_PACKAGE, BUILDFLAG(BOUT_LOCALE_PATH)); + + fprintf(stderr, "LOCALE_PATH = '%s'\n", BUILDFLAG(BOUT_LOCALE_PATH)); + } catch (const std::runtime_error& e) { + fprintf(stderr, "WARNING: Could not set locale. Try a different LANG setting\n"); + } +#endif // BOUT_HAS_GETTEXT +} + auto parseCommandLineArgs(int argc, char** argv) -> CommandLineArgs { /// NB: "restart" and "append" are now caught by options /// Check for help flag separately From a350acddbe3aeb749c3017f68737c59121b969c3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 13:34:43 +0000 Subject: [PATCH 1137/1783] Pull out check for data_dir accessibility from BoutInitialise --- include/bout.hxx | 5 +++++ src/bout++.cxx | 24 +++++++++++++----------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index 417b857210..2d57fe2c02 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -135,6 +135,11 @@ struct CommandLineArgs { /// Parse the "fixed" command line arguments, like --help and -d CommandLineArgs parseCommandLineArgs(int argc, char** argv); +/// Throw an exception if \p data_dir is either not a directory or not +/// accessible. We do not check whether we can write, as it is +/// sufficient that the files we need are writeable +void checkDataDirectoryIsAccessible(const std::string& data_dir); + /// Print the initial header void printStartupHeader(int MYPE, int NPES); diff --git a/src/bout++.cxx b/src/bout++.cxx index cc853e6e42..00adbce1c9 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -125,17 +125,7 @@ int BoutInitialise(int &argc, char **&argv) { return 1; } - // Check that data_dir exists. We do not check whether we can write, as it is - // sufficient that the files we need are writeable ... - struct stat test; - if (stat(args.data_dir.c_str(), &test) == 0) { - if (!S_ISDIR(test.st_mode)) { - throw BoutException(_("DataDir \"%s\" is not a directory\n"), args.data_dir.c_str()); - } - } else { - throw BoutException(_("DataDir \"%s\" does not exist or is not accessible\n"), - args.data_dir.c_str()); - } + bout::experimental::checkDataDirectoryIsAccessible(args.data_dir); // Set the command-line arguments SlepcLib::setArgs(argc, argv); // SLEPc initialisation @@ -430,6 +420,18 @@ auto parseCommandLineArgs(int argc, char** argv) -> CommandLineArgs { return args; } +void checkDataDirectoryIsAccessible(const std::string& data_dir) { + struct stat test; + if (stat(data_dir.c_str(), &test) == 0) { + if (!S_ISDIR(test.st_mode)) { + throw BoutException(_("DataDir \"%s\" is not a directory\n"), data_dir.c_str()); + } + } else { + throw BoutException(_("DataDir \"%s\" does not exist or is not accessible\n"), + data_dir.c_str()); + } +} + void printStartupHeader(int MYPE, int NPES) { output_progress.write(_("BOUT++ version %s\n"), BOUT_VERSION_STRING); #ifdef REVISION From 443b1d4a58a7474f0a1d79ce7ec421bd7ceaa8b3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 13:35:04 +0000 Subject: [PATCH 1138/1783] Pull out setting up output from BoutInitialise --- include/bout.hxx | 6 ++++++ src/bout++.cxx | 52 ++++++++++++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index 2d57fe2c02..baf613feec 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -140,6 +140,12 @@ CommandLineArgs parseCommandLineArgs(int argc, char** argv); /// sufficient that the files we need are writeable void checkDataDirectoryIsAccessible(const std::string& data_dir); +/// Set up the output: open the log file for each processor, enable or +/// disable the default outputs based on \p verbosity, disable writing +/// to stdout for \p MYPE != 0 +void setupOutput(const std::string& data_dir, const std::string& log_file, int verbosity, + int MYPE = 0); + /// Print the initial header void printStartupHeader(int MYPE, int NPES); diff --git a/src/bout++.cxx b/src/bout++.cxx index 00adbce1c9..8145faa4ba 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -137,28 +137,7 @@ int BoutInitialise(int &argc, char **&argv) { bout::experimental::setupBoutLogColor(args.color_output, MYPE); - /// Set up the output, accessing underlying Output object - { - Output &output = *Output::getInstance(); - if (MYPE == 0) output.enable(); // Enable writing to stdout - else output.disable(); // No writing to stdout - - /// Open an output file to echo everything to - /// On processor 0 anything written to output will go to stdout and the file - if (output.open("%s/%s.%d", args.data_dir.c_str(), args.log_file.c_str(), MYPE)) { - return 1; - } - } - - output_error.enable(args.verbosity > 0); - output_warn.enable(args.verbosity > 1); - output_progress.enable(args.verbosity > 2); - output_info.enable(args.verbosity > 3); - output_verbose.enable(args.verbosity > 4); - output_debug.enable(args.verbosity > 5); // Only actually enabled if also compiled with DEBUG - - // The backward-compatible output object same as output_progress - output.enable(args.verbosity>2); + bout::experimental::setupOutput(args.data_dir, args.log_file, args.verbosity, MYPE); // Save the PID of this process to file, so it can be shut down by user signal { @@ -547,6 +526,35 @@ bool setupBoutLogColor(bool color_output, int MYPE) { return false; } +void setupOutput(const std::string& data_dir, const std::string& log_file, int verbosity, + int MYPE) { + { + Output& output = *Output::getInstance(); + if (MYPE == 0) { + output.enable(); // Enable writing to stdout + } else { + output.disable(); // No writing to stdout + } + /// Open an output file to echo everything to + /// On processor 0 anything written to output will go to stdout and the file + if (output.open("%s/%s.%d", data_dir.c_str(), log_file.c_str(), MYPE)) { + throw BoutException(_("Could not open %s/%s.%d for writing"), data_dir.c_str(), + log_file.c_str(), MYPE); + } + } + + output_error.enable(verbosity > 0); + output_warn.enable(verbosity > 1); + output_progress.enable(verbosity > 2); + output_info.enable(verbosity > 3); + output_verbose.enable(verbosity > 4); + // Only actually enabled if also compiled with DEBUG + output_debug.enable(verbosity > 5); + + // The backward-compatible output object same as output_progress + output.enable(verbosity > 2); +} + } // namespace experimental } // namespace bout From 706de6b921004e2570555b2fbde9e937c5aa7037 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 13:52:50 +0000 Subject: [PATCH 1139/1783] Pull out saving PID to file from BoutInitialise --- include/bout.hxx | 4 ++++ src/bout++.cxx | 23 +++++++++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index baf613feec..c3230ea180 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -146,6 +146,10 @@ void checkDataDirectoryIsAccessible(const std::string& data_dir); void setupOutput(const std::string& data_dir, const std::string& log_file, int verbosity, int MYPE = 0); +/// Save the process ID for processor N = \p MYPE to file BOUT.pid.N +/// in \p data_dir, so it can be shut down by user signal +void savePIDtoFile(const std::string& data_dir, int MYPE); + /// Print the initial header void printStartupHeader(int MYPE, int NPES); diff --git a/src/bout++.cxx b/src/bout++.cxx index 8145faa4ba..e35bc84ca9 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -139,18 +139,10 @@ int BoutInitialise(int &argc, char **&argv) { bout::experimental::setupOutput(args.data_dir, args.log_file, args.verbosity, MYPE); - // Save the PID of this process to file, so it can be shut down by user signal - { - std::string filename; - std::stringstream(filename) << args.data_dir << "/.BOUT.pid." << MYPE; - std::ofstream pid_file; - pid_file.open(filename, std::ios::out); - if (pid_file.is_open()) { - pid_file << getpid() << "\n"; - pid_file.close(); - } } + bout::experimental::savePIDtoFile(args.data_dir, MYPE); + // Print the different parts of the startup info bout::experimental::printStartupHeader(MYPE, BoutComm::size()); bout::experimental::printCompileTimeOptions(); @@ -411,6 +403,17 @@ void checkDataDirectoryIsAccessible(const std::string& data_dir) { } } +void savePIDtoFile(const std::string& data_dir, int MYPE) { + std::string filename; + std::stringstream(filename) << data_dir << "/.BOUT.pid." << MYPE; + std::ofstream pid_file; + pid_file.open(filename, std::ios::out); + if (pid_file.is_open()) { + pid_file << getpid() << "\n"; + pid_file.close(); + } +} + void printStartupHeader(int MYPE, int NPES) { output_progress.write(_("BOUT++ version %s\n"), BOUT_VERSION_STRING); #ifdef REVISION From 8ebd237134978660021718345f5ee02a10f127cf Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 13:53:19 +0000 Subject: [PATCH 1140/1783] Wrap a couple of the new init functions in try/catch --- src/bout++.cxx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index e35bc84ca9..0d333d44e3 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -125,7 +125,13 @@ int BoutInitialise(int &argc, char **&argv) { return 1; } - bout::experimental::checkDataDirectoryIsAccessible(args.data_dir); + try { + bout::experimental::checkDataDirectoryIsAccessible(args.data_dir); + } catch (BoutException& e) { + output << _("Error encountered during initialisation\n"); + output << e.what() << endl; + return 1; + } // Set the command-line arguments SlepcLib::setArgs(argc, argv); // SLEPc initialisation @@ -136,9 +142,13 @@ int BoutInitialise(int &argc, char **&argv) { const int MYPE = BoutComm::rank(); bout::experimental::setupBoutLogColor(args.color_output, MYPE); - - bout::experimental::setupOutput(args.data_dir, args.log_file, args.verbosity, MYPE); + try { + bout::experimental::setupOutput(args.data_dir, args.log_file, args.verbosity, MYPE); + } catch (BoutException& e) { + output << _("Error encountered during initialisation\n"); + output << e.what() << endl; + return 1; } bout::experimental::savePIDtoFile(args.data_dir, MYPE); From b4642b038b494aa8edd8aa56a49f2ed83f5d2660 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 13:58:23 +0000 Subject: [PATCH 1141/1783] Pull out small setRunInfo function from BoutInitialise --- include/bout.hxx | 5 +++++ src/bout++.cxx | 27 +++++++++++++++------------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index c3230ea180..625da7d3f2 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -162,6 +162,11 @@ void printCommandLineArguments(const std::vector& original_argv); /// Setup the pipe etc and run stdout through bout-log-color. Return /// true if it was successful bool setupBoutLogColor(bool color_output, int MYPE); + +/// Set BOUT++ version information, along with current time, into +/// `run` section of \p options. This is mainly so it can be easily +/// read in post-processing +void setRunInfo(Options& options); } // namespace experimental } // namespace bout diff --git a/src/bout++.cxx b/src/bout++.cxx index 0d333d44e3..1ff2edf6d2 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -174,18 +174,8 @@ int BoutInitialise(int &argc, char **&argv) { Options::root()["optionfile"].force(args.opt_file); Options::root()["settingsfile"].force(args.set_file); - // Put some run information in the options. - // This is mainly so it can be easily read in post-processing - auto &runinfo = Options::root()["run"]; - - // Note: have to force value, since may already be set if a previously - // output BOUT.settings file was used as input - runinfo["version"].force(BOUT_VERSION_STRING, ""); - runinfo["revision"].force(BUILDFLAG(REVISION), ""); - - time_t start_time = time(nullptr); - runinfo["started"].force(ctime(&start_time), ""); - + bout::experimental::setRunInfo(Options::root()); + // Save settings if (BoutComm::rank() == 0) { reader->write(options, "%s/%s", args.data_dir.c_str(), args.set_file.c_str()); @@ -568,6 +558,19 @@ void setupOutput(const std::string& data_dir, const std::string& log_file, int v output.enable(verbosity > 2); } +void setRunInfo(Options& options) { + // Put some run information in the options. + auto& runinfo = options["run"]; + + // Note: have to force value, since may already be set if a previously + // output BOUT.settings file was used as input + runinfo["version"].force(BOUT_VERSION_STRING, ""); + runinfo["revision"].force(BUILDFLAG(REVISION), ""); + + time_t start_time = time(nullptr); + runinfo["started"].force(ctime(&start_time), ""); +} + } // namespace experimental } // namespace bout From f2a0a818664c3c57804e01030c65ac118be25060 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 14:14:07 +0000 Subject: [PATCH 1142/1783] Pull out set up of dump file from BoutInitialise --- include/bout.hxx | 4 +++ src/bout++.cxx | 63 ++++++++++++++++++++++++------------------------ 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index 625da7d3f2..ed9e91407c 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -167,6 +167,10 @@ bool setupBoutLogColor(bool color_output, int MYPE); /// `run` section of \p options. This is mainly so it can be easily /// read in post-processing void setRunInfo(Options& options); + +/// Setup the output dump files from \p options using the \p +/// mesh. Files are created in the \p data_dir directory +Datafile setupDumpFile(Options& options, Mesh& mesh, const std::string& data_dir); } // namespace experimental } // namespace bout diff --git a/src/bout++.cxx b/src/bout++.cxx index 1ff2edf6d2..d66cc968c9 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -110,8 +110,6 @@ char get_spin(); // Produces a spinning bar */ int BoutInitialise(int &argc, char **&argv) { - string dump_ext; ///< Extensions for restart and dump files - bout::experimental::setupSignalHandler(bout_signal_handler); bout::experimental::setupGetText(); @@ -192,39 +190,11 @@ int BoutInitialise(int &argc, char **&argv) { bout::globals::mesh = Mesh::create(); ///< Create the mesh bout::globals::mesh->load(); ///< Load from sources. Required for Field initialisation bout::globals::mesh->setParallelTransform(); ///< Set the parallel transform from options - ///////////////////////////////////////////// - /// Get some settings - - // Check if restarting - bool append; - OPTION(options, append, false); - /// Get file extensions - options->get("dump_format", dump_ext, "nc"); - - //////////////////////////////////////////// - // Set up the "dump" data output file - output << "Setting up output (dump) file\n"; + bout::globals::dump = bout::experimental::setupDumpFile( + Options::root(), *bout::globals::mesh, args.data_dir); - bout::globals::dump = Datafile(options->getSection("output"), bout::globals::mesh); - - /// Open a file for the output - if(append) { - bout::globals::dump.opena("%s/BOUT.dmp.%s", args.data_dir.c_str(), dump_ext.c_str()); - }else { - bout::globals::dump.openw("%s/BOUT.dmp.%s", args.data_dir.c_str(), dump_ext.c_str()); - } - - /// Add book-keeping variables to the output files - bout::globals::dump.add(const_cast(BOUT_VERSION), "BOUT_VERSION", false); - bout::globals::dump.add(simtime, "t_array", true); // Appends the time of dumps into an array - bout::globals::dump.add(iteration, "iteration", false); - - //////////////////////////////////////////// - - bout::globals::mesh->outputVars(bout::globals::dump); ///< Save mesh configuration into output file - }catch(BoutException &e) { output_error.write(_("Error encountered during initialisation: %s\n"), e.what()); throw; @@ -571,6 +541,35 @@ void setRunInfo(Options& options) { runinfo["started"].force(ctime(&start_time), ""); } +Datafile setupDumpFile(Options& options, Mesh& mesh, const std::string& data_dir) { + // Check if restarting + const bool append = options["append"].withDefault(false); + + // Get file extensions + const auto dump_ext = options["dump_format"].withDefault(std::string{"nc"}); + + output_progress << "Setting up output (dump) file\n"; + + auto dump_file = Datafile(&(options["output"]), &mesh); + + if (append) { + dump_file.opena("%s/BOUT.dmp.%s", data_dir.c_str(), dump_ext.c_str()); + } else { + dump_file.openw("%s/BOUT.dmp.%s", data_dir.c_str(), dump_ext.c_str()); + } + + // Add book-keeping variables to the output files + dump_file.add(const_cast(BOUT_VERSION), "BOUT_VERSION", false); + // Appends the time of dumps into an array + dump_file.add(simtime, "t_array", true); + dump_file.add(iteration, "iteration", false); + + // Save mesh configuration into output file + mesh.outputVars(dump_file); + + return dump_file; +} + } // namespace experimental } // namespace bout From 7c57515ee0fecd3fe03ff4e54a7d356b2b73560c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 14:28:04 +0000 Subject: [PATCH 1143/1783] Wrap most of BoutInitialise in the same try/catch block Consistent handling of errors -- but do we want to rethrow or just return 1? --- src/bout++.cxx | 78 +++++++++++++++++++------------------------------- 1 file changed, 29 insertions(+), 49 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index d66cc968c9..83a5921618 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -108,7 +108,7 @@ char get_spin(); // Produces a spinning bar value of BoutInitialise. */ -int BoutInitialise(int &argc, char **&argv) { +int BoutInitialise(int& argc, char**& argv) { bout::experimental::setupSignalHandler(bout_signal_handler); @@ -118,54 +118,39 @@ int BoutInitialise(int &argc, char **&argv) { try { args = bout::experimental::parseCommandLineArgs(argc, argv); } catch (BoutException& e) { - output_error << _("Bad command line arguments\n"); - output_error << e.what() << endl; + output_error << _("Bad command line arguments:\n") << e.what() << std::endl; return 1; } try { bout::experimental::checkDataDirectoryIsAccessible(args.data_dir); - } catch (BoutException& e) { - output << _("Error encountered during initialisation\n"); - output << e.what() << endl; - return 1; - } - // Set the command-line arguments - SlepcLib::setArgs(argc, argv); // SLEPc initialisation - PetscLib::setArgs(argc, argv); // PETSc initialisation - Solver::setArgs(argc, argv); // Solver initialisation - BoutComm::setArgs(argc, argv); // MPI initialisation + // Set the command-line arguments + SlepcLib::setArgs(argc, argv); // SLEPc initialisation + PetscLib::setArgs(argc, argv); // PETSc initialisation + Solver::setArgs(argc, argv); // Solver initialisation + BoutComm::setArgs(argc, argv); // MPI initialisation - const int MYPE = BoutComm::rank(); + const int MYPE = BoutComm::rank(); - bout::experimental::setupBoutLogColor(args.color_output, MYPE); + bout::experimental::setupBoutLogColor(args.color_output, MYPE); - try { bout::experimental::setupOutput(args.data_dir, args.log_file, args.verbosity, MYPE); - } catch (BoutException& e) { - output << _("Error encountered during initialisation\n"); - output << e.what() << endl; - return 1; - } - - bout::experimental::savePIDtoFile(args.data_dir, MYPE); - // Print the different parts of the startup info - bout::experimental::printStartupHeader(MYPE, BoutComm::size()); - bout::experimental::printCompileTimeOptions(); - bout::experimental::printCommandLineArguments(args.original_argv); + bout::experimental::savePIDtoFile(args.data_dir, MYPE); - /// Get the options tree - Options *options = Options::getRoot(); + // Print the different parts of the startup info + bout::experimental::printStartupHeader(MYPE, BoutComm::size()); + bout::experimental::printCompileTimeOptions(); + bout::experimental::printCommandLineArguments(args.original_argv); - try { - /// Load settings file - OptionsReader *reader = OptionsReader::getInstance(); - reader->read(options, "%s/%s", args.data_dir.c_str(), args.opt_file.c_str()); + // Load settings file + OptionsReader* reader = OptionsReader::getInstance(); + reader->read(Options::getRoot(), "%s/%s", args.data_dir.c_str(), + args.opt_file.c_str()); // Get options override from command-line - reader->parseCommandLine(options, argc, argv); + reader->parseCommandLine(Options::getRoot(), argc, argv); // Override options set from short option from the command-line Options::root()["datadir"].force(args.data_dir); @@ -176,30 +161,25 @@ int BoutInitialise(int &argc, char **&argv) { // Save settings if (BoutComm::rank() == 0) { - reader->write(options, "%s/%s", args.data_dir.c_str(), args.set_file.c_str()); + reader->write(Options::getRoot(), "%s/%s", args.data_dir.c_str(), + args.set_file.c_str()); } - } catch (BoutException &e) { - output << _("Error encountered during initialisation\n"); - output << e.what() << endl; - return 1; - } - - try { - ///////////////////////////////////////////// - - bout::globals::mesh = Mesh::create(); ///< Create the mesh - bout::globals::mesh->load(); ///< Load from sources. Required for Field initialisation - bout::globals::mesh->setParallelTransform(); ///< Set the parallel transform from options + // Create the mesh + bout::globals::mesh = Mesh::create(); + // Load from sources. Required for Field initialisation + bout::globals::mesh->load(); + // Set the parallel transform from options + bout::globals::mesh->setParallelTransform(); bout::globals::dump = bout::experimental::setupDumpFile( Options::root(), *bout::globals::mesh, args.data_dir); - }catch(BoutException &e) { + } catch (BoutException& e) { output_error.write(_("Error encountered during initialisation: %s\n"), e.what()); throw; } - + return 0; } From 548e41b61e3e75202a3cac7ffe97513237268d45 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 14:30:51 +0000 Subject: [PATCH 1144/1783] Use bout::experimental namespace in BoutInitialise --- src/bout++.cxx | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 83a5921618..37c57d9f8d 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -110,20 +110,22 @@ char get_spin(); // Produces a spinning bar */ int BoutInitialise(int& argc, char**& argv) { - bout::experimental::setupSignalHandler(bout_signal_handler); + using namespace bout::experimental; - bout::experimental::setupGetText(); + setupSignalHandler(bout_signal_handler); - bout::experimental::CommandLineArgs args; + setupGetText(); + + CommandLineArgs args; try { - args = bout::experimental::parseCommandLineArgs(argc, argv); + args = parseCommandLineArgs(argc, argv); } catch (BoutException& e) { output_error << _("Bad command line arguments:\n") << e.what() << std::endl; return 1; } try { - bout::experimental::checkDataDirectoryIsAccessible(args.data_dir); + checkDataDirectoryIsAccessible(args.data_dir); // Set the command-line arguments SlepcLib::setArgs(argc, argv); // SLEPc initialisation @@ -133,16 +135,16 @@ int BoutInitialise(int& argc, char**& argv) { const int MYPE = BoutComm::rank(); - bout::experimental::setupBoutLogColor(args.color_output, MYPE); + setupBoutLogColor(args.color_output, MYPE); - bout::experimental::setupOutput(args.data_dir, args.log_file, args.verbosity, MYPE); + setupOutput(args.data_dir, args.log_file, args.verbosity, MYPE); - bout::experimental::savePIDtoFile(args.data_dir, MYPE); + savePIDtoFile(args.data_dir, MYPE); // Print the different parts of the startup info - bout::experimental::printStartupHeader(MYPE, BoutComm::size()); - bout::experimental::printCompileTimeOptions(); - bout::experimental::printCommandLineArguments(args.original_argv); + printStartupHeader(MYPE, BoutComm::size()); + printCompileTimeOptions(); + printCommandLineArguments(args.original_argv); // Load settings file OptionsReader* reader = OptionsReader::getInstance(); @@ -157,7 +159,7 @@ int BoutInitialise(int& argc, char**& argv) { Options::root()["optionfile"].force(args.opt_file); Options::root()["settingsfile"].force(args.set_file); - bout::experimental::setRunInfo(Options::root()); + setRunInfo(Options::root()); // Save settings if (BoutComm::rank() == 0) { @@ -172,8 +174,8 @@ int BoutInitialise(int& argc, char**& argv) { // Set the parallel transform from options bout::globals::mesh->setParallelTransform(); - bout::globals::dump = bout::experimental::setupDumpFile( - Options::root(), *bout::globals::mesh, args.data_dir); + bout::globals::dump = + setupDumpFile(Options::root(), *bout::globals::mesh, args.data_dir); } catch (BoutException& e) { output_error.write(_("Error encountered during initialisation: %s\n"), e.what()); From 2774e934feb5bb33954f2e7d985fcc039c794240 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 15:34:36 +0000 Subject: [PATCH 1145/1783] Add more unit tests for BoutInitialise functions --- tests/unit/src/test_bout++.cxx | 160 +++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/tests/unit/src/test_bout++.cxx b/tests/unit/src/test_bout++.cxx index cf8d7e334e..9ead91563d 100644 --- a/tests/unit/src/test_bout++.cxx +++ b/tests/unit/src/test_bout++.cxx @@ -109,6 +109,23 @@ TEST(ParseCommandLineArgs, SettingsFileBad) { BoutException); } +TEST(ParseCommandLineArgs, OptionsAndSettingsFilesSame) { + std::vector v_args{"test", "-o", "same", "-f", "same"}; + auto c_args = get_c_string_vector(v_args); + char** argv = c_args.data(); + + EXPECT_THROW(bout::experimental::parseCommandLineArgs(c_args.size(), argv), + BoutException); +} + +TEST(ParseCommandLineArgs, OptionsAndSettingsFilesDifferent) { + std::vector v_args{"test", "-o", "same", "-f", "different"}; + auto c_args = get_c_string_vector(v_args); + char** argv = c_args.data(); + + EXPECT_NO_THROW(bout::experimental::parseCommandLineArgs(c_args.size(), argv)); +} + TEST(ParseCommandLineArgs, LogFile) { std::vector v_args{"test", "-l", "test_log_file"}; auto v_args_copy = v_args; @@ -130,6 +147,126 @@ TEST(ParseCommandLineArgs, LogFileBad) { BoutException); } +TEST(ParseCommandLineArgs, VerbosityShort) { + std::vector v_args{"test", "-v"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_EQ(args.verbosity, 5); + EXPECT_EQ(args.original_argv, v_args); +} + +TEST(ParseCommandLineArgs, VerbosityShortMultiple) { + std::vector v_args{"test", "-v", "-v"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_EQ(args.verbosity, 6); + EXPECT_EQ(args.original_argv, v_args); +} + +TEST(ParseCommandLineArgs, VerbosityLong) { + std::vector v_args{"test", "--verbose"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_EQ(args.verbosity, 5); + EXPECT_EQ(args.original_argv, v_args); +} + +TEST(ParseCommandLineArgs, VerbosityLongMultiple) { + std::vector v_args{"test", "--verbose", "--verbose"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_EQ(args.verbosity, 6); + EXPECT_EQ(args.original_argv, v_args); +} + +TEST(ParseCommandLineArgs, QuietShort) { + std::vector v_args{"test", "-q"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_EQ(args.verbosity, 3); + EXPECT_EQ(args.original_argv, v_args); +} + +TEST(ParseCommandLineArgs, QuietShortMultiple) { + std::vector v_args{"test", "-q", "-q"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_EQ(args.verbosity, 2); + EXPECT_EQ(args.original_argv, v_args); +} + +TEST(ParseCommandLineArgs, QuietLong) { + std::vector v_args{"test", "--quiet"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_EQ(args.verbosity, 3); + EXPECT_EQ(args.original_argv, v_args); +} + +TEST(ParseCommandLineArgs, QuietLongMultiple) { + std::vector v_args{"test", "--quiet", "--quiet"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_EQ(args.verbosity, 2); + EXPECT_EQ(args.original_argv, v_args); +} + +TEST(ParseCommandLineArgs, ColorShort) { + std::vector v_args{"test", "-c"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_TRUE(args.color_output); + EXPECT_EQ(args.original_argv, v_args); +} + +TEST(ParseCommandLineArgs, ColorLong) { + std::vector v_args{"test", "--color"}; + auto v_args_copy = v_args; + auto c_args = get_c_string_vector(v_args_copy); + char** argv = c_args.data(); + + auto args = bout::experimental::parseCommandLineArgs(c_args.size(), argv); + + EXPECT_TRUE(args.color_output); + EXPECT_EQ(args.original_argv, v_args); +} + class PrintStartupTest : public ::testing::Test { public: PrintStartupTest() : sbuf(std::cout.rdbuf()) { @@ -193,3 +330,26 @@ TEST_F(SignalHandlerTest, SegFault) { EXPECT_DEATH(std::raise(SIGSEGV), "SEGMENTATION FAULT"); } #endif + +TEST(BoutInitialiseFunctions, SetRunInfo) { + WithQuietOutput quiet{output_info}; + + Options options; + + bout::experimental::setRunInfo(options); + + auto run_section = options["run"]; + + EXPECT_TRUE(run_section.isSet("version")); + EXPECT_TRUE(run_section.isSet("revision")); + EXPECT_TRUE(run_section.isSet("started")); +} + +TEST(BoutInitialiseFunctions, CheckDataDirectoryIsAccessible) { + using namespace bout::experimental; + EXPECT_THROW(checkDataDirectoryIsAccessible("./bad/non/existent/directory"), + BoutException); + EXPECT_THROW(checkDataDirectoryIsAccessible(__FILE__), BoutException); + EXPECT_NO_THROW(checkDataDirectoryIsAccessible(".")); +} + From 3458cb5e7c21b9744e75c57f2c1481b43ae48c16 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 16:29:18 +0000 Subject: [PATCH 1146/1783] Fix bug in savePIDtoFile: filename was written to temporary Also make savePIDtoFile throw if file could not be opened --- include/bout.hxx | 4 +++- src/bout++.cxx | 15 +++++++++------ tests/unit/src/test_bout++.cxx | 20 ++++++++++++++++++++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index ed9e91407c..759991f478 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -146,8 +146,10 @@ void checkDataDirectoryIsAccessible(const std::string& data_dir); void setupOutput(const std::string& data_dir, const std::string& log_file, int verbosity, int MYPE = 0); -/// Save the process ID for processor N = \p MYPE to file BOUT.pid.N +/// Save the process ID for processor N = \p MYPE to file ".BOUT.pid.N" /// in \p data_dir, so it can be shut down by user signal +/// +/// Throws if it was not possible to create the file void savePIDtoFile(const std::string& data_dir, int MYPE); /// Print the initial header diff --git a/src/bout++.cxx b/src/bout++.cxx index 37c57d9f8d..df22b30940 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -356,14 +356,17 @@ void checkDataDirectoryIsAccessible(const std::string& data_dir) { } void savePIDtoFile(const std::string& data_dir, int MYPE) { - std::string filename; - std::stringstream(filename) << data_dir << "/.BOUT.pid." << MYPE; + std::stringstream filename; + filename << data_dir << "/.BOUT.pid." << MYPE; std::ofstream pid_file; - pid_file.open(filename, std::ios::out); - if (pid_file.is_open()) { - pid_file << getpid() << "\n"; - pid_file.close(); + pid_file.open(filename.str(), std::ios::out | std::ios::trunc); + + if (not pid_file.is_open()) { + throw BoutException(_("Could not create PID file %s"), filename.str().c_str()); } + + pid_file << getpid() << "\n"; + pid_file.close(); } void printStartupHeader(int MYPE, int NPES) { diff --git a/tests/unit/src/test_bout++.cxx b/tests/unit/src/test_bout++.cxx index 9ead91563d..2e086607bc 100644 --- a/tests/unit/src/test_bout++.cxx +++ b/tests/unit/src/test_bout++.cxx @@ -353,3 +353,23 @@ TEST(BoutInitialiseFunctions, CheckDataDirectoryIsAccessible) { EXPECT_NO_THROW(checkDataDirectoryIsAccessible(".")); } +TEST(BoutInitialiseFunctions, SavePIDtoFile) { + WithQuietOutput quiet{output_info}; + + EXPECT_NO_THROW(bout::experimental::savePIDtoFile("/tmp", 1)); + + std::string filename{"/tmp/.BOUT.pid.1"}; + std::ifstream pid_file; + pid_file.open(filename); + + EXPECT_TRUE(pid_file.good()); + + std::stringstream contents; + contents << pid_file.rdbuf(); + + EXPECT_GT(contents.str().length(), 0); + + std::remove(filename.c_str()); + + EXPECT_THROW(bout::experimental::savePIDtoFile("/", 2), BoutException); +} From 1d6c944c6189079af82e25d198d30e3471af07ed Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 16:58:46 +0000 Subject: [PATCH 1147/1783] Pass optional bool to BoutFinalise to write settings file Some small tidying with minor functions --- include/bout.hxx | 23 +++++++++++--- src/bout++.cxx | 56 +++++++++++++++++++--------------- tests/unit/src/test_bout++.cxx | 16 ++++++++-- 3 files changed, 63 insertions(+), 32 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index 759991f478..223ffec9e9 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -165,10 +165,18 @@ void printCommandLineArguments(const std::vector& original_argv); /// true if it was successful bool setupBoutLogColor(bool color_output, int MYPE); -/// Set BOUT++ version information, along with current time, into -/// `run` section of \p options. This is mainly so it can be easily -/// read in post-processing -void setRunInfo(Options& options); +/// Set BOUT++ version information, along with current time (as +/// `started`), into `run` section of \p options +void setRunStartInfo(Options& options); + +/// Set the current time (as `finished`) into `run` section of \p +/// options +void setRunFinishInfo(Options& options); + +/// Write \p options to \p settings_file in directory \p +/// data_dir. Actually writes only if \p write is true +void writeSettingsFile(Options& options, const std::string& data_dir, + const std::string& settings_file, bool write = true); /// Setup the output dump files from \p options using the \p /// mesh. Files are created in the \p data_dir directory @@ -209,7 +217,12 @@ private: * Frees memory, flushes buffers, and closes files. * If BOUT++ initialised MPI or external libraries, * then these are also finalised. + * + * If \p write_settings is true, output the settings, showing which + * options were used. This overwrites the file written during + * initialisation (BOUT.settings by default) + * */ -int BoutFinalise(); +int BoutFinalise(bool write_settings = true); #endif // __BOUT_H__ diff --git a/src/bout++.cxx b/src/bout++.cxx index df22b30940..575828b080 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -159,13 +159,9 @@ int BoutInitialise(int& argc, char**& argv) { Options::root()["optionfile"].force(args.opt_file); Options::root()["settingsfile"].force(args.set_file); - setRunInfo(Options::root()); + setRunStartInfo(Options::root()); - // Save settings - if (BoutComm::rank() == 0) { - reader->write(Options::getRoot(), "%s/%s", args.data_dir.c_str(), - args.set_file.c_str()); - } + writeSettingsFile(Options::root(), args.data_dir, args.set_file, MYPE == 0); // Create the mesh bout::globals::mesh = Mesh::create(); @@ -513,8 +509,7 @@ void setupOutput(const std::string& data_dir, const std::string& log_file, int v output.enable(verbosity > 2); } -void setRunInfo(Options& options) { - // Put some run information in the options. +void setRunStartInfo(Options& options) { auto& runinfo = options["run"]; // Note: have to force value, since may already be set if a previously @@ -526,6 +521,11 @@ void setRunInfo(Options& options) { runinfo["started"].force(ctime(&start_time), ""); } +void setRunFinishInfo(Options& options) { + time_t end_time = time(nullptr); + options["run"]["finished"].force(ctime(&end_time), ""); +} + Datafile setupDumpFile(Options& options, Mesh& mesh, const std::string& data_dir) { // Check if restarting const bool append = options["append"].withDefault(false); @@ -555,6 +555,15 @@ Datafile setupDumpFile(Options& options, Mesh& mesh, const std::string& data_dir return dump_file; } +void writeSettingsFile(Options& options, const std::string& data_dir, + const std::string& settings_file, bool write) { + if (not write) { + return; + } + OptionsReader::getInstance()->write(&options, "%s/%s", data_dir.c_str(), + settings_file.c_str()); +} + } // namespace experimental } // namespace bout @@ -571,27 +580,24 @@ int bout_run(Solver *solver, rhsfunc physics_run) { return solver->solve(); } -int BoutFinalise() { +int BoutFinalise(bool write_settings) { // Output the settings, showing which options were used // This overwrites the file written during initialisation - try { - if (BoutComm::rank() == 0) { - string data_dir; - Options::getRoot()->get("datadir", data_dir, "data"); - - // Set the end time in the settings file - time_t end_time = time(nullptr); - Options::root()["run"]["finished"].force(ctime(&end_time), ""); - - OptionsReader *reader = OptionsReader::getInstance(); - std::string settingsfile; - OPTION(Options::getRoot(), settingsfile, ""); - reader->write(Options::getRoot(), "%s/%s", data_dir.c_str(), settingsfile.c_str()); + if (write_settings) { + try { + using namespace bout::experimental; + auto& options = Options::root(); + + setRunFinishInfo(options); + + const auto data_dir = options["datadir"].withDefault(std::string{DEFAULT_DIR}); + const auto set_file = options["settingsfile"].withDefault(""); + + writeSettingsFile(options, data_dir, set_file, BoutComm::rank() == 0); + } catch (const BoutException& e) { + output_error << _("Error whilst writing settings") << e.what() << endl; } - } catch (BoutException &e) { - output_error << _("Error whilst writing settings") << endl; - output_error << e.what() << endl; } // Delete the mesh diff --git a/tests/unit/src/test_bout++.cxx b/tests/unit/src/test_bout++.cxx index 2e086607bc..38d89e141e 100644 --- a/tests/unit/src/test_bout++.cxx +++ b/tests/unit/src/test_bout++.cxx @@ -331,20 +331,32 @@ TEST_F(SignalHandlerTest, SegFault) { } #endif -TEST(BoutInitialiseFunctions, SetRunInfo) { +TEST(BoutInitialiseFunctions, SetRunStartInfo) { WithQuietOutput quiet{output_info}; Options options; - bout::experimental::setRunInfo(options); + bout::experimental::setRunStartInfo(options); auto run_section = options["run"]; + ASSERT_TRUE(run_section.isSection()); EXPECT_TRUE(run_section.isSet("version")); EXPECT_TRUE(run_section.isSet("revision")); EXPECT_TRUE(run_section.isSet("started")); } +TEST(BoutInitialiseFunctions, SetRunFinishInfo) { + WithQuietOutput quiet{output_info}; + + Options options; + + bout::experimental::setRunFinishInfo(options); + + ASSERT_TRUE(options["run"].isSection()); + EXPECT_TRUE(options["run"].isSet("finished")); +} + TEST(BoutInitialiseFunctions, CheckDataDirectoryIsAccessible) { using namespace bout::experimental; EXPECT_THROW(checkDataDirectoryIsAccessible("./bad/non/existent/directory"), From bca9436e9744ff94987344946d85079d1f9f9b71 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 17:00:48 +0000 Subject: [PATCH 1148/1783] Catch exceptions by const& --- src/bout++.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 575828b080..365b80ec24 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -119,7 +119,7 @@ int BoutInitialise(int& argc, char**& argv) { CommandLineArgs args; try { args = parseCommandLineArgs(argc, argv); - } catch (BoutException& e) { + } catch (const BoutException& e) { output_error << _("Bad command line arguments:\n") << e.what() << std::endl; return 1; } @@ -173,7 +173,7 @@ int BoutInitialise(int& argc, char**& argv) { bout::globals::dump = setupDumpFile(Options::root(), *bout::globals::mesh, args.data_dir); - } catch (BoutException& e) { + } catch (const BoutException& e) { output_error.write(_("Error encountered during initialisation: %s\n"), e.what()); throw; } From bafb9bc22399b939994cbe7d3065ed4697bcb587 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 25 Mar 2019 17:39:06 +0000 Subject: [PATCH 1149/1783] Clang-format bout++.cxx and bout.hxx --- include/bout.hxx | 62 +++++++++------------ src/bout++.cxx | 142 +++++++++++++++++++++++------------------------ 2 files changed, 95 insertions(+), 109 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index 223ffec9e9..961e6e8558 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -1,10 +1,10 @@ /*!************************************************************************ * * @mainpage BOUT++ - * + * * @version 3.0 - * - * @par Description + * + * @par Description * Framework for the solution of partial differential * equations, in particular fluid models in plasma physics. * @@ -15,7 +15,7 @@ * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -37,34 +37,23 @@ #define __BOUT_H__ #include "boutcomm.hxx" - -#include -#include "globals.hxx" - +#include "datafile.hxx" +#include "difops.hxx" // Differential operators #include "field2d.hxx" #include "field3d.hxx" +#include "globals.hxx" +#include "output.hxx" +#include "smoothing.hxx" // Smoothing functions +#include "sourcex.hxx" // source and mask functions +#include "utils.hxx" +#include "vecops.hxx" // Vector differential operations #include "vector2d.hxx" #include "vector3d.hxx" - -#include "difops.hxx" // Differential operators - -#include "vecops.hxx" // Vector differential operations - -#include "smoothing.hxx" // Smoothing functions - -#include "sourcex.hxx" // source and mask functions - -#include "bout/solver.hxx" - -#include "datafile.hxx" - #include "where.hxx" +#include "bout/mesh.hxx" +#include "bout/solver.hxx" -#include "output.hxx" - -#include "utils.hxx" - -const BoutReal BOUT_VERSION = BOUT_VERSION_DOUBLE; ///< Version number +const BoutReal BOUT_VERSION = BOUT_VERSION_DOUBLE; ///< Version number #ifndef BOUT_NO_USING_NAMESPACE_BOUTGLOBALS // Include using statement by default in user code. @@ -78,11 +67,11 @@ using namespace bout::globals; /*! * BOUT++ initialisation. This function must be * called first, passing command-line arguments. - * + * * This will call MPI_Initialize, and if BOUT++ * has been configured with external libraries such as * PETSc then these will be initialised as well. - * + * * Example * ------- * @@ -90,21 +79,21 @@ using namespace bout::globals; * * int main(int argc, char** argv) { * BoutInitialise(argc, argv); - * + * * BoutFinalise(); * } * * Usually this function is called in a standard main() function, * either by including boutmain.hxx or by including bout/physicsmodel.hxx * and using the BOUTMAIN macro. - * + * */ -int BoutInitialise(int &argc, char **&argv); +int BoutInitialise(int& argc, char**& argv); namespace bout { namespace experimental { /// Function type for handling signals -using SignalHandler = void(*)(int); +using SignalHandler = void (*)(int); /// Set a signal handler for user-requested clean exit, and /// (optionally) segmentation faults and floating point errors @@ -189,22 +178,23 @@ Datafile setupDumpFile(Options& options, Mesh& mesh, const std::string& data_dir * for old-style physics models with standalone C functions * The main() function in boutmain.hxx calls this function * to set up the RHS function and add bout_monitor. - * + * */ -int bout_run(Solver *solver, rhsfunc physics_run); +int bout_run(Solver* solver, rhsfunc physics_run); /*! * Monitor class for output. Called by the solver every output timestep. - * + * * This is added to the solver in bout_run (for C-style models) * or in bout/physicsmodel.hxx */ -class BoutMonitor: public Monitor { +class BoutMonitor : public Monitor { public: BoutMonitor(BoutReal timestep = -1) : Monitor(timestep) { // Add wall clock time etc to dump file run_data.outputVars(bout::globals::dump); } + private: int call(Solver* solver, BoutReal t, int iter, int NOUT) override; RunMetrics run_data; diff --git a/src/bout++.cxx b/src/bout++.cxx index 365b80ec24..c40aec7f95 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -7,7 +7,7 @@ * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -38,57 +38,46 @@ const char DEFAULT_DIR[] = "data"; #define INDIRECT0_BOUTMAIN(...) INDIRECT1_BOUTMAIN(#__VA_ARGS__) #define STRINGIFY(a) INDIRECT0_BOUTMAIN(a) -#include "mpi.h" - -#include -#include -#include -#include -#include -#include +#include "boundary_factory.hxx" +#include "boutcomm.hxx" +#include "boutexception.hxx" +#include "datafile.hxx" +#include "invert_laplace.hxx" +#include "msg_stack.hxx" +#include "optionsreader.hxx" +#include "output.hxx" +#include "bout/openmpwrap.hxx" +#include "bout/petsclib.hxx" +#include "bout/slepclib.hxx" +#include "bout/solver.hxx" +#include "bout/sys/timer.hxx" #define BOUT_NO_USING_NAMESPACE_BOUTGLOBALS -#include +#include "bout.hxx" #undef BOUT_NO_USING_NAMESPACE_BOUTGLOBALS -#include - -#include - -#include - -#include -#include - +#include #include - -#include #include #include -using std::string; -#include + +// POSIX headers #include #include -#ifdef _OPENMP -#include -#endif - -#include -void bout_signal_handler(int sig); // Handles signals #ifdef BOUT_FPE #include #endif +using std::string; -#include - -BoutReal simtime; -int iteration; -bool user_requested_exit=false; +BoutReal simtime{0.0}; +int iteration{0}; +bool user_requested_exit = false; -const string time_to_hms(BoutReal t); // Converts to h:mm:ss.s format -char get_spin(); // Produces a spinning bar +void bout_signal_handler(int sig); // Handles signals +std::string time_to_hms(BoutReal t); // Converts to h:mm:ss.s format +char get_spin(); // Produces a spinning bar /*! Initialise BOUT++ @@ -197,9 +186,7 @@ void setupSignalHandler(SignalHandler signal_handler) { } // This is currently just an alias to the existing handler -void defaultSignalHandler(int sig) { - bout_signal_handler(sig); -} +void defaultSignalHandler(int sig) { bout_signal_handler(sig); } void setupGetText() { #if BOUT_HAS_GETTEXT @@ -567,13 +554,13 @@ void writeSettingsFile(Options& options, const std::string& data_dir, } // namespace experimental } // namespace bout -int bout_run(Solver *solver, rhsfunc physics_run) { - +int bout_run(Solver* solver, rhsfunc physics_run) { + /// Set the RHS function solver->setRHS(physics_run); - + /// Add the monitor function - Monitor * bout_monitor = new BoutMonitor(); + Monitor* bout_monitor = new BoutMonitor(); solver->addMonitor(bout_monitor, Solver::BACK); /// Run the simulation @@ -618,10 +605,10 @@ int BoutFinalise(bool write_settings) { Array::cleanup(); Array::cleanup(); Array::cleanup(); - + // Cleanup boundary factory BoundaryFactory::cleanup(); - + // Cleanup timer Timer::cleanup(); @@ -640,7 +627,7 @@ int BoutFinalise(bool write_settings) { // MPI communicator, including MPI_Finalize() BoutComm::cleanup(); - + return 0; } @@ -650,32 +637,34 @@ int BoutFinalise(bool write_settings) { * Called each timestep by the solver **************************************************************************/ -int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { +int BoutMonitor::call(Solver* solver, BoutReal t, int iter, int NOUT) { TRACE("BoutMonitor::call(%e, %d, %d)", t, iter, NOUT); // Data used for timing static bool first_time = true; static BoutReal wall_limit, mpi_start_time; // Keep track of remaining wall time - - static bool stopCheck; // Check for file, exit if exists? + + static bool stopCheck; // Check for file, exit if exists? static std::string stopCheckName; // File checked, whose existence triggers a stop - + // Set the global variables. This is done because they need to be // written to the output file before the first step (initial condition) simtime = t; iteration = iter; /// Collect timing information - run_data.wtime = Timer::resetTime("run"); - run_data.ncalls = solver->resetRHSCounter(); - run_data.ncalls_e = solver->resetRHSCounter_e(); - run_data.ncalls_i = solver->resetRHSCounter_i(); + run_data.wtime = Timer::resetTime("run"); + run_data.ncalls = solver->resetRHSCounter(); + run_data.ncalls_e = solver->resetRHSCounter_e(); + run_data.ncalls_i = solver->resetRHSCounter_i(); - bool output_split = solver->splitOperator(); - run_data.wtime_rhs = Timer::resetTime("rhs"); + bool output_split = solver->splitOperator(); + run_data.wtime_rhs = Timer::resetTime("rhs"); run_data.wtime_invert = Timer::resetTime("invert"); - run_data.wtime_comms = Timer::resetTime("comms"); // Time spent communicating (part of RHS) - run_data.wtime_io = Timer::resetTime("io"); // Time spend on I/O + // Time spent communicating (part of RHS) + run_data.wtime_comms = Timer::resetTime("comms"); + // Time spend on I/O + run_data.wtime_io = Timer::resetTime("io"); run_data.calculateDerivedMetrics(); @@ -685,7 +674,7 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { /// First time the monitor has been called /// Get some options - Options *options = Options::getRoot(); + Options* options = Options::getRoot(); OPTION(options, wall_limit, -1.0); // Wall time limit. By default, no limit wall_limit *= 60.0 * 60.0; // Convert from hours to seconds @@ -720,8 +709,12 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { run_data.t_elapsed = MPI_Wtime() - mpi_start_time; - output_progress.print("%c Step %d of %d. Elapsed %s", get_spin(), iteration+1, NOUT, (time_to_hms(run_data.t_elapsed)).c_str()); - output_progress.print(" ETA %s", (time_to_hms(run_data.wtime * static_cast(NOUT - iteration - 1))).c_str()); + output_progress.print("%c Step %d of %d. Elapsed %s", get_spin(), iteration + 1, NOUT, + (time_to_hms(run_data.t_elapsed)).c_str()); + output_progress.print( + " ETA %s", + (time_to_hms(run_data.wtime * static_cast(NOUT - iteration - 1))) + .c_str()); /// Write dump file bout::globals::dump.write(); @@ -744,9 +737,8 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { if (stopCheck) { std::ifstream f(stopCheckName); if (f.good()) { - output << "\n" << "File " << stopCheckName - << " exists -- triggering exit." << endl; - user_requested_exit=true; + output << "\nFile " << stopCheckName << " exists -- triggering exit." << endl; + user_requested_exit = true; } } @@ -793,7 +785,7 @@ void bout_signal_handler(int sig) { **************************************************************************/ /// Write a time in h:mm:ss.s format -const string time_to_hms(BoutReal t) { +std::string time_to_hms(BoutReal t) { int h, m; h = static_cast(t / 3600); @@ -812,17 +804,21 @@ char get_spin() { static int i = 0; char c = '|'; // Doesn't need to be assigned; squash warning - switch(i) { - case 0: - c = '|'; break; + switch (i) { + case 0: + c = '|'; + break; case 1: - c = '/'; break; + c = '/'; + break; case 2: - c = '-'; break; + c = '-'; + break; case 3: - c = '\\'; break; + c = '\\'; + break; } - i = (i+1) % 4; + i = (i + 1) % 4; return c; } @@ -833,7 +829,7 @@ char get_spin() { /*! * Adds variables to the output file, for post-processing */ -void RunMetrics::outputVars(Datafile &file) { +void RunMetrics::outputVars(Datafile& file) { file.add(t_elapsed, "wall_time", true); file.add(wtime, "wtime", true); file.add(ncalls, "ncalls", true); From ca936c661aec93e09f26752f73fd69acbb4a18a3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 25 Mar 2019 18:24:24 +0000 Subject: [PATCH 1150/1783] Hypnotoad: refine position of starting line in grid_region_nonorth Previously was done before calling grid_region_nonorth in the closed-field line only case (though this was recently commented out), but not in other cases. Now done for all cases. --- .../tokamak_grids/gridgen/create_nonorthogonal.pro | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index 8c68880475..a2121dfad5 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -345,6 +345,13 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ npar_total = npar + nguards_ydown + nguards_yup nsurf = N_ELEMENTS(fvals) + + ; refine location of starting line + FOR i=0, N_ELEMENTS(ri)-1 DO BEGIN + follow_gradient_nonorth, interp_data, R, Z, ri[i], zi[i], fvals[sind], ri1, zi1 + ri[i] = ri1 + zi[i] = zi1 + ENDFOR IF sind GE 0 THEN BEGIN ; starting position is on one of the output surfaces @@ -1146,12 +1153,6 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ start_ri = (SMOOTH([start_ri[(np-s):(np-1)], start_ri, start_ri[0:(s-1)]], s))[s:(np-1+s)] start_zi = (SMOOTH([start_zi[(np-s):(np-1)], start_zi, start_zi[0:(s-1)]], s))[s:(np-1+s)] - ;FOR i=0, np-1 DO BEGIN - ; follow_gradient_nonorth, interp_data, R, Z, start_ri[i], start_zi[i], start_f, ri1, zi1 - ; start_ri[i] = ri1 - ; start_zi[i] = zi1 - ;ENDFOR - oplot_contour, info, xy, R, Z, /periodic, color=2, thick=1.5D a = grid_region_nonorth(interp_data, R, Z, $ From aba34cf22a94d36a50166ed8773691f83f1be831 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 25 Mar 2019 20:17:32 +0000 Subject: [PATCH 1151/1783] Hypnotoad: remove some commented-out code --- tools/tokamak_grids/gridgen/create_grid.pro | 17 ---- .../gridgen/create_nonorthogonal.pro | 77 ------------------- .../tokamak_grids/gridgen/leg_separatrix.pro | 11 --- tools/tokamak_grids/gridgen/smooth_nl.pro | 8 -- 4 files changed, 113 deletions(-) diff --git a/tools/tokamak_grids/gridgen/create_grid.pro b/tools/tokamak_grids/gridgen/create_grid.pro index a6a23aa15a..bfc8827caa 100644 --- a/tools/tokamak_grids/gridgen/create_grid.pro +++ b/tools/tokamak_grids/gridgen/create_grid.pro @@ -611,17 +611,6 @@ FUNCTION solve_xpt_hthe, dctF, R, Z, sep_info, dist0, pf_f, core_f, sol_in_f, so RETURN, dist0 ; Don't modify ENDIF -; ; Invert using SVD -; SVDC, dfdx, W, U, V -; WP = DBLARR(4, 4) -; for i=0,2 do wp[i,i] = 1.0D/w[i] -; ddist = V ## WP ## TRANSPOSE(U) # xp0 -; -; ;ddist = INVERT(dfdx) # xp0 -; w = WHERE(ABS(ddist) GT 0.5D*dist, count) -; IF count GT 0 THEN ddist[w] = ddist[w] * 0.5D*dist[w] / ABS(ddist[w]) -; dist = dist - ddist -; PRINT, "DIST =", REFORM(dist) PRINT, "RESP = ", response ; PRINT, "CHANGE = ", ddist @@ -1213,10 +1202,6 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ IF mini LT 0.D THEN mini = mini + ni ENDIF ELSE mini = (hit_ind1 + hit_ind2) / 2.D - ;OPLOT, [INTERPOLATE(R[start_ri], hit_ind1, /DOUBLE)], [INTERPOLATE(Z[start_zi], hit_ind1, /DOUBLE)], psym=2, color=2 - ;OPLOT, [INTERPOLATE(R[start_ri], hit_ind2, /DOUBLE)], [INTERPOLATE(Z[start_zi], hit_ind2, /DOUBLE)], psym=2, color=2 - ;OPLOT, [INTERPOLATE(R[start_ri], mini, /DOUBLE)], [INTERPOLATE(Z[start_zi], mini, /DOUBLE)], psym=2, color=4 - PRINT, "Theta location: " + STR(hit_ind1) + "," + STR(hit_ind2) + " -> " + STR(mini) ; Get line a little bit beyond the X-point @@ -1224,8 +1209,6 @@ FUNCTION create_grid, F, R, Z, in_settings, critical=critical, $ INTERPOLATE(start_ri, mini, /DOUBLE), INTERPOLATE(start_zi, mini, /DOUBLE), $ critical.xpt_f[i] + (critical.xpt_f[i] - opt_f[primary_opt]) * 0.05D) - ;OPLOT, INTERPOLATE(R, pos[*,0], /DOUBLE), INTERPOLATE(Z, pos[*,1], /DOUBLE), color=4, thick=2 - ; Find which separatrix line this intersected with cpos = line_crossings([xpt_ri[i], legsep.core1[*,0]], $ [xpt_zi[i], legsep.core1[*,1]], 0, $ diff --git a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro index a2121dfad5..9526cd14c7 100644 --- a/tools/tokamak_grids/gridgen/create_nonorthogonal.pro +++ b/tools/tokamak_grids/gridgen/create_nonorthogonal.pro @@ -396,19 +396,7 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ rii = INTERPOLATE(ri, ind, /DOUBLE) zii = INTERPOLATE(zi, ind, /DOUBLE) - ;rii = int_func(SMOOTH(deriv(rii), 3), /simple) + rii[0] - ;zii = int_func(SMOOTH(deriv(zii), 3), /simple) + zii[0] - ;STOP - - ; Refine the location of the starting point - ;FOR i=0, npar_total-1 DO BEGIN - ; follow_gradient_nonorth, interp_data, R, Z, rii[i], zii[i], f0, ri1, zi1 - ; rii[i] = ri1 - ; zii[i] = zi1 - ;ENDFOR - ; From each starting point, follow gradient in both directions - rixy = DBLARR(nsurf, npar_total) zixy = DBLARR(nsurf, npar_total) FOR i=0, npar_total-1 DO BEGIN @@ -574,9 +562,6 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ z1 = [ zixy[nin-1,i] - 1000.D*dz, zixy[nin-1,i] + 1000.D*dz ] ; Second line going through first point in SOL, along line vec_out - ;r2 = [ rixy[nin+1,i] - 1000.D*vec_out[0], rixy[nin+1,i] + 1000.D*vec_out[0] ] - ;z2 = [ zixy[nin+1,i] - 1000.D*vec_out[1], zixy[nin+1,i] + 1000.D*vec_out[1] ] - dr = rixy[nin+1,i] - rixy[nin+2,i] dz = zixy[nin+1,i] - zixy[nin+2,i] r2 = [ rixy[nin+1,i] - 1000.D*dr, rixy[nin+1,i] + 1000.D*dr ] @@ -614,12 +599,6 @@ FUNCTION grid_region_nonorth, interp_data, R, Z, $ OPLOT, INTERPOLATE(R, rixy[*, i], /DOUBLE), INTERPOLATE(Z, zixy[*, i], /DOUBLE), color=4 ENDIF - ;PLOT, INTERPOLATE(R, rixy[*, i], /DOUBLE), INTERPOLATE(Z, zixy[*, i], /DOUBLE), color=1,psym=1 - ;OPLOT, [INTERPOLATE(R, rixy[nin, i], /DOUBLE)], [INTERPOLATE(Z, zixy[nin, i], /DOUBLE)], color=4,psym=4 - ;IF ncross EQ 1 THEN BEGIN - ; OPLOT, [INTERPOLATE(R, cross[0,0], /DOUBLE)], [INTERPOLATE(Z, cross[1,0], /DOUBLE)],psym=2,color=2 - ;ENDIF - ;CURSOR, ax,by, /down ENDFOR RETURN, {rixy:rixy, zixy:zixy, rxy:INTERPOLATE(R, rixy, /DOUBLE), zxy:INTERPOLATE(Z, zixy, /DOUBLE)} @@ -821,17 +800,6 @@ FUNCTION solve_xpt_hthe, dctF, R, Z, sep_info, dist0, pf_f, core_f, sol_in_f, so RETURN, dist0 ; Don't modify ENDIF -; ; Invert using SVD -; SVDC, dfdx, W, U, V -; WP = DBLARR(4, 4) -; for i=0,2 do wp[i,i] = 1.0D/w[i] -; ddist = V ## WP ## TRANSPOSE(U) # xp0 -; -; ;ddist = INVERT(dfdx) # xp0 -; w = WHERE(ABS(ddist) GT 0.5D*dist, count) -; IF count GT 0 THEN ddist[w] = ddist[w] * 0.5D*dist[w] / ABS(ddist[w]) -; dist = dist - ddist -; PRINT, "DIST =", REFORM(dist) PRINT, "RESP = ", response ; PRINT, "CHANGE = ", ddist @@ -1483,12 +1451,6 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ vecpvt[i,0] = (meanrpvt[nflux_pvt/2]-meanrpvt[0])/lengthpvt vecpvt[i,1] = (meanzpvt[nflux_pvt/2]-meanzpvt[0])/lengthpvt - ;; oplot, INTERPOLATE(R,[meanr1[0],meanr1[nflux_leg1/2]], /DOUBLE),INTERPOLATE(Z,[meanz1[0],meanz1[nflux_leg1/2]], /DOUBLE), thick=5 - ;; oplot, INTERPOLATE(R,[meanr2[0],meanr2[nflux_leg2/2]], /DOUBLE),INTERPOLATE(Z,[meanz2[0],meanz2[nflux_leg2/2]], /DOUBLE), thick=5 - ;; oplot, INTERPOLATE(R,[meanrpvt[0],meanrpvt[nflux_pvt/2]], /DOUBLE),INTERPOLATE(Z,[meanzpvt[0],meanzpvt[nflux_pvt/2]], /DOUBLE), thick=5 - - ;; stop - ; Go a little way along each core separatrix and follow ; Note: add starting point to end of 'boundary' so we find intersections with a closed contour follow_gradient, interp_data, R, Z, $ @@ -1512,45 +1474,6 @@ FUNCTION create_nonorthogonal, F, R, Z, in_settings, critical=critical, $ PRINT, hit_ind1, hit_ind2, mini - ;; IF 0 THEN BEGIN ;; Disabled for now, as doesn't seem to work well - ;; ; Refine the theta index of the X-point using divide and conquer - ;; REPEAT BEGIN - ;; IF MIN([ni - hit_ind2 + hit_ind1, ni - hit_ind1 + hit_ind2]) LT ABS(hit_ind2 - hit_ind1) THEN BEGIN - ;; ; One at the beginning and one at the end (across the join) - ;; mini = (hit_ind2 + hit_ind1 - ni) / 2.D - ;; IF mini LT 0.D THEN mini = mini + ni - ;; ENDIF ELSE mini = (hit_ind1 + hit_ind2) / 2.D - - ;; OPLOT, [INTERPOLATE(R, INTERPOLATE(start_ri, mini, /DOUBLE), /DOUBLE)], [INTERPOLATE(Z, INTERPOLATE(start_zi, mini, /DOUBLE), /DOUBLE)], psym=2, color=4 - - ;; PRINT, "Theta location: " + STR(hit_ind1) + "," + STR(hit_ind2) + " -> " + STR(mini) - - ;; ; Get line a little bit beyond the X-point - ;; pos = get_line_nonorth(interp_data, R, Z, $ - ;; INTERPOLATE(start_ri, mini, /DOUBLE), INTERPOLATE(start_zi, mini, /DOUBLE), $ - ;; critical.xpt_f[i] + (critical.xpt_f[i] - opt_f[primary_opt]) * 0.05D) - - ;; ;OPLOT, INTERPOLATE(R, pos[*,0], /DOUBLE), INTERPOLATE(Z, pos[*,1], /DOUBLE), color=4, thick=2 - - ;; ; Find which separatrix line this intersected with - ;; cpos = line_crossings([xpt_ri[i], legsep.core1[*,0]], $ - ;; [xpt_zi[i], legsep.core1[*,1]], 0, $ - ;; pos[*,0], pos[*,1], 0, $ - ;; ncross=ncross, inds1=inds) - ;; IF ncross GT 0 THEN BEGIN - ;; hit_ind1 = mini - ;; ENDIF ELSE BEGIN - ;; hit_ind2 = mini - ;; ENDELSE - ;; dist = MIN([ni - hit_ind2 + hit_ind1, ni - hit_ind1 + hit_ind2, ABS([hit_ind2 - hit_ind1])]) - ;; ENDREP UNTIL dist LT 0.1D - ;; IF MIN([ni - hit_ind2 + hit_ind1, ni - hit_ind1 + hit_ind2]) LT ABS(hit_ind2 - hit_ind1) THEN BEGIN - ;; ; One at the beginning and one at the end (across the join) - ;; mini = (hit_ind2 + hit_ind1 - ni) / 2.D - ;; IF mini LT 0.D THEN mini = mini + ni - ;; ENDIF ELSE mini = (hit_ind1 + hit_ind2) / 2.D - ;; ENDIF - xpt_ind[i] = mini ; Record the index IF (mini LT 0) OR (mini GE ni) THEN BEGIN diff --git a/tools/tokamak_grids/gridgen/leg_separatrix.pro b/tools/tokamak_grids/gridgen/leg_separatrix.pro index 6781d6963f..72d9041416 100644 --- a/tools/tokamak_grids/gridgen/leg_separatrix.pro +++ b/tools/tokamak_grids/gridgen/leg_separatrix.pro @@ -36,17 +36,6 @@ FUNCTION leg_separatrix, dctF, R, Z, xpt_ri, xpt_zi, $ drdi = INTERPOLATE(DERIV(R), xpt_ri, /DOUBLE) dzdi = INTERPOLATE(DERIV(Z), xpt_zi, /DOUBLE) - ; Use finite-differencing - ;di = 2.DD - ;axp = local_gradient(dctF, xpt_ri + di, xpt_zi) - ;axm = local_gradient(dctF, xpt_ri - di, xpt_zi) - ;ayp = local_gradient(dctF, xpt_ri, xpt_zi + di) - ;aym = local_gradient(dctF, xpt_ri, xpt_zi - di) - - ;fxx = 0.5D*(axp.dfdr - axm.dfdr)/di - ;fyy = 0.5D*(ayp.dfdz - aym.dfdz)/di - ;fxy = 0.25D*( (axp.dfdz - axm.dfdz) + (ayp.dfdr - aym.dfdr) ) / di - IF ABS(fyy) GT 1e-4 THEN BEGIN ; Get gradients 1 and 2 (solutions y = g1 * x and y = g2 * x) diff --git a/tools/tokamak_grids/gridgen/smooth_nl.pro b/tools/tokamak_grids/gridgen/smooth_nl.pro index fca53894f8..4a80be53ba 100644 --- a/tools/tokamak_grids/gridgen/smooth_nl.pro +++ b/tools/tokamak_grids/gridgen/smooth_nl.pro @@ -45,11 +45,6 @@ FUNCTION smooth_nl, input, mesh, iter=iter dym = output[x,y] - output[x,ym] dyp = output[x,yp] - output[x,y] - ;markx[x,y] = ABS(dxm - dxp)^2 - ;marky[x,y] = ABS(dym - dyp)^2 - - ;markx[x,y] = ABS - mxn[x,y] = 0.5D*(ABS(dxm) + ABS(dxp)) myn[x,y] = 0.5D*(ABS(dym) + ABS(dyp)) @@ -57,9 +52,6 @@ FUNCTION smooth_nl, input, mesh, iter=iter ENDIF ENDREP UNTIL last - ;markx = (markx / MEAN(mxn)^2) < 1.0D - ;marky = (marky / MEAN(myn)^2) < 1.0D - markx = (0.5D*mxn / MEAN(mxn)) < 1.0D marky = (0.5D*myn / MEAN(myn)) < 1.0D From d9ae902b7cef04456e2ddcafd546c87417da4018 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 25 Mar 2019 20:26:42 +0000 Subject: [PATCH 1152/1783] Hypnotoad: protect older BOUT++ from loading incompatible grid files If y_boundary_guards>0, then write 'MYG=y_boundary_guards' into the grid file. This ensures that checks present in BOUT++ versions earlier than 4.3 will only allow compatible grids to be read; i.e. single null with y_boundary_guards=0 or MYG, or double null with y_boundary_guards=0. --- tools/tokamak_grids/gridgen/process_grid.pro | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/tokamak_grids/gridgen/process_grid.pro b/tools/tokamak_grids/gridgen/process_grid.pro index e40da2b169..c0dfd1bde8 100644 --- a/tools/tokamak_grids/gridgen/process_grid.pro +++ b/tools/tokamak_grids/gridgen/process_grid.pro @@ -1579,6 +1579,14 @@ retrybetacalc: s = file_write(handle, "nx", nx) s = file_write(handle, "ny", ny) s = file_write(handle, "y_boundary_guards", settings.y_boundary_guards) + IF settings.y_boundary_guards GT 0 THEN BEGIN + ; set number of y-guard cells, instead of allowing this to be set in + ; BOUT.inp or by default. Ensures only compatibile grids with + ; y_boundary_guards=0 or y_boundary_guards=MYG can be loaded by versions of + ; BOUT++ older than v4.3. Note double-null grids with y_boundary_guards>0 + ; cannot be read by versions of BOUT++ earlier than v4.3. + s = file_write(handle, "MYG", settings.y_boundary_guards) + ENDIF ; Topology for original scheme s = file_write(handle, "ixseps1", ixseps1) From e5f3bc002d8dc97b8cf9d10cde9d37d5a6c11c04 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 26 Mar 2019 11:20:38 +0000 Subject: [PATCH 1153/1783] Fix mesh checks in Laplace implementation headers Previously were using '=' instead of '=='. --- .../laplace/impls/cyclic/cyclic_laplace.hxx | 6 +++--- .../impls/multigrid/multigrid_laplace.hxx | 20 +++++++++---------- .../laplace/impls/serial_band/serial_band.hxx | 6 +++--- .../laplace/impls/serial_tri/serial_tri.hxx | 6 +++--- .../laplace/impls/shoot/shoot_laplace.hxx | 6 +++--- src/invert/laplace/impls/spt/spt.hxx | 6 +++--- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx index d4419dd5f2..02236f7e3b 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx @@ -50,19 +50,19 @@ public: using Laplacian::setCoefA; void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); Acoef = val; } using Laplacian::setCoefC; void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); Ccoef = val; } using Laplacian::setCoefD; void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); Dcoef = val; } using Laplacian::setCoefEx; diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx index 0d9b2ae8dc..375455ea9e 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx @@ -138,28 +138,28 @@ public: void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); A = val; } void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); C1 = val; C2 = val; } void setCoefC1(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); C1 = val; } void setCoefC2(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); C2 = val; } void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); D = val; } void setCoefEx(const Field2D &UNUSED(val)) override { throw BoutException("setCoefEx is not implemented in LaplaceMultigrid"); } @@ -167,28 +167,28 @@ public: void setCoefA(const Field3D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); A = val; } void setCoefC(const Field3D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); C1 = val; C2 = val; } void setCoefC1(const Field3D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); C1 = val; } void setCoefC2(const Field3D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); C2 = val; } void setCoefD(const Field3D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); D = val; } diff --git a/src/invert/laplace/impls/serial_band/serial_band.hxx b/src/invert/laplace/impls/serial_band/serial_band.hxx index 41c29b8875..e2cfa61309 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.hxx +++ b/src/invert/laplace/impls/serial_band/serial_band.hxx @@ -42,19 +42,19 @@ public: using Laplacian::setCoefA; void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); Acoef = val; } using Laplacian::setCoefC; void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); Ccoef = val; } using Laplacian::setCoefD; void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); Dcoef = val; } using Laplacian::setCoefEx; diff --git a/src/invert/laplace/impls/serial_tri/serial_tri.hxx b/src/invert/laplace/impls/serial_tri/serial_tri.hxx index 770b71050d..6486472af3 100644 --- a/src/invert/laplace/impls/serial_tri/serial_tri.hxx +++ b/src/invert/laplace/impls/serial_tri/serial_tri.hxx @@ -41,19 +41,19 @@ public: using Laplacian::setCoefA; void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); A = val; } using Laplacian::setCoefC; void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); C = val; } using Laplacian::setCoefD; void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); D = val; } using Laplacian::setCoefEx; diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.hxx b/src/invert/laplace/impls/shoot/shoot_laplace.hxx index a31780a032..f18856d4a4 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.hxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.hxx @@ -43,19 +43,19 @@ public: using Laplacian::setCoefA; void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); Acoef = val; } using Laplacian::setCoefC; void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); Ccoef = val; } using Laplacian::setCoefD; void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); Dcoef = val; } using Laplacian::setCoefEx; diff --git a/src/invert/laplace/impls/spt/spt.hxx b/src/invert/laplace/impls/spt/spt.hxx index 1bdc064b98..f02f91a393 100644 --- a/src/invert/laplace/impls/spt/spt.hxx +++ b/src/invert/laplace/impls/spt/spt.hxx @@ -72,19 +72,19 @@ public: using Laplacian::setCoefA; void setCoefA(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); Acoef = val; } using Laplacian::setCoefC; void setCoefC(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); Ccoef = val; } using Laplacian::setCoefD; void setCoefD(const Field2D &val) override { ASSERT1(val.getLocation() == location); - ASSERT1(localmesh = val.getMesh()); + ASSERT1(localmesh == val.getMesh()); Dcoef = val; } using Laplacian::setCoefEx; From 8ef842424b49fa9040684f22525eaacdf38d07ff Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 26 Mar 2019 12:06:33 +0000 Subject: [PATCH 1154/1783] Options::withDefault sets type attribute * When an option is converted to a type, the type name is stored in an attribute "type". This can't always be done, since `Options::as` is `const`. * Defined `bout::utils::typeName()` in `include/bout/sys/type_name.hxx` to convert type to a string. This falls back to `typeid(T).name()` but is specialised for commonly used types. * Modified `OptionsINI::write` to print the type if it's available. This code now uses the `Options` objects directly, not relying on conversion to the older `OptionValue` types. The old interface has therefore been deprecated. The `examples/blob2d` code now writed to `BOUT.settings`: ``` bndry_all = neumann # type: string evolve_bndry = false # type: bool function = 0.0 # type: string scale = 0.0 # type: BoutReal ``` Lining up would be nice, but maybe later... --- include/bout/sys/type_name.hxx | 43 +++++++++++++++++++++++++++++++++ include/options.hxx | 21 ++++++++++++++-- src/sys/makefile | 2 +- src/sys/options/options_ini.cxx | 42 +++++++++++++++++++++++--------- src/sys/type_name.cxx | 37 ++++++++++++++++++++++++++++ 5 files changed, 131 insertions(+), 14 deletions(-) create mode 100644 include/bout/sys/type_name.hxx create mode 100644 src/sys/type_name.cxx diff --git a/include/bout/sys/type_name.hxx b/include/bout/sys/type_name.hxx new file mode 100644 index 0000000000..143d16aed3 --- /dev/null +++ b/include/bout/sys/type_name.hxx @@ -0,0 +1,43 @@ + +#pragma once + +#ifndef TYPE_NAME_HXX +#define TYPE_NAME_HXX + +#include +#include +#include "bout_types.hxx" + +namespace bout { +namespace utils { + + class Field2D; + class Field3D; + + template + std::string typeName() { + return typeid(T).name(); + } + + template <> + std::string typeName(); + + template <> + std::string typeName(); + + template <> + std::string typeName(); + + // Specialised for BOUT++ types to ensure that the result is human-readable + template <> + std::string typeName(); + + template <> + std::string typeName(); + + template <> + std::string typeName(); +} +} + +#endif //TYPE_NAME_HXX diff --git a/include/options.hxx b/include/options.hxx index 2e49f1356b..124d98f3bd 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -44,6 +44,8 @@ class Options; #include "output.hxx" #include "utils.hxx" #include "bout/sys/variant.hxx" +#include "bout/sys/type_name.hxx" +#include "bout/deprecated.hxx" #include "field2d.hxx" #include "field3d.hxx" @@ -96,7 +98,7 @@ class Options; * int other; * options.get("otherkey", other, 2.0); // Sets other to 2 because "otherkey" not found * - * Internally, all values are stored as strings, so conversion is performed silently: + * Conversion is performed silently: * * options.set("value", "2.34", "here"); // Set a string * @@ -231,6 +233,12 @@ public: /// do not need to be forced. The string will be used /// when writing the output as the name of the time /// dimension (unlimited first dimension in NetCDF files). + /// + /// - source [string] Describes where the value came from + /// e.g. a file name, or "default". + /// + /// - type [string] The type the Option is converted to + /// when used. std::map attributes; /// Get a sub-section or value @@ -379,6 +387,10 @@ public: /// Get the value of this option. If not found, /// set to the default value template T withDefault(T def) { + + // Set the type + attributes["type"] = bout::utils::typeName(); + if (!is_value) { // Option not found assign(def, DEFAULT_SOURCE); @@ -535,7 +547,8 @@ public: /// Read-only access to internal options and sections /// to allow iteration over the tree - std::map values() const; + using ValuesMap = std::map; + DEPRECATED(ValuesMap values() const); std::map subsections() const; const std::map& getChildren() const { @@ -546,6 +559,10 @@ public: return is_value; } bool isSection(const std::string& name = "") const; + + /// If the option value has been used anywhere + bool valueUsed() const { return value_used; } + private: /// The source label given to default values diff --git a/src/sys/makefile b/src/sys/makefile index 061d15da47..5caf35f05d 100644 --- a/src/sys/makefile +++ b/src/sys/makefile @@ -5,7 +5,7 @@ SOURCEC = bout_types.cxx boutexception.cxx derivs.cxx \ msg_stack.cxx options.cxx output.cxx \ utils.cxx optionsreader.cxx boutcomm.cxx \ timer.cxx range.cxx petsclib.cxx expressionparser.cxx \ - slepclib.cxx + slepclib.cxx type_name.cxx SOURCEH = $(SOURCEC:%.cxx=%.hxx) globals.hxx bout_types.hxx multiostream.hxx TARGET = lib diff --git a/src/sys/options/options_ini.cxx b/src/sys/options/options_ini.cxx index e5dd9be262..ab48e84453 100644 --- a/src/sys/options/options_ini.cxx +++ b/src/sys/options/options_ini.cxx @@ -186,19 +186,39 @@ void OptionINI::writeSection(const Options *options, std::ofstream &fout) { fout << "[" << section_name << "]" << endl; } // Iterate over all values - for(const auto& it : options->values()) { - fout << it.first << " = " << it.second.value; - if (it.second.value.empty()) { - // Print an empty string as "" - fout << "\"\""; - } - if (! it.second.used ) { - fout << " # not used , from: " - << it.second.source; + for(const auto& it : options->getChildren()) { + if (it.second.isValue()) { + auto value = bout::utils::variantToString(it.second.value); + fout << it.first << " = " << value; + + if (value.empty()) { + // Print an empty string as "" + fout << "\"\""; + } + bool in_comment = false; // Has a '#' been printed yet? + + if (! it.second.valueUsed() ) { + fout << "\t\t# not used "; + in_comment = true; + + if (it.second.attributes.count("source")) { + fout << ", from: " + << it.second.attributes.at("source").as(); + } + } + + if (it.second.attributes.count("type")) { + if (!in_comment) { + fout << "\t\t# type: "; + in_comment = true; + } else { + fout << ", type: "; + } + fout << it.second.attributes.at("type").as(); + } } - fout << endl; } - + // Iterate over sub-sections for(const auto& it : options->subsections()) { fout << endl; diff --git a/src/sys/type_name.cxx b/src/sys/type_name.cxx new file mode 100644 index 0000000000..b8d7ba1fd9 --- /dev/null +++ b/src/sys/type_name.cxx @@ -0,0 +1,37 @@ +#include "bout/sys/type_name.hxx" + +namespace bout { +namespace utils { + +template <> +std::string typeName() { + return "bool"; +} + +template <> +std::string typeName() { + return "int"; +} + +template <> +std::string typeName() { + return "string"; +} + +template <> +std::string typeName() { + return "BoutReal"; +} + +template <> +std::string typeName() { + return "Field2D"; +} + +template <> +std::string typeName() { + return "Field3D"; +} + +} +} From 0dbad7fbcc49bbd3c8f69dc7301aa2dff1c0f80f Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 26 Mar 2019 12:48:13 +0000 Subject: [PATCH 1155/1783] Add Options::doc(string) Puts a documentation string into options as an attribute "doc". Can be chained with access to the option, putting documentation where the value is used. Unfortunately currently the `const` version of `withDefault` can be called, so that values are not stored and documentation not printed. --- examples/blob2d/blob2d.cxx | 27 +++++++++++++++------------ include/options.hxx | 11 +++++++++++ src/sys/options/options_ini.cxx | 11 +++++++++++ 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/examples/blob2d/blob2d.cxx b/examples/blob2d/blob2d.cxx index bab001e62c..2192bbe97d 100644 --- a/examples/blob2d/blob2d.cxx +++ b/examples/blob2d/blob2d.cxx @@ -54,27 +54,30 @@ class Blob2D : public PhysicsModel { auto options = globalOptions["model"]; // Load system parameters - Te0 = options["Te0"].withDefault(30); // Temp in eV + Te0 = options["Te0"].doc("Temperature in eV").withDefault(30); + e = options["e"].withDefault(1.602e-19); m_i = options["m_i"].withDefault(2 * 1.667e-27); m_e = options["m_e"].withDefault(9.11e-31); - n0 = options["n0"].withDefault(1e19); // Background density in cubic m - D_vort = options["D_vort"].withDefault(0); // Viscous diffusion coefficient - D_n = options["D_n"].withDefault(0); // Density diffusion coefficient + n0 = options["n0"].doc("Background density in cubic m").withDefault(1e19); + D_vort = options["D_vort"].doc("Viscous diffusion coefficient").withDefault(0); + D_n = options["D_n"].doc("Density diffusion coefficient").withDefault(0); - R_c = options["R_c"].withDefault(1.5); // Radius of curvature - L_par = options["L_par"].withDefault(10); // Parallel connection length + R_c = options["R_c"].doc("Radius of curvature").withDefault(1.5); + L_par = options["L_par"].doc("Parallel connection length").withDefault(10); - B0 = options["B0"].withDefault(0.35); // Value of magnetic field strength + B0 = options["B0"].doc("Value of magnetic field strength").withDefault(0.35); // System option switches - compressible = options["compressible"].withDefault( - false); // Compressible ExB term in density equation - boussinesq = options["boussinesq"].withDefault( - true); // Use Boussinesq approximation in vorticity - sheath = options["sheath"].withDefault(true); // Sheath closure + compressible = options["compressible"] + .doc("Compressible ExB term in density equation") + .withDefault(false); + boussinesq = options["boussinesq"] + .doc("Use Boussinesq approximation in vorticity") + .withDefault(true); + sheath = options["sheath"].doc("Sheath closure").withDefault(true); /***************Calculate the Parameters **********/ diff --git a/include/options.hxx b/include/options.hxx index 124d98f3bd..6dbe12c754 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -239,6 +239,9 @@ public: /// /// - type [string] The type the Option is converted to /// when used. + /// + /// - doc [string] Documentation, describing what the variable does + /// std::map attributes; /// Get a sub-section or value @@ -562,6 +565,14 @@ public: /// If the option value has been used anywhere bool valueUsed() const { return value_used; } + + + /// Set a documentation string as an attribute "doc" + /// Returns a reference to this, to allow chaining + Options& doc(const std::string& docstring) { + attributes["doc"] = docstring; + return *this; + } private: diff --git a/src/sys/options/options_ini.cxx b/src/sys/options/options_ini.cxx index ab48e84453..e2a9f932ec 100644 --- a/src/sys/options/options_ini.cxx +++ b/src/sys/options/options_ini.cxx @@ -216,6 +216,17 @@ void OptionINI::writeSection(const Options *options, std::ofstream &fout) { } fout << it.second.attributes.at("type").as(); } + + if (it.second.attributes.count("doc")) { + if (!in_comment) { + fout << "\t\t# "; + in_comment = true; + } else { + fout << ", doc: "; + } + fout << it.second.attributes.at("doc").as(); + } + fout << endl; } } From 9424f49516354abefe87dc9aa10d1b1bfddb2d95 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Mar 2019 14:05:22 +0000 Subject: [PATCH 1156/1783] Don't clean up msg_stack till last thing --- src/bout++.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index c40aec7f95..c6c18f461b 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -616,9 +616,6 @@ int BoutFinalise(bool write_settings) { Options::cleanup(); OptionsReader::cleanup(); - // Debugging message stack - msg_stack.clear(); - // Call SlepcFinalize if not already called SlepcLib::cleanup(); @@ -628,6 +625,9 @@ int BoutFinalise(bool write_settings) { // MPI communicator, including MPI_Finalize() BoutComm::cleanup(); + // Debugging message stack + msg_stack.clear(); + return 0; } From fd84ccda2a4ce316ca0075ef4e54bc41014ab4cd Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 26 Mar 2019 15:20:19 +0000 Subject: [PATCH 1157/1783] set value_used in Options Not setting flag when reading as Field2D or Field3D. Added `&` to `Options` used in blob2d example. Previously the options tree was being copied, so changes made in physics `init` code were not recorded. --- examples/blob2d/blob2d.cxx | 4 ++-- src/sys/options.cxx | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/blob2d/blob2d.cxx b/examples/blob2d/blob2d.cxx index 2192bbe97d..360e743edc 100644 --- a/examples/blob2d/blob2d.cxx +++ b/examples/blob2d/blob2d.cxx @@ -50,8 +50,8 @@ class Blob2D : public PhysicsModel { /******************Reading options *****************/ - auto globalOptions = Options::root(); - auto options = globalOptions["model"]; + auto& globalOptions = Options::root(); + auto& options = globalOptions["model"]; // Load system parameters Te0 = options["Te0"].doc("Temperature in eV").withDefault(30); diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 04f526561e..3b1902b932 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -331,6 +331,9 @@ template <> Field3D Options::as(Mesh* localmesh) const { if (!is_value) { throw BoutException("Option %s has no value", full_name.c_str()); } + + // Mark value as used + value_used = true; try { return bout::utils::variantStaticCastOrThrow(value); @@ -368,6 +371,9 @@ template <> Field2D Options::as(Mesh* localmesh) const { throw BoutException("Option %s has no value", full_name.c_str()); } + // Mark value as used + value_used = true; + try { return bout::utils::variantStaticCastOrThrow(value); } catch (const std::bad_cast &e) { From 6d2e2aa6139eccf94252fe967ee246db5d2eef25 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 26 Mar 2019 15:58:35 +0000 Subject: [PATCH 1158/1783] Use `auto&` for Options If just `auto` is used then a copy of the Options tree is made. This works, but doesn't record when values are used, or their type and documentation (if any). --- examples/2Dturbulence_multigrid/data/BOUT.inp | 8 ----- examples/2Dturbulence_multigrid/esel.cxx | 12 +++---- examples/conducting-wall-mode/cwm.cxx | 6 ++-- examples/conduction/conduction.cxx | 9 +++--- examples/fci-wave/fci-wave.cxx | 6 ++-- .../finite-volume/diffusion/diffusion.cxx | 4 +-- examples/finite-volume/fluid/fluid.cxx | 13 ++++---- examples/gas-compress/advect1d/BOUT.inp | 3 ++ examples/gas-compress/gas_compress.cxx | 32 +++++++------------ examples/hasegawa-wakatani/hw.cxx | 14 ++++---- examples/orszag-tang/mhd.cxx | 5 ++- examples/reconnect-2field/2field.cxx | 23 ++++++------- examples/reconnect-2field/data/BOUT.inp | 2 +- 13 files changed, 61 insertions(+), 76 deletions(-) diff --git a/examples/2Dturbulence_multigrid/data/BOUT.inp b/examples/2Dturbulence_multigrid/data/BOUT.inp index c01bfb5dd2..5bca6fa48d 100644 --- a/examples/2Dturbulence_multigrid/data/BOUT.inp +++ b/examples/2Dturbulence_multigrid/data/BOUT.inp @@ -68,14 +68,6 @@ function = 15*sqrt(2*pi)*gauss(150*x,15) bndry_xin = dirichlet_o2(1.0) bndry_xout = neumann_o2 -[N] -scale = 1.0 -#function = log(15*sqrt(2*pi)*gauss(150*x,15)) -function = 0-x - -bndry_xin = dirichlet_o2(0.0) -bndry_xout = neumann_o2 - [T] scale = 1.0 function = 15*sqrt(2*pi)*gauss(150*x,15) diff --git a/examples/2Dturbulence_multigrid/esel.cxx b/examples/2Dturbulence_multigrid/esel.cxx index 34e880b96e..50e1ed08ec 100644 --- a/examples/2Dturbulence_multigrid/esel.cxx +++ b/examples/2Dturbulence_multigrid/esel.cxx @@ -19,14 +19,13 @@ class ESEL : public PhysicsModel { Field3D vort_error; protected: - int init(bool restart) { + int init(bool UNUSED(restart)) { - auto options = Options::root()["esel"]; + auto& options = Options::root()["esel"]; zeta = options["zeta"].withDefault(2.15e-3); D = options["D"].withDefault(1.97e-3); mu = options["mu"].withDefault(3.88e-2); - int bracket = options["bracket"].withDefault(2); test_laplacian = options["test_laplacian"].withDefault(false); // Set sources and sinks from input profile @@ -41,7 +40,7 @@ class ESEL : public PhysicsModel { // Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE // Choose method to use for Poisson bracket advection terms - switch (bracket) { + switch (options["bracket"].withDefault(2)) { case 0: { bm = BRACKET_STD; output << "\tBrackets: default differencing\n"; @@ -88,8 +87,7 @@ class ESEL : public PhysicsModel { coord->geometry(); - SOLVE_FOR(N); - SOLVE_FOR(vort); + SOLVE_FOR(N, vort); SAVE_REPEAT(phi); if (test_laplacian) { SAVE_REPEAT(vort_error); @@ -102,7 +100,7 @@ class ESEL : public PhysicsModel { Field3D C(const Field3D& f) { return zeta * DDZ(f); } - int rhs(BoutReal time) { + int rhs(BoutReal UNUSED(time)) { mesh->communicate(N, vort); phiSolver->setCoefC2(N); diff --git a/examples/conducting-wall-mode/cwm.cxx b/examples/conducting-wall-mode/cwm.cxx index 25f5c2f914..9289a2b6ec 100644 --- a/examples/conducting-wall-mode/cwm.cxx +++ b/examples/conducting-wall-mode/cwm.cxx @@ -109,9 +109,9 @@ class CWM : public PhysicsModel { /*************** READ OPTIONS *************************/ // Read some parameters - auto globalOptions = Options::root(); - auto options = globalOptions["2fluid"]; - AA = options["AA"].withDefault(4.0); // <=> options["AA"].withDefault(1.0); + auto& globalOptions = Options::root(); + auto& options = globalOptions["2fluid"]; + AA = options["AA"].withDefault(4.0); ZZ = options["ZZ"].withDefault(1.0); zeff = options["zeff"].withDefault(1.0); diff --git a/examples/conduction/conduction.cxx b/examples/conduction/conduction.cxx index 2c8cf0858c..72ecfae5fd 100644 --- a/examples/conduction/conduction.cxx +++ b/examples/conduction/conduction.cxx @@ -15,13 +15,14 @@ class Conduction : public PhysicsModel { protected: // This is called once at the start - int init(bool restarting) override { + int init(bool UNUSED(restarting)) override { // Get the options - auto options = Options::root()["conduction"]; + auto& options = Options::root()["conduction"]; // Read from BOUT.inp, setting default to 1.0 - chi = options["chi"].withDefault(1.0); + // The doc() provides some documentation in BOUT.settings + chi = options["chi"].doc("Conduction coefficient").withDefault(1.0); // Tell BOUT++ to solve T SOLVE_FOR(T); @@ -29,7 +30,7 @@ class Conduction : public PhysicsModel { return 0; } - int rhs(BoutReal time) override { + int rhs(BoutReal UNUSED(time)) override { mesh->communicate(T); // Communicate guard cells ddt(T) = Div_par_K_Grad_par(chi, T); // Parallel diffusion Div_{||}( chi * Grad_{||}(T) ) diff --git a/examples/fci-wave/fci-wave.cxx b/examples/fci-wave/fci-wave.cxx index 5380d73360..384711d141 100644 --- a/examples/fci-wave/fci-wave.cxx +++ b/examples/fci-wave/fci-wave.cxx @@ -56,12 +56,12 @@ class FCIwave : public PhysicsModel { } protected: - int init(bool restarting) override { + int init(bool UNUSED(restarting)) override { // Get the magnetic field mesh->get(Bxyz, "B"); - auto options = Options::root()["fciwave"]; + auto& options = Options::root()["fciwave"]; div_integrate = options["div_integrate"].withDefault(true); log_density = options["log_density"].withDefault(false); background = options["background"].withDefault(false); @@ -85,7 +85,7 @@ class FCIwave : public PhysicsModel { return 0; } - int rhs(BoutReal t) override { + int rhs(BoutReal UNUSED(time)) override { if (log_density) { mesh->communicate(logn, nv); // Apply boundary condition to log(n) diff --git a/examples/finite-volume/diffusion/diffusion.cxx b/examples/finite-volume/diffusion/diffusion.cxx index 7e13ea0ec7..8613e4e378 100644 --- a/examples/finite-volume/diffusion/diffusion.cxx +++ b/examples/finite-volume/diffusion/diffusion.cxx @@ -6,7 +6,7 @@ class Diffusion : public PhysicsModel { protected: - int init(bool restarting) override { + int init(bool UNUSED(restarting)) override { GRID_LOAD(k); mesh->communicate(k); @@ -15,7 +15,7 @@ class Diffusion : public PhysicsModel { return 0; } - int rhs(BoutReal time) override { + int rhs(BoutReal UNUSED(time)) override { mesh->communicate(f); ddt(f) = FV::Div_par_K_Grad_par(k, f); diff --git a/examples/finite-volume/fluid/fluid.cxx b/examples/finite-volume/fluid/fluid.cxx index 6de380db4b..547996dc91 100644 --- a/examples/finite-volume/fluid/fluid.cxx +++ b/examples/finite-volume/fluid/fluid.cxx @@ -10,18 +10,19 @@ class Fluid : public PhysicsModel { protected: - int init(bool restart) override { - auto opt = Options::root()["fluid"]; + int init(bool UNUSED(restart)) override { + auto& opt = Options::root()["fluid"]; - // Adiabatic index (ratio of specific heats) - gamma = opt["gamma"].withDefault(5. / 3); + gamma = opt["gamma"] + .doc("Adiabatic index (ratio of specific heats)") + .withDefault(5. / 3); - SOLVE_FOR3(n, p, nv); + SOLVE_FOR(n, p, nv); return 0; } - int rhs(BoutReal time) override { + int rhs(BoutReal UNUSED(time)) override { mesh->communicate(n, p, nv); diff --git a/examples/gas-compress/advect1d/BOUT.inp b/examples/gas-compress/advect1d/BOUT.inp index 7ebd775c30..9ced3b3a25 100644 --- a/examples/gas-compress/advect1d/BOUT.inp +++ b/examples/gas-compress/advect1d/BOUT.inp @@ -12,8 +12,11 @@ TIMESTEP = 0.05 # time between outputs MXG = 0 # Guard cells in X MYG = 2 # Guard cells in Y + [mesh] +staggergrids = true + ixseps1 = 5 ixseps2 = 5 diff --git a/examples/gas-compress/gas_compress.cxx b/examples/gas-compress/gas_compress.cxx index b56878c9b3..10d5624d2d 100644 --- a/examples/gas-compress/gas_compress.cxx +++ b/examples/gas-compress/gas_compress.cxx @@ -15,17 +15,14 @@ int GasCompress::init(bool restarting) { // read options - Options *options = Options::getRoot(); - options = options->getSection("gas"); - options->get("gamma", gamma_ratio, 5./3.); - options->get("viscosity", nu, 0.1); - options->get("include_viscosity", include_viscosity, false); + auto& options = Options::root()["gas"]; + gamma_ratio = options["gamma"].withDefault(0.1); + include_viscosity = options["include_viscosity"].withDefault(false); - BoutReal v0_multiply; - options->get("v0_multiply", v0_multiply, 1.0); + BoutReal v0_multiply = options["v0_multiply"].withDefault(1.0); V0 *= v0_multiply; - options->get("sub_initial", sub_initial, false); + sub_initial = options["sub_initial"].withDefault(false); V.y.setLocation(CELL_YLOW); // Stagger @@ -46,23 +43,20 @@ int GasCompress::init(bool restarting) { return 0; } -int GasCompress::rhs(BoutReal t) { +int GasCompress::rhs(BoutReal UNUSED(time)) { // Run communications mesh->communicate(N,P,V); // Density - - //ddt(N) = -V_dot_Grad(V, N) - N*Div(V); ddt(N) = -Div(V, N); - // Velocity - - - if(sub_initial) { + // Velocity + + if (sub_initial) { // Subtract force balance of initial profiles - ddt(V) = -V_dot_Grad(V, V) - Grad(P - P0, CELL_VSHIFT)/N; - }else { - ddt(V) = -V_dot_Grad(V, V) - Grad(P, CELL_VSHIFT)/N + g; + ddt(V) = -V_dot_Grad(V, V) - Grad(P - P0, CELL_VSHIFT) / N; + } else { + ddt(V) = -V_dot_Grad(V, V) - Grad(P, CELL_VSHIFT) / N + g; } if(include_viscosity) { @@ -73,8 +67,6 @@ int GasCompress::rhs(BoutReal t) { } // Pressure - - //ddt(P) = -V_dot_Grad(V, P) - gamma_ratio*P*Div(V); ddt(P) = -Div(V, P) - (gamma_ratio-1.)*P*Div(V); return 0; diff --git a/examples/hasegawa-wakatani/hw.cxx b/examples/hasegawa-wakatani/hw.cxx index 2940084e31..f7a2c5a625 100644 --- a/examples/hasegawa-wakatani/hw.cxx +++ b/examples/hasegawa-wakatani/hw.cxx @@ -33,9 +33,9 @@ class HW : public PhysicsModel { } protected: - int init(bool restart) { + int init(bool UNUSED(restart)) { - auto options = Options::root()["hw"]; + auto& options = Options::root()["hw"]; alpha = options["alpha"].withDefault(1.0); kappa = options["kappa"].withDefault(0.1); Dvort = options["Dvort"].withDefault(1e-2); @@ -43,7 +43,7 @@ class HW : public PhysicsModel { modified = options["modified"].withDefault(false); - SOLVE_FOR2(n, vort); + SOLVE_FOR(n, vort); SAVE_REPEAT(phi); // Split into convective and diffusive parts @@ -55,9 +55,7 @@ class HW : public PhysicsModel { // Use default flags // Choose method to use for Poisson bracket advection terms - int bracket; - bracket = options["bracket"].withDefault(0); - switch(bracket) { + switch(options["bracket"].withDefault(0)) { case 0: { bm = BRACKET_STD; output << "\tBrackets: default differencing\n"; @@ -86,7 +84,7 @@ class HW : public PhysicsModel { return 0; } - int convective(BoutReal time) { + int convective(BoutReal UNUSED(time)) { // Non-stiff, convective part of the problem // Solve for potential @@ -111,7 +109,7 @@ class HW : public PhysicsModel { return 0; } - int diffusive(BoutReal time) { + int diffusive(BoutReal UNUSED(time)) { // Diffusive terms mesh->communicate(n, vort); ddt(n) = -Dn*Delp4(n); diff --git a/examples/orszag-tang/mhd.cxx b/examples/orszag-tang/mhd.cxx index 330926b551..acaaca8efa 100644 --- a/examples/orszag-tang/mhd.cxx +++ b/examples/orszag-tang/mhd.cxx @@ -24,8 +24,7 @@ class MHD : public PhysicsModel { Vector2D v0, B0; // read options - auto globalOptions = Options::root(); - auto options = globalOptions["mhd"]; + auto& options = Options::root()["mhd"]; g = options["g"].withDefault(5.0 / 3.0); include_viscos = options["include_viscos"].withDefault(false); viscos = options["viscos"].withDefault(0.1); @@ -86,7 +85,7 @@ class MHD : public PhysicsModel { return 0; } - int rhs(BoutReal t) override { + int rhs(BoutReal UNUSED(time)) override { // Communicate variables mesh->communicate(v, B, p, rho); diff --git a/examples/reconnect-2field/2field.cxx b/examples/reconnect-2field/2field.cxx index ae68c08065..6a7f1f8143 100644 --- a/examples/reconnect-2field/2field.cxx +++ b/examples/reconnect-2field/2field.cxx @@ -74,8 +74,7 @@ class TwoField : public PhysicsModel { mesh->get(coord->Bxy, "Bxy"); // Read some parameters - auto globalOptions = Options::root(); - auto options = globalOptions["2field"]; + auto& options = Options::root()["2field"]; // normalisation values nonlinear = options["nonlinear"].withDefault(false); @@ -83,14 +82,12 @@ class TwoField : public PhysicsModel { include_jpar0 = options["include_jpar0"].withDefault(true); jpar_bndry = options["jpar_bndry"].withDefault(0); - eta = options["eta"].withDefault(1e-3); // Normalised resistivity - mu = options["mu"].withDefault(1.e-3); // Normalised vorticity + eta = options["eta"].doc("Normalised resistivity").withDefault(1e-3); + mu = options["mu"].doc("Normalised vorticity").withDefault(1.e-3); phi_flags = options["phi_flags"].withDefault(0); - - int bracket_method; - bracket_method = options["bracket_method"].withDefault(0); - switch (bracket_method) { + + switch (options["bracket_method"].withDefault(0)) { case 0: { bm = BRACKET_STD; output << "\tBrackets: default differencing\n"; @@ -120,11 +117,15 @@ class TwoField : public PhysicsModel { // Normalisation Tenorm = max(Te0, true); - if (Tenorm < 1) + if (Tenorm < 1) { Tenorm = 1000; + } + Nenorm = max(Ni0, true); - if (Nenorm < 1) + if (Nenorm < 1) { Nenorm = 1.e19; + } + Bnorm = max(coord->Bxy, true); // Sound speed in m/s @@ -254,7 +255,7 @@ class TwoField : public PhysicsModel { return result; } - int rhs(BoutReal UNUSED(t)) override { + int rhs(BoutReal UNUSED(time)) override { // Solve EM fields // U = (1/B) * Delp2(phi) diff --git a/examples/reconnect-2field/data/BOUT.inp b/examples/reconnect-2field/data/BOUT.inp index bb5ab976d6..474dad7f00 100644 --- a/examples/reconnect-2field/data/BOUT.inp +++ b/examples/reconnect-2field/data/BOUT.inp @@ -106,7 +106,7 @@ bracket_method = 2 # Method to use for [f,g] terms # 2 = Arakawa scheme # 3 = Corner Transport Upwind (CTU) -parallel_lc = true # Use quasi-staggered LtoC and CtoL in Y +parallel_lc = false # Use quasi-staggered LtoC and CtoL in Y nonlinear = false # Include nonlinear terms? include_jpar0 = false From ba3feab32d27b182507eb0d5032bdd0f893b8090 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 26 Mar 2019 16:37:43 +0000 Subject: [PATCH 1159/1783] Deprecate no-longer used interface to tridagMatrix The version which returns a matrix of all kz components is not used anywhere. --- include/invert_laplace.hxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index e6a4417208..e26c13010f 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -216,10 +216,10 @@ protected: const Field2D *ccoef = nullptr, const Field2D *d = nullptr, CELL_LOC loc = CELL_DEFAULT); - void tridagMatrix(dcomplex **avec, dcomplex **bvec, dcomplex **cvec, dcomplex **bk, - int jy, int flags, int inner_boundary_flags, int outer_boundary_flags, - const Field2D *a = nullptr, const Field2D *ccoef = nullptr, - const Field2D *d = nullptr); + void DEPRECATED(tridagMatrix(dcomplex **avec, dcomplex **bvec, dcomplex **cvec, + dcomplex **bk, int jy, int flags, int inner_boundary_flags, + int outer_boundary_flags, const Field2D *a = nullptr, + const Field2D *ccoef = nullptr, const Field2D *d = nullptr)); void tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, dcomplex *bk, int jy, int kz, BoutReal kwave, From e0f5f81959591e4faa61a06d7db81364d6fd0288 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 26 Mar 2019 16:40:59 +0000 Subject: [PATCH 1160/1783] Add version of tridagMatrix which takes different C1 and C2 coefficients Original version which takes a single C=C1=C2 is an overload of tridagMatrix which calls the new two-C-argument version, passing C to both. Requires a similarly updated tridagCoefs method. --- include/invert_laplace.hxx | 14 ++++++++++++ src/invert/laplace/invert_laplace.cxx | 33 ++++++++++++++++----------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index e26c13010f..5f22d911b9 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -214,6 +214,11 @@ protected: void tridagCoefs(int jx, int jy, BoutReal kwave, dcomplex &a, dcomplex &b, dcomplex &c, const Field2D *ccoef = nullptr, const Field2D *d = nullptr, + CELL_LOC loc = CELL_DEFAULT) { + tridagCoefs(jx, jy, kwave, a, b, c, ccoef, ccoef, d, loc); + } + void tridagCoefs(int jx, int jy, BoutReal kwave, dcomplex &a, dcomplex &b, dcomplex &c, + const Field2D *c1coef, const Field2D *c2coef, const Field2D *d, CELL_LOC loc = CELL_DEFAULT); void DEPRECATED(tridagMatrix(dcomplex **avec, dcomplex **bvec, dcomplex **cvec, @@ -226,6 +231,15 @@ protected: int flags, int inner_boundary_flags, int outer_boundary_flags, const Field2D *a, const Field2D *ccoef, const Field2D *d, + bool includeguards=true) { + tridagMatrix(avec, bvec, cvec, bk, jy, kz, kwave, flags, inner_boundary_flags, + outer_boundary_flags, a, ccoef, ccoef, d, includeguards); + } + void tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, + dcomplex *bk, int jy, int kz, BoutReal kwave, + int flags, int inner_boundary_flags, int outer_boundary_flags, + const Field2D *a, const Field2D *c1coef, const Field2D *c2coef, + const Field2D *d, bool includeguards=true); CELL_LOC location; ///< staggered grid location of this solver Mesh* localmesh; ///< Mesh object for this solver diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index ce41620fdd..6bfbf2b8c6 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -255,12 +255,12 @@ void Laplacian::tridagCoefs(int jx, int jy, int jz, void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, dcomplex &a, dcomplex &b, dcomplex &c, - const Field2D *ccoef, const Field2D *d, - CELL_LOC loc) { + const Field2D *c1coef, const Field2D *c2coef, + const Field2D *d, CELL_LOC loc) { /* Function: Laplacian::tridagCoef * Purpose: - Set the matrix components of A in Ax=b, solving * - * D*Laplace_perp(x) + (1/C)Grad_perp(C)*Grad_perp(x) + Ax = B + * D*Laplace_perp(x) + (1/C1)Grad_perp(C2)*Grad_perp(x) + Ax = B * * for each fourier component. * NOTE: A in the equation above is not added here. @@ -275,13 +275,15 @@ void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, * a - Lower diagonal of the tridiagonal matrix. DO NOT CONFUSE WITH A * b - The main diagonal * c - The upper diagonal. DO NOT CONFUSE WITH C (called ccoef here) - * ccoef - C in the equation above. DO NOT CONFUSE WITH c + * c1coef - C1 in the equation above. DO NOT CONFUSE WITH c + * c2coef - C2 in the equation above. DO NOT CONFUSE WITH c * d - D in the equation above * * Output: * a - Lower diagonal of the tridiagonal matrix. DO NOT CONFUSE WITH A * b - The main diagonal - * c - The upper diagonal. DO NOT CONFUSE WITH C (called ccoef here) + * c - The upper diagonal. DO NOT CONFUSE WITH C1, C2 (called c1coef, c2coef + * here) */ Coordinates* localcoords; @@ -292,7 +294,10 @@ void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, localcoords = localmesh->getCoordinates(loc); } - ASSERT1(ccoef == nullptr || ccoef->getLocation() == loc); + ASSERT1(c1coef == nullptr || c1coef->getLocation() == loc); + ASSERT1(c2coef == nullptr || c2coef->getLocation() == loc); + ASSERT1( (c1coef == nullptr and c2coef == nullptr) + or (c1coef != nullptr and c2coef != nullptr) ); ASSERT1(d == nullptr || d->getLocation() == loc); BoutReal coef1, coef2, coef3, coef4, coef5; @@ -325,10 +330,10 @@ void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, } } - if (ccoef != nullptr) { + if (c1coef != nullptr) { // A first order derivative term if((jx > 0) && (jx < (localmesh->LocalNx-1))) - coef4 += localcoords->g11(jx,jy) * ((*ccoef)(jx+1,jy) - (*ccoef)(jx-1,jy)) / (2.*localcoords->dx(jx,jy)*((*ccoef)(jx,jy))); + coef4 += localcoords->g11(jx,jy) * ((*c2coef)(jx+1,jy) - (*c2coef)(jx-1,jy)) / (2.*localcoords->dx(jx,jy)*((*c1coef)(jx,jy))); } if(localmesh->IncIntShear) { @@ -379,7 +384,7 @@ void Laplacian::tridagMatrix(dcomplex **avec, dcomplex **bvec, dcomplex **cvec, * This function will * 1. Calling tridagCoef, solving * - * D*Laplace_perp(x) + (1/C)Grad_perp(C)*Grad_perp(x) + Ax = B + * D*Laplace_perp(x) + (1/C1)Grad_perp(C2)*Grad_perp(x) + Ax = B * * for each fourier component * 2. Set the boundary conditions by setting the first and last rows @@ -399,7 +404,8 @@ void Laplacian::tridagMatrix(dcomplex **avec, dcomplex **bvec, dcomplex **cvec, * \param[in] inner_boundary_flags Flags used to set the inner boundary * \param[in] outer_boundary_flags Flags used to set the outer boundary * \param[in] a A in the equation above. DO NOT CONFUSE WITH avec - * \param[in] ccoef C in the equation above. DO NOT CONFUSE WITH cvec + * \param[in] c1coef C1 in the equation above. DO NOT CONFUSE WITH cvec + * \param[in] c2coef C2 in the equation above. DO NOT CONFUSE WITH cvec * \param[in] d D in the equation above * \param[in] includeguards Whether or not the guard points in x should be used * @@ -412,12 +418,13 @@ void Laplacian::tridagMatrix(dcomplex **avec, dcomplex **bvec, dcomplex **cvec, void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, dcomplex *bk, int jy, int kz, BoutReal kwave, int global_flags, int inner_boundary_flags, int outer_boundary_flags, - const Field2D *a, const Field2D *ccoef, + const Field2D *a, const Field2D *c1coef, const Field2D *c2coef, const Field2D *d, bool includeguards) { ASSERT1(a->getLocation() == location); - ASSERT1(ccoef->getLocation() == location); + ASSERT1(c1coef->getLocation() == location); + ASSERT1(c2coef->getLocation() == location); ASSERT1(d->getLocation() == location); int xs = 0; // xstart set to the start of x on this processor (including ghost points) @@ -451,7 +458,7 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, // The boundaries will be set according to the if-statements below. for(int ix=0;ix<=ncx;ix++) { // Actually set the metric coefficients - tridagCoefs(xs+ix, jy, kwave, avec[ix], bvec[ix], cvec[ix], ccoef, d); + tridagCoefs(xs+ix, jy, kwave, avec[ix], bvec[ix], cvec[ix], c1coef, c2coef, d); if (a != nullptr) // Add A to bvec (the main diagonal in the matrix) bvec[ix] += (*a)(xs+ix,jy); From a5d69c46ce02032bfd81222b5c483256e5cf74fb Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 26 Mar 2019 16:43:41 +0000 Subject: [PATCH 1161/1783] CyclicLaplace accepts separate C1 and C2 coefficients --- .../laplace/impls/cyclic/cyclic_laplace.cxx | 13 +++++++------ .../laplace/impls/cyclic/cyclic_laplace.hxx | 15 +++++++++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index bf74c55b77..c29747b5d3 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -45,9 +45,10 @@ #include "cyclic_laplace.hxx" LaplaceCyclic::LaplaceCyclic(Options *opt, const CELL_LOC loc, Mesh *mesh_in) - : Laplacian(opt, loc, mesh_in), Acoef(0.0), Ccoef(1.0), Dcoef(1.0) { + : Laplacian(opt, loc, mesh_in), Acoef(0.0), C1coef(1.0), C2coef(1.0), Dcoef(1.0) { Acoef.setLocation(location); - Ccoef.setLocation(location); + C1coef.setLocation(location); + C2coef.setLocation(location); Dcoef.setLocation(location); // Get options @@ -150,7 +151,7 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) kz, // wave number index kwave, // kwave (inverse wave length) global_flags, inner_boundary_flags, outer_boundary_flags, &Acoef, - &Ccoef, &Dcoef, + &C1coef, &C2coef, &Dcoef, false); // Don't include guard cells in arrays } } @@ -215,7 +216,7 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) kz, // True for the component constant (DC) in Z kwave, // Z wave number global_flags, inner_boundary_flags, outer_boundary_flags, &Acoef, - &Ccoef, &Dcoef, + &C1coef, &C2coef, &Dcoef, false); // Don't include guard cells in arrays } } @@ -346,7 +347,7 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { kz, // wave number index kwave, // kwave (inverse wave length) global_flags, inner_boundary_flags, outer_boundary_flags, &Acoef, - &Ccoef, &Dcoef, + &C1coef, &C2coef, &Dcoef, false); // Don't include guard cells in arrays } } @@ -424,7 +425,7 @@ const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { kz, // True for the component constant (DC) in Z kwave, // Z wave number global_flags, inner_boundary_flags, outer_boundary_flags, &Acoef, - &Ccoef, &Dcoef, + &C1coef, &C2coef, &Dcoef, false); // Don't include guard cells in arrays } } diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx index 02236f7e3b..356793dc67 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx @@ -55,9 +55,20 @@ public: } using Laplacian::setCoefC; void setCoefC(const Field2D &val) override { + setCoefC1(val); + setCoefC2(val); + } + using Laplacian::setCoefC1; + void setCoefC1(const Field2D &val) override { + ASSERT1(val.getLocation() == location); + ASSERT1(localmesh == val.getMesh()); + C1coef = val; + } + using Laplacian::setCoefC2; + void setCoefC2(const Field2D &val) override { ASSERT1(val.getLocation() == location); ASSERT1(localmesh == val.getMesh()); - Ccoef = val; + C2coef = val; } using Laplacian::setCoefD; void setCoefD(const Field2D &val) override { @@ -81,7 +92,7 @@ public: const Field3D solve(const Field3D &b) override {return solve(b,b);} const Field3D solve(const Field3D &b, const Field3D &x0) override; private: - Field2D Acoef, Ccoef, Dcoef; + Field2D Acoef, C1coef, C2coef, Dcoef; int nmode; // Number of modes being solved int xs, xe; // Start and end X indices From 93407cd699c73d25596c6c938f6bcdc20beb9897 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 26 Mar 2019 16:49:16 +0000 Subject: [PATCH 1162/1783] LaplaceNaulin passes DC parts of the C1/C2 coefficients to direct sub-solver This ensures that LaplaceNaulin converges in one step when solving with constant-in-z coefficients. Hopefully it is also slightly more efficient, as the direct solver gets closer to the true solution. --- .../laplace/impls/naulin/naulin_laplace.cxx | 33 +++++++++++++++---- tests/integrated/test-naulin-laplace/runtest | 1 - 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index a216d9de70..b2bc1491f6 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -175,17 +175,38 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { Field3D x(x0); // Result Field3D rhsOverD = rhs/Dcoef; - Field3D ddx_c = DDX(C2coef, location, DIFF_C2); - Field3D ddz_c = DDZ(C2coef, location, DIFF_FFT); - Field3D oneOverC1coefTimesDcoef = 1./C1coef/Dcoef; + + // x-component of 1./(C1*D) * Grad_perp(C2) + Field3D coef_x = DDX(C2coef, location, DIFF_C2)/C1coef/Dcoef; + + // z-component of 1./(C1*D) * Grad_perp(C2) + Field3D coef_z = DDZ(C2coef, location, DIFF_FFT)/C1coef/Dcoef; + Field3D AOverD = Acoef/Dcoef; - // Split A into DC and AC parts so that delp2solver can use DC part. + + // Split coefficients into DC and AC parts so that delp2solver can use DC part. // This allows all-Neumann boundary conditions as long as AOverD_DC is non-zero + + Field2D C1coefTimesD_DC = DC(C1coef*Dcoef); + Field2D C2coef_DC = DC(C2coef); + + // Our naming is slightly misleading here, as coef_x_AC may actually have a + // DC component, as the AC components of C2coef and C1coefTimesD are not + // necessarily in phase. + // This is the piece that cannot be passed to an FFT-based Laplacian solver + // (through our current interface). + Field3D coef_x_AC = coef_x - DDX(C2coef_DC, location, DIFF_C2)/C1coefTimesD_DC; + + // coef_z is a z-derivative so must already have zero DC component + Field2D AOverD_DC = DC(AOverD); Field3D AOverD_AC = AOverD - AOverD_DC; + delp2solver->setCoefA(AOverD_DC); + delp2solver->setCoefC1(C1coefTimesD_DC); + delp2solver->setCoefC2(C2coef_DC); // Use this below to normalize error for relative error estimate BoutReal RMS_rhsOverD = sqrt(mean(SQ(rhsOverD), true, RGN_NOBNDRY)); // use sqrt(mean(SQ)) to make sure we do not divide by zero at a point @@ -196,7 +217,7 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { // Initial values for derivatives of x Field3D ddx_x = DDX(x, location, DIFF_C2); Field3D ddz_x = DDZ(x, location, DIFF_FFT); - Field3D b = rhsOverD - (coords->g11*ddx_c*ddx_x + coords->g33*ddz_c*ddz_x + coords->g13*(ddx_c*ddz_x + ddz_c*ddx_x))*oneOverC1coefTimesDcoef - AOverD_AC*x; + Field3D b = rhsOverD - (coords->g11*coef_x_AC*ddx_x + coords->g33*coef_z*ddz_x + coords->g13*(coef_x_AC*ddz_x + coef_z*ddx_x)) - AOverD_AC*x; while (error_rel>rtol && error_abs>atol) { @@ -213,7 +234,7 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { // Use here to calculate an error, can also use for the next iteration ddx_x = DDX(x, location, DIFF_C2); // can be used also for the next iteration ddz_x = DDZ(x, location, DIFF_FFT); - Field3D bnew = rhsOverD - (coords->g11*ddx_c*ddx_x + coords->g33*ddz_c*ddz_x + coords->g13*(ddx_c*ddz_x + ddz_c*ddx_x))*oneOverC1coefTimesDcoef - AOverD_AC*x; + Field3D bnew = rhsOverD - (coords->g11*coef_x_AC*ddx_x + coords->g33*coef_z*ddz_x + coords->g13*(coef_x_AC*ddz_x + coef_z*ddx_x)) - AOverD_AC*x; Field3D error3D = b - bnew; error_abs = max(abs(error3D, RGN_NOBNDRY), true, RGN_NOBNDRY); diff --git a/tests/integrated/test-naulin-laplace/runtest b/tests/integrated/test-naulin-laplace/runtest index e9ac4bc300..078e523e15 100755 --- a/tests/integrated/test-naulin-laplace/runtest +++ b/tests/integrated/test-naulin-laplace/runtest @@ -20,7 +20,6 @@ from sys import exit print("Making LaplaceNaulin inversion test") -shell("rm test_naulin_laplace") shell_safe("make > make.log") print("Running LaplaceNaulin inversion test") From dedcdd669e5004514568162b43bb055c3687e6ce Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 27 Mar 2019 10:02:13 +0000 Subject: [PATCH 1163/1783] Add some documentation to manual Use `.doc` method in a few places in `Solver` and `Laplacian`, to start adding documentation to the output `BOUT.settings`. --- examples/blob2d/blob2d.cxx | 8 ++--- manual/sphinx/user_docs/bout_options.rst | 43 ++++++++++++++++++++---- src/invert/laplace/invert_laplace.cxx | 19 ++++++----- src/solver/solver.cxx | 31 ++++++++++------- 4 files changed, 70 insertions(+), 31 deletions(-) diff --git a/examples/blob2d/blob2d.cxx b/examples/blob2d/blob2d.cxx index 360e743edc..51af7ecc20 100644 --- a/examples/blob2d/blob2d.cxx +++ b/examples/blob2d/blob2d.cxx @@ -54,18 +54,18 @@ class Blob2D : public PhysicsModel { auto& options = globalOptions["model"]; // Load system parameters - Te0 = options["Te0"].doc("Temperature in eV").withDefault(30); + Te0 = options["Te0"].doc("Temperature in eV").withDefault(30.0); e = options["e"].withDefault(1.602e-19); m_i = options["m_i"].withDefault(2 * 1.667e-27); m_e = options["m_e"].withDefault(9.11e-31); n0 = options["n0"].doc("Background density in cubic m").withDefault(1e19); - D_vort = options["D_vort"].doc("Viscous diffusion coefficient").withDefault(0); - D_n = options["D_n"].doc("Density diffusion coefficient").withDefault(0); + D_vort = options["D_vort"].doc("Viscous diffusion coefficient").withDefault(0.0); + D_n = options["D_n"].doc("Density diffusion coefficient").withDefault(0.0); R_c = options["R_c"].doc("Radius of curvature").withDefault(1.5); - L_par = options["L_par"].doc("Parallel connection length").withDefault(10); + L_par = options["L_par"].doc("Parallel connection length").withDefault(10.0); B0 = options["B0"].doc("Value of magnetic field strength").withDefault(0.35); diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index c88edb9567..33c84bf3cb 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -444,17 +444,20 @@ tree structure there is the `Options` class defined in To access the options, there is a static function (singleton):: - auto options = Options::root(); + auto& options = Options::root(); -which returns a reference (type ``Options&``). Options can be set by +which returns a reference (type ``Options&``). Note that without +the ``&`` the options tree will be copied, so any changes made will not +be retained in the global tree. Options can be set by assigning, treating options as a map or dictionary:: options["nout"] = 10; // Integer options["restart"] = true; // bool -Internally these values are converted to strings. Any type can be -assigned, so long as it can be streamed to a string (using ``<<`` -operator and a ``std::stringstream``). +Internally these values are stored in a variant type, which supports commonly +used types including strings, integers, real numbers and fields (2D and +3D). Since strings can be stored, any type can be assigned, so long as it can be +streamed to a string (using ``<<`` operator and a ``std::stringstream``). Often it’s useful to see where an option setting has come from e.g. the name of the options file or “command line”. To specify a source, use @@ -473,7 +476,7 @@ any):: Sub-sections are created as they are accessed, so a value in a sub-section could be set using:: - auto section = options["mysection"]; + auto& section = options["mysection"]; section["myswitch"] = true; or just:: @@ -495,6 +498,15 @@ cached. If a default value has already been cached for this option, then the default values must be consistent: A ``BoutException`` is thrown if inconsistent default values are detected. +Note that if the result should be a real number (e.g. ``BoutReal``) then ``withDefault`` +should be given a real. Otherwise it will convert the number to an integer:: + + BoutReal value = options["value"].withDefault(42); // Convert to integer + + BoutReal value = options["value"].withDefault(42.0); // ok + + auto value = options["value"].withDefault(42); // ok + It is common for BOUT++ models to read in many settings which have the same variable name as option setting (e.g. "nout" here). A convenient macro reads options into an already-defined variable:: @@ -526,11 +538,28 @@ inferred from the argument:: BoutReal nout = options["nout"].withDefault(1); +Documentation +~~~~~~~~~~~~~ + +Options can be given a ``doc`` attribute describing what they do. This documentation +will then be written to the ``BOUT.settings`` file at the end of a run:: + + Te0 = options["Te0"].doc("Temperature in eV").withDefault(30.0); + +The ``.doc()`` function returns a reference ``Options&`` so can be chained +with ``withDefault`` or ``as`` functions, or as part of an assignment:: + + options["value"].doc("Useful setting info") = 42; + +This string is stored in the attributes of the option:: + + std::string docstring = options["value"].attributes["doc"]; + Older interface ~~~~~~~~~~~~~~~ -Most code in BOUT++ currently uses an older interface to ``Options`` +Some code in BOUT++ currently uses an older interface to ``Options`` which uses pointers rather than references. Both interfaces are currently supported, but use of the newer interface above is encouraged. diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index ce41620fdd..53ee91e4e5 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -69,10 +69,11 @@ Laplacian::Laplacian(Options *options, const CELL_LOC loc, Mesh *mesh_in) coords = localmesh->getCoordinates(location); // Communication option. Controls if asyncronous sends are used - options->get("async", async_send, true); + async_send = (*options)["async"].doc("Use asyncronous MPI send?").withDefault(true); - BoutReal filter; ///< Fraction of Z modes to filter out. Between 0 and 1 - OPTION(options, filter, 0.0); + BoutReal filter = (*options)["filter"] + .doc("Fraction of Z modes to filter out. Between 0 and 1") + .withDefault(0.0); int ncz = localmesh->LocalNz; // convert filtering into an integer number of modes maxmode = ROUND((1.0 - filter) * static_cast(ncz / 2)); @@ -83,17 +84,19 @@ Laplacian::Laplacian(Options *options, const CELL_LOC loc, Mesh *mesh_in) OPTION(options, low_mem, false); - OPTION(options, nonuniform, - coords->non_uniform); // Default is the mesh setting + nonuniform = (*options)["nonuniform"] + .doc("Use non-uniform grid corrections? Default is the mesh setting.") + .withDefault(coords->non_uniform); - OPTION(options, all_terms, true); // Include first derivative terms + all_terms = (*options)["all_terms"].doc("Include first derivative terms?").withDefault(true); if (options->isSet("flags")) { if ( options->isSet("global_flags") || options->isSet("inner_boundary_flags") || options->isSet("outer_boundary_flags") ) { throw BoutException("Should not use old flags as well as new global_flags/inner_boundary_flags/outer_boundary_flags"); } - int flags; - OPTION(options, flags, 0); + int flags = (*options)["flags"] + .doc("Flags to control inner and outer boundaries.") + .withDefault(0); setFlags(flags); } else { diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 16f959a637..362332485d 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -479,16 +479,20 @@ void Solver::constraint(Vector3D &v, Vector3D &C_v, const std::string name) { int Solver::solve(int NOUT, BoutReal TIMESTEP) { - Options *globaloptions = Options::getRoot(); // Default from global options + Options& globaloptions = Options::root(); // Default from global options if(NOUT < 0) { /// Get options - OPTION(globaloptions, NOUT, 1); - OPTION(globaloptions, TIMESTEP, 1.0); + NOUT = globaloptions["NOUT"].doc("Number of output steps").withDefault(1); + TIMESTEP = globaloptions["TIMESTEP"].doc("Output time step size").withDefault(1.0); // Check specific solver options, which override global options - OPTION(options, NOUT, NOUT); - options->get("output_step", TIMESTEP, TIMESTEP); + NOUT = (*options)["NOUT"] + .doc("Number of output steps. Overrides global setting.") + .withDefault(NOUT); + TIMESTEP = (*options)["output_step"] + .doc("Output time step size. Overrides global TIMESTEP setting.") + .withDefault(TIMESTEP); } /// syncronize timestep with those set to the monitors @@ -535,13 +539,16 @@ int Solver::solve(int NOUT, BoutReal TIMESTEP) { output_progress.write(_("\nRun started at : %s\n"), toString(start_time).c_str()); Timer timer("run"); // Start timer - - bool restart; - OPTION(globaloptions, restart, false); - bool append; - OPTION(globaloptions, append, false); - bool dump_on_restart; - OPTION(globaloptions, dump_on_restart, !restart || !append); + + bool restart = globaloptions["restart"] + .doc("Load state from restart files?").withDefault(false); + + bool append = globaloptions["append"] + .doc("Add new outputs to the end of existing files? If false, overwrite files.") + .withDefault(false); + bool dump_on_restart = globaloptions["dump_on_restart"] + .doc("Write initial state as time point 0?") + .withDefault(!restart || !append); if ( dump_on_restart ) { /// Write initial state as time-point 0 From e441d890249ba658ea6224d324186500ec43fc90 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 11:45:18 +0000 Subject: [PATCH 1164/1783] Explicitly call boutcore.finalise in boutcore tests --- tests/integrated/test-boutcore/collect-staggered/runtest | 1 + tests/integrated/test-boutcore/collect/runtest | 2 ++ tests/integrated/test-boutcore/legacy-model/runtest | 2 ++ tests/integrated/test-boutcore/mms-ddz/runtest | 2 ++ tests/integrated/test-boutcore/simple-model/runtest | 1 + 5 files changed, 8 insertions(+) diff --git a/tests/integrated/test-boutcore/collect-staggered/runtest b/tests/integrated/test-boutcore/collect-staggered/runtest index 6767618531..aab2ccd93e 100755 --- a/tests/integrated/test-boutcore/collect-staggered/runtest +++ b/tests/integrated/test-boutcore/collect-staggered/runtest @@ -45,5 +45,6 @@ if compare(fc,fo) > 1e-3: print("Something is wrong. Maybe setting the location from field failed.") fail=1 +bc.finalise() exit(fail) diff --git a/tests/integrated/test-boutcore/collect/runtest b/tests/integrated/test-boutcore/collect/runtest index 52d88e3aa5..2d4def3d77 100755 --- a/tests/integrated/test-boutcore/collect/runtest +++ b/tests/integrated/test-boutcore/collect/runtest @@ -48,3 +48,5 @@ if not ((p==pn).all()): errorlist+="multiplication not working\n" print(p.shape) print(pn.shape) + +bc.finalise() diff --git a/tests/integrated/test-boutcore/legacy-model/runtest b/tests/integrated/test-boutcore/legacy-model/runtest index ade2766e35..acf6eee1eb 100755 --- a/tests/integrated/test-boutcore/legacy-model/runtest +++ b/tests/integrated/test-boutcore/legacy-model/runtest @@ -18,3 +18,5 @@ model=boutcore.PhysicsModelBase() model.setRhs(rhs) model.solve_for(n=dens) model.solve() + +boutcore.finalise() diff --git a/tests/integrated/test-boutcore/mms-ddz/runtest b/tests/integrated/test-boutcore/mms-ddz/runtest index c405aec57c..6af0ede2b9 100755 --- a/tests/integrated/test-boutcore/mms-ddz/runtest +++ b/tests/integrated/test-boutcore/mms-ddz/runtest @@ -34,6 +34,8 @@ errc=np.log(errors[-2]/errors[-1]) difc=np.log(nzs[-1]/nzs[-2]) conv=errc/difc +boutcore.finalise() + if 1.9 < conv < 2.1: print("The convergence is: %f"%conv) else: diff --git a/tests/integrated/test-boutcore/simple-model/runtest b/tests/integrated/test-boutcore/simple-model/runtest index d716090877..cc25f8049b 100755 --- a/tests/integrated/test-boutcore/simple-model/runtest +++ b/tests/integrated/test-boutcore/simple-model/runtest @@ -16,3 +16,4 @@ class MyModel(PhysicsModel): model=MyModel() model.solve() +finalise() From 07af6ec248b34b1aeadae392c4437f5834c5fe1b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 11:50:55 +0000 Subject: [PATCH 1165/1783] Allow a space in `# requires` comments for test suite --- tests/requirements/requirements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/requirements/requirements.py b/tests/requirements/requirements.py index 1139f0877d..fe3c54752a 100755 --- a/tests/requirements/requirements.py +++ b/tests/requirements/requirements.py @@ -74,7 +74,7 @@ def check(self, script): # Find all lines starting with '#requires' or '#Requires:' match = re.findall( - "^\s*\#[Rr]equires:?(.*)", contents, re.MULTILINE) + "^\s*\#\s?[Rr]equires:?(.*)", contents, re.MULTILINE) # Iterate over all expressions to evaluate for expr in match: try: From 0d47d7c87baf881fdb3b6534ee71fa7d039acd55 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 11:51:22 +0000 Subject: [PATCH 1166/1783] Auto-pep8 boutcore tests --- .../test-boutcore/collect-staggered/runtest | 46 ++++++++-------- .../integrated/test-boutcore/collect/runtest | 54 +++++++++---------- .../test-boutcore/legacy-model/runtest | 16 +++--- .../integrated/test-boutcore/mms-ddz/runtest | 54 +++++++++---------- .../test-boutcore/simple-model/runtest | 15 +++--- 5 files changed, 95 insertions(+), 90 deletions(-) diff --git a/tests/integrated/test-boutcore/collect-staggered/runtest b/tests/integrated/test-boutcore/collect-staggered/runtest index aab2ccd93e..9ad329e41a 100755 --- a/tests/integrated/test-boutcore/collect-staggered/runtest +++ b/tests/integrated/test-boutcore/collect-staggered/runtest @@ -1,49 +1,51 @@ #!/usr/bin/env python3 import boutcore as bc -#requires boutcore -#requires not make +# requires boutcore +# requires not make bc.init("-q -q -q") -fail=0 -f=bc.create3D("sin(y)",outloc='YLOW') +fail = 0 +f = bc.create3D("sin(y)", outloc='YLOW') -dump=bc.Datafile() # get global :( -dump.add(f3d_evolve=f,save_repeat=True) -dump.add(f3d_once=f,save_repeat=False) +dump = bc.Datafile() # get global :( +dump.add(f3d_evolve=f, save_repeat=True) +dump.add(f3d_once=f, save_repeat=False) dump.write() -fc=bc.create3D("sin(y)",outloc='CENTRE') +fc = bc.create3D("sin(y)", outloc='CENTRE') -fe=bc.Field3D.fromCollect("f3d_evolve",path='data',info=False) -fo=bc.Field3D.fromCollect("f3d_once",path='data',info=False) +fe = bc.Field3D.fromCollect("f3d_evolve", path='data', info=False) +fo = bc.Field3D.fromCollect("f3d_once", path='data', info=False) if fe.getLocation() == fc.getLocation(): print("The loaded field should not be at CELL_CENTRE") - fail=1 - + fail = 1 + if fo.getLocation() == fc.getLocation(): print("The loaded field should not be at CELL_CENTRE") - fail=1 + fail = 1 + -def compare(a,b): - diff=a-bc.interp_to(b,a.getLocation()) - err=bc.max(bc.sqrt(diff*diff)) +def compare(a, b): + diff = a-bc.interp_to(b, a.getLocation()) + err = bc.max(bc.sqrt(diff*diff)) return err -if compare(fc,f) > 1e-3: + +if compare(fc, f) > 1e-3: print("Something is wrong. Maybe interpolation is broken") - fail=1 + fail = 1 -if compare(fc,fe) > 1e-3: +if compare(fc, fe) > 1e-3: print("Something is wrong. Maybe setting the location from field failed.") - fail=1 + fail = 1 -if compare(fc,fo) > 1e-3: +if compare(fc, fo) > 1e-3: print("Something is wrong. Maybe setting the location from field failed.") - fail=1 + fail = 1 bc.finalise() diff --git a/tests/integrated/test-boutcore/collect/runtest b/tests/integrated/test-boutcore/collect/runtest index 2d4def3d77..f9661ef262 100755 --- a/tests/integrated/test-boutcore/collect/runtest +++ b/tests/integrated/test-boutcore/collect/runtest @@ -3,49 +3,47 @@ import boutcore as bc import numpy as np from boutdata import collect -#requires boutcore -#requires not make +# requires boutcore +# requires not make bc.init("-d input".split(" ")) -f=bc.Field3D.fromMesh(None) +f = bc.Field3D.fromMesh(None) f.setAll(np.array([[[1.]]])) -f2=bc.Field3D.fromMesh(None) +f2 = bc.Field3D.fromMesh(None) f2.setAll(np.array([[[2.]]])) print(f.getAll()) -dump=bc.Datafile() # get global :( -dump.add(f3d=f,f2d=f2,save_repeat=True) +dump = bc.Datafile() # get global :( +dump.add(f3d=f, f2d=f2, save_repeat=True) dump.write() -errorlist="" -n=collect("f2d",path='input',tind=-1,yguards=True) +errorlist = "" +n = collect("f2d", path='input', tind=-1, yguards=True) print(n.shape) -T=collect("f3d",path='input',tind=-1,yguards=True) +T = collect("f3d", path='input', tind=-1, yguards=True) print(n.shape) print("initialized mesh") -mesh=bc.Mesh.getGlobal(); +mesh = bc.Mesh.getGlobal() print("initialized mesh") -dens=bc.Field3D.fromMesh(mesh) -dens[:,:,:]=n.reshape((1,1,1)) -temp=bc.Field3D.fromCollect("f3d",path="input") -pres=dens+temp -print(slice(None,None,-2).indices(5)) -p=pres[::5,0,::-2] -pn=(n+T) -pn=pn.reshape(p.shape) -#print(p [::50,::10,::20]) -#print(pn[::50,::10,::20]) -if not ((p==pn).all()): - errorlist+="addition not working\n" -pres=dens*temp*1 -p=pres.getAll() -pn=n*T -pn=pn.reshape(p.shape) -if not ((p==pn).all()): - errorlist+="multiplication not working\n" +dens = bc.Field3D.fromMesh(mesh) +dens[:, :, :] = n.reshape((1, 1, 1)) +temp = bc.Field3D.fromCollect("f3d", path="input") +pres = dens+temp +print(slice(None, None, -2).indices(5)) +p = pres[::5, 0, ::-2] +pn = (n+T) +pn = pn.reshape(p.shape) +if not ((p == pn).all()): + errorlist += "addition not working\n" +pres = dens*temp*1 +p = pres.getAll() +pn = n*T +pn = pn.reshape(p.shape) +if not ((p == pn).all()): + errorlist += "multiplication not working\n" print(p.shape) print(pn.shape) diff --git a/tests/integrated/test-boutcore/legacy-model/runtest b/tests/integrated/test-boutcore/legacy-model/runtest index acf6eee1eb..bd40d14aed 100755 --- a/tests/integrated/test-boutcore/legacy-model/runtest +++ b/tests/integrated/test-boutcore/legacy-model/runtest @@ -2,19 +2,21 @@ import boutcore import sys -#requires boutcore -#requires not make +# requires boutcore +# requires not make boutcore.init(sys.argv[1:]) -dens=boutcore.create3D("0") +dens = boutcore.create3D("0") + def rhs(time): - n_ddt=dens.ddt() - n_ddt[:,:,:]=dens*0 - n_ddt+=1 + n_ddt = dens.ddt() + n_ddt[:, :, :] = dens*0 + n_ddt += 1 + -model=boutcore.PhysicsModelBase() +model = boutcore.PhysicsModelBase() model.setRhs(rhs) model.solve_for(n=dens) model.solve() diff --git a/tests/integrated/test-boutcore/mms-ddz/runtest b/tests/integrated/test-boutcore/mms-ddz/runtest index 6af0ede2b9..43816e3469 100755 --- a/tests/integrated/test-boutcore/mms-ddz/runtest +++ b/tests/integrated/test-boutcore/mms-ddz/runtest @@ -2,45 +2,45 @@ import boutcore import numpy as np -#requires boutcore -#requires not make - -errorlist="" -boutcore.init("-d data -q -q -q")#+" -f BOUT.settings") - -shapes=[] -errors=[] -mmax=7 -start=6 -doPlot=False -nzs=np.logspace(start,mmax,num=mmax-start+1,base=2) +# requires boutcore +# requires not make + +errorlist = "" +boutcore.init("-d data -q -q -q") # +" -f BOUT.settings") + +shapes = [] +errors = [] +mmax = 7 +start = 6 +doPlot = False +nzs = np.logspace(start, mmax, num=mmax-start+1, base=2) for nz in nzs: - boutcore.setOption("meshz:nz","%d"%nz,force=True) - boutcore.setOption("meshz:dz","2*Pi/%d"%nz,force=True)#%.30g"%(2*np.pi/nz))# better pass calculation to bout ... - mesh=boutcore.Mesh(section="meshz") - f=boutcore.create3D("sin(z)",mesh) - sim=boutcore.DDZ(f) - ana=boutcore.create3D("cos(z)",mesh) - err=sim-ana - err=np.max(np.abs(err.getAll())) + boutcore.setOption("meshz:nz", "%d" % nz, force=True) + boutcore.setOption("meshz:dz", "2*Pi/%d" % nz, force=True) + mesh = boutcore.Mesh(section="meshz") + f = boutcore.create3D("sin(z)", mesh) + sim = boutcore.DDZ(f) + ana = boutcore.create3D("cos(z)", mesh) + err = sim-ana + err = np.max(np.abs(err.getAll())) errors.append(err) if doPlot: from matplotlib import pyplot as plt - plt.plot(1/np.array(nzs),errors,'-o') + plt.plot(1/np.array(nzs), errors, '-o') plt.show() -errc=np.log(errors[-2]/errors[-1]) -difc=np.log(nzs[-1]/nzs[-2]) -conv=errc/difc +errc = np.log(errors[-2]/errors[-1]) +difc = np.log(nzs[-1]/nzs[-2]) +conv = errc/difc boutcore.finalise() if 1.9 < conv < 2.1: - print("The convergence is: %f"%conv) + print("The convergence is: %f" % conv) else: - errorlist+="DDZ is not working\n" + errorlist += "DDZ is not working\n" if errorlist != "": - print("Found errors:\n%s"%errorlist) + print("Found errors:\n%s" % errorlist) exit(1) diff --git a/tests/integrated/test-boutcore/simple-model/runtest b/tests/integrated/test-boutcore/simple-model/runtest index cc25f8049b..472e3ac774 100755 --- a/tests/integrated/test-boutcore/simple-model/runtest +++ b/tests/integrated/test-boutcore/simple-model/runtest @@ -1,19 +1,22 @@ #!/usr/bin/env python3 -#requires boutcore -#requires not make +# requires boutcore +# requires not make from boutcore import * init("-d mini") + class MyModel(PhysicsModel): - def init(self,restart): - self.n=create3D("dens:function") + def init(self, restart): + self.n = create3D("dens:function") self.solve_for(dens=self.n) - def rhs(self,time): + + def rhs(self, time): self.n.ddt(DDX(self.n)) -model=MyModel() + +model = MyModel() model.solve() finalise() From 59abef33a057a22dc377a23184564a806bd3fd08 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 13:48:57 +0000 Subject: [PATCH 1167/1783] Explicitly delete global mesh in boutcore test --- tests/integrated/test-boutcore/mms-ddz/runtest | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/integrated/test-boutcore/mms-ddz/runtest b/tests/integrated/test-boutcore/mms-ddz/runtest index 43816e3469..f46315621f 100755 --- a/tests/integrated/test-boutcore/mms-ddz/runtest +++ b/tests/integrated/test-boutcore/mms-ddz/runtest @@ -34,6 +34,12 @@ errc = np.log(errors[-2]/errors[-1]) difc = np.log(nzs[-1]/nzs[-2]) conv = errc/difc +# FIXME: this is a workaround for a strange bug, MPI_Comm_free after +# MPI_Finalize. Seems to be from the global mesh getting destroyed +# after/at the same time as finalise is called -- hence explicitly +# deleting it here +mesh = boutcore.Mesh.getGlobal() +del mesh boutcore.finalise() if 1.9 < conv < 2.1: From 25a2eeb445f8ed420b32d59330007b2a2302abb4 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 27 Mar 2019 00:58:40 +0000 Subject: [PATCH 1168/1783] Add FieldPerp to gen_fieldops.py/gen_fieldops.jinja Generate the FieldPerp operators in the same way as the Field3D/Field2D ones. Implements some operators that were previously declared but not implemented. --- include/fieldperp.hxx | 8 +- src/field/fieldperp.cxx | 150 ----- src/field/gen_fieldops.jinja | 30 +- src/field/gen_fieldops.py | 17 +- src/field/generated_fieldops.cxx | 930 +++++++++++++++++++++++++++++-- 5 files changed, 938 insertions(+), 197 deletions(-) diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index abf0ad35de..41381910a4 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -275,9 +275,7 @@ const FieldPerp operator+(const FieldPerp &lhs, const FieldPerp &rhs); const FieldPerp operator+(const FieldPerp &lhs, const Field3D &rhs); const FieldPerp operator+(const FieldPerp &lhs, const Field2D &rhs); const FieldPerp operator+(const FieldPerp &lhs, BoutReal rhs); -inline const FieldPerp operator+(BoutReal lhs, const FieldPerp &rhs) { - return rhs + lhs; -} +const FieldPerp operator+(BoutReal lhs, const FieldPerp &rhs); const FieldPerp operator-(const FieldPerp &lhs, const FieldPerp &other); const FieldPerp operator-(const FieldPerp &lhs, const Field3D &other); @@ -289,9 +287,7 @@ const FieldPerp operator*(const FieldPerp &lhs, const FieldPerp &other); const FieldPerp operator*(const FieldPerp &lhs, const Field3D &other); const FieldPerp operator*(const FieldPerp &lhs, const Field2D &other); const FieldPerp operator*(const FieldPerp &lhs, BoutReal rhs); -inline const FieldPerp operator*(BoutReal lhs, const FieldPerp &rhs) { - return rhs * lhs; -} +const FieldPerp operator*(BoutReal lhs, const FieldPerp &rhs); const FieldPerp operator/(const FieldPerp &lhs, const FieldPerp &other); const FieldPerp operator/(const FieldPerp &lhs, const Field3D &other); diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 7990027b7b..2d6746a86c 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -97,77 +97,6 @@ FieldPerp & FieldPerp::operator=(const BoutReal rhs) { return *this; } -/*************************************************************** - * OPERATORS - ***************************************************************/ - -#define FPERP_OP_FPERP(op, bop) \ - FieldPerp& FieldPerp::operator op(const FieldPerp& rhs) { \ - ASSERT1(areFieldsCompatible(*this, rhs)); \ - if (data.unique()) { \ - checkData(rhs); \ - /* Only reference to the data */ \ - BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] op rhs[i]; } \ - checkData(*this); \ - } else { \ - /* Shared with another FieldPerp */ \ - (*this) = (*this)bop rhs; \ - } \ - return *this; \ - } - -FPERP_OP_FPERP(+=, +); -FPERP_OP_FPERP(-=, -); -FPERP_OP_FPERP(*=, *); -FPERP_OP_FPERP(/=, /); - -#define FPERP_OP_FIELD(op, bop, ftype) \ - FieldPerp& FieldPerp::operator op(const ftype& rhs) { \ - ASSERT1(areFieldsCompatible(*this, rhs)); \ - if (data.unique()) { \ - checkData(*this); \ - checkData(rhs); \ - /* Only reference to the data */ \ - BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] op rhs(i.x(), yindex, i.z()); } \ - checkData(*this); \ - } else { \ - /* Shared with another FieldPerp */ \ - (*this) = (*this)bop rhs; \ - } \ - return *this; \ - } - -FPERP_OP_FIELD(+=, +, Field3D); -FPERP_OP_FIELD(+=, +, Field2D); - -FPERP_OP_FIELD(-=, -, Field3D); -FPERP_OP_FIELD(-=, -, Field2D); - -FPERP_OP_FIELD(*=, *, Field3D); -FPERP_OP_FIELD(*=, *, Field2D); - -FPERP_OP_FIELD(/=, /, Field3D); -FPERP_OP_FIELD(/=, /, Field2D); - -#define FPERP_OP_REAL(op, bop) \ - FieldPerp &FieldPerp::operator op(BoutReal rhs) { \ - if (data.unique()) { \ - checkData(rhs); \ - /* Only reference to the data */ \ - BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] op rhs; } \ - checkData(*this); \ - } else { \ - /* Shared with another FieldPerp */ \ - (*this) = (*this)bop rhs; \ - } \ - return *this; \ - } - -FPERP_OP_REAL(+=, +); -FPERP_OP_REAL(-=, -); -FPERP_OP_REAL(*=, *); -FPERP_OP_REAL(/=, /); - const Region &FieldPerp::getRegion(REGION region) const { return fieldmesh->getRegionPerp(toString(region)); }; @@ -182,85 +111,6 @@ const Region &FieldPerp::getRegion(const std::string ®ion_name) cons // Unary minus FieldPerp operator-(const FieldPerp &f) { return -1.0 * f; } -// Operator on FieldPerp and another field -#define FPERP_FPERP_OP_FPERP(op) \ - const FieldPerp operator op(const FieldPerp& lhs, const FieldPerp& rhs) { \ - ASSERT1(areFieldsCompatible(lhs, rhs)); \ - checkData(lhs); \ - checkData(rhs); \ - FieldPerp result{emptyFrom(lhs)}; \ - \ - BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs[i] op rhs[i]; } \ - checkData(result); \ - return result; \ - } - -FPERP_FPERP_OP_FPERP(+); -FPERP_FPERP_OP_FPERP(-); -FPERP_FPERP_OP_FPERP(*); -FPERP_FPERP_OP_FPERP(/); - -// Operator on FieldPerp and another field -#define FPERP_FPERP_OP_FIELD(op, ftype) \ - const FieldPerp operator op(const FieldPerp& lhs, const ftype& rhs) { \ - ASSERT1(areFieldsCompatible(lhs, rhs)); \ - checkData(lhs); \ - checkData(rhs); \ - FieldPerp result{emptyFrom(lhs)}; \ - \ - BOUT_FOR(i, result.getRegion("RGN_ALL")) { \ - result[i] = lhs[i] op rhs(i.x(), lhs.getIndex(), i.z()); \ - } \ - checkData(result); \ - return result; \ - } - -FPERP_FPERP_OP_FIELD(+, Field3D); -FPERP_FPERP_OP_FIELD(+, Field2D); - -FPERP_FPERP_OP_FIELD(-, Field3D); -FPERP_FPERP_OP_FIELD(-, Field2D); - -FPERP_FPERP_OP_FIELD(*, Field3D); -FPERP_FPERP_OP_FIELD(*, Field2D); - -FPERP_FPERP_OP_FIELD(/, Field3D); -FPERP_FPERP_OP_FIELD(/, Field2D); - -// Operator on FieldPerp and BoutReal -#define FPERP_FPERP_OP_REAL(op) \ - const FieldPerp operator op(const FieldPerp& lhs, BoutReal rhs) { \ - checkData(lhs); \ - checkData(rhs); \ - FieldPerp result{emptyFrom(lhs)}; \ - \ - BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs[i] op rhs; } \ - \ - checkData(result); \ - return result; \ - } - -FPERP_FPERP_OP_REAL(+); -FPERP_FPERP_OP_REAL(-); -FPERP_FPERP_OP_REAL(*); -FPERP_FPERP_OP_REAL(/); - -#define FPERP_REAL_OP_FPERP(op) \ - const FieldPerp operator op(BoutReal lhs, const FieldPerp& rhs) { \ - checkData(lhs); \ - checkData(rhs); \ - FieldPerp result{emptyFrom(rhs)}; \ - \ - BOUT_FOR(i, result.getRegion("RGN_ALL")) { result[i] = lhs op rhs[i]; } \ - \ - checkData(result); \ - return result; \ - } - -// Only need the asymmetric operators -FPERP_REAL_OP_FPERP(-); -FPERP_REAL_OP_FPERP(/); - ///////////////////////////////////////////////// // functions diff --git a/src/field/gen_fieldops.jinja b/src/field/gen_fieldops.jinja index 2f3c9d156c..25e1af328b 100644 --- a/src/field/gen_fieldops.jinja +++ b/src/field/gen_fieldops.jinja @@ -27,6 +27,18 @@ {% endif %} } } + {% elif out == "FieldPerp" and (lhs == "Field2D" or lhs == "Field3D" or rhs == "Field2D" or rhs == "Field3D")%} + Mesh *localmesh = {{lhs.name if lhs.field_type != "BoutReal" else rhs.name}}.getMesh(); + + {{region_loop}}({{index_var}}, {{out.name}}.getRegion({{region_name}})) { + int yind = {{lhs.name if lhs == "FieldPerp" else rhs.name}}.getIndex(); + const auto {{mixed_base_ind}} = localmesh->indPerpto3D({{index_var}}, yind); + {% if lhs != "FieldPerp" %} + {{out.index}} = {{lhs.base_index}} {{operator}} {{rhs.index}}; + {% else %} + {{out.index}} = {{lhs.index}} {{operator}} {{rhs.base_index}}; + {% endif %} + } {% else %} {{region_loop}}({{index_var}}, {{out.name}}.getRegion({{region_name}})) { {{out.index}} = {{lhs.index}} {{operator}} {{rhs.index}}; @@ -50,7 +62,7 @@ checkData(*this); checkData({{rhs.name}}); - {% if (out == "Field3D") and (rhs =="Field2D") %} + {% if (lhs == "Field3D") and (rhs =="Field2D") %} {{region_loop}}({{index_var}}, {{rhs.name}}.getRegion({{region_name}})) { const auto {{mixed_base_ind}} = fieldmesh->ind2Dto3D({{index_var}}); {% if (operator == "/") and (rhs == "Field2D") %} @@ -63,6 +75,22 @@ {% endif %} } } + {% elif lhs == "FieldPerp" and (rhs == "Field3D" or rhs == "Field2D")%} + Mesh *localmesh = this->getMesh(); + + {{region_loop}}({{index_var}}, this->getRegion({{region_name}})) { + int yind = this->getIndex(); + const auto {{mixed_base_ind}} = localmesh->indPerpto3D({{index_var}}, yind); + (*this)[{{index_var}}] {{operator}}= {{rhs.base_index}}; + } + {% elif rhs == "FieldPerp" and (lhs == "Field3D" or lhs == "Field2D")%} + Mesh *localmesh = this->getMesh(); + + {{region_loop}}({{index_var}}, {{rhs.name}}.getRegion({{region_name}})) { + int yind = {{rhs.name}}.getIndex(); + const auto {{mixed_base_ind}} = localmesh->indPerpto3D({{index_var}}, yind); + (*this)[{{base_ind_var}}] {{operator}}= {{rhs.index}}; + } {% else %} {{region_loop}}({{index_var}}, this->getRegion({{region_name}})) { (*this)[{{index_var}}] {{operator}}= {{rhs.index}}; diff --git a/src/field/gen_fieldops.py b/src/field/gen_fieldops.py index 96fc0bb22e..3a5bd97a93 100755 --- a/src/field/gen_fieldops.py +++ b/src/field/gen_fieldops.py @@ -133,6 +133,17 @@ def mixed_index(self): else: # Field2D return "{self.name}[{self.index_var}]".format(self=self) + @property + def base_index(self): + """Returns "[{mixed_base_ind_var}]" if field_type is Field3D, Field2D or FieldPerp + or just returns "" for BoutReal + + """ + if self.field_type == "BoutReal": + return "{self.name}".format(self=self) + else: + return "{self.name}[{self.mixed_base_ind_var}]".format(self=self) + def __eq__(self, other): try: return self.field_type == other.field_type @@ -159,6 +170,8 @@ def returnType(f1, f2): return copy(f2) elif f2 == 'BoutReal': return copy(f1) + elif f1 == 'FieldPerp' or f2 == 'FieldPerp': + return copy(fieldPerp) else: return copy(field3D) @@ -191,10 +204,12 @@ def returnType(f1, f2): jz_var = jz_var, mixed_base_ind_var = mixed_base_ind_var) field2D = Field('Field2D', ['x', 'y'], index_var=index_var, jz_var = jz_var, mixed_base_ind_var = mixed_base_ind_var) + fieldPerp = Field('FieldPerp', ['x', 'z'], index_var=index_var, + jz_var = jz_var, mixed_base_ind_var = mixed_base_ind_var) boutreal = Field('BoutReal', [], index_var=index_var, jz_var = jz_var, mixed_base_ind_var = mixed_base_ind_var) - fields = [field3D, field2D, boutreal] + fields = [field3D, field2D, fieldPerp, boutreal] with smart_open(args.filename, "w") as f: f.write(header) diff --git a/src/field/generated_fieldops.cxx b/src/field/generated_fieldops.cxx index 50fa45796a..de7f39f0a0 100644 --- a/src/field/generated_fieldops.cxx +++ b/src/field/generated_fieldops.cxx @@ -336,6 +336,86 @@ Field3D& Field3D::operator-=(const Field2D& rhs) { return *this; } +// Provide the C++ wrapper for multiplication of Field3D and FieldPerp +FieldPerp operator*(const Field3D& lhs, const FieldPerp& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = rhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[base_ind] * rhs[index]; + } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for division of Field3D and FieldPerp +FieldPerp operator/(const Field3D& lhs, const FieldPerp& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = rhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[base_ind] / rhs[index]; + } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for addition of Field3D and FieldPerp +FieldPerp operator+(const Field3D& lhs, const FieldPerp& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = rhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[base_ind] + rhs[index]; + } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for subtraction of Field3D and FieldPerp +FieldPerp operator-(const Field3D& lhs, const FieldPerp& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = rhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[base_ind] - rhs[index]; + } + + checkData(result); + return result; +} + // Provide the C++ wrapper for multiplication of Field3D and BoutReal Field3D operator*(const Field3D& lhs, const BoutReal rhs) { @@ -692,6 +772,86 @@ Field2D& Field2D::operator-=(const Field2D& rhs) { return *this; } +// Provide the C++ wrapper for multiplication of Field2D and FieldPerp +FieldPerp operator*(const Field2D& lhs, const FieldPerp& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = rhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[base_ind] * rhs[index]; + } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for division of Field2D and FieldPerp +FieldPerp operator/(const Field2D& lhs, const FieldPerp& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = rhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[base_ind] / rhs[index]; + } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for addition of Field2D and FieldPerp +FieldPerp operator+(const Field2D& lhs, const FieldPerp& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = rhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[base_ind] + rhs[index]; + } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for subtraction of Field2D and FieldPerp +FieldPerp operator-(const Field2D& lhs, const FieldPerp& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = rhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[base_ind] - rhs[index]; + } + + checkData(result); + return result; +} + // Provide the C++ wrapper for multiplication of Field2D and BoutReal Field2D operator*(const Field2D& lhs, const BoutReal rhs) { @@ -820,101 +980,793 @@ Field2D& Field2D::operator-=(const BoutReal rhs) { return *this; } -// Provide the C++ wrapper for multiplication of BoutReal and Field3D -Field3D operator*(const BoutReal lhs, const Field3D& rhs) { +// Provide the C++ wrapper for multiplication of FieldPerp and Field3D +FieldPerp operator*(const FieldPerp& lhs, const Field3D& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); - Field3D result{emptyFrom(rhs)}; + FieldPerp result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); - BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs * rhs[index]; } + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = lhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[index] * rhs[base_ind]; + } checkData(result); return result; } -// Provide the C++ wrapper for division of BoutReal and Field3D -Field3D operator/(const BoutReal lhs, const Field3D& rhs) { +// Provide the C++ operator to update FieldPerp by multiplication with Field3D +FieldPerp& FieldPerp::operator*=(const Field3D& rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + ASSERT1(areFieldsCompatible(*this, rhs)); - Field3D result{emptyFrom(rhs)}; - checkData(lhs); - checkData(rhs); + checkData(*this); + checkData(rhs); - BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs / rhs[index]; } + Mesh* localmesh = this->getMesh(); - checkData(result); - return result; + BOUT_FOR(index, this->getRegion("RGN_ALL")) { + int yind = this->getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + (*this)[index] *= rhs[base_ind]; + } + + checkData(*this); + + } else { + (*this) = (*this) * rhs; + } + return *this; } -// Provide the C++ wrapper for addition of BoutReal and Field3D -Field3D operator+(const BoutReal lhs, const Field3D& rhs) { +// Provide the C++ wrapper for division of FieldPerp and Field3D +FieldPerp operator/(const FieldPerp& lhs, const Field3D& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); - Field3D result{emptyFrom(rhs)}; + FieldPerp result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); - BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs + rhs[index]; } + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = lhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[index] / rhs[base_ind]; + } checkData(result); return result; } -// Provide the C++ wrapper for subtraction of BoutReal and Field3D -Field3D operator-(const BoutReal lhs, const Field3D& rhs) { +// Provide the C++ operator to update FieldPerp by division with Field3D +FieldPerp& FieldPerp::operator/=(const Field3D& rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + ASSERT1(areFieldsCompatible(*this, rhs)); - Field3D result{emptyFrom(rhs)}; - checkData(lhs); - checkData(rhs); + checkData(*this); + checkData(rhs); - BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs - rhs[index]; } + Mesh* localmesh = this->getMesh(); - checkData(result); - return result; + BOUT_FOR(index, this->getRegion("RGN_ALL")) { + int yind = this->getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + (*this)[index] /= rhs[base_ind]; + } + + checkData(*this); + + } else { + (*this) = (*this) / rhs; + } + return *this; } -// Provide the C++ wrapper for multiplication of BoutReal and Field2D -Field2D operator*(const BoutReal lhs, const Field2D& rhs) { +// Provide the C++ wrapper for addition of FieldPerp and Field3D +FieldPerp operator+(const FieldPerp& lhs, const Field3D& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); - Field2D result{emptyFrom(rhs)}; + FieldPerp result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); - BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs * rhs[index]; } + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = lhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[index] + rhs[base_ind]; + } checkData(result); return result; } -// Provide the C++ wrapper for division of BoutReal and Field2D -Field2D operator/(const BoutReal lhs, const Field2D& rhs) { +// Provide the C++ operator to update FieldPerp by addition with Field3D +FieldPerp& FieldPerp::operator+=(const Field3D& rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + ASSERT1(areFieldsCompatible(*this, rhs)); - Field2D result{emptyFrom(rhs)}; + checkData(*this); + checkData(rhs); + + Mesh* localmesh = this->getMesh(); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { + int yind = this->getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + (*this)[index] += rhs[base_ind]; + } + + checkData(*this); + + } else { + (*this) = (*this) + rhs; + } + return *this; +} + +// Provide the C++ wrapper for subtraction of FieldPerp and Field3D +FieldPerp operator-(const FieldPerp& lhs, const Field3D& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); - BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs / rhs[index]; } + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = lhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[index] - rhs[base_ind]; + } checkData(result); return result; } -// Provide the C++ wrapper for addition of BoutReal and Field2D -Field2D operator+(const BoutReal lhs, const Field2D& rhs) { +// Provide the C++ operator to update FieldPerp by subtraction with Field3D +FieldPerp& FieldPerp::operator-=(const Field3D& rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + ASSERT1(areFieldsCompatible(*this, rhs)); - Field2D result{emptyFrom(rhs)}; + checkData(*this); + checkData(rhs); + + Mesh* localmesh = this->getMesh(); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { + int yind = this->getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + (*this)[index] -= rhs[base_ind]; + } + + checkData(*this); + + } else { + (*this) = (*this) - rhs; + } + return *this; +} + +// Provide the C++ wrapper for multiplication of FieldPerp and Field2D +FieldPerp operator*(const FieldPerp& lhs, const Field2D& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(lhs)}; checkData(lhs); checkData(rhs); - BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs + rhs[index]; } + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = lhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[index] * rhs[base_ind]; + } checkData(result); return result; } -// Provide the C++ wrapper for subtraction of BoutReal and Field2D -Field2D operator-(const BoutReal lhs, const Field2D& rhs) { +// Provide the C++ operator to update FieldPerp by multiplication with Field2D +FieldPerp& FieldPerp::operator*=(const Field2D& rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + ASSERT1(areFieldsCompatible(*this, rhs)); - Field2D result{emptyFrom(rhs)}; + checkData(*this); + checkData(rhs); + + Mesh* localmesh = this->getMesh(); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { + int yind = this->getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + (*this)[index] *= rhs[base_ind]; + } + + checkData(*this); + + } else { + (*this) = (*this) * rhs; + } + return *this; +} + +// Provide the C++ wrapper for division of FieldPerp and Field2D +FieldPerp operator/(const FieldPerp& lhs, const Field2D& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(lhs)}; + checkData(lhs); + checkData(rhs); + + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = lhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[index] / rhs[base_ind]; + } + + checkData(result); + return result; +} + +// Provide the C++ operator to update FieldPerp by division with Field2D +FieldPerp& FieldPerp::operator/=(const Field2D& rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + ASSERT1(areFieldsCompatible(*this, rhs)); + + checkData(*this); + checkData(rhs); + + Mesh* localmesh = this->getMesh(); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { + int yind = this->getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + (*this)[index] /= rhs[base_ind]; + } + + checkData(*this); + + } else { + (*this) = (*this) / rhs; + } + return *this; +} + +// Provide the C++ wrapper for addition of FieldPerp and Field2D +FieldPerp operator+(const FieldPerp& lhs, const Field2D& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(lhs)}; + checkData(lhs); + checkData(rhs); + + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = lhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[index] + rhs[base_ind]; + } + + checkData(result); + return result; +} + +// Provide the C++ operator to update FieldPerp by addition with Field2D +FieldPerp& FieldPerp::operator+=(const Field2D& rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + ASSERT1(areFieldsCompatible(*this, rhs)); + + checkData(*this); + checkData(rhs); + + Mesh* localmesh = this->getMesh(); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { + int yind = this->getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + (*this)[index] += rhs[base_ind]; + } + + checkData(*this); + + } else { + (*this) = (*this) + rhs; + } + return *this; +} + +// Provide the C++ wrapper for subtraction of FieldPerp and Field2D +FieldPerp operator-(const FieldPerp& lhs, const Field2D& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(lhs)}; + checkData(lhs); + checkData(rhs); + + Mesh* localmesh = lhs.getMesh(); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + int yind = lhs.getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + result[index] = lhs[index] - rhs[base_ind]; + } + + checkData(result); + return result; +} + +// Provide the C++ operator to update FieldPerp by subtraction with Field2D +FieldPerp& FieldPerp::operator-=(const Field2D& rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + ASSERT1(areFieldsCompatible(*this, rhs)); + + checkData(*this); + checkData(rhs); + + Mesh* localmesh = this->getMesh(); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { + int yind = this->getIndex(); + const auto base_ind = localmesh->indPerpto3D(index, yind); + (*this)[index] -= rhs[base_ind]; + } + + checkData(*this); + + } else { + (*this) = (*this) - rhs; + } + return *this; +} + +// Provide the C++ wrapper for multiplication of FieldPerp and FieldPerp +FieldPerp operator*(const FieldPerp& lhs, const FieldPerp& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(lhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + result[index] = lhs[index] * rhs[index]; + } + + checkData(result); + return result; +} + +// Provide the C++ operator to update FieldPerp by multiplication with FieldPerp +FieldPerp& FieldPerp::operator*=(const FieldPerp& rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + ASSERT1(areFieldsCompatible(*this, rhs)); + + checkData(*this); + checkData(rhs); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= rhs[index]; } + + checkData(*this); + + } else { + (*this) = (*this) * rhs; + } + return *this; +} + +// Provide the C++ wrapper for division of FieldPerp and FieldPerp +FieldPerp operator/(const FieldPerp& lhs, const FieldPerp& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(lhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + result[index] = lhs[index] / rhs[index]; + } + + checkData(result); + return result; +} + +// Provide the C++ operator to update FieldPerp by division with FieldPerp +FieldPerp& FieldPerp::operator/=(const FieldPerp& rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + ASSERT1(areFieldsCompatible(*this, rhs)); + + checkData(*this); + checkData(rhs); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] /= rhs[index]; } + + checkData(*this); + + } else { + (*this) = (*this) / rhs; + } + return *this; +} + +// Provide the C++ wrapper for addition of FieldPerp and FieldPerp +FieldPerp operator+(const FieldPerp& lhs, const FieldPerp& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(lhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + result[index] = lhs[index] + rhs[index]; + } + + checkData(result); + return result; +} + +// Provide the C++ operator to update FieldPerp by addition with FieldPerp +FieldPerp& FieldPerp::operator+=(const FieldPerp& rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + ASSERT1(areFieldsCompatible(*this, rhs)); + + checkData(*this); + checkData(rhs); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] += rhs[index]; } + + checkData(*this); + + } else { + (*this) = (*this) + rhs; + } + return *this; +} + +// Provide the C++ wrapper for subtraction of FieldPerp and FieldPerp +FieldPerp operator-(const FieldPerp& lhs, const FieldPerp& rhs) { + ASSERT1(areFieldsCompatible(lhs, rhs)); + + FieldPerp result{emptyFrom(lhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { + result[index] = lhs[index] - rhs[index]; + } + + checkData(result); + return result; +} + +// Provide the C++ operator to update FieldPerp by subtraction with FieldPerp +FieldPerp& FieldPerp::operator-=(const FieldPerp& rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + ASSERT1(areFieldsCompatible(*this, rhs)); + + checkData(*this); + checkData(rhs); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] -= rhs[index]; } + + checkData(*this); + + } else { + (*this) = (*this) - rhs; + } + return *this; +} + +// Provide the C++ wrapper for multiplication of FieldPerp and BoutReal +FieldPerp operator*(const FieldPerp& lhs, const BoutReal rhs) { + + FieldPerp result{emptyFrom(lhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] * rhs; } + + checkData(result); + return result; +} + +// Provide the C++ operator to update FieldPerp by multiplication with BoutReal +FieldPerp& FieldPerp::operator*=(const BoutReal rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + + checkData(*this); + checkData(rhs); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= rhs; } + + checkData(*this); + + } else { + (*this) = (*this) * rhs; + } + return *this; +} + +// Provide the C++ wrapper for division of FieldPerp and BoutReal +FieldPerp operator/(const FieldPerp& lhs, const BoutReal rhs) { + + FieldPerp result{emptyFrom(lhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] / rhs; } + + checkData(result); + return result; +} + +// Provide the C++ operator to update FieldPerp by division with BoutReal +FieldPerp& FieldPerp::operator/=(const BoutReal rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + + checkData(*this); + checkData(rhs); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] /= rhs; } + + checkData(*this); + + } else { + (*this) = (*this) / rhs; + } + return *this; +} + +// Provide the C++ wrapper for addition of FieldPerp and BoutReal +FieldPerp operator+(const FieldPerp& lhs, const BoutReal rhs) { + + FieldPerp result{emptyFrom(lhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] + rhs; } + + checkData(result); + return result; +} + +// Provide the C++ operator to update FieldPerp by addition with BoutReal +FieldPerp& FieldPerp::operator+=(const BoutReal rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + + checkData(*this); + checkData(rhs); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] += rhs; } + + checkData(*this); + + } else { + (*this) = (*this) + rhs; + } + return *this; +} + +// Provide the C++ wrapper for subtraction of FieldPerp and BoutReal +FieldPerp operator-(const FieldPerp& lhs, const BoutReal rhs) { + + FieldPerp result{emptyFrom(lhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] - rhs; } + + checkData(result); + return result; +} + +// Provide the C++ operator to update FieldPerp by subtraction with BoutReal +FieldPerp& FieldPerp::operator-=(const BoutReal rhs) { + // only if data is unique we update the field + // otherwise just call the non-inplace version + if (data.unique()) { + + checkData(*this); + checkData(rhs); + + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] -= rhs; } + + checkData(*this); + + } else { + (*this) = (*this) - rhs; + } + return *this; +} + +// Provide the C++ wrapper for multiplication of BoutReal and Field3D +Field3D operator*(const BoutReal lhs, const Field3D& rhs) { + + Field3D result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs * rhs[index]; } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for division of BoutReal and Field3D +Field3D operator/(const BoutReal lhs, const Field3D& rhs) { + + Field3D result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs / rhs[index]; } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for addition of BoutReal and Field3D +Field3D operator+(const BoutReal lhs, const Field3D& rhs) { + + Field3D result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs + rhs[index]; } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for subtraction of BoutReal and Field3D +Field3D operator-(const BoutReal lhs, const Field3D& rhs) { + + Field3D result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs - rhs[index]; } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for multiplication of BoutReal and Field2D +Field2D operator*(const BoutReal lhs, const Field2D& rhs) { + + Field2D result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs * rhs[index]; } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for division of BoutReal and Field2D +Field2D operator/(const BoutReal lhs, const Field2D& rhs) { + + Field2D result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs / rhs[index]; } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for addition of BoutReal and Field2D +Field2D operator+(const BoutReal lhs, const Field2D& rhs) { + + Field2D result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs + rhs[index]; } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for subtraction of BoutReal and Field2D +Field2D operator-(const BoutReal lhs, const Field2D& rhs) { + + Field2D result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs - rhs[index]; } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for multiplication of BoutReal and FieldPerp +FieldPerp operator*(const BoutReal lhs, const FieldPerp& rhs) { + + FieldPerp result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs * rhs[index]; } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for division of BoutReal and FieldPerp +FieldPerp operator/(const BoutReal lhs, const FieldPerp& rhs) { + + FieldPerp result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs / rhs[index]; } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for addition of BoutReal and FieldPerp +FieldPerp operator+(const BoutReal lhs, const FieldPerp& rhs) { + + FieldPerp result{emptyFrom(rhs)}; + checkData(lhs); + checkData(rhs); + + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs + rhs[index]; } + + checkData(result); + return result; +} + +// Provide the C++ wrapper for subtraction of BoutReal and FieldPerp +FieldPerp operator-(const BoutReal lhs, const FieldPerp& rhs) { + + FieldPerp result{emptyFrom(rhs)}; checkData(lhs); checkData(rhs); From 17b7d065c95e7b2fe6d2cdb00d2ea3c183c2e655 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 17:12:23 +0000 Subject: [PATCH 1169/1783] Apply finalisation workaround to boutcore MMS tests --- tests/MMS/derivatives3/runtest | 2 +- tests/MMS/upwinding3/runtest | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/MMS/derivatives3/runtest b/tests/MMS/derivatives3/runtest index c3f64624cb..a10e87157c 100755 --- a/tests/MMS/derivatives3/runtest +++ b/tests/MMS/derivatives3/runtest @@ -122,7 +122,7 @@ derivatives=[ runtests(functions,derivatives,directions,True,"D2D2") - +boutcore.finalise() if errorlist: for error in errorlist: diff --git a/tests/MMS/upwinding3/runtest b/tests/MMS/upwinding3/runtest index 41a9b04573..2862e7a347 100755 --- a/tests/MMS/upwinding3/runtest +++ b/tests/MMS/upwinding3/runtest @@ -106,6 +106,8 @@ derivatives=[ runtests(functions,derivatives,directions,stag=True,msg="DD") +boutcore.finalise() + if errorlist: for error in errorlist: print(error) From 1fa2eb008a709e666e6b62d01187d0d74c4666bd Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 27 Mar 2019 16:40:10 +0000 Subject: [PATCH 1170/1783] Fix const-ness in FieldPerp non-member operators The FieldPerp operators should return a non-const FieldPerp. Makes them consistent with other fields, and interface from gen_fieldops.py. Rename second argument to 'rhs' to be consistent with gen_fieldops.py --- include/fieldperp.hxx | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 41381910a4..8db7dfa768 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -271,29 +271,29 @@ private: // Non-member overloaded operators -const FieldPerp operator+(const FieldPerp &lhs, const FieldPerp &rhs); -const FieldPerp operator+(const FieldPerp &lhs, const Field3D &rhs); -const FieldPerp operator+(const FieldPerp &lhs, const Field2D &rhs); -const FieldPerp operator+(const FieldPerp &lhs, BoutReal rhs); -const FieldPerp operator+(BoutReal lhs, const FieldPerp &rhs); - -const FieldPerp operator-(const FieldPerp &lhs, const FieldPerp &other); -const FieldPerp operator-(const FieldPerp &lhs, const Field3D &other); -const FieldPerp operator-(const FieldPerp &lhs, const Field2D &other); -const FieldPerp operator-(const FieldPerp &lhs, BoutReal rhs); -const FieldPerp operator-(BoutReal lhs, const FieldPerp &rhs); - -const FieldPerp operator*(const FieldPerp &lhs, const FieldPerp &other); -const FieldPerp operator*(const FieldPerp &lhs, const Field3D &other); -const FieldPerp operator*(const FieldPerp &lhs, const Field2D &other); -const FieldPerp operator*(const FieldPerp &lhs, BoutReal rhs); -const FieldPerp operator*(BoutReal lhs, const FieldPerp &rhs); - -const FieldPerp operator/(const FieldPerp &lhs, const FieldPerp &other); -const FieldPerp operator/(const FieldPerp &lhs, const Field3D &other); -const FieldPerp operator/(const FieldPerp &lhs, const Field2D &other); -const FieldPerp operator/(const FieldPerp &lhs, BoutReal rhs); -const FieldPerp operator/(BoutReal lhs, const FieldPerp &rhs); +FieldPerp operator+(const FieldPerp &lhs, const FieldPerp &rhs); +FieldPerp operator+(const FieldPerp &lhs, const Field3D &rhs); +FieldPerp operator+(const FieldPerp &lhs, const Field2D &rhs); +FieldPerp operator+(const FieldPerp &lhs, BoutReal rhs); +FieldPerp operator+(BoutReal lhs, const FieldPerp &rhs); + +FieldPerp operator-(const FieldPerp &lhs, const FieldPerp &rhs); +FieldPerp operator-(const FieldPerp &lhs, const Field3D &rhs); +FieldPerp operator-(const FieldPerp &lhs, const Field2D &rhs); +FieldPerp operator-(const FieldPerp &lhs, BoutReal rhs); +FieldPerp operator-(BoutReal lhs, const FieldPerp &rhs); + +FieldPerp operator*(const FieldPerp &lhs, const FieldPerp &rhs); +FieldPerp operator*(const FieldPerp &lhs, const Field3D &rhs); +FieldPerp operator*(const FieldPerp &lhs, const Field2D &rhs); +FieldPerp operator*(const FieldPerp &lhs, BoutReal rhs); +FieldPerp operator*(BoutReal lhs, const FieldPerp &rhs); + +FieldPerp operator/(const FieldPerp &lhs, const FieldPerp &rhs); +FieldPerp operator/(const FieldPerp &lhs, const Field3D &rhs); +FieldPerp operator/(const FieldPerp &lhs, const Field2D &rhs); +FieldPerp operator/(const FieldPerp &lhs, BoutReal rhs); +FieldPerp operator/(BoutReal lhs, const FieldPerp &rhs); /*! * Unary minus. Returns the negative of given field, From 85cc09d10872db140bde85a3e71df5fd7ba141a5 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 27 Mar 2019 17:25:52 +0000 Subject: [PATCH 1171/1783] More FieldPerp arithmetic unit tests --- tests/unit/field/test_fieldperp.cxx | 96 +++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/tests/unit/field/test_fieldperp.cxx b/tests/unit/field/test_fieldperp.cxx index 47412fb1ba..8d7074bf93 100644 --- a/tests/unit/field/test_fieldperp.cxx +++ b/tests/unit/field/test_fieldperp.cxx @@ -825,6 +825,18 @@ TEST_F(FieldPerpTest, AddFieldPerpField2D) { EXPECT_TRUE(IsFieldEqual(c, 3.0)); } +TEST_F(FieldPerpTest, AddField2DFieldPerp) { + FieldPerp b, c; + Field2D a; + + b.setIndex(1); + a = 1.0; + b = 2.0; + c = a + b; + + EXPECT_TRUE(IsFieldEqual(c, 3.0)); +} + TEST_F(FieldPerpTest, AddFieldPerpField3D) { FieldPerp a, c; Field3D b; @@ -837,6 +849,18 @@ TEST_F(FieldPerpTest, AddFieldPerpField3D) { EXPECT_TRUE(IsFieldEqual(c, 3.0)); } +TEST_F(FieldPerpTest, AddField3DFieldPerp) { + FieldPerp b, c; + Field3D a; + + b.setIndex(1); + a = 1.0; + b = 2.0; + c = a + b; + + EXPECT_TRUE(IsFieldEqual(c, 3.0)); +} + TEST_F(FieldPerpTest, MultiplyEqualsBoutReal) { FieldPerp a; a.setIndex(0); @@ -961,6 +985,18 @@ TEST_F(FieldPerpTest, MultiplyFieldPerpField2D) { EXPECT_TRUE(IsFieldEqual(c, 32.0)); } +TEST_F(FieldPerpTest, MultiplyField2DFieldPerp) { + FieldPerp b, c; + Field2D a; + + b.setIndex(1); + a = 4.0; + b = 8.0; + c = a * b; + + EXPECT_TRUE(IsFieldEqual(c, 32.0)); +} + TEST_F(FieldPerpTest, MultiplyFieldPerpField3D) { FieldPerp a, c; Field3D b; @@ -973,6 +1009,18 @@ TEST_F(FieldPerpTest, MultiplyFieldPerpField3D) { EXPECT_TRUE(IsFieldEqual(c, 32.0)); } +TEST_F(FieldPerpTest, MultiplyField3DFieldPerp) { + FieldPerp b, c; + Field3D a; + + b.setIndex(1); + a = 4.0; + b = 8.0; + c = a * b; + + EXPECT_TRUE(IsFieldEqual(c, 32.0)); +} + TEST_F(FieldPerpTest, SubtractEqualsBoutReal) { FieldPerp a; a.setIndex(0); @@ -1097,6 +1145,18 @@ TEST_F(FieldPerpTest, SubtractFieldPerpField2D) { EXPECT_TRUE(IsFieldEqual(c, -10.0)); } +TEST_F(FieldPerpTest, SubtractField2DFieldPerp) { + FieldPerp b, c; + Field2D a; + + b.setIndex(1); + a = 10.0; + b = 20.0; + c = a - b; + + EXPECT_TRUE(IsFieldEqual(c, -10.0)); +} + TEST_F(FieldPerpTest, SubtractFieldPerpField3D) { FieldPerp a, c; Field3D b; @@ -1109,6 +1169,18 @@ TEST_F(FieldPerpTest, SubtractFieldPerpField3D) { EXPECT_TRUE(IsFieldEqual(c, -10.0)); } +TEST_F(FieldPerpTest, SubtractField3DFieldPerp) { + FieldPerp b, c; + Field3D a; + + b.setIndex(1); + a = 10.0; + b = 20.0; + c = a - b; + + EXPECT_TRUE(IsFieldEqual(c, -10.0)); +} + TEST_F(FieldPerpTest, DivideEqualsBoutReal) { FieldPerp a; a.setIndex(0); @@ -1233,6 +1305,18 @@ TEST_F(FieldPerpTest, DivideFieldPerpField2D) { EXPECT_TRUE(IsFieldEqual(c, 4.0)); } +TEST_F(FieldPerpTest, DivideField2DFieldPerp) { + FieldPerp b, c; + Field2D a; + + b.setIndex(1); + a = 32.0; + b = 8.0; + c = a / b; + + EXPECT_TRUE(IsFieldEqual(c, 4.0)); +} + TEST_F(FieldPerpTest, DivideFieldPerpField3D) { FieldPerp a, c; Field3D b; @@ -1245,6 +1329,18 @@ TEST_F(FieldPerpTest, DivideFieldPerpField3D) { EXPECT_TRUE(IsFieldEqual(c, 4.0)); } +TEST_F(FieldPerpTest, DivideField3DFieldPerp) { + FieldPerp b, c; + Field3D a; + + b.setIndex(1); + a = 32.0; + b = 8.0; + c = a / b; + + EXPECT_TRUE(IsFieldEqual(c, 4.0)); +} + TEST_F(FieldPerpTest, PowBoutRealFieldPerp) { FieldPerp a, b; a.setIndex(0); From 80525bab6332e2724dc2310241ba8e7fdcad053a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 27 Mar 2019 17:53:34 +0000 Subject: [PATCH 1172/1783] Use non-const BoutReal arguments in gen_fieldops.py/gen_fieldops.jinja Should not pass-by-value const arguments. Seems to have worked previously because declarations of operators did not have 'const', but now remove const from BoutReal arguments in implementations in generated_fieldops.cxx --- src/field/gen_fieldops.jinja | 4 +- src/field/gen_fieldops.py | 3 +- src/field/generated_fieldops.cxx | 72 ++++++++++++++++---------------- 3 files changed, 40 insertions(+), 39 deletions(-) diff --git a/src/field/gen_fieldops.jinja b/src/field/gen_fieldops.jinja index 25e1af328b..2fadf6c704 100644 --- a/src/field/gen_fieldops.jinja +++ b/src/field/gen_fieldops.jinja @@ -1,5 +1,5 @@ // Provide the C++ wrapper for {{operator_name}} of {{lhs}} and {{rhs}} -{{out}} operator{{operator}}(const {{lhs.passByReference}}, const {{rhs.passByReference}}) { +{{out}} operator{{operator}}({{lhs.passByReference}}, {{rhs.passByReference}}) { {% if lhs != "BoutReal" and rhs != "BoutReal" %} ASSERT1(areFieldsCompatible(lhs, rhs)); {% endif %} @@ -51,7 +51,7 @@ {% if out.field_type == lhs.field_type %} // Provide the C++ operator to update {{lhs}} by {{operator_name}} with {{rhs}} -{{lhs}} &{{lhs}}::operator{{operator}}=(const {{rhs.passByReference}}) { +{{lhs}} &{{lhs}}::operator{{operator}}=({{rhs.passByReference}}) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { diff --git a/src/field/gen_fieldops.py b/src/field/gen_fieldops.py index 3a5bd97a93..2d096ecfa4 100755 --- a/src/field/gen_fieldops.py +++ b/src/field/gen_fieldops.py @@ -106,7 +106,8 @@ def passByReference(self): in which case just returns "Type name" """ - return "{self.field_type}{ref} {self.name}".format( + return "{maybe_const}{self.field_type}{ref} {self.name}".format( + maybe_const="const " if self.field_type != "BoutReal" else "", self=self, ref="&" if self.field_type != "BoutReal" else "") @property diff --git a/src/field/generated_fieldops.cxx b/src/field/generated_fieldops.cxx index de7f39f0a0..5843d0c96a 100644 --- a/src/field/generated_fieldops.cxx +++ b/src/field/generated_fieldops.cxx @@ -417,7 +417,7 @@ FieldPerp operator-(const Field3D& lhs, const FieldPerp& rhs) { } // Provide the C++ wrapper for multiplication of Field3D and BoutReal -Field3D operator*(const Field3D& lhs, const BoutReal rhs) { +Field3D operator*(const Field3D& lhs, BoutReal rhs) { Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -430,7 +430,7 @@ Field3D operator*(const Field3D& lhs, const BoutReal rhs) { } // Provide the C++ operator to update Field3D by multiplication with BoutReal -Field3D& Field3D::operator*=(const BoutReal rhs) { +Field3D& Field3D::operator*=(BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -449,7 +449,7 @@ Field3D& Field3D::operator*=(const BoutReal rhs) { } // Provide the C++ wrapper for division of Field3D and BoutReal -Field3D operator/(const Field3D& lhs, const BoutReal rhs) { +Field3D operator/(const Field3D& lhs, BoutReal rhs) { Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -462,7 +462,7 @@ Field3D operator/(const Field3D& lhs, const BoutReal rhs) { } // Provide the C++ operator to update Field3D by division with BoutReal -Field3D& Field3D::operator/=(const BoutReal rhs) { +Field3D& Field3D::operator/=(BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -481,7 +481,7 @@ Field3D& Field3D::operator/=(const BoutReal rhs) { } // Provide the C++ wrapper for addition of Field3D and BoutReal -Field3D operator+(const Field3D& lhs, const BoutReal rhs) { +Field3D operator+(const Field3D& lhs, BoutReal rhs) { Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -494,7 +494,7 @@ Field3D operator+(const Field3D& lhs, const BoutReal rhs) { } // Provide the C++ operator to update Field3D by addition with BoutReal -Field3D& Field3D::operator+=(const BoutReal rhs) { +Field3D& Field3D::operator+=(BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -513,7 +513,7 @@ Field3D& Field3D::operator+=(const BoutReal rhs) { } // Provide the C++ wrapper for subtraction of Field3D and BoutReal -Field3D operator-(const Field3D& lhs, const BoutReal rhs) { +Field3D operator-(const Field3D& lhs, BoutReal rhs) { Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -526,7 +526,7 @@ Field3D operator-(const Field3D& lhs, const BoutReal rhs) { } // Provide the C++ operator to update Field3D by subtraction with BoutReal -Field3D& Field3D::operator-=(const BoutReal rhs) { +Field3D& Field3D::operator-=(BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -853,7 +853,7 @@ FieldPerp operator-(const Field2D& lhs, const FieldPerp& rhs) { } // Provide the C++ wrapper for multiplication of Field2D and BoutReal -Field2D operator*(const Field2D& lhs, const BoutReal rhs) { +Field2D operator*(const Field2D& lhs, BoutReal rhs) { Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -866,7 +866,7 @@ Field2D operator*(const Field2D& lhs, const BoutReal rhs) { } // Provide the C++ operator to update Field2D by multiplication with BoutReal -Field2D& Field2D::operator*=(const BoutReal rhs) { +Field2D& Field2D::operator*=(BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -885,7 +885,7 @@ Field2D& Field2D::operator*=(const BoutReal rhs) { } // Provide the C++ wrapper for division of Field2D and BoutReal -Field2D operator/(const Field2D& lhs, const BoutReal rhs) { +Field2D operator/(const Field2D& lhs, BoutReal rhs) { Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -898,7 +898,7 @@ Field2D operator/(const Field2D& lhs, const BoutReal rhs) { } // Provide the C++ operator to update Field2D by division with BoutReal -Field2D& Field2D::operator/=(const BoutReal rhs) { +Field2D& Field2D::operator/=(BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -917,7 +917,7 @@ Field2D& Field2D::operator/=(const BoutReal rhs) { } // Provide the C++ wrapper for addition of Field2D and BoutReal -Field2D operator+(const Field2D& lhs, const BoutReal rhs) { +Field2D operator+(const Field2D& lhs, BoutReal rhs) { Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -930,7 +930,7 @@ Field2D operator+(const Field2D& lhs, const BoutReal rhs) { } // Provide the C++ operator to update Field2D by addition with BoutReal -Field2D& Field2D::operator+=(const BoutReal rhs) { +Field2D& Field2D::operator+=(BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -949,7 +949,7 @@ Field2D& Field2D::operator+=(const BoutReal rhs) { } // Provide the C++ wrapper for subtraction of Field2D and BoutReal -Field2D operator-(const Field2D& lhs, const BoutReal rhs) { +Field2D operator-(const Field2D& lhs, BoutReal rhs) { Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -962,7 +962,7 @@ Field2D operator-(const Field2D& lhs, const BoutReal rhs) { } // Provide the C++ operator to update Field2D by subtraction with BoutReal -Field2D& Field2D::operator-=(const BoutReal rhs) { +Field2D& Field2D::operator-=(BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1493,7 +1493,7 @@ FieldPerp& FieldPerp::operator-=(const FieldPerp& rhs) { } // Provide the C++ wrapper for multiplication of FieldPerp and BoutReal -FieldPerp operator*(const FieldPerp& lhs, const BoutReal rhs) { +FieldPerp operator*(const FieldPerp& lhs, BoutReal rhs) { FieldPerp result{emptyFrom(lhs)}; checkData(lhs); @@ -1506,7 +1506,7 @@ FieldPerp operator*(const FieldPerp& lhs, const BoutReal rhs) { } // Provide the C++ operator to update FieldPerp by multiplication with BoutReal -FieldPerp& FieldPerp::operator*=(const BoutReal rhs) { +FieldPerp& FieldPerp::operator*=(BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1525,7 +1525,7 @@ FieldPerp& FieldPerp::operator*=(const BoutReal rhs) { } // Provide the C++ wrapper for division of FieldPerp and BoutReal -FieldPerp operator/(const FieldPerp& lhs, const BoutReal rhs) { +FieldPerp operator/(const FieldPerp& lhs, BoutReal rhs) { FieldPerp result{emptyFrom(lhs)}; checkData(lhs); @@ -1538,7 +1538,7 @@ FieldPerp operator/(const FieldPerp& lhs, const BoutReal rhs) { } // Provide the C++ operator to update FieldPerp by division with BoutReal -FieldPerp& FieldPerp::operator/=(const BoutReal rhs) { +FieldPerp& FieldPerp::operator/=(BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1557,7 +1557,7 @@ FieldPerp& FieldPerp::operator/=(const BoutReal rhs) { } // Provide the C++ wrapper for addition of FieldPerp and BoutReal -FieldPerp operator+(const FieldPerp& lhs, const BoutReal rhs) { +FieldPerp operator+(const FieldPerp& lhs, BoutReal rhs) { FieldPerp result{emptyFrom(lhs)}; checkData(lhs); @@ -1570,7 +1570,7 @@ FieldPerp operator+(const FieldPerp& lhs, const BoutReal rhs) { } // Provide the C++ operator to update FieldPerp by addition with BoutReal -FieldPerp& FieldPerp::operator+=(const BoutReal rhs) { +FieldPerp& FieldPerp::operator+=(BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1589,7 +1589,7 @@ FieldPerp& FieldPerp::operator+=(const BoutReal rhs) { } // Provide the C++ wrapper for subtraction of FieldPerp and BoutReal -FieldPerp operator-(const FieldPerp& lhs, const BoutReal rhs) { +FieldPerp operator-(const FieldPerp& lhs, BoutReal rhs) { FieldPerp result{emptyFrom(lhs)}; checkData(lhs); @@ -1602,7 +1602,7 @@ FieldPerp operator-(const FieldPerp& lhs, const BoutReal rhs) { } // Provide the C++ operator to update FieldPerp by subtraction with BoutReal -FieldPerp& FieldPerp::operator-=(const BoutReal rhs) { +FieldPerp& FieldPerp::operator-=(BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1621,7 +1621,7 @@ FieldPerp& FieldPerp::operator-=(const BoutReal rhs) { } // Provide the C++ wrapper for multiplication of BoutReal and Field3D -Field3D operator*(const BoutReal lhs, const Field3D& rhs) { +Field3D operator*(BoutReal lhs, const Field3D& rhs) { Field3D result{emptyFrom(rhs)}; checkData(lhs); @@ -1634,7 +1634,7 @@ Field3D operator*(const BoutReal lhs, const Field3D& rhs) { } // Provide the C++ wrapper for division of BoutReal and Field3D -Field3D operator/(const BoutReal lhs, const Field3D& rhs) { +Field3D operator/(BoutReal lhs, const Field3D& rhs) { Field3D result{emptyFrom(rhs)}; checkData(lhs); @@ -1647,7 +1647,7 @@ Field3D operator/(const BoutReal lhs, const Field3D& rhs) { } // Provide the C++ wrapper for addition of BoutReal and Field3D -Field3D operator+(const BoutReal lhs, const Field3D& rhs) { +Field3D operator+(BoutReal lhs, const Field3D& rhs) { Field3D result{emptyFrom(rhs)}; checkData(lhs); @@ -1660,7 +1660,7 @@ Field3D operator+(const BoutReal lhs, const Field3D& rhs) { } // Provide the C++ wrapper for subtraction of BoutReal and Field3D -Field3D operator-(const BoutReal lhs, const Field3D& rhs) { +Field3D operator-(BoutReal lhs, const Field3D& rhs) { Field3D result{emptyFrom(rhs)}; checkData(lhs); @@ -1673,7 +1673,7 @@ Field3D operator-(const BoutReal lhs, const Field3D& rhs) { } // Provide the C++ wrapper for multiplication of BoutReal and Field2D -Field2D operator*(const BoutReal lhs, const Field2D& rhs) { +Field2D operator*(BoutReal lhs, const Field2D& rhs) { Field2D result{emptyFrom(rhs)}; checkData(lhs); @@ -1686,7 +1686,7 @@ Field2D operator*(const BoutReal lhs, const Field2D& rhs) { } // Provide the C++ wrapper for division of BoutReal and Field2D -Field2D operator/(const BoutReal lhs, const Field2D& rhs) { +Field2D operator/(BoutReal lhs, const Field2D& rhs) { Field2D result{emptyFrom(rhs)}; checkData(lhs); @@ -1699,7 +1699,7 @@ Field2D operator/(const BoutReal lhs, const Field2D& rhs) { } // Provide the C++ wrapper for addition of BoutReal and Field2D -Field2D operator+(const BoutReal lhs, const Field2D& rhs) { +Field2D operator+(BoutReal lhs, const Field2D& rhs) { Field2D result{emptyFrom(rhs)}; checkData(lhs); @@ -1712,7 +1712,7 @@ Field2D operator+(const BoutReal lhs, const Field2D& rhs) { } // Provide the C++ wrapper for subtraction of BoutReal and Field2D -Field2D operator-(const BoutReal lhs, const Field2D& rhs) { +Field2D operator-(BoutReal lhs, const Field2D& rhs) { Field2D result{emptyFrom(rhs)}; checkData(lhs); @@ -1725,7 +1725,7 @@ Field2D operator-(const BoutReal lhs, const Field2D& rhs) { } // Provide the C++ wrapper for multiplication of BoutReal and FieldPerp -FieldPerp operator*(const BoutReal lhs, const FieldPerp& rhs) { +FieldPerp operator*(BoutReal lhs, const FieldPerp& rhs) { FieldPerp result{emptyFrom(rhs)}; checkData(lhs); @@ -1738,7 +1738,7 @@ FieldPerp operator*(const BoutReal lhs, const FieldPerp& rhs) { } // Provide the C++ wrapper for division of BoutReal and FieldPerp -FieldPerp operator/(const BoutReal lhs, const FieldPerp& rhs) { +FieldPerp operator/(BoutReal lhs, const FieldPerp& rhs) { FieldPerp result{emptyFrom(rhs)}; checkData(lhs); @@ -1751,7 +1751,7 @@ FieldPerp operator/(const BoutReal lhs, const FieldPerp& rhs) { } // Provide the C++ wrapper for addition of BoutReal and FieldPerp -FieldPerp operator+(const BoutReal lhs, const FieldPerp& rhs) { +FieldPerp operator+(BoutReal lhs, const FieldPerp& rhs) { FieldPerp result{emptyFrom(rhs)}; checkData(lhs); @@ -1764,7 +1764,7 @@ FieldPerp operator+(const BoutReal lhs, const FieldPerp& rhs) { } // Provide the C++ wrapper for subtraction of BoutReal and FieldPerp -FieldPerp operator-(const BoutReal lhs, const FieldPerp& rhs) { +FieldPerp operator-(BoutReal lhs, const FieldPerp& rhs) { FieldPerp result{emptyFrom(rhs)}; checkData(lhs); From bb8c899472fab098c9902dae498d0879ae77e6d2 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 27 Mar 2019 23:54:13 +0000 Subject: [PATCH 1173/1783] Add tests for Options type and doc attributes Needed to add: * `==` and `<<` operators for `Field2D` and `Field3D` types * A template function `meshFromValue` to get a mesh pointer from a Field{2,3}D in `Options::withDefault`. Probably there is a better way to specify that the result field should be similar to the given default. --- include/bout/sys/type_name.hxx | 6 +- include/field2d.hxx | 6 ++ include/field3d.hxx | 6 ++ include/options.hxx | 26 ++++++- src/field/field2d.cxx | 12 +++ src/field/field3d.cxx | 12 +++ src/sys/type_name.cxx | 3 + tests/unit/sys/test_options.cxx | 123 ++++++++++++++++++++++++++++++ tests/unit/sys/test_type_name.cxx | 32 ++++++++ 9 files changed, 221 insertions(+), 5 deletions(-) create mode 100644 tests/unit/sys/test_type_name.cxx diff --git a/include/bout/sys/type_name.hxx b/include/bout/sys/type_name.hxx index 143d16aed3..f35645a2fe 100644 --- a/include/bout/sys/type_name.hxx +++ b/include/bout/sys/type_name.hxx @@ -8,11 +8,11 @@ #include #include "bout_types.hxx" +class Field2D; +class Field3D; + namespace bout { namespace utils { - - class Field2D; - class Field3D; template std::string typeName() { diff --git a/include/field2d.hxx b/include/field2d.hxx index 78ff610715..55a560cb00 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -475,4 +475,10 @@ inline std::string toString<>(const Field2D& UNUSED(val)) { return ""; } +/// Test if two fields are the same, by calculating +/// the minimum absolute difference between them +bool operator==(const Field2D &a, const Field2D &b); + +std::ostream& operator<<(std::ostream &out, const Field2D &value); + #endif /* __FIELD2D_H__ */ diff --git a/include/field3d.hxx b/include/field3d.hxx index 7257f68f41..32e114821a 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -781,4 +781,10 @@ inline std::string toString<>(const Field3D& UNUSED(val)) { return ""; } +/// Test if two fields are the same, by calculating +/// the minimum absolute difference between them +bool operator==(const Field3D &a, const Field3D &b); + +std::ostream& operator<<(std::ostream &out, const Field3D &value); + #endif /* __FIELD3D_H__ */ diff --git a/include/options.hxx b/include/options.hxx index 6dbe12c754..3328b4f478 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -56,6 +56,28 @@ class Options; #include #include +namespace bout { +namespace utils { + + /// Get a mesh pointer from the given object. + /// In most cases this is nullptr + template + Mesh* meshFromValue(const T& UNUSED(value)) { + return nullptr; + } + + template <> + Mesh* meshFromValue(const Field2D& value) { + return value.getMesh(); + } + template <> + Mesh* meshFromValue(const Field3D& value) { + return value.getMesh(); + } + +} +} + /// Class to represent hierarchy of options /*! * @@ -403,7 +425,7 @@ public: << ")" << std::endl; return def; } - T val = as(); + T val = as(bout::utils::meshFromValue(def)); // Check if this was previously set as a default option if (bout::utils::variantEqualTo(attributes.at("source"), DEFAULT_SOURCE)) { // Check that the default values are the same @@ -430,7 +452,7 @@ public: << ")" << std::endl; return def; } - T val = as(); + T val = as(bout::utils::meshFromValue(def)); // Check if this was previously set as a default option if (bout::utils::variantEqualTo(attributes.at("source"), DEFAULT_SOURCE)) { // Check that the default values are the same diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index d0d85a9d64..d92d28ef6a 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -522,3 +522,15 @@ void invalidateGuards(Field2D &var) { BOUT_FOR(i, var.getRegion("RGN_GUARDS")) { var[i] = BoutNaN; } } #endif + +bool operator==(const Field2D &a, const Field2D &b) { + if (!a.isAllocated() || !b.isAllocated()) { + return false; + } + return min(abs(a - b)) < 1e-10; +} + +std::ostream& operator<<(std::ostream &out, const Field2D &value) { + out << toString(value); + return out; +} diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 39f2bc3a55..230ea072d4 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -992,3 +992,15 @@ void invalidateGuards(Field3D &var) { BOUT_FOR(i, var.getRegion("RGN_GUARDS")) { var[i] = BoutNaN; } } #endif + +bool operator==(const Field3D &a, const Field3D &b) { + if (!a.isAllocated() || !b.isAllocated()) { + return false; + } + return min(abs(a - b)) < 1e-10; +} + +std::ostream& operator<<(std::ostream &out, const Field3D &value) { + out << toString(value); + return out; +} diff --git a/src/sys/type_name.cxx b/src/sys/type_name.cxx index b8d7ba1fd9..bbcff04cff 100644 --- a/src/sys/type_name.cxx +++ b/src/sys/type_name.cxx @@ -1,5 +1,8 @@ #include "bout/sys/type_name.hxx" +#include "field2d.hxx" +#include "field3d.hxx" + namespace bout { namespace utils { diff --git a/tests/unit/sys/test_options.cxx b/tests/unit/sys/test_options.cxx index ef9730944b..84b1420072 100644 --- a/tests/unit/sys/test_options.cxx +++ b/tests/unit/sys/test_options.cxx @@ -12,6 +12,7 @@ class OptionsTest : public ::testing::Test { virtual ~OptionsTest() = default; WithQuietOutput quiet_info{output_info}; WithQuietOutput quiet_warn{output_warn}; + WithQuietOutput quiet_progress{output_progress}; }; TEST_F(OptionsTest, IsSet) { @@ -724,3 +725,125 @@ TEST_F(OptionsTest, ComparisonString) { EXPECT_TRUE(option < "ccc"); EXPECT_FALSE(option < "aaa"); } + +TEST_F(OptionsTest, WithDefaultIntThrow) { + // If given an integer as default, will try to cast to int + + Options option; + option = "4.32"; + + EXPECT_THROW(option.withDefault(0), BoutException); +} + +TEST_F(OptionsTest, TypeAttributeBool) { + Options option; + option = "true"; + + // Getting into bool using withDefault should modify the "type" attribute + bool value = option.withDefault(false); + + EXPECT_TRUE(value); + EXPECT_EQ(option.attributes["type"].as(), "bool"); +} + +TEST_F(OptionsTest, AsNoTypeAttribute) { + Options option; + option = "true"; + + // as is const so doesn't set the type attribute + bool value = option.as(); + + EXPECT_TRUE(value); + EXPECT_EQ(option.attributes.count("type"), 0); +} + +TEST_F(OptionsTest, TypeAttributeInt) { + Options option; + option = "42"; + + // Casting to bool should modify the "type" attribute + int value = option.withDefault(-1); + + EXPECT_EQ(value, 42); + EXPECT_EQ(option.attributes["type"].as(), "int"); +} + +TEST_F(OptionsTest, TypeAttributeField2D) { + // Note: Need a Mesh to create Field2D + FakeMesh fieldmesh(6,6,2); + fieldmesh.createDefaultRegions(); + + Options option; + option = "42"; + + // Casting to bool should modify the "type" attribute + Field2D value = option.withDefault(Field2D(-1,&fieldmesh)); + + EXPECT_EQ(value(0,0), 42); + EXPECT_EQ(option.attributes["type"].as(), "Field2D"); +} + +TEST_F(OptionsTest, TypeAttributeField3D) { + // Note: Need a Mesh to create Field3D + FakeMesh fieldmesh(6,6,2); + fieldmesh.createDefaultRegions(); + + Options option; + option = "42"; + + // Casting to bool should modify the "type" attribute + Field3D value = option.withDefault(Field3D(-1,&fieldmesh)); + + EXPECT_EQ(value(0,0,0), 42); + EXPECT_EQ(option.attributes["type"].as(), "Field3D"); +} + +TEST_F(OptionsTest, DocString) { + Options option; + + option.doc("test string"); + + EXPECT_EQ(option.attributes["doc"].as(), "test string"); +} + +TEST_F(OptionsTest, DocStringAssignTo) { + Options option; + + option.doc("test string") = 42; + + EXPECT_EQ(option.attributes["doc"].as(), "test string"); + EXPECT_EQ(option.as(), 42); +} + +TEST_F(OptionsTest, DocStringAssignFrom) { + Options option; + option = 42; + + int value = option.doc("test string"); + + EXPECT_EQ(option.attributes["doc"].as(), "test string"); + EXPECT_EQ(value, 42); +} + +TEST_F(OptionsTest, DocStringWithDefault) { + Options option; + option = 42; + + int value = option.doc("some value").withDefault(2); + + EXPECT_EQ(value, 42); + EXPECT_EQ(option.attributes["doc"].as(), "some value"); +} + +TEST_F(OptionsTest, DocStringNotCopied) { + Options option; + option = 32; + + Options option2 = option; + + int value = option2.doc("test value"); + + EXPECT_EQ(value, 32); + EXPECT_EQ(option2.attributes["doc"].as(), "test value"); + EXPECT_EQ(option.attributes.count("doc"), 0); +} diff --git a/tests/unit/sys/test_type_name.cxx b/tests/unit/sys/test_type_name.cxx new file mode 100644 index 0000000000..91d9601908 --- /dev/null +++ b/tests/unit/sys/test_type_name.cxx @@ -0,0 +1,32 @@ +#include "gtest/gtest.h" +#include "bout/sys/type_name.hxx" +#include "field2d.hxx" +#include "field3d.hxx" + +#include + +using bout::utils::typeName; + +TEST(TypeNameTest, BoolName) { + EXPECT_EQ(typeName(), "bool"); +} + +TEST(TypeNameTest, IntName) { + EXPECT_EQ(typeName(), "int"); +} + +TEST(TypeNameTest, StringName) { + EXPECT_EQ(typeName(), "string"); +} + +TEST(TypeNameTest, BoutRealName) { + EXPECT_EQ(typeName(), "BoutReal"); +} + +TEST(TypeNameTest, Field2DName) { + EXPECT_EQ(typeName(), "Field2D"); +} + +TEST(TypeNameTest, Field3DName) { + EXPECT_EQ(typeName(), "Field3D"); +} From 044e9ec73141dbbab0ca483c869141f31b8efb03 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 28 Mar 2019 00:36:45 +0000 Subject: [PATCH 1174/1783] Document more settings Change some parts of `Mesh`, `Solver` and the output monitor, to use the new `Options` API, and add some documentation. --- include/options.hxx | 9 ++------- src/bout++.cxx | 22 +++++++++++++--------- src/mesh/impls/bout/boutmesh.cxx | 28 +++++++++++++++++----------- src/mesh/mesh.cxx | 5 ++--- src/solver/impls/cvode/cvode.cxx | 28 ++++++++++++++++------------ src/solver/solver.cxx | 10 +++++----- src/sys/options.cxx | 13 +++++++++++++ 7 files changed, 68 insertions(+), 47 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index 3328b4f478..bd793a2c67 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -67,14 +67,9 @@ namespace utils { } template <> - Mesh* meshFromValue(const Field2D& value) { - return value.getMesh(); - } + Mesh* meshFromValue(const Field2D& value); template <> - Mesh* meshFromValue(const Field3D& value) { - return value.getMesh(); - } - + Mesh* meshFromValue(const Field3D& value); } } diff --git a/src/bout++.cxx b/src/bout++.cxx index c855105e64..bd5a0bc79f 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -643,17 +643,21 @@ int BoutMonitor::call(Solver *solver, BoutReal t, int iter, int NOUT) { /// First time the monitor has been called /// Get some options - Options *options = Options::getRoot(); - OPTION(options, wall_limit, -1.0); // Wall time limit. By default, no limit - wall_limit *= 60.0 * 60.0; // Convert from hours to seconds - - OPTION(options, stopCheck, false); + auto& options = Options::root(); + wall_limit = options["wall_limit"] + .doc("Wall time limit in hours. By default (< 0), no limit") + .withDefault(-1.0); + wall_limit *= 60.0 * 60.0; // Convert from hours to seconds + + stopCheck = options["stopCheck"] + .doc("Check if a file exists, and exit if it does.") + .withDefault(false); if (stopCheck) { - // Get name of file whose existence triggers a stop - OPTION(options, stopCheckName, "BOUT.stop"); + stopCheckName = options["stopCheckName"] + .doc("Name of file whose existence triggers a stop") + .withDefault("BOUT.stop"); // Now add data directory to start of name to ensure we look in a run specific location - std::string data_dir; - Options::getRoot()->get("datadir", data_dir, string(DEFAULT_DIR)); + std::string data_dir = Options::root()["datadir"].withDefault(DEFAULT_DIR); stopCheckName = data_dir + "/" + stopCheckName; } diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 4342dbafce..77a4c088e4 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -53,8 +53,7 @@ BoutMesh::BoutMesh(GridDataSource *s, Options *opt) : Mesh(s, opt) { OPTION(options, symmetricGlobalX, true); if (!options->isSet("symmetricGlobalY")) { - std::string optionfile; - OPTION(Options::getRoot(), optionfile, ""); + std::string optionfile = Options::root()["optionfile"].withDefault(""); output_warn << "WARNING: The default of this option has changed in release 4.1.\n\ If you want the old setting, you have to specify mesh:symmetricGlobalY=false in " << optionfile << "\n"; @@ -91,7 +90,7 @@ int BoutMesh::load() { output_progress << _("Loading mesh") << endl; // Use root level options - Options *options = Options::getRoot(); + auto& options = Options::root(); ////////////// // Number of processors @@ -133,12 +132,12 @@ int BoutMesh::load() { // get from options if (Mesh::get(MXG, "MXG")) { // Error code returned - options->get("MXG", MXG, 2); + MXG = options["MXG"].doc("Number of guard cells on each side in X").withDefault(2); } ASSERT0(MXG >= 0); if (Mesh::get(MYG, "MYG")) { - options->get("MYG", MYG, 2); + MYG = options["MYG"].doc("Number of guard cells on each side in Y").withDefault(2); } ASSERT0(MYG >= 0); @@ -237,8 +236,11 @@ int BoutMesh::load() { // For now don't parallelise z NZPE = 1; - if (options->isSet("NXPE")) { // Specified NXPE - options->get("NXPE", NXPE, 1); // Decomposition in the radial direction + if (options.isSet("NXPE")) { // Specified NXPE + NXPE = options["NXPE"] + .doc("Decomposition in the radial direction. If not given then calculated " + "automatically.") + .withDefault(1); if ((NPES % NXPE) != 0) { throw BoutException( _("Number of processors (%d) not divisible by NPs in x direction (%d)\n"), NPES, @@ -433,9 +435,11 @@ int BoutMesh::load() { /// Get mesh options OPTION(options, IncIntShear, false); - OPTION(options, periodicX, false); // Periodic in X + periodicX = options["periodicX"].doc("Make grid periodic in X?").withDefault(false); - OPTION(options, async_send, false); // Whether to use asyncronous sends + async_send = options["async_send"] + .doc("Whether to use asyncronous MPI sends") + .withDefault(false); // Set global offsets @@ -443,7 +447,7 @@ int BoutMesh::load() { OffsetY = PE_YIND * MYSUB; OffsetZ = 0; - if (options->isSet("zperiod")) { + if (options.isSet("zperiod")) { OPTION(options, zperiod, 1); ZMIN = 0.0; ZMAX = 1.0 / static_cast(zperiod); @@ -474,7 +478,9 @@ int BoutMesh::load() { /// Call topology to set layout of grid topology(); - OPTION(options, TwistShift, false); + TwistShift = options["TwistShift"] + .doc("Apply a Twist-Shift boundary using ShiftAngle?") + .withDefault(false); if (TwistShift) { output_info.write("Applying Twist-Shift condition. Interpolation: FFT\n"); diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 8766cb5c32..cd03fa9972 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -317,10 +317,9 @@ void Mesh::setParallelTransform() { }else if(ptstr == "fci") { - Options *fci_options = Options::getRoot()->getSection("fci"); + auto& fci_options = Options::root()["fci"]; // Flux Coordinate Independent method - bool fci_zperiodic; - fci_options->get("z_periodic", fci_zperiodic, true); + bool fci_zperiodic = fci_options["z_periodic"].withDefault(true); transform = bout::utils::make_unique(*this, fci_zperiodic); }else { diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index 8810cd233a..682de9bcc4 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -158,8 +158,10 @@ int CvodeSolver::init(int nout, BoutReal tstep) { // Put the variables into uvec save_vars(NV_DATA_P(uvec)); - diagnose = (*options)["diagnose"].withDefault(false); - const auto adams_moulton = (*options)["adams_moulton"].withDefault(false); + diagnose = (*options)["diagnose"].doc("Print solver diagnostic information?").withDefault(false); + const auto adams_moulton = (*options)["adams_moulton"] + .doc("Use Adams Moulton implicit multistep. Otherwise BDF method.") + .withDefault(false); if (adams_moulton) { // By default use functional iteration for Adams-Moulton @@ -183,7 +185,7 @@ int CvodeSolver::init(int nout, BoutReal tstep) { if (CVodeInit(cvode_mem, cvode_rhs, simtime, uvec) < 0) throw BoutException("CVodeInit failed\n"); - const auto max_order = (*options)["cvode_max_order"].withDefault(-1); + const auto max_order = (*options)["cvode_max_order"].doc("Maximum order of method to use. < 0 means no limit.").withDefault(-1); if (max_order > 0) { if (CVodeSetMaxOrd(cvode_mem, max_order) < 0) throw BoutException("CVodeSetMaxOrder failed\n"); @@ -196,8 +198,8 @@ int CvodeSolver::init(int nout, BoutReal tstep) { throw BoutException("CVodeSetStabLimDet failed\n"); } - const auto abstol = (*options)["ATOL"].withDefault(1.0e-12); - const auto reltol = (*options)["RTOL"].withDefault(1.0e-5); + const auto abstol = (*options)["ATOL"].doc("Absolute tolerance").withDefault(1.0e-12); + const auto reltol = (*options)["RTOL"].doc("Relative tolerance").withDefault(1.0e-5); const auto use_vector_abstol = (*options)["use_vector_abstol"].withDefault(false); if (use_vector_abstol) { std::vector f2dtols; @@ -236,20 +238,20 @@ int CvodeSolver::init(int nout, BoutReal tstep) { throw BoutException("CVodeSStolerances failed\n"); } - const auto mxsteps = (*options)["mxstep"].withDefault(500); + const auto mxsteps = (*options)["mxstep"].doc("Maximum number of internal steps between outputs.").withDefault(500); CVodeSetMaxNumSteps(cvode_mem, mxsteps); - const auto max_timestep = (*options)["max_timestep"].withDefault(-1.); + const auto max_timestep = (*options)["max_timestep"].doc("Maximum time step size").withDefault(-1.0); if (max_timestep > 0.0) { CVodeSetMaxStep(cvode_mem, max_timestep); } - const auto min_timestep = (*options)["min_timestep"].withDefault(-1); + const auto min_timestep = (*options)["min_timestep"].doc("Minimum time step size").withDefault(-1.0); if (min_timestep > 0.0) { CVodeSetMinStep(cvode_mem, min_timestep); } - const auto start_timestep = (*options)["start_timestep"].withDefault(-1); + const auto start_timestep = (*options)["start_timestep"].doc("Starting time step. < 0 then chosen by CVODE.").withDefault(-1.0); if (start_timestep > 0.0) { CVodeSetInitStep(cvode_mem, start_timestep); } @@ -263,12 +265,14 @@ int CvodeSolver::init(int nout, BoutReal tstep) { if (!func_iter) { output_info.write("\tUsing Newton iteration\n"); TRACE("Setting preconditioner"); - const auto maxl = (*options)["maxl"].withDefault(5); - const auto use_precon = (*options)["use_precon"].withDefault(false); + const auto maxl = (*options)["maxl"].doc("Maximum number of linear iterations").withDefault(5); + const auto use_precon = (*options)["use_precon"].doc("Use preconditioner?").withDefault(false); if (use_precon) { - const auto rightprec = (*options)["rightprec"].withDefault(false); + const auto rightprec = (*options)["rightprec"] + .doc("Use right preconditioner? Otherwise use left.") + .withDefault(false); const int prectype = rightprec ? PREC_RIGHT : PREC_LEFT; #if SUNDIALS_VERSION_MAJOR >= 3 diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 362332485d..d3014ea872 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -173,8 +173,8 @@ void Solver::add(Field2D &v, const std::string name) { // Check if the boundary regions should be evolved // First get option from section "All" // then use that as default for specific section - Options::getRoot()->getSection("all")->get("evolve_bndry", d.evolve_bndry, false); - Options::getRoot()->getSection(name)->get("evolve_bndry", d.evolve_bndry, d.evolve_bndry); + d.evolve_bndry = Options::root()["all"]["evolve_bndry"].withDefault(false); + d.evolve_bndry = Options::root()[name]["evolve_bndry"].withDefault(d.evolve_bndry); v.applyBoundary(true); @@ -220,7 +220,7 @@ void Solver::add(Field3D &v, const std::string name) { // Load solution at t = 0 FieldFactory *fact = FieldFactory::get(); - v = fact->create3D("solution", Options::getRoot()->getSection(name), mesh, v.getLocation()); + v = fact->create3D("solution", &Options::root()[name], mesh, v.getLocation()); } else { initial_profile(name, v); @@ -235,8 +235,8 @@ void Solver::add(Field3D &v, const std::string name) { // Check if the boundary regions should be evolved // First get option from section "All" // then use that as default for specific section - Options::getRoot()->getSection("all")->get("evolve_bndry", d.evolve_bndry, false); - Options::getRoot()->getSection(name)->get("evolve_bndry", d.evolve_bndry, d.evolve_bndry); + d.evolve_bndry = Options::root()["all"]["evolve_bndry"].withDefault(false); + d.evolve_bndry = Options::root()[name]["evolve_bndry"].withDefault(d.evolve_bndry); v.applyBoundary(true); // Make sure initial profile obeys boundary conditions v.setLocation(d.location); // Restore location if changed diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 3b1902b932..41b82fbcbe 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -7,6 +7,19 @@ #include #include +namespace bout { +namespace utils { + template <> + Mesh* meshFromValue(const Field2D& value) { + return value.getMesh(); + } + template <> + Mesh* meshFromValue(const Field3D& value) { + return value.getMesh(); + } +} +} + /// The source label given to default values const std::string Options::DEFAULT_SOURCE{_("default")}; Options *Options::root_instance{nullptr}; From 6d808221880309c3c2f8e9045fa2a1634aec169d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Mar 2019 09:50:19 +0000 Subject: [PATCH 1175/1783] Apply finalisation workaround to missed boutcore MMS test --- tests/MMS/bracket/runtest | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/MMS/bracket/runtest b/tests/MMS/bracket/runtest index a4b83b3191..c552170cc4 100755 --- a/tests/MMS/bracket/runtest +++ b/tests/MMS/bracket/runtest @@ -83,5 +83,13 @@ if errlist: print(errlist) exit(1) +# FIXME: this is a workaround for a strange bug, MPI_Comm_free after +# MPI_Finalize. Seems to be from the global mesh getting destroyed +# after/at the same time as finalise is called -- hence explicitly +# deleting it here +mesh = bc.Mesh.getGlobal() +del mesh +bc.finalise() + print("All tests passed") exit(0) From 8ad4b115a3f55b651eb320b9d26232e739c48088 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Mar 2019 09:50:54 +0000 Subject: [PATCH 1176/1783] PEP8 boutcore bracket MMS test --- tests/MMS/bracket/runtest | 91 ++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/tests/MMS/bracket/runtest b/tests/MMS/bracket/runtest index c552170cc4..ac316316db 100755 --- a/tests/MMS/bracket/runtest +++ b/tests/MMS/bracket/runtest @@ -20,7 +20,7 @@ bc.init("-q -q -q") funcs = [ - ['sin(z)','sin(4*x)' , '4*cos(z)*cos(4*x)' ] + ['sin(z)', 'sin(4*x)', '4*cos(z)*cos(4*x)'] ] # List of NX values to use @@ -29,55 +29,58 @@ nlist = [8, 16, 32] prec = 0.2 -def genMesh(nx,ny,nz,**kwargs): - bc.setOption("mesh:mxg",str(2 if nx > 1 else 0), force=True) - bc.setOption("mesh:myg",str(2 if ny > 1 else 0), force=True) - bc.setOption("mesh:nx",str(nx + 4 if nx > 1 else nx), force=True) - bc.setOption("mesh:ny",str(ny), force=True) - bc.setOption("mz",str(nz), force=True) - bc.setOption("mesh:nz",str(nz), force=True) - bc.setOption("mesh:dx","2*pi/(%d)"%(nx), force=True) - bc.setOption("mesh:dy","1/(%d)"%(ny), force=True) - bc.setOption("mesh:dz","1/(%d)"%(nz), force=True) - for k,v in kwargs.items(): - bc.setOption(k,v, force=True) +def genMesh(nx, ny, nz, **kwargs): + bc.setOption("mesh:mxg", str(2 if nx > 1 else 0), force=True) + bc.setOption("mesh:myg", str(2 if ny > 1 else 0), force=True) + bc.setOption("mesh:nx", str(nx + 4 if nx > 1 else nx), force=True) + bc.setOption("mesh:ny", str(ny), force=True) + bc.setOption("mz", str(nz), force=True) + bc.setOption("mesh:nz", str(nz), force=True) + bc.setOption("mesh:dx", "2*pi/(%d)" % (nx), force=True) + bc.setOption("mesh:dy", "1/(%d)" % (ny), force=True) + bc.setOption("mesh:dz", "1/(%d)" % (nz), force=True) + for k, v in kwargs.items(): + bc.setOption(k, v, force=True) return bc.Mesh(section="mesh") -errlist="" -brackets=[["ARAKAWA", 2,{}], - ["STD", 1 , {"mesh:ddx:upwind":"U1", - "mesh:ddz:upwind":"U1"} - ], - ["STD", 2 , {"mesh:ddx:upwind":"C2", - "mesh:ddz:upwind":"C2"} - ], - # Weno convergence order is currently under discusision: - # https://github.com/boutproject/BOUT-dev/issues/1049 - # ["STD", 3 , {"mesh:ddx:upwind":"W3", - # "mesh:ddz:upwind":"W3"} - # ] -] -for in1 , in2, outfunc in funcs: - for name, order ,args in brackets: - errors=[] + + +errlist = "" +brackets = [["ARAKAWA", 2, {}], + ["STD", 1, {"mesh:ddx:upwind": "U1", + "mesh:ddz:upwind": "U1"} + ], + ["STD", 2, {"mesh:ddx:upwind": "C2", + "mesh:ddz:upwind": "C2"} + ], + # Weno convergence order is currently under discusision: + # https://github.com/boutproject/BOUT-dev/issues/1049 + # ["STD", 3 , {"mesh:ddx:upwind":"W3", + # "mesh:ddz:upwind":"W3"} + # ] + ] +for in1, in2, outfunc in funcs: + for name, order, args in brackets: + errors = [] for n in nlist[-2:]: - mesh=genMesh(n,1,n,**args) - inf1=bc.create3D(in1,mesh) - inf2=bc.create3D(in2,mesh) - inf=bc.bracket(inf1,inf2,method=name) - outf=bc.create3D(outfunc,mesh) - err=(inf-outf) - slize=[slice(2,-2) , 0, slice(None)] - err=err[slize] - err=np.sqrt(np.mean(err**2)) + mesh = genMesh(n, 1, n, **args) + inf1 = bc.create3D(in1, mesh) + inf2 = bc.create3D(in2, mesh) + inf = bc.bracket(inf1, inf2, method=name) + outf = bc.create3D(outfunc, mesh) + err = (inf-outf) + slize = [slice(2, -2), 0, slice(None)] + err = err[slize] + err = np.sqrt(np.mean(err**2)) errors.append(err) - errc=np.log(errors[-2]/errors[-1]) - difc=np.log(nlist[-1]/nlist[-2]) - conv=errc/difc + errc = np.log(errors[-2]/errors[-1]) + difc = np.log(nlist[-1]/nlist[-2]) + conv = errc/difc if order-prec < conv < order+prec: pass else: - err="{%s,%s} -> %s failed (conv: %f - expected: %f)\n"%(in1,in2,outfunc,conv,order) - errlist+=err + err = "{%s,%s} -> %s failed (conv: %f - expected: %f)\n" % ( + in1, in2, outfunc, conv, order) + errlist += err if errlist: print(errlist) From 3ea72a8959a3895daf7c2e15c4fe66ffbbbdedf9 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 28 Mar 2019 18:39:29 +0000 Subject: [PATCH 1177/1783] Updating Options use, adding docs Some core library code updates, so that options are documented in the BOUT.settings file. --- src/invert/fft_fftw.cxx | 4 +- src/invert/laplace/invert_laplace.cxx | 4 +- src/invert/laplacexy/laplacexy.cxx | 48 +++++----- .../laplacexz/impls/petsc/laplacexz-petsc.cxx | 89 ++++++++++--------- src/invert/laplacexz/laplacexz.cxx | 11 ++- .../interpolation/interpolation_factory.cxx | 3 +- src/mesh/parallel/shiftedmetric.cxx | 8 +- src/solver/impls/rk4/rk4.cxx | 16 ++-- src/solver/impls/rkgeneric/rkgeneric.cxx | 12 +-- 9 files changed, 106 insertions(+), 89 deletions(-) diff --git a/src/invert/fft_fftw.cxx b/src/invert/fft_fftw.cxx index 5e8e3960bd..e5c4b5f532 100644 --- a/src/invert/fft_fftw.cxx +++ b/src/invert/fft_fftw.cxx @@ -59,7 +59,9 @@ void fft_init(Options* options) { if (options == nullptr) { options = Options::getRoot()->getSection("fft"); } - fft_init((*options)["fft_measure"].withDefault(false)); + fft_init((*options)["fft_measure"] + .doc("Perform speed measurements to optimise settings?") + .withDefault(false)); } void fft_init(bool fft_measure) { diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index 53ee91e4e5..1812078e8d 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -105,7 +105,9 @@ Laplacian::Laplacian(Options *options, const CELL_LOC loc, Mesh *mesh_in) OPTION(options, outer_boundary_flags, 0); } - OPTION(options, include_yguards, false); + include_yguards = (*options)["include_yguards"] + .doc("Solve Laplacian in Y guard cells?") + .withDefault(false); OPTION2(options, extra_yguards_lower, extra_yguards_upper, 0); } diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index 88c661c76c..4cd5f3fafa 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -32,7 +32,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) if (opt == nullptr) { // If no options supplied, use default - opt = Options::getRoot()->getSection("laplacexy"); + opt = &(Options::root()["laplacexy"]); } // Get MPI communicator @@ -212,8 +212,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) // Configure Linear Solver - bool direct; - OPTION(opt, direct, false); + bool direct = (*opt)["direct"].doc("Use a direct LU solver").withDefault(false); if(direct) { KSPGetPC(ksp,&pc); @@ -227,21 +226,22 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) // Convergence Parameters. Solution is considered converged if |r_k| < max( rtol * |b| , atol ) // where r_k = b - Ax_k. The solution is considered diverged if |r_k| > dtol * |b|. - BoutReal rtol, atol, dtol; - int maxits; ///< Maximum iterations - - OPTION(opt, rtol, 1e-5); // Relative tolerance - OPTION(opt, atol, 1e-10); // Absolute tolerance - OPTION(opt, dtol, 1e3); // Diverged threshold - OPTION(opt, maxits, 100000); // Maximum iterations - + + BoutReal rtol = (*opt)["rtol"].doc("Relative tolerance").withDefault(1e-5); + BoutReal atol = (*opt)["atol"] + .doc("Absolute tolerance. The solution is considered converged if |Ax-b| " + "< max( rtol * |b| , atol )") + .withDefault(1e-10); + BoutReal dtol = (*opt)["dtol"] + .doc("The solution is considered diverged if |Ax-b| > dtol * |b|") + .withDefault(1e3); + int maxits = (*opt)["maxits"].doc("Maximum iterations").withDefault(100000); + // Get KSP Solver Type - std::string ksptype; - opt->get("ksptype", ksptype, "gmres"); + std::string ksptype = (*opt)["ksptype"].doc("KSP solver type").withDefault("gmres"); // Get PC type - std::string pctype; - opt->get("pctype", pctype, "none", true); + std::string pctype = (*opt)["pctype"].doc("Preconditioner type").withDefault("none"); KSPSetType( ksp, ksptype.c_str() ); KSPSetTolerances( ksp, rtol, atol, dtol, maxits ); @@ -256,12 +256,12 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) PCShellSetApply(pc,laplacePCapply); PCShellSetContext(pc,this); - bool rightprec; - OPTION(opt, rightprec, true); - if(rightprec) { + bool rightprec = (*opt)["rightprec"].doc("Use right preconditioning?").withDefault(true); + if (rightprec) { KSPSetPCSide(ksp, PC_RIGHT); // Right preconditioning - }else + } else { KSPSetPCSide(ksp, PC_LEFT); // Left preconditioning + } } } @@ -269,10 +269,10 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) /////////////////////////////////////////////////// // Decide boundary condititions - if(localmesh->periodicY(localmesh->xstart)) { + if (localmesh->periodicY(localmesh->xstart)) { // Periodic in Y, so in the core opt->get("core_bndry_dirichlet", x_inner_dirichlet, false); - }else { + } else { // Non-periodic, so in the PF region opt->get("pf_bndry_dirichlet", x_inner_dirichlet, true); } @@ -281,8 +281,10 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) /////////////////////////////////////////////////// // Including Y derivatives? - OPTION(opt, include_y_derivs, true); - + include_y_derivs = (*opt)["include_y_derivs"] + .doc("Include Y derivatives in operator to invert?") + .withDefault(true); + /////////////////////////////////////////////////// // Set the default coefficients Field2D one(1., localmesh); diff --git a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx index 7c85fdefb2..182fa63ec7 100644 --- a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx +++ b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx @@ -97,58 +97,67 @@ LaplaceXZpetsc::LaplaceXZpetsc(Mesh *m, Options *opt, const CELL_LOC loc) if (opt == nullptr) { // If no options supplied, use default - opt = Options::getRoot()->getSection("laplacexz"); + opt = &(Options::root())["laplacexz"]; } // Getting the boundary flags OPTION(opt, inner_boundary_flags, 0); OPTION(opt, outer_boundary_flags, 0); - #if CHECK > 0 - // Checking flags are set to something which is not implemented - // This is done binary (which is possible as each flag is a power of 2) - if ( inner_boundary_flags & ~implemented_boundary_flags ) { - throw BoutException("Attempted to set LaplaceXZ inversion boundary flag that is not implemented in petsc_laplace.cxx"); - } - if ( outer_boundary_flags & ~implemented_boundary_flags ) { - throw BoutException("Attempted to set LaplaceXZ inversion boundary flag that is not implemented in petsc_laplace.cxx"); - } - if(localmesh->periodicX) { - throw BoutException("LaplacePetsc does not work with periodicity in the x direction (localmesh->PeriodicX == true). Change boundary conditions or use serial-tri or cyclic solver instead"); - } - #endif +#if CHECK > 0 + // Checking flags are set to something which is not implemented + // This is done binary (which is possible as each flag is a power of 2) + if (inner_boundary_flags & ~implemented_boundary_flags) { + throw BoutException("Attempted to set LaplaceXZ inversion boundary flag that is not " + "implemented in petsc_laplace.cxx"); + } + if (outer_boundary_flags & ~implemented_boundary_flags) { + throw BoutException("Attempted to set LaplaceXZ inversion boundary flag that is not " + "implemented in petsc_laplace.cxx"); + } + if (localmesh->periodicX) { + throw BoutException("LaplacePetsc does not work with periodicity in the x direction " + "(localmesh->PeriodicX == true). Change boundary conditions or " + "use serial-tri or cyclic solver instead"); + } +#endif - OPTION(opt, reuse_limit, 100); + reuse_limit = (*opt)["reuse_limit"] + .doc("How many solves can the preconditioner be reused?") + .withDefault(100); reuse_count = reuse_limit + 1; // So re-calculates first time // Convergence Parameters. Solution is considered converged if |r_k| < max( rtol * |b| , atol ) // where r_k = b - Ax_k. The solution is considered diverged if |r_k| > dtol * |b|. - BoutReal rtol, atol, dtol; - int maxits; ///< Maximum iterations - OPTION(opt, rtol, 1e-5); // Relative tolerance - OPTION(opt, atol, 1e-10); // Absolute tolerance - OPTION(opt, dtol, 1e3); // Diverged threshold - OPTION(opt, maxits, 100000); // Maximum iterations - // Get KSP Solver Type - std::string ksptype; - opt->get("ksptype", ksptype, "gmres"); + BoutReal rtol = (*opt)["rtol"].doc("Relative tolerance").withDefault(1e-5); + BoutReal atol = (*opt)["atol"] + .doc("Absolute tolerance. The solution is considered converged if |Ax-b| " + "< max( rtol * |b| , atol )") + .withDefault(1e-10); + BoutReal dtol = (*opt)["dtol"] + .doc("The solution is considered diverged if |Ax-b| > dtol * |b|") + .withDefault(1e3); + int maxits = (*opt)["maxits"].doc("Maximum iterations").withDefault(100000); + // Get KSP Solver Type + std::string ksptype = (*opt)["ksptype"].doc("KSP solver type").withDefault("gmres"); + // Get PC type - std::string pctype; - opt->get("pctype", pctype, "lu", true); + std::string pctype = (*opt)["pctype"].doc("Preconditioner type").withDefault("none"); - std::string factor_package; - opt->get("factor_package", factor_package, "petsc", true); + std::string factor_package = (*opt)["factor_package"] + .doc("Package to use in preconditioner. Passed to PCFactorSetMatSolver") + .withDefault("petsc"); // Get MPI communicator MPI_Comm comm = localmesh->getXcomm(); // Local size int localN = (localmesh->xend - localmesh->xstart + 1) * (localmesh->LocalNz); - if(localmesh->firstX()) { + if (localmesh->firstX()) { localN += localmesh->LocalNz; } - if(localmesh->lastX()) { + if (localmesh->lastX()) { localN += localmesh->LocalNz; } @@ -158,7 +167,7 @@ LaplaceXZpetsc::LaplaceXZpetsc(Mesh *m, Options *opt, const CELL_LOC loc) VecSetFromOptions( xs ); VecDuplicate( xs , &bs ); - for(int y = localmesh->ystart; y <= localmesh->yend; y++) { + for (int y = localmesh->ystart; y <= localmesh->yend; y++) { YSlice data; data.yindex = y; @@ -175,7 +184,7 @@ LaplaceXZpetsc::LaplaceXZpetsc(Mesh *m, Options *opt, const CELL_LOC loc) PetscMalloc( (localN)*sizeof(PetscInt), &d_nnz ); PetscMalloc( (localN)*sizeof(PetscInt), &o_nnz ); - for(int i=0;ifirstX()) { - for(int z=0;zLocalNz;z++) { + if (localmesh->firstX()) { + for (int z = 0; z < localmesh->LocalNz; z++) { d_nnz[z] = 2; } - }else { + } else { // One point on another processor - for(int z=0;zLocalNz;z++) { + for (int z = 0; z < localmesh->LocalNz; z++) { d_nnz[z] -= 1; o_nnz[z] += 1; } } - if(localmesh->lastX()) { - for(int z=0;zLocalNz;z++) { + if (localmesh->lastX()) { + for (int z = 0; z < localmesh->LocalNz; z++) { int ind = localN - (localmesh->LocalNz) + z; d_nnz[ind] = 2; } - }else { + } else { // One point on another processor - for(int z=0;zLocalNz;z++) { + for (int z = 0; z < localmesh->LocalNz; z++) { int ind = localN - (localmesh->LocalNz) + z; d_nnz[ind] -= 1; o_nnz[ind] += 1; diff --git a/src/invert/laplacexz/laplacexz.cxx b/src/invert/laplacexz/laplacexz.cxx index 05bba728ca..f4c6c7d6da 100644 --- a/src/invert/laplacexz/laplacexz.cxx +++ b/src/invert/laplacexz/laplacexz.cxx @@ -13,17 +13,16 @@ LaplaceXZ* LaplaceXZ::create(Mesh *m, Options *options, const CELL_LOC loc) { } if (options == nullptr) { - options = Options::getRoot()->getSection("laplacexz"); + options = &(Options::root()["laplacexz"]); } - std::string type; - options->get("type", type, "cyclic"); + std::string type = (*options)["type"].withDefault("cyclic"); - if(strcasecmp(type.c_str(), "cyclic") == 0) { + if (strcasecmp(type.c_str(), "cyclic") == 0) { return new LaplaceXZcyclic(m, options, loc); - }else if(strcasecmp(type.c_str(), "petsc") == 0) { + } else if(strcasecmp(type.c_str(), "petsc") == 0) { return new LaplaceXZpetsc(m, options, loc); - }else { + } else { throw BoutException("Unknown LaplaceXZ solver type '%s'", type.c_str()); } return nullptr; diff --git a/src/mesh/interpolation/interpolation_factory.cxx b/src/mesh/interpolation/interpolation_factory.cxx index c09da0bbd5..bc3adbceaf 100644 --- a/src/mesh/interpolation/interpolation_factory.cxx +++ b/src/mesh/interpolation/interpolation_factory.cxx @@ -36,8 +36,7 @@ Interpolation* InterpolationFactory::create(Options *options, Mesh *mesh) { if (options == nullptr) options = Options::getRoot()->getSection("interpolation"); - std::string interp_option; - options->get("type", interp_option, type); + std::string interp_option = (*options)["type"].withDefault(type); if (!interp_option.empty()) type = interp_option.c_str(); diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index fb0d96a879..a05a686136 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -27,8 +27,12 @@ ShiftedMetric::ShiftedMetric(Mesh& m) : ParallelTransform(m), zShift(&m) { // TwistShift needs to be set for derivatives to be correct at the jump where // poloidal angle theta goes 2pi->0 - bool twistshift = Options::root()["TwistShift"].withDefault(false); - bool shift_without_twist = Options::root()["ShiftWithoutTwist"].withDefault(false); + bool twistshift = Options::root()["TwistShift"] + .doc("Enable twist-shift boundary condition in core region?") + .withDefault(false); + bool shift_without_twist = Options::root()["ShiftWithoutTwist"] + .doc("Use ShiftedMetric without TwistShift?") + .withDefault(false); if (!twistshift and !shift_without_twist) { throw BoutException( "ShiftedMetric usually requires the option TwistShift=true\n" diff --git a/src/solver/impls/rk4/rk4.cxx b/src/solver/impls/rk4/rk4.cxx index 418d45a2e8..6ac3c7d336 100644 --- a/src/solver/impls/rk4/rk4.cxx +++ b/src/solver/impls/rk4/rk4.cxx @@ -17,10 +17,10 @@ RK4Solver::~RK4Solver() { } void RK4Solver::setMaxTimestep(BoutReal dt) { - if(dt > timestep) + if (dt > timestep) return; // Already less than this - if(adaptive) + if (adaptive) timestep = dt; // Won't be used this time, but next } @@ -67,12 +67,12 @@ int RK4Solver::init(int nout, BoutReal tstep) { save_vars(std::begin(f0)); // Get options - OPTION(options, atol, 1.e-5); // Absolute tolerance - OPTION(options, rtol, 1.e-3); // Relative tolerance - OPTION(options, max_timestep, tstep); // Maximum timestep - OPTION(options, timestep, max_timestep); // Starting timestep - OPTION(options, mxstep, 500); // Maximum number of steps between outputs - OPTION(options, adaptive, false); + atol = (*options)["atol"].doc("Absolute tolerance").withDefault(1.e-5); + rtol = (*options)["rtol"].doc("Relative tolerance").withDefault(1.e-3); + max_timestep = (*options)["max_timestep"].doc("Maximum timestep").withDefault(tstep); + timestep = (*options)["timestep"].doc("Starting timestep").withDefault(max_timestep); + mxstep = (*options)["mxstep"].doc("Maximum number of steps between outputs").withDefault(500); + adaptive = (*options)["adaptive"].doc("Adapt internal timestep using ATOL and RTOL.").withDefault(false); return 0; } diff --git a/src/solver/impls/rkgeneric/rkgeneric.cxx b/src/solver/impls/rkgeneric/rkgeneric.cxx index 4ed7879e54..f0dca63501 100644 --- a/src/solver/impls/rkgeneric/rkgeneric.cxx +++ b/src/solver/impls/rkgeneric/rkgeneric.cxx @@ -58,12 +58,12 @@ int RKGenericSolver::init(int nout, BoutReal tstep) { n3Dvars(), n2Dvars(), neq, nlocal); // Get options - OPTION(options, atol, 1.e-5); // Absolute tolerance - OPTION(options, rtol, 1.e-3); // Relative tolerance - OPTION(options, max_timestep, tstep); // Maximum timestep - OPTION(options, timestep, max_timestep); // Starting timestep - OPTION(options, mxstep, 500); // Maximum number of steps between outputs - OPTION(options, adaptive, true); // Prefer adaptive scheme + atol = (*options)["atol"].doc("Absolute tolerance").withDefault(1.e-5); + rtol = (*options)["rtol"].doc("Relative tolerance").withDefault(1.e-3); + max_timestep = (*options)["max_timestep"].doc("Maximum timestep").withDefault(tstep); + timestep = (*options)["timestep"].doc("Starting timestep").withDefault(max_timestep); + mxstep = (*options)["mxstep"].doc("Maximum number of steps between outputs").withDefault(500); + adaptive = (*options)["adaptive"].doc("Adapt internal timestep using ATOL and RTOL.").withDefault(true); // Allocate memory f0.reallocate(nlocal); // Input From 42ba2444a624489ca907d04ec2a26973d8837939 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 28 Mar 2019 20:50:15 +0000 Subject: [PATCH 1178/1783] Add documentation on OptionsNetCDF Adapted from the PR description, shows how to read and write options from NetCDF files. --- manual/sphinx/user_docs/bout_options.rst | 81 ++++++++++++++++++++++++ manual/sphinx/user_docs/running_bout.rst | 4 +- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index 33c84bf3cb..b83cb1e6ff 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -648,6 +648,87 @@ has a method:: This is currently quite rudimentary and needs improving. +Reading and writing to NetCDF +----------------------------- + +If NetCDF4 support is enabled, then the ``OptionsNetCDF`` class +provides an experimental way to read and write options. + +Examples are in integrated test ``tests/integrated/test-options-netcdf/`` + +To write the current ``Options`` tree (e.g. from ``BOUT.inp``) to a +NetCDF file:: + + OptionsNetCDF("settings.nc").write(Options::root()); + +and to read it in again:: + + Options data = OptionsNetCDF("settings.nc").read(); + +Fields can also be stored and written:: + + Options fields; + fields["f2d"] = Field2D(1.0); + fields["f3d"] = Field3D(2.0); + OptionsNetCDF("fields.nc").write(fields); + +This should allow the input settings and evolving variables to be +combined into a single tree (see above on joining trees) and written +to the output dump or restart files. + +Reading fields is a bit more difficult. Currently 1D data is read as +an ``Array``, 2D as ``Matrix`` and 3D as +``Tensor``. These can be extracted directly from the +``Options`` tree, or converted to a Field if given a ``Mesh``:: + + Options fields_in = OptionsNetCDF("fields.nc").read(); + Field2D f2d = fields_in["f2d"].as(mesh); + Field3D f3d = fields_in["f3d"].as(mesh); + +Currently this only works if the data in the ``Matrix`` or ``Tensor`` is the +same size as the ``Field``. In the case of grid files, the fields only +needs a part of the global values. Some kind of mapping from the global +index to local index is needed, probably defined by ``Mesh``. For now it +should be possible to be compatible with the current system, so that +all quantities from the grid file are accessed through Mesh::get. + +Time dependence +~~~~~~~~~~~~~~~ + +When writing NetCDF files, some variables should have a time +dimension added, and then be added to each time they are written. This +has been implemented using an attribute: If variables in the ``Options`` +tree have an attribute "time_dimension" then that is used as the name +of the time dimension in the output file. This allows multiple time +dimensions e.g. high frequency diagnostics and low frequency outputs, +to exist in the same file:: + + Options data; + data["scalar"] = 1.0; + data["scalar"].attributes["time_dimension"] = "t"; + + data["field"] = Field3D(2.0); + data["field"].attributes["time_dimension"] = "t"; + + OptionsNetCDF("time.nc").write(data); + + // Update time-dependent values. This can be done without `force` if the time_dimension + // attribute is set + data["scalar"] = 2.0; + data["field"] = Field3D(3.0); + + // Append data to file + OptionsNetCDF("time.nc", OptionsNetCDF::FileMode::append).write(data); + +Some issues: + +* Currently all variables in the Options tree are written when passed + to ``OptionsNetCDF::write``. This means that the variables with + different time dimensions should be stored in different Options + trees, so they can be written at different times. One possibility is + to have an optional argument to write, so that only variables with + one specified time dimension are updated. + FFT --- diff --git a/manual/sphinx/user_docs/running_bout.rst b/manual/sphinx/user_docs/running_bout.rst index 228e802a6e..625b2d744c 100644 --- a/manual/sphinx/user_docs/running_bout.rst +++ b/manual/sphinx/user_docs/running_bout.rst @@ -79,7 +79,9 @@ run, and produce a bunch of files in the ``data/`` subdirectory. - ``BOUT.settings`` contains all the options used in the code, including options which were not set and used the default values. It's in the same format as BOUT.inp, so can be renamed and used to re-run simulations - if needed. + if needed. In some cases the options used have documentation, with a brief + explanation of how they are used. In most cases the type the option is used + as (e.g. ``int``, ``BoutReal`` or ``bool``) is given. - ``BOUT.restart.*.nc`` are the restart files for the last time point. Currently each processor saves its own state in a separate file, but From bc06e4daba6101a49ccc6f5a55e139dd6c810ecf Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 29 Mar 2019 09:40:11 +0000 Subject: [PATCH 1179/1783] Revert "Use non-const BoutReal arguments in gen_fieldops.py/gen_fieldops.jinja" This reverts commit 80525bab6332e2724dc2310241ba8e7fdcad053a. It does make sense to have 'const' qualifier for pass-by-value arguments only in the implementation and not in the interface. The const does not affect the interface, so does not need to be there, but affects the local variable inside the scope of the implementation. See #1655 for explanation from @dschwoerer. --- src/field/gen_fieldops.jinja | 4 +- src/field/gen_fieldops.py | 3 +- src/field/generated_fieldops.cxx | 72 ++++++++++++++++---------------- 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/field/gen_fieldops.jinja b/src/field/gen_fieldops.jinja index 2fadf6c704..25e1af328b 100644 --- a/src/field/gen_fieldops.jinja +++ b/src/field/gen_fieldops.jinja @@ -1,5 +1,5 @@ // Provide the C++ wrapper for {{operator_name}} of {{lhs}} and {{rhs}} -{{out}} operator{{operator}}({{lhs.passByReference}}, {{rhs.passByReference}}) { +{{out}} operator{{operator}}(const {{lhs.passByReference}}, const {{rhs.passByReference}}) { {% if lhs != "BoutReal" and rhs != "BoutReal" %} ASSERT1(areFieldsCompatible(lhs, rhs)); {% endif %} @@ -51,7 +51,7 @@ {% if out.field_type == lhs.field_type %} // Provide the C++ operator to update {{lhs}} by {{operator_name}} with {{rhs}} -{{lhs}} &{{lhs}}::operator{{operator}}=({{rhs.passByReference}}) { +{{lhs}} &{{lhs}}::operator{{operator}}=(const {{rhs.passByReference}}) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { diff --git a/src/field/gen_fieldops.py b/src/field/gen_fieldops.py index 2d096ecfa4..3a5bd97a93 100755 --- a/src/field/gen_fieldops.py +++ b/src/field/gen_fieldops.py @@ -106,8 +106,7 @@ def passByReference(self): in which case just returns "Type name" """ - return "{maybe_const}{self.field_type}{ref} {self.name}".format( - maybe_const="const " if self.field_type != "BoutReal" else "", + return "{self.field_type}{ref} {self.name}".format( self=self, ref="&" if self.field_type != "BoutReal" else "") @property diff --git a/src/field/generated_fieldops.cxx b/src/field/generated_fieldops.cxx index 5843d0c96a..de7f39f0a0 100644 --- a/src/field/generated_fieldops.cxx +++ b/src/field/generated_fieldops.cxx @@ -417,7 +417,7 @@ FieldPerp operator-(const Field3D& lhs, const FieldPerp& rhs) { } // Provide the C++ wrapper for multiplication of Field3D and BoutReal -Field3D operator*(const Field3D& lhs, BoutReal rhs) { +Field3D operator*(const Field3D& lhs, const BoutReal rhs) { Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -430,7 +430,7 @@ Field3D operator*(const Field3D& lhs, BoutReal rhs) { } // Provide the C++ operator to update Field3D by multiplication with BoutReal -Field3D& Field3D::operator*=(BoutReal rhs) { +Field3D& Field3D::operator*=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -449,7 +449,7 @@ Field3D& Field3D::operator*=(BoutReal rhs) { } // Provide the C++ wrapper for division of Field3D and BoutReal -Field3D operator/(const Field3D& lhs, BoutReal rhs) { +Field3D operator/(const Field3D& lhs, const BoutReal rhs) { Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -462,7 +462,7 @@ Field3D operator/(const Field3D& lhs, BoutReal rhs) { } // Provide the C++ operator to update Field3D by division with BoutReal -Field3D& Field3D::operator/=(BoutReal rhs) { +Field3D& Field3D::operator/=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -481,7 +481,7 @@ Field3D& Field3D::operator/=(BoutReal rhs) { } // Provide the C++ wrapper for addition of Field3D and BoutReal -Field3D operator+(const Field3D& lhs, BoutReal rhs) { +Field3D operator+(const Field3D& lhs, const BoutReal rhs) { Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -494,7 +494,7 @@ Field3D operator+(const Field3D& lhs, BoutReal rhs) { } // Provide the C++ operator to update Field3D by addition with BoutReal -Field3D& Field3D::operator+=(BoutReal rhs) { +Field3D& Field3D::operator+=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -513,7 +513,7 @@ Field3D& Field3D::operator+=(BoutReal rhs) { } // Provide the C++ wrapper for subtraction of Field3D and BoutReal -Field3D operator-(const Field3D& lhs, BoutReal rhs) { +Field3D operator-(const Field3D& lhs, const BoutReal rhs) { Field3D result{emptyFrom(lhs)}; checkData(lhs); @@ -526,7 +526,7 @@ Field3D operator-(const Field3D& lhs, BoutReal rhs) { } // Provide the C++ operator to update Field3D by subtraction with BoutReal -Field3D& Field3D::operator-=(BoutReal rhs) { +Field3D& Field3D::operator-=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -853,7 +853,7 @@ FieldPerp operator-(const Field2D& lhs, const FieldPerp& rhs) { } // Provide the C++ wrapper for multiplication of Field2D and BoutReal -Field2D operator*(const Field2D& lhs, BoutReal rhs) { +Field2D operator*(const Field2D& lhs, const BoutReal rhs) { Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -866,7 +866,7 @@ Field2D operator*(const Field2D& lhs, BoutReal rhs) { } // Provide the C++ operator to update Field2D by multiplication with BoutReal -Field2D& Field2D::operator*=(BoutReal rhs) { +Field2D& Field2D::operator*=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -885,7 +885,7 @@ Field2D& Field2D::operator*=(BoutReal rhs) { } // Provide the C++ wrapper for division of Field2D and BoutReal -Field2D operator/(const Field2D& lhs, BoutReal rhs) { +Field2D operator/(const Field2D& lhs, const BoutReal rhs) { Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -898,7 +898,7 @@ Field2D operator/(const Field2D& lhs, BoutReal rhs) { } // Provide the C++ operator to update Field2D by division with BoutReal -Field2D& Field2D::operator/=(BoutReal rhs) { +Field2D& Field2D::operator/=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -917,7 +917,7 @@ Field2D& Field2D::operator/=(BoutReal rhs) { } // Provide the C++ wrapper for addition of Field2D and BoutReal -Field2D operator+(const Field2D& lhs, BoutReal rhs) { +Field2D operator+(const Field2D& lhs, const BoutReal rhs) { Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -930,7 +930,7 @@ Field2D operator+(const Field2D& lhs, BoutReal rhs) { } // Provide the C++ operator to update Field2D by addition with BoutReal -Field2D& Field2D::operator+=(BoutReal rhs) { +Field2D& Field2D::operator+=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -949,7 +949,7 @@ Field2D& Field2D::operator+=(BoutReal rhs) { } // Provide the C++ wrapper for subtraction of Field2D and BoutReal -Field2D operator-(const Field2D& lhs, BoutReal rhs) { +Field2D operator-(const Field2D& lhs, const BoutReal rhs) { Field2D result{emptyFrom(lhs)}; checkData(lhs); @@ -962,7 +962,7 @@ Field2D operator-(const Field2D& lhs, BoutReal rhs) { } // Provide the C++ operator to update Field2D by subtraction with BoutReal -Field2D& Field2D::operator-=(BoutReal rhs) { +Field2D& Field2D::operator-=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1493,7 +1493,7 @@ FieldPerp& FieldPerp::operator-=(const FieldPerp& rhs) { } // Provide the C++ wrapper for multiplication of FieldPerp and BoutReal -FieldPerp operator*(const FieldPerp& lhs, BoutReal rhs) { +FieldPerp operator*(const FieldPerp& lhs, const BoutReal rhs) { FieldPerp result{emptyFrom(lhs)}; checkData(lhs); @@ -1506,7 +1506,7 @@ FieldPerp operator*(const FieldPerp& lhs, BoutReal rhs) { } // Provide the C++ operator to update FieldPerp by multiplication with BoutReal -FieldPerp& FieldPerp::operator*=(BoutReal rhs) { +FieldPerp& FieldPerp::operator*=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1525,7 +1525,7 @@ FieldPerp& FieldPerp::operator*=(BoutReal rhs) { } // Provide the C++ wrapper for division of FieldPerp and BoutReal -FieldPerp operator/(const FieldPerp& lhs, BoutReal rhs) { +FieldPerp operator/(const FieldPerp& lhs, const BoutReal rhs) { FieldPerp result{emptyFrom(lhs)}; checkData(lhs); @@ -1538,7 +1538,7 @@ FieldPerp operator/(const FieldPerp& lhs, BoutReal rhs) { } // Provide the C++ operator to update FieldPerp by division with BoutReal -FieldPerp& FieldPerp::operator/=(BoutReal rhs) { +FieldPerp& FieldPerp::operator/=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1557,7 +1557,7 @@ FieldPerp& FieldPerp::operator/=(BoutReal rhs) { } // Provide the C++ wrapper for addition of FieldPerp and BoutReal -FieldPerp operator+(const FieldPerp& lhs, BoutReal rhs) { +FieldPerp operator+(const FieldPerp& lhs, const BoutReal rhs) { FieldPerp result{emptyFrom(lhs)}; checkData(lhs); @@ -1570,7 +1570,7 @@ FieldPerp operator+(const FieldPerp& lhs, BoutReal rhs) { } // Provide the C++ operator to update FieldPerp by addition with BoutReal -FieldPerp& FieldPerp::operator+=(BoutReal rhs) { +FieldPerp& FieldPerp::operator+=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1589,7 +1589,7 @@ FieldPerp& FieldPerp::operator+=(BoutReal rhs) { } // Provide the C++ wrapper for subtraction of FieldPerp and BoutReal -FieldPerp operator-(const FieldPerp& lhs, BoutReal rhs) { +FieldPerp operator-(const FieldPerp& lhs, const BoutReal rhs) { FieldPerp result{emptyFrom(lhs)}; checkData(lhs); @@ -1602,7 +1602,7 @@ FieldPerp operator-(const FieldPerp& lhs, BoutReal rhs) { } // Provide the C++ operator to update FieldPerp by subtraction with BoutReal -FieldPerp& FieldPerp::operator-=(BoutReal rhs) { +FieldPerp& FieldPerp::operator-=(const BoutReal rhs) { // only if data is unique we update the field // otherwise just call the non-inplace version if (data.unique()) { @@ -1621,7 +1621,7 @@ FieldPerp& FieldPerp::operator-=(BoutReal rhs) { } // Provide the C++ wrapper for multiplication of BoutReal and Field3D -Field3D operator*(BoutReal lhs, const Field3D& rhs) { +Field3D operator*(const BoutReal lhs, const Field3D& rhs) { Field3D result{emptyFrom(rhs)}; checkData(lhs); @@ -1634,7 +1634,7 @@ Field3D operator*(BoutReal lhs, const Field3D& rhs) { } // Provide the C++ wrapper for division of BoutReal and Field3D -Field3D operator/(BoutReal lhs, const Field3D& rhs) { +Field3D operator/(const BoutReal lhs, const Field3D& rhs) { Field3D result{emptyFrom(rhs)}; checkData(lhs); @@ -1647,7 +1647,7 @@ Field3D operator/(BoutReal lhs, const Field3D& rhs) { } // Provide the C++ wrapper for addition of BoutReal and Field3D -Field3D operator+(BoutReal lhs, const Field3D& rhs) { +Field3D operator+(const BoutReal lhs, const Field3D& rhs) { Field3D result{emptyFrom(rhs)}; checkData(lhs); @@ -1660,7 +1660,7 @@ Field3D operator+(BoutReal lhs, const Field3D& rhs) { } // Provide the C++ wrapper for subtraction of BoutReal and Field3D -Field3D operator-(BoutReal lhs, const Field3D& rhs) { +Field3D operator-(const BoutReal lhs, const Field3D& rhs) { Field3D result{emptyFrom(rhs)}; checkData(lhs); @@ -1673,7 +1673,7 @@ Field3D operator-(BoutReal lhs, const Field3D& rhs) { } // Provide the C++ wrapper for multiplication of BoutReal and Field2D -Field2D operator*(BoutReal lhs, const Field2D& rhs) { +Field2D operator*(const BoutReal lhs, const Field2D& rhs) { Field2D result{emptyFrom(rhs)}; checkData(lhs); @@ -1686,7 +1686,7 @@ Field2D operator*(BoutReal lhs, const Field2D& rhs) { } // Provide the C++ wrapper for division of BoutReal and Field2D -Field2D operator/(BoutReal lhs, const Field2D& rhs) { +Field2D operator/(const BoutReal lhs, const Field2D& rhs) { Field2D result{emptyFrom(rhs)}; checkData(lhs); @@ -1699,7 +1699,7 @@ Field2D operator/(BoutReal lhs, const Field2D& rhs) { } // Provide the C++ wrapper for addition of BoutReal and Field2D -Field2D operator+(BoutReal lhs, const Field2D& rhs) { +Field2D operator+(const BoutReal lhs, const Field2D& rhs) { Field2D result{emptyFrom(rhs)}; checkData(lhs); @@ -1712,7 +1712,7 @@ Field2D operator+(BoutReal lhs, const Field2D& rhs) { } // Provide the C++ wrapper for subtraction of BoutReal and Field2D -Field2D operator-(BoutReal lhs, const Field2D& rhs) { +Field2D operator-(const BoutReal lhs, const Field2D& rhs) { Field2D result{emptyFrom(rhs)}; checkData(lhs); @@ -1725,7 +1725,7 @@ Field2D operator-(BoutReal lhs, const Field2D& rhs) { } // Provide the C++ wrapper for multiplication of BoutReal and FieldPerp -FieldPerp operator*(BoutReal lhs, const FieldPerp& rhs) { +FieldPerp operator*(const BoutReal lhs, const FieldPerp& rhs) { FieldPerp result{emptyFrom(rhs)}; checkData(lhs); @@ -1738,7 +1738,7 @@ FieldPerp operator*(BoutReal lhs, const FieldPerp& rhs) { } // Provide the C++ wrapper for division of BoutReal and FieldPerp -FieldPerp operator/(BoutReal lhs, const FieldPerp& rhs) { +FieldPerp operator/(const BoutReal lhs, const FieldPerp& rhs) { FieldPerp result{emptyFrom(rhs)}; checkData(lhs); @@ -1751,7 +1751,7 @@ FieldPerp operator/(BoutReal lhs, const FieldPerp& rhs) { } // Provide the C++ wrapper for addition of BoutReal and FieldPerp -FieldPerp operator+(BoutReal lhs, const FieldPerp& rhs) { +FieldPerp operator+(const BoutReal lhs, const FieldPerp& rhs) { FieldPerp result{emptyFrom(rhs)}; checkData(lhs); @@ -1764,7 +1764,7 @@ FieldPerp operator+(BoutReal lhs, const FieldPerp& rhs) { } // Provide the C++ wrapper for subtraction of BoutReal and FieldPerp -FieldPerp operator-(BoutReal lhs, const FieldPerp& rhs) { +FieldPerp operator-(const BoutReal lhs, const FieldPerp& rhs) { FieldPerp result{emptyFrom(rhs)}; checkData(lhs); From 1decd1535c8eff9979e5cc786ffeacd84b5cd21b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 29 Mar 2019 10:05:00 +0000 Subject: [PATCH 1180/1783] Move conditional out of writeSettings to calling site --- include/bout.hxx | 5 ++--- src/bout++.cxx | 13 +++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/bout.hxx b/include/bout.hxx index 961e6e8558..eec5d68aaf 100644 --- a/include/bout.hxx +++ b/include/bout.hxx @@ -162,10 +162,9 @@ void setRunStartInfo(Options& options); /// options void setRunFinishInfo(Options& options); -/// Write \p options to \p settings_file in directory \p -/// data_dir. Actually writes only if \p write is true +/// Write \p options to \p settings_file in directory \p data_dir void writeSettingsFile(Options& options, const std::string& data_dir, - const std::string& settings_file, bool write = true); + const std::string& settings_file); /// Setup the output dump files from \p options using the \p /// mesh. Files are created in the \p data_dir directory diff --git a/src/bout++.cxx b/src/bout++.cxx index c6c18f461b..a87103422f 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -150,7 +150,9 @@ int BoutInitialise(int& argc, char**& argv) { setRunStartInfo(Options::root()); - writeSettingsFile(Options::root(), args.data_dir, args.set_file, MYPE == 0); + if (MYPE == 0) { + writeSettingsFile(Options::root(), args.data_dir, args.set_file); + } // Create the mesh bout::globals::mesh = Mesh::create(); @@ -543,10 +545,7 @@ Datafile setupDumpFile(Options& options, Mesh& mesh, const std::string& data_dir } void writeSettingsFile(Options& options, const std::string& data_dir, - const std::string& settings_file, bool write) { - if (not write) { - return; - } + const std::string& settings_file) { OptionsReader::getInstance()->write(&options, "%s/%s", data_dir.c_str(), settings_file.c_str()); } @@ -581,7 +580,9 @@ int BoutFinalise(bool write_settings) { const auto data_dir = options["datadir"].withDefault(std::string{DEFAULT_DIR}); const auto set_file = options["settingsfile"].withDefault(""); - writeSettingsFile(options, data_dir, set_file, BoutComm::rank() == 0); + if (BoutComm::rank() == 0) { + writeSettingsFile(options, data_dir, set_file); + } } catch (const BoutException& e) { output_error << _("Error whilst writing settings") << e.what() << endl; } From a52754dbaddea82eb1f5cba7964e17ad738fb3a6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 1 Apr 2019 00:10:18 +0200 Subject: [PATCH 1181/1783] Make tolerances tighter in TestTimer unit test Previously the tolerance was 1ms but the interval used for testing was 0.5ms, so tests could pass incorrectly. --- tests/unit/sys/test_timer.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/sys/test_timer.cxx b/tests/unit/sys/test_timer.cxx index 2e5a307f71..b37d90815c 100644 --- a/tests/unit/sys/test_timer.cxx +++ b/tests/unit/sys/test_timer.cxx @@ -8,8 +8,8 @@ namespace bout { namespace testing { using ms = std::chrono::duration; -constexpr double TimerTolerance{1e-3}; -constexpr auto sleep_length = ms(0.5); +constexpr double TimerTolerance{0.5e-3}; +constexpr auto sleep_length = ms(1.); } // namespace testing } // namespace bout From 4341315155720569c8f2de11943480b419366b81 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 31 Mar 2019 23:38:07 +0200 Subject: [PATCH 1182/1783] Counters for timers, makes them correct with multiple Timer objects Previously, if multiple Timer objects were created with the same label, the timings would not be correct. The timer should run as long as any of the objects are in scope. This commit makes this happen by adding a counter to the timer_info struct, and only stopping the timer when the counter is 0. --- include/bout/sys/timer.hxx | 2 ++ src/sys/timer.cxx | 23 ++++++++++++++++------- tests/unit/sys/test_timer.cxx | 20 ++++++++++++++++++++ 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/include/bout/sys/timer.hxx b/include/bout/sys/timer.hxx index 04838dbda3..855363248a 100644 --- a/include/bout/sys/timer.hxx +++ b/include/bout/sys/timer.hxx @@ -86,6 +86,8 @@ private: seconds time; ///< Total time bool running; ///< Is the timer currently running? clock_type::time_point started; ///< Start time + uint counter{0}; ///< Number of Timer objects associated with this + /// timer_info }; /// Store of existing timing info objects diff --git a/src/sys/timer.cxx b/src/sys/timer.cxx index bc16140a3f..5d1615c0e9 100644 --- a/src/sys/timer.cxx +++ b/src/sys/timer.cxx @@ -1,19 +1,28 @@ #include "bout/sys/timer.hxx" Timer::Timer() : timing(getInfo("")) { - timing.started = clock_type::now(); - timing.running = true; + if (timing.counter == 0) { + timing.started = clock_type::now(); + timing.running = true; + } + timing.counter += 1; } Timer::Timer(const std::string& label) : timing(getInfo(label)) { - timing.started = clock_type::now(); - timing.running = true; + if (timing.counter == 0) { + timing.started = clock_type::now(); + timing.running = true; + } + timing.counter += 1; } Timer::~Timer() { - auto finished = clock_type::now(); - timing.running = false; - timing.time += finished - timing.started; + timing.counter -= 1; + if (timing.counter == 0) { + auto finished = clock_type::now(); + timing.running = false; + timing.time += finished - timing.started; + } } void Timer::cleanup() { info.clear(); } diff --git a/tests/unit/sys/test_timer.cxx b/tests/unit/sys/test_timer.cxx index b37d90815c..9d118c8d35 100644 --- a/tests/unit/sys/test_timer.cxx +++ b/tests/unit/sys/test_timer.cxx @@ -60,6 +60,26 @@ TEST(TimerTest, GetTimeLabelOutOfScope) { bout::testing::TimerTolerance); } +TEST(TimerTest, GetTimeLabelSubScope) { + auto start = Timer::clock_type::now(); + + Timer timer{"GetTimeLabelSubScope test"}; + + { + Timer timer{"GetTimeLabelSubScope test"}; + + std::this_thread::sleep_for(bout::testing::sleep_length); + } + + std::this_thread::sleep_for(bout::testing::sleep_length); + + auto end = Timer::clock_type::now(); + Timer::seconds elapsed = end - start; + + EXPECT_NEAR(Timer::getTime("GetTimeLabelSubScope test"), elapsed.count(), + bout::testing::TimerTolerance); +} + TEST(TimerTest, GetTimeLabelRepeat) { auto start = Timer::clock_type::now(); From 72c61a400b3c1b099c9463c471fcea4149952038 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 31 Mar 2019 23:42:47 +0100 Subject: [PATCH 1183/1783] Update LaplaceNaulin comments with extra DC terms Documentation in the comments at the top of naulin_laplace.cxx to reflect recent addition of DC parts of C1*D and C2 to direct solver. --- .../laplace/impls/naulin/naulin_laplace.cxx | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index b2bc1491f6..159d456cf0 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -4,11 +4,14 @@ * \brief Iterative solver to handle non-constant-in-z coefficients * * Scheme suggested by Volker Naulin: solve - * Delp2(phi[i+1]) + DC(A/D)*phi[i+1] = rhs(phi[i]) + DC(A/D)*phi[i] + * Delp2(phi[i+1]) + 1/DC(C1*D)*Grad_perp(DC(C2))*Grad_perp(phi[i+1]) + DC(A/D)*phi[i+1] + * = rhs(phi[i]) + 1/DC(C1*D)*Grad_perp(DC(C2))*Grad_perp(phi[i]) + DC(A/D)*phi[i] * using standard FFT-based solver, iterating to include other terms by * evaluating them on rhs using phi from previous iteration. - * DC part (i.e. Field2D part) of A/D is kept in the FFT inversion so that all - * Neumann boundary conditions can be used at least when DC(A/D)!=0. + * DC part (i.e. Field2D part) of C1*D, C2 and A/D is kept in the FFT inversion + * to improve convergence by including as much as possible in the direct solve + * and so that all Neumann boundary conditions can be used at least when + * DC(A/D)!=0. * * CHANGELOG * ========= @@ -65,7 +68,9 @@ * 1. Get the vorticity from * \code{.cpp} * vort = (vortD/n) - grad_perp(ln_n)*grad_perp(phiCur) - * [Delp2(phiNext) + DC(A/D)*phiNext = b(phiCur) = (rhs/D) - 1/C1*grad_perp(C2)*grad_perp(phiCur) - (A/D - DC(A/D))*phiCur] + * [Delp2(phiNext) + 1/DC(C2*D)*grad_perp(DC(C2))*grad_perp(phiNext) + DC(A/D)*phiNext + * = b(phiCur) + * = (rhs/D) - (1/C1/D*grad_perp(C2)*grad_perp(phiCur) - 1/DC(C2*D)*grad_perp(DC(C2))*grad_perp(phiNext)) - (A/D - DC(A/D))*phiCur] * \endcode * where phiCur is phi of the current iteration * [and DC(f) is the constant-in-z component of f] @@ -73,14 +78,17 @@ * \code{.cpp} * phiNext = invert_laplace_perp(vort) * [set Acoef of laplace_perp solver to DC(A/D) - * phiNext = invert_laplace_perp(b)] + * and C1coef of laplace_perp solver to DC(C1*D) + * and C2coef of laplace_perp solver to DC(C2) + * then phiNext = invert_laplace_perp(b)] * \endcode * where phiNext is the newly obtained \f$phi\f$ * 3. Calculate the error at phi=phiNext * \code{.cpp} * error3D = Delp2(phiNext) + 1/C1*grad_perp(C2)*grad_perp(phiNext) + A/D*phiNext - rhs/D * = b(phiCur) - b(phiNext) - * as b(phiCur) = Delp2(phiNext) + DC(A/D)*phiNext up to rounding errors + * as b(phiCur) = Delp2(phiNext) + 1/DC(C2*D)*grad_perp(DC(C2))*grad_perp(phiNext) + DC(A/D)*phiNext + * up to rounding errors * \endcode * 4. Calculate the infinity norms of the error * \code{.cpp} From c5a848bd1beb280fd3efb1e280c3bb1a63c59538 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 31 Mar 2019 16:45:31 +0100 Subject: [PATCH 1184/1783] Add LaplaceNaulin statistics to dump for multiple LaplaceNaulin solvers Previously only the first LaplaceNaulin object would add its mean iteration count to bout::globals::dump. This commit changes the 'static bool' switch to a 'static int' counter and names the variables "naulinsolver"+str(i)+"_mean_its" for the i'th LaplaceNaulin object. --- src/invert/laplace/impls/naulin/naulin_laplace.cxx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index 159d456cf0..0d08b9817e 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -154,11 +154,10 @@ LaplaceNaulin::LaplaceNaulin(Options *opt, const CELL_LOC loc, Mesh *mesh_in) delp2solver->setInnerBoundaryFlags(inner_boundary_flags); delp2solver->setOuterBoundaryFlags(outer_boundary_flags); - static bool first = true; - if (first) { - SAVE_REPEAT(naulinsolver_mean_its); - first = false; - } + static int naulinsolver_count = 1; + bout::globals::dump.addRepeat(naulinsolver_mean_its, + "naulinsolver"+std::to_string(naulinsolver_count)+"_mean_its"); + naulinsolver_count++; } LaplaceNaulin::~LaplaceNaulin() { From ad2a55af7215dc218fc97787481ff4b7b2503da5 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 31 Mar 2019 14:35:38 +0100 Subject: [PATCH 1185/1783] Under-relaxation for LaplaceNaulin Under-relaxation can make convergence of the iteration in LaplaceNaulin more robust. This commit introduces under-relaxation: - if the error increases on an iteration, reduce underrelax_factor by a factor of 0.9 and restart the iteration. - initial value of underrelax_factor can be set with an option (defaults to 1., corresponding to no under-relaxation). The mean number of resets with the underrelaxation factor reduced is saved to the dump file so that the user can monitor whether the initial under-relaxation factor should be reduced. --- .../laplace/impls/naulin/naulin_laplace.cxx | 70 ++++++++++++++++--- .../laplace/impls/naulin/naulin_laplace.hxx | 19 +++++ 2 files changed, 78 insertions(+), 11 deletions(-) diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index 0d08b9817e..d4e382d79c 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -64,6 +64,13 @@ * &=& rhs/D - \frac{1}{D\,C1} \nabla_\perp C2\cdot\nabla_\perp \phi - (\frac{A}{D} - <\frac{A}{D}>)*\phi * \f} * + * The iteration can be under-relaxed to help it converge. Amount of under-relaxation is + * set by the parameter 'underrelax_factor'. 0 rtol * \endcode * * If yes - * * Set - * \code{.cpp} - * phiCur = phiNext - * \endcode - * increase curCount and start from step 1 - * * If number of iteration is above maxit, throw exception + * * Check whether + * \code{.cpp} + * EAbsLInf > EAbsLInf(previous step) + * \endcode + * * If yes + * \code{.cpp} + * underrelax_factor *= 0.9 + * \endcode + * Restart iteration + * * If no + * * Set + * \code{.cpp} + * phiCur = phiNext + * \endcode + * increase curCount and start from step 1 + * * If number of iteration is above maxit, throw exception * * If no * * Stop: Function returns phiNext * * if no @@ -143,6 +162,8 @@ LaplaceNaulin::LaplaceNaulin(Options *opt, const CELL_LOC loc, Mesh *mesh_in) OPTION(opt, rtol, 1.e-7); OPTION(opt, atol, 1.e-20); OPTION(opt, maxits, 100); + OPTION(opt, initial_underrelax_factor, 1.); + ASSERT0(initial_underrelax_factor > 0. and initial_underrelax_factor <= 1.); delp2solver = create(opt->getSection("delp2solver"), location, localmesh); std::string delp2type; opt->getSection("delp2solver")->get("type", delp2type, "cyclic"); @@ -157,6 +178,8 @@ LaplaceNaulin::LaplaceNaulin(Options *opt, const CELL_LOC loc, Mesh *mesh_in) static int naulinsolver_count = 1; bout::globals::dump.addRepeat(naulinsolver_mean_its, "naulinsolver"+std::to_string(naulinsolver_count)+"_mean_its"); + bout::globals::dump.addRepeat(naulinsolver_mean_underrelax_counts, + "naulinsolver"+std::to_string(naulinsolver_count)+"_mean_underrelax_counts"); naulinsolver_count++; } @@ -218,8 +241,10 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { // Use this below to normalize error for relative error estimate BoutReal RMS_rhsOverD = sqrt(mean(SQ(rhsOverD), true, RGN_NOBNDRY)); // use sqrt(mean(SQ)) to make sure we do not divide by zero at a point - BoutReal error_rel = 1e20, error_abs=1e20; + BoutReal error_rel = 1e20, error_abs=1e20, last_error=error_abs; int count = 0; + int underrelax_count = 0; + BoutReal underrelax_factor = initial_underrelax_factor; // Initial values for derivatives of x Field3D ddx_x = DDX(x, location, DIFF_C2); @@ -241,13 +266,33 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { // Use here to calculate an error, can also use for the next iteration ddx_x = DDX(x, location, DIFF_C2); // can be used also for the next iteration ddz_x = DDZ(x, location, DIFF_FFT); - Field3D bnew = rhsOverD - (coords->g11*coef_x_AC*ddx_x + coords->g33*coef_z*ddz_x + coords->g13*(coef_x_AC*ddz_x + coef_z*ddx_x)) - AOverD_AC*x; + + Field3D bnew = rhsOverD + - (coords->g11*coef_x_AC*ddx_x + coords->g33*coef_z*ddz_x + + coords->g13*(coef_x_AC*ddz_x + coef_z*ddx_x)) + - AOverD_AC*x; Field3D error3D = b - bnew; error_abs = max(abs(error3D, RGN_NOBNDRY), true, RGN_NOBNDRY); error_rel = error_abs / RMS_rhsOverD; - b = bnew; + b = underrelax_factor*bnew + (1. - underrelax_factor)*b; + + if (error_abs > last_error) { + // Iteration seems to be diverging... try underrelaxing and restart + underrelax_factor *= .9; + underrelax_count++; + + // Set x back to initial guess to restart iteration + x = x0; + ddx_x = DDX(x, location, DIFF_C2); + ddz_x = DDZ(x, location, DIFF_FFT); + b = rhsOverD - (coords->g11*coef_x_AC*ddx_x + coords->g33*coef_z*ddz_x + coords->g13*(coef_x_AC*ddz_x + coef_z*ddx_x)) - AOverD_AC*x; + + last_error = 1.e20; + } else { + last_error = error_abs; + } count++; if (count>maxits) @@ -255,7 +300,10 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { } ncalls++; - naulinsolver_mean_its = (naulinsolver_mean_its*BoutReal(ncalls-1) + BoutReal(count))/BoutReal(ncalls); + naulinsolver_mean_its = (naulinsolver_mean_its * BoutReal(ncalls-1) + + BoutReal(count))/BoutReal(ncalls); + naulinsolver_mean_underrelax_counts = (naulinsolver_mean_underrelax_counts * BoutReal(ncalls - 1) + + BoutReal(underrelax_count)) / BoutReal(ncalls); return x; } diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.hxx b/src/invert/laplace/impls/naulin/naulin_laplace.hxx index 673f7bd858..5b2a73a854 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.hxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.hxx @@ -123,12 +123,31 @@ private: LaplaceNaulin(const LaplaceNaulin&); LaplaceNaulin& operator=(const LaplaceNaulin&); Field3D Acoef, C1coef, C2coef, Dcoef; + + /// Laplacian solver used to solve the equation with constant-in-z coefficients Laplacian* delp2solver; + + /// Solver tolerances BoutReal rtol, atol; + + /// Maximum number of iterations int maxits; + + /// Initial choice for under-relaxation factor, should be greater than 0 and + /// less than or equal to 1. Value of 1 means no underrelaxation + BoutReal initial_underrelax_factor{1.}; + + /// Mean number of iterations taken by the solver BoutReal naulinsolver_mean_its; + + /// Mean number of times the underrelaxation factor is reduced + BoutReal naulinsolver_mean_underrelax_counts{0.}; + + /// Counter for the number of times the solver has been called int ncalls; + /// Copy the boundary guard cells from the input 'initial guess' x0 into x. + /// These may be used to set non-zero-value boundary conditions void copy_x_boundaries(Field3D &x, const Field3D &x0, Mesh *mesh); }; From 30a61f43b142f0e6a8d8fa33f0b0695f62d62017 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 1 Apr 2019 00:23:19 +0100 Subject: [PATCH 1186/1783] Documentation for new LaplaceNaulin under-relaxation option --- manual/sphinx/user_docs/laplacian.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/manual/sphinx/user_docs/laplacian.rst b/manual/sphinx/user_docs/laplacian.rst index 9f6e9e3e7a..e600923ca8 100644 --- a/manual/sphinx/user_docs/laplacian.rst +++ b/manual/sphinx/user_docs/laplacian.rst @@ -783,6 +783,23 @@ This scheme was introduced for BOUT++ by Michael Løiten in the `CELMA code `_ and the iterative algoritm is detailed in his thesis [Løiten2017]_. +The iteration can be under-relaxed (see naulin_laplace.cxx for more details of the +implementation). A factor 0`` being the number of the +LaplaceNaulin solver, counting in the order they are created in the physics model: +- ``naulinsolver_mean_underrelax_counts`` gives the mean number of times + ``underrelax_factor`` had to be reduced to get the iteration to converge. If this is + much above 0, it is probably worth reducing ``initial_underrelax_factor``. +- ``naulinsolver_mean_its`` is the mean number of iterations taken to converge. Try to + minimise when adjusting ``initial_underrelax_factor``. + .. [Løiten2017] Michael Løiten, "Global numerical modeling of magnetized plasma in a linear device", 2017, https://celma-project.github.io/. From 87af2398663e9412ca2136adb7d0e53c5f90a987 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 1 Apr 2019 09:48:15 +0100 Subject: [PATCH 1187/1783] Use 'unsigned int' instead of 'uint' 'uint' is not standard. --- include/bout/sys/timer.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/sys/timer.hxx b/include/bout/sys/timer.hxx index 855363248a..08da8df61e 100644 --- a/include/bout/sys/timer.hxx +++ b/include/bout/sys/timer.hxx @@ -86,7 +86,7 @@ private: seconds time; ///< Total time bool running; ///< Is the timer currently running? clock_type::time_point started; ///< Start time - uint counter{0}; ///< Number of Timer objects associated with this + unsigned int counter{0}; ///< Number of Timer objects associated with this /// timer_info }; From 3108d022e98beee3c956cf37574ed3b50cdc2627 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 1 Apr 2019 13:13:50 +0100 Subject: [PATCH 1188/1783] Fix initialization of timer_info.counter Giving a member of a struct a default initialisation makes the struct no longer an "aggregate", which means it no longer has the "sensible" constructor that we're using in Timer::getInfo. In C++14, this would work as expected. --- include/bout/sys/timer.hxx | 2 +- src/sys/timer.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bout/sys/timer.hxx b/include/bout/sys/timer.hxx index 08da8df61e..dc527939c4 100644 --- a/include/bout/sys/timer.hxx +++ b/include/bout/sys/timer.hxx @@ -86,7 +86,7 @@ private: seconds time; ///< Total time bool running; ///< Is the timer currently running? clock_type::time_point started; ///< Start time - unsigned int counter{0}; ///< Number of Timer objects associated with this + unsigned int counter; ///< Number of Timer objects associated with this /// timer_info }; diff --git a/src/sys/timer.cxx b/src/sys/timer.cxx index 5d1615c0e9..a98f45c7ad 100644 --- a/src/sys/timer.cxx +++ b/src/sys/timer.cxx @@ -33,7 +33,7 @@ Timer::timer_info& Timer::getInfo(const std::string& label) { auto it = info.find(label); if (it == info.end()) { auto timer = info.emplace( - label, timer_info{seconds{0}, false, clock_type::now()}); + label, timer_info{seconds{0}, false, clock_type::now(), 0}); return timer.first->second; } return it->second; From 287a215d2cd482cdbf8d6e5c736e93f680121986 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Mar 2019 17:31:49 +0000 Subject: [PATCH 1189/1783] Add SolverFactory unit tests, with some minor tidying --- include/bout/solverfactory.hxx | 28 +++--- src/solver/solverfactory.cxx | 32 +++---- tests/unit/solver/test_solverfactory.cxx | 115 +++++++++++++++++++++++ 3 files changed, 140 insertions(+), 35 deletions(-) create mode 100644 tests/unit/solver/test_solverfactory.cxx diff --git a/include/bout/solverfactory.hxx b/include/bout/solverfactory.hxx index 9b0041bbbd..58a763fd68 100644 --- a/include/bout/solverfactory.hxx +++ b/include/bout/solverfactory.hxx @@ -8,8 +8,8 @@ class SolverFactory; #include "bout/solver.hxx" #include -#include #include +#include class Options; @@ -21,34 +21,35 @@ class Options; /// using SolverFactory = Factory>; class SolverFactory : public Factory> { - public: - SolverType getDefaultSolverType(); - - static SolverFactory *getInstance(); +public: + static SolverType getDefaultSolverType(); - Solver* createSolver(Options *options = nullptr); - Solver* createSolver(SolverType &name) { + static SolverFactory* getInstance(); + + Solver* createSolver(Options* options = nullptr); + Solver* createSolver(const SolverType& name) { return createSolver(name, Options::getRoot()->getSection("solver")); } - Solver* createSolver(SolverType &name, Options *options) { + Solver* createSolver(const SolverType& name, Options* options) { try { return create(name, options); - } catch (const BoutException &e) { + } catch (const BoutException& e) { throw BoutException("Error when trying to create a Solver: %s", e.what()); } } + private: SolverFactory() {} static SolverFactory* instance; }; /// Specialisation of Factory registration helper class -template +template class RegisterInFactory { public: - RegisterInFactory(const std::string &name) { + RegisterInFactory(const std::string& name) { SolverFactory::getInstance()->add( - name, [](Options *options) -> Solver * { return new DerivedType(options); }); + name, [](Options* options) -> Solver* { return new DerivedType(options); }); } }; @@ -60,8 +61,7 @@ public: /// namespace { /// RegisterSolver registersolvermine("mysolver"); /// } -template +template using RegisterSolver = RegisterInFactory; #endif // __SOLVER_FACTORY_H__ - diff --git a/src/solver/solverfactory.cxx b/src/solver/solverfactory.cxx index 4f75ab662c..f80b7a1aec 100644 --- a/src/solver/solverfactory.cxx +++ b/src/solver/solverfactory.cxx @@ -17,7 +17,7 @@ SolverFactory* SolverFactory::instance = nullptr; -SolverFactory *SolverFactory::getInstance() { +SolverFactory* SolverFactory::getInstance() { if (instance == nullptr) { // Create the singleton object instance = new SolverFactory(); @@ -26,34 +26,24 @@ SolverFactory *SolverFactory::getInstance() { } inline SolverType SolverFactory::getDefaultSolverType() { - SolverType type; - - #if defined BOUT_HAS_CVODE - type = SOLVERCVODE; - #elif defined BOUT_HAS_IDA - type = SOLVERIDA; - //#elif defined BOUT_HAS_PETSC - //type = SOLVERPETSC; - #else - type = SOLVERPVODE; - #endif + SolverType type = +#if defined BOUT_HAS_CVODE + SOLVERCVODE; +#elif defined BOUT_HAS_IDA + SOLVERIDA; +#else + SOLVERPVODE; +#endif return type; } -Solver *SolverFactory::createSolver(Options *options) { - SolverType type = getDefaultSolverType(); - +Solver* SolverFactory::createSolver(Options* options) { if (options == nullptr) { options = Options::getRoot()->getSection("solver"); } - std::string solver_option; - options->get("type", solver_option, ""); - - if (!solver_option.empty()) { - type = solver_option.c_str(); - } + auto type = (*options)["type"].withDefault(getDefaultSolverType()); return createSolver(type, options); } diff --git a/tests/unit/solver/test_solverfactory.cxx b/tests/unit/solver/test_solverfactory.cxx new file mode 100644 index 0000000000..89da04b6fd --- /dev/null +++ b/tests/unit/solver/test_solverfactory.cxx @@ -0,0 +1,115 @@ +#include "gtest/gtest.h" + +#include "boutexception.hxx" +#include "test_extras.hxx" +#include "bout/solver.hxx" +#include "bout/solverfactory.hxx" + +#include + +namespace { +class FakeSolver : public Solver { +public: + FakeSolver(Options* options) : Solver(options) {} + ~FakeSolver() = default; + int run() { return (*options)["number"].withDefault(42); } +}; + +RegisterSolver register_fake("fake_solver"); +} // namespace + +TEST(SolverFactoryTest, GetInstance) { EXPECT_NE(SolverFactory::getInstance(), nullptr); } + +TEST(SolverFactoryTest, GetDefaultSolverType) { + EXPECT_NE(SolverFactory::getDefaultSolverType(), ""); +} + +TEST(SolverFactoryTest, RegisterSolver) { + auto available = SolverFactory::getInstance()->listAvailable(); + + auto found_fake = std::find(begin(available), end(available), "fake_solver"); + + EXPECT_NE(found_fake, end(available)); +} + +TEST(SolverFactoryTest, Create) { + WithQuietOutput quiet{output_info}; + + Options::root()["solver"]["type"] = "fake_solver"; + auto solver = SolverFactory::getInstance()->createSolver(); + + EXPECT_EQ(solver->run(), 42); + + Options::cleanup(); +} + +TEST(SolverFactoryTest, CreateDefault) { + WithQuietOutput quiet{output_info}; + + EXPECT_NO_THROW(SolverFactory::getInstance()->createSolver()); + + Options::cleanup(); +} + +TEST(SolverFactoryTest, CreateFromOptions) { + WithQuietOutput quiet{output_info}; + + Options options; + options["type"] = "fake_solver"; + auto solver = SolverFactory::getInstance()->createSolver(&options); + + EXPECT_EQ(solver->run(), 42); +} + +TEST(SolverFactoryTest, CreateFromName) { + WithQuietOutput quiet{output_info}; + + constexpr auto number = 13; + Options::root()["solver"]["number"] = number; + auto solver = SolverFactory::getInstance()->createSolver("fake_solver"); + + EXPECT_EQ(solver->run(), number); + + Options::cleanup(); +} + +TEST(SolverFactoryTest, CreateFromNameAndOptions) { + WithQuietOutput quiet{output_info}; + + constexpr auto number = 13; + Options options; + options["number"] = number; + auto solver = SolverFactory::getInstance()->createSolver("fake_solver", &options); + + EXPECT_EQ(solver->run(), number); +} + +TEST(SolverFactoryTest, BadCreate) { + WithQuietOutput quiet{output_info}; + + Options::root()["solver"]["type"] = "bad_solver"; + EXPECT_THROW(SolverFactory::getInstance()->createSolver(), BoutException); + Options::cleanup(); +} + +TEST(SolverFactoryTest, BadCreateFromOptions) { + WithQuietOutput quiet{output_info}; + + Options options; + options["type"] = "bad_solver"; + EXPECT_THROW(SolverFactory::getInstance()->createSolver(&options), BoutException); +} + +TEST(SolverFactoryTest, BadCreateFromName) { + WithQuietOutput quiet{output_info}; + + EXPECT_THROW(SolverFactory::getInstance()->createSolver("bad_solver"), BoutException); + Options::cleanup(); +} + +TEST(SolverFactoryTest, BadCreateFromNameAndOptions) { + WithQuietOutput quiet{output_info}; + + Options options; + EXPECT_THROW(SolverFactory::getInstance()->createSolver("bad_solver", &options), BoutException); +} From 449d529b742510f3ee3f9019161a0d9aeac0d597 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 26 Mar 2019 18:01:36 +0000 Subject: [PATCH 1190/1783] Add some basic unit tests for Solver --- include/bout/solver.hxx | 2 +- src/solver/solver.cxx | 8 +- tests/unit/solver/test_solver.cxx | 191 ++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 tests/unit/solver/test_solver.cxx diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index b7990b1c1d..1f99dfaa00 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -304,7 +304,7 @@ class Solver { /*! * Create a Solver object, specifying the type */ - static Solver *create(SolverType &type, Options *opts = nullptr); + static Solver* create(const SolverType& type, Options* opts = nullptr); /*! * Pass the command-line arguments. This static function is diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 16f959a637..c5c2e2c66e 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -599,8 +599,8 @@ int Solver::init(int UNUSED(nout), BoutReal UNUSED(tstep)) { output_progress.write(_("Initialising solver\n")); - MPI_Comm_size(BoutComm::get(), &NPES); - MPI_Comm_rank(BoutComm::get(), &MYPE); + NPES = BoutComm::size(); + MYPE = BoutComm::rank(); /// Mark as initialised. No more variables can be added initialised = true; @@ -818,11 +818,11 @@ int Solver::getLocalN() { return local_N; } -Solver* Solver::create(Options *opts) { +Solver* Solver::create(Options* opts) { return SolverFactory::getInstance()->createSolver(opts); } -Solver* Solver::create(SolverType &type, Options *opts) { +Solver* Solver::create(const SolverType& type, Options* opts) { return SolverFactory::getInstance()->createSolver(type, opts); } diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx new file mode 100644 index 0000000000..6d4a08b24c --- /dev/null +++ b/tests/unit/solver/test_solver.cxx @@ -0,0 +1,191 @@ +#include "gtest/gtest.h" + +#include "boutexception.hxx" +#include "field2d.hxx" +#include "field3d.hxx" +#include "test_extras.hxx" +#include "bout/solver.hxx" +#include "bout/solverfactory.hxx" + +#include + +namespace { +class FakeSolver : public Solver { +public: + FakeSolver(Options* options) : Solver(options) {} + ~FakeSolver() = default; + int run() { return (*options)["number"].withDefault(42); } +}; + +RegisterSolver register_fake("fake_solver"); +} // namespace + +class SolverTest : public FakeMeshFixture { +public: + SolverTest() : FakeMeshFixture() {} + virtual ~SolverTest() = default; + + WithQuietOutput quiet_info{output_info}; + WithQuietOutput quiet_progress{output_progress}; +}; + +TEST_F(SolverTest, Create) { + WithQuietOutput quiet{output_info}; + + Options::root()["solver"]["type"] = "fake_solver"; + auto solver = Solver::create(); + + EXPECT_EQ(solver->run(), 42); + + Options::cleanup(); +} + +TEST_F(SolverTest, CreateDefault) { + WithQuietOutput quiet{output_info}; + + EXPECT_NO_THROW(Solver::create()); + + Options::cleanup(); +} + +TEST_F(SolverTest, CreateFromOptions) { + WithQuietOutput quiet{output_info}; + + Options options; + options["type"] = "fake_solver"; + auto solver = Solver::create(&options); + + EXPECT_EQ(solver->run(), 42); +} + +TEST_F(SolverTest, CreateFromName) { + WithQuietOutput quiet{output_info}; + + constexpr auto number = 13; + Options::root()["solver"]["number"] = number; + auto solver = Solver::create("fake_solver"); + + EXPECT_EQ(solver->run(), number); + + Options::cleanup(); +} + +TEST_F(SolverTest, CreateFromNameAndOptions) { + WithQuietOutput quiet{output_info}; + + constexpr auto number = 13; + Options options; + options["number"] = number; + auto solver = Solver::create("fake_solver", &options); + + EXPECT_EQ(solver->run(), number); +} + +TEST_F(SolverTest, BadCreate) { + WithQuietOutput quiet{output_info}; + + Options::root()["solver"]["type"] = "bad_solver"; + EXPECT_THROW(Solver::create(), BoutException); + Options::cleanup(); +} + +TEST_F(SolverTest, BadCreateFromOptions) { + WithQuietOutput quiet{output_info}; + + Options options; + options["type"] = "bad_solver"; + EXPECT_THROW(Solver::create(&options), BoutException); +} + +TEST_F(SolverTest, BadCreateFromName) { + WithQuietOutput quiet{output_info}; + + EXPECT_THROW(Solver::create("bad_solver"), BoutException); + Options::cleanup(); +} + +TEST_F(SolverTest, BadCreateFromNameAndOptions) { + WithQuietOutput quiet{output_info}; + + Options options; + EXPECT_THROW(Solver::create("bad_solver", &options), BoutException); +} + +TEST_F(SolverTest, AddField2D) { + Options options; + FakeSolver solver{&options}; + + Field2D field{}; + EXPECT_NO_THROW(solver.add(field, "field")); + EXPECT_EQ(solver.n2Dvars(), 1); + EXPECT_EQ(solver.n3Dvars(), 0); + +#if CHECK > 0 + EXPECT_THROW(solver.add(field, "field"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 1); + EXPECT_EQ(solver.n3Dvars(), 0); +#endif + + EXPECT_NO_THROW(solver.add(field, "another_field")); + EXPECT_EQ(solver.n2Dvars(), 2); + EXPECT_EQ(solver.n3Dvars(), 0); +} + +TEST_F(SolverTest, AddField3D) { + Options options; + FakeSolver solver{&options}; + + Field3D field{}; + EXPECT_NO_THROW(solver.add(field, "field")); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 1); + +#if CHECK > 0 + EXPECT_THROW(solver.add(field, "field"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 1); +#endif + + EXPECT_NO_THROW(solver.add(field, "another_field")); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 2); +} + +TEST_F(SolverTest, Init) { + Options options; + FakeSolver solver{&options}; + + EXPECT_NO_THROW(solver.init(0, 0)); + EXPECT_THROW(solver.init(0, 0), BoutException); + + Field2D field{}; + EXPECT_THROW(solver.add(field, "field"), BoutException); +} + +TEST_F(SolverTest, SplitOperator) { + Options options; + FakeSolver solver{&options}; + + EXPECT_FALSE(solver.splitOperator()); +} + +TEST_F(SolverTest, ResetInternalFields) { + Options options; + FakeSolver solver{&options}; + + EXPECT_THROW(solver.resetInternalFields(), BoutException); +} + +TEST_F(SolverTest, SetMaxTimestep) { + Options options; + FakeSolver solver{&options}; + + EXPECT_NO_THROW(solver.setMaxTimestep(4.5)); +} + +TEST_F(SolverTest, GetCurrentTimestep) { + Options options; + FakeSolver solver{&options}; + + EXPECT_EQ(solver.getCurrentTimestep(), 0.0); +} From ed2573610c52400ad572840fd3f4adcad3c21793 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 15:36:01 +0000 Subject: [PATCH 1191/1783] Add some more Solver unit tests --- tests/unit/solver/test_solver.cxx | 270 ++++++++++++++++++++++++++++-- 1 file changed, 256 insertions(+), 14 deletions(-) diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx index 6d4a08b24c..2d4abe06de 100644 --- a/tests/unit/solver/test_solver.cxx +++ b/tests/unit/solver/test_solver.cxx @@ -12,7 +12,9 @@ namespace { class FakeSolver : public Solver { public: - FakeSolver(Options* options) : Solver(options) {} + FakeSolver(Options* options) : Solver(options) { + has_constraints = true; + } ~FakeSolver() = default; int run() { return (*options)["number"].withDefault(42); } }; @@ -22,8 +24,19 @@ RegisterSolver register_fake("fake_solver"); class SolverTest : public FakeMeshFixture { public: - SolverTest() : FakeMeshFixture() {} - virtual ~SolverTest() = default; + SolverTest() : FakeMeshFixture() { + Options::root()["field"]["function"] = "1.0"; + Options::root()["field"]["solution"] = "2.0"; + Options::root()["another_field"]["function"] = "3.0"; + Options::root()["another_field"]["solution"] = "4.0"; + Options::root()["vector_x"]["function"] = "5.0"; + Options::root()["vector_y"]["function"] = "6.0"; + Options::root()["vector_z"]["function"] = "7.0"; + Options::root()["another_vectorx"]["function"] = "8.0"; + Options::root()["another_vectory"]["function"] = "9.0"; + Options::root()["another_vectorz"]["function"] = "10.0"; + } + virtual ~SolverTest() { Options::cleanup(); } WithQuietOutput quiet_info{output_info}; WithQuietOutput quiet_progress{output_progress}; @@ -115,51 +128,280 @@ TEST_F(SolverTest, AddField2D) { Options options; FakeSolver solver{&options}; - Field2D field{}; - EXPECT_NO_THROW(solver.add(field, "field")); + Field2D field1{}, field2{}; + EXPECT_NO_THROW(solver.add(field1, "field")); EXPECT_EQ(solver.n2Dvars(), 1); EXPECT_EQ(solver.n3Dvars(), 0); + EXPECT_TRUE(IsFieldEqual(field1, 1.0)); #if CHECK > 0 - EXPECT_THROW(solver.add(field, "field"), BoutException); + EXPECT_THROW(solver.add(field2, "field"), BoutException); EXPECT_EQ(solver.n2Dvars(), 1); EXPECT_EQ(solver.n3Dvars(), 0); #endif - EXPECT_NO_THROW(solver.add(field, "another_field")); + EXPECT_NO_THROW(solver.add(field2, "another_field")); EXPECT_EQ(solver.n2Dvars(), 2); EXPECT_EQ(solver.n3Dvars(), 0); + EXPECT_TRUE(IsFieldEqual(field2, 3.0)); +} + +TEST_F(SolverTest, AddField2DMMS) { + Options options; + options["mms"] = true; + options["mms_initialise"] = true; + FakeSolver solver{&options}; + + Field2D field1{}, field2{}; + EXPECT_NO_THROW(solver.add(field1, "field")); + EXPECT_EQ(solver.n2Dvars(), 1); + EXPECT_EQ(solver.n3Dvars(), 0); + EXPECT_TRUE(IsFieldEqual(field1, 2.0)); + +#if CHECK > 0 + EXPECT_THROW(solver.add(field2, "field"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 1); + EXPECT_EQ(solver.n3Dvars(), 0); +#endif + + EXPECT_NO_THROW(solver.add(field2, "another_field")); + EXPECT_EQ(solver.n2Dvars(), 2); + EXPECT_EQ(solver.n3Dvars(), 0); + EXPECT_TRUE(IsFieldEqual(field2, 4.0)); } TEST_F(SolverTest, AddField3D) { Options options; FakeSolver solver{&options}; - Field3D field{}; - EXPECT_NO_THROW(solver.add(field, "field")); + Field3D field1{}, field2{}; + EXPECT_NO_THROW(solver.add(field1, "field")); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 1); + EXPECT_TRUE(IsFieldEqual(field1, 1.0)); + +#if CHECK > 0 + EXPECT_THROW(solver.add(field2, "field"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 1); +#endif + + EXPECT_NO_THROW(solver.add(field2, "another_field")); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 2); + EXPECT_TRUE(IsFieldEqual(field2, 3.0)); +} + +TEST_F(SolverTest, AddField3DMMS) { + Options options; + options["mms"] = true; + options["mms_initialise"] = true; + FakeSolver solver{&options}; + + Field3D field1{}, field2{}; + EXPECT_NO_THROW(solver.add(field1, "field")); EXPECT_EQ(solver.n2Dvars(), 0); EXPECT_EQ(solver.n3Dvars(), 1); + EXPECT_TRUE(IsFieldEqual(field1, 2.0)); #if CHECK > 0 - EXPECT_THROW(solver.add(field, "field"), BoutException); + EXPECT_THROW(solver.add(field2, "field"), BoutException); EXPECT_EQ(solver.n2Dvars(), 0); EXPECT_EQ(solver.n3Dvars(), 1); #endif - EXPECT_NO_THROW(solver.add(field, "another_field")); + EXPECT_NO_THROW(solver.add(field2, "another_field")); EXPECT_EQ(solver.n2Dvars(), 0); EXPECT_EQ(solver.n3Dvars(), 2); + EXPECT_TRUE(IsFieldEqual(field2, 4.0)); +} + +TEST_F(SolverTest, AddVector2D) { + Options options; + FakeSolver solver{&options}; + + Vector2D vector1{}, vector2{}; + EXPECT_NO_THROW(solver.add(vector1, "vector")); + EXPECT_EQ(solver.n2Dvars(), 3); + EXPECT_EQ(solver.n3Dvars(), 0); + EXPECT_TRUE(IsFieldEqual(vector1.x, 5.0)); + EXPECT_TRUE(IsFieldEqual(vector1.y, 6.0)); + EXPECT_TRUE(IsFieldEqual(vector1.z, 7.0)); + +#if CHECK > 0 + EXPECT_THROW(solver.add(vector2, "vector"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 3); + EXPECT_EQ(solver.n3Dvars(), 0); +#endif + + vector2.covariant = false; + EXPECT_NO_THROW(solver.add(vector2, "another_vector")); + EXPECT_EQ(solver.n2Dvars(), 6); + EXPECT_EQ(solver.n3Dvars(), 0); + EXPECT_TRUE(IsFieldEqual(vector2.x, 8.0)); + EXPECT_TRUE(IsFieldEqual(vector2.y, 9.0)); + EXPECT_TRUE(IsFieldEqual(vector2.z, 10.0)); +} + +TEST_F(SolverTest, AddVector3D) { + Options options; + FakeSolver solver{&options}; + + Vector3D vector1{}, vector2{}; + EXPECT_NO_THROW(solver.add(vector1, "vector")); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 3); + EXPECT_TRUE(IsFieldEqual(vector1.x, 5.0)); + EXPECT_TRUE(IsFieldEqual(vector1.y, 6.0)); + EXPECT_TRUE(IsFieldEqual(vector1.z, 7.0)); + +#if CHECK > 0 + EXPECT_THROW(solver.add(vector2, "vector"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 3); +#endif + + vector2.covariant = false; + EXPECT_NO_THROW(solver.add(vector2, "another_vector")); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 6); + EXPECT_TRUE(IsFieldEqual(vector2.x, 8.0)); + EXPECT_TRUE(IsFieldEqual(vector2.y, 9.0)); + EXPECT_TRUE(IsFieldEqual(vector2.z, 10.0)); } -TEST_F(SolverTest, Init) { +TEST_F(SolverTest, ConstraintField2D) { + Options options; + FakeSolver solver{&options}; + + Field2D field1{}, field2{}; + EXPECT_NO_THROW(solver.constraint(field1, field1, "field")); + EXPECT_EQ(solver.n2Dvars(), 1); + EXPECT_EQ(solver.n3Dvars(), 0); + +#if CHECK > 0 + EXPECT_THROW(solver.constraint(field2, field2, "field"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 1); + EXPECT_EQ(solver.n3Dvars(), 0); + EXPECT_THROW(solver.constraint(field2, field2, ""), BoutException); + EXPECT_EQ(solver.n2Dvars(), 1); + EXPECT_EQ(solver.n3Dvars(), 0); +#endif + + EXPECT_NO_THROW(solver.constraint(field2, field2, "another_field")); + EXPECT_EQ(solver.n2Dvars(), 2); + EXPECT_EQ(solver.n3Dvars(), 0); +} + +TEST_F(SolverTest, ConstraintField3D) { + Options options; + FakeSolver solver{&options}; + + Field3D field1{}, field2{}; + EXPECT_NO_THROW(solver.constraint(field1, field1, "field")); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 1); + +#if CHECK > 0 + EXPECT_THROW(solver.constraint(field2, field2, "field"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 1); + EXPECT_THROW(solver.constraint(field2, field2, ""), BoutException); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 1); +#endif + + EXPECT_NO_THROW(solver.constraint(field2, field2, "another_field")); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 2); +} + +TEST_F(SolverTest, ConstraintVector2D) { + Options options; + FakeSolver solver{&options}; + + Vector2D vector1{}, vector2{}; + EXPECT_NO_THROW(solver.constraint(vector1, vector1, "vector")); + EXPECT_EQ(solver.n2Dvars(), 3); + EXPECT_EQ(solver.n3Dvars(), 0); + +#if CHECK > 0 + EXPECT_THROW(solver.constraint(vector2, vector2, "vector"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 3); + EXPECT_EQ(solver.n3Dvars(), 0); + EXPECT_THROW(solver.constraint(vector2, vector2, ""), BoutException); + EXPECT_EQ(solver.n2Dvars(), 3); + EXPECT_EQ(solver.n3Dvars(), 0); +#endif + + vector2.covariant = false; + EXPECT_NO_THROW(solver.constraint(vector2, vector2, "another_vector")); + EXPECT_EQ(solver.n2Dvars(), 6); + EXPECT_EQ(solver.n3Dvars(), 0); +} + +TEST_F(SolverTest, ConstraintVector3D) { + Options options; + FakeSolver solver{&options}; + + Vector3D vector1{}, vector2{}; + EXPECT_NO_THROW(solver.constraint(vector1, vector1, "vector")); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 3); + +#if CHECK > 0 + EXPECT_THROW(solver.constraint(vector2, vector2, "vector"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 3); + EXPECT_THROW(solver.constraint(vector2, vector2, ""), BoutException); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 3); +#endif + + vector2.covariant = false; + EXPECT_NO_THROW(solver.constraint(vector2, vector2, "another_vector")); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 6); +} + +TEST_F(SolverTest, NoInitTwice) { Options options; FakeSolver solver{&options}; EXPECT_NO_THROW(solver.init(0, 0)); EXPECT_THROW(solver.init(0, 0), BoutException); +} + +TEST_F(SolverTest, NoAddAfterInit) { + Options options; + FakeSolver solver{&options}; + + EXPECT_NO_THROW(solver.init(0, 0)); + + Field2D field1{}; + EXPECT_THROW(solver.add(field1, "field"), BoutException); + Field3D field2{}; + EXPECT_THROW(solver.add(field2, "field"), BoutException); + Vector2D vector1{}; + EXPECT_THROW(solver.add(vector1, "vector"), BoutException); + Vector3D vector2{}; + EXPECT_THROW(solver.add(vector2, "vector"), BoutException); +} + +TEST_F(SolverTest, NoConstraintsAfterInit) { + Options options; + FakeSolver solver{&options}; + + EXPECT_NO_THROW(solver.init(0, 0)); - Field2D field{}; - EXPECT_THROW(solver.add(field, "field"), BoutException); + Field2D field1{}; + EXPECT_THROW(solver.constraint(field1, field1, "field"), BoutException); + Field3D field2{}; + EXPECT_THROW(solver.constraint(field2, field2, "field"), BoutException); + Vector2D vector1{}; + EXPECT_THROW(solver.constraint(vector1, vector1, "vector"), BoutException); + Vector3D vector2{}; + EXPECT_THROW(solver.constraint(vector2, vector2, "vector"), BoutException); } TEST_F(SolverTest, SplitOperator) { From 13fddf61c0c557c2c7a3392806b20d2c570d015e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 15:38:46 +0000 Subject: [PATCH 1192/1783] Bugfix: d.MMS_err not set for constraint Initialise VarStr pointer members to nullptr --- include/bout/solver.hxx | 12 ++++++------ src/solver/solver.cxx | 8 -------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 1f99dfaa00..5ad61b52e7 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -333,12 +333,12 @@ protected: template struct VarStr { bool constraint; - T *var; - T *F_var; - T *MMS_err; // Error for MMS - CELL_LOC location; // For fields and vector components - bool covariant; // For vectors - bool evolve_bndry; // Are the boundary regions being evolved? + T* var{nullptr}; + T* F_var{nullptr}; + T* MMS_err{nullptr}; // Error for MMS + CELL_LOC location; // For fields and vector components + bool covariant; // For vectors + bool evolve_bndry; // Are the boundary regions being evolved? std::string name; // Name of the variable }; diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index c5c2e2c66e..d58289ccf7 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -166,8 +166,6 @@ void Solver::add(Field2D &v, const std::string name) { if (mms) { // Allocate storage for error variable d.MMS_err = new Field2D{zeroFrom(v)}; - } else { - d.MMS_err = nullptr; } // Check if the boundary regions should be evolved @@ -228,8 +226,6 @@ void Solver::add(Field3D &v, const std::string name) { if (mms) { d.MMS_err = new Field3D{zeroFrom(v)}; - } else { - d.MMS_err = nullptr; } // Check if the boundary regions should be evolved @@ -265,8 +261,6 @@ void Solver::add(Vector2D &v, const std::string name) { d.location = CELL_DEFAULT; d.covariant = v.covariant; d.name = name; - // MMS errors set on individual components - d.MMS_err = nullptr; v2d.push_back(d); @@ -309,8 +303,6 @@ void Solver::add(Vector3D &v, const std::string name) { d.location = CELL_DEFAULT; d.covariant = v.covariant; d.name = name; - // MMS errors set on individual components - d.MMS_err = nullptr; v3d.push_back(d); From e8a06e76e9b67e770173148d1c69b071cf40db11 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 16:09:47 +0000 Subject: [PATCH 1193/1783] Fix copy-paste error in constraint(Vector2D/3D) --- src/solver/solver.cxx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index d58289ccf7..1987c84cab 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -415,12 +415,12 @@ void Solver::constraint(Vector2D &v, Vector2D &C_v, const std::string name) { // Add suffix, depending on co- /contravariance if (v.covariant) { constraint(v.x, C_v.x, d.name+"_x"); - constraint(v.y, C_v.y, d.name+"_x"); - constraint(v.z, C_v.z, d.name+"_x"); + constraint(v.y, C_v.y, d.name+"_y"); + constraint(v.z, C_v.z, d.name+"_z"); } else { constraint(v.x, C_v.x, d.name+"x"); - constraint(v.y, C_v.y, d.name+"x"); - constraint(v.z, C_v.z, d.name+"x"); + constraint(v.y, C_v.y, d.name+"y"); + constraint(v.z, C_v.z, d.name+"z"); } } @@ -456,12 +456,12 @@ void Solver::constraint(Vector3D &v, Vector3D &C_v, const std::string name) { // Add suffix, depending on co- /contravariance if (v.covariant) { constraint(v.x, C_v.x, d.name+"_x"); - constraint(v.y, C_v.y, d.name+"_x"); - constraint(v.z, C_v.z, d.name+"_x"); + constraint(v.y, C_v.y, d.name+"_y"); + constraint(v.z, C_v.z, d.name+"_z"); } else { constraint(v.x, C_v.x, d.name+"x"); - constraint(v.y, C_v.y, d.name+"x"); - constraint(v.z, C_v.z, d.name+"x"); + constraint(v.y, C_v.y, d.name+"y"); + constraint(v.z, C_v.z, d.name+"z"); } } From a34eb984993a60649280265326b4824e4b2e4da3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 16:11:02 +0000 Subject: [PATCH 1194/1783] Set default values for all components of VarStr --- include/bout/solver.hxx | 17 ++++++++--------- src/solver/solver.cxx | 8 -------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 5ad61b52e7..a36a6a2da3 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -332,15 +332,14 @@ protected: /// A structure to hold an evolving variable template struct VarStr { - bool constraint; - T* var{nullptr}; - T* F_var{nullptr}; - T* MMS_err{nullptr}; // Error for MMS - CELL_LOC location; // For fields and vector components - bool covariant; // For vectors - bool evolve_bndry; // Are the boundary regions being evolved? - - std::string name; // Name of the variable + bool constraint{false}; /// Does F_var represent a constraint? + T* var{nullptr}; /// The evolving variable + T* F_var{nullptr}; /// The time derivative or constraint on var + T* MMS_err{nullptr}; /// Error for MMS + CELL_LOC location{CELL_DEFAULT}; /// For fields and vector components + bool covariant{false}; /// For vectors + bool evolve_bndry{false}; /// Are the boundary regions being evolved? + std::string name; /// Name of the variable }; /// Vectors of variables to evolve diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 1987c84cab..dab52e231e 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -137,11 +137,9 @@ void Solver::add(Field2D &v, const std::string name) { VarStr d; - d.constraint = false; d.var = &v; d.F_var = &ddt(v); d.location = v.getLocation(); - d.covariant = false; d.name = name; #ifdef TRACK @@ -203,11 +201,9 @@ void Solver::add(Field3D &v, const std::string name) { VarStr d; - d.constraint = false; d.var = &v; d.F_var = &ddt(v); d.location = v.getLocation(); - d.covariant = false; d.name = name; #ifdef TRACK @@ -255,10 +251,8 @@ void Solver::add(Vector2D &v, const std::string name) { VarStr d; - d.constraint = false; d.var = &v; d.F_var = &ddt(v); - d.location = CELL_DEFAULT; d.covariant = v.covariant; d.name = name; @@ -297,10 +291,8 @@ void Solver::add(Vector3D &v, const std::string name) { VarStr d; - d.constraint = false; d.var = &v; d.F_var = &ddt(v); - d.location = CELL_DEFAULT; d.covariant = v.covariant; d.name = name; From 16888c8b981b61a4fbe0f97e4a3eba378b218712 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 16:12:51 +0000 Subject: [PATCH 1195/1783] Ensure TRACE macro is first line in Solver::constraint Also be more consistent with checking if variable is added to solver --- src/solver/solver.cxx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index dab52e231e..5ddbad5084 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -125,8 +125,10 @@ void Solver::setModel(PhysicsModel *m) { void Solver::add(Field2D &v, const std::string name) { TRACE("Adding 2D field: Solver::add(%s)", name.c_str()); +#if CHECK > 0 if (varAdded(name)) throw BoutException("Variable '%s' already added to Solver", name.c_str()); +#endif if (initialised) throw BoutException("Error: Cannot add to solver after initialisation\n"); @@ -317,13 +319,12 @@ void Solver::add(Vector3D &v, const std::string name) { **************************************************************************/ void Solver::constraint(Field2D &v, Field2D &C_v, const std::string name) { + TRACE("Constrain 2D scalar: Solver::constraint(%s)", name.c_str()); if (name.empty()) { throw BoutException("ERROR: Constraint requested for variable with empty name\n"); } - TRACE("Constrain 2D scalar: Solver::constraint(%s)", name.c_str()); - #if CHECK > 0 if (varAdded(name)) throw BoutException("Variable '%s' already added to Solver", name.c_str()); @@ -346,13 +347,12 @@ void Solver::constraint(Field2D &v, Field2D &C_v, const std::string name) { } void Solver::constraint(Field3D &v, Field3D &C_v, const std::string name) { + TRACE("Constrain 3D scalar: Solver::constraint(%s)", name.c_str()); if (name.empty()) { throw BoutException("ERROR: Constraint requested for variable with empty name\n"); } - TRACE("Constrain 3D scalar: Solver::constraint(%s)", name.c_str()); - #if CHECK > 0 if (varAdded(name)) throw BoutException("Variable '%s' already added to Solver", name.c_str()); @@ -376,13 +376,12 @@ void Solver::constraint(Field3D &v, Field3D &C_v, const std::string name) { } void Solver::constraint(Vector2D &v, Vector2D &C_v, const std::string name) { + TRACE("Constrain 2D vector: Solver::constraint(%s)", name.c_str()); if (name.empty()) { throw BoutException("ERROR: Constraint requested for variable with empty name\n"); } - TRACE("Constrain 2D vector: Solver::constraint(%s)", name.c_str()); - #if CHECK > 0 if (varAdded(name)) throw BoutException("Variable '%s' already added to Solver", name.c_str()); @@ -417,13 +416,12 @@ void Solver::constraint(Vector2D &v, Vector2D &C_v, const std::string name) { } void Solver::constraint(Vector3D &v, Vector3D &C_v, const std::string name) { + TRACE("Constrain 3D vector: Solver::constraint(%s)", name.c_str()); if (name.empty()) { throw BoutException("ERROR: Constraint requested for variable with empty name\n"); } - TRACE("Constrain 3D vector: Solver::constraint(%s)", name.c_str()); - #if CHECK > 0 if (varAdded(name)) throw BoutException("Variable '%s' already added to Solver", name.c_str()); From f0feb85c6af397db1a0e04345156d793e3b3aff7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 16:38:48 +0000 Subject: [PATCH 1196/1783] Tweak Solver unit tests - Check adding constraint when solver doesn't support it fails - Check stored evolving variables have the right name --- tests/unit/solver/test_solver.cxx | 101 ++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx index 2d4abe06de..9b7eb4fb32 100644 --- a/tests/unit/solver/test_solver.cxx +++ b/tests/unit/solver/test_solver.cxx @@ -8,6 +8,8 @@ #include "bout/solverfactory.hxx" #include +#include +#include namespace { class FakeSolver : public Solver { @@ -17,6 +19,36 @@ class FakeSolver : public Solver { } ~FakeSolver() = default; int run() { return (*options)["number"].withDefault(42); } + + void changeHasConstraints(bool new_value) { has_constraints = new_value; } + + auto listField2DNames() -> std::vector { + std::vector result{}; + std::transform(begin(f2d), end(f2d), std::back_inserter(result), + [](const VarStr& f) { return f.name; }); + return result; + } + + auto listField3DNames() -> std::vector { + std::vector result{}; + std::transform(begin(f3d), end(f3d), std::back_inserter(result), + [](const VarStr& f) { return f.name; }); + return result; + } + + auto listVector2DNames() -> std::vector { + std::vector result{}; + std::transform(begin(v2d), end(v2d), std::back_inserter(result), + [](const VarStr& f) { return f.name; }); + return result; + } + + auto listVector3DNames() -> std::vector { + std::vector result{}; + std::transform(begin(v3d), end(v3d), std::back_inserter(result), + [](const VarStr& f) { return f.name; }); + return result; + } }; RegisterSolver register_fake("fake_solver"); @@ -144,6 +176,9 @@ TEST_F(SolverTest, AddField2D) { EXPECT_EQ(solver.n2Dvars(), 2); EXPECT_EQ(solver.n3Dvars(), 0); EXPECT_TRUE(IsFieldEqual(field2, 3.0)); + + const auto expected_names = std::vector{"field", "another_field"}; + EXPECT_EQ(solver.listField2DNames(), expected_names); } TEST_F(SolverTest, AddField2DMMS) { @@ -168,6 +203,9 @@ TEST_F(SolverTest, AddField2DMMS) { EXPECT_EQ(solver.n2Dvars(), 2); EXPECT_EQ(solver.n3Dvars(), 0); EXPECT_TRUE(IsFieldEqual(field2, 4.0)); + + const auto expected_names = std::vector{"field", "another_field"}; + EXPECT_EQ(solver.listField2DNames(), expected_names); } TEST_F(SolverTest, AddField3D) { @@ -190,6 +228,9 @@ TEST_F(SolverTest, AddField3D) { EXPECT_EQ(solver.n2Dvars(), 0); EXPECT_EQ(solver.n3Dvars(), 2); EXPECT_TRUE(IsFieldEqual(field2, 3.0)); + + const auto expected_names = std::vector{"field", "another_field"}; + EXPECT_EQ(solver.listField3DNames(), expected_names); } TEST_F(SolverTest, AddField3DMMS) { @@ -214,6 +255,9 @@ TEST_F(SolverTest, AddField3DMMS) { EXPECT_EQ(solver.n2Dvars(), 0); EXPECT_EQ(solver.n3Dvars(), 2); EXPECT_TRUE(IsFieldEqual(field2, 4.0)); + + const auto expected_names = std::vector{"field", "another_field"}; + EXPECT_EQ(solver.listField3DNames(), expected_names); } TEST_F(SolverTest, AddVector2D) { @@ -241,6 +285,9 @@ TEST_F(SolverTest, AddVector2D) { EXPECT_TRUE(IsFieldEqual(vector2.x, 8.0)); EXPECT_TRUE(IsFieldEqual(vector2.y, 9.0)); EXPECT_TRUE(IsFieldEqual(vector2.z, 10.0)); + + const auto expected_names = std::vector{"vector", "another_vector"}; + EXPECT_EQ(solver.listVector2DNames(), expected_names); } TEST_F(SolverTest, AddVector3D) { @@ -268,6 +315,9 @@ TEST_F(SolverTest, AddVector3D) { EXPECT_TRUE(IsFieldEqual(vector2.x, 8.0)); EXPECT_TRUE(IsFieldEqual(vector2.y, 9.0)); EXPECT_TRUE(IsFieldEqual(vector2.z, 10.0)); + + const auto expected_names = std::vector{"vector", "another_vector"}; + EXPECT_EQ(solver.listVector3DNames(), expected_names); } TEST_F(SolverTest, ConstraintField2D) { @@ -283,14 +333,24 @@ TEST_F(SolverTest, ConstraintField2D) { EXPECT_THROW(solver.constraint(field2, field2, "field"), BoutException); EXPECT_EQ(solver.n2Dvars(), 1); EXPECT_EQ(solver.n3Dvars(), 0); + EXPECT_THROW(solver.constraint(field2, field2, ""), BoutException); EXPECT_EQ(solver.n2Dvars(), 1); EXPECT_EQ(solver.n3Dvars(), 0); + + solver.changeHasConstraints(false); + EXPECT_THROW(solver.constraint(field2, field2, "some_other_name"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 1); + EXPECT_EQ(solver.n3Dvars(), 0); + solver.changeHasConstraints(true); #endif EXPECT_NO_THROW(solver.constraint(field2, field2, "another_field")); EXPECT_EQ(solver.n2Dvars(), 2); EXPECT_EQ(solver.n3Dvars(), 0); + + const auto expected_names = std::vector{"field", "another_field"}; + EXPECT_EQ(solver.listField2DNames(), expected_names); } TEST_F(SolverTest, ConstraintField3D) { @@ -306,14 +366,24 @@ TEST_F(SolverTest, ConstraintField3D) { EXPECT_THROW(solver.constraint(field2, field2, "field"), BoutException); EXPECT_EQ(solver.n2Dvars(), 0); EXPECT_EQ(solver.n3Dvars(), 1); + EXPECT_THROW(solver.constraint(field2, field2, ""), BoutException); EXPECT_EQ(solver.n2Dvars(), 0); EXPECT_EQ(solver.n3Dvars(), 1); + + solver.changeHasConstraints(false); + EXPECT_THROW(solver.constraint(field2, field2, "some_other_name"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 1); + solver.changeHasConstraints(true); #endif EXPECT_NO_THROW(solver.constraint(field2, field2, "another_field")); EXPECT_EQ(solver.n2Dvars(), 0); EXPECT_EQ(solver.n3Dvars(), 2); + + const auto expected_names = std::vector{"field", "another_field"}; + EXPECT_EQ(solver.listField3DNames(), expected_names); } TEST_F(SolverTest, ConstraintVector2D) { @@ -329,15 +399,25 @@ TEST_F(SolverTest, ConstraintVector2D) { EXPECT_THROW(solver.constraint(vector2, vector2, "vector"), BoutException); EXPECT_EQ(solver.n2Dvars(), 3); EXPECT_EQ(solver.n3Dvars(), 0); + EXPECT_THROW(solver.constraint(vector2, vector2, ""), BoutException); EXPECT_EQ(solver.n2Dvars(), 3); EXPECT_EQ(solver.n3Dvars(), 0); + + solver.changeHasConstraints(false); + EXPECT_THROW(solver.constraint(vector2, vector2, "some_other_name"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 3); + EXPECT_EQ(solver.n3Dvars(), 0); + solver.changeHasConstraints(true); #endif vector2.covariant = false; EXPECT_NO_THROW(solver.constraint(vector2, vector2, "another_vector")); EXPECT_EQ(solver.n2Dvars(), 6); EXPECT_EQ(solver.n3Dvars(), 0); + + const auto expected_names = std::vector{"vector", "another_vector"}; + EXPECT_EQ(solver.listVector2DNames(), expected_names); } TEST_F(SolverTest, ConstraintVector3D) { @@ -353,15 +433,25 @@ TEST_F(SolverTest, ConstraintVector3D) { EXPECT_THROW(solver.constraint(vector2, vector2, "vector"), BoutException); EXPECT_EQ(solver.n2Dvars(), 0); EXPECT_EQ(solver.n3Dvars(), 3); + EXPECT_THROW(solver.constraint(vector2, vector2, ""), BoutException); EXPECT_EQ(solver.n2Dvars(), 0); EXPECT_EQ(solver.n3Dvars(), 3); + + solver.changeHasConstraints(false); + EXPECT_THROW(solver.constraint(vector2, vector2, "some_other_name"), BoutException); + EXPECT_EQ(solver.n2Dvars(), 0); + EXPECT_EQ(solver.n3Dvars(), 3); + solver.changeHasConstraints(true); #endif vector2.covariant = false; EXPECT_NO_THROW(solver.constraint(vector2, vector2, "another_vector")); EXPECT_EQ(solver.n2Dvars(), 0); EXPECT_EQ(solver.n3Dvars(), 6); + + const auto expected_names = std::vector{"vector", "another_vector"}; + EXPECT_EQ(solver.listVector3DNames(), expected_names); } TEST_F(SolverTest, NoInitTwice) { @@ -431,3 +521,14 @@ TEST_F(SolverTest, GetCurrentTimestep) { EXPECT_EQ(solver.getCurrentTimestep(), 0.0); } + +TEST_F(SolverTest, HasConstraints) { + Options options; + FakeSolver solver{&options}; + + EXPECT_TRUE(solver.constraints()); + + solver.changeHasConstraints(false); + + EXPECT_FALSE(solver.constraints()); +} From d7592ca13b9fd730170a376c384423666a196bab Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 17:40:16 +0000 Subject: [PATCH 1197/1783] Set default values for Solver members --- include/bout/solver.hxx | 99 +++++++++++++++++++++++++++-------------- src/solver/solver.cxx | 34 +++----------- 2 files changed, 70 insertions(+), 63 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index a36a6a2da3..0b5b73b4e5 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -286,8 +286,8 @@ class Solver { */ bool splitOperator() {return split_operator;} - bool canReset; - + bool canReset{false}; + /// Add evolving variables to output (dump) file or restart file /// /// @param[inout] outputfile The file to add variable to @@ -321,14 +321,17 @@ protected: static int* pargc; static char*** pargv; - // Settings to use during initialisation (set by constructor) - Options *options; + /// Settings to use during initialisation (set by constructor) + Options* options{nullptr}; + + /// Number of processors + int NPES{1}; + /// This processor's index + int MYPE{0}; - int NPES, MYPE; ///< Number of processors and this processor's index - /// Calculate the number of evolving variables on this processor int getLocalN(); - + /// A structure to hold an evolving variable template struct VarStr { @@ -348,19 +351,28 @@ protected: std::vector> v2d; std::vector> v3d; - bool has_constraints; ///< Can this solver handle constraints? Set to true if so. - bool initialised; ///< Has init been called yet? + /// Can this solver handle constraints? Set to true if so. + bool has_constraints{false}; + /// Has init been called yet? + bool initialised{false}; - BoutReal simtime; ///< Current simulation time - int iteration; ///< Current iteration (output time-step) number + /// Current simulation time + BoutReal simtime{0.0}; + /// Current iteration (output time-step) number + int iteration{0}; - int run_rhs(BoutReal t); ///< Run the user's RHS function - int run_convective(BoutReal t); ///< Calculate only the convective parts - int run_diffusive(BoutReal t, bool linear=true); ///< Calculate only the diffusive parts - - int call_monitors(BoutReal simtime, int iter, int NOUT); ///< Calls all monitor functions - - bool monitor_timestep; ///< Should timesteps be monitored? + /// Run the user's RHS function + int run_rhs(BoutReal t); + /// Calculate only the convective parts + int run_convective(BoutReal t); + /// Calculate only the diffusive parts + int run_diffusive(BoutReal t, bool linear = true); + + /// Calls all monitor functions + int call_monitors(BoutReal simtime, int iter, int NOUT); + + /// Should timesteps be monitored? + bool monitor_timestep{false}; int call_timestep_monitors(BoutReal simtime, BoutReal lastdt); bool have_user_precon(); // Do we have a user preconditioner? @@ -375,23 +387,42 @@ protected: // const Field3D globalIndex(int localStart); - - BoutReal max_dt; ///< Maximum internal timestep - + + /// Maximum internal timestep + BoutReal max_dt{-1.0}; + private: - int rhs_ncalls,rhs_ncalls_e,rhs_ncalls_i; ///< Number of calls to the RHS function - bool initCalled=false; ///< Has the init function of the solver been called? - int freqDefault=1; ///< Default sampling rate at which to call monitors - same as output to screen - BoutReal timestep=-1; ///< timestep - shouldn't be changed after init is called. - PhysicsModel *model; ///< physics model being evolved - - rhsfunc phys_run; ///< The user's RHS function - PhysicsPrecon prefunc; // Preconditioner - bool split_operator; - rhsfunc phys_conv, phys_diff; ///< Convective and Diffusive parts (if split operator) - - bool mms; ///< Enable sources and solutions for Method of Manufactured Solutions - bool mms_initialise; ///< Initialise variables to the manufactured solution + /// Number of calls to the RHS function + int rhs_ncalls{0}; + /// Number of calls to the explicit (convective) RHS function + int rhs_ncalls_e{0}; + /// Number of calls to the implicit (diffusive) RHS function + int rhs_ncalls_i{0}; + /// Has the init function of the solver been called? + bool initCalled{false}; + /// Default sampling rate at which to call monitors - same as output to screen + int freqDefault{1}; + /// timestep - shouldn't be changed after init is called. + BoutReal timestep{-1}; + /// Physics model being evolved + PhysicsModel* model{nullptr}; + + /// The user's RHS function + rhsfunc phys_run{nullptr}; + /// The user's preconditioner function + PhysicsPrecon prefunc{nullptr}; + /// Is the physics model using separate convective (explicit) and + /// diffusive (implicit) RHS functions? + bool split_operator{false}; + /// Convective part (if split operator) + rhsfunc phys_conv{nullptr}; + /// Diffusive part (if split operator) + rhsfunc phys_diff{nullptr}; + + /// Enable sources and solutions for Method of Manufactured Solutions + bool mms{false}; + /// Initialise variables to the manufactured solution + bool mms_initialise{false}; void add_mms_sources(BoutReal t); void calculate_mms_error(BoutReal t); diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 5ddbad5084..4d36e15be5 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -50,35 +50,11 @@ char ***Solver::pargv = nullptr; * Constructor **************************************************************************/ -Solver::Solver(Options *opts) : options(opts), model(nullptr), prefunc(nullptr) { - if(options == nullptr) - options = Options::getRoot()->getSection("solver"); - - // Set flags to defaults - has_constraints = false; - initialised = false; - canReset = false; - - // Zero timing - rhs_ncalls = 0; - rhs_ncalls_e = 0; - rhs_ncalls_i = 0; - - // Split operator - split_operator = false; - max_dt = -1.0; - - // Set simulation time and iteration count - // This may be modified by restart - simtime = 0.0; iteration = 0; - - // Output monitor - options->get("monitor_timestep", monitor_timestep, false); - - // Method of Manufactured Solutions (MMS) - options->get("mms", mms, false); - options->get("mms_initialise", mms_initialise, mms); -} +Solver::Solver(Options* opts) + : options(opts == nullptr ? &Options::root()["solver"] : opts), + monitor_timestep((*options)["monitor_timestep"].withDefault(false)), + mms((*options)["mms"].withDefault(false)), + mms_initialise((*options)["mms_initialise"].withDefault(mms)) {} /************************************************************************** * Destructor From 992bccab5810e1b0cdcd8d3adfa490cb18fdd738 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 17:50:31 +0000 Subject: [PATCH 1198/1783] Use type alias rather than type def in Solver --- include/bout/solver.hxx | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 0b5b73b4e5..343561db75 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -33,7 +33,6 @@ * **************************************************************************/ -class Solver; #include #include @@ -50,20 +49,19 @@ class Solver; /////////////////////////////////////////////////////////////////// // C function pointer types +class Solver; + /// RHS function pointer -typedef int (*rhsfunc)(BoutReal); // C-style function pointer +using rhsfunc = int (*)(BoutReal); /// User-supplied preconditioner function -typedef int (*PhysicsPrecon)(BoutReal t, BoutReal gamma, BoutReal delta); +using PhysicsPrecon = int (*)(BoutReal t, BoutReal gamma, BoutReal delta); /// User-supplied Jacobian function -typedef int (*Jacobian)(BoutReal t); - +using Jacobian = int (*)(BoutReal t); /// Solution monitor, called each timestep -typedef int (*TimestepMonitorFunc)(Solver *solver, BoutReal simtime, BoutReal lastdt); - - +using TimestepMonitorFunc = int (*)(Solver* solver, BoutReal simtime, BoutReal lastdt); //#include "globals.hxx" #include "field2d.hxx" @@ -78,7 +76,7 @@ typedef int (*TimestepMonitorFunc)(Solver *solver, BoutReal simtime, BoutReal la #include #include -typedef std::string SolverType; +using SolverType = std::string; #define SOLVERCVODE "cvode" #define SOLVERPVODE "pvode" #define SOLVERIDA "ida" From b1eec4d3f9aa19c833cc363b606d1aa8eb44c1d0 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 18:02:08 +0000 Subject: [PATCH 1199/1783] Use constexpr auto instead of macro for Solver names Note: these are const char*, not std::string --- include/bout/solver.hxx | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 343561db75..d5437ef443 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -77,20 +77,20 @@ using TimestepMonitorFunc = int (*)(Solver* solver, BoutReal simtime, BoutReal l #include using SolverType = std::string; -#define SOLVERCVODE "cvode" -#define SOLVERPVODE "pvode" -#define SOLVERIDA "ida" -#define SOLVERPETSC "petsc" -#define SOLVERSLEPC "slepc" -#define SOLVERKARNIADAKIS "karniadakis" -#define SOLVERRK4 "rk4" -#define SOLVEREULER "euler" -#define SOLVERRK3SSP "rk3ssp" -#define SOLVERPOWER "power" -#define SOLVERARKODE "arkode" -#define SOLVERIMEXBDF2 "imexbdf2" -#define SOLVERSNES "snes" -#define SOLVERRKGENERIC "rkgeneric" +constexpr auto SOLVERCVODE = "cvode"; +constexpr auto SOLVERPVODE = "pvode"; +constexpr auto SOLVERIDA = "ida"; +constexpr auto SOLVERPETSC = "petsc"; +constexpr auto SOLVERSLEPC = "slepc"; +constexpr auto SOLVERKARNIADAKIS = "karniadakis"; +constexpr auto SOLVERRK4 = "rk4"; +constexpr auto SOLVEREULER = "euler"; +constexpr auto SOLVERRK3SSP = "rk3ssp"; +constexpr auto SOLVERPOWER = "power"; +constexpr auto SOLVERARKODE = "arkode"; +constexpr auto SOLVERIMEXBDF2 = "imexbdf2"; +constexpr auto SOLVERSNES = "snes"; +constexpr auto SOLVERRKGENERIC = "rkgeneric"; enum SOLVER_VAR_OP {LOAD_VARS, LOAD_DERIVS, SET_ID, SAVE_VARS, SAVE_DERIVS}; From 9780e6f4cfe212f3360e382efef409917d0b42fd Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 27 Mar 2019 18:02:59 +0000 Subject: [PATCH 1200/1783] Clang-format Solver plus more consistent documentation --- include/bout/solver.hxx | 293 ++++++++++++++++++++-------------------- src/solver/solver.cxx | 7 +- 2 files changed, 144 insertions(+), 156 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index d5437ef443..c439e116ff 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -2,20 +2,20 @@ * Base class for all solvers. Specifies required interface functions * * Changelog: - * + * * 2009-08 Ben Dudson, Sean Farley * * Major overhaul, and changed API. Trying to make consistent * interface to PETSc and SUNDIALS solvers - * + * * 2013-08 Ben Dudson * * Added OO-style API, to allow multiple physics models to coexist * For now both APIs are supported - * + * ************************************************************************** * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -33,19 +33,16 @@ * **************************************************************************/ - -#include -#include -#include -#include "bout/monitor.hxx" -#include "options.hxx" -#include "datafile.hxx" - -/////////////////////////////////////////////////////////////////// - #ifndef __SOLVER_H__ #define __SOLVER_H__ +#include "bout_types.hxx" +#include "boutexception.hxx" +#include "datafile.hxx" +#include "options.hxx" +#include "unused.hxx" +#include "bout/monitor.hxx" + /////////////////////////////////////////////////////////////////// // C function pointer types @@ -73,8 +70,8 @@ using TimestepMonitorFunc = int (*)(Solver* solver, BoutReal simtime, BoutReal l #include "physicsmodel.hxx" #undef BOUT_NO_USING_NAMESPACE_BOUTGLOBALS -#include #include +#include using SolverType = std::string; constexpr auto SOLVERCVODE = "cvode"; @@ -99,24 +96,24 @@ enum SOLVER_VAR_OP {LOAD_VARS, LOAD_DERIVS, SET_ID, SAVE_VARS, SAVE_DERIVS}; /*! * Interface to integrators, mainly for time integration * - * + * * Creation * -------- - * + * * Solver is a base class and can't be created directly: - * + * * Solver *solver = Solver(); // Error - * + * * Instead, use the create() static function: - * + * * Solver *solver = Solver::create(); // ok * * By default this will use the options in the "solver" section * of the options, equivalent to: - * + * * Options *opts = Options::getRoot()->getSection("solver"); * Solver *solver = Solver::create(opts); - * + * * To use a different set of options, for example if there are * multiple solvers, use a different option section: * @@ -125,7 +122,7 @@ enum SOLVER_VAR_OP {LOAD_VARS, LOAD_DERIVS, SET_ID, SAVE_VARS, SAVE_DERIVS}; * * Problem specification * --------------------- - * + * * The equations to be solved are specified in a PhysicsModel object * * class MyProblem : public PhysicsModel { @@ -146,131 +143,128 @@ enum SOLVER_VAR_OP {LOAD_VARS, LOAD_DERIVS, SET_ID, SAVE_VARS, SAVE_DERIVS}; * private: * Field3D f; // A variable to evolve * } - * + * * The init() and rhs() functions must be defined, but there * are other functions which can be defined. See PhysicsModel * documentation for details. - * + * * Create an object, then add to the solver: - * + * * MyProblem *prob = MyProblem(); * solver->setModel(prob); - * + * * Running simulation * ------------------ - * + * * To run a calculation - * + * * solver->solve(); - * - * This will use NOUT and TIMESTEP in the solver options + * + * This will use NOUT and TIMESTEP in the solver options * (specified during creation). If these are not present * then the global options will be used. - * + * * To specify NOUT and TIMESTEP, pass the values to solve: * * solver->solve(NOUT, TIMESTEP); */ class Solver { - public: - Solver(Options *opts = nullptr); +public: + Solver(Options* opts = nullptr); virtual ~Solver(); ///////////////////////////////////////////// // New API - - /*! - * Specify physics model to solve. Currently only one model - * can be evolved by a Solver. - */ - virtual void setModel(PhysicsModel *model); + + /// Specify physics model to solve. Currently only one model can be + /// evolved by a Solver. + virtual void setModel(PhysicsModel* model); ///////////////////////////////////////////// // Old API - - virtual void setRHS(rhsfunc f) { phys_run = f; } ///< Set the RHS function - void setPrecon(PhysicsPrecon f) {prefunc = f;} ///< Specify a preconditioner (optional) - virtual void setJacobian(Jacobian UNUSED(j)) {} ///< Specify a Jacobian (optional) - virtual void setSplitOperator(rhsfunc fC, rhsfunc fD); ///< Split operator solves - + + /// Set the RHS function + virtual void setRHS(rhsfunc f) { phys_run = f; } + /// Specify a preconditioner (optional) + void setPrecon(PhysicsPrecon f) { prefunc = f; } + /// Specify a Jacobian (optional) + virtual void setJacobian(Jacobian UNUSED(j)) {} + /// Split operator solves + virtual void setSplitOperator(rhsfunc fC, rhsfunc fD); + ///////////////////////////////////////////// // Monitors - - enum MonitorPosition {BACK, FRONT}; ///< A type to set where in the list monitors are added + + /// A type to set where in the list monitors are added + enum MonitorPosition { BACK, FRONT }; /// Add a monitor to be called every output - void addMonitor(Monitor * f, MonitorPosition pos=FRONT); - void removeMonitor(Monitor * f); ///< Remove a monitor function previously added + void addMonitor(Monitor* f, MonitorPosition pos = FRONT); + /// Remove a monitor function previously added + void removeMonitor(Monitor* f); - void addTimestepMonitor(TimestepMonitorFunc f); ///< Add a monitor function to be called every timestep - void removeTimestepMonitor(TimestepMonitorFunc f); ///< Remove a previously added timestep monitor + /// Add a monitor function to be called every timestep + void addTimestepMonitor(TimestepMonitorFunc f); + /// Remove a previously added timestep monitor + void removeTimestepMonitor(TimestepMonitorFunc f); ///////////////////////////////////////////// // Routines to add variables. Solvers can just call these // (or leave them as-is) - - /*! - * Add a variable to be solved. This must be done - * in the initialisation stage, before the simulation starts. - */ - virtual void add(Field2D &v, const std::string name); - virtual void add(Field3D &v, const std::string name); - virtual void add(Vector2D &v, const std::string name); - virtual void add(Vector3D &v, const std::string name); - - /*! - * Returns true if constraints available - */ - virtual bool constraints() {return has_constraints; } - - /*! - * Add constraint functions (optional). These link a variable - * v to a control parameter C_v such that v is adjusted - * to keep C_v = 0. - */ - virtual void constraint(Field2D &v, Field2D &C_v, const std::string name); - virtual void constraint(Field3D &v, Field3D &C_v, const std::string name); - virtual void constraint(Vector2D &v, Vector2D &C_v, const std::string name); - virtual void constraint(Vector3D &v, Vector3D &C_v, const std::string name); - + + /// Add a variable to be solved. This must be done in the + /// initialisation stage, before the simulation starts. + virtual void add(Field2D& v, const std::string name); + virtual void add(Field3D& v, const std::string name); + virtual void add(Vector2D& v, const std::string name); + virtual void add(Vector3D& v, const std::string name); + + /// Returns true if constraints available + virtual bool constraints() { return has_constraints; } + + /// Add constraint functions (optional). These link a variable v to + /// a control parameter C_v such that v is adjusted to keep C_v = 0. + virtual void constraint(Field2D& v, Field2D& C_v, const std::string name); + virtual void constraint(Field3D& v, Field3D& C_v, const std::string name); + virtual void constraint(Vector2D& v, Vector2D& C_v, const std::string name); + virtual void constraint(Vector3D& v, Vector3D& C_v, const std::string name); + /// Set a maximum internal timestep (only for explicit schemes) - virtual void setMaxTimestep(BoutReal dt) {max_dt = dt;} - /// Return the current internal timestep - virtual BoutReal getCurrentTimestep() {return 0.0;} - - /*! - * Start the solver. By default solve() uses options - * to determine the number of steps and the output timestep. - * If nout and dt are specified here then the options are not used - * - * @param[in] nout Number of output timesteps - * @param[in] dt The time between outputs - */ - int solve(int nout=-1, BoutReal dt=0.0); + virtual void setMaxTimestep(BoutReal dt) { max_dt = dt; } + /// Return the current internal timestep + virtual BoutReal getCurrentTimestep() { return 0.0; } + + /// Start the solver. By default solve() uses options + /// to determine the number of steps and the output timestep. + /// If nout and dt are specified here then the options are not used + /// + /// @param[in] nout Number of output timesteps + /// @param[in] dt The time between outputs + int solve(int nout = -1, BoutReal dt = 0.0); /// Initialise the solver /// NOTE: nout and tstep should be passed to run, not init. /// Needed because of how the PETSc TS code works virtual int init(int nout, BoutReal tstep); - /*! - * Run the solver, calling monitors nout times, at intervals of tstep - * This function is called by solve(), and is specific to each solver type - * - * This should probably be protected, since it shouldn't be called - * by users. - */ + /// Run the solver, calling monitors nout times, at intervals of + /// tstep. This function is called by solve(), and is specific to + /// each solver type + /// + /// This should probably be protected, since it shouldn't be called + /// by users. virtual int run() = 0; - //Should wipe out internal field vector and reset from current field object data - virtual void resetInternalFields(){ - throw BoutException("resetInternalFields not supported by this Solver");} + /// Should wipe out internal field vector and reset from current field object data + virtual void resetInternalFields() { + throw BoutException("resetInternalFields not supported by this Solver"); + } // Solver status. Optional functions used to query the solver /// Number of 2D variables. Vectors count as 3 - virtual int n2Dvars() const {return f2d.size();} + virtual int n2Dvars() const { return f2d.size(); } /// Number of 3D variables. Vectors count as 3 - virtual int n3Dvars() const {return f3d.size();} + virtual int n3Dvars() const { return f3d.size(); } /// Get and reset the number of calls to the RHS function int resetRHSCounter(); @@ -278,11 +272,9 @@ class Solver { int resetRHSCounter_e(); /// Same but fur implicit timestep counter - for IMEX int resetRHSCounter_i(); - - /*! - * Test if this solver supports split operators (e.g. implicit/explicit) - */ - bool splitOperator() {return split_operator;} + + /// Test if this solver supports split operators (e.g. implicit/explicit) + bool splitOperator() { return split_operator; } bool canReset{false}; @@ -290,33 +282,28 @@ class Solver { /// /// @param[inout] outputfile The file to add variable to /// @param[in] save_repeat If true, add variables with time dimension - virtual void outputVars(Datafile &outputfile, bool save_repeat=true); - - /*! - * Create a Solver object. This uses the "type" option - * in the given Option section to determine which solver - * type to create. - */ - static Solver *create(Options *opts = nullptr); - - /*! - * Create a Solver object, specifying the type - */ + virtual void outputVars(Datafile& outputfile, bool save_repeat = true); + + /// Create a Solver object. This uses the "type" option in the given + /// Option section to determine which solver type to create. + static Solver* create(Options* opts = nullptr); + + /// Create a Solver object, specifying the type static Solver* create(const SolverType& type, Options* opts = nullptr); - /*! - * Pass the command-line arguments. This static function is - * called by BoutInitialise, and puts references - * into protected variables. These may then be used by Solvers - * to control behavior - * - */ - static void setArgs(int &c, char **&v) { pargc = &c; pargv = &v;} - + /// Pass the command-line arguments. This static function is + /// called by BoutInitialise, and puts references + /// into protected variables. These may then be used by Solvers + /// to control behavior + static void setArgs(int& c, char**& v) { + pargc = &c; + pargv = &v; + } + protected: - - // Command-line arguments + /// Number of command-line arguments static int* pargc; + /// Command-line arguments static char*** pargv; /// Settings to use during initialisation (set by constructor) @@ -373,18 +360,19 @@ protected: bool monitor_timestep{false}; int call_timestep_monitors(BoutReal simtime, BoutReal lastdt); - bool have_user_precon(); // Do we have a user preconditioner? + /// Do we have a user preconditioner? + bool have_user_precon(); int run_precon(BoutReal t, BoutReal gamma, BoutReal delta); - + // Loading data from BOUT++ to/from solver - void load_vars(BoutReal *udata); - void load_derivs(BoutReal *udata); - void save_vars(BoutReal *udata); - void save_derivs(BoutReal *dudata); - void set_id(BoutReal *udata); - - // - const Field3D globalIndex(int localStart); + void load_vars(BoutReal* udata); + void load_derivs(BoutReal* udata); + void save_vars(BoutReal* udata); + void save_derivs(BoutReal* dudata); + void set_id(BoutReal* udata); + + /// Returns a Field3D containing the global indices + Field3D globalIndex(int localStart); /// Maximum internal timestep BoutReal max_dt{-1.0}; @@ -424,18 +412,23 @@ private: void add_mms_sources(BoutReal t); void calculate_mms_error(BoutReal t); - - std::list monitors; ///< List of monitor functions - std::list timestep_monitors; ///< List of timestep monitor functions - void pre_rhs(BoutReal t); // Should be run before user RHS is called - void post_rhs(BoutReal t); // Should be run after user RHS is called - - // Loading data from BOUT++ to/from solver - void loop_vars_op(Ind2D i2d, BoutReal *udata, int &p, SOLVER_VAR_OP op, bool bndry); - void loop_vars(BoutReal *udata, SOLVER_VAR_OP op); + /// List of monitor functions + std::list monitors; + /// List of timestep monitor functions + std::list timestep_monitors; + + /// Should be run before user RHS is called + void pre_rhs(BoutReal t); + /// Should be run after user RHS is called + void post_rhs(BoutReal t); + + /// Loading data from BOUT++ to/from solver + void loop_vars_op(Ind2D i2d, BoutReal* udata, int& p, SOLVER_VAR_OP op, bool bndry); + void loop_vars(BoutReal* udata, SOLVER_VAR_OP op); - bool varAdded(const std::string &name); // Check if a variable has already been added + /// Check if a variable has already been added + bool varAdded(const std::string& name); }; #endif // __SOLVER_H__ diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 4d36e15be5..1bbfa5ef48 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -1040,12 +1040,7 @@ void Solver::set_id(BoutReal *udata) { loop_vars(udata, SET_ID); } - -/*! - * Returns a Field3D containing the global indices - * - */ -const Field3D Solver::globalIndex(int localStart) { +Field3D Solver::globalIndex(int localStart) { // Use global mesh: FIX THIS! Mesh* mesh = bout::globals::mesh; From 811042e6e86efdceb2fa3882f8693379a0619a01 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Mar 2019 11:09:27 +0000 Subject: [PATCH 1201/1783] Simplify Solver::varAdded with algorithm + helper functions --- include/bout/solver.hxx | 13 +++++++++++++ src/solver/solver.cxx | 25 +++---------------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index c439e116ff..95cb217949 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -330,6 +330,19 @@ protected: std::string name; /// Name of the variable }; + /// Does \p var represent field \p name? + template + friend bool operator==(const VarStr& var, const std::string& name) { + return var.name == name; + } + + /// Does \p vars contain a field with \p name? + template + bool contains(const std::vector>& vars, const std::string& name) { + const auto in_vars = std::find(begin(vars), end(vars), name); + return in_vars != end(vars); + } + /// Vectors of variables to evolve std::vector> f2d; std::vector> f3d; diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 1bbfa5ef48..3c5212d208 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -1276,28 +1276,9 @@ void Solver::post_rhs(BoutReal UNUSED(t)) { #endif } -bool Solver::varAdded(const std::string &name) { - for(const auto& f : f2d) { - if(f.name == name) - return true; - } - - for(const auto& f : f3d) { - if(f.name == name) - return true; - } - - for(const auto& f : v2d) { - if(f.name == name) - return true; - } - - for(const auto& f : v3d) { - if(f.name == name) - return true; - } - - return false; +bool Solver::varAdded(const std::string& name) { + return contains(f2d, name) || contains(f3d, name) || contains(v2d, name) + || contains(v3d, name); } bool Solver::have_user_precon() { From e877634c9639542f8892f37a9c591014ed51ef5c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Mar 2019 11:15:09 +0000 Subject: [PATCH 1202/1783] Improve Solver test for splitOperator --- tests/unit/solver/test_solver.cxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx index 9b7eb4fb32..fe15776b01 100644 --- a/tests/unit/solver/test_solver.cxx +++ b/tests/unit/solver/test_solver.cxx @@ -499,6 +499,11 @@ TEST_F(SolverTest, SplitOperator) { FakeSolver solver{&options}; EXPECT_FALSE(solver.splitOperator()); + + rhsfunc fake_rhs = [](BoutReal) -> int { return 0;}; + solver.setSplitOperator(fake_rhs, fake_rhs); + + EXPECT_TRUE(solver.splitOperator()); } TEST_F(SolverTest, ResetInternalFields) { From 2d4d58d77d98414a56efec846856785a7cdd479a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Mar 2019 14:36:20 +0000 Subject: [PATCH 1203/1783] Add test for Solver::getLocalN - Need shim in FakeSolver to expose protected method - Need method in FakeMesh to make regions for boundaries --- tests/unit/solver/test_solver.cxx | 29 +++++++++++++++++++++ tests/unit/test_extras.hxx | 43 ++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx index fe15776b01..5b431b7329 100644 --- a/tests/unit/solver/test_solver.cxx +++ b/tests/unit/solver/test_solver.cxx @@ -49,6 +49,8 @@ class FakeSolver : public Solver { [](const VarStr& f) { return f.name; }); return result; } + + int getLocalNHelper() { return getLocalN(); } }; RegisterSolver register_fake("fake_solver"); @@ -537,3 +539,30 @@ TEST_F(SolverTest, HasConstraints) { EXPECT_FALSE(solver.constraints()); } + +TEST_F(SolverTest, GetLocalN) { + Options options; + FakeSolver solver{&options}; + + Options::root()["field2"]["evolve_bndry"] = true; + Options::root()["field4"]["evolve_bndry"] = true; + + Field2D field1{}, field2{}; + Field3D field3{}, field4{}; + + solver.add(field1, "field1"); + solver.add(field2, "field2"); + solver.add(field3, "field3"); + solver.add(field4, "field4"); + + solver.init(0, 0); + + static_cast(field1.getMesh())->createBoundaryRegions(); + + constexpr auto nx_no_boundry = nx - 2; + constexpr auto ny_no_boundry = ny - 2; + constexpr auto expected_total = (nx_no_boundry * ny_no_boundry) + (nx * ny) + + (nx_no_boundry * ny_no_boundry * nz) + (nx * ny * nz); + + EXPECT_EQ(solver.getLocalNHelper(), expected_total); +} diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 2ac8cc1fdf..d5c7bbd52c 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -3,11 +3,12 @@ #include "gtest/gtest.h" +#include #include #include -#include #include +#include "boutcomm.hxx" #include "bout/mesh.hxx" #include "bout/coordinates.hxx" #include "field3d.hxx" @@ -275,6 +276,46 @@ public: StaggerGrids=true; derivs_init(opt); } + + void createBoundaryRegions() { + addRegion2D("RGN_LOWER_Y", + Region(0, LocalNx - 1, 0, ystart - 1, 0, 0, LocalNy, 1)); + addRegion3D("RGN_LOWER_Y", Region(0, LocalNx - 1, 0, ystart - 1, 0, + LocalNz - 1, LocalNy, LocalNz)); + addRegion2D("RGN_UPPER_Y", + Region(0, LocalNx - 1, yend + 1, LocalNy - 1, 0, 0, LocalNy, 1)); + addRegion3D("RGN_UPPER_Y", Region(0, LocalNx - 1, yend + 1, LocalNy - 1, 0, + LocalNz - 1, LocalNy, LocalNz)); + addRegion2D("RGN_INNER_X", + Region(0, xstart - 1, 0, LocalNy - 1, 0, 0, LocalNy, 1)); + addRegion3D("RGN_INNER_X", Region(0, xstart - 1, 0, LocalNy - 1, 0, + LocalNz - 1, LocalNy, LocalNz)); + addRegion2D("RGN_OUTER_X", + Region(xend + 1, LocalNx - 1, 0, LocalNy - 1, 0, 0, LocalNy, 1)); + addRegion3D("RGN_OUTER_X", Region(xend + 1, LocalNx - 1, 0, LocalNy - 1, 0, + LocalNz - 1, LocalNy, LocalNz)); + + const auto boundary_names = {"RGN_LOWER_Y", "RGN_UPPER_Y", "RGN_INNER_X", + "RGN_OUTER_X"}; + + // Sum up and get unique points in the boundaries defined above + addRegion2D("RGN_BNDRY", + std::accumulate(begin(boundary_names), end(boundary_names), + Region{}, + [this](Region& a, const std::string& b) { + return a + getRegion2D(b); + }) + .unique()); + + addRegion3D("RGN_BNDRY", + std::accumulate(begin(boundary_names), end(boundary_names), + Region{}, + [this](Region& a, const std::string& b) { + return a + getRegion3D(b); + }) + .unique()); + } + private: std::vector boundaries; }; From 308fedaccec0fcbdeae932923eef62477602c548 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Mar 2019 14:37:41 +0000 Subject: [PATCH 1204/1783] Simplify Solver::getLocalN via helper function Also removes dependency on global Mesh --- include/bout/solver.hxx | 10 ++++++++ src/solver/solver.cxx | 53 +++++++++++++++-------------------------- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 95cb217949..59120c4b38 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -343,6 +343,16 @@ protected: return in_vars != end(vars); } + /// Helper function for getLocalN: return the number of points to + /// evolve in \p f, plus the accumulator \p value + /// + /// If f.evolve_bndry, includes the boundary (NB: not guard!) points + /// + /// FIXME: This could be a lambda local to getLocalN with an `auto` + /// argument in C++14 + template + friend int local_N_sum(int value, const VarStr& f); + /// Vectors of variables to evolve std::vector> f2d; std::vector> f3d; diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 3c5212d208..47ed3ce452 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -41,6 +41,8 @@ #include #include "bout/region.hxx" +#include + // Static member variables int *Solver::pargc = nullptr; @@ -732,45 +734,28 @@ int Solver::call_timestep_monitors(BoutReal simtime, BoutReal lastdt) { * Useful routines (protected) **************************************************************************/ -int Solver::getLocalN() { +template +int local_N_sum(int value, const Solver::VarStr& f) { + const auto boundary_size = f.evolve_bndry ? size(f.var->getRegion("RGN_BNDRY")) : 0; + return value + boundary_size + size(f.var->getRegion("RGN_NOBNDRY")); +} - // Use global mesh: FIX THIS! - Mesh* mesh = bout::globals::mesh; +int Solver::getLocalN() { - /// Cache the value, so this is not repeatedly called. - /// This value should not change after initialisation - static int cacheLocalN = -1; - if(cacheLocalN != -1) { + // Cache the value, so this is not repeatedly called. + // This value should not change after initialisation + static int cacheLocalN{-1}; + if (cacheLocalN != -1) { return cacheLocalN; } - - ASSERT0(initialised); // Must be initialised - - int n2d = n2Dvars(); - int n3d = n3Dvars(); - - int local_N = size(mesh->getRegion2D("RGN_NOBNDRY")) * (n2d + mesh->LocalNz*n3d); - - //////////// How many variables have evolving boundaries? - - int n2dbndry = 0; - for(const auto& f : f2d) { - if(f.evolve_bndry) - n2dbndry++; - } - - int n3dbndry = 0; - for(const auto& f : f3d) { - if(f.evolve_bndry) - n3dbndry++; - } - //////////// Find boundary regions //////////// - - // Add the points which will be evolved in the boundaries - local_N += size(mesh->getRegion2D("RGN_BNDRY")) * n2dbndry - + size(mesh->getRegion3D("RGN_BNDRY")) * n3dbndry; - + // Must be initialised + ASSERT0(initialised); + + const auto local_N_2D = std::accumulate(begin(f2d), end(f2d), 0, local_N_sum); + const auto local_N_3D = std::accumulate(begin(f3d), end(f3d), 0, local_N_sum); + const auto local_N = local_N_2D + local_N_3D; + cacheLocalN = local_N; return local_N; From 841dbf6936a1049796edf59c7445e5dc928b90d1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Mar 2019 14:47:19 +0000 Subject: [PATCH 1205/1783] Test that Solver::getLocalN works with multiple meshes --- tests/unit/solver/test_solver.cxx | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx index 5b431b7329..c5df252060 100644 --- a/tests/unit/solver/test_solver.cxx +++ b/tests/unit/solver/test_solver.cxx @@ -547,8 +547,18 @@ TEST_F(SolverTest, GetLocalN) { Options::root()["field2"]["evolve_bndry"] = true; Options::root()["field4"]["evolve_bndry"] = true; - Field2D field1{}, field2{}; - Field3D field3{}, field4{}; + constexpr auto localmesh_nx = 5; + constexpr auto localmesh_ny = 7; + constexpr auto localmesh_nz = 9; + + FakeMesh localmesh{localmesh_nx, localmesh_ny, localmesh_nz}; + localmesh.createDefaultRegions(); + localmesh.createBoundaryRegions(); + + Field2D field1{bout::globals::mesh}; + Field2D field2{&localmesh}; + Field3D field3{&localmesh}; + Field3D field4{bout::globals::mesh}; solver.add(field1, "field1"); solver.add(field2, "field2"); @@ -559,10 +569,15 @@ TEST_F(SolverTest, GetLocalN) { static_cast(field1.getMesh())->createBoundaryRegions(); - constexpr auto nx_no_boundry = nx - 2; - constexpr auto ny_no_boundry = ny - 2; - constexpr auto expected_total = (nx_no_boundry * ny_no_boundry) + (nx * ny) - + (nx_no_boundry * ny_no_boundry * nz) + (nx * ny * nz); + constexpr auto globalmesh_nx_no_boundry = SolverTest::nx - 2; + constexpr auto globalmesh_ny_no_boundry = SolverTest::ny - 2; + constexpr auto localmesh_nx_no_boundry = localmesh_nx - 2; + constexpr auto localmesh_ny_no_boundry = localmesh_ny - 2; + constexpr auto expected_total = + (globalmesh_nx_no_boundry * globalmesh_ny_no_boundry) + + (localmesh_nx * localmesh_ny) + + (localmesh_nx_no_boundry * localmesh_ny_no_boundry * localmesh_nz) + + (nx * ny * nz); EXPECT_EQ(solver.getLocalNHelper(), expected_total); } From 29694c36bbabe75ce248d0ffc83bd3235e6bc9a1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Mar 2019 17:56:07 +0000 Subject: [PATCH 1206/1783] Add some more unit tests for Solver Currently, in order to test the add/remove monitor functions are working correctly, this requires adding some protected functions to get the list of monitors (and timestep monitors) Could possibly remove them after testing call_monitors --- include/bout/solver.hxx | 7 ++ tests/unit/solver/test_solver.cxx | 178 ++++++++++++++++++++++++++++-- 2 files changed, 177 insertions(+), 8 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 59120c4b38..a00f4a1d4e 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -400,6 +400,13 @@ protected: /// Maximum internal timestep BoutReal max_dt{-1.0}; + /// Get the list of monitors + auto getMonitors() const -> const std::list& { return monitors; } + /// Get the list of timestep monitors + auto getTimestepMonitors() const -> const std::list& { + return timestep_monitors; + } + private: /// Number of calls to the RHS function int rhs_ncalls{0}; diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx index c5df252060..ff66143305 100644 --- a/tests/unit/solver/test_solver.cxx +++ b/tests/unit/solver/test_solver.cxx @@ -8,15 +8,13 @@ #include "bout/solverfactory.hxx" #include -#include #include +#include namespace { class FakeSolver : public Solver { public: - FakeSolver(Options* options) : Solver(options) { - has_constraints = true; - } + FakeSolver(Options* options) : Solver(options) { has_constraints = true; } ~FakeSolver() = default; int run() { return (*options)["number"].withDefault(42); } @@ -50,10 +48,33 @@ class FakeSolver : public Solver { return result; } - int getLocalNHelper() { return getLocalN(); } + // Shims for protected functions + auto getMaxTimestepShim() const -> BoutReal { return max_dt; } + auto getLocalNShim() -> int { return getLocalN(); } + auto haveUserPreconShim() -> bool { return have_user_precon(); } + auto runPreconShim(BoutReal t, BoutReal gamma, BoutReal delta) -> int { + return run_precon(t, gamma, delta); + } + auto globalIndexShim(int local_start) -> Field3D { return globalIndex(local_start); } + auto getMonitorsShim() const -> const std::list& { return getMonitors(); } + auto getTimestepMonitorsShim() const -> const std::list& { + return getTimestepMonitors(); + } }; RegisterSolver register_fake("fake_solver"); + +class FakeMonitor : public Monitor { +public: + FakeMonitor(BoutReal timestep = -1) : Monitor(timestep) {} + ~FakeMonitor() = default; + auto call(Solver*, BoutReal time, int iter, int nout) -> int { + return static_cast(time + iter + nout); + } + auto getTimestepShim() -> BoutReal { return getTimestep(); } + auto setTimestepShim(BoutReal timestep) -> void { setTimestep(timestep); } +}; + } // namespace class SolverTest : public FakeMeshFixture { @@ -502,7 +523,7 @@ TEST_F(SolverTest, SplitOperator) { EXPECT_FALSE(solver.splitOperator()); - rhsfunc fake_rhs = [](BoutReal) -> int { return 0;}; + rhsfunc fake_rhs = [](BoutReal) -> int { return 0; }; solver.setSplitOperator(fake_rhs, fake_rhs); EXPECT_TRUE(solver.splitOperator()); @@ -519,7 +540,9 @@ TEST_F(SolverTest, SetMaxTimestep) { Options options; FakeSolver solver{&options}; - EXPECT_NO_THROW(solver.setMaxTimestep(4.5)); + auto expected = 4.5; + EXPECT_NO_THROW(solver.setMaxTimestep(expected)); + EXPECT_EQ(solver.getMaxTimestepShim(), expected); } TEST_F(SolverTest, GetCurrentTimestep) { @@ -554,6 +577,7 @@ TEST_F(SolverTest, GetLocalN) { FakeMesh localmesh{localmesh_nx, localmesh_ny, localmesh_nz}; localmesh.createDefaultRegions(); localmesh.createBoundaryRegions(); + localmesh.setCoordinates(nullptr); Field2D field1{bout::globals::mesh}; Field2D field2{&localmesh}; @@ -579,5 +603,143 @@ TEST_F(SolverTest, GetLocalN) { + (localmesh_nx_no_boundry * localmesh_ny_no_boundry * localmesh_nz) + (nx * ny * nz); - EXPECT_EQ(solver.getLocalNHelper(), expected_total); + EXPECT_EQ(solver.getLocalNShim(), expected_total); +} + +TEST_F(SolverTest, HavePreconditioner) { + PhysicsPrecon preconditioner = [](BoutReal time, BoutReal gamma, + BoutReal delta) -> int { + return static_cast(time + gamma + delta); + }; + + Options options; + FakeSolver solver{&options}; + + EXPECT_FALSE(solver.haveUserPreconShim()); + + solver.setPrecon(preconditioner); + + EXPECT_TRUE(solver.haveUserPreconShim()); +} + +TEST_F(SolverTest, RunPreconditioner) { + PhysicsPrecon preconditioner = [](BoutReal time, BoutReal gamma, + BoutReal delta) -> int { + return static_cast(time + gamma + delta); + }; + + Options options; + FakeSolver solver{&options}; + + solver.setPrecon(preconditioner); + + constexpr auto time = 1.0; + constexpr auto gamma = 2.0; + constexpr auto delta = 3.0; + constexpr auto expected = time + gamma + delta; + + EXPECT_EQ(solver.runPreconShim(time, gamma, delta), expected); } + +TEST_F(SolverTest, AddMonitor) { + Options options; + FakeSolver solver{&options}; + + FakeMonitor monitor; + EXPECT_NO_THROW(monitor.setTimestepShim(10.0)); + EXPECT_EQ(monitor.getTimestepShim(), 10.0); + + EXPECT_NO_THROW(solver.addMonitor(&monitor)); + + EXPECT_THROW(monitor.setTimestepShim(20.0), BoutException); + + std::list expected{&monitor}; + + EXPECT_EQ(solver.getMonitorsShim(), expected); +} + +TEST_F(SolverTest, AddMonitorFront) { + Options options; + FakeSolver solver{&options}; + + FakeMonitor monitor1; + FakeMonitor monitor2; + EXPECT_NO_THROW(solver.addMonitor(&monitor1, Solver::FRONT)); + EXPECT_NO_THROW(solver.addMonitor(&monitor2, Solver::FRONT)); + + std::list expected{&monitor2, &monitor1}; + + EXPECT_EQ(solver.getMonitorsShim(), expected); +} + +TEST_F(SolverTest, AddMonitorBack) { + Options options; + FakeSolver solver{&options}; + + FakeMonitor monitor1; + FakeMonitor monitor2; + EXPECT_NO_THROW(solver.addMonitor(&monitor1, Solver::BACK)); + EXPECT_NO_THROW(solver.addMonitor(&monitor2, Solver::BACK)); + + std::list expected{&monitor1, &monitor2}; + + EXPECT_EQ(solver.getMonitorsShim(), expected); +} + +TEST_F(SolverTest, RemoveMonitor) { + Options options; + FakeSolver solver{&options}; + + FakeMonitor monitor1; + FakeMonitor monitor2; + EXPECT_NO_THROW(solver.addMonitor(&monitor1, Solver::BACK)); + EXPECT_NO_THROW(solver.addMonitor(&monitor2, Solver::BACK)); + + solver.removeMonitor(&monitor1); + + std::list expected{&monitor2}; + EXPECT_EQ(solver.getMonitorsShim(), expected); + + // Removing same monitor again should be a no-op + solver.removeMonitor(&monitor1); + EXPECT_EQ(solver.getMonitorsShim(), expected); +} + +TEST_F(SolverTest, AddTimestepMonitor) { + Options options; + FakeSolver solver{&options}; + + TimestepMonitorFunc monitor1 = [](Solver*, BoutReal simtime, BoutReal lastdt) -> int { + return static_cast(simtime + lastdt);}; + TimestepMonitorFunc monitor2 = [](Solver*, BoutReal simtime, BoutReal lastdt) -> int { + return static_cast(simtime * lastdt);}; + + EXPECT_NO_THROW(solver.addTimestepMonitor(monitor1)); + EXPECT_NO_THROW(solver.addTimestepMonitor(monitor2)); + + std::list expected{monitor2, monitor1}; + + EXPECT_EQ(solver.getTimestepMonitorsShim(), expected); +} + +TEST_F(SolverTest, RemoveTimestepMonitor) { + Options options; + FakeSolver solver{&options}; + + TimestepMonitorFunc monitor1 = [](Solver*, BoutReal simtime, BoutReal lastdt) -> int { + return static_cast(simtime + lastdt);}; + TimestepMonitorFunc monitor2 = [](Solver*, BoutReal simtime, BoutReal lastdt) -> int { + return static_cast(simtime * lastdt);}; + + EXPECT_NO_THROW(solver.addTimestepMonitor(monitor1)); + EXPECT_NO_THROW(solver.addTimestepMonitor(monitor2)); + + solver.removeTimestepMonitor(monitor1); + std::list expected{monitor2}; + + EXPECT_EQ(solver.getTimestepMonitorsShim(), expected); + + solver.removeTimestepMonitor(monitor1); + EXPECT_EQ(solver.getTimestepMonitorsShim(), expected); +} + From 7cc23a928105804cf61d8856d42c4633d4cd2bb6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 28 Mar 2019 18:02:57 +0000 Subject: [PATCH 1207/1783] Remove duplicated variable Solver::initCalled is identical to Solver::initialised --- include/bout/solver.hxx | 2 -- src/solver/solver.cxx | 5 ++--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index a00f4a1d4e..83f4d24bcb 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -414,8 +414,6 @@ private: int rhs_ncalls_e{0}; /// Number of calls to the implicit (diffusive) RHS function int rhs_ncalls_i{0}; - /// Has the init function of the solver been called? - bool initCalled{false}; /// Default sampling rate at which to call monitors - same as output to screen int freqDefault{1}; /// timestep - shouldn't be changed after init is called. diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 47ed3ce452..5b0012f65c 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -486,7 +486,6 @@ int Solver::solve(int NOUT, BoutReal TIMESTEP) { if (init(NOUT, TIMESTEP)) { throw BoutException(_("Failed to initialise solver-> Aborting\n")); } - initCalled=true; /// Run the solver output_info.write(_("Running simulation\n\n")); @@ -596,7 +595,7 @@ void Solver::outputVars(Datafile &outputfile, bool save_repeat) { /// as the timestep cannot be changed afterwards void Solver::addMonitor(Monitor * mon, MonitorPosition pos) { if (mon->timestep > 0){ // not default - if (!initCalled && timestep < 0){ + if (!initialised && timestep < 0) { timestep = mon->timestep; } if (!isMultiple(timestep,mon->timestep)) @@ -605,7 +604,7 @@ void Solver::addMonitor(Monitor * mon, MonitorPosition pos) { if (mon->timestep > timestep*1.5){ mon->freq=(mon->timestep/timestep)+.5; } else { // mon.timestep is truly smaller - if (initCalled) + if (initialised) throw BoutException(_("Solver::addMonitor: Cannot reduce timestep \ (from %g to %g) after init is called!") ,timestep,mon->timestep); From a527418d4ac1b85811a76d5b6f381e9bed956260 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 29 Mar 2019 14:50:22 +0000 Subject: [PATCH 1208/1783] Remove `inline` SolverFactory::getDefaultSolverType Also add docstring --- include/bout/solverfactory.hxx | 1 + src/solver/solverfactory.cxx | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/bout/solverfactory.hxx b/include/bout/solverfactory.hxx index 58a763fd68..c805bfe48d 100644 --- a/include/bout/solverfactory.hxx +++ b/include/bout/solverfactory.hxx @@ -22,6 +22,7 @@ class Options; /// std::function>; class SolverFactory : public Factory> { public: + /// Return the name of the default Solver type static SolverType getDefaultSolverType(); static SolverFactory* getInstance(); diff --git a/src/solver/solverfactory.cxx b/src/solver/solverfactory.cxx index f80b7a1aec..6852b42e92 100644 --- a/src/solver/solverfactory.cxx +++ b/src/solver/solverfactory.cxx @@ -25,8 +25,8 @@ SolverFactory* SolverFactory::getInstance() { return instance; } -inline SolverType SolverFactory::getDefaultSolverType() { - SolverType type = +SolverType SolverFactory::getDefaultSolverType() { + return #if defined BOUT_HAS_CVODE SOLVERCVODE; #elif defined BOUT_HAS_IDA @@ -34,8 +34,6 @@ inline SolverType SolverFactory::getDefaultSolverType() { #else SOLVERPVODE; #endif - - return type; } Solver* SolverFactory::createSolver(Options* options) { From 10618c3b7e7df00ddb14488de740dee099225598 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 29 Mar 2019 15:03:47 +0000 Subject: [PATCH 1209/1783] Expand unit tests for Solver::addMonitor: check frequencies Requires some new (hopefully temporary) protected functions in Solver to get the frequencies and timesteps of the monitors Pulls out some of the addMonitor logic to make it more readable Also give default values to the Monitor members --- include/bout/monitor.hxx | 10 ++-- include/bout/solver.hxx | 18 +++++++ src/solver/solver.cxx | 89 +++++++++++++++++++------------ tests/unit/solver/test_solver.cxx | 53 ++++++++++++++++-- 4 files changed, 127 insertions(+), 43 deletions(-) diff --git a/include/bout/monitor.hxx b/include/bout/monitor.hxx index 107f5cb043..98d7f0aae1 100644 --- a/include/bout/monitor.hxx +++ b/include/bout/monitor.hxx @@ -66,10 +66,12 @@ protected: } private: - bool is_added = false; ///< Set to true when Monitor is added to a Solver - BoutReal timestep; - int freq; - + /// Set to true when Monitor is added to a Solver + bool is_added{false}; + /// The desired physical timestep + BoutReal timestep{-1}; + /// How often this monitor should be called, in internal Solver steps + int freq{1}; }; struct RunMetrics { diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 83f4d24bcb..3c215b54ed 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -406,6 +406,20 @@ protected: auto getTimestepMonitors() const -> const std::list& { return timestep_monitors; } + /// Get a list of the iteration frequencies of monitors + auto getMonitorFrequencies() const -> std::vector { + std::vector frequencies{}; + std::transform(begin(monitors), end(monitors), back_inserter(frequencies), + [](const Monitor* monitor) { return monitor->freq; }); + return frequencies; + } + /// Get a list of the physical timesteps of monitors + auto getMonitorTimesteps() const -> std::vector { + std::vector timesteps{}; + std::transform(begin(monitors), end(monitors), back_inserter(timesteps), + [](const Monitor* monitor) { return monitor->timestep; }); + return timesteps; + } private: /// Number of calls to the RHS function @@ -457,6 +471,10 @@ private: /// Check if a variable has already been added bool varAdded(const std::string& name); + + /// (Possibly) adjust the frequencies of \p monitor, and the + /// `monitors` timesteps, returning the new Solver timestep + BoutReal adjustMonitorFrequencies(Monitor* monitor); }; #endif // __SOLVER_H__ diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 5b0012f65c..31a624642e 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -590,43 +590,64 @@ void Solver::outputVars(Datafile &outputfile, bool save_repeat) { ///////////////////////////////////////////////////// -/// Method to add a Monitor to the Solver -/// Note that behaviour changes if init() is called, -/// as the timestep cannot be changed afterwards -void Solver::addMonitor(Monitor * mon, MonitorPosition pos) { - if (mon->timestep > 0){ // not default - if (!initialised && timestep < 0) { - timestep = mon->timestep; - } - if (!isMultiple(timestep,mon->timestep)) - throw BoutException(_("Couldn't add Monitor: %g is not a multiple of %g!") - ,timestep,mon->timestep); - if (mon->timestep > timestep*1.5){ - mon->freq=(mon->timestep/timestep)+.5; - } else { // mon.timestep is truly smaller - if (initialised) - throw BoutException(_("Solver::addMonitor: Cannot reduce timestep \ -(from %g to %g) after init is called!") - ,timestep,mon->timestep); - int multi = timestep/mon->timestep+.5; - timestep=mon->timestep; - for (const auto &i: monitors){ - i->freq=i->freq*multi; - } - // update freqDefault so that monitors with no timestep are called at the - // output frequency - freqDefault *= multi; +BoutReal Solver::adjustMonitorFrequencies(Monitor* new_monitor) { - mon->freq=1; - } + if (new_monitor->timestep < 0) { + // The timestep will get adjusted when we call solve + new_monitor->freq = freqDefault; + return timestep; + } + + if (!initialised && timestep < 0) { + // This is the first monitor to be added + return new_monitor->timestep; + } + + if (!isMultiple(timestep, new_monitor->timestep)) { + throw BoutException(_("Couldn't add Monitor: %g is not a multiple of %g!"), timestep, + new_monitor->timestep); + } + + if (new_monitor->timestep > timestep * 1.5) { + // Monitor has a larger timestep + new_monitor->freq = (new_monitor->timestep / timestep) + .5; + return timestep; + } + + // Monitor timestep is smaller, so we need to adjust our timestep, + // along with that of all of the other monitors + + if (initialised) { + throw BoutException(_("Solver::addMonitor: Cannot reduce timestep (from %g to %g) " + "after init is called!"), + timestep, new_monitor->timestep); + } + + // This is the relative increase in timestep + const int multiplier = timestep / new_monitor->timestep + .5; + for (const auto& monitor : monitors) { + monitor->freq *= multiplier; + } + + // Update default_monitor_frequency so that monitors with no + // timestep are called at the output frequency + freqDefault *= multiplier; + + // This monitor is now the fastest monitor + return new_monitor->timestep; +} + +void Solver::addMonitor(Monitor* monitor, MonitorPosition pos) { + + timestep = adjustMonitorFrequencies(monitor); + + monitor->is_added = true; + + if (pos == Solver::FRONT) { + monitors.push_front(monitor); } else { - mon->freq = freqDefault; + monitors.push_back(monitor); } - mon->is_added = true; // Records that monitor has been added to solver so timestep should not be updated - if(pos == Solver::FRONT) { - monitors.push_front(mon); - }else - monitors.push_back(mon); } void Solver::removeMonitor(Monitor * f) { diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx index ff66143305..1febffd382 100644 --- a/tests/unit/solver/test_solver.cxx +++ b/tests/unit/solver/test_solver.cxx @@ -60,6 +60,12 @@ class FakeSolver : public Solver { auto getTimestepMonitorsShim() const -> const std::list& { return getTimestepMonitors(); } + auto getMonitorFrequenciesShim() const -> std::vector { + return getMonitorFrequencies(); + } + auto getMonitorTimestepsShim() const -> std::vector { + return getMonitorTimesteps(); + } }; RegisterSolver register_fake("fake_solver"); @@ -686,6 +692,40 @@ TEST_F(SolverTest, AddMonitorBack) { EXPECT_EQ(solver.getMonitorsShim(), expected); } +TEST_F(SolverTest, AddMonitorCheckFrequencies) { + Options options; + FakeSolver solver{&options}; + + FakeMonitor default_timestep; + FakeMonitor smaller_timestep{0.01}; + FakeMonitor larger_timestep{2.}; + FakeMonitor incompatible_timestep{3.14259}; + + EXPECT_NO_THROW(solver.addMonitor(&default_timestep)); + EXPECT_NO_THROW(solver.addMonitor(&smaller_timestep)); + EXPECT_NO_THROW(solver.addMonitor(&larger_timestep)); + EXPECT_THROW(solver.addMonitor(&incompatible_timestep), BoutException); + + std::vector expected_frequencies{200, 1, 1}; + std::vector expected_timesteps{2., 0.01, -1}; + + EXPECT_EQ(solver.getMonitorFrequenciesShim(), expected_frequencies); + EXPECT_EQ(solver.getMonitorTimestepsShim(), expected_timesteps); + + solver.init(0, 0); + + FakeMonitor too_small_postinit_timestep{0.001}; + EXPECT_THROW(solver.addMonitor(&too_small_postinit_timestep), BoutException); + FakeMonitor larger_postinit_timestep{4.}; + EXPECT_NO_THROW(solver.addMonitor(&larger_postinit_timestep, Solver::BACK)); + + expected_frequencies.push_back(400); + expected_timesteps.push_back(4.); + + EXPECT_EQ(solver.getMonitorFrequenciesShim(), expected_frequencies); + EXPECT_EQ(solver.getMonitorTimestepsShim(), expected_timesteps); +} + TEST_F(SolverTest, RemoveMonitor) { Options options; FakeSolver solver{&options}; @@ -710,9 +750,11 @@ TEST_F(SolverTest, AddTimestepMonitor) { FakeSolver solver{&options}; TimestepMonitorFunc monitor1 = [](Solver*, BoutReal simtime, BoutReal lastdt) -> int { - return static_cast(simtime + lastdt);}; + return static_cast(simtime + lastdt); + }; TimestepMonitorFunc monitor2 = [](Solver*, BoutReal simtime, BoutReal lastdt) -> int { - return static_cast(simtime * lastdt);}; + return static_cast(simtime * lastdt); + }; EXPECT_NO_THROW(solver.addTimestepMonitor(monitor1)); EXPECT_NO_THROW(solver.addTimestepMonitor(monitor2)); @@ -727,9 +769,11 @@ TEST_F(SolverTest, RemoveTimestepMonitor) { FakeSolver solver{&options}; TimestepMonitorFunc monitor1 = [](Solver*, BoutReal simtime, BoutReal lastdt) -> int { - return static_cast(simtime + lastdt);}; + return static_cast(simtime + lastdt); + }; TimestepMonitorFunc monitor2 = [](Solver*, BoutReal simtime, BoutReal lastdt) -> int { - return static_cast(simtime * lastdt);}; + return static_cast(simtime * lastdt); + }; EXPECT_NO_THROW(solver.addTimestepMonitor(monitor1)); EXPECT_NO_THROW(solver.addTimestepMonitor(monitor2)); @@ -742,4 +786,3 @@ TEST_F(SolverTest, RemoveTimestepMonitor) { solver.removeTimestepMonitor(monitor1); EXPECT_EQ(solver.getTimestepMonitorsShim(), expected); } - From 66c14486aebe7199d4e0f4752ed53c11d0dfa2e0 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 29 Mar 2019 15:07:04 +0000 Subject: [PATCH 1210/1783] Rename some Monitor/Solver members for readability --- include/bout/monitor.hxx | 10 +++++----- include/bout/solver.hxx | 26 +++++++++++++++++++------- src/solver/solver.cxx | 28 ++++++++++++++-------------- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/include/bout/monitor.hxx b/include/bout/monitor.hxx index 98d7f0aae1..7cacf41fd7 100644 --- a/include/bout/monitor.hxx +++ b/include/bout/monitor.hxx @@ -33,9 +33,9 @@ class Monitor{ public: /// A \p timestep_ of -1 defaults to the the frequency of the BOUT++ /// output monitor - Monitor(BoutReal timestep_ = -1) : timestep(timestep_){}; + Monitor(BoutReal timestep_ = -1) : timestep(timestep_) {}; - virtual ~Monitor(){}; + virtual ~Monitor() = default; /// Callback function for the solver, called after timestep_ has passed /// @@ -45,7 +45,7 @@ public: /// @param[in] nout The total number of iterations for this simulation /// /// @returns non-zero if simulation should be stopped - virtual int call(Solver *solver, BoutReal time, int iter, int nout) = 0; + virtual int call(Solver* solver, BoutReal time, int iter, int nout) = 0; /// Callback function for when a clean shutdown is initiated virtual void cleanup(){}; @@ -60,7 +60,7 @@ protected: void setTimestep(BoutReal new_timestep) { if (is_added) { throw BoutException("Monitor::set_timestep - Error: Monitor has already" - "been added to a Solver, so timestep cannot be changed."); + "been added to a Solver, so timestep cannot be changed."); } timestep = new_timestep; } @@ -71,7 +71,7 @@ private: /// The desired physical timestep BoutReal timestep{-1}; /// How often this monitor should be called, in internal Solver steps - int freq{1}; + int frequency{1}; }; struct RunMetrics { diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 3c215b54ed..2b8fc0e0d4 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -198,15 +198,27 @@ public: /// A type to set where in the list monitors are added enum MonitorPosition { BACK, FRONT }; - /// Add a monitor to be called every output - void addMonitor(Monitor* f, MonitorPosition pos = FRONT); + /// Add a \p monitor to be called regularly + /// + /// The frequency at which the \p monitor is called is set by + /// `Monitor::timestep`. By default this is every output + /// timestep. When a new Monitor with a smaller timestep is added, + /// the solver attemps to adjust its internal timestep to match, as + /// well as adjusting the timesteps of the current set of Monitors + /// to be multiples of the new timestep. If this is not possible, + /// `addMonitor` will throw an exception. + /// + /// Adding new Monitors after the Solver has been initialised is + /// only possible if their timestep is a multiple of the Solver's + /// timestep. Smaller timesteps will throw an exception. + void addMonitor(Monitor* monitor, MonitorPosition pos = FRONT); /// Remove a monitor function previously added - void removeMonitor(Monitor* f); + void removeMonitor(Monitor* monitor); /// Add a monitor function to be called every timestep - void addTimestepMonitor(TimestepMonitorFunc f); + void addTimestepMonitor(TimestepMonitorFunc monitor); /// Remove a previously added timestep monitor - void removeTimestepMonitor(TimestepMonitorFunc f); + void removeTimestepMonitor(TimestepMonitorFunc monitor); ///////////////////////////////////////////// // Routines to add variables. Solvers can just call these @@ -410,7 +422,7 @@ protected: auto getMonitorFrequencies() const -> std::vector { std::vector frequencies{}; std::transform(begin(monitors), end(monitors), back_inserter(frequencies), - [](const Monitor* monitor) { return monitor->freq; }); + [](const Monitor* monitor) { return monitor->frequency; }); return frequencies; } /// Get a list of the physical timesteps of monitors @@ -429,7 +441,7 @@ private: /// Number of calls to the implicit (diffusive) RHS function int rhs_ncalls_i{0}; /// Default sampling rate at which to call monitors - same as output to screen - int freqDefault{1}; + int default_monitor_frequency{1}; /// timestep - shouldn't be changed after init is called. BoutReal timestep{-1}; /// Physics model being evolved diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 31a624642e..0a53872981 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -457,30 +457,30 @@ int Solver::solve(int NOUT, BoutReal TIMESTEP) { throw BoutException("A monitor requested a timestep not compatible with the output_step!"); } if (timestep < TIMESTEP*1.5){ - freqDefault=TIMESTEP/timestep+.5; - NOUT*=freqDefault; + default_monitor_frequency=TIMESTEP/timestep+.5; + NOUT*=default_monitor_frequency; TIMESTEP=timestep; } else { - freqDefault = 1; + default_monitor_frequency = 1; // update old monitors int fac=timestep/TIMESTEP+.5; for (const auto &i: monitors){ - i->freq=i->freq*fac; + i->frequency=i->frequency*fac; } } } for (const auto &i: monitors){ if (i->timestep < 0){ - i->timestep=timestep*freqDefault; - i->freq=freqDefault; + i->timestep=timestep*default_monitor_frequency; + i->frequency=default_monitor_frequency; } } output_progress.write(_("Solver running for %d outputs with output timestep of %e\n"), NOUT, TIMESTEP); - if (freqDefault > 1) + if (default_monitor_frequency > 1) output_progress.write(_("Solver running for %d outputs with monitor timestep of %e\n"), - NOUT/freqDefault, TIMESTEP*freqDefault); + NOUT/default_monitor_frequency, TIMESTEP*default_monitor_frequency); // Initialise if (init(NOUT, TIMESTEP)) { @@ -594,7 +594,7 @@ BoutReal Solver::adjustMonitorFrequencies(Monitor* new_monitor) { if (new_monitor->timestep < 0) { // The timestep will get adjusted when we call solve - new_monitor->freq = freqDefault; + new_monitor->frequency = default_monitor_frequency; return timestep; } @@ -610,7 +610,7 @@ BoutReal Solver::adjustMonitorFrequencies(Monitor* new_monitor) { if (new_monitor->timestep > timestep * 1.5) { // Monitor has a larger timestep - new_monitor->freq = (new_monitor->timestep / timestep) + .5; + new_monitor->frequency = (new_monitor->timestep / timestep) + .5; return timestep; } @@ -626,12 +626,12 @@ BoutReal Solver::adjustMonitorFrequencies(Monitor* new_monitor) { // This is the relative increase in timestep const int multiplier = timestep / new_monitor->timestep + .5; for (const auto& monitor : monitors) { - monitor->freq *= multiplier; + monitor->frequency *= multiplier; } // Update default_monitor_frequency so that monitors with no // timestep are called at the output frequency - freqDefault *= multiplier; + default_monitor_frequency *= multiplier; // This monitor is now the fastest monitor return new_monitor->timestep; @@ -670,9 +670,9 @@ int Solver::call_monitors(BoutReal simtime, int iter, int NOUT) { try { // Call monitors for (const auto &it : monitors){ - if ((iter % it->freq)==0){ + if ((iter % it->frequency)==0){ // Call each monitor one by one - int ret = it->call(this, simtime,iter/it->freq-1, NOUT/it->freq); + int ret = it->call(this, simtime,iter/it->frequency-1, NOUT/it->frequency); if(ret) throw BoutException(_("Monitor signalled to quit")); } From 5f952ed3af52737f24c52933a2955698a5950503 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 29 Mar 2019 15:29:18 +0000 Subject: [PATCH 1211/1783] Rewrite timestep monitor tests in terms of call_timestep_monitors --- include/bout/solver.hxx | 4 -- src/solver/solver.cxx | 21 +++++----- tests/unit/solver/test_solver.cxx | 69 ++++++++++++++++++------------- 3 files changed, 51 insertions(+), 43 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 2b8fc0e0d4..84ab819e3c 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -414,10 +414,6 @@ protected: /// Get the list of monitors auto getMonitors() const -> const std::list& { return monitors; } - /// Get the list of timestep monitors - auto getTimestepMonitors() const -> const std::list& { - return timestep_monitors; - } /// Get a list of the iteration frequencies of monitors auto getMonitorFrequencies() const -> std::vector { std::vector frequencies{}; diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 0a53872981..e5ba502285 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -731,21 +731,20 @@ void Solver::removeTimestepMonitor(TimestepMonitorFunc f) { } int Solver::call_timestep_monitors(BoutReal simtime, BoutReal lastdt) { - if(!monitor_timestep) + if (!monitor_timestep) return 0; - - for(const auto& monitor : timestep_monitors) { - // Call each monitor one by one - int ret = monitor(this, simtime, lastdt); - if(ret) + + for (const auto& monitor : timestep_monitors) { + const int ret = monitor(this, simtime, lastdt); + if (ret != 0) return ret; // Return first time an error is encountered } - + // Call physics model monitor - if(model) { - int ret = model->runTimestepMonitor(simtime, lastdt); - if(ret) - return ret; // Return first time an error is encountered + if (model != nullptr) { + const int ret = model->runTimestepMonitor(simtime, lastdt); + if (ret) + return ret; } return 0; } diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx index 1febffd382..cc9d3e8c5e 100644 --- a/tests/unit/solver/test_solver.cxx +++ b/tests/unit/solver/test_solver.cxx @@ -57,15 +57,15 @@ class FakeSolver : public Solver { } auto globalIndexShim(int local_start) -> Field3D { return globalIndex(local_start); } auto getMonitorsShim() const -> const std::list& { return getMonitors(); } - auto getTimestepMonitorsShim() const -> const std::list& { - return getTimestepMonitors(); - } auto getMonitorFrequenciesShim() const -> std::vector { return getMonitorFrequencies(); } auto getMonitorTimestepsShim() const -> std::vector { return getMonitorTimesteps(); } + auto callTimestepMonitorsShim(BoutReal simtime, BoutReal lastdt) -> int { + return call_timestep_monitors(simtime, lastdt); + } }; RegisterSolver register_fake("fake_solver"); @@ -745,44 +745,57 @@ TEST_F(SolverTest, RemoveMonitor) { EXPECT_EQ(solver.getMonitorsShim(), expected); } +namespace { +auto timestep_monitor1(Solver*, BoutReal simtime, BoutReal lastdt) -> int { + return simtime * lastdt < 0. ? 1 : 0; +} +auto timestep_monitor2(Solver*, BoutReal simtime, BoutReal lastdt) -> int { + return simtime + lastdt < 0. ? 2 : 0; +} +} // namespace + TEST_F(SolverTest, AddTimestepMonitor) { Options options; + options["monitor_timestep"] = true; FakeSolver solver{&options}; - TimestepMonitorFunc monitor1 = [](Solver*, BoutReal simtime, BoutReal lastdt) -> int { - return static_cast(simtime + lastdt); - }; - TimestepMonitorFunc monitor2 = [](Solver*, BoutReal simtime, BoutReal lastdt) -> int { - return static_cast(simtime * lastdt); - }; - - EXPECT_NO_THROW(solver.addTimestepMonitor(monitor1)); - EXPECT_NO_THROW(solver.addTimestepMonitor(monitor2)); + EXPECT_NO_THROW(solver.addTimestepMonitor(timestep_monitor1)); + EXPECT_NO_THROW(solver.addTimestepMonitor(timestep_monitor2)); - std::list expected{monitor2, monitor1}; - - EXPECT_EQ(solver.getTimestepMonitorsShim(), expected); + EXPECT_EQ(solver.callTimestepMonitorsShim(1., 1.), 0); + EXPECT_EQ(solver.callTimestepMonitorsShim(1., -1.), 1); + EXPECT_EQ(solver.callTimestepMonitorsShim(-1., -1.), 2); } TEST_F(SolverTest, RemoveTimestepMonitor) { Options options; + options["monitor_timestep"] = true; FakeSolver solver{&options}; - TimestepMonitorFunc monitor1 = [](Solver*, BoutReal simtime, BoutReal lastdt) -> int { - return static_cast(simtime + lastdt); - }; - TimestepMonitorFunc monitor2 = [](Solver*, BoutReal simtime, BoutReal lastdt) -> int { - return static_cast(simtime * lastdt); - }; + EXPECT_NO_THROW(solver.addTimestepMonitor(timestep_monitor1)); + EXPECT_NO_THROW(solver.addTimestepMonitor(timestep_monitor2)); + + solver.removeTimestepMonitor(timestep_monitor1); + + EXPECT_EQ(solver.callTimestepMonitorsShim(1., 1.), 0); + EXPECT_EQ(solver.callTimestepMonitorsShim(1., -1.), 0); + EXPECT_EQ(solver.callTimestepMonitorsShim(-1., -1.), 2); - EXPECT_NO_THROW(solver.addTimestepMonitor(monitor1)); - EXPECT_NO_THROW(solver.addTimestepMonitor(monitor2)); + solver.removeTimestepMonitor(timestep_monitor1); - solver.removeTimestepMonitor(monitor1); - std::list expected{monitor2}; + EXPECT_EQ(solver.callTimestepMonitorsShim(1., 1.), 0); + EXPECT_EQ(solver.callTimestepMonitorsShim(1., -1.), 0); + EXPECT_EQ(solver.callTimestepMonitorsShim(-1., -1.), 2); +} + +TEST_F(SolverTest, DontCallTimestepMonitors) { + Options options; + FakeSolver solver{&options}; - EXPECT_EQ(solver.getTimestepMonitorsShim(), expected); + EXPECT_NO_THROW(solver.addTimestepMonitor(timestep_monitor1)); + EXPECT_NO_THROW(solver.addTimestepMonitor(timestep_monitor2)); - solver.removeTimestepMonitor(monitor1); - EXPECT_EQ(solver.getTimestepMonitorsShim(), expected); + EXPECT_EQ(solver.callTimestepMonitorsShim(1., 1.), 0); + EXPECT_EQ(solver.callTimestepMonitorsShim(1., -1.), 0); + EXPECT_EQ(solver.callTimestepMonitorsShim(-1., -1.), 0); } From 1346f25de09f9fe514e37b0286177d23b7b2f0ac Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Apr 2019 15:55:36 +0100 Subject: [PATCH 1212/1783] Rewrite Solver monitor tests in terms of call_monitors --- include/bout/solver.hxx | 14 ---- tests/unit/solver/test_solver.cxx | 130 ++++++++++++++++++++++++------ 2 files changed, 107 insertions(+), 37 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 84ab819e3c..727540d159 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -414,20 +414,6 @@ protected: /// Get the list of monitors auto getMonitors() const -> const std::list& { return monitors; } - /// Get a list of the iteration frequencies of monitors - auto getMonitorFrequencies() const -> std::vector { - std::vector frequencies{}; - std::transform(begin(monitors), end(monitors), back_inserter(frequencies), - [](const Monitor* monitor) { return monitor->frequency; }); - return frequencies; - } - /// Get a list of the physical timesteps of monitors - auto getMonitorTimesteps() const -> std::vector { - std::vector timesteps{}; - std::transform(begin(monitors), end(monitors), back_inserter(timesteps), - [](const Monitor* monitor) { return monitor->timestep; }); - return timesteps; - } private: /// Number of calls to the RHS function diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx index cc9d3e8c5e..c83bb9e56b 100644 --- a/tests/unit/solver/test_solver.cxx +++ b/tests/unit/solver/test_solver.cxx @@ -57,11 +57,8 @@ class FakeSolver : public Solver { } auto globalIndexShim(int local_start) -> Field3D { return globalIndex(local_start); } auto getMonitorsShim() const -> const std::list& { return getMonitors(); } - auto getMonitorFrequenciesShim() const -> std::vector { - return getMonitorFrequencies(); - } - auto getMonitorTimestepsShim() const -> std::vector { - return getMonitorTimesteps(); + auto callMonitorsShim(BoutReal simtime, int iter, int NOUT) -> int { + return call_monitors(simtime, iter, NOUT); } auto callTimestepMonitorsShim(BoutReal simtime, BoutReal lastdt) -> int { return call_timestep_monitors(simtime, lastdt); @@ -70,15 +67,29 @@ class FakeSolver : public Solver { RegisterSolver register_fake("fake_solver"); +/// A sentinel value for whether a `FakeMonitor` has been called or not +constexpr static int called_sentinel{-999}; + +/// A `Monitor` that returns a bad value when called past its \p +/// trigger_time_ class FakeMonitor : public Monitor { public: - FakeMonitor(BoutReal timestep = -1) : Monitor(timestep) {} + FakeMonitor(BoutReal timestep = -1, BoutReal trigger_time_ = 0.) + : Monitor(timestep), trigger_time(trigger_time_) {} ~FakeMonitor() = default; - auto call(Solver*, BoutReal time, int iter, int nout) -> int { - return static_cast(time + iter + nout); + auto call(Solver*, BoutReal time, int iter, int) -> int { + last_called = iter; + return time > trigger_time ? -1 : 0; } auto getTimestepShim() -> BoutReal { return getTimestep(); } auto setTimestepShim(BoutReal timestep) -> void { setTimestep(timestep); } + void cleanup() { cleaned = true; } + + int last_called{called_sentinel}; + bool cleaned{false}; + +private: + BoutReal trigger_time{0.0}; }; } // namespace @@ -659,12 +670,13 @@ TEST_F(SolverTest, AddMonitor) { EXPECT_THROW(monitor.setTimestepShim(20.0), BoutException); - std::list expected{&monitor}; + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, 0, 0)); - EXPECT_EQ(solver.getMonitorsShim(), expected); + EXPECT_EQ(monitor.last_called, 0); } TEST_F(SolverTest, AddMonitorFront) { + WithQuietOutput quiet{output_error}; Options options; FakeSolver solver{&options}; @@ -673,12 +685,29 @@ TEST_F(SolverTest, AddMonitorFront) { EXPECT_NO_THROW(solver.addMonitor(&monitor1, Solver::FRONT)); EXPECT_NO_THROW(solver.addMonitor(&monitor2, Solver::FRONT)); - std::list expected{&monitor2, &monitor1}; + // Everything's fine + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, 0, 0)); - EXPECT_EQ(solver.getMonitorsShim(), expected); + EXPECT_EQ(monitor1.last_called, 0); + EXPECT_EQ(monitor2.last_called, 0); + + // One monitor signals to quit + EXPECT_THROW(solver.callMonitorsShim(5.0, 1, 0), BoutException); + + EXPECT_EQ(monitor1.last_called, 0); + EXPECT_EQ(monitor2.last_called, 1); + + // Last timestep + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, 9, 10)); + + EXPECT_EQ(monitor1.last_called, 9); + EXPECT_EQ(monitor2.last_called, 9); + EXPECT_TRUE(monitor1.cleaned); + EXPECT_TRUE(monitor2.cleaned); } TEST_F(SolverTest, AddMonitorBack) { + WithQuietOutput quiet{output_error}; Options options; FakeSolver solver{&options}; @@ -687,9 +716,25 @@ TEST_F(SolverTest, AddMonitorBack) { EXPECT_NO_THROW(solver.addMonitor(&monitor1, Solver::BACK)); EXPECT_NO_THROW(solver.addMonitor(&monitor2, Solver::BACK)); - std::list expected{&monitor1, &monitor2}; + // Everything's fine + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, 0, 0)); - EXPECT_EQ(solver.getMonitorsShim(), expected); + EXPECT_EQ(monitor1.last_called, 0); + EXPECT_EQ(monitor2.last_called, 0); + + // One monitor signals to quit + EXPECT_THROW(solver.callMonitorsShim(5.0, 1, 0), BoutException); + + EXPECT_EQ(monitor1.last_called, 1); + EXPECT_EQ(monitor2.last_called, 0); + + // Last timestep + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, 9, 10)); + + EXPECT_EQ(monitor1.last_called, 9); + EXPECT_EQ(monitor2.last_called, 9); + EXPECT_TRUE(monitor1.cleaned); + EXPECT_TRUE(monitor2.cleaned); } TEST_F(SolverTest, AddMonitorCheckFrequencies) { @@ -697,20 +742,56 @@ TEST_F(SolverTest, AddMonitorCheckFrequencies) { FakeSolver solver{&options}; FakeMonitor default_timestep; - FakeMonitor smaller_timestep{0.01}; + FakeMonitor smaller_timestep{0.1}; + FakeMonitor even_smaller_timestep{0.01}; FakeMonitor larger_timestep{2.}; FakeMonitor incompatible_timestep{3.14259}; EXPECT_NO_THROW(solver.addMonitor(&default_timestep)); EXPECT_NO_THROW(solver.addMonitor(&smaller_timestep)); + EXPECT_NO_THROW(solver.addMonitor(&even_smaller_timestep)); EXPECT_NO_THROW(solver.addMonitor(&larger_timestep)); EXPECT_THROW(solver.addMonitor(&incompatible_timestep), BoutException); - std::vector expected_frequencies{200, 1, 1}; - std::vector expected_timesteps{2., 0.01, -1}; + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, -1, 0)); + + EXPECT_EQ(default_timestep.last_called, -1); + EXPECT_EQ(smaller_timestep.last_called, -1); + EXPECT_EQ(even_smaller_timestep.last_called, -1); + EXPECT_EQ(larger_timestep.last_called, -1); + EXPECT_EQ(incompatible_timestep.last_called, called_sentinel); + + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, 9, 0)); + + EXPECT_EQ(default_timestep.last_called, 0); + EXPECT_EQ(smaller_timestep.last_called, 0); + EXPECT_EQ(even_smaller_timestep.last_called, 9); + EXPECT_EQ(larger_timestep.last_called, -1); + EXPECT_EQ(incompatible_timestep.last_called, called_sentinel); + + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, 10, 0)); + + EXPECT_EQ(default_timestep.last_called, 0); + EXPECT_EQ(smaller_timestep.last_called, 0); + EXPECT_EQ(even_smaller_timestep.last_called, 10); + EXPECT_EQ(larger_timestep.last_called, -1); + EXPECT_EQ(incompatible_timestep.last_called, called_sentinel); + + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, 199, 0)); + + EXPECT_EQ(default_timestep.last_called, 19); + EXPECT_EQ(smaller_timestep.last_called, 19); + EXPECT_EQ(even_smaller_timestep.last_called, 199); + EXPECT_EQ(larger_timestep.last_called, 0); + EXPECT_EQ(incompatible_timestep.last_called, called_sentinel); + + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, 399, 0)); - EXPECT_EQ(solver.getMonitorFrequenciesShim(), expected_frequencies); - EXPECT_EQ(solver.getMonitorTimestepsShim(), expected_timesteps); + EXPECT_EQ(default_timestep.last_called, 39); + EXPECT_EQ(smaller_timestep.last_called, 39); + EXPECT_EQ(even_smaller_timestep.last_called, 399); + EXPECT_EQ(larger_timestep.last_called, 1); + EXPECT_EQ(incompatible_timestep.last_called, called_sentinel); solver.init(0, 0); @@ -719,11 +800,14 @@ TEST_F(SolverTest, AddMonitorCheckFrequencies) { FakeMonitor larger_postinit_timestep{4.}; EXPECT_NO_THROW(solver.addMonitor(&larger_postinit_timestep, Solver::BACK)); - expected_frequencies.push_back(400); - expected_timesteps.push_back(4.); + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, 399, 0)); - EXPECT_EQ(solver.getMonitorFrequenciesShim(), expected_frequencies); - EXPECT_EQ(solver.getMonitorTimestepsShim(), expected_timesteps); + EXPECT_EQ(default_timestep.last_called, 39); + EXPECT_EQ(smaller_timestep.last_called, 39); + EXPECT_EQ(even_smaller_timestep.last_called, 399); + EXPECT_EQ(larger_timestep.last_called, 1); + EXPECT_EQ(larger_postinit_timestep.last_called, 0); + EXPECT_EQ(incompatible_timestep.last_called, called_sentinel); } TEST_F(SolverTest, RemoveMonitor) { From 07171b6ee34cd0556e1ce04c729903ab758f7675 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Apr 2019 15:58:31 +0100 Subject: [PATCH 1213/1783] Rename some private Solver and Monitor variables for clarity - Monitor::frequency -> Monitor::period - Solver::default_monitor_frequency -> Solver::default_monitor_period - Solver::timestep -> Solver::internal_timestep --- include/bout/monitor.hxx | 2 +- include/bout/solver.hxx | 4 +- src/solver/solver.cxx | 81 ++++++++++++++++++++-------------------- 3 files changed, 44 insertions(+), 43 deletions(-) diff --git a/include/bout/monitor.hxx b/include/bout/monitor.hxx index 7cacf41fd7..7c4de8137b 100644 --- a/include/bout/monitor.hxx +++ b/include/bout/monitor.hxx @@ -71,7 +71,7 @@ private: /// The desired physical timestep BoutReal timestep{-1}; /// How often this monitor should be called, in internal Solver steps - int frequency{1}; + int period{1}; }; struct RunMetrics { diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 727540d159..a81a915f77 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -423,9 +423,9 @@ private: /// Number of calls to the implicit (diffusive) RHS function int rhs_ncalls_i{0}; /// Default sampling rate at which to call monitors - same as output to screen - int default_monitor_frequency{1}; + int default_monitor_period{1}; /// timestep - shouldn't be changed after init is called. - BoutReal timestep{-1}; + BoutReal internal_timestep{-1}; /// Physics model being evolved PhysicsModel* model{nullptr}; diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index e5ba502285..3bf57379db 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -452,35 +452,35 @@ int Solver::solve(int NOUT, BoutReal TIMESTEP) { } /// syncronize timestep with those set to the monitors - if (timestep > 0){ - if (!isMultiple(timestep,TIMESTEP)){ + if (internal_timestep > 0){ + if (!isMultiple(internal_timestep,TIMESTEP)){ throw BoutException("A monitor requested a timestep not compatible with the output_step!"); } - if (timestep < TIMESTEP*1.5){ - default_monitor_frequency=TIMESTEP/timestep+.5; - NOUT*=default_monitor_frequency; - TIMESTEP=timestep; + if (internal_timestep < TIMESTEP*1.5){ + default_monitor_period=TIMESTEP/internal_timestep+.5; + NOUT*=default_monitor_period; + TIMESTEP=internal_timestep; } else { - default_monitor_frequency = 1; + default_monitor_period = 1; // update old monitors - int fac=timestep/TIMESTEP+.5; + int fac=internal_timestep/TIMESTEP+.5; for (const auto &i: monitors){ - i->frequency=i->frequency*fac; + i->period=i->period*fac; } } } for (const auto &i: monitors){ if (i->timestep < 0){ - i->timestep=timestep*default_monitor_frequency; - i->frequency=default_monitor_frequency; + i->timestep=internal_timestep*default_monitor_period; + i->period=default_monitor_period; } } output_progress.write(_("Solver running for %d outputs with output timestep of %e\n"), NOUT, TIMESTEP); - if (default_monitor_frequency > 1) + if (default_monitor_period > 1) output_progress.write(_("Solver running for %d outputs with monitor timestep of %e\n"), - NOUT/default_monitor_frequency, TIMESTEP*default_monitor_frequency); + NOUT/default_monitor_period, TIMESTEP*default_monitor_period); // Initialise if (init(NOUT, TIMESTEP)) { @@ -594,24 +594,24 @@ BoutReal Solver::adjustMonitorFrequencies(Monitor* new_monitor) { if (new_monitor->timestep < 0) { // The timestep will get adjusted when we call solve - new_monitor->frequency = default_monitor_frequency; - return timestep; + new_monitor->period = default_monitor_period; + return internal_timestep; } - if (!initialised && timestep < 0) { + if (!initialised && internal_timestep < 0) { // This is the first monitor to be added return new_monitor->timestep; } - if (!isMultiple(timestep, new_monitor->timestep)) { - throw BoutException(_("Couldn't add Monitor: %g is not a multiple of %g!"), timestep, + if (!isMultiple(internal_timestep, new_monitor->timestep)) { + throw BoutException(_("Couldn't add Monitor: %g is not a multiple of %g!"), internal_timestep, new_monitor->timestep); } - if (new_monitor->timestep > timestep * 1.5) { + if (new_monitor->timestep > internal_timestep * 1.5) { // Monitor has a larger timestep - new_monitor->frequency = (new_monitor->timestep / timestep) + .5; - return timestep; + new_monitor->period = (new_monitor->timestep / internal_timestep) + .5; + return internal_timestep; } // Monitor timestep is smaller, so we need to adjust our timestep, @@ -620,18 +620,18 @@ BoutReal Solver::adjustMonitorFrequencies(Monitor* new_monitor) { if (initialised) { throw BoutException(_("Solver::addMonitor: Cannot reduce timestep (from %g to %g) " "after init is called!"), - timestep, new_monitor->timestep); + internal_timestep, new_monitor->timestep); } // This is the relative increase in timestep - const int multiplier = timestep / new_monitor->timestep + .5; + const int multiplier = internal_timestep / new_monitor->timestep + .5; for (const auto& monitor : monitors) { - monitor->frequency *= multiplier; + monitor->period *= multiplier; } // Update default_monitor_frequency so that monitors with no // timestep are called at the output frequency - default_monitor_frequency *= multiplier; + default_monitor_period *= multiplier; // This monitor is now the fastest monitor return new_monitor->timestep; @@ -639,7 +639,7 @@ BoutReal Solver::adjustMonitorFrequencies(Monitor* new_monitor) { void Solver::addMonitor(Monitor* monitor, MonitorPosition pos) { - timestep = adjustMonitorFrequencies(monitor); + internal_timestep = adjustMonitorFrequencies(monitor); monitor->is_added = true; @@ -657,28 +657,29 @@ void Solver::removeMonitor(Monitor * f) { extern bool user_requested_exit; int Solver::call_monitors(BoutReal simtime, int iter, int NOUT) { bool abort; - MPI_Allreduce(&user_requested_exit,&abort,1,MPI_C_BOOL,MPI_LOR,MPI_COMM_WORLD); - if(abort){ - NOUT=iter+1; + MPI_Allreduce(&user_requested_exit, &abort, 1, MPI_C_BOOL, MPI_LOR, MPI_COMM_WORLD); + if (abort) { + NOUT = iter + 1; } - if(mms) { + if (mms) { // Calculate MMS errors calculate_mms_error(simtime); } - + ++iter; try { // Call monitors - for (const auto &it : monitors){ - if ((iter % it->frequency)==0){ + for (const auto& monitor : monitors) { + if ((iter % monitor->period) == 0) { // Call each monitor one by one - int ret = it->call(this, simtime,iter/it->frequency-1, NOUT/it->frequency); - if(ret) + int ret = monitor->call(this, simtime, iter / monitor->period - 1, + NOUT / monitor->period); + if (ret) throw BoutException(_("Monitor signalled to quit")); } } - } catch (BoutException &e) { - for (const auto &it : monitors){ + } catch (BoutException& e) { + for (const auto& it : monitors) { it->cleanup(); } output_error.write(_("Monitor signalled to quit\n")); @@ -686,10 +687,10 @@ int Solver::call_monitors(BoutReal simtime, int iter, int NOUT) { } // Check if any of the monitors has asked to quit - MPI_Allreduce(&user_requested_exit,&abort,1,MPI_C_BOOL,MPI_LOR,MPI_COMM_WORLD); + MPI_Allreduce(&user_requested_exit, &abort, 1, MPI_C_BOOL, MPI_LOR, MPI_COMM_WORLD); - if ( iter == NOUT || abort ){ - for (const auto &it : monitors){ + if (iter == NOUT || abort) { + for (const auto& it : monitors) { it->cleanup(); } } From 80580835fa7d207ca50268798f58a4dbde4bc9c9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Apr 2019 15:58:37 +0100 Subject: [PATCH 1214/1783] Add better docstring for Solver::call_monitors --- include/bout/solver.hxx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index a81a915f77..3255898e97 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -389,6 +389,22 @@ protected: int run_diffusive(BoutReal t, bool linear = true); /// Calls all monitor functions + /// + /// There are two important things to note about how \p iter is + /// passed along to each monitor: + /// - The solvers all start their iteration numbering from zero, so the + /// initial state is calculated at \p iter = -1 + /// - Secondly, \p iter is passed along to each monitor *relative to + /// that monitor's period* + /// + /// In practice, this means that each monitor is called like: + /// + /// monitor->call(solver, simulation_time, + /// ((iter + 1) / monitor->period) - 1, + /// NOUT / monitor->period); + /// + /// e.g. for a monitor with period 10, passing \p iter = 9 will + /// result in it being called with a value of `(9 + 1)/10 - 1 == 0` int call_monitors(BoutReal simtime, int iter, int NOUT); /// Should timesteps be monitored? From 06a051f6bf04eb892a2b03ed2b6635fce591a222 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Apr 2019 16:14:13 +0100 Subject: [PATCH 1215/1783] Add some very basic unit tests for Solver::solve --- tests/unit/solver/test_solver.cxx | 57 ++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx index c83bb9e56b..c7acc05b69 100644 --- a/tests/unit/solver/test_solver.cxx +++ b/tests/unit/solver/test_solver.cxx @@ -16,7 +16,21 @@ class FakeSolver : public Solver { public: FakeSolver(Options* options) : Solver(options) { has_constraints = true; } ~FakeSolver() = default; - int run() { return (*options)["number"].withDefault(42); } + + int run() override { + run_called = true; + return 0; + } + bool run_called{false}; + + int init(int nout, BoutReal tstep) override { + init_called = true; + if (Solver::init(nout, tstep)) { + return 1; + } + return 0; + } + bool init_called{false}; void changeHasConstraints(bool new_value) { has_constraints = new_value; } @@ -883,3 +897,44 @@ TEST_F(SolverTest, DontCallTimestepMonitors) { EXPECT_EQ(solver.callTimestepMonitorsShim(1., -1.), 0); EXPECT_EQ(solver.callTimestepMonitorsShim(-1., -1.), 0); } + +TEST_F(SolverTest, BasicSolve) { + Options options; + FakeSolver solver{&options}; + + Options::root()["dump_on_restart"] = false; + + EXPECT_NO_THROW(solver.solve()); + + EXPECT_TRUE(solver.init_called); + EXPECT_TRUE(solver.run_called); +} + +TEST_F(SolverTest, SolveFixDefaultTimestep) { + Options options; + FakeSolver solver{&options}; + + Options::root()["dump_on_restart"] = false; + + FakeMonitor default_timestep; + FakeMonitor smaller_timestep{0.1}; + FakeMonitor even_smaller_timestep{0.01}; + FakeMonitor larger_timestep{2.}; + + solver.addMonitor(&default_timestep); + solver.addMonitor(&smaller_timestep); + solver.addMonitor(&even_smaller_timestep); + solver.addMonitor(&larger_timestep); + + EXPECT_NO_THROW(solver.solve(100, 1.)); + + EXPECT_TRUE(solver.init_called); + EXPECT_TRUE(solver.run_called); + + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, 99, 0)); + + EXPECT_EQ(default_timestep.last_called, 0); + EXPECT_EQ(smaller_timestep.last_called, 9); + EXPECT_EQ(even_smaller_timestep.last_called, 99); + EXPECT_EQ(larger_timestep.last_called, called_sentinel); +} From 434c63a9004a158a7473abad01084b04f5d0725e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Apr 2019 16:33:31 +0100 Subject: [PATCH 1216/1783] Pull monitor timestep synchronisation out of Solver::solve Now in Solver::finaliseMonitorPeriods which is called in Solver::solve --- include/bout/solver.hxx | 10 +++++--- src/solver/solver.cxx | 57 +++++++++++++++++++++++------------------ 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 3255898e97..6bbb022b2c 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -482,9 +482,13 @@ private: /// Check if a variable has already been added bool varAdded(const std::string& name); - /// (Possibly) adjust the frequencies of \p monitor, and the - /// `monitors` timesteps, returning the new Solver timestep - BoutReal adjustMonitorFrequencies(Monitor* monitor); + /// (Possibly) adjust the periods of \p monitor, and the `monitors` + /// timesteps, returning the new Solver timestep + BoutReal adjustMonitorPeriods(Monitor* monitor); + + /// Fix all the monitor periods based on \p output_timestep, as well + /// as adjusting \p NOUT and \p output_timestep to be consistent + void finaliseMonitorPeriods(int& NOUT, BoutReal& output_timestep); }; #endif // __SOLVER_H__ diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 3bf57379db..e06a29706d 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -451,31 +451,9 @@ int Solver::solve(int NOUT, BoutReal TIMESTEP) { options->get("output_step", TIMESTEP, TIMESTEP); } - /// syncronize timestep with those set to the monitors - if (internal_timestep > 0){ - if (!isMultiple(internal_timestep,TIMESTEP)){ - throw BoutException("A monitor requested a timestep not compatible with the output_step!"); - } - if (internal_timestep < TIMESTEP*1.5){ - default_monitor_period=TIMESTEP/internal_timestep+.5; - NOUT*=default_monitor_period; - TIMESTEP=internal_timestep; - } else { - default_monitor_period = 1; - // update old monitors - int fac=internal_timestep/TIMESTEP+.5; - for (const auto &i: monitors){ - i->period=i->period*fac; - } - } - } - for (const auto &i: monitors){ - if (i->timestep < 0){ - i->timestep=internal_timestep*default_monitor_period; - i->period=default_monitor_period; - } } + finaliseMonitorPeriods(NOUT, TIMESTEP); output_progress.write(_("Solver running for %d outputs with output timestep of %e\n"), NOUT, TIMESTEP); if (default_monitor_period > 1) @@ -590,7 +568,7 @@ void Solver::outputVars(Datafile &outputfile, bool save_repeat) { ///////////////////////////////////////////////////// -BoutReal Solver::adjustMonitorFrequencies(Monitor* new_monitor) { +BoutReal Solver::adjustMonitorPeriods(Monitor* new_monitor) { if (new_monitor->timestep < 0) { // The timestep will get adjusted when we call solve @@ -637,9 +615,38 @@ BoutReal Solver::adjustMonitorFrequencies(Monitor* new_monitor) { return new_monitor->timestep; } +void Solver::finaliseMonitorPeriods(int& NOUT, BoutReal& output_timestep) { + // Synchronise timestep with those of the monitors + if (internal_timestep > 0) { + if (!isMultiple(internal_timestep, output_timestep)) { + throw BoutException( + "A monitor requested a timestep not compatible with the output_step!"); + } + if (internal_timestep < output_timestep * 1.5) { + default_monitor_period = output_timestep / internal_timestep + .5; + NOUT *= default_monitor_period; + output_timestep = internal_timestep; + } else { + default_monitor_period = 1; + // update old monitors + int multiplier = internal_timestep / output_timestep + .5; + for (const auto& i : monitors) { + i->period = i->period * multiplier; + } + } + } + // Now set any monitors which still have the default timestep/period + for (const auto& i : monitors) { + if (i->timestep < 0) { + i->timestep = internal_timestep * default_monitor_period; + i->period = default_monitor_period; + } + } +} + void Solver::addMonitor(Monitor* monitor, MonitorPosition pos) { - internal_timestep = adjustMonitorFrequencies(monitor); + internal_timestep = adjustMonitorPeriods(monitor); monitor->is_added = true; From 7ee145b7c1e5e0be4b7ef7ec78861d25aab615fd Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Apr 2019 16:34:36 +0100 Subject: [PATCH 1217/1783] Use new Options API and clang-format Solver::solve --- src/solver/solver.cxx | 65 +++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index e06a29706d..549a79d102 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -438,61 +438,59 @@ void Solver::constraint(Vector3D &v, Vector3D &C_v, const std::string name) { **************************************************************************/ int Solver::solve(int NOUT, BoutReal TIMESTEP) { - - Options *globaloptions = Options::getRoot(); // Default from global options - - if(NOUT < 0) { - /// Get options - OPTION(globaloptions, NOUT, 1); - OPTION(globaloptions, TIMESTEP, 1.0); - - // Check specific solver options, which override global options - OPTION(options, NOUT, NOUT); - options->get("output_step", TIMESTEP, TIMESTEP); - } + Options* globaloptions = Options::getRoot(); // Default from global options + + if (NOUT < 0) { + NOUT = (*globaloptions)["NOUT"].withDefault(1); + TIMESTEP = (*globaloptions)["TIMESTEP"].withDefault(1.0); + + // Check specific solver options, which override global options + NOUT = (*options)["NOUT"].withDefault(NOUT); + TIMESTEP = (*options)["output_step"].withDefault(TIMESTEP); } finaliseMonitorPeriods(NOUT, TIMESTEP); - output_progress.write(_("Solver running for %d outputs with output timestep of %e\n"), NOUT, TIMESTEP); + output_progress.write(_("Solver running for %d outputs with output timestep of %e\n"), + NOUT, TIMESTEP); if (default_monitor_period > 1) - output_progress.write(_("Solver running for %d outputs with monitor timestep of %e\n"), - NOUT/default_monitor_period, TIMESTEP*default_monitor_period); - + output_progress.write( + _("Solver running for %d outputs with monitor timestep of %e\n"), + NOUT / default_monitor_period, TIMESTEP * default_monitor_period); + // Initialise if (init(NOUT, TIMESTEP)) { throw BoutException(_("Failed to initialise solver-> Aborting\n")); } - + /// Run the solver output_info.write(_("Running simulation\n\n")); time_t start_time = time(nullptr); output_progress.write(_("\nRun started at : %s\n"), toString(start_time).c_str()); - + Timer timer("run"); // Start timer - - bool restart; - OPTION(globaloptions, restart, false); - bool append; - OPTION(globaloptions, append, false); - bool dump_on_restart; - OPTION(globaloptions, dump_on_restart, !restart || !append); - if ( dump_on_restart ) { + + const bool restart = (*globaloptions)["restart"].withDefault(false); + const bool append = (*globaloptions)["append"].withDefault(false); + const bool dump_on_restart = + (*globaloptions)["dump_on_restart"].withDefault(!restart || !append); + + if (dump_on_restart) { /// Write initial state as time-point 0 - + // Run RHS once to ensure all variables set if (run_rhs(simtime)) { throw BoutException("Physics RHS call failed\n"); } - + // Call monitors so initial values are written to output dump files - if (call_monitors(simtime, -1, NOUT)){ + if (call_monitors(simtime, -1, NOUT)) { throw BoutException("Initial monitor call failed!"); } } - + int status; try { status = run(); @@ -505,15 +503,15 @@ int Solver::solve(int NOUT, BoutReal TIMESTEP) { int i = static_cast(dt / (60. * 60.)); if (i > 0) { output_progress.write("%d h ", i); - dt -= i*60*60; + dt -= i * 60 * 60; } i = static_cast(dt / 60.); if (i > 0) { output_progress.write("%d m ", i); - dt -= i*60; + dt -= i * 60; } output_progress.write("%d s\n", dt); - } catch (BoutException &e) { + } catch (BoutException& e) { output_error << "Error encountered in solver run\n"; output_error << e.what() << endl; throw; @@ -522,7 +520,6 @@ int Solver::solve(int NOUT, BoutReal TIMESTEP) { return status; } - /************************************************************************** * Initialisation **************************************************************************/ From 7b5b0e0c277b8281f26bdb9411415453f6cec80f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Apr 2019 16:35:57 +0100 Subject: [PATCH 1218/1783] Clang-format Solver includes --- src/solver/solver.cxx | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 549a79d102..005cf942b8 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -20,27 +20,22 @@ * **************************************************************************/ -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "bout/solverfactory.hxx" - -#include -#include -#include -#include - -#include +#include "bout/solver.hxx" +#include "boutcomm.hxx" +#include "boutexception.hxx" +#include "field_factory.hxx" +#include "initialprofiles.hxx" +#include "interpolation.hxx" +#include "msg_stack.hxx" +#include "output.hxx" +#include "bout/array.hxx" +#include "bout/assert.hxx" #include "bout/region.hxx" +#include "bout/solverfactory.hxx" +#include "bout/sys/timer.hxx" +#include +#include #include // Static member variables From 8cd4031de97ed8443f3e9e8b1bec4fc3f1108ed6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Apr 2019 17:08:57 +0100 Subject: [PATCH 1219/1783] Store MMS_err as a unique_ptr in Solver::VarStr --- include/bout/solver.hxx | 20 +++++----- src/solver/solver.cxx | 84 ++++++++++++++++------------------------- 2 files changed, 43 insertions(+), 61 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 6bbb022b2c..a274ce632e 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -43,6 +43,8 @@ #include "unused.hxx" #include "bout/monitor.hxx" +#include + /////////////////////////////////////////////////////////////////// // C function pointer types @@ -171,7 +173,7 @@ enum SOLVER_VAR_OP {LOAD_VARS, LOAD_DERIVS, SET_ID, SAVE_VARS, SAVE_DERIVS}; class Solver { public: Solver(Options* opts = nullptr); - virtual ~Solver(); + virtual ~Solver() = default; ///////////////////////////////////////////// // New API @@ -332,14 +334,14 @@ protected: /// A structure to hold an evolving variable template struct VarStr { - bool constraint{false}; /// Does F_var represent a constraint? - T* var{nullptr}; /// The evolving variable - T* F_var{nullptr}; /// The time derivative or constraint on var - T* MMS_err{nullptr}; /// Error for MMS - CELL_LOC location{CELL_DEFAULT}; /// For fields and vector components - bool covariant{false}; /// For vectors - bool evolve_bndry{false}; /// Are the boundary regions being evolved? - std::string name; /// Name of the variable + bool constraint{false}; /// Does F_var represent a constraint? + T* var{nullptr}; /// The evolving variable + T* F_var{nullptr}; /// The time derivative or constraint on var + std::unique_ptr MMS_err{nullptr}; /// Error for MMS + CELL_LOC location{CELL_DEFAULT}; /// For fields and vector components + bool covariant{false}; /// For vectors + bool evolve_bndry{false}; /// Are the boundary regions being evolved? + std::string name; /// Name of the variable }; /// Does \p var represent field \p name? diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 005cf942b8..b5b897b295 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -53,24 +53,6 @@ Solver::Solver(Options* opts) mms((*options)["mms"].withDefault(false)), mms_initialise((*options)["mms_initialise"].withDefault(mms)) {} -/************************************************************************** - * Destructor - **************************************************************************/ -Solver::~Solver(){ - //Ensure all MMS_err fields allocated here are destroyed etc. - for(const auto& f : f3d) { - if(f.MMS_err) { - delete f.MMS_err; - } - } - - for(const auto& f : f2d) { - if(f.MMS_err) { - delete f.MMS_err; - } - } -} - /************************************************************************** * Add physics models **************************************************************************/ @@ -138,7 +120,7 @@ void Solver::add(Field2D &v, const std::string name) { if (mms) { // Allocate storage for error variable - d.MMS_err = new Field2D{zeroFrom(v)}; + d.MMS_err = bout::utils::make_unique(zeroFrom(v)); } // Check if the boundary regions should be evolved @@ -149,7 +131,7 @@ void Solver::add(Field2D &v, const std::string name) { v.applyBoundary(true); - f2d.push_back(d); + f2d.emplace_back(std::move(d)); } void Solver::add(Field3D &v, const std::string name) { @@ -196,7 +178,7 @@ void Solver::add(Field3D &v, const std::string name) { } if (mms) { - d.MMS_err = new Field3D{zeroFrom(v)}; + d.MMS_err = bout::utils::make_unique(zeroFrom(v)); } // Check if the boundary regions should be evolved @@ -208,12 +190,12 @@ void Solver::add(Field3D &v, const std::string name) { v.applyBoundary(true); // Make sure initial profile obeys boundary conditions v.setLocation(d.location); // Restore location if changed - f3d.push_back(d); + f3d.emplace_back(std::move(d)); } -void Solver::add(Vector2D &v, const std::string name) { +void Solver::add(Vector2D& v, const std::string name) { TRACE("Adding 2D vector: Solver::add(%s)", name.c_str()); - + if (varAdded(name)) throw BoutException("Variable '%s' already added to Solver", name.c_str()); @@ -223,68 +205,66 @@ void Solver::add(Vector2D &v, const std::string name) { // Set boundary conditions v.setBoundary(name); ddt(v).copyBoundary(v); // Set boundary to be the same as v - + VarStr d; - + d.var = &v; d.F_var = &ddt(v); d.covariant = v.covariant; d.name = name; - v2d.push_back(d); - /// NOTE: No initial_profile call, because this will be done for each /// component individually. - + /// Add suffix, depending on co- /contravariance if (v.covariant) { - add(v.x, d.name+"_x"); - add(v.y, d.name+"_y"); - add(v.z, d.name+"_z"); + add(v.x, d.name + "_x"); + add(v.y, d.name + "_y"); + add(v.z, d.name + "_z"); } else { - add(v.x, d.name+"x"); - add(v.y, d.name+"y"); - add(v.z, d.name+"z"); + add(v.x, d.name + "x"); + add(v.y, d.name + "y"); + add(v.z, d.name + "z"); } - + /// Make sure initial profile obeys boundary conditions v.applyBoundary(true); + v2d.emplace_back(std::move(d)); } -void Solver::add(Vector3D &v, const std::string name) { +void Solver::add(Vector3D& v, const std::string name) { TRACE("Adding 3D vector: Solver::add(%s)", name.c_str()); - + if (varAdded(name)) throw BoutException("Variable '%s' already added to Solver", name.c_str()); if (initialised) throw BoutException("Error: Cannot add to solver after initialisation\n"); - + // Set boundary conditions v.setBoundary(name); ddt(v).copyBoundary(v); // Set boundary to be the same as v VarStr d; - + d.var = &v; d.F_var = &ddt(v); d.covariant = v.covariant; d.name = name; - - v3d.push_back(d); // Add suffix, depending on co- /contravariance if (v.covariant) { - add(v.x, d.name+"_x"); - add(v.y, d.name+"_y"); - add(v.z, d.name+"_z"); + add(v.x, d.name + "_x"); + add(v.y, d.name + "_y"); + add(v.z, d.name + "_z"); } else { - add(v.x, d.name+"x"); - add(v.y, d.name+"y"); - add(v.z, d.name+"z"); + add(v.x, d.name + "x"); + add(v.y, d.name + "y"); + add(v.z, d.name + "z"); } v.applyBoundary(true); + v3d.emplace_back(std::move(d)); } /************************************************************************** @@ -316,7 +296,7 @@ void Solver::constraint(Field2D &v, Field2D &C_v, const std::string name) { d.F_var = &C_v; d.name = name; - f2d.push_back(d); + f2d.emplace_back(std::move(d)); } void Solver::constraint(Field3D &v, Field3D &C_v, const std::string name) { @@ -345,7 +325,7 @@ void Solver::constraint(Field3D &v, Field3D &C_v, const std::string name) { d.location = v.getLocation(); d.name = name; - f3d.push_back(d); + f3d.emplace_back(std::move(d)); } void Solver::constraint(Vector2D &v, Vector2D &C_v, const std::string name) { @@ -374,7 +354,7 @@ void Solver::constraint(Vector2D &v, Vector2D &C_v, const std::string name) { d.covariant = v.covariant; d.name = name; - v2d.push_back(d); + v2d.emplace_back(std::move(d)); // Add suffix, depending on co- /contravariance if (v.covariant) { @@ -414,7 +394,7 @@ void Solver::constraint(Vector3D &v, Vector3D &C_v, const std::string name) { d.covariant = v.covariant; d.name = name; - v3d.push_back(d); + v3d.emplace_back(std::move(d)); // Add suffix, depending on co- /contravariance if (v.covariant) { From 2e439618276fc6b292017979daba913135b66d3e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Apr 2019 17:25:00 +0100 Subject: [PATCH 1220/1783] Tidy up multiple monitors/sub-sampling example - Use unique_ptr to avoid leaking memory - Make monitors all output at the same location, to make the plotting clearer --- examples/subsampling/README.md | 24 ++++--- examples/subsampling/monitor.cxx | 107 ++++++++++++++++--------------- examples/subsampling/show.py | 32 ++++++--- 3 files changed, 87 insertions(+), 76 deletions(-) mode change 100644 => 100755 examples/subsampling/show.py diff --git a/examples/subsampling/README.md b/examples/subsampling/README.md index 09d91214b8..9a95625225 100644 --- a/examples/subsampling/README.md +++ b/examples/subsampling/README.md @@ -9,24 +9,22 @@ Therefore the fields, which are solved for, and any field that is added with `SAVE_REPEAT()` will be written out every second timeunit. In the code another monitor is added with an output timestep of 0.01. -This Monitor uses a separat datafile, (via class `SimpleDatafile`, see monitor.cxx -line 12 ff) to write the data. The options for the simple datafile are -read from the `[probes]` section in the input. -As netcdf supports several unlimited dimension, it is also possible to -extend the netcdf interface, to write it to the same output file, as -all other data is going. +This Monitor uses a separate datafile, (via class `SimpleDatafile`) to +write the data. The options for the simple datafile are read from the +`[probes]` section in the input. As NetCDF supports several unlimited +dimensions, it is also possible to extend the netcdf interface, to +write it to the same output file, as all other data is going. -The Monitor1dDump just saves a single point of the 3D field. +The `Monitor1dDump` just saves a single point of the 3D field. As mentioned, it is set to an output timestep of 0.01. This sets the internal timestep for the solver therefore to 0.01, as this is smaller then the standard output timestep of 2. Therefore 200 timesteps are written to the 1D datafile, for every output to the `BOUT.dmp` datafile. -The timestep of the Monitor is by default independent of the output +The timestep of the `Monitor` is by default independent of the output timestep set in `BOUT.inp`. If this is not desired, it is easy to read -this value, and set an apropriate timestep. -If the monitors are used for physics, e.g. by coupling to an external -library for some calulation or using it as an PID controller, it is -probably desirable to to not change the physics, if the output -timestep is changed. \ No newline at end of file +this value, and set an apropriate timestep. If the monitors are used +for physics, e.g. by coupling to an external library for some +calulation or using it as an PID controller, it is probably desirable +to to not change the physics, if the output timestep is changed. diff --git a/examples/subsampling/monitor.cxx b/examples/subsampling/monitor.cxx index 0de09dd654..7480b32697 100644 --- a/examples/subsampling/monitor.cxx +++ b/examples/subsampling/monitor.cxx @@ -3,113 +3,114 @@ #include #include -// simplify the datafile with sane defaults -// Note that you should never ever copy the datafile ... +// Simplify the datafile with sane defaults +// Note that you should never ever copy the datafile. // The constructor takes a pointer to an options object, or the name // of a section. // Unlike the default Datafile, SimpleDatafile always ends up in the // correct folder, and should throw if it possible to detect the error. -class SimpleDatafile: public Datafile{ +class SimpleDatafile : public Datafile { public: SimpleDatafile(std::string section) : SimpleDatafile(Options::root()[section], section){}; SimpleDatafile(Options& ops, std::string section = "Default") : Datafile(&ops) { + // Open a file for the output std::string datadir = "data"; if (ops.isSet("path")) { - datadir = ops["path"].withDefault(datadir); // default never needed + datadir = ops["path"].as(); } else { - datadir = Options::root()["datadir"].withDefault( - datadir); // I need to know data is default :( + datadir = Options::root()["datadir"].withDefault(datadir); } - std::string file; - file = section+".dmp"; - file = ops["file"].withDefault(file); + + const std::string default_filename = section + ".dmp"; + const std::string file = ops["file"].withDefault(default_filename); + bool append; if (ops.isSet("append")) { append = ops["append"].withDefault(false); } else { - append = Options::root()["append"].withDefault( - false); // I hope that is the correct default + append = Options::root()["append"].withDefault(false); } - std::string dump_ext="nc"; // bad style, but I only use nc - if(append) { + const std::string dump_ext = "nc"; + + if (append) { if (!this->opena("%s/%s.%s", datadir.c_str(), file.c_str(), dump_ext.c_str())) throw BoutException("Failed to open file for appending!"); - //output.write("opend succesfully for appending\n"); - }else { + } else { if (!this->openw("%s/%s.%s", datadir.c_str(), file.c_str(), dump_ext.c_str())) throw BoutException("Failed to open file for writing!"); - //output.write("opend succesfully for writing\n"); } } }; // Monitor to write out 1d Data -class Monitor1dDump:public Monitor{ +class Monitor1dDump : public Monitor { public: - Monitor1dDump(BoutReal timestep,std::string section_name) - :Monitor(timestep), - dump(new SimpleDatafile(section_name)) - { - dump->add(time,"t_array",true); + Monitor1dDump(BoutReal timestep, std::string section_name) + : Monitor(timestep), dump(bout::utils::make_unique(section_name)) { + dump->add(time, "t_array", true); }; - int call(Solver * solver,double _time,int i1,int i2) override{ - time=_time; - dump->write(); // this should throw if it doesn't work + int call(Solver*, BoutReal _time, int, int) override { + time = _time; + dump->write(); return 0; } - void add(BoutReal &data,std::string name){ - dump->add(data,name.c_str(),true); + void add(BoutReal& data, const std::string& name) { + dump->add(data, name.c_str(), true); } + private: BoutReal time; - Datafile * dump; + std::unique_ptr dump{nullptr}; }; - - +/// An example of using multiple monitors on different timescales class MonitorExample : public PhysicsModel { protected: - int init(bool restarting) { - SOLVE_FOR2(n,T); - // our monitor writes out data every 100th of a time unit + int init(bool) { + SOLVE_FOR2(n, T); + + // Our monitor writes out data every 100th of a time unit // note that this is independent of time_step. // Especially if the monitor influences the physics, and isn't // just used to output data, this is probably what you want. - probes=new Monitor1dDump(.01, "probes"); + probes = bout::utils::make_unique(.01, "probes"); + // In case the monitor should be relative to the timestep, the // timestep needs to be read first: - BoutReal timestep; - timestep = Options::root()["timestep"].withDefault(-1); - // There is no 'slow' section in BOUT.inp, therfore it will write + const BoutReal timestep = Options::root()["timestep"].withDefault(-1); + + // There is no 'slow' section in BOUT.inp, therefore it will write // to data/slow.dmp.0.nc - Monitor1dDump * slow=new Monitor1dDump(timestep*2,"slow"); - // now we can add the monitors - solver->addMonitor(probes); - solver->addMonitor(slow); - // the derived monitor Monitor1dData can dump 1d data, which we can - // now add: - probes->add(n(mesh->xstart,mesh->ystart,0),"n_up"); - probes->add(T(mesh->xstart,mesh->ystart,0),"T_up"); - // add the corner value - slow->add(T(0,0,0),"T"); // T is already present in BOUT.dmp - but - // as it is a differnt file, this doesn't - // cause issues. + slow = bout::utils::make_unique(timestep * 2, "slow"); + + // Now we can add the monitors + solver->addMonitor(probes.get()); + solver->addMonitor(slow.get()); + + // The derived monitor Monitor1dData can dump 1d data, which we + // can now add: + probes->add(n(mesh->xstart, mesh->ystart, 0), "n_up"); + probes->add(T(mesh->xstart, mesh->ystart, 0), "T_up"); + + // Add the corner value. T is already present in BOUT.dmp - but + // as it is a different file, this doesn't cause issues + slow->add(T(mesh->xstart, mesh->ystart, 0), "T"); return 0; } - int rhs(BoutReal t) { + int rhs(BoutReal) { ddt(n) = -T; ddt(T) = -n; return 0; } + private: - Field3D n,T; + Field3D n, T; - Monitor1dDump * probes, * slow; + std::unique_ptr probes{nullptr}, slow{nullptr}; }; BOUTMAIN(MonitorExample); - diff --git a/examples/subsampling/show.py b/examples/subsampling/show.py old mode 100644 new mode 100755 index c78a975862..155dd68d8e --- a/examples/subsampling/show.py +++ b/examples/subsampling/show.py @@ -1,13 +1,25 @@ -from boututils.datafile import DataFile +#!/usr/bin/env python3 +from boututils.datafile import DataFile import matplotlib.pyplot as plt -path="data" -todo=[["slow","T"], - ["PROBES","T_up"], - ["PROBES","n_up"], + +path = "data" +monitors = [ + ["PROBES", "T_up"], + ["PROBES", "n_up"], + ["slow", "T"], ] -for pack in todo: - filename,data = pack - t=DataFile(path+'/'+filename+'.dmp.0.nc').read('t_array').flatten() - data=DataFile(path+'/'+filename+'.dmp.0.nc').read(data).flatten() - plt.plot(t,data) + +for pack in monitors: + filename, data_name = pack + t = DataFile(path+'/'+filename+'.dmp.0.nc').read('t_array') + data = DataFile(path+'/'+filename+'.dmp.0.nc').read(data_name).flatten() + plt.plot(t, data, label="{} {}".format(filename, data_name)) + +time = DataFile(path+'/BOUT.dmp.0.nc').read('t_array') +data = DataFile(path+'/BOUT.dmp.0.nc').read("T")[:, 2, 2, 0] + +plt.plot(time, data, marker='+', label="BOUT++ T") + +plt.xlabel("Time") +plt.legend() plt.show() From 199ae970fe216de32230833b2944fd2a3246b25f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Apr 2019 17:51:03 +0100 Subject: [PATCH 1221/1783] Don't copy Solver::VarStr in range-based for loop --- src/solver/impls/petsc/petsc.cxx | 2 +- src/solver/impls/pvode/pvode.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solver/impls/petsc/petsc.cxx b/src/solver/impls/petsc/petsc.cxx index ed54809ca0..7e55a83292 100644 --- a/src/solver/impls/petsc/petsc.cxx +++ b/src/solver/impls/petsc/petsc.cxx @@ -178,7 +178,7 @@ int PetscSolver::init(int NOUT, BoutReal TIMESTEP) { // int MXSUB = mesh->xend - mesh->xstart + 1; // int band_width_default = n3Dvars()*(MXSUB+2); int band_width_default = 0; - for (auto fvar : f3d) { + for (const auto& fvar : f3d) { Mesh* localmesh = fvar.var->getMesh(); band_width_default += localmesh->xend - localmesh->xstart + 3; } diff --git a/src/solver/impls/pvode/pvode.cxx b/src/solver/impls/pvode/pvode.cxx index be9d4cbfa9..80e5a29255 100644 --- a/src/solver/impls/pvode/pvode.cxx +++ b/src/solver/impls/pvode/pvode.cxx @@ -128,7 +128,7 @@ int PvodeSolver::init(int nout, BoutReal tstep) { // int MXSUB = mesh->xend - mesh->xstart + 1; // int band_width_default = n3Dvars()*(MXSUB+2); int band_width_default = 0; - for (auto fvar : f3d) { + for (const auto& fvar : f3d) { Mesh* localmesh = fvar.var->getMesh(); band_width_default += localmesh->xend - localmesh->xstart + 3; } From 6ec09dfef55735ff6ab524493b28d9b0ba489503 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 2 Apr 2019 00:04:32 +0100 Subject: [PATCH 1222/1783] Change Options::at interface The optional input argument is now a value which the result should be similar to. This is so that `Field` types can be requested, and the metadata like `Mesh` pointer and cell location will be taken from the input. No (non-test) code uses this interface yet, so should be ok to change. --- include/field3d.hxx | 1 + include/options.hxx | 22 ++++--- manual/sphinx/user_docs/bout_options.rst | 31 ++++++--- src/sys/options.cxx | 80 ++++++++++++++++-------- tests/unit/sys/test_options_fields.cxx | 17 +++-- 5 files changed, 103 insertions(+), 48 deletions(-) diff --git a/include/field3d.hxx b/include/field3d.hxx index 32e114821a..287083b403 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -785,6 +785,7 @@ inline std::string toString<>(const Field3D& UNUSED(val)) { /// the minimum absolute difference between them bool operator==(const Field3D &a, const Field3D &b); +/// Output a string describing a Field3D to a stream std::ostream& operator<<(std::ostream &out, const Field3D &value); #endif /* __FIELD3D_H__ */ diff --git a/include/options.hxx b/include/options.hxx index bd793a2c67..7c0db962ce 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -351,8 +351,12 @@ public: /// option["test"] = 2.0; /// int value = option["test"].as(); /// + /// An optional argument is an object which the result should be similar to. + /// The main use for this is in Field2D and Field3D specialisations, + /// where the Mesh and cell location are taken from this input. + /// template - T as(Mesh* UNUSED(mesh) = nullptr) const { + T as(T&& UNUSED(similar_to) = {}) const { if (!is_value) { throw BoutException("Option %s has no value", full_name.c_str()); } @@ -420,7 +424,7 @@ public: << ")" << std::endl; return def; } - T val = as(bout::utils::meshFromValue(def)); + T val = as(std::forward(def)); // Check if this was previously set as a default option if (bout::utils::variantEqualTo(attributes.at("source"), DEFAULT_SOURCE)) { // Check that the default values are the same @@ -447,7 +451,7 @@ public: << ")" << std::endl; return def; } - T val = as(bout::utils::meshFromValue(def)); + T val = as(std::forward(def)); // Check if this was previously set as a default option if (bout::utils::variantEqualTo(attributes.at("source"), DEFAULT_SOURCE)) { // Check that the default values are the same @@ -662,12 +666,12 @@ template<> void Options::assign<>(Tensor val, const std::string source template <> inline bool Options::similar(BoutReal a, BoutReal b) const { return fabs(a - b) < 1e-10; } /// Specialised as routines -template <> std::string Options::as(Mesh* mesh) const; -template <> int Options::as(Mesh* mesh) const; -template <> BoutReal Options::as(Mesh* mesh) const; -template <> bool Options::as(Mesh* mesh) const; -template <> Field2D Options::as(Mesh* mesh) const; -template <> Field3D Options::as(Mesh* mesh) const; +template <> std::string Options::as(std::string&& similar_to) const; +template <> int Options::as(int&& similar_to) const; +template <> BoutReal Options::as(BoutReal&& similar_to) const; +template <> bool Options::as(bool&& similar_to) const; +template <> Field2D Options::as(Field2D&& similar_to) const; +template <> Field3D Options::as(Field3D&& similar_to) const; /// Define for reading options which passes the variable name #define OPTION(options, var, def) \ diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index b83cb1e6ff..83fa40d7ab 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -679,18 +679,29 @@ to the output dump or restart files. Reading fields is a bit more difficult. Currently 1D data is read as an ``Array``, 2D as ``Matrix`` and 3D as ``Tensor``. These can be extracted directly from the -``Options`` tree, or converted to a Field if given a ``Mesh``:: +``Options`` tree, or converted to a Field:: Options fields_in = OptionsNetCDF("fields.nc").read(); - Field2D f2d = fields_in["f2d"].as(mesh); - Field3D f3d = fields_in["f3d"].as(mesh); - -Currently this only works if the data in the ``Matrix`` or ``Tensor`` is the -same size as the ``Field``. In the case of grid files, the fields only -needs a part of the global values. Some kind of mapping from the global -index to local index is needed, probably defined by ``Mesh``. For now it -should be possible to be compatible with the current system, so that -all quantities from the grid file are accessed through Mesh::get. + Field2D f2d = fields_in["f2d"].as(); + Field3D f3d = fields_in["f3d"].as(); + +Note that by default reading as ``Field2D`` or ``Field3D`` will use the global +``bout::globals::mesh``. To use a different mesh, or different cell location, +pass a field which the result should be similar to:: + + Field3D example = ... // Some existing field + + Field3D f3d = fields_in["f3d"].as(example); + +Meta data like ``Mesh`` pointer, will be taken from ``example``. + +Currently converting from ``Matrix`` or ``Tensor`` types only works if +the data in the ``Matrix`` or ``Tensor`` is the same size as the +``Field``. In the case of grid files, the fields only needs a part of +the global values. Some kind of mapping from the global index to local +index is needed, probably defined by ``Mesh``. For now it should be +possible to be compatible with the current system, so that all +quantities from the grid file are accessed through Mesh::get. Time dependence ~~~~~~~~~~~~~~~ diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 41b82fbcbe..48eeea357e 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -7,19 +7,6 @@ #include #include -namespace bout { -namespace utils { - template <> - Mesh* meshFromValue(const Field2D& value) { - return value.getMesh(); - } - template <> - Mesh* meshFromValue(const Field3D& value) { - return value.getMesh(); - } -} -} - /// The source label given to default values const std::string Options::DEFAULT_SOURCE{_("default")}; Options *Options::root_instance{nullptr}; @@ -183,7 +170,7 @@ void Options::assign<>(Tensor val, const std::string source) { is_value = true; } -template <> std::string Options::as(Mesh* UNUSED(mesh)) const { +template <> std::string Options::as(std::string&& UNUSED(similar_to)) const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); } @@ -203,7 +190,7 @@ template <> std::string Options::as(Mesh* UNUSED(mesh)) const { return result; } -template <> int Options::as(Mesh* UNUSED(mesh)) const { +template <> int Options::as(int&& UNUSED(similar_to)) const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); } @@ -258,7 +245,7 @@ template <> int Options::as(Mesh* UNUSED(mesh)) const { return result; } -template <> BoutReal Options::as(Mesh* UNUSED(mesh)) const { +template <> BoutReal Options::as(BoutReal&& UNUSED(similar_to)) const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); } @@ -300,7 +287,7 @@ template <> BoutReal Options::as(Mesh* UNUSED(mesh)) const { return result; } -template <> bool Options::as(Mesh* UNUSED(mesh)) const { +template <> bool Options::as(bool&& UNUSED(similar_to)) const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); } @@ -340,22 +327,47 @@ template <> bool Options::as(Mesh* UNUSED(mesh)) const { return result; } -template <> Field3D Options::as(Mesh* localmesh) const { +template <> Field3D Options::as(Field3D&& similar_to) const { if (!is_value) { throw BoutException("Option %s has no value", full_name.c_str()); } // Mark value as used value_used = true; + + if (bout::utils::holds_alternative(value)) { + Field3D stored_value = bout::utils::get(value); + + // Check that meta-data is consistent + ASSERT1(areFieldsCompatible(stored_value, similar_to)); + + return stored_value; + } + + if (bout::utils::holds_alternative(value)) { + Field2D stored_value = bout::utils::get(value); + + // Check that meta-data is consistent + ASSERT1(areFieldsCompatible(stored_value, similar_to)); + + return Field3D(stored_value); + } try { - return bout::utils::variantStaticCastOrThrow(value); + BoutReal scalar_value = bout::utils::variantStaticCastOrThrow(value); + + Field3D result {emptyFrom(similar_to)}; // Make a field with correct metadata + result = scalar_value; // Fill with the scalar value + return result; } catch (const std::bad_cast &e) { // Convert from a string using FieldFactory if (bout::utils::holds_alternative(value)) { - return FieldFactory::get()->create3D( bout::utils::get(value), this, localmesh); + return FieldFactory::get()->create3D(bout::utils::get(value), this, + similar_to.getMesh(), + similar_to.getLocation()); } else if (bout::utils::holds_alternative>(value)) { + auto localmesh = similar_to.getMesh(); if (!localmesh) { throw BoutException("mesh must be supplied when converting Tensor to Field3D"); } @@ -367,7 +379,8 @@ template <> Field3D Options::as(Mesh* localmesh) const { if (tensor.shape() == std::make_tuple(localmesh->LocalNx, localmesh->LocalNy, localmesh->LocalNz)) { - return Field3D(tensor.getData(), localmesh); + return Field3D(tensor.getData(), localmesh, similar_to.getLocation(), + {similar_to.getDirectionY(), similar_to.getDirectionZ()}); } // If dimension sizes not the same, may be able // to select a region from it using Mesh e.g. if this @@ -379,22 +392,38 @@ template <> Field3D Options::as(Mesh* localmesh) const { full_name.c_str()); } -template <> Field2D Options::as(Mesh* localmesh) const { +template <> Field2D Options::as(Field2D&& similar_to) const { if (!is_value) { throw BoutException("Option %s has no value", full_name.c_str()); } // Mark value as used value_used = true; + + if (bout::utils::holds_alternative(value)) { + Field2D stored_value = bout::utils::get(value); + + // Check that meta-data is consistent + ASSERT1(areFieldsCompatible(stored_value, similar_to)); + + return stored_value; + } try { - return bout::utils::variantStaticCastOrThrow(value); + BoutReal scalar_value = bout::utils::variantStaticCastOrThrow(value); + + Field2D result {emptyFrom(similar_to)}; // Make a field with correct metadata + result = scalar_value; // Fill with the scalar value + return result; } catch (const std::bad_cast &e) { // Convert from a string using FieldFactory if (bout::utils::holds_alternative(value)) { - return FieldFactory::get()->create2D( bout::utils::get(value), this, localmesh); + return FieldFactory::get()->create2D(bout::utils::get(value), this, + similar_to.getMesh(), + similar_to.getLocation()); } else if (bout::utils::holds_alternative>(value)) { + auto localmesh = similar_to.getMesh(); if (!localmesh) { throw BoutException("mesh must be supplied when converting Matrix to Field2D"); } @@ -405,7 +434,8 @@ template <> Field2D Options::as(Mesh* localmesh) const { // Check if the dimension sizes are the same as a Field3D if (matrix.shape() == std::make_tuple(localmesh->LocalNx, localmesh->LocalNy)) { - return Field2D(matrix.getData(), localmesh); + return Field2D(matrix.getData(), localmesh, similar_to.getLocation(), + {similar_to.getDirectionY(), similar_to.getDirectionZ()}); } } } diff --git a/tests/unit/sys/test_options_fields.cxx b/tests/unit/sys/test_options_fields.cxx index 5fdfc58645..c2b6939b6f 100644 --- a/tests/unit/sys/test_options_fields.cxx +++ b/tests/unit/sys/test_options_fields.cxx @@ -76,7 +76,16 @@ TEST_F(OptionsFieldTest, RetrieveField2DfromField3D) { Field3D field = 1.2; options = field; - EXPECT_THROW(Field2D value = options.as(bout::globals::mesh), BoutException); + EXPECT_THROW(Field2D value = options.as(), BoutException); +} + +TEST_F(OptionsFieldTest, RetrieveField3DfromField2D) { + Options options; + Field2D field = 1.2; + options = field; + + Field3D value = options.as(); + EXPECT_DOUBLE_EQ(value(0,1,0), 1.2); } TEST_F(OptionsFieldTest, RetrieveStringfromField3D) { @@ -103,7 +112,7 @@ TEST_F(OptionsFieldTest, RetrieveField3DfromString) { WithQuietOutput quiet{output_info}; - Field3D other = options.as(bout::globals::mesh); + Field3D other = options.as(); EXPECT_DOUBLE_EQ(other(0,1,0), 3.0); EXPECT_DOUBLE_EQ(other(0,0,1), 3.0); @@ -113,7 +122,7 @@ TEST_F(OptionsFieldTest, RetrieveField2DfromString) { Options options; options = "1 + 2"; - Field2D other = options.as(bout::globals::mesh); + Field2D other = options.as(); EXPECT_DOUBLE_EQ(other(0,1,0), 3.0); EXPECT_DOUBLE_EQ(other(0,0,1), 3.0); @@ -123,6 +132,6 @@ TEST_F(OptionsFieldTest, RetrieveField2DfromBadString) { Options options; options = "1 + "; - EXPECT_THROW(Field2D other = options.as(bout::globals::mesh), ParseException); + EXPECT_THROW(Field2D other = options.as(), ParseException); } From e443987e7cf41f15b42e2c0e66d4a5809a613584 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 2 Apr 2019 00:11:00 +0100 Subject: [PATCH 1223/1783] Put OptionsNetCDF into bout::experimental For now put into a namespace so that the API can be modified while still under development. --- include/options_netcdf.hxx | 12 ++++++++++++ manual/sphinx/user_docs/bout_options.rst | 5 ++++- src/sys/options/options_netcdf.cxx | 13 +++++++++++++ .../test-options-netcdf/test-options-netcdf.cxx | 2 ++ tests/unit/sys/test_options_netcdf.cxx | 2 ++ 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/options_netcdf.hxx b/include/options_netcdf.hxx index 5b4e171298..db7145511c 100644 --- a/include/options_netcdf.hxx +++ b/include/options_netcdf.hxx @@ -11,6 +11,9 @@ #include "boutexception.hxx" #include "options.hxx" +namespace bout { +namespace experimental { + class OptionsNetCDF { public: enum class FileMode { @@ -31,12 +34,18 @@ public: } }; +} +} + #else #include #include "options.hxx" +namespace bout { +namespace experimental { + class OptionsNetCDF { public: enum class FileMode { @@ -62,6 +71,9 @@ private: std::map time_index; }; +} +} + #endif #endif // __OPTIONS_NETCDF_H__ diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index 83fa40d7ab..0e785f8803 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -652,7 +652,10 @@ Reading and writing to NetCDF ----------------------------- If NetCDF4 support is enabled, then the ``OptionsNetCDF`` class -provides an experimental way to read and write options. +provides an experimental way to read and write options. To use this class:: + + #include "options_netcdf.hxx" + using bout::experimental::OptionsNetCDF; Examples are in integrated test ``tests/integrated/test-options-netcdf/`` diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 2ad893220b..80d96f98b7 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -116,6 +116,10 @@ void readGroup(const std::string& filename, NcGroup group, Options& result) { } } // namespace + +namespace bout { +namespace experimental { + Options OptionsNetCDF::read() { // Open file NcFile dataFile(filename, NcFile::read); @@ -130,6 +134,9 @@ Options OptionsNetCDF::read() { return result; } +} // experimental +} // bout + namespace { /// Convert variant into NcType @@ -505,6 +512,9 @@ void writeGroup(const Options& options, NcGroup group, } // namespace +namespace bout { +namespace experimental { + /// Write options to file void OptionsNetCDF::write(const Options& options) { // Check the file mode to use @@ -522,4 +532,7 @@ void OptionsNetCDF::write(const Options& options) { writeGroup(options, dataFile, time_index); } +} // experimental +} // bout + #endif // NCDF4 diff --git a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx index 183dfb9ecf..3c019a33dd 100644 --- a/tests/integrated/test-options-netcdf/test-options-netcdf.cxx +++ b/tests/integrated/test-options-netcdf/test-options-netcdf.cxx @@ -4,6 +4,8 @@ #include "options_netcdf.hxx" #include "optionsreader.hxx" +using bout::experimental::OptionsNetCDF; + int main(int argc, char** argv) { BoutInitialise(argc, argv); diff --git a/tests/unit/sys/test_options_netcdf.cxx b/tests/unit/sys/test_options_netcdf.cxx index 212538a475..98e92cff55 100644 --- a/tests/unit/sys/test_options_netcdf.cxx +++ b/tests/unit/sys/test_options_netcdf.cxx @@ -9,6 +9,8 @@ #include "test_extras.hxx" #include "options_netcdf.hxx" +using bout::experimental::OptionsNetCDF; + #include /// Global mesh From 9250e3efb5ff5df241ed21492d508a7612aef34a Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 2 Apr 2019 00:11:59 +0100 Subject: [PATCH 1224/1783] Document more options, make some const Add const to options which are not modified after reading. Add some documentation to some Laplacian PETSc options. --- .../laplace/impls/petsc/petsc_laplace.cxx | 22 ++++++++++--------- src/invert/laplacexy/laplacexy.cxx | 16 +++++++------- .../laplacexz/impls/petsc/laplacexz-petsc.cxx | 14 ++++++------ 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.cxx b/src/invert/laplace/impls/petsc/petsc_laplace.cxx index fe9a4f2c62..6c6fb29dc1 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.cxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.cxx @@ -276,14 +276,16 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc, Mesh *mesh_in) : KSPCreate( comm, &ksp ); // Get KSP Solver Type (Generalizes Minimal RESidual is the default) - std::string type; - opts->get("ksptype", ksptype, KSP_GMRES); - + std::string type = (*opts)["ksptype"] + .doc("KSP solver type").withDefault(KSP_GMRES); + // Get preconditioner type // WARNING: only a few of these options actually make sense: see the // PETSc documentation to work out which they are (possibly // pbjacobi, sor might be useful choices?) - opts->get("pctype", pctype, "none", true); + pctype = (*opts)["pctype"] + .doc("Preconditioner type. See the PETSc documentation for options") + .withDefault("none"); // Let "user" be a synonym for "shell" if (pctype == "user") { @@ -297,13 +299,13 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc, Mesh *mesh_in) : opts->get("gmres_max_steps",gmres_max_steps,30,true); // Get Tolerances for KSP solver - opts->get("rtol",rtol,pow(10.0,-5),true); - opts->get("atol",atol,pow(10.0,-50),true); - opts->get("dtol",dtol,pow(10.0,5),true); - opts->get("maxits",maxits,pow(10,5),true); + rtol = (*opts)["rtol"].doc("Relative tolerance for KSP solver").withDefault(1e-5); + atol = (*opts)["atol"].doc("Absolute tolerance for KSP solver").withDefault(1e-50); + dtol = (*opts)["dtol"].doc("Divergence tolerance for KSP solver").withDefault(1e5); + maxits = (*opts)["maxits"].doc("Maximum number of KSP iterations").withDefault(100000); // Get direct solver switch - opts->get("direct", direct, false); + direct = (*opts)["direct"].doc("Use direct (LU) solver?").withDefault(false); if (direct) { output << endl << "Using LU decompostion for direct solution of system" << endl << endl; } @@ -311,7 +313,7 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc, Mesh *mesh_in) : pcsolve = nullptr; if (pctype == PCSHELL) { - OPTION(opts, rightprec, true); // Right preconditioning by default + rightprec = (*opts)["rightprec"].doc("Right preconditioning?").withDefault(true); // Options for preconditioner are in a subsection pcsolve = Laplacian::create(opts->getSection("precon")); diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index 4cd5f3fafa..aed537935b 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -227,21 +227,21 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) // Convergence Parameters. Solution is considered converged if |r_k| < max( rtol * |b| , atol ) // where r_k = b - Ax_k. The solution is considered diverged if |r_k| > dtol * |b|. - BoutReal rtol = (*opt)["rtol"].doc("Relative tolerance").withDefault(1e-5); - BoutReal atol = (*opt)["atol"] + const BoutReal rtol = (*opt)["rtol"].doc("Relative tolerance").withDefault(1e-5); + const BoutReal atol = (*opt)["atol"] .doc("Absolute tolerance. The solution is considered converged if |Ax-b| " "< max( rtol * |b| , atol )") .withDefault(1e-10); - BoutReal dtol = (*opt)["dtol"] + const BoutReal dtol = (*opt)["dtol"] .doc("The solution is considered diverged if |Ax-b| > dtol * |b|") .withDefault(1e3); - int maxits = (*opt)["maxits"].doc("Maximum iterations").withDefault(100000); + const int maxits = (*opt)["maxits"].doc("Maximum iterations").withDefault(100000); // Get KSP Solver Type - std::string ksptype = (*opt)["ksptype"].doc("KSP solver type").withDefault("gmres"); + const std::string ksptype = (*opt)["ksptype"].doc("KSP solver type").withDefault("gmres"); // Get PC type - std::string pctype = (*opt)["pctype"].doc("Preconditioner type").withDefault("none"); + const std::string pctype = (*opt)["pctype"].doc("Preconditioner type").withDefault("none"); KSPSetType( ksp, ksptype.c_str() ); KSPSetTolerances( ksp, rtol, atol, dtol, maxits ); @@ -251,12 +251,12 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) KSPGetPC(ksp,&pc); PCSetType(pc, pctype.c_str()); - if(pctype == "shell") { + if (pctype == "shell") { // Using tridiagonal solver as preconditioner PCShellSetApply(pc,laplacePCapply); PCShellSetContext(pc,this); - bool rightprec = (*opt)["rightprec"].doc("Use right preconditioning?").withDefault(true); + const bool rightprec = (*opt)["rightprec"].doc("Use right preconditioning?").withDefault(true); if (rightprec) { KSPSetPCSide(ksp, PC_RIGHT); // Right preconditioning } else { diff --git a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx index 182fa63ec7..cde72ae4ab 100644 --- a/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx +++ b/src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx @@ -129,23 +129,23 @@ LaplaceXZpetsc::LaplaceXZpetsc(Mesh *m, Options *opt, const CELL_LOC loc) // Convergence Parameters. Solution is considered converged if |r_k| < max( rtol * |b| , atol ) // where r_k = b - Ax_k. The solution is considered diverged if |r_k| > dtol * |b|. - BoutReal rtol = (*opt)["rtol"].doc("Relative tolerance").withDefault(1e-5); - BoutReal atol = (*opt)["atol"] + const BoutReal rtol = (*opt)["rtol"].doc("Relative tolerance").withDefault(1e-5); + const BoutReal atol = (*opt)["atol"] .doc("Absolute tolerance. The solution is considered converged if |Ax-b| " "< max( rtol * |b| , atol )") .withDefault(1e-10); - BoutReal dtol = (*opt)["dtol"] + const BoutReal dtol = (*opt)["dtol"] .doc("The solution is considered diverged if |Ax-b| > dtol * |b|") .withDefault(1e3); - int maxits = (*opt)["maxits"].doc("Maximum iterations").withDefault(100000); + const int maxits = (*opt)["maxits"].doc("Maximum iterations").withDefault(100000); // Get KSP Solver Type - std::string ksptype = (*opt)["ksptype"].doc("KSP solver type").withDefault("gmres"); + const std::string ksptype = (*opt)["ksptype"].doc("KSP solver type").withDefault("gmres"); // Get PC type - std::string pctype = (*opt)["pctype"].doc("Preconditioner type").withDefault("none"); + const std::string pctype = (*opt)["pctype"].doc("Preconditioner type").withDefault("none"); - std::string factor_package = (*opt)["factor_package"] + const std::string factor_package = (*opt)["factor_package"] .doc("Package to use in preconditioner. Passed to PCFactorSetMatSolver") .withDefault("petsc"); From ef4eb12795764e8fdb46d08f406f77099853648a Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 2 Apr 2019 00:21:24 +0100 Subject: [PATCH 1225/1783] Remove unused variable in petsc laplace Codacy spotted. Previous commit misread old code and resulted in assignment to variable which is never used. --- src/invert/laplace/impls/petsc/petsc_laplace.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.cxx b/src/invert/laplace/impls/petsc/petsc_laplace.cxx index 6c6fb29dc1..2945b03768 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.cxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.cxx @@ -276,8 +276,7 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc, Mesh *mesh_in) : KSPCreate( comm, &ksp ); // Get KSP Solver Type (Generalizes Minimal RESidual is the default) - std::string type = (*opts)["ksptype"] - .doc("KSP solver type").withDefault(KSP_GMRES); + ksptype = (*opts)["ksptype"].doc("KSP solver type").withDefault(KSP_GMRES); // Get preconditioner type // WARNING: only a few of these options actually make sense: see the From d59dc65613694d8d9654c0d29a0566fa0a233d6d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 2 Apr 2019 10:34:58 +0100 Subject: [PATCH 1226/1783] Share FakeSolver between Solver and SolverFactory tests --- tests/unit/solver/test_fakesolver.cxx | 5 ++ tests/unit/solver/test_fakesolver.hxx | 80 ++++++++++++++++++++++++ tests/unit/solver/test_solver.cxx | 78 +++-------------------- tests/unit/solver/test_solverfactory.cxx | 23 +++---- 4 files changed, 101 insertions(+), 85 deletions(-) create mode 100644 tests/unit/solver/test_fakesolver.cxx create mode 100644 tests/unit/solver/test_fakesolver.hxx diff --git a/tests/unit/solver/test_fakesolver.cxx b/tests/unit/solver/test_fakesolver.cxx new file mode 100644 index 0000000000..b36241ecd6 --- /dev/null +++ b/tests/unit/solver/test_fakesolver.cxx @@ -0,0 +1,5 @@ +#include "test_fakesolver.hxx" + +namespace { +RegisterSolver register_fake_solver("fake_solver"); +} diff --git a/tests/unit/solver/test_fakesolver.hxx b/tests/unit/solver/test_fakesolver.hxx new file mode 100644 index 0000000000..af491ad3be --- /dev/null +++ b/tests/unit/solver/test_fakesolver.hxx @@ -0,0 +1,80 @@ +#ifndef FAKESOLVER_H +#define FAKESOLVER_H + +#include "gtest/gtest.h" + +#include "bout/solver.hxx" +#include "bout/solverfactory.hxx" + +#include +#include +#include + +class FakeSolver : public Solver { +public: + FakeSolver(Options* options) : Solver(options) { has_constraints = true; } + ~FakeSolver() = default; + + int run() override { + run_called = true; + return (*options)["number"].withDefault(0); + } + bool run_called{false}; + + int init(int nout, BoutReal tstep) override { + init_called = true; + if (Solver::init(nout, tstep)) { + return 1; + } + return 0; + } + bool init_called{false}; + + void changeHasConstraints(bool new_value) { has_constraints = new_value; } + + auto listField2DNames() -> std::vector { + std::vector result{}; + std::transform(begin(f2d), end(f2d), std::back_inserter(result), + [](const VarStr& f) { return f.name; }); + return result; + } + + auto listField3DNames() -> std::vector { + std::vector result{}; + std::transform(begin(f3d), end(f3d), std::back_inserter(result), + [](const VarStr& f) { return f.name; }); + return result; + } + + auto listVector2DNames() -> std::vector { + std::vector result{}; + std::transform(begin(v2d), end(v2d), std::back_inserter(result), + [](const VarStr& f) { return f.name; }); + return result; + } + + auto listVector3DNames() -> std::vector { + std::vector result{}; + std::transform(begin(v3d), end(v3d), std::back_inserter(result), + [](const VarStr& f) { return f.name; }); + return result; + } + + // Shims for protected functions + auto getMaxTimestepShim() const -> BoutReal { return max_dt; } + auto getLocalNShim() -> int { return getLocalN(); } + auto haveUserPreconShim() -> bool { return have_user_precon(); } + auto runPreconShim(BoutReal t, BoutReal gamma, BoutReal delta) -> int { + return run_precon(t, gamma, delta); + } + auto globalIndexShim(int local_start) -> Field3D { return globalIndex(local_start); } + auto getMonitorsShim() const -> const std::list& { return getMonitors(); } + auto callMonitorsShim(BoutReal simtime, int iter, int NOUT) -> int { + return call_monitors(simtime, iter, NOUT); + } + auto callTimestepMonitorsShim(BoutReal simtime, BoutReal lastdt) -> int { + return call_timestep_monitors(simtime, lastdt); + } +}; + +#endif // FAKESOLVER_H diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx index c7acc05b69..6fa343013a 100644 --- a/tests/unit/solver/test_solver.cxx +++ b/tests/unit/solver/test_solver.cxx @@ -4,6 +4,7 @@ #include "field2d.hxx" #include "field3d.hxx" #include "test_extras.hxx" +#include "test_fakesolver.hxx" #include "bout/solver.hxx" #include "bout/solverfactory.hxx" @@ -12,75 +13,6 @@ #include namespace { -class FakeSolver : public Solver { -public: - FakeSolver(Options* options) : Solver(options) { has_constraints = true; } - ~FakeSolver() = default; - - int run() override { - run_called = true; - return 0; - } - bool run_called{false}; - - int init(int nout, BoutReal tstep) override { - init_called = true; - if (Solver::init(nout, tstep)) { - return 1; - } - return 0; - } - bool init_called{false}; - - void changeHasConstraints(bool new_value) { has_constraints = new_value; } - - auto listField2DNames() -> std::vector { - std::vector result{}; - std::transform(begin(f2d), end(f2d), std::back_inserter(result), - [](const VarStr& f) { return f.name; }); - return result; - } - - auto listField3DNames() -> std::vector { - std::vector result{}; - std::transform(begin(f3d), end(f3d), std::back_inserter(result), - [](const VarStr& f) { return f.name; }); - return result; - } - - auto listVector2DNames() -> std::vector { - std::vector result{}; - std::transform(begin(v2d), end(v2d), std::back_inserter(result), - [](const VarStr& f) { return f.name; }); - return result; - } - - auto listVector3DNames() -> std::vector { - std::vector result{}; - std::transform(begin(v3d), end(v3d), std::back_inserter(result), - [](const VarStr& f) { return f.name; }); - return result; - } - - // Shims for protected functions - auto getMaxTimestepShim() const -> BoutReal { return max_dt; } - auto getLocalNShim() -> int { return getLocalN(); } - auto haveUserPreconShim() -> bool { return have_user_precon(); } - auto runPreconShim(BoutReal t, BoutReal gamma, BoutReal delta) -> int { - return run_precon(t, gamma, delta); - } - auto globalIndexShim(int local_start) -> Field3D { return globalIndex(local_start); } - auto getMonitorsShim() const -> const std::list& { return getMonitors(); } - auto callMonitorsShim(BoutReal simtime, int iter, int NOUT) -> int { - return call_monitors(simtime, iter, NOUT); - } - auto callTimestepMonitorsShim(BoutReal simtime, BoutReal lastdt) -> int { - return call_timestep_monitors(simtime, lastdt); - } -}; - -RegisterSolver register_fake("fake_solver"); - /// A sentinel value for whether a `FakeMonitor` has been called or not constexpr static int called_sentinel{-999}; @@ -134,7 +66,9 @@ TEST_F(SolverTest, Create) { Options::root()["solver"]["type"] = "fake_solver"; auto solver = Solver::create(); - EXPECT_EQ(solver->run(), 42); + solver->run(); + + EXPECT_TRUE(static_cast(solver)->run_called); Options::cleanup(); } @@ -154,7 +88,9 @@ TEST_F(SolverTest, CreateFromOptions) { options["type"] = "fake_solver"; auto solver = Solver::create(&options); - EXPECT_EQ(solver->run(), 42); + solver->run(); + + EXPECT_TRUE(static_cast(solver)->run_called); } TEST_F(SolverTest, CreateFromName) { diff --git a/tests/unit/solver/test_solverfactory.cxx b/tests/unit/solver/test_solverfactory.cxx index 89da04b6fd..bcdb0071fa 100644 --- a/tests/unit/solver/test_solverfactory.cxx +++ b/tests/unit/solver/test_solverfactory.cxx @@ -2,22 +2,12 @@ #include "boutexception.hxx" #include "test_extras.hxx" +#include "test_fakesolver.hxx" #include "bout/solver.hxx" #include "bout/solverfactory.hxx" #include -namespace { -class FakeSolver : public Solver { -public: - FakeSolver(Options* options) : Solver(options) {} - ~FakeSolver() = default; - int run() { return (*options)["number"].withDefault(42); } -}; - -RegisterSolver register_fake("fake_solver"); -} // namespace - TEST(SolverFactoryTest, GetInstance) { EXPECT_NE(SolverFactory::getInstance(), nullptr); } TEST(SolverFactoryTest, GetDefaultSolverType) { @@ -38,7 +28,9 @@ TEST(SolverFactoryTest, Create) { Options::root()["solver"]["type"] = "fake_solver"; auto solver = SolverFactory::getInstance()->createSolver(); - EXPECT_EQ(solver->run(), 42); + solver->run(); + + EXPECT_TRUE(static_cast(solver)->run_called); Options::cleanup(); } @@ -58,7 +50,9 @@ TEST(SolverFactoryTest, CreateFromOptions) { options["type"] = "fake_solver"; auto solver = SolverFactory::getInstance()->createSolver(&options); - EXPECT_EQ(solver->run(), 42); + solver->run(); + + EXPECT_TRUE(static_cast(solver)->run_called); } TEST(SolverFactoryTest, CreateFromName) { @@ -111,5 +105,6 @@ TEST(SolverFactoryTest, BadCreateFromNameAndOptions) { WithQuietOutput quiet{output_info}; Options options; - EXPECT_THROW(SolverFactory::getInstance()->createSolver("bad_solver", &options), BoutException); + EXPECT_THROW(SolverFactory::getInstance()->createSolver("bad_solver", &options), + BoutException); } From 25feaf9c906c59ac9db114d486675ab21eba7416 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 2 Apr 2019 10:35:19 +0100 Subject: [PATCH 1227/1783] Use BoutComm instead of MPI_COMM_WORLD in Solver::call_monitors --- src/solver/solver.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index b5b897b295..872b438ff7 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -636,7 +636,7 @@ void Solver::removeMonitor(Monitor * f) { extern bool user_requested_exit; int Solver::call_monitors(BoutReal simtime, int iter, int NOUT) { bool abort; - MPI_Allreduce(&user_requested_exit, &abort, 1, MPI_C_BOOL, MPI_LOR, MPI_COMM_WORLD); + MPI_Allreduce(&user_requested_exit, &abort, 1, MPI_C_BOOL, MPI_LOR, BoutComm::get()); if (abort) { NOUT = iter + 1; } @@ -666,7 +666,7 @@ int Solver::call_monitors(BoutReal simtime, int iter, int NOUT) { } // Check if any of the monitors has asked to quit - MPI_Allreduce(&user_requested_exit, &abort, 1, MPI_C_BOOL, MPI_LOR, MPI_COMM_WORLD); + MPI_Allreduce(&user_requested_exit, &abort, 1, MPI_C_BOOL, MPI_LOR, BoutComm::get()); if (iter == NOUT || abort) { for (const auto& it : monitors) { From 56ae88d3dabe5dba53e9ee546580293549625e0c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 2 Apr 2019 11:13:09 +0100 Subject: [PATCH 1228/1783] Better testing of Solver::run/solve failure --- tests/unit/solver/test_fakesolver.hxx | 7 +- tests/unit/solver/test_solver.cxx | 117 +++++++++++++++++++++-- tests/unit/solver/test_solverfactory.cxx | 12 +-- 3 files changed, 122 insertions(+), 14 deletions(-) diff --git a/tests/unit/solver/test_fakesolver.hxx b/tests/unit/solver/test_fakesolver.hxx index af491ad3be..e175f3a0f7 100644 --- a/tests/unit/solver/test_fakesolver.hxx +++ b/tests/unit/solver/test_fakesolver.hxx @@ -17,7 +17,10 @@ public: int run() override { run_called = true; - return (*options)["number"].withDefault(0); + if ((*options)["throw_run"].withDefault(false)) { + throw BoutException("Deliberate exception in FakeSolver::run"); + } + return (*options)["fail_run"].withDefault(0); } bool run_called{false}; @@ -26,7 +29,7 @@ public: if (Solver::init(nout, tstep)) { return 1; } - return 0; + return (*options)["fail_init"].withDefault(0); } bool init_called{false}; diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx index 6fa343013a..c272078792 100644 --- a/tests/unit/solver/test_solver.cxx +++ b/tests/unit/solver/test_solver.cxx @@ -96,11 +96,11 @@ TEST_F(SolverTest, CreateFromOptions) { TEST_F(SolverTest, CreateFromName) { WithQuietOutput quiet{output_info}; - constexpr auto number = 13; - Options::root()["solver"]["number"] = number; + constexpr auto fail_run = 13; + Options::root()["solver"]["fail_run"] = fail_run; auto solver = Solver::create("fake_solver"); - EXPECT_EQ(solver->run(), number); + EXPECT_EQ(solver->run(), fail_run); Options::cleanup(); } @@ -108,12 +108,12 @@ TEST_F(SolverTest, CreateFromName) { TEST_F(SolverTest, CreateFromNameAndOptions) { WithQuietOutput quiet{output_info}; - constexpr auto number = 13; + constexpr auto fail_run = 13; Options options; - options["number"] = number; + options["fail_run"] = fail_run; auto solver = Solver::create("fake_solver", &options); - EXPECT_EQ(solver->run(), number); + EXPECT_EQ(solver->run(), fail_run); } TEST_F(SolverTest, BadCreate) { @@ -846,6 +846,47 @@ TEST_F(SolverTest, BasicSolve) { EXPECT_TRUE(solver.run_called); } +TEST_F(SolverTest, SolveBadInit) { + Options options; + options["fail_init"] = -1; + FakeSolver solver{&options}; + + Options::root()["dump_on_restart"] = false; + + EXPECT_THROW(solver.solve(), BoutException); + + EXPECT_TRUE(solver.init_called); + EXPECT_FALSE(solver.run_called); +} + +TEST_F(SolverTest, SolveBadRun) { + Options options; + options["fail_run"] = -1; + FakeSolver solver{&options}; + + Options::root()["dump_on_restart"] = false; + + EXPECT_EQ(solver.solve(), -1); + + EXPECT_TRUE(solver.init_called); + EXPECT_TRUE(solver.run_called); +} + +TEST_F(SolverTest, SolveThrowRun) { + WithQuietOutput quiet_error{output_error}; + + Options options; + options["throw_run"] = true; + FakeSolver solver{&options}; + + Options::root()["dump_on_restart"] = false; + + EXPECT_THROW(solver.solve(), BoutException); + + EXPECT_TRUE(solver.init_called); + EXPECT_TRUE(solver.run_called); +} + TEST_F(SolverTest, SolveFixDefaultTimestep) { Options options; FakeSolver solver{&options}; @@ -874,3 +915,67 @@ TEST_F(SolverTest, SolveFixDefaultTimestep) { EXPECT_EQ(even_smaller_timestep.last_called, 99); EXPECT_EQ(larger_timestep.last_called, called_sentinel); } + +TEST_F(SolverTest, SolveFixDefaultTimestepBad) { + Options options; + FakeSolver solver{&options}; + + Options::root()["dump_on_restart"] = false; + + FakeMonitor default_timestep; + FakeMonitor smaller_timestep{0.1}; + + solver.addMonitor(&default_timestep); + solver.addMonitor(&smaller_timestep); + + EXPECT_THROW(solver.solve(100, 3.142), BoutException); + + EXPECT_FALSE(solver.init_called); + EXPECT_FALSE(solver.run_called); +} + +TEST_F(SolverTest, SolveFixDefaultTimestepSmaller) { + Options options; + FakeSolver solver{&options}; + + Options::root()["dump_on_restart"] = false; + + FakeMonitor default_timestep; + FakeMonitor smaller_timestep{0.1}; + + solver.addMonitor(&default_timestep); + solver.addMonitor(&smaller_timestep); + + EXPECT_NO_THROW(solver.solve(100, 0.01)); + + EXPECT_TRUE(solver.init_called); + EXPECT_TRUE(solver.run_called); + + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, 99, 0)); + + EXPECT_EQ(default_timestep.last_called, 99); + EXPECT_EQ(smaller_timestep.last_called, 9); +} + +TEST_F(SolverTest, SolveFixDefaultTimestepLarger) { + Options options; + FakeSolver solver{&options}; + + Options::root()["dump_on_restart"] = false; + + FakeMonitor default_timestep; + FakeMonitor smaller_timestep{0.1}; + + solver.addMonitor(&default_timestep); + solver.addMonitor(&smaller_timestep); + + EXPECT_NO_THROW(solver.solve(100, 1.)); + + EXPECT_TRUE(solver.init_called); + EXPECT_TRUE(solver.run_called); + + EXPECT_NO_THROW(solver.callMonitorsShim(0.0, 99, 0)); + + EXPECT_EQ(default_timestep.last_called, 9); + EXPECT_EQ(smaller_timestep.last_called, 99); +} diff --git a/tests/unit/solver/test_solverfactory.cxx b/tests/unit/solver/test_solverfactory.cxx index bcdb0071fa..439214a2d4 100644 --- a/tests/unit/solver/test_solverfactory.cxx +++ b/tests/unit/solver/test_solverfactory.cxx @@ -58,11 +58,11 @@ TEST(SolverFactoryTest, CreateFromOptions) { TEST(SolverFactoryTest, CreateFromName) { WithQuietOutput quiet{output_info}; - constexpr auto number = 13; - Options::root()["solver"]["number"] = number; + constexpr auto fail_run = 13; + Options::root()["solver"]["fail_run"] = fail_run; auto solver = SolverFactory::getInstance()->createSolver("fake_solver"); - EXPECT_EQ(solver->run(), number); + EXPECT_EQ(solver->run(), fail_run); Options::cleanup(); } @@ -70,12 +70,12 @@ TEST(SolverFactoryTest, CreateFromName) { TEST(SolverFactoryTest, CreateFromNameAndOptions) { WithQuietOutput quiet{output_info}; - constexpr auto number = 13; + constexpr auto fail_run = 31; Options options; - options["number"] = number; + options["fail_run"] = fail_run; auto solver = SolverFactory::getInstance()->createSolver("fake_solver", &options); - EXPECT_EQ(solver->run(), number); + EXPECT_EQ(solver->run(), fail_run); } TEST(SolverFactoryTest, BadCreate) { From 84cae3aabf6b5b975db5c47f7a75a8981c264bd7 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 2 Apr 2019 14:51:20 +0100 Subject: [PATCH 1229/1783] Add filledFrom function for fields Like emptyFrom and zeroFrom, but fills the field with a given scalar value. --- include/field.hxx | 10 ++++++++++ src/sys/options.cxx | 10 ++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index cb8067cd56..6682ce87fa 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -206,6 +206,16 @@ inline T zeroFrom(const T& f) { return result; } +/// Return a field of some type derived from Field, with metadata copied from +/// another field and a data array allocated and filled with the given value. +template +inline T filledFrom(const T& f, BoutReal fill_value) { + static_assert(std::is_base_of::value, "emptyFrom only works on Fields"); + T result{emptyFrom(f)}; + result = fill_value; + return result; +} + /// Unary + operator. This doesn't do anything template T operator+(const T& f) {return f;} diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 48eeea357e..67a5d33cd1 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -356,9 +356,8 @@ template <> Field3D Options::as(Field3D&& similar_to) const { try { BoutReal scalar_value = bout::utils::variantStaticCastOrThrow(value); - Field3D result {emptyFrom(similar_to)}; // Make a field with correct metadata - result = scalar_value; // Fill with the scalar value - return result; + // Get metadata from similar_to, fill field with scalar_value + return filledFrom(similar_to, scalar_value); } catch (const std::bad_cast &e) { // Convert from a string using FieldFactory @@ -412,9 +411,8 @@ template <> Field2D Options::as(Field2D&& similar_to) const { try { BoutReal scalar_value = bout::utils::variantStaticCastOrThrow(value); - Field2D result {emptyFrom(similar_to)}; // Make a field with correct metadata - result = scalar_value; // Fill with the scalar value - return result; + // Get metadata from similar_to, fill field with scalar_value + return filledFrom(similar_to, scalar_value); } catch (const std::bad_cast &e) { // Convert from a string using FieldFactory From 97a8ee04dc5f9b19cfe48f5d9a7e7d89ddb7ff1b Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 2 Apr 2019 15:00:37 +0100 Subject: [PATCH 1230/1783] Small option doc improvements in bout++.cxx --- src/bout++.cxx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 44d024839b..06e415d362 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -517,7 +517,9 @@ void setRunFinishInfo(Options& options) { Datafile setupDumpFile(Options& options, Mesh& mesh, const std::string& data_dir) { // Check if restarting - const bool append = options["append"].withDefault(false); + const bool append = options["append"] + .doc("Add output data to existing (dump) files?") + .withDefault(false); // Get file extensions const auto dump_ext = options["dump_format"].withDefault(std::string{"nc"}); @@ -677,16 +679,16 @@ int BoutMonitor::call(Solver* solver, BoutReal t, int iter, int NOUT) { /// Get some options auto& options = Options::root(); wall_limit = options["wall_limit"] - .doc("Wall time limit in hours. By default (< 0), no limit") + .doc(_("Wall time limit in hours. By default (< 0), no limit")) .withDefault(-1.0); wall_limit *= 60.0 * 60.0; // Convert from hours to seconds stopCheck = options["stopCheck"] - .doc("Check if a file exists, and exit if it does.") + .doc(_("Check if a file exists, and exit if it does.")) .withDefault(false); if (stopCheck) { stopCheckName = options["stopCheckName"] - .doc("Name of file whose existence triggers a stop") + .doc(_("Name of file whose existence triggers a stop")) .withDefault("BOUT.stop"); // Now add data directory to start of name to ensure we look in a run specific location std::string data_dir = Options::root()["datadir"].withDefault(DEFAULT_DIR); From b06a94e1fc1d2ca31b2dc204acd7785e9bc88348 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 2 Apr 2019 16:26:20 +0100 Subject: [PATCH 1231/1783] Change T&& to const T& in Options::as Not modifying the value inside the function; it's intended that the result is similar to (same type, metadata) the value passed in. Template specialisations have things like `const BoutReal&` because otherwise the specialisation doesn't match the template. --- include/options.hxx | 18 +++++++++--------- src/sys/options.cxx | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index 7c0db962ce..da5f1ae3a1 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -356,7 +356,7 @@ public: /// where the Mesh and cell location are taken from this input. /// template - T as(T&& UNUSED(similar_to) = {}) const { + T as(const T& UNUSED(similar_to) = {}) const { if (!is_value) { throw BoutException("Option %s has no value", full_name.c_str()); } @@ -424,7 +424,7 @@ public: << ")" << std::endl; return def; } - T val = as(std::forward(def)); + T val = as(def); // Check if this was previously set as a default option if (bout::utils::variantEqualTo(attributes.at("source"), DEFAULT_SOURCE)) { // Check that the default values are the same @@ -451,7 +451,7 @@ public: << ")" << std::endl; return def; } - T val = as(std::forward(def)); + T val = as(def); // Check if this was previously set as a default option if (bout::utils::variantEqualTo(attributes.at("source"), DEFAULT_SOURCE)) { // Check that the default values are the same @@ -666,12 +666,12 @@ template<> void Options::assign<>(Tensor val, const std::string source template <> inline bool Options::similar(BoutReal a, BoutReal b) const { return fabs(a - b) < 1e-10; } /// Specialised as routines -template <> std::string Options::as(std::string&& similar_to) const; -template <> int Options::as(int&& similar_to) const; -template <> BoutReal Options::as(BoutReal&& similar_to) const; -template <> bool Options::as(bool&& similar_to) const; -template <> Field2D Options::as(Field2D&& similar_to) const; -template <> Field3D Options::as(Field3D&& similar_to) const; +template <> std::string Options::as(const std::string& similar_to) const; +template <> int Options::as(const int& similar_to) const; +template <> BoutReal Options::as(const BoutReal& similar_to) const; +template <> bool Options::as(const bool& similar_to) const; +template <> Field2D Options::as(const Field2D& similar_to) const; +template <> Field3D Options::as(const Field3D& similar_to) const; /// Define for reading options which passes the variable name #define OPTION(options, var, def) \ diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 67a5d33cd1..9cbd2d54e2 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -170,7 +170,7 @@ void Options::assign<>(Tensor val, const std::string source) { is_value = true; } -template <> std::string Options::as(std::string&& UNUSED(similar_to)) const { +template <> std::string Options::as(const std::string& UNUSED(similar_to)) const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); } @@ -190,7 +190,7 @@ template <> std::string Options::as(std::string&& UNUSED(similar_to return result; } -template <> int Options::as(int&& UNUSED(similar_to)) const { +template <> int Options::as(const int& UNUSED(similar_to)) const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); } @@ -245,7 +245,7 @@ template <> int Options::as(int&& UNUSED(similar_to)) const { return result; } -template <> BoutReal Options::as(BoutReal&& UNUSED(similar_to)) const { +template <> BoutReal Options::as(const BoutReal& UNUSED(similar_to)) const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); } @@ -287,7 +287,7 @@ template <> BoutReal Options::as(BoutReal&& UNUSED(similar_to)) const return result; } -template <> bool Options::as(bool&& UNUSED(similar_to)) const { +template <> bool Options::as(const bool& UNUSED(similar_to)) const { if (!is_value) { throw BoutException(_("Option %s has no value"), full_name.c_str()); } @@ -327,7 +327,7 @@ template <> bool Options::as(bool&& UNUSED(similar_to)) const { return result; } -template <> Field3D Options::as(Field3D&& similar_to) const { +template <> Field3D Options::as(const Field3D& similar_to) const { if (!is_value) { throw BoutException("Option %s has no value", full_name.c_str()); } @@ -391,7 +391,7 @@ template <> Field3D Options::as(Field3D&& similar_to) const { full_name.c_str()); } -template <> Field2D Options::as(Field2D&& similar_to) const { +template <> Field2D Options::as(const Field2D& similar_to) const { if (!is_value) { throw BoutException("Option %s has no value", full_name.c_str()); } From b471ef77f829fd9e7b2635f70653caaff3210fdc Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 2 Apr 2019 17:34:13 +0100 Subject: [PATCH 1232/1783] Support use of parallel slices in D2DYDZ Previously, D2DYDZ was using an explicit loop, doing 2nd order centred differences without taking into account whether yup/ydown should be used. Instead it should be OK to just use DDZ(DDY(f)) since the z-grid spacing is constant and the y-grid spacing does not depend on z, so the order of derivatives is not important. --- src/sys/derivs.cxx | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 5a889525f1..07857888fa 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -339,32 +339,14 @@ const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc, return zeroFrom(f).setLocation(outloc); } -const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, - MAYBE_UNUSED(const std::string& method), REGION UNUSED(region)) { - Coordinates *coords = f.getCoordinates(outloc); - - Field3D result{emptyFrom(f)}; - ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); - result.allocate(); - result.setLocation(f.getLocation()); - ASSERT1(method == "DEFAULT"); - for(int i=f.getMesh()->xstart;i<=f.getMesh()->xend;i++) - for(int j=f.getMesh()->ystart;j<=f.getMesh()->yend;j++) - for(int k=0;kLocalNz;k++) { - int kp = (k+1) % (f.getMesh()->LocalNz); - int km = (k-1+f.getMesh()->LocalNz) % (f.getMesh()->LocalNz); - result(i,j,k) = 0.25*( +(f(i,j+1,kp) - f(i,j-1,kp)) - -(f(i,j+1,km) - f(i,j-1,km)) ) - / (coords->dy(i,j) * coords->dz); - } - // TODO: use region aware implementation - // BOUT_FOR(i, f.getRegion(region)) { - // result[i] = 0.25*( +(f[i.offset(0,1, 1)] - f[i.offset(0,-1, 1)]) - // / (coords->dy[i.yp()]) - // -(f[i.offset(0,1,-1)] - f[i.offset(0,-1,-1)]) - // / (coords->dy[i.ym()])) - // / coords->dz; } - return result; +const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, const std::string& method, + REGION region) { + if (outloc == CELL_ZLOW || f.getLocation() == CELL_ZLOW) { + // Staggering in z, so take y-derivative at f's location. + return DDZ(DDY(f, CELL_DEFAULT, method, region), outloc, method, region); + } else { + return DDZ(DDY(f, outloc, method, region), outloc, method, region); + } } /******************************************************************************* From efbcefa660aa5f0f4291d1b67dac48cac06afc03 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 2 Apr 2019 22:29:22 +0100 Subject: [PATCH 1233/1783] Use lambdas to simplify LaplaceNaulin; improve underrelaxation updates Put repeated code in LaplaceNaulin::solve into lambda functions. Also improve underrelaxation updates: when the relaxation factor needs to be reduced, restart the iteration from the best solution so far, rather than from the beginning. --- .../laplace/impls/naulin/naulin_laplace.cxx | 104 +++++++++++------- 1 file changed, 67 insertions(+), 37 deletions(-) diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index d4e382d79c..32b96ee687 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -202,13 +202,14 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { ASSERT1(Acoef.getLocation() == location); ASSERT1(localmesh == rhs.getMesh() && localmesh == x0.getMesh()); - Field3D x(x0); // Result - Field3D rhsOverD = rhs/Dcoef; // x-component of 1./(C1*D) * Grad_perp(C2) Field3D coef_x = DDX(C2coef, location, DIFF_C2)/C1coef/Dcoef; + // y-component of 1./(C1*D) * Grad_perp(C2) + Field3D coef_y = DDY(C2coef, location, DIFF_C2)/C1coef/Dcoef; + // z-component of 1./(C1*D) * Grad_perp(C2) Field3D coef_z = DDZ(C2coef, location, DIFF_FFT)/C1coef/Dcoef; @@ -246,57 +247,86 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { int underrelax_count = 0; BoutReal underrelax_factor = initial_underrelax_factor; - // Initial values for derivatives of x - Field3D ddx_x = DDX(x, location, DIFF_C2); - Field3D ddz_x = DDZ(x, location, DIFF_FFT); - Field3D b = rhsOverD - (coords->g11*coef_x_AC*ddx_x + coords->g33*coef_z*ddz_x + coords->g13*(coef_x_AC*ddz_x + coef_z*ddx_x)) - AOverD_AC*x; - - while (error_rel>rtol && error_abs>atol) { - - if ( (inner_boundary_flags & INVERT_SET) || (outer_boundary_flags & INVERT_SET) ) + auto calc_b_guess = [&] (const Field3D& x_in) { + // Derivatives of x + Field3D ddx_x = DDX(x_in, location, DIFF_C2); + Field3D ddz_x = DDZ(x_in, location, DIFF_FFT); + return rhsOverD - (coords->g11*coef_x_AC*ddx_x + coords->g33*coef_z*ddz_x + + coords->g13*(coef_x_AC*ddz_x + coef_z*ddx_x)) - AOverD_AC*x_in; + }; + + auto calc_b_x_pair = [&, this] (Field3D b, Field3D& x_guess) { + // Note take a copy of the 'b' argument, because we want to return a copy of it in the + // result + // Is it dangerous to take x_guess by reference, if we will call something like + // b_x_pair = calc_b_x_pair(b_guess, b_x_pair.second); + // ??? + + if ( (inner_boundary_flags & INVERT_SET) || (outer_boundary_flags & INVERT_SET) ) { // This passes in the boundary conditions from x0's guard cells - copy_x_boundaries(x, x0, localmesh); + copy_x_boundaries(x_guess, x0, localmesh); + } - // NB need to pass x in case boundary flags require 'x0', even if - // delp2solver is not iterative and does not use an initial guess - x = delp2solver->solve(b, x); + // NB need to pass x_guess in case boundary flags require 'x0', even if delp2solver is + // not iterative and does not use an initial guess + Field3D x = delp2solver->solve(b, x_guess); localmesh->communicate(x); - // re-calculate the rhs from the new solution - // Use here to calculate an error, can also use for the next iteration - ddx_x = DDX(x, location, DIFF_C2); // can be used also for the next iteration - ddz_x = DDZ(x, location, DIFF_FFT); + return std::pair(b, x); + }; - Field3D bnew = rhsOverD - - (coords->g11*coef_x_AC*ddx_x + coords->g33*coef_z*ddz_x - + coords->g13*(coef_x_AC*ddz_x + coef_z*ddx_x)) - - AOverD_AC*x; + Field3D b = calc_b_guess(x0); + // Need to make a copy of x0 here to make sure we don't change x0 + auto b_x_pair = calc_b_x_pair(b, Field3D(x0).allocate()); + auto b_x_pair_old = b_x_pair; - Field3D error3D = b - bnew; + while (true) { + Field3D bnew = calc_b_guess(b_x_pair.second); + + Field3D error3D = b_x_pair.first - bnew; error_abs = max(abs(error3D, RGN_NOBNDRY), true, RGN_NOBNDRY); error_rel = error_abs / RMS_rhsOverD; - b = underrelax_factor*bnew + (1. - underrelax_factor)*b; + if (error_relmaxits) { + throw BoutException("LaplaceNaulin error: Took more than maxits=%i iterations to converge.", maxits); + } + + output< last_error) { + while (error_abs > last_error) { // Iteration seems to be diverging... try underrelaxing and restart underrelax_factor *= .9; underrelax_count++; - // Set x back to initial guess to restart iteration - x = x0; - ddx_x = DDX(x, location, DIFF_C2); - ddz_x = DDZ(x, location, DIFF_FFT); - b = rhsOverD - (coords->g11*coef_x_AC*ddx_x + coords->g33*coef_z*ddz_x + coords->g13*(coef_x_AC*ddz_x + coef_z*ddx_x)) - AOverD_AC*x; + // Restart from b_x_pair_old - that was our best guess + bnew = calc_b_guess(b_x_pair_old.second); + b_x_pair = calc_b_x_pair(underrelax_factor*bnew + (1. - underrelax_factor)*b_x_pair_old.first, b_x_pair_old.second); + + bnew = calc_b_guess(b_x_pair.second); + + error3D = b_x_pair.first - bnew; + error_abs = max(abs(error3D, RGN_NOBNDRY), true, RGN_NOBNDRY); + error_rel = error_abs / RMS_rhsOverD; + + // effectively another iteration, so increment the counter + count++; + if (count>maxits) { + throw BoutException("LaplaceNaulin error: Took more than maxits=%i iterations to converge.", maxits); + } - last_error = 1.e20; - } else { - last_error = error_abs; + output<maxits) - throw BoutException("LaplaceNaulin error: Took more than maxits=%i iterations to converge.", maxits); + // Might have met convergence criterion while in underrelaxation loop + if (error_rel Date: Wed, 3 Apr 2019 09:35:23 +0100 Subject: [PATCH 1234/1783] Minor tidy-ups for LaplaceNaulin - '/(C1coef*Dcoef)' instead of '/C1coef/Dcoef' - More accurate error message when failing because of too many iterations. --- src/invert/laplace/impls/naulin/naulin_laplace.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index 32b96ee687..b00eb92101 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -205,13 +205,13 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { Field3D rhsOverD = rhs/Dcoef; // x-component of 1./(C1*D) * Grad_perp(C2) - Field3D coef_x = DDX(C2coef, location, DIFF_C2)/C1coef/Dcoef; + Field3D coef_x = DDX(C2coef, location, DIFF_C2)/(C1coef*Dcoef); // y-component of 1./(C1*D) * Grad_perp(C2) - Field3D coef_y = DDY(C2coef, location, DIFF_C2)/C1coef/Dcoef; + Field3D coef_y = DDY(C2coef, location, DIFF_C2)/(C1coef*Dcoef); // z-component of 1./(C1*D) * Grad_perp(C2) - Field3D coef_z = DDZ(C2coef, location, DIFF_FFT)/C1coef/Dcoef; + Field3D coef_z = DDZ(C2coef, location, DIFF_FFT)/(C1coef*Dcoef); Field3D AOverD = Acoef/Dcoef; @@ -291,7 +291,7 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { count++; if (count>maxits) { - throw BoutException("LaplaceNaulin error: Took more than maxits=%i iterations to converge.", maxits); + throw BoutException("LaplaceNaulin error: Not converged within maxits=%i iterations.", maxits); } output<maxits) { - throw BoutException("LaplaceNaulin error: Took more than maxits=%i iterations to converge.", maxits); + throw BoutException("LaplaceNaulin error: Not converged within maxits=%i iterations.", maxits); } output< Date: Wed, 3 Apr 2019 10:19:58 +0100 Subject: [PATCH 1235/1783] Take x_guess argument by value in calc_b_x_pair lambda function We need to modify x_guess's boundary cells, and don't need to change the original value. Also a couple of other minor tidy-ups: - use std::make_pair instead of std::pair - use prefix increment operators instead of postfix, as we don't need to return the old value, which the postfix form does --- .../laplace/impls/naulin/naulin_laplace.cxx | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index b00eb92101..3e265054f1 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -180,7 +180,7 @@ LaplaceNaulin::LaplaceNaulin(Options *opt, const CELL_LOC loc, Mesh *mesh_in) "naulinsolver"+std::to_string(naulinsolver_count)+"_mean_its"); bout::globals::dump.addRepeat(naulinsolver_mean_underrelax_counts, "naulinsolver"+std::to_string(naulinsolver_count)+"_mean_underrelax_counts"); - naulinsolver_count++; + ++naulinsolver_count; } LaplaceNaulin::~LaplaceNaulin() { @@ -204,14 +204,16 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { Field3D rhsOverD = rhs/Dcoef; + Field3D C1TimesD = C1coef*Dcoef; // This is needed several times + // x-component of 1./(C1*D) * Grad_perp(C2) - Field3D coef_x = DDX(C2coef, location, DIFF_C2)/(C1coef*Dcoef); + Field3D coef_x = DDX(C2coef, location, DIFF_C2)/C1TimesD; // y-component of 1./(C1*D) * Grad_perp(C2) - Field3D coef_y = DDY(C2coef, location, DIFF_C2)/(C1coef*Dcoef); + Field3D coef_y = DDY(C2coef, location, DIFF_C2)/C1TimesD; // z-component of 1./(C1*D) * Grad_perp(C2) - Field3D coef_z = DDZ(C2coef, location, DIFF_FFT)/(C1coef*Dcoef); + Field3D coef_z = DDZ(C2coef, location, DIFF_FFT)/C1TimesD; Field3D AOverD = Acoef/Dcoef; @@ -219,7 +221,7 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { // Split coefficients into DC and AC parts so that delp2solver can use DC part. // This allows all-Neumann boundary conditions as long as AOverD_DC is non-zero - Field2D C1coefTimesD_DC = DC(C1coef*Dcoef); + Field2D C1coefTimesD_DC = DC(C1TimesD); Field2D C2coef_DC = DC(C2coef); // Our naming is slightly misleading here, as coef_x_AC may actually have a @@ -255,12 +257,9 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { + coords->g13*(coef_x_AC*ddz_x + coef_z*ddx_x)) - AOverD_AC*x_in; }; - auto calc_b_x_pair = [&, this] (Field3D b, Field3D& x_guess) { + auto calc_b_x_pair = [&, this] (Field3D b, Field3D x_guess) { // Note take a copy of the 'b' argument, because we want to return a copy of it in the // result - // Is it dangerous to take x_guess by reference, if we will call something like - // b_x_pair = calc_b_x_pair(b_guess, b_x_pair.second); - // ??? if ( (inner_boundary_flags & INVERT_SET) || (outer_boundary_flags & INVERT_SET) ) { // This passes in the boundary conditions from x0's guard cells @@ -272,12 +271,12 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { Field3D x = delp2solver->solve(b, x_guess); localmesh->communicate(x); - return std::pair(b, x); + return std::make_pair(b, x); }; Field3D b = calc_b_guess(x0); // Need to make a copy of x0 here to make sure we don't change x0 - auto b_x_pair = calc_b_x_pair(b, Field3D(x0).allocate()); + auto b_x_pair = calc_b_x_pair(b, x0); auto b_x_pair_old = b_x_pair; while (true) { @@ -289,7 +288,7 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { if (error_relmaxits) { throw BoutException("LaplaceNaulin error: Not converged within maxits=%i iterations.", maxits); } @@ -299,7 +298,7 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { while (error_abs > last_error) { // Iteration seems to be diverging... try underrelaxing and restart underrelax_factor *= .9; - underrelax_count++; + ++underrelax_count; // Restart from b_x_pair_old - that was our best guess bnew = calc_b_guess(b_x_pair_old.second); @@ -312,7 +311,7 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { error_rel = error_abs / RMS_rhsOverD; // effectively another iteration, so increment the counter - count++; + ++count; if (count>maxits) { throw BoutException("LaplaceNaulin error: Not converged within maxits=%i iterations.", maxits); } @@ -329,7 +328,7 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { } - ncalls++; + ++ncalls; naulinsolver_mean_its = (naulinsolver_mean_its * BoutReal(ncalls-1) + BoutReal(count))/BoutReal(ncalls); naulinsolver_mean_underrelax_counts = (naulinsolver_mean_underrelax_counts * BoutReal(ncalls - 1) @@ -340,15 +339,15 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { void LaplaceNaulin::copy_x_boundaries(Field3D &x, const Field3D &x0, Mesh *localmesh) { if (localmesh->firstX()) { - for (int i=localmesh->xstart-1; i>=0; i--) - for (int j=localmesh->ystart; j<=localmesh->yend; j++) - for (int k=0; kLocalNz; k++) + for (int i=localmesh->xstart-1; i>=0; --i) + for (int j=localmesh->ystart; j<=localmesh->yend; ++j) + for (int k=0; kLocalNz; ++k) x(i, j, k) = x0(i, j, k); } if (localmesh->lastX()) { - for (int i=localmesh->xend+1; iLocalNx; i++) - for (int j=localmesh->ystart; j<=localmesh->yend; j++) - for (int k=0; kLocalNz; k++) + for (int i=localmesh->xend+1; iLocalNx; ++i) + for (int j=localmesh->ystart; j<=localmesh->yend; ++j) + for (int k=0; kLocalNz; ++k) x(i, j, k) = x0(i, j, k); } } From c44e37f127587e094f464e5779c17569b040fb66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Wed, 3 Apr 2019 13:30:06 +0100 Subject: [PATCH 1236/1783] Call C++ destructors before BoutFinalise --- .../test-boutcore/collect-staggered/runtest | 2 - .../integrated/test-boutcore/collect/runtest | 2 - .../test-boutcore/legacy-model/runtest | 2 - .../integrated/test-boutcore/mms-ddz/runtest | 2 - .../test-boutcore/simple-model/runtest | 2 - tools/pylib/_boutcore_build/boutcore.pyx.in | 41 ++++++++++++++++--- 6 files changed, 36 insertions(+), 15 deletions(-) diff --git a/tests/integrated/test-boutcore/collect-staggered/runtest b/tests/integrated/test-boutcore/collect-staggered/runtest index 9ad329e41a..7f683a862e 100755 --- a/tests/integrated/test-boutcore/collect-staggered/runtest +++ b/tests/integrated/test-boutcore/collect-staggered/runtest @@ -47,6 +47,4 @@ if compare(fc, fo) > 1e-3: print("Something is wrong. Maybe setting the location from field failed.") fail = 1 -bc.finalise() - exit(fail) diff --git a/tests/integrated/test-boutcore/collect/runtest b/tests/integrated/test-boutcore/collect/runtest index f9661ef262..b1ba11fa7b 100755 --- a/tests/integrated/test-boutcore/collect/runtest +++ b/tests/integrated/test-boutcore/collect/runtest @@ -46,5 +46,3 @@ if not ((p == pn).all()): errorlist += "multiplication not working\n" print(p.shape) print(pn.shape) - -bc.finalise() diff --git a/tests/integrated/test-boutcore/legacy-model/runtest b/tests/integrated/test-boutcore/legacy-model/runtest index bd40d14aed..9d84b27741 100755 --- a/tests/integrated/test-boutcore/legacy-model/runtest +++ b/tests/integrated/test-boutcore/legacy-model/runtest @@ -20,5 +20,3 @@ model = boutcore.PhysicsModelBase() model.setRhs(rhs) model.solve_for(n=dens) model.solve() - -boutcore.finalise() diff --git a/tests/integrated/test-boutcore/mms-ddz/runtest b/tests/integrated/test-boutcore/mms-ddz/runtest index 43816e3469..aa1ef07c9e 100755 --- a/tests/integrated/test-boutcore/mms-ddz/runtest +++ b/tests/integrated/test-boutcore/mms-ddz/runtest @@ -34,8 +34,6 @@ errc = np.log(errors[-2]/errors[-1]) difc = np.log(nzs[-1]/nzs[-2]) conv = errc/difc -boutcore.finalise() - if 1.9 < conv < 2.1: print("The convergence is: %f" % conv) else: diff --git a/tests/integrated/test-boutcore/simple-model/runtest b/tests/integrated/test-boutcore/simple-model/runtest index 472e3ac774..9748cc4b0c 100755 --- a/tests/integrated/test-boutcore/simple-model/runtest +++ b/tests/integrated/test-boutcore/simple-model/runtest @@ -18,5 +18,3 @@ class MyModel(PhysicsModel): model = MyModel() model.solve() - -finalise() diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 1f9c99770d..8e9cbfc9b2 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -58,7 +58,7 @@ cat <0 def __dealloc__(self): + self.__mydealloc__() + + def __mydealloc__(self): if self.cobj != 0: del self.cobj + self.cobj = NULL + # @classmethod # def fromPtr(cls,FieldFactory * cobj_): # fu=cls() @@ -946,8 +958,12 @@ cdef class PythonModelCallback: self.cobj = new c.PythonModelCallback(callback, method) def __dealloc__(self): + self.__mydealloc__() + + def __mydealloc__(self): if self.thisptr: del self.thisptr + self.thisptr = NULL cpdef void execute(self, parameter): # 'parameter' :: The parameter to be passed to the 'method' @@ -1015,6 +1031,9 @@ cdef class PhysicsModelBase(object): self.cmodel.set_init_func(self.callbackinit) def __dealloc__(self): + self.__mydealloc__() + + def __mydealloc__(self): if self.cmodel != 0: self.cmodel.free() del self.cmodel @@ -1118,17 +1137,29 @@ def init(args=[]): raise RuntimeError("Failed to initialise the BOUT++ Library (Error code %d)"%ret) else: _isInit=True - #atexit.register(finalise) + atexit.register(finalise) def finalise(): """ Finalize BOUT++ and also MPI. After this most objects and functions are not valid anymore. """ - checkInit() - BoutFinalise() global _isInit - _isInit=False + import gc + ls = gc.get_objects() + #im=(Coordinates, Field2D, Field3D, Laplacian, Mesh, Options, PhysicsModel, PhysicsModelBase, Vector2D, Vector3D, PythonModelCallback) + # list of class with custom deallocation + # May need to be extended if other classes also have MPI calls in + # dealloc, and thus need to be called before finalise + im=(Field2D, Field3D, Mesh, FieldFactory, PhysicsModelBase, PythonModelCallback) + print("isInit is",_isInit) + for i in ls: + if isinstance(i,im): + i.__mydealloc__() + del ls + if _isInit: + BoutFinalise() + _isInit = False def checkInit(): """ From d1b50bebc059d6c0b588306c3b061882b301ae58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Wed, 3 Apr 2019 15:15:15 +0100 Subject: [PATCH 1237/1783] Fix whitespace --- tools/pylib/_boutcore_build/boutcore.pyx.in | 26 ++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 8e9cbfc9b2..2aef36c528 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -923,7 +923,7 @@ cdef class FieldFactory: def __mydealloc__(self): if self.cobj != 0: del self.cobj - self.cobj = NULL + self.cobj = NULL # @classmethod # def fromPtr(cls,FieldFactory * cobj_): @@ -963,7 +963,7 @@ cdef class PythonModelCallback: def __mydealloc__(self): if self.thisptr: del self.thisptr - self.thisptr = NULL + self.thisptr = NULL cpdef void execute(self, parameter): # 'parameter' :: The parameter to be passed to the 'method' @@ -1513,19 +1513,19 @@ cdef class Options: def __init__(self,name=""): """ - Get a section from the global options tree + Get a section from the global options tree - Parameters - ---------- - name : string, optional - The name of the section. Can contain ':' to specify subsections. - Defaults to the root section ''. + Parameters + ---------- + name : string, optional + The name of the section. Can contain ':' to specify subsections. + Defaults to the root section ''. - Returns - ------- - Options - The Options object - """ + Returns + ------- + Options + The Options object + """ checkInit() self.cobj = c.Options.getRoot() cdef c.string sec_ From 8172f9c33cab5ed01e0656d10cead37aa5f171fa Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 3 Apr 2019 15:23:34 +0100 Subject: [PATCH 1238/1783] Remove printing that was there for debugging --- src/invert/laplace/impls/naulin/naulin_laplace.cxx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index 3e265054f1..92e280d86d 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -143,7 +143,6 @@ #include #include #include -#include #include "naulin_laplace.hxx" @@ -293,8 +292,6 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { throw BoutException("LaplaceNaulin error: Not converged within maxits=%i iterations.", maxits); } - output< last_error) { // Iteration seems to be diverging... try underrelaxing and restart underrelax_factor *= .9; @@ -315,8 +312,6 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { if (count>maxits) { throw BoutException("LaplaceNaulin error: Not converged within maxits=%i iterations.", maxits); } - - output< Date: Wed, 3 Apr 2019 16:41:13 +0100 Subject: [PATCH 1239/1783] Bugfix - thisptr was renamed to cobj We want to delete cobj ... --- tools/pylib/_boutcore_build/boutcore.pyx.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 2aef36c528..cacf05c55e 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -961,9 +961,9 @@ cdef class PythonModelCallback: self.__mydealloc__() def __mydealloc__(self): - if self.thisptr: - del self.thisptr - self.thisptr = NULL + if self.cobj: + del self.cobj + self.cobj = NULL cpdef void execute(self, parameter): # 'parameter' :: The parameter to be passed to the 'method' From 0e19ca1cc4441467598395c96c35969ea919d70b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Wed, 3 Apr 2019 16:52:05 +0100 Subject: [PATCH 1240/1783] Add __mydealloc__ to all clases This makes sure that they can all be free'd before we call finalise. Further minor changes such as whitespace. --- tools/pylib/_boutcore_build/boutcore.pyx.in | 130 ++++++++++++++------ 1 file changed, 91 insertions(+), 39 deletions(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index cacf05c55e..e589f6dce7 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -24,7 +24,7 @@ do then libs+=" ${fl:2}" else - ldflags+=" $fl" + ldflags+=" $fl" fi done @@ -622,6 +622,7 @@ cdef class $vec: A vector of $field """ cdef c.$vec * cobj + cdef c.bool isSelfOwned EOF for d in x y z do @@ -644,9 +645,18 @@ EOF str(type(self))+"' and '"+str(type(rhs))+ "' - not supported (yet?).") + def __dealloc__(self): + self.__mydealloc__() + + def __mydealloc__(self): + if self.isSelfOwned and self.cobj!=NULL: + del self.cobj + self.cobj=NULL + cdef $vec ${vdd}FromObj(c.$vec i): v=$vec() v.cobj = new c.$vec( i) + v.isSelfOwned = True return v EOF done @@ -674,7 +684,7 @@ cdef class Mesh: cdef double isNormalised cdef FieldFactory factory cdef Coordinates _coords - #factory=FieldFactory() + def __init__(self, create=True, section=None, options=None): """ Create a Mesh @@ -796,19 +806,22 @@ cdef class Mesh: Get the Coordinates object of this mesh """ if self._coords is None: - self._coords = coordsFromObj(self.cobj.getCoordinates()) + self._coords = coordsFromPtr(self.cobj.getCoordinates()) return self._coords -cdef Coordinates coordsFromObj(c.Coordinates * obj): +cdef Coordinates coordsFromPtr(c.Coordinates * obj): coords = Coordinates() coords.cobj = obj coords._setmembers() + coords.isSelfOwned = False return coords + cdef class Coordinates: """ Contains information about geometry, such as metric tensors """ cdef c.Coordinates * cobj + cdef c.bool isSelfOwned cdef public Field2D dx, dy cdef public double dz cdef public Field2D J @@ -823,7 +836,8 @@ cdef class Coordinates: cdef public Field2D IntShiftTorsion def __init__(self): - self.cobj = 0 + self.cobj = NULL + self.isSelfOwned = False def _setmembers(self): EOF @@ -837,6 +851,14 @@ do done cat <<"EOF" + def __dealloc__(self): + self.__mydealloc__() + + def __mydealloc__(self): + if self.cobj and self.isSelfOwned: + del self.cobj + self.cobj = NULL + cdef class Laplacian: """ Laplacian inversion solver @@ -846,6 +868,7 @@ cdef class Laplacian: Equation solved is: d\\nabla^2_\\perp x + (1/c1)\\nabla_perp c2\\cdot\\nabla_\\perp x + ex\\nabla_x x + ez\\nabla_z x + a x = b """ cdef c.Laplacian * cobj + cdef c.bool isSelfOwned def __init__(self,section=None): """ Initialiase a Laplacian solver @@ -860,7 +883,7 @@ cdef class Laplacian: self.cobj = c.Laplacian.create((section).cobj) else: self.cobj = c.Laplacian.create(NULL) - + self.isSelfOwned = True def solve(self,Field3D x, Field3D guess): """ Calculate the Laplacian inversion @@ -912,6 +935,15 @@ EOF done cat <<"EOF" + + def __dealloc__(self): + self.__mydealloc__() + + def __mydealloc__(self): + if self.cobj and self.isSelfOwned: + del self.cobj + self.cobj = NULL + cdef class FieldFactory: cdef c.FieldFactory * cobj def __init__(self): @@ -921,7 +953,7 @@ cdef class FieldFactory: self.__mydealloc__() def __mydealloc__(self): - if self.cobj != 0: + if self.cobj != NULL: del self.cobj self.cobj = NULL @@ -1085,6 +1117,12 @@ class PhysicsModel(PhysicsModelBase): """ pass + def __dealloc__(self): + super(PhysicsModel,self).__dealloc__() + + def __mydealloc__(self): + super(PhysicsModel,self).__mydealloc__() + cdef extern from "bout.hxx": int BoutInitialise(int&, char **&) except +raise_bout_py_error void BoutFinalise() @@ -1147,11 +1185,9 @@ def finalise(): global _isInit import gc ls = gc.get_objects() - #im=(Coordinates, Field2D, Field3D, Laplacian, Mesh, Options, PhysicsModel, PhysicsModelBase, Vector2D, Vector3D, PythonModelCallback) - # list of class with custom deallocation - # May need to be extended if other classes also have MPI calls in - # dealloc, and thus need to be called before finalise - im=(Field2D, Field3D, Mesh, FieldFactory, PhysicsModelBase, PythonModelCallback) + im=(Coordinates, Field2D, Field3D, Laplacian, Mesh, Options, + PhysicsModel, PhysicsModelBase, Vector2D, Vector3D, + PythonModelCallback) print("isInit is",_isInit) for i in ls: if isinstance(i,im): @@ -1635,36 +1671,52 @@ cdef class Options: opt.get(key,ret_str, default_) return ret_str + def __dealloc__(self): + self.__mydealloc__() + + def __mydealloc__(self): + if self.isSelfOwned and self.cobj!=NULL: + del self.cobj + self.cobj=NULL + cdef class Datafile: - cdef c.Datafile * cobj - def __init__(self): - self.cobj = c_get_global_datafile() - def add(self,save_repeat=False,**kwargs): - for key in kwargs: - self._add(kwargs[key],key,save_repeat) - - def _add(self,data,name,save_repeat): - cdef char * tmp - cdef double * dbl - cdef c.Field3D * f3d - t2=str.encode(name) - tmp=t2 - # import numbers - # if isinstance(data,int): - # #c_datafile_add_int(self.cobj, - # self.cobj.add(data,tmp,save_repeat) - # elif isinstance(data,numbers.Number): - # self.cobj.add(dbl,tmp,save_repeat) - # el - if isinstance(data,Field3D): - f3d=(data).cobj - self.cobj.add(f3d[0],tmp,save_repeat) - else: - raise TypeError("unsupported datatype") - def write(self): - self.cobj.write() + cdef c.Datafile * cobj + def __init__(self): + self.cobj = c_get_global_datafile() + def add(self,save_repeat=False,**kwargs): + for key in kwargs: + self._add(kwargs[key],key,save_repeat) + + def _add(self,data,name,save_repeat): + cdef char * tmp + cdef double * dbl + cdef c.Field3D * f3d + t2=str.encode(name) + tmp=t2 + # import numbers + # if isinstance(data,int): + # #c_datafile_add_int(self.cobj, + # self.cobj.add(data,tmp,save_repeat) + # elif isinstance(data,numbers.Number): + # self.cobj.add(dbl,tmp,save_repeat) + # el + if isinstance(data,Field3D): + f3d=(data).cobj + self.cobj.add(f3d[0],tmp,save_repeat) + else: + raise TypeError("unsupported datatype") + def write(self): + self.cobj.write() + + + def __dealloc__(self): + self.__mydealloc__() + + def __mydealloc__(self): + # is never self owned + pass EOF From acc7e3559fbe661628ea7f35ca2bb0fa911a6848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Wed, 3 Apr 2019 19:51:41 +0100 Subject: [PATCH 1241/1783] Bugfix: return fields by reference Returning the fields by value prevents the fields from being changed. --- tools/pylib/_boutcore_build/boutcore.pyx.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 1f9c99770d..e0c0de06e6 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -822,7 +822,7 @@ cdef class Coordinates: EOF for f in "dx" "dy" "J" "Bxy" "g11" "g22" "g33" "g12" "g13" "g23" "g_11" "g_22" "g_33" "g_12" "g_13" "g_23" "G1_11" "G1_22" "G1_33" "G1_12" "G1_13" "G1_23" "G2_11" "G2_22" "G2_33" "G2_12" "G2_13" "G2_23" "G3_11" "G3_22" "G3_33" "G3_12" "G3_13" "G3_23" "G1" "G2" "G3" "ShiftTorsion" "IntShiftTorsion" do - echo " self.${f} = f2dFromObj(self.cobj.${f})" + echo " self.${f} = f2dFromPtr(&self.cobj.${f})" done for f in "dz" do From b3397c91ca073aac0d733b853b29505ac637bc81 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 4 Apr 2019 09:23:33 +0100 Subject: [PATCH 1242/1783] Update test-code-style to exclude templates Excludes lines if they include the word "template". This won't exclude lines where template is put on the line before. --- tests/integrated/test-code-style/runtest | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integrated/test-code-style/runtest b/tests/integrated/test-code-style/runtest index 33845575fa..c653a7a7ee 100755 --- a/tests/integrated/test-code-style/runtest +++ b/tests/integrated/test-code-style/runtest @@ -7,7 +7,9 @@ error= for i in BoutReal # double float int char size_t do - grep -E "\([^\)]*const[^\(,:<]*$i[^,\):\*>]*\&" -r --include=*xx $BOUT_TOP && + # Search for "(... const $i...)", but exclude lines with "template" + # because sometimes "const BoutReal" is needed in template specialisations + grep -E "\([^\)]*const[^\(,:<]*$i[^,\):\*>]*\&" -r --include=*xx $BOUT_TOP | grep -v template && error=yes && echo "const $i should be passed by value" done From cc7de4e53b24bb8d741877b00056063355d7e818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 4 Apr 2019 10:14:58 +0100 Subject: [PATCH 1243/1783] Cleanup: remove comments and use better names --- tools/pylib/_boutcore_build/boutcore.pyx.in | 29 ++++++--------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index e589f6dce7..8f5652e35a 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -353,7 +353,6 @@ cat < default) return ret_bool elif isinstance(default,numbers.Number): - #print("isreal") opt.get(key,ret_real, default) return ret_real else: - #print("isstr") default_= str(default).encode('ascii') opt.get(key,ret_str, default_) return ret_str @@ -1695,13 +1689,6 @@ cdef class Datafile: cdef c.Field3D * f3d t2=str.encode(name) tmp=t2 - # import numbers - # if isinstance(data,int): - # #c_datafile_add_int(self.cobj, - # self.cobj.add(data,tmp,save_repeat) - # elif isinstance(data,numbers.Number): - # self.cobj.add(dbl,tmp,save_repeat) - # el if isinstance(data,Field3D): f3d=(data).cobj self.cobj.add(f3d[0],tmp,save_repeat) From e0a1591d1c0075f7c3d1987cd6d743fc183c342a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 4 Apr 2019 10:23:47 +0100 Subject: [PATCH 1244/1783] Add documentation --- tools/pylib/_boutcore_build/boutcore.pyx.in | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 8f5652e35a..c893a93fb6 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -1179,8 +1179,20 @@ def finalise(): """ Finalize BOUT++ and also MPI. After this most objects and functions are not valid anymore. + + Note that this deallocates the C++ objects, thus the python + objects might not work any more. """ + # Go through all living objects, find the ones from boutcore, so + # that we can free them. + # We cannot rely on python, as + # * Python does not even garantee that they are freed + # * MPI routines are invalid after finalise, and some destructors + # include calls to MPI + # first set _isInit to False, so no further bc objects can be created global _isInit + wasInit = _isInit + _isInit = False import gc objects = gc.get_objects() ourClasses = (Coordinates, Field2D, Field3D, Laplacian, Mesh, Options, @@ -1190,9 +1202,9 @@ def finalise(): if isinstance(obj,ourClasses): obj.__mydealloc__() del objects - if _isInit: + # Actually finalise + if wasInit: BoutFinalise() - _isInit = False def checkInit(): """ From e656c0db9dbb361f0d4af482f20eb72bb3e64c12 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 4 Apr 2019 16:52:11 +0100 Subject: [PATCH 1245/1783] Check that Coordinates is valid object before using it in create3D --- src/field/field_factory.cxx | 15 ++++++++++----- tests/unit/field/test_field_factory.cxx | 16 ++++++++++++++++ tests/unit/solver/test_solver.cxx | 1 + 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 0d385d731e..9118be76b9 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -222,11 +222,16 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC } }; - if (transform_from_field_aligned - and result.getCoordinates()->getParallelTransform().canToFromFieldAligned()) { - // Transform from field aligned coordinates, to be compatible with - // older BOUT++ inputs. This is not a particularly "nice" solution. - result = fromFieldAligned(result, RGN_ALL); + if (transform_from_field_aligned) { + auto coords = result.getCoordinates(); + if (coords == nullptr) { + throw BoutException("Unable to transform result: Mesh does not have Coordinates set"); + } + if (coords->getParallelTransform().canToFromFieldAligned()) { + // Transform from field aligned coordinates, to be compatible with + // older BOUT++ inputs. This is not a particularly "nice" solution. + result = fromFieldAligned(result, RGN_ALL); + } } return result; diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index df3a5c8d30..a0ba5a2543 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -587,6 +587,22 @@ TYPED_TEST(FieldFactoryCreationTest, CreateOnMesh) { EXPECT_EQ(output.getNz(), nz); } +TYPED_TEST(FieldFactoryCreationTest, CreateOnMeshWithoutCoordinates) { + constexpr auto nx = int{1}; + constexpr auto ny = int{1}; + constexpr auto nz = int{1}; + + FakeMesh localmesh{nx, ny, nz}; + localmesh.setCoordinates(nullptr); + localmesh.createDefaultRegions(); + localmesh.setCoordinates(nullptr); + + // Field2D version doesn't try to transform back + if (std::is_base_of::value) { + EXPECT_THROW(this->create("x", nullptr, &localmesh), BoutException); + } +} + // The following tests still use the FieldFactory, but don't need to // be typed and make take longer as they check that exceptions get // thrown. Doing these twice will slow down the test unnecessarily diff --git a/tests/unit/solver/test_solver.cxx b/tests/unit/solver/test_solver.cxx index c272078792..fba99fb75e 100644 --- a/tests/unit/solver/test_solver.cxx +++ b/tests/unit/solver/test_solver.cxx @@ -536,6 +536,7 @@ TEST_F(SolverTest, GetLocalN) { Options::root()["field2"]["evolve_bndry"] = true; Options::root()["field4"]["evolve_bndry"] = true; + Options::root()["input"]["transform_from_field_aligned"] = false; constexpr auto localmesh_nx = 5; constexpr auto localmesh_ny = 7; From 7bcf1e370f3b8fafb46bdb332ce54c9d787c937c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 4 Apr 2019 16:52:41 +0100 Subject: [PATCH 1246/1783] Ensure parallel transform is always set if we try to get it --- src/mesh/coordinates.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 3fd5d21fcf..ef942bbf2b 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -857,7 +857,9 @@ void Coordinates::setParallelTransform(Options* options) { } ParallelTransform& Coordinates::getParallelTransform() { - // Return a reference to the ParallelTransform object + if (transform == nullptr) { + setParallelTransform(Options::getRoot()); + } return *transform; } From efb99ae46e139913a4f96b9d080a2d3c20cc5dd6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 4 Apr 2019 17:10:06 +0100 Subject: [PATCH 1247/1783] Read boundary cells of zShift, and read staggered zShift Apply updates to reading of Coordinates members to reading of zShift: - If y-boundary guard cells are present in the grid file, then read them, otherwise extrapolate into boundary cells - If staggered versions of zShift are available in the grid file, then load them, otherwise interpolate from the CELL_CENTRE version, and extrapolate into boundary cells --- src/mesh/coordinates.cxx | 76 ++++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index fe664388b8..0b390e36ff 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -140,6 +140,29 @@ void getAtLoc(Mesh* mesh, Field2D &var, std::string name, std::string suffix, mesh->get(var, name+suffix, default_value); var.setLocation(location); } + +std::string getLocationSuffix(CELL_LOC location) { + switch (location) { + case CELL_CENTRE: { + return ""; + } + case CELL_XLOW: { + return "_xlow"; + } + case CELL_YLOW: { + return "_ylow"; + } + case CELL_ZLOW: { + // geometrical quantities are Field2D, so CELL_ZLOW version is the same + // as CELL_CENTRE + return ""; + } + default: { + throw BoutException("Incorrect location passed to " + "Coordinates(Mesh*,const CELL_LOC,const Coordinates*) constructor."); + } + } +} } Coordinates::Coordinates(Mesh* mesh, Field2D dx, Field2D dy, BoutReal dz, Field2D J, @@ -380,27 +403,7 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, G3_23(mesh), G1(mesh), G2(mesh), G3(mesh), ShiftTorsion(mesh), IntShiftTorsion(mesh), localmesh(mesh), location(loc) { - std::string suffix = ""; - switch (location) { - case CELL_XLOW: { - suffix = "_xlow"; - break; - } - case CELL_YLOW: { - suffix = "_ylow"; - break; - } - case CELL_ZLOW: { - // geometrical quantities are Field2D, so CELL_ZLOW version is the same - // as CELL_CENTRE - suffix = ""; - break; - } - default: { - throw BoutException("Incorrect location passed to " - "Coordinates(Mesh*,const CELL_LOC,const Coordinates*) constructor."); - } - } + std::string suffix = getLocationSuffix(location); nz = mesh->LocalNz; @@ -964,12 +967,33 @@ void Coordinates::setParallelTransform(Options* options) { Field2D zShift{localmesh}; // Read the zShift angle from the mesh - if (localmesh->get(zShift, "zShift")) { - // No zShift variable. Try qinty in BOUT grid files - localmesh->get(zShift, "qinty"); - } + std::string suffix = getLocationSuffix(location); + if (localmesh->sourceHasVar("dx"+suffix)) { + // Grid file has variables at this location, so should be able to read + checkStaggeredGet(localmesh, "zShift", suffix); + if (localmesh->get(zShift, "zShift"+suffix)) { + // No zShift variable. Try qinty in BOUT grid files + if (localmesh->get(zShift, "qinty"+suffix)) { + // Failed to find either variable, cannot use ShiftedMetric + throw BoutException("Could not read zShift"+suffix+" from grid file"); + } + } - zShift = interpolateAndNeumann(zShift, location); + // extrapolate into boundary guard cells if necessary + interpolateAndExtrapolate(zShift, location, + not localmesh->sourceHasXBoundaryGuards(), + not localmesh->sourceHasYBoundaryGuards()); + } else { + if (localmesh->get(zShift, "zShift")) { + // No zShift variable. Try qinty in BOUT grid files + if (localmesh->get(zShift, "qinty")) { + // Failed to find either variable, cannot use ShiftedMetric + throw BoutException("Could not read zShift"+suffix+" from grid file"); + } + } + + zShift = interpolateAndExtrapolate(zShift, location); + } // make sure zShift has been communicated localmesh->communicate(zShift); From 9bcc8a40b99709cd7259462dda4591fb79e834e8 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 5 Apr 2019 11:58:54 +0100 Subject: [PATCH 1248/1783] Throw if parallel transform is not available Coordinates *should* always have a valid parallel transform, unless it was created via the "dumb" ctor --- src/mesh/coordinates.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index ef942bbf2b..f1da0a20ab 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -858,12 +858,11 @@ void Coordinates::setParallelTransform(Options* options) { ParallelTransform& Coordinates::getParallelTransform() { if (transform == nullptr) { - setParallelTransform(Options::getRoot()); + throw BoutException(_("Coordinates instance does not have parallel transform set")); } return *transform; } - /******************************************************************************* * Operators * From dbd0970c0f398be457776c58a7ea1dbfd3dd1869 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 5 Apr 2019 12:00:07 +0100 Subject: [PATCH 1249/1783] Remove extraneous calls to Mesh::setCoordinates in tests --- tests/unit/field/test_field_factory.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index a0ba5a2543..cb22f5afbc 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -564,7 +564,6 @@ TYPED_TEST(FieldFactoryCreationTest, CreateOnMesh) { constexpr auto nz = int{1}; FakeMesh localmesh{nx, ny, nz}; - localmesh.setCoordinates(nullptr); localmesh.createDefaultRegions(); localmesh.setCoordinates(std::make_shared( &localmesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, @@ -595,7 +594,6 @@ TYPED_TEST(FieldFactoryCreationTest, CreateOnMeshWithoutCoordinates) { FakeMesh localmesh{nx, ny, nz}; localmesh.setCoordinates(nullptr); localmesh.createDefaultRegions(); - localmesh.setCoordinates(nullptr); // Field2D version doesn't try to transform back if (std::is_base_of::value) { From 605d830f45cb9e6835edbc55cc0d919f69a258d5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 5 Apr 2019 18:01:59 +0100 Subject: [PATCH 1250/1783] Move getParallelTransform body to header; use ASSERT1 --- include/bout/coordinates.hxx | 9 +++++---- src/mesh/coordinates.cxx | 7 ------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index 12ebc58e45..6e5b87c4e0 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -123,15 +123,16 @@ public: /////////////////////////////////////////////////////////// /// Set the parallel (y) transform for this mesh. - /// Unique pointer used so that ParallelTransform will be deleted. /// Mostly useful for tests. void setParallelTransform(std::unique_ptr pt) { transform = std::move(pt); } - /// Return the parallel transform, setting it if need be - ParallelTransform& getParallelTransform(); - + /// Return the parallel transform + ParallelTransform& getParallelTransform() { + ASSERT1(transform != nullptr); + return *transform; + } /////////////////////////////////////////////////////////// // Operators diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index f1da0a20ab..a8b1e4b1bf 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -856,13 +856,6 @@ void Coordinates::setParallelTransform(Options* options) { } } -ParallelTransform& Coordinates::getParallelTransform() { - if (transform == nullptr) { - throw BoutException(_("Coordinates instance does not have parallel transform set")); - } - return *transform; -} - /******************************************************************************* * Operators * From 0f82cdf8edf785cb190f845c3792db56c41f6eac Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 4 Apr 2019 19:44:54 +0100 Subject: [PATCH 1251/1783] Method for Laplace solvers to say whether they use 3D coefficients ...or only take the DC component. --- include/invert_laplace.hxx | 3 +++ src/invert/laplace/impls/multigrid/multigrid_laplace.hxx | 2 ++ src/invert/laplace/impls/mumps/mumps_laplace.hxx | 2 ++ src/invert/laplace/impls/naulin/naulin_laplace.hxx | 2 ++ 4 files changed, 9 insertions(+) diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index 5f22d911b9..772afc8bc5 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -173,6 +173,9 @@ public: virtual void setGlobalFlags(int f) { global_flags = f; } virtual void setInnerBoundaryFlags(int f) { inner_boundary_flags = f; } virtual void setOuterBoundaryFlags(int f) { outer_boundary_flags = f; } + + /// Does this solver use Field3D coefficients (true) or only their DC component (false) + virtual bool uses3DCoefs() const { return false; } virtual const FieldPerp solve(const FieldPerp &b) = 0; virtual const Field3D solve(const Field3D &b); diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx index 375455ea9e..402d2f3bd1 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx @@ -192,6 +192,8 @@ public: D = val; } + virtual bool uses3DCoefs() const override { return true; } + const FieldPerp solve(const FieldPerp &b) override { ASSERT1(localmesh == b.getMesh()); diff --git a/src/invert/laplace/impls/mumps/mumps_laplace.hxx b/src/invert/laplace/impls/mumps/mumps_laplace.hxx index 82fc082b7e..616f352bed 100644 --- a/src/invert/laplace/impls/mumps/mumps_laplace.hxx +++ b/src/invert/laplace/impls/mumps/mumps_laplace.hxx @@ -172,6 +172,8 @@ public: issetE = true; } + virtual bool uses3DCoefs() const override { return true; } + void setFlags(int f) {throw BoutException("May not change the value of flags during run in LaplaceMumps as it might change the number of non-zero matrix elements: flags may only be set in the options file.");} const FieldPerp solve(const FieldPerp &b) override; diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.hxx b/src/invert/laplace/impls/naulin/naulin_laplace.hxx index 673f7bd858..094e29960a 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.hxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.hxx @@ -102,6 +102,8 @@ public: throw BoutException("LaplaceNaulin does not have Ez coefficient"); } + virtual bool uses3DCoefs() const override { return true; } + const FieldPerp solve(const FieldPerp &b) override {return solve(b,b);} const FieldPerp solve(const FieldPerp &UNUSED(b), const FieldPerp &UNUSED(x0)) override { From 59e5cb01b33a1ce82981dbb24e0189394ac6d6ed Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 8 Apr 2019 10:38:42 +0100 Subject: [PATCH 1252/1783] Add unit tests for where --- tests/unit/field/test_where.cxx | 95 +++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 tests/unit/field/test_where.cxx diff --git a/tests/unit/field/test_where.cxx b/tests/unit/field/test_where.cxx new file mode 100644 index 0000000000..e4c0029490 --- /dev/null +++ b/tests/unit/field/test_where.cxx @@ -0,0 +1,95 @@ +#include "gtest/gtest.h" + +#include "field.hxx" +#include "where.hxx" +#include "test_extras.hxx" + +/// Global mesh +namespace bout{ +namespace globals{ +extern Mesh *mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; + +// Reuse the "standard" fixture for FakeMesh +class WhereTest : public FakeMeshFixture { +public: + WhereTest() : FakeMeshFixture(), expected_2d(mesh), expected_3d(mesh) { + fillField(expected_2d, + {{4., 4., 4., 2., 2.}, {4., 4., 4., 2., 2.}, {4., 4., 4., 2., 2.}}); + + fillField(expected_3d, {{{4., 4., 4., 4., 4., 4., 4.}, + {4., 4., 4., 4., 4., 4., 4.}, + {4., 4., 4., 4., 4., 4., 4.}, + {2., 2., 2., 2., 2., 2., 2.}, + {2., 2., 2., 2., 2., 2., 2.}}, + + {{4., 4., 4., 4., 4., 4., 4.}, + {4., 4., 4., 4., 4., 4., 4.}, + {4., 4., 4., 4., 4., 4., 4.}, + {2., 2., 2., 2., 2., 2., 2.}, + {2., 2., 2., 2., 2., 2., 2.}}, + + {{4., 4., 4., 4., 4., 4., 4.}, + {4., 4., 4., 4., 4., 4., 4.}, + {4., 4., 4., 4., 4., 4., 4.}, + {2., 2., 2., 2., 2., 2., 2.}, + {2., 2., 2., 2., 2., 2., 2.}}}); + + test_2d = makeField( + [](Field2D::ind_type i) { return i.y() - (WhereTest::ny / 2); }); + test_3d = makeField( + [](Field3D::ind_type i) { return i.y() - (WhereTest::ny / 2); }); + } + + virtual ~WhereTest() = default; + + Field2D expected_2d; + Field3D expected_3d; + + Field2D test_2d; + Field3D test_3d; +}; + +TEST_F(WhereTest, Field2DField3DField3D) { + EXPECT_TRUE(IsFieldEqual(where(test_2d, Field3D{2.0}, Field3D{4.0}), expected_3d)); +} + +TEST_F(WhereTest, Field2DField3DBoutReal) { + EXPECT_TRUE(IsFieldEqual(where(test_2d, Field3D{2.0}, 4.0), expected_3d)); +} + +TEST_F(WhereTest, Field2DBoutRealField3D) { + EXPECT_TRUE(IsFieldEqual(where(test_2d, 2.0, Field3D{4.0}), expected_3d)); +} + +TEST_F(WhereTest, Field2DField3DField2D) { + EXPECT_TRUE(IsFieldEqual(where(test_2d, Field3D{2.0}, Field2D{4.0}), expected_3d)); +} + +TEST_F(WhereTest, Field2DField2DField3D) { + EXPECT_TRUE(IsFieldEqual(where(test_2d, Field2D{2.0}, Field3D{4.0}), expected_3d)); +} + +TEST_F(WhereTest, Field2DField2DField2D) { + EXPECT_TRUE(IsFieldEqual(where(test_2d, Field2D{2.0}, Field2D{4.0}), expected_2d)); +} + +TEST_F(WhereTest, Field2DField2DBoutReal) { + EXPECT_TRUE(IsFieldEqual(where(test_2d, Field2D{2.0}, 4.0), expected_2d)); +} + +TEST_F(WhereTest, Field2DBoutRealField2D) { + EXPECT_TRUE(IsFieldEqual(where(test_2d, 2.0, Field2D{4.0}), expected_2d)); +} + +TEST_F(WhereTest, Field2DBoutRealBoutReal) { + EXPECT_TRUE(IsFieldEqual(where(test_2d, 2.0, 4.0), expected_2d)); +} + +TEST_F(WhereTest, Field3DBoutRealField3D) { + EXPECT_TRUE(IsFieldEqual(where(test_3d, 2.0, Field3D{4.0}), expected_3d)); +} From 239fd68aa19324cc92806c72447b09e54cf94bc6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 8 Apr 2019 11:26:54 +0100 Subject: [PATCH 1253/1783] Vary test fields in as many dimensions as possible --- tests/unit/field/test_where.cxx | 111 +++++++++++++++++++------------- 1 file changed, 68 insertions(+), 43 deletions(-) diff --git a/tests/unit/field/test_where.cxx b/tests/unit/field/test_where.cxx index e4c0029490..493a925eb9 100644 --- a/tests/unit/field/test_where.cxx +++ b/tests/unit/field/test_where.cxx @@ -1,95 +1,120 @@ #include "gtest/gtest.h" #include "field.hxx" -#include "where.hxx" #include "test_extras.hxx" +#include "where.hxx" /// Global mesh -namespace bout{ -namespace globals{ -extern Mesh *mesh; +namespace bout { +namespace globals { +extern Mesh* mesh; } // namespace globals } // namespace bout // The unit tests use the global mesh using namespace bout::globals; +namespace { +constexpr auto le0 = 4.0; +constexpr auto gt0 = 2.0; +} // namespace + // Reuse the "standard" fixture for FakeMesh class WhereTest : public FakeMeshFixture { public: - WhereTest() : FakeMeshFixture(), expected_2d(mesh), expected_3d(mesh) { - fillField(expected_2d, - {{4., 4., 4., 2., 2.}, {4., 4., 4., 2., 2.}, {4., 4., 4., 2., 2.}}); - - fillField(expected_3d, {{{4., 4., 4., 4., 4., 4., 4.}, - {4., 4., 4., 4., 4., 4., 4.}, - {4., 4., 4., 4., 4., 4., 4.}, - {2., 2., 2., 2., 2., 2., 2.}, - {2., 2., 2., 2., 2., 2., 2.}}, - - {{4., 4., 4., 4., 4., 4., 4.}, - {4., 4., 4., 4., 4., 4., 4.}, - {4., 4., 4., 4., 4., 4., 4.}, - {2., 2., 2., 2., 2., 2., 2.}, - {2., 2., 2., 2., 2., 2., 2.}}, - - {{4., 4., 4., 4., 4., 4., 4.}, - {4., 4., 4., 4., 4., 4., 4.}, - {4., 4., 4., 4., 4., 4., 4.}, - {2., 2., 2., 2., 2., 2., 2.}, - {2., 2., 2., 2., 2., 2., 2.}}}); - - test_2d = makeField( - [](Field2D::ind_type i) { return i.y() - (WhereTest::ny / 2); }); - test_3d = makeField( - [](Field3D::ind_type i) { return i.y() - (WhereTest::ny / 2); }); + WhereTest() + : FakeMeshFixture(), expected_2d2d(mesh), expected_2d3d(mesh), test_2d(mesh) { + fillField(expected_2d2d, {{le0, le0, le0, gt0, gt0}, + {gt0, le0, le0, le0, le0}, + {le0, le0, gt0, gt0, gt0}}); + + fillField(expected_2d3d, {{{le0, le0, le0, le0, le0, le0, le0}, + {le0, le0, le0, le0, le0, le0, le0}, + {le0, le0, le0, le0, le0, le0, le0}, + {gt0, gt0, gt0, gt0, gt0, gt0, gt0}, + {gt0, gt0, gt0, gt0, gt0, gt0, gt0}}, + + {{gt0, gt0, gt0, gt0, gt0, gt0, gt0}, + {le0, le0, le0, le0, le0, le0, le0}, + {le0, le0, le0, le0, le0, le0, le0}, + {le0, le0, le0, le0, le0, le0, le0}, + {le0, le0, le0, le0, le0, le0, le0}}, + + {{le0, le0, le0, le0, le0, le0, le0}, + {le0, le0, le0, le0, le0, le0, le0}, + {gt0, gt0, gt0, gt0, gt0, gt0, gt0}, + {gt0, gt0, gt0, gt0, gt0, gt0, gt0}, + {gt0, gt0, gt0, gt0, gt0, gt0, gt0}}}); + + fillField(test_2d, + {{-2., -1., 0., 1., 2.}, {1., 0., -1., -2., -3.}, {-1., 0., 1., 2., 3.}}); } virtual ~WhereTest() = default; - Field2D expected_2d; - Field3D expected_3d; + Field2D expected_2d2d; + Field3D expected_2d3d; Field2D test_2d; - Field3D test_3d; }; TEST_F(WhereTest, Field2DField3DField3D) { - EXPECT_TRUE(IsFieldEqual(where(test_2d, Field3D{2.0}, Field3D{4.0}), expected_3d)); + EXPECT_TRUE(IsFieldEqual(where(test_2d, Field3D{gt0}, Field3D{le0}), expected_2d3d)); } TEST_F(WhereTest, Field2DField3DBoutReal) { - EXPECT_TRUE(IsFieldEqual(where(test_2d, Field3D{2.0}, 4.0), expected_3d)); + EXPECT_TRUE(IsFieldEqual(where(test_2d, Field3D{gt0}, le0), expected_2d3d)); } TEST_F(WhereTest, Field2DBoutRealField3D) { - EXPECT_TRUE(IsFieldEqual(where(test_2d, 2.0, Field3D{4.0}), expected_3d)); + EXPECT_TRUE(IsFieldEqual(where(test_2d, gt0, Field3D{le0}), expected_2d3d)); } TEST_F(WhereTest, Field2DField3DField2D) { - EXPECT_TRUE(IsFieldEqual(where(test_2d, Field3D{2.0}, Field2D{4.0}), expected_3d)); + EXPECT_TRUE(IsFieldEqual(where(test_2d, Field3D{gt0}, Field2D{le0}), expected_2d3d)); } TEST_F(WhereTest, Field2DField2DField3D) { - EXPECT_TRUE(IsFieldEqual(where(test_2d, Field2D{2.0}, Field3D{4.0}), expected_3d)); + EXPECT_TRUE(IsFieldEqual(where(test_2d, Field2D{gt0}, Field3D{le0}), expected_2d3d)); } TEST_F(WhereTest, Field2DField2DField2D) { - EXPECT_TRUE(IsFieldEqual(where(test_2d, Field2D{2.0}, Field2D{4.0}), expected_2d)); + EXPECT_TRUE(IsFieldEqual(where(test_2d, Field2D{gt0}, Field2D{le0}), expected_2d2d)); } TEST_F(WhereTest, Field2DField2DBoutReal) { - EXPECT_TRUE(IsFieldEqual(where(test_2d, Field2D{2.0}, 4.0), expected_2d)); + EXPECT_TRUE(IsFieldEqual(where(test_2d, Field2D{gt0}, le0), expected_2d2d)); } TEST_F(WhereTest, Field2DBoutRealField2D) { - EXPECT_TRUE(IsFieldEqual(where(test_2d, 2.0, Field2D{4.0}), expected_2d)); + EXPECT_TRUE(IsFieldEqual(where(test_2d, gt0, Field2D{le0}), expected_2d2d)); } TEST_F(WhereTest, Field2DBoutRealBoutReal) { - EXPECT_TRUE(IsFieldEqual(where(test_2d, 2.0, 4.0), expected_2d)); + EXPECT_TRUE(IsFieldEqual(where(test_2d, gt0, le0), expected_2d2d)); } TEST_F(WhereTest, Field3DBoutRealField3D) { - EXPECT_TRUE(IsFieldEqual(where(test_3d, 2.0, Field3D{4.0}), expected_3d)); + auto test_3d = makeField([](Field3D::ind_type i) { + return (i.y() - (ny / 2)) + (i.x() - (nx / 2)) + (i.z() - (nz / 2)); + }); + + Field3D expected_3d3d; + fillField(expected_3d3d, {{{le0, le0, le0, le0, le0, le0, le0}, + {le0, le0, le0, le0, le0, le0, gt0}, + {le0, le0, le0, le0, le0, gt0, gt0}, + {le0, le0, le0, le0, gt0, gt0, gt0}, + {le0, le0, le0, gt0, gt0, gt0, gt0}}, + {{le0, le0, le0, le0, le0, le0, gt0}, + {le0, le0, le0, le0, le0, gt0, gt0}, + {le0, le0, le0, le0, gt0, gt0, gt0}, + {le0, le0, le0, gt0, gt0, gt0, gt0}, + {le0, le0, gt0, gt0, gt0, gt0, gt0}}, + {{le0, le0, le0, le0, le0, gt0, gt0}, + {le0, le0, le0, le0, gt0, gt0, gt0}, + {le0, le0, le0, gt0, gt0, gt0, gt0}, + {le0, le0, gt0, gt0, gt0, gt0, gt0}, + {le0, gt0, gt0, gt0, gt0, gt0, gt0}}}); + + EXPECT_TRUE(IsFieldEqual(where(test_3d, gt0, Field3D{le0}), expected_3d3d)); } From 13ab1c03a8ad556dd372dbaf8eaaa8fb2ad6113b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 8 Apr 2019 12:21:49 +0100 Subject: [PATCH 1254/1783] Replace where functions with template versions --- include/where.hxx | 85 ++++++++++++++++------ src/field/where.cxx | 168 -------------------------------------------- 2 files changed, 64 insertions(+), 189 deletions(-) diff --git a/include/where.hxx b/include/where.hxx index 664d55a675..cf7b175863 100644 --- a/include/where.hxx +++ b/include/where.hxx @@ -36,28 +36,71 @@ /// @param[in] test The value which determines which input to use /// @param[in] gt0 Uses this value if test > 0.0 /// @param[in] le0 Uses this value if test <= 0.0 -const Field3D where(const Field2D &test, const Field3D >0, const Field3D &le0); -const Field3D where(const Field2D &test, const Field3D >0, BoutReal le0); -const Field3D where(const Field2D &test, BoutReal gt0, const Field3D &le0); -const Field3D where(const Field2D &test, const Field3D >0, const Field2D &le0); -const Field3D where(const Field2D &test, const Field2D >0, const Field3D &le0); +template ::type> +auto where(const T& test, const U& gt0, const V& le0) -> ResultType { + ASSERT1(areFieldsCompatible(test, gt0)); + ASSERT1(areFieldsCompatible(test, le0)); -/// For each point, choose between two inputs based on a third input -/// -/// @param[in] test The value which determines which input to use -/// @param[in] gt0 Uses this value if test > 0.0 -/// @param[in] le0 Uses this value if test <= 0.0 -const Field2D where(const Field2D &test, const Field2D >0, const Field2D &le0); -const Field2D where(const Field2D &test, const Field2D >0, BoutReal le0); -const Field2D where(const Field2D &test, BoutReal gt0, const Field2D &le0); -const Field2D where(const Field2D &test, BoutReal gt0, BoutReal le0); + ResultType result{emptyFrom(test)}; -/// For each point, choose between two inputs based on a third input -/// -/// @param[in] test The value which determines which input to use -/// @param[in] gt0 Uses this value if test > 0.0 -/// @param[in] le0 Uses this value if test <= 0.0 -const Field3D where(const Field3D &test, BoutReal gt0, const Field3D &le0); + BOUT_FOR(i, result.getRegion("RGN_ALL")) { + if (test[i] > 0.0) { + result[i] = gt0[i]; + } else { + result[i] = le0[i]; + } + } + return result; +} -#endif // __WHERE_H__ +template ::type> +auto where(const T& test, const U& gt0, BoutReal le0) -> ResultType { + ASSERT1(areFieldsCompatible(test, gt0)); + + ResultType result{emptyFrom(test)}; + + BOUT_FOR(i, result.getRegion("RGN_ALL")) { + if (test[i] > 0.0) { + result[i] = gt0[i]; + } else { + result[i] = le0; + } + } + return result; +} + +template ::type> +auto where(const T& test, BoutReal gt0, const V& le0) -> ResultType { + ASSERT1(areFieldsCompatible(test, le0)); + + ResultType result{emptyFrom(test)}; + BOUT_FOR(i, result.getRegion("RGN_ALL")) { + if (test[i] > 0.0) { + result[i] = gt0; + } else { + result[i] = le0[i]; + } + } + return result; +} + +template +auto where(const T& test, BoutReal gt0, BoutReal le0) -> ResultType { + + ResultType result{emptyFrom(test)}; + + BOUT_FOR(i, result.getRegion("RGN_ALL")) { + if (test[i] > 0.0) { + result[i] = gt0; + } else { + result[i] = le0; + } + } + return result; +} + +#endif // __WHERE_H__ diff --git a/src/field/where.cxx b/src/field/where.cxx index 6f2a8c028e..30763cb1a4 100644 --- a/src/field/where.cxx +++ b/src/field/where.cxx @@ -25,171 +25,3 @@ #include #include - -////////////////////////////////////////////////////////////////////////////////// -// Versions taking Field2D and returning Field3D - -const Field3D where(const Field2D &test, const Field3D >0, const Field3D &le0) { - ASSERT1(areFieldsCompatible(test, gt0)); - ASSERT1(areFieldsCompatible(test, le0)); - - Field3D result{emptyFrom(gt0)}; - - BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if(test[i] > 0.0) { - result[i] = gt0[i]; - }else { - result[i] = le0[i]; - } - } - return result; -} - -const Field3D where(const Field2D &test, const Field3D >0, BoutReal le0) { - ASSERT1(areFieldsCompatible(test, gt0)); - - Field3D result{emptyFrom(gt0)}; - - BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if(test[i] > 0.0) { - result[i] = gt0[i]; - }else { - result[i] = le0; - } - } - return result; -} - -const Field3D where(const Field2D &test, BoutReal gt0, const Field3D &le0) { - ASSERT1(areFieldsCompatible(test, le0)); - - Field3D result{emptyFrom(le0)}; - - BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if(test[i] > 0.0) { - result[i] = gt0; - }else { - result[i] = le0[i]; - } - } - - return result; -} - -const Field3D where(const Field2D &test, const Field3D >0, const Field2D &le0) { - ASSERT1(areFieldsCompatible(test, gt0)); - ASSERT1(areFieldsCompatible(test, le0)); - - Field3D result{emptyFrom(gt0)}; - - BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if(test[i] > 0.0) { - result[i] = gt0[i]; - }else { - result[i] = le0[i]; - } - } - - return result; -} - -const Field3D where(const Field2D &test, const Field2D >0, const Field3D &le0) { - ASSERT1(areFieldsCompatible(test, gt0)); - ASSERT1(areFieldsCompatible(test, le0)); - - Field3D result{emptyFrom(le0)}; - - BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if(test[i] > 0.0) { - result[i] = gt0[i]; - }else { - result[i] = le0[i]; - } - } - - return result; -} - -////////////////////////////////////////////////////////////////////////////////// -// Versions taking Field2D and returning Field2D - -const Field2D where(const Field2D &test, const Field2D >0, const Field2D &le0) { - ASSERT1(areFieldsCompatible(test, gt0)); - ASSERT1(areFieldsCompatible(test, le0)); - - Field2D result{emptyFrom(test)}; - - BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if(test[i] > 0.0) { - result[i] = gt0[i]; - }else { - result[i] = le0[i]; - } - } - - return result; -} - -const Field2D where(const Field2D &test, const Field2D >0, BoutReal le0) { - ASSERT1(areFieldsCompatible(test, gt0)); - - Field2D result{emptyFrom(test)}; - - BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if(test[i] > 0.0) { - result[i] = gt0[i]; - }else { - result[i] = le0; - } - } - - return result; -} - -const Field2D where(const Field2D &test, BoutReal gt0, const Field2D &le0) { - ASSERT1(areFieldsCompatible(test, le0)); - - Field2D result{emptyFrom(test)}; - - BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if(test[i] > 0.0) { - result[i] = gt0; - }else { - result[i] = le0[i]; - } - } - - return result; -} - -const Field2D where(const Field2D &test, BoutReal gt0, BoutReal le0) { - Field2D result{emptyFrom(test)}; - - BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if(test[i] > 0.0) { - result[i] = gt0; - }else { - result[i] = le0; - } - } - - return result; -} - -////////////////////////////////////////////////////////////////////////////////// -// Versions taking Field3D and returning Field3D - -const Field3D where(const Field3D &test, BoutReal gt0, const Field3D &le0) { - ASSERT1(areFieldsCompatible(test, le0)); - - Field3D result{emptyFrom(test)}; - - BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if(test[i] > 0.0) { - result[i] = gt0; - }else { - result[i] = le0[i]; - } - } - return result; -} From 0de5cac06556d588700452fe402d8f8480b1dc43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Mon, 8 Apr 2019 15:27:49 +0100 Subject: [PATCH 1255/1783] Don't try to build documentation * Otherwise latex is required for tests * If run in an interactive shell, latex will wait for user on error --- examples/makefile | 30 ------------------- .../integrated/test-compile-examples/runtest | 2 +- 2 files changed, 1 insertion(+), 31 deletions(-) delete mode 100644 examples/makefile diff --git a/examples/makefile b/examples/makefile deleted file mode 100644 index b0ff4a1492..0000000000 --- a/examples/makefile +++ /dev/null @@ -1,30 +0,0 @@ -# Makefile for example codes -# Works in the same way as the root Makefile - -BOUT_TOP = .. - -list=test_suite_list - -BUILD = $(shell grep '^[^\#!]' $(list) ) - -CHECKING = $(shell grep '^[^\#]' $(list) |sed s/\!// ) - -include $(BOUT_TOP)/make.config - - -CHECKING_=$(CHECKING:%=%_checking) - -.PHONY: $(BUILD) $(CHECKING_) check - -all: $(BUILD) - -buildncheck: all check - -$(BUILD): - @$(MAKE) --no-print-directory -C $@ - -check: $(CHECKING_) - @echo $(CHECKING_) - -$(CHECKING_): - @$(MAKE) --no-print-directory -C $(@:%_checking=%) runtest diff --git a/tests/integrated/test-compile-examples/runtest b/tests/integrated/test-compile-examples/runtest index 55e7d7c79c..cc7601a017 100755 --- a/tests/integrated/test-compile-examples/runtest +++ b/tests/integrated/test-compile-examples/runtest @@ -9,7 +9,7 @@ export PATH=$BOUT_TOP/bin:$PATH error=0 failed= -for target in $(find $BOUT_TOP/examples/ -name makefile) +for target in $(find $BOUT_TOP/examples/ -name makefile | grep -v doc) do dir=$(dirname ${target}) echo "Trying to compile ${dir}" From 6915b136700a83adeffa6e82edef0b22f6b69ce6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 8 Apr 2019 16:23:50 +0100 Subject: [PATCH 1256/1783] Fix check of number of y-points in grid file when using y-boundary cells --- src/mesh/data/gridfromfile.cxx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 64bb84131f..bbdbf1d607 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -244,6 +244,10 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) // Need to increase offset by 2*(# boundary guards) for each target position // we pass int ys = m->OffsetY; + + // Total number of y-boundary cells in grid file, used for check later. + // Value depends on if we are double-null or not. + int total_grid_yguards = 2*grid_yguards; if (m->numberOfXPoints > 1) { ASSERT1(m->numberOfXPoints == 2); // Need to check if we are before or after the target in the middle of the @@ -253,6 +257,9 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) // Note: neither ny_inner nor OffsetY include guard cells ys += 2*grid_yguards; } + + // Add y-boundary guard cells at upper target + total_grid_yguards += 2*grid_yguards; } // Index offsets into destination @@ -285,7 +292,7 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) ///Check if field dimensions are correct. y-direction if (grid_yguards > 0) { ///including ghostpoints - ASSERT1(field_dimensions[1] == m->GlobalNy - 2*myg + grid_yguards); + ASSERT1(field_dimensions[1] == m->GlobalNy - 2*myg + total_grid_yguards); ny_to_read = m->LocalNy; yd = grid_yguards - myg; ASSERT1(yd >= 0); From bf79be48e6598e9d9a38b2128d4eab229ba23473 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 8 Apr 2019 20:41:30 +0100 Subject: [PATCH 1257/1783] Fix string attribute writing from Hypnotoad Passing /CHAR argument to NCDF_ATTPUT means that strings read back in by the netCDF4-c++ interface have the correct length and can be compared as expected. Can remove work-around using strcmp in ParallelTransform implementations. --- src/mesh/parallel/fci.cxx | 10 +++------- src/mesh/parallel/identity.cxx | 10 +++------- src/mesh/parallel/shiftedmetric.cxx | 12 ++++-------- tools/idllib/file_write_string.pro | 2 +- 4 files changed, 11 insertions(+), 23 deletions(-) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index ed8c56c9a8..e97cfa042a 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -327,13 +327,9 @@ Field3D FCIMap::integrate(Field3D &f) const { void FCITransform::checkInputGrid() { std::string coordinates_type = ""; if (!mesh.get(coordinates_type, "coordinates_type")) { - // Note: using strcmp here because coordinates_type may have a length that is one - // greater than it should be (probably due to either IDL's string-attribute writing or - // netCDF's string-attribute reading). This makes the comparison - // operator==(std::string,std::string) fail. - if (strcmp(coordinates_type.c_str(), "fci") != 0) { - throw BoutException("Incorrect coordinate system type "+coordinates_type+" used " - "to generate metric components for FCITransform. Should be 'fci."); + if (coordinates_type != "fci") { + throw BoutException("Incorrect coordinate system type '"+coordinates_type+"' used " + "to generate metric components for FCITransform. Should be 'fci'."); } } // else: coordinate_system variable not found in grid input, indicates older input // file so must rely on the user having ensured the type is correct diff --git a/src/mesh/parallel/identity.cxx b/src/mesh/parallel/identity.cxx index 1fc32df926..4b25a285ae 100644 --- a/src/mesh/parallel/identity.cxx +++ b/src/mesh/parallel/identity.cxx @@ -21,14 +21,10 @@ void ParallelTransformIdentity::calcParallelSlices(Field3D& f) { void ParallelTransformIdentity::checkInputGrid() { std::string coordinates_type = ""; if (!mesh.get(coordinates_type, "coordinates_type")) { - // Note: using strcmp here because coordinates_type may have a length that is one - // greater than it should be (probably due to either IDL's string-attribute writing or - // netCDF's string-attribute reading). This makes the comparison - // operator==(std::string,std::string) fail. - if (strcmp(coordinates_type.c_str(), "field_aligned") != 0) { - throw BoutException("Incorrect coordinate system type "+coordinates_type+" used " + if (coordinates_type != "field_aligned") { + throw BoutException("Incorrect coordinate system type '"+coordinates_type+"' used " "to generate metric components for ParallelTransformIdentity. Should be " - "'field_aligned."); + "'field_aligned'."); } } // else: coordinate_system variable not found in grid input, indicates older input // file so must rely on the user having ensured the type is correct diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 26ec894e08..3cc1e8de2d 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -37,14 +37,10 @@ ShiftedMetric::ShiftedMetric(Mesh& m, CELL_LOC location_in, Field2D zShift_, void ShiftedMetric::checkInputGrid() { std::string coordinates_type = ""; if (!mesh.get(coordinates_type, "coordinates_type")) { - // Note: using strcmp here because coordinates_type may have a length that is one - // greater than it should be (probably due to either IDL's string-attribute writing or - // netCDF's string-attribute reading). This makes the comparison - // operator==(std::string,std::string) fail. - if (strcmp(coordinates_type.c_str(), "orthogonal") != 0) { - throw BoutException("Incorrect coordinate system type " + coordinates_type - + " used to generate metric components for ShiftedMetric. " - "Should be 'orthogonal."); + if (coordinates_type != "orthogonal") { + throw BoutException("Incorrect coordinate system type '" + coordinates_type + + "' used to generate metric components for ShiftedMetric. " + "Should be 'orthogonal'."); } } // else: coordinate_system variable not found in grid input, indicates older input // file so must rely on the user having ensured the type is correct diff --git a/tools/idllib/file_write_string.pro b/tools/idllib/file_write_string.pro index 15d235bc03..c68a902ade 100644 --- a/tools/idllib/file_write_string.pro +++ b/tools/idllib/file_write_string.pro @@ -26,7 +26,7 @@ FUNCTION file_write_string, handle, varname, data NCDF_CONTROL, handle.id, /REDEF - NCDF_ATTPUT, handle.id, /GLOBAL, varname, data + NCDF_ATTPUT, handle.id, /GLOBAL, varname, data, /CHAR NCDF_CONTROL, handle.id, /ENDEF From 17f06c46a43c16e84c53382df7ca208a317ee7fc Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 9 Apr 2019 11:09:46 +0100 Subject: [PATCH 1258/1783] Make EnableIfField work for multiple arguments and yield common type Also move it to field.hxx and bout::utils:: namespace This means it can now be used to give the correct result type of a function that takes some combination of Field2Ds and Field3Ds --- include/field.hxx | 49 ++++++++++++++++++++++++++++++++++++++ include/where.hxx | 11 ++++----- tests/unit/test_extras.hxx | 6 ++--- 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index cb8067cd56..c8564f015b 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -48,6 +48,55 @@ class Coordinates; #include #endif +namespace bout { +namespace utils { + +namespace details { +/// Helper class for fold expressions pre-C++17 +/// +/// Taken from "C++ Templates: The Complete Guide, Second Edition" +/// Addison-Wesley, 2017 +/// ISBN-13: 978-0-321-71412-1 +/// ISBN-10: 0-321-71412-1 +/// Copyright © 2017 by Addison-Wesley, David Vandevoorde, Nicolai +/// M. Josuttis, and Douglas Gregor. +constexpr bool and_all() { return true; } +template +constexpr bool and_all(T cond) { + return cond; +} +template +constexpr bool and_all(T cond, Ts... conds) { + return cond and and_all(conds...); +} +} // namespace details + +/// Enable a function if all the Ts are subclasses of `Field`, and +/// returns the common type: i.e. `Field3D` if at least one argument +/// is `Field3D`, otherwise `Field2D` if they are all `Field2D` +/// +/// Examples +/// -------- +/// +/// Consider the following template function: +/// +/// template > +/// auto where(const T& test, const U& gt0, const V& le0) -> ResultType { +/// // function body +/// } +/// +/// This function only "appears" if `T`, `U` and `V` are all +/// subclasses of `Field`. `ResultType` is the common type of `T`, `U` +/// and `V`. If `T` and `U` are both `Field2D`, `ResultType` is +/// `Field2D` if `V` is `Field2D`, and `Field3D` if `V` is `Field3D`. +template +using EnableIfField = + typename std::enable_if::value ...), + typename std::common_type::type>::type; +} // namespace utils +} // namespace bout + /*! * \brief Base class for fields * diff --git a/include/where.hxx b/include/where.hxx index cf7b175863..eb1f21c6f7 100644 --- a/include/where.hxx +++ b/include/where.hxx @@ -28,8 +28,9 @@ #ifndef __WHERE_H__ #define __WHERE_H__ -#include "field3d.hxx" +#include "field.hxx" #include "field2d.hxx" +#include "field3d.hxx" /// For each point, choose between two inputs based on a third input /// @@ -37,7 +38,7 @@ /// @param[in] gt0 Uses this value if test > 0.0 /// @param[in] le0 Uses this value if test <= 0.0 template ::type> + class ResultType = typename bout::utils::EnableIfField> auto where(const T& test, const U& gt0, const V& le0) -> ResultType { ASSERT1(areFieldsCompatible(test, gt0)); ASSERT1(areFieldsCompatible(test, le0)); @@ -54,8 +55,7 @@ auto where(const T& test, const U& gt0, const V& le0) -> ResultType { return result; } -template ::type> +template > auto where(const T& test, const U& gt0, BoutReal le0) -> ResultType { ASSERT1(areFieldsCompatible(test, gt0)); @@ -71,8 +71,7 @@ auto where(const T& test, const U& gt0, BoutReal le0) -> ResultType { return result; } -template ::type> +template > auto where(const T& test, BoutReal gt0, const V& le0) -> ResultType { ASSERT1(areFieldsCompatible(test, le0)); diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 5249dc5aa1..88d7ba8f9c 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -25,9 +25,7 @@ static constexpr BoutReal FFTTolerance{1.e-12}; void fillField(Field3D& f, std::vector>> values); void fillField(Field2D& f, std::vector> values); -/// Enable a function if T is a subclass of Field -template -using EnableIfField = typename std::enable_if::value>::type; +using bout::utils::EnableIfField; /// Returns a field filled with the result of \p fill_function at each point /// Arbitrary arguments can be passed to the field constructor @@ -80,7 +78,7 @@ auto inline getIndexXYZ(const IndPerp& index) -> std::string { } /// Is \p field equal to \p reference, with a tolerance of \p tolerance? -template , typename = EnableIfField> +template > auto IsFieldEqual(const T& field, const U& reference, const std::string& region = "RGN_ALL", BoutReal tolerance = BoutRealTolerance) -> ::testing::AssertionResult { From 65e054c5b31e0ce4b1a88c5455a1a756d342553d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 9 Apr 2019 11:12:46 +0100 Subject: [PATCH 1259/1783] Use ternaries in where.hxx to simplify further + clang-format --- include/where.hxx | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/include/where.hxx b/include/where.hxx index eb1f21c6f7..1a3a7aff18 100644 --- a/include/where.hxx +++ b/include/where.hxx @@ -1,13 +1,13 @@ /*!************************************************************************* * \file where.hxx - * + * * A set of functions which choose between two values * ************************************************************************** * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -46,11 +46,7 @@ auto where(const T& test, const U& gt0, const V& le0) -> ResultType { ResultType result{emptyFrom(test)}; BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if (test[i] > 0.0) { - result[i] = gt0[i]; - } else { - result[i] = le0[i]; - } + result[i] = (test[i] > 0.0) ? gt0[i] : le0[i]; } return result; } @@ -61,12 +57,8 @@ auto where(const T& test, const U& gt0, BoutReal le0) -> ResultType { ResultType result{emptyFrom(test)}; - BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if (test[i] > 0.0) { - result[i] = gt0[i]; - } else { - result[i] = le0; - } + BOUT_FOR(i, result.getRegion("RGN_ALL")) { // clang-format: ignore + result[i] = (test[i] > 0.0) ? gt0[i] : le0; } return result; } @@ -77,27 +69,18 @@ auto where(const T& test, BoutReal gt0, const V& le0) -> ResultType { ResultType result{emptyFrom(test)}; - BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if (test[i] > 0.0) { - result[i] = gt0; - } else { - result[i] = le0[i]; - } + BOUT_FOR(i, result.getRegion("RGN_ALL")) { // clang-format: ignore + result[i] = (test[i] > 0.0) ? gt0 : le0[i]; } return result; } template auto where(const T& test, BoutReal gt0, BoutReal le0) -> ResultType { - ResultType result{emptyFrom(test)}; - BOUT_FOR(i, result.getRegion("RGN_ALL")) { - if (test[i] > 0.0) { - result[i] = gt0; - } else { - result[i] = le0; - } + BOUT_FOR(i, result.getRegion("RGN_ALL")) { // clang-format: ignore + result[i] = (test[i] > 0.0) ? gt0 : le0; } return result; } From 2e336f64599fc191f081090f39499621a0e78bcb Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 9 Apr 2019 15:08:28 +0100 Subject: [PATCH 1260/1783] Remove meshFromValue from Options header Already removed from options.cxx, but was still in header. --- include/options.hxx | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index da5f1ae3a1..84cd12e85b 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -56,23 +56,6 @@ class Options; #include #include -namespace bout { -namespace utils { - - /// Get a mesh pointer from the given object. - /// In most cases this is nullptr - template - Mesh* meshFromValue(const T& UNUSED(value)) { - return nullptr; - } - - template <> - Mesh* meshFromValue(const Field2D& value); - template <> - Mesh* meshFromValue(const Field3D& value); -} -} - /// Class to represent hierarchy of options /*! * From 66f99c1e64418812349fa32cebe360982db6b267 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 9 Apr 2019 15:22:26 +0100 Subject: [PATCH 1261/1783] Remove 'virtual' keyword from overriding methods --- src/invert/laplace/impls/multigrid/multigrid_laplace.hxx | 2 +- src/invert/laplace/impls/mumps/mumps_laplace.hxx | 2 +- src/invert/laplace/impls/naulin/naulin_laplace.hxx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx index 402d2f3bd1..0ef7f3bc39 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx @@ -192,7 +192,7 @@ public: D = val; } - virtual bool uses3DCoefs() const override { return true; } + bool uses3DCoefs() const override { return true; } const FieldPerp solve(const FieldPerp &b) override { ASSERT1(localmesh == b.getMesh()); diff --git a/src/invert/laplace/impls/mumps/mumps_laplace.hxx b/src/invert/laplace/impls/mumps/mumps_laplace.hxx index 616f352bed..ac2990dc6f 100644 --- a/src/invert/laplace/impls/mumps/mumps_laplace.hxx +++ b/src/invert/laplace/impls/mumps/mumps_laplace.hxx @@ -172,7 +172,7 @@ public: issetE = true; } - virtual bool uses3DCoefs() const override { return true; } + bool uses3DCoefs() const override { return true; } void setFlags(int f) {throw BoutException("May not change the value of flags during run in LaplaceMumps as it might change the number of non-zero matrix elements: flags may only be set in the options file.");} diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.hxx b/src/invert/laplace/impls/naulin/naulin_laplace.hxx index 094e29960a..71762294a5 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.hxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.hxx @@ -102,7 +102,7 @@ public: throw BoutException("LaplaceNaulin does not have Ez coefficient"); } - virtual bool uses3DCoefs() const override { return true; } + bool uses3DCoefs() const override { return true; } const FieldPerp solve(const FieldPerp &b) override {return solve(b,b);} const FieldPerp solve(const FieldPerp &UNUSED(b), From 924c5006de45f389b9f88c3d4a5829c721d43630 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 9 Apr 2019 15:34:22 +0100 Subject: [PATCH 1262/1783] Utility functions take string arguments as const references Avoids unnecessary copies. --- src/mesh/coordinates.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 938da85b91..c8d6278ad1 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -125,7 +125,7 @@ Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location, // If the CELL_CENTRE variable was read, the staggered version is required to // also exist for consistency -void checkStaggeredGet(Mesh* mesh, std::string name, std::string suffix) { +void checkStaggeredGet(Mesh* mesh, const std::string& name, const std::string& suffix) { if (mesh->sourceHasVar(name) != mesh->sourceHasVar(name+suffix)) { throw BoutException("Attempting to read staggered fields from grid, but " + name + " is not present in both CELL_CENTRE and staggered versions."); @@ -133,8 +133,8 @@ void checkStaggeredGet(Mesh* mesh, std::string name, std::string suffix) { } // convenience function for repeated code -void getAtLoc(Mesh* mesh, Field2D &var, std::string name, std::string suffix, - CELL_LOC location, BoutReal default_value = 0.) { +void getAtLoc(Mesh* mesh, Field2D &var, const std::string& name, + const std::string& suffix, CELL_LOC location, BoutReal default_value = 0.) { checkStaggeredGet(mesh, name, suffix); mesh->get(var, name+suffix, default_value); From ea264d0300e64f23791c7d51107fd521cd5c3d42 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 10 Apr 2019 00:14:03 +0100 Subject: [PATCH 1263/1783] Started 2nd-order split RK scheme Uses Strang splitting (2nd order), with RK3-SSP for the advection parts, and Runge-Kutta-Legendre for the diffusion. This method can take timesteps considerably larger than a standard explicit scheme can for diffusive problems. --- src/solver/impls/split-rk/README.md | 17 +++ src/solver/impls/split-rk/makefile | 8 ++ src/solver/impls/split-rk/split-rk.cxx | 177 +++++++++++++++++++++++++ src/solver/impls/split-rk/split-rk.hxx | 81 +++++++++++ 4 files changed, 283 insertions(+) create mode 100644 src/solver/impls/split-rk/README.md create mode 100644 src/solver/impls/split-rk/makefile create mode 100644 src/solver/impls/split-rk/split-rk.cxx create mode 100644 src/solver/impls/split-rk/split-rk.hxx diff --git a/src/solver/impls/split-rk/README.md b/src/solver/impls/split-rk/README.md new file mode 100644 index 0000000000..b392cda715 --- /dev/null +++ b/src/solver/impls/split-rk/README.md @@ -0,0 +1,17 @@ +Strang split Runge Kutta +======================== + +A second order Strang splitting scheme: + + - 2nd order Runge-Kutta-Legendre method for the diffusion (parabolic) part + https://doi.org/10.1016/j.jcp.2013.08.021 + + - 3rd order SSP-RK3 scheme for the advection (hyperbolic) part + http://www.cscamm.umd.edu/tadmor/pub/linear-stability/Gottlieb-Shu-Tadmor.SIREV-01.pdf + +Each timestep consists of + + - A half timestep of the diffusion part + - A full timestep of the advection part + - A half timestep of the diffusion part + diff --git a/src/solver/impls/split-rk/makefile b/src/solver/impls/split-rk/makefile new file mode 100644 index 0000000000..4d8153a3b5 --- /dev/null +++ b/src/solver/impls/split-rk/makefile @@ -0,0 +1,8 @@ + +BOUT_TOP = ../../../.. + +SOURCEC = split-rk.cxx +SOURCEH = $(SOURCEC:%.cxx=%.hxx) +TARGET = lib + +include $(BOUT_TOP)/make.config diff --git a/src/solver/impls/split-rk/split-rk.cxx b/src/solver/impls/split-rk/split-rk.cxx new file mode 100644 index 0000000000..8096b448ef --- /dev/null +++ b/src/solver/impls/split-rk/split-rk.cxx @@ -0,0 +1,177 @@ +#include "split-rk.hxx" + +int SplitRK::init(int nout, BoutReal tstep) { + AUTO_TRACE(); + + /// Call the generic initialisation first + if (Solver::init(nout, tstep)) + return 1; + + output.write(_("\n\tSplit Runge-Kutta-Legendre and SSP-RK3 solver\n")); + + nsteps = nout; // Save number of output steps + out_timestep = tstep; + + // Calculate number of variables + const int nlocal = getLocalN(); + + // Allocate memory + state.reallocate(nlocal); + + // memory for taking a single time step + u1.reallocate(nlocal); + u2.reallocate(nlocal); + u3.reallocate(nlocal); + L.reallocate(nlocal); + + // Put starting values into f + save_vars(std::begin(state)); + + // Get options + auto &opt = *options; + timestep = opt["timestep"] + .doc("Internal timestep. This may be rounded down.") + .withDefault(out_timestep); + + ninternal_steps = static_cast(std::ceil(out_timestep / timestep)); + + ASSERT0(ninternal_steps > 0); + + timestep = out_timestep / ninternal_steps; + output.write(_("\tUsing a timestep %e"), timestep); + + nstages = opt["nstages"].doc("Number of stages in RKL step. Must be > 1").withDefault(10); + ASSERT0(nstages > 1); + + return 0; +} + +int SplitRK::run() { + AUTO_TRACE(); + + for (int step = 0; step < nsteps; step++) { + // Take an output step + + for (int internal_step = 0; internal_step < ninternal_steps; internal_step++) { + // Take a single step + state = take_step(simtime, timestep, state); + + simtime += timestep; + + call_timestep_monitors(simtime, timestep); + } + + load_vars(std::begin(state)); // Put result into variables + // Call rhs function to get extra variables at this time + run_rhs(simtime); + + iteration++; // Advance iteration number + + /// Call the monitor function + + if(call_monitors(simtime, step, nsteps)) { + // User signalled to quit + break; + } + } + return 0; +} + +Array SplitRK::take_step(BoutReal curtime, BoutReal dt, Array& start) { + return take_diffusion_step(curtime + 0.5*dt, 0.5*dt, // Half step + take_advection_step(curtime, dt, // Full step + take_diffusion_step(curtime, 0.5*dt, start))); // Half step +} + +Array SplitRK::take_diffusion_step(BoutReal curtime, BoutReal dt, Array& start) { + + const BoutReal weight = dt * 4./(SQ(nstages) + nstages - 2); + + load_vars(std::begin(start)); + run_diffusive(curtime); + save_derivs(std::begin(L)); // L = f(y0) + + // Stage j = 1 + // y_m2 = y0 + weight/3.0 * f(y0) -> u2 + + BOUT_OMP(parallel for) + for (int i = 0; i < L.size(); i++) { + u2[i] = start[i] + (weight/3.0) * L[i]; + } + + // Stage j = 2 + // mu = 0.75, nu terms cancel + load_vars(std::begin(u2)); + run_diffusive(curtime); + save_derivs(std::begin(u3)); // f(y_m2) -> u3 + + BOUT_OMP(parallel for) + for (int i = 0; i < u3.size(); i++) { + u1[i] = 0.75 * u2[i] + 0.25 * start[i] + 0.75 * weight * u3[i] - 0.5 * weight * L[i]; + } + + BoutReal b_jm2 = 1. / 3; // b_{j - 2} + BoutReal b_jm1 = 1. / 3; // b_{j - 1} + + for (int j = 3; j <= nstages; j++) { + + BoutReal b_j = (SQ(j) + j - 2.0) / (2.*j * (j + 1.)); + + BoutReal mu = (2.*j - 1.)/j * b_j / b_jm1; + BoutReal nu = -(j - 1.)/j * b_j / b_jm2; + BoutReal a_jm1 = 1. - b_jm1; + + load_vars(std::begin(u1)); + run_diffusive(curtime); + save_derivs(std::begin(u3)); // f(y_m1) -> u3 + + BOUT_OMP(parallel for) + for (int i = 0; i < u3.size(); i++) { + // Next stage result in u3 + u3[i] = mu * u1[i] + nu * u2[i] + (1. - mu - nu) * start[i] + + mu * weight * u3[i] - a_jm1 * mu * weight * L[i]; + } + + // Cycle values + b_jm2 = b_jm1; + b_jm1 = b_j; + + // Cycle u2 <- u1 <- u3 <- u2 + // so that no new memory is allocated, and no arrays point to the same data + Array tmp = u2; + u2 = u1; + u1 = u3; + u3 = tmp; + + // Most recent now in u1, then u2, then u3 + } + return u1; +} + +Array SplitRK::take_advection_step(BoutReal curtime, BoutReal dt, Array& start) { + const int nlocal = getLocalN(); + + load_vars(std::begin(start)); + run_convective(curtime); + save_derivs(std::begin(L)); + + BOUT_OMP(parallel for) + for(int i=0;i. + * + **************************************************************************/ + +class SplitRK; + +#pragma once + +#ifndef SPLITRK_HXX +#define SPLITRK_HXX + +#include +#include + +#include +namespace { +RegisterSolver registersolversplitrk("splitrk"); +} + +class SplitRK : public Solver { +public: + SplitRK(Options *opt = nullptr) : Solver(opt) {} + ~SplitRK() = default; + + int init(int nout, BoutReal tstep) override; + + int run() override; +private: + int nstages; ///< Number of stages in the RKL + + BoutReal out_timestep; ///< The output timestep + int nsteps; ///< Number of output steps + + int ninternal_steps; ///< Number of internal timesteps + BoutReal timestep; ///< The internal timestep + + /// System state + Array state; + + // Temporary time-stepping arrays + Array u1, u2, u3, L; + + /// Take a combined step + /// Uses 2nd order Strang splitting + Array take_step(BoutReal curtime, BoutReal dt, Array& start); + + /// Take a step of the diffusion terms + /// Uses the Runge-Kutta-Legendre 2nd order method + Array take_diffusion_step(BoutReal curtime, BoutReal dt, + Array& start); + + /// Take a step of the advection terms + /// Uses the Strong Stability Preserving Runge-Kutta 3rd order method + Array take_advection_step(BoutReal curtime, BoutReal dt, + Array& start); +}; + +#endif From bff330e400f9b67f3a86051cfba7beae6dec34f3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 10 Apr 2019 12:16:58 +0100 Subject: [PATCH 1264/1783] Fix error test in test-griddata Should check the maximum absolute error - previously was checking the minimum. --- tests/integrated/test-griddata/runtest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integrated/test-griddata/runtest b/tests/integrated/test-griddata/runtest index 19e3906527..16627fcb95 100755 --- a/tests/integrated/test-griddata/runtest +++ b/tests/integrated/test-griddata/runtest @@ -38,7 +38,7 @@ for nproc in [1]: dr = float(rwidth) / nx # Test value of dx - if np.min(np.abs(dx - dr * Bpxy * Rxy)) > 1e-7: + if np.max(np.abs(dx - dr * Bpxy * Rxy)) > 1e-7: print("Failed: dx does not match") exit(1) From 113884b013bbbff9dba702de42ff1ec9bd65240f Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 10 Apr 2019 12:24:49 +0100 Subject: [PATCH 1265/1783] splitrk working, some examples - Some changes to ensure that Arrays were always unique without having to reallocate. - Updated the IMEX/drift-wave and IMEX/advection-diffusion examples --- examples/IMEX/advection-diffusion/README.md | 34 ++++++++ .../IMEX/advection-diffusion/data/BOUT.inp | 78 ++++--------------- examples/IMEX/advection-diffusion/imex.cxx | 74 ++++++++---------- examples/IMEX/drift-wave/test-drift.cxx | 8 +- src/solver/impls/makefile | 2 +- src/solver/impls/split-rk/split-rk.cxx | 59 +++++++------- src/solver/impls/split-rk/split-rk.hxx | 22 ++++-- src/solver/solverfactory.cxx | 1 + 8 files changed, 135 insertions(+), 143 deletions(-) create mode 100644 examples/IMEX/advection-diffusion/README.md diff --git a/examples/IMEX/advection-diffusion/README.md b/examples/IMEX/advection-diffusion/README.md new file mode 100644 index 0000000000..af12df8376 --- /dev/null +++ b/examples/IMEX/advection-diffusion/README.md @@ -0,0 +1,34 @@ +# Advection-Diffusion in 2D + +Doubly periodic 2D domain in X-Z, evolving a single variable `U`. +An advection velocity `Vx` in the X direction, and diffusion in Z. + +The default settings use the `splitrk` method, which uses Strang splitting +to combine RK3-SSP (advection) with Runge-Kutta-Legendre (diffusion). + +``` +$ ./imex +1.000e-02 31 181 9.23e-02 60.7 0.0 0.7 8.6 30.1 +2.000e-02 31 181 9.00e-02 61.6 0.0 0.7 7.2 30.6 +... +``` + +This test case can be used to try different solvers, for example the PVODE solver +(adaptive implicit BDF scheme): + +``` +$ ./imex solver:type=pvode +1.000e-02 338 338 3.68e-01 62.8 0.0 0.5 2.0 34.7 +2.000e-02 156 156 1.78e-01 59.8 0.0 0.5 3.5 36.1 +... +``` + +In this case the `splitrk` solver is faster, but note that it has no error +control. Increasing the tolerances for `CVODE` also speeds up the calculation: +``` +$ ./imex solver:type=pvode solver:atol=1e-4 solver:rtol=1e-2 +1.000e-02 116 116 1.35e-01 58.6 0.0 0.5 5.5 35.4 +2.000e-02 56 56 7.09e-02 54.5 0.0 0.5 8.4 36.6 +3.000e-02 34 34 4.67e-02 49.5 0.0 0.5 13.3 36.7 +... +``` diff --git a/examples/IMEX/advection-diffusion/data/BOUT.inp b/examples/IMEX/advection-diffusion/data/BOUT.inp index 883bddeb1f..8efa164fad 100644 --- a/examples/IMEX/advection-diffusion/data/BOUT.inp +++ b/examples/IMEX/advection-diffusion/data/BOUT.inp @@ -3,19 +3,13 @@ ################################################## # settings used by the core code -NOUT = 100 # number of time-steps +NOUT = 50 # number of time-steps TIMESTEP = 1e-2 # time between outputs -MZ = 129 # number of points in z direction (2^n + 1) - -ZPERIOD = 6.28319 # Fraction of a torus. 2*PI sets Z length to 1 - -dump_format = "nc" # Set extension for dump files (nc = NetCDF) - -#NXPE = 1 - periodicX = true # Make domain periodic in X +myg = 0 + ################################################## # derivative methods @@ -42,71 +36,33 @@ flux = U1 [mesh] -nx = 132 -#dx = 0.03125 # 1/32 -#dx = 0.015625 #1/64 -dx = 0.0078125 #1/128 -#dx = 0.00390625 #1/256 -#dx = 0.001953125 #1/512 -#dx = 0.0009765625 #1/1024 - -ny = 5 -dy = 0.1 # 1/512 +nx = 132 +ny = 1 +nz = 128 -#ixseps1 = -1 #Specify ixseps to stop y from being periodic -#ixseps2 = -1 +dx = 1 / nx +dz = 1 / (nz-4) ################################################## # Solver settings [solver] -# mudq, mldq, mukeep, mlkeep preconditioner options -ATOL = 1.0e-10 # absolute tolerance -RTOL = 1.0e-5 # relative tolerance -mxstep = 50000 - -type=arkode #use arkode solver -imex=true #use split operator ImEx method -explicit=true #include explicit operator -implicit=true #include implicit operator - - +type = splitrk +timestep = 1e-3 # Fixed internal timestep +nstages = 9 # Stages in RKL steps for diffusive component ################################################## # settings for split operator model [imex] -cz = 100.0 -cx = 1.0 -################################################## -# settings for individual variables -# The section "All" defines default settings for all variables -# These can be overridden for individual variables in -# a section of that name. - -[All] -scale = 1.0 # default size of initial perturbations - -# boundary conditions -# ------------------- -# dirichlet - Zero value -# neumann - Zero gradient -# zerolaplace - Laplacian = 0, decaying solution -# constlaplace - Laplacian = const, decaying solution -# -# relax( ) - Make boundary condition relaxing - -#bndry_xin = dirichlet_o2(1.0) # Default zero value -#bndry_all = neumann -# form of initial profile: -# 0 - constant -# 1 - Gaussian -# 2 - Sinusoidal -# 3 - Mix of mode numbers +vx = 2.0 # Advection velocity in X +Dz = 1.0 # Diffusion coefficient in Z + +# Settings for evolving variable [U] -scale = 1.0 -function = 0.125*gauss(x-0.2,0.05)*gauss(z-0.5*2*3.14159,0.05*2*3.14159) + H(x-0.7)*(1-H(x-0.8))*H(z-0.45*2*3.14159)*(1-H(z-0.55*2*3.14159)) +zs = z / (2π) +function = exp(-((x-0.5)/0.1)^2 - ((zs-0.5)/0.1)^2) diff --git a/examples/IMEX/advection-diffusion/imex.cxx b/examples/IMEX/advection-diffusion/imex.cxx index 4df83f93ec..d8e6a9b2ca 100644 --- a/examples/IMEX/advection-diffusion/imex.cxx +++ b/examples/IMEX/advection-diffusion/imex.cxx @@ -7,58 +7,46 @@ * * *******************************************************************/ - -#include -#include -#include +#include #include +class IMEXexample : public PhysicsModel { +private: + Field3D U; // Evolving variable and auxilliary variable + Field3D Vx, Dz; // Velocity, diffusion -int diffusive(BoutReal time); - -Field3D U,Cx,Cz; // Evolving variable and auxilliary variable - -BoutReal cx,cz; //Advection velocity, diffusion rate - -int physics_init(bool restarting) { - - // Give the solver two RHS functions - // First function is explicit, second is implicit - solver->setSplitOperator(physics_run,diffusive); +protected: + int init(bool) { + setSplitOperator(); // Split into convective and diffusive - // Get options - auto globalOptions = Options::root(); - auto options = globalOptions["imex"]; - cz = options["cz"].withDefault(100.0); - cx = options["cx"].withDefault(1.0); + // Get options + auto& options = Options::root()["imex"]; + Vx = options["Vx"].doc("Velocity in X").withDefault(Field3D(100.0)); + Dz = options["Dz"].doc("Diffusion in Z").withDefault(Field3D(1.0)); - SOLVE_FOR(U); + SOLVE_FOR(U); - Cx = cx; - Cz = cz; + return 0; + } - return 0; -} - -int physics_run(BoutReal time) { - - // Need communication - mesh->communicate(U); + int convective(BoutReal) { + // Need communication + mesh->communicate(U); - //Slow Passive advection - ddt(U) = -VDDX(Cx,U); + // Passive advection + ddt(U) = -VDDX(Vx,U); - return 0; -} - -int diffusive(BoutReal time) { - - mesh->communicate(U); - //Fast passive advection - - ddt(U) = -VDDZ(Cz,U); + return 0; + } - return 0; -} + int diffusive(BoutReal) { + mesh->communicate(U); + // Diffusion + ddt(U) = Dz*D2DZ2(U); + + return 0; + } +}; +BOUTMAIN(IMEXexample); diff --git a/examples/IMEX/drift-wave/test-drift.cxx b/examples/IMEX/drift-wave/test-drift.cxx index 012f074002..42a1696767 100644 --- a/examples/IMEX/drift-wave/test-drift.cxx +++ b/examples/IMEX/drift-wave/test-drift.cxx @@ -5,7 +5,7 @@ class DriftWave : public PhysicsModel { protected: - int init(bool restart) { + int init(bool) { // Specify evolving variables solver->add(Vort, "Vort"); // Vorticity solver->add(Ne, "Ne"); // Electron density @@ -13,7 +13,7 @@ class DriftWave : public PhysicsModel { SAVE_REPEAT(phi); // Get the normalised resistivity - Options::getRoot()->getSection("drift")->get("nu", nu, 1.0); + nu = Options::root()["drift"]["nu"].doc("Normalised resistivity").withDefault(1.0); // Read background profile mesh->get(Ne0, "Ne0"); @@ -26,7 +26,7 @@ class DriftWave : public PhysicsModel { return 0; } - int convective(BoutReal time) { + int convective(BoutReal) { // Non-stiff parts of the problem here // Here just the nonlinear advection @@ -45,7 +45,7 @@ class DriftWave : public PhysicsModel { return 0; } - int diffusive(BoutReal time) { + int diffusive(BoutReal) { // Parallel dynamics treated implicitly // Solve for potential diff --git a/src/solver/impls/makefile b/src/solver/impls/makefile index 893626f24b..f342840cc1 100644 --- a/src/solver/impls/makefile +++ b/src/solver/impls/makefile @@ -6,7 +6,7 @@ DIRS = arkode \ petsc \ snes imex-bdf2 \ power slepc \ - karniadakis rk4 euler rk3-ssp rkgeneric + karniadakis rk4 euler rk3-ssp rkgeneric split-rk TARGET = lib include $(BOUT_TOP)/make.config diff --git a/src/solver/impls/split-rk/split-rk.cxx b/src/solver/impls/split-rk/split-rk.cxx index 8096b448ef..767a895f7f 100644 --- a/src/solver/impls/split-rk/split-rk.cxx +++ b/src/solver/impls/split-rk/split-rk.cxx @@ -22,7 +22,7 @@ int SplitRK::init(int nout, BoutReal tstep) { u1.reallocate(nlocal); u2.reallocate(nlocal); u3.reallocate(nlocal); - L.reallocate(nlocal); + dydt.reallocate(nlocal); // Put starting values into f save_vars(std::begin(state)); @@ -34,11 +34,10 @@ int SplitRK::init(int nout, BoutReal tstep) { .withDefault(out_timestep); ninternal_steps = static_cast(std::ceil(out_timestep / timestep)); - ASSERT0(ninternal_steps > 0); timestep = out_timestep / ninternal_steps; - output.write(_("\tUsing a timestep %e"), timestep); + output.write(_("\tUsing a timestep %e\n"), timestep); nstages = opt["nstages"].doc("Number of stages in RKL step. Must be > 1").withDefault(10); ASSERT0(nstages > 1); @@ -54,7 +53,7 @@ int SplitRK::run() { for (int internal_step = 0; internal_step < ninternal_steps; internal_step++) { // Take a single step - state = take_step(simtime, timestep, state); + take_step(simtime, timestep, state, state); simtime += timestep; @@ -77,26 +76,33 @@ int SplitRK::run() { return 0; } -Array SplitRK::take_step(BoutReal curtime, BoutReal dt, Array& start) { - return take_diffusion_step(curtime + 0.5*dt, 0.5*dt, // Half step - take_advection_step(curtime, dt, // Full step - take_diffusion_step(curtime, 0.5*dt, start))); // Half step +void SplitRK::take_step(BoutReal curtime, BoutReal dt, Array& start, + Array& result) { + // Half step + take_diffusion_step(curtime, 0.5*dt, start, result); + + // Full step + take_advection_step(curtime, dt, result, result); + + // Half step + take_diffusion_step(curtime + 0.5*dt, 0.5*dt, result, result); } -Array SplitRK::take_diffusion_step(BoutReal curtime, BoutReal dt, Array& start) { +void SplitRK::take_diffusion_step(BoutReal curtime, BoutReal dt, Array& start, + Array& result) { const BoutReal weight = dt * 4./(SQ(nstages) + nstages - 2); load_vars(std::begin(start)); run_diffusive(curtime); - save_derivs(std::begin(L)); // L = f(y0) + save_derivs(std::begin(dydt)); // dydt = f(y0) // Stage j = 1 // y_m2 = y0 + weight/3.0 * f(y0) -> u2 BOUT_OMP(parallel for) - for (int i = 0; i < L.size(); i++) { - u2[i] = start[i] + (weight/3.0) * L[i]; + for (int i = 0; i < dydt.size(); i++) { + u2[i] = start[i] + (weight/3.0) * dydt[i]; } // Stage j = 2 @@ -107,7 +113,7 @@ Array SplitRK::take_diffusion_step(BoutReal curtime, BoutReal dt, Arra BOUT_OMP(parallel for) for (int i = 0; i < u3.size(); i++) { - u1[i] = 0.75 * u2[i] + 0.25 * start[i] + 0.75 * weight * u3[i] - 0.5 * weight * L[i]; + u1[i] = 0.75 * (u2[i] + weight * u3[i]) + 0.25 * start[i] - 0.5 * weight * dydt[i]; } BoutReal b_jm2 = 1. / 3; // b_{j - 2} @@ -128,8 +134,8 @@ Array SplitRK::take_diffusion_step(BoutReal curtime, BoutReal dt, Arra BOUT_OMP(parallel for) for (int i = 0; i < u3.size(); i++) { // Next stage result in u3 - u3[i] = mu * u1[i] + nu * u2[i] + (1. - mu - nu) * start[i] - + mu * weight * u3[i] - a_jm1 * mu * weight * L[i]; + u3[i] = mu * (u1[i] + weight * (u3[i] - a_jm1 * dydt[i])) + nu * u2[i] + + (1. - mu - nu) * start[i]; } // Cycle values @@ -138,40 +144,39 @@ Array SplitRK::take_diffusion_step(BoutReal curtime, BoutReal dt, Arra // Cycle u2 <- u1 <- u3 <- u2 // so that no new memory is allocated, and no arrays point to the same data - Array tmp = u2; - u2 = u1; - u1 = u3; - u3 = tmp; + swap(u1, u2); + swap(u1, u3); // Most recent now in u1, then u2, then u3 } - return u1; + swap(u1, result); } -Array SplitRK::take_advection_step(BoutReal curtime, BoutReal dt, Array& start) { +void SplitRK::take_advection_step(BoutReal curtime, BoutReal dt, Array& start, + Array& result) { const int nlocal = getLocalN(); load_vars(std::begin(start)); run_convective(curtime); - save_derivs(std::begin(L)); + save_derivs(std::begin(dydt)); BOUT_OMP(parallel for) for(int i=0;i state; - // Temporary time-stepping arrays - Array u1, u2, u3, L; + /// Temporary time-stepping arrays + /// These are used by both diffusion and advection time-step routines + Array u1, u2, u3, dydt; /// Take a combined step /// Uses 2nd order Strang splitting - Array take_step(BoutReal curtime, BoutReal dt, Array& start); + /// + /// Note: start and result can be the same + void take_step(BoutReal curtime, BoutReal dt, Array& start, + Array& result); /// Take a step of the diffusion terms /// Uses the Runge-Kutta-Legendre 2nd order method - Array take_diffusion_step(BoutReal curtime, BoutReal dt, - Array& start); + /// + /// Note: start and result can be the same + void take_diffusion_step(BoutReal curtime, BoutReal dt, + Array& start, Array& result); /// Take a step of the advection terms /// Uses the Strong Stability Preserving Runge-Kutta 3rd order method - Array take_advection_step(BoutReal curtime, BoutReal dt, - Array& start); + /// + /// Note: start and result can be the same + void take_advection_step(BoutReal curtime, BoutReal dt, Array& start, + Array& result); }; #endif diff --git a/src/solver/solverfactory.cxx b/src/solver/solverfactory.cxx index 6852b42e92..a9c4c6bccc 100644 --- a/src/solver/solverfactory.cxx +++ b/src/solver/solverfactory.cxx @@ -14,6 +14,7 @@ #include "impls/rkgeneric/rkgeneric.hxx" #include "impls/slepc/slepc.hxx" #include "impls/snes/snes.hxx" +#include "impls/split-rk/split-rk.hxx" SolverFactory* SolverFactory::instance = nullptr; From fc0e09c714f5ffeacf4d642356381752e3d558ad Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 10 Apr 2019 12:37:27 +0100 Subject: [PATCH 1266/1783] Test of gridfile reading from gridfiles with y-boundary cells --- .../data-doublenull-0/BOUT.inp | 2 + .../data-doublenull-1/BOUT.inp | 2 + .../data-doublenull-2/BOUT.inp | 2 + .../data-singlenull-0/BOUT.inp | 2 + .../data-singlenull-1/BOUT.inp | 2 + .../data-singlenull-2/BOUT.inp | 2 + .../make_inputs.py | 111 ++++++++++ .../test-griddata-yboundary-guards/makefile | 6 + .../test-griddata-yboundary-guards/runtest | 191 ++++++++++++++++++ .../test_griddata.cxx | 20 ++ 10 files changed, 340 insertions(+) create mode 100644 tests/integrated/test-griddata-yboundary-guards/data-doublenull-0/BOUT.inp create mode 100644 tests/integrated/test-griddata-yboundary-guards/data-doublenull-1/BOUT.inp create mode 100644 tests/integrated/test-griddata-yboundary-guards/data-doublenull-2/BOUT.inp create mode 100644 tests/integrated/test-griddata-yboundary-guards/data-singlenull-0/BOUT.inp create mode 100644 tests/integrated/test-griddata-yboundary-guards/data-singlenull-1/BOUT.inp create mode 100644 tests/integrated/test-griddata-yboundary-guards/data-singlenull-2/BOUT.inp create mode 100755 tests/integrated/test-griddata-yboundary-guards/make_inputs.py create mode 100644 tests/integrated/test-griddata-yboundary-guards/makefile create mode 100755 tests/integrated/test-griddata-yboundary-guards/runtest create mode 100644 tests/integrated/test-griddata-yboundary-guards/test_griddata.cxx diff --git a/tests/integrated/test-griddata-yboundary-guards/data-doublenull-0/BOUT.inp b/tests/integrated/test-griddata-yboundary-guards/data-doublenull-0/BOUT.inp new file mode 100644 index 0000000000..c8d7b562d1 --- /dev/null +++ b/tests/integrated/test-griddata-yboundary-guards/data-doublenull-0/BOUT.inp @@ -0,0 +1,2 @@ +[mesh] +file = data-doublenull-0/grid-doublenull-0.nc diff --git a/tests/integrated/test-griddata-yboundary-guards/data-doublenull-1/BOUT.inp b/tests/integrated/test-griddata-yboundary-guards/data-doublenull-1/BOUT.inp new file mode 100644 index 0000000000..72de92da69 --- /dev/null +++ b/tests/integrated/test-griddata-yboundary-guards/data-doublenull-1/BOUT.inp @@ -0,0 +1,2 @@ +[mesh] +file = data-doublenull-1/grid-doublenull-1.nc diff --git a/tests/integrated/test-griddata-yboundary-guards/data-doublenull-2/BOUT.inp b/tests/integrated/test-griddata-yboundary-guards/data-doublenull-2/BOUT.inp new file mode 100644 index 0000000000..cc8fd1f0d2 --- /dev/null +++ b/tests/integrated/test-griddata-yboundary-guards/data-doublenull-2/BOUT.inp @@ -0,0 +1,2 @@ +[mesh] +file = data-doublenull-2/grid-doublenull-2.nc diff --git a/tests/integrated/test-griddata-yboundary-guards/data-singlenull-0/BOUT.inp b/tests/integrated/test-griddata-yboundary-guards/data-singlenull-0/BOUT.inp new file mode 100644 index 0000000000..40211cf587 --- /dev/null +++ b/tests/integrated/test-griddata-yboundary-guards/data-singlenull-0/BOUT.inp @@ -0,0 +1,2 @@ +[mesh] +file = data-singlenull-0/grid-singlenull-0.nc diff --git a/tests/integrated/test-griddata-yboundary-guards/data-singlenull-1/BOUT.inp b/tests/integrated/test-griddata-yboundary-guards/data-singlenull-1/BOUT.inp new file mode 100644 index 0000000000..82d2722bf2 --- /dev/null +++ b/tests/integrated/test-griddata-yboundary-guards/data-singlenull-1/BOUT.inp @@ -0,0 +1,2 @@ +[mesh] +file = data-singlenull-1/grid-singlenull-1.nc diff --git a/tests/integrated/test-griddata-yboundary-guards/data-singlenull-2/BOUT.inp b/tests/integrated/test-griddata-yboundary-guards/data-singlenull-2/BOUT.inp new file mode 100644 index 0000000000..3b0c3fdc60 --- /dev/null +++ b/tests/integrated/test-griddata-yboundary-guards/data-singlenull-2/BOUT.inp @@ -0,0 +1,2 @@ +[mesh] +file = data-singlenull-2/grid-singlenull-2.nc diff --git a/tests/integrated/test-griddata-yboundary-guards/make_inputs.py b/tests/integrated/test-griddata-yboundary-guards/make_inputs.py new file mode 100755 index 0000000000..896ae2f597 --- /dev/null +++ b/tests/integrated/test-griddata-yboundary-guards/make_inputs.py @@ -0,0 +1,111 @@ +#! /usr/bin/env python3 + +import numpy +from netCDF4 import Dataset +import os.path + +# make a grid with topology of a 'double null' case + +nx = 4 +ny = 24 +blocksize = ny/6 + +for n_yguards in [0, 1, 2]: + datadir = "data-doublenull-" + str(n_yguards) + gridname = "grid-doublenull-" + str(n_yguards) + ".nc" + + with Dataset(os.path.join(datadir,gridname), 'w') as gridfile: + gridfile.createDimension('x', nx) + gridfile.createDimension('y', ny + 4*n_yguards) + + gridfile.createVariable('nx', numpy.int32) + gridfile['nx'][...] = nx + + gridfile.createVariable('ny', numpy.int32) + gridfile['ny'][...] = ny + + gridfile.createVariable('y_boundary_guards', numpy.int32) + gridfile['y_boundary_guards'][...] = n_yguards + + gridfile.createVariable('MXG', numpy.int32) + gridfile['MXG'][...] = 1 + + gridfile.createVariable('MYG', numpy.int32) + gridfile['MYG'][...] = 2 if n_yguards==0 else n_yguards + + gridfile.createVariable('ixseps1', numpy.int32) + gridfile['ixseps1'][...] = nx//2 - 1 + + gridfile.createVariable('ixseps2', numpy.int32) + gridfile['ixseps2'][...] = nx//2 - 1 + + gridfile.createVariable('jyseps1_1', numpy.int32) + gridfile['jyseps1_1'][...] = blocksize - 1 + + gridfile.createVariable('jyseps2_1', numpy.int32) + gridfile['jyseps2_1'][...] = 2*blocksize - 1 + + gridfile.createVariable('ny_inner', numpy.int32) + gridfile['ny_inner'][...] = 3*blocksize + + gridfile.createVariable('jyseps1_2', numpy.int32) + gridfile['jyseps1_2'][...] = 4*blocksize - 1 + + gridfile.createVariable('jyseps2_2', numpy.int32) + gridfile['jyseps2_2'][...] = 5*blocksize - 1 + + testdata = numpy.zeros([nx, ny + 4*n_yguards]) + testdata[:,:] = numpy.arange(ny + 4*n_yguards)[numpy.newaxis,:] + gridfile.createVariable('test', float, ('x', 'y')) + gridfile['test'][...] = testdata + +for n_yguards in [0, 1, 2]: + datadir = "data-singlenull-" + str(n_yguards) + gridname = "grid-singlenull-" + str(n_yguards) + ".nc" + + with Dataset(os.path.join(datadir,gridname), 'w') as gridfile: + gridfile.createDimension('x', nx) + gridfile.createDimension('y', ny + 2*n_yguards) + + gridfile.createVariable('nx', numpy.int32) + gridfile['nx'][...] = nx + + gridfile.createVariable('ny', numpy.int32) + gridfile['ny'][...] = ny + + gridfile.createVariable('y_boundary_guards', numpy.int32) + gridfile['y_boundary_guards'][...] = n_yguards + + gridfile.createVariable('MXG', numpy.int32) + gridfile['MXG'][...] = 1 + + gridfile.createVariable('MYG', numpy.int32) + gridfile['MYG'][...] = 2 if n_yguards==0 else n_yguards + + gridfile.createVariable('ixseps1', numpy.int32) + gridfile['ixseps1'][...] = nx//2 - 1 + + gridfile.createVariable('ixseps2', numpy.int32) + gridfile['ixseps2'][...] = nx//2 - 1 + + gridfile.createVariable('jyseps1_1', numpy.int32) + gridfile['jyseps1_1'][...] = blocksize - 1 + + gridfile.createVariable('jyseps2_1', numpy.int32) + gridfile['jyseps2_1'][...] = ny//2 + + gridfile.createVariable('ny_inner', numpy.int32) + gridfile['ny_inner'][...] = ny//2 + + gridfile.createVariable('jyseps1_2', numpy.int32) + gridfile['jyseps1_2'][...] = ny//2 + + gridfile.createVariable('jyseps2_2', numpy.int32) + gridfile['jyseps2_2'][...] = 5*blocksize - 1 + + testdata = numpy.zeros([nx, ny + 2*n_yguards]) + testdata[:,:] = numpy.arange(ny + 2*n_yguards)[numpy.newaxis,:] + gridfile.createVariable('test', float, ('x', 'y')) + gridfile['test'][...] = testdata + +exit(0) diff --git a/tests/integrated/test-griddata-yboundary-guards/makefile b/tests/integrated/test-griddata-yboundary-guards/makefile new file mode 100644 index 0000000000..f2ff47b18b --- /dev/null +++ b/tests/integrated/test-griddata-yboundary-guards/makefile @@ -0,0 +1,6 @@ + +BOUT_TOP = ../../.. + +SOURCEC = test_griddata.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-griddata-yboundary-guards/runtest b/tests/integrated/test-griddata-yboundary-guards/runtest new file mode 100755 index 0000000000..c52c6b1e61 --- /dev/null +++ b/tests/integrated/test-griddata-yboundary-guards/runtest @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 + +from boututils.run_wrapper import shell, shell_safe, launch_safe +from boutdata.collect import collect +from netCDF4 import Dataset +import numpy +import os.path +from sys import stdout, exit + +print("Making griddata test") +shell_safe("make > make.log") + +nx = 4 +ny = 24 +blocksize = ny/6 + +# first generate some grid files to test +# double null case: +for n_yguards in [0, 1, 2]: + datadir = "data-doublenull-" + str(n_yguards) + gridname = "grid-doublenull-" + str(n_yguards) + ".nc" + + with Dataset(os.path.join(datadir,gridname), 'w') as gridfile: + gridfile.createDimension('x', nx) + gridfile.createDimension('y', ny + 4*n_yguards) + + gridfile.createVariable('nx', numpy.int32) + gridfile['nx'][...] = nx + + gridfile.createVariable('ny', numpy.int32) + gridfile['ny'][...] = ny + + gridfile.createVariable('y_boundary_guards', numpy.int32) + gridfile['y_boundary_guards'][...] = n_yguards + + gridfile.createVariable('MXG', numpy.int32) + gridfile['MXG'][...] = 1 + + gridfile.createVariable('MYG', numpy.int32) + gridfile['MYG'][...] = 2 if n_yguards==0 else n_yguards + + gridfile.createVariable('ixseps1', numpy.int32) + gridfile['ixseps1'][...] = nx//2 - 1 + + gridfile.createVariable('ixseps2', numpy.int32) + gridfile['ixseps2'][...] = nx//2 - 1 + + gridfile.createVariable('jyseps1_1', numpy.int32) + gridfile['jyseps1_1'][...] = blocksize - 1 + + gridfile.createVariable('jyseps2_1', numpy.int32) + gridfile['jyseps2_1'][...] = 2*blocksize - 1 + + gridfile.createVariable('ny_inner', numpy.int32) + gridfile['ny_inner'][...] = 3*blocksize + + gridfile.createVariable('jyseps1_2', numpy.int32) + gridfile['jyseps1_2'][...] = 4*blocksize - 1 + + gridfile.createVariable('jyseps2_2', numpy.int32) + gridfile['jyseps2_2'][...] = 5*blocksize - 1 + + testdata = numpy.zeros([nx, ny + 4*n_yguards]) + testdata[:,:] = numpy.arange(ny + 4*n_yguards)[numpy.newaxis,:] + gridfile.createVariable('test', float, ('x', 'y')) + gridfile['test'][...] = testdata + +# grid files for single-null: +for n_yguards in [0, 1, 2]: + datadir = "data-singlenull-" + str(n_yguards) + gridname = "grid-singlenull-" + str(n_yguards) + ".nc" + + with Dataset(os.path.join(datadir,gridname), 'w') as gridfile: + gridfile.createDimension('x', nx) + gridfile.createDimension('y', ny + 2*n_yguards) + + gridfile.createVariable('nx', numpy.int32) + gridfile['nx'][...] = nx + + gridfile.createVariable('ny', numpy.int32) + gridfile['ny'][...] = ny + + gridfile.createVariable('y_boundary_guards', numpy.int32) + gridfile['y_boundary_guards'][...] = n_yguards + + gridfile.createVariable('MXG', numpy.int32) + gridfile['MXG'][...] = 1 + + gridfile.createVariable('MYG', numpy.int32) + gridfile['MYG'][...] = 2 if n_yguards==0 else n_yguards + + gridfile.createVariable('ixseps1', numpy.int32) + gridfile['ixseps1'][...] = nx//2 - 1 + + gridfile.createVariable('ixseps2', numpy.int32) + gridfile['ixseps2'][...] = nx//2 - 1 + + gridfile.createVariable('jyseps1_1', numpy.int32) + gridfile['jyseps1_1'][...] = blocksize - 1 + + gridfile.createVariable('jyseps2_1', numpy.int32) + gridfile['jyseps2_1'][...] = ny//2 + + gridfile.createVariable('ny_inner', numpy.int32) + gridfile['ny_inner'][...] = ny//2 + + gridfile.createVariable('jyseps1_2', numpy.int32) + gridfile['jyseps1_2'][...] = ny//2 + + gridfile.createVariable('jyseps2_2', numpy.int32) + gridfile['jyseps2_2'][...] = 5*blocksize - 1 + + testdata = numpy.zeros([nx, ny + 2*n_yguards]) + testdata[:,:] = numpy.arange(ny + 2*n_yguards)[numpy.newaxis,:] + gridfile.createVariable('test', float, ('x', 'y')) + gridfile['test'][...] = testdata + + +for nproc in [6]: + stdout.write("Checking %d processors ... " % (nproc)) + + shell("rm ./data*/BOUT.dmp.*.nc run.log.*") + + success = True + + # double null tests + for n_yguards in [0, 1, 2]: + datadir = "data-doublenull-" + str(n_yguards) + + s, out = launch_safe("./test_griddata -d " + datadir, nproc=nproc, pipe=True) + + with open("run.log.doublenull."+str(nproc), "a") as f: + f.write(out) + + testfield = collect("test", path=datadir, info=False, yguards=True) + + if n_yguards == 0: + # output has 2 y-guard cells, but grid file did not + myg = 2 + checkfield = list(numpy.zeros(myg)) + checkfield += list(numpy.arange(ny//2)) + checkfield += list(numpy.arange(ny//2) + checkfield[-1] + 1) + checkfield += list(numpy.zeros(myg) + checkfield[-1]) + else: + checkfield = [] + checkfield += list(numpy.arange(n_yguards)) + checkfield += list(numpy.arange(ny//2) + checkfield[-1] + 1) + checkfield += list(numpy.arange(ny//2) + checkfield[-1] + 1 + 2*n_yguards) + checkfield += list(numpy.arange(n_yguards) + checkfield[-1] + 1) + checkfield = numpy.array(checkfield) + + # Test value of testfield + if numpy.max(numpy.abs(testfield - checkfield)) > 1e-13: + print("Failed: testfield does not match in doublenull case for n_yguards="+str(n_yguards)) + success = False + + # single null tests + for n_yguards in [0, 1, 2]: + datadir = "data-singlenull-" + str(n_yguards) + + s, out = launch_safe("./test_griddata -d " + datadir, nproc=nproc, pipe=True) + + with open("run.log.singlenull."+str(nproc), "a") as f: + f.write(out) + + testfield = collect("test", path=datadir, info=False, yguards=True) + + if n_yguards == 0: + # output has 2 y-guard cells, but grid file did not + myg = 2 + checkfield = list(numpy.zeros(myg)) + checkfield += list(numpy.arange(ny)) + checkfield += list(numpy.zeros(myg) + checkfield[-1]) + else: + checkfield = [] + checkfield += list(numpy.arange(n_yguards)) + checkfield += list(numpy.arange(ny) + checkfield[-1] + 1) + checkfield += list(numpy.arange(n_yguards) + checkfield[-1] + 1) + checkfield = numpy.array(checkfield) + + # Test value of testfield + if numpy.max(numpy.abs(testfield - checkfield)) > 1e-13: + print("Failed: testfield does not match in doublenull case for n_yguards="+str(n_yguards)) + success = False + + if not success: + exit(1) + else: + print("Passed") + +exit(0) diff --git a/tests/integrated/test-griddata-yboundary-guards/test_griddata.cxx b/tests/integrated/test-griddata-yboundary-guards/test_griddata.cxx new file mode 100644 index 0000000000..fee6020130 --- /dev/null +++ b/tests/integrated/test-griddata-yboundary-guards/test_griddata.cxx @@ -0,0 +1,20 @@ +#include +#include + +int main(int argc, char** argv) { + BoutInitialise(argc, argv); + + Datafile df(Options::getRoot()->getSection("output")); + + Field2D test; + mesh->get(test, "test"); + + dump.add(test, "test"); + + dump.write(); + + MPI_Barrier(BoutComm::get()); + + BoutFinalise(); + return 0; +} From a103ee0ba3ec754c92919dc1bfdfccd92181c3f9 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 10 Apr 2019 13:41:28 +0100 Subject: [PATCH 1267/1783] Add .BOUT.pid.* files to .gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 90f0ec37c7..e7abe2ab8b 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,4 @@ bout-coverage/ src/.libfast .*.mk *.mo - +.BOUT.pid.* From f587d823a2670f2acfc0e822f428bc8e42f62900 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 10 Apr 2019 14:14:10 +0100 Subject: [PATCH 1268/1783] Remove unnecessary make_inputs.py file The functionality was merged into runtest, so this stript isn't needed. --- .../make_inputs.py | 111 ------------------ 1 file changed, 111 deletions(-) delete mode 100755 tests/integrated/test-griddata-yboundary-guards/make_inputs.py diff --git a/tests/integrated/test-griddata-yboundary-guards/make_inputs.py b/tests/integrated/test-griddata-yboundary-guards/make_inputs.py deleted file mode 100755 index 896ae2f597..0000000000 --- a/tests/integrated/test-griddata-yboundary-guards/make_inputs.py +++ /dev/null @@ -1,111 +0,0 @@ -#! /usr/bin/env python3 - -import numpy -from netCDF4 import Dataset -import os.path - -# make a grid with topology of a 'double null' case - -nx = 4 -ny = 24 -blocksize = ny/6 - -for n_yguards in [0, 1, 2]: - datadir = "data-doublenull-" + str(n_yguards) - gridname = "grid-doublenull-" + str(n_yguards) + ".nc" - - with Dataset(os.path.join(datadir,gridname), 'w') as gridfile: - gridfile.createDimension('x', nx) - gridfile.createDimension('y', ny + 4*n_yguards) - - gridfile.createVariable('nx', numpy.int32) - gridfile['nx'][...] = nx - - gridfile.createVariable('ny', numpy.int32) - gridfile['ny'][...] = ny - - gridfile.createVariable('y_boundary_guards', numpy.int32) - gridfile['y_boundary_guards'][...] = n_yguards - - gridfile.createVariable('MXG', numpy.int32) - gridfile['MXG'][...] = 1 - - gridfile.createVariable('MYG', numpy.int32) - gridfile['MYG'][...] = 2 if n_yguards==0 else n_yguards - - gridfile.createVariable('ixseps1', numpy.int32) - gridfile['ixseps1'][...] = nx//2 - 1 - - gridfile.createVariable('ixseps2', numpy.int32) - gridfile['ixseps2'][...] = nx//2 - 1 - - gridfile.createVariable('jyseps1_1', numpy.int32) - gridfile['jyseps1_1'][...] = blocksize - 1 - - gridfile.createVariable('jyseps2_1', numpy.int32) - gridfile['jyseps2_1'][...] = 2*blocksize - 1 - - gridfile.createVariable('ny_inner', numpy.int32) - gridfile['ny_inner'][...] = 3*blocksize - - gridfile.createVariable('jyseps1_2', numpy.int32) - gridfile['jyseps1_2'][...] = 4*blocksize - 1 - - gridfile.createVariable('jyseps2_2', numpy.int32) - gridfile['jyseps2_2'][...] = 5*blocksize - 1 - - testdata = numpy.zeros([nx, ny + 4*n_yguards]) - testdata[:,:] = numpy.arange(ny + 4*n_yguards)[numpy.newaxis,:] - gridfile.createVariable('test', float, ('x', 'y')) - gridfile['test'][...] = testdata - -for n_yguards in [0, 1, 2]: - datadir = "data-singlenull-" + str(n_yguards) - gridname = "grid-singlenull-" + str(n_yguards) + ".nc" - - with Dataset(os.path.join(datadir,gridname), 'w') as gridfile: - gridfile.createDimension('x', nx) - gridfile.createDimension('y', ny + 2*n_yguards) - - gridfile.createVariable('nx', numpy.int32) - gridfile['nx'][...] = nx - - gridfile.createVariable('ny', numpy.int32) - gridfile['ny'][...] = ny - - gridfile.createVariable('y_boundary_guards', numpy.int32) - gridfile['y_boundary_guards'][...] = n_yguards - - gridfile.createVariable('MXG', numpy.int32) - gridfile['MXG'][...] = 1 - - gridfile.createVariable('MYG', numpy.int32) - gridfile['MYG'][...] = 2 if n_yguards==0 else n_yguards - - gridfile.createVariable('ixseps1', numpy.int32) - gridfile['ixseps1'][...] = nx//2 - 1 - - gridfile.createVariable('ixseps2', numpy.int32) - gridfile['ixseps2'][...] = nx//2 - 1 - - gridfile.createVariable('jyseps1_1', numpy.int32) - gridfile['jyseps1_1'][...] = blocksize - 1 - - gridfile.createVariable('jyseps2_1', numpy.int32) - gridfile['jyseps2_1'][...] = ny//2 - - gridfile.createVariable('ny_inner', numpy.int32) - gridfile['ny_inner'][...] = ny//2 - - gridfile.createVariable('jyseps1_2', numpy.int32) - gridfile['jyseps1_2'][...] = ny//2 - - gridfile.createVariable('jyseps2_2', numpy.int32) - gridfile['jyseps2_2'][...] = 5*blocksize - 1 - - testdata = numpy.zeros([nx, ny + 2*n_yguards]) - testdata[:,:] = numpy.arange(ny + 2*n_yguards)[numpy.newaxis,:] - gridfile.createVariable('test', float, ('x', 'y')) - gridfile['test'][...] = testdata - -exit(0) From c7ec32384fc11b6d1a814ee3ad37e96298610038 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 10 Apr 2019 15:34:27 +0100 Subject: [PATCH 1269/1783] Fix unit tests In OptionsTest, use FakeMeshFixture so we can use the bout::globals::mesh which has Coordiates objects created. Avoids implicit creation of Coordinates when getCoordinates is called, which lead previously to a segfault because the locally FakeMesh doesn't have a GridDataSource. We can't resolve this by calling 'fieldmesh->setCoordinates(nullptr)' because create3D requires a ParallelTransform, which belongs to the Coordinates. --- tests/unit/sys/test_options.cxx | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/tests/unit/sys/test_options.cxx b/tests/unit/sys/test_options.cxx index 84b1420072..9a77770ee8 100644 --- a/tests/unit/sys/test_options.cxx +++ b/tests/unit/sys/test_options.cxx @@ -7,7 +7,7 @@ #include -class OptionsTest : public ::testing::Test { +class OptionsTest : public FakeMeshFixture { public: virtual ~OptionsTest() = default; WithQuietOutput quiet_info{output_info}; @@ -769,30 +769,22 @@ TEST_F(OptionsTest, TypeAttributeInt) { } TEST_F(OptionsTest, TypeAttributeField2D) { - // Note: Need a Mesh to create Field2D - FakeMesh fieldmesh(6,6,2); - fieldmesh.createDefaultRegions(); - Options option; option = "42"; // Casting to bool should modify the "type" attribute - Field2D value = option.withDefault(Field2D(-1,&fieldmesh)); + Field2D value = option.withDefault(Field2D(-1, bout::globals::mesh)); EXPECT_EQ(value(0,0), 42); EXPECT_EQ(option.attributes["type"].as(), "Field2D"); } TEST_F(OptionsTest, TypeAttributeField3D) { - // Note: Need a Mesh to create Field3D - FakeMesh fieldmesh(6,6,2); - fieldmesh.createDefaultRegions(); - Options option; option = "42"; // Casting to bool should modify the "type" attribute - Field3D value = option.withDefault(Field3D(-1,&fieldmesh)); + Field3D value = option.withDefault(Field3D(-1, bout::globals::mesh)); EXPECT_EQ(value(0,0,0), 42); EXPECT_EQ(option.attributes["type"].as(), "Field3D"); From a12a3a627586945a5ef1b25a0b7ed29fb9a40aae Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 10 Apr 2019 17:35:28 +0100 Subject: [PATCH 1270/1783] Read d2x and d2y at staggered locations from grid file if possible Adds functionality to read 'd2x_ylow', etc., from grid files if they are present. Also communicate and set guard cells for 'd1_dx' and 'd1_dy'. --- src/mesh/coordinates.cxx | 73 +++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 16 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index c8d6278ad1..723785b7a7 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -764,26 +764,67 @@ int Coordinates::geometry(bool recalculate_staggered) { Field2D d2x(localmesh), d2y(localmesh); // d^2 x / d i^2 // Read correction for non-uniform meshes - if (localmesh->get(d2x, "d2x")) { - output_warn.write( - "\tWARNING: differencing quantity 'd2x' not found. Calculating from dx\n"); - d1_dx = bout::derivatives::index::DDX(1. / dx); // d/di(1/dx) - } else { - // Shift d2x to our location - d2x = interp_to(d2x, location); + std::string suffix = getLocationSuffix(location); + if (CELL_CENTRE or (!force_interpolate_from_centre + and mesh->sourceHasVar("dx"+suffix))) { + extrapolate_x = not mesh->sourceHasXBoundaryGuards(); + extrapolate_y = not mesh->sourceHasYBoundaryGuards(); - d1_dx = -d2x / (dx * dx); - } + if (localmesh->get(d2x, "d2x"+suffix)) { + output_warn.write( + "\tWARNING: differencing quantity 'd2x' not found. Calculating from dx\n"); + d1_dx = bout::derivatives::index::DDX(1. / dx); // d/di(1/dx) - if (localmesh->get(d2y, "d2y")) { - output_warn.write( - "\tWARNING: differencing quantity 'd2y' not found. Calculating from dy\n"); - d1_dy = bout::derivatives::index::DDY(1. / dy); // d/di(1/dy) + localmesh->communicate(d1_dx); + d1_dx = interpolateAndExtrapolate(d1_dx, location); + } else { + // set boundary cells if necessary + d2x = interpolateAndExtrapolate(d2x, location, extrapolate_x, extrapolate_y); + + d1_dx = -d2x / (dx * dx); + } + + if (localmesh->get(d2y, "d2y"+suffix)) { + output_warn.write( + "\tWARNING: differencing quantity 'd2y' not found. Calculating from dy\n"); + d1_dy = bout::derivatives::index::DDY(1. / dy); // d/di(1/dy) + + localmesh->communicate(d1_dy); + d1_dy = interpolateAndExtrapolate(d1_dy, location); + } else { + // Shift d2y to our location + d2y = interpolateAndExtrapolate(d2y, location, extrapolate_x, extrapolate_y); + + d1_dy = -d2y / (dy * dy); + } } else { - // Shift d2y to our location - d2y = interp_to(d2y, location); + if (localmesh->get(d2x, "d2x")) { + output_warn.write( + "\tWARNING: differencing quantity 'd2x' not found. Calculating from dx\n"); + d1_dx = bout::derivatives::index::DDX(1. / dx); // d/di(1/dx) - d1_dy = -d2y / (dy * dy); + localmesh->communicate(d1_dx); + d1_dx = interpolateAndExtrapolate(d1_dx, location); + } else { + // Shift d2x to our location + d2x = interpolateAndExtrapolate(d2x, location); + + d1_dx = -d2x / (dx * dx); + } + + if (localmesh->get(d2y, "d2y")) { + output_warn.write( + "\tWARNING: differencing quantity 'd2y' not found. Calculating from dy\n"); + d1_dy = bout::derivatives::index::DDY(1. / dy); // d/di(1/dy) + + localmesh->communicate(d1_dy); + d1_dy = interpolateAndExtrapolate(d1_dy, location); + } else { + // Shift d2y to our location + d2y = interpolateAndExtrapolate(d2y, location); + + d1_dy = -d2y / (dy * dy); + } } if (location == CELL_CENTRE && recalculate_staggered) { From e252205e4ec995ed29aa5b8420fd3b9059ea9833 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 10 Apr 2019 17:50:20 +0100 Subject: [PATCH 1271/1783] Add Solver:unsplit_diffusive option If a physics model is not split into convective and diffusive parts, should it be treated as convective or diffusive? Previous behaviour was to treat as diffusive. This switch keeps this default, but allows it to be changed. --- include/bout/solver.hxx | 3 +++ src/solver/solver.cxx | 54 ++++++++++++++++++++++++++++------------- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index a274ce632e..29de99e13a 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -459,6 +459,9 @@ private: /// Diffusive part (if split operator) rhsfunc phys_diff{nullptr}; + /// Should unsplit physics models be treated as diffusive? + bool unsplit_diffusive{true}; + /// Enable sources and solutions for Method of Manufactured Solutions bool mms{false}; /// Initialise variables to the manufactured solution diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 6c1af7ac60..ac3739ec98 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -51,7 +51,12 @@ Solver::Solver(Options* opts) : options(opts == nullptr ? &Options::root()["solver"] : opts), monitor_timestep((*options)["monitor_timestep"].withDefault(false)), mms((*options)["mms"].withDefault(false)), - mms_initialise((*options)["mms_initialise"].withDefault(mms)) {} + mms_initialise((*options)["mms_initialise"].withDefault(mms)) { + + unsplit_diffusive = (*options)["unsplit_diffusive"] + .doc("If not a split operator, treat RHS as diffusive?") + .withDefault(true); +} /************************************************************************** * Add physics models @@ -1161,27 +1166,34 @@ int Solver::run_rhs(BoutReal t) { /// NOTE: This calls add_mms_sources int Solver::run_convective(BoutReal t) { int status; - + Timer timer("rhs"); pre_rhs(t); - if(split_operator) { - if(model) { + if (split_operator) { + if (model) { status = model->runConvective(t); - }else + } else status = (*phys_conv)(t); - }else { + } else if (!unsplit_diffusive) { + // Return total + if (model) { + status = model->runRHS(t); + } else { + status = (*phys_run)(t); + } + } else { // Zero if not split - for(const auto& f : f3d) + for (const auto& f : f3d) *(f.F_var) = 0.0; - for(const auto& f : f2d) + for (const auto& f : f2d) *(f.F_var) = 0.0; status = 0; } post_rhs(t); - + // If using Method of Manufactured Solutions add_mms_sources(t); - + rhs_ncalls++; rhs_ncalls_e++; return status; @@ -1189,22 +1201,30 @@ int Solver::run_convective(BoutReal t) { int Solver::run_diffusive(BoutReal t, bool linear) { int status = 0; - + Timer timer("rhs"); pre_rhs(t); - if(split_operator) { + if (split_operator) { - if(model) { + if (model) { status = model->runDiffusive(t, linear); - }else + } else { status = (*phys_diff)(t); + } post_rhs(t); - }else { + } else if (unsplit_diffusive) { // Return total - if(model) { + if (model) { status = model->runRHS(t); - }else + } else status = (*phys_run)(t); + } else { + // Zero if not split + for (const auto& f : f3d) + *(f.F_var) = 0.0; + for (const auto& f : f2d) + *(f.F_var) = 0.0; + status = 0; } rhs_ncalls_i++; return status; From 3c6f5b90e1120c7def8d041ea64d7b7a57010a70 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 10 Apr 2019 17:52:52 +0100 Subject: [PATCH 1272/1783] Fix factor of 2 bug in split-rk solver Apparently I can't do mental arithmetic, so coefficients were off by a factor of 2 (and wrong sign in some cases...). Caught thanks to `test-solver`. Thanks @ZedThree! --- src/solver/impls/split-rk/split-rk.cxx | 6 +++--- tests/integrated/test-solver/data/BOUT.inp | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/solver/impls/split-rk/split-rk.cxx b/src/solver/impls/split-rk/split-rk.cxx index 767a895f7f..6948667ee8 100644 --- a/src/solver/impls/split-rk/split-rk.cxx +++ b/src/solver/impls/split-rk/split-rk.cxx @@ -106,14 +106,14 @@ void SplitRK::take_diffusion_step(BoutReal curtime, BoutReal dt, Array } // Stage j = 2 - // mu = 0.75, nu terms cancel + // mu = 1.5, nu terms cancel load_vars(std::begin(u2)); - run_diffusive(curtime); + run_diffusive(curtime + (weight/3.0) * dt); save_derivs(std::begin(u3)); // f(y_m2) -> u3 BOUT_OMP(parallel for) for (int i = 0; i < u3.size(); i++) { - u1[i] = 0.75 * (u2[i] + weight * u3[i]) + 0.25 * start[i] - 0.5 * weight * dydt[i]; + u1[i] = 1.5 * (u2[i] + weight * u3[i]) - 0.5 * start[i] - weight * dydt[i]; } BoutReal b_jm2 = 1. / 3; // b_{j - 2} diff --git a/tests/integrated/test-solver/data/BOUT.inp b/tests/integrated/test-solver/data/BOUT.inp index b248ee4ea2..46dd448dd1 100644 --- a/tests/integrated/test-solver/data/BOUT.inp +++ b/tests/integrated/test-solver/data/BOUT.inp @@ -55,5 +55,9 @@ adaptive = true # This solver currently fails this test without adaptive timestepping adaptive = true +[splitrk] +timestep = end / (NOUT * 500) +nstages = 3 + [field] bndry_all = none From 65ad8c8277ab643cb72329684b8e6858495a3933 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 10 Apr 2019 17:37:00 +0100 Subject: [PATCH 1273/1783] Extrapolate Christoffel symbol terms into boundary cells --- include/bout/coordinates.hxx | 3 +- src/mesh/coordinates.cxx | 70 ++++++++++++++++++++++++++++-------- 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index 6e5b87c4e0..48e8d5725c 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -112,7 +112,8 @@ public: Field2D IntShiftTorsion; ///< Integrated shear (I in BOUT notation) /// Calculate differential geometry quantities from the metric tensor - int geometry(bool recalculate_staggered = true); + int geometry(bool recalculate_staggered = true, + bool force_interpolate_from_centre = false); int calcCovariant(); ///< Inverts contravatiant metric to get covariant int calcContravariant(); ///< Invert covariant metric to get contravariant int jacobian(); ///< Calculate J and Bxy diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 723785b7a7..a07f286de5 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -27,7 +27,8 @@ namespace { /// 'free_o3' boundary conditions /// Corner guard cells are set to BoutNaN Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location, - bool extrapolate_x = true, bool extrapolate_y = true) { + bool extrapolate_x = true, bool extrapolate_y = true, + bool no_extra_interpolate = false) { Mesh* localmesh = f.getMesh(); Field2D result = interp_to(f, location, RGN_NOBNDRY); @@ -51,10 +52,15 @@ Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location, for (auto& bndry : localmesh->getBoundaries()) { if ((extrapolate_x and bndry->bx != 0) or (extrapolate_y and bndry->by != 0)) { int extrap_start = 0; - if ((location == CELL_XLOW) && (bndry->bx > 0)) { - extrap_start = 1; - } else if ((location == CELL_YLOW) && (bndry->by > 0)) { - extrap_start = 1; + if (not no_extra_interpolate) { + // Can use no_extra_interpolate argument to skip the extra interpolation when we + // want to extrapolate the Christoffel symbol terms which come from derivatives so + // don't have the extra point set already + if ((location == CELL_XLOW) && (bndry->bx > 0)) { + extrap_start = 1; + } else if ((location == CELL_YLOW) && (bndry->by > 0)) { + extrap_start = 1; + } } for (bndry->first(); !bndry->isDone(); bndry->next1d()) { // interpolate extra boundary point that is missed by interp_to, if @@ -589,7 +595,7 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, ////////////////////////////////////////////////////// /// Calculate Christoffel symbols. Needs communication - if (geometry()) { + if (geometry(false, force_interpolate_from_centre)) { throw BoutException("Differential geometry failed while constructing staggered Coordinates"); } @@ -620,7 +626,8 @@ void Coordinates::outputVars(Datafile& file) { file.addOnce(J, "J" + loc_string); } -int Coordinates::geometry(bool recalculate_staggered) { +int Coordinates::geometry(bool recalculate_staggered, + bool force_interpolate_from_centre) { TRACE("Coordinates::geometry"); output_progress.write("Calculating differential geometry terms\n"); @@ -757,6 +764,41 @@ int Coordinates::geometry(bool recalculate_staggered) { localmesh->communicate(com); + // Set boundary guard cells of Christoffel symbol terms + // Ideally, when location is staggered, we would set the upper/outer boundary point + // correctly rather than by extrapolating here: e.g. if location==CELL_YLOW and we are + // at the upper y-boundary the x- and z-derivatives at yend+1 at the boundary can be + // calculated because the guard cells are available, while the y-derivative could be + // calculated from the CELL_CENTRE metric components (which have guard cells available + // past the boundary location). This would avoid the problem that the y-boundary on the + // CELL_YLOW grid is at a 'guard cell' location (yend+1). + // However, the above would require lots of special handling, so just extrapolate for + // now. + G1_11 = interpolateAndExtrapolate(G1_11, location, true, true, true); + G1_22 = interpolateAndExtrapolate(G1_22, location, true, true, true); + G1_33 = interpolateAndExtrapolate(G1_33, location, true, true, true); + G1_12 = interpolateAndExtrapolate(G1_12, location, true, true, true); + G1_13 = interpolateAndExtrapolate(G1_13, location, true, true, true); + G1_23 = interpolateAndExtrapolate(G1_23, location, true, true, true); + + G2_11 = interpolateAndExtrapolate(G2_11, location, true, true, true); + G2_22 = interpolateAndExtrapolate(G2_22, location, true, true, true); + G2_33 = interpolateAndExtrapolate(G2_33, location, true, true, true); + G2_12 = interpolateAndExtrapolate(G2_12, location, true, true, true); + G2_13 = interpolateAndExtrapolate(G2_13, location, true, true, true); + G2_23 = interpolateAndExtrapolate(G2_23, location, true, true, true); + + G3_11 = interpolateAndExtrapolate(G3_11, location, true, true, true); + G3_22 = interpolateAndExtrapolate(G3_22, location, true, true, true); + G3_33 = interpolateAndExtrapolate(G3_33, location, true, true, true); + G3_12 = interpolateAndExtrapolate(G3_12, location, true, true, true); + G3_13 = interpolateAndExtrapolate(G3_13, location, true, true, true); + G3_23 = interpolateAndExtrapolate(G3_23, location, true, true, true); + + G1 = interpolateAndExtrapolate(G1, location, true, true, true); + G2 = interpolateAndExtrapolate(G2, location, true, true, true); + G3 = interpolateAndExtrapolate(G3, location, true, true, true); + ////////////////////////////////////////////////////// /// Non-uniform meshes. Need to use DDX, DDY @@ -766,9 +808,9 @@ int Coordinates::geometry(bool recalculate_staggered) { // Read correction for non-uniform meshes std::string suffix = getLocationSuffix(location); if (CELL_CENTRE or (!force_interpolate_from_centre - and mesh->sourceHasVar("dx"+suffix))) { - extrapolate_x = not mesh->sourceHasXBoundaryGuards(); - extrapolate_y = not mesh->sourceHasYBoundaryGuards(); + and localmesh->sourceHasVar("dx"+suffix))) { + bool extrapolate_x = not localmesh->sourceHasXBoundaryGuards(); + bool extrapolate_y = not localmesh->sourceHasYBoundaryGuards(); if (localmesh->get(d2x, "d2x"+suffix)) { output_warn.write( @@ -776,7 +818,7 @@ int Coordinates::geometry(bool recalculate_staggered) { d1_dx = bout::derivatives::index::DDX(1. / dx); // d/di(1/dx) localmesh->communicate(d1_dx); - d1_dx = interpolateAndExtrapolate(d1_dx, location); + d1_dx = interpolateAndExtrapolate(d1_dx, location, true, true, true); } else { // set boundary cells if necessary d2x = interpolateAndExtrapolate(d2x, location, extrapolate_x, extrapolate_y); @@ -790,7 +832,7 @@ int Coordinates::geometry(bool recalculate_staggered) { d1_dy = bout::derivatives::index::DDY(1. / dy); // d/di(1/dy) localmesh->communicate(d1_dy); - d1_dy = interpolateAndExtrapolate(d1_dy, location); + d1_dy = interpolateAndExtrapolate(d1_dy, location, true, true, true); } else { // Shift d2y to our location d2y = interpolateAndExtrapolate(d2y, location, extrapolate_x, extrapolate_y); @@ -804,7 +846,7 @@ int Coordinates::geometry(bool recalculate_staggered) { d1_dx = bout::derivatives::index::DDX(1. / dx); // d/di(1/dx) localmesh->communicate(d1_dx); - d1_dx = interpolateAndExtrapolate(d1_dx, location); + d1_dx = interpolateAndExtrapolate(d1_dx, location, true, true, true); } else { // Shift d2x to our location d2x = interpolateAndExtrapolate(d2x, location); @@ -818,7 +860,7 @@ int Coordinates::geometry(bool recalculate_staggered) { d1_dy = bout::derivatives::index::DDY(1. / dy); // d/di(1/dy) localmesh->communicate(d1_dy); - d1_dy = interpolateAndExtrapolate(d1_dy, location); + d1_dy = interpolateAndExtrapolate(d1_dy, location, true, true, true); } else { // Shift d2y to our location d2y = interpolateAndExtrapolate(d2y, location); From 9d1ce7553000f1be2d3e8b65ab2b3572c918e21a Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 10 Apr 2019 22:02:28 +0100 Subject: [PATCH 1274/1783] Add SplitRK to modified MMS/time test Modify the MMS/time test so that it has non-zero convective and diffusive parts. This reduces the Karniadakis convergence order to 1, since it uses an Euler method for the diffusion part. Probably should remove this solver as there are better options. SplitRK converging at expected 2nd order. --- tests/MMS/time/runtest | 2 +- tests/MMS/time/time.cxx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/MMS/time/runtest b/tests/MMS/time/runtest index d570688227..36832936e0 100755 --- a/tests/MMS/time/runtest +++ b/tests/MMS/time/runtest @@ -39,10 +39,10 @@ if "only_petsc" in sys.argv: else: options = [ ("solver:type=euler", "Euler", "-^",1) - ,("solver:type=karniadakis", "Karniadakis", "-x",2) # Whats the expected order? ,("solver:type=rk3ssp", "RK3-SSP", "-s",3) ,("solver:type=rk4", "RK4", "-o",4) ,("solver:type=rkgeneric", "RK-generic", "-o",4) + ,("solver:type=splitrk", "SplitRK", "-x", 2) ] #Missing: cvode, ida, slepc, power, arkode, snes diff --git a/tests/MMS/time/time.cxx b/tests/MMS/time/time.cxx index ab87136d38..d97660cd7d 100644 --- a/tests/MMS/time/time.cxx +++ b/tests/MMS/time/time.cxx @@ -25,11 +25,11 @@ class TimeTest : public PhysicsModel { } int convective(MAYBE_UNUSED(BoutReal time)) { - ddt(f) = f; + ddt(f) = 0.5*f; return 0; } int diffusive(MAYBE_UNUSED(BoutReal time)) { - ddt(f) = 0; + ddt(f) = 0.5*f; return 0; } private: From 3f8e23f00d4d595de66a945b5237de9e48c92cea Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 10 Apr 2019 23:18:03 +0100 Subject: [PATCH 1275/1783] Adaptive timestep for SplitRK solver Doesn't yet seem to work well, or at least is taking a lot more steps than should probably be necessary. --- src/solver/impls/split-rk/split-rk.cxx | 122 +++++++++++++++++++-- src/solver/impls/split-rk/split-rk.hxx | 17 ++- tests/integrated/test-solver/data/BOUT.inp | 2 + 3 files changed, 127 insertions(+), 14 deletions(-) diff --git a/src/solver/impls/split-rk/split-rk.cxx b/src/solver/impls/split-rk/split-rk.cxx index 6948667ee8..963332cc0a 100644 --- a/src/solver/impls/split-rk/split-rk.cxx +++ b/src/solver/impls/split-rk/split-rk.cxx @@ -13,7 +13,12 @@ int SplitRK::init(int nout, BoutReal tstep) { out_timestep = tstep; // Calculate number of variables - const int nlocal = getLocalN(); + nlocal = getLocalN(); + + // Get total problem size + if(MPI_Allreduce(&nlocal, &neq, 1, MPI_INT, MPI_SUM, BoutComm::get())) { + throw BoutException("MPI_Allreduce failed!"); + } // Allocate memory state.reallocate(nlocal); @@ -27,15 +32,39 @@ int SplitRK::init(int nout, BoutReal tstep) { // Put starting values into f save_vars(std::begin(state)); - // Get options + // Get options. Default values for many of these are set in constructor. auto &opt = *options; timestep = opt["timestep"] .doc("Internal timestep. This may be rounded down.") .withDefault(out_timestep); - ninternal_steps = static_cast(std::ceil(out_timestep / timestep)); - ASSERT0(ninternal_steps > 0); + adaptive = opt["adaptive"].doc("Use accuracy tolerances to adapt timestep?").withDefault(adaptive); + + atol = opt["atol"].doc("Absolute tolerance").withDefault(atol); + rtol = opt["rtol"].doc("Relative tolerance").withDefault(rtol); + + max_timestep = opt["max_timestep"].doc("Maximum timestep. Negative means no limit.").withDefault(out_timestep); + + mxstep = opt["mxstep"] + .doc("Maximum number of internal steps between outputs") + .withDefault(mxstep); + ASSERT0(mxstep > 0); + adapt_period = opt["adapt_period"] + .doc("Number of steps between tolerance checks. 1 means check every step.") + .withDefault(adapt_period); + + if (adaptive) { + // Need additional storage to compare results after time steps + state1.reallocate(nlocal); + state2.reallocate(nlocal); + } + + ASSERT0(adapt_period > 0); + + int ninternal_steps = static_cast(std::ceil(out_timestep / timestep)); + ASSERT0(ninternal_steps > 0); + timestep = out_timestep / ninternal_steps; output.write(_("\tUsing a timestep %e\n"), timestep); @@ -51,15 +80,86 @@ int SplitRK::run() { for (int step = 0; step < nsteps; step++) { // Take an output step - for (int internal_step = 0; internal_step < ninternal_steps; internal_step++) { - // Take a single step - take_step(simtime, timestep, state, state); - - simtime += timestep; + BoutReal target = simtime + out_timestep; + + BoutReal dt; // The next timestep to take + bool running = true; // Changed to false to break out of inner loop + int internal_steps = 0; // Quit if this exceeds mxstep + + do { + // Take a single time step + + if (adaptive and (internal_steps % adapt_period == 0)) { + do { + // Keep adapting the timestep until the error is within tolerances + + dt = timestep; + running = true; // Reset after maybe adapting timestep + if ((simtime + dt) >= target) { + dt = target - simtime; // Make sure the last timestep is on the output + running = false; // Fall out of this inner loop after this step + } + + // Take two half-steps + take_step(simtime, 0.5*dt, state, state1); + take_step(simtime + 0.5*dt, 0.5*dt, state1, state2); + + // Take a full step + take_step(simtime, dt, state, state1); + + // Check accuracy + BoutReal local_err = 0.; + BOUT_OMP(parallel for reduction(+: local_err) ) + for (int i = 0; i < nlocal; i++) { + local_err += fabs(state2[i] - state1[i]) / (fabs(state1[i]) + fabs(state2[i]) + atol); + } + + // Average over all processors + BoutReal err; + if (MPI_Allreduce(&local_err, &err, 1, MPI_DOUBLE, MPI_SUM, BoutComm::get())) { + throw BoutException("MPI_Allreduce failed"); + } + + err /= static_cast(neq); + + internal_steps++; + if (internal_steps > mxstep) { + throw BoutException("ERROR: MXSTEP exceeded. timestep = %e, err=%e\n", + timestep, err); + } + + if ((err > rtol) || (err < 0.1 * rtol)) { + // Need to change timestep. Error ~ dt^2 + timestep /= sqrt(err / (0.5 * rtol)); + + if ((max_timestep > 0) && (timestep > max_timestep)) { + timestep = max_timestep; + } + } + if (err < rtol) { + swap(state, state2); // Put result in state + break; // Acceptable accuracy + } + } while (true); + } else { + // No adaptive timestepping. Take a single step + + dt = timestep; + running = true; // Reset after maybe adapting timestep + if ((simtime + dt) >= target) { + dt = target - simtime; // Make sure the last timestep is on the output + running = false; // Fall out of this inner loop after this step + } + + take_step(simtime, timestep, state, state); + internal_steps++; + } + simtime += dt; call_timestep_monitors(simtime, timestep); - } - + + } while (running); + load_vars(std::begin(state)); // Put result into variables // Call rhs function to get extra variables at this time run_rhs(simtime); diff --git a/src/solver/impls/split-rk/split-rk.hxx b/src/solver/impls/split-rk/split-rk.hxx index 7f022a8300..c7f39b20fd 100644 --- a/src/solver/impls/split-rk/split-rk.hxx +++ b/src/solver/impls/split-rk/split-rk.hxx @@ -42,7 +42,7 @@ RegisterSolver registersolversplitrk("splitrk"); class SplitRK : public Solver { public: - SplitRK(Options *opt = nullptr) : Solver(opt) {} + explicit SplitRK(Options *opt = nullptr) : Solver(opt) {} ~SplitRK() = default; int init(int nout, BoutReal tstep) override; @@ -53,10 +53,18 @@ private: BoutReal out_timestep; ///< The output timestep int nsteps; ///< Number of output steps - - int ninternal_steps; ///< Number of internal timesteps + BoutReal timestep; ///< The internal timestep + bool adaptive{true}; ///< Adapt timestep using tolerances? + BoutReal atol{1e-10}; ///< Absolute tolerance + BoutReal rtol{1e-5}; ///< Relative tolerance + BoutReal max_timestep; ///< Maximum timestep + int mxstep{1000}; ///< Maximum number of internal steps between outputs + int adapt_period{1}; ///< Number of steps between checks + + int nlocal, neq; ///< Number of variables on local processor and in total + /// System state Array state; @@ -64,6 +72,9 @@ private: /// These are used by both diffusion and advection time-step routines Array u1, u2, u3, dydt; + /// Arrays used for adaptive timestepping + Array state1, state2; + /// Take a combined step /// Uses 2nd order Strang splitting /// diff --git a/tests/integrated/test-solver/data/BOUT.inp b/tests/integrated/test-solver/data/BOUT.inp index 46dd448dd1..4d0a116eee 100644 --- a/tests/integrated/test-solver/data/BOUT.inp +++ b/tests/integrated/test-solver/data/BOUT.inp @@ -58,6 +58,8 @@ adaptive = true [splitrk] timestep = end / (NOUT * 500) nstages = 3 +mxstep = 10000 +adaptive=false [field] bndry_all = none From bf911fb95fa10b40b0e30f34e9a6e1d51b40abca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 11 Apr 2019 14:14:28 +0100 Subject: [PATCH 1276/1783] time-petsc is working again --- tests/MMS/time-petsc/{runtest.broken => runtest} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/MMS/time-petsc/{runtest.broken => runtest} (100%) diff --git a/tests/MMS/time-petsc/runtest.broken b/tests/MMS/time-petsc/runtest similarity index 100% rename from tests/MMS/time-petsc/runtest.broken rename to tests/MMS/time-petsc/runtest From 771a63be5b590c576cb7d4a8e800ef0e9b04a75b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 11 Apr 2019 14:45:56 +0100 Subject: [PATCH 1277/1783] fix: set absolute path The we may be later in a different sub-directory --- tests/integrated/test-compile-examples/runtest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integrated/test-compile-examples/runtest b/tests/integrated/test-compile-examples/runtest index 55e7d7c79c..89fbe933f4 100755 --- a/tests/integrated/test-compile-examples/runtest +++ b/tests/integrated/test-compile-examples/runtest @@ -3,7 +3,7 @@ #requires: all_tests #requires: not make -BOUT_TOP=../../.. +BOUT_TOP=$(pwd)/../../.. export PATH=$BOUT_TOP/bin:$PATH error=0 From 25420048715594ecf6a9c4eb507c165e91badf71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 11 Apr 2019 14:52:05 +0100 Subject: [PATCH 1278/1783] Seems the name has changed --- examples/fci-wave-logn/fci-wave.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fci-wave-logn/fci-wave.cxx b/examples/fci-wave-logn/fci-wave.cxx index c64c2356e8..bcd602bf73 100644 --- a/examples/fci-wave-logn/fci-wave.cxx +++ b/examples/fci-wave-logn/fci-wave.cxx @@ -17,7 +17,7 @@ class FCIwave : public PhysicsModel { Field3D f_B = f / Bxyz; f_B.splitYupYdown(); - mesh->getParallelTransform().integrateYUpDown(f_B); + mesh->getParallelTransform().integrateYupYdown(f_B); // integrateYUpDown replaces all yup/down points, so the boundary conditions // now need to be applied. If Bxyz has neumann parallel boundary conditions From 0fc181ec7447701e2ee32a59e082842ae2a8d658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 11 Apr 2019 14:52:46 +0100 Subject: [PATCH 1279/1783] Seems the name has changed --- examples/fci-wave/fci-wave.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/fci-wave/fci-wave.cxx b/examples/fci-wave/fci-wave.cxx index 5380d73360..f861ad2c2d 100644 --- a/examples/fci-wave/fci-wave.cxx +++ b/examples/fci-wave/fci-wave.cxx @@ -18,7 +18,7 @@ class FCIwave : public PhysicsModel { Field3D f_B = f / Bxyz; f_B.splitYupYdown(); - mesh->getParallelTransform().integrateYUpDown(f_B); + mesh->getParallelTransform().integrateYupYdown(f_B); // integrateYUpDown replaces all yup/down points, so the boundary conditions // now need to be applied. If Bxyz has neumann parallel boundary conditions From 4ecc0eb7a63dedb23f5d09527888814c35a5062f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 11 Apr 2019 15:31:01 +0100 Subject: [PATCH 1280/1783] Split compile-example tests One examples requires PETSc to build. In order to make the test independent of petsc, that example is split out. Also adds a check to the example's make file, to ensure PETSc is present. --- examples/invertable_operator/makefile | 7 +++- .../test-compile-examples-petsc/README.md | 1 + .../test-compile-examples-petsc/runtest | 36 +++++++++++++++++++ .../integrated/test-compile-examples/runtest | 27 ++++++++------ 4 files changed, 59 insertions(+), 12 deletions(-) create mode 120000 tests/integrated/test-compile-examples-petsc/README.md create mode 100755 tests/integrated/test-compile-examples-petsc/runtest diff --git a/examples/invertable_operator/makefile b/examples/invertable_operator/makefile index f59c90b2a1..12c82cc6c3 100644 --- a/examples/invertable_operator/makefile +++ b/examples/invertable_operator/makefile @@ -1,6 +1,11 @@ - BOUT_TOP = ../.. SOURCEC = invertable_operator.cxx +target: requires_petsc invertable_operator + +requires_petsc: + @test $$($(BOUT_TOP)/bin/bout-config --has-petsc ) = yes || \ + (echo "ERROR: This example requires PETSc. Please compile BOUT++ with PETSc." ; exit 1) + include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-compile-examples-petsc/README.md b/tests/integrated/test-compile-examples-petsc/README.md new file mode 120000 index 0000000000..77bd1f7308 --- /dev/null +++ b/tests/integrated/test-compile-examples-petsc/README.md @@ -0,0 +1 @@ +../test-compile-examples/README.md \ No newline at end of file diff --git a/tests/integrated/test-compile-examples-petsc/runtest b/tests/integrated/test-compile-examples-petsc/runtest new file mode 100755 index 0000000000..7de133d496 --- /dev/null +++ b/tests/integrated/test-compile-examples-petsc/runtest @@ -0,0 +1,36 @@ +#!/bin/bash + +#requires: all_tests +#requires: not make +#requires: petsc + +BOUT_TOP=../../.. +export PATH=$(pwd)/$BOUT_TOP/bin:$PATH + +error=0 + +failed= +for target in $(find $BOUT_TOP/examples/ -name makefile) +do + dir=$(dirname ${target}) + if grep ":.*requires_petsc" $target -q; + then + echo "Trying to compile ${dir}" + + (cd ${dir} && make 2>&1) + ex=$? + + if test $ex -gt 0 + then + echo $(basename $dir) failed + error=1 + failed="$failed\n$(basename $dir) failed" + fi + else + echo "Skipping $dir - requires PETSc" + fi +done + +echo -e $failed + +exit $error diff --git a/tests/integrated/test-compile-examples/runtest b/tests/integrated/test-compile-examples/runtest index 89fbe933f4..8131c3b7db 100755 --- a/tests/integrated/test-compile-examples/runtest +++ b/tests/integrated/test-compile-examples/runtest @@ -3,8 +3,8 @@ #requires: all_tests #requires: not make -BOUT_TOP=$(pwd)/../../.. -export PATH=$BOUT_TOP/bin:$PATH +BOUT_TOP=../../.. +export PATH=$(pwd)/$BOUT_TOP/bin:$PATH error=0 @@ -12,18 +12,23 @@ failed= for target in $(find $BOUT_TOP/examples/ -name makefile) do dir=$(dirname ${target}) - echo "Trying to compile ${dir}" + if grep ":.*requires_petsc" $target -q; + then + #grep petsc_ + echo "Skipping $dir - requires PETSc" + else + echo "Trying to compile ${dir}" - (cd ${dir} && make 2>&1) - ex=$? + (cd ${dir} && make 2>&1) + ex=$? - if test $ex -gt 0 - then - echo $(basename $dir) failed - error=1 - failed="$failed\n$(basename $dir) failed" + if test $ex -gt 0 + then + echo $(basename $dir) failed + error=1 + failed="$failed\n$(basename $dir) failed" + fi fi - done echo -e $failed From 15474efd257167e5b4b0e78ef96069e7c8c9a25a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 11 Apr 2019 15:31:18 +0100 Subject: [PATCH 1281/1783] string header was missing --- include/initialprofiles.hxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/initialprofiles.hxx b/include/initialprofiles.hxx index 143c44544c..bf30ed0f34 100644 --- a/include/initialprofiles.hxx +++ b/include/initialprofiles.hxx @@ -26,6 +26,8 @@ #ifndef __INITIALPROF_H__ #define __INITIALPROF_H__ +#include + class Field3D; class Field2D; class Vector2D; From b19bb908494c66a9be93480f67f5108f4017a6a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 11 Apr 2019 15:34:20 +0100 Subject: [PATCH 1282/1783] Update documentation --- tests/integrated/test-compile-examples/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/integrated/test-compile-examples/README.md b/tests/integrated/test-compile-examples/README.md index 889044fa4c..2fa005c7c4 100644 --- a/tests/integrated/test-compile-examples/README.md +++ b/tests/integrated/test-compile-examples/README.md @@ -3,4 +3,11 @@ test-compile-examples This test ensures that all models in examples can be compiled. -This currently works by finding any makefile located beneath examples. As such this test will also attempt to build documentation provided with some of the models and hence may fail if a suitable document compiler is not available. \ No newline at end of file +This currently works by finding any makefile located beneath +examples. It skips any directories matching doc in order to skip +documentation. Building documentation requires often additional +tools, and is thus skipped. The test is split in two parts, one for +examples without PETSc, and one for examples that require PETSc. + +PETSc detection works by checking the makefile whether any target +requires `requires_petsc`. From 510214dabf991aa6b6a2799b176eddeba6ce9ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 11 Apr 2019 15:42:56 +0100 Subject: [PATCH 1283/1783] Cleanup Fix whitespace and commented out code --- .../test-compile-examples-petsc/runtest | 18 +++++++++--------- .../integrated/test-compile-examples/runtest | 19 +++++++++---------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/tests/integrated/test-compile-examples-petsc/runtest b/tests/integrated/test-compile-examples-petsc/runtest index 7de133d496..cd61c30ef5 100755 --- a/tests/integrated/test-compile-examples-petsc/runtest +++ b/tests/integrated/test-compile-examples-petsc/runtest @@ -15,19 +15,19 @@ do dir=$(dirname ${target}) if grep ":.*requires_petsc" $target -q; then - echo "Trying to compile ${dir}" + echo "Trying to compile ${dir}" - (cd ${dir} && make 2>&1) - ex=$? - - if test $ex -gt 0 - then + (cd ${dir} && make 2>&1) + ex=$? + + if test $ex -gt 0 + then echo $(basename $dir) failed error=1 - failed="$failed\n$(basename $dir) failed" - fi + failed="$failed\n$(basename $dir) failed" + fi else - echo "Skipping $dir - requires PETSc" + echo "Skipping $dir - requires PETSc" fi done diff --git a/tests/integrated/test-compile-examples/runtest b/tests/integrated/test-compile-examples/runtest index dc206108c9..9a77d6d04b 100755 --- a/tests/integrated/test-compile-examples/runtest +++ b/tests/integrated/test-compile-examples/runtest @@ -14,20 +14,19 @@ do dir=$(dirname ${target}) if grep ":.*requires_petsc" $target -q; then - #grep petsc_ - echo "Skipping $dir - requires PETSc" + echo "Skipping $dir - requires PETSc" else - echo "Trying to compile ${dir}" + echo "Trying to compile ${dir}" - (cd ${dir} && make 2>&1) - ex=$? - - if test $ex -gt 0 - then + (cd ${dir} && make 2>&1) + ex=$? + + if test $ex -gt 0 + then echo $(basename $dir) failed error=1 - failed="$failed\n$(basename $dir) failed" - fi + failed="$failed\n$(basename $dir) failed" + fi fi done From cd43b65ae45f031821a0cc2d2bcc5aa655d01cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 11 Apr 2019 15:56:57 +0100 Subject: [PATCH 1284/1783] Ignore new meta-vars in test-squash --- bin/bout-squashoutput | 2 -- tests/integrated/test-squash/runtest | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/bout-squashoutput b/bin/bout-squashoutput index cd3ccf5f92..804e68ab7f 100755 --- a/bin/bout-squashoutput +++ b/bin/bout-squashoutput @@ -51,8 +51,6 @@ if argcomplete: args = parser.parse_args() -# Late imports to not slow down bash completion - for ind in "txyz": args.__dict__[ind + "ind"] = slice(*args.__dict__[ind + "ind"]) # Call the function, using command line arguments diff --git a/tests/integrated/test-squash/runtest b/tests/integrated/test-squash/runtest index cc440597bf..3671cc71fc 100755 --- a/tests/integrated/test-squash/runtest +++ b/tests/integrated/test-squash/runtest @@ -51,7 +51,9 @@ def verify(f1, f2): for v in d1.keys(): if d1[v].shape != d2[v].shape: raise RuntimeError("shape mismatch in ", v, d1[v], d2[v]) - if v in ["MXSUB", "MYSUB", "NXPE", "NYPE", "iteration"]: + if v in ["MXSUB", "MYSUB", "NXPE", "NYPE", "iteration","wall_time"]: + continue + if v.startswith("wtime") or v.startswith("ncalls"): continue if not np.allclose(d1[v], d2[v]): err = "" From a3dffe0867b4a2343a9f0c6499217b0c0c8a2ac4 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 11 Apr 2019 17:58:37 +0100 Subject: [PATCH 1285/1783] SplitRK: limits on timestep and timestep changes Large increases in timestep generally overshoot and result in reductions later. In some tests the timestep was oscillating between extremes. The default now limits changes in timestep to a factor of 2 (up or down). --- .../IMEX/advection-diffusion/data/BOUT.inp | 3 +- examples/IMEX/diffusion-nl/diffusion-nl.cxx | 8 ++--- src/solver/impls/split-rk/split-rk.cxx | 32 ++++++++++++++++--- src/solver/impls/split-rk/split-rk.hxx | 5 ++- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/examples/IMEX/advection-diffusion/data/BOUT.inp b/examples/IMEX/advection-diffusion/data/BOUT.inp index 8efa164fad..4067bb1ab8 100644 --- a/examples/IMEX/advection-diffusion/data/BOUT.inp +++ b/examples/IMEX/advection-diffusion/data/BOUT.inp @@ -49,8 +49,9 @@ dz = 1 / (nz-4) [solver] type = splitrk -timestep = 1e-3 # Fixed internal timestep +timestep = 1e-4 # Internal timestep nstages = 9 # Stages in RKL steps for diffusive component +adapt_period = 5 # Internal steps between accuracy checks ################################################## # settings for split operator model diff --git a/examples/IMEX/diffusion-nl/diffusion-nl.cxx b/examples/IMEX/diffusion-nl/diffusion-nl.cxx index 920a43b94c..da685c9cd1 100644 --- a/examples/IMEX/diffusion-nl/diffusion-nl.cxx +++ b/examples/IMEX/diffusion-nl/diffusion-nl.cxx @@ -21,7 +21,7 @@ class DiffusionNL : public PhysicsModel { protected: - int init(bool restarting) { + int init(bool) { // Get the input parameter alpha auto opt = Options::root(); alpha = opt["alpha"].withDefault(2.5); @@ -42,7 +42,7 @@ class DiffusionNL : public PhysicsModel { * Convective part of the problem. In an IMEX scheme * this will be treated explicitly */ - int convective(BoutReal time) { + int convective(BoutReal) { ddt(f) = 0.0; return 0; } @@ -62,7 +62,7 @@ class DiffusionNL : public PhysicsModel { * ------- * ddt(f) = Time derivative of f */ - int diffusive(BoutReal time, bool linear) { + int diffusive(BoutReal, bool linear) { mesh->communicate(f); if (!linear) { // Update diffusion coefficient @@ -96,7 +96,7 @@ class DiffusionNL : public PhysicsModel { * * ddt(f) = Result of the inversion */ - int precon(BoutReal t, BoutReal gamma, BoutReal delta) { + int precon(BoutReal, BoutReal gamma, BoutReal) { // Preconditioner static InvertPar *inv = NULL; diff --git a/src/solver/impls/split-rk/split-rk.cxx b/src/solver/impls/split-rk/split-rk.cxx index 963332cc0a..d9c454bb6b 100644 --- a/src/solver/impls/split-rk/split-rk.cxx +++ b/src/solver/impls/split-rk/split-rk.cxx @@ -45,6 +45,11 @@ int SplitRK::init(int nout, BoutReal tstep) { max_timestep = opt["max_timestep"].doc("Maximum timestep. Negative means no limit.").withDefault(out_timestep); + max_timestep_change = opt["max_timestep_change"] + .doc("Maximum factor by which the timestep should be changed. Must be >1") + .withDefault(max_timestep_change); + ASSERT0(max_timestep_change > 1.0); + mxstep = opt["mxstep"] .doc("Maximum number of internal steps between outputs") .withDefault(mxstep); @@ -70,7 +75,9 @@ int SplitRK::init(int nout, BoutReal tstep) { nstages = opt["nstages"].doc("Number of stages in RKL step. Must be > 1").withDefault(10); ASSERT0(nstages > 1); - + + diagnose = opt["diagnose"].doc("Print diagnostic information?").withDefault(diagnose); + return 0; } @@ -113,7 +120,7 @@ int SplitRK::run() { for (int i = 0; i < nlocal; i++) { local_err += fabs(state2[i] - state1[i]) / (fabs(state1[i]) + fabs(state2[i]) + atol); } - + // Average over all processors BoutReal err; if (MPI_Allreduce(&local_err, &err, 1, MPI_DOUBLE, MPI_SUM, BoutComm::get())) { @@ -121,20 +128,37 @@ int SplitRK::run() { } err /= static_cast(neq); - + internal_steps++; if (internal_steps > mxstep) { throw BoutException("ERROR: MXSTEP exceeded. timestep = %e, err=%e\n", timestep, err); } + if (diagnose) { + output.write("\nError: %e. atol=%e, rtol=%e\n", err, atol, rtol); + } + if ((err > rtol) || (err < 0.1 * rtol)) { // Need to change timestep. Error ~ dt^2 - timestep /= sqrt(err / (0.5 * rtol)); + + BoutReal factor = pow((0.5 * rtol) / err, 1./3); + + if (factor > max_timestep_change) { + factor = max_timestep_change; + } else if (factor < 1. / max_timestep_change) { + factor = 1. / max_timestep_change; + } + + timestep *= factor; if ((max_timestep > 0) && (timestep > max_timestep)) { timestep = max_timestep; } + + if (diagnose) { + output.write("\tAdapting. timestep %e (factor %e). Max=%e\n", timestep, factor, max_timestep); + } } if (err < rtol) { swap(state, state2); // Put result in state diff --git a/src/solver/impls/split-rk/split-rk.hxx b/src/solver/impls/split-rk/split-rk.hxx index c7f39b20fd..e5752cb4cc 100644 --- a/src/solver/impls/split-rk/split-rk.hxx +++ b/src/solver/impls/split-rk/split-rk.hxx @@ -59,10 +59,13 @@ private: bool adaptive{true}; ///< Adapt timestep using tolerances? BoutReal atol{1e-10}; ///< Absolute tolerance BoutReal rtol{1e-5}; ///< Relative tolerance - BoutReal max_timestep; ///< Maximum timestep + BoutReal max_timestep{1.0}; ///< Maximum timestep + BoutReal max_timestep_change{2.0}; ///< Maximum factor by which the timestep should be changed int mxstep{1000}; ///< Maximum number of internal steps between outputs int adapt_period{1}; ///< Number of steps between checks + bool diagnose{false}; ///< Turn on diagnostic output + int nlocal, neq; ///< Number of variables on local processor and in total /// System state From 46d2f0fdcd3471c71de896cf9f92b285eaebe023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 12 Apr 2019 10:51:19 +0100 Subject: [PATCH 1286/1783] Use integrateParallelSlices and update comments --- examples/fci-wave-logn/fci-wave.cxx | 4 ++-- examples/fci-wave/fci-wave.cxx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/fci-wave-logn/fci-wave.cxx b/examples/fci-wave-logn/fci-wave.cxx index bcd602bf73..13a81e71ee 100644 --- a/examples/fci-wave-logn/fci-wave.cxx +++ b/examples/fci-wave-logn/fci-wave.cxx @@ -17,9 +17,9 @@ class FCIwave : public PhysicsModel { Field3D f_B = f / Bxyz; f_B.splitYupYdown(); - mesh->getParallelTransform().integrateYupYdown(f_B); + mesh->getParallelTransform().integrateParallelSlices(f_B); - // integrateYUpDown replaces all yup/down points, so the boundary conditions + // integrateParallelSlices replaces all yup/down points, so the boundary conditions // now need to be applied. If Bxyz has neumann parallel boundary conditions // then the boundary condition is simpler since f = 0 gives f_B=0 boundary condition. diff --git a/examples/fci-wave/fci-wave.cxx b/examples/fci-wave/fci-wave.cxx index e02b9b7ef3..b3b416b23e 100644 --- a/examples/fci-wave/fci-wave.cxx +++ b/examples/fci-wave/fci-wave.cxx @@ -18,9 +18,9 @@ class FCIwave : public PhysicsModel { Field3D f_B = f / Bxyz; f_B.splitYupYdown(); - mesh->getParallelTransform().integrateYupYdown(f_B); + mesh->getParallelTransform().integrateParallelSlices(f_B); - // integrateYUpDown replaces all yup/down points, so the boundary conditions + // integrateParallelSlices replaces all yup/down points, so the boundary conditions // now need to be applied. If Bxyz has neumann parallel boundary conditions // then the boundary condition is simpler since f = 0 gives f_B=0 boundary condition. From e2ce2caca5fcd4e0d4b9306568683f0d03fb232d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 12 Apr 2019 16:26:45 +0100 Subject: [PATCH 1287/1783] Clear Field3D parallel slices in operator= When a Field3D is assigned to, any existing parallel slices become invalid as they were calculated from the old Field3D. Therefore operator= should call clearParallelSlices() to reset yup_fields and ydown_fields. --- src/field/field3d.cxx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 66fdd158ea..495c077174 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -244,7 +244,11 @@ Field3D & Field3D::operator=(const Field3D &rhs) { return(*this); // skip this assignment TRACE("Field3D: Assignment from Field3D"); - + + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + copyFieldMembers(rhs); // Copy the data and data sizes @@ -263,6 +267,10 @@ Field3D & Field3D::operator=(const Field2D &rhs) { /// Check that the data is allocated ASSERT1(rhs.isAllocated()); + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + setLocation(rhs.getLocation()); /// Make sure there's a unique array to copy data into @@ -282,6 +290,10 @@ void Field3D::operator=(const FieldPerp &rhs) { /// Check that the data is allocated ASSERT1(rhs.isAllocated()); + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + /// Make sure there's a unique array to copy data into allocate(); @@ -292,6 +304,10 @@ void Field3D::operator=(const FieldPerp &rhs) { Field3D & Field3D::operator=(const BoutReal val) { TRACE("Field3D = BoutReal"); + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + allocate(); BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] = val; } From e93f38b8a46cb5d2fd39b325f841cb75b94dec15 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 12 Apr 2019 16:47:47 +0100 Subject: [PATCH 1288/1783] Clear parallel slices in compound assignment operators +=, -=, *=, /= should also clear parallel slices of Field3Ds as they update the data array, making the parallel slices inconsistent. --- src/field/gen_fieldops.jinja | 6 ++++ src/field/generated_fieldops.cxx | 48 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/field/gen_fieldops.jinja b/src/field/gen_fieldops.jinja index 25e1af328b..4bd091ddaf 100644 --- a/src/field/gen_fieldops.jinja +++ b/src/field/gen_fieldops.jinja @@ -59,6 +59,12 @@ ASSERT1(areFieldsCompatible(*this, rhs)); {% endif %} + {% if (lhs == "Field3D") %} + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + + {% endif %} checkData(*this); checkData({{rhs.name}}); diff --git a/src/field/generated_fieldops.cxx b/src/field/generated_fieldops.cxx index de7f39f0a0..ee9a26f0dd 100644 --- a/src/field/generated_fieldops.cxx +++ b/src/field/generated_fieldops.cxx @@ -29,6 +29,10 @@ Field3D& Field3D::operator*=(const Field3D& rhs) { if (data.unique()) { ASSERT1(areFieldsCompatible(*this, rhs)); + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + checkData(*this); checkData(rhs); @@ -65,6 +69,10 @@ Field3D& Field3D::operator/=(const Field3D& rhs) { if (data.unique()) { ASSERT1(areFieldsCompatible(*this, rhs)); + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + checkData(*this); checkData(rhs); @@ -101,6 +109,10 @@ Field3D& Field3D::operator+=(const Field3D& rhs) { if (data.unique()) { ASSERT1(areFieldsCompatible(*this, rhs)); + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + checkData(*this); checkData(rhs); @@ -137,6 +149,10 @@ Field3D& Field3D::operator-=(const Field3D& rhs) { if (data.unique()) { ASSERT1(areFieldsCompatible(*this, rhs)); + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + checkData(*this); checkData(rhs); @@ -178,6 +194,10 @@ Field3D& Field3D::operator*=(const Field2D& rhs) { if (data.unique()) { ASSERT1(areFieldsCompatible(*this, rhs)); + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + checkData(*this); checkData(rhs); @@ -225,6 +245,10 @@ Field3D& Field3D::operator/=(const Field2D& rhs) { if (data.unique()) { ASSERT1(areFieldsCompatible(*this, rhs)); + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + checkData(*this); checkData(rhs); @@ -272,6 +296,10 @@ Field3D& Field3D::operator+=(const Field2D& rhs) { if (data.unique()) { ASSERT1(areFieldsCompatible(*this, rhs)); + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + checkData(*this); checkData(rhs); @@ -318,6 +346,10 @@ Field3D& Field3D::operator-=(const Field2D& rhs) { if (data.unique()) { ASSERT1(areFieldsCompatible(*this, rhs)); + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + checkData(*this); checkData(rhs); @@ -435,6 +467,10 @@ Field3D& Field3D::operator*=(const BoutReal rhs) { // otherwise just call the non-inplace version if (data.unique()) { + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + checkData(*this); checkData(rhs); @@ -467,6 +503,10 @@ Field3D& Field3D::operator/=(const BoutReal rhs) { // otherwise just call the non-inplace version if (data.unique()) { + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + checkData(*this); checkData(rhs); @@ -499,6 +539,10 @@ Field3D& Field3D::operator+=(const BoutReal rhs) { // otherwise just call the non-inplace version if (data.unique()) { + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + checkData(*this); checkData(rhs); @@ -531,6 +575,10 @@ Field3D& Field3D::operator-=(const BoutReal rhs) { // otherwise just call the non-inplace version if (data.unique()) { + // Delete existing parallel slices. We don't copy parallel slices, so any + // that currently exist will be incorrect. + clearParallelSlices(); + checkData(*this); checkData(rhs); From 5b72ca162819fdbb609ad02f985685e757668a5d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 12 Apr 2019 17:13:57 +0100 Subject: [PATCH 1289/1783] Fix comparison of corner boundary cells in test-squash The corner boundary cells of geometrical fields are now set to NaN. Therefore use the option equal_nan in numpy.allclose() to allow NaNs to compare as equal. --- tests/integrated/test-squash/runtest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integrated/test-squash/runtest b/tests/integrated/test-squash/runtest index 3671cc71fc..691f7be057 100755 --- a/tests/integrated/test-squash/runtest +++ b/tests/integrated/test-squash/runtest @@ -55,7 +55,7 @@ def verify(f1, f2): continue if v.startswith("wtime") or v.startswith("ncalls"): continue - if not np.allclose(d1[v], d2[v]): + if not np.allclose(d1[v], d2[v], equal_nan=True): err = "" dimensions = [range(x) for x in d1[v].shape] for i in itertools.product(*dimensions): From d382136ad26eebfedf9c68e3ad8fc0b9b31dd884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 12 Apr 2019 19:18:37 +0100 Subject: [PATCH 1290/1783] call Finalise in test Ensures everything is cleaned up properly. Otherwise use-after-free might happen, e.g. for msg_stack --- tests/integrated/test-datadir/test.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integrated/test-datadir/test.cxx b/tests/integrated/test-datadir/test.cxx index 0d51c1fe7e..2916f84dba 100644 --- a/tests/integrated/test-datadir/test.cxx +++ b/tests/integrated/test-datadir/test.cxx @@ -1,5 +1,7 @@ #include int main(int argc, char **argv) { - return BoutInitialise(argc, argv); + auto ret = BoutInitialise(argc, argv); + BoutFinalise(false); + return ret; } From 22b84073bab42c02e7e3ca50c3db235593f67b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 12 Apr 2019 19:42:59 +0100 Subject: [PATCH 1291/1783] Fix and reenable --- tests/MMS/advection/data/BOUT.inp | 2 +- tests/MMS/advection/weno3/{runtest.broken => runtest} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/MMS/advection/weno3/{runtest.broken => runtest} (100%) diff --git a/tests/MMS/advection/data/BOUT.inp b/tests/MMS/advection/data/BOUT.inp index 82d7ae1d9e..4dc6ce6b79 100644 --- a/tests/MMS/advection/data/BOUT.inp +++ b/tests/MMS/advection/data/BOUT.inp @@ -6,7 +6,7 @@ MZ = 16 ZMAX = 1 MXG = 2 -MYG = 1 +MYG = 0 [mesh] diff --git a/tests/MMS/advection/weno3/runtest.broken b/tests/MMS/advection/weno3/runtest similarity index 100% rename from tests/MMS/advection/weno3/runtest.broken rename to tests/MMS/advection/weno3/runtest From 3815bf18a6a3f002e2051112851cf6408e023f1f Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sat, 13 Apr 2019 14:51:54 +0100 Subject: [PATCH 1292/1783] Remove delta_e_inv from elm-pb Now compiles again --- examples/elm-pb/elm_pb.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index af287d9da3..3ddaa5a085 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -1062,7 +1062,6 @@ int physics_init(bool restarting) { aparSolver = Laplacian::create(); aparSolver->setFlags(apar_flags); - aparSolver->setCoefA(-delta_e_inv * N0 * N0); /////////////// CHECK VACUUM /////////////////////// // In vacuum region, initial vorticity should equal zero From f1fd26bdf1428270716aa7732497fa1a823cda00 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sun, 14 Apr 2019 15:07:30 +0100 Subject: [PATCH 1293/1783] Change elm-pb to PhysicsModel class Just wrapping in class, no actual code changes. --- examples/elm-pb/elm_pb.cxx | 2991 ++++++++++++++++++------------------ 1 file changed, 1496 insertions(+), 1495 deletions(-) diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index 3ddaa5a085..f9104bc0fe 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -19,1769 +18,1771 @@ #include -// 2D inital profiles -Field2D J0, P0; // Current and pressure -Vector2D b0xcv; // Curvature term -Field2D beta, gradparB; // Used for Vpar terms -Field2D phi0; // When diamagnetic terms used -Field2D U0, Psixy, x; // 0th vorticity of equilibrium flow, -// radial flux coordinate, normalized radial flux coordinate - -bool constn0; -// the total height, average width and center of profile of N0 -BoutReal n0_height, n0_ave, n0_width, n0_center, n0_bottom_x, Nbar, Tibar, Tebar; - -BoutReal Tconst; // the ampitude of constant temperature - -Field2D N0, Ti0, Te0, Ne0; // number density and temperature -Field2D Pi0, Pe0; -Field2D q95; -Field3D ubyn; -BoutReal q95_input; -bool n0_fake_prof, T0_fake_prof; -BoutReal Zi; // charge number of ion - -// B field vectors -Vector2D B0vec; // B0 field vector - -// V0 field vectors -Vector2D V0net; // net flow - -// 3D evolving variables -Field3D U, Psi, P, Vpar; - -// Derived 3D variables -Field3D Jpar, phi; // Parallel current, electric potential - -Field3D Jpar2; // Delp2 of Parallel current - -Field3D tmpP2; // Grad2_par2new of pressure -Field3D tmpU2; // Grad2_par2new of Parallel vorticity -Field3D tmpA2; // Grad2_par2new of Parallel vector potential - -// Constraint -Field3D C_phi; - -// Parameters -BoutReal density; // Number density [m^-3] -BoutReal Bbar, Lbar, Tbar, Va; // Normalisation constants -BoutReal dnorm; // For diamagnetic terms: 1 / (2. * wci * Tbar) -BoutReal dia_fact; // Multiply diamagnetic term by this -BoutReal delta_i; // Normalized ion skin depth -BoutReal omega_i; // ion gyrofrequency - -BoutReal diffusion_p4; // xqx: parallel hyper-viscous diffusion for pressure -BoutReal diffusion_u4; // xqx: parallel hyper-viscous diffusion for vorticity -BoutReal diffusion_a4; // xqx: parallel hyper-viscous diffusion for vector potential - -BoutReal diffusion_par; // Parallel pressure diffusion -BoutReal heating_P; // heating power in pressure -BoutReal hp_width; // heating profile radial width in pressure -BoutReal hp_length; // heating radial domain in pressure -BoutReal sink_P; // sink in pressure -BoutReal sp_width; // sink profile radial width in pressure -BoutReal sp_length; // sink radial domain in pressure - -BoutReal sink_Ul; // left edge sink in vorticity -BoutReal su_widthl; // left edge sink profile radial width in vorticity -BoutReal su_lengthl; // left edge sink radial domain in vorticity - -BoutReal sink_Ur; // right edge sink in vorticity -BoutReal su_widthr; // right edge sink profile radial width in vorticity -BoutReal su_lengthr; // right edge sink radial domain in vorticity - -BoutReal viscos_par; // Parallel viscosity -BoutReal viscos_perp; // Perpendicular viscosity -BoutReal hyperviscos; // Hyper-viscosity (radial) -Field3D hyper_mu_x; // Hyper-viscosity coefficient - -Field3D Dperp2Phi0, Dperp2Phi, GradPhi02, GradPhi2; // Temporary variables for gyroviscous -Field3D GradparPhi02, GradparPhi2, GradcPhi, GradcparPhi; -Field3D Dperp2Pi0, Dperp2Pi, bracketPhi0P, bracketPhiP0, bracketPhiP; -BoutReal Upara2; - -// options -bool include_curvature, include_jpar0, compress0; -bool evolve_pressure, gyroviscous; - -BoutReal vacuum_pressure; -BoutReal vacuum_trans; // Transition width -Field3D vac_mask; - -int phi_flags, apar_flags; -bool nonlinear; -bool evolve_jpar; -BoutReal g; // Only if compressible -bool phi_curv; - -// Poisson brackets: b0 x Grad(f) dot Grad(g) / B = [f, g] -// Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE -/* - * Bracket method - * - * BRACKET_STD - Same as b0xGrad_dot_Grad, methods in BOUT.inp - * BRACKET_SIMPLE - Subset of terms, used in BOUT-06 - * BRACKET_ARAKAWA - Arakawa central differencing (2nd order) - * BRACKET_CTU - 1st order upwind method - * - */ - -// Bracket method for advection terms -BRACKET_METHOD bm_exb; -BRACKET_METHOD bm_mag; -int bm_exb_flag; -int bm_mag_flag; -/* BRACKET_METHOD bm_ExB = BRACKET_STD; - BRACKET_METHOD bm_mflutter = BRACKET_STD; */ - -bool diamag; -bool diamag_grad_t; // Grad_par(Te) term in Psi equation -bool diamag_phi0; // Include the diamagnetic equilibrium phi0 - -bool eHall; -BoutReal AA; // ion mass in units of the proton mass; AA=Mi/Mp - -// net flow, Er=-R*Bp*Dphi0,Dphi0=-D_min-0.5*D_0*(1.0-tanh(D_s*(x-x0))) -Field2D V0; // net flow amplitude -Field2D Dphi0; // differential potential to flux -BoutReal D_0; // potential amplitude -BoutReal D_s; // shear parameter -BoutReal x0; // velocity peak location -BoutReal sign; // direction of flow -BoutReal Psiaxis, Psibndry; -bool withflow; -bool K_H_term; // Kelvin-Holmhotz term -Field2D perp; // for test -BoutReal D_min; // constant in flow - -// for C_mod -bool experiment_Er; // read in total Er from experiment - -bool nogradparj; -bool filter_z; -int filter_z_mode; -int low_pass_z; -bool zonal_flow; -bool zonal_field; -bool zonal_bkgd; -bool relax_j_vac; -BoutReal relax_j_tconst; // Time-constant for j relax -Field3D Psitarget; // The (moving) target to relax to - -bool smooth_j_x; // Smooth Jpar in the x direction - -int jpar_bndry_width; // Zero jpar in a boundary region - -bool sheath_boundaries; // Apply sheath boundaries in Y - -bool parallel_lr_diff; // Use left and right shifted stencils for parallel differences - -bool phi_constraint; // Solver for phi using a solver constraint - -bool include_rmp; // Include RMP coil perturbation -bool simple_rmp; // Just use a simple form for the perturbation -int rmp_n, rmp_m; // toroidal and poloidal mode numbers -BoutReal rmp_polwid; // Poloidal width (-ve -> full, fraction of 2pi) -BoutReal rmp_polpeak; // Peak poloidal location (fraction of 2pi) -BoutReal rmp_factor; // Multiply amplitude by this factor -BoutReal rmp_ramp; // Ramp-up time for RMP [s]. negative -> instant -BoutReal rmp_freq; // Amplitude oscillation frequency [Hz] (negative -> no oscillation) -BoutReal rmp_rotate; // Rotation rate [Hz] -bool rmp_vac_mask; // Should a vacuum mask be applied? -Field3D - rmp_Psi0; // Parallel vector potential from Resonant Magnetic Perturbation (RMP) coils -Field3D rmp_Psi; // Value used in calculations -Field3D rmp_dApdt; // Time variation - -BoutReal vac_lund, core_lund; // Lundquist number S = (Tau_R / Tau_A). -ve -> infty -BoutReal vac_resist, core_resist; // The resistivities (just 1 / S) -Field3D eta; // Resistivity profile (1 / S) -bool spitzer_resist; // Use Spitzer formula for resistivity -BoutReal Zeff; // Z effective for resistivity formula - -BoutReal hyperresist; // Hyper-resistivity coefficient (in core only) -BoutReal ehyperviscos; // electron Hyper-viscosity coefficient - -int damp_width; // Width of inner damped region -BoutReal damp_t_const; // Timescale of damping - -// Metric coefficients -Field2D Rxy, Bpxy, Btxy, B0, hthe; -Field2D I; // Shear factor - -const BoutReal MU0 = 4.0e-7 * PI; -const BoutReal Mi = 2.0 * 1.6726e-27; // Ion mass -const BoutReal Me = 9.1094e-31; // Electron mass -const BoutReal mi_me = Mi / Me; - -// Communication objects -FieldGroup comms; - -/// Solver for inverting Laplacian -Laplacian* phiSolver; -Laplacian* aparSolver; - -int precon(BoutReal t, BoutReal cj, BoutReal delta); // Preconditioner -int jacobian(BoutReal t); // Jacobian-vector multiply - -int precon_phi(BoutReal t, BoutReal cj, - BoutReal delta); // Preconditioner with phi constraint - -const Field3D Grad2_par2new(const Field3D& f); // for 4th order diffusion - -const Field2D N0tanh(BoutReal n0_height, BoutReal n0_ave, BoutReal n0_width, - BoutReal n0_center, BoutReal n0_bottom_x) { - Field2D result; - result.allocate(); - - BoutReal Grid_NX, Grid_NXlimit; // the grid number on x, and the - BoutReal Jysep; - mesh->get(Grid_NX, "nx"); - mesh->get(Jysep, "jyseps1_1"); - Grid_NXlimit = n0_bottom_x * Grid_NX; - output.write("Jysep1_1 = %i Grid number = %e\n", int(Jysep), Grid_NX); - - if (Jysep > 0.) { // for single null geometry - BoutReal Jxsep, Jysep2; - mesh->get(Jxsep, "ixseps1"); - mesh->get(Jysep2, "jyseps2_2"); - // output.write("Jysep2_2 = %i Ixsep1 = %i\n", int(Jysep2), int(Jxsep)); - - for (auto i : result) { - BoutReal mgx = mesh->GlobalX(i.x()); - BoutReal xgrid_num = (Jxsep + 1.) / Grid_NX; - // output.write("mgx = %e xgrid_num = %e\n", mgx); - - int globaly = mesh->YGLOBAL(i.y()); - // output.write("local y = %i; global y: %i\n", i.y, globaly); - if (mgx > xgrid_num || (globaly <= int(Jysep) - 4) || (globaly > int(Jysep2))) - mgx = xgrid_num; - BoutReal rlx = mgx - n0_center; - BoutReal temp = exp(rlx / n0_width); - BoutReal dampr = ((temp - 1.0 / temp) / (temp + 1.0 / temp)); - result[i] = 0.5 * (1.0 - dampr) * n0_height + n0_ave; - } - } else { // circular geometry - for (auto i : result) { - BoutReal mgx = mesh->GlobalX(i.x()); - BoutReal xgrid_num = Grid_NXlimit / Grid_NX; - if (mgx > xgrid_num) - mgx = xgrid_num; - BoutReal rlx = mgx - n0_center; - BoutReal temp = exp(rlx / n0_width); - BoutReal dampr = ((temp - 1.0 / temp) / (temp + 1.0 / temp)); - result[i] = 0.5 * (1.0 - dampr) * n0_height + n0_ave; +class ELMpb : public PhysicsModel { +private: + // 2D inital profiles + Field2D J0, P0; // Current and pressure + Vector2D b0xcv; // Curvature term + Field2D beta, gradparB; // Used for Vpar terms + Field2D phi0; // When diamagnetic terms used + Field2D U0, Psixy, x; // 0th vorticity of equilibrium flow, + // radial flux coordinate, normalized radial flux coordinate + + bool constn0; + // the total height, average width and center of profile of N0 + BoutReal n0_height, n0_ave, n0_width, n0_center, n0_bottom_x, Nbar, Tibar, Tebar; + + BoutReal Tconst; // the ampitude of constant temperature + + Field2D N0, Ti0, Te0, Ne0; // number density and temperature + Field2D Pi0, Pe0; + Field2D q95; + Field3D ubyn; + BoutReal q95_input; + bool n0_fake_prof, T0_fake_prof; + BoutReal Zi; // charge number of ion + + // B field vectors + Vector2D B0vec; // B0 field vector + + // V0 field vectors + Vector2D V0net; // net flow + + // 3D evolving variables + Field3D U, Psi, P, Vpar; + + // Derived 3D variables + Field3D Jpar, phi; // Parallel current, electric potential + + Field3D Jpar2; // Delp2 of Parallel current + + Field3D tmpP2; // Grad2_par2new of pressure + Field3D tmpU2; // Grad2_par2new of Parallel vorticity + Field3D tmpA2; // Grad2_par2new of Parallel vector potential + + // Constraint + Field3D C_phi; + + // Parameters + BoutReal density; // Number density [m^-3] + BoutReal Bbar, Lbar, Tbar, Va; // Normalisation constants + BoutReal dnorm; // For diamagnetic terms: 1 / (2. * wci * Tbar) + BoutReal dia_fact; // Multiply diamagnetic term by this + BoutReal delta_i; // Normalized ion skin depth + BoutReal omega_i; // ion gyrofrequency + + BoutReal diffusion_p4; // xqx: parallel hyper-viscous diffusion for pressure + BoutReal diffusion_u4; // xqx: parallel hyper-viscous diffusion for vorticity + BoutReal diffusion_a4; // xqx: parallel hyper-viscous diffusion for vector potential + + BoutReal diffusion_par; // Parallel pressure diffusion + BoutReal heating_P; // heating power in pressure + BoutReal hp_width; // heating profile radial width in pressure + BoutReal hp_length; // heating radial domain in pressure + BoutReal sink_P; // sink in pressure + BoutReal sp_width; // sink profile radial width in pressure + BoutReal sp_length; // sink radial domain in pressure + + BoutReal sink_Ul; // left edge sink in vorticity + BoutReal su_widthl; // left edge sink profile radial width in vorticity + BoutReal su_lengthl; // left edge sink radial domain in vorticity + + BoutReal sink_Ur; // right edge sink in vorticity + BoutReal su_widthr; // right edge sink profile radial width in vorticity + BoutReal su_lengthr; // right edge sink radial domain in vorticity + + BoutReal viscos_par; // Parallel viscosity + BoutReal viscos_perp; // Perpendicular viscosity + BoutReal hyperviscos; // Hyper-viscosity (radial) + Field3D hyper_mu_x; // Hyper-viscosity coefficient + + Field3D Dperp2Phi0, Dperp2Phi, GradPhi02, + GradPhi2; // Temporary variables for gyroviscous + Field3D GradparPhi02, GradparPhi2, GradcPhi, GradcparPhi; + Field3D Dperp2Pi0, Dperp2Pi, bracketPhi0P, bracketPhiP0, bracketPhiP; + BoutReal Upara2; + + // options + bool include_curvature, include_jpar0, compress0; + bool evolve_pressure, gyroviscous; + + BoutReal vacuum_pressure; + BoutReal vacuum_trans; // Transition width + Field3D vac_mask; + + int phi_flags, apar_flags; + bool nonlinear; + bool evolve_jpar; + BoutReal g; // Only if compressible + bool phi_curv; + + // Poisson brackets: b0 x Grad(f) dot Grad(g) / B = [f, g] + // Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE + /* + * Bracket method + * + * BRACKET_STD - Same as b0xGrad_dot_Grad, methods in BOUT.inp + * BRACKET_SIMPLE - Subset of terms, used in BOUT-06 + * BRACKET_ARAKAWA - Arakawa central differencing (2nd order) + * BRACKET_CTU - 1st order upwind method + * + */ + + // Bracket method for advection terms + BRACKET_METHOD bm_exb; + BRACKET_METHOD bm_mag; + int bm_exb_flag; + int bm_mag_flag; + /* BRACKET_METHOD bm_ExB = BRACKET_STD; + BRACKET_METHOD bm_mflutter = BRACKET_STD; */ + + bool diamag; + bool diamag_grad_t; // Grad_par(Te) term in Psi equation + bool diamag_phi0; // Include the diamagnetic equilibrium phi0 + + bool eHall; + BoutReal AA; // ion mass in units of the proton mass; AA=Mi/Mp + + // net flow, Er=-R*Bp*Dphi0,Dphi0=-D_min-0.5*D_0*(1.0-tanh(D_s*(x-x0))) + Field2D V0; // net flow amplitude + Field2D Dphi0; // differential potential to flux + BoutReal D_0; // potential amplitude + BoutReal D_s; // shear parameter + BoutReal x0; // velocity peak location + BoutReal sign; // direction of flow + BoutReal Psiaxis, Psibndry; + bool withflow; + bool K_H_term; // Kelvin-Holmhotz term + Field2D perp; // for test + BoutReal D_min; // constant in flow + + // for C_mod + bool experiment_Er; // read in total Er from experiment + + bool nogradparj; + bool filter_z; + int filter_z_mode; + int low_pass_z; + bool zonal_flow; + bool zonal_field; + bool zonal_bkgd; + bool relax_j_vac; + BoutReal relax_j_tconst; // Time-constant for j relax + Field3D Psitarget; // The (moving) target to relax to + + bool smooth_j_x; // Smooth Jpar in the x direction + + int jpar_bndry_width; // Zero jpar in a boundary region + + bool sheath_boundaries; // Apply sheath boundaries in Y + + bool parallel_lr_diff; // Use left and right shifted stencils for parallel differences + + bool phi_constraint; // Solver for phi using a solver constraint + + bool include_rmp; // Include RMP coil perturbation + bool simple_rmp; // Just use a simple form for the perturbation + int rmp_n, rmp_m; // toroidal and poloidal mode numbers + BoutReal rmp_polwid; // Poloidal width (-ve -> full, fraction of 2pi) + BoutReal rmp_polpeak; // Peak poloidal location (fraction of 2pi) + BoutReal rmp_factor; // Multiply amplitude by this factor + BoutReal rmp_ramp; // Ramp-up time for RMP [s]. negative -> instant + BoutReal rmp_freq; // Amplitude oscillation frequency [Hz] (negative -> no oscillation) + BoutReal rmp_rotate; // Rotation rate [Hz] + bool rmp_vac_mask; // Should a vacuum mask be applied? + Field3D rmp_Psi0; // Parallel vector potential from Resonant Magnetic Perturbation (RMP) + // coils + Field3D rmp_Psi; // Value used in calculations + Field3D rmp_dApdt; // Time variation + + BoutReal vac_lund, core_lund; // Lundquist number S = (Tau_R / Tau_A). -ve -> infty + BoutReal vac_resist, core_resist; // The resistivities (just 1 / S) + Field3D eta; // Resistivity profile (1 / S) + bool spitzer_resist; // Use Spitzer formula for resistivity + BoutReal Zeff; // Z effective for resistivity formula + + BoutReal hyperresist; // Hyper-resistivity coefficient (in core only) + BoutReal ehyperviscos; // electron Hyper-viscosity coefficient + + int damp_width; // Width of inner damped region + BoutReal damp_t_const; // Timescale of damping + + // Metric coefficients + Field2D Rxy, Bpxy, Btxy, B0, hthe; + Field2D I; // Shear factor + + const BoutReal MU0 = 4.0e-7 * PI; + const BoutReal Mi = 2.0 * 1.6726e-27; // Ion mass + const BoutReal Me = 9.1094e-31; // Electron mass + const BoutReal mi_me = Mi / Me; + + // Communication objects + FieldGroup comms; + + /// Solver for inverting Laplacian + Laplacian* phiSolver; + Laplacian* aparSolver; + + const Field2D N0tanh(BoutReal n0_height, BoutReal n0_ave, BoutReal n0_width, + BoutReal n0_center, BoutReal n0_bottom_x) { + Field2D result; + result.allocate(); + + BoutReal Grid_NX, Grid_NXlimit; // the grid number on x, and the + BoutReal Jysep; + mesh->get(Grid_NX, "nx"); + mesh->get(Jysep, "jyseps1_1"); + Grid_NXlimit = n0_bottom_x * Grid_NX; + output.write("Jysep1_1 = %i Grid number = %e\n", int(Jysep), Grid_NX); + + if (Jysep > 0.) { // for single null geometry + BoutReal Jxsep, Jysep2; + mesh->get(Jxsep, "ixseps1"); + mesh->get(Jysep2, "jyseps2_2"); + // output.write("Jysep2_2 = %i Ixsep1 = %i\n", int(Jysep2), int(Jxsep)); + + for (auto i : result) { + BoutReal mgx = mesh->GlobalX(i.x()); + BoutReal xgrid_num = (Jxsep + 1.) / Grid_NX; + // output.write("mgx = %e xgrid_num = %e\n", mgx); + + int globaly = mesh->YGLOBAL(i.y()); + // output.write("local y = %i; global y: %i\n", i.y, globaly); + if (mgx > xgrid_num || (globaly <= int(Jysep) - 4) || (globaly > int(Jysep2))) + mgx = xgrid_num; + BoutReal rlx = mgx - n0_center; + BoutReal temp = exp(rlx / n0_width); + BoutReal dampr = ((temp - 1.0 / temp) / (temp + 1.0 / temp)); + result[i] = 0.5 * (1.0 - dampr) * n0_height + n0_ave; + } + } else { // circular geometry + for (auto i : result) { + BoutReal mgx = mesh->GlobalX(i.x()); + BoutReal xgrid_num = Grid_NXlimit / Grid_NX; + if (mgx > xgrid_num) + mgx = xgrid_num; + BoutReal rlx = mgx - n0_center; + BoutReal temp = exp(rlx / n0_width); + BoutReal dampr = ((temp - 1.0 / temp) / (temp + 1.0 / temp)); + result[i] = 0.5 * (1.0 - dampr) * n0_height + n0_ave; + } } - } - mesh->communicate(result); + mesh->communicate(result); - return result; -} + return result; + } -/*! - * This function implements d2/dy2 where y is the poloidal coordinate theta - */ -const Field3D Grad2_par2new(const Field3D& f) { - TRACE("Grad2_par2new( Field3D )"); + /*! + * This function implements d2/dy2 where y is the poloidal coordinate theta + */ + const Field3D Grad2_par2new(const Field3D& f) { + TRACE("Grad2_par2new( Field3D )"); - Field3D result = D2DY2(f); + Field3D result = D2DY2(f); #ifdef TRACK - result.name = "Grad2_par2new(" + f.name + ")"; + result.name = "Grad2_par2new(" + f.name + ")"; #endif - return result; -} + return result; + } +protected: + int init(bool restarting) { + bool noshear; -int physics_init(bool restarting) { - bool noshear; + Coordinates* metric = mesh->getCoordinates(); - Coordinates* metric = mesh->getCoordinates(); + output.write("Solving high-beta flute reduced equations\n"); + output.write("\tFile : %s\n", __FILE__); + output.write("\tCompiled: %s at %s\n", __DATE__, __TIME__); - output.write("Solving high-beta flute reduced equations\n"); - output.write("\tFile : %s\n", __FILE__); - output.write("\tCompiled: %s at %s\n", __DATE__, __TIME__); + ////////////////////////////////////////////////////////////// + // Load data from the grid - ////////////////////////////////////////////////////////////// - // Load data from the grid + // Load 2D profiles + mesh->get(J0, "Jpar0"); // A / m^2 + mesh->get(P0, "pressure"); // Pascals - // Load 2D profiles - mesh->get(J0, "Jpar0"); // A / m^2 - mesh->get(P0, "pressure"); // Pascals + // Load curvature term + b0xcv.covariant = false; // Read contravariant components + mesh->get(b0xcv, "bxcv"); // mixed units x: T y: m^-2 z: m^-2 - // Load curvature term - b0xcv.covariant = false; // Read contravariant components - mesh->get(b0xcv, "bxcv"); // mixed units x: T y: m^-2 z: m^-2 + // Load metrics + if (mesh->get(Rxy, "Rxy")) { // m + output_error.write("Error: Cannot read Rxy from grid\n"); + return 1; + } + if (mesh->get(Bpxy, "Bpxy")) { // T + output_error.write("Error: Cannot read Bpxy from grid\n"); + return 1; + } + mesh->get(Btxy, "Btxy"); // T + mesh->get(B0, "Bxy"); // T + mesh->get(hthe, "hthe"); // m + mesh->get(I, "sinty"); // m^-2 T^-1 + mesh->get(Psixy, "psixy"); // get Psi + mesh->get(Psiaxis, "psi_axis"); // axis flux + mesh->get(Psibndry, "psi_bndry"); // edge flux + + ////////////////////////////////////////////////////////////// + // Read parameters from the options file + // + // Options.get ( NAME, VARIABLE, DEFAULT VALUE) + // + // or if NAME = "VARIABLE" then just + // + // OPTION(VARIABLE, DEFAULT VALUE) + // + // Prints out what values are assigned + ///////////////////////////////////////////////////////////// + + auto globalOptions = Options::root(); + auto options = globalOptions["highbeta"]; + + constn0 = options["constn0"].withDefault(true); + // use the hyperbolic profile of n0. If both n0_fake_prof and + // T0_fake_prof are false, use the profiles from grid file + n0_fake_prof = options["n0_fake_prof"].withDefault(false); + // the total height of profile of N0, in percentage of Ni_x + n0_height = options["n0_height"].withDefault(0.4); + // the center or average of N0, in percentage of Ni_x + n0_ave = options["n0_ave"].withDefault(0.01); + // the width of the gradient of N0,in percentage of x + n0_width = options["n0_width"].withDefault(0.1); + // the grid number of the center of N0, in percentage of x + n0_center = options["n0_center"].withDefault(0.633); + // the start of flat region of N0 on SOL side, in percentage of x + n0_bottom_x = options["n0_bottom_x"].withDefault(0.81); + T0_fake_prof = options["T0_fake_prof"].withDefault(false); + // the amplitude of constant temperature, in percentage + Tconst = options["Tconst"].withDefault(-1.0); + + density = options["density"].withDefault(1.0e19); // Number density [m^-3] + + // If true, evolve J raher than Psi + evolve_jpar = options["evolve_jpar"].withDefault(false); + // Use solver constraint for phi + phi_constraint = options["phi_constraint"].withDefault(false); + + // Effects to include/exclude + include_curvature = options["include_curvature"].withDefault(true); + include_jpar0 = options["include_jpar0"].withDefault(true); + evolve_pressure = options["evolve_pressure"].withDefault(true); + nogradparj = options["nogradparj"].withDefault(false); + + compress0 = options["compress0"].withDefault(false); + gyroviscous = options["gyroviscous"].withDefault(false); + nonlinear = options["nonlinear"].withDefault(false); + + // option for ExB Poisson Bracket + bm_exb_flag = options["bm_exb_flag"].withDefault(0); + switch (bm_exb_flag) { + case 0: { + bm_exb = BRACKET_STD; + output << "\tBrackets for ExB: default differencing\n"; + break; + } + case 1: { + bm_exb = BRACKET_SIMPLE; + output << "\tBrackets for ExB: simplified operator\n"; + break; + } + case 2: { + bm_exb = BRACKET_ARAKAWA; + output << "\tBrackets for ExB: Arakawa scheme\n"; + break; + } + case 3: { + bm_exb = BRACKET_CTU; + output << "\tBrackets for ExB: Corner Transport Upwind method\n"; + break; + } + default: + output << "ERROR: Invalid choice of bracket method. Must be 0 - 3\n"; + return 1; + } - // Load metrics - if (mesh->get(Rxy, "Rxy")) { // m - output_error.write("Error: Cannot read Rxy from grid\n"); - return 1; - } - if (mesh->get(Bpxy, "Bpxy")) { // T - output_error.write("Error: Cannot read Bpxy from grid\n"); - return 1; - } - mesh->get(Btxy, "Btxy"); // T - mesh->get(B0, "Bxy"); // T - mesh->get(hthe, "hthe"); // m - mesh->get(I, "sinty"); // m^-2 T^-1 - mesh->get(Psixy, "psixy"); // get Psi - mesh->get(Psiaxis, "psi_axis"); // axis flux - mesh->get(Psibndry, "psi_bndry"); // edge flux - - ////////////////////////////////////////////////////////////// - // Read parameters from the options file - // - // Options.get ( NAME, VARIABLE, DEFAULT VALUE) - // - // or if NAME = "VARIABLE" then just - // - // OPTION(VARIABLE, DEFAULT VALUE) - // - // Prints out what values are assigned - ///////////////////////////////////////////////////////////// - - auto globalOptions = Options::root(); - auto options = globalOptions["highbeta"]; - - constn0 = options["constn0"].withDefault(true); - // use the hyperbolic profile of n0. If both n0_fake_prof and - // T0_fake_prof are false, use the profiles from grid file - n0_fake_prof = options["n0_fake_prof"].withDefault(false); - // the total height of profile of N0, in percentage of Ni_x - n0_height = options["n0_height"].withDefault(0.4); - // the center or average of N0, in percentage of Ni_x - n0_ave = options["n0_ave"].withDefault(0.01); - // the width of the gradient of N0,in percentage of x - n0_width = options["n0_width"].withDefault(0.1); - // the grid number of the center of N0, in percentage of x - n0_center = options["n0_center"].withDefault(0.633); - // the start of flat region of N0 on SOL side, in percentage of x - n0_bottom_x = options["n0_bottom_x"].withDefault(0.81); - T0_fake_prof = options["T0_fake_prof"].withDefault(false); - // the amplitude of constant temperature, in percentage - Tconst = options["Tconst"].withDefault(-1.0); - - density = options["density"].withDefault(1.0e19); // Number density [m^-3] - - // If true, evolve J raher than Psi - evolve_jpar = options["evolve_jpar"].withDefault(false); - // Use solver constraint for phi - phi_constraint = options["phi_constraint"].withDefault(false); - - // Effects to include/exclude - include_curvature = options["include_curvature"].withDefault(true); - include_jpar0 = options["include_jpar0"].withDefault(true); - evolve_pressure = options["evolve_pressure"].withDefault(true); - nogradparj = options["nogradparj"].withDefault(false); - - compress0 = options["compress0"].withDefault(false); - gyroviscous = options["gyroviscous"].withDefault(false); - nonlinear = options["nonlinear"].withDefault(false); - - // option for ExB Poisson Bracket - bm_exb_flag = options["bm_exb_flag"].withDefault(0); - switch (bm_exb_flag) { - case 0: { - bm_exb = BRACKET_STD; - output << "\tBrackets for ExB: default differencing\n"; - break; - } - case 1: { - bm_exb = BRACKET_SIMPLE; - output << "\tBrackets for ExB: simplified operator\n"; - break; - } - case 2: { - bm_exb = BRACKET_ARAKAWA; - output << "\tBrackets for ExB: Arakawa scheme\n"; - break; - } - case 3: { - bm_exb = BRACKET_CTU; - output << "\tBrackets for ExB: Corner Transport Upwind method\n"; - break; - } - default: - output << "ERROR: Invalid choice of bracket method. Must be 0 - 3\n"; - return 1; - } + // option for magnetic flutter Poisson Bracket + bm_mag_flag = options["bm_mag_flag"].withDefault(0); + switch (bm_mag_flag) { + case 0: { + bm_mag = BRACKET_STD; + output << "\tBrackets: default differencing\n"; + break; + } + case 1: { + bm_mag = BRACKET_SIMPLE; + output << "\tBrackets: simplified operator\n"; + break; + } + case 2: { + bm_mag = BRACKET_ARAKAWA; + output << "\tBrackets: Arakawa scheme\n"; + break; + } + case 3: { + bm_mag = BRACKET_CTU; + output << "\tBrackets: Corner Transport Upwind method\n"; + break; + } + default: + output << "ERROR: Invalid choice of bracket method. Must be 0 - 3\n"; + return 1; + } - // option for magnetic flutter Poisson Bracket - bm_mag_flag = options["bm_mag_flag"].withDefault(0); - switch (bm_mag_flag) { - case 0: { - bm_mag = BRACKET_STD; - output << "\tBrackets: default differencing\n"; - break; - } - case 1: { - bm_mag = BRACKET_SIMPLE; - output << "\tBrackets: simplified operator\n"; - break; - } - case 2: { - bm_mag = BRACKET_ARAKAWA; - output << "\tBrackets: Arakawa scheme\n"; - break; - } - case 3: { - bm_mag = BRACKET_CTU; - output << "\tBrackets: Corner Transport Upwind method\n"; - break; - } - default: - output << "ERROR: Invalid choice of bracket method. Must be 0 - 3\n"; - return 1; - } + // electron Hall or electron parallel pressue gradient effects? + eHall = options["eHall"].withDefault(false); + AA = options["AA"].withDefault(1.0); // ion mass in units of proton mass + + // Diamagnetic effects? + diamag = options["diamag"].withDefault(false); + // Grad_par(Te) term in Psi equation + diamag_grad_t = options["diamag_grad_t"].withDefault(diamag); + // Include equilibrium phi0 + diamag_phi0 = options["diamag_phi0"].withDefault(diamag); + // Scale diamagnetic effects by this factor + dia_fact = options["dia_fact"].withDefault(1.0); + + // withflow or not + withflow = options["withflow"].withDefault(false); + // keep K-H term + K_H_term = options["K_H_term"].withDefault(true); + // velocity magnitude + D_0 = options["D_0"].withDefault(0.0); + // flowshear + D_s = options["D_s"].withDefault(0.0); + // flow location + x0 = options["x0"].withDefault(0.0); + // flow direction, -1 means negative electric field + sign = options["sign"].withDefault(1.0); + // a constant + D_min = options["D_min"].withDefault(3000.0); + + experiment_Er = options["experiment_Er"].withDefault(false); + + noshear = options["noshear"].withDefault(false); + + relax_j_vac = + options["relax_j_vac"].withDefault(false); // Relax vacuum current to zero + relax_j_tconst = options["relax_j_tconst"].withDefault(0.1); + + // Toroidal filtering + filter_z = options["filter_z"].withDefault(false); // Filter a single n + filter_z_mode = options["filter_z_mode"].withDefault(1); + low_pass_z = options["low_pass_z"].withDefault(false); // Low-pass filter + zonal_flow = options["zonal_flow"].withDefault(false); // zonal flow filter + zonal_field = options["zonal_field"].withDefault(false); // zonal field filter + zonal_bkgd = options["zonal_bkgd"].withDefault(false); // zonal background P filter + + // Radial smoothing + smooth_j_x = options["smooth_j_x"].withDefault(false); // Smooth Jpar in x + + // Jpar boundary region + jpar_bndry_width = options["jpar_bndry_width"].withDefault(-1); + + sheath_boundaries = options["sheath_boundaries"].withDefault(false); + + // Parallel differencing + parallel_lr_diff = options["parallel_lr_diff"].withDefault(false); + + // RMP-related options + include_rmp = options["include_rmp"].withDefault(false); // Read RMP data from grid + + simple_rmp = options["simple_rmp"].withDefault(false); // Include a simple RMP model + rmp_factor = options["rmp_factor"].withDefault(1.0); + rmp_ramp = options["rmp_ramp"].withDefault(-1.0); + rmp_freq = options["rmp_freq"].withDefault(-1.0); + rmp_rotate = options["rmp_rotate"].withDefault(0.0); + + // Vacuum region control + // Fraction of peak pressure + vacuum_pressure = options["vacuum_pressure"].withDefault(0.02); + // Transition width in pressure + vacuum_trans = options["vacuum_trans"].withDefault(0.005); + + // Resistivity and hyper-resistivity options + vac_lund = options["vac_lund"].withDefault(0.0); // Lundquist number in vacuum region + core_lund = options["core_lund"].withDefault(0.0); // Lundquist number in core region + hyperresist = options["hyperresist"].withDefault(-1.0); + ehyperviscos = options["ehyperviscos"].withDefault(-1.0); + // Use Spitzer resistivity + spitzer_resist = options["spitzer_resist"].withDefault(false); + Zeff = options["Zeff"].withDefault(2.0); // Z effective + + // Inner boundary damping + damp_width = options["damp_width"].withDefault(0); + damp_t_const = options["damp_t_const"].withDefault(0.1); + + // Viscosity and hyper-viscosity + viscos_par = options["viscos_par"].withDefault(-1.0); // Parallel viscosity + viscos_perp = options["viscos_perp"].withDefault(-1.0); // Perpendicular viscosity + hyperviscos = options["hyperviscos"].withDefault(-1.0); // Radial hyperviscosity + + // parallel pressure diffusion + // Parallel pressure diffusion + diffusion_par = options["diffusion_par"].withDefault(-1.0); + // xqx: parallel hyper-viscous diffusion for pressure + diffusion_p4 = options["diffusion_p4"].withDefault(-1.0); + // xqx: parallel hyper-viscous diffusion for vorticity + diffusion_u4 = options["diffusion_u4"].withDefault(-1.0); + // xqx: parallel hyper-viscous diffusion for vector potential + diffusion_a4 = options["diffusion_a4"].withDefault(-1.0); + + // heating factor in pressure + // heating power in pressure + heating_P = options["heating_P"].withDefault(-1.0); + // the percentage of radial grid points for heating profile radial + // width in pressure + hp_width = options["hp_width"].withDefault(0.1); + // the percentage of radial grid points for heating profile radial + // domain in pressure + hp_length = options["hp_length"].withDefault(0.04); + + // sink factor in pressure + // sink in pressure + sink_P = options["sink_P"].withDefault(-1.0); + // the percentage of radial grid points for sink profile radial + // width in pressure + sp_width = options["sp_width"].withDefault(0.05); + // the percentage of radial grid points for sink profile radial + // domain in pressure + sp_length = options["sp_length"].withDefault(0.04); + + // left edge sink factor in vorticity + // left edge sink in vorticity + sink_Ul = options["sink_Ul"].withDefault(-1.0); + // the percentage of left edge radial grid points for sink profile + // radial width in vorticity + su_widthl = options["su_widthl"].withDefault(0.06); + // the percentage of left edge radial grid points for sink profile + // radial domain in vorticity + su_lengthl = options["su_lengthl"].withDefault(0.15); + + // right edge sink factor in vorticity + // right edge sink in vorticity + sink_Ur = options["sink_Ur"].withDefault(-1.0); + // the percentage of right edge radial grid points for sink profile + // radial width in vorticity + su_widthr = options["su_widthr"].withDefault(0.06); + // the percentage of right edge radial grid points for sink profile + // radial domain in vorticity + su_lengthr = options["su_lengthr"].withDefault(0.15); + + // Compressional terms + phi_curv = options["phi_curv"].withDefault(true); + g = options["gamma"].withDefault(5.0 / 3.0); + + // Field inversion flags + phi_flags = options["phi_flags"].withDefault(0); + apar_flags = options["apar_flags"].withDefault(0); + + x = (Psixy - Psiaxis) / (Psibndry - Psiaxis); + + if (experiment_Er) { // get er from experiment + mesh->get(Dphi0, "Epsi"); + diamag_phi0 = false; + K_H_term = false; + } else { + Dphi0 = -D_min - 0.5 * D_0 * (1.0 - tanh(D_s * (x - x0))); + } - // electron Hall or electron parallel pressue gradient effects? - eHall = options["eHall"].withDefault(false); - AA = options["AA"].withDefault(1.0); // ion mass in units of proton mass - - // Diamagnetic effects? - diamag = options["diamag"].withDefault(false); - // Grad_par(Te) term in Psi equation - diamag_grad_t = options["diamag_grad_t"].withDefault(diamag); - // Include equilibrium phi0 - diamag_phi0 = options["diamag_phi0"].withDefault(diamag); - // Scale diamagnetic effects by this factor - dia_fact = options["dia_fact"].withDefault(1.0); - - // withflow or not - withflow = options["withflow"].withDefault(false); - // keep K-H term - K_H_term = options["K_H_term"].withDefault(true); - // velocity magnitude - D_0 = options["D_0"].withDefault(0.0); - // flowshear - D_s = options["D_s"].withDefault(0.0); - // flow location - x0 = options["x0"].withDefault(0.0); - // flow direction, -1 means negative electric field - sign = options["sign"].withDefault(1.0); - // a constant - D_min = options["D_min"].withDefault(3000.0); - - experiment_Er = options["experiment_Er"].withDefault(false); - - noshear = options["noshear"].withDefault(false); - - relax_j_vac = options["relax_j_vac"].withDefault(false); // Relax vacuum current to zero - relax_j_tconst = options["relax_j_tconst"].withDefault(0.1); - - // Toroidal filtering - filter_z = options["filter_z"].withDefault(false); // Filter a single n - filter_z_mode = options["filter_z_mode"].withDefault(1); - low_pass_z = options["low_pass_z"].withDefault(false); // Low-pass filter - zonal_flow = options["zonal_flow"].withDefault(false); // zonal flow filter - zonal_field = options["zonal_field"].withDefault(false); // zonal field filter - zonal_bkgd = options["zonal_bkgd"].withDefault(false); // zonal background P filter - - // Radial smoothing - smooth_j_x = options["smooth_j_x"].withDefault(false); // Smooth Jpar in x - - // Jpar boundary region - jpar_bndry_width = options["jpar_bndry_width"].withDefault(-1); - - sheath_boundaries = options["sheath_boundaries"].withDefault(false); - - // Parallel differencing - parallel_lr_diff = options["parallel_lr_diff"].withDefault(false); - - // RMP-related options - include_rmp = options["include_rmp"].withDefault(false); // Read RMP data from grid - - simple_rmp = options["simple_rmp"].withDefault(false); // Include a simple RMP model - rmp_factor = options["rmp_factor"].withDefault(1.0); - rmp_ramp = options["rmp_ramp"].withDefault(-1.0); - rmp_freq = options["rmp_freq"].withDefault(-1.0); - rmp_rotate = options["rmp_rotate"].withDefault(0.0); - - // Vacuum region control - // Fraction of peak pressure - vacuum_pressure = options["vacuum_pressure"].withDefault(0.02); - // Transition width in pressure - vacuum_trans = options["vacuum_trans"].withDefault(0.005); - - // Resistivity and hyper-resistivity options - vac_lund = options["vac_lund"].withDefault(0.0); // Lundquist number in vacuum region - core_lund = options["core_lund"].withDefault(0.0); // Lundquist number in core region - hyperresist = options["hyperresist"].withDefault(-1.0); - ehyperviscos = options["ehyperviscos"].withDefault(-1.0); - // Use Spitzer resistivity - spitzer_resist = options["spitzer_resist"].withDefault(false); - Zeff = options["Zeff"].withDefault(2.0); // Z effective - - // Inner boundary damping - damp_width = options["damp_width"].withDefault(0); - damp_t_const = options["damp_t_const"].withDefault(0.1); - - // Viscosity and hyper-viscosity - viscos_par = options["viscos_par"].withDefault(-1.0); // Parallel viscosity - viscos_perp = options["viscos_perp"].withDefault(-1.0); // Perpendicular viscosity - hyperviscos = options["hyperviscos"].withDefault(-1.0); // Radial hyperviscosity - - // parallel pressure diffusion - // Parallel pressure diffusion - diffusion_par = options["diffusion_par"].withDefault(-1.0); - // xqx: parallel hyper-viscous diffusion for pressure - diffusion_p4 = options["diffusion_p4"].withDefault(-1.0); - // xqx: parallel hyper-viscous diffusion for vorticity - diffusion_u4 = options["diffusion_u4"].withDefault(-1.0); - // xqx: parallel hyper-viscous diffusion for vector potential - diffusion_a4 = options["diffusion_a4"].withDefault(-1.0); - - // heating factor in pressure - // heating power in pressure - heating_P = options["heating_P"].withDefault(-1.0); - // the percentage of radial grid points for heating profile radial - // width in pressure - hp_width = options["hp_width"].withDefault(0.1); - // the percentage of radial grid points for heating profile radial - // domain in pressure - hp_length = options["hp_length"].withDefault(0.04); - - // sink factor in pressure - // sink in pressure - sink_P = options["sink_P"].withDefault(-1.0); - // the percentage of radial grid points for sink profile radial - // width in pressure - sp_width = options["sp_width"].withDefault(0.05); - // the percentage of radial grid points for sink profile radial - // domain in pressure - sp_length = options["sp_length"].withDefault(0.04); - - // left edge sink factor in vorticity - // left edge sink in vorticity - sink_Ul = options["sink_Ul"].withDefault(-1.0); - // the percentage of left edge radial grid points for sink profile - // radial width in vorticity - su_widthl = options["su_widthl"].withDefault(0.06); - // the percentage of left edge radial grid points for sink profile - // radial domain in vorticity - su_lengthl = options["su_lengthl"].withDefault(0.15); - - // right edge sink factor in vorticity - // right edge sink in vorticity - sink_Ur = options["sink_Ur"].withDefault(-1.0); - // the percentage of right edge radial grid points for sink profile - // radial width in vorticity - su_widthr = options["su_widthr"].withDefault(0.06); - // the percentage of right edge radial grid points for sink profile - // radial domain in vorticity - su_lengthr = options["su_lengthr"].withDefault(0.15); - - // Compressional terms - phi_curv = options["phi_curv"].withDefault(true); - g = options["gamma"].withDefault(5.0 / 3.0); - - // Field inversion flags - phi_flags = options["phi_flags"].withDefault(0); - apar_flags = options["apar_flags"].withDefault(0); - - x = (Psixy - Psiaxis) / (Psibndry - Psiaxis); - - if (experiment_Er) { // get er from experiment - mesh->get(Dphi0, "Epsi"); - diamag_phi0 = false; - K_H_term = false; - } else { - Dphi0 = -D_min - 0.5 * D_0 * (1.0 - tanh(D_s * (x - x0))); - } + if (sign < 0) // change flow direction + Dphi0 *= -1; - if (sign < 0) // change flow direction - Dphi0 *= -1; + V0 = -Rxy * Bpxy * Dphi0 / B0; - V0 = -Rxy * Bpxy * Dphi0 / B0; + if (simple_rmp) + include_rmp = true; - if (simple_rmp) - include_rmp = true; + if (include_rmp) { + // Including external field coils. + if (simple_rmp) { + // Use a fairly simple form for the perturbation + + Field2D pol_angle; + if (mesh->get(pol_angle, "pol_angle")) { + output_warn.write(" ***WARNING: need poloidal angle for simple RMP\n"); + include_rmp = false; + } else { + rmp_n = options["rmp_n"].withDefault(3); + rmp_m = options["rmp_m"].withDefault(9); + rmp_polwid = options["rmp_polwid"].withDefault(-1.0); + rmp_polpeak = options["rmp_polpeak"].withDefault(0.5); + rmp_vac_mask = options["rmp_vac_mask"].withDefault(true); + // Divide n by the size of the domain + int zperiod = globalOptions["zperiod"].withDefault(1); + if ((rmp_n % zperiod) != 0) + output_warn.write( + " ***WARNING: rmp_n (%d) not a multiple of zperiod (%d)\n", rmp_n, + zperiod); + + output.write("\tMagnetic perturbation: n = %d, m = %d, magnitude %e Tm\n", + rmp_n, rmp_m, rmp_factor); + + rmp_Psi0 = 0.0; + if (mesh->lastX()) { + // Set the outer boundary + for (int jx = mesh->LocalNx - 4; jx < mesh->LocalNx; jx++) + for (int jy = 0; jy < mesh->LocalNy; jy++) + for (int jz = 0; jz < mesh->LocalNz; jz++) { + + BoutReal angle = rmp_m * pol_angle(jx, jy) + + rmp_n * ((BoutReal)jz) * mesh->getCoordinates()->dz; + rmp_Psi0(jx, jy, jz) = + (((BoutReal)(jx - 4)) / ((BoutReal)(mesh->LocalNx - 5))) + * rmp_factor * cos(angle); + if (rmp_polwid > 0.0) { + // Multiply by a Gaussian in poloidal angle + BoutReal gx = + ((pol_angle(jx, jy) / (2. * PI)) - rmp_polpeak) / rmp_polwid; + rmp_Psi0(jx, jy, jz) *= exp(-gx * gx); + } + } + } - if (include_rmp) { - // Including external field coils. - if (simple_rmp) { - // Use a fairly simple form for the perturbation + // Now have a simple model for Psi due to coils at the outer boundary + // Need to calculate Psi inside the domain, enforcing j = 0 - Field2D pol_angle; - if (mesh->get(pol_angle, "pol_angle")) { - output_warn.write(" ***WARNING: need poloidal angle for simple RMP\n"); - include_rmp = false; + Jpar = 0.0; + Laplacian* psiLap = Laplacian::create(); + psiLap->setInnerBoundaryFlags(INVERT_AC_GRAD); // Zero gradient inner BC + psiLap->setOuterBoundaryFlags(INVERT_SET); // Set to rmp_Psi0 on outer boundary + rmp_Psi0 = psiLap->solve(Jpar, rmp_Psi0); + mesh->communicate(rmp_Psi0); + } } else { - rmp_n = options["rmp_n"].withDefault(3); - rmp_m = options["rmp_m"].withDefault(9); - rmp_polwid = options["rmp_polwid"].withDefault(-1.0); - rmp_polpeak = options["rmp_polpeak"].withDefault(0.5); - rmp_vac_mask = options["rmp_vac_mask"].withDefault(true); - // Divide n by the size of the domain - int zperiod = globalOptions["zperiod"].withDefault(1); - if ((rmp_n % zperiod) != 0) - output_warn.write( - " ***WARNING: rmp_n (%d) not a multiple of zperiod (%d)\n", rmp_n, - zperiod); - - output.write("\tMagnetic perturbation: n = %d, m = %d, magnitude %e Tm\n", rmp_n, - rmp_m, rmp_factor); - - rmp_Psi0 = 0.0; - if (mesh->lastX()) { - // Set the outer boundary - for (int jx = mesh->LocalNx - 4; jx < mesh->LocalNx; jx++) - for (int jy = 0; jy < mesh->LocalNy; jy++) - for (int jz = 0; jz < mesh->LocalNz; jz++) { - - BoutReal angle = rmp_m * pol_angle(jx, jy) - + rmp_n * ((BoutReal)jz) * mesh->getCoordinates()->dz; - rmp_Psi0(jx, jy, jz) = - (((BoutReal)(jx - 4)) / ((BoutReal)(mesh->LocalNx - 5))) * rmp_factor - * cos(angle); - if (rmp_polwid > 0.0) { - // Multiply by a Gaussian in poloidal angle - BoutReal gx = - ((pol_angle(jx, jy) / (2. * PI)) - rmp_polpeak) / rmp_polwid; - rmp_Psi0(jx, jy, jz) *= exp(-gx * gx); - } - } + // Load perturbation from grid file. + include_rmp = !mesh->get(rmp_Psi0, "rmp_A"); // Only include if found + if (!include_rmp) { + output_warn.write("WARNING: Couldn't read 'rmp_A' from grid file\n"); } + // Multiply by factor + rmp_Psi0 *= rmp_factor; + } + } - // Now have a simple model for Psi due to coils at the outer boundary - // Need to calculate Psi inside the domain, enforcing j = 0 + if (!include_curvature) + b0xcv = 0.0; - Jpar = 0.0; - Laplacian* psiLap = Laplacian::create(); - psiLap->setInnerBoundaryFlags(INVERT_AC_GRAD); // Zero gradient inner BC - psiLap->setOuterBoundaryFlags(INVERT_SET); // Set to rmp_Psi0 on outer boundary - rmp_Psi0 = psiLap->solve(Jpar, rmp_Psi0); - mesh->communicate(rmp_Psi0); - } - } else { - // Load perturbation from grid file. - include_rmp = !mesh->get(rmp_Psi0, "rmp_A"); // Only include if found - if (!include_rmp) { - output_warn.write("WARNING: Couldn't read 'rmp_A' from grid file\n"); - } - // Multiply by factor - rmp_Psi0 *= rmp_factor; + if (!include_jpar0) + J0 = 0.0; + + if (noshear) { + if (include_curvature) + b0xcv.z += I * b0xcv.x; + I = 0.0; } - } - if (!include_curvature) - b0xcv = 0.0; + ////////////////////////////////////////////////////////////// + // SHIFTED RADIAL COORDINATES - if (!include_jpar0) - J0 = 0.0; + if (mesh->IncIntShear) { + // BOUT-06 style, using d/dx = d/dpsi + I * d/dz + metric->IntShiftTorsion = I; - if (noshear) { - if (include_curvature) - b0xcv.z += I * b0xcv.x; - I = 0.0; - } + } else { + // Dimits style, using local coordinate system + if (include_curvature) + b0xcv.z += I * b0xcv.x; + I = 0.0; // I disappears from metric + } - ////////////////////////////////////////////////////////////// - // SHIFTED RADIAL COORDINATES + ////////////////////////////////////////////////////////////// + // NORMALISE QUANTITIES - if (mesh->IncIntShear) { - // BOUT-06 style, using d/dx = d/dpsi + I * d/dz - metric->IntShiftTorsion = I; + if (mesh->get(Bbar, "bmag")) // Typical magnetic field + Bbar = 1.0; + if (mesh->get(Lbar, "rmag")) // Typical length scale + Lbar = 1.0; - } else { - // Dimits style, using local coordinate system - if (include_curvature) - b0xcv.z += I * b0xcv.x; - I = 0.0; // I disappears from metric - } + Va = sqrt(Bbar * Bbar / (MU0 * density * Mi)); - ////////////////////////////////////////////////////////////// - // NORMALISE QUANTITIES + Tbar = Lbar / Va; - if (mesh->get(Bbar, "bmag")) // Typical magnetic field - Bbar = 1.0; - if (mesh->get(Lbar, "rmag")) // Typical length scale - Lbar = 1.0; + dnorm = dia_fact * Mi / (2. * 1.602e-19 * Bbar * Tbar); - Va = sqrt(Bbar * Bbar / (MU0 * density * Mi)); + delta_i = AA * 60.67 * 5.31e5 / sqrt(density / 1e6) / (Lbar * 100.0); - Tbar = Lbar / Va; + output.write("Normalisations: Bbar = %e T Lbar = %e m\n", Bbar, Lbar); + output.write(" Va = %e m/s Tbar = %e s\n", Va, Tbar); + output.write(" dnorm = %e\n", dnorm); + output.write(" Resistivity\n"); - dnorm = dia_fact * Mi / (2. * 1.602e-19 * Bbar * Tbar); + if (gyroviscous) { + omega_i = 9.58e7 * Zeff * Bbar; + Upara2 = 0.5 / (Tbar * omega_i); + // Upara3 = 1.0; + output.write("Upara2 = %e Omega_i = %e\n", Upara2, omega_i); + } - delta_i = AA * 60.67 * 5.31e5 / sqrt(density / 1e6) / (Lbar * 100.0); + if (eHall) + output.write(" delta_i = %e AA = %e \n", delta_i, AA); - output.write("Normalisations: Bbar = %e T Lbar = %e m\n", Bbar, Lbar); - output.write(" Va = %e m/s Tbar = %e s\n", Va, Tbar); - output.write(" dnorm = %e\n", dnorm); - output.write(" Resistivity\n"); + if (vac_lund > 0.0) { + output.write(" Vacuum Tau_R = %e s eta = %e Ohm m\n", vac_lund * Tbar, + MU0 * Lbar * Lbar / (vac_lund * Tbar)); + vac_resist = 1. / vac_lund; + } else { + output.write(" Vacuum - Zero resistivity -\n"); + vac_resist = 0.0; + } + if (core_lund > 0.0) { + output.write(" Core Tau_R = %e s eta = %e Ohm m\n", core_lund * Tbar, + MU0 * Lbar * Lbar / (core_lund * Tbar)); + core_resist = 1. / core_lund; + } else { + output.write(" Core - Zero resistivity -\n"); + core_resist = 0.0; + } - if (gyroviscous) { - omega_i = 9.58e7 * Zeff * Bbar; - Upara2 = 0.5 / (Tbar * omega_i); - // Upara3 = 1.0; - output.write("Upara2 = %e Omega_i = %e\n", Upara2, omega_i); - } + if (hyperresist > 0.0) { + output.write(" Hyper-resistivity coefficient: %e\n", hyperresist); + } - if (eHall) - output.write(" delta_i = %e AA = %e \n", delta_i, AA); + if (ehyperviscos > 0.0) { + output.write(" electron Hyper-viscosity coefficient: %e\n", ehyperviscos); + } - if (vac_lund > 0.0) { - output.write(" Vacuum Tau_R = %e s eta = %e Ohm m\n", vac_lund * Tbar, - MU0 * Lbar * Lbar / (vac_lund * Tbar)); - vac_resist = 1. / vac_lund; - } else { - output.write(" Vacuum - Zero resistivity -\n"); - vac_resist = 0.0; - } - if (core_lund > 0.0) { - output.write(" Core Tau_R = %e s eta = %e Ohm m\n", core_lund * Tbar, - MU0 * Lbar * Lbar / (core_lund * Tbar)); - core_resist = 1. / core_lund; - } else { - output.write(" Core - Zero resistivity -\n"); - core_resist = 0.0; - } + if (hyperviscos > 0.0) { + output.write(" Hyper-viscosity coefficient: %e\n", hyperviscos); + dump.add(hyper_mu_x, "hyper_mu_x", 1); + } - if (hyperresist > 0.0) { - output.write(" Hyper-resistivity coefficient: %e\n", hyperresist); - } + if (diffusion_par > 0.0) { + output.write(" diffusion_par: %e\n", diffusion_par); + dump.add(diffusion_par, "diffusion_par", 1); + } - if (ehyperviscos > 0.0) { - output.write(" electron Hyper-viscosity coefficient: %e\n", ehyperviscos); - } + // xqx: parallel hyper-viscous diffusion for pressure + if (diffusion_p4 > 0.0) { + output.write(" diffusion_p4: %e\n", diffusion_p4); + dump.add(diffusion_p4, "diffusion_p4", 1); + } - if (hyperviscos > 0.0) { - output.write(" Hyper-viscosity coefficient: %e\n", hyperviscos); - dump.add(hyper_mu_x, "hyper_mu_x", 1); - } + // xqx: parallel hyper-viscous diffusion for vorticity + if (diffusion_u4 > 0.0) { + output.write(" diffusion_u4: %e\n", diffusion_u4); + dump.add(diffusion_u4, "diffusion_u4", 1); + } - if (diffusion_par > 0.0) { - output.write(" diffusion_par: %e\n", diffusion_par); - dump.add(diffusion_par, "diffusion_par", 1); - } + // xqx: parallel hyper-viscous diffusion for vector potential + if (diffusion_a4 > 0.0) { + output.write(" diffusion_a4: %e\n", diffusion_a4); + dump.add(diffusion_a4, "diffusion_a4", 1); + } - // xqx: parallel hyper-viscous diffusion for pressure - if (diffusion_p4 > 0.0) { - output.write(" diffusion_p4: %e\n", diffusion_p4); - dump.add(diffusion_p4, "diffusion_p4", 1); - } + if (heating_P > 0.0) { + output.write(" heating_P(watts): %e\n", heating_P); + dump.add(heating_P, "heating_P", 1); - // xqx: parallel hyper-viscous diffusion for vorticity - if (diffusion_u4 > 0.0) { - output.write(" diffusion_u4: %e\n", diffusion_u4); - dump.add(diffusion_u4, "diffusion_u4", 1); - } + output.write(" hp_width(%%): %e\n", hp_width); + dump.add(hp_width, "hp_width", 1); - // xqx: parallel hyper-viscous diffusion for vector potential - if (diffusion_a4 > 0.0) { - output.write(" diffusion_a4: %e\n", diffusion_a4); - dump.add(diffusion_a4, "diffusion_a4", 1); - } + output.write(" hp_length(%%): %e\n", hp_length); + dump.add(hp_length, "hp_length", 1); + } - if (heating_P > 0.0) { - output.write(" heating_P(watts): %e\n", heating_P); - dump.add(heating_P, "heating_P", 1); + if (sink_P > 0.0) { + output.write(" sink_P(rate): %e\n", sink_P); + dump.add(sink_P, "sink_P", 1); - output.write(" hp_width(%%): %e\n", hp_width); - dump.add(hp_width, "hp_width", 1); + output.write(" sp_width(%%): %e\n", sp_width); + dump.add(sp_width, "sp_width", 1); - output.write(" hp_length(%%): %e\n", hp_length); - dump.add(hp_length, "hp_length", 1); - } + output.write(" sp_length(%%): %e\n", sp_length); + dump.add(sp_length, "sp_length", 1); + } - if (sink_P > 0.0) { - output.write(" sink_P(rate): %e\n", sink_P); - dump.add(sink_P, "sink_P", 1); + if (K_H_term) + output.write(" keep K-H term\n"); + else + output.write(" drop K-H term\n"); - output.write(" sp_width(%%): %e\n", sp_width); - dump.add(sp_width, "sp_width", 1); + Field2D Te; + Te = P0 / (2.0 * density * 1.602e-19); // Temperature in eV - output.write(" sp_length(%%): %e\n", sp_length); - dump.add(sp_length, "sp_length", 1); - } + J0 = -MU0 * Lbar * J0 / B0; + P0 = 2.0 * MU0 * P0 / (Bbar * Bbar); + V0 = V0 / Va; + Dphi0 *= Tbar; - if (K_H_term) - output.write(" keep K-H term\n"); - else - output.write(" drop K-H term\n"); - - Field2D Te; - Te = P0 / (2.0 * density * 1.602e-19); // Temperature in eV - - J0 = -MU0 * Lbar * J0 / B0; - P0 = 2.0 * MU0 * P0 / (Bbar * Bbar); - V0 = V0 / Va; - Dphi0 *= Tbar; - - b0xcv.x /= Bbar; - b0xcv.y *= Lbar * Lbar; - b0xcv.z *= Lbar * Lbar; - - Rxy /= Lbar; - Bpxy /= Bbar; - Btxy /= Bbar; - B0 /= Bbar; - hthe /= Lbar; - metric->dx /= Lbar * Lbar * Bbar; - I *= Lbar * Lbar * Bbar; - - if (constn0) { - T0_fake_prof = false; - n0_fake_prof = false; - } else { - Nbar = 1.0; - Tibar = 1000.0; - Tebar = 1000.0; - - if ((!T0_fake_prof) && n0_fake_prof) { - N0 = N0tanh(n0_height * Nbar, n0_ave * Nbar, n0_width, n0_center, n0_bottom_x); - - Ti0 = P0 / N0 / 2.0; - Te0 = Ti0; - } else if (T0_fake_prof) { - Ti0 = Tconst; - Te0 = Ti0; - N0 = P0 / (Ti0 + Te0); + b0xcv.x /= Bbar; + b0xcv.y *= Lbar * Lbar; + b0xcv.z *= Lbar * Lbar; + + Rxy /= Lbar; + Bpxy /= Bbar; + Btxy /= Bbar; + B0 /= Bbar; + hthe /= Lbar; + metric->dx /= Lbar * Lbar * Bbar; + I *= Lbar * Lbar * Bbar; + + if (constn0) { + T0_fake_prof = false; + n0_fake_prof = false; } else { - if (mesh->get(N0, "Niexp")) { // N_i0 - output_error.write("Error: Cannot read Ni0 from grid\n"); - return 1; - } + Nbar = 1.0; + Tibar = 1000.0; + Tebar = 1000.0; + + if ((!T0_fake_prof) && n0_fake_prof) { + N0 = N0tanh(n0_height * Nbar, n0_ave * Nbar, n0_width, n0_center, n0_bottom_x); + + Ti0 = P0 / N0 / 2.0; + Te0 = Ti0; + } else if (T0_fake_prof) { + Ti0 = Tconst; + Te0 = Ti0; + N0 = P0 / (Ti0 + Te0); + } else { + if (mesh->get(N0, "Niexp")) { // N_i0 + output_error.write("Error: Cannot read Ni0 from grid\n"); + return 1; + } - if (mesh->get(Ti0, "Tiexp")) { // T_i0 - output_error.write("Error: Cannot read Ti0 from grid\n"); - return 1; - } + if (mesh->get(Ti0, "Tiexp")) { // T_i0 + output_error.write("Error: Cannot read Ti0 from grid\n"); + return 1; + } - if (mesh->get(Te0, "Teexp")) { // T_e0 - output_error.write("Error: Cannot read Te0 from grid\n"); - return 1; + if (mesh->get(Te0, "Teexp")) { // T_e0 + output_error.write("Error: Cannot read Te0 from grid\n"); + return 1; + } + N0 /= Nbar; + Ti0 /= Tibar; + Te0 /= Tebar; } - N0 /= Nbar; - Ti0 /= Tibar; - Te0 /= Tebar; } - } - if (gyroviscous) { - Dperp2Phi0.setLocation(CELL_CENTRE); - Dperp2Phi0.setBoundary("phi"); - Dperp2Phi.setLocation(CELL_CENTRE); - Dperp2Phi.setBoundary("phi"); - GradPhi02.setLocation(CELL_CENTRE); - GradPhi02.setBoundary("phi"); - GradcPhi.setLocation(CELL_CENTRE); - GradcPhi.setBoundary("phi"); - Dperp2Pi0.setLocation(CELL_CENTRE); - Dperp2Pi0.setBoundary("P"); - Dperp2Pi.setLocation(CELL_CENTRE); - Dperp2Pi.setBoundary("P"); - bracketPhi0P.setLocation(CELL_CENTRE); - bracketPhi0P.setBoundary("P"); - bracketPhiP0.setLocation(CELL_CENTRE); - bracketPhiP0.setBoundary("P"); - if (nonlinear) { - GradPhi2.setLocation(CELL_CENTRE); - GradPhi2.setBoundary("phi"); - bracketPhiP.setLocation(CELL_CENTRE); - bracketPhiP.setBoundary("P"); + if (gyroviscous) { + Dperp2Phi0.setLocation(CELL_CENTRE); + Dperp2Phi0.setBoundary("phi"); + Dperp2Phi.setLocation(CELL_CENTRE); + Dperp2Phi.setBoundary("phi"); + GradPhi02.setLocation(CELL_CENTRE); + GradPhi02.setBoundary("phi"); + GradcPhi.setLocation(CELL_CENTRE); + GradcPhi.setBoundary("phi"); + Dperp2Pi0.setLocation(CELL_CENTRE); + Dperp2Pi0.setBoundary("P"); + Dperp2Pi.setLocation(CELL_CENTRE); + Dperp2Pi.setBoundary("P"); + bracketPhi0P.setLocation(CELL_CENTRE); + bracketPhi0P.setBoundary("P"); + bracketPhiP0.setLocation(CELL_CENTRE); + bracketPhiP0.setBoundary("P"); + if (nonlinear) { + GradPhi2.setLocation(CELL_CENTRE); + GradPhi2.setBoundary("phi"); + bracketPhiP.setLocation(CELL_CENTRE); + bracketPhiP.setBoundary("P"); + } } - } - BoutReal pnorm = max(P0, true); // Maximum over all processors + BoutReal pnorm = max(P0, true); // Maximum over all processors - vacuum_pressure *= pnorm; // Get pressure from fraction - vacuum_trans *= pnorm; + vacuum_pressure *= pnorm; // Get pressure from fraction + vacuum_trans *= pnorm; - // Transitions from 0 in core to 1 in vacuum - vac_mask = (1.0 - tanh((P0 - vacuum_pressure) / vacuum_trans)) / 2.0; + // Transitions from 0 in core to 1 in vacuum + vac_mask = (1.0 - tanh((P0 - vacuum_pressure) / vacuum_trans)) / 2.0; - if (spitzer_resist) { - // Use Spitzer resistivity - output.write("\tTemperature: %e -> %e [eV]\n", min(Te), max(Te)); - eta = 0.51 * 1.03e-4 * Zeff * 20. - * pow(Te, -1.5); // eta in Ohm-m. NOTE: ln(Lambda) = 20 - output.write("\tSpitzer resistivity: %e -> %e [Ohm m]\n", min(eta), max(eta)); - eta /= MU0 * Va * Lbar; - output.write("\t -> Lundquist %e -> %e\n", 1.0 / max(eta), 1.0 / min(eta)); - } else { - // transition from 0 for large P0 to resistivity for small P0 - eta = core_resist + (vac_resist - core_resist) * vac_mask; - } + if (spitzer_resist) { + // Use Spitzer resistivity + output.write("\tTemperature: %e -> %e [eV]\n", min(Te), max(Te)); + eta = 0.51 * 1.03e-4 * Zeff * 20. + * pow(Te, -1.5); // eta in Ohm-m. NOTE: ln(Lambda) = 20 + output.write("\tSpitzer resistivity: %e -> %e [Ohm m]\n", min(eta), max(eta)); + eta /= MU0 * Va * Lbar; + output.write("\t -> Lundquist %e -> %e\n", 1.0 / max(eta), 1.0 / min(eta)); + } else { + // transition from 0 for large P0 to resistivity for small P0 + eta = core_resist + (vac_resist - core_resist) * vac_mask; + } - SAVE_ONCE(eta); + SAVE_ONCE(eta); - if (include_rmp) { - // Normalise RMP quantities + if (include_rmp) { + // Normalise RMP quantities - rmp_Psi0 /= Bbar * Lbar; + rmp_Psi0 /= Bbar * Lbar; - rmp_ramp /= Tbar; - rmp_freq *= Tbar; - rmp_rotate *= Tbar; + rmp_ramp /= Tbar; + rmp_freq *= Tbar; + rmp_rotate *= Tbar; - rmp_Psi = rmp_Psi0; - rmp_dApdt = 0.0; + rmp_Psi = rmp_Psi0; + rmp_dApdt = 0.0; - bool apar_changing = false; + bool apar_changing = false; - output.write("Including magnetic perturbation\n"); - if (rmp_ramp > 0.0) { - output.write("\tRamping up over period t = %e (%e ms)\n", rmp_ramp, - rmp_ramp * Tbar * 1000.); - apar_changing = true; - } - if (rmp_freq > 0.0) { - output.write("\tOscillating with frequency f = %e (%e kHz)\n", rmp_freq, - rmp_freq / Tbar / 1000.); - apar_changing = true; - } - if (rmp_rotate != 0.0) { - output.write("\tRotating with a frequency f = %e (%e kHz)\n", rmp_rotate, - rmp_rotate / Tbar / 1000.); - apar_changing = true; - } + output.write("Including magnetic perturbation\n"); + if (rmp_ramp > 0.0) { + output.write("\tRamping up over period t = %e (%e ms)\n", rmp_ramp, + rmp_ramp * Tbar * 1000.); + apar_changing = true; + } + if (rmp_freq > 0.0) { + output.write("\tOscillating with frequency f = %e (%e kHz)\n", rmp_freq, + rmp_freq / Tbar / 1000.); + apar_changing = true; + } + if (rmp_rotate != 0.0) { + output.write("\tRotating with a frequency f = %e (%e kHz)\n", rmp_rotate, + rmp_rotate / Tbar / 1000.); + apar_changing = true; + } - if (apar_changing) { - SAVE_REPEAT(rmp_Psi, rmp_dApdt); - } else { - SAVE_ONCE(rmp_Psi); - } - } else - rmp_Psi = 0.0; + if (apar_changing) { + SAVE_REPEAT(rmp_Psi, rmp_dApdt); + } else { + SAVE_ONCE(rmp_Psi); + } + } else + rmp_Psi = 0.0; - /**************** CALCULATE METRICS ******************/ + /**************** CALCULATE METRICS ******************/ - metric->g11 = SQ(Rxy * Bpxy); - metric->g22 = 1.0 / SQ(hthe); - metric->g33 = SQ(I) * metric->g11 + SQ(B0) / metric->g11; - metric->g12 = 0.0; - metric->g13 = -I * metric->g11; - metric->g23 = -Btxy / (hthe * Bpxy * Rxy); + metric->g11 = SQ(Rxy * Bpxy); + metric->g22 = 1.0 / SQ(hthe); + metric->g33 = SQ(I) * metric->g11 + SQ(B0) / metric->g11; + metric->g12 = 0.0; + metric->g13 = -I * metric->g11; + metric->g23 = -Btxy / (hthe * Bpxy * Rxy); - metric->J = hthe / Bpxy; - metric->Bxy = B0; + metric->J = hthe / Bpxy; + metric->Bxy = B0; - metric->g_11 = 1.0 / metric->g11 + SQ(I * Rxy); - metric->g_22 = SQ(B0 * hthe / Bpxy); - metric->g_33 = Rxy * Rxy; - metric->g_12 = Btxy * hthe * I * Rxy / Bpxy; - metric->g_13 = I * Rxy * Rxy; - metric->g_23 = Btxy * hthe * Rxy / Bpxy; + metric->g_11 = 1.0 / metric->g11 + SQ(I * Rxy); + metric->g_22 = SQ(B0 * hthe / Bpxy); + metric->g_33 = Rxy * Rxy; + metric->g_12 = Btxy * hthe * I * Rxy / Bpxy; + metric->g_13 = I * Rxy * Rxy; + metric->g_23 = Btxy * hthe * Rxy / Bpxy; - metric->geometry(); // Calculate quantities from metric tensor + metric->geometry(); // Calculate quantities from metric tensor - // Set B field vector + // Set B field vector - B0vec.covariant = false; - B0vec.x = 0.; - B0vec.y = Bpxy / hthe; - B0vec.z = 0.; + B0vec.covariant = false; + B0vec.x = 0.; + B0vec.y = Bpxy / hthe; + B0vec.z = 0.; - V0net.covariant = false; // presentation for net flow - V0net.x = 0.; - V0net.y = Rxy * Btxy * Bpxy / (hthe * B0 * B0) * Dphi0; - V0net.z = -Dphi0; + V0net.covariant = false; // presentation for net flow + V0net.x = 0.; + V0net.y = Rxy * Btxy * Bpxy / (hthe * B0 * B0) * Dphi0; + V0net.z = -Dphi0; - U0 = B0vec * Curl(V0net) / B0; // get 0th vorticity for Kelvin-Holmholtz term + U0 = B0vec * Curl(V0net) / B0; // get 0th vorticity for Kelvin-Holmholtz term - /**************** SET EVOLVING VARIABLES *************/ + /**************** SET EVOLVING VARIABLES *************/ - // Tell BOUT which variables to evolve - SOLVE_FOR(U, P); + // Tell BOUT which variables to evolve + SOLVE_FOR(U, P); - if (evolve_jpar) { - output.write("Solving for jpar: Inverting to get Psi\n"); - SOLVE_FOR(Jpar); - dump.add(Psi, "Psi", 1); - } else { - output.write("Solving for Psi, Differentiating to get jpar\n"); - SOLVE_FOR(Psi); - dump.add(Jpar, "jpar", 1); - } + if (evolve_jpar) { + output.write("Solving for jpar: Inverting to get Psi\n"); + SOLVE_FOR(Jpar); + dump.add(Psi, "Psi", 1); + } else { + output.write("Solving for Psi, Differentiating to get jpar\n"); + SOLVE_FOR(Psi); + dump.add(Jpar, "jpar", 1); + } - if (compress0) { - output.write("Including compression (Vpar) effects\n"); + if (compress0) { + output.write("Including compression (Vpar) effects\n"); - SOLVE_FOR(Vpar); - comms.add(Vpar); + SOLVE_FOR(Vpar); + comms.add(Vpar); - beta = B0 * B0 / (0.5 + (B0 * B0 / (g * P0))); - gradparB = Grad_par(B0) / B0; + beta = B0 * B0 / (0.5 + (B0 * B0 / (g * P0))); + gradparB = Grad_par(B0) / B0; - output.write("Beta in range %e -> %e\n", min(beta), max(beta)); - } else { - Vpar = 0.0; - } + output.write("Beta in range %e -> %e\n", min(beta), max(beta)); + } else { + Vpar = 0.0; + } - if (phi_constraint) { - // Implicit Phi solve using IDA + if (phi_constraint) { + // Implicit Phi solve using IDA - if (!bout_constrain(phi, C_phi, "phi")) { - output_error.write( - "ERROR: Cannot constrain. Run again with phi_constraint=false\n"); - throw BoutException("Aborting.\n"); - } + if (!solver->constraints()) { + output_error.write( + "ERROR: Cannot constrain. Run again with phi_constraint=false\n"); + throw BoutException("Aborting.\n"); + } - // Set preconditioner - solver->setPrecon(precon_phi); + solver->constraint(phi, C_phi, "phi"); + + // Set preconditioner + setPrecon( (preconfunc) &ELMpb::precon_phi ); - } else { - // Phi solved in RHS (explicitly) - dump.add(phi, "phi", 1); + } else { + // Phi solved in RHS (explicitly) + dump.add(phi, "phi", 1); - // Set preconditioner - solver->setPrecon(precon); + // Set preconditioner + setPrecon( (preconfunc) &ELMpb::precon ); - // Set Jacobian - solver->setJacobian(jacobian); - } + // Set Jacobian + setJacobian( (jacobianfunc) &ELMpb::jacobian ); + } - // Diamagnetic phi0 - if (diamag_phi0) { - if (constn0) - phi0 = -0.5 * dnorm * P0 / B0; - else - // Stationary equilibrium plasma. ExB velocity balances diamagnetic drift - phi0 = -0.5 * dnorm * P0 / B0 / N0; - SAVE_ONCE(phi0); - } + // Diamagnetic phi0 + if (diamag_phi0) { + if (constn0) + phi0 = -0.5 * dnorm * P0 / B0; + else + // Stationary equilibrium plasma. ExB velocity balances diamagnetic drift + phi0 = -0.5 * dnorm * P0 / B0 / N0; + SAVE_ONCE(phi0); + } - // Add some equilibrium quantities and normalisations - // everything needed to recover physical units - SAVE_ONCE(J0, P0); - SAVE_ONCE(density, Lbar, Bbar, Tbar); - SAVE_ONCE(Va, B0); - SAVE_ONCE(Dphi0, U0); - SAVE_ONCE(V0); - if (!constn0) - SAVE_ONCE(Ti0, Te0, N0); + // Add some equilibrium quantities and normalisations + // everything needed to recover physical units + SAVE_ONCE(J0, P0); + SAVE_ONCE(density, Lbar, Bbar, Tbar); + SAVE_ONCE(Va, B0); + SAVE_ONCE(Dphi0, U0); + SAVE_ONCE(V0); + if (!constn0) + SAVE_ONCE(Ti0, Te0, N0); - // Create a solver for the Laplacian - phiSolver = Laplacian::create(); - phiSolver->setFlags(phi_flags); + // Create a solver for the Laplacian + phiSolver = Laplacian::create(); + phiSolver->setFlags(phi_flags); - aparSolver = Laplacian::create(); - aparSolver->setFlags(apar_flags); + aparSolver = Laplacian::create(); + aparSolver->setFlags(apar_flags); - /////////////// CHECK VACUUM /////////////////////// - // In vacuum region, initial vorticity should equal zero + /////////////// CHECK VACUUM /////////////////////// + // In vacuum region, initial vorticity should equal zero - // ubyn.setLocation(CELL_YLOW); - // ubyn.setBoundary("U"); + // ubyn.setLocation(CELL_YLOW); + // ubyn.setBoundary("U"); - if (!restarting) { - // Only if not restarting: Check initial perturbation + if (!restarting) { + // Only if not restarting: Check initial perturbation - // Set U to zero where P0 < vacuum_pressure - U = where(P0 - vacuum_pressure, U, 0.0); + // Set U to zero where P0 < vacuum_pressure + U = where(P0 - vacuum_pressure, U, 0.0); - if (constn0) { - ubyn = U; - // Phi should be consistent with U - phi = phiSolver->solve(ubyn); - } else { - ubyn = U / N0; - phiSolver->setCoefC(N0); - phi = phiSolver->solve(ubyn); + if (constn0) { + ubyn = U; + // Phi should be consistent with U + phi = phiSolver->solve(ubyn); + } else { + ubyn = U / N0; + phiSolver->setCoefC(N0); + phi = phiSolver->solve(ubyn); + } + + // if(diamag) { + // phi -= 0.5*dnorm * P / B0; + //} } - // if(diamag) { - // phi -= 0.5*dnorm * P / B0; - //} - } + /************** SETUP COMMUNICATIONS **************/ - /************** SETUP COMMUNICATIONS **************/ + comms.add(U, P); - comms.add(U, P); + phi.setBoundary("phi"); // Set boundary conditions + tmpU2.setBoundary("U"); + tmpP2.setBoundary("P"); + tmpA2.setBoundary("J"); - phi.setBoundary("phi"); // Set boundary conditions - tmpU2.setBoundary("U"); - tmpP2.setBoundary("P"); - tmpA2.setBoundary("J"); + if (evolve_jpar) { + comms.add(Jpar); + } else { + comms.add(Psi); + // otherwise Need to communicate Jpar separately + Jpar.setBoundary("J"); + } + Jpar2.setBoundary("J"); - if (evolve_jpar) { - comms.add(Jpar); - } else { - comms.add(Psi); - // otherwise Need to communicate Jpar separately - Jpar.setBoundary("J"); + return 0; } - Jpar2.setBoundary("J"); - - return 0; -} -// Parallel gradient along perturbed field-line -const Field3D Grad_parP(const Field3D& f, CELL_LOC loc = CELL_DEFAULT) { - Field3D result; + // Parallel gradient along perturbed field-line + const Field3D Grad_parP(const Field3D& f, CELL_LOC loc = CELL_DEFAULT) { + Field3D result; - if (parallel_lr_diff) { - // Use left/right biased stencils. NOTE: First order only! - if (loc == CELL_YLOW) { - result = Grad_par_CtoL(f); + if (parallel_lr_diff) { + // Use left/right biased stencils. NOTE: First order only! + if (loc == CELL_YLOW) { + result = Grad_par_CtoL(f); + } else + result = Grad_par_LtoC(f); } else - result = Grad_par_LtoC(f); - } else - result = Grad_par(f, loc); + result = Grad_par(f, loc); - if (nonlinear) { - result -= bracket(Psi, f, bm_mag) * B0; + if (nonlinear) { + result -= bracket(Psi, f, bm_mag) * B0; - if (include_rmp) { - result -= bracket(rmp_Psi, f, bm_mag) * B0; + if (include_rmp) { + result -= bracket(rmp_Psi, f, bm_mag) * B0; + } } - } - - return result; -} -bool first_run = true; // For printing out some diagnostics first time around + return result; + } -int physics_run(BoutReal t) { - // Perform communications - mesh->communicate(comms); + bool first_run = true; // For printing out some diagnostics first time around - Coordinates* metric = mesh->getCoordinates(); + int rhs(BoutReal t) override { + // Perform communications + mesh->communicate(comms); - //////////////////////////////////////////// - // Transitions from 0 in core to 1 in vacuum - if (nonlinear) { - vac_mask = (1.0 - tanh(((P0 + P) - vacuum_pressure) / vacuum_trans)) / 2.0; + Coordinates* metric = mesh->getCoordinates(); - // Update resistivity - if (spitzer_resist) { - // Use Spitzer formula - Field3D Te; - Te = (P0 + P) * Bbar * Bbar / (4. * MU0) / (density * 1.602e-19); // eV - eta = 0.51 * 1.03e-4 * Zeff * 20. * pow(Te, -1.5); // eta in Ohm-m. ln(Lambda) = 20 - eta /= MU0 * Va * Lbar; // Normalised eta - } else { - // Use specified core and vacuum Lundquist numbers - eta = core_resist + (vac_resist - core_resist) * vac_mask; + //////////////////////////////////////////// + // Transitions from 0 in core to 1 in vacuum + if (nonlinear) { + vac_mask = (1.0 - tanh(((P0 + P) - vacuum_pressure) / vacuum_trans)) / 2.0; + + // Update resistivity + if (spitzer_resist) { + // Use Spitzer formula + Field3D Te; + Te = (P0 + P) * Bbar * Bbar / (4. * MU0) / (density * 1.602e-19); // eV + eta = + 0.51 * 1.03e-4 * Zeff * 20. * pow(Te, -1.5); // eta in Ohm-m. ln(Lambda) = 20 + eta /= MU0 * Va * Lbar; // Normalised eta + } else { + // Use specified core and vacuum Lundquist numbers + eta = core_resist + (vac_resist - core_resist) * vac_mask; + } } - } - //////////////////////////////////////////// - // Resonant Magnetic Perturbation code + //////////////////////////////////////////// + // Resonant Magnetic Perturbation code - if (include_rmp) { + if (include_rmp) { - if ((rmp_ramp > 0.0) || (rmp_freq > 0.0) || (rmp_rotate != 0.0)) { - // Need to update the RMP terms + if ((rmp_ramp > 0.0) || (rmp_freq > 0.0) || (rmp_rotate != 0.0)) { + // Need to update the RMP terms - if ((rmp_ramp > 0.0) && (t < rmp_ramp)) { - // Still in ramp phase + if ((rmp_ramp > 0.0) && (t < rmp_ramp)) { + // Still in ramp phase - rmp_Psi = (t / rmp_ramp) * rmp_Psi0; // Linear ramp + rmp_Psi = (t / rmp_ramp) * rmp_Psi0; // Linear ramp - rmp_dApdt = rmp_Psi0 / rmp_ramp; - } else { - rmp_Psi = rmp_Psi0; - rmp_dApdt = 0.0; - } + rmp_dApdt = rmp_Psi0 / rmp_ramp; + } else { + rmp_Psi = rmp_Psi0; + rmp_dApdt = 0.0; + } - if (rmp_freq > 0.0) { - // Oscillating the amplitude + if (rmp_freq > 0.0) { + // Oscillating the amplitude - rmp_dApdt = rmp_dApdt * sin(2. * PI * rmp_freq * t) - + rmp_Psi * (2. * PI * rmp_freq) * cos(2. * PI * rmp_freq * t); + rmp_dApdt = rmp_dApdt * sin(2. * PI * rmp_freq * t) + + rmp_Psi * (2. * PI * rmp_freq) * cos(2. * PI * rmp_freq * t); - rmp_Psi *= sin(2. * PI * rmp_freq * t); - } + rmp_Psi *= sin(2. * PI * rmp_freq * t); + } - if (rmp_rotate != 0.0) { - // Rotate toroidally at given frequency + if (rmp_rotate != 0.0) { + // Rotate toroidally at given frequency - shiftZ(rmp_Psi, 2 * PI * rmp_rotate * t); - shiftZ(rmp_dApdt, 2 * PI * rmp_rotate * t); + shiftZ(rmp_Psi, 2 * PI * rmp_rotate * t); + shiftZ(rmp_dApdt, 2 * PI * rmp_rotate * t); - // Add toroidal rotation term. CHECK SIGN + // Add toroidal rotation term. CHECK SIGN - rmp_dApdt += DDZ(rmp_Psi) * 2 * PI * rmp_rotate; + rmp_dApdt += DDZ(rmp_Psi) * 2 * PI * rmp_rotate; + } + + // Set to zero in the core + if (rmp_vac_mask) + rmp_Psi *= vac_mask; + } else { + // Set to zero in the core region + if (rmp_vac_mask) + rmp_Psi = + rmp_Psi0 * vac_mask; // Only in vacuum -> skin current -> diffuses inwards } - // Set to zero in the core - if (rmp_vac_mask) - rmp_Psi *= vac_mask; - } else { - // Set to zero in the core region - if (rmp_vac_mask) - rmp_Psi = - rmp_Psi0 * vac_mask; // Only in vacuum -> skin current -> diffuses inwards + mesh->communicate(rmp_Psi); } - mesh->communicate(rmp_Psi); - } - - //////////////////////////////////////////// - // Inversion + //////////////////////////////////////////// + // Inversion - if (evolve_jpar) { - // Invert laplacian for Psi - Psi = aparSolver->solve(Jpar); - mesh->communicate(Psi); - } + if (evolve_jpar) { + // Invert laplacian for Psi + Psi = aparSolver->solve(Jpar); + mesh->communicate(Psi); + } - if (phi_constraint) { - // Phi being solved as a constraint + if (phi_constraint) { + // Phi being solved as a constraint - Field3D Ctmp = phi; - Ctmp.setBoundary("phi"); // Look up boundary conditions for phi - Ctmp.applyBoundary(); - Ctmp -= phi; // Now contains error in the boundary + Field3D Ctmp = phi; + Ctmp.setBoundary("phi"); // Look up boundary conditions for phi + Ctmp.applyBoundary(); + Ctmp -= phi; // Now contains error in the boundary - C_phi = Delp2(phi) - U; // Error in the bulk - C_phi.setBoundaryTo(Ctmp); + C_phi = Delp2(phi) - U; // Error in the bulk + C_phi.setBoundaryTo(Ctmp); - } else { + } else { - if (constn0) { - phi = phiSolver->solve(U); + if (constn0) { + phi = phiSolver->solve(U); - if (diamag) { - phi -= 0.5 * dnorm * P / B0; - } - } else { - ubyn = U / N0; - if (diamag) { - ubyn -= 0.5 * dnorm / (N0 * B0) * Delp2(P); - mesh->communicate(ubyn); + if (diamag) { + phi -= 0.5 * dnorm * P / B0; + } + } else { + ubyn = U / N0; + if (diamag) { + ubyn -= 0.5 * dnorm / (N0 * B0) * Delp2(P); + mesh->communicate(ubyn); + } + // Invert laplacian for phi + phiSolver->setCoefC(N0); + phi = phiSolver->solve(ubyn); } - // Invert laplacian for phi - phiSolver->setCoefC(N0); - phi = phiSolver->solve(ubyn); + // Apply a boundary condition on phi for target plates + phi.applyBoundary(); + mesh->communicate(phi); } - // Apply a boundary condition on phi for target plates - phi.applyBoundary(); - mesh->communicate(phi); - } - if (!evolve_jpar) { - // Get J from Psi - Jpar = Delp2(Psi); - if (include_rmp) - Jpar += Delp2(rmp_Psi); + if (!evolve_jpar) { + // Get J from Psi + Jpar = Delp2(Psi); + if (include_rmp) + Jpar += Delp2(rmp_Psi); - Jpar.applyBoundary(); - mesh->communicate(Jpar); - - if (jpar_bndry_width > 0) { - // Zero j in boundary regions. Prevents vorticity drive - // at the boundary + Jpar.applyBoundary(); + mesh->communicate(Jpar); - for (int i = 0; i < jpar_bndry_width; i++) - for (int j = 0; j < mesh->LocalNy; j++) - for (int k = 0; k < mesh->LocalNz; k++) { - if (mesh->firstX()) - Jpar(i, j, k) = 0.0; - if (mesh->lastX()) - Jpar(mesh->LocalNx - 1 - i, j, k) = 0.0; - } - } + if (jpar_bndry_width > 0) { + // Zero j in boundary regions. Prevents vorticity drive + // at the boundary + + for (int i = 0; i < jpar_bndry_width; i++) + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + if (mesh->firstX()) + Jpar(i, j, k) = 0.0; + if (mesh->lastX()) + Jpar(mesh->LocalNx - 1 - i, j, k) = 0.0; + } + } - // Smooth j in x - if (smooth_j_x) { - Jpar = smooth_x(Jpar); - Jpar.applyBoundary(); + // Smooth j in x + if (smooth_j_x) { + Jpar = smooth_x(Jpar); + Jpar.applyBoundary(); - // Recommunicate now smoothed - mesh->communicate(Jpar); - } + // Recommunicate now smoothed + mesh->communicate(Jpar); + } - // Get Delp2(J) from J - Jpar2 = Delp2(Jpar); + // Get Delp2(J) from J + Jpar2 = Delp2(Jpar); - Jpar2.applyBoundary(); - mesh->communicate(Jpar2); + Jpar2.applyBoundary(); + mesh->communicate(Jpar2); - if (jpar_bndry_width > 0) { - // Zero jpar2 in boundary regions. Prevents vorticity drive - // at the boundary + if (jpar_bndry_width > 0) { + // Zero jpar2 in boundary regions. Prevents vorticity drive + // at the boundary - for (int i = 0; i < jpar_bndry_width; i++) - for (int j = 0; j < mesh->LocalNy; j++) - for (int k = 0; k < mesh->LocalNz; k++) { - if (mesh->firstX()) - Jpar2(i, j, k) = 0.0; - if (mesh->lastX()) - Jpar2(mesh->LocalNx - 1 - i, j, k) = 0.0; - } + for (int i = 0; i < jpar_bndry_width; i++) + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + if (mesh->firstX()) + Jpar2(i, j, k) = 0.0; + if (mesh->lastX()) + Jpar2(mesh->LocalNx - 1 - i, j, k) = 0.0; + } + } } - } - //////////////////////////////////////////////////// - // Sheath boundary conditions - // Normalised and linearised, since here we have only pressure - // rather than density and temperature. Applying a boundary - // to Jpar so that Jpar = sqrt(mi/me)/(2*pi) * phi - // + //////////////////////////////////////////////////// + // Sheath boundary conditions + // Normalised and linearised, since here we have only pressure + // rather than density and temperature. Applying a boundary + // to Jpar so that Jpar = sqrt(mi/me)/(2*pi) * phi + // - if (sheath_boundaries) { + if (sheath_boundaries) { - // At y = ystart (lower boundary) + // At y = ystart (lower boundary) - for (RangeIterator r = mesh->iterateBndryLowerY(); !r.isDone(); r++) { - for (int jz = 0; jz < mesh->LocalNz; jz++) { + for (RangeIterator r = mesh->iterateBndryLowerY(); !r.isDone(); r++) { + for (int jz = 0; jz < mesh->LocalNz; jz++) { - // Zero-gradient potential - BoutReal phisheath = phi(r.ind, mesh->ystart, jz); + // Zero-gradient potential + BoutReal phisheath = phi(r.ind, mesh->ystart, jz); - BoutReal jsheath = -(sqrt(mi_me) / (2. * sqrt(PI))) * phisheath; + BoutReal jsheath = -(sqrt(mi_me) / (2. * sqrt(PI))) * phisheath; - // Apply boundary condition half-way between cells - for (int jy = mesh->ystart - 1; jy >= 0; jy--) { - // Neumann conditions - P(r.ind, jy, jz) = P(r.ind, mesh->ystart, jz); - phi(r.ind, jy, jz) = phisheath; - // Dirichlet condition on Jpar - Jpar(r.ind, jy, jz) = 2. * jsheath - Jpar(r.ind, mesh->ystart, jz); + // Apply boundary condition half-way between cells + for (int jy = mesh->ystart - 1; jy >= 0; jy--) { + // Neumann conditions + P(r.ind, jy, jz) = P(r.ind, mesh->ystart, jz); + phi(r.ind, jy, jz) = phisheath; + // Dirichlet condition on Jpar + Jpar(r.ind, jy, jz) = 2. * jsheath - Jpar(r.ind, mesh->ystart, jz); + } } } - } - // At y = yend (upper boundary) + // At y = yend (upper boundary) - for (RangeIterator r = mesh->iterateBndryUpperY(); !r.isDone(); r++) { - for (int jz = 0; jz < mesh->LocalNz; jz++) { + for (RangeIterator r = mesh->iterateBndryUpperY(); !r.isDone(); r++) { + for (int jz = 0; jz < mesh->LocalNz; jz++) { - // Zero-gradient potential - BoutReal phisheath = phi(r.ind, mesh->yend, jz); + // Zero-gradient potential + BoutReal phisheath = phi(r.ind, mesh->yend, jz); - BoutReal jsheath = (sqrt(mi_me) / (2. * sqrt(PI))) * phisheath; + BoutReal jsheath = (sqrt(mi_me) / (2. * sqrt(PI))) * phisheath; - // Apply boundary condition half-way between cells - for (int jy = mesh->yend - 1; jy >= 0; jy--) { - // Neumann conditions - P(r.ind, jy, jz) = P(r.ind, mesh->yend, jz); - phi(r.ind, jy, jz) = phisheath; - // Dirichlet condition on Jpar - Jpar(r.ind, jy, jz) = 2. * jsheath - Jpar(r.ind, mesh->yend, jz); + // Apply boundary condition half-way between cells + for (int jy = mesh->yend - 1; jy >= 0; jy--) { + // Neumann conditions + P(r.ind, jy, jz) = P(r.ind, mesh->yend, jz); + phi(r.ind, jy, jz) = phisheath; + // Dirichlet condition on Jpar + Jpar(r.ind, jy, jz) = 2. * jsheath - Jpar(r.ind, mesh->yend, jz); + } } } } - } - //////////////////////////////////////////////////// - // Parallel electric field + //////////////////////////////////////////////////// + // Parallel electric field - if (evolve_jpar) { - // Jpar - Field3D B0U = B0 * U; - mesh->communicate(B0U); - ddt(Jpar) = -Grad_parP(B0U, CELL_YLOW) / B0 + eta * Delp2(Jpar); + if (evolve_jpar) { + // Jpar + Field3D B0U = B0 * U; + mesh->communicate(B0U); + ddt(Jpar) = -Grad_parP(B0U, CELL_YLOW) / B0 + eta * Delp2(Jpar); - if (relax_j_vac) { - // Make ddt(Jpar) relax to zero. + if (relax_j_vac) { + // Make ddt(Jpar) relax to zero. - ddt(Jpar) -= vac_mask * Jpar / relax_j_tconst; - } - } else { - // Vector potential - ddt(Psi) = -Grad_parP(phi, CELL_CENTRE) + eta * Jpar; - - if (eHall) { - ddt(Psi) += 0.25 * delta_i - * (Grad_parP(P, CELL_CENTRE) - + bracket(P0, Psi, bm_mag)); // electron parallel pressure - } + ddt(Jpar) -= vac_mask * Jpar / relax_j_tconst; + } + } else { + // Vector potential + ddt(Psi) = -Grad_parP(phi, CELL_CENTRE) + eta * Jpar; - if (diamag_phi0) - ddt(Psi) -= bracket(phi0, Psi, bm_exb); // Equilibrium flow + if (eHall) { + ddt(Psi) += 0.25 * delta_i + * (Grad_parP(P, CELL_CENTRE) + + bracket(P0, Psi, bm_mag)); // electron parallel pressure + } - if (withflow) // net flow - ddt(Psi) -= V_dot_Grad(V0net, Psi); + if (diamag_phi0) + ddt(Psi) -= bracket(phi0, Psi, bm_exb); // Equilibrium flow - if (diamag_grad_t) { - // grad_par(T_e) correction + if (withflow) // net flow + ddt(Psi) -= V_dot_Grad(V0net, Psi); - ddt(Psi) += 1.71 * dnorm * 0.5 * Grad_parP(P, CELL_YLOW) / B0; - } + if (diamag_grad_t) { + // grad_par(T_e) correction - // Hyper-resistivity - if (hyperresist > 0.0) { - ddt(Psi) -= eta * hyperresist * Delp2(Jpar); - } + ddt(Psi) += 1.71 * dnorm * 0.5 * Grad_parP(P, CELL_YLOW) / B0; + } - // electron Hyper-viscosity coefficient - if (ehyperviscos > 0.0) { - ddt(Psi) -= eta * ehyperviscos * Delp2(Jpar2); - } + // Hyper-resistivity + if (hyperresist > 0.0) { + ddt(Psi) -= eta * hyperresist * Delp2(Jpar); + } - // xqx: parallel hyper-viscous diffusion for vector potential - if (diffusion_a4 > 0.0) { - tmpA2 = Grad2_par2new(Psi); - mesh->communicate(tmpA2); - tmpA2.applyBoundary(); - ddt(Psi) -= diffusion_a4 * Grad2_par2new(tmpA2); - } + // electron Hyper-viscosity coefficient + if (ehyperviscos > 0.0) { + ddt(Psi) -= eta * ehyperviscos * Delp2(Jpar2); + } - // Vacuum solution - if (relax_j_vac) { - // Calculate the J and Psi profile we're aiming for - Field3D Jtarget = Jpar * (1.0 - vac_mask); // Zero in vacuum + // xqx: parallel hyper-viscous diffusion for vector potential + if (diffusion_a4 > 0.0) { + tmpA2 = Grad2_par2new(Psi); + mesh->communicate(tmpA2); + tmpA2.applyBoundary(); + ddt(Psi) -= diffusion_a4 * Grad2_par2new(tmpA2); + } - // Invert laplacian for Psi - Psitarget = aparSolver->solve(Jtarget); + // Vacuum solution + if (relax_j_vac) { + // Calculate the J and Psi profile we're aiming for + Field3D Jtarget = Jpar * (1.0 - vac_mask); // Zero in vacuum - // Add a relaxation term in the vacuum - ddt(Psi) = - ddt(Psi) * (1. - vac_mask) - (Psi - Psitarget) * vac_mask / relax_j_tconst; + // Invert laplacian for Psi + Psitarget = aparSolver->solve(Jtarget); + + // Add a relaxation term in the vacuum + ddt(Psi) = + ddt(Psi) * (1. - vac_mask) - (Psi - Psitarget) * vac_mask / relax_j_tconst; + } } - } - //////////////////////////////////////////////////// - // Vorticity equation + //////////////////////////////////////////////////// + // Vorticity equation - // Grad j term - ddt(U) = SQ(B0) * b0xGrad_dot_Grad(Psi, J0, CELL_CENTRE); - if (include_rmp) { - ddt(U) += SQ(B0) * b0xGrad_dot_Grad(rmp_Psi, J0, CELL_CENTRE); - } + // Grad j term + ddt(U) = SQ(B0) * b0xGrad_dot_Grad(Psi, J0, CELL_CENTRE); + if (include_rmp) { + ddt(U) += SQ(B0) * b0xGrad_dot_Grad(rmp_Psi, J0, CELL_CENTRE); + } - ddt(U) += b0xcv * Grad(P); // curvature term + ddt(U) += b0xcv * Grad(P); // curvature term - if (!nogradparj) { - // Parallel current term - ddt(U) -= SQ(B0) * Grad_parP(Jpar, CELL_CENTRE); // b dot grad j - } + if (!nogradparj) { + // Parallel current term + ddt(U) -= SQ(B0) * Grad_parP(Jpar, CELL_CENTRE); // b dot grad j + } - if (withflow && K_H_term) // K_H_term - ddt(U) -= b0xGrad_dot_Grad(phi, U0); + if (withflow && K_H_term) // K_H_term + ddt(U) -= b0xGrad_dot_Grad(phi, U0); - if (diamag_phi0) - ddt(U) -= b0xGrad_dot_Grad(phi0, U); // Equilibrium flow + if (diamag_phi0) + ddt(U) -= b0xGrad_dot_Grad(phi0, U); // Equilibrium flow - if (withflow) // net flow - ddt(U) -= V_dot_Grad(V0net, U); + if (withflow) // net flow + ddt(U) -= V_dot_Grad(V0net, U); - if (nonlinear) { - ddt(U) -= bracket(phi, U, bm_exb) * B0; // Advection - } + if (nonlinear) { + ddt(U) -= bracket(phi, U, bm_exb) * B0; // Advection + } - // Viscosity terms - if (viscos_par > 0.0) - ddt(U) += viscos_par * Grad2_par2(U); // Parallel viscosity - - // xqx: parallel hyper-viscous diffusion for vorticity - if (diffusion_u4 > 0.0) { - tmpU2 = Grad2_par2new(U); - mesh->communicate(tmpU2); - tmpU2.applyBoundary(); - // tmpU2.applyBoundary("neumann"); - ddt(U) -= diffusion_u4 * Grad2_par2new(tmpU2); - } + // Viscosity terms + if (viscos_par > 0.0) + ddt(U) += viscos_par * Grad2_par2(U); // Parallel viscosity + + // xqx: parallel hyper-viscous diffusion for vorticity + if (diffusion_u4 > 0.0) { + tmpU2 = Grad2_par2new(U); + mesh->communicate(tmpU2); + tmpU2.applyBoundary(); + // tmpU2.applyBoundary("neumann"); + ddt(U) -= diffusion_u4 * Grad2_par2new(tmpU2); + } - if (viscos_perp > 0.0) - ddt(U) += viscos_perp * Delp2(U); // Perpendicular viscosity + if (viscos_perp > 0.0) + ddt(U) += viscos_perp * Delp2(U); // Perpendicular viscosity - // Hyper-viscosity - if (hyperviscos > 0.0) { - // Calculate coefficient. + // Hyper-viscosity + if (hyperviscos > 0.0) { + // Calculate coefficient. - hyper_mu_x = hyperviscos * metric->g_11 * SQ(metric->dx) * abs(metric->g11 * D2DX2(U)) - / (abs(U) + 1e-3); - hyper_mu_x.applyBoundary("dirichlet"); // Set to zero on all boundaries + hyper_mu_x = hyperviscos * metric->g_11 * SQ(metric->dx) + * abs(metric->g11 * D2DX2(U)) / (abs(U) + 1e-3); + hyper_mu_x.applyBoundary("dirichlet"); // Set to zero on all boundaries - ddt(U) += hyper_mu_x * metric->g11 * D2DX2(U); + ddt(U) += hyper_mu_x * metric->g11 * D2DX2(U); - if (first_run) { // Print out maximum values of viscosity used on this processor - output.write(" Hyper-viscosity values:\n"); - output.write(" Max mu_x = %e, Max_DC mu_x = %e\n", max(hyper_mu_x), - max(DC(hyper_mu_x))); + if (first_run) { // Print out maximum values of viscosity used on this processor + output.write(" Hyper-viscosity values:\n"); + output.write(" Max mu_x = %e, Max_DC mu_x = %e\n", max(hyper_mu_x), + max(DC(hyper_mu_x))); + } } - } - if (gyroviscous) { + if (gyroviscous) { - Field3D Pi; - Field2D Pi0; - Pi = 0.5 * P; - Pi0 = 0.5 * P0; + Field3D Pi; + Field2D Pi0; + Pi = 0.5 * P; + Pi0 = 0.5 * P0; - Dperp2Phi0 = Field3D(Delp2(B0 * phi0)); - Dperp2Phi0.applyBoundary(); - mesh->communicate(Dperp2Phi0); + Dperp2Phi0 = Field3D(Delp2(B0 * phi0)); + Dperp2Phi0.applyBoundary(); + mesh->communicate(Dperp2Phi0); - Dperp2Phi = Delp2(B0 * phi); - Dperp2Phi.applyBoundary(); - mesh->communicate(Dperp2Phi); + Dperp2Phi = Delp2(B0 * phi); + Dperp2Phi.applyBoundary(); + mesh->communicate(Dperp2Phi); - Dperp2Pi0 = Field3D(Delp2(Pi0)); - Dperp2Pi0.applyBoundary(); - mesh->communicate(Dperp2Pi0); + Dperp2Pi0 = Field3D(Delp2(Pi0)); + Dperp2Pi0.applyBoundary(); + mesh->communicate(Dperp2Pi0); - Dperp2Pi = Delp2(Pi); - Dperp2Pi.applyBoundary(); - mesh->communicate(Dperp2Pi); + Dperp2Pi = Delp2(Pi); + Dperp2Pi.applyBoundary(); + mesh->communicate(Dperp2Pi); - bracketPhi0P = bracket(B0 * phi0, Pi, bm_exb); - bracketPhi0P.applyBoundary(); - mesh->communicate(bracketPhi0P); + bracketPhi0P = bracket(B0 * phi0, Pi, bm_exb); + bracketPhi0P.applyBoundary(); + mesh->communicate(bracketPhi0P); - bracketPhiP0 = bracket(B0 * phi, Pi0, bm_exb); - bracketPhiP0.applyBoundary(); - mesh->communicate(bracketPhiP0); + bracketPhiP0 = bracket(B0 * phi, Pi0, bm_exb); + bracketPhiP0.applyBoundary(); + mesh->communicate(bracketPhiP0); - ddt(U) -= 0.5 * Upara2 * bracket(Pi, Dperp2Phi0, bm_exb) / B0; - ddt(U) -= 0.5 * Upara2 * bracket(Pi0, Dperp2Phi, bm_exb) / B0; - Field3D B0phi = B0 * phi; - mesh->communicate(B0phi); - Field3D B0phi0 = B0 * phi0; - mesh->communicate(B0phi0); - ddt(U) += 0.5 * Upara2 * bracket(B0phi, Dperp2Pi0, bm_exb) / B0; - ddt(U) += 0.5 * Upara2 * bracket(B0phi0, Dperp2Pi, bm_exb) / B0; - ddt(U) -= 0.5 * Upara2 * Delp2(bracketPhi0P) / B0; - ddt(U) -= 0.5 * Upara2 * Delp2(bracketPhiP0) / B0; - - if (nonlinear) { + ddt(U) -= 0.5 * Upara2 * bracket(Pi, Dperp2Phi0, bm_exb) / B0; + ddt(U) -= 0.5 * Upara2 * bracket(Pi0, Dperp2Phi, bm_exb) / B0; Field3D B0phi = B0 * phi; mesh->communicate(B0phi); - bracketPhiP = bracket(B0phi, Pi, bm_exb); - bracketPhiP.applyBoundary(); - mesh->communicate(bracketPhiP); - - ddt(U) -= 0.5 * Upara2 * bracket(Pi, Dperp2Phi, bm_exb) / B0; - ddt(U) += 0.5 * Upara2 * bracket(B0phi, Dperp2Pi, bm_exb) / B0; - ddt(U) -= 0.5 * Upara2 * Delp2(bracketPhiP) / B0; + Field3D B0phi0 = B0 * phi0; + mesh->communicate(B0phi0); + ddt(U) += 0.5 * Upara2 * bracket(B0phi, Dperp2Pi0, bm_exb) / B0; + ddt(U) += 0.5 * Upara2 * bracket(B0phi0, Dperp2Pi, bm_exb) / B0; + ddt(U) -= 0.5 * Upara2 * Delp2(bracketPhi0P) / B0; + ddt(U) -= 0.5 * Upara2 * Delp2(bracketPhiP0) / B0; + + if (nonlinear) { + Field3D B0phi = B0 * phi; + mesh->communicate(B0phi); + bracketPhiP = bracket(B0phi, Pi, bm_exb); + bracketPhiP.applyBoundary(); + mesh->communicate(bracketPhiP); + + ddt(U) -= 0.5 * Upara2 * bracket(Pi, Dperp2Phi, bm_exb) / B0; + ddt(U) += 0.5 * Upara2 * bracket(B0phi, Dperp2Pi, bm_exb) / B0; + ddt(U) -= 0.5 * Upara2 * Delp2(bracketPhiP) / B0; + } } - } - - // left edge sink terms - if (sink_Ul > 0.0) { - ddt(U) -= sink_Ul * sink_tanhxl(P0, U, su_widthl, su_lengthl); // core sink - } - - // right edge sink terms - if (sink_Ur > 0.0) { - ddt(U) -= sink_Ur * sink_tanhxr(P0, U, su_widthr, su_lengthr); // sol sink - } - //////////////////////////////////////////////////// - // Pressure equation - - ddt(P) = 0.0; - if (evolve_pressure) { - ddt(P) -= b0xGrad_dot_Grad(phi, P0); - - if (diamag_phi0) - ddt(P) -= b0xGrad_dot_Grad(phi0, P); // Equilibrium flow - - if (withflow) // net flow - ddt(P) -= V_dot_Grad(V0net, P); + // left edge sink terms + if (sink_Ul > 0.0) { + ddt(U) -= sink_Ul * sink_tanhxl(P0, U, su_widthl, su_lengthl); // core sink + } - if (nonlinear) - ddt(P) -= bracket(phi, P, bm_exb) * B0; // Advection - } + // right edge sink terms + if (sink_Ur > 0.0) { + ddt(U) -= sink_Ur * sink_tanhxr(P0, U, su_widthr, su_lengthr); // sol sink + } - // Parallel diffusion terms - if (diffusion_par > 0.0) - ddt(P) += diffusion_par * Grad2_par2(P); // Parallel diffusion + //////////////////////////////////////////////////// + // Pressure equation - // xqx: parallel hyper-viscous diffusion for pressure - if (diffusion_p4 > 0.0) { - tmpP2 = Grad2_par2new(P); - mesh->communicate(tmpP2); - tmpP2.applyBoundary(); - ddt(P) = diffusion_p4 * Grad2_par2new(tmpP2); - } + ddt(P) = 0.0; + if (evolve_pressure) { + ddt(P) -= b0xGrad_dot_Grad(phi, P0); - // heating source terms - if (heating_P > 0.0) { - BoutReal pnorm = P0(0, 0); - ddt(P) += heating_P * source_expx2(P0, 2. * hp_width, 0.5 * hp_length) - * (Tbar / pnorm); // heat source - ddt(P) += (100. * source_tanhx(P0, hp_width, hp_length) + 0.01) * metric->g11 - * D2DX2(P) * (Tbar / Lbar / Lbar); // radial diffusion - } + if (diamag_phi0) + ddt(P) -= b0xGrad_dot_Grad(phi0, P); // Equilibrium flow - // sink terms - if (sink_P > 0.0) { - ddt(P) -= sink_P * sink_tanhxr(P0, P, sp_width, sp_length) * Tbar; // sink - } - - //////////////////////////////////////////////////// - // Compressional effects + if (withflow) // net flow + ddt(P) -= V_dot_Grad(V0net, P); - if (compress0) { + if (nonlinear) + ddt(P) -= bracket(phi, P, bm_exb) * B0; // Advection + } - // ddt(P) += beta*( - Grad_parP(Vpar, CELL_CENTRE) + Vpar*gradparB ); - ddt(P) -= beta * Div_par_CtoL(Vpar); + // Parallel diffusion terms + if (diffusion_par > 0.0) + ddt(P) += diffusion_par * Grad2_par2(P); // Parallel diffusion - if (phi_curv) { - ddt(P) -= 2. * beta * b0xcv * Grad(phi); + // xqx: parallel hyper-viscous diffusion for pressure + if (diffusion_p4 > 0.0) { + tmpP2 = Grad2_par2new(P); + mesh->communicate(tmpP2); + tmpP2.applyBoundary(); + ddt(P) = diffusion_p4 * Grad2_par2new(tmpP2); } - // Vpar equation + // heating source terms + if (heating_P > 0.0) { + BoutReal pnorm = P0(0, 0); + ddt(P) += heating_P * source_expx2(P0, 2. * hp_width, 0.5 * hp_length) + * (Tbar / pnorm); // heat source + ddt(P) += (100. * source_tanhx(P0, hp_width, hp_length) + 0.01) * metric->g11 + * D2DX2(P) * (Tbar / Lbar / Lbar); // radial diffusion + } - // ddt(Vpar) = -0.5*Grad_parP(P + P0, CELL_YLOW); - ddt(Vpar) = -0.5 * (Grad_par_LtoC(P) + Grad_par_LtoC(P0)); + // sink terms + if (sink_P > 0.0) { + ddt(P) -= sink_P * sink_tanhxr(P0, P, sp_width, sp_length) * Tbar; // sink + } - if (nonlinear) - ddt(Vpar) -= bracket(phi, Vpar, bm_exb) * B0; // Advection - } + //////////////////////////////////////////////////// + // Compressional effects - if (filter_z) { - // Filter out all except filter_z_mode + if (compress0) { - if (evolve_jpar) { - ddt(Jpar) = filter(ddt(Jpar), filter_z_mode); - } else - ddt(Psi) = filter(ddt(Psi), filter_z_mode); + // ddt(P) += beta*( - Grad_parP(Vpar, CELL_CENTRE) + Vpar*gradparB ); + ddt(P) -= beta * Div_par_CtoL(Vpar); - ddt(U) = filter(ddt(U), filter_z_mode); - ddt(P) = filter(ddt(P), filter_z_mode); - } + if (phi_curv) { + ddt(P) -= 2. * beta * b0xcv * Grad(phi); + } - if (low_pass_z > 0) { - // Low-pass filter, keeping n up to low_pass_z - if (evolve_jpar) { - ddt(Jpar) = lowPass(ddt(Jpar), low_pass_z, zonal_field); - } else - ddt(Psi) = lowPass(ddt(Psi), low_pass_z, zonal_field); + // Vpar equation - ddt(U) = lowPass(ddt(U), low_pass_z, zonal_flow); - ddt(P) = lowPass(ddt(P), low_pass_z, zonal_bkgd); - } + // ddt(Vpar) = -0.5*Grad_parP(P + P0, CELL_YLOW); + ddt(Vpar) = -0.5 * (Grad_par_LtoC(P) + Grad_par_LtoC(P0)); - if (damp_width > 0) { - for (int i = 0; i < damp_width; i++) { - for (int j = 0; j < mesh->LocalNy; j++) - for (int k = 0; k < mesh->LocalNz; k++) { - if (mesh->firstX()) - ddt(U)(i, j, k) -= U(i, j, k) / damp_t_const; - if (mesh->lastX()) - ddt(U)(mesh->LocalNx - 1 - i, j, k) -= - U(mesh->LocalNx - 1 - i, j, k) / damp_t_const; - } + if (nonlinear) + ddt(Vpar) -= bracket(phi, Vpar, bm_exb) * B0; // Advection } - } - first_run = false; + if (filter_z) { + // Filter out all except filter_z_mode - return 0; -} + if (evolve_jpar) { + ddt(Jpar) = filter(ddt(Jpar), filter_z_mode); + } else + ddt(Psi) = filter(ddt(Psi), filter_z_mode); -/******************************************************************************* - * Preconditioner - * - * o System state in variables (as in rhs function) - * o Values to be inverted in time derivatives - * - * o Return values should be in time derivatives - * - * enable by setting solver / use_precon = true in BOUT.inp - *******************************************************************************/ + ddt(U) = filter(ddt(U), filter_z_mode); + ddt(P) = filter(ddt(P), filter_z_mode); + } -int precon(BoutReal UNUSED(t), BoutReal gamma, BoutReal UNUSED(delta)) { - // First matrix, applying L - mesh->communicate(ddt(Psi)); - Field3D Jrhs = Delp2(ddt(Psi)); - Jrhs.applyBoundary("neumann"); + if (low_pass_z > 0) { + // Low-pass filter, keeping n up to low_pass_z + if (evolve_jpar) { + ddt(Jpar) = lowPass(ddt(Jpar), low_pass_z, zonal_field); + } else + ddt(Psi) = lowPass(ddt(Psi), low_pass_z, zonal_field); - if (jpar_bndry_width > 0) { - // Boundary in jpar - if (mesh->firstX()) { - for (int i = jpar_bndry_width; i >= 0; i--) - for (int j = 0; j < mesh->LocalNy; j++) - for (int k = 0; k < mesh->LocalNz; k++) { - Jrhs(i, j, k) = 0.5 * Jrhs(i + 1, j, k); - } + ddt(U) = lowPass(ddt(U), low_pass_z, zonal_flow); + ddt(P) = lowPass(ddt(P), low_pass_z, zonal_bkgd); } - if (mesh->lastX()) { - for (int i = mesh->LocalNx - jpar_bndry_width - 1; i < mesh->LocalNx; i++) + + if (damp_width > 0) { + for (int i = 0; i < damp_width; i++) { for (int j = 0; j < mesh->LocalNy; j++) for (int k = 0; k < mesh->LocalNz; k++) { - Jrhs(i, j, k) = 0.5 * Jrhs(i - 1, j, k); + if (mesh->firstX()) + ddt(U)(i, j, k) -= U(i, j, k) / damp_t_const; + if (mesh->lastX()) + ddt(U)(mesh->LocalNx - 1 - i, j, k) -= + U(mesh->LocalNx - 1 - i, j, k) / damp_t_const; } + } } + + first_run = false; + + return 0; } - mesh->communicate(Jrhs, ddt(P)); + /******************************************************************************* + * Preconditioner + * + * o System state in variables (as in rhs function) + * o Values to be inverted in time derivatives + * + * o Return values should be in time derivatives + * + * enable by setting solver / use_precon = true in BOUT.inp + *******************************************************************************/ + + int precon(BoutReal UNUSED(t), BoutReal gamma, BoutReal UNUSED(delta)) { + // First matrix, applying L + mesh->communicate(ddt(Psi)); + Field3D Jrhs = Delp2(ddt(Psi)); + Jrhs.applyBoundary("neumann"); - Field3D U1 = ddt(U); - U1 += (gamma * B0 * B0) * Grad_par(Jrhs, CELL_CENTRE) + (gamma * b0xcv) * Grad(P); + if (jpar_bndry_width > 0) { + // Boundary in jpar + if (mesh->firstX()) { + for (int i = jpar_bndry_width; i >= 0; i--) + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + Jrhs(i, j, k) = 0.5 * Jrhs(i + 1, j, k); + } + } + if (mesh->lastX()) { + for (int i = mesh->LocalNx - jpar_bndry_width - 1; i < mesh->LocalNx; i++) + for (int j = 0; j < mesh->LocalNy; j++) + for (int k = 0; k < mesh->LocalNz; k++) { + Jrhs(i, j, k) = 0.5 * Jrhs(i - 1, j, k); + } + } + } - // Second matrix, solving Alfven wave dynamics - static InvertPar* invU = 0; - if (!invU) - invU = InvertPar::Create(); + mesh->communicate(Jrhs, ddt(P)); - invU->setCoefA(1.); - invU->setCoefB(-SQ(gamma) * B0 * B0); - ddt(U) = invU->solve(U1); - ddt(U).applyBoundary(); + Field3D U1 = ddt(U); + U1 += (gamma * B0 * B0) * Grad_par(Jrhs, CELL_CENTRE) + (gamma * b0xcv) * Grad(P); - // Third matrix, applying U - Field3D phi3 = phiSolver->solve(ddt(U)); - mesh->communicate(phi3); - phi3.applyBoundary("neumann"); - Field3D B0phi3 = B0 * phi3; - mesh->communicate(B0phi3); - ddt(Psi) = ddt(Psi) - gamma * Grad_par(B0phi3) / B0; - ddt(Psi).applyBoundary(); + // Second matrix, solving Alfven wave dynamics + static InvertPar* invU = 0; + if (!invU) + invU = InvertPar::Create(); - return 0; -} + invU->setCoefA(1.); + invU->setCoefB(-SQ(gamma) * B0 * B0); + ddt(U) = invU->solve(U1); + ddt(U).applyBoundary(); -/******************************************************************************* - * Jacobian-vector multiply - * - * Input - * System state is in (P, Psi, U) - * Vector v is in (F_P, F_Psi, F_U) - * Output - * Jacobian-vector multiplied Jv should be in (P, Psi, U) - * - * NOTE: EXPERIMENTAL - * enable by setting solver / use_jacobian = true in BOUT.inp - *******************************************************************************/ + // Third matrix, applying U + Field3D phi3 = phiSolver->solve(ddt(U)); + mesh->communicate(phi3); + phi3.applyBoundary("neumann"); + Field3D B0phi3 = B0 * phi3; + mesh->communicate(B0phi3); + ddt(Psi) = ddt(Psi) - gamma * Grad_par(B0phi3) / B0; + ddt(Psi).applyBoundary(); -int jacobian(BoutReal UNUSED(t)) { - // NOTE: LINEAR ONLY! + return 0; + } - // Communicate - mesh->communicate(ddt(P), ddt(Psi), ddt(U)); + /******************************************************************************* + * Jacobian-vector multiply + * + * Input + * System state is in (P, Psi, U) + * Vector v is in (F_P, F_Psi, F_U) + * Output + * Jacobian-vector multiplied Jv should be in (P, Psi, U) + * + * NOTE: EXPERIMENTAL + * enable by setting solver / use_jacobian = true in BOUT.inp + *******************************************************************************/ - phi = phiSolver->solve(ddt(U)); + int jacobian(BoutReal UNUSED(t)) { + // NOTE: LINEAR ONLY! - Jpar = Delp2(ddt(Psi)); + // Communicate + mesh->communicate(ddt(P), ddt(Psi), ddt(U)); - mesh->communicate(phi, Jpar); + phi = phiSolver->solve(ddt(U)); - Field3D JP = -b0xGrad_dot_Grad(phi, P0); - JP.setBoundary("P"); - JP.applyBoundary(); - Field3D B0phi = B0 * phi; - mesh->communicate(B0phi); - Field3D JPsi = -Grad_par(B0phi, CELL_YLOW) / B0; - JPsi.setBoundary("Psi"); - JPsi.applyBoundary(); + Jpar = Delp2(ddt(Psi)); - Field3D JU = b0xcv * Grad(ddt(P)) - SQ(B0) * Grad_par(Jpar, CELL_CENTRE) - + SQ(B0) * b0xGrad_dot_Grad(ddt(Psi), J0, CELL_CENTRE); - JU.setBoundary("U"); - JU.applyBoundary(); + mesh->communicate(phi, Jpar); - // Put result into time-derivatives + Field3D JP = -b0xGrad_dot_Grad(phi, P0); + JP.setBoundary("P"); + JP.applyBoundary(); + Field3D B0phi = B0 * phi; + mesh->communicate(B0phi); + Field3D JPsi = -Grad_par(B0phi, CELL_YLOW) / B0; + JPsi.setBoundary("Psi"); + JPsi.applyBoundary(); - ddt(P) = JP; - ddt(Psi) = JPsi; - ddt(U) = JU; + Field3D JU = b0xcv * Grad(ddt(P)) - SQ(B0) * Grad_par(Jpar, CELL_CENTRE) + + SQ(B0) * b0xGrad_dot_Grad(ddt(Psi), J0, CELL_CENTRE); + JU.setBoundary("U"); + JU.applyBoundary(); - return 0; -} + // Put result into time-derivatives -/******************************************************************************* - * Preconditioner for when phi solved as a constraint - * Currently only possible with the IDA solver - * - * o System state in variables (as in rhs function) - * o Values to be inverted in F_vars - * - * o Return values should be in vars (overwriting system state) - *******************************************************************************/ + ddt(P) = JP; + ddt(Psi) = JPsi; + ddt(U) = JU; + + return 0; + } + + /******************************************************************************* + * Preconditioner for when phi solved as a constraint + * Currently only possible with the IDA solver + * + * o System state in variables (as in rhs function) + * o Values to be inverted in F_vars + * + * o Return values should be in vars (overwriting system state) + *******************************************************************************/ + + int precon_phi(BoutReal UNUSED(t), BoutReal UNUSED(cj), BoutReal UNUSED(delta)) { + ddt(phi) = phiSolver->solve(C_phi - ddt(U)); + return 0; + } +}; -int precon_phi(BoutReal UNUSED(t), BoutReal UNUSED(cj), BoutReal UNUSED(delta)) { - ddt(phi) = phiSolver->solve(C_phi - ddt(U)); - return 0; -} +BOUTMAIN(ELMpb); From ed8a8cf1465402a7addcd537fc43feb2b5bbefaa Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 15 Apr 2019 18:12:19 +0100 Subject: [PATCH 1294/1783] getRegion2D method for Field3D Sometimes need to get a 2d region (x- and y-indices) to loop over a Field3D. Used in FFT-based routines. Could get from the field's mesh, but we prefer the interface 'f.getRegion2D()' to 'f.getMesh()->getRegion2D()'. --- include/field3d.hxx | 5 +++++ src/field/field3d.cxx | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/include/field3d.hxx b/include/field3d.hxx index 3a88f948d9..9b0b8fd993 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -316,6 +316,11 @@ class Field3D : public Field, public FieldData { /// const Region& getRegion(REGION region) const; const Region& getRegion(const std::string ®ion_name) const; + + /// Return a Region reference to use to iterate over the x- and + /// y-indices of this field + const Region& getRegion2D(REGION region) const; + const Region& getRegion2D(const std::string ®ion_name) const; Region::RegionIndices::const_iterator begin() const {return std::begin(getRegion("RGN_ALL"));}; Region::RegionIndices::const_iterator end() const {return std::end(getRegion("RGN_ALL"));}; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 495c077174..2456920ff6 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -232,6 +232,13 @@ const Region &Field3D::getRegion(const std::string ®ion_name) const { return fieldmesh->getRegion3D(region_name); }; +const Region &Field3D::getRegion2D(REGION region) const { + return fieldmesh->getRegion2D(toString(region)); +}; +const Region &Field3D::getRegion2D(const std::string ®ion_name) const { + return fieldmesh->getRegion2D(region_name); +}; + /*************************************************************** * OPERATORS ***************************************************************/ From 1504cb920db2edf00d9737e7075699ed255e9200 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 15 Apr 2019 18:16:11 +0100 Subject: [PATCH 1295/1783] Fix slowdown in bracket() functions In a couple of places 'result.getRegion()' was used, returning a 3d region where a 2d region was needed. Gave correct results, but loop was repeated unnecessarily Nz times, resulting in a significant slow-down. Replace these with 'result.getRegion2D()'. --- src/mesh/difops.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index 187739a67f..e93f3176d3 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -820,7 +820,7 @@ const Field3D bracket(const Field3D &f, const Field2D &g, BRACKET_METHOD method, const BoutReal fac = 1.0 / (12 * metric->dz); const int ncz = mesh->LocalNz; - BOUT_FOR(j2D, result.getRegion("RGN_NOBNDRY")) { + BOUT_FOR(j2D, result.getRegion2D("RGN_NOBNDRY")) { // Get constants for this iteration const BoutReal spacingFactor = fac / metric->dx[j2D]; const int jy = j2D.y(), jx = j2D.x(); @@ -1103,7 +1103,7 @@ const Field3D bracket(const Field3D &f, const Field3D &g, BRACKET_METHOD method, Field3D f_temp = f; Field3D g_temp = g; - BOUT_FOR(j2D, result.getRegion("RGN_NOBNDRY")) { + BOUT_FOR(j2D, result.getRegion2D("RGN_NOBNDRY")) { const BoutReal spacingFactor = partialFactor / metric->dx[j2D]; const int jy = j2D.y(), jx = j2D.x(); const int xm = jx - 1, xp = jx + 1; From 9bc42d4128fc9db43492a20264ed4c801e03baa6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 15 Apr 2019 18:26:48 +0100 Subject: [PATCH 1296/1783] Use Field3D::getRegion2D() where it makes sense to --- src/field/field3d.cxx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 2456920ff6..ddeecdb135 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -807,9 +807,7 @@ Field3D filter(const Field3D &var, int N0, REGION rgn) { checkData(var); - Mesh *localmesh = var.getMesh(); - - int ncz = localmesh->LocalNz; + int ncz = var.getNz(); Field3D result{emptyFrom(var)}; @@ -819,7 +817,7 @@ Field3D filter(const Field3D &var, int N0, REGION rgn) { ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" || region_str == "RGN_NOX" || region_str == "RGN_NOY"); - const Region ®ion = localmesh->getRegion2D(region_str); + const Region ®ion = var.getRegion2D(region_str); BOUT_OMP(parallel) { @@ -854,8 +852,7 @@ Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn) { TRACE("lowPass(Field3D, %d, %d)", zmax, keep_zonal); checkData(var); - Mesh *localmesh = var.getMesh(); - int ncz = localmesh->LocalNz; + int ncz = var.getNz(); if (((zmax >= ncz / 2) || (zmax < 0)) && keep_zonal) { // Removing nothing @@ -870,7 +867,7 @@ Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn) { ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" || region_str == "RGN_NOX" || region_str == "RGN_NOY"); - const Region ®ion = localmesh->getRegion2D(region_str); + const Region ®ion = var.getRegion2D(region_str); BOUT_OMP(parallel) { Array f(ncz / 2 + 1); @@ -931,7 +928,7 @@ void shiftZ(Field3D &var, double zangle, REGION rgn) { ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" || region_str == "RGN_NOX" || region_str == "RGN_NOY"); - const Region ®ion = var.getMesh()->getRegion2D(region_str); + const Region ®ion = var.getRegion2D(region_str); // Could be OpenMP if shiftZ(Field3D, int, int, double) didn't throw BOUT_FOR_SERIAL(i, region) { From 09bef9924efaae0d4ff52ffaa25bb69763d31f0a Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 15 Apr 2019 23:39:54 +0100 Subject: [PATCH 1297/1783] Adding docstring to some options Moving comments into strings, so they are written to BOUT.settings. --- examples/elm-pb/elm_pb.cxx | 72 +++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index f9104bc0fe..e83d52029b 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -337,8 +337,8 @@ class ELMpb : public PhysicsModel { // Prints out what values are assigned ///////////////////////////////////////////////////////////// - auto globalOptions = Options::root(); - auto options = globalOptions["highbeta"]; + auto& globalOptions = Options::root(); + auto& options = globalOptions["highbeta"]; constn0 = options["constn0"].withDefault(true); // use the hyperbolic profile of n0. If both n0_fake_prof and @@ -358,12 +358,14 @@ class ELMpb : public PhysicsModel { // the amplitude of constant temperature, in percentage Tconst = options["Tconst"].withDefault(-1.0); - density = options["density"].withDefault(1.0e19); // Number density [m^-3] + density = options["density"].doc("Number density [m^-3]").withDefault(1.0e19); - // If true, evolve J raher than Psi - evolve_jpar = options["evolve_jpar"].withDefault(false); - // Use solver constraint for phi - phi_constraint = options["phi_constraint"].withDefault(false); + evolve_jpar = options["evolve_jpar"] + .doc("If true, evolve J raher than Psi") + .withDefault(false); + phi_constraint = options["phi_constraint"] + .doc("Use solver constraint for phi?") + .withDefault(false); // Effects to include/exclude include_curvature = options["include_curvature"].withDefault(true); @@ -373,7 +375,7 @@ class ELMpb : public PhysicsModel { compress0 = options["compress0"].withDefault(false); gyroviscous = options["gyroviscous"].withDefault(false); - nonlinear = options["nonlinear"].withDefault(false); + nonlinear = options["nonlinear"].doc("Include nonlinear terms?").withDefault(false); // option for ExB Poisson Bracket bm_exb_flag = options["bm_exb_flag"].withDefault(0); @@ -402,9 +404,8 @@ class ELMpb : public PhysicsModel { output << "ERROR: Invalid choice of bracket method. Must be 0 - 3\n"; return 1; } - - // option for magnetic flutter Poisson Bracket - bm_mag_flag = options["bm_mag_flag"].withDefault(0); + + bm_mag_flag = options["bm_mag_flag"].doc("magnetic flutter Poisson Bracket").withDefault(0); switch (bm_mag_flag) { case 0: { bm_mag = BRACKET_STD; @@ -431,18 +432,19 @@ class ELMpb : public PhysicsModel { return 1; } - // electron Hall or electron parallel pressue gradient effects? - eHall = options["eHall"].withDefault(false); - AA = options["AA"].withDefault(1.0); // ion mass in units of proton mass - - // Diamagnetic effects? - diamag = options["diamag"].withDefault(false); - // Grad_par(Te) term in Psi equation - diamag_grad_t = options["diamag_grad_t"].withDefault(diamag); - // Include equilibrium phi0 - diamag_phi0 = options["diamag_phi0"].withDefault(diamag); - // Scale diamagnetic effects by this factor - dia_fact = options["dia_fact"].withDefault(1.0); + eHall = options["eHall"] + .doc("electron Hall or electron parallel pressue gradient effects?") + .withDefault(false); + AA = options["AA"].doc("ion mass in units of proton mass").withDefault(1.0); + + diamag = options["diamag"].doc("Diamagnetic effects?").withDefault(false); + diamag_grad_t = options["diamag_grad_t"] + .doc("Grad_par(Te) term in Psi equation") + .withDefault(diamag); + diamag_phi0 = options["diamag_phi0"].doc("Include equilibrium phi0").withDefault(diamag); + dia_fact = options["dia_fact"] + .doc("Scale diamagnetic effects by this factor") + .withDefault(1.0); // withflow or not withflow = options["withflow"].withDefault(false); @@ -468,15 +470,15 @@ class ELMpb : public PhysicsModel { relax_j_tconst = options["relax_j_tconst"].withDefault(0.1); // Toroidal filtering - filter_z = options["filter_z"].withDefault(false); // Filter a single n + filter_z = options["filter_z"].doc("Filter a single toroidal mode number?").withDefault(false); filter_z_mode = options["filter_z_mode"].withDefault(1); - low_pass_z = options["low_pass_z"].withDefault(false); // Low-pass filter + low_pass_z = options["low_pass_z"].doc("Low-pass filter").withDefault(false); zonal_flow = options["zonal_flow"].withDefault(false); // zonal flow filter zonal_field = options["zonal_field"].withDefault(false); // zonal field filter zonal_bkgd = options["zonal_bkgd"].withDefault(false); // zonal background P filter // Radial smoothing - smooth_j_x = options["smooth_j_x"].withDefault(false); // Smooth Jpar in x + smooth_j_x = options["smooth_j_x"].doc("Smooth Jpar in x").withDefault(false); // Jpar boundary region jpar_bndry_width = options["jpar_bndry_width"].withDefault(-1); @@ -489,7 +491,7 @@ class ELMpb : public PhysicsModel { // RMP-related options include_rmp = options["include_rmp"].withDefault(false); // Read RMP data from grid - simple_rmp = options["simple_rmp"].withDefault(false); // Include a simple RMP model + simple_rmp = options["simple_rmp"].doc("Include a simple RMP model?").withDefault(false); rmp_factor = options["rmp_factor"].withDefault(1.0); rmp_ramp = options["rmp_ramp"].withDefault(-1.0); rmp_freq = options["rmp_freq"].withDefault(-1.0); @@ -502,12 +504,11 @@ class ELMpb : public PhysicsModel { vacuum_trans = options["vacuum_trans"].withDefault(0.005); // Resistivity and hyper-resistivity options - vac_lund = options["vac_lund"].withDefault(0.0); // Lundquist number in vacuum region - core_lund = options["core_lund"].withDefault(0.0); // Lundquist number in core region + vac_lund = options["vac_lund"].doc("Lundquist number in vacuum region").withDefault(0.0); + core_lund = options["core_lund"].doc("Lundquist number in core region").withDefault(0.0); hyperresist = options["hyperresist"].withDefault(-1.0); ehyperviscos = options["ehyperviscos"].withDefault(-1.0); - // Use Spitzer resistivity - spitzer_resist = options["spitzer_resist"].withDefault(false); + spitzer_resist = options["spitzer_resist"].doc("Use Spitzer resistivity?").withDefault(false); Zeff = options["Zeff"].withDefault(2.0); // Z effective // Inner boundary damping @@ -515,11 +516,10 @@ class ELMpb : public PhysicsModel { damp_t_const = options["damp_t_const"].withDefault(0.1); // Viscosity and hyper-viscosity - viscos_par = options["viscos_par"].withDefault(-1.0); // Parallel viscosity - viscos_perp = options["viscos_perp"].withDefault(-1.0); // Perpendicular viscosity - hyperviscos = options["hyperviscos"].withDefault(-1.0); // Radial hyperviscosity - - // parallel pressure diffusion + viscos_par = options["viscos_par"].doc("Parallel viscosity").withDefault(-1.0); + viscos_perp = options["viscos_perp"].doc("Perpendicular viscosity").withDefault(-1.0); + hyperviscos = options["hyperviscos"].doc("Radial hyperviscosity").withDefault(-1.0); + // Parallel pressure diffusion diffusion_par = options["diffusion_par"].withDefault(-1.0); // xqx: parallel hyper-viscous diffusion for pressure From 7ddee19548dd8dc587d42c2b8e27b382e96f3306 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Mon, 15 Apr 2019 23:43:26 +0100 Subject: [PATCH 1298/1783] Fix elm-pb data/BOUT.inp Now runs again, though don't know if the result is correct. --- examples/elm-pb/data/BOUT.inp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/elm-pb/data/BOUT.inp b/examples/elm-pb/data/BOUT.inp index 23c2bcc3d9..d9d4ede7d4 100644 --- a/examples/elm-pb/data/BOUT.inp +++ b/examples/elm-pb/data/BOUT.inp @@ -9,11 +9,8 @@ TIMESTEP = 1 # time between outputs archive = 20 # Archive restart files after this number of outputs wall_limit = 1.55 # wall time limit (in hours) -ShiftXderivs = true # use shifted radial derivatives? -TwistShift = true # use twist-shift condition? - -MZ = 16 # number of points in z direction (2^n + 1) ZPERIOD = 15 # Fraction of a torus to simulate +MZ = 16 # Number of points in Z grid = "cbm18_dens8.grid_nx68ny64.nc" # Grid file @@ -23,6 +20,7 @@ restart_format = "nc" # Restart file format StaggerGrids = false # Use staggered grids (EXPERIMENTAL) [mesh] + paralleltransform = shifted # Use shifted metric method ################################################## @@ -145,9 +143,9 @@ relax_j_tconst = 1e-2 # Time constant for vacuum relaxation filter_z = true # remove all except one mode filter_z_mode = 1 # Specify which harmonic to keep (1 = fundamental) low_pass_z = 16 # Keep up to and including this harmonic (-1 = keep all) -zonal_flow = 0 # remove this zonal harmonic (-1 = keep zonal harmonic) -zonal_field= 0 # remove this zonal harmonic (-1 = keep zonal harmonic) -zonal_bkgd = -1 # remove this zonal harmonic (-1 = keep zonal harmonic) +zonal_flow = false # keep this zonal harmonic? +zonal_field= false # keep this zonal harmonic? +zonal_bkgd = true # keep this zonal harmonic? ## Jpar smoothing smooth_j_x = true # Filter Jpar in the X direction From e204aa5b062097fc2927020e18ddf98915eb639b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 16 Apr 2019 08:47:17 +0100 Subject: [PATCH 1299/1783] Remove redundant printing of BOUT_LOCALE_PATH Previously was printed to stderr by each MPI process. Is printed to the log along with the other compile-flags anyway. --- src/bout++.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 991be62676..89ba3b0baa 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -206,8 +206,6 @@ void setupGetText() { std::setlocale(LC_NUMERIC, "C"); bindtextdomain(GETTEXT_PACKAGE, BUILDFLAG(BOUT_LOCALE_PATH)); - - fprintf(stderr, "LOCALE_PATH = '%s'\n", BUILDFLAG(BOUT_LOCALE_PATH)); } catch (const std::runtime_error& e) { fprintf(stderr, "WARNING: Could not set locale. Try a different LANG setting\n"); } From 7b1b77ce44277a858fb559a695fff846b87036e2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 16 Apr 2019 16:55:12 +0100 Subject: [PATCH 1300/1783] More helpful error message for GETTEXT initialization exceptions --- src/bout++.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index 89ba3b0baa..c9b59d28e5 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -207,7 +207,9 @@ void setupGetText() { bindtextdomain(GETTEXT_PACKAGE, BUILDFLAG(BOUT_LOCALE_PATH)); } catch (const std::runtime_error& e) { - fprintf(stderr, "WARNING: Could not set locale. Try a different LANG setting\n"); + fprintf(stderr, "WARNING: Could not set locale. Check the LANG environment variable " + "(get available values by running 'locale -a'). If LANG is correct, there may be " + "a problem with the BOUT_LOCALE_PATH that BOUT++ was compiled with.\n"); } #endif // BOUT_HAS_GETTEXT } From feed26dda13271eb0114dedff58e3d6d4e894e53 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 16 Apr 2019 18:06:33 +0100 Subject: [PATCH 1301/1783] Include value of BOUT_LOCALE_PATH in warning message. --- src/bout++.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bout++.cxx b/src/bout++.cxx index c9b59d28e5..e1c360bd36 100644 --- a/src/bout++.cxx +++ b/src/bout++.cxx @@ -209,7 +209,8 @@ void setupGetText() { } catch (const std::runtime_error& e) { fprintf(stderr, "WARNING: Could not set locale. Check the LANG environment variable " "(get available values by running 'locale -a'). If LANG is correct, there may be " - "a problem with the BOUT_LOCALE_PATH that BOUT++ was compiled with.\n"); + "a problem with the BOUT_LOCALE_PATH=%s that BOUT++ was compiled with.\n", + BUILDFLAG(BOUT_LOCALE_PATH)); } #endif // BOUT_HAS_GETTEXT } From 0342750f85a470c30478a076602ef4c207f69bd6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 16 Apr 2019 21:14:29 +0100 Subject: [PATCH 1302/1783] Use asynchronous communications in LaplaceMultigrid May allow overlapping of sends and receives. --- .../laplace/impls/multigrid/multigrid_alg.cxx | 70 +++++++++++++------ 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx index 1c1d94315e..ebdc0a0601 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx @@ -612,34 +612,51 @@ BOUT_OMP(for collapse(2)) } void MultigridAlg::communications(BoutReal* x, int level) { + // Note: currently z-direction communications and x-direction communications are done + // independently. They should really be done together if zNP>1 and xNP>1 (with a single + // MPI_Waitall after all the MPI_Isend and MPI_Irecv calls, instead of the two + // MPI_Waitalls there are now. As there are never any z-communications at the moment, it + // is not worth implementing for now. MPI_Status status[4]; int stag, rtag; MAYBE_UNUSED(int ierr); if(zNP > 1) { + MPI_Request requests[4]; MPI_Datatype xvector; - // output<<"Start Z-comm"< 1) { - // Send to x+ and recieve from x- + MPI_Request requests[4]; + + // Send to x+ stag = rProcI; + ierr = MPI_Isend(&x[lnx[level]*(lnz[level]+2)], lnz[level]+2, MPI_DOUBLE, xProcP, + stag, commMG, &requests[0]); + ASSERT1(ierr == MPI_SUCCESS); + + // Send to x- + stag = rProcI+xNP; + ierr = MPI_Isend(&x[lnz[level]+2], lnz[level]+2, MPI_DOUBLE, xProcM, stag, commMG, + &requests[1]); + ASSERT1(ierr == MPI_SUCCESS); + + // Receive from x- rtag = xProcM; - ierr = MPI_Sendrecv(&x[lnx[level]*(lnz[level]+2)],lnz[level]+2, - MPI_DOUBLE,xProcP,stag,&x[0],lnz[level]+2,MPI_DOUBLE, - xProcM,rtag,commMG,status); + ierr = MPI_Irecv(&x[0], lnz[level]+2, MPI_DOUBLE, xProcM, rtag, commMG, &requests[2]); ASSERT1(ierr == MPI_SUCCESS); - // Send to x- and recieve from x+ - stag = rProcI+xNP; + // Receive from x+ rtag = xProcP+xNP;; - ierr = MPI_Sendrecv(&x[lnz[level]+2],lnz[level]+2,MPI_DOUBLE,xProcM,stag, - &x[(lnx[level]+1)*(lnz[level]+2)],lnz[level]+2, - MPI_DOUBLE,xProcP,rtag,commMG,status); + ierr = MPI_Irecv(&x[(lnx[level]+1)*(lnz[level]+2)], lnz[level]+2, MPI_DOUBLE, xProcP, + rtag, commMG, &requests[3]); + ASSERT1(ierr == MPI_SUCCESS); + + // Wait for communications to complete + ierr = MPI_Waitall(4, requests, status); ASSERT1(ierr == MPI_SUCCESS); } else { for (int i=0;i Date: Wed, 17 Apr 2019 10:48:08 +0100 Subject: [PATCH 1303/1783] LaplaceMultigrid: don't send/receive at x-boundaries Previously LaplaceMultigrid was exchanging guard cells at the x-boundaries as if x is periodic. This is unnecessary and does not affect the results. (I think these cells must be over-written or ignored when boundary conditions are applied /J.Omotani). --- .../laplace/impls/multigrid/multigrid_alg.cxx | 76 ++++++++++--------- .../impls/multigrid/multigrid_laplace.cxx | 3 + 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx index ebdc0a0601..f89b51e684 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx @@ -623,7 +623,7 @@ void MultigridAlg::communications(BoutReal* x, int level) { MAYBE_UNUSED(int ierr); if(zNP > 1) { - MPI_Request requests[4]; + MPI_Request requests[] = {MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL}; MPI_Datatype xvector; // Create datatype to hold z-direction guard cells, which are not continuous in memory @@ -633,17 +633,6 @@ void MultigridAlg::communications(BoutReal* x, int level) { ierr = MPI_Type_commit(&xvector); ASSERT1(ierr == MPI_SUCCESS); - // Send to z+ - stag = rProcI; - ierr = MPI_Isend(&x[2*(lnz[level]+2)-2], 1, xvector, zProcP, stag, commMG, - &requests[0]); - ASSERT1(ierr == MPI_SUCCESS); - - // Send to z- - stag = rProcI+numP; - ierr = MPI_Isend(&x[lnz[level]+3], 1, xvector, zProcM, stag, commMG, &requests[1]); - ASSERT1(ierr == MPI_SUCCESS); - // Receive from z- rtag = zProcM; ierr = MPI_Irecv(&x[lnz[level]+2], 1, xvector, zProcM, rtag, commMG, &requests[2]); @@ -655,6 +644,17 @@ void MultigridAlg::communications(BoutReal* x, int level) { &requests[3]); ASSERT1(ierr == MPI_SUCCESS); + // Send to z+ + stag = rProcI; + ierr = MPI_Isend(&x[2*(lnz[level]+2)-2], 1, xvector, zProcP, stag, commMG, + &requests[0]); + ASSERT1(ierr == MPI_SUCCESS); + + // Send to z- + stag = rProcI+numP; + ierr = MPI_Isend(&x[lnz[level]+3], 1, xvector, zProcM, stag, commMG, &requests[1]); + ASSERT1(ierr == MPI_SUCCESS); + // Wait for communications to complete ierr = MPI_Waitall(4, requests, status); ASSERT1(ierr == MPI_SUCCESS); @@ -668,35 +668,43 @@ void MultigridAlg::communications(BoutReal* x, int level) { } } if (xNP > 1) { - MPI_Request requests[4]; - - // Send to x+ - stag = rProcI; - ierr = MPI_Isend(&x[lnx[level]*(lnz[level]+2)], lnz[level]+2, MPI_DOUBLE, xProcP, - stag, commMG, &requests[0]); - ASSERT1(ierr == MPI_SUCCESS); + // Note: periodic x-direction not handled here - // Send to x- - stag = rProcI+xNP; - ierr = MPI_Isend(&x[lnz[level]+2], lnz[level]+2, MPI_DOUBLE, xProcM, stag, commMG, - &requests[1]); - ASSERT1(ierr == MPI_SUCCESS); + MPI_Request requests[] = {MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL, MPI_REQUEST_NULL}; - // Receive from x- - rtag = xProcM; - ierr = MPI_Irecv(&x[0], lnz[level]+2, MPI_DOUBLE, xProcM, rtag, commMG, &requests[2]); - ASSERT1(ierr == MPI_SUCCESS); + if (xProcI > 0) { + // Receive from x- + rtag = xProcM; + ierr = MPI_Irecv(&x[0], lnz[level]+2, MPI_DOUBLE, xProcM, rtag, commMG, &requests[2]); + ASSERT1(ierr == MPI_SUCCESS); + } - // Receive from x+ - rtag = xProcP+xNP;; - ierr = MPI_Irecv(&x[(lnx[level]+1)*(lnz[level]+2)], lnz[level]+2, MPI_DOUBLE, xProcP, - rtag, commMG, &requests[3]); - ASSERT1(ierr == MPI_SUCCESS); + if (xProcI < xNP - 1) { + // Receive from x+ + rtag = xProcP+xNP;; + ierr = MPI_Irecv(&x[(lnx[level]+1)*(lnz[level]+2)], lnz[level]+2, MPI_DOUBLE, xProcP, + rtag, commMG, &requests[3]); + ASSERT1(ierr == MPI_SUCCESS); + + // Send to x+ + stag = rProcI; + ierr = MPI_Isend(&x[lnx[level]*(lnz[level]+2)], lnz[level]+2, MPI_DOUBLE, xProcP, + stag, commMG, &requests[0]); + ASSERT1(ierr == MPI_SUCCESS); + } + + if (xProcI > 0) { + // Send to x- + stag = rProcI+xNP; + ierr = MPI_Isend(&x[lnz[level]+2], lnz[level]+2, MPI_DOUBLE, xProcM, stag, commMG, + &requests[1]); + ASSERT1(ierr == MPI_SUCCESS); + } // Wait for communications to complete ierr = MPI_Waitall(4, requests, status); ASSERT1(ierr == MPI_SUCCESS); - } else { + } else { for (int i=0;iperiodicX); + A.setLocation(location); C1.setLocation(location); C2.setLocation(location); From 5d62e99e487919c8da6e7bb620d5d3f86a8e10f8 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 17 Apr 2019 11:18:57 +0100 Subject: [PATCH 1304/1783] Remove redundant communications from LaplaceMultigrid Communications were being done at the end of one method, and then repeated at the beginning of the following method. This commit removes the communications at the start of methods, assuming that the inputs have already been communicated. --- .../laplace/impls/multigrid/multigrid_alg.cxx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx index f89b51e684..e2283e02db 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx @@ -73,6 +73,11 @@ MultigridAlg::~MultigridAlg() { void MultigridAlg::getSolution(BoutReal *x,BoutReal *b,int flag) { + // swap ghost cells of initial guess + communications(x, mglevel-1); + // don't think the ghost cells of the rhs are used, so don't need to be communicated + // /JTO 17-4-2019 + if(flag == 0) { //Solve exaclty if(mglevel == 1) pGMRES(x,b,mglevel-1,1); @@ -132,14 +137,12 @@ BOUT_OMP(for) smoothings(level,sol,rhs); } - communications(sol,level); return; } void MultigridAlg::projection(int level,BoutReal *r,BoutReal *pr) { - communications(r,level); BOUT_OMP(parallel default(shared)) { BOUT_OMP(for) @@ -166,7 +169,6 @@ BOUT_OMP(for collapse(2)) void MultigridAlg::prolongation(int level,BoutReal *x,BoutReal *ix) { - communications(x,level); BOUT_OMP(parallel default(shared)) { BOUT_OMP(for) @@ -202,7 +204,6 @@ void MultigridAlg::smoothings(int level, BoutReal *x, BoutReal *b) { dim = mm*(lnx[level]+2); if(mgsm == 0) { Array x0(dim); - communications(x,level); BOUT_OMP(parallel default(shared)) for(int num =0;num < 2;num++) { BOUT_OMP(for) @@ -228,7 +229,6 @@ BOUT_OMP(for collapse(2)) } } else { - communications(x,level); for(int i = 1;i Date: Wed, 17 Apr 2019 22:55:20 +0100 Subject: [PATCH 1305/1783] Some tidying and documentation Changing error printing to throwing exceptions Putting more documentation in options docstrings. --- examples/elm-pb/elm_pb.cxx | 150 ++++++++++++++++++------------------- 1 file changed, 71 insertions(+), 79 deletions(-) diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index e83d52029b..8c136424e5 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -244,10 +244,9 @@ class ELMpb : public PhysicsModel { for (auto i : result) { BoutReal mgx = mesh->GlobalX(i.x()); BoutReal xgrid_num = (Jxsep + 1.) / Grid_NX; - // output.write("mgx = %e xgrid_num = %e\n", mgx); int globaly = mesh->YGLOBAL(i.y()); - // output.write("local y = %i; global y: %i\n", i.y, globaly); + if (mgx > xgrid_num || (globaly <= int(Jysep) - 4) || (globaly > int(Jysep2))) mgx = xgrid_num; BoutReal rlx = mgx - n0_center; @@ -310,12 +309,10 @@ class ELMpb : public PhysicsModel { // Load metrics if (mesh->get(Rxy, "Rxy")) { // m - output_error.write("Error: Cannot read Rxy from grid\n"); - return 1; + throw BoutException("Error: Cannot read Rxy from grid\n"); } if (mesh->get(Bpxy, "Bpxy")) { // T - output_error.write("Error: Cannot read Bpxy from grid\n"); - return 1; + throw BoutException("Error: Cannot read Bpxy from grid\n"); } mesh->get(Btxy, "Btxy"); // T mesh->get(B0, "Bxy"); // T @@ -326,17 +323,6 @@ class ELMpb : public PhysicsModel { mesh->get(Psibndry, "psi_bndry"); // edge flux ////////////////////////////////////////////////////////////// - // Read parameters from the options file - // - // Options.get ( NAME, VARIABLE, DEFAULT VALUE) - // - // or if NAME = "VARIABLE" then just - // - // OPTION(VARIABLE, DEFAULT VALUE) - // - // Prints out what values are assigned - ///////////////////////////////////////////////////////////// - auto& globalOptions = Options::root(); auto& options = globalOptions["highbeta"]; @@ -378,7 +364,9 @@ class ELMpb : public PhysicsModel { nonlinear = options["nonlinear"].doc("Include nonlinear terms?").withDefault(false); // option for ExB Poisson Bracket - bm_exb_flag = options["bm_exb_flag"].withDefault(0); + bm_exb_flag = options["bm_exb_flag"] + .doc("ExB Poisson bracket method. 0=standard;1=simple;2=arakawa") + .withDefault(0); switch (bm_exb_flag) { case 0: { bm_exb = BRACKET_STD; @@ -401,8 +389,7 @@ class ELMpb : public PhysicsModel { break; } default: - output << "ERROR: Invalid choice of bracket method. Must be 0 - 3\n"; - return 1; + throw BoutException("Invalid choice of bracket method. Must be 0 - 3\n"); } bm_mag_flag = options["bm_mag_flag"].doc("magnetic flutter Poisson Bracket").withDefault(0); @@ -428,8 +415,7 @@ class ELMpb : public PhysicsModel { break; } default: - output << "ERROR: Invalid choice of bracket method. Must be 0 - 3\n"; - return 1; + throw BoutException("Invalid choice of bracket method. Must be 0 - 3\n"); } eHall = options["eHall"] @@ -465,17 +451,25 @@ class ELMpb : public PhysicsModel { noshear = options["noshear"].withDefault(false); - relax_j_vac = - options["relax_j_vac"].withDefault(false); // Relax vacuum current to zero - relax_j_tconst = options["relax_j_tconst"].withDefault(0.1); + relax_j_vac = options["relax_j_vac"].doc("Relax vacuum current to zero").withDefault(false); + relax_j_tconst = options["relax_j_tconst"] + .doc("Time constant for relaxation of vacuum current. Alfven " + "(normalised) units") + .withDefault(0.1); // Toroidal filtering filter_z = options["filter_z"].doc("Filter a single toroidal mode number?").withDefault(false); filter_z_mode = options["filter_z_mode"].withDefault(1); low_pass_z = options["low_pass_z"].doc("Low-pass filter").withDefault(false); - zonal_flow = options["zonal_flow"].withDefault(false); // zonal flow filter - zonal_field = options["zonal_field"].withDefault(false); // zonal field filter - zonal_bkgd = options["zonal_bkgd"].withDefault(false); // zonal background P filter + zonal_flow = options["zonal_flow"] + .doc("Keep zonal (n=0) component of potential?") + .withDefault(false); + zonal_field = options["zonal_field"] + .doc("Keep zonal (n=0) component of magnetic potential?") + .withDefault(false); + zonal_bkgd = options["zonal_bkgd"] + .doc("Evolve zonal (n=0) pressure profile?") + .withDefault(false); // Radial smoothing smooth_j_x = options["smooth_j_x"].doc("Smooth Jpar in x").withDefault(false); @@ -489,7 +483,7 @@ class ELMpb : public PhysicsModel { parallel_lr_diff = options["parallel_lr_diff"].withDefault(false); // RMP-related options - include_rmp = options["include_rmp"].withDefault(false); // Read RMP data from grid + include_rmp = options["include_rmp"].doc("Read RMP field rmp_A from grid?").withDefault(false); simple_rmp = options["simple_rmp"].doc("Include a simple RMP model?").withDefault(false); rmp_factor = options["rmp_factor"].withDefault(1.0); @@ -498,10 +492,12 @@ class ELMpb : public PhysicsModel { rmp_rotate = options["rmp_rotate"].withDefault(0.0); // Vacuum region control - // Fraction of peak pressure - vacuum_pressure = options["vacuum_pressure"].withDefault(0.02); - // Transition width in pressure - vacuum_trans = options["vacuum_trans"].withDefault(0.005); + vacuum_pressure = options["vacuum_pressure"] + .doc("Fraction of peak pressure, below which is considered vacuum.") + .withDefault(0.02); + vacuum_trans = options["vacuum_trans"] + .doc("Vacuum boundary transition width, as fraction of peak pressure.") + .withDefault(0.005); // Resistivity and hyper-resistivity options vac_lund = options["vac_lund"].doc("Lundquist number in vacuum region").withDefault(0.0); @@ -512,22 +508,28 @@ class ELMpb : public PhysicsModel { Zeff = options["Zeff"].withDefault(2.0); // Z effective // Inner boundary damping - damp_width = options["damp_width"].withDefault(0); - damp_t_const = options["damp_t_const"].withDefault(0.1); + damp_width = options["damp_width"] + .doc("Width of the radial damping regions, in grid cells") + .withDefault(0); + damp_t_const = options["damp_t_const"] + .doc("Time constant for damping in radial regions. Normalised time units.") + .withDefault(0.1); // Viscosity and hyper-viscosity viscos_par = options["viscos_par"].doc("Parallel viscosity").withDefault(-1.0); viscos_perp = options["viscos_perp"].doc("Perpendicular viscosity").withDefault(-1.0); hyperviscos = options["hyperviscos"].doc("Radial hyperviscosity").withDefault(-1.0); - // Parallel pressure diffusion - diffusion_par = options["diffusion_par"].withDefault(-1.0); - // xqx: parallel hyper-viscous diffusion for pressure - diffusion_p4 = options["diffusion_p4"].withDefault(-1.0); - // xqx: parallel hyper-viscous diffusion for vorticity - diffusion_u4 = options["diffusion_u4"].withDefault(-1.0); - // xqx: parallel hyper-viscous diffusion for vector potential - diffusion_a4 = options["diffusion_a4"].withDefault(-1.0); + diffusion_par = options["diffusion_par"].doc("Parallel pressure diffusion").withDefault(-1.0); + diffusion_p4 = options["diffusion_p4"] + .doc("parallel hyper-viscous diffusion for pressure") + .withDefault(-1.0); + diffusion_u4 = options["diffusion_u4"] + .doc("parallel hyper-viscous diffusion for vorticity") + .withDefault(-1.0); + diffusion_a4 = options["diffusion_a4"] + .doc("parallel hyper-viscous diffusion for vector potential") + .withDefault(-1.0); // heating factor in pressure // heating power in pressure @@ -570,8 +572,8 @@ class ELMpb : public PhysicsModel { su_lengthr = options["su_lengthr"].withDefault(0.15); // Compressional terms - phi_curv = options["phi_curv"].withDefault(true); - g = options["gamma"].withDefault(5.0 / 3.0); + phi_curv = options["phi_curv"].doc("ExB compression in P equation?").withDefault(true); + g = options["gamma"].doc("Ratio of specific heats").withDefault(5.0 / 3.0); // Field inversion flags phi_flags = options["phi_flags"].withDefault(0); @@ -605,8 +607,8 @@ class ELMpb : public PhysicsModel { output_warn.write(" ***WARNING: need poloidal angle for simple RMP\n"); include_rmp = false; } else { - rmp_n = options["rmp_n"].withDefault(3); - rmp_m = options["rmp_m"].withDefault(9); + rmp_n = options["rmp_n"].doc("Simple RMP toroidal mode number").withDefault(3); + rmp_m = options["rmp_m"].doc("Simple RMP poloidal mode number").withDefault(9); rmp_polwid = options["rmp_polwid"].withDefault(-1.0); rmp_polpeak = options["rmp_polpeak"].withDefault(0.5); rmp_vac_mask = options["rmp_vac_mask"].withDefault(true); @@ -746,58 +748,55 @@ class ELMpb : public PhysicsModel { if (hyperviscos > 0.0) { output.write(" Hyper-viscosity coefficient: %e\n", hyperviscos); - dump.add(hyper_mu_x, "hyper_mu_x", 1); + SAVE_ONCE(hyper_mu_x); } if (diffusion_par > 0.0) { output.write(" diffusion_par: %e\n", diffusion_par); - dump.add(diffusion_par, "diffusion_par", 1); + SAVE_ONCE(diffusion_par); } // xqx: parallel hyper-viscous diffusion for pressure if (diffusion_p4 > 0.0) { output.write(" diffusion_p4: %e\n", diffusion_p4); - dump.add(diffusion_p4, "diffusion_p4", 1); + SAVE_ONCE(diffusion_p4); } // xqx: parallel hyper-viscous diffusion for vorticity if (diffusion_u4 > 0.0) { output.write(" diffusion_u4: %e\n", diffusion_u4); - dump.add(diffusion_u4, "diffusion_u4", 1); + SAVE_ONCE(diffusion_u4) } // xqx: parallel hyper-viscous diffusion for vector potential if (diffusion_a4 > 0.0) { output.write(" diffusion_a4: %e\n", diffusion_a4); - dump.add(diffusion_a4, "diffusion_a4", 1); + SAVE_ONCE(diffusion_a4); } if (heating_P > 0.0) { output.write(" heating_P(watts): %e\n", heating_P); - dump.add(heating_P, "heating_P", 1); output.write(" hp_width(%%): %e\n", hp_width); - dump.add(hp_width, "hp_width", 1); output.write(" hp_length(%%): %e\n", hp_length); - dump.add(hp_length, "hp_length", 1); + + SAVE_ONCE(heating_P, hp_width, hp_length); } if (sink_P > 0.0) { output.write(" sink_P(rate): %e\n", sink_P); - dump.add(sink_P, "sink_P", 1); - output.write(" sp_width(%%): %e\n", sp_width); - dump.add(sp_width, "sp_width", 1); - output.write(" sp_length(%%): %e\n", sp_length); - dump.add(sp_length, "sp_length", 1); + + SAVE_ONCE(sink_P, sp_width, sp_length); } - if (K_H_term) + if (K_H_term) { output.write(" keep K-H term\n"); - else + } else { output.write(" drop K-H term\n"); + } Field2D Te; Te = P0 / (2.0 * density * 1.602e-19); // Temperature in eV @@ -838,18 +837,15 @@ class ELMpb : public PhysicsModel { N0 = P0 / (Ti0 + Te0); } else { if (mesh->get(N0, "Niexp")) { // N_i0 - output_error.write("Error: Cannot read Ni0 from grid\n"); - return 1; + throw BoutException("Error: Cannot read Ni0 from grid\n"); } if (mesh->get(Ti0, "Tiexp")) { // T_i0 - output_error.write("Error: Cannot read Ti0 from grid\n"); - return 1; + throw BoutException("Error: Cannot read Ti0 from grid\n"); } if (mesh->get(Te0, "Teexp")) { // T_e0 - output_error.write("Error: Cannot read Te0 from grid\n"); - return 1; + throw BoutException("Error: Cannot read Te0 from grid\n"); } N0 /= Nbar; Ti0 /= Tibar; @@ -987,11 +983,11 @@ class ELMpb : public PhysicsModel { if (evolve_jpar) { output.write("Solving for jpar: Inverting to get Psi\n"); SOLVE_FOR(Jpar); - dump.add(Psi, "Psi", 1); + SAVE_REPEAT(Psi); } else { output.write("Solving for Psi, Differentiating to get jpar\n"); SOLVE_FOR(Psi); - dump.add(Jpar, "jpar", 1); + SAVE_REPEAT(Jpar); } if (compress0) { @@ -1012,9 +1008,7 @@ class ELMpb : public PhysicsModel { // Implicit Phi solve using IDA if (!solver->constraints()) { - output_error.write( - "ERROR: Cannot constrain. Run again with phi_constraint=false\n"); - throw BoutException("Aborting.\n"); + throw BoutException("Cannot constrain. Run again with phi_constraint=false.\n"); } solver->constraint(phi, C_phi, "phi"); @@ -1024,7 +1018,7 @@ class ELMpb : public PhysicsModel { } else { // Phi solved in RHS (explicitly) - dump.add(phi, "phi", 1); + SAVE_REPEAT(phi); // Set preconditioner setPrecon( (preconfunc) &ELMpb::precon ); @@ -1050,8 +1044,9 @@ class ELMpb : public PhysicsModel { SAVE_ONCE(Va, B0); SAVE_ONCE(Dphi0, U0); SAVE_ONCE(V0); - if (!constn0) + if (!constn0) { SAVE_ONCE(Ti0, Te0, N0); + } // Create a solver for the Laplacian phiSolver = Laplacian::create(); @@ -1063,9 +1058,6 @@ class ELMpb : public PhysicsModel { /////////////// CHECK VACUUM /////////////////////// // In vacuum region, initial vorticity should equal zero - // ubyn.setLocation(CELL_YLOW); - // ubyn.setBoundary("U"); - if (!restarting) { // Only if not restarting: Check initial perturbation @@ -1348,7 +1340,7 @@ class ELMpb : public PhysicsModel { BoutReal jsheath = (sqrt(mi_me) / (2. * sqrt(PI))) * phisheath; // Apply boundary condition half-way between cells - for (int jy = mesh->yend - 1; jy >= 0; jy--) { + for (int jy = mesh->yend + 1; jy < mesh->LocalNy; jy++) { // Neumann conditions P(r.ind, jy, jz) = P(r.ind, mesh->yend, jz); phi(r.ind, jy, jz) = phisheath; From 3f39f8251154979e0d864cdd800a77a9eaba4141 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 17 Apr 2019 23:00:49 +0100 Subject: [PATCH 1306/1783] Rename compress0 to compress This is what is used in the input files, but for some reason was called `compress0` in the code. --- examples/elm-pb/elm_pb.cxx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index 8c136424e5..bc90331310 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -103,7 +103,7 @@ class ELMpb : public PhysicsModel { BoutReal Upara2; // options - bool include_curvature, include_jpar0, compress0; + bool include_curvature, include_jpar0, compress; bool evolve_pressure, gyroviscous; BoutReal vacuum_pressure; @@ -359,7 +359,9 @@ class ELMpb : public PhysicsModel { evolve_pressure = options["evolve_pressure"].withDefault(true); nogradparj = options["nogradparj"].withDefault(false); - compress0 = options["compress0"].withDefault(false); + compress = options["compress"] + .doc("Include compressibility effects (evolve Vpar)?") + .withDefault(false); gyroviscous = options["gyroviscous"].withDefault(false); nonlinear = options["nonlinear"].doc("Include nonlinear terms?").withDefault(false); @@ -990,7 +992,7 @@ class ELMpb : public PhysicsModel { SAVE_REPEAT(Jpar); } - if (compress0) { + if (compress) { output.write("Including compression (Vpar) effects\n"); SOLVE_FOR(Vpar); @@ -1592,7 +1594,7 @@ class ELMpb : public PhysicsModel { //////////////////////////////////////////////////// // Compressional effects - if (compress0) { + if (compress) { // ddt(P) += beta*( - Grad_parP(Vpar, CELL_CENTRE) + Vpar*gradparB ); ddt(P) -= beta * Div_par_CtoL(Vpar); From 445db49fb16f1424b4bd899fba51db219bdafda9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 18 Apr 2019 11:39:52 +0100 Subject: [PATCH 1307/1783] Warn about random failures in test --- .../test-coordinates-initialization/runtest | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/integrated/test-coordinates-initialization/runtest b/tests/integrated/test-coordinates-initialization/runtest index 94b589e2d4..73d3e6eb8c 100755 --- a/tests/integrated/test-coordinates-initialization/runtest +++ b/tests/integrated/test-coordinates-initialization/runtest @@ -1,7 +1,18 @@ #!/bin/bash -set -e +make || exit -make # Kill the test after 3 seconds, if it hasn't already exited OMP_NUM_THREADS=1 mpirun -n 3 timeout 3s ./test-coordinates-initialization + +e=$? + +if test $e -ne 0 +then + echo "The test failed. That can be caused by a timeout." + echo "If this test is run on high load, it may fail occationally." + echo "The load is:" + uptime +fi + +exit $e From e91090dbe901295df58d16d04a720f1ea65ed2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 18 Apr 2019 12:09:23 +0100 Subject: [PATCH 1308/1783] typo --- tests/integrated/test-coordinates-initialization/runtest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integrated/test-coordinates-initialization/runtest b/tests/integrated/test-coordinates-initialization/runtest index 73d3e6eb8c..759f4526f2 100755 --- a/tests/integrated/test-coordinates-initialization/runtest +++ b/tests/integrated/test-coordinates-initialization/runtest @@ -10,7 +10,7 @@ e=$? if test $e -ne 0 then echo "The test failed. That can be caused by a timeout." - echo "If this test is run on high load, it may fail occationally." + echo "If this test is run on high load, it may fail occasionally." echo "The load is:" uptime fi From 9e997cebe80d490cc61999e68b1bdbfb282dbc1b Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 18 Apr 2019 22:51:29 +0100 Subject: [PATCH 1309/1783] Adding LaplaceXY for n=0 component If `split_n0` is `true` then the axisymmetric component of phi is solved separately from the other components. --- examples/elm-pb/elm_pb.cxx | 54 +++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index bc90331310..c1c3622bf9 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -166,6 +167,11 @@ class ELMpb : public PhysicsModel { bool zonal_flow; bool zonal_field; bool zonal_bkgd; + + bool split_n0; // Solve the n=0 component of potential + LaplaceXY *laplacexy; // Laplacian solver in X-Y (n=0) + Field2D phi2D; // Axisymmetric phi + bool relax_j_vac; BoutReal relax_j_tconst; // Time-constant for j relax Field3D Psitarget; // The (moving) target to relax to @@ -473,6 +479,20 @@ class ELMpb : public PhysicsModel { .doc("Evolve zonal (n=0) pressure profile?") .withDefault(false); + // n = 0 electrostatic potential solve + split_n0 = options["split_n0"] + .doc("Solve zonal (n=0) component of potential using LaplaceXY?") + .withDefault(false); + if (split_n0) { + // Create an XY solver for n=0 component + laplacexy = new LaplaceXY(mesh); + // Set coefficients for Boussinesq solve + laplacexy->setCoefs(1.0, 0.0); + phi2D = 0.0; // Starting guess + phi2D.setBoundary("phi"); + } + + // Radial smoothing smooth_j_x = options["smooth_j_x"].doc("Smooth Jpar in x").withDefault(false); @@ -482,7 +502,9 @@ class ELMpb : public PhysicsModel { sheath_boundaries = options["sheath_boundaries"].withDefault(false); // Parallel differencing - parallel_lr_diff = options["parallel_lr_diff"].withDefault(false); + parallel_lr_diff = options["parallel_lr_diff"] + .doc("Use left and right shifted stencils for parallel differences?") + .withDefault(false); // RMP-related options include_rmp = options["include_rmp"].doc("Read RMP field rmp_A from grid?").withDefault(false); @@ -716,7 +738,6 @@ class ELMpb : public PhysicsModel { if (gyroviscous) { omega_i = 9.58e7 * Zeff * Bbar; Upara2 = 0.5 / (Tbar * omega_i); - // Upara3 = 1.0; output.write("Upara2 = %e Omega_i = %e\n", Upara2, omega_i); } @@ -1197,9 +1218,10 @@ class ELMpb : public PhysicsModel { rmp_Psi *= vac_mask; } else { // Set to zero in the core region - if (rmp_vac_mask) - rmp_Psi = - rmp_Psi0 * vac_mask; // Only in vacuum -> skin current -> diffuses inwards + if (rmp_vac_mask) { + // Only in vacuum -> skin current -> diffuses inwards + rmp_Psi = rmp_Psi0 * vac_mask; + } } mesh->communicate(rmp_Psi); @@ -1228,8 +1250,26 @@ class ELMpb : public PhysicsModel { } else { if (constn0) { - phi = phiSolver->solve(U); - + if (split_n0) { + //////////////////////////////////////////// + // Boussinesq, split + // Split into axisymmetric and non-axisymmetric components + Field2D Vort2D = DC(U); // n=0 component + + // Applies boundary condition for "phi". + phi2D.applyBoundary(t); + + // Solve axisymmetric (n=0) part + phi2D = laplacexy->solve(Vort2D, phi2D); + + // Solve non-axisymmetric part + phi = phiSolver->solve(U - Vort2D); + + phi += phi2D; // Add axisymmetric part + } else { + phi = phiSolver->solve(U); + } + if (diamag) { phi -= 0.5 * dnorm * P / B0; } From 67de8093e9e36796704ea5d2651dd77a5fd12a7d Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sun, 21 Apr 2019 08:57:50 +0100 Subject: [PATCH 1310/1783] More minor tidying Some documentation, removed `Grad2_par2new` since it just calls D2DY2. --- examples/elm-pb/elm_pb.cxx | 45 ++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index c1c3622bf9..ee36084d1f 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -245,7 +245,6 @@ class ELMpb : public PhysicsModel { BoutReal Jxsep, Jysep2; mesh->get(Jxsep, "ixseps1"); mesh->get(Jysep2, "jyseps2_2"); - // output.write("Jysep2_2 = %i Ixsep1 = %i\n", int(Jysep2), int(Jxsep)); for (auto i : result) { BoutReal mgx = mesh->GlobalX(i.x()); @@ -278,20 +277,6 @@ class ELMpb : public PhysicsModel { return result; } - /*! - * This function implements d2/dy2 where y is the poloidal coordinate theta - */ - const Field3D Grad2_par2new(const Field3D& f) { - TRACE("Grad2_par2new( Field3D )"); - - Field3D result = D2DY2(f); - -#ifdef TRACK - result.name = "Grad2_par2new(" + f.name + ")"; -#endif - - return result; - } protected: int init(bool restarting) { bool noshear; @@ -466,8 +451,13 @@ class ELMpb : public PhysicsModel { .withDefault(0.1); // Toroidal filtering - filter_z = options["filter_z"].doc("Filter a single toroidal mode number?").withDefault(false); - filter_z_mode = options["filter_z_mode"].withDefault(1); + filter_z = options["filter_z"] + .doc("Filter a single toroidal mode number? The mode to keep is " + "filter_z_mode.") + .withDefault(false); + filter_z_mode = options["filter_z_mode"] + .doc("Single toroidal mode number to keep") + .withDefault(1); low_pass_z = options["low_pass_z"].doc("Low-pass filter").withDefault(false); zonal_flow = options["zonal_flow"] .doc("Keep zonal (n=0) component of potential?") @@ -491,15 +481,18 @@ class ELMpb : public PhysicsModel { phi2D = 0.0; // Starting guess phi2D.setBoundary("phi"); } - // Radial smoothing smooth_j_x = options["smooth_j_x"].doc("Smooth Jpar in x").withDefault(false); // Jpar boundary region - jpar_bndry_width = options["jpar_bndry_width"].withDefault(-1); + jpar_bndry_width = options["jpar_bndry_width"] + .doc("Number of cells near the boundary where jpar = 0") + .withDefault(-1); - sheath_boundaries = options["sheath_boundaries"].withDefault(false); + sheath_boundaries = options["sheath_boundaries"] + .doc("Apply sheath boundaries in Y?") + .withDefault(false); // Parallel differencing parallel_lr_diff = options["parallel_lr_diff"] @@ -1441,10 +1434,10 @@ class ELMpb : public PhysicsModel { // xqx: parallel hyper-viscous diffusion for vector potential if (diffusion_a4 > 0.0) { - tmpA2 = Grad2_par2new(Psi); + tmpA2 = D2DY2(Psi); mesh->communicate(tmpA2); tmpA2.applyBoundary(); - ddt(Psi) -= diffusion_a4 * Grad2_par2new(tmpA2); + ddt(Psi) -= diffusion_a4 * D2DY2(tmpA2); } // Vacuum solution @@ -1496,11 +1489,11 @@ class ELMpb : public PhysicsModel { // xqx: parallel hyper-viscous diffusion for vorticity if (diffusion_u4 > 0.0) { - tmpU2 = Grad2_par2new(U); + tmpU2 = D2DY2(U); mesh->communicate(tmpU2); tmpU2.applyBoundary(); // tmpU2.applyBoundary("neumann"); - ddt(U) -= diffusion_u4 * Grad2_par2new(tmpU2); + ddt(U) -= diffusion_u4 * D2DY2(tmpU2); } if (viscos_perp > 0.0) @@ -1611,10 +1604,10 @@ class ELMpb : public PhysicsModel { // xqx: parallel hyper-viscous diffusion for pressure if (diffusion_p4 > 0.0) { - tmpP2 = Grad2_par2new(P); + tmpP2 = D2DY2(P); mesh->communicate(tmpP2); tmpP2.applyBoundary(); - ddt(P) = diffusion_p4 * Grad2_par2new(tmpP2); + ddt(P) = diffusion_p4 * D2DY2(tmpP2); } // heating source terms From 8a7ba016a5b49eccff4743b04dae7b809861a5db Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 23 Apr 2019 15:56:06 +0100 Subject: [PATCH 1311/1783] Add basic CMake files --- CMakeLists.txt | 316 ++++++++++++++++++++++++++ externalpackages/PVODE/CMakeLists.txt | 45 ++++ tests/unit/CMakeLists.txt | 70 ++++++ 3 files changed, 431 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 externalpackages/PVODE/CMakeLists.txt create mode 100644 tests/unit/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..00ac2c9cd8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,316 @@ +cmake_minimum_required(VERSION 3.1...3.12) + +if(${CMAKE_VERSION} VERSION_LESS 3.11) + cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +else() + cmake_policy(VERSION 3.12) +endif() + +project(BOUT++ + DESCRIPTION "Fluid PDE solver framework" + VERSION 4.2.2 + LANGUAGES CXX) + +find_package(MPI REQUIRED) + +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) + +find_package(NetCDF) +find_package(FFTW) + +add_subdirectory(externalpackages/mpark.variant) +add_subdirectory(externalpackages/PVODE) + +set(BOUT_SOURCES + ./include/boundary_factory.hxx + ./include/boundary_op.hxx + ./include/boundary_region.hxx + ./include/boundary_standard.hxx + ./include/bout.hxx + ./include/bout/array.hxx + ./include/bout/assert.hxx + ./include/bout/constants.hxx + ./include/bout/coordinates.hxx + ./include/bout/deprecated.hxx + ./include/bout/deriv_store.hxx + ./include/bout/expr.hxx + ./include/bout/field_visitor.hxx + ./include/bout/fieldgroup.hxx + ./include/bout/format.hxx + ./include/bout/fv_ops.hxx + ./include/bout/generic_factory.hxx + ./include/bout/globalfield.hxx + ./include/bout/griddata.hxx + ./include/bout/index_derivs.hxx + ./include/bout/index_derivs_interface.hxx + ./include/bout/invert/laplace3d.hxx + ./include/bout/invert/laplacexy.hxx + ./include/bout/invert/laplacexz.hxx + ./include/bout/invertable_operator.hxx + ./include/bout/macro_for_each.hxx + ./include/bout/mesh.hxx + ./include/bout/monitor.hxx + ./include/bout/openmpwrap.hxx + ./include/bout/paralleltransform.hxx + ./include/bout/petsclib.hxx + ./include/bout/physicsmodel.hxx + ./include/bout/region.hxx + ./include/bout/rkscheme.hxx + ./include/bout/rvec.hxx + ./include/bout/scorepwrapper.hxx + ./include/bout/slepclib.hxx + ./include/bout/solver.hxx + ./include/bout/solverfactory.hxx + ./include/bout/surfaceiter.hxx + ./include/bout/sys/expressionparser.hxx + ./include/bout/sys/gettext.hxx + ./include/bout/sys/range.hxx + ./include/bout/sys/timer.hxx + ./include/bout/sys/type_name.hxx + ./include/bout/sys/uncopyable.hxx + ./include/bout/sys/variant.hxx + ./include/bout/template_combinations.hxx + ./include/bout_types.hxx + ./include/boutcomm.hxx + ./include/boutexception.hxx + ./include/boutmain.hxx + ./include/cyclic_reduction.hxx + ./include/datafile.hxx + ./include/dataformat.hxx + ./include/dcomplex.hxx + ./include/derivs.hxx + ./include/difops.hxx + ./include/fft.hxx + ./include/field.hxx + ./include/field2d.hxx + ./include/field3d.hxx + ./include/field_data.hxx + ./include/field_factory.hxx + ./include/fieldperp.hxx + ./include/globals.hxx + ./include/gyro_average.hxx + ./include/initialprofiles.hxx + ./include/interpolation.hxx + ./include/interpolation_factory.hxx + ./include/invert_laplace.hxx + ./include/invert_parderiv.hxx + ./include/lapack_routines.hxx + ./include/mask.hxx + ./include/msg_stack.hxx + ./include/multiostream.hxx + ./include/options.hxx + ./include/options_netcdf.hxx + ./include/optionsreader.hxx + ./include/output.hxx + ./include/parallel_boundary_op.hxx + ./include/parallel_boundary_region.hxx + ./include/smoothing.hxx + ./include/sourcex.hxx + ./include/stencils.hxx + ./include/unused.hxx + ./include/utils.hxx + ./include/vecops.hxx + ./include/vector2d.hxx + ./include/vector3d.hxx + ./include/where.hxx + ./src/bout++.cxx + ./src/field/field.cxx + ./src/field/field2d.cxx + ./src/field/field3d.cxx + ./src/field/field_data.cxx + ./src/field/field_factory.cxx + ./src/field/fieldgenerators.cxx + ./src/field/fieldgenerators.hxx + ./src/field/fieldgroup.cxx + ./src/field/fieldperp.cxx + ./src/field/generated_fieldops.cxx + ./src/field/globalfield.cxx + ./src/field/initialprofiles.cxx + ./src/field/vecops.cxx + ./src/field/vector2d.cxx + ./src/field/vector3d.cxx + ./src/field/where.cxx + ./src/fileio/datafile.cxx + ./src/fileio/dataformat.cxx + ./src/fileio/formatfactory.cxx + ./src/fileio/formatfactory.hxx + ./src/fileio/impls/emptyformat.hxx + ./src/fileio/impls/hdf5/h5_format.cxx + ./src/fileio/impls/hdf5/h5_format.hxx + ./src/fileio/impls/netcdf/nc_format.cxx + ./src/fileio/impls/netcdf/nc_format.hxx + ./src/fileio/impls/netcdf4/ncxx4.cxx + ./src/fileio/impls/netcdf4/ncxx4.hxx + ./src/fileio/impls/pnetcdf/pnetcdf.cxx + ./src/fileio/impls/pnetcdf/pnetcdf.hxx + ./src/invert/fft_fftw.cxx + ./src/invert/lapack_routines.cxx + ./src/invert/laplace/impls/cyclic/cyclic_laplace.cxx + ./src/invert/laplace/impls/cyclic/cyclic_laplace.hxx + ./src/invert/laplace/impls/multigrid/multigrid_alg.cxx + ./src/invert/laplace/impls/multigrid/multigrid_laplace.cxx + ./src/invert/laplace/impls/multigrid/multigrid_laplace.hxx + ./src/invert/laplace/impls/multigrid/multigrid_solver.cxx + ./src/invert/laplace/impls/mumps/mumps_laplace.cxx + ./src/invert/laplace/impls/mumps/mumps_laplace.hxx + ./src/invert/laplace/impls/naulin/naulin_laplace.cxx + ./src/invert/laplace/impls/naulin/naulin_laplace.hxx + ./src/invert/laplace/impls/pdd/pdd.cxx + ./src/invert/laplace/impls/pdd/pdd.hxx + ./src/invert/laplace/impls/petsc/petsc_laplace.cxx + ./src/invert/laplace/impls/petsc/petsc_laplace.hxx + ./src/invert/laplace/impls/serial_band/serial_band.cxx + ./src/invert/laplace/impls/serial_band/serial_band.hxx + ./src/invert/laplace/impls/serial_tri/serial_tri.cxx + ./src/invert/laplace/impls/serial_tri/serial_tri.hxx + ./src/invert/laplace/impls/shoot/shoot_laplace.cxx + ./src/invert/laplace/impls/shoot/shoot_laplace.hxx + ./src/invert/laplace/impls/spt/spt.cxx + ./src/invert/laplace/impls/spt/spt.hxx + ./src/invert/laplace/invert_laplace.cxx + ./src/invert/laplace/laplacefactory.cxx + ./src/invert/laplace/laplacefactory.hxx + ./src/invert/laplace3d/impls/emptylaplace3d.hxx + ./src/invert/laplace3d/impls/petsc/petsc_laplace3d.cxx + ./src/invert/laplace3d/impls/petsc/petsc_laplace3d.hxx + ./src/invert/laplace3d/laplace3d.cxx + ./src/invert/laplace3d/laplace3d_factory.cxx + ./src/invert/laplace3d/laplace3d_factory.hxx + ./src/invert/laplacexy/laplacexy.cxx + ./src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx + ./src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx + ./src/invert/laplacexz/impls/petsc/laplacexz-petsc.cxx + ./src/invert/laplacexz/impls/petsc/laplacexz-petsc.hxx + ./src/invert/laplacexz/laplacexz.cxx + ./src/invert/parderiv/impls/cyclic/cyclic.cxx + ./src/invert/parderiv/impls/cyclic/cyclic.hxx + ./src/invert/parderiv/invert_parderiv.cxx + ./src/invert/parderiv/parderiv_factory.cxx + ./src/invert/parderiv/parderiv_factory.hxx + ./src/mesh/boundary_factory.cxx + ./src/mesh/boundary_region.cxx + ./src/mesh/boundary_standard.cxx + ./src/mesh/coordinates.cxx + ./src/mesh/data/gridfromfile.cxx + ./src/mesh/data/gridfromoptions.cxx + ./src/mesh/difops.cxx + ./src/mesh/fv_ops.cxx + ./src/mesh/impls/bout/boutmesh.cxx + ./src/mesh/impls/bout/boutmesh.hxx + ./src/mesh/index_derivs.cxx + ./src/mesh/interpolation.cxx + ./src/mesh/interpolation/bilinear.cxx + ./src/mesh/interpolation/hermite_spline.cxx + ./src/mesh/interpolation/interpolation_factory.cxx + ./src/mesh/interpolation/lagrange_4pt.cxx + ./src/mesh/interpolation/monotonic_hermite_spline.cxx + ./src/mesh/mesh.cxx + ./src/mesh/meshfactory.cxx + ./src/mesh/meshfactory.hxx + ./src/mesh/parallel/fci.cxx + ./src/mesh/parallel/fci.hxx + ./src/mesh/parallel/identity.cxx + ./src/mesh/parallel/shiftedmetric.cxx + ./src/mesh/parallel_boundary_op.cxx + ./src/mesh/parallel_boundary_region.cxx + ./src/mesh/surfaceiter.cxx + ./src/physics/gyro_average.cxx + ./src/physics/physicsmodel.cxx + ./src/physics/smoothing.cxx + ./src/physics/sourcex.cxx + ./src/solver/impls/arkode/arkode.cxx + ./src/solver/impls/arkode/arkode.hxx + ./src/solver/impls/cvode/cvode.cxx + ./src/solver/impls/cvode/cvode.hxx + ./src/solver/impls/euler/euler.cxx + ./src/solver/impls/euler/euler.hxx + ./src/solver/impls/ida/ida.cxx + ./src/solver/impls/ida/ida.hxx + ./src/solver/impls/imex-bdf2/imex-bdf2.cxx + ./src/solver/impls/imex-bdf2/imex-bdf2.hxx + ./src/solver/impls/karniadakis/karniadakis.cxx + ./src/solver/impls/karniadakis/karniadakis.hxx + ./src/solver/impls/petsc/petsc.cxx + ./src/solver/impls/petsc/petsc.hxx + ./src/solver/impls/power/power.cxx + ./src/solver/impls/power/power.hxx + ./src/solver/impls/pvode/pvode.cxx + ./src/solver/impls/pvode/pvode.hxx + ./src/solver/impls/rk3-ssp/rk3-ssp.cxx + ./src/solver/impls/rk3-ssp/rk3-ssp.hxx + ./src/solver/impls/rk4/rk4.cxx + ./src/solver/impls/rk4/rk4.hxx + ./src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx + ./src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.hxx + ./src/solver/impls/rkgeneric/impls/rk4simple/rk4simple.cxx + ./src/solver/impls/rkgeneric/impls/rk4simple/rk4simple.hxx + ./src/solver/impls/rkgeneric/impls/rkf34/rkf34.cxx + ./src/solver/impls/rkgeneric/impls/rkf34/rkf34.hxx + ./src/solver/impls/rkgeneric/impls/rkf45/rkf45.cxx + ./src/solver/impls/rkgeneric/impls/rkf45/rkf45.hxx + ./src/solver/impls/rkgeneric/rkgeneric.cxx + ./src/solver/impls/rkgeneric/rkgeneric.hxx + ./src/solver/impls/rkgeneric/rkscheme.cxx + ./src/solver/impls/rkgeneric/rkschemefactory.cxx + ./src/solver/impls/rkgeneric/rkschemefactory.hxx + ./src/solver/impls/slepc/slepc.cxx + ./src/solver/impls/slepc/slepc.hxx + ./src/solver/impls/snes/snes.cxx + ./src/solver/impls/snes/snes.hxx + ./src/solver/solver.cxx + ./src/solver/solverfactory.cxx + ./src/sys/bout_types.cxx + ./src/sys/boutcomm.cxx + ./src/sys/boutexception.cxx + ./src/sys/derivs.cxx + ./src/sys/expressionparser.cxx + ./src/sys/msg_stack.cxx + ./src/sys/options.cxx + ./src/sys/options/optionparser.hxx + ./src/sys/options/options_ini.cxx + ./src/sys/options/options_ini.hxx + ./src/sys/options/options_netcdf.cxx + ./src/sys/optionsreader.cxx + ./src/sys/output.cxx + ./src/sys/petsclib.cxx + ./src/sys/range.cxx + ./src/sys/slepclib.cxx + ./src/sys/timer.cxx + ./src/sys/type_name.cxx + ./src/sys/utils.cxx + ) + +add_library(bout + ${BOUT_SOURCES} + ) +target_link_libraries(bout PUBLIC MPI::MPI_CXX pvode pvpre mpark_variant) +target_include_directories(bout PUBLIC include) + +target_compile_definitions(bout + PUBLIC "CHECK=3" + PUBLIC "BOUT_VERSION_STRING=\"4.2.2\"" + PUBLIC "BOUT_VERSION_DOUBLE=4.22" + PUBLIC "BOUT_HAS_PVODE" + ) + +target_compile_features(bout PUBLIC cxx_std_11) +set_target_properties(bout PROPERTIES CXX_EXTENSIONS OFF) + +if (NetCDF_FOUND) + target_compile_definitions(bout + PUBLIC "NCDF4") + target_link_libraries(bout PUBLIC NetCDF::NetCDF) +endif() + +if (FFTW_FOUND) + target_compile_definitions(bout + PUBLIC "BOUT_HAS_FFTW" + ) + target_link_libraries(bout PUBLIC FFTW::FFTW) +endif() + +option(PACKAGE_TESTS "Build the tests" ON) +if(PACKAGE_TESTS) + enable_testing() + add_subdirectory(tests/unit) +endif() diff --git a/externalpackages/PVODE/CMakeLists.txt b/externalpackages/PVODE/CMakeLists.txt new file mode 100644 index 0000000000..443dd1f373 --- /dev/null +++ b/externalpackages/PVODE/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.1...3.12) + +if(${CMAKE_VERSION} VERSION_LESS 3.11) + cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +else() + cmake_policy(VERSION 3.12) +endif() + +project(PVODE + DESCRIPTION "ODE Solver" + VERSION 0.1 + LANGUAGES CXX) + +add_library(pvode + source/cvode.cpp + source/nvector.cpp + source/llnlmath.cpp + source/cvspgmr.cpp + source/spgmr.cpp + source/iterativ.cpp + source/cvdiag.cpp + source/smalldense.cpp + include/band.h + include/cvdiag.h + include/cvode.h + include/cvspgmr.h + include/iterativ.h + include/llnlmath.h + include/llnltyps.h + include/nvector.h + include/smalldense.h + include/spgmr.h + include/vector.h + ) + +target_include_directories(pvode PUBLIC include) + +add_library(pvpre + precon/pvbbdpre.cpp + precon/pvbbdpre.h + precon/band.cpp + precon/band.h + ) + +target_include_directories(pvpre PUBLIC include) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt new file mode 100644 index 0000000000..b1aba3beb0 --- /dev/null +++ b/tests/unit/CMakeLists.txt @@ -0,0 +1,70 @@ +add_subdirectory("${PROJECT_SOURCE_DIR}/externalpackages/googletest" + "externalpackages/googletest") + +mark_as_advanced( + BUILD_GMOCK BUILD_GTEST BUILD_SHARED_LIBS + gmock_build_tests gtest_build_samples gtest_build_tests + gtest_disable_pthreads gtest_force_shared_crt gtest_hide_internal_symbols + ) + +add_executable(serial_tests + ./bout_test_main.cxx + ./field/test_field.cxx + ./field/test_field2d.cxx + ./field/test_field3d.cxx + ./field/test_field_factory.cxx + ./field/test_fieldgroup.cxx + ./field/test_fieldperp.cxx + ./field/test_initialprofiles.cxx + ./field/test_vector2d.cxx + ./field/test_vector3d.cxx + ./field/test_where.cxx + ./include/bout/test_array.cxx + ./include/bout/test_assert.cxx + ./include/bout/test_deriv_store.cxx + ./include/bout/test_generic_factory.cxx + ./include/bout/test_macro_for_each.cxx + ./include/bout/test_monitor.cxx + ./include/bout/test_region.cxx + ./include/bout/test_template_combinations.cxx + ./include/test_cyclic_reduction.cxx + ./include/test_derivs.cxx + ./include/test_interpolation_factory.cxx + ./include/test_mask.cxx + ./invert/test_fft.cxx + ./mesh/data/test_gridfromoptions.cxx + ./mesh/parallel/test_fci.cxx + ./mesh/parallel/test_shiftedmetric.cxx + ./mesh/test_boundary_factory.cxx + ./mesh/test_boundary_testtest.cxx + ./mesh/test_boutmesh.cxx + ./mesh/test_coordinates.cxx + ./mesh/test_interpolation.cxx + ./mesh/test_mesh.cxx + ./mesh/test_paralleltransform.cxx + ./solver/test_fakesolver.cxx + ./solver/test_fakesolver.hxx + ./solver/test_solver.cxx + ./solver/test_solverfactory.cxx + ./sys/test_boutexception.cxx + ./sys/test_expressionparser.cxx + ./sys/test_msg_stack.cxx + ./sys/test_options.cxx + ./sys/test_options_fields.cxx + ./sys/test_options_netcdf.cxx + ./sys/test_optionsreader.cxx + ./sys/test_output.cxx + ./sys/test_range.cxx + ./sys/test_timer.cxx + ./sys/test_type_name.cxx + ./sys/test_utils.cxx + ./sys/test_variant.cxx + ./test_extras.cxx + ./test_extras.hxx + ./src/test_bout++.cxx + ) + +target_include_directories(serial_tests PUBLIC .) +target_link_libraries(serial_tests gtest gmock bout) +add_test(NAME serial_tests COMMAND serial_tests) +set_target_properties(serial_tests PROPERTIES FOLDER tests/unit) From 6ad983fa8ea82a2380ab0916c4523280e148afb4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 23 Apr 2019 15:59:13 +0100 Subject: [PATCH 1312/1783] Modernise Laplace3DFactory --- src/invert/laplace3d/laplace3d_factory.cxx | 17 ++++++++--------- src/invert/laplace3d/laplace3d_factory.hxx | 3 --- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/invert/laplace3d/laplace3d_factory.cxx b/src/invert/laplace3d/laplace3d_factory.cxx index 23aea95974..039bd0c777 100644 --- a/src/invert/laplace3d/laplace3d_factory.cxx +++ b/src/invert/laplace3d/laplace3d_factory.cxx @@ -8,27 +8,26 @@ // Include implementations here #include "impls/petsc/petsc_laplace3d.hxx" -Laplace3DFactory* Laplace3DFactory::instance = 0; +Laplace3DFactory* Laplace3DFactory::instance = nullptr; Laplace3DFactory* Laplace3DFactory::getInstance() { - if(instance == 0) { + if (instance == nullptr) { // Create the singleton object instance = new Laplace3DFactory(); } return instance; } -Laplace3D* Laplace3DFactory::createLaplace3D(Options *options) { - if(!options) +Laplace3D* Laplace3DFactory::createLaplace3D(Options* options) { + if (!options) options = Options::getRoot()->getSection("laplace3d"); - - string type; - options->get("type", type, "petsc"); + + std::string type = (*options)["type"].withDefault("petsc"); // Add tests for available solvers here. See src/invert/laplace/laplacefactory.cxx - if(strcasecmp(type.c_str(), "petsc") == 0) { + if (type == "petsc") { return new Laplace3DPetsc(options); } - + throw BoutException("Unknown Laplace3D solver type '%s'", type.c_str()); } diff --git a/src/invert/laplace3d/laplace3d_factory.hxx b/src/invert/laplace3d/laplace3d_factory.hxx index b911ed878d..c93858fadc 100644 --- a/src/invert/laplace3d/laplace3d_factory.hxx +++ b/src/invert/laplace3d/laplace3d_factory.hxx @@ -1,6 +1,3 @@ - -class Laplace3DFactory; - #ifndef __LAPLACE3D_FACTORY_H__ #define __LAPLACE3D_FACTORY_H__ From 060d2446f9cb677e22779f01a56000d45b3db2ad Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 23 Apr 2019 16:02:52 +0100 Subject: [PATCH 1313/1783] Make MsgStackTest::TraceMacroTest more flexible --- tests/unit/sys/test_msg_stack.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/sys/test_msg_stack.cxx b/tests/unit/sys/test_msg_stack.cxx index 96671a9f3f..b68fc34d3a 100644 --- a/tests/unit/sys/test_msg_stack.cxx +++ b/tests/unit/sys/test_msg_stack.cxx @@ -3,6 +3,7 @@ #include "gtest/gtest.h" #include "msg_stack.hxx" +#include "test_extras.hxx" #include #include @@ -128,10 +129,9 @@ TEST(MsgStackTest, TraceMacroTest) { std::string line = std::to_string(__LINE__ + 1); TRACE("Second"); auto second = msg_stack.getDump(); - auto second_dump = "====== Back trace ======\n -> Second on line " + line + - " of 'sys/test_msg_stack.cxx'\n -> First\n"; + auto second_dump = "====== Back trace ======\n -> Second on line " + line; - EXPECT_EQ(second_dump, second); + EXPECT_TRUE(IsSubString(second, second_dump)); } // Should now contain only the first message From b3f09a973df95317a5eff893cade9760e5a838df Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 23 Apr 2019 16:57:08 +0100 Subject: [PATCH 1314/1783] Hardcode all variables for test-solver; remove input file Also do bare minimum initialisation --- tests/integrated/test-solver/data/BOUT.inp | 59 ----------- tests/integrated/test-solver/test_solver.cxx | 105 ++++++++++++------- 2 files changed, 66 insertions(+), 98 deletions(-) delete mode 100644 tests/integrated/test-solver/data/BOUT.inp diff --git a/tests/integrated/test-solver/data/BOUT.inp b/tests/integrated/test-solver/data/BOUT.inp deleted file mode 100644 index b248ee4ea2..0000000000 --- a/tests/integrated/test-solver/data/BOUT.inp +++ /dev/null @@ -1,59 +0,0 @@ -# Integrate up to pi/2 -end = pi / 2 - -NOUT = 100 -TIMESTEP = end / NOUT - -[mesh] -# This is the smallest mesh that doesn't cause problems -# Could possibly be even smaller with a "null" boundary condition -MXG = 1 -MYG = 1 -nx = 3 -ny = 1 -nz = 1 - -[output] -enabled = false - -[restart] -enabled = false - -[solver] - -[arkode] -[cvode] -[euler] -mxstep = 100000 -nout = 100 -timestep = end / (NOUT * 1000) -[ida] -[imexbdf2] -# This solver currently fails this test without adaptive timestepping -adaptive = true -# We should tighten up the default tolerance -adaptRtol = 1.e-5 -[karniadakis] -nout = 100 -timestep = end / (NOUT * 10000) -[petsc] -# For PETSc < 3.7, there are issues with the RK solvers not -# interpolating at the final step if they are adaptive -nout = 10000 -output_step = end / nout -[power] -[pvode] -[rk3ssp] -[rk4] -# This solver currently fails this test without adaptive timestepping -adaptive = true -[rkgeneric] -# This solver currently fails this test without adaptive timestepping -adaptive = true -[slepc] -[snes] -# This solver currently fails this test without adaptive timestepping -adaptive = true - -[field] -bndry_all = none diff --git a/tests/integrated/test-solver/test_solver.cxx b/tests/integrated/test-solver/test_solver.cxx index d203a677a9..e2f84f1d1f 100644 --- a/tests/integrated/test-solver/test_solver.cxx +++ b/tests/integrated/test-solver/test_solver.cxx @@ -1,8 +1,11 @@ #include "bout/constants.hxx" #include "bout/physicsmodel.hxx" #include "bout/solverfactory.hxx" +#include "bout/petsclib.hxx" +#include "bout/slepclib.hxx" #include +#include #include #include @@ -22,13 +25,13 @@ class TestSolver : public PhysicsModel { } }; -int main(int argc, char **argv) { +int main(int argc, char** argv) { // The expected answer to the integral of \f$\int_0^{\pi/2}\sin^2(t)\f$ - BoutReal expected = PI / 4.; + const BoutReal expected = PI / 4.; // Absolute tolerance for difference between the actual value and the // expected value - BoutReal tolerance = 1.e-5; + constexpr BoutReal tolerance = 1.e-5; // Our own output to stdout, as main library will only be writing to log files Output output_test; @@ -37,47 +40,76 @@ int main(int argc, char **argv) { // Should be able to check which solvers aren't suitable std::vector eigen_solvers = {"power", "slepc", "snes"}; - for (auto &eigen_solver : eigen_solvers) { + for (auto& eigen_solver : eigen_solvers) { if (SolverFactory::getInstance()->remove(eigen_solver)) { output_test << "Removed '" << eigen_solver << "' eigen solver\n"; } } output_test << "\nTesting the following solvers:\n"; - for (auto &solver : SolverFactory::getInstance()->listAvailable()) { + for (auto& solver : SolverFactory::getInstance()->listAvailable()) { output_test << " " << solver << "\n"; } // Explicit flush to make sure list of available solvers gets printed output_test << std::endl; - // DANGER, hack below! BoutInitialise turns on writing to stdout for rank 0, - // and then immediately prints a load of stuff to stdout. We want this test to - // be quiet, so we need to hide stdout from the main library before - // BoutInitialise. After the call to BoutInitialise, we can turn off the main - // library writing to stdout in a nicer way. + auto& root = Options::root(); - // Save cout's buffer here - std::stringstream buffer; - auto *sbuf = std::cout.rdbuf(); - // Redirect cout to our buffer - std::cout.rdbuf(buffer.rdbuf()); + root["mesh"]["MXG"] = 1; + root["mesh"]["MYG"] = 1; + root["mesh"]["nx"] = 3; + root["mesh"]["ny"] = 1; + root["mesh"]["nz"] = 1; - int init_err = BoutInitialise(argc, argv); - if (init_err < 0) { - return 0; - } else if (init_err > 0) { - return init_err; - } + root["output"]["enabled"] = false; + root["restart"]["enabled"] = false; + + // Set the command-line arguments + SlepcLib::setArgs(argc, argv); + PetscLib::setArgs(argc, argv); + Solver::setArgs(argc, argv); + BoutComm::setArgs(argc, argv); - // Now BoutInitialise is done, redirect stdout to its old self - std::cout.rdbuf(sbuf); // Turn off writing to stdout for the main library Output::getInstance()->disable(); + bout::globals::mesh = Mesh::create(); + bout::globals::mesh->load(); + + bout::globals::dump = + bout::experimental::setupDumpFile(Options::root(), *bout::globals::mesh, "."); + + const BoutReal end = PI / 2.; + constexpr int NOUT = 100; + + // Global options + root["NOUT"] = NOUT; + root["TIMESTEP"] = end / NOUT; + + // Solver-specific options + root["euler"]["mxstep"] = 100000; + root["euler"]["nout"] = NOUT; + root["euler"]["timestep"] = end / (NOUT * 1000); + + root["rk4"]["adaptive"] = true; + + root["rkgeneric"]["adaptive"] = true; + + root["imexbdf2"]["adaptive"] = true; + root["imexbdf2"]["adaptRtol"] = 1.e-5; + + root["karniadakis"]["nout"] = 100; + root["karniadakis"]["timestep"] = end / (NOUT * 10000); + + root["petsc"]["nout"] = 10000; + root["petsc"]["output_step"] = end / 10000; + + root["snes"]["adaptive"] = true; + // Solver and its actual value if it didn't pass std::map errors; - for (auto &name : SolverFactory::getInstance()->listAvailable()) { + for (auto& name : SolverFactory::getInstance()->listAvailable()) { output_test << "Testing " << name << " solver:"; try { @@ -85,28 +117,23 @@ int main(int argc, char **argv) { // "solver" section, as we run into problems when solvers use the same // name for an option with inconsistent defaults auto options = Options::getRoot()->getSection(name); - Solver *solver = SolverFactory::getInstance()->createSolver(name, options); + std::unique_ptr solver{SolverFactory::getInstance()->createSolver(name, options)}; - TestSolver *model = new TestSolver(); - solver->setModel(model); + TestSolver model{}; + solver->setModel(&model); - Monitor *bout_monitor = new BoutMonitor(); - solver->addMonitor(bout_monitor, Solver::BACK); + BoutMonitor bout_monitor{}; + solver->addMonitor(&bout_monitor, Solver::BACK); solver->solve(); - if (fabs(model->field(1, 1, 0) - expected) > tolerance) { + if (std::abs(model.field(1, 1, 0) - expected) > tolerance) { output_test << " FAILED\n"; - errors[name] = model->field(1, 1, 0); + errors[name] = model.field(1, 1, 0); } else { output_test << " PASSED\n"; } - - delete model; - delete solver; - delete bout_monitor; - - } catch (BoutException &e) { + } catch (BoutException& e) { // Don't let one bad solver stop us trying the rest output_test << " ERROR\n"; output_info << "Error encountered with solver " << name << "\n"; @@ -115,11 +142,11 @@ int main(int argc, char **argv) { } } - BoutFinalise(); + BoutFinalise(false); if (!errors.empty()) { output_test << "\n => Some failed tests\n\n"; - for (auto &error : errors) { + for (auto& error : errors) { output_test << " " << error.first << " got: " << error.second << ", expected: " << expected << "\n"; } From c1de7e6914c7c688be87759ae075c6fb109fd4e0 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 23 Apr 2019 16:58:24 +0100 Subject: [PATCH 1315/1783] Add macro for adding integrated tests to ctest; add test-solver --- CMakeLists.txt | 13 +++++++++++-- tests/integrated/test-solver/CMakeLists.txt | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/integrated/test-solver/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 00ac2c9cd8..0a4f832f2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -309,8 +309,17 @@ if (FFTW_FOUND) target_link_libraries(bout PUBLIC FFTW::FFTW) endif() +macro(bout_add_integrated_test TESTNAME) + add_executable(${TESTNAME} ${ARGN}) + target_link_libraries(${TESTNAME} bout) + target_include_directories(${TESTNAME} PRIVATE $) + add_test(NAME ${TESTNAME} COMMAND ${TESTNAME}) + set_target_properties(${TESTNAME} PROPERTIES FOLDER tests/integrated) +endmacro() + option(PACKAGE_TESTS "Build the tests" ON) if(PACKAGE_TESTS) - enable_testing() - add_subdirectory(tests/unit) + enable_testing() + add_subdirectory(tests/unit) + add_subdirectory(tests/integrated/test-solver) endif() diff --git a/tests/integrated/test-solver/CMakeLists.txt b/tests/integrated/test-solver/CMakeLists.txt new file mode 100644 index 0000000000..706f473c11 --- /dev/null +++ b/tests/integrated/test-solver/CMakeLists.txt @@ -0,0 +1,3 @@ +bout_add_integrated_test(test_solver + test_solver.cxx + ) From b70dd9cd696f0b49ddfd325471f6c052aac24c1a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 23 Apr 2019 17:37:56 +0100 Subject: [PATCH 1316/1783] Add finding LAPACK and PETSc to cmake --- CMakeLists.txt | 22 +- cmake/CorrectWindowsPaths.cmake | 14 ++ cmake/FindFFTW.cmake | 29 +++ cmake/FindNetCDF.cmake | 53 +++++ cmake/FindPETSc.cmake | 356 +++++++++++++++++++++++++++++++ cmake/FindPackageMultipass.cmake | 106 +++++++++ cmake/ResolveCompilerPaths.cmake | 105 +++++++++ 7 files changed, 680 insertions(+), 5 deletions(-) create mode 100644 cmake/CorrectWindowsPaths.cmake create mode 100644 cmake/FindFFTW.cmake create mode 100644 cmake/FindNetCDF.cmake create mode 100644 cmake/FindPETSc.cmake create mode 100644 cmake/FindPackageMultipass.cmake create mode 100644 cmake/ResolveCompilerPaths.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a4f832f2d..e9d6c9a45e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,9 +15,6 @@ find_package(MPI REQUIRED) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) -find_package(NetCDF) -find_package(FFTW) - add_subdirectory(externalpackages/mpark.variant) add_subdirectory(externalpackages/PVODE) @@ -296,19 +293,34 @@ target_compile_definitions(bout target_compile_features(bout PUBLIC cxx_std_11) set_target_properties(bout PROPERTIES CXX_EXTENSIONS OFF) +find_package(NetCDF) if (NetCDF_FOUND) target_compile_definitions(bout PUBLIC "NCDF4") target_link_libraries(bout PUBLIC NetCDF::NetCDF) endif() +find_package(FFTW) if (FFTW_FOUND) target_compile_definitions(bout - PUBLIC "BOUT_HAS_FFTW" - ) + PUBLIC "BOUT_HAS_FFTW") target_link_libraries(bout PUBLIC FFTW::FFTW) endif() +find_package(LAPACK) +if (LAPACK_FOUND) + target_compile_definitions(bout + PUBLIC "LAPACK") + target_link_libraries(bout PUBLIC "${LAPACK_LIBRARIES}") +endif() + +find_package(PETSc) +if (PETSC_FOUND) + target_compile_definitions(bout + PUBLIC "BOUT_HAS_PETSC") + target_link_libraries(bout PUBLIC PETSC::PETSc) +endif() + macro(bout_add_integrated_test TESTNAME) add_executable(${TESTNAME} ${ARGN}) target_link_libraries(${TESTNAME} bout) diff --git a/cmake/CorrectWindowsPaths.cmake b/cmake/CorrectWindowsPaths.cmake new file mode 100644 index 0000000000..09bcdd67dc --- /dev/null +++ b/cmake/CorrectWindowsPaths.cmake @@ -0,0 +1,14 @@ +# CorrectWindowsPaths - this module defines one macro +# +# CONVERT_CYGWIN_PATH( PATH ) +# This uses the command cygpath (provided by cygwin) to convert +# unix-style paths into paths useable by cmake on windows + +macro (CONVERT_CYGWIN_PATH _path) + if (WIN32) + EXECUTE_PROCESS(COMMAND cygpath.exe -m ${${_path}} + OUTPUT_VARIABLE ${_path}) + string (STRIP ${${_path}} ${_path}) + endif (WIN32) +endmacro (CONVERT_CYGWIN_PATH) + diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake new file mode 100644 index 0000000000..8dc7d82b9d --- /dev/null +++ b/cmake/FindFFTW.cmake @@ -0,0 +1,29 @@ +if (FFTW_INCLUDES) + # Already in cache, be silent + set (FFTW_FIND_QUIETLY TRUE) +endif (FFTW_INCLUDES) + +find_path (FFTW_INCLUDES fftw3.h) + +find_library (FFTW_LIBRARIES NAMES fftw3) + +# handle the QUIETLY and REQUIRED arguments and set FFTW_FOUND to TRUE if +# all listed variables are TRUE +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (FFTW DEFAULT_MSG FFTW_LIBRARIES FFTW_INCLUDES) + +mark_as_advanced (FFTW_LIBRARIES FFTW_INCLUDES) + +if (FFTW_FOUND) + if (NOT TARGET FFTW::FFTW) + add_library(FFTW::FFTW UNKNOWN IMPORTED) + set_target_properties(FFTW::FFTW PROPERTIES + IMPORTED_LOCATION "${FFTW_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDES}" + ) + # set_target_properties(FFTW::FFTW PROPERTIES + # IMPORTED_LOCATION "${FFTW_LIBRARIES}" + # INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" + # ) + endif() +endif() diff --git a/cmake/FindNetCDF.cmake b/cmake/FindNetCDF.cmake new file mode 100644 index 0000000000..98cc3666fb --- /dev/null +++ b/cmake/FindNetCDF.cmake @@ -0,0 +1,53 @@ +find_path(NetCDF_INCLUDE_DIR + NAMES netcdf.h + DOC "netcdf include directories") +mark_as_advanced(NetCDF_INCLUDE_DIR) + +find_library(NetCDF_LIBRARY + NAMES netcdf + DOC "netcdf library") +mark_as_advanced(NetCDF_LIBRARY) + +find_path(NetCDF_CXX_INCLUDE_DIR + NAMES netcdf + DOC "netcdf C++ include directories") +mark_as_advanced(NetCDF_CXX_INCLUDE_DIR) + +find_library(NetCDF_CXX_LIBRARY + NAMES netcdf_c++4 + DOC "netcdf C++ library") +mark_as_advanced(NetCDF_CXX_LIBRARY) + +if (NetCDF_INCLUDE_DIR) + file(STRINGS "${NetCDF_INCLUDE_DIR}/netcdf_meta.h" _netcdf_version_lines + REGEX "#define[ \t]+NC_VERSION_(MAJOR|MINOR|PATCH|NOTE)") + string(REGEX REPLACE ".*NC_VERSION_MAJOR *\([0-9]*\).*" "\\1" _netcdf_version_major "${_netcdf_version_lines}") + string(REGEX REPLACE ".*NC_VERSION_MINOR *\([0-9]*\).*" "\\1" _netcdf_version_minor "${_netcdf_version_lines}") + string(REGEX REPLACE ".*NC_VERSION_PATCH *\([0-9]*\).*" "\\1" _netcdf_version_patch "${_netcdf_version_lines}") + string(REGEX REPLACE ".*NC_VERSION_NOTE *\"\([^\"]*\)\".*" "\\1" _netcdf_version_note "${_netcdf_version_lines}") + set(NetCDF_VERSION "${_netcdf_version_major}.${_netcdf_version_minor}.${_netcdf_version_patch}${_netcdf_version_note}") + unset(_netcdf_version_major) + unset(_netcdf_version_minor) + unset(_netcdf_version_patch) + unset(_netcdf_version_note) + unset(_netcdf_version_lines) +endif () + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(NetCDF + REQUIRED_VARS NetCDF_LIBRARY NetCDF_INCLUDE_DIR NetCDF_CXX_LIBRARY NetCDF_CXX_INCLUDE_DIR + VERSION_VAR NetCDF_VERSION) + +if (NetCDF_FOUND) + set(NetCDF_INCLUDE_DIRS "${NetCDF_INCLUDE_DIR}") + set(NetCDF_LIBRARIES "${NetCDF_LIBRARY}") + + if (NOT TARGET NetCDF::NetCDF) + add_library(NetCDF::NetCDF UNKNOWN IMPORTED) + set_target_properties(NetCDF::NetCDF PROPERTIES + IMPORTED_LOCATION "${NetCDF_LIBRARY}" + IMPORTED_LOCATION "${NetCDF_CXX_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_INCLUDE_DIR}" + INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_CXX_INCLUDE_DIR}") + endif () +endif () diff --git a/cmake/FindPETSc.cmake b/cmake/FindPETSc.cmake new file mode 100644 index 0000000000..e7d4d6522a --- /dev/null +++ b/cmake/FindPETSc.cmake @@ -0,0 +1,356 @@ +# - Try to find PETSc +# Once done this will define +# +# PETSC_FOUND - system has PETSc +# PETSC_INCLUDES - the PETSc include directories +# PETSC_LIBRARIES - Link these to use PETSc +# PETSC_COMPILER - Compiler used by PETSc, helpful to find a compatible MPI +# PETSC_DEFINITIONS - Compiler switches for using PETSc +# PETSC_MPIEXEC - Executable for running MPI programs +# PETSC_VERSION - Version string (MAJOR.MINOR.SUBMINOR) +# +# Usage: +# find_package(PETSc COMPONENTS CXX) - required if build --with-clanguage=C++ --with-c-support=0 +# find_package(PETSc COMPONENTS C) - standard behavior of checking build using a C compiler +# find_package(PETSc) - same as above +# +# Setting these changes the behavior of the search +# PETSC_DIR - directory in which PETSc resides +# PETSC_ARCH - build architecture +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +cmake_policy(VERSION 3.3) + +set(PETSC_VALID_COMPONENTS + C + CXX) + +if(NOT PETSc_FIND_COMPONENTS) + get_property (_enabled_langs GLOBAL PROPERTY ENABLED_LANGUAGES) + if ("C" IN_LIST _enabled_langs) + set(PETSC_LANGUAGE_BINDINGS "C") + else () + set(PETSC_LANGUAGE_BINDINGS "CXX") + endif () +else() + # Right now, this is designed for compatability with the --with-clanguage option, so + # only allow one item in the components list. + list(LENGTH ${PETSc_FIND_COMPONENTS} components_length) + if(${components_length} GREATER 1) + message(FATAL_ERROR "Only one component for PETSc is allowed to be specified") + endif() + # This is a stub for allowing multiple components should that time ever come. Perhaps + # to also test Fortran bindings? + foreach(component ${PETSc_FIND_COMPONENTS}) + list(FIND PETSC_VALID_COMPONENTS ${component} component_location) + if(${component_location} EQUAL -1) + message(FATAL_ERROR "\"${component}\" is not a valid PETSc component.") + else() + list(APPEND PETSC_LANGUAGE_BINDINGS ${component}) + endif() + endforeach() +endif() + +function (petsc_get_version) + if (EXISTS "${PETSC_DIR}/include/petscversion.h") + file (STRINGS "${PETSC_DIR}/include/petscversion.h" vstrings REGEX "#define PETSC_VERSION_(RELEASE|MAJOR|MINOR|SUBMINOR|PATCH) ") + foreach (line ${vstrings}) + string (REGEX REPLACE " +" ";" fields ${line}) # break line into three fields (the first is always "#define") + list (GET fields 1 var) + list (GET fields 2 val) + set (${var} ${val} PARENT_SCOPE) + set (${var} ${val}) # Also in local scope so we have access below + endforeach () + if (PETSC_VERSION_RELEASE) + if ($(PETSC_VERSION_PATCH) GREATER 0) + set (PETSC_VERSION "${PETSC_VERSION_MAJOR}.${PETSC_VERSION_MINOR}.${PETSC_VERSION_SUBMINOR}p${PETSC_VERSION_PATCH}" CACHE INTERNAL "PETSc version") + else () + set (PETSC_VERSION "${PETSC_VERSION_MAJOR}.${PETSC_VERSION_MINOR}.${PETSC_VERSION_SUBMINOR}" CACHE INTERNAL "PETSc version") + endif () + else () + # make dev version compare higher than any patch level of a released version + set (PETSC_VERSION "${PETSC_VERSION_MAJOR}.${PETSC_VERSION_MINOR}.${PETSC_VERSION_SUBMINOR}.99" CACHE INTERNAL "PETSc version") + endif () + else () + message (SEND_ERROR "PETSC_DIR can not be used, ${PETSC_DIR}/include/petscversion.h does not exist") + endif () +endfunction () + +# Debian uses versioned paths e.g /usr/lib/petscdir/3.5/ +file (GLOB DEB_PATHS "/usr/lib/petscdir/*") + +find_path (PETSC_DIR include/petsc.h + HINTS ENV PETSC_DIR + PATHS + /usr/lib/petsc + # Debian paths + ${DEB_PATHS} + # Arch Linux path + /opt/petsc/linux-c-opt + # MacPorts path + /opt/local/lib/petsc + $ENV{HOME}/petsc + DOC "PETSc Directory") + +find_program (MAKE_EXECUTABLE NAMES make gmake) + +if (PETSC_DIR AND NOT PETSC_ARCH) + set (_petsc_arches + $ENV{PETSC_ARCH} # If set, use environment variable first + linux-gnu-c-debug linux-gnu-c-opt # Debian defaults + x86_64-unknown-linux-gnu i386-unknown-linux-gnu) + set (petscconf "NOTFOUND" CACHE FILEPATH "Cleared" FORCE) + foreach (arch ${_petsc_arches}) + if (NOT PETSC_ARCH) + find_path (petscconf petscconf.h + HINTS ${PETSC_DIR} + PATH_SUFFIXES ${arch}/include bmake/${arch} + NO_DEFAULT_PATH) + if (petscconf) + set (PETSC_ARCH "${arch}" CACHE STRING "PETSc build architecture") + endif (petscconf) + endif (NOT PETSC_ARCH) + endforeach (arch) + set (petscconf "NOTFOUND" CACHE INTERNAL "Scratch variable" FORCE) +endif (PETSC_DIR AND NOT PETSC_ARCH) + +set (petsc_slaves LIBRARIES_SYS LIBRARIES_VEC LIBRARIES_MAT LIBRARIES_DM LIBRARIES_KSP LIBRARIES_SNES LIBRARIES_TS + INCLUDE_DIR INCLUDE_CONF) +include (FindPackageMultipass) +find_package_multipass (PETSc petsc_config_current + STATES DIR ARCH + DEPENDENTS INCLUDES LIBRARIES COMPILER MPIEXEC ${petsc_slaves}) + +# Determine whether the PETSc layout is old-style (through 2.3.3) or +# new-style (>= 3.0.0) +if (EXISTS "${PETSC_DIR}/${PETSC_ARCH}/lib/petsc/conf/petscvariables") # > 3.5 + set (petsc_conf_rules "${PETSC_DIR}/lib/petsc/conf/rules") + set (petsc_conf_variables "${PETSC_DIR}/lib/petsc/conf/variables") +elseif (EXISTS "${PETSC_DIR}/${PETSC_ARCH}/include/petscconf.h") # > 2.3.3 + set (petsc_conf_rules "${PETSC_DIR}/conf/rules") + set (petsc_conf_variables "${PETSC_DIR}/conf/variables") +elseif (EXISTS "${PETSC_DIR}/bmake/${PETSC_ARCH}/petscconf.h") # <= 2.3.3 + set (petsc_conf_rules "${PETSC_DIR}/bmake/common/rules") + set (petsc_conf_variables "${PETSC_DIR}/bmake/common/variables") +elseif (PETSC_DIR) + message (SEND_ERROR "The pair PETSC_DIR=${PETSC_DIR} PETSC_ARCH=${PETSC_ARCH} do not specify a valid PETSc installation") +endif () + +if (petsc_conf_rules AND petsc_conf_variables AND NOT petsc_config_current) + petsc_get_version() + + # Put variables into environment since they are needed to get + # configuration (petscvariables) in the PETSc makefile + set (ENV{PETSC_DIR} "${PETSC_DIR}") + set (ENV{PETSC_ARCH} "${PETSC_ARCH}") + + # A temporary makefile to probe the PETSc configuration + set (petsc_config_makefile "${PROJECT_BINARY_DIR}/Makefile.petsc") + file (WRITE "${petsc_config_makefile}" +"## This file was autogenerated by FindPETSc.cmake +# PETSC_DIR = ${PETSC_DIR} +# PETSC_ARCH = ${PETSC_ARCH} +include ${petsc_conf_rules} +include ${petsc_conf_variables} +show : +\t-@echo -n \${\${VARIABLE}} +") + + macro (PETSC_GET_VARIABLE name var) + set (${var} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) + execute_process (COMMAND ${MAKE_EXECUTABLE} --no-print-directory -f ${petsc_config_makefile} show VARIABLE=${name} + OUTPUT_VARIABLE ${var} + RESULT_VARIABLE petsc_return) + endmacro (PETSC_GET_VARIABLE) + petsc_get_variable (PETSC_LIB_DIR petsc_lib_dir) + petsc_get_variable (PETSC_EXTERNAL_LIB_BASIC petsc_libs_external) + petsc_get_variable (PETSC_CCPPFLAGS petsc_cpp_line) + petsc_get_variable (PETSC_INCLUDE petsc_include) + petsc_get_variable (PCC petsc_cc) + petsc_get_variable (PCC_FLAGS petsc_cc_flags) + petsc_get_variable (MPIEXEC petsc_mpiexec) + # We are done with the temporary Makefile, calling PETSC_GET_VARIABLE after this point is invalid! + file (REMOVE ${petsc_config_makefile}) + + include (ResolveCompilerPaths) + # Extract include paths and libraries from compile command line + resolve_includes (petsc_includes_all "${petsc_cpp_line}") + + #on windows we need to make sure we're linking against the right + #runtime library + if (WIN32) + if (petsc_cc_flags MATCHES "-MT") + set(using_md False) + foreach(flag_var + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if(${flag_var} MATCHES "/MD") + set(using_md True) + endif(${flag_var} MATCHES "/MD") + endforeach(flag_var) + if(${using_md} MATCHES "True") + message(WARNING "PETSc was built with /MT, but /MD is currently set. + See http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F") + endif(${using_md} MATCHES "True") + endif (petsc_cc_flags MATCHES "-MT") + endif (WIN32) + + include (CorrectWindowsPaths) + convert_cygwin_path(petsc_lib_dir) + message (STATUS "petsc_lib_dir ${petsc_lib_dir}") + + macro (PETSC_FIND_LIBRARY suffix name) + set (PETSC_LIBRARY_${suffix} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) # Clear any stale value, if we got here, we need to find it again + if (WIN32) + set (libname lib${name}) #windows expects "libfoo", linux expects "foo" + else (WIN32) + set (libname ${name}) + endif (WIN32) + find_library (PETSC_LIBRARY_${suffix} NAMES ${libname} HINTS ${petsc_lib_dir} NO_DEFAULT_PATH) + set (PETSC_LIBRARIES_${suffix} "${PETSC_LIBRARY_${suffix}}") + mark_as_advanced (PETSC_LIBRARY_${suffix}) + endmacro (PETSC_FIND_LIBRARY suffix name) + + # Look for petscvec first, if it doesn't exist, we must be using single-library + petsc_find_library (VEC petscvec) + if (PETSC_LIBRARY_VEC) + petsc_find_library (SYS "petscsys;petsc") # libpetscsys is called libpetsc prior to 3.1 (when single-library was introduced) + petsc_find_library (MAT petscmat) + petsc_find_library (DM petscdm) + petsc_find_library (KSP petscksp) + petsc_find_library (SNES petscsnes) + petsc_find_library (TS petscts) + macro (PETSC_JOIN libs deps) + list (APPEND PETSC_LIBRARIES_${libs} ${PETSC_LIBRARIES_${deps}}) + endmacro (PETSC_JOIN libs deps) + petsc_join (VEC SYS) + petsc_join (MAT VEC) + petsc_join (DM MAT) + petsc_join (KSP DM) + petsc_join (SNES KSP) + petsc_join (TS SNES) + petsc_join (ALL TS) + else () + set (PETSC_LIBRARY_VEC "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) # There is no libpetscvec + petsc_find_library (SINGLE petsc) + # Debian 9/Ubuntu 16.04 uses _real and _complex extensions when using libraries in /usr/lib/petsc. + if (NOT PETSC_LIBRARY_SINGLE) + petsc_find_library (SINGLE petsc_real) + endif() + if (NOT PETSC_LIBRARY_SINGLE) + petsc_find_library (SINGLE petsc_complex) + endif() + foreach (pkg SYS VEC MAT DM KSP SNES TS ALL) + set (PETSC_LIBRARIES_${pkg} "${PETSC_LIBRARY_SINGLE}") + endforeach () + endif () + if (PETSC_LIBRARY_TS) + message (STATUS "Recognized PETSc install with separate libraries for each package") + else () + message (STATUS "Recognized PETSc install with single library for all packages") + endif () + + include(Check${PETSC_LANGUAGE_BINDINGS}SourceRuns) + macro (PETSC_TEST_RUNS includes libraries runs) + if (PETSC_VERSION VERSION_GREATER 3.1) + set (_PETSC_TSDestroy "TSDestroy(&ts)") + else () + set (_PETSC_TSDestroy "TSDestroy(ts)") + endif () + + set(_PETSC_TEST_SOURCE " +static const char help[] = \"PETSc test program.\"; +#include +int main(int argc,char *argv[]) { + PetscErrorCode ierr; + TS ts; + + ierr = PetscInitialize(&argc,&argv,0,help);CHKERRQ(ierr); + ierr = TSCreate(PETSC_COMM_WORLD,&ts);CHKERRQ(ierr); + ierr = TSSetFromOptions(ts);CHKERRQ(ierr); + ierr = ${_PETSC_TSDestroy};CHKERRQ(ierr); + ierr = PetscFinalize();CHKERRQ(ierr); + return 0; +} +") + multipass_source_runs ("${includes}" "${libraries}" "${_PETSC_TEST_SOURCE}" ${runs} "${PETSC_LANGUAGE_BINDINGS}") + if (${${runs}}) + set (PETSC_EXECUTABLE_RUNS "YES" CACHE BOOL + "Can the system successfully run a PETSc executable? This variable can be manually set to \"YES\" to force CMake to accept a given PETSc configuration, but this will almost always result in a broken build. If you change PETSC_DIR, PETSC_ARCH, or PETSC_CURRENT you would have to reset this variable." FORCE) + endif (${${runs}}) + endmacro (PETSC_TEST_RUNS) + + + find_path (PETSC_INCLUDE_DIR petscts.h HINTS "${PETSC_DIR}" PATH_SUFFIXES include NO_DEFAULT_PATH) + find_path (PETSC_INCLUDE_CONF petscconf.h HINTS "${PETSC_DIR}" PATH_SUFFIXES "${PETSC_ARCH}/include" "bmake/${PETSC_ARCH}" NO_DEFAULT_PATH) + mark_as_advanced (PETSC_INCLUDE_DIR PETSC_INCLUDE_CONF) + set (petsc_includes_minimal ${PETSC_INCLUDE_CONF} ${PETSC_INCLUDE_DIR}) + + petsc_test_runs ("${petsc_includes_minimal}" "${PETSC_LIBRARIES_TS}" petsc_works_minimal) + if (petsc_works_minimal) + message (STATUS "Minimal PETSc includes and libraries work. This probably means we are building with shared libs.") + set (petsc_includes_needed "${petsc_includes_minimal}") + else (petsc_works_minimal) # Minimal includes fail, see if just adding full includes fixes it + petsc_test_runs ("${petsc_includes_all}" "${PETSC_LIBRARIES_TS}" petsc_works_allincludes) + if (petsc_works_allincludes) # It does, we just need all the includes ( + message (STATUS "PETSc requires extra include paths, but links correctly with only interface libraries. This is an unexpected configuration (but it seems to work fine).") + set (petsc_includes_needed ${petsc_includes_all}) + else (petsc_works_allincludes) # We are going to need to link the external libs explicitly + resolve_libraries (petsc_libraries_external "${petsc_libs_external}") + foreach (pkg SYS VEC MAT DM KSP SNES TS ALL) + list (APPEND PETSC_LIBRARIES_${pkg} ${petsc_libraries_external}) + endforeach (pkg) + petsc_test_runs ("${petsc_includes_minimal}" "${PETSC_LIBRARIES_TS}" petsc_works_alllibraries) + if (petsc_works_alllibraries) + message (STATUS "PETSc only need minimal includes, but requires explicit linking to all dependencies. This is expected when PETSc is built with static libraries.") + set (petsc_includes_needed ${petsc_includes_minimal}) + else (petsc_works_alllibraries) + # It looks like we really need everything, should have listened to Matt + set (petsc_includes_needed ${petsc_includes_all}) + petsc_test_runs ("${petsc_includes_all}" "${PETSC_LIBRARIES_TS}" petsc_works_all) + if (petsc_works_all) # We fail anyways + message (STATUS "PETSc requires extra include paths and explicit linking to all dependencies. This probably means you have static libraries and something unexpected in PETSc headers.") + else (petsc_works_all) # We fail anyways + message (STATUS "PETSc could not be used, maybe the install is broken.") + endif (petsc_works_all) + endif (petsc_works_alllibraries) + endif (petsc_works_allincludes) + endif (petsc_works_minimal) + + # We do an out-of-source build so __FILE__ will be an absolute path, hence __INSDIR__ is superfluous + if (${PETSC_VERSION} VERSION_LESS 3.1) + set (PETSC_DEFINITIONS "-D__SDIR__=\"\"" CACHE STRING "PETSc definitions" FORCE) + else () + set (PETSC_DEFINITIONS "-D__INSDIR__=" CACHE STRING "PETSc definitions" FORCE) + endif () + # Sometimes this can be used to assist FindMPI.cmake + set (PETSC_MPIEXEC ${petsc_mpiexec} CACHE FILEPATH "Executable for running PETSc MPI programs" FORCE) + set (PETSC_INCLUDES ${petsc_includes_needed} CACHE STRING "PETSc include path" FORCE) + set (PETSC_LIBRARIES ${PETSC_LIBRARIES_ALL} CACHE STRING "PETSc libraries" FORCE) + set (PETSC_COMPILER ${petsc_cc} CACHE FILEPATH "PETSc compiler" FORCE) + # Note that we have forced values for all these choices. If you + # change these, you are telling the system to trust you that they + # work. It is likely that you will end up with a broken build. + mark_as_advanced (PETSC_INCLUDES PETSC_LIBRARIES PETSC_COMPILER PETSC_DEFINITIONS PETSC_MPIEXEC PETSC_EXECUTABLE_RUNS) +endif () + +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (PETSc + REQUIRED_VARS PETSC_INCLUDES PETSC_LIBRARIES PETSC_EXECUTABLE_RUNS + VERSION_VAR PETSC_VERSION + FAIL_MESSAGE "PETSc could not be found. Be sure to set PETSC_DIR and PETSC_ARCH.") + +if (PETSC_FOUND) + if (NOT TARGET PETSC::PETSc) + add_library(PETSC::PETSc UNKNOWN IMPORTED) + set_target_properties(PETSC::PETSc PROPERTIES + IMPORTED_LOCATION "${PETSC_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${PETSC_INCLUDES}" + ) + endif() +endif() diff --git a/cmake/FindPackageMultipass.cmake b/cmake/FindPackageMultipass.cmake new file mode 100644 index 0000000000..fbf06a7f0f --- /dev/null +++ b/cmake/FindPackageMultipass.cmake @@ -0,0 +1,106 @@ +# PackageMultipass - this module defines two macros +# +# FIND_PACKAGE_MULTIPASS (Name CURRENT +# STATES VAR0 VAR1 ... +# DEPENDENTS DEP0 DEP1 ...) +# +# This function creates a cache entry _CURRENT which +# the user can set to "NO" to trigger a reconfiguration of the package. +# The first time this function is called, the values of +# _VAR0, ... are saved. If _CURRENT +# is false or if any STATE has changed since the last time +# FIND_PACKAGE_MULTIPASS() was called, then CURRENT will be set to "NO", +# otherwise CURRENT will be "YES". IF not CURRENT, then +# _DEP0, ... will be FORCED to NOTFOUND. +# Example: +# find_path (FOO_DIR include/foo.h) +# FIND_PACKAGE_MULTIPASS (Foo foo_current +# STATES DIR +# DEPENDENTS INCLUDES LIBRARIES) +# if (NOT foo_current) +# # Make temporary files, run programs, etc, to determine FOO_INCLUDES and FOO_LIBRARIES +# endif (NOT foo_current) +# +# MULTIPASS_SOURCE_RUNS (Name INCLUDES LIBRARIES SOURCE RUNS LANGUAGE) +# Always runs the given test, use this when you need to re-run tests +# because parent variables have made old cache entries stale. The LANGUAGE +# variable is either C or CXX indicating which compiler the test should +# use. +# MULTIPASS_C_SOURCE_RUNS (Name INCLUDES LIBRARIES SOURCE RUNS) +# DEPRECATED! This is only included for backwards compatability. Use +# the more general MULTIPASS_SOURCE_RUNS instead. +# Always runs the given test, use this when you need to re-run tests +# because parent variables have made old cache entries stale. + +macro (FIND_PACKAGE_MULTIPASS _name _current) + string (TOUPPER ${_name} _NAME) + set (_args ${ARGV}) + list (REMOVE_AT _args 0 1) + + set (_states_current "YES") + list (GET _args 0 _cmd) + if (_cmd STREQUAL "STATES") + list (REMOVE_AT _args 0) + list (GET _args 0 _state) + while (_state AND NOT _state STREQUAL "DEPENDENTS") + # The name of the stored value for the given state + set (_stored_var PACKAGE_MULTIPASS_${_NAME}_${_state}) + if (NOT "${${_stored_var}}" STREQUAL "${${_NAME}_${_state}}") + set (_states_current "NO") + endif (NOT "${${_stored_var}}" STREQUAL "${${_NAME}_${_state}}") + set (${_stored_var} "${${_NAME}_${_state}}" CACHE INTERNAL "Stored state for ${_name}." FORCE) + list (REMOVE_AT _args 0) + list (GET _args 0 _state) + endwhile (_state AND NOT _state STREQUAL "DEPENDENTS") + endif (_cmd STREQUAL "STATES") + + set (_stored ${_NAME}_CURRENT) + if (NOT ${_stored}) + set (${_stored} "YES" CACHE BOOL "Is the configuration for ${_name} current? Set to \"NO\" to reconfigure." FORCE) + set (_states_current "NO") + endif (NOT ${_stored}) + + set (${_current} ${_states_current}) + if (NOT ${_current} AND PACKAGE_MULTIPASS_${_name}_CALLED) + message (STATUS "Clearing ${_name} dependent variables") + # Clear all the dependent variables so that the module can reset them + list (GET _args 0 _cmd) + if (_cmd STREQUAL "DEPENDENTS") + list (REMOVE_AT _args 0) + foreach (dep ${_args}) + set (${_NAME}_${dep} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) + endforeach (dep) + endif (_cmd STREQUAL "DEPENDENTS") + set (${_NAME}_FOUND "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) + endif () + set (PACKAGE_MULTIPASS_${name}_CALLED YES CACHE INTERNAL "Private" FORCE) +endmacro (FIND_PACKAGE_MULTIPASS) + + +macro (MULTIPASS_SOURCE_RUNS includes libraries source runs language) + include (Check${language}SourceRuns) + # This is a ridiculous hack. CHECK_${language}_SOURCE_* thinks that if the + # *name* of the return variable doesn't change, then the test does + # not need to be re-run. We keep an internal count which we + # increment to guarantee that every test name is unique. If we've + # gotten here, then the configuration has changed enough that the + # test *needs* to be rerun. + if (NOT MULTIPASS_TEST_COUNT) + set (MULTIPASS_TEST_COUNT 00) + endif (NOT MULTIPASS_TEST_COUNT) + math (EXPR _tmp "${MULTIPASS_TEST_COUNT} + 1") # Why can't I add to a cache variable? + set (MULTIPASS_TEST_COUNT ${_tmp} CACHE INTERNAL "Unique test ID") + set (testname MULTIPASS_TEST_${MULTIPASS_TEST_COUNT}_${runs}) + set (CMAKE_REQUIRED_INCLUDES ${includes}) + set (CMAKE_REQUIRED_LIBRARIES ${libraries}) + if(${language} STREQUAL "C") + check_c_source_runs ("${source}" ${testname}) + elseif(${language} STREQUAL "CXX") + check_cxx_source_runs ("${source}" ${testname}) + endif() + set (${runs} "${${testname}}") +endmacro (MULTIPASS_SOURCE_RUNS) + +macro (MULTIPASS_C_SOURCE_RUNS includes libraries source runs) + multipass_source_runs("${includes}" "${libraries}" "${source}" ${runs} "C") +endmacro (MULTIPASS_C_SOURCE_RUNS) diff --git a/cmake/ResolveCompilerPaths.cmake b/cmake/ResolveCompilerPaths.cmake new file mode 100644 index 0000000000..54787fa38f --- /dev/null +++ b/cmake/ResolveCompilerPaths.cmake @@ -0,0 +1,105 @@ +# ResolveCompilerPaths - this module defines two macros +# +# RESOLVE_LIBRARIES (XXX_LIBRARIES LINK_LINE) +# This macro is intended to be used by FindXXX.cmake modules. +# It parses a compiler link line and resolves all libraries +# (-lfoo) using the library path contexts (-L/path) in scope. +# The result in XXX_LIBRARIES is the list of fully resolved libs. +# Example: +# +# RESOLVE_LIBRARIES (FOO_LIBRARIES "-L/A -la -L/B -lb -lc -ld") +# +# will be resolved to +# +# FOO_LIBRARIES:STRING="/A/liba.so;/B/libb.so;/A/libc.so;/usr/lib/libd.so" +# +# if the filesystem looks like +# +# /A: liba.so libc.so +# /B: liba.so libb.so +# /usr/lib: liba.so libb.so libc.so libd.so +# +# and /usr/lib is a system directory. +# +# Note: If RESOLVE_LIBRARIES() resolves a link line differently from +# the native linker, there is a bug in this macro (please report it). +# +# RESOLVE_INCLUDES (XXX_INCLUDES INCLUDE_LINE) +# This macro is intended to be used by FindXXX.cmake modules. +# It parses a compile line and resolves all includes +# (-I/path/to/include) to a list of directories. Other flags are ignored. +# Example: +# +# RESOLVE_INCLUDES (FOO_INCLUDES "-I/A -DBAR='\"irrelevant -I/string here\"' -I/B") +# +# will be resolved to +# +# FOO_INCLUDES:STRING="/A;/B" +# +# assuming both directories exist. +# Note: as currently implemented, the -I/string will be picked up mistakenly (cry, cry) +include (CorrectWindowsPaths) + +macro (RESOLVE_LIBRARIES LIBS LINK_LINE) + string (REGEX MATCHALL "((-L|-l|-Wl)([^\" ]+|\"[^\"]+\")|[^\" ]+\\.(a|so|dll|lib))" _all_tokens "${LINK_LINE}") + set (_libs_found "") + set (_directory_list "") + foreach (token ${_all_tokens}) + if (token MATCHES "-L([^\" ]+|\"[^\"]+\")") + # If it's a library path, add it to the list + string (REGEX REPLACE "^-L" "" token ${token}) + string (REGEX REPLACE "//" "/" token ${token}) + convert_cygwin_path(token) + list (APPEND _directory_list ${token}) + elseif (token MATCHES "^(-l([^\" ]+|\"[^\"]+\")|[^\" ]+\\.(a|so|dll|lib))") + # It's a library, resolve the path by looking in the list and then (by default) in system directories + if (WIN32) #windows expects "libfoo", linux expects "foo" + string (REGEX REPLACE "^-l" "lib" token ${token}) + else (WIN32) + string (REGEX REPLACE "^-l" "" token ${token}) + endif (WIN32) + set (_root "") + if (token MATCHES "^/") # We have an absolute path + #separate into a path and a library name: + string (REGEX MATCH "[^/]*\\.(a|so|dll|lib)$" libname ${token}) + string (REGEX MATCH ".*[^${libname}$]" libpath ${token}) + convert_cygwin_path(libpath) + set (_directory_list ${_directory_list} ${libpath}) + set (token ${libname}) + endif (token MATCHES "^/") + set (_lib "NOTFOUND" CACHE FILEPATH "Cleared" FORCE) + find_library (_lib ${token} HINTS ${_directory_list} ${_root}) + if (_lib) + string (REPLACE "//" "/" _lib ${_lib}) + list (APPEND _libs_found ${_lib}) + else (_lib) + message (STATUS "Unable to find library ${token}") + endif (_lib) + endif (token MATCHES "-L([^\" ]+|\"[^\"]+\")") + endforeach (token) + set (_lib "NOTFOUND" CACHE INTERNAL "Scratch variable" FORCE) + # only the LAST occurence of each library is required since there should be no circular dependencies + if (_libs_found) + list (REVERSE _libs_found) + list (REMOVE_DUPLICATES _libs_found) + list (REVERSE _libs_found) + endif (_libs_found) + set (${LIBS} "${_libs_found}") +endmacro (RESOLVE_LIBRARIES) + +macro (RESOLVE_INCLUDES INCS COMPILE_LINE) + string (REGEX MATCHALL "-I([^\" ]+|\"[^\"]+\")" _all_tokens "${COMPILE_LINE}") + set (_incs_found "") + foreach (token ${_all_tokens}) + string (REGEX REPLACE "^-I" "" token ${token}) + string (REGEX REPLACE "//" "/" token ${token}) + convert_cygwin_path(token) + if (EXISTS ${token}) + list (APPEND _incs_found ${token}) + else (EXISTS ${token}) + message (STATUS "Include directory ${token} does not exist") + endif (EXISTS ${token}) + endforeach (token) + list (REMOVE_DUPLICATES _incs_found) + set (${INCS} "${_incs_found}") +endmacro (RESOLVE_INCLUDES) From e584aeb642d8a9128dbd71993f4bdb39f6be4711 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 23 Apr 2019 23:52:19 +0200 Subject: [PATCH 1317/1783] Move Gridfile::get implementations for Field3D/Field2D to .cxx Intel compilers don't instantiate the getField templates when they are called in the .hxx file rather than the .cxx. This commit moves the implementations from .hxx to .cxx to work around this. --- include/bout/griddata.hxx | 8 ++------ src/mesh/data/gridfromfile.cxx | 7 +++++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index d269544e58..f88a15ac21 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -89,12 +89,8 @@ public: bool get(Mesh *m, int &ival, const std::string &name) override; ///< Get an integer bool get(Mesh *m, BoutReal &rval, const std::string &name) override; ///< Get a BoutReal number - bool get(Mesh *m, Field2D &var, const std::string &name, BoutReal def = 0.0) override { - return getField(m, var, name, def); - } - bool get(Mesh *m, Field3D &var, const std::string &name, BoutReal def = 0.0) override { - return getField(m, var, name, def); - } + bool get(Mesh *m, Field2D &var, const std::string &name, BoutReal def = 0.0) override; + bool get(Mesh *m, Field3D &var, const std::string &name, BoutReal def = 0.0) override; bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, GridDataSource::Direction dir = GridDataSource::X) override; diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index bbdbf1d607..3dc18a8af1 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -176,6 +176,13 @@ bool GridFile::get(Mesh *UNUSED(m), BoutReal &rval, const std::string &name) { * Successfully reads Field2D if the variable in the file is 0-D or 2-D. * Successfully reads Field3D if the variable in the file is 0-D, 2-D or 3-D. */ +bool GridFile::get(Mesh *m, Field2D &var, const std::string &name, BoutReal def) { + return getField(m, var, name, def); +} +bool GridFile::get(Mesh *m, Field3D &var, const std::string &name, BoutReal def) { + return getField(m, var, name, def); +} + template bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) { static_assert(std::is_base_of::value || std::is_base_of::value, From 20afc6264703db0ffc5231b1db837dda342454cb Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 24 Apr 2019 15:32:56 +0100 Subject: [PATCH 1318/1783] Link PVODE against MPI --- externalpackages/PVODE/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/externalpackages/PVODE/CMakeLists.txt b/externalpackages/PVODE/CMakeLists.txt index 443dd1f373..2206f4c55b 100644 --- a/externalpackages/PVODE/CMakeLists.txt +++ b/externalpackages/PVODE/CMakeLists.txt @@ -11,6 +11,8 @@ project(PVODE VERSION 0.1 LANGUAGES CXX) +find_package(MPI REQUIRED) + add_library(pvode source/cvode.cpp source/nvector.cpp @@ -34,6 +36,7 @@ add_library(pvode ) target_include_directories(pvode PUBLIC include) +target_link_libraries(pvode PUBLIC MPI::MPI_CXX) add_library(pvpre precon/pvbbdpre.cpp @@ -43,3 +46,4 @@ add_library(pvpre ) target_include_directories(pvpre PUBLIC include) +target_link_libraries(pvpre PUBLIC MPI::MPI_CXX) From 7ccf0726e540bd0a8530fac0f453d72cd921f387 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 24 Apr 2019 15:33:28 +0100 Subject: [PATCH 1319/1783] Add various configure-time options to CMake --- CMakeLists.txt | 97 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e9d6c9a45e..6da302e974 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -284,7 +284,6 @@ target_link_libraries(bout PUBLIC MPI::MPI_CXX pvode pvpre mpark_variant) target_include_directories(bout PUBLIC include) target_compile_definitions(bout - PUBLIC "CHECK=3" PUBLIC "BOUT_VERSION_STRING=\"4.2.2\"" PUBLIC "BOUT_VERSION_DOUBLE=4.22" PUBLIC "BOUT_HAS_PVODE" @@ -293,12 +292,92 @@ target_compile_definitions(bout target_compile_features(bout PUBLIC cxx_std_11) set_target_properties(bout PROPERTIES CXX_EXTENSIONS OFF) +# Compile time features + +set(CHECK_LEVELS 0 1 2 3 4) +set(CHECK 3 CACHE STRINGS "Set run-time checking level") +set_property(CACHE CHECK PROPERTY STRINGS ${CHECK_LEVELS}) +if (NOT CHECK IN_LIST CHECK_LEVELS) + message(FATAL_ERROR "CHECK must be one of ${CHECK_LEVELS}") +endif() +message(STATUS "Runtime checking level: CHECK=${CHECK}") +target_compile_definitions(bout + PUBLIC "CHECK=${CHECK}") + +option(ENABLE_SIGNAL "SegFault handling" ON) +if (ENABLE_SIGNAL) + target_compile_definitions(bout + PUBLIC "SIGHANDLE") +endif() +message(STATUS "Signal handling: SIGHANDLE=${ENABLE_SIGNAL}") + +option(ENABLE_COLOR "Output coloring" ON) +if (ENABLE_COLOR) + target_compile_definitions(bout + PUBLIC "LOGCOLOR") +endif() +message(STATUS "Output coloring: LOGCOLOR=${ENABLE_COLOR}") + +option(ENABLE_TRACK "Field name tracking" ON) +if (ENABLE_TRACK) + target_compile_definitions(bout + PUBLIC "TRACK") +endif() +message(STATUS "Field name tracking: TRACK=${ENABLE_TRACK}") + +option(ENABLE_SIGFPE "Signalling floating point exceptions" ON) +if (ENABLE_SIGFPE) + target_compile_definitions(bout + PUBLIC "BOUT_FPE") +endif() +message(STATUS "Signalling floating point exceptions: BOUT_FPE=${ENABLE_SIGFPE}") + +option(ENABLE_BACKTRACE "Enable backtrace" ON) +if (ENABLE_BACKTRACE) + find_program(ADDR2LINE_FOUND addr2line) + if (NOT ADDR2LINE_FOUND) + message(FATAL_ERROR "addr2line not found") + endif() + target_compile_definitions(bout + PUBLIC "BACKTRACE") + target_link_libraries(bout PUBLIC ${CMAKE_DL_LIBS}) +endif() +message(STATUS "Enable backtrace: SIGHANDLE=${ENABLE_BACKTRACE}") + +option(ENABLE_OPENMP "Enable OpenMP support" OFF) +if (ENABLE_OPENMP) + find_package(OpenMP) + if (OpenMP_CXX_FOUND) + target_link_libraries(bout PUBLIC OpenMP::OpenMP_CXX) + else() + message(FATAL_ERROR "OpenMP support requested but could not be enabled") + endif() + set(possible_openmp_schedules static dynamic guided auto) + set(OPENMP_SCHEDULE static CACHE STRINGS "Set OpenMP schedule") + if (NOT OPENMP_SCHEDULE IN_LIST possible_openmp_schedules) + message(FATAL_ERROR "OPENMP_SCHEDULE must be one of ${possible_openmp_schedules}") + endif() + target_compile_definitions(bout + PUBLIC "OPENMP_SCHEDULE=${OPENMP_SCHEDULE}") + message(STATUS "OpenMP schedule: ${OPENMP_SCHEDULE}") +endif() +message(STATUS "Enable OpenMP: ${ENABLE_OPENMP}") + +include(GetGitRevisionDescription) +get_git_head_revision(GIT_REFSPEC GIT_SHA1) +message(STATUS "Git revision: ${GIT_SHA1}") +target_compile_definitions(bout + PUBLIC "GIT_REVISION=${GIT_SHA1}") + +# Optional dependencies + find_package(NetCDF) if (NetCDF_FOUND) target_compile_definitions(bout PUBLIC "NCDF4") target_link_libraries(bout PUBLIC NetCDF::NetCDF) endif() +message(STATUS "NetCDF support: ${NetCDF_FOUND}") find_package(FFTW) if (FFTW_FOUND) @@ -306,6 +385,7 @@ if (FFTW_FOUND) PUBLIC "BOUT_HAS_FFTW") target_link_libraries(bout PUBLIC FFTW::FFTW) endif() +message(STATUS "FFTW support: ${FFTW_FOUND}") find_package(LAPACK) if (LAPACK_FOUND) @@ -313,6 +393,7 @@ if (LAPACK_FOUND) PUBLIC "LAPACK") target_link_libraries(bout PUBLIC "${LAPACK_LIBRARIES}") endif() +message(STATUS "LAPACK support: ${LAPACK_FOUND}") find_package(PETSc) if (PETSC_FOUND) @@ -320,6 +401,20 @@ if (PETSC_FOUND) PUBLIC "BOUT_HAS_PETSC") target_link_libraries(bout PUBLIC PETSC::PETSc) endif() +message(STATUS "PETSc support: ${PETSC_FOUND}") + +find_package(Gettext) +if (GETTEXT_FOUND) + target_compile_definitions(bout + PUBLIC "BOUT_HAS_GETTEXT") + find_package(Intl) + if (Intl_FOUND) + target_link_libraries(bout + PUBLIC ${Intl_LIBRARIES}) + target_include_directories(bout + PUBLIC ${Intl_INCLUDE_DIRS}) + endif() +endif() macro(bout_add_integrated_test TESTNAME) add_executable(${TESTNAME} ${ARGN}) From cc43d708a5aae7ee9037854d5b4db5285f1d3deb Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 24 Apr 2019 15:33:45 +0100 Subject: [PATCH 1320/1783] Make boutexception test more flexible for name of executable --- tests/unit/sys/test_boutexception.cxx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/unit/sys/test_boutexception.cxx b/tests/unit/sys/test_boutexception.cxx index 842870baae..13991f285b 100644 --- a/tests/unit/sys/test_boutexception.cxx +++ b/tests/unit/sys/test_boutexception.cxx @@ -1,5 +1,6 @@ #include "gtest/gtest.h" #include "boutexception.hxx" +#include "test_extras.hxx" #include #include @@ -29,13 +30,16 @@ TEST(BoutExceptionTest, GetBacktrace) { try { throw BoutException(test_message); } catch (const BoutException &e) { - std::string expected{"[bt] #1 ./serial_tests"}; + std::string expected_1{"[bt] #1"}; + std::string expected_2{"serial_tests"}; #ifdef BACKTRACE // Should be able to find something about backtrace - EXPECT_NE(e.getBacktrace().find(expected), std::string::npos); + EXPECT_TRUE(IsSubString(e.getBacktrace(), expected_1)); + EXPECT_TRUE(IsSubString(e.getBacktrace(), expected_2)); #else // Should *not* be able to find something about backtrace - EXPECT_EQ(e.getBacktrace().find(expected), std::string::npos); + EXPECT_FALSE(IsSubString(e.getBacktrace(), expected_1)); + EXPECT_FALSE(IsSubString(e.getBacktrace(), expected_2)); #endif } } From a9577d022eea46ce06f8172315faf21c46100a8e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 24 Apr 2019 15:35:14 +0100 Subject: [PATCH 1321/1783] Update required Jinja2 version to avoid CVE-2019-10906 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 74bee944c2..475bd0a605 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -Jinja2==2.9.6 +Jinja2==2.10.1 numpy>=1.14.1 scipy>=1.0.0 netcdf4>=1.3.1 From a64a6ecf8082ce65611aa3f222969e1d43b76f75 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 25 Apr 2019 15:40:43 +0100 Subject: [PATCH 1322/1783] Add SUNDIALS to CMake --- CMakeLists.txt | 15 ++++++ cmake/FindSUNDIALS.cmake | 95 +++++++++++++++++++++++++++++++++ cmake/tests/arkode_int_type.cxx | 3 ++ cmake/tests/cvode_int_type.cxx | 3 ++ cmake/tests/ida_int_type.cxx | 3 ++ 5 files changed, 119 insertions(+) create mode 100644 cmake/FindSUNDIALS.cmake create mode 100644 cmake/tests/arkode_int_type.cxx create mode 100644 cmake/tests/cvode_int_type.cxx create mode 100644 cmake/tests/ida_int_type.cxx diff --git a/CMakeLists.txt b/CMakeLists.txt index 6da302e974..c0a7ed14b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -403,6 +403,21 @@ if (PETSC_FOUND) endif() message(STATUS "PETSc support: ${PETSC_FOUND}") +find_package(SUNDIALS) +if (SUNDIALS_FOUND) + target_compile_definitions(bout + PUBLIC "BOUT_HAS_CVODE" + PUBLIC "CVODEINT=${SUNDIALS_cvode_INT}" + PUBLIC "BOUT_HAS_IDA" + PUBLIC "IDAINT=${SUNDIALS_ida_INT}" + PUBLIC "BOUT_HAS_ARKODE" + PUBLIC "ARKODEINT=${SUNDIALS_arkode_INT}") + target_link_libraries(bout PUBLIC SUNDIALS_cvode::cvode) + target_link_libraries(bout PUBLIC SUNDIALS_ida::ida) + target_link_libraries(bout PUBLIC SUNDIALS_arkode::arkode) +endif() +message(STATUS "SUNDIALS support: ${SUNDIALS_FOUND}") + find_package(Gettext) if (GETTEXT_FOUND) target_compile_definitions(bout diff --git a/cmake/FindSUNDIALS.cmake b/cmake/FindSUNDIALS.cmake new file mode 100644 index 0000000000..a87156a1af --- /dev/null +++ b/cmake/FindSUNDIALS.cmake @@ -0,0 +1,95 @@ +include(FindPackageHandleStandardArgs) + +find_path(SUNDIALS_INCLUDE_DIR + sundials_config.h + HINTS ENV SUNDIALS_DIR + PATH_SUFFIXES include include/sundials + DOC "SUNDIALS Directory") + +if (SUNDIALS_INCLUDE_DIR) + message(STATUS "Found SUNDIALS include directory: ${SUNDIALS_INCLUDE_DIR}") +else() + message(STATUS "Could not find SUNDIALS include directory") +endif() + +set(SUNDIALS_INCLUDE_DIRS + "${SUNDIALS_INCLUDE_DIR}" + "${SUNDIALS_INCLUDE_DIR}/..") + +find_library(SUNDIALS_nvecparallel_LIBRARY + NAMES sundials_nvecparallel + HINTS "${SUNDIALS_INCLUDE_DIR}/../.." + PATH_SUFFIXES lib lib64 + ) + +if (SUNDIALS_nvecparallel_LIBRARY) + list(APPEND SUNDIALS_LIBRARIES "${SUNDIALS_nvecparallel_LIBRARY}") +endif() +mark_as_advanced(SUNDIALS_nvecparallel_LIBRARY) + + +set(SUNDIALS_COMPONENTS arkode cvode ida) +set(SUNDIALS_INT_TYPES int64_t;"long long";long;int32_t;int;) + +foreach (LIB ${SUNDIALS_COMPONENTS}) + find_library(SUNDIALS_${LIB}_LIBRARY + NAMES sundials_${LIB} + HINTS "${SUNDIALS_INCLUDE_DIR}/../.." + PATH_SUFFIXES lib lib64 + ) + + if (SUNDIALS_${LIB}_LIBRARY) + list(APPEND SUNDIALS_LIBRARIES "${SUNDIALS_${LIB}_LIBRARY}") + endif() + mark_as_advanced(SUNDIALS_${LIB}_LIBRARY) + + # Now we need to determine what size integer is being used for indices + + # We need to compile but not link a test file + set(OLD_CMAKE_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE}) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + + foreach (POSSIBLE_${LIB}INT ${SUNDIALS_INT_TYPES}) + string(TOUPPER ${LIB} UPPER_LIB) + try_compile(${LIB}_INT_SIZE_FOUND + "${CMAKE_BINARY_DIR}/temp" + SOURCES "${CMAKE_SOURCE_DIR}/cmake/tests/${LIB}_int_type.cxx" + CMAKE_FLAGS + "-DINCLUDE_DIRECTORIES=${SUNDIALS_INCLUDE_DIRS}" + COMPILE_DEFINITIONS + "-D${UPPER_LIB}INT=${POSSIBLE_${LIB}INT}" + LINK_LIBRARIES + "${SUNDIALS_${LIB}_LIBRARY}" + OUTPUT_VARIABLE ${LIB}_output) + # Uncomment the following for some debug output + # message(${${LIB}_output}) + if (${LIB}_INT_SIZE_FOUND) + set(SUNDIALS_${LIB}_INT "${POSSIBLE_${LIB}INT}") + message(STATUS "SUNDIALS_${LIB}_INT is ${POSSIBLE_${LIB}INT}") + break() + endif() + endforeach() + + # Restore old value so we don't interfere with other tests + set(CMAKE_TRY_COMPILE_TARGET_TYPE ${OLD_CMAKE_TRY_COMPILE_TARGET_TYPE}) +endforeach() + +find_package_handle_standard_args(SUNDIALS + REQUIRED_VARS SUNDIALS_LIBRARIES SUNDIALS_INCLUDE_DIR SUNDIALS_INCLUDE_DIRS) + +mark_as_advanced(SUNDIALS_LIBRARIES SUNDIALS_INCLUDE_DIR SUNDIALS_INCLUDE_DIRS) + +if (SUNDIALS_FOUND AND NOT TARGET SUNDIALS::SUNDIALS) + add_library(SUNDIALS::NVecParallel UNKNOWN IMPORTED) + set_target_properties(SUNDIALS::NVecParallel PROPERTIES + IMPORTED_LOCATION "${SUNDIALS_nvecparallel_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${SUNDIALS_INCLUDE_DIRS}") + + foreach (LIB ${SUNDIALS_COMPONENTS}) + add_library(SUNDIALS_${LIB}::${LIB} UNKNOWN IMPORTED) + target_link_libraries(SUNDIALS_${LIB}::${LIB} INTERFACE SUNDIALS::NVecParallel) + set_target_properties(SUNDIALS_${LIB}::${LIB} PROPERTIES + IMPORTED_LOCATION "${SUNDIALS_${LIB}_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${SUNDIALS_INCLUDE_DIRS}") + endforeach() +endif() diff --git a/cmake/tests/arkode_int_type.cxx b/cmake/tests/arkode_int_type.cxx new file mode 100644 index 0000000000..e6891cca74 --- /dev/null +++ b/cmake/tests/arkode_int_type.cxx @@ -0,0 +1,3 @@ +#include +extern int arkode_bbd_rhs(ARKODEINT, double, N_Vector, N_Vector, void*); +int main() { ARKBBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, arkode_bbd_rhs, nullptr); } diff --git a/cmake/tests/cvode_int_type.cxx b/cmake/tests/cvode_int_type.cxx new file mode 100644 index 0000000000..dc372dbfc7 --- /dev/null +++ b/cmake/tests/cvode_int_type.cxx @@ -0,0 +1,3 @@ +#include +extern int cvode_bbd_rhs(CVODEINT, double, N_Vector, N_Vector, void*); +int main() { CVBBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, cvode_bbd_rhs, nullptr); } diff --git a/cmake/tests/ida_int_type.cxx b/cmake/tests/ida_int_type.cxx new file mode 100644 index 0000000000..b7505797a5 --- /dev/null +++ b/cmake/tests/ida_int_type.cxx @@ -0,0 +1,3 @@ +#include +extern int ida_bbd_rhs(IDAINT, double, N_Vector, N_Vector, N_Vector, void*); +int main() { IDABBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, ida_bbd_rhs, nullptr); } From 7888b8fadb6304a9e5ccf54d287655ca410661d7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 25 Apr 2019 16:21:39 +0100 Subject: [PATCH 1323/1783] Simplify CMake SUNDIALS config by directly checking integer type Adds `bout::utils::function_traits` to allow getting types of function arguments. This is then used to get the type of the argument for the various SUNDIALS user functions. In later versions of SUNDIALS this is provided by the typedef `sunindextype` which we can use directly. This removes the need for the preprocessor macros CVODEINT etc --- CMakeLists.txt | 5 +---- cmake/FindSUNDIALS.cmake | 31 ------------------------------ cmake/tests/arkode_int_type.cxx | 3 --- cmake/tests/cvode_int_type.cxx | 3 --- cmake/tests/ida_int_type.cxx | 3 --- include/utils.hxx | 30 +++++++++++++++++++++++++++++ src/solver/impls/arkode/arkode.cxx | 7 ++++++- src/solver/impls/cvode/cvode.cxx | 7 ++++++- src/solver/impls/ida/ida.cxx | 6 +++++- 9 files changed, 48 insertions(+), 47 deletions(-) delete mode 100644 cmake/tests/arkode_int_type.cxx delete mode 100644 cmake/tests/cvode_int_type.cxx delete mode 100644 cmake/tests/ida_int_type.cxx diff --git a/CMakeLists.txt b/CMakeLists.txt index c0a7ed14b1..87cc788236 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -407,11 +407,8 @@ find_package(SUNDIALS) if (SUNDIALS_FOUND) target_compile_definitions(bout PUBLIC "BOUT_HAS_CVODE" - PUBLIC "CVODEINT=${SUNDIALS_cvode_INT}" PUBLIC "BOUT_HAS_IDA" - PUBLIC "IDAINT=${SUNDIALS_ida_INT}" - PUBLIC "BOUT_HAS_ARKODE" - PUBLIC "ARKODEINT=${SUNDIALS_arkode_INT}") + PUBLIC "BOUT_HAS_ARKODE") target_link_libraries(bout PUBLIC SUNDIALS_cvode::cvode) target_link_libraries(bout PUBLIC SUNDIALS_ida::ida) target_link_libraries(bout PUBLIC SUNDIALS_arkode::arkode) diff --git a/cmake/FindSUNDIALS.cmake b/cmake/FindSUNDIALS.cmake index a87156a1af..ca129068ff 100644 --- a/cmake/FindSUNDIALS.cmake +++ b/cmake/FindSUNDIALS.cmake @@ -27,7 +27,6 @@ if (SUNDIALS_nvecparallel_LIBRARY) endif() mark_as_advanced(SUNDIALS_nvecparallel_LIBRARY) - set(SUNDIALS_COMPONENTS arkode cvode ida) set(SUNDIALS_INT_TYPES int64_t;"long long";long;int32_t;int;) @@ -42,36 +41,6 @@ foreach (LIB ${SUNDIALS_COMPONENTS}) list(APPEND SUNDIALS_LIBRARIES "${SUNDIALS_${LIB}_LIBRARY}") endif() mark_as_advanced(SUNDIALS_${LIB}_LIBRARY) - - # Now we need to determine what size integer is being used for indices - - # We need to compile but not link a test file - set(OLD_CMAKE_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE}) - set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) - - foreach (POSSIBLE_${LIB}INT ${SUNDIALS_INT_TYPES}) - string(TOUPPER ${LIB} UPPER_LIB) - try_compile(${LIB}_INT_SIZE_FOUND - "${CMAKE_BINARY_DIR}/temp" - SOURCES "${CMAKE_SOURCE_DIR}/cmake/tests/${LIB}_int_type.cxx" - CMAKE_FLAGS - "-DINCLUDE_DIRECTORIES=${SUNDIALS_INCLUDE_DIRS}" - COMPILE_DEFINITIONS - "-D${UPPER_LIB}INT=${POSSIBLE_${LIB}INT}" - LINK_LIBRARIES - "${SUNDIALS_${LIB}_LIBRARY}" - OUTPUT_VARIABLE ${LIB}_output) - # Uncomment the following for some debug output - # message(${${LIB}_output}) - if (${LIB}_INT_SIZE_FOUND) - set(SUNDIALS_${LIB}_INT "${POSSIBLE_${LIB}INT}") - message(STATUS "SUNDIALS_${LIB}_INT is ${POSSIBLE_${LIB}INT}") - break() - endif() - endforeach() - - # Restore old value so we don't interfere with other tests - set(CMAKE_TRY_COMPILE_TARGET_TYPE ${OLD_CMAKE_TRY_COMPILE_TARGET_TYPE}) endforeach() find_package_handle_standard_args(SUNDIALS diff --git a/cmake/tests/arkode_int_type.cxx b/cmake/tests/arkode_int_type.cxx deleted file mode 100644 index e6891cca74..0000000000 --- a/cmake/tests/arkode_int_type.cxx +++ /dev/null @@ -1,3 +0,0 @@ -#include -extern int arkode_bbd_rhs(ARKODEINT, double, N_Vector, N_Vector, void*); -int main() { ARKBBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, arkode_bbd_rhs, nullptr); } diff --git a/cmake/tests/cvode_int_type.cxx b/cmake/tests/cvode_int_type.cxx deleted file mode 100644 index dc372dbfc7..0000000000 --- a/cmake/tests/cvode_int_type.cxx +++ /dev/null @@ -1,3 +0,0 @@ -#include -extern int cvode_bbd_rhs(CVODEINT, double, N_Vector, N_Vector, void*); -int main() { CVBBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, cvode_bbd_rhs, nullptr); } diff --git a/cmake/tests/ida_int_type.cxx b/cmake/tests/ida_int_type.cxx deleted file mode 100644 index b7505797a5..0000000000 --- a/cmake/tests/ida_int_type.cxx +++ /dev/null @@ -1,3 +0,0 @@ -#include -extern int ida_bbd_rhs(IDAINT, double, N_Vector, N_Vector, N_Vector, void*); -int main() { IDABBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, ida_bbd_rhs, nullptr); } diff --git a/include/utils.hxx b/include/utils.hxx index fcc85a4a2b..92ca151563 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -82,6 +82,36 @@ typename _Unique_if::_Known_bound make_unique(Args&&...) = delete; #else using std::make_unique; #endif + +template +struct function_traits; + +/// Traits class to get the types of function arguments for function pointers +/// +/// Use like: +/// +// // A function signature we'd like to check: +/// using some_function = int(*)(int, double, std::string); +/// // Get the type of the first argument: +/// using first_argument_type = +/// bout::utils::function_traits::arg<1>::type; +/// // The following prints "true": +/// std::cout << std::boolalpha +/// << std::is_same::value; +/// +/// Adapted from https://stackoverflow.com/a/9065203/2043465 +template +struct function_traits { + /// Total number of arguments + static constexpr size_t nargs = sizeof...(Args); + + using result_type = R; + + template + struct arg { + using type = typename std::tuple_element>::type; + }; +}; } // namespace utils } // namespace bout diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index 747288e499..514987d16a 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -37,6 +37,7 @@ #include "output.hxx" #include "unused.hxx" #include "bout/mesh.hxx" +#include "utils.hxx" #if SUNDIALS_VERSION_MAJOR >= 4 #include @@ -65,7 +66,11 @@ class Field2D; #define ONE RCONST(1.0) #ifndef ARKODEINT -using ARKODEINT = int; +#if SUNDIALS_VERSION_MAJOR < 3 +using ARKODEINT = bout::utils::function_traits::arg<0>::type; +#else +using ARKODEINT = sunindextype; +#endif #endif static int arkode_rhs_explicit(BoutReal t, N_Vector u, N_Vector du, void* user_data); diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index 682de9bcc4..a3eb4f8ab0 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -36,6 +36,7 @@ #include "output.hxx" #include "unused.hxx" #include "bout/mesh.hxx" +#include "utils.hxx" #include @@ -60,7 +61,11 @@ class Field2D; #define ONE RCONST(1.0) #ifndef CVODEINT -using CVODEINT = int; +#if SUNDIALS_VERSION_MAJOR < 3 +using CVODEINT = bout::utils::function_traits::arg<0>::type; +#else +using CVODEINT = sunindextype; +#endif #endif static int cvode_rhs(BoutReal t, N_Vector u, N_Vector du, void* user_data); diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index 9bbc34dd77..219db38b37 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -56,7 +56,11 @@ #define ONE RCONST(1.0) #ifndef IDAINT -using IDAINT = int; +#if SUNDIALS_VERSION_MAJOR < 3 +using IDAINT = bout::utils::function_traits::arg<0>::type; +#else +using IDAINT = sunindextype; +#endif #endif static int idares(BoutReal t, N_Vector u, N_Vector du, N_Vector rr, void* user_data); From 89cd2c11bb4587438ab5b2e40362939731543a9c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 25 Apr 2019 17:43:17 +0100 Subject: [PATCH 1324/1783] Bugfix: use region in Coordinates::calcCovariant/calcContravariant --- include/bout/coordinates.hxx | 6 ++- src/mesh/coordinates.cxx | 94 ++++++++++++++++-------------------- 2 files changed, 46 insertions(+), 54 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index 48e8d5725c..819a82f438 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -114,8 +114,10 @@ public: /// Calculate differential geometry quantities from the metric tensor int geometry(bool recalculate_staggered = true, bool force_interpolate_from_centre = false); - int calcCovariant(); ///< Inverts contravatiant metric to get covariant - int calcContravariant(); ///< Invert covariant metric to get contravariant + /// Invert contravatiant metric to get covariant components + int calcCovariant(const std::string& region = "RGN_ALL"); + /// Invert covariant metric to get contravariant components + int calcContravariant(const std::string& region = "RGN_ALL"); int jacobian(); ///< Calculate J and Bxy diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index a07f286de5..27e8803839 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -313,13 +313,13 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) output_warn.write("Not all covariant components of metric tensor found. " "Calculating all from the contravariant tensor\n"); /// Calculate contravariant metric components if not found - if (calcCovariant()) { + if (calcCovariant("RGN_NOBNDRY")) { throw BoutException("Error in calcCovariant call"); } } } else { /// Calculate contravariant metric components if not found - if (calcCovariant()) { + if (calcCovariant("RGN_NOBNDRY")) { throw BoutException("Error in calcCovariant call"); } } @@ -497,13 +497,13 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, output_warn.write("Not all staggered covariant components of metric tensor found. " "Calculating all from the contravariant tensor\n"); /// Calculate contravariant metric components if not found - if (calcCovariant()) { + if (calcCovariant("RGN_NOBNDRY")) { throw BoutException("Error in staggered calcCovariant call"); } } } else { /// Calculate contravariant metric components if not found - if (calcCovariant()) { + if (calcCovariant("RGN_NOBNDRY")) { throw BoutException("Error in staggered calcCovariant call"); } } @@ -877,7 +877,7 @@ int Coordinates::geometry(bool recalculate_staggered, return 0; } -int Coordinates::calcCovariant() { +int Coordinates::calcCovariant(const std::string& region) { TRACE("Coordinates::calcCovariant"); // Make sure metric elements are allocated @@ -900,32 +900,27 @@ int Coordinates::calcCovariant() { auto a = Matrix(3, 3); - for (int jx = 0; jx < localmesh->LocalNx; jx++) { - for (int jy = 0; jy < localmesh->LocalNy; jy++) { - // set elements of g - a(0, 0) = g11(jx, jy); - a(1, 1) = g22(jx, jy); - a(2, 2) = g33(jx, jy); - - a(0, 1) = a(1, 0) = g12(jx, jy); - a(1, 2) = a(2, 1) = g23(jx, jy); - a(0, 2) = a(2, 0) = g13(jx, jy); - - // invert - if (invert3x3(a)) { - output_error.write("\tERROR: metric tensor is singular at (%d, %d)\n", jx, jy); - return 1; - } + BOUT_FOR_SERIAL(i, g11.getRegion(region)) { + a(0, 0) = g11[i]; + a(1, 1) = g22[i]; + a(2, 2) = g33[i]; - // put elements into g_{ij} - g_11(jx, jy) = a(0, 0); - g_22(jx, jy) = a(1, 1); - g_33(jx, jy) = a(2, 2); + a(0, 1) = a(1, 0) = g12[i]; + a(1, 2) = a(2, 1) = g23[i]; + a(0, 2) = a(2, 0) = g13[i]; - g_12(jx, jy) = a(0, 1); - g_13(jx, jy) = a(0, 2); - g_23(jx, jy) = a(1, 2); + if (invert3x3(a)) { + output_error.write("\tERROR: metric tensor is singular at (%d, %d)\n", i.x(), i.y()); + return 1; } + + g_11[i] = a(0, 0); + g_22[i] = a(1, 1); + g_33[i] = a(2, 2); + + g_12[i] = a(0, 1); + g_13[i] = a(0, 2); + g_23[i] = a(1, 2); } BoutReal maxerr; @@ -944,7 +939,7 @@ int Coordinates::calcCovariant() { return 0; } -int Coordinates::calcContravariant() { +int Coordinates::calcContravariant(const std::string& region) { TRACE("Coordinates::calcContravariant"); // Make sure metric elements are allocated @@ -960,32 +955,27 @@ int Coordinates::calcContravariant() { auto a = Matrix(3, 3); - for (int jx = 0; jx < localmesh->LocalNx; jx++) { - for (int jy = 0; jy < localmesh->LocalNy; jy++) { - // set elements of g - a(0, 0) = g_11(jx, jy); - a(1, 1) = g_22(jx, jy); - a(2, 2) = g_33(jx, jy); - - a(0, 1) = a(1, 0) = g_12(jx, jy); - a(1, 2) = a(2, 1) = g_23(jx, jy); - a(0, 2) = a(2, 0) = g_13(jx, jy); - - // invert - if (invert3x3(a)) { - output_error.write("\tERROR: metric tensor is singular at (%d, %d)\n", jx, jy); - return 1; - } + BOUT_FOR_SERIAL(i, g_11.getRegion(region)) { + a(0, 0) = g_11[i]; + a(1, 1) = g_22[i]; + a(2, 2) = g_33[i]; - // put elements into g_{ij} - g11(jx, jy) = a(0, 0); - g22(jx, jy) = a(1, 1); - g33(jx, jy) = a(2, 2); + a(0, 1) = a(1, 0) = g_12[i]; + a(1, 2) = a(2, 1) = g_23[i]; + a(0, 2) = a(2, 0) = g_13[i]; - g12(jx, jy) = a(0, 1); - g13(jx, jy) = a(0, 2); - g23(jx, jy) = a(1, 2); + if (invert3x3(a)) { + output_error.write("\tERROR: metric tensor is singular at (%d, %d)\n", i.x(), i.y()); + return 1; } + + g11[i] = a(0, 0); + g22[i] = a(1, 1); + g33[i] = a(2, 2); + + g12[i] = a(0, 1); + g13[i] = a(0, 2); + g23[i] = a(1, 2); } BoutReal maxerr; From 79cb33239c8a209bec1bdc917996bebf31749247 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 25 Apr 2019 17:58:44 +0100 Subject: [PATCH 1325/1783] Make bout_add_integrated_test work with runtest scripts --- CMakeLists.txt | 44 +++++++++++++++++-- tests/integrated/test-griddata/CMakeLists.txt | 5 +++ tests/integrated/test-initial/CMakeLists.txt | 5 +++ tests/integrated/test-initial/runtest | 1 + tests/integrated/test-solver/CMakeLists.txt | 4 +- 5 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 tests/integrated/test-griddata/CMakeLists.txt create mode 100644 tests/integrated/test-initial/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 87cc788236..7747831f47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -428,17 +428,53 @@ if (GETTEXT_FOUND) endif() endif() -macro(bout_add_integrated_test TESTNAME) - add_executable(${TESTNAME} ${ARGN}) +# Copy FILENAME from source directory to build directory +# and add dependency on TARGET +macro(bout_test_copy_file TARGET FILENAME) + add_custom_command(TARGET "${TARGET}" POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/"${FILENAME}" + ${CMAKE_CURRENT_BINARY_DIR}/"${FILENAME}") +endmacro() + +# Add a new integrated test +# +# Required arguments: +# - TESTNAME: name of the test +# - SOURCES: list of source files +# Optional arguments: +# - USE_RUNTEST: if given, the test uses `./runtest` as the test +# command, otherwise it uses the executable +function(bout_add_integrated_test TESTNAME) + set(options USE_RUNTEST USE_DATA_BOUT_INP) + set(multiValueArgs SOURCES EXTRA_FILES) + cmake_parse_arguments(BOUT_TEST_OPTIONS "${options}" "" "${multiValueArgs}" ${ARGN}) + add_executable(${TESTNAME} ${BOUT_TEST_OPTIONS_SOURCES}) target_link_libraries(${TESTNAME} bout) target_include_directories(${TESTNAME} PRIVATE $) - add_test(NAME ${TESTNAME} COMMAND ${TESTNAME}) + + if (BOUT_TEST_OPTIONS_USE_RUNTEST) + add_test(NAME ${TESTNAME} COMMAND ./runtest) + bout_test_copy_file("${TESTNAME}" runtest) + else() + add_test(NAME ${TESTNAME} COMMAND ${TESTNAME}) + endif() + if (BOUT_TEST_OPTIONS_USE_DATA_BOUT_INP) + bout_test_copy_file("${TESTNAME}" data/BOUT.inp) + endif() + if (BOUT_TEST_OPTIONS_EXTRA_FILES) + foreach (FILE "${BOUT_TEST_OPTIONS_EXTRA_FILES}") + bout_test_copy_file("${TESTNAME}" "${FILE}") + endforeach() + endif() set_target_properties(${TESTNAME} PROPERTIES FOLDER tests/integrated) -endmacro() +endfunction() option(PACKAGE_TESTS "Build the tests" ON) if(PACKAGE_TESTS) enable_testing() add_subdirectory(tests/unit) add_subdirectory(tests/integrated/test-solver) + add_subdirectory(tests/integrated/test-initial) + add_subdirectory(tests/integrated/test-griddata) endif() diff --git a/tests/integrated/test-griddata/CMakeLists.txt b/tests/integrated/test-griddata/CMakeLists.txt new file mode 100644 index 0000000000..2701ed41cc --- /dev/null +++ b/tests/integrated/test-griddata/CMakeLists.txt @@ -0,0 +1,5 @@ +bout_add_integrated_test(test_griddata + SOURCES test_griddata.cxx + USE_RUNTEST + EXTRA_FILES screw/BOUT.inp + ) diff --git a/tests/integrated/test-initial/CMakeLists.txt b/tests/integrated/test-initial/CMakeLists.txt new file mode 100644 index 0000000000..486f07bd18 --- /dev/null +++ b/tests/integrated/test-initial/CMakeLists.txt @@ -0,0 +1,5 @@ +bout_add_integrated_test(test_initial + SOURCES test_initial.cxx + USE_RUNTEST + USE_DATA_BOUT_INP + ) diff --git a/tests/integrated/test-initial/runtest b/tests/integrated/test-initial/runtest index cffeb872eb..a37d2238dc 100755 --- a/tests/integrated/test-initial/runtest +++ b/tests/integrated/test-initial/runtest @@ -145,6 +145,7 @@ sqrt = np.sqrt tan = np.tan TanhHat = tanhhat pi = np.pi +fmod = np.fmod ######################################## # Running the test diff --git a/tests/integrated/test-solver/CMakeLists.txt b/tests/integrated/test-solver/CMakeLists.txt index 706f473c11..d686b4be47 100644 --- a/tests/integrated/test-solver/CMakeLists.txt +++ b/tests/integrated/test-solver/CMakeLists.txt @@ -1,3 +1 @@ -bout_add_integrated_test(test_solver - test_solver.cxx - ) +bout_add_integrated_test(test_solver SOURCES test_solver.cxx) From 29b135ef19c850d6177a6512bfe375250e982150 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Apr 2019 10:32:40 +0100 Subject: [PATCH 1326/1783] Ignore CMake build directories --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e7abe2ab8b..e23b756987 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,5 @@ src/.libfast .*.mk *.mo .BOUT.pid.* +build/ +build*/ From ce65b65d7c3f6c1d7e021807b7b0d96ca854a367 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Apr 2019 10:32:52 +0100 Subject: [PATCH 1327/1783] Clean-up FindFFTW.cmake --- cmake/FindFFTW.cmake | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake index 8dc7d82b9d..d4ebc22818 100644 --- a/cmake/FindFFTW.cmake +++ b/cmake/FindFFTW.cmake @@ -14,16 +14,10 @@ find_package_handle_standard_args (FFTW DEFAULT_MSG FFTW_LIBRARIES FFTW_INCLUDES mark_as_advanced (FFTW_LIBRARIES FFTW_INCLUDES) -if (FFTW_FOUND) - if (NOT TARGET FFTW::FFTW) - add_library(FFTW::FFTW UNKNOWN IMPORTED) - set_target_properties(FFTW::FFTW PROPERTIES - IMPORTED_LOCATION "${FFTW_LIBRARIES}" - INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDES}" - ) - # set_target_properties(FFTW::FFTW PROPERTIES - # IMPORTED_LOCATION "${FFTW_LIBRARIES}" - # INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" - # ) - endif() +if (FFTW_FOUND AND NOT TARGET FFTW::FFTW) + add_library(FFTW::FFTW UNKNOWN IMPORTED) + set_target_properties(FFTW::FFTW PROPERTIES + IMPORTED_LOCATION "${FFTW_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDES}" + ) endif() From 0297c44a95f5bc216ee7758c55462ca2289da2ce Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Apr 2019 10:33:31 +0100 Subject: [PATCH 1328/1783] Rename CMake target to bout++ --- CMakeLists.txt | 65 ++++++++++++++++++++------------------- tests/unit/CMakeLists.txt | 2 +- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7747831f47..5b4a9e43bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -277,20 +277,21 @@ set(BOUT_SOURCES ./src/sys/utils.cxx ) -add_library(bout +add_library(bout++ ${BOUT_SOURCES} ) -target_link_libraries(bout PUBLIC MPI::MPI_CXX pvode pvpre mpark_variant) -target_include_directories(bout PUBLIC include) +add_library(bout++::bout++ ALIAS bout++) +target_link_libraries(bout++ PUBLIC MPI::MPI_CXX pvode pvpre mpark_variant) +target_include_directories(bout++ PUBLIC include) -target_compile_definitions(bout +target_compile_definitions(bout++ PUBLIC "BOUT_VERSION_STRING=\"4.2.2\"" PUBLIC "BOUT_VERSION_DOUBLE=4.22" PUBLIC "BOUT_HAS_PVODE" ) -target_compile_features(bout PUBLIC cxx_std_11) -set_target_properties(bout PROPERTIES CXX_EXTENSIONS OFF) +target_compile_features(bout++ PUBLIC cxx_std_11) +set_target_properties(bout++ PROPERTIES CXX_EXTENSIONS OFF) # Compile time features @@ -301,33 +302,33 @@ if (NOT CHECK IN_LIST CHECK_LEVELS) message(FATAL_ERROR "CHECK must be one of ${CHECK_LEVELS}") endif() message(STATUS "Runtime checking level: CHECK=${CHECK}") -target_compile_definitions(bout +target_compile_definitions(bout++ PUBLIC "CHECK=${CHECK}") option(ENABLE_SIGNAL "SegFault handling" ON) if (ENABLE_SIGNAL) - target_compile_definitions(bout + target_compile_definitions(bout++ PUBLIC "SIGHANDLE") endif() message(STATUS "Signal handling: SIGHANDLE=${ENABLE_SIGNAL}") option(ENABLE_COLOR "Output coloring" ON) if (ENABLE_COLOR) - target_compile_definitions(bout + target_compile_definitions(bout++ PUBLIC "LOGCOLOR") endif() message(STATUS "Output coloring: LOGCOLOR=${ENABLE_COLOR}") option(ENABLE_TRACK "Field name tracking" ON) if (ENABLE_TRACK) - target_compile_definitions(bout + target_compile_definitions(bout++ PUBLIC "TRACK") endif() message(STATUS "Field name tracking: TRACK=${ENABLE_TRACK}") option(ENABLE_SIGFPE "Signalling floating point exceptions" ON) if (ENABLE_SIGFPE) - target_compile_definitions(bout + target_compile_definitions(bout++ PUBLIC "BOUT_FPE") endif() message(STATUS "Signalling floating point exceptions: BOUT_FPE=${ENABLE_SIGFPE}") @@ -338,9 +339,9 @@ if (ENABLE_BACKTRACE) if (NOT ADDR2LINE_FOUND) message(FATAL_ERROR "addr2line not found") endif() - target_compile_definitions(bout + target_compile_definitions(bout++ PUBLIC "BACKTRACE") - target_link_libraries(bout PUBLIC ${CMAKE_DL_LIBS}) + target_link_libraries(bout++ PUBLIC ${CMAKE_DL_LIBS}) endif() message(STATUS "Enable backtrace: SIGHANDLE=${ENABLE_BACKTRACE}") @@ -348,7 +349,7 @@ option(ENABLE_OPENMP "Enable OpenMP support" OFF) if (ENABLE_OPENMP) find_package(OpenMP) if (OpenMP_CXX_FOUND) - target_link_libraries(bout PUBLIC OpenMP::OpenMP_CXX) + target_link_libraries(bout++ PUBLIC OpenMP::OpenMP_CXX) else() message(FATAL_ERROR "OpenMP support requested but could not be enabled") endif() @@ -357,7 +358,7 @@ if (ENABLE_OPENMP) if (NOT OPENMP_SCHEDULE IN_LIST possible_openmp_schedules) message(FATAL_ERROR "OPENMP_SCHEDULE must be one of ${possible_openmp_schedules}") endif() - target_compile_definitions(bout + target_compile_definitions(bout++ PUBLIC "OPENMP_SCHEDULE=${OPENMP_SCHEDULE}") message(STATUS "OpenMP schedule: ${OPENMP_SCHEDULE}") endif() @@ -366,64 +367,64 @@ message(STATUS "Enable OpenMP: ${ENABLE_OPENMP}") include(GetGitRevisionDescription) get_git_head_revision(GIT_REFSPEC GIT_SHA1) message(STATUS "Git revision: ${GIT_SHA1}") -target_compile_definitions(bout +target_compile_definitions(bout++ PUBLIC "GIT_REVISION=${GIT_SHA1}") # Optional dependencies find_package(NetCDF) if (NetCDF_FOUND) - target_compile_definitions(bout + target_compile_definitions(bout++ PUBLIC "NCDF4") - target_link_libraries(bout PUBLIC NetCDF::NetCDF) + target_link_libraries(bout++ PUBLIC NetCDF::NetCDF) endif() message(STATUS "NetCDF support: ${NetCDF_FOUND}") find_package(FFTW) if (FFTW_FOUND) - target_compile_definitions(bout + target_compile_definitions(bout++ PUBLIC "BOUT_HAS_FFTW") - target_link_libraries(bout PUBLIC FFTW::FFTW) + target_link_libraries(bout++ PUBLIC FFTW::FFTW) endif() message(STATUS "FFTW support: ${FFTW_FOUND}") find_package(LAPACK) if (LAPACK_FOUND) - target_compile_definitions(bout + target_compile_definitions(bout++ PUBLIC "LAPACK") - target_link_libraries(bout PUBLIC "${LAPACK_LIBRARIES}") + target_link_libraries(bout++ PUBLIC "${LAPACK_LIBRARIES}") endif() message(STATUS "LAPACK support: ${LAPACK_FOUND}") find_package(PETSc) if (PETSC_FOUND) - target_compile_definitions(bout + target_compile_definitions(bout++ PUBLIC "BOUT_HAS_PETSC") - target_link_libraries(bout PUBLIC PETSC::PETSc) + target_link_libraries(bout++ PUBLIC PETSC::PETSc) endif() message(STATUS "PETSc support: ${PETSC_FOUND}") find_package(SUNDIALS) if (SUNDIALS_FOUND) - target_compile_definitions(bout + target_compile_definitions(bout++ PUBLIC "BOUT_HAS_CVODE" PUBLIC "BOUT_HAS_IDA" PUBLIC "BOUT_HAS_ARKODE") - target_link_libraries(bout PUBLIC SUNDIALS_cvode::cvode) - target_link_libraries(bout PUBLIC SUNDIALS_ida::ida) - target_link_libraries(bout PUBLIC SUNDIALS_arkode::arkode) + target_link_libraries(bout++ PUBLIC SUNDIALS_cvode::cvode) + target_link_libraries(bout++ PUBLIC SUNDIALS_ida::ida) + target_link_libraries(bout++ PUBLIC SUNDIALS_arkode::arkode) endif() message(STATUS "SUNDIALS support: ${SUNDIALS_FOUND}") find_package(Gettext) if (GETTEXT_FOUND) - target_compile_definitions(bout + target_compile_definitions(bout++ PUBLIC "BOUT_HAS_GETTEXT") find_package(Intl) if (Intl_FOUND) - target_link_libraries(bout + target_link_libraries(bout++ PUBLIC ${Intl_LIBRARIES}) - target_include_directories(bout + target_include_directories(bout++ PUBLIC ${Intl_INCLUDE_DIRS}) endif() endif() @@ -450,7 +451,7 @@ function(bout_add_integrated_test TESTNAME) set(multiValueArgs SOURCES EXTRA_FILES) cmake_parse_arguments(BOUT_TEST_OPTIONS "${options}" "" "${multiValueArgs}" ${ARGN}) add_executable(${TESTNAME} ${BOUT_TEST_OPTIONS_SOURCES}) - target_link_libraries(${TESTNAME} bout) + target_link_libraries(${TESTNAME} bout++) target_include_directories(${TESTNAME} PRIVATE $) if (BOUT_TEST_OPTIONS_USE_RUNTEST) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index b1aba3beb0..236bb99e2f 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -65,6 +65,6 @@ add_executable(serial_tests ) target_include_directories(serial_tests PUBLIC .) -target_link_libraries(serial_tests gtest gmock bout) +target_link_libraries(serial_tests gtest gmock bout++::bout++) add_test(NAME serial_tests COMMAND serial_tests) set_target_properties(serial_tests PROPERTIES FOLDER tests/unit) From 96d910b4b06fd6d958f873c8a3fa03f79a6f81d9 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 26 Apr 2019 14:54:47 +0100 Subject: [PATCH 1329/1783] Convert Options::isSection() argument to lower case Option/section names are stored in lower case, so need to convert 'std::string name' argument to lower case before searching. --- src/sys/options.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 9cbd2d54e2..273ea8effa 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -126,7 +126,7 @@ bool Options::isSection(const std::string& name) const { } // Is there a child section? - auto it = children.find(name); + auto it = children.find(lowercase(name)); if (it == children.end()) { return false; } else { From 4b296641af034d73135be637c4578e22a746cc06 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Apr 2019 15:17:10 +0100 Subject: [PATCH 1330/1783] Basic installation with CMake --- CMakeLists.txt | 72 ++++++++++++++++++++++++++- bout++Config.cmake.in | 35 +++++++++++++ externalpackages/PVODE/CMakeLists.txt | 10 +++- 3 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 bout++Config.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b4a9e43bb..b7e9ee42b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -282,13 +282,17 @@ add_library(bout++ ) add_library(bout++::bout++ ALIAS bout++) target_link_libraries(bout++ PUBLIC MPI::MPI_CXX pvode pvpre mpark_variant) -target_include_directories(bout++ PUBLIC include) +target_include_directories(bout++ PUBLIC + $ + $ + ) target_compile_definitions(bout++ PUBLIC "BOUT_VERSION_STRING=\"4.2.2\"" PUBLIC "BOUT_VERSION_DOUBLE=4.22" PUBLIC "BOUT_HAS_PVODE" ) +set(BOUT_HAS_PVODE TRUE) target_compile_features(bout++ PUBLIC cxx_std_11) set_target_properties(bout++ PROPERTIES CXX_EXTENSIONS OFF) @@ -304,6 +308,7 @@ endif() message(STATUS "Runtime checking level: CHECK=${CHECK}") target_compile_definitions(bout++ PUBLIC "CHECK=${CHECK}") +set(BOUT_CHECK_LEVEL ${CHECK}) option(ENABLE_SIGNAL "SegFault handling" ON) if (ENABLE_SIGNAL) @@ -311,6 +316,7 @@ if (ENABLE_SIGNAL) PUBLIC "SIGHANDLE") endif() message(STATUS "Signal handling: SIGHANDLE=${ENABLE_SIGNAL}") +set(BOUT_USE_SIGNAL ${ENABLE_SIGNAL}) option(ENABLE_COLOR "Output coloring" ON) if (ENABLE_COLOR) @@ -318,6 +324,7 @@ if (ENABLE_COLOR) PUBLIC "LOGCOLOR") endif() message(STATUS "Output coloring: LOGCOLOR=${ENABLE_COLOR}") +set(BOUT_USE_COLOR ${ENABLE_COLOR}) option(ENABLE_TRACK "Field name tracking" ON) if (ENABLE_TRACK) @@ -325,6 +332,7 @@ if (ENABLE_TRACK) PUBLIC "TRACK") endif() message(STATUS "Field name tracking: TRACK=${ENABLE_TRACK}") +set(BOUT_USE_TRACK ${ENABLE_TRACK}) option(ENABLE_SIGFPE "Signalling floating point exceptions" ON) if (ENABLE_SIGFPE) @@ -332,6 +340,7 @@ if (ENABLE_SIGFPE) PUBLIC "BOUT_FPE") endif() message(STATUS "Signalling floating point exceptions: BOUT_FPE=${ENABLE_SIGFPE}") +set(BOUT_USE_SIGFPE ${ENABLE_SIGFPE}) option(ENABLE_BACKTRACE "Enable backtrace" ON) if (ENABLE_BACKTRACE) @@ -343,7 +352,8 @@ if (ENABLE_BACKTRACE) PUBLIC "BACKTRACE") target_link_libraries(bout++ PUBLIC ${CMAKE_DL_LIBS}) endif() -message(STATUS "Enable backtrace: SIGHANDLE=${ENABLE_BACKTRACE}") +message(STATUS "Enable backtrace: BACKTRACE=${ENABLE_BACKTRACE}") +set(BOUT_USE_BACKTRACE ${ENABLE_BACKTRACE}) option(ENABLE_OPENMP "Enable OpenMP support" OFF) if (ENABLE_OPENMP) @@ -363,12 +373,14 @@ if (ENABLE_OPENMP) message(STATUS "OpenMP schedule: ${OPENMP_SCHEDULE}") endif() message(STATUS "Enable OpenMP: ${ENABLE_OPENMP}") +set(BOUT_USE_OPENMP ${ENABLE_OPENMP}) include(GetGitRevisionDescription) get_git_head_revision(GIT_REFSPEC GIT_SHA1) message(STATUS "Git revision: ${GIT_SHA1}") target_compile_definitions(bout++ PUBLIC "GIT_REVISION=${GIT_SHA1}") +set(BOUT_GIT_REVISION ${GIT_SHA1}) # Optional dependencies @@ -379,6 +391,7 @@ if (NetCDF_FOUND) target_link_libraries(bout++ PUBLIC NetCDF::NetCDF) endif() message(STATUS "NetCDF support: ${NetCDF_FOUND}") +set(BOUT_HAS_NETCDF ${NetCDF_FOUND}) find_package(FFTW) if (FFTW_FOUND) @@ -387,6 +400,7 @@ if (FFTW_FOUND) target_link_libraries(bout++ PUBLIC FFTW::FFTW) endif() message(STATUS "FFTW support: ${FFTW_FOUND}") +set(BOUT_HAS_FFTW ${FFTW_FOUND}) find_package(LAPACK) if (LAPACK_FOUND) @@ -395,6 +409,7 @@ if (LAPACK_FOUND) target_link_libraries(bout++ PUBLIC "${LAPACK_LIBRARIES}") endif() message(STATUS "LAPACK support: ${LAPACK_FOUND}") +set(BOUT_HAS_LAPACK ${LAPACK_FOUND}) find_package(PETSc) if (PETSC_FOUND) @@ -403,6 +418,7 @@ if (PETSC_FOUND) target_link_libraries(bout++ PUBLIC PETSC::PETSc) endif() message(STATUS "PETSc support: ${PETSC_FOUND}") +set(BOUT_HAS_PETSC ${PETSC_FOUND}) find_package(SUNDIALS) if (SUNDIALS_FOUND) @@ -415,6 +431,7 @@ if (SUNDIALS_FOUND) target_link_libraries(bout++ PUBLIC SUNDIALS_arkode::arkode) endif() message(STATUS "SUNDIALS support: ${SUNDIALS_FOUND}") +set(BOUT_HAS_SUNDIALS ${SUNDIALS_FOUND}) find_package(Gettext) if (GETTEXT_FOUND) @@ -428,6 +445,7 @@ if (GETTEXT_FOUND) PUBLIC ${Intl_INCLUDE_DIRS}) endif() endif() +set(BOUT_HAS_GETTEXT ${GETTEXT_FOUND}) # Copy FILENAME from source directory to build directory # and add dependency on TARGET @@ -479,3 +497,53 @@ if(PACKAGE_TESTS) add_subdirectory(tests/integrated/test-initial) add_subdirectory(tests/integrated/test-griddata) endif() + +################################################## +# Installation + +include(GNUInstallDirs) +install(TARGETS bout++ pvode pvpre mpark_variant + EXPORT bout++Targets + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + ) +install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + bout++ConfigVersion.cmake + VERSION ${PACKAGE_VERSION} + COMPATIBILITY SameMajorVersion + ) + +install(EXPORT bout++Targets + FILE bout++Targets.cmake + NAMESPACE bout++:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/bout++" + ) + +configure_package_config_file(bout++Config.cmake.in bout++Config.cmake + INSTALL_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/bout++Config.cmake" + ) +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/bout++Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/bout++ConfigVersion.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/CorrectWindowsPaths.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindFFTW.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindNetCDF.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindPackageMultipass.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindPETSc.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindSUNDIALS.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/ResolveCompilerPaths.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/bout++" + ) + +export(EXPORT bout++Targets + FILE "${CMAKE_CURRENT_BINARY_DIR}/bout++Targets.cmake" + NAMESPACE bout++:: + ) + +export(PACKAGE bout) diff --git a/bout++Config.cmake.in b/bout++Config.cmake.in new file mode 100644 index 0000000000..699515230f --- /dev/null +++ b/bout++Config.cmake.in @@ -0,0 +1,35 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + +set(BOUT_USE_SIGNAL @BOUT_USE_SIGNAL@) +set(BOUT_USE_COLOR @BOUT_USE_COLOR@) +set(BOUT_USE_TRACK @BOUT_USE_TRACK@) +set(BOUT_USE_SIGFPE @BOUT_USE_SIGFPE@) +set(BOUT_USE_BACKTRACE @BOUT_USE_BACKTRACE@) +set(BOUT_USE_OPENMP @BOUT_USE_OPENMP@) + +set(BOUT_HAS_PVODE @BOUT_HAS_PVODE@) +set(BOUT_HAS_NETCDF @BOUT_HAS_NETCDF@) +set(BOUT_HAS_FFTW @BOUT_HAS_FFTW@) +set(BOUT_HAS_LAPACK @BOUT_HAS_LAPACK@) +set(BOUT_HAS_PETSC @BOUT_HAS_PETSC@) +set(BOUT_HAS_SUNDIALS @BOUT_HAS_SUNDIALS@) +set(BOUT_HAS_GETTEXT @BOUT_HAS_GETTEXT@) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}" + "${CMAKE_CURRENT_LIST_DIR}/../../../lib/cmake/mpark_variant" + ) + +find_dependency(MPI) +find_dependency(OpenMP) +find_dependency(NetCDF) +find_dependency(FFTW) +find_dependency(LAPACK) +find_dependency(PETSc) +find_dependency(SUNDIALS) +find_dependency(Gettext) +find_dependency(Intl) +find_dependency(mpark_variant) + +include("${CMAKE_CURRENT_LIST_DIR}/bout++Targets.cmake") diff --git a/externalpackages/PVODE/CMakeLists.txt b/externalpackages/PVODE/CMakeLists.txt index 2206f4c55b..9fded327aa 100644 --- a/externalpackages/PVODE/CMakeLists.txt +++ b/externalpackages/PVODE/CMakeLists.txt @@ -35,7 +35,10 @@ add_library(pvode include/vector.h ) -target_include_directories(pvode PUBLIC include) +target_include_directories(pvode PUBLIC + $ + $ + ) target_link_libraries(pvode PUBLIC MPI::MPI_CXX) add_library(pvpre @@ -45,5 +48,8 @@ add_library(pvpre precon/band.h ) -target_include_directories(pvpre PUBLIC include) +target_include_directories(pvpre PUBLIC + $ + $ + ) target_link_libraries(pvpre PUBLIC MPI::MPI_CXX) From f68ec930b152021f5d9926ea0ee5e8b2e87bae7a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 26 Apr 2019 16:16:07 +0100 Subject: [PATCH 1331/1783] More tests for case sensitivity/insensitivity in options unit tests --- tests/unit/sys/test_options.cxx | 200 +++++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 2 deletions(-) diff --git a/tests/unit/sys/test_options.cxx b/tests/unit/sys/test_options.cxx index 9a77770ee8..dd3be978a4 100644 --- a/tests/unit/sys/test_options.cxx +++ b/tests/unit/sys/test_options.cxx @@ -49,6 +49,22 @@ TEST_F(OptionsTest, IsSection) { ASSERT_TRUE(options.isSection("subsection")); } +TEST_F(OptionsTest, IsSectionNotCaseSensitive) { + Options options; + + // make sure options is initialized as a section + options["Testkey"] = 1.; + + ASSERT_TRUE(options.isSection()); + ASSERT_FALSE(options["testKey"].isSection()); + ASSERT_TRUE(options.isSection("")); + ASSERT_FALSE(options.isSection("Subsection")); + + options["subSection"]["testkey"] = 1.; + + ASSERT_TRUE(options.isSection("Subsection")); +} + TEST_F(OptionsTest, SetGetInt) { Options options; options.set("int_key", 42, "code"); @@ -61,6 +77,18 @@ TEST_F(OptionsTest, SetGetInt) { EXPECT_EQ(value, 42); } +TEST_F(OptionsTest, SetGetIntNotCaseSensitive) { + Options options; + options.set("Int_key", 42, "code"); + + ASSERT_TRUE(options.isSet("int_Key")); + + int value; + options.get("iNt_key", value, 99, false); + + EXPECT_EQ(value, 42); +} + TEST_F(OptionsTest, SetGetIntFromReal) { Options options; options.set("int_key", 42.00001, "code"); @@ -98,6 +126,16 @@ TEST_F(OptionsTest, InconsistentDefaultValueInt) { EXPECT_EQ(value, 99); } +TEST_F(OptionsTest, InconsistentDefaultValueIntNotCaseSensitive) { + Options options; + + int value; + options.get("Int_key", value, 99, false); + EXPECT_THROW(options.get("int_Key", value, 98, false), BoutException); + + EXPECT_EQ(value, 99); +} + TEST_F(OptionsTest, SetGetReal) { Options options; options.set("real_key", 6.7e8, "code"); @@ -110,6 +148,18 @@ TEST_F(OptionsTest, SetGetReal) { EXPECT_DOUBLE_EQ(value, 6.7e8); } +TEST_F(OptionsTest, SetGetRealNotCaseSensitive) { + Options options; + options.set("Real_key", 6.7e8, "code"); + + ASSERT_TRUE(options.isSet("real_Key")); + + BoutReal value; + options.get("Real_Key", value, -78.0, false); + + EXPECT_DOUBLE_EQ(value, 6.7e8); +} + TEST_F(OptionsTest, SetGetDouble) { Options options; options.set("real_key", 0.7853981633974483, "code"); @@ -172,6 +222,18 @@ TEST_F(OptionsTest, SetGetBool) { EXPECT_EQ(value, true); } +TEST_F(OptionsTest, SetGetBoolNotCaseSensitive) { + Options options; + options.set("Bool_key", true, "code"); + + ASSERT_TRUE(options.isSet("bool_Key")); + + bool value; + options.get("Bool_Key", value, false, false); + + EXPECT_EQ(value, true); +} + TEST_F(OptionsTest, SetGetBoolFalse) { Options options; options.set("bool_key", false, "code"); @@ -233,6 +295,20 @@ TEST_F(OptionsTest, SetGetString) { EXPECT_EQ(value, "abcdef"); } +TEST_F(OptionsTest, SetGetStringNotCaseSensitive) { + Options options; + // Note, string values are case sensitive + options.set("String_key", "AbCdEf", "code"); + + ASSERT_TRUE(options.isSet("string_Key")); + + std::string value; + options.get("String_Key", value, "GhIjKl", false); + + EXPECT_EQ(value, "AbCdEf"); + EXPECT_NE(value, "abcdef"); +} + TEST_F(OptionsTest, DefaultValueString) { Options options; @@ -242,6 +318,17 @@ TEST_F(OptionsTest, DefaultValueString) { EXPECT_EQ(value, "ghijkl"); } +TEST_F(OptionsTest, DefaultValueStringNotCaseSensitive) { + Options options; + + std::string value; + // Note, string values are case sensitive + options.get("String_key", value, "GhIjKl", false); + + EXPECT_EQ(value, "GhIjKl"); + EXPECT_NE(value, "ghijkl"); +} + TEST_F(OptionsTest, InconsistentDefaultValueString) { Options options; @@ -382,6 +469,18 @@ TEST_F(OptionsTest, SetSameOptionTwice) { EXPECT_NO_THROW(options.set("key", "value", "code",true)); } +TEST_F(OptionsTest, SetSameOptionTwiceNotCaseSensitive) { + Options options; + // Note string values are case sensitive + options.set("Key", "Value", "code"); + EXPECT_THROW(options.set("keY", "New Value", "code"),BoutException); + + options.set("kEy", "Value", "code"); + EXPECT_THROW(options.set("keY", "vAlue", "code"),BoutException); + EXPECT_NO_THROW(options.forceSet("KeY", "nEw valUe", "code")); + EXPECT_NO_THROW(options.set("KEY", "valuE", "code",true)); +} + /// New interface @@ -389,12 +488,22 @@ TEST_F(OptionsTest, NewIsSet) { Options options; ASSERT_FALSE(options["int_key"].isSet()); - + options["int_key"].assign(42, "code"); ASSERT_TRUE(options["int_key"].isSet()); } +TEST_F(OptionsTest, NewIsSetNotCaseSensitive) { + Options options; + + ASSERT_FALSE(options["Int_key"].isSet()); + + options["int_Key"].assign(42, "code"); + + ASSERT_TRUE(options["Int_key"].isSet()); +} + TEST_F(OptionsTest, NewSubSection) { Options options; @@ -407,6 +516,18 @@ TEST_F(OptionsTest, NewSubSection) { EXPECT_EQ(value, 42); } +TEST_F(OptionsTest, NewSubSectionNotCaseSensitive) { + Options options; + + options["Sub-section"]["Int_key"].assign(42, "code"); + + ASSERT_FALSE(options["int_key"].isSet()); + ASSERT_TRUE(options["sub-Section"]["int_Key"].isSet()); + + int value = options["sub-secTion"]["inT_key"].withDefault(99); + EXPECT_EQ(value, 42); +} + TEST_F(OptionsTest, NewIsSetDefault) { Options options; ASSERT_FALSE(options.isSet()); @@ -440,6 +561,20 @@ TEST_F(OptionsTest, NewSetGetIntFromReal) { EXPECT_THROW(options["key2"].as(), BoutException); } +TEST_F(OptionsTest, NewSetGetIntFromRealNotCaseSensitive) { + Options options; + options["Key1"] = 42.00001; + + ASSERT_TRUE(options["kEy1"].isSet()); + + int value = options["keY1"].withDefault(99); + + EXPECT_EQ(value, 42); + + options["Key2"] = 12.5; + EXPECT_THROW(options["kEy2"].as(), BoutException); +} + TEST_F(OptionsTest, NewDefaultValueInt) { Options options; @@ -454,6 +589,13 @@ TEST_F(OptionsTest, WithDefaultString) { EXPECT_EQ(value, "hello"); } +TEST_F(OptionsTest, WithDefaultStringCaseSensitive) { + Options options; + + std::string value = options.withDefault("Hello"); + EXPECT_NE(value, "hello"); +} + TEST_F(OptionsTest, OptionsMacroPointer) { Options options; @@ -571,6 +713,17 @@ TEST_F(OptionsTest, AssignSectionReplace) { EXPECT_EQ(option2["key"].as(), 42); } +TEST_F(OptionsTest, AssignSectionReplaceNotCaseSensitive) { + Options option1, option2; + + option1["Key"] = 42; + option2["kEy"] = 23; + + option2 = option1; + + EXPECT_EQ(option2["keY"].as(), 42); +} + TEST_F(OptionsTest, AssignSectionParent) { Options option1, option2; @@ -639,6 +792,14 @@ TEST_F(OptionsTest, AttributeStoreBool) { EXPECT_FALSE(option.attributes["test"].as()); } +TEST_F(OptionsTest, AttributeStoreBoolCaseSensitive) { + Options option; + option.attributes["Test"] = true; + + EXPECT_FALSE(option.attributes["test"].as()); + EXPECT_TRUE(option.attributes["Test"].as()); +} + TEST_F(OptionsTest, AttributeStoreInt) { Options option; option.attributes["test"] = 42; @@ -647,6 +808,14 @@ TEST_F(OptionsTest, AttributeStoreInt) { EXPECT_EQ(value, 42); } +TEST_F(OptionsTest, AttributeStoreIntCaseSensitive) { + Options option; + option.attributes["Test"] = 42; + + int value = option.attributes["tEst"]; + EXPECT_NE(value, 42); +} + TEST_F(OptionsTest, AttributeStoreBoutReal) { Options option; option.attributes["test"] = 3.1415; @@ -655,6 +824,14 @@ TEST_F(OptionsTest, AttributeStoreBoutReal) { EXPECT_DOUBLE_EQ(value, 3.1415); } +TEST_F(OptionsTest, AttributeStoreBoutRealCaseSensitive) { + Options option; + option.attributes["Test"] = 3.1415; + + BoutReal value = option.attributes["tEst"]; + EXPECT_DOUBLE_EQ(value, 0.); +} + TEST_F(OptionsTest, AttributeStoreConstChars) { Options option; option.attributes["test"] = "hello"; @@ -663,7 +840,16 @@ TEST_F(OptionsTest, AttributeStoreConstChars) { EXPECT_EQ(test, "hello"); } -TEST_F(OptionsTest, AttributeTimeDimension) { +TEST_F(OptionsTest, AttributeStoreConstCharsCaseSensitive) { + Options option; + option.attributes["Test"] = "HeLlO"; + + std::string test = option.attributes["Test"]; + EXPECT_EQ(test, "HeLlO"); + EXPECT_NE(test, "hello"); +} + +TEST_F(OptionsTest, AttributeTimeDimension) { Options option; option = 3; @@ -708,6 +894,16 @@ TEST_F(OptionsTest, EqualityString) { EXPECT_FALSE(option == "goodbye"); } +TEST_F(OptionsTest, EqualityStringCaseSensitive) { + Options option; + + option = "HeLlO"; + + EXPECT_TRUE(option == "HeLlO"); + EXPECT_FALSE(option == "hello"); + EXPECT_FALSE(option == "goodbye"); +} + TEST_F(OptionsTest, ComparisonInt) { Options option; From 9cd715eb685963e585d27f4387e528c955476c99 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Apr 2019 16:55:00 +0100 Subject: [PATCH 1332/1783] Add minimal example compiling with CMake --- examples/blob2d/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 examples/blob2d/CMakeLists.txt diff --git a/examples/blob2d/CMakeLists.txt b/examples/blob2d/CMakeLists.txt new file mode 100644 index 0000000000..dee5d08e41 --- /dev/null +++ b/examples/blob2d/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.13) + +project(blob2d LANGUAGES CXX) + +find_package(bout++ REQUIRED) +add_executable(blob2d blob2d.cxx) +target_link_libraries(blob2d PRIVATE bout++::bout++) From 29bd48e9da75c23ea6fa3556c9fcdcd12ca51f35 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Apr 2019 17:00:44 +0100 Subject: [PATCH 1333/1783] Set SUNDIALS version in FindSUNDIALS; add some docs --- cmake/FindSUNDIALS.cmake | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/cmake/FindSUNDIALS.cmake b/cmake/FindSUNDIALS.cmake index ca129068ff..521f906fe9 100644 --- a/cmake/FindSUNDIALS.cmake +++ b/cmake/FindSUNDIALS.cmake @@ -1,3 +1,13 @@ +# Find SUNDIALS, the SUite of Nonlinear and DIfferential/ALgebraic equation Solvers +# +# Currently only actually looks for arkode, cvode and ida, as well as nvecparallel +# +# This module will define the following variables: +# SUNDIALS_FOUND: true if SUNDIALS was found on the system +# SUNDIALS_INCLUDE_DIRS: Location of the SUNDIALS includes +# SUNDIALS_LIBRARIES: Required libraries +# SUNDIALS_VERSION: Full version string + include(FindPackageHandleStandardArgs) find_path(SUNDIALS_INCLUDE_DIR @@ -28,7 +38,6 @@ endif() mark_as_advanced(SUNDIALS_nvecparallel_LIBRARY) set(SUNDIALS_COMPONENTS arkode cvode ida) -set(SUNDIALS_INT_TYPES int64_t;"long long";long;int32_t;int;) foreach (LIB ${SUNDIALS_COMPONENTS}) find_library(SUNDIALS_${LIB}_LIBRARY @@ -43,8 +52,29 @@ foreach (LIB ${SUNDIALS_COMPONENTS}) mark_as_advanced(SUNDIALS_${LIB}_LIBRARY) endforeach() +if (SUNDIALS_INCLUDE_DIR) + file(READ "${SUNDIALS_INCLUDE_DIR}/sundials_config.h" SUNDIALS_CONFIG_FILE) + string(FIND "${SUNDIALS_CONFIG_FILE}" "SUNDIALS_PACKAGE_VERSION" index) + if("${index}" LESS 0) + # Version >3 + set(SUNDIALS_VERSION_REGEX_PATTERN + ".*#define SUNDIALS_VERSION \"([0-9]+)\\.([0-9]+)\\.([0-9]+)\".*") + else() + # Version <3 + set(SUNDIALS_VERSION_REGEX_PATTERN + ".*#define SUNDIALS_PACKAGE_VERSION \"([0-9]+)\\.([0-9]+)\\.([0-9]+)\".*") + endif() + string(REGEX MATCH ${SUNDIALS_VERSION_REGEX_PATTERN} _ "${SUNDIALS_CONFIG_FILE}") + set(SUNDIALS_VERSION_MAJOR ${CMAKE_MATCH_1}) + set(SUNDIALS_VERSION_MINOR ${CMAKE_MATCH_2}) + set(SUNDIALS_VERSION_PATCH ${CMAKE_MATCH_3}) + set(SUNDIALS_VERSION "${SUNDIALS_VERSION_MAJOR}.${SUNDIALS_VERSION_MINOR}.${SUNDIALS_VERSION_PATCH}") +endif() + find_package_handle_standard_args(SUNDIALS - REQUIRED_VARS SUNDIALS_LIBRARIES SUNDIALS_INCLUDE_DIR SUNDIALS_INCLUDE_DIRS) + REQUIRED_VARS SUNDIALS_LIBRARIES SUNDIALS_INCLUDE_DIR SUNDIALS_INCLUDE_DIRS + VERSION_VAR SUNDIALS_VERSION + ) mark_as_advanced(SUNDIALS_LIBRARIES SUNDIALS_INCLUDE_DIR SUNDIALS_INCLUDE_DIRS) From 428cf2d4bfd07d00ed38f9beb0711ed0fba7b45c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 26 Apr 2019 17:01:04 +0100 Subject: [PATCH 1334/1783] Make CMake-installed BOUT++ a bit easier to use --- bout++Config.cmake.in | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/bout++Config.cmake.in b/bout++Config.cmake.in index 699515230f..2cd1da691a 100644 --- a/bout++Config.cmake.in +++ b/bout++Config.cmake.in @@ -17,17 +17,22 @@ set(BOUT_HAS_PETSC @BOUT_HAS_PETSC@) set(BOUT_HAS_SUNDIALS @BOUT_HAS_SUNDIALS@) set(BOUT_HAS_GETTEXT @BOUT_HAS_GETTEXT@) -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}" - "${CMAKE_CURRENT_LIST_DIR}/../../../lib/cmake/mpark_variant" - ) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") -find_dependency(MPI) +# This is almost certainly bad practice, but means the user doesn't +# need to find these manually +set(PETSC_DIR @PETSC_DIR@) +set(SUNDIALS_ROOT @SUNDIALS_ROOT@) +set(mpark_variant_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../lib/cmake/mpark_variant") +set(MPIEXEC_EXECUTABLE @MPIEXEC_EXECUTABLE@) + +find_dependency(MPI @MPI_CXX_VERSION@ EXACT) find_dependency(OpenMP) -find_dependency(NetCDF) +find_dependency(NetCDF @NetCDF_VERSION@ EXACT) find_dependency(FFTW) find_dependency(LAPACK) -find_dependency(PETSc) -find_dependency(SUNDIALS) +find_dependency(PETSc @PETSC_VERSION@ EXACT) +find_dependency(SUNDIALS @SUNDIALS_VERSION@ EXACT) find_dependency(Gettext) find_dependency(Intl) find_dependency(mpark_variant) From ef1cdbad289a5ade981cb43a9221b59fed90eb8f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 26 Apr 2019 17:46:18 +0100 Subject: [PATCH 1335/1783] Add support for shifting a FieldPerp toFieldAligned/fromFieldAligned --- include/bout/paralleltransform.hxx | 19 ++++++++++-- include/fieldperp.hxx | 5 +++ src/field/fieldperp.cxx | 8 +++++ src/mesh/parallel/fci.hxx | 6 ++++ src/mesh/parallel/shiftedmetric.cxx | 47 +++++++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 2 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index dd15a1f4d8..e002ccd403 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -44,13 +44,15 @@ public: integrateParallelSlices(f); } - /// Convert a 3D field into field-aligned coordinates + /// Convert a field into field-aligned coordinates /// so that the y index is along the magnetic field virtual const Field3D toFieldAligned(const Field3D &f, const REGION region = RGN_ALL) = 0; + virtual const FieldPerp toFieldAligned(const FieldPerp &f, const REGION region = RGN_ALL) = 0; /// Convert back from field-aligned coordinates /// into standard form virtual const Field3D fromFieldAligned(const Field3D &f, const REGION region = RGN_ALL) = 0; + virtual const FieldPerp fromFieldAligned(const FieldPerp &f, const REGION region = RGN_ALL) = 0; virtual bool canToFromFieldAligned() = 0; @@ -87,6 +89,9 @@ public: const Field3D toFieldAligned(const Field3D& f, const REGION UNUSED(region)) override { return f; } + const FieldPerp toFieldAligned(const FieldPerp& f, const REGION UNUSED(region)) override { + return f; + } /*! * The field is already aligned in Y, so this @@ -95,6 +100,9 @@ public: const Field3D fromFieldAligned(const Field3D& f, const REGION UNUSED(region)) override { return f; } + const FieldPerp fromFieldAligned(const FieldPerp& f, const REGION UNUSED(region)) override { + return f; + } bool canToFromFieldAligned() override { return true; } @@ -130,6 +138,8 @@ public: * if X derivatives are used. */ const Field3D toFieldAligned(const Field3D& f, const REGION region = RGN_ALL) override; + const FieldPerp toFieldAligned(const FieldPerp& f, + const REGION region = RGN_ALL) override; /*! * Converts a field back to X-Z orthogonal coordinates @@ -137,6 +147,8 @@ public: */ const Field3D fromFieldAligned(const Field3D& f, const REGION region = RGN_ALL) override; + const FieldPerp fromFieldAligned(const FieldPerp& f, + const REGION region = RGN_ALL) override; bool canToFromFieldAligned() override { return true; } @@ -195,7 +207,7 @@ private: const REGION region = RGN_NOX) const; /*! - * Shift a 3D field \p f by the given phase \p phs in Z + * Shift a 3D field or FieldPerp \p f by the given phase \p phs in Z * * Calculates FFT in Z, multiplies by the complex phase * and inverse FFTS. @@ -207,6 +219,9 @@ private: const Field3D shiftZ(const Field3D& f, const Tensor& phs, const YDirectionType y_direction_out, const REGION region = RGN_NOX) const; + const FieldPerp shiftZ(const FieldPerp& f, const Tensor& phs, + const YDirectionType y_direction_out, + const REGION region = RGN_NOX) const; /*! * Shift a given 1D array, assumed to be in Z, by the given \p zangle diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 8db7dfa768..cf145a07d2 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -269,6 +269,11 @@ private: Array data; }; +// Non-member functions + +FieldPerp toFieldAligned(const FieldPerp& f, const REGION region = RGN_ALL); +FieldPerp fromFieldAligned(const FieldPerp& f, const REGION region = RGN_ALL); + // Non-member overloaded operators FieldPerp operator+(const FieldPerp &lhs, const FieldPerp &rhs); diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 2d6746a86c..6c04f30362 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -106,6 +106,14 @@ const Region &FieldPerp::getRegion(const std::string ®ion_name) cons //////////////// NON-MEMBER FUNCTIONS ////////////////// +FieldPerp toFieldAligned(const FieldPerp& f, const REGION region) { + return f.getCoordinates()->getParallelTransform().toFieldAligned(f, region); +} + +FieldPerp fromFieldAligned(const FieldPerp& f, const REGION region) { + return f.getCoordinates()->getParallelTransform().fromFieldAligned(f, region); +} + ////////////// NON-MEMBER OVERLOADED OPERATORS ////////////// // Unary minus diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index f50b4b130a..122a3dd66d 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -96,10 +96,16 @@ public: const Field3D toFieldAligned(const Field3D &UNUSED(f), const REGION UNUSED(region)) override { throw BoutException("FCI method cannot transform into field aligned grid"); } + const FieldPerp toFieldAligned(const FieldPerp &UNUSED(f), const REGION UNUSED(region)) override { + throw BoutException("FCI method cannot transform into field aligned grid"); + } const Field3D fromFieldAligned(const Field3D &UNUSED(f), const REGION UNUSED(region)) override { throw BoutException("FCI method cannot transform into field aligned grid"); } + const FieldPerp fromFieldAligned(const FieldPerp &UNUSED(f), const REGION UNUSED(region)) override { + throw BoutException("FCI method cannot transform into field aligned grid"); + } bool canToFromFieldAligned() override { return false; } diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 0cc9994e69..2b4ccf9484 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -138,6 +138,20 @@ const Field3D ShiftedMetric::toFieldAligned(const Field3D& f, const REGION regio return f; } } +const FieldPerp ShiftedMetric::toFieldAligned(const FieldPerp& f, const REGION region) { + switch (f.getDirectionY()) { + case (YDirectionType::Standard): + return shiftZ(f, toAlignedPhs, YDirectionType::Aligned, region); + case (YDirectionType::Aligned): + // f is already in field-aligned coordinates + return f; + default: + throw BoutException("Unrecognized y-direction type for FieldPerp passed to " + "ShiftedMetric::toFieldAligned"); + // This should never happen, but use 'return f' to avoid compiler warnings + return f; + } +} /*! * Shift back, so that X-Z is orthogonal, @@ -157,6 +171,20 @@ const Field3D ShiftedMetric::fromFieldAligned(const Field3D& f, const REGION reg return f; } } +const FieldPerp ShiftedMetric::fromFieldAligned(const FieldPerp& f, const REGION region) { + switch (f.getDirectionY()) { + case (YDirectionType::Aligned): + return shiftZ(f, fromAlignedPhs, YDirectionType::Standard, region); + case (YDirectionType::Standard): + // f is already in orthogonal coordinates + return f; + default: + throw BoutException("Unrecognized y-direction type for Field3D passed to " + "ShiftedMetric::toFieldAligned"); + // This should never happen, but use 'return f' to avoid compiler warnings + return f; + } +} const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Tensor& phs, const YDirectionType y_direction_out, @@ -176,6 +204,25 @@ const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Tensor& ph return result; } +const FieldPerp ShiftedMetric::shiftZ(const FieldPerp& f, const Tensor& phs, + const YDirectionType y_direction_out, + const REGION UNUSED(region)) const { + ASSERT1(f.getMesh() == &mesh); + ASSERT1(f.getLocation() == location); + + if (mesh.LocalNz == 1) + return f; // Shifting makes no difference + + FieldPerp result{emptyFrom(f).setDirectionY(y_direction_out)}; + + int y = f.getIndex(); + for (int i=mesh.xstart; i<=mesh.xend; ++i) { + shiftZ(&f(i, 0), &phs(i, y, 0), &result(i, 0)); + } + + return result; +} + void ShiftedMetric::shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* out) const { Array cmplx(nmodes); From 2761dff9c52df8a92656053da873c6cfaf136963 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 27 Apr 2019 15:24:28 +0100 Subject: [PATCH 1336/1783] Unit tests for FieldPerp toFieldAligned and fromFieldAligned --- .../unit/mesh/parallel/test_shiftedmetric.cxx | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 4e76a02330..9fb1e78ac3 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -181,6 +181,95 @@ TEST_F(ShiftedMetricTest, ToFromFieldAligned) { FFTTolerance)); } +TEST_F(ShiftedMetricTest, ToFieldAlignedFieldPerp) { + Field3D expected{mesh}; + expected.setDirectionY(YDirectionType::Aligned); + + fillField(expected, {{{2., 3., 4., 5., 1.}, + {3., 4., 5., 2., 1.}, + {4., 5., 1., 3., 2.}, + {5., 1., 2., 4., 3.}, + {1., 2., 3., 5., 4.}, + {2., 3., 4., 5., 1.}, + {3., 4., 5., 2., 1.}}, + + {{3., 4., 5., 2., 1.}, + {5., 1., 3., 2., 4.}, + {2., 4., 3., 5., 1.}, + {5., 4., 1., 2., 3.}, + {1., 2., 3., 4., 5.}, + {3., 4., 5., 2., 1.}, + {5., 1., 3., 2., 4.}}, + + {{4., 5., 1., 3., 2.}, + {2., 4., 3., 5., 1.}, + {4., 1., 2., 3., 5.}, + {3., 4., 5., 1., 2.}, + {2., 1., 3., 4., 5.}, + {4., 5., 1., 3., 2.}, + {2., 4., 3., 5., 1.}}}); + + FieldPerp result = toFieldAligned(sliceXZ(input, 3)); + + EXPECT_TRUE(IsFieldEqual(result, sliceXZ(expected, 3), "RGN_ALL", FFTTolerance)); + EXPECT_TRUE(IsFieldEqual(fromFieldAligned(sliceXZ(input,2)), sliceXZ(input, 2))); + EXPECT_TRUE(areFieldsCompatible(result, sliceXZ(expected, 3))); + EXPECT_FALSE(areFieldsCompatible(result, sliceXZ(input, 3))); +} + +TEST_F(ShiftedMetricTest, FromFieldAlignedFieldPerp) { + // reset input.yDirectionType so that fromFieldAligned is not a null + // operation + input.setDirectionY(YDirectionType::Aligned); + + Field3D expected{mesh, CELL_CENTRE}; + expected.setDirectionY(YDirectionType::Standard); + + fillField(expected, {{{5., 1., 2., 3., 4.}, + {4., 5., 2., 1., 3.}, + {2., 4., 5., 1., 3.}, + {2., 4., 3., 5., 1.}, + {1., 2., 3., 5., 4.}, + {5., 1., 2., 3., 4.}, + {4., 5., 2., 1., 3.}}, + + {{4., 5., 2., 1., 3.}, + {3., 2., 4., 5., 1.}, + {5., 1., 2., 4., 3.}, + {3., 5., 4., 1., 2.}, + {1., 2., 3., 4., 5.}, + {4., 5., 2., 1., 3.}, + {3., 2., 4., 5., 1.}}, + + {{2., 4., 5., 1., 3.}, + {5., 1., 2., 4., 3.}, + {2., 3., 5., 4., 1.}, + {4., 5., 1., 2., 3.}, + {2., 1., 3., 4., 5.}, + {2., 4., 5., 1., 3.}, + {5., 1., 2., 4., 3.}}}); + + FieldPerp result = fromFieldAligned(sliceXZ(input, 4)); + + // Loosen tolerance a bit due to FFTs + EXPECT_TRUE(IsFieldEqual(result, sliceXZ(expected, 4), "RGN_ALL", FFTTolerance)); + EXPECT_TRUE(IsFieldEqual(toFieldAligned(sliceXZ(input, 0)), sliceXZ(input, 0))); + EXPECT_TRUE(areFieldsCompatible(result, sliceXZ(expected, 4))); + EXPECT_FALSE(areFieldsCompatible(result, sliceXZ(input, 4))); +} + +TEST_F(ShiftedMetricTest, FromToFieldAlignedFieldPerp) { + EXPECT_TRUE(IsFieldEqual(fromFieldAligned(toFieldAligned(sliceXZ(input, 2))), + sliceXZ(input, 2), "RGN_ALL", FFTTolerance)); +} + +TEST_F(ShiftedMetricTest, ToFromFieldAlignedFieldPerp) { + input.setDirectionY(YDirectionType::Aligned); + + EXPECT_TRUE(IsFieldEqual(toFieldAligned(fromFieldAligned(sliceXZ(input, 6))), + sliceXZ(input, 6), "RGN_ALL", FFTTolerance)); +} + TEST_F(ShiftedMetricTest, CalcParallelSlices) { // We don't shift in the guard cells, and the parallel slices are // stored offset in y, therefore we need to make new regions that we From 3b2fb33fcb6fd405ddfa388f102fafc76efad2b7 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 28 Apr 2019 17:39:14 +0100 Subject: [PATCH 1337/1783] RGN_NOBNDRY in FieldPerp unit tests toFieldAligned and fromFieldAligned The FieldPerp versions never set guard cells, so need to only check RGN_NOBNDRY. --- .../unit/mesh/parallel/test_shiftedmetric.cxx | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 9fb1e78ac3..3a40eb5157 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -211,7 +211,10 @@ TEST_F(ShiftedMetricTest, ToFieldAlignedFieldPerp) { FieldPerp result = toFieldAligned(sliceXZ(input, 3)); - EXPECT_TRUE(IsFieldEqual(result, sliceXZ(expected, 3), "RGN_ALL", FFTTolerance)); + // Note that the region argument does not do anything for FieldPerp, as + // FieldPerp does not have a getRegion2D() method. Values are never set in + // the x-guard or x-boundary cells + EXPECT_TRUE(IsFieldEqual(result, sliceXZ(expected, 3), "RGN_NOBNDRY", FFTTolerance)); EXPECT_TRUE(IsFieldEqual(fromFieldAligned(sliceXZ(input,2)), sliceXZ(input, 2))); EXPECT_TRUE(areFieldsCompatible(result, sliceXZ(expected, 3))); EXPECT_FALSE(areFieldsCompatible(result, sliceXZ(input, 3))); @@ -251,23 +254,31 @@ TEST_F(ShiftedMetricTest, FromFieldAlignedFieldPerp) { FieldPerp result = fromFieldAligned(sliceXZ(input, 4)); - // Loosen tolerance a bit due to FFTs - EXPECT_TRUE(IsFieldEqual(result, sliceXZ(expected, 4), "RGN_ALL", FFTTolerance)); + // Note that the region argument does not do anything for FieldPerp, as + // FieldPerp does not have a getRegion2D() method. Values are never set in + // the x-guard or x-boundary cells + EXPECT_TRUE(IsFieldEqual(result, sliceXZ(expected, 4), "RGN_NOBNDRY", FFTTolerance)); EXPECT_TRUE(IsFieldEqual(toFieldAligned(sliceXZ(input, 0)), sliceXZ(input, 0))); EXPECT_TRUE(areFieldsCompatible(result, sliceXZ(expected, 4))); EXPECT_FALSE(areFieldsCompatible(result, sliceXZ(input, 4))); } TEST_F(ShiftedMetricTest, FromToFieldAlignedFieldPerp) { + // Note that the region argument does not do anything for FieldPerp, as + // FieldPerp does not have a getRegion2D() method. Values are never set in + // the x-guard or x-boundary cells EXPECT_TRUE(IsFieldEqual(fromFieldAligned(toFieldAligned(sliceXZ(input, 2))), - sliceXZ(input, 2), "RGN_ALL", FFTTolerance)); + sliceXZ(input, 2), "RGN_NOBNDRY", FFTTolerance)); } TEST_F(ShiftedMetricTest, ToFromFieldAlignedFieldPerp) { + // Note that the region argument does not do anything for FieldPerp, as + // FieldPerp does not have a getRegion2D() method. Values are never set in + // the x-guard or x-boundary cells input.setDirectionY(YDirectionType::Aligned); EXPECT_TRUE(IsFieldEqual(toFieldAligned(fromFieldAligned(sliceXZ(input, 6))), - sliceXZ(input, 6), "RGN_ALL", FFTTolerance)); + sliceXZ(input, 6), "RGN_NOBNDRY", FFTTolerance)); } TEST_F(ShiftedMetricTest, CalcParallelSlices) { From 165e7cb72a13f6250c0858e29a17c9b343e082ff Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sun, 28 Apr 2019 22:47:19 +0100 Subject: [PATCH 1338/1783] Add some documentation of splitrk method Describes the options and includes links to paper describing the RKL method. --- manual/sphinx/user_docs/time_integration.rst | 69 +++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/manual/sphinx/user_docs/time_integration.rst b/manual/sphinx/user_docs/time_integration.rst index 15d4ec83b2..29550bc7c0 100644 --- a/manual/sphinx/user_docs/time_integration.rst +++ b/manual/sphinx/user_docs/time_integration.rst @@ -35,18 +35,26 @@ needed to make the solver available. +---------------+-----------------------------------------+--------------------+ | Name | Description | Compile options | +===============+=========================================+====================+ - | euler | Euler explicit method | Always available | + | euler | Euler explicit method (example only) | Always available | +---------------+-----------------------------------------+--------------------+ | rk4 | Runge-Kutta 4th-order explicit method | Always available | +---------------+-----------------------------------------+--------------------+ + | rkgeneric | Generic Runge Kutta explicit methods | Always available | + +---------------+-----------------------------------------+--------------------+ | karniadakis | Karniadakis explicit method | Always available | +---------------+-----------------------------------------+--------------------+ + | rk3ssp | 3rd-order Strong Stability Preserving | Always available | + +---------------+-----------------------------------------+--------------------+ + | splitrk | Split RK3-SSP and RK-Legendre | Always available | + +---------------+-----------------------------------------+--------------------+ | pvode | 1998 PVODE with BDF method | Always available | +---------------+-----------------------------------------+--------------------+ | cvode | SUNDIALS CVODE. BDF and Adams methods | –with-cvode | +---------------+-----------------------------------------+--------------------+ | ida | SUNDIALS IDA. DAE solver | –with-ida | +---------------+-----------------------------------------+--------------------+ + | arkode | SUNDIALS ARKODE IMEX solver | –with-arkode | + +---------------+-----------------------------------------+--------------------+ | petsc | PETSc TS methods | –with-petsc | +---------------+-----------------------------------------+--------------------+ | imexbdf2 | IMEX-BDF2 scheme | –with-petsc | @@ -264,6 +272,65 @@ The options which control this behaviour are: | | | Currently the timestep increase is limited to 25% | +------------------+-----------+----------------------------------------------------+ + +Split-RK +-------- + +The `splitrk` solver type uses Strang splitting to combine two +explicit Runge Kutta schemes: + +#. `2nd order Runge-Kutta-Legendre method `_ + for the diffusion (parabolic) part. These schemes use + multiple stages to increase stability, rather than accuracy; this + is always 2nd order, but the stable timestep for diffusion + problems increases as the square of the number of stages. The + number of stages is an input option, and can be arbitrarily large. + +#. 3rd order SSP-RK3 scheme for the advection (hyperbolic) part + http://www.cscamm.umd.edu/tadmor/pub/linear-stability/Gottlieb-Shu-Tadmor.SIREV-01.pdf + +Each timestep consists of + +#. A half timestep of the diffusion part +#. A full timestep of the advection part +#. A half timestep of the diffusion part + +Options to control the behaviour of the solver are: + ++------------------+-----------+----------------------------------------------------+ +| Option | Default |Description | ++==================+===========+====================================================+ +| timestep | output | If adaptive sets the starting timestep. | +| | timestep | If not adaptive, timestep fixed at this value | ++------------------+-----------+----------------------------------------------------+ +| nstages | 10 | Number of stages in RKL step. Must be > 1 | ++------------------+-----------+----------------------------------------------------+ +| diagnose | false | Print diagnostic information | ++------------------+-----------+----------------------------------------------------+ + +And the adaptive timestepping options: + ++---------------------+-----------+----------------------------------------------------+ +| Option | Default |Description | ++=====================+===========+====================================================+ +| adaptive | true | Turn on adaptive timestepping | ++---------------------+-----------+----------------------------------------------------+ +| atol | 1e-10 | Absolute tolerance | ++---------------------+-----------+----------------------------------------------------+ +| rtol | 1e-5 | Relative tolerance | ++---------------------+-----------+----------------------------------------------------+ +| max_timestep | output | Maximum internal timestep | +| | timestep | | ++---------------------+-----------+----------------------------------------------------+ +| max_timestep_change | 2 | Maximum factor by which the timestep by which the | +| | | time step can be changed at each step | ++---------------------+-----------+----------------------------------------------------+ +| mxstep | 1000 | Maximum number of internal steps before output | ++---------------------+-----------+----------------------------------------------------+ +| adapt_period | 1 | Number of internal steps between tolerance checks | ++---------------------+-----------+----------------------------------------------------+ + + ODE integration --------------- From eabd7384b1ff1be39f91fd379a15e3c4f754f6f0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 09:55:21 +0100 Subject: [PATCH 1339/1783] Correct Field3D->FieldPerp in error message --- src/mesh/parallel/shiftedmetric.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 2b4ccf9484..905c287735 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -179,7 +179,7 @@ const FieldPerp ShiftedMetric::fromFieldAligned(const FieldPerp& f, const REGION // f is already in orthogonal coordinates return f; default: - throw BoutException("Unrecognized y-direction type for Field3D passed to " + throw BoutException("Unrecognized y-direction type for FieldPerp passed to " "ShiftedMetric::toFieldAligned"); // This should never happen, but use 'return f' to avoid compiler warnings return f; From ae838da9d6769e8b5af88cb6ee305c7308129d4a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 10:04:22 +0100 Subject: [PATCH 1340/1783] Set y-direction of results in ParallelTransformIdentity Previously ParallelTransformIdentity::toFieldAligned and ParallelTransformIdentity::fromFieldAligned just returned their input. For correctness, they should make a separate 'result' field and call 'result.setDirectionY' before returning it. Otherwise fields wouldn't always have correct meta-data, so checks might pass/fail incorrectly, especially in code which should be able to switch between ParallelTransformIdentity and ShiftedMetric. --- include/bout/paralleltransform.hxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index dd15a1f4d8..ecee717b7c 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -85,7 +85,8 @@ public: * does nothing */ const Field3D toFieldAligned(const Field3D& f, const REGION UNUSED(region)) override { - return f; + Field3D result = f; + return result.setDirectionY(YDirectionType::Aligned); } /*! @@ -93,7 +94,8 @@ public: * does nothing */ const Field3D fromFieldAligned(const Field3D& f, const REGION UNUSED(region)) override { - return f; + Field3D result = f; + return result.setDirectionY(YDirectionType::Standard); } bool canToFromFieldAligned() override { return true; } From 99d791802d3fbfac86c430121e88521f7b0e2b9c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 10:36:46 +0100 Subject: [PATCH 1341/1783] Unit test ParallelTransformIdentity::toFieldAligned/fromFieldAligned --- tests/unit/mesh/test_paralleltransform.cxx | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/unit/mesh/test_paralleltransform.cxx b/tests/unit/mesh/test_paralleltransform.cxx index 25854c1f70..27badf9613 100644 --- a/tests/unit/mesh/test_paralleltransform.cxx +++ b/tests/unit/mesh/test_paralleltransform.cxx @@ -39,3 +39,28 @@ TEST_F(ParallelTransformTest, IdentityCalcTwoParallelSlices) { EXPECT_TRUE(IsFieldEqual(field.ydown(0), 1.0)); EXPECT_TRUE(IsFieldEqual(field.ydown(1), 1.0)); } + +TEST_F(ParallelTransformTest, IdentityToFieldAligned) { + + ParallelTransformIdentity transform{*bout::globals::mesh}; + + Field3D field{1.0}; + + Field3D result = transform.toFieldAligned(field, RGN_ALL); + + EXPECT_TRUE(IsFieldEqual(result, 1.0)); + EXPECT_TRUE(result.getDirectionY() == YDirectionType::Aligned); +} + +TEST_F(ParallelTransformTest, IdentityFromFieldAligned) { + + ParallelTransformIdentity transform{*bout::globals::mesh}; + + Field3D field{1.0}; + field.setDirectionY(YDirectionType::Aligned); + + Field3D result = transform.fromFieldAligned(field, RGN_ALL); + + EXPECT_TRUE(IsFieldEqual(result, 1.0)); + EXPECT_TRUE(result.getDirectionY() == YDirectionType::Standard); +} From 8800ffda0a241737c5fded34bb8fbb5a6b0eac03 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 00:02:20 +0100 Subject: [PATCH 1342/1783] Make XLOCAL and YLOCAL methods public members of Mesh --- include/bout/mesh.hxx | 9 ++++++++- src/mesh/impls/bout/boutmesh.hxx | 5 +++-- tests/unit/test_extras.hxx | 2 ++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 5a6f377395..ec0c7630d9 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -446,13 +446,20 @@ class Mesh { int OffsetX, OffsetY, OffsetZ; ///< Offset of this mesh within the global array ///< so startx on this processor is OffsetX in global - /// Returns the global X index given a local indexs + /// Returns the global X index given a local index /// If the local index includes the boundary cells, then so does the global. virtual int XGLOBAL(int xloc) const = 0; /// Returns the global Y index given a local index /// The local index must include the boundary, the global index does not. virtual int YGLOBAL(int yloc) const = 0; + /// Returns the local X index given a global index + /// If the global index includes the boundary cells, then so does the local. + virtual int XLOCAL(int xglo) const = 0; + /// Returns the local Y index given a global index + /// If the global index includes the boundary cells, then so does the local. + virtual int YLOCAL(int yglo) const = 0; + /// Size of the mesh on this processor including guard/boundary cells int LocalNx, LocalNy, LocalNz; diff --git a/src/mesh/impls/bout/boutmesh.hxx b/src/mesh/impls/bout/boutmesh.hxx index b847daf1ab..7af52c50de 100644 --- a/src/mesh/impls/bout/boutmesh.hxx +++ b/src/mesh/impls/bout/boutmesh.hxx @@ -175,6 +175,9 @@ class BoutMesh : public Mesh { int XGLOBAL(BoutReal xloc, BoutReal &xglo) const; int YGLOBAL(BoutReal yloc, BoutReal &yglo) const; + int XLOCAL(int xglo) const; + int YLOCAL(int yglo) const; + private: std::string gridname; int nx, ny, nz; ///< Size of the grid in the input file @@ -201,9 +204,7 @@ class BoutMesh : public Mesh { // Processor number, local <-> global translation int PROC_NUM(int xind, int yind); // (PE_XIND, PE_YIND) -> MYPE - int XLOCAL(int xglo) const; int YGLOBAL(int yloc, int yproc) const; - int YLOCAL(int yglo) const; int YLOCAL(int yglo, int yproc) const; int YPROC(int yind); int XPROC(int xind); diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 88d7ba8f9c..f967c4630f 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -275,6 +275,8 @@ public: BoutReal GlobalY(BoutReal jy) const { return jy; } int XGLOBAL(int UNUSED(xloc)) const { return 0; } int YGLOBAL(int UNUSED(yloc)) const { return 0; } + int XLOCAL(int UNUSED(xglo)) const { return 0; } + int YLOCAL(int UNUSED(yglo)) const { return 0; } void initDerivs(Options * opt){ StaggerGrids=true; From c36cfbc754bc493995ce1c4855c7e84178bd3a63 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 00:05:17 +0100 Subject: [PATCH 1343/1783] Functions to get CELL_LOC, YDirectionType or ZDirectionType from string --- include/bout_types.hxx | 4 ++++ src/sys/bout_types.cxx | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index d8cded9ae3..ba48a555f3 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -34,11 +34,13 @@ typedef double BoutReal; const BoutReal BoutNaN = std::numeric_limits::quiet_NaN(); #define ENUMSTR(val) {val, #val} +#define STRENUM(val) {#val, val} /// 4 possible variable locations. Default is for passing to functions enum CELL_LOC {CELL_DEFAULT=0, CELL_CENTRE=1, CELL_CENTER=1, CELL_XLOW=2, CELL_YLOW=3, CELL_ZLOW=4, CELL_VSHIFT=5}; std::string toString(CELL_LOC location); +CELL_LOC CELL_LOCFromString(std::string location_string); DEPRECATED(inline std::string CELL_LOC_STRING(CELL_LOC location)) { return toString(location); } @@ -78,6 +80,7 @@ DEPRECATED(inline std::string DIRECTION_STRING(DIRECTION direction)) { enum class YDirectionType { Standard, Aligned }; std::string toString(YDirectionType d); +YDirectionType YDirectionTypeFromString(std::string y_direction_string); /// Identify kind of a field's z-direction /// - Standard is the default @@ -87,6 +90,7 @@ std::string toString(YDirectionType d); enum class ZDirectionType { Standard, Average }; std::string toString(ZDirectionType d); +ZDirectionType ZDirectionTypeFromString(std::string z_direction_string); /// Container for direction types struct DirectionTypes { diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index c5b7d6eeef..aa16a6baa5 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -3,6 +3,7 @@ #include #include +namespace { template const std::string& safeAt(const std::map& mymap, T t) { AUTO_TRACE(); @@ -13,6 +14,17 @@ const std::string& safeAt(const std::map& mymap, T t) { return found->second; } +template +const T& safeAtReverse(const std::map& mymap, std::string s) { + AUTO_TRACE(); + auto found = mymap.find(s); + if (found == mymap.end()) { + throw BoutException("Did not find enum %s", s.c_str()); + } + return found->second; +} +} + std::string toString(CELL_LOC location) { AUTO_TRACE(); const static std::map CELL_LOCtoString = { @@ -22,6 +34,15 @@ std::string toString(CELL_LOC location) { return safeAt(CELL_LOCtoString, location); } +CELL_LOC CELL_LOCFromString(std::string location_string) { + AUTO_TRACE(); + const static std::map stringtoCELL_LOC = { + STRENUM(CELL_DEFAULT), STRENUM(CELL_CENTRE), STRENUM(CELL_XLOW), + STRENUM(CELL_YLOW), STRENUM(CELL_ZLOW), STRENUM(CELL_VSHIFT)}; + + return safeAtReverse(stringtoCELL_LOC, location_string); +} + std::string toString(DIFF_METHOD location) { AUTO_TRACE(); const static std::map DIFF_METHODtoString = { @@ -125,6 +146,15 @@ std::string toString(YDirectionType d) { return safeAt(YDirectionTypeToString, d); } +YDirectionType YDirectionTypeFromString(std::string y_direction_string) { + AUTO_TRACE(); + const static std::map stringToYDirectionType = { + {"Standard", YDirectionType::Standard}, + {"Aligned", YDirectionType::Aligned}}; + + return safeAtReverse(stringToYDirectionType, y_direction_string); +} + std::string toString(ZDirectionType d) { AUTO_TRACE(); const static std::map ZDirectionTypeToString = { @@ -133,3 +163,12 @@ std::string toString(ZDirectionType d) { return safeAt(ZDirectionTypeToString, d); } + +ZDirectionType ZDirectionTypeFromString(std::string z_direction_string) { + AUTO_TRACE(); + const static std::map stringToZDirectionType = { + {"Standard", ZDirectionType::Standard}, + {"Average", ZDirectionType::Average}}; + + return safeAtReverse(stringToZDirectionType, z_direction_string); +} From 82f84994007ee544147cae325c2cab75d685b23b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 00:06:29 +0100 Subject: [PATCH 1344/1783] Make setDirectionY, setDirectionZ public --- include/field.hxx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index 2c66a11ac2..58f652ada1 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -136,6 +136,14 @@ class Field { return directions.z; } + /// Setters for *DirectionType + void setDirectionY(YDirectionType y_type) { + directions.y = y_type; + } + void setDirectionZ(ZDirectionType z_type) { + directions.z = z_type; + } + std::string name; #if CHECK > 0 @@ -216,14 +224,6 @@ protected: directions = f.directions; } - /// Setters for *DirectionType - void setDirectionY(YDirectionType y_type) { - directions.y = y_type; - } - void setDirectionZ(ZDirectionType z_type) { - directions.z = z_type; - } - private: DirectionTypes directions{YDirectionType::Standard, ZDirectionType::Standard}; }; From e6195d4f51df40cda89d25cb98fbea9395a2416b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 28 Apr 2019 15:43:40 +0100 Subject: [PATCH 1345/1783] Allow reading/writing FieldPerp in output files Note: need new dimension lists for FieldPerp in ncxx4.cxx and ncformat.cxx as we need to use {t,x,z} or {x,z} which are not consecutive entries in the existing lists/methods. --- include/datafile.hxx | 7 ++ include/dataformat.hxx | 1 + src/fileio/datafile.cxx | 147 ++++++++++++++++++++++++++ src/fileio/impls/hdf5/h5_format.cxx | 61 +++++++---- src/fileio/impls/hdf5/h5_format.hxx | 3 +- src/fileio/impls/netcdf/nc_format.cxx | 28 +++++ src/fileio/impls/netcdf/nc_format.hxx | 1 + src/fileio/impls/netcdf4/ncxx4.cxx | 31 ++++++ src/fileio/impls/netcdf4/ncxx4.hxx | 1 + src/mesh/data/gridfromfile.cxx | 30 +++--- 10 files changed, 277 insertions(+), 33 deletions(-) diff --git a/include/datafile.hxx b/include/datafile.hxx index a784876695..88119cb6c4 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -26,6 +26,7 @@ class Mesh; class Field; class Field2D; class Field3D; +class FieldPerp; class Options; class Vector2D; class Vector3D; @@ -71,6 +72,7 @@ class Datafile { void add(BoutReal &r, const char *name, bool save_repeat = false); void add(Field2D &f, const char *name, bool save_repeat = false); void add(Field3D &f, const char *name, bool save_repeat = false); + void add(FieldPerp &f, const char *name, bool save_repeat = false); void add(Vector2D &f, const char *name, bool save_repeat = false); void add(Vector3D &f, const char *name, bool save_repeat = false); @@ -125,20 +127,25 @@ class Datafile { std::vector> BoutReal_arr; std::vector> f2d_arr; std::vector> f3d_arr; + std::vector> fperp_arr; std::vector> v2d_arr; std::vector> v3d_arr; bool read_f2d(const std::string &name, Field2D *f, bool save_repeat); bool read_f3d(const std::string &name, Field3D *f, bool save_repeat); + bool read_fperp(const std::string &name, FieldPerp *f, bool save_repeat); bool write_int(const std::string &name, int *f, bool save_repeat); bool write_real(const std::string &name, BoutReal *f, bool save_repeat); bool write_f2d(const std::string &name, Field2D *f, bool save_repeat); bool write_f3d(const std::string &name, Field3D *f, bool save_repeat); + bool write_fperp(const std::string &name, FieldPerp *f, bool save_repeat); /// Write out the meta-data of a field as attributes of the variable in /// 'file'. void writeFieldAttributes(const std::string& name, const Field& f); + /// Overload for FieldPerp so we can also write 'yindex' + void writeFieldAttributes(const std::string& name, const FieldPerp& f); /// Check if a variable has already been added bool varAdded(const std::string &name); diff --git a/include/dataformat.hxx b/include/dataformat.hxx index 462bf712c0..19665cf333 100644 --- a/include/dataformat.hxx +++ b/include/dataformat.hxx @@ -78,6 +78,7 @@ class DataFormat { virtual bool addVarBoutReal(const std::string &name, bool repeat) = 0; virtual bool addVarField2D(const std::string &name, bool repeat) = 0; virtual bool addVarField3D(const std::string &name, bool repeat) = 0; + virtual bool addVarFieldPerp(const std::string &name, bool repeat) = 0; // Read / Write simple variables up to 3D diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 635eccb6f8..e812296ec8 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -252,6 +252,13 @@ bool Datafile::openw(const char *format, ...) { } } + // Add FieldPerps + for (const auto& var : fperp_arr) { + if (!file->addVarFieldPerp(var.name, var.save_repeat)) { + throw BoutException("Failed to add FieldPerp variable %s to Datafile", var.name.c_str()); + } + } + // 2D vectors for(const auto& var : v2d_arr) { if (!file->addVarField2D(var.name + "_x", var.save_repeat)) { @@ -354,6 +361,13 @@ bool Datafile::opena(const char *format, ...) { } } + // Add FieldPerps + for (const auto& var : fperp_arr) { + if (!file->addVarFieldPerp(var.name, var.save_repeat)) { + throw BoutException("Failed to add FieldPerp variable %s to Datafile", var.name.c_str()); + } + } + // 2D vectors for(const auto& var : v2d_arr) { if (!file->addVarField2D(var.name + "_x", var.save_repeat)) { @@ -621,6 +635,58 @@ void Datafile::add(Field3D &f, const char *name, bool save_repeat) { } } +void Datafile::add(FieldPerp &f, const char *name, bool save_repeat) { + AUTO_TRACE(); + if (!enabled) + return; + if (varAdded(name)) { + // Check if it's the same variable + if (&f == varPtr(name)) { + output_warn.write("WARNING: variable '%s' added again to Datafile\n", name); + } else { + throw BoutException("Variable with name '%s' already added to Datafile", name); + } + } + + VarStr d; + + d.ptr = &f; + d.name = name; + d.save_repeat = save_repeat; + d.covar = false; + + fperp_arr.push_back(d); + + if (writable) { + // Otherwise will add variables when Datafile is opened for writing/appending + if (openclose) { + // Open the file + int MYPE; + MPI_Comm_rank(BoutComm::get(), &MYPE); + if (strcmp(filename, "") == 0) + throw BoutException("Datafile::add: Filename has not been set"); + if(!file->openw(filename, MYPE, appending)) + throw BoutException("Datafile::add: Failed to open file!"); + appending = true; + } + + if(!file->is_valid()) + throw BoutException("Datafile::add: File is not valid!"); + + if(floats) + file->setLowPrecision(); + + // Add variable to file + if (!file->addVarFieldPerp(name, save_repeat)) { + throw BoutException("Failed to add FieldPerp variable %s to Datafile", name); + } + + if(openclose) { + file->close(); + } + } +} + void Datafile::add(Vector2D &f, const char *name, bool save_repeat) { TRACE("DataFile::add(Vector2D)"); if (!enabled) @@ -809,6 +875,11 @@ bool Datafile::read() { read_f3d(var.name, var.ptr, var.save_repeat); } + // Read FieldPerps + for(const auto& var : fperp_arr) { + read_fperp(var.name, var.ptr, var.save_repeat); + } + // 2D vectors for(const auto& var : v2d_arr) { if(var.covar) { @@ -855,6 +926,19 @@ void Datafile::writeFieldAttributes(const std::string& name, const Field& f) { file->setAttribute(name, "direction_z", toString(f.getDirectionZ())); } +void Datafile::writeFieldAttributes(const std::string& name, const FieldPerp& f) { + writeFieldAttributes(name, static_cast(f)); + + int yindex = f.getIndex(); + if (yindex >= 0 and yindex < f.getMesh()->LocalNy) { + // write global y-index as attribute + file->setAttribute(name, "yindex_global", f.getMesh()->YGLOBAL(f.getIndex())); + } else { + // y-index is not valid, set global y-index to -1 to indicate 'not-valid' + file->setAttribute(name, "yindex_global", -1); + } +} + bool Datafile::write() { if(!enabled) return true; // Just pretend it worked @@ -900,6 +984,11 @@ bool Datafile::write() { writeFieldAttributes(var.name, *var.ptr); } + // FieldPerps + for (const auto& var : fperp_arr) { + writeFieldAttributes(var.name, *var.ptr); + } + // 2D vectors for(const auto& var : v2d_arr) { Vector2D v = *(var.ptr); @@ -937,6 +1026,11 @@ bool Datafile::write() { write_f3d(var.name, var.ptr, var.save_repeat); } + // Write FieldPerps + for (const auto& var : fperp_arr) { + write_fperp(var.name, var.ptr, var.save_repeat); + } + // 2D vectors for(const auto& var : v2d_arr) { if(var.covar) { @@ -1162,6 +1256,39 @@ bool Datafile::read_f3d(const std::string &name, Field3D *f, bool save_repeat) { return true; } +bool Datafile::read_fperp(const std::string &name, FieldPerp *f, bool save_repeat) { + f->allocate(); + + if(save_repeat) { + if(!file->read_rec(&((*f)(0,0)), name, mesh->LocalNx, 0, mesh->LocalNz)) { + if(init_missing) { + output_warn.write("\tWARNING: Could not read FieldPerp %s. Setting to zero\n", name.c_str()); + *f = 0.0; + }else { + throw BoutException("Missing evolving FieldPerp %s in input. Set init_missing=true to set to zero.", name.c_str()); + } + return false; + } + }else { + if(!file->read(&((*f)(0,0)), name, mesh->LocalNx, 0, mesh->LocalNz)) { + if(init_missing) { + output_warn.write("\tWARNING: Could not read FieldPerp %s. Setting to zero\n", name.c_str()); + *f = 0.0; + }else { + throw BoutException("Missing FieldPerp %s in input. Set init_missing=true to set to zero.", name.c_str()); + } + return false; + } + } + + if (shiftInput) { + // Input file is in field-aligned coordinates e.g. BOUT++ 3.x restart file + *f = fromFieldAligned(*f, RGN_ALL); + } + + return true; +} + bool Datafile::write_int(const std::string &name, int *f, bool save_repeat) { if(save_repeat) { return file->write_rec(f, name); @@ -1214,6 +1341,26 @@ bool Datafile::write_f3d(const std::string &name, Field3D *f, bool save_repeat) } } +bool Datafile::write_fperp(const std::string &name, FieldPerp *f, bool save_repeat) { + if (!f->isAllocated()) { + throw BoutException("Datafile::write_fperp: FieldPerp '%s' is not allocated!", name.c_str()); + } + + //Deal with shifting the output + FieldPerp f_out{emptyFrom(*f)}; + if(shiftOutput) { + f_out = toFieldAligned(*f); + }else { + f_out = *f; + } + + if(save_repeat) { + return file->write_rec(&(f_out(0,0)), name, mesh->LocalNx, 0, mesh->LocalNz); + }else { + return file->write(&(f_out(0,0)), name, mesh->LocalNx, 0, mesh->LocalNz); + } +} + bool Datafile::varAdded(const std::string &name) { for(const auto& var : int_arr ) { if(name == var.name) diff --git a/src/fileio/impls/hdf5/h5_format.cxx b/src/fileio/impls/hdf5/h5_format.cxx index c9ac9a155a..a1245a0f8c 100644 --- a/src/fileio/impls/hdf5/h5_format.cxx +++ b/src/fileio/impls/hdf5/h5_format.cxx @@ -256,27 +256,47 @@ bool H5Format::setRecord(int t) { } // Add a variable to the file -bool H5Format::addVar(const std::string &name, bool repeat, hid_t write_hdf5_type, int nd) { +bool H5Format::addVar(const std::string &name, bool repeat, hid_t write_hdf5_type, + std::string datatype) { hid_t dataSet = H5Dopen(dataFile, name.c_str(), H5P_DEFAULT); if (dataSet >= 0) { // >=0 means variable already exists, so return. if (H5Dclose(dataSet) < 0) throw BoutException("Failed to close dataSet"); return true; } + + int nd = 0; + if (datatype == "scalar") nd = 0; + else if (datatype == "FieldX") nd = 1; + else if (datatype == "Field2D") nd = 2; + else if (datatype == "FieldPerp") nd = 2; + else if (datatype == "Field3D") nd = 3; + else throw BoutException("Unrecognized datatype '"+datatype+"'"); + if (repeat) { - nd += 1; // add time dimension + // add time dimension + datatype += "_t"; + nd += 1; hsize_t init_size[4]; if (parallel) { init_size[0]=0; init_size[1]=mesh->GlobalNx-2*mesh->xstart; - init_size[2]=mesh->GlobalNy-2*mesh->ystart; + if (datatype == "FieldPerp_t") { + init_size[2]=mesh->GlobalNz; + } else { + init_size[2]=mesh->GlobalNy-2*mesh->ystart; + } init_size[3]=mesh->GlobalNz; } else { init_size[0]=0; init_size[1]=mesh->LocalNx; - init_size[2]=mesh->LocalNy; + if (datatype == "FieldPerp_t") { + init_size[2]=mesh->LocalNz; + } else { + init_size[2]=mesh->LocalNy; + } init_size[3]=mesh->LocalNz; } @@ -298,10 +318,6 @@ bool H5Format::addVar(const std::string &name, bool repeat, hid_t write_hdf5_typ throw BoutException("Failed to create dataSet"); // Add attribute to say what kind of field this is - std::string datatype = "scalar_t"; - if(nd > 1) datatype = "FieldX_t"; - if(nd == 3) datatype = "Field2D_t"; - if(nd == 4) datatype = "Field3D_t"; // Create new dataspace for attribute hid_t attribute_dataspace = H5Screate(H5S_SCALAR); @@ -339,19 +355,23 @@ bool H5Format::addVar(const std::string &name, bool repeat, hid_t write_hdf5_typ hsize_t init_size[3]; if (parallel) { init_size[0] = mesh->GlobalNx - 2 * mesh->xstart; - init_size[1] = mesh->GlobalNy - 2 * mesh->ystart; + if (datatype == "FieldPerp") { + init_size[1] = mesh->GlobalNy - 2 * mesh->ystart; + } else { + init_size[1] = mesh->GlobalNz; + } init_size[2] = mesh->GlobalNz; } else { init_size[0] = mesh->LocalNx; - init_size[1] = mesh->LocalNy; + if (datatype == "FieldPerp") { + init_size[1] = mesh->LocalNz; + } else { + init_size[1] = mesh->LocalNy; + } init_size[2] = mesh->LocalNz; } // Create value for attribute to say what kind of field this is - std::string datatype = "scalar"; - if(nd > 0) datatype = "FieldX"; - if(nd == 2) datatype = "Field2D"; - if(nd == 3) datatype = "Field3D"; if (nd==0) { // Need to write a scalar, not a 0-d array @@ -377,22 +397,27 @@ bool H5Format::addVar(const std::string &name, bool repeat, hid_t write_hdf5_typ } bool H5Format::addVarInt(const std::string &name, bool repeat) { - return addVar(name, repeat, H5T_NATIVE_INT, 0); + return addVar(name, repeat, H5T_NATIVE_INT, "scalar"); } bool H5Format::addVarBoutReal(const std::string &name, bool repeat) { auto h5_float_type = lowPrecision ? H5T_NATIVE_FLOAT : H5T_NATIVE_DOUBLE; - return addVar(name, repeat, h5_float_type, 0); + return addVar(name, repeat, h5_float_type, "scalar"); } bool H5Format::addVarField2D(const std::string &name, bool repeat) { auto h5_float_type = lowPrecision ? H5T_NATIVE_FLOAT : H5T_NATIVE_DOUBLE; - return addVar(name, repeat, h5_float_type, 2); + return addVar(name, repeat, h5_float_type, "Field2D"); } bool H5Format::addVarField3D(const std::string &name, bool repeat) { auto h5_float_type = lowPrecision ? H5T_NATIVE_FLOAT : H5T_NATIVE_DOUBLE; - return addVar(name, repeat, h5_float_type, 3); + return addVar(name, repeat, h5_float_type, "Field3D"); +} + +bool H5Format::addVarFieldPerp(const std::string &name, bool repeat) { + auto h5_float_type = lowPrecision ? H5T_NATIVE_FLOAT : H5T_NATIVE_DOUBLE; + return addVar(name, repeat, h5_float_type, "FieldPerp"); } bool H5Format::read(int *data, const char *name, int lx, int ly, int lz) { diff --git a/src/fileio/impls/hdf5/h5_format.hxx b/src/fileio/impls/hdf5/h5_format.hxx index b319aac461..7e7cbd7976 100644 --- a/src/fileio/impls/hdf5/h5_format.hxx +++ b/src/fileio/impls/hdf5/h5_format.hxx @@ -86,6 +86,7 @@ class H5Format : public DataFormat { bool addVarBoutReal(const std::string &name, bool repeat) override; bool addVarField2D(const std::string &name, bool repeat) override; bool addVarField3D(const std::string &name, bool repeat) override; + bool addVarFieldPerp(const std::string &name, bool repeat) override; // Read / Write simple variables up to 3D @@ -141,7 +142,7 @@ class H5Format : public DataFormat { hsize_t chunk_length; - bool addVar(const std::string &name, bool repeat, hid_t write_hdf5_type, int nd); + bool addVar(const std::string &name, bool repeat, hid_t write_hdf5_type, std::string datatype); bool read(void *var, hid_t hdf5_type, const char *name, int lx = 1, int ly = 0, int lz = 0); bool write(void *var, hid_t mem_hdf5_type, const char *name, int lx = 0, int ly = 0, int lz = 0); bool read_rec(void *var, hid_t hdf5_type, const char *name, int lx = 1, int ly = 0, int lz = 0); diff --git a/src/fileio/impls/netcdf/nc_format.cxx b/src/fileio/impls/netcdf/nc_format.cxx index 97f84c3e53..fc23e5ddfd 100644 --- a/src/fileio/impls/netcdf/nc_format.cxx +++ b/src/fileio/impls/netcdf/nc_format.cxx @@ -474,6 +474,34 @@ bool NcFormat::addVarField3D(const string &name, bool repeat) { return true; } +bool NcFormat::addVarFieldPerp(const string &name, bool repeat) { + if(!is_valid()) + return false; + + // Create an error object so netCDF doesn't exit +#ifdef NCDF_VERBOSE + NcError err(NcError::verbose_nonfatal); +#else + NcError err(NcError::silent_nonfatal); +#endif + + NcVar* var; + if (!(var = dataFile->get_var(name.c_str()))) { + // Variable not in file, so add it. + auto nc_float_type = lowPrecision ? ncFloat : ncDouble; + if (repeat) + var = dataFile->add_var(name.c_str(), nc_float_type, 3, {tDim, xDim, zDim}); + else + var = dataFile->add_var(name.c_str(), nc_float_type, 2, {xDim, zDim}); + + if(!var->is_valid()) { + output_error.write("ERROR: NetCDF could not add FieldPerp '%s' to file '%s'\n", name.c_str(), fname); + return false; + } + } + return true; +} + bool NcFormat::read(int *data, const char *name, int lx, int ly, int lz) { if(!is_valid()) return false; diff --git a/src/fileio/impls/netcdf/nc_format.hxx b/src/fileio/impls/netcdf/nc_format.hxx index e1ebfaa964..ca007186fa 100644 --- a/src/fileio/impls/netcdf/nc_format.hxx +++ b/src/fileio/impls/netcdf/nc_format.hxx @@ -90,6 +90,7 @@ class NcFormat : public DataFormat { bool addVarBoutReal(const std::string &name, bool repeat) override; bool addVarField2D(const std::string &name, bool repeat) override; bool addVarField3D(const std::string &name, bool repeat) override; + bool addVarFieldPerp(const std::string &name, bool repeat) override; // Read / Write simple variables up to 3D diff --git a/src/fileio/impls/netcdf4/ncxx4.cxx b/src/fileio/impls/netcdf4/ncxx4.cxx index 3078e3c6b6..6d1324acee 100644 --- a/src/fileio/impls/netcdf4/ncxx4.cxx +++ b/src/fileio/impls/netcdf4/ncxx4.cxx @@ -417,6 +417,37 @@ bool Ncxx4::addVarField3D(const string &name, bool repeat) { return true; } +bool Ncxx4::addVarFieldPerp(const string &name, bool repeat) { + if(!is_valid()) + return false; + + NcVar var = dataFile->getVar(name); + if(var.isNull()) { + // Variable not in file, so add it. + if (repeat) { + std::vector vec = {*recDimList[0], *recDimList[1], *recDimList[3]}; + if(lowPrecision) { + var = dataFile->addVar(name, ncFloat, vec); + } else { + var = dataFile->addVar(name, ncDouble, vec); + } + } else { + std::vector vec = {*dimList[0], *dimList[2]}; + if(lowPrecision) { + var = dataFile->addVar(name, ncFloat, vec); + } else { + var = dataFile->addVar(name, ncDouble, vec); + } + } + + if(var.isNull()) { + output_error.write("ERROR: NetCDF could not add FieldPerp '%s' to file '%s'\n", name.c_str(), fname); + return false; + } + } + return true; +} + bool Ncxx4::read(int *data, const char *name, int lx, int ly, int lz) { TRACE("Ncxx4::read(int)"); diff --git a/src/fileio/impls/netcdf4/ncxx4.hxx b/src/fileio/impls/netcdf4/ncxx4.hxx index 497b32df0b..8e95b98d8c 100644 --- a/src/fileio/impls/netcdf4/ncxx4.hxx +++ b/src/fileio/impls/netcdf4/ncxx4.hxx @@ -91,6 +91,7 @@ class Ncxx4 : public DataFormat { bool addVarBoutReal(const std::string &name, bool repeat) override; bool addVarField2D(const std::string &name, bool repeat) override; bool addVarField3D(const std::string &name, bool repeat) override; + bool addVarFieldPerp(const std::string &name, bool repeat) override; // Read / Write simple variables up to 3D diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 3dc18a8af1..0282377f80 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -297,20 +297,22 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) "nor grid_xguards = 0", name.c_str(), grid_xguards, mxg); } - ///Check if field dimensions are correct. y-direction - if (grid_yguards > 0) { ///including ghostpoints - ASSERT1(field_dimensions[1] == m->GlobalNy - 2*myg + total_grid_yguards); - ny_to_read = m->LocalNy; - yd = grid_yguards - myg; - ASSERT1(yd >= 0); - } else if (grid_yguards == 0) { ///excluding ghostpoints - ASSERT1(field_dimensions[1] == m->GlobalNy - 2*myg); - ny_to_read = m->LocalNy - 2*myg; - yd = myg; - } else { - throw BoutException("Could not read '%s' from file: number of y-boundary guard cells " - "in the grid file grid_yguards=%i neither matches grid_yguards >= myg=%i " - "nor grid_yguards = 0", name.c_str(), grid_yguards, myg); + if (not std::is_base_of::value) { + ///Check if field dimensions are correct. y-direction + if (grid_yguards > 0) { ///including ghostpoints + ASSERT1(field_dimensions[1] == m->GlobalNy - 2*myg + total_grid_yguards); + ny_to_read = m->LocalNy; + yd = grid_yguards - myg; + ASSERT1(yd >= 0); + } else if (grid_yguards == 0) { ///excluding ghostpoints + ASSERT1(field_dimensions[1] == m->GlobalNy - 2*myg); + ny_to_read = m->LocalNy - 2*myg; + yd = myg; + } else { + throw BoutException("Could not read '%s' from file: number of y-boundary guard cells " + "in the grid file grid_yguards=%i neither matches grid_yguards >= myg=%i " + "nor grid_yguards = 0", name.c_str(), grid_yguards, myg); + } } // Now read data from file From 100fd424092262d15f91a7322d6e88a8ddf98ad7 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 28 Apr 2019 21:53:48 +0100 Subject: [PATCH 1346/1783] Fix FieldPerp I/O Need special read/write functions because FieldPerps don't have 'standard' order of dimensions ('z' comes right after 'x'). --- include/dataformat.hxx | 4 + src/fileio/datafile.cxx | 8 +- src/fileio/impls/hdf5/h5_format.cxx | 282 ++++++++++++++++++++++++++ src/fileio/impls/hdf5/h5_format.hxx | 4 + src/fileio/impls/netcdf/nc_format.cxx | 201 ++++++++++++++++++ src/fileio/impls/netcdf/nc_format.hxx | 4 + src/fileio/impls/netcdf4/ncxx4.cxx | 167 +++++++++++++++ src/fileio/impls/netcdf4/ncxx4.hxx | 4 + 8 files changed, 670 insertions(+), 4 deletions(-) diff --git a/include/dataformat.hxx b/include/dataformat.hxx index 19665cf333..908373c443 100644 --- a/include/dataformat.hxx +++ b/include/dataformat.hxx @@ -86,11 +86,13 @@ class DataFormat { virtual bool read(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) = 0; virtual bool read(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) = 0; virtual bool read(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) = 0; + virtual bool read_perp(BoutReal *var, const std::string &name, int lx = 1, int lz = 0) = 0; virtual bool write(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) = 0; virtual bool write(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) = 0; virtual bool write(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) = 0; virtual bool write(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) = 0; + virtual bool write_perp(BoutReal *var, const std::string &name, int lx = 0, int lz = 0) = 0; // Read / Write record-based variables @@ -98,11 +100,13 @@ class DataFormat { virtual bool read_rec(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) = 0; virtual bool read_rec(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) = 0; virtual bool read_rec(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) = 0; + virtual bool read_rec_perp(BoutReal *var, const std::string &name, int lx = 1, int lz = 0) = 0; virtual bool write_rec(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) = 0; virtual bool write_rec(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) = 0; virtual bool write_rec(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) = 0; virtual bool write_rec(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) = 0; + virtual bool write_rec_perp(BoutReal *var, const std::string &name, int lx = 0, int lz = 0) = 0; // Optional functions diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index e812296ec8..4b50ade5e1 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -1260,7 +1260,7 @@ bool Datafile::read_fperp(const std::string &name, FieldPerp *f, bool save_repea f->allocate(); if(save_repeat) { - if(!file->read_rec(&((*f)(0,0)), name, mesh->LocalNx, 0, mesh->LocalNz)) { + if(!file->read_rec_perp(&((*f)(0,0)), name, mesh->LocalNx, mesh->LocalNz)) { if(init_missing) { output_warn.write("\tWARNING: Could not read FieldPerp %s. Setting to zero\n", name.c_str()); *f = 0.0; @@ -1270,7 +1270,7 @@ bool Datafile::read_fperp(const std::string &name, FieldPerp *f, bool save_repea return false; } }else { - if(!file->read(&((*f)(0,0)), name, mesh->LocalNx, 0, mesh->LocalNz)) { + if(!file->read_perp(&((*f)(0,0)), name, mesh->LocalNx, mesh->LocalNz)) { if(init_missing) { output_warn.write("\tWARNING: Could not read FieldPerp %s. Setting to zero\n", name.c_str()); *f = 0.0; @@ -1355,9 +1355,9 @@ bool Datafile::write_fperp(const std::string &name, FieldPerp *f, bool save_repe } if(save_repeat) { - return file->write_rec(&(f_out(0,0)), name, mesh->LocalNx, 0, mesh->LocalNz); + return file->write_rec_perp(&(f_out(0,0)), name, mesh->LocalNx, mesh->LocalNz); }else { - return file->write(&(f_out(0,0)), name, mesh->LocalNx, 0, mesh->LocalNz); + return file->write_perp(&(f_out(0,0)), name, mesh->LocalNx, mesh->LocalNz); } } diff --git a/src/fileio/impls/hdf5/h5_format.cxx b/src/fileio/impls/hdf5/h5_format.cxx index a1245a0f8c..6b9af4a99b 100644 --- a/src/fileio/impls/hdf5/h5_format.cxx +++ b/src/fileio/impls/hdf5/h5_format.cxx @@ -491,6 +491,60 @@ bool H5Format::read(void *data, hid_t hdf5_type, const char *name, int lx, int l return true; } +bool H5Format::read_perp(BoutReal *data, const std::string& name, int lx, int lz) { + TRACE("H5Format::read(void)"); + + hid_t hdf5_type = H5T_NATIVE_DOUBLE; + + if(!is_valid()) + return false; + + if((lx < 0) || (lz < 0)) + return false; + + int nd = 0; // Number of dimensions + if(lx != 0) nd = 1; + if(lz != 0) nd = 2; + hsize_t counts[2],offset[2],offset_local[2],init_size_local[2]; + counts[0]=lx; counts[1]=lz; + offset[0]=x0; offset[1]=z0; + offset_local[0]=x0_local; + offset_local[1]=z0_local; + + // Want to be able to use without needing mesh to be initialised; makes hyperslab selection redundant + init_size_local[0]=offset_local[0]+counts[0]; + init_size_local[1]=offset_local[1]+counts[1]; + + hid_t mem_space = H5Screate_simple(nd, init_size_local, init_size_local); + if (mem_space < 0) + throw BoutException("Failed to create mem_space"); + + hid_t dataSet = H5Dopen(dataFile, name.c_str(), H5P_DEFAULT); + if (dataSet < 0) { + return false; + } + + hid_t dataSpace = H5Dget_space(dataSet); + if (dataSpace < 0) + throw BoutException("Failed to create dataSpace"); + if (nd > 0 && !(nd==1 && lx==1)) + if (H5Sselect_hyperslab(dataSpace, H5S_SELECT_SET, offset, /*stride=*/nullptr, counts, + /*block=*/nullptr) < 0) + throw BoutException("Failed to select hyperslab"); + + if (H5Dread(dataSet, hdf5_type, mem_space, dataSpace, H5P_DEFAULT, data) < 0) + throw BoutException("Failed to read data"); + + if (H5Sclose(mem_space) < 0) + throw BoutException("Failed to close mem_space"); + if (H5Sclose(dataSpace) < 0) + throw BoutException("Failed to close dataSpace"); + if (H5Dclose(dataSet) < 0) + throw BoutException("Failed to close dataSet"); + + return true; +} + bool H5Format::write(int *data, const char *name, int lx, int ly, int lz) { return write(data, H5T_NATIVE_INT, name, lx, ly, lz); } @@ -599,6 +653,72 @@ bool H5Format::write(void *data, hid_t mem_hdf5_type, const char *name, int lx, return true; } +bool H5Format::write_perp(BoutReal *data, const std::string& name, int lx, int lz) { + TRACE("H5Format::write_perp(void)"); + + hid_t mem_hdf5_type = H5T_NATIVE_DOUBLE; + + if(!is_valid()) + return false; + + if((lx < 0) || (lz < 0)) + return false; + + int nd = 0; // Number of dimensions + if(lx != 0) nd = 1; + if(lz != 0) nd = 2; + hsize_t counts[2], offset[2], offset_local[2], init_size_local[2]; + counts[0] = lx; + counts[1] = lz; + offset[0] = x0; + offset[1] = z0; + offset_local[0] = x0_local; + offset_local[1] = z0_local; + init_size_local[0] = mesh->LocalNx; + init_size_local[1] = mesh->LocalNz; + + if (nd==0) { + // Need to write a scalar, not a 0-d array + nd = 1; + counts[0] = 1; + offset[0] = 0; + offset_local[0] = 0; + init_size_local[0] = 1; + } + + hid_t mem_space = H5Screate_simple(nd, init_size_local, init_size_local); + if (mem_space < 0) + throw BoutException("Failed to create mem_space"); + if (H5Sselect_hyperslab(mem_space, H5S_SELECT_SET, offset_local, /*stride=*/nullptr, + counts, /*block=*/nullptr) < 0) + throw BoutException("Failed to select hyperslab"); + + hid_t dataSet = H5Dopen(dataFile, name.c_str(), H5P_DEFAULT); + if (dataSet < 0) { + output_error.write("ERROR: HDF5 variable '%s' has not been added to file '%s'\n", name.c_str(), fname); + return false; + } + + hid_t dataSpace = H5Dget_space(dataSet); + if (dataSpace < 0) + throw BoutException("Failed to create dataSpace"); + if (H5Sselect_hyperslab(dataSpace, H5S_SELECT_SET, offset, /*stride=*/nullptr, counts, + /*block=*/nullptr) < 0) + throw BoutException("Failed to select hyperslab"); + + if (H5Dwrite(dataSet, mem_hdf5_type, mem_space, dataSpace, dataSet_plist, data) < 0) + throw BoutException("Failed to write data"); + + if (H5Sclose(mem_space) < 0) + throw BoutException("Failed to close mem_space"); + if (H5Sclose(dataSpace) < 0) + throw BoutException("Failed to close dataSpace"); + if (H5Dclose(dataSet) < 0) + throw BoutException("Failed to close dataSet"); + + return true; +} + /*************************************************************************** * Record-based (time-dependent) data ***************************************************************************/ @@ -697,6 +817,76 @@ bool H5Format::read_rec(void *data, hid_t hdf5_type, const char *name, int lx, i return true; } +bool H5Format::read_rec_perp(BoutReal *data, const std::string& name, int lx, int lz) { + if (!is_valid()) { + return false; + } + + hid_t hdf5_type = H5T_NATIVE_DOUBLE; + + if ((lx < 0) || (lz < 0)) { + return false; + } + + int nd = 1; // Number of dimensions + if (lx != 0) { + nd = 2; + } + if (lz != 0) { + nd = 3; + } + hsize_t counts[3], offset[3]; + hsize_t offset_local[2], init_size_local[2]; + counts[0] = 1; + counts[1] = lx; + counts[2] = lz; + offset[0] = t0; + offset[1] = x0; + offset[2] = z0; + offset_local[0] = x0_local; + offset_local[1] = z0_local; + init_size_local[0] = mesh->LocalNx; + init_size_local[1] = mesh->LocalNz; + + if (nd == 1) { + // Need to write a time-series of scalars + nd = 1; + counts[1] = 1; + offset[1] = 0; + init_size_local[0] = 1; + } + + hid_t mem_space = H5Screate_simple(nd, init_size_local, init_size_local); + if (mem_space < 0) + throw BoutException("Failed to create mem_space"); + if (H5Sselect_hyperslab(mem_space, H5S_SELECT_SET, offset_local, /*stride=*/nullptr, + counts, /*block=*/nullptr) < 0) + throw BoutException("Failed to select hyperslab"); + + hid_t dataSet = H5Dopen(dataFile, name.c_str(), H5P_DEFAULT); + if (dataSet < 0) + throw BoutException("Failed to open dataSet"); + + hid_t dataSpace = H5Dget_space(dataSet); + if (dataSpace < 0) + throw BoutException("Failed to create dataSpace"); + if (H5Sselect_hyperslab(dataSpace, H5S_SELECT_SET, offset, /*stride=*/nullptr, counts, + /*block=*/nullptr) < 0) + throw BoutException("Failed to select hyperslab"); + + if (H5Dread(dataSet, hdf5_type, mem_space, dataSpace, H5P_DEFAULT, data) < 0) + throw BoutException("Failed to read data"); + + if (H5Sclose(mem_space) < 0) + throw BoutException("Failed to close mem_space"); + if (H5Sclose(dataSpace) < 0) + throw BoutException("Failed to close dataSpace"); + if (H5Dclose(dataSet) < 0) + throw BoutException("Failed to close dataSet"); + + return true; +} + bool H5Format::write_rec(int *data, const char *name, int lx, int ly, int lz) { return write_rec(data, H5T_NATIVE_INT, name, lx, ly, lz); } @@ -828,6 +1018,98 @@ bool H5Format::write_rec(void *data, hid_t mem_hdf5_type, const char *name, int return true; } +bool H5Format::write_rec_perp(BoutReal *data, const std::string& name, int lx, int lz) { + if(!is_valid()) + return false; + + hid_t mem_hdf5_type = H5T_NATIVE_DOUBLE; + + if((lx < 0) || (lz < 0)) + return false; + + int nd = 1; // Number of dimensions + if(lx != 0) nd = 2; + if(lz != 0) nd = 3; + int nd_local = nd-1; + hsize_t counts[3], offset[3]; + hsize_t counts_local[2], offset_local[2], init_size_local[2]; + counts[0] = 1; + counts[1] = lx; + counts[2] = lz; + counts_local[0] = lx; + counts_local[1] = lz; + // Do this later, after setting t0// offset[0]=t0; + offset[1] = x0; + offset[2] = z0; + offset_local[0] = x0_local; + offset_local[1] = z0_local; + init_size_local[0] = mesh->LocalNx; + init_size_local[1] = mesh->LocalNz; + + if (nd_local == 0) { + nd_local = 1; + // Need to write a time-series of scalars + counts_local[0] = 1; + offset_local[0] = 0; + init_size_local[0] = 1; + } + + hid_t mem_space = H5Screate_simple(nd_local, init_size_local, init_size_local); + if (mem_space < 0) + throw BoutException("Failed to create mem_space"); + if (H5Sselect_hyperslab(mem_space, H5S_SELECT_SET, offset_local, /*stride=*/nullptr, + counts_local, /*block=*/nullptr) < 0) + throw BoutException("Failed to select hyperslab"); + + hid_t dataSet = H5Dopen(dataFile, name.c_str(), H5P_DEFAULT); + if (dataSet >= 0) { // >=0 means file exists, so open. Else error. + + hsize_t dims[3] = {}; + hid_t dataSpace = H5Dget_space(dataSet); + if (dataSpace < 0) + throw BoutException("Failed to create dataSpace"); + if (H5Sget_simple_extent_dims(dataSpace, dims, /*maxdims=*/nullptr) < 0) + throw BoutException("Failed to get dims"); + dims[0]+=1; + if (t0 == -1) { + // Want t0 to be last record + t0 = dims[0]-1; + } + + if (H5Dset_extent(dataSet, dims) < 0) + throw BoutException("Failed to extend dataSet"); + + if (H5Sclose(dataSpace) < 0) + throw BoutException("Failed to close dataSpace"); + + } + else { + output_error.write("ERROR: HDF5 variable '%s' has not been added to file '%s'\n", name.c_str(), fname); + return false; + } + + offset[0]=t0; + + hid_t dataSpace = H5Dget_space(dataSet); + if (dataSpace < 0) + throw BoutException("Failed to create dataSpace"); + if (H5Sselect_hyperslab(dataSpace, H5S_SELECT_SET, offset, /*stride=*/nullptr, counts, + /*block=*/nullptr) < 0) + throw BoutException("Failed to select hyperslab"); + + if (H5Dwrite(dataSet, mem_hdf5_type, mem_space, dataSpace, dataSet_plist, data) < 0) + throw BoutException("Failed to write data"); + + if (H5Sclose(mem_space) < 0) + throw BoutException("Failed to close mem_space"); + if (H5Sclose(dataSpace) < 0) + throw BoutException("Failed to close dataSpace"); + if (H5Dclose(dataSet) < 0) + throw BoutException("Failed to close dataSet"); + + return true; +} + /*************************************************************************** * Attributes diff --git a/src/fileio/impls/hdf5/h5_format.hxx b/src/fileio/impls/hdf5/h5_format.hxx index 7e7cbd7976..17f8c35f0c 100644 --- a/src/fileio/impls/hdf5/h5_format.hxx +++ b/src/fileio/impls/hdf5/h5_format.hxx @@ -94,11 +94,13 @@ class H5Format : public DataFormat { bool read(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool read(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; bool read(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read_perp(BoutReal *var, const std::string &name, int lx = 1, int lz = 0) override; bool write(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; bool write(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write_perp(BoutReal *var, const std::string &name, int lx = 0, int lz = 0) override; // Read / Write record-based variables @@ -106,11 +108,13 @@ class H5Format : public DataFormat { bool read_rec(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool read_rec(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; bool read_rec(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read_rec_perp(BoutReal *var, const std::string &name, int lx = 1, int lz = 0) override; bool write_rec(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write_rec_perp(BoutReal *var, const std::string &name, int lx = 0, int lz = 0) override; void setLowPrecision() override { lowPrecision = true; } diff --git a/src/fileio/impls/netcdf/nc_format.cxx b/src/fileio/impls/netcdf/nc_format.cxx index fc23e5ddfd..58c9c877b7 100644 --- a/src/fileio/impls/netcdf/nc_format.cxx +++ b/src/fileio/impls/netcdf/nc_format.cxx @@ -597,6 +597,43 @@ bool NcFormat::read(BoutReal *var, const string &name, int lx, int ly, int lz) { return read(var, name.c_str(), lx, ly, lz); } +bool NcFormat::read_perp(BoutReal *data, const std::string& name, int lx, int lz) { + if(!is_valid()) + return false; + + if((lx < 0) || (lz < 0)) + return false; + + TRACE("NcFormat::read_perp(BoutReal)"); + + // Create an error object so netCDF doesn't exit +#ifdef NCDF_VERBOSE + NcError err(NcError::verbose_nonfatal); +#else + NcError err(NcError::silent_nonfatal); +#endif + + NcVar *var; + + if(!(var = dataFile->get_var(name))) { + return false; + } + + long cur[2], counts[2]; + cur[0] = x0; cur[1] = z0; + counts[0] = lx; counts[1] = lz; + + if(!(var->set_cur(cur))) { + return false; + } + + if(!(var->get(data, counts))) { + return false; + } + + return true; +} + bool NcFormat::write(int *data, const char *name, int lx, int ly, int lz) { if(!is_valid()) return false; @@ -700,6 +737,63 @@ bool NcFormat::write(BoutReal *var, const string &name, int lx, int ly, int lz) return write(var, name.c_str(), lx, ly, lz); } +bool NcFormat::write_perp(BoutReal *data, const std::string& name, int lx, int lz) { + if(!is_valid()) + return false; + + if((lx < 0) || (lz < 0)) + return false; + + // Check for valid name + checkName(name); + + TRACE("NcFormat::write_perp(BoutReal)"); + +#ifdef NCDF_VERBOSE + NcError err(NcError::verbose_nonfatal); +#else + NcError err(NcError::silent_nonfatal); +#endif + + NcVar *var; + if(!(var = dataFile->get_var(name))) { + output_error.write("ERROR: NetCDF BoutReal variable '%s' has not been added to file '%s'\n", name, fname); + return false; + } + + long cur[2], counts[2]; + cur[0] = x0; cur[1] = z0; + counts[0] = lx; counts[1] = lz; + + if(!(var->set_cur(cur))) + return false; + + if(lowPrecision) { + // An out of range value can make the conversion + // corrupt the whole dataset. Make sure everything + // is in the range of a float + int i_max=1; + if (lx>0) i_max*=lx; + if (lz>0) i_max*=lz; + for(int i=0;i 1e20) + data[i] = 1e20; + if(data[i] < -1e20) + data[i] = -1e20; + } + } + + for(int i=0;iput(data, counts))) + return false; + + return true; +} + /*************************************************************************** * Record-based (time-dependent) data ***************************************************************************/ @@ -786,6 +880,43 @@ bool NcFormat::read_rec(BoutReal *var, const string &name, int lx, int ly, int l return read_rec(var, name.c_str(), lx, ly, lz); } +bool NcFormat::read_rec_perp(BoutReal *data, const std::string& name, int lx, int lz) { + if(!is_valid()) + return false; + + if((lx < 0) || (lz < 0)) + return false; + + // Check for valid name + checkName(name); + + // Create an error object so netCDF doesn't exit +#ifdef NCDF_VERBOSE + NcError err(NcError::verbose_nonfatal); +#else + NcError err(NcError::silent_nonfatal); +#endif + + NcVar *var; + + if(!(var = dataFile->get_var(name))) + return false; + + // NOTE: Probably should do something here to check t0 + + long cur[3], counts[3]; + cur[0] = t0; cur[1] = x0; cur[2] = z0; + counts[0] = 1; counts[1] = lx; counts[2] = lz; + + if(!(var->set_cur(cur))) + return false; + + if(!(var->get(data, counts))) + return false; + + return true; +} + bool NcFormat::write_rec(int *data, const char *name, int lx, int ly, int lz) { if(!is_valid()) return false; @@ -906,6 +1037,76 @@ bool NcFormat::write_rec(BoutReal *var, const string &name, int lx, int ly, int return write_rec(var, name.c_str(), lx, ly, lz); } +bool NcFormat::write_rec_perp(BoutReal *data, const std::string& name, int lx, int lz) { + if(!is_valid()) + return false; + + if((lx < 0) || (lz < 0)) + return false; + + // Check the name + checkName(name); + + TRACE("NcFormat::write_rec_perp(BoutReal*)"); + +#ifdef NCDF_VERBOSE + NcError err(NcError::verbose_nonfatal); +#else + NcError err(NcError::silent_nonfatal); +#endif + + NcVar *var; + + // Try to find variable + if(!(var = dataFile->get_var(name))) { + output_error.write("ERROR: NetCDF BoutReal variable '%s' has not been added to file '%s'\n", name, fname); + return false; + }else { + // Get record number + if(rec_nr.find(name) == rec_nr.end()) { + // Add to map + rec_nr[name] = default_rec; + } + } + + int t = rec_nr[name]; + +#ifdef NCDF_VERBOSE + output_info.write("INFO: NetCDF writing record %d of '%s' in '%s'\n",t, name, fname); +#endif + + if(lowPrecision) { + // An out of range value can make the conversion + // corrupt the whole dataset. Make sure everything + // is in the range of a float + + for(int i=0;i 1e20) + data[i] = 1e20; + if(data[i] < -1e20) + data[i] = -1e20; + } + } + int i_max=1; + if (lx>0) i_max*=lx; + if (lz>0) i_max*=lz; + for(int i=0;iput_rec(data, t)) + return false; + + var->sync(); + + // Increment record number + rec_nr[name] = rec_nr[name] + 1; + + return true; +} + /*************************************************************************** * Attributes ***************************************************************************/ diff --git a/src/fileio/impls/netcdf/nc_format.hxx b/src/fileio/impls/netcdf/nc_format.hxx index ca007186fa..b1e801158c 100644 --- a/src/fileio/impls/netcdf/nc_format.hxx +++ b/src/fileio/impls/netcdf/nc_format.hxx @@ -98,11 +98,13 @@ class NcFormat : public DataFormat { bool read(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool read(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; bool read(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read_perp(BoutReal *var, const std::string &name, int lx = 1, int lz = 0) override; bool write(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; bool write(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write_perp(BoutReal *var, const std::string &name, int lx = 0, int lz = 0) override; // Read / Write record-based variables @@ -110,11 +112,13 @@ class NcFormat : public DataFormat { bool read_rec(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool read_rec(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; bool read_rec(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read_perp(BoutReal *var, const std::string &name, int lx = 1, int lz = 0) override; bool write_rec(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write_perp(BoutReal *var, const std::string &name, int lx = 0, int lz = 0) override; void setLowPrecision() override { lowPrecision = true; } diff --git a/src/fileio/impls/netcdf4/ncxx4.cxx b/src/fileio/impls/netcdf4/ncxx4.cxx index 6d1324acee..17c5a4623b 100644 --- a/src/fileio/impls/netcdf4/ncxx4.cxx +++ b/src/fileio/impls/netcdf4/ncxx4.cxx @@ -515,6 +515,34 @@ bool Ncxx4::read(BoutReal *var, const std::string &name, int lx, int ly, int lz) return read(var, name.c_str(), lx, ly, lz); } +bool Ncxx4::read_perp(BoutReal *data, const std::string& name, int lx, int lz) { + TRACE("Ncxx4::read_perp(BoutReal)"); + +#ifdef NCDF_VERBOSE + output.write("Ncxx4:: read(BoutReal, %s)\n", name); +#endif + if(!is_valid()) + return false; + + if((lx < 0) || (lz < 0)) + return false; + + NcVar var = dataFile->getVar(name); + + if(var.isNull()) { + return false; + } + + std::vector start(2); + start[0] = x0; start[1] = z0; + std::vector counts(2); + counts[0] = lx; counts[1] = lz; + + var.getVar(start, counts, data); + + return true; +} + bool Ncxx4::write(int *data, const char *name, int lx, int ly, int lz) { TRACE("Ncxx4::write(int)"); @@ -605,6 +633,54 @@ bool Ncxx4::write(BoutReal *var, const std::string &name, int lx, int ly, int lz return write(var, name.c_str(), lx, ly, lz); } +bool Ncxx4::write_perp(BoutReal *data, const std::string& name, int lx, int lz) { + TRACE("Ncxx4::write_perp(BoutReal)"); + +#ifdef NCDF_VERBOSE + output.write("Ncxx4:: write_perp(BoutReal, %s)\n", name); +#endif + if(!is_valid()) + return false; + + if((lx < 0) || (lz < 0)) + return false; + + NcVar var = dataFile->getVar(name); + if(var.isNull()) { + output_error.write( + "ERROR: NetCDF BoutReal variable '%s' has not been added to file '%s'\n", + name.c_str(), fname); + return false; + } + + std::vector start(2); + start[0] = x0; start[1] = z0; + std::vector counts(2); + counts[0] = lx; counts[1] = lz; + + if(lowPrecision) { + // An out of range value can make the conversion + // corrupt the whole dataset. Make sure everything + // is in the range of a float + + for(int i=0;i 1e20) + data[i] = 1e20; + if(data[i] < -1e20) + data[i] = -1e20; + } + } + + for(int i=0;igetVar(name); + + if(var.isNull()) + return false; + + // NOTE: Probably should do something here to check t0 + + std::vector start(3); + start[0] = t0; start[1] = x0; start[2] = z0; + std::vector counts(4); + counts[0] = 1; counts[1] = lx; counts[2] = lz; + + var.getVar(start, counts, data); + + return true; +} + bool Ncxx4::write_rec(int *data, const char *name, int lx, int ly, int lz) { #ifdef NCDF_VERBOSE output.write("Ncxx4:: write_rec(int, %s)\n", name); @@ -782,6 +885,70 @@ bool Ncxx4::write_rec(BoutReal *var, const std::string &name, int lx, int ly, in return write_rec(var, name.c_str(), lx, ly, lz); } +bool Ncxx4::write_rec_perp(BoutReal *data, const std::string& name, int lx, int lz) { + TRACE("Ncxx4::write_rec_perp(BoutReal)"); + +#ifdef NCDF_VERBOSE + output.write("Ncxx4::write_rec_perp(BoutReal, %s)\n", name); +#endif + if(!is_valid()) + return false; + + if((lx < 0) || (lz < 0)) + return false; + + // Try to find variable + NcVar var = dataFile->getVar(name); + if(var.isNull()) { + output_error.write( + "ERROR: NetCDF BoutReal variable '%s' has not been added to file '%s'\n", + name.c_str(), fname); + return false; + }else { + // Get record number + if(rec_nr.find(name) == rec_nr.end()) { + // Add to map + rec_nr[name] = default_rec; + } + } + + int t = rec_nr[name]; + +#ifdef NCDF_VERBOSE + output_info.write("INFO: NetCDF writing record %d of '%s' in '%s'\n",t, name, fname); +#endif + + if(lowPrecision) { + // An out of range value can make the conversion + // corrupt the whole dataset. Make sure everything + // is in the range of a float + + for(int i=0;i 1e20) + data[i] = 1e20; + if(data[i] < -1e20) + data[i] = -1e20; + } + } + + for(int i=0;i start(3); + start[0] = t; start[1] = x0; start[2] = z0; + std::vector counts(3); + counts[0] = 1; counts[1] = lx; counts[2] = lz; + + // Add the record + var.putVar(start, counts, data); + + // Increment record number + rec_nr[name] = rec_nr[name] + 1; + + return true; +} /*************************************************************************** * Attributes diff --git a/src/fileio/impls/netcdf4/ncxx4.hxx b/src/fileio/impls/netcdf4/ncxx4.hxx index 8e95b98d8c..dc4a7a8cce 100644 --- a/src/fileio/impls/netcdf4/ncxx4.hxx +++ b/src/fileio/impls/netcdf4/ncxx4.hxx @@ -99,11 +99,13 @@ class Ncxx4 : public DataFormat { bool read(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool read(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; bool read(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read_perp(BoutReal *var, const std::string &name, int lx = 1, int lz = 0) override; bool write(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; bool write(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write_perp(BoutReal *var, const std::string &name, int lx = 0, int lz = 0) override; // Read / Write record-based variables @@ -111,11 +113,13 @@ class Ncxx4 : public DataFormat { bool read_rec(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool read_rec(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; bool read_rec(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; + bool read_rec_perp(BoutReal *var, const std::string &name, int lx = 1, int lz = 0) override; bool write_rec(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; + bool write_rec_perp(BoutReal *var, const std::string &name, int lx = 0, int lz = 0) override; void setLowPrecision() override { lowPrecision = true; } From 850bf5e151418e201a4e1080499de276b6d5bf52 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 00:09:20 +0100 Subject: [PATCH 1347/1783] Read attributes of Fields back from files If attributes were written to files, then read them back when loading from the files. --- include/datafile.hxx | 5 +++ src/fileio/datafile.cxx | 84 ++++++++++++++++++++++++++++++----------- 2 files changed, 67 insertions(+), 22 deletions(-) diff --git a/include/datafile.hxx b/include/datafile.hxx index 88119cb6c4..2086f79ee3 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -147,6 +147,11 @@ class Datafile { /// Overload for FieldPerp so we can also write 'yindex' void writeFieldAttributes(const std::string& name, const FieldPerp& f); + /// Read the attributes of a field from 'file' + void readFieldAttributes(const std::string& name, Field& f); + /// Overload for FieldPerp so we can also write 'yindex' + void readFieldAttributes(const std::string& name, FieldPerp& f); + /// Check if a variable has already been added bool varAdded(const std::string &name); diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 4b50ade5e1..bd3152fb61 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -38,6 +38,7 @@ #include #include #include +#include "bout_types.hxx" #include #include #include @@ -939,6 +940,34 @@ void Datafile::writeFieldAttributes(const std::string& name, const FieldPerp& f) } } +void Datafile::readFieldAttributes(const std::string& name, Field& f) { + std::string location_string; + if (file->getAttribute(name, "cell_location", location_string)) { + f.setLocation(CELL_LOCFromString(location_string)); + } + + std::string direction_y_string; + if (file->getAttribute(name, "direction_y", direction_y_string)) { + f.setDirectionY(YDirectionTypeFromString(direction_y_string)); + } + + std::string direction_z_string; + if (file->getAttribute(name, "direction_z", direction_z_string)) { + f.setDirectionZ(ZDirectionTypeFromString(direction_z_string)); + } +} + +void Datafile::readFieldAttributes(const std::string& name, FieldPerp& f) { + readFieldAttributes(name, static_cast(f)); + + int yindex_global = 0; + if (file->getAttribute(name, "yindex_global", yindex_global)) { + f.setIndex(mesh->YLOCAL(yindex_global)); + } else { + f.setIndex(mesh->YLOCAL(0)); + } +} + bool Datafile::write() { if(!enabled) return true; // Just pretend it worked @@ -1195,6 +1224,8 @@ void Datafile::setAttribute(const std::string &varname, const std::string &attrn ///////////////////////////////////////////////////////////// bool Datafile::read_f2d(const std::string &name, Field2D *f, bool save_repeat) { + readFieldAttributes(name, *f); + f->allocate(); if(save_repeat) { @@ -1223,6 +1254,8 @@ bool Datafile::read_f2d(const std::string &name, Field2D *f, bool save_repeat) { } bool Datafile::read_f3d(const std::string &name, Field3D *f, bool save_repeat) { + readFieldAttributes(name, *f); + f->allocate(); if(save_repeat) { @@ -1257,33 +1290,40 @@ bool Datafile::read_f3d(const std::string &name, Field3D *f, bool save_repeat) { } bool Datafile::read_fperp(const std::string &name, FieldPerp *f, bool save_repeat) { - f->allocate(); + readFieldAttributes(name, *f); - if(save_repeat) { - if(!file->read_rec_perp(&((*f)(0,0)), name, mesh->LocalNx, mesh->LocalNz)) { - if(init_missing) { - output_warn.write("\tWARNING: Could not read FieldPerp %s. Setting to zero\n", name.c_str()); - *f = 0.0; - }else { - throw BoutException("Missing evolving FieldPerp %s in input. Set init_missing=true to set to zero.", name.c_str()); + int yindex = f->getIndex(); + if (yindex >= 0 and yindex < mesh->LocalNy) { + // yindex is in the range of this processor, so read FieldPerp + + f->allocate(); + + if(save_repeat) { + if(!file->read_rec_perp(&((*f)(0,0)), name, mesh->LocalNx, mesh->LocalNz)) { + if(init_missing) { + output_warn.write("\tWARNING: Could not read FieldPerp %s. Setting to zero\n", name.c_str()); + *f = 0.0; + }else { + throw BoutException("Missing evolving FieldPerp %s in input. Set init_missing=true to set to zero.", name.c_str()); + } + return false; } - return false; - } - }else { - if(!file->read_perp(&((*f)(0,0)), name, mesh->LocalNx, mesh->LocalNz)) { - if(init_missing) { - output_warn.write("\tWARNING: Could not read FieldPerp %s. Setting to zero\n", name.c_str()); - *f = 0.0; - }else { - throw BoutException("Missing FieldPerp %s in input. Set init_missing=true to set to zero.", name.c_str()); + }else { + if(!file->read_perp(&((*f)(0,0)), name, mesh->LocalNx, mesh->LocalNz)) { + if(init_missing) { + output_warn.write("\tWARNING: Could not read FieldPerp %s. Setting to zero\n", name.c_str()); + *f = 0.0; + }else { + throw BoutException("Missing FieldPerp %s in input. Set init_missing=true to set to zero.", name.c_str()); + } + return false; } - return false; } - } - if (shiftInput) { - // Input file is in field-aligned coordinates e.g. BOUT++ 3.x restart file - *f = fromFieldAligned(*f, RGN_ALL); + if (shiftInput) { + // Input file is in field-aligned coordinates e.g. BOUT++ 3.x restart file + *f = fromFieldAligned(*f, RGN_ALL); + } } return true; From d3063dc444a558e8770bcc6703826765af625ba9 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 11:55:25 +0100 Subject: [PATCH 1348/1783] Move readFieldAttributes/writeFieldAttributes to DataFormat Allows readFieldAttributes to be used by both Datafile and GridFromFile. --- include/datafile.hxx | 11 ---- include/dataformat.hxx | 12 +++++ src/fileio/datafile.cxx | 106 ++++++++++++-------------------------- src/fileio/dataformat.cxx | 47 +++++++++++++++++ 4 files changed, 92 insertions(+), 84 deletions(-) diff --git a/include/datafile.hxx b/include/datafile.hxx index 2086f79ee3..7236c35bb9 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -141,17 +141,6 @@ class Datafile { bool write_f3d(const std::string &name, Field3D *f, bool save_repeat); bool write_fperp(const std::string &name, FieldPerp *f, bool save_repeat); - /// Write out the meta-data of a field as attributes of the variable in - /// 'file'. - void writeFieldAttributes(const std::string& name, const Field& f); - /// Overload for FieldPerp so we can also write 'yindex' - void writeFieldAttributes(const std::string& name, const FieldPerp& f); - - /// Read the attributes of a field from 'file' - void readFieldAttributes(const std::string& name, Field& f); - /// Overload for FieldPerp so we can also write 'yindex' - void readFieldAttributes(const std::string& name, FieldPerp& f); - /// Check if a variable has already been added bool varAdded(const std::string &name); diff --git a/include/dataformat.hxx b/include/dataformat.hxx index 908373c443..37f155f80c 100644 --- a/include/dataformat.hxx +++ b/include/dataformat.hxx @@ -41,6 +41,8 @@ class DataFormat; #include class Mesh; +class Field; +class FieldPerp; // Can't copy, to control access to file class DataFormat { @@ -204,6 +206,16 @@ class DataFormat { /// value A BoutReal attribute of the variable virtual bool getAttribute(const std::string &varname, const std::string &attrname, BoutReal &value) = 0; + /// Write out the meta-data of a field as attributes of the variable + void writeFieldAttributes(const std::string& name, const Field& f); + /// Overload for FieldPerp so we can also write 'yindex' + void writeFieldAttributes(const std::string& name, const FieldPerp& f); + + /// Read the attributes of a field + void readFieldAttributes(const std::string& name, Field& f); + /// Overload for FieldPerp so we can also read 'yindex' + void readFieldAttributes(const std::string& name, FieldPerp& f); + protected: Mesh* mesh; }; diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index bd3152fb61..43bd24db61 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -921,53 +921,6 @@ bool Datafile::read() { return true; } -void Datafile::writeFieldAttributes(const std::string& name, const Field& f) { - file->setAttribute(name, "cell_location", toString(f.getLocation())); - file->setAttribute(name, "direction_y", toString(f.getDirectionY())); - file->setAttribute(name, "direction_z", toString(f.getDirectionZ())); -} - -void Datafile::writeFieldAttributes(const std::string& name, const FieldPerp& f) { - writeFieldAttributes(name, static_cast(f)); - - int yindex = f.getIndex(); - if (yindex >= 0 and yindex < f.getMesh()->LocalNy) { - // write global y-index as attribute - file->setAttribute(name, "yindex_global", f.getMesh()->YGLOBAL(f.getIndex())); - } else { - // y-index is not valid, set global y-index to -1 to indicate 'not-valid' - file->setAttribute(name, "yindex_global", -1); - } -} - -void Datafile::readFieldAttributes(const std::string& name, Field& f) { - std::string location_string; - if (file->getAttribute(name, "cell_location", location_string)) { - f.setLocation(CELL_LOCFromString(location_string)); - } - - std::string direction_y_string; - if (file->getAttribute(name, "direction_y", direction_y_string)) { - f.setDirectionY(YDirectionTypeFromString(direction_y_string)); - } - - std::string direction_z_string; - if (file->getAttribute(name, "direction_z", direction_z_string)) { - f.setDirectionZ(ZDirectionTypeFromString(direction_z_string)); - } -} - -void Datafile::readFieldAttributes(const std::string& name, FieldPerp& f) { - readFieldAttributes(name, static_cast(f)); - - int yindex_global = 0; - if (file->getAttribute(name, "yindex_global", yindex_global)) { - f.setIndex(mesh->YLOCAL(yindex_global)); - } else { - f.setIndex(mesh->YLOCAL(0)); - } -} - bool Datafile::write() { if(!enabled) return true; // Just pretend it worked @@ -1005,33 +958,33 @@ bool Datafile::write() { // output is written, since this happens after the first rhs evaluation // 2D fields for (const auto& var : f2d_arr) { - writeFieldAttributes(var.name, *var.ptr); + file->writeFieldAttributes(var.name, *var.ptr); } // 3D fields for (const auto& var : f3d_arr) { - writeFieldAttributes(var.name, *var.ptr); + file->writeFieldAttributes(var.name, *var.ptr); } // FieldPerps for (const auto& var : fperp_arr) { - writeFieldAttributes(var.name, *var.ptr); + file->writeFieldAttributes(var.name, *var.ptr); } // 2D vectors for(const auto& var : v2d_arr) { Vector2D v = *(var.ptr); - writeFieldAttributes(var.name+"_x", v.x); - writeFieldAttributes(var.name+"_y", v.y); - writeFieldAttributes(var.name+"_z", v.z); + file->writeFieldAttributes(var.name+"_x", v.x); + file->writeFieldAttributes(var.name+"_y", v.y); + file->writeFieldAttributes(var.name+"_z", v.z); } // 3D vectors for(const auto& var : v3d_arr) { Vector3D v = *(var.ptr); - writeFieldAttributes(var.name+"_x", v.x); - writeFieldAttributes(var.name+"_y", v.y); - writeFieldAttributes(var.name+"_z", v.z); + file->writeFieldAttributes(var.name+"_x", v.x); + file->writeFieldAttributes(var.name+"_y", v.y); + file->writeFieldAttributes(var.name+"_z", v.z); } } @@ -1224,7 +1177,7 @@ void Datafile::setAttribute(const std::string &varname, const std::string &attrn ///////////////////////////////////////////////////////////// bool Datafile::read_f2d(const std::string &name, Field2D *f, bool save_repeat) { - readFieldAttributes(name, *f); + file->readFieldAttributes(name, *f); f->allocate(); @@ -1254,7 +1207,7 @@ bool Datafile::read_f2d(const std::string &name, Field2D *f, bool save_repeat) { } bool Datafile::read_f3d(const std::string &name, Field3D *f, bool save_repeat) { - readFieldAttributes(name, *f); + file->readFieldAttributes(name, *f); f->allocate(); @@ -1290,7 +1243,7 @@ bool Datafile::read_f3d(const std::string &name, Field3D *f, bool save_repeat) { } bool Datafile::read_fperp(const std::string &name, FieldPerp *f, bool save_repeat) { - readFieldAttributes(name, *f); + file->readFieldAttributes(name, *f); int yindex = f->getIndex(); if (yindex >= 0 and yindex < mesh->LocalNy) { @@ -1382,23 +1335,30 @@ bool Datafile::write_f3d(const std::string &name, Field3D *f, bool save_repeat) } bool Datafile::write_fperp(const std::string &name, FieldPerp *f, bool save_repeat) { - if (!f->isAllocated()) { - throw BoutException("Datafile::write_fperp: FieldPerp '%s' is not allocated!", name.c_str()); - } + int yindex = f->getIndex(); + if (yindex >= 0 and yindex < mesh->LocalNy) { + if (!f->isAllocated()) { + throw BoutException("Datafile::write_fperp: FieldPerp '%s' is not allocated!", name.c_str()); + } - //Deal with shifting the output - FieldPerp f_out{emptyFrom(*f)}; - if(shiftOutput) { - f_out = toFieldAligned(*f); - }else { - f_out = *f; - } + //Deal with shifting the output + FieldPerp f_out{emptyFrom(*f)}; + if(shiftOutput) { + f_out = toFieldAligned(*f); + }else { + f_out = *f; + } - if(save_repeat) { - return file->write_rec_perp(&(f_out(0,0)), name, mesh->LocalNx, mesh->LocalNz); - }else { - return file->write_perp(&(f_out(0,0)), name, mesh->LocalNx, mesh->LocalNz); + if(save_repeat) { + return file->write_rec_perp(&(f_out(0,0)), name, mesh->LocalNx, mesh->LocalNz); + }else { + return file->write_perp(&(f_out(0,0)), name, mesh->LocalNx, mesh->LocalNz); + } } + + // Don't need to write f as it's y-index is not on this processor. Return + // without doing anything. + return true; } bool Datafile::varAdded(const std::string &name) { diff --git a/src/fileio/dataformat.cxx b/src/fileio/dataformat.cxx index cf09ea170b..8aeadb6a52 100644 --- a/src/fileio/dataformat.cxx +++ b/src/fileio/dataformat.cxx @@ -31,3 +31,50 @@ bool DataFormat::setLocalOrigin(int x, int y, int z, int UNUSED(offset_x), int UNUSED(offset_y), int UNUSED(offset_z)) { return setGlobalOrigin(x + mesh->OffsetX, y + mesh->OffsetY, z + mesh->OffsetZ); } + +void DataFormat::writeFieldAttributes(const std::string& name, const Field& f) { + setAttribute(name, "cell_location", toString(f.getLocation())); + setAttribute(name, "direction_y", toString(f.getDirectionY())); + setAttribute(name, "direction_z", toString(f.getDirectionZ())); +} + +void DataFormat::writeFieldAttributes(const std::string& name, const FieldPerp& f) { + writeFieldAttributes(name, static_cast(f)); + + int yindex = f.getIndex(); + if (yindex >= 0 and yindex < f.getMesh()->LocalNy) { + // write global y-index as attribute + setAttribute(name, "yindex_global", f.getMesh()->YGLOBAL(f.getIndex())); + } else { + // y-index is not valid, set global y-index to -1 to indicate 'not-valid' + setAttribute(name, "yindex_global", -1); + } +} + +void DataFormat::readFieldAttributes(const std::string& name, Field& f) { + std::string location_string; + if (getAttribute(name, "cell_location", location_string)) { + f.setLocation(CELL_LOCFromString(location_string)); + } + + std::string direction_y_string; + if (getAttribute(name, "direction_y", direction_y_string)) { + f.setDirectionY(YDirectionTypeFromString(direction_y_string)); + } + + std::string direction_z_string; + if (getAttribute(name, "direction_z", direction_z_string)) { + f.setDirectionZ(ZDirectionTypeFromString(direction_z_string)); + } +} + +void DataFormat::readFieldAttributes(const std::string& name, FieldPerp& f) { + readFieldAttributes(name, static_cast(f)); + + int yindex_global = 0; + if (getAttribute(name, "yindex_global", yindex_global)) { + f.setIndex(mesh->YLOCAL(yindex_global)); + } else { + f.setIndex(mesh->YLOCAL(0)); + } +} From 21dac46038eea1f3a90ec971142b68082890400c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 12:51:59 +0100 Subject: [PATCH 1349/1783] Don't use DataFormat::mesh when it might be nullptr The DataFormat which is a member of GridFromFile has a null 'mesh' member, because it is created before the Mesh is. Therefore get the Mesh* pointer from the field in readFieldAttributes, and add a check for nullptr in setLocalOrigin, which should not be called for a grid-file DataFormat. --- src/fileio/dataformat.cxx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/fileio/dataformat.cxx b/src/fileio/dataformat.cxx index 8aeadb6a52..7e7406f598 100644 --- a/src/fileio/dataformat.cxx +++ b/src/fileio/dataformat.cxx @@ -29,6 +29,9 @@ bool DataFormat::openw(const std::string &name, int mype, bool append) { bool DataFormat::setLocalOrigin(int x, int y, int z, int UNUSED(offset_x), int UNUSED(offset_y), int UNUSED(offset_z)) { + // This function should not be called from the DataFormat in GridFromFile, which is + // created before the Mesh - then DataFormat::mesh would be nullptr. + ASSERT1(mesh != nullptr); return setGlobalOrigin(x + mesh->OffsetX, y + mesh->OffsetY, z + mesh->OffsetZ); } @@ -72,9 +75,11 @@ void DataFormat::readFieldAttributes(const std::string& name, FieldPerp& f) { readFieldAttributes(name, static_cast(f)); int yindex_global = 0; + // Note: don't use DataFormat::mesh variable, because it may be null if the DataFormat + // is part of a GridFromFile, which is created before the Mesh. if (getAttribute(name, "yindex_global", yindex_global)) { - f.setIndex(mesh->YLOCAL(yindex_global)); + f.setIndex(f.getMesh()->YLOCAL(yindex_global)); } else { - f.setIndex(mesh->YLOCAL(0)); + f.setIndex(f.getMesh()->YLOCAL(0)); } } From 23173aba65d421cdd16ddbf85872355c1c1ad02b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 28 Apr 2019 17:09:01 +0100 Subject: [PATCH 1350/1783] Implement FieldPerp capability in FieldFactory --- include/field_factory.hxx | 11 +++++ src/field/field_factory.cxx | 80 +++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/include/field_factory.hxx b/include/field_factory.hxx index c24a996bba..1346fa4c2c 100644 --- a/include/field_factory.hxx +++ b/include/field_factory.hxx @@ -68,6 +68,12 @@ public: Field3D create3D(const std::string& value, const Options* opt = nullptr, Mesh* m = nullptr, CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0) const; + /// Create a FieldPerp by parsing a string and evaluating the expression + /// using the given options \p opt, over Mesh \p m at time \p t. + /// The resulting field is at cell location \p loc. + FieldPerp createPerp(const std::string& value, const Options* opt = nullptr, + Mesh* m = nullptr, CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0) const; + /// Parse a string into a tree of generators FieldGeneratorPtr parse(const std::string& input, const Options* opt = nullptr) const; @@ -81,6 +87,11 @@ public: Field3D create3D(FieldGeneratorPtr generator, Mesh* m = nullptr, CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0) const; + /// Create a FieldPerp from a generator, over a given mesh + /// at a given cell location and time. + FieldPerp createPerp(FieldGeneratorPtr generator, Mesh* m = nullptr, + CELL_LOC loc = CELL_CENTRE, BoutReal t = 0.0) const; + /// Get the Singleton object static FieldFactory* get(); diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 9118be76b9..e74518e8ce 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -237,6 +237,86 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC return result; } +FieldPerp FieldFactory::createPerp(const std::string& value, const Options* opt, + Mesh* localmesh, CELL_LOC loc, BoutReal t) const { + return createPerp(parse(value, opt), localmesh, loc, t); +} + +FieldPerp FieldFactory::createPerp(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC loc, + BoutReal t) const { + AUTO_TRACE(); + + if (localmesh == nullptr) { + if (fieldmesh == nullptr) { + throw BoutException("FieldFactory not created with mesh and no mesh passed in"); + } + localmesh = fieldmesh; + } + + if (!gen) { + throw BoutException("Couldn't create FieldPerp from null generator"); + } + + FieldPerp result(localmesh); + result.allocate(); + result.setLocation(loc); + + switch (loc) { + case CELL_XLOW: { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { + BoutReal xpos = 0.5 * (localmesh->GlobalX(i.x() - 1) + localmesh->GlobalX(i.x())); + result[i] = gen->generate(xpos, 0., + TWOPI * static_cast(i.z()) + / static_cast(localmesh->LocalNz), + t); + } + break; + } + case CELL_YLOW: { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { + result[i] = gen->generate(localmesh->GlobalX(i.x()), 0., + TWOPI * static_cast(i.z()) + / static_cast(localmesh->LocalNz), + t); + } + break; + } + case CELL_ZLOW: { + BOUT_FOR(i, result.getRegion("RGN_ALL")) { + result[i] = + gen->generate(localmesh->GlobalX(i.x()), 0., + TWOPI * (static_cast(i.z()) - 0.5) + / static_cast(localmesh->LocalNz), + t); + } + break; + } + default: { // CELL_CENTRE + BOUT_FOR(i, result.getRegion("RGN_ALL")) { + result[i] = + gen->generate(localmesh->GlobalX(i.x()), 0., + TWOPI * static_cast(i.z()) + / static_cast(localmesh->LocalNz), + t); + } + } + }; + + if (transform_from_field_aligned) { + auto coords = result.getCoordinates(); + if (coords == nullptr) { + throw BoutException("Unable to transform result: Mesh does not have Coordinates set"); + } + if (coords->getParallelTransform().canToFromFieldAligned()) { + // Transform from field aligned coordinates, to be compatible with + // older BOUT++ inputs. This is not a particularly "nice" solution. + result = fromFieldAligned(result, RGN_ALL); + } + } + + return result; +} + const Options* FieldFactory::findOption(const Options* opt, const std::string& name, std::string& val) const { const Options* result = opt; From 721e5698f56ee99ee3e0a7fa5b325e844be006a1 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 28 Apr 2019 16:37:50 +0100 Subject: [PATCH 1351/1783] Add FieldPerp version of Mesh::get() Set y-index of FieldPerp to 0 when reading from grid files Not totally correct, probably should set from an attribute in the file, but need to set something otherwise checkData() fails. --- include/bout/griddata.hxx | 28 ++++- include/bout/mesh.hxx | 10 ++ src/mesh/data/gridfromfile.cxx | 194 +++++++++++++++++++++++++++--- src/mesh/data/gridfromoptions.cxx | 20 +++ src/mesh/mesh.cxx | 19 +++ tests/unit/mesh/test_boutmesh.cxx | 4 + 6 files changed, 256 insertions(+), 19 deletions(-) diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index f88a15ac21..c764bc58d9 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -58,6 +58,7 @@ public: const std::string &name) = 0; ///< Get a BoutReal number virtual bool get(Mesh *m, Field2D &var, const std::string &name, BoutReal def = 0.0) = 0; virtual bool get(Mesh *m, Field3D &var, const std::string &name, BoutReal def = 0.0) = 0; + virtual bool get(Mesh *m, FieldPerp &var, const std::string &name, BoutReal def = 0.0) = 0; enum Direction { X = 1, Y = 2, Z = 3 }; virtual bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, @@ -91,6 +92,9 @@ public: const std::string &name) override; ///< Get a BoutReal number bool get(Mesh *m, Field2D &var, const std::string &name, BoutReal def = 0.0) override; bool get(Mesh *m, Field3D &var, const std::string &name, BoutReal def = 0.0) override; + bool get(Mesh *m, FieldPerp &var, const std::string &name, BoutReal def = 0.0) override { + return getField(m, var, name, def); + } bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, GridDataSource::Direction dir = GridDataSource::X) override; @@ -115,8 +119,14 @@ private: bool readgrid_3dvar_real(const std::string &name, int yread, int ydest, int ysize, int xread, int xdest, int xsize, Field3D &var); - // convenience template method to remove code duplication between Field2D and - // Field3D versions of get + bool readgrid_perpvar_fft(Mesh *m, const std::string &name, int xread, int xdest, + int xsize, FieldPerp &var); + + bool readgrid_perpvar_real(const std::string &name, int xread, int xdest, int xsize, + FieldPerp &var); + + // convenience template method to remove code duplication between Field2D, + // Field3D and FieldPerp versions of get template bool getField(Mesh* m, T& var, const std::string& name, BoutReal def = 0.0); // utility method for Field2D to implement unshared parts of getField @@ -125,6 +135,9 @@ private: // utility method for Field3D to implement unshared parts of getField void readField(Mesh* m, const std::string& name, int ys, int yd, int ny_to_read, int xs, int xd, int nx_to_read, const std::vector& size, Field3D& var); + // utility method for FieldPerp to implement unshared parts of getField + void readField(Mesh* m, const std::string& name, int ys, int yd, int ny_to_read, + int xs, int xd, int nx_to_read, const std::vector& size, FieldPerp& var); }; /*! @@ -205,6 +218,17 @@ public: */ bool get(Mesh *mesh, Field3D &var, const std::string &name, BoutReal def = 0.0) override; + /*! + * Get a FieldPerp object by finding the option with the given name, + * and passing the string to FieldFactory + * + * @param[in] mesh The Mesh object over which the field is defined + * @param[out] var The variable which will be set + * @param[in] name The name in the options. Not case sensitive + * @param[in] def Default value to use if option not found + */ + bool get(Mesh *mesh, FieldPerp &var, const std::string &name, BoutReal def = 0.0) override; + /*! * Get an array of integers. Currently reads a single * integer, and sets the whole array to the same value diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index ec0c7630d9..d17745ea06 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -166,6 +166,16 @@ class Mesh { /// @returns zero if successful, non-zero on failure int get(Field3D &var, const std::string &name, BoutReal def=0.0, bool communicate=true); + /// Get a FieldPerp from the input source + /// + /// @param[out] var This will be set to the value. Will be allocated if needed + /// @param[in] name Name of the variable to read + /// @param[in] def The default value if not found + /// @param[in] communicate Should the field be communicated to fill guard cells? + /// + /// @returns zero if successful, non-zero on failure + int get(FieldPerp &var, const std::string &name, BoutReal def=0.0, bool communicate=true); + /// Get a Vector2D from the input source. /// If \p var is covariant then this gets three /// Field2D variables with "_x", "_y", "_z" appended to \p name diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 0282377f80..7c6f841db9 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -171,9 +171,9 @@ bool GridFile::get(Mesh *UNUSED(m), BoutReal &rval, const std::string &name) { } /*! - * Reads a 2D or 3D field variable from a file + * Reads a 2D, 3D or FieldPerp field variable from a file * - * Successfully reads Field2D if the variable in the file is 0-D or 2-D. + * Successfully reads Field2D or FieldPerp if the variable in the file is 0-D or 2-D. * Successfully reads Field3D if the variable in the file is 0-D, 2-D or 3-D. */ bool GridFile::get(Mesh *m, Field2D &var, const std::string &name, BoutReal def) { @@ -185,11 +185,12 @@ bool GridFile::get(Mesh *m, Field3D &var, const std::string &name, BoutReal def) template bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) { - static_assert(std::is_base_of::value || std::is_base_of::value, - "templated GridFile::get only works for Field2D or Field3D"); + static_assert(std::is_base_of::value or std::is_base_of::value + or std::is_base_of::value, + "templated GridFile::get only works for Field2D, Field3D or FieldPerp"); Timer timer("io"); - TRACE("GridFile::get(Field2D)"); + AUTO_TRACE(); if (!file->is_valid()) { throw BoutException("Could not read '%s' from file: File cannot be read", name.c_str()); @@ -221,7 +222,7 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) } case 3: { // Check size if getting Field3D - if (std::is_base_of::value) { + if (std::is_base_of::value or std::is_base_of::value) { output_warn.write("WARNING: Variable '%s' should be 2D, but has %zu dimensions. Ignored\n", name.c_str(), size.size()); var = def; @@ -337,18 +338,20 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) } } - ///If field does not include ghost points in y-direction -> - ///Upper and lower Y boundaries copied from nearest point - if (grid_yguards == 0) { - for(int x=0; xLocalNx; x++) { - for(int y=0; yystart; y++) { - for (int z=0; zystart, z); + if (not std::is_base_of::value) { + ///If field does not include ghost points in y-direction -> + ///Upper and lower Y boundaries copied from nearest point + if (grid_yguards == 0) { + for(int x=0; xLocalNx; x++) { + for(int y=0; yystart; y++) { + for (int z=0; zystart, z); + } } - } - for(int y=m->yend+1; yLocalNy; y++) { - for (int z=0; zyend, z); + for(int y=m->yend+1; yLocalNy; y++) { + for (int z=0; zyend, z); + } } } } @@ -409,6 +412,42 @@ void GridFile::readField(Mesh* m, const std::string& name, int ys, int yd, } } +void GridFile::readField(Mesh* m, const std::string& name, int UNUSED(ys), int UNUSED(yd), + int UNUSED(ny_to_read), int xs, int xd, int nx_to_read, const std::vector& size, + FieldPerp& var) { + + // Check whether "nz" is defined + if (hasVar("nz")) { + // Check the array is the right size + if (size[2] != m->LocalNz) { + throw BoutException("FieldPerp variable '%s' has incorrect size %d (expecting %d)", + name.c_str(), size[2], m->LocalNz); + } + + if (!readgrid_perpvar_real(name, + xs,// Start reading at global x-index + xd,// Insert data starting from x=xd + nx_to_read, // Length of data in X + var) ) { + throw BoutException("\tWARNING: Could not read '%s' from grid. Setting to zero\n", + name.c_str()); + } + } else { + // No Z size specified in file. Assume FFT format + if (!readgrid_perpvar_fft(m, name, + xs,// Start reading at global x-index + xd,// Insert data starting from x=xd + nx_to_read, // Length of data in X + var) ) { + throw BoutException("\tWARNING: Could not read '%s' from grid. Setting to zero\n", + name.c_str()); + } + } + + // Should really try to read this from attributes in the file + var.setIndex(0); +} + bool GridFile::get(Mesh *UNUSED(m), std::vector &var, const std::string &name, int len, int offset, GridDataSource::Direction UNUSED(dir)) { TRACE("GridFile::get(vector)"); @@ -596,3 +635,124 @@ bool GridFile::readgrid_3dvar_real(const std::string &name, return true; } +/* + Data stored as toroidal FFTs in BoutReal space at each X point. + In toroidal direction, array must have an odd number of points. + Format is: + + DC, r1,i1, r2,i2, ... , rn,in + + with the BoutReal and imaginary parts of each (positive) frequency + up to the nyquist frequency. + */ +bool GridFile::readgrid_perpvar_fft(Mesh *m, const std::string &name, + int xread, int xdest, int xsize, FieldPerp &var) { + /// Check the arguments make sense + if ((xread < 0) || (xdest < 0) || (xsize < 0)) { + return false; + } + + /// Check the size of the data + std::vector size = file->getSize(name); + + if (size.size() != 2) { + output_warn.write("\tWARNING: Number of dimensions of %s incorrect\n", name.c_str()); + return false; + } + + int maxmode = (size[1] - 1)/2; ///< Maximum mode-number n + + int ncz = m->LocalNz; + + /// we should be able to replace the following with + /// var.getCoordinates()->zlength(); + /// but don't do it yet as we don't assert that m == var.getMesh() + /// Expect the assertion to be true, in which case we probably don't + /// need to pass m as can just use var.getMesh() + BoutReal zlength = m->getCoordinates(var.getLocation())->zlength(); + + int zperiod = ROUND(TWOPI / zlength); /// Number of periods in 2pi + + // Print out which modes are going to be read in + if (zperiod > maxmode) { + // Domain is too small: Only DC + output_warn.write("zperiod (%d) > maxmode (%d) => Only reading n = 0 component\n", zperiod, maxmode); + } else { + // Get maximum mode in the input which is a multiple of zperiod + int mm = (maxmode / zperiod) * zperiod; + if ( (ncz/2)*zperiod < mm ) + mm = (ncz/2)*zperiod; // Limited by Z resolution + + if (mm == zperiod) { + output_info.write(" => Reading n = 0, %d\n", zperiod); + } else { + output_info.write(" => Reading n = 0, %d ... %d\n", zperiod, mm); + } + } + + /// Data for FFT. Only positive frequencies + Array fdata(ncz / 2 + 1); + Array zdata(size[1]); + + for (int jx = xread; jx < xread+xsize; jx++) { + // jx is global x-index to start from + + file->setGlobalOrigin(jx, 0); + if (!file->read_perp(std::begin(zdata), name, 1, size[1])) { + return false; + } + + /// Load into dcomplex array + + fdata[0] = zdata[0]; // DC component + + for(int i=1;i<=ncz/2;i++) { + int modenr = i*zperiod; // Z mode number + + if (modenr <= maxmode) { + // Have data for this mode + fdata[i] = dcomplex(zdata[modenr*2 - 1], zdata[modenr*2]); + } else { + fdata[i] = 0.0; + } + } + irfft(std::begin(fdata), ncz, &var(jx-xread+xdest, 0)); + } + + file->setGlobalOrigin(); + + return true; +} + +/*! + * Reads a FieldPerp variable directly from the file, without + * any processing + */ +bool GridFile::readgrid_perpvar_real(const std::string &name, + int xread, int xdest, int xsize, FieldPerp &var) { + /// Check the arguments make sense + if ((xread < 0) || (xdest < 0) || (xsize < 0)) { + return false; + } + + /// Check the size of the data + std::vector size = file->getSize(name); + + if (size.size() != 2) { + output_warn.write("\tWARNING: Number of dimensions of %s incorrect\n", name.c_str()); + return false; + } + + for (int jx = xread; jx < xread+xsize; jx++) { + // jx is global x-index to start from + + file->setGlobalOrigin(jx, 0); + if (!file->read_perp(&var(jx-xread+xdest, 0), name, 1, size[1])) { + return false; + } + } + file->setGlobalOrigin(); + + return true; +} + diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index 3cd8f88fc3..49e09a0223 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -71,6 +71,26 @@ bool GridFromOptions::get(Mesh* m, Field3D& var, const std::string& name, BoutRe return true; } +bool GridFromOptions::get(Mesh* m, FieldPerp& var, const std::string& name, BoutReal def) { + // Cannot set attributes from options at the moment, so don't know what 'yindex' this + // FieldPerp should have: just set to 0 for now, and create FieldPerp on all processors + // (note: this is different to behaviour of GridFromFile which will only create the + // FieldPerp at a single global y-index). + + if (!hasVar(name)) { + output_warn.write("Variable '%s' not in mesh options. Setting to %e\n", name.c_str(), + def); + var = def; + var.setIndex(0); + return false; + } + + var = FieldFactory::get()->createPerp(name, options, m); + var.setIndex(0); + + return true; +} + bool GridFromOptions::get(Mesh* m, std::vector& var, const std::string& name, int len, int UNUSED(offset), GridDataSource::Direction UNUSED(dir)) { diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 514a42a2a6..887204778c 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -115,6 +115,25 @@ int Mesh::get(Field3D &var, const std::string &name, BoutReal def, bool communic return 0; } +int Mesh::get(FieldPerp &var, const std::string &name, BoutReal def, + bool UNUSED(communicate)) { + TRACE("Loading FieldPerp: Mesh::get(FieldPerp, %s)", name.c_str()); + + // Ensure data allocated + var.allocate(); + + if (source == nullptr or !source->get(this, var, name, def)) + return 1; + + // Communicate to get guard cell data + Mesh::communicate(var); + + // Check that the data is valid + checkData(var); + + return 0; +} + /************************************************************************** * Data get routines **************************************************************************/ diff --git a/tests/unit/mesh/test_boutmesh.cxx b/tests/unit/mesh/test_boutmesh.cxx index 885fbcb901..4ef211dc73 100644 --- a/tests/unit/mesh/test_boutmesh.cxx +++ b/tests/unit/mesh/test_boutmesh.cxx @@ -27,6 +27,10 @@ class FakeGridDataSource : public GridDataSource { BoutReal UNUSED(def) = 0.0) { return true; } + bool get(Mesh *UNUSED(m), FieldPerp &UNUSED(var), const std::string &UNUSED(name), + BoutReal UNUSED(def) = 0.0) { + return true; + } bool get(Mesh *UNUSED(m), std::vector &UNUSED(var), const std::string &UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, Direction UNUSED(dir) = GridDataSource::X) { From ec9ac8d9a987c42904fd8641b09202fda3a1971e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 11:57:47 +0100 Subject: [PATCH 1352/1783] Read attributes when getting Fields from grid-file --- src/mesh/data/gridfromfile.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 7c6f841db9..f16619a787 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -363,6 +363,7 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) void GridFile::readField(Mesh* UNUSED(m), const std::string& name, int ys, int yd, int ny_to_read, int xs, int xd, int nx_to_read, const std::vector& UNUSED(size), Field2D& var) { + file->readFieldAttributes(name, var); for(int x = xs; x < xs+nx_to_read; x++) { file->setGlobalOrigin(x,ys,0); @@ -376,6 +377,7 @@ void GridFile::readField(Mesh* UNUSED(m), const std::string& name, int ys, int y void GridFile::readField(Mesh* m, const std::string& name, int ys, int yd, int ny_to_read, int xs, int xd, int nx_to_read, const std::vector& size, Field3D& var) { + file->readFieldAttributes(name, var); // Check whether "nz" is defined if (hasVar("nz")) { @@ -416,6 +418,8 @@ void GridFile::readField(Mesh* m, const std::string& name, int UNUSED(ys), int U int UNUSED(ny_to_read), int xs, int xd, int nx_to_read, const std::vector& size, FieldPerp& var) { + file->readFieldAttributes(name, var); + // Check whether "nz" is defined if (hasVar("nz")) { // Check the array is the right size @@ -443,9 +447,6 @@ void GridFile::readField(Mesh* m, const std::string& name, int UNUSED(ys), int U name.c_str()); } } - - // Should really try to read this from attributes in the file - var.setIndex(0); } bool GridFile::get(Mesh *UNUSED(m), std::vector &var, const std::string &name, From e5a647f0522a18424a0b038f477bd54e9721a481 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 12:27:34 +0100 Subject: [PATCH 1353/1783] GridFromFile: only allocate FieldPerp when actually reading Check that yindex is on the processor before reading, only allocate if we are actually reading. --- src/mesh/data/gridfromfile.cxx | 116 ++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 51 deletions(-) diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index f16619a787..dc881e53ac 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -238,8 +238,6 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) } }; - var.allocate(); // Make sure data allocated - ///Ghost region widths. const int mxg = (m->LocalNx - (m->xend - m->xstart + 1)) / 2; const int myg = (m->LocalNy - (m->yend - m->ystart + 1)) / 2; @@ -319,38 +317,42 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) // Now read data from file readField(m, name, ys, yd, ny_to_read, xs, xd, nx_to_read, size, var); - ///If field does not include ghost points in x-direction -> - ///Upper and lower X boundaries copied from nearest point - if (field_dimensions[0] == m->GlobalNx - 2*mxg ) { - for (int x=0; xxstart; x++) { - for (int y=0; yLocalNy; y++) { - for (int z=0; zxstart, y, z); + if (var.isAllocated()) { + // FieldPerps might not be allocated if they are not read on this processor + + ///If field does not include ghost points in x-direction -> + ///Upper and lower X boundaries copied from nearest point + if (field_dimensions[0] == m->GlobalNx - 2*mxg ) { + for (int x=0; xxstart; x++) { + for (int y=0; yLocalNy; y++) { + for (int z=0; zxstart, y, z); + } } } - } - for (int x=m->xend+1;xLocalNx;x++) { - for (int y=0; yLocalNy; y++) { - for (int z=0; zxend, y, z); + for (int x=m->xend+1;xLocalNx;x++) { + for (int y=0; yLocalNy; y++) { + for (int z=0; zxend, y, z); + } } } } - } - if (not std::is_base_of::value) { - ///If field does not include ghost points in y-direction -> - ///Upper and lower Y boundaries copied from nearest point - if (grid_yguards == 0) { - for(int x=0; xLocalNx; x++) { - for(int y=0; yystart; y++) { - for (int z=0; zystart, z); + if (not std::is_base_of::value) { + ///If field does not include ghost points in y-direction -> + ///Upper and lower Y boundaries copied from nearest point + if (grid_yguards == 0) { + for(int x=0; xLocalNx; x++) { + for(int y=0; yystart; y++) { + for (int z=0; zystart, z); + } } - } - for(int y=m->yend+1; yLocalNy; y++) { - for (int z=0; zyend, z); + for(int y=m->yend+1; yLocalNy; y++) { + for (int z=0; zyend, z); + } } } } @@ -365,6 +367,8 @@ void GridFile::readField(Mesh* UNUSED(m), const std::string& name, int ys, int y Field2D& var) { file->readFieldAttributes(name, var); + var.allocate(); + for(int x = xs; x < xs+nx_to_read; x++) { file->setGlobalOrigin(x,ys,0); if (!file->read(&var(x-xs+xd, yd), name, 1, ny_to_read) ) { @@ -379,6 +383,8 @@ void GridFile::readField(Mesh* m, const std::string& name, int ys, int yd, Field3D& var) { file->readFieldAttributes(name, var); + var.allocate(); + // Check whether "nz" is defined if (hasVar("nz")) { // Check the array is the right size @@ -420,31 +426,39 @@ void GridFile::readField(Mesh* m, const std::string& name, int UNUSED(ys), int U file->readFieldAttributes(name, var); - // Check whether "nz" is defined - if (hasVar("nz")) { - // Check the array is the right size - if (size[2] != m->LocalNz) { - throw BoutException("FieldPerp variable '%s' has incorrect size %d (expecting %d)", - name.c_str(), size[2], m->LocalNz); - } + int yindex = var.getIndex(); - if (!readgrid_perpvar_real(name, - xs,// Start reading at global x-index - xd,// Insert data starting from x=xd - nx_to_read, // Length of data in X - var) ) { - throw BoutException("\tWARNING: Could not read '%s' from grid. Setting to zero\n", - name.c_str()); - } - } else { - // No Z size specified in file. Assume FFT format - if (!readgrid_perpvar_fft(m, name, - xs,// Start reading at global x-index - xd,// Insert data starting from x=xd - nx_to_read, // Length of data in X - var) ) { - throw BoutException("\tWARNING: Could not read '%s' from grid. Setting to zero\n", - name.c_str()); + if (yindex >= 0 and yindex <= m->LocalNy) { + // Only read if yindex is on this processor + + var.allocate(); + + // Check whether "nz" is defined + if (hasVar("nz")) { + // Check the array is the right size + if (size[2] != m->LocalNz) { + throw BoutException("FieldPerp variable '%s' has incorrect size %d (expecting %d)", + name.c_str(), size[2], m->LocalNz); + } + + if (!readgrid_perpvar_real(name, + xs,// Start reading at global x-index + xd,// Insert data starting from x=xd + nx_to_read, // Length of data in X + var) ) { + throw BoutException("\tWARNING: Could not read '%s' from grid. Setting to zero\n", + name.c_str()); + } + } else { + // No Z size specified in file. Assume FFT format + if (!readgrid_perpvar_fft(m, name, + xs,// Start reading at global x-index + xd,// Insert data starting from x=xd + nx_to_read, // Length of data in X + var) ) { + throw BoutException("\tWARNING: Could not read '%s' from grid. Setting to zero\n", + name.c_str()); + } } } } From c69c8cb1d0a62de0cf0ad4ba86feec7f18d05174 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 13:14:21 +0100 Subject: [PATCH 1354/1783] Don't allocate in Mesh::get Not necessary as var.allocate() is called in GridFromFile::get when necessary, and we don't always want to allocate a FieldPerp. --- src/mesh/mesh.cxx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 887204778c..46aee3d7fa 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -80,9 +80,6 @@ int Mesh::get(BoutReal &rval, const std::string &name) { int Mesh::get(Field2D &var, const std::string &name, BoutReal def) { TRACE("Loading 2D field: Mesh::get(Field2D, %s)", name.c_str()); - // Ensure data allocated - var.allocate(); - if (source == nullptr or !source->get(this, var, name, def)) return 1; @@ -98,9 +95,6 @@ int Mesh::get(Field2D &var, const std::string &name, BoutReal def) { int Mesh::get(Field3D &var, const std::string &name, BoutReal def, bool communicate) { TRACE("Loading 3D field: Mesh::get(Field3D, %s)", name.c_str()); - // Ensure data allocated - var.allocate(); - if (source == nullptr or !source->get(this, var, name, def)) return 1; @@ -119,9 +113,6 @@ int Mesh::get(FieldPerp &var, const std::string &name, BoutReal def, bool UNUSED(communicate)) { TRACE("Loading FieldPerp: Mesh::get(FieldPerp, %s)", name.c_str()); - // Ensure data allocated - var.allocate(); - if (source == nullptr or !source->get(this, var, name, def)) return 1; From b44d79272c3833878f4a740e01a7116f07f0e496 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 13:15:19 +0100 Subject: [PATCH 1355/1783] Loading FieldPerp from grid, only communicate and checkData if valid Don't necessarily load FieldPerps on every processor, so they may not be valid fields, and it is OK if they are invalid. Only call communicate and checkData if the FieldPerp has 0<=yindexget(this, var, name, def)) return 1; - // Communicate to get guard cell data - Mesh::communicate(var); + int yindex = var.getIndex(); + if (yindex >= 0 and yindex < var.getMesh()->LocalNy) { + // Communicate to get guard cell data + Mesh::communicate(var); - // Check that the data is valid - checkData(var); + // Check that the data is valid + checkData(var); + } return 0; } From 7b5576662bb651960238ee833045f1bc3c475f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Tue, 30 Apr 2019 09:15:34 +0100 Subject: [PATCH 1356/1783] Add new header --- bin/bout_4to5_header_file_list | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/bout_4to5_header_file_list b/bin/bout_4to5_header_file_list index 211cc1b177..476d88a2f1 100644 --- a/bin/bout_4to5_header_file_list +++ b/bin/bout_4to5_header_file_list @@ -31,6 +31,7 @@ mask.hxx msg_stack.hxx multiostream.hxx options.hxx +options_netcdf.hxx optionsreader.hxx output.hxx parallel_boundary_op.hxx From 5e7d038f8a77703d4b2925b817269a717e1f04cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Tue, 30 Apr 2019 09:17:37 +0100 Subject: [PATCH 1357/1783] More usefull error message --- .travis_script.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.travis_script.sh b/.travis_script.sh index 628b1549ad..032e250b71 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -53,7 +53,14 @@ done if test $UPDATE_SCRIPT -gt 0 then # Make sure the header list is up to date - diff <(cd include/;ls *xx|grep -v ^bout.hxx|sort) bin/bout_4to5_header_file_list + if ! diff bin/bout_4to5_header_file_list <(cd include/;ls *xx|grep -v ^bout.hxx|sort) + then + echo "Some header files changed." + echo "Please update the list by running:" + echo "(cd include/;ls *xx|grep -v ^bout.hxx|sort) > bin/bout_4to5_header_file_list" + echo "And commit the updated file." + exit 1 + fi bin/bout_4to5 -f fi From 32a2af32e5b63b328f42f49dda433ca426676b65 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 28 Apr 2019 17:44:18 +0100 Subject: [PATCH 1358/1783] Add FieldPerp support to collect.py Note: read FieldPerp only from files with yindex_global>=0 - A negative yindex_global indicates an invalid FieldPerp in that file. There should be only one pe_yind where the FieldPerp was written, which will have yindex_global>=0, and these should be the only ones read. Previously attributes were always loaded from processor 0, but this is wrong for FieldPerps that are not not valid on that processor. For FieldPerps, check the yindex_global, and get attributes from the first processor where it is valid (i.e. part of the grid, including guard cells, on that processor). Also check that every processor where it is valid has the same y-processor-index. --- .../test-io/data/benchmark.out.0.nc | Bin 47224 -> 132190 bytes tools/pylib/boutdata/collect.py | 137 +++++++++++++----- tools/pylib/boututils/datafile.py | 2 + 3 files changed, 100 insertions(+), 39 deletions(-) diff --git a/tests/integrated/test-io/data/benchmark.out.0.nc b/tests/integrated/test-io/data/benchmark.out.0.nc index ec41997e6ae5134e3517553708d5b6c5d25f349a..5a4906d1fdaff7c1ef04a19d535f7551c76ca75c 100644 GIT binary patch literal 132190 zcmeHQ2S63a)4vCgBBG)oARvMj8&U)nc{fJ~6;z611rsow6MRdh^rDDKkM zrsR|!{}ccDC|QzqlmDhx4XZZ?sc`g{C)MdBHP0H!jEPRgwS6Mb<`*s zN6`)8{>rGTls5Zch@V@h=%K^O!~P)6F6(Kwb%Lz}y!rl!Ux)MMMhm};FO zB=-~0&o8pc-wK5bscXZfkWrdEa&8@50s`1LhZxteeAaB}?&Is>7vR&;FC@UtrGp2h z8_M02Q5t+IKNnvQmWfZrupv$rI51+k1^a&=3l?WLcTbD3i0}GGa?o4!9T8&@IW*?e zt=K-%5q2GZzUbc2@PL1~b-a){L1*i~CSnP24Z*kJD!Dh?0A+A5eMcE5CZmm*A zifb2&+NaL_rKm_Dpag2-Tp`*}Y%R6{shT3k--CO1(f*EZ-tBQoixxv6cZG(KhjW3f zex0%}kjvw1w4Wn2DrubjpIeW6kGKnmU)p-O^)V(||4HkO5|J$2dLI&nI%r~XXIoEf zX5mJmzbz)-4fhNP@Sx(vu1i*lqF!-H2W~%|t7*V7%fwET{S|MEp<(I!<9rr;rB<_O zNxe%7Y4Fdj#+8w~@VoQbR#O-HCT*@eq14sXa6+!yT>WsfRnE^6bKvmHx+mcUXraYD zR{GLCn^akCjwl*lODDEN2RlQVZXAm?xYcDbcST9z7#{hzSNmG6 zWBw#ImT z!3rOq!C`uPaeT#^f|M?dJ)iO!E@ps7P$|Erh_aN9)fG&~`QSJXad|{tD8KxeE*NzF zUY^QDJQtfMr1@8o@Z<7SmC*5Xs}(^P;m$87&IfBJ(&zHCdNwa9oma04&~ZNee5(K* zmj_S3rTG|2%8B#g^bhWm^7HEAKhQa~jJq&D&WBf^3ea(ROnL54{FrVgq2qjNOX!&2 zya+n43$yp6<*_J&UsU|^`EmYrCH%NN^(1u6U%v>tI62PGALrAs2>wPz(5)nNoKIs3 z9hav`5%i`KI?kt=gpTuRUIg7*LdW^EkkD~HHbu~FC3Kt*XDs6`+>SUOdx88ndP@l% z=i?xu<9r+?bj;sMLdRx{))G3-r%e%bCkY+rgAKsAUbw%-MlC5_A;|~x(?!rhLdWG~ zBy^mQi-eB(T_tpkkDG*!^T9JGY56@Q{5XG42_5I-C81+}ZwVcj$45fP`Lrv7-d;k- z`FD`eaX!8hI_CG2&~bS>O6WMBPDRi=OXxU%e+eDu6Cj~ues+e;Ul@N}o*)Sw=hH<( z$N6-X&~ZM&5;~UWZW21qzk3n%9uhi!Zchmv=hI6<$Naq|bX?952_5GXDxu?i`bg+F zpS}`0u5UjH9p@ib1iin6j-NX~LdW@pOX!$?poEUg86lzLd2+K@F0Ev2x0<3HK?xfotbaa&wbpIp z6xTp+ch*CO<*Urz3$yYQ{Rd} zv0OOB#gtQ>s5r`kjS6MjDNYlxwE~9+|MU!V4ea1aX{e7~sYz{Q^D(5xCiK^$(%G~I z)a<$2bSWd2T9ayT4Am$zHakOV+NPfkC^xp|M$~~SKE~7$mTE+~2R=8YIht+l#^*QIFVsjj3Fl@r|e!Ja13c?M74%%V0#UiC)u$;wE-= zsO=A(n^ByN#(=s?U9zUs_%aOm;f*78j?ZD#w1%xH7e3#HyJK5ZHTkD0X53?c@+Awc zZOl;9SY9(KZD>_jYBEpFUizCmmBf~}CiQW^NiS+KPpuSp*oQj8{xqcQt3UIhda;?A zP_<2B+fjCWjZain>rD;klhqzoeI7Joao@FoGp+s`}&BNAcwj* zDl`%{IaA(zn_){c)thfOY+x3f5!;nTVW^I?TEa79D>Ai(jT-U(Y&?S?>DXpWUFYv& zQ?V$6*g`D60N5~0x$#1U?ZKjq894WSf*)N*p{KXID~0_kxiZvgR21zU@W1p187Be!^=V|3$+0j=$3z*cbP1P+Z*V}6YjQm?tsD!O zhHp2PepEE;%H&wmG<>_W^b2AKDU)N7Q}+$_x+xlUWpXTe>b~8)o>=3&u>h+3cK3QC z8gylHEQe~5ahkT66-%R9Nkfe+9*2%ZIiNOB;(W6%>nUUBg348;kB0 z6pJ4^*PUM4SoE%-Sj2B$npE0Y^sS&+cwV|(>ixxl3W~)lPutO@Ef<3-C>FQQheek* z7LgSci}U+!w-$kgu>GwBn-@~0m@LFIpz;~Ewcgk6pEnB0*oo$IZr+`HG*GMX^qsXa z)NHpsPbSAk33+#4m*DQA7miGhjT0={$4`Z=lyYpO(29r~-hbF|+oPgejZBX172+Mc z3!-CR~xoP2hb|JQJ7=a{{^UDWpL`-KF zVyEef@6{H5P}-5BLLwp~`$yMs!?&oVM_LUJr9e1C-Z2 zued%q%-5y)I#5);8ZE}hXNtai-<=#2&!lATfrE;4;#}krK&0as~!2OIqw)<8Qy?BYO4@;%J zc{#T}?C}q{laIw$?ZsQp7n)_d*gBu@#f9EK&re7YDW=n9m(aPRiG-t|`t=_&BxK0Y ze!Mdx%fT&`b8Gu}?(62!p+kt9hhLz-$0s)vF{h_yR*|lOK7N!Yws}w^**?;YI@(C! zsFlad4@FsaxjX2on2H475(0vk6t-(obNTkirYveBAH~)y>KGrz1}o|=8#Se{kxKMs z!{#Z`z0LxI)r{@MYEqUsD!91S#nGdAFYq?3VwFj>_jc#?_ztC=-nrZ zEJYn)?;273tIeesT<}EO5nBXyWH+Lk;GCQBQPEq55}p5=;k(`WyP|gtMMbeu14?v@ zp+wI+(I18qUG8jf+MiiwLrQdvp+qk{(ItkWI0eI)V&7!pdc{V~DA5gueTi9DGc!tb zf1yN&LecGo5`7W#-CZJB=Gv5K38kn+J}TPCC~74ib;1wI;-mJ{m+TTLynYkPMM_g! zU%=H^>e#eCwU8gpP!Gk%X2tqos$ z_JG83XTMmY&yPF0p&V;z$^$neDku+vN7>fDvYYY}@tR`2Da)%C#=bH9g~O6cM80)h z%r|FNfDiZcjrxzT%0^G0_@hvivXl_caj>9-2y^E(ecpHFB}7}sy1tiJ3E}1#+=au^ zmXQ3F7vV9KW3P43xStNUt2QkgiSb$>6s0UBhVvCIC^4Mo%i1fn=8WSd##qK~fheyM zBg{fSoy+%MOHBSM9gh)3o!)t$U$@jeGg0*E`P!pWWpSQZmJ-CRB^Q(+VG+60i9gTt z5@aQ#DwSIa(iU41hhJNQ@>h7pa-6zr%j>#Zj3a}~rcXLq4kXH0B2mJ;dM@e_z)MtX z8KqNhC5l&5+4AGCtR*VnSwNJqe#28Qaz7U}KDe-KBy8>?p(th9XK_>Wf_;`SH@Dh! zFy=EpHL`jXb%oPmZ#>B|D4Vk<@m>@hmNyB*ekdHi+@|`$daMw&+5&YVtWY@*q z^VtKEg&_aX)UUbn!`XKVN}OQec|YuUHNH;^ma*$!cKO-LvF(*3 z+n)#*pC-pPSe9&OKYkD>1KQkKQ^&%h8){|bz<#tw#*EivW@VA z`gC(thne^$whMo{86TW1Cir|%Hd@%Va?m5yXTd4hBQ@Z`YS(?e5#J-lajSFXbxf=x zHY^S+dXJRfXNdLcv}H8^qOPwUHn(gfbmdZ^C}lZja?4=_B~(}sdm3D;J1?P0oOG5~ z39Tx&Bo4nd3C$nQ#Cp~-+8xIIG+NdmqHH8Ke3?*`vXod(KPV`%f@1JnFOAK-#QrE_ zec8&Z#B!?_+=at$U1IZFYyys?9o*@s}t1{uTFw(*w9m>d`9ou95muNLR|G>z>k8E9n}8 z)B>Duy%35+<(nWWK>cOyB;OJ3nzhQ#4MR3YuT(?bl0QBRoVdKC7af z#MyCK*yMbP!`*SM z(9_AN8s&CIP+b%y9R3$G0v-ikk1X!!!n(-v7Y+-e+=0DQFzzdf`?2xs%N1E{z+Skg z{#;LodwR?tpzg}|^gl;LjS}8=E18TpWXjm@4|A6;|5x~09`_UXV@1(Ry2~nlx$wXP z;&cCnpJb_H&l!lh+T&eUoK3i3TrdNVOr0Tocyl~^o4sE=%>v_y!-DyTNS+reiT9Dj z`?B$+(?)m+d0DVAwmjm881a~nLo5L}o^MX)Q&H52j`3}|pLkb`NY2**a2)FZIF5Ay z9LG8Uj$<7F$FUB8<5&m4ajXO2IMxAh9P0o$j&%SW$2tIx<2M7xu?~Ra7#AGhu!qw7 z-&P>pa`;Wa@shp)utF%qBe5v>4bb?C`wY3|ih>d;tWe~5ZPn&_JABGGKJ$SaA-GHT zu#DaLQeLe?oTnmp;Si4n0+mQS?g=m+$IRZf$kzZlm#X|e1&>#_{fj)OUi=;{D@oFG z>UlR&_EXJ{8^y=5Zx8nZVPXH8-=pRGyINv7{yCWW{i(D3IDfbz?XZ=8RTeLg;yNx0 z${G7FTljN2|L4CvoQlN9mSIafb49?qAVxt52Mzh9-hZRXd9n{E*q3@q;@)h0UE=s; zp&Y{Bg5P}LD0no-ZypXm*TQ(w8|R%_#qxE2ix<-KaE^F1(-V{6cU(&U>?l{XL~zb? z>}T5L2j2_N;K1Rs=N?(G4=CEbN-!FaPZZLR6#`12HeD%1GeqjAYAum%+X-IF8+2aNKXXV<8J9o;?VH zK~Z@2faBckfp4?%EQGuUS{y4c*XeK<4hyzX1WPX%=X{_F#s^E{L)duTZnbu@0efLQ zunQ56W3M3`S6`lo-&`SKfxmpcv@6oitKyDI*!v1s8l#2d7%d#HS3OpbL#4=h$ZHw9 z>9@SjL%97e+=W9j4-xRdf2H#fEFJh=$I^l0SUPaL^T7w7PSN6&E7mtpxQBZeZh+-3 ztmEMKz9?M>-!FmAQ-^z=x|&8}U7;x4--6>j_Xs@q`JCPpHjB%QqOis&=shh~3)D;@ z5dI#Vd~$yNxL)3{IAK$AEPjd?Dq0weoPWY%?drGh%Pkg$P;x9piww-p7#Jfu3!E9XZ#JpyFX79jq@Iunj#oe9Si ztK>NT&r#7zjjB~{M@3_?8aO1QB5qe9Ea|9-rAg>!*yBrP3i;wVmL?pBI#QY7`NI1k&gKL3TF>w4__hi8HFkD}(JK=c-)}3%1>rOb1r3A;Zl;Aj)5*$BV z@7VEzeNMW#vX2i-`(i&nU3N`DjTJjx_V@s8Dl8(pe?RU!pCP082Is8D+U!4E&48Fb zkzswJ!*p8+=2>YfK}q0JX%$H263c!)G`xSWceNY})nOgW!(F1fSP|-AVcGab!8#l~ zBvc{44qp$>n-^bqD^!%DlA_pi?e+x+r+r0{cu*y4RG~T?uXuGxdmm+8s1BzpUL9_p zHyvE44reP~9prZ{b`+|^g^E{)Uw?~US*Q-bRlGX*{}f)h9dasO9V-1+DX>sGT&s9> zh&(x5S*Q*-D_$M$O^Lo$s1CO)ULE>aj;md$4)-cv9Xf{wA1zdehmtycJ+(*q;>zAa zMR_7AN(E4Ra=-tJKOqO()ek-u>mV9TzqTgKwjOt!dC}VZKg|I=7L4^Q*bwQW;VTQ* z&!~vVu>Ntvslwcp2Tyx!rfUBd%+>X4H_R7Jv;2l#CS~P? zP@nz#Pon!})7LV>^^4?sLg0~)Wg!IrKMKnU7uPp%vc+}T+@ca^slnD7j)v*nJ=~XY zA->10fpI5ja{nreA$MP)Glik3@xcD1E>}AOm#g`(@vL#eKaO6Ue>fcui<6e){nB*B zeGcI-Ub}v6yuMTpa5@|ox7;`#4$CTiai2^0%eOoiw|&Z1{w7qa!BL$_Fn!1KD;p#z04EMy!m$bpo3{(VOWPr z*B^%J`Ff~2>dt_W%axd*aVwB7t%(*kcLTGfI?V5XrJ=6&>L{hPCyY8nHJ!C}6mi=?8xdvPOsflG9B5rYCZ z$WMX*L4Y7Y5FiK;1ilpnimfmB5`E!YX?s!+f&f8)AV3fx2>e?FimfkvNA!h%i!I?J z2oMAa0t5kqz_)`y*{)B0TWfvAT^l6)U+yP@4o_AG1p!_P0SMu*ek@JrJdHyz>swh$<({8aSx-&Sjq+7uUoiY~t;Eq`(G zBK+SL0wtB7(n|lOdK-TJm!>anI>P^L%@;~4KNUSak>_tqo{QU_67_B`tq(@gn@+76K)e zpVCTST)i4U7l&V(zPRZKKhgg=8NhOf!{W+?kS_g05G=ab92Qh=4*OcXp{IGahEp>} zz(US0tX<*s;Da%=l)qV~6KM5oNox+>r09FKF&y#TtoWGH8utEp zhki5C5a#VPhg!$tpx;FsFsgfomhvZtiH2T*o5SkgcN zIvqpl)LlJbn}(A9>5M)|`CW(lL90V2=vgv1(4FB9?VAQe_y|wvx^M^>{;-U8QlCYu zJZIBcZB1Z%^=oaV{OP$0a0;rUc;sRQO}52DdzUzX8V>Me^A>ur@l|@h`D^-g+mm$i z;{b3UYY$R>mjnYadcTY|+55_QM-w+1jk!x(wAw^Jk&OVYDi7&P$^H;q|GB~_Jcrh3 zZvs+&Lv=5DrBOfnP5sk!z21M)mQy03-i8VE+Kb)brOr#b($xiun89u^F~}3LPdF%~ z{Fna7p!+P}PP=V!rR(%gqTj8YMDJMA17<2>z_a-Q#gsO|FeCYAMO4@Y+MR6+DgR`@ z?eq`Udll>7&8HzJ6ecJ}!-IGC70(W8z^iNf>Dkl>m^+k$u3e|l^yvtY@=pw0ML+yu zIJj5t3Z{797(% z5B^7{BKn;k*tKz?M>MR-Y<}?qc^YXV&F8tWGWh`9^jWX68<9>+7oY z`ly4~gvJV+nGTGNcTMD2qZ_)rd%tS+z7|a8bG0n58Qnpn`%Cyp)n}SsxUXXT9aM^o z6qC}mGxN|k1l?bBjkZ}A0@lN}gIlr#>N$3%YE6n4OqJF;wf}6q$oKLA>?)g;o(e5}cd+{8mwO4_| zgj#5&_8@q;>jFLB{UCf?rJp5_(1PsSnGk&P0gMivM^}qDNvG##LP^W7x7V4m=N&^PpF*W>$m89bv^$ zcbNF$IXKPz0i7OlQ>FIv2ROSu613*!DeOBRR?fK481~$=gS9RD(ncdU(8`Y2=|&gL zn8vve(4|$n$l~=5Xg$@3=`pb?8rd~b(XpKk?6F-7`ipaw(Pk%9zt{xB%6g5M_qi8T z%7h$c<@+-FJA;K#C2Ftgaf-XDrA{K0wEUHFnld?OjL^XTe<*EQU4qrEH^6Xo2yIFq z1KpR|!kye(5dU(I>gKFWSTQ9E?j|3FjLfa*?5WxCSG0_-Y2Jb{cK-?4db*&tcGZ}7 zu>+aMDf3Z{O9^!Iu|L9^Y&S;l(l8X*ye@5#V+@WOK}=r8UetNuI#tTZli;rZ3YxEb zjAExP0P1-XWVxk4>t|biAAchh`Sqo0{EQ7a6y2G^;LYOS^d z^R4@!%i%T1Q#k=yF7FMoH-^H4n%=bA>1(t@z%)2+ti~uZ)Uy)*$^@VIb1>OK#xyx} z8jXH6R%vBXgYkP^m1%ik4QiGHabTsDi4vpdYrJfL$5w7{56qQJ!&g zWPY}m>P8!VCiK*K(NtJbNZT<0ke4b zOV~N+w(6b936<}gO|WOoO1QB22Fkb^1*;EVg?nA~n95sqvz!m4qD_kyz=)(tz|@+C zhM9Ln!O4-})lvycwtuW0yLD%HdsC*~rP*M+akQe=g~6)H$0pHjoEtIcqIRiTHExdd zQf1KB;W1ph>WvPChCpXCOVySx<_t^-M+TufDBV5@7RO(QcUle5B>i#FBl3x|q~#B8 z-->x(b*IYmnk(`cxKwF>`7K=c8iVHae6GmYn*vYT9)JxRRkQ4G^`dX5)Q6aaTo~C( zJu7X)NP6S?>Gb%x>dZQmvC0o^#-a%CR?x|BIvmQqq8i#RXlI`PM_PVJgW0z+6^+)p ztMFT_tGsHm4F+{Mp`s54!pk#f;i8E?Gw;$F=bi(Xp#%jDty;Bb5}Uk4!IeB!r+?0c z`^K-K#_9lMkue`8F;nQ+!N$xiD_yj|yCyt(QAJhK^2b=)GFyCat889`pr6LC~<#v`jm+#GwnnR=KA+pDA|9NA}>{)X=7;049(t(!eR!)(x>0S^pn+?H(UCu ztkd1-X_Z>hR{~lxPV?3x&yfdI=2`Wa-q&`6tJ7PRddOPZ?#;E`H_pl!MdDzjwO9(p#tiNV zf$i%s1LoWVmyS<%U*7Ks8MOw(&24Mpy3TV{)qM%AYiJDbO|xNmra{&^tv&SB78}5K zrW13fUm|i{{$zLD?923k`M-k8cyn}anw|fJZ~FQhW3Y>yL{~P_W^S0LA@_$q^sC{&(Z^CKX2h8x$b95U)zIUc zU~23ExIAn+8k1^CdtbT_(;W4fMcFlw(alOA;H7yI-S?fV|gf4SU-(3Oxh#vG`t>u9{Tk95k+;KtL$a!NVm^f47XcUrO&UQ0jDmcgPp+u zxU-afp3yw|*`#AIx#nI7OioiJ&L2UeC5ypS{RNmg-9)eCbHOS&5_+jMXKJ@wi)KCZ zLwadPp`_&(_KU0k{X9DSA;!-b+j=L6`^QCo$!_w$rS841Fh4%`_HT?Lq4&kYIpSh* zXW?>}o)A#vJUkHy5)cFk0t5kq06~BtKoB4Z5Cr~11WG)A7+-ikP*~gld%=5W7Uuu# z{NeY)Igwf(=>qW7l4{GXja zTq&F*nLqp;Q$isK5CjMU1Ob8oL4Y7Y5FiMAEd+|3KVS!;e_4>;iK3n_rYo%V7oAD( zp9`n^+q z2Mf>giY{YsR5;zgo<}|^`~)(OEE;2Shaf-@AP5iy2m%BFf&f8)AV3fx2$UuQr8bXT zT6jKKc$QamiF+R_obF%GBVQMO0+~k^jWM}H5FiK;1PB5I0fGQQfFM8+AP5iy{yPNn z#!wXbM=&5VKxBZ(0FePA14IUh3=kP0GC*X2$N-T6A_L!=3~;Nl+}bU-4$J=LPRS(y z2nIw3hzt-JATmH?fXD!m0U`rL28aw086Yx1WZ)Zo=n9J27n8#BlG2fbPgVcxE z>xc{x86Yx1WPr#3kpUtDLLCWts)DK!6Izi8pxqJU9@@La0n~7SC!4p>gN?7!^UYt=r`w*S zlOG3w`&fIB^1CD$fYJM9w8`FA&O4g8(P+$F+M?Aa`iX1=XjOSgUrP3e*!s^EM&UWM zMtc*G@*Apq(JPJm(QoRXrt9_oleU}^3H3Hipx0jP1}}A9(v_|*P{a&&gNZ?&kbS~I zA?3gHM+V(z`F7fEiz{8HcM|<>a!|871FIiWB?F&ZAcyRUe5Py=3F+fUD?M!?*m6m;!6g{DtOfRuk?;41pz z55vK|a#t{QbO(LMOy}FLSJAB#C)0Xo$HM6<`t%@;CeW&<4%m-w0aE_fzlOpdwyhiN z7zK43g+tWA=Sd={>j$MnvF|BJ^(j; z)~oCWX47l_&|%VF%9zypx+=Xs>fkk@vBGAi17qV|6FJuChVJg(uUfsY1(W$)Ez4_0 zchKnm54r?OS_(>jKMzg!+6*NvzspN?#wspj_r$H)bcpp4h59Zn z=1S}Wq_@5wXvp`&&^#OFP*7v&wagVQXb}!`9vy(=x9wC@l4=1;dJN+u9)UyknaC+G z5q|siJd7Ee1}%NxsIJfQQQc1(2DdHEnB&(cpyaI{ka~P9TwF{s(HWtr-!FmSrmzC% zQ!1EyJ{5hmJ5I}9JcnuRRp2n87Fwx22p;abK+ktS2p?DJXUQY9Ap3SE1fP5WqeJJ> z)gn&P>A9Iu((>!=b!IF&yP}^SOh%d7aiG4p5m?^IR<-r13)}9rgoQ63fNZuU`qgR= zZS`g*{bArd=#{IP)!=bQSaH-HCVqGhPIG@ir-$5Bsr~!`&Tfwct$BG0`_6}zGcGiS zJ@@QjZOgv2(Z~(7vg38S(M2<+aqa_jX_YRrc)bH!PxWDXOstAVc1=`tY-a;|Y}bPR z;#_64*$LGzHo>s6UL)px?gf=HAxByHzKs6PU?EhA+N*k;;;w3`lL#d(f2EwJOwJi2 zG_e04N}E=fV0G&aFdQ91o6^TX_hq(lC-)Y_zucp`IV%%ZOo@WK$wwh0b1OP~YBu~8 zEu(9iw_uFje?qpNE~u?tHRfIHK<07Ed{pC70^NMXVyUX3|mb`vhY?28WR z09;JGqk0~23vR6cpa|@|j=sG`4kayr=f2ONPS6_Fl*=-3pQZ(-&rF#fm1m*4ZXMCx zG#}OIXJ$;)3d5|yb!wwptL?yi>ptjmcn$JYPC%B+dqeDvq41!lH|=)%8to7;4UQYD zF^UZJti-=E!6*J4Om>hlO%9z#qhF0xT3OU!{9adOS{_(~8tQt`L1QM+Q6aj_TIUU_ zpeiothb<>yS4KO=Z_Y@RXWSf_pRJ|3(MF#MJ#`*A#eWZ`W^(4y>D{1HdlG7Lq%F8F zvSUhG{?KM7%>G}jQCCMBRi%B~!2RtV81&W|U7aQehoy61+{(+aG;NqN`Cd0z*VGzX z-m+qrtZR<$x*ev^&IRy2=E&?g_8pqFAPIGIxJ{dQTQJU<=g^{s06|eNpvjRS=BTNL zv%!y7Rlm4}g6Z@o%pY$f=zf!~t5S_W(EF1p=JL!mG{r`Vj(Xm^wkSWpJO+mzePJn`Mnpan{Z#Xq(Lf_wERB$?_gEm5lFf65iR?; z0EZ+SRb`H9&dS`M%<@;t6>>0BXE-b!*GOk9!>cdyzUROP) z@>bm}=L4x|)1n11B54vZwWgtA<{eRRawK@QRDzQ2A8W^M-5K8Al&N=VHrQ?)t*CWj zuxj$LNpu_MM$EaWU8+`%n#C+`z>~HI zV1q{0Ec;u%=-VmvAtoUgMz&JVO4~4!-nf1`JwC2Fv(99!@qjl~o{1)pfubOOwK^;!0=!1dq^2}MdXrj-|yL866=fGts zK|w>SR_&R@CNEKNB~R7qpL5~9@oT8DIsjQ@%!f(L6gqaWF*D0b7wzw^36EY>QI)j( zG1j)s7T?<{n-?MIr!jkAM!iLlIsYC?++UqOWunPUJJEu<{(Tlo_FtvQOI2su7@9Ie zv$vwKn8C30>31;wWHsi^mcAEYytT-4XvVyD3RID^y2g~Q5f(9SvBfEHYSdwubj_-L20b`D#o4tFgVp}hTPWIOz?7pFL zmf;=RMdS^PBumQUOWB`yD=i^n0xF&AkZu!im(4Po=_MsR)UE9I(3tCWA<2vSfDwV2I; zo6(J%=jkx-{;)0l9$X#bhqPb0p%o3!fcxV5VBX)GzW&A->>?-8m5sES8|G=q{h<&2 zYWQ#Tu@s6Kab^fIA9+$W^!O&28hZdP51Wq0q*~J6m+r$fM?Gdyb`4}S^bCD-;au8! zg*{YF%R+Y6dXOEV%UsjIHqPusu(#zY^%yiR9ieuAjz{I=*bVh@Hq z{wfK5WNkCE5ATKFs_HPI#w$?2VH#-iTQ}G~w-0>Wq>XZV>Y)*{*3cgv?U@-l15qVw zHS~L3CltP54n)~LM6WaVwB6?M6#SM&gL#kf$f8ar?GbkxUJpMHeR}~&R_uCS;{`oXdeA+(lMA^b1wuYr>PR>kD$?##bB!b0?eFl zqF3^{U=J6jC;C6p z|B3!j^nYUiC-#40|0ni;V*e-he`5b9_J3mkC-#40|1W>`f8zg1{GW;cGx7f?{{O`P zpX`4j`(OUQ?SCQu55)hO_&*c>XX5`%{GW;cGx2{W{?Ek!nfN~w|7WuQk?emY`ya{v zN3#Es?0+QtAIbhlvj36neXX5`%{GW;cGx2{W{?Fw6XL9~CIsciQ|4hz*Cg(qs^PkE2 z&*c1Pa{edr$(6cBOQ9usj-ON%39F-#kKd^^gguq{?EV7q(5fTsqN%8 zcKnb(ht%HFXG^D6JL#(JE!;m;WkouBd1B9#HD}g z;`gNY&TgZJ)uX5j@592~|2Dk86t3$ZIz7ZE)PK(GdJmy-YfmjXz4|Zk38_a?7mg%c zmxfQ7zFP}1e%zD^!^VttbaAdD_~S~yi$tq6lwKz}4R-sR zaEID($G?j|N(yfhI>jd>#D{(T`tS2cI;QmbS|NYUTitt%mcn&u_&?;W?pYoZt>%ng z)1-^65&e-4nr_`8(NPxFqGg~tqc@|Y06i#OT^#yfqBW2%O(<>C1-+)RQ&$wEi?sZ6*1C;HLR0{p-_sweQz} zcs)LiSNo0)h^L_ObflBE1@wLBNxvB_^SbY&0iz18K%|672XZv{5hg{Bg|}A^;|cN> ziZNw|L_dEmBwEJcj_4ZdHNyZ(G&(}ck1<%cO)FyZ`iuJXLQ;U0c%vd#>>1D*q7wTE zE9J}ZYOA}s`XLeW`xEA27wZ?wE*?LES3}{2Gtk%D7~i=39A{g~ zN!#7$;K7|-h0eSvd^pubSUylsyfSN*csN3dM>1G=q^9~)+`q01LGOl%-DmF=+k4dDDXmga>*-cdYA_RT$}hotT0JAp zU6R2%dq919IKMR%YqsqN+dJ8cdz&QU){UCMuvN+Ma$gPXU8xWT8KlF|ZTqmNVk8_M zW?G+KS-d6@D(;%Y*~k6GEnZ>J`LRN7*(e2mu;_zB+Yf}&gj})M)ImHt-T+4>x&DRz zNWwh9t)MwR6!jjovrCkX{gUx?gCcOggGrk=5wNP|A@SAr1nk+Xy%?@1Ks|bRkhKTK zP2Yh#uUaGw+V4s01-6T_h9584!Lz2}c$p<@z{Haa3t+!h97(G=saQX?l+uxq1!qZ1 z@KAnj?MyW7R#Qy4{5(_)ihhG!jXDq)?+8Zc1_*%(H5b=D|hVb2y& z9;!h3=V<#UgL|HCD7YdE-(L8V#C~T^F=g@Gj;L2)zCtU!0FJcMXLQSlPT*io)?dJ_^Ih?)4jH&OJ6e2dX2$5$oL`dgzOlH`xQw(s z&;tC;2hlW0#*k;YZ1yd@$=HhY6@3^MfA9-fQMsM?YAqF#s#!kJ+O%1?Jbx}xoc4h4 ze=(wTczoys9P;8<#qB52Smzf@iYd>yI>C_l7x3!2ixn9;_ZZ#FuQz_%bVM7pDzF1G zTsMJYu+uvQHW$1lYm)ncMQLM-5t}Ymq|qo%#jdg(xVxE-HDo0H&N@gdy9`f{E+m_l z*)vS9!(v!p_#P#%xJ5LUo@3bP4=$wniFLU0U!|~pb}+-#oL|()@jUYHt0#<{|1)W4 z@}8z4KE{5y>*#69G}%6-|8rf6AziI$q|Mb6xMf!>wCVM5hONr+!Zo|1!FkzSy!ApY zU+o$0MwSlfLtH;@L~idg8C{p#{^G7RCiv0ES9s<}CB=xNQ!^+#bqKYo0kYbN_7gHP zBHRisD)=3F4Yb6OKOJV6PP^m8XjUh9pnC+L3&#{2lshaEIX{YpHx?Vf!hH^-+qZBD zGABTW5^+eI*;}~{DBOac`PDR6oXd-*$%djQ7Lm=vf zlQ_8C8*Ui1*1z%fR!@PU1eJEBU6M zF&y(-K`|7ka}o7Tau93Et&pBy6~)w@Ul6md5U)KaQ0Km8!Z{<>)MLtypOgg+mJEKav0{mc^4W`G7kWq3h~~j7NKaQzSrmiEy^kT=wJu1@FdIk}q8J%n6+;@w z^cAxv#G!-fw<(6_1ivN&2bL0zBQIcg^H~%_ZKs(Dp;lpJie8lbxjcbl19 z{E{KUB)i&vrgZmpl+YxX>^(eFSoxh5i>rTYxj3{_x$wiL0;G|*kHw9h^Oop&-A0FE zq&ic>_yDOnzvRq@X83)c7c%wjs!Y9BLDLnCY~SMI*u%)GqMDe5^`{t`;p~m~dfg_I zQW5GFQQH>pia&s-wyQ?#vUMTKv4qhXXbeX?qf&)KCN|{Sc2=iR)1X$U%ZJ%`@1klF zY*ESR1|B^nY#n3-)3%?*8;&vz7kk)=n+}{I10LTIWA&d>I>1w-Nb8{j5X0XevUfgm`#ZF6>j`936$8utx-#r) zxeMuV{RHZFYBdVqo<=e8acFc; z$Z9$V^?s8N*E*kM*t#+$84%`+rhRczgc}Db2CmC&iBrGp#QJ*|v~4G%n7Z?e=CzK1 zha-X5m(3>w=e(n75TlB9DDA78kdhcrAbSSIkZjcs5)fG`4}2^WOTvQ~-NjS6V%e)U zXz_@NsPobr6jSc9C+O=1mdN5!94`9!hGOEX!XJ|G|IlQ4wR zoQY>@7^OqL-A&P$lt|)}-3G6WXhSi4B-R2Z2IhgT?r0SD;yS|$bc?a=hGEFjE>Zlj zBb8xEe)F-PO*Ul2tReQPg$&yxH^i0K&ZAL!-BGV?IuuiPeigqvv>?-OCJVcB#=#z& za+dB&hx=%J)EF_=Ia~Z~2^(|aldVmV!}qU55B>f~Hk*xY(ShfcFg`g22M$Yudwp4Z zg?n#~KwiIeB8uG(&^|exJZ%@oAM zQUiy|$CB2Ct_*8`|5qp;>428lB*5H7MHEwaeqrO7$!N%GIWqsc5WktflBR*z>+e+V zJ@FQ`Ki^D|<+zw(SEk#Lmf~m};d%kTckWIxWCVjD?07t}v)U{=bz@^V9GBf0i@NJ@ zj7Jr|X3xfn#PIoV(4=A^n%wv@4tVHJSRxv;!!H z!}1nm=Y`MEv0*>K*2S!yBvwA5L|^A9@-Kdcm)>CQy-=85L{iRLlg3?c%P%%ZG%k|a z7(!6RVR#x_i8G$mw#7ex><{^UFNu=akFUQxP3eevV@GJ7V~gy({9xJU3k(yS^@w$D zHux)Iv8xTDn7Z>TJ(A50@wp&r?x^0}4xbD9%;tjlTqvIl{ha4QIsbG1|D5?>&2!^i z7a)ymxh_DGHyft=Q1{%pz;yv!7a$3E4b^?9dv2WT0;IWYt_x_e?t|+BRMUN^du|-K zE`aL-=$vB%bsy@U8|S(Jt_zUZPlg+)`%w4X_~)hz;I?oQuc=`B$8F(MllQs&E7=OD zVEd(fBnKXu!Naa%ZPJjre0 zWDT|bQ@3pxw}q4HKDULFHPrTx%fDRyrSnaM`+{*_FgowZ@!~%i2K5DUzpF?7l!jc z=l{={|G6(1w}q3&!dw?1l>uKDj_U%b4A0kv*9A~M;JN^=3!r@PAJ)O+ zzF?~9KDaHMRDLR~gU5ZrRI~l#wr~>vabGYl|I+@A%fDRymH2?mzfxV`ws2hjrFDU? zi_Ya=i4PjOHVC(cQ%xS^YoVwn4{~2H)#O3G7K&=}AYThq8awi}K>1prbj-l_1>^gI zQ5k~o3)bMZG5K03d@U5I$~1T%G`<$7R8}hNgT~iFk;ZE(?1RSjzpBamT>q<@ywCN& zs>%COSEI@Lo0V&->hJl^_lW0v#D7+M#B*O5?hErd`@(Sk=luUU^FQ|m^gI z(RK|y&+H`bGrE#*`WeG9zZI;li_^J?`X)JuHRV=F&##JN>fQ&9?~ARPypQ<4U@Gkc z&iBPu&GwJm!f{(T+ArWFzxmkDCL1zh))4#DLWb>;8{*1q=g}y=?x@!`9g3;j_D|jN zAom4RO&;XFU{Zh1_XXqof=O*1+&bSCzv_^Ii?gG}r)Flf{ZqHR&*fh(|5Cmp`xY)i z=Hv;+5v_&NX(1HjzF<;ccF{8gJ{afWo!gHPxA}RrTyS7OszTe}8@4#C!%tspQH;yK zQW=Dv$`Ow_eIRia=5YDjXjWD>nQtM;ZZWYvS1ov2%w$+qkrvTBcm?U{%8A_jIK$rA zxf83kHMs06Yn&GEKrvx$cLENPJ#ybaQsC7Yi4;?}ypOp2%jI8*uSl4^5v(`9g!`YK zN18ks&3G++qP5WT`9OJ|O&rcne?>8M%llmZ= 0: + if yindex_global is None: + yindex_global = temp_yindex + + # we have found a file with containing the FieldPerp, get the attributes from here + var_attributes = f_attributes + assert temp_yindex == yindex_global + + if temp_yindex >= 0: + # Check we only read from one pe_yind + assert fieldperp_yproc is None or fieldperp_yproc == pe_yind + + fieldperp_yproc = pe_yind - if dimens[2] == 'z': # xyz - d = f.read(varname, ranges=[slice(xstart, xstop), - slice(ystart, ystop), - zind]) - data[(xgstart-xind.start):(xgstart-xind.start+nx_loc), - (ygstart-yind.start):(ygstart-yind.start+ny_loc), :] = d - else: # txy d = f.read(varname, ranges=[tind, slice(xstart, xstop), - slice(ystart, ystop)]) - data[:, (xgstart-xind.start):(xgstart-xind.start+nx_loc), - (ygstart-yind.start):(ygstart-yind.start+ny_loc)] = d - elif ndims == 2: - # xy + zind]) + data[:, (xgstart-xind.start):(xgstart-xind.start+nx_loc), :] = d + elif dimensions == ('x', 'y'): d = f.read(varname, ranges=[slice(xstart, xstop), slice(ystart, ystop)]) data[(xgstart-xind.start):(xgstart-xind.start+nx_loc), (ygstart-yind.start):(ygstart-yind.start+ny_loc)] = d + elif dimensions == ('x', 'z'): + # FieldPerp should only be defined on processors which contain its yindex_global + f_attributes = f.attributes(varname) + temp_yindex = f_attributes["yindex_global"] + + if temp_yindex >= 0: + if yindex_global is None: + yindex_global = temp_yindex + + # we have found a file with containing the FieldPerp, get the attributes from here + var_attributes = f_attributes + assert temp_yindex == yindex_global + + if temp_yindex >= 0: + # Check we only read from one pe_yind + assert fieldperp_yproc is None or fieldperp_yproc == pe_yind + + fieldperp_yproc = pe_yind + + d = f.read(varname, ranges=[slice(xstart, xstop), zind]) + data[(xgstart-xind.start):(xgstart-xind.start+nx_loc), :] = d + else: + raise ValueError('Incorrect dimensions '+str(dimensions)+' in collect') if datafile_cache is None: # close the DataFile if we are not keeping it in a cache @@ -554,15 +608,20 @@ def load_and_check(varname): # if a step was requested in x or y, need to apply it here if xind.step is not None or yind.step is not None: - if ndims == 4: + if dimensions == ('t', 'x', 'y', 'z'): data = data[:, ::xind.step, ::yind.step] - elif ndims == 3: - if dimens[2] == 'z': - data = data[::xind.step, ::yind.step, :] - else: - data = data[:, ::xind.step, ::yind.step] - elif ndims == 2: + elif dimensions == ('x', 'y', 'z'): + data = data[::xind.step, ::yind.step, :] + elif dimensions == ('t', 'x', 'y'): + data = data[:, ::xind.step, ::yind.step] + elif dimensions == ('t', 'x', 'z'): + data = data[:, ::xind.step, :] + elif dimensions == ('x', 'y'): data = data[::xind.step, ::yind.step] + elif dimensions == ('x', 'z'): + data = data[::xind.step, :] + else: + raise ValueError('Incorrect dimensions '+str(dimensions)+' applying steps in collect') # Force the precision of arrays of dimension>1 if ndims > 1: diff --git a/tools/pylib/boututils/datafile.py b/tools/pylib/boututils/datafile.py index a535e328b1..cc10470f3c 100644 --- a/tools/pylib/boututils/datafile.py +++ b/tools/pylib/boututils/datafile.py @@ -760,9 +760,11 @@ def dimensions(self, varname): bout_type = self.bout_type(varname) dims_dict = { "Field3D_t": ('t', 'x', 'y', 'z'), + "FieldPerp_t": ('t', 'x', 'z'), "Field2D_t": ('t', 'x', 'y'), "scalar_t": ('t',), "Field3D": ('x', 'y', 'z'), + "FieldPerp": ('x', 'z'), "Field2D": ('x', 'y'), "scalar": (), } From 283af0adb780c9fb900288b6e7c00013c7eb7e8f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 19:30:59 +0100 Subject: [PATCH 1359/1783] More FieldPerp support in datafile.py Tries to ensure that the 'bout_type' attribute gets read/set correctly. When the input to DataFile.write is a BoutArray, we can get the variable type, and therefore dimensions, from the 'bout_type' attribute. This means we don't have to rely on just counting the number of dimensions, which cannot distinguish between Field2D and FieldPerp. Enables writing of FieldPerp with the correct {'x','z'} dimensions. Fix check for string attribute in DataFile_HDF5 --- tools/pylib/boututils/datafile.py | 36 ++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/tools/pylib/boututils/datafile.py b/tools/pylib/boututils/datafile.py index cc10470f3c..470b5c4f3f 100644 --- a/tools/pylib/boututils/datafile.py +++ b/tools/pylib/boututils/datafile.py @@ -473,14 +473,30 @@ def _bout_type_from_dimensions(self, varname): dims_dict = { ('t', 'x', 'y', 'z'): "Field3D_t", ('t', 'x', 'y'): "Field2D_t", + ('t', 'x', 'z'): "FieldPerp_t", ('t',): "scalar_t", ('x', 'y', 'z'): "Field3D", ('x', 'y'): "Field2D", + ('x', 'z'): "FieldPerp", (): "scalar", } return dims_dict.get(dims, None) + def _bout_dimensions_from_type(self, bout_type): + dims_dict = { + "Field3D_t": ('t', 'x', 'y', 'z'), + "Field2D_t": ('t', 'x', 'y'), + "FieldPerp_t": ('t', 'x', 'z'), + "scalar_t": ('t',), + "Field3D": ('x', 'y', 'z'), + "Field2D": ('x', 'y'), + "FieldPerp": ('x', 'z'), + "scalar": (), + } + + return dims_dict.get(bout_type, None) + def write(self, name, data, info=False): if not self.writeable: @@ -523,11 +539,15 @@ def write(self, name, data, info=False): # Not found, so add. # Get dimensions - defdims = [(), - ('t',), - ('x', 'y'), - ('x', 'y', 'z'), - ('t', 'x', 'y', 'z')] + if t == 'BoutArray': + defdims = _bout_dimensions_from_type(data.attributes['bout_type']) + else: + defdims_list = [(), + ('t',), + ('x', 'y'), + ('x', 'y', 'z'), + ('t', 'x', 'y', 'z')] + defdims = defdims_list[len(s)] def find_dim(dim): # Find a dimension with given name and size @@ -585,7 +605,7 @@ def find_dim(dim): return name # List of (size, 'name') tuples - dlist = list(zip(s, defdims[len(s)])) + dlist = list(zip(s, defdims)) # Get new list of variables, and turn into a tuple dims = tuple(map(find_dim, dlist)) @@ -868,7 +888,7 @@ def write(self, name, data, info=False): print("Creating variable '" + name + "' with bout_type '" + bout_type + "'") - if bout_type in ["Field3D_t", "Field2D_t", "scalar_t"]: + if bout_type in ["Field3D_t", "Field2D_t", "FieldPerp_t", "scalar_t"]: # time evolving fields shape = list(data.shape) # set time dimension to None to make unlimited @@ -898,7 +918,7 @@ def write(self, name, data, info=False): try: for attrname in data.attributes: attrval = data.attributes[attrname] - if type(attrval == str): + if type(attrval) == str: attrval = attrval.encode(encoding='utf-8') self.handle[name].attrs.create(attrname, attrval) except AttributeError: From e1e1c26978a45228bf0e9c605358294cc3a724f2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 28 Apr 2019 17:10:02 +0100 Subject: [PATCH 1360/1783] Add FieldPerp to test-io and test-io_hdf5 --- .../test-io/data/benchmark.out.0.nc | Bin 132190 -> 138486 bytes tests/integrated/test-io/generate.py | 42 ++++++++++++++++++ tests/integrated/test-io/runtest | 7 ++- tests/integrated/test-io/test_io.cxx | 12 +++++ tests/integrated/test-io/test_io.grd.nc | Bin 3752 -> 21460 bytes .../test-io_hdf5/data/benchmark.out.0.hdf5 | Bin 180800 -> 500376 bytes tests/integrated/test-io_hdf5/generate.py | 31 +++++++++++++ tests/integrated/test-io_hdf5/runtest | 6 ++- tests/integrated/test-io_hdf5/test_io.cxx | 12 +++++ .../integrated/test-io_hdf5/test_io.grd.hdf5 | Bin 7888 -> 12480 bytes 10 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 tests/integrated/test-io/generate.py create mode 100644 tests/integrated/test-io_hdf5/generate.py diff --git a/tests/integrated/test-io/data/benchmark.out.0.nc b/tests/integrated/test-io/data/benchmark.out.0.nc index 5a4906d1fdaff7c1ef04a19d535f7551c76ca75c..0f1d7022f68838691d3dc0084c8b4ccc59f7a88c 100644 GIT binary patch literal 138486 zcmeHQ2|!QT_kZ6uA=#oRWG7iFldbPN4@H);6hoFoNhqlph3tFwWrWF|wU9Kn-mS4` z8)OY*o3V~13}Z0=x1H28{Y+|9{`bx3e($;G-gocko_F85=bn4t3}?qSC5lxn#)y}p zA*08Xl78Z!zm@9`3mu7saZK-rKe7osIXiaMF}k5sO-k3*Ds0PY$Um%W%3)U}ET+R~ zM2eB8_*cUiGls%{p02Gs2Mr7K2@3J^2^Q#Og?~+?bm5P1jr0i$_8S(UwHXuO6EeVi z;84H*NNU``zCoiggS-cRlZj~4z@|}yMoc*ip}7pBt6{KJ>X4}}7XJ}dBxb!PB@bUK zHMN9=Mq?(XX*5zp7$b!dLtPWGg{7-jk?zefmW-((V>(XY(l-=SbaZs2jHQHrsL0e< zC}$6l(a)%|#YdIGN*Xm1b7&X?3AxrCTe`UkaS<`GW2K^n(6OD1ldD_1POhGAty^|< zVvPEUX&Odf%H`V9#Yte2a&bb4x!ec&1zQULdszxNw{~n}>Fww56Cgrw*?&ZcWx%kI z4@o1vg8aPt5A|tasa!U;LP57M4>uJ`Nf!_2}KHwQ~ooY4&0$m#)>9%W%k4 zRKm0a?qV5VqW|of(COp!{<-(W=SaLT{M_Ed-bYM|{wKW`svw!Q_ZBRc+fWO|UFf|c zGU*@w&fIGCR~t7sCuWo~bZLq*%qubLpxtMl7?_AzG!F#NpXNqzttD!q}l z+v+V7E5k6|vD-`;Mt+^i^elf3efHE4k(UeHWGE-LRd}%1l!u$qgxpmmMPzu?wS&%= z>a|8p<(j7DGkQ&`C$>-NCCh(!gBXcJwfF{+h3)AWJ?Wi-F&ry5?~oguA(9G&3Je7< zn7`=W#t*&rR(R0FtCbuu235o#8a-@{QL9ef+&#NHbrs)lKV*7>2gS6p&VV$_%Lh9g zrSy{!3l9QBj$so%0T~61SkR&0gAv^jX>MhojOXd#muir zp~d)qL4^+$ccgbv-mj=BsOj>%=R-NcN&)x=Rr4DtD68qHt{@%D!8nFkA4M0+s6WzC z14e!u;M{8)~$ijMpxv!N?+XVeqRLG46+Uujk^l%=Li>QyE>mLtu# zGSRU?aQ(je1EJxHo#7oUDsf+(W7u7QHLVheqQlK)?u|DP!_XmEYTd3$*P9+r` z`738bmvmtvOqil?}a~ijL)2tLRux{cPwBRCFw-p^A>>G|Gl$LJI`TJB(a~(tR7J;fnq@<8uA*Z(EmU+Y2aQ_l_M*WU=~xb{DhJ1H$cD~k zLvNW4y_JfN^=z%8<9%`Fg!M#zClx>9+(t#ma?likBaJ<#?#*SWYh$9p$;VijL*?$%funMaTPks_0lwKNTJMy;O9pXMYtP z%Nd}eV>#X`I+o+3qGNjps_0n0Z#MKnDmvcRPesRa2CL}EKSV{xdJa|5u^fLD9m_!* zB+46>Gfc&g?G04XvHaoL(1TQTyl=3Ij^&_b1?z+SBUJoYABD`kM#U8gG^7Yn1SkSu zDFPYxe`%mpCiRT2v~ZHyhOD1uDMjEL|G~~L#&9Xcb%zX8#xT03Z~#|yVD#$`_WzE` zv<|gi18F*{(L*amQNIwMAg>T%q5rAnhxS=TGcWQQ&#r|O&$)m0=_BHaONc00no!gX za7_g*JVn9;hZetK-dr^q(cbsAjmv8^yBAV4)6R^q+or2?XKDRiM_NEq#12>Jepdj- z)%T1EF)Bbxi1Wt}Qv1)pgy&ZWQ{IJPF1VF@$2N?bkR8z*${kb{gBiJn~F{dBSuF6;oEiq*pZ;h$JOp?m| zb-8bC=8;gY8S|vk_}YxK#M_(ywKj8AU@&Di1Z}Wlx(EzanB5N@tQpZpW5Qf#E;V3u zq&f^-^v0e^l}ZSmS*r=tQYyFB{*g_Ya?;(j5%+|jQqB5RGUJ$;0-1%U zrECvg>PHBrem$4e|2SZaz=)s=O_eWM4g@^pOYRZ@cKH(J*F;%A6@JQnCv>ZPiF22V zfIoGx6CNMslI73{qjD#q$(eDM`pg(p`%3+W z24wDZ zIn|ZCdMIG}EN3&!5;-X z+%tXfgS^I~Zz08EgU#x1@*0c&g%pduQ_k4rH5LO4DHg*9HaeZxSPU+tSgf>gYL(Ym z1Qb#%{OfI>lGj)S6;do#-}{TpYb-_Dl+li2|GZI1BTO`( zi}UU$DegtGPTvK?K)Lq2pKA2bD52-!(z1t#;)SEpL*s-%Zs*FQl~NCl6h-_-1^WaB z+oULNH5xs%S12jA7Zj7FMh{IFMF)pUc|2`yDb6(-J+xzFq}e`J9BedtXw*>BY&~t> zaB@#*^w7eQk!EYq3ezgdKN!P+P*1;r0H2^TtuYCm+H|}}Rdz%odbH_yhhAudL`(Sx zqvIWR$r*`N6{4=Mjm@2QNUfGZwYBZt8L5gPfzkD~vkUKv)EXJQHn!W{ky`Tu)h=Ce z9MS02%AnfXIVx@-8ok;IRnOPc#wNNK7E$K|+1Az!oi`Ms6tr<}m(_feBHHMLYeq9U zv>qUb6PC-N-_}>||J5@VSIC|*7+Rr9HduW2%HB*h28G1_L7r9blh;_xDWq8V=vam3 zH5LmBDHc{8oh|YjizS5=3-cz{qw^YzWrY+A!$ZI4`J6whkYdrI$HM5mmWwro6bpT0 z6E7JHLybn#Uo`UW?~EfYaGe8JQ850=-Lu(lP?oo4PxwLBa1P2r#@1QA?01#-6IsPQ zs5#j>D=690g`v1IggW9mStP$M@gPW)#o0^&vq$nip{ELn+@o+cL2DqN8}x zm2$VtQhEmuK*)X+mq-7nu5yL|C7+S7gf1RUBp(Gez-Q=C&!NKxNY01?hqzQOuI-C5 zFJ7&kI(GDI?d0m-)#-zqiJZjLC^n^dEBAJ;i~-spn7hIlY0ji5v-V0)CHWB?mlA%y zFki_!eJ_L6$3r2BaVHj&Es<^H&ijQE1%Zlt?s8}-@W}?7ciBara46{;-Hpgo0m!gV| zlVL7PQN^$+fFr!|Dl-dKX@?^J{|u$KU_X&1FSSL{8!7W!SM)*}RmUJqy4yYBXgBF@ z1yNTNI#IeX%;`Hf!=kE`6E?iA2nG{zB}kcJf9cu7BIUhvP^ro`qip~7$@1*sH6wUa7E~=vc)X+w!`wkDlIRm0Xql zln~KzF!P8Z&z0r@xPXsj8!_h+n6(Z?}PZ$ z;OwMX`6EF$3V;NOYsr}L550CV)&&cC}V|JsmITEZ6rN8 z&Mcru{z%liHF8z*b4)T*NtEnMFn`ksFG-@BYJ`(G3+k98si{K!G0bm?%5WA?By2$N zl8fTc<#i7)%O43Fv{tT4eoC0=Ws-T!l08d8_bu*_jZcj*_4-3pT{E0(>NocpnLlSw z;$9RC3z~$XABu>tcp0UKPZ7iScP&QbkHlH86Ynn^kSquJvhpL^hB8Z>Y#f5dm5xYb zS`Uq|{#8)NG~DHcVL_L;W&PxiMhP^0@WMr;yb1WDWBy3s(*huYRRshxOQ39Vtp1|- zHAw;oX_yiPRsu!Khj?LF*d)-}N3K6ggojv(w@$7qooIROC|4x`6HpD zqUEaOr-X`2X_+Ooj#MS1-x`=n5-OYyAfCoiFwdwrR(cY{uT4TTUS~=>tC;Th7Jr(q ztm&6O66>%*u1bDNtf(JkmRMOa7*J{H21#OVd^pOMUzL7}Kga8u&4(y% zFm2Z*`YY$?@MjtaD6S;)&;A;uxO4aiRSi`fJuZ3g3RC=J7GI5-p&YO?e_`3Vif@a9 zU9AO-d^S*x{)?9==Mhy2J`t(7H5uE~lQ%Qtby zjwsGB22bCdU}P_$#!j8jFtQ^HKfg~ZBR&lknP2_tUu5JXkzS7e{=VWg0Qfxe4DDG+-rfhwqobOa4ay3p73xX_3Z?1k~O~f}>Uio5+EzJC;6eqwz z5$WZmyX`JaUmwD$wvGsqaJ3;5UWuXDI`L9_w5q*p)V>tzm2&mEr+U>&y~d!n0B2Y) zAf{y|FpTR`3dh$LopE%`23SNqj$(R(Npfl zDC=VwEvTVO^k$L`7PfO{*CbJ>`$8PtWZxt4^Eb8y!;a_vsmg zQJ!Nj+K4k_FWQAO$7NG+=$0|RNPT~_FzvcR3BY%KhB;lqdqk%&$?A-|S`>1I4uEmg z0Wgj_0LD=Vz&Ppv7)Kod6 zRmjZOF7Y@LV0({Sylt32PeAo8avk#X32+dqkXb^tQk5zW(e(ef9zL3r8pcj^My|YO zohZ-QU#3EmINivrugjtbG=@2S0&sN_pCDY2#5k@&Vmx8=K}k8qz+)MtdxM)wzoIXs5S1KCpAq2vOBLc4DVjP!lF<#%Ji8LaVD{VVJV@@PG8Gbb8 z;5qQw&KH$0Gz)c7f4M<&oEAP_?z%@TSh$3-O&s2E`2Uh$XlBLxR}lYXd$sj_f4uN% zKkDx+qhA0vvxDP?<^QsWKQ#;f^tZTUk14m!$DWq_&vAByD9GWRr>B0EdN|MZ>vqBo zGC!5=Rq+l&yvv-OiXJ4_Ci7QNL`rsV`%m>SdV9#FGK^(%`iJv(v&?*ObVL0PXF&Lj ztLdNA`?8k^bFntMI(n5&L|9~S#Nx$UW*!4RwMluw3^6yugv$XVFRs{bm7_`^?@m@Y zvIKX_mNdh$kb2D z#iOGY-u*WtL2ID~nMVRgRoqF4mx*4xM6M|POA+`d1SHusEKGY7bNZG-H$-ebYOEMX zjTPfveomIo%)#%0;XA95!eC^mBdjGBRI6=yrIr|?)fQX#|J^pFo~fe+1Mxv=kzX1N zgVKU=lopKh?;D-Uc<(!lrQr8aveSV?r9`|?u8icUq_BuTF+CSLk+i`PeNuL6rjt+u(xV%b=^p;@uG{ZClT zs#fpY0*ggJx7=fKcEUelF>l*H$VI@zh-K1yX1th~m$uIyQh6UvW$3Aji^dAEsdxsQ zU`%251iEw;Ym@Ex?yMsmAXHGt_liOb#0x_@zRP&v-@G2*(ViziFv9e3o_r^aqdgDf zkC$dmkJNiTU6OsX!nB+JzqWcJN@yi?Ntr56SEOfE46PF4<@G@`9pQkYg8D3qwrBCe z5T8Yq1=O`Lj;kUV$5j!G<2oS5aUBrjxDJT%f3g*e^}%#p2gLZYeq!o}bX*6-bX*6- zIIaU?9M=Icj_ZIJN2$R$>QdOts7qlSbt#PFvxaee)-aCG8phdJJCNV8Hma3(weE#F zm0IUQx@_#xZkO>Xtu#RSV(_PJPuGjcImExBo+TEWS;zVx%a4KLEpz%x#O7fr-WOkS z!BTl2;^J=P?u=7h3qu<=wypa|<~CeEqiVyKgLD4a(UM;?&Nr^7s;VOF z#r>?)P`{u^xO&WW%mU}d!q-%JB!?nWK2JdfOc4TS8jl$Q4 z66fD^%+iM2g|7`pcPvx0wBfhH*M<pJ_$+OBRQTFpd-s$yU(a~Q zJt=%`7~8t$#4P=gUijJ&^MielENytHYQvXPdk#F)G0akx*Q%-%0=4Id{l)ucX@lg- zCbUCYv-#4Ru+V$rH%hYC=KpC9FhjGkQ|3nSKgu1Er1VFjXoQiYXi*UlB{32Vf}wr^ z-aex|eTNR~?=@6tMs^NPI32=JY;l`YZ2~jH5x!f-AxRFH|3`2X7n**hM5=|SSNFwdJ;g*Y}|+}Qa~ z@o5uZAL5%8P5a{d1Fk`cG^C3re~}meVVbz=Anqp+|B2;_p~#~xHjQJL@sb~LTFGOO zRz@INx!An+0+WVVa3b6q|3KP zWRp(>Od03FRiA!~EcSoT?|oE+JASb?r%AFTb*=;jkww~UpO49UX9-#beSDukqE&(=Mdd`8~E}?=R(Db(GW0y z9RY_r5IUkVSoP|}Xr4T=pRQ>n}5){`KRq^YWI&6Gk(k zuQrxl{o@e`tTl+db=QX>Lyz;5Vk|lLRVn1BdllF}COm|B9kxK=Fh4SJE&~(XqhNjP zJ?PQ#hy6P5Hn72a4`?Hgd4u5}+eoqZ@!DsPk3x+x#kk-3>e?YNiL^;Egl&EA!(rYS zD!8WYTdv~-P=l`$7Lh2tma|;KSLd9>)fx00z%avIGYdDvBm|3Z_Dq+k6bP3R z$PxONB0v$K2v7tl0u+I-3V|H!3j?UW@Kp%_Z45<#B0v$K2v7w61p+zN7ba1C;a|W? zSttS&0g3=cfFkgfA&|f8Q(xCwUryHsDgWpDiJ;tKm{TkB!{ z-}k5T{B_B5PWv;zd>Pv!aRlINWEXJMD$+}1y*cv1eZ z>v_qo{Nz>soNASLUkpDte@^pJ{;vyx+{#a3&;NDxCT&el5h(2Po7?*56fesEbs>;j z`N^yNIn}H2z8HRP{+#Bc{8axJWdP+4!<@>6oUi?qez47QHv2I7IqO&JN0F7*u4}I2uD}{51CD`=Zb+ z_&MvQ=>moi>w~x530BSjl54ujYEqHivEy54*((tC{GbmT ztuL`%4p)J|xULRr{`5yB;Z5zU?9;PV;e6yRZPjVd*=A3?wdUO-*wXQq@aooD_RgW< zaII)L*j#-GsQDw-*u$QI^R@i7RMx%Q6n32JAolMEwc%U0uCUddW6xR^gT%py**+_3 zLG#&fwQBxB&W#-A_wj?3C7qzxhT?EKCIA|0{b1ZoH@G@(5Coq!h2!52grc#X;o&!( zLCwFpT?sHh*c&GG8x5A_#q*J!5)@zXJBN&dv;c|E7bYBB)oh)5Q3jvVe9UEq%Cu|xOS%5cvj87-veOk zz2oeolrh@Ul`4V#5gLH z->c$m==v-kOuW-c!yCWy#ZLVKfg!$Nbgqon$bTvOclZqGIaQBq-*9B&V!!X%M|~sN z5zR_)y<)c~E}OL&7CkASxTkj!&Y0gs_BZKG4&5yemD}Bf?@QbxQ)iclz#rekq;j>n z330Q?!s(F^bTbeF%KimE-q^|SFM5}KJ8V6iY%QYE<9^--)^rmX8RlLO5jZbeq^UwUWND$ z3&`KA{rQdlF;KTr6Yjy<+9cp<7;!k|3X@~4Id5kN(y+1z+ihMbbiS#_mAD;FoEMgH zc(}A4m)rX9jj-ivmU=^8C5-R@6%w5+I28>(`BY$l{jzv%6eV1>5@T=Eh-(VwtLEk8{z2!x=Oo-5atEVKm z&MH2{;68ZGZ4bB8YLP2N?1<0kvXC6xfHSRdgBYeQAqxhahTPVFa!?=c)QP#|;Hap? z-OH~*W<|o8$$x9_Y4@d}YqS&3 zo`-tT8g5h%SK@4R1YEDxh9@Ns!sV?)N#wC*;P!qK)cU;|clFvNlKA^TGW+LbaN2ek zyk1TwvHIs&_eBR_&@OLo*JNAL?o<>0LDg03T@5pczA=CuuPL3h*i_=*HXEV+{?hTB1_E>wXb`0q^J(}IJ zeyR4+{shwFRz-&v^W&lE&Zb;w&tJ%$4R`pqUA92`BQN2M?@hjm-Enraj|=R!tH(X8 zzn`p}@F#DYX2N+z)#b)_Hz2yBTWb55q(SnsbkJKAK<>q@fy=Eo!xPtJFt}Phsn45k zeDL7a@cvj$ZjEgOvHN`(+1{!ocX;42Xy|pAtyIK>wdj$;=C=N8UGa1PABywSq0aPu1oL`(=nTx#>%}+D4W*=-`&J*7>_+Ga|Vv~DqA+^SC z2ujz&?59oG;r&X(h(@VwZtLIYh!=P0k{6j2)0DluXb_yZ`3+aETr4ru4PakBWw^cb zR>GZk^ZC2XG(Pr#=(NF_C;daA^x37*??DGnxA_gS zePdO&d-_AL(&M>_jcHpeSN@So<1za*!C zk6QvCv0*nH=w1%ic1;EC#rI^&|@5JfrM3cjFo0EZDFc{sh&c)7|Kt?w;0shKX*texKG_CZ4L|1ZR19bf0 z=9QCBChRs@`}zldLa%2KYx2Cp(*@#HkTo{^=IbWa#2I9$?LZ^>^_e@5VX_{ z{%HFrx&L-fV#KLyP;0Ug*J;HI{`7cXer2^85Re`RMVr`?5bYEa_SzG?O^b2cU+#A3 zyQCWsXMH$rbq`K?Z6~##)rDsM`ytf*XQ&bRkStzm3e_}TurHx0=X0e((wj-M`Oa=p zaP?v-u2_&SX=a?d|9SJj;JnU8_`BN`vNX9kR68;Up8GcD&ROatEv(^0jCwo-k8*E- zzxF+8(Z!ma_P-0ct^cD%L%HTBNAN?V9N2@+rn0v~l41Cp8Hvj`ALRpM>%oe*)wl+G zSCg>a`uwkbJz&VrKyLroKgsZ$b@{1Pufv?`DPsl_|@8hFnIe}s9EVbX?M7CVw5l^TC{u*M2|4#UoLkAoxq>> z`cEp)=`;-`98@FC2588J-VL~bM`?WVy44_Y@g|3TH=Y3-RVB&c;o8I=Y&Z-GtIyr- zaDlhFo5YuDQ4_-Y&4xHv3qB@jBDfEE$L6;F@_upMkIth@`jw7!`uOMOF^{M4fmRu6W@&co@o5`j;X=5ugZA1SkR&0g3=cfFeK<_%9I1 zZvG&ASn6M02@91OgTnvG`9pG6{;acuk8f%JBx{LSEu24;QnJwb!^hZB3Ppe-KoOt_ zPy{Ff6ak6=MIf&c$o2eTN!Iy5R&D>|+KxP!mH(6ThxDu^()q*3m{JNwfFeKvfFeKR;@q#LPn-!&G)JK1eRp~I_n)iHLsxlO^6%~ zDFPG$iU37`B0v$K2v7tl0u%v?K<*I8vw7sktnt zW{(w3p$Jd}C;}7#iU37`B0v$K2v7tl0{gU zpfW&ZfXV=s0V)Gun+%AnxZ;YexDG4)9#8*K45$oH8K5#iWq`^6l>sUPR0gOFP#K^y zKxKf+z}F`OX(iinX(j!*-=|IHzBbziZ4b5AQ5m2zKxKf+0F?nM15^g63{V-MGC*a3 z$^exCSq9oq=?B{^XR{BJpR1dah99`YiTUY8Q51Wk=Z3ejfW`lQp||usx{x zTkmfLKC5T2;V~&%%V;h1I$R9?x)BE5*%0XSU7Ew<8Q0mGnip))mISt9@6)WBzxBZ( zu+OZv_TVNr(fShGk3=VIrgk&F-RPInC-Ko7BrvzR;%V8 zV*;R|)(^(bbc3to20`#yQ#k(ZKqwm986JMq8Pxon+m!(GgS}x=ztLb>ZY?10ndy6}IlqN7^!Xi)&|^jc3*T`#k`r-aF1dN*SXqU8xe-FVTbLqx(adX)L=U zcplrPoCnNFYYoQhE^6DE4`$W;H`jg7_8K#nO*lBV#f7w&Y(z*6*rF*1z80_9U9J4t zce)|at;J-v(;_!`?>gB*&99bcD*sgesr=LNpN{|kKgR!v!Bx4NNu`raPCD_uD$a(k z&*H(vJDoJV@he~K)GrVi;tNLS%4m)Jm$H9{&w!p&^|AScThF1oBv$mdAu@VNixiwdje|g+(cHz+VZ8#hQX#4 z-C(wjev<1Y2k?wr1kHRmLaB3}WJlxaaCuxDBvm^MO&pIBqx3V{$5y6X`1$7Cy+%WM z%0ygY;U%|!L9_}B;ZGOs^wLP@34UUz1pAO z=pO@h8#Un`tgTG~o`w;JQ?4*M)|&Hnb|4Kad$8T+g+k|>dR&Ry;lz1i8Ha~U>v6fQ z|K12&u4bt>M7UWp;B;I%V1_-};9rg`2;urLdBHLSDWXpsI?YDYLg6pi}Lk#YN z*WC7SJFOPEQpAqB{U-G z629jQNtXdD$P=&bP-|8soSFQ$_MUbR`zodwv_9g&y`H$8{M3IkpKyZV%&Sa*iG$6F zul-NFpJQ7#Y7-uWeKK;1%#%wt& z^>8K5Mn}N)T5Whz;vih!I+R2nTLy0LH$ko6t8rJaO(KcE4VDgNbSBJr0Up9+Hs9f!e161M0n(&R9rm7M>=prY!?vIpUc4RAqye5^|yaz z&b2f+NkXDaLvq;)+}h*q;NavK62CZ|HE=fL+~eNBh-Z(rw`#|be$%7bE$f$RAMH;d zJ#JNWXfZz?n(l1Mh4%b~+}Uu4Z`)-Hv_J9^&iLNso7f#^H~YB2Zo7Ki!}|Nl$_an+ zrfDXeS5#eYe0Kw)JG!N|k4YLNFG~l#MFHeq+#0ytdNVw6O$LLj)syBa{SUJdV$ z)#TRLMi9H-hmq~AN^*w>9)pHnhuKO+OjwH^DQs@*zc%g~v>Fyp4i9NYdU{1d37vPa zYI$8U#56#d6Bpr5wKU<5HhWKO&Q9c8jH?ezlFhk={X1$yr|Xj^_P@hKiyvV8<46+P zpe>ZSX$4;X_u=rs+eD*d%iel-0Z!N%aYeL6lJ3TgCg}@Pp=HcW@T%iY0#a792Q8k# zyqU>BrYDgLiwvM@@#FmBCr);#GS3Z>63g?I?NgPRc;PWC1AB}a-I@DsO{<7O9`!?!tJ8G`>bPy8i01$^8R_=pX= z;XwCtu(oR|XfN(3vrhJ8gUzlaPV9RP>c84ZcHccf{38-ztba}JeEpJ1woRIm_)=%! z`FJNzUniOzp4*%ZK za}py?U4vSajkr!LUht>K`|>NR&47UPI4Ii0mV{`hkg(UD;B8ur+x~L5L*FIcfH>>J zX{&p1%4<8R{j4rD^WP7l?mt6~$cJR{Qd6j=@q&E`O*x+{6_Vaen$351i-M~cOL4`5 zd`UCo)cwz!{{`oDHp1WCu8^h4#i81fIq=-KF?Y^VCuv~~Ct}p&A$XK~1N^n`NsBJl z9g+;g-^@r{zWFF07+VikysgGH*t?p9?bhdi z?dt(Ub_R0$$Nou%->l0|t$H2iR9^|H`b<)M(qgDoRRg#0>v5LvPLa3{mH_WLxK@*g zPP=uJit;~e?Z;e#hO->Fp(j0fhYNN14q?+^a2sc|z<|tV%0OxDQ)ub*1NpZ099C-;3%RZT`eSa~<>Bt+wN(o5 zs6RuyM)xwL4th&gyg&q=$(l@p@`o7ke|dmws*DgSc0E9eCNyw`tHc}}Nk zDB++QX*NJZHuP@51w2aQi`T6NiHkQm?7Q&{*r+N=4iDER_F%(dP*{ELZifrJ)!ih% zREwGr)^9e%xmxfsK@-7!$U8Q-_0O&TO!a@N|5N>+>i<;#r}{tD|Ec~@^?$1WQ~jUn z|J43Z?f=yNPwoHI{!i`y)c#NH|J43Z?f=yNU-0bz^{*d?otL*Ho-mpTeYLUd>K~6l zV68#qt-C%98G4+b6l2M`uSy|5-K)U#zj^hxw6-a~YW69tG=T??I1_KkV0e zw}B1bdq5j`%o_~<*hY%IkJmnXd=zSoDaQTISJw`KNu*7RA#Cd_tPk_XP{B2A-*O!{ zFx%Ic`*GSL;>fN_yl&eS_Lv_9qtq(oP@OdXf&OJ!Tw)_wl@De2&Ir1^Z#xC4)x!l{@c`loBD54|845O zP5rm2|2FmCrvBU1f1CPm)BT%t|0dnPN%wEk{hM_ECf&bD_ixhun{@vs-M>lqZ_@Ky z==m-5{1$qC3q8Mup5H>xZ=vV6(DPg9`7QMPmcn~}3-#Zo=Wo;Vx9R!Y^!#~x{yaT@ zo_>FUet)5GeSd-aZ&Uwm>c36>x2gX&_1~uc+th!X`fpSJZR)>G{kN(AHuc}8{@c`l zoBD54|845OP5rm2|2FmCrvBU1f1CPmQ~z!1zfJwOssA?h-=_ZC)PI}$Z&Uwm>c36> KxAW`#?f(O-JdC#h literal 132190 zcmeHQ2S63a)4vCgBBG)oARvMj8&U)nc{fJ~6;z611rsow6MRdh^rDDKkM zrsR|!{}ccDC|QzqlmDhx4XZZ?sc`g{C)MdBHP0H!jEPRgwS6Mb<`*s zN6`)8{>rGTls5Zch@V@h=%K^O!~P)6F6(Kwb%Lz}y!rl!Ux)MMMhm};FO zB=-~0&o8pc-wK5bscXZfkWrdEa&8@50s`1LhZxteeAaB}?&Is>7vR&;FC@UtrGp2h z8_M02Q5t+IKNnvQmWfZrupv$rI51+k1^a&=3l?WLcTbD3i0}GGa?o4!9T8&@IW*?e zt=K-%5q2GZzUbc2@PL1~b-a){L1*i~CSnP24Z*kJD!Dh?0A+A5eMcE5CZmm*A zifb2&+NaL_rKm_Dpag2-Tp`*}Y%R6{shT3k--CO1(f*EZ-tBQoixxv6cZG(KhjW3f zex0%}kjvw1w4Wn2DrubjpIeW6kGKnmU)p-O^)V(||4HkO5|J$2dLI&nI%r~XXIoEf zX5mJmzbz)-4fhNP@Sx(vu1i*lqF!-H2W~%|t7*V7%fwET{S|MEp<(I!<9rr;rB<_O zNxe%7Y4Fdj#+8w~@VoQbR#O-HCT*@eq14sXa6+!yT>WsfRnE^6bKvmHx+mcUXraYD zR{GLCn^akCjwl*lODDEN2RlQVZXAm?xYcDbcST9z7#{hzSNmG6 zWBw#ImT z!3rOq!C`uPaeT#^f|M?dJ)iO!E@ps7P$|Erh_aN9)fG&~`QSJXad|{tD8KxeE*NzF zUY^QDJQtfMr1@8o@Z<7SmC*5Xs}(^P;m$87&IfBJ(&zHCdNwa9oma04&~ZNee5(K* zmj_S3rTG|2%8B#g^bhWm^7HEAKhQa~jJq&D&WBf^3ea(ROnL54{FrVgq2qjNOX!&2 zya+n43$yp6<*_J&UsU|^`EmYrCH%NN^(1u6U%v>tI62PGALrAs2>wPz(5)nNoKIs3 z9hav`5%i`KI?kt=gpTuRUIg7*LdW^EkkD~HHbu~FC3Kt*XDs6`+>SUOdx88ndP@l% z=i?xu<9r+?bj;sMLdRx{))G3-r%e%bCkY+rgAKsAUbw%-MlC5_A;|~x(?!rhLdWG~ zBy^mQi-eB(T_tpkkDG*!^T9JGY56@Q{5XG42_5I-C81+}ZwVcj$45fP`Lrv7-d;k- z`FD`eaX!8hI_CG2&~bS>O6WMBPDRi=OXxU%e+eDu6Cj~ues+e;Ul@N}o*)Sw=hH<( z$N6-X&~ZM&5;~UWZW21qzk3n%9uhi!Zchmv=hI6<$Naq|bX?952_5GXDxu?i`bg+F zpS}`0u5UjH9p@ib1iin6j-NX~LdW@pOX!$?poEUg86lzLd2+K@F0Ev2x0<3HK?xfotbaa&wbpIp z6xTp+ch*CO<*Urz3$yYQ{Rd} zv0OOB#gtQ>s5r`kjS6MjDNYlxwE~9+|MU!V4ea1aX{e7~sYz{Q^D(5xCiK^$(%G~I z)a<$2bSWd2T9ayT4Am$zHakOV+NPfkC^xp|M$~~SKE~7$mTE+~2R=8YIht+l#^*QIFVsjj3Fl@r|e!Ja13c?M74%%V0#UiC)u$;wE-= zsO=A(n^ByN#(=s?U9zUs_%aOm;f*78j?ZD#w1%xH7e3#HyJK5ZHTkD0X53?c@+Awc zZOl;9SY9(KZD>_jYBEpFUizCmmBf~}CiQW^NiS+KPpuSp*oQj8{xqcQt3UIhda;?A zP_<2B+fjCWjZain>rD;klhqzoeI7Joao@FoGp+s`}&BNAcwj* zDl`%{IaA(zn_){c)thfOY+x3f5!;nTVW^I?TEa79D>Ai(jT-U(Y&?S?>DXpWUFYv& zQ?V$6*g`D60N5~0x$#1U?ZKjq894WSf*)N*p{KXID~0_kxiZvgR21zU@W1p187Be!^=V|3$+0j=$3z*cbP1P+Z*V}6YjQm?tsD!O zhHp2PepEE;%H&wmG<>_W^b2AKDU)N7Q}+$_x+xlUWpXTe>b~8)o>=3&u>h+3cK3QC z8gylHEQe~5ahkT66-%R9Nkfe+9*2%ZIiNOB;(W6%>nUUBg348;kB0 z6pJ4^*PUM4SoE%-Sj2B$npE0Y^sS&+cwV|(>ixxl3W~)lPutO@Ef<3-C>FQQheek* z7LgSci}U+!w-$kgu>GwBn-@~0m@LFIpz;~Ewcgk6pEnB0*oo$IZr+`HG*GMX^qsXa z)NHpsPbSAk33+#4m*DQA7miGhjT0={$4`Z=lyYpO(29r~-hbF|+oPgejZBX172+Mc z3!-CR~xoP2hb|JQJ7=a{{^UDWpL`-KF zVyEef@6{H5P}-5BLLwp~`$yMs!?&oVM_LUJr9e1C-Z2 zued%q%-5y)I#5);8ZE}hXNtai-<=#2&!lATfrE;4;#}krK&0as~!2OIqw)<8Qy?BYO4@;%J zc{#T}?C}q{laIw$?ZsQp7n)_d*gBu@#f9EK&re7YDW=n9m(aPRiG-t|`t=_&BxK0Y ze!Mdx%fT&`b8Gu}?(62!p+kt9hhLz-$0s)vF{h_yR*|lOK7N!Yws}w^**?;YI@(C! zsFlad4@FsaxjX2on2H475(0vk6t-(obNTkirYveBAH~)y>KGrz1}o|=8#Se{kxKMs z!{#Z`z0LxI)r{@MYEqUsD!91S#nGdAFYq?3VwFj>_jc#?_ztC=-nrZ zEJYn)?;273tIeesT<}EO5nBXyWH+Lk;GCQBQPEq55}p5=;k(`WyP|gtMMbeu14?v@ zp+wI+(I18qUG8jf+MiiwLrQdvp+qk{(ItkWI0eI)V&7!pdc{V~DA5gueTi9DGc!tb zf1yN&LecGo5`7W#-CZJB=Gv5K38kn+J}TPCC~74ib;1wI;-mJ{m+TTLynYkPMM_g! zU%=H^>e#eCwU8gpP!Gk%X2tqos$ z_JG83XTMmY&yPF0p&V;z$^$neDku+vN7>fDvYYY}@tR`2Da)%C#=bH9g~O6cM80)h z%r|FNfDiZcjrxzT%0^G0_@hvivXl_caj>9-2y^E(ecpHFB}7}sy1tiJ3E}1#+=au^ zmXQ3F7vV9KW3P43xStNUt2QkgiSb$>6s0UBhVvCIC^4Mo%i1fn=8WSd##qK~fheyM zBg{fSoy+%MOHBSM9gh)3o!)t$U$@jeGg0*E`P!pWWpSQZmJ-CRB^Q(+VG+60i9gTt z5@aQ#DwSIa(iU41hhJNQ@>h7pa-6zr%j>#Zj3a}~rcXLq4kXH0B2mJ;dM@e_z)MtX z8KqNhC5l&5+4AGCtR*VnSwNJqe#28Qaz7U}KDe-KBy8>?p(th9XK_>Wf_;`SH@Dh! zFy=EpHL`jXb%oPmZ#>B|D4Vk<@m>@hmNyB*ekdHi+@|`$daMw&+5&YVtWY@*q z^VtKEg&_aX)UUbn!`XKVN}OQec|YuUHNH;^ma*$!cKO-LvF(*3 z+n)#*pC-pPSe9&OKYkD>1KQkKQ^&%h8){|bz<#tw#*EivW@VA z`gC(thne^$whMo{86TW1Cir|%Hd@%Va?m5yXTd4hBQ@Z`YS(?e5#J-lajSFXbxf=x zHY^S+dXJRfXNdLcv}H8^qOPwUHn(gfbmdZ^C}lZja?4=_B~(}sdm3D;J1?P0oOG5~ z39Tx&Bo4nd3C$nQ#Cp~-+8xIIG+NdmqHH8Ke3?*`vXod(KPV`%f@1JnFOAK-#QrE_ zec8&Z#B!?_+=at$U1IZFYyys?9o*@s}t1{uTFw(*w9m>d`9ou95muNLR|G>z>k8E9n}8 z)B>Duy%35+<(nWWK>cOyB;OJ3nzhQ#4MR3YuT(?bl0QBRoVdKC7af z#MyCK*yMbP!`*SM z(9_AN8s&CIP+b%y9R3$G0v-ikk1X!!!n(-v7Y+-e+=0DQFzzdf`?2xs%N1E{z+Skg z{#;LodwR?tpzg}|^gl;LjS}8=E18TpWXjm@4|A6;|5x~09`_UXV@1(Ry2~nlx$wXP z;&cCnpJb_H&l!lh+T&eUoK3i3TrdNVOr0Tocyl~^o4sE=%>v_y!-DyTNS+reiT9Dj z`?B$+(?)m+d0DVAwmjm881a~nLo5L}o^MX)Q&H52j`3}|pLkb`NY2**a2)FZIF5Ay z9LG8Uj$<7F$FUB8<5&m4ajXO2IMxAh9P0o$j&%SW$2tIx<2M7xu?~Ra7#AGhu!qw7 z-&P>pa`;Wa@shp)utF%qBe5v>4bb?C`wY3|ih>d;tWe~5ZPn&_JABGGKJ$SaA-GHT zu#DaLQeLe?oTnmp;Si4n0+mQS?g=m+$IRZf$kzZlm#X|e1&>#_{fj)OUi=;{D@oFG z>UlR&_EXJ{8^y=5Zx8nZVPXH8-=pRGyINv7{yCWW{i(D3IDfbz?XZ=8RTeLg;yNx0 z${G7FTljN2|L4CvoQlN9mSIafb49?qAVxt52Mzh9-hZRXd9n{E*q3@q;@)h0UE=s; zp&Y{Bg5P}LD0no-ZypXm*TQ(w8|R%_#qxE2ix<-KaE^F1(-V{6cU(&U>?l{XL~zb? z>}T5L2j2_N;K1Rs=N?(G4=CEbN-!FaPZZLR6#`12HeD%1GeqjAYAum%+X-IF8+2aNKXXV<8J9o;?VH zK~Z@2faBckfp4?%EQGuUS{y4c*XeK<4hyzX1WPX%=X{_F#s^E{L)duTZnbu@0efLQ zunQ56W3M3`S6`lo-&`SKfxmpcv@6oitKyDI*!v1s8l#2d7%d#HS3OpbL#4=h$ZHw9 z>9@SjL%97e+=W9j4-xRdf2H#fEFJh=$I^l0SUPaL^T7w7PSN6&E7mtpxQBZeZh+-3 ztmEMKz9?M>-!FmAQ-^z=x|&8}U7;x4--6>j_Xs@q`JCPpHjB%QqOis&=shh~3)D;@ z5dI#Vd~$yNxL)3{IAK$AEPjd?Dq0weoPWY%?drGh%Pkg$P;x9piww-p7#Jfu3!E9XZ#JpyFX79jq@Iunj#oe9Si ztK>NT&r#7zjjB~{M@3_?8aO1QB5qe9Ea|9-rAg>!*yBrP3i;wVmL?pBI#QY7`NI1k&gKL3TF>w4__hi8HFkD}(JK=c-)}3%1>rOb1r3A;Zl;Aj)5*$BV z@7VEzeNMW#vX2i-`(i&nU3N`DjTJjx_V@s8Dl8(pe?RU!pCP082Is8D+U!4E&48Fb zkzswJ!*p8+=2>YfK}q0JX%$H263c!)G`xSWceNY})nOgW!(F1fSP|-AVcGab!8#l~ zBvc{44qp$>n-^bqD^!%DlA_pi?e+x+r+r0{cu*y4RG~T?uXuGxdmm+8s1BzpUL9_p zHyvE44reP~9prZ{b`+|^g^E{)Uw?~US*Q-bRlGX*{}f)h9dasO9V-1+DX>sGT&s9> zh&(x5S*Q*-D_$M$O^Lo$s1CO)ULE>aj;md$4)-cv9Xf{wA1zdehmtycJ+(*q;>zAa zMR_7AN(E4Ra=-tJKOqO()ek-u>mV9TzqTgKwjOt!dC}VZKg|I=7L4^Q*bwQW;VTQ* z&!~vVu>Ntvslwcp2Tyx!rfUBd%+>X4H_R7Jv;2l#CS~P? zP@nz#Pon!})7LV>^^4?sLg0~)Wg!IrKMKnU7uPp%vc+}T+@ca^slnD7j)v*nJ=~XY zA->10fpI5ja{nreA$MP)Glik3@xcD1E>}AOm#g`(@vL#eKaO6Ue>fcui<6e){nB*B zeGcI-Ub}v6yuMTpa5@|ox7;`#4$CTiai2^0%eOoiw|&Z1{w7qa!BL$_Fn!1KD;p#z04EMy!m$bpo3{(VOWPr z*B^%J`Ff~2>dt_W%axd*aVwB7t%(*kcLTGfI?V5XrJ=6&>L{hPCyY8nHJ!C}6mi=?8xdvPOsflG9B5rYCZ z$WMX*L4Y7Y5FiK;1ilpnimfmB5`E!YX?s!+f&f8)AV3fx2>e?FimfkvNA!h%i!I?J z2oMAa0t5kqz_)`y*{)B0TWfvAT^l6)U+yP@4o_AG1p!_P0SMu*ek@JrJdHyz>swh$<({8aSx-&Sjq+7uUoiY~t;Eq`(G zBK+SL0wtB7(n|lOdK-TJm!>anI>P^L%@;~4KNUSak>_tqo{QU_67_B`tq(@gn@+76K)e zpVCTST)i4U7l&V(zPRZKKhgg=8NhOf!{W+?kS_g05G=ab92Qh=4*OcXp{IGahEp>} zz(US0tX<*s;Da%=l)qV~6KM5oNox+>r09FKF&y#TtoWGH8utEp zhki5C5a#VPhg!$tpx;FsFsgfomhvZtiH2T*o5SkgcN zIvqpl)LlJbn}(A9>5M)|`CW(lL90V2=vgv1(4FB9?VAQe_y|wvx^M^>{;-U8QlCYu zJZIBcZB1Z%^=oaV{OP$0a0;rUc;sRQO}52DdzUzX8V>Me^A>ur@l|@h`D^-g+mm$i z;{b3UYY$R>mjnYadcTY|+55_QM-w+1jk!x(wAw^Jk&OVYDi7&P$^H;q|GB~_Jcrh3 zZvs+&Lv=5DrBOfnP5sk!z21M)mQy03-i8VE+Kb)brOr#b($xiun89u^F~}3LPdF%~ z{Fna7p!+P}PP=V!rR(%gqTj8YMDJMA17<2>z_a-Q#gsO|FeCYAMO4@Y+MR6+DgR`@ z?eq`Udll>7&8HzJ6ecJ}!-IGC70(W8z^iNf>Dkl>m^+k$u3e|l^yvtY@=pw0ML+yu zIJj5t3Z{797(% z5B^7{BKn;k*tKz?M>MR-Y<}?qc^YXV&F8tWGWh`9^jWX68<9>+7oY z`ly4~gvJV+nGTGNcTMD2qZ_)rd%tS+z7|a8bG0n58Qnpn`%Cyp)n}SsxUXXT9aM^o z6qC}mGxN|k1l?bBjkZ}A0@lN}gIlr#>N$3%YE6n4OqJF;wf}6q$oKLA>?)g;o(e5}cd+{8mwO4_| zgj#5&_8@q;>jFLB{UCf?rJp5_(1PsSnGk&P0gMivM^}qDNvG##LP^W7x7V4m=N&^PpF*W>$m89bv^$ zcbNF$IXKPz0i7OlQ>FIv2ROSu613*!DeOBRR?fK481~$=gS9RD(ncdU(8`Y2=|&gL zn8vve(4|$n$l~=5Xg$@3=`pb?8rd~b(XpKk?6F-7`ipaw(Pk%9zt{xB%6g5M_qi8T z%7h$c<@+-FJA;K#C2Ftgaf-XDrA{K0wEUHFnld?OjL^XTe<*EQU4qrEH^6Xo2yIFq z1KpR|!kye(5dU(I>gKFWSTQ9E?j|3FjLfa*?5WxCSG0_-Y2Jb{cK-?4db*&tcGZ}7 zu>+aMDf3Z{O9^!Iu|L9^Y&S;l(l8X*ye@5#V+@WOK}=r8UetNuI#tTZli;rZ3YxEb zjAExP0P1-XWVxk4>t|biAAchh`Sqo0{EQ7a6y2G^;LYOS^d z^R4@!%i%T1Q#k=yF7FMoH-^H4n%=bA>1(t@z%)2+ti~uZ)Uy)*$^@VIb1>OK#xyx} z8jXH6R%vBXgYkP^m1%ik4QiGHabTsDi4vpdYrJfL$5w7{56qQJ!&g zWPY}m>P8!VCiK*K(NtJbNZT<0ke4b zOV~N+w(6b936<}gO|WOoO1QB22Fkb^1*;EVg?nA~n95sqvz!m4qD_kyz=)(tz|@+C zhM9Ln!O4-})lvycwtuW0yLD%HdsC*~rP*M+akQe=g~6)H$0pHjoEtIcqIRiTHExdd zQf1KB;W1ph>WvPChCpXCOVySx<_t^-M+TufDBV5@7RO(QcUle5B>i#FBl3x|q~#B8 z-->x(b*IYmnk(`cxKwF>`7K=c8iVHae6GmYn*vYT9)JxRRkQ4G^`dX5)Q6aaTo~C( zJu7X)NP6S?>Gb%x>dZQmvC0o^#-a%CR?x|BIvmQqq8i#RXlI`PM_PVJgW0z+6^+)p ztMFT_tGsHm4F+{Mp`s54!pk#f;i8E?Gw;$F=bi(Xp#%jDty;Bb5}Uk4!IeB!r+?0c z`^K-K#_9lMkue`8F;nQ+!N$xiD_yj|yCyt(QAJhK^2b=)GFyCat889`pr6LC~<#v`jm+#GwnnR=KA+pDA|9NA}>{)X=7;049(t(!eR!)(x>0S^pn+?H(UCu ztkd1-X_Z>hR{~lxPV?3x&yfdI=2`Wa-q&`6tJ7PRddOPZ?#;E`H_pl!MdDzjwO9(p#tiNV zf$i%s1LoWVmyS<%U*7Ks8MOw(&24Mpy3TV{)qM%AYiJDbO|xNmra{&^tv&SB78}5K zrW13fUm|i{{$zLD?923k`M-k8cyn}anw|fJZ~FQhW3Y>yL{~P_W^S0LA@_$q^sC{&(Z^CKX2h8x$b95U)zIUc zU~23ExIAn+8k1^CdtbT_(;W4fMcFlw(alOA;H7yI-S?fV|gf4SU-(3Oxh#vG`t>u9{Tk95k+;KtL$a!NVm^f47XcUrO&UQ0jDmcgPp+u zxU-afp3yw|*`#AIx#nI7OioiJ&L2UeC5ypS{RNmg-9)eCbHOS&5_+jMXKJ@wi)KCZ zLwadPp`_&(_KU0k{X9DSA;!-b+j=L6`^QCo$!_w$rS841Fh4%`_HT?Lq4&kYIpSh* zXW?>}o)A#vJUkHy5)cFk0t5kq06~BtKoB4Z5Cr~11WG)A7+-ikP*~gld%=5W7Uuu# z{NeY)Igwf(=>qW7l4{GXja zTq&F*nLqp;Q$isK5CjMU1Ob8oL4Y7Y5FiMAEd+|3KVS!;e_4>;iK3n_rYo%V7oAD( zp9`n^+q z2Mf>giY{YsR5;zgo<}|^`~)(OEE;2Shaf-@AP5iy2m%BFf&f8)AV3fx2$UuQr8bXT zT6jKKc$QamiF+R_obF%GBVQMO0+~k^jWM}H5FiK;1PB5I0fGQQfFM8+AP5iy{yPNn z#!wXbM=&5VKxBZ(0FePA14IUh3=kP0GC*X2$N-T6A_L!=3~;Nl+}bU-4$J=LPRS(y z2nIw3hzt-JATmH?fXD!m0U`rL28aw086Yx1WZ)Zo=n9J27n8#BlG2fbPgVcxE z>xc{x86Yx1WPr#3kpUtDLLCWts)DK!6Izi8pxqJU9@@La0n~7SC!4p>gN?7!^UYt=r`w*S zlOG3w`&fIB^1CD$fYJM9w8`FA&O4g8(P+$F+M?Aa`iX1=XjOSgUrP3e*!s^EM&UWM zMtc*G@*Apq(JPJm(QoRXrt9_oleU}^3H3Hipx0jP1}}A9(v_|*P{a&&gNZ?&kbS~I zA?3gHM+V(z`F7fEiz{8HcM|<>a!|871FIiWB?F&ZAcyRUe5Py=3F+fUD?M!?*m6m;!6g{DtOfRuk?;41pz z55vK|a#t{QbO(LMOy}FLSJAB#C)0Xo$HM6<`t%@;CeW&<4%m-w0aE_fzlOpdwyhiN z7zK43g+tWA=Sd={>j$MnvF|BJ^(j; z)~oCWX47l_&|%VF%9zypx+=Xs>fkk@vBGAi17qV|6FJuChVJg(uUfsY1(W$)Ez4_0 zchKnm54r?OS_(>jKMzg!+6*NvzspN?#wspj_r$H)bcpp4h59Zn z=1S}Wq_@5wXvp`&&^#OFP*7v&wagVQXb}!`9vy(=x9wC@l4=1;dJN+u9)UyknaC+G z5q|siJd7Ee1}%NxsIJfQQQc1(2DdHEnB&(cpyaI{ka~P9TwF{s(HWtr-!FmSrmzC% zQ!1EyJ{5hmJ5I}9JcnuRRp2n87Fwx22p;abK+ktS2p?DJXUQY9Ap3SE1fP5WqeJJ> z)gn&P>A9Iu((>!=b!IF&yP}^SOh%d7aiG4p5m?^IR<-r13)}9rgoQ63fNZuU`qgR= zZS`g*{bArd=#{IP)!=bQSaH-HCVqGhPIG@ir-$5Bsr~!`&Tfwct$BG0`_6}zGcGiS zJ@@QjZOgv2(Z~(7vg38S(M2<+aqa_jX_YRrc)bH!PxWDXOstAVc1=`tY-a;|Y}bPR z;#_64*$LGzHo>s6UL)px?gf=HAxByHzKs6PU?EhA+N*k;;;w3`lL#d(f2EwJOwJi2 zG_e04N}E=fV0G&aFdQ91o6^TX_hq(lC-)Y_zucp`IV%%ZOo@WK$wwh0b1OP~YBu~8 zEu(9iw_uFje?qpNE~u?tHRfIHK<07Ed{pC70^NMXVyUX3|mb`vhY?28WR z09;JGqk0~23vR6cpa|@|j=sG`4kayr=f2ONPS6_Fl*=-3pQZ(-&rF#fm1m*4ZXMCx zG#}OIXJ$;)3d5|yb!wwptL?yi>ptjmcn$JYPC%B+dqeDvq41!lH|=)%8to7;4UQYD zF^UZJti-=E!6*J4Om>hlO%9z#qhF0xT3OU!{9adOS{_(~8tQt`L1QM+Q6aj_TIUU_ zpeiothb<>yS4KO=Z_Y@RXWSf_pRJ|3(MF#MJ#`*A#eWZ`W^(4y>D{1HdlG7Lq%F8F zvSUhG{?KM7%>G}jQCCMBRi%B~!2RtV81&W|U7aQehoy61+{(+aG;NqN`Cd0z*VGzX z-m+qrtZR<$x*ev^&IRy2=E&?g_8pqFAPIGIxJ{dQTQJU<=g^{s06|eNpvjRS=BTNL zv%!y7Rlm4}g6Z@o%pY$f=zf!~t5S_W(EF1p=JL!mG{r`Vj(Xm^wkSWpJO+mzePJn`Mnpan{Z#Xq(Lf_wERB$?_gEm5lFf65iR?; z0EZ+SRb`H9&dS`M%<@;t6>>0BXE-b!*GOk9!>cdyzUROP) z@>bm}=L4x|)1n11B54vZwWgtA<{eRRawK@QRDzQ2A8W^M-5K8Al&N=VHrQ?)t*CWj zuxj$LNpu_MM$EaWU8+`%n#C+`z>~HI zV1q{0Ec;u%=-VmvAtoUgMz&JVO4~4!-nf1`JwC2Fv(99!@qjl~o{1)pfubOOwK^;!0=!1dq^2}MdXrj-|yL866=fGts zK|w>SR_&R@CNEKNB~R7qpL5~9@oT8DIsjQ@%!f(L6gqaWF*D0b7wzw^36EY>QI)j( zG1j)s7T?<{n-?MIr!jkAM!iLlIsYC?++UqOWunPUJJEu<{(Tlo_FtvQOI2su7@9Ie zv$vwKn8C30>31;wWHsi^mcAEYytT-4XvVyD3RID^y2g~Q5f(9SvBfEHYSdwubj_-L20b`D#o4tFgVp}hTPWIOz?7pFL zmf;=RMdS^PBumQUOWB`yD=i^n0xF&AkZu!im(4Po=_MsR)UE9I(3tCWA<2vSfDwV2I; zo6(J%=jkx-{;)0l9$X#bhqPb0p%o3!fcxV5VBX)GzW&A->>?-8m5sES8|G=q{h<&2 zYWQ#Tu@s6Kab^fIA9+$W^!O&28hZdP51Wq0q*~J6m+r$fM?Gdyb`4}S^bCD-;au8! zg*{YF%R+Y6dXOEV%UsjIHqPusu(#zY^%yiR9ieuAjz{I=*bVh@Hq z{wfK5WNkCE5ATKFs_HPI#w$?2VH#-iTQ}G~w-0>Wq>XZV>Y)*{*3cgv?U@-l15qVw zHS~L3CltP54n)~LM6WaVwB6?M6#SM&gL#kf$f8ar?GbkxUJpMHeR}~&R_uCS;{`oXdeA+(lMA^b1wuYr>PR>kD$?##bB!b0?eFl zqF3^{U=J6jC;C6p z|B3!j^nYUiC-#40|0ni;V*e-he`5b9_J3mkC-#40|1W>`f8zg1{GW;cGx7f?{{O`P zpX`4j`(OUQ?SCQu55)hO_&*c>XX5`%{GW;cGx2{W{?Ek!nfN~w|7WuQk?emY`ya{v zN3#Es?0+QtAIbhlvj36neXX5`%{GW;cGx2{W{?Fw6XL9~CIsciQ|4hz*Cg(qs^PkE2 z&*c1Pa{e make.log") # Read benchmark values -vars = ['ivar', 'rvar', 'f2d', 'f3d', 'ivar_evol', 'rvar_evol', 'v2d_evol_x', 'v2d_evol_y', 'v2d_evol_z'] +vars = ['ivar', 'rvar', 'f2d', 'f3d', 'fperp', 'fperp2', 'ivar_evol', 'rvar_evol', 'v2d_evol_x', + 'v2d_evol_y', 'v2d_evol_z', 'fperp2_evol'] -field_vars = ['f2d', 'f3d', 'v2d_evol_x', 'v2d_evol_y', 'v2d_evol_z'] # Field quantities, not scalars +field_vars = ['f2d', 'f3d', 'fperp', 'fperp2', 'v2d_evol_x', 'v2d_evol_y', 'v2d_evol_z', + 'fperp2_evol'] # Field quantities, not scalars tol = 1e-10 diff --git a/tests/integrated/test-io/test_io.cxx b/tests/integrated/test-io/test_io.cxx index 8e6fbe717b..7955ffa947 100644 --- a/tests/integrated/test-io/test_io.cxx +++ b/tests/integrated/test-io/test_io.cxx @@ -19,29 +19,40 @@ int main(int argc, char **argv) { BoutReal rvar, rvar_evol; Field2D f2d; Field3D f3d; + // fperp is at yindex_global=0. + // fperp2 is at yindex_global=11, it is included to make sure the test does not pass + // only for the special case of the FieldPerp being present on processor number 0. + FieldPerp fperp, fperp2, fperp2_evol; Vector2D v2d; Vector3D v3d; f2d = 0.0; f3d = 0.0; + fperp = 0.0; + fperp2 = 0.0; // Read data from grid file mesh->get(ivar, "ivar"); mesh->get(rvar, "rvar"); mesh->get(f2d, "f2d"); mesh->get(f3d, "f3d"); + mesh->get(fperp, "fperp"); + mesh->get(fperp2, "fperp2"); // Non-evolving variables dump.add(ivar, "ivar", false); dump.add(rvar, "rvar", false); dump.add(f2d, "f2d", false); dump.add(f3d, "f3d", false); + dump.add(fperp, "fperp", false); + dump.add(fperp2, "fperp2", false); // Evolving variables dump.add(ivar_evol, "ivar_evol", true); dump.add(rvar_evol, "rvar_evol", true); dump.add(v2d, "v2d_evol", true); dump.add(v3d, "v3d_evol", true); + dump.add(fperp2_evol, "fperp2_evol", true); int MYPE; MPI_Comm_rank(BoutComm::get(), &MYPE); @@ -51,6 +62,7 @@ int main(int argc, char **argv) { rvar_evol = rvar + 0.5 * i; v2d.x = v2d.y = v2d.z = f2d; v3d.x = v3d.y = v3d.z = f3d; + fperp2_evol = fperp2; dump.write(); } diff --git a/tests/integrated/test-io/test_io.grd.nc b/tests/integrated/test-io/test_io.grd.nc index 02f7604e9e11e6f4f0c88f0911c47bd4d4594235..fe32eec0b5c8e10ce1f1e1a15d8b6aa152520fc8 100644 GIT binary patch literal 21460 zcmeHv2|SfszyIE*RFY(Fl2nppNCVYZWK0O9(NLyJC^D2&N{Q-7gAyrZEKO2GLLy|I zXL}nqwy8mAbf1lsilQ-}PH-{eHhS_-U`#oH9vl z5{2csxhWhJzR^eWXJp(}7>`lNFd1(_KKzMqpuOIRjfci2F&fW4c{~}v)Yt=EaLk_| zH0DoYqfl8-Jm#!lDutKAP5d+0S2sN5=wyA!Wv{g}L7z_itr(3behBAkeaLyQqr)0` zPX}w4JytgMdv}whWwOg<?axAvl?IL~mdD|3QX)>uD$t4U@xL)pWfh_ z-Gzp)l~ox>OQAZF+jCPnA4gVaeJu6vghJySlg$&$5dWgnXKi3M@(XpZ8x=AjHmz@m zO%<$SzF(1r9%tB zLgR5LJKgs7*;3Rhga4#Z8@y(@w3&HUVELVaU!Je*gPBZrm`ZpHw2$ssd)TTM6J;;! z-uy<#N|yx9kyG_>-{UEgH>tqs2loulp3WrBys zap5p~E^huZcZ1k^I+jU#TsJMOf%k=>;B)0|C^;~^I_6?J9%SA;x2b}GPH(ft)iMdN z7g25d5Z;OYp^gLHE_8UV_v(38*^6}&7OhbWdr_yw-E44>iJg1gJ-PJu#31lbkPe_o^2{yg2iiX?F)y&vq8^{Zb2x zU)*KTJU0SQpI`pX6(Fr_2QP;LIU6HnB!i3 zD7mI|ZQq#^+^2c=EV^_Sw+M2>B>DR1!g$%<1M zQ4HutedbR&T8E%IOR7&n5#05uXG<3+fKTYr6ZY%b2{I#&+X`Kc=zDa!EWRf z?*CSIf)2^>ePsg51(5UDn;tOm05gj>ehl7Sj|}F^(l+iY%y8ECZ17;<+l5?{6IGoU z{%#-lg!vd3lM=*MzHNbSn7+w@j0SL9cddR?!~pk_KP&X`RM1G`-wqJqNXDv$ojH{iqUax6OIF$g2!iC6(Uo4Gn0G@VFsW zMTgVJ=ss1GGF*A+rgFEZ6juZ{e3H9Sfv>Np-THp)6&yO0H=Oop!lu{Tllq3+uyDH4 z0fRDq0(xl;;xPrzcj z+`aXgQP?%Peutw=C+v=GH(0l?5w;rozUJ=j`0LJ&|2InZuabq#|Ch-^S$Rtp4AiwZ z{C!cAZ&dD192b~Wf6pd4Y3$qoRe;+5F9USHR-zsY&@s3O{b1CQaB&He(2N>MoW zx>_EJC6x|VT)>>QXa59C0hU-kO&mW2^<|SO%SPBKe-PMNxlkxKwSE)WNeU^jJN^;V zOJgbiYQL3ScQ^corQX!B@~s&!CW$2hz^LOmL|{2U3iK?JknCBHA6Sa8C{*g0piibE zefBYI=gt{bxF{5HiZC}t_&D(fCpW1KvEC;UBsDHM7Ljmd_u=|?x)_;~XEZ65!ZoTe zs_U&YW+|*JMUmC7NcCgA&PEM=V;uv1b7S>&dK#25F7g|%xdV}s<;JM)Dr2F+F^@tS ztsxosqc46s{RRt5u2F@S%0YgS&B4QTOt~J7g z^w(|FU?pNzLY4Rnu+Ew-hI|UG?>v;#PYPSUa#3VDa6DUBn$6U4DxqnryG- zZhLE4@o^`wK+%zq?f&m=HjaNuvtb;`ziqZH@&r_bs~YqEPO~LR%rVk5HrAj-N{ywb zex^{kSV)_x>b~O=U=gVtoMUkms>jectFQ<{+C|oXg;pa=NBaNO&Nf!S^9T?+C|L2{p@On`1Zv&U(c){0>ze~0n*LawE&N8K_-FojEB+IvBe(JC$cts{A{^Pie{S{~8vyT(<4U#^ zMS1M~|LX6TyRMupC)cPIkjgP({1fap3RZhq!yn`w>h$CzYnt}yy0LUCDzye z)>cPE5bmZHk2dQKmUWVcD1*md2PTLrZ)#(VykWwQwvC@=NtImFKIOXs;(G6rz%>?^#I=j&dO@M1J3OZHn?} zDlS$k)&NJOk{-+Hw^Y2LaR67${W5phq0VxzRpYb{T2c1k$g80XL$Zk#2 z$$CxsL;hqw<2~R<{$zS`z9I7=%QK!0#g}}MB>eP$BJdM|p9uU!;3on<5%`I~PXvA< z@DqWb2>e9gCj$Qh1V&9V$*fIFER&22VGc3U(9|%}&{x+mA2Z1a5vo7SIACSzV(Dz{ z@^{NXnr?nrwa4EeHQ+zX;2$-TkOn2vQbBcj(f*&C=t!Fbsne6;f1ZhMXxw~38!yy9 zYN8vI8AIcrWuj}kWq4K7NZXLYGMliCHrqJdX4Ect@vsz5JIW5R?*A;0{i-N+>4J_p5+;!Y7KLSre&g%+{#c+yX! zPz2OW^fW1)$9}P%KsiA~3s91~SIbZWM<2r+dDSSa4FtlJ5u0Ky%9hc`iSD^Nl()pA z5T%Hh&5Xjbj|oySPxn8Cz-arECPP+}vHnQL8gJVlY&pgYq@i-0A4vP;c#D!l!ZZ>xU)@p=-KgY1T!HpI?y zryo`3Ap0ZNC|%)4-8smf$!?=)wOV-$k^j5DV=@yTl`6%;;E&6ia7jx$(e zG2!gTJj$Q%vRSP#mV`FWWu(l+_UFsi7OXe^nM;Q(7W#dUXR(fbw}r(2z8?QashH$% zvd6Qnb#Y^%M>?UI3sTvYn~mP=@4(6qah0tu8Ia@ry47PrDtz>|zrMVw6&w%dJ#J-o zf@fyMqz?_mCTvH_p2+YLcmXe7 zE%4>rcuR73H%@I&eQB%GikwTQr!0-F$BoRk5UMd9Jz2}*KV;;i`5-MIOOB3saYMG! zwKX`F$u6v5w_pIrTEU}x`c$vN8(m%{&4bYvU8mYMItGLt7{_eu5wv;ftfSstFg#V( z7;*iroueD zCbs@dE39^kDye#PLi~WdYPcJ5c%ixAg=Atg&R)B`YGNO;S^rVwx9k38_%y>fxhk3t z|1RT|X${TDs9QlD@ozzf*zFwNj74LA0OwMr42j#W>@-10As zgUP-d`x08S@nPf0dszZUvqzb>Zyifv)sz}3(Om<|ZDYolJWJ@GH`VVFt3vdrSt-6# z>R58mPxljnp9uU!;3on<5%_lqj7flURO(7r6qPtf$#SH`NBV!11pi3?=ULHA#CH{Yv2uTfv^nWh_viA4hDiyM44VjE)*Y>N4Qn&oUsV$(+m!UlT8{BHg+kVn z43o7aHD{p*Yo^ZKld|a1u@=-+EzwQ0&BEaAiFG`oB@i!K#q;|3HAMFq_4>PaA;9(H zk;fp1IEYQ761c)_keGk^#%AkU^8e4j3($<6Rrwgh{tIH4PDR z<92?roY-d_DC!gr4N+`^XD@T-hKw?N%#U&~wC}^4xt)F%W^}Zesp#nx_F-`71J5k2 zURWJH=B$6E3SuJPuPdt25Y`bsWy^zpWK>ZTHxxWX^m^Uox(X&1R4A9vk*)!Q@1X|g z#yXts*2&5|R}E|LuqV;dOuWe8xjS!VGnfMJw<|_gL2~$keIp|e33uY88boVwaQo9G zva(%J>k08sTHb(}ZZCqP?sbC_5_oUcvvkZeoxSG+vmb_Zde^S^G%SrjZQf|u1uu#G z2w^9G#LoQYIO9q)VuiH>&u%Qnjtx37E|)vu%4J`F!j(AuCu9}Zo!pMxcL%F8Cw9YW zMM};R?jF1~^xMr8x{bGUx>gmh%!j^cM&jbaM!ZOlrq7+%3tm2jk6oFi$WY(E(uKVa zvDM6M$Cg)6-4&v?<5dt&&r}XFebBq1R0P%JVp*5gv!8)N1-LaBlA_+m(T>u>USs<1Ai{Wg#&u!uR&W{#O@o zUcEPXrLJ|_ZAB>-Fa9L;RJ{}RC3Qx}E_L9B=e)0$npr5CW$M7g#=!d3+>u{1N^$&D zd}L?|1B=#oI}W+EVp6f?@O>5H5a^ER5;nVXxCbsX2#P4f_f_)du9g*GDsVKtLLE9! zZ93>2lZ0gJxViQIFCniIC0VtSiTieDhOg!8A!ZkQFG#r=nh%pQ0tx-)&Y4Bxx_c|& zeIj|gvu-CoI)$J@i-y}=L1%o^`rx0Ox=X^g8WN)7Qf7DRVRJyt^F&=WEbq(g)LYht z^q5ZmEA&=~HA|d3M;tyq+IDVTp?NzvZg%O#7Sf?E{qXP!=|1RrU%y%HM+5(7sdA-# zz3}oF*^zqr8Iqzidf13VzTR?@=V(V;AhwV}cT?}ei#JgJTB3Z?KdPEWqOvjHRD-lga7Z$VJm@XUQgm|IAG`KOo^NDJtA7_IBV0?qSz z?$_&4A&@GZl2n6%OYc&}2XZlYmi7J#!mVgCnEbqKOBJ@Pi+45KR)RPOkGkuP4BYjf z$=lh}4nyyQsjCVqp?};sT*#KdMdVV90?ZyK=mI|KHE zlfKZEbFophiRYSA5AH-9ZLTNu+>Lg^k6s_@g%K@yiMl@>afzEB?k5h@^6@>2;Y~;d zgcHQ* zBlDY4BVIlX#_fP|#H`Q%cynnV-fg^+l5>>_x@Wmv;cTKEWW%?ciob@DvPFW_`6}?& zhF5D8ltAOXzwqItK2(2U-ms78LFbv9-iGswpb>iS{LL~tV&!;*x{LDhHhCIMAEY30 zCwog}L;>7iCY=jPNJsC`_TX1r``|i#s;e`>ci-G8HBP_2+aZsrZn;j?jdIqRjCRh?irVzWAYGmLoYe!ZVBS!lLSonl)=3y=8TnL0bV-W$n%vD zhjzIY`L3%xNAbt%;4Ud+-iCoy#1Ai5HE71`K8a-ZISTfL!@SuA|W)&R>GPx3FIlT-5rqb_N`)|cmey$E(HdbbX$JNIol4NDa}=T*m4m4dA0U%2m_MprQ4;L zmGJs}Xu3nmWi*w{wvCEyf_hY!|3l)?^uzk+rCj1K5Udrsd*_~N^iY+T@2TxYhMVi{ zT;V(Lb6WXvaA6m?1LB@aM=5{z(1PVFcY0Ha!|em#rF$$n>6l(o zeS<%+8;ft22Qap`Vav449m0ftrY=n-(bA|F&HNYFeSX-Ej3DZ~)Lm7We4C~h;@bwZ z&$BMBNU4XLoAZ3((tdn8nm*yPN)NWZy?9cGs}EO}92(wxqy~Lq`;r#$GhtJZbS$u^ z0}ozl%PuC~*P10>n&#Ju3qv~FmAx47@Ls{md$AW3E_rS5o0*sy7^Ls0n29gKhnEI- z^}dUdkMKG*68|-b6BnkTXK| zv+J$tfxf}}>?dDaV4t5L)v~Px?GrcINeJ~|^Pa~CrucPXGKc#nYke9dvlZ3vy4PZN zUSYEJnp(W_3znaqSOd<-l2T7JIgRNn_gQpAR$Og@r8 z;5^Wb0>`}QfvuegoOs9W7rib}TI`RkGwXw9$G5l|1A~g*gYvbWm=z3gYb3a8~dgAuXc<@se)D^eHG>Wu< zLo;vjn)wXmM({f(u@m*R2%QynQWY6Xo*TSAQ4jWahldtk>Vw^+X<6lkZG?Q|!!e|j zf#_AgOlLD^Al_JEOWevHBo-f><#m^dQ`{%##u;Ux*#63#1y{Op)W0UzoZ5!`_S=Tf z8>&Ew{rC(--&jLDOK0{OO!s$M+RVQC_jqHHb z-quY=>l#3Dk@}dgzZ)XydJf-;Y9VxNZFjOyHSC7Nb0c0phuxh>X?k}fHa|aXGsBq3 zKkz_-%+e0*?E4aV&8`Vw`#&sG+h(~w_}n_lTjO7cTaT|KUcF62j7ZieABk2BTh2F%^UsB+YL@m? zMdFeX*WlfelT$#e(-d}_bsrhGANjcWg+pY4z{ZII#VFzGFL{w%3egR|^SDp;V_Bfz zh|e*i{ajp(<}aWj-nli9>eT`-x>LNbvny0*{vr^e%*0nei@fU6DonKE67l0FTf3vt6gTp*~+a8soYvEOm?JXUc)NVc9#kC2BQqnRMooGBf{5WPZ?|lrb zrNxwVckW-$4l8Sd(gx|R~F%9!oEJik<+0XfddyMTWGzADzbP|Inajr zlbK8W`i<8HvRc>djy?eQ>r4?KVGeUG&4W9 z4YAU6uBJ1oxcmH6T~9|pjy`$gtYOoISlerE%Xz!-YMEd;&+H0Zy)K~Zv4sJPIl-Zy zGTL$E^M%tMsx>HBvG0B$qaSK6(zoxp5q$S9f66kV-coBDJ9>zDR$;ba<8Ka+goCap{HBmz%tNO~t76mW-K9T!IrD z5xPN}XNRRD6NvGi!tmx~AVAeH!)UyAk8BdI_rL#1DC2+rX^ve9b1g`3qtGcrX`_TSA z#5F3p6`_9dcdzYehmOxe9&bTHZ)(>$dE- z+q`Z_)pB~ecGGZPPgL;y}8I)n6U^SRV8JjwYdHTk>?0YA~d+}P)O1^n{A2MooY+rGif%^q1B|>IQSY8U@ z95HA?pE<7=`WcA)WX+yXUxp%%$nfDOjTo3*;Tfb`0TZ3Yi%$CHq9wIsQrSfYTE0X# zE+p#FxVdP@=Zkb4n|#d4>rNvIqinxQJnaE<$2ozJPkktD|77U=o``q)#l4e8%(wAr zvDY1&&|E#$vzfge>7ASMlLv@-PAlZIv~V^&hbzB#nik@2uE7nv&R*!5?Vv8`Bjm-@ z{BZ71H1LMk&VS=g$IgX)0q=+E@l~&PL&nxjm`p3~qdq8rSkw_wyMw*ZRxg@xSg;sQ zZ@tfCUWmYu>FpNR$utD)ICGR^e>*~3>N$h^Xo${Upk8!?0h{pKkR~qeTIaD=sDq~) zqQ%tZa{K!6k#TkQfJZM;{^=zL-21RrUn_|mQx3g_56)m-6;@X6)h_(ri~GuL`LEVD!|THO59#cMSX**QDT_*scPn3M z^S5?lWv0LI@$D73Q(*Gd>`N1LZ)x)ude`CR$_FpHGfN=(`Q0tC<-K@k``F3;3USF= zYM_)rd?j%?63@|{7CE@IzfNSQc_%dZ`A!9S&>$h-yYhUS}2} zV1X02z}y1Z87$WKJ6wymTaDg%=jI{ch=$^p*LP6;L8E$+M<-M^CoFlP+kyejnY(PS z*5ZQk&DNo(#HC~+$~R`q((v9u>H5m$jc}D_3@ljHk5@MGu@<5|u(Ir*#>Jn3+q$=2 z{Mtn5w+ZIuN-7=j>^vK?Dxe-mo~0?gb8f;iMUf{-p|8=f>15TNQyGx5y;@#oQVW}e zFwwzT#N|u__CfAS#b}7-II=6I0V2or@8zoI;DjHSaU-EG_r+>o2b0_N{N(GKcBS;PJY z8X79&O>Hi}g2jzz$w4U*=u@3KkgZC{Q!*{V51!{Bpz_Jx8`tmS{4(JfTSA`keSdL- z!pAfmI5Xn9@p2d5dX(Iol2nGSfD7#b*NA@O<919hg$BNfBTJr@JjWy2NtZ{gU=wI*E0OoSd%4>ukxMLlM?uZf{H};77)53c(^X{G{h6x3zy1-+=zrUB556++1 uP+J74`ujuoT%Tjc;OcpjVIA0WhHY6`NIxDjD-(_VQ*qHjg}qI>75@e;kC-8fv6lS+djV?viQ^Cp=Zq{z(Y z?6;(Wl&KV=nbd8NWT<@Ue(zd$t>162wa;S8;AeQ ztB+yPJ^z;_!{{PW3vlNSk&};Q zLA19NTZ0Nn(q;}J!UtrEcf3%r5pCl(zG`pUSR_A)j zhr4`=zdNuOzP&*iVHMu2@LL%8^%{6j8$_v2e{x}h9YouHA~`3Fh!XrptfE%KwsoqY z{^mc_-QgQgQzsXsgZ=2{;&@_xk4qdQjsVdZVD;l;iAR<^B+o0M-Tk+~>yKROm1@tb z&G^i=pgq+nTS8uVvOM^N!k_l5; z9Wp0I6~rUmL1kE5NE_`(36b;NhOwC>O z1XJ!##&eHGNQyNddV*8I-Nk}bahz~|{e6^)PNus~`YkewpOf54@E`W5t8IM75h1f7@c7xFwj_yA#^qkm3dEJ8La@1 z{+F=hQ32@L{RPk5HK@|5x8%%w3-X~t4V)U?$&!K*o^Z@TsGqeUe(|t3U-l4o%h+T_qD-(`Ydefn1y_` zUer9R4eKk~F*M5%4`xRbUg=D5lRFP{Dy^Vgp@)8TUyj z{q9vMnA$mtnm%>RU4ApnRLX+|Cf4A0^D6a~dI`>xjmX=j_wYuxD2Y5fhp8~!Pcwcw z%?f}Jm4Y=4Lkg%yuRh9r+E1f9oOqmPd^Cui3{S;Ql1t{wnBaa6eJ?7K#)=oD=>V6Y z#T9Dv=XNq<$uGFi!xKaPI8F=F!ys(CF6o(`j;m`FP;};;%3JMf{cbWeEeI_aO{cVzi>FMoF>LQJn=2)b7x4itQr`d?Zs+N3lR%u{|AF>tt_HEo z2N|6o^4RR$0=4hMAvtOQ=h!|ZaWR%Wxt20W|J{^om3z^nYZRf`>M%O`UI58SEcB)Z z(K=259qPUZn=T*1iMFlOBPN#(96BQ~X*gwGS$-Njdt=d`xdP|&a-dSG+EVE>9dcFy`U@ z_?sK}*JY93<=r&cOdRr?0b8$2fr|N7p2*x$_JH3ddRl8ETahaX_8`WdO&3Aa>N5E7 z?lX3L*ikt{q!&*;ttXM^-a@E)9nC3>!DE+|DVdZDv}_go>$g`lGi4p!(Ek9u@(l%+ zYdTS%d5rTnC_&`z>7?2?585B5VPs{Bfb*9GmPMArpEm};XeRJWPRxO5)E*h z*-UEtY~bm^2Jq8+Leo~=Mkf6Q+tZ&an4;N6KD#*4CGO90LS!)s>`5biY@lHAi4X|c zmIdnK`RvwLo#3h?hxO6($!PK-+}M%?5bgxRQR1}dT0X=nQF5h!C1&Mjle7c=W_y!s zG4P{3yO=nXPS zCy7lsd>tnySwp^d3DnK32Qy7^9JZf`A>^H4iq0sgUGqa3TOEPYa|viP*29dQqOc-Q zoSu>|AX!1%c%ljkX#6&Z-eSG6*EEHM9Z4c#_S)?J$KuHE(jYBPTx7qukj&RAC=UWS z8r6b_xeoZ_OETylHUZh1TBfJamtD+V3oeUNc|vN6=ybRcH^!xs4E;u?qIm?*nI@po z{CJWOX@*bR6(HNMns#w1&?)C(>B@H~+BKJq8f^i)0tKjkrVMUbF09EjBG7za1j{zW zW31;iTs)}^$}T=Z^{#wuEm5c8!g=`p`w@!k9Z}*&8ca7If+T$cvv-Q4f#Op9#D2sQ z!$CI1Q48l4)xzY5f5G!z$#~p594EaT1edlE@U4rWUu3JnYFZZ-di}s7cY>M92g;bp z7cdsWcR{b`GW>GqJMQh;gEI$zphQ~+1Ru48)C*t1EN)dZBUfcN~0MMasr}q?d3Yf3+s&7=FSlUK|?# z(TU{TTMxDe_?6w|95Sz%A+JUY;8NahjI}Ys_)WLi5`{QW94Z?77Z#XRyH21Nw6$qX z`Y|}2yPKZ%+k#>59WX*cSuk;A?${d*$FEXNG)msSsyJeVw4W4Vbfgj?Fnk8y3%8_X zdKFFk^bS;q(`es;D%SGu8Ax3u4hF;rZM{87O@uAA?DayQf-(&Gm;zQhckzkwVyfbM zlBp_hAZ=9$8gI%Nr**oJWzb6#gmmbIKuP-fLmFOiI#gxTZNyHlzfZOv*bj=QhlqvK zZ&-4~gO+dgBGtKZz?X3X!{H&A_DNpgxW$HMNH}0EbCqZ-t|2WIgoda;rRQ6pLg>9X zruktk1UUIrh3$DuR9~uN{z*U7J5fNryB1)K@qJQX90`_FSQJ~l0`BZE0JX`M=F*D* zcYM}|RS%R&cg_h=4Bd^=H4*S8^c2LctfbkWEirvl0H_KDk&n{1N$J`Q^s;qf<_4OQ z;fNNeZUWf88bzbxT4<>grLU%SK;V0CTsE)+tcV*O9$E{F zvgZl(ymH6`v3xjlWG^lhOW>Qx# zpE4z@m*k|u$%!k*Ih)?9FAtPq-cm=?Bz0V!KUjIAQOYExTxlo2(Qwi~j;p3jFR#Qm zuh*xSw>QU?;?($RsVv5|Dki@ZlnJeN%5T&-Gm_;NtW@XURmPQuwepYyv{J`^k{dWw z9Uo_JTGF5{AFIq)$35hV^OX9+COKY)GCuf#5?`s0;@Jvx_3qSDifB;wtDZ{P%3a=W z>e@Q{`S%HY!@F1SZhk$aX|aJp(a}NiTzG6~bWm(~WQ0<2OjKxecw`9Y8_?UovvHbl zU%6B^XV!0lhI2ISzw!%bEaW{|qmgT>_0`heIA3~SUR%fbyCe--uBsDPb-d|4$2o9L zrulYucBVy~lz8@c~qe)wv4B`qCg(UQlKCfYMx7WxOO;$vAIF(UV1gQ1Cdt_FQ34&U0Y>vqofdB*`0D%`=po^#9 zYo?Dd=>yd`C?990&rxYSCOBwBP_*<;9@5LH?@&Sj0uX=z1Rwwb2tWV=5P$##AW&EY z9+&@Dv)bzUswd9>+neS8?d%q}l}`Xj=i;(X0zB*dzm&Jv)|d6=T!wY||H87}&`tkAOHafKmY;|fB*y_009U`F~sY3M>x+2tWV= zMO^^-|DwKy(LV@400Izz00bZa0SG_<0uX=zXS|ocqv?MB@{2TH&BUV7$XRsxRhljj z*5Cg>A^-CK3*|OGi~N6QKmR^~Z+Q3W-OaCu6g4(5C^|YQo(qo+jSh+pkBpF4#f^yy zjSi0t;d}#n`*$`@^X;pY{gg7Gi>an>U#09Pml31o01@#@IYush`^jaGfS%scyB>X& zvY%Y4+re3`hF1tc00Izzz*7kz|Nm5MSO@|TfB*y_009U<00Izz00baVs08vp|NlY$ z<^NM;`e%{5jfDUNAOHafSSf(~zm;I94gm;200Izz00bZa0SG_<0uU&K0(qbR zPs+di|BvzpuqFTByN92bhAYM;DBDuoQN7~+-#6}HwcfA)K3|>MRjoHmo$~Kxl3K5K z?(6;cr7;x(5P$##An;@Y$p1f?6KX*K0uX=z1Rwwb2tWV=5P$##3bR1o=l`eXU;h8B zyd`YO{}<+MiMB%k0uX=z1fEm?`Tr-CLOlpT00Izz00bZa0SG_<0uX>e;T6dH{Qr#n z%l~J}+X4Ci!n;4Bgf>C|0uX=z1Rwwb2tWV=5P$##Y!k@) z{QtcC%l|h;{@=E}0ZT&w0uX?}iz0yh|BJGv(N73K00Izz00bZa0SG_<0uXqS1@b=s z|7rf^|2=Kb|EtgcjZ$_BZ7DgX#eGDXt?h4Tv5GWfv@%y)Klga^)Oe+er(BzqTqI8vw0@ z00bZa0SFX;0P_C@fR0r{00Izz00bZa0SG_<0uX=z1oBxR@ALo5^DqA&gZzI!?><-^ z1Rwwb2ozEQ zKmY;|c!33w|9^ouKDrJ82tWV=5P$##AOHafKmYz zxT@n7F$d1cG~dq7&XkOI;;NbE*lV;69Zc_X-q*f@vA#4&l^0amJ)kt#RT(eIRWi;S z5;-z9Fg89a)HIdjT#OZ+jqjx&(+VD1UaC^u_@iAW&yinUrO8$go&Eg#1isn+T^-b%GzO78WP zYA7H80SFXX0p$OS?50J>AOHafKmY;|fB*y_009U<00LP8`IrB1kbn9At#WQxeto+9 ze-;qlKmY;|fB*!FpaAm!MR22{OAvqn1Rwwb2tWV=5P$##AOHa~0qgVs&Zg_`ot?O> z>;I*YmaqF?lYjUBIr4DcAJ6|a+te6^00bZa0SIIXApf65fj1C<00bZa0SG_<0uX=z z1Rwx`A}f&h`Twu-FaLiD`TrujqoQLFfB*y_@Jt1e|9_^O2nGQNKmY;|fB*y_009U< z00IzrE(P*F|NnLV<^S#NOvdtAfTz3uU%o%R1LrIU;j}SwOiLTDnp$s4?)9{4y=A%A zTddZrpYu5h=IdXn*6WyiJ@e%-4gm;200Iz@1d#v7egFXoKmY;|fB*y_009U<00Iyw z`T}{M|4+@o{C^GG^Z!MEi=&4SfB*y_00HFxu@6810uX=z1Rwwb2tWV=5P$##UIc-> z&;M`Bzx;n2{N=m`WM009U<00Izz00bZa0SG|Al7NOQ z#hD%@t2|Fu!?~KOYV70*rIiJpmC}6No~veBzPz>$CqIc+%T;yas*YFcJ8({>`F3`4 zKqq5;X|UG>G<1;b*vp0dTESRf8l<%^sIq%NX|Ag>UXrV1oHrzLWNct;d{n4uD#y7P zD@tvXe&iNsFE3SbH2!GEW}g>uHq|sv%amK2Ays;4ke~lsj60-E(^iz1eW*%~x4)_N zn&w_lU60l?_j*Iscvo|*1|txF00bZafoCdUDgQ5hZc2ksc<6`_H!pd__?liW>n+|u z00Izz00bZa0SG_<0uX=z1RzjI1PU+AiC8v|=s zXXpDl<@*fk`cOgu0uX=z1R%h1mh%77=cqKq1P6@>ik9C?uekm{+XC+(009U<00Izz z00bZa0SG_<0)<7O;I9AYeDdx3|L?NT2dMY|;qKx3|H875qMZ;)|4|8f7H zXK#&&5P$##AOHafKmY;|fB*y_0D*!MD8T%Gw|vY0|N3bDKf^-)U%vmp6W3FIm;k43 zljHFOk8Gw_)OwfXbv#l*nGm4Xdo}lXQEI(exz`)5)?1x>y}@d|;N0sasP(?fz1~o@ z-q_shS#rR12tWV=5O_WWkpF)^wgXxL0SG_<0uX=z1Rwwb2tWV=5Xeh`0?hxvmT&q0 ztB>aYf4h(C|MPOcLTm^?00Izrz6Fr~f4;X5S_c6LKmY;|fB*y_009U<00Izr76JvB z|M$zc{C_F=T6O8tb@l!~haMpR|19<&#DD+NG1c_#tCaoZGGeqGAR=BV z$H=8`Ke_A?(9>Ib*Q2je_LIwgzMTT3>HU1Wnc5XTIwmwKrZp#*ZrreV(|BNOsgiL} z$KB*nW!%kdzFVL=KO#ObJR%}ATB**3DD4bU+8Ls>Gpx0|hA=mI$*?wUOpAoIR>oT^ z<8DeBC@&BeC@&BeC@&BeC@)|vO%;vvO=Wkb0pW2$rnW>YsjytLfI<8f{wrqMv9Us>Zy|FXuFe#W&itFMl$_0@5uzTA%NH7buw z;G{NUfB*y_@H`11|NlH~4YUOU5P$##AOHafKmY;|fB*y_kT(Jvt_)|&Q7VZ_4d-fF zk;YD*P+D27vr?LmtM}86YKfcgJH z`Ii5m_-OwBP$hZo=K25LJ^Z{hTyajT>;PK%_B9rFhZ)NECbU=Oby%usQ0q;UpF3=+ z-dE~+e^eH*P%%}lcQ*HW2DM&h?)5CJ29qHG0SG{#hzcP8Uqm-7x&;9UKmY;|fB*y_ z009U<00IzrNT2}o|3Ued|6llM{@+mf-}Cq)Q+vMml z1Rwwb2tWV=5P$##AOHafynq4)nEwyUxBUN)kLLduS4IB+1>D`yWe7k30uWFHkpIW7 z009U<00Izz00bZa0SG_<0uU(r0tJ}=AC_$wlM=^Xv->4E)1LFWw-t=_r9rB^pvvw6rMa%kcuB63 zao&)~k+FfX@lm0ssT}8GtmtffFa5}E$zEQnQr!5X&CJg8b6hKFG6o1h00Izz00jO; zz*7ES`aG3}nBbrhLDBMi={3Dv_Itd800bZa0SG_<0uX=z1Rwwb2tc542w0#0uV%`> zm)F+G%Kuk&;;N2Ux@-A7K(mJVb{?Rje6B%0PvBZOHUwG;0SG_<0uabY0p$Pl5gV(5 z00bZa0SG_<0uX=z1Rwwb2o#V&0p9=TZTWlvCttL$^#56ZFTl|lSKBoEe1Nm*8w4De z;3BU*qk!D8S_nV@0uX>eK?+#P|4W~n(%=&wIwHi)OCB-4;`;wA3cP^;1Rwwb2tWV= z5P$##AOHaf6dC~yS6aTGj(oAa@%<~NwrlL=38j^uNcY{52K6pJmZq!u^{DD{e%)D# zD=*D)mcJjsMJeY4)X=6y^5lGgXZHC3PPq?}+P>aB{Jf;^M0};RTiaXhv05W%nX1+s zo_jsPPF_xXHurk2YP_w=0y$TgH72O_>~owx$(pae>8jSNk$b&XYP}=5uUCzW5&{r_ z00auRz!T;F+jwPl68Zlu3cP^;1Rwwb2tWV=5P$##AOHaf6dHj?^Z)Yway0U7{EcS^ z00Iyw;sTcP|I+8CG?=dc?-?2$C68vk9>Q|~vMlfh0uX=z1Rwwb2tWV=5P$## zAn?2k6kPtF8<%hS|CmSf|6kQa{{MO3H_<)_KmY;|$U6b#|MSikks$y92tWV=5P$## zAOHafKmY>Ii@@Wa|Eu0L=7BQU8?T@@T}SVv-U~=;>PpsqeeC5g4mcUV7a$Gxc6L$C zKmY;|fB*y_009U<00Iywc!5Xn|C96izv}h> z>V5y!=K!nU2QZ(m-e12}9XZ)=@%g`5=LfVV1be$;+|2Cr15#LNReAP(0n>8gslbS@$eIX<>w(6;|{6M2VR)9Nn|jySNU5X#_wX(Fq>gE z`kNXrCHHt4O1)NJ=U&e&{Bt*&SNm1Zx>oO33FiuEzfym9p1X~M20`Ej6|j{5&vE~M zH?OQO0H~i0mgcL!uOr3rkFfI{r|jqo?p$zS~?G)&R5R|46bKwp3=ckuDGcw(tU#-J|AET{jBdF zWI7*kL~gaz^Zas&s&BQ6)0_fwk#awe=CPmc{_@1nlYZphu zBERRjhkt+7zgf>s=g<%cJf{Lrl>cw@nEd}k^VQ$I9Qpr;=Bo_I|Em%xApijgKmY;| zfB*y_009U<00Mb0pyA5M`7|Ywrr~nG{$I^9n&1tl}w_0-kw5OV&Q@Zl#a{{!c zImYY%4ax(7)qKAcQVsjepBGTd7+iZv4sX^(Q+x0N0SG_<0uU(50+#as(&wWz_=Ja! z2_CM~rTT>q0Ue5JPdGzdfrA_fd!lOfjrC5RSCXL6%ldkI3D)FRCn=Qv1 z^F;BaOTyK7(zS`%@oev}boL-Sp6&gW6fMWIzQ5Af1hV7V-e1WwJD%AM8k@oevJ`CQ{!-`@&3;@Q4^E9Qu2dw(nC8qfOvR?ZR6_WoAM5zqGi zR?Rh@_5GFZm6pB#+1_6lV?1kz$L0S$y{1q&Y>l7Cn9TXOtbpl^KpI{zOK5{UA|IjR+{1rEjGmoc^TZ*T~QA@Rb>h}@U z<<<5{f8(XWQap9Kc|7&|kmm8EzoF8gE@$3f>2IPmn8#C3rZy{a-3-MlhOuU8`;x)1m z&-F3!8e53h#6rBLkBQgJLcHb{;S%}xh!gTk?#A|C|xpo$& zzxD?X^ue*iiUbQg&wa3KswXj?d3)7X!+#z*CsS{8_00Izz z00baVXapX2zm@F#gzfng>Hlt)<5{0Sk^aw@9nbdsiS&QP?0B~KSNgxD<#^WjSNcC` zc0AkrEB#+KJD%yT^z zt^a+Ka;wkMQ_9H}CQm6>Y`Oo|drG-w%kiFU|CG|2>fbLZC!L@Bmym1wt@n^}b% z7N%+HbZMScSN)NuOFz=RC5jtM=|}pUmrAvc6wBWDliQ#xnJDBoKj*vz)2YW_%k80G z%XJgvpK#&N#19@5!!VxXq#tQ{Ykt(_)Y6(|rMgeMoVDvgee1SsetSLbexNR=me#gg zT}~|vYI$qdi~7&^{%q~`DcJq5#ribzIzL5h-s=r=?o&;7Ol&J`daDE$)|SqoUb`rmjgYU0N)4CRD!c0*XyAITJXr8~dP`d&rgzR47@!5zCtb+X>e(xDZf0dc8ul4&!%(?0`KCzuv_`CXE*6-eGecOLN zHhzxe&0xGv)LUcxv{vsArIxN1R=4jZha7WCDr0hvB*!d_KmY;|fB*y_P(%c*Jzltl z2iWKy5eY*PIM34F_cIn3ccL?YrQ~R-@^zqT!eBZHac=P(v z%XjGL-IC-M7fPN7t9g9)OG$eFjdpabO?w*lO&lK=-+**YZ}Y*^X7cMAo#)N#dk4aB`Fo;G^eT)8FQk;M3A4giS)%NoMira1 zr@c-?`5^;0@v|GgLG5dgrxF{+(gokrbf(h$jt=gnXw?2u{FE*4k$L@rCEC(P{|mad zQ~$@epOd278=k~pJ=B{2BytKLI5&`PEQsI_-5E?VcNl-Je^WBAUux)eUDDP?y7wBt z&7W-HLtS_+t@Vqd>g|is=hJTRUu)my6NY(EwO^uXaM#*oUjIag!#Zxu8`P+-Km9ZQ zG#{N_gNivu)2Sslbq@|yBi|V-JTCWrjV9D-l2?=zgA|CNES zb+!uiST{^p{OvRR`!7|ZP60pZ22P*C57Snnn!o6H^ZF}yj-*D%8qtuEO=w~{Pik8t zkbWN>NI(6$nooawnJ(#mGGA-_K$`z+dH%l>R`BNa`4$&RH^kBK&zFf}@7C@#<>-f` zAGMU-cyN)gntYZ%&>f;%Gg`C7zOMXdle$yFz@EacHlMKn)M?AkH7+mA@NXozbo!Y6 zFglu@JX=cG?2$oVEtt#ub+s2yE%}m?8ttMxH7Bs($eQHU{Tu54{{LuG@mXwJqiOmn zLNXurpuUi*naz*9lEQvX^`{FJylF;BEz^a?>wT7YC*8n{{5a<{)@Q{ev26Rp^j1|* zVM6>I#x1KyE&EI+Tifqd?Q44VCs%f<`Av^KlPBm#eP2!(7jvA|ahuON?Tsa`p1#7m zluuaA1B-O}`#q@H;8dFMVL#q;#YX;Ev9XlCs=KgqD`O4T_=*qaPb2q^ndHA{I~zK} zhs{h#r=_bLh2*dr;9}3G-=m!+X?r=1jfI*!%j5oxZ1+PTSL_3h8X(JAd$T`^pHmw!hSx z$+T;CXFjdFKdsvnK`9=W=zoTIG5OC@{9mr$^AWWN3L!%;u>*Ck>3hYM5Hd%+B2;R3 zNndV3>b8$&)TH~H@6nL+v)JVGJ85SKkuH8QeO@M&?Y~)>dO4R9r=DLy^|sv8efx7; zy7ftY+N0M~|E3~ydG}K?IBuuwM=I0K`XS6m)0DqK)97^1sZ?jyLe}oeAc{HPf!+9` zwBYXaG7J16fkuaZ$@>JZriqj74Gpd((km4^kge@sH>#o#c&sUV-($IWGim`%@#)5Q z>wG~>OFE+))b$L%{(2@APxfSy!PRNL>pptWFpYX~DQrylArujKoK^%+rQso&V&^8| ze5X0{XqPySN^~8@Ui)nu|8n_>bfANaFfVc@+nng4({1OdYP)8_`GHr&MHR2=D_`6o zHi?U(;KnH|RNqJZB4sYkuUbz?F58@qc#z80L=z3%>Lw&zUnaI&XU_sZoXKBs$fQ({ z{w&hxU5ZFLMz*&9;K?A0P0||DPxK|j_W5L2Ybo7~Eye;?Y||xXLLth0K7sjM*W?oYd>Sz7ZjQ=B{ zp1}1!C)T*?Kyl$oG-WI=lq(g%m-Tklt-o&I<2Jeq3)Yo4T&Z_X3~o`4Y;Au`VoRDn z_;a@4KLd5{L*l7+l_XjkeUN>Ya#1&SZ4zy{+<`8n|IT8Qy*)B6UZP6%j*(cqC3BqV zOtF#O$YFp+=r?>e`(Wd0e$vUqG^JMw;X=hIwyW+Mc6`_dzR`(^RKnBIu>89=9v%A~ zq;hvZpf@wzSjMR}y1jp;>JC;~M$uK5vF=fO#iRkn1c#otsmxaaEPCN&e&paGdcQKK zsN<|1?Dn?OjJ>^y=IzL!gUQ3#8(;JkS8$if*7mPxoJmc))MdiUYenZx%PD&B?^I@T z6{bo1h-!J=+hkHD`+prybKWYMn4fv7HgkKeJwRRD&Z$Bb>w+s*l-P_83y>wRhk>@QE zhBpvW9h$L#0so;Yor&6P_%H4FeIlFOA&mXD;1G38Xhm~o-}flr><)iqkPBby_1zTy zp}SafotDNa+u``Zdatnt26?q3kAUbdllvO;CyRLC{f@p~P+ zzHJWeIJurmy~D93ua{)41KdU3b)xU;cje!n{$oe4ZslmWQ!8QLFC7fq&ib=&&VE4p zVI_ph-Z8Af#x897(VevTU`b)#EiIcjX@eM3&-gbeG?voWwr7Le4WPY0wkKQLe?8Ju z=-nrrCGNf`x^KB8&ivV4*ciN8cf0KCx=EKlCie~{gmnX}h*xeU@$YOtOzCGj3P=C` zN8hWKAAjDvE$7AJu=wY_wu1A93c|Oy`?DE`b?meKdQtrN4y{UhkM$Yc znl@#gr^ZK03RgzoVWV3l@a2Zzq(;-~3)4Fi^FP{{%@%zqa$r+o+T}>`{a5blYk4H` zW!|kUoWEb3+H@<$(keEgpM4U^-|-OpP2)LaYx`fmy@#4#OJW~HP7;qE@}aY- z{i##pBJrir^Wu@=seEXgTNL$m8XNa&65BZ|m{!GoPMbWE*w0gM@J-_CvT6GbjV z9>WYa_r#w%=Qxe9aHof`x}S0X)1A^aqJwlwH;mE@AF&g2I67S2QJD4Mzr^=pVyU)U z#cBsXBk#-0`36TXv)OjZx-!A`!usaJs8KT=|6r9D6?0fgnLS| z<;C+A=jmU|jN$7=R2DWljAwV&hqF;{`qQ$Bb%inQ=8ClfNtcOUz(`WN(iyf>w~^`+VI zpR#K=E{O9FyhmZbtR9`uubmss)V?`hMZ8ivUu=hMe^zo3A)+tj1U7`88< z5&QezNGccqHH~;LRj*BJO71s~Z=3HroBZ#7&Vp|Cr@weVH7Cr|NlYz3-j!pn;`%J2ta`2EaeY5>0#neFbK)H=MSBg7|0(!0Vb+I z00Izz00bZa0SG|gc^5GIJ^;QyfbS2yNZ%hY|2_=%f9(I*|MC4Xe1Gi4`2N`Qet3rV zK>z{}fB*y_009U<00Izz00bZa0SG_<0uXpw0b8#hP1uF&N1xUn%RvAF5P$##AOHaf zK%meG;QCSAfBFT!|1_>2#r@Y` zXmeUD;r^qz|0wQ1iu;e^{-e16Xc0KNLl+Lu{v3Ne&prniMj!wI2tWV=5P$##AOHaf6dD1(#YNH$ zaWwq%Wun--wL48Y`XT8@EoCno&~AbYby&pXJ?2H}E1q z&N+?sSusg0+x{@URn=3N5I=`;%j!|fK9kAT_Ip+PnqK|Mm0fCn(__!%3A$0=mlMXt z9A|ah=Ce+FW67(hudpuV6IS!UBAxzz4{A0zl_q@HkM~@$kv~>!ETymNF09Y;G9<`l0Q|~hNzP@6o@9Cw}_Oz)& zI-B^;AAH=tGJ>t`FSTYe?b_X$PwVba>-I!YipM4TpCMjM{<9SSm+SX@MD2k>$k0pd zK%Hy)UU4Oa%n`2$mD*j>ms^m!?V}kr>Hg+>H01m&Hu?Nc+8IKmi(gEimq}&&Z&s#W z&gI0Z=T}g@E%$Wa{@j*seNvzH==IdUsmNU3{ge!j+v)m|%Cxh72=mc2xI4Yf0)I%L(V<`RK7p%g;$(Y6gKLTOO2rOjYx~!Yswe~= zYs%jDST5d-T0m2Ly7ApQUl7xh&gcepJ;SfRo=L@%Jy~RMb(-(Gj~+Bkqh4GJ8`FIV zMFbwF6~R+!cu1z$xk)(RY0f;_C61#KU5ByPe%r>sTz(=Q=-?vEi=4?eC%Wi#+c~P* zu99L<6_F2}#$N ziS5?ev%n8$@)sO3Db=Gti}ZPyB9e}gt?fT}GKgZ6w1)H(eaWzWKH1e;N;hMRv49oZ zbcy5diu>!d73wWNt~VskPa3mNWHS;)mT{F=SHZ=F zF=?Bb*VKdhS-&*n|467OaJ|ooHLf~PTzC>q8OsahN=5Kxy$6L z>YWpVTT~-k+aHtIlBN&-oGtjzK%M)Lc&c3`iIzqmWS^y6)Qw%6L|ZO*pbP20v)E*B zkBp0#s8YRSB-U=p9A`RHY-Bfb7@!gQ4WG?E*tnXXbn-Aw=~Y6wP%(<_s=J0AAGU#S zbYdcv@N_gR|E`Tk$9@N?+}#i8%?vk|acYfj?_a69gO!$1bk$|7d(>VrX+SZ-q33NX z^Hl(gUO1T_Ie3WPugodxIBN&Hy{$B3Z*QV`J2L2C@-X(s7d^!l+-0)0{VN)0QqwMV zneg&j(RtHyiXQwsm6=?HY0^Go-wH?gjIO6?Nwa-y9PW4|ppL>&`a(VW@$ zJ<2z`!yg&s!q<9zH-&%bF4kP9rLhx}cw5`=opFHD=5OOYFW03{Un@=3-s~pSHqAk#*Up_chxR8h=73uIU8F_p2F}eREihTPf21wt^75WD;}#f>`yk z4aJicDhsDVuCb2a>)7>eb7;rO^;GH|jxBk;Bx@buF6yomeOJFL|Mv7BJ9>31N5h?3 z3HyHOVAyunpM7)o1JVyGAyoE`VGTBRVbhQ9q{RnI3iEDh*}O>`#F%=UMrRnmK`&*0XyDf2uvK2lP+GWrf1-6DZ6H~c0wnpR(!-jSI9(Z+1H=tGeM zn+nq|M~d&ia#vr=BZ)8bZe`*8{o>T7TPc=Su?hX`lSuxKhu9z2cJON&&mmje|MKlU z)cjf!`yg_Xc=V7DolWgeoe~#`FNK~Lj|@-cL)+YfV-YT9&I0-Ryn(p1G&lU$QC_>MdM_>3X0 zl(1>Nm>PGFpF908ewu4Ct#z!x*82@L9&;5VTid^+XGP&__gn1F53}iw+QHAr`|@(W!O_cXwq3HWOt8JMzWFd})J(@eSmi~<99B|h zkJp9m#olI#2P?7n*3F}kmpTYvo~*=bT@Pa!?^YMK-`+tLY7`g!ntiY9!t}J;b2|T5 z)2-~wFF)kJ&>tgP+dpVj8uf6R#1?P$V5tH3X<^xG^k$8ry8eIf=Y2|*pzal8sYU!s zR=1WfCANB7KYwXop@C<4@qER3`qwgJ_<9kQg-s6Q*`4*_Y}A|nv}|HsVNAQZVy~gi z#WM~g=>A3rVbq>AY}~d9qFafz^pkfTVcMZxtm#|7i!LP+>AkW|ggG^Kh*y^nV5dEA z(ruSE!s63gSnYbf`RW<(kYnG~G}U7@t8zA;=3iV)$=)+*VVANj&1af^mxqCDZNII@ z&p7_a@js6Lar}?te;ohg_#emrIR3}+KaT%#{Ez%U^8d*HBma;5Kl1;`|0Dm8{6F&l z$p1fo`Ts(5p%NMj0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOL|vDA1>ux3`AVa1YD|ZnSls>AAdkjs;38W2KeSSt*N| zmC7gz2tWV=5P$##AOHafKmY;|C?o=Sj`Y{`>QAohQuCW0dnQlNjrzWvFfQgetK&AG zb=n(CUOjzeHES~jps|;uWD% zyG#0V3sSdzG@~Zn-+Ygd|405G`G4g9k^e{jANhae|B?SMJo*1Za+wmE2>}Q|00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwx` zLMhOvm$$cu({K;W25z)<-I>?KF~8zB+%t~bx1q2`f0SG_<0uX=z1Rwwb z2ow?lJVy@Ck;8N3nzHvjmWwx|7SI%*ZhW`S7sRxrGrB=t&+zN7XHxNGPZk+mo#wml zqX!Mss27*Q#&jP-5rM~PMetM_9)jn{;W=`6jvSsNhv&%QIdXW89G)Xrc%CDN<9{6g za_t$AF)LVXBZ%CZWf9&6fzMWB1nCqF& zW*k^4mPzhR%{R=YmZuN3$MHXo|8e|}<9{6guN8aTJj|&HQGgYYEEFm zku}My`#048{r}OX;Q5Icc+-rMTBZw&*ZVB* zPP%~?`Ekx^tj~%`V%heG>8+}s!i4xaj9XTZTK1Vtw*LRcs~V2~ar}?te;of0)VU9d zr`lDLXle98_F2kB-PpBBwB>RKx{&@mi%s_S$hdfkD%CqiV(pg9ai%lHMs_2I0UDv- z@Y(ExjX3_t@js6Lar}?te;of8p5y;Qa+wmE2>}Q|00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## rAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwx`LMiZnwU7fm literal 180800 zcmeI52VB+0AHc&D6p^JOSc?jZiWL_w$ejzpmgQ)1u@wQ?k-Ar@MfsDLq}691twmq4{=(N{V|NODAyOum)9FKpl@G> z(PpIbrBKYqSgQ+LuA+dp5H`xhxWgC1Mpw}gSAQWsS~6^k7#H>3+X@>i#CR$aH$?rA zBq5$5#xuGL2P7Sbs11RV2srfZDLeI4tXGT}>V>~w15}t=l{L6>5$l19Sd&#$1c4}) zk{Pwi`pwJqw3y0kiC@fQYYj$ACRbHem1WVYEQjAvQ}Gh3lvu%K+6-e*sn0LG&ZY9A zp*oC%7_ZG3Ri^m_PYCx6pByq$CS{mLm5Th8%l~9McqKotqFMR#5{eYlt$FcVF9V%j z`tVH7h&iL}sxBf{ForQ(RJERDO-R$K^~}WNSpI;jSh|X7(aow*s!XyJlfBHU)^in; zGc2ms`@5;{zh3z%yDbRKH5L;Ghu-i}_))$Z5Zz)-k_?H_Fjg zpf5O3Z`xT$fxeCcd0ho^T?O)b3gja0H|*C}pl_f+ZYatn9s)Pda3cl!^%dwhP@vyX zfn2;;->|=t0(}z&`!yBi(s{NI7&+FjLm#HG0{JHjk#gXZ=MPd_MRA1E>Q~2cQmoe0AVY|CxaBPYAsKex0#O z@7EFf9;6n;KRM_sMDL$Rh|+loeJ(YXN4U~?@O~@9)Knf3O6MW;A=FeJ)0ECb=u4}q zJffA(L+FF~XFR0wDDL7tS4--+665lLmnbl9C7<$oyhPG-d|fUddmsud`^%@i9yjJ6 zVk?)zuY^$1+Dz1YARUkb#WGRe^>YOZZz+EN|CeSdy{BWR>t;@emw96=9gQ ztWSY2Uf74w$M9-gO&o`?~6O)&r6y$`TK={$t7pYMln!l0s zxx{Gr9()-S&Re))%XiosqW00e*l5C8(zCh%8&sOT2S-c8_l_Rsqf%9ZYy z3-98;ogb<^9*p>k|L;w`vUB;a+k5#jdQy9@@C|~R%0pf0JcJ7Qc07dV6fGt}yfCa2 zWT#ExYK5qW6BVk+5-g<)ZD`ecSlaK%s`VVC{f??y&sx;e^Q~IXRn%KCx@tY?yJTj5 zRqHA5I@3~my%Ki#cJ=D7c)Y{*fD9Mm)F`bzK=@|K+wpkY=U5%_EK9Wx`j;dU5CQ=p z00e*l5cuyBc+-Cp{EhcNKCYAGc}Omr4D!2vj(c@{obatTxrTeWQ~NLSkUlx5G#zWNcg64 z)&9`G$RkkMJU*4}u*UKTQZ^5>n$06r**u#54IV;2m?q;c_6yO!c#R}P)GM4M9*u$^ zLezT@p+G?tdx?6R1FF`G7WMQNR;?$^pL1qn)q3wb^sRr7e)_3e-Hzz>FJp^v!^{Bb3~77zdeKmZ7Qd;|i*M}~Qa2LwwGol`vvPw%iW@5#(ir=IS7e5jM7Ozt;@k1h~y$M4_wG?RUkNljH< zZ>wMu|H%u!SiQ=hg#Vp?KmOHu6Rd>&%GNcAhwDYbE~WEm`wEZW`;i>8X@xh|GVkc(!BdR|N95+Di$fB+C+pxx`^Z1;lm&Y$;z(L>Sp)6bEf z?UzKqc!1r!JY5>sY$-Z}TabFAI^Y&61t{)^)u>@(ZSu)4MpRzke9SU7zT_NdImVjn zv@`}yx1GgaHJ?MG!gO=Se_3Sv*usT8|EX23q1`!hKE060>$kkL3!R;}8|_(z*b9$R z$o>O6bDf8~q2B!;pbpzF*}0=qZu!w0dEAJKT>Zm@X(~lXsg#nc7c|L*2>wou4G$}IY$~&yt&ANI>cFX3;Xbk1*qe~G}af@ zXIj7*Zd0pfSYE&GHy3g@{k)H}IAzaHn>T=c)|5qwOWWldZ17=s zw^@mfJh{bf8aEobt{TlfZt_X4y#Cn%?nL`+5$gNfShPNTD6&NC)59-?oGojA+47ieq##QJrTA;+UZ^*ckSoq8s;n{HR)021N`A&Q z?J$C{I+2{b{<_TTXw}F;X!2}JGGcQN)*{A+*c|%-Mb^HL{F+TCCnoLT63jQFJx|kU zq0a)l0~5pOa8#c}@_nEgfzuMn551fs^oUe~pd#ypw zPb@)QQsz?4LQ{0Fl@(R{LX~D0ueGyUauv(KI33(&=x zDfr+t73%WRmCoN?mll3nNh`aqdwo|uhbWw#H-SV3|4!GP3 z8_iwIJ*&7$aw|rYI!=ys+umY?o;JoB26L!+WIy`i#AMv8y9eI>V>H=irbSzhGoTsT z*Aa<4NTU1Z^oYOdj2D`gq2M8=XzHX5^bR$_jiLw%^DAUSz3by5OMSYfw<*_hY8hKy z`?>M;xHWfT=&u@v^vDPooN5ul&8U-!o+sT$yL2kp;BSk`z#k&1by|CpFgO+`s+=S~ z@%K?IYma?zGPIZWRO0kF26^4;$vvod4iy-NqBZ@0;(Qjl(z3bVBEvSD(Z)`WT+X(Y z?9fHoB&5e;v_0Jvo9}ZX8Es8S*odR#h~Z0=k-UZ+ncz-0jtL}Q0UCDm9hM{YU+$7M z`$wSGqlQq!F5l9b{yWi8tpx0_tTQ&h^_08kuY;>=|H(`a?Ox|WjXPUnKZAqpk2~_w zFf=z8J>8FXSoh(Mr)bfliqDW$N;1x#K7g)WGK7vV=!R=)ZbN%f57Hym3#H%FqZ(QU z`0GRa5gO78`Pg?N3lnUpR`e?NGSdu?Z@eC-e4fY^{d|RH?+r&Uopy32B?&b4yW{Bj z7ArEvW-NMiupJ$3I)YWdaF3k)MvdBP>)>5pwseTiZ{+Dbb87Ky#tBed;2_OoaQ zWOuVXXKDHzQeFE`M5|-9;ZNw|z~MM}+-iI^_Bq?&pcy$~=*|We48->rC6FsQ?P7-AZYnbNYl0)p!`T=ePnu-=&~{4RKFSu^;$8)Lc#zFd_H1e)%Bhuv zM{i$G&A*?;&bX+HZ?){homl)ocEb@B{5&|GUiQ$T)^XeLj;FD>y7t#uxSx6)DJQLc z8{m>N8*`txGhnyJ=aWYz=D2Hw5%qE&g)e)oCwSvf8XDCGZ%tfFADQ_O?X3B@z%d5d ztJK3AW7c3Rqiw8j@)_E2Y;7F$vK4+bc|9pL4W)Z`bjJogR{ZQ$Sg~VofKH0x@ zF?Z#5H+ok$o{RAzsB};Y4b#7c*#1AFG?j+9!JWEz`Itw<=Y=LQ=p8|i87@HM_jM(% z*K1LWuQs9X53Sh*t0T70Hf53O+P^2#h1=C80B?2FCwCX0A`4B8aL~66Y1uU!+H&1Y zs(U8{v05u}ryq=Ill!@JP})MGn=~7THra+shP2?kbI+k0FZAj6mow<@ z6&rBeJp6_tk_E+UR^sZ~ zAJu3)M*VM~3B|qXZ^7N^{1O9t{_`}PxO6odm4)c4*$gg>9z&Vifwp5K3%H!UM``0{ z#oSl@rr>kaEHUl9Hn-WtuW`anQ(RVYfgIaDo3n4)p3eE?5gOHO50^J4kw#Em?3{*i z#KsY{L0exOy?Ov{oaId$N6jLp@fqYu;8)01TN|By9D(z-PmsO~+mWRC4(CjQ7+m^rD_)&47%l4?NRm2VLs3gQl9oSvV24yY zx+$e8iksw4t_{0^3_bGbqb@_~-7^|k!`GVibXq`e1{$)TIYyI|TcP-Lun#`!?@Kfe zjwKWCRIoP-!btt0gGf?JB3;H!!&W!8a93@&a(2dQRHa$vbBAp>aXZzBJ}7ER9s1{^ zB&(_T!sHNCUHgX(ScGin^unjUHo>zdl#w;M3&```>vQWIYKo^gX4+YeJV{)+`t-0{ z6lv>RPI@8(oVY6jEit#D8f~07%d7-4Uz;QMhQ|^6-e<_K5B2G!l3M7v<}f_u#u(Dw z>KOlEgD(WSkT0KPQs48f(4*KHsL{G8GWxfTIhn?KxVSJbXYTX@V%{b_cUE&mu4gYr zJMOV;+r+^%X^SOxJ5)$cwH-r8?dyQ*4NF1{vS(i|YeBqko8ju(Z{+kCH!*KXb#_J5 z6&kk4qn#e|ICFs5x@+T82FuZw^9AT?X+L6o*ozF!xNUcI&}e*YvMa$od(y%!EvVmD zwsiAIbzD4VDjB1(8c#VALGDj-CO`JwiFK!}K;hozbcdEMeU=}9UC&J;7dD+@Ee@=v zms@F4T=%H0z7>PFmyAWF@pnf00e*l5C8&yi$Hb9k0unoz8e@n`Z^DY0RbQY z1b_e#00KY&2mpcq5&;-L1mlN3=J7*N|Dpav{fF;w!S}a5&hKyimwY)m79aowfB+Bx z0zd!=00AHX1b_e#00KY&2mk>f00e-*s|0G$d||1wiPRWI>GOqs_6m^dj;Afu5hwf- z%Y^Z?ufT;(AOHk_01yBIKmZ5;0U+=nBLL$GVLTy>Cxr2YFrM(^98U=Mf4KjD%=iEQ zm^%lD0|bBo5C8%|00;m9AOHk_01yBIKmZ5;0U!VbfB+Eqoq!6XDI3PBB@P2sVH{*> zD(ZqjP1Mv8Lp?E67sCp1QIxL67|Y7nH~W+k@|ZCVwU~xcVtx%qOO~#xrYhT^7Goxh ztEp;~wGm8^A73jg#-K7Ezwj!T%8Q2TNOo5a$2F=<^9i01?ioHgWTZ@sVH#B`^0xCo zq1Zq2^D5evKQBSVw5!}!IIcE=*Z%tp?k?<2%JEm@YbCCdK7>F32mk>f00e*l5C8%| z00;m9An;)jSeJPntr|H9O`dH@Mr`iETEy58n`1wq$lCXjU$g1t#H2l3g862&=V=-( z^jTncU}6{@j_Olqi?4I%*r?I)hsW8n*s)x512-Jyb_L>(K2>i+B_VRcZ&?)XGaZwzJ#ua z4<-*DhmqJjm+hMUtVNvM_U9fh?}es>%pupZ)9n_0{e(2`SNpr>fwS?K^Y!s+uQllT zi6y8@%3P{hXo~K&vZ88VsM74>wRToZuA=!@Hqqn7X=u`pyQuf{#dJz@9a?^B0lGLd z1s|NILS0_E()qjV(!x(mNoY_qs;>Qq996MS=K%cEg#K)~ks0+Tw>dx8)?@>dmaF|R zAlFY_8}B~dn3}h)PwanLj6Jev&TYhuL0he20 zqq%FjXB9U|ZpCO)$H|dy+gps#)5ciCU=B5p>_=amn2eis_rTkKj3&Fxv}nt51~fza zIwFw=Np#F@eM@K*Mgn!*Znl%U!Z& z{|MB2)DUXeptA^6fIg*@fos8NygdJ2hg=khS2c^-Eb|N3iM_?vazdgtnc>eirS3 z>~5ClEKQ$7s%!s=XmzYM{0UtgI2;F$TaB;AK4%*oG$SVr-Pxdmf%yKS1ac*(JM5+ z&|p&7y*quJp+d*iO-06jO>l&HI2)tmNt0|J+D^&aN7*7<+^ZlD53(7`o=q)8Ikl4T z=*$#?%1Hm3id#NazB?2N?S;DlV;=4CfiWSkQSVG?m2Yhg+BfMat7VK zVgru5XMkJ#&pPSf3Io6|XayWq6sNZjV;9&Y8Su{3MyIZ{Xxaf6-P$>WO#G=I4X z<%X>#*Hj&7aP3SsudE~9V|fPU7SE@?5#8vXPyFyV=MdL!x*Iy%#fiFHvY>d)N?cw0 zqZ*CJsQ(Q#p}05wEx0?KUt&Pdf1ZXDm##*mvJhQ0o56+AV<>Yw&~|KO0hhD)C~f?# znER^V6nt))C8oXC<~E!7HBPu`ipwf4kYn3tbM{T!(>b3!LZh1P;qt~L(g>=HozpOm z*f@eVXzPokR}a9Av%G2Js9D4`K7$+y{0g~hYooJ|BXGX<3DS3AJF?Wq5pP`elAGYa zjAU8)leux}=+wsERNr{Rxa)jCw<2kFTzj8*6_K;_n9B^0N;haejgG(Q7#j8^Wqh);qNmA!)C~8SZ((-2y?2u|l zH>EU1ag*H1wP81qp+_El)MY5Wdqx9m_*%1`P7BD*KtuL3$7qsrD-@p&_Q6N}eTl}w zv1H<%3if6}7^y#W5J^f&q|3Nz*y_d>?yBup&dykksx&jA18u{J+o?wMK~Yoc&_5p~ zSxvLxt_fg z?YPIXZ4(F6q%D@%?NA{()piUWwXXxJH!KM;$ew+#mJY87xOz&KIDorTvKUVJ|W?`4o^w4i=p z+0xA;)p7Bdsbq}CYCPpg1i3%Snf%yyC)S;^0)=~<(;Zs6^jUrYc0D(ZT-bDqwK%Yv zUT&pHaowY~`c@3yUNRPy#@|IP@1&Ei6+fY4o%0Y`x{KTQmq*-8+>@l zbfn|V(ySZ{8gCbXu$3FBuKm^ZpTYkJ{~!E+@c+U82mc@ZfAIgo{|Emc{D1KOq5U7) z|DpXK+W(>bAKL$+{U6%@q5U7)|DpZA=C%KS7^9THN+19PfB+Bx0zd!=00AHX1b_e# z00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5;0U!VbfB+Bx0zd!=00AHX1b_e# z00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5;0U!VbfB+Bx0zd!=00AHX1b_e# z00KY&2mk>f@L>{AVKf<)O4GIYRpp|>I0&J-AW)OV7)D17^~6wJ3@gM%QMwvqEGu8% z>{CX_W5zVpVj4z?`860VS-Ps4s%(c^jF~L1rmEq-Q!t@+r7B-MziYk-SuqBc`S^ub zxl~>>R7bL#sm&NwruhU<2=@%195Pa-#W0O375M`ApHS={`FR!X%Ac1YVyr8-2My@k zSEW)@IzB06B6#h;zodRA>`ltS9}K@J;w5nvv|tScfB+Bx0zd!=00AHX1b_e#00JKh z0hnJqi543!;`FxGr#(yp(EVQN^kPskF*jUHyt&TwlW!7fa_LMoP2HF3K3c|(OPhy7 z@@|pg`|PN}&zI2kaF|~k=GTV#wPAj3m|q*_*M|AEVSa6xUmNDvhWWK&er=dv8|K%B z`L$twZJ1vh=GTV#wPAj3m|q*_*RFZf00e*l5C8%|00;m9AOHk_01yBIKmZ5;0U!Vb zfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5;0U!Vb zfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ7Qhy+v^ zEk=bmT(;r^2iak$s0#u$@t}0XP)`ii#jrwL6s4;%#JZ4NoEv8|Vm|sKO zzp9$5Y=>HmnM_|zRimtjs!XYN<(e;^-!)%^tQdpJeEh;^x>Q~?R8N-7FlXA!#Eh#D zRIV+5-}*Zn1D##^s4yA~6%Le36TC$&==!QvwGH( zSiA6BXwbnt>^|Ze$}9=RPbOU^Cf~=?79sh$d4V19iAZ%j-G&(`yVnf#qQ4qyJ+U_F zW^{l|h@6EgmKCAhdium!EtIrAbP=UDe@0@n@`~-AXjqQ(|q6aXm`JXWbnxX61JfMNjC37GGDI3J3HP+ zF7w*qEPe3*!T$&UAN+st|H1$NaQy!dWtf00e*l5C8%|00;m9AOHk_01yBIKmZ5; z0U!VbfB+Bx0zd!=00AHX1b_e#00KY&2mk>f00e*l5C8%|00;m9AOHk_01yBIKmZ5; M0U!VbK12fl2Od~JUH||9 diff --git a/tests/integrated/test-io_hdf5/generate.py b/tests/integrated/test-io_hdf5/generate.py new file mode 100644 index 0000000000..ea8e6478a8 --- /dev/null +++ b/tests/integrated/test-io_hdf5/generate.py @@ -0,0 +1,31 @@ +# Create an input file for testing + +from h5py import File +import numpy +from sys import exit + +# number of components +nx = 12 +ny = 12 +nz = 5 + +ivar = 1 +rvar = numpy.pi +f2d = numpy.random.rand(nx, ny) +fperp = numpy.random.rand(nx, nz) +fperp2 = numpy.random.rand(nx, nz) +f3d = numpy.random.rand(nx, ny, nz) + +with File('test_io.grd.hdf5', 'w') as f: + f['nx'] = nx + f['ny'] = nx + f['ivar'] = ivar + f['rvar'] = rvar + + f['f2d'] = f2d + f['fperp'] = fperp + f['fperp2'] = fperp2 + f['fperp2'].attrs['yindex_global'] = 11 + f['f3d'] = f3d + +exit(0) diff --git a/tests/integrated/test-io_hdf5/runtest b/tests/integrated/test-io_hdf5/runtest index c6789d7248..c7fe2aa11d 100755 --- a/tests/integrated/test-io_hdf5/runtest +++ b/tests/integrated/test-io_hdf5/runtest @@ -19,9 +19,11 @@ shell_safe("make > make.log") # Read benchmark values -vars = ['ivar', 'rvar', 'f2d', 'f3d', 'ivar_evol', 'rvar_evol', 'v2d_evol_x', 'v2d_evol_y', 'v2d_evol_z'] +vars = ['ivar', 'rvar', 'f2d', 'f3d', 'fperp', 'fperp2', 'ivar_evol', 'rvar_evol', + 'v2d_evol_x', 'v2d_evol_y', 'v2d_evol_z', 'fperp2_evol'] -field_vars = ['f2d', 'f3d', 'v2d_evol_x', 'v2d_evol_y', 'v2d_evol_z'] # Field quantities, not scalars +field_vars = ['f2d', 'f3d', 'fperp', 'fperp2', 'v2d_evol_x', 'v2d_evol_y', 'v2d_evol_z', + 'fperp2_evol'] # Field quantities, not scalars tol = 1e-10 diff --git a/tests/integrated/test-io_hdf5/test_io.cxx b/tests/integrated/test-io_hdf5/test_io.cxx index 8e6fbe717b..7955ffa947 100644 --- a/tests/integrated/test-io_hdf5/test_io.cxx +++ b/tests/integrated/test-io_hdf5/test_io.cxx @@ -19,29 +19,40 @@ int main(int argc, char **argv) { BoutReal rvar, rvar_evol; Field2D f2d; Field3D f3d; + // fperp is at yindex_global=0. + // fperp2 is at yindex_global=11, it is included to make sure the test does not pass + // only for the special case of the FieldPerp being present on processor number 0. + FieldPerp fperp, fperp2, fperp2_evol; Vector2D v2d; Vector3D v3d; f2d = 0.0; f3d = 0.0; + fperp = 0.0; + fperp2 = 0.0; // Read data from grid file mesh->get(ivar, "ivar"); mesh->get(rvar, "rvar"); mesh->get(f2d, "f2d"); mesh->get(f3d, "f3d"); + mesh->get(fperp, "fperp"); + mesh->get(fperp2, "fperp2"); // Non-evolving variables dump.add(ivar, "ivar", false); dump.add(rvar, "rvar", false); dump.add(f2d, "f2d", false); dump.add(f3d, "f3d", false); + dump.add(fperp, "fperp", false); + dump.add(fperp2, "fperp2", false); // Evolving variables dump.add(ivar_evol, "ivar_evol", true); dump.add(rvar_evol, "rvar_evol", true); dump.add(v2d, "v2d_evol", true); dump.add(v3d, "v3d_evol", true); + dump.add(fperp2_evol, "fperp2_evol", true); int MYPE; MPI_Comm_rank(BoutComm::get(), &MYPE); @@ -51,6 +62,7 @@ int main(int argc, char **argv) { rvar_evol = rvar + 0.5 * i; v2d.x = v2d.y = v2d.z = f2d; v3d.x = v3d.y = v3d.z = f3d; + fperp2_evol = fperp2; dump.write(); } diff --git a/tests/integrated/test-io_hdf5/test_io.grd.hdf5 b/tests/integrated/test-io_hdf5/test_io.grd.hdf5 index d0be83eecb05febbb9c990651e828818d88dcb2a..fd29cfdd9682b347341ff311502161b10c10b342 100644 GIT binary patch literal 12480 zcmeHt2{e^&yZ1IEWeBN|M59!S22%N{kR}--l_F&b8B)?LNt7f-QlSu)Q05^KLT0vk z+8cYax4kuJpmd&!Z=LnN-}^u3JL|0PJMVYS-fKPAJzUST?)&##_w`)Y@4f>JboIq1 z%S|Tz`Uwk@1W6LVi{qD{W50sse_F=t!qKPD6S{}lL0zy2hW%vihR*z^BZ zZUSq2ao+K9UGH&>W6=K*tyvrb0bQ>r8*&3{AnMzjEL8aS{o{H9 zggyT%OAyU}dUSsGPatZ)+WGnUf2#_QtpEW&>pyB^+P{^Fi_}>Cm$KLNGD{LEc)aVs zlr%Nmsrw59<*`w@N&fZlbjG@)rTm2aTrNZ4YeeMN+%qhYLD%aG%ND@eFQ;K~mr$@9jP4 zJFiO{dfSA``^MjFyt_dy4j6c$*awqh#htHhTF`U;0g2DC2XZ2BXKz2&2a1w~LzinX z3g*>2#eT{HYhjGz&b=IXP7$ou^26OoI&()LRl{F#rpm-~`qzX6pt1!T+njmAJ%t5sBA>Eg4MTnR!An$ae z5&9o1y;&Vyn0#}#-?yeZ9Axgo+awNj0urp4vX{`>I?2dl9~GmUG-uSlqhn*+fa;kA z42WKiQmbmJMpRyWvFeRJOs9A!+t2TY(C)8?D%I-o$yC2|sILRzqVk)9c4gsWY+Y;o zPAU|2+v2CsZ$th1<&sgm}gRg#5)h? zOit=Ri=W`iI>&TmH17y_Qc(-lh)G|A&vDRlZOH@Xvw9raddOH{HW#mN2CF?TV8g@r z)KE|z2f;p~3G2xPxbNv3tUF3U^bXcG)8<5+*SQ%>naf5^p)R|>s2^^}l-?_wr(=%5 zUy+0hS z13%A{%KpHH@beF^4>VLkW$!Any|Xzu?@(rM__Gj%j|Fdxe6KWvhzGbzP8Qe)XOn zTLlf7izK7#3<#L}3~$`W#q*rmqN3%!VET8O@IB9m%v?lasnS zM)T+}XvjGmx2OgdhCR3UEzH5|@K@i_+>hl8ue$m=R-ud*AwP9`3;gf8-aFLM1Eaiw zoN}}0=+Owxj^5FMkxzRUr}*|D!OBlU_*xDgd)c&$OsRX_00YhHxZY$o1P!&MJl4K}R))LU-V`!MHtZ7)&EjH-c5cJGkv=>W zAa9e@>Vc&(Z}2kp9hin&^EJCtvF=IA-Y+CNrfc3Yvw7JFqo)dNr&1P_7SBGbmchfY z;SJaD+6G8WIlH4X`zh`>QkTfbw8MUTSNXSGHWuw$^)5<`hC?@kQnUqm2+I)HpApjo zt2V(^RQUm@mK{*x9q5KdGFMp7ih<=Hn)s&PXo6S8P~@r-9>SeSWPguN{4l(iLwD;# z*?Qw6YT0FQ(3l+8wyh2^JURLfTOJJ9M*bd!#rPDmkXsVe0O!mc#f9_BkW`+dTwc(I zf-g}q4$d%D+UGU4&bcjtsp z9LT=HgZO&`h}z83_E)1~!-r+5(MRmYm(!xRDFH5kK1- zwcXfpc;3?LmwlL^uw{3BEe(O2v$d_N=&%tk4ZB^(#y{N$^Z&B}|J!k$%kB9Q_@$vmh6G`K7(m#>{L>~DohWbCp%X~xcKaK}U?9W6g<00wq>i>H@CjNfEe=fiHhX1{N zjL-i+4-f0Hl=-jm5G8369O18Vi4(ReOgeSM<*==nmA$j8%|U0P{cm}Yad1WcfK6Qg z%;$eq|Bb@m+s7XUfKTAhlgH;jF8>ynzit1I+l!9epP_nB|JOtQdwa3?*WLe9{vQPX zTO&~1I9*|4NCOnDH9ol%-a~A7`jL4uWf<)j@{4lr#C>m7$&ru6a5P@3`furEyX4scTWi-4ZMx z+(9*)6o;<*&gs29WTd8+%ZcYxF;DW;`%@J~C^&G1tFn^<-*>XI+6ybN?&-QE>6{`M zW$Cqw6urW$!t7VB8U1+lE%mzziw8p``4cjqTM;Z#aIbiI1`;PfDCKny;QFhK!&kUm ztZp~&-u<1(v-$2G_wpoTly|g!aeW{3U9R?A;_pV_laEsbzmxGrW^ix#Qx=9>#dsn| zyP+8zQF9@t6b05N+h!^ULwajI^G7HZUyDrA7M)0eulncYvy$CNc(`5hcvva~CeJu5 zxSEKcL-~u}wNoIyHdH|*x)v$6hJ3;&xtL&*H7{d54Rs~0a#?09NQW-nU3;ql4}x}A zn+!5hTL^M{YBmCB6q^2A7IZ_OHtkpKLyNlOp_~pTHm=DsIbPoiQh|wwyJi=-g0f<# z?V90MW_;*LVKYd{Mo%qe+mSHxC33@#T#QaxS(K_ffShELgNbQ8gjAVNKIOoMPEurp z9bYrHeicnK+th&9BczGu$uv|w-M!Z9JO^6^_F7zz?uX#!_hmxE1n$`?s!k_cL5-Vz zxoD^#QY*epvYbpo7$4)P-N{;5UzgBO+7^u@>j2$p_sA$RoT^tA-iLxUX_-T7tC90e zug$}+7wgP!Qr9o&zMO$mP` zq#v7ITO9fh&O`k615cZ9HmRa!wYDkAbMR$mB&jrTCy}cPsoj zkymdEdT&4BIlRNgOzw+DL8h@gEIFNnM;E`oA@Ar#q{eKicF`WNr-w84XmP>K|1{#Y ztQI8kj75WYVsMwbHSSs=1rsZ}H`HIJ<5iB7(zj{`Uh!NKMe}KB-c-IcX(k2BKRq-! zRPqMWd&Km15c&1@ra&)|jvCxP-{+ulzYwA1DUWV?G9b~Hy;o~83#t~AE*$jhM)0QM zOEYH;!0o_{a(8+f4oV&jE$?JNRY>YkyJsB~rOC3cfn~@Gy2Q96R)hrU`awoZI&{C- z$}!{nFcj*uA$71H>Edm!due?Lw?4alR%JhK-F`IVa1;&sk3+0WI~sAt(CFNB24Sa} ziU&p?vS4?dbjE95E!-F__fqzhLxk^J_R+gEST4~$sPLl&wfEO+g*B()GM}Mji8c-1 zi61XzB(ULaeb`x*FCQ-k_x`NtWuZa1OZw7#HVOk`bwm&ML2&WTBj;YfL*Mj5^?NJX zuokXY6J>_MXt-@2PSjx;?O90fBn}R}S?rue@HB_p7eos_qJsRIEURK$fnnOrICuzq}4UvaaimV%(~!`ZqOtw@m{*nQ|)7D}6flc_|W zJe)Lfj%`mfthc2LA4&*@7b!*{M~jC70dCd-fjnph7Im=5p>{|-w9jvn(Lfj`d zVO}r!eA>KH2$^JVx8Fp8z!8bN*GBswb9b@)n)xsBnrmBCdyU{DhRdo0j?y4;Rc#$j zv=jZl=eG`-bYP=J-QfF$1JKevabw^P2Q!{Ozi33`;qszeUyf)nQN~#JN|xYzwC`;G z@wTNO8-X|@if_bLx+Zu;F2u1l^ z)AZ=VQt{ƴ?J#QGetRi6rGo@RIUn-nm!cfT~VDuMpvXHFg^WLzj;v}T7nk+)k` zA3XG+87}2DPT>pb5Ej2s&dz^>EC-E?8D|Qxks@vIgw}xDYx%S&(oBr*V4OK#N5j`N z36e#03i7qYAF6$1;L8bW2jc_{`)${}%zL`(K;r;fy6>dXlLlZAwrc-pBPO!UH_tK>NWs^H;;XzjrI0x!7(_i> zj)m`)^J_Nr!jDvMT*jebFnM=Rw?;b#clfLbQ!Iwm^N;U^%{n3eDYJ-wq!VxKJj-Wj zvf-7v?&JBEM(89mUb%PopsOH2{%LDFR+?65JmA%!s$I=BeKG?MXJ*;D>6F8Zk@{m~ zh>4L!azgc8RJ7#Wh;{$xk7d7eTJ*vwgf!H~KHkI%_c0fEzy2uXbm0aduOhoaNgNi1Y?C zLfd)}vDBkTNUIHvA3mvyU1lO>#wYWA1V8mANc4)r{0?X&&GcwGMThm&%+;(lkysvO zv#>^*4NGro(lEh`B}yNbak^FjZAtZ&7JKV4%=QhdeclJliNy=H=vU*_5kUr0N%^<oY0ztU+w2>4 zFMkQr8OO=~q%g#Wtgw5URS9L~Bkwp@(oj)wD07_%8*S9Lf=Xpv9ATP;x9RoaeuHDl z#vfHUzn!BZLHMHxkJZ&e_TBK}Pp+8pvmPSm&s>aG(P2gJs#3b!i^bgZ!KDY7px&c7 zIM&c1HgaUo;=(?V_}4D_y7DdZ1owZqvbPEb2PU}O*jR>E*1j`U#Qwwnwwm{IS28iV zYQR+8rv=RNxl_93xrnY*HN03_fm<4zrgS#xaoVb?I{z>^=4b@f1%?Czp?(@&s=c)kFLG*lkm$Mr+J2M z&IL(=cb~)Oji(`Aw^g1Gz}w%ZxY>jWdWO$Ob@?V3ZOfZ}PCo;N^hiImclGe*FYB!& zdx3lS+oqYHdf=p1I%(oy51g0BB{F==(XnOTnX=)x5V>IIvtD!nSsw?N_l=Zb-_8p6 zeez6VeoGcCWA&i+)=qx)ne}Ljh+W$2-;7E|UddctD%dwqmSqs}OI_Ug>~qBaLr}*K zt)t)C5PUpQHS#zem5(O`EL+fpr;gqW)=sBmdD=yODe_Y^4d*o<<*<>Tl<657NQTbJ z8IO$ho1haB+Lw2|o8bHBQdapD;(qU)32BD45KW3~7wj6q-t?WXC4yQ&U$MGtMo<@| zxi>#)cojf2P(i`>S~X&MPrj9JD2K`I+8Fzcc34l^v#5426}8Euk)z^Ib`e(7vZ)OI8TW%ef+tR z*mp^ATH^Jbf;CRQ#b2fAD89d0_WNiltfST@Zr<98aB4}Rg?A3Tt}S2Ku&NlXLnfEy z)Ov7R%hvj%NF6@P-79|HN`aulYI)J0MUcp}mdV~*joyLEDn1_?n!X5qsYz)^NK%ro zvLzG#;x2Ugcq$$_v1ZJtwqwfCp^*6mkG?##rS#*iMhNFV^U=-7#yYDldsZozq3w3S zaZ61mW*Dv`=Mvf%?QHp%+q^D;3M|Jwf|lR4_$9F zHdJ}GV#=4%oR5q(R#Blp!k1bsAb=avwD`kN`!l-dpNC>4{;V0UnpDl^`YxftA1 zm0lT9hy|-B)$FQmM?tIdFem;7=3Z#)l8o*_qC0*1LiaAL%d;3+oy0@mkHFmTO8tnJ z5ML{<%SMUW2A2DLCMaQ!M)tGQp`DfLDM7^Bj#2T-daliwZr#~+HjS_+?cKMxmUD1- ztGnqmZZC|a79H7esu8AXu9q1^e0IvKL4J5M4bh#WS8Mk_LUiO!_m~Ay2s#q0uae)0 z0#bmgZ2A-EkUYLmJQN9w%bPXUv1*{{yR&4s6%FzaYbq{p>H(8gNVzmxg+cMeZzUFa zxLIHsexZ&6qh$Ur`?*~>Z)yIXtlfj)#do%!v?un3tXF49KkEWHG4^uUhiW`aioY6X zLhQE|+RNLO6hdlGf|`9Q9o0+fZ$9R)g|F~+)%u^6kT(*qQ1EGmV#I98Xj>}gL>`dg zi)_Q&zPSZT_dAf{`qRCLTL-PyNAZJ%|Lh;ysJb(@4JkD3#hw$`;3Vg*P8jAQyPbA> z?*ld#gkP+3s9<2_o`HdI{aSpUZL9iGfD4K93?q(46&&X5c1b1n!@3M)`rB_e!g5aT z%qqJI99d%+b2*raAmLN%XT4-1^3ar!l%O6AN2afyZQO;yh58HZKExpBeT&J5=q?C{ zNhZ8*N`q9R*TZGYT98uv(|tYh9b6)9DaKmbf{rx7s-lWgNR)i9mNv=+Y0&)Ci>XWD zreEmBdyoik(~sNsth|UY8Jl&BQ#ja{bFSs~6CRSQsL^6pTW&xY_5ElP)*IH$>A;?}<+gIfe!bi^k0&WF z8nEuBebA5FoiHDjSCQV<2$$iq>`0MLcs~wP(_9vggy$`a5gN^i91gLkOzgz-XrD~i z(^S+Sq(-TmvJmZ^(&2x;hFE7RD_VX&#$k)a_A5;r!8~U!D^^p8ez7?l-$~V>e7|49 zNG=a-0hY}ps{zzlYF=6Pl!I?U0yf-SF0O8o{Z3oMgSfNtvl5{$te%tFeK@!S$M2j` z&2g`S9c3hSCbFLNLCh`4=H_?7UL-2Yv z%lU+VH!$IwQ$CGG?B^M^+#~FOWWCLjv2q1erd~T#MA%~ijqG{VHw_~8Dn3cNObo`@ zy65P=hL7Cm;=9^(#Dz;T#82|D-_{@?_B9(et33Tp){(L6+u}G9;qM2NR3^I{cM|I* zV_n=XZ+worF110W7b^Bwg3MF9(BJo?1_Zxinj0tz(T!?mG&d67CiRzQxvT3MCK%A%MCSbILO(h2B!2OS;_MN-JaM#&SL8<5GX)G zn}FZ}f=8HnGr(DCHx1{suk;TPd87Evx)tn63>19L+`-9C@t9c)7Rg09rVWx?6DP~y8{I_+VsqZAQ;tdUB2B2))!qc1)u z=2t>BX6e?Ho+en6zMG{Fhl2iXa#WQ=udI)P-#m&alDz()aRuFa=o*8!^?(99-HOn!{&ELE_?x ztrjOs@qX+1zG!kUaw?nLsN0*NxsCE={`_`m_P>~#ZrO&ME#;5N3ibHPNg3ULo&mST z#>XP$%dnN!!BRTb4E2So&AS?iypYAOemXS?2}>209*NF@a%)7L#j}^toKS3dV*3E9 z7ufFblj(+{PmykbEejU+5)YqVLaakywu_Z&6%&;Ih zo*pfCPj@3j@%%8Sydf6CRz(iRpUSaOK3_=MqZXEdgCqJqM83S`cF05d7wF$Aut#Vb zaV|w&U3H>E9iorMC{OFl1k*XmXH!Wd-fWrWuD-DrQu41PW3F~WUO{do6zb+q5HYu_7?a8fsx&^K+rQ#laLL%G1iL9=Y)d=X!2 zeQACVjy{VIOEsiIrpYWfWSD}xHP>Q3RP`by@%hbyBRM#%+~sM%lZCGe)25XVXCPeM ze@DvJ3~UfEy-}i01#P3dO_e+a!`59rzT{SDI=JqicRvRf7qIx(bbPpE3JClZvy0bviwrSj5_y~$w+RZ$XdIV>r z+^Q~&hq_W$)n^qd9#l?c&m;0+_^r6Qua*l=b+PyI~98*LUHiA8a6OS|njYazimJ>8t>SIoepkh%WdgrCzt z*r9Az+loPwK)R9g3&eIm%VXOPpmJb=wBE-uc*hOJtzSu;zo}oc=dK|O{zltZ*Y8RN zNsi+cJoy+dHu*7sL^H5tcicwEsV&lhKSJt#f zF1}0LtrY662T%P;`YGaER?FJw){Vzr!Tzk_OY%W3l&?%VUAQ+3(O>7@l0Fjyol6<3 zhm^=*^<^DTn#jV+rFTQ)!zr6K{lQ(PbAq_68@`n`2>b(78DNX^i(&oKylR? zblw#X@y9HwxcOu_yWF3lJHkTkgKg>cdYzDo7ie?d*9w{SSI=De#>T`ti@vWd1RvI& z#;13UhL_KEKT4i%K--s-^B%;uqxeCux=$1pT#b1G4F@`LPQ)hLxUdJQn}>r{9?)Ra z8hND8uoGXcWGebi3UFZ5fzK?o1s??;D43pRprT61Ibxs>^ye=`?jGuc!n&femQE?*tZulsm#EIasR`YHy}9CdsRq*@@{FjeR9 WqkM!JxqAe8wSyY<)}6GTgMR_LTMi-s literal 7888 zcmeHM2{hIF_CFlzm@+pR!lmdYp(LE|J}9?b$!RJB!A|WFpq}zmapXdN1!s`FASR;jUdEx%Q zx0~xUV+O0wa&Z4aDqO~zBsRe54hp`~|EUVhoMGwEpRlViYf~XTE5w=bk+sZt=_huX z(E#=K9ng4h8lY=8EMD8sEf>;3+-eM{Kbu8ZLq6emVCqNcfM*f*z)ET1ia{#=yXW7_ z*?pbRzfxXfOkc0{4-M7`4r@ffC!WO;XK_C1MMXtFIp7HG*&>TL113Bvq3I{0&}ZL2 z`i^ew+;ES zorX}IuJUEO!S~4#)i2xq)!NT-H4ur&z_GIiaq~y?pT|+U;y^CEzw4aOapd(^r~JkJ zKCj0Bay~Ud-%55L;`({HKJh@{0|@-%erZ)6aQJs=vOdo<`ipV>rl`>P)rC+>cRk|3MI(Zj@$11%>o)(cyR_vw<0fTN82-&Pdi&i&Vyx9>- zR*AkOXLWS2P+uSUmQCDSIpMhb)HU3k8%QTEu%PnihYNbH?L)pzGD!)32$pUh;KHsT z7i%YAQj`q(>{?Az{tS1Mm^l2b`qz_!1nW)fUJhS^G8XlO) zvk{l%z5Ue$EuHsJ_sNIhS*aAAvn~-&Tzf~x>YJmso*^d1t%mP)6%p5ZkO0FgIR3l4 z_{O9H{S(?N$dMg*nSYP$io1hWOK0NxO+Ul3{0ul}Q;D?sI6d{$4K|z!!p5d;Bs8rC zd+d~Ogi|6(V0WT%MikD`G!%@bA^1!tl+H4~Pw#aufr4u*;i>&Z(Db+sk9R9m%V+6C zt?W7Rxa0yo1=GmcXc1n5aU|F)Ek-xpWw0u_9n6wOqm$zkP^m0qj8^UhV~bIgCm{}x z>*UEt^%FW4jt3b@yuFjj|uXC@U1BvNz$F<2&FcZs*cD2qd6pGQ0@9rVS!WtWJ~#>?c0C6X1t+0yT(sT0p7>v8)pAsCic zK=oIILE7ktM6qfPjvFI}YB$c5XW>>-<&{QF$2!2lqMfj&RuY0nc9GFjtWc+g(rnY+ z*u5?cIa0aI6+DRZH45o|cTEU1Jxiba55YNF9dy%SaZvcE$8B(}$M9#>@McF6T(ujA zR?)Gfq(P2n_H!C|m1OH3vFHW*TajT(QYW_MlYf1 zU4hK*I#a=((sGNK_7*(C^~apN{ZJ}Z4th+lg`-p=F3$JDXxVVIAKO99wMW1cJVt-L znwCRfi4QGw^PgAvRsjB`w(iEq`yxq= zMkqud&7q?XZ^PVSgw8IZaR2=e%)I1GdZlwdHOlvb7H2ELb*=#_&!2#!*F-{|NhL|W zdIOTnBT?chTW~zG1Ore11`alDL`!lQG)g*=?o-+DMlcJM{Zs|&Iv2t6NDwtNU4kaE z#<1hcVOn}`CU416Ht+GqcjQEXE4=aF$@P)l0-D7iX#E&>un@=0ra@J3E!$ zP2*xp=R>ARYq-G0?G?G>F^v{Q4#Cuifh3UWAR#-a3bK}mKt4wUTJA4ncv_H3!O#Yy?jOVTO13!V7kjiG>4{~XIS`#rE!LT3 z5w+9RwBBDEdjrsbI)CEy~hqgs6-bhJLdI zyfwPap7y+lHysPO&i=^&YxkkDTqcb_p~>6wqJ^FktD}i}!^p|a@r+I4P%PHXhuSeU zz|k^?p$^^ngoI$P-f)562{q8OlR=3)%7Td|mq2V)26FOdL4m?&UNXoaJ@sYWc(Z*NH^CUqBjbtUjaIDm%Lb}* zi|!vz;mP;YVf-yITx#4)6btNO)a^=e%W?;D+mtDMrX`4*KLbX3#$d^?sd)2X3FP0> zK#k%?%o7QxTRwb1ryr4~o|3>Wi_t&~5`nX7EKFB2#23sX-8^r}20 zt-b@{-rMoryB|>}k>htvUJd(kKVnUPsX7MI8O{LJr|?v;%f& zTRFGrTT;+_pRCC{1je>8cxF)?#wr#wgc97F3$+>K>rm(yHj1+&!?=Z!dLx z7KWn~BXE4rP(gSfMlVafMF)i)v?rpdLUh*+k|3qWRSypYtMCh0F`CdPFH>o1w<=U@ z?4arAtr*Uf6!0O2;OT9Lb`e#?tKEv06!>8Bix51oXAM(LZsIOq6 z^yj&7+YPfoj}=cP0}s&D=db9mE(g%K&9>rVtvs_~<1*5a=@`0dKaf}Im_(k*X#(Igrpi)slo+zMt*6-UFB=fFx{4Pc72g~6+peK?p6J9FB| znouQ(sFKFrp^u>a`&h7gl}!T{rC|_D70yb(AQ^Ly6E{0AGz%Qhb=+G-WUmF_p@Ny* z`6=U|O~aE6si`Er_wAs%$QZ?H8lZXPed_%z5LUjKf$qc_=5}?{Z?mUBj@Lv%zW5cg zZc93xcfX9{#l6JqW;i^ESwSmL55*$YGibh#PwxE~0l)DpF-)f(FMk{ZMv;5KDPuNd z#PC7gWFeedJe&)Ya%rA#ZdOkrOfFh3L$KpZ4d&(FRYj6CVN9iPbcI zjXpG=w1%cU36!&#hw=}cxDn@u3ASs+K^<=_$}ThFjTLEu?Kk)^LRA9Q-YN;41KlA1 zVmIinm_#SX1%aPM2x-<1!+^EJD%Q=rZShKH4tC$sV-&fUv3`FmYOjbVkqkz!9u%Uw~2mRjw3%u;L$?b7i8+3UN=@pdsN2x>&V z#fgL;FdZk~Ji@dt7f{RkXk23%gs%_!f&b)jFyUKUqzOqR`=mLx@3Th!`RBy(XQYqb zA7E7a`s_^jH@p*X1M%HRZ}4xCLi-^H$V(kc@G%0_C2Woqc;(5uoLd&^b_6q;NvwjY>TEQ9R0+QB36%Rt7xZc#%;Akx_J^a?F+K?6!W)^<%@5&y&>?Io6o=HGhcFGYo`_BM5b#b_ za7Z~6Vw2xcO{0ZKr2Xl-*driw-jxjAAN=e8+z4?oA3Fr#>f8wwFClM From 63c5256c26cf96d0b86468349f39b97527fd6b2a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 29 Apr 2019 19:31:24 +0100 Subject: [PATCH 1361/1783] Make restart.redistribute work for FieldPerps Notes: - Update MXSUB, MYSUB in restart.redistribute. Previously kept old values of MXSUB and MYSUB, this caused problems in using 'collect' to get the data, instead of the previous reading direct from 'DataFile's. Using collect is simpler though, and should be more robust. The new approach means MXSUB and MYSUB are consistent with the processor layout of the restart files. - When writing a null FieldPerp (because the processor being written for does not contain the yindex_global of the FieldPerp), make sure mesh->YLOCAL(yindex_global) is always negative so that the FieldPerp is always recognized as invalid. --- tools/pylib/boutdata/restart.py | 83 +++++++++++---------------------- 1 file changed, 26 insertions(+), 57 deletions(-) diff --git a/tools/pylib/boutdata/restart.py b/tools/pylib/boutdata/restart.py index b1bf1fbd44..89cd37c39d 100644 --- a/tools/pylib/boutdata/restart.py +++ b/tools/pylib/boutdata/restart.py @@ -15,6 +15,7 @@ import os import glob +from boutdata.collect import collect, create_cache from boututils.datafile import DataFile from boututils.boutarray import BoutArray from boutdata.processor_rearrange import get_processor_layout, create_processor_layout @@ -587,66 +588,22 @@ def redistribute(npes, path="data", nxpe=None, output=".", informat=None, outfor nype = new_processor_layout.nype mxsub = new_processor_layout.mxsub mysub = new_processor_layout.mysub + mzsub = new_processor_layout.mz outfile_list = [] for i in range(npes): outpath = os.path.join(output, "BOUT.restart."+str(i)+"."+outformat) outfile_list.append(DataFile(outpath, write=True, create=True)) - infile_list = [] - for i in range(old_npes): - inpath = os.path.join(path, "BOUT.restart."+str(i)+"."+outformat) - infile_list.append(DataFile(inpath)) + + DataFileCache = create_cache(path, "BOUT.restart") for v in var_list: - ndims = f.ndims(v) + dimensions = f.dimensions(v) + ndims = len(dimensions) # collect data - if ndims == 0: - # scalar - data = f.read(v) - elif ndims == 2: - data = np.zeros((nx+2*mxg, ny+2*myg)) - for i in range(old_npes): - ix = i % old_nxpe - iy = int(i/old_nxpe) - ixstart = mxg - if ix == 0: - ixstart = 0 - ixend = -mxg - if ix == old_nxpe-1: - ixend = 0 - iystart = myg - if iy == 0: - iystart = 0 - iyend = -myg - if iy == old_nype-1: - iyend = 0 - data[ix*old_mxsub+ixstart:(ix+1)*old_mxsub+2*mxg+ixend, - iy*old_mysub+iystart:(iy+1)*old_mysub+2*myg+iyend] = infile_list[i].read(v)[ixstart:old_mxsub+2*mxg+ixend, iystart:old_mysub+2*myg+iyend] - data = BoutArray(data, attributes=infile_list[0].attributes(v)) - elif ndims == 3: - data = np.zeros((nx+2*mxg, ny+2*myg, mz)) - for i in range(old_npes): - ix = i % old_nxpe - iy = int(i/old_nxpe) - ixstart = mxg - if ix == 0: - ixstart = 0 - ixend = -mxg - if ix == old_nxpe-1: - ixend = 0 - iystart = myg - if iy == 0: - iystart = 0 - iyend = -myg - if iy == old_nype-1: - iyend = 0 - data[ix*old_mxsub+ixstart:(ix+1)*old_mxsub+2*mxg+ixend, iy*old_mysub+iystart:(iy+1)*old_mysub+2*myg+iyend, - :] = infile_list[i].read(v)[ixstart:old_mxsub+2*mxg+ixend, iystart:old_mysub+2*myg+iyend, :] - data = BoutArray(data, attributes=infile_list[0].attributes(v)) - else: - print("ERROR: variable found with unexpected number of dimensions,", ndims, v) - return False + data = collect(v, xguards=True, yguards=True, info=False, + datafile_cache=DataFileCache) # write data for i in range(npes): @@ -659,24 +616,36 @@ def redistribute(npes, path="data", nxpe=None, output=".", informat=None, outfor outfile.write(v, nxpe) elif v == "NYPE": outfile.write(v, nype) - elif ndims == 0: + elif v == "MXSUB": + outfile.write(v, mxsub) + elif v == "MYSUB": + outfile.write(v, mysub) + elif v == "MZSUB": + outfile.write(v, mzsub) + elif dimensions == (): # scalar outfile.write(v, data) - elif ndims == 2: + elif dimensions == ('x', 'y'): # Field2D outfile.write( v, data[ix*mxsub:(ix+1)*mxsub+2*mxg, iy*mysub:(iy+1)*mysub+2*myg]) - elif ndims == 3: + elif dimensions == ('x', 'z'): + # FieldPerp + yindex_global = data.attributes['yindex_global'] + if yindex_global + myg >= iy*mysub and yindex_global + myg < (iy+1)*mysub+2*myg: + outfile.write(v, data[ix*mxsub:(ix+1)*mxsub+2*mxg, :]) + else: + nullarray = BoutArray(np.zeros([mxsub+2*mxg, mysub+2*myg]), attributes={"bout_type":"FieldPerp", "yindex_global":-myg-1}) + outfile.write(v, nullarray) + elif dimensions == ('x', 'y', 'z'): # Field3D outfile.write( v, data[ix*mxsub:(ix+1)*mxsub+2*mxg, iy*mysub:(iy+1)*mysub+2*myg, :]) else: print( - "ERROR: variable found with unexpected number of dimensions,", f.ndims(v)) + "ERROR: variable found with unexpected dimensions,", dimensions, v) f.close() - for infile in infile_list: - infile.close() for outfile in outfile_list: outfile.close() From fa053d3d04eee6728d5a808715e4eee76213c9b4 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 30 Apr 2019 18:20:30 +0100 Subject: [PATCH 1362/1783] I/O test with reading from restart files The already existing test-io doesn't test Datafile::read(), so add a test with input from restart files that does. --- tests/integrated/test-restart-io/.gitignore | 1 + .../integrated/test-restart-io/data/BOUT.inp | 18 +++ tests/integrated/test-restart-io/makefile | 5 + tests/integrated/test-restart-io/runtest | 124 ++++++++++++++++++ .../test-restart-io/test-restart-io.cxx | 34 +++++ 5 files changed, 182 insertions(+) create mode 100644 tests/integrated/test-restart-io/.gitignore create mode 100644 tests/integrated/test-restart-io/data/BOUT.inp create mode 100644 tests/integrated/test-restart-io/makefile create mode 100755 tests/integrated/test-restart-io/runtest create mode 100644 tests/integrated/test-restart-io/test-restart-io.cxx diff --git a/tests/integrated/test-restart-io/.gitignore b/tests/integrated/test-restart-io/.gitignore new file mode 100644 index 0000000000..3f5630137c --- /dev/null +++ b/tests/integrated/test-restart-io/.gitignore @@ -0,0 +1 @@ +test-restart-io diff --git a/tests/integrated/test-restart-io/data/BOUT.inp b/tests/integrated/test-restart-io/data/BOUT.inp new file mode 100644 index 0000000000..d161156a17 --- /dev/null +++ b/tests/integrated/test-restart-io/data/BOUT.inp @@ -0,0 +1,18 @@ +restart = true +timestep = 1 + +[mesh] +nx = 12 +ny = 16 +nz = 4 + +# no periodic region +ixseps1 = -1 +ixseps2 = -1 + +[solver] +type = euler +timestep = 0.5 + +[all] +bndry_all = none diff --git a/tests/integrated/test-restart-io/makefile b/tests/integrated/test-restart-io/makefile new file mode 100644 index 0000000000..4be85e426e --- /dev/null +++ b/tests/integrated/test-restart-io/makefile @@ -0,0 +1,5 @@ +BOUT_TOP = ../../.. + +SOURCEC = test-restart-io.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-restart-io/runtest b/tests/integrated/test-restart-io/runtest new file mode 100755 index 0000000000..c4a558f638 --- /dev/null +++ b/tests/integrated/test-restart-io/runtest @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +# +# Test file I/O by loading from restart files and writing to dump files +# +# require: netcdf + +from boutdata import restart +from boutdata.collect import collect +from boututils.boutarray import BoutArray +from boututils.datafile import DataFile +from boututils.run_wrapper import shell, shell_safe, launch_safe +import numpy +import os +from sys import exit + +nx = 8 +ny = 16 +nz = 4 +mxg = 2 +myg = 2 + +print("Making restart I/O test") +shell_safe("make > make.log") + +x = numpy.linspace(0., 1., nx+2*mxg)[:, numpy.newaxis, numpy.newaxis] +y = numpy.linspace(0., 1., ny+2*myg)[numpy.newaxis, :, numpy.newaxis] +z = numpy.linspace(0., 1., nz)[numpy.newaxis, numpy.newaxis, :] + +testvars = {} +testvars['f3d'] = BoutArray(numpy.exp(numpy.sin(x + y + z)), attributes = {'bout_type':'Field3D'}) +testvars['f2d'] = BoutArray(numpy.exp(numpy.sin(x + y + 1.))[:, :, 0], attributes = {'bout_type':'Field2D'}) +testvars['fperp_lower'] = BoutArray(numpy.exp(numpy.sin(x + z + 2.))[:, 0, :], attributes = {'bout_type':'FieldPerp', 'yindex_global':0}) +testvars['fperp_upper'] = BoutArray(numpy.exp(numpy.sin(x + z + 3.))[:, 0, :], attributes = {'bout_type':'FieldPerp', 'yindex_global':16}) + +# make restart file +restartdir = os.path.join('data', 'restart') +try: + os.mkdir(restartdir) +except FileExistsError: + pass + +with DataFile(os.path.join(restartdir, 'BOUT.restart.0.nc'), create=True) as base_restart: + base_restart.write('MXSUB', nx) + base_restart.write('MYSUB', ny) + base_restart.write('MZSUB', nz) + base_restart.write('MXG', mxg) + base_restart.write('MYG', myg) + base_restart.write('MZG', 0) + base_restart.write('nx', nx+2*mxg) + base_restart.write('ny', ny) + base_restart.write('nz', nz) + base_restart.write('MZ', nz) + base_restart.write('NXPE', 1) + base_restart.write('NYPE', 1) + base_restart.write('NZPE', 1) + base_restart.write('tt', 0.) + base_restart.write('hist_hi', 0) + # set BOUT_VERSION to stop collect from changing nz or printing a warning + base_restart.write('BOUT_VERSION', 4.) + base_restart.write('f3d', testvars['f3d']) + base_restart.write('f2d', testvars['f2d']) + base_restart.write('fperp_lower', testvars['fperp_lower']) + base_restart.write('fperp_upper', testvars['fperp_upper']) + +success = True + +# Note: expect this to fail for 16 processors, because when there are 2 +# y-points per processor, the fperp_lower FieldPerp is in the grid cells of one +# set of processors and also in the guard cells of anoether set. This means +# valid FieldPerps get written to output files with different +# y-processor-indices, and collect() cannot handle this. +for nproc in [1, 2, 4]: + # delete any existing output + shell("rm data/BOUT.dmp.*.nc data/BOUT.restart.*.nc") + + # create restart files for the run + restart.redistribute(nproc, path=restartdir, output='data') + + print(" %d processor...." % (nproc)) + + # run the test executable + s, out = launch_safe('./test-restart-io', nproc=nproc, pipe=True) + with open("run.log."+str(nproc), "w") as f: + f.write(out) + + # check the results + for name in testvars.keys(): + # check non-evolving version + result = collect(name+"_once", path='data', xguards=True, yguards=True, info=False) + testvar = testvars[name] + + if not numpy.all(testvar == result): + success = False + print(name+' is different') + from boututils.showdata import showdata + showdata([result, testvar]) + if name == 'fperp_lower' or name == 'fperp_upper': + yindex_result = result.attributes['yindex_global'] + yindex_test = testvar.attributes['yindex_global'] + if not yindex_result == yindex_test: + success = False + print('Fail: yindex_global of '+name+' is '+str(yindex_result)+' should be '+str(yindex_test)) + + # check evolving versions + result = collect(name, path='data', xguards=True, yguards=True, info=False) + + for result_timeslice in result: + if not numpy.all(testvar == result_timeslice): + success = False + print(name+' evolving version is different') + if name == 'fperp_lower' or name == 'fperp_upper': + yindex_result = result.attributes['yindex_global'] + yindex_test = testvar.attributes['yindex_global'] + if not yindex_result == yindex_test: + success = False + print('Fail: yindex_global of '+name+' evolving version is '+str(yindex_result)+' should be '+str(yindex_test)) + +if success: + print('pass') + + # clean up binary files + shell("rm data/BOUT.dmp.*.nc data/BOUT.restart.*.nc data/restart/BOUT.restart.0.nc") + +exit(0) diff --git a/tests/integrated/test-restart-io/test-restart-io.cxx b/tests/integrated/test-restart-io/test-restart-io.cxx new file mode 100644 index 0000000000..ad8d3a043d --- /dev/null +++ b/tests/integrated/test-restart-io/test-restart-io.cxx @@ -0,0 +1,34 @@ +#include "bout/physicsmodel.hxx" + +class TestRestartIO : public PhysicsModel { + int init(bool UNUSED(restarting)) { + solver->add(f3d, "f3d"); + solver->add(f2d, "f2d"); + dump.addRepeat(fperp_lower, "fperp_lower"); + dump.addRepeat(fperp_upper, "fperp_upper"); + restart.addOnce(fperp_lower, "fperp_lower"); + restart.addOnce(fperp_upper, "fperp_upper"); + + dump.addOnce(f3d, "f3d_once"); + dump.addOnce(f2d, "f2d_once"); + dump.addOnce(fperp_lower, "fperp_lower_once"); + dump.addOnce(fperp_upper, "fperp_upper_once"); + + return 0; + } + + int rhs(BoutReal UNUSED(time)) { + ddt(f3d) = 0.; + ddt(f2d) = 0.; + return 0; + } + + Field3D f3d; + Field2D f2d; + // fperp_lower is at yindex_global=0. + // fperp_upper is at yindex_global=16, it is included to make sure the test does not + // pass only for the special case of the FieldPerp being present on prcossor number 0. + FieldPerp fperp_lower, fperp_upper; +}; + +BOUTMAIN(TestRestartIO); From 7359f7cdfdf91a30efa70c2a30991b13a67d58a1 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 30 Apr 2019 18:50:02 +0100 Subject: [PATCH 1363/1783] HDF5 version of I/O test with reading from restart files Require all_tests for test-restart-io_hdf5, avoids failure on Travis due to missing h5py module. --- .../test-restart-io_hdf5/.gitignore | 1 + .../test-restart-io_hdf5/data/BOUT.inp | 19 +++ .../integrated/test-restart-io_hdf5/makefile | 5 + tests/integrated/test-restart-io_hdf5/runtest | 125 ++++++++++++++++++ .../test-restart-io_hdf5/test-restart-io.cxx | 34 +++++ 5 files changed, 184 insertions(+) create mode 100644 tests/integrated/test-restart-io_hdf5/.gitignore create mode 100644 tests/integrated/test-restart-io_hdf5/data/BOUT.inp create mode 100644 tests/integrated/test-restart-io_hdf5/makefile create mode 100755 tests/integrated/test-restart-io_hdf5/runtest create mode 100644 tests/integrated/test-restart-io_hdf5/test-restart-io.cxx diff --git a/tests/integrated/test-restart-io_hdf5/.gitignore b/tests/integrated/test-restart-io_hdf5/.gitignore new file mode 100644 index 0000000000..3f5630137c --- /dev/null +++ b/tests/integrated/test-restart-io_hdf5/.gitignore @@ -0,0 +1 @@ +test-restart-io diff --git a/tests/integrated/test-restart-io_hdf5/data/BOUT.inp b/tests/integrated/test-restart-io_hdf5/data/BOUT.inp new file mode 100644 index 0000000000..bdacaef63b --- /dev/null +++ b/tests/integrated/test-restart-io_hdf5/data/BOUT.inp @@ -0,0 +1,19 @@ +restart = true +timestep = 1 +dump_format = h5 + +[mesh] +nx = 12 +ny = 16 +nz = 4 + +# no periodic region +ixseps1 = -1 +ixseps2 = -1 + +[solver] +type = euler +timestep = 0.5 + +[all] +bndry_all = none diff --git a/tests/integrated/test-restart-io_hdf5/makefile b/tests/integrated/test-restart-io_hdf5/makefile new file mode 100644 index 0000000000..4be85e426e --- /dev/null +++ b/tests/integrated/test-restart-io_hdf5/makefile @@ -0,0 +1,5 @@ +BOUT_TOP = ../../.. + +SOURCEC = test-restart-io.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-restart-io_hdf5/runtest b/tests/integrated/test-restart-io_hdf5/runtest new file mode 100755 index 0000000000..cddb450691 --- /dev/null +++ b/tests/integrated/test-restart-io_hdf5/runtest @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 +# +# Test file I/O by loading from restart files and writing to dump files +# +# requires: hdf5 +# requires: all_tests + +from boutdata import restart +from boutdata.collect import collect +from boututils.boutarray import BoutArray +from boututils.datafile import DataFile +from boututils.run_wrapper import shell, shell_safe, launch_safe +import numpy +import os +from sys import exit + +nx = 8 +ny = 16 +nz = 4 +mxg = 2 +myg = 2 + +print("Making restart I/O test") +shell_safe("make > make.log") + +x = numpy.linspace(0., 1., nx+2*mxg)[:, numpy.newaxis, numpy.newaxis] +y = numpy.linspace(0., 1., ny+2*myg)[numpy.newaxis, :, numpy.newaxis] +z = numpy.linspace(0., 1., nz)[numpy.newaxis, numpy.newaxis, :] + +testvars = {} +testvars['f3d'] = BoutArray(numpy.exp(numpy.sin(x + y + z)), attributes = {'bout_type':'Field3D'}) +testvars['f2d'] = BoutArray(numpy.exp(numpy.sin(x + y + 1.))[:, :, 0], attributes = {'bout_type':'Field2D'}) +testvars['fperp_lower'] = BoutArray(numpy.exp(numpy.sin(x + z + 2.))[:, 0, :], attributes = {'bout_type':'FieldPerp', 'yindex_global':0}) +testvars['fperp_upper'] = BoutArray(numpy.exp(numpy.sin(x + z + 3.))[:, 0, :], attributes = {'bout_type':'FieldPerp', 'yindex_global':16}) + +# make restart file +restartdir = os.path.join('data', 'restart') +try: + os.mkdir(restartdir) +except FileExistsError: + pass + +with DataFile(os.path.join(restartdir, 'BOUT.restart.0.h5'), create=True) as base_restart: + base_restart.write('MXSUB', nx) + base_restart.write('MYSUB', ny) + base_restart.write('MZSUB', nz) + base_restart.write('MXG', mxg) + base_restart.write('MYG', myg) + base_restart.write('MZG', 0) + base_restart.write('nx', nx+2*mxg) + base_restart.write('ny', ny) + base_restart.write('nz', nz) + base_restart.write('MZ', nz) + base_restart.write('NXPE', 1) + base_restart.write('NYPE', 1) + base_restart.write('NZPE', 1) + base_restart.write('tt', 0.) + base_restart.write('hist_hi', 0) + # set BOUT_VERSION to stop collect from changing nz or printing a warning + base_restart.write('BOUT_VERSION', 4.) + base_restart.write('f3d', testvars['f3d']) + base_restart.write('f2d', testvars['f2d']) + base_restart.write('fperp_lower', testvars['fperp_lower']) + base_restart.write('fperp_upper', testvars['fperp_upper']) + +success = True + +# Note: expect this to fail for 16 processors, because when there are 2 +# y-points per processor, the fperp_lower FieldPerp is in the grid cells of one +# set of processors and also in the guard cells of anoether set. This means +# valid FieldPerps get written to output files with different +# y-processor-indices, and collect() cannot handle this. +for nproc in [1, 2, 4]: + # delete any existing output + shell("rm data/BOUT.dmp.*.h5 data/BOUT.restart.*.h5") + + # create restart files for the run + restart.redistribute(nproc, path=restartdir, output='data') + + print(" %d processor...." % (nproc)) + + # run the test executable + s, out = launch_safe('./test-restart-io', nproc=nproc, pipe=True) + with open("run.log."+str(nproc), "w") as f: + f.write(out) + + # check the results + for name in testvars.keys(): + # check non-evolving version + result = collect(name+"_once", path='data', xguards=True, yguards=True, info=False) + testvar = testvars[name] + + if not numpy.all(testvar == result): + success = False + print(name+' is different') + from boututils.showdata import showdata + showdata([result, testvar]) + if name == 'fperp_lower' or name == 'fperp_upper': + yindex_result = result.attributes['yindex_global'] + yindex_test = testvar.attributes['yindex_global'] + if not yindex_result == yindex_test: + success = False + print('Fail: yindex_global of '+name+' is '+str(yindex_result)+' should be '+str(yindex_test)) + + # check evolving versions + result = collect(name, path='data', xguards=True, yguards=True, info=False) + + for result_timeslice in result: + if not numpy.all(testvar == result_timeslice): + success = False + print(name+' evolving version is different') + if name == 'fperp_lower' or name == 'fperp_upper': + yindex_result = result.attributes['yindex_global'] + yindex_test = testvar.attributes['yindex_global'] + if not yindex_result == yindex_test: + success = False + print('Fail: yindex_global of '+name+' evolving version is '+str(yindex_result)+' should be '+str(yindex_test)) + +if success: + print('pass') + + # clean up binary files + shell("rm data/BOUT.dmp.*.h5 data/BOUT.restart.*.h5 data/restart/BOUT.restart.0.h5") + +exit(0) diff --git a/tests/integrated/test-restart-io_hdf5/test-restart-io.cxx b/tests/integrated/test-restart-io_hdf5/test-restart-io.cxx new file mode 100644 index 0000000000..ad8d3a043d --- /dev/null +++ b/tests/integrated/test-restart-io_hdf5/test-restart-io.cxx @@ -0,0 +1,34 @@ +#include "bout/physicsmodel.hxx" + +class TestRestartIO : public PhysicsModel { + int init(bool UNUSED(restarting)) { + solver->add(f3d, "f3d"); + solver->add(f2d, "f2d"); + dump.addRepeat(fperp_lower, "fperp_lower"); + dump.addRepeat(fperp_upper, "fperp_upper"); + restart.addOnce(fperp_lower, "fperp_lower"); + restart.addOnce(fperp_upper, "fperp_upper"); + + dump.addOnce(f3d, "f3d_once"); + dump.addOnce(f2d, "f2d_once"); + dump.addOnce(fperp_lower, "fperp_lower_once"); + dump.addOnce(fperp_upper, "fperp_upper_once"); + + return 0; + } + + int rhs(BoutReal UNUSED(time)) { + ddt(f3d) = 0.; + ddt(f2d) = 0.; + return 0; + } + + Field3D f3d; + Field2D f2d; + // fperp_lower is at yindex_global=0. + // fperp_upper is at yindex_global=16, it is included to make sure the test does not + // pass only for the special case of the FieldPerp being present on prcossor number 0. + FieldPerp fperp_lower, fperp_upper; +}; + +BOUTMAIN(TestRestartIO); From 5675e0f96e85b9f6e9bdda5a0d4138ca7976f25d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 30 Apr 2019 19:59:24 +0200 Subject: [PATCH 1364/1783] Make sure yindex_global is invalid in DataFormat::writeFieldAttributes Setting the invalid value of yindex_global to '-fieldmesh->ystart-1' ensures that YLOCAL(yindex_global) is always negative so the FieldPerp is always invalid when read back from the output file. --- src/fileio/dataformat.cxx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/fileio/dataformat.cxx b/src/fileio/dataformat.cxx index 7e7406f598..2059452597 100644 --- a/src/fileio/dataformat.cxx +++ b/src/fileio/dataformat.cxx @@ -44,13 +44,14 @@ void DataFormat::writeFieldAttributes(const std::string& name, const Field& f) { void DataFormat::writeFieldAttributes(const std::string& name, const FieldPerp& f) { writeFieldAttributes(name, static_cast(f)); + auto& fieldmesh = *f.getMesh(); int yindex = f.getIndex(); - if (yindex >= 0 and yindex < f.getMesh()->LocalNy) { + if (yindex >= 0 and yindex < fieldmesh.LocalNy) { // write global y-index as attribute - setAttribute(name, "yindex_global", f.getMesh()->YGLOBAL(f.getIndex())); + setAttribute(name, "yindex_global", fieldmesh.YGLOBAL(f.getIndex())); } else { // y-index is not valid, set global y-index to -1 to indicate 'not-valid' - setAttribute(name, "yindex_global", -1); + setAttribute(name, "yindex_global", -fieldmesh.ystart-1); } } From 5428c3f50aa3e45df9f0cececb59e0249aff9c97 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 28 Apr 2019 16:49:25 +0100 Subject: [PATCH 1365/1783] Throw in unimplemented 'int' version of GridFromOptions::get Also update unit test to expect the throw, and comment that the method is not implemented - the test will need updating if the method is implemented, and this will now be obvious as the test will fail. --- src/mesh/data/gridfromoptions.cxx | 1 + tests/unit/mesh/data/test_gridfromoptions.cxx | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index 49e09a0223..ff78399bb6 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -103,6 +103,7 @@ bool GridFromOptions::get(Mesh* m, std::vector& var, const std::string& nam } // FIXME: actually implement this! + throw BoutException("not implemented"); int ival; get(m, ival, name); var.resize(len, ival); diff --git a/tests/unit/mesh/data/test_gridfromoptions.cxx b/tests/unit/mesh/data/test_gridfromoptions.cxx index 194319ce2b..3949454002 100644 --- a/tests/unit/mesh/data/test_gridfromoptions.cxx +++ b/tests/unit/mesh/data/test_gridfromoptions.cxx @@ -193,11 +193,12 @@ TEST_F(GridFromOptionsTest, GetField3DNoneWithDefault) { } TEST_F(GridFromOptionsTest, GetVectorInt) { + // Getting a vector from GridFromOptions is not currently implemented std::vector result{}; - std::vector expected{3, 3, 3}; + //std::vector expected{3, 3, 3}; - EXPECT_TRUE(griddata->get(&mesh_from_options, result, "f", 3)); - EXPECT_EQ(result, expected); + EXPECT_THROW(griddata->get(&mesh_from_options, result, "f", 3), BoutException); + //EXPECT_EQ(result, expected); } TEST_F(GridFromOptionsTest, GetVectorIntNone) { From 35cbce0fdd1864ff44a1325eab384192edf6687f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 1 May 2019 10:10:11 +0100 Subject: [PATCH 1366/1783] Add FieldPerp to File I/O documentation Also update the Datafile and DataFormat interfaces to the current versions. --- manual/sphinx/developer_docs/file_io.rst | 185 ++++++++++++++++++----- 1 file changed, 143 insertions(+), 42 deletions(-) diff --git a/manual/sphinx/developer_docs/file_io.rst b/manual/sphinx/developer_docs/file_io.rst index 80a3d11795..2a78ff2356 100644 --- a/manual/sphinx/developer_docs/file_io.rst +++ b/manual/sphinx/developer_docs/file_io.rst @@ -30,11 +30,11 @@ interface. class Datafile { public: - Datafile(Options *opt = NULL); - Datafile(Datafile &&other); - ~Datafile(); - - Datafile& operator=(Datafile &&rhs); + Datafile(Options *opt = nullptr, Mesh* mesh_in = nullptr); + Datafile(Datafile &&other) noexcept; + ~Datafile(); // need to delete filename + + Datafile& operator=(Datafile &&rhs) noexcept; Datafile& operator=(const Datafile &rhs) = delete; bool openr(const char *filename, ...); @@ -58,83 +58,90 @@ interface. void add(BoutReal &r, const char *name, bool save_repeat = false); void add(Field2D &f, const char *name, bool save_repeat = false); void add(Field3D &f, const char *name, bool save_repeat = false); + void add(FieldPerp &f, const char *name, bool save_repeat = false); void add(Vector2D &f, const char *name, bool save_repeat = false); void add(Vector3D &f, const char *name, bool save_repeat = false); bool read(); ///< Read data into added variables bool write(); ///< Write added variables - bool write(const char *filename, ...) const; ///< Opens, writes, closes file - - // Write a variable to the file now - DEPRECATED(bool writeVar(const int &i, const char *name)); - DEPRECATED(bool writeVar(BoutReal r, const char *name)); + /// Opens, writes, closes file + bool write(const char* filename, ...) const; - void setAttribute(const string &varname, const string &attrname, const string &text) { - attrib_string[varname][attrname] = text; - } - void setAttribute(const string &varname, const string &attrname, int value) { - attrib_int[varname][attrname] = value; - } - } + void setAttribute(const std::string &varname, const std::string &attrname, const std::string &text); + void setAttribute(const std::string &varname, const std::string &attrname, int value); + void setAttribute(const std::string &varname, const std::string &attrname, BoutReal value); + }; The important bits of the DataFormat interface are:: class DataFormat { public: + DataFormat(Mesh* mesh_in = nullptr); virtual ~DataFormat() { } // File opening routines virtual bool openr(const char *name) = 0; - virtual bool openr(const string &name) { + virtual bool openr(const std::string &name) { return openr(name.c_str()); } - virtual bool openr(const string &base, int mype); + virtual bool openr(const std::string &base, int mype); virtual bool openw(const char *name, bool append=false) = 0; - virtual bool openw(const string &name, bool append=false) { + virtual bool openw(const std::string &name, bool append=false) { return openw(name.c_str(), append); } - virtual bool openw(const string &base, int mype, bool append=false); - + virtual bool openw(const std::string &base, int mype, bool append=false); + virtual bool is_valid() = 0; - + virtual void close() = 0; virtual void flush() = 0; - virtual const vector getSize(const char *var) = 0; - virtual const vector getSize(const string &var) = 0; + virtual const std::vector getSize(const char *var) = 0; + virtual const std::vector getSize(const std::string &var) = 0; // Set the origin for all subsequent calls virtual bool setGlobalOrigin(int x = 0, int y = 0, int z = 0) = 0; virtual bool setLocalOrigin(int x = 0, int y = 0, int z = 0, int offset_x = 0, int offset_y = 0, int offset_z = 0); virtual bool setRecord(int t) = 0; // negative -> latest - + + // Add a variable to the file + virtual bool addVarInt(const std::string &name, bool repeat) = 0; + virtual bool addVarBoutReal(const std::string &name, bool repeat) = 0; + virtual bool addVarField2D(const std::string &name, bool repeat) = 0; + virtual bool addVarField3D(const std::string &name, bool repeat) = 0; + virtual bool addVarFieldPerp(const std::string &name, bool repeat) = 0; + // Read / Write simple variables up to 3D virtual bool read(int *var, const char *name, int lx = 1, int ly = 0, int lz = 0) = 0; - virtual bool read(int *var, const string &name, int lx = 1, int ly = 0, int lz = 0) = 0; + virtual bool read(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) = 0; virtual bool read(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) = 0; - virtual bool read(BoutReal *var, const string &name, int lx = 1, int ly = 0, int lz = 0) = 0; + virtual bool read(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) = 0; + virtual bool read_perp(BoutReal *var, const std::string &name, int lx = 1, int lz = 0) = 0; virtual bool write(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) = 0; - virtual bool write(int *var, const string &name, int lx = 0, int ly = 0, int lz = 0) = 0; + virtual bool write(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) = 0; virtual bool write(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) = 0; - virtual bool write(BoutReal *var, const string &name, int lx = 0, int ly = 0, int lz = 0) = 0; + virtual bool write(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) = 0; + virtual bool write_perp(BoutReal *var, const std::string &name, int lx = 0, int lz = 0) = 0; // Read / Write record-based variables virtual bool read_rec(int *var, const char *name, int lx = 1, int ly = 0, int lz = 0) = 0; - virtual bool read_rec(int *var, const string &name, int lx = 1, int ly = 0, int lz = 0) = 0; + virtual bool read_rec(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) = 0; virtual bool read_rec(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) = 0; - virtual bool read_rec(BoutReal *var, const string &name, int lx = 1, int ly = 0, int lz = 0) = 0; + virtual bool read_rec(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) = 0; + virtual bool read_rec_perp(BoutReal *var, const std::string &name, int lx = 1, int lz = 0) = 0; virtual bool write_rec(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) = 0; - virtual bool write_rec(int *var, const string &name, int lx = 0, int ly = 0, int lz = 0) = 0; + virtual bool write_rec(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) = 0; virtual bool write_rec(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) = 0; - virtual bool write_rec(BoutReal *var, const string &name, int lx = 0, int ly = 0, int lz = 0) = 0; + virtual bool write_rec(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) = 0; + virtual bool write_rec_perp(BoutReal *var, const std::string &name, int lx = 0, int lz = 0) = 0; // Optional functions - + virtual void setLowPrecision() { } // By default doesn't do anything // Attributes @@ -144,22 +151,116 @@ The important bits of the DataFormat interface are:: /// Inputs /// ------ /// - /// @param[in] varname Variable name. The variable must already exist + /// @param[in] varname Variable name. The variable must already exist. If + /// varname is the empty string "" then the attribute + /// will be added to the file instead of to a + /// variable. /// @param[in] attrname Attribute name /// @param[in] text A string attribute to attach to the variable - virtual void setAttribute(const string &UNUSED(varname), const string &UNUSED(attrname), - const string &UNUSED(text)) {} + virtual void setAttribute(const std::string &varname, const std::string &attrname, + const std::string &text) = 0; /// Sets an integer attribute /// /// Inputs /// ------ /// - /// @param[in] varname Variable name. The variable must already exist + /// @param[in] varname Variable name. The variable must already exist. If + /// varname is the empty string "" then the attribute + /// will be added to the file instead of to a + /// variable. + /// @param[in] attrname Attribute name + /// @param[in] value An int attribute to attach to the variable + virtual void setAttribute(const std::string &varname, const std::string &attrname, + int value) = 0; + + /// Sets a BoutReal attribute + /// + /// Inputs + /// ------ + /// + /// @param[in] varname Variable name. The variable must already exist. If + /// varname is the empty string "" then the attribute + /// will be added to the file instead of to a + /// variable. + /// @param[in] attrname Attribute name + /// @param[in] value A BoutReal attribute to attach to the variable + virtual void setAttribute(const std::string &varname, const std::string &attrname, + BoutReal value) = 0; + + /// Gets a string attribute + /// + /// Inputs + /// ------ + /// + /// @param[in] varname Variable name. The variable must already exist. If + /// varname is the empty string "" then get the + /// attribute from the top-level of the file instead + /// of from a variable. /// @param[in] attrname Attribute name - /// @param[in] value A string attribute to attach to the variable - virtual void setAttribute(const string &UNUSED(varname), const string &UNUSED(attrname), - int UNUSED(value)) {} + /// + /// Returns + /// ------- + /// text A string attribute of the variable + virtual bool getAttribute(const std::string &varname, const std::string &attrname, std::string &text) = 0; + + /// Gets an integer attribute + /// + /// Inputs + /// ------ + /// + /// @param[in] varname Variable name. The variable must already exist. If + /// varname is the empty string "" then get the + /// attribute from the top-level of the file instead + /// of from a variable. + /// @param[in] attrname Attribute name + /// + /// Returns + /// ------- + /// value An int attribute of the variable + virtual bool getAttribute(const std::string &varname, const std::string &attrname, int &value) = 0; + + /// Gets a BoutReal attribute + /// + /// Inputs + /// ------ + /// + /// @param[in] varname Variable name. The variable must already exist. If + /// varname is the empty string "" then get the + /// attribute from the top-level of the file instead + /// of from a variable. + /// @param[in] attrname Attribute name + /// + /// Returns + /// ------- + /// value A BoutReal attribute of the variable + virtual bool getAttribute(const std::string &varname, const std::string &attrname, BoutReal &value) = 0; + + /// Write out the meta-data of a field as attributes of the variable + void writeFieldAttributes(const std::string& name, const Field& f); + /// Overload for FieldPerp so we can also write 'yindex' + void writeFieldAttributes(const std::string& name, const FieldPerp& f); + + /// Read the attributes of a field + void readFieldAttributes(const std::string& name, Field& f); + /// Overload for FieldPerp so we can also read 'yindex' + void readFieldAttributes(const std::string& name, FieldPerp& f); }; .. [1] Support for PDB files was removed in BOUT++ 4.0.0 + +FieldPerp I/O +------------- + +`FieldPerp` objects can be saved to output files and read from them. The `yindex` of a +`FieldPerp` is the local y-index on a certain processor, but is saved in output files as a +global y-index in the attribute `yindex_global`. The intention is that a `FieldPerp` being +saved should be a globally well-defined object, e.g. a set of values at one divertor +target boundary, that will only be saved from processors holding that global y-index. +Actually, the C++ I/O code should work fine even if a `FieldPerp` object is defined with +different y-indices on different processors, but Python routines like `collect` and +`restart.redistribute` will fail because they find inconsistent `yindex_global` values. + +`FieldPerp` objects should be added to the output files on every processor even if they +are not allocated or used, otherwise `collect` cannot find the variable in the first +output file to get its dimensions. From 5b987e23dd16963db335b8a3c298f0c4bbad2361 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 1 May 2019 14:45:10 +0100 Subject: [PATCH 1367/1783] Allow default value of Options to be set from another Options object --- include/options.hxx | 27 +++++++++++++++++++++++++++ tests/unit/sys/test_options.cxx | 25 +++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/include/options.hxx b/include/options.hxx index 84cd12e85b..21adc01995 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -425,6 +425,33 @@ public: return withDefault(std::string(def)); } + /// Overloaded version to copy from another option + Options& withDefault(const Options& def) { + // if def is a section, then it does not make sense to try to use it as a default for + // a value + ASSERT0(def.is_value); + + if (!is_value) { + // Option not found + *this = def; + + output_info << _("\tOption ") << full_name << " = " << def.full_name << " (" + << DEFAULT_SOURCE << ")" << std::endl; + } else { + // Check if this was previously set as a default option + if (bout::utils::variantEqualTo(attributes.at("source"), DEFAULT_SOURCE)) { + // Check that the default values are the same + if (!similar(bout::utils::variantToString(value), + bout::utils::variantToString(def.value))) { + throw BoutException("Inconsistent default values for '%s': '%s' then '%s'", + full_name.c_str(), bout::utils::variantToString(value).c_str(), + bout::utils::variantToString(def.value).c_str()); + } + } + } + return *this; + } + /// Get the value of this option. If not found, /// return the default value but do not set template T withDefault(T def) const { diff --git a/tests/unit/sys/test_options.cxx b/tests/unit/sys/test_options.cxx index dd3be978a4..8c8fae0e00 100644 --- a/tests/unit/sys/test_options.cxx +++ b/tests/unit/sys/test_options.cxx @@ -342,6 +342,31 @@ TEST_F(OptionsTest, InconsistentDefaultValueString) { EXPECT_EQ(value, "ghijkl"); } +TEST_F(OptionsTest, DefaultValueOptions) { + Options options, default_options; + + default_options.set("int_key", 99); + + int value = options["int_key"].withDefault(default_options["int_key"]).as(); + + EXPECT_EQ(value, 99); +} + +TEST_F(OptionsTest, InconsistentDefaultValueOptions) { + Options options, default_options; + + default_options.set("int_key", 99); + + EXPECT_EQ(options["int_key"].withDefault(42), 42); + + int value = 0; + EXPECT_THROW( + value = options["int_key"].withDefault(default_options["int_key"]).as(), + BoutException); + + EXPECT_EQ(value, 0); +} + TEST_F(OptionsTest, SingletonTest) { Options *root = Options::getRoot(); Options *second = Options::getRoot(); From a7306a8f8d7f79973451551d88cd2e2d121cb6cc Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 1 May 2019 17:36:23 +0100 Subject: [PATCH 1368/1783] Do not calculate parallel slices for field-aligned fields It is incorrect to calculate yup/ydown fields for an input that is already field-aligned. In calcParallelSlices, if 'f.getDirectionY() == YDirectionType::Aligned', then return without calculating parallel slices. Do not throw an exception, because: a simulation might mix field-aligned fields with fields using parallel slices; calcParallelSlices() may be called in communicate(); and a field-aligned field might need to be communicated. In the y-derivatives, before calling a YOrthogonal method, add ASSERT1 checks that the input or inputs have YDirectionType::Standard. --- include/bout/index_derivs_interface.hxx | 7 +++++++ src/mesh/parallel/identity.cxx | 6 ++++++ src/mesh/parallel/shiftedmetric.cxx | 5 +++++ 3 files changed, 18 insertions(+) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 39b52cc112..724e64d9f9 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -200,6 +200,7 @@ T DDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "D REGION region = RGN_NOBNDRY) { AUTO_TRACE(); if (f.hasParallelSlices()) { + ASSERT1(f.getDirectionY() == YDirectionType::Standard); return standardDerivative(f, outloc, method, region); } else { @@ -215,6 +216,7 @@ T D2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = REGION region = RGN_NOBNDRY) { AUTO_TRACE(); if (f.hasParallelSlices()) { + ASSERT1(f.getDirectionY() == YDirectionType::Standard); return standardDerivative( f, outloc, method, region); } else { @@ -230,6 +232,7 @@ T D4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = REGION region = RGN_NOBNDRY) { AUTO_TRACE(); if (f.hasParallelSlices()) { + ASSERT1(f.getDirectionY() == YDirectionType::Standard); return standardDerivative( f, outloc, method, region); } else { @@ -304,6 +307,8 @@ T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, const bool fHasParallelSlices = (f.hasParallelSlices()); const bool velHasParallelSlices = (vel.hasParallelSlices()); if (fHasParallelSlices && velHasParallelSlices) { + ASSERT1(vel.getDirectionY() == YDirectionType::Standard); + ASSERT1(f.getDirectionY() == YDirectionType::Standard); return flowDerivative(vel, f, outloc, method, region); } else { @@ -322,6 +327,8 @@ T FDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, const bool fHasParallelSlices = (f.hasParallelSlices()); const bool velHasParallelSlices = (vel.hasParallelSlices()); if (fHasParallelSlices && velHasParallelSlices) { + ASSERT1(vel.getDirectionY() == YDirectionType::Standard); + ASSERT1(f.getDirectionY() == YDirectionType::Standard); return flowDerivative(vel, f, outloc, method, region); } else { diff --git a/src/mesh/parallel/identity.cxx b/src/mesh/parallel/identity.cxx index 4b25a285ae..ab9e4b89d4 100644 --- a/src/mesh/parallel/identity.cxx +++ b/src/mesh/parallel/identity.cxx @@ -10,6 +10,12 @@ #include "bout/paralleltransform.hxx" void ParallelTransformIdentity::calcParallelSlices(Field3D& f) { + if (f.getDirectionY() == YDirectionType::Aligned) { + // Cannot calculate parallel slices for field-aligned fields, so just return without + // setting yup or ydown + return; + } + f.splitParallelSlices(); for (int i = 0; i < f.getMesh()->ystart; ++i) { diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 905c287735..f265ca0a03 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -242,6 +242,11 @@ void ShiftedMetric::shiftZ(const BoutReal* in, const dcomplex* phs, BoutReal* ou } void ShiftedMetric::calcParallelSlices(Field3D& f) { + if (f.getDirectionY() == YDirectionType::Aligned) { + // Cannot calculate parallel slices for field-aligned fields, so return without + // setting yup or ydown + return; + } auto results = shiftZ(f, parallel_slice_phases); From 186cbdc61118699a25d69c648cff727a4d8d07a0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 1 May 2019 18:13:37 +0100 Subject: [PATCH 1369/1783] Set y-direction of FieldPerp results in ParallelTransformIdentity --- include/bout/paralleltransform.hxx | 6 +++-- tests/unit/mesh/test_paralleltransform.cxx | 27 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index e302f0b3b0..b5c7d66d1d 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -91,7 +91,8 @@ public: return result.setDirectionY(YDirectionType::Aligned); } const FieldPerp toFieldAligned(const FieldPerp& f, const REGION UNUSED(region)) override { - return f; + FieldPerp result = f; + return result.setDirectionY(YDirectionType::Aligned); } /*! @@ -103,7 +104,8 @@ public: return result.setDirectionY(YDirectionType::Standard); } const FieldPerp fromFieldAligned(const FieldPerp& f, const REGION UNUSED(region)) override { - return f; + FieldPerp result = f; + return result.setDirectionY(YDirectionType::Standard); } bool canToFromFieldAligned() override { return true; } diff --git a/tests/unit/mesh/test_paralleltransform.cxx b/tests/unit/mesh/test_paralleltransform.cxx index 27badf9613..8141eec363 100644 --- a/tests/unit/mesh/test_paralleltransform.cxx +++ b/tests/unit/mesh/test_paralleltransform.cxx @@ -64,3 +64,30 @@ TEST_F(ParallelTransformTest, IdentityFromFieldAligned) { EXPECT_TRUE(IsFieldEqual(result, 1.0)); EXPECT_TRUE(result.getDirectionY() == YDirectionType::Standard); } + +TEST_F(ParallelTransformTest, IdentityToFieldAlignedFieldPerp) { + + ParallelTransformIdentity transform{*bout::globals::mesh}; + + FieldPerp field{1.0}; + field.setIndex(2); + + FieldPerp result = transform.toFieldAligned(field, RGN_ALL); + + EXPECT_TRUE(IsFieldEqual(result, 1.0)); + EXPECT_TRUE(result.getDirectionY() == YDirectionType::Aligned); +} + +TEST_F(ParallelTransformTest, IdentityFromFieldAlignedFieldPerp) { + + ParallelTransformIdentity transform{*bout::globals::mesh}; + + FieldPerp field{1.0}; + field.setIndex(2); + field.setDirectionY(YDirectionType::Aligned); + + FieldPerp result = transform.fromFieldAligned(field, RGN_ALL); + + EXPECT_TRUE(IsFieldEqual(result, 1.0)); + EXPECT_TRUE(result.getDirectionY() == YDirectionType::Standard); +} From 3898fb627d498bec1b5b8c49fc9e5f6bc07bba22 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 2 May 2019 10:05:34 +0100 Subject: [PATCH 1370/1783] Add Options::withDefault(Options&) to manual --- manual/sphinx/user_docs/bout_options.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index 0e785f8803..b028f133a8 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -498,6 +498,11 @@ cached. If a default value has already been cached for this option, then the default values must be consistent: A ``BoutException`` is thrown if inconsistent default values are detected. +The default can also be set from another option. This may be useful if two or +more options should usually be changed together:: + + BoutReal value2 = options["value2"].withDefault(options["value1"]); + Note that if the result should be a real number (e.g. ``BoutReal``) then ``withDefault`` should be given a real. Otherwise it will convert the number to an integer:: From 15a2f6ede5ab295f992e46d0263a986e0941a4cb Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sun, 5 May 2019 20:44:53 +0100 Subject: [PATCH 1371/1783] Fixes for FV::Div_a_Laplace_perp - Extrapolation of metrics into the boundary meant that Dirichlet boundaries applied to coefficients did not have the desired effect. Changed so that the diffusion coefficients are interpolated using simple midpoint. - A copy-paste error using up rather than down coefficients. --- src/mesh/fv_ops.cxx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index 86d3d17b01..36f372af52 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -37,7 +37,7 @@ namespace FV { for(int k=0;kLocalNz;k++) { // Calculate flux from i to i+1 - BoutReal fout = (coord->J(i,j)*a(i,j,k)*coord->g11(i,j) + coord->J(i+1,j)*a(i+1,j,k)*coord->g11(i+1,j)) * + BoutReal fout = 0.5*(a(i,j,k) + a(i+1,j,k)) * (coord->J(i,j)*coord->g11(i,j) + coord->J(i+1,j)*coord->g11(i+1,j)) * (f(i+1,j,k) - f(i,j,k))/(coord->dx(i,j) + coord->dx(i+1,j)); result(i,j,k) += fout / (coord->dx(i,j)*coord->J(i,j)); @@ -80,7 +80,7 @@ namespace FV { // Y flux for (int i = mesh->xstart; i <= mesh->xend; i++) { - for (int j = mesh->ystart - 1; j <= mesh->yend; j++) { + for (int j = mesh->ystart; j <= mesh->yend; j++) { BoutReal coef = 0.5 * (coord->g_23(i, j) / SQ(coord->J(i, j) * coord->Bxy(i, j)) + @@ -88,8 +88,8 @@ namespace FV { for (int k = 0; k < mesh->LocalNz; k++) { // Calculate flux between j and j+1 - int kp = (k + 1) % (mesh->LocalNz); - int km = (k - 1 + (mesh->LocalNz)) % (mesh->LocalNz); + int kp = (k + 1) % mesh->LocalNz; + int km = (k - 1 + mesh->LocalNz) % mesh->LocalNz; // Calculate Z derivative at y boundary BoutReal dfdz = 0.25 * (fc(i, j, kp) - fc(i, j, km) + fup(i, j + 1, kp) - @@ -100,9 +100,9 @@ namespace FV { BoutReal dfdy = 2. * (fup(i, j + 1, k) - fc(i, j, k)) / (coord->dy(i, j + 1) + coord->dy(i, j)); - BoutReal fout = 0.5 * - (coord->J(i, j) * ac(i, j, k) * coord->g23(i, j) + - coord->J(i, j + 1) * aup(i, j + 1, k) * coord->g23(i, j + 1)) * + BoutReal fout = 0.25 * (ac(i, j, k) + aup(i, j + 1, k)) * + (coord->J(i, j) * coord->g23(i, j) + + coord->J(i, j + 1) * coord->g23(i, j + 1)) * (dfdz - coef * dfdy); yzresult(i, j, k) = fout / (coord->dy(i, j) * coord->J(i, j)); @@ -115,8 +115,9 @@ namespace FV { dfdy = 2. * (fc(i, j, k) - fdown(i, j - 1, k)) / (coord->dy(i, j) + coord->dy(i, j - 1)); - fout = 0.5 * (coord->J(i, j) * ac(i, j, k) * coord->g23(i, j) + - coord->J(i, j - 1) * aup(i, j + 1, k) * coord->g23(i, j + 1)) * + fout = 0.25 * (ac(i, j, k) + adown(i, j - 1, k)) * + (coord->J(i, j) * coord->g23(i, j) + + coord->J(i, j - 1) * coord->g23(i, j - 1)) * (dfdz - coef * dfdy); yzresult(i, j, k) -= fout / (coord->dy(i, j) * coord->J(i, j)); From 06f4b9106eadab17a0bdaae2c3931494d7cee0bb Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 7 May 2019 10:25:26 +0100 Subject: [PATCH 1372/1783] Don't run unit tests that require FFTW if not compiled with FFTW --- tests/unit/field/test_field3d.cxx | 2 ++ tests/unit/invert/test_fft.cxx | 2 ++ tests/unit/mesh/parallel/test_shiftedmetric.cxx | 2 ++ 3 files changed, 6 insertions(+) diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index 9c2a9cadec..aa30224b32 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -2096,6 +2096,7 @@ TEST_F(Field3DTest, FillField) { EXPECT_TRUE(IsFieldEqual(f, g)); } +#ifdef BOUT_HAS_FFTW namespace bout { namespace testing { @@ -2215,6 +2216,7 @@ TEST_F(Field3DTest, LowPassTwoArgNothing) { EXPECT_TRUE(IsFieldEqual(output, input)); } +#endif TEST_F(Field3DTest, OperatorEqualsField3D) { Field3D field; diff --git a/tests/unit/invert/test_fft.cxx b/tests/unit/invert/test_fft.cxx index 61b25cef87..4278589e53 100644 --- a/tests/unit/invert/test_fft.cxx +++ b/tests/unit/invert/test_fft.cxx @@ -10,6 +10,7 @@ #include #include +#ifdef BOUT_HAS_FFTW class FFTTest : public ::testing::TestWithParam { public: FFTTest() @@ -108,3 +109,4 @@ TEST_P(FFTTest, RoundTrip) { EXPECT_NEAR(output[i], real_signal[i], FFTTolerance); } } +#endif diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 3a40eb5157..e70fead41b 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -3,6 +3,7 @@ #include "fft.hxx" #include "test_extras.hxx" +#ifdef BOUT_HAS_FFTW // The unit tests use the global mesh using namespace bout::globals; @@ -415,3 +416,4 @@ TEST_F(ShiftedMetricTest, CalcParallelSlices) { EXPECT_TRUE(IsFieldEqual(input.ynext(-1), expected_down_1, "RGN_YDOWN", FFTTolerance)); EXPECT_TRUE(IsFieldEqual(input.ynext(-2), expected_down2, "RGN_YDOWN2", FFTTolerance)); } +#endif From 5e641b92ca142e4aadc0d272db9d13ff3f14241c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 7 May 2019 10:25:59 +0100 Subject: [PATCH 1373/1783] Don't register FFT-based derivative if not compiled with FFTW --- src/mesh/index_derivs.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index 737469ac9e..a4f6f51577 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -409,6 +409,7 @@ REGISTER_FLUX_DERIVATIVE_STAGGERED(FDDX_U2_stag, "U2", 2, DERIV::Flux) { /// into the standard stencil based approach. // ///////////////////////////////////////////////////////////////////////////////// +#ifdef BOUT_HAS_FFTW class FFTDerivativeType { public: template @@ -550,6 +551,7 @@ produceCombinations, Set, Set>, Set> registerFFTDerivative(registerMethod{}); +#endif class SplitFluxDerivativeType { public: From 58fc47aa98554f60d714b6391ffad56d3045727b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 7 May 2019 11:08:56 +0100 Subject: [PATCH 1374/1783] Fix typos in BoutMesh boundary Region y-ranges Fixes #1656 --- src/mesh/impls/bout/boutmesh.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index a401c6817b..5078bc8584 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2210,9 +2210,9 @@ void BoutMesh::addBoundaryRegions() { if (xe > xend) xe = xend; - addRegion3D("RGN_LOWER_Y", Region(xs, xe, 0, ystart-1, 0, LocalNz-1, + addRegion3D("RGN_LOWER_Y", Region(xs, xe, yend, LocalNy-1, 0, LocalNz-1, LocalNy, LocalNz, maxregionblocksize)); - addRegion2D("RGN_LOWER_Y", Region(xs, xe, 0, ystart-1, 0, 0, + addRegion2D("RGN_LOWER_Y", Region(xs, xe, yend, LocalNy-1, 0, 0, LocalNy, 1, maxregionblocksize)); all_boundaries.emplace_back("RGN_LOWER_Y"); @@ -2236,9 +2236,9 @@ void BoutMesh::addBoundaryRegions() { xe = -2; } - addRegion3D("RGN_UPPER_INNER_Y", Region(xs, xe, 0, ystart-1, 0, LocalNz-1, + addRegion3D("RGN_UPPER_INNER_Y", Region(xs, xe, yend, LocalNy-1, 0, LocalNz-1, LocalNy, LocalNz, maxregionblocksize)); - addRegion2D("RGN_UPPER_INNER_Y", Region(xs, xe, 0, ystart-1, 0, 0, + addRegion2D("RGN_UPPER_INNER_Y", Region(xs, xe, yend, LocalNy-1, 0, 0, LocalNy, 1, maxregionblocksize)); all_boundaries.emplace_back("RGN_UPPER_INNER_Y"); @@ -2262,9 +2262,9 @@ void BoutMesh::addBoundaryRegions() { xe = xend; } - addRegion3D("RGN_UPPER_OUTER_Y", Region(xs, xe, 0, ystart-1, 0, LocalNz-1, + addRegion3D("RGN_UPPER_OUTER_Y", Region(xs, xe, yend, LocalNy-1, 0, LocalNz-1, LocalNy, LocalNz, maxregionblocksize)); - addRegion2D("RGN_UPPER_OUTER_Y", Region(xs, xe, 0, ystart-1, 0, 0, + addRegion2D("RGN_UPPER_OUTER_Y", Region(xs, xe, yend, LocalNy-1, 0, 0, LocalNy, 1, maxregionblocksize)); all_boundaries.emplace_back("RGN_UPPER_OUTER_Y"); From c88fdfaab516e1a3f154b461a0688e8448cd7f74 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 7 May 2019 11:42:42 +0100 Subject: [PATCH 1375/1783] Add implementation of Field2D::applyBoundary(BoutReal time) Fixes #1657 --- include/field2d.hxx | 1 + src/field/field2d.cxx | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/include/field2d.hxx b/include/field2d.hxx index 58f4058595..f1bcdd88cc 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -261,6 +261,7 @@ class Field2D : public Field, public FieldData { friend class Vector2D; void applyBoundary(bool init=false) override; + void applyBoundary(BoutReal time); void applyBoundary(const std::string &condition); void applyBoundary(const char* condition) { applyBoundary(std::string(condition)); } void applyBoundary(const std::string ®ion, const std::string &condition); diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index d92d28ef6a..627c36c58f 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -200,6 +200,22 @@ void Field2D::applyBoundary(bool init) { bndry->apply(*this); } +void Field2D::applyBoundary(BoutReal time) { + TRACE("Field2D::applyBoundary(time)"); + +#if CHECK > 0 + if (!boundaryIsSet) { + output_warn << "WARNING: Call to Field2D::applyBoundary(time), but no boundary set\n"; + } +#endif + + checkData(*this); + + for (const auto& bndry : bndry_op) { + bndry->apply(*this, time); + } +} + void Field2D::applyBoundary(const std::string &condition) { TRACE("Field2D::applyBoundary(condition)"); From 66aa80de2758e4f93587c2cb79e18d8b678d7d3b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 7 May 2019 11:48:18 +0100 Subject: [PATCH 1376/1783] Fix more typos in BoutMesh boundary Region y-ranges --- src/mesh/impls/bout/boutmesh.cxx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 5078bc8584..0b351f3374 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2210,9 +2210,9 @@ void BoutMesh::addBoundaryRegions() { if (xe > xend) xe = xend; - addRegion3D("RGN_LOWER_Y", Region(xs, xe, yend, LocalNy-1, 0, LocalNz-1, + addRegion3D("RGN_LOWER_Y", Region(xs, xe, 0, ystart-1, 0, LocalNz-1, LocalNy, LocalNz, maxregionblocksize)); - addRegion2D("RGN_LOWER_Y", Region(xs, xe, yend, LocalNy-1, 0, 0, + addRegion2D("RGN_LOWER_Y", Region(xs, xe, 0, ystart-1, 0, 0, LocalNy, 1, maxregionblocksize)); all_boundaries.emplace_back("RGN_LOWER_Y"); @@ -2236,9 +2236,9 @@ void BoutMesh::addBoundaryRegions() { xe = -2; } - addRegion3D("RGN_UPPER_INNER_Y", Region(xs, xe, yend, LocalNy-1, 0, LocalNz-1, + addRegion3D("RGN_UPPER_INNER_Y", Region(xs, xe, yend+1, LocalNy-1, 0, LocalNz-1, LocalNy, LocalNz, maxregionblocksize)); - addRegion2D("RGN_UPPER_INNER_Y", Region(xs, xe, yend, LocalNy-1, 0, 0, + addRegion2D("RGN_UPPER_INNER_Y", Region(xs, xe, yend+1, LocalNy-1, 0, 0, LocalNy, 1, maxregionblocksize)); all_boundaries.emplace_back("RGN_UPPER_INNER_Y"); @@ -2262,9 +2262,9 @@ void BoutMesh::addBoundaryRegions() { xe = xend; } - addRegion3D("RGN_UPPER_OUTER_Y", Region(xs, xe, yend, LocalNy-1, 0, LocalNz-1, + addRegion3D("RGN_UPPER_OUTER_Y", Region(xs, xe, yend+1, LocalNy-1, 0, LocalNz-1, LocalNy, LocalNz, maxregionblocksize)); - addRegion2D("RGN_UPPER_OUTER_Y", Region(xs, xe, yend, LocalNy-1, 0, 0, + addRegion2D("RGN_UPPER_OUTER_Y", Region(xs, xe, yend+1, LocalNy-1, 0, 0, LocalNy, 1, maxregionblocksize)); all_boundaries.emplace_back("RGN_UPPER_OUTER_Y"); @@ -2282,9 +2282,9 @@ void BoutMesh::addBoundaryRegions() { if (xe > xend) xe = xend; - addRegion3D("RGN_UPPER_Y", Region(xs, xe, 0, ystart-1, 0, LocalNz-1, + addRegion3D("RGN_UPPER_Y", Region(xs, xe, yend+1, LocalNy-1, 0, LocalNz-1, LocalNy, LocalNz, maxregionblocksize)); - addRegion2D("RGN_UPPER_Y", Region(xs, xe, 0, ystart-1, 0, 0, + addRegion2D("RGN_UPPER_Y", Region(xs, xe, yend+1, LocalNy-1, 0, 0, LocalNy, 1, maxregionblocksize)); all_boundaries.emplace_back("RGN_UPPER_Y"); From 2dce11a6adacbf0f19e88426463a0e2ed4748b6c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 7 May 2019 18:45:50 +0100 Subject: [PATCH 1377/1783] Use BoutComm::rank() in datafile.cxx Removes need for intermediate 'int MYPE' variables and direct calls to MPI_Comm_rank(). --- src/fileio/datafile.cxx | 60 +++++++++++------------------------------ 1 file changed, 15 insertions(+), 45 deletions(-) diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 43bd24db61..e695e67527 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -173,9 +173,7 @@ bool Datafile::openr(const char *format, ...) { if(!openclose) { // Open the file now. Otherwise defer until later - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); - if(!file->openr(filename, MYPE)) + if(!file->openr(filename, BoutComm::rank())) throw BoutException("Datafile::open: Failed to open file!"); } @@ -216,9 +214,7 @@ bool Datafile::openw(const char *format, ...) { appending = false; // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); - if(!file->openw(filename, MYPE, appending)) + if(!file->openw(filename, BoutComm::rank(), appending)) throw BoutException("Datafile::open: Failed to open file!"); appending = true; @@ -326,9 +322,7 @@ bool Datafile::opena(const char *format, ...) { appending = true; // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); - if(!file->openw(filename, MYPE, true)) + if(!file->openw(filename, BoutComm::rank(), true)) throw BoutException("Datafile::open: Failed to open file!"); first_time = true; // newly opened file, so write attributes when variables are first written @@ -456,12 +450,10 @@ void Datafile::add(int &i, const char *name, bool save_repeat) { // Otherwise will add variables when Datafile is opened for writing/appending if (openclose) { // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); // Check filename has been set if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, MYPE, appending)) + if(!file->openw(filename, BoutComm::rank(), appending)) throw BoutException("Datafile::add: Failed to open file!"); appending = true; } @@ -506,11 +498,9 @@ void Datafile::add(BoutReal &r, const char *name, bool save_repeat) { // Otherwise will add variables when Datafile is opened for writing/appending if (openclose) { // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, MYPE, appending)) + if(!file->openw(filename, BoutComm::rank(), appending)) throw BoutException("Datafile::add: Failed to open file!"); appending = true; } @@ -558,11 +548,9 @@ void Datafile::add(Field2D &f, const char *name, bool save_repeat) { // Otherwise will add variables when Datafile is opened for writing/appending if (openclose) { // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, MYPE, appending)) + if(!file->openw(filename, BoutComm::rank(), appending)) throw BoutException("Datafile::add: Failed to open file!"); appending = true; } @@ -610,11 +598,9 @@ void Datafile::add(Field3D &f, const char *name, bool save_repeat) { // Otherwise will add variables when Datafile is opened for writing/appending if (openclose) { // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, MYPE, appending)) + if(!file->openw(filename, BoutComm::rank(), appending)) throw BoutException("Datafile::add: Failed to open file!"); appending = true; } @@ -662,11 +648,9 @@ void Datafile::add(FieldPerp &f, const char *name, bool save_repeat) { // Otherwise will add variables when Datafile is opened for writing/appending if (openclose) { // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, MYPE, appending)) + if(!file->openw(filename, BoutComm::rank(), appending)) throw BoutException("Datafile::add: Failed to open file!"); appending = true; } @@ -714,11 +698,9 @@ void Datafile::add(Vector2D &f, const char *name, bool save_repeat) { // Otherwise will add variables when Datafile is opened for writing/appending if (openclose) { // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, MYPE, appending)) + if(!file->openw(filename, BoutComm::rank(), appending)) throw BoutException("Datafile::add: Failed to open file!"); appending = true; } @@ -772,11 +754,9 @@ void Datafile::add(Vector3D &f, const char *name, bool save_repeat) { // Otherwise will add variables when Datafile is opened for writing/appending if (openclose) { // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, MYPE, appending)) + if(!file->openw(filename, BoutComm::rank(), appending)) throw BoutException("Datafile::add: Failed to open file!"); appending = true; } @@ -809,9 +789,7 @@ bool Datafile::read() { if(openclose) { // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); - if(!file->openr(filename, MYPE)) + if(!file->openr(filename, BoutComm::rank())) throw BoutException("Datafile::read: Failed to open file!"); } @@ -932,9 +910,7 @@ bool Datafile::write() { if(openclose && (flushFrequencyCounter % flushFrequency == 0)) { // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); - if(!file->openw(filename, MYPE, appending)) + if(!file->openw(filename, BoutComm::rank(), appending)) throw BoutException("Datafile::write: Failed to open file!"); appending = true; flushFrequencyCounter = 0; @@ -1098,9 +1074,7 @@ void Datafile::setAttribute(const std::string &varname, const std::string &attrn if(openclose && (flushFrequencyCounter % flushFrequency == 0)) { // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); - if(!file->openw(filename, MYPE, appending)) + if(!file->openw(filename, BoutComm::rank(), appending)) throw BoutException("Datafile::write: Failed to open file!"); appending = true; flushFrequencyCounter = 0; @@ -1127,9 +1101,7 @@ void Datafile::setAttribute(const std::string &varname, const std::string &attrn if(openclose && (flushFrequencyCounter % flushFrequency == 0)) { // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); - if(!file->openw(filename, MYPE, appending)) + if(!file->openw(filename, BoutComm::rank(), appending)) throw BoutException("Datafile::write: Failed to open file!"); appending = true; flushFrequencyCounter = 0; @@ -1156,9 +1128,7 @@ void Datafile::setAttribute(const std::string &varname, const std::string &attrn if(openclose && (flushFrequencyCounter % flushFrequency == 0)) { // Open the file - int MYPE; - MPI_Comm_rank(BoutComm::get(), &MYPE); - if(!file->openw(filename, MYPE, appending)) + if(!file->openw(filename, BoutComm::rank(), appending)) throw BoutException("Datafile::write: Failed to open file!"); appending = true; flushFrequencyCounter = 0; From 751cdaa68f3879bc4417330ec99553f9b6e86299 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 7 May 2019 18:47:42 +0100 Subject: [PATCH 1378/1783] Rename safeAtReverse to safeAt It is fine to treat it as an overload of safeAt. --- src/sys/bout_types.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index aa16a6baa5..90dd280d71 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -15,7 +15,7 @@ const std::string& safeAt(const std::map& mymap, T t) { } template -const T& safeAtReverse(const std::map& mymap, std::string s) { +const T& safeAt(const std::map& mymap, std::string s) { AUTO_TRACE(); auto found = mymap.find(s); if (found == mymap.end()) { @@ -40,7 +40,7 @@ CELL_LOC CELL_LOCFromString(std::string location_string) { STRENUM(CELL_DEFAULT), STRENUM(CELL_CENTRE), STRENUM(CELL_XLOW), STRENUM(CELL_YLOW), STRENUM(CELL_ZLOW), STRENUM(CELL_VSHIFT)}; - return safeAtReverse(stringtoCELL_LOC, location_string); + return safeAt(stringtoCELL_LOC, location_string); } std::string toString(DIFF_METHOD location) { @@ -152,7 +152,7 @@ YDirectionType YDirectionTypeFromString(std::string y_direction_string) { {"Standard", YDirectionType::Standard}, {"Aligned", YDirectionType::Aligned}}; - return safeAtReverse(stringToYDirectionType, y_direction_string); + return safeAt(stringToYDirectionType, y_direction_string); } std::string toString(ZDirectionType d) { @@ -170,5 +170,5 @@ ZDirectionType ZDirectionTypeFromString(std::string z_direction_string) { {"Standard", ZDirectionType::Standard}, {"Average", ZDirectionType::Average}}; - return safeAtReverse(stringToZDirectionType, z_direction_string); + return safeAt(stringToZDirectionType, z_direction_string); } From beae092cc9cafca10f5b8337a7699cd01ad78b96 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 7 May 2019 18:57:54 +0100 Subject: [PATCH 1379/1783] Make manual entry on file I/O for FieldPerps clearer --- manual/sphinx/developer_docs/file_io.rst | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/manual/sphinx/developer_docs/file_io.rst b/manual/sphinx/developer_docs/file_io.rst index 2a78ff2356..908aee349c 100644 --- a/manual/sphinx/developer_docs/file_io.rst +++ b/manual/sphinx/developer_docs/file_io.rst @@ -256,11 +256,16 @@ FieldPerp I/O `FieldPerp` is the local y-index on a certain processor, but is saved in output files as a global y-index in the attribute `yindex_global`. The intention is that a `FieldPerp` being saved should be a globally well-defined object, e.g. a set of values at one divertor -target boundary, that will only be saved from processors holding that global y-index. -Actually, the C++ I/O code should work fine even if a `FieldPerp` object is defined with -different y-indices on different processors, but Python routines like `collect` and -`restart.redistribute` will fail because they find inconsistent `yindex_global` values. - -`FieldPerp` objects should be added to the output files on every processor even if they -are not allocated or used, otherwise `collect` cannot find the variable in the first -output file to get its dimensions. +target boundary, that will only be saved from processors holding that global +y-index. The expectation is that the other processors would all save an invalid +`FieldPerp` variable, with a `yindex_global` that is more negative than the +lowest y-boundary guard cell [2]_. The reason for saving the invalid `FieldPerp` variables +is so that all variables are present in every dump file (even if they are not allocated or +used); in particular the Python `collect` routine assumes that any variable will be found +in the first output file, which `collect` uses to get its type and dimensions. + +.. [2] Actually, the C++ I/O code should work fine even if a `FieldPerp` object is defined + with different y-indices on different processors. This may be useful for diagnostic + or debugging purposes. However, Python routines like `collect` and + `restart.redistribute` will fail because they find inconsistent `yindex_global` + values. From 02ebbddc68bd74f16e1ebb1eb48937028c8ad5a9 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 7 May 2019 19:14:40 +0100 Subject: [PATCH 1380/1783] Tidy up direction-type setters setDirectionType(d) methods of Field3D, Field2D and FieldPerp that return the field (allowing method chaining) are the interface to set the YDirectionType. Add Field2D::setDirectionType(d) in case it is wanted in a template function which needs to call it on Field3D/FieldPerp. Field2D version ASSERT1's that the argument is YDirectionType::Standard, which is the only valid value for Field2D as field-aligned and orthogonal Field2Ds would be identical. Remove the setDirectionTypeY and setDirectionTypeZ methods of Field. Functionality of setDirectionTypeY is provided by the derived-class methods. setDirectionTypeZ is not needed anywhere at the moment, and should be provided by similar derived-class methods if/when it is needed. Make Field::directions protected instead of private so that the derived classes don't need the setters. --- include/field.hxx | 10 +--------- include/field2d.hxx | 8 ++++++++ include/field3d.hxx | 2 +- include/fieldperp.hxx | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index 2c66a11ac2..74bdf93602 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -216,15 +216,7 @@ protected: directions = f.directions; } - /// Setters for *DirectionType - void setDirectionY(YDirectionType y_type) { - directions.y = y_type; - } - void setDirectionZ(ZDirectionType z_type) { - directions.z = z_type; - } - -private: + /// Labels for the type of coordinate system this field is defined over DirectionTypes directions{YDirectionType::Standard, ZDirectionType::Standard}; }; diff --git a/include/field2d.hxx b/include/field2d.hxx index f1bcdd88cc..090d517503 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -124,6 +124,14 @@ class Field2D : public Field, public FieldData { Field::setLocation(location); return *this; } + Field2D& setDirectionY(YDirectionType d) { + // This method included in case it is wanted in a templated function also dealing with + // Field3D or FieldPerp - there is no difference between orthogonal and field-aligned + // coordinates for Field2D, so should always have YDirectionType::Standard. + ASSERT1(d == YDirectionType::Standard); + directions.y = d; + return *this; + } /// Check if this field has yup and ydown fields bool hasParallelSlices() const { diff --git a/include/field3d.hxx b/include/field3d.hxx index 9b0b8fd993..e6611cc843 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -232,7 +232,7 @@ class Field3D : public Field, public FieldData { return *this; } Field3D& setDirectionY(YDirectionType d) { - Field::setDirectionY(d); + directions.y = d; return *this; } diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index cf145a07d2..301abdfc4f 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -129,7 +129,7 @@ class FieldPerp : public Field { return *this; } FieldPerp& setDirectionY(YDirectionType d) { - Field::setDirectionY(d); + directions.y = d; return *this; } From b24ca9213be2f5aead898fe7c0a6152a78c3902d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 15:29:07 +0100 Subject: [PATCH 1381/1783] Remove virtual function calls from some ctors/dtors --- include/bout/paralleltransform.hxx | 2 +- src/fileio/impls/netcdf4/ncxx4.cxx | 10 ++++++---- src/invert/laplace/invert_laplace.cxx | 2 +- src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx | 2 +- src/mesh/parallel/fci.hxx | 2 +- src/mesh/parallel/shiftedmetric.cxx | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index b5c7d66d1d..342f353e87 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -73,7 +73,7 @@ class ParallelTransformIdentity : public ParallelTransform { public: ParallelTransformIdentity(Mesh& mesh_in) : ParallelTransform(mesh_in) { // check the coordinate system used for the grid data source - checkInputGrid(); + ParallelTransformIdentity::checkInputGrid(); } /*! diff --git a/src/fileio/impls/netcdf4/ncxx4.cxx b/src/fileio/impls/netcdf4/ncxx4.cxx index 17c5a4623b..0537a999e0 100644 --- a/src/fileio/impls/netcdf4/ncxx4.cxx +++ b/src/fileio/impls/netcdf4/ncxx4.cxx @@ -62,12 +62,12 @@ Ncxx4::Ncxx4(const char *name, Mesh* mesh_in) : DataFormat(mesh_in) { default_rec = 0; rec_nr.clear(); - openr(name); + Ncxx4::openr(name); } Ncxx4::~Ncxx4() { delete[] recDimList; - close(); + Ncxx4::close(); rec_nr.clear(); } @@ -78,8 +78,10 @@ bool Ncxx4::openr(const char *name) { output.write("Ncxx4:: openr(%s)\n", name); #endif - if (dataFile != nullptr) // Already open. Close then re-open - close(); + if (dataFile != nullptr) { + // Already open. Close then re-open + Ncxx4::close(); + } dataFile = new NcFile(name, NcFile::read); diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index b1de244ecc..b114cc9398 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -97,7 +97,7 @@ Laplacian::Laplacian(Options *options, const CELL_LOC loc, Mesh *mesh_in) int flags = (*options)["flags"] .doc("Flags to control inner and outer boundaries.") .withDefault(0); - setFlags(flags); + Laplacian::setFlags(flags); } else { OPTION(options, global_flags, 0); diff --git a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx index 157168a5d0..72c63e5fc5 100644 --- a/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx +++ b/src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx @@ -52,7 +52,7 @@ LaplaceXZcyclic::LaplaceXZcyclic(Mesh *m, Options *options, const CELL_LOC loc) Field2D zero(0., localmesh); one.setLocation(location); zero.setLocation(location); - setCoefs(one, zero); + LaplaceXZcyclic::setCoefs(one, zero); } void LaplaceXZcyclic::setCoefs(const Field2D &A2D, const Field2D &B2D) { diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index 122a3dd66d..5a95076c0e 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -73,7 +73,7 @@ public: FCITransform(Mesh& mesh, bool zperiodic = true) : ParallelTransform(mesh) { // check the coordinate system used for the grid data source - checkInputGrid(); + FCITransform::checkInputGrid(); auto forward_boundary = new BoundaryRegionPar("FCI_forward", BNDRY_PAR_FWD, +1, &mesh); auto backward_boundary = new BoundaryRegionPar("FCI_backward", BNDRY_PAR_BKWD, -1, &mesh); diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index f265ca0a03..f88a4ea06e 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -21,7 +21,7 @@ ShiftedMetric::ShiftedMetric(Mesh& m, CELL_LOC location_in, Field2D zShift_, zlength(zlength_in) { ASSERT1(zShift.getLocation() == location); // check the coordinate system used for the grid data source - checkInputGrid(); + ShiftedMetric::checkInputGrid(); // TwistShift should not be set for derivatives to be correct at the jump where // poloidal angle theta goes 2pi->0. zShift has been corrected for the jump From cab2044f8609fb8624347d62fa4e5b348d02c8d3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 15:29:35 +0100 Subject: [PATCH 1382/1783] Remove 'virtual' from Field::getMesh/getCoordinates --- include/field.hxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index 58f652ada1..763d633284 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -165,8 +165,8 @@ class Field { bool bndry_xin{true}, bndry_xout{true}, bndry_yup{true}, bndry_ydown{true}; #endif - virtual Mesh * getMesh() const{ - if (fieldmesh){ + Mesh* getMesh() const { + if (fieldmesh) { return fieldmesh; } else { // Don't set fieldmesh=mesh here, so that fieldmesh==nullptr until @@ -180,13 +180,13 @@ class Field { /// Returns a pointer to the coordinates object at this field's /// location from the mesh this field is on. - virtual Coordinates *getCoordinates() const; - + Coordinates* getCoordinates() const; + /// Returns a pointer to the coordinates object at the requested /// location from the mesh this field is on. If location is CELL_DEFAULT /// then return coordinates at field location - virtual Coordinates *getCoordinates(CELL_LOC loc) const; - + Coordinates* getCoordinates(CELL_LOC loc) const; + /*! * Return the number of nx points */ From abfb2559bd03a5a0dcdc2ddee76465a89ecccae9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 15:34:56 +0100 Subject: [PATCH 1383/1783] Remove some unused variables/function parameters --- .../test-invertable-operator/invertable_operator.cxx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/integrated/test-invertable-operator/invertable_operator.cxx b/tests/integrated/test-invertable-operator/invertable_operator.cxx index c85cee9cfd..1594286778 100644 --- a/tests/integrated/test-invertable-operator/invertable_operator.cxx +++ b/tests/integrated/test-invertable-operator/invertable_operator.cxx @@ -31,10 +31,8 @@ class InvertableOperatorTest : public PhysicsModel { class Laplacian* laplacianSolver; - const int nits = 10; - protected: - int init(bool restart) { + int init(bool) { SOLVE_FOR(n); SOLVE_FOR(solutionLap); SOLVE_FOR(solutionInv); @@ -62,7 +60,7 @@ class InvertableOperatorTest : public PhysicsModel { return 0; } - int rhs(BoutReal time) { + int rhs(BoutReal) { ddt(n) = 0.; ddt(solutionInv) = 0.; ddt(solutionLap) = 0.; From a54169ee3c45cd934de21eaedeaa533d03b34f56 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 16:09:54 +0100 Subject: [PATCH 1384/1783] Fix use-after-delete from strLocation --- src/mesh/interpolation.cxx | 4 ++-- src/solver/solver.cxx | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/mesh/interpolation.cxx b/src/mesh/interpolation.cxx index 4e01a7e6dd..ba93ffbdb2 100644 --- a/src/mesh/interpolation.cxx +++ b/src/mesh/interpolation.cxx @@ -30,10 +30,10 @@ #include void printLocation(const Field3D& var) { - output.write("%s", strLocation(var.getLocation())); + output << toString(var.getLocation()); } void printLocation(const Field2D& var) { - output.write("%s", strLocation(var.getLocation())); + output << toString(var.getLocation()); } const char* strLocation(CELL_LOC loc) { return toString(loc).c_str(); } diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 6c1af7ac60..f6701a22d5 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -152,7 +152,7 @@ void Solver::add(Field3D &v, const std::string name) { ddt(v).copyBoundary(v); // Set boundary to be the same as v if (mesh->StaggerGrids && (v.getLocation() != CELL_CENTRE)) { - output_info.write("\tVariable %s shifted to %s\n", name.c_str(), strLocation(v.getLocation())); + output_info.write("\tVariable %s shifted to %s\n", name.c_str(), toString(v.getLocation()).c_str()); ddt(v).setLocation(v.getLocation()); // Make sure both at the same location } @@ -1023,9 +1023,12 @@ void Solver::save_derivs(BoutReal *dudata) { } // Make sure 3D fields are at the correct cell location - for(const auto& f : f3d) { - if(f.var->getLocation() != (f.F_var)->getLocation()) { - throw BoutException(_("Time derivative at wrong location - Field is at %s, derivative is at %s for field '%s'\n"),strLocation(f.var->getLocation()), strLocation(f.F_var->getLocation()),f.name.c_str()); + for (const auto& f : f3d) { + if (f.var->getLocation() != (f.F_var)->getLocation()) { + throw BoutException(_("Time derivative at wrong location - Field is at %s, " + "derivative is at %s for field '%s'\n"), + toString(f.var->getLocation()).c_str(), + toString(f.F_var->getLocation()).c_str(), f.name.c_str()); } } From 1078f2aaf0e91c6aac3d04cc7de0fd44dbccc820 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 16:10:16 +0100 Subject: [PATCH 1385/1783] Deprecate strLocation, printLocation: just use toString(CELL_LOC) --- include/interpolation.hxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/interpolation.hxx b/include/interpolation.hxx index a78ba4999c..b27a110650 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -195,9 +195,11 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { } /// Print out the cell location (for debugging) -void printLocation(const Field3D &var); +[[gnu::deprecated("Please use `output << toString(var.getLocation())` instead")]] +void printLocation(const Field3D& var); -const char *strLocation(CELL_LOC loc); +[[gnu::deprecated("Please use `toString(loc)` instead")]] +const char* strLocation(CELL_LOC loc); /// Interpolate a field onto a perturbed set of points const Field3D interpolate(const Field3D &f, const Field3D &delta_x, From 71469fb7433f3683fc973c7a197cf7a05c2a5a7e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 16:10:43 +0100 Subject: [PATCH 1386/1783] Check error return codes in PETSc wrapper --- src/solver/impls/petsc/petsc.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/solver/impls/petsc/petsc.cxx b/src/solver/impls/petsc/petsc.cxx index 7e55a83292..924738ac06 100644 --- a/src/solver/impls/petsc/petsc.cxx +++ b/src/solver/impls/petsc/petsc.cxx @@ -167,9 +167,9 @@ int PetscSolver::init(int NOUT, BoutReal TIMESTEP) { // Set user provided RHSFunction // Need to duplicate the solution vector for the residual Vec rhs_vec; - ierr = VecDuplicate(u,&rhs_vec); + ierr = VecDuplicate(u,&rhs_vec);CHKERRQ(ierr); ierr = TSSetRHSFunction(ts,rhs_vec,solver_f,this);CHKERRQ(ierr); - ierr = VecDestroy(&rhs_vec); + ierr = VecDestroy(&rhs_vec);CHKERRQ(ierr); ///////////// GET OPTIONS ///////////// // Compute band_width_default from actually added fields, to allow for multiple Mesh objects @@ -335,7 +335,7 @@ int PetscSolver::init(int NOUT, BoutReal TIMESTEP) { ierr = PCShellSetName(pc,"PhysicsPreconditioner");CHKERRQ(ierr); // Need a callback for IJacobian to get shift 'alpha' - ierr = TSSetIJacobian(ts, Jmf, Jmf, solver_ijacobian, this); + ierr = TSSetIJacobian(ts, Jmf, Jmf, solver_ijacobian, this);CHKERRQ(ierr); // Use right preconditioner ierr = KSPSetPCSide(ksp, PC_RIGHT);CHKERRQ(ierr); @@ -471,7 +471,7 @@ int PetscSolver::init(int NOUT, BoutReal TIMESTEP) { ierr = TSComputeRHSJacobian(ts,simtime,u,&J,&J,&J_structure);CHKERRQ(ierr); #endif - ierr = PetscSynchronizedPrintf(comm, "[%d] TSComputeRHSJacobian is done\n",rank); + ierr = PetscSynchronizedPrintf(comm, "[%d] TSComputeRHSJacobian is done\n",rank);CHKERRQ(ierr); #if PETSC_VERSION_GE(3,5,0) ierr = PetscSynchronizedFlush(comm,PETSC_STDOUT);CHKERRQ(ierr); From 43a440ac8be056875e7dc2d6485062265a6dc567 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 16:11:07 +0100 Subject: [PATCH 1387/1783] Bugfix: fix assignment instead of comparison in ASSERT --- src/mesh/boundary_standard.cxx | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index bff082d020..020b8f0333 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -127,7 +127,7 @@ void BoundaryDirichlet::apply(Field2D &f,BoutReal t) { // N.B. Only first guard cells (closest to the grid) should ever be used Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); bndry->first(); // Decide which generator to use @@ -316,7 +316,7 @@ void BoundaryDirichlet::apply(Field3D &f,BoutReal t) { // N.B. Only first guard cells (closest to the grid) should ever be used Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); bndry->first(); // Decide which generator to use @@ -555,7 +555,7 @@ void BoundaryDirichlet::apply_ddt(Field2D &f) { void BoundaryDirichlet::apply_ddt(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -585,7 +585,7 @@ void BoundaryDirichlet_O3::apply(Field2D &f,BoutReal t) { // N.B. Only first guard cells (closest to the grid) should ever be used Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); bndry->first(); // Decide which generator to use @@ -772,7 +772,7 @@ void BoundaryDirichlet_O3::apply(Field3D &f,BoutReal t) { // N.B. Only first guard cells (closest to the grid) should ever be used Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); bndry->first(); // Decide which generator to use @@ -973,7 +973,7 @@ void BoundaryDirichlet_O3::apply_ddt(Field2D &f) { void BoundaryDirichlet_O3::apply_ddt(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Field3D *dt = f.timeDeriv(); bndry->first() ; @@ -1006,7 +1006,7 @@ void BoundaryDirichlet_O4::apply(Field2D &f,BoutReal t) { // N.B. Only first guard cells (closest to the grid) should ever be used Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); bndry->first(); // Decide which generator to use @@ -1205,7 +1205,7 @@ void BoundaryDirichlet_O4::apply(Field3D &f,BoutReal t) { // N.B. Only first guard cells (closest to the grid) should ever be used Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); bndry->first(); // Decide which generator to use @@ -1411,7 +1411,7 @@ void BoundaryDirichlet_O4::apply_ddt(Field2D &f) { void BoundaryDirichlet_O4::apply_ddt(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -1441,7 +1441,7 @@ void BoundaryDirichlet_4thOrder::apply(Field2D &f) { void BoundaryDirichlet_4thOrder::apply(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); // Set (at 4th order) the value at the mid-point between the guard cell and the grid cell to be val for(bndry->first(); !bndry->isDone(); bndry->next1d()) for(int z=0;zLocalNz;z++) { @@ -1458,7 +1458,7 @@ void BoundaryDirichlet_4thOrder::apply_ddt(Field2D &f) { void BoundaryDirichlet_4thOrder::apply_ddt(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -1480,7 +1480,7 @@ BoundaryOp* BoundaryNeumann_NonOrthogonal::clone(BoundaryRegion *region, const s void BoundaryNeumann_NonOrthogonal::apply(Field2D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Coordinates *metric = f.getCoordinates(); // Calculate derivatives for metric use mesh->communicate(f); @@ -1522,7 +1522,7 @@ void BoundaryNeumann_NonOrthogonal::apply(Field2D &f) { void BoundaryNeumann_NonOrthogonal::apply(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Coordinates *metric = f.getCoordinates(); // Calculate derivatives for metric use mesh->communicate(f); @@ -1589,7 +1589,7 @@ void BoundaryNeumann::apply(Field2D &f,BoutReal t) { // N.B. Only first guard cells (closest to the grid) should ever be used Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Coordinates *metric = f.getCoordinates(); bndry->first(); @@ -1788,7 +1788,7 @@ void BoundaryNeumann::apply(Field3D &f) { void BoundaryNeumann::apply(Field3D &f,BoutReal t) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Coordinates *metric = f.getCoordinates(); bndry->first(); @@ -1993,7 +1993,7 @@ void BoundaryNeumann::apply_ddt(Field2D &f) { void BoundaryNeumann::apply_ddt(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -2017,7 +2017,7 @@ void BoundaryNeumann_O4::apply(Field2D &f) { void BoundaryNeumann_O4::apply(Field2D &f,BoutReal t) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); // Set (at 4th order) the value at the mid-point between the guard cell and the grid cell to be val // N.B. Only first guard cells (closest to the grid) should ever be used From ee30f66d3937b61bab207d773438d53cda4c1665 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 17:10:27 +0100 Subject: [PATCH 1388/1783] Pass std::string by value and move when taking a copy --- include/bout/sys/expressionparser.hxx | 2 +- src/sys/expressionparser.cxx | 5 ++--- src/sys/options/options_netcdf.cxx | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/bout/sys/expressionparser.hxx b/include/bout/sys/expressionparser.hxx index 4f35201050..34ff468659 100644 --- a/include/bout/sys/expressionparser.hxx +++ b/include/bout/sys/expressionparser.hxx @@ -125,7 +125,7 @@ private: /// Lexing info, used when splitting input into tokens struct LexInfo { - LexInfo(const std::string& input, const std::string& reserved_chars = ""); + LexInfo(const std::string& input, std::string reserved_chars = ""); /// Current token. -1 for number, -2 for string, 0 for "end of input" signed char curtok = 0; diff --git a/src/sys/expressionparser.cxx b/src/sys/expressionparser.cxx index ede1469415..c2aff81960 100644 --- a/src/sys/expressionparser.cxx +++ b/src/sys/expressionparser.cxx @@ -292,9 +292,8 @@ FieldGeneratorPtr ExpressionParser::parseExpression(LexInfo& lex) const { ////////////////////////////////////////////////////////// // LexInfo -ExpressionParser::LexInfo::LexInfo(const std::string& input, - const std::string& reserved_chars) - : reserved_chars(reserved_chars) { +ExpressionParser::LexInfo::LexInfo(const std::string& input, std::string reserved_chars) + : reserved_chars(std::move(reserved_chars)) { ss.clear(); ss.str(input); // Set the input stream ss.seekg(0, std::ios_base::beg); diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 80d96f98b7..8a7813fe13 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -323,7 +323,7 @@ void NcPutVarCountVisitor::operator()(const Field3D& value) { /// Visit a variant type, and put the data into an attributute struct NcPutAttVisitor { - NcPutAttVisitor(NcVar& var, std::string name) : var(var), name(name) {} + NcPutAttVisitor(NcVar& var, std::string name) : var(var), name(std::move(name)) {} template void operator()(const T& UNUSED(value)) { // Default is to ignore if unhandled From fb909110d685fc43c6bfcabfa7901b04537463c6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 17:16:54 +0100 Subject: [PATCH 1389/1783] Replaced deprecated std::random_shuffle with std::shuffle --- tests/unit/include/bout/test_region.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/unit/include/bout/test_region.cxx b/tests/unit/include/bout/test_region.cxx index 07f119c6e9..60ceb88e64 100644 --- a/tests/unit/include/bout/test_region.cxx +++ b/tests/unit/include/bout/test_region.cxx @@ -10,9 +10,10 @@ #include #include -#include +#include #include #include +#include /// Global mesh namespace bout{ @@ -358,7 +359,7 @@ TEST_F(RegionTest, regionAsSorted) { Region::RegionIndices regionIndicesSortedIn = regionSortedIn.getIndices(); // Now shuffle the order and create a new region - std::random_shuffle(std::begin(indicesIn), std::end(indicesIn)); + std::shuffle(std::begin(indicesIn), std::end(indicesIn), std::mt19937()); Region regionShuffledIn(indicesIn); Region::RegionIndices regionIndicesShuffledIn = regionShuffledIn.getIndices(); // Should we check the shuffle has actually changed the index order? From 62570a09ba54d4c29e5a38241048da914c7c19b6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 17:17:27 +0100 Subject: [PATCH 1390/1783] Use emplace_back rather than push_back in RegionTest --- tests/unit/include/bout/test_region.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/include/bout/test_region.cxx b/tests/unit/include/bout/test_region.cxx index 60ceb88e64..b2a1ce50f6 100644 --- a/tests/unit/include/bout/test_region.cxx +++ b/tests/unit/include/bout/test_region.cxx @@ -76,7 +76,7 @@ TEST_F(RegionTest, regionFromIndices) { maxContiguousSizeUsed = currBlockSize > maxContiguousSizeUsed ? currBlockSize : maxContiguousSizeUsed; for (int i = block.first; i <= block.second; i++) { - indicesIn.push_back(Ind3D{i}); + indicesIn.emplace_back(i); } } From 4a851cbb6ad29197652edfc06a3101b19f202583 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 17:27:06 +0100 Subject: [PATCH 1391/1783] Use nullptr instead of NULL --- tests/MMS/diffusion/diffusion.cxx | 2 +- tests/integrated/test-laplace/test_laplace.cxx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/MMS/diffusion/diffusion.cxx b/tests/MMS/diffusion/diffusion.cxx index 3259759c8f..17453cf77f 100644 --- a/tests/MMS/diffusion/diffusion.cxx +++ b/tests/MMS/diffusion/diffusion.cxx @@ -89,7 +89,7 @@ int physics_init(bool UNUSED(restarting)) { source.allocate(); SAVE_REPEAT(source); - error_monitor.call(NULL, 0, 0, 0); + error_monitor.call(nullptr, 0, 0, 0); solver->addMonitor(&error_monitor); return 0; diff --git a/tests/integrated/test-laplace/test_laplace.cxx b/tests/integrated/test-laplace/test_laplace.cxx index 138fdac619..1638ca5c11 100644 --- a/tests/integrated/test-laplace/test_laplace.cxx +++ b/tests/integrated/test-laplace/test_laplace.cxx @@ -32,8 +32,8 @@ int main(int argc, char **argv) { Field3D flag3ac = invert_laplace(input, 3, &a, &c); SAVE_ONCE2(flag0ac, flag3ac); - Field3D flag0ad = invert_laplace(input, 0, &a, NULL, &d); - Field3D flag3ad = invert_laplace(input, 3, &a, NULL, &d); + Field3D flag0ad = invert_laplace(input, 0, &a, nullptr, &d); + Field3D flag3ad = invert_laplace(input, 3, &a, nullptr, &d); SAVE_ONCE2(flag0ad, flag3ad); /// Test new interface and INVERT_IN/OUT_SET flags From 92ccaa6a463bbfcd7b9586b1123b43cf3ab456a1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 17:31:32 +0100 Subject: [PATCH 1392/1783] Convert some for-loops to range-based --- src/solver/impls/imex-bdf2/imex-bdf2.cxx | 12 ++++++------ tests/unit/include/bout/test_region.cxx | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/solver/impls/imex-bdf2/imex-bdf2.cxx b/src/solver/impls/imex-bdf2/imex-bdf2.cxx index b78cc10e49..ee6cb8b149 100644 --- a/src/solver/impls/imex-bdf2/imex-bdf2.cxx +++ b/src/solver/impls/imex-bdf2/imex-bdf2.cxx @@ -1318,10 +1318,10 @@ void IMEXBDF2::loopVars(BoutReal *u) { Mesh* mesh = bout::globals::mesh; // Loop over 2D variables - for(auto it = f2d.begin(); it != f2d.end(); ++it) { - Op op(it->var, it->F_var); // Initialise the operator + for(auto & it : f2d) { + Op op(it.var, it.F_var); // Initialise the operator - if(it->evolve_bndry) { + if(it.evolve_bndry) { // Include boundary regions // Inner X @@ -1362,9 +1362,9 @@ void IMEXBDF2::loopVars(BoutReal *u) { } // Loop over 3D variables - for(auto it = f3d.begin(); it != f3d.end(); ++it) { - Op op(it->var, it->F_var); // Initialise the operator - if(it->evolve_bndry) { + for(auto & it : f3d) { + Op op(it.var, it.F_var); // Initialise the operator + if(it.evolve_bndry) { // Include boundary regions // Inner X diff --git a/tests/unit/include/bout/test_region.cxx b/tests/unit/include/bout/test_region.cxx index b2a1ce50f6..661151c3d4 100644 --- a/tests/unit/include/bout/test_region.cxx +++ b/tests/unit/include/bout/test_region.cxx @@ -643,8 +643,8 @@ TEST_F(RegionTest, regionMask) { EXPECT_EQ(masked1Indices.size(), indicesIn.size() - indicesMask1.size()); // Check values - for (unsigned int i = 0; i < masked1Indices.size(); i++) { - EXPECT_EQ((masked1Indices[i] % 2).ind, 0); + for (auto& masked1Index : masked1Indices) { + EXPECT_EQ((masked1Index % 2).ind, 0); } // Check size of other regions not changed @@ -703,8 +703,8 @@ TEST_F(RegionTest, regionFriendMask) { EXPECT_EQ(masked1Indices.size(), indicesIn.size() - indicesMask1.size()); // Check values - for (unsigned int i = 0; i < masked1Indices.size(); i++) { - EXPECT_EQ((masked1Indices[i] % 2).ind, 0); + for (auto& masked1Index : masked1Indices) { + EXPECT_EQ((masked1Index % 2).ind, 0); } // Check size of other regions not changed From 6cc405987c2a134778ff686ffbba730718f375f3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 17:32:30 +0100 Subject: [PATCH 1393/1783] Remove redundant void argument in function casts --- src/solver/impls/imex-bdf2/imex-bdf2.cxx | 2 +- src/solver/impls/petsc/petsc.cxx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/solver/impls/imex-bdf2/imex-bdf2.cxx b/src/solver/impls/imex-bdf2/imex-bdf2.cxx index ee6cb8b149..d7461efee1 100644 --- a/src/solver/impls/imex-bdf2/imex-bdf2.cxx +++ b/src/solver/impls/imex-bdf2/imex-bdf2.cxx @@ -616,7 +616,7 @@ void IMEXBDF2::constructSNES(SNES *snesIn){ ISColoringDestroy(&iscoloring); // Set the function to difference //MatFDColoringSetFunction(fdcoloring,(PetscErrorCode (*)(void))FormFunctionForDifferencing,this); - MatFDColoringSetFunction(fdcoloring,(PetscErrorCode (*)(void))FormFunctionForColoring,this); + MatFDColoringSetFunction(fdcoloring,(PetscErrorCode (*)())FormFunctionForColoring,this); MatFDColoringSetFromOptions(fdcoloring); //MatFDColoringSetUp(Jmf,iscoloring,fdcoloring); diff --git a/src/solver/impls/petsc/petsc.cxx b/src/solver/impls/petsc/petsc.cxx index 924738ac06..f38e8d2ff7 100644 --- a/src/solver/impls/petsc/petsc.cxx +++ b/src/solver/impls/petsc/petsc.cxx @@ -294,7 +294,7 @@ int PetscSolver::init(int NOUT, BoutReal TIMESTEP) { if(use_jacobian && (jacfunc != nullptr)) { // Use a user-supplied Jacobian function ierr = MatCreateShell(comm, local_N, local_N, neq, neq, this, &Jmf); CHKERRQ(ierr); - ierr = MatShellSetOperation(Jmf, MATOP_MULT, (void (*)(void)) PhysicsJacobianApply); CHKERRQ(ierr); + ierr = MatShellSetOperation(Jmf, MATOP_MULT, (void (*)()) PhysicsJacobianApply); CHKERRQ(ierr); ierr = TSSetIJacobian(ts, Jmf, Jmf, solver_ijacobian, this); CHKERRQ(ierr); }else { // Use finite difference approximation @@ -452,7 +452,7 @@ int PetscSolver::init(int NOUT, BoutReal TIMESTEP) { ierr = MatFDColoringSetFromOptions(matfdcoloring);CHKERRQ(ierr); ierr = ISColoringDestroy(&iscoloring);CHKERRQ(ierr); - ierr = MatFDColoringSetFunction(matfdcoloring,(PetscErrorCode (*)(void))solver_f,this);CHKERRQ(ierr); + ierr = MatFDColoringSetFunction(matfdcoloring,(PetscErrorCode (*)())solver_f,this);CHKERRQ(ierr); ierr = SNESSetJacobian(snes,J,J,SNESComputeJacobianDefaultColor,matfdcoloring);CHKERRQ(ierr); // Write J in binary for study - see ~petsc/src/mat/examples/tests/ex124.c From 20c5f3320e34806f2f85d5b084fa6084ccdd686e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 8 May 2019 17:38:25 +0100 Subject: [PATCH 1394/1783] Use auto when type is named on rhs of assignment --- src/field/field2d.cxx | 4 ++-- src/field/field3d.cxx | 10 +++++----- src/field/field_data.cxx | 4 ++-- src/field/globalfield.cxx | 4 ++-- src/fileio/impls/hdf5/h5_format.cxx | 2 +- src/invert/parderiv/impls/cyclic/cyclic.cxx | 3 +-- src/mesh/boundary_factory.cxx | 2 +- src/mesh/boundary_standard.cxx | 8 ++++---- src/mesh/impls/bout/boutmesh.cxx | 2 +- src/solver/impls/arkode/arkode.cxx | 10 +++++----- src/solver/impls/cvode/cvode.cxx | 6 +++--- src/solver/impls/ida/ida.cxx | 4 ++-- src/solver/impls/petsc/petsc.cxx | 6 +++--- tests/integrated/test-cyclic/test_cyclic.cxx | 3 +-- .../test-naulin-laplace/test_naulin_laplace.cxx | 2 +- 15 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 627c36c58f..a76345b591 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -226,7 +226,7 @@ void Field2D::applyBoundary(const std::string &condition) { /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundaries()) { - BoundaryOp* op = static_cast(bfact->create(condition, reg)); + auto* op = static_cast(bfact->create(condition, reg)); op->apply(*this); delete op; } @@ -262,7 +262,7 @@ void Field2D::applyBoundary(const std::string ®ion, const std::string &condit for (const auto ® : fieldmesh->getBoundaries()) { if (reg->label.compare(region) == 0) { region_found = true; - BoundaryOp *op = static_cast(bfact->create(condition, reg)); + auto *op = static_cast(bfact->create(condition, reg)); op->apply(*this); delete op; break; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index ddeecdb135..91705f12fe 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -400,7 +400,7 @@ void Field3D::applyBoundary(const std::string &condition) { /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundaries()) { - BoundaryOp* op = static_cast(bfact->create(condition, reg)); + auto* op = static_cast(bfact->create(condition, reg)); op->apply(*this); delete op; } @@ -420,7 +420,7 @@ void Field3D::applyBoundary(const std::string ®ion, const std::string &condit for (const auto ® : fieldmesh->getBoundaries()) { if (reg->label.compare(region) == 0) { region_found = true; - BoundaryOp *op = static_cast(bfact->create(condition, reg)); + auto *op = static_cast(bfact->create(condition, reg)); op->apply(*this); delete op; break; @@ -527,7 +527,7 @@ void Field3D::applyParallelBoundary(const std::string &condition) { /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundariesPar()) { - BoundaryOpPar* op = static_cast(bfact->create(condition, reg)); + auto* op = static_cast(bfact->create(condition, reg)); op->apply(*this); delete op; } @@ -552,7 +552,7 @@ void Field3D::applyParallelBoundary(const std::string ®ion, const std::string /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundariesPar()) { if(reg->label.compare(region) == 0) { - BoundaryOpPar* op = static_cast(bfact->create(condition, reg)); + auto* op = static_cast(bfact->create(condition, reg)); op->apply(*this); delete op; break; @@ -581,7 +581,7 @@ void Field3D::applyParallelBoundary(const std::string ®ion, const std::string if(reg->label.compare(region) == 0) { // BoundaryFactory can't create boundaries using Field3Ds, so get temporary // boundary of the right type - BoundaryOpPar* tmp = static_cast(bfact->create(condition, reg)); + auto* tmp = static_cast(bfact->create(condition, reg)); // then clone that with the actual argument BoundaryOpPar* op = tmp->clone(reg, f); op->apply(*this); diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 8282f9cda4..520ed8a1be 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -22,7 +22,7 @@ void FieldData::setBoundary(const std::string &name) { output_info << "Setting boundary for variable " << name << endl; /// Loop over the mesh boundary regions for(const auto& reg : bout::globals::mesh->getBoundaries()) { - BoundaryOp* op = static_cast(bfact->createFromOptions(name, reg)); + auto* op = static_cast(bfact->createFromOptions(name, reg)); if (op != nullptr) bndry_op.push_back(op); output_info << endl; @@ -32,7 +32,7 @@ void FieldData::setBoundary(const std::string &name) { std::vector par_reg = bout::globals::mesh->getBoundariesPar(); /// Loop over the mesh parallel boundary regions for(const auto& reg : bout::globals::mesh->getBoundariesPar()) { - BoundaryOpPar* op = static_cast(bfact->createFromOptions(name, reg)); + auto* op = static_cast(bfact->createFromOptions(name, reg)); if (op != nullptr) bndry_op_par.push_back(op); output_info << endl; diff --git a/src/field/globalfield.cxx b/src/field/globalfield.cxx index a9991c1e65..33a03e0ecc 100644 --- a/src/field/globalfield.cxx +++ b/src/field/globalfield.cxx @@ -112,7 +112,7 @@ void GlobalField2D::gather(const Field2D &f) { if(mype == data_on_proc) { // This processor will receive the data - MPI_Request* req = new MPI_Request[npes]; // Array of receive handles + auto* req = new MPI_Request[npes]; // Array of receive handles // Post receives for(int p = 0; p < npes; p++) { @@ -275,7 +275,7 @@ void GlobalField3D::gather(const Field3D &f) { if(mype == data_on_proc) { // This processor will receive the data - MPI_Request* req = new MPI_Request[npes]; // Array of receive handles + auto* req = new MPI_Request[npes]; // Array of receive handles // Post receives for(int p = 0; p < npes; p++) { diff --git a/src/fileio/impls/hdf5/h5_format.cxx b/src/fileio/impls/hdf5/h5_format.cxx index 6b9af4a99b..226ed502b9 100644 --- a/src/fileio/impls/hdf5/h5_format.cxx +++ b/src/fileio/impls/hdf5/h5_format.cxx @@ -203,7 +203,7 @@ const std::vector H5Format::getSize(const char *name) { return size; } else { - hsize_t* dims = new hsize_t[nd]; + auto* dims = new hsize_t[nd]; int error = H5Sget_simple_extent_dims(dataSpace, dims, nullptr); if (error < 0) throw BoutException("Failed to get dimensions of dataSpace"); diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index 3fd8eaeb61..72e8b93bdc 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -68,8 +68,7 @@ const Field3D InvertParCR::solve(const Field3D &f) { Field3D alignedField = toFieldAligned(f, RGN_NOX); // Create cyclic reduction object - CyclicReduce *cr = - new CyclicReduce(); + auto* cr = new CyclicReduce(); // Find out if we are on a boundary int size = localmesh->LocalNy - 2 * localmesh->ystart; diff --git a/src/mesh/boundary_factory.cxx b/src/mesh/boundary_factory.cxx index e2454d7371..76c7b6928e 100644 --- a/src/mesh/boundary_factory.cxx +++ b/src/mesh/boundary_factory.cxx @@ -170,7 +170,7 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * BoundaryModifier *mod = findBoundaryMod(func); if (mod != nullptr) { // The first argument should be an operation - BoundaryOp *op = static_cast(create(arglist.front(), region)); + auto* op = static_cast(create(arglist.front(), region)); if (op == nullptr) return nullptr; diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 020b8f0333..60df63a8d3 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -3197,7 +3197,7 @@ void BoundaryFree_O3::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryRelax::cloneMod(BoundaryOp *operation, const std::list &args) { - BoundaryRelax* result = new BoundaryRelax(operation, r); + auto* result = new BoundaryRelax(operation, r); if(!args.empty()) { // First argument should be the rate @@ -3255,7 +3255,7 @@ void BoundaryRelax::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryWidth::cloneMod(BoundaryOp *operation, const std::list &args) { - BoundaryWidth* result = new BoundaryWidth(operation, width); + auto* result = new BoundaryWidth(operation, width); if(args.empty()) { output << "WARNING: BoundaryWidth expected 1 argument\n"; @@ -3299,7 +3299,7 @@ void BoundaryWidth::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryToFieldAligned::cloneMod(BoundaryOp *operation, const std::list &args) { - BoundaryToFieldAligned* result = new BoundaryToFieldAligned(operation); + auto* result = new BoundaryToFieldAligned(operation); if(!args.empty()) { output << "WARNING: BoundaryToFieldAligned expected no argument\n"; @@ -3346,7 +3346,7 @@ void BoundaryToFieldAligned::apply_ddt(Field3D &f) { /////////////////////////////////////////////////////////////// BoundaryOp* BoundaryFromFieldAligned::cloneMod(BoundaryOp *operation, const std::list &args) { - BoundaryFromFieldAligned* result = new BoundaryFromFieldAligned(operation); + auto* result = new BoundaryFromFieldAligned(operation); if(!args.empty()) { output << "WARNING: BoundaryFromFieldAligned expected no argument\n"; diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 0b351f3374..12b0570c42 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -1078,7 +1078,7 @@ int BoutMesh::wait(comm_handle handle) { if (handle == nullptr) return 1; - CommHandle *ch = static_cast(handle); + auto* ch = static_cast(handle); if (!ch->in_progress) return 2; diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index 747288e499..8518d1268c 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -691,7 +691,7 @@ static int arkode_rhs_explicit(BoutReal t, N_Vector u, N_Vector du, void* user_d BoutReal* udata = NV_DATA_P(u); BoutReal* dudata = NV_DATA_P(du); - ArkodeSolver* s = static_cast(user_data); + auto* s = static_cast(user_data); // Calculate RHS function try { @@ -707,7 +707,7 @@ static int arkode_rhs_implicit(BoutReal t, N_Vector u, N_Vector du, void* user_d BoutReal* udata = NV_DATA_P(u); BoutReal* dudata = NV_DATA_P(du); - ArkodeSolver* s = static_cast(user_data); + auto* s = static_cast(user_data); // Calculate RHS function try { @@ -723,7 +723,7 @@ static int arkode_rhs(BoutReal t, N_Vector u, N_Vector du, void* user_data) { BoutReal* udata = NV_DATA_P(u); BoutReal* dudata = NV_DATA_P(du); - ArkodeSolver* s = static_cast(user_data); + auto* s = static_cast(user_data); // Calculate RHS function try { @@ -748,7 +748,7 @@ static int arkode_pre(BoutReal t, N_Vector yy, N_Vector UNUSED(yp), N_Vector rve BoutReal* rdata = NV_DATA_P(rvec); BoutReal* zdata = NV_DATA_P(zvec); - ArkodeSolver* s = static_cast(user_data); + auto* s = static_cast(user_data); // Calculate residuals s->pre(t, gamma, delta, udata, rdata, zdata); @@ -763,7 +763,7 @@ static int arkode_jac(N_Vector v, N_Vector Jv, realtype t, N_Vector y, BoutReal* vdata = NV_DATA_P(v); ///< Input vector BoutReal* Jvdata = NV_DATA_P(Jv); ///< Jacobian*vector output - ArkodeSolver* s = static_cast(user_data); + auto* s = static_cast(user_data); s->jac(t, ydata, vdata, Jvdata); diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index 682de9bcc4..d6ee3360e1 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -569,7 +569,7 @@ static int cvode_rhs(BoutReal t, N_Vector u, N_Vector du, void* user_data) { BoutReal* udata = NV_DATA_P(u); BoutReal* dudata = NV_DATA_P(du); - CvodeSolver* s = static_cast(user_data); + auto* s = static_cast(user_data); // Calculate RHS function try { @@ -594,7 +594,7 @@ static int cvode_pre(BoutReal t, N_Vector yy, N_Vector UNUSED(yp), N_Vector rvec BoutReal* rdata = NV_DATA_P(rvec); BoutReal* zdata = NV_DATA_P(zvec); - CvodeSolver* s = static_cast(user_data); + auto* s = static_cast(user_data); // Calculate residuals s->pre(t, gamma, delta, udata, rdata, zdata); @@ -609,7 +609,7 @@ static int cvode_jac(N_Vector v, N_Vector Jv, realtype t, N_Vector y, N_Vector U BoutReal* vdata = NV_DATA_P(v); ///< Input vector BoutReal* Jvdata = NV_DATA_P(Jv); ///< Jacobian*vector output - CvodeSolver* s = static_cast(user_data); + auto* s = static_cast(user_data); s->jac(t, ydata, vdata, Jvdata); diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index 9bbc34dd77..701c8597d2 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -353,7 +353,7 @@ static int idares(BoutReal t, N_Vector u, N_Vector du, N_Vector rr, void* user_d BoutReal* dudata = NV_DATA_P(du); BoutReal* rdata = NV_DATA_P(rr); - IdaSolver* s = static_cast(user_data); + auto* s = static_cast(user_data); // Calculate residuals s->res(t, udata, dudata, rdata); @@ -375,7 +375,7 @@ static int ida_pre(BoutReal t, N_Vector yy, N_Vector UNUSED(yp), N_Vector UNUSED BoutReal* rdata = NV_DATA_P(rvec); BoutReal* zdata = NV_DATA_P(zvec); - IdaSolver* s = static_cast(user_data); + auto* s = static_cast(user_data); // Calculate residuals s->pre(t, cj, delta, udata, rdata, zdata); diff --git a/src/solver/impls/petsc/petsc.cxx b/src/solver/impls/petsc/petsc.cxx index f38e8d2ff7..8d6562b73d 100644 --- a/src/solver/impls/petsc/petsc.cxx +++ b/src/solver/impls/petsc/petsc.cxx @@ -708,7 +708,7 @@ PetscErrorCode solver_ijacobian(TS ts, BoutReal t, Vec globalin, Vec UNUSED(glob ierr = solver_rhsjacobian(ts, t, globalin, J, Jpre, f_data); CHKERRQ(ierr); ////// Save data for preconditioner - PetscSolver *solver = (PetscSolver*) f_data; + auto* solver = (PetscSolver*)f_data; if(solver->diagnose) output << "Saving state, t = " << t << ", a = " << a << endl; @@ -840,7 +840,7 @@ PetscErrorCode PhysicsJacobianApply(Mat J, Vec x, Vec y) { #define __FUNCT__ "PetscMonitor" PetscErrorCode PetscMonitor(TS ts, PetscInt UNUSED(step), PetscReal t, Vec X, void *ctx) { PetscErrorCode ierr; - PetscSolver *s = (PetscSolver *)ctx; + auto *s = (PetscSolver *)ctx; PetscReal tfinal, dt; Vec interpolatedX; const PetscScalar *x; @@ -887,7 +887,7 @@ PetscErrorCode PetscSNESMonitor(SNES snes, PetscInt its, PetscReal norm, void *c PetscInt linear_its=0; BoutReal tmp = .0; snes_info row; - PetscSolver *s = (PetscSolver*)ctx; + auto *s = (PetscSolver*)ctx; PetscFunctionBegin; diff --git a/tests/integrated/test-cyclic/test_cyclic.cxx b/tests/integrated/test-cyclic/test_cyclic.cxx index 745e7f1c47..113e23192d 100644 --- a/tests/integrated/test-cyclic/test_cyclic.cxx +++ b/tests/integrated/test-cyclic/test_cyclic.cxx @@ -30,8 +30,7 @@ int main(int argc, char **argv) { OPTION(options, periodic, false); // Create a cyclic reduction object, operating on Ts - CyclicReduce *cr = - new CyclicReduce(BoutComm::get(), n); + auto* cr = new CyclicReduce(BoutComm::get(), n); int mype, npe; MPI_Comm_rank(BoutComm::get(), &mype); diff --git a/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx b/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx index b2873903ac..bbaa1cbf59 100644 --- a/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx +++ b/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx @@ -43,7 +43,7 @@ int main(int argc, char** argv) { //class Laplacian* invert = Laplacian::create(); Options* options = Options::getRoot()->getSection("laplace"); - LaplaceNaulin* invert = new LaplaceNaulin(options); + auto* invert = new LaplaceNaulin(options); // Solving equations of the form d*Grad_perp2(f) + 1/c*Grad_perp(c).Grad_perp(f) + a*f = b for various boundary conditions Field3D f1,a1,b1,c1,d1,sol1,bcheck1; From 585d55eb0107fd2f0528c0ae1f832855c70a8439 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 09:41:02 +0100 Subject: [PATCH 1395/1783] Update deprecated std C++ headers in integrated tests --- tests/MMS/diffusion/diffusion.cxx | 2 +- tests/MMS/wave-1d/wave.cxx | 2 +- tests/integrated/test-drift-instability/2fluid.cxx | 6 +++--- tests/integrated/test-interchange-instability/2fluid.cxx | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/MMS/diffusion/diffusion.cxx b/tests/MMS/diffusion/diffusion.cxx index 17453cf77f..c764a7ee2c 100644 --- a/tests/MMS/diffusion/diffusion.cxx +++ b/tests/MMS/diffusion/diffusion.cxx @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include "mathematica.h" #include #include diff --git a/tests/MMS/wave-1d/wave.cxx b/tests/MMS/wave-1d/wave.cxx index 0e87965ec3..57e3185f96 100644 --- a/tests/MMS/wave-1d/wave.cxx +++ b/tests/MMS/wave-1d/wave.cxx @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "mathematica.h" #include #include diff --git a/tests/integrated/test-drift-instability/2fluid.cxx b/tests/integrated/test-drift-instability/2fluid.cxx index 75bade9a81..3bc11ab6b5 100644 --- a/tests/integrated/test-drift-instability/2fluid.cxx +++ b/tests/integrated/test-drift-instability/2fluid.cxx @@ -11,9 +11,9 @@ #include #include -#include -#include -#include +#include +#include +#include // 2D initial profiles Field2D Ni0, Ti0, Te0, Vi0, phi0, Ve0, rho0, Ajpar0; diff --git a/tests/integrated/test-interchange-instability/2fluid.cxx b/tests/integrated/test-interchange-instability/2fluid.cxx index 09fa27bf0c..9be72f4d39 100644 --- a/tests/integrated/test-interchange-instability/2fluid.cxx +++ b/tests/integrated/test-interchange-instability/2fluid.cxx @@ -10,9 +10,9 @@ #include #include -#include -#include -#include +#include +#include +#include class Interchange : public PhysicsModel { From cba2f8c8e035b949502ca1ea9cc03a4a72bb942f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 09:41:56 +0100 Subject: [PATCH 1396/1783] Use default member init in GridFromOptionsTest --- tests/unit/mesh/data/test_gridfromoptions.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/mesh/data/test_gridfromoptions.cxx b/tests/unit/mesh/data/test_gridfromoptions.cxx index 3949454002..2f762eb594 100644 --- a/tests/unit/mesh/data/test_gridfromoptions.cxx +++ b/tests/unit/mesh/data/test_gridfromoptions.cxx @@ -16,7 +16,7 @@ using namespace bout::globals; class GridFromOptionsTest : public ::testing::Test { public: - GridFromOptionsTest() : options(), griddata(nullptr) { + GridFromOptionsTest() : options() { mesh_from_options.StaggerGrids = true; mesh_from_options.xstart = 2; @@ -78,7 +78,7 @@ class GridFromOptionsTest : public ::testing::Test { std::shared_ptr test_coords; Options options; - GridFromOptions* griddata; + GridFromOptions* griddata{nullptr}; std::string expected_string{"x + y + z + 3"}; Field2D expected_2d; Field3D expected_3d; From bb2faf71ca132c9fd3c7d22e6ca892b678b1cb4f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 10:01:34 +0100 Subject: [PATCH 1397/1783] Use unique_ptr instead of new/delete in BOUTMAIN --- include/bout/physicsmodel.hxx | 48 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/include/bout/physicsmodel.hxx b/include/bout/physicsmodel.hxx index 8f4f3266d1..b8f58635e8 100644 --- a/include/bout/physicsmodel.hxx +++ b/include/bout/physicsmodel.hxx @@ -42,6 +42,7 @@ class PhysicsModel; #include #include "solver.hxx" #include "unused.hxx" +#include "utils.hxx" #include "bout/macro_for_each.hxx" /*! @@ -298,31 +299,28 @@ private: * * BOUTMAIN(MyModel); */ -#define BOUTMAIN(ModelClass) \ - int main(int argc, char **argv) { \ - int init_err = BoutInitialise(argc, argv); \ - if (init_err < 0) \ - return 0; \ - else if (init_err > 0) \ - return init_err; \ - try { \ - ModelClass *model = new ModelClass(); \ - Solver *solver = Solver::create(); \ - solver->setModel(model); \ - Monitor * bout_monitor = new BoutMonitor(); \ - solver->addMonitor(bout_monitor, Solver::BACK); \ - solver->outputVars(bout::globals::dump); \ - solver->solve(); \ - delete model; \ - delete solver; \ - delete bout_monitor; \ - } catch (const BoutException &e) { \ - output << "Error encountered\n"; \ - output << e.getBacktrace() << endl; \ - MPI_Abort(BoutComm::get(), 1); \ - } \ - BoutFinalise(); \ - return 0; \ +#define BOUTMAIN(ModelClass) \ + int main(int argc, char** argv) { \ + int init_err = BoutInitialise(argc, argv); \ + if (init_err < 0) \ + return 0; \ + else if (init_err > 0) \ + return init_err; \ + try { \ + auto model = bout::utils::make_unique(); \ + auto solver = std::unique_ptr(Solver::create()); \ + solver->setModel(model.get()); \ + auto bout_monitor = bout::utils::make_unique(); \ + solver->addMonitor(bout_monitor.get(), Solver::BACK); \ + solver->outputVars(bout::globals::dump); \ + solver->solve(); \ + } catch (const BoutException& e) { \ + output << "Error encountered\n"; \ + output << e.getBacktrace() << endl; \ + MPI_Abort(BoutComm::get(), 1); \ + } \ + BoutFinalise(); \ + return 0; \ } /// Macro to replace solver->add, passing variable name From 76c9a486c11d4dc7f038b137c20240e1b1996b48 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 11:05:09 +0100 Subject: [PATCH 1398/1783] Remove or =default empty destructors --- include/bout/globalfield.hxx | 2 +- include/bout/physicsmodel.hxx | 2 +- include/bout/rkscheme.hxx | 2 +- include/invert_parderiv.hxx | 4 ++-- src/field/globalfield.cxx | 4 ---- src/invert/parderiv/impls/cyclic/cyclic.cxx | 3 --- src/invert/parderiv/impls/cyclic/cyclic.hxx | 1 - src/physics/physicsmodel.cxx | 3 --- src/solver/impls/rk4/rk4.cxx | 3 --- src/solver/impls/rk4/rk4.hxx | 1 - src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx | 6 ------ src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.hxx | 9 +++------ src/solver/impls/rkgeneric/impls/rk4simple/rk4simple.cxx | 5 ----- src/solver/impls/rkgeneric/impls/rk4simple/rk4simple.hxx | 7 ++----- src/solver/impls/rkgeneric/impls/rkf34/rkf34.cxx | 6 ------ src/solver/impls/rkgeneric/impls/rkf34/rkf34.hxx | 9 +++------ src/solver/impls/rkgeneric/impls/rkf45/rkf45.cxx | 6 ------ src/solver/impls/rkgeneric/impls/rkf45/rkf45.hxx | 9 +++------ src/solver/impls/rkgeneric/rkscheme.cxx | 4 ---- src/sys/options/optionparser.hxx | 6 +++--- src/sys/options/options_ini.cxx | 6 ------ src/sys/options/options_ini.hxx | 3 --- tests/unit/mesh/test_boutmesh.cxx | 2 -- 23 files changed, 19 insertions(+), 84 deletions(-) diff --git a/include/bout/globalfield.hxx b/include/bout/globalfield.hxx index 65356a9aa0..e167a698a3 100644 --- a/include/bout/globalfield.hxx +++ b/include/bout/globalfield.hxx @@ -20,7 +20,7 @@ class GlobalField2D; class GlobalField { public: GlobalField() = delete; - virtual ~GlobalField(); + virtual ~GlobalField() = default; virtual bool valid() const = 0; ///< Is the data valid on any processor? bool dataIsLocal() const {return valid() && (data_on_proc == mype);} ///< Data is on this processor diff --git a/include/bout/physicsmodel.hxx b/include/bout/physicsmodel.hxx index b8f58635e8..5faa5911d6 100644 --- a/include/bout/physicsmodel.hxx +++ b/include/bout/physicsmodel.hxx @@ -55,7 +55,7 @@ public: PhysicsModel(); - virtual ~PhysicsModel(); + virtual ~PhysicsModel() = default; /*! * Initialse the model, calling the init() and postInit() methods diff --git a/include/bout/rkscheme.hxx b/include/bout/rkscheme.hxx index 19f8a00a3f..1c3c61a4cb 100644 --- a/include/bout/rkscheme.hxx +++ b/include/bout/rkscheme.hxx @@ -53,7 +53,7 @@ class RKScheme { //Options picks the scheme, pretty much everything else is automated RKScheme(Options *opts = nullptr); - virtual ~RKScheme(); + virtual ~RKScheme() = default; //Finish generic initialisation void init(int nlocalIn, int neqIn, bool adaptiveIn, BoutReal atolIn, diff --git a/include/invert_parderiv.hxx b/include/invert_parderiv.hxx index 6eff81f6b1..2ad993dcc9 100644 --- a/include/invert_parderiv.hxx +++ b/include/invert_parderiv.hxx @@ -65,8 +65,8 @@ public: */ InvertPar(Options *UNUSED(opt), Mesh *mesh_in = nullptr) : localmesh(mesh_in==nullptr ? bout::globals::mesh : mesh_in) {} - virtual ~InvertPar() {} - + virtual ~InvertPar() = default; + /*! * Create an instance of InvertPar * diff --git a/src/field/globalfield.cxx b/src/field/globalfield.cxx index 33a03e0ecc..2b091547ba 100644 --- a/src/field/globalfield.cxx +++ b/src/field/globalfield.cxx @@ -19,10 +19,6 @@ GlobalField::GlobalField(Mesh *m, int proc, int xsize, int ysize, int zsize) data.reallocate(nx * ny * nz); } } - -GlobalField::~GlobalField() { -} - void GlobalField::proc_local_origin(int proc, int *x, int *y, int *z) const { int nxpe = mesh->getNXPE(); diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index 72e8b93bdc..db1cffdec0 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -54,9 +54,6 @@ InvertParCR::InvertParCR(Options *opt, Mesh *mesh_in) nsys = 1 + (localmesh->LocalNz)/2; } -InvertParCR::~InvertParCR() { -} - const Field3D InvertParCR::solve(const Field3D &f) { TRACE("InvertParCR::solve(Field3D)"); ASSERT1(localmesh == f.getMesh()); diff --git a/src/invert/parderiv/impls/cyclic/cyclic.hxx b/src/invert/parderiv/impls/cyclic/cyclic.hxx index 390228b57f..ae13d30118 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.hxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.hxx @@ -47,7 +47,6 @@ class InvertParCR : public InvertPar { public: InvertParCR(Options *opt, Mesh *mesh_in = bout::globals::mesh); - ~InvertParCR(); using InvertPar::solve; const Field3D solve(const Field3D &f) override; diff --git a/src/physics/physicsmodel.cxx b/src/physics/physicsmodel.cxx index 67907caace..d3cdfbc6bd 100644 --- a/src/physics/physicsmodel.cxx +++ b/src/physics/physicsmodel.cxx @@ -42,9 +42,6 @@ PhysicsModel::PhysicsModel() restart = Datafile(Options::getRoot()->getSection("restart")); } -PhysicsModel::~PhysicsModel() { -} - int PhysicsModel::runRHS(BoutReal time) { return rhs(time); } diff --git a/src/solver/impls/rk4/rk4.cxx b/src/solver/impls/rk4/rk4.cxx index 6ac3c7d336..25e1a3bb6e 100644 --- a/src/solver/impls/rk4/rk4.cxx +++ b/src/solver/impls/rk4/rk4.cxx @@ -13,9 +13,6 @@ RK4Solver::RK4Solver(Options *options) : Solver(options) { canReset = true; } -RK4Solver::~RK4Solver() { -} - void RK4Solver::setMaxTimestep(BoutReal dt) { if (dt > timestep) return; // Already less than this diff --git a/src/solver/impls/rk4/rk4.hxx b/src/solver/impls/rk4/rk4.hxx index 15273ba230..8c2bd6b086 100644 --- a/src/solver/impls/rk4/rk4.hxx +++ b/src/solver/impls/rk4/rk4.hxx @@ -43,7 +43,6 @@ RegisterSolver registersolverrk4("rk4"); class RK4Solver : public Solver { public: RK4Solver(Options *options); - ~RK4Solver(); void resetInternalFields() override; void setMaxTimestep(BoutReal dt) override; diff --git a/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx b/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx index 69ecf37a7a..e60955124e 100644 --- a/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx +++ b/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.cxx @@ -91,9 +91,3 @@ CASHKARPScheme::CASHKARPScheme(Options *options):RKScheme(options){ timeCoeffs[5] = 7.0/8.0; } - -CASHKARPScheme::~CASHKARPScheme(){ - //Do my cleanup - -} - diff --git a/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.hxx b/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.hxx index 4973aa9867..52ecf656f0 100644 --- a/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.hxx +++ b/src/solver/impls/rkgeneric/impls/cashkarp/cashkarp.hxx @@ -7,12 +7,9 @@ class CASHKARPScheme; #include #include -class CASHKARPScheme : public RKScheme{ - public: - CASHKARPScheme(Options *options); - ~CASHKARPScheme(); - private: - +class CASHKARPScheme : public RKScheme { +public: + CASHKARPScheme(Options* options); }; #endif // __CASHKARP_SCHEME_H__ diff --git a/src/solver/impls/rkgeneric/impls/rk4simple/rk4simple.cxx b/src/solver/impls/rkgeneric/impls/rk4simple/rk4simple.cxx index f33ae5acd7..dfa221498c 100644 --- a/src/solver/impls/rkgeneric/impls/rk4simple/rk4simple.cxx +++ b/src/solver/impls/rkgeneric/impls/rk4simple/rk4simple.cxx @@ -109,11 +109,6 @@ RK4SIMPLEScheme::RK4SIMPLEScheme(Options *options):RKScheme(options){ } -RK4SIMPLEScheme::~RK4SIMPLEScheme(){ - //Do my cleanup - -} - BoutReal RK4SIMPLEScheme::setOutputStates(const Array &start, const BoutReal dt, Array &resultFollow) { //return RKScheme::setOutputStates(start,dt,resultFollow); diff --git a/src/solver/impls/rkgeneric/impls/rk4simple/rk4simple.hxx b/src/solver/impls/rkgeneric/impls/rk4simple/rk4simple.hxx index 78d36bab0a..29527630dd 100644 --- a/src/solver/impls/rkgeneric/impls/rk4simple/rk4simple.hxx +++ b/src/solver/impls/rkgeneric/impls/rk4simple/rk4simple.hxx @@ -8,13 +8,10 @@ class RK4SIMPLEScheme; #include class RK4SIMPLEScheme : public RKScheme{ - public: +public: RK4SIMPLEScheme(Options *options); - ~RK4SIMPLEScheme(); - + BoutReal setOutputStates(const Array &start,BoutReal dt, Array &resultFollow); - private: - }; #endif // __RK4SIMPLE_SCHEME_H__ diff --git a/src/solver/impls/rkgeneric/impls/rkf34/rkf34.cxx b/src/solver/impls/rkgeneric/impls/rkf34/rkf34.cxx index 31f05ac967..26d396b0e1 100644 --- a/src/solver/impls/rkgeneric/impls/rkf34/rkf34.cxx +++ b/src/solver/impls/rkgeneric/impls/rkf34/rkf34.cxx @@ -85,9 +85,3 @@ RKF34Scheme::RKF34Scheme(Options *options):RKScheme(options){ timeCoeffs[4] = 1.0; } - -RKF34Scheme::~RKF34Scheme(){ - //Do my cleanup - -} - diff --git a/src/solver/impls/rkgeneric/impls/rkf34/rkf34.hxx b/src/solver/impls/rkgeneric/impls/rkf34/rkf34.hxx index fe6c6ef447..8ac17f521a 100644 --- a/src/solver/impls/rkgeneric/impls/rkf34/rkf34.hxx +++ b/src/solver/impls/rkgeneric/impls/rkf34/rkf34.hxx @@ -7,12 +7,9 @@ class RKF34Scheme; #include #include -class RKF34Scheme : public RKScheme{ - public: - RKF34Scheme(Options *options); - ~RKF34Scheme(); - private: - +class RKF34Scheme : public RKScheme { +public: + RKF34Scheme(Options* options); }; #endif // __RKF34_SCHEME_H__ diff --git a/src/solver/impls/rkgeneric/impls/rkf45/rkf45.cxx b/src/solver/impls/rkgeneric/impls/rkf45/rkf45.cxx index 089c6b8c0f..c732c132e2 100644 --- a/src/solver/impls/rkgeneric/impls/rkf45/rkf45.cxx +++ b/src/solver/impls/rkgeneric/impls/rkf45/rkf45.cxx @@ -91,9 +91,3 @@ RKF45Scheme::RKF45Scheme(Options *options):RKScheme(options){ timeCoeffs[5] = 1.0/2.0; } - -RKF45Scheme::~RKF45Scheme(){ - //Do my cleanup - -} - diff --git a/src/solver/impls/rkgeneric/impls/rkf45/rkf45.hxx b/src/solver/impls/rkgeneric/impls/rkf45/rkf45.hxx index b3fbfc3acd..e4ae10ed06 100644 --- a/src/solver/impls/rkgeneric/impls/rkf45/rkf45.hxx +++ b/src/solver/impls/rkgeneric/impls/rkf45/rkf45.hxx @@ -7,12 +7,9 @@ class RKF45Scheme; #include #include -class RKF45Scheme : public RKScheme{ - public: - RKF45Scheme(Options *options); - ~RKF45Scheme(); - private: - +class RKF45Scheme : public RKScheme { +public: + RKF45Scheme(Options* options); }; #endif // __RKF45_SCHEME_H__ diff --git a/src/solver/impls/rkgeneric/rkscheme.cxx b/src/solver/impls/rkgeneric/rkscheme.cxx index 94e5a54f29..fa0b2580af 100644 --- a/src/solver/impls/rkgeneric/rkscheme.cxx +++ b/src/solver/impls/rkgeneric/rkscheme.cxx @@ -17,10 +17,6 @@ RKScheme::RKScheme(Options *UNUSED(opts)) { dtfac = 1.0; // Time step factor } -//Cleanup -RKScheme::~RKScheme(){ -} - //Finish generic initialisation void RKScheme::init(const int nlocalIn, const int neqIn, const bool adaptiveIn, const BoutReal atolIn, const BoutReal rtolIn, Options *options){ diff --git a/src/sys/options/optionparser.hxx b/src/sys/options/optionparser.hxx index f3864314f0..382d11d0f3 100644 --- a/src/sys/options/optionparser.hxx +++ b/src/sys/options/optionparser.hxx @@ -48,9 +48,9 @@ class OptionParser; /// Base class for input file types class OptionParser { - public: - OptionParser() {} - virtual ~OptionParser() {} +public: + OptionParser() = default; + virtual ~OptionParser() = default; /// Read \p filename into \p options virtual void read(Options *options, const std::string &filename) = 0; diff --git a/src/sys/options/options_ini.cxx b/src/sys/options/options_ini.cxx index e2a9f932ec..1010a68a87 100644 --- a/src/sys/options/options_ini.cxx +++ b/src/sys/options/options_ini.cxx @@ -56,12 +56,6 @@ using namespace std; -OptionINI::OptionINI() { -} - -OptionINI::~OptionINI() { -} - /************************************************************************** * Read input file **************************************************************************/ diff --git a/src/sys/options/options_ini.hxx b/src/sys/options/options_ini.hxx index 1387f054c7..336d33435b 100644 --- a/src/sys/options/options_ini.hxx +++ b/src/sys/options/options_ini.hxx @@ -47,9 +47,6 @@ class OptionINI; */ class OptionINI : public OptionParser { public: - OptionINI(); - ~OptionINI(); - /// Read options from file void read(Options *options, const std::string &filename) override; diff --git a/tests/unit/mesh/test_boutmesh.cxx b/tests/unit/mesh/test_boutmesh.cxx index 4ef211dc73..3369210dbb 100644 --- a/tests/unit/mesh/test_boutmesh.cxx +++ b/tests/unit/mesh/test_boutmesh.cxx @@ -7,8 +7,6 @@ class FakeGridDataSource : public GridDataSource { public: - FakeGridDataSource(){}; - ~FakeGridDataSource(){}; bool hasVar(const std::string &UNUSED(name)) { return false; }; bool get(Mesh *UNUSED(m), std::string &UNUSED(sval), const std::string &UNUSED(name)) { return true; From c0f183d37ad1fbec4c30d405d468bde698f39372 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 11:06:02 +0100 Subject: [PATCH 1399/1783] Use unique_ptr instead of new/delete in test-solver --- tests/integrated/test-solver/test_solver.cxx | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/tests/integrated/test-solver/test_solver.cxx b/tests/integrated/test-solver/test_solver.cxx index d203a677a9..9db728538e 100644 --- a/tests/integrated/test-solver/test_solver.cxx +++ b/tests/integrated/test-solver/test_solver.cxx @@ -85,13 +85,13 @@ int main(int argc, char **argv) { // "solver" section, as we run into problems when solvers use the same // name for an option with inconsistent defaults auto options = Options::getRoot()->getSection(name); - Solver *solver = SolverFactory::getInstance()->createSolver(name, options); + auto solver = std::unique_ptr{SolverFactory::getInstance()->createSolver(name, options)}; - TestSolver *model = new TestSolver(); - solver->setModel(model); + auto model = bout::utils::make_unique(); + solver->setModel(model.get()); - Monitor *bout_monitor = new BoutMonitor(); - solver->addMonitor(bout_monitor, Solver::BACK); + auto bout_monitor = bout::utils::make_unique(); + solver->addMonitor(bout_monitor.get(), Solver::BACK); solver->solve(); @@ -101,11 +101,6 @@ int main(int argc, char **argv) { } else { output_test << " PASSED\n"; } - - delete model; - delete solver; - delete bout_monitor; - } catch (BoutException &e) { // Don't let one bad solver stop us trying the rest output_test << " ERROR\n"; From 52c8bb7998d4d322549addf2fdba7b6c732ea7a4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 11:29:53 +0100 Subject: [PATCH 1400/1783] Use `using` instead of `typedef` everywhere --- .../performance/arithmetic/arithmetic.cxx | 4 +- .../arithmetic_3d2d/arithmetic_3d2d.cxx | 4 +- examples/performance/bracket/bracket.cxx | 4 +- examples/performance/ddx/ddx.cxx | 2 +- examples/performance/ddy/ddy.cxx | 2 +- examples/performance/ddz/ddz.cxx | 2 +- .../iterator-offsets/iterator-offsets.cxx | 2 +- examples/performance/iterator/iterator.cxx | 4 +- .../tuning_regionblocksize.cxx | 4 +- include/bout/expr.hxx | 41 ++++++++++--------- include/bout/fieldgroup.hxx | 4 +- include/bout/mesh.hxx | 2 +- include/bout/physicsmodel.hxx | 6 +-- include/bout/region.hxx | 8 ++-- include/bout/rvec.hxx | 2 +- include/bout_types.hxx | 2 +- include/dcomplex.hxx | 2 +- include/multiostream.hxx | 6 +-- include/output.hxx | 4 +- include/parallel_boundary_region.hxx | 4 +- src/fileio/impls/hdf5/h5_format.hxx | 2 +- src/fileio/impls/netcdf/nc_format.hxx | 2 +- src/fileio/impls/netcdf4/ncxx4.hxx | 2 +- src/fileio/impls/pnetcdf/pnetcdf.hxx | 2 +- src/invert/laplace/impls/pdd/pdd.hxx | 4 +- .../laplace3d/impls/petsc/petsc_laplace3d.hxx | 2 +- src/solver/impls/petsc/petsc.hxx | 8 ++-- tests/integrated/test-cyclic/test_cyclic.cxx | 2 +- .../include/bout/test_generic_factory.cxx | 4 +- tests/unit/include/bout/test_region.cxx | 4 +- 30 files changed, 71 insertions(+), 70 deletions(-) diff --git a/examples/performance/arithmetic/arithmetic.cxx b/examples/performance/arithmetic/arithmetic.cxx index d4c38b3c0b..465587e7c3 100644 --- a/examples/performance/arithmetic/arithmetic.cxx +++ b/examples/performance/arithmetic/arithmetic.cxx @@ -9,8 +9,8 @@ #include -typedef std::chrono::time_point SteadyClock; -typedef std::chrono::duration Duration; +using SteadyClock = std::chrono::time_point; +using Duration = std::chrono::duration; using namespace std::chrono; #define TIMEIT(elapsed, ...) \ diff --git a/examples/performance/arithmetic_3d2d/arithmetic_3d2d.cxx b/examples/performance/arithmetic_3d2d/arithmetic_3d2d.cxx index 1b2337f31a..4aae7f053d 100644 --- a/examples/performance/arithmetic_3d2d/arithmetic_3d2d.cxx +++ b/examples/performance/arithmetic_3d2d/arithmetic_3d2d.cxx @@ -10,8 +10,8 @@ #include #include -typedef std::chrono::time_point SteadyClock; -typedef std::chrono::duration Duration; +using SteadyClock = std::chrono::time_point; +using Duration = std::chrono::duration; using namespace std::chrono; #define TIMEIT(NAME, ...) \ diff --git a/examples/performance/bracket/bracket.cxx b/examples/performance/bracket/bracket.cxx index d468da331e..0c10c15bb7 100644 --- a/examples/performance/bracket/bracket.cxx +++ b/examples/performance/bracket/bracket.cxx @@ -18,8 +18,8 @@ #include "bout/openmpwrap.hxx" #include "bout/region.hxx" -typedef std::chrono::time_point SteadyClock; -typedef std::chrono::duration Duration; +using SteadyClock = std::chrono::time_point; +using Duration = std::chrono::duration; using namespace std::chrono; #define ITERATOR_TEST_BLOCK(NAME, ...) \ diff --git a/examples/performance/ddx/ddx.cxx b/examples/performance/ddx/ddx.cxx index 9102994533..b7a838e28a 100644 --- a/examples/performance/ddx/ddx.cxx +++ b/examples/performance/ddx/ddx.cxx @@ -35,7 +35,7 @@ BoutReal test_ddy(stencil &s) { return (s.p - s.m); } -typedef BoutReal (*deriv_func)(stencil &); +using deriv_func = BoutReal (*)(stencil &); deriv_func func_ptr = &test_ddy; int main(int argc, char **argv) { diff --git a/examples/performance/ddy/ddy.cxx b/examples/performance/ddy/ddy.cxx index f3d23c5bc1..7b5b401f24 100644 --- a/examples/performance/ddy/ddy.cxx +++ b/examples/performance/ddy/ddy.cxx @@ -35,7 +35,7 @@ BoutReal test_ddy(stencil &s) { return (s.p - s.m); } -typedef BoutReal (*deriv_func)(stencil &); +using deriv_func = BoutReal (*)(stencil &); deriv_func func_ptr = &test_ddy; int main(int argc, char **argv) { diff --git a/examples/performance/ddz/ddz.cxx b/examples/performance/ddz/ddz.cxx index 8bbee408f4..ae99c3f256 100644 --- a/examples/performance/ddz/ddz.cxx +++ b/examples/performance/ddz/ddz.cxx @@ -35,7 +35,7 @@ BoutReal test_ddy(stencil &s) { return (s.p - s.m); } -typedef BoutReal (*deriv_func)(stencil &); +using deriv_func = BoutReal (*)(stencil &); deriv_func func_ptr = &test_ddy; int main(int argc, char **argv) { diff --git a/examples/performance/iterator-offsets/iterator-offsets.cxx b/examples/performance/iterator-offsets/iterator-offsets.cxx index 5ebba9da5e..abe0c34f66 100644 --- a/examples/performance/iterator-offsets/iterator-offsets.cxx +++ b/examples/performance/iterator-offsets/iterator-offsets.cxx @@ -34,7 +34,7 @@ BoutReal test_ddy(stencil &s) { return (s.p - s.m); } -typedef BoutReal (*deriv_func)(stencil &); +using deriv_func = BoutReal (*)(stencil &); deriv_func func_ptr = &test_ddy; int main(int argc, char **argv) { diff --git a/examples/performance/iterator/iterator.cxx b/examples/performance/iterator/iterator.cxx index 7ac20792fb..c356ed29a7 100644 --- a/examples/performance/iterator/iterator.cxx +++ b/examples/performance/iterator/iterator.cxx @@ -15,8 +15,8 @@ #include "bout/openmpwrap.hxx" #include "bout/region.hxx" -typedef std::chrono::time_point SteadyClock; -typedef std::chrono::duration Duration; +using SteadyClock = std::chrono::time_point; +using Duration = std::chrono::duration; using namespace std::chrono; #define ITERATOR_TEST_BLOCK(NAME, ...) \ diff --git a/examples/performance/tuning_regionblocksize/tuning_regionblocksize.cxx b/examples/performance/tuning_regionblocksize/tuning_regionblocksize.cxx index 29b3238606..76cba66500 100644 --- a/examples/performance/tuning_regionblocksize/tuning_regionblocksize.cxx +++ b/examples/performance/tuning_regionblocksize/tuning_regionblocksize.cxx @@ -16,8 +16,8 @@ #include "bout/openmpwrap.hxx" #include "bout/region.hxx" -typedef std::chrono::time_point SteadyClock; -typedef std::chrono::duration Duration; +using SteadyClock = std::chrono::time_point; +using Duration = std::chrono::duration; using namespace std::chrono; #define ITERATOR_TEST_BLOCK(NAME, ...) \ diff --git a/include/bout/expr.hxx b/include/bout/expr.hxx index 4cbe31cb9f..30a9d9664c 100644 --- a/include/bout/expr.hxx +++ b/include/bout/expr.hxx @@ -21,7 +21,8 @@ /// Literal class to capture BoutReal values in expressions class Literal { public: - typedef Literal type; ///< Type of this expression + /// Type of this expression + using type = Literal; Literal(BoutReal v) : val(v) {} ~Literal() {} @@ -32,7 +33,7 @@ private: class Field3DExpr { public: - typedef Field3D type; + using type = Field3D; Field3DExpr(const Field3D &f) : data(&f(0,0,0)) {} const BoutReal& operator()(int x, int y, int z) const { return data[(x*bout::globals::mesh->LocalNy + y)*bout::globals::mesh->LocalNz + z]; } @@ -42,7 +43,7 @@ private: class Field2DExpr { public: - typedef Field2D type; + using type = Field2D; Field2DExpr(const Field2D &f) : data(&f(0,0)) {} const BoutReal& operator()(int x, int y, int z) const { return data[x*bout::globals::mesh->LocalNy + y]; } @@ -54,22 +55,22 @@ private: template struct exprTraits { - typedef ExprT expr_type; + using expr_type = ExprT; }; template <> struct exprTraits { - typedef Literal expr_type; + using expr_type = Literal; }; template <> struct exprTraits { - typedef Literal expr_type; + using expr_type = Literal; }; template <> struct exprTraits { - typedef Literal expr_type; + using expr_type = Literal; }; /////////////////////////////////////////////// @@ -77,31 +78,31 @@ struct exprTraits { template struct asExpr { - typedef T type; + using type = T; static const T& getExpr(const T& x) {return x;} }; template <> struct asExpr { - typedef Literal type; + using type = Literal; static const Literal getExpr(const int& x) {return Literal(x);} }; template <> struct asExpr { - typedef Literal type; + using type = Literal; static const Literal getExpr(const double& x) {return Literal(x);} }; template <> struct asExpr { - typedef Literal type; + using type = Literal; static const Literal getExpr(const float& x) {return Literal(x);} }; template <> struct asExpr { - typedef Field3DExpr type; + using type = Field3DExpr; static const Field3DExpr getExpr(const Field3D& x) {return Field3DExpr(x);} }; @@ -111,7 +112,7 @@ struct asExpr { template // If in doubt, convert to Field3D struct PromoteType { - typedef Field3D type; + using type = Field3D; }; ///////////////////////////////////////////////////////////// @@ -125,11 +126,11 @@ public: } // Work out the type of the inputs - typedef typename exprTraits::expr_type ltype; - typedef typename exprTraits::expr_type rtype; + using ltype = typename exprTraits::expr_type; + using rtype = typename exprTraits::expr_type; /// Type of the resulting expression - typedef typename PromoteType::type type; + using type = typename PromoteType::type; BoutReal operator()(int x, int y, int z) const { return BinOp::apply((_expr1)(x,y,z),(_expr2)(x,y,z)); @@ -142,9 +143,9 @@ private: template struct BinaryResult { - typedef typename asExpr::type arg1; - typedef typename asExpr::type arg2; - typedef BinaryExpr type; + using arg1 = typename asExpr::type; + using arg2 = typename asExpr::type; + using type = BinaryExpr; }; /// Binary operator classes @@ -174,7 +175,7 @@ struct Power { template \ typename BinaryResult::type \ func(const ExprT1 &e1, const ExprT2 &e2) { \ - typedef typename BinaryResult::type type; \ + using type = typename BinaryResult::type; \ return type(asExpr::getExpr(e1), asExpr::getExpr(e2)); \ } diff --git a/include/bout/fieldgroup.hxx b/include/bout/fieldgroup.hxx index 54c8c5dd87..42e7bfea39 100644 --- a/include/bout/fieldgroup.hxx +++ b/include/bout/fieldgroup.hxx @@ -168,7 +168,7 @@ class FieldGroup { void clear() {fvec.clear(); f3vec.clear(); } /// Iteration over all fields - typedef std::vector::iterator iterator; + using iterator = std::vector::iterator; iterator begin() { return fvec.begin(); } @@ -177,7 +177,7 @@ class FieldGroup { } /// Const iteration over all fields - typedef std::vector::const_iterator const_iterator; + using const_iterator = std::vector::const_iterator; const_iterator begin() const { return fvec.begin(); } diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index d17745ea06..8d6b906036 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -76,7 +76,7 @@ class Mesh; #include /// Type used to return pointers to handles -typedef void* comm_handle; +using comm_handle = void*; class Mesh { public: diff --git a/include/bout/physicsmodel.hxx b/include/bout/physicsmodel.hxx index 5faa5911d6..c5dc6aa054 100644 --- a/include/bout/physicsmodel.hxx +++ b/include/bout/physicsmodel.hxx @@ -50,9 +50,9 @@ class PhysicsModel; */ class PhysicsModel { public: - typedef int (PhysicsModel::*preconfunc)(BoutReal t, BoutReal gamma, BoutReal delta); - typedef int (PhysicsModel::*jacobianfunc)(BoutReal t); - + using preconfunc = int (PhysicsModel::*)(BoutReal t, BoutReal gamma, BoutReal delta); + using jacobianfunc = int (PhysicsModel::*)(BoutReal t); + PhysicsModel(); virtual ~PhysicsModel() = default; diff --git a/include/bout/region.hxx b/include/bout/region.hxx index 25872222c8..75d8b4cd17 100644 --- a/include/bout/region.hxx +++ b/include/bout/region.hxx @@ -456,14 +456,14 @@ template class Region { "Region must be templated with one of IndPerp, Ind2D or Ind3D"); public: - typedef T data_type; + using data_type = T; /// Indices to iterate over - typedef std::vector RegionIndices; + using RegionIndices = std::vector; /// Start and end of contiguous region. This describes a range [block.first,block.second) - typedef std::pair ContiguousBlock; + using ContiguousBlock = std::pair; /// Collection of contiguous regions - typedef std::vector ContiguousBlocks; + using ContiguousBlocks = std::vector; // NOTE:: // Probably want to require a mesh in constructor, both to know nx/ny/nz diff --git a/include/bout/rvec.hxx b/include/bout/rvec.hxx index d3fe0dced0..5723c7372e 100644 --- a/include/bout/rvec.hxx +++ b/include/bout/rvec.hxx @@ -6,6 +6,6 @@ #include #include -typedef std::vector rvec; +using rvec = std::vector; #endif // __RVEC_H__ diff --git a/include/bout_types.hxx b/include/bout_types.hxx index ba48a555f3..1e43f6e72e 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -28,7 +28,7 @@ #include /// Size of real numbers -typedef double BoutReal; +using BoutReal = double; /// Quiet NaN const BoutReal BoutNaN = std::numeric_limits::quiet_NaN(); diff --git a/include/dcomplex.hxx b/include/dcomplex.hxx index 673550ce3f..0b0ce50552 100644 --- a/include/dcomplex.hxx +++ b/include/dcomplex.hxx @@ -35,7 +35,7 @@ #include #include "bout_types.hxx" -typedef std::complex dcomplex; +using dcomplex = std::complex; const dcomplex Im(0,1); // 1i diff --git a/include/multiostream.hxx b/include/multiostream.hxx index 47c1b2d154..bdd8ba210b 100644 --- a/include/multiostream.hxx +++ b/include/multiostream.hxx @@ -75,7 +75,7 @@ class multiostream : private public std::basic_ostream { private: - typedef ::multioutbuf_init multioutbuf_init; + using multioutbuf_init = ::multioutbuf_init; public: multiostream() : multioutbuf_init(), std::basic_ostream cmultiostream; -typedef multiostream wmultiostream; +using cmultiostream = multiostream; +using wmultiostream = multiostream; #endif // __MULTIOSTREAM_H__ diff --git a/include/output.hxx b/include/output.hxx index 7dd1a5cec0..dd27df5699 100644 --- a/include/output.hxx +++ b/include/output.hxx @@ -59,8 +59,8 @@ using std::endl; class Output : private multioutbuf_init>, public std::basic_ostream> { - typedef std::char_traits _Tr; - typedef ::multioutbuf_init multioutbuf_init; + using _Tr = std::char_traits; + using multioutbuf_init = ::multioutbuf_init; public: Output() : multioutbuf_init(), std::basic_ostream(multioutbuf_init::buf()) { diff --git a/include/parallel_boundary_region.hxx b/include/parallel_boundary_region.hxx index 094611b823..c37e713313 100644 --- a/include/parallel_boundary_region.hxx +++ b/include/parallel_boundary_region.hxx @@ -35,8 +35,8 @@ class BoundaryRegionPar : public BoundaryRegionBase { BoutReal angle; }; - typedef std::vector IndicesVec; - typedef IndicesVec::iterator IndicesIter; + using IndicesVec = std::vector; + using IndicesIter = IndicesVec::iterator; /// Vector of points in the boundary IndicesVec bndry_points; diff --git a/src/fileio/impls/hdf5/h5_format.hxx b/src/fileio/impls/hdf5/h5_format.hxx index 17f8c35f0c..df037e2e50 100644 --- a/src/fileio/impls/hdf5/h5_format.hxx +++ b/src/fileio/impls/hdf5/h5_format.hxx @@ -36,7 +36,7 @@ #ifndef HDF5 #include "../emptyformat.hxx" -typedef EmptyFormat H5Format; +using H5Format = EmptyFormat; #else diff --git a/src/fileio/impls/netcdf/nc_format.hxx b/src/fileio/impls/netcdf/nc_format.hxx index b1e801158c..b2986a0835 100644 --- a/src/fileio/impls/netcdf/nc_format.hxx +++ b/src/fileio/impls/netcdf/nc_format.hxx @@ -36,7 +36,7 @@ #ifndef NCDF #include "../emptyformat.hxx" -typedef EmptyFormat NcFormat; +using NcFormat = EmptyFormat; #else diff --git a/src/fileio/impls/netcdf4/ncxx4.hxx b/src/fileio/impls/netcdf4/ncxx4.hxx index dc4a7a8cce..7919b621ed 100644 --- a/src/fileio/impls/netcdf4/ncxx4.hxx +++ b/src/fileio/impls/netcdf4/ncxx4.hxx @@ -36,7 +36,7 @@ #ifndef NCDF4 #include "../emptyformat.hxx" -typedef EmptyFormat Ncxx4; +using Ncxx4 = EmptyFormat; #else diff --git a/src/fileio/impls/pnetcdf/pnetcdf.hxx b/src/fileio/impls/pnetcdf/pnetcdf.hxx index dd355f22df..6c400e936a 100644 --- a/src/fileio/impls/pnetcdf/pnetcdf.hxx +++ b/src/fileio/impls/pnetcdf/pnetcdf.hxx @@ -36,7 +36,7 @@ #ifndef PNCDF #include "../emptyformat.hxx" -typedef EmptyFormat PncFormat; +using PncFormat = EmptyFormat; #else diff --git a/src/invert/laplace/impls/pdd/pdd.hxx b/src/invert/laplace/impls/pdd/pdd.hxx index 62c2031afb..cef88111d9 100644 --- a/src/invert/laplace/impls/pdd/pdd.hxx +++ b/src/invert/laplace/impls/pdd/pdd.hxx @@ -87,7 +87,7 @@ private: const int PDD_COMM_Y; // Second tag /// Data structure for PDD algorithm - typedef struct { + struct PDD_data { Matrix bk; ///< b vector in Fourier space Matrix avec, bvec, cvec; ///< Diagonal bands of matrix @@ -103,7 +103,7 @@ private: comm_handle recv_handle; Array y2i; - }PDD_data; + }; void start(const FieldPerp &b, PDD_data &data); void next(PDD_data &data); diff --git a/src/invert/laplace3d/impls/petsc/petsc_laplace3d.hxx b/src/invert/laplace3d/impls/petsc/petsc_laplace3d.hxx index 82a9a713f5..232c97c731 100644 --- a/src/invert/laplace3d/impls/petsc/petsc_laplace3d.hxx +++ b/src/invert/laplace3d/impls/petsc/petsc_laplace3d.hxx @@ -6,7 +6,7 @@ // No PETSc available, so define as an empty laplace3d #include "../emptylaplace3d.hxx" -typedef EmptyLaplace3D Laplace3DPetsc; +using Laplace3DPetsc = EmptyLaplace3D; #else // BOUT_HAS_PETSC diff --git a/src/solver/impls/petsc/petsc.hxx b/src/solver/impls/petsc/petsc.hxx index a191e81652..30a977c9e6 100644 --- a/src/solver/impls/petsc/petsc.hxx +++ b/src/solver/impls/petsc/petsc.hxx @@ -49,10 +49,10 @@ namespace { RegisterSolver registersolverpetsc("petsc"); } -typedef PetscScalar BoutReal; +using BoutReal = PetscScalar; #define OPT_SIZE 40 -typedef int (*rhsfunc)(BoutReal); +using rhsfunc = int (*)(BoutReal); extern BoutReal simtime; @@ -71,12 +71,12 @@ extern PetscErrorCode solver_ijacobian(TS, PetscReal, Vec, Vec, PetscReal, Mat * #endif /// Data for SNES -typedef struct snes_info { +struct snes_info { PetscInt it; PetscInt linear_its; PetscReal time; PetscReal norm; -} snes_info; +}; class PetscSolver : public Solver { public: diff --git a/tests/integrated/test-cyclic/test_cyclic.cxx b/tests/integrated/test-cyclic/test_cyclic.cxx index 113e23192d..516fa0cfbc 100644 --- a/tests/integrated/test-cyclic/test_cyclic.cxx +++ b/tests/integrated/test-cyclic/test_cyclic.cxx @@ -10,7 +10,7 @@ #include "utils.hxx" // Change this to dcomplex to test complex matrix inversion -typedef BoutReal T; +using T = BoutReal; int main(int argc, char **argv) { diff --git a/tests/unit/include/bout/test_generic_factory.cxx b/tests/unit/include/bout/test_generic_factory.cxx index eede1b0e91..f91e1a3fa9 100644 --- a/tests/unit/include/bout/test_generic_factory.cxx +++ b/tests/unit/include/bout/test_generic_factory.cxx @@ -50,8 +50,8 @@ class DerivedComplicated2 : public BaseComplicated { }; // Save some typing later -typedef Factory> - ComplicatedFactory; +using ComplicatedFactory = + Factory>; // We need to specialise the helper class to pass arguments to the constructor template diff --git a/tests/unit/include/bout/test_region.cxx b/tests/unit/include/bout/test_region.cxx index 661151c3d4..5a251cc685 100644 --- a/tests/unit/include/bout/test_region.cxx +++ b/tests/unit/include/bout/test_region.cxx @@ -1174,7 +1174,7 @@ template class RegionIndexTest : public ::testing::Test { virtual ~RegionIndexTest() = default; }; -typedef ::testing::Types RegionIndexTypes; +using RegionIndexTypes = ::testing::Types; TYPED_TEST_SUITE(RegionIndexTest, RegionIndexTypes); TYPED_TEST(RegionIndexTest, Begin) { @@ -1493,7 +1493,7 @@ class FieldIndexTest : public ::testing::Test { virtual ~FieldIndexTest() = default; }; -typedef ::testing::Types FieldIndexTypes; +using FieldIndexTypes = ::testing::Types; TYPED_TEST_SUITE(FieldIndexTest, FieldIndexTypes); TYPED_TEST(FieldIndexTest, Constructor) { From c436eb07f59baf6c9815a8e9b556568f1feb3bf3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 11:35:56 +0100 Subject: [PATCH 1401/1783] Add override keyword on test PhysicsModel virtual functions --- tests/MMS/wave-1d-y/wave.cxx | 6 +-- tests/MMS/wave-1d/wave.cxx | 10 ++--- .../test-interchange-instability/2fluid.cxx | 4 +- .../invertable_operator.cxx | 4 +- .../test-restart-io/test-restart-io.cxx | 4 +- .../test-restarting/test_restarting.cxx | 4 +- tests/integrated/test-solver/test_solver.cxx | 4 +- tests/integrated/test-vec/testVec.cxx | 4 +- tests/unit/include/bout/test_region.cxx | 9 +++-- tests/unit/mesh/data/test_gridfromoptions.cxx | 2 +- tests/unit/mesh/test_boutmesh.cxx | 38 ++++++++++--------- 11 files changed, 46 insertions(+), 43 deletions(-) diff --git a/tests/MMS/wave-1d-y/wave.cxx b/tests/MMS/wave-1d-y/wave.cxx index 767c968935..5cbe046b91 100644 --- a/tests/MMS/wave-1d-y/wave.cxx +++ b/tests/MMS/wave-1d-y/wave.cxx @@ -8,7 +8,7 @@ class Wave1D : public PhysicsModel { Field3D f, g; // Evolving variables protected: - int init(bool UNUSED(restarting)) { + int init(bool UNUSED(restarting)) override { g.setLocation(CELL_YLOW); // g staggered @@ -18,8 +18,8 @@ class Wave1D : public PhysicsModel { return 0; } - - int rhs(BoutReal UNUSED(t)) { + + int rhs(BoutReal UNUSED(t)) override { mesh->communicate(f,g); // Communicate guard cells // Central differencing diff --git a/tests/MMS/wave-1d/wave.cxx b/tests/MMS/wave-1d/wave.cxx index 57e3185f96..b8406c1dab 100644 --- a/tests/MMS/wave-1d/wave.cxx +++ b/tests/MMS/wave-1d/wave.cxx @@ -51,7 +51,7 @@ class Wave1D : public PhysicsModel { const Field3D solution_g(BoutReal t); const Field3D source_g(BoutReal t); protected: - int init(bool UNUSED(restarting)) { + int init(bool UNUSED(restarting)) override { // Coordinate system coord = mesh->getCoordinates(); @@ -123,8 +123,8 @@ class Wave1D : public PhysicsModel { return 0; } - - int rhs(BoutReal t) { + + int rhs(BoutReal t) override { mesh->communicate(f,g); // Communicate guard cells //update time-dependent boundary conditions @@ -145,9 +145,9 @@ class Wave1D : public PhysicsModel { return 0; } - + // This called every output timestep - int outputMonitor(BoutReal simtime, int UNUSED(iter), int UNUSED(NOUT)) { + int outputMonitor(BoutReal simtime, int UNUSED(iter), int UNUSED(NOUT)) override { Field3D Sf = solution_f(simtime); Field3D Sg = solution_g(simtime); diff --git a/tests/integrated/test-interchange-instability/2fluid.cxx b/tests/integrated/test-interchange-instability/2fluid.cxx index 9be72f4d39..fd6b7ce687 100644 --- a/tests/integrated/test-interchange-instability/2fluid.cxx +++ b/tests/integrated/test-interchange-instability/2fluid.cxx @@ -37,7 +37,7 @@ class Interchange : public PhysicsModel { Coordinates *coord; protected: - int init(bool UNUSED(restarting)) { + int init(bool UNUSED(restarting)) override { Field2D I; // Shear factor output << "Solving 2-variable equations\n"; @@ -169,7 +169,7 @@ class Interchange : public PhysicsModel { return (0); } - int rhs(BoutReal UNUSED(t)) { + int rhs(BoutReal UNUSED(t)) override { // Solve EM fields phi = phi_solver->solve(rho / Ni0, phi); diff --git a/tests/integrated/test-invertable-operator/invertable_operator.cxx b/tests/integrated/test-invertable-operator/invertable_operator.cxx index 1594286778..6580e20726 100644 --- a/tests/integrated/test-invertable-operator/invertable_operator.cxx +++ b/tests/integrated/test-invertable-operator/invertable_operator.cxx @@ -32,7 +32,7 @@ class InvertableOperatorTest : public PhysicsModel { class Laplacian* laplacianSolver; protected: - int init(bool) { + int init(bool) override { SOLVE_FOR(n); SOLVE_FOR(solutionLap); SOLVE_FOR(solutionInv); @@ -60,7 +60,7 @@ class InvertableOperatorTest : public PhysicsModel { return 0; } - int rhs(BoutReal) { + int rhs(BoutReal) override { ddt(n) = 0.; ddt(solutionInv) = 0.; ddt(solutionLap) = 0.; diff --git a/tests/integrated/test-restart-io/test-restart-io.cxx b/tests/integrated/test-restart-io/test-restart-io.cxx index ad8d3a043d..109809e1d4 100644 --- a/tests/integrated/test-restart-io/test-restart-io.cxx +++ b/tests/integrated/test-restart-io/test-restart-io.cxx @@ -1,7 +1,7 @@ #include "bout/physicsmodel.hxx" class TestRestartIO : public PhysicsModel { - int init(bool UNUSED(restarting)) { + int init(bool UNUSED(restarting)) override { solver->add(f3d, "f3d"); solver->add(f2d, "f2d"); dump.addRepeat(fperp_lower, "fperp_lower"); @@ -17,7 +17,7 @@ class TestRestartIO : public PhysicsModel { return 0; } - int rhs(BoutReal UNUSED(time)) { + int rhs(BoutReal UNUSED(time)) override { ddt(f3d) = 0.; ddt(f2d) = 0.; return 0; diff --git a/tests/integrated/test-restarting/test_restarting.cxx b/tests/integrated/test-restarting/test_restarting.cxx index ba340d19ca..1dc459bd47 100644 --- a/tests/integrated/test-restarting/test_restarting.cxx +++ b/tests/integrated/test-restarting/test_restarting.cxx @@ -6,12 +6,12 @@ class RestartTest : public PhysicsModel { Field3D f3d; Field2D f2d; protected: - int init(bool UNUSED(restarting)) { + int init(bool UNUSED(restarting)) override { // Evolve a 3D and a 2D field SOLVE_FOR2(f3d, f2d); return 0; } - int rhs(BoutReal UNUSED(time)) { + int rhs(BoutReal UNUSED(time)) override { // Simple time evolution ddt(f3d) = 0.1*f3d; ddt(f2d) = -0.1*f2d; diff --git a/tests/integrated/test-solver/test_solver.cxx b/tests/integrated/test-solver/test_solver.cxx index 9db728538e..746dda1bff 100644 --- a/tests/integrated/test-solver/test_solver.cxx +++ b/tests/integrated/test-solver/test_solver.cxx @@ -11,12 +11,12 @@ class TestSolver : public PhysicsModel { public: Field3D field; - int init(bool UNUSED(restarting)) { + int init(bool UNUSED(restarting)) override { solver->add(field, "field"); return 0; } - int rhs(BoutReal time) { + int rhs(BoutReal time) override { ddt(field) = sin(time) * sin(time); return 0; } diff --git a/tests/integrated/test-vec/testVec.cxx b/tests/integrated/test-vec/testVec.cxx index fbdc502372..3f89b8529d 100644 --- a/tests/integrated/test-vec/testVec.cxx +++ b/tests/integrated/test-vec/testVec.cxx @@ -4,8 +4,8 @@ class VecTest : public PhysicsModel { protected: - int init(bool restarting); - int rhs(BoutReal t); + int init(bool restarting) override; + int rhs(BoutReal t) override; public: Field3D n; diff --git a/tests/unit/include/bout/test_region.cxx b/tests/unit/include/bout/test_region.cxx index 5a251cc685..8e37a30466 100644 --- a/tests/unit/include/bout/test_region.cxx +++ b/tests/unit/include/bout/test_region.cxx @@ -1169,9 +1169,10 @@ TEST(RegionIndex3DTest, NonMemberSize) { EXPECT_EQ(size(region), nmesh); } -template class RegionIndexTest : public ::testing::Test { +template +class RegionIndexTest : public ::testing::Test { public: - virtual ~RegionIndexTest() = default; + ~RegionIndexTest() override = default; }; using RegionIndexTypes = ::testing::Types; @@ -1490,7 +1491,7 @@ TYPED_TEST(RegionIndexTest, RangeBasedForLoop) { template class FieldIndexTest : public ::testing::Test { public: - virtual ~FieldIndexTest() = default; + ~FieldIndexTest() override = default; }; using FieldIndexTypes = ::testing::Types; @@ -1668,7 +1669,7 @@ class IndexOffsetTest : public ::testing::Test { mesh->createDefaultRegions(); } - virtual ~IndexOffsetTest() { + ~IndexOffsetTest() override { delete mesh; mesh = nullptr; } diff --git a/tests/unit/mesh/data/test_gridfromoptions.cxx b/tests/unit/mesh/data/test_gridfromoptions.cxx index 2f762eb594..e926e83f93 100644 --- a/tests/unit/mesh/data/test_gridfromoptions.cxx +++ b/tests/unit/mesh/data/test_gridfromoptions.cxx @@ -64,7 +64,7 @@ class GridFromOptionsTest : public ::testing::Test { &mesh_from_options); } - ~GridFromOptionsTest() { + ~GridFromOptionsTest() override { Options::cleanup(); output_info.enable(); output_progress.enable(); diff --git a/tests/unit/mesh/test_boutmesh.cxx b/tests/unit/mesh/test_boutmesh.cxx index 3369210dbb..b391fca523 100644 --- a/tests/unit/mesh/test_boutmesh.cxx +++ b/tests/unit/mesh/test_boutmesh.cxx @@ -7,40 +7,42 @@ class FakeGridDataSource : public GridDataSource { public: - bool hasVar(const std::string &UNUSED(name)) { return false; }; - bool get(Mesh *UNUSED(m), std::string &UNUSED(sval), const std::string &UNUSED(name)) { + bool hasVar(const std::string& UNUSED(name)) override { return false; }; + bool get(Mesh* UNUSED(m), std::string& UNUSED(sval), + const std::string& UNUSED(name)) override { return true; }; - bool get(Mesh *UNUSED(m), int &UNUSED(ival), const std::string &UNUSED(name)) { + bool get(Mesh* UNUSED(m), int& UNUSED(ival), const std::string& UNUSED(name)) override { return true; }; - bool get(Mesh *UNUSED(m), BoutReal &UNUSED(rval), const std::string &UNUSED(name)) { + bool get(Mesh* UNUSED(m), BoutReal& UNUSED(rval), + const std::string& UNUSED(name)) override { return true; } - bool get(Mesh *UNUSED(m), Field2D &UNUSED(var), const std::string &UNUSED(name), - BoutReal UNUSED(def) = 0.0) { + bool get(Mesh* UNUSED(m), Field2D& UNUSED(var), const std::string& UNUSED(name), + BoutReal UNUSED(def) = 0.0) override { return true; } - bool get(Mesh *UNUSED(m), Field3D &UNUSED(var), const std::string &UNUSED(name), - BoutReal UNUSED(def) = 0.0) { + bool get(Mesh* UNUSED(m), Field3D& UNUSED(var), const std::string& UNUSED(name), + BoutReal UNUSED(def) = 0.0) override { return true; } - bool get(Mesh *UNUSED(m), FieldPerp &UNUSED(var), const std::string &UNUSED(name), - BoutReal UNUSED(def) = 0.0) { + bool get(Mesh* UNUSED(m), FieldPerp& UNUSED(var), const std::string& UNUSED(name), + BoutReal UNUSED(def) = 0.0) override { return true; } - bool get(Mesh *UNUSED(m), std::vector &UNUSED(var), const std::string &UNUSED(name), - int UNUSED(len), int UNUSED(offset) = 0, - Direction UNUSED(dir) = GridDataSource::X) { + bool get(Mesh* UNUSED(m), std::vector& UNUSED(var), + const std::string& UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, + Direction UNUSED(dir) = GridDataSource::X) override { return true; } - bool get(Mesh *UNUSED(m), std::vector &UNUSED(var), const std::string &UNUSED(name), - int UNUSED(len), int UNUSED(offset) = 0, - Direction UNUSED(dir) = GridDataSource::X) { + bool get(Mesh* UNUSED(m), std::vector& UNUSED(var), + const std::string& UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, + Direction UNUSED(dir) = GridDataSource::X) override { return true; } - bool hasXBoundaryGuards(Mesh* UNUSED(m)) { return false; } - bool hasYBoundaryGuards() { return false; } + bool hasXBoundaryGuards(Mesh* UNUSED(m)) override { return false; } + bool hasYBoundaryGuards() override { return false; } }; TEST(BoutMeshTest, NullOptionsCheck) { From 35499fcb9a2253323a0ad2cad827766743c27b68 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 11:36:40 +0100 Subject: [PATCH 1402/1783] Use bool literals instead of 0/1 in 2fluid test --- .../test-drift-instability/2fluid.cxx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/integrated/test-drift-instability/2fluid.cxx b/tests/integrated/test-drift-instability/2fluid.cxx index 3bc11ab6b5..479413266d 100644 --- a/tests/integrated/test-drift-instability/2fluid.cxx +++ b/tests/integrated/test-drift-instability/2fluid.cxx @@ -256,7 +256,7 @@ int physics_init(bool UNUSED(restarting)) { }else { initial_profile("Ajpar", Ajpar); if(ZeroElMass) - dump.add(Ajpar, "Ajpar", 1); // output calculated Ajpar + dump.add(Ajpar, "Ajpar", true); // output calculated Ajpar } if(evolve_vi) { @@ -283,19 +283,19 @@ int physics_init(bool UNUSED(restarting)) { comms.add(Apar); // Add any other variables to be dumped to file - dump.add(phi, "phi", 1); - dump.add(Apar, "Apar", 1); - dump.add(jpar, "jpar", 1); - - dump.add(Ni0, "Ni0", 0); - dump.add(Te0, "Te0", 0); - dump.add(Ti0, "Ti0", 0); - - dump.add(Te_x, "Te_x", 0); - dump.add(Ti_x, "Ti_x", 0); - dump.add(Ni_x, "Ni_x", 0); - dump.add(rho_s, "rho_s", 0); - dump.add(wci, "wci", 0); + dump.add(phi, "phi", true); + dump.add(Apar, "Apar", true); + dump.add(jpar, "jpar", true); + + dump.add(Ni0, "Ni0", false); + dump.add(Te0, "Te0", false); + dump.add(Ti0, "Ti0", false); + + dump.add(Te_x, "Te_x", false); + dump.add(Ti_x, "Ti_x", false); + dump.add(Ni_x, "Ni_x", false); + dump.add(rho_s, "rho_s", false); + dump.add(wci, "wci", false); if (mesh->StaggerGrids) { maybe_ylow = CELL_YLOW; From 76e04145539bb237f53277ea35f951c8a6f532c1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 13:16:04 +0100 Subject: [PATCH 1403/1783] Use dynamic_cast to downcast when creating BoundaryOps Also use unique_ptr to avoid manual delete --- src/field/field2d.cxx | 8 ++++---- src/field/field3d.cxx | 23 +++++++++++------------ src/field/field_data.cxx | 4 ++-- src/mesh/boundary_factory.cxx | 10 +++++----- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index a76345b591..8c43cbfedf 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -226,9 +226,9 @@ void Field2D::applyBoundary(const std::string &condition) { /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundaries()) { - auto* op = static_cast(bfact->create(condition, reg)); + auto op = std::unique_ptr{ + dynamic_cast(bfact->create(condition, reg))}; op->apply(*this); - delete op; } // Set the corners to zero @@ -262,9 +262,9 @@ void Field2D::applyBoundary(const std::string ®ion, const std::string &condit for (const auto ® : fieldmesh->getBoundaries()) { if (reg->label.compare(region) == 0) { region_found = true; - auto *op = static_cast(bfact->create(condition, reg)); + auto op = std::unique_ptr{ + dynamic_cast(bfact->create(condition, reg))}; op->apply(*this); - delete op; break; } } diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 91705f12fe..2906bddba2 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -400,9 +400,9 @@ void Field3D::applyBoundary(const std::string &condition) { /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundaries()) { - auto* op = static_cast(bfact->create(condition, reg)); + auto op = std::unique_ptr{ + dynamic_cast(bfact->create(condition, reg))}; op->apply(*this); - delete op; } //Field2D sets the corners to zero here, should we do the same here? @@ -420,9 +420,9 @@ void Field3D::applyBoundary(const std::string ®ion, const std::string &condit for (const auto ® : fieldmesh->getBoundaries()) { if (reg->label.compare(region) == 0) { region_found = true; - auto *op = static_cast(bfact->create(condition, reg)); + auto op = std::unique_ptr{ + dynamic_cast(bfact->create(condition, reg))}; op->apply(*this); - delete op; break; } } @@ -527,9 +527,9 @@ void Field3D::applyParallelBoundary(const std::string &condition) { /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundariesPar()) { - auto* op = static_cast(bfact->create(condition, reg)); + auto op = std::unique_ptr{ + dynamic_cast(bfact->create(condition, reg))}; op->apply(*this); - delete op; } } } @@ -552,9 +552,9 @@ void Field3D::applyParallelBoundary(const std::string ®ion, const std::string /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundariesPar()) { if(reg->label.compare(region) == 0) { - auto* op = static_cast(bfact->create(condition, reg)); + auto op = std::unique_ptr{ + dynamic_cast(bfact->create(condition, reg))}; op->apply(*this); - delete op; break; } } @@ -581,12 +581,11 @@ void Field3D::applyParallelBoundary(const std::string ®ion, const std::string if(reg->label.compare(region) == 0) { // BoundaryFactory can't create boundaries using Field3Ds, so get temporary // boundary of the right type - auto* tmp = static_cast(bfact->create(condition, reg)); + auto tmp = std::unique_ptr{ + dynamic_cast(bfact->create(condition, reg))}; // then clone that with the actual argument - BoundaryOpPar* op = tmp->clone(reg, f); + auto op = std::unique_ptr{tmp->clone(reg, f)}; op->apply(*this); - delete tmp; - delete op; break; } } diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index 520ed8a1be..a152cdd0c9 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -22,7 +22,7 @@ void FieldData::setBoundary(const std::string &name) { output_info << "Setting boundary for variable " << name << endl; /// Loop over the mesh boundary regions for(const auto& reg : bout::globals::mesh->getBoundaries()) { - auto* op = static_cast(bfact->createFromOptions(name, reg)); + auto* op = dynamic_cast(bfact->createFromOptions(name, reg)); if (op != nullptr) bndry_op.push_back(op); output_info << endl; @@ -32,7 +32,7 @@ void FieldData::setBoundary(const std::string &name) { std::vector par_reg = bout::globals::mesh->getBoundariesPar(); /// Loop over the mesh parallel boundary regions for(const auto& reg : bout::globals::mesh->getBoundariesPar()) { - auto* op = static_cast(bfact->createFromOptions(name, reg)); + auto* op = dynamic_cast(bfact->createFromOptions(name, reg)); if (op != nullptr) bndry_op_par.push_back(op); output_info << endl; diff --git a/src/mesh/boundary_factory.cxx b/src/mesh/boundary_factory.cxx index 76c7b6928e..a1071c6539 100644 --- a/src/mesh/boundary_factory.cxx +++ b/src/mesh/boundary_factory.cxx @@ -97,7 +97,7 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * // Clone the boundary operation, passing the region to operate over, // an empty args list and empty keyword map list args; - return pop->clone(static_cast(region), args, {}); + return pop->clone(dynamic_cast(region), args, {}); } else { // Perpendicular boundary BoundaryOp *op = findBoundaryOp(trim(name)); @@ -107,7 +107,7 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * // Clone the boundary operation, passing the region to operate over, // an empty args list and empty keyword map list args; - return op->clone(static_cast(region), args, {}); + return op->clone(dynamic_cast(region), args, {}); } } // Contains a bracket. Find the last bracket and remove @@ -170,7 +170,7 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * BoundaryModifier *mod = findBoundaryMod(func); if (mod != nullptr) { // The first argument should be an operation - auto* op = static_cast(create(arglist.front(), region)); + auto* op = dynamic_cast(create(arglist.front(), region)); if (op == nullptr) return nullptr; @@ -186,14 +186,14 @@ BoundaryOpBase* BoundaryFactory::create(const string &name, BoundaryRegionBase * BoundaryOpPar *pop = findBoundaryOpPar(trim(func)); if (pop != nullptr) { // An operation with arguments - return pop->clone(static_cast(region), arglist, keywords); + return pop->clone(dynamic_cast(region), arglist, keywords); } } else { // Perpendicular boundary BoundaryOp *op = findBoundaryOp(trim(func)); if (op != nullptr) { // An operation with arguments - return op->clone(static_cast(region), arglist, keywords); + return op->clone(dynamic_cast(region), arglist, keywords); } } From 7f938068cb6bff88697fe53ea70be81c01cd2bc1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 13:40:20 +0100 Subject: [PATCH 1404/1783] Remove a couple of unused variables from elm-pb --- examples/elm-pb/elm_pb.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index ee36084d1f..7df688f68b 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -39,9 +39,7 @@ class ELMpb : public PhysicsModel { Field2D Pi0, Pe0; Field2D q95; Field3D ubyn; - BoutReal q95_input; bool n0_fake_prof, T0_fake_prof; - BoutReal Zi; // charge number of ion // B field vectors Vector2D B0vec; // B0 field vector From 8879c65de8e05db8c54f3623b8835d62a5e3d8bd Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 13:41:35 +0100 Subject: [PATCH 1405/1783] Use unique_ptr instead of raw pointer for Laplacians in elm-pb --- examples/elm-pb/elm_pb.cxx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index 7df688f68b..d2b1dd9098 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -167,7 +167,7 @@ class ELMpb : public PhysicsModel { bool zonal_bkgd; bool split_n0; // Solve the n=0 component of potential - LaplaceXY *laplacexy; // Laplacian solver in X-Y (n=0) + std::unique_ptr laplacexy{nullptr}; // Laplacian solver in X-Y (n=0) Field2D phi2D; // Axisymmetric phi bool relax_j_vac; @@ -224,8 +224,8 @@ class ELMpb : public PhysicsModel { FieldGroup comms; /// Solver for inverting Laplacian - Laplacian* phiSolver; - Laplacian* aparSolver; + std::unique_ptr phiSolver{nullptr}; + std::unique_ptr aparSolver{nullptr}; const Field2D N0tanh(BoutReal n0_height, BoutReal n0_ave, BoutReal n0_width, BoutReal n0_center, BoutReal n0_bottom_x) { @@ -473,7 +473,7 @@ class ELMpb : public PhysicsModel { .withDefault(false); if (split_n0) { // Create an XY solver for n=0 component - laplacexy = new LaplaceXY(mesh); + laplacexy = bout::utils::make_unique(mesh); // Set coefficients for Boussinesq solve laplacexy->setCoefs(1.0, 0.0); phi2D = 0.0; // Starting guess @@ -662,7 +662,7 @@ class ELMpb : public PhysicsModel { // Need to calculate Psi inside the domain, enforcing j = 0 Jpar = 0.0; - Laplacian* psiLap = Laplacian::create(); + auto psiLap = std::unique_ptr{Laplacian::create()}; psiLap->setInnerBoundaryFlags(INVERT_AC_GRAD); // Zero gradient inner BC psiLap->setOuterBoundaryFlags(INVERT_SET); // Set to rmp_Psi0 on outer boundary rmp_Psi0 = psiLap->solve(Jpar, rmp_Psi0); @@ -1063,10 +1063,10 @@ class ELMpb : public PhysicsModel { } // Create a solver for the Laplacian - phiSolver = Laplacian::create(); + phiSolver = std::unique_ptr(Laplacian::create()); phiSolver->setFlags(phi_flags); - aparSolver = Laplacian::create(); + aparSolver = std::unique_ptr(Laplacian::create()); aparSolver->setFlags(apar_flags); /////////////// CHECK VACUUM /////////////////////// From fccfc180746fe5da190d47f6a668c0bbcf37e7f6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 13:42:28 +0100 Subject: [PATCH 1406/1783] Mark ELMpb::init as override --- examples/elm-pb/elm_pb.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index d2b1dd9098..8a470ef9ef 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -276,7 +276,7 @@ class ELMpb : public PhysicsModel { } protected: - int init(bool restarting) { + int init(bool restarting) override { bool noshear; Coordinates* metric = mesh->getCoordinates(); From cd57b0ddeac6e35fceacf387fd26f19928c5e954 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 14:00:29 +0100 Subject: [PATCH 1407/1783] Mark some global constants as constexpr --- include/bout/constants.hxx | 26 +++++++++++++------------- include/bout_types.hxx | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/bout/constants.hxx b/include/bout/constants.hxx index 1087b5c981..c8799b4bcd 100644 --- a/include/bout/constants.hxx +++ b/include/bout/constants.hxx @@ -9,23 +9,23 @@ #include /// Mathematical constant pi -const BoutReal PI = 3.141592653589793; +constexpr BoutReal PI = 3.141592653589793; /// Mathematical constant 2 * pi -const BoutReal TWOPI = 2 * PI; +constexpr BoutReal TWOPI = 2 * PI; namespace SI { // Constants in SI system of units - const BoutReal c = 299792458; ///< Speed of light in vacuum - const BoutReal mu0 = 4.e-7*PI; ///< Permeability of free space - const BoutReal e0 = 1/(c*c*mu0); ///< Permittivity of free space - const BoutReal qe = 1.602176634e-19; ///< Electron charge - const BoutReal Me = 9.10938356e-31; ///< Electron mass - const BoutReal Mp = 1.672621898e-27; ///< Proton mass - const BoutReal kb = 1.38064852e-23; ///< Boltzmanns constant - const BoutReal amu = 1.660539040e-27; ///< Unified atomic mass unit - const BoutReal M_Hydrogen = 1.008 * amu; ///< Mass of a Hydrogen atom - const BoutReal M_Deuterium = 2.01410178 * amu; ///< Mass of a Deuterium atom - const BoutReal M_Tritium = 3.0160492 * amu; ///< Mass of a Tritium atom + constexpr BoutReal c = 299792458; ///< Speed of light in vacuum + constexpr BoutReal mu0 = 4.e-7*PI; ///< Permeability of free space + constexpr BoutReal e0 = 1/(c*c*mu0); ///< Permittivity of free space + constexpr BoutReal qe = 1.602176634e-19; ///< Electron charge + constexpr BoutReal Me = 9.10938356e-31; ///< Electron mass + constexpr BoutReal Mp = 1.672621898e-27; ///< Proton mass + constexpr BoutReal kb = 1.38064852e-23; ///< Boltzmanns constant + constexpr BoutReal amu = 1.660539040e-27; ///< Unified atomic mass unit + constexpr BoutReal M_Hydrogen = 1.008 * amu; ///< Mass of a Hydrogen atom + constexpr BoutReal M_Deuterium = 2.01410178 * amu; ///< Mass of a Deuterium atom + constexpr BoutReal M_Tritium = 3.0160492 * amu; ///< Mass of a Tritium atom } #endif // __CONSTANTS_H__ diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 1e43f6e72e..187d9083c6 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -31,7 +31,7 @@ using BoutReal = double; /// Quiet NaN -const BoutReal BoutNaN = std::numeric_limits::quiet_NaN(); +constexpr BoutReal BoutNaN = std::numeric_limits::quiet_NaN(); #define ENUMSTR(val) {val, #val} #define STRENUM(val) {#val, val} From 91430beae0c7810d587bb0c99b52786117b05662 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 15:26:34 +0100 Subject: [PATCH 1408/1783] Replace multiple calls to dump.add with SAVE_REPEAT/ONCE in test --- .../test-drift-instability/2fluid.cxx | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/tests/integrated/test-drift-instability/2fluid.cxx b/tests/integrated/test-drift-instability/2fluid.cxx index 479413266d..59e151a6d1 100644 --- a/tests/integrated/test-drift-instability/2fluid.cxx +++ b/tests/integrated/test-drift-instability/2fluid.cxx @@ -255,8 +255,9 @@ int physics_init(bool UNUSED(restarting)) { output.write("ajpar\n"); }else { initial_profile("Ajpar", Ajpar); - if(ZeroElMass) - dump.add(Ajpar, "Ajpar", true); // output calculated Ajpar + if (ZeroElMass) { + SAVE_REPEAT(Ajpar); // output calculated Ajpar + } } if(evolve_vi) { @@ -283,19 +284,8 @@ int physics_init(bool UNUSED(restarting)) { comms.add(Apar); // Add any other variables to be dumped to file - dump.add(phi, "phi", true); - dump.add(Apar, "Apar", true); - dump.add(jpar, "jpar", true); - - dump.add(Ni0, "Ni0", false); - dump.add(Te0, "Te0", false); - dump.add(Ti0, "Ti0", false); - - dump.add(Te_x, "Te_x", false); - dump.add(Ti_x, "Ti_x", false); - dump.add(Ni_x, "Ni_x", false); - dump.add(rho_s, "rho_s", false); - dump.add(wci, "wci", false); + SAVE_REPEAT(phi, Apar, jpar); + SAVE_ONCE(Ni0, Te0, Ti0, Te_x, Ti_x, Ni_x, rho_s, wci); if (mesh->StaggerGrids) { maybe_ylow = CELL_YLOW; From 6c4b57f4295cb490cb798a5e416884323a7f7c87 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 15:29:51 +0100 Subject: [PATCH 1409/1783] Change SAVE_ONCE/REPEAT to use Datafile::addOnce/addRepeat --- include/datafile.hxx | 96 ++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/include/datafile.hxx b/include/datafile.hxx index 7236c35bb9..fc57e0d4b6 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -60,13 +60,13 @@ class Datafile { void close(); void setLowPrecision(); ///< Only output floats - template - void addRepeat(t &value, std::string name){ - add(value,name.c_str(),true); + template + void addRepeat(T& value, std::string name) { + add(value, name.c_str(), true); } - template - void addOnce(t &value, std::string name){ - add(value,name.c_str(),false); + template + void addOnce(T& value, std::string name) { + add(value, name.c_str(), false); } void add(int &i, const char *name, bool save_repeat = false); void add(BoutReal &r, const char *name, bool save_repeat = false); @@ -150,63 +150,63 @@ class Datafile { }; /// Write this variable once to the grid file -#define SAVE_ONCE1(var) bout::globals::dump.add(var, #var, 0); +#define SAVE_ONCE1(var) bout::globals::dump.addOnce(var, #var); #define SAVE_ONCE2(var1, var2) { \ - bout::globals::dump.add(var1, #var1, 0); \ - bout::globals::dump.add(var2, #var2, 0);} + bout::globals::dump.addOnce(var1, #var1); \ + bout::globals::dump.addOnce(var2, #var2);} #define SAVE_ONCE3(var1, var2, var3) {\ - bout::globals::dump.add(var1, #var1, 0); \ - bout::globals::dump.add(var2, #var2, 0); \ - bout::globals::dump.add(var3, #var3, 0);} + bout::globals::dump.addOnce(var1, #var1); \ + bout::globals::dump.addOnce(var2, #var2); \ + bout::globals::dump.addOnce(var3, #var3);} #define SAVE_ONCE4(var1, var2, var3, var4) { \ - bout::globals::dump.add(var1, #var1, 0); \ - bout::globals::dump.add(var2, #var2, 0); \ - bout::globals::dump.add(var3, #var3, 0); \ - bout::globals::dump.add(var4, #var4, 0);} + bout::globals::dump.addOnce(var1, #var1); \ + bout::globals::dump.addOnce(var2, #var2); \ + bout::globals::dump.addOnce(var3, #var3); \ + bout::globals::dump.addOnce(var4, #var4);} #define SAVE_ONCE5(var1, var2, var3, var4, var5) {\ - bout::globals::dump.add(var1, #var1, 0); \ - bout::globals::dump.add(var2, #var2, 0); \ - bout::globals::dump.add(var3, #var3, 0); \ - bout::globals::dump.add(var4, #var4, 0); \ - bout::globals::dump.add(var5, #var5, 0);} + bout::globals::dump.addOnce(var1, #var1); \ + bout::globals::dump.addOnce(var2, #var2); \ + bout::globals::dump.addOnce(var3, #var3); \ + bout::globals::dump.addOnce(var4, #var4); \ + bout::globals::dump.addOnce(var5, #var5);} #define SAVE_ONCE6(var1, var2, var3, var4, var5, var6) {\ - bout::globals::dump.add(var1, #var1, 0); \ - bout::globals::dump.add(var2, #var2, 0); \ - bout::globals::dump.add(var3, #var3, 0); \ - bout::globals::dump.add(var4, #var4, 0); \ - bout::globals::dump.add(var5, #var5, 0); \ - bout::globals::dump.add(var6, #var6, 0);} + bout::globals::dump.addOnce(var1, #var1); \ + bout::globals::dump.addOnce(var2, #var2); \ + bout::globals::dump.addOnce(var3, #var3); \ + bout::globals::dump.addOnce(var4, #var4); \ + bout::globals::dump.addOnce(var5, #var5); \ + bout::globals::dump.addOnce(var6, #var6);} #define SAVE_ONCE(...) \ { MACRO_FOR_EACH(SAVE_ONCE1, __VA_ARGS__) } /// Write this variable every timestep -#define SAVE_REPEAT1(var) bout::globals::dump.add(var, #var, 1); +#define SAVE_REPEAT1(var) bout::globals::dump.addRepeat(var, #var); #define SAVE_REPEAT2(var1, var2) { \ - bout::globals::dump.add(var1, #var1, 1); \ - bout::globals::dump.add(var2, #var2, 1);} + bout::globals::dump.addRepeat(var1, #var1); \ + bout::globals::dump.addRepeat(var2, #var2);} #define SAVE_REPEAT3(var1, var2, var3) {\ - bout::globals::dump.add(var1, #var1, 1); \ - bout::globals::dump.add(var2, #var2, 1); \ - bout::globals::dump.add(var3, #var3, 1);} + bout::globals::dump.addRepeat(var1, #var1); \ + bout::globals::dump.addRepeat(var2, #var2); \ + bout::globals::dump.addRepeat(var3, #var3);} #define SAVE_REPEAT4(var1, var2, var3, var4) { \ - bout::globals::dump.add(var1, #var1, 1); \ - bout::globals::dump.add(var2, #var2, 1); \ - bout::globals::dump.add(var3, #var3, 1); \ - bout::globals::dump.add(var4, #var4, 1);} + bout::globals::dump.addRepeat(var1, #var1); \ + bout::globals::dump.addRepeat(var2, #var2); \ + bout::globals::dump.addRepeat(var3, #var3); \ + bout::globals::dump.addRepeat(var4, #var4);} #define SAVE_REPEAT5(var1, var2, var3, var4, var5) {\ - bout::globals::dump.add(var1, #var1, 1); \ - bout::globals::dump.add(var2, #var2, 1); \ - bout::globals::dump.add(var3, #var3, 1); \ - bout::globals::dump.add(var4, #var4, 1); \ - bout::globals::dump.add(var5, #var5, 1);} + bout::globals::dump.addRepeat(var1, #var1); \ + bout::globals::dump.addRepeat(var2, #var2); \ + bout::globals::dump.addRepeat(var3, #var3); \ + bout::globals::dump.addRepeat(var4, #var4); \ + bout::globals::dump.addRepeat(var5, #var5);} #define SAVE_REPEAT6(var1, var2, var3, var4, var5, var6) {\ - bout::globals::dump.add(var1, #var1, 1); \ - bout::globals::dump.add(var2, #var2, 1); \ - bout::globals::dump.add(var3, #var3, 1); \ - bout::globals::dump.add(var4, #var4, 1); \ - bout::globals::dump.add(var5, #var5, 1); \ - bout::globals::dump.add(var6, #var6, 1);} + bout::globals::dump.addRepeat(var1, #var1); \ + bout::globals::dump.addRepeat(var2, #var2); \ + bout::globals::dump.addRepeat(var3, #var3); \ + bout::globals::dump.addRepeat(var4, #var4); \ + bout::globals::dump.addRepeat(var5, #var5); \ + bout::globals::dump.addRepeat(var6, #var6);} #define SAVE_REPEAT(...) \ { MACRO_FOR_EACH(SAVE_REPEAT1, __VA_ARGS__) } From fd7c91cbd14ceb6752ede26333a54515838d3c98 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 15:42:49 +0100 Subject: [PATCH 1410/1783] Get Options::root() by reference in IMEX example --- examples/IMEX/diffusion-nl/diffusion-nl.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/IMEX/diffusion-nl/diffusion-nl.cxx b/examples/IMEX/diffusion-nl/diffusion-nl.cxx index da685c9cd1..e89b0f337b 100644 --- a/examples/IMEX/diffusion-nl/diffusion-nl.cxx +++ b/examples/IMEX/diffusion-nl/diffusion-nl.cxx @@ -23,7 +23,7 @@ class DiffusionNL : public PhysicsModel { protected: int init(bool) { // Get the input parameter alpha - auto opt = Options::root(); + auto& opt = Options::root(); alpha = opt["alpha"].withDefault(2.5); // Specify that the operator is split From 3716cde73806a431cb8728f3a8abbb391bf66425 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 15:53:36 +0100 Subject: [PATCH 1411/1783] Rename unsplit_diffusive -> is_nonsplit_model_diffusive --- include/bout/solver.hxx | 4 ++-- src/solver/solver.cxx | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 29de99e13a..f0d74a57ca 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -459,8 +459,8 @@ private: /// Diffusive part (if split operator) rhsfunc phys_diff{nullptr}; - /// Should unsplit physics models be treated as diffusive? - bool unsplit_diffusive{true}; + /// Should non-split physics models be treated as diffusive? + bool is_nonsplit_model_diffusive{true}; /// Enable sources and solutions for Method of Manufactured Solutions bool mms{false}; diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index ac3739ec98..ebd979ffd7 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -53,9 +53,10 @@ Solver::Solver(Options* opts) mms((*options)["mms"].withDefault(false)), mms_initialise((*options)["mms_initialise"].withDefault(mms)) { - unsplit_diffusive = (*options)["unsplit_diffusive"] - .doc("If not a split operator, treat RHS as diffusive?") - .withDefault(true); + is_nonsplit_model_diffusive = + (*options)["is_nonsplit_model_diffusive"] + .doc("If not a split operator, treat RHS as diffusive?") + .withDefault(true); } /************************************************************************** @@ -1174,7 +1175,7 @@ int Solver::run_convective(BoutReal t) { status = model->runConvective(t); } else status = (*phys_conv)(t); - } else if (!unsplit_diffusive) { + } else if (!is_nonsplit_model_diffusive) { // Return total if (model) { status = model->runRHS(t); @@ -1212,7 +1213,7 @@ int Solver::run_diffusive(BoutReal t, bool linear) { status = (*phys_diff)(t); } post_rhs(t); - } else if (unsplit_diffusive) { + } else if (is_nonsplit_model_diffusive) { // Return total if (model) { status = model->runRHS(t); From 381e7ca3de83d020e2e10fbbff779d63eb3c4ae2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 15:55:01 +0100 Subject: [PATCH 1412/1783] Move is_nonsplit_model_diffusive init into Solver init list --- src/solver/solver.cxx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index ebd979ffd7..cab3f75a1a 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -50,14 +50,12 @@ char ***Solver::pargv = nullptr; Solver::Solver(Options* opts) : options(opts == nullptr ? &Options::root()["solver"] : opts), monitor_timestep((*options)["monitor_timestep"].withDefault(false)), + is_nonsplit_model_diffusive( + (*options)["is_nonsplit_model_diffusive"] + .doc("If not a split operator, treat RHS as diffusive?") + .withDefault(true)), mms((*options)["mms"].withDefault(false)), - mms_initialise((*options)["mms_initialise"].withDefault(mms)) { - - is_nonsplit_model_diffusive = - (*options)["is_nonsplit_model_diffusive"] - .doc("If not a split operator, treat RHS as diffusive?") - .withDefault(true); -} + mms_initialise((*options)["mms_initialise"].withDefault(mms)) {} /************************************************************************** * Add physics models From 1d3eeb67d60411055eaa63a6285c7ba557869847 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 16:57:54 +0100 Subject: [PATCH 1413/1783] Don't return const Fields from Laplace*::solve --- include/invert_laplace.hxx | 12 ++++++------ src/invert/laplace/impls/cyclic/cyclic_laplace.cxx | 4 ++-- src/invert/laplace/impls/cyclic/cyclic_laplace.hxx | 8 ++++---- .../laplace/impls/multigrid/multigrid_laplace.cxx | 2 +- .../laplace/impls/multigrid/multigrid_laplace.hxx | 4 ++-- src/invert/laplace/impls/mumps/mumps_laplace.cxx | 4 ++-- src/invert/laplace/impls/mumps/mumps_laplace.hxx | 6 +++--- src/invert/laplace/impls/naulin/naulin_laplace.cxx | 2 +- src/invert/laplace/impls/naulin/naulin_laplace.hxx | 8 ++++---- src/invert/laplace/impls/pdd/pdd.cxx | 4 ++-- src/invert/laplace/impls/pdd/pdd.hxx | 4 ++-- src/invert/laplace/impls/petsc/petsc_laplace.cxx | 6 ++---- src/invert/laplace/impls/petsc/petsc_laplace.hxx | 4 ++-- src/invert/laplace/impls/serial_band/serial_band.cxx | 6 ++---- src/invert/laplace/impls/serial_band/serial_band.hxx | 4 ++-- src/invert/laplace/impls/serial_tri/serial_tri.cxx | 6 ++---- src/invert/laplace/impls/serial_tri/serial_tri.hxx | 4 ++-- src/invert/laplace/impls/shoot/shoot_laplace.cxx | 2 +- src/invert/laplace/impls/shoot/shoot_laplace.hxx | 4 ++-- src/invert/laplace/impls/spt/spt.cxx | 10 ++++------ src/invert/laplace/impls/spt/spt.hxx | 8 ++++---- src/invert/laplace/invert_laplace.cxx | 8 ++++---- 22 files changed, 56 insertions(+), 64 deletions(-) diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index 772afc8bc5..43450172b3 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -177,13 +177,13 @@ public: /// Does this solver use Field3D coefficients (true) or only their DC component (false) virtual bool uses3DCoefs() const { return false; } - virtual const FieldPerp solve(const FieldPerp &b) = 0; - virtual const Field3D solve(const Field3D &b); - virtual const Field2D solve(const Field2D &b); + virtual FieldPerp solve(const FieldPerp &b) = 0; + virtual Field3D solve(const Field3D &b); + virtual Field2D solve(const Field2D &b); - virtual const FieldPerp solve(const FieldPerp &b, const FieldPerp &UNUSED(x0)) { return solve(b); } - virtual const Field3D solve(const Field3D &b, const Field3D &x0); - virtual const Field2D solve(const Field2D &b, const Field2D &x0); + virtual FieldPerp solve(const FieldPerp &b, const FieldPerp &UNUSED(x0)) { return solve(b); } + virtual Field3D solve(const Field3D &b, const Field3D &x0); + virtual Field2D solve(const Field2D &b, const Field2D &x0); /// Coefficients in tridiagonal inversion void tridagCoefs(int jx, int jy, int jz, dcomplex &a, dcomplex &b, dcomplex &c, diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index c29747b5d3..6c44a4b85e 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -91,7 +91,7 @@ LaplaceCyclic::~LaplaceCyclic() { delete cr; } -const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) { +FieldPerp LaplaceCyclic::solve(const FieldPerp& rhs, const FieldPerp& x0) { ASSERT1(localmesh == rhs.getMesh() && localmesh == x0.getMesh()); ASSERT1(rhs.getLocation() == location); ASSERT1(x0.getLocation() == location); @@ -247,7 +247,7 @@ const FieldPerp LaplaceCyclic::solve(const FieldPerp &rhs, const FieldPerp &x0) return x; } -const Field3D LaplaceCyclic::solve(const Field3D &rhs, const Field3D &x0) { +Field3D LaplaceCyclic::solve(const Field3D& rhs, const Field3D& x0) { TRACE("LaplaceCyclic::solve(Field3D, Field3D)"); ASSERT1(rhs.getLocation() == location); diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx index 356793dc67..1633a13909 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.hxx @@ -86,11 +86,11 @@ public: } using Laplacian::solve; - const FieldPerp solve(const FieldPerp &b) override {return solve(b,b);} - const FieldPerp solve(const FieldPerp &b, const FieldPerp &x0) override; + FieldPerp solve(const FieldPerp &b) override {return solve(b,b);} + FieldPerp solve(const FieldPerp &b, const FieldPerp &x0) override; - const Field3D solve(const Field3D &b) override {return solve(b,b);} - const Field3D solve(const Field3D &b, const Field3D &x0) override; + Field3D solve(const Field3D &b) override {return solve(b,b);} + Field3D solve(const Field3D &b, const Field3D &x0) override; private: Field2D Acoef, C1coef, C2coef, Dcoef; diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx index 7eea59ba62..15b52cdbdd 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.cxx @@ -201,7 +201,7 @@ BOUT_OMP(master) } } -const FieldPerp LaplaceMultigrid::solve(const FieldPerp &b_in, const FieldPerp &x0) { +FieldPerp LaplaceMultigrid::solve(const FieldPerp& b_in, const FieldPerp& x0) { TRACE("LaplaceMultigrid::solve(const FieldPerp, const FieldPerp)"); diff --git a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx index 0ef7f3bc39..e2eae6d926 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx +++ b/src/invert/laplace/impls/multigrid/multigrid_laplace.hxx @@ -194,12 +194,12 @@ public: bool uses3DCoefs() const override { return true; } - const FieldPerp solve(const FieldPerp &b) override { + FieldPerp solve(const FieldPerp &b) override { ASSERT1(localmesh == b.getMesh()); return solve(b, zeroFrom(b)); } - const FieldPerp solve(const FieldPerp &b_in, const FieldPerp &x0) override; + FieldPerp solve(const FieldPerp &b_in, const FieldPerp &x0) override; private: Field3D A,C1,C2,D; // ODE Coefficients diff --git a/src/invert/laplace/impls/mumps/mumps_laplace.cxx b/src/invert/laplace/impls/mumps/mumps_laplace.cxx index 853c214fcc..26b8338b7c 100644 --- a/src/invert/laplace/impls/mumps/mumps_laplace.cxx +++ b/src/invert/laplace/impls/mumps/mumps_laplace.cxx @@ -558,11 +558,11 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc, Mesh *mesh_in = mes // // } -const FieldPerp LaplaceMumps::solve(const FieldPerp &b, const FieldPerp &x0) { +FieldPerp LaplaceMumps::solve(const FieldPerp& b, const FieldPerp& x0) { return solve(b); } -const FieldPerp LaplaceMumps::solve(const FieldPerp &b) { +FieldPerp LaplaceMumps::solve(const FieldPerp& b) { ASSERT1(localmesh == b.getMesh()); ASSERT1(b.getLocation() == location); diff --git a/src/invert/laplace/impls/mumps/mumps_laplace.hxx b/src/invert/laplace/impls/mumps/mumps_laplace.hxx index ac2990dc6f..5fddcb594a 100644 --- a/src/invert/laplace/impls/mumps/mumps_laplace.hxx +++ b/src/invert/laplace/impls/mumps/mumps_laplace.hxx @@ -52,7 +52,7 @@ public: void setCoefEz(const Field2D &UNUSED(val)) override {} using Laplacian::solve; - const FieldPerp solve(const FieldPerp &UNUSED(b)) override{ + FieldPerp solve(const FieldPerp &UNUSED(b)) override{ throw BoutException("Mumps library not available"); } }; @@ -176,8 +176,8 @@ public: void setFlags(int f) {throw BoutException("May not change the value of flags during run in LaplaceMumps as it might change the number of non-zero matrix elements: flags may only be set in the options file.");} - const FieldPerp solve(const FieldPerp &b) override; - const FieldPerp solve(const FieldPerp &b, const FieldPerp &x0) override; + FieldPerp solve(const FieldPerp &b) override; + FieldPerp solve(const FieldPerp &b, const FieldPerp &x0) override; // const Field3D solve(const Field3D &b); // const Field3D solve(const Field3D &b, const Field3D &x0); diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index 92e280d86d..9b9da2f65d 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -186,7 +186,7 @@ LaplaceNaulin::~LaplaceNaulin() { delete delp2solver; } -const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { +Field3D LaplaceNaulin::solve(const Field3D& rhs, const Field3D& x0) { // Rearrange equation so first term is just Delp2(x): // D*Delp2(x) + 1/C1*Grad_perp(C2).Grad_perp(phi) = rhs // -> Delp2(x) + 1/(C1*D)*Grad_perp(C2).Grad_perp(phi) = rhs/D diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.hxx b/src/invert/laplace/impls/naulin/naulin_laplace.hxx index b1665cb386..2b47ffb3d1 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.hxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.hxx @@ -104,14 +104,14 @@ public: bool uses3DCoefs() const override { return true; } - const FieldPerp solve(const FieldPerp &b) override {return solve(b,b);} - const FieldPerp solve(const FieldPerp &UNUSED(b), + FieldPerp solve(const FieldPerp &b) override {return solve(b,b);} + FieldPerp solve(const FieldPerp &UNUSED(b), const FieldPerp &UNUSED(x0)) override { throw BoutException( "LaplaceNaulin has no solve(FieldPerp), must call solve(Field3D)"); } - const Field3D solve(const Field3D &b, const Field3D &x0) override; - const Field3D solve(const Field3D &b) override { + Field3D solve(const Field3D &b, const Field3D &x0) override; + Field3D solve(const Field3D &b) override { return solve(b, zeroFrom(b)); } diff --git a/src/invert/laplace/impls/pdd/pdd.cxx b/src/invert/laplace/impls/pdd/pdd.cxx index 7f8ac94aae..5a07ed4cde 100644 --- a/src/invert/laplace/impls/pdd/pdd.cxx +++ b/src/invert/laplace/impls/pdd/pdd.cxx @@ -38,7 +38,7 @@ #include "pdd.hxx" -const FieldPerp LaplacePDD::solve(const FieldPerp &b) { +FieldPerp LaplacePDD::solve(const FieldPerp& b) { ASSERT1(localmesh == b.getMesh()); ASSERT1(b.getLocation() == location); @@ -53,7 +53,7 @@ const FieldPerp LaplacePDD::solve(const FieldPerp &b) { return x; } -const Field3D LaplacePDD::solve(const Field3D &b) { +Field3D LaplacePDD::solve(const Field3D& b) { ASSERT1(localmesh == b.getMesh()); ASSERT1(b.getLocation() == location); diff --git a/src/invert/laplace/impls/pdd/pdd.hxx b/src/invert/laplace/impls/pdd/pdd.hxx index 62c2031afb..f16aba197d 100644 --- a/src/invert/laplace/impls/pdd/pdd.hxx +++ b/src/invert/laplace/impls/pdd/pdd.hxx @@ -78,8 +78,8 @@ public: } using Laplacian::solve; - const FieldPerp solve(const FieldPerp &b) override; - const Field3D solve(const Field3D &b) override; + FieldPerp solve(const FieldPerp &b) override; + Field3D solve(const Field3D &b) override; private: Field2D Acoef, Ccoef, Dcoef; diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.cxx b/src/invert/laplace/impls/petsc/petsc_laplace.cxx index 2945b03768..50e711e13a 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.cxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.cxx @@ -323,9 +323,7 @@ LaplacePetsc::LaplacePetsc(Options *opt, const CELL_LOC loc, Mesh *mesh_in) : // lastflag = -1; } -const FieldPerp LaplacePetsc::solve(const FieldPerp &b) { - return solve(b,b); -} +FieldPerp LaplacePetsc::solve(const FieldPerp& b) { return solve(b, b); } /*! * Solves Ax=b for x given a b and an initial guess for x (x0) @@ -344,7 +342,7 @@ const FieldPerp LaplacePetsc::solve(const FieldPerp &b) { * * \returns sol The solution x of the problem Ax=b. */ -const FieldPerp LaplacePetsc::solve(const FieldPerp &b, const FieldPerp &x0) { +FieldPerp LaplacePetsc::solve(const FieldPerp& b, const FieldPerp& x0) { TRACE("LaplacePetsc::solve"); ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.hxx b/src/invert/laplace/impls/petsc/petsc_laplace.hxx index b71b504f59..85b19da9fe 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.hxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.hxx @@ -174,8 +174,8 @@ public: if(pcsolve) pcsolve->setCoefEz(val); } - const FieldPerp solve(const FieldPerp &b) override; - const FieldPerp solve(const FieldPerp &b, const FieldPerp &x0) override; + FieldPerp solve(const FieldPerp &b) override; + FieldPerp solve(const FieldPerp &b, const FieldPerp &x0) override; int precon(Vec x, Vec y); ///< Preconditioner function diff --git a/src/invert/laplace/impls/serial_band/serial_band.cxx b/src/invert/laplace/impls/serial_band/serial_band.cxx index 1f169c43c4..8af81a0edc 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.cxx +++ b/src/invert/laplace/impls/serial_band/serial_band.cxx @@ -76,11 +76,9 @@ LaplaceSerialBand::LaplaceSerialBand(Options *opt, const CELL_LOC loc, Mesh *mes A.reallocate(localmesh->LocalNx, 5); } -const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b) { - return solve(b,b); -} +FieldPerp LaplaceSerialBand::solve(const FieldPerp& b) { return solve(b, b); } -const FieldPerp LaplaceSerialBand::solve(const FieldPerp &b, const FieldPerp &x0) { +FieldPerp LaplaceSerialBand::solve(const FieldPerp& b, const FieldPerp& x0) { ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); ASSERT1(b.getLocation() == location); ASSERT1(x0.getLocation() == location); diff --git a/src/invert/laplace/impls/serial_band/serial_band.hxx b/src/invert/laplace/impls/serial_band/serial_band.hxx index e2cfa61309..ca060a2186 100644 --- a/src/invert/laplace/impls/serial_band/serial_band.hxx +++ b/src/invert/laplace/impls/serial_band/serial_band.hxx @@ -67,8 +67,8 @@ public: } using Laplacian::solve; - const FieldPerp solve(const FieldPerp &b) override; - const FieldPerp solve(const FieldPerp &b, const FieldPerp &x0) override; + FieldPerp solve(const FieldPerp &b) override; + FieldPerp solve(const FieldPerp &b, const FieldPerp &x0) override; private: Field2D Acoef, Ccoef, Dcoef; diff --git a/src/invert/laplace/impls/serial_tri/serial_tri.cxx b/src/invert/laplace/impls/serial_tri/serial_tri.cxx index c8292262b8..12a1d0d410 100644 --- a/src/invert/laplace/impls/serial_tri/serial_tri.cxx +++ b/src/invert/laplace/impls/serial_tri/serial_tri.cxx @@ -49,9 +49,7 @@ LaplaceSerialTri::LaplaceSerialTri(Options *opt, CELL_LOC loc, Mesh *mesh_in) } } -const FieldPerp LaplaceSerialTri::solve(const FieldPerp &b) { - return solve(b,b); // Call the solver below -} +FieldPerp LaplaceSerialTri::solve(const FieldPerp& b) { return solve(b, b); } /*! * Solve Ax=b for x given b @@ -73,7 +71,7 @@ const FieldPerp LaplaceSerialTri::solve(const FieldPerp &b) { * * \return The inverted variable. */ -const FieldPerp LaplaceSerialTri::solve(const FieldPerp &b, const FieldPerp &x0) { +FieldPerp LaplaceSerialTri::solve(const FieldPerp& b, const FieldPerp& x0) { ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); ASSERT1(b.getLocation() == location); ASSERT1(x0.getLocation() == location); diff --git a/src/invert/laplace/impls/serial_tri/serial_tri.hxx b/src/invert/laplace/impls/serial_tri/serial_tri.hxx index 6486472af3..4cdb7cf8fe 100644 --- a/src/invert/laplace/impls/serial_tri/serial_tri.hxx +++ b/src/invert/laplace/impls/serial_tri/serial_tri.hxx @@ -66,8 +66,8 @@ public: } using Laplacian::solve; - const FieldPerp solve(const FieldPerp &b) override; - const FieldPerp solve(const FieldPerp &b, const FieldPerp &x0) override; + FieldPerp solve(const FieldPerp &b) override; + FieldPerp solve(const FieldPerp &b, const FieldPerp &x0) override; private: // The coefficents in // D*grad_perp^2(x) + (1/C)*(grad_perp(C))*grad_perp(x) + A*x = b diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.cxx b/src/invert/laplace/impls/shoot/shoot_laplace.cxx index 08dd46e217..36a4d13dca 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.cxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.cxx @@ -69,7 +69,7 @@ LaplaceShoot::LaplaceShoot(Options *opt, const CELL_LOC loc, Mesh *mesh_in) buffer.reallocate(4 * maxmode); } -const FieldPerp LaplaceShoot::solve(const FieldPerp &rhs) { +FieldPerp LaplaceShoot::solve(const FieldPerp& rhs) { ASSERT1(localmesh = rhs.getMesh()); ASSERT1(rhs.getLocation() == location); diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.hxx b/src/invert/laplace/impls/shoot/shoot_laplace.hxx index f18856d4a4..48f0975626 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.hxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.hxx @@ -68,8 +68,8 @@ public: } using Laplacian::solve; - const FieldPerp solve(const FieldPerp &b) override; - const FieldPerp solve(const FieldPerp &b, const FieldPerp &UNUSED(x0)) override {return solve(b);} + FieldPerp solve(const FieldPerp &b) override; + FieldPerp solve(const FieldPerp &b, const FieldPerp &UNUSED(x0)) override {return solve(b);} private: Field2D Acoef, Ccoef, Dcoef; diff --git a/src/invert/laplace/impls/spt/spt.cxx b/src/invert/laplace/impls/spt/spt.cxx index e5bae7a787..f75abe4f23 100644 --- a/src/invert/laplace/impls/spt/spt.cxx +++ b/src/invert/laplace/impls/spt/spt.cxx @@ -76,11 +76,9 @@ LaplaceSPT::~LaplaceSPT() { delete[] alldata; } -const FieldPerp LaplaceSPT::solve(const FieldPerp &b) { - return solve(b,b); -} +FieldPerp LaplaceSPT::solve(const FieldPerp& b) { return solve(b, b); } -const FieldPerp LaplaceSPT::solve(const FieldPerp &b, const FieldPerp &x0) { +FieldPerp LaplaceSPT::solve(const FieldPerp& b, const FieldPerp& x0) { ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); ASSERT1(b.getLocation() == location); ASSERT1(x0.getLocation() == location); @@ -120,7 +118,7 @@ const FieldPerp LaplaceSPT::solve(const FieldPerp &b, const FieldPerp &x0) { * This is done at the expense of more memory useage. Setting low_mem * in the config file uses less memory, and less communication overlap */ -const Field3D LaplaceSPT::solve(const Field3D &b) { +Field3D LaplaceSPT::solve(const Field3D& b) { ASSERT1(b.getLocation() == location); ASSERT1(localmesh = b.getMesh()); @@ -157,7 +155,7 @@ const Field3D LaplaceSPT::solve(const Field3D &b) { return x; } -const Field3D LaplaceSPT::solve(const Field3D &b, const Field3D &x0) { +Field3D LaplaceSPT::solve(const Field3D& b, const Field3D& x0) { ASSERT1(localmesh == b.getMesh() && localmesh == x0.getMesh()); if( ((inner_boundary_flags & INVERT_SET) && localmesh->firstX()) || diff --git a/src/invert/laplace/impls/spt/spt.hxx b/src/invert/laplace/impls/spt/spt.hxx index f02f91a393..63b3a8b3e4 100644 --- a/src/invert/laplace/impls/spt/spt.hxx +++ b/src/invert/laplace/impls/spt/spt.hxx @@ -97,11 +97,11 @@ public: } using Laplacian::solve; - const FieldPerp solve(const FieldPerp &b) override; - const FieldPerp solve(const FieldPerp &b, const FieldPerp &x0) override; + FieldPerp solve(const FieldPerp &b) override; + FieldPerp solve(const FieldPerp &b, const FieldPerp &x0) override; - const Field3D solve(const Field3D &b) override; - const Field3D solve(const Field3D &b, const Field3D &x0) override; + Field3D solve(const Field3D &b) override; + Field3D solve(const Field3D &b, const Field3D &x0) override; private: enum { SPT_DATA = 1123 }; ///< 'magic' number for SPT MPI messages diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index b1de244ecc..9c6021ee18 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -140,7 +140,7 @@ void Laplacian::cleanup() { * Solve routines **********************************************************************************/ -const Field3D Laplacian::solve(const Field3D &b) { +Field3D Laplacian::solve(const Field3D& b) { TRACE("Laplacian::solve(Field3D)"); ASSERT1(b.getLocation() == location); @@ -180,7 +180,7 @@ const Field3D Laplacian::solve(const Field3D &b) { } // NB: Really inefficient, but functional -const Field2D Laplacian::solve(const Field2D &b) { +Field2D Laplacian::solve(const Field2D& b) { ASSERT1(b.getLocation() == location); @@ -198,7 +198,7 @@ const Field2D Laplacian::solve(const Field2D &b) { * * \returns x All the y-slices of x_slice in the equation A*x_slice = b_slice */ -const Field3D Laplacian::solve(const Field3D &b, const Field3D &x0) { +Field3D Laplacian::solve(const Field3D& b, const Field3D& x0) { TRACE("Laplacian::solve(Field3D, Field3D)"); ASSERT1(b.getLocation() == location); @@ -231,7 +231,7 @@ const Field3D Laplacian::solve(const Field3D &b, const Field3D &x0) { return x; // Return the result of the inversion } -const Field2D Laplacian::solve(const Field2D &b, const Field2D &x0) { +Field2D Laplacian::solve(const Field2D& b, const Field2D& x0) { Field3D f = b, g = x0; f = solve(f, g); return DC(f); From ed115be4d735c42fcc65dd9137c5fbbd45777c65 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 17:03:02 +0100 Subject: [PATCH 1414/1783] Don't return const Fields from gyro-averages --- include/gyro_average.hxx | 32 +++++++++++--------------------- src/physics/gyro_average.cxx | 24 ++++++++++++------------ 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/include/gyro_average.hxx b/include/gyro_average.hxx index 887b2fef6b..38bab5c61f 100644 --- a/include/gyro_average.hxx +++ b/include/gyro_average.hxx @@ -44,7 +44,7 @@ const int GYRO_FLAGS = 64 + 16384 + 32768; ///< = INVERT_BNDRY_ONE | INVERT_IN_R /// /// @param[in] f The field to gyro-average /// @param[in] rho Gyro-radius -const Field3D gyroTaylor0(const Field3D &f, const Field3D &rho); +Field3D gyroTaylor0(const Field3D& f, const Field3D& rho); /// Gyro-average using Pade approximation /// @@ -55,12 +55,9 @@ const Field3D gyroTaylor0(const Field3D &f, const Field3D &rho); /// @param[in] f The field to gyro-average /// @param[in] rho Gyro-radius /// @param[in] flags Flags to be passed to the Laplacian inversion operator -const Field3D gyroPade0(const Field3D &f, const Field3D &rho, - int flags=GYRO_FLAGS); -const Field3D gyroPade0(const Field3D &f, const Field2D &rho, - int flags=GYRO_FLAGS); -const Field3D gyroPade0(const Field3D &f, BoutReal rho, - int flags=GYRO_FLAGS); +Field3D gyroPade0(const Field3D& f, const Field3D& rho, int flags = GYRO_FLAGS); +Field3D gyroPade0(const Field3D& f, const Field2D& rho, int flags = GYRO_FLAGS); +Field3D gyroPade0(const Field3D& f, BoutReal rho, int flags = GYRO_FLAGS); /// Pade approximation \f$Gamma_1 = (1 - \frac{1}{2} \rho^2 \nabla_\perp^2)g = f\f$ /// @@ -69,14 +66,10 @@ const Field3D gyroPade0(const Field3D &f, BoutReal rho, /// @param[in] f The field to gyro-average /// @param[in] rho Gyro-radius /// @param[in] flags Flags to be passed to the Laplacian inversion operator -const Field3D gyroPade1(const Field3D &f, const Field3D &rho, - int flags=GYRO_FLAGS); -const Field3D gyroPade1(const Field3D &f, const Field2D &rho, - int flags=GYRO_FLAGS); -const Field3D gyroPade1(const Field3D &f, BoutReal rho, - int flags=GYRO_FLAGS); -const Field2D gyroPade1(const Field2D &f, const Field2D &rho, - int flags=GYRO_FLAGS); +Field3D gyroPade1(const Field3D& f, const Field3D& rho, int flags = GYRO_FLAGS); +Field3D gyroPade1(const Field3D& f, const Field2D& rho, int flags = GYRO_FLAGS); +Field3D gyroPade1(const Field3D& f, BoutReal rho, int flags = GYRO_FLAGS); +Field2D gyroPade1(const Field2D& f, const Field2D& rho, int flags = GYRO_FLAGS); /// Pade approximation /// @@ -89,11 +82,8 @@ const Field2D gyroPade1(const Field2D &f, const Field2D &rho, /// @param[in] f The field to gyro-average /// @param[in] rho Gyro-radius /// @param[in] flags Flags to be passed to the Laplacian inversion operator -const Field3D gyroPade2(const Field3D &f, const Field3D &rho, - int flags=GYRO_FLAGS); -const Field3D gyroPade2(const Field3D &f, const Field2D &rho, - int flags=GYRO_FLAGS); -const Field3D gyroPade2(const Field3D &f, BoutReal rho, - int flags=GYRO_FLAGS); +Field3D gyroPade2(const Field3D& f, const Field3D& rho, int flags = GYRO_FLAGS); +Field3D gyroPade2(const Field3D& f, const Field2D& rho, int flags = GYRO_FLAGS); +Field3D gyroPade2(const Field3D& f, BoutReal rho, int flags = GYRO_FLAGS); #endif // __GYRO_AVERAGE_H__ diff --git a/src/physics/gyro_average.cxx b/src/physics/gyro_average.cxx index b8f1a0cd83..b57c44b07a 100644 --- a/src/physics/gyro_average.cxx +++ b/src/physics/gyro_average.cxx @@ -33,12 +33,12 @@ #include #include -const Field3D gyroTaylor0(const Field3D &f, const Field3D &rho) { +Field3D gyroTaylor0(const Field3D& f, const Field3D& rho) { return f + SQ(rho) * Delp2(f); } -const Field3D gyroPade0(const Field3D &f, BoutReal rho, int flags) { - +Field3D gyroPade0(const Field3D& f, BoutReal rho, int flags) { + Field2D a = 1.0; Field2D d = -rho*rho; @@ -46,7 +46,7 @@ const Field3D gyroPade0(const Field3D &f, BoutReal rho, int flags) { return invert_laplace(f, flags, &a, nullptr, &d); } -const Field3D gyroPade0(const Field3D &f, const Field2D &rho, int flags) { +Field3D gyroPade0(const Field3D& f, const Field2D& rho, int flags) { // Have to use Z average of rho for efficient inversion Field2D a = 1.0; @@ -56,12 +56,12 @@ const Field3D gyroPade0(const Field3D &f, const Field2D &rho, int flags) { return invert_laplace(f, flags, &a, nullptr, &d); } -const Field3D gyroPade0(const Field3D &f, const Field3D &rho, int flags) { +Field3D gyroPade0(const Field3D& f, const Field3D& rho, int flags) { // Have to use Z average of rho for efficient inversion return gyroPade0(f, DC(rho), flags); } -const Field3D gyroPade1(const Field3D &f, BoutReal rho, int flags) { +Field3D gyroPade1(const Field3D& f, BoutReal rho, int flags) { Field2D a = 1.0; Field2D d = -0.5*rho*rho; @@ -69,7 +69,7 @@ const Field3D gyroPade1(const Field3D &f, BoutReal rho, int flags) { return invert_laplace(f, flags, &a, nullptr, &d); } -const Field3D gyroPade1(const Field3D &f, const Field2D &rho, int flags) { +Field3D gyroPade1(const Field3D& f, const Field2D& rho, int flags) { Field2D a = 1.0; Field2D d = -0.5*rho*rho; @@ -77,18 +77,18 @@ const Field3D gyroPade1(const Field3D &f, const Field2D &rho, int flags) { return invert_laplace(f, flags, &a, nullptr, &d); } -const Field3D gyroPade1(const Field3D &f, const Field3D &rho, int flags) { +Field3D gyroPade1(const Field3D& f, const Field3D& rho, int flags) { return gyroPade1(f, DC(rho), flags); } -const Field2D gyroPade1(const Field2D &f, const Field2D &rho, int flags) { +Field2D gyroPade1(const Field2D& f, const Field2D& rho, int flags) { // Very inefficient implementation Field3D tmp = f; tmp = gyroPade1(tmp, rho, flags); return DC(tmp); } -const Field3D gyroPade2(const Field3D &f, BoutReal rho, int flags) { +Field3D gyroPade2(const Field3D& f, BoutReal rho, int flags) { Field3D result = gyroPade1(gyroPade1(f, rho, flags), rho, flags); result.getMesh()->communicate(result); result = 0.5*rho*rho*Delp2( result ); @@ -96,7 +96,7 @@ const Field3D gyroPade2(const Field3D &f, BoutReal rho, int flags) { return result; } -const Field3D gyroPade2(const Field3D &f, const Field2D &rho, int flags) { +Field3D gyroPade2(const Field3D& f, const Field2D& rho, int flags) { Field3D result = gyroPade1(gyroPade1(f, rho, flags), rho, flags); result.getMesh()->communicate(result); result = 0.5*rho*rho*Delp2( result ); @@ -104,7 +104,7 @@ const Field3D gyroPade2(const Field3D &f, const Field2D &rho, int flags) { return result; } -const Field3D gyroPade2(const Field3D &f, const Field3D &rho, int flags) { +Field3D gyroPade2(const Field3D& f, const Field3D& rho, int flags) { // Have to use Z average of rho for efficient inversion return gyroPade2(f, DC(rho), flags); } From cbc68669f0969a9d1b47f2b66a11d60defb673d0 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 17:04:29 +0100 Subject: [PATCH 1415/1783] Make Laplacian inversion flags constexpr --- include/invert_laplace.hxx | 46 +++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index 43450172b3..68b1d30f91 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -48,24 +48,38 @@ class Laplacian; #include "options.hxx" // Inversion flags for each boundary -const int INVERT_DC_GRAD = 1; ///< Zero-gradient for DC (constant in Z) component. Default is zero value -const int INVERT_AC_GRAD = 2; ///< Zero-gradient for AC (non-constant in Z) component. Default is zero value -const int INVERT_AC_LAP = 4; ///< Use zero-laplacian (decaying solution) to AC component -const int INVERT_SYM = 8; ///< Use symmetry to enforce either zero-value or zero-gradient -const int INVERT_SET = 16; ///< Set boundary to value -const int INVERT_RHS = 32; ///< Use input value in RHS boundary -const int INVERT_DC_LAP = 64; ///< Use zero-laplacian solution for DC component -const int INVERT_BNDRY_ONE = 128; ///< Only use one boundary point -const int INVERT_DC_GRADPAR = 256; -const int INVERT_DC_GRADPARINV = 512; -const int INVERT_IN_CYLINDER = 1024; ///< For use in cylindrical coordiate system. +/// Zero-gradient for DC (constant in Z) component. Default is zero value +constexpr int INVERT_DC_GRAD = 1; +/// Zero-gradient for AC (non-constant in Z) component. Default is zero value +constexpr int INVERT_AC_GRAD = 2; +/// Use zero-laplacian (decaying solution) to AC component +constexpr int INVERT_AC_LAP = 4; +/// Use symmetry to enforce either zero-value or zero-gradient +constexpr int INVERT_SYM = 8; +/// Set boundary to value +constexpr int INVERT_SET = 16; +/// Use input value in RHS boundary +constexpr int INVERT_RHS = 32; +/// Use zero-laplacian solution for DC component +constexpr int INVERT_DC_LAP = 64; +/// Only use one boundary point +constexpr int INVERT_BNDRY_ONE = 128; +constexpr int INVERT_DC_GRADPAR = 256; +constexpr int INVERT_DC_GRADPARINV = 512; +/// For use in cylindrical coordiate system. +constexpr int INVERT_IN_CYLINDER = 1024; // Global flags -const int INVERT_ZERO_DC = 1; ///< Zero the DC (constant in Z) component of the solution -const int INVERT_START_NEW = 2; ///< Iterative method start from solution=0. Has no effect for direct solvers -const int INVERT_BOTH_BNDRY_ONE = 4; ///< Sets the width of the boundaries to 1 -const int INVERT_4TH_ORDER = 8; ///< Use band solver for 4th order in x -const int INVERT_KX_ZERO = 16; ///< Zero the kx=0, n = 0 component +/// Zero the DC (constant in Z) component of the solution +constexpr int INVERT_ZERO_DC = 1; +/// Iterative method start from solution=0. Has no effect for direct solvers +constexpr int INVERT_START_NEW = 2; +/// Sets the width of the boundaries to 1 +constexpr int INVERT_BOTH_BNDRY_ONE = 4; +/// Use band solver for 4th order in x +constexpr int INVERT_4TH_ORDER = 8; +/// Zero the kx=0, n = 0 component +constexpr int INVERT_KX_ZERO = 16; /* // Legacy flags, can be used in calls to setFlags() From ca0d9ff41faf9979fef2459f408e28d5fd761e25 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 17:05:32 +0100 Subject: [PATCH 1416/1783] Replace deprecated invert_laplace in gyro_average Just do the "dumb" thing and essentially inline invert_laplace --- include/gyro_average.hxx | 5 ++- src/physics/gyro_average.cxx | 71 +++++++++++++++++++++++++++--------- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/include/gyro_average.hxx b/include/gyro_average.hxx index 38bab5c61f..818db3c059 100644 --- a/include/gyro_average.hxx +++ b/include/gyro_average.hxx @@ -33,8 +33,11 @@ #define __GYRO_AVERAGE_H__ #include "field3d.hxx" +#include "invert_laplace.hxx" -const int GYRO_FLAGS = 64 + 16384 + 32768; ///< = INVERT_BNDRY_ONE | INVERT_IN_RHS | INVERT_OUT_RHS; uses old-style Laplacian inversion flags +/// INVERT_BNDRY_ONE | INVERT_IN_RHS | INVERT_OUT_RHS; uses old-style +/// Laplacian inversion flags +constexpr int GYRO_FLAGS = 64 + 16384 + 32768; /// Gyro-average using Taylor series approximation /// diff --git a/src/physics/gyro_average.cxx b/src/physics/gyro_average.cxx index b57c44b07a..cce8843282 100644 --- a/src/physics/gyro_average.cxx +++ b/src/physics/gyro_average.cxx @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -38,22 +39,38 @@ Field3D gyroTaylor0(const Field3D& f, const Field3D& rho) { } Field3D gyroPade0(const Field3D& f, BoutReal rho, int flags) { + const Field2D a = 1.0; + const Field2D d = -rho * rho; - Field2D a = 1.0; - Field2D d = -rho*rho; - // Invert, leaving boundaries unchanged - return invert_laplace(f, flags, &a, nullptr, &d); + + Timer timer("invert"); + + auto* lap = Laplacian::defaultInstance(); + + lap->setCoefA(a); + lap->setCoefC(1.0); + lap->setCoefD(d); + lap->setFlags(flags); + + return lap->solve(f).setLocation(f.getLocation()); } Field3D gyroPade0(const Field3D& f, const Field2D& rho, int flags) { - // Have to use Z average of rho for efficient inversion - - Field2D a = 1.0; - Field2D d = -rho*rho; - + const Field2D a = 1.0; + const Field2D d = -rho * rho; + // Invert, leaving boundaries unchanged - return invert_laplace(f, flags, &a, nullptr, &d); + Timer timer("invert"); + + auto* lap = Laplacian::defaultInstance(); + + lap->setCoefA(a); + lap->setCoefC(1.0); + lap->setCoefD(d); + lap->setFlags(flags); + + return lap->solve(f).setLocation(f.getLocation()); } Field3D gyroPade0(const Field3D& f, const Field3D& rho, int flags) { @@ -62,19 +79,37 @@ Field3D gyroPade0(const Field3D& f, const Field3D& rho, int flags) { } Field3D gyroPade1(const Field3D& f, BoutReal rho, int flags) { - Field2D a = 1.0; - Field2D d = -0.5*rho*rho; - + const Field2D a = 1.0; + const Field2D d = -0.5 * rho * rho; + // Invert, leaving boundaries unchanged - return invert_laplace(f, flags, &a, nullptr, &d); + Timer timer("invert"); + + auto* lap = Laplacian::defaultInstance(); + + lap->setCoefA(a); + lap->setCoefC(1.0); + lap->setCoefD(d); + lap->setFlags(flags); + + return lap->solve(f).setLocation(f.getLocation()); } Field3D gyroPade1(const Field3D& f, const Field2D& rho, int flags) { - Field2D a = 1.0; - Field2D d = -0.5*rho*rho; - + const Field2D a = 1.0; + const Field2D d = -0.5 * rho * rho; + // Invert, leaving boundaries unchanged - return invert_laplace(f, flags, &a, nullptr, &d); + Timer timer("invert"); + + auto* lap = Laplacian::defaultInstance(); + + lap->setCoefA(a); + lap->setCoefC(1.0); + lap->setCoefD(d); + lap->setFlags(flags); + + return lap->solve(f).setLocation(f.getLocation()); } Field3D gyroPade1(const Field3D& f, const Field3D& rho, int flags) { From 2d6eb65b5580b56dbd9853ad9b9eeb9c2c7e2bb2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 17:05:48 +0100 Subject: [PATCH 1417/1783] Clang-format gyro_average --- src/physics/gyro_average.cxx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/physics/gyro_average.cxx b/src/physics/gyro_average.cxx index cce8843282..135e53fd16 100644 --- a/src/physics/gyro_average.cxx +++ b/src/physics/gyro_average.cxx @@ -4,12 +4,12 @@ * * 2010-09-03 Ben Dudson * * Initial version, simple averaging operator - * + * ************************************************************************** * Copyright 2010 B.D.Dudson, S.Farley, M.V.Umansky, X.Q.Xu * * Contact: Ben Dudson, bd512@york.ac.uk - * + * * This file is part of BOUT++. * * BOUT++ is free software: you can redistribute it and/or modify @@ -28,9 +28,9 @@ **************************************************************/ #include -#include #include #include +#include #include #include @@ -126,7 +126,7 @@ Field2D gyroPade1(const Field2D& f, const Field2D& rho, int flags) { Field3D gyroPade2(const Field3D& f, BoutReal rho, int flags) { Field3D result = gyroPade1(gyroPade1(f, rho, flags), rho, flags); result.getMesh()->communicate(result); - result = 0.5*rho*rho*Delp2( result ); + result = 0.5 * rho * rho * Delp2(result); result.applyBoundary("dirichlet"); return result; } @@ -134,7 +134,7 @@ Field3D gyroPade2(const Field3D& f, BoutReal rho, int flags) { Field3D gyroPade2(const Field3D& f, const Field2D& rho, int flags) { Field3D result = gyroPade1(gyroPade1(f, rho, flags), rho, flags); result.getMesh()->communicate(result); - result = 0.5*rho*rho*Delp2( result ); + result = 0.5 * rho * rho * Delp2(result); result.applyBoundary("dirichlet"); return result; } @@ -143,4 +143,3 @@ Field3D gyroPade2(const Field3D& f, const Field3D& rho, int flags) { // Have to use Z average of rho for efficient inversion return gyroPade2(f, DC(rho), flags); } - From 3618646e5ab450832e3bbeea4642d65ad270b17a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 17:22:38 +0100 Subject: [PATCH 1418/1783] Replace MPI_Request[] with std::vector in globalfield --- src/field/globalfield.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/field/globalfield.cxx b/src/field/globalfield.cxx index 2b091547ba..40c912ca1c 100644 --- a/src/field/globalfield.cxx +++ b/src/field/globalfield.cxx @@ -108,7 +108,8 @@ void GlobalField2D::gather(const Field2D &f) { if(mype == data_on_proc) { // This processor will receive the data - auto* req = new MPI_Request[npes]; // Array of receive handles + // Array of receive handles + std::vector req(npes); // Post receives for(int p = 0; p < npes; p++) { @@ -138,7 +139,7 @@ void GlobalField2D::gather(const Field2D &f) { int pe; MPI_Status status; do { - MPI_Waitany(npes, req, &pe, &status); + MPI_Waitany(npes, req.data(), &pe, &status); if(pe != MPI_UNDEFINED) { // Unpack data from processor 'pe' @@ -156,7 +157,6 @@ void GlobalField2D::gather(const Field2D &f) { } }while(pe != MPI_UNDEFINED); } - delete[] req; }else { // Sending data to proc @@ -271,7 +271,8 @@ void GlobalField3D::gather(const Field3D &f) { if(mype == data_on_proc) { // This processor will receive the data - auto* req = new MPI_Request[npes]; // Array of receive handles + // Array of receive handles + std::vector req(npes); // Post receives for(int p = 0; p < npes; p++) { @@ -302,7 +303,7 @@ void GlobalField3D::gather(const Field3D &f) { int pe; MPI_Status status; do { - MPI_Waitany(npes, req, &pe, &status); + MPI_Waitany(npes, req.data(), &pe, &status); if(pe != MPI_UNDEFINED) { // Unpack data from processor 'pe' @@ -322,7 +323,6 @@ void GlobalField3D::gather(const Field3D &f) { } }while(pe != MPI_UNDEFINED); } - delete[] req; }else { // Sending data to proc From 5344dd418e1ff14f42dc470eee8eff02c713bf36 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 17:31:24 +0100 Subject: [PATCH 1419/1783] Replace hsize_t[] with std::vector in h5_format --- src/fileio/impls/hdf5/h5_format.cxx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/fileio/impls/hdf5/h5_format.cxx b/src/fileio/impls/hdf5/h5_format.cxx index 226ed502b9..f2dc17c550 100644 --- a/src/fileio/impls/hdf5/h5_format.cxx +++ b/src/fileio/impls/hdf5/h5_format.cxx @@ -201,10 +201,9 @@ const std::vector H5Format::getSize(const char *name) { size.push_back(1); return size; - } - else { - auto* dims = new hsize_t[nd]; - int error = H5Sget_simple_extent_dims(dataSpace, dims, nullptr); + } else { + std::vector dims(nd); + int error = H5Sget_simple_extent_dims(dataSpace, dims.data(), nullptr); if (error < 0) throw BoutException("Failed to get dimensions of dataSpace"); @@ -213,10 +212,7 @@ const std::vector H5Format::getSize(const char *name) { if (H5Dclose(dataSet) < 0) throw BoutException("Failed to close dataSet"); - for (int i=0; i Date: Thu, 9 May 2019 17:54:54 +0100 Subject: [PATCH 1420/1783] Use unique_ptr rather than raw pointer in InvertParCR --- src/invert/parderiv/impls/cyclic/cyclic.cxx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index db1cffdec0..2d27bf9a77 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -65,7 +65,7 @@ const Field3D InvertParCR::solve(const Field3D &f) { Field3D alignedField = toFieldAligned(f, RGN_NOX); // Create cyclic reduction object - auto* cr = new CyclicReduce(); + auto cr = bout::utils::make_unique>(); // Find out if we are on a boundary int size = localmesh->LocalNy - 2 * localmesh->ystart; @@ -206,9 +206,6 @@ const Field3D InvertParCR::solve(const Field3D &f) { for(int y=0;yLocalNz, result(x, y + localmesh->ystart - y0)); } - - // Delete cyclic reduction object - delete cr; return fromFieldAligned(result, RGN_NOBNDRY); } From a0b6c57630b557da7f173e975d3ca1a56cbbe6b4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 17:55:16 +0100 Subject: [PATCH 1421/1783] Replace old-style C casts with static_cast in PetscSolver --- src/solver/impls/petsc/petsc.cxx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/solver/impls/petsc/petsc.cxx b/src/solver/impls/petsc/petsc.cxx index 8d6562b73d..83265cedc9 100644 --- a/src/solver/impls/petsc/petsc.cxx +++ b/src/solver/impls/petsc/petsc.cxx @@ -635,10 +635,8 @@ PetscErrorCode PetscSolver::jac(Vec x, Vec y) { #undef __FUNCT__ #define __FUNCT__ "solver_f" PetscErrorCode solver_f(TS ts, BoutReal t, Vec globalin, Vec globalout, void *f_data) { - PetscSolver *s; - PetscFunctionBegin; - s = (PetscSolver*) f_data; + auto* s = static_cast(f_data); PetscLogEventBegin(s->solver_event,0,0,0,0); s->rhs(ts, t, globalin, globalout); PetscLogEventEnd(s->solver_event,0,0,0,0); @@ -840,7 +838,7 @@ PetscErrorCode PhysicsJacobianApply(Mat J, Vec x, Vec y) { #define __FUNCT__ "PetscMonitor" PetscErrorCode PetscMonitor(TS ts, PetscInt UNUSED(step), PetscReal t, Vec X, void *ctx) { PetscErrorCode ierr; - auto *s = (PetscSolver *)ctx; + auto* s = static_cast(ctx); PetscReal tfinal, dt; Vec interpolatedX; const PetscScalar *x; @@ -887,7 +885,7 @@ PetscErrorCode PetscSNESMonitor(SNES snes, PetscInt its, PetscReal norm, void *c PetscInt linear_its=0; BoutReal tmp = .0; snes_info row; - auto *s = (PetscSolver*)ctx; + auto *s = static_cast(ctx); PetscFunctionBegin; From 7fd6447e0d4950a9cdac73e461ce817ea839a97c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 9 May 2019 17:55:55 +0100 Subject: [PATCH 1422/1783] Add LaplacianNaulin::resetMeanIterations Enables Naulin solver test to make Laplacian on the stack instead of heap and re-initialising it --- .../laplace/impls/naulin/naulin_laplace.hxx | 1 + .../test_naulin_laplace.cxx | 83 +++++++++---------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.hxx b/src/invert/laplace/impls/naulin/naulin_laplace.hxx index b1665cb386..9ec584f741 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.hxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.hxx @@ -121,6 +121,7 @@ public: void setOuterBoundaryFlags(int f) override { Laplacian::setOuterBoundaryFlags(f); delp2solver->setOuterBoundaryFlags(f); } BoutReal getMeanIterations() const { return naulinsolver_mean_its; } + void resetMeanIterations() { naulinsolver_mean_its = 0; } private: LaplaceNaulin(const LaplaceNaulin&); LaplaceNaulin& operator=(const LaplaceNaulin&); diff --git a/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx b/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx index bbaa1cbf59..df7541c780 100644 --- a/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx +++ b/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx @@ -41,9 +41,8 @@ int main(int argc, char** argv) { // Initialise BOUT++, setting up mesh BoutInitialise(argc, argv); - //class Laplacian* invert = Laplacian::create(); Options* options = Options::getRoot()->getSection("laplace"); - auto* invert = new LaplaceNaulin(options); + LaplaceNaulin invert(options); // Solving equations of the form d*Grad_perp2(f) + 1/c*Grad_perp(c).Grad_perp(f) + a*f = b for various boundary conditions Field3D f1,a1,b1,c1,d1,sol1,bcheck1; @@ -53,7 +52,7 @@ int main(int argc, char** argv) { dump.add(mesh->getCoordinates()->G1,"G1"); dump.add(mesh->getCoordinates()->G3,"G3"); - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// // Test 1: zero-value Dirichlet boundaries f1 = FieldFactory::get()->create3D("f1:function", Options::getRoot(), mesh); d1 = FieldFactory::get()->create3D("d1:function", Options::getRoot(), mesh); @@ -63,14 +62,14 @@ int main(int argc, char** argv) { b1 = d1*Delp2(f1) + this_Grad_perp_dot_Grad_perp(c1,f1)/c1 + a1*f1; sol1 = 0.; - invert->setInnerBoundaryFlags(0); - invert->setOuterBoundaryFlags(0); - invert->setCoefA(a1); - invert->setCoefC(c1); - invert->setCoefD(d1); + invert.setInnerBoundaryFlags(0); + invert.setOuterBoundaryFlags(0); + invert.setCoefA(a1); + invert.setCoefC(c1); + invert.setCoefD(d1); try { - sol1 = invert->solve(b1); + sol1 = invert.solve(b1); mesh->communicate(sol1); checkData(sol1); bcheck1 = d1*Delp2(sol1) + this_Grad_perp_dot_Grad_perp(c1,sol1)/c1 + a1*sol1; @@ -87,7 +86,7 @@ int main(int argc, char** argv) { output<getMeanIterations()<<" iterations to converge"<setInnerBoundaryFlags(INVERT_DC_GRAD + INVERT_AC_GRAD); - invert->setOuterBoundaryFlags(INVERT_DC_GRAD + INVERT_AC_GRAD); - invert->setCoefA(a2); - invert->setCoefC(c2); - invert->setCoefD(d2); + invert.setInnerBoundaryFlags(INVERT_DC_GRAD + INVERT_AC_GRAD); + invert.setOuterBoundaryFlags(INVERT_DC_GRAD + INVERT_AC_GRAD); + invert.setCoefA(a2); + invert.setCoefC(c2); + invert.setCoefD(d2); try { - sol2 = invert->solve(b2); + sol2 = invert.solve(b2); mesh->communicate(sol2); bcheck2 = d2*Delp2(sol2) + this_Grad_perp_dot_Grad_perp(c2,sol2)/c2 + a2*sol2; absolute_error2 = f2-sol2; @@ -137,7 +136,7 @@ int main(int argc, char** argv) { output<getMeanIterations()<<" iterations to converge"<setInnerBoundaryFlags(INVERT_SET); - invert->setOuterBoundaryFlags(INVERT_SET); - invert->setCoefA(a3); - invert->setCoefC(c3); - invert->setCoefD(d3); + invert.setInnerBoundaryFlags(INVERT_SET); + invert.setOuterBoundaryFlags(INVERT_SET); + invert.setCoefA(a3); + invert.setCoefC(c3); + invert.setCoefD(d3); // make field to pass in boundary conditions Field3D x0 = 0.; @@ -180,7 +179,7 @@ int main(int argc, char** argv) { x0(mesh->xend+1,mesh->ystart,k) = 0.5*(f3(mesh->xend+1,mesh->ystart,k)+f3(mesh->xend,mesh->ystart,k)); try { - sol3 = invert->solve(b3, x0); + sol3 = invert.solve(b3, x0); mesh->communicate(sol3); bcheck3 = d3*Delp2(sol3) + this_Grad_perp_dot_Grad_perp(c3,f3)/c3 + a3*sol3; absolute_error3 = f3-sol3; @@ -196,7 +195,7 @@ int main(int argc, char** argv) { output<getMeanIterations()<<" iterations to converge"<setInnerBoundaryFlags(INVERT_DC_GRAD + INVERT_AC_GRAD + INVERT_SET); - invert->setOuterBoundaryFlags(INVERT_DC_GRAD + INVERT_AC_GRAD + INVERT_SET); - invert->setCoefA(a4); - invert->setCoefC(c4); - invert->setCoefD(d4); + invert.setInnerBoundaryFlags(INVERT_DC_GRAD + INVERT_AC_GRAD + INVERT_SET); + invert.setOuterBoundaryFlags(INVERT_DC_GRAD + INVERT_AC_GRAD + INVERT_SET); + invert.setCoefA(a4); + invert.setCoefC(c4); + invert.setCoefD(d4); // make field to pass in boundary conditions x0 = 0.; @@ -243,7 +242,7 @@ int main(int argc, char** argv) { /sqrt(mesh->getCoordinates()->g_11(mesh->xend,mesh->ystart)); try { - sol4 = invert->solve(b4, x0); + sol4 = invert.solve(b4, x0); mesh->communicate(sol4); bcheck4 = d4*Delp2(sol4) + this_Grad_perp_dot_Grad_perp(c4,sol4)/c4 + a4*sol4; absolute_error4 = f4-sol4; @@ -259,7 +258,7 @@ int main(int argc, char** argv) { output<getMeanIterations()<<" iterations to converge"< Date: Fri, 10 May 2019 11:03:44 +0100 Subject: [PATCH 1423/1783] Fix return type on empty Petsc Laplace solve --- src/invert/laplace/impls/petsc/petsc_laplace.hxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/invert/laplace/impls/petsc/petsc_laplace.hxx b/src/invert/laplace/impls/petsc/petsc_laplace.hxx index 85b19da9fe..b1f6a7290d 100644 --- a/src/invert/laplace/impls/petsc/petsc_laplace.hxx +++ b/src/invert/laplace/impls/petsc/petsc_laplace.hxx @@ -53,7 +53,9 @@ public: void setCoefEz(const Field2D &UNUSED(val)) override {} using Laplacian::solve; - const FieldPerp solve(const FieldPerp &UNUSED(b)) override {throw BoutException("PETSc not available");} + FieldPerp solve(const FieldPerp& UNUSED(b)) override { + throw BoutException("PETSc not available"); + } }; #else From b1dbd9ddfe6663ca136f7457469baa7ff40923f6 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Fri, 10 May 2019 22:53:27 +0100 Subject: [PATCH 1424/1783] Default initialise member variables Codacy complaining about variable `neq` not initialised in constructor. This initialises `neq` and other similar variables. --- src/solver/impls/split-rk/split-rk.hxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/solver/impls/split-rk/split-rk.hxx b/src/solver/impls/split-rk/split-rk.hxx index e5752cb4cc..82cca23d7c 100644 --- a/src/solver/impls/split-rk/split-rk.hxx +++ b/src/solver/impls/split-rk/split-rk.hxx @@ -49,12 +49,12 @@ public: int run() override; private: - int nstages; ///< Number of stages in the RKL + int nstages{2}; ///< Number of stages in the RKL - BoutReal out_timestep; ///< The output timestep - int nsteps; ///< Number of output steps + BoutReal out_timestep{0.0}; ///< The output timestep + int nsteps{0}; ///< Number of output steps - BoutReal timestep; ///< The internal timestep + BoutReal timestep{0.0}; ///< The internal timestep bool adaptive{true}; ///< Adapt timestep using tolerances? BoutReal atol{1e-10}; ///< Absolute tolerance @@ -66,7 +66,7 @@ private: bool diagnose{false}; ///< Turn on diagnostic output - int nlocal, neq; ///< Number of variables on local processor and in total + int nlocal{0}, neq{0}; ///< Number of variables on local processor and in total /// System state Array state; From c12a7ecf535e94e590e87e87171449426961526b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 10 May 2019 23:04:21 +0100 Subject: [PATCH 1425/1783] Revert "Hypnotoad: 'H' is derivative of integral" This reverts commit e642121161e91cbe6b6fb3ddd01fcd44b973a13f. --- tools/tokamak_grids/gridgen/hypnotoad_version.pro | 5 ++++- tools/tokamak_grids/gridgen/process_grid.pro | 7 ++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/tokamak_grids/gridgen/hypnotoad_version.pro b/tools/tokamak_grids/gridgen/hypnotoad_version.pro index 502227aaf5..b202423e33 100644 --- a/tools/tokamak_grids/gridgen/hypnotoad_version.pro +++ b/tools/tokamak_grids/gridgen/hypnotoad_version.pro @@ -47,10 +47,13 @@ FUNCTION hypnotoad_version ; Less sensitive to small changes in implementation (e.g. changes ; in indexing due to different number of y-boundary guard cells). ; 1.2.1 * Don't smooth 'beta' after calculating + ; 1.2.2 * Revert incorrect change in 1.1.4 to the calculation of 'H' - the + ; derivative was with respect to theta, but the integral was in y + ; and for non-orthogonal grids thetaxy and yxy are different. major_version = 1 minor_version = 2 - patch_number = 1 + patch_number = 2 RETURN, LONG([major_version, minor_version, patch_number]) diff --git a/tools/tokamak_grids/gridgen/process_grid.pro b/tools/tokamak_grids/gridgen/process_grid.pro index c0dfd1bde8..76414ffd5f 100644 --- a/tools/tokamak_grids/gridgen/process_grid.pro +++ b/tools/tokamak_grids/gridgen/process_grid.pro @@ -1147,11 +1147,8 @@ retrybetacalc: ; Calculate zshift (qinty), sinty = d(zshift)/dpsi, and H = d(zshift)/dtheta qinty = my_int_y(pitch*(1.D + dyshiftdy), yxy, mesh, /nosmooth, loop=qloop) sinty = DDX(psixy,qinty) - - ; original calculation for H was: - ; H = dfdy_seps(qinty,thetaxy,mesh) - ; but qinty is an integral in y, so H is just the integrand - H = pitch*(1.D + dyshiftdy) + H = dfdy_seps(qinty,thetaxy,mesh) +; H = dfdy(qinty,thetaxy,mesh) ; NOTE: This is only valid in the core pol_angle = DBLARR(nx,ny_total) From 91bdaaa4fb4ffc18c39af6cfc9c9c0b25cef0646 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Sun, 12 May 2019 21:26:34 +0100 Subject: [PATCH 1426/1783] Handle attributes for missing variables If `init_missing` is set to true, reading could still fail when fetching attributes. This adds code to check for this, enabling restart with new evolving variables. --- src/fileio/datafile.cxx | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index e695e67527..1c3e8c1094 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -1147,7 +1147,15 @@ void Datafile::setAttribute(const std::string &varname, const std::string &attrn ///////////////////////////////////////////////////////////// bool Datafile::read_f2d(const std::string &name, Field2D *f, bool save_repeat) { - file->readFieldAttributes(name, *f); + try { + file->readFieldAttributes(name, *f); + } catch (const BoutException &e) { + if (init_missing) { + output_warn.write("\tWARNING: Could not read 2D field %s attributes.\n", name.c_str()); + } else { + throw; + } + } f->allocate(); @@ -1177,7 +1185,15 @@ bool Datafile::read_f2d(const std::string &name, Field2D *f, bool save_repeat) { } bool Datafile::read_f3d(const std::string &name, Field3D *f, bool save_repeat) { - file->readFieldAttributes(name, *f); + try { + file->readFieldAttributes(name, *f); + } catch (const BoutException &e) { + if (init_missing) { + output_warn.write("\tWARNING: Could not read 3D field %s attributes.\n", name.c_str()); + } else { + throw; + } + } f->allocate(); @@ -1213,7 +1229,15 @@ bool Datafile::read_f3d(const std::string &name, Field3D *f, bool save_repeat) { } bool Datafile::read_fperp(const std::string &name, FieldPerp *f, bool save_repeat) { - file->readFieldAttributes(name, *f); + try { + file->readFieldAttributes(name, *f); + } catch (const BoutException &e) { + if (init_missing) { + output_warn.write("\tWARNING: Could not read FieldPerp %s attributes.\n", name.c_str()); + } else { + throw; + } + } int yindex = f->getIndex(); if (yindex >= 0 and yindex < mesh->LocalNy) { From e62dc127d959a90cdc3b4800b169292f8a8f39bb Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 15 May 2019 17:09:26 +0100 Subject: [PATCH 1427/1783] Add RGN_NOCORNERS, RGN_XGUARDS, RGN_YGUARDS and RGN_ZGUARDS by default Add RGN_NOCORNERS which excludes the corner guard cells. This is useful for checks which want to allow the corner guard cells to be set to BoutNaN. Also add regions containing just x- y- or z-guard cells, which are useful in constructing RGN_NOCORNERS. Add RGN_NOZ for Field2D. Consistent with having a RGN_NOY for FieldPerp. May be useful in template functions which want to get RGN_NOZ from any type of Field. Rename what was RGN_NOCORNERS in invertable_operator.hxx to RGN_WITHBOUNDARIES as it has a different purpose - it excludes internal guard cells, but includes some boundary cells. --- include/bout/invertable_operator.hxx | 20 +-- include/bout/region.hxx | 2 +- src/mesh/mesh.cxx | 47 ++++++ tests/unit/field/test_field2d.cxx | 214 ++++++++++++++++++++++++++- tests/unit/field/test_field3d.cxx | 194 ++++++++++++++++++++++++ tests/unit/field/test_fieldperp.cxx | 175 ++++++++++++++++++++++ 6 files changed, 639 insertions(+), 13 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index f128468c85..1577f53fdc 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -76,7 +76,7 @@ PetscErrorCode fieldToPetscVec(const T& in, Vec out) { int counter = 0; // Should explore ability to OpenMP this - BOUT_FOR_SERIAL(i, in.getRegion("RGN_NOCORNERS")) { + BOUT_FOR_SERIAL(i, in.getRegion("RGN_WITHBNDRIES")) { vecData[counter] = in[i]; counter++; } @@ -101,7 +101,7 @@ PetscErrorCode petscVecToField(Vec in, T& out) { int counter = 0; // Should explore ability to OpenMP this - BOUT_FOR_SERIAL(i, out.getRegion("RGN_NOCORNERS")) { + BOUT_FOR_SERIAL(i, out.getRegion("RGN_WITHBNDRIES")) { out[i] = vecData[counter]; counter++; } @@ -194,9 +194,9 @@ public: "already been setup."); } - // Add the RGN_NOCORNERS region to the mesh. Requires RGN_NOBNDRY to be defined. + // Add the RGN_WITHBNDRIES region to the mesh. Requires RGN_NOBNDRY to be defined. if (std::is_same::value) { - if (not localmesh->hasRegion3D("RGN_NOCORNERS")) { + if (not localmesh->hasRegion3D("RGN_WITHBNDRIES")) { // This avoids all guard cells and corners but includes boundaries // Note we probably don't want to include periodic boundaries as these // are essentially just duplicate points so should be careful here (particularly @@ -233,11 +233,11 @@ public: } nocorner3D.unique(); - localmesh->addRegion3D("RGN_NOCORNERS", nocorner3D); + localmesh->addRegion3D("RGN_WITHBNDRIES", nocorner3D); } } else if (std::is_same::value) { - if (not localmesh->hasRegion2D("RGN_NOCORNERS")) { + if (not localmesh->hasRegion2D("RGN_WITHBNDRIES")) { // This avoids all guard cells and corners but includes boundaries Region nocorner2D = localmesh->getRegion2D("RGN_NOBNDRY"); if (!localmesh->periodicX) { @@ -267,11 +267,11 @@ public: } } nocorner2D.unique(); - localmesh->addRegion2D("RGN_NOCORNERS", nocorner2D); + localmesh->addRegion2D("RGN_WITHBNDRIES", nocorner2D); } } else if (std::is_same::value) { - if (not localmesh->hasRegionPerp("RGN_NOCORNERS")) { + if (not localmesh->hasRegionPerp("RGN_WITHBNDRIES")) { // This avoids all guard cells and corners but includes boundaries Region nocornerPerp = localmesh->getRegionPerp("RGN_NOBNDRY"); if (!localmesh->periodicX) { @@ -286,7 +286,7 @@ public: 1, localmesh->LocalNz, localmesh->maxregionblocksize); } nocornerPerp.unique(); - localmesh->addRegionPerp("RGN_NOCORNERS", nocornerPerp); + localmesh->addRegionPerp("RGN_WITHBNDRIES", nocornerPerp); } } else { @@ -297,7 +297,7 @@ public: PetscInt nlocal = 0; { T tmp(localmesh); - nlocal = tmp.getRegion("RGN_NOCORNERS").size(); + nlocal = tmp.getRegion("RGN_WITHBNDRIES").size(); } PetscInt nglobal = PETSC_DETERMINE; // Depends on type of T diff --git a/include/bout/region.hxx b/include/bout/region.hxx index 75d8b4cd17..1618a0ce83 100644 --- a/include/bout/region.hxx +++ b/include/bout/region.hxx @@ -451,7 +451,7 @@ inline std::ostream &operator<<(std::ostream &out, const RegionStats &stats){ /// } template class Region { // Following prevents a Region being created with anything other - // than Ind2D or Ind3D as template type + // than Ind2D, Ind3D or IndPerp as template type static_assert(std::is_base_of::value || std::is_base_of::value || std::is_base_of::value, "Region must be templated with one of IndPerp, Ind2D or Ind3D"); diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index de9284e4fa..45076b950a 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -410,6 +410,21 @@ void Mesh::createDefaultRegions(){ addRegion3D("RGN_NOZ", Region(0, LocalNx - 1, 0, LocalNy - 1, zstart, zend, LocalNy, LocalNz, maxregionblocksize)); addRegion3D("RGN_GUARDS", mask(getRegion3D("RGN_ALL"), getRegion3D("RGN_NOBNDRY"))); + addRegion3D("RGN_XGUARDS", Region(0, xstart - 1, ystart, yend, zstart, zend, + LocalNy, LocalNz, maxregionblocksize) + + Region(xend + 1, LocalNx - 1, ystart, yend, zstart, zend, + LocalNy, LocalNz, maxregionblocksize)); + addRegion3D("RGN_YGUARDS", Region(xstart, xend, 0, ystart - 1, zstart, zend, + LocalNy, LocalNz, maxregionblocksize) + + Region(xstart, xend, yend + 1, LocalNy - 1, zstart, zend, + LocalNy, LocalNz, maxregionblocksize)); + addRegion3D("RGN_ZGUARDS", Region(xstart, xend, ystart, yend, 0, zstart - 1, + LocalNy, LocalNz, maxregionblocksize) + + Region(xstart, xend, ystart, yend, zend + 1, LocalNz - 1, + LocalNy, LocalNz, maxregionblocksize)); + addRegion3D("RGN_NOCORNERS", + (getRegion3D("RGN_NOBNDRY") + getRegion3D("RGN_XGUARDS") + + getRegion3D("RGN_YGUARDS") + getRegion3D("RGN_ZGUARDS")).unique()); //2D regions addRegion2D("RGN_ALL", Region(0, LocalNx - 1, 0, LocalNy - 1, 0, 0, LocalNy, 1, @@ -420,7 +435,24 @@ void Mesh::createDefaultRegions(){ maxregionblocksize)); addRegion2D("RGN_NOY", Region(0, LocalNx - 1, ystart, yend, 0, 0, LocalNy, 1, maxregionblocksize)); + addRegion2D("RGN_NOZ", Region(0, LocalNx - 1, 0, LocalNy - 1, 0, 0, LocalNy, 1, + maxregionblocksize)); addRegion2D("RGN_GUARDS", mask(getRegion2D("RGN_ALL"), getRegion2D("RGN_NOBNDRY"))); + addRegion2D("RGN_XGUARDS", Region(0, xstart - 1, ystart, yend, 0, 0, LocalNy, 1, + maxregionblocksize) + + Region(xend + 1, LocalNx - 1, ystart, yend, 0, 0, LocalNy, 1, + maxregionblocksize)); + addRegion2D("RGN_YGUARDS", Region(xstart, xend, 0, ystart - 1, 0, 0, LocalNy, 1, + maxregionblocksize) + + Region(xstart, xend, yend + 1, LocalNy - 1, 0, 0, LocalNy, 1, + maxregionblocksize)); + addRegion2D("RGN_ZGUARDS", Region(xstart, xend, ystart, yend, 0, -1, LocalNy, 1, + maxregionblocksize) + + Region(xstart, xend, ystart, yend, 0, -1, LocalNy, 1, + maxregionblocksize)); + addRegion2D("RGN_NOCORNERS", + (getRegion2D("RGN_NOBNDRY") + getRegion2D("RGN_XGUARDS") + + getRegion2D("RGN_YGUARDS") + getRegion2D("RGN_ZGUARDS")).unique()); // Perp regions addRegionPerp("RGN_ALL", Region(0, LocalNx - 1, 0, 0, 0, LocalNz - 1, 1, @@ -435,6 +467,21 @@ void Mesh::createDefaultRegions(){ addRegionPerp("RGN_NOZ", Region(0, LocalNx - 1, 0, 0, zstart, zend, 1, LocalNz, maxregionblocksize)); addRegionPerp("RGN_GUARDS", mask(getRegionPerp("RGN_ALL"), getRegionPerp("RGN_NOBNDRY"))); + addRegionPerp("RGN_XGUARDS", Region(0, xstart - 1, 0, 0, zstart, zend, 1, + LocalNz, maxregionblocksize) + + Region(xend + 1, LocalNx - 1, 0, 0, zstart, zend, 1, + LocalNz, maxregionblocksize)); + addRegionPerp("RGN_YGUARDS", Region(xstart, xend, 0, -1, zstart, zend, 1, + LocalNz, maxregionblocksize) + + Region(xstart, xend, 0, -1, zstart, zend, 1, + LocalNz, maxregionblocksize)); + addRegionPerp("RGN_ZGUARDS", Region(xstart, xend, 0, 0, 0, zstart - 1, 1, + LocalNz, maxregionblocksize) + + Region(xstart, xend, 0, 0, zend + 1, LocalNz - 1, 1, + LocalNz, maxregionblocksize)); + addRegionPerp("RGN_NOCORNERS", + (getRegionPerp("RGN_NOBNDRY") + getRegionPerp("RGN_XGUARDS") + + getRegionPerp("RGN_YGUARDS") + getRegionPerp("RGN_ZGUARDS")).unique()); // Construct index lookup for 3D-->2D indexLookup3Dto2D = Array(LocalNx*LocalNy*LocalNz); diff --git a/tests/unit/field/test_field2d.cxx b/tests/unit/field/test_field2d.cxx index 3c06cda286..ea0f5919ca 100644 --- a/tests/unit/field/test_field2d.cxx +++ b/tests/unit/field/test_field2d.cxx @@ -473,10 +473,220 @@ TEST_F(Field2DTest, IterateOverRGN_NOY) { TEST_F(Field2DTest, IterateOverRGN_NOZ) { Field2D field = 1.0; - // This is not a valid region for Field2D - EXPECT_THROW(field.getRegion(RGN_NOZ), BoutException); + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0}); + test_indices.insert({0, 1}); + test_indices.insert({1, 0}); + test_indices.insert({1, 1}); + + // This is the set of indices actually inside the region we want + std::set> region_indices; + region_indices.insert({0, 0}); + region_indices.insert({0, 1}); + region_indices.insert({1, 0}); + region_indices.insert({1, 1}); + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (auto index : test_indices) { + field(index[0], index[1]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (auto &i : field.getRegion(RGN_NOZ)) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.y()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, ((nx * ny) - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); +} + +TEST_F(Field2DTest, IterateOverRGN_XGUARDS) { + Field2D field; + + field = 1.0; + + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0}); + test_indices.insert({0, 1}); + test_indices.insert({1, 0}); + test_indices.insert({1, 1}); + + // This is the set of indices actually inside the region we want + std::set> region_indices; + region_indices.insert({0, 1}); + + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (const auto index : test_indices) { + field(index[0], index[1]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (const auto &i : field.getRegion("RGN_XGUARDS")) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.y()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, ((2 * (ny - 2)) - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); +} + +TEST_F(Field2DTest, IterateOverRGN_YGUARDS) { + Field2D field; + + field = 1.0; + + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0}); + test_indices.insert({0, 1}); + test_indices.insert({1, 0}); + test_indices.insert({1, 1}); + + // This is the set of indices actually inside the region we want + std::set> region_indices; + region_indices.insert({1, 0}); + + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (const auto index : test_indices) { + field(index[0], index[1]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (const auto &i : field.getRegion("RGN_YGUARDS")) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.y()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, (((nx - 2) * 2) - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); } +TEST_F(Field2DTest, IterateOverRGN_ZGUARDS) { + Field2D field; + + field = 1.0; + + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0}); + test_indices.insert({0, 1}); + test_indices.insert({1, 0}); + test_indices.insert({1, 1}); + + // This is the set of indices actually inside the region we want + std::set> region_indices; + + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (const auto index : test_indices) { + field(index[0], index[1]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (const auto &i : field.getRegion("RGN_ZGUARDS")) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.y()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, ((nx - 2) * (ny - 2) * 0 - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); +} + +TEST_F(Field2DTest, IterateOverRGN_NOCORNERS) { + Field2D field; + + field = 1.0; + + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0}); + test_indices.insert({0, 1}); + test_indices.insert({1, 0}); + test_indices.insert({1, 1}); + + // This is the set of indices actually inside the region we want + std::set> region_indices; + region_indices.insert({0, 1}); + region_indices.insert({1, 0}); + region_indices.insert({1, 1}); + + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (const auto index : test_indices) { + field(index[0], index[1]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (const auto &i : field.getRegion("RGN_NOCORNERS")) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.y()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, ((nx * ny - 4) - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); +} + + TEST_F(Field2DTest, Indexing) { Field2D field; diff --git a/tests/unit/field/test_field3d.cxx b/tests/unit/field/test_field3d.cxx index aa30224b32..8d4925e197 100644 --- a/tests/unit/field/test_field3d.cxx +++ b/tests/unit/field/test_field3d.cxx @@ -671,6 +671,200 @@ TEST_F(Field3DTest, IterateOverRGN_NOZ) { EXPECT_TRUE(region_indices == result_indices); } +TEST_F(Field3DTest, IterateOverRGN_XGUARDS) { + Field3D field; + + field = 1.0; + + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0, 0}); + test_indices.insert({0, 0, 1}); + test_indices.insert({0, 1, 0}); + test_indices.insert({1, 0, 0}); + test_indices.insert({0, 1, 1}); + test_indices.insert({1, 0, 1}); + test_indices.insert({1, 1, 0}); + test_indices.insert({1, 1, 1}); + + // This is the set of indices actually inside the region we want + std::set> region_indices; + region_indices.insert({0, 1, 0}); + region_indices.insert({0, 1, 1}); + + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (const auto index : test_indices) { + field(index[0], index[1], index[2]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (const auto &i : field.getRegion("RGN_XGUARDS")) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.y(), i.z()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, ((2 * (ny - 2) * nz) - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); +} + +TEST_F(Field3DTest, IterateOverRGN_YGUARDS) { + Field3D field; + + field = 1.0; + + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0, 0}); + test_indices.insert({0, 0, 1}); + test_indices.insert({0, 1, 0}); + test_indices.insert({1, 0, 0}); + test_indices.insert({0, 1, 1}); + test_indices.insert({1, 0, 1}); + test_indices.insert({1, 1, 0}); + test_indices.insert({1, 1, 1}); + + // This is the set of indices actually inside the region we want + std::set> region_indices; + region_indices.insert({1, 0, 0}); + region_indices.insert({1, 0, 1}); + + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (const auto index : test_indices) { + field(index[0], index[1], index[2]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (const auto &i : field.getRegion("RGN_YGUARDS")) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.y(), i.z()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, (((nx - 2) * 2 * nz) - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); +} + +TEST_F(Field3DTest, IterateOverRGN_ZGUARDS) { + Field3D field; + + field = 1.0; + + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0, 0}); + test_indices.insert({0, 0, 1}); + test_indices.insert({0, 1, 0}); + test_indices.insert({1, 0, 0}); + test_indices.insert({0, 1, 1}); + test_indices.insert({1, 0, 1}); + test_indices.insert({1, 1, 0}); + test_indices.insert({1, 1, 1}); + + // This is the set of indices actually inside the region we want + std::set> region_indices; + + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (const auto index : test_indices) { + field(index[0], index[1], index[2]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (const auto &i : field.getRegion("RGN_ZGUARDS")) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.y(), i.z()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, ((nx - 2) * (ny - 2) * 0 - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); +} + +TEST_F(Field3DTest, IterateOverRGN_NOCORNERS) { + Field3D field; + + field = 1.0; + + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0, 0}); + test_indices.insert({0, 0, 1}); + test_indices.insert({0, 1, 0}); + test_indices.insert({1, 0, 0}); + test_indices.insert({0, 1, 1}); + test_indices.insert({1, 0, 1}); + test_indices.insert({1, 1, 0}); + test_indices.insert({1, 1, 1}); + + // This is the set of indices actually inside the region we want + std::set> region_indices; + region_indices.insert({0, 1, 0}); + region_indices.insert({1, 0, 0}); + region_indices.insert({0, 1, 1}); + region_indices.insert({1, 0, 1}); + region_indices.insert({1, 1, 0}); + region_indices.insert({1, 1, 1}); + + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (const auto index : test_indices) { + field(index[0], index[1], index[2]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (const auto &i : field.getRegion("RGN_NOCORNERS")) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.y(), i.z()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, (((nx * ny - 4) * nz) - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); +} + TEST_F(Field3DTest, IterateOver2DRGN_ALL) { Field3D field; field.allocate(); diff --git a/tests/unit/field/test_fieldperp.cxx b/tests/unit/field/test_fieldperp.cxx index 8d7074bf93..e8943c368e 100644 --- a/tests/unit/field/test_fieldperp.cxx +++ b/tests/unit/field/test_fieldperp.cxx @@ -419,6 +419,181 @@ TEST_F(FieldPerpTest, IterateOverRGN_NOX) { EXPECT_TRUE(region_indices == result_indices); } +TEST_F(FieldPerpTest, IterateOverRGN_XGUARDS) { + FieldPerp field; + + field = 1.0; + + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0}); + test_indices.insert({0, 1}); + test_indices.insert({1, 0}); + test_indices.insert({1, 1}); + + // This is the set of indices actually inside the region we want + std::set> region_indices; + region_indices.insert({0, 0}); + region_indices.insert({0, 1}); + + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (const auto index : test_indices) { + field(index[0], index[1]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (const auto &i : field.getRegion("RGN_XGUARDS")) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.z()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, ((2 * nz) - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); +} + +TEST_F(FieldPerpTest, IterateOverRGN_YGUARDS) { + FieldPerp field; + + field = 1.0; + + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0}); + test_indices.insert({0, 1}); + test_indices.insert({1, 0}); + test_indices.insert({1, 1}); + + // This is the set of indices actually inside the region we want + std::set> region_indices; + + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (const auto index : test_indices) { + field(index[0], index[1]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (const auto &i : field.getRegion("RGN_YGUARDS")) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.z()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, (((nx - 2) * 0 * nz) - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); +} + +TEST_F(FieldPerpTest, IterateOverRGN_ZGUARDS) { + FieldPerp field; + + field = 1.0; + + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0}); + test_indices.insert({0, 1}); + test_indices.insert({1, 0}); + test_indices.insert({1, 1}); + + // This is the set of indices actually inside the region we want + std::set> region_indices; + + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (const auto index : test_indices) { + field(index[0], index[1]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (const auto &i : field.getRegion("RGN_ZGUARDS")) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.z()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, ((nx - 2) * 0 - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); +} + +TEST_F(FieldPerpTest, IterateOverRGN_NOCORNERS) { + FieldPerp field; + + field = 1.0; + + const BoutReal sentinel = -99.0; + + // We use a set in case for some reason the iterator doesn't visit + // each point in the order we expect. + std::set> test_indices; + test_indices.insert({0, 0}); + test_indices.insert({0, 1}); + test_indices.insert({1, 0}); + test_indices.insert({1, 1}); + + // This is the set of indices actually inside the region we want + std::set> region_indices; + region_indices.insert({0, 0}); + region_indices.insert({0, 1}); + region_indices.insert({1, 0}); + region_indices.insert({1, 1}); + + const int num_sentinels = region_indices.size(); + + // Assign sentinel value to watch out for to our chosen points + for (const auto index : test_indices) { + field(index[0], index[1]) = sentinel; + } + + int found_sentinels = 0; + BoutReal sum = 0.0; + std::set> result_indices; + + for (const auto &i : field.getRegion("RGN_NOCORNERS")) { + sum += field[i]; + if (field[i] == sentinel) { + result_indices.insert({i.x(), i.z()}); + ++found_sentinels; + } + } + + EXPECT_EQ(found_sentinels, num_sentinels); + EXPECT_EQ(sum, ((nx * nz) - num_sentinels) + (num_sentinels * sentinel)); + EXPECT_TRUE(region_indices == result_indices); +} + + TEST_F(FieldPerpTest, Indexing) { FieldPerp field; From ea89cfce56aa199b4bd40e066b677c8fa49c11e0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 15 May 2019 12:22:39 +0100 Subject: [PATCH 1428/1783] toString functions for Ind3D, Ind2D and IndPerp These may be useful for creating error or warning messages. --- include/bout/region.hxx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/include/bout/region.hxx b/include/bout/region.hxx index 1618a0ce83..d4a63f8bc9 100644 --- a/include/bout/region.hxx +++ b/include/bout/region.hxx @@ -367,6 +367,23 @@ using Ind3D = SpecificInd; using Ind2D = SpecificInd; using IndPerp = SpecificInd; +/// Get string representation of Ind3D +inline const std::string toString(const Ind3D& i) { + return "(" + std::to_string(i.x()) + ", " + + std::to_string(i.y()) + ", " + + std::to_string(i.z()) + ")"; +} +/// Get string representation of Ind2D +inline const std::string toString(const Ind2D& i) { + return "(" + std::to_string(i.x()) + ", " + + std::to_string(i.y()) + ")"; +} +/// Get string representation of IndPerp +inline const std::string toString(const IndPerp& i) { + return "(" + std::to_string(i.x()) + ", " + + std::to_string(i.z()) + ")"; +} + /// Structure to hold various derived "statistics" from a particular region struct RegionStats { int numBlocks = 0; ///< How many blocks From 244334761e30e45eb938bafa1383f7338d6adb9d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 15 May 2019 12:23:31 +0100 Subject: [PATCH 1429/1783] checkFinite and checkPositive functions These fill a similar role to 'finite(f)' and 'min(f) > 0.', but if the check fails, they throw an exception that includes the array indices where the first failure was found. --- include/field.hxx | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/include/field.hxx b/include/field.hxx index 763d633284..3c69b86995 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -29,6 +29,7 @@ class Field; #ifndef __FIELD_H__ #define __FIELD_H__ +#include #include #include @@ -36,6 +37,7 @@ class Field; #include "boutexception.hxx" #include #include "msg_stack.hxx" +#include "bout/region.hxx" #include "stencils.hxx" #include @@ -269,4 +271,42 @@ inline T filledFrom(const T& f, BoutReal fill_value) { template T operator+(const T& f) {return f;} +/// Check if all values of a field \p var are finite. Loops over all points including the +/// boundaries by default (can be changed using the \p rgn argument) +/// If any element is not finite, throws an exception that includes the position of the +/// first found. +template +inline void checkFinite(const T& f, const std::string& name="field", const std::string& rgn="RGN_ALL") { + AUTO_TRACE(); + + if (!f.isAllocated()) { + throw BoutException("%s is not allocated", name.c_str()); + } + + BOUT_FOR_SERIAL(i, f.getRegion(rgn)) { + if (!::finite(f[i])) { + throw BoutException("%s is not finite at %s", name.c_str(), toString(i).c_str()); + } + } +} + +/// Check if all values of a field \p var are positive. Loops over all points including +/// the boundaries by default (can be changed using the \p rgn argument) +/// If any element is not finite, throws an exception that includes the position of the +/// first found. +template +inline void checkPositive(const T& f, const std::string& name="field", const std::string& rgn="RGN_ALL") { + AUTO_TRACE(); + + if (!f.isAllocated()) { + throw BoutException("%s is not allocated", name.c_str()); + } + + BOUT_FOR_SERIAL(i, f.getRegion(rgn)) { + if (f[i] <= 0.) { + throw BoutException("%s is not positive at %s", name.c_str(), toString(i).c_str()); + } + } +} + #endif /* __FIELD_H__ */ From efae9d5a1cb0d87d2318cfe99a51b455e017846f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 15 May 2019 12:35:12 +0100 Subject: [PATCH 1430/1783] Use checkFinite and checkPositive in coordinates.cxx --- src/mesh/coordinates.cxx | 108 ++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 58 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index a07f286de5..895e193ac1 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -275,18 +275,9 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) g23 = interpolateAndExtrapolate(g23, location, extrapolate_x, extrapolate_y); // Check input metrics - if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) - || (!finite(g33, RGN_NOBNDRY))) { - throw BoutException("\tERROR: Diagonal metrics are not finite!\n"); - } - if ((min(g11, RGN_NOBNDRY) <= 0.0) || (min(g22, RGN_NOBNDRY) <= 0.0) - || (min(g33, RGN_NOBNDRY) <= 0.0)) { - throw BoutException("\tERROR: Diagonal metrics are negative!\n"); - } - if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) - || (!finite(g23, RGN_NOBNDRY))) { - throw BoutException("\tERROR: Off-diagonal metrics are not finite!\n"); - } + checkFinite(g11, "g11", "RGN_NOCORNERS"); + checkFinite(g22, "g22", "RGN_NOCORNERS"); + checkFinite(g33, "g33", "RGN_NOCORNERS"); /// Find covariant metric components auto covariant_component_names = {"g_11", "g_22", "g_33", "g_12", "g_13", "g_23"}; @@ -359,9 +350,8 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) } else { output_warn.write("\tMaximum difference in Bxy is %e\n", max(abs(Bxy - Bcalc))); // Check Bxy - if (!finite(Bxy)) { - throw BoutException("\tERROR: Bxy not finite everywhere!\n"); - } + checkFinite(Bxy, "Bxy", "RGN_NOCORNERS"); + checkPositive(Bxy, "Bxy", "RGN_NOCORNERS"); } // More robust to extrapolate derived quantities directly, rather than // deriving from extrapolated covariant metric components @@ -573,17 +563,18 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, } // Check input metrics - if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) - || (!finite(g33, RGN_NOBNDRY))) { - throw BoutException("\tERROR: Staggered diagonal metrics are not finite!\n"); - } - if ((min(g11) <= 0.0) || (min(g22) <= 0.0) || (min(g33) <= 0.0)) { - throw BoutException("\tERROR: Staggered diagonal metrics are negative!\n"); - } - if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) - || (!finite(g23, RGN_NOBNDRY))) { - throw BoutException("\tERROR: Staggered off-diagonal metrics are not finite!\n"); - } + // Diagonal metric components should be finite + checkFinite(g11, "g11", "RGN_NOCORNERS"); + checkFinite(g22, "g22", "RGN_NOCORNERS"); + checkFinite(g33, "g33", "RGN_NOCORNERS"); + // Diagonal metric components should be positive + checkPositive(g11, "g11", "RGN_NOCORNERS"); + checkPositive(g22, "g22", "RGN_NOCORNERS"); + checkPositive(g33, "g33", "RGN_NOCORNERS"); + // Off-diagonal metric components should be finite + checkFinite(g12, "g12", "RGN_NOCORNERS"); + checkFinite(g13, "g13", "RGN_NOCORNERS"); + checkFinite(g23, "g23", "RGN_NOCORNERS"); /// Calculate Jacobian and Bxy if (jacobian()) @@ -642,29 +633,31 @@ int Coordinates::geometry(bool recalculate_staggered, throw BoutException("dz magnitude less than 1e-8"); // Check input metrics - if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) - || (!finite(g33, RGN_NOBNDRY))) { - throw BoutException("\tERROR: Diagonal metrics are not finite!\n"); - } - if ((min(g11) <= 0.0) || (min(g22) <= 0.0) || (min(g33) <= 0.0)) { - throw BoutException("\tERROR: Diagonal metrics are negative!\n"); - } - if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) - || (!finite(g23, RGN_NOBNDRY))) { - throw BoutException("\tERROR: Off-diagonal metrics are not finite!\n"); - } - - if ((!finite(g_11, RGN_NOBNDRY)) || (!finite(g_22, RGN_NOBNDRY)) - || (!finite(g_33, RGN_NOBNDRY))) { - throw BoutException("\tERROR: Diagonal g_ij metrics are not finite!\n"); - } - if ((min(g_11) <= 0.0) || (min(g_22) <= 0.0) || (min(g_33) <= 0.0)) { - throw BoutException("\tERROR: Diagonal g_ij metrics are negative!\n"); - } - if ((!finite(g_12, RGN_NOBNDRY)) || (!finite(g_13, RGN_NOBNDRY)) - || (!finite(g_23, RGN_NOBNDRY))) { - throw BoutException("\tERROR: Off-diagonal g_ij metrics are not finite!\n"); - } + // Diagonal metric components should be finite + checkFinite(g11, "g11", "RGN_NOCORNERS"); + checkFinite(g22, "g22", "RGN_NOCORNERS"); + checkFinite(g33, "g33", "RGN_NOCORNERS"); + // Diagonal metric components should be positive + checkPositive(g11, "g11", "RGN_NOCORNERS"); + checkPositive(g22, "g22", "RGN_NOCORNERS"); + checkPositive(g33, "g33", "RGN_NOCORNERS"); + // Off-diagonal metric components should be finite + checkFinite(g12, "g12", "RGN_NOCORNERS"); + checkFinite(g13, "g13", "RGN_NOCORNERS"); + checkFinite(g23, "g23", "RGN_NOCORNERS"); + + // Diagonal metric components should be finite + checkFinite(g_11, "g_11", "RGN_NOCORNERS"); + checkFinite(g_22, "g_22", "RGN_NOCORNERS"); + checkFinite(g_33, "g_33", "RGN_NOCORNERS"); + // Diagonal metric components should be positive + checkPositive(g_11, "g_11", "RGN_NOCORNERS"); + checkPositive(g_22, "g_22", "RGN_NOCORNERS"); + checkPositive(g_33, "g_33", "RGN_NOCORNERS"); + // Off-diagonal metric components should be finite + checkFinite(g_12, "g_12", "RGN_NOCORNERS"); + checkFinite(g_13, "g_13", "RGN_NOCORNERS"); + checkFinite(g_23, "g_23", "RGN_NOCORNERS"); // Calculate Christoffel symbol terms (18 independent values) // Note: This calculation is completely general: metric @@ -1011,24 +1004,23 @@ int Coordinates::jacobian() { - g33 * g12 * g12; // Check that g is positive - if (min(g) < 0.0) { - throw BoutException("The determinant of g^ij is somewhere less than 0.0"); - } + checkPositive(g, "The determinant of g^ij", "RGN_NOCORNERS"); + J = 1. / sqrt(g); // Check jacobian - if (!finite(J, RGN_NOBNDRY)) { - throw BoutException("\tERROR: Jacobian not finite everywhere!\n"); - } + checkFinite(J, "The Jacobian", "RGN_NOCORNERS"); if (min(abs(J)) < 1.0e-10) { throw BoutException("\tERROR: Jacobian becomes very small\n"); } - if (min(g_22) < 0.0) { - throw BoutException("g_22 is somewhere less than 0.0"); - } + checkPositive(g_22, "g_22", "RGN_NOCORNERS"); + Bxy = sqrt(g_22) / J; + checkFinite(Bxy, "Bxy", "RGN_NOCORNERS"); + checkPositive(Bxy, "Bxy", "RGN_NOCORNERS"); + return 0; } From 5eca93471af96b46ba926ecf905fea5c4cce5447 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 15 May 2019 11:36:14 +0100 Subject: [PATCH 1431/1783] Extrapolate Jacobian before running checks Checks for the Jacobian being finite and not too small were being done before extrapolating into boundary guard cells. Then the checks could fail because of boundary-cell values that would be overwritten. This commit moves 'interpolateAndExtrapolate' inside the 'jacobian' method, so that the extrapolation (if necessary) can be done before the checks. Also move interpolateAndExtrapolate done for J and Bxy read from grid files to before checks done comparing input to calculated J and Bxy. --- src/mesh/coordinates.cxx | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 895e193ac1..5bbc579fd9 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -334,6 +334,8 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) "\tWARNING: Jacobian 'J' not found. Calculating from metric tensor\n"); J = Jcalc; } else { + J = interpolateAndExtrapolate(J, location, extrapolate_x, extrapolate_y); + // Compare calculated and loaded values output_warn.write("\tMaximum difference in J is %e\n", max(abs(J - Jcalc))); @@ -348,15 +350,13 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) "metric tensor\n"); Bxy = Bcalc; } else { + Bxy = interpolateAndExtrapolate(Bxy, location, extrapolate_x, extrapolate_y); + output_warn.write("\tMaximum difference in Bxy is %e\n", max(abs(Bxy - Bcalc))); // Check Bxy checkFinite(Bxy, "Bxy", "RGN_NOCORNERS"); checkPositive(Bxy, "Bxy", "RGN_NOCORNERS"); } - // More robust to extrapolate derived quantities directly, rather than - // deriving from extrapolated covariant metric components - J = interpolateAndExtrapolate(J, location, extrapolate_x, extrapolate_y); - Bxy = interpolateAndExtrapolate(Bxy, location, extrapolate_x, extrapolate_y); ////////////////////////////////////////////////////// /// Calculate Christoffel symbols. Needs communication @@ -579,10 +579,6 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, /// Calculate Jacobian and Bxy if (jacobian()) throw BoutException("Error in jacobian call while constructing staggered Coordinates"); - // More robust to extrapolate derived quantities directly, rather than - // deriving from extrapolated covariant metric components - J = interpolateAndExtrapolate(J, location, extrapolate_x, extrapolate_y); - Bxy = interpolateAndExtrapolate(Bxy, location, extrapolate_x, extrapolate_y); ////////////////////////////////////////////////////// /// Calculate Christoffel symbols. Needs communication @@ -1000,6 +996,9 @@ int Coordinates::jacobian() { TRACE("Coordinates::jacobian"); // calculate Jacobian using g^-1 = det[g^ij], J = sqrt(g) + const bool extrapolate_x = not localmesh->sourceHasXBoundaryGuards(); + const bool extrapolate_y = not localmesh->sourceHasYBoundaryGuards(); + Field2D g = g11 * g22 * g33 + 2.0 * g12 * g13 * g23 - g11 * g23 * g23 - g22 * g13 * g13 - g33 * g12 * g12; @@ -1007,9 +1006,13 @@ int Coordinates::jacobian() { checkPositive(g, "The determinant of g^ij", "RGN_NOCORNERS"); J = 1. / sqrt(g); + // More robust to extrapolate derived quantities directly, rather than + // deriving from extrapolated covariant metric components + J = interpolateAndExtrapolate(J, location, extrapolate_x, extrapolate_y); // Check jacobian checkFinite(J, "The Jacobian", "RGN_NOCORNERS"); + checkPositive(J, "The Jacobian", "RGN_NOCORNERS"); if (min(abs(J)) < 1.0e-10) { throw BoutException("\tERROR: Jacobian becomes very small\n"); } @@ -1017,6 +1020,7 @@ int Coordinates::jacobian() { checkPositive(g_22, "g_22", "RGN_NOCORNERS"); Bxy = sqrt(g_22) / J; + Bxy = interpolateAndExtrapolate(Bxy, location, extrapolate_x, extrapolate_y); checkFinite(Bxy, "Bxy", "RGN_NOCORNERS"); checkPositive(Bxy, "Bxy", "RGN_NOCORNERS"); From 4e26ff4c28bf728d1d049b35d271c04065709ad0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 16 May 2019 10:15:05 +0100 Subject: [PATCH 1432/1783] Interpolate J and Bxy when getting metrics by interpolation Similar to the calculation of the covariant metric components, it is more robust to interpolate J than to calculate it from the interpolated metric components. For consistency also interpolate Bxy. --- src/mesh/coordinates.cxx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 5bbc579fd9..01d70adb70 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -506,6 +506,11 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, g_13 = interpolateAndExtrapolate(g_13, location, extrapolate_x, extrapolate_y); g_23 = interpolateAndExtrapolate(g_23, location, extrapolate_x, extrapolate_y); + /// Calculate Jacobian and Bxy + if (jacobian()) { + throw BoutException("Error in jacobian call while constructing staggered Coordinates"); + } + checkStaggeredGet(mesh, "ShiftTorsion", suffix); if (mesh->get(ShiftTorsion, "ShiftTorsion"+suffix)) { output_warn.write("\tWARNING: No Torsion specified for zShift. Derivatives may not be correct\n"); @@ -555,6 +560,9 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, g_13 = interpolateAndExtrapolate(coords_in->g_13, location); g_23 = interpolateAndExtrapolate(coords_in->g_23, location); + J = interpolateAndExtrapolate(coords_in->J, location); + Bxy = interpolateAndExtrapolate(coords_in->J, location); + ShiftTorsion = interpolateAndExtrapolate(coords_in->ShiftTorsion, location); if (mesh->IncIntShear) { @@ -576,10 +584,6 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, checkFinite(g13, "g13", "RGN_NOCORNERS"); checkFinite(g23, "g23", "RGN_NOCORNERS"); - /// Calculate Jacobian and Bxy - if (jacobian()) - throw BoutException("Error in jacobian call while constructing staggered Coordinates"); - ////////////////////////////////////////////////////// /// Calculate Christoffel symbols. Needs communication if (geometry(false, force_interpolate_from_centre)) { From 41c23b0ee66f08f0fe5e22406f4d8d8ff223c35a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 16 May 2019 12:36:44 +0100 Subject: [PATCH 1433/1783] FakeGridDataSource for unit tests Prevents segfaults for methods of Coordinates that try to access localmesh->source->hasXBoundaryGuards() or localmesh->source->hasYBoundaryGuards(). --- tests/unit/test_extras.hxx | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index f967c4630f..21a5398bb7 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -326,6 +326,50 @@ private: std::vector boundaries; }; +/// FakeGridDataSource provides a non-null GridDataSource* source to use with FakeMesh, to +/// allow testing of methods that use 'source' - in particular allowing +/// source->hasXBoundaryGuards and source->hasXBoundaryGuards to be called. +class FakeGridDataSource : public GridDataSource { + bool hasVar(const std::string& UNUSED(name)) { return false; } + + bool get(Mesh* UNUSED(m), std::string& UNUSED(sval), const std::string& UNUSED(name)) { + return false; + } + bool get(Mesh* UNUSED(m), int& UNUSED(ival), const std::string& UNUSED(name)) { + return false; + } + bool get(Mesh* UNUSED(m), BoutReal& UNUSED(rval), const std::string& UNUSED(name)) { + return false; + } + bool get(Mesh* UNUSED(m), Field2D& UNUSED(var), const std::string& UNUSED(name), + BoutReal UNUSED(def) = 0.0) { + return false; + } + bool get(Mesh* UNUSED(m), Field3D& UNUSED(var), const std::string& UNUSED(name), + BoutReal UNUSED(def) = 0.0) { + return false; + } + bool get(Mesh* UNUSED(m), FieldPerp& UNUSED(var), const std::string& UNUSED(name), + BoutReal UNUSED(def) = 0.0) { + return false; + } + + bool get(Mesh* UNUSED(m), std::vector& UNUSED(var), + const std::string& UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, + Direction UNUSED(dir) = GridDataSource::X) { + return false; + } + bool get(Mesh* UNUSED(m), std::vector& UNUSED(var), + const std::string& UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, + Direction UNUSED(dir) = GridDataSource::X) { + return false; + } + + bool hasXBoundaryGuards(Mesh* UNUSED(m)) { return true; } + + bool hasYBoundaryGuards() { return true; } +}; + /// Test fixture to make sure the global mesh is our fake /// one. Also initialize the global mesh_staggered for use in tests with /// staggering. Multiple tests have exactly the same fixture, so use a type @@ -348,6 +392,8 @@ public: Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, false); static_cast(bout::globals::mesh)->setCoordinates(test_coords); + static_cast(bout::globals::mesh)->setGridDataSource( + new FakeGridDataSource()); // May need a ParallelTransform to create fields, because create3D calls // fromFieldAligned test_coords->setParallelTransform( From 7446fa230f7b337884e4d7faf8d634c0b2bf5e31 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 16 May 2019 16:33:47 +0100 Subject: [PATCH 1434/1783] Simplify location-setting in D2DYDZ --- src/sys/derivs.cxx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 07857888fa..4a90a37714 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -341,12 +341,11 @@ const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc, const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, const std::string& method, REGION region) { - if (outloc == CELL_ZLOW || f.getLocation() == CELL_ZLOW) { - // Staggering in z, so take y-derivative at f's location. - return DDZ(DDY(f, CELL_DEFAULT, method, region), outloc, method, region); - } else { - return DDZ(DDY(f, outloc, method, region), outloc, method, region); - } + // If staggering in z, take y-derivative at f's location. + const auto y_location = + (outloc == CELL_ZLOW or f.getLocation() == CELL_ZLOW) ? CELL_DEFAULT : outloc; + + return DDZ(DDY(f, y_location, method, region), outloc, method, region); } /******************************************************************************* From e878d968c95602fc09d2c4e39b9f53cdf33b5b76 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 16 May 2019 16:39:34 +0100 Subject: [PATCH 1435/1783] Take z-derivative before x-derivative in D2DXDZ Following the pattern recently adopted in D2DYDZ, take the x-derivative first, and then the z-derivative. z is periodic so DDZ does not require guard cells and we avoid needing communication or boundary conditions for the intermediate df/dx. --- src/sys/derivs.cxx | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 4a90a37714..70201c3bd0 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -309,26 +309,11 @@ const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc, /// X-Z mixed derivative const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - // Take derivative in Z, including in X boundaries. Then take derivative in X - // Maybe should average results of DDX(DDZ) and DDZ(DDX)? - ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); - // region specifies what the combined derivative should return - // Therefore we need to add the X boundary to the inner derivative - // RGN_NOY and RGN_NOZ include the X boundary, therefore we need to - // throw - or add communication code. - REGION region_inner; - switch (region){ - case RGN_NOBNDRY: - region_inner = RGN_NOY; - break; - case RGN_NOX: - region_inner = RGN_ALL; - break; - default: - throw BoutException("Unhandled region case in D2DXDZ"); - } + // If staggering in z, take x-derivative at f's location. + const auto x_location = + (outloc == CELL_ZLOW or f.getLocation() == CELL_ZLOW) ? CELL_DEFAULT : outloc; - return DDX(DDZ(f, outloc,method, region_inner),outloc,method,region);; + return DDZ(DDX(f, x_location, method, region), outloc, method, region); } const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc, From 5d31d5bfa40775a96010b533ae6899f49873fd92 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 16 May 2019 17:39:32 +0100 Subject: [PATCH 1436/1783] In D2DXDY take y-derivative first, apply boundary condition before DDX In the mixed derivative, apply DDY before DDX (see PR #1661, mixed derivatives section in manual). Apply a boundary condition to dfdy before applying DDX. By default 'free_o3', can be changed with a new argument to D2DXDY. --- include/derivs.hxx | 20 ++++++++++++++------ src/sys/derivs.cxx | 40 ++++++++++++++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/include/derivs.hxx b/include/derivs.hxx index 93cdbc6a61..803ee7fed6 100644 --- a/include/derivs.hxx +++ b/include/derivs.hxx @@ -694,11 +694,15 @@ inline const Field2D FDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY +/// @param[in] dfdy_boundary_condition Boundary condition to use to set the guard cells of +/// df/dy, before calculating the x-derivative. const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY, + const std::string& dfdy_boundary_condition = "free_o3"); inline const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DXDY(f, outloc, toString(method), region); + REGION region = RGN_NOBNDRY, + const std::string& dfdy_boundary_condition = "free_o3") { + return D2DXDY(f, outloc, toString(method), region, dfdy_boundary_condition); }; /// Calculate mixed partial derivative in x and y @@ -713,11 +717,15 @@ inline const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD metho /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY +/// @param[in] dfdy_boundary_condition Boundary condition to use to set the guard cells of +/// df/dy, before calculating the x-derivative. const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); + const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY, + const std::string& dfdy_boundary_condition = "free_o3"); inline const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DXDY(f, outloc, toString(method), region); + REGION region = RGN_NOBNDRY, + const std::string& dfdy_boundary_condition = "free_o3") { + return D2DXDY(f, outloc, toString(method), region, dfdy_boundary_condition); }; /// Calculate mixed partial derivative in x and z diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 70201c3bd0..a5719a87e6 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -276,26 +276,50 @@ const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, const std::string &method /*! * Mixed derivative in X and Y * - * This first takes derivatives in X, then in Y. + * This first takes derivatives in Y, then in X. * - * ** Applies Neumann boundary in Y, communicates + * ** Communicates and applies boundary in X. */ -const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { - Field2D dfdy = DDY(f, outloc, method, RGN_NOY); +const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, const std::string& method, + REGION region, const std::string& dfdy_boundary_condition) { + + // If staggering in x, take y-derivative at f's location. + const auto y_location = + (outloc == CELL_XLOW or f.getLocation() == CELL_XLOW) ? CELL_DEFAULT : outloc; + + Field2D dfdy = DDY(f, y_location, method, region); + + // Set x-guard cells and x-boundary cells before calculating DDX f.getMesh()->communicate(dfdy); + dfdy.applyBoundary("core", dfdy_boundary_condition); + dfdy.applyBoundary("pf", dfdy_boundary_condition); + dfdy.applyBoundary("sol", dfdy_boundary_condition); + return DDX(dfdy, outloc, method, region); } /*! * Mixed derivative in X and Y * - * This first takes derivatives in X, then in Y. + * This first takes derivatives in Y, then in X. * - * ** Applies Neumann boundary in Y, communicates + * ** Communicates and applies boundary in X. */ -const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - Field3D dfdy = DDY(f, outloc, method, RGN_NOY); +const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, const std::string& method, + REGION region, const std::string& dfdy_boundary_condition) { + + // If staggering in x, take y-derivative at f's location. + const auto y_location = + (outloc == CELL_XLOW or f.getLocation() == CELL_XLOW) ? CELL_DEFAULT : outloc; + + Field3D dfdy = DDY(f, y_location, method, region); + + // Set x-guard cells and x-boundary cells before calculating DDX f.getMesh()->communicate(dfdy); + dfdy.applyBoundary("core", dfdy_boundary_condition); + dfdy.applyBoundary("pf", dfdy_boundary_condition); + dfdy.applyBoundary("sol", dfdy_boundary_condition); + return DDX(dfdy, outloc, method, region); } From 1e14412814d20063d219583a75f18ea981faedcf Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 16 May 2019 17:46:20 +0100 Subject: [PATCH 1437/1783] Manual section on mixed second derivatives Records discussion from PR #1661. --- .../user_docs/differential_operators.rst | 82 ++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/manual/sphinx/user_docs/differential_operators.rst b/manual/sphinx/user_docs/differential_operators.rst index 1579a2753c..bab4c35262 100644 --- a/manual/sphinx/user_docs/differential_operators.rst +++ b/manual/sphinx/user_docs/differential_operators.rst @@ -240,6 +240,84 @@ store using key `"C2"` for all three directions and both fields with no staggering. +.. _sec-diffmethod-mixedsecond: + +Mixed second-derivative operators +--------------------------------- + +Coordinate derivatives commute, as long as the coordinates are globally well-defined, i.e. + +.. math:: + + \frac{\partial}{\partial x} \left(\frac{\partial}{\partial y} f \right) + = \frac{\partial}{\partial y} \left(\frac{\partial}{\partial x} f \right) \\ + \frac{\partial}{\partial y} \left(\frac{\partial}{\partial z} f \right) + = \frac{\partial}{\partial z} \left(\frac{\partial}{\partial y} f \right) \\ + \frac{\partial}{\partial z} \left(\frac{\partial}{\partial x} f \right) + = \frac{\partial}{\partial x} \left(\frac{\partial}{\partial z} f \right) + +When using ``paralleltransform = shifted`` or ``paralleltransform = fci`` (see +:ref:`sec-parallel-transforms`) we do not have globally well-defined coordinates. In those +cases the coordinate systems are field-aligned, but the grid points are at constant +toroidal angle. The field-aligned coordinates are defined locally, on planes of constant +:math:`y`. There are different coordinate systems for each plane. However, within each +local coordinate system the derivatives do commute. :math:`y`-derivatives are taken in the +local field-aligned coordinate system, so mixed derivatives are calculated as + +:: + + D2DXDY(f) = DDX(DDY(f)) + D2DYDZ(f) = DDZ(DDY(f)) + +This order is simpler -- the alternative is possible. Using second-order central +difference operators for the y-derivatives we could calculate (not worring about +communications or boundary conditions here) + +:: + + Field3D D2DXDY(Field3D f) { + auto result{emptyFrom(f)}; + auto& coords = \*f.getCoordinates() + + auto dfdx_yup = DDX(f.yup()); + auto dfdx_ydown = DDX(f.ydown()); + + BOUT_FOR(i, f.getRegion()) { + result[i] = (dfdx_yup[i.yp()] - dfdx_ydown[i.ym()]) / (2. * coords.dy[i]) + } + + return result; + } + +This would give equivalent results to the previous form [#]_ as ``yup`` and ``ydown`` give +the values of ``f`` one grid point along the magnetic field *in the local field-aligned +coordinate system*. + +The :math:`x\mathrm{-}z` derivative is unaffected as it is taken entirely on a plane of +constant :math:`y` anyway. It is evaluated as + +:: + + D2DXDZ(f) = DDZ(DDX(f)) + +As the ``z``-direction is periodic and the ``z``-grid is not split across processors, +``DDZ`` does not require any guard cells. By taking ``DDZ`` second, we do not have to +communicate or set boundary conditions on the result of ``DDX`` or ``DDY`` before taking +``DDZ``. + +The derivatives in ``D2DXDY(f)`` are applied in two steps. First ``dfdy = DDY(f)`` is +calculated; ``dfdy`` is communicated and has a boundary condition applied so that all the +x-guard cells are filled. The boundary condition is ``free_o3`` by default (3rd order +extrapolation into the boundary cells), but can be specified with the fifth argument to +``D2DXDY`` (see :ref:`sec-bndryopts` for possible options). Second ``DDX(dfdy)`` is +calculated, and returned from the function. + +.. [#] Equivalent but not exactly the same numerically. Expanding out the derivatives in + second-order central-difference form shows that the two differ in the grid points + at which they evaluate ``dx`` and ``dy``. As long as the grid spacings are smooth + this should not affect the order of accuracy of the scheme (?). + + .. _sec-diffmethod-nonuniform: Non-uniform meshes @@ -693,7 +771,7 @@ well defined Fourier transform. This means that In our case, we are dealing with periodic boundary conditions. Strictly speaking, the Fourier transform does not exist in such cases, but it is possible to define a Fourier transform in the limit which in the end -lead to the Fourier series [1]_ By discretising the spatial domain, it +lead to the Fourier series [#]_ By discretising the spatial domain, it is no longer possible to represent the infinite amount of Fourier modes, but only :math:`N+1` number of modes, where :math:`N` is the number of points (this includes the modes with negative frequencies, and the @@ -724,5 +802,5 @@ The discrete version of equation (:eq:`f_derivative`) thus gives \partial_z^n F(x,y)_k = (i k)^n F(x,y)_k -.. [1] For more detail see Bracewell, R. N. - The Fourier Transform +.. [#] For more detail see Bracewell, R. N. - The Fourier Transform and Its Applications 3rd Edition chapter 10 From 784a2b1c6beffde5ff7132a6c677c6c7442b0895 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 15 May 2019 16:07:22 +0100 Subject: [PATCH 1438/1783] Default region arguments for Field2D::to/fromFieldAligned These were previously missing, but to be compatible with the Field3D versions the region arguments should be optional. --- include/field2d.hxx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/field2d.hxx b/include/field2d.hxx index f1bcdd88cc..ceb2a97a84 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -326,8 +326,12 @@ Field2D operator-(const Field2D &f); // Non-member functions -inline Field2D toFieldAligned(const Field2D& f, const REGION UNUSED(region)) { return f; } -inline Field2D fromFieldAligned(const Field2D& f, const REGION UNUSED(region)) { return f; } +inline Field2D toFieldAligned(const Field2D& f, const REGION UNUSED(region) = RGN_ALL) { + return f; +} +inline Field2D fromFieldAligned(const Field2D& f, const REGION UNUSED(region) = RGN_ALL) { + return f; +} /// Square root of \p f over region \p rgn /// From 5ad9c0a989924ef62e06597ce2aa901eb4eaff07 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 16 May 2019 21:27:38 +0100 Subject: [PATCH 1439/1783] Make Field functions templates, deprecate use of REGION enum Move most Field3D, Field2D and FieldPerp functions to template functions in field.hxx. In the process also change REGION enum arguments to std::strings, and provide a deprecated overload for REGION. Also update some other functions to use std::string instead of REGION. --- include/bout/mesh.hxx | 8 +- include/bout/paralleltransform.hxx | 64 ++- include/field.hxx | 394 +++++++++++++++++- include/field2d.hxx | 151 +------ include/field3d.hxx | 214 +++------- include/fieldperp.hxx | 128 +----- include/interpolation.hxx | 18 +- include/vector2d.hxx | 7 +- include/vector3d.hxx | 7 +- src/field/field2d.cxx | 180 +------- src/field/field3d.cxx | 216 +--------- src/field/field_factory.cxx | 4 +- src/field/fieldperp.cxx | 179 +------- src/field/vector2d.cxx | 2 +- src/field/vector3d.cxx | 2 +- src/fileio/datafile.cxx | 4 +- .../laplace/impls/naulin/naulin_laplace.cxx | 18 +- src/invert/parderiv/impls/cyclic/cyclic.cxx | 4 +- src/mesh/coordinates.cxx | 40 +- src/mesh/difops.cxx | 12 +- src/mesh/fv_ops.cxx | 16 +- src/mesh/parallel/fci.hxx | 8 +- src/mesh/parallel/shiftedmetric.cxx | 14 +- tests/unit/mesh/test_interpolation.cxx | 12 +- tests/unit/mesh/test_paralleltransform.cxx | 8 +- 25 files changed, 643 insertions(+), 1067 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 8d6b906036..f1ea86e7e1 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -741,22 +741,22 @@ class Mesh { [[gnu::deprecated("Please use free function toFieldAligned instead")]] const Field3D toFieldAligned(const Field3D &f, const REGION region = RGN_ALL) { - return ::toFieldAligned(f, region); + return ::toFieldAligned(f, toString(region)); } [[gnu::deprecated("Please use free function fromFieldAligned instead")]] const Field3D fromFieldAligned(const Field3D &f, const REGION region = RGN_ALL) { - return ::fromFieldAligned(f, region); + return ::fromFieldAligned(f, toString(region)); } [[gnu::deprecated("Please use free function toFieldAligned instead")]] const Field2D toFieldAligned(const Field2D &f, const REGION region = RGN_ALL) { - return ::toFieldAligned(f, region); + return ::toFieldAligned(f, toString(region)); } [[gnu::deprecated("Please use free function fromFieldAligned instead")]] const Field2D fromFieldAligned(const Field2D &f, const REGION region = RGN_ALL) { - return ::fromFieldAligned(f, region); + return ::fromFieldAligned(f, toString(region)); } [[gnu::deprecated("Please use " diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 342f353e87..ba425642dc 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -46,13 +46,33 @@ public: /// Convert a field into field-aligned coordinates /// so that the y index is along the magnetic field - virtual const Field3D toFieldAligned(const Field3D &f, const REGION region = RGN_ALL) = 0; - virtual const FieldPerp toFieldAligned(const FieldPerp &f, const REGION region = RGN_ALL) = 0; + virtual const Field3D toFieldAligned(const Field3D &f, const std::string& region = "RGN_ALL") = 0; + [[gnu::deprecated("Please use toFieldAligned(const Field3D& f, " + "const std::string& region = \"RGN_ALL\") instead")]] + const Field3D toFieldAligned(const Field3D &f, REGION region) { + return toFieldAligned(f, toString(region)); + } + virtual const FieldPerp toFieldAligned(const FieldPerp &f, const std::string& region = "RGN_ALL") = 0; + [[gnu::deprecated("Please use toFieldAligned(const FieldPerp& f, " + "const std::string& region = \"RGN_ALL\") instead")]] + const FieldPerp toFieldAligned(const FieldPerp &f, REGION region) { + return toFieldAligned(f, toString(region)); + } /// Convert back from field-aligned coordinates /// into standard form - virtual const Field3D fromFieldAligned(const Field3D &f, const REGION region = RGN_ALL) = 0; - virtual const FieldPerp fromFieldAligned(const FieldPerp &f, const REGION region = RGN_ALL) = 0; + virtual const Field3D fromFieldAligned(const Field3D &f, const std::string& region = "RGN_ALL") = 0; + [[gnu::deprecated("Please use fromFieldAligned(const Field3D& f, " + "const std::string& region = \"RGN_ALL\") instead")]] + const Field3D fromFieldAligned(const Field3D &f, REGION region) { + return fromFieldAligned(f, toString(region)); + } + virtual const FieldPerp fromFieldAligned(const FieldPerp &f, const std::string& region = "RGN_ALL") = 0; + [[gnu::deprecated("Please use fromFieldAligned(const FieldPerp& f, " + "const std::string& region = \"RGN_ALL\") instead")]] + const FieldPerp fromFieldAligned(const FieldPerp &f, REGION region) { + return fromFieldAligned(f, toString(region)); + } virtual bool canToFromFieldAligned() = 0; @@ -86,11 +106,11 @@ public: * The field is already aligned in Y, so this * does nothing */ - const Field3D toFieldAligned(const Field3D& f, const REGION UNUSED(region)) override { + const Field3D toFieldAligned(const Field3D& f, const std::string& UNUSED(region) = "RGN_ALL") override { Field3D result = f; return result.setDirectionY(YDirectionType::Aligned); } - const FieldPerp toFieldAligned(const FieldPerp& f, const REGION UNUSED(region)) override { + const FieldPerp toFieldAligned(const FieldPerp& f, const std::string& UNUSED(region) = "RGN_ALL") override { FieldPerp result = f; return result.setDirectionY(YDirectionType::Aligned); } @@ -99,11 +119,11 @@ public: * The field is already aligned in Y, so this * does nothing */ - const Field3D fromFieldAligned(const Field3D& f, const REGION UNUSED(region)) override { + const Field3D fromFieldAligned(const Field3D& f, const std::string& UNUSED(region) = "RGN_ALL") override { Field3D result = f; return result.setDirectionY(YDirectionType::Standard); } - const FieldPerp fromFieldAligned(const FieldPerp& f, const REGION UNUSED(region)) override { + const FieldPerp fromFieldAligned(const FieldPerp& f, const std::string& UNUSED(region) = "RGN_ALL") override { FieldPerp result = f; return result.setDirectionY(YDirectionType::Standard); } @@ -141,18 +161,18 @@ public: * in X-Z, and the metric tensor will need to be changed * if X derivatives are used. */ - const Field3D toFieldAligned(const Field3D& f, const REGION region = RGN_ALL) override; + const Field3D toFieldAligned(const Field3D& f, const std::string& region = "RGN_ALL") override; const FieldPerp toFieldAligned(const FieldPerp& f, - const REGION region = RGN_ALL) override; + const std::string& region = "RGN_ALL") override; /*! * Converts a field back to X-Z orthogonal coordinates * from field aligned coordinates. */ const Field3D fromFieldAligned(const Field3D& f, - const REGION region = RGN_ALL) override; + const std::string& region = "RGN_ALL") override; const FieldPerp fromFieldAligned(const FieldPerp& f, - const REGION region = RGN_ALL) override; + const std::string& region = "RGN_ALL") override; bool canToFromFieldAligned() override { return true; } @@ -196,7 +216,13 @@ private: * Since 2D fields are constant in Z, this has no effect */ const Field2D shiftZ(const Field2D& f, const Field2D& UNUSED(zangle), - const REGION UNUSED(region) = RGN_NOX) const { + const std::string UNUSED(region) = "RGN_NOX") const { + return f; + }; + [[gnu::deprecated("Please use shiftZ(const Field2D& f, const Field2D& zangle, " + "const std::string& region = \"RGN_NOX\") instead")]] + const Field2D shiftZ(const Field2D& f, const Field2D& UNUSED(zangle), + REGION UNUSED(region)) const { return f; }; @@ -208,7 +234,13 @@ private: * */ const Field3D shiftZ(const Field3D& f, const Field2D& zangle, - const REGION region = RGN_NOX) const; + const std::string& region = "RGN_NOX") const; + [[gnu::deprecated("Please use shiftZ(const Field3D& f, const Field2D& zangle, " + "const std::string& region = \"RGN_NOX\") instead")]] + const Field3D shiftZ(const Field3D& f, const Field2D& zangle, + REGION region) const { + return shiftZ(f, zangle, toString(region)); + }; /*! * Shift a 3D field or FieldPerp \p f by the given phase \p phs in Z @@ -222,10 +254,10 @@ private: */ const Field3D shiftZ(const Field3D& f, const Tensor& phs, const YDirectionType y_direction_out, - const REGION region = RGN_NOX) const; + const std::string& region = "RGN_NOX") const; const FieldPerp shiftZ(const FieldPerp& f, const Tensor& phs, const YDirectionType y_direction_out, - const REGION region = RGN_NOX) const; + const std::string& region = "RGN_NOX") const; /*! * Shift a given 1D array, assumed to be in Z, by the given \p zangle diff --git a/include/field.hxx b/include/field.hxx index 763d633284..fc69c7a6ac 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -29,14 +29,18 @@ class Field; #ifndef __FIELD_H__ #define __FIELD_H__ +#include #include #include +#include "bout/region.hxx" #include "bout_types.hxx" +#include "boutcomm.hxx" #include "boutexception.hxx" #include #include "msg_stack.hxx" #include "stencils.hxx" +#include "utils.hxx" #include #include "unused.hxx" @@ -239,7 +243,7 @@ inline bool areFieldsCompatible(const Field& field1, const Field& field2) { /// Return an empty shell field of some type derived from Field, with metadata /// copied and a data array that is allocated but not initialised. -template +template> inline T emptyFrom(const T& f) { static_assert(std::is_base_of::value, "emptyFrom only works on Fields"); return T(f.getMesh(), f.getLocation(), {f.getDirectionY(), f.getDirectionZ()}).allocate(); @@ -247,7 +251,7 @@ inline T emptyFrom(const T& f) { /// Return a field of some type derived from Field, with metadata copied from /// another field and a data array allocated and initialised to zero. -template +template> inline T zeroFrom(const T& f) { static_assert(std::is_base_of::value, "emptyFrom only works on Fields"); T result{emptyFrom(f)}; @@ -257,7 +261,7 @@ inline T zeroFrom(const T& f) { /// Return a field of some type derived from Field, with metadata copied from /// another field and a data array allocated and filled with the given value. -template +template> inline T filledFrom(const T& f, BoutReal fill_value) { static_assert(std::is_base_of::value, "emptyFrom only works on Fields"); T result{emptyFrom(f)}; @@ -266,7 +270,389 @@ inline T filledFrom(const T& f, BoutReal fill_value) { } /// Unary + operator. This doesn't do anything -template +template> T operator+(const T& f) {return f;} +//////////////// NON-MEMBER FUNCTIONS ////////////////// + +template> +inline T toFieldAligned(const T& f, const std::string& region = "RGN_ALL") { + return f.getCoordinates()->getParallelTransform().toFieldAligned(f, region); +} +template> +[[gnu::deprecated("Please use toFieldAligned(const T& f, " + "const std::string& region = \"RGN_ALL\") instead")]] +inline T toFieldAligned(const T& f, REGION region) { + return toFieldAligned(f, toString(region)); +} + +template> +inline T fromFieldAligned(const T& f, const std::string& region = "RGN_ALL") { + return f.getCoordinates()->getParallelTransform().fromFieldAligned(f, region); +} +template> +[[gnu::deprecated("Please use fromFieldAligned(const T& f, " + "const std::string& region = \"RGN_ALL\") instead")]] +inline T fromFieldAligned(const T& f, REGION region) { + return fromFieldAligned(f, toString(region)); +} + +template> +inline BoutReal min(const T& f, bool allpe = false, const std::string& rgn = "RGN_NOBNDRY") { + AUTO_TRACE(); + + checkData(f); + + const auto region = f.getRegion(rgn); + BoutReal result = f[*region.cbegin()]; + + BOUT_FOR_OMP(i, region, parallel for reduction(min:result)) { + if(f[i] < result) { + result = f[i]; + } + } + + if(allpe) { + // MPI reduce + BoutReal localresult = result; + MPI_Allreduce(&localresult, &result, 1, MPI_DOUBLE, MPI_MIN, BoutComm::get()); + } + + return result; +} +template> +[[gnu::deprecated("Please use Field3D min(const Field3D& f, bool allpe, " + "const std::string& region = \"RGN_NOBNDRY\") instead")]] +inline BoutReal min(const T& f, bool allpe, REGION rgn) { + return min(f, allpe, toString(rgn)); +} + +template> +inline BoutReal max(const T& f, bool allpe = false, const std::string& rgn = "RGN_NOBNDRY") { + AUTO_TRACE(); + + checkData(f); + + const auto region = f.getRegion(rgn); + BoutReal result = f[*region.cbegin()]; + + BOUT_FOR_OMP(i, region, parallel for reduction(max:result)) { + if(f[i] > result) { + result = f[i]; + } + } + + if(allpe) { + // MPI reduce + BoutReal localresult = result; + MPI_Allreduce(&localresult, &result, 1, MPI_DOUBLE, MPI_MAX, BoutComm::get()); + } + + return result; +} +template> +[[gnu::deprecated("Please use Field3D max(const Field3D& f, bool allpe, " + "const std::string& region = \"RGN_NOBNDRY\") instead")]] +inline BoutReal max(const T& f, bool allpe, REGION rgn) { + return max(f, allpe, toString(rgn)); +} + +template> +inline BoutReal mean(const T &f, bool allpe = false, + const std::string& rgn = "RGN_NOBNDRY") { + AUTO_TRACE(); + + checkData(f); + + // Intitialise the cummulative sum and counter + BoutReal result = 0.; + int count = 0; + + BOUT_FOR_OMP(i, f.getRegion(rgn), parallel for reduction(+:result,count)) { + result += f[i]; + count += 1; + } + + if(allpe) { + // MPI reduce + BoutReal localresult = result; + MPI_Allreduce(&localresult, &result, 1, MPI_DOUBLE, MPI_SUM, BoutComm::get()); + int localcount = count; + MPI_Allreduce(&localcount, &count, 1, MPI_INT, MPI_SUM, BoutComm::get()); + } + + return result / static_cast(count); +} +template> +[[gnu::deprecated("Please use Field3D mean(const Field3D& f, bool allpe, " + "const std::string& region = \"RGN_NOBNDRY\") instead")]] +inline BoutReal mean(const T& f, bool allpe, REGION rgn) { + return mean(f, allpe, toString(rgn)); +} + +/// Exponent: pow(lhs, lhs) is \p lhs raised to the power of \p rhs +/// +/// This loops over the entire domain, including guard/boundary cells by +/// default (can be changed using the \p rgn argument) +/// If CHECK >= 3 then the result will be checked for non-finite numbers +template> +T pow(const T& lhs, const T& rhs, const std::string& rgn = "RGN_ALL") { + AUTO_TRACE(); + + ASSERT1(areFieldsCompatible(lhs, rhs)); + + T result{emptyFrom(lhs)}; + + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } + + checkData(result); + return result; +} +template> +[[gnu::deprecated("Please use pow(const T& lhs, const T& rhs" + "const std::string& region = \"RGN_ALL\") instead")]] +inline T pow(const T& lhs, const T& rhs, REGION rgn) { + return pow(lhs, rhs, toString(rgn)); +} + +template> +T pow(const T &lhs, BoutReal rhs, const std::string& rgn = "RGN_ALL") { + AUTO_TRACE(); + + // Check if the inputs are allocated + checkData(lhs); + checkData(rhs); + + T result{emptyFrom(lhs)}; + + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs); } + + checkData(result); + return result; +} +template> +[[gnu::deprecated("Please use pow(const T& lhs, BoutReal rhs" + "const std::string& region = \"RGN_ALL\") instead")]] +inline T pow(const T& lhs, BoutReal rhs, REGION rgn) { + return pow(lhs, rhs, toString(rgn)); +} + +template> +T pow(BoutReal lhs, const T &rhs, const std::string& rgn = "RGN_ALL") { + AUTO_TRACE(); + + // Check if the inputs are allocated + checkData(lhs); + checkData(rhs); + + // Define and allocate the output result + T result{emptyFrom(rhs)}; + + BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs, rhs[i]); } + + checkData(result); + return result; +} +template> +[[gnu::deprecated("Please use pow(BoutReal lhs, const T& rhs" + "const std::string& region = \"RGN_ALL\") instead")]] +inline T pow(BoutReal lhs, const T& rhs, REGION rgn) { + return pow(lhs, rhs, toString(rgn)); +} + + +/*! + * This macro takes a function \p func, which is + * assumed to operate on a single BoutReal and return + * a single BoutReal, and wraps it up into a function + * of a Field called \p name. + * + * @param name The name of the function to define + * @param func The function to apply to each value + * + * If CHECK >= 1, checks if the Field is allocated + * + * Loops over the entire domain, applies function, + * and uses checkData() to, if CHECK >= 3, check + * result for non-finite numbers + * + */ +#ifdef FIELD_FUNC +#error This macro has already been defined +#else +#define FIELD_FUNC(name, func) \ + template> \ + inline T name(const T &f, const std::string& rgn = "RGN_ALL") { \ + AUTO_TRACE(); \ + /* Check if the input is allocated */ \ + checkData(f); \ + /* Define and allocate the output result */ \ + T result{emptyFrom(f)}; \ + BOUT_FOR(d, result.getRegion(rgn)) { result[d] = func(f[d]); } \ + checkData(result); \ + return result; \ + } \ + template> \ + [[gnu::deprecated("Please use func(const T& f, " \ + "const std::string& region = \"RGN_ALL\") instead")]] \ + inline T name(const T& f, REGION region) { \ + return name(f, toString(region)); \ + } +#endif + +/// Square root of \p f over region \p rgn +/// +/// This loops over the entire domain, including guard/boundary cells by +/// default (can be changed using the \p rgn argument). +/// If CHECK >= 3 then the result will be checked for non-finite numbers +FIELD_FUNC(sqrt, ::sqrt); + +/// Absolute value (modulus, |f|) of \p f over region \p rgn +/// +/// This loops over the entire domain, including guard/boundary cells by +/// default (can be changed using the \p rgn argument). +/// If CHECK >= 3 then the result will be checked for non-finite numbers +FIELD_FUNC(abs, ::fabs); + +/// Exponential: \f$\exp(f)\f$ is e to the power of \p f, over region +/// \p rgn +/// +/// This loops over the entire domain, including guard/boundary cells by +/// default (can be changed using the \p rgn argument). +/// If CHECK >= 3 then the result will be checked for non-finite numbers +FIELD_FUNC(exp, ::exp); + +/// Natural logarithm of \p f over region \p rgn, inverse of +/// exponential +/// +/// \f$\ln(\exp(f)) = f\f$ +/// +/// This loops over the entire domain, including guard/boundary cells by +/// default (can be changed using the rgn argument) +/// If CHECK >= 3 then the result will be checked for non-finite numbers +FIELD_FUNC(log, ::log); + +/// Sine trigonometric function. +/// +/// @param[in] f Angle in radians +/// @param[in] rgn The region to calculate the result over +/// +/// This loops over the entire domain, including guard/boundary cells by +/// default (can be changed using the \p rgn argument). +/// If CHECK >= 3 then the result will be checked for non-finite numbers +FIELD_FUNC(sin, ::sin); + +/// Cosine trigonometric function. +/// +/// @param[in] f Angle in radians +/// @param[in] rgn The region to calculate the result over +/// +/// This loops over the entire domain, including guard/boundary cells by +/// default (can be changed using the \p rgn argument). +/// If CHECK >= 3 then the result will be checked for non-finite numbers +FIELD_FUNC(cos, ::cos); + +/// Tangent trigonometric function. +/// +/// @param[in] f Angle in radians +/// @param[in] rgn The region to calculate the result over +/// +/// This loops over the entire domain, including guard/boundary cells by +/// default (can be changed using the \p rgn argument). +/// If CHECK >= 3 then the result will be checked for non-finite numbers +FIELD_FUNC(tan, ::tan); + +/// Hyperbolic sine trigonometric function. +/// +/// @param[in] f Angle in radians +/// @param[in] rgn The region to calculate the result over +/// +/// This loops over the entire domain, including guard/boundary cells by +/// default (can be changed using the \p rgn argument). +/// If CHECK >= 3 then the result will be checked for non-finite numbers +FIELD_FUNC(sinh, ::sinh); + +/// Hyperbolic cosine trigonometric function. +/// +/// @param[in] f Angle in radians +/// @param[in] rgn The region to calculate the result over +/// +/// This loops over the entire domain, including guard/boundary cells by +/// default (can be changed using the \p rgn argument). +/// If CHECK >= 3 then the result will be checked for non-finite numbers +FIELD_FUNC(cosh, ::cosh); + +/// Hyperbolic tangent trigonometric function. +/// +/// @param[in] f Angle in radians +/// @param[in] rgn The region to calculate the result over +/// +/// This loops over the entire domain, including guard/boundary cells by +/// default (can be changed using the \p rgn argument). +/// If CHECK >= 3 then the result will be checked for non-finite numbers +FIELD_FUNC(tanh, ::tanh); + +/// Check if all values of a field \p var are finite. +/// Loops over all points including the boundaries by +/// default (can be changed using the \p rgn argument +template> +inline bool finite(const T &f, const std::string& rgn = "RGN_ALL") { + AUTO_TRACE(); + + if (!f.isAllocated()) { + return false; + } + + BOUT_FOR_SERIAL(i, f.getRegion(rgn)) { + if (!finite(f[i])) { + return false; + } + } + + return true; +} +template> +[[gnu::deprecated("Please use bool finite(const Field3D& f, " + "const std::string& region = \"RGN_ALL\") instead")]] +inline bool finite(const T& f, REGION rgn) { + return finite(f, toString(rgn)); +} + +/// Makes a copy of a field \p f, ensuring that the underlying data is +/// not shared. +template> +T copy(const T &f) { + T result = f; + result.allocate(); + return result; +} + +/// Apply a floor value \p f to a field \p var. Any value lower than +/// the floor is set to the floor. +/// +/// @param[in] var Variable to apply floor to +/// @param[in] f The floor value +/// @param[in] rgn The region to calculate the result over +template> +inline T floor(const T& var, BoutReal f, const std::string& rgn = "RGN_ALL") { + checkData(var); + T result = copy(var); + + BOUT_FOR(d, var.getRegion(rgn)) { + if (result[d] < f) { + result[d] = f; + } + } + + return result; +} +template> +[[gnu::deprecated("Please use floor(const T& var, BoutReal f, " + "const std::string& region = \"RGN_ALL\") instead")]] +inline T floor(const T& var, BoutReal f, REGION rgn) { + return floor(var, f, toString(rgn)); +} + +#undef FIELD_FUNC + #endif /* __FIELD_H__ */ diff --git a/include/field2d.hxx b/include/field2d.hxx index ceb2a97a84..d2380f48f2 100644 --- a/include/field2d.hxx +++ b/include/field2d.hxx @@ -326,145 +326,40 @@ Field2D operator-(const Field2D &f); // Non-member functions -inline Field2D toFieldAligned(const Field2D& f, const REGION UNUSED(region) = RGN_ALL) { +inline Field2D toFieldAligned(const Field2D& f, const std::string& UNUSED(region) = "RGN_ALL") { return f; } -inline Field2D fromFieldAligned(const Field2D& f, const REGION UNUSED(region) = RGN_ALL) { - return f; +[[gnu::deprecated("Please use toFieldAligned(const Field2D& f, " + "const std::string& region = \"RGN_ALL\") instead")]] +inline Field2D toFieldAligned(const Field2D& f, REGION region) { + return toFieldAligned(f, toString(region)); } -/// Square root of \p f over region \p rgn -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -const Field2D sqrt(const Field2D &f, REGION rgn=RGN_ALL); - -/// Absolute value (modulus, |f|) of \p f over region \p rgn -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -const Field2D abs(const Field2D &f, REGION rgn=RGN_ALL); - -/// Calculates the minimum of a field, excluding the boundary/guard -/// cells by default (can be changed with \p rgn argument). -/// -/// By default this is only on the local processor, but setting \p -/// allpe true does a collective Allreduce over all processors. -/// -/// @param[in] f The field to loop over -/// @param[in] allpe Minimum over all processors? -/// @param[in] rgn The region to calculate the result over -BoutReal min(const Field2D &f, bool allpe=false, REGION rgn=RGN_NOBNDRY); - -/// Calculates the maximum of a field, excluding the boundary/guard -/// cells by default (can be changed with \p rgn argument). -/// -/// By default this is only on the local processor, but setting \p -/// allpe to true does a collective Allreduce over all processors. -/// -/// @param[in] f The field to loop over -/// @param[in] allpe Maximum over all processors? -/// @param[in] rgn The region to calculate the result over -BoutReal max(const Field2D &f, bool allpe=false, REGION rgn=RGN_NOBNDRY); - -/// Check if all values of a field \p var are finite. -/// Loops over all points including the boundaries by -/// default (can be changed using the \p rgn argument -bool finite(const Field2D &f, REGION rgn=RGN_ALL); - -/// Exponential -const Field2D exp(const Field2D &f, REGION rgn=RGN_ALL); - -/// Natural logarithm -const Field2D log(const Field2D &f, REGION rgn=RGN_ALL); - -/// Sine trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field2D sin(const Field2D &f, REGION rgn=RGN_ALL); - -/// Cosine trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field2D cos(const Field2D &f, REGION rgn=RGN_ALL); - -/// Tangent trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field2D tan(const Field2D &f, REGION rgn=RGN_ALL); - -/// Hyperbolic sine trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field2D sinh(const Field2D &f, REGION rgn=RGN_ALL); - -/// Hyperbolic cosine trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field2D cosh(const Field2D &f, REGION rgn=RGN_ALL); - -/// Hyperbolic tangent trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -const Field2D tanh(const Field2D &f, REGION rgn=RGN_ALL); - -/// Make an independent copy of field \p f -const Field2D copy(const Field2D &f); - -/// Apply a floor value \p f to a field \p var. Any value lower than -/// the floor is set to the floor. -/// -/// @param[in] var Variable to apply floor to -/// @param[in] f The floor value -/// @param[in] rgn The region to calculate the result over -const Field2D floor(const Field2D &var, BoutReal f, REGION rgn=RGN_ALL); - -/// Exponent: pow(lhs, lhs) is \p lhs raised to the power of \p rhs -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument) -Field2D pow(const Field2D &lhs, const Field2D &rhs, REGION rgn=RGN_ALL); -Field2D pow(const Field2D &lhs, BoutReal rhs, REGION rgn=RGN_ALL); -Field2D pow(BoutReal lhs, const Field2D &rhs, REGION rgn=RGN_ALL); +inline Field2D fromFieldAligned(const Field2D& f, const std::string& UNUSED(region) = "RGN_ALL") { + return f; +} +[[gnu::deprecated("Please use fromFieldAligned(const Field2D& f, " + "const std::string& region = \"RGN_ALL\") instead")]] +inline Field2D fromFieldAligned(const Field2D& f, REGION region) { + return fromFieldAligned(f, toString(region)); +} #if CHECK > 0 /// Throw an exception if \p f is not allocated or if any /// elements are non-finite (for CHECK > 2). /// Loops over all points including the boundaries by /// default (can be changed using the \p rgn argument -void checkData(const Field2D &f, REGION region = RGN_NOBNDRY); +void checkData(const Field2D &f, const std::string& region = "RGN_NOBNDRY"); +[[gnu::deprecated("Please use checkData(const Field2D& f, " + "const std::string& region = \"RGN_NOBNDRY\") instead")]] +inline void checkData(const Field2D &f, REGION region) { + return checkData(f, toString(region)); +} #else -inline void checkData(const Field2D &UNUSED(f), REGION UNUSED(region) = RGN_NOBNDRY) {} +inline void checkData(const Field2D &UNUSED(f), std::string UNUSED(region) = "RGN_NOBNDRY") {} +[[gnu::deprecated("Please use checkData(const Field2D& f, " + "const std::string& region = \"RGN_NOBNDRY\") instead")]] +inline void checkData(const Field2D &UNUSED(f), REGION UNUSED(region)) {} #endif /// Force guard cells of passed field \p var to NaN diff --git a/include/field3d.hxx b/include/field3d.hxx index 9b0b8fd993..11aa0c70ff 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -562,182 +562,57 @@ Field3D operator-(const Field3D &f); // Non-member functions -Field3D toFieldAligned(const Field3D& f, const REGION region = RGN_ALL); -Field3D fromFieldAligned(const Field3D& f, const REGION region = RGN_ALL); - -/// Calculates the minimum of a field, excluding the boundary/guard -/// cells by default (can be changed with \p rgn argument). -/// -/// By default this is only on the local processor, but setting \p -/// allpe true does a collective Allreduce over all processors. -/// -/// @param[in] f The field to loop over -/// @param[in] allpe Minimum over all processors? -/// @param[in] rgn The region to calculate the result over -BoutReal min(const Field3D &f, bool allpe=false, REGION rgn=RGN_NOBNDRY); - -/// Calculates the maximum of a field, excluding the boundary/guard -/// cells by default (can be changed with \p rgn argument). -/// -/// By default this is only on the local processor, but setting \p -/// allpe to true does a collective Allreduce over all processors. -/// -/// @param[in] f The field to loop over -/// @param[in] allpe Maximum over all processors? -/// @param[in] rgn The region to calculate the result over -BoutReal max(const Field3D &f, bool allpe=false, REGION rgn=RGN_NOBNDRY); - -/// Calculates the mean of a field, excluding the boundary/guard -/// cells by default (can be changed with \p rgn argument). -/// -/// By default this is only on the local processor, but setting \p -/// allpe to true does a collective Allreduce over all processors. -/// -/// @param[in] f The field to loop over -/// @param[in] allpe Mean over all processors? -/// @param[in] rgn The region to calculate the result over -BoutReal mean(const Field3D &f, bool allpe=false, REGION rgn=RGN_NOBNDRY); - /// Exponent: pow(lhs, lhs) is \p lhs raised to the power of \p rhs /// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument) -/// If CHECK >= 3 then the result will be checked for non-finite numbers -Field3D pow(const Field3D &lhs, const Field3D &rhs, REGION rgn = RGN_ALL); -Field3D pow(const Field3D &lhs, const Field2D &rhs, REGION rgn = RGN_ALL); -FieldPerp pow(const Field3D &lhs, const FieldPerp &rhs, REGION rgn = RGN_ALL); -Field3D pow(const Field3D &lhs, BoutReal rhs, REGION rgn = RGN_ALL); -Field3D pow(BoutReal lhs, const Field3D &rhs, REGION rgn = RGN_ALL); - -/// Square root of \p f over region \p rgn -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -Field3D sqrt(const Field3D &f, REGION rgn = RGN_ALL); - -/// Absolute value (modulus, |f|) of \p f over region \p rgn -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -Field3D abs(const Field3D &f, REGION rgn = RGN_ALL); - -/// Exponential: \f$\exp(f)\f$ is e to the power of \p f, over region -/// \p rgn -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -Field3D exp(const Field3D &f, REGION rgn = RGN_ALL); - -/// Natural logarithm of \p f over region \p rgn, inverse of -/// exponential -/// -/// \f$\ln(\exp(f)) = f\f$ -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the rgn argument) -/// If CHECK >= 3 then the result will be checked for non-finite numbers -/// -Field3D log(const Field3D &f, REGION rgn = RGN_ALL); - -/// Sine trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -Field3D sin(const Field3D &f, REGION rgn = RGN_ALL); - -/// Cosine trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -Field3D cos(const Field3D &f, REGION rgn = RGN_ALL); - -/// Tangent trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -Field3D tan(const Field3D &f, REGION rgn = RGN_ALL); - -/// Hyperbolic sine trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -Field3D sinh(const Field3D &f, REGION rgn = RGN_ALL); - -/// Hyperbolic cosine trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -Field3D cosh(const Field3D &f, REGION rgn = RGN_ALL); - -/// Hyperbolic tangent trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over +/// Extra overloads not provided by the templates in field.hxx /// /// This loops over the entire domain, including guard/boundary cells by /// default (can be changed using the \p rgn argument). /// If CHECK >= 3 then the result will be checked for non-finite numbers -Field3D tanh(const Field3D &f, REGION rgn = RGN_ALL); - -/// Check if all values of a field \p var are finite. -/// Loops over all points including the boundaries by -/// default (can be changed using the \p rgn argument -bool finite(const Field3D &var, REGION rgn = RGN_ALL); - +Field3D pow(const Field3D& lhs, const Field2D& rhs, const std::string& rgn = "RGN_ALL"); +[[gnu::deprecated("Please use pow(const Field3D& lhs, const Field2D& rhs" + "const std::string& region = \"RGN_ALL\") instead")]] +inline Field3D pow(const Field3D &lhs, const Field2D &rhs, REGION rgn) { + return pow(lhs, rhs, toString(rgn)); +} +FieldPerp pow(const Field3D& lhs, const FieldPerp& rhs, const std::string& rgn = "RGN_ALL"); +[[gnu::deprecated("Please use pow(const Field3D& lhs, const FieldPerp& rhs" + "const std::string& region = \"RGN_ALL\") instead")]] +inline FieldPerp pow(const Field3D& lhs, const FieldPerp& rhs, REGION rgn) { + return pow(lhs, rhs, toString(rgn)); +} #if CHECK > 0 /// Throw an exception if \p f is not allocated or if any /// elements are non-finite (for CHECK > 2). /// Loops over all points including the boundaries by /// default (can be changed using the \p rgn argument -void checkData(const Field3D &f, REGION region = RGN_NOBNDRY); +void checkData(const Field3D& f, const std::string& region = "RGN_NOBNDRY"); +[[gnu::deprecated("Please use checkData(const Field3D& f, " + "const std::string& region = \"RGN_NOBNDRY\") instead")]] +inline void checkData(const Field3D &f, REGION region) { + return checkData(f, toString(region)); +} #else /// Ignored with disabled CHECK; Throw an exception if \p f is not /// allocated or if any elements are non-finite (for CHECK > 2) -inline void checkData(const Field3D &UNUSED(f), REGION UNUSED(region) = RGN_NOBNDRY){}; +inline void checkData(const Field3D& UNUSED(f), const std::string& UNUSED(region) = "RGN_NOBNDRY") {}; +[[gnu::deprecated("Please use checkData(const Field3D& f, " + "const std::string& region = \"RGN_NOBNDRY\") instead")]] +inline void checkData(const Field3D &UNUSED(f), REGION UNUSED(region)) {} #endif -/// Makes a copy of a field \p f, ensuring that the underlying data is -/// not shared. -Field3D copy(const Field3D &f); - -/// Apply a floor value \p f to a field \p var. Any value lower than -/// the floor is set to the floor. -/// -/// @param[in] var Variable to apply floor to -/// @param[in] f The floor value -/// @param[in] rgn The region to calculate the result over -Field3D floor(const Field3D &var, BoutReal f, REGION rgn = RGN_ALL); - /// Fourier filtering, removes all except one mode /// /// @param[in] var Variable to apply filter to /// @param[in] N0 The component to keep /// @param[in] rgn The region to calculate the result over -Field3D filter(const Field3D &var, int N0, REGION rgn = RGN_ALL); +Field3D filter(const Field3D& var, int N0, const std::string& rgn = "RGN_ALL"); +[[gnu::deprecated("Please use filter(const Field3D& var, int N0, " + "const std::string& region = \"RGN_ALL\") instead")]] +inline Field3D filter(const Field3D& var, int N0, REGION rgn) { + return filter(var, N0, toString(rgn)); +} /// Fourier low pass filtering. Removes modes /// higher than \p zmax and optionally the zonal component @@ -746,14 +621,20 @@ Field3D filter(const Field3D &var, int N0, REGION rgn = RGN_ALL); /// @param[in] zmax Maximum mode in Z /// @param[in] keep_zonal Keep the zonal component if true /// @param[in] rgn The region to calculate the result over -Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn = RGN_ALL); +Field3D lowPass(const Field3D& var, int zmax, bool keep_zonal, + const std::string& rgn = "RGN_ALL"); +[[gnu::deprecated("Please use lowpass(const Field3D& var, int zmax, bool keep_zonal, " + "const std::string& region = \"RGN_ALL\") instead")]] +inline Field3D lowPass(const Field3D& var, int zmax, bool keep_zonal, REGION rgn) { + return lowPass(var, zmax, keep_zonal, toString(rgn)); +} /// The argument \p keep_zonal used to be integer "zmin" -- this was a /// misnomer. Please use the version above which uses a bool instead DEPRECATED(inline Field3D lowPass(const Field3D& var, int zmax, int keep_zonal, REGION rgn = RGN_ALL)) { ASSERT0(static_cast(keep_zonal) == keep_zonal); - return lowPass(var, zmax, static_cast(keep_zonal), rgn); + return lowPass(var, zmax, static_cast(keep_zonal), toString(rgn)); } /// Fourier low pass filtering. Removes modes higher than \p zmax @@ -761,9 +642,14 @@ DEPRECATED(inline Field3D lowPass(const Field3D& var, int zmax, int keep_zonal, /// @param[in] var Variable to apply filter to /// @param[in] zmax Maximum mode in Z /// @param[in] rgn The region to calculate the result over -inline Field3D lowPass(const Field3D &var, int zmax, REGION rgn = RGN_ALL) { +inline Field3D lowPass(const Field3D &var, int zmax, const std::string rgn = "RGN_ALL") { return lowPass(var, zmax, true, rgn); } +[[gnu::deprecated("Please use lowpass(const Field3D& var, int zmax, " + "const std::string& region = \"RGN_ALL\") instead")]] +inline Field3D lowPass(const Field3D &var, int zmax, REGION rgn) { + return lowPass(var, zmax, toString(rgn)); +} /// Perform a shift by a given angle in Z /// @@ -778,13 +664,23 @@ void shiftZ(Field3D &var, int jx, int jy, double zangle); /// @param[inout] var The variable to modify in-place /// @param[in] zangle The angle to shift by in Z /// @param[in] rgn The region to calculate the result over -void shiftZ(Field3D &var, double zangle, REGION rgn=RGN_ALL); +void shiftZ(Field3D &var, BoutReal zangle, const std::string& rgn="RGN_ALL"); +[[gnu::deprecated("Please use shiftZ(const Field3D& var, BoutReal zangle, " + "const std::string& region = \"RGN_ALL\") instead")]] +inline void shiftZ(Field3D &var, BoutReal zangle, REGION rgn) { + return shiftZ(var, zangle, toString(rgn)); +} /// Average in the Z direction /// /// @param[in] f Variable to average /// @param[in] rgn The region to calculate the result over -Field2D DC(const Field3D &f, REGION rgn = RGN_ALL); +Field2D DC(const Field3D &f, const std::string& rgn = "RGN_ALL"); +[[gnu::deprecated("Please use DC(const Field3D& f, " + "const std::string& region = \"RGN_ALL\") instead")]] +inline Field2D DC(const Field3D &f, REGION rgn) { + return DC(f, toString(rgn)); +} /// Force guard cells of passed field \p var to NaN #if CHECK > 2 diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index cf145a07d2..fb8092b03e 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -271,9 +271,6 @@ private: // Non-member functions -FieldPerp toFieldAligned(const FieldPerp& f, const REGION region = RGN_ALL); -FieldPerp fromFieldAligned(const FieldPerp& f, const REGION region = RGN_ALL); - // Non-member overloaded operators FieldPerp operator+(const FieldPerp &lhs, const FieldPerp &rhs); @@ -306,122 +303,9 @@ FieldPerp operator/(BoutReal lhs, const FieldPerp &rhs); */ FieldPerp operator-(const FieldPerp &f); -/// Square root -const FieldPerp sqrt(const FieldPerp &f, REGION rgn=RGN_ALL); - -/// Absolute value -const FieldPerp abs(const FieldPerp &f, REGION rgn=RGN_ALL); - -/// Exponential -const FieldPerp exp(const FieldPerp &f, REGION rgn=RGN_ALL); - -/// Natural logarithm -const FieldPerp log(const FieldPerp &f, REGION rgn=RGN_ALL); - -/// Sine trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -const FieldPerp sin(const FieldPerp &f, REGION rgn=RGN_ALL); - -/// Cosine trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -const FieldPerp cos(const FieldPerp &f, REGION rgn=RGN_ALL); - -/// Tangent trigonometric function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -const FieldPerp tan(const FieldPerp &f, REGION rgn=RGN_ALL); - -/// Hyperbolic sine function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -const FieldPerp sinh(const FieldPerp &f, REGION rgn=RGN_ALL); - -/// Hyperbolic cosine function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -const FieldPerp cosh(const FieldPerp &f, REGION rgn=RGN_ALL); - -/// Hyperbolic tangent function. -/// -/// @param[in] f Angle in radians -/// @param[in] rgn The region to calculate the result over -/// -/// This loops over the entire domain, including guard/boundary cells by -/// default (can be changed using the \p rgn argument). -/// If CHECK >= 3 then the result will be checked for non-finite numbers -const FieldPerp tanh(const FieldPerp &f, REGION rgn=RGN_ALL); - -/// Create a unique copy of a FieldPerp, ensuring -/// that they do not share an underlying data array -const FieldPerp copy(const FieldPerp &f); - -/// Sets a floor on var, so minimum of the return value is >= f -const FieldPerp floor(const FieldPerp &var, BoutReal f, REGION rgn=RGN_ALL); - -/// Power, lhs ** rhs -FieldPerp pow(const FieldPerp &lhs, const FieldPerp &rhs, REGION rgn=RGN_ALL); -FieldPerp pow(const FieldPerp &lhs, BoutReal rhs, REGION rgn=RGN_ALL); -FieldPerp pow(BoutReal lhs, const FieldPerp &rhs, REGION rgn=RGN_ALL); - /// Create a FieldPerp by slicing a 3D field at a given y const FieldPerp sliceXZ(const Field3D& f, int y); -/// Calculates the minimum of a field, excluding -/// the boundary/guard cells by default (this can be -/// changed with the rgn argument). -/// By default this is only on the local processor, -/// but setting allpe=true does a collective Allreduce -/// over all processors. -/// -/// @param[in] f The field to loop over -/// @param[in] allpe Minimum over all processors? -/// @param[in] rgn The region to calculate the result over -BoutReal min(const FieldPerp &f, bool allpe=false, REGION rgn=RGN_NOX); - -/// Calculates the maximum of a field, excluding -/// the boundary/guard cells by default (this can be -/// changed with the rgn argument). -/// By default this is only on the local processor, -/// but setting allpe=true does a collective Allreduce -/// over all processors. -/// -/// @param[in] f The field to loop over -/// @param[in] allpe Minimum over all processors? -/// @param[in] rgn The region to calculate the result over -BoutReal max(const FieldPerp &f, bool allpe=false, REGION rgn=RGN_NOX); - -/// Test if all values of this field are finite -/// Loops over the entire domain including boundaries by -/// default (can be changed using the \p rgn argument) -bool finite(const FieldPerp &f, REGION rgn=RGN_ALL); - // Specialize newEmptyField templates for FieldPerp /// Return an empty shell field of some type derived from Field, with metadata /// copied and a data array that is allocated but not initialised. @@ -431,9 +315,17 @@ inline FieldPerp emptyFrom(const FieldPerp& f) { } #if CHECK > 0 -void checkData(const FieldPerp &f, REGION region = RGN_NOX); +void checkData(const FieldPerp &f, const std::string& region = "RGN_NOX"); +[[gnu::deprecated("Please use checkData(const FieldPerp& f, " + "const std::string& region = \"RGN_NOBNDRY\") instead")]] +inline void checkData(const FieldPerp &f, REGION region) { + return checkData(f, toString(region)); +} #else -inline void checkData(const FieldPerp &UNUSED(f), REGION UNUSED(region) = RGN_NOX) {} +inline void checkData(const FieldPerp &UNUSED(f), const std::string& UNUSED(region) = "RGN_NOX") {} +[[gnu::deprecated("Please use checkData(const FieldPerp& f, " + "const std::string& region = \"RGN_NOBNDRY\") instead")]] +inline void checkData(const FieldPerp &UNUSED(f), REGION UNUSED(region)) {} #endif /// Force guard cells of passed field \p var to NaN diff --git a/include/interpolation.hxx b/include/interpolation.hxx index b27a110650..761b7f9715 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -58,7 +58,7 @@ inline BoutReal interp(const stencil& s) { @param[in] region Region where output will be calculated */ template -const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { +const T interp_to(const T& var, CELL_LOC loc, const std::string region = "RGN_ALL") { AUTO_TRACE(); static_assert(std::is_base_of::value || std::is_base_of::value, "interp_to must be templated with one of Field2D or Field3D."); @@ -84,7 +84,7 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { TRACE("Interpolating %s -> %s", toString(var.getLocation()).c_str(), toString(loc).c_str()); - if (region != RGN_NOBNDRY) { + if (region != "RGN_NOBNDRY") { // result is requested in some boundary region(s) result = var; // NOTE: This is just for boundaries. FIX! result.setLocation(loc); // location gets reset when assigning from var @@ -126,8 +126,8 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { // We can't interpolate in y unless we're field-aligned // FIXME: Add check once we label fields as orthogonal/aligned - const T var_fa = toFieldAligned(var, RGN_NOX); - if (region != RGN_NOBNDRY) { + const T var_fa = toFieldAligned(var, "RGN_NOX"); + if (region != "RGN_NOBNDRY") { // repeat the hack above for boundary points // this avoids a duplicate toFieldAligned call if we had called // result = toFieldAligned(result) @@ -153,7 +153,7 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { } } - result = fromFieldAligned(result, RGN_NOBNDRY); + result = fromFieldAligned(result, "RGN_NOBNDRY"); break; } @@ -180,7 +180,7 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { } }; - if ((dir != CELL_ZLOW) && (region != RGN_NOBNDRY)) { + if ((dir != CELL_ZLOW) && (region != "RGN_NOBNDRY")) { fieldmesh->communicate(result); } @@ -193,6 +193,12 @@ const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { } return result; } +template +[[gnu::deprecated("Please use interp_to(const T& var, CELL_LOC loc, " + "const std::string& region = \"RGN_ALL\") instead")]] +const T interp_to(const T& var, CELL_LOC loc, REGION region) { + return interp_to(var, loc, toString(region)); +} /// Print out the cell location (for debugging) [[gnu::deprecated("Please use `output << toString(var.getLocation())` instead")]] diff --git a/include/vector2d.hxx b/include/vector2d.hxx index 80040b76a2..bd7be6722f 100644 --- a/include/vector2d.hxx +++ b/include/vector2d.hxx @@ -175,7 +175,12 @@ const Vector3D cross(const Vector2D & lhs, const Vector3D &rhs); * * |v| = sqrt( v dot v ) */ -const Field2D abs(const Vector2D &v, REGION region = RGN_ALL); +const Field2D abs(const Vector2D& v, const std::string& region = "RGN_ALL"); +[[gnu::deprecated("Please use Vector2D abs(const Vector2D& f, " + "const std::string& region = \"RGN_ALL\") instead")]] +inline const Field2D abs(const Vector2D &v, REGION region) { + return abs(v, toString(region)); +} /*! * @brief Time derivative of 2D vector field diff --git a/include/vector3d.hxx b/include/vector3d.hxx index 38eb25658b..09df39c7f7 100644 --- a/include/vector3d.hxx +++ b/include/vector3d.hxx @@ -218,7 +218,12 @@ const Vector3D cross(const Vector3D & lhs, const Vector2D &rhs); * * sqrt( v.x^2 + v.y^2 + v.z^2 ) */ -const Field3D abs(const Vector3D &v, REGION region = RGN_ALL); +const Field3D abs(const Vector3D& v, const std::string& region = "RGN_ALL"); +[[gnu::deprecated("Please use Vector3D abs(const Vector3D& f, " + "const std::string& region = \"RGN_ALL\") instead")]] +inline const Field3D abs(const Vector3D& v, REGION region) { + return abs(v, toString(region)); +} /*! * @brief Time derivative of 3D vector field diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 8c43cbfedf..e9be1c1239 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -329,185 +329,11 @@ Field2D operator-(const Field2D &f) { return -1.0 * f; } //////////////// NON-MEMBER FUNCTIONS ////////////////// -BoutReal min(const Field2D &f, bool allpe, REGION rgn) { - TRACE("Field2D::Min() %s",allpe? "over all PEs" : ""); - - checkData(f); - - const auto region = f.getRegion(rgn); - BoutReal result = f[*region.cbegin()]; - - BOUT_FOR_OMP(i, region, parallel for reduction(min:result)) { - if (f[i] < result) { - result = f[i]; - } - } - - if(allpe) { - // MPI reduce - BoutReal localresult = result; - MPI_Allreduce(&localresult, &result, 1, MPI_DOUBLE, MPI_MIN, BoutComm::get()); - } - - return result; -} - -BoutReal max(const Field2D &f, bool allpe,REGION rgn) { - TRACE("Field2D::Max() %s",allpe? "over all PEs" : ""); - - checkData(f); - - const auto region = f.getRegion(rgn); - BoutReal result = f[*region.cbegin()]; - - BOUT_FOR_OMP(i, region, parallel for reduction(max:result)) { - if (f[i] > result) { - result = f[i]; - } - } - - if(allpe) { - // MPI reduce - BoutReal localresult = result; - MPI_Allreduce(&localresult, &result, 1, MPI_DOUBLE, MPI_MAX, BoutComm::get()); - } - - return result; -} - -bool finite(const Field2D &f, REGION rgn) { - TRACE("finite(Field2D)"); - - if (!f.isAllocated()) { - return false; - } - - BOUT_FOR_SERIAL(i, f.getRegion(rgn)) { - if (!::finite(f[i])) { - return false; - } - } - - return true; -} - -///////////////////////////////////////////////// -// functions - -/*! - * This macro takes a function \p func, which is - * assumed to operate on a single BoutReal and return - * a single BoutReal, and wraps it up into a function - * of a Field2D called \p name. - * - * @param name The name of the function to define - * @param func The function to apply to each value - * - * If CHECK >= 1, checks if the Field2D is allocated - * - * Loops over the entire domain, applies function, - * and uses checkData() to, if CHECK >= 3, check - * result for non-finite numbers - * - */ -#define F2D_FUNC(name, func) \ - const Field2D name(const Field2D &f, REGION rgn) { \ - TRACE(#name "(Field2D)"); \ - /* Check if the input is allocated */ \ - checkData(f); \ - /* Define and allocate the output result */ \ - Field2D result{emptyFrom(f)}; \ - BOUT_FOR(d, result.getRegion(rgn)) { result[d] = func(f[d]); } \ - checkData(result); \ - return result; \ - } - -F2D_FUNC(abs, ::fabs); - -F2D_FUNC(sqrt, ::sqrt); - -F2D_FUNC(exp, ::exp); -F2D_FUNC(log, ::log); - -F2D_FUNC(sin, ::sin); -F2D_FUNC(cos, ::cos); -F2D_FUNC(tan, ::tan); - -F2D_FUNC(sinh, ::sinh); -F2D_FUNC(cosh, ::cosh); -F2D_FUNC(tanh, ::tanh); - -const Field2D copy(const Field2D &f) { - Field2D result = f; - result.allocate(); - return result; -} - -const Field2D floor(const Field2D &var, BoutReal f, REGION rgn) { - checkData(var); - - Field2D result = copy(var); - - BOUT_FOR(d, result.getRegion(rgn)) { - if (result[d] < f) { - result[d] = f; - } - } - - return result; -} - -Field2D pow(const Field2D &lhs, const Field2D &rhs, REGION rgn) { - TRACE("pow(Field2D, Field2D)"); - // Check if the inputs are allocated - checkData(lhs); - checkData(rhs); - ASSERT1(areFieldsCompatible(lhs, rhs)); - - // Define and allocate the output result - Field2D result{emptyFrom(lhs)}; - - BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } - - checkData(result); - return result; -} - -Field2D pow(const Field2D &lhs, BoutReal rhs, REGION rgn) { - TRACE("pow(Field2D, BoutReal)"); - // Check if the inputs are allocated - checkData(lhs); - checkData(rhs); - - // Define and allocate the output result - Field2D result{emptyFrom(lhs)}; - - BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs); } - - checkData(result); - return result; -} - -Field2D pow(BoutReal lhs, const Field2D &rhs, REGION rgn) { - TRACE("pow(lhs, Field2D)"); - // Check if the inputs are allocated - checkData(lhs); - checkData(rhs); - - // Define and allocate the output result - Field2D result{emptyFrom(rhs)}; - - BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs, rhs[i]); } - - checkData(result); - return result; -} - namespace { // Internal routine to avoid ugliness with interactions between CHECK // levels and UNUSED parameters #if CHECK > 2 -void checkDataIsFiniteOnRegion(const Field2D& f, REGION region) { +void checkDataIsFiniteOnRegion(const Field2D& f, const std::string& region) { // Do full checks BOUT_FOR_SERIAL(i, f.getRegion(region)) { if (!::finite(f[i])) { @@ -518,13 +344,13 @@ void checkDataIsFiniteOnRegion(const Field2D& f, REGION region) { } #elif CHECK > 0 // No-op for no checking -void checkDataIsFiniteOnRegion(const Field2D &UNUSED(f), REGION UNUSED(region)) {} +void checkDataIsFiniteOnRegion(const Field2D &UNUSED(f), const std::string& UNUSED(region)) {} #endif } #if CHECK > 0 /// Check if the data is valid -void checkData(const Field2D &f, REGION region) { +void checkData(const Field2D &f, const std::string& region) { if (!f.isAllocated()) { throw BoutException("Field2D: Operation on empty data\n"); } diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 2906bddba2..3fa2d3f649 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -601,28 +601,7 @@ Field3D operator-(const Field3D &f) { return -1.0 * f; } //////////////// NON-MEMBER FUNCTIONS ////////////////// -Field3D toFieldAligned(const Field3D& f, const REGION region) { - return f.getCoordinates()->getParallelTransform().toFieldAligned(f, region); -} - -Field3D fromFieldAligned(const Field3D& f, const REGION region) { - return f.getCoordinates()->getParallelTransform().fromFieldAligned(f, region); -} - -Field3D pow(const Field3D &lhs, const Field3D &rhs, REGION rgn) { - TRACE("pow(Field3D, Field3D)"); - - ASSERT1(areFieldsCompatible(lhs, rhs)); - - Field3D result{emptyFrom(lhs)}; - - BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } - - checkData(result); - return result; -} - -Field3D pow(const Field3D &lhs, const Field2D &rhs, REGION rgn) { +Field3D pow(const Field3D &lhs, const Field2D &rhs, const std::string& rgn) { TRACE("pow(Field3D, Field2D)"); // Check if the inputs are allocated checkData(lhs); @@ -638,7 +617,7 @@ Field3D pow(const Field3D &lhs, const Field2D &rhs, REGION rgn) { return result; } -FieldPerp pow(const Field3D &lhs, const FieldPerp &rhs, REGION rgn) { +FieldPerp pow(const Field3D &lhs, const FieldPerp &rhs, const std::string& rgn) { TRACE("pow(Field3D, FieldPerp)"); checkData(lhs); @@ -656,152 +635,10 @@ FieldPerp pow(const Field3D &lhs, const FieldPerp &rhs, REGION rgn) { return result; } -Field3D pow(const Field3D &lhs, BoutReal rhs, REGION rgn) { - TRACE("pow(Field3D, BoutReal)"); - // Check if the inputs are allocated - checkData(lhs); - checkData(rhs); - - Field3D result{emptyFrom(lhs)}; - - BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs); } - - checkData(result); - return result; -} - -Field3D pow(BoutReal lhs, const Field3D &rhs, REGION rgn) { - TRACE("pow(lhs, Field3D)"); - // Check if the inputs are allocated - checkData(lhs); - checkData(rhs); - - // Define and allocate the output result - Field3D result{emptyFrom(rhs)}; - - BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs, rhs[i]); } - - checkData(result); - return result; -} - -BoutReal min(const Field3D &f, bool allpe, REGION rgn) { - TRACE("Field3D::Min() %s",allpe? "over all PEs" : ""); - - checkData(f); - - const auto region = f.getRegion(rgn); - BoutReal result = f[*region.cbegin()]; - - BOUT_FOR_OMP(i, region, parallel for reduction(min:result)) { - if(f[i] < result) { - result = f[i]; - } - } - - if(allpe) { - // MPI reduce - BoutReal localresult = result; - MPI_Allreduce(&localresult, &result, 1, MPI_DOUBLE, MPI_MIN, BoutComm::get()); - } - - return result; -} - -BoutReal max(const Field3D &f, bool allpe, REGION rgn) { - TRACE("Field3D::Max() %s",allpe? "over all PEs" : ""); - - checkData(f); - - const auto region = f.getRegion(rgn); - BoutReal result = f[*region.cbegin()]; - - BOUT_FOR_OMP(i, region, parallel for reduction(max:result)) { - if(f[i] > result) { - result = f[i]; - } - } - - if(allpe) { - // MPI reduce - BoutReal localresult = result; - MPI_Allreduce(&localresult, &result, 1, MPI_DOUBLE, MPI_MAX, BoutComm::get()); - } - - return result; -} - -BoutReal mean(const Field3D &f, bool allpe, REGION rgn) { - TRACE("Field3D::mean() %s",allpe? "over all PEs" : ""); - - checkData(f); - - // Intitialise the cummulative sum and counter - BoutReal result = 0.; - int count = 0; - - BOUT_FOR_OMP(i, f.getRegion(rgn), parallel for reduction(+:result,count)) { - result += f[i]; - count += 1; - } - - if(allpe) { - // MPI reduce - BoutReal localresult = result; - MPI_Allreduce(&localresult, &result, 1, MPI_DOUBLE, MPI_SUM, BoutComm::get()); - int localcount = count; - MPI_Allreduce(&localcount, &count, 1, MPI_INT, MPI_SUM, BoutComm::get()); - } - - return result / static_cast(count); -} - ///////////////////////////////////////////////////////////////////// // Friend functions -/*! - * This macro takes a function \p func, which is - * assumed to operate on a single BoutReal and return - * a single BoutReal, and wraps it up into a function - * of a Field3D called \p name. - * - * @param name The name of the function to define - * @param func The function to apply to each value - * - * If CHECK >= 1, checks if the Field3D is allocated - * - * Loops over the entire domain, applies function, - * and uses checkData() to, if CHECK >= 3, check - * result for non-finite numbers - * - */ -#define F3D_FUNC(name, func) \ - Field3D name(const Field3D &f, REGION rgn) { \ - TRACE(#name "(Field3D)"); \ - /* Check if the input is allocated */ \ - checkData(f); \ - /* Define and allocate the output result */ \ - Field3D result{emptyFrom(f)}; \ - BOUT_FOR(d, result.getRegion(rgn)) { result[d] = func(f[d]); } \ - checkData(result); \ - return result; \ - } - -F3D_FUNC(sqrt, ::sqrt); -F3D_FUNC(abs, ::fabs); - -F3D_FUNC(exp, ::exp); -F3D_FUNC(log, ::log); - -F3D_FUNC(sin, ::sin); -F3D_FUNC(cos, ::cos); -F3D_FUNC(tan, ::tan); - -F3D_FUNC(sinh, ::sinh); -F3D_FUNC(cosh, ::cosh); -F3D_FUNC(tanh, ::tanh); - -Field3D filter(const Field3D &var, int N0, REGION rgn) { +Field3D filter(const Field3D &var, int N0, const std::string& rgn) { TRACE("filter(Field3D, int)"); checkData(var); @@ -847,7 +684,7 @@ Field3D filter(const Field3D &var, int N0, REGION rgn) { } // Fourier filter in z with zmin -Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, REGION rgn) { +Field3D lowPass(const Field3D &var, int zmax, bool keep_zonal, const std::string& rgn) { TRACE("lowPass(Field3D, %d, %d)", zmax, keep_zonal); checkData(var); @@ -920,7 +757,7 @@ void shiftZ(Field3D &var, int jx, int jy, double zangle) { irfft(v.begin(), ncz, &(var(jx,jy,0))); // Reverse FFT } -void shiftZ(Field3D &var, double zangle, REGION rgn) { +void shiftZ(Field3D &var, double zangle, const std::string& rgn) { const auto region_str = toString(rgn); // Only allow a whitelist of regions for now @@ -935,27 +772,11 @@ void shiftZ(Field3D &var, double zangle, REGION rgn) { } } -bool finite(const Field3D &f, REGION rgn) { - TRACE("finite( Field3D )"); - - if (!f.isAllocated()) { - return false; - } - - BOUT_FOR_SERIAL(i, f.getRegion(rgn)) { - if (!finite(f[i])) { - return false; - } - } - - return true; -} - namespace { // Internal routine to avoid ugliness with interactions between CHECK // levels and UNUSED parameters #if CHECK > 2 -void checkDataIsFiniteOnRegion(const Field3D& f, REGION region) { +void checkDataIsFiniteOnRegion(const Field3D& f, const std::string& region) { // Do full checks BOUT_FOR_SERIAL(i, f.getRegion(region)) { if (!finite(f[i])) { @@ -966,12 +787,12 @@ void checkDataIsFiniteOnRegion(const Field3D& f, REGION region) { } #elif CHECK > 0 // No-op for no checking -void checkDataIsFiniteOnRegion(const Field3D &UNUSED(f), REGION UNUSED(region)) {} +void checkDataIsFiniteOnRegion(const Field3D &UNUSED(f), const std::string& UNUSED(region)) {} #endif } #if CHECK > 0 -void checkData(const Field3D &f, REGION region) { +void checkData(const Field3D &f, const std::string& region) { if (!f.isAllocated()) throw BoutException("Field3D: Operation on empty data\n"); @@ -979,26 +800,7 @@ void checkData(const Field3D &f, REGION region) { } #endif -Field3D copy(const Field3D &f) { - Field3D result = f; - result.allocate(); - return result; -} - -Field3D floor(const Field3D &var, BoutReal f, REGION rgn) { - checkData(var); - Field3D result = copy(var); - - BOUT_FOR(d, var.getRegion(rgn)) { - if (result[d] < f) { - result[d] = f; - } - } - - return result; -} - -Field2D DC(const Field3D &f, REGION rgn) { +Field2D DC(const Field3D &f, const std::string& rgn) { TRACE("DC(Field3D)"); checkData(f); diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index e74518e8ce..755f09a7cc 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -230,7 +230,7 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC if (coords->getParallelTransform().canToFromFieldAligned()) { // Transform from field aligned coordinates, to be compatible with // older BOUT++ inputs. This is not a particularly "nice" solution. - result = fromFieldAligned(result, RGN_ALL); + result = fromFieldAligned(result, "RGN_ALL"); } } @@ -310,7 +310,7 @@ FieldPerp FieldFactory::createPerp(FieldGeneratorPtr gen, Mesh* localmesh, CELL_ if (coords->getParallelTransform().canToFromFieldAligned()) { // Transform from field aligned coordinates, to be compatible with // older BOUT++ inputs. This is not a particularly "nice" solution. - result = fromFieldAligned(result, RGN_ALL); + result = fromFieldAligned(result, "RGN_ALL"); } } diff --git a/src/field/fieldperp.cxx b/src/field/fieldperp.cxx index 6c04f30362..b4e2374a0d 100644 --- a/src/field/fieldperp.cxx +++ b/src/field/fieldperp.cxx @@ -106,11 +106,11 @@ const Region &FieldPerp::getRegion(const std::string ®ion_name) cons //////////////// NON-MEMBER FUNCTIONS ////////////////// -FieldPerp toFieldAligned(const FieldPerp& f, const REGION region) { +FieldPerp toFieldAligned(const FieldPerp& f, const std::string& region) { return f.getCoordinates()->getParallelTransform().toFieldAligned(f, region); } -FieldPerp fromFieldAligned(const FieldPerp& f, const REGION region) { +FieldPerp fromFieldAligned(const FieldPerp& f, const std::string& region) { return f.getCoordinates()->getParallelTransform().fromFieldAligned(f, region); } @@ -122,70 +122,6 @@ FieldPerp operator-(const FieldPerp &f) { return -1.0 * f; } ///////////////////////////////////////////////// // functions -/*! - * This macro takes a function \p func, which is - * assumed to operate on a single BoutReal and return - * a single BoutReal, and wraps it up into a function - * of a FieldPerp called \p name. - * - * @param name The name of the function to define - * @param func The function to apply to each value - * - * If CHECK >= 1, checks if the FieldPerp is allocated - * - * Loops over the entire domain, applies function, - * and uses checkData() to, if CHECK >= 3, check - * result for non-finite numbers - * - */ -#define FPERP_FUNC(name, func) \ - const FieldPerp name(const FieldPerp& f, REGION rgn) { \ - checkData(f); \ - TRACE(#name "(FieldPerp)"); \ - /* Check if the input is allocated */ \ - ASSERT1(f.isAllocated()); \ - /* Define and allocate the output result */ \ - FieldPerp result{emptyFrom(f)}; \ - BOUT_FOR(d, result.getRegion(rgn)) { result[d] = func(f[d]); } \ - checkData(result); \ - return result; \ - } - -FPERP_FUNC(abs, ::fabs); - -FPERP_FUNC(sqrt, ::sqrt); - -FPERP_FUNC(exp, ::exp); -FPERP_FUNC(log, ::log); - -FPERP_FUNC(sin, ::sin); -FPERP_FUNC(cos, ::cos); -FPERP_FUNC(tan, ::tan); - -FPERP_FUNC(sinh, ::sinh); -FPERP_FUNC(cosh, ::cosh); -FPERP_FUNC(tanh, ::tanh); - -const FieldPerp copy(const FieldPerp &f) { - FieldPerp fcopy = f; - fcopy.allocate(); - return fcopy; -} - -const FieldPerp floor(const FieldPerp &var, BoutReal f, REGION rgn) { - checkData(var); - FieldPerp result = copy(var); - - BOUT_FOR(d, var.getRegion(rgn)) { - if (result[d] < f) { - result[d] = f; - } - } - - checkData(result); - return result; -} - const FieldPerp sliceXZ(const Field3D& f, int y) { // Source field should be valid checkData(f); @@ -201,113 +137,8 @@ const FieldPerp sliceXZ(const Field3D& f, int y) { return result; } -BoutReal min(const FieldPerp &f, bool allpe, REGION rgn) { - TRACE("FieldPerp::Min() %s", allpe ? "over all PEs" : ""); - - checkData(f); - - const auto region = f.getRegion(rgn); - BoutReal result = f[*region.cbegin()]; - - BOUT_FOR_OMP(i, region, parallel for reduction(min:result)) { - if (f[i] < result) { - result = f[i]; - } - } - - if (allpe) { - // MPI reduce - BoutReal localresult = result; - MPI_Allreduce(&localresult, &result, 1, MPI_DOUBLE, MPI_MIN, BoutComm::get()); - } - - return result; -} - -BoutReal max(const FieldPerp &f, bool allpe, REGION rgn) { - TRACE("FieldPerp::Max() %s", allpe ? "over all PEs" : ""); - - checkData(f); - - const auto region = f.getRegion(rgn); - BoutReal result = f[*region.cbegin()]; - - BOUT_FOR_OMP(i, region, parallel for reduction(max:result)) { - if (f[i] > result) { - result = f[i]; - } - } - - if (allpe) { - // MPI reduce - BoutReal localresult = result; - MPI_Allreduce(&localresult, &result, 1, MPI_DOUBLE, MPI_MAX, BoutComm::get()); - } - - return result; -} - -bool finite(const FieldPerp &f, REGION rgn) { - TRACE("finite(FieldPerp)"); - - if (!f.isAllocated()) { - return false; - } - - BOUT_FOR_SERIAL(i, f.getRegion(rgn)) { - if (!::finite(f[i])) { - return false; - } - } - - return true; -} - -FieldPerp pow(const FieldPerp &lhs, const FieldPerp &rhs, REGION rgn) { - TRACE("pow(FieldPerp, FieldPerp)"); - // Check if the inputs are allocated - checkData(lhs); - checkData(rhs); - - // Define and allocate the output result - ASSERT1(areFieldsCompatible(lhs, rhs)); - FieldPerp result{emptyFrom(lhs)}; - BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs[i]); } - - checkData(result); - return result; -} - -FieldPerp pow(const FieldPerp &lhs, BoutReal rhs, REGION rgn) { - TRACE("pow(FieldPerp, BoutReal)"); - // Check if the inputs are allocated - checkData(lhs); - checkData(rhs); - - // Define and allocate the output result - FieldPerp result{emptyFrom(lhs)}; - BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs[i], rhs); } - - checkData(result); - return result; -} - -FieldPerp pow(BoutReal lhs, const FieldPerp &rhs, REGION rgn) { - TRACE("pow(lhs, FieldPerp)"); - // Check if the inputs are allocated - checkData(lhs); - checkData(rhs); - - // Define and allocate the output result - FieldPerp result{emptyFrom(rhs)}; - BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs, rhs[i]); } - - checkData(result); - return result; -} - #if CHECK > 2 -void checkDataIsFiniteOnRegion(const FieldPerp &f, REGION region) { +void checkDataIsFiniteOnRegion(const FieldPerp &f, const std::string& region) { // Do full checks BOUT_FOR_SERIAL(i, f.getRegion(region)) { if (!::finite(f[i])) { @@ -317,13 +148,13 @@ void checkDataIsFiniteOnRegion(const FieldPerp &f, REGION region) { } } #else -void checkDataIsFiniteOnRegion(const FieldPerp &UNUSED(f), REGION UNUSED(region)) {} +void checkDataIsFiniteOnRegion(const FieldPerp &UNUSED(f), const std::string& UNUSED(region)) {} #endif #if CHECK > 0 /// Check if the data is valid -void checkData(const FieldPerp &f, REGION region) { +void checkData(const FieldPerp &f, const std::string& region) { if (!f.isAllocated()) { throw BoutException("FieldPerp: Operation on empty data\n"); } diff --git a/src/field/vector2d.cxx b/src/field/vector2d.cxx index 93abef985a..1dc3d7a2c3 100644 --- a/src/field/vector2d.cxx +++ b/src/field/vector2d.cxx @@ -469,7 +469,7 @@ const Vector3D operator*(const Field3D &lhs, const Vector2D &rhs) { ***************************************************************/ // Return the magnitude of a vector -const Field2D abs(const Vector2D &v, REGION region) { +const Field2D abs(const Vector2D &v, const std::string& region) { return sqrt(v*v, region); } diff --git a/src/field/vector3d.cxx b/src/field/vector3d.cxx index f785e9f250..8c06f2755a 100644 --- a/src/field/vector3d.cxx +++ b/src/field/vector3d.cxx @@ -600,7 +600,7 @@ const Vector3D operator*(const Field3D &lhs, const Vector3D &rhs) ***************************************************************/ // Return the magnitude of a vector -const Field3D abs(const Vector3D &v, REGION region) { +const Field3D abs(const Vector3D &v, const std::string& region) { return sqrt(v*v, region); } diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 1c3e8c1094..82c0569511 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -1222,7 +1222,7 @@ bool Datafile::read_f3d(const std::string &name, Field3D *f, bool save_repeat) { if (shiftInput) { // Input file is in field-aligned coordinates e.g. BOUT++ 3.x restart file - *f = fromFieldAligned(*f, RGN_ALL); + *f = fromFieldAligned(*f, "RGN_ALL"); } return true; @@ -1269,7 +1269,7 @@ bool Datafile::read_fperp(const std::string &name, FieldPerp *f, bool save_repea if (shiftInput) { // Input file is in field-aligned coordinates e.g. BOUT++ 3.x restart file - *f = fromFieldAligned(*f, RGN_ALL); + *f = fromFieldAligned(*f, "RGN_ALL"); } } diff --git a/src/invert/laplace/impls/naulin/naulin_laplace.cxx b/src/invert/laplace/impls/naulin/naulin_laplace.cxx index 92e280d86d..823b081434 100644 --- a/src/invert/laplace/impls/naulin/naulin_laplace.cxx +++ b/src/invert/laplace/impls/naulin/naulin_laplace.cxx @@ -206,13 +206,13 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { Field3D C1TimesD = C1coef*Dcoef; // This is needed several times // x-component of 1./(C1*D) * Grad_perp(C2) - Field3D coef_x = DDX(C2coef, location, DIFF_C2)/C1TimesD; + Field3D coef_x = DDX(C2coef, location, "C2")/C1TimesD; // y-component of 1./(C1*D) * Grad_perp(C2) - Field3D coef_y = DDY(C2coef, location, DIFF_C2)/C1TimesD; + Field3D coef_y = DDY(C2coef, location, "C2")/C1TimesD; // z-component of 1./(C1*D) * Grad_perp(C2) - Field3D coef_z = DDZ(C2coef, location, DIFF_FFT)/C1TimesD; + Field3D coef_z = DDZ(C2coef, location, "FFT")/C1TimesD; Field3D AOverD = Acoef/Dcoef; @@ -228,7 +228,7 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { // necessarily in phase. // This is the piece that cannot be passed to an FFT-based Laplacian solver // (through our current interface). - Field3D coef_x_AC = coef_x - DDX(C2coef_DC, location, DIFF_C2)/C1coefTimesD_DC; + Field3D coef_x_AC = coef_x - DDX(C2coef_DC, location, "C2")/C1coefTimesD_DC; // coef_z is a z-derivative so must already have zero DC component @@ -241,7 +241,7 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { delp2solver->setCoefC2(C2coef_DC); // Use this below to normalize error for relative error estimate - BoutReal RMS_rhsOverD = sqrt(mean(SQ(rhsOverD), true, RGN_NOBNDRY)); // use sqrt(mean(SQ)) to make sure we do not divide by zero at a point + BoutReal RMS_rhsOverD = sqrt(mean(SQ(rhsOverD), true, "RGN_NOBNDRY")); // use sqrt(mean(SQ)) to make sure we do not divide by zero at a point BoutReal error_rel = 1e20, error_abs=1e20, last_error=error_abs; int count = 0; @@ -250,8 +250,8 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { auto calc_b_guess = [&] (const Field3D& x_in) { // Derivatives of x - Field3D ddx_x = DDX(x_in, location, DIFF_C2); - Field3D ddz_x = DDZ(x_in, location, DIFF_FFT); + Field3D ddx_x = DDX(x_in, location, "C2"); + Field3D ddz_x = DDZ(x_in, location, "FFT"); return rhsOverD - (coords->g11*coef_x_AC*ddx_x + coords->g33*coef_z*ddz_x + coords->g13*(coef_x_AC*ddz_x + coef_z*ddx_x)) - AOverD_AC*x_in; }; @@ -282,7 +282,7 @@ const Field3D LaplaceNaulin::solve(const Field3D &rhs, const Field3D &x0) { Field3D bnew = calc_b_guess(b_x_pair.second); Field3D error3D = b_x_pair.first - bnew; - error_abs = max(abs(error3D, RGN_NOBNDRY), true, RGN_NOBNDRY); + error_abs = max(abs(error3D, "RGN_NOBNDRY"), true, "RGN_NOBNDRY"); error_rel = error_abs / RMS_rhsOverD; if (error_rel>(); @@ -207,6 +207,6 @@ const Field3D InvertParCR::solve(const Field3D &f) { irfft(&rhs(y, 0), localmesh->LocalNz, result(x, y + localmesh->ystart - y0)); } - return fromFieldAligned(result, RGN_NOBNDRY); + return fromFieldAligned(result, "RGN_NOBNDRY"); } diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index a07f286de5..2fbf05c371 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -31,7 +31,7 @@ Field2D interpolateAndExtrapolate(const Field2D& f, CELL_LOC location, bool no_extra_interpolate = false) { Mesh* localmesh = f.getMesh(); - Field2D result = interp_to(f, location, RGN_NOBNDRY); + Field2D result = interp_to(f, location, "RGN_NOBNDRY"); // Ensure result's data is unique. Otherwise result might be a duplicate of // f (if no interpolation is needed, e.g. if interpolation is in the // z-direction); then f would be communicated. Since this function is used @@ -275,16 +275,16 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) g23 = interpolateAndExtrapolate(g23, location, extrapolate_x, extrapolate_y); // Check input metrics - if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) - || (!finite(g33, RGN_NOBNDRY))) { + if ((!finite(g11, "RGN_NOBNDRY")) || (!finite(g22, "RGN_NOBNDRY")) + || (!finite(g33, "RGN_NOBNDRY"))) { throw BoutException("\tERROR: Diagonal metrics are not finite!\n"); } - if ((min(g11, RGN_NOBNDRY) <= 0.0) || (min(g22, RGN_NOBNDRY) <= 0.0) - || (min(g33, RGN_NOBNDRY) <= 0.0)) { + if ((min(g11, "RGN_NOBNDRY") <= 0.0) || (min(g22, "RGN_NOBNDRY") <= 0.0) + || (min(g33, "RGN_NOBNDRY") <= 0.0)) { throw BoutException("\tERROR: Diagonal metrics are negative!\n"); } - if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) - || (!finite(g23, RGN_NOBNDRY))) { + if ((!finite(g12, "RGN_NOBNDRY")) || (!finite(g13, "RGN_NOBNDRY")) + || (!finite(g23, "RGN_NOBNDRY"))) { throw BoutException("\tERROR: Off-diagonal metrics are not finite!\n"); } @@ -573,15 +573,15 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, } // Check input metrics - if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) - || (!finite(g33, RGN_NOBNDRY))) { + if ((!finite(g11, "RGN_NOBNDRY")) || (!finite(g22, "RGN_NOBNDRY")) + || (!finite(g33, "RGN_NOBNDRY"))) { throw BoutException("\tERROR: Staggered diagonal metrics are not finite!\n"); } if ((min(g11) <= 0.0) || (min(g22) <= 0.0) || (min(g33) <= 0.0)) { throw BoutException("\tERROR: Staggered diagonal metrics are negative!\n"); } - if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) - || (!finite(g23, RGN_NOBNDRY))) { + if ((!finite(g12, "RGN_NOBNDRY")) || (!finite(g13, "RGN_NOBNDRY")) + || (!finite(g23, "RGN_NOBNDRY"))) { throw BoutException("\tERROR: Staggered off-diagonal metrics are not finite!\n"); } @@ -642,27 +642,27 @@ int Coordinates::geometry(bool recalculate_staggered, throw BoutException("dz magnitude less than 1e-8"); // Check input metrics - if ((!finite(g11, RGN_NOBNDRY)) || (!finite(g22, RGN_NOBNDRY)) - || (!finite(g33, RGN_NOBNDRY))) { + if ((!finite(g11, "RGN_NOBNDRY")) || (!finite(g22, "RGN_NOBNDRY")) + || (!finite(g33, "RGN_NOBNDRY"))) { throw BoutException("\tERROR: Diagonal metrics are not finite!\n"); } if ((min(g11) <= 0.0) || (min(g22) <= 0.0) || (min(g33) <= 0.0)) { throw BoutException("\tERROR: Diagonal metrics are negative!\n"); } - if ((!finite(g12, RGN_NOBNDRY)) || (!finite(g13, RGN_NOBNDRY)) - || (!finite(g23, RGN_NOBNDRY))) { + if ((!finite(g12, "RGN_NOBNDRY")) || (!finite(g13, "RGN_NOBNDRY")) + || (!finite(g23, "RGN_NOBNDRY"))) { throw BoutException("\tERROR: Off-diagonal metrics are not finite!\n"); } - if ((!finite(g_11, RGN_NOBNDRY)) || (!finite(g_22, RGN_NOBNDRY)) - || (!finite(g_33, RGN_NOBNDRY))) { + if ((!finite(g_11, "RGN_NOBNDRY")) || (!finite(g_22, "RGN_NOBNDRY")) + || (!finite(g_33, "RGN_NOBNDRY"))) { throw BoutException("\tERROR: Diagonal g_ij metrics are not finite!\n"); } if ((min(g_11) <= 0.0) || (min(g_22) <= 0.0) || (min(g_33) <= 0.0)) { throw BoutException("\tERROR: Diagonal g_ij metrics are negative!\n"); } - if ((!finite(g_12, RGN_NOBNDRY)) || (!finite(g_13, RGN_NOBNDRY)) - || (!finite(g_23, RGN_NOBNDRY))) { + if ((!finite(g_12, "RGN_NOBNDRY")) || (!finite(g_13, "RGN_NOBNDRY")) + || (!finite(g_23, "RGN_NOBNDRY"))) { throw BoutException("\tERROR: Off-diagonal g_ij metrics are not finite!\n"); } @@ -1017,7 +1017,7 @@ int Coordinates::jacobian() { J = 1. / sqrt(g); // Check jacobian - if (!finite(J, RGN_NOBNDRY)) { + if (!finite(J, "RGN_NOBNDRY")) { throw BoutException("\tERROR: Jacobian not finite everywhere!\n"); } if (min(abs(J)) < 1.0e-10) { diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index e93f3176d3..a824364a78 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -287,7 +287,7 @@ const Field3D Grad_par_CtoL(const Field3D &var) { } } else { // No yup/ydown fields, so transform to cell centred - Field3D var_fa = toFieldAligned(var, RGN_NOX); + Field3D var_fa = toFieldAligned(var, "RGN_NOX"); for(int jx=0; jxLocalNx;jx++) { for(int jy=1;jyLocalNy;jy++) { @@ -297,7 +297,7 @@ const Field3D Grad_par_CtoL(const Field3D &var) { } } - result = fromFieldAligned(result, RGN_NOBNDRY); + result = fromFieldAligned(result, "RGN_NOBNDRY"); } return result; @@ -351,8 +351,8 @@ const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION reg // (even if one of v and f has yup/ydown fields, it doesn't make sense to // multiply them with one in field-aligned and one in non-field-aligned // coordinates) - Field3D v_fa = toFieldAligned(v, RGN_NOX); - Field3D f_fa = toFieldAligned(f, RGN_NOX); + Field3D v_fa = toFieldAligned(v, "RGN_NOX"); + Field3D f_fa = toFieldAligned(f, "RGN_NOX"); BOUT_OMP(parallel) { stencil fval, vval; @@ -396,12 +396,12 @@ const Field3D Grad_par_LtoC(const Field3D &var) { } else { // No yup/ydown field, so transform to field aligned - Field3D var_fa = toFieldAligned(var, RGN_NOX); + Field3D var_fa = toFieldAligned(var, "RGN_NOX"); BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { result[i] = (var_fa[i.yp()] - var_fa[i]) / (metric->dy[i]*sqrt(metric->g_22[i])); } - result = fromFieldAligned(result, RGN_NOBNDRY); + result = fromFieldAligned(result, "RGN_NOBNDRY"); } return result; diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index 36f372af52..32f84ab55a 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -174,8 +174,8 @@ namespace FV { bool use_parallel_slices = (Kin.hasParallelSlices() && fin.hasParallelSlices()); - const auto& K = use_parallel_slices ? Kin : toFieldAligned(Kin, RGN_NOX); - const auto& f = use_parallel_slices ? fin : toFieldAligned(fin, RGN_NOX); + const auto& K = use_parallel_slices ? Kin : toFieldAligned(Kin, "RGN_NOX"); + const auto& f = use_parallel_slices ? fin : toFieldAligned(fin, "RGN_NOX"); // K and f fields in yup and ydown directions const auto& Kup = use_parallel_slices ? Kin.yup() : K; @@ -221,7 +221,7 @@ namespace FV { if (!use_parallel_slices) { // Shifted to field aligned coordinates, so need to shift back - result = fromFieldAligned(result, RGN_NOBNDRY); + result = fromFieldAligned(result, "RGN_NOBNDRY"); } return result; @@ -237,8 +237,8 @@ namespace FV { Coordinates *coord = f_in.getCoordinates(); // Convert to field aligned coordinates - Field3D d = toFieldAligned(d_in, RGN_NOX); - Field3D f = toFieldAligned(f_in, RGN_NOX); + Field3D d = toFieldAligned(d_in, "RGN_NOX"); + Field3D f = toFieldAligned(f_in, "RGN_NOX"); for(int i=mesh->xstart;i<=mesh->xend;i++) for(int j=mesh->ystart;j<=mesh->yend;j++) { @@ -277,7 +277,7 @@ namespace FV { } // Convert result back to non-aligned coordinates - return fromFieldAligned(result, RGN_NOBNDRY); + return fromFieldAligned(result, "RGN_NOBNDRY"); } const Field3D D4DY4_Index(const Field3D &f_in, bool bndry_flux) { @@ -286,7 +286,7 @@ namespace FV { Mesh* mesh = f_in.getMesh(); // Convert to field aligned coordinates - Field3D f = toFieldAligned(f_in, RGN_NOX); + Field3D f = toFieldAligned(f_in, "RGN_NOX"); Coordinates *coord = f_in.getCoordinates(); @@ -387,7 +387,7 @@ namespace FV { } // Convert result back to non-aligned coordinates - return fromFieldAligned(result, RGN_NOBNDRY); + return fromFieldAligned(result, "RGN_NOBNDRY"); } void communicateFluxes(Field3D &f) { diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index 5a95076c0e..866f58c946 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -93,17 +93,17 @@ public: void integrateParallelSlices(Field3D &f) override; - const Field3D toFieldAligned(const Field3D &UNUSED(f), const REGION UNUSED(region)) override { + const Field3D toFieldAligned(const Field3D &UNUSED(f), const std::string& UNUSED(region) = "RGN_ALL") override { throw BoutException("FCI method cannot transform into field aligned grid"); } - const FieldPerp toFieldAligned(const FieldPerp &UNUSED(f), const REGION UNUSED(region)) override { + const FieldPerp toFieldAligned(const FieldPerp &UNUSED(f), const std::string& UNUSED(region) = "RGN_ALL") override { throw BoutException("FCI method cannot transform into field aligned grid"); } - const Field3D fromFieldAligned(const Field3D &UNUSED(f), const REGION UNUSED(region)) override { + const Field3D fromFieldAligned(const Field3D &UNUSED(f), const std::string& UNUSED(region) = "RGN_ALL") override { throw BoutException("FCI method cannot transform into field aligned grid"); } - const FieldPerp fromFieldAligned(const FieldPerp &UNUSED(f), const REGION UNUSED(region)) override { + const FieldPerp fromFieldAligned(const FieldPerp &UNUSED(f), const std::string& UNUSED(region) = "RGN_ALL") override { throw BoutException("FCI method cannot transform into field aligned grid"); } diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index f88a4ea06e..63a334e5be 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -124,7 +124,7 @@ void ShiftedMetric::cachePhases() { * Shift the field so that X-Z is not orthogonal, * and Y is then field aligned. */ -const Field3D ShiftedMetric::toFieldAligned(const Field3D& f, const REGION region) { +const Field3D ShiftedMetric::toFieldAligned(const Field3D& f, const std::string& region) { switch (f.getDirectionY()) { case (YDirectionType::Standard): return shiftZ(f, toAlignedPhs, YDirectionType::Aligned, region); @@ -138,7 +138,7 @@ const Field3D ShiftedMetric::toFieldAligned(const Field3D& f, const REGION regio return f; } } -const FieldPerp ShiftedMetric::toFieldAligned(const FieldPerp& f, const REGION region) { +const FieldPerp ShiftedMetric::toFieldAligned(const FieldPerp& f, const std::string& region) { switch (f.getDirectionY()) { case (YDirectionType::Standard): return shiftZ(f, toAlignedPhs, YDirectionType::Aligned, region); @@ -157,7 +157,7 @@ const FieldPerp ShiftedMetric::toFieldAligned(const FieldPerp& f, const REGION r * Shift back, so that X-Z is orthogonal, * but Y is not field aligned. */ -const Field3D ShiftedMetric::fromFieldAligned(const Field3D& f, const REGION region) { +const Field3D ShiftedMetric::fromFieldAligned(const Field3D& f, const std::string& region) { switch (f.getDirectionY()) { case (YDirectionType::Aligned): return shiftZ(f, fromAlignedPhs, YDirectionType::Standard, region); @@ -171,7 +171,7 @@ const Field3D ShiftedMetric::fromFieldAligned(const Field3D& f, const REGION reg return f; } } -const FieldPerp ShiftedMetric::fromFieldAligned(const FieldPerp& f, const REGION region) { +const FieldPerp ShiftedMetric::fromFieldAligned(const FieldPerp& f, const std::string& region) { switch (f.getDirectionY()) { case (YDirectionType::Aligned): return shiftZ(f, fromAlignedPhs, YDirectionType::Standard, region); @@ -188,7 +188,7 @@ const FieldPerp ShiftedMetric::fromFieldAligned(const FieldPerp& f, const REGION const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Tensor& phs, const YDirectionType y_direction_out, - const REGION region) const { + const std::string& region) const { ASSERT1(f.getMesh() == &mesh); ASSERT1(f.getLocation() == location); @@ -206,7 +206,7 @@ const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Tensor& ph const FieldPerp ShiftedMetric::shiftZ(const FieldPerp& f, const Tensor& phs, const YDirectionType y_direction_out, - const REGION UNUSED(region)) const { + const std::string& UNUSED(region)) const { ASSERT1(f.getMesh() == &mesh); ASSERT1(f.getLocation() == location); @@ -310,7 +310,7 @@ ShiftedMetric::shiftZ(const Field3D& f, // Old approach retained so we can still specify a general zShift const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Field2D& zangle, - const REGION region) const { + const std::string& region) const { ASSERT1(&mesh == f.getMesh()); ASSERT1(f.getLocation() == zangle.getLocation()); if (mesh.LocalNz == 1) diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index 43d984e534..7c03ee9d9f 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -112,7 +112,7 @@ TEST_F(Field3DInterpToTest, CellCentreToXlowNoBndry) { // CELL_CENTRE -> CELL_XLOW input.setLocation(CELL_CENTRE); - output = interp_to(input, CELL_XLOW, RGN_NOBNDRY); + output = interp_to(input, CELL_XLOW, "RGN_NOBNDRY"); EXPECT_TRUE(output.getLocation() == CELL_XLOW); EXPECT_NEAR(output(2, 2, 2), 1.95, 1.e-15); } @@ -134,7 +134,7 @@ TEST_F(Field3DInterpToTest, CellXlowToCentreNoBndry) { // CELL_XLOW -> CELL_CENTRE input.setLocation(CELL_XLOW); - output = interp_to(input, CELL_CENTRE, RGN_NOBNDRY); + output = interp_to(input, CELL_CENTRE, "RGN_NOBNDRY"); EXPECT_TRUE(output.getLocation() == CELL_CENTRE); EXPECT_NEAR(output(2, 2, 2), 1.65, 1.e-15); } @@ -156,7 +156,7 @@ TEST_F(Field3DInterpToTest, CellCentreToYlowNoBndry) { // CELL_CENTRE -> CELL_YLOW input.setLocation(CELL_CENTRE); - output = interp_to(input, CELL_YLOW, RGN_NOBNDRY); + output = interp_to(input, CELL_YLOW, "RGN_NOBNDRY"); EXPECT_TRUE(output.getLocation() == CELL_YLOW); EXPECT_NEAR(output(2, 2, 2), 2.825, 1.e-15); } @@ -178,7 +178,7 @@ TEST_F(Field3DInterpToTest, CellYlowToCentreNoBndry) { // CELL_YLOW -> CELL_CENTRE input.setLocation(CELL_YLOW); - output = interp_to(input, CELL_CENTRE, RGN_NOBNDRY); + output = interp_to(input, CELL_CENTRE, "RGN_NOBNDRY"); EXPECT_TRUE(output.getLocation() == CELL_CENTRE); EXPECT_NEAR(output(2, 2, 2), 2.525, 1.e-15); } @@ -200,7 +200,7 @@ TEST_F(Field3DInterpToTest, CellCentreToZlowNoBndry) { // CELL_CENTRE -> CELL_ZLOW input.setLocation(CELL_CENTRE); - output = interp_to(input, CELL_ZLOW, RGN_NOBNDRY); + output = interp_to(input, CELL_ZLOW, "RGN_NOBNDRY"); EXPECT_TRUE(output.getLocation() == CELL_ZLOW); EXPECT_NEAR(output(2, 2, 2), 3.7, 1.e-15); } @@ -222,7 +222,7 @@ TEST_F(Field3DInterpToTest, CellZlowToCentreNoBndry) { // CELL_XLOW -> CELL_CENTRE input.setLocation(CELL_ZLOW); - output = interp_to(input, CELL_CENTRE, RGN_NOBNDRY); + output = interp_to(input, CELL_CENTRE, "RGN_NOBNDRY"); EXPECT_TRUE(output.getLocation() == CELL_CENTRE); EXPECT_NEAR(output(2, 2, 2), 3.4, 1.e-15); } diff --git a/tests/unit/mesh/test_paralleltransform.cxx b/tests/unit/mesh/test_paralleltransform.cxx index 8141eec363..8085107572 100644 --- a/tests/unit/mesh/test_paralleltransform.cxx +++ b/tests/unit/mesh/test_paralleltransform.cxx @@ -46,7 +46,7 @@ TEST_F(ParallelTransformTest, IdentityToFieldAligned) { Field3D field{1.0}; - Field3D result = transform.toFieldAligned(field, RGN_ALL); + Field3D result = transform.toFieldAligned(field, "RGN_ALL"); EXPECT_TRUE(IsFieldEqual(result, 1.0)); EXPECT_TRUE(result.getDirectionY() == YDirectionType::Aligned); @@ -59,7 +59,7 @@ TEST_F(ParallelTransformTest, IdentityFromFieldAligned) { Field3D field{1.0}; field.setDirectionY(YDirectionType::Aligned); - Field3D result = transform.fromFieldAligned(field, RGN_ALL); + Field3D result = transform.fromFieldAligned(field, "RGN_ALL"); EXPECT_TRUE(IsFieldEqual(result, 1.0)); EXPECT_TRUE(result.getDirectionY() == YDirectionType::Standard); @@ -72,7 +72,7 @@ TEST_F(ParallelTransformTest, IdentityToFieldAlignedFieldPerp) { FieldPerp field{1.0}; field.setIndex(2); - FieldPerp result = transform.toFieldAligned(field, RGN_ALL); + FieldPerp result = transform.toFieldAligned(field, "RGN_ALL"); EXPECT_TRUE(IsFieldEqual(result, 1.0)); EXPECT_TRUE(result.getDirectionY() == YDirectionType::Aligned); @@ -86,7 +86,7 @@ TEST_F(ParallelTransformTest, IdentityFromFieldAlignedFieldPerp) { field.setIndex(2); field.setDirectionY(YDirectionType::Aligned); - FieldPerp result = transform.fromFieldAligned(field, RGN_ALL); + FieldPerp result = transform.fromFieldAligned(field, "RGN_ALL"); EXPECT_TRUE(IsFieldEqual(result, 1.0)); EXPECT_TRUE(result.getDirectionY() == YDirectionType::Standard); From fd94f1b5caff52a603a23977698e6500da607043 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 16 May 2019 21:33:05 +0100 Subject: [PATCH 1440/1783] Replace REGION enum with std::string in derivatives Provide deprecated overloads for REGION enum (and also for DIFF_METHOD enum). Do this in derivs.hxx with a couple of macros - reduces boiler-plate code since all the functions have the same signature apart from the function name. --- include/bout/coordinates.hxx | 15 +- include/bout/deriv_store.hxx | 4 +- include/bout/index_derivs.hxx | 4 +- include/bout/index_derivs_interface.hxx | 58 +-- include/derivs.hxx | 368 +++++++----------- include/difops.hxx | 9 +- src/mesh/coordinates.cxx | 6 +- src/mesh/difops.cxx | 2 +- src/mesh/index_derivs.cxx | 28 +- src/mesh/interpolation/hermite_spline.cxx | 2 +- .../monotonic_hermite_spline.cxx | 2 +- src/sys/derivs.cxx | 143 ++++--- tests/unit/include/bout/test_deriv_store.cxx | 8 +- tests/unit/include/test_derivs.cxx | 8 +- 14 files changed, 308 insertions(+), 349 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index 48e8d5725c..83b89b165c 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -140,23 +140,26 @@ public: /////////////////////////////////////////////////////////// const Field2D DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); const Field2D DDX(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { + const std::string& region = "RGN_NOBNDRY") { return DDX(f, outloc, toString(method), region); }; const Field2D DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); const Field2D DDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { + const std::string& region = "RGN_NOBNDRY") { return DDY(f, outloc, toString(method), region); }; const Field2D DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); + const std::string& method = "DEFAULT", + const std::string& region = "RGN_NOBNDRY"); const Field2D DDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { + const std::string& region = "RGN_NOBNDRY") { return DDZ(f, outloc, toString(method), region); }; diff --git a/include/bout/deriv_store.hxx b/include/bout/deriv_store.hxx index ec0ae63eb3..15edf573c0 100644 --- a/include/bout/deriv_store.hxx +++ b/include/bout/deriv_store.hxx @@ -50,9 +50,9 @@ /// upwind and flux). template struct DerivativeStore { - using standardFunc = std::function; + using standardFunc = std::function; using flowFunc = - std::function; + std::function; using upwindFunc = flowFunc; using fluxFunc = flowFunc; diff --git a/include/bout/index_derivs.hxx b/include/bout/index_derivs.hxx index b43118429e..612c5b3b48 100644 --- a/include/bout/index_derivs.hxx +++ b/include/bout/index_derivs.hxx @@ -83,7 +83,7 @@ template class DerivativeType { public: template - void standard(const T& var, T& result, REGION region) const { + void standard(const T& var, T& result, const std::string& region) const { AUTO_TRACE(); ASSERT2(meta.derivType == DERIV::Standard || meta.derivType == DERIV::StandardSecond || meta.derivType == DERIV::StandardFourth) @@ -96,7 +96,7 @@ public: } template - void upwindOrFlux(const T& vel, const T& var, T& result, REGION region) const { + void upwindOrFlux(const T& vel, const T& var, T& result, const std::string& region) const { AUTO_TRACE(); ASSERT2(meta.derivType == DERIV::Upwind || meta.derivType == DERIV::Flux) ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 724e64d9f9..94934df214 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -43,7 +43,7 @@ namespace index { /// The main kernel used for all upwind and flux derivatives template T flowDerivative(const T& vel, const T& f, CELL_LOC outloc, const std::string& method, - REGION region) { + const std::string& region) { AUTO_TRACE(); // Checks @@ -108,7 +108,7 @@ T flowDerivative(const T& vel, const T& f, CELL_LOC outloc, const std::string& m /// The main kernel used for all standard derivatives template T standardDerivative(const T& f, CELL_LOC outloc, const std::string& method, - REGION region) { + const std::string& region) { AUTO_TRACE(); // Checks @@ -172,14 +172,14 @@ T standardDerivative(const T& f, CELL_LOC outloc, const std::string& method, ////////////// X DERIVATIVE ///////////////// template T DDX(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - REGION region = RGN_NOBNDRY) { + const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); return standardDerivative(f, outloc, method, region); } template T D2DX2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - REGION region = RGN_NOBNDRY) { + const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); return standardDerivative(f, outloc, method, region); @@ -187,7 +187,7 @@ T D2DX2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = template T D4DX4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - REGION region = RGN_NOBNDRY) { + const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); return standardDerivative(f, outloc, method, region); @@ -197,63 +197,63 @@ T D4DX4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = template T DDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - REGION region = RGN_NOBNDRY) { + const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); if (f.hasParallelSlices()) { ASSERT1(f.getDirectionY() == YDirectionType::Standard); return standardDerivative(f, outloc, method, region); } else { - const T f_aligned = toFieldAligned(f, RGN_NOX); + const T f_aligned = toFieldAligned(f, "RGN_NOX"); T result = standardDerivative(f_aligned, outloc, method, region); - return fromFieldAligned(result, region); + return fromFieldAligned(result, toString(region)); } } template T D2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - REGION region = RGN_NOBNDRY) { + const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); if (f.hasParallelSlices()) { ASSERT1(f.getDirectionY() == YDirectionType::Standard); return standardDerivative( f, outloc, method, region); } else { - const T f_aligned = toFieldAligned(f, RGN_NOX); + const T f_aligned = toFieldAligned(f, "RGN_NOX"); T result = standardDerivative( f_aligned, outloc, method, region); - return fromFieldAligned(result, region); + return fromFieldAligned(result, toString(region)); } } template T D4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - REGION region = RGN_NOBNDRY) { + const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); if (f.hasParallelSlices()) { ASSERT1(f.getDirectionY() == YDirectionType::Standard); return standardDerivative( f, outloc, method, region); } else { - const T f_aligned = toFieldAligned(f, RGN_NOX); + const T f_aligned = toFieldAligned(f, "RGN_NOX"); T result = standardDerivative( f_aligned, outloc, method, region); - return fromFieldAligned(result, region); + return fromFieldAligned(result, toString(region)); } } ////////////// Z DERIVATIVE ///////////////// template T DDZ(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - REGION region = RGN_NOBNDRY) { + const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); return standardDerivative(f, outloc, method, region); } template T D2DZ2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - REGION region = RGN_NOBNDRY) { + const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); return standardDerivative(f, outloc, method, region); @@ -261,7 +261,7 @@ T D2DZ2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = template T D4DZ4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - REGION region = RGN_NOBNDRY) { + const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); return standardDerivative(f, outloc, method, region); @@ -286,14 +286,14 @@ T D4DZ4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = template T VDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); return flowDerivative(vel, f, outloc, method, region); } template T FDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); return flowDerivative(vel, f, outloc, method, region); } @@ -302,7 +302,7 @@ T FDDX(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, template T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); const bool fHasParallelSlices = (f.hasParallelSlices()); const bool velHasParallelSlices = (vel.hasParallelSlices()); @@ -312,17 +312,17 @@ T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, return flowDerivative(vel, f, outloc, method, region); } else { - const T f_aligned = toFieldAligned(f, RGN_NOX); - const T vel_aligned = toFieldAligned(vel, RGN_NOX); + const T f_aligned = toFieldAligned(f, "RGN_NOX"); + const T vel_aligned = toFieldAligned(vel, "RGN_NOX"); T result = flowDerivative(vel_aligned, f_aligned, outloc, method, region); - return fromFieldAligned(result, region); + return fromFieldAligned(result, toString(region)); } } template T FDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); const bool fHasParallelSlices = (f.hasParallelSlices()); const bool velHasParallelSlices = (vel.hasParallelSlices()); @@ -332,11 +332,11 @@ T FDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, return flowDerivative(vel, f, outloc, method, region); } else { - const T f_aligned = toFieldAligned(f, RGN_NOX); - const T vel_aligned = toFieldAligned(vel, RGN_NOX); + const T f_aligned = toFieldAligned(f, "RGN_NOX"); + const T vel_aligned = toFieldAligned(vel, "RGN_NOX"); T result = flowDerivative(vel_aligned, f_aligned, outloc, method, region); - return fromFieldAligned(result, region); + return fromFieldAligned(result, toString(region)); } } @@ -344,14 +344,14 @@ T FDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, template T VDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); return flowDerivative(vel, f, outloc, method, region); } template T FDDZ(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY) { + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); return flowDerivative(vel, f, outloc, method, region); } diff --git a/include/derivs.hxx b/include/derivs.hxx index 93cdbc6a61..4031f4fd61 100644 --- a/include/derivs.hxx +++ b/include/derivs.hxx @@ -36,6 +36,46 @@ #include "bout_types.hxx" +#ifdef DERIV_FUNC_REGION_ENUM_TO_STRING +#error This utility macro should not clash with another one +#else +#define DERIV_FUNC_REGION_ENUM_TO_STRING(func, T) \ +[[gnu::deprecated("Please use #func(const #T& f, CELL_LOC outloc = CELL_DEFAULT, " \ + "const std::string& method = \"DEFAULT\", const std::string& region = \"RGN_ALL\") " \ + "instead")]] \ +inline const T func(const T& f, CELL_LOC outloc, const std::string& method, \ + REGION region) { \ + return func(f, outloc, method, toString(region)); \ +} \ +[[gnu::deprecated("Please use #func(const #T& f, CELL_LOC outloc = CELL_DEFAULT, " \ + "const std::string& method = \"DEFAULT\", const std::string& region = \"RGN_ALL\") " \ + "instead")]] \ +inline const T func(const T& f, CELL_LOC outloc, DIFF_METHOD method, \ + REGION region = RGN_NOBNDRY) { \ + return func(f, outloc, toString(method), toString(region)); \ +} +#endif + +#ifdef VDERIV_FUNC_REGION_ENUM_TO_STRING +#error This utility macro should not clash with another one +#else +#define VDERIV_FUNC_REGION_ENUM_TO_STRING(func, T, T1, T2) \ +[[gnu::deprecated("Please use #func(const #T1 v, const #T2& f, " \ + "CELL_LOC outloc = CELL_DEFAULT, const std::string& method = \"DEFAULT\", const " \ + "std::string& region = \"RGN_ALL\") instead")]] \ +inline const T func(const T1& v, const T2& f, CELL_LOC outloc, const std::string& method, \ + REGION region) { \ + return func(v, f, outloc, method, toString(region)); \ +} \ +[[gnu::deprecated("Please use #func(const #T& f, CELL_LOC outloc = CELL_DEFAULT, " \ + "const std::string& method = \"DEFAULT\", const std::string& region = \"RGN_ALL\") " \ + "instead")]] \ +inline const T func(const T1& v, const T2& f, CELL_LOC outloc, DIFF_METHOD method, \ + REGION region = RGN_NOBNDRY) { \ + return func(v, f, outloc, toString(method), toString(region)); \ +} +#endif + ////////// FIRST DERIVATIVES ////////// /// Calculate first partial derivative in X @@ -50,12 +90,9 @@ /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D DDX(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D DDX(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return DDX(f, outloc, toString(method), region); -}; +const Field3D DDX(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(DDX, Field3D) /// Calculate first partial derivative in X /// @@ -69,12 +106,9 @@ inline const Field3D DDX(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D DDX(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return DDX(f, outloc, toString(method), region); -}; +const Field2D DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(DDX, Field2D) /// Calculate first partial derivative in Y /// @@ -88,12 +122,9 @@ inline const Field2D DDX(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D DDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D DDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return DDY(f, outloc, toString(method), region); -}; +const Field3D DDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(DDY, Field3D) /// Calculate first partial derivative in Y /// @@ -107,12 +138,9 @@ inline const Field3D DDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D DDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return DDY(f, outloc, toString(method), region); -}; +const Field2D DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(DDY, Field2D) /// Calculate first partial derivative in Z /// @@ -126,12 +154,9 @@ inline const Field2D DDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D DDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D DDZ(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return DDZ(f, outloc, toString(method), region); -}; +const Field3D DDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(DDZ, Field3D) /// Calculate first partial derivative in Z /// @@ -145,12 +170,9 @@ inline const Field3D DDZ(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D DDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return DDZ(f, outloc, toString(method), region); -}; +const Field2D DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(DDZ, Field2D) /// Calculate first partial derivative in Z /// @@ -164,12 +186,9 @@ inline const Field2D DDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Vector3D DDZ(const Vector3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Vector3D DDZ(const Vector3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return DDZ(f, outloc, toString(method), region); -}; +const Vector3D DDZ(const Vector3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(DDZ, Vector3D) /// Calculate first partial derivative in Z /// @@ -183,12 +202,9 @@ inline const Vector3D DDZ(const Vector3D& f, CELL_LOC outloc, DIFF_METHOD method /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Vector2D DDZ(const Vector2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Vector2D DDZ(const Vector2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return DDZ(f, outloc, toString(method), region); -}; +const Vector2D DDZ(const Vector2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(DDZ, Vector2D) ////////// SECOND DERIVATIVES ////////// @@ -204,12 +220,9 @@ inline const Vector2D DDZ(const Vector2D& f, CELL_LOC outloc, DIFF_METHOD method /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DX2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D2DX2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DX2(f, outloc, toString(method), region); -}; +const Field3D D2DX2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D2DX2, Field3D) /// Calculate second partial derivative in X /// @@ -223,12 +236,9 @@ inline const Field3D D2DX2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DX2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D2DX2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DX2(f, outloc, toString(method), region); -}; +const Field2D D2DX2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D2DX2, Field2D) /// Calculate second partial derivative in Y /// @@ -242,12 +252,9 @@ inline const Field2D D2DX2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DY2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D2DY2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DY2(f, outloc, toString(method), region); -}; +const Field3D D2DY2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D2DY2, Field3D) /// Calculate second partial derivative in Y /// @@ -261,12 +268,9 @@ inline const Field3D D2DY2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DY2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D2DY2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DY2(f, outloc, toString(method), region); -}; +const Field2D D2DY2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D2DY2, Field2D) /// Calculate second partial derivative in Z /// @@ -280,12 +284,9 @@ inline const Field2D D2DY2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DZ2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D2DZ2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DZ2(f, outloc, toString(method), region); -}; +const Field3D D2DZ2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D2DZ2, Field3D) /// Calculate second partial derivative in Z /// @@ -299,12 +300,9 @@ inline const Field3D D2DZ2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DZ2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D2DZ2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DZ2(f, outloc, toString(method), region); -}; +const Field2D D2DZ2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D2DZ2, Field2D) ////////// FOURTH DERIVATIVES ////////// @@ -320,12 +318,9 @@ inline const Field2D D2DZ2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D4DX4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D4DX4(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D4DX4(f, outloc, toString(method), region); -}; +const Field3D D4DX4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D4DX4, Field3D) /// Calculate forth partial derivative in X /// @@ -339,12 +334,9 @@ inline const Field3D D4DX4(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D4DX4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D4DX4(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D4DX4(f, outloc, toString(method), region); -}; +const Field2D D4DX4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D4DX4, Field2D) /// Calculate forth partial derivative in Y /// @@ -358,12 +350,9 @@ inline const Field2D D4DX4(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D4DY4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D4DY4(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D4DY4(f, outloc, toString(method), region); -}; +const Field3D D4DY4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D4DY4, Field3D) /// Calculate forth partial derivative in Y /// @@ -377,12 +366,9 @@ inline const Field3D D4DY4(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D4DY4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D4DY4(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D4DY4(f, outloc, toString(method), region); -}; +const Field2D D4DY4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D4DY4, Field2D) /// Calculate forth partial derivative in Z /// @@ -396,12 +382,9 @@ inline const Field2D D4DY4(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D4DZ4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D4DZ4(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D4DZ4(f, outloc, toString(method), region); -}; +const Field3D D4DZ4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D4DZ4, Field3D) /// Calculate forth partial derivative in Z /// @@ -415,12 +398,9 @@ inline const Field3D D4DZ4(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D4DZ4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D4DZ4(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D4DZ4(f, outloc, toString(method), region); -}; +const Field2D D4DZ4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D4DZ4, Field2D) /// For terms of form v * grad(f) /// @@ -436,11 +416,8 @@ inline const Field2D D4DZ4(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D VDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D VDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDX(v, f, outloc, toString(method), region); -}; + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDX, Field3D, Field3D, Field3D) /// For terms of form v * grad(f) /// @@ -456,11 +433,8 @@ inline const Field3D VDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D VDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D VDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDX(v, f, outloc, toString(method), region); -}; + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDX, Field2D, Field2D, Field2D) /// For terms of form v * grad(f) /// @@ -476,11 +450,8 @@ inline const Field2D VDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D VDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D VDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDY(v, f, outloc, toString(method), region); -}; + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDY, Field3D, Field3D, Field3D) /// For terms of form v * grad(f) /// @@ -496,11 +467,8 @@ inline const Field3D VDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D VDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D VDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDY(v, f, outloc, toString(method), region); -}; + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDY, Field2D, Field2D, Field2D) /// For terms of form v * grad(f) /// @@ -516,11 +484,8 @@ inline const Field2D VDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D VDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D VDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDZ(v, f, outloc, toString(method), region); -}; + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDZ, Field3D, Field3D, Field3D) /// For terms of form v * grad(f) /// @@ -536,11 +501,8 @@ inline const Field3D VDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D VDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D VDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDZ(v, f, outloc, toString(method), region); -}; + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDZ, Field2D, Field2D, Field2D) /// For terms of form v * grad(f) /// @@ -556,11 +518,8 @@ inline const Field2D VDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D VDDZ(const Field3D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D VDDZ(const Field3D& v, const Field2D& f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return VDDZ(v, f, outloc, toString(method), region); -}; + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDZ, Field2D, Field3D, Field2D) /// for terms of form div(v * f) /// @@ -576,11 +535,8 @@ inline const Field2D VDDZ(const Field3D& v, const Field2D& f, CELL_LOC outloc, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D FDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D FDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return FDDX(v, f, outloc, toString(method), region); -}; + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDX, Field3D, Field3D, Field3D) /// for terms of form div(v * f) /// @@ -596,11 +552,8 @@ inline const Field3D FDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D FDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D FDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return FDDX(v, f, outloc, toString(method), region); -}; + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDX, Field2D, Field2D, Field2D) /// for terms of form div(v * f) /// @@ -616,11 +569,8 @@ inline const Field2D FDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D FDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D FDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return FDDY(v, f, outloc, toString(method), region); -}; + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDY, Field3D, Field3D, Field3D) /// for terms of form div(v * f) /// @@ -636,11 +586,8 @@ inline const Field3D FDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D FDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D FDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return FDDY(v, f, outloc, toString(method), region); -}; + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDY, Field2D, Field2D, Field2D) /// for terms of form div(v * f) /// @@ -656,11 +603,8 @@ inline const Field2D FDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field3D FDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D FDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return FDDZ(v, f, outloc, toString(method), region); -}; + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDZ, Field3D, Field3D, Field3D) /// for terms of form div(v * f) /// @@ -676,11 +620,8 @@ inline const Field3D FDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc, /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY const Field2D FDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D FDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc, - DIFF_METHOD method, REGION region = RGN_NOBNDRY) { - return FDDZ(v, f, outloc, toString(method), region); -}; + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDZ, Field2D, Field2D, Field2D) /// Calculate mixed partial derivative in x and y /// @@ -694,12 +635,9 @@ inline const Field2D FDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc, /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DXDY(f, outloc, toString(method), region); -}; +const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D2DXDY, Field3D) /// Calculate mixed partial derivative in x and y /// @@ -713,12 +651,9 @@ inline const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD metho /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DXDY(f, outloc, toString(method), region); -}; +const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D2DXDY, Field2D) /// Calculate mixed partial derivative in x and z /// @@ -732,12 +667,9 @@ inline const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD metho /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DXDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D2DXDZ(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DXDZ(f, outloc, toString(method), region); -}; +const Field3D D2DXDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D2DXDZ, Field3D) /// Calculate mixed partial derivative in x and z /// @@ -751,12 +683,9 @@ inline const Field3D D2DXDZ(const Field3D& f, CELL_LOC outloc, DIFF_METHOD metho /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DXDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D2DXDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DXDZ(f, outloc, toString(method), region); -}; +const Field2D D2DXDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D2DXDZ, Field2D) /// Calculate mixed partial derivative in y and z /// @@ -770,12 +699,9 @@ inline const Field2D D2DXDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD metho /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DYDZ(f, outloc, toString(method), region); -}; +const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D2DYDZ, Field3D) /// Calculate mixed partial derivative in y and z /// @@ -789,11 +715,11 @@ inline const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, DIFF_METHOD metho /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DYDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", REGION region = RGN_NOBNDRY); -inline const Field2D D2DYDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - REGION region = RGN_NOBNDRY) { - return D2DYDZ(f, outloc, toString(method), region); -}; +const Field2D D2DYDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& + method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); +DERIV_FUNC_REGION_ENUM_TO_STRING(D2DYDZ, Field2D) + +#undef DERIV_FUNC_REGION_ENUM_TO_STRING +#undef VDERIV_FUNC_REGION_ENUM_TO_STRING #endif // __DERIVS_H__ diff --git a/include/difops.hxx b/include/difops.hxx index 5578cb3b1b..094c036daa 100644 --- a/include/difops.hxx +++ b/include/difops.hxx @@ -223,7 +223,14 @@ inline const Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD m */ const Field3D Grad_par_CtoL(const Field3D &var); const Field2D Grad_par_CtoL(const Field2D &var); -const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION region=RGN_NOBNDRY); +const Field3D Vpar_Grad_par_LCtoC(const Field3D& v, const Field3D& f, + const std::string& region="RGN_NOBNDRY"); +[[gnu::deprecated("Please use Field3D Vpar_Grad_par_LCtoC(const Field3D& v, " \ + "const Field3D &f, const std::string& region = \"RGN_NOBNDRY\") instead")]] \ +inline const Field3D Vpar_Grad_par_LCtoC(const Field3D& v, const Field3D& f, + REGION region=RGN_NOBNDRY) { + return Vpar_Grad_par_LCtoC(v, f, toString(region)); +} const Field3D Grad_par_LtoC(const Field3D &var); const Field2D Grad_par_LtoC(const Field2D &var); const Field3D Div_par_LtoC(const Field3D &var); diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 2fbf05c371..9e916d63b1 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -1122,19 +1122,19 @@ void Coordinates::setParallelTransform(Options* options) { *******************************************************************************/ const Field2D Coordinates::DDX(const Field2D& f, CELL_LOC loc, const std::string& method, - REGION region) { + const std::string& region) { ASSERT1(location == loc || loc == CELL_DEFAULT); return bout::derivatives::index::DDX(f, loc, method, region) / dx; } const Field2D Coordinates::DDY(const Field2D& f, CELL_LOC loc, const std::string& method, - REGION region) { + const std::string& region) { ASSERT1(location == loc || loc == CELL_DEFAULT); return bout::derivatives::index::DDY(f, loc, method, region) / dy; } const Field2D Coordinates::DDZ(MAYBE_UNUSED(const Field2D& f), CELL_LOC loc, - const std::string& UNUSED(method), REGION UNUSED(region)) { + const std::string& UNUSED(method), const std::string& UNUSED(region)) { ASSERT1(location == loc || loc == CELL_DEFAULT); ASSERT1(f.getMesh() == localmesh); if (loc == CELL_DEFAULT) { diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index a824364a78..1f96e749ae 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -316,7 +316,7 @@ const Field2D Grad_par_CtoL(const Field2D &var) { } -const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, REGION region) { +const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, const std::string& region) { ASSERT1(v.getMesh() == f.getMesh()); ASSERT1(v.getLocation() == CELL_YLOW); ASSERT1(f.getLocation() == CELL_CENTRE); diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index a4f6f51577..0eebd182fb 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -413,7 +413,7 @@ REGISTER_FLUX_DERIVATIVE_STAGGERED(FDDX_U2_stag, "U2", 2, DERIV::Flux) { class FFTDerivativeType { public: template - void standard(const T& var, T& result, REGION region) const { + void standard(const T& var, T& result, const std::string& region) const { AUTO_TRACE(); ASSERT2(meta.derivType == DERIV::Standard) ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); @@ -422,11 +422,9 @@ class FFTDerivativeType { ASSERT2((std::is_base_of::value)); // Should never need to call this with Field2D - const auto region_str = toString(region); - // Only allow a whitelist of regions for now - ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" - || region_str == "RGN_NOX" || region_str == "RGN_NOY"); + ASSERT2(region == "RGN_ALL" || region == "RGN_NOBNDRY" + || region == "RGN_NOX" || region == "RGN_NOY"); auto* theMesh = var.getMesh(); @@ -454,7 +452,7 @@ class FFTDerivativeType { // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro // here, // but should be ok for now. - BOUT_FOR_INNER(i, theMesh->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, theMesh->getRegion2D(region)) { auto i3D = theMesh->ind2Dto3D(i, 0); rfft(&var[i3D], ncz, cv.begin()); // Forward FFT @@ -475,7 +473,7 @@ class FFTDerivativeType { template void upwindOrFlux(const T& UNUSED(vel), const T& UNUSED(var), T& UNUSED(result), - REGION UNUSED(region)) const { + const std::string& UNUSED(region)) const { AUTO_TRACE(); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); } @@ -485,7 +483,7 @@ class FFTDerivativeType { class FFT2ndDerivativeType { public: template - void standard(const T& var, T& result, REGION region) const { + void standard(const T& var, T& result, const std::string& region) const { AUTO_TRACE(); ASSERT2(meta.derivType == DERIV::StandardSecond); ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); @@ -494,11 +492,9 @@ class FFT2ndDerivativeType { ASSERT2((std::is_base_of::value)); // Should never need to call this with Field2D - const auto region_str = toString(region); - // Only allow a whitelist of regions for now - ASSERT2(region_str == "RGN_ALL" || region_str == "RGN_NOBNDRY" - || region_str == "RGN_NOX" || region_str == "RGN_NOY"); + ASSERT2(region == "RGN_ALL" || region == "RGN_NOBNDRY" + || region == "RGN_NOX" || region == "RGN_NOY"); auto* theMesh = var.getMesh(); @@ -519,7 +515,7 @@ class FFT2ndDerivativeType { // With this in mind we could perhaps avoid the use of the BOUT_FOR_INNER macro // here, // but should be ok for now. - BOUT_FOR_INNER(i, theMesh->getRegion2D(region_str)) { + BOUT_FOR_INNER(i, theMesh->getRegion2D(region)) { auto i3D = theMesh->ind2Dto3D(i, 0); rfft(&var[i3D], ncz, cv.begin()); // Forward FFT @@ -540,7 +536,7 @@ class FFT2ndDerivativeType { template void upwindOrFlux(const T& UNUSED(vel), const T& UNUSED(var), T& UNUSED(result), - REGION UNUSED(region)) const { + const std::string& UNUSED(region)) const { AUTO_TRACE(); throw BoutException("The FFT METHOD isn't available in upwind/Flux"); } @@ -556,13 +552,13 @@ produceCombinations, Set, class SplitFluxDerivativeType { public: template - void standard(const T&, T&, REGION) const { + void standard(const T&, T&, const std::string) const { AUTO_TRACE(); throw BoutException("The SPLIT method isn't available for standard"); } template - void upwindOrFlux(const T& vel, const T& var, T& result, REGION region) const { + void upwindOrFlux(const T& vel, const T& var, T& result, const std::string region) const { AUTO_TRACE(); // Split into an upwind and a central differencing part // d/dx(v*f) = v*d/dx(f) + f*d/dx(v) diff --git a/src/mesh/interpolation/hermite_spline.cxx b/src/mesh/interpolation/hermite_spline.cxx index 79d940c47b..c95c37ec77 100644 --- a/src/mesh/interpolation/hermite_spline.cxx +++ b/src/mesh/interpolation/hermite_spline.cxx @@ -121,7 +121,7 @@ Field3D HermiteSpline::interpolate(const Field3D &f) const { // coordinates Field3D fx = bout::derivatives::index::DDX(f, CELL_DEFAULT, "DEFAULT"); localmesh->communicateXZ(fx); - Field3D fz = bout::derivatives::index::DDZ(f, CELL_DEFAULT, "DEFAULT", RGN_ALL); + Field3D fz = bout::derivatives::index::DDZ(f, CELL_DEFAULT, "DEFAULT", "RGN_ALL"); localmesh->communicateXZ(fz); Field3D fxz = bout::derivatives::index::DDX(fz, CELL_DEFAULT, "DEFAULT"); localmesh->communicateXZ(fxz); diff --git a/src/mesh/interpolation/monotonic_hermite_spline.cxx b/src/mesh/interpolation/monotonic_hermite_spline.cxx index d0cbf380e4..102dfe5f94 100644 --- a/src/mesh/interpolation/monotonic_hermite_spline.cxx +++ b/src/mesh/interpolation/monotonic_hermite_spline.cxx @@ -37,7 +37,7 @@ Field3D MonotonicHermiteSpline::interpolate(const Field3D &f) const { // coordinates Field3D fx = bout::derivatives::index::DDX(f, CELL_DEFAULT, "DEFAULT"); localmesh->communicateXZ(fx); - Field3D fz = bout::derivatives::index::DDZ(f, CELL_DEFAULT, "DEFAULT", RGN_ALL); + Field3D fz = bout::derivatives::index::DDZ(f, CELL_DEFAULT, "DEFAULT", "RGN_ALL"); localmesh->communicateXZ(fz); Field3D fxz = bout::derivatives::index::DDX(fz, CELL_DEFAULT, "DEFAULT"); localmesh->communicateXZ(fxz); diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 5a889525f1..9a34e6d6bf 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -58,7 +58,8 @@ ////////////// X DERIVATIVE ///////////////// -const Field3D DDX(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D DDX(const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { Field3D result = bout::derivatives::index::DDX(f, outloc, method, region); Coordinates *coords = f.getCoordinates(outloc); result /= coords->dx; @@ -74,36 +75,41 @@ const Field3D DDX(const Field3D &f, CELL_LOC outloc, const std::string &method, return result; } -const Field2D DDX(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field2D DDX(const Field2D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return f.getCoordinates(outloc)->DDX(f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// -const Field3D DDY(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D DDY(const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::DDY(f, outloc, method, region) / f.getCoordinates(outloc)->dy; } -const Field2D DDY(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field2D DDY(const Field2D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return f.getCoordinates(outloc)->DDY(f, outloc, method, region); } ////////////// Z DERIVATIVE ///////////////// -const Field3D DDZ(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D DDZ(const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::DDZ(f, outloc, method, region) / f.getCoordinates(outloc)->dz; } -const Field2D DDZ(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), - REGION UNUSED(region)) { +const Field2D DDZ(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string + &UNUSED(method), const std::string& UNUSED(region)) { auto tmp = Field2D(0., f.getMesh()); tmp.setLocation(f.getLocation()); return tmp; } -const Vector3D DDZ(const Vector3D &v, CELL_LOC outloc, const std::string &method, REGION region) { +const Vector3D DDZ(const Vector3D &v, CELL_LOC outloc, const std::string &method, + const std::string& region) { Vector3D result(v.x.getMesh()); ASSERT2(v.x.getMesh()==v.y.getMesh()); @@ -131,8 +137,8 @@ const Vector3D DDZ(const Vector3D &v, CELL_LOC outloc, const std::string &method return result; } -const Vector2D DDZ(const Vector2D &v, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), - REGION UNUSED(region)) { +const Vector2D DDZ(const Vector2D &v, CELL_LOC UNUSED(outloc), const std::string + &UNUSED(method), const std::string& UNUSED(region)) { Vector2D result(v.x.getMesh()); result.covariant = v.covariant; @@ -153,7 +159,8 @@ const Vector2D DDZ(const Vector2D &v, CELL_LOC UNUSED(outloc), const std::string ////////////// X DERIVATIVE ///////////////// -const Field3D D2DX2(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D D2DX2(const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { Coordinates *coords = f.getCoordinates(outloc); Field3D result = @@ -171,7 +178,8 @@ const Field3D D2DX2(const Field3D &f, CELL_LOC outloc, const std::string &method return result; } -const Field2D D2DX2(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field2D D2DX2(const Field2D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { Coordinates *coords = f.getCoordinates(outloc); Field2D result = @@ -188,7 +196,8 @@ const Field2D D2DX2(const Field2D &f, CELL_LOC outloc, const std::string &method ////////////// Y DERIVATIVE ///////////////// -const Field3D D2DY2(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D D2DY2(const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { Coordinates *coords = f.getCoordinates(outloc); Field3D result = @@ -206,7 +215,8 @@ const Field3D D2DY2(const Field3D &f, CELL_LOC outloc, const std::string &method return result; } -const Field2D D2DY2(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field2D D2DY2(const Field2D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { Coordinates *coords = f.getCoordinates(outloc); Field2D result = @@ -222,13 +232,14 @@ const Field2D D2DY2(const Field2D &f, CELL_LOC outloc, const std::string &method ////////////// Z DERIVATIVE ///////////////// -const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::D2DZ2(f, outloc, method, region) / SQ(f.getCoordinates(outloc)->dz); } const Field2D D2DZ2(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), - REGION UNUSED(region)) { + const std::string& UNUSED(region)) { if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } @@ -239,32 +250,38 @@ const Field2D D2DZ2(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED * Fourth derivatives *******************************************************************************/ -const Field3D D4DX4(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D D4DX4(const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::D4DX4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dx)); } -const Field2D D4DX4(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field2D D4DX4(const Field2D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::D4DX4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dx)); } -const Field3D D4DY4(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D D4DY4(const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::D4DY4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dy)); } -const Field2D D4DY4(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field2D D4DY4(const Field2D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::D4DY4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dy)); } -const Field3D D4DZ4(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D D4DZ4(const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::D4DZ4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dz)); } -const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::D4DZ4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dz)); } @@ -280,8 +297,9 @@ const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, const std::string &method * * ** Applies Neumann boundary in Y, communicates */ -const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { - Field2D dfdy = DDY(f, outloc, method, RGN_NOY); +const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { + Field2D dfdy = DDY(f, outloc, method, "RGN_NOY"); f.getMesh()->communicate(dfdy); return DDX(dfdy, outloc, method, region); } @@ -293,14 +311,15 @@ const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, const std::string &metho * * ** Applies Neumann boundary in Y, communicates */ -const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { - Field3D dfdy = DDY(f, outloc, method, RGN_NOY); +const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { + Field3D dfdy = DDY(f, outloc, method, "RGN_NOY"); f.getMesh()->communicate(dfdy); return DDX(dfdy, outloc, method, region); } -const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc, - const std::string &UNUSED(method), REGION UNUSED(region)) { +const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), + const std::string& UNUSED(region)) { if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } @@ -308,7 +327,8 @@ const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc, } /// X-Z mixed derivative -const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { // Take derivative in Z, including in X boundaries. Then take derivative in X // Maybe should average results of DDX(DDZ) and DDZ(DDX)? ASSERT1(outloc == CELL_DEFAULT || outloc == f.getLocation()); @@ -316,31 +336,28 @@ const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, const std::string &metho // Therefore we need to add the X boundary to the inner derivative // RGN_NOY and RGN_NOZ include the X boundary, therefore we need to // throw - or add communication code. - REGION region_inner; - switch (region){ - case RGN_NOBNDRY: - region_inner = RGN_NOY; - break; - case RGN_NOX: - region_inner = RGN_ALL; - break; - default: + std::string region_inner; + if (region == "RGN_NOBNDRY") { + region_inner = "RGN_NOY"; + } else if (region == "RGN_NOX") { + region_inner = "RGN_ALL"; + } else { throw BoutException("Unhandled region case in D2DXDZ"); } return DDX(DDZ(f, outloc,method, region_inner),outloc,method,region);; } -const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc, - const std::string &UNUSED(method), REGION UNUSED(region)) { +const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), + const std::string& UNUSED(region)) { if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } return zeroFrom(f).setLocation(outloc); } -const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, - MAYBE_UNUSED(const std::string& method), REGION UNUSED(region)) { +const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, MAYBE_UNUSED(const std::string& + method), const std::string& UNUSED(region)) { Coordinates *coords = f.getCoordinates(outloc); Field3D result{emptyFrom(f)}; @@ -376,13 +393,15 @@ const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, ////////////// X DERIVATIVE ///////////////// /// Special case where both arguments are 2D. Output location ignored for now -const Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::VDDX(v, f, outloc, method, region) / f.getCoordinates(outloc)->dx; } /// General version for 2 or 3-D objects -const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::VDDX(v, f, outloc, method, region) / f.getCoordinates(outloc)->dx; } @@ -390,13 +409,15 @@ const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const st ////////////// Y DERIVATIVE ///////////////// // special case where both are 2D -const Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::VDDY(v, f, outloc, method, region) / f.getCoordinates(outloc)->dy; } // general case -const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::VDDY(v, f, outloc, method, region) / f.getCoordinates(outloc)->dy; } @@ -404,8 +425,8 @@ const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const st ////////////// Z DERIVATIVE ///////////////// // special case where both are 2D -const Field2D VDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, - const std::string &UNUSED(method), REGION UNUSED(region)) { +const Field2D VDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const + std::string &UNUSED(method), const std::string& UNUSED(region)) { if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } @@ -413,8 +434,8 @@ const Field2D VDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, } // Note that this is zero because no compression is included -const Field2D VDDZ(const Field3D &UNUSED(v), const Field2D &f, CELL_LOC outloc, - const std::string &UNUSED(method), REGION UNUSED(region)) { +const Field2D VDDZ(const Field3D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const + std::string &UNUSED(method), const std::string& UNUSED(region)) { if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } @@ -422,7 +443,8 @@ const Field2D VDDZ(const Field3D &UNUSED(v), const Field2D &f, CELL_LOC outloc, } // general case -const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::VDDZ(v, f, outloc, method, region) / f.getCoordinates(outloc)->dz; } @@ -430,39 +452,44 @@ const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const st /******************************************************************************* * Flux conserving schemes *******************************************************************************/ -const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::FDDX(v, f, outloc, method, region) / f.getCoordinates(outloc)->dx; } -const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::FDDX(v, f, outloc, method, region) / f.getCoordinates(outloc)->dx; } ///////////////////////////////////////////////////////////////////////// -const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::FDDY(v, f, outloc, method, region) / f.getCoordinates(outloc)->dy; } -const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::FDDY(v, f, outloc, method, region) / f.getCoordinates(outloc)->dy; } ///////////////////////////////////////////////////////////////////////// -const Field2D FDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, - const std::string &UNUSED(method), REGION UNUSED(region)) { +const Field2D FDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const + std::string &UNUSED(method), const std::string& UNUSED(region)) { if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); } return zeroFrom(f).setLocation(outloc); } -const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, REGION region) { +const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, + const std::string& region) { return bout::derivatives::index::FDDZ(v, f, outloc, method, region) / f.getCoordinates(outloc)->dz; } diff --git a/tests/unit/include/bout/test_deriv_store.cxx b/tests/unit/include/bout/test_deriv_store.cxx index bb815cb2ad..5e96dce2e0 100644 --- a/tests/unit/include/bout/test_deriv_store.cxx +++ b/tests/unit/include/bout/test_deriv_store.cxx @@ -14,12 +14,12 @@ using standardType = DerivativeStore::standardFunc; using flowType = DerivativeStore::upwindFunc; void standardReturnTenSetToOne(const FieldType& UNUSED(inp), FieldType& out, - const REGION = RGN_ALL) { + const std::string& = "RGN_ALL") { out.resize(10, 1.0); } void flowReturnSixSetToTwo(const FieldType& UNUSED(vel), const FieldType& UNUSED(inp), - FieldType& out, const REGION = RGN_ALL) { + FieldType& out, const std::string& = "RGN_ALL") { out.resize(6, 2.0); } @@ -250,7 +250,7 @@ TEST_F(DerivativeStoreTest, RegisterStandardAndGetBack) { standardReturnTenSetToOne({}, outOrig); FieldType outRet; - returned(inOrig, outRet, RGN_ALL); + returned(inOrig, outRet, "RGN_ALL"); EXPECT_EQ(outOrig.size(), 10); ASSERT_EQ(outRet.size(), outOrig.size()); @@ -278,7 +278,7 @@ TEST_F(DerivativeStoreTest, RegisterFlowAndGetBack) { flowReturnSixSetToTwo(inOrig, inOrig, outOrig); FieldType outRet; - returned(inOrig, inOrig, outRet, RGN_ALL); + returned(inOrig, inOrig, outRet, "RGN_ALL"); EXPECT_EQ(outOrig.size(), 6); ASSERT_EQ(outRet.size(), outOrig.size()); diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index 1832484dc9..e7b73acaae 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -75,18 +75,18 @@ class DerivativesTest nx = grid_size; dir = &Index::x; x_guards = 2; - region = RGN_NOX; + region = "RGN_NOX"; break; case DIRECTION::Y: ny = grid_size; dir = &Index::y; y_guards = 2; - region = RGN_NOY; + region = "RGN_NOY"; break; case DIRECTION::Z: nz = grid_size; dir = &Index::z; - region = RGN_ALL; + region = "RGN_ALL"; break; default: throw BoutException("bad direction"); @@ -154,7 +154,7 @@ class DerivativesTest Field3D expected; // Region not including the guard cells in current direction - REGION region; + std::string region; }; using DerivativesTestAdvection = DerivativesTest; From c87d98a41445f4315ffa510865b2208632a9e2be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 17 May 2019 16:48:05 +0100 Subject: [PATCH 1441/1783] fix nc-format --- src/fileio/impls/netcdf/nc_format.cxx | 37 +++++++++++++++------------ src/fileio/impls/netcdf/nc_format.hxx | 4 +-- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/fileio/impls/netcdf/nc_format.cxx b/src/fileio/impls/netcdf/nc_format.cxx index 58c9c877b7..461e3dd7e5 100644 --- a/src/fileio/impls/netcdf/nc_format.cxx +++ b/src/fileio/impls/netcdf/nc_format.cxx @@ -489,10 +489,13 @@ bool NcFormat::addVarFieldPerp(const string &name, bool repeat) { if (!(var = dataFile->get_var(name.c_str()))) { // Variable not in file, so add it. auto nc_float_type = lowPrecision ? ncFloat : ncDouble; - if (repeat) - var = dataFile->add_var(name.c_str(), nc_float_type, 3, {tDim, xDim, zDim}); - else - var = dataFile->add_var(name.c_str(), nc_float_type, 2, {xDim, zDim}); + if (repeat){ + const NcDim * dims[3] = {tDim, xDim, zDim}; + var = dataFile->add_var(name.c_str(), nc_float_type, 3, dims); + } else { + const NcDim * dims[2] = {xDim, zDim}; + var = dataFile->add_var(name.c_str(), nc_float_type, 2, dims); + } if(!var->is_valid()) { output_error.write("ERROR: NetCDF could not add FieldPerp '%s' to file '%s'\n", name.c_str(), fname); @@ -615,7 +618,7 @@ bool NcFormat::read_perp(BoutReal *data, const std::string& name, int lx, int lz NcVar *var; - if(!(var = dataFile->get_var(name))) { + if(!(var = dataFile->get_var(name.c_str()))) { return false; } @@ -745,7 +748,7 @@ bool NcFormat::write_perp(BoutReal *data, const std::string& name, int lx, int l return false; // Check for valid name - checkName(name); + checkName(name.c_str()); TRACE("NcFormat::write_perp(BoutReal)"); @@ -756,8 +759,8 @@ bool NcFormat::write_perp(BoutReal *data, const std::string& name, int lx, int l #endif NcVar *var; - if(!(var = dataFile->get_var(name))) { - output_error.write("ERROR: NetCDF BoutReal variable '%s' has not been added to file '%s'\n", name, fname); + if(!(var = dataFile->get_var(name.c_str()))) { + output_error.write("ERROR: NetCDF BoutReal variable '%s' has not been added to file '%s'\n", name.c_str(), fname); return false; } @@ -888,7 +891,7 @@ bool NcFormat::read_rec_perp(BoutReal *data, const std::string& name, int lx, in return false; // Check for valid name - checkName(name); + checkName(name.c_str()); // Create an error object so netCDF doesn't exit #ifdef NCDF_VERBOSE @@ -899,7 +902,7 @@ bool NcFormat::read_rec_perp(BoutReal *data, const std::string& name, int lx, in NcVar *var; - if(!(var = dataFile->get_var(name))) + if(!(var = dataFile->get_var(name.c_str()))) return false; // NOTE: Probably should do something here to check t0 @@ -1045,7 +1048,7 @@ bool NcFormat::write_rec_perp(BoutReal *data, const std::string& name, int lx, i return false; // Check the name - checkName(name); + checkName(name.c_str()); TRACE("NcFormat::write_rec_perp(BoutReal*)"); @@ -1058,12 +1061,12 @@ bool NcFormat::write_rec_perp(BoutReal *data, const std::string& name, int lx, i NcVar *var; // Try to find variable - if(!(var = dataFile->get_var(name))) { - output_error.write("ERROR: NetCDF BoutReal variable '%s' has not been added to file '%s'\n", name, fname); + if(!(var = dataFile->get_var(name.c_str()))) { + output_error.write("ERROR: NetCDF BoutReal variable '%s' has not been added to file '%s'\n", name.c_str(), fname); return false; }else { // Get record number - if(rec_nr.find(name) == rec_nr.end()) { + if(rec_nr.find(name.c_str()) == rec_nr.end()) { // Add to map rec_nr[name] = default_rec; } @@ -1072,7 +1075,7 @@ bool NcFormat::write_rec_perp(BoutReal *data, const std::string& name, int lx, i int t = rec_nr[name]; #ifdef NCDF_VERBOSE - output_info.write("INFO: NetCDF writing record %d of '%s' in '%s'\n",t, name, fname); + output_info.write("INFO: NetCDF writing record %d of '%s' in '%s'\n",t, name.c_str(), fname); #endif if(lowPrecision) { @@ -1190,8 +1193,8 @@ void NcFormat::setAttribute(const std::string &varname, const std::string &attrn int existing_att; if (getAttribute(varname, attrname, existing_att)) { if (value != existing_att) { - output_warn.write("Overwriting attribute '%s' of variable '%s' with '%d', was previously '%d'", - attrname.c_str(), varname.c_str(), value, existing_att); + output_warn.write("Overwriting attribute '%s' of variable '%s' with '%f', was previously '%d'", + attrname.c_str(), varname.c_str(), value, existing_att); } } // else: attribute does not exist, so just write it diff --git a/src/fileio/impls/netcdf/nc_format.hxx b/src/fileio/impls/netcdf/nc_format.hxx index b2986a0835..f8592eb599 100644 --- a/src/fileio/impls/netcdf/nc_format.hxx +++ b/src/fileio/impls/netcdf/nc_format.hxx @@ -112,13 +112,13 @@ class NcFormat : public DataFormat { bool read_rec(int *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; bool read_rec(BoutReal *var, const char *name, int lx = 1, int ly = 0, int lz = 0) override; bool read_rec(BoutReal *var, const std::string &name, int lx = 1, int ly = 0, int lz = 0) override; - bool read_perp(BoutReal *var, const std::string &name, int lx = 1, int lz = 0) override; + bool read_rec_perp(BoutReal *var, const std::string &name, int lx = 1, int lz = 0) override; bool write_rec(int *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(int *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(BoutReal *var, const char *name, int lx = 0, int ly = 0, int lz = 0) override; bool write_rec(BoutReal *var, const std::string &name, int lx = 0, int ly = 0, int lz = 0) override; - bool write_perp(BoutReal *var, const std::string &name, int lx = 0, int lz = 0) override; + bool write_rec_perp(BoutReal *var, const std::string &name, int lx = 0, int lz = 0) override; void setLowPrecision() override { lowPrecision = true; } From 24da0abf6be8c9fbab8183c323537cb72850052f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 20 May 2019 15:57:58 +0100 Subject: [PATCH 1442/1783] Restore missing checks of metric components Some checks had been removed and mistakenly not replaced with 'checkFinite' and 'checkPositive' versions. --- src/mesh/coordinates.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 01d70adb70..ed4b3be797 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -275,9 +275,18 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) g23 = interpolateAndExtrapolate(g23, location, extrapolate_x, extrapolate_y); // Check input metrics + // Diagonal metric components should be finite checkFinite(g11, "g11", "RGN_NOCORNERS"); checkFinite(g22, "g22", "RGN_NOCORNERS"); checkFinite(g33, "g33", "RGN_NOCORNERS"); + // Diagonal metric components should be positive + checkPositive(g11, "g11", "RGN_NOCORNERS"); + checkPositive(g22, "g22", "RGN_NOCORNERS"); + checkPositive(g33, "g33", "RGN_NOCORNERS"); + // Off-diagonal metric components should be finite + checkFinite(g12, "g12", "RGN_NOCORNERS"); + checkFinite(g13, "g13", "RGN_NOCORNERS"); + checkFinite(g23, "g23", "RGN_NOCORNERS"); /// Find covariant metric components auto covariant_component_names = {"g_11", "g_22", "g_33", "g_12", "g_13", "g_23"}; From eda4fb968b70e58fd91cbc3132d8e8db6695be02 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 20 May 2019 16:17:23 +0100 Subject: [PATCH 1443/1783] More checks in Coordinates::geometry Check that the covariant metric components are finite, and the diagonal components are positive. Check that the interpolated J and Bxy are finite and positive. --- src/mesh/coordinates.cxx | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index ed4b3be797..db77c6e87a 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -332,6 +332,20 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) g_13 = interpolateAndExtrapolate(g_13, location, extrapolate_x, extrapolate_y); g_23 = interpolateAndExtrapolate(g_23, location, extrapolate_x, extrapolate_y); + // Check covariant metrics + // Diagonal metric components should be finite + checkFinite(g_11, "g_11", "RGN_NOCORNERS"); + checkFinite(g_22, "g_22", "RGN_NOCORNERS"); + checkFinite(g_33, "g_33", "RGN_NOCORNERS"); + // Diagonal metric components should be positive + checkPositive(g_11, "g_11", "RGN_NOCORNERS"); + checkPositive(g_22, "g_22", "RGN_NOCORNERS"); + checkPositive(g_33, "g_33", "RGN_NOCORNERS"); + // Off-diagonal metric components should be finite + checkFinite(g_12, "g_12", "RGN_NOCORNERS"); + checkFinite(g_13, "g_13", "RGN_NOCORNERS"); + checkFinite(g_23, "g_23", "RGN_NOCORNERS"); + /// Calculate Jacobian and Bxy if (jacobian()) throw BoutException("Error in jacobian call"); @@ -572,6 +586,11 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, J = interpolateAndExtrapolate(coords_in->J, location); Bxy = interpolateAndExtrapolate(coords_in->J, location); + checkFinite(J, "The Jacobian", "RGN_NOCORNERS"); + checkPositive(J, "The Jacobian", "RGN_NOCORNERS"); + checkFinite(Bxy, "Bxy", "RGN_NOCORNERS"); + checkPositive(Bxy, "Bxy", "RGN_NOCORNERS"); + ShiftTorsion = interpolateAndExtrapolate(coords_in->ShiftTorsion, location); if (mesh->IncIntShear) { @@ -584,14 +603,23 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, checkFinite(g11, "g11", "RGN_NOCORNERS"); checkFinite(g22, "g22", "RGN_NOCORNERS"); checkFinite(g33, "g33", "RGN_NOCORNERS"); + checkFinite(g_11, "g_11", "RGN_NOCORNERS"); + checkFinite(g_22, "g_22", "RGN_NOCORNERS"); + checkFinite(g_33, "g_33", "RGN_NOCORNERS"); // Diagonal metric components should be positive checkPositive(g11, "g11", "RGN_NOCORNERS"); checkPositive(g22, "g22", "RGN_NOCORNERS"); checkPositive(g33, "g33", "RGN_NOCORNERS"); + checkPositive(g_11, "g_11", "RGN_NOCORNERS"); + checkPositive(g_22, "g_22", "RGN_NOCORNERS"); + checkPositive(g_33, "g_33", "RGN_NOCORNERS"); // Off-diagonal metric components should be finite checkFinite(g12, "g12", "RGN_NOCORNERS"); checkFinite(g13, "g13", "RGN_NOCORNERS"); checkFinite(g23, "g23", "RGN_NOCORNERS"); + checkFinite(g_12, "g_12", "RGN_NOCORNERS"); + checkFinite(g_13, "g_13", "RGN_NOCORNERS"); + checkFinite(g_23, "g_23", "RGN_NOCORNERS"); ////////////////////////////////////////////////////// /// Calculate Christoffel symbols. Needs communication From 2437a2c50a96b2d8ec75cef0177b43b77b6c5530 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 21 May 2019 12:25:48 +0100 Subject: [PATCH 1444/1783] Remove ODR-violation from tests (FakeGridDataSource defined twice) --- tests/unit/mesh/test_boutmesh.cxx | 40 +------------------------------ 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/tests/unit/mesh/test_boutmesh.cxx b/tests/unit/mesh/test_boutmesh.cxx index b391fca523..7924ea566f 100644 --- a/tests/unit/mesh/test_boutmesh.cxx +++ b/tests/unit/mesh/test_boutmesh.cxx @@ -5,45 +5,7 @@ #include "output.hxx" #include "unused.hxx" -class FakeGridDataSource : public GridDataSource { -public: - bool hasVar(const std::string& UNUSED(name)) override { return false; }; - bool get(Mesh* UNUSED(m), std::string& UNUSED(sval), - const std::string& UNUSED(name)) override { - return true; - }; - bool get(Mesh* UNUSED(m), int& UNUSED(ival), const std::string& UNUSED(name)) override { - return true; - }; - bool get(Mesh* UNUSED(m), BoutReal& UNUSED(rval), - const std::string& UNUSED(name)) override { - return true; - } - bool get(Mesh* UNUSED(m), Field2D& UNUSED(var), const std::string& UNUSED(name), - BoutReal UNUSED(def) = 0.0) override { - return true; - } - bool get(Mesh* UNUSED(m), Field3D& UNUSED(var), const std::string& UNUSED(name), - BoutReal UNUSED(def) = 0.0) override { - return true; - } - bool get(Mesh* UNUSED(m), FieldPerp& UNUSED(var), const std::string& UNUSED(name), - BoutReal UNUSED(def) = 0.0) override { - return true; - } - bool get(Mesh* UNUSED(m), std::vector& UNUSED(var), - const std::string& UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, - Direction UNUSED(dir) = GridDataSource::X) override { - return true; - } - bool get(Mesh* UNUSED(m), std::vector& UNUSED(var), - const std::string& UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, - Direction UNUSED(dir) = GridDataSource::X) override { - return true; - } - bool hasXBoundaryGuards(Mesh* UNUSED(m)) override { return false; } - bool hasYBoundaryGuards() override { return false; } -}; +#include "test_extras.hxx" TEST(BoutMeshTest, NullOptionsCheck) { // Temporarily turn off outputs to make test quiet From f1e409cfc196770c6784ccb844ebdfc76dfef14e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 25 Apr 2019 16:21:39 +0100 Subject: [PATCH 1445/1783] Add traits class to get types of function arguments --- include/utils.hxx | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/include/utils.hxx b/include/utils.hxx index fcc85a4a2b..92ca151563 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -82,6 +82,36 @@ typename _Unique_if::_Known_bound make_unique(Args&&...) = delete; #else using std::make_unique; #endif + +template +struct function_traits; + +/// Traits class to get the types of function arguments for function pointers +/// +/// Use like: +/// +// // A function signature we'd like to check: +/// using some_function = int(*)(int, double, std::string); +/// // Get the type of the first argument: +/// using first_argument_type = +/// bout::utils::function_traits::arg<1>::type; +/// // The following prints "true": +/// std::cout << std::boolalpha +/// << std::is_same::value; +/// +/// Adapted from https://stackoverflow.com/a/9065203/2043465 +template +struct function_traits { + /// Total number of arguments + static constexpr size_t nargs = sizeof...(Args); + + using result_type = R; + + template + struct arg { + using type = typename std::tuple_element>::type; + }; +}; } // namespace utils } // namespace bout From 659efb323622672e09a6039e0f47785acefd4cd7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 21 May 2019 14:58:07 +0100 Subject: [PATCH 1446/1783] Replace SUNDIALS int types with `function_traits` or sunindextype --- src/solver/impls/arkode/arkode.cxx | 7 ++++++- src/solver/impls/cvode/cvode.cxx | 7 ++++++- src/solver/impls/ida/ida.cxx | 6 +++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index 8518d1268c..a2f404304a 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -37,6 +37,7 @@ #include "output.hxx" #include "unused.hxx" #include "bout/mesh.hxx" +#include "utils.hxx" #if SUNDIALS_VERSION_MAJOR >= 4 #include @@ -65,7 +66,11 @@ class Field2D; #define ONE RCONST(1.0) #ifndef ARKODEINT -using ARKODEINT = int; +#if SUNDIALS_VERSION_MAJOR < 3 +using ARKODEINT = bout::utils::function_traits::arg<0>::type; +#else +using ARKODEINT = sunindextype; +#endif #endif static int arkode_rhs_explicit(BoutReal t, N_Vector u, N_Vector du, void* user_data); diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index d6ee3360e1..22a6c58622 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -36,6 +36,7 @@ #include "output.hxx" #include "unused.hxx" #include "bout/mesh.hxx" +#include "utils.hxx" #include @@ -60,7 +61,11 @@ class Field2D; #define ONE RCONST(1.0) #ifndef CVODEINT -using CVODEINT = int; +#if SUNDIALS_VERSION_MAJOR < 3 +using CVODEINT = bout::utils::function_traits::arg<0>::type; +#else +using CVODEINT = sunindextype; +#endif #endif static int cvode_rhs(BoutReal t, N_Vector u, N_Vector du, void* user_data); diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index 701c8597d2..abb5d8d983 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -56,7 +56,11 @@ #define ONE RCONST(1.0) #ifndef IDAINT -using IDAINT = int; +#if SUNDIALS_VERSION_MAJOR < 3 +using IDAINT = bout::utils::function_traits::arg<0>::type; +#else +using IDAINT = sunindextype; +#endif #endif static int idares(BoutReal t, N_Vector u, N_Vector du, N_Vector rr, void* user_data); From 69ba9488bf87172d078cd606deec7418a039749f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 21 May 2019 14:58:47 +0100 Subject: [PATCH 1447/1783] Remove autoconf macros for handling SUNDIALS integer types --- configure | 201 --------------------------------------------------- configure.ac | 15 +--- m4/bout.m4 | 34 --------- 3 files changed, 3 insertions(+), 247 deletions(-) diff --git a/configure b/configure index e73f0e405a..67e5ff5087 100755 --- a/configure +++ b/configure @@ -10800,73 +10800,6 @@ $as_echo "$as_me: => $module_upper solver enabled" >&6;} eval "`$as_echo "${module_upper}LIBS" | $as_tr_sh`=\"\$SUNDIALS_MODULE_LDFLAGS \$sundials_module_libs\"" eval "`$as_echo "${module_upper}INCS" | $as_tr_sh`=\"\$sundials_module_includes\"" - # Now we have successfully found the library, we need to determine - # whether $module_upper uses int or long. Try to compile a simple - # program to check - save_CXXFLAGS=$CXXFLAGS - { $as_echo "$as_me:${as_lineno-$LINENO}: \"checking $module_upper types...\"" >&5 -$as_echo "$as_me: \"checking $module_upper types...\"" >&6;} - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - - for sundials_int_type in int long; do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking $sundials_int_type" >&5 -$as_echo_n "checking $sundials_int_type... " >&6; } - eval sundials_type_name=`$as_echo "${module_upper}INT" | $as_tr_sh` - CXXFLAGS="$CXXFLAGS $sundials_module_includes -D$sundials_type_name=$sundials_int_type" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - - - #include - extern int ida_bbd_rhs(IDAINT, double, N_Vector, N_Vector, N_Vector, void *); - - -int -main () -{ -IDABBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, ida_bbd_rhs, nullptr); - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - sundials_int_type_found=yes -else - sundials_int_type_found=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sundials_int_type_found" >&5 -$as_echo "$sundials_int_type_found" >&6; } - if test "x$sundials_int_type_found" = "xyes"; then - break; - fi - CXXFLAGS=$save_CXXFLAGS - done - - if test "x$sundials_int_type_found" = "xno"; then : - - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "*** Cannot compile $module_upper with either long or int -See \`config.log' for more details" "$LINENO" 5; } - -fi - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - - # We can now add that macro definition to the compilation flags - CXXFLAGS="$save_CXXFLAGS -D$sundials_type_name=$sundials_int_type" - fi @@ -11389,73 +11322,6 @@ $as_echo "$as_me: => $module_upper solver enabled" >&6;} eval "`$as_echo "${module_upper}LIBS" | $as_tr_sh`=\"\$SUNDIALS_MODULE_LDFLAGS \$sundials_module_libs\"" eval "`$as_echo "${module_upper}INCS" | $as_tr_sh`=\"\$sundials_module_includes\"" - # Now we have successfully found the library, we need to determine - # whether $module_upper uses int or long. Try to compile a simple - # program to check - save_CXXFLAGS=$CXXFLAGS - { $as_echo "$as_me:${as_lineno-$LINENO}: \"checking $module_upper types...\"" >&5 -$as_echo "$as_me: \"checking $module_upper types...\"" >&6;} - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - - for sundials_int_type in int long; do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking $sundials_int_type" >&5 -$as_echo_n "checking $sundials_int_type... " >&6; } - eval sundials_type_name=`$as_echo "${module_upper}INT" | $as_tr_sh` - CXXFLAGS="$CXXFLAGS $sundials_module_includes -D$sundials_type_name=$sundials_int_type" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - - - #include - extern int cvode_bbd_rhs(CVODEINT, double, N_Vector, N_Vector, void *); - - -int -main () -{ -CVBBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, cvode_bbd_rhs, nullptr); - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - sundials_int_type_found=yes -else - sundials_int_type_found=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sundials_int_type_found" >&5 -$as_echo "$sundials_int_type_found" >&6; } - if test "x$sundials_int_type_found" = "xyes"; then - break; - fi - CXXFLAGS=$save_CXXFLAGS - done - - if test "x$sundials_int_type_found" = "xno"; then : - - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "*** Cannot compile $module_upper with either long or int -See \`config.log' for more details" "$LINENO" 5; } - -fi - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - - # We can now add that macro definition to the compilation flags - CXXFLAGS="$save_CXXFLAGS -D$sundials_type_name=$sundials_int_type" - fi @@ -11986,73 +11852,6 @@ $as_echo "$as_me: => $module_upper solver enabled" >&6;} eval "`$as_echo "${module_upper}LIBS" | $as_tr_sh`=\"\$SUNDIALS_MODULE_LDFLAGS \$sundials_module_libs\"" eval "`$as_echo "${module_upper}INCS" | $as_tr_sh`=\"\$sundials_module_includes\"" - # Now we have successfully found the library, we need to determine - # whether $module_upper uses int or long. Try to compile a simple - # program to check - save_CXXFLAGS=$CXXFLAGS - { $as_echo "$as_me:${as_lineno-$LINENO}: \"checking $module_upper types...\"" >&5 -$as_echo "$as_me: \"checking $module_upper types...\"" >&6;} - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - - for sundials_int_type in int long; do - { $as_echo "$as_me:${as_lineno-$LINENO}: checking $sundials_int_type" >&5 -$as_echo_n "checking $sundials_int_type... " >&6; } - eval sundials_type_name=`$as_echo "${module_upper}INT" | $as_tr_sh` - CXXFLAGS="$CXXFLAGS $sundials_module_includes -D$sundials_type_name=$sundials_int_type" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - - - #include - extern int arkode_bbd_rhs(ARKODEINT, double, N_Vector, N_Vector, void *); - - -int -main () -{ -ARKBBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, arkode_bbd_rhs, nullptr); - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - sundials_int_type_found=yes -else - sundials_int_type_found=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sundials_int_type_found" >&5 -$as_echo "$sundials_int_type_found" >&6; } - if test "x$sundials_int_type_found" = "xyes"; then - break; - fi - CXXFLAGS=$save_CXXFLAGS - done - - if test "x$sundials_int_type_found" = "xno"; then : - - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "*** Cannot compile $module_upper with either long or int -See \`config.log' for more details" "$LINENO" 5; } - -fi - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - - # We can now add that macro definition to the compilation flags - CXXFLAGS="$save_CXXFLAGS -D$sundials_type_name=$sundials_int_type" - fi diff --git a/configure.ac b/configure.ac index eee887b454..73127108e7 100644 --- a/configure.ac +++ b/configure.ac @@ -1027,10 +1027,7 @@ AS_IF([test "x$with_ida" != "x" && test "x$with_ida" != "xno"], [ #include #include extern void foo(N_Vector); - ], [IDACreate();], [ - #include - extern int ida_bbd_rhs(IDAINT, double, N_Vector, N_Vector, N_Vector, void *); - ], [IDABBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, ida_bbd_rhs, nullptr);]) + ], [IDACreate();]) ]) AS_IF([test "x$with_cvode" != "x" && test "x$with_cvode" != "xno"], [ @@ -1044,10 +1041,7 @@ AS_IF([test "x$with_cvode" != "x" && test "x$with_cvode" != "xno"], [ #else CVodeCreate(0, 0); #endif - ], [ - #include - extern int cvode_bbd_rhs(CVODEINT, double, N_Vector, N_Vector, void *); - ], [CVBBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, cvode_bbd_rhs, nullptr);]) + ]) ]) AS_IF([test "x$with_arkode" != "x" && test "x$with_arkode" != "xno"], [ @@ -1065,10 +1059,7 @@ AS_IF([test "x$with_arkode" != "x" && test "x$with_arkode" != "xno"], [ #else ARKodeCreate(); #endif - ], [ - #include - extern int arkode_bbd_rhs(ARKODEINT, double, N_Vector, N_Vector, void *); - ], [ARKBBDPrecInit(nullptr, 0, 0, 0, 0, 0, 0, arkode_bbd_rhs, nullptr);]) + ]) ]) ############################################################# diff --git a/m4/bout.m4 b/m4/bout.m4 index 4239f7670e..9b12a6f77c 100644 --- a/m4/bout.m4 +++ b/m4/bout.m4 @@ -171,8 +171,6 @@ AC_DEFUN([BOUT_CHECK_PRETTYFUNCTION], [ dnl First argument is lower case module name dnl Second argument is test program includes dnl Third argument is test program main body -dnl Fourth argument is includes for test program to determine the integer type -dnl Fifth argument is main body for test program to determine the integer type AC_DEFUN([BOUT_FIND_SUNDIALS_MODULE],[ dnl Slightly complicated as we have to deal with shell indirection @@ -293,36 +291,4 @@ $2 AS_VAR_SET([AS_TR_SH([BOUT_HAS_$module_upper])], [yes]) AS_VAR_SET([AS_TR_SH([${module_upper}LIBS])], ["$SUNDIALS_MODULE_LDFLAGS $sundials_module_libs"]) AS_VAR_SET([AS_TR_SH([${module_upper}INCS])], ["$sundials_module_includes"]) - - # Now we have successfully found the library, we need to determine - # whether $module_upper uses int or long. Try to compile a simple - # program to check - save_CXXFLAGS=$CXXFLAGS - AC_MSG_NOTICE(["checking $module_upper types..."]) - AC_LANG_PUSH([C++]) - - for sundials_int_type in int long; do - AC_MSG_CHECKING([$sundials_int_type]) - eval sundials_type_name=AS_TR_SH([${module_upper}INT]) - CXXFLAGS="$CXXFLAGS $sundials_module_includes -D$sundials_type_name=$sundials_int_type" - AC_COMPILE_IFELSE([ - AC_LANG_PROGRAM([ -$4 - ], [$5])], - [sundials_int_type_found=yes], - [sundials_int_type_found=no]) - AC_MSG_RESULT($sundials_int_type_found) - if test "x$sundials_int_type_found" = "xyes"; then - break; - fi - CXXFLAGS=$save_CXXFLAGS - done - - AS_IF([test "x$sundials_int_type_found" = "xno"], [ - AC_MSG_FAILURE([*** Cannot compile $module_upper with either long or int]) - ]) - AC_LANG_POP([C++]) - - # We can now add that macro definition to the compilation flags - CXXFLAGS="$save_CXXFLAGS -D$sundials_type_name=$sundials_int_type" ]) From 18b6c4d95135fdc0c35f9a373c9e57c9a9395328 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 21 May 2019 15:59:40 +0100 Subject: [PATCH 1448/1783] Provide function_traits::arg_t<0> for ease of use --- include/utils.hxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/utils.hxx b/include/utils.hxx index 92ca151563..13d14ca73b 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -111,6 +111,9 @@ struct function_traits { struct arg { using type = typename std::tuple_element>::type; }; + + template + using arg_t = typename arg::type; }; } // namespace utils } // namespace bout From 108be2867910c153443c6d70b300603242420f13 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 21 May 2019 16:00:19 +0100 Subject: [PATCH 1449/1783] Add some tests for function_traits This is a compile-time feature so tests use static_assert --- tests/unit/sys/test_utils.cxx | 66 +++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/unit/sys/test_utils.cxx b/tests/unit/sys/test_utils.cxx index a5e9d43b4b..426dc0fcd4 100644 --- a/tests/unit/sys/test_utils.cxx +++ b/tests/unit/sys/test_utils.cxx @@ -668,3 +668,69 @@ TEST(StringUtilitiesTest, StringTrimComments) { EXPECT_EQ("space ", trimComments(input, "#")); } + +namespace { +using function_typedef = int(*)(char, int, double); +int function_pointer(double, char) {return 0;}; +template +void function_template(T) {} +} // namespace + +TEST(FunctionTraitsTest, ResultType) { + using bout::utils::function_traits; + static_assert(std::is_same::result_type, int>::value, + "Wrong result_type for function_traits of a typedef"); + static_assert( + std::is_same::result_type, int>::value, + "Wrong result_type for function_traits of a function pointer"); + static_assert( + std::is_same)>::result_type, + void>::value, + "Wrong result_type for function_traits of a template function"); + + // Use foo to suppress warning + function_pointer(0, 0); +} + +TEST(FunctionTraitsTest, NumberOfArgs) { + using bout::utils::function_traits; + static_assert(function_traits::nargs == 3, + "Wrong number of arguments for function_traits of a typedef>"); + static_assert(function_traits::nargs == 2, + "Wrong number of arguments for function_traits of a function pointer"); + static_assert(function_traits)>::nargs == 1, + "Wrong number of arguments for function_traits of a template function"); +} + +TEST(FunctionTraitsTest, FirstArg) { + using bout::utils::function_traits; + static_assert( + std::is_same::arg<0>::type, char>::value, + "Wrong first argument type for function_traits of a typedef"); + static_assert(std::is_same::arg<0>::type, + double>::value, + "Wrong first argument type for function_traits of a function pointer"); + static_assert( + std::is_same)>::arg<0>::type, + int>::value, + "Wrong first argument type for function_traits of a template function"); + + static_assert(std::is_same::arg_t<0>, char>::value, + "Wrong first argument type for function_traits of a typedef using arg_t"); + static_assert( + std::is_same::arg_t<0>, double>::value, + "Wrong first argument type for function_traits of a function pointer using arg_t"); + static_assert( + std::is_same)>::arg_t<0>, + int>::value, + "Wrong first argument type for function_traits of a template function using arg_t"); +} + +TEST(FunctionTraitsTest, SecondArg) { + using bout::utils::function_traits; + static_assert(std::is_same::arg<1>::type, int>::value, + "Wrong second argument type for function_traits of a typedef"); + static_assert( + std::is_same::arg_t<1>, int>::value, + "Wrong second argument type for function_traits of a typedef using arg_t"); +} From 33077bdfc74328e0266c4e86e75047edec953b06 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 21 May 2019 16:03:18 +0100 Subject: [PATCH 1450/1783] Use function_traits::arg_t in SUNDIALS wrappers --- src/solver/impls/arkode/arkode.cxx | 2 +- src/solver/impls/cvode/cvode.cxx | 2 +- src/solver/impls/ida/ida.cxx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/solver/impls/arkode/arkode.cxx b/src/solver/impls/arkode/arkode.cxx index a2f404304a..d938825be2 100644 --- a/src/solver/impls/arkode/arkode.cxx +++ b/src/solver/impls/arkode/arkode.cxx @@ -67,7 +67,7 @@ class Field2D; #ifndef ARKODEINT #if SUNDIALS_VERSION_MAJOR < 3 -using ARKODEINT = bout::utils::function_traits::arg<0>::type; +using ARKODEINT = bout::utils::function_traits::arg_t<0>; #else using ARKODEINT = sunindextype; #endif diff --git a/src/solver/impls/cvode/cvode.cxx b/src/solver/impls/cvode/cvode.cxx index 22a6c58622..7b01615ae2 100644 --- a/src/solver/impls/cvode/cvode.cxx +++ b/src/solver/impls/cvode/cvode.cxx @@ -62,7 +62,7 @@ class Field2D; #ifndef CVODEINT #if SUNDIALS_VERSION_MAJOR < 3 -using CVODEINT = bout::utils::function_traits::arg<0>::type; +using CVODEINT = bout::utils::function_traits::arg_t<0>; #else using CVODEINT = sunindextype; #endif diff --git a/src/solver/impls/ida/ida.cxx b/src/solver/impls/ida/ida.cxx index abb5d8d983..665df2e34c 100644 --- a/src/solver/impls/ida/ida.cxx +++ b/src/solver/impls/ida/ida.cxx @@ -57,7 +57,7 @@ #ifndef IDAINT #if SUNDIALS_VERSION_MAJOR < 3 -using IDAINT = bout::utils::function_traits::arg<0>::type; +using IDAINT = bout::utils::function_traits::arg_t<0>; #else using IDAINT = sunindextype; #endif From fa830e53299b46c502ab529f5d633c33f82f68b5 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 21 May 2019 16:23:18 +0100 Subject: [PATCH 1451/1783] Don't specify boundary regions in D2DXDY It is correct to apply the boundary condition to all boundaries, even though y-boundaries are not needed. This avoids potential problems if the list of boundary regions changes, or is re-named, or is different in a new implementation of Mesh, etc. --- src/sys/derivs.cxx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index a5719a87e6..94c6a6bb02 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -291,9 +291,7 @@ const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, const std::string& metho // Set x-guard cells and x-boundary cells before calculating DDX f.getMesh()->communicate(dfdy); - dfdy.applyBoundary("core", dfdy_boundary_condition); - dfdy.applyBoundary("pf", dfdy_boundary_condition); - dfdy.applyBoundary("sol", dfdy_boundary_condition); + dfdy.applyBoundary(dfdy_boundary_condition); return DDX(dfdy, outloc, method, region); } @@ -316,9 +314,7 @@ const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, const std::string& metho // Set x-guard cells and x-boundary cells before calculating DDX f.getMesh()->communicate(dfdy); - dfdy.applyBoundary("core", dfdy_boundary_condition); - dfdy.applyBoundary("pf", dfdy_boundary_condition); - dfdy.applyBoundary("sol", dfdy_boundary_condition); + dfdy.applyBoundary(dfdy_boundary_condition); return DDX(dfdy, outloc, method, region); } From c9fbb6e57f22c6b855959cbd0fd2c999092893a0 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 21 May 2019 16:45:23 +0100 Subject: [PATCH 1452/1783] Remove Laplace3D --- include/bout/invert/laplace3d.hxx | 59 ------------------- src/invert/laplace3d/impls/emptylaplace3d.hxx | 21 ------- src/invert/laplace3d/impls/makefile | 6 -- src/invert/laplace3d/impls/petsc/makefile | 10 ---- .../laplace3d/impls/petsc/petsc_laplace3d.cxx | 21 ------- .../laplace3d/impls/petsc/petsc_laplace3d.hxx | 43 -------------- src/invert/laplace3d/laplace3d.cxx | 8 --- src/invert/laplace3d/laplace3d_factory.cxx | 34 ----------- src/invert/laplace3d/laplace3d_factory.hxx | 23 -------- src/invert/laplace3d/makefile | 9 --- tests/integrated/test-laplace3d/data/BOUT.inp | 12 ---- tests/integrated/test-laplace3d/makefile | 6 -- .../test-laplace3d/test_laplace3d.cxx | 25 -------- 13 files changed, 277 deletions(-) delete mode 100644 include/bout/invert/laplace3d.hxx delete mode 100644 src/invert/laplace3d/impls/emptylaplace3d.hxx delete mode 100644 src/invert/laplace3d/impls/makefile delete mode 100644 src/invert/laplace3d/impls/petsc/makefile delete mode 100644 src/invert/laplace3d/impls/petsc/petsc_laplace3d.cxx delete mode 100644 src/invert/laplace3d/impls/petsc/petsc_laplace3d.hxx delete mode 100644 src/invert/laplace3d/laplace3d.cxx delete mode 100644 src/invert/laplace3d/laplace3d_factory.cxx delete mode 100644 src/invert/laplace3d/laplace3d_factory.hxx delete mode 100644 src/invert/laplace3d/makefile delete mode 100644 tests/integrated/test-laplace3d/data/BOUT.inp delete mode 100644 tests/integrated/test-laplace3d/makefile delete mode 100644 tests/integrated/test-laplace3d/test_laplace3d.cxx diff --git a/include/bout/invert/laplace3d.hxx b/include/bout/invert/laplace3d.hxx deleted file mode 100644 index 2df37c6307..0000000000 --- a/include/bout/invert/laplace3d.hxx +++ /dev/null @@ -1,59 +0,0 @@ -class Laplace3D; - -#ifndef __LAPLACE3D_H__ -#define __LAPLACE3D_H__ - -/////////////////////////////////////////////////////////////////// -// Interface to 3D Laplacian solver -// -// Solves the following: -// -// A*x + B * Delp^2(x) + Div( C * Delp(x)) + D * Del^2(x) = rhs -// -// where Del^2 is the full 3D Laplacian -// Delp^2 is the full perpendicular Laplacian -// including Y derivatives -// -/////////////////////////////////////////////////////////////////// - -#include -#include -#include - -class Laplace3D { -public: - Laplace3D(Options *opt = nullptr) : flags(0) {} - virtual ~Laplace3D() {} - - virtual void setCoefA(const Field2D &f) = 0; - virtual void setCoefA(const Field3D &f) {setCoefA(DC(f));} - virtual void setCoefA(BoutReal f) {setCoefA(Field2D(f));} - - virtual void setCoefB(const Field2D &f) = 0; - virtual void setCoefB(const Field3D &f) {setCoefB(DC(f));} - virtual void setCoefB(BoutReal f) {setCoefB(Field2D(f));} - - virtual void setCoefC(const Field2D &f) = 0; - virtual void setCoefC(const Field3D &f) {setCoefC(DC(f));} - virtual void setCoefC(BoutReal f) {setCoefC(Field2D(f));} - - virtual void setCoefD(const Field2D &f) = 0; - virtual void setCoefD(const Field3D &f) {setCoefD(DC(f));} - virtual void setCoefD(BoutReal f) {setCoefD(Field2D(f));} - - virtual void setFlags(int f) {flags = f;} - - virtual const Field3D solve(const Field3D &b) = 0; - virtual const Field2D solve(const Field2D &b) {return solve(DC(Field3D(b)));} - - virtual const Field3D solve(const Field3D &b, const Field3D &x0) { return solve(b); } - virtual const Field2D solve(const Field2D &b, const Field2D &x0) { return solve(b); } - - static Laplace3D* create(Options *opt = nullptr); -protected: - int flags; - -}; - -#endif //__LAPLACE3D_H__ - diff --git a/src/invert/laplace3d/impls/emptylaplace3d.hxx b/src/invert/laplace3d/impls/emptylaplace3d.hxx deleted file mode 100644 index 4cfb27ab28..0000000000 --- a/src/invert/laplace3d/impls/emptylaplace3d.hxx +++ /dev/null @@ -1,21 +0,0 @@ - -#ifndef __EMPTYLAPLACE3D_H__ -#define __EMPTYLAPLACE3D_H__ - -#include -#include - -class EmptyLaplace3D : public Laplace3D { -public: - EmptyLaplace3D(Options *opt = nullptr) { - throw BoutException("Laplace3D solver not available"); - } - void setCoefA(const Field2D &f) {} - void setCoefB(const Field2D &f) {} - void setCoefC(const Field2D &f) {} - void setCoefD(const Field2D &f) {} - - const Field3D solve(const Field3D &b) {return b;} -}; - -#endif // __EMPTYLAPLACE3D_H__ diff --git a/src/invert/laplace3d/impls/makefile b/src/invert/laplace3d/impls/makefile deleted file mode 100644 index f63a3f8ac5..0000000000 --- a/src/invert/laplace3d/impls/makefile +++ /dev/null @@ -1,6 +0,0 @@ - -BOUT_TOP = ../../../.. - -DIRS = petsc - -include $(BOUT_TOP)/make.config diff --git a/src/invert/laplace3d/impls/petsc/makefile b/src/invert/laplace3d/impls/petsc/makefile deleted file mode 100644 index 5206784755..0000000000 --- a/src/invert/laplace3d/impls/petsc/makefile +++ /dev/null @@ -1,10 +0,0 @@ - -BOUT_TOP = ../../../../.. - -SOURCEC = petsc_laplace3d.cxx -SOURCEH = petsc_laplace3d.hxx -TARGET = lib - -CXXFLAGS +=-g - -include $(BOUT_TOP)/make.config diff --git a/src/invert/laplace3d/impls/petsc/petsc_laplace3d.cxx b/src/invert/laplace3d/impls/petsc/petsc_laplace3d.cxx deleted file mode 100644 index e0897a6f4d..0000000000 --- a/src/invert/laplace3d/impls/petsc/petsc_laplace3d.cxx +++ /dev/null @@ -1,21 +0,0 @@ - -#ifdef BOUT_HAS_PETSC - -#include "petsc_laplace3d.hxx" - -Laplace3DPetsc::Laplace3DPetsc(Options *opt) : Laplace3D(opt) { - // Get options -} - -Laplace3DPetsc::~Laplace3DPetsc() { - -} - -const Field3D Laplace3DPetsc::solve(const Field3D &b) { - // Set matrix coefficients - - // Solve - -} - -#endif // BOUT_HAS_PETSC diff --git a/src/invert/laplace3d/impls/petsc/petsc_laplace3d.hxx b/src/invert/laplace3d/impls/petsc/petsc_laplace3d.hxx deleted file mode 100644 index 232c97c731..0000000000 --- a/src/invert/laplace3d/impls/petsc/petsc_laplace3d.hxx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 3D Laplacian solver using PETSc - */ - -#ifndef BOUT_HAS_PETSC -// No PETSc available, so define as an empty laplace3d - -#include "../emptylaplace3d.hxx" -using Laplace3DPetsc = EmptyLaplace3D; - -#else // BOUT_HAS_PETSC - -class Laplace3DPetsc; - -#ifndef __PETSC_LAPLACE3D_H__ -#define __PETSC_LAPLACE3D_H__ - -#include - -class Laplace3DPetsc : public Laplace3D { -public: - Laplace3DPetsc(Options *opt = nullptr); - ~Laplace3DPetsc(); - - void setCoefA(const Field2D &f) {A = f;} - void setCoefB(const Field2D &f) {B = f;} - void setCoefC(const Field2D &f) {C = f;} - void setCoefD(const Field2D &f) {D = f;} - - void setCoefA(const Field3D &f) {A = f;} - void setCoefB(const Field3D &f) {B = f;} - void setCoefC(const Field3D &f) {C = f;} - void setCoefD(const Field3D &f) {D = f;} - - const Field3D solve(const Field3D &b); -private: - Field3D A,B,C,D; // Coefficients -}; - -#endif // __PETSC_LAPLACE3D_H__ - -#endif // BOUT_HAS_PETSC - diff --git a/src/invert/laplace3d/laplace3d.cxx b/src/invert/laplace3d/laplace3d.cxx deleted file mode 100644 index d41005c281..0000000000 --- a/src/invert/laplace3d/laplace3d.cxx +++ /dev/null @@ -1,8 +0,0 @@ - -#include - -#include "laplace3d_factory.hxx" - -Laplace3D* Laplace3D::create(Options *opts) { - return Laplace3DFactory::getInstance()->createLaplace3D(opts); -} diff --git a/src/invert/laplace3d/laplace3d_factory.cxx b/src/invert/laplace3d/laplace3d_factory.cxx deleted file mode 100644 index 23aea95974..0000000000 --- a/src/invert/laplace3d/laplace3d_factory.cxx +++ /dev/null @@ -1,34 +0,0 @@ - -#include -#include -#include - -#include "laplace3d_factory.hxx" - -// Include implementations here -#include "impls/petsc/petsc_laplace3d.hxx" - -Laplace3DFactory* Laplace3DFactory::instance = 0; - -Laplace3DFactory* Laplace3DFactory::getInstance() { - if(instance == 0) { - // Create the singleton object - instance = new Laplace3DFactory(); - } - return instance; -} - -Laplace3D* Laplace3DFactory::createLaplace3D(Options *options) { - if(!options) - options = Options::getRoot()->getSection("laplace3d"); - - string type; - options->get("type", type, "petsc"); - - // Add tests for available solvers here. See src/invert/laplace/laplacefactory.cxx - if(strcasecmp(type.c_str(), "petsc") == 0) { - return new Laplace3DPetsc(options); - } - - throw BoutException("Unknown Laplace3D solver type '%s'", type.c_str()); -} diff --git a/src/invert/laplace3d/laplace3d_factory.hxx b/src/invert/laplace3d/laplace3d_factory.hxx deleted file mode 100644 index b911ed878d..0000000000 --- a/src/invert/laplace3d/laplace3d_factory.hxx +++ /dev/null @@ -1,23 +0,0 @@ - -class Laplace3DFactory; - -#ifndef __LAPLACE3D_FACTORY_H__ -#define __LAPLACE3D_FACTORY_H__ - -#include -#include - -class Laplace3DFactory { - public: - /// Return a pointer to the only instance - static Laplace3DFactory* getInstance(); - - Laplace3D* createLaplace3D(Options *options = nullptr); - -private: - Laplace3DFactory() {} // Prevent instantiation of this class - static Laplace3DFactory* instance; ///< The only instance of this class (Singleton) -}; - -#endif // __LAPLACE3D_FACTORY_H__ - diff --git a/src/invert/laplace3d/makefile b/src/invert/laplace3d/makefile deleted file mode 100644 index ca9f7d0a9b..0000000000 --- a/src/invert/laplace3d/makefile +++ /dev/null @@ -1,9 +0,0 @@ - -BOUT_TOP = ../../.. - -DIRS = impls -SOURCEC = laplace3d.cxx laplace3d_factory.cxx -SOURCEH = laplace3d_factory.hxx -TARGET = lib - -include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-laplace3d/data/BOUT.inp b/tests/integrated/test-laplace3d/data/BOUT.inp deleted file mode 100644 index a66ad214bd..0000000000 --- a/tests/integrated/test-laplace3d/data/BOUT.inp +++ /dev/null @@ -1,12 +0,0 @@ -# Test of the Laplace3D class -# - -NOUT = 0 # No timesteps - -MZ = 32 # Z size - -[mesh] - -nx = 20 -ny = 16 - diff --git a/tests/integrated/test-laplace3d/makefile b/tests/integrated/test-laplace3d/makefile deleted file mode 100644 index 29fffa21e5..0000000000 --- a/tests/integrated/test-laplace3d/makefile +++ /dev/null @@ -1,6 +0,0 @@ - -BOUT_TOP = ../../.. - -SOURCEC = test_laplace3d.cxx - -include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-laplace3d/test_laplace3d.cxx b/tests/integrated/test-laplace3d/test_laplace3d.cxx deleted file mode 100644 index 37c3e43e39..0000000000 --- a/tests/integrated/test-laplace3d/test_laplace3d.cxx +++ /dev/null @@ -1,25 +0,0 @@ - -#include - -#include - -class Laplace3DTest : public PhysicsModel { -protected: - int init(bool restarting); -}; - - -int Laplace3DTest::init(bool restarting) { - - // Create a 3D Laplacian solver - Laplace3D *lap = Laplace3D::create(); - - // Set coefficients - - // solve - - return 1; -} - -// Generate a main() function to run test -BOUTMAIN(Laplace3DTest); From 87c41391b3e8dd28d299aff2cacd328007828f9a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 23 Apr 2019 16:57:08 +0100 Subject: [PATCH 1453/1783] Hardcode all variables for test-solver; remove input file Also do bare minimum initialisation --- tests/integrated/test-solver/data/BOUT.inp | 65 ------------ tests/integrated/test-solver/test_solver.cxx | 105 +++++++++++++------ 2 files changed, 71 insertions(+), 99 deletions(-) delete mode 100644 tests/integrated/test-solver/data/BOUT.inp diff --git a/tests/integrated/test-solver/data/BOUT.inp b/tests/integrated/test-solver/data/BOUT.inp deleted file mode 100644 index 4d0a116eee..0000000000 --- a/tests/integrated/test-solver/data/BOUT.inp +++ /dev/null @@ -1,65 +0,0 @@ -# Integrate up to pi/2 -end = pi / 2 - -NOUT = 100 -TIMESTEP = end / NOUT - -[mesh] -# This is the smallest mesh that doesn't cause problems -# Could possibly be even smaller with a "null" boundary condition -MXG = 1 -MYG = 1 -nx = 3 -ny = 1 -nz = 1 - -[output] -enabled = false - -[restart] -enabled = false - -[solver] - -[arkode] -[cvode] -[euler] -mxstep = 100000 -nout = 100 -timestep = end / (NOUT * 1000) -[ida] -[imexbdf2] -# This solver currently fails this test without adaptive timestepping -adaptive = true -# We should tighten up the default tolerance -adaptRtol = 1.e-5 -[karniadakis] -nout = 100 -timestep = end / (NOUT * 10000) -[petsc] -# For PETSc < 3.7, there are issues with the RK solvers not -# interpolating at the final step if they are adaptive -nout = 10000 -output_step = end / nout -[power] -[pvode] -[rk3ssp] -[rk4] -# This solver currently fails this test without adaptive timestepping -adaptive = true -[rkgeneric] -# This solver currently fails this test without adaptive timestepping -adaptive = true -[slepc] -[snes] -# This solver currently fails this test without adaptive timestepping -adaptive = true - -[splitrk] -timestep = end / (NOUT * 500) -nstages = 3 -mxstep = 10000 -adaptive=false - -[field] -bndry_all = none diff --git a/tests/integrated/test-solver/test_solver.cxx b/tests/integrated/test-solver/test_solver.cxx index 746dda1bff..f0c0c2612e 100644 --- a/tests/integrated/test-solver/test_solver.cxx +++ b/tests/integrated/test-solver/test_solver.cxx @@ -1,8 +1,11 @@ #include "bout/constants.hxx" #include "bout/physicsmodel.hxx" #include "bout/solverfactory.hxx" +#include "bout/petsclib.hxx" +#include "bout/slepclib.hxx" #include +#include #include #include @@ -22,13 +25,13 @@ class TestSolver : public PhysicsModel { } }; -int main(int argc, char **argv) { +int main(int argc, char** argv) { // The expected answer to the integral of \f$\int_0^{\pi/2}\sin^2(t)\f$ - BoutReal expected = PI / 4.; + constexpr BoutReal expected = PI / 4.; // Absolute tolerance for difference between the actual value and the // expected value - BoutReal tolerance = 1.e-5; + constexpr BoutReal tolerance = 1.e-5; // Our own output to stdout, as main library will only be writing to log files Output output_test; @@ -37,47 +40,81 @@ int main(int argc, char **argv) { // Should be able to check which solvers aren't suitable std::vector eigen_solvers = {"power", "slepc", "snes"}; - for (auto &eigen_solver : eigen_solvers) { + for (auto& eigen_solver : eigen_solvers) { if (SolverFactory::getInstance()->remove(eigen_solver)) { output_test << "Removed '" << eigen_solver << "' eigen solver\n"; } } output_test << "\nTesting the following solvers:\n"; - for (auto &solver : SolverFactory::getInstance()->listAvailable()) { + for (auto& solver : SolverFactory::getInstance()->listAvailable()) { output_test << " " << solver << "\n"; } // Explicit flush to make sure list of available solvers gets printed output_test << std::endl; - // DANGER, hack below! BoutInitialise turns on writing to stdout for rank 0, - // and then immediately prints a load of stuff to stdout. We want this test to - // be quiet, so we need to hide stdout from the main library before - // BoutInitialise. After the call to BoutInitialise, we can turn off the main - // library writing to stdout in a nicer way. + auto& root = Options::root(); - // Save cout's buffer here - std::stringstream buffer; - auto *sbuf = std::cout.rdbuf(); - // Redirect cout to our buffer - std::cout.rdbuf(buffer.rdbuf()); + root["mesh"]["MXG"] = 1; + root["mesh"]["MYG"] = 1; + root["mesh"]["nx"] = 3; + root["mesh"]["ny"] = 1; + root["mesh"]["nz"] = 1; - int init_err = BoutInitialise(argc, argv); - if (init_err < 0) { - return 0; - } else if (init_err > 0) { - return init_err; - } + root["output"]["enabled"] = false; + root["restart"]["enabled"] = false; + + // Set the command-line arguments + SlepcLib::setArgs(argc, argv); + PetscLib::setArgs(argc, argv); + Solver::setArgs(argc, argv); + BoutComm::setArgs(argc, argv); - // Now BoutInitialise is done, redirect stdout to its old self - std::cout.rdbuf(sbuf); // Turn off writing to stdout for the main library Output::getInstance()->disable(); + bout::globals::mesh = Mesh::create(); + bout::globals::mesh->load(); + + bout::globals::dump = + bout::experimental::setupDumpFile(Options::root(), *bout::globals::mesh, "."); + + constexpr BoutReal end = PI / 2.; + constexpr int NOUT = 100; + + // Global options + root["NOUT"] = NOUT; + root["TIMESTEP"] = end / NOUT; + + // Solver-specific options + root["euler"]["mxstep"] = 100000; + root["euler"]["nout"] = NOUT; + root["euler"]["timestep"] = end / (NOUT * 1000); + + root["rk4"]["adaptive"] = true; + + root["rkgeneric"]["adaptive"] = true; + + root["imexbdf2"]["adaptive"] = true; + root["imexbdf2"]["adaptRtol"] = 1.e-5; + + root["karniadakis"]["nout"] = 100; + root["karniadakis"]["timestep"] = end / (NOUT * 10000); + + root["petsc"]["nout"] = 10000; + root["petsc"]["output_step"] = end / 10000; + + root["snes"]["adaptive"] = true; + + root["splitrk"]["timestep"] = end / (NOUT * 500); + root["splitrk"]["nstages"] = 3; + root["splitrk"]["mxstep"] = 10000; + root["splitrk"]["adaptive"] = false; + // Solver and its actual value if it didn't pass std::map errors; - for (auto &name : SolverFactory::getInstance()->listAvailable()) { + for (auto& name : SolverFactory::getInstance()->listAvailable()) { output_test << "Testing " << name << " solver:"; try { @@ -85,23 +122,23 @@ int main(int argc, char **argv) { // "solver" section, as we run into problems when solvers use the same // name for an option with inconsistent defaults auto options = Options::getRoot()->getSection(name); - auto solver = std::unique_ptr{SolverFactory::getInstance()->createSolver(name, options)}; + auto solver = std::unique_ptr{Solver::create(name, options)}; - auto model = bout::utils::make_unique(); - solver->setModel(model.get()); + TestSolver model{}; + solver->setModel(&model); - auto bout_monitor = bout::utils::make_unique(); - solver->addMonitor(bout_monitor.get(), Solver::BACK); + BoutMonitor bout_monitor{}; + solver->addMonitor(&bout_monitor, Solver::BACK); solver->solve(); - if (fabs(model->field(1, 1, 0) - expected) > tolerance) { + if (std::abs(model.field(1, 1, 0) - expected) > tolerance) { output_test << " FAILED\n"; - errors[name] = model->field(1, 1, 0); + errors[name] = model.field(1, 1, 0); } else { output_test << " PASSED\n"; } - } catch (BoutException &e) { + } catch (BoutException& e) { // Don't let one bad solver stop us trying the rest output_test << " ERROR\n"; output_info << "Error encountered with solver " << name << "\n"; @@ -110,11 +147,11 @@ int main(int argc, char **argv) { } } - BoutFinalise(); + BoutFinalise(false); if (!errors.empty()) { output_test << "\n => Some failed tests\n\n"; - for (auto &error : errors) { + for (auto& error : errors) { output_test << " " << error.first << " got: " << error.second << ", expected: " << expected << "\n"; } From bee7bf4bb93165c53b23be5168fab34ebfbfb3ff Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 25 Apr 2019 17:43:17 +0100 Subject: [PATCH 1454/1783] Bugfix: use region in Coordinates::calcCovariant/calcContravariant --- include/bout/coordinates.hxx | 6 ++- src/mesh/coordinates.cxx | 94 ++++++++++++++++-------------------- 2 files changed, 46 insertions(+), 54 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index 48e8d5725c..819a82f438 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -114,8 +114,10 @@ public: /// Calculate differential geometry quantities from the metric tensor int geometry(bool recalculate_staggered = true, bool force_interpolate_from_centre = false); - int calcCovariant(); ///< Inverts contravatiant metric to get covariant - int calcContravariant(); ///< Invert covariant metric to get contravariant + /// Invert contravatiant metric to get covariant components + int calcCovariant(const std::string& region = "RGN_ALL"); + /// Invert covariant metric to get contravariant components + int calcContravariant(const std::string& region = "RGN_ALL"); int jacobian(); ///< Calculate J and Bxy diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index a07f286de5..27e8803839 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -313,13 +313,13 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) output_warn.write("Not all covariant components of metric tensor found. " "Calculating all from the contravariant tensor\n"); /// Calculate contravariant metric components if not found - if (calcCovariant()) { + if (calcCovariant("RGN_NOBNDRY")) { throw BoutException("Error in calcCovariant call"); } } } else { /// Calculate contravariant metric components if not found - if (calcCovariant()) { + if (calcCovariant("RGN_NOBNDRY")) { throw BoutException("Error in calcCovariant call"); } } @@ -497,13 +497,13 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, output_warn.write("Not all staggered covariant components of metric tensor found. " "Calculating all from the contravariant tensor\n"); /// Calculate contravariant metric components if not found - if (calcCovariant()) { + if (calcCovariant("RGN_NOBNDRY")) { throw BoutException("Error in staggered calcCovariant call"); } } } else { /// Calculate contravariant metric components if not found - if (calcCovariant()) { + if (calcCovariant("RGN_NOBNDRY")) { throw BoutException("Error in staggered calcCovariant call"); } } @@ -877,7 +877,7 @@ int Coordinates::geometry(bool recalculate_staggered, return 0; } -int Coordinates::calcCovariant() { +int Coordinates::calcCovariant(const std::string& region) { TRACE("Coordinates::calcCovariant"); // Make sure metric elements are allocated @@ -900,32 +900,27 @@ int Coordinates::calcCovariant() { auto a = Matrix(3, 3); - for (int jx = 0; jx < localmesh->LocalNx; jx++) { - for (int jy = 0; jy < localmesh->LocalNy; jy++) { - // set elements of g - a(0, 0) = g11(jx, jy); - a(1, 1) = g22(jx, jy); - a(2, 2) = g33(jx, jy); - - a(0, 1) = a(1, 0) = g12(jx, jy); - a(1, 2) = a(2, 1) = g23(jx, jy); - a(0, 2) = a(2, 0) = g13(jx, jy); - - // invert - if (invert3x3(a)) { - output_error.write("\tERROR: metric tensor is singular at (%d, %d)\n", jx, jy); - return 1; - } + BOUT_FOR_SERIAL(i, g11.getRegion(region)) { + a(0, 0) = g11[i]; + a(1, 1) = g22[i]; + a(2, 2) = g33[i]; - // put elements into g_{ij} - g_11(jx, jy) = a(0, 0); - g_22(jx, jy) = a(1, 1); - g_33(jx, jy) = a(2, 2); + a(0, 1) = a(1, 0) = g12[i]; + a(1, 2) = a(2, 1) = g23[i]; + a(0, 2) = a(2, 0) = g13[i]; - g_12(jx, jy) = a(0, 1); - g_13(jx, jy) = a(0, 2); - g_23(jx, jy) = a(1, 2); + if (invert3x3(a)) { + output_error.write("\tERROR: metric tensor is singular at (%d, %d)\n", i.x(), i.y()); + return 1; } + + g_11[i] = a(0, 0); + g_22[i] = a(1, 1); + g_33[i] = a(2, 2); + + g_12[i] = a(0, 1); + g_13[i] = a(0, 2); + g_23[i] = a(1, 2); } BoutReal maxerr; @@ -944,7 +939,7 @@ int Coordinates::calcCovariant() { return 0; } -int Coordinates::calcContravariant() { +int Coordinates::calcContravariant(const std::string& region) { TRACE("Coordinates::calcContravariant"); // Make sure metric elements are allocated @@ -960,32 +955,27 @@ int Coordinates::calcContravariant() { auto a = Matrix(3, 3); - for (int jx = 0; jx < localmesh->LocalNx; jx++) { - for (int jy = 0; jy < localmesh->LocalNy; jy++) { - // set elements of g - a(0, 0) = g_11(jx, jy); - a(1, 1) = g_22(jx, jy); - a(2, 2) = g_33(jx, jy); - - a(0, 1) = a(1, 0) = g_12(jx, jy); - a(1, 2) = a(2, 1) = g_23(jx, jy); - a(0, 2) = a(2, 0) = g_13(jx, jy); - - // invert - if (invert3x3(a)) { - output_error.write("\tERROR: metric tensor is singular at (%d, %d)\n", jx, jy); - return 1; - } + BOUT_FOR_SERIAL(i, g_11.getRegion(region)) { + a(0, 0) = g_11[i]; + a(1, 1) = g_22[i]; + a(2, 2) = g_33[i]; - // put elements into g_{ij} - g11(jx, jy) = a(0, 0); - g22(jx, jy) = a(1, 1); - g33(jx, jy) = a(2, 2); + a(0, 1) = a(1, 0) = g_12[i]; + a(1, 2) = a(2, 1) = g_23[i]; + a(0, 2) = a(2, 0) = g_13[i]; - g12(jx, jy) = a(0, 1); - g13(jx, jy) = a(0, 2); - g23(jx, jy) = a(1, 2); + if (invert3x3(a)) { + output_error.write("\tERROR: metric tensor is singular at (%d, %d)\n", i.x(), i.y()); + return 1; } + + g11[i] = a(0, 0); + g22[i] = a(1, 1); + g33[i] = a(2, 2); + + g12[i] = a(0, 1); + g13[i] = a(0, 2); + g23[i] = a(1, 2); } BoutReal maxerr; From 1fc5448b2c1d2195e571ac19ba43a7c79b71a46f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 23 Apr 2019 16:02:52 +0100 Subject: [PATCH 1455/1783] Make MsgStackTest::TraceMacroTest more flexible --- tests/unit/sys/test_msg_stack.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/sys/test_msg_stack.cxx b/tests/unit/sys/test_msg_stack.cxx index 96671a9f3f..b68fc34d3a 100644 --- a/tests/unit/sys/test_msg_stack.cxx +++ b/tests/unit/sys/test_msg_stack.cxx @@ -3,6 +3,7 @@ #include "gtest/gtest.h" #include "msg_stack.hxx" +#include "test_extras.hxx" #include #include @@ -128,10 +129,9 @@ TEST(MsgStackTest, TraceMacroTest) { std::string line = std::to_string(__LINE__ + 1); TRACE("Second"); auto second = msg_stack.getDump(); - auto second_dump = "====== Back trace ======\n -> Second on line " + line + - " of 'sys/test_msg_stack.cxx'\n -> First\n"; + auto second_dump = "====== Back trace ======\n -> Second on line " + line; - EXPECT_EQ(second_dump, second); + EXPECT_TRUE(IsSubString(second, second_dump)); } // Should now contain only the first message From f7b40bfd248ba2fc4106b9036e007f0902b8bda0 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 24 Apr 2019 15:33:45 +0100 Subject: [PATCH 1456/1783] Make boutexception test more flexible for name of executable --- tests/unit/sys/test_boutexception.cxx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/unit/sys/test_boutexception.cxx b/tests/unit/sys/test_boutexception.cxx index 842870baae..13991f285b 100644 --- a/tests/unit/sys/test_boutexception.cxx +++ b/tests/unit/sys/test_boutexception.cxx @@ -1,5 +1,6 @@ #include "gtest/gtest.h" #include "boutexception.hxx" +#include "test_extras.hxx" #include #include @@ -29,13 +30,16 @@ TEST(BoutExceptionTest, GetBacktrace) { try { throw BoutException(test_message); } catch (const BoutException &e) { - std::string expected{"[bt] #1 ./serial_tests"}; + std::string expected_1{"[bt] #1"}; + std::string expected_2{"serial_tests"}; #ifdef BACKTRACE // Should be able to find something about backtrace - EXPECT_NE(e.getBacktrace().find(expected), std::string::npos); + EXPECT_TRUE(IsSubString(e.getBacktrace(), expected_1)); + EXPECT_TRUE(IsSubString(e.getBacktrace(), expected_2)); #else // Should *not* be able to find something about backtrace - EXPECT_EQ(e.getBacktrace().find(expected), std::string::npos); + EXPECT_FALSE(IsSubString(e.getBacktrace(), expected_1)); + EXPECT_FALSE(IsSubString(e.getBacktrace(), expected_2)); #endif } } From 51f2e3c69f60b676ae3c51fde8487323f90dfc0d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 21 May 2019 17:47:45 +0100 Subject: [PATCH 1457/1783] Deprecate Karniadakis solver Solver is _very_ slow, and now `splitrk` is a built-in, there is always a split-scheme solver available --- src/solver/impls/karniadakis/karniadakis.cxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/solver/impls/karniadakis/karniadakis.cxx b/src/solver/impls/karniadakis/karniadakis.cxx index 0cefc82647..ce66d4b84b 100644 --- a/src/solver/impls/karniadakis/karniadakis.cxx +++ b/src/solver/impls/karniadakis/karniadakis.cxx @@ -50,6 +50,11 @@ KarniadakisSolver::KarniadakisSolver(Options *options) : Solver(options) { int KarniadakisSolver::init(int nout, BoutReal tstep) { TRACE("Initialising Karniadakis solver"); + output_error << "\nWARNING:\n" + " The Karniadakis solver is now deprecated and will be removed in BOUT++ 5.0!\n" + " Try the \"splitrk\", \"imexbdf2\" (requires PETSc) or \"arkode\" (requires SUNDIALS)\n" + " solvers for other split-schemes\n\n"; + /// Call the generic initialisation first if (Solver::init(nout, tstep)) return 1; From 9dfb1fb5e3ec5aeca713211a844fb72467019f2c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 22 May 2019 12:08:09 +0100 Subject: [PATCH 1458/1783] Move `EnableIfField` to bout/traits.hxx; Add `is_Field` etc. `bout::utils::EnableIfField` is now implemented in terms of `bout::utils::is_Field`. There are also variants for `is_Field2D`, `is_Field3D` and `is_FieldPerp`, along with the corresponding versions of `EnableIfField*` Also add static tests for these traits --- include/bout/traits.hxx | 127 +++++++++++++++++++++++ include/field.hxx | 50 +-------- tests/unit/include/bout/test_traits.cxx | 129 ++++++++++++++++++++++++ 3 files changed, 257 insertions(+), 49 deletions(-) create mode 100644 include/bout/traits.hxx create mode 100644 tests/unit/include/bout/test_traits.cxx diff --git a/include/bout/traits.hxx b/include/bout/traits.hxx new file mode 100644 index 0000000000..13cb57467a --- /dev/null +++ b/include/bout/traits.hxx @@ -0,0 +1,127 @@ +#ifndef BOUT_TRAITS_H +#define BOUT_TRAITS_H + +#include + +class Field; +class Field2D; +class Field3D; +class FieldPerp; + +namespace bout { +namespace utils { + +namespace details { +/// Helper class for fold expressions pre-C++17 +/// +/// Taken from "C++ Templates: The Complete Guide, Second Edition" +/// Addison-Wesley, 2017 +/// ISBN-13: 978-0-321-71412-1 +/// ISBN-10: 0-321-71412-1 +/// Copyright © 2017 by Addison-Wesley, David Vandevoorde, Nicolai +/// M. Josuttis, and Douglas Gregor. +constexpr bool and_all() { return true; } +template +constexpr bool and_all(T cond) { + return cond; +} +template +constexpr bool and_all(T cond, Ts... conds) { + return cond and and_all(conds...); +} +} // namespace details + +/// If `T` is derived from `Field`, provides the member constant +/// `value` equal to `true`. Otherwise `value is `false`. +/// +/// The following is C++14, but simplifies the use of `is_field`: +/// +/// template +/// constexpr bool is_field_v = is_field::value; +/// +/// Examples +/// -------- +/// +/// template +/// void print_field(const T& field) { +/// static_assert(bout::utils::is_field::value, +/// "print_field only works with Field2Ds, Field3Ds or FieldPerps") +/// // implementation +/// } +template +using is_Field = std::is_base_of; + +/// If `T` is derived from `Field2D`, provides the member constant +/// `value` equal to `true`. Otherwise `value is `false`. +template +using is_Field2D = std::is_base_of; + +/// If `T` is derived from `Field3D`, provides the member constant +/// `value` equal to `true`. Otherwise `value is `false`. +template +using is_Field3D = std::is_base_of; + +/// If `T` is derived from `FieldPerp`, provides the member constant +/// `value` equal to `true`. Otherwise `value is `false`. +template +using is_FieldPerp = std::is_base_of; + +/// Enable a function if all the Ts are subclasses of `Field`, and +/// returns the common type: i.e. `Field3D` if at least one argument +/// is `Field3D`, otherwise `Field2D` if they are all `Field2D` +/// +/// This is most useful in two particular cases: +/// 1. when there are multiple overloads for a function but some only +/// make sense for fields (as opposed to `BoutReal`, say) or +/// vice-versa, and some overloads should not be used for fields +/// 2. when a function takes multiple fields and the return type is +/// also a field and must be "big enough" +/// +/// In other cases, such as a function without overloads that only +/// works for fields, consider using `static_assert` with `is_Field` +/// to give a nice compile-time error +/// +/// Examples +/// -------- +/// +/// Consider the following template function: +/// +/// template > +/// auto where(const T& test, const U& gt0, const V& le0) -> ResultType { +/// // function body +/// } +/// +/// This function only "appears" if `T`, `U` and `V` are all +/// subclasses of `Field`. `ResultType` is the common type of `T`, `U` +/// and `V`. If `T` and `U` are both `Field2D`, `ResultType` is +/// `Field2D` if `V` is `Field2D`, and `Field3D` if `V` is `Field3D`. +template +using EnableIfField = + typename std::enable_if::value ...), + typename std::common_type::type>::type; + +/// Enable a function if all the Ts are subclasses of `Field2D`, and +/// returns the common type +template +using EnableIfField2D = + typename std::enable_if::value ...), + typename std::common_type::type>::type; + +/// Enable a function if all the Ts are subclasses of `Field3D`, and +/// returns the common type +template +using EnableIfField3D = + typename std::enable_if::value ...), + typename std::common_type::type>::type; + +/// Enable a function if all the Ts are subclasses of `FieldPerp`, and +/// returns the common type +template +using EnableIfFieldPerp = + typename std::enable_if::value ...), + typename std::common_type::type>::type; +} // namespace utils +} // namespace bout + +#endif // BOUT_TRAITS_H diff --git a/include/field.hxx b/include/field.hxx index 4e97e820bf..54b4adc509 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -38,6 +38,7 @@ class Field; #include "msg_stack.hxx" #include "stencils.hxx" #include +#include "bout/traits.hxx" #include "unused.hxx" @@ -48,55 +49,6 @@ class Coordinates; #include #endif -namespace bout { -namespace utils { - -namespace details { -/// Helper class for fold expressions pre-C++17 -/// -/// Taken from "C++ Templates: The Complete Guide, Second Edition" -/// Addison-Wesley, 2017 -/// ISBN-13: 978-0-321-71412-1 -/// ISBN-10: 0-321-71412-1 -/// Copyright © 2017 by Addison-Wesley, David Vandevoorde, Nicolai -/// M. Josuttis, and Douglas Gregor. -constexpr bool and_all() { return true; } -template -constexpr bool and_all(T cond) { - return cond; -} -template -constexpr bool and_all(T cond, Ts... conds) { - return cond and and_all(conds...); -} -} // namespace details - -/// Enable a function if all the Ts are subclasses of `Field`, and -/// returns the common type: i.e. `Field3D` if at least one argument -/// is `Field3D`, otherwise `Field2D` if they are all `Field2D` -/// -/// Examples -/// -------- -/// -/// Consider the following template function: -/// -/// template > -/// auto where(const T& test, const U& gt0, const V& le0) -> ResultType { -/// // function body -/// } -/// -/// This function only "appears" if `T`, `U` and `V` are all -/// subclasses of `Field`. `ResultType` is the common type of `T`, `U` -/// and `V`. If `T` and `U` are both `Field2D`, `ResultType` is -/// `Field2D` if `V` is `Field2D`, and `Field3D` if `V` is `Field3D`. -template -using EnableIfField = - typename std::enable_if::value ...), - typename std::common_type::type>::type; -} // namespace utils -} // namespace bout - /*! * \brief Base class for fields * diff --git a/tests/unit/include/bout/test_traits.cxx b/tests/unit/include/bout/test_traits.cxx new file mode 100644 index 0000000000..7f475604a5 --- /dev/null +++ b/tests/unit/include/bout/test_traits.cxx @@ -0,0 +1,129 @@ +#include "gtest/gtest.h" + +#include "field.hxx" +#include "field2d.hxx" +#include "field3d.hxx" +#include "fieldperp.hxx" +#include "bout/traits.hxx" + +#include + +TEST(BoutTraitsTest, IsField) { + using namespace bout::utils; + static_assert(is_Field::value, "is_Field should be true"); + static_assert(is_Field::value, "is_Field should be true"); + static_assert(is_Field::value, "is_Field should be true"); + static_assert(is_Field::value, "is_Field should be true"); +} + +TEST(BoutTraitsTest, IsField2D) { + using namespace bout::utils; + static_assert(!is_Field2D::value, "is_Field2D should be false"); + static_assert(is_Field2D::value, "is_Field2D should be true"); + static_assert(!is_Field2D::value, "is_Field2D should be false"); + static_assert(!is_Field2D::value, "is_Field2D should be false"); +} + +TEST(BoutTraitsTest, IsField3D) { + using namespace bout::utils; + static_assert(!is_Field3D::value, "is_Field3D should be false"); + static_assert(!is_Field3D::value, "is_Field3D should be false"); + static_assert(is_Field3D::value, "is_Field3D should be true"); + static_assert(!is_Field3D::value, "is_Field3D should be false"); +} + +TEST(BoutTraitsTest, IsFieldPerp) { + using namespace bout::utils; + static_assert(!is_FieldPerp::value, "is_FieldPerp should be false"); + static_assert(!is_FieldPerp::value, "is_FieldPerp should be false"); + static_assert(!is_FieldPerp::value, "is_FieldPerp should be false"); + static_assert(is_FieldPerp::value, "is_FieldPerp should be true"); +} + +namespace { +struct CorrectForFields {}; +struct CorrectForBoutReal {}; + +template > +auto function_overloads(T, U) -> CorrectForFields { + return {}; +} + +// Commenting out the below template should break the +// EnableIfFieldOverloads test +template +auto function_overloads(T, BoutReal) -> CorrectForBoutReal { + return {}; +} + +struct OnlyForField2D {}; +struct OnlyForField3D {}; +struct OnlyForFieldPerp {}; + +template > +auto specific_function_overloads(T, U) -> OnlyForField2D { + return {}; +} + +template > +auto specific_function_overloads(T, U) -> OnlyForField3D { + return {}; +} + +template > +auto specific_function_overloads(T, U) -> OnlyForFieldPerp { + return {}; +} + +template > +auto example_function(T, U) -> ResultType { + return {}; +} + +} // namespace + +TEST(BoutTraitsTest, EnableIfFieldOverloads) { + using namespace bout::utils; + static_assert(std::is_same(), + std::declval()))>::value, + "EnableIfField should enable function_overloads for two Fields"); + static_assert( + std::is_same(), + std::declval()))>::value, + "EnableIfField should disable one overload of function_overloads.\n" + "This static_assert should fail if the `function_overloads(T, BoutReal)` template\n" + "is commented out"); + static_assert( + std::is_same(), + std::declval()))>::value, + "EnableIfField should pick the correct version of specific_function_overloads"); + static_assert( + std::is_same(), + std::declval()))>::value, + "EnableIfField should pick the correct version of specific_function_overloads"); + static_assert( + std::is_same(), std::declval()))>::value, + "EnableIfField should pick the correct version of specific_function_overloads"); +} + +TEST(BoutTraitsTest, EnableIfFieldReturnType) { + using namespace bout::utils; + static_assert( + std::is_same(), + std::declval()))>::value, + "EnableIfField should return Field2D for two Field2Ds"); + static_assert( + std::is_same(), + std::declval()))>::value, + "EnableIfField should return Field3D for a Field2D and a Field3D"); + static_assert( + std::is_same(), + std::declval()))>::value, + "EnableIfField should return Field3D for a Field2D and a Field3D"); +} From bf6784d4775e2357f9ac1c7beb2dc210ffb08ac9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 22 May 2019 12:17:16 +0100 Subject: [PATCH 1459/1783] Use bout::utils::is_Field instead of std::is_base_of --- include/bout/index_derivs_interface.hxx | 5 +++-- include/bout/invertable_operator.hxx | 4 ++-- include/field.hxx | 6 +++--- include/interpolation.hxx | 3 ++- src/mesh/data/gridfromfile.cxx | 10 +++++----- src/mesh/index_derivs.cxx | 7 +++---- tests/unit/field/test_field_factory.cxx | 9 +++++---- 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 724e64d9f9..754a886bbc 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -32,6 +32,7 @@ #include #include #include +#include "bout/traits.hxx" class Field3D; class Field2D; @@ -47,7 +48,7 @@ T flowDerivative(const T& vel, const T& f, CELL_LOC outloc, const std::string& m AUTO_TRACE(); // Checks - static_assert(std::is_base_of::value || std::is_base_of::value, + static_assert(bout::utils::is_Field2D::value || bout::utils::is_Field3D::value, "flowDerivative only works on Field2D or Field3D input"); static_assert(derivType == DERIV::Upwind || derivType == DERIV::Flux, @@ -112,7 +113,7 @@ T standardDerivative(const T& f, CELL_LOC outloc, const std::string& method, AUTO_TRACE(); // Checks - static_assert(std::is_base_of::value || std::is_base_of::value, + static_assert(bout::utils::is_Field2D::value || bout::utils::is_Field3D::value, "standardDerivative only works on Field2D or Field3D input"); static_assert(derivType == DERIV::Standard || derivType == DERIV::StandardSecond diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index f128468c85..8566a4dece 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -35,6 +35,7 @@ class InvertableOperator; #ifdef BOUT_HAS_PETSC +#include "bout/traits.hxx" #include #include #include @@ -117,8 +118,7 @@ PetscErrorCode petscVecToField(Vec in, T& out) { template class InvertableOperator { static_assert( - std::is_base_of::value || std::is_base_of::value - || std::is_base_of::value, + bout::utils::is_Field::value, "InvertableOperator must be templated with one of FieldPerp, Field2D or Field3D"); public: diff --git a/include/field.hxx b/include/field.hxx index 54b4adc509..da4d5dd442 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -193,7 +193,7 @@ inline bool areFieldsCompatible(const Field& field1, const Field& field2) { /// copied and a data array that is allocated but not initialised. template inline T emptyFrom(const T& f) { - static_assert(std::is_base_of::value, "emptyFrom only works on Fields"); + static_assert(bout::utils::is_Field::value, "emptyFrom only works on Fields"); return T(f.getMesh(), f.getLocation(), {f.getDirectionY(), f.getDirectionZ()}).allocate(); } @@ -201,7 +201,7 @@ inline T emptyFrom(const T& f) { /// another field and a data array allocated and initialised to zero. template inline T zeroFrom(const T& f) { - static_assert(std::is_base_of::value, "emptyFrom only works on Fields"); + static_assert(bout::utils::is_Field::value, "emptyFrom only works on Fields"); T result{emptyFrom(f)}; result = 0.; return result; @@ -211,7 +211,7 @@ inline T zeroFrom(const T& f) { /// another field and a data array allocated and filled with the given value. template inline T filledFrom(const T& f, BoutReal fill_value) { - static_assert(std::is_base_of::value, "emptyFrom only works on Fields"); + static_assert(bout::utils::is_Field::value, "emptyFrom only works on Fields"); T result{emptyFrom(f)}; result = fill_value; return result; diff --git a/include/interpolation.hxx b/include/interpolation.hxx index b27a110650..8d332824e9 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -26,6 +26,7 @@ #ifndef __INTERP_H__ #define __INTERP_H__ +#include "bout/traits.hxx" #include "bout_types.hxx" #include "field3d.hxx" #include "mask.hxx" @@ -60,7 +61,7 @@ inline BoutReal interp(const stencil& s) { template const T interp_to(const T& var, CELL_LOC loc, REGION region = RGN_ALL) { AUTO_TRACE(); - static_assert(std::is_base_of::value || std::is_base_of::value, + static_assert(bout::utils::is_Field2D::value || bout::utils::is_Field3D::value, "interp_to must be templated with one of Field2D or Field3D."); ASSERT1(loc != CELL_DEFAULT); // doesn't make sense to interplote to CELL_DEFAULT diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index dc881e53ac..7c8997882f 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -1,4 +1,5 @@ +#include "bout/traits.hxx" #include #include @@ -185,8 +186,7 @@ bool GridFile::get(Mesh *m, Field3D &var, const std::string &name, BoutReal def) template bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) { - static_assert(std::is_base_of::value or std::is_base_of::value - or std::is_base_of::value, + static_assert(bout::utils::is_Field::value, "templated GridFile::get only works for Field2D, Field3D or FieldPerp"); Timer timer("io"); @@ -222,7 +222,7 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) } case 3: { // Check size if getting Field3D - if (std::is_base_of::value or std::is_base_of::value) { + if (bout::utils::is_Field2D::value or bout::utils::is_FieldPerp::value) { output_warn.write("WARNING: Variable '%s' should be 2D, but has %zu dimensions. Ignored\n", name.c_str(), size.size()); var = def; @@ -296,7 +296,7 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) "nor grid_xguards = 0", name.c_str(), grid_xguards, mxg); } - if (not std::is_base_of::value) { + if (not bout::utils::is_FieldPerp::value) { ///Check if field dimensions are correct. y-direction if (grid_yguards > 0) { ///including ghostpoints ASSERT1(field_dimensions[1] == m->GlobalNy - 2*myg + total_grid_yguards); @@ -339,7 +339,7 @@ bool GridFile::getField(Mesh* m, T& var, const std::string& name, BoutReal def) } } - if (not std::is_base_of::value) { + if (not bout::utils::is_FieldPerp::value) { ///If field does not include ghost points in y-direction -> ///Upper and lower Y boundaries copied from nearest point if (grid_yguards == 0) { diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index a4f6f51577..04982a187b 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -20,6 +20,7 @@ * **************************************************************************/ +#include "bout/traits.hxx" #include #include #include @@ -419,8 +420,7 @@ class FFTDerivativeType { ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); ASSERT2(direction == DIRECTION::Z); // Only in Z for now ASSERT2(stagger == STAGGER::None); // Staggering not currently supported - ASSERT2((std::is_base_of::value)); // Should never need to call this with Field2D + ASSERT2(bout::utils::is_Field3D::value); // Should never need to call this with Field2D const auto region_str = toString(region); @@ -491,8 +491,7 @@ class FFT2ndDerivativeType { ASSERT2(var.getMesh()->getNguard(direction) >= nGuards); ASSERT2(direction == DIRECTION::Z); // Only in Z for now ASSERT2(stagger == STAGGER::None); // Staggering not currently supported - ASSERT2((std::is_base_of::value)); // Should never need to call this with Field2D + ASSERT2(bout::utils::is_Field3D::value); // Should never need to call this with Field2D const auto region_str = toString(region); diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index cb22f5afbc..d11d0fb2bc 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -8,6 +8,7 @@ #include "test_extras.hxx" #include "bout/constants.hxx" #include "bout/mesh.hxx" +#include "bout/traits.hxx" /// Global mesh namespace bout { @@ -49,7 +50,7 @@ class FieldFactoryCreationTest : public FakeMeshFixture { // We can't just decide which FieldFactory::create?D function to // call with // - // if (std::is_base_of::value) { + // if (bout::utils::is_Field3D::value) { // return factory.create3D(...); // } else { // return factory.create2D(...); @@ -71,7 +72,7 @@ class FieldFactoryCreationTest : public FakeMeshFixture { // FieldFactory::create3D template T create(Args&&... args) { - return createDispatch(std::is_base_of{}, std::forward(args)...); + return createDispatch(bout::utils::is_Field3D{}, std::forward(args)...); } }; @@ -237,7 +238,7 @@ TYPED_TEST(FieldFactoryCreationTest, CreateZStaggered) { [](typename TypeParam::ind_type& index) -> BoutReal { auto offset = BoutReal{0.0}; - if (std::is_base_of::value) { + if (bout::utils::is_Field3D::value) { offset = 0.5; } @@ -596,7 +597,7 @@ TYPED_TEST(FieldFactoryCreationTest, CreateOnMeshWithoutCoordinates) { localmesh.createDefaultRegions(); // Field2D version doesn't try to transform back - if (std::is_base_of::value) { + if (bout::utils::is_Field3D::value) { EXPECT_THROW(this->create("x", nullptr, &localmesh), BoutException); } } From 805596739247b854bbd63a45dfd68bd87af67f1b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 22 May 2019 15:22:13 +0100 Subject: [PATCH 1460/1783] Put checkFinite and checkPositive in namespace bout:: Also add a note to their docstrings that both functions perform the checks regardless of the value of CHECK, unlike checkData, so they should only be used during initialization. --- include/field.hxx | 10 +++ src/mesh/coordinates.cxx | 132 +++++++++++++++++++-------------------- 2 files changed, 76 insertions(+), 66 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index 3c69b86995..9f3683c664 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -271,10 +271,15 @@ inline T filledFrom(const T& f, BoutReal fill_value) { template T operator+(const T& f) {return f;} +namespace bout { /// Check if all values of a field \p var are finite. Loops over all points including the /// boundaries by default (can be changed using the \p rgn argument) /// If any element is not finite, throws an exception that includes the position of the /// first found. +/// +/// Note that checkFinite runs the check irrespective of CHECK level. It is intended to be +/// used during initialization, where we always want to check inputs, even for optimized +/// builds. template inline void checkFinite(const T& f, const std::string& name="field", const std::string& rgn="RGN_ALL") { AUTO_TRACE(); @@ -294,6 +299,10 @@ inline void checkFinite(const T& f, const std::string& name="field", const std:: /// the boundaries by default (can be changed using the \p rgn argument) /// If any element is not finite, throws an exception that includes the position of the /// first found. +/// +/// Note that checkPositive runs the check irrespective of CHECK level. It is intended to +/// be used during initialization, where we always want to check inputs, even for +/// optimized builds. template inline void checkPositive(const T& f, const std::string& name="field", const std::string& rgn="RGN_ALL") { AUTO_TRACE(); @@ -308,5 +317,6 @@ inline void checkPositive(const T& f, const std::string& name="field", const std } } } +} // namespace bout #endif /* __FIELD_H__ */ diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index db77c6e87a..287bdc6559 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -276,17 +276,17 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) // Check input metrics // Diagonal metric components should be finite - checkFinite(g11, "g11", "RGN_NOCORNERS"); - checkFinite(g22, "g22", "RGN_NOCORNERS"); - checkFinite(g33, "g33", "RGN_NOCORNERS"); + bout::checkFinite(g11, "g11", "RGN_NOCORNERS"); + bout::checkFinite(g22, "g22", "RGN_NOCORNERS"); + bout::checkFinite(g33, "g33", "RGN_NOCORNERS"); // Diagonal metric components should be positive - checkPositive(g11, "g11", "RGN_NOCORNERS"); - checkPositive(g22, "g22", "RGN_NOCORNERS"); - checkPositive(g33, "g33", "RGN_NOCORNERS"); + bout::checkPositive(g11, "g11", "RGN_NOCORNERS"); + bout::checkPositive(g22, "g22", "RGN_NOCORNERS"); + bout::checkPositive(g33, "g33", "RGN_NOCORNERS"); // Off-diagonal metric components should be finite - checkFinite(g12, "g12", "RGN_NOCORNERS"); - checkFinite(g13, "g13", "RGN_NOCORNERS"); - checkFinite(g23, "g23", "RGN_NOCORNERS"); + bout::checkFinite(g12, "g12", "RGN_NOCORNERS"); + bout::checkFinite(g13, "g13", "RGN_NOCORNERS"); + bout::checkFinite(g23, "g23", "RGN_NOCORNERS"); /// Find covariant metric components auto covariant_component_names = {"g_11", "g_22", "g_33", "g_12", "g_13", "g_23"}; @@ -334,17 +334,17 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) // Check covariant metrics // Diagonal metric components should be finite - checkFinite(g_11, "g_11", "RGN_NOCORNERS"); - checkFinite(g_22, "g_22", "RGN_NOCORNERS"); - checkFinite(g_33, "g_33", "RGN_NOCORNERS"); + bout::checkFinite(g_11, "g_11", "RGN_NOCORNERS"); + bout::checkFinite(g_22, "g_22", "RGN_NOCORNERS"); + bout::checkFinite(g_33, "g_33", "RGN_NOCORNERS"); // Diagonal metric components should be positive - checkPositive(g_11, "g_11", "RGN_NOCORNERS"); - checkPositive(g_22, "g_22", "RGN_NOCORNERS"); - checkPositive(g_33, "g_33", "RGN_NOCORNERS"); + bout::checkPositive(g_11, "g_11", "RGN_NOCORNERS"); + bout::checkPositive(g_22, "g_22", "RGN_NOCORNERS"); + bout::checkPositive(g_33, "g_33", "RGN_NOCORNERS"); // Off-diagonal metric components should be finite - checkFinite(g_12, "g_12", "RGN_NOCORNERS"); - checkFinite(g_13, "g_13", "RGN_NOCORNERS"); - checkFinite(g_23, "g_23", "RGN_NOCORNERS"); + bout::checkFinite(g_12, "g_12", "RGN_NOCORNERS"); + bout::checkFinite(g_13, "g_13", "RGN_NOCORNERS"); + bout::checkFinite(g_23, "g_23", "RGN_NOCORNERS"); /// Calculate Jacobian and Bxy if (jacobian()) @@ -377,8 +377,8 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) output_warn.write("\tMaximum difference in Bxy is %e\n", max(abs(Bxy - Bcalc))); // Check Bxy - checkFinite(Bxy, "Bxy", "RGN_NOCORNERS"); - checkPositive(Bxy, "Bxy", "RGN_NOCORNERS"); + bout::checkFinite(Bxy, "Bxy", "RGN_NOCORNERS"); + bout::checkPositive(Bxy, "Bxy", "RGN_NOCORNERS"); } ////////////////////////////////////////////////////// @@ -586,10 +586,10 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, J = interpolateAndExtrapolate(coords_in->J, location); Bxy = interpolateAndExtrapolate(coords_in->J, location); - checkFinite(J, "The Jacobian", "RGN_NOCORNERS"); - checkPositive(J, "The Jacobian", "RGN_NOCORNERS"); - checkFinite(Bxy, "Bxy", "RGN_NOCORNERS"); - checkPositive(Bxy, "Bxy", "RGN_NOCORNERS"); + bout::checkFinite(J, "The Jacobian", "RGN_NOCORNERS"); + bout::checkPositive(J, "The Jacobian", "RGN_NOCORNERS"); + bout::checkFinite(Bxy, "Bxy", "RGN_NOCORNERS"); + bout::checkPositive(Bxy, "Bxy", "RGN_NOCORNERS"); ShiftTorsion = interpolateAndExtrapolate(coords_in->ShiftTorsion, location); @@ -600,26 +600,26 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, // Check input metrics // Diagonal metric components should be finite - checkFinite(g11, "g11", "RGN_NOCORNERS"); - checkFinite(g22, "g22", "RGN_NOCORNERS"); - checkFinite(g33, "g33", "RGN_NOCORNERS"); - checkFinite(g_11, "g_11", "RGN_NOCORNERS"); - checkFinite(g_22, "g_22", "RGN_NOCORNERS"); - checkFinite(g_33, "g_33", "RGN_NOCORNERS"); + bout::checkFinite(g11, "g11", "RGN_NOCORNERS"); + bout::checkFinite(g22, "g22", "RGN_NOCORNERS"); + bout::checkFinite(g33, "g33", "RGN_NOCORNERS"); + bout::checkFinite(g_11, "g_11", "RGN_NOCORNERS"); + bout::checkFinite(g_22, "g_22", "RGN_NOCORNERS"); + bout::checkFinite(g_33, "g_33", "RGN_NOCORNERS"); // Diagonal metric components should be positive - checkPositive(g11, "g11", "RGN_NOCORNERS"); - checkPositive(g22, "g22", "RGN_NOCORNERS"); - checkPositive(g33, "g33", "RGN_NOCORNERS"); - checkPositive(g_11, "g_11", "RGN_NOCORNERS"); - checkPositive(g_22, "g_22", "RGN_NOCORNERS"); - checkPositive(g_33, "g_33", "RGN_NOCORNERS"); + bout::checkPositive(g11, "g11", "RGN_NOCORNERS"); + bout::checkPositive(g22, "g22", "RGN_NOCORNERS"); + bout::checkPositive(g33, "g33", "RGN_NOCORNERS"); + bout::checkPositive(g_11, "g_11", "RGN_NOCORNERS"); + bout::checkPositive(g_22, "g_22", "RGN_NOCORNERS"); + bout::checkPositive(g_33, "g_33", "RGN_NOCORNERS"); // Off-diagonal metric components should be finite - checkFinite(g12, "g12", "RGN_NOCORNERS"); - checkFinite(g13, "g13", "RGN_NOCORNERS"); - checkFinite(g23, "g23", "RGN_NOCORNERS"); - checkFinite(g_12, "g_12", "RGN_NOCORNERS"); - checkFinite(g_13, "g_13", "RGN_NOCORNERS"); - checkFinite(g_23, "g_23", "RGN_NOCORNERS"); + bout::checkFinite(g12, "g12", "RGN_NOCORNERS"); + bout::checkFinite(g13, "g13", "RGN_NOCORNERS"); + bout::checkFinite(g23, "g23", "RGN_NOCORNERS"); + bout::checkFinite(g_12, "g_12", "RGN_NOCORNERS"); + bout::checkFinite(g_13, "g_13", "RGN_NOCORNERS"); + bout::checkFinite(g_23, "g_23", "RGN_NOCORNERS"); ////////////////////////////////////////////////////// /// Calculate Christoffel symbols. Needs communication @@ -671,30 +671,30 @@ int Coordinates::geometry(bool recalculate_staggered, // Check input metrics // Diagonal metric components should be finite - checkFinite(g11, "g11", "RGN_NOCORNERS"); - checkFinite(g22, "g22", "RGN_NOCORNERS"); - checkFinite(g33, "g33", "RGN_NOCORNERS"); + bout::checkFinite(g11, "g11", "RGN_NOCORNERS"); + bout::checkFinite(g22, "g22", "RGN_NOCORNERS"); + bout::checkFinite(g33, "g33", "RGN_NOCORNERS"); // Diagonal metric components should be positive - checkPositive(g11, "g11", "RGN_NOCORNERS"); - checkPositive(g22, "g22", "RGN_NOCORNERS"); - checkPositive(g33, "g33", "RGN_NOCORNERS"); + bout::checkPositive(g11, "g11", "RGN_NOCORNERS"); + bout::checkPositive(g22, "g22", "RGN_NOCORNERS"); + bout::checkPositive(g33, "g33", "RGN_NOCORNERS"); // Off-diagonal metric components should be finite - checkFinite(g12, "g12", "RGN_NOCORNERS"); - checkFinite(g13, "g13", "RGN_NOCORNERS"); - checkFinite(g23, "g23", "RGN_NOCORNERS"); + bout::checkFinite(g12, "g12", "RGN_NOCORNERS"); + bout::checkFinite(g13, "g13", "RGN_NOCORNERS"); + bout::checkFinite(g23, "g23", "RGN_NOCORNERS"); // Diagonal metric components should be finite - checkFinite(g_11, "g_11", "RGN_NOCORNERS"); - checkFinite(g_22, "g_22", "RGN_NOCORNERS"); - checkFinite(g_33, "g_33", "RGN_NOCORNERS"); + bout::checkFinite(g_11, "g_11", "RGN_NOCORNERS"); + bout::checkFinite(g_22, "g_22", "RGN_NOCORNERS"); + bout::checkFinite(g_33, "g_33", "RGN_NOCORNERS"); // Diagonal metric components should be positive - checkPositive(g_11, "g_11", "RGN_NOCORNERS"); - checkPositive(g_22, "g_22", "RGN_NOCORNERS"); - checkPositive(g_33, "g_33", "RGN_NOCORNERS"); + bout::checkPositive(g_11, "g_11", "RGN_NOCORNERS"); + bout::checkPositive(g_22, "g_22", "RGN_NOCORNERS"); + bout::checkPositive(g_33, "g_33", "RGN_NOCORNERS"); // Off-diagonal metric components should be finite - checkFinite(g_12, "g_12", "RGN_NOCORNERS"); - checkFinite(g_13, "g_13", "RGN_NOCORNERS"); - checkFinite(g_23, "g_23", "RGN_NOCORNERS"); + bout::checkFinite(g_12, "g_12", "RGN_NOCORNERS"); + bout::checkFinite(g_13, "g_13", "RGN_NOCORNERS"); + bout::checkFinite(g_23, "g_23", "RGN_NOCORNERS"); // Calculate Christoffel symbol terms (18 independent values) // Note: This calculation is completely general: metric @@ -1044,7 +1044,7 @@ int Coordinates::jacobian() { - g33 * g12 * g12; // Check that g is positive - checkPositive(g, "The determinant of g^ij", "RGN_NOCORNERS"); + bout::checkPositive(g, "The determinant of g^ij", "RGN_NOCORNERS"); J = 1. / sqrt(g); // More robust to extrapolate derived quantities directly, rather than @@ -1052,19 +1052,19 @@ int Coordinates::jacobian() { J = interpolateAndExtrapolate(J, location, extrapolate_x, extrapolate_y); // Check jacobian - checkFinite(J, "The Jacobian", "RGN_NOCORNERS"); - checkPositive(J, "The Jacobian", "RGN_NOCORNERS"); + bout::checkFinite(J, "The Jacobian", "RGN_NOCORNERS"); + bout::checkPositive(J, "The Jacobian", "RGN_NOCORNERS"); if (min(abs(J)) < 1.0e-10) { throw BoutException("\tERROR: Jacobian becomes very small\n"); } - checkPositive(g_22, "g_22", "RGN_NOCORNERS"); + bout::checkPositive(g_22, "g_22", "RGN_NOCORNERS"); Bxy = sqrt(g_22) / J; Bxy = interpolateAndExtrapolate(Bxy, location, extrapolate_x, extrapolate_y); - checkFinite(Bxy, "Bxy", "RGN_NOCORNERS"); - checkPositive(Bxy, "Bxy", "RGN_NOCORNERS"); + bout::checkFinite(Bxy, "Bxy", "RGN_NOCORNERS"); + bout::checkPositive(Bxy, "Bxy", "RGN_NOCORNERS"); return 0; } From e9199e1210a2ee76fac691905a1ce1d254c72259 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 22 May 2019 17:09:40 +0100 Subject: [PATCH 1461/1783] Add missing test for EnableIfField --- tests/unit/include/bout/test_traits.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/include/bout/test_traits.cxx b/tests/unit/include/bout/test_traits.cxx index 7f475604a5..68b1c2b005 100644 --- a/tests/unit/include/bout/test_traits.cxx +++ b/tests/unit/include/bout/test_traits.cxx @@ -126,4 +126,8 @@ TEST(BoutTraitsTest, EnableIfFieldReturnType) { std::is_same(), std::declval()))>::value, "EnableIfField should return Field3D for a Field2D and a Field3D"); + static_assert( + std::is_same(), + std::declval()))>::value, + "EnableIfField should return Field3D for a Field3D and a Field3D"); } From 5d694512357e10bbf92d976eba065c33893fa0a2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 22 May 2019 21:06:01 +0100 Subject: [PATCH 1462/1783] Only twist-shift field-aligned variables When TwistShift==true, only apply the twist-shift for field-aligned variables. Since #1635 variables in the 'standard' x-z orthogonal coordinates do not require a twist-shift. This change allows field-aligned and orthogonal variables to both be communicated correctly in the same simulation, by setting TwistShift==true. --- src/mesh/impls/bout/boutmesh.cxx | 47 ++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 12b0570c42..13c9fff073 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -1165,28 +1165,33 @@ int BoutMesh::wait(comm_handle handle) { // Perform Twist-shift using shifting method // Loop over 3D fields for (const auto &var : ch->var_list.field3d()) { - // Lower boundary - if (TS_down_in && (DDATA_INDEST != -1)) { - for (jx = 0; jx < DDATA_XSPLIT; jx++) - for (jy = 0; jy != MYG; jy++) - shiftZ(*var, jx, jy, ShiftAngle[jx]); - } - if (TS_down_out && (DDATA_OUTDEST != -1)) { - for (jx = DDATA_XSPLIT; jx < LocalNx; jx++) - for (jy = 0; jy != MYG; jy++) - shiftZ(*var, jx, jy, ShiftAngle[jx]); - } + if (var->getDirectionY() == YDirectionType::Aligned) { + // Only variables in field-aligned coordinates need the twist-shift boundary + // condition to be applied + + // Lower boundary + if (TS_down_in && (DDATA_INDEST != -1)) { + for (jx = 0; jx < DDATA_XSPLIT; jx++) + for (jy = 0; jy != MYG; jy++) + shiftZ(*var, jx, jy, ShiftAngle[jx]); + } + if (TS_down_out && (DDATA_OUTDEST != -1)) { + for (jx = DDATA_XSPLIT; jx < LocalNx; jx++) + for (jy = 0; jy != MYG; jy++) + shiftZ(*var, jx, jy, ShiftAngle[jx]); + } - // Upper boundary - if (TS_up_in && (UDATA_INDEST != -1)) { - for (jx = 0; jx < UDATA_XSPLIT; jx++) - for (jy = LocalNy - MYG; jy != LocalNy; jy++) - shiftZ(*var, jx, jy, -ShiftAngle[jx]); - } - if (TS_up_out && (UDATA_OUTDEST != -1)) { - for (jx = UDATA_XSPLIT; jx < LocalNx; jx++) - for (jy = LocalNy - MYG; jy != LocalNy; jy++) - shiftZ(*var, jx, jy, -ShiftAngle[jx]); + // Upper boundary + if (TS_up_in && (UDATA_INDEST != -1)) { + for (jx = 0; jx < UDATA_XSPLIT; jx++) + for (jy = LocalNy - MYG; jy != LocalNy; jy++) + shiftZ(*var, jx, jy, -ShiftAngle[jx]); + } + if (TS_up_out && (UDATA_OUTDEST != -1)) { + for (jx = UDATA_XSPLIT; jx < LocalNx; jx++) + for (jy = LocalNy - MYG; jy != LocalNy; jy++) + shiftZ(*var, jx, jy, -ShiftAngle[jx]); + } } } } From c788235c286be88800636cc8652c4c3ace97bb4c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 22 May 2019 21:14:57 +0100 Subject: [PATCH 1463/1783] Minor correction of explanation of TwistShift in manual --- manual/sphinx/user_docs/input_grids.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manual/sphinx/user_docs/input_grids.rst b/manual/sphinx/user_docs/input_grids.rst index 38ebf4da5e..501d6e57cc 100644 --- a/manual/sphinx/user_docs/input_grids.rst +++ b/manual/sphinx/user_docs/input_grids.rst @@ -140,8 +140,8 @@ to many other situations. enabled in the options file or in general the ``TwistShift`` flag in ``mesh/impls/bout/boutmesh.hxx`` is enabled by other means. BOUT++ automatically reads the twist shifts in the gridfile if the shifts - are stored in a field in a field ShiftAngle[nx]. If not given, this - is set to zero. + are stored in a field ShiftAngle[nx]; ShiftAngle must be given in the + gridfile or grid-options if ``TwistShift = True``. The only quantities which are required are the sizes of the grid. If these are the only quantities specified, then the coordinates revert to From 30b5155f99d740803734c9077e7d6cedcfdf5431 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 22 May 2019 21:16:34 +0100 Subject: [PATCH 1464/1783] Remove check on twistshift in ShiftedMetric ShiftedMetric is now compatible with twistshift==true, as the twist-shift is now only applied to field-aligned variables. --- src/mesh/parallel/shiftedmetric.cxx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index f88a4ea06e..30a7797175 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -23,16 +23,6 @@ ShiftedMetric::ShiftedMetric(Mesh& m, CELL_LOC location_in, Field2D zShift_, // check the coordinate system used for the grid data source ShiftedMetric::checkInputGrid(); - // TwistShift should not be set for derivatives to be correct at the jump where - // poloidal angle theta goes 2pi->0. zShift has been corrected for the jump - // already in Coordinates::Coordinates - bool twistshift = Options::root()["TwistShift"] - .doc("Enable twist-shift boundary condition in core region?") - .withDefault(false); - if (twistshift) { - throw BoutException("ShiftedMetric requires the option TwistShift=false"); - } - cachePhases(); } From 3be469e7cfbe2659fa76a863efaf721b5dcbbda2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 22 May 2019 21:17:37 +0100 Subject: [PATCH 1465/1783] Remove unused variable from InvertParCR --- src/invert/parderiv/impls/cyclic/cyclic.cxx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index 2d27bf9a77..43c6bb5a8a 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -71,9 +71,8 @@ const Field3D InvertParCR::solve(const Field3D &f) { int size = localmesh->LocalNy - 2 * localmesh->ystart; SurfaceIter surf(localmesh); for(surf.first(); !surf.isDone(); surf.next()) { - BoutReal ts; int n = localmesh->LocalNy - 2 * localmesh->ystart; - if (!surf.closed(ts)) { + if (!surf.closed()) { // Open field line if (surf.firstY()) n += localmesh->ystart; From 3d6ebd9e1f10f888afb72e96bd34402adfa85ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Thu, 23 May 2019 06:01:09 +0100 Subject: [PATCH 1466/1783] make sure values() returns valid pointer --- src/fileio/impls/netcdf/nc_format.cxx | 36 ++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/fileio/impls/netcdf/nc_format.cxx b/src/fileio/impls/netcdf/nc_format.cxx index 461e3dd7e5..f84611a4e2 100644 --- a/src/fileio/impls/netcdf/nc_format.cxx +++ b/src/fileio/impls/netcdf/nc_format.cxx @@ -1229,7 +1229,11 @@ bool NcFormat::getAttribute(const std::string &varname, const std::string &attrn return false; } - text = fileAtt->values()->as_string(0); + auto values = fileAtt->values(); + if (values == nullptr) + return false; + + text = values->as_string(0); return true; } else { @@ -1243,7 +1247,11 @@ bool NcFormat::getAttribute(const std::string &varname, const std::string &attrn return false; } - text = varAtt->values()->as_string(0); + auto values = varAtt->values(); + if (values == nullptr) + return false; + + text = values->as_string(0); return true; } @@ -1265,7 +1273,11 @@ bool NcFormat::getAttribute(const std::string &varname, const std::string &attrn return false; } - value = fileAtt->values()->as_int(0); + auto values = fileAtt->values(); + if (values == nullptr) + return false; + + value = values->as_int(0); return true; } else { @@ -1279,7 +1291,11 @@ bool NcFormat::getAttribute(const std::string &varname, const std::string &attrn if (!(varAtt = var->get_att(attrname.c_str()))) return false; - value = varAtt->values()->as_int(0); + auto values = varAtt->values(); + if (values == nullptr) + return false; + + value = values->as_int(0); return true; } @@ -1301,7 +1317,11 @@ bool NcFormat::getAttribute(const std::string &varname, const std::string &attrn return false; } - value = fileAtt->values()->as_double(0); + auto values = fileAtt->values(); + if (values == nullptr) + return false; + + value = values->as_double(0); return true; } else { @@ -1315,7 +1335,11 @@ bool NcFormat::getAttribute(const std::string &varname, const std::string &attrn if (!(varAtt = var->get_att(attrname.c_str()))) return false; - value = varAtt->values()->as_double(0); + auto values = varAtt->values(); + if (values == nullptr) + return false; + + value = values->as_double(0); return true; } From bb289d97258ac9ad6688aa33ce08388987e42e78 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 23 May 2019 09:49:50 +0100 Subject: [PATCH 1467/1783] Deprecate MsgStack::setPoint Fixes #1149 --- include/msg_stack.hxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/msg_stack.hxx b/include/msg_stack.hxx index d59b9ad58a..1b84d24d2e 100644 --- a/include/msg_stack.hxx +++ b/include/msg_stack.hxx @@ -72,6 +72,7 @@ public: int push(const char *s, ...) BOUT_FORMAT_ARGS( 2, 3); ///< Add a message to the stack. Returns a message id + [[gnu::deprecated("Please use `MsgStack::push` with an empty message instead")]] int setPoint(); ///< get a message point void pop(); ///< Remove the last message @@ -84,6 +85,7 @@ public: /// Dummy functions which should be optimised out int push(const char *UNUSED(s), ...) { return 0; } + [[gnu::deprecated("Please use `MsgStack::push` with an empty message instead")]] int setPoint() { return 0; } void pop() {} From f3f0425d146947c65cbc08d82618d884bc04c8b7 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 23 May 2019 10:44:52 +0100 Subject: [PATCH 1468/1783] Enable different twist-shift behaviour for different ParallelTransforms Where the twist-shift is applied during communications in BoutMesh::wait(), instead of just checking the TwistShift flag, pass the flag to a new twistShift(bool twist_shift_enabled) method of Field3D, that then calls a twistShift method of ParallelTransform with both the value of the TwistShift flag, and the y-direction type (standard or aligned) of the Field3D. This enables us to have different behaviour depending on the ParallelTransform: - ParallelTransformIdentity twist-shifts all fields if TwistShift=true, or none if TwistShift=false (this keeps the old behaviour of TwistShift). - ShiftedMetric twist-shifts only field-aligned fields, throwing an exception if TwistShift=false and the field is field-aligned. - FCI never twist-shifts as there cannot be field-aligned variables. --- include/bout/paralleltransform.hxx | 24 ++++++++++++++++++++++++ include/field3d.hxx | 3 +++ src/field/field3d.cxx | 5 +++++ src/mesh/impls/bout/boutmesh.cxx | 12 +++++++----- src/mesh/parallel/fci.hxx | 7 +++++++ 5 files changed, 46 insertions(+), 5 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 342f353e87..bdae1d4384 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -56,6 +56,9 @@ public: virtual bool canToFromFieldAligned() = 0; + /// Does a Field3D with ytype require a twist-shift at branch cuts on closed field lines? + virtual bool twistShift(bool twist_shift_enabled, YDirectionType ytype) = 0; + protected: /// This method should be called in the constructor to check that if the grid /// has a 'coordinates_type' variable, it has the correct value @@ -110,6 +113,12 @@ public: bool canToFromFieldAligned() override { return true; } + bool twistShift(bool twist_shift_enabled, YDirectionType UNUSED(ytype)) { + // All Field3Ds require twist-shift, because all are effectively field-aligned, but + // allow twist-shift to be turned off by twist_shift_enabled + return twist_shift_enabled; + } + protected: void checkInputGrid() override; }; @@ -156,6 +165,21 @@ public: bool canToFromFieldAligned() override { return true; } + bool twistShift(bool twist_shift_enabled, YDirectionType ytype) { + // Twist-shift only if field-aligned + + if (ytype == YDirectionType::Aligned) { + // Twist-shift is required if field-aligned + if (not twist_shift_enabled) { + throw BoutException("'TwistShift = true' is required to communicate " + "field-aligned Field3Ds when using ShiftedMetric."); + } + return true; + } else { + return false; + } + } + protected: void checkInputGrid() override; diff --git a/include/field3d.hxx b/include/field3d.hxx index e6611cc843..088b9bd855 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -297,6 +297,9 @@ class Field3D : public Field, public FieldData { Field3D& ynext(int offset); const Field3D& ynext(int offset) const; + /// Does the field require a twist-shift at branch cuts on closed field lines? + bool twistShift(bool twist_shift_enabled); + ///////////////////////////////////////////////////////// // Data access diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 2906bddba2..1eaa6ccf0a 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -208,6 +208,11 @@ Field3D &Field3D::ynext(int dir) { return const_cast(static_cast(*this).ynext(dir)); } +bool Field3D::twistShift(bool twist_shift_enabled) { + return getCoordinates()->getParallelTransform().twistShift(twist_shift_enabled, + getDirectionY()); +} + // Not in header because we need to access fieldmesh BoutReal &Field3D::operator()(const IndPerp &d, int jy) { return operator[](fieldmesh->indPerpto3D(d, jy)); diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 13c9fff073..1e17f977ab 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -1159,12 +1159,14 @@ int BoutMesh::wait(comm_handle handle) { } // TWIST-SHIFT CONDITION - if (TwistShift) { - int jx, jy; + // Loop over 3D fields + for (const auto &var : ch->var_list.field3d()) { + if (var->twistShift(TwistShift)) { + + // Twist-shift only needed for field-aligned fields + int jx, jy; - // Perform Twist-shift using shifting method - // Loop over 3D fields - for (const auto &var : ch->var_list.field3d()) { + // Perform Twist-shift using shifting method if (var->getDirectionY() == YDirectionType::Aligned) { // Only variables in field-aligned coordinates need the twist-shift boundary // condition to be applied diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index 5a95076c0e..0c191dfd52 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -109,6 +109,13 @@ public: bool canToFromFieldAligned() override { return false; } + bool twistShift(bool UNUSED(twist_shift_enabled), MAYBE_UNUSED(YDirectionType ytype)) { + // No Field3Ds require twist-shift, because they cannot be field-aligned + ASSERT1(ytype == YDirectionType::Standard); + + return false; + } + protected: void checkInputGrid() override; From 7a2ba2cf0d60231c1dbb2ca21cf9b274702e1ca2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 23 May 2019 11:07:20 +0100 Subject: [PATCH 1469/1783] Deprecate some unused experimental Mesh methods Fixes some more of #734 --- include/bout/mesh.hxx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 8d6b906036..d861bcaa86 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -276,6 +276,7 @@ class Mesh { /// @param[in] buffer A buffer of data to send /// @param[in] size The length of \p buffer /// @param[in] tag A label, must be the same at receive + [[gnu::deprecated("This experimental functionality will be removed in 5.0")]] virtual MPI_Request sendToProc(int xproc, int yproc, BoutReal *buffer, int size, int tag) = 0; /// Low-level communication routine @@ -288,6 +289,7 @@ class Mesh { /// @param[inout] buffer The buffer to fill with data. Must already be allocated of length \p size /// @param[in] size The length of \p buffer /// @param[in] tag A label, must be the same as send + [[gnu::deprecated("This experimental functionality will be removed in 5.0")]] virtual comm_handle receiveFromProc(int xproc, int yproc, BoutReal *buffer, int size, int tag) = 0; virtual int getNXPE() = 0; ///< The number of processors in the X direction @@ -370,19 +372,25 @@ class Mesh { virtual bool lastY() const = 0; ///< Is this processor last in Y? i.e. is there a boundary at upper Y? virtual bool firstY(int xpos) const = 0; ///< Is this processor first in Y? i.e. is there a boundary at lower Y? virtual bool lastY(int xpos) const = 0; ///< Is this processor last in Y? i.e. is there a boundary at upper Y? + [[gnu::deprecated("This experimental functionality will be removed in 5.0")]] virtual int UpXSplitIndex() = 0; ///< If the upper Y guard cells are split in two, return the X index where the split occurs + [[gnu::deprecated("This experimental functionality will be removed in 5.0")]] virtual int DownXSplitIndex() = 0; ///< If the lower Y guard cells are split in two, return the X index where the split occurs /// Send data + [[gnu::deprecated("This experimental functionality will be removed in 5.0")]] virtual int sendYOutIndest(BoutReal *buffer, int size, int tag) = 0; - /// + /// + [[gnu::deprecated("This experimental functionality will be removed in 5.0")]] virtual int sendYOutOutdest(BoutReal *buffer, int size, int tag) = 0; /// + [[gnu::deprecated("This experimental functionality will be removed in 5.0")]] virtual int sendYInIndest(BoutReal *buffer, int size, int tag) = 0; /// + [[gnu::deprecated("This experimental functionality will be removed in 5.0")]] virtual int sendYInOutdest(BoutReal *buffer, int size, int tag) = 0; /// Non-blocking receive. Must be followed by a call to wait() @@ -390,6 +398,7 @@ class Mesh { /// @param[out] buffer A buffer of length \p size which must already be allocated /// @param[in] size The number of BoutReals expected /// @param[in] tag The tag number of the expected message + [[gnu::deprecated("This experimental functionality will be removed in 5.0")]] virtual comm_handle irecvYOutIndest(BoutReal *buffer, int size, int tag) = 0; /// Non-blocking receive. Must be followed by a call to wait() @@ -397,6 +406,7 @@ class Mesh { /// @param[out] buffer A buffer of length \p size which must already be allocated /// @param[in] size The number of BoutReals expected /// @param[in] tag The tag number of the expected message + [[gnu::deprecated("This experimental functionality will be removed in 5.0")]] virtual comm_handle irecvYOutOutdest(BoutReal *buffer, int size, int tag) = 0; /// Non-blocking receive. Must be followed by a call to wait() @@ -404,6 +414,7 @@ class Mesh { /// @param[out] buffer A buffer of length \p size which must already be allocated /// @param[in] size The number of BoutReals expected /// @param[in] tag The tag number of the expected message + [[gnu::deprecated("This experimental functionality will be removed in 5.0")]] virtual comm_handle irecvYInIndest(BoutReal *buffer, int size, int tag) = 0; /// Non-blocking receive. Must be followed by a call to wait() @@ -411,6 +422,7 @@ class Mesh { /// @param[out] buffer A buffer of length \p size which must already be allocated /// @param[in] size The number of BoutReals expected /// @param[in] tag The tag number of the expected message + [[gnu::deprecated("This experimental functionality will be removed in 5.0")]] virtual comm_handle irecvYInOutdest(BoutReal *buffer, int size, int tag) = 0; // Boundary region iteration From 69c4871b6414e87e7c11bc4d811afdf0a99e2513 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 23 May 2019 14:12:53 +0100 Subject: [PATCH 1470/1783] Add test for BoutMesh decomposition on single processor This test will fail; next commit fixes bug --- tests/unit/mesh/test_boutmesh.cxx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/unit/mesh/test_boutmesh.cxx b/tests/unit/mesh/test_boutmesh.cxx index 7924ea566f..5a7fcd1975 100644 --- a/tests/unit/mesh/test_boutmesh.cxx +++ b/tests/unit/mesh/test_boutmesh.cxx @@ -4,6 +4,7 @@ #include "bout/mesh.hxx" #include "output.hxx" #include "unused.hxx" +#include "bout/griddata.hxx" #include "test_extras.hxx" @@ -14,4 +15,20 @@ TEST(BoutMeshTest, NullOptionsCheck) { EXPECT_NO_THROW(BoutMesh mesh(new FakeGridDataSource, nullptr)); output_info.enable(); output_warn.enable(); +// Not a great test as it's not specific to the thing we want to test, +// and also takes a whopping ~300ms! +TEST(BoutMeshTest, SingleCoreDecomposition) { + WithQuietOutput info{output_info}; + WithQuietOutput warn{output_warn}; + WithQuietOutput progress{output_progress}; + + Options options{}; + options["ny"] = 1; + options["nx"] = 4; + options["nz"] = 1; + options["MXG"] = 1; + options["MYG"] = 0; + + BoutMesh mesh{new GridFromOptions{&options}, &options}; + EXPECT_NO_THROW(mesh.load()); } From 3714de4ed0e65f0ca2db6250f4e803068f2f9128 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 23 May 2019 14:14:21 +0100 Subject: [PATCH 1471/1783] Fix #1537: BoutMesh decomposition fails on one processor --- src/mesh/impls/bout/boutmesh.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 12b0570c42..8a35796702 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -333,8 +333,8 @@ int BoutMesh::load() { int nyp = NPES / i; int ysub = ny / nyp; - // Check size of Y mesh - if (ysub < MYG) { + // Check size of Y mesh if we've got multiple processors + if (ysub < MYG and NPES != 1) { output_info.write(_("\t -> ny/NYPE (%d/%d = %d) must be >= MYG (%d)\n"), ny, nyp, ysub, MYG); continue; From 4f78772ab22e86666bc144e395daff193521634c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 23 May 2019 14:15:18 +0100 Subject: [PATCH 1472/1783] Make some local variables const in BoutMesh; use braces with if --- src/mesh/impls/bout/boutmesh.cxx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 8a35796702..bad617440d 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -319,7 +319,8 @@ int BoutMesh::load() { NXPE = -1; // Best option - BoutReal ideal = sqrt(MX * NPES / static_cast(ny)); // Results in square domains + // Results in square domains + const BoutReal ideal = sqrt(MX * NPES / static_cast(ny)); output_info.write(_("Finding value for NXPE (ideal = %f)\n"), ideal); @@ -330,8 +331,8 @@ int BoutMesh::load() { output_info.write(_("\tCandidate value: %d\n"), i); - int nyp = NPES / i; - int ysub = ny / nyp; + const int nyp = NPES / i; + const int ysub = ny / nyp; // Check size of Y mesh if we've got multiple processors if (ysub < MYG and NPES != 1) { @@ -395,8 +396,9 @@ int BoutMesh::load() { } output_info.write(_("\t -> Good value\n")); // Found an acceptable value - if ((NXPE < 1) || (fabs(ideal - i) < fabs(ideal - NXPE))) + if ((NXPE < 1) || (fabs(ideal - i) < fabs(ideal - NXPE))) { NXPE = i; // Keep value nearest to the ideal + } } } From 5f039d4faf121890dfdea706e1133efb8cb6fb09 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 23 May 2019 14:15:36 +0100 Subject: [PATCH 1473/1783] Clang-format and tidy BoutMesh unit test --- tests/unit/mesh/test_boutmesh.cxx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/unit/mesh/test_boutmesh.cxx b/tests/unit/mesh/test_boutmesh.cxx index 5a7fcd1975..3c218a5131 100644 --- a/tests/unit/mesh/test_boutmesh.cxx +++ b/tests/unit/mesh/test_boutmesh.cxx @@ -1,20 +1,19 @@ #include "gtest/gtest.h" #include "../src/mesh/impls/bout/boutmesh.hxx" -#include "bout/mesh.hxx" +#include "options.hxx" #include "output.hxx" -#include "unused.hxx" #include "bout/griddata.hxx" #include "test_extras.hxx" TEST(BoutMeshTest, NullOptionsCheck) { - // Temporarily turn off outputs to make test quiet - output_info.disable(); - output_warn.disable(); + WithQuietOutput info{output_info}; + WithQuietOutput warn{output_warn}; + EXPECT_NO_THROW(BoutMesh mesh(new FakeGridDataSource, nullptr)); - output_info.enable(); - output_warn.enable(); +} + // Not a great test as it's not specific to the thing we want to test, // and also takes a whopping ~300ms! TEST(BoutMeshTest, SingleCoreDecomposition) { From 05bb259714634198705561f2c0393b4c19d30938 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 23 May 2019 14:35:16 +0100 Subject: [PATCH 1474/1783] Output ParallelTransform variables Add a method outputVars(Datafile& file) to ParallelTransform, which is called from Coordinates::outputVars(Datafile& file) so that the ParallelTransform implementations can output variables to the dump files. Now ShiftedMetric saves zShift. --- include/bout/paralleltransform.hxx | 6 ++++++ src/mesh/coordinates.cxx | 2 ++ src/mesh/parallel/shiftedmetric.cxx | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 342f353e87..9a79b5d155 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -56,6 +56,9 @@ public: virtual bool canToFromFieldAligned() = 0; + /// Output variables used by a ParallelTransform instance to the dump files + virtual void outputVars(Datafile& UNUSED(file)) {} + protected: /// This method should be called in the constructor to check that if the grid /// has a 'coordinates_type' variable, it has the correct value @@ -156,6 +159,9 @@ public: bool canToFromFieldAligned() override { return true; } + /// Save zShift to the output + void outputVars(Datafile& file) override; + protected: void checkInputGrid() override; diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 287bdc6559..ebd07afe7f 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -652,6 +652,8 @@ void Coordinates::outputVars(Datafile& file) { file.addOnce(g_23, "g_23" + loc_string); file.addOnce(J, "J" + loc_string); + + getParallelTransform().outputVars(file); } int Coordinates::geometry(bool recalculate_staggered, diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index f88a4ea06e..8cdc95977d 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -48,6 +48,12 @@ void ShiftedMetric::checkInputGrid() { // file so must rely on the user having ensured the type is correct } +void ShiftedMetric::outputVars(Datafile& file) { + const std::string loc_string = (location == CELL_CENTRE) ? "" : "_"+toString(location); + + file.addOnce(zShift, "zShift" + loc_string); +} + void ShiftedMetric::cachePhases() { // If we wanted to be efficient we could move the following cached phase setup // into the relevant shifting routines (with static bool first protection) From c0959d518f257f2a07ed72c25e933c37bc4325df Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 23 May 2019 14:45:15 +0100 Subject: [PATCH 1475/1783] Rename twistShift methods to requiresTwistShift Renaming makes it clear that this method is a query, and does not change the object. --- include/bout/paralleltransform.hxx | 9 +++++---- include/field3d.hxx | 5 +++-- src/field/field3d.cxx | 4 ++-- src/mesh/impls/bout/boutmesh.cxx | 2 +- src/mesh/parallel/fci.hxx | 2 +- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index bdae1d4384..0c32a53456 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -56,8 +56,9 @@ public: virtual bool canToFromFieldAligned() = 0; - /// Does a Field3D with ytype require a twist-shift at branch cuts on closed field lines? - virtual bool twistShift(bool twist_shift_enabled, YDirectionType ytype) = 0; + /// If \p twist_shift_enabled is true, does a `Field3D` with Y direction \p ytype + /// require a twist-shift at branch cuts on closed field lines? + virtual bool requiresTwistShift(bool twist_shift_enabled, YDirectionType ytype) = 0; protected: /// This method should be called in the constructor to check that if the grid @@ -113,7 +114,7 @@ public: bool canToFromFieldAligned() override { return true; } - bool twistShift(bool twist_shift_enabled, YDirectionType UNUSED(ytype)) { + bool requiresTwistShift(bool twist_shift_enabled, YDirectionType UNUSED(ytype)) override { // All Field3Ds require twist-shift, because all are effectively field-aligned, but // allow twist-shift to be turned off by twist_shift_enabled return twist_shift_enabled; @@ -165,7 +166,7 @@ public: bool canToFromFieldAligned() override { return true; } - bool twistShift(bool twist_shift_enabled, YDirectionType ytype) { + bool requiresTwistShift(bool twist_shift_enabled, YDirectionType ytype) override { // Twist-shift only if field-aligned if (ytype == YDirectionType::Aligned) { diff --git a/include/field3d.hxx b/include/field3d.hxx index 088b9bd855..2f689d2edd 100644 --- a/include/field3d.hxx +++ b/include/field3d.hxx @@ -297,8 +297,9 @@ class Field3D : public Field, public FieldData { Field3D& ynext(int offset); const Field3D& ynext(int offset) const; - /// Does the field require a twist-shift at branch cuts on closed field lines? - bool twistShift(bool twist_shift_enabled); + /// If \p twist_shift_enabled is true, does this Field3D require a twist-shift at branch + /// cuts on closed field lines? + bool requiresTwistShift(bool twist_shift_enabled); ///////////////////////////////////////////////////////// // Data access diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 1eaa6ccf0a..4b549c9554 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -208,8 +208,8 @@ Field3D &Field3D::ynext(int dir) { return const_cast(static_cast(*this).ynext(dir)); } -bool Field3D::twistShift(bool twist_shift_enabled) { - return getCoordinates()->getParallelTransform().twistShift(twist_shift_enabled, +bool Field3D::requiresTwistShift(bool twist_shift_enabled) { + return getCoordinates()->getParallelTransform().requiresTwistShift(twist_shift_enabled, getDirectionY()); } diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 1e17f977ab..001ffcea4e 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -1161,7 +1161,7 @@ int BoutMesh::wait(comm_handle handle) { // TWIST-SHIFT CONDITION // Loop over 3D fields for (const auto &var : ch->var_list.field3d()) { - if (var->twistShift(TwistShift)) { + if (var->requiresTwistShift(TwistShift)) { // Twist-shift only needed for field-aligned fields int jx, jy; diff --git a/src/mesh/parallel/fci.hxx b/src/mesh/parallel/fci.hxx index 0c191dfd52..d449600698 100644 --- a/src/mesh/parallel/fci.hxx +++ b/src/mesh/parallel/fci.hxx @@ -109,7 +109,7 @@ public: bool canToFromFieldAligned() override { return false; } - bool twistShift(bool UNUSED(twist_shift_enabled), MAYBE_UNUSED(YDirectionType ytype)) { + bool requiresTwistShift(bool UNUSED(twist_shift_enabled), MAYBE_UNUSED(YDirectionType ytype)) override { // No Field3Ds require twist-shift, because they cannot be field-aligned ASSERT1(ytype == YDirectionType::Standard); From bcf5adbe0965adf9fa82172c4d6fe895f1a7d24c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 23 May 2019 14:51:03 +0100 Subject: [PATCH 1476/1783] Clean up ShiftedMetric::requiresTwistShift --- include/bout/paralleltransform.hxx | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 0c32a53456..286f84519e 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -168,17 +168,11 @@ public: bool requiresTwistShift(bool twist_shift_enabled, YDirectionType ytype) override { // Twist-shift only if field-aligned - - if (ytype == YDirectionType::Aligned) { - // Twist-shift is required if field-aligned - if (not twist_shift_enabled) { - throw BoutException("'TwistShift = true' is required to communicate " - "field-aligned Field3Ds when using ShiftedMetric."); - } - return true; - } else { - return false; + if (ytype == YDirectionType::Aligned and not twist_shift_enabled) { + throw BoutException("'TwistShift = true' is required to communicate field-aligned " + "Field3Ds when using ShiftedMetric."); } + return ytype == YDirectionType::Aligned; } protected: From d7dbf3274c206a2c8623f4d4b4d78c8e49a1fbf4 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 23 May 2019 14:57:47 +0100 Subject: [PATCH 1477/1783] Update manual with more detail about TwistShift --- .../sphinx/user_docs/parallel-transforms.rst | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/manual/sphinx/user_docs/parallel-transforms.rst b/manual/sphinx/user_docs/parallel-transforms.rst index af2aca34cf..74ae47423f 100644 --- a/manual/sphinx/user_docs/parallel-transforms.rst +++ b/manual/sphinx/user_docs/parallel-transforms.rst @@ -54,8 +54,8 @@ a second derivative along Y using the Field3D iterators (section Note the use of yp() and ym() to increase and decrease the Y index. -Slab geometries ---------------- +Field-aligned grid +------------------ The default `ParallelTransform` is the identity transform, which sets yup() and ydown() to point to the same field. In the input options the @@ -70,6 +70,20 @@ setting is This then uses the `ParallelTransformIdentity` class to calculate the yup and ydown fields. +This is mostly useful for slab geometries, where for a straight magnetic field +the grid is either periodic in the y-direction or ends on a y-boundary. By +setting the global option ``TwistShift = true`` and providing a ``ShiftAngle`` +in the gridfile or ``[mesh]`` options a branch cut can be introduced between +the beginning and end of the y-domain. + +`ParallelTransformIdentity` can also be used in non-slab geometries. Then +``TwistShift = true`` should be set so that a twist-shift boundary condition is +applied on closed field lines, as field-line following coordinates are not +periodic in poloidal angle. Note that it is not recommended to use +`ParallelTransformIdentity` with toroidal geometries, as magnetic shear will +make the radial derivatives inaccurate away from the outboard midplane (which +is normall chosen as the zero point for the integrated shear). + Shifted metric -------------- From ad4bc06f5798139eefd330034b68cfc5e9051a4e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 23 May 2019 16:50:56 +0100 Subject: [PATCH 1478/1783] Integrated test for twist-shift --- .../integrated/test-twistshift/data/BOUT.inp | 15 +++++ tests/integrated/test-twistshift/makefile | 5 ++ tests/integrated/test-twistshift/runtest | 64 +++++++++++++++++++ .../test-twistshift/test-twistshift.cxx | 32 ++++++++++ 4 files changed, 116 insertions(+) create mode 100644 tests/integrated/test-twistshift/data/BOUT.inp create mode 100644 tests/integrated/test-twistshift/makefile create mode 100755 tests/integrated/test-twistshift/runtest create mode 100644 tests/integrated/test-twistshift/test-twistshift.cxx diff --git a/tests/integrated/test-twistshift/data/BOUT.inp b/tests/integrated/test-twistshift/data/BOUT.inp new file mode 100644 index 0000000000..87a058f6c2 --- /dev/null +++ b/tests/integrated/test-twistshift/data/BOUT.inp @@ -0,0 +1,15 @@ +twistshift = true + +test = sin(y) * (x+0.2)^2 * cos(z) + +[mesh] +paralleltransform = shifted +nx = 5 +ny = 7 +nz = 5 + +zShift = (y-0.5) * (x+1) +ShiftAngle = (x+1) + +[input] +transform_from_field_aligned = false diff --git a/tests/integrated/test-twistshift/makefile b/tests/integrated/test-twistshift/makefile new file mode 100644 index 0000000000..0018135bce --- /dev/null +++ b/tests/integrated/test-twistshift/makefile @@ -0,0 +1,5 @@ +BOUT_TOP = ../../.. + +SOURCEC = test-twistshift.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-twistshift/runtest b/tests/integrated/test-twistshift/runtest new file mode 100755 index 0000000000..24dd0490e2 --- /dev/null +++ b/tests/integrated/test-twistshift/runtest @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +from boutdata import collect +from boututils.run_wrapper import launch_safe, shell_safe +import numpy +from sys import exit + +datapath = 'data' +nproc = 1 +tol = 1.e-13 + +print('Making twistshift test') +shell_safe('make > make.log') + +s, out = launch_safe('./test-twistshift', nproc=nproc, pipe=True) +with open("run.log."+str(nproc), "w") as f: + f.write(out) + +test = collect('test', path=datapath, yguards=True, info=False) +test_aligned = collect('test_aligned', path=datapath, yguards=True, info=False) +result = collect('result', path=datapath, yguards=True, info=False) + +#from boututils.showdata import showdata +#showdata([test, test_aligned, result], titles=['test', 'test_aligned', 'result']) + +success = True + +# Check test_aligned is *not* periodic in y +def test1(ylower, yupper): + global success + if numpy.any(numpy.abs(test_aligned[:, yupper, :] - test_aligned[:, ylower, :]) < 1.e-6): + success = False + print("Fail - test_aligned should not be periodic jy=%i and jy=%i should be " + "different", yupper, ylower) +test1(0,-4) +test1(1,-3) +test1(2,-2) +test1(3,-1) + +# Check test and result are the same +if numpy.any(numpy.abs(result - test) > tol): + print("Fail - result has not been communicated correctly - is different from input") + success = False + +# Check result is periodic in y +def test2(ylower, yupper): + global success + if numpy.any(numpy.abs(result[:, yupper, :] - result[:, ylower, :]) > tol): + success = False + print("Fail - result should be periodic jy=%i and jy=%i should not be " + "different", yupper, ylower) + print(ylower, result[:, ylower, :]) + print(yupper, result[:, yupper, :]) + print(result[:, ylower, :] - result[:, yupper, :]) +test2(0,-4) +test2(1,-3) +test2(2,-2) +test2(3,-1) + +if success: + print('Pass') + exit(0) +else: + exit(1) diff --git a/tests/integrated/test-twistshift/test-twistshift.cxx b/tests/integrated/test-twistshift/test-twistshift.cxx new file mode 100644 index 0000000000..3a1cb47355 --- /dev/null +++ b/tests/integrated/test-twistshift/test-twistshift.cxx @@ -0,0 +1,32 @@ +#include "bout.hxx" +#include "field_factory.hxx" + +int main(int argc, char** argv) { + BoutInitialise(argc, argv); + + Field3D test = FieldFactory::get()->create3D("test"); + + Field3D test_aligned = toFieldAligned(test); + + // zero guard cells to check that communication is doing something + for (int x=0; xLocalNx; x++) { + for (int z=0; zLocalNz; z++) { + for (int y=0; yystart; y++) { + test_aligned(x, y, z) = 0.; + } + for (int y=mesh->yend+1; yLocalNy; y++) { + test_aligned(x, y, z) = 0.; + } + } + } + + mesh->communicate(test_aligned); + + Field3D result = fromFieldAligned(test_aligned); + + SAVE_ONCE(test, test_aligned, result); + + dump.write(); + + BoutFinalise(); +} From 9d9af68ff776f4c1551d754435cccaf37a550a7d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 23 May 2019 17:39:39 +0100 Subject: [PATCH 1479/1783] Remove unnecessary toString() in index_derivs_interface.hxx --- include/bout/index_derivs_interface.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 4a427016e7..78639e0713 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -317,7 +317,7 @@ T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, const T vel_aligned = toFieldAligned(vel, "RGN_NOX"); T result = flowDerivative(vel_aligned, f_aligned, outloc, method, region); - return fromFieldAligned(result, toString(region)); + return fromFieldAligned(result, region); } } @@ -337,7 +337,7 @@ T FDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, const T vel_aligned = toFieldAligned(vel, "RGN_NOX"); T result = flowDerivative(vel_aligned, f_aligned, outloc, method, region); - return fromFieldAligned(result, toString(region)); + return fromFieldAligned(result, region); } } From 0d62e5c317085c10e7d8e01023781d6160e5b59e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 23 May 2019 17:41:42 +0100 Subject: [PATCH 1480/1783] Remove const from return types of derivative functions --- include/derivs.hxx | 94 +++++++++++++++++++++++----------------------- src/sys/derivs.cxx | 78 +++++++++++++++++++------------------- 2 files changed, 86 insertions(+), 86 deletions(-) diff --git a/include/derivs.hxx b/include/derivs.hxx index 50aa6e9933..a29af56b8b 100644 --- a/include/derivs.hxx +++ b/include/derivs.hxx @@ -43,14 +43,14 @@ [[gnu::deprecated("Please use #func(const #T& f, CELL_LOC outloc = CELL_DEFAULT, " \ "const std::string& method = \"DEFAULT\", const std::string& region = \"RGN_ALL\") " \ "instead")]] \ -inline const T func(const T& f, CELL_LOC outloc, const std::string& method, \ +inline T func(const T& f, CELL_LOC outloc, const std::string& method, \ REGION region) { \ return func(f, outloc, method, toString(region)); \ } \ [[gnu::deprecated("Please use #func(const #T& f, CELL_LOC outloc = CELL_DEFAULT, " \ "const std::string& method = \"DEFAULT\", const std::string& region = \"RGN_ALL\") " \ "instead")]] \ -inline const T func(const T& f, CELL_LOC outloc, DIFF_METHOD method, \ +inline T func(const T& f, CELL_LOC outloc, DIFF_METHOD method, \ REGION region = RGN_NOBNDRY) { \ return func(f, outloc, toString(method), toString(region)); \ } @@ -63,14 +63,14 @@ inline const T func(const T& f, CELL_LOC outloc, DIFF_METHOD method, \ [[gnu::deprecated("Please use #func(const #T1 v, const #T2& f, " \ "CELL_LOC outloc = CELL_DEFAULT, const std::string& method = \"DEFAULT\", const " \ "std::string& region = \"RGN_ALL\") instead")]] \ -inline const T func(const T1& v, const T2& f, CELL_LOC outloc, const std::string& method, \ +inline T func(const T1& v, const T2& f, CELL_LOC outloc, const std::string& method, \ REGION region) { \ return func(v, f, outloc, method, toString(region)); \ } \ [[gnu::deprecated("Please use #func(const #T& f, CELL_LOC outloc = CELL_DEFAULT, " \ "const std::string& method = \"DEFAULT\", const std::string& region = \"RGN_ALL\") " \ "instead")]] \ -inline const T func(const T1& v, const T2& f, CELL_LOC outloc, DIFF_METHOD method, \ +inline T func(const T1& v, const T2& f, CELL_LOC outloc, DIFF_METHOD method, \ REGION region = RGN_NOBNDRY) { \ return func(v, f, outloc, toString(method), toString(region)); \ } @@ -90,7 +90,7 @@ inline const T func(const T1& v, const T2& f, CELL_LOC outloc, DIFF_METHOD metho /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D DDX(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field3D DDX(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(DDX, Field3D) @@ -106,7 +106,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(DDX, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field2D DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(DDX, Field2D) @@ -122,7 +122,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(DDX, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D DDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field3D DDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(DDY, Field3D) @@ -138,7 +138,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(DDY, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field2D DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(DDY, Field2D) @@ -154,7 +154,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(DDY, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D DDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field3D DDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(DDZ, Field3D) @@ -170,7 +170,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(DDZ, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field2D DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(DDZ, Field2D) @@ -186,7 +186,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(DDZ, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Vector3D DDZ(const Vector3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Vector3D DDZ(const Vector3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(DDZ, Vector3D) @@ -202,7 +202,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(DDZ, Vector3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Vector2D DDZ(const Vector2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Vector2D DDZ(const Vector2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(DDZ, Vector2D) @@ -220,7 +220,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(DDZ, Vector2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DX2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field3D D2DX2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D2DX2, Field3D) @@ -236,7 +236,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D2DX2, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DX2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field2D D2DX2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D2DX2, Field2D) @@ -252,7 +252,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D2DX2, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DY2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field3D D2DY2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D2DY2, Field3D) @@ -268,7 +268,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D2DY2, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DY2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field2D D2DY2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D2DY2, Field2D) @@ -284,7 +284,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D2DY2, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DZ2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field3D D2DZ2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D2DZ2, Field3D) @@ -300,7 +300,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D2DZ2, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DZ2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field2D D2DZ2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D2DZ2, Field2D) @@ -318,7 +318,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D2DZ2, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D4DX4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field3D D4DX4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D4DX4, Field3D) @@ -334,7 +334,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D4DX4, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D4DX4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field2D D4DX4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D4DX4, Field2D) @@ -350,7 +350,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D4DX4, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D4DY4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field3D D4DY4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D4DY4, Field3D) @@ -366,7 +366,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D4DY4, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D4DY4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field2D D4DY4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D4DY4, Field2D) @@ -382,7 +382,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D4DY4, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D4DZ4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field3D D4DZ4(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D4DZ4, Field3D) @@ -398,7 +398,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D4DZ4, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D4DZ4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field2D D4DZ4(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D4DZ4, Field2D) @@ -415,7 +415,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D4DZ4, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D VDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, +Field3D VDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDX, Field3D, Field3D, Field3D) @@ -432,7 +432,7 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDX, Field3D, Field3D, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D VDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, +Field2D VDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDX, Field2D, Field2D, Field2D) @@ -449,7 +449,7 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDX, Field2D, Field2D, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D VDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, +Field3D VDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDY, Field3D, Field3D, Field3D) @@ -466,7 +466,7 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDY, Field3D, Field3D, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D VDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, +Field2D VDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDY, Field2D, Field2D, Field2D) @@ -483,7 +483,7 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDY, Field2D, Field2D, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D VDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, +Field3D VDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDZ, Field3D, Field3D, Field3D) @@ -500,7 +500,7 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDZ, Field3D, Field3D, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D VDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, +Field2D VDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDZ, Field2D, Field2D, Field2D) @@ -517,7 +517,7 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDZ, Field2D, Field2D, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D VDDZ(const Field3D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, +Field2D VDDZ(const Field3D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDZ, Field2D, Field3D, Field2D) @@ -534,7 +534,7 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(VDDZ, Field2D, Field3D, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D FDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, +Field3D FDDX(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDX, Field3D, Field3D, Field3D) @@ -551,7 +551,7 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDX, Field3D, Field3D, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D FDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, +Field2D FDDX(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDX, Field2D, Field2D, Field2D) @@ -568,7 +568,7 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDX, Field2D, Field2D, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D FDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, +Field3D FDDY(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDY, Field3D, Field3D, Field3D) @@ -585,7 +585,7 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDY, Field3D, Field3D, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D FDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, +Field2D FDDY(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDY, Field2D, Field2D, Field2D) @@ -602,7 +602,7 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDY, Field2D, Field2D, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D FDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, +Field3D FDDZ(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDZ, Field3D, Field3D, Field3D) @@ -619,7 +619,7 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDZ, Field3D, Field3D, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D FDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, +Field2D FDDZ(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDZ, Field2D, Field2D, Field2D) @@ -637,14 +637,14 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDZ, Field2D, Field2D, Field2D) /// If not given, defaults to RGN_NOBNDRY /// @param[in] dfdy_boundary_condition Boundary condition to use to set the guard cells of /// df/dy, before calculating the x-derivative. -const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, +Field3D D2DXDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string region = "RGN_NOBNDRY", const std::string& dfdy_boundary_condition = "free_o3"); [[gnu::deprecated("Please use D2DXDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, " "const std::string& method = \"DEFAULT\", const std::string& region = \"RGN_ALL\", " "const std::string& dfdy_boundary_condition) instead")]] -inline const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, const std::string& method, +inline Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, const std::string& method, REGION region, const std::string& dfdy_boundary_condition = "free_o3") { return D2DXDY(f, outloc, method, toString(region), dfdy_boundary_condition); @@ -652,7 +652,7 @@ inline const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, const std::string [[gnu::deprecated("Please use D2DXDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, " "const std::string& method = \"DEFAULT\", const std::string& region = \"RGN_ALL\", " "const std::string& dfdy_boundary_condition) instead")]] -inline const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, +inline Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY, const std::string& dfdy_boundary_condition = "free_o3") { return D2DXDY(f, outloc, toString(method), toString(region), dfdy_boundary_condition); @@ -672,14 +672,14 @@ inline const Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD metho /// If not given, defaults to RGN_NOBNDRY /// @param[in] dfdy_boundary_condition Boundary condition to use to set the guard cells of /// df/dy, before calculating the x-derivative. -const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, +Field2D D2DXDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string region = "RGN_NOBNDRY", const std::string& dfdy_boundary_condition = "free_o3"); [[gnu::deprecated("Please use D2DXDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, " "const std::string& method = \"DEFAULT\", const std::string& region = \"RGN_ALL\", " "const std::string& dfdy_boundary_condition) instead")]] -inline const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, const std::string& method, +inline Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, const std::string& method, REGION region, const std::string& dfdy_boundary_condition = "free_o3") { return D2DXDY(f, outloc, method, toString(region), dfdy_boundary_condition); @@ -687,7 +687,7 @@ inline const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, const std::string [[gnu::deprecated("Please use D2DXDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, " "const std::string& method = \"DEFAULT\", const std::string& region = \"RGN_ALL\", " "const std::string& dfdy_boundary_condition) instead")]] -inline const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, +inline Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, REGION region = RGN_NOBNDRY, const std::string& dfdy_boundary_condition = "free_o3") { return D2DXDY(f, outloc, toString(method), toString(region), dfdy_boundary_condition); @@ -705,7 +705,7 @@ inline const Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD metho /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DXDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field3D D2DXDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D2DXDZ, Field3D) @@ -721,7 +721,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D2DXDZ, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DXDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field2D D2DXDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D2DXDZ, Field2D) @@ -737,7 +737,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D2DXDZ, Field2D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D2DYDZ, Field3D) @@ -753,7 +753,7 @@ DERIV_FUNC_REGION_ENUM_TO_STRING(D2DYDZ, Field3D) /// If not given, defaults to DIFF_DEFAULT /// @param[in] region What region is expected to be calculated /// If not given, defaults to RGN_NOBNDRY -const Field2D D2DYDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& +Field2D D2DYDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); DERIV_FUNC_REGION_ENUM_TO_STRING(D2DYDZ, Field2D) diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 92a65c101d..1198af1607 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -58,7 +58,7 @@ ////////////// X DERIVATIVE ///////////////// -const Field3D DDX(const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D DDX(const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { Field3D result = bout::derivatives::index::DDX(f, outloc, method, region); Coordinates *coords = f.getCoordinates(outloc); @@ -75,40 +75,40 @@ const Field3D DDX(const Field3D &f, CELL_LOC outloc, const std::string &method, return result; } -const Field2D DDX(const Field2D &f, CELL_LOC outloc, const std::string &method, +Field2D DDX(const Field2D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return f.getCoordinates(outloc)->DDX(f, outloc, method, region); } ////////////// Y DERIVATIVE ///////////////// -const Field3D DDY(const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D DDY(const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::DDY(f, outloc, method, region) / f.getCoordinates(outloc)->dy; } -const Field2D DDY(const Field2D &f, CELL_LOC outloc, const std::string &method, +Field2D DDY(const Field2D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return f.getCoordinates(outloc)->DDY(f, outloc, method, region); } ////////////// Z DERIVATIVE ///////////////// -const Field3D DDZ(const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D DDZ(const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::DDZ(f, outloc, method, region) / f.getCoordinates(outloc)->dz; } -const Field2D DDZ(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string +Field2D DDZ(const Field2D &f, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), const std::string& UNUSED(region)) { auto tmp = Field2D(0., f.getMesh()); tmp.setLocation(f.getLocation()); return tmp; } -const Vector3D DDZ(const Vector3D &v, CELL_LOC outloc, const std::string &method, +Vector3D DDZ(const Vector3D &v, CELL_LOC outloc, const std::string &method, const std::string& region) { Vector3D result(v.x.getMesh()); @@ -137,7 +137,7 @@ const Vector3D DDZ(const Vector3D &v, CELL_LOC outloc, const std::string &method return result; } -const Vector2D DDZ(const Vector2D &v, CELL_LOC UNUSED(outloc), const std::string +Vector2D DDZ(const Vector2D &v, CELL_LOC UNUSED(outloc), const std::string &UNUSED(method), const std::string& UNUSED(region)) { Vector2D result(v.x.getMesh()); @@ -159,7 +159,7 @@ const Vector2D DDZ(const Vector2D &v, CELL_LOC UNUSED(outloc), const std::string ////////////// X DERIVATIVE ///////////////// -const Field3D D2DX2(const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D D2DX2(const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { Coordinates *coords = f.getCoordinates(outloc); @@ -178,7 +178,7 @@ const Field3D D2DX2(const Field3D &f, CELL_LOC outloc, const std::string &method return result; } -const Field2D D2DX2(const Field2D &f, CELL_LOC outloc, const std::string &method, +Field2D D2DX2(const Field2D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { Coordinates *coords = f.getCoordinates(outloc); @@ -196,7 +196,7 @@ const Field2D D2DX2(const Field2D &f, CELL_LOC outloc, const std::string &method ////////////// Y DERIVATIVE ///////////////// -const Field3D D2DY2(const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D D2DY2(const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { Coordinates *coords = f.getCoordinates(outloc); @@ -215,7 +215,7 @@ const Field3D D2DY2(const Field3D &f, CELL_LOC outloc, const std::string &method return result; } -const Field2D D2DY2(const Field2D &f, CELL_LOC outloc, const std::string &method, +Field2D D2DY2(const Field2D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { Coordinates *coords = f.getCoordinates(outloc); @@ -232,13 +232,13 @@ const Field2D D2DY2(const Field2D &f, CELL_LOC outloc, const std::string &method ////////////// Z DERIVATIVE ///////////////// -const Field3D D2DZ2(const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D D2DZ2(const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::D2DZ2(f, outloc, method, region) / SQ(f.getCoordinates(outloc)->dz); } -const Field2D D2DZ2(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), +Field2D D2DZ2(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), const std::string& UNUSED(region)) { if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); @@ -250,37 +250,37 @@ const Field2D D2DZ2(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED * Fourth derivatives *******************************************************************************/ -const Field3D D4DX4(const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D D4DX4(const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::D4DX4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dx)); } -const Field2D D4DX4(const Field2D &f, CELL_LOC outloc, const std::string &method, +Field2D D4DX4(const Field2D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::D4DX4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dx)); } -const Field3D D4DY4(const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D D4DY4(const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::D4DY4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dy)); } -const Field2D D4DY4(const Field2D &f, CELL_LOC outloc, const std::string &method, +Field2D D4DY4(const Field2D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::D4DY4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dy)); } -const Field3D D4DZ4(const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D D4DZ4(const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::D4DZ4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dz)); } -const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, const std::string &method, +Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::D4DZ4(f, outloc, method, region) / SQ(SQ(f.getCoordinates(outloc)->dz)); @@ -297,7 +297,7 @@ const Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, const std::string &method * * ** Communicates and applies boundary in X. */ -const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, const std::string &method, +Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, const std::string &method, const std::string& region, const std::string dfdy_boundary_condition) { // If staggering in x, take y-derivative at f's location. @@ -320,7 +320,7 @@ const Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, const std::string &metho * * ** Communicates and applies boundary in X. */ -const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region, const std::string dfdy_boundary_condition) { // If staggering in x, take y-derivative at f's location. @@ -336,7 +336,7 @@ const Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, const std::string &metho return DDX(dfdy, outloc, method, region); } -const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), +Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), const std::string& UNUSED(region)) { if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); @@ -345,7 +345,7 @@ const Field2D D2DXDZ(const Field2D &f, CELL_LOC outloc, const std::string &UNUSE } /// X-Z mixed derivative -const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { // If staggering in z, take x-derivative at f's location. @@ -355,7 +355,7 @@ const Field3D D2DXDZ(const Field3D &f, CELL_LOC outloc, const std::string &metho return DDZ(DDX(f, x_location, method, region), outloc, method, region); } -const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), +Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), const std::string& UNUSED(region)) { if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); @@ -363,7 +363,7 @@ const Field2D D2DYDZ(const Field2D &f, CELL_LOC outloc, const std::string &UNUSE return zeroFrom(f).setLocation(outloc); } -const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, MAYBE_UNUSED(const std::string& +Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, MAYBE_UNUSED(const std::string& method), const std::string& region) { // If staggering in z, take y-derivative at f's location. const auto y_location = @@ -381,14 +381,14 @@ const Field3D D2DYDZ(const Field3D& f, CELL_LOC outloc, MAYBE_UNUSED(const std:: ////////////// X DERIVATIVE ///////////////// /// Special case where both arguments are 2D. Output location ignored for now -const Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, +Field2D VDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::VDDX(v, f, outloc, method, region) / f.getCoordinates(outloc)->dx; } /// General version for 2 or 3-D objects -const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::VDDX(v, f, outloc, method, region) / f.getCoordinates(outloc)->dx; @@ -397,14 +397,14 @@ const Field3D VDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const st ////////////// Y DERIVATIVE ///////////////// // special case where both are 2D -const Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, +Field2D VDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::VDDY(v, f, outloc, method, region) / f.getCoordinates(outloc)->dy; } // general case -const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::VDDY(v, f, outloc, method, region) / f.getCoordinates(outloc)->dy; @@ -413,7 +413,7 @@ const Field3D VDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const st ////////////// Z DERIVATIVE ///////////////// // special case where both are 2D -const Field2D VDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const +Field2D VDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), const std::string& UNUSED(region)) { if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); @@ -422,7 +422,7 @@ const Field2D VDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, } // Note that this is zero because no compression is included -const Field2D VDDZ(const Field3D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const +Field2D VDDZ(const Field3D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), const std::string& UNUSED(region)) { if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); @@ -431,7 +431,7 @@ const Field2D VDDZ(const Field3D &UNUSED(v), const Field2D &f, CELL_LOC outloc, } // general case -const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::VDDZ(v, f, outloc, method, region) / f.getCoordinates(outloc)->dz; @@ -440,13 +440,13 @@ const Field3D VDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const st /******************************************************************************* * Flux conserving schemes *******************************************************************************/ -const Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, +Field2D FDDX(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::FDDX(v, f, outloc, method, region) / f.getCoordinates(outloc)->dx; } -const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::FDDX(v, f, outloc, method, region) / f.getCoordinates(outloc)->dx; @@ -454,13 +454,13 @@ const Field3D FDDX(const Field3D &v, const Field3D &f, CELL_LOC outloc, const st ///////////////////////////////////////////////////////////////////////// -const Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, +Field2D FDDY(const Field2D &v, const Field2D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::FDDY(v, f, outloc, method, region) / f.getCoordinates(outloc)->dy; } -const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::FDDY(v, f, outloc, method, region) / f.getCoordinates(outloc)->dy; @@ -468,7 +468,7 @@ const Field3D FDDY(const Field3D &v, const Field3D &f, CELL_LOC outloc, const st ///////////////////////////////////////////////////////////////////////// -const Field2D FDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const +Field2D FDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, const std::string &UNUSED(method), const std::string& UNUSED(region)) { if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); @@ -476,7 +476,7 @@ const Field2D FDDZ(const Field2D &UNUSED(v), const Field2D &f, CELL_LOC outloc, return zeroFrom(f).setLocation(outloc); } -const Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, +Field3D FDDZ(const Field3D &v, const Field3D &f, CELL_LOC outloc, const std::string &method, const std::string& region) { return bout::derivatives::index::FDDZ(v, f, outloc, method, region) / f.getCoordinates(outloc)->dz; From fe4e16c18bafd6ef638ecba875b5d75cc38b7a4a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 23 May 2019 17:50:23 +0100 Subject: [PATCH 1481/1783] Fix uses of deprecated to/fromFieldAligned in fv_ops.hxx --- include/bout/fv_ops.hxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index 3c8379b132..d9af56a542 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -188,8 +188,8 @@ namespace FV { CellEdges cellboundary; - Field3D f = toFieldAligned(f_in, RGN_NOX); - Field3D v = toFieldAligned(v_in, RGN_NOX); + Field3D f = toFieldAligned(f_in, "RGN_NOX"); + Field3D v = toFieldAligned(v_in, "RGN_NOX"); Coordinates *coord = f_in.getCoordinates(); @@ -326,7 +326,7 @@ namespace FV { } } } - return fromFieldAligned(result, RGN_NOBNDRY); + return fromFieldAligned(result, "RGN_NOBNDRY"); } /*! @@ -470,8 +470,8 @@ namespace FV { // Currently just using simple centered differences // so no fluxes need to be exchanged - n = toFieldAligned(n_in, RGN_NOX); - Field3D vy = toFieldAligned(v.y, RGN_NOX); + n = toFieldAligned(n_in, "RGN_NOX"); + Field3D vy = toFieldAligned(v.y, "RGN_NOX"); Field3D yresult = 0.0; for(int i=mesh->xstart;i<=mesh->xend;i++) @@ -490,7 +490,7 @@ namespace FV { yresult(i,j,k) = (nU*vU - nD*vD) / (coord->J(i,j)*coord->dy(i,j)); } - return result + fromFieldAligned(yresult, RGN_NOBNDRY); + return result + fromFieldAligned(yresult, "RGN_NOBNDRY"); } } From 641bcbe1bae9323fe216b68a404612a7cd906865 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 24 May 2019 01:32:53 +0100 Subject: [PATCH 1482/1783] Fix D2DXDY merge --- include/derivs.hxx | 4 ++-- src/sys/derivs.cxx | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/derivs.hxx b/include/derivs.hxx index a29af56b8b..da5b411023 100644 --- a/include/derivs.hxx +++ b/include/derivs.hxx @@ -639,7 +639,7 @@ VDERIV_FUNC_REGION_ENUM_TO_STRING(FDDZ, Field2D, Field2D, Field2D) /// df/dy, before calculating the x-derivative. Field3D D2DXDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - const std::string region = "RGN_NOBNDRY", + const std::string& region = "RGN_NOBNDRY", const std::string& dfdy_boundary_condition = "free_o3"); [[gnu::deprecated("Please use D2DXDY(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, " "const std::string& method = \"DEFAULT\", const std::string& region = \"RGN_ALL\", " @@ -674,7 +674,7 @@ inline Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method, /// df/dy, before calculating the x-derivative. Field2D D2DXDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", - const std::string region = "RGN_NOBNDRY", + const std::string& region = "RGN_NOBNDRY", const std::string& dfdy_boundary_condition = "free_o3"); [[gnu::deprecated("Please use D2DXDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, " "const std::string& method = \"DEFAULT\", const std::string& region = \"RGN_ALL\", " diff --git a/src/sys/derivs.cxx b/src/sys/derivs.cxx index 1198af1607..180c76834c 100644 --- a/src/sys/derivs.cxx +++ b/src/sys/derivs.cxx @@ -297,8 +297,8 @@ Field2D D4DZ4(const Field2D &f, CELL_LOC outloc, const std::string &method, * * ** Communicates and applies boundary in X. */ -Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, const std::string &method, - const std::string& region, const std::string dfdy_boundary_condition) { +Field2D D2DXDY(const Field2D& f, CELL_LOC outloc, const std::string& method, + const std::string& region, const std::string& dfdy_boundary_condition) { // If staggering in x, take y-derivative at f's location. const auto y_location = @@ -320,8 +320,8 @@ Field2D D2DXDY(const Field2D &f, CELL_LOC outloc, const std::string &method, * * ** Communicates and applies boundary in X. */ -Field3D D2DXDY(const Field3D &f, CELL_LOC outloc, const std::string &method, - const std::string& region, const std::string dfdy_boundary_condition) { +Field3D D2DXDY(const Field3D& f, CELL_LOC outloc, const std::string& method, + const std::string& region, const std::string& dfdy_boundary_condition) { // If staggering in x, take y-derivative at f's location. const auto y_location = From 2fa5553ab0c55a6e48bc042fc667ecc126a864a0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 24 May 2019 01:34:52 +0100 Subject: [PATCH 1483/1783] Fix warnings and compile errors in tests and examples --- examples/IMEX/advection-reaction/split_operator.cxx | 8 +++++--- examples/IMEX/drift-wave-constraint/test-drift.cxx | 6 +++--- examples/advdiff/advdiff.cxx | 2 +- examples/advdiff2/run.cxx | 5 +---- examples/backtrace/backtrace.cxx | 6 +++--- examples/blob2d-laplacexz/blob2d.cxx | 4 ++-- examples/bout_runners_example/diffusion_3D.cxx | 4 ++-- examples/eigen-box/eigen-box.cxx | 4 ++-- examples/fci-wave-logn/fci-wave.cxx | 10 +++++----- examples/fci-wave/fci-wave.cxx | 10 +++++----- examples/gyro-gem/gem.cxx | 2 +- examples/laplacexy/alfven-wave/alfven.cxx | 2 +- examples/monitor-newapi/monitor.cxx | 4 ++-- examples/monitor/monitor.cxx | 8 ++++---- examples/preconditioning/wave/test_precon.cxx | 8 ++++---- examples/staggered_grid/test_staggered.cxx | 4 ++-- examples/wave-slab/wave_slab.cxx | 4 ++-- tests/MMS/GBS/gbs.cxx | 5 +++-- tests/MMS/advection/advection.cxx | 2 +- tests/MMS/fieldalign/fieldalign.cxx | 2 +- tests/MMS/hw/hw.cxx | 2 +- tests/MMS/tokamak/tokamak.cxx | 2 +- tests/integrated/test-dataformat/test_dataformat.cxx | 2 +- tests/integrated/test-drift-instability/2fluid.cxx | 4 ++-- .../test-fieldfactory2/test_fieldfactory2.cxx | 2 +- .../test-fieldgroupComm/test_fieldgroupcomm.cxx | 4 ++-- tests/integrated/test-globalfield/test_globalfield.cxx | 4 ++-- tests/integrated/test-integrate/test_integrate.cxx | 10 +++++----- tests/integrated/test-laplace2/test_laplace.cxx | 6 +++--- .../test-multigrid_laplace/test_multigrid_laplace.cxx | 8 ++++---- .../test-naulin-laplace/test_naulin_laplace.cxx | 8 ++++---- tests/integrated/test-nonuniform/test_delp2.cxx | 4 ++-- tests/integrated/test-simple-diffusion/simple_diff.cxx | 2 +- tests/integrated/test-squash/squash.cxx | 4 ++-- tests/integrated/test-visitor/test_visitor.cxx | 10 +++++----- 35 files changed, 86 insertions(+), 86 deletions(-) diff --git a/examples/IMEX/advection-reaction/split_operator.cxx b/examples/IMEX/advection-reaction/split_operator.cxx index 1fcd5e8c23..91a4cf5cfc 100644 --- a/examples/IMEX/advection-reaction/split_operator.cxx +++ b/examples/IMEX/advection-reaction/split_operator.cxx @@ -31,7 +31,7 @@ Field3D phi; // Potential used for advection BoutReal rate; // Reaction rate -int physics_init(bool restarting) { +int physics_init(bool UNUSED(restarting)) { // Give the solver two RHS functions solver->setSplitOperator(physics_run, reaction); @@ -54,7 +54,7 @@ int physics_init(bool restarting) { return 0; } -int physics_run(BoutReal time) { +int physics_run(BoutReal UNUSED(time)) { // Need communication mesh->communicate(U); @@ -64,7 +64,9 @@ int physics_run(BoutReal time) { return 0; } -int reaction(BoutReal time) { +int reaction(BoutReal UNUSED(time)) { // A simple reaction operator. No communication needed ddt(U) = rate * (1.-U); + + return 0; } diff --git a/examples/IMEX/drift-wave-constraint/test-drift.cxx b/examples/IMEX/drift-wave-constraint/test-drift.cxx index 163775f043..44747330be 100644 --- a/examples/IMEX/drift-wave-constraint/test-drift.cxx +++ b/examples/IMEX/drift-wave-constraint/test-drift.cxx @@ -7,7 +7,7 @@ class DriftWave : public PhysicsModel { protected: - int init(bool restart) { + int init(bool UNUSED(restart)) { // Specify evolving variables solver->add(Vort, "Vort"); // Vorticity solver->add(Ne, "Ne"); // Electron density @@ -31,7 +31,7 @@ class DriftWave : public PhysicsModel { return 0; } - int convective(BoutReal time) { + int convective(BoutReal UNUSED(time)) { // Non-stiff parts of the problem here // Here just the nonlinear advection @@ -52,7 +52,7 @@ class DriftWave : public PhysicsModel { return 0; } - int diffusive(BoutReal time) { + int diffusive(BoutReal UNUSED(time)) { // Parallel dynamics treated implicitly mesh->communicate(phi, Vort, Ne); diff --git a/examples/advdiff/advdiff.cxx b/examples/advdiff/advdiff.cxx index d320e2bde6..ac540e52c9 100644 --- a/examples/advdiff/advdiff.cxx +++ b/examples/advdiff/advdiff.cxx @@ -38,7 +38,7 @@ class AdvDiff : public PhysicsModel { return 0; } - int rhs(BoutReal t) { + int rhs(BoutReal UNUSED(t)) { // Run communications mesh->communicate(V); diff --git a/examples/advdiff2/run.cxx b/examples/advdiff2/run.cxx index e0f7204ca4..44d40bb9e7 100644 --- a/examples/advdiff2/run.cxx +++ b/examples/advdiff2/run.cxx @@ -3,15 +3,12 @@ #include "globals.hxx" -int physics_run(BoutReal t) -{ +int physics_run(BoutReal UNUSED(t)) { // Run communications mesh->communicate(V); - //ddt(V) = D2DX2(V) + 0.5*DDX(V) + D2DY2(V); ddt(V) = DDX(V); - return 0; } diff --git a/examples/backtrace/backtrace.cxx b/examples/backtrace/backtrace.cxx index 97f7d53b43..472371725b 100644 --- a/examples/backtrace/backtrace.cxx +++ b/examples/backtrace/backtrace.cxx @@ -13,7 +13,7 @@ void f1(){ output.write("c is %f\n",c); throw BoutException("Tomatoes are red?\n"); } -void f2(int a){ +void f2(int UNUSED(a)) { f1(); } @@ -22,13 +22,13 @@ int f3(){ return 0; } -int physics_init(bool restarting) { +int physics_init(bool UNUSED(restarting)) { f3(); return 1; } -int physics_run(BoutReal time) { +int physics_run(BoutReal UNUSED(time)) { return 1; diff --git a/examples/blob2d-laplacexz/blob2d.cxx b/examples/blob2d-laplacexz/blob2d.cxx index 7fc57dbe27..9ad0b1f1e8 100644 --- a/examples/blob2d-laplacexz/blob2d.cxx +++ b/examples/blob2d-laplacexz/blob2d.cxx @@ -37,7 +37,7 @@ class Blob2D : public PhysicsModel { int boussinesq_used; // How many times has it been reused protected: - int init(bool restarting) { + int init(bool UNUSED(restarting)) { /******************Reading options *****************/ @@ -109,7 +109,7 @@ class Blob2D : public PhysicsModel { return 0; } - int rhs(BoutReal t) { + int rhs(BoutReal UNUSED(t)) { // Run communications //////////////////////////////////////////////////////////////////////////// diff --git a/examples/bout_runners_example/diffusion_3D.cxx b/examples/bout_runners_example/diffusion_3D.cxx index 670472eb99..dbf8bf948d 100644 --- a/examples/bout_runners_example/diffusion_3D.cxx +++ b/examples/bout_runners_example/diffusion_3D.cxx @@ -17,7 +17,7 @@ bool use_grid; // If the spatial size should be loaded from the grid // Initialization of the physics // ############################################################################ -int physics_init(bool restarting) { +int physics_init(bool UNUSED(restarting)) { // Get the option (before any sections) in the BOUT.inp file Options *options = Options::getRoot(); @@ -79,7 +79,7 @@ int physics_init(bool restarting) { // Solving the equations // ############################################################################ -int physics_run(BoutReal t){ +int physics_run(BoutReal UNUSED(t)) { mesh->communicate(n); // Communicate guard cells // Density diffusion diff --git a/examples/eigen-box/eigen-box.cxx b/examples/eigen-box/eigen-box.cxx index 08d49d1037..b739e19cc5 100644 --- a/examples/eigen-box/eigen-box.cxx +++ b/examples/eigen-box/eigen-box.cxx @@ -10,12 +10,12 @@ class EigenBox : public PhysicsModel { protected: - int init(bool restarting) { + int init(bool UNUSED(restarting)) { solver->add(f, "f"); solver->add(g, "g"); return 0; } - int rhs(BoutReal t) { + int rhs(BoutReal UNUSED(t)) { mesh->communicate(f); ddt(g) = D2DX2(f); diff --git a/examples/fci-wave-logn/fci-wave.cxx b/examples/fci-wave-logn/fci-wave.cxx index 13a81e71ee..2de3f878d9 100644 --- a/examples/fci-wave-logn/fci-wave.cxx +++ b/examples/fci-wave-logn/fci-wave.cxx @@ -16,8 +16,8 @@ class FCIwave : public PhysicsModel { Field3D Div_par_integrate(const Field3D &f) { Field3D f_B = f / Bxyz; - f_B.splitYupYdown(); - mesh->getParallelTransform().integrateParallelSlices(f_B); + f_B.splitParallelSlices(); + mesh->getCoordinates()->getParallelTransform().integrateParallelSlices(f_B); // integrateParallelSlices replaces all yup/down points, so the boundary conditions // now need to be applied. If Bxyz has neumann parallel boundary conditions @@ -58,7 +58,7 @@ class FCIwave : public PhysicsModel { } protected: - int init(bool restarting) override { + int init(bool UNUSED(restarting)) override { // Get the magnetic field mesh->get(Bxyz, "B"); @@ -81,7 +81,7 @@ class FCIwave : public PhysicsModel { return 0; } - int rhs(BoutReal t) override { + int rhs(BoutReal UNUSED(t)) override { mesh->communicate(logn,v); // Boundary condition applied to log(n) to prevent negative densities @@ -106,7 +106,7 @@ class FCIwave : public PhysicsModel { // Calculate the flux divergence using Div_par_integrate Field3D nv = n * v; - nv.splitYupYdown(); + nv.splitParallelSlices(); for (const auto ® : mesh->getBoundariesPar()) { Field3D &nv_next = nv.ynext(reg->dir); nv_next.allocate(); diff --git a/examples/fci-wave/fci-wave.cxx b/examples/fci-wave/fci-wave.cxx index b3b416b23e..c6451ebc47 100644 --- a/examples/fci-wave/fci-wave.cxx +++ b/examples/fci-wave/fci-wave.cxx @@ -17,8 +17,8 @@ class FCIwave : public PhysicsModel { Field3D Div_par_integrate(const Field3D &f) { Field3D f_B = f / Bxyz; - f_B.splitYupYdown(); - mesh->getParallelTransform().integrateParallelSlices(f_B); + f_B.splitParallelSlices(); + mesh->getCoordinates()->getParallelTransform().integrateParallelSlices(f_B); // integrateParallelSlices replaces all yup/down points, so the boundary conditions // now need to be applied. If Bxyz has neumann parallel boundary conditions @@ -93,7 +93,7 @@ class FCIwave : public PhysicsModel { logn.applyParallelBoundary(); n = exp(logn); - n.splitYupYdown(); + n.splitParallelSlices(); n.yup() = exp(logn.yup()); n.ydown() = exp(logn.ydown()); } else { @@ -107,7 +107,7 @@ class FCIwave : public PhysicsModel { Field3D momflux = nv * v; // Apply boundary conditions to v - v.splitYupYdown(); + v.splitParallelSlices(); v.yup().allocate(); v.ydown().allocate(); v.applyParallelBoundary(); @@ -115,7 +115,7 @@ class FCIwave : public PhysicsModel { // Ensure that boundary conditions are consistent // between v, nv and momentum flux - momflux.splitYupYdown(); + momflux.splitParallelSlices(); for (const auto ® : mesh->getBoundariesPar()) { // Using the values of density and velocity on the boundary const Field3D &n_next = n.ynext(reg->dir); diff --git a/examples/gyro-gem/gem.cxx b/examples/gyro-gem/gem.cxx index 44ace1c516..efddb22969 100644 --- a/examples/gyro-gem/gem.cxx +++ b/examples/gyro-gem/gem.cxx @@ -1088,7 +1088,7 @@ class GEM : public PhysicsModel { } /// Artificial dissipation terms in advection - const Field3D UE_Grad_D(const Field3D &f, const Field3D &p) { + const Field3D UE_Grad_D(const Field3D &f, const Field3D &UNUSED(p)) { Field3D delp2 = Delp2(f); delp2.applyBoundary("neumann"); mesh->communicate(delp2); diff --git a/examples/laplacexy/alfven-wave/alfven.cxx b/examples/laplacexy/alfven-wave/alfven.cxx index 86a690a157..1fac46b83c 100644 --- a/examples/laplacexy/alfven-wave/alfven.cxx +++ b/examples/laplacexy/alfven-wave/alfven.cxx @@ -36,7 +36,7 @@ class Alfven : public PhysicsModel { Laplacian *phiSolver; // Old Laplacian in X-Z LaplaceXZ *newSolver; // New Laplacian in X-Z protected: - int init(bool restarting) { + int init(bool UNUSED(restarting)) { // Normalisation auto opt = Options::root()["alfven"]; diff --git a/examples/monitor-newapi/monitor.cxx b/examples/monitor-newapi/monitor.cxx index 29d7718247..3282924e74 100644 --- a/examples/monitor-newapi/monitor.cxx +++ b/examples/monitor-newapi/monitor.cxx @@ -6,13 +6,13 @@ class MonitorExample : public PhysicsModel { protected: // Initialisation - int init(bool restarting) { + int init(bool UNUSED(restarting)) { solver->add(f, "f"); return 0; } // Calculate time-derivatives - int rhs(BoutReal t) { + int rhs(BoutReal UNUSED(t)) { ddt(f) = -f; return 0; } diff --git a/examples/monitor/monitor.cxx b/examples/monitor/monitor.cxx index 653205dfdc..e911778cb5 100644 --- a/examples/monitor/monitor.cxx +++ b/examples/monitor/monitor.cxx @@ -13,14 +13,14 @@ class MyOutputMonitor: public Monitor{ int call(Solver *solver, BoutReal simtime, int iter, int NOUT) override; }; -int MyOutputMonitor::call(Solver *solver, BoutReal simtime, int iter, int NOUT) { +int MyOutputMonitor::call(Solver *UNUSED(solver), BoutReal simtime, int iter, int NOUT) { output.write("Output monitor, time = %e, step %d of %d\n", simtime, iter, NOUT); return 0; } // Create a function to be called every timestep -int my_timestep_monitor(Solver *solver, BoutReal simtime, BoutReal dt) { +int my_timestep_monitor(Solver *UNUSED(solver), BoutReal simtime, BoutReal dt) { output.write("\nTimestep monitor, time = %e, dt = %e\n", simtime, dt); return 0; @@ -29,7 +29,7 @@ int my_timestep_monitor(Solver *solver, BoutReal simtime, BoutReal dt) { MyOutputMonitor my_output_monitor; MyOutputMonitor my_output_monitor_fast(.5); -int physics_init(bool restarting) { +int physics_init(bool UNUSED(restarting)) { solver->addMonitor(&my_output_monitor); solver->addMonitor(&my_output_monitor_fast); solver->addTimestepMonitor(my_timestep_monitor); @@ -37,7 +37,7 @@ int physics_init(bool restarting) { return 0; } -int physics_run(BoutReal t) { +int physics_run(BoutReal UNUSED(t)) { ddt(f) = -f; return 0; } diff --git a/examples/preconditioning/wave/test_precon.cxx b/examples/preconditioning/wave/test_precon.cxx index f4bef86b71..65316315bd 100644 --- a/examples/preconditioning/wave/test_precon.cxx +++ b/examples/preconditioning/wave/test_precon.cxx @@ -17,7 +17,7 @@ Field3D u, v; // Evolving variables InvertPar *inv; // Parallel inversion class -int physics_init(bool restarting) { +int physics_init(bool UNUSED(restarting)) { // Set variables to evolve SOLVE_FOR2(u,v); @@ -34,7 +34,7 @@ int physics_init(bool restarting) { return 0; } -int physics_run(BoutReal t) { +int physics_run(BoutReal UNUSED(t)) { mesh->communicate(u,v); ddt(u) = Grad_par(v); @@ -52,7 +52,7 @@ int physics_run(BoutReal t) { * o Return values should be in time derivatives * *********************************************************/ -int precon(BoutReal t, BoutReal gamma, BoutReal delta) { +int precon(BoutReal UNUSED(t), BoutReal gamma, BoutReal UNUSED(delta)) { // Communicate vector to be inverted mesh->communicate(ddt(u), ddt(v)); @@ -93,7 +93,7 @@ int precon(BoutReal t, BoutReal gamma, BoutReal delta) { * enable by setting solver / use_jacobian = true in BOUT.inp *********************************************************/ -int jacobian(BoutReal t) { +int jacobian(BoutReal UNUSED(t)) { mesh->communicate(ddt(u), ddt(v)); Field3D utmp = Grad_par(ddt(v)); // Shouldn't overwrite ddt(u) before using it ddt(v) = Grad_par(ddt(u)); diff --git a/examples/staggered_grid/test_staggered.cxx b/examples/staggered_grid/test_staggered.cxx index d49a854deb..5520480809 100644 --- a/examples/staggered_grid/test_staggered.cxx +++ b/examples/staggered_grid/test_staggered.cxx @@ -9,7 +9,7 @@ Field3D n, v; -int physics_init(bool restart) { +int physics_init(bool UNUSED(restart)) { v.setLocation(CELL_YLOW); // Staggered relative to n @@ -18,7 +18,7 @@ int physics_init(bool restart) { return 0; } -int physics_run(BoutReal time) { +int physics_run(BoutReal UNUSED(time)) { mesh->communicate(n, v); //ddt(n) = -Div_par_flux(v, n, CELL_CENTRE); diff --git a/examples/wave-slab/wave_slab.cxx b/examples/wave-slab/wave_slab.cxx index 68c96c9dbb..e361f4ecb3 100644 --- a/examples/wave-slab/wave_slab.cxx +++ b/examples/wave-slab/wave_slab.cxx @@ -15,7 +15,7 @@ class WaveTest : public PhysicsModel { public: - int init(bool restarting) { + int init(bool UNUSED(restarting)) { auto *coords = mesh->getCoordinates(); Field2D Rxy, Bpxy, Btxy, hthe, I; GRID_LOAD(Rxy); @@ -54,7 +54,7 @@ class WaveTest : public PhysicsModel { return 0; } - int rhs(BoutReal time) { + int rhs(BoutReal UNUSED(time)) { mesh->communicate(f,g); ddt(f) = Grad_par(g); diff --git a/tests/MMS/GBS/gbs.cxx b/tests/MMS/GBS/gbs.cxx index c7bde653c9..aa013db8b6 100644 --- a/tests/MMS/GBS/gbs.cxx +++ b/tests/MMS/GBS/gbs.cxx @@ -106,7 +106,7 @@ int GBS::init(bool restarting) { if(mms) { Sn = 0.0; }else { - string source; + std::string source; optne->get("source", source, "0.0"); Sn = FieldFactory::get()->create3D(source, NULL, mesh); Sn /= Omega_ci; @@ -120,7 +120,7 @@ int GBS::init(bool restarting) { if(mms) { Sp = 0.0; }else { - string source; + std::string source; optte->get("source", source, "0.0"); Sp = FieldFactory::get()->create3D(source, NULL, mesh); Sp /= Omega_ci; @@ -249,6 +249,7 @@ int GBS::init(bool restarting) { } case 3: { // logB, taken from mesh logB = log(coords->Bxy); + break; } default: throw BoutException("Invalid value for curv_method"); diff --git a/tests/MMS/advection/advection.cxx b/tests/MMS/advection/advection.cxx index ee6d93ff34..c06af19727 100644 --- a/tests/MMS/advection/advection.cxx +++ b/tests/MMS/advection/advection.cxx @@ -9,7 +9,7 @@ class AdvectMMS : public PhysicsModel { public: - int init(bool restarting) { + int init(bool UNUSED(restarting)) { solver->add(f, "f"); Options::getRoot()->get("method", method, 0); diff --git a/tests/MMS/fieldalign/fieldalign.cxx b/tests/MMS/fieldalign/fieldalign.cxx index ccd20ca7fa..afa57132d7 100644 --- a/tests/MMS/fieldalign/fieldalign.cxx +++ b/tests/MMS/fieldalign/fieldalign.cxx @@ -3,7 +3,7 @@ class FieldAlign : public PhysicsModel { protected: - int init(bool restarting) { + int init(bool UNUSED(restarting)) { mesh->get(vx, "vx"); mesh->get(vy, "vy"); mesh->get(vz, "vz"); diff --git a/tests/MMS/hw/hw.cxx b/tests/MMS/hw/hw.cxx index 20ca7d6c8c..1804783566 100644 --- a/tests/MMS/hw/hw.cxx +++ b/tests/MMS/hw/hw.cxx @@ -18,7 +18,7 @@ class Laplacian* phiSolver; // Laplacian solver for vort -> phi // Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE BRACKET_METHOD bm; // Bracket method for advection terms -int physics_init(bool restart) { +int physics_init(bool UNUSED(restart)) { Options *options = Options::getRoot()->getSection("hw"); OPTION(options, alpha, 1.0); diff --git a/tests/MMS/tokamak/tokamak.cxx b/tests/MMS/tokamak/tokamak.cxx index a917afe960..c9dc580078 100644 --- a/tests/MMS/tokamak/tokamak.cxx +++ b/tests/MMS/tokamak/tokamak.cxx @@ -12,7 +12,7 @@ class TokamakMMS : public PhysicsModel { public: - int init(bool restarting) { + int init(bool UNUSED(restarting)) { solver->add(laplacepar, "laplacepar"); solver->add(delp2, "delp2"); solver->add(advect, "advect"); diff --git a/tests/integrated/test-dataformat/test_dataformat.cxx b/tests/integrated/test-dataformat/test_dataformat.cxx index 420dc85b2a..30ab4a6a70 100644 --- a/tests/integrated/test-dataformat/test_dataformat.cxx +++ b/tests/integrated/test-dataformat/test_dataformat.cxx @@ -3,7 +3,7 @@ #include int main() { - const string izfilename="sample.nc"; + const std::string izfilename="sample.nc"; // Create a file format handler auto izfile = data_format(izfilename.c_str()); diff --git a/tests/integrated/test-drift-instability/2fluid.cxx b/tests/integrated/test-drift-instability/2fluid.cxx index 59e151a6d1..c942b109fa 100644 --- a/tests/integrated/test-drift-instability/2fluid.cxx +++ b/tests/integrated/test-drift-instability/2fluid.cxx @@ -293,8 +293,8 @@ int physics_init(bool UNUSED(restarting)) { maybe_ylow = CELL_CENTRE; } Vi = interp_to(Vi,maybe_ylow); - Ni0_maybe_ylow = interp_to(Ni0, maybe_ylow, RGN_NOBNDRY); - Te0_maybe_ylow = interp_to(Te0, maybe_ylow, RGN_NOBNDRY); + Ni0_maybe_ylow = interp_to(Ni0, maybe_ylow, "RGN_NOBNDRY"); + Te0_maybe_ylow = interp_to(Te0, maybe_ylow, "RGN_NOBNDRY"); return(0); } diff --git a/tests/integrated/test-fieldfactory2/test_fieldfactory2.cxx b/tests/integrated/test-fieldfactory2/test_fieldfactory2.cxx index 7ded611331..6338f4f694 100644 --- a/tests/integrated/test-fieldfactory2/test_fieldfactory2.cxx +++ b/tests/integrated/test-fieldfactory2/test_fieldfactory2.cxx @@ -10,7 +10,7 @@ class TestFieldFactory2 : public PhysicsModel { protected: // Initialisation - int init(bool restarting) { + int init(bool UNUSED(restarting)) { // Create a field factory for parsing strings FieldFactory f(mesh); diff --git a/tests/integrated/test-fieldgroupComm/test_fieldgroupcomm.cxx b/tests/integrated/test-fieldgroupComm/test_fieldgroupcomm.cxx index 5a5fa124b8..10d19fdc6b 100644 --- a/tests/integrated/test-fieldgroupComm/test_fieldgroupcomm.cxx +++ b/tests/integrated/test-fieldgroupComm/test_fieldgroupcomm.cxx @@ -3,7 +3,7 @@ class TestFieldGroupComm : public PhysicsModel{ protected: - int init(bool restarting) { + int init(bool UNUSED(restarting)) { //Create identical fields solver->add(fld1,"fld1"); solver->add(fld2,"fld2"); @@ -17,7 +17,7 @@ class TestFieldGroupComm : public PhysicsModel{ return 0; } - int rhs(BoutReal t) { + int rhs(BoutReal UNUSED(t)) { //Communicate -- ideally would all produce the same result //1. As it should be mesh->communicate(comm1); diff --git a/tests/integrated/test-globalfield/test_globalfield.cxx b/tests/integrated/test-globalfield/test_globalfield.cxx index 0561716092..645b48fcd6 100644 --- a/tests/integrated/test-globalfield/test_globalfield.cxx +++ b/tests/integrated/test-globalfield/test_globalfield.cxx @@ -8,7 +8,7 @@ #include #include -int physics_init(bool restarting) { +int physics_init(bool UNUSED(restarting)) { ///////////////////////////////////////////////////////////// // 2D fields @@ -117,7 +117,7 @@ int physics_init(bool restarting) { return 1; // Signal an error, so quits } -int physics_run(BoutReal t) { +int physics_run(BoutReal UNUSED(t)) { // Doesn't do anything return 1; } diff --git a/tests/integrated/test-integrate/test_integrate.cxx b/tests/integrated/test-integrate/test_integrate.cxx index 57fd8589c3..8e36dc5009 100644 --- a/tests/integrated/test-integrate/test_integrate.cxx +++ b/tests/integrated/test-integrate/test_integrate.cxx @@ -10,17 +10,17 @@ // This class represents a sub-problem to be solved class MyFunction : public PhysicsModel { public: - int init(bool restarting) { + int init(bool UNUSED(restarting)) { solver->add(result, "result"); return 0; } - int rhs(BoutReal time) { + int rhs(BoutReal UNUSED(time)) { ddt(result) = 1.0; return 0; } - int outputMonitor(BoutReal simtime, int iter, int NOUT) { + int outputMonitor(BoutReal simtime, int UNUSED(iter), int UNUSED(NOUT)) { output.write("MyFunction: time = %e\n", simtime); return 0; } @@ -39,7 +39,7 @@ class TestIntegrate : public PhysicsModel { delete ode; } - int init(bool restarting) { + int init(bool UNUSED(restarting)) { // Create a model model = new MyFunction(); @@ -55,7 +55,7 @@ class TestIntegrate : public PhysicsModel { return 0; } - int rhs(BoutReal time) { + int rhs(BoutReal UNUSED(time)) { ddt(f) = model->result; return 0; } diff --git a/tests/integrated/test-laplace2/test_laplace.cxx b/tests/integrated/test-laplace2/test_laplace.cxx index afdf376925..7bf9bcd321 100644 --- a/tests/integrated/test-laplace2/test_laplace.cxx +++ b/tests/integrated/test-laplace2/test_laplace.cxx @@ -8,13 +8,13 @@ #include #include -int physics_init(bool restarting) { +int physics_init(bool UNUSED(restarting)) { FieldFactory f(mesh); Options *options = Options::getRoot(); // Read strings containing coefficients - string in, acoef, ccoef; + std::string in, acoef, ccoef; OPTION(options, in, "(1-gauss(x-0.5,0.2))*gauss(z-pi)"); OPTION(options, acoef, "gauss(x)"); OPTION(options, ccoef, "sin(x) * gauss(x-0.5)"); @@ -57,7 +57,7 @@ int physics_init(bool restarting) { return 1; } -int physics_run(BoutReal t) { +int physics_run(BoutReal UNUSED(t)) { // Doesn't do anything return 1; } diff --git a/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx b/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx index bc532c7e12..b26580a31c 100644 --- a/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx +++ b/tests/integrated/test-multigrid_laplace/test_multigrid_laplace.cxx @@ -72,7 +72,7 @@ int main(int argc, char** argv) { checkData(sol1); bcheck1 = d1*Delp2(sol1, CELL_DEFAULT, false) + this_Grad_perp_dot_Grad_perp(c1,sol1)/c1 + a1*sol1; absolute_error1 = f1-sol1; - max_error1 = max_error_at_ystart(abs(absolute_error1, RGN_NOBNDRY)); + max_error1 = max_error_at_ystart(abs(absolute_error1, "RGN_NOBNDRY")); } catch (BoutException &err) { output << "BoutException occured in invert->solve(b1): " << err.what() << endl << "Laplacian inversion failed to converge (probably)" << endl; @@ -123,7 +123,7 @@ int main(int argc, char** argv) { mesh->communicate(sol2); bcheck2 = d2*Delp2(sol2, CELL_DEFAULT, false) + this_Grad_perp_dot_Grad_perp(c2,sol2)/c2 + a2*sol2; absolute_error2 = f2-sol2; - max_error2 = max_error_at_ystart(abs(absolute_error2, RGN_NOBNDRY)); + max_error2 = max_error_at_ystart(abs(absolute_error2, "RGN_NOBNDRY")); } catch (BoutException &err) { output << "BoutException occured in invert->solve(b2): " << err.what() << endl << "Laplacian inversion failed to converge (probably)" << endl; @@ -179,7 +179,7 @@ int main(int argc, char** argv) { mesh->communicate(sol3); bcheck3 = d3*Delp2(sol3, CELL_DEFAULT, false) + this_Grad_perp_dot_Grad_perp(c3,f3)/c3 + a3*sol3; absolute_error3 = f3-sol3; - max_error3 = max_error_at_ystart(abs(absolute_error3, RGN_NOBNDRY)); + max_error3 = max_error_at_ystart(abs(absolute_error3, "RGN_NOBNDRY")); } catch (BoutException &err) { output << "BoutException occured in invert->solve(b3): " << err.what() << endl << "Laplacian inversion failed to converge (probably)" << endl; @@ -239,7 +239,7 @@ int main(int argc, char** argv) { mesh->communicate(sol4); bcheck4 = d4*Delp2(sol4, CELL_DEFAULT, false) + this_Grad_perp_dot_Grad_perp(c4,sol4)/c4 + a4*sol4; absolute_error4 = f4-sol4; - max_error4 = max_error_at_ystart(abs(absolute_error4, RGN_NOBNDRY)); + max_error4 = max_error_at_ystart(abs(absolute_error4, "RGN_NOBNDRY")); } catch (BoutException &err) { output << "BoutException occured in invert->solve(b4): " << err.what() << endl << "Laplacian inversion failed to converge (probably)" << endl; diff --git a/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx b/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx index df7541c780..7fd465402b 100644 --- a/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx +++ b/tests/integrated/test-naulin-laplace/test_naulin_laplace.cxx @@ -74,7 +74,7 @@ int main(int argc, char** argv) { checkData(sol1); bcheck1 = d1*Delp2(sol1) + this_Grad_perp_dot_Grad_perp(c1,sol1)/c1 + a1*sol1; absolute_error1 = f1-sol1; - max_error1 = max_error_at_ystart(abs(absolute_error1, RGN_NOBNDRY)); + max_error1 = max_error_at_ystart(abs(absolute_error1, "RGN_NOBNDRY")); } catch (BoutException &err) { output << "BoutException occured in invert->solve(b1): " << err.what() << endl << "Laplacian inversion failed to converge (probably)" << endl; @@ -124,7 +124,7 @@ int main(int argc, char** argv) { mesh->communicate(sol2); bcheck2 = d2*Delp2(sol2) + this_Grad_perp_dot_Grad_perp(c2,sol2)/c2 + a2*sol2; absolute_error2 = f2-sol2; - max_error2 = max_error_at_ystart(abs(absolute_error2, RGN_NOBNDRY)); + max_error2 = max_error_at_ystart(abs(absolute_error2, "RGN_NOBNDRY")); } catch (BoutException &err) { output << "BoutException occured in invert->solve(b2): " << err.what() << endl << "Laplacian inversion failed to converge (probably)" << endl; @@ -183,7 +183,7 @@ int main(int argc, char** argv) { mesh->communicate(sol3); bcheck3 = d3*Delp2(sol3) + this_Grad_perp_dot_Grad_perp(c3,f3)/c3 + a3*sol3; absolute_error3 = f3-sol3; - max_error3 = max_error_at_ystart(abs(absolute_error3, RGN_NOBNDRY)); + max_error3 = max_error_at_ystart(abs(absolute_error3, "RGN_NOBNDRY")); } catch (BoutException &err) { output << "BoutException occured in invert->solve(b3): " << err.what() << endl << "Laplacian inversion failed to converge (probably)" << endl; @@ -246,7 +246,7 @@ int main(int argc, char** argv) { mesh->communicate(sol4); bcheck4 = d4*Delp2(sol4) + this_Grad_perp_dot_Grad_perp(c4,sol4)/c4 + a4*sol4; absolute_error4 = f4-sol4; - max_error4 = max_error_at_ystart(abs(absolute_error4, RGN_NOBNDRY)); + max_error4 = max_error_at_ystart(abs(absolute_error4, "RGN_NOBNDRY")); } catch (BoutException &err) { output << "BoutException occured in invert->solve(b4): " << err.what() << endl << "Laplacian inversion failed to converge (probably)" << endl; diff --git a/tests/integrated/test-nonuniform/test_delp2.cxx b/tests/integrated/test-nonuniform/test_delp2.cxx index 06b947b6cd..0ad7a1c4eb 100644 --- a/tests/integrated/test-nonuniform/test_delp2.cxx +++ b/tests/integrated/test-nonuniform/test_delp2.cxx @@ -10,7 +10,7 @@ #include #include -int physics_init(bool restarting) { +int physics_init(bool UNUSED(restarting)) { Field3D input, reference, result; GRID_LOAD(input); // Read input from file @@ -34,7 +34,7 @@ int physics_init(bool restarting) { return 1; } -int physics_run(BoutReal t) { +int physics_run(BoutReal UNUSED(t)) { // Doesn't do anything return 1; } diff --git a/tests/integrated/test-simple-diffusion/simple_diff.cxx b/tests/integrated/test-simple-diffusion/simple_diff.cxx index f45ea15a4b..df30aacd10 100644 --- a/tests/integrated/test-simple-diffusion/simple_diff.cxx +++ b/tests/integrated/test-simple-diffusion/simple_diff.cxx @@ -63,7 +63,7 @@ int physics_init(bool restarting) return 0; } -int physics_run(BoutReal t) +int physics_run(BoutReal UNUSED(t)) { // Run communications //mesh->communicate(N,P,V); diff --git a/tests/integrated/test-squash/squash.cxx b/tests/integrated/test-squash/squash.cxx index 98528ba860..95a6edceb6 100644 --- a/tests/integrated/test-squash/squash.cxx +++ b/tests/integrated/test-squash/squash.cxx @@ -6,14 +6,14 @@ class SquashRun : public PhysicsModel { protected: // Initialisation - int init(bool restarting) { + int init(bool UNUSED(restarting)) { solver->add(f2, "f2"); solver->add(f3, "f3"); return 0; } // Calculate time-derivatives - int rhs(BoutReal t) { + int rhs(BoutReal UNUSED(t)) { ddt(f2) = 1; ddt(f3) = -1; f2.applyBoundary(); diff --git a/tests/integrated/test-visitor/test_visitor.cxx b/tests/integrated/test-visitor/test_visitor.cxx index 0e4e1c25b0..95bb980449 100644 --- a/tests/integrated/test-visitor/test_visitor.cxx +++ b/tests/integrated/test-visitor/test_visitor.cxx @@ -3,15 +3,15 @@ #include class MyVisitor : public FieldVisitor { - void accept(Field2D &f) override { output << "Field2D" << endl; } + void accept(Field2D &UNUSED(f)) override { output << "Field2D" << endl; } - void accept(Field3D &f) override { output << "Field3D" << endl; } + void accept(Field3D &UNUSED(f)) override { output << "Field3D" << endl; } - void accept(FieldPerp &f) override { output << "FieldPerp" << endl; } + void accept(FieldPerp &UNUSED(f)) override { output << "FieldPerp" << endl; } - void accept(Vector2D &f) override { output << "Vector2D\n"; } + void accept(Vector2D &UNUSED(f)) override { output << "Vector2D\n"; } - void accept(Vector3D &f) override { output << "Vector3D" << endl; } + void accept(Vector3D &UNUSED(f)) override { output << "Vector3D" << endl; } }; int main(int argc, char** argv) { From 843b30ab32186fadb721f63ed40cf2190253c873 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 24 May 2019 10:43:20 +0100 Subject: [PATCH 1484/1783] Replace EnableIfField with static_assert of is_Field where appropriate EnableIfField is only needed for functions which might be called on non-Field variables. E.g. for 'toFieldAligned' it is clearer to have a static_assert(bout::utils::is_Field::value), which can give a helpful compile-error message. --- include/field.hxx | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/include/field.hxx b/include/field.hxx index b5f2542445..2329c3c17b 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -196,7 +196,7 @@ inline bool areFieldsCompatible(const Field& field1, const Field& field2) { /// Return an empty shell field of some type derived from Field, with metadata /// copied and a data array that is allocated but not initialised. -template> +template inline T emptyFrom(const T& f) { static_assert(bout::utils::is_Field::value, "emptyFrom only works on Fields"); return T(f.getMesh(), f.getLocation(), {f.getDirectionY(), f.getDirectionZ()}).allocate(); @@ -204,9 +204,9 @@ inline T emptyFrom(const T& f) { /// Return a field of some type derived from Field, with metadata copied from /// another field and a data array allocated and initialised to zero. -template> +template inline T zeroFrom(const T& f) { - static_assert(bout::utils::is_Field::value, "emptyFrom only works on Fields"); + static_assert(bout::utils::is_Field::value, "zeroFrom only works on Fields"); T result{emptyFrom(f)}; result = 0.; return result; @@ -214,9 +214,9 @@ inline T zeroFrom(const T& f) { /// Return a field of some type derived from Field, with metadata copied from /// another field and a data array allocated and filled with the given value. -template> +template inline T filledFrom(const T& f, BoutReal fill_value) { - static_assert(bout::utils::is_Field::value, "emptyFrom only works on Fields"); + static_assert(bout::utils::is_Field::value, "filledFrom only works on Fields"); T result{emptyFrom(f)}; result = fill_value; return result; @@ -276,22 +276,24 @@ inline void checkPositive(const T& f, const std::string& name="field", const std //////////////// NON-MEMBER FUNCTIONS ////////////////// -template> +template inline T toFieldAligned(const T& f, const std::string& region = "RGN_ALL") { + static_assert(bout::utils::is_Field::value, "toFieldAligned only works on Fields"); return f.getCoordinates()->getParallelTransform().toFieldAligned(f, region); } -template> +template [[gnu::deprecated("Please use toFieldAligned(const T& f, " "const std::string& region = \"RGN_ALL\") instead")]] inline T toFieldAligned(const T& f, REGION region) { return toFieldAligned(f, toString(region)); } -template> +template inline T fromFieldAligned(const T& f, const std::string& region = "RGN_ALL") { + static_assert(bout::utils::is_Field::value, "fromFieldAligned only works on Fields"); return f.getCoordinates()->getParallelTransform().fromFieldAligned(f, region); } -template> +template [[gnu::deprecated("Please use fromFieldAligned(const T& f, " "const std::string& region = \"RGN_ALL\") instead")]] inline T fromFieldAligned(const T& f, REGION region) { From d2a214efc178d4a20a680a51fe7e6c171ad1da12 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 24 May 2019 10:55:56 +0100 Subject: [PATCH 1485/1783] Remove 'const' from return types of derivatives in Coordinates --- include/bout/coordinates.hxx | 98 +++++++++++++++++------------------- src/mesh/coordinates.cxx | 59 +++++++++++----------- 2 files changed, 74 insertions(+), 83 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index 83b89b165c..36dbd20231 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -139,104 +139,96 @@ public: // Operators /////////////////////////////////////////////////////////// - const Field2D DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); - const Field2D DDX(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - const std::string& region = "RGN_NOBNDRY") { + Field2D DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); + Field2D DDX(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + const std::string& region = "RGN_NOBNDRY") { return DDX(f, outloc, toString(method), region); }; - const Field2D DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); - const Field2D DDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - const std::string& region = "RGN_NOBNDRY") { + Field2D DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); + Field2D DDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + const std::string& region = "RGN_NOBNDRY") { return DDY(f, outloc, toString(method), region); }; - const Field2D DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT", - const std::string& region = "RGN_NOBNDRY"); - const Field2D DDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - const std::string& region = "RGN_NOBNDRY") { + Field2D DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); + Field2D DDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, + const std::string& region = "RGN_NOBNDRY") { return DDZ(f, outloc, toString(method), region); }; /// Gradient along magnetic field b.Grad(f) - const Field2D Grad_par(const Field2D& var, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - const Field2D Grad_par(const Field2D& var, CELL_LOC outloc, DIFF_METHOD method) { + Field2D Grad_par(const Field2D& var, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + Field2D Grad_par(const Field2D& var, CELL_LOC outloc, DIFF_METHOD method) { return Grad_par(var, outloc, toString(method)); }; - const Field3D Grad_par(const Field3D& var, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - const Field3D Grad_par(const Field3D& var, CELL_LOC outloc, DIFF_METHOD method) { + Field3D Grad_par(const Field3D& var, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + Field3D Grad_par(const Field3D& var, CELL_LOC outloc, DIFF_METHOD method) { return Grad_par(var, outloc, toString(method)); }; /// Advection along magnetic field V*b.Grad(f) - const Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, - CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - const Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, CELL_LOC outloc, - DIFF_METHOD method) { + Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, + CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); + Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, CELL_LOC outloc, + DIFF_METHOD method) { return Vpar_Grad_par(v, f, outloc, toString(method)); }; - const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, - CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - const Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, CELL_LOC outloc, - DIFF_METHOD method) { + Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, + CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); + Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, CELL_LOC outloc, + DIFF_METHOD method) { return Vpar_Grad_par(v, f, outloc, toString(method)); }; /// Divergence along magnetic field Div(b*f) = B.Grad(f/B) - const Field2D Div_par(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - const Field2D Div_par(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { + Field2D Div_par(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + Field2D Div_par(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { return Div_par(f, outloc, toString(method)); }; - const Field3D Div_par(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - const Field3D Div_par(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { + Field3D Div_par(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + Field3D Div_par(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { return Div_par(f, outloc, toString(method)); }; // Second derivative along magnetic field - const Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - const Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { + Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { return Grad2_par2(f, outloc, toString(method)); }; - const Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - const std::string& method = "DEFAULT"); - const Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { + Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, + const std::string& method = "DEFAULT"); + Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { return Grad2_par2(f, outloc, toString(method)); }; // Perpendicular Laplacian operator, using only X-Z derivatives // NOTE: This might be better bundled with the Laplacian inversion code // since it makes use of the same coefficients and FFT routines - const Field2D Delp2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, - bool useFFT = true); - const Field3D Delp2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, - bool useFFT = true); - const FieldPerp Delp2(const FieldPerp& f, CELL_LOC outloc = CELL_DEFAULT, - bool useFFT = true); + Field2D Delp2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, bool useFFT = true); + Field3D Delp2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, bool useFFT = true); + FieldPerp Delp2(const FieldPerp& f, CELL_LOC outloc = CELL_DEFAULT, bool useFFT = true); // Full parallel Laplacian operator on scalar field // Laplace_par(f) = Div( b (b dot Grad(f)) ) - const Field2D Laplace_par(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT); - const Field3D Laplace_par(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT); + Field2D Laplace_par(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT); + Field3D Laplace_par(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT); // Full Laplacian operator on scalar field - const Field2D Laplace(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT); - const Field3D Laplace(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT); + Field2D Laplace(const Field2D &f, CELL_LOC outloc=CELL_DEFAULT); + Field3D Laplace(const Field3D &f, CELL_LOC outloc=CELL_DEFAULT); private: int nz; // Size of mesh in Z. This is mesh->ngz-1 diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index f3b30ab8b7..a0213ec0f7 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -1158,20 +1158,20 @@ void Coordinates::setParallelTransform(Options* options) { * *******************************************************************************/ -const Field2D Coordinates::DDX(const Field2D& f, CELL_LOC loc, const std::string& method, - const std::string& region) { +Field2D Coordinates::DDX(const Field2D& f, CELL_LOC loc, const std::string& method, + const std::string& region) { ASSERT1(location == loc || loc == CELL_DEFAULT); return bout::derivatives::index::DDX(f, loc, method, region) / dx; } -const Field2D Coordinates::DDY(const Field2D& f, CELL_LOC loc, const std::string& method, - const std::string& region) { +Field2D Coordinates::DDY(const Field2D& f, CELL_LOC loc, const std::string& method, + const std::string& region) { ASSERT1(location == loc || loc == CELL_DEFAULT); return bout::derivatives::index::DDY(f, loc, method, region) / dy; } -const Field2D Coordinates::DDZ(MAYBE_UNUSED(const Field2D& f), CELL_LOC loc, - const std::string& UNUSED(method), const std::string& UNUSED(region)) { +Field2D Coordinates::DDZ(MAYBE_UNUSED(const Field2D& f), CELL_LOC loc, + const std::string& UNUSED(method), const std::string& UNUSED(region)) { ASSERT1(location == loc || loc == CELL_DEFAULT); ASSERT1(f.getMesh() == localmesh); if (loc == CELL_DEFAULT) { @@ -1185,8 +1185,8 @@ const Field2D Coordinates::DDZ(MAYBE_UNUSED(const Field2D& f), CELL_LOC loc, ///////////////////////////////////////////////////////// // Parallel gradient -const Field2D Coordinates::Grad_par(const Field2D& var, MAYBE_UNUSED(CELL_LOC outloc), - const std::string& UNUSED(method)) { +Field2D Coordinates::Grad_par(const Field2D& var, MAYBE_UNUSED(CELL_LOC outloc), + const std::string& UNUSED(method)) { TRACE("Coordinates::Grad_par( Field2D )"); ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == var.getLocation())); @@ -1194,8 +1194,8 @@ const Field2D Coordinates::Grad_par(const Field2D& var, MAYBE_UNUSED(CELL_LOC ou return DDY(var) / sqrt(g_22); } -const Field3D Coordinates::Grad_par(const Field3D& var, CELL_LOC outloc, - const std::string& method) { +Field3D Coordinates::Grad_par(const Field3D& var, CELL_LOC outloc, + const std::string& method) { TRACE("Coordinates::Grad_par( Field3D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); @@ -1206,15 +1206,14 @@ const Field3D Coordinates::Grad_par(const Field3D& var, CELL_LOC outloc, // Vpar_Grad_par // vparallel times the parallel derivative along unperturbed B-field -const Field2D Coordinates::Vpar_Grad_par(const Field2D& v, const Field2D& f, - MAYBE_UNUSED(CELL_LOC outloc), - const std::string& UNUSED(method)) { +Field2D Coordinates::Vpar_Grad_par(const Field2D& v, const Field2D& f, + MAYBE_UNUSED(CELL_LOC outloc), const std::string& UNUSED(method)) { ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == f.getLocation())); return VDDY(v, f) / sqrt(g_22); } -const Field3D Coordinates::Vpar_Grad_par(const Field3D& v, const Field3D& f, - CELL_LOC outloc, const std::string& method) { +Field3D Coordinates::Vpar_Grad_par(const Field3D& v, const Field3D& f, CELL_LOC outloc, + const std::string& method) { ASSERT1(location == outloc || outloc == CELL_DEFAULT); return VDDY(v, f, outloc, method) / sqrt(g_22); } @@ -1222,8 +1221,8 @@ const Field3D Coordinates::Vpar_Grad_par(const Field3D& v, const Field3D& f, ///////////////////////////////////////////////////////// // Parallel divergence -const Field2D Coordinates::Div_par(const Field2D& f, CELL_LOC outloc, - const std::string& method) { +Field2D Coordinates::Div_par(const Field2D& f, CELL_LOC outloc, + const std::string& method) { TRACE("Coordinates::Div_par( Field2D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); @@ -1234,8 +1233,8 @@ const Field2D Coordinates::Div_par(const Field2D& f, CELL_LOC outloc, return Bxy * Grad_par(f / Bxy_floc, outloc, method); } -const Field3D Coordinates::Div_par(const Field3D& f, CELL_LOC outloc, - const std::string& method) { +Field3D Coordinates::Div_par(const Field3D& f, CELL_LOC outloc, + const std::string& method) { TRACE("Coordinates::Div_par( Field3D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); @@ -1261,8 +1260,8 @@ const Field3D Coordinates::Div_par(const Field3D& f, CELL_LOC outloc, // second parallel derivative (b dot Grad)(b dot Grad) // Note: For parallel Laplacian use Laplace_par -const Field2D Coordinates::Grad2_par2(const Field2D& f, CELL_LOC outloc, - const std::string& method) { +Field2D Coordinates::Grad2_par2(const Field2D& f, CELL_LOC outloc, + const std::string& method) { TRACE("Coordinates::Grad2_par2( Field2D )"); ASSERT1(location == outloc || (outloc == CELL_DEFAULT && location == f.getLocation())); @@ -1273,8 +1272,8 @@ const Field2D Coordinates::Grad2_par2(const Field2D& f, CELL_LOC outloc, return result; } -const Field3D Coordinates::Grad2_par2(const Field3D& f, CELL_LOC outloc, - const std::string& method) { +Field3D Coordinates::Grad2_par2(const Field3D& f, CELL_LOC outloc, + const std::string& method) { TRACE("Coordinates::Grad2_par2( Field3D )"); if (outloc == CELL_DEFAULT) { outloc = f.getLocation(); @@ -1300,7 +1299,7 @@ const Field3D Coordinates::Grad2_par2(const Field3D& f, CELL_LOC outloc, #include // Delp2 uses same coefficients as inversion code -const Field2D Coordinates::Delp2(const Field2D& f, CELL_LOC outloc, bool UNUSED(useFFT)) { +Field2D Coordinates::Delp2(const Field2D& f, CELL_LOC outloc, bool UNUSED(useFFT)) { TRACE("Coordinates::Delp2( Field2D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); @@ -1309,7 +1308,7 @@ const Field2D Coordinates::Delp2(const Field2D& f, CELL_LOC outloc, bool UNUSED( return result; } -const Field3D Coordinates::Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) { +Field3D Coordinates::Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) { TRACE("Coordinates::Delp2( Field3D )"); if (outloc == CELL_DEFAULT) { @@ -1372,7 +1371,7 @@ const Field3D Coordinates::Delp2(const Field3D& f, CELL_LOC outloc, bool useFFT) return result; } -const FieldPerp Coordinates::Delp2(const FieldPerp& f, CELL_LOC outloc, bool useFFT) { +FieldPerp Coordinates::Delp2(const FieldPerp& f, CELL_LOC outloc, bool useFFT) { TRACE("Coordinates::Delp2( FieldPerp )"); if (outloc == CELL_DEFAULT) { @@ -1434,19 +1433,19 @@ const FieldPerp Coordinates::Delp2(const FieldPerp& f, CELL_LOC outloc, bool use return result; } -const Field2D Coordinates::Laplace_par(const Field2D& f, CELL_LOC outloc) { +Field2D Coordinates::Laplace_par(const Field2D& f, CELL_LOC outloc) { ASSERT1(location == outloc || outloc == CELL_DEFAULT); return D2DY2(f, outloc) / g_22 + DDY(J / g_22, outloc) * DDY(f, outloc) / J; } -const Field3D Coordinates::Laplace_par(const Field3D& f, CELL_LOC outloc) { +Field3D Coordinates::Laplace_par(const Field3D& f, CELL_LOC outloc) { ASSERT1(location == outloc || outloc == CELL_DEFAULT); return D2DY2(f, outloc) / g_22 + DDY(J / g_22, outloc) * ::DDY(f, outloc) / J; } // Full Laplacian operator on scalar field -const Field2D Coordinates::Laplace(const Field2D& f, CELL_LOC outloc) { +Field2D Coordinates::Laplace(const Field2D& f, CELL_LOC outloc) { TRACE("Coordinates::Laplace( Field2D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); @@ -1458,7 +1457,7 @@ const Field2D Coordinates::Laplace(const Field2D& f, CELL_LOC outloc) { return result; } -const Field3D Coordinates::Laplace(const Field3D& f, CELL_LOC outloc) { +Field3D Coordinates::Laplace(const Field3D& f, CELL_LOC outloc) { TRACE("Coordinates::Laplace( Field3D )"); ASSERT1(location == outloc || outloc == CELL_DEFAULT); From a4443027a34dcf92fce4847ecdd9938dc818883f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 24 May 2019 13:50:54 +0100 Subject: [PATCH 1486/1783] Only call checkPositive(g) for grid cells Avoids exceptions being thrown due to negative values in guard cells. The guard cells of g are not necessarily used to calculate J=1/sqrt(g) - when the metric components are extrapolated, it is more robust to extrapolate J rather than calculating from the extrapolated metric coefficients. In any case, we check that J is finite and positive after extrapolating into the guard cells. The check for positiveness of g is only intended to help track down where an error in J came from, the checks on J are sufficient to guarantee that it is correct; therefore it is safe to change the check on g to just RGN_NOBNDRY. --- src/mesh/coordinates.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 287bdc6559..dffb3c568e 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -1044,7 +1044,7 @@ int Coordinates::jacobian() { - g33 * g12 * g12; // Check that g is positive - bout::checkPositive(g, "The determinant of g^ij", "RGN_NOCORNERS"); + bout::checkPositive(g, "The determinant of g^ij", "RGN_NOBNDRY"); J = 1. / sqrt(g); // More robust to extrapolate derived quantities directly, rather than From baaf06929925a549e3026e562fa11b684de4ca8d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 26 May 2019 20:30:15 +0100 Subject: [PATCH 1487/1783] Correct calculation of Bxy when interpolating from CELL_CENTRE --- src/mesh/coordinates.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 287bdc6559..341ae7b666 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -584,7 +584,7 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, g_23 = interpolateAndExtrapolate(coords_in->g_23, location); J = interpolateAndExtrapolate(coords_in->J, location); - Bxy = interpolateAndExtrapolate(coords_in->J, location); + Bxy = interpolateAndExtrapolate(coords_in->Bxy, location); bout::checkFinite(J, "The Jacobian", "RGN_NOCORNERS"); bout::checkPositive(J, "The Jacobian", "RGN_NOCORNERS"); From ae5f2563fdb925b1f53b676c52f28bd1b6484f71 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 30 May 2019 10:55:21 +0100 Subject: [PATCH 1488/1783] Use RGN_NOCORNERS in calcCovariant to ensure boundaries are correct Actual boundary corners are still invalid --- src/mesh/coordinates.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index c40b78aa5b..204e0c7feb 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -313,13 +313,13 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) output_warn.write("Not all covariant components of metric tensor found. " "Calculating all from the contravariant tensor\n"); /// Calculate contravariant metric components if not found - if (calcCovariant("RGN_NOBNDRY")) { + if (calcCovariant("RGN_NOCORNERS")) { throw BoutException("Error in calcCovariant call"); } } } else { /// Calculate contravariant metric components if not found - if (calcCovariant("RGN_NOBNDRY")) { + if (calcCovariant("RGN_NOCORNERS")) { throw BoutException("Error in calcCovariant call"); } } @@ -510,13 +510,13 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, output_warn.write("Not all staggered covariant components of metric tensor found. " "Calculating all from the contravariant tensor\n"); /// Calculate contravariant metric components if not found - if (calcCovariant("RGN_NOBNDRY")) { + if (calcCovariant("RGN_NOCORNERS")) { throw BoutException("Error in staggered calcCovariant call"); } } } else { /// Calculate contravariant metric components if not found - if (calcCovariant("RGN_NOBNDRY")) { + if (calcCovariant("RGN_NOCORNERS")) { throw BoutException("Error in staggered calcCovariant call"); } } From 90c0073b563b4f2b3bc3ecb77ada577c9dd22019 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 30 May 2019 10:56:32 +0100 Subject: [PATCH 1489/1783] Enable signalling floating-point checks on Travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5a8995d613..c22802bce3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -65,7 +65,7 @@ matrix: - *standard_packages env: - *default_env - - CONFIGURE_OPTIONS="--enable-debug --with-petsc --with-slepc --with-sundials=$HOME/local" + - CONFIGURE_OPTIONS="--enable-sigfpe --enable-debug --with-petsc --with-slepc --with-sundials=$HOME/local" - CC=gcc-7 CXX=g++-7 - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" - env: From 631cd69be96a942d74258845f0e521887cc0b505 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 30 May 2019 11:34:24 +0100 Subject: [PATCH 1490/1783] Restore floating-point exception handler and exceptions in unit test --- tests/unit/src/test_bout++.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/unit/src/test_bout++.cxx b/tests/unit/src/test_bout++.cxx index 38d89e141e..4946b57f75 100644 --- a/tests/unit/src/test_bout++.cxx +++ b/tests/unit/src/test_bout++.cxx @@ -314,6 +314,11 @@ TEST_F(PrintStartupTest, CommandLineArguments) { } #ifdef SIGHANDLE + +#ifdef BOUT_FPE +#include +#endif + class SignalHandlerTest : public ::testing::Test { public: SignalHandlerTest() = default; @@ -321,6 +326,10 @@ class SignalHandlerTest : public ::testing::Test { std::signal(SIGUSR1, SIG_DFL); std::signal(SIGFPE, SIG_DFL); std::signal(SIGSEGV, SIG_DFL); +#ifdef BOUT_FPE + std::signal(SIGFPE, SIG_DFL); + fedisableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); +#endif } }; From 0db2423d2fe794e945885e897aeac0f5b1bd4cb3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 30 May 2019 14:30:50 +0100 Subject: [PATCH 1491/1783] Staggered version of test-twistshift Tests use of ShiftedMetric at CELL_YLOW. Also calculates an expected version of 'test_aligned', called 'check', rather than transforming back to x-z orthogonal coordinates. This avoids masking errors where an incorrect zShift is not noticed because it is used for both to- and from-field-aligned transformations. --- .../test-twistshift-staggered/data/BOUT.inp | 17 ++++++ .../test-twistshift-staggered/makefile | 5 ++ .../test-twistshift-staggered/runtest | 53 +++++++++++++++++++ .../test-twistshift.cxx | 32 +++++++++++ .../integrated/test-twistshift/data/BOUT.inp | 2 +- 5 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 tests/integrated/test-twistshift-staggered/data/BOUT.inp create mode 100644 tests/integrated/test-twistshift-staggered/makefile create mode 100755 tests/integrated/test-twistshift-staggered/runtest create mode 100644 tests/integrated/test-twistshift-staggered/test-twistshift.cxx diff --git a/tests/integrated/test-twistshift-staggered/data/BOUT.inp b/tests/integrated/test-twistshift-staggered/data/BOUT.inp new file mode 100644 index 0000000000..f9fa78ae08 --- /dev/null +++ b/tests/integrated/test-twistshift-staggered/data/BOUT.inp @@ -0,0 +1,17 @@ +twistshift = true + +test = sin(y+1.) * (x+0.2)^2 * cos(z) +check = sin(y+1.) * (x+0.2)^2 * cos(z + mesh:zShift) + +[mesh] +staggergrids = true +paralleltransform = shifted +nx = 5 +ny = 7 +nz = 5 + +zShift = (y-0.5) * (x+1) +ShiftAngle = 2*pi*(x+1) + +[input] +transform_from_field_aligned = false diff --git a/tests/integrated/test-twistshift-staggered/makefile b/tests/integrated/test-twistshift-staggered/makefile new file mode 100644 index 0000000000..0018135bce --- /dev/null +++ b/tests/integrated/test-twistshift-staggered/makefile @@ -0,0 +1,5 @@ +BOUT_TOP = ../../.. + +SOURCEC = test-twistshift.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-twistshift-staggered/runtest b/tests/integrated/test-twistshift-staggered/runtest new file mode 100755 index 0000000000..ed5567fbda --- /dev/null +++ b/tests/integrated/test-twistshift-staggered/runtest @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +from boutdata import collect +from boututils.run_wrapper import launch_safe, shell_safe +import numpy +from sys import exit + +datapath = 'data' +nproc = 1 +tol = 1.e-13 + +print('Making twistshift test') +shell_safe('make > make.log') + +s, out = launch_safe('./test-twistshift', nproc=nproc, pipe=True) +with open("run.log."+str(nproc), "w") as f: + f.write(out) + +test = collect('test', path=datapath, yguards=True, info=False) +test_aligned = collect('test_aligned', path=datapath, yguards=True, info=False) +check = collect('check', path=datapath, yguards=True, info=False) + +#from boututils.showdata import showdata +#showdata([test, test_aligned, check], titles=['test', 'test_aligned', 'check']) + +success = True + +# Check test_aligned is *not* periodic in y +def test1(ylower, yupper): + global success + if numpy.any(numpy.abs(test_aligned[:, yupper, :] - test_aligned[:, ylower, :]) < 1.e-6): + success = False + print("Fail - test_aligned should not be periodic jy=%i and jy=%i should be " + "different", yupper, ylower) +test1(0,-4) +test1(1,-3) +test1(2,-2) +test1(3,-1) + +# Check test_aligned is the same as check +# Cannot check in guard cells, as the expression used for 'zShift' in the input file is +# not the same as the corrected zShift used for the transforms in the guard cells +if numpy.any(numpy.abs(test_aligned[2:-2, 2:-2, :] - check[2:-2, 2:-2, :]) > tol): + success = False + print('Fail - test_aligned is different from the expected value') + print('test_aligned', test_aligned) + print('check', check) + +if success: + print('Pass') + exit(0) +else: + exit(1) diff --git a/tests/integrated/test-twistshift-staggered/test-twistshift.cxx b/tests/integrated/test-twistshift-staggered/test-twistshift.cxx new file mode 100644 index 0000000000..5b482db922 --- /dev/null +++ b/tests/integrated/test-twistshift-staggered/test-twistshift.cxx @@ -0,0 +1,32 @@ +#include "bout.hxx" +#include "field_factory.hxx" + +int main(int argc, char** argv) { + BoutInitialise(argc, argv); + + Field3D test = FieldFactory::get()->create3D("test", nullptr, nullptr, CELL_YLOW); + + Field3D test_aligned = toFieldAligned(test); + + // zero guard cells to check that communication is doing something + for (int x=0; xLocalNx; x++) { + for (int z=0; zLocalNz; z++) { + for (int y=0; yystart; y++) { + test_aligned(x, y, z) = 0.; + } + for (int y=mesh->yend+1; yLocalNy; y++) { + test_aligned(x, y, z) = 0.; + } + } + } + + mesh->communicate(test_aligned); + + Field3D check = FieldFactory::get()->create3D("check", nullptr, nullptr, CELL_YLOW); + + SAVE_ONCE(test, test_aligned, check); + + dump.write(); + + BoutFinalise(); +} diff --git a/tests/integrated/test-twistshift/data/BOUT.inp b/tests/integrated/test-twistshift/data/BOUT.inp index 87a058f6c2..284b4006ed 100644 --- a/tests/integrated/test-twistshift/data/BOUT.inp +++ b/tests/integrated/test-twistshift/data/BOUT.inp @@ -9,7 +9,7 @@ ny = 7 nz = 5 zShift = (y-0.5) * (x+1) -ShiftAngle = (x+1) +ShiftAngle = 2.*pi*(x+1) [input] transform_from_field_aligned = false From 104b244201a065df3394a03648c80d9e22298a1f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 30 May 2019 17:37:23 +0100 Subject: [PATCH 1492/1783] Fix interpolation of staggered zShift zShift needs to have its guard cells correctly initialized. Previously when initializing a staggered zShift, if the staggered zShift was not present in the input grid then an unstaggered zShift was read from the grid and interpolated to the staggered location; it had not had its guard cells corrected and this led to errors. This commit applies the guard cell fixes to the cell-centre zShift before interpolating to staggered grid. --- src/mesh/coordinates.cxx | 64 ++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index b157102a50..d495bea00d 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -1069,6 +1069,37 @@ int Coordinates::jacobian() { return 0; } +namespace { +// Utility function for fixing up guard cells of zShift +void fixZShiftGuards(Field2D& zShift) { + auto localmesh = zShift.getMesh(); + + // extrapolate into boundary guard cells if necessary + interpolateAndExtrapolate(zShift, zShift.getLocation(), + not localmesh->sourceHasXBoundaryGuards(), + not localmesh->sourceHasYBoundaryGuards()); + + // make sure zShift has been communicated + localmesh->communicate(zShift); + + // Correct guard cells for discontinuity of zShift at poloidal branch cut + for (int x = 0; x < localmesh->LocalNx; x++) { + const auto lower = localmesh->hasBranchCutLower(x); + if (lower.first) { + for (int y = 0; y < localmesh->ystart; y++) { + zShift(x, y) -= lower.second; + } + } + const auto upper = localmesh->hasBranchCutUpper(x); + if (upper.first) { + for (int y = localmesh->yend + 1; y < localmesh->LocalNy; y++) { + zShift(x, y) += upper.second; + } + } + } +} +} + void Coordinates::setParallelTransform(Options* options) { std::string ptstr; @@ -1098,42 +1129,23 @@ void Coordinates::setParallelTransform(Options* options) { throw BoutException("Could not read zShift"+suffix+" from grid file"); } } - - // extrapolate into boundary guard cells if necessary - interpolateAndExtrapolate(zShift, location, - not localmesh->sourceHasXBoundaryGuards(), - not localmesh->sourceHasYBoundaryGuards()); } else { - if (localmesh->get(zShift, "zShift")) { + Field2D zShift_centre; + if (localmesh->get(zShift_centre, "zShift")) { // No zShift variable. Try qinty in BOUT grid files - if (localmesh->get(zShift, "qinty")) { + if (localmesh->get(zShift_centre, "qinty")) { // Failed to find either variable, cannot use ShiftedMetric throw BoutException("Could not read zShift"+suffix+" from grid file"); } } - zShift = interpolateAndExtrapolate(zShift, location); - } - - // make sure zShift has been communicated - localmesh->communicate(zShift); + fixZShiftGuards(zShift_centre); - // Correct guard cells for discontinuity of zShift at poloidal branch cut - for (int x = 0; x < localmesh->LocalNx; x++) { - const auto lower = localmesh->hasBranchCutLower(x); - if (lower.first) { - for (int y = 0; y < localmesh->ystart; y++) { - zShift(x, y) -= lower.second; - } - } - const auto upper = localmesh->hasBranchCutUpper(x); - if (upper.first) { - for (int y = localmesh->yend + 1; y < localmesh->LocalNy; y++) { - zShift(x, y) += upper.second; - } - } + zShift = interpolateAndExtrapolate(zShift_centre, location); } + fixZShiftGuards(zShift); + transform = bout::utils::make_unique(*localmesh, location, zShift, zlength()); From e465da399f80f75e871882613fc3423e67100e78 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 3 Jun 2019 11:48:46 +0100 Subject: [PATCH 1493/1783] Workarounds for signalling floating point errors in test-laplace This avoids one FPE in BOUT++ and one in NetCDF: - Don't do non-uniform correction in Laplacian - Corners of geometry variables are explicitly set to NaNs, and non-uniform correction involves derivative of dx in y-guards - Don't convert to floats in output in test-laplace - NetCDF does a comparison when converting from double -> float to check for out-of-range errors. This comparison signals with NaNs - Loosen tolerance in test-laplace - Benchmark fields are floats, but tolerance is smaller than single-precision! --- tests/integrated/test-laplace/data/BOUT.inp | 5 +---- tests/integrated/test-laplace/runtest | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/integrated/test-laplace/data/BOUT.inp b/tests/integrated/test-laplace/data/BOUT.inp index 3cb058dca2..286de10079 100644 --- a/tests/integrated/test-laplace/data/BOUT.inp +++ b/tests/integrated/test-laplace/data/BOUT.inp @@ -8,7 +8,7 @@ NOUT = 0 # No timesteps MZ = 32 # Z size grid = "test_laplace.grd.nc" - +non_uniform = false dump_format = "nc" # NetCDF format. Alternative is "pdb" [mesh] @@ -19,6 +19,3 @@ symmetricGlobalY = false all_terms = false include_yguards = true filter = 0.2 - -[output] -floats = true diff --git a/tests/integrated/test-laplace/runtest b/tests/integrated/test-laplace/runtest index 35cb484a73..8b641ac4e2 100755 --- a/tests/integrated/test-laplace/runtest +++ b/tests/integrated/test-laplace/runtest @@ -15,7 +15,7 @@ vars = ['flag0', 'flag3', 'flagis', 'flagos', 'flag0a', 'flag3a', 'flagisa', 'flagosa', 'flag0ac', 'flag3ac','flagisac', 'flagosac', 'flag0ad', 'flag3ad', 'flagisad', 'flagosad'] -tol = 1e-10 # Absolute tolerance +tol = 1e-6 # Absolute tolerance from boututils.run_wrapper import shell, shell_safe, launch_safe from boutdata.collect import collect From a3631927fcfccb5d112f85689dc51746b399cabc Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 3 Jun 2019 11:08:46 +0100 Subject: [PATCH 1494/1783] Include g13*dc/dx*df/dz terms in FFT Laplacian solvers Previously this term was neglected. --- src/invert/laplace/invert_laplace.cxx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index 725a68943e..0fb6e60ae1 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -336,9 +336,12 @@ void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, } if (c1coef != nullptr) { - // A first order derivative term - if((jx > 0) && (jx < (localmesh->LocalNx-1))) - coef4 += localcoords->g11(jx,jy) * ((*c2coef)(jx+1,jy) - (*c2coef)(jx-1,jy)) / (2.*localcoords->dx(jx,jy)*((*c1coef)(jx,jy))); + // First derivative terms + if((jx > 0) && (jx < (localmesh->LocalNx-1))) { + BoutReal dc2dx_over_c1 = ((*c2coef)(jx+1,jy) - (*c2coef)(jx-1,jy)) / (2.*localcoords->dx(jx,jy)*((*c1coef)(jx,jy))); + coef4 += localcoords->g11(jx,jy) * dc2dx_over_c1; + coef5 += localcoords->g13(jx,jy) * dc2dx_over_c1; + } } if(localmesh->IncIntShear) { From 43518c9fc1a93909b6c2a99102c1fd5c05707f1d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 3 Jun 2019 12:04:42 +0100 Subject: [PATCH 1495/1783] Updates to Laplacian solvers section of manual Mostly to say that separate c1 and c2 coefficients are supported in the FFT solvers. Mention cyclic and multigrid solvers. Note 'invert_laplace' functions are deprecated. --- manual/sphinx/user_docs/laplacian.rst | 138 ++++++++++++++------------ 1 file changed, 77 insertions(+), 61 deletions(-) diff --git a/manual/sphinx/user_docs/laplacian.rst b/manual/sphinx/user_docs/laplacian.rst index e600923ca8..2a9268a3e4 100644 --- a/manual/sphinx/user_docs/laplacian.rst +++ b/manual/sphinx/user_docs/laplacian.rst @@ -88,7 +88,10 @@ and :math:`n_z` are the number of grid-points in the :math:`x` and In the second approach, the full :math:`2`\ -D system is being solved. -This requires PETSc to be built with BOUT++. +The available solvers for this approach are 'multigrid' using a multigrid +algorithm; 'naulin' using an iterative scheme to correct the FFT-based +approach; or 'petsc' using KSP linear solvers from the PETSc library (this +requires PETSc to be built with BOUT++). The `Laplacian` class is defined in ``invert_laplace.hxx`` and solves @@ -99,15 +102,17 @@ class, first create an instance of it:: By default, this will use the options in a section called “laplace”, but can be given a different section as an argument. By default -:math:`d = 1`, :math:`a = 0`, and the :math:`c=1`. To set the values of -these coefficients, there are the ``setCoefA()``, ``setCoefC()``, and -``setCoefD()`` methods:: +:math:`d = 1`, :math:`a = 0`, and :math:`c1=c2=1`. To set the values of +these coefficients, there are the ``setCoefA()``, ``setCoefC1()``, +``setCoefC2()``, ``setCoefC()`` (which sets both `c1` and `c2` to its +argument), and ``setCoefD()`` methods:: Field2D a = ...; lap->setCoefA(a); lap->setCoefC(0.5); -arguments can be `Field2D`, `Field3D`, or `BoutReal` values. +arguments can be `Field2D`, `Field3D`, or `BoutReal` values. Note that FFT +solvers will use only the DC part of `Field3D` arguments. Settings for the inversion can be set in the input file under the section ``laplace`` (default) or whichever settings section name was @@ -292,8 +297,8 @@ To perform the inversion, there’s the ``solve`` method x = lap->solve(b); -If you prefer, there are functions compatible with older versions of the -BOUT++ code:: +There are also functions compatible with older versions of the +BOUT++ code, but these are deprecated:: Field2D a, c, d; invert_laplace(b, x, flags, &a, &c, &d); @@ -341,17 +346,9 @@ for derivation) Using tridiagonal solvers ~~~~~~~~~~~~~~~~~~~~~~~~~ -When using the tridiagonal solvers, :math:`c_1 = c_2` in equation -:eq:`to_invert`, hence, it is rather solving - -.. math:: - :label: to_invert_tri - - d\nabla_\perp^2f + \frac{1}{c}(\nabla_\perp c)\cdot\nabla_\perp f + af = b - Since there are no parallel :math:`y`-derivatives if :math:`g_{xy}=g_{yz}=0` (or if they are neglected), equation -:eq:`to_invert_tri` will only contain derivatives of :math:`x` and +:eq:`to_invert` will only contain derivatives of :math:`x` and :math:`z` for the dependent variable. The hope is that the modes in the periodic :math:`z` direction will decouple, so that we in the end only have to invert for the :math:`x` coordinate. @@ -375,22 +372,19 @@ of two terms which depends on :math:`z`, as this would give terms like \frac{1}{N}\sum_{Z=0}^{N-1} a(x,y)_Z f(x,y)_Z \exp(\frac{-2\pi i k Z}{N}) -Thus, in order to use a tridiagonal solver, :math:`a`, :math:`c` and -:math:`d` cannot be functions of :math:`z`. Because of this, the +Thus, in order to use a tridiagonal solver, :math:`a`, :math:`c1`, :math:`c2` +and :math:`d` cannot be functions of :math:`z`. Because of this, the :math:`{{\boldsymbol{e}}}^z \partial_z c` term in equation -:eq:`invert_expanded` is zero. In principle the modes would still -decouple if the :math:`{{\boldsymbol{e}}}^z \partial_z f` -part of equation :eq:`invert_expanded` was kept, but currently this -part is also neglected in solvers using a tridiagonal matrix. Thus the -tridiagonal solvers are solving equations on the form +:eq:`invert_expanded` is zero. Thus the tridiagonal solvers are solving +equations of the form .. math:: \, &d(x,y) ( g^{xx}(x,y) \partial_x^2 + G^x(x,y) \partial_x + g^{zz}(x,y) \partial_z^2 + G^z(x,y) \partial_z + 2g^{xz}(x,y) \partial_x \partial_z ) f(x,y,z) \\ - +& \frac{1}{c(x,y)}({{\boldsymbol{e}}}^x \partial_x ) c(x,y) \cdot ( - {{\boldsymbol{e}}}^x \partial_x ) f(x,y,z) \\ + +& \frac{1}{c_1(x,y)}({{\boldsymbol{e}}}^x \partial_x c_2(x,y) ) \cdot ( + {{\boldsymbol{e}}}^x \partial_x + \boldsymbol{e}^z \partial_z) f(x,y,z) \\ +& a(x,y)f(x,y,z) = b(x,y,z) after using the discrete Fourier transform (see section @@ -400,8 +394,8 @@ after using the discrete Fourier transform (see section \, &d ( g^{xx} \partial_x^2F_z + G^x \partial_xF_z + g^{zz} [i k]^2F_z + G^z [i k]F_z + 2g^{xz} \partial_x[i k]F_z ) \\ - +& \frac{1}{c}( {{\boldsymbol{e}}}^x \partial_x ) c \cdot ( {{\boldsymbol{e}}}^x - \partial_xF_z ) \\ + +& \frac{1}{c_1}( {{\boldsymbol{e}}}^x \partial_x c_2 ) \cdot ( {{\boldsymbol{e}}}^x + \partial_xF_z + \boldsymbol{e}^z i k F_z) \\ +& aF_z = B_z which gives @@ -411,15 +405,15 @@ which gives \, &d ( g^{xx} \partial_x^2 + G^x \partial_x - k^2 g^{zz} + i kG^z + i k2g^{xz} \partial_x )F_z \\ - +& \frac{g^{xx}}{c} (\partial_x c ) \partial_xF_z \\ + +& \frac{1}{c_1} (\partial_x c_2 ) (g^{xx}\partial_xF_z + g^{xz} i k F_z) \\ +& aF_z = B_z As nothing in equation :eq:`FT_laplace_inversion` couples points in :math:`y` together (since we neglected the :math:`y`-derivatives if -:math:`g_{xy}` and :math:`g_{yz}` were non-zero). Also, as the modes are -decoupled, we may solve equation :eq:`FT_laplace_inversion` :math:`k` -mode by :math:`k` mode in addition to :math:`y`\ -plane by -:math:`y`\ -plane. +:math:`g_{xy}` and :math:`g_{yz}` were non-zero) we can solve :math:`y`\ -plane +by :math:`y`\ -plane. Also, as the modes are decoupled, we may solve equation +:eq:`FT_laplace_inversion` :math:`k` mode by :math:`k` mode in addition to +:math:`y`\ -plane by :math:`y`\ -plane. The second order centred approximation of the first and second derivatives in :math:`x` reads @@ -433,12 +427,14 @@ This gives .. math:: - \, &d ( g^{xx} \frac{F_{z,n-1} - 2F_{z,n} + F_{z, n+1}}{\text{d}x^2} + - G^x \frac{-F_{z,n-1} + F_{z,n+1}}{2\text{d}x} - k^2 g^{zz}F_{z,n} .\\ - &\quad. + i kG^zF_{z,n} + i k2g^{xz} \frac{-F_{z,n-1} + - F_{z,n+1}}{2\text{d}x} ) \\ - +& \frac{g^{xx}}{c} ( \frac{-c_{n-1} + c_{n+1}}{2\text{d}x} ) - \frac{-F_{z,n-1} + F_{z,n+1}}{2\text{d}x} \\ + \, &d \left( g^{xx} \frac{F_{z,n-1} - 2F_{z,n} + F_{z, n+1}}{\text{d}x^2} + + G^x \frac{-F_{z,n-1} + F_{z,n+1}}{2\text{d}x} - k^2 g^{zz}F_{z,n} + \right. \\ + &\left. \quad + i kG^zF_{z,n} + i k2g^{xz} \frac{-F_{z,n-1} + + F_{z,n+1}}{2\text{d}x} \right) \\ + +& \frac{1}{c_1} \left( \frac{-c_{2,n-1} + c_{2,n+1}}{2\text{d}x} \right) + \left(g^{xx}\frac{-F_{z,n-1} + F_{z,n+1}}{2\text{d}x} + + g^{xz} i k F_{z,n} \right) \\ +& aF_{z,n} = B_{z,n} collecting point by point @@ -446,35 +442,37 @@ collecting point by point .. math:: :label: discretized_laplace - &( \frac{dg^{xx}}{\text{d}x^2} - \frac{dG^x}{2\text{d}x} - - \frac{g^{xx}}{c_{n}} \frac{-c_{n-1} + c_{n+1}}{4\text{d}x^2} - i\frac{d - k2g^{xz}}{2\text{d}x} ) F_{z,n-1} \\ - +&( - \frac{ dg^{xx} }{\text{d}x^2} - dk^2 g^{zz} + a + idkG^z ) + &\left( \frac{dg^{xx}}{\text{d}x^2} - \frac{dG^x}{2\text{d}x} - + \frac{g^{xx}}{c_{1,n}} \frac{-c_{2,n-1} + c_{2,n+1}}{4\text{d}x^2} - i\frac{d + k2g^{xz}}{2\text{d}x} \right) F_{z,n-1} \\ + +&\left( - \frac{ dg^{xx} }{\text{d}x^2} - dk^2 g^{zz} + a + idkG^z + + i\frac{g^{xz}}{c_{1,n}} \frac{-c_{2,n-1} + + c_{2,n+1}}{2\text{d}x}k \right) F_{z,n} \\ - +&( \frac{dg^{xx}}{\text{d}x^2} + \frac{dG^x}{2\text{d}x} + - \frac{g^{xx}}{c_{n}} \frac{-c_{n-1} + c_{n+1}}{4\text{d}x^2} + - i\frac{dk2g^{xz}}{2\text{d}x} ) F_{z, n+1} \\ - =& B_{z,n} + +&\left( \frac{dg^{xx}}{\text{d}x^2} + \frac{dG^x}{2\text{d}x} + + \frac{g^{xx}}{c_{1,n}} \frac{-c_{2,n-1} + c_{2,n+1}}{4\text{d}x^2} + + i\frac{dk2g^{xz}}{2\text{d}x} \right) F_{z, n+1} \\ + = B_{z,n} We now introduce .. math:: - c_1 = \frac{dg^{xx}}{\text{d}x^2} + C_1 &= \frac{dg^{xx}}{\text{d}x^2} - c_2 = dg^{zz} + C_2 &= dg^{zz} - c_3 = \frac{2dg^{xz}}{2\text{d}x} + C_3 &= \frac{2dg^{xz}}{2\text{d}x} - c_4 = \frac{dG^x + g^{xx}\frac{-c_{n-1} + c_{n+1}}{2c_n\text{d}x}}{2\text{d}x} + C_4 &= \frac{dG^x + g^{xx}\frac{-c_{2,n-1} + c_{2,n+1}}{2c_{1,n}\text{d}x}}{2\text{d}x} - c_5 = dG^z + C_5 &= dG^z + \frac{g^{xz}}{c_{1,n}} \frac{-c_{2,n-1} + c_{2,n+1}}{2\text{d}x} which inserted in equation :eq:`discretized_laplace` gives .. math:: - ( c_1 - c_4 -ikc_3 ) F_{z,n-1} + ( -2c_1 - k^2c_2 +ikc_5 + a ) F_{z,n} + ( c_1 + c_4 + ikc_3 ) F_{z, n+1} = B_{z,n} + ( C_1 - C_4 -ikC_3 ) F_{z,n-1} + ( -2C_1 - k^2C_2 +ikC_5 + a ) F_{z,n} + ( C_1 + C_4 + ikC_3 ) F_{z, n+1} = B_{z,n} This can be formulated as the matrix equation @@ -485,6 +483,9 @@ This can be formulated as the matrix equation where the matrix :math:`A` is tridiagonal. The boundary conditions are set by setting the first and last rows in :math:`A` and :math:`B_z`. +The tridiagonal solvers previously required :math:`c_1 = c_2` in equation +:eq:`to_invert`, but from version 4.3 allow :math:`c_1 \neq c_2`. + .. _sec-petsc-laplace: Using PETSc solvers @@ -662,14 +663,14 @@ Implementation internals The Laplacian inversion code solves the equation: -.. math:: d\nabla^2_\perp x + \frac{1}{c}\nabla_\perp c\cdot\nabla_\perp x + a x = b +.. math:: d\nabla^2_\perp x + \frac{1}{c_1}\nabla_\perp c_2\cdot\nabla_\perp x + a x = b where :math:`x` and :math:`b` are 3D variables, whilst :math:`a`, -:math:`c` and :math:`d` are 2D variables. Several different algorithms -are implemented for Laplacian inversion, and they differ between -serial and parallel versions. Serial inversion can currently either be -done using a tridiagonal solver (Thomas algorithm), or a band-solver -(allowing :math:`4^{th}`-order differencing). +:math:`c_1`, :math:`c_2` and :math:`d` are 2D variables for the FFT solvers, or +3D variables otherwise. Several different algorithms are implemented for +Laplacian inversion, and they differ between serial and parallel versions. +Serial inversion can currently either be done using a tridiagonal solver (Thomas +algorithm), or a band-solver (allowing :math:`4^{th}`-order differencing). To support multiple implementations, a base class `Laplacian` is defined in ``include/invert_laplace.hxx``. This defines a set of @@ -693,12 +694,13 @@ For convenience, the `Laplacian` base class also defines a function to calculate coefficients in a Tridiagonal matrix:: void tridagCoefs(int jx, int jy, int jz, dcomplex &a, dcomplex &b, - dcomplex &c, const Field2D *ccoef = NULL, - const Field2D *d=NULL); + dcomplex &c, const Field2D *c1coef = nullptr, + const Field2D *c2coef = nullptr, + const Field2D *d=nullptr); For the user of the class, some static functions are defined:: - static Laplacian* create(Options *opt = NULL); + static Laplacian* create(Options *opt = nullptr); static Laplacian* defaultInstance(); The create function allows new Laplacian implementations to be created, @@ -774,6 +776,20 @@ fast, but achieves this by neglecting some cross-processor terms. For ELM simulations, it has been found that these terms are important, so this method is not usually used. +.. _sec-cyclic: +Cyclic algorithm +~~~~~~~~~~~~~~~~ + +This is now the default solver in both serial and parallel. It is an FFT-based +solver using a cyclic reduction algorithm. + +.. _sec-multigrid: +Multigrid solver +~~~~~~~~~~~~~~~~ + +A solver using a geometric multigrid algorithm was introduced by projects in +2015 and 2016 of CCFE and the EUROfusion HLST. + .. _sec-naulin: Naulin solver From 8a06a8a71e6ff8b4d54d27b931987f8139d5df36 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 4 Jun 2019 11:38:49 +0100 Subject: [PATCH 1496/1783] Fix zShift extrapolation bug Previously the result of interpolateAndExtrapolate(zShift,...) was not being stored in zShift. --- src/mesh/coordinates.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index d495bea00d..7a028b0e1b 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -1075,7 +1075,7 @@ void fixZShiftGuards(Field2D& zShift) { auto localmesh = zShift.getMesh(); // extrapolate into boundary guard cells if necessary - interpolateAndExtrapolate(zShift, zShift.getLocation(), + zShift = interpolateAndExtrapolate(zShift, zShift.getLocation(), not localmesh->sourceHasXBoundaryGuards(), not localmesh->sourceHasYBoundaryGuards()); From f911b292eed0ed84f56f2a79bca0b7a9e6699db1 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 4 Jun 2019 11:38:06 +0100 Subject: [PATCH 1497/1783] Make zShift a const member of ShiftedMetric zShift should never be changed, and is initialized in the initializer list of the constructor, so can be const. --- include/bout/paralleltransform.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 286f84519e..04bce3eb38 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -183,7 +183,7 @@ private: /// This is the shift in toroidal angle (z) which takes a point from /// X-Z orthogonal to field-aligned along Y. - Field2D zShift; + const Field2D zShift; /// Length of the z-domain in radians BoutReal zlength{0.}; From eafb4034233432daf41c08bf322678e554c936f7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 4 Jun 2019 13:49:36 +0100 Subject: [PATCH 1498/1783] Fix to previous commit: keep non_uniform, turn off include_yguards Non-uniform correction is not needed for test-laplace, but is "more correct" that turning off include_yguards (which is sufficient workaround for issue with corner NaNs) --- tests/integrated/test-laplace/data/BOUT.inp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integrated/test-laplace/data/BOUT.inp b/tests/integrated/test-laplace/data/BOUT.inp index 286de10079..762e37744b 100644 --- a/tests/integrated/test-laplace/data/BOUT.inp +++ b/tests/integrated/test-laplace/data/BOUT.inp @@ -8,7 +8,7 @@ NOUT = 0 # No timesteps MZ = 32 # Z size grid = "test_laplace.grd.nc" -non_uniform = false + dump_format = "nc" # NetCDF format. Alternative is "pdb" [mesh] @@ -17,5 +17,5 @@ symmetricGlobalY = false [laplace] all_terms = false -include_yguards = true +include_yguards = false filter = 0.2 From 65c2df455dc25c1d9b3428d1cc2f0adc6b589cb2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 4 Jun 2019 16:59:37 +0100 Subject: [PATCH 1499/1783] Don't mark Coordinates::zShift as const, can't be output Unfortunately, `DataFile::add` takes fields by non-const ref! --- include/bout/paralleltransform.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 30f8bc6258..09091a93bd 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -189,7 +189,7 @@ private: /// This is the shift in toroidal angle (z) which takes a point from /// X-Z orthogonal to field-aligned along Y. - const Field2D zShift; + Field2D zShift; /// Length of the z-domain in radians BoutReal zlength{0.}; From 15836a33d4def802c0903c1d031757589406412d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 4 Jun 2019 17:34:22 +0100 Subject: [PATCH 1500/1783] Add deprecated overloads for differential operators in Coordinates --- include/bout/coordinates.hxx | 88 ++++++++++++++++++++++-------------- include/derivs.hxx | 6 +-- 2 files changed, 57 insertions(+), 37 deletions(-) diff --git a/include/bout/coordinates.hxx b/include/bout/coordinates.hxx index 36dbd20231..073bf15eb7 100644 --- a/include/bout/coordinates.hxx +++ b/include/bout/coordinates.hxx @@ -139,80 +139,100 @@ public: // Operators /////////////////////////////////////////////////////////// +#ifdef DERIV_FUNC_REGION_ENUM_TO_STRING +#error This utility macro should not clash with another one +#else +#define DERIV_FUNC_REGION_ENUM_TO_STRING(func, T) \ + [[gnu::deprecated("Please use Coordinates::#func(const #T& f, " \ + "CELL_LOC outloc = CELL_DEFAULT, const std::string& method = \"DEFAULT\", " \ + "const std::string& region = \"RGN_ALL\") instead")]] \ + inline T func(const T& f, CELL_LOC outloc, const std::string& method, \ + REGION region) { \ + return func(f, outloc, method, toString(region)); \ + } \ + [[gnu::deprecated("Please use Coordinates::#func(const #T& f, " \ + "CELL_LOC outloc = CELL_DEFAULT, const std::string& method = \"DEFAULT\", " \ + "const std::string& region = \"RGN_ALL\") instead")]] \ + inline T func(const T& f, CELL_LOC outloc, DIFF_METHOD method, \ + REGION region = RGN_NOBNDRY) { \ + return func(f, outloc, toString(method), toString(region)); \ + } +#endif + +#ifdef GRAD_FUNC_REGION_ENUM_TO_STRING +#error This utility macro should not clash with another one +#else +#define GRAD_FUNC_REGION_ENUM_TO_STRING(func, T) \ + [[gnu::deprecated("Please use Coordinates::#func(const #T& f, " \ + "CELL_LOC outloc = CELL_DEFAULT, const std::string& method = \"DEFAULT\") " \ + "instead")]] \ + inline T func(const T& f, CELL_LOC outloc, DIFF_METHOD method) { \ + return func(f, outloc, toString(method)); \ + } +#endif + Field2D DDX(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); - Field2D DDX(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - const std::string& region = "RGN_NOBNDRY") { - return DDX(f, outloc, toString(method), region); - }; + DERIV_FUNC_REGION_ENUM_TO_STRING(DDX, Field2D); Field2D DDY(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); - Field2D DDY(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - const std::string& region = "RGN_NOBNDRY") { - return DDY(f, outloc, toString(method), region); - }; + DERIV_FUNC_REGION_ENUM_TO_STRING(DDY, Field2D); Field2D DDZ(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY"); - Field2D DDZ(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method, - const std::string& region = "RGN_NOBNDRY") { - return DDZ(f, outloc, toString(method), region); - }; + DERIV_FUNC_REGION_ENUM_TO_STRING(DDZ, Field2D); /// Gradient along magnetic field b.Grad(f) Field2D Grad_par(const Field2D& var, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); - Field2D Grad_par(const Field2D& var, CELL_LOC outloc, DIFF_METHOD method) { - return Grad_par(var, outloc, toString(method)); - }; + GRAD_FUNC_REGION_ENUM_TO_STRING(Grad_par, Field2D); Field3D Grad_par(const Field3D& var, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); - Field3D Grad_par(const Field3D& var, CELL_LOC outloc, DIFF_METHOD method) { - return Grad_par(var, outloc, toString(method)); - }; + GRAD_FUNC_REGION_ENUM_TO_STRING(Grad_par, Field3D); /// Advection along magnetic field V*b.Grad(f) Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); - Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, CELL_LOC outloc, + [[gnu::deprecated("Please use Coordinates::Vpar_Grad_par(const Field2D& v, " + "const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, " + "const std::string& method = \"DEFAULT\") instead")]] + inline Field2D Vpar_Grad_par(const Field2D& v, const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { return Vpar_Grad_par(v, f, outloc, toString(method)); - }; + } Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); - Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, CELL_LOC outloc, + [[gnu::deprecated("Please use Coordinates::Vpar_Grad_par(const Field3D& v, " + "const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, " + "const std::string& method = \"DEFAULT\") instead")]] + inline Field3D Vpar_Grad_par(const Field3D& v, const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { return Vpar_Grad_par(v, f, outloc, toString(method)); - }; + } /// Divergence along magnetic field Div(b*f) = B.Grad(f/B) Field2D Div_par(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); - Field2D Div_par(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Div_par(f, outloc, toString(method)); - }; + GRAD_FUNC_REGION_ENUM_TO_STRING(Div_par, Field2D); Field3D Div_par(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); - Field3D Div_par(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Div_par(f, outloc, toString(method)); - }; + GRAD_FUNC_REGION_ENUM_TO_STRING(Div_par, Field3D); // Second derivative along magnetic field Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); - Field2D Grad2_par2(const Field2D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Grad2_par2(f, outloc, toString(method)); - }; + GRAD_FUNC_REGION_ENUM_TO_STRING(Grad2_par2, Field2D); Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT"); - Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD method) { - return Grad2_par2(f, outloc, toString(method)); - }; + GRAD_FUNC_REGION_ENUM_TO_STRING(Grad2_par2, Field3D); + +#undef DERIV_FUNC_REGION_ENUM_TO_STRING +#undef GRAD_FUNC_REGION_ENUM_TO_STRING // Perpendicular Laplacian operator, using only X-Z derivatives // NOTE: This might be better bundled with the Laplacian inversion code diff --git a/include/derivs.hxx b/include/derivs.hxx index da5b411023..576beb96da 100644 --- a/include/derivs.hxx +++ b/include/derivs.hxx @@ -67,9 +67,9 @@ inline T func(const T1& v, const T2& f, CELL_LOC outloc, const std::string& meth REGION region) { \ return func(v, f, outloc, method, toString(region)); \ } \ -[[gnu::deprecated("Please use #func(const #T& f, CELL_LOC outloc = CELL_DEFAULT, " \ - "const std::string& method = \"DEFAULT\", const std::string& region = \"RGN_ALL\") " \ - "instead")]] \ +[[gnu::deprecated("Please use #func(const #T1& v, const #T2& f, " \ + "CELL_LOC outloc = CELL_DEFAULT, const std::string& method = \"DEFAULT\", " \ + "const std::string& region = \"RGN_ALL\") instead")]] \ inline T func(const T1& v, const T2& f, CELL_LOC outloc, DIFF_METHOD method, \ REGION region = RGN_NOBNDRY) { \ return func(v, f, outloc, toString(method), toString(region)); \ From 8eba7f4fc2b1eac5c3c9c9e8fc2133553ed7dda3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 4 Jun 2019 17:35:08 +0100 Subject: [PATCH 1501/1783] Remove unnecessary toString conversions in index_derivs_interface.hxx --- include/bout/index_derivs_interface.hxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 78639e0713..7a2d44289f 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -208,7 +208,7 @@ T DDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "D const T f_aligned = toFieldAligned(f, "RGN_NOX"); T result = standardDerivative(f_aligned, outloc, method, region); - return fromFieldAligned(result, toString(region)); + return fromFieldAligned(result, region); } } @@ -224,7 +224,7 @@ T D2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = const T f_aligned = toFieldAligned(f, "RGN_NOX"); T result = standardDerivative( f_aligned, outloc, method, region); - return fromFieldAligned(result, toString(region)); + return fromFieldAligned(result, region); } } @@ -240,7 +240,7 @@ T D4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = const T f_aligned = toFieldAligned(f, "RGN_NOX"); T result = standardDerivative( f_aligned, outloc, method, region); - return fromFieldAligned(result, toString(region)); + return fromFieldAligned(result, region); } } From 2e7ede664100eab4eea6b054b531f7f0a7988dec Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 5 Jun 2019 15:53:37 +0100 Subject: [PATCH 1502/1783] Pin packages in requirements.txt for Sphinx docs breathe 4.13 is incompatible with the version of Sphinx on Readthedocs --- manual/sphinx/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manual/sphinx/requirements.txt b/manual/sphinx/requirements.txt index 0c64ca8d21..49311794a0 100644 --- a/manual/sphinx/requirements.txt +++ b/manual/sphinx/requirements.txt @@ -1,2 +1,2 @@ -breathe -future +breathe==4.12.0 +future==0.16.0 From ec6a4a6da64e643bd6d12a684137b2d9106a9a2a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 5 Jun 2019 16:27:04 +0100 Subject: [PATCH 1503/1783] Fix typos with 'c' coefficients --- manual/sphinx/user_docs/laplacian.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/manual/sphinx/user_docs/laplacian.rst b/manual/sphinx/user_docs/laplacian.rst index 2a9268a3e4..d51eae8ed5 100644 --- a/manual/sphinx/user_docs/laplacian.rst +++ b/manual/sphinx/user_docs/laplacian.rst @@ -102,10 +102,10 @@ class, first create an instance of it:: By default, this will use the options in a section called “laplace”, but can be given a different section as an argument. By default -:math:`d = 1`, :math:`a = 0`, and :math:`c1=c2=1`. To set the values of +:math:`d = 1`, :math:`a = 0`, and :math:`c_1=c_2=1`. To set the values of these coefficients, there are the ``setCoefA()``, ``setCoefC1()``, -``setCoefC2()``, ``setCoefC()`` (which sets both `c1` and `c2` to its -argument), and ``setCoefD()`` methods:: +``setCoefC2()``, ``setCoefC()`` (which sets both :math:`c_1` and :math:`c_2` +to its argument), and ``setCoefD()`` methods:: Field2D a = ...; lap->setCoefA(a); @@ -372,9 +372,9 @@ of two terms which depends on :math:`z`, as this would give terms like \frac{1}{N}\sum_{Z=0}^{N-1} a(x,y)_Z f(x,y)_Z \exp(\frac{-2\pi i k Z}{N}) -Thus, in order to use a tridiagonal solver, :math:`a`, :math:`c1`, :math:`c2` +Thus, in order to use a tridiagonal solver, :math:`a`, :math:`c_1`, :math:`c_2` and :math:`d` cannot be functions of :math:`z`. Because of this, the -:math:`{{\boldsymbol{e}}}^z \partial_z c` term in equation +:math:`{{\boldsymbol{e}}}^z \partial_z c_2` term in equation :eq:`invert_expanded` is zero. Thus the tridiagonal solvers are solving equations of the form From e5d12cbe652cd0edc3cb269eb4ca5c79a8185fe8 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 5 Jun 2019 17:00:24 +0100 Subject: [PATCH 1504/1783] Fix some grammar and formatting errors in Laplacian docs --- manual/sphinx/user_docs/coordinates.rst | 4 +- manual/sphinx/user_docs/laplacian.rst | 90 +++++++++++++------------ 2 files changed, 50 insertions(+), 44 deletions(-) diff --git a/manual/sphinx/user_docs/coordinates.rst b/manual/sphinx/user_docs/coordinates.rst index 45c0e08393..d2a92b3982 100644 --- a/manual/sphinx/user_docs/coordinates.rst +++ b/manual/sphinx/user_docs/coordinates.rst @@ -1,5 +1,7 @@ .. default-role:: math +.. _sec-field-aligned-coordinates: + ========================= Field-aligned coordinates ========================= @@ -15,8 +17,6 @@ Introduction This manual covers the field-aligned coordinate system used in many BOUT++ tokamak models, and useful derivations and expressions. -.. _sec:coordinates: - Orthogonal toroidal coordinates =============================== diff --git a/manual/sphinx/user_docs/laplacian.rst b/manual/sphinx/user_docs/laplacian.rst index d51eae8ed5..b2945d3e68 100644 --- a/manual/sphinx/user_docs/laplacian.rst +++ b/manual/sphinx/user_docs/laplacian.rst @@ -65,33 +65,34 @@ Usage of the laplacian inversion In BOUT++, equation :eq:`full_laplace_inv` can be solved in two ways. The first method Fourier transforms in the :math:`z`-direction, -whilst the other is solving the full two dimensional problem by matrix +whilst the other solves the full two dimensional problem by matrix inversion. The derivation of :math:`\nabla_\perp^2f` for a general -coordinate system can be found in the ``coordinates`` manual. What is -important, is to note that if :math:`g_{xy}` and :math:`g_{yz}` are -non-zero, BOUT++ is neglecting the :math:`y`-parallel derivatives when -using the solvers `Laplacian` and `LaplaceXZ`. +coordinate system can be found in the +:ref:`sec-field-aligned-coordinates` section. What is important, is to +note that if :math:`g_{xy}` and :math:`g_{yz}` are non-zero, BOUT++ +neglects the :math:`y`-parallel derivatives when using the solvers +`Laplacian` and `LaplaceXZ`. By neglecting the :math:`y`-derivatives (or if :math:`g_{xy}=g_{yz}=0`), one can solve equation :eq:`full_laplace_inv` :math:`y` plane by :math:`y` plane. -The first approach utilizes that it is possible Fourier transform the -equation in :math:`z` (using some assumptions described in section -:ref:`sec-num-laplace`), and solve a tridiagonal system for each -mode. These inversion problems are band-diagonal (tri-diagonal in the -case of 2nd-order differencing) and so inversions can be very +The first approach utilizes the face that it is possible to Fourier +transform the equation in :math:`z` (using some assumptions described +in section :ref:`sec-num-laplace`), and solve a tridiagonal system for +each mode. These inversion problems are band-diagonal (tri-diagonal in +the case of 2nd-order differencing) and so inversions can be very efficient: :math:`O(n_z \log n_z)` for the FFTs, :math:`O(n_x)` for tridiagonal inversion using the Thomas algorithm, where :math:`n_x` and :math:`n_z` are the number of grid-points in the :math:`x` and :math:`z` directions respectively. -In the second approach, the full :math:`2`\ -D system is being solved. -The available solvers for this approach are 'multigrid' using a multigrid +In the second approach, the full :math:`2`\ -D system is solved. The +available solvers for this approach are 'multigrid' using a multigrid algorithm; 'naulin' using an iterative scheme to correct the FFT-based -approach; or 'petsc' using KSP linear solvers from the PETSc library (this -requires PETSc to be built with BOUT++). +approach; or 'petsc' using KSP linear solvers from the PETSc library +(this requires PETSc to be built with BOUT++). The `Laplacian` class is defined in ``invert_laplace.hxx`` and solves @@ -327,11 +328,10 @@ following equation for :math:`f` d\nabla_\perp^2f + \frac{1}{c_1}(\nabla_\perp c_2)\cdot\nabla_\perp f + af = b -BOUT++ is neglecting the :math:`y`-parallel derivatives if -:math:`g_{xy}` and :math:`g_{yz}` are no-zero when using the solvers -`Laplacian` and `LaplaceXZ`. For these two -solvers, equation :eq:`to_invert` becomes (see ``coordinates`` manual -for derivation) +BOUT++ neglects the :math:`y`-parallel derivatives if :math:`g_{xy}` +and :math:`g_{yz}` are no-zero when using the solvers `Laplacian` and +`LaplaceXZ`. For these two solvers, equation :eq:`to_invert` becomes +(see :ref:`sec-field-aligned-coordinates` for derivation) .. math:: :label: invert_expanded @@ -375,7 +375,7 @@ of two terms which depends on :math:`z`, as this would give terms like Thus, in order to use a tridiagonal solver, :math:`a`, :math:`c_1`, :math:`c_2` and :math:`d` cannot be functions of :math:`z`. Because of this, the :math:`{{\boldsymbol{e}}}^z \partial_z c_2` term in equation -:eq:`invert_expanded` is zero. Thus the tridiagonal solvers are solving +:eq:`invert_expanded` is zero. Thus the tridiagonal solvers solve equations of the form .. math:: @@ -491,12 +491,12 @@ The tridiagonal solvers previously required :math:`c_1 = c_2` in equation Using PETSc solvers ~~~~~~~~~~~~~~~~~~~ -When using PETSc, all terms of equation :eq:`invert_expanded` is being -used when inverting to find :math:`f`. Note that when using PETSc, we -are not Fourier decomposing in the :math:`z`-direction, so it may take -substantially longer time to find the solution. As with the tridiagonal -solver, the fields are being sliced in the :math:`y`-direction, and a -solution is being found for one :math:`y` plane at the time. +When using PETSc, all terms of equation :eq:`invert_expanded` are used +when inverting to find :math:`f`. Note that when using PETSc, we do +not Fourier decompose in the :math:`z`-direction, so it may take +substantially longer time to find the solution. As with the +tridiagonal solver, the fields are sliced in the :math:`y`-direction, +and a solution is found for one :math:`y` plane at the time. Before solving, equation :eq:`invert_expanded` is rewritten to the form @@ -566,25 +566,25 @@ Second order approximation (5-point stencil) .. math:: - \texttt{ddx\_c} = \frac{\texttt{c2}_{x+1} - \texttt{c2}_{x-1} }{2\texttt{c1}\text{d}x} + \texttt{ddx_c} = \frac{\texttt{c2}_{x+1} - \texttt{c2}_{x-1} }{2\texttt{c1}\text{d}x} - \texttt{ddz\_c} = \frac{\texttt{c2}_{z+1} - \texttt{c2}_{z-1} }{2\texttt{c1}\text{d}z} + \texttt{ddz_c} = \frac{\texttt{c2}_{z+1} - \texttt{c2}_{z-1} }{2\texttt{c1}\text{d}z} Fourth order approximation (9-point stencil) .. math:: - \texttt{ddx\_c} = \frac{-\texttt{c2}_{x+2} + 8\texttt{c2}_{x+1} - + \texttt{ddx_c} = \frac{-\texttt{c2}_{x+2} + 8\texttt{c2}_{x+1} - 8\texttt{c2}_{x-1} + \texttt{c2}_{x-1} }{ 12\texttt{c1}\text{d}x} \\ - \texttt{ddz\_c} = \frac{-\texttt{c2}_{z+2} + 8\texttt{c2}_{z+1} - + \texttt{ddz_c} = \frac{-\texttt{c2}_{z+2} + 8\texttt{c2}_{z+1} - 8\texttt{c2}_{z-1} + \texttt{c2}_{z-1} }{ 12\texttt{c1}\text{d}z} This gives .. math:: - A_4 = dG^x + g^{xx}\texttt{ddx\_c} + g^{xz}\texttt{ddz\_c} - A_5 = dG^z + g^{xz}\texttt{ddx\_c} + g^{xx}\texttt{ddz\_c} + A_4 &= dG^x + g^{xx}\texttt{ddx_c} + g^{xz}\texttt{ddz_c} \\ + A_5 &= dG^z + g^{xz}\texttt{ddx_c} + g^{xx}\texttt{ddz_c} The coefficients :math:`c_{i+m,j+n}` are finally being set according to the appropriate order of discretisation. The coefficients can be @@ -677,7 +677,7 @@ defined in ``include/invert_laplace.hxx``. This defines a set of functions which all implementations must provide:: class Laplacian { - public: + public: virtual void setCoefA(const Field2D &val) = 0; virtual void setCoefC(const Field2D &val) = 0; virtual void setCoefD(const Field2D &val) = 0; @@ -714,7 +714,7 @@ The code for the `Laplacian` base class is in Laplacian implementations is done in the `LaplaceFactory` class, defined in ``src/invert/laplace/laplacefactory.cxx``. This file includes all the headers for the implementations, and chooses which -one to create based on the “type” setting in the input options. This +one to create based on the ``type`` setting in the input options. This factory therefore provides a single point of access to the underlying Laplacian inversion implementations. @@ -777,6 +777,7 @@ ELM simulations, it has been found that these terms are important, so this method is not usually used. .. _sec-cyclic: + Cyclic algorithm ~~~~~~~~~~~~~~~~ @@ -784,6 +785,7 @@ This is now the default solver in both serial and parallel. It is an FFT-based solver using a cyclic reduction algorithm. .. _sec-multigrid: + Multigrid solver ~~~~~~~~~~~~~~~~ @@ -799,8 +801,8 @@ This scheme was introduced for BOUT++ by Michael Løiten in the `CELMA code `_ and the iterative algoritm is detailed in his thesis [Løiten2017]_. -The iteration can be under-relaxed (see naulin_laplace.cxx for more details of the -implementation). A factor 0`` being the number of the -LaplaceNaulin solver, counting in the order they are created in the physics model: -- ``naulinsolver_mean_underrelax_counts`` gives the mean number of times - ``underrelax_factor`` had to be reduced to get the iteration to converge. If this is - much above 0, it is probably worth reducing ``initial_underrelax_factor``. -- ``naulinsolver_mean_its`` is the mean number of iterations taken to converge. Try to - minimise when adjusting ``initial_underrelax_factor``. +`LaplaceNaulin` solver, counting in the order they are created in the physics model: + +- ``naulinsolver_mean_underrelax_counts`` gives the mean number of + times ``underrelax_factor`` had to be reduced to get the iteration + to converge. If this is much above 0, it is probably worth reducing + ``initial_underrelax_factor``. + +- ``naulinsolver_mean_its`` is the mean number of iterations taken + to converge. Try to minimise when adjusting + ``initial_underrelax_factor``. .. [Løiten2017] Michael Løiten, "Global numerical modeling of magnetized plasma in a linear device", 2017, https://celma-project.github.io/. From 46b0f23d690477a6f182e30413fc31481b173463 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 5 Jun 2019 17:13:40 +0100 Subject: [PATCH 1505/1783] Fix a couple more typos in laplacian.rst --- manual/sphinx/user_docs/laplacian.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manual/sphinx/user_docs/laplacian.rst b/manual/sphinx/user_docs/laplacian.rst index b2945d3e68..7480b3f525 100644 --- a/manual/sphinx/user_docs/laplacian.rst +++ b/manual/sphinx/user_docs/laplacian.rst @@ -77,7 +77,7 @@ By neglecting the :math:`y`-derivatives (or if :math:`g_{xy}=g_{yz}=0`), one can solve equation :eq:`full_laplace_inv` :math:`y` plane by :math:`y` plane. -The first approach utilizes the face that it is possible to Fourier +The first approach utilizes the fact that it is possible to Fourier transform the equation in :math:`z` (using some assumptions described in section :ref:`sec-num-laplace`), and solve a tridiagonal system for each mode. These inversion problems are band-diagonal (tri-diagonal in @@ -329,7 +329,7 @@ following equation for :math:`f` d\nabla_\perp^2f + \frac{1}{c_1}(\nabla_\perp c_2)\cdot\nabla_\perp f + af = b BOUT++ neglects the :math:`y`-parallel derivatives if :math:`g_{xy}` -and :math:`g_{yz}` are no-zero when using the solvers `Laplacian` and +and :math:`g_{yz}` are non-zero when using the solvers `Laplacian` and `LaplaceXZ`. For these two solvers, equation :eq:`to_invert` becomes (see :ref:`sec-field-aligned-coordinates` for derivation) From 7a36917547d27a644791e0c901d7ecb9c6bafd0e Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 11 Jun 2019 17:39:20 +0100 Subject: [PATCH 1506/1783] Started adding SNB heat flux model Based on C.Ridgers' notes, this is a multigroup diffusion model which captures some features of nonlocal heat transport, including preheat and flux limiting. Compiles, but not yet tested. --- include/bout/snb.hxx | 48 ++++++++++++++++++++++++++++++ src/physics/makefile | 2 +- src/physics/snb.cxx | 70 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 include/bout/snb.hxx create mode 100644 src/physics/snb.cxx diff --git a/include/bout/snb.hxx b/include/bout/snb.hxx new file mode 100644 index 0000000000..24e89de1ab --- /dev/null +++ b/include/bout/snb.hxx @@ -0,0 +1,48 @@ +#include "../options.hxx" +#include "../invert_parderiv.hxx" + +class HeatFluxSNB { +public: + HeatFluxSNB(Options *options = nullptr) { + invertpar = InvertPar::Create(); + + if (!options) { + options = &Options::root()["snb"]; + } + + // Read options. Note that the defaults are initialised already + r = (*options)["r"].doc("Scaling of the electron-electron mean free path") + .withDefault(r); + beta_max = (*options)["beta_max"].doc("Maximum energy group to consider (multiple of eT)") + .withDefault(beta_max); + ngroups = (*options)["ngroups"].doc("Number of energy groups").withDefault(ngroups); + + } + ~HeatFluxSNB() { + delete invertpar; + } + + /// Calculate divergence of heat flux + /// Te: Electron temperature in eV + /// Ne: Electron density in m^-3 + Field3D div_heatflux(const Field3D &Te, const Field3D &Ne); + +private: + InvertPar *invertpar; + + BoutReal Z{1}; // Average ion charge (1 = Hydrogen) + BoutReal r{2}; // Electron-electron mean free path scaling factor + BoutReal beta_max{5.0}; // Maximum energy group to consider (multiple of eT) + int ngroups{20}; // Number of energy groups + + /// Indefinite integral of beta^4 * exp(-beta) + /// with constant set to zero + BoutReal int_beta4_exp(BoutReal beta) { + return - exp(- beta) * (24 + beta * (24 + beta * (12 + beta * (4 + beta)))); + } + + /// Integral of beta^4 * exp(-beta) from beta_min to beta_max + BoutReal groupWeight(BoutReal beta_min, BoutReal beta_max) { + return int_beta4_exp(beta_max) - int_beta4_exp(beta_min); + } +}; diff --git a/src/physics/makefile b/src/physics/makefile index 7977db2214..388cda9c8f 100644 --- a/src/physics/makefile +++ b/src/physics/makefile @@ -1,7 +1,7 @@ BOUT_TOP = ../.. -SOURCEC = physicsmodel.cxx smoothing.cxx sourcex.cxx gyro_average.cxx +SOURCEC = physicsmodel.cxx smoothing.cxx sourcex.cxx gyro_average.cxx snb.cxx SOURCEH = $(SOURCEC:%.cxx=%.hxx) TARGET = lib diff --git a/src/physics/snb.cxx b/src/physics/snb.cxx new file mode 100644 index 0000000000..300b5102b0 --- /dev/null +++ b/src/physics/snb.cxx @@ -0,0 +1,70 @@ +/// SNB model +/// + +#include "bout/snb.hxx" +#include "derivs.hxx" +#include "bout/fv_ops.hxx" +#include "bout/constants.hxx" + +Field3D HeatFluxSNB::div_heatflux(const Field3D &Te, const Field3D &Ne) { + Coordinates *coord = Te.getCoordinates(); + + Field3D thermal_speed = sqrt(2.*SI::qe * Te / SI::Me); + + BoutReal Y = SQ(SQ(SI::qe) / (SI::e0 * SI::Me)) / (4 * PI); + Field3D coulomb_log = 6.6 - 0.5 * log(Ne * 1e-20) + 1.5 * log(Te); + + // Thermal electron-electron mean free path [m] + Field3D lambda_ee_T = pow(thermal_speed, 3) / (Y * Ne * coulomb_log); + Field3D lambda_ei_T = lambda_ee_T / SQ(Z); + + + // Thermal electron-ion collision time [s] + Field3D tau_ei_T = thermal_speed / lambda_ei_T; + + // Divergence of Spitzer-Harm heat flux + Field3D Div_Q_SH = FV::Div_par_K_Grad_par((Ne * SI::qe * Te / SI::Me) + * (0.25 * 3 * sqrt(PI) * tau_ei_T) + * 13.58 * (Z + 0.24) / (Z + 4.2), + Te); + + Field3D lambda_ee_Tprime = lambda_ee_T / r; + Field3D lambda_ei_Tprime = lambda_ei_T * ((Z + 0.25) / (Z + 4.2)); + + // Loop over energy groups. + // beta = E / eT is the normalised group energy + + BoutReal beta_last = 0.0; // The last beta value calculated. Ths increases through the loop + BoutReal dbeta = beta_max / ngroups; // Step in beta + + Field3D Div_Q = Div_Q_SH; // Divergence of heat flux. Corrections added for each group + + for (int i = 0; i < ngroups; i++) { + BoutReal beta = beta_last + dbeta; + BoutReal weight = groupWeight(beta_last, beta); + + // Mean free paths for this group + Field3D lambda_g_ee = SQ(beta) * lambda_ee_Tprime; + Field3D lambda_g_ei = SQ(beta) * lambda_ei_Tprime; + + // Update coefficients in solver + invertpar->setCoefA(1./lambda_g_ee); // Constant term + + // The divergence term is implemented as a second derivative and first derivative correction + Field3D coefB = (-1./3) * lambda_g_ei; + invertpar->setCoefB(coefB); // Grad2_par2 + invertpar->setCoefE(DDY(coefB * coord->J / coord->g_22) / coord->J); // DDY + + // Solve to get H_g + Field3D H_g = invertpar->solve((-weight) * Div_Q); + + // Add correction to divergence of heat flux + // Note: The sum of weight over all groups approaches 24 as beta_max -> infinity + Div_Q -= weight * Div_Q_SH - H_g / lambda_g_ee; + + // move to next group, updating lower limit + beta_last = beta; + } + + return Div_Q; +} From 14c77a2c3c84d428beb502fbe940a1df31ec9d2f Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 12 Jun 2019 12:37:10 +0100 Subject: [PATCH 1507/1783] Add example using SNB model A sinusoidal test, varying the electron temperature Fixed several bugs in SNB code. Results seem sensible now, but not properly tested yet. --- examples/conduction-snb/conduction-snb.cxx | 25 +++++++++ examples/conduction-snb/data/BOUT.inp | 22 ++++++++ examples/conduction-snb/makefile | 6 ++ examples/conduction-snb/sinusoid.py | 65 ++++++++++++++++++++++ include/bout/snb.hxx | 24 ++++---- src/physics/snb.cxx | 31 +++++++---- 6 files changed, 151 insertions(+), 22 deletions(-) create mode 100644 examples/conduction-snb/conduction-snb.cxx create mode 100644 examples/conduction-snb/data/BOUT.inp create mode 100644 examples/conduction-snb/makefile create mode 100644 examples/conduction-snb/sinusoid.py diff --git a/examples/conduction-snb/conduction-snb.cxx b/examples/conduction-snb/conduction-snb.cxx new file mode 100644 index 0000000000..ac6c7abe4b --- /dev/null +++ b/examples/conduction-snb/conduction-snb.cxx @@ -0,0 +1,25 @@ +// SNB heat conduction model + +#include +#include + +int main(int argc, char **argv) { + BoutInitialise(argc, argv); + + // Read the density and temperature profiles + Options &opt = Options::root(); + + Field3D Ne = opt["Ne"].doc("Electron density in m^-3").as(); + Field3D Te = opt["Te"].doc("Electron temperature in eV").as(); + + // Calculate divergence of heat flux + HeatFluxSNB snb; + Field3D Div_Q_SH; + Field3D Div_Q = snb.divHeatFlux(Te, Ne, &Div_Q_SH); + + // Save to the output + SAVE_ONCE(Ne, Te, Div_Q, Div_Q_SH); + dump.write(); + + BoutFinalise(); +} diff --git a/examples/conduction-snb/data/BOUT.inp b/examples/conduction-snb/data/BOUT.inp new file mode 100644 index 0000000000..85d218d990 --- /dev/null +++ b/examples/conduction-snb/data/BOUT.inp @@ -0,0 +1,22 @@ + +MXG = 0 + +Ne = 1e14 # Electron density, m^-3 +Te = 1 + 0.01*sin(y) # Electron temperature, eV + +[mesh] +# Size of the domain +nx = 1 +ny = 64 # Along magnetic field +nz = 1 + +length = 1 # in meters +dy = length / ny # Grid spacing + +# Set periodic +ixseps1 = 1000 +ixseps2 = 1000 + +[snb] +ngroups = 20 # Number of energy groups +beta_max = 10 # Maximum energy group to consider (multiple of eT) diff --git a/examples/conduction-snb/makefile b/examples/conduction-snb/makefile new file mode 100644 index 0000000000..83941ca021 --- /dev/null +++ b/examples/conduction-snb/makefile @@ -0,0 +1,6 @@ + +BOUT_TOP = ../.. + +SOURCEC = conduction-snb.cxx + +include $(BOUT_TOP)/make.config diff --git a/examples/conduction-snb/sinusoid.py b/examples/conduction-snb/sinusoid.py new file mode 100644 index 0000000000..d1dfe17b82 --- /dev/null +++ b/examples/conduction-snb/sinusoid.py @@ -0,0 +1,65 @@ +# +# SNB model test +# A small sinusoidal temperature perturbation is added to a periodic 1D domain + +import numpy as np +import matplotlib.pyplot as plt + +from boututils.run_wrapper import shell_safe, launch_safe +from boutdata.collect import collect + +shell_safe("make > make.log") + +# Electron temperature in eV +Telist = 10 ** np.linspace(0,3,10) + +# Electron density in m^-3 +Ne = 1e14 + +# Length of the domain in m +length = 1.0 + +c = 299792458 +mu0 = 4.e-7*np.pi +e0 = 1/(c*c*mu0) +qe = 1.602176634e-19 +me = 9.10938356e-31 + +thermal_speed = np.sqrt(2.*qe * Telist / me) +Y = (qe**2 / (e0 * me))**2 / (4 * np.pi) +coulomb_log = 6.6 - 0.5 * np.log(Ne * 1e-20) + 1.5 * np.log(Telist) +lambda_ee_T = thermal_speed**3 / (Y * Ne * coulomb_log) + +beta_max_list = [5, 10, 20, 40] +colors = ['k','b','g','r'] + +ngroups_list = [20, 40, 80] +syms = ['x', 'o', 'D'] + +for beta_max, color in zip(beta_max_list, colors): + for ngroups, sym in zip(ngroups_list, syms): + + flux_ratio = [] + for Te in Telist: + cmd = "./conduction-snb \"Te={0}+0.01*sin(y)\" Ne={1} mesh:length={2} snb:beta_max={3} snb:ngroups={4}".format(Te, Ne, length, beta_max, ngroups) + + # Run the case + s, out = launch_safe(cmd, nproc=1, mthread=1, pipe=True) + + div_q = collect("Div_Q", path="data").ravel() + div_q_SH = collect("Div_Q_SH", path="data").ravel() + + # Get the index of maximum S-H heat flux + ind = np.argmax(div_q_SH) + + flux_ratio.append(div_q[ind] / div_q_SH[ind]) + + plt.plot(lambda_ee_T / length, flux_ratio, '-'+sym+color, label=r"$\beta_{{max}}={0}, N_g={1}$".format(beta_max,ngroups)) + +plt.legend() +plt.xlabel(r"$\lambda_{ee,T} / L$") +plt.ylabel(r"$q / q_{SH}$") +plt.xscale("log") + +plt.savefig("snb-sinusoidal.png") +plt.show() diff --git a/include/bout/snb.hxx b/include/bout/snb.hxx index 24e89de1ab..2c9fa3bb55 100644 --- a/include/bout/snb.hxx +++ b/include/bout/snb.hxx @@ -1,21 +1,21 @@ #include "../options.hxx" #include "../invert_parderiv.hxx" +/// Calculate heat flux using the SNB model +/// class HeatFluxSNB { public: - HeatFluxSNB(Options *options = nullptr) { + HeatFluxSNB() : HeatFluxSNB(Options::root()["snb"]) {} + + HeatFluxSNB(Options &options) { invertpar = InvertPar::Create(); - if (!options) { - options = &Options::root()["snb"]; - } - // Read options. Note that the defaults are initialised already - r = (*options)["r"].doc("Scaling of the electron-electron mean free path") + r = options["r"].doc("Scaling of the electron-electron mean free path") .withDefault(r); - beta_max = (*options)["beta_max"].doc("Maximum energy group to consider (multiple of eT)") + beta_max = options["beta_max"].doc("Maximum energy group to consider (multiple of eT)") .withDefault(beta_max); - ngroups = (*options)["ngroups"].doc("Number of energy groups").withDefault(ngroups); + ngroups = options["ngroups"].doc("Number of energy groups").withDefault(ngroups); } ~HeatFluxSNB() { @@ -25,7 +25,9 @@ public: /// Calculate divergence of heat flux /// Te: Electron temperature in eV /// Ne: Electron density in m^-3 - Field3D div_heatflux(const Field3D &Te, const Field3D &Ne); + /// + /// Div_Q_SH_out : An optional output field to store the Spitzer-Harm heat flux + Field3D divHeatFlux(const Field3D &Te, const Field3D &Ne, Field3D *Div_Q_SH_out = nullptr); private: InvertPar *invertpar; @@ -41,8 +43,8 @@ private: return - exp(- beta) * (24 + beta * (24 + beta * (12 + beta * (4 + beta)))); } - /// Integral of beta^4 * exp(-beta) from beta_min to beta_max + /// (1/24) * Integral of beta^4 * exp(-beta) from beta_min to beta_max BoutReal groupWeight(BoutReal beta_min, BoutReal beta_max) { - return int_beta4_exp(beta_max) - int_beta4_exp(beta_min); + return (1./24) * (int_beta4_exp(beta_max) - int_beta4_exp(beta_min)); } }; diff --git a/src/physics/snb.cxx b/src/physics/snb.cxx index 300b5102b0..dd9cc73990 100644 --- a/src/physics/snb.cxx +++ b/src/physics/snb.cxx @@ -5,8 +5,9 @@ #include "derivs.hxx" #include "bout/fv_ops.hxx" #include "bout/constants.hxx" +#include "output.hxx" -Field3D HeatFluxSNB::div_heatflux(const Field3D &Te, const Field3D &Ne) { +Field3D HeatFluxSNB::divHeatFlux(const Field3D &Te, const Field3D &Ne, Field3D *Div_Q_SH_out) { Coordinates *coord = Te.getCoordinates(); Field3D thermal_speed = sqrt(2.*SI::qe * Te / SI::Me); @@ -18,15 +19,18 @@ Field3D HeatFluxSNB::div_heatflux(const Field3D &Te, const Field3D &Ne) { Field3D lambda_ee_T = pow(thermal_speed, 3) / (Y * Ne * coulomb_log); Field3D lambda_ei_T = lambda_ee_T / SQ(Z); - // Thermal electron-ion collision time [s] - Field3D tau_ei_T = thermal_speed / lambda_ei_T; + Field3D tau_ei_T = lambda_ei_T / thermal_speed; // Divergence of Spitzer-Harm heat flux - Field3D Div_Q_SH = FV::Div_par_K_Grad_par((Ne * SI::qe * Te / SI::Me) - * (0.25 * 3 * sqrt(PI) * tau_ei_T) - * 13.58 * (Z + 0.24) / (Z + 4.2), - Te); + Field3D Div_Q_SH = -FV::Div_par_K_Grad_par((Ne * SI::qe * Te / SI::Me) + * (0.25 * 3 * sqrt(PI) * tau_ei_T) + * 13.58 * (Z + 0.24) / (Z + 4.2), + Te); + // User can supply an out parameter to get the S-H heat flux divergence + if (Div_Q_SH_out) { + *Div_Q_SH_out = Div_Q_SH; + } Field3D lambda_ee_Tprime = lambda_ee_T / r; Field3D lambda_ei_Tprime = lambda_ei_T * ((Z + 0.25) / (Z + 4.2)); @@ -56,15 +60,20 @@ Field3D HeatFluxSNB::div_heatflux(const Field3D &Te, const Field3D &Ne) { invertpar->setCoefE(DDY(coefB * coord->J / coord->g_22) / coord->J); // DDY // Solve to get H_g - Field3D H_g = invertpar->solve((-weight) * Div_Q); + Field3D H_g = invertpar->solve((-weight) * Div_Q_SH); // Add correction to divergence of heat flux - // Note: The sum of weight over all groups approaches 24 as beta_max -> infinity - Div_Q -= weight * Div_Q_SH - H_g / lambda_g_ee; + // Note: The sum of weight over all groups approaches 1 as beta_max -> infinity + Div_Q -= weight * Div_Q_SH + H_g / lambda_g_ee; + + output.write("%d: %e, %e => %e\n", i, beta, weight, Div_Q(0,4,0)); // move to next group, updating lower limit beta_last = beta; } - + + output.write("%e, %e, %e => %e, %e\n", tau_ei_T(0,4,0), thermal_speed(0,4,0), lambda_ee_T(0,4,0), + Div_Q_SH(0,4,0), Div_Q(0,4,0)); + return Div_Q; } From 83adee574d635e58cc65b0ba759d14a1bdf0fdaf Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 12 Jun 2019 13:16:50 +0100 Subject: [PATCH 1508/1783] Add section to manual on SNB heat flux Doesn't yet describe the interface, just the model implemented. --- manual/sphinx/index.rst | 1 + manual/sphinx/user_docs/nonlocal.rst | 95 ++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 manual/sphinx/user_docs/nonlocal.rst diff --git a/manual/sphinx/index.rst b/manual/sphinx/index.rst index 5261585193..1923087d98 100644 --- a/manual/sphinx/index.rst +++ b/manual/sphinx/index.rst @@ -68,6 +68,7 @@ The documentation is divided into the following sections: user_docs/algebraic_operators user_docs/staggered_grids user_docs/eigenvalue_solver + user_docs/nonlocal .. toctree:: :maxdepth: 1 diff --git a/manual/sphinx/user_docs/nonlocal.rst b/manual/sphinx/user_docs/nonlocal.rst new file mode 100644 index 0000000000..e5f8a173af --- /dev/null +++ b/manual/sphinx/user_docs/nonlocal.rst @@ -0,0 +1,95 @@ +.. default-role:: math + +.. _sec-nonlocal-heatflux: + + +Nonlocal heat flux models +========================= + +Spitzer-Harm heat flux +---------------------- + +The Spitzer-Harm heat flux `q_{SH}` is calculated using + +.. math:: + + q_{SH} = - \frac{n_e e T_e}{m_e}\frac{3\sqrt{\pi}}{4}\tau_{ei,T}\kappa_0\frac{Z+0.24}{Z+4.2} \partial_{||} T_e + +where `n_e` is the electron density in `m^{-3}`, `T_e` is the electron temperature in eV, `kappa_0 = 13.58`, +`Z` is the average ion charge. The resulting expression is in units of `eV/m^2/s`. + +The thermal collision time `tau_{ei,T} = \lambda_{ei,T} / v_{T}` is calculated using the thermal mean free path +and thermal velocity: + +.. math:: + + \lambda_{ee,T} = \frac{v_T^3}{Yn_e \ln\Lambda} + + \lambda_{ei,T} = \frac{v_T^3}{YZ^2n_i \ln\Lambda} + + v_T = \sqrt{\frac{2eT_e}{m_e}} + +where it is assumed that `n_i = n_e`, and the following are used: + +.. math:: + + Y = 4\pi\left(\frac{e^2}{4\pi \epsilon_0 m_e}\right)^2 + + \ln\Lambda = 6.6 - 0.5\log\left(\frac{n_e}{10^{20}}\right) + 1.5 \log\left(T_e\right); + +SNB model +--------- + +The SNB model calculates a correction to the Spitzer-Harm heat flux, solving a +diffusion equation for each of a set of energy groups with normalised +energy `\beta = E_g / eT_e` where `E_g` is the energy of the group. + +.. math:: + + \left[\frac{1}{\lambda'_{g,ee}} - \nabla_{||}\left(\frac{\lambda'_{g,ei}}{3}\partial_{||}\right)\right]H_g = -\nabla_{||} U_g + + +where `\nabla_{||}` is the divergence of a parallel flux, and `\partial_{||}` is a parallel gradient. +`U_g = W_g q_{SH}` is the contribution to the Spitzer-Harm heat flux from a group: + +.. math:: + + W_g = \frac{1}{24}\int_{\beta_{g-1}}^{\beta^{g+1}} \beta^4 e^{-\beta} d\beta + +The modified mean free paths for each group are: + +.. math:: + + \lambda'_{g,ee} = \beta^2 \lambda_{ee,T} / r + + \lambda'_{g,ei} = \beta^2 \lambda_{ei,T} \frac{Z + 0.24}{Z + 4.2} + +From the quantities `H_g` for each group, the SNB heat flux is: + +.. math:: + + q_{SNB} = q_{SH} - \sum_g\frac{\lambda_g,ei}{3}\nabla H_g + +In flud models we actually want the divergence of the heat flux, rather than the heat flux itself. +We therefore rearrange to get: + +.. math:: + + \nabla_{||}\left(\frac{\lambda'_{g,ei}}{3}\partial_{||}\right)H_g = \nabla_{||} U_g + H_g / \lambda'_{g,ee} + +and so calculate the divergence of the heat flux as: + +.. math:: + + \nabla_{||} q_{SNB} = \nabla_{||} q_{SH} - \sum_g\left(\nabla_{||} U_g + H_g / \lambda'_{g,ee}\right) + + +The Helmholtz type equation along the magnetic field is solved using a tridiagonal solver. +The parallel divergence term is currently split into a second derivative term, and a first derivative correction: + +.. math:: + + \nabla_{||}\left(k\partial_{||} T\right) = \frac{1}{J}\frac{\partial}{\partial y}\left(\frac{k J}{g_{22}}\frac{\partial T}{\partial y}\right) + = k\frac{1}{g_22}\frac{\partial^2 T}{\partial y^2} + \frac{1}{J}\frac{\partial}{\partial y}\left(\frac{k J}{g_{22}}\right)\frac{\partial T}{\partial y} + + From f26c62391a0517fd5276eb4c1bdc045a4ed88595 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 6 Jun 2019 16:01:06 +0100 Subject: [PATCH 1509/1783] CMake: Add REQUIRES optional argument to bout_add_integrated_test Allows tests to depend on configure-time features --- CMakeLists.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b7e9ee42b4..8117012b9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -464,10 +464,20 @@ endmacro() # Optional arguments: # - USE_RUNTEST: if given, the test uses `./runtest` as the test # command, otherwise it uses the executable +# - USE_DATA_BOUT_INP: if given, copy `data/BOUT.inp` +# - REQUIRES: list of required dependencies function(bout_add_integrated_test TESTNAME) set(options USE_RUNTEST USE_DATA_BOUT_INP) - set(multiValueArgs SOURCES EXTRA_FILES) + set(multiValueArgs SOURCES EXTRA_FILES REQUIRES) cmake_parse_arguments(BOUT_TEST_OPTIONS "${options}" "" "${multiValueArgs}" ${ARGN}) + + foreach (REQUIREMENT "${BOUT_TEST_OPTIONS_REQUIRES}") + if (REQUIREMENT AND NOT BOUT_HAS_${REQUIREMENT}) + message(STATUS "Not building test ${TESTNAME}, requirement not met: ${REQUIREMENT}") + return() + endif() + endforeach() + add_executable(${TESTNAME} ${BOUT_TEST_OPTIONS_SOURCES}) target_link_libraries(${TESTNAME} bout++) target_include_directories(${TESTNAME} PRIVATE $) From b589515979c32f21b92483abc111a0ea9c5a4aa2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 6 Jun 2019 16:02:05 +0100 Subject: [PATCH 1510/1783] CMake: remove laplace3d files from sources --- CMakeLists.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8117012b9f..bb96036fa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,6 @@ set(BOUT_SOURCES ./include/bout/griddata.hxx ./include/bout/index_derivs.hxx ./include/bout/index_derivs_interface.hxx - ./include/bout/invert/laplace3d.hxx ./include/bout/invert/laplacexy.hxx ./include/bout/invert/laplacexz.hxx ./include/bout/invertable_operator.hxx @@ -167,12 +166,6 @@ set(BOUT_SOURCES ./src/invert/laplace/invert_laplace.cxx ./src/invert/laplace/laplacefactory.cxx ./src/invert/laplace/laplacefactory.hxx - ./src/invert/laplace3d/impls/emptylaplace3d.hxx - ./src/invert/laplace3d/impls/petsc/petsc_laplace3d.cxx - ./src/invert/laplace3d/impls/petsc/petsc_laplace3d.hxx - ./src/invert/laplace3d/laplace3d.cxx - ./src/invert/laplace3d/laplace3d_factory.cxx - ./src/invert/laplace3d/laplace3d_factory.hxx ./src/invert/laplacexy/laplacexy.cxx ./src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.cxx ./src/invert/laplacexz/impls/cyclic/laplacexz-cyclic.hxx From 1784c16141cbf920640ecba7f38961b9f158b8ce Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 6 Jun 2019 16:02:23 +0100 Subject: [PATCH 1511/1783] CMake: add split-rk files to sources --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb96036fa4..790d39c1a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -247,6 +247,8 @@ set(BOUT_SOURCES ./src/solver/impls/slepc/slepc.hxx ./src/solver/impls/snes/snes.cxx ./src/solver/impls/snes/snes.hxx + ./src/solver/impls/split-rk/split-rk.cxx + ./src/solver/impls/split-rk/split-rk.hxx ./src/solver/solver.cxx ./src/solver/solverfactory.cxx ./src/sys/bout_types.cxx From 6e96dbf50c3558d3614fc359dd3d3e6873234932 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 6 Jun 2019 16:03:51 +0100 Subject: [PATCH 1512/1783] CMake: Print a config summary --- CMakeLists.txt | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 790d39c1a0..c10c7f88ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -552,3 +552,29 @@ export(EXPORT bout++Targets ) export(PACKAGE bout) + +################################################## +# Configure summary + +message(" + -------------------------------- + BOUT++ Configuration Summary + -------------------------------- + + PETSc support : ${BOUT_HAS_PETSC} + SUNDIALS support : ${BOUT_HAS_SUNDIALS} + NetCDF support : ${BOUT_HAS_NETCDF} + FFTW support : ${BOUT_HAS_FFTW} + LAPACK support : ${BOUT_HAS_LAPACK} + OpenMP support : ${BOUT_USE_OPENMP} + Natural language support : ${BOUT_HAS_GETTEXT} + + === Python === + + Make sure that the tools/pylib directory is in your PYTHONPATH + e.g. by adding to your ~/.bashrc file + + export PYTHONPATH=$PWD/tools/pylib/:\$PYTHONPATH + +*** Now run `cmake --build .` to compile BOUT++ *** +") From c68eeef3abdb3d4db7c315a94690622adeb628c0 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 6 Jun 2019 16:05:21 +0100 Subject: [PATCH 1513/1783] CMake: Move integrated test cmake file to tests directory Also add cmake files for some other tests --- CMakeLists.txt | 4 +--- tests/integrated/CMakeLists.txt | 8 ++++++++ tests/integrated/test-attribs/CMakeLists.txt | 5 +++++ tests/integrated/test-invertable-operator/CMakeLists.txt | 6 ++++++ tests/integrated/test-io/CMakeLists.txt | 7 +++++++ tests/integrated/test-laplace/CMakeLists.txt | 6 ++++++ tests/integrated/test-stopCheck/CMakeLists.txt | 5 +++++ 7 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 tests/integrated/CMakeLists.txt create mode 100644 tests/integrated/test-attribs/CMakeLists.txt create mode 100644 tests/integrated/test-invertable-operator/CMakeLists.txt create mode 100644 tests/integrated/test-io/CMakeLists.txt create mode 100644 tests/integrated/test-laplace/CMakeLists.txt create mode 100644 tests/integrated/test-stopCheck/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index c10c7f88ac..7cba0bf925 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -498,9 +498,7 @@ option(PACKAGE_TESTS "Build the tests" ON) if(PACKAGE_TESTS) enable_testing() add_subdirectory(tests/unit) - add_subdirectory(tests/integrated/test-solver) - add_subdirectory(tests/integrated/test-initial) - add_subdirectory(tests/integrated/test-griddata) + add_subdirectory(tests/integrated) endif() ################################################## diff --git a/tests/integrated/CMakeLists.txt b/tests/integrated/CMakeLists.txt new file mode 100644 index 0000000000..15ce45cd51 --- /dev/null +++ b/tests/integrated/CMakeLists.txt @@ -0,0 +1,8 @@ +add_subdirectory(test-attribs) +add_subdirectory(test-griddata) +add_subdirectory(test-initial) +add_subdirectory(test-invertable-operator) +add_subdirectory(test-io) +add_subdirectory(test-laplace) +add_subdirectory(test-solver) +add_subdirectory(test-stopCheck) diff --git a/tests/integrated/test-attribs/CMakeLists.txt b/tests/integrated/test-attribs/CMakeLists.txt new file mode 100644 index 0000000000..37f7888d89 --- /dev/null +++ b/tests/integrated/test-attribs/CMakeLists.txt @@ -0,0 +1,5 @@ +bout_add_integrated_test(test-attribs + SOURCES test-attribs.cxx + USE_RUNTEST + USE_DATA_BOUT_INP + ) diff --git a/tests/integrated/test-invertable-operator/CMakeLists.txt b/tests/integrated/test-invertable-operator/CMakeLists.txt new file mode 100644 index 0000000000..6f6ba7b0f2 --- /dev/null +++ b/tests/integrated/test-invertable-operator/CMakeLists.txt @@ -0,0 +1,6 @@ +bout_add_integrated_test(test_invertable_operator + SOURCES invertable_operator.cxx + USE_RUNTEST + USE_DATA_BOUT_INP + REQUIRES PETSC + ) diff --git a/tests/integrated/test-io/CMakeLists.txt b/tests/integrated/test-io/CMakeLists.txt new file mode 100644 index 0000000000..6f4dc5297a --- /dev/null +++ b/tests/integrated/test-io/CMakeLists.txt @@ -0,0 +1,7 @@ +bout_add_integrated_test(test_io + SOURCES test_io.cxx + USE_RUNTEST + USE_DATA_BOUT_INP + EXTRA_FILES test_io.grd.nc data/benchmark.out.0.nc + REQUIRES NETCDF + ) diff --git a/tests/integrated/test-laplace/CMakeLists.txt b/tests/integrated/test-laplace/CMakeLists.txt new file mode 100644 index 0000000000..91640e8159 --- /dev/null +++ b/tests/integrated/test-laplace/CMakeLists.txt @@ -0,0 +1,6 @@ +bout_add_integrated_test(test_laplace + SOURCES test_laplace.cxx + EXTRA_FILES test_laplace.grd.nc data/benchmark.0.nc + USE_RUNTEST + USE_DATA_BOUT_INP + ) diff --git a/tests/integrated/test-stopCheck/CMakeLists.txt b/tests/integrated/test-stopCheck/CMakeLists.txt new file mode 100644 index 0000000000..fc2b1c1f70 --- /dev/null +++ b/tests/integrated/test-stopCheck/CMakeLists.txt @@ -0,0 +1,5 @@ +bout_add_integrated_test(test_stopCheck + SOURCES test_stopCheck.cxx + USE_RUNTEST + USE_DATA_BOUT_INP + ) From 2d7d84eee5e5dff2152e183bd635f08705764fdf Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 12 Jun 2019 13:57:30 +0100 Subject: [PATCH 1514/1783] CMake: Set dep. paths for installed BOUT++ in a slightly nicer way --- bout++Config.cmake.in | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/bout++Config.cmake.in b/bout++Config.cmake.in index 2cd1da691a..82d9bcbf1d 100644 --- a/bout++Config.cmake.in +++ b/bout++Config.cmake.in @@ -19,10 +19,19 @@ set(BOUT_HAS_GETTEXT @BOUT_HAS_GETTEXT@) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") -# This is almost certainly bad practice, but means the user doesn't -# need to find these manually -set(PETSC_DIR @PETSC_DIR@) -set(SUNDIALS_ROOT @SUNDIALS_ROOT@) +if(EXISTS "@PETSC_DIR@") + set(PETSC_DIR "@PETSC_DIR@") +endif() +if(EXISTS "@SUNDIALS_ROOT@") + set(SUNDIALS_ROOT "@SUNDIALS_ROOT@") +endif() +if(EXISTS "@FFTW_ROOT@") + set(FFTW_ROOT "@FFTW_ROOT@") +endif() +if(EXISTS "@LAPACK_ROOT@") + set(LAPACK_ROOT "@LAPACK_ROOT@") +endif() + set(mpark_variant_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../lib/cmake/mpark_variant") set(MPIEXEC_EXECUTABLE @MPIEXEC_EXECUTABLE@) From 053d018a42b1c8cd455bf974128f3e4a87d6bc5c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 12 Jun 2019 13:59:00 +0100 Subject: [PATCH 1515/1783] CMake: Fix bug when iterating over option in add test function --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7cba0bf925..2886f16e72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -487,7 +487,7 @@ function(bout_add_integrated_test TESTNAME) bout_test_copy_file("${TESTNAME}" data/BOUT.inp) endif() if (BOUT_TEST_OPTIONS_EXTRA_FILES) - foreach (FILE "${BOUT_TEST_OPTIONS_EXTRA_FILES}") + foreach (FILE ${BOUT_TEST_OPTIONS_EXTRA_FILES}) bout_test_copy_file("${TESTNAME}" "${FILE}") endforeach() endif() From 47df4a6416999286f3c13c369abf5d7b3661c742 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 12 Jun 2019 13:59:24 +0100 Subject: [PATCH 1516/1783] CMake: Provide hint for MPI location via finding mpiexec --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2886f16e72..a914963f5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,9 @@ project(BOUT++ VERSION 4.2.2 LANGUAGES CXX) +# This might not be entirely sensible, but helps CMake to find the +# correct MPI, workaround for https://gitlab.kitware.com/cmake/cmake/issues/18895 +find_program(MPIEXEC_EXECUTABLE NAMES mpiexec mpirun) find_package(MPI REQUIRED) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) From 57f379d3d2fbb73cb10c5696a23598acde280496 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 12 Jun 2019 13:59:59 +0100 Subject: [PATCH 1517/1783] CMake: Improve FindNetCDF: use nc-config to provide hints --- CMakeLists.txt | 2 +- cmake/FindNetCDF.cmake | 101 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 92 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a914963f5e..e44e25dd30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -386,7 +386,7 @@ find_package(NetCDF) if (NetCDF_FOUND) target_compile_definitions(bout++ PUBLIC "NCDF4") - target_link_libraries(bout++ PUBLIC NetCDF::NetCDF) + target_link_libraries(bout++ PUBLIC NetCDF::NetCDF_CXX) endif() message(STATUS "NetCDF support: ${NetCDF_FOUND}") set(BOUT_HAS_NETCDF ${NetCDF_FOUND}) diff --git a/cmake/FindNetCDF.cmake b/cmake/FindNetCDF.cmake index 98cc3666fb..14737879f5 100644 --- a/cmake/FindNetCDF.cmake +++ b/cmake/FindNetCDF.cmake @@ -1,21 +1,98 @@ +# Taken from https://github.com/conan-io/conan/issues/2125#issuecomment-351176653 +function(add_cloned_imported_target dst src) + add_library(${dst} INTERFACE IMPORTED) + foreach(name INTERFACE_LINK_LIBRARIES INTERFACE_INCLUDE_DIRECTORIES INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS) + get_property(value TARGET ${src} PROPERTY ${name} ) + set_property(TARGET ${dst} PROPERTY ${name} ${value}) + endforeach() +endfunction() + +find_package(netCDFCxx QUIET) +if (netCDFCxx_FOUND) + if(NOT TARGET NetCDF::NetCDF_CXX) + add_cloned_imported_target(NetCDF::NetCDF_CXX netCDF::netcdf-cxx4) + endif() + set(NetCDF_FOUND TRUE) + return() +endif() + +# A function to call nx-config with an argument, and append the resulting path to a list +# Taken from https://github.com/LiamBindle/geos-chem/blob/feature/CMake/CMakeScripts/FindNetCDF.cmake +function(inspect_netcdf_config VAR NX_CONFIG ARG) + execute_process( + COMMAND ${NX_CONFIG} ${ARG} + OUTPUT_VARIABLE NX_CONFIG_OUTPUT + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(EXISTS "${NX_CONFIG_OUTPUT}") + list(APPEND ${VAR} ${NX_CONFIG_OUTPUT}) + set(${VAR} ${${VAR}} PARENT_SCOPE) + endif() +endfunction() + +find_program(NC_CONFIG "nc-config" + DOC "Path to NetCDF C config helper" + ) +get_filename_component(NC_CONFIG_TMP "${NC_CONFIG}" DIRECTORY) +get_filename_component(NC_CONFIG_LOCATION "${NC_CONFIG_TMP}" DIRECTORY) + +find_program(NCXX4_CONFIG "ncxx4-config" + DOC "Path to NetCDF C++ config helper" + ) +get_filename_component(NCXX4_CONFIG_TMP "${NCXX4_CONFIG}" DIRECTORY) +get_filename_component(NCXX4_CONFIG_LOCATION "${NCXX4_CONFIG_TMP}" DIRECTORY) + +set(NC_HINTS "") +inspect_netcdf_config(NC_HINTS "${NC_CONFIG}" "--includedir") +inspect_netcdf_config(NC_HINTS "${NC_CONFIG}" "--prefix") + find_path(NetCDF_INCLUDE_DIR NAMES netcdf.h - DOC "netcdf include directories") + DOC "NetCDF C include directories" + HINTS + "${NC_HINTS}" + "${NC_CONFIG_LOCATION}" + PATH_SUFFIXES + "include" + ) +message(${NetCDF_INCLUDE_DIR}) mark_as_advanced(NetCDF_INCLUDE_DIR) find_library(NetCDF_LIBRARY NAMES netcdf - DOC "netcdf library") + DOC "NetCDF C library" + HINTS + "${NC_HINTS}" + "${NC_CONFIG_LOCATION}" + PATH_SUFFIXES + "lib" "lib64" + ) mark_as_advanced(NetCDF_LIBRARY) +set(NCXX4_HINTS "") +inspect_netcdf_config(NCXX4_HINTS "${NCXX4_CONFIG}" "--includedir") +inspect_netcdf_config(NCXX4_HINTS "${NCXX4_CONFIG}" "--prefix") + find_path(NetCDF_CXX_INCLUDE_DIR NAMES netcdf - DOC "netcdf C++ include directories") + DOC "NetCDF C++ include directories" + HINTS + "${NCXX4_HINTS}" + "${NCXX4_CONFIG_LOCATION}" + PATH_SUFFIXES + "include" + ) mark_as_advanced(NetCDF_CXX_INCLUDE_DIR) find_library(NetCDF_CXX_LIBRARY - NAMES netcdf_c++4 - DOC "netcdf C++ library") + NAMES netcdf_c++4 netcdf-cxx4 + DOC "NetCDF C++ library" + HINTS + "${NCXX4_HINTS}" + "${NCXX4_CONFIG_LOCATION}" + PATH_SUFFIXES + "lib" "lib64" + ) mark_as_advanced(NetCDF_CXX_LIBRARY) if (NetCDF_INCLUDE_DIR) @@ -39,15 +116,19 @@ find_package_handle_standard_args(NetCDF VERSION_VAR NetCDF_VERSION) if (NetCDF_FOUND) - set(NetCDF_INCLUDE_DIRS "${NetCDF_INCLUDE_DIR}") - set(NetCDF_LIBRARIES "${NetCDF_LIBRARY}") + set(NetCDF_INCLUDE_DIRS "${NetCDF_CXX_INCLUDE_DIR}" "${NetCDF_INCLUDE_DIR}") + set(NetCDF_LIBRARIES "${NetCDF_CXX_LIBRARY}" "${NetCDF_LIBRARY}") if (NOT TARGET NetCDF::NetCDF) - add_library(NetCDF::NetCDF UNKNOWN IMPORTED) - set_target_properties(NetCDF::NetCDF PROPERTIES + add_library(NetCDF::NetCDF_C UNKNOWN IMPORTED) + set_target_properties(NetCDF::NetCDF_C PROPERTIES IMPORTED_LOCATION "${NetCDF_LIBRARY}" - IMPORTED_LOCATION "${NetCDF_CXX_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_INCLUDE_DIR}" + ) + add_library(NetCDF::NetCDF_CXX UNKNOWN IMPORTED) + set_target_properties(NetCDF::NetCDF_CXX PROPERTIES + IMPORTED_LINK_INTERFACE_LIBRARIES NetCDF::NetCDF_C + IMPORTED_LOCATION "${NetCDF_CXX_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_CXX_INCLUDE_DIR}") endif () endif () From 3f49d7b03ce1a96f1b709bb64cad41bce9a2f54c Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 12 Jun 2019 16:32:35 +0100 Subject: [PATCH 1518/1783] Add example with temperature step Appears to be very close to published SNB results, but not quantitatively compared yet. Possibly ready to go in as an experimental feature. Manual updated --- examples/conduction-snb/conduction-snb.cxx | 2 + examples/conduction-snb/data/BOUT.inp | 2 +- examples/conduction-snb/sinusoid.py | 17 ++-- examples/conduction-snb/step.py | 63 ++++++++++++ include/bout/snb.hxx | 6 +- manual/sphinx/figs/snb-sinusoidal.png | Bin 0 -> 59450 bytes manual/sphinx/figs/snb-step.png | Bin 0 -> 50363 bytes manual/sphinx/user_docs/nonlocal.rst | 107 ++++++++++++++++++++- src/physics/snb.cxx | 11 +-- 9 files changed, 186 insertions(+), 22 deletions(-) create mode 100644 examples/conduction-snb/step.py create mode 100644 manual/sphinx/figs/snb-sinusoidal.png create mode 100644 manual/sphinx/figs/snb-step.png diff --git a/examples/conduction-snb/conduction-snb.cxx b/examples/conduction-snb/conduction-snb.cxx index ac6c7abe4b..59b222ee2f 100644 --- a/examples/conduction-snb/conduction-snb.cxx +++ b/examples/conduction-snb/conduction-snb.cxx @@ -12,6 +12,8 @@ int main(int argc, char **argv) { Field3D Ne = opt["Ne"].doc("Electron density in m^-3").as(); Field3D Te = opt["Te"].doc("Electron temperature in eV").as(); + mesh->communicate(Ne, Te); + // Calculate divergence of heat flux HeatFluxSNB snb; Field3D Div_Q_SH; diff --git a/examples/conduction-snb/data/BOUT.inp b/examples/conduction-snb/data/BOUT.inp index 85d218d990..85eec72b09 100644 --- a/examples/conduction-snb/data/BOUT.inp +++ b/examples/conduction-snb/data/BOUT.inp @@ -1,7 +1,7 @@ MXG = 0 -Ne = 1e14 # Electron density, m^-3 +Ne = 1e20 # Electron density, m^-3 Te = 1 + 0.01*sin(y) # Electron temperature, eV [mesh] diff --git a/examples/conduction-snb/sinusoid.py b/examples/conduction-snb/sinusoid.py index d1dfe17b82..9d569fd333 100644 --- a/examples/conduction-snb/sinusoid.py +++ b/examples/conduction-snb/sinusoid.py @@ -1,5 +1,5 @@ # -# SNB model test +# SNB model example # A small sinusoidal temperature perturbation is added to a periodic 1D domain import numpy as np @@ -7,14 +7,15 @@ from boututils.run_wrapper import shell_safe, launch_safe from boutdata.collect import collect +from sys import exit shell_safe("make > make.log") # Electron temperature in eV -Telist = 10 ** np.linspace(0,3,10) +Telist = 10 ** np.linspace(0,3,20) # Electron density in m^-3 -Ne = 1e14 +Ne = 1e20 # Length of the domain in m length = 1.0 @@ -28,7 +29,7 @@ thermal_speed = np.sqrt(2.*qe * Telist / me) Y = (qe**2 / (e0 * me))**2 / (4 * np.pi) coulomb_log = 6.6 - 0.5 * np.log(Ne * 1e-20) + 1.5 * np.log(Telist) -lambda_ee_T = thermal_speed**3 / (Y * Ne * coulomb_log) +lambda_ee_T = thermal_speed**4 / (Y * Ne * coulomb_log) beta_max_list = [5, 10, 20, 40] colors = ['k','b','g','r'] @@ -42,16 +43,16 @@ flux_ratio = [] for Te in Telist: cmd = "./conduction-snb \"Te={0}+0.01*sin(y)\" Ne={1} mesh:length={2} snb:beta_max={3} snb:ngroups={4}".format(Te, Ne, length, beta_max, ngroups) - + # Run the case s, out = launch_safe(cmd, nproc=1, mthread=1, pipe=True) - + div_q = collect("Div_Q", path="data").ravel() div_q_SH = collect("Div_Q_SH", path="data").ravel() - + # Get the index of maximum S-H heat flux ind = np.argmax(div_q_SH) - + flux_ratio.append(div_q[ind] / div_q_SH[ind]) plt.plot(lambda_ee_T / length, flux_ratio, '-'+sym+color, label=r"$\beta_{{max}}={0}, N_g={1}$".format(beta_max,ngroups)) diff --git a/examples/conduction-snb/step.py b/examples/conduction-snb/step.py new file mode 100644 index 0000000000..89babda747 --- /dev/null +++ b/examples/conduction-snb/step.py @@ -0,0 +1,63 @@ +# +# SNB model example +# +# Uses a step in the temperature, intended for comparison to VFP results + +length = 6e-4 # Domain length in m + +qe = 1.602176634e-19 + +import numpy as np +import matplotlib.pyplot as plt + +from boututils.run_wrapper import shell_safe, launch_safe +from boutdata.collect import collect + +path = "step" + +shell_safe("make > make.log") +# Run the case +s, out = launch_safe("./conduction-snb -d " + path, nproc=1, mthread=1, pipe=True) + +Te = collect("Te", path=path).ravel() + +ny = len(Te) +dy = length / ny + +position = (np.arange(ny) + 0.5) * length / ny + +# Read divergence of heat flux +div_q = collect("Div_Q", path=path).ravel() +div_q_SH = collect("Div_Q_SH", path=path).ravel() + +# Integrate the divergence of flux to get heat flux W/m^2 +q = np.cumsum(div_q) * qe * dy +q_SH = np.cumsum(div_q_SH) * qe * dy + +# Subtract the minimum value of each heat flux +q -= np.amin(q) +q_SH -= np.amin(q_SH) + +fig, ax1 = plt.subplots() + +color='tab:red' +ax1.plot(position, Te * 1e-3, color=color) +ax1.set_xlabel("position [m]") +ax1.set_ylabel("Electron temperature [keV]", color=color) +ax1.set_ylim(0,1) +ax1.tick_params(axis='y', colors=color) + +ax2 = ax1.twinx() +ax2.plot(position, q_SH * 1e-4, '--k', label="Spitzer-Harm") +ax2.plot(position, q * 1e-4, label="SNB") +ax2.set_ylabel("Heat flux W/cm^2") +ax2.set_ylim(bottom=0.0) + +plt.legend() +fig.tight_layout() + +plt.xlim(0,3.5e-4) + +plt.savefig("snb-step.png") +plt.show() + diff --git a/include/bout/snb.hxx b/include/bout/snb.hxx index 2c9fa3bb55..86b2dc1a7e 100644 --- a/include/bout/snb.hxx +++ b/include/bout/snb.hxx @@ -7,7 +7,7 @@ class HeatFluxSNB { public: HeatFluxSNB() : HeatFluxSNB(Options::root()["snb"]) {} - HeatFluxSNB(Options &options) { + explicit HeatFluxSNB(Options &options) { invertpar = InvertPar::Create(); // Read options. Note that the defaults are initialised already @@ -34,8 +34,8 @@ private: BoutReal Z{1}; // Average ion charge (1 = Hydrogen) BoutReal r{2}; // Electron-electron mean free path scaling factor - BoutReal beta_max{5.0}; // Maximum energy group to consider (multiple of eT) - int ngroups{20}; // Number of energy groups + BoutReal beta_max{10.0}; // Maximum energy group to consider (multiple of eT) + int ngroups{40}; // Number of energy groups /// Indefinite integral of beta^4 * exp(-beta) /// with constant set to zero diff --git a/manual/sphinx/figs/snb-sinusoidal.png b/manual/sphinx/figs/snb-sinusoidal.png new file mode 100644 index 0000000000000000000000000000000000000000..f8376ca542b1fe96d7f01879efdb6b31e30b5e1d GIT binary patch literal 59450 zcmeEubySsY*XPZlQ%bs9Pzk{R3E@bWfTR*4Eg>z9G!h~pAc7!L(n@zoi-4pwqSB$# zIr}{CJKubhYt4W2$2@C2OX9?RpX<8z{?#TzQ(b|Sh=B+}5K<*Yv=)M(0uTgijsOpS zA~rbn1OCBrkyX+mfd7059)`pBgieYEE(mhY4D&x$o^-Aa{P2eBZGBg5M@v@^GiM9L z-ptkMk)!J)n+I&}7S1jWa93O$;W9UzP%M1Bw7tJKj{*(6*DGeD zgZ_TlHMWZg4{xS3j}q>P3LPK766%1j%R1T#*)Ts!j+@7ME(|~V+~tJo!aU0I;dQKs z@Ef`-BCin<%!BFa)e-uCo=?IXfccHNd?=L+<~PEeZU6se{@?y=IzA0x-R#rhKYzNv za8BRA;1(Apy*LwQ@sM$0?dVc<^Aje}Cj(d(7|x zHPJ&WtE}qk@qtXCoGU4+c;4RLirHFnVPCl(W43IeJbxllN=nLeMJ^{NrvM%PpT_4$ z-%(Id6X9;mG(7wKS=Dv<#xrgQ$P{moGo>ez-K#AVJ0~{&49z-Ia@8cvuF`i60?ds}NO z--zz}ias5q3n3vPBR77PmI{eG+P$w>|67@}W1AYD=eDYb^G+*#K`8pF98(y@bLAo< z$M<@5XtbpFE*B!^0RI$vOvVxs6AxKeHA)kAkYvAm7kt^cUXh!dJCrPY=KJ^WU9GK8 z-8W~{#!5_b0|F4+vEsDMw)c0ft*sN!QeUT~tqylQXO|;D)@K@wvV7V?Ngp~omh?N> zmD`T+uS`}68W7T+WI7NHpqZvYOKcgA(R5dW5@9F6Y9y>TV@QUD`Xu}SSo!%|#{ywbp zBPC+1S(OBpfy$ta$e_gHqC7b2fj&})hVNpPOkgX@;(VW`v03B`t=68(-%brC#TE8rM?d#9R7oyM9TL2J`4Sm^ z<~UaQ^XJd`TP0(qN25fl4LJucG1YP58~x`x%H4+sYFwi zOx*QQMBmV`wY3$ctE*dDS=lku;2oEqUM#k;z3mzt7RD(mTK>{MZUt74T}rC4=LtNN zoR&5$f{J&gA}LN-_v6x%H4ZMW*~)M}f|!_?1WEtNDqxZHnp=G1Ph*^#ymVTohQ98x z!L+u%PQl75cuyMP;^uCV>klHab6y)4zNlY{oE+}R-M)>hTYN7fj#J_L_x5L{rKJe6 zHd%EpFfefZg9UMYef?H9?;BItZq?2|i6+WzhWH*cFw0qGkYb5%Bks#zLv)J_v+uYs z4X~qR+S}VlShS~2%m>;`$d#GBPSbbSk9I{E7NlNzT`$QPUH5n~zCv=#IV8XprB1%Z zj3tbNrr5fQWis%@=%b+*Z65)_;6(i1yVU4t(w*g@FdtuEo73Zia))X0!-K^)7X$>J z@$>WB9$&LBgcHN?O3Dk7lasr^!2t)80tz1kgW+bSUHqFj8V|~n)ziee6L4{H2TRS` z7}j1NQZg_oZ@AU3{>>B6D<((aR;aokiookp?$*@SzPNXJOd;9rWooJlvNT?1E}N2@ z%X>+`RK~MNhrhd}CGhRrw=2FZ8(70JRLu&*FA-RJEo0;KQVR=<<)5VGl^&bo+}a^L z8FjxnYOU}Nhe)=Q=$9I)w`GWW;-CIeyM>#>c9%K6ymr+8g&MAA3f*?@4Zf@!OND94 zjjPtmMqc_ubu2OERq++->v@j&`0@G|dEyk&9C3Lp5ynDTJxxucl1kLi+PM;yyL);f zCo1h#E*X{&EMISA{+y0?sEBZKa1h8Oa+T&d`yTF$nRI{p6s)YQoR^muUTHrmpOcfb zJ?$|oHhzP3uLYm=Ic%%Z^^R!9yD`M1q}(a0^1Hjc!)4|Quddn~R_xe*@ZNI}xppo0 z!v~QMA3s75y3V0>mij6=d7vc-pYf+Si^tB&U6hQCjSU*DqpK@V8S$=XaW{(oiuLDY zVYkTNcU~j5R^?Rz>uYPzwzIPnwHqy*F#r7dv#F(J&YnIhKEAA2uY^C# zzu@DSY366zTBezDb;44DrtYnR;++%{Q}`eKZ=w=jqT1VKln9|%pMSD<=X6d(=lFoP z=d>sAyYc1I@f!RShpEAu_09-H@vh7>t({R}4cr~lb!Vh@)-bj@j=-6E-iVRg*b|HH z8rjk;tB_ccVNy6b3(M)a;w(8r;qT9S;PLPrzMamgcT!T4T(;I-#vtYFr?Qy=vY9fs zZUufR3kwOk1s#x!3%zJgXGavCr{3F&i-#whsVQ?gNiI{<6pELAgO}Kh|CuiiK0c?A z5c%!fx5X>CJ`^~s-yMQ%(? zOz#t(JbA(nUEs@?FI`{0$a{KT$2-Ro1@!>n%ZS&^j~@@KYie%sCq6jd|J}O4o1dQ# z%bWN2(%hkOXBHqGnoEW_j*gDoYu~64r_C8jzC`76`$^p_hsjF&$8d?_?OiL)1N7E% z0c4T^y)Q2nI5Rpx`M_hukwqs=ynWfiaOs_!gG*Qi3w~&tJd3LJ34%cnQ~ zrzr`_7HR&c=oJ>~IK|-%Nxsk3cgLP->Fev4?A1zDLKPHmm$v%C^h($q4~p*K@=)#t zaq(9VMGS&w+#UG#HfMQZqfIpW)~WCK`uKFs&b|o`_d8tX{qW(#+pk}>ChDJDsc@LC zWtS_8Yig3dAug_^tNT*Z{b<)7CDU}Wn<_t@t&;R2H`l76zg;q5Lh=fs>8)E>X%ZeW zU(zHL5I%S__=49}LC~b}_3`m>@F6`tJy(3U_43zjz+2pyx}wBIc{m@&>ME7nI4iR{ zHEpMg(l%1Gxi9$!_lAkegC~tF5f<5!_Y2D_8*-oB?ZX#HL{~Xdo$N9WZcL*KbSWBk zXr^6Ci(Dv^1#wSuQ^PGu?KQ|wf(VL+2sLeVu3X_<`5MyIAKUfm$2s-`VwPfcj-W6( zMO5GC;^EcBJ5N*!ic=N2I205Vh)75Z-Cggwc?JvHk!X0M#&b1T4}ZjKi1y6DY8`e; zpWZ^FvlL=;JZ7GRL9NfT8!L7_+_qu3VoBn*G!S^z-s}2MGp&iwEoc>4>5|@Gdj*?R zv$M0&Xi=v*nfZg(YcrlfZ?m!rK4p{`<)YEPN4wcSdy`gm#yUDeF@*<>hE*DVdz<+1 zaJ9td%j+8qY0QgX(y~rZj^a~O8HxT+DD^pSUA0A1Z%i7Iihs ziU&(oQ88~<`dP{qD@uyN&nZ`ImIgBK#w?E%&?;qX!RDoE|MY2i`8DYdo|lhua;^Hw zpX%gHxn-Z;6?~o7jyCebu_yOd9(Z4B2$)8p(57yHsJx>$SiXKq-I8UM z@M_B4f|ImkNyB|>O8r@%mEWHVbJX|~ZKoHPmz7q>N^-sTHtyc&v@2=QU4LBCuxoho z)Upt7#5erC4nP0Ji-mt_n3xKG&zvJ8D|TVzPgGtU@9pjFo|<|c!*t{AotY+of3LHX zy@>Fx?rx=}JE_wCQl#`E!GHe#T|V4d9jmKL;O+fGZ7?lut4gW(8P@>>8Iv zUB*s06-s&~#v`?fNl9Z~lF-r~+S#eVWtCKH?5vIvA^^w;Ek0WIy`{fmsku4RVDqyl z5siMQ$=5YKop$+tEgHQN?AiT-+pB>rQTaA}%51=W4o~)G3+yL{hT>^1-{Y&-p)TE?QdJB7146CT?>LS(Cqrl+;|7FkZmB>}(3;&+cvxRJ~fC0}&_| z&(qSFEv&4x{rsfh*b?n5_P-G%NvL*TXE@m3Cyx^kjEIbU+vt1r0`}Fni3zO-58gVx z4hzGF-#(Yk9I!jSb?a6_a&CfDzu2pNPQ;8fU-L^`{;*h#vdot{8z%`Yrep}LXigjvjE}n$R6RXhnq2Qq)-p3Q#drcSV0`x=>(3u&alhm1YHy^{ z9@*Qwt=ulOS(t25HA(+HQ zgFrc!CMxV0+<>DJ`ORN$H+-l%&zqAH$IcjQZv|!^t z$9Y=Xp#UuG;O;1BY8vsp8V=0``NmCtC+XJR<*#2etqkR!tEs6Oge@oLho=F%tb&Sy zB5*_n&c~~3jxqK1H}#E-7{!@(^IlN0T_zi^B;DW9%S_HlU)Ip$M<~e+%aI2U0))-C zne#R{I62vqdfkdyDJWW8NIvlD8X87o1cbG5ieJBeg_7l}8&)|)UoxsR{r)Ke*k3o` z=BFVcxPUrleE06Vu1}o*`>XGYtG-v}dPDD<*#L~-Hp=!&4Ey*vV4*Yc8Es&*Oom0T zIJZAS&QFAk9PiKyxnG=HC!MO!JaclRprm~J_ppVS_VSM(vGfgf9-Gd8^qz^?jb>Q& zr*Ca-fx6KSbexo#(vE8idmm?CFg#b)fZl0~&H6V-_y;?ab}l`<`akaHUOzh_JHPij z*f|27rXi0;LYK%>#NGIJH>L|JV$d8d(8IP?3QDeO>8u&-i0&aG3mwqqAD?5p!eVLJ zoN$5MVp_IF^$4FH%UYX+X~G99%XpbADZ+&CC_&k@k0C=2f39wm;rcIIpmf8A3i&z@ z{`}}BAR)myi|(W|UwaJF;R0ve+}xkXd43kNVf}=Z0i*5BV{eikter&AReDK%zN8Z3 z<*|v%QowEt#Y#yLdvjTYlKk0-$zs`u$=O&85!DHLMpIP^K5qV0SrdxP|%e zRo|FjeXNzaI;a9YY<2bKs@eCw9Groj`0G7C4_66shOy;z_!BzP>sLNX z(FC&f48vIA`$LHvpu6SL@CJOoe%I29f7T`?l-ADJ&Nc9S{FkI&q)aC3+tj@s9pN(7ZO)~Z2r#I+TFnIh}QORa=(P9^hUvOEv)Mb z_UA;I%nNJl-hGJH|goQOQ`oZf$+fzgp3wx`?E5U#NMQLj`azdyh^G668m<}3gO$? zQ)yF$Z8x8nze1XQ8HL>pr@clP1PB2NTz~Q6#XzPUekMpH=1%VJ9U}#Lj8X{5hiYV? zN#C^^~PhbUt@3p6q>k%gkXST#1`MaeOvnWk+<>maJ7T*sc?sWd<&?VVuYl)DAe$5 z({H>9bQ52NIKBn8z~Nt5L!?DUX!?!&sBsL2Xhx%BVSX!f{(SSIo~cmpL< zPtS$>>IJ$*&y$nGVUH175QU%?I-=Wp5(P4~Mnr|lV8yLS;VwqdT&TBMfd(Ik`$^PO zP|sYJms}2cVw%1a2_r{7=ZmWnWo4V+n*{XlO+W1`XK$Xn+dSaZtPnG29w0(OAcYsr z<+Qu@YE$+aHRwib6BPwLOi%CJx#Rh}oi^^xo02;$^z?*f`cYjS)p~s(n+}5DpM3R! zaH&0`kQpjN6EW|UeUT8wKKt(bzQjuRJBdX;r}h?-Y)aTpR#orkCKe=3J?WmtV#N`z zn3Q(~hbd)zdlold*(a35MHxZPzz})A&b{T+Cp6#L&m@z%@86$-z<_A-`u|&T{GtSo zgQOg|3x!vCc$zn+o4evfFl=+*bwUz9ifS+7?x z@Apf&ecj9J;VS)X6m$1X?2+saU}#Qub}V52Z@A#WEuIINt)~>~vF)l0WmkHz zRzCW{1CHIbZ$X%QPwbJu;ppRY6VPP%^XKI6a&yf=G}_wRb4+lNj)005j^>C44Cvry zYYrG5WZ%1fxz`+~2mp)vh8D!b#+KuvG#h+-`|hs&L^+|ly1LM{Yhg)Av_Kk$mVVPy zff+ND7=r7xL_SbJ`#c^yiVkb4HiRW>R;IgzuzE(9C=8XcxjuopdO0da8@f^&U~L`w z+POk-Cev2nnpYMIN*bTW$5Vx#V~v3=X|}&L@8s; z%h=dnehU6ag;*9K<203Lr+ZD}tSbLWQY$GFyl{b#g@xsiOt0XhRsZ*o{Zc`xsYZ!F zg4X3sP1$7SkBS2$5t(G*!*iTlrjE+|JoPxagIrZ8(xUbM>&xk7@ zeZ%Z3sHLKYQ5_gRVdcFV<6Q2WfZg@L-lRbPW9+WpplCUTa&OJ5e4Wrvo?+wsI5ZkP zobP9CuJ)ko6%&W-ojY;rMu1Lco-C%>Cb1S?Bqkt`@$+j`UmtO!ZyO%g32%Q;T~`N} zMmJgI*cnR7So*M=vf=omYZ(Z}AeY)sJIvG@td{{B3JD6r7I#|-9y9T8=BwZeM`qO$VWabB8d!Vf+X zyuSJ5gSxQDbjq-Ch_LSMFtX-;Y3v}p{4q*!DE8;^!&}?zjB%M=Naa0pJE{E3`B;wioU7Qxg)XT~|j*m6Vj|M6JmY z)7D@@&*ki-mGh3i`$tFS038fhb@pzi!!E}h-LzQuR9|1G__z4ug3_N|9k25cd=Vf27>=TCY>mez3kWSB5Ek5-skAq` z*XUD&xjV3o^nKmdiH`RtV?l63YZ1q$&x*REajeDb7aaFF6?Z?h9>h^?g5jT;7ve|S`r0|=>jG71Yxy1Tor zr)$L~fCA@wuDCE87#M&N-K-&fg5%=ySDd+*fo2wExu&$elFdTL5swvi4%^RE|{!V$Mk)lV{0CzprdKyr-b0MF}hv_7oNs6;*O_@*FgK zcp|o{s%nM~|KR((0*YLez|E|gQb9x%ixmWaWMxZ&$?Z(JB6=H^uj^4k0i=w@JPiAjpTC7J~Tl;s9Kna3;{rXkNeNDg6 zq>06`>E!Cm%l9KU8;{65fXV?)+yeHDt-03$B$XKva-6vdzTN}q1O$YHEh{4h!Xn*d zr2mlx*fND9f6=(UTA695!R@dbP}IF9KW0BazlzbmuCC@F{ByzRekfz+9Z|QSxxiZo z&$I&#{`^Xe7(|)d!1jbJKPTHNERXJq8+*>P*6Nzfz*wi-rShx6Xk-_Hx%EEAN4 zzZWiFjtLJhzF#LVB_#zKj#fS&KY!%m?z)PDg9AqPiHL}3eGEP4$HIafQHX5GZ+u+b zJJ5zLEG;p@sx`P{!?0g^`ud7?#!rs+;&u45LB-Epn{;gAhTRE-zSV7GvMLso=MZsV z>sinwS9Zi%uDLF05)lv#@J&KBfpdT7(W8s^>pkOUeEzC^C@ag9@YonWx;ZgZcYL7s zsVabeC@F#}aD8%Q_H3GX-_u{=r(Lh}+*8~0;=4~g1s1!8qgJzRkCW5HF3DywQ}tbcqxgGZFwAd39|qO0$H+`QVQQle8Zb z)W_0_iV$dB$j+3z|H%$5aAGpp!wnt&tD~1x)5OoiDNnxnM8vT2QG|A`dZydzsBGH! zxPCbLEq^BuFK-qgo#)EgvfrKwHWFlO5r)XJZ}`bT3c=Bq;=@&TDQ9f=$D3~&Yqf%faDrB?e*)I*e=Rp3unhj`UR5M zQM}o7Z5vm|ZGA%Qg(8=1e;)`l|M1(xC9Fc7J9lmo5)zh!52LK8m=PICB#GAl_@6}% zW!Q$TcD%g2^G97>iWtFr;0tiYi14K$4QXzu5gZ&~I?w>>06i6NXJa}Q4iCe3k@6S4 zKSf=a2E16C+}8~aKRhI)py1}>dJYeiFPR^T@wcO!xH-iAY#T)@Gt5 zikYzxZhz@t+q(uC+h1epPWw+7!j2BG{7**0f3IY?EPnCaoAwA9YdSp?02X0~E&nMU zd?6fgecOifwS^yzm*V-q6y@f=ZRZH;!mCng0Rfe)T!~AU)RwTe|Nd=LVD-gN5zZ@D zsKD9hyKtcez*;2il(*)cG5Tc>LT>RWNc-#yNgXa_d9h0S9=dXIaWzj*Gtc_`B?TQd zchIgY{XWNA@h|VYalj0=o~gg_=g%Ko<{RBnBoyRy1U`Qv4l5!EHSYu-(L5NZ$#?2g zk6hg3bNWn?{GplbeRR^}Ype4&t+jIy?>z>-T?T3znzsNTs$CYz5RfijRzLY`nWkXz zAy>u5=7PwTD}!a`ow*JSvGA#z!$C5{7o)Fx`<4T&3QUCox9v8x0b!_sa$(uD{~VmY zp=O~`Av6b@ID_W`>CS2-kqm!(qT&w0tt094e8O0vGe~G!V~~`J=;APVu%3^W)q_5k zm!n->%eM~urO(h#PNi6!4^->^kNOBm5TlxCj-5#ML~0_>pGNbt3dH&e*!1heL)JdW zoK75z+9a>H{TaggQ?PGdz4WrBVRym~)69%Zprq>+-xD@PN0sqX(9nd!xqA2R-CWQ) zsXTWXLhq{>5Fr;4r6WzOUqjGPbO~){Wxv!C5B?_}NK_D|a&ZS@r@` zdJ_KUw1UReDILK6kEW{ccou2p3;7;yikm2(~lr5H}OR@!k$FhWBk^YhUzJ-v+Q^;gkoYJ;%&|FK)qsA&=B#QkOcX61-~oA#6V_WjTX&;H$D#^9=Y-2 z;-dMt4;FY);XtkL0|C`Hx1K(n51(sVTw5tOqg7T5NIw&h)so&JB7AdnumZ5*{_hqw;o4m)qkkjc+Ca>Mj z<;N=)d4|)~&zJ;+Ymaep(s91rsE^)FQ_j$`VewlxB(-M@fJV|0K+e&+y*!lZC2EaP z6euwt-ODd&flBeiv;N1zNb`EUq^Id+*(3>~d-UVy5po|UzPiWEK}jW}*XzrvlZE9@ zJk7K*l1KgFN@GunlcoXVHXkQ^e#Z0zL2 zU0ffZVS%9I2G!S#D}q~L(KzcYd0V+gw0VfC3VwaD!1HVS_M%nnIyyHWJ@~0S*NWQ~ zY{Co;wot!J*7Lr;emK17zt*+_L&iFEZy36->du||ihgtmT*bPAAR7u=POXbikmioI z=I+#{xsmW`goTXYf*^j5hMs?Plui<(DXAAJ9D2Dh1zpK+H7>k>h3%WeAv|V-Nd`vS z|4?l1Bjw{qoo1)+KbiA3avGT-spQ5<%*NfgM%5yT?1h^M~2$Eeuk={QpN0Y%G8Aru+y=7a<-c}uGp59l{r0r9H`182XO2$>wm_adevU!o=l-qWK>kJ{zdtRoQ(zx3kzjV^RmIg!EBO}%m7rMHZ}QY zr8PBz(8UJ81{C$$k^JaPxiDEE?fvPJ3_lsKIRpm<1xd9P#X-|oR3s30UkeAhFB4ir zcvMv3hu|Ne+|T{^0npwBn87^w4bhZu203&c!S}`qfLcw$OyoVmM~!9{C&xm+@dfjc zKl_DNtsxbb>srX-va^H>M?mE^RzxdWRPdM@3r!huSo*3moS^MKbQFe&_6H~#B+uZZ zWkOn-eRaS%mB57yna^kiwUm^)sjALXP_WluLp0Hx4F>pROp4Am_dHJ^_ooHIHRI1I z4GvM!1h4I-TcCusy6sQ%voN-`jd z{%QUN%^RBE7he}<$rr~uwm&CY0 zpIUn?Hj#vcggK0lVD{8ZP5I$Nt{=`d@+tQ&J8q>nKYfaNE$&7n*mV3s)BQ&m#Wn~* zxB3eNd3bnAKYpaDgo?E6vj$?z9Zk)Exj9n|RfgD3Ya{qfhqk^}V{s?sG0tKBTp!Nv$oaw!tDr4_iv#<-2A49I}X z+RfK1iwGgs*OI1|h?W>~?EP&aCn*WsJ#pXn+C!nLD9ES{e6UcNce{6wDTZ0XGTBr= zUi1DRz5LAh=KqZr@B&X_aRKfCS4BmoXc8=x0?A$A6p((D0Sjvj)Uh%B5^-Qzpd59A zU0`N!9}QXuHlnPe@)*2%Pft(L9yb!E>*S#7v~M<@k;$Am{+T^Hr4?*=myS}&)MNui zhf_X^Jci;~I~^E=V4fM|(xq&uk}xCY^1WXvJ&)|69R{3}#_5Q~2d?z3l==LOV4J`N zd|qjT(AFVVGZ`A8lbc)ZTjX=!x!9WS7xjgO+Fn+e(g(*5BV*L>j2g*)D>V4%^t0!@ zqJTnKX)XhW%{GtCN3R{*`m@s`!_}^z&V1BF7fl-LM|UAH1|cBzMZAFjK}*>A`#!N- z!5jp(&L7?J6{GnZPi_hd3V!P7X#Mt$9yT%LE;|8ILa2;PK%l^|KNX}X;N*}XjbfE% z0o0v*{V|7@wl*lGcNTF<8^_AP(}T8`1sWYhN;UZt_u)=4A1XEin+QK!D*_CCTc)x9 z5EVX%3vEj-<5ra$kW`EE{ z{m9i2D=Yzi{ybod4E^4alA*uMrt3H≻v#`fta{WFyFLrhR_{w7M@@I0%Zu5^PIq zW@a^!lqe9?c8=q1J^wFK9wQ)FvOqAAdHvhRurF_ISh=|h}x6tL20Ef&Zj4fPwlSIs^1^dPB|UUbe|{ zVZq!|6YlHLSK=G65O=$)3l5*^kbr<8nW{R(*q9)h2K(Rs!fattp#3Dn3IBTxuypv1 ztStJ>_#N2;E7-ox6Q2n=!_iCEuUD(DE2^or1EHS#^-I@2b*CW)WWMnBSIePjjzHyX6avQx_9Z^lk@LF+I{ZwMUewrl zBzZfA29or(#D8o$?sus=@~G>~R;7ul@b&c8DD6Gu*eMsGw|)Qsd*3FBYBlt;QI zCsRT0TmJL27h~ju!VCRQ4H(alr6s=MH;^uYf=)p(SYbET)!7*qK0K63auZfXM1;S*WF(If2UguazrGQl?!9rtj3K$C@h}qe z63`>4R@SELl0Yxvy9!zn2v>&h_3$Qq~*deUYDn38U#eE@9p;_@=v{*G&Br z;EckW=)y9P3D`I|WbM+z!^8PEseBcclmZ(XBq4bl3QnpyXf~L9zpN|@@&Hcrt+?B( zV;XsHUcSVG`iaPRd5Ocpz{=C3sDa!`46AeubffW!iPrXZTm+0JgJXzSV#uYcn%WM- z87!EP+lmgHV~m_@{p|xcmdf;hjhC1 z@s?a-AiHWTNm`&(-@YJ0j-FiDdvC0yixiQ{#DAA8iK#dO{GPaQajP;a;%J7Fb{$Jv z?;@uSxM$YQgRCQbmo8;Pip_3&7Z4tKT&)L4gklrH&4nA=Vic}wl7XZLj;xSF0K2Z> z@fqBV*q6;8Ke&8Y>FFKV{f|=yx0Q?k+A_QBfo-({LZt6+(y^XDk4b^wx||dg z&R`*HYNu`G7yr-+zwPcbnpHZ!;D)J7`94 z-@U_u&B_lEm2f~I585No<2^aY3aE%xQY4_TI7j1645&_+GMehxcnjhep0zyYW=kYG zZ~o`7x?NEdM3q;dET^QVYQq4DHP~5hhXP3;0(oU?QS7YcZ{Xf*FyzzKO&H4F?F&Z? zCs{?Gyzok=4bgX*Nt&B~B^gK&p_Z$smaR1?efs-c&`tb~^eCyMr<}G^#WZx zR_>}7K;F{^B3-f?iys3(vhlX0Y_2Wl+y?{lMM?_2@4?Tcgp?E|g%~DGipQ|tv+T>_ zk89*Zb^X$Mysoff+1awc&)N$)P72vvGZr<}Z8HvRW5v6mQ1V2eTb1Ut zzwpMrBWo26M9gi$<3ik_7) zDw*B#?>L%uR^REH4+}Z3L&^|h>x9qlSUr3=ceL3wrZ4omOrAFpmH0Qj$N>9TQiBFi zn10iFWI!M{)clMl1?lo2Q!q8b{(^Hq8kDiu*B{H~)*h>Z2P;-+#ep?k88Zi!=e?vQ zM5LfVG-uojGPSjhgyVqG-1TdmEut48X)XuGR7XcL1a5aVWo;zyex# zmw^6nck~eD-4k9I9Q1Wl4fkSxWJst3z%*zS!W}tvaD|2a;!oMx*#RoF0fwDlS&96; z&}lyM{%&|=B<0K8CsUE<1)e7*@je2##H)#>13@+3=OeA z>1x2MBujc%s=I-dIh`>SB-D{y_Rp0Ta_SFF1S2x&5f*bxOFY0Q(a~jiW>)y0U+14T zexMcN!g;?Xlty;$7Tt^jL8XIz^45wScq|pCGmt4VH`3MzV%m{z){jOJAed2sN_$4B zvtyTgwXTFv*c8C&8(0uB?;yc&?mTI)ZR_Jzle1RLj6+IF#2dduLbxPEL!ze<0?( zW(cx076vo{xihjb0SYdhdEt`fXFBtKK8g|7ruY$lX=zrVBnrmHEVE>mqzgZkOy^{p zhpG2x&jM!s@k7s*?39}A(|2y6kPLr+w<~J5|6y)7fKg+b(D9=5+2DB7gLa}q!-^i6 z!LrW8moGU$3ipSKcR($JCdDE%4+L-{l*P5%b(#^m~3izOw3hN^qK)RBO@`yj$rb|b#sO} zjEouTNEAIaMkaEDG=^*b;Snh#`B?{IHaMklxA7%E)+#0LT&==*(wh<%m9IKQ_iD7v zpN~QeF)k^|syTf8BbSsE3$#y+*zk2|NZ59m4_sA7@j^ppZ~!2c6AC6VnuCIj<)*%U zgIem4a!=3l@wODk}Gqv;Jm4uTR+M@EZnVrdT{1?&={ zyJxE=(ezH!t{YSIez7EXVYI6Q1bGrV3h$R_1qDt%J_2wZZUeNPgQ+v1?Q&sv3qU@G zPGdflqXtf0l_M((8=C_1C79$t{1{xcuD-sJWhQhmXeuo;Gc4dOF&qKj2a@p{J(f`b zO1T+0-Phe#s4M7+?bniE`!Ua>a*E@`5Ue1)^j?a0w*~p%03c;y{JhdhlxT zNAUB9Q&Q%cnu{hrlflt!U7bNACvPMP%-G7+*dx%sbTY0#BQpixS~i`XN<^UF_Iy!$ z(fx3Ht_52z%wiiRO_sn*)dAA6c~w>}f`jAzEG>kDXEh<@taOoP2vQiqA29aC)kpem zY2{c*2F$eST-bvlFHFBENmS;(as9fcj!uI5x^azj2r>X#5ddM}rg5eHBO{4FoDbsh zO)!B+oB-(4JP9K^hAkWApw>BexKewEO zh;V?HaVZX4@u*WK-)9`HZETta!oKIp&RED8VC8*C#KXD_(MI4r?+xrsGK>X<@7j<0 zSul}+ML2nQC_H{FT|zNZc6=W}15FpM`q-CWq3Z$pN)^Po!Rt4jtP)_>_ykTEQ`&aAStc$JSP|{&{U4tP830o;S~TH>?kwoo$%P^OK7|pxv4d3;0SB;B|R< zZx;XaXA(Dx30!=9b6`iUs}P$s1+FPCp`oXJ8;6>9)mU1HT$69OJ6#s*q6t}{agm=O z9)7`|v~#Y8Knh7KwL&dGA|g_o~`X;Yk+FOxwe0Bvgv0a5;y1Y~7Z{O*4@nG)bvoM`hM z9Hw+0EUXo!O#hR+=I&Ni*W@%G5xLeI#b}jCApy%aGB-{Lulo!5n9ekv^Es(tM~y{) z{CEYjIsEmP`T1KR8v-jMtr^Ib~<%K6|1!n*zNr69Khj0r_ zC;SEmj9~;#($o-8unvR~IpbB!2M>}@li_Hwcc(%Q3>hd3KCJj2P&Eu^GG5CT{T0$54b$mQ4PeD^IaxoMQc$ounL zl!VUC&Z0do&d#P*R=L`Y5Uf}lQaDjqfZ;a`x&Z-ChaQ1S@e~Ui4`Z6K`t7sB4CM&h zSPkgBK49HpSaqEOUhVRNVG0jqt-L36r0QI^*tWVv312J^VIf}#Z4_CH8|_7|oag%> zjnbc%|H(Q-NZ7oy8qM%H4HQA^DS24*RtWZ!LX~^1ibqW|>Ra%6JzHyMY;LZ$iamar z#R}#PFW;*U07c0z;mP(JiT|1f$j!+istOwV`V|;=C{)Jz5L)AA&}7Q@=$Hv1W zfBjc>l5s0U)}I4cgV-1(3s4B~xKdEgprp!Oq%ntWfA>3RVhYO2k)uUYRRP&r7Y?_V zgP<7@S-`k7M)!jR21HRfIkC^N+$5(2}BA<&%&|g=*S8ICv*d+W*ui^4T*^j<*n6 zkBf~xM?sOV!w)X||8f2SCP$zf-GE^$Caes|cVWJmu6`_+_t9h17!1uUaKAArhK7S* zsTi8?u`!ijaq_drr@waIB{L(kDIPw$tB}u8~DGTa>#&c4uS_n=^+lMBzpoS3=%pt6co%iJ)eWn z79MU5YbNUQOO>5|8D@rH3Ju6BY$O=SiGWa5$=*H{C8ekzK7SSb&~|vT`Y|VF{0Smg zPrSTrRiDVAsi~;sMt1fpvB%fGbD zKk~j#9f4sx!T z1DIpt^OxJ&zAr%1WFk8!$JU1&rvDxbX22ga_>17dI4g|I*-kZq2N>zeCG>yq|EDM4 zyPONOWb|ks1fs7mxK+Xx(-K~#rrK>YT)hi(o1OiTD-tCl#Nt=zmA{?8I2Il*GdXRt z5K}=123EW~a|Sh5kOM016!rPAGo$|4jOvZAW%7U0t{UaDqVAXdk6>skOTb! zY|0u+D5fB`gj^FZWCuV_KuTJ)bpWBGd1%=%bXf*D3|Mx}pC(-wMhuDAiHgr9^l*ag z2+Rp2^q*1|T02A5&ExtK8CH)}{oH9cCR3y&I1k?F5$o72yGAs$wa%1Q$KuwoUlSS~ z<`vYaOPa`50ctYtkif&wuk6VEHZk!$jL~<(n+M#HG=gbGxXO&X1-i*V=fz(;!^S2o z&?~V7iVEWwx+)qP@K98=d>a@t){~W&KqC@%)z{FOu+sDM@4egnLdW}(ag>99QvJ>wvxlAy%06fGL!#u8LaR&j~ZQM&u9n23`rv9o05BR5Ia5{dA_Hy6B7* z@qYZm?0pRq`Mb9_=G|aD$RW~G$5_gxbe@KeP7%BxkZK_T zMtA#(Lp#Taz6e&ry9plY17f15KYKIpOK29D?K^GlDU^8%Cz-6{1uSp8319w36F?~Z zd}hhR+BMy4r(BJjw=G>VbVczS25hskvQDppWOsvzPwB;W!b23FQbn|3k=p6;aXIau zgF`7P8fqL{u}e8$urst(iE`S?Q~8@7Gpzg!`09(Dk`k+7@G(a`sD$pH=j+t`^L({= z?!*JaxtWHEx?miZcX+rT@sKq(#a@C8P9yUECw|S0B41v)`$Ko{!6%3NpSn)tf!m zfY7mKvGxAIt1o5c)*tRb-&gJ$%?f)T@J*-1*FQU}jW&3DfZ|o+eMtcep3bk%6YxTZ z_6Ki3oyY1fcDcufysD8vLi6-i!>8kRB2FxG^;-_B)24pUj@P##$f%Ax=8A=d%A7=7DHaGODRqm$sx()Su%2$tNm13 z+^8$egu@}>3WD)SLnFjf?QG@d;3dSO{&@)@k*DkvI3;tUPGL>BFA8uvKdCafZ>r=7 zU!S3LZ6w<vyOmL8(7`YGVmN#)O#bZ?bO`(lP;ma(F--nV&3Vgy2=bz z0sU_>*7jM2z6?jBcz9OUxwOqOf9U|mV3v$$Yg`m!P|Dd8(0(BPo}8Mxu(Z^b{>qP- zN$LFq%*m*IH|H)Si)c2LNebV8h3#}ykobCMgQWSBwz6~dhTPG8uRUzzx=KUNVseP9 zDPU!bOg8#TT(SJz+~1E$4%as{z%vLCVmGY5FLHs=ol-TX$rideblJNnHzi* zs5syq=z;QWT)ejodM;7OQwVsfm-v7WMWI_x`x_GLZ${i|T0U6xf`D}u(Ca$@<@@{lkc$pldGa^+d3t&b zWTIiv;$qnsa3GS!>}X(*qUGhkLmL9@1Sw?;uXF4;Kp-J8SO($N26NCufJRH-W$jr7 zWak5FJP5!vH+IW?6Suo@G+(Sx!r$d+vY7aiR{K4MN@}h#1yv_Xno?E#I49%=KWS7{ z(4(UuQ{Rw|=nA*Le@quTR?aolD>LAJ?(PQPLCeN{4gRQ*=Q1~)nDS9>P|(Z>(cSN0 zIDj{lFlOwnrdJ783Y1!%3dehdcqDYqZ*M=N6L+c)*5kn|iVG5If?y$3kg|Nk%iu_db^BFQew%E%T)$jFwhL`I@)p=6ef z2xTV8O3ElQN~I`?M3TrRBeJs2G=%z&iuC_hxb%%M>jmMh3oW0ji!$;FO z-g`S;imc&^d2^kz*V*?U%1087FJ6>{p+XR2V&(a_ot?=TloD&=^CWS@pn?5hFkv)! zvKqdG9FxMcUy4$#{ouGh1Sv#nH`Fb!5ImHm^%{uMS3sfAJn{+%gu_tp$seNE{t=Vh zww*iQfliE8wBAWPZCh|oxUfsMp4&v>-(LUFy++OR58TvnNl4XUPjw;uT6P*dP;D(H0<&|a4Vkd)-8tsGmGTf7f+eH z;}5$`JT5o=^6H=sej=nBVK6(7ycgmbgE<=9jeixFs;s1ISDdt4cj8|$Y3cXA$6=Kf zc{evd?*J(eQm6233C}QCF2B@o1y0I06B1HnF9`eyS~&n&R?-)l{EPpNqX#KxZF#q` zIIcL07PYK+Z@bP(Q~!XCL5qRS>uY^YKa5Hm&RHQZk#2_HGA0H<1J{H!~Ys zq(MI4)BDsS#@ALUTbr8b^z`(41Ev)rx^ITCl0+CL!0q0H8Ucdz8*n8bL`)PkH}3$k zU!24pkpZWU5TYx1e9paohUkum#rV>{$MQ0FL}eG;4*{WeJwAR5Mq&RU{0kJ`t^AlP zoy$0HX)yFHO#iSsO?C_y350Van9*1S`nbDKYfU&pv5fPBfZSYNua}mJgGRAKeg+!{ z2X4M_ZixZ6YQZD47-W(7ms$jm=HGKY%&OVUE*UMN#4brOTKqui;*Ek2^9vg*AUf`>kyWOd2cfh%G55<59!%@*GJpHBkj#-&gJhLj{p(+LQ#C??+ z(BU>hpp0l1BF~2quvT4wRjfEb2{|LB?mv|9oA4Ieg9ZJ0Q%`9NS~?Nw8z68al{Z$O zeAa-@JpU5eE6^d=5(E7Gqmd~vYF*gj{2Mm#sJOT|gKyhZBO$7ygM<9YXcNpFdob_| z;#}if{~a4l%Y79?)fRlpPskcnX}PHxckRX7Zg_U>xVH8-h}isN5lIj!e(FtRS63I^ zV)@gL=aiP$4qQD>%Dl2l(v&(GySv-{%TTk|QTFnamgijeQ%3$sZeiB2_Sr)I%0y<{ z;XPMc3d7=0jM;pal1hdv-!W=a)^T#-hh?Il9=~ng_H%iJYeUIkDO;cR)AMH))(+QV zVpu{5%r`zh{wItq_V_w4zkD(2!RQOSKos7L@o~L7(mJl+Ds*VMUxjUEJ%ZUbjJexJ z4Cum-fVVHqK=Wnccam85U&WZb z7V5tFCChQg%khnW1*blk80JAczuR)$D6X!qE{#!|#LK(%>)_THo&JHEJy~{ z=)X}RPn1|I`Y-%K+*%F1Q9m*E;C%$+0*jmFX9UXxE;#i@x z!&spaV|a^-%fV%it42Bed`=N&iCWwS1{Ytm2CbZ+W&Wxj`OUN?YIB7Ux5{z$d#yLf zrK5z~6RmVO^f8_ac~LUUZZ+f9lP6DcU-6ziX8Yo!{@if)Y=Hz0bn(+~|@m_JdU zp6l!D%L>?ybdNji;P5NVo}7tcR*i%d+Y*F>vV-UfOmJsiOQrTHCQfS~Ty*jEsF#55Kp%FP^jdz1h0t!j#`Z zBj-q)ZO7YeC!_m4;$y>Y<&xaEYE%QnIEqp!%XIe)5h^* zz6$zQEPyz*IrF1qVmdhWU~IGa&CbD5$U(LXq9Wu+z=0M63LDuQZ{NQ^4a*})xhtTO zevTuh{UrSd@an>FomX4Urf^-C}U#d(PxD>eHU+nL2J@jyDBzIvqUF2rLU{ z)JTXv`J8RX{*X@VP{n|Yuls`oVw5%*c?)V7D&*I-pDiI?n8Np3RDZJhNsNIVJzK)~NV!-TP;AL@9@@(5xs1pymc8RG)7!>Bh zMrvnwSv|)Nr3hh0xAqy{XOk-u6qSx`m&Yfq^(rcLL zs7`RQlZh#*Q|+kCn#|zQVUhH(|Dd@}0*q&tJD=M<22F#+av>!bWX|w`;Hb|r$cG!` zakg55(B*%S4(o^cpvMF1N=>%L7y%*O@^JdFTo4od4Vt*RE zA$0v2Iq+QcZ}zFex!xI7Q{(N^i$;zIa+u!u|HfC{sU2Ijo5M?L}QK=&&6dl_!V;Fq+H)Bl9ZbNR5fK;AnLFRmO5n>MjwgmwFS?^q z?e*sF&Z2SdrHejkm+}%mx3U$w&M3Om>$Ir;AnDVNPB7J6NtG&euAF>85BL>*$At99 z1A%kPb?fsbr%#_|abD>o%b>-NH%NPV%j&9WoM$XLKlO!ObGu-aU` zuhYMNiI%C8rPJM2?_%-@*)i)y(UWUd)v2@Ete?AbS=@#%9t>V({M^H*Uu?2%`}TX4 zO+NTJ36`g%7caLezNA-#Ag<*p;#y`S5-D~DG&qQJERk!tiSH=>?>k0ktCa^& zb?4S7_V98F1|2Kd*_Bry`{*pUjbhcv$`YFyGvm05+4&=N`!;57-=W-*hxR8B*_r+h zPod%xh?|}cU z?LCb5RoVume_9#rPm*l9DjG~mws@VHkxA)&Y}3mUpULX<+erM`_}f|crzvQ8h_&|b zxG=?0jM=Bzi00EVs#4~2Au%-eE=r6o>y3_F;T-n_Zhdt}Crt=2@%?Yovc+z9k+ zVk#xSrh_-+(F0OPkAB^{i(V^t;p2Fj$AEfTS{fl0{`4sx+G-%L?h-9v>4*DpopIX*x7BAB=&;8>zipLeBYqz(?A?0ZrdJkNg_^MoUer%TJr zTM+JuxfP|ZI723wu5NX9Gx&yAAbG=7U%(I;U2NJrUHg)7y{Kj*gQT`y*rwE;3gUE@ z8+8gOl`u^rS2Nmwe*8DYlCXJO4$fZ3Xl@kpfLGeRcR#ufv$~*~$kmY9QGEl4WGdti6&oJiZ|)m(26k5AfZg$Wp1mLQ2KFdd$l5LS=fT^wN5 zTiZnW=%SZB-6282h{#A^6cXy+XJGvxLvB z4*B%_4HDMb?WCp9QTL8^$M?2%&gJz0HtC|KoMH(y9QMfUdp_49U-g)1IUwf2#7@s< z{^8$9o%C(^?$PeXn+kysY7)zf&|{rNaxyR^n6N02xcY-<^W}mzSR4H?ifR`d#=A@k z5my4L9x%`7<--{{n{ZIDNxQNEMHw6#N)jduyd4xY^MVG=)Ti1@0oSiz*Dve<`knF# zaX?A!rkXbC$4J7eIiFh5_v7dY#rz6g(=aqIgvpd&AOyOp{g!6c3raWd*)!~>H_Uq( zwJk1%_Q1(e#@Dg_VM;c?gcl_1l(cqmTIB}7-V&FZZ)Ij_K}3c@0yRrq_9o10jhHmW zrKF^6Pa8NupYsNcFdBQb)xd1FR5DH;J$pnIl5tQuQRP{6v#*a(C2ZTT0H>#2o zr^3{A3O{$W>p&cYvBkx1r6U+WK0!`^|9a5@Asju={h*mmv;VjZE3KxEPKP3RYoU^D z2}bFNtJcWj-hR@&YuJ5`Y_9?}n`7bW6I={sEAgwr0|zA@bhOuJrK|tNXfmHrgHx>( z7!`%O@srd$E*d{G{+K<=3Y-)%n;Dee{Jtw$Gl<;D!66JmuhTV)yP=&K0`pEnMrR~O zt+rwd8C>>8P+B_`e8mubb-JUVvF_LZ1UyJ1zEZpM3xvB%f7;_~!&;+#=*pc(Gt)n-?;%?Rh3tL^Ze0#(*VgodFd_g>*2Nf!dWCM0qHkoR5#&BW z9c$$#fITg-qHBHl-?RY7cA*UNqX2!@IC?*XIA2_+xklwTC zV+9=|HeWj&vwf^%Pi**}OXkh4I zzW-F^&8E)Y=RK|bs#Rvop$!d5*QKS_ z8=Ta?)c7GK*aoA9zh)okS|}zCcMM-5!D{Ye=jbSiLMga^|NbMuz95n*L3GD;+)b2B zwdcRza8&(O^#8*QQy8ux(na~tw5093%50B7Q{wya4198z!^yYCD+@xB6( zE3CKn(dDJ=-mn#V;&`%lybT_TIbQL~BrYKn4j ztyztK`9nb3de0W#AGiibtT;2-`0^&`Kan0 zT9AnY)*6@ev3f;aIrKq4(j(4;#Wb_;Mt8_MM8J%(eX+E&V5qrnoe3U1P50L>I4q!< z3|UzJ^#6ikY_c)-x zxWoP&4UiV6!gSsoa$=`C6edJOgL4NR_zkrPLlK?Zl6Lds9rT4C?iha|jg5^V3Lxu~ zQ;LlHZsK%pO57LDI1#0_@~dfjTJABOS;Dt=2#}1Z*`OR?{$t=wFxoUo+h-V8clel> z>S?}c2kC&2f-1LvBYzwjz`Y$@& z*Upj)jLp0ZVwY;WrHC%6+R_SuXA@q>6WhCdr_gH*A=;1nI)Ms!{u_|J=&0y93og~3 zqWP`(tyIy8GI}Jlv+$Oic`O%=i_B+Ew#>W_wCNS`N%K#2t!`6OBXQ?6o<4sEVmjvK z4TWL?`Oq;nGdB20Nl&_^eQ&u>=eHo&a@aXnQ7_BfV zlaCLn(&XKLq5c$InyV$3s{7@W0UYI3(tu!Kk$^A=J?Zm@Mey7Zj8#=9Vq%w!=MzjQ z;tlH!-1zfCv;{Rt{F?uX82DbiCVc&RmL6A;nleTGd>}j1bkClOC*G&e56ZHnD21>F zefiF@)UUQQ9n8QS%u--lvKwK&ox;K?t7PCmn&VY86P#H8*P;4cvGzJ|~pTR)&6k zW+=aAp%PumN;;z)-Y;Rd+x*SUOHPKCeJU$lzH#w6g)0qAap_i8hfOmdAK&(lPe0*a z_sgtJS?W3BgWt3hj9RrtFPE2l3#a60%ri=Hm2j?k##D!?r)yllbAZJAF*W4tB`2?A zmF!C|LaSsLa4xa0 zpJ}%Zty$;&%dlPp>Vw{);LhP~Dj-e~ceoRXCGR%*^ z7;0wbEcSUY*0n)V&p*q4|JIkZ@vQVYPQPBt@$Xa-yj30bXV1>eeeBrj+W|4&DM$nz z3gqoxUX`onzs{%Wr4eIJX>h*s5-jdL-@h}k#qcTSy#HWVPnw)lZLh!4d+O<#Q&$}r z)BY}Olc08&w`}|_>Ku3d@ z8++H=w~>%AE0p$vParb1aiSE2Ke+d}>;I$@z%798>48n166Es^;EZrEK0HZzp>jRX5)Q^;vK|VwV~SpWZ*l~ zcbQN;Kt+J?k&8r=3IP8&2J({UvvfG7tK=*yTqDuQJ2D zgC?VKVe)Uz5?c5UX%17)OG$KFq~4+@eT6Fd8sqRQF!2nWE!&{jqf8|0?U$G zAxhfP(^1wQ*18o>9Y7EsdDY2vZN|LeD#_#XizCdDw)OO%o|Y~cG28bXqIhj{^vabh zlzYf2C|*OLK(z<_^?)xnEhdi)0u8m1{-I(Zru`Dsi@0~ya= zg$G@y4)-7C={v6y_AMv@eFvO|uQ677IS`{XLRa!1FBS=*%OPh5o%tyV!p3L}ffEF` zXXoxNifNwA_cz`l!Eu)l|y0YuBKsEqTtEsOIpeyzJw{)%6`Ovv@;5 z?+m+M-V%<#>Axxwh?bw8EtOBPft;e;;-yObS=*dkuK3>L@~;+cn+3Xcmr119=4V|> zq_m0)D=hvnJXXoCZ zw_hByyBhpd`Gv-xMGbnTt=I8ub-Em(fN8YJ?+3792z%%FDt82&3DhMBw_y{Q<`~DmtMlT z`XfWphQ$ZMNa7dza!%9_*F{k??9Ni?Q}tR%^<^Xw<^zc6IN?jTURsf`G z61L_L*x8D{1ks)FyOhKml6z2EzjspzGWMpHQQ%V{RS`BR+QZF#*<;|%Z^Bq4Ca3AI zKICrqbGl^h!ierQ{%#u3P@qUJpVRlGC8S;2=#zET zaP5Y5fO-EDggzu9wqh$Jt%z|f6lPT=e6^rbUxLS;_f~umBjI`Q5q)V<>$7V?RhrlnqBm)TYaRh9Q1vy*T*vv9og^TPO!mHwoqHhB` z13JD604iyFk_mJV=Mq15cCsSZ195Co*RNxe7dWb3u5Gw;?P|e9;k}PphV{^IjG&Vt z9<5W2jJ=S^kYH}k_36*!)9iTvar(En*mO;v_WI0R!{@f!Pel%pp00ghKdJXcK<>Nf zaO+;q^WEy6(d&|k!S9!OPz~w}^8J2TdSA5}C~MMf+GGbzX;491nVAADe{oR}`kp~( zicjH?2Z=`?f*Fq(Bj6uWhpY4uGT;FL+(#xATqs(dEiyj>LxEzTT?RoKw>H{MIGL?1 zpy2q4_vXOXhIZYU7NjY_co&74W^Q%v<3!W{Adi?wTzYAF`GNM2g8vI_5gbpo=YPd4 zYBG(#o8~jCF)9ndor%8vDc)HwH4D5*F5$HwwQ z<~>_)r_jcnJkTOpB1jpz!C_yNP8~G$;8Cex;NJ{I>haLapi#9j`#ye~cpjDCTFNXskK8Y(}l~IlC)lD|WVEF?_s%fEw!iQ~T#jcV#*< zo^P~v^JG_2iz%HhZpw;@VWz4*l_3kEIWglOO{hl|jYcdZ4%LFDVo`jW$bj2^(N7Lal39 zgiRt5H$n@88}z{Q70 zinO%8CYBWCjo&Ysm6adU)KH(`c%*nfk@ZVm%TWs!(Vq8qZ>e~tWd%d5wo9i@_0%yf zPB**=jTIFR{E~9}_G7ySYGAJzSu-9gAZUPzi3xv|23|x4HoFdk%~FRiU749E4vrmM z?R3r-nJUZMfoK-6WXQmBENwh>>Xe6<7gWBGMNCyafu97b0}?2wMlAUOGes~V;1ir6 zX2+i)0uy%0U5v!hOt4>1o?OU%EqZmYVGT4#Fb`kf8Y{@h*9uyRX9%!2sGHFw@KFi3 zZrwNi^2kmNfEY;yOOk+foz}=ca5uxmVcu9s9vA8B6GtXA5_rI+!4*748x8rh9?%aW zXwrAGymJZ2^0l5@>IwIpvrHy-1on;6!oz9maY){!xuaXuC9kf9S8vngO$p8GN(g1s zBlXHT-gRp{%dvxMhs&4p0E*;fkZ_=#MvyR1Y<4rvh>w4P^Y0Y^v_IpJW1*$k#KFl+y6@5UDImt1}JkD;vmYzK&=ax=dwI6^vX;*U_lr>b!y1&3N59+hEcm(ykE@ zR}`A^u_Ubciek0)J&a8PMudST4CpTE^$-sZQH^AP^PlErwtLTvfIZVSdDos zO;f!7nkloHjORP0-8vIxuzQXSLr>Oa=A^(VqhgkA+jxKi%*Pr-H4ahF{aK~uqtrutN0WRtosS#rxB-VnHo_sv>- zg)?5u$!RaNxq-l!R#A??3N$eHgGi5q-u>evvA0ca@`=Ma-;?U>%nrG&FbYCtKm1H= z=I$2BD$)o0cR!})dKD)nA5j7Ug~R^}+VF{_kI1XW|5oSny19O%XD!Xqmimgu3=B+4 zcEf{trS+v#7y>=u=gc)A)^4dq@EMbb@`V6kaRhjHv`OA;{9ZLf47BM`ea)=S&CGD` zI+W$}VAAFXP5tsqigWz0;%5v5N$P0r5cs90m;^NJuPx}Cm)$*xibsOFk~#pvDa^RjJg`;5XhKuV!vVL#s%0K zMjp=Cp(J{-zcM|C#-n(@KDlGvYUG8rmWv zYe2}8J4o{%Lf{~Nj2shP04AM+>Xa`%J-bjbA^0&K4yNVTEKrA&Vd{Haa-PrVf^c_7 z;jr>#<0nT2nWC5nnG_`gd$Zr|l#J1xP$z@09;qS+XKw3d>&IE#C^94Feq-v;?{p8L z<==Jad9vOLz(5e66BJmC*WF8+*}|<_8d9r=-B(PP|y+RIzWqeckXH%xcxH`nyWgLe84+wN@#EjN#sf?FWK&gD~0YTpypMUpf8`wlb z(~gFa@VIAQS}>27KXfdCFX>))2^pAv?0~xo>p#GhMz9)0P!!>u1Nri2yyF_e>M|{b zpI+2Y;A=Q|FtpRUT}f1uq37Wb3rjcKt9~MB-G9V)xSy?*{;iaB*+4D6qaJ_vUX*!h z*DihMbab2BXlNpMhJZgmUzw_wbpA{WI&^Dg!oCM0-_IUNxHo(7El(UMocKj2{_LC_ zUIGCA=NpfTLiSjO4LrZS)Vc}IcUN_?H@nf~=nFk-ZDa^}KKWxn&R$^g!*)p>)<4G$ zu3X}Kb}RXTjg7@d3)aY%ym{&pg(9vJp#0^^tPLV=FQ8rqt<9U>Kc1?(w#qfi3t#)M zo@d)|2*Bq1!ZGvG8}!N1&p)ES!GWMbdl@N)&q@v_^5rj}y#U*%0RcNvQh_fz0ysc5 zLe%d&g3W_CF6E%(4Q|z&KpIPGsD)V4Y(UXYMSPA`OTrR81ET zc;A-vv$WBrV9hlt+yw4aQPIjrrw>nvrkw!KrtF5LHq|l zXse0jTms_4mlc3&DFoQXRyMW=rZQq;arm`~HWyyoo!eiMOqn9W!o<(@93o^OTDd$( zi-xNM^8|P!*wo;|4lgWpiCNd!_n+RhX0OQ`d>zh8N{@U*_n)Mk8<~jicqZH9=A?cz z;>t~qnie8 zR_5(5FyD^=D@VL|jX`(7Ng{0tX%ILV5xa(dAr`_vzEFu{zf9C{W^|fhrWFkOxWwMU!T1np{AymKw1Tc+bilh`K>E(OIRf@u>@MDHr=#^ zT00#b5GYa&*yDgiA*{N*t-IubV2uWnE`W1^o6IDB;L~rJ@rIk;>%~eHkMrm2v4jjn znn3W<*dxfsi<^)KLquKgmezSu-lgXb=^H=E;ND!5z6Rq#Q zX*gq{45yAf28WqT_jdn3tx7-2wWs5n-=^NXt@?z9{ijcGlzkTm>AAlU1!Z4Z%&S)k zcW!Cg4xy#P=C1Xs*ZdCi$UW`{Gzir^z9_DCI${wJ5rEe~qu7KspckiNRBWth0`p+9 zpp_2Ks^_5}uY)v}hR%P!{qvh&!mL0FhLclRWpI6$Yywo8NFp`-^)n^9!e)zuU+n)S zhL;Aj)A38ps?5lVf|d+wt4?{?f-hHB2ZRljL?WqR<~6HL-{|Or3CExn{&^|bR1JDp z%umHpo=4zL;NP)4B+P{2(2-{!x9nsu$#zXThKJk$M zpS>l3TqqIol8Hy(SZig-IAgI3$sySNmIVz4;ax@h3*>8l>Onc=={PE1;#Bg$){`GU zxWFHwb7}fh8@#?O2s^wjFcSjBkB`rm-vJK@v666Cupbo6abUf!EzgY@LLkmFDGJF7 z-mkI0RY0l$6`F$t4f`=?ekP9c5z!jJ@$?^x<9|V%J!$ZyjKY(y$<@rw5feMCAk-1-f4UZ(4vhvt6l_CL+qpbv(ks+7d{q zM_;M7vA%W|ErL)|L6^TOEtV(vEzNM_6|+QQJ+`&mPwcMpi1dq}JJxdii*Vg7?--ei z+7rWkGXSai1z>PX?Wy)DIR^2<{~~e{_0EfmF0?ah=`VLv_!)gX3JHOQ@*FY1WNo=Lpay1l6EzR!5 zdWL@;7gp_HC_EvQ1googFOyk(6~$3f>WLJWJ81d+My@^B>H-VOy|;U?baz*i-SK z{NT|u>SvBtJb#y*n)(jW1%zuEDl(K*!kdp2PC?zYECgbZmj3>gfGDKq0wTw)?d=U8 zt$`v-_P4V1K*UEAlGZfgu83++LM)HSydqvclpYZRzjToUP60db{jWKjUFKF=i8;`w z*7Cj*Vf{l?mR7DkGUwprh#{s*xD%|cGpxy%?q$Y8V; zP|=D(8|#;#p#)6q|NFnn&u+2ZG?EDA4_QVlaTugKJ!d$&HK~gaq{(_p)kMk4oLUo4 zak`E9&kA(P6u(-_(HW!+JRBkK-2MH^g#*E4*G?Z3wUc_w>*@Zp3D1d9_5hSFn1RPC z+KzqH%)4}KMeCX{zi?Rc`iep7`1;Sa&GXkMl6+S&ZzHhEVo^>(VHXBTd@Ix{L|ueK zHTeUjAPMoj)jg%RylX5pqxLyzAcj!qEMe68kz*TxIT;t?F#z!I+h>Y3a;EVHW214> zaz-mr08zjIFJmjIDt;iswgwwKAb-z4qbGu}=>}q5#4lE2yU-5RNWlts#OIcmOJ#9J z?VlR)fG35=0r3u}@yHS?8~W!>^(||C9&~x=R*+a{6=sDg^}v z9&CP*sRthbzkP(&4JyNXIK{B8;4)^U(FOT5_&m|YzG`eFqA+2J#$z)A<L5SPvj% zORlc2ViFR>P(Z3WQIAzGJd>IZgjXOz=*_1s-4$VTBjp@wv25A$pY47s%#wd;TkzkJ zthZ~AORLLy=WS{&j*lNPb)W4s*jm57R;aY!Y>gJ_~zTUJFtQh3-y#%ejOy@5b^!7Q}{QN75UQ7Yog;j5&%9V zq8a=2#8D4hpEzsR7AycRUV#RycR^xV^DE#}HZfb$v)mq%d@$Xi%&4eM0s;brA`+FJ z;6GvbGapm{CxHFyqd)4DQG`K>z+;hptr{VL{)Pr^2K`!F zjs_FrpKpC(_#uk2Q^_+g#kl&~L9@N&lcbAar8@%4Tz57Icu6B9h<;{E{ z3>g8JX&b{Y-l%IHipl(`u$cLP)&1_kyydQ`7Y-5U#p)P##$0ndX-#K258Fsn`qGf$ z-tA@&_Wx<>E^}2|X!ym`8R_NLmURD&j^;a|^==s|x{ONy3{z`gD&E`^rC#`5q0gfH zQcY62zkQpyPyG?O#!#bxf|qpfC5HX=wdr7j-6pO%E(_kO_rS9|7jVi0=|qk}fSH-o z%HFGl@0*x;T6N8dKSBUz$UF;2x%OCH^1w+H5f!BwRhr~gow%yBI_VyK3P>QpC?;4k zb$xoeyH8eXd1G%4G1Zw``yqjfhIkZUW!#D6#%t&f z{=69W!P-KU^k?#0GWJWy<2`N%(q--2AI38|tVhPW8mw;u_}yPQ6K5vG;>F2MH`t}3 zVa|i}(FeLobA$l&x^2sy6@M#atC=t!x!O@5u&A2Nk~OAOLTYvTAu8#8e$Xgja)(~S z-C~veaBt=9-|i)`{P|_>#jR}&{DJyt#k80KoA|f0($N|lEQuR`ZA#V)Uk!?8*3?{z zuh@*djSTCbTR1sm&^todLu`a0=4W(p1o~E7d;qQ$l>O0eJ!Ey@oFbw9IFTH$f33Z_heR@qIo4r4O*nhU0YafM@MSW32MS!ce-fC^|#$J#x%1uiut^f7|fP z@U^euF%FwwcO`y)?@8Z`rhK?uV_m=hzREcI*v+k|zW}IWjg>XC1ueb#nv&55cEu;w6JjNQye(8TMp~LM=|0sEh?KHx;SKP#)E^ zwCGf63B=psTPjXHG9us$EylUy!UgNO@hkJo&?N&L5Yi7)Q3)w61{weffrx{Dokl7> z6h=adBCD=4rgxZ?V`S^B@HJPna0?}9NuiDcDKXYK&VXHJ+Yf^aN{4XbK zKZ<&EkN`nrh6Wi(jn{YL;&FiAmzlD;0|XmsVgI!&fC75!iR&MPwY$R;go@ILvBLb?5R{0*dhzXBb$#Hg=%Qf1TcY3dw!XHK5n+i#${1c4bmLva=4AUcV-vZ8 zua0C!H0};{>D=>?aypbuw14jPIY~E;pDe)~-)~kt&D7)fRpC?`OEJ#c`$Vn3r)!7m zPWdhOJc$fjcms*-L^s=l(4J-cqaS3RR8~5|p+nCpSEkw|S{NM^J1c}uP%&ua?8Vr8 zH`W&YFt_bg4hk$U2|l4*J-b**Pij80PSV_pt&uu+UQT{vW}&LBeREGaSYD;MrRLoU zwej2wX=%z-nGV&Fp5fLdtkyl+(*3_~3oM4@ixjw!_8MnEUWnoljwORI+64ajq;Yi0 z&&=vA>5-EsEtGtZ#bqKcQzUi%NZmcw@wk01&FxIsGqRs`86Wl1f02zY3rgxX+r<5h z_@mFm*mR+fFTaX*^JXF~uh^s+a%q<%GlGhi#dIXp)f))9gU9mXSX&r)0hWnppr7GR zWJ{AzhDa*mcb!b^#L6`HkF1v+y-j?R@7?ZfdiFG&O+##(*n`OSJE}Pj%t*d5iU*wf z6t6qcP{Z~7$w?A^`8M?1G#S+?6L`ugX=vKjrsTObb35~xJ{NC}ii&eL&TeOOxcOx& zZ(3hwb49h#Vnjx`In80N`+@J>z5o28dsxP&*_KoIg)#*5ksW{rLSakzGNA~9c(ei2 zG)+LUJorL=%fVLeYi3unUjYdOe<8YEe6q zIGd?|#OTEyv9bsSdNW|bcRxpy#2`+DtYct{WY(?=#IkNceVsH)th;yXg4t%fGqNWD zkt_Rr3`YaMy?F51Swx|8cZiHg_wRsH#~zc-1vY;?ex;tP!DGWhgc8olg1zNDB(RYJ z{x!Ar=lW3UhS08sDa~Q;_8f5LxeiksmX%8cjHRh5{)|tvYUDNRirC`pifn8$l3+MY z@a%{twIYuWbEs!uJ=uU_DExgCG@}4uF0X>lKb+T|-QgV5iT~&a4z1O>oaxusLc=^p zblC#Qe42hh#DtO_Z(VBRzj^Oga1Xeh3n?GE%c;DRh+v$i!^N~DGU7=D9RC^sas%dE zLPLU>0^$iGJ;w?v#K&(V!M1>~k>d}k8QAp!D&W_c0g9ULA2aySac`5tO401!m1&&> z`fPrS&*FDvSJ&lNXSMx|b#c9#j9tj<|9fd8+&U+VZ^0+Q&Ki!$%_x*}6ORM@V_RlI z>};RN_OFihWSJe^??XGln;3FJgc@H|D0p^%pG2JFCM^SQ5o=0TR{g^MZmCC=G6I}d z(lTSRAn$DI+KZNFJ9>+7za;y>RvZakD@wCvn$UXO0(6jsv_5Cm92!lZ`guAu6q z0abz{8Ef&EKTv!c=^TKxh<0pa%n;?YKL|8j3s|KKf6fry1+?wFCI2vLB0UF{`!HV+|ZK*6= zXqN+X6{)3?kqe0C3lDl~Pb_9VnB9)M?G>r9Mz=zXBNZI}+^cPR1c0%wRPeaMxJvI| z!LI9ha(T{;=G3W9HY=JT)+Q>Z_SYtL%GSxTf%QcLGWQ$?`-Z%fbr>l+8SxEiV;GO_ z5t@HK0xKHx_U*8+@Dg!qI3yv1GieG)ehutv6D@7u+jw3ArUGHv1}Onl2-p3z0_dGZ zxGB*Y)x&}bJMo=+uV20DOIqZzr#kt_mJA9bTcGmL6Wm5h>>~tKA|D{euc_N)9~XDh zNl(wmq$9uyj7^Uw6eK@A#H~WBt<62Vwz9N55TzQj)R27xPR5s6s&1~Kft0^PeW3}ZS|%PT9_0PeFZi=MT(_V;U2U0qn5BGE9_Rk-z!<#Ee% zEc_DJ^b8odG*!_5&IM}+QutTv7*;!4)2e*>zh4c=TfS%(s!QV+J8E6|aJE1+siY^P z?xoR1JzF5)&gJX~R6#1Td5ymmnhbs{+j!Y~untZ_JhkI2epXGDZU%NhX33mBKiH!G z_muuzbX3#}WEw)$0j)@LM!<$Ogzd5r#6_AK;NM+ zChrpcj7?P%?w!O^3=;}bvn+ZFCa!bG|NeP@GFhDS*qx&+(kleQlOm|!y#n@7? z-tj-eT^RQMW&2DRYzohzxdlH2-e;%8XX|A7kri z&(7OYhPQqXXSC&X9&|PCudDZ5xu~?{F5pa&;COJxlvu%6?0EN!dsrUJ_-$9zOhYwr_yfRP|d>XGEj1-T6 z`;l)}DLZ)pDO3%R5935Y+EksV+X!wIeky8WjRXD`qWpqh$LiVVo-T!_wHAnDSNyXx zn*!S{QB&!#g*oWpt{_&`ne5KHBH)hw%g$)WG<-v!^oFnj~BMZz84ZHX=lE32FxH zxAsYqc4Nny4hpO|w?*a#VKXIm3ugj0CliCE94Ia{r(6K+Fq&r~{|!D~Tve^h{)ygB zMzk+L7dN9C6Xr}rRP!lLi$4J3Pd&vIDhE_GBIpw2FZIeBtEcGyV8X|^y$3}?Bd>jD z#5>Gi%}`{vKtv0)lYy|2H#Fq*bZ;V3(@wf|3u0qg_zT;;$rV~u??^BOL=Q}tP=?6+ zsOsK$oO40^c~I`A4Ugr`az%%qe7o}|rhiz+LFe6@n3<_+7EAa1V?f=_8Xj$_;dvza zB(RS>?)l404V!-N`|5F-i2%Vc{cpnVDLB_bl|aD%f{+G4c#qbImYYyW{7wZO7>iT% z!rEW20qPg3w1l-E`P#aG?TEdEwlfI-?L%nuX*?sPiC7ex{|xWI#Fp<4A3%lE={OZa_8wv%I4NW^<}Gb5t~f*sm=Tv)U= z9B6FF>N`3*22&qbY_ml>^*&ub88cuSL^K{hUv0Xz-~1)8=(Fz)ZxNS@8!&^A?#GPQ z2k~2L)>aQ5lG`y+S~0RtR$sIxaMcesvLAXk8|tOBBlT$eYx|E5=STK2CE95dy9bMl z$3ErIAZ370Ts$7Y9~wExqVjOIyjhh?zX1al38g)vx>`OfjmHyL5qZ={aE?POb`Pv6 z2|I1maDz`dI!1&Y-BO*F{PKS@*k?p=hTgW=c)6nm7}t(-jO3cHr&=}6@nqS84U$nHnXhvR2OSfbdz_{+_-H+(K-Fp*CSCp)?~Aw?%s%)V^V78&YPO) z*&d||&Y}!~SJ6(Rmf_unv5RsyRfe&-=#8v5hI2O3o5sd=;5oQH=Cy&c5aT0Y@B%1U zoLhiM*5AU22L+9AnPXAe5pg}|bjh;@@eNtPC82cP{*)NL2X<9kdX0ZZ!tCooYiue! zgj8b^6sv?jWqLM!-pT}&;|QLK0sJE@@uQ(zh$ZtE88iU)Ly9a%iid676|bpmT9|FB z@%i$CTxzC5*Idf=%h>~_5BFMZ9!?Mp{j3l+Pib;`hDM8IW~67_OA-?o|8)AbOE2j> zxSRc!Pvd}8BtW=@y9ehfJ%{vl=q`Z+AT#a0rn|A%W2_h;l4r(8G-B9^{Q>~Cpi{Vs z&h5@0b}gx!TH6=(=<`W_DP?>tYU{sx;XgOFv211X=WGgQTj_Gy(;e0W+sKJeDT6@QFh z@L!{Wf|6zM!oBWr?VO6Svs7?R0cGF~4j&$RYK6T0d)jw(TYh-6p}U!WeE<1xXk)d+ zNh2-$RWh z(BhmsaqT32SL=`IMTnTaOg?*ywB7mti-D#tmzY1gEUZJuBi2 zhn(KE)Nb^ADUQ2+va|!&tHA9v32^w(yL1}gQD$g?_dGk?w?ewOI;OC(niMipczJa> zMYh6RO!kEA-D`|4vX|J|CH0kb^df@S3MGU@fm;N;B}x)x6Ggjzx`@?3w4zG*#=zD* zt!rX7qVnsf?dLPYeDuGm>ZkMgNc*2lhnVlsQ}Wx8m8IX0KP>U@ZhHF35`Jvx6%m-QZ1eYrNm$OXfZaLz1ovqJy<+?LPC z`hqtsMh9yaUR=|B5+YdQko~Q6Yol~}t8X`jSpPlGr4ol^sh+AZP0_w8FBU5g;4dG zr=>-g)Iv|-w&&js>r9hvx+SK6-f%RMmUeT_i9ULg9H(yI!q5fZ7^a~!RxCP(RNE3x z?lGdCvD6Dx_X|>w!erqq?_*L;z`%$!Xn5QZZTc8kWx+!{z58|&JDz@lFV|3zGt8(PE%&PtxYtJ&f5K{;~7exr$`Tj~F`$Y@L|? z6dc?N6Jz7F4#>)ylZecnf%cNYp=1_UVD7w+y3*8cZd)7eZ_g6bI#-V z9Z+5d5E6^3X|!f=>+qAJKfM1@2L#}inm?$~73bsZ!-O6leYC;E{W$~Bb@_mOBR!Ef z`+Yqgct9+sE8J!*0Ay#Yarno@g7 zBjA=mOhAy<#JLQjA~qJ5_QM8fb;9kihVgM1?>Te{(MdqkNsX|9`1wDl{sPh=3<*Bw zvvS;nqZ(QyoIvR|lWR(qPS^UTr{#N)eWB<>6lI@EI2s>+az=;b-SwBb+fGF7>2{f@ zxSe1@jG2Rht0c1HurE=(5NSA{7`C{SouwQ4Fr=nt)&lS)B}O*{-Bcqz1urTd1^nRS zXnAXwy!8@Jj?u=YAK;h|4SM}@^UnZ_06leCmY{|l!fbiq|JaeQ>ee8u=oaj z1#~9>!hoVCHLq~U85DA#VE|)X(g-aDOFO$R7&U_F-LAjokrC)Wpr_EN2nQf1hoIix zKHXTz!bmnT;kf-v&kRj1fl1q!>!*XmC56zVu=WqPr9)0_mUcg8PBh+oz8}h*C=tvr zAi77`H2N@j)FR@(i8#H?m&2zTICMn!)(nk^d@*0=E428%_TSHqOZD)#m=6V2D^vt+hnq&qAlHGo7jvG=npR%xKx=~9=O@@IA4ww$Qm8?1 zc~R?44!}$rq(iq$8l6Pwz?KP}F)-V*B4P*79)mFHCfv&>=`6pxxGLj%5J*1CO5kt5OG<3$@dp zhX%nFLH0znFFb0TFdEu$ev~DnW#vKp?|)yc;%E4$7DI*eA){m#0wsZS76-VzgT9#Yaq8jztxgyEnr3WH z{TwIhs;XulQ70WAQ4vhgED+0nEIlT{#)#qMQFzcIQty=dnlpF1{Oe(j2f&Jj?WX!) zd)nLN?!Hgn1=+jr)OVdDu{-*`A1f+(wDr9HUsSL+u87bg&%{Lh0R=#D!kzM7CDRJ>7N7Ya6)>{hd1=HR|%N#7OHR+Bf|)! zd9BcTVDWmCoSY0gvdrF7INL@68dnv3fz{R32;KtV8VJf5+`Lh+=y;r+_=iC(# zhlsQ?iMqZT0dW=l5L7#n(EN+mls-}ffkxR^KO|HDG1)7bgVgP+FL=k4mY^blMzV%A zq+7{D`TE<}-#;3*8Csd))x8`D^X>xA75oacNMsh!GHelShBS+Fpo=;S%p8E<0>*?N zt``E&eMBOU@ZMmuk#h687cC(+DG3P+_*veA0@>U#BcV=D0G;OrOoL=$8l)qxs!82B zWsZk^%}qe$V@FUK^b8x0=KuqeGtJ128974bjcFAr!F-Lfp!!kM@hM7ZlOw$SdvR}Z zh_^&KN)d|FM}R2#@a087J+C6y!u(t z1qFcy87MD7p$>y`5Uh=+TI3HP=K`dO1+iK&=x>E_7BPv?x5vvpr0ejCpv5O2Y0%)5kee`p`A)!Hb8*!2dZV8r4 z*atqa&L9L@utC^lK&>c$aFH(>>@)~;3Y1_l{rzwUgr*$M#k%NvjG;elcLZ@EP5>w| zgW8Y1yRsD?**|e}V#kaucwkN;kGp**#a=#S$-!- zm{Xy8NX^l)0Cs1dz2BJuJ5M}%L?ILe&QNK)bovHWI2DdnIB+H|8qULeN}Jn!HlHY8 zJwaCrbH!$F8SKCdzub6Kd|TY-vAs9s?W38qTy?Vhe8k6$0WaLf`f9umXXlqV5258N9#HbMMrV`JY2y zTM!E%H!^Qnt0+xZzK8$z%}ZbtgZUQpPr*W3y0QY3n)|;9-!_Kbz;fvCysepbak?Rp zC_It9&M3>MjilcIqv6N<$M)w-w4yaU7EN3otzBDpzA8)?ReVz|bcd}O(w=5!XLYj2 z<8?71ycFE%z0d_HZsfgc{NL57E|yS&2#nQ)rkLv}-ys;ik!#M5Q`29M!Ll0tI@QQ< zr#r*}MH93;)lkOxBa4Alr)ISJW9bi_tM|dkNPChT4q>v0h#t}^Kne(J*2Yg_wV{l^ zRe^Na#@zw2nQ|YU#D^=?#cm&dH z&WJ-u8($U>g&cEMs0PoN>@MHls6|RLkAME*<-0TxWU8iC;b9YMTh2qET86>zwvaVi zfm{B7?Qq;!={E&N;4Gbdx~}`=S^F#_=| z$2Yfr??f=+OV=#TAu9@lT*oN@$NkCU$BP7#DTx>|XNK{VFj6d{{pWMrIN&sx+@h!w z-W_OF_$H-IOn~vqnB>zy%VUqC*F?{;Q}6Ye_lmglebQIZ9Qf>;udarEg%Y~SUC8S30flqW^#ymw&Zar8D`PYjr`dZ z3w`5DQ2ZBh{4JcMYVYC+Ug~bEgfBn;ERlLEHaUu_e$TNrEp~DKD9=Q8HIJdu^xEg+ zYCG;aK_yEe?#zhCpfaE|4TcZmtp2w!v}iEtygP;&d}^0q>oOiW(%Ls0`zqPOa`9^d zhB*-$jem}%Hcz^Iwgb#j$xeDdXK|?cCH?Krt`vJY*o}g;j)c~TrNP%-43%zOMpo&| z7HxKpJu@U$@KR6Jw?&>*D(UCU!pEPx%lO4Gz1FGaMC!?+`U!KeDg6Axn3%`qM>s#9 zSeHuA;y-lbLhVBtI=R!khHV(TRzjhjt}q@ADSTNexJwZP(i1x_+Rnt&cnE_fbbUXxu^tjC5##{PBW&7(U({m~71Lof$M z^gNX|#4^O!1tHT1(uY8{ce#NX039%@Nn0_aqa4*=mi~K(S_+457%;XwWQLl%B}{C$ z_)gS4?!KKhE$*1AT@iUAm$er!{vo5S@HXr9rmz)(wC}5|62@r*w2Wpm{zlr+=9LF2 zDZoUKz$Ii#0l-t9O*1A$9tCoyck_QYY)8{FLSGl-yt+0A1u3Xe;S9 z;cCW0lUR4@_<0JD9E3dQRgpG2lCa4V2qBe-CQo$ACmd8ORbaaXg{fino2>!&onw%d zL%O{k*lnQVi`d;gUUa-8LMH*(L01>w)F@XNn*4oagRfl^^2pg~jEl*BiNg~uXX-|2 zrmjd4Kw>vDBe%8NEOYMmg#py0l9%|>AhN~oX6DDE{lx}Pr3Q;ox&ON%BqU*eb-+MJ zhY+w_I1*xgM<5JOo(QYmE*?UZr=Z5IHS~`DUk8&?{wRRU&I68@V+D=x=JiXtr3pO0 zi^^nujiLJhT}9-O1Y#Gcke}4oKgjlNgX;o#5lv`Ypa4WR4;LWFG6-G{Ls=A`DQ??Y zk?CY3ZDPh@Wn7>I6HAzoe9mBjy!_MSn_OI%{4vT5wWpHHUOx!cvhfpgpPim7}I-PIf@208pVVdeo7Lg0NMhT^j|8B&g&CZ<&lU?z+Pk3sgIfx6Lg6b{*m-z*=STk$ z?nLeF^EwhEtns<<#~|HwDXF#C-Rv!kUtFhat6GKghS#qP#?~my%M? zGUkacDAQkam5CX69E=|I2S*uX#N4VZPD@Nw2ndh_<22_1`1NDnbx1(aH!(4|0y;qo z)eqBDKo?+uIlJU@^|}`5y^)bF{0t((&do)`1zZV8e)){5Fl&uJCrwbU`ocPn1}Dw= zRD@;Hokt%0WY4&^4p&Eo~7pwQSZYMm@l}Fx@nfuUcS5n zG4C+{b0wnzX>tnGc{3zlZ{ORS zc^)RDm{Q&tX`r%%h5K`X1GF#`{XdG5Nz&5v25MHo@T!3L$9m4`qmvTZ6@UK%y5*x_ z3te7T;~K4<ia21fcQoAZ`JR~H0{7(9S@6hMm@-D-pNW32pJ7gm zIl9XB_FG4beXA$YqMkD6Yt^&-C?3{Q{b+D{0)7#3JVEy$0qg`Y41>rqn57Q@K*A;{ zT|)&HGZdT;-T~fFOM?^)280n87};RR4%g{BV1i{w>o?%-0oJXR)%Hwg%m1-F)a&V_ z1z7}u65u@l!T*2inb&9~eRnRx9xD0^u_M;tROC?Rm+Ii@dSeU6e8f$i0C~< zqPsxiP|@Q+&2M}WDs+VPar2}VDHw~`rUPp^J&w%Gd-|Dz1{_+9p*I29BGTx`-7N>9W z4Hk0HynPSNWaiXX0Aay$>UuH(_3WVp8=E{tgN+$}fie?tHvsro2bTi0W!?rHRe?B{ z1c-M4XTL`xkzU63Lfanf0G-|4`Gfrk#FI@-%n+AV5dyX=Amw=ZYDt+bvE?^sC1Ojb zMQmh*3FRuF*l$8(nK!oxMnDk;7Fb+dhpU1k&7(d|lbR0O)$g2AeOLLmQFz03C3cTt`17P0?LY)JPToVQ^xcQ+3@vSR=j!7zw! zi;M8!;=UhuyX61&l_Va{g?3FDpbknpMq3WG5M-@(pT~xN5sb6xvD#bcRZlJ0rF9nR zyC0tQ5IRh-oxNCt*(suYE-KcZgDh)Y(CNb#jC6tlp`mBSQOHp6Fz&o1Ss%3M&_RJX zYnwZFOooQy^Hlo%H|1>es;+*zQ_kb?Nm?-~8Gl^8V?%gyJ9tNI^v~T^#x1uutzvO` z7uBytVB0+eOC|nYg{xrY`!@}?XQFwbGS7;G!P!|E$1#kQb|YU%(hfS0G*Mr^61~@x z$&Q2ix;p+&-OGnIBrY>w$Sr>7gjhy4;=;ji%}n!?+x<{eIphC5v3u1zV<|l5E+=LT z`}LWC57oAI%z_FB6H4mRJppvE3U!`1=TnRCNK^A?s%1SO@LG7px?deT^d zK6&l$pwFHFUq{+?qUQ@KW6bp$YWvls(AHEoG=-*=ZXk!ok&&eXi zyRcS)is=c>%?s$3pXxnKB}j=v4yeyLE91pKpM4`gX}hOeFhWs}mpL5NIZ9h*{>Wb? z8+~iN-hEzm;TjBZ3v>R?L0`CSS=vd@l$vaP7VWFFZfzB^#ytGfadTx&@HPB95rw6SSuLl&V3^;es!C%F)029$gS% zm?V(>eRUkhsQZgLX~CnEA;iHaapDASx9iI;Qwwcsfu8V^N|%x%_w}#30|T&MCq!NR zdtV~__AEOw7xuU^DPFwp?w-zZ8peIu6nD*&=1fi6%caKLd$oR1O^43R2Y!F>SUIP*L?&x_8G?tLhgH ziQS#L<;mzS6C9ziNrXL<#&JGN+$|xZLH=nf|1NIJY(1r<=+s3L!#!F_j69jc&q41curiAGOP5Hm~u9%4EZ+m)iyzh=v)x6?+FtSYOaLfF|p zc)D3-{iv#V<_S5}dBkkt?JM9u^hTPVFz^EEz$hFiKm?Icl=Syml7g?3Z5iS+KGQF= znXjZ6cm2)r-6iK|-j4E&QWK0)2~BCsKFtj6nk^Zamfy$3RtihRb{AR8L`J|u%d3?4 zn(}o2GA`d^-c-p3poM^oMG>UG(2zpLnRpEYSk94P=|+-|UNw#I#DZZLUW zuT{sZ>`P(Q&y0Fl?h0bNjkR2~-$gQ0Nt00ot(8d6OHLCth*ONfAq&k{mS zVJm$KMy+Z%gM&;*6`+8^nnvTi3+#D1FjAum0RvUpN|98%umVC6{9$EZWrXT5XzMsePE0BD%4G$T#8DJk7os! zJ_l%y`}DP@Hg8T9$8Fy9y`iQ?3Vb;RanJWYg52Dy;EmQtih7`_Z4chod;$|R0%(8$ z$j~uiV||?;eA`bmSNHsW&d*;2iJw8q4w&*Tp(+E8Jdu1kL|N?wJzX{tk(vOy9THGt z&wdu27HL?7uy*BV3{EG_c`p2aS8*!&zv9TIhY#C9b+9_9dw6JLwn48EThQ?|$Z5l*%>R_OcY6hX3?o#!?&1|o4{v13&;wH(-Z4%z-7b9V_ z2-LlDg^HX!9G*icqTc=Z@f;e_C}1`B9v|Yo{+AX2rad2VM z;2|~es^1v~G|&Z38!VrW^K(iLL?y=v%f31fEB6*w7V@kLSA@j4TG8RYX z6dWQHRn^fCW~yRtg>KqtgESQcg{OKn;RNNfkMu#Rm;=dUrBsb)Bi zzT1}9ufh2LR{CQiO4t9hJlQ!DUbe$4q7knc?944cJ{Jn~3oVH;8}qbvC5hn@e6#q* zB9giC`F+6_m{<{P9i3qgh?-lUVqOg%4IhM3_ZGt*kVInOH*{Wgqf zLd+z%D@{tRr-Oxk&xLjN;^z^TVmjAmI5X=_IJoV21fs9u&E;X zqtNo3huj*W=hcA41JyH-!@40z8L0oL#s{0Oe0Ko&gfK#|Rqx* z2aGuoi6-}4z$^+ZW1zo;bKAd+Jk`K`gOfYO>MHbsmV7n~=z%^80R}K{wFt#x0j)NG z-~i0p3pp&%)3IoPtMgxJoFzj%p%?VGUpK_$8{RhIF>-!_li{oE3*YSI&?Y;!(N$Vj zC-AD~MLVzE&#i;?ZXde79-wGy7x5W4M-m2R2=5u~x7QmKCVjKFun_a9kfhiDJTk&9 zBph^f7dzSxs5-FNQfM3$JokG6mkK|ED4&> zi<(e_(1?3p1nUI|@c#|agmZyGNE#&lp#MR^mg&DVya>j2&|1rUknNwCcm-yqD%j!@ z+qa-m-VE-{60@e~z#jyouIW3kq=nffvtp?xv8kA;F?9yN(YDmL!A?_571G_9daH8 z;X<$V6VSqD^VC&{IsM1^a*>tmG*#!2-m-_M7x`>vFuv{4;#lUaC&m?4 zS;e+_frlh)E8Z5YvZkfwWP1)-YecE%E3^WpW{&_67M5;8K&^jY;iKlQDI6gOhPloKL@6`1Fs}6xJF^nr?pFJkB>SuDl_wcP4&1J>Wpo_#!Z(_aHuh?BJ>L->E zp{E+S>WM?W&hM^D`A|hFYt20SRb8y*J8U~v)v0Cmf&5E%w06>+_Z)djxGKW@&ODvq zmG>|5Ts#l0TDi6vWst7nu!aWIAQ7nUk)|v%0^ZorP*%o9qO<{t21iZEZE^Z;qL+@$ zEWpG4{Lc~emLY8y$!~)BM;^Q}oGp)ai1da?9dB`-hsEX5t-Qx$T^YLVmvy#zo+KW2 z#IQE4k4ut5_u|R?>Jw`#M>kg4`2vy*H+Fle{7;mx_Dnl6WNVEhL3dSADZIYs_xl#> z##Cw8{&Ts8J=8CJVuNQl3TMb=AClz!FMWXQSIwjh40qRvN;i5_t-ZbvL2-E;i4YC1UHux^*@b|Jf*+hY<_f_w2=@)PW9YEL zX{mUHS8YL-<2}0+w>Bpn6QD~L|4+=8o`DLOhyVPd_c`@m*sHQ5A+bzgXtLwUD91+M z>QogQr4R_Xp#LXK>5(K3^U-|J8+k_8c1tbm&q)+-;}$Q9TUZ<(v}JRi)W`pOKY+54 zwen(eeNNE*g-y4HzYj{4u+2uM^!7&6*69IfZ^panxfvF_y}6Zi6892NeyjVVzYAQf za3F?a(U?E)bw|sxElN@4lHAPR>cTh!OiO3~j>}@}h^0g7r*z&d$Izf1U3h+Q_AB_} zh{;z;O6ik^r5v`LnQoa(_V-*5TLXWN2)lbf%DX7$PbJ~qn0fFXZ)u8Az?|=#6HK{M zPmwyxuclD9B0&7`h$rzkHX$4oMLA8zr5@kfJnItJXsFeW^e;Bc^aCu8cGRaY`gLq; zUw;Noc`YWf2nm!;7_&pmoe!z>)Gmug@S7wFG=f10)M&0v{x4jo^s06`?Q=!BZMy2} z`g%M!BofKFW|s3e9ZpvT?SfYihzq;;=A&uU^7tGSTq^cSM zQU%UUG)TzK$&nB22riacelUQ>5%=;s^))x_J9l1(f9sHYavkmLjNb1+zmEIiu?ihQ zc0iIGyq61q2@7fsFRtn3RCF`l{%|LP7*2h-cpXAqC5B4xcfB37%O%z%n-a~ZcW0Hy zh-}8Te!3qD)i|OJmxaFOfNkE1mR86;tLm1zV}VoJ5G!sHy|U`nn3FVqP)R|3zvK7E z={48aK77bteK3W_sul6&m-|6C^Pjhi=lAZuop|)vo6dc=PdmftH{qgNrs$goOIh!q z_e&EjFZU%k5h!U~xI3=z)1XI*`76WiWk!bik(+>;UEJ{%6G{h>VN6fv_RDd{xN185 z`( z3wft84n<=*wU}J8zmHKZnPL}x{VwlhIX`qcEBa@)sg>dfv=!66%biP|3v_R(OpJfc zibXekQ7Xg5pT)pzNy(3r(0Yg!Ccof>rv13%c^ylj_T4egw&U)~>}<6cyBBW_1jyX! zN(kH^T})Yb+Am+M>}Nc*{DGqyeXDv1@~`YOAR^k=O$6QE>!a1t;j+^Ovj$HrN=nKl zNY((^Z1y*?6||gvIYoESa3&=uvjWfwMp+Kk5)5r=sG?5B$bxW_T70CIIAA`BkxGVlr~aq3-z^JIghTZW|@5ko)JvLdtc z@-X2yy3}j4CBx|eSS9OQ#8l6w)lqssFDO!AQt|7M$&~(R;d7Z&W+-ln3~K9__bJU1 zQ;%MxB79H(XW*-IjgQ^;OFoi&9!+{R#tV;$A2^9*a6Fx|t~AsFs^>mE=Z+RM4em*# z4=gaWp|!MOu&_A~pZ%5z-E6~|^6f5NNq!-bXMcusCd^GFGa*BJdShivM)1{#He1e_ zqY*D3>tXV@roOZdv<-FaA~@$Dhnx=G-rsSBEK+ANU6!TO#vyLh$cGyv;keH`PHzW zzjrFmr!XBwj0ultFYikQ5Tj<|W258GgA8^HhOFN`Axf?BAS?PjgbLxxyeGpDt(0c! zH>+qj*17O8*~u<4a-s_}F0zNw%8ENxk^=Q&5~L4PjC81O`=^}_#23OT+fz0Bb5F`z z#cExMzKb%w&u%+G6IBQiwwP{@AFib_b$y>d9T+9-_Ov5;TQEq-8Y}vykBK^Kl5Wf z+pp)Or%%MOy_1|N^KCU5FZX4un{6ex7w$7=;@wr8lLbM5(z-`#(y_8lVU?h70`Nd5 zEv=p2ZNg8+3cbR+ct@-uQ`hX2iOa#>a&U?O72;Kyp5=S&qPVNpo_wrqz4eIK5N-a9 zm*VDtD_f2i=9{#78?${!8m{>c$(MZlV(bytlaohtqU5rAZ!t)*gu~GsB{*)BoA))0aAjy^u1+~hlitsi zXi1s3rZv-f$*A*B=t-W$QX93I=e3$EDwa@1GZA+9G&!?CB?V*_)6Dy#6GJT*4ImUnNA1NhB~%A!3z*Tz5gY7b|y zH#D%(eJ(vG3jHB{MBVL1${E7zj>Cq3xt=SyK1JrdxhMF%UR8Inbj_h16(2*d#0SL9 zBZm%Y@$KImbqksK%DtKT>WSnn#$P^7+(M^MPKj>bR$fhLKlF*mBUj7_)VCerj4y8` zD=hSAX<54)|6Z|sor9D2V@t;{p1sM%3bxS9_t>7t|5`-3du$!9Gsk#(x!H+by~-xo z%Kg1MKM;F2_?*kS_J%^b(aw2bPO5ibRf0g=1DwW`G&?(45plZMPS;PGE!!(oX0|gB zRWqQtv!i%_ld9pKTCZC=NARsCSt1LrRF~xTD9j)-`lWTR6MOUm{0A&-o`qF9y{(;{ zt}(WSg>1}0+}5>y4N@lars`a=)fJzKIieam*0j0P(xz^rGq#A(9jp}6_5`L|{%H)1 zZ`ZWOXgO78XjAf`uE1}OhIK^8{6dK#TJtWM*6rM+NiX7xyR@I)=+ZPkzWUO1jPg=Q z0X6&f%e-lpD;(s#-+KAWY${Pwe%ud;uMd>cLoKYOi+S=pv+v>nwIDh;=}lYL0?g$! zokaR5uKG!lkfGDW^u-K74yjoaugAkjXr!c&5!grcBZBynri_!C#)Y`_bzk+HDV_Ht zY6ZvKl9DiANv{X^TC=&YP>dhw9mj|TdC}1z?_9h}nK{vdE+{?0;xAGx;Fc5B9E}9_*bI^y6ea zl*1RyYc8IxlaH~p-i}C%^YLL`bG>(c_gd~Zk@E)wnYS#cqIX6oh8nJr(5<{RQyF(U zdEi~US@zZ-9J}S(#%j$;Mf37<%L)@6$Y35Z^Sa(vOkc(yEd23a7$U1x z6Kmh5xBTapIVaCrFQB!Sw>rPPsby`G&BMD>kY>!dWfg4sk;QTtl_fnGa!kIVVt<2k zWBq~PJ>zt<(^m{L6XKSu#J)atKYhm~!-KyqS{wIssH(bea*wRPx+So#ezzoHexkW> zzQfzQuQ*#y?E~L)6RxvJ2JPz};@xhXAw}?7u;~eyp+D!x_)%_9#Ux5`A*yqaDV@~6 z4tLwY?Uv$c?wS7OL%CoUzRTFvIQ`1M;?xP3#M|`+H>)KF`2(4JkLt%v6VPa?yee() zuBzx-q|4VDCV4;S_X=iA#G{ck>@B6YAR^kASzUEwJZcIs>g}Bz0=pmjTDi`hfa!we zsvobUVtYzE0yDCIU#2%=L08apA6+LQ^&NOVk!F3wGwO8}-Ixfwu;oq&1=m5M zTQHSCa{7z@4xQWxU3y8eyxG?mwG`*~o)R`)v*_>Hx^aFe(Xs1&%(k!gYkhp{KH10p z^tr>&m|Bz@vWoM!Mvq3TI3B#YJnlL0zQoHx++Q;+Acbr?z{p0YVCaT-zpLlfPVQQX ze)6_A0->9j^bYO-wI zdwJR1sh)q#P5pApZte7kgw|#ATh^nkcNp5P8=@ZqE9~ZUYhah7NK~(F0!V4zmb3xR zNe$xJbH8yz3uFgkNPTLgkWc9yL#<$E&l?+e=T%3;b`Dpx(tIaYJimz|6+cnvX<=v@*S)Kpe;DVyE-pnidU%F@*>jDKna36Vns9W8?-syn5yHD?NvLTCyMABaZ zWec=%xxf(--_7K&4kyyrH8q1)ry!4y(#TH)ag}x}^!GvY1$Jo?aqpF+@$vZ!ii+k# z->V;|n;p5E6D5-Pyg0 z>i1brVOfvM$2V~^S-+0Ez29!akixSC+JfrMoA1EPM~H%Wu_YKPQ1KatfVBH+@%dK; z;_NqXuz_?}l^jDOj1Dz2VrelMpLdy8oYxZ<57Aik39D{yHu1`NTUL88R5ln#dbTY%-3ap ze(toEatHIPc)_ZA3wDKAFMn4@q6lWl6h4h)YJHgo!Jt2hZe&;W{%7N?j`00Gs`e$T zukU$o(ck{-L zSFR36I}3)O_xuy`By#M9M#Oq>Gc&RDxd6k0fIjN{x&+8UgQ1tx=j1Hq#Rb;9N`gox%p4^`^n1of1IUy`-ct(4hIP> zk>FXH7&ZF{!yM1if7%BQ>D(l*XwyTQx;fZ9Hka)`wlbweUdbgF%B_^m)n@V=hh2to zy=pQw#azCl{ITVdO1H_=pT+(-Ha$Q3lU3Z`ZdXl|bUbN3qWROSRxh*I5cE@smuDW!I_es!AVjVvfqD5u|WsIxP>TClX?dMvBx&A73Zby{r3 zP_rrTqsO>W;L&z^8v9J4alE!S{z5zoa7AF2%7&M#thuI!;+sb6ThQi76%nJrkffZe z9oVj@7!>Cvi?b$GYO3P1oUnu2_(?s>&En#(c^2W*VaN3XiF=FMx(}{qnUwy%nBSO4 zr6A3xRpxas@k0C8Sk0QI)qZQKsj$WINaxBojr;ybZ%?lWjJ8G%wB;?445QHdZn1DC z;sHYdGiw6#JGgFuVlusaiv>Jj?*VJzVh3qi#Ms14pI*vF7TE0U-{PznzbZhgcI5C% zu%G7PMI068NpI;oa%_s1>4LGs*0S0zO)hQxbshVY@3!eL2x8%>LND+=2ze`E_Ci5L zh4jD+3JVb`HOdlZyoSv_m8EC5HKiVbG}8u#xCqM{U{IhY(ndau1v6|m^`4##T)`na zWo&SG&J!L8O}nB^?;QLl@7f^lr&oo12H8HHxUXV80;qlkJSFWSSFTyzAGfBzn>q2T zU)-_T1u%oicN2yd{N=QH7Zhr z>C57CUeM0)T2u009FyU&-kjJCasK<|%-|&tVb8ksFRbT+n}_II$LnPI3Z!k-N*bmV_2Y*SHWpoYStMQU3`MY+dN8IqD} z$Nd+7t-QI3LN}UY7}L|!3wrht=JXRoVy-y9tA$cgMOtQNL?~Du>oeI|+1S`L^$ZNy z`S?CfTODFCW95epIV*X12!o>>J4Sh63!t?Y1+o1((g{ovmJjvwt})U zWzf&ojLkIDJySvHfuj^Of43)}Y2@D-`m)yRSGMBU_$mFeiZ=|}HmU`sEe@=1?!DrF zP(P6_y=Qmc5H)17>RU}5?!kPwP#`$=$bXGj->q~wJ}5SPug8Mj44kmf+QM1dZ7&}M z{ObeH`B#rVg-9ec==neX=6FxkH1_Dbq|HEf4X=MtI9U3Osou0Go zxZOVQ1>YFBjS6;luQkti)(b|0S1O5zY?zDQo!yQNTr!hHS9O8+l2uBI(NC&e!jWh{ z({D{-ZzN)+;(XAC*^fB(pSzbf)4cZxZU%RxFd8IILh+=Ig4~FxWh$%3f^c?CX&GJ`oVv*WpOhO{R_+q0q7PA z)A8f$Ng2ZdgG7I3D<1J_&j08(lwop^%SJ!*^P~K5dYf_G_cK0_pz48 zkFk-@a&&ZrTp$S91aHFoX%k|PwmVWmo3$5WQ94c81Ir|IbojEq^Rba3!I?h4zFgl_ zgs+8Sk&vK+A5^_j|VhirNn_p#*bkOjsB? z=)3SQacOMshOFA#L|aZ2D5}0OP2@W zIqJh8mb5fE1KCM0Ab|$1q17um?|-zM+7!dMj?d*^V+ZlcWy`avR_oK$x`PRR%qGAN9|=>r+cI zC>og{N&8Q!p)lVh0ZEjclxovJzF!LyKnG=E@C5L`txs3_w=T?ZPD~0mOpE{0ILG>Z zkUfe!6*ffptbbU4jzEwR;a}&|;3wR=54j zz2PL%%m#xj(B_WbqK6j?z+U^ebweKo7F;;)KOV_P780xTqYLD+JNV%pAt3&NL07lF zeXVgN(1T89soS<}Y(vBU^N(wyC5}U?V<>EvBU2X5KBU0006~KkVuS@*F9`s-5UQ`` zzza$0O#^v0 zhm)H@I3PWT8&Z3;&rd}Fa4!Vz(dk?Z>D}Zskl6ULTTXG140hDPY!ML=77-DOd>C^7 zc3}oIIsn>`Y62YGTDNZ_%kmh<-yZ}+#!t|61gW7Otc`?%w*>h3Sx_p#69n&(>u<5h zNaIfUafzpJVz2^U1;h{}43k4o)qouwv+$I{U>{jsVf_P2u3d38$QO_Y2c@N@6#{Yw zWZ-We6CT+^FT%!lb|EZMmA`lhAKn%ar&z-(<})9!0v{JqgA~FCJsxGY}By_Aj^C7DSn1rl8zqqRL(G1ve4*nq7IQQ2^&}19Vh*2=Tn5>P&4o8FFH?8x~Cy~0= z@F=0Vzy$zSfgnBs!FnI$aNX@4h6kep9xh3M+~4;G9{|Jirr9Oj8935fT~32=aJ(6P zbTJSjHu-@By%TQJ#1s{2eEAmigt2OXfRo$Y%mDDQ`wMQZN1R}3xqw0lejtClYjS^Q zUM*z-we`{Bj7&*M>AuSuaN@ZI1tI0>m6`8AQ!tt(lt?7;_JW+jii76JHN7Bs zciyg+H6hM*AUclQHAK$9#sZG32(#-D@`(K1i(15@9s7)pjP!^;Ka`cN@s^bp>yI+C u=(e-Ha^&Ud;riFXF$10RKb|-~onstRlN`mgrQoCBkD8K(Vwt>U*#7_^v4&{? literal 0 HcmV?d00001 diff --git a/manual/sphinx/figs/snb-step.png b/manual/sphinx/figs/snb-step.png new file mode 100644 index 0000000000000000000000000000000000000000..c4250643a82324e1098dcaecd26aeb7d12739388 GIT binary patch literal 50363 zcmc$`WmJ`G)GoXLky1)ZR6-h&P&$=H8bMM*x>Gs@q)P-uIuro`>F#b&DQOT8>2CPu za)0l8{+$1ZG4=r2to77=&w15cAxa8TH?hgF5eURh8EJ791On9;fk2tVybizN8lL(M z->x}|%BW((mnWuCF#H?KPFm9ufxt6B{)h5KB*z?n$>$`Y;q=_r#L30L!5Cp};ACfI z>ttpAipts8!O`5-hUyV32kRpiDl;c1JAO8{|MLf|whpFjTsS9P2m}>EM*OL&Yx4TE ziz|`wSkwIMx{W&nmJAgZ*8O`-+@YKjC@AP|PbJW=i4qVAA9y{*&t}R*<#xA4RU!U_ z{T)5#Gv_KTiVEiHgwdp@53ObhKIXUX&&g*shxY~c`UFj>j1*JzzU1ZI55O12r0%&9 zQICfFApl=OmhcID6AgYO`Ty_-qMDbr&chjE7|g0)d@~upYFBQi77q6HWt$GB{>*)j zk)j~g8F|l^snm3k;v=W|o1!8%R#sNkBHa|G=by*_5=@pWt!$=<5R5!p$ z!taQ`5bu0S&~54Ok7y4go!ljOCb)`9f_$6lo8+9qv)*SBOT7tuD``I8Kgp8*Dl>1L zC^g+WOO=YeYcSj3#c4Y;^)@CR_d7ZZ@)^~JhKCzno}Y+IN~&atq9bN}uDrOdf3=;T z?4A6MRoq+Cdqlt?Dz&gpf!&lLVmmQw~12ro8J_qjMAH7QNZQ_ElGOO1;Q zEGpU(nzcRJoX-CAso3Yr`|Zs;l5xyxt_LIP*2FfsR9NZA<*?5D@ZrsZ7rhx`K|>bh zZUfb|wX=H{Ev>C6U!LdS78e(XQwV7hHu=O{Q$nsCXSGIeuRfE#&t9vn<*+TuDC3zC{(2)T_MD0g_LJzW{e~G>KG+s z6z2C6Q+oXamcn%xYpceo@GMU%&YcI$4BdM-=5?rbJkk!xFZ) zw>PKNcr=G$hfN;VQN1XjWV_^jO65sOZZ>Coaa$QH{Va>i4>>9I4a`cg@f-*{W-@*xyFL=fj)-Gyg z#d5GVCYAGGhiM3nX-CmEvN3XCjBSu3C5Gjl4{5YNAW5%`^{e3j+!@$VcH4hJ;&NR28 z`KG5+z47@{)5VT%LiT?zK4Ekg@EaF%a^j?>rWTiwn6|%>K4H~i#z|selu7GgXZIw3#?>pss^IETkm9d z$^P~0IK0;}Y-(!VU0qbHthi6&i3vq9m04s^U166`d^|rnJ^dwcR~facstSQmN-6~} z`XrzMYoqx2x(Ny?PqpEt&dZk@cS9Iu92)hE`o6#c7NiNAP~X|;*|YsVlYl?9r~j`A zh~K8cO0UY2O<>Jn#FmPpD0g8*UgI|c8H8;0@v-am8)Q#l7b++yT)Te#d(CUh!_8^! z^ffV2(JJQ+@^Z_u>-w+>;W{em>^I*>SC|dIp%!~PPR)#52u3lQO`mjD22wc4Zm{T7 zMfb!#xOL}FZ-w=ww6rwi(1BJ#d{a}CXyopT>;5QGQl0k;o~x-riQ!K{ z&lLauecR@AZ6dGz{fF8W*(#r&3GTGr^4xC5sM~JAd2(nJxcVdKM}@Vvj*iY3o$5#V zFA7R#7MDpX;hKg^jAap?o}NlXfvG|sTD|9IBbgF7YhH)z6JkF;%R?!nrlk#VnQ;r+ z-*;L&`Sy*yBjSz}6waOf{cPLW2E6n0FjBVV;!cXz)>i+frYAM8*Gyif;a!^dPgU8| zL%l%1GaJx1)H|q{YwLkQm2%oJ#Mnywo(rXZ;^f})_>tsZ3 zD1TaCJSrg}p;>hk6BEDQzXzwNarNr(s;b)BQk!Z1l9H0$hdd6yrTJYp`-%-aT{p_d zT$ke1d0+qi`EW^8R8*thoeSY}b-^=M_;NA7sG-F9)=ER2jO zffNB`4=Q=pjt$q`3Y~Cw>MD$_A>C%W<}RN@Kn#u4%--H*(y*BkT+m$s=kV8SqxP%c z>D&+3-DIl`THo%h=A=3N{mDe(_M5=6?+%ZR5!^Ty?TYYf$CdAeF9kBQvL>n>8E!Es z{BFe)`Q7A)hIcmy|5Hj{Ugdf6Ez$8r=AU1_FcK?eWoFv&<&3S3#4;%6xz}IDJ3eVB zf>RS#)Kpg=^X%oeoe@;j6cK5hjIX7HXQ<-k>8WaJYFci;*zp&G(lebxz?o(6@&4AV z$RL-Z@JTkmeiK4XP3-_$4RbmLpMyC3!Ky1la))AK4Hns)c} z2&esM|9JL#^L3@RN1@}&K$+!OC0LsGs#v4Sb>}{p#ZSZ>tovTaBG|4a z9!E9^X0^PwkXsC2S6+P8FsNr8vn;BQU%3GEfP^IQE;Jk*1Yzx{PmGLcxhzM^;?G>_ zqo?UM=I0H(DDm-qU*wkyKi@1)s(l}bf5o2E?|HJ65KhMN=Id9Msi~>2EAbDtJK+5j z1>GLeNJScre>33a7>jS_?_aakA*F2J$gg-8McZ148`8DfYX(E zxmI{_@#s;4&jr_P33DrC4}K-5Mz#+VaFScr zQ~I1TCGprU!y0#cms3{8d3vzcDX>-NDBG2hkuh3id+Ce#@Ypo6eDcpMB`)*^)m#<2 z!Q!ch<5abG>S1G**-U@@B%83XwWSC*sX)83L!bS3_2%rsOrfxZvW*7|PcD(@Io!t> zQa#V%Qyd+5Mu}XO@dxKW6h-9W7Hd}8+=Hk1syF^2AgF>a25&6oc<2kUz63OwyG$4+ zxAG=XNgivGKg3E+{d0ak%=hQgJmtAsox`O#y3$iM$A#5`2H1?9bzWh@aaY#8nm_Jxik~-VyBl6nvXA{|- zFs7WqUZOi;)XdoO3Zh>cT?xjLi%>?br+cdG7d3di_=z7s?uO?m!1vSa%h`78T@j~X z`~niX6*BUhp_zVnc-SpC^^5ffx|-g<56B#OBPkYLWb0f#Wx3f5wOmG8dJe9aj+XYC zugK-`V(KP!K$VMRR!rf`TI52Unw~~35&*&7Kg0;g$htmqS!z^R-A229Lm%*cIHgD` zl+0fo4%9s)uyPhorW{={Fjn~D6BA{iSp4ZZnVVa;%IUIsU3-l~@l|dftxn@WZ&AJE z;O2Dh^L!Et8=JfQo*$UPNQN`KJnk~9BJ?-d8n<0rB{{tp?Bfe``zbr49K{tfC>)Hq4ogkuY+#JbcFsenccL?)$yn zg=q>Qvz^nm8x+FHsVM@B%L^^Jdn*%{leTiVIqsji^_j4Acavph?fIBVh`s3JLfnW^ zHqxwJD~%N&(QnEeGpw=q51pCe<>%i$c+a%IHkoiMNAa=ERF&x25x%I=okvEPjpw^K zHa0fvGxbUC2Y;t4k~0~d)<$n)U|`fZZ}c#vd5XefG9OBRN+87|K0%A6kM(Iv@RIFl zys^ji^lZ;)vBQ(gntWw2t<#K?kdRPRe74~RrSRRC3JI$piVZcZZSL9P-Fc>@gbxcb z%SPeoTUPh`3)4VsUbRBGrJlIkk4vqd0FF>0pQ^))C3A4cf0*R%4J&C1mX|GCq93%5Ppo?6aD9p88qSG(9rwG+z)+8 z*>q_I1@ErB`iW}x0M>x>h8Dl`y4jY}?k6pliEjPPG!w^Ekv;lw6ZRx!N8M_@6`tbd zLLxc=j-M9P3{U&^W}2zb>ixx1jf%^BW-;v<64>-U1I|HbrKF@(gc@*iyclIZSz%2r zN#9c=;5C!L^&OQlw0?@i_h=F~Ve(}v12tz-srD^f1rm9B)!5avqKEP8YvGcrSv#A= z=A5HOL+Okko~uY}9ibHp3-exkFGY&)J21#5ph=WTG`x0TR<5;18|fi)i8#Nw;B)#D zT~>jk96*ag^hwvor8;xCNr+Z2k1nT|kAX?mkx*RDMAcED#EkRJ@V+8Wc5}24$?&V@ zckz-feTlTXwa$+0f6g!Lzi8}yR!6_f{GzS+m4p*9b9zi-bY{S9E(@YN+*bMn$$XV8 z57d-+7<@>==my`(iegU2Ui%gvOMp0e4v$_+it&l4i9CJ;Tn>SwOhEu?JGy z$wheyWPz>C|G zUR%-d7hcsHmt`M4#{%X5lJZuD?$XY_)eleX_D1&drzDM9^Abh)@ed z-;20IR`jyfbt&|~_?x#Ev0721;hQf9JKeEF`~hzlh$tcrU3otyjXovHWYl0GIX&8n zny^|HxjMmvhI)=Rt(ZSjV%$q|pN1y!u_-Q%!wW3HeyKo~i3lXJp02C}4GiKX@V~a< zE6QVD&ZZ3?R%h1@>A)uroZmGLPhd5y^1Kb)bGc1?KP2SORsHj@%sKqK;m_lkCyIjd z=Z=TOc!l=y$rA(aV|PQJABXx35E9u}xvN*8Nlm~n9-H*({~3Z+zso@5YW1ji3y2w)sY+sV9!ue zirDz|^rpy#&4oV0GeDkK%AmrH!DQ;aee;sb%R9g`PeC7{ zURFIB&3$f^Dk!m>yPiPD71tNb01futZ?$~C^@oU*wV%zObcJ;Oj<$c=r1|6NwQ(Sw z`2k3ed=huD=Qrv{zfG)#-W?blD7Z=vKdyM;vrU#+fyj)w7dOdue@h{6Bh@BFWHVGu%kU0WVWD-&sznJJqc`E1o6VdCNC09Flr z5yV)l^8C3>_rw}SNv(N`!wdT^MF)pR2xuU+hSdPC0B{Dhzsh*(f87&+{LehKwPybc zj+5M%J?)*Hj{*LRiiz1fINWDvj~*@1E_K<`MQS{7*%xO=E7dk#(bR6mDFPVY~L?)XGHYK=B3BJR*0+-YS`2dgfhv`)*VEP}!}M)$un57{&!5*d--m zc7G_gMN$s7C-6IdRyNGMj=Rv2DPfc{AHU30JMI~eGN16Ha&vJ<^&lQE# z{=5z;$ua5w=<4RCsdtNBuFB9Yti2_gTFmTwHdeXiEWZq!db!2O2Oe7rk@Iad*?5-b zSH(kB_J%;EtS>O}R zX=_k1EkkUD^&My_DCq~gEe9c;_Fm^$I%%GSIYIf-I0j4v#KaOg3MqE4UoVXp8wR|6 z`%8e9db77XmSL|?r%`)t7S=JJ_c^b};d-@UwIm2p6E|~!sQvt+><^{x5r7d4oL?QZ zC@k&o-n|>I_uvt5UjG*PBUd$-P*HG4Jk`PL?9jL){I=EjxA{n%>c39>YgKQ7Uw1^_ z>jmn{=eT?$O61aYUMQH6yDT-eN@V2PQO-xi#3I&X#bhejC*8*vRJVh04HOjUU$3!c z+w@-=KV4h&U%RC^H?z-#>=i+T?A(%5Gk~Q1n)TC_vm^ro0*Ktb07ruQY`;DC6jad{ ze-1)QfZC%CqHccWG#jGwK3!!1!X{y7w=FcXI5+nM3K^fv=F~-i<`-I&I=sBROrDP$ zDwSdW6-|#r0g2kXxR?Sn1f7w6cGeEW)79BV5lYW(6zgAQOhXjOnwpw@X(E)iwp#)U zA*7#@GJh<|;pXBH5PXp|R1kG#_gJ5sZ~buVmdtcr;?Mph6g&501LWBseO8>`9XBjF zvd4n^dUJUo1*a*PfF{()#1Qt#pwQ7>lCVG^@iJjqj4F9~yN8purGPt}*Ty|*%G3be3pr{hj#{j8qPMPO~M0OI!T+peyz-=OBBUXjo} z6KQXz_UN#ycOT*rp#FLFIvK<|>Dl@_7im84ULUe(nhrV`UV0Ldl1`Cxw=E{-*xL@H zrlh6SQ$GD|xZIbRos;vt(&nWW$i%d-Pft#UzbMmy#?%WPw9gj>Ei_w~nyPm4sCKJi zF^JN;31pZLAIK1Ob#->#6YixRN1Li&HHP`$+O3ZlBgI~*8POmZfv_+D`a7_RsOeN1 zkw@$~@7JcPAFCJXE_G7+WJAe=zlUok{|2(L;1a+dx2uaIBs#h7KVNZ_2Y?X7u%$o4 zS$FxJf>F?}4}ppgTqNqgE1@zW6E1EQ_m`-vbiaTCje*v)Llyg7+B*K%qH9}0d1JAM zYehO|cC@BR+>76Pi|o9XS)i+ksi}Dcu{nTZu9@%(d9X02m!+Uhplt)!A=XS0MaZQI zr~LkH1eNlsl2Y_RIcPSPiCtaNKzmHQ(ms5U78kz;w0!PlC5?fOE)aH*a;b^DhhWP+ zro8j_bo~4uqoeUNL1tN<1vBM0P@RCFpvC0U91EFM)B(jbVXyI;*AD<&(zCFHgGk42 z)P?{3`}Z#@pRils-dqHq0x8+w6L3aMl=_YpXm<|#Y&_MjcYjUcvCa|CqPhEoBaXZB ztbxESH}Bc#>W}P=@uz<)HjF4lQdjE4%or&KD_TnB?<8A}u~vlT#-r~o_h-3m&0NF4 zaGY;JzkBy?=+{klO$cEA*%vkbKQ|`3j;%!iLfG`B zbVgL~*?rL<7_6|~Hk-b_@~fQoHp?qgRvi##9~pH;-#cI@(TJi`sD;| zK-J?_RMvK&JFcgzIhrL#SU#6041n#8pdoo4PMFqxC`D{H9&AjKLN94J+pN_dNR*?0 z_3Bk{NXR^BfJovA-F(@Dje0Xs>k7 zf4>Lr4GK$5k?KXe{dggpX%_*n#vx@L0)6U!k+w1sztbOtG|xBu3RQ=s;sgBlr z9Ep12Dj%9nO>JBKARpu|DE@Phy)h-xvn&sfF@%HvV*sC{%!kLMITj<^?ipyQ8KnLfu?qNMi+$!d) zgh@YEcoCX8 zx7$UdN+y!Z+-Q??ezuj7j~~Ft5fgCxG2fBggTlHq)>FgI^?Me@F_WibSyFg{f`aRJ z`$Zf&?>|FjZ1az0ovQ_>(bdD_7AYx)QIU`O-5N3Ro$NejXen*&?eiNO5ug&fNH5Uy zQ&M`K?Pur=re@pBDl9C}8Qm3>?s*%LZ8aW@?D2O9{3f5v_pD#-{rss4$~Ib)wr#!f zirKCOU@SeagE$~rV*epuectycgi6cULZFZ)9`|nQ~ z`f#FK^YimMHBKQ9wWrH#)&3_7P_eyUI*2rNTBK2rqe_nQH_+ft?KZQDGcDnhNjH7V zI6m0wjQAugqf>XyP?d-ytJBWw^v3z=QERQEDbQt)AT2XsWIKn4tfLRd9%_}%9q%lH z|A1V7A@mP@yKJw4%cS|}k+fF%#{joI_VzZ!oKgm=x9!a?UDIzw3ftze$-$~I1oY2o zIodZfKNX*s*UtZxxIM{p=1R;2Hfo!-na)e5v5T7&ze*B)@kGQ|w!ke@EA--hx3}>t z_PiDE%cn2I%#R+ui@3wH3#Q;LGBUF*yIs2OH2ex`q~SE>*D)O9P}JBVrd_Gz{YR;6 zsmCBZ{P*7>1D!wHsJV^jD$Ju^$$*Rj-GCsh0;s?v$Wa~ENA~B>NKfq<3)1w?L~sra z95+nFGHX}PUCq>*)z`7>R6W^GuMF|b5;$#)oD^s~GkKKwLBNF-0T8a#k<*38bz2`` z13>BwaNsiA-XU%6O+VnJjlq}{zYcL4F3vJ|`C>q5MpowsS7($RmSgMp7KA3j>KPs$ zJ_c}7YzTMSQ5~G+4|4Q}TeG%c-!T>gLlO->OMmT>a~@4CSY}S6%hrH+(i64DH~aaa zeQb`tf^4Z{06LGyp%slpaup96ORDH`!^TIBs5 z_m$ny3SiZe-u`K8e*>pAIl8IbfD(VA9z%0wU_zkIGmcF!wLgjHvBgiuJoO@*Ejw&l zMn+5@A0MbIolyx>#R;P0u}C}LfCjevPTynI%N>mKSufJ|iNtV!jOwA{TlTT^2Hg_| z*}TJMoPv9OkHc?2?wH9S`jE-^GhZDq+D4yxGvVJm7=~uicze-&0rk2{FI{)nfW;E>ggtkLlisGioTb72Srz$+WtnNbXQsKHN~XRLQ(vVeDx4-ODbjC zn{8yIrd!)&AU6Pkq=24W=E8XN6^d=$>EC?8gP+e2aV3HYWh&l?RlFq-B@&jEygrsQ zNM&&8$(}gm>PB!pk104=S=qZu0ttm{=;$%=@f`rG%pjK$(@7<+96NaCBaH+1j|e3q z|H0C%N5VE&zI~w@j;zBY^{X?HOpN*nCgFyzMa^;xVt5M>_9e820~r1PJ^A~;b;_9y zdK2bFj_=voQCUxNvzBc=*&P%iU46$va<5Ovz0<7a2Q{O z`lETHUB_>*pi|(o&{t4c{_C;jXuORthlLfWdj(`_ywntrJmM`_prr0zflH8V$pEk{ zm&DyalYyzcAdL!+qVs}I0r~uFQIqWu)zGT+bV(o%n=`G~Y=dZl3&ctgNGmXu_yLK< z%fMWqH@NEW>Rdu2AL8X{&?^A8$3SLc~O6zMUPxKJ)MoD+^1mAHA)$A$#rkfILN zy4WVoHZm@;qSIKSVB2r~yY5#_pa-?QC~T{>R98|XH0k^85S0poS*f`YY*^%@`T12d z7BKGQ{)|L{LJGebC;2Nw!;p}WVi#V~_l)h2Q0j`Em{wA~-~NdDx%6r*VfgA~C8d{5 zr|X2biPb?xbcrx#m}$f_UW=_XmQ;?6aOv1 z&hK`i*e3rm94M{o<%#K=jwlA>R>=hhMW%(WK>QYN!8D)L?Q%;ySPYI1kA`jQ<1WGq zn)OThpZ)Ed^@&BUcEw^@#4Qq*wpv-zI)TOj(C4m2-j0A%%^tC|(bo0(jmdhGd~PH| z2$CK4K6zNF8^1EH){5>&>R?h^b#idNf7aWOr4zNTSp!**`@0dFWQJQl7%@;oOJFUr zkc1Vql+{iN`F%oH3if#ZmGH@kKGj|u))YBU2?dCyQ{-HtX@j;dtOskcZVLhBN#pp$ z62A&xR`FQI+X|8Rqd02)5-HkuniLL376>T7zIeh^uD>`r!6S;gx47WLA8UWSEi@~u zriKh2!Rl&<1PwN|)|uHz9x)(r+WYrgkc%zz&-%Tlez_1CeeSG-gMLSywH4VH!X9ew zug#(W2gnxH9b!fFdm!sMOv3 zj&FOXJ@9#7@d_6;Xw7-t6?BaT{JgNfE(a(Po8wpJNcvMWa!xb-E%pFL`%pEUxeIBL zZGkb<{`+=6rCZdCJ}>a-#a1|y?zm`>{e(zL-lhG}XjuF*wbL%e}O#xuqqw4;cXVd|$;O{(9Cu&2K+1!lGPW!vgEf#zX#m zOmFd^1?Sjl^^IeBo~!T~%hHuCCRV9Q*7D;4iN!y`qth2@2}w!)X~;{HU;O*5y*qZt z=jf#p5n-dYr0T3Ui0+%NFC`_fgHM81QtAD`x=^RO1%wA)x83Z2U5N1oR{Fx9V8;Tj z?5m1dce!#6>Dflggk-;ltIvNA7(e>-oBS|yR3Mpd_y~arA|i?ABHL@tvz`$P3!^KNQ1$b2wK`7>J7-{vsMWv^@NY}=t*Iqx*uvzGI)CI&JlZehA4>wkBb^Qz*4Nx;ST`nLjVQzK5%Kq*~Udxfes^} z%owjo2Qcyxsl|DJ|35|zc*!&KnAB}T966t$zUqHJ+C+!=$uQ;ok56F-b$NNoy!LN? zm0M17^t8mDJ=Vz|c^4C-yx_u15GWYj8XOda0Y(EP7Xi#sKfCr1tPm;Py^HyA8>@l93lV(wiqOZ4^J94U z4FRba$4HGA?L8C`?0c~{+&Aj zm;)FO|9c^QDz7K*beITX{&6so)jfJrh z^15>(uu4~=*k!XD3&eq`p;yA`Ir!`~p%&cX(V-5-K*W zVaxyf8#>|3V?$l{RXR8cyRnjndJpBzejb!6?gg>$&YLXj+t|}^!0;FObP#U@YKUAJ zp4j@EQ=_z`Mrt4o*(l&*GSU<*pGd z*!*`_^`W3Z@=UoF>{=v6#K72*cRrCQru`jIIogaKA$2}r@vrrc>@aW88g)3a)?Z#oU4n{jh!@5QP4N9Ftns7u|7!I^ZlZCbr)%+J5kz)nm z*Fv7j0n$qp-p2-z*zMXI6wwn`CY|!CM0~z1x!K-~5>YGVr)w_Y{HnX_oAEl7)aBf~ z9x%^*&nz!$6CL|MPSgf6V#_>u5nbh3{ZN!e1(3`QGIn2xdSUuE>u=eKV^x5oavk?> z*X7081PE#%C?kEG{r!Eyx!5wYgpDQqv3^ z%&OVH5LcUe>+g?d+jzkZYHPX7F2>ws4qobDC3b6gby#>j@-e zo8HC0nAL187c2cOhDy*r4O-0H>Z-XHA0OY6wlf4X z&i8*Po}aE2x!mI+BO{Zxva(7wgh)1oFn|5KmTN<6?WDP7`oehD6XEKek+enHohPFO zA?qVy?{D5wGQJ)U%`~*8;4|Ns-bqJ%_p!>0*RNsO1njeBAc6!8~3=? zDlSC-tZSO}o;bX23re>B75-s|axxPevY$NNFHa%r#Cm*uOl0vAREDMkdm7dH)IZc$ zK})#3`a~E|LQEmOxIS4qIFk`fXf@a5$D&yh03i%qJUqPrWYwodW7@q=TQfq6M>})P z{u5>9w_@q#7l8FbHvJ=ngZ#m`m{=s({L_%&SDo~}Upx3V7q+7XGnYatV>q*wWV|1N z=zCfS@F7WGYN~f99g|h}`{<^21vZ1wuvWN-U)b$mWsETe6ioN7)MqkQ3JLpMdP4dU z>j}jDF>!DVAyz)R_dvZ68E-6Oy>>BSnnv6kn7-w~5IqSdsOa~P<#6+ZAYf9-kk*v% zXsV42O&iYu-;!2T1U)qm;__wEe}A5wB5eXzm#wGJU>6QmpV#r1vAwGa{1)`4ENWxC zcro7a|4*I-;>TDE*`bXI7eyzHKkfsEp^>@lZ(S*4DzZvS=Vz&$xSfaebe`YgTw)D$?$t z@ha>4f&?Rfk~9588*sZ52uJ1Br#MH!=3>NT6zxEAeTctt|7bm{Q zL#qCMUvWs4<>`~IF#z&81g~b}MWvw~yI+^Gc0f$T8!)n8X_Ev$zYX zONGxlU0m1sGt^vTYt&b@qm#xpNumb1=R}veCKND9*6&?M=x$8TPZZwMV9~jE__TPE znUx1693nlXAKK}~?e$}?vD@qtl_*@vf0Dpaw$YNGgcYp9ZBr%z(S7C5;DJDp61hM? zUpmCa@NJ5r%se=1wVOxX(ettf)oc6csPo4UWH!L(vaY_BAalG}2K7VD1}UnPcko(P zl*1n86G#xSOG^GiZW+cOkV-`s8hdAF)_1S3utnE4B6(j+Z&o`}d*3};hFTPJr|GleV5-${fi@4QTu9j!aCBS#a|R`~LR`v7I-1rQ zYR&F=JJH{R@M^~mEztc>2K|z=+02)ib^eZ&{<|!b_KuDcP?-^s`_^AEvms_bM|1M? zBV&^y$uFE!6uEd0h zrbNXT$ddPb1wvxLN$v(7K19y^>RYP=M_c{V?F~ah|MbH2%#PJ8MFM~M#yt|4Q7Li3 z6eZH;Hb-&t+E;EFD?l&3os*{~Gh2&SP{d}?8$Yj78~-p50_~5wt+*dMF3Y96R$MMQ z*#06KJltr0HUI02@)yahdND$f8vEmIU2fc@Gn=Y{+w|!1Ft5O59y#3T=fDx#q5Qxc zN`~cF;UVryB&sl(P4DPr?P|>9u&I0algbbs z;aA5Moeyu{7C+c94TCbDDVGOhLtri%!&-n;{znpnQ6edB8HCu%0JZtjGaD8iOkci-DP1#OPyB`^ zO0AS(KT6g&)Moo;fZ@L%ZP2{lBdP5`ZkkHd*lR;Tm81DetA(xkk&1Yp zi!BibhNx-3=;B|C|E>_?#+kq_1W*5D(G{M3FIJ&jJ8m3T6e(Z(IobzR3jg+0P(Tq~lEnW7`CxFLp4w@YThIP_^OjtF) zy`N?8Ob>2K<}A5%%Nump*M9?^FKyqC64L^Is{ZUUcL5~Kig2K<;*qUEc*uz|C;oc` z1O)KV8>%a{VfyYK2r+&ElzmFhp?G^3iRjuH zQP)Emg8oQ2agijeOoS?VgW;lbR(iHFs?2(F8?+K>L!_As0w3M!mU3{5ekliXE{Z}2 z#&4kJVdw+fagJPW=6m~A1<4SCVLV0EKSO$LY}E-|(yZaG&J=u}+N~=BACU?C=dWJ* z^`=>$a7voLAr%c4&;m#Dy1yTY2fJ;z6vqYbCT&LqKLN*i$AOlo;cNidt@2k*mUz#o zNe2nvvrW{B?Cj_UOHy*YDAYI}2D*&pJta7slAE_51;C`(!se#UmXehu!1t48|LVhe z=|aV%NMJ*mdpk@er|Jb-?J%wZ5s`;N9)~O??txXLOiWDBd4pi*EUvD~GVSXgO`ylbE4B?qG`AtL2-?3)tlza1Nw5 zhd?57z=z1;L+|q)DMZphW`c4t)bkrik~B1=Bz&>|+#^WE3>j9qSj}m+qTdXYk$6$` z6`k?f8<>ZIe1VbI*2+pJTjRN?g#|Oj6a;T`&nW+==3Z|&{rdnUPKb;o*NZW!F3tK- zmT5t#jbU+n{(kP`e+{NZsjW0Rknsx~4GK}*$_LO4v@5It>-@-l&X6?9@K4CsgoHR0 zC-i5X-`QLiRQc|1CFr6e2b_{3&3hD|JV6u|7JkX=fo6(RFHF7J={P9V3CS5-J|F@E zFoptMq{7?_DXRyh$b*YmIw1#~G52{+WPK}>leho%OkTbW$YqzM2*4XiC}-c%Ao4Km z2sZ$?y;5jpe!dwX`b2|QZU5hYG<%&&(GYR~v)z2GFa=KXQ3C;inV=9-Cw!mg&Afj~@=z;4w`c`sJdnq5 z#ZOF3lu(J1Cv4iE^;v1bVS5LfRkqD^D4pr&XUnUNAy>=V|H|p7$h<>8s9Bh z>IzhPTH5WN2Sr05$KFqLV`;00#1#vW-p>Gg!2u|c{#z!4`sHA|iO6NG=~v%#hGFz; zr_c=qSrE1qjPJ@d&>%pkEnP`TB#G&bAx z$y@0B`hMj<++hJZffBRf`)i-Kj8j|^uF`RCv=QAB``!~5_(IXul@|d)4dyaPD^kL4 zHiiNbewVML>+jEr1$r=FL>fv zm!^IU+MUMK=&YYUIu*I9Gjwx&hRtEv>G0Y7xx$!Rz+S;5QTL%JC@Dps71I=e%tK%c z6B1#`uxGeABO{Lw`cny#*QEo&7k#O-r}10t=vg;}5yRNT z#BKI1(K`}kbl&+Vi) zgrw-z{l&_Q?5*jr=OcOGBkv~T4QQ@5P!ayGb8_v;+=pRgH~#*YYjhUZHonZ{=JIc& zmUu7ImjS;xsus`$BY;Xo!q6^^5z0zSV?vUz+=aJ2vZEVoHr1B!=wyYq?_&heVMgw$ z`Ygbm5cchfq!QK7x~8-?9};x4<`K||zFQ2twCqD;HIYDBv!~ z)OZQhI0(B|SVq~3Qzl)`0o248f$$gPg5Z+@n&v;hjBOL~)OAZ-D>X5w@)DPQM3lWpD3b#V0mg|Mz&Bl>mJ2!ds8 ziN?_BDIupbOX!O*FpJ3y7o|V&@XTIg|DWMsN<)?@dGNlBwKoeX-*pkmK`3Rhqs|Q( zRRQH}Zn)%A|E7@56t6egEJ78^SoU1$#O#|BOR~ZDYfGkJ6lj z`n9+RO7-r3ufSUOCQ5oF!D}~%fPsc@E{t?< zZ3j~sadBZq(JgKpBu(?UJbVI#mPj4yyJ1@}!KhdMa}|}{I;(cbV=UFUG;ZwNkxh8# zcHSm5-CJpjSBQItfT)_iTQ)BEfGwG0ix(<~wifC^xDx8ZzPnrXIKFW9(N#`N#gsm8 z2G@#^%Wv(mDLncy%Jqx@{Fdtq$-K=#(gHFW>yBnT4smnZhEC2FPZn@!i?sT$N?m4~ zm0#$gbvD*c?CVNXMJS0X5Q%~k@Dt)oD1Rm^*=A;D zt`B^+vcD_%As`}2dd9~$e6o_GUayWgF!}oZXSL8L4XmvC0IaEeO?skwijf~1_O!3W zxb31O@*~C}sXC?v#DeGM=bzfyu|t`Et00A`tN^31{$K@V{a8g#6F^v$%juc1!uGa{ zjIa}Ctsh$M?h>g4B^xgp4AQ}@=>D~@zCA5x^?`xtu-#faJ99J^86TmMjaO2h*FG5$ zb9N&7HO|ZIbDB#Ck=;P!;afH!L8Kf!$^_hX?s{(!Asds!&zaRsWCAG5F@2}{5TfyEE7T^7a0aY z8ow|>fy_HoT9D6z@hY)EwDxeWB$GuB3kN3YQWQD?5W;Yf(&kBHrXAtck%(w#czf4q z{6`GD^onnc-(B%YeuRbQu++`wkKpl`Dd(zwa=g_=JX_;RDYQHE)6-e!F3&GPu@v7o z8`nrggG&?&Ui^ShT!0};(?6;`f@`cV*_~Y&9?%8^Y)lsWtbV#5!O)(@*#FGJ|J|cn zU&_ZJUk3X`=~iB1Q!|sLC>(Vu?qu4jN=ow99WoOm^vd359E?Wqh6mM+ry_yL?tENfuy}EyDW964Fs2g=R<-vT5ym}uOS&m zoWXDSBAtBSOFZIbdFZ%W{*xjGn~T$_&f@$R1XpYB`{t{vC+CkP2#Mj+^+9r;s`p5E zs9hl)Mu2`>Q`>N|Q3O#eQpEaQgE=k~Y;a_J>Oss${7|hrSB`Q@dqHaelA2{^F|X`H z_lL`tFTD^`UKcl~NLib@Mqk8a!@^<-jf`A|c=I&}=gS`JXU2SW{J~XRmePEl0pU%P zA6~HO82-V?@q+~)9T#^n#41aDgGo>@87Ph5z9$SqgP8T4CGvilYF?o(U3(gSW(!Qa zQUL1%0rNfNPww!iICN%PsD1rai9u!4|4}q*abe+2V&ZLB%yV=4fhD&@Zv)(iDf0D< zm8g3HZ(&gSl|7Mm@;hP*h3|f7MnQoYgMB@FLJ2aIOvLaJ9?w2iRq;Z460-@;nx)jI zy>0$rOj_7A`nW(lmvh-G+{y}D@a?ltExo;AAk;gY9a`u0YQ0tt1vK^^KGp*+BhG_j z8;qC}a0Q5k6m?=y*_Ya|-bjVFwM`4H)JfXfmWYZyE$ZwWQx8FYqCnn55Yu3g=U2%-ghn5S=neuf-IFfcH%nkWeb9bfS9 zAPDzfCJb}q2~m=eNCIEkBX$H20&E8MS8bS&9zRB5fBe`GY$+I8%C!^eqG5Ev;oVJg zbF@m`_$&_U0%Q53M~`;A03Xj z4J4x|2Vf znt_RlM9>OWyq8wQGC;XPX0%{3gjzu04j4c%e53#gU3M<6hwD+>8lgnK%s4pvntW@Q zoN>%CCq)wF6FWQ4kRO7fQUJ+dn3mAfYJ86uo6jXB{i)_Oa#Z~QKq$88rv)?}dWCBn;}uJ=I+SXL zdV0bj4B-{nG=S`r1kU7tZ98AV59S5@E08t}5p?wGs46ec+k5^u(Xu&L1tCI#%30RuM;a1N$UXNI&j!D0`J!e`vjr;AQuTf z7@0(OSzGm+eQoB^zklOSj!7TV{;;Qg|6(6&(Hs zbF>U0#C~I)c_PEE8)MP%0uU#S*Jj;^z#z&84^TWj6%(z^#Vwn@a4&6}Q4W7YS1))G z53aIB?_N0ZDyWX{yJISw7>oDn*nNo}e;^uw1vT@-!+|i1{;x9A!dHrR_ZmkA@ohxW z1FJ8d&#Y0b_eLex7-#{rmU- zZH&i4e@np2B4LY`2t*#uRscWUy?5_wJp>oILAHdW{^dr+G{UIZPW@~LdW#T@ z&Y(Sb2_Hcz1a2KJXs@519&8ksmVN<`8{+5y$3xnnCI02;y+X4S9Kk&3*;CR@A;_^Z)d-$EK1l-i;SxgoX zWB~Le9w}*Xb#*l?LeZ#K@2=sR!olYRO8`U!a4%r7I8C_Saoud%%p}O!JzhGl-AuHr zHGt2AL;BJ1ZIn4l^I<$d0WbsCk_FZTlNoF-N{o>ysTX%Y7E zf!RhXt3b6c%cmcXbb)o3z8xPZ(#wn5hMn23(97mlyKcP#Q|m+_xMQ@-tpih2Qw`bR z`7-N#S2iR>mM`$75Ji9qi7VGY?aJfChhAj<2Yv2ait*%4Du?06>$~p69q-VUhfqO% zFJVJeV(0@ig(Nb-W`@<;_tV`mI3xr=Bug6Y`X`SQPKPy~Pxz$4<7akkE)J9iN)VS4eW2-y5)Y~8@o|8XK>^up~%35UBL9VPA#?w5Y&LR`p3o+jE;_)a|YGW zV5z*ct39R#yQddqi6AL4K?GixnQgS6nkGH3dw9}Ya;WuPLGLv)MNd0Ph`&VW%6 z^bb7~m5#ixPn?R+CRH*}!Ft~Vey93KM(3!hoUaLoOGLJ0TzjE{1jP{!?98=VK#fVp z=k$P|f4p}k;Ij7#ufb$7HEO5s+;qnJJ^hcrjUV>b3hVCNzuyA&J=mkJA%+f!L>n0& z?=Lk|g1YF7rho)iedl;ZvH8KaHX-a=J_|hN_w;lBAOe6^9#ua+u4DR9_7T+4XwoCK zWV#+6z6H_ox+)1rCnvj`)mtUr=N_ukS><`7yh&^pJRu{@g8nSn04~N4EiNv^y#-0K zT&JJ?_mIS0T(~J-|GWLE|LV}-;9xybV5+2JEB^9Wdmeh9a53OR#Q^7i zjEKLez!YeWo;WSz0oyJ1)*hs1pR1pZaWQrlMc47gGmu#8{%Y)4I8t&87n3l=s z`eG)AZyP`Tg7Ws;f8X>!Zz2Fv{*jT9op++q%3q(}F5Bks>rSGa8)BBX8gQFk%ft_+ zXNG4d1!gbUAXk8R{za8~&V(%&j;@@k`j^w|NvN3rC!%}rA9LaN6LTr+Xfv?=gm*74 zD~pvnEvz*QW;CDxTZ(Q3X0f|Cw0wK*8F9Ep=iO-cL;hqru+YbzyomGNeSa4yZ|;O- zwGr1}Q>UfPW@i4Q{_P=BGInC$y45l@l>!PhR`5iMWl`_8Z~CF39$Jt4Kc=1wEPSnu zYH4l;E35KE&J7hydR5eFX=z}RaH>^Tf@7(gnXSueXPIeN;MsxBKP|2Q>ViAZ!7_%> zaFF4|3Lm~O9R*E9WtQ)J7F}A>4JHOE6Gil6qiY2m zW-l-MKE@p%yx=mc0@H(&H&kH{%Tk-MCq`f4kz>idKr zM>Q0fbi{mz!f1qG5?dt!zTh``c~%!k&t-QbS6B6Bub5;!QF@!*`F1433KDP{dUFCq z*+2LrI3>=Bc~S%>Eu}p|9blPnI~m@x zhVu@{3olzGRT}y}Oxp9`_^L`t^I!En<*iOppB(myPx6?UbjltY4`fdaSFyav7MG@c zuRKu~=H)pT!UH*ewZ0s8Bn$=%$RtBU&5aDDg*-S9^JZFsC~VN&)V^_rA1v{Obr*b~ z8d`|e_x=lF0pz#?Maaz7R-q=T1eOT36-nMDhqLXA%Ah-9AVLfr1*-)ZFPkSOlAver zgENRqm59V>JeQ!DQ3J2eea{HH9>U^4qAUS6SRfU%)xX{8RuAxjXdPm3F@POT5fmc5 zD^B2?ipCW_Q~oop0KaHBo+FA7Iu0CKW@cvBgDucLVyu@J1E?9;e3V@2SS(el$` zhJ2Y5D@07nfMi{HKub$o!5oa|{|W?Xh~NzDi16R%py&oOieb*nFcS%qr|_w@xIj_7 zIaTu!?nlyNjnFs`Pa};wA!D=1?bEF=uaL@0UNCWEX5a_2{?sZpMFg5vPAd&iKR}+> zJp`cxm?9|UetH|uOK6h+z}2`r{OCIy+w%U2!1UqqTE-m%XzxZKxiSpi>JBgh()^!Z zwUpaY^g;B9!QOq+DYv=s3iyk2B>^l4zw&4JJ(z8(0i=k97tEBPp&@$%Q7{gW$`*(q5{R$)*IArHO;})f_mu`$kwrS~y zJDl^a#9m=7e17dio!X{Tlj*X11J~}TcKHQv;XjtqDV?r%(;;Cp0Sls-E+~W?geHFev zmtrB?0|+u$uP_UWOrVlJLa0pJ?B%P@a=W@Dbo^@6G=7{*hp@qMPCzY^u|sYc-#LJ88l9?=YTSrE`BhTn2n+^v8_1VS(M-+bU;)ny+bcauP0w*$j5}hH_Us!}~0>-h210H(82& z(g08bS8*F_`;8qIFv)t(@4+?4+m5C9?U5?VU-1YpTJqg^(kLM>pD)vAq};l+J>5;i zySI?2J1x}2q$mHo*vMEy{N?(r;d0dbwhCzaqM_VoHR~poXi>{Rbpm{4naE?LU6XL9 z5em#=sPjPNH_usgxtd#;u_1?HFuUOA-v2ctnOCf#eB((C$G^|R0_MdAC#hU-MG42i zK?*Ibnl)VHBBdVA?YD3v(Uq^O&>|@uAnSvYs~zfY>t!eL8zpPQJXxrTpG2*n?UuBx zAtTDC+<{A_= zNpjWXprD{>0Ae@1xv8lLB$jZ5!QzcAXTcA4t}wfi%AMTF?<&o|6b3a*<#cIDiD==l z93!EDGW0|4mpfMdwHg#$qO2L<^^1~*BdR{(^niga7>@kwATtKT zxbZUQd*6|RHMxeNd|1MM9T_s&TZL$^d$E;GQ4$hqa6qpwe*LeSwT9pqUJy_LrWQF~ zi=QO1w@B#e24$pt-&D=W!RF02oHSNaPtQ}YOWmN5kY^9SQeiw0X(+d8I$vk|Q;VK*PP; z$A-gMxPP$gsP_x&+Hh|CYMLZ-b#;YH76K69<;ytQs~94E3FP}0fB%lOY{-cn^40B9 ziJskKJ)ulJ{)A>Ing4F7vBl<|>Hg}S`Gu4*yh36F&h0z~8$6#h)6w&A5eMB*u7*&A9|$iOiINLV8%qcx2fc7>T3A6_lx zb0+uDvoU=8nE8KNb$Sp7HcU@b@bmLSjI717)9>i{VCzu5FvH71>07!VAM)|;eI6zx z$+54fs2?4>r)ESgA3R__z%bj-9;n#;kew~L>7Vsue_DGsPTyyAn}!yK;$bJx2uCK~ znLgXAyJYa zql6(t>5Znze_SLT`v*e)gfj2){lG)dujz4d^onI_#w#F~&-GYaWEl{4D%v<2H zC@@?ft(3aAu*L6i=E4_8M$q_!Frl7N?lN7?#*B79TS39hs@a*X}}x#o)K-&;5@ap$nozH_~)i zzjazDo>qNn``6f{Veh8y%J4|Chb?!r%SUcL-gg+Mc17?#zw-$amjwm(3@vVy58nG2 zzqr+t9IGd3V(NeRhuV6yCK33qSrDT@fruYSDH~R@?d=0F9!R9r))PhUF`_7XGc!NS zDS%lid%mdo8xxX#izPMYelJNQ%dBU?{ytf4^YN$m6HDU*PV;3kdQRWwUS!ADHdNt9 zcLtL^AMxS3^G2~OIet%6Y@JylNT6J=kgjOS(HIj`^|*uOy1nCEyjjX;00#T;sz@Ua zPkrcjg^xB#?9vtFJBfNH1S*dDY3UpfLwKU0hs8UNIVkKhQ$1Tqh2P#$iC5+280R{i zvfw3+{*{=ku>7C#^beQ3*VQyVL%A=~n<+#>WHp#PzYz7G3^a;=F@>$=!Sp1^$KETv zRU=1zWWPhpF1pBF&X%Pfk}pb1OFs(K;$=otU4B$kN)}B8hA(JV9zhVF z>jP|4B6si(DQTX_qG*(&1OuwS zP?!3Aj0?qXJN5f@lJ^Gj3h2=7Cf+-+u^@!zHCP3ZFaCgm0g-5vl~oy=efypMg(uz3 z_HXLX%Ut1#bk!m*9#c^sicqE1rlSI(CtC5ue9Z!0x;7(1t3+c1P7i6+I!HQ{9G10> z!&^9ATw1=_=%6BiM1q&`2Kt!a6;%1GKPR(Tvena6Z~t3N#C@%AVk)^1mUWK?&V>1K z;9W)`mG(U`0ZJx_cdg>1%+>El;bI z99~#oA7tt}uh63?IK2xTX+*+}q2w;2RY(9(_A02E0OE9%ZVRl;=R*0+vuBN zvXB?Du2RQN;gTB?8=2`_%1C-QB;lBaOEfGcnV^xVb`eKM^806PN^kP$Vz%-ckK5IT z7$F?&2$X0693z`CbJG_pD^Yrv-p`c4+7EH*RW{WZ4mj ztdEs7U3^bkUpAMw8veT5s>W*9JCid^vp({xW{2YCV9s6gX`kol@mQ2N8(@cG()&sH z2C8!-OYN$me4+@wLbJmK`>z)ce!WLYlYc@4H;#UoktJw2v)a2zWU;C4b=6D0Z%Lhp z3)L?FEU}AP+sI61dsM#K`*omh@!QbPhlJ%W%*1pHN))$e9oE;^m2=dg0h5~g1wVN0 zG!q0hGe%>)ob65)?>-3voGH}35wod4TcLMcET`CN>Fz1EssDSp*{wShxtM=h`{DU7 zZf%80egSeuFj6c(n|O?|_OeTS!W zS0%HyHxo+pi2Km*D*WO`i-(SDs0eLkiRDw#xhv@hoX1~-{oF?2ScC_QX#Sw&{yVeX zbB*)v-Me544nmlzoqKjy^WTqO(Qo>xCkX894U|W6XyOL{OQ@2Ok~n;LxlDVr_JkO^ z`*4pFoUx1yuO5`Fku>G+TIfksGG*~eJCyI9%tj={ce!4(E%|5uKucSYR?^b{_?emb zX+m6L)U@;H^M*S_+j9=8>}5Ds&y!^YSMRw6|JWzFe!0$(t#`BQ>{vZt8~<)(Nh!Cg zfR>h9U7hFQV_?ymr<&6S_N4&_jPO2YkIBE}EtkpEFdF@a50F$?&Eu0(3f5OnZNq;Y zt2*Vsx3^zO2@tbU zpjY!7VB1}Q6f5ON@-3W_9fSbU^#cR5~{c_St1&pSF-B(ssAb(7XZ2N}2v1 zXsJ^%&nVeBOCt^p^XA-kUMJm8ZRo;QocNHN5hT%w%LFGm^w;D^rMbxb*jHh4j-?z+ zrAx0@X4g~;Y!8LHO7|J|R2^}>&-vqaNX|yNzLJ$M9@|+N8QX*?R22NstCo%8P6QNm z6o*Py9q2Cvo`xbn?5tMx<|h6l6vx)Y->IlD8AyZJ;`!&HoRfW5*(){ed;6n_Q+ujs zU%dlcrY=?pP@#=ezYMk$E5n#Y#lS{n_#2uY(wN7(zk!SG0WBZI>NG$((EEt!y++p3 z(p}fMnp5IO@!G*5>hNygg_He0+?b*}p6At9yxL;VLmRDBp=)>{hru{weY)Q|*D8^u zq_ng+nA;qci5JFg+DSM&H+KwhsyRe&fC7|~is~(}AZ&mu{nsQ-C2|r)huMyNw{DpNPl@unI9|dpKdL59X_HEPyqFR={{5RE$LU~J%twPT z8xBr6wVME51)zOYEb6)>C$r-3uMXF#Evzt~3jU@T`YEcd?2FV#HZ@9e7qC(Q{3;2Z zv~unsEaT|Mx>YZYj2c0mu>v|EDx{b1FVxE%`x+9bQK&ax3|L{@V7}b%z(`HkO`Lga zbQxavJEu?Ik$cq0?60bi*E07w0{xyQC-ci>_hB$2K`qBmy!3ytiIKQO;B66adbY|J zoMhENxt_j~?fRSdDQ-Q~$!h(r-q^HRMl{fHx2$S*V)J!GOUgm;=5p81*TctNrzU5X z&wjgF5k_k(Y?RylJ+QG&dT!eljdvUlu`uIXJpfn&gAdDI0(v#1#|Ic<^s1ru7tFCA zPiXwn>vy_%0xmarW-F{|0Bmg#zC_p6hI8Qr-5$UbswM9$Z^j1hm1>vmdI6XJrTlwS zo(8jeiKkq^D-(!g2m2kIJ9m+AxnPD73$a!^iT>9YDz(CHAFY#93Thv(lPtAbG3Uze z98ys857f6dC;S*-T3oNxNV8fy=yI>CB)O|#s;umgLDximd~{^Lq20Y@1@1j9&<21) z1TOFZVDahiONA4OEaA4?<@LN3-4fdTJ%)#2?kBcwNM0TmXNp1?xp8aD?J|3`v21gB zh>UbxiI~u-*E(zvdA7>UicJ}$1$W)1gI((D10n#Xes)P|;io3F2PZ!tvFE#rGP6>v zUDqv?UYd?^C8p-mKPc$&<9gPMGOu07y>!?5(=kwoB_#o4KWR4`3Sv^si(!GiSnxz5xsr{=C^o0 zXP_FnW}#suBw6xtHPb5JGbBv4trmBBrP%uRxsJ!~-_o*Twp>DCAC;QRHQw^$=`Z0Q z$P%Y*k_+QiL9SvoS!Lk4N!qx2)Hl=nly|(A6ycw6$9{pJW;SDHg)^uVFtQ_k7seiM*;d*!dqXc47`Vl^bf*opA0koJ#$O&S)20ExMF_c=2n;THtO& z{UW(ijby&Y-d-r#g!T9>8})mS=oAe>IC7^=BY+en$`iG(69EnH&5*g<-1V(OT|rjW(v4Ca0|M*nA`%iTmpNs{)m1UK z3V0ja^tAM;0i^K~aM*G2@e4xJm5ydZh5G-&z4hNe#{L-0WCTFtvz)X@>?e`+-_Isi z`=U8{B|&y|6=CZD^<{_G&M+*I2Gz>xv8PkAYn*Ou!=LPD!JG442Zt%`hbJ1>q;}Q~7;ow5In?O?Wre7bDAGdgf*L_4mnx_ zIfjix;WmWBnfGalSKQK~Y@Kz@XKdwUzs6AD3Z932KRKT&|D2FCsOmt%omO8fqvD^D zkJ)XsLqHSetUk{o2cF9( zw_cM(FQ(G?F@#{YR!mc!M|6S-0Bfn{aEcn#K77urtUxo1Wqo-96$1CAa#c5f!)C{A zz$RLp4ot_}xCa~~wS+Ts)W1z=)eq8b-AVa$(KI}qt#ai}b#ZYv6H{9iiTJ91R*;~Q ziU;7z$#7-;IrP?V%K~-MZLl{Pf!+Xi?FUdGhCy;7tKHO3uU2ay7C{%(_WCSs8Lm1a zP-roX;BH?HvPM_Y(F%8FS^pd94x^dBc4}rB|y7O6y zJLT5RJNc9}amC8oA|fKT4!HE}r&$?rBo=`b!!QJ4cG=lJ??$yh2_um+Rc1xerjTcM zbwv~EU03<#1-%mZ$2nlh%K!f5KIKu9(q$%gJbT#j@T-}Tb;j(u;uOwau5WR;^)Bms zw&WV#SAqa)i4si@UL#19Vqt?*5ff6T{(^YXiQ)+TF9FLPzuFh~FZ$pS(EfNcrh@y&V&1UUu{{RntX#G8m{x z++FsCx}ooKyv!e7TLFCln2tIebG2oHCeU4og@W7M_v}ws8H3l?qX<>u{hq-ehnp%0 zf*W>WuYi=0>V}-OQQzW6(yIFyB4VyOrggoav>&stJx_4jc4!$N4I&9|&pTxdF!1I| z@d$yXd-t$|FXDjW0V5NW8M=6s4#ZM?g#)=VtTlw>T0M!~&tD);yMc{OO;1mMc#0fQ zpneJ_tWrM|dvZf=%#hb9Y zD!ru5Gqw6;u}k(n&@yUZ6Er{y>VX2?@%qtwDd0`2=%|sI0W1o}mb@s~E#{!eXfxD=xHKg20m#5lFa)o{c9M|I@cm~shA7V+ z3$O3TR8j>?ohMwoMMej2Fx@)x^mB%)!$}+uUQko9y|cMEBpm6S`#cQREJV8sar|OH zn-=*j012E-bx{%WB!tkniqu;D4t^M1f|)8?kAMV8M?ZlG+#T>Wx3>oZLz1Qun;*{( z3$D=T8prEa{0NQ`wm;d&X;#cr9$)z+EstNm7>hR_z_CyZiLWjwnU{XR!s+Z|PFV}n zufQdV$gBZic{!OwO>AaXLQO3*R&#B9DV0O{ApIv}ck&{r_jveSf2~#AG+*D?6DU-W zpLeOd7?`Md9>^*h@X8bbWoR|7y-D>x31l#_7JMfCf+3Pye||Z{9F^cUwzL1nABs12 zd(-p>ddI>__sM^>ceNRZP6q!avda>fE_{}IA7UJq;3bH3FG^JtT)R`V%|AO-5RI-( zpRQl$?M|MRmBj&`1Ex#I^f6Pvm_Z=uO#S?YUJ(=taYW`_{%ZuF`VI8PQ(k)tC`5{f zh)NTc(UzS&hR(^FI+LHvbhovre?gEu%!(Y^Qg4$_W$|q12|tQYnsmK|+?PJ1_l}Q~ zAQ|5CLT1AD5B_|-AGx@t)INn0-jw{Qb4ob(L~0P0ei>)V2#AISyze#j+ypp0ef0PdNGB^<_hG=3Dlx zqutEblQBL2UGiK0Odi`d=jGh;9fym_mSKe{tpx zH^h55c0lk^36dZF*2!4?rzY0&UGJ`eEJ@H(QzfYF^jtWI^NQw@EDFWL@7!WFXNQ}Q zWHDZ1;oyKC_u*lfofiFttyC7P!yJaDQ4v?)5!W*2PkoX$&E_e!Zh|a=0>-qyKcMwYjCUKK_Q7gs^`u-8Qs4>6>`wwtRn-PtfIli`Spr z$2G)Nzc;3^x~22eebii$r{iDuZe_4H8nDMN8o4quGL!-WXP=F*LnbGRRz}}7ZPeW@ zbz|GaCLpBuq}UyqT@bo8e z6>s)oyjiA^lciOm#FBxn!^jy`uUB(}{FwZ&T2^{U$4U%EsWs7U{T>bE@!}w3U9F_#V7#n0OcKum1+r&jz~`Rq#l{20OqoA zz+OiIlWDZQ@3fN>@3lSdu6Mq|^46%|zKqMLIk7ALQq_nw-*`w#K(C?-IEsEe;?$O6 zoj*#+Xjeh!Lja>1pXSn-u9QT`J_|qxX^A}lYvQcGTj?h~w|Qah7)yyGRILgo07sC} z&H_qjcNjn8zLsBs6Y~)o_*OqwJ|D-p5HnHboS6`fXQLe5VYkYXZ^p#Z^LGY^EKj!G ze6#O!tse}Q2+j%(M~Yi=|8|mA{SmWH8x}6hfq)-94#-ey^l+;_44)WFy^qc50@Zj! zM|bxk4B(xes__KfXo+$Aop)Uqesmdo-92W6#~oUrSIAkhZf^OTf0XVjm?w{K;r)Oi z;97<6;Z*;w!Jkog_9u=-2 zhRc6JI2hxgYiaO}jbX=2{5VZDXL$wtUsnhXei=|^N?vD-DaL?uSS?8 zlIo@lg-ylj{Pgma0<(EE*{Ug z(c09;c?Rp~*wLB(%MbhTP9kuT@;48he%czYGsZ8O5>}agpFxW*u+PV#ub)>fEZ0|X zd7EoXN8tXs=2<&dxRT#vR3wD99a`nX97$_J2t3RjULz9r767G71}HXZi1{B0eysE? zC|zwL`{z+q%DNbtQv1(p)^xj^Bi(Bi==n(B;`fA06SumR(5@?6{4H!o@!4@ zGayQ{@@fHIj815T?7KB*HOiUkiuDT(kVYJ(ihxU?^FnehK#ctXqWthZ<)Lcc?D&f? zUAF^?Q2%V!TcT2&?ITjW(+Qmm_2ZSwb*b3N3g!RSPg9jsov)o(div^E?IUbZ{D zW{;l@7lh+JN>`_MLWBC}Lg*a!d@5wMBHjQLO!QEpYSuURB2KlbZmMPEt&yl9WsV!l z66$f|$M>|R%7vk|;CSCP!o@B5k{+PN)b-i#FMbY6{&88U7Mpo8Kf`jp9XnH4Rs+H>~T z-cKY&G^xrLTf7GAgx01l{3<>=7dPFTwFnLw5Ey>26k|7in8jw^o93mT%gxnn()SQ$ zs8K*AHbvs+i@$My+eha*L%%AJOIRkx#%cX4tlZqDut30NK~FALIJ{RU_t)uo@j7GJ z()#ws_(;h4+__tEC7tEU8XZpFbL!`)ZmD;E&cBFLwIF!cq`Lf5v_w;9JpF+G^8nFs zE|@jo#Rd*E=*E*^MiiV;^g`aS6vUpV8XP5Xyr=s*w_yG&q2eOUorODstTuhXeAXhY zx`r2+tb^(4Pf_{|(F|tydq?7;sHJ31rZ0mY$x)^hm}8{LM(^!UFTKZGkc7^2Q{GQI z|7&2w>rOb+&g_?Ilb6V04O}0crvYQ61}+hy^V)>H7TBvw4b@z&_rV6Wsb~Jzm&7~yk>e&Uk%nP^U)F-a7Y@%6!xIP zV}2Ko1Y}pRGMGI##%8(p^)R1q?MyspC^wu@n6yelx}2G=M=wok=>Vf@%HoJM;$Vwz zZj7s;E-C2r%jA#_z+SRwJ z>Arqzdb3(l_UrvJETkbBd0YnC4~++ol(Lf7uTa(fpB8{Q^6KN+w&`%c@iqfEocsB= z@Xi}?-}~_51NPlZzwIL*a2BBecjE^nQuM#}JXfpETM+CmjJt7kSB#b`XXyJ~^(bl7 zjohbpp9U94pimwG$zsAh3 zt7w0>T^93L##hccn!8Z-f2$fFH*+$`r2h451}U#BjNZU9d(<>1gGT?p4WEFZwdhnz z0|HJ$!Ipc^BhNZN6u;HB-=f=~JPBJO^DT_AYWLmo#XlnpijL)# zKew{&?R?%fOGU#gdr8^e8u}1|ZZQTJn|Cm|uRzH9e+*rM`YOlR`)J?Iv(xngwdYBRuDab{QN zu=VbS`uNWqa}3Y!b!!IvG{#iE9{wRUl>!WSt!>#eW*d?ZzjD~t2%q~1{E7zBNMTDS zjF}ohUb^4O%xfC`>6YE>{u@hM_!dmDVOcNXWkLt`>993TPEL(Vf|6VgON5f)2Sfye z-n0qsY%D=ZkC>P(+^LMlBr$6t0<8La(@j#st=6>5+@SD@P5cFApfcQwO>Uyfk3ZaB zG3SB8+7^59OL-a1c>@Lv`xHw}&R72?Dj<&h&8$F-J+~?fOXcaxz6WUbS|M_>*PIjFUZiUMX9U(fR1t2kk01G;d->VywGdD=Pre4GlzSJy(>XNMrM=6SDw|Lp}&cvkqgi+QZ_~Rn>8jV!o%-{ z2!*Ek_DD2jL>rVK9;;m1$tliRZ{w<$h=I^SIqf_DolB{8<74oYEW$JK&B=LGTU-0$ zhZiviwcz2MKHk?nq4x(#K`y6zc>&ufAc-S(nZjEn@za}*sP^muc01}QN{lo-{7$gx zxh*BTqL3slFcWsF74i}hHZF~`IC2TxK-rlw3VGH(M(%8@0?{ZJgbxK1pIf%!58u0> zT?1(Y8tJq*NpvOe?f$QKD_oet5A(vTOWcHsZYdx=GVG41IxG0!vUICma3J=Jh$F=- z#T7s@Y7pH4;8IDP@;)TqzbEz3WcbtuI-R#k=y)PNOLiz1JsfJe+=+18TkkOc@_BNb zb3WW0dD`3S+7=q9V(q2k(2fHiKR7?1x!Pqz^vj<#RY7nNs(Rdqlek&QXNnd&bZv~n zvsAjds-u~g7OD+I*eV`^^eDUJBMQZLr+CRpzfyV9SCq%KiV4em_M6&T5?}*-^4NV? zae6R!IbOYY6jyNJJC_P0mU6ABJ_g{)-6?J&E@t_onJA<__%4lkL#;|+az88cbrrph zMVV}wxz(d@WwCeUREj@*x*qYVO_F=GBL4K0nk(b&gIura!smJpTY`sETckW3)4Yc% zjxQFyL)}|L@m+4I93rzHoJD}hLq^9Ki~=nbvN*Km)66H>A@=x>SvPs@=v@he;*^3- z7i;g&bQA(Zk`cm`7oXv|qFw}t8orTg&!4{ec?aK{yhE?XyvpU~m}wV%?JGaIr*ksr zoBa2Z3mST8Rxu&;*{w~t)+-)Ls6FVHz(O>^-a#MKuvz+?@L#jg*Fs?hOGV1fgZp0m z1=P8;&Y91|av4Ik1IB)Jci#dwx3ja;+)V9yJ;mSl`TH7Y54vf)68oLHEc5(tUP%sR zO!aPQrjraOaJhW<<71VaEgJR?o}8>~y3geW;90$SS{&eKaF&Y?Xp$G2xby1*`w?m+ zfn=}5NA6-{oY08+IF!C=5>l*DV51(eG?!(0DS;a?3E z*zKvEw3nSkkA-%wmVc2lx@=JAEHB6RR@||VaCN05SB2C7FwZ(}PVmBT?~yVqf}12$ zMTbLSkK-N<-E)U|QT4j?bSem#mWE~zjHQqa*bgr*$jQSS zt5ST6*E6nqFUeqP%K37oW%zRQO>Q#IB2&{jLQ{ex0C88DTD{Fu6AW^~s!LV;7O|&u zbo}SvursH25vqSEUuAb!8vM6$^{oL!J5S)rwJm-A;U}BpyVubqz=l;il<(kiNQSys zlY;&F#1ML=gGjnbXCH~IxfcZbq|@=CT}EM(WoIA{b8vR1dHgsOR+OOqnW%aN*joKv zr(egyrub9kY~?MS+?2Et-jp$qn$eg}8onYx*w=DgF7^u=6)BZ_Kw?(9Y!D+!1tJL; zsn+}-Q$1g6C~Rsk6wi|$eGD$MY9A}Z4hq5*Xnhj}t zO3S#*vn639JGj(>k6dS)fNqW*m2LNVf#&kQz-T3#wnE5Hv;vm3fe6Y?fv%a9g2qQCxxW^xZD*{X`Zg}^71`Wx zv($74`}%a93igVu$0spSg>~FabokFU9f?KN%af8w^?c5qk(8G8jg3I*PUC}e$Mw*k zSZ^wa0%Qay;|Ds(W!;PG+*P9N0a5=V5Xw2q~Ep`$SJgFKgBI z&8z*95ANT)Du=TBT3p(=Slo&eCV@{w8$m!U>+Ns%$R2r1usTVqaS8wR?wK5 zMPE7#&chqYE-pi(rgpkq-u^5nBVpvTR4Juar!TrX+svs~a#amCY&=HIsw}OB?TfDp znb$2*0a8foAmlX1`=BH-^JLq-;5$WU)f`PJ9vmEB#!t z8kMbfjrTJ&vDe^NWmobB6 zv${EDP}L?=;(uBGM_*;w=uu!N=DT*T ze0gEB9P3fzxhh;v!abo{n|FRu$wCt%$MRFToA?n@nZvnE3X(kY;Q})F#fbIKBt{qH zBH*ZFD(h})dVh9y=E-OFEZgD61CjF^b24sL#9#AujE2f@S_q#72(jQM{=Gzh@E0bL zJb5y^y~>EnK>TvCdlpA4S%lR;l)cL4E9uHA-ILcB9+G><&PHB$`)l;7s`gEpg-nO& zxa81J@|mY$i@SIgc+a{a=SSxy^9VLo^(Pnam4j@~S#Hz)K}tT3%|E zYV&M8T-sgmltlr#-^Ez?vjK{VWSJ5JF7jQ>iq%AMkqfQq}c39RXA zubz;l$|OpfgvnD{7J%tD3G`1y+WU~a(*}krO$e5?tJ&9xKh0KWfXSTS*gH>Esqc!Q zs*8<^NOTUE^(#`nnaU=-p4&fr|4_W_QQyk(!iY&Nj*!x9nOAR|QB-1!)s>n!fg);2 zOPRCx*|sp%9Th`Me5S)&vY<{yqSPXXuK5lkI>O`QEi}2=*nZ7ZkV!!*A+O6iA!L_u z^hx<7n&F9pB+4OriKUiu!Yly4fJlwDc=0 zEBm_y3~6nqysRu1U-B&}saDlBGBPq5Sq9G-0!W^RNvFt!9?e=WUJ#pr9>@X4FUY!+ z;ik8gLvs_0zxL0XFS`D023!0RVz47(+voCEcmArqX654kHU&+x2@sd}fX_7s(-sm( zGDUu~h<)%AVA_ArS7FXJX^xwl+667oGJC)txRZEkXO3YETIZH89o|Ll7pC zA^EJ0mmvtIQL4OK{)bhU{G*fF@p8T{SLsf2#5+ICl1uHU6Ff?{t4tr$vcLO)#}$)K zKfkm@VtYHmJeY7`jOa}W-CQmQr$Z!&0S!z{OpYEgqJ6KZXa(KjyieyBc+)R7&CVd@ z0-5{=Vba;3elSLOMO;_80>5resfpv|rk>cWnUQU9o!G4F3N2fu31|mMbI0)W3f5oDhLa4T>zevfar*#Vl&b zhBPx<`i-?$+s^!w@>{rKVbQTVy8hKvx)aOxd_59JBienZrLpjkv+3MIuqsYGslB}L zgpZiZ@q)5R_k|M9EpmZ?bb45*RaL`4gasc33zVnIQ1!MhJeIo6)r@RDFg~mdzJhI5Phgg-kT-Oc5k0(IR0oz$jkGLPWyUOfTkY(S2l|FdPXBAZ(#|^ymhp^?+R3beZrD35m{X4KD=h!bS{_ih2)y z6wKY72e&-JybbQ(v6VwUiSpCpQ2nshy{;5`!~R!jMcf>wuUK5)o=s$%Sq8(~J{QdF zLoC;zk;>&ThS^4tjsW2$w;=xd=eW_T*+88EF(HY!@bY4?+6 z?KlDSHSG`QZ|%#+O>`vtoN~9k(AlLUBqsj-(|u19WXzzehw*R_jG>(T8Jlu5vaU`T znYnm!5~F=7z9dN+thf+6=kT+)kk^u^QB9p1TB+=-P>eJ2+J~E5Gi>W*A;K#U&nN2H zw{4jtBZ($%wS%JtDfOUsN`T4lFo)wCqcx~q2?g9(!68s?={uA8V~6!TZ%U|u z&Tc8wr_+r2y_;K{MF`mj@&3;{#82eDNl=`eidM7z?WcS6E>AyWEddJ>HK%zJxj11I@!Lpf1 zsK-Lx<#{2_HdB+BF&t;XfUrTBdokD(8&3`jxH(;m<{P4|hf)K~lJp~2u~i2wkWBZm ze;$65;m-W;issmyNAR0A${gWTwv-QQ4 zdiXz@+S=$eHD|3y|F5_24(GD}-=?&aGD?I*$P5{Yl9JoVO32KL%&hEaP(;cqm65VH znHiP6vp1EMy^749^XmToe!t^6p69RUkLNy)`}jDJ>$=|8`~8~d>pX==i!XoUrtmef z)DT%&U{CUfGGxdVq|yQGRKJ&+I2wJ&i@xN;4Gi3Mjz>VNh?=_$O5z0D zyNM6?g9J8^Gh!(J!Q(@GSvG@bi9zfx;i3yHH*6lW3Y>oY_Ib;A-*BToop-`sfqf8y zu;s~nWV3X!*<#6BPunfXzNTCArI~Z?^D}FMQ&m${z5Vf8TGX=apSAEM_P3K}SmPR3WEUPt%dbE8!A=72pA^Yp&N? zaAU1*ba~B4)9xq)*i>Ti0vs=8Dk{x&bFDkfQLgd5qwUDEGHz&V@D#^QFVk9xA5pSvWjdv4{4SqH4L0+E3v768$LJOS0RFeY;mf(g0+I~xj!fe>HXUwU0pbu=>^WGQ8=eaKA z_(3FF6lTU7!>;&RBIf-?Lh(AaA&FT|rL$V{%l9`y`tOXesTemVNd9Qe9U>NAIX+&O z#o{bO_mlgrtAbWfJGUP9Brx3IXk7;{1FSpRlAqw85TZ$i+=Si_$vVV#het;TvWg>; z$#q}$sHA9UE_GILK2dDD+JZ;fZF{qTo1&l`MH%DagQU^z35R<+!jG1+{m$1ynT)gAM7~XWg?&n?=eCgkJOvkd`**=<`xpj4Mh3YI#&^jr0=mAQ~ zds?YCV3LkVxT>K5SgxC>#(Bw~mh>Y^-L>4UO|7Kx7REHx*{lEPT=ij};D82Vj-uU- zvlfAs^NY_!v3(DBEL$2VJ=LdLbrDnR@=Ai3ZFze;4GRkkHxJLXOv7!Qp}Y0<2X~(? z*&k!=j0J*{dQ%sKkAP0itKa=jJ^4jjYsAe`A7am+zjOJE`MZEiYK#Si7gM8Kxu(v# zdCQ(-jO|U)bziMIjq4czmSwoiHszWla!z8p&P)9Xo`&Y&!G&fSrf(x775BF7**l4h zffJ7Wd!*xd%eF&@4k2qtw_YaPWV3x>+e242R-HQ2Un)1ZQHRQFkw^!GIr9Vx$?)PS zxp#FgkWZcw$ux0zUb)wL$Uo7xqA@Ge^Uob()(0X|q(tox`hUggZww#o-y)f+PWUB4 zdjSaJI&LF#%kq$thVab!z526-AFH1PaISA$el)4(XXjD4Ryc{l`TW8{%0q`_FeI3C z=CxS5X1wWaL2`=Nk-D^OjW2&ZytQ5(7L2*Ta>>ay*4wBeFz0zlNI9ko8(L!J?*_Su zpZl|JU+I6Cg?PNXvGMUn1_pQ4-PXc=79KnN+;E`q?OX`wPoaTPO8vZ(>CS?S=Y8x7 zI+n96c*O6T_NShdztUQBf7QcZC~veq_jb~In=*@zlyBqlQEbRmyb!_hqaT4`Sk4i5 zsYiwJ;uoaD>FD`$^zAoi^IEyPs49XZ=#An+)g@KtVP4vkqBW};=eSZN4pv2trO|1v zSvCZ?6dAExak-%%$Q2rYoeeSJCvMG#`6xy8lgpZ2?%C)lJ_psrAAwWqE6Nt$~$ zyICId{@+M&q{`OTx73xM-Bo^5e z1NqFt%KCt4;eCm_OuxB0$tUJC8EGb~EE<*` zEXtgrMx-%sGgztlqPi+4LDNp!moxaK?#IOPBOarZYwFv7{-lFH7j9UTR=TJ#x6aCX}&Zn#;1Uq}Mkv zaO^(C*{=|ee4C$7>%|`BPRYfUEGLl;1v`be%_pHJa&~P>5KK7^y=2Np??wYil;Tpv z8)J%9#G4Zj1X#{`?v`iXlyxO#DZa;9wld7!!T6y*y=q9dhWBKOO>gzfXAJc7W@iqi zG;nz)y+!sws1g#29}A1}VqwVi!RN*F1@X1qxzhbo>#c|c=H})kV^t4OQQd#_N;`an zTH4^}_x(~at+aiWzT1q%)NS8UFs&4op2w;3maRKsyqHMV!4NoRtm9))TpSx#<*q~9 zT|+|=@5fX!qKJPD2nljLG?<-;Yr8Jb=*IFx)U*MVJhFc_H+Esf6TdAXs6%wtJH2W&vWo}*+*Dj;1;p7muv=}mM zFq+og`Sa$Z;#k?x3TiZg4>0t;DFS69~B8tmmoLIVC}eG{ngTyz1c-uL0*i>j)W z@P$U06UyURtMv-A6c3j)wmXPGjsN`ihX-jSv2Co!g0p}Bx+qSsSpNKFSOc;}$ta)o zo{~y4xsT5c(W^oB4EtH9l?|Y75V*M(Z%$Aybd=F z9~K6=&2L`0bZI;Ac&5lmbUgjuAgEd&{IkJ?cr94FSn3g-4G3{Yc-Llm1G;Y=i$pN% zGW7gPigRUN?VwXdnKY%O?c@4&tA@z#|H1+s+Y}A1uMFNbb3IogKQ;}R0Evk)0k?)WFsP*+zxxE2xoP@7FuRk?(-GTF* zw~nEE9^2JJ(at|03{Fzb)po#LIQ%j@6`W(}XTxFx?X^nby*9I-pXQQhX6J9Pj)op* zX1=>^&%un_(^^lM&OHJBIU*uVh#T721jfgkhE}m+Jnl_G!Xu{vmxqX6!Z135gYVv( zb$N>Cg>YA}lgR6DLxU_o+Oy8bQbh7G>IIQ>7Zi+jFUXG{iIuNN~{iZP^wc!5o zz+8*!jN9bNBjlIjTQflsTC%aEEo?L3uc$%U3)HF0L}EM%qEVU9Dj;}hWZyRLr=*mE zI0hIonSqZeG+IIQV|gZ`Twf)zD0hi9ncXQ=@6-2^>XRqiQmwy<6-)i&z)63B>i34j zvG5fU*E!)VAwgD;NX1`CBc}@ynq`4UlBh;N*J1CZ+s_}L2r13$*RO}$n?kzYDhF8! z3N7B3-ZBdaP(rHnOjzmb$hwa%Yt_6QquqKl3iMM~rJr@&aU5UVv>pzAzYoI2Lz&~2 zV&T=OHpJc-y@f>LX>Ox|;BsG7^ZVPGH#9%^T%}5JHv4DKQHn8< zEz&AGmFkU$YRH766j;x)G-WhY_Psct8gaOz@$g{WFD?(pfh+{w1b7<07hHaZzzh0V zp+0yJfs_d#EEt?rM=rEerJcww5x#>R0A<^d$?nl>rBNo|1~>rh{QYai+WB-{->B2# z$vXpse6l1i&b&L}!TzZ?w9q`Jt;A00Ayk#oAZ2mUE03zIN9diKz1#bj6D~KPHGU7x zrEJ5B-IyjP^U_LXV`e5rmCoE(b|JsBpC5KOWW%4~Nq$o?U$bDRbtcReERQ@Mhs zLv1r%FEl)4ihG6)R*KSh29ctO3$nO>oH>89-z zy>{8KafBBq#G^G$O-w3KA#6khG~S+k=+dS3Lr^eO%fs$P$wvtW0StRbFe~iT&(4zf z)IfilotGz2(K>hix5J_OoCSx@>9*0PH9s~DS)O+syW@HFiPZfLh5Rw$=}Rr9F)FQ9 zZ%JVx5H8+zjmwMD&k`8gLrz|SD9~*!$hQvEW&|%FU4Rd;==`XGL1V+U$~GOqG+r+#8PuUOgkv0p&iuR}J8AU8){kCK6*0d|i-Ly?61oaxUp z*#qHQ4x~_58L=LunH%h-sXldJm!o1pF4Y-SQjUHg5AZk7%GFv{Cb~~W%x8t z(mbh%%SNu#tH}N=#D!%%`wJZ|`;6J@^^g7*QbDVB;rX$#vEZjquhYJj1HP`$zDY$> zbEj8uFcm=+QT>z|&ilFnGfUeZ$kqLZm&2WG0rZUZ)T#G6fprcx)=iy8Vsm{9MwUA- zA7#mV1mAsKh1|*eVgq}gSK=m{L4@A7>WWi%$-~R7vN|<|{EAVrzS}+dc5KhFjdQBo zezoTrkbU-G9`jgSfm5o2kofoM@~^^*SVH~d68T6hMD2!mVwCxNfXKkf zy=9ct)a8KNka@+%9>*M_0qQWQzYL9xT%FGLhQHU%gxQT#2;V}aShQ!|oeP$WUj&u? zj(u1V^766z+tG+OskD>5`HH0v<+nKBXZ2E>+4d|*_haLnG3vtKKYFX}c62Qhmf@me zyg5SHnv$8@p{p5bC`Mx#8nsd+b)T{Bq9FP2{Iho9!Ud?0F^~|W=>K6h29Xh|(NGc- zz<3}iJ*4M+7Yfh2v5`>*k->x17TahkGN-3X)F2@tLE+u^T3N55m7d68=W)`a^O1W~ z$)2~`ci)L)9Y5pBPrh;a#O*6?dl=_$8%O6+P1AKpr#-mYwR`t&0)dNB>aMOXl9Mn+ z&~~~be+`Y0Lb%t7?qV56mk0R&-RB|TVr^$f8zbs4zX*Z0Gq{Jsc(N}j(=HF4ncvu? zJ==XdY*2~a_NS`Y>|U#ijNC@YLZOVbV6u!YXhp7YbrWuINl^B+Y&CaIan55J($v>G z&89Ez*-^K9<34i1zg>AWF0nc9!RjH6JHg5M9frXGGBzZbaM>jsXJ_WF1Vb@G{{%BfPXekYg@$2E|{5e1p2l)Zgcyn0Ny~!@hd+iYwmXWVBNFTFt%mKCsR|FQc_Zc92>+WaZ~#l85O}uO9E%iPdH021Mw1I;95&O z+`vn@x0GIlcOyFe63d@;1^f?W%T)b%TGrS4(n%70uW#o*SYI}#`;OBPl9Ij87YnXo(+ zxraF2{;$&)nF6#;X)^&ofnmvGd9Uwjxk;wc@QCC(Z~^U!d- zHH#Ewh#&ok;l$&4&9{$lt4}Symo{?nfP3ycs;U8djT*kfX8XJn?=aXPEMkoI;%cmq zg$lJd>^`EYjEszrWo28v9y}l;=zAfS>Fev8_xcZ*<%oPovPR?s>?P!6_Ye&{5FjFr z1ciqxidb@Ky8z(LsX%a9DcB@_K}(Bnbaa$RI?E~%yvCwU9F~1l4u9k^` z(9kE>k%)<$Mc%t|i247+_m!TNbQp{h6>%&_6k85ZM##-y)^*agtpCybIc%W8@<(Ux zE|7A7$ip2L81#TaPoEORWEc?~9(%6PFMP9wm54>7hjV8dYF>fv9E2}~^cW`o{Xtkg z&}x4K^EhOZ?(X8}&z}c_*B%ZRRx^zAf`jyX$&*9DL1hb1xWr;j7_siF*di_U#PtojtY}2<(u#>L2z?T6fI^x5M{+h;$|J7xA z%8&n9y`LgyG(R{n7mQJ;zK*;lUjUx?Yz#7%Enxf_6qOQFDU3OD9zU9Q9;FYyhfphsOW3~L^n8(H z<<`3p-kWRt>oMO6zd)JEQJ*r4bi?isP6dsQi`(W=3Nx^hefsd7y7fHV zpZR0(HVc5KsVplwnG3Usrii;xp54fG%AC2FuJP!f+TmLYbTYhgwxVniAyfAR>Uv(% zx2D`Z4i3swSwdy)xx-E@+V-!l6u2Chl6woH$mT$`0>;qOprB|5X(wQ;N|?8^*1j{{ zlT)*YTqY%zEc-uL-g6`)E zYOX-k?>T*1q%v7ZK)?`JUZ2$evqg^4qQyLCS^QUg42H`_?S=UtKYFKdj51sF)eBh% zxqV_A)2(}Qc28)(yl!*z9;y@De<_&V@+gQrXd!4c5l&}hV(uRr?&BI)sc9C#m@hrA zcWxF1?90l^`ysyy3X$hH6`Am6pvASlbt^x1UEgy<8mIU-hRP3%IdBjn>kzK`h6XOk zVOQ@Orke=~kovnAQr}3`9{M?RhJ?da;?U~PirZ6~Q|yCcyH`j4Y#ur;LeVL`$L5Gp z8;62K@vS>Hqq5qZpHHmH;Tq-VE+5QpuzFur8alsGK&1$I48o*6HJpn)waEG zjicj!Pp1$Nu(_#Xw6t8>@ZKavQ1}?v2It*=t>5BA=Q)HE=)W>sPq| z=$SuAAO|FL=ia@nCr|DtXgi>EK;E0K#Ow;>B`)n$w+a6QYq^DBhb~zerH5ch#{2i> zEiEl`Hh^GYFZyENr|PE2o^=a(=dpHDM7XlI>&0z4a=INxyW81@IV*oVOv~P_eGoDw zbNQX32L%iM*uTicKUD``&u?O$cSBE1g$R=w5sG?z-CGX4pc-i4!Ja zorey_P#>fVdz_U;QhVgB5}w_;E1}&S6l&yk$Ulu+-pQh7>Wc=U-TZfHRF{b<)Z@pu z0ql-^k`$D_ETh6vRU}}PJRjdmngNxG3zOHb5d>yCY-~P0c#*2zC2p$Ny)EE9xAux) zgSb|(u5vvey>Rxz^Ir)8mz8h6PdLTq`G@wcfbg3rPZHrJ@@hWyd|J2gMgHf?hi|Hc z1cg-rSwKK7M2mcVYj_w$(@U-Y3ts|OG0SiRw&TY`ubn+{Vm#MTS(ktU(x@Ktkgx63 zrw=PzkSjURH~vNu9xW!V@cCG$>+|fbY#-r_>ok-#svoG7)p_*kFLM_UEqRtiqD^zs zeze|>>5qZ(5T#^5Dmm?8Fun5R=sgees~jkq0#L9yHZJ6Y`-UmIk%;X*gM#x~betk0 zpB1AjdwNzs>3zJw$;I^;3C00NMqa_7knw&dwh1#;G4c!01}c`F}03ja}dQYklKxkmAwP%*FD~eLpRQzH3`$O$hp;8-mO*4=pDqnAR@BsF+HK4b<5WFnHcB& zwx)hr1^^rX`$ISV(3vwIK6E@&PmTqJ2XL{A=u?p%kB|hy1ax8M;cLHFRt_9FQcsYR zYvvhM?E_kj^9POE>m;TJ@kb_`U1bf#*HAY!Y5RFDh!zHfq31g0&^W--JLxa=7=dnV+0q=^oF5{&$dDV0erHLYOkE#A z>IG{r1X24>K-YuB2*o4!ss)^viq=-DD_5?dt5$}lzr2+OwKq`2hfGaPVc7_P1%%9E zYv0Aj^1~6Qq@-kIX8x!7@H= zPLQf6h1`5@Zpc9VBBss3qm+qQwW{hNS{i-!+%#`;JCt-inf(0y-=U-{Dkf%VZte$_ z2!duiA>l`)VdBo5oI6PibVi6ZI~ci60x0nW z4!BPgCM|a-zj~=B1NcTQ)WqWn%6K_RNiRxTT4#A~G;{n43JMm$H^Twx#9F)+qG@S@ zD!l4BzZjq>v`Is%tE*KzpDD&CXRNA(ywsLK@%0VCZ!rQRMsSCQAObjHo}<+b0V;_K z)#sD(X{8j>($Xj7!?;zXE?fwO_2xvlstjKof@JvL+f16EOEMEWOFGpO`&huFmbxrU zG5!kVnG@X69yJN`{O-#h0+!(rt+C0;Wbw7BY`+)|KfQDfKqEpR-bb5jYHZ8_p5s~o zRj8#^La@Hulp*eC$gzmJDHms`9C}9@_{l+T&FHS49!{Wgd<4+ikNf`Zo63wPr<7G% z6i{NE9UUFZYb|xDaUIPKL`UMry~Rp;8xAzMV>{r{<#z4dncrK-o7baru9NEH&!0ct zoGX^ogxi`OQD#zyK&0lse~ih6sj%Ji&zgQLv`$8z#2#xKT}@1~NQi0wq5TmRIVdRZ z{ZktMU@K@f|AUMC>o~6`E|9=$`YeDG1;;;>)5yvyAU!?(O+6Twuv^~XIQR%`Zf?Ra zVq+U~v?goty%)KB;?Vy6lE%iY$e&02M$We{t&(C~pt7NX9K?8Awr<5D)o-ZFgqzzj zgv#ia_{?|*22vmtCMG4YG5Z!bom6`#en8YAc2qRfBH_Jf2SxSTmj*(U2lnR&qy`F% zT$FQ)??f-8zo}JzOZ5?{or73}LHYFL5e5dEHGd^l)fR?2{XZUg0+?xt&9yj1hnA^a z=!r>Mk*Fc-O!0&sy>p1W#!-zi@9}ZSmKGHi z*)fgXHh0?)J#!`-lZdbz#IV^dN5@#DsIy1T-6`s;%74|PCPOr8AvNH0GpUxU?taqr zFP7O0$MKs!nAqacdLNCbun6>&BTxP=N}``df+I0 z$3m6k{qW%q+^5e7kf9(7Att(4&>9?x6EJnwg(nbgleMX z36dCM8W;LJ5vX^ChzvNtEi6mopHVxP^NTL2na68sX$csEXRrq59;hUszHBlxG(7B3 zwb1D~m|BlaM9zwjmlpyyscPX_Piz-Y&m8>wOp8ju&OvY}5>a-@#=Y4Km($)Z8F?3Bd?@I4vJU8%=iT0gez?X1X*pe1;@No_fn5e(6Z8I^ggaV?oEs&-mSb4#V z@#3#YZJN%%Z|0BM;Z9|fgyvn*|LuI~J22))U^`8EMHUwqxvnx^M@iRb0mb=>nwmtl z@cMd%zngGqY)l6IFZ@t2q#I}e*J4K4{|n*h%x9}<%mMfa{oT8%sa6I5xf!TC95{H; zCp&wwSgnkqeOQb$u+W{nKmE&>FJg}5gfYfx|C=GXEDXE-`|eiQU6?q1Qxg)vf2NoW)Cbac6PhfwL7rsT!O$smQMN7OA(+FyCwIGw(+nY|Yb#ZkvoeRM{f<;f=6J;OarvThc zBh=DHV2tH7HD3_1$6xb`R;G8m67~URaZaEjQVV-4M}8hGp{`1qZ6m9Rld~59@6rH~ zTPn0Hxq!f`MOYDv=j23uToA80VYi{yE~M6M?!F~~!%qMN?y-0_KPWc|OI;xy&~T`<~6Eh8fXMVE`?gQcaEhYw#%QZP49 zBK%WDON%PTLsSXfTr>hgIf>#pVG#Y`j!+hg0o%}ISl8^qzYcv72qOCLw;deRKwgwW z9PusY!|FmgPcU9a{WUD=)ifLsx+5y@fx?}cNyB#k`H5?o$=qVY9ZM~TiX^BWuT(TP zDvr0t2WG)H?oJAAfpZUFI#*J^I^O?b86N2Xe!uP4GUEHqYvW(u+=m`WB1kiX-~X#ZY!D>h=DjG0kR`PAxHoJ=Pw><-9*j`q%%sI zGn#3@nGnLBsz!)Y4g(_u2rk0hb;+v2%|b9o21+bxZj;8#Y5#0+MA+b3~be5CT^fUl|T28cFsH1U{5t zuY^DtuvCQ9baW1;qOw|4NNqzVEZG;39 zh&mz+)(|9$LbZorWW$s+F}(BXKI-3F2pUgnYU()vFA4oa;7jhs#*Xlejd!HdBYrHa zt@Xn`hn%d-bWW%BiTKXRUC7IMcmhy+%|bE)4hsOn)e`M++K~80VlX!w6pKqU{dKUn zGs*i<)0YQ6k>KjQ;Ir2Nh6!uPk75V9>x$UGpdaT9rG?;_NwCu!i)SPxTffL&Jg=sW z33s`niHTacB8YB-MPfg0kHB^R%f)MoRlrQA7aSI82HL795fHr}MDeV`!eJP+Cy+oS zef|A);=r>b&|FQ+Gq`{MK0%qt#O&-&3mEk@-IrAK^mQ0xkV3qMfZY((vjn*u397~Skb|JB zQjX!_(=H3F$bm6I;*D>T=-pW{0jGo_CYV8JXo^jQF_KW1H2n6{h=|L0L72xSfR?J2 zgM(3E1UZRZ3cIQiby{e~$AF3wU7f@QP8cn7TEYZ`vT<-cDk>5uP-tLfa)ym~A?}i8 zu!jBtG2DU9Sw&M5pb214PX2ZqyY@La;|IyD~_%wY3Sn1aSUUT=fc z!cjt=9&rSb(PkL!W-fOGLKIMsudo_`n=fFyo&92qrrblc62Xs@5M7O`r#gWKmlBUA zw)tBb3KEc!F#gbt5OX|s>J)W!{rPn7{V~U?F^odwuws`mF-?5c#!tNJ|L`_, +`\kappa_0\frac{Z+0.24}{Z+4.2} \simeq 3.2`, a different definition of collision time `\tau_{ei}` is used here, +but the other factors are included so that the heat flux `q_{SH}` is the same here as in those notes. + SNB model --------- @@ -92,4 +97,102 @@ The parallel divergence term is currently split into a second derivative term, a \nabla_{||}\left(k\partial_{||} T\right) = \frac{1}{J}\frac{\partial}{\partial y}\left(\frac{k J}{g_{22}}\frac{\partial T}{\partial y}\right) = k\frac{1}{g_22}\frac{\partial^2 T}{\partial y^2} + \frac{1}{J}\frac{\partial}{\partial y}\left(\frac{k J}{g_{22}}\right)\frac{\partial T}{\partial y} + +Using the SNB model +~~~~~~~~~~~~~~~~~~~ + +To use the SNB model, first include the header:: + + #include + +then create an instance:: + + HeatFluxSNB snb; + +By default this will use options in a section called "snb", but if +needed a different ``Options&`` section can be given to the constructor:: + + HeatFluxSNB snb(Options::root()["mysnb"]); + +The options are listed in table :numref:`tab-snb-options`. + +.. _tab-snb-options +.. table:: SNB options + + +--------------+---------------------------------------------------+---------------+ + | Name | Meaning | Default value | + +==============+===================================================+===============+ + | ``beta_max`` | Maximum energy group to consider (multiple of eT) | 10 | + | ``ngroups`` | Number of energy groups | 40 | + | ``r`` | Scaling down the electron-electron mean free path | 2 | + +--------------+---------------------------------------------------+---------------+ + +The divergence of the heat flux can then be calculated:: + + Field3D Div_q = snb.divHeatFlux(Te, Ne); + +where ``Te`` is the temperature in eV, and ``Ne`` is the electron density in `m^{-3}`. +The result is in eV per `m^3` per second, so multiplying by `e=1.602\times 10^{-19}` will give +Watts per cubic meter. + +To compare to the Spitzer-Harm result, pass in a pointer to a +``Field3D`` as the third argument. This field will be set to the +Spitzer-Harm value:: + + Field3D Div_q_SH; + Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); + +This is used in the examples discussed below. + +Example: Linear perturbation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. highlight:: console + +The ``examples/conduction-snb`` example calculates the heat flux for a +given density and temperature profile, comparing the SNB and +Spitzer-Harm fluxes. The ``sinusoidal.py`` case uses a periodic +domain of length 1 meter and a small (0.01eV) perturbation to the +temperature. The temperature is varied from 1eV to 1keV, so that the +mean free path varies. This is done for different SNB settings, +changing the number of groups and the maximum `\beta`:: + + $ python sinusoid.py + +This should output a file ``snb-sinusoidal.png`` and display the results, +shown in figure :numref:`fig-snb-sinusoidal`. + +.. _fig-snb-sinusoidal: +.. figure:: ../figs/snb-sinusoidal.* + :alt: When the mean free path is short, the SNB heat flux is close + to the Spitzer-Harm value. When the mean free path is long, + the ratio goes towards zero. + + The ratio of SNB heat flux to Spitzer-Harm heat flux, as a function + of electron mean free path divided by temperature perturbation + wavelength. Note that the difference between SNB and Spitzer-Harm + becomes significant (20%) when the mean free path is just 1% of the + wavelength. + + +Example: Nonlinear heat flux +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A nonlinear test is also included in ``examples/conduction-snb``, a step function in temperature +from around 200eV to 950eV over a distance of around 0.1mm, at an electron density of 5e26 per cubic meter:: + + $ python step.py + +This should output a file ``snb-step.png``, shown in figure :numref:`fig-snb-step`. + +.. _fig-snb-step: +.. figure:: ../figs/snb-step.* + :alt: The SNB peak heat flux in the steep gradient region is lower + than Spitzer-Harm by nearly a factor of 2. In the cold region + the SNB heat flux is above the Spitzer-Harm value, and is + nonzero in regions where the temperature gradient is zero. + + Temperature profile and heat flux calculated using Spitzer-Harm and + the SNB model, for a temperature step profile, at a density of 5e26 + per cubic meter. Note the reduction in peak heat flux (flux limit) + and higher flux in the cold region (preheat) with the SNB model. diff --git a/src/physics/snb.cxx b/src/physics/snb.cxx index dd9cc73990..8f53ac3dc6 100644 --- a/src/physics/snb.cxx +++ b/src/physics/snb.cxx @@ -5,7 +5,6 @@ #include "derivs.hxx" #include "bout/fv_ops.hxx" #include "bout/constants.hxx" -#include "output.hxx" Field3D HeatFluxSNB::divHeatFlux(const Field3D &Te, const Field3D &Ne, Field3D *Div_Q_SH_out) { Coordinates *coord = Te.getCoordinates(); @@ -16,13 +15,14 @@ Field3D HeatFluxSNB::divHeatFlux(const Field3D &Te, const Field3D &Ne, Field3D * Field3D coulomb_log = 6.6 - 0.5 * log(Ne * 1e-20) + 1.5 * log(Te); // Thermal electron-electron mean free path [m] - Field3D lambda_ee_T = pow(thermal_speed, 3) / (Y * Ne * coulomb_log); - Field3D lambda_ei_T = lambda_ee_T / SQ(Z); + Field3D lambda_ee_T = pow(thermal_speed, 4) / (Y * Ne * coulomb_log); + Field3D lambda_ei_T = lambda_ee_T / Z; // Note: Z rather than Z^2 since Ni = Ne / Z // Thermal electron-ion collision time [s] Field3D tau_ei_T = lambda_ei_T / thermal_speed; // Divergence of Spitzer-Harm heat flux + // Note: 13.58 from 128/(3pi) Field3D Div_Q_SH = -FV::Div_par_K_Grad_par((Ne * SI::qe * Te / SI::Me) * (0.25 * 3 * sqrt(PI) * tau_ei_T) * 13.58 * (Z + 0.24) / (Z + 4.2), @@ -66,14 +66,9 @@ Field3D HeatFluxSNB::divHeatFlux(const Field3D &Te, const Field3D &Ne, Field3D * // Note: The sum of weight over all groups approaches 1 as beta_max -> infinity Div_Q -= weight * Div_Q_SH + H_g / lambda_g_ee; - output.write("%d: %e, %e => %e\n", i, beta, weight, Div_Q(0,4,0)); - // move to next group, updating lower limit beta_last = beta; } - output.write("%e, %e, %e => %e, %e\n", tau_ei_T(0,4,0), thermal_speed(0,4,0), lambda_ee_T(0,4,0), - Div_Q_SH(0,4,0), Div_Q(0,4,0)); - return Div_Q; } From 2f852a5054f8b0194258edbcb2e00d6b0f452a3f Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 12 Jun 2019 16:53:56 +0100 Subject: [PATCH 1519/1783] Add docstrings to SNB model Include some paper references, to original SNB paper and Brodrick 2017. --- include/bout/snb.hxx | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/include/bout/snb.hxx b/include/bout/snb.hxx index 86b2dc1a7e..36c1a0e15b 100644 --- a/include/bout/snb.hxx +++ b/include/bout/snb.hxx @@ -1,12 +1,22 @@ #include "../options.hxx" #include "../invert_parderiv.hxx" -/// Calculate heat flux using the SNB model +/// Calculate heat flux using the Shurtz-Nicolai-Busquet (SNB) model +/// +/// Useful references: +/// +/// Braginskii equations by R.Fitzpatrick: http://farside.ph.utexas.edu/teaching/plasma/Plasmahtml/node35.html /// +/// J.P.Brodrick et al 2017: https://doi.org/10.1063/1.5001079 and https://arxiv.org/abs/1704.08963 +/// +/// Shurtz, Nicolai and Busquet 2000: https://doi.org/10.1063/1.1289512 +/// class HeatFluxSNB { public: + /// Construct using the options in the "snb" section. HeatFluxSNB() : HeatFluxSNB(Options::root()["snb"]) {} - + + /// Construct using options in given section. explicit HeatFluxSNB(Options &options) { invertpar = InvertPar::Create(); @@ -16,8 +26,8 @@ public: beta_max = options["beta_max"].doc("Maximum energy group to consider (multiple of eT)") .withDefault(beta_max); ngroups = options["ngroups"].doc("Number of energy groups").withDefault(ngroups); - } + ~HeatFluxSNB() { delete invertpar; } @@ -27,15 +37,18 @@ public: /// Ne: Electron density in m^-3 /// /// Div_Q_SH_out : An optional output field to store the Spitzer-Harm heat flux + /// + /// Returns the divergence of heat flux in units of eV per cubic meter per second + /// -> multiply by e=1.602e-19 to get Watts per cubic meter. Field3D divHeatFlux(const Field3D &Te, const Field3D &Ne, Field3D *Div_Q_SH_out = nullptr); private: - InvertPar *invertpar; + InvertPar *invertpar; ///< Parallel inversion of tridiagonal matrices - BoutReal Z{1}; // Average ion charge (1 = Hydrogen) - BoutReal r{2}; // Electron-electron mean free path scaling factor - BoutReal beta_max{10.0}; // Maximum energy group to consider (multiple of eT) - int ngroups{40}; // Number of energy groups + BoutReal Z{1}; ///< Average ion charge (1 = Hydrogen) + BoutReal r{2}; ///< Electron-electron mean free path scaling factor + BoutReal beta_max{10.0}; ///< Maximum energy group to consider (multiple of eT) + int ngroups{40}; ///< Number of energy groups /// Indefinite integral of beta^4 * exp(-beta) /// with constant set to zero From 9347be5123cced3a8b0a0d1848a368794de41501 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 12 Jun 2019 17:36:51 +0100 Subject: [PATCH 1520/1783] Started adding unit tests for SNB model Just sanity checks, rather than proper tests, but mayb better than nothing. --- tests/unit/physics/test_snb.cxx | 93 +++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 tests/unit/physics/test_snb.cxx diff --git a/tests/unit/physics/test_snb.cxx b/tests/unit/physics/test_snb.cxx new file mode 100644 index 0000000000..977f75e7c4 --- /dev/null +++ b/tests/unit/physics/test_snb.cxx @@ -0,0 +1,93 @@ +#include "gtest/gtest.h" +#include "test_extras.hxx" + +#include "bout/mesh.hxx" + +#include "bout/snb.hxx" + +/// Global mesh +namespace bout{ +namespace globals{ +extern Mesh *mesh; +} // namespace globals +} // namespace bout + +// The unit tests use the global mesh +using namespace bout::globals; + + +/// Test fixture to make sure the global mesh is our fake +/// one. Also initialize the global mesh_staggered for use in tests with +/// staggering. Multiple tests have exactly the same fixture, so use a type +/// alias to make a new test: +/// +/// using MyTest = FakeParallelMeshFixture; +class FakeParallelMeshFixture : public ::testing::Test { +public: + FakeParallelMeshFixture() { + WithQuietOutput quiet{output_info}; + + delete bout::globals::mesh; + bout::globals::mesh = new FakeMesh(nx, ny, nz); + bout::globals::mesh->createDefaultRegions(); + static_cast(bout::globals::mesh)->setCoordinates(nullptr); + test_coords = std::make_shared( + bout::globals::mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, + Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, + Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, + false); + static_cast(bout::globals::mesh)->setCoordinates(test_coords); + static_cast(bout::globals::mesh)->setGridDataSource( + new FakeGridDataSource()); + // May need a ParallelTransform to create fields, because create3D calls + // fromFieldAligned + test_coords->setParallelTransform( + bout::utils::make_unique(*bout::globals::mesh)); + + delete mesh_staggered; + mesh_staggered = new FakeMesh(nx, ny, nz); + mesh_staggered->StaggerGrids = true; + static_cast(mesh_staggered)->setCoordinates(nullptr); + static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); + static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_YLOW); + static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_ZLOW); + mesh_staggered->createDefaultRegions(); + + test_coords_staggered = std::make_shared( + mesh_staggered, Field2D{1.0, mesh_staggered}, Field2D{1.0, mesh_staggered}, + BoutReal{1.0}, Field2D{1.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, + Field2D{1.0, mesh_staggered}, Field2D{1.0, mesh_staggered}, + Field2D{1.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, + Field2D{0.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, + Field2D{1.0, mesh_staggered}, Field2D{1.0, mesh_staggered}, + Field2D{1.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, + Field2D{0.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, + Field2D{0.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, false); + test_coords_staggered->setParallelTransform( + bout::utils::make_unique(*mesh_staggered)); + } + + virtual ~FakeParallelMeshFixture() { + delete bout::globals::mesh; + bout::globals::mesh = nullptr; + delete mesh_staggered; + mesh_staggered = nullptr; + } + + static constexpr int nx = 1; + static constexpr int ny = 16; + static constexpr int nz = 1; + + Mesh* mesh_staggered = nullptr; + + std::shared_ptr test_coords{nullptr}; + std::shared_ptr test_coords_staggered{nullptr}; +}; + +using SNBTest = FakeParallelMeshFixture; + +TEST_F(SNBTest, createInstance) { + HeatFluxSNB snb; +} + From 3d69a0f5db2ffc1555e930eeedfb2bf9d9a4c1c0 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 12 Jun 2019 23:23:10 +0100 Subject: [PATCH 1521/1783] Add missing BOUT.inp Forgot to add to previous commits --- examples/conduction-snb/step/BOUT.inp | 37 +++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 examples/conduction-snb/step/BOUT.inp diff --git a/examples/conduction-snb/step/BOUT.inp b/examples/conduction-snb/step/BOUT.inp new file mode 100644 index 0000000000..30ea2c87a1 --- /dev/null +++ b/examples/conduction-snb/step/BOUT.inp @@ -0,0 +1,37 @@ +# Step function temperature profile + +MXG = 0 + +Ne = 5e26 # Electron density, m^-3 + +# Electron temperature, eV +Tmin = 195 # Minimum temperature, on right of domain +Tmax = 950 # Maximum temperature, on left + +mid = 2.5e-4 # Middle of the tanh profile [m] + +# Width of the tanh profile [m] +width0 = 8e-5 +width1 = 1e-5 +width = width0 - 0.5*(1 + tanh((ypos - mid) / width0))*(width0 - width1) + +Te = Tmax - 0.5*(1 + tanh((ypos - mid) / width)) * (Tmax - Tmin) + +ypos = y * mesh:length / (2*pi) # Y position in meters. y variable from 0 to 2pi + +[mesh] +# Size of the domain +nx = 1 +ny = 256 # Along magnetic field +nz = 1 + +length = 6e-4 # in meters +dy = length / ny # Grid spacing + +# Set boundaries +ixseps1 = -1 +ixseps2 = -1 + +[snb] +ngroups = 50 # Number of energy groups +beta_max = 20 # Maximum energy group to consider (multiple of eT) From 5208b8e620731760ac59dc099b6935a2c03e0eed Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 13 Jun 2019 00:05:56 +0100 Subject: [PATCH 1522/1783] Adding reference heat flux values Benchmark values extracted from plots using https://automeris.io/WebPlotDigitizer/ Adjusted step temperature profiles to be closer to the benchmark case. --- examples/conduction-snb/sinusoid.py | 1 - examples/conduction-snb/snb.csv | 29 ++++++++++++++++ examples/conduction-snb/spitzer-harm.csv | 43 ++++++++++++++++++++++++ examples/conduction-snb/step.py | 24 ++++++++++++- examples/conduction-snb/step/BOUT.inp | 13 +++---- examples/conduction-snb/temperature.csv | 40 ++++++++++++++++++++++ examples/conduction-snb/vfp.csv | 34 +++++++++++++++++++ 7 files changed, 176 insertions(+), 8 deletions(-) create mode 100644 examples/conduction-snb/snb.csv create mode 100644 examples/conduction-snb/spitzer-harm.csv create mode 100644 examples/conduction-snb/temperature.csv create mode 100644 examples/conduction-snb/vfp.csv diff --git a/examples/conduction-snb/sinusoid.py b/examples/conduction-snb/sinusoid.py index 9d569fd333..209d6de85e 100644 --- a/examples/conduction-snb/sinusoid.py +++ b/examples/conduction-snb/sinusoid.py @@ -7,7 +7,6 @@ from boututils.run_wrapper import shell_safe, launch_safe from boutdata.collect import collect -from sys import exit shell_safe("make > make.log") diff --git a/examples/conduction-snb/snb.csv b/examples/conduction-snb/snb.csv new file mode 100644 index 0000000000..93cb3418d2 --- /dev/null +++ b/examples/conduction-snb/snb.csv @@ -0,0 +1,29 @@ +0.03354297693920316, 132530120481.92969 +0.1750524109014674, 855421686746.9922 +0.3165618448637316, 1674698795180.7266 +0.434161512206109, 2457200703641.0156 +0.552035506580961, 3145042981844.7383 +0.6857771540447355, 3937103787049.0273 +0.7932238335325812, 4624946065252.75 +0.9020305975709062, 5325294566696.539 +0.996329793070788, 5948521358159.918 +1.0960693267725856, 6584254372863.359 +1.2157567672147431, 7351302731587.512 +1.3408845458588168, 8126688572471.707 +1.4406240795606147, 8626937502074.418 +1.544897228430676, 9085499020876.898 +1.6877061062309777, 9669122772080.059 +1.7987796778534344, 9919247236881.414 +1.9465408805031448, 9963855421686.75 +2.109332316879487, 9606591655879.72 +2.2158722733336798, 9148030137077.238 +2.3171230120915656, 8474083662473.59 +2.4304633912981544, 7466637901468.137 +2.5123707053381152, 6642616747983.672 +2.58762871713129, 5813037273059.184 +2.6750627239478013, 4744052953253.398 +2.7517455862224303, 3757847920608.0586 +2.824887910937082, 2901866418843.422 +2.9125378041901766, 1943055970438.2305 +3.051568669350259, 845287486032.2891 +3.1225953069863874, 206080520428.82812 diff --git a/examples/conduction-snb/spitzer-harm.csv b/examples/conduction-snb/spitzer-harm.csv new file mode 100644 index 0000000000..ed990b92ec --- /dev/null +++ b/examples/conduction-snb/spitzer-harm.csv @@ -0,0 +1,43 @@ +0.028301886792453,228915662650.605 +0.139476526268979,1415015433635.37 +0.225615214465986,2373825882040.56 +0.295597484276729,3072289156626.51 +0.358601259401717,3818989456448.39 +0.429627897037846,4645789770652.86 +0.488564894225271,5375319459656.81 +0.579237197590542,6625941783663.58 +0.660842270619286,7904355714870.5 +0.715245652638449,8738103930875.02 +0.793501048218029,10108433734939.8 +0.869388568359409,11489473043689.9 +0.924528301886792,12518072289156.6 +0.978195332397734,13587739387301.3 +1.01899786891211,14379800192505.6 +1.08700209643606,15713797338112.8 +1.16407355429654,17089481894520.2 +1.22754416665223,18215041986126.3 +1.29101477900792,19278070961532.1 +1.35901900653187,20202141900937.1 +1.43815513626834,21144578313253 +1.52676276775762,21716784493345.3 +1.61635220125786,22012048192771.1 +1.7035737593199,21758471904145.5 +1.81238052335822,21008098509741.4 +1.87840670859539,20132530120481.9 +1.93327692784525,19271123059732 +2.014882000874,17812063681724.1 +2.06172935761272,16797670018918.7 +2.11764394468797,15533151891311.8 +2.16600250648278,14213050549304.7 +2.25214119467979,12024461482292.8 +2.30805578175504,10600141613285.1 +2.36094795871811,9252248664077.8 +2.40775681341719,7987951807228.92 +2.46522110758817,6625941783663.58 +2.51055725927081,5583756513657.94 +2.59216233229955,3902364278048.84 +2.65865535476742,2790699990042.82 +2.73421560757181,1734618916437.1 +2.83697755138578,789704271631.988 +2.95283018867925,277108433734.941 +3.04716981132075,132530120481.93 diff --git a/examples/conduction-snb/step.py b/examples/conduction-snb/step.py index 89babda747..c3120eddf6 100644 --- a/examples/conduction-snb/step.py +++ b/examples/conduction-snb/step.py @@ -38,10 +38,26 @@ q -= np.amin(q) q_SH -= np.amin(q_SH) +# Read reference values +Te_ref = np.loadtxt("temperature.csv", delimiter=",") +Te_ref[:,0] *= 1e-4 # Convert X axis to m + +SH_ref = np.loadtxt("spitzer-harm.csv", delimiter=",") +SH_ref[:,0] *= 1e-4 + +SNB_ref = np.loadtxt("snb.csv", delimiter=",") +SNB_ref[:,0] *= 1e-4 + +VFP_ref = np.loadtxt("vfp.csv", delimiter=",") +VFP_ref[:,0] *= 1e-4 + +######################################### + fig, ax1 = plt.subplots() color='tab:red' ax1.plot(position, Te * 1e-3, color=color) +ax1.plot(Te_ref[:,0], Te_ref[:,1], color=color, marker="o") ax1.set_xlabel("position [m]") ax1.set_ylabel("Electron temperature [keV]", color=color) ax1.set_ylim(0,1) @@ -49,7 +65,13 @@ ax2 = ax1.twinx() ax2.plot(position, q_SH * 1e-4, '--k', label="Spitzer-Harm") -ax2.plot(position, q * 1e-4, label="SNB") +ax2.plot(SH_ref[:,0], SH_ref[:,1], 'ok', label="Reference SH") + +ax2.plot(position, q * 1e-4, '-b', label="SNB") +ax2.plot(SNB_ref[:,0], SNB_ref[:,1], 'ob', label="Reference SNB") + +ax2.plot(VFP_ref[:,0], VFP_ref[:,1], 'or', label="Reference VFP") + ax2.set_ylabel("Heat flux W/cm^2") ax2.set_ylim(bottom=0.0) diff --git a/examples/conduction-snb/step/BOUT.inp b/examples/conduction-snb/step/BOUT.inp index 30ea2c87a1..e2979fcc89 100644 --- a/examples/conduction-snb/step/BOUT.inp +++ b/examples/conduction-snb/step/BOUT.inp @@ -5,15 +5,16 @@ MXG = 0 Ne = 5e26 # Electron density, m^-3 # Electron temperature, eV -Tmin = 195 # Minimum temperature, on right of domain -Tmax = 950 # Maximum temperature, on left +Tmin = 190 # Minimum temperature, on right of domain +Tmax = 960 # Maximum temperature, on left -mid = 2.5e-4 # Middle of the tanh profile [m] +mid = 2.2e-4 # Middle of the tanh profile [m] # Width of the tanh profile [m] -width0 = 8e-5 -width1 = 1e-5 -width = width0 - 0.5*(1 + tanh((ypos - mid) / width0))*(width0 - width1) +width0 = 1.1e-4 +width1 = 4e-5 +mid_width = 2.4e-4 +width = width0 - 0.5*(1 + tanh((ypos - mid_width) / 1e-4))*(width0 - width1) Te = Tmax - 0.5*(1 + tanh((ypos - mid) / width)) * (Tmax - Tmin) diff --git a/examples/conduction-snb/temperature.csv b/examples/conduction-snb/temperature.csv new file mode 100644 index 0000000000..f34b6ac6e3 --- /dev/null +++ b/examples/conduction-snb/temperature.csv @@ -0,0 +1,40 @@ +-0.3263485477178425, 0.9445290581162327 +-0.08748271092669446, 0.9445290581162327 +0.15138312586445357, 0.9433849517216253 +0.3902489626556016, 0.9388085261431957 +0.6291147994467496, 0.9283685552924033 +0.8679806362378977, 0.911779012570596 +1.1068464730290457, 0.885035525596648 +1.3239972337482708, 0.8508394566911603 +1.497717842323651, 0.8146321213856286 +1.638865836791148, 0.7788243152972614 +1.7582987551867215, 0.744424849699399 +1.8668741355463347, 0.7088717434869741 +1.975449515905947, 0.6698577154308618 +2.073167358229599, 0.6326528056112226 +2.160027662517289, 0.59686372745491 +2.246887966804979, 0.5595015030060122 +2.3337482710926696, 0.5201728456913829 +2.4206085753803595, 0.47940213760855055 +2.5074688796680493, 0.4367960921843689 +2.59432918395574, 0.39353456913827667 +2.68118948824343, 0.35302605210420857 +2.76804979253112, 0.3130419171676687 +2.8549100968188106, 0.27672845691382775 +2.963485477178423, 0.24054609218436884 +3.148063623789765, 0.20729550009109143 +3.386929460580913, 0.19471032975041003 +3.625795297372061, 0.19413827655310634 +3.864661134163209, 0.19413827655310634 +4.103526970954357, 0.19413827655310634 +4.3423928077455045, 0.19413827655310634 +4.581258644536653, 0.19413827655310634 +4.820124481327801, 0.19413827655310634 +5.058990318118948, 0.19413827655310634 +5.297856154910097, 0.19413827655310634 +5.536721991701246, 0.19413827655310634 +5.775587828492393, 0.19413827655310634 +6.014453665283542, 0.19413827655310634 +6.253319502074689, 0.19413827655310634 +6.492185338865838, 0.19413827655310634 +6.709336099585062, 0.19413827655310634 diff --git a/examples/conduction-snb/vfp.csv b/examples/conduction-snb/vfp.csv new file mode 100644 index 0000000000..811d350611 --- /dev/null +++ b/examples/conduction-snb/vfp.csv @@ -0,0 +1,34 @@ +0.03354297693920316, 84337349397.59375 +0.1168084504276613, 622954628431.082 +0.2256152144659862, 1206578379634.2422 +0.3117539026629934, 1581765076836.2734 +0.4161425576519916, 2204819277108.4375 +0.5339010459079068, 2801121842742.875 +0.6064388886001235, 3228417803445.1914 +0.7307894760724949, 4005590247649.3945 +0.838300921491316, 4648767442852.879 +0.945326622427823, 5333632048856.586 +1.0455519006119347, 5982764588460.102 +1.141405478455221, 6598150176463.434 +1.2437356493960265, 7245297601266.9375 +1.3629049623903824, 7953983584870.773 +1.4610253478178006, 8533140827773.91 +1.5796549447206965, 9106342726277.012 +1.6582376076372647, 9405102503678.63 +1.782156422236468, 9710810182880.285 +1.880384750882178, 9877559826081.188 +2.0027923604252935, 9919247236881.414 +2.125199969968409, 9731653888280.398 +2.218592442434638, 9410660825118.66 +2.3123735104867182, 8859195933675.672 +2.4224755931445467, 8114777883671.645 +2.528691719943864, 7277781297994.387 +2.6329648688139256, 6167380264861.102 +2.720917003078238, 5241919745096.09 +2.7968226741811644, 4351000222851.2695 +2.893647740989079, 3384745593946.035 +2.9846438740092256, 2492932770041.211 +3.0772591553037523, 1665139898436.7266 +3.182827622793318, 968364603632.957 +3.316029554165632, 351986458229.6172 +3.3825995807127884, 36144578313.25781 From 8fd9ee54541c3843fb2b3cffdfa19a8a6261e08f Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 13 Jun 2019 00:09:53 +0100 Subject: [PATCH 1523/1783] Tried to add unit tests (fail, need MPI) Unfortunately the parallel inversion needs MPI to work, but this is not currently initialised in the unit test. --- tests/unit/physics/test_snb.cxx | 119 +++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 3 deletions(-) diff --git a/tests/unit/physics/test_snb.cxx b/tests/unit/physics/test_snb.cxx index 977f75e7c4..27e0bdb239 100644 --- a/tests/unit/physics/test_snb.cxx +++ b/tests/unit/physics/test_snb.cxx @@ -2,7 +2,7 @@ #include "test_extras.hxx" #include "bout/mesh.hxx" - +#include "field_factory.hxx" #include "bout/snb.hxx" /// Global mesh @@ -31,8 +31,9 @@ class FakeParallelMeshFixture : public ::testing::Test { bout::globals::mesh = new FakeMesh(nx, ny, nz); bout::globals::mesh->createDefaultRegions(); static_cast(bout::globals::mesh)->setCoordinates(nullptr); + /// Note: dy = 1/ny so length in Y is 1 test_coords = std::make_shared( - bout::globals::mesh, Field2D{1.0}, Field2D{1.0}, BoutReal{1.0}, Field2D{1.0}, + bout::globals::mesh, Field2D{1.0}, Field2D{1.0 / ny}, BoutReal{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, @@ -87,7 +88,119 @@ class FakeParallelMeshFixture : public ::testing::Test { using SNBTest = FakeParallelMeshFixture; -TEST_F(SNBTest, createInstance) { +// We can create an instance +TEST_F(SNBTest, CreateInstance) { + HeatFluxSNB snb; +} + +// When there is a temperature gradient the flux is nonzero +TEST_F(SNBTest, FluxNotZero) { + + FieldFactory factory; + auto Te = factory.create3D("5 + cos(y)"); + auto Ne = factory.create3D("1e18 * (1 + 0.5*sin(y))"); + HeatFluxSNB snb; + + Field3D Div_q_SH; + Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); + + // Check that flux is not zero + EXPECT_FALSE(IsFieldEqual(Div_q_SH, 0.0, "RGN_NOBNDRY")); + EXPECT_FALSE(IsFieldEqual(Div_q, 0.0, "RGN_NOBNDRY")); +} + +// When the temperature is constant there is no flux +TEST_F(SNBTest, ZeroTempGradient) { + + FieldFactory factory; + auto Te = factory.create3D("1.5"); + auto Ne = factory.create3D("1e18 * (1 + 0.5*sin(y))"); + + HeatFluxSNB snb; + + Field3D Div_q_SH; + Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); + + // Check that flux is zero + EXPECT_TRUE(IsFieldEqual(Div_q_SH, 0.0, "RGN_NOBNDRY")); + EXPECT_TRUE(IsFieldEqual(Div_q, 0.0, "RGN_NOBNDRY")); +} + +// In the collisional limit the SH and SNB fluxes are close +TEST_F(SNBTest, CollisionalLimitClose) { + + FieldFactory factory; + auto Te = factory.create3D("1 + 0.01*sin(y)"); + auto Ne = factory.create3D("1e20 * (1 + 0.5*sin(y))"); + + HeatFluxSNB snb; + + Field3D Div_q_SH; + Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); + + // Check that flux is zero + EXPECT_TRUE(IsFieldEqual(Div_q, Div_q_SH, "RGN_NOBNDRY")); } +// In the collisionless limit the SH and SNB fluxes are different +TEST_F(SNBTest, CollisionlessLimitDifferent) { + + FieldFactory factory; + auto Te = factory.create3D("1e3 + 0.01*sin(y)"); + auto Ne = factory.create3D("1e19 * (1 + 0.5*sin(y))"); + + HeatFluxSNB snb; + + Field3D Div_q_SH; + Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); + + // Check that fluxes are not equal + EXPECT_FALSE(IsFieldEqual(Div_q, Div_q_SH, "RGN_NOBNDRY")); +} + +// Reversing the temperature gradient reverses the flux +TEST_F(SNBTest, FluxReverses) { + + FieldFactory factory; + auto Te = factory.create3D("10 + 0.01*sin(y)"); + auto Ne = factory.create3D("1e19 * (1 + 0.5*sin(y))"); + + HeatFluxSNB snb; + + Field3D Div_q_SH_1; + Field3D Div_q_1 = snb.divHeatFlux(Te, Ne, &Div_q_SH_1); + + auto Te2 = factory.create3D("10 - 0.01*sin(y)"); + + Field3D Div_q_SH_2; + Field3D Div_q_2 = snb.divHeatFlux(Te2, Ne, &Div_q_SH_2); + + // Check that fluxes are reversed + EXPECT_TRUE(IsFieldEqual(Div_q_2, -Div_q_1, "RGN_NOBNDRY")); + EXPECT_TRUE(IsFieldEqual(Div_q_SH_2, -Div_q_SH_1, "RGN_NOBNDRY")); +} + +// Spitzer-Harm is independent of density, but SNB is not +TEST_F(SNBTest, DensityDependence) { + + FieldFactory factory; + auto Te = factory.create3D("10 + 0.01*sin(y)"); + auto Ne = factory.create3D("1e19 * (1 + 0.5*sin(y))"); + + HeatFluxSNB snb; + + Field3D Div_q_SH_1; + Field3D Div_q_1 = snb.divHeatFlux(Te, Ne, &Div_q_SH_1); + + auto Ne2 = factory.create3D("1e17 * (1 + 0.5*sin(y))"); + + Field3D Div_q_SH_2; + Field3D Div_q_2 = snb.divHeatFlux(Te, Ne2, &Div_q_SH_2); + + // SNB result different + EXPECT_FALSE(IsFieldEqual(Div_q_2, Div_q_1, "RGN_NOBNDRY")); + + // Spitzer-Harm not changed + EXPECT_TRUE(IsFieldEqual(Div_q_SH_2, Div_q_SH_1, "RGN_NOBNDRY")); +} From 6cb8a4729aa84fa439d01d11e548b9e3d3cefe57 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 13 Jun 2019 12:55:49 +0100 Subject: [PATCH 1524/1783] Updated SNB step comparison - Improved match to temperature by fitting to data -> added the script fit_temperature.py used to get coefficients - Updated graph in manual --- examples/conduction-snb/fit_temperature.py | 25 +++++++++++++++++++++ examples/conduction-snb/step.py | 12 +++++----- examples/conduction-snb/step/BOUT.inp | 21 +++++++++-------- manual/sphinx/figs/snb-step.png | Bin 50363 -> 71950 bytes 4 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 examples/conduction-snb/fit_temperature.py diff --git a/examples/conduction-snb/fit_temperature.py b/examples/conduction-snb/fit_temperature.py new file mode 100644 index 0000000000..de54cd2dab --- /dev/null +++ b/examples/conduction-snb/fit_temperature.py @@ -0,0 +1,25 @@ +import numpy as np +from scipy import optimize +import matplotlib.pyplot as plt + +Te_ref = np.loadtxt("temperature.csv", delimiter=",") +Te_ref[:,0] *= 1e-4 # Convert X axis to m + +def te_function(ypos, mid, wwid, w0, w1, w2, Tmax, Tmin, clip=False): + width = w0 + ((ypos - mid)*w1 + (ypos - mid)**2 * w2) * np.exp(-((ypos - mid)/wwid)**2) + + if clip: + width = np.clip(width, 1e-10, None) + + return Tmax - 0.5 * (1 + np.tanh((ypos - mid)/width)) * (Tmax - Tmin) + +popt, pcov = optimize.curve_fit(te_function, Te_ref[:,0], Te_ref[:,1], + p0 = [2.2e-4, 1e-4, 1e-4, 0.0, 0.0, 0.960, 0.190]) + +print(popt) + +xfit = np.linspace(Te_ref[0,0], Te_ref[-1,0], 100) + +plt.plot(xfit, te_function(xfit, *popt, clip=True), '-k') +plt.plot(Te_ref[:,0], Te_ref[:,1], 'or') +plt.show() diff --git a/examples/conduction-snb/step.py b/examples/conduction-snb/step.py index c3120eddf6..3e49a58038 100644 --- a/examples/conduction-snb/step.py +++ b/examples/conduction-snb/step.py @@ -56,21 +56,21 @@ fig, ax1 = plt.subplots() color='tab:red' -ax1.plot(position, Te * 1e-3, color=color) -ax1.plot(Te_ref[:,0], Te_ref[:,1], color=color, marker="o") +ax1.plot(position, Te * 1e-3, color=color, label="Te") +ax1.plot(Te_ref[:,0], Te_ref[:,1], color=color, marker="o", label="Reference Te") ax1.set_xlabel("position [m]") ax1.set_ylabel("Electron temperature [keV]", color=color) ax1.set_ylim(0,1) ax1.tick_params(axis='y', colors=color) ax2 = ax1.twinx() -ax2.plot(position, q_SH * 1e-4, '--k', label="Spitzer-Harm") -ax2.plot(SH_ref[:,0], SH_ref[:,1], 'ok', label="Reference SH") +ax2.plot(position, q_SH * 1e-4, '-k', label="Spitzer-Harm") +ax2.plot(SH_ref[:,0], SH_ref[:,1], '--k', label="Reference SH") ax2.plot(position, q * 1e-4, '-b', label="SNB") -ax2.plot(SNB_ref[:,0], SNB_ref[:,1], 'ob', label="Reference SNB") +ax2.plot(SNB_ref[:,0], SNB_ref[:,1], '--b', label="Reference SNB") -ax2.plot(VFP_ref[:,0], VFP_ref[:,1], 'or', label="Reference VFP") +ax2.plot(VFP_ref[:,0], VFP_ref[:,1], '--g', label="Reference VFP") ax2.set_ylabel("Heat flux W/cm^2") ax2.set_ylim(bottom=0.0) diff --git a/examples/conduction-snb/step/BOUT.inp b/examples/conduction-snb/step/BOUT.inp index e2979fcc89..1f15a0dfa8 100644 --- a/examples/conduction-snb/step/BOUT.inp +++ b/examples/conduction-snb/step/BOUT.inp @@ -5,18 +5,21 @@ MXG = 0 Ne = 5e26 # Electron density, m^-3 # Electron temperature, eV -Tmin = 190 # Minimum temperature, on right of domain -Tmax = 960 # Maximum temperature, on left +# These values fitted from data in temperature.csv by script fit_temperature.py -mid = 2.2e-4 # Middle of the tanh profile [m] +Tmin = 194.128366 # Minimum temperature, on right of domain +Tmax = 943.775872 # Maximum temperature, on left -# Width of the tanh profile [m] -width0 = 1.1e-4 -width1 = 4e-5 -mid_width = 2.4e-4 -width = width0 - 0.5*(1 + tanh((ypos - mid_width) / 1e-4))*(width0 - width1) +mid = 2.22729804e-04 # Middle of the tanh profile [m] +wwid = 2.79208361e-04 # Distance over which the tanh width varies +w0 = 8.45148657e-05 # Width of the tanh profile +w1 = -2.73392710e-01 # 1st order variation of tanh width +w2 = -1.92344478e+03 # 2nd order variation of tanh width -Te = Tmax - 0.5*(1 + tanh((ypos - mid) / width)) * (Tmax - Tmin) +width = w0 + ((ypos - mid)*w1 + (ypos - mid)^2 * w2) * exp(-((ypos - mid)/wwid)^2) +width_clip = 1e-10 + H(width) * width # Ensure that width is positive + +Te = Tmax - 0.5*(1 + tanh((ypos - mid) / width_clip)) * (Tmax - Tmin) ypos = y * mesh:length / (2*pi) # Y position in meters. y variable from 0 to 2pi diff --git a/manual/sphinx/figs/snb-step.png b/manual/sphinx/figs/snb-step.png index c4250643a82324e1098dcaecd26aeb7d12739388..73f55e6fa7a0546dad49a996530a7899e68665b7 100644 GIT binary patch literal 71950 zcmd43byU{vw>JoaAfRA?2$GW0DJ5Of9RkwbDIJPPi;~g;(j_1zB`96e4bt7+vu}Ur z%scNoGi%L%GtXK)Ab0SM>)QKM`wmu=m%M{Xh>3)RbVurim@*R54L>9#}ud>f@EXh zY;SGnY;9pk_S(eJ$->T-jE#wviH(8G+}YWlmznv0J%P#2(TtfB>$D9Ci3~|fOjy+| zX=BP=Q`P1CWcN7UfK*ZJrp{0PI7iV*I@E!8T_kd4^#Vsh!PRy#f|Zl@ja1#4%^Y{y zGIP2XwTmJG-dLUCeHW7ZEq0SbXUt&f;!21{QmD_*pjvOlr6`nV*{P?xmz$d_RZU4v zP5c)5ySpN)goIA$Wbnf+a_KlqKlt|UZcNz!hdCO!A6(~T%BWSnmaH`-t7z8TxM>KsPE{$9OMD{WvkC@jqQ zWM_88nfLvj$43gJX(CFhYHHoY|1J(4j=0ijsY$35qprI8!|jG^0X^?SJTANGg?O_R zgT8d}larGLKHr_cjgz(RWiQHuyw8usvj<9iF3;w?-Z?5H_yxcb8N4=X37h?sChB#0 zIFj_-J@V@Ee13VkmDKlQ_xH$ihdESq9FpG?6E%-03LkyN&_vt~QfB4NUdn+oKU zc>{EdmvggI*v3+0V#E*EhDgsn?%lihH7m>UWXB*&HeLj-2LX$|kVAkr`HLI0i1RIz zmXj0DA9B1narmxP*v{(ddEQ#D>yLH^$$YGos=d9vD}`VC{!jG(e!AsE1*1n@O1?(% z+~T5I!N{{mw~b9q@YXr$Z%82_&Rl6uSw)4%bt`Gt#mnotl9CcP56|wPiUO(R zgunYUWh~%5Mv7h;!JYbUITRA7=R@H4`SYXFva)KQOJ3KlNpd3^ z;Ucm#j#(u`;tsFNnwY*m8KZUu>KC|67pKdqr$r9TF{djT5t?-#oV&Zbnwpw_a+D~h zea>y(lvS=>eCx7u(e-SLCD?c&navG`TSRx9c3pSp9=UMW7u=ml}C_N#fK zhvk+^M!#DO zOB?m%*L(X3akoXH6-=0ry>wQUltx{)tV@aTqJN5Isx#MSb3nP4fF_ z>+8pV)vHN0UIyuog@tiTOC-T#tOdD!_$Jd6Lyx5M>Wo~2TH#r&>qY7{`FTH8q~M8P z!Txe}y~Tq{*UhH(nHh%N|J*AVlOhc6`O2AUH@&^rF0)UN@{U$THv_QR>RyK@(FeE8 ztGlev9gUe$GV8R3GmjX}u1ObGJDFfULfnNQk?86ep{`k2(^b{gpFVyh^M*Z;j=OT` z;pphtMf^TTpMjCF&$2v#ByRh>A*Py82wsL4mzPILMdh%+B*=B9;E0CG8<~{URquWNLQ3js|EX5tLk*3Q`ybdEHa4sa3JRnTQ}XiCN7hTe zeZ(>{d1HvF@L?kbKcquNAK~RpWngW{^!t8jPLdNOiT6A z-|g|PWIosaqE~zcg@wV;T8=ixzFQ2uXRbfF;p*zTvAIdWX^9IpvpE!her*lz5c~de z?{zC{NGr{%JBHGsM}Gt{&G9%VgXQq=o-*Q)E=kIFcO{Ogw>Se^Pm_3hdO~-U z&X!O9R#Cz9Z4z3UW|ciTy?TNE<=Npy@AU-^JeKahzeK$_IXO96>&_0ppYMuiSIt$v z2}=VGLQ3|+v+(@uSIQr*+wyTtuaJU5Lx1)5M!<`9oALGRH^(_!!U%qSW;MEnjr}a8 z(zyM;X-`sn!OJp|W1FXn^77bD%RQME16ewC9x<*n-f@lo=w(K&*inuuS+WN0kyISk zqaQ7Y^6rt4$m{43@wsjpLyiC4+`Kz(RqSwe;hy5L_Vj3brWamEz-D}Fs>U_jsP#kh z{bJfDYB?Af7<6B#DJgL~4{bN63sVk{l#CLdvD=!}c@JvWxZ-yn2IR;pD=W+DqNAbZ z+12j8Kf64h$tNHnFb$D@4p;p)CpC4;$#!f)Lf#G2F=#=g^hewE=kkT>g$b5MMi~O< z8)a*Qxhg{|E9UbKLd2|w@7j5Y`Ch9^ejv)t%gbwNZO!-dnEQ>Prlxkdoa(ENeAp8H zIG|nw@f^>?wam3c4|s@^j7*65ne}I>>Y$)oY8icxW(GVC*Kz@;xG(HahPDn5s}HR@ zQzuGfD78kA>aA2aT%F}(=0Hzlb&rM0mJprDX%%Z}W|lo&?>$k~J2IkCsMk=x8xH^^ z@tI8?ljgU-pIGsS{8P)$@s5wZ-Kph%Hg6oI@avEWzM1?=8Fg9R-j4Wr!t*HFLpD!W zVf<6Z-L4G;$J2z%4Ug`*(bNe4rSIE-V<66}QlGbASH!jpgiUGZYpe z^!GWyB9wf56J1K7Aq9F3K04Ko0h<$*08%8~+_*_dNZ!4B_o&l(YjSKMsVAB5!Q;p0 zV#kl+#=*H53}nffbGYjb_4V~3o@Pb4xw#1ip;@2hE-9(q^O1ppfdwt*x`W7)iva~e z8%G8PhOnF*+NjOO{RmRQ9{S?iw>33<*x1-^o}MW70DGbwaZ=FT<@(`QEh9`!OyAA> znoeYokEUk6GDrt;H{sd?->3@f2^xagIPgajH=Y-}ubD{M~l$*Pj} zde6>Wi6y4};$oAL5>=69QUyOm8V{pS2OnrOX~czY!3 zj)3op^Wukc&JYO{!kf6=Q>pvU#Pc~%Pp7S#MX(4NE!EZQ69gaRN!u#lZ{J@w8c4rM zn9O8XR(XAHmW*8}AEHKixW=E+T;_>!tgHNYD))_yL3ffL;WXlu7 zd39;q)rn_Fg!|Pphd^}&42v#s@)reu6hmA$pL0ejDJkmqca8dFPoBJmt)e@O!kB?8 z{*=XnmRak&dE;=Qc6c!ksX!MLPg&hcKpa1vw!^!I1phoKbKf^z>Wcpb3o1PI-1GVK z=Rv{2?Q!4urIUGGNb)Z(UZq@^*TT>tLwzT*c4f`9i=Y>XV^@1-ir$|1Gf*PDZj zmquLAybo7ILf#r$yfL&0Fti9ZvQMwKuk$TZQqr~ILK$;&TISjvkzm2NoX=33R%RLmMc>~}Q_EN9 z=H|BF7-fCPtSbxe8NOJ5d87@U!~N=Xd92ETLNbEHWa@{@P2DoxIuF{ACLF;Fq23h! zlJfG!rU0zlgd9QbQ8fDp0}4^jl_HHD9hfvUG}H;h|*_ zTPDlb*m=4U37*G?b*YDE4SMT`kJ#9iLi2e<)%Ld%Ux|dioGA>KP2zuizMS$aPgoSX zlhFEKzdfNtuaYTc2??ydgc6AlL{d=efy$tMfimcIeR=G>@~81Lt^jtSx)qxm+QOki zo_Zl6Y_xPZXNFflqM^aI^QO&}j7>}olo(0IGHOe}I{;`00JRH8&2BT!VO0I|r%?UX znUzF1p?INI`N>*-u{kiWHzNfq+1PL1ypfG(3#gp-2o?56o1LE*_3+>Yl4mqs>)uj2 zJw5#{FmNDG4a)ya@A-B^L|hzxUS2-}-Mh_)-}gL9;Iz7b|9%s+Xw7OzDkyXeFH3)O zUxw2*;Hoj^gyc9@JFniiwY8E~r0wb$6@^vgj>3?X>~PJ7>*&O4 zY?5Ybl3{8F|2JssX!@A)X12%Xz;#Rih1{=?u^|GScSJ2Mr(;t-kW-*=vOf@2e`su$ zv9z#2^|g5@u&L=u@zWpDc;7iK^;g$IOs04>hjT+s!q?36HCodp?!e_1Gcr>7DkH5Y zhP*Rj*U;DC>kGRhTs?nrZ?TiQ{B<)U1%f@ln7&F#z~Ku6D}#FS1P&M2>w||6)zjNa z7hFuQ_d1y^Mv90Z(8yB)A_N9le|>c>eVy8HH{CG`_1kB))jkw;hF-mi#X04<@>d}e z{*ILq`Z2o9PA+4mO;!|mH?i>X3AfLg%{f-=rYYfw3aa*vTT^My4R7#h6n#7&(SzTM zF&dYubMhxAh2pnYyWRUh^puiC{OpOkp@oG-7zuyEpFfI79tSIpfJjqva*w58Kfc3w zfMCB+A$XyG)5F$pQECQiOCWVa^G4pm${W#2Thq;L^{?Y?7AoPaFIDs3iY2 zJ-j_Owm?lC8TI)^PmGvjkq-I!T&nT4`zL7Ljw;GzT$O+INrpTB+Uotrx+V#Fl{l=) zY5DGON^X7SM68#oBbIC0%^y^Pd*KqIKw6>Evd5zoe0N?S4u@h`Vl(kf>PoC6YFahD z_LG30>V^Pv=FqXcn%V)E?MJ6mOrBtkHaS_!bLl6m4J1_bOYPJmL#o9e#eKL~Y=iUbuqv*Tc=000;c}pK4hRN=c10L$zWMJ&=?kh00)FWm9|iox zDLDP`bS#D>=tABGL_K&YFF#u0)lwz6*`~yFb}rb*dFScVui0NeUI`79!Zj$+=4j0l z$C@`)E7qM(3UAtAV`Jm?ILL7*_dD90*azGZU5zTErUv`*4iJXZ#W=l_t(xr|wfxxX zU-w0Vl*uvlslJ$(ukgNR>8#s)K4CDscD7R=)YCKgvOcVU-K_mNv5fkL1zT^Da5sb7 zN$}M$V?Pct_2nOfd4cd`;^A(&D3NuEJ4y_gS3#Z898~igV`T^1GpX!mJ@z1kjDNR4 zQCx}?Y&*{|>HjK~#O?6bA020Ib+sL;5tOgz4fJrY6DW~!sq$WU-3R5AKnorEt{l4iHifdFKFB?_2(ZKp) z*ki5_3WAroeoU`^>Db>8TVV6{QuC$w361+aenW(fw*PpC%fO1DUlaM)=3hO7G z;|1x@^iQaFPlcjmBQ0NZe$9?LY$bKI!rZ2QZ`PYW{p#YvL9^;dzuSy&CeH~gFp9vJ zWv0jo$_0JgUz}WS+a$hGU%w}b2Neyi|GS0C2O=Jkp*&F2)B~Pie4)J)iS$tJ^juFX zTAOMJU&+WU&}Myjw8GYAQbX~9ql7cZ`-w_Yk3vtCepT;N6X#yRKsA3fwz(5>pUXpy z8z?BqfV-I8)(b1Ui29-i%sD`gO02M%K>Q`x2*IEEJ)h;P7b2E!sbdfeJ;Af5bd*rm zei)$S9c%>edv4ENof7Jp^)U2T$M^M7qTh6=U+zruOna;`?VCEm_xhvfyaa~it1E;M zh4FxTXDQJxc70*nr_S>@3(mA<Zal6PtH}zMsyx)YwH}i^U#~DCn~x%folZ9 z-&)|~qNGHXjK3})d~xSX4hKVu{$lXtZ!ue&s}$|T2K1jCAT4J=?mw{gMdNc3fdO9XPHI=lnv2kHx!5;KH=m|==0pg(# z@lFXH92|tENeQkO%A%v9R7}saKRjZ63w(a3Pm&ZmD;B^PZnqt>r%#_QVaq)ivP2Tk zbg+{q#5|ACQ2H}m5WN50VkO1*N+L$j}_r~oX%YCFl@-`^j$41YWI%NH_GhCy0I+1lCyM%zNU zBooKPs{a!yDJkjCs0n{w=d`lCIt@x6gces6^=S(baHgu0ru6{_y$-h zHW9a9T^&ELKVvg9c857JIB(<^va*z{toQuFA9JxeEy*tRrYcxlGYAU{1E={__40d?;aTObLQED~}!2Da6$Rq72}yx$P4LkJHj^ zq}<$GICQ7eJ(CK%8F^=Cjwot5w&4{?F)Nr`rzX9S16l{4ygUgw1gPM01}1zxsy_VlRpIj?-VVF}1{5TsD2 zK-D?mbVHyi=lGqStrsWqB{>3q5)BUyR$^yklRZKSu;uqW;&^IhW~O2O($3Bi<#_+Ux&YNti(>33m0T zS-Vw@`idah4FQutXcKVZ)QO3R2BV{+Z=}{}SK3-CDt>IQKU^QlFSi_`TS!(Ox;#J5 z2YWz`k&#hNK|#Re7wB0wDdS&YjxFPkC&G>0ahnrqCdHvyC|sJU^f6EN8dxUoXViZEGjAjr3$ZY zy`!(fMjQ4yW*9TP0tFrW^We$qp$8i~JBX^SJv~e_JgSDilb+ja-y#zf~ zJ9}V}&lS8c01HerE zVrFIr{@GRQzW&WcvuBAKg<3-=KGX9X8yA1v#C9W56@z?VtgpNn($Gy?qc8qq zY8K^l!R_jE7C)HkOTFBm*?_gQ6#2uBH23@{ZFE$Bzl+_Nh%a{A0~9THndO)?H7V#q zC%wK`{&{(~iFu<(bUnK#$zy(um6?_KUi(1338<^9tNxX%NFr<7rF7(A&Ow+Zm)HU# zZ)d~xrJc2n&F;<)83V&@kk0c!`TV*Lj9n36P*190FKE@I^k_IZIEIFXdsIph8L+tu zUe&~|j}+r;Vy(bsk7qZ#>f=WO2}9V{mMK0y-o)|MPKPwwn_Eg@xb*bS$$ax?R~&?! zQ=Mr=D`-CYbUr=5JCE4dXM|J)cnPmJw0-xw{?srQP{PVop??2Jp~ zBPs)dc@eY}Aonk_{OD0|nm;>Y=y^Pk7(f7c0zw|>1v_cSsn6ZnfO;E42?w!$7x2J0&|19wg-A?6=Yj&; z51bFW!B42TV;~6!ViVuc2h`>Th#SD#9*|>D^*TrNe7g@;2e9h0A|i00)GVFs&I96k z1HvZ@kZ}`c#BJgV)MWp`?Xcctx44o|IW3~(IK zvYC_hNe#{pR=?ZLq!ibm<^8r)>+nB+(2&SwxAfSBjt&P43kxAN!xER0k@?lr^Fhz& z^d?Bt{)Ln#vx5i$SsrBQTy=D!F&tc~5h zy>vM5t|XrQlHtDH&>-Cl|#p%WNbdG z!3|Ey+spw$BywtMxu-v@pteJS`n$c|`}QVQ7qNUbxfOC~KbaLWe)u2~rU9_ykRy#V zz0NqNtD*YI$g#S^TyU?BMZM6GDcu!dB@b74yCl{g^ z>$Cj%Diw9VTGGAJaZwull9u2HG@3u0bE|*d6TvOJiS_VLy|*XSX#3Z%vlLPVTGUiY zmH>)mLJJrj9sN^kBJ+AZ(WkrV+?z8EseKuePC)C9wx(pjr9g;xD~@jw8v}L$+!uSmDzF+wQw6+FHY;bO zS@+UE36s6ZRy5ERe}zGL+;Yd(X1eR}@Nt{BzMNLLeBk`gH{5rKf-*Y=6J=ch6BX!G zM}j!u2$%VW**U(us#-JnCV&?HuCI53_1s0Q98c{pBxXUID@+ES$FH%mc<9FinKE%V zI%{`Z9)r-k`wK_#(Xq?gU@$-$0er}1X_wjJ?B|PwFpN>3TAaiigbMJp1fS{;a6e+aJ>j(-;KXzy#i4S+xKwA zXF+Li2CWdfD4UG?mk)Q-4<>)OV14i&{k?x%<<8E95@m0U;D)5dyLKlM_5dp0+(LldGzZ5`Qyqo|{5 z^~pIUBbw5)*xRulegw@ZHqS7lPk(kTr1N{O=Fy75mgG~{+h`~tGv8S5O>Lc;N(Sp~ zWRe_%9CP;X-<`JdU^O)pXg1bkr2#uTJCaPj=zpr6%-|-pf`}D%j@T4Xo~|9bn&m8! z0&>0-tc_$JU7T|8I0q#>m=Oha9O+m1W6Ivd-o@Sdb~$Oo)?~hmb&==j{rzon@=JRs z7?aawtzCU_f`sAkfd(P7*iAnNi^E_kNX+5?$rMH!EY>3xSK{_M`PT0KfLit^7_BEB z;EU3R7*2v990D}${CJzWyY-$pi^qZaGwacx(8=xX?SX*?gGU*~`4jyPp|P?jx6g$e zz?o*Cy*%D$96%(tAc@~I7U6+` zrYtQTQW6#(eh09Q&q8^M&zZ&j2M-YJ9(odoMgKdfNd%JdA*BYObs)AGSOQ>vnoKq| zHHDcl>DIn5G)&(;gw5FrC#G3udI!wEB|s`h0Ml@Yxeb~6Q5nRj(r7W&yga|SI4`6( z2qKZ{)<}owDu~k4zn@MV7gB@U@#J#U!I_xvGwa-5E5KwR^L_am%z#cCA!^~^>dNJ+ zIY$cW05xcopnK16Zr%}srUok3!Lbo+RxgMy!1C}<;rD##!4HksD3wJ+LjzENsJ%Ul zS#L@v#Fqk6XrwiivZSzaaC$3?eXp+ooiw06q0?1Hp%tTw^4uguYV995-LefA{Sr#A zPAKgS+G#+o_nTIC|z@d+DjfY zL17%_GX8hQ(~u^B49F)S8wY>*@XSffM8ku3bRyAAMuFKQ>EXkNU`5^~Bn*MK?d3lv z0_k*qp*`xf161>5;9bvbCpA|NAthxZOJ`$a^RmD-nCIcb|lA|gOF*Y7~NM_KOvM}ZClSnUJ1#b@cCzL?TRlA?okB;**x3F z_m8H2D0%Ka`Ocdhe}h>MYLeO3-Hzvcd@tlUXX;4fVA(?W;0fXj2#h|o(XIr}Q1IOo zqdkwOTu;GRLVRJ>eu#;|0|xP|-WC#Bz$;Bo_ZF>3zs>HVJeb1(O$q{n>9p3^IA+U{ zR0lt{Wp4d!Y7XF~kDX_8zb}VP{M&ublh!p(QhKT~qKugDQ?0SoCtk_WhTJ@@1p$MY z;B-HEvy{!P8Q$v`P^e$X$aGfDOi!l}u$!{@UU>m4R{3gWQLYuWD*lcZ5qwdSI;}e< zk@Fc3^fad}k7H=$=ZJ1Ozmkcmi4vj@5jji~bzfV#2LYX^VU1e zN8H)n&Drzx7~nIav;jN7tc$%%C466qoG!SafB`U$Z7FSa`cV4%=$pJcU5Swrl#a{p zMpui1!rVH01MuNSp~=oy_0pEdja=m*gfB)(HUf$IH=H16g+vE;Y!ThT!B- zUDAp?dYbor(SEg`3Vh@jFJ62UpAru^1mKUrtO*768xmoqh`h8!HInn;fyKSm^q zass`37S6Bi{?&kwpFRmID&9rfuHEl>K;w(_8WdRL8Q)w^Uy_cglmm-8EZZjpDO0uanWMG$^N!zZA?0Vu=mhb*zdmih!UJxW-$2y3PFCs2KShZp(38f6RAKftZDxSS-dSG0NXXqP;Vd&7n%a{Qh>F?Nm=OSXnJ5hF+upi!cgo zoGxMjoso1-*XPsICI0zXAom}b6M8ieBxcD~b064%|AoomyYB1zcdZ{Mm(_#gj_<`M zt^Fkj&sO;&@2Y}m3jFj9h=a|7d$9=p&9u59*^G}t=M`!7-?f-y>d3uj{1{8y=Md0s z@D+r}5QFBopOdpe%FiGU3n4=ggb@)NJ|d;ym}*oODoWhet4oKC5qyA`4tJ8mTUy>H zCN?mC^8!jU>fxq%7^AB>ROo-X->bB^7}w72lK1ZjPX7AijQ((;r;rF^k#Wp4FRzkK z^f+!tk@{OV5^@6#MFZbg$SYN&{dB#!|4x4x6cMza8hYN%K(o7v!rh{w(1QL1Oc@dd z5VZNsVWIq{vzA{L1Xu8`3v}xeATFotv6^{5WYnvFU?85?g$~5RCOACsrsp;{yTRZH zGx75BQpBa2IU9u-Yc}X(EhFUQu0?iKrp`qKvjgXeTZ%EOT7Mucek5>IT84)3tgO~) zLf|hh2lvq5flK@ss@*a$nK{rP5NT&neZr&BwRS=4|198rMvi65bsoZ;X=FS`Bw+gjQ!)rKd!M#R8MMrm9 z?7(A}q#$V?A14H?1+{u*AR7mALS~Q!p*Df=fg6Ov9h{wix3>p_?Bg`sbd#)j^*BaD z7g;Ey@AHL01!yh_Ty`Izkwe9p2V%!bQe!`RBP9Lq!-wxHE4jd-u%4{C=l4Idi?8(p z5EKam6Vnhd3dB$#J>3JVO4hI*QVl3*w|};`VILGHwq27>3qsS}+L|;d z{-3$*NPs0oMLc>;Mp7tC<)`ojEaEGzGPIF+cJpuU>@EUYQfpUwRj+55|M=(OkhZ9_ z`f%FbaowP84ho~!A95^IZ6_3xPRk8m!mnh$lByaO z&!t?Ir2Vy~LQ)?Njke6D&dyMvYblT)jb(aexn=*`2*LNk*80+(#|sIQle4qAzkh`w zKZ=e`^b=y0f`Wp8%i_5mo`AxH)I!Mke`}BULqH(PQywBGyYsCem>~jNAW5H`p7sIq zL%<7&MFIFgkdlR3ApHm@8CL2eNPU9C#xb0dnU#gu)gT0p!F7eqoNNLIhJPax;!vPK z7$SU^-@m_k99jZwB>9mLo}W+8_j=mpH6ev{EBi~-$#vSx@{%~M~7`x{dM)e zp8vPWvSa)POGyF_S>ooPS*o`>=cC(8*vlo4ZliHp>>6@ry>#NtvS3Gi9rltVTiSa3 zs1~JXg;1v|vRd{)?mrKkn~LfG>Y!w2J*?+fJV-Mky~x2;-*PxTKhM`HM8qNUz<9vS zAqXbJ&iRihJ)^RVrmjtU* zE`!GiNlA-utU>Zct^?ph4y5|n$MEmnOS9x4oIlqt*5yC!=9=Lk;d*pCudJ->2iPKD zx41xO&-3^9Pl$|E{_EtrJ}h?!6O(PM5^}ud07n99Rq}p-vRrOE^&=0E#MM)-gK}wv<2%S$d;|-91J4 zUYes+G3ebpRHOYK0E(Srn=|u@xHsdjkFU+YEqcy7I$EG(@3cDgMiIVbjg#L$JT!r+ z5MX*LnbLSpfkw}cjsom1&*EcUUNhBh_#4r!jWAbDMy-sO)5GWm5sxFPudgp6;deHL zuLHguXaT<(8<8PU3{Awr(eVj8`@rb&wlHL2AgX)s?p^)otpL#>6uijSib!#~z>A>o zP%ndWWXSR;C?bL@)@mp(W_Q`MI~U63O)_9J(68ne7F6}UU~MBd?*fTk!{xK!;NY*> z+4ydVv@y5u)${YC&H3^X-TC7g-&WYG)lSPx^j2VL!@|}CGUkid-`xooCgeoZ)6)@* z9IO@uZM?pmxn}%UOZ$V3>z?yrBOo|7yhO8<#tJo=qClTuNLRJi7vHcq*)wKHdS&mk z{R(NL=Jle-i(A9piAEDYILCai+RJ0;OSadH`Ufe+#FyvhnnLjCVG3v=0AH8Im0O`J z>m_@_2F`NF!Rq96DISD{-ld5;teoC=dB`YI@?C6bT}tqE(xlbMx15&`_V1!hEGKZyAY1{q7WgUjdkoFQ(Cd#eMHd0+15(2tH;}a4veJp<*mV0=hGfyK%Mg~i+Zp7z==88_wN*>3o*2wgDt_xQgpt3@6n?dFe9^1Tvk%@ z^x(OSj0^g%%5YsV{8KN z*Zgk&sYD^ujSVJ73i``vsz>bXH#1^ZiZ26P_Lr)B>(N4MI3X`}U--0UuC%4?-WOUO z?UKmJ1>^7X^4!jcX-n@gmON0&yP7&WLheyWuo(Wn%lW{$5*PLz|!i%#|$?eYwB*?g0hHAU-Ev$~_y8q<{|L2jJ z!dkkIOK+YP*32`9BuiuoL6rO$mF(`AXKeM%gsr!z{las&?2*<-G%3gcj@ zJ@k)>NnMM(531_SA_&qimZ88PymAYO8)aS?4yczUr+n@i9vwVt<76YCQc+UWo=7X)N znzr7jnCjFIgviDE0PhWe3kykva5+A_;Fb=|<6d>8b%XuIDLKC=|A$}J4l{9I?v|95 z89{}D9P}qJv*Q8Cqk^mhUFto|PDI7VzE4gjMhp!CheX^;ps)|_-W4)6T@tlI1$V0h z;)NL4*jXl>v5-c1aR0stbXO9OYbf<4Q09A5_(MT>1WarKO9W!SaD@6MCe5%%5MBmg z9dMZ7*RGF)m50ha-h?xvT>=m}^qim)73i3+ymP3t3RsSnudc38ID-w;5$X`GZ z2jQ0g3dD)4X(SbodA&f3e|bszvWK4o_f;!)=3S-TGtg}a_&qovpPIzyS|sx9CJap8 zCnZ%toauO=Y>@AqK`Q%c{dFQZPf8zNLGpbRl@ro7n28t23%WJx1&bXCFi4N(sT!P`|2Hw9If@LAG=cxdNhn>jiHG26$w#Sz{pt!vvK*`Qfq_& zmdqFT@#9^Xw|bZJ(-@b9jqXLXU|!yR5|SQ7xyHus;hOLj*BF&1t9DhcK1sd)=yJw^ zMCj=`Df+g=dx?Nul0irUOg-`pzfcJf(rE*6#nYhdfLfN;Pv!e@gs9;El!yEs2)MD( zJqfK(NwOQ=2by89uKLfli*mh=U5`DChjo1dX6~5vME*!830J()qyu-&ryi}j15-67 zUs#wjj6|h~I(WLo2py~}{fP>jC2a9qO3452Q6v;J2q1k1#t5;#XRh2P3I1{T;a4^I zp<3lgFF=QLVm=~U-ZCux-zGyCo!Vz%AhHR_h6zj1-E=V+Ars?4_~^Na=`f|Yuoe>YKV*|S*+Q!45NAX}=<={Hf%DQb!7XlSZoUc3 z{D(_EIE68v!G4K;fad=OSTV{@58w6|`XaSWdTy|sY=*MA72&R1Epr(qC z?);C}U_y-nyoME058`TSh<*yXa_$|H=a0md02M(4B;+vv3HBtWPR)@4q$V+L-!=w} zhcHYbP8p;4dkMi)fI8{^EdjMJeaI4lxczo7YkfT-V-dc%J)>7{sfO^Qe9l(0mEAvd zh=9=75ey0GyN@5s0Q(4cY7S1%7Z^?T(6gcQ!fvd2@Prbbk(Rx?5rJutK+}$j5$@^& z2M}01B3J-R8!<%+BdQ(+Rsf=q|3HEb2INXADtyv4VGb~5r8e^6-Mc?Qo#TPg=6WN* zQ~%{p&({Nr1Y;q5qHbZQaUOWd7x2>#)`mi1L@e&aN%i5sMW2&rS#bFnQfH7^;B*pO zj7o^Hkv+g<`VyHKEp}EipNT&xT6?yZuL|WDf^8*MBTR@3_y0C-2Lpdd3!InrdmZ#h zfE=P?JP|`H;KW0)E)8s5FSt}KM)*uRLQ1&Mkav!bTHwDbb!SM0L1=Ase0*+csRage zLE>dk(T34Em{)!TgA_2$1A{PdWeB4_Gr#)r+YcGV-qBGcdteqQ5;Wql*8h>Xb98dT z@`?Z;;2#($Sx;!CrUp7s@wiUbvwxAlAU#1lv|; zdwb)^2tJgYCr_Sm+y6y6IywT1_bEBK`*-jI=qhL|!*0m1I6py5gbn0t#Oec<4MB!? z@82g(I(0-p4I>py868EW2ZH}ITL-F*!`^}vTrUqt}0D0mwKx@gVBJq*vbsjRc$yQ$P(Z@n~>dk2uWlf^$GaP5mCU6=-mV z7e?R7kdcwS_Pe>LgUw-Z3q;)81Z)ezGfs$!Pyk%1Cxmmzd5Z94RUx?-FIZe@MR0Rq zk*dSM8(>bxWrl#tY#wOE0fl%p8!sxSm39|APJa zS(mY%nAp3#KJ&0`JFvC}0qPF8P3p7c^z`(sK|TQ{=Z4^FqnD&BaMe z+h#lim~aTuYWC!F*TCmc1!d1c&_K+K*kBH?IFGtl&@Z-OjzEAFe0bw67U}5A8|NYsht~a3q}P`j zyXE`$&H9}%A&pU!!ZqvvE4+BUIHy-{)pwCTyT{|=<~Q(Jp-|?-_A(kPHPO`6{9MpT zOibJj6bd|379QsR!QwWyG293E`A55d{WpoDQApuf6!Ym1BlqEGa2XmJY?^~UyWY+WAy$LzF zC0L%;)3xym0;iOEV*tAP>O5WN*ROl0y<11zE|H0@Cnpo@L@DoysOAfc1@#Snkl4(r zdz$8RM4MTzt!*P6mZioho!fW6j8-i~I#}tG_!HyaL_Qy1O52;{ku=p(NyqDlwQcM@ zr!Dk*UfcUg`~31eREZ?(Q#D+U)ky~j&cI<|)K;ZvTaq^E29004+xn&cj2S**oqJ&eTP%V{Jf{EB;rSmlw3A3qc zr@Oklb9L)@ksz$p^6QsB2=T1OZFkAeT`WOXbD}bifWalf%I@fBT(a{+9~f(KB=-E# zH842YtWZkn~LB3&XCRO+83+kv<-CY5n!h|?@iD_?2H;fqWbd}&UE^@*9 zg2s#RV_;NNk|}Ng6jHMuCuiru%S3_RdDOn~ao%2E(X_vqNk})iz0NG^Q&*@+c~w6b zq0W|nRnB$1lkgC;w_^lfoq@)5`a&mD9~T>2=rzyh=nP4W!*!9NWIh%*!=yNYW*EW+ zB@Cg`Lt6Tf_`_G_tgHohS=*0%_dHlug;SOZ+Z=JM8u*TE)8;zLNKsHgeQAOG07AFS z%F05_Sp%e1NfWsVli7PiA0SALN3XsB`V_$M;~2vnjbaiAzIYnkIAnv23nGjSjgbHN zsXlC2=nF0M$9<3sf~E+|7Yoi7A++A4(>^RkRf0RGaKi!Pg7B2SORRwCoA5D~`rUUI ztJ8ISh*&0I{4?xK*^<4(%(Fg$&-vY zAhM}I)Mp5P$1>{`Z7Wim*&3%To2Ik0A6I9+&pPGRzyu){F7~>v4J_X{5R?WWF9EKw zI85`=$S3I|(sU9MOJhBdGm01V6`o8j5y3HOXr27@LEN))jIryv(IFKqp$bi@S@9@A}H5$UrLnIhdeXnMrG$Hb62!Ed0 zT7x=j7uZIr?G!JNlzdNVx@d-*@<`o}pNU099%ol%#}5_j845^YiCEYluBkzg0x|j5 zSD)h?tVqUIO|&m@r)29734Ht1zSw5WrZemtu=#T%zH)6eaMJdYB)-yil}F2&s}Dj; zD=qdIXBmpL2ze4**(cC#*xA{A&NsQhK|xp__D)VlpdA|<8`tgx|An{%Vqy_8&5aN~ zfeWz@>N|w^&zi2*2XlYHoMJVk4`7=#4-7 z1uJ1D9%505s1~3&Ay^|XVXRUuPu1OG0@%wFR@P5YtNHgmv}p;9$3-SzimbWmkBy_R z7riQRJAUspWm$wns(w1B+k>Cc$CvxI*kKZQEX#&tb+_p)09+ zY#!A~{XvQOuxv3aCroR=Oex~-u|cAwu0{DSjE+O&2Icy!iPiY6;v?oWo(IS0*SLAu zUj`<5a^~iOcSu_{)dhYRX@#?~N#~8irgJ$zvVnj*_D>ijKP2j2Z!dDSqqEb*apcJv z61#mJRJC2P%9#a_0%eSzGAO(0Eg7yv+I^w*p5)xU!-vz{Ubn0S1@9kk%+5TsxploG z8i`FJMvwUnQ{)YUPSstQ_=2^vb8s-|%3aJDnkDBjRf8U%`_#PrcUQ8^0scPHpS+>3 zR}Lw^FVSCI&U=+Gkd6SzSQMctU7n!nTd;ut*9fP0Gm7{3fEVz;~k115l&Hg|Kw`I4r6mVc|t(o z9S%`jomA8u^|hw@*^%lOXixVJ^ z#3@bH9*7r}usY%J&wz#L9dJ&AlAfj|%Q14VF2X*IaV~mpc;--xU??ZvYoLV3LrEQPU z#VFJ?BuJREa&Y|qDYW;ApcpSkS{&dqR0k^fz#537L`FqP$;(S*DjOIZzx(v*9@JUY z97SZ9^o6WCOsaCFylg#;uP`#&#}^gor7wW-EySlERV$bNUYa*)huIe0AGhPla8ehZH^*MP1Tn!<@cn7M`K>%kL zv`9zzSO&-{wZS8ZUA%Uqr>zjod(hdkK(XSm8omuc6lV9GTk%eHA~+hB@me5#^%BNr zfu1abT=jJC>ML1XC-8(mywYdv><@5mqqaj*501`l=PxqYRJ{e+42T2!Hs0&$ZDgbPe{gpln7+5_dmJfbNK+q1gjmPVR1^NUH56@}56To{& z`N5V~ZS3j61{Me(s-i@T3n!7LN(T{Q3c$lKOysaV&5uCkSXdPBaRcDL@4)9;d{Lx@ z#4s{K#DRcI?V=iKKn6wL=g%9gzP;p?Wxu-eeUz@*|IW@L8;_tSv6)EcN__>GgZ$f) zTI3Vrye^Y4-026U$s#QJ2ZFCIobDeR)4a30IKz^Np?|=C>;yeGnsiBTMJO~f=Qh*I z1kl0HECx5=BP!5<=h6N~&(R?f@M?ozd3tre%>#pTMMke*zeZ%ppa-Y`S%N9}9L!&Q^PxN6g7ppwlt zNf@05_34U|p+<4qxI#^4P*+(`lY! z*2Tq+H2D`u<%Gs;Ne{bPvz(Tn1h1C>BLkhg4f+h^zG?gGQPUXiB954C{Q2q1J)&&i z_b)Hco}b=ts`79tO*unlyd`3*=X=Qs$A<{o!slwO^AXjlt=X4RDJ42MLdptE+3=A}?-RE-kW$(UBS(>EM>`otA+C{4h)y^N4u_;cXN*wdc%e~oZN@8@ym*NB6)piKU}{8y z0S+zLU@>G|z_3lUYdcvb+kKMDi6{|BJpdZjgW|!PaR6Q}RNwX-8%2AkkMC=G*@C-A zg~H9BztS8M6B8qVY^6mbC1o^o@eVs|d+H)p|IxmCWTZhK)N@U*jh)|pQ>SON#dvva zpYFM?c&@Kp-1X#CE5K}smmdr(Fl5XALB`7J&5bnhsh%T^yGigtG+-VltT7P$_(zLu z#>dB-mDs}xF7o9~#IKI>!@0G!0$I--()423r9Wo!E}#DamYnEsD!eDTT&JjOb;4KI zgLt$^TM`EcR~m*Vo~Mj+&2AJG*dg=%1IM-Xo>*N1<>m?|~R^~-BD{T_)sK0+YXy|=_%CQ;O3cg%|4nbqx4e0C>k_BYF zCzOC5U{FGfbk(jQdcULK@>cXBBVZ+ktzWYk85w=#<(pOZWvS-jjSHCN^trM)bXka_ zcH6FzzC10WS-6n(m1qAktAS%^?r+26iEcXf_rBfa*{$(BTXbdo;=7XyJ%4@9%cuXX zxZ}c>yAJf%OV8IuFd=Ax4ovQhK|~!88FidPLVZI?NvWGI9f!NHFK9C`@TQ3aBMk*a z287iY=zcBd63dbU=^m|8Jz7^h*S7u^3jZccXpprO#-0JB0nwnPK z2oZcwX22@IOaWL01-=u7+94-5_bj|!D7PAgopYEGJR#9EeCd$Fh;IXk$!N{bBgO{& zuX2q)9iA4czMnU8?BxGimf~IwG}#4+XPBIv%;CGoNhQjwMMh<7m`j;dWzleLv?VSj z)lf!>Cn$9GIl#=L?tMFIP~R8W^g2+d7&9|7kz7a*;0>MiTa1L(En1@bbC*2^8w5`k zIJ;_>s=o_=sCiVu|NUpLKgJ~`#l0_d`3TJj3A2+%yf1|^eJPyF6|=QbA5;)2JjtW=oo&p)c4s(TFoAkm#F=6dr-(w__|>gOu71L zS&(sYG0~L2+v;1GsC~}2l;p-wH%qQN38ah;gmXDBKB?`iQu^gH`6&!{{l$s)1L#1+ z7&vMvlpBwSFevG8a0m?JN$VGOmO^Gh!h38wrhN%Dig=@;k0BAG?!KeveJ|9njNVK! z4P=atrek;~yiLQEB~5Hbc}FD!gI}Iu$@84UCQL&1W2dT>eqHhPH2@0_bPqyzG5BTa zgSLfoCNg1i`=xO^QDT=e|2(b&!ifUx076Us{y|Maj5+KI{uia4DW~8TN|yKYOwsY& zuETeCSnPt}$ukWH4vXE3d3-4P1`S_dWkb^!<6}`&&hwV;dtL{oL=nZ3m35`3OPYav zu#RWnR(`75mNyGuEx|E8*L{;384-~KS2{*777TTlXZk)Q3K*%*-Q6Z+W0P(wtT8x1 zQWDy(bJX-nRGHPs{=IwuQqc?z#b&!4NhK>&#GMZX5d2i}66eu3uETNZJ>4A#uAD2O z$y&B*5jSt6L#gu%;9~X>(wo2~`dq%SoC*l2YOC%nWimf`lH%71I_)wp>x&wMR|`ln zpR_a!dRk(@h792Eev@0yqf;(9cR|F zl`quPLw8eVdsqR)Kz;yESOOmIPdPTNbj6@dyjOqFX%cb>bS|m@`xo|`6dXus5qJM$ zuv8{D`<)}GJ?G?^-%d{Lm!?dvO2&S+edq5$S-fa|8vPI4&BW{Y{l(+=aocOBazP|g ztSA}-6#+wLJ(&vM0+AtwNIOVC?P0RSuV?W4NKdqp5J~0SaS6E%l!~-;EJaX@F4W+T zg6}Nh?@QF?g-4>@M>?JmJwRR#1ULy%nHL9YwoGrA_B!>iEsdQ$eQlWS&^{?XF79hj z`pHYbce50C7Ftgxt$^53fwTg5`XETxp-Znh8J~gEicd+=`qfjGa^&0|f5DNZ>S zC<}$vAiP?<2M&Zlzm<+~lSsfJXB-^JHCK-o)KK61zHly{0#)K01dU;a1$nrKBwfE~ zq6}N0wL{JwA5sl~8xyftXYA~ChErt!#nAJy%s#rLL>wGKm|GV#a4-qdpmRgxNk9#_b_Z~C-h;zJ z^z~(U`G{Z%L==!9E_CUyQh+a!FwRoO{(YC8OwL86#((&50_fr`-|pLJR|1#(1Y#P~ z!aVNvfe2x zcMCGEC8Q|Nw2jkOc`{j)rG8QTnDAMZ@>)@`2O z9~{w=SzylkfXQTU-dkN*ud@HDruuy=I4|2@xlJ?$>Q`{9w1zn|togrI?J zIlOvESXkP7B6fu1l^Pj8mD&iTo>mp!)C>#^uyp0)>zPJ9#n*#zZW79+{=lWv1t*+z z($p{Xk3YE3Z^xhDA;}x2=Hq$L>%XwU6+Y_c&z|LiTqhwy;$`;`)AdqBYKGxg6Cng7 z@bl#X%cW1)TF^=(@izGP8qVM|pBZbn{wh5{<|vHAgpr7Cd9Lm-0m~v4BJ)b?r%&<7 ziok?p^3PrH=6}9E{D7N8m@FVagC|xpD9W6WDC8o83*x5FNPPrkenaKt!=WuITmE@Z z)z?b(lW~e2%e65_39`f$NXM;o`jb`_1yNQwOf6^#ydLBvx$TTeXbOdwseoiYib{N28Hp&AUu6Fom z(e!iHuT5(GH7ND_OLTt?iSZP{?dBi+nCJKm6y52_66b zrB#gM_RFV*niy)nAX4>n!Qs6@n|huGbgAhnf_o20g`Y07KsTezuMQ(K5rheKTc6+f zepu0j;uRGP>*~n{+?_Q{&z+O3d4J_(Z*yzFZ@(BBNL7c2x#Ja;`FQ~a%r87Qpo!-R zF43uee|6f->ZrT=;(Jln`TEI&_P@RVKPoN9ftXp zT~lSwWB-8`8XZ`g9Rene<05D%cAJ|A1Z=XqKHdWmD%r0yXsicp3eqrQ&>drN_Yb$G zyMDL)($pRpsR)oAz{?(;EPQNF9UWs@`>bzS9_y?$+qMy1s-bdj$5S|RNnjkWy%l;g z_(&gGTY_Q4Tn_8|GH}@ftMbyScl3?cQr&hICo&{bc36gmp8A+17S|-5k=opRleU9D zsbWw{ABjx%IB+mbp;yYbj|L>T=F;5KQO-udxn1i(u2H+P(D3D%$f!mDj~a8RfuOv|+Vsqf&7=Ac6y)SjegD{# z5WAs*0pTxO+^oDwRh6-#Kl$AnB|#DM+Hgca27IKymZjD|-hZx(ibI0@v3Al_MFaH! z@Pnr2X2Hc*fEP>f?h{FUnCYy~2Wp#8QgTjh1WF)6EaA?LTWR~$PZer+ddCUw{9GFr zKZ8*eS;frdR)BVVE_!%$_-HQEGcu||v2n7nlZeeW?bn8XytLE>SF3Yd#=9Tyue+aq zWZPALS6j$rqW&Hz#`KH~^eIG8I7CE0Wn7ipW8wp8tfj(Ui@N$ZUjgLEG5*;zEJe2D!2zuDxydP#W&@Emz_+K{ulG*yM9{(5C(RUjfZ` z?d`D~FWiw$dIy22!nXsJng==U_lSJT;J({3nSPjU9A=j=KiihorylZKel#cPlvWl1e+u`~Jw6wKzfWP408Tj=}Pf1CsAgxT;!OO$rfS4Fvu>0_^ zOnkcTT9*yO%S(m7)6pK22$#*7hu}RuVc)i&)QJ}legU+f-*))$@Ch2O$pK|{ zVKdF;IBt(0Z?-3}9--p+8S}FvcRaKBlpyuyMXKh9{DP0ol*?dy@c7LpzG}vg2C$5{ z_9bBj?9YCksGghc-d}~cU|@Q>6?(7;Z*lMJiA(5tfj5weDe$Ex7YW-R+YEh=lDa-D zf62(uBWPX^z>=D)>!ZwECh`NKi*?3rM)7J2pRX0iUtVM@aQZnnwvhlxs5Lhw@J#pUE!%ChrDr|8BK7mV>Z7aGdZyQV9>#kesM@!S zGe_xvS^#DKRRUnZA;mRpN8}pF%Knt&Q6_^pV;J2yp_Dr--a#&HI@Fh3QZf8}=Lmo3 z=G%caKe}NO#b6oV$^A+~!hwO}?w`nU2eFu$jrGjw6dK3>X;VzTQl0z#;9;?vwG1E4 z>VW0)E*=iK8<;j#+frIS_@rHYa7KguYS~7LS_eh;L&8J~DF{L*b7u_Z9D%+;flAw$ zxjr>IdVf5eyntoz-V!v;x_WvtX{pUV)NOl)OzYm$9l6Y=b(41LfC>QkF6I#9~_f!f&w{ZUM~eha1*+gpu6=2TfcKfQ?ws=+y_kAB$aLaK zeT!!^-jHdsgI#I15qoiz^KR}{*V>yagWQaxEsC4auZbCttT3KiQ$O;hgtkL4sWB=l zvpm0d)~1f2Z-QkLj%#HeYvtE*5y?c$~m%#=`kTQ(|TlG zQ-ZSHZGbdQ`M2xBi#J!!SiBTT9dS7CsZBd_v$c^b!J7w#V#MN%XbEcQ?yzs z21eKhbYrnCqXZU=sgwA24*(lmq@noi_2>Y(y#M=!s2!xADXI3Nrm;mGv)?o1R(2TC zT^~0?%t+SN6#=LuMsP~eOOE#BaWye0Rc_guS*Zx$LL=42cv6p`lnW>3w+M_@$zMGV zip=hloSf_qXr~CiVw8XH;eb-uEe6ulUq2%M%~WxZMf!CwPDM%xN8Ox~vhA{ox9HGtzJ3S|6kSE1)^#*ifL>LN5+k0^Q%NJwf@`G6vgi050sLD6KgcgtFqe%}-hX1v8 z#LZ`)z3$*t`lo|iJyEo6Rfc+?FY79BO6FYMJW~`-U z_1vY)>nrwM#WP+prSJ0EFvgmETnQc}jZ=EnD8tiI%U zHvdG%N~;pUVq^XPiFf{km&2&HBYlI;Kg^!asqH=w|1JPcuI3A{OHWo~W` z(k}|Q;vXnBFG9L@a!!q83+W7ESXhyM_Qa+-`uu07p_gtHHANxJA|WA-+7mZfm19-T zzUo(;c^j(Bmk>Z7&a?TsxT`4aXF*RO>Cr#mCtXFnM9;=Wh$x6iL|Dy$q%7?J=mo4V z62Hz4HV_;M)wzQcaD0#f41g$dFCO!*tP}5EYcT*RKO1Dt>Hqb7;7xw2;y3N>?anXo zOeQuGBP0`)=6u5+o^m?CAjOfr!yH;n5|krvJ33Cbb;wVl+_z>aax_|xzXX!IvQv}) zB&JtDeKqi);1m-vL5t_UtkJXAZ#0WMJ+qC^&Hc>x%9mBgnXY%4Bnh61xSyrM8|={^ zkhad85_LU8(cac6UoOA%p;qO^E!^Ui2K?MZLqq=-zfWf^;|Wa3q&h1E{EJ0rp55vC zXKCpHdZCqFTKpjhfZhuYCqj14Af63l`EO^3i`s>6nYZSQx7M|nv7%o;bzYd}%9YmF zKO>J^qsUGs{&GkXk3lM8wTc}ygohML@wmLKTHfH0kZ(a9uD1Y*ban4e$v$x7<45Ta zspbzc^yhUyKg$5r*VorK@s)iuZu6L9E8&39h9T61=4D}jyg}#(7>&`odM^Dw-G_;r zz%hX&{=1=}WU^=XHOf(0o56|jch3vH-FL(^X9#@38NF@WbTOpu(DexJrM3l*N21y% z77Nk%o`+*uoQafzN!m**J`mCHKKa{%oT?hMRR;Wwgw;G*;g6&>U8a+r-CL;TCOQk5 zgEp2AlD5TgIR8m6cR1hsuXXvqa$Af?zW)9{Ww^2>QF^xlO;Rc_ws&(o0gLAq zDfg=zO)|r;&y0Q05bD^Wih^2^goBlskl8Tf`vcbnT=+A{AyT1y^?ST~S&k1tX(U>r%;J6=4B9RBe1Y z=zPG`V@nVl5Xl1~BGG&4MIQ^HvszoSDO#6x4$3yT_o1-{oZ_l@t{>y)d@MC?8H(q_MOqM^Nq)>zs?Ip&@hS3KeDmP#)pLn zE(~a<2joX!XYof939i8H&RCJRNNUHEnp<1jog8CUjk>?*MuoTUH{#{_&qu5SLooUE z@jl@DE4z5_q5^mz*}b*3m1@ThRT0qI(GA=M%5g zthKJYI~m{`(eNSxrwQ>r8Y;U-Ph!Z=XJ^kl{hBIR?U~biVXMY>#Z^Na&-KL@Vx2nh zY25^qB95HRGimr$egJ(H*(_AbOvf z1=+pmn1fu-_2ryYpIrN1%RsC%ina&`{05FnDQuAtH()Gb!pL~nTR=L+#PVN^S93TO zw35kR9)|E8x}6*rsafq!or~n8e-1RbR1Du+IB35cYFGL59T{QhU+)9>R8>{Qamks9 zH7M+qbni&AsG@;AE+y^)n1h3O9lHd8GXv4JU*!3 zUB|>%n%1=F{g-!Jx4XM5s0&dQZ-cBHI%eF}2Z8PY+0&BXGl)MJeBhG&!^^WI_4_<& zS1r!2sd6$t{=cQs*2P5=dclvp0|J*po8md~0JF#0_yZHoBo5*ZLDMH}faG7jdWA@u z)T!e)1jXaNAF{~N)7Nlv(JZ_7jzvcHr?`c(?-AbRtNl@{|Mu|Lr0k*{3 zt|0#BIGuJS)Hz$*i*2guwO!nCQxN@(l+28swMtd$;(FueEn!l%z_2X|1K!g_(kM>;JT~veX#zoOhSUhr1 zLcp4|IW0R#(xx(Mm9sgX2Mya&ussQ0|M zPKf zEyM#yK0rm)ar$OyWCs!T3Lx13>tVWAo1AwgiU1!l0J{cXtmH&?`q zjH#ck@Lrj`7r(ak0Am(3%TR?jwziHCrrme%ju-#IHn|~eWW(tv&?(4P{BLXct`nvU z;5N1xWAU6H8f2?H83v1C`N8tu)qk_gI~yJN+1MUl{TuGPUpSEpN8a7mHW-#p0yIRF zvcUdl!3n$e^94Lqq~xo2u&TUq)VckstW4O=sV*H98pd)cOn1ZP2Dw1N>B<*X@9bdV zgMO2Mw+Ww6;7#t=#0^IzI%?|aIijy^W7Ds^C_XbntMorYT#e;EXW~u*C&NP^g2X{5 zwi8PzL{2xu_QxM_w+z=ZZS@LGgZW{PR5|99p=!G@rv>?@SC>x{n6qYqvEb>!aezZV z126o5ieRMH|rV=4sh-FtTB{1lu?CfN}Bfc*@baW)Ow1`TtMx+NLMBdKb zorp1AV2#wiUkghN1f!5T(7fr5;bbHvgvg%|g^`RVFgq zp$im87xKdc;0)SV85?;;>Y~{uM)57GbaR7P+r@$Vn#kVRvXzn!S;KgOR5UbP;6y>a zh#h`FRmq6Q(6V#Bq2lQ_b0sCD!CoRWQ|@Y6P!|GXF0G zLS096JF#m5{+)E$OA&B(d_pi6Bc)yu0ORm70j&*GJV zJiPMgul)mu7GI5Jg@kN@O$(fok$VYM?HN=-CwRq)@Ki4^FDyjSN1=r}?%b34=dPEY zBqDU45*U`MTBn^$o>%=FpE7K^!Ci0|IG>42QOfh9eH?6Tqir6M(a`9c^mY0DRUZ5DIUbD{HE_*&VHz!VhJj8_T zU>ZApSfC}lgC1ybVxkdOKW=2s2?+U;AhtdXHx>qLf*S@S0>5GPtZa&|deSdN&chO9 zkMGQGY&AeQh0zyO!6+VTTZB3$JUw%eiBGR~;lYnr8_&~d5aj>#9CJrb@M8lNObp>z z89DJ)zVj|IVm6;60&@{(Idz0x*|!JxXbOUN!TMBeiV~?}kn{!)Ub->bVs!S01xd1? z;QGR(B@e{~5DJ$*6_J;2l9=`a?aQ9%&B7l zjkO!c)lprYMOIGnS^rZ*UI(?;cQQB`-~ZP#1P2g}AHG=pFybNa+CT-=#P=D9Z zd-~Yr1O_b$YS{^GrVB`sY;0`2Yi((_=BukPMHV}|PRp}j)+(=rM&;~fPo7e2lRgVJ@FTu?n)&H^Tmg9|H zrL?55Wx3m48I}U$^_KDB=E}u)K?ffOCj7{>_ypFU^nG2=kZ`0yZ&XWc_S;z2m=TJl zs*RN2P!LFH0(3I~@c1=!56Q{N|BV8qRLS>>ytfDDrg(3uf_d5XvDyGb7aZdOy+V*w{cUU(?<}eO%)p z@lSJamc*VuZ7rh?J%+M^`b6WPcFmPUuxBi9Bdx3ibs)F@!LBY;Y}w>67Ro zaab^;E?eL0du4ItJbR2+AlLF%ga0A%byIeO3uFHcqd_4hlHhVNBM{C-Tz;B&*0%8H zx#SJ4`58)bQ>p#NVTVTQhoRicy-rsGyZ}N(Sk%FQPVnwh_C1A}bpUcuf*pW(PAqW6 z8;yG#3UM;NPFN^KUt1TNBzR7nv2R0HxBIaBu{+0(*)K~EmR&~61mmd^SkzZ|$>9d) zJalNM7d3NtEWQ-Z#62KGiA9mn`Z8gree?b)V%hO~QRw1+3*cX%#3Z7|m*6qhx)%r| zWI2Zrh>r&Tkd0ys8a|BLA6LmA?>XfyiT|a|QpTAmvVD*6K!#7>Ae3f=&KjyZ0tQ5A z;5+2K^5XQ68!&O`|4o-!`(CwGYG3uc+v>NyE}(+pu@hL@o4*-xac_~2y(Jl;K?H=W z!xm~lhn5y{Zt`GaZBL4Be&Kdtm97|8t$p7J9zANaPILhLkwj=G5yye16WR|#2#nu9 z|8^TkJH#!(Hb$6c-v}51^=_!JG-VuZzQ*r(AW;nW0a!^q*uO`A)7oOqBJ`Nspeq4? zkpEJeJo_G@;Q*#a%vvN!Cu<=cK!|rK;0G)>OByeWxci#xYUey;)fK>OaO~U4+CT_m zsL+vh(8T*9^|SLq^NSfVztsx@_JWu1+nK}~NaKxq*U)ei57HCqRBw1fz~#RNZvxH3 zGwdMp2WB)aPNibU%fk~31@4s3C`1zzhy(?HKy)gOjtjl#%3P1&R?m&N)x(;G6 zOax5U=$fxX6-feG2=0=iv_TZv17m)-lZr*rWanPI===N6%`ICV#>eN;n$T(A!gn<^ zIGFw273)$A3r4Wf1kd7h=~eXk{4bxw$ffe{-rI885#1@D%EcJQA5f^7kkPJn zj(_wn^x;6wNCD^*f!Z-%*%8Xg3(p7=-_e{5q2(v49W+tm$Ye*&CnU0HoSWwT(NG8n z29!EeG}PxjeW{U=ss2TSyFLH@?qe==Pbx3pqSdZFCs4e10XhdRwc4Am@$y@uR(vHS z!pO#XBR#&AQrs=}dQnsCvFsm-dZZG96+zeVYHj%@{Nay>jPQPqJCk$vBnZ$3wliHN)H6RC@|AC}oZ@yk$`s(pi zTZ-%*(g=IQTNht;5QDB^<(@|qtA>)iRPkWyD-4-p8V)kOggrkYIXN83Xhch=vm?}i z5#p@~qNNhGCcKU$GjnrdzTff`gSx4kk&|t3i&RLXr<-RS_c0YF4$;%?p$0Sovv0SR zzd%RVj!Yn8og(B`|G8S)pV%nojDO&^ThhE+7cW}l#PqcJAFOiyxE!Za@T7^_8)NPaS00K`20=5Rj7=^2x|67%z>J3)Xcf>2M z88e<>rqL(fXh4=sObfNcz>LCvmM7pyy;Xr}Sbw%P7*Mm(GbcTWXW=Rx{zWECkMcuUTAe;x<~8rz`n1vf z#tAwa?f?AJy~**J1JuQL!A(ISXdsxB4p^YOYyFg9QicCD*yWjxB;|hL>AqM4d zrS^3+c-Rg5++P!$@Myw#vb^TdX*ud9i){h8kDbOT0a3v+L!)uW#<@>0uSj?`U!+p;Aetw{TSNLFVOtYyKNIw|$Q-r>T()me|33+WM`o9U&3hzq~Mc%r~4hAivA0x+Wq;isP42Q#PmO0k~d~ zE`=YIP&|M9`0=xt9Z)nzK#dTqH(+}5gf5EN8kCXX4?zz6Uy0L4W+FA`e0hW<=ozG5 zIxp^H*_*AUe>Z2lvabO6HOs{dXpiIfw6?|oU_dCA&6aP)A!^^42QQVNalxj{Tga?J z5KqUinJ)zl?r#?MfY0H9!wQol&fb4JmZtx=W3lhk6qe`IEQHGVIVx`dc+f(pDP+Vy z`&7%z%RN^9o<$?5j`)PR*G~XbVMzf!f{8$sL4RNO^(*#696k4Sy0hw*yyhHvJEj5& z6_w0yS)M;7)!mH~h(Ei4Ab-$MLOcd!K(%B^5iiIW*CTk(D^^@W?-?q4O33??N=jCu z^IZsaCVU2-qcl>P57%97ZHX9`;AvVl?fY{{-%Up6ISy5iQcWK?>w8W)7TA8GtovfOF)5~2BAMPNVgsAXS z$X5AYx?uQmiMc`)nB^fhC+Rxs-d3y1;)yOy-ycN08_KdH)n#Qov3QBIFm};3ov} zn7UfpxreSg8bxxK zRTDC!`3~)@V>pscp8aYfcdQQ|xcut6EYZGR8fMUb@?Q1d#_II-nSUO>{;wC%c;6+N z6j5=kILF(2gpq%al$Wf~d_K+9(PJz5u=_!n)5|@>PBZEYKc9L;#%GUyqb%(GSf!%WX!S zcsX`(97{)w?TH%Jo5{kwftKJu8`RM#pY}^$i~oNTCN>|7Eii(>Qd3YGOfs{u*rSz1 zsiD!Z`OGJC@TBo+(p4X+FmDU0H!ta8cYWHiKQ4z+Ss>JS@?IisK`0{=_5PEwTshgd z$jA)uYsT?iZ&%TwilyUJ;Q97rex0S8m*>m08-4PU-`Ih}UQ3x?@6P{D@oH1J`SfX` zc%hx09mqe$j@2dUs;aZqj25hsEWuqBmmUoC%1reB=#Z7k4iwWoeqOk1+m5`(ImbJ6 zxjFHCXsPND4~ta>X)RSgGnoZPhw+k26wQSd*(&{_&Pc`FXR$ff70~K`WzYVA#IlK-lc#Oof4*Z4gP=057Gl*AkwUk| z?Pi3e9U?mg?J1)9uN>G)XE3++AycjU%h?I{AKI5TKMwKwK0kZr^Pfi#^Zv7G7;Tu5 z6`&0{pm)ujw=+Y{f@@0q;@Nh`{q*-#y-vQ8`0_ecAtHRaf*~7pcrGX?8s6cOh@qZ} z6O`J^@-@^B8sw`Si%(BK@3ky=mSO)PY+B;Fwk`7CzwqEjOZWTdKR<|R9BJaZLd(;< z7+LA?@5SI8WaFw!VJDKq|NiLi`f~JujPhJinoXbe@{6c%GU{I`o+K15J&EXWdH%3( z>9>GC?S4Ue4)>~K-Vdo*ueo@hPNYB7rS(gkA#ZW|s9}H!wH;TjszXcNq5Q=ln{~@( zQGQXcT_57EP%jBT8vcwIwY>Y=wyqO$!B@81(q%p<7qWQ}M=NAVAyzj}`B-o4zv zxp5G~!;vxw3QIwhw}kKJ9)TN-NKERO^e%-$urTVNLS73=SK8+U{l|<1e7(f4oRlBz zmC=&+Qg;h_sVQ>Q#YN!s;~TCdr_+#y@C9QpWD_8;^Mb2u%k%cm&If~uMVk4gr#_9< z?~L2cjlPa4cV;lVBmB!FUVE|R@AbTOT4^@l!@nC#CG1|9on5Kdxp86t9gnSkQD;A^ zHYaMy@X?h#V<<2eRezDCz<+WnSNE6V$}jHEX6aSl@xS*~w7iYIwnxg0Zx zzh4F8wp;1O&S$MNUtJ`dM;CwTsoS)$ z1setCAzF_kbAqS)ChT2p{N2uq^t}mx@a*6Rog)wYn#R5eS;efmEgv5Bw0Gg3{+27u zJkvvATCDOmwE4v7&7T|dw2Z=gn>b8OODDRy$Z9`mCHBwyUpsbcrTu{`$MmJeqg_Ez z8DIy197s41+<%epZTH%rDW9<9xD|PPctW#Dp|a$P%7!FUQju8y5*BI!S9#Fvgattj zusZ+4s)9pY2TxPldb;p)T`bUIhAp;vhVQ36Pm2MnQ9_{%xkFjXd8Wh8Z7Nj(vtoZe=be&end+lL1Q%+%FP{|( zqFisXxx2wNca_I&mz!!-RE_dDspjjw$0L_N>Lmr7YIhZm-_wb~HispM_Dua5`+H{M zyth9%XT7ZnsZE)xKSXuxvb-wmiV!0bOly{_g>fDdBb6MOgp$Z?B6y*FA4^VeE*-$J_euVynNtMJ?@jXLZjx7N;)6 zS~A-org~7_QuSbNhbAoP{AN!%p^wq>fP*qMstS4;+ouN0N5`9!nie>huNWH8*?rEp z%(G!)vZUX?Uk|Z@T=9Y@7m#T54_E4;w0&aSU0GT68A(E;_SbHBzNp>jxxBuMezQNQ zZK1qTFOBD^t~vE@#es6i0`Xw;7^rTya{@lhw?!1KO9$5$9;B7)-}W&q5mwJ_><@~R zypSrf>&dC=Yw_pB+-sKSW<>S=xSwJ^l~f|v(5(1&GraF!o6@ffH?2iWv3)N2tyOuV zbZv5S;)S4N3(qEfMkVUha3AoM+$x#;N^s$1jga9O{)mi>OaQw;!-)x0|7DRzdGAJ` zk-Y76$ksi-EJr&z54SBL#`?L%F9zC-69;XsF5j;kan#-_<~r{rV_6m2Ygu{Xx6NyQ zsru*yug-IM<)8nZq(AV4N0&r>89?}N0#QHV2os< zr#;yk&1OA(ZfH#lbUAErX= zX#bKk_laq%%b_RU6X8b7b0hl|cag+dsUP(Rvz@Mpt<;~9ROF`I+EwArd!_Qldk%#g z2l#HN%#SPFeO*Mya4$af)hlU~&c=-Im$fcxV0|pwNWByZN8){6Tzo;B7qlN6-|vV} zTzSd=Xu(?LVwKGG`qNwS=GNq`B(R+FF{V71BGWN7*kyBola#MmDpBFM{q@40SFiZ@ zJ$gZT;eK2GF{_xWXp>w=d4$!vH8Zmq(%YWO`}@?>u3kYV8->Vx{n{&?-4XTH~xlra74yQ0wzaRKV%=ZluZ zBcFx;7JLB-QeA$1Kbly=l}Q45^w@RH{MLwr*$dr*#6Pk68aze|^ZFiZHV1Z91gX39 z9`TeLcUrR?rey6YU*?QG4k)inIL+#?pWLq&{)?uH#of z(JLErV&1bpzOqt|ScXbyHw%6<^BV*MpCvO3SgP{6uPrdN<#@%V@%q_8a-S)6gWP)6 z&4s&aqXiGmQn}P3(CFWai5UmZ3?fpn&Q3tsm85M*-}KTgE?`(aVpy%cKa%{~mLF&C zk9e1RWygeT&L95M5WTzHZT~X+c^cn6K6?V&!dyG`8b-0e_`v>C64984h*dmM>bV~r zV_*P)QKa^7>tsC>(xaD`+2z~*ts`WjkaT!b(OrBP~^S|@l+P+6?Ulv=;+kf`^ zj`k?}?zMp?FLjB-jS||P@%rr_8QQokze$|6?z$PaTh`&BEBPY_SHcm9s^;P4MIhcl zC>}@)hpFwT$tyH1?9e5Cf6Bai^XiUuO@yYX*`IEYB_cGofjhtm_cQ_jg9EG)j~a*{=o zD)d^|^pT?;56^G?{k~tkEbXfctEHSf?>!sRn@4{ol8lY~Jbrdw^BNy$;9wH9^_AYi zvFp-L{sPAy-i2$kQS$N?09( zw&{?Bh(T>gZT^WXwR*fm0_T59zE_cpJ!LHX0r=i6grNhdM4v^NIKc3qC@{Pa4~3#I zUjtWJuzS=7+wBt?*)w~vA^7Y^%@qln(Z*e}`;q!>XeFiE`&Q)kXw^upZT#`$)RSHP z0e?b#CW`d^w9hXy+^h{V3Q(UKAOS}9%7|>ynJToGBO@cz?Yj<5YNM0qPRgxd&9~me zF3H3oGXoReAHrs&;rh2fDx3YPv>#jy+BEujaE9j-DKh%d(7b=vR)b>AH#@%k?R?i~ z{pb1RNirdmn$3*|U$~waZ4)^idh^oM@!aF)`(E8i&SMe0Y8sdF!Rb?__Kb5Cxno;q z2GACRBD0c%`Da;=o@ap~cAQws2IL*h>Vqp*e>7t5n~Qc|r&_Um8LsHR<8JDaPlxo? z>OK*xNeDR(pccq_1q}13&<_%kXb4{cZMi+Nu_Szp?`E$|#AD0IGk=CAf9nhnC>`bC z7}~{N``F`*(l>H?p9wk{S)UV~ec8Sq5$k`hM4Wr+-1e4*`DWL6Zb@63)DPJLhh6!) zDP&4S4%nYRB`Lj#*(3H>f_P7nJRAREq-vL{nn1nHt%#TW-Iv%_hpvt|mG0h_vGus? zu59Pg%)O6?7LmEKjaAO{NNCon_F|7!j%Z0_8oP7?EZ_!kMf_p z(*~|2-&PDJ`%NL;Im7rv%6oj~T+nA9Bb%e?-)n}xMjH82f3^p;r~hUXV4xw=yq+Lg z1FSNnP^J|Pxz&N+bAA~cpVzapN*Cz2fmM|VGekgGJ|Js0#jCycp2GGd**p9pgMA7* z-V{nte*bv&r@F&I$cFual;B05Wtu2zY6ti4l)?LQ)$Q&!M9OCcMttpvJAYs2!N1qP zm6sD6im`VMLYbKAYQ@=Ut-5$DD2L4_Vw)>y3g~=$bQcTN4e5o=$#AWWeuLEaPu5h| z`RMg{ostrg_v~cNU-i!dcXG{cOtS7RFz$YJSx<(2gN<#6on1r;GZV$6xms)7ajl-| zQHrqbLgIdEk%Ho}eSOUemg=mGf>;#7pQg@E&+>4>RMPb1=JwlIro7GjrfIjrxX)j|?*$LLQzaamFCuI!V$UIM zC@0LHyX;2!8O71#wy6r(lW=DDRd$TZyDX*OryoTZjtuGeeKNm)H*9S!=Ai|e^-X9PCoeAE36$emDW@MXd{{ zcRex=d2}l2-S>S(DRml?z9tPz#T@pXvQ53~ z8eKV@aBjsK8fcs_;IGb(&}&9Gj4wqYIQB&wl=ZUc!@mjI#2{bdFKj36n!j`Cab{jAq*un>|Lt>8BQXJjah- z8H->P-%OV(wog}(TuINcX*F^d<7cm*y;zs#JD>mUo$n}()vJ4JXv;dku2%*VK}9l4LNiH$G5xX|PN(+UpRt>pr7tRx&;xto`b}#JJY`mG zZBF`-dD>y^ZpYlWtlT<}(p<6K9lBo{8}=Q$!xI><=E%B(t0DT9Zib*?byfJAz~frtZ>{uDXr=3clKYVcpVxIjNS~)md^|G>F}P5Wg1&W`wf@;%?WQ=Krw`#Zuf4& zysevd^aE~cC(_T{93K0o7+exXx> z%rT|orvvrnU-ZaOn=kL+mvDY!?euHadM+TL!Pxo5M(K*@TD?bP)0-=%4s|qfCo)v! z6^!-;s6|G2&xp*eFL7R8)+58&3?W)yLvgUw>+sz z?vlSQ^EK=GX|^*fL5rt<3ca*3Na$rok-w-Cc|EWBz3-<6S|qwWHx}Je;%A@S!O*lT5DNF zFLCkS^&M>d%mGs^%c<_#0ZPHVs%FGze;qyDUu}b!Hh#G6jwY=>jeS#CSlIj8?{j|X zGgi|l{C)feQP(v3m-n!l+e%Pre-sed_tA|GyS&^|q}(Hft@uCX-3re*t)1J@c`EOe zP@Lbqs)&`rj*hOdSh~1!FQ%CX>Ss1G99sB3Jx*(Udu?(vkbGOD_ryJxzOyCAF1~rC zcZq?Ii=yff=S`Jex567ia8bl!<*&k@)$?L3d02H%*7(}*>q0AU*v*!2Qi9sHDW#r^ zwQVZ+?y#g5No8Gxzq6!}}>< zQj|<8g_rx_qLlMTwk>(ODH8TiODm6#)oe*%p0&@dw>Rd<>^F-o;ox=to7$?Mrlj=IB%8W$q6yN(fsxSi4sHb_6J_Tz&q0!CgpKb;bRs zC>Iyprv-2eGy*Km>bCLreh!F@niILZT3McL%E?(-O;kJfN;m$*nb$WhXk6N zD`Jc9vU2+`fVsp5_W!gJvjM+k>7Tg={U4^zGODUCTKgb~pfn;Op`?VgAdPf)O9|2- zDXkzWEe#?K(hVZgASfkW(%mgx?>zr|?-=i=;};qG?6db;bItiYzo%f6-SedL?C)FV z$E^jg17L{yoKH_!E?wv4PSRp&Djc#ZdQS6NG6$Xn&VAtxag|$cuXU1IO12Zf`+)1lKwnQB z#P?^tY;dn*pS*exoHNc@PSWs-t)Cn*CnwM^gP@X|9-$yi5-K0iz+W!MdLYA@P;Y&B z;x+1wPNP6?I5lG_Hax7eHFjw*>+GUW^P+-Dc?=|$NCVmdpwbc$scOZ}`+yzEPVrim z<#aS5uQ!=?y#q_;hl3auk8Sk5#-rtxScZ7qR~i+qDEoZuFfK#R7Wr@s;^WOZYoR$! zC<2NvlPK+Kt$^%b+?&{>G#sydD=_Of4_Fwsw6qgHS~T@{-F&-I+M%EIeg)))5X^`1 z9uP+#_Q_*>($6k+uf-~y^@dbj z^kPfMMac^;KxV#MQ!lw{SDV_+dqt7v=r? zG@xOR2FhJ%O-+sS&Xf+gS4>q%9#q?>v;ChIfE_73IN0&9o5As$*KLe{Ec72{mX~Y- zc$P+o^NoMsav;=M{@_LqVWC7|jX-`4%sB2CPv9paqkaOD+_?N3Gs#k|_|t<`EpBxI zSufRk%t^kUr6VSxy6;;}@g9V8mQziL&e;a-jDWj%Ahw2TYM#sYBQ{cr>r=68D~-cl zAy1d6(nfrDY$^S_qN3sxy&gQ4QF_-2N2WL=#OR)g zY@|C16eS$4g2tyw5zzS89)0=jmLcBo*-V%O{tMxsiJwGN?a`621MX!gFuk;(qhX>A z^co?7*aOguWQUA+dMX4k1!SxJ0Eh!=-K)1rNhv6IjQSrvcM#>>ouypq zy}Tuo#`x~^+eFQGJ^{m(rBI^zi``cf93MX_msnQ!SJ3`j&!TzuP4n%& zxZ#hGL(b+>6zxVD`=ePcS9JAHpW*US7opqc)9>%e88y`zi$OTJOHV`Jf0pp)(nUfB zX(mJO&U>#DDLpbh)uU>YU)a#v@C9oF=siKmmF=3SB!P*>GF;-v&d9ipMvCQPU=TZ1 zixU3KdOu$~rAJ^^N?2O;nt5tEP0wRLK)Up{rMzr(v!hV-r+}>T5gy;3HaJmbLz@{C zo46b%NiCn{nedTopnxcw}j&KW3L%y}tf6Ev;R>uPh}3B&4H#V{Ud7=Pv4 z{fhb0q;y$J1LrRAH%NErK&zBx)Zz;U zW-2k~-^_Xq1;pOfRxM38jNMhWPWSFz>x<;Tzi(` zE{uUh(A}Ku3X(5*@d>FS=_+_dIH z5X}^G7eRt7?=U?!HfDUle6V`5(^n|n=n@`kcV?U>EKIr@TkhRHR$Ajv9H({PuSEo0 zNBhUeX5g(|>P;S_bF>4o9e}Zr!GXmG>R0ZlS8X4&uP{f=2(Pa{$ZyY#+R5vqHI@|;f;RsqOOUD{YLEGqnlostj{;?DH-yuPxM z6DAESo25-=z{an7GyPYV`u3`oMtOHK(L3$LOgGZ;<=#+e=4uYTkZ2#({)w^%-g{op ze~+}%gud6<1ix&PWWXkj%iV{lRfo${2e`BTDOmcV;5(rMcPjMJ2J+SDlRJAci80yS zIfhHHf`hxB@$;KvC>P$oLGor~E^0weKFo47NS~>42ZfR5FcXv-U@dpIQF;qpIgw(?rfC?@v#~U2Aer6w-s}zrTU#QDT&T@$?&I$f+gq9f`$p;kGNSI%(zIG z;fcL30*zENf~2H?qfH6NC1pAjEv+a*Ce<1p`_~`V8v8r_rwM3e(qcCn2lC`M-fn)z zLN3;v5VV;W$YD(Sba5gf8NsFH&tRapq_eA>%pE*F$+TVPN(9G;7(gdN6Zoa-@MX$d z`}psbwrzDAW~e)-=Qp@p#!v<_q( zV5%+y3IsL%n)?qrQQSuB$a0Q%+gP+p?vEYe;py4*6)>%Y38Z__~>E5Q5V?3Mi&GKc4 zsl!a)65@a85bv0}ta=1dbzzh^7sm{%*w}mfzu1gXp$N-r$$NeGcqbrI$k%$TdB!04 zii~5a(;a23*e`-SZVyEJbCBfsrsiN+_J`eC#0$)-CnL9Rj<1J{brPUv=78b}EE}c` zFLFM>EGPYIFWXGr9a5|St)k`}k7vmn>BhVqhh8@@*cH~QgMCU@(#WIe*IEict;eb& z2J`0AsE6E%f3jS6V)L4=qmvEgqtngoUj9_Arb{{tpVKe{_WvzuIE<;fAs5Nm*c9D= zqAY@x6n(qvzHZ2y>7JP%QPdI?57u~H78Bk24&$lbOVDh*A0`mKIhmz8+DyK%cUG5e z70lmC=-O;)@T9Vx{G1j#S}ZZBjmc5&n6to+dDp|EDfy3Gw2h$|9HHLE4@aHJt=xMA zp#agqZS2Ng;Qj8s90IzI1jHz8>mecS`smZ-&2(cDC`#miU^WNQI^JsNPV##Sg5g$9=?sBhq ztkZaTAy=OKnqFS~;LmTSUvJ3dj%rcvh?73!P};-Brb0n`f{~@6E*|^I$NezYeDRgw zTyDTEf%9s9rN#R=-?Tszn0vUUt)47S3D8HKA?Lm3jUXpr z&{cOg_>v-Vd6jmR#BCdo9`*@z8eiRSnqJ<>1U)0C5n?dth#+V3f$_sw>t|u%nx>0C zuTc%IP8TtU#Fm#;Ry{d4Sd3ICKaK^!VCwE8ux@x;Jw7k`^Cv}?mqod&RPZN=EKa1F zh!PlBTE&09`&?J_yq2nccVR=rwD$CsPm?CoU}f&_I3{k&K-mX0RHE4qCWoPIc`7SJ zk-uu~U;O;@=gFhYA*_VDK6@%KCx-k{q<4GtD^3#ZO7NdKX4F zYF`aW*6x@*2rsYN=u>FXdH?)A6Iyf1uJ@z!((R8eB2)9!;+A~ zWmK%go^lIHcd~y_P~tu!nmMQjI|aa=5i1|YgGTDuY#dZ>{s;sizGJn!zeOx>eT{G zH37td#Vh3pgCm;3UNNhR(!(&>z>Gg9X3Pu7T;h_MPEHDM^;b7S5QBq{%I>%OH;=yF z#|BZBXkqp5#S?j0syje}1mH#^5KC}JS;~!;1jxqC{l@#9NhFBl%|Qm%^VR8IDQzsf+1Ft|GwL+&mcLjID-! zZm#7fB(pvcGTpt!gv9^1hR1P5{_hpe;juFfc-5Pz{r*>zxFu_X{i}CH9=Qw43TF9)%(ytid z1MB9}FLyat7X+N88IZ^F2~h7aJu}oQ@z0XVupFXab%63!#cC|DEhs~emzH_HxW;I# zB-R$(&eB)sg+2{Ge_B{h;J=wwtP?i(G&dVd#k%=`M?KB$Y_c<7t4S%P3y)Xe=(ON= zGLEPo3=Gv0{4_Y8!Y=LPva5I+MlzMkned%j>Lb6S|D@9ju8rfW_SsdRUd zpk5Wf1aX2He~!Ak0aEB?XWvW-xj~jBK1{G%rhgDj74xfj+tBR#?=P+Ox8PH$S3C#R zCv^K_fDVJmd{6$3dG~H>UmuPSB98_L^#rw}D+z|_q5-i6(cHFknwM`$S?qo4rJb(VYzsb;h9L>FC89<=8_~gb{F9ZUwW!`ip*yLs! zTQeX3Nn32gVK_RWkR=~iO3J!Xb^PU0(R7lU^Fyn%6%xY_5t?*1$R7b!l`WMkRDm?~ z^oKxc13B03xcJv+GSWVc?+96EYMu6)zuj(rBKi4d>dU*93;VbBrW%tP%x`LAtA*>- z3hv7%Wik_9oHNQb2w$U@zPK$AColfZCS-LtgZllR(Q@s5WB_VFHd|-X5SefK7@!s` zPey>}0U~I0LyA9{q@inu4NbOa`{*uxB#H<1h#6vdJEq9MX7I%-rSbLOYqrY|OJ(+9 zmfJU4?#2HN6=mZxp$c~{i;{8!;W5Je0&Q%wKVOoThZ?^K$n;EREAoO~4&k7NIrHL-jRn`2Bb&NK>MPd!&Ruyf{1ot$&vJ6~;_rjM+m5&QXxR6l%1y z*v;gk_5S^zvjz8nl*F0NV}Ftckwxl9@Wq(b=dE+Ah|wZrQ6!HV}2}3dv9@Z z5hU7DfV$37aJivVnrSkS?dg^<1;aFKd) zAZp?OU5i-hSS65RBK#@l^?vfwZKwRSGxx6SB%Vs<&S~D#8FzQjaThkezJ*_EP#w$y zO5HHpXpGcS6}271AIwx#tBhJvKj)0_@MJJ+S=##NM-Z0mBLW8TWeKDeyj{egd_PoT#WT z<}`YibZ{vK*hTAcU0#r&9#>JonU8D;Zbk;VGq)ZUmbwp@#zZC1~M7Orud=2dy zLR3=^_K`x+iPcv527{(WHy4aC@ECP4@m|4Oju@%3o7iZ5vxL3?jL%iUS%o-8an{Da z?xS#$j|~c1I7)tw_h%L>yJLaW%lp!k%Ys;S*-3V5QfyK(;JLf%ge9-H(B(yG^oE24 zEmMDOCH`veNb7Es=fci469&eAv(rC+_I^>ymUP`C>Y-=}LU^U`v*;y4R2w2^r_u5p z3oG;)4L3vl$>r>#fv@ddJb1wLtVWx&Oz$B+avV+X_N3nS`AKhIt6}|5Nsa^*>B!Kn zcg|N!uIr}k{9Q6&6c)O8Jmvnq@hF~FJnuF8_30uGKn)^eVhA8JyC%2?N;Cv_i;ENs z8U>X)Ie2nWpO6|n#r)7h9-rXS(`&mpl8kugDT=ru8L$}qbG-;P)z2+6P9jGV^msz> z`sP|Ty&*(aGgFPe5|5aC8aWZHgvF?j428z4F!c1}tay--SNbL70o{x%~{I8_jcwgO{O6F>@Zbd~3Q&G`-bHx%kK8`s6H|{AjhnPn=sl;XQ zqMp?NzKJS6kI+L!kYBB}wf^S3161l z>ga!^<#olj8uf1vjZ4g1TZ=tW3QD09;!WMCC5`dimRa#0O$6D8)NYHPY*G4WTTxo3 z!+!K(3)Ho~KPlmm`g40OoX2RI&y@4`V%@ms(MAB=IzahSB4BDYPH*0Co<3A`QMAGO z+x72i$W}P<&eG)`isO-%>M(I@TkT+pV8`hx=8%*G?d^D7Ic_?7xuxBv?&8v>_=g1a zUDG3l?VmmwHXzHNfzPDxd(nGome`ZRoxQ&h$r;+tov3Uz- zgHq_0G@$4d#xzrOY2SJmG4YtZ(N&vXrE=~e#$Z;{ywx2WC%4-HU;#%e_Ycbb$gz4wr}?ju!3}*5k@cD++j7 z15XYkdlCY>AIcg#Mi=Q&N3*8YPD@b+`v;j<9WyeHW*IigeO-Om;yZkTLx#)nQgi7N zY!Z(i!T8v!+7S+1YIRbEnH>1=hsHck*hxNoSY}G}W>M4pZ+c-n$)Vdjb_y&uKt&f#b0v?|n3MEVafeEGeIH-=RX(iFa+n{Or~1K?EUZi%v2x!#V)?CzI0F%nU1~+SB{dA?7Cv1v6nyx*0&wN$5eCY4QdjT|* z7g(g3I55Z-`$P}#wFS2HXUr{T>21y$$|P0J%?4mja);4~;U7ClNE<9ivRBdBHRQNmRk*Pe z5XKSFF*4%&y<*=~~ikIeStDsGUh2~M1%;J)zQd;tHRSFH@(zOUwP+o|i$ zq0aFX$8~ce8iu_Hp)1J9&Nd25ZCGw3p1+l4SpDW!zEI94q*~&VzZ{Nb`K` z^OF0o&Lrg+TDjQ24F&tT2Yj#rcAXzt2S>c=O9s;-gUmh>1^?HnQY|G0>N~O;fVXqT zB;`W)0a^Io+QKN*?`2!lrbu3geLR2C&5Sk}G(|!?S@(NP*WpaD ze}zL#(P@~`YUJv>e$4{N#r2K%bC&$ zC$+y8xc?-b*;4RxW|{qxl*P`fPci5G7?!hbT8z_b?9_W5=D3WIkoGc2iGYTh&j$hb z!2a*-Kigk)$J=jz9yD81Uh7AWj+wtY$uRAvfLS9xVE*AjSNnI;*mn_DQaHS`eI})( zIKyW-xi4Uz`gQexuKroW&uw8Jf#~?FKbaE5nVCIUm}t=@dNPsdaq2&{hjy43}iB+o1H$cx=B&W{6rid)R+G!kGuvOF&A6| z7UtW=%f;G42(1)_2??9kd(FG!u>c#T va6RLGhl)C`fgqHK$)T#+>P4!+j`Qve zxiY?(@Si2L7)yf+UW{|pnTsPqss(Br?g#(V0UxWHr&e(0+q(ClEJ=~ElxO{rRiM#( zY56!N@AWH0pdYXW9PI63a&g-t_4rq>C`cW<)%O=coYoy%_g+ji-Ad#1NQ>6zYO^%X z3hlT=#aVAMYD0K9U45}hr&@OZ;2n3r-%xJcDIFmpAvD$)mBB9z@s{8jC-lC?I6D+G zdQ@dw7#rZ^q=qjJ-R_;8#P|;gnyIp~a>%u_F1c{cRZ=vsoa56CQp9O(LYs?^+#oIT zz5RiIQw$o4){J-B&+dXn@%Hn)d-9B|2zvpr50H)itqlO3tz&}&T!@I35eal$eN}|Q z2g_;^tpRbJmOs&-lel~dxmQp@XOCsvk8kP;iwf{brVOSaePCy6;Z%KpRmZn8g!w?MMux-MW#Y{soHNo>ld}o#?ZML4l zaWx_u)n#V>%$R53MdC-cs*h_SWKgGy;}dWy8iL^l^4q>c0~!O72Tw&+@wV`zVlGVx z1<#);Zf?!&cb<6Wt27_*7gkp2R8&;@VqbBQ7U#VGd+_gEJx(MnI2fP9qKx;2GcRTE zR8{9!j|S|#!-k}Pv|{-49cu#?RUG6u&yfX~n>31Yznzdcdr06f@og zkP?J)6~=Lt6ciMi31{_}7p%@(=*7A%ZT(sG?vMG{KR@X9D5uqy+3KksRlld-Rng0< zkZ+`}uAUkO&;@9;cR=7aY{V%2MI_96= zOmM*9?(*j~2z}4&r-QskPMNF-3ru6!EuDW1=NmZl-R(J`w)xAob5(_piT1{e`%Cs_ z#?sEvB;EWo#!{kn-CM_QyMkMeE25hlfukc>k($M2-7&wM-z0DnQQ&a87SyXwHFy#M zhM3QFM;>|^#Vkq`Hrz7u^5BQ0gG{V}4UV)sc&1u*DSY;O@(AYD5t8;yQjbKuMeI9ZYEMbOj`ZlSLid%DE zk{ipqe~1pNo(yde-f>cg}QvLy_^z3s3&e zZWYU5nP*b#cwhHB(uMrz1IEI1==BXNJc5@Q_GVk-O9-E5hmsdb=;rcJ{?%m)|D9*n zj0BM>mj};R9ZT}V|i>WgQZXk=lqjtj+I$I*x7%i3q`G)O-7!Hg6N3a-30Wt!S zkOznc?x+hIe1Z&d40Nn#3E2fNi8Ob4+oT@O(hpoQf3Z~JUnE`WRWnA`P*)%P1!)+t z6)?j8n)>m!`#ugjE(P{Tp_n}zmt|&b*w8w#i5A9xjNE?yD~cKeD1K+bSG$cB$#lZc zS{|X9aV52wR|{9RgX?~!qb*${S_d?){ql1u+*q@du)FO2|E zPkJC}q$UGa4B?;xK5{B!Q+zc<)!B#i(vjF+B0uMAovM{3A0(iU4bD9}U3Q)_@Do3& zv@kj3%x^auEzt;vJxERk7IUEZDj6G7!IQ+Wv)qZ&bW@V8`nQo>GD3Z@wMci_H+NMh z9q0Y~S%K;sw02Uq&21edM2ThlVzTI2EKzHIJ&uIdg~?67HaqcmK@+sc(?6U{PVIf` z-cskOm}K6ZGno)-bUNmtrFS_Ytb$Mo{ufPcTY;IJm?#aHL0mkr@ycdl_C%9G9uCgu zzR9W&Dg2MubOqcmj$db$@IU{#NI2>5^Mamutk^&@zaaBK768HWyvV==Ox<{&BU@%1 za8Q{>$@~(H*RlDV?a7CCrxzDa%Or96XzG+AeO-bKt2z;|2kE*Xtv6@bzY4iNzjqvP zH^<$O@`2>qr;Gx;yaUnyu8(I~Gso)7_KBoQ{7~xKbcRuo<{@!XQo4$s+fhnvoVK9#ek_AN6 z35{I2Y#Uv=Ew47di%a+hW|W~SOEqXpEp}XqyPd{dj9GB?c$*8|{5uW8=atj8yw4iM zB89yq!~cO&+%Z5QC6E}Cdsvp1DT~yHu@8~61)dWE7%HvIgY@xj5^N3fDSRU|Ll2S_ zD1KS^TMor0W=_^*h#=>zU6z|D7nAm!IQiL}*blG1ny#BXtDb%CtosaGN}^pCwxk4j z^idFL>$wwVt*Gr{X|dUto>zRJ>cF@7)hF!TAw@|mRBe@?l|ua{;?37X>I^Biu9%_U z;~}S6zxsuHJqZ7|Mx9V(h+_`7LMjj-1bZQj9tJj#0CEuzU432suPsLDz>0w8U-eO(zL(*6W-Tg$wB*p+8&>eJmg9iNmZ?y}OGDkJ zrA_q{6n(UCNE&%ptf_OiL>alYHFnpbSQiV9XLrWSZIh`(iG{8gZ z;MJ3zPu8RrPEQju4O3wPJs>)%VZ!8!?~Nm98556@0pRUOSuCT#<&~nKHRjke^q7ED(k)03ceJ;=VVo z%anMvtxK!4TA+bT`ZvP3og1kxICQ8#Cseg~)zaBL>t35Rg9fkA^_2;tM6Uf%{|Htd z;{=}4iiR^8f$!!Yzl%wqL?T)SGA%9KgUYmp8Hh(R8wgeqVbZw)W_kz@{`BdS2w;ZR zM+y^0Oux2oO|UsX0WXK(ISt3rPouEi8b2Eq^}d(MizwK0776?77H|)>fc2PaZQ49W z)Oe+N=05y{e7E5Qs~;P&0y*_8DSxmKK7#)OuQ@xP4 z^2N@6xiuFgTHQ>NERpcyhgWhUo%DT~R~<4#J=yWQ{zLxIx+r=AabLM~>RgI@9j^pm z!+MV(+=AqGA6oO{HtRf(kkD|rHS|Pt)eeH6t-A$RR&R*()*^-F3HqWm94r5(-d4wC zWMuqC3)$qLITWn!O@Gm!AG5H1akhH$J81|dN(m`ZKnLT@jg+rA!f^6Rw(|=uM#SB( zi+>}C!$>NJMjI^Epd%JAZL&PKRbT&v&GP}pZoOCu1*O``-ebpi2N*yWL0UN8UNoNe z@W&+nc)c?nrmRoPNyYg8;R%v_VP!%Ld=XxJm{!!9P15RYde zba2E+#uFBf^1dP5-^XiNk6>f0W5erYf0_$gvQ9H-5#$LZ!<+*=as<%Y5B~Vk&1!O7 z8&ON|x@U;C+&Ye?{v}DmKl(&QrjLGC{*=TaX@N>!d^AAVS6|uyx^yN8t24X< zbP&`ET#@~JTYWvFE04WBpHH7e$0vGMW*Rhy3v0+dFIHo;{#25M>arL+6t-6#z4`B} zlBQsTXKc@6;ud_QYNIJy+bIE%h~eES?#|PfPhMtAe4H-#ORw?5*cl4Se#m1}^llVb zzG+IrSFzwtvj_1JP?V&>CXDVaD@y_LP2fXW^1+5ylZQtRjBOaCuK0b~hFZ8#ECRO0{8 z8fezjh6K|yGmV`f)|krYK9i(>O zu4Rp=MC8eYyvAd_+~;p5>JIl3OL%-1XOrX~yr2>_4lSn9#mlDk*EPw{t9CKYr!6j4 zXQ3)CcSJ)Nca1CgUn* zYfRQdP;G4E%7wquS#D8$qFFD7%n)iI4*m}aZ>HYG?r??8tf$ia-b5V_nQ#*l%!kpi z+_o7XvwD!-Bqm9jQyC;^@CC6y)&7KEX{K_$_qa&6N*PT61sU-AS`nSi8bIR0APji5;xM+Ts8@W93f({|Kofz0_z<>g zbN3W*#`(1rYM?MNX^_kFODn&JL@rs>((LHv`RsUSTrq z;T?tKTiUmh6FJSfb&K&Yk9K;kwJ_Z29y5Hf3N2uNJ%)SzJf)*(koRLpN8o~*m%V@s zX7Zb9WgTs#Pi{wyuIK;eWffdoSN>2tUbvKS|C@6;*_nFC9X2^#=Tx2Xi@$tjPm1!L zKZIJ&Lphb5&;|3!tfBQX?^lE24Gn_O?abdnB*TK!rwsh4z+((HDE&1(eHF*cR2hT# z>N1UFkhKRLvY|_f&nmE3AgE)IA{qpa$@Bq>itNXLT#|(IS^Fx>L{~_HRvbWt?2tYIirBA~$-cK+#>OzK`H=UPeo-os zINri05&f)*aW;DO^0QaJ|7o@xpUs*`J-5)+ov2=Qt7qQ?J?7k&*swz%ywWY1D!eC5 zE=qFVovrtd|GD?|CE%_|C{|WjS6!Y$R~v|oAkF#eCJ3BYSnIR%DIjLPK(qLKbf_Rl zA_5aB>+;f#Z6ZkY>O#$INRs)>7wFIQF%jr=kPCl^Gv}0jYACs0ZO!&nHFnbQSn{Iv zhHHHUAmNEXXNCNUu7e-ICS3zGI8e0_aUZZrn0t`#@Av28fOt5Pf`Jo$3H6Ta3Bm!D zl1a?yVfJALjUdjeKmFNyG4ghPG%|L-5N=9n=K=Lf`jA_rpm}XTc2`rRndm+9y{w4x8Q9bk|qrq$$;J@ExVq$`ZrxZ*MIN#nRu!_~W*zbIael$D! zptUXTgwHilr}B~PJ3nER>(|4%S+7geXc~UW#!t1U@GG$KM6S%WTyk07ii!d~Y#8zW z%C@WFq(V$w7tZhSZ5}hvki;I`^*TRKrQLpFg{+n;X}q4U`1X1)_a4CE6scRnhq#G( zkgTm&liKjkwEr~+L;JRcLKGE5`vq$(c1Uh_k8fVVoD%W#0k=0D{F;c+14LvsQ~`j( zkAxQp`r15Uk1s)fh={odf($hkl`q&~5vlSpTWE(x=JnJE^KvrRWrE;ffm-{=66v|B zg`F=e>GsVBzhP$yU1Lx&U=Ubu4$msdi__4NrfwRWaE`9&S;2tWd42FU4-XGOhht4m z_EKGsw{&0{eCNp`HYfk-%LdZ(V~zLiFLfCOfsT8t@Q2*qmUE=WRV*dpx7b%U)8$FJ zH8e64yPzzUEPi~wn#Mg`ctVMRp>cM;NiUyl)-ssWPZ#c>w}?Y}m~!DNFUS!`iE}Mo zc(+)&&~d4^nrrC3;^cD+PAREq3IP#Hyr@fKRs6qmMpZ2>Kd&$BLJk-?IpsqM+lp*R zdb(m;ie59oJyrD;^Sn^^Ys;IitK~mUPB2>)co_QIjx!wlR`>t}H$%u1g2fFBESSau zz(h()7YNwRheuA^?=MfmEA#I$4GrqUhYt}UVqoZwUi20I{Q=o%a1p(KovplDVgHBB zlq}lPr%nXqqE*59@tz6#4IU$GZs&l@^JHo<6cxP% z!Lkr|1qzOUgaoaxJF|T_Kb%#rZ7nez9DGcPX&ZOM>>G=VFg_r=k}m9gI$sry&YqG( z2inc{IFLsnJYx=C62&1G*bH(tpR!_8rnavS-G1)*;QC6dGwF+_@Uv5laNRbxlUKDu zrzmBYOD0?rA)oG(em<|Vh`Sr!AZW^CCu(Z!%fk1We)SI?R7pQmp3AgWTd%bm7;pkk zGTQBsE||ye)`ePQ{y;i|Hm(AmXOHZ2Bh9Z|5ORTce#n|%^8#HtAN|S{|Lh^Rmnp|q z52D*I_M?IbtfG(F4@o%9*no`BY%OQj<$!D?8NjM19y>c5t6NU?meG$7+2-OX$Ec4Y za5dg_7d)JH`2iEGP-BAp5kbrW80qPJ5ao<)1426W=utBpHDl%2d9fBwS3E>}$IX?B z9Fg}g$oa;IvTGzCsQIPYGwsCZzlAM~6Ii^k=;4YYvX>sP8hlx?^*+ntdAsR>Jeer? z&}zijJgH1nH1AhjQ64waa=IQah4>bpbeu&7t+@H$+xS#sKE4Y8t?Z9 zKk9PVoCkjWim|`q3)U))wm)K2DnX5co&E0}h|_piJD5!a59Oov7L-)fFLE!%0v<8Y z_*;iR%=(jnBhMw9EHAGt_|C}KS2hc|`fi+T@74G3&S?p*3K0)cp5PPIs*l9sH}%ro zICT>3hM!XCJ9A+>8Kz_|%`edU1Gu7-R_?c2CvWfDMmrNEC~LZaF8CjS2ndo)zv_Ww zkFeO_`a)}K09FY3iQSdn{%j0X)F<6P^naixcBsB@X7eptMNuxdm(cvCBNIoZ!I7gV z6YcmFbOLI1F1CPV2k3aJ3JDhEp)_A#h5JM;_1=?;Xs$42^KOjhW-NBy^T%aAv%^@n z?N-ZGPjM!fQjAJ6*-gb0O%MI}XdPm~9zV9&otE<4W%)bl+8-F0>G=;`U;Y01=_ya& zPnjTGTPmy)LvOp1lhT+)D1Xh&wAG8Gi*8iJkYMdL2GZWj#8rd3z~v%N>ndyd5@l%E z-Rl`1P-O=0tb>`oAx_u_6gu$r0&#EI+3m_>TrVtuyGgsA7}V0EyCa(|jUSt>EZ+Gp zC?c_Cci_IaJiYgTG!%1;K}Pk@%Fa#%SdgII!>s=!7Lasb-6!F6QReOaPQ8HiXUAx+ z*d1W5kVs8c(vt~cT9PnS?hT99ySk~h7NDA+r?iX?9``<6R@MxE7}NAhY(X)Vih&tZ zVZK%S{eeT^o0N*rkIYAz33P`=Hi3VUXZdZ+ABC$C3C_ ziN55noWX9)@^_g>6Z86Ms6gj^3|$V3@xAS%j}qeI%GFjHa88y19SihqYy-_e>vorg zrOS=Xr`1%Hfin;17j+GQW1Iywt92yGFWWh?&Z23SjbFTYu{Bu}3HRv}tD#WVH$mus z!QGO|Q62j3fC_DeTxmSo8VhGG7;OP#;oG}2vV-}HhS@C5{E1PAhp7>%>(5CsVsBG$ zm@qHYy>H-=jHtiOY?`{aXV2%dB@JOzfI2^XnXiWa06H$J)QC_FQ41S!ow>w33624z`jz};y&L*HBF0jsWY7l}U%t$hn{1R z_!{Xn0*=l1VMn-Q1OemlXL!3e!@|O{VOxPXM|c2C0!eBUzvFh5Zg$1ZAKNZhx4QWD zHafrzft!2p!n~=n^g`&p?PX!lHoeTC_3hiY9d@R8SN^0}|NACl;qqbojQBF(;l!7QX}fM*FoO+MS0 z;L&<8xOwE}?v8*}fO;0e(hL8w?0CZR{Rg98VcJ#2&OcM)5;b9ScX^`JaP_iI6S0QD zql!6L4eQwf@Ga%c*L9LZ0KdfF_z=olAH$tz3oM{(`)r6VEf@n@dj6U$sq5 zeSw?x%G^9*#g^4TeRNOINz&cmJ6q3qeHsd-rrB6H`6c;39->y3*DBq#G9FrRI1htX z)-5)Osm-dnfr96EG7l@1cSgS=6p9Q>mq^1yZmFs5odnIkm%F&Oip^^Y(PTnOeCzd~ zGP0NZheC9$4*YP~2Vh17>3oq+Wk+5$+fa93UnH1s{tKUkfn5xjEj=nYrPAKt1)H9= zV3U02YS#d!;N+(Z_LH-+{vfhlCo*&X+WIsanU0504nu5^py%;k)6G?1p6&MbHdc3M zIMlwG5(J=c=zLK$!f5*b^sy~QW}2l|IeE-OMYOqO{naWnVqhn z98MOI2j82u-`*!ToCR=aNDz-SV8&n`6CH#@*;vg7>~%ndz`Kk$45ahfL3>sjIy6!) z9~OP1oA=AyT|a~E53=WeF%|FQ9RKQ?3aPdotH^7oI{3W&?w%Bt%wU}jC@d0_k`MzB z#V^la0Zm;~6Qc3(d|;G$xHdoyyv>gA7o~Ry2++}yOjhb4A8p0`Pu8oXz@Jto>$_vK zYt8D>9I|LWyC2IMw5x2!9nCoo^O^SUNBHbk~F+4HE6JR zaan;2LtG#Mf$3?8pV$G-r$pjKI{(Dai4_@FXg}09T04#(&UR_r%6O#8qblquVb%hj z9s1$0b~!9cLgO-K`7PwDr`R=JJ%E=7ItCDvbIjD;(f%UzL78jmfnJVpWW*v`;He!LY$ox z&3Y`5Tnq03m47-2yXQ8u2D{F!X=utI1S(|P5>76I1 z!tdcko1b>gDMe=&9mCDfva98OGnF_JWt;eaT7W*Gi!gxeK}IC9$k7Iy)7OLRy?J=9 z8Db{G)-k+hx_sg=CvEkv)n#N^Nsv~IMbY6{-43dmeC3Q=z%=hW;A1tY|BVRRP|O8| z2L-}1njaq;;`;$5F16{@EoW@Eu=LU1xe1-VbTjU z#7?hVm)%1j$VN1=%u;^cXl1mi|Bk0t%`il&)K*i;>f%0>%BdVp!$1xHHyF}J0cj=~ znQ*<96^R*qbO)1I1ZLZegv@$*%!X%k9~^5IbJM_MviMgcL-{tHr+@-Z<>A9`27j%l zuxUD_IgomCfU;j{&LktAE1wj-EY|=bIQ@uFHNz%FSd6MighOViG!YO<(xbIB+ z;RyK%dKztNj^ptL|LERuGmsHy&Ov2%|tei&-^k z(8hvX!WCFc0(qm!s z%Bl2g`285<`iyVqotuWdRGDo%Giha_In+QIM#AwL9bxJbGhgy)xOMw3{LCoL{ul&^ z_%|d%M#!V;T!!zNDi~+PRt)*NP6DfYI<JH)yz>k*{N4s1BZcrq&pxYBT%BV?eM%?7S)?HCvV5ys4w^^ss?E9_ z!WF4PAQvt)=x^bIG?L516Hu%W<^C86A}D^{-&OdMcyM9ABEL9EbVMVoo?@uMMlt_< zQbqiy6mb&)gT{eJn*1@+3I`-1nnNXK_tbI?YP3WyOME2A|H_1Y#3%ab{ZDjzhY!sn zIYlYtWW2Ws-ecuVf7Ki|G)VK$Mn&SX!s;bY?$&9HrZMG*?3qBp-YEe{6N7GJ*k6NU zP2gRUK?fg#AWUy6m%cucYpb?S&~rJpKkfS+Aaszt`U@UQ+G4rEoh%paq?aT$C^E7r z@IF#O(#%hYC5P;A7!rptm)gNDi%HCer2OXXzpV)ZWi;>>V5)t6Qsa&6@z3WW&!g;S zvoEW>mD>m0ECGfK7JCECcDXb%(dB4Zq~bs;MO2(%m*MpA1S@%cLj$tu)e*hYn6FxX zY_NSFPIp8oXXCr}1ER&E6P@=~doh>u%%&J{A^4D|0V#qpAe4q3Z5^!s@uT1vdId%8 zM}yK_h`d9D4qTjMsL`A1&Bie)S3U8%s^%DgEkL?)X4;S2yZW&J3mK6ok>Wqz7t@1p zE2~nXX=K);pvu0!JXB&aY?Lq7tsbn7O!K}@%9IENsS+W==+U<6e#jUzYh(ME9nY+f z`wjCP=WXV@#Mk7d;pQ661UjarIUD?vBAu+nxVT1crRogh^(0)R+BMj8N+9b0H$xkf8Gl^&&;OtExqC`$?lVtJt>-vYHsYd|H7gQK!CE-)k6m(DMC>ad23 z^5NZFVl8FVFdAhp`=)7ze&e<$wIe<~kCKdYTJx*va&V8R=h;eWsWdEIcOWbK%RF}p zJ3`G2#i5L>Y$p5)3}%Gh=a!B_!zx*^b##3l@($(b-!ZuYcphU`-pKkUzeGgv!};DU-&GemETByAl-j!jk#t7Z`~BDBj0M#p*$9?#k@D$T{FbK5fPrhSjM!zl^! zRPz&Oy@bMrE#$v&N30YkJ8>?29k7kdHizw}4Z1=fVPFG7gNmXE=)wRh6r9GSJ-w0m zq#JEnQk|6HeL{Xi$QV=1?7?@PzG%C?A`iWJDQ~ZCA73pKO|xzbiUuM?HXjt<2p)+3 z#oBZo40N#`p7x$lc*PJ=V!okUXf7Ms(R({7m&>xkD`RS`c8jJte*;hwZ*?sG7 zKxqjcLQ3hBl#-SdPz0ou4wXhg8dN}9B&9<-MU<9KsV&ki2zS2U_d9o-JI4Lv zjPw2R4PnD(?e(rT*Idth=JO0G8vZOhSCgW7;%qbAsMY@H=Z7WD2r^#{&DM|diIu9z zsQ871tY^fnT{=LSMa*R}bl?PBm$<=68%hDNS}#ew=rb_nSi_?9xb?~X)C0^weooq1 zI|iBAN~stmFmem49bl@Ub1y&P%5oy20RPjMFR|P=rZVKieqXYq7x$2cqDyxi8&JXg zfWys6u!i6EZJp9_h7L3SLi{#|>k6mf*oMMv+vMomb^R(VO%^lKT;Vq=NhQHPjYu3aVA% z;A00m0o}1~H?*|+tDoEijZQ}4DvI~L%U5JO*hVgFq#n{Hrf?)D|FgD)~$dAnH zSqg=#T;3H<-B3{R)~o?y+7+(EVqbuK!3Z8I{#XA|`c=!wV>{gr+1dOOX8{T{6*SN8 zPb(acFQs^S{CZ2EI;aC{hzY8MsX1uVJuibsI>{r(FolR6tlST}`~i40mk3Y!Nea#) zSDoKu81p*t+m9Cd2ugCFTI5zKK=jG`1e6T~X*6B{($=%O2pNfTUmvq4!3@ z@s28}@*N-Qo3-3%%C5ilJ@6gVb^hS_b3)ti+hXY1m_5@N409qRs{wlRh1aZTQ;pOY z6O{@3UTtkc%~y3lvf;)=XXadcRR55D_d{>vTW@|5{uRf)X|*CV`1{qcOv%|_f4*Ss z74pT~%WDUOKQUD_f!6jd3Bchj?h=j*r&})t(7Y0g!}Kl0>1QbRu*{^>Y8Kzyu`^uo z;cY;NpTSS_%&7^2ubTSdWeRNH6WL0;xlLjctXItgpD2UY)jsq)iz%ClecJdz7`vxj z;by07el894z}Jr)UIS_v8AyUaZ~z*RFfgPS`>MUUi3jB&W@cs}vVaPbaK{N`k;d2u z2R*J&o>)8V?<{S9>g7Fm!bdP@~y_&-E&;SJB z^mW!XZlmneI^BX%tf=9SPm{Bh&NF`u&zOAde_48@N#}6&xc=*`J-Q~SOc-rOsRKLu zK0=oSX>C!r)z|Yxk)PDm)dBzF0j;7r5cBkbxO^jlU-0Gm85RM-QvJk`P6~%TcY;dC z-t{5$KbhlNZn1qsh0y)=#2I3kCJYdVYlYK(D8Xe;0f+cS0T&@1E-9&IraToNNkb#l zKYiMuo`oE1lMMu(>bna+=i6#az7JHG483B2r8;<<`N_;@gmkEBg9BD}toKil)^DiT zT|_{ZLZixGIRXk1tuqbp^|;U$Q`1ZmBgmyuC|wD*+iGCc$clbm!MDK^8SH>@gmwj2 z{Odyp?kiCOiP@$SqV7ca6y!G_md4DPGniu=phLOz@CXQ4E7hQi=DPOQn6N~MPLQlz z?QsZYzM%$wS+Svpv)_^6M79RHelU2(XJYdQC$sBAH zJ3#ec`7h!5vuO;%0+ob{jl^mtUnd;s^} zB$$q03%gD#dc{SS%`L?T2Bo}N42c)D*Jdywwd{ij59$uG^a>2YpcEQaFW}$|RXG>~ z%4*69{Z*GQB;FuC+>rVE2Tg#PK0qKb(>SAhUo%0F$#$^m8afq{vg$jK_W%Zh0I_fn zGOV&UtkWA2b;JFruRmBfRgVK28J&@Qey139Pj{g?ODe++_t#khNy3l!dim5kwuDMv zS2IjnTvGhak)f56UQ^U;^zj6Jt+6_xzhqp6MMdM_dI>iqpb{m6ZSwokHJx}^-W?I( z>iv>fDsax6HFETL7hSNcJV?eHc%N}W`9kEGeS1e~1lqA_&k=wcV+iIiOG<9QV}MRB zCWYesiW+CEiAs>#xaV?WXxI|Z0Sa|<-&1FytUwygVAft{jk7vK;(KN;S$Z7M)%4bUXOBXjGtaoO`N4mQE!5BJi&#>2a5 zHyb5YbyT0Z&9rnWNL?4_eHY9{Dm2Pl@lsg4YP zvDp-Yf5p5F+xi`-+4rF4{r+YiEkrc>?0zFh*bQJN=le$&mGHjgvDtTz^bEx?8pEds z$OHz#)p-aIRkiV?kdP1yn=P;;?EzdP(N0WN)!KuY-SFzK5gjk=NNWd+Z^gy+PF1eU ze!adl#SgpJyC>214SU7Npj@DFtj(*bAuV#p7b{ic%TN7A@uMSYOJ)xbptth*O9lp~ zWm$HVjLnPCb5jaBOxVLx4!Rqs{2N^raxwh|W4d8up#&dH*I_T*>478twO?_&Bq~ORDkB+=ojPX{O+AO^&hsV2ay=CA>jB!l$mchKt9kn}(L^3_= zfh^ESdJW|ae0=UATlhaSTm;pv4>zu~b|~Po3Vk4nijoDb-9XbDfu<#tO@9yS`S__h zN*g&>wUm+%&*i7;vc3%-Kswa02{;cAHxEw`__;vcjd~&pegUu$$^broeo{!1RVt^z zb26Uit&aqX$)-=kEVcTYV}!P#3SJ!Eb<4>d2kM8u8+%p7hqcck*Rbp(-f|es#!F00 zEaCA-U#_snyF|-5KIdR>zO2StZMM5iLQk*w68kTec#S|^I76#`vF0DMn;pED9b=>R zw&96szqtokHsro>@$v0|!L*zYy52ni1LzKTYKnl8_oLkqeAvuvHmN6p17xfNB2;%C zW8t)hlBy`;T8SFmE(J)s>e*D!ibi@~{krxBTt~Po;MfI>40s#vGX}yp$s7ORze|PW zlaF8Ptoh{&^DT30o3S57lgD!}Q|M}Di0Y!B3!9pgDtx;vB(~;DF`8NYWc~vz_Zc(0 z$~REI7z7jsLKY&%cD&hiKG+}y?N`7flm&_52-JSi z$%{hCL!QzBW*dSPO>h7VfHge^uArdcCrBIghq>B6d&(9XFa@ThxP1Gds~if>O8QUK zWM8q16udJRUx;XGB#F7pJmgPO8}Rw!J2mV8=3OZgIQTNPb5t-%5Vh8RJ2RsG*w{dW ziaVj13UOFXb|ZnJ9(>ldU>6ylsc`iIqpn>->3QQTKI$i&e;f`eVD;FlcmsgJ@>4-k z5g)GP7`WgLNN6SpQI=5Vy-^VbB)^^xp8oz!fP$_mWys3@p0xEz^=dHfy>(0Vq2DlW z=QTjC!(B6020br`r4yp!z8E*BsNu>0i5{+qbl{l-Cks)e;_lSR+zL(tmt4A}(|Myn zqt&{RsF$wcH!McbuQYNn9{7M>wd#^!9dz)gFEr@n z1wwC4ZC78XVkmkj$YY14R?X5flS+91cE*P8gj0e3^y+QrH9eEy$?GtI){RgU4X>%` zJ&F3Uwr@FBYJo`-Kqc=t20okPa zn9IvO2mbbdU%vPozWeyM?w*E-%!ks(Y5Li8FP*XnY4&2sxX}BMpDU(`f0-Qsjvv#R zA@+)!X1*>c6bB)$q+5tlDxghCKbZ9L=Rz3bp;f1d^P?V@d&);$tzwZ*_IK5Mx9fjD zP)p@UnRvQgBuh}Pi&7 zKxE7Ey%W_cBUQ+JQqsr!xA`9~h{g0o!xfo@BLvcoOjKZAUfvxwwcf2WK;0QZ+~gWc z3+~RO`3!(gywDx7Fa!^txi39u{%^=qiKDS2T zeaKlIfI%|1yg-eGtd2^OnOxtK=v-o)m1#?5PZ(j6qU>0k}V~ zXF+vVGkABcwyw_QUk8q`@bFBaniJBAz6S3<@+D9kDi#8*y-_n24a3_&Z=|1^LgZJL z7GEv-ccpu>t?+L&ivo2((Zj?eI7+F9>EEZg6JZVl#F)C7#?|VXvO$YxCakLXpX^g& zH|`;~uFHolV@s(u-*&bz7g1}5q#GsB*5C^V~@gGm<)>V-B`E`yq0Qn(iB~Sdtc4(}iO1M=^mw*$?xY7aY zdYnW6bt!OZf{72YqPAAji)!8Q>>VurxYhVj*SYKK?bW!h5P|G$PJ13}@@0vO4(dF~ zs7#h^BL-;JkDCr*Mz&!lOc_65WGE0v?}o4~@cAxKIDxIu3%sV%%E~3!O2K+6f-_ zKY#+mmn~=IaXIV&^x_&Vbc*6L9bgERR*=7vv!Iel8QHxp`n# zN$c_(RL8imRe!QkFjZ48KY55uU+)1ZAZGAZhd}M{(?s<|h=S68cj-H?gY0BuREwp-f_en%Mw-~*ML9pI3LlmtxtoT|@0wfId{8bG4tc;>ql6wH_By&Bb(NFf zyrDVkAGWLfFjASwE@^m-#s1@&Vz^Wq-3%8mvWY%{`ZCg0XaV)wnrFI2M)$xu(q^J) z2+|gQt4>0#51JX|Pwl5_wAwpZ!*bOV)(i{uZaC&WDE5$i8&q3MGF_i15i++PI+?kW zm?kSB!$TF#mtxNRx!OCzTkB9@X-wcHWD5C#-R3Vc-KGC8H#j6yLABIN=+)JN-b74* zBD+@78GimKLLVKk&wYtoG`!2p%UkhiHn?D^xNK)oWvOG8c}^sRNqutb&C}0F#5~k| z@PGv|C4nqJUP%c{6B z7P=)NMaC984@CXMk0GpOxIcl+wy@CD?C=<8g}T>9cuYTw4z1x55RgIPQ&^3B z9!=E(SI|(f0wicK4F%%h?7^6kY0m7vWlW)mfAYM&)( zED72=@7;WA-(F}4cV6MEuOMK>7r-&Y2ep5=5=JU!VVHvq(AdPp&UQI#wg5YHjzDct z0G7wbOvB0Ey(`vVi&;5);^abxMa6OkS#bk{Tf?uEx^b9%PCl(G;;DFqwLT#;U1x4{ zuu}yG=B(7Wu8!DftA&=ZcrJq|qVHEV3uYXJZ;fLmL$WK*fGWl*#)|t?p$0cd><=S$ zpzj$BwF4X?y5{NW>C$On9b`?sc(dwQtFQ zWn2s3or&JQZQIir7aKbU?z;c>YgjcqH{&Jz;#{Bjma7z<3k-eK?n=3`6l&9y2ExR09bAB%h)mU}n`4t`=LQHQh0SkOk_Mhl+X9ovP zq`I0qy(QotXTjkF#vKfxNd{z2gHn*UJK33YrVIO&D1I_^>WZd1qm{B5>mTmYff|c) zEI)*{c4)*!5D-~hsA2*s*Aj*v&!x{h^a~Fkf8lVpn$O))DK?faz*SnJurPLOZ!a4Z zU!h+L*VuS6sY+et#Y-FuP+0ml-`^j{iuY;H18EPkJ02M%gG%z;K8#65l(aD3h%G1-iy+=!xD+#=p zp8g6b-~wrNR=T$2r^~j>X~_|KB?>{|jtTYr9ai`U$G-*F$4ptUkbH1)iCEsv?It+H zF!J%ehDKKb*8|6i?+kKIVJWD^hJl#(%8x<@hHn9E9VW37`Rr zPShzNIhhLTN={Br(h1+w!k_}1$16_vQ8z5pRD$8`*p?Q-yR|fOwC8{Seg!6n@Htw+ zg$*g#eGuWqCt?W3!ihI+jboF^^RE34b@!c-64$0ys_)?=iz1cFgQNN!dha#sqL_F9 zhvn|V4gl?kg@FZD=sdJC&A?PpJeQ`YOwvz`o~Vs0owdmT8HjT2oKo5Yp5tFXK-u|* zAM$t}!ad*FnTDonyvNSrF1s@!%DvHgrBr#bkBf3E0iMnby}!Tz>FFtSqGZlj_DP-7 znVGRphgVh#K}>~10gsZB68V^}u5v{hlkySgXD|QkGYM$d7D0b#&%QHkbs#1Z!u6I7QnjE|^4oaAqx`kQY1%pOO+23~ zcktZg9DnCxtn@tNz(`%dFo+ZR!XT_dimO zKvbUYXIcbPhC60v^k<)v1!zUg=U0z9|7f2`ADt-myUodD(i~uZRZ6~oWzId?dar0w zU?^H2*?5CitNj@WDr)lCBPKgLn|yPrFFhTq{5Np|-e0gAEs+~7&Tj&r9OSw1pMyO~}#c+uR`48l>@b)b& z)bk%en=*K0Q{TQ_uls$L6cYG0&;ofl^H~hYUY%eZ3G5l$3Hh|%SU^H)*Kfb>8c$)i z>OwL8KaDy$J1ug-j0+3S27FSU3|DWNYt74rYfzp4GfBT2yhx(&?W3G}jU!XdinCs+ zr@Uf#2h+o1T?Ux|kW|~Dp9dEgmywY%05RzTZWnjaA>1oLLe>S`<-jMe56%SWvl0hs zaliFvkjRZqPSVl?jSQ4wKtsvUt*-2yk4x}hinu%d;@Um4MG?=sN}M*yvL=$)qGN0R zjJNgvCOtc=dPIbpo|;0UP}BL@ZIo97J;0dIRoe}n6X)8;&=NyJOZ#{=;Ueo7cc^nF zOZlIvE|te!uczH&j!Ev0BcRm2;Kf<_=Cjb_%l^x1A1B+>#UdP{H#khc>K6zPcpv80 zgU8TOJa)%hos2uwxgx3IwaZH!2nrS(PX?4TYR8jj=)t9;k;fJm&kG8;ii?XmOryiY znIX0SuL3FjBaN{hprkBL6=C{ zB9J}M)a-RO3vGqbRAMgK^FozIks%>Cpmve( z2>um)V2`Qu`3DfYs-XRH*=shDjuLfUA_|pC6i4Z}|AxGbb-pulxEhbRtG%jUbt$g3 zO^2uCKix!+(|O}u&(HpnFHwlRiR_e@Gq^*Ad`6a>`(c+^*|jn+JT;?=E*V05Y|UYS zV+fF($iUYO`ewuZl@t_6p)+JSpPgAlu{p05BWpYPu{krs-F1?C56*YC(i0k8t zl(%o2;!pU*#pzNtLcn&+@C%?oCUtHcBSv8Gqs_x``EqQqaMOJ;UX%|lJ<_Q2PAqt3 zWg$TZr-XKx0|uk4ExhgP8WZm(-9FUy)s!w8X`AhgW=M|;UNVJW8y+J^k&(F(Gvs>Q zr#vH3<`NevE%b_K;8f+mge7^|b^sNXSB;>dN`+iM&We^q9vFanw(hPj zbe?`QYH3-caVsm|7R9_I;7e`+fy=hGwvJOZGEiZ?RFYSOx)=a$Pu!e(EI-cKk0s)lECNmM{vOC0`)p|23mNexm-{lpKSKezg)Ma3Ce(s0++_05scxGWs%cr5pckB>y$Av{XdWy>Xi^ zB_(AWt{mm=o2CH8Uu2JyKG>N48i0YNJ)H|3dVu*SAuaS<6TsE~0GG+@S7nwx>kIhu zVql%i7nvyg z-uspy8T}4oLIQ@>vmR%O0F>UhH!*vw{1)Z583Y7fr=Sd6`!HiZvG`!dSCh4?II;L1 z$Jv^0tIe6>*emMf1m2*w&GMmmETGB3-{%mzddrQGoBI_IssNglg&ht^V4g*07hLsp z77g9p-EARfe?>3x2IwPNP^3Y&#!nZNEYT$t2L7{k*_Pt`*&Uw!mGC6fa=Qugf?V~X zdr7smVn88NeM%UR{d#3}fAQE;&@;;PZd$rX+`nIz@4d^yz{37qhO-G8FgF@No$NLg zF_LDkHwuXfkX9gLgZS{&WsyqypMSD&taYRQ9Wz?u8rHwx%sx~r#zn34rXc6Rr_$2q zZ{H$+c11T;odT+a5FIHfD3BvqN~(!`lYj~7hl3Q36*??n+mQeame~t8fYreq0w^_s zAwj^6rqfuUF_K$@ZS4_s+9U4?mXlDBrr)f&eWo0C5dEx0}ySY zQvwI34!R|%cGMbH;UfVQV(I9pQR}i~0M)TS8m*5Pf9$$~{#TNu9A^TjYU2H#uodJ7 zkxp-*Ma7CdG5x5U-wMWLuN+lvx{Fp;e9!6YKok(TBwaHz^aKP12>%KG5@<~-R%8ij&^Y3R|Bhg=E>S%rfxO$1C)`1#*W|4frwmrNjQ z1RsK#c~C<`158{596_HA%55Tn3=(ZnYW`fy!85(D4|t402?+@`{^yPJq!5%Itz6Gb z&w_++etn$>paXVj>tZ&lvOm@~hOCDdN;4f0dlk&h-$UWF3MtCm1|x|TCEQO?C&LH@ zbR_SH4((Q_c3VnzamsZM5{L+(Jw^bfKLSqWaL~KJuQcMRdNS*%Ydo{EyW8kb3;>=w zw_%w)BteQG>8)cwU3U-8#xUs1rWr{*JU;zg)Te3lbsGb5&Q^fPeW?#xjM%|)4j6*k zAD4hNcmtGvbUs4?@j9$0wm=fulFA+4;g2EC31xa4`g+&xRcqz}4O~W9?$lM}sse z1%{ND&qJLs*+(p`rbY;ebt~)`C{(*ZQD!eKN_T0|HJ)N~*S4DqX@Y+^kO^0)Pg#2JKn3F`X#2;Q0@am36XCOUp`Fv`7y3Z$r&;!;RMXj z&w~bnT<5wi@X5@?I@wrQ7Au$1{~oGa|Ni}3`*X>_Luel~4;RQ^|9O0CW;pRx&-zN& z|3_XRb#891A~oP<_m>rR9@CLTKrnznH1s)L|I7MH9t^TKT`E12R^+Uy;Uqe&Eb1rf z%sU6M-WRMnYaG)+Ad#I#+}d!k>~yA>0ch;d&yLd+XoLkY}YsQ4I-90b)pf>GO*yI zGUubhO#fyBoKf$2Cs8Lr(H`~wo`3AkH{@UnH#Oa_G_v{Qk;1Dp1yuaMh27H zvuBn-G##sVzcJ%?vX0i^vJ?Lx`N@k=VgE`qTruEcK}|(Pg*ze1#}}}-x5s~eT|(mT z^X;~#t_Wza_v$}`t&M1H%kW!8I&aebT)Oj%pJ`F%SHV)VY(16x}w;M#mB zER}uW-~h`wpF449Uo)_ljB2jjcNGb_;9r)KBW2hOK6`?~S-GcKUH-&^+HV>^pIN^CRLOPtrpBWp& zec2K)JUoo|pK(a06FXMZLUc`4qo!v^K82lRaPBYQ;eEUnY-D6q>a}mDd+%OGcJ_n8 ze;$_LTCc6K+M=!@`CEh~+>J`4H4(J=Vq$Mw9s>4{Kv zd2ig-U|N!$lN0vM22|*e73>~AX65I19=0;?{HpM6-xK&mOQ5kaI627$pZqnPL5OHM z>~}Hy{jg=4uu%A?;jLS@vOj#d!%Y$4=H_+>Zf54^TUO@JevdKHM=K%nexc&n*Y(zZ zI*DdCHkx{Qd9|-UQ#CY95#Q;)wgX+>!9|h-CRw?;*FkPE9-NIuR!PZUzI++i10&En z@mvL6(zv?1Tj*cEVrOPd^9u^%*wQ>?p%X$h-(=V%J>)52knylc05kK*$jHuO+}&`+ zteDeNA2II(dvh}xndkO!XJd!9h_*5ij|YQaP%6D9b-E?j@7FYY0~*d_D=Kax#y-%J zVOm#T|I!j02ge##Pv(dntUG0A=TC$nq}>54z6Z`h5E(Ot8#5c6YgsM~H$`RW+`)Ro1!I#NtEu!vUi#DA5oEXh|K~IXWgzO_?BnIVAxcQuxV?xQ#D9KK}ItRZ;laVL$qhMMVi<{cBWV zRK&u{s{HI(l@B1~GU|i!E_fjZMSX4J!L7=qq@FdSbfDK1`tX**{y7Ecr?i` znwA_scc!MM9s^ScdDr~>{O6hM@a?6gC8kKB(*|;dmajLO=yD0eLSJ;KyJO1B>sScC z9hjYs2FoRs``gl;ogJ-97T(^sp(ezf2IV+8&^hXMz2sj~Rwe*9Ixe+wQqqgaF!`0U z1{ftIe5YzaA5%Qg9;KjlJ-*K)xM>uKVK6eSb|<{#Q07+4Pv!utBG4i{PJVdQAYw~! z*ywi(&`aR7qmrE+CscX1fiaZ{TBD`s)w6zbT3V#qIyy1&@qzE&(IINu(p#6ER8O;K(*P|*SFND2&fHEsPtG$(C6dhBN;Q((s~Y$5iE5{U?%QpXmmn0 zzz?|}w7#P7fbGY=#d(NGfAt!Q?pGcnQT0c@gkVoqi2-)J!`< z)Q~9{iF(szFKh)Q02t!x=BARrztoJ^T9KBsUlW5~!4NCWiI>{0|ED5n3gE{`bt1L zAJNz-2~Q3iIxR3!4{U6r#G)0mK*MXN=4+`&9vQ?)IOl^*OK?y=C+pSSU%tq|DuJ{C zd(JV-Ku6~#2zrpC%*)5;+-_|TC^4wlVFv{Td8}8CqEMg$N8fn5ql)mEA@#k80>w5m z2-8?tSQdt|*O}konqshIhI%fi*uH01nJfSDK=$rkVjoEcae88~tts_6-f2FAc33*> zml*WXIH)aXUP45L3_e+21TV-);4lWoM|b^vZdyWo(;xLZH8nCmKEC-~^K{PS{4y~L z8b2eTR&e*xcL4cu&QcQ-u~E;14`v*6uBL}RGKJo;{?1f>z7MGSXAd)TY zf-Jt^YI!F6*2!O{XrU>>=t_r=KgmedFCu#`8L+?ieIU-Hpr=Ox1r>~}flxRsFLZ#y zRc3uX?fCfka|ZxukcLd8=?7MnCFHGE-*W~Y&g~x4Cr85>4>+$ARArj0ii>$Y8fM;$ zg@vAN{T5-t{ugu^;pfD-QN@89i^`13&+ zGAPnRNqc&VX{3pVL6Y6NOkAg~2#ZX4QdAzJFJ8R-(`w1J8zGzpMG ze8x@s8U!a`i(_@x`}ZhMPtO>x3#3}{7O>4pt*R%tflI_JCB=}Flf%x%C8w+m>|0QT zFLgs}f8HBZHwt?iR zS(Xrs;K+LoSDTeIZ=wRdB3T=o>%V^eV%9-1XR_zurb|f6lbU}rcnvV$_GqcX%aev6 z7IIL8em=UU02_a-lZBb4lM6zkh12e`I*6FSvJ%X8Mw(UN3%Xlw>}n~bq>-H~5GI2j zLfUTttXC8xD=TaECx~-S+Y1UPs@;rHdHMNfR&$8I%n9?C`TmCi7x`&qe*Ra{8u{g8 Z;#m@{@0e2Gs@q)P-uIuro`>F#b&DQOT8>2CPu za)0l8{+$1ZG4=r2to77=&w15cAxa8TH?hgF5eURh8EJ791On9;fk2tVybizN8lL(M z->x}|%BW((mnWuCF#H?KPFm9ufxt6B{)h5KB*z?n$>$`Y;q=_r#L30L!5Cp};ACfI z>ttpAipts8!O`5-hUyV32kRpiDl;c1JAO8{|MLf|whpFjTsS9P2m}>EM*OL&Yx4TE ziz|`wSkwIMx{W&nmJAgZ*8O`-+@YKjC@AP|PbJW=i4qVAA9y{*&t}R*<#xA4RU!U_ z{T)5#Gv_KTiVEiHgwdp@53ObhKIXUX&&g*shxY~c`UFj>j1*JzzU1ZI55O12r0%&9 zQICfFApl=OmhcID6AgYO`Ty_-qMDbr&chjE7|g0)d@~upYFBQi77q6HWt$GB{>*)j zk)j~g8F|l^snm3k;v=W|o1!8%R#sNkBHa|G=by*_5=@pWt!$=<5R5!p$ z!taQ`5bu0S&~54Ok7y4go!ljOCb)`9f_$6lo8+9qv)*SBOT7tuD``I8Kgp8*Dl>1L zC^g+WOO=YeYcSj3#c4Y;^)@CR_d7ZZ@)^~JhKCzno}Y+IN~&atq9bN}uDrOdf3=;T z?4A6MRoq+Cdqlt?Dz&gpf!&lLVmmQw~12ro8J_qjMAH7QNZQ_ElGOO1;Q zEGpU(nzcRJoX-CAso3Yr`|Zs;l5xyxt_LIP*2FfsR9NZA<*?5D@ZrsZ7rhx`K|>bh zZUfb|wX=H{Ev>C6U!LdS78e(XQwV7hHu=O{Q$nsCXSGIeuRfE#&t9vn<*+TuDC3zC{(2)T_MD0g_LJzW{e~G>KG+s z6z2C6Q+oXamcn%xYpceo@GMU%&YcI$4BdM-=5?rbJkk!xFZ) zw>PKNcr=G$hfN;VQN1XjWV_^jO65sOZZ>Coaa$QH{Va>i4>>9I4a`cg@f-*{W-@*xyFL=fj)-Gyg z#d5GVCYAGGhiM3nX-CmEvN3XCjBSu3C5Gjl4{5YNAW5%`^{e3j+!@$VcH4hJ;&NR28 z`KG5+z47@{)5VT%LiT?zK4Ekg@EaF%a^j?>rWTiwn6|%>K4H~i#z|selu7GgXZIw3#?>pss^IETkm9d z$^P~0IK0;}Y-(!VU0qbHthi6&i3vq9m04s^U166`d^|rnJ^dwcR~facstSQmN-6~} z`XrzMYoqx2x(Ny?PqpEt&dZk@cS9Iu92)hE`o6#c7NiNAP~X|;*|YsVlYl?9r~j`A zh~K8cO0UY2O<>Jn#FmPpD0g8*UgI|c8H8;0@v-am8)Q#l7b++yT)Te#d(CUh!_8^! z^ffV2(JJQ+@^Z_u>-w+>;W{em>^I*>SC|dIp%!~PPR)#52u3lQO`mjD22wc4Zm{T7 zMfb!#xOL}FZ-w=ww6rwi(1BJ#d{a}CXyopT>;5QGQl0k;o~x-riQ!K{ z&lLauecR@AZ6dGz{fF8W*(#r&3GTGr^4xC5sM~JAd2(nJxcVdKM}@Vvj*iY3o$5#V zFA7R#7MDpX;hKg^jAap?o}NlXfvG|sTD|9IBbgF7YhH)z6JkF;%R?!nrlk#VnQ;r+ z-*;L&`Sy*yBjSz}6waOf{cPLW2E6n0FjBVV;!cXz)>i+frYAM8*Gyif;a!^dPgU8| zL%l%1GaJx1)H|q{YwLkQm2%oJ#Mnywo(rXZ;^f})_>tsZ3 zD1TaCJSrg}p;>hk6BEDQzXzwNarNr(s;b)BQk!Z1l9H0$hdd6yrTJYp`-%-aT{p_d zT$ke1d0+qi`EW^8R8*thoeSY}b-^=M_;NA7sG-F9)=ER2jO zffNB`4=Q=pjt$q`3Y~Cw>MD$_A>C%W<}RN@Kn#u4%--H*(y*BkT+m$s=kV8SqxP%c z>D&+3-DIl`THo%h=A=3N{mDe(_M5=6?+%ZR5!^Ty?TYYf$CdAeF9kBQvL>n>8E!Es z{BFe)`Q7A)hIcmy|5Hj{Ugdf6Ez$8r=AU1_FcK?eWoFv&<&3S3#4;%6xz}IDJ3eVB zf>RS#)Kpg=^X%oeoe@;j6cK5hjIX7HXQ<-k>8WaJYFci;*zp&G(lebxz?o(6@&4AV z$RL-Z@JTkmeiK4XP3-_$4RbmLpMyC3!Ky1la))AK4Hns)c} z2&esM|9JL#^L3@RN1@}&K$+!OC0LsGs#v4Sb>}{p#ZSZ>tovTaBG|4a z9!E9^X0^PwkXsC2S6+P8FsNr8vn;BQU%3GEfP^IQE;Jk*1Yzx{PmGLcxhzM^;?G>_ zqo?UM=I0H(DDm-qU*wkyKi@1)s(l}bf5o2E?|HJ65KhMN=Id9Msi~>2EAbDtJK+5j z1>GLeNJScre>33a7>jS_?_aakA*F2J$gg-8McZ148`8DfYX(E zxmI{_@#s;4&jr_P33DrC4}K-5Mz#+VaFScr zQ~I1TCGprU!y0#cms3{8d3vzcDX>-NDBG2hkuh3id+Ce#@Ypo6eDcpMB`)*^)m#<2 z!Q!ch<5abG>S1G**-U@@B%83XwWSC*sX)83L!bS3_2%rsOrfxZvW*7|PcD(@Io!t> zQa#V%Qyd+5Mu}XO@dxKW6h-9W7Hd}8+=Hk1syF^2AgF>a25&6oc<2kUz63OwyG$4+ zxAG=XNgivGKg3E+{d0ak%=hQgJmtAsox`O#y3$iM$A#5`2H1?9bzWh@aaY#8nm_Jxik~-VyBl6nvXA{|- zFs7WqUZOi;)XdoO3Zh>cT?xjLi%>?br+cdG7d3di_=z7s?uO?m!1vSa%h`78T@j~X z`~niX6*BUhp_zVnc-SpC^^5ffx|-g<56B#OBPkYLWb0f#Wx3f5wOmG8dJe9aj+XYC zugK-`V(KP!K$VMRR!rf`TI52Unw~~35&*&7Kg0;g$htmqS!z^R-A229Lm%*cIHgD` zl+0fo4%9s)uyPhorW{={Fjn~D6BA{iSp4ZZnVVa;%IUIsU3-l~@l|dftxn@WZ&AJE z;O2Dh^L!Et8=JfQo*$UPNQN`KJnk~9BJ?-d8n<0rB{{tp?Bfe``zbr49K{tfC>)Hq4ogkuY+#JbcFsenccL?)$yn zg=q>Qvz^nm8x+FHsVM@B%L^^Jdn*%{leTiVIqsji^_j4Acavph?fIBVh`s3JLfnW^ zHqxwJD~%N&(QnEeGpw=q51pCe<>%i$c+a%IHkoiMNAa=ERF&x25x%I=okvEPjpw^K zHa0fvGxbUC2Y;t4k~0~d)<$n)U|`fZZ}c#vd5XefG9OBRN+87|K0%A6kM(Iv@RIFl zys^ji^lZ;)vBQ(gntWw2t<#K?kdRPRe74~RrSRRC3JI$piVZcZZSL9P-Fc>@gbxcb z%SPeoTUPh`3)4VsUbRBGrJlIkk4vqd0FF>0pQ^))C3A4cf0*R%4J&C1mX|GCq93%5Ppo?6aD9p88qSG(9rwG+z)+8 z*>q_I1@ErB`iW}x0M>x>h8Dl`y4jY}?k6pliEjPPG!w^Ekv;lw6ZRx!N8M_@6`tbd zLLxc=j-M9P3{U&^W}2zb>ixx1jf%^BW-;v<64>-U1I|HbrKF@(gc@*iyclIZSz%2r zN#9c=;5C!L^&OQlw0?@i_h=F~Ve(}v12tz-srD^f1rm9B)!5avqKEP8YvGcrSv#A= z=A5HOL+Okko~uY}9ibHp3-exkFGY&)J21#5ph=WTG`x0TR<5;18|fi)i8#Nw;B)#D zT~>jk96*ag^hwvor8;xCNr+Z2k1nT|kAX?mkx*RDMAcED#EkRJ@V+8Wc5}24$?&V@ zckz-feTlTXwa$+0f6g!Lzi8}yR!6_f{GzS+m4p*9b9zi-bY{S9E(@YN+*bMn$$XV8 z57d-+7<@>==my`(iegU2Ui%gvOMp0e4v$_+it&l4i9CJ;Tn>SwOhEu?JGy z$wheyWPz>C|G zUR%-d7hcsHmt`M4#{%X5lJZuD?$XY_)eleX_D1&drzDM9^Abh)@ed z-;20IR`jyfbt&|~_?x#Ev0721;hQf9JKeEF`~hzlh$tcrU3otyjXovHWYl0GIX&8n zny^|HxjMmvhI)=Rt(ZSjV%$q|pN1y!u_-Q%!wW3HeyKo~i3lXJp02C}4GiKX@V~a< zE6QVD&ZZ3?R%h1@>A)uroZmGLPhd5y^1Kb)bGc1?KP2SORsHj@%sKqK;m_lkCyIjd z=Z=TOc!l=y$rA(aV|PQJABXx35E9u}xvN*8Nlm~n9-H*({~3Z+zso@5YW1ji3y2w)sY+sV9!ue zirDz|^rpy#&4oV0GeDkK%AmrH!DQ;aee;sb%R9g`PeC7{ zURFIB&3$f^Dk!m>yPiPD71tNb01futZ?$~C^@oU*wV%zObcJ;Oj<$c=r1|6NwQ(Sw z`2k3ed=huD=Qrv{zfG)#-W?blD7Z=vKdyM;vrU#+fyj)w7dOdue@h{6Bh@BFWHVGu%kU0WVWD-&sznJJqc`E1o6VdCNC09Flr z5yV)l^8C3>_rw}SNv(N`!wdT^MF)pR2xuU+hSdPC0B{Dhzsh*(f87&+{LehKwPybc zj+5M%J?)*Hj{*LRiiz1fINWDvj~*@1E_K<`MQS{7*%xO=E7dk#(bR6mDFPVY~L?)XGHYK=B3BJR*0+-YS`2dgfhv`)*VEP}!}M)$un57{&!5*d--m zc7G_gMN$s7C-6IdRyNGMj=Rv2DPfc{AHU30JMI~eGN16Ha&vJ<^&lQE# z{=5z;$ua5w=<4RCsdtNBuFB9Yti2_gTFmTwHdeXiEWZq!db!2O2Oe7rk@Iad*?5-b zSH(kB_J%;EtS>O}R zX=_k1EkkUD^&My_DCq~gEe9c;_Fm^$I%%GSIYIf-I0j4v#KaOg3MqE4UoVXp8wR|6 z`%8e9db77XmSL|?r%`)t7S=JJ_c^b};d-@UwIm2p6E|~!sQvt+><^{x5r7d4oL?QZ zC@k&o-n|>I_uvt5UjG*PBUd$-P*HG4Jk`PL?9jL){I=EjxA{n%>c39>YgKQ7Uw1^_ z>jmn{=eT?$O61aYUMQH6yDT-eN@V2PQO-xi#3I&X#bhejC*8*vRJVh04HOjUU$3!c z+w@-=KV4h&U%RC^H?z-#>=i+T?A(%5Gk~Q1n)TC_vm^ro0*Ktb07ruQY`;DC6jad{ ze-1)QfZC%CqHccWG#jGwK3!!1!X{y7w=FcXI5+nM3K^fv=F~-i<`-I&I=sBROrDP$ zDwSdW6-|#r0g2kXxR?Sn1f7w6cGeEW)79BV5lYW(6zgAQOhXjOnwpw@X(E)iwp#)U zA*7#@GJh<|;pXBH5PXp|R1kG#_gJ5sZ~buVmdtcr;?Mph6g&501LWBseO8>`9XBjF zvd4n^dUJUo1*a*PfF{()#1Qt#pwQ7>lCVG^@iJjqj4F9~yN8purGPt}*Ty|*%G3be3pr{hj#{j8qPMPO~M0OI!T+peyz-=OBBUXjo} z6KQXz_UN#ycOT*rp#FLFIvK<|>Dl@_7im84ULUe(nhrV`UV0Ldl1`Cxw=E{-*xL@H zrlh6SQ$GD|xZIbRos;vt(&nWW$i%d-Pft#UzbMmy#?%WPw9gj>Ei_w~nyPm4sCKJi zF^JN;31pZLAIK1Ob#->#6YixRN1Li&HHP`$+O3ZlBgI~*8POmZfv_+D`a7_RsOeN1 zkw@$~@7JcPAFCJXE_G7+WJAe=zlUok{|2(L;1a+dx2uaIBs#h7KVNZ_2Y?X7u%$o4 zS$FxJf>F?}4}ppgTqNqgE1@zW6E1EQ_m`-vbiaTCje*v)Llyg7+B*K%qH9}0d1JAM zYehO|cC@BR+>76Pi|o9XS)i+ksi}Dcu{nTZu9@%(d9X02m!+Uhplt)!A=XS0MaZQI zr~LkH1eNlsl2Y_RIcPSPiCtaNKzmHQ(ms5U78kz;w0!PlC5?fOE)aH*a;b^DhhWP+ zro8j_bo~4uqoeUNL1tN<1vBM0P@RCFpvC0U91EFM)B(jbVXyI;*AD<&(zCFHgGk42 z)P?{3`}Z#@pRils-dqHq0x8+w6L3aMl=_YpXm<|#Y&_MjcYjUcvCa|CqPhEoBaXZB ztbxESH}Bc#>W}P=@uz<)HjF4lQdjE4%or&KD_TnB?<8A}u~vlT#-r~o_h-3m&0NF4 zaGY;JzkBy?=+{klO$cEA*%vkbKQ|`3j;%!iLfG`B zbVgL~*?rL<7_6|~Hk-b_@~fQoHp?qgRvi##9~pH;-#cI@(TJi`sD;| zK-J?_RMvK&JFcgzIhrL#SU#6041n#8pdoo4PMFqxC`D{H9&AjKLN94J+pN_dNR*?0 z_3Bk{NXR^BfJovA-F(@Dje0Xs>k7 zf4>Lr4GK$5k?KXe{dggpX%_*n#vx@L0)6U!k+w1sztbOtG|xBu3RQ=s;sgBlr z9Ep12Dj%9nO>JBKARpu|DE@Phy)h-xvn&sfF@%HvV*sC{%!kLMITj<^?ipyQ8KnLfu?qNMi+$!d) zgh@YEcoCX8 zx7$UdN+y!Z+-Q??ezuj7j~~Ft5fgCxG2fBggTlHq)>FgI^?Me@F_WibSyFg{f`aRJ z`$Zf&?>|FjZ1az0ovQ_>(bdD_7AYx)QIU`O-5N3Ro$NejXen*&?eiNO5ug&fNH5Uy zQ&M`K?Pur=re@pBDl9C}8Qm3>?s*%LZ8aW@?D2O9{3f5v_pD#-{rss4$~Ib)wr#!f zirKCOU@SeagE$~rV*epuectycgi6cULZFZ)9`|nQ~ z`f#FK^YimMHBKQ9wWrH#)&3_7P_eyUI*2rNTBK2rqe_nQH_+ft?KZQDGcDnhNjH7V zI6m0wjQAugqf>XyP?d-ytJBWw^v3z=QERQEDbQt)AT2XsWIKn4tfLRd9%_}%9q%lH z|A1V7A@mP@yKJw4%cS|}k+fF%#{joI_VzZ!oKgm=x9!a?UDIzw3ftze$-$~I1oY2o zIodZfKNX*s*UtZxxIM{p=1R;2Hfo!-na)e5v5T7&ze*B)@kGQ|w!ke@EA--hx3}>t z_PiDE%cn2I%#R+ui@3wH3#Q;LGBUF*yIs2OH2ex`q~SE>*D)O9P}JBVrd_Gz{YR;6 zsmCBZ{P*7>1D!wHsJV^jD$Ju^$$*Rj-GCsh0;s?v$Wa~ENA~B>NKfq<3)1w?L~sra z95+nFGHX}PUCq>*)z`7>R6W^GuMF|b5;$#)oD^s~GkKKwLBNF-0T8a#k<*38bz2`` z13>BwaNsiA-XU%6O+VnJjlq}{zYcL4F3vJ|`C>q5MpowsS7($RmSgMp7KA3j>KPs$ zJ_c}7YzTMSQ5~G+4|4Q}TeG%c-!T>gLlO->OMmT>a~@4CSY}S6%hrH+(i64DH~aaa zeQb`tf^4Z{06LGyp%slpaup96ORDH`!^TIBs5 z_m$ny3SiZe-u`K8e*>pAIl8IbfD(VA9z%0wU_zkIGmcF!wLgjHvBgiuJoO@*Ejw&l zMn+5@A0MbIolyx>#R;P0u}C}LfCjevPTynI%N>mKSufJ|iNtV!jOwA{TlTT^2Hg_| z*}TJMoPv9OkHc?2?wH9S`jE-^GhZDq+D4yxGvVJm7=~uicze-&0rk2{FI{)nfW;E>ggtkLlisGioTb72Srz$+WtnNbXQsKHN~XRLQ(vVeDx4-ODbjC zn{8yIrd!)&AU6Pkq=24W=E8XN6^d=$>EC?8gP+e2aV3HYWh&l?RlFq-B@&jEygrsQ zNM&&8$(}gm>PB!pk104=S=qZu0ttm{=;$%=@f`rG%pjK$(@7<+96NaCBaH+1j|e3q z|H0C%N5VE&zI~w@j;zBY^{X?HOpN*nCgFyzMa^;xVt5M>_9e820~r1PJ^A~;b;_9y zdK2bFj_=voQCUxNvzBc=*&P%iU46$va<5Ovz0<7a2Q{O z`lETHUB_>*pi|(o&{t4c{_C;jXuORthlLfWdj(`_ywntrJmM`_prr0zflH8V$pEk{ zm&DyalYyzcAdL!+qVs}I0r~uFQIqWu)zGT+bV(o%n=`G~Y=dZl3&ctgNGmXu_yLK< z%fMWqH@NEW>Rdu2AL8X{&?^A8$3SLc~O6zMUPxKJ)MoD+^1mAHA)$A$#rkfILN zy4WVoHZm@;qSIKSVB2r~yY5#_pa-?QC~T{>R98|XH0k^85S0poS*f`YY*^%@`T12d z7BKGQ{)|L{LJGebC;2Nw!;p}WVi#V~_l)h2Q0j`Em{wA~-~NdDx%6r*VfgA~C8d{5 zr|X2biPb?xbcrx#m}$f_UW=_XmQ;?6aOv1 z&hK`i*e3rm94M{o<%#K=jwlA>R>=hhMW%(WK>QYN!8D)L?Q%;ySPYI1kA`jQ<1WGq zn)OThpZ)Ed^@&BUcEw^@#4Qq*wpv-zI)TOj(C4m2-j0A%%^tC|(bo0(jmdhGd~PH| z2$CK4K6zNF8^1EH){5>&>R?h^b#idNf7aWOr4zNTSp!**`@0dFWQJQl7%@;oOJFUr zkc1Vql+{iN`F%oH3if#ZmGH@kKGj|u))YBU2?dCyQ{-HtX@j;dtOskcZVLhBN#pp$ z62A&xR`FQI+X|8Rqd02)5-HkuniLL376>T7zIeh^uD>`r!6S;gx47WLA8UWSEi@~u zriKh2!Rl&<1PwN|)|uHz9x)(r+WYrgkc%zz&-%Tlez_1CeeSG-gMLSywH4VH!X9ew zug#(W2gnxH9b!fFdm!sMOv3 zj&FOXJ@9#7@d_6;Xw7-t6?BaT{JgNfE(a(Po8wpJNcvMWa!xb-E%pFL`%pEUxeIBL zZGkb<{`+=6rCZdCJ}>a-#a1|y?zm`>{e(zL-lhG}XjuF*wbL%e}O#xuqqw4;cXVd|$;O{(9Cu&2K+1!lGPW!vgEf#zX#m zOmFd^1?Sjl^^IeBo~!T~%hHuCCRV9Q*7D;4iN!y`qth2@2}w!)X~;{HU;O*5y*qZt z=jf#p5n-dYr0T3Ui0+%NFC`_fgHM81QtAD`x=^RO1%wA)x83Z2U5N1oR{Fx9V8;Tj z?5m1dce!#6>Dflggk-;ltIvNA7(e>-oBS|yR3Mpd_y~arA|i?ABHL@tvz`$P3!^KNQ1$b2wK`7>J7-{vsMWv^@NY}=t*Iqx*uvzGI)CI&JlZehA4>wkBb^Qz*4Nx;ST`nLjVQzK5%Kq*~Udxfes^} z%owjo2Qcyxsl|DJ|35|zc*!&KnAB}T966t$zUqHJ+C+!=$uQ;ok56F-b$NNoy!LN? zm0M17^t8mDJ=Vz|c^4C-yx_u15GWYj8XOda0Y(EP7Xi#sKfCr1tPm;Py^HyA8>@l93lV(wiqOZ4^J94U z4FRba$4HGA?L8C`?0c~{+&Aj zm;)FO|9c^QDz7K*beITX{&6so)jfJrh z^15>(uu4~=*k!XD3&eq`p;yA`Ir!`~p%&cX(V-5-K*W zVaxyf8#>|3V?$l{RXR8cyRnjndJpBzejb!6?gg>$&YLXj+t|}^!0;FObP#U@YKUAJ zp4j@EQ=_z`Mrt4o*(l&*GSU<*pGd z*!*`_^`W3Z@=UoF>{=v6#K72*cRrCQru`jIIogaKA$2}r@vrrc>@aW88g)3a)?Z#oU4n{jh!@5QP4N9Ftns7u|7!I^ZlZCbr)%+J5kz)nm z*Fv7j0n$qp-p2-z*zMXI6wwn`CY|!CM0~z1x!K-~5>YGVr)w_Y{HnX_oAEl7)aBf~ z9x%^*&nz!$6CL|MPSgf6V#_>u5nbh3{ZN!e1(3`QGIn2xdSUuE>u=eKV^x5oavk?> z*X7081PE#%C?kEG{r!Eyx!5wYgpDQqv3^ z%&OVH5LcUe>+g?d+jzkZYHPX7F2>ws4qobDC3b6gby#>j@-e zo8HC0nAL187c2cOhDy*r4O-0H>Z-XHA0OY6wlf4X z&i8*Po}aE2x!mI+BO{Zxva(7wgh)1oFn|5KmTN<6?WDP7`oehD6XEKek+enHohPFO zA?qVy?{D5wGQJ)U%`~*8;4|Ns-bqJ%_p!>0*RNsO1njeBAc6!8~3=? zDlSC-tZSO}o;bX23re>B75-s|axxPevY$NNFHa%r#Cm*uOl0vAREDMkdm7dH)IZc$ zK})#3`a~E|LQEmOxIS4qIFk`fXf@a5$D&yh03i%qJUqPrWYwodW7@q=TQfq6M>})P z{u5>9w_@q#7l8FbHvJ=ngZ#m`m{=s({L_%&SDo~}Upx3V7q+7XGnYatV>q*wWV|1N z=zCfS@F7WGYN~f99g|h}`{<^21vZ1wuvWN-U)b$mWsETe6ioN7)MqkQ3JLpMdP4dU z>j}jDF>!DVAyz)R_dvZ68E-6Oy>>BSnnv6kn7-w~5IqSdsOa~P<#6+ZAYf9-kk*v% zXsV42O&iYu-;!2T1U)qm;__wEe}A5wB5eXzm#wGJU>6QmpV#r1vAwGa{1)`4ENWxC zcro7a|4*I-;>TDE*`bXI7eyzHKkfsEp^>@lZ(S*4DzZvS=Vz&$xSfaebe`YgTw)D$?$t z@ha>4f&?Rfk~9588*sZ52uJ1Br#MH!=3>NT6zxEAeTctt|7bm{Q zL#qCMUvWs4<>`~IF#z&81g~b}MWvw~yI+^Gc0f$T8!)n8X_Ev$zYX zONGxlU0m1sGt^vTYt&b@qm#xpNumb1=R}veCKND9*6&?M=x$8TPZZwMV9~jE__TPE znUx1693nlXAKK}~?e$}?vD@qtl_*@vf0Dpaw$YNGgcYp9ZBr%z(S7C5;DJDp61hM? zUpmCa@NJ5r%se=1wVOxX(ettf)oc6csPo4UWH!L(vaY_BAalG}2K7VD1}UnPcko(P zl*1n86G#xSOG^GiZW+cOkV-`s8hdAF)_1S3utnE4B6(j+Z&o`}d*3};hFTPJr|GleV5-${fi@4QTu9j!aCBS#a|R`~LR`v7I-1rQ zYR&F=JJH{R@M^~mEztc>2K|z=+02)ib^eZ&{<|!b_KuDcP?-^s`_^AEvms_bM|1M? zBV&^y$uFE!6uEd0h zrbNXT$ddPb1wvxLN$v(7K19y^>RYP=M_c{V?F~ah|MbH2%#PJ8MFM~M#yt|4Q7Li3 z6eZH;Hb-&t+E;EFD?l&3os*{~Gh2&SP{d}?8$Yj78~-p50_~5wt+*dMF3Y96R$MMQ z*#06KJltr0HUI02@)yahdND$f8vEmIU2fc@Gn=Y{+w|!1Ft5O59y#3T=fDx#q5Qxc zN`~cF;UVryB&sl(P4DPr?P|>9u&I0algbbs z;aA5Moeyu{7C+c94TCbDDVGOhLtri%!&-n;{znpnQ6edB8HCu%0JZtjGaD8iOkci-DP1#OPyB`^ zO0AS(KT6g&)Moo;fZ@L%ZP2{lBdP5`ZkkHd*lR;Tm81DetA(xkk&1Yp zi!BibhNx-3=;B|C|E>_?#+kq_1W*5D(G{M3FIJ&jJ8m3T6e(Z(IobzR3jg+0P(Tq~lEnW7`CxFLp4w@YThIP_^OjtF) zy`N?8Ob>2K<}A5%%Nump*M9?^FKyqC64L^Is{ZUUcL5~Kig2K<;*qUEc*uz|C;oc` z1O)KV8>%a{VfyYK2r+&ElzmFhp?G^3iRjuH zQP)Emg8oQ2agijeOoS?VgW;lbR(iHFs?2(F8?+K>L!_As0w3M!mU3{5ekliXE{Z}2 z#&4kJVdw+fagJPW=6m~A1<4SCVLV0EKSO$LY}E-|(yZaG&J=u}+N~=BACU?C=dWJ* z^`=>$a7voLAr%c4&;m#Dy1yTY2fJ;z6vqYbCT&LqKLN*i$AOlo;cNidt@2k*mUz#o zNe2nvvrW{B?Cj_UOHy*YDAYI}2D*&pJta7slAE_51;C`(!se#UmXehu!1t48|LVhe z=|aV%NMJ*mdpk@er|Jb-?J%wZ5s`;N9)~O??txXLOiWDBd4pi*EUvD~GVSXgO`ylbE4B?qG`AtL2-?3)tlza1Nw5 zhd?57z=z1;L+|q)DMZphW`c4t)bkrik~B1=Bz&>|+#^WE3>j9qSj}m+qTdXYk$6$` z6`k?f8<>ZIe1VbI*2+pJTjRN?g#|Oj6a;T`&nW+==3Z|&{rdnUPKb;o*NZW!F3tK- zmT5t#jbU+n{(kP`e+{NZsjW0Rknsx~4GK}*$_LO4v@5It>-@-l&X6?9@K4CsgoHR0 zC-i5X-`QLiRQc|1CFr6e2b_{3&3hD|JV6u|7JkX=fo6(RFHF7J={P9V3CS5-J|F@E zFoptMq{7?_DXRyh$b*YmIw1#~G52{+WPK}>leho%OkTbW$YqzM2*4XiC}-c%Ao4Km z2sZ$?y;5jpe!dwX`b2|QZU5hYG<%&&(GYR~v)z2GFa=KXQ3C;inV=9-Cw!mg&Afj~@=z;4w`c`sJdnq5 z#ZOF3lu(J1Cv4iE^;v1bVS5LfRkqD^D4pr&XUnUNAy>=V|H|p7$h<>8s9Bh z>IzhPTH5WN2Sr05$KFqLV`;00#1#vW-p>Gg!2u|c{#z!4`sHA|iO6NG=~v%#hGFz; zr_c=qSrE1qjPJ@d&>%pkEnP`TB#G&bAx z$y@0B`hMj<++hJZffBRf`)i-Kj8j|^uF`RCv=QAB``!~5_(IXul@|d)4dyaPD^kL4 zHiiNbewVML>+jEr1$r=FL>fv zm!^IU+MUMK=&YYUIu*I9Gjwx&hRtEv>G0Y7xx$!Rz+S;5QTL%JC@Dps71I=e%tK%c z6B1#`uxGeABO{Lw`cny#*QEo&7k#O-r}10t=vg;}5yRNT z#BKI1(K`}kbl&+Vi) zgrw-z{l&_Q?5*jr=OcOGBkv~T4QQ@5P!ayGb8_v;+=pRgH~#*YYjhUZHonZ{=JIc& zmUu7ImjS;xsus`$BY;Xo!q6^^5z0zSV?vUz+=aJ2vZEVoHr1B!=wyYq?_&heVMgw$ z`Ygbm5cchfq!QK7x~8-?9};x4<`K||zFQ2twCqD;HIYDBv!~ z)OZQhI0(B|SVq~3Qzl)`0o248f$$gPg5Z+@n&v;hjBOL~)OAZ-D>X5w@)DPQM3lWpD3b#V0mg|Mz&Bl>mJ2!ds8 ziN?_BDIupbOX!O*FpJ3y7o|V&@XTIg|DWMsN<)?@dGNlBwKoeX-*pkmK`3Rhqs|Q( zRRQH}Zn)%A|E7@56t6egEJ78^SoU1$#O#|BOR~ZDYfGkJ6lj z`n9+RO7-r3ufSUOCQ5oF!D}~%fPsc@E{t?< zZ3j~sadBZq(JgKpBu(?UJbVI#mPj4yyJ1@}!KhdMa}|}{I;(cbV=UFUG;ZwNkxh8# zcHSm5-CJpjSBQItfT)_iTQ)BEfGwG0ix(<~wifC^xDx8ZzPnrXIKFW9(N#`N#gsm8 z2G@#^%Wv(mDLncy%Jqx@{Fdtq$-K=#(gHFW>yBnT4smnZhEC2FPZn@!i?sT$N?m4~ zm0#$gbvD*c?CVNXMJS0X5Q%~k@Dt)oD1Rm^*=A;D zt`B^+vcD_%As`}2dd9~$e6o_GUayWgF!}oZXSL8L4XmvC0IaEeO?skwijf~1_O!3W zxb31O@*~C}sXC?v#DeGM=bzfyu|t`Et00A`tN^31{$K@V{a8g#6F^v$%juc1!uGa{ zjIa}Ctsh$M?h>g4B^xgp4AQ}@=>D~@zCA5x^?`xtu-#faJ99J^86TmMjaO2h*FG5$ zb9N&7HO|ZIbDB#Ck=;P!;afH!L8Kf!$^_hX?s{(!Asds!&zaRsWCAG5F@2}{5TfyEE7T^7a0aY z8ow|>fy_HoT9D6z@hY)EwDxeWB$GuB3kN3YQWQD?5W;Yf(&kBHrXAtck%(w#czf4q z{6`GD^onnc-(B%YeuRbQu++`wkKpl`Dd(zwa=g_=JX_;RDYQHE)6-e!F3&GPu@v7o z8`nrggG&?&Ui^ShT!0};(?6;`f@`cV*_~Y&9?%8^Y)lsWtbV#5!O)(@*#FGJ|J|cn zU&_ZJUk3X`=~iB1Q!|sLC>(Vu?qu4jN=ow99WoOm^vd359E?Wqh6mM+ry_yL?tENfuy}EyDW964Fs2g=R<-vT5ym}uOS&m zoWXDSBAtBSOFZIbdFZ%W{*xjGn~T$_&f@$R1XpYB`{t{vC+CkP2#Mj+^+9r;s`p5E zs9hl)Mu2`>Q`>N|Q3O#eQpEaQgE=k~Y;a_J>Oss${7|hrSB`Q@dqHaelA2{^F|X`H z_lL`tFTD^`UKcl~NLib@Mqk8a!@^<-jf`A|c=I&}=gS`JXU2SW{J~XRmePEl0pU%P zA6~HO82-V?@q+~)9T#^n#41aDgGo>@87Ph5z9$SqgP8T4CGvilYF?o(U3(gSW(!Qa zQUL1%0rNfNPww!iICN%PsD1rai9u!4|4}q*abe+2V&ZLB%yV=4fhD&@Zv)(iDf0D< zm8g3HZ(&gSl|7Mm@;hP*h3|f7MnQoYgMB@FLJ2aIOvLaJ9?w2iRq;Z460-@;nx)jI zy>0$rOj_7A`nW(lmvh-G+{y}D@a?ltExo;AAk;gY9a`u0YQ0tt1vK^^KGp*+BhG_j z8;qC}a0Q5k6m?=y*_Ya|-bjVFwM`4H)JfXfmWYZyE$ZwWQx8FYqCnn55Yu3g=U2%-ghn5S=neuf-IFfcH%nkWeb9bfS9 zAPDzfCJb}q2~m=eNCIEkBX$H20&E8MS8bS&9zRB5fBe`GY$+I8%C!^eqG5Ev;oVJg zbF@m`_$&_U0%Q53M~`;A03Xj z4J4x|2Vf znt_RlM9>OWyq8wQGC;XPX0%{3gjzu04j4c%e53#gU3M<6hwD+>8lgnK%s4pvntW@Q zoN>%CCq)wF6FWQ4kRO7fQUJ+dn3mAfYJ86uo6jXB{i)_Oa#Z~QKq$88rv)?}dWCBn;}uJ=I+SXL zdV0bj4B-{nG=S`r1kU7tZ98AV59S5@E08t}5p?wGs46ec+k5^u(Xu&L1tCI#%30RuM;a1N$UXNI&j!D0`J!e`vjr;AQuTf z7@0(OSzGm+eQoB^zklOSj!7TV{;;Qg|6(6&(Hs zbF>U0#C~I)c_PEE8)MP%0uU#S*Jj;^z#z&84^TWj6%(z^#Vwn@a4&6}Q4W7YS1))G z53aIB?_N0ZDyWX{yJISw7>oDn*nNo}e;^uw1vT@-!+|i1{;x9A!dHrR_ZmkA@ohxW z1FJ8d&#Y0b_eLex7-#{rmU- zZH&i4e@np2B4LY`2t*#uRscWUy?5_wJp>oILAHdW{^dr+G{UIZPW@~LdW#T@ z&Y(Sb2_Hcz1a2KJXs@519&8ksmVN<`8{+5y$3xnnCI02;y+X4S9Kk&3*;CR@A;_^Z)d-$EK1l-i;SxgoX zWB~Le9w}*Xb#*l?LeZ#K@2=sR!olYRO8`U!a4%r7I8C_Saoud%%p}O!JzhGl-AuHr zHGt2AL;BJ1ZIn4l^I<$d0WbsCk_FZTlNoF-N{o>ysTX%Y7E zf!RhXt3b6c%cmcXbb)o3z8xPZ(#wn5hMn23(97mlyKcP#Q|m+_xMQ@-tpih2Qw`bR z`7-N#S2iR>mM`$75Ji9qi7VGY?aJfChhAj<2Yv2ait*%4Du?06>$~p69q-VUhfqO% zFJVJeV(0@ig(Nb-W`@<;_tV`mI3xr=Bug6Y`X`SQPKPy~Pxz$4<7akkE)J9iN)VS4eW2-y5)Y~8@o|8XK>^up~%35UBL9VPA#?w5Y&LR`p3o+jE;_)a|YGW zV5z*ct39R#yQddqi6AL4K?GixnQgS6nkGH3dw9}Ya;WuPLGLv)MNd0Ph`&VW%6 z^bb7~m5#ixPn?R+CRH*}!Ft~Vey93KM(3!hoUaLoOGLJ0TzjE{1jP{!?98=VK#fVp z=k$P|f4p}k;Ij7#ufb$7HEO5s+;qnJJ^hcrjUV>b3hVCNzuyA&J=mkJA%+f!L>n0& z?=Lk|g1YF7rho)iedl;ZvH8KaHX-a=J_|hN_w;lBAOe6^9#ua+u4DR9_7T+4XwoCK zWV#+6z6H_ox+)1rCnvj`)mtUr=N_ukS><`7yh&^pJRu{@g8nSn04~N4EiNv^y#-0K zT&JJ?_mIS0T(~J-|GWLE|LV}-;9xybV5+2JEB^9Wdmeh9a53OR#Q^7i zjEKLez!YeWo;WSz0oyJ1)*hs1pR1pZaWQrlMc47gGmu#8{%Y)4I8t&87n3l=s z`eG)AZyP`Tg7Ws;f8X>!Zz2Fv{*jT9op++q%3q(}F5Bks>rSGa8)BBX8gQFk%ft_+ zXNG4d1!gbUAXk8R{za8~&V(%&j;@@k`j^w|NvN3rC!%}rA9LaN6LTr+Xfv?=gm*74 zD~pvnEvz*QW;CDxTZ(Q3X0f|Cw0wK*8F9Ep=iO-cL;hqru+YbzyomGNeSa4yZ|;O- zwGr1}Q>UfPW@i4Q{_P=BGInC$y45l@l>!PhR`5iMWl`_8Z~CF39$Jt4Kc=1wEPSnu zYH4l;E35KE&J7hydR5eFX=z}RaH>^Tf@7(gnXSueXPIeN;MsxBKP|2Q>ViAZ!7_%> zaFF4|3Lm~O9R*E9WtQ)J7F}A>4JHOE6Gil6qiY2m zW-l-MKE@p%yx=mc0@H(&H&kH{%Tk-MCq`f4kz>idKr zM>Q0fbi{mz!f1qG5?dt!zTh``c~%!k&t-QbS6B6Bub5;!QF@!*`F1433KDP{dUFCq z*+2LrI3>=Bc~S%>Eu}p|9blPnI~m@x zhVu@{3olzGRT}y}Oxp9`_^L`t^I!En<*iOppB(myPx6?UbjltY4`fdaSFyav7MG@c zuRKu~=H)pT!UH*ewZ0s8Bn$=%$RtBU&5aDDg*-S9^JZFsC~VN&)V^_rA1v{Obr*b~ z8d`|e_x=lF0pz#?Maaz7R-q=T1eOT36-nMDhqLXA%Ah-9AVLfr1*-)ZFPkSOlAver zgENRqm59V>JeQ!DQ3J2eea{HH9>U^4qAUS6SRfU%)xX{8RuAxjXdPm3F@POT5fmc5 zD^B2?ipCW_Q~oop0KaHBo+FA7Iu0CKW@cvBgDucLVyu@J1E?9;e3V@2SS(el$` zhJ2Y5D@07nfMi{HKub$o!5oa|{|W?Xh~NzDi16R%py&oOieb*nFcS%qr|_w@xIj_7 zIaTu!?nlyNjnFs`Pa};wA!D=1?bEF=uaL@0UNCWEX5a_2{?sZpMFg5vPAd&iKR}+> zJp`cxm?9|UetH|uOK6h+z}2`r{OCIy+w%U2!1UqqTE-m%XzxZKxiSpi>JBgh()^!Z zwUpaY^g;B9!QOq+DYv=s3iyk2B>^l4zw&4JJ(z8(0i=k97tEBPp&@$%Q7{gW$`*(q5{R$)*IArHO;})f_mu`$kwrS~y zJDl^a#9m=7e17dio!X{Tlj*X11J~}TcKHQv;XjtqDV?r%(;;Cp0Sls-E+~W?geHFev zmtrB?0|+u$uP_UWOrVlJLa0pJ?B%P@a=W@Dbo^@6G=7{*hp@qMPCzY^u|sYc-#LJ88l9?=YTSrE`BhTn2n+^v8_1VS(M-+bU;)ny+bcauP0w*$j5}hH_Us!}~0>-h210H(82& z(g08bS8*F_`;8qIFv)t(@4+?4+m5C9?U5?VU-1YpTJqg^(kLM>pD)vAq};l+J>5;i zySI?2J1x}2q$mHo*vMEy{N?(r;d0dbwhCzaqM_VoHR~poXi>{Rbpm{4naE?LU6XL9 z5em#=sPjPNH_usgxtd#;u_1?HFuUOA-v2ctnOCf#eB((C$G^|R0_MdAC#hU-MG42i zK?*Ibnl)VHBBdVA?YD3v(Uq^O&>|@uAnSvYs~zfY>t!eL8zpPQJXxrTpG2*n?UuBx zAtTDC+<{A_= zNpjWXprD{>0Ae@1xv8lLB$jZ5!QzcAXTcA4t}wfi%AMTF?<&o|6b3a*<#cIDiD==l z93!EDGW0|4mpfMdwHg#$qO2L<^^1~*BdR{(^niga7>@kwATtKT zxbZUQd*6|RHMxeNd|1MM9T_s&TZL$^d$E;GQ4$hqa6qpwe*LeSwT9pqUJy_LrWQF~ zi=QO1w@B#e24$pt-&D=W!RF02oHSNaPtQ}YOWmN5kY^9SQeiw0X(+d8I$vk|Q;VK*PP; z$A-gMxPP$gsP_x&+Hh|CYMLZ-b#;YH76K69<;ytQs~94E3FP}0fB%lOY{-cn^40B9 ziJskKJ)ulJ{)A>Ing4F7vBl<|>Hg}S`Gu4*yh36F&h0z~8$6#h)6w&A5eMB*u7*&A9|$iOiINLV8%qcx2fc7>T3A6_lx zb0+uDvoU=8nE8KNb$Sp7HcU@b@bmLSjI717)9>i{VCzu5FvH71>07!VAM)|;eI6zx z$+54fs2?4>r)ESgA3R__z%bj-9;n#;kew~L>7Vsue_DGsPTyyAn}!yK;$bJx2uCK~ znLgXAyJYa zql6(t>5Znze_SLT`v*e)gfj2){lG)dujz4d^onI_#w#F~&-GYaWEl{4D%v<2H zC@@?ft(3aAu*L6i=E4_8M$q_!Frl7N?lN7?#*B79TS39hs@a*X}}x#o)K-&;5@ap$nozH_~)i zzjazDo>qNn``6f{Veh8y%J4|Chb?!r%SUcL-gg+Mc17?#zw-$amjwm(3@vVy58nG2 zzqr+t9IGd3V(NeRhuV6yCK33qSrDT@fruYSDH~R@?d=0F9!R9r))PhUF`_7XGc!NS zDS%lid%mdo8xxX#izPMYelJNQ%dBU?{ytf4^YN$m6HDU*PV;3kdQRWwUS!ADHdNt9 zcLtL^AMxS3^G2~OIet%6Y@JylNT6J=kgjOS(HIj`^|*uOy1nCEyjjX;00#T;sz@Ua zPkrcjg^xB#?9vtFJBfNH1S*dDY3UpfLwKU0hs8UNIVkKhQ$1Tqh2P#$iC5+280R{i zvfw3+{*{=ku>7C#^beQ3*VQyVL%A=~n<+#>WHp#PzYz7G3^a;=F@>$=!Sp1^$KETv zRU=1zWWPhpF1pBF&X%Pfk}pb1OFs(K;$=otU4B$kN)}B8hA(JV9zhVF z>jP|4B6si(DQTX_qG*(&1OuwS zP?!3Aj0?qXJN5f@lJ^Gj3h2=7Cf+-+u^@!zHCP3ZFaCgm0g-5vl~oy=efypMg(uz3 z_HXLX%Ut1#bk!m*9#c^sicqE1rlSI(CtC5ue9Z!0x;7(1t3+c1P7i6+I!HQ{9G10> z!&^9ATw1=_=%6BiM1q&`2Kt!a6;%1GKPR(Tvena6Z~t3N#C@%AVk)^1mUWK?&V>1K z;9W)`mG(U`0ZJx_cdg>1%+>El;bI z99~#oA7tt}uh63?IK2xTX+*+}q2w;2RY(9(_A02E0OE9%ZVRl;=R*0+vuBN zvXB?Du2RQN;gTB?8=2`_%1C-QB;lBaOEfGcnV^xVb`eKM^806PN^kP$Vz%-ckK5IT z7$F?&2$X0693z`CbJG_pD^Yrv-p`c4+7EH*RW{WZ4mj ztdEs7U3^bkUpAMw8veT5s>W*9JCid^vp({xW{2YCV9s6gX`kol@mQ2N8(@cG()&sH z2C8!-OYN$me4+@wLbJmK`>z)ce!WLYlYc@4H;#UoktJw2v)a2zWU;C4b=6D0Z%Lhp z3)L?FEU}AP+sI61dsM#K`*omh@!QbPhlJ%W%*1pHN))$e9oE;^m2=dg0h5~g1wVN0 zG!q0hGe%>)ob65)?>-3voGH}35wod4TcLMcET`CN>Fz1EssDSp*{wShxtM=h`{DU7 zZf%80egSeuFj6c(n|O?|_OeTS!W zS0%HyHxo+pi2Km*D*WO`i-(SDs0eLkiRDw#xhv@hoX1~-{oF?2ScC_QX#Sw&{yVeX zbB*)v-Me544nmlzoqKjy^WTqO(Qo>xCkX894U|W6XyOL{OQ@2Ok~n;LxlDVr_JkO^ z`*4pFoUx1yuO5`Fku>G+TIfksGG*~eJCyI9%tj={ce!4(E%|5uKucSYR?^b{_?emb zX+m6L)U@;H^M*S_+j9=8>}5Ds&y!^YSMRw6|JWzFe!0$(t#`BQ>{vZt8~<)(Nh!Cg zfR>h9U7hFQV_?ymr<&6S_N4&_jPO2YkIBE}EtkpEFdF@a50F$?&Eu0(3f5OnZNq;Y zt2*Vsx3^zO2@tbU zpjY!7VB1}Q6f5ON@-3W_9fSbU^#cR5~{c_St1&pSF-B(ssAb(7XZ2N}2v1 zXsJ^%&nVeBOCt^p^XA-kUMJm8ZRo;QocNHN5hT%w%LFGm^w;D^rMbxb*jHh4j-?z+ zrAx0@X4g~;Y!8LHO7|J|R2^}>&-vqaNX|yNzLJ$M9@|+N8QX*?R22NstCo%8P6QNm z6o*Py9q2Cvo`xbn?5tMx<|h6l6vx)Y->IlD8AyZJ;`!&HoRfW5*(){ed;6n_Q+ujs zU%dlcrY=?pP@#=ezYMk$E5n#Y#lS{n_#2uY(wN7(zk!SG0WBZI>NG$((EEt!y++p3 z(p}fMnp5IO@!G*5>hNygg_He0+?b*}p6At9yxL;VLmRDBp=)>{hru{weY)Q|*D8^u zq_ng+nA;qci5JFg+DSM&H+KwhsyRe&fC7|~is~(}AZ&mu{nsQ-C2|r)huMyNw{DpNPl@unI9|dpKdL59X_HEPyqFR={{5RE$LU~J%twPT z8xBr6wVME51)zOYEb6)>C$r-3uMXF#Evzt~3jU@T`YEcd?2FV#HZ@9e7qC(Q{3;2Z zv~unsEaT|Mx>YZYj2c0mu>v|EDx{b1FVxE%`x+9bQK&ax3|L{@V7}b%z(`HkO`Lga zbQxavJEu?Ik$cq0?60bi*E07w0{xyQC-ci>_hB$2K`qBmy!3ytiIKQO;B66adbY|J zoMhENxt_j~?fRSdDQ-Q~$!h(r-q^HRMl{fHx2$S*V)J!GOUgm;=5p81*TctNrzU5X z&wjgF5k_k(Y?RylJ+QG&dT!eljdvUlu`uIXJpfn&gAdDI0(v#1#|Ic<^s1ru7tFCA zPiXwn>vy_%0xmarW-F{|0Bmg#zC_p6hI8Qr-5$UbswM9$Z^j1hm1>vmdI6XJrTlwS zo(8jeiKkq^D-(!g2m2kIJ9m+AxnPD73$a!^iT>9YDz(CHAFY#93Thv(lPtAbG3Uze z98ys857f6dC;S*-T3oNxNV8fy=yI>CB)O|#s;umgLDximd~{^Lq20Y@1@1j9&<21) z1TOFZVDahiONA4OEaA4?<@LN3-4fdTJ%)#2?kBcwNM0TmXNp1?xp8aD?J|3`v21gB zh>UbxiI~u-*E(zvdA7>UicJ}$1$W)1gI((D10n#Xes)P|;io3F2PZ!tvFE#rGP6>v zUDqv?UYd?^C8p-mKPc$&<9gPMGOu07y>!?5(=kwoB_#o4KWR4`3Sv^si(!GiSnxz5xsr{=C^o0 zXP_FnW}#suBw6xtHPb5JGbBv4trmBBrP%uRxsJ!~-_o*Twp>DCAC;QRHQw^$=`Z0Q z$P%Y*k_+QiL9SvoS!Lk4N!qx2)Hl=nly|(A6ycw6$9{pJW;SDHg)^uVFtQ_k7seiM*;d*!dqXc47`Vl^bf*opA0koJ#$O&S)20ExMF_c=2n;THtO& z{UW(ijby&Y-d-r#g!T9>8})mS=oAe>IC7^=BY+en$`iG(69EnH&5*g<-1V(OT|rjW(v4Ca0|M*nA`%iTmpNs{)m1UK z3V0ja^tAM;0i^K~aM*G2@e4xJm5ydZh5G-&z4hNe#{L-0WCTFtvz)X@>?e`+-_Isi z`=U8{B|&y|6=CZD^<{_G&M+*I2Gz>xv8PkAYn*Ou!=LPD!JG442Zt%`hbJ1>q;}Q~7;ow5In?O?Wre7bDAGdgf*L_4mnx_ zIfjix;WmWBnfGalSKQK~Y@Kz@XKdwUzs6AD3Z932KRKT&|D2FCsOmt%omO8fqvD^D zkJ)XsLqHSetUk{o2cF9( zw_cM(FQ(G?F@#{YR!mc!M|6S-0Bfn{aEcn#K77urtUxo1Wqo-96$1CAa#c5f!)C{A zz$RLp4ot_}xCa~~wS+Ts)W1z=)eq8b-AVa$(KI}qt#ai}b#ZYv6H{9iiTJ91R*;~Q ziU;7z$#7-;IrP?V%K~-MZLl{Pf!+Xi?FUdGhCy;7tKHO3uU2ay7C{%(_WCSs8Lm1a zP-roX;BH?HvPM_Y(F%8FS^pd94x^dBc4}rB|y7O6y zJLT5RJNc9}amC8oA|fKT4!HE}r&$?rBo=`b!!QJ4cG=lJ??$yh2_um+Rc1xerjTcM zbwv~EU03<#1-%mZ$2nlh%K!f5KIKu9(q$%gJbT#j@T-}Tb;j(u;uOwau5WR;^)Bms zw&WV#SAqa)i4si@UL#19Vqt?*5ff6T{(^YXiQ)+TF9FLPzuFh~FZ$pS(EfNcrh@y&V&1UUu{{RntX#G8m{x z++FsCx}ooKyv!e7TLFCln2tIebG2oHCeU4og@W7M_v}ws8H3l?qX<>u{hq-ehnp%0 zf*W>WuYi=0>V}-OQQzW6(yIFyB4VyOrggoav>&stJx_4jc4!$N4I&9|&pTxdF!1I| z@d$yXd-t$|FXDjW0V5NW8M=6s4#ZM?g#)=VtTlw>T0M!~&tD);yMc{OO;1mMc#0fQ zpneJ_tWrM|dvZf=%#hb9Y zD!ru5Gqw6;u}k(n&@yUZ6Er{y>VX2?@%qtwDd0`2=%|sI0W1o}mb@s~E#{!eXfxD=xHKg20m#5lFa)o{c9M|I@cm~shA7V+ z3$O3TR8j>?ohMwoMMej2Fx@)x^mB%)!$}+uUQko9y|cMEBpm6S`#cQREJV8sar|OH zn-=*j012E-bx{%WB!tkniqu;D4t^M1f|)8?kAMV8M?ZlG+#T>Wx3>oZLz1Qun;*{( z3$D=T8prEa{0NQ`wm;d&X;#cr9$)z+EstNm7>hR_z_CyZiLWjwnU{XR!s+Z|PFV}n zufQdV$gBZic{!OwO>AaXLQO3*R&#B9DV0O{ApIv}ck&{r_jveSf2~#AG+*D?6DU-W zpLeOd7?`Md9>^*h@X8bbWoR|7y-D>x31l#_7JMfCf+3Pye||Z{9F^cUwzL1nABs12 zd(-p>ddI>__sM^>ceNRZP6q!avda>fE_{}IA7UJq;3bH3FG^JtT)R`V%|AO-5RI-( zpRQl$?M|MRmBj&`1Ex#I^f6Pvm_Z=uO#S?YUJ(=taYW`_{%ZuF`VI8PQ(k)tC`5{f zh)NTc(UzS&hR(^FI+LHvbhovre?gEu%!(Y^Qg4$_W$|q12|tQYnsmK|+?PJ1_l}Q~ zAQ|5CLT1AD5B_|-AGx@t)INn0-jw{Qb4ob(L~0P0ei>)V2#AISyze#j+ypp0ef0PdNGB^<_hG=3Dlx zqutEblQBL2UGiK0Odi`d=jGh;9fym_mSKe{tpx zH^h55c0lk^36dZF*2!4?rzY0&UGJ`eEJ@H(QzfYF^jtWI^NQw@EDFWL@7!WFXNQ}Q zWHDZ1;oyKC_u*lfofiFttyC7P!yJaDQ4v?)5!W*2PkoX$&E_e!Zh|a=0>-qyKcMwYjCUKK_Q7gs^`u-8Qs4>6>`wwtRn-PtfIli`Spr z$2G)Nzc;3^x~22eebii$r{iDuZe_4H8nDMN8o4quGL!-WXP=F*LnbGRRz}}7ZPeW@ zbz|GaCLpBuq}UyqT@bo8e z6>s)oyjiA^lciOm#FBxn!^jy`uUB(}{FwZ&T2^{U$4U%EsWs7U{T>bE@!}w3U9F_#V7#n0OcKum1+r&jz~`Rq#l{20OqoA zz+OiIlWDZQ@3fN>@3lSdu6Mq|^46%|zKqMLIk7ALQq_nw-*`w#K(C?-IEsEe;?$O6 zoj*#+Xjeh!Lja>1pXSn-u9QT`J_|qxX^A}lYvQcGTj?h~w|Qah7)yyGRILgo07sC} z&H_qjcNjn8zLsBs6Y~)o_*OqwJ|D-p5HnHboS6`fXQLe5VYkYXZ^p#Z^LGY^EKj!G ze6#O!tse}Q2+j%(M~Yi=|8|mA{SmWH8x}6hfq)-94#-ey^l+;_44)WFy^qc50@Zj! zM|bxk4B(xes__KfXo+$Aop)Uqesmdo-92W6#~oUrSIAkhZf^OTf0XVjm?w{K;r)Oi z;97<6;Z*;w!Jkog_9u=-2 zhRc6JI2hxgYiaO}jbX=2{5VZDXL$wtUsnhXei=|^N?vD-DaL?uSS?8 zlIo@lg-ylj{Pgma0<(EE*{Ug z(c09;c?Rp~*wLB(%MbhTP9kuT@;48he%czYGsZ8O5>}agpFxW*u+PV#ub)>fEZ0|X zd7EoXN8tXs=2<&dxRT#vR3wD99a`nX97$_J2t3RjULz9r767G71}HXZi1{B0eysE? zC|zwL`{z+q%DNbtQv1(p)^xj^Bi(Bi==n(B;`fA06SumR(5@?6{4H!o@!4@ zGayQ{@@fHIj815T?7KB*HOiUkiuDT(kVYJ(ihxU?^FnehK#ctXqWthZ<)Lcc?D&f? zUAF^?Q2%V!TcT2&?ITjW(+Qmm_2ZSwb*b3N3g!RSPg9jsov)o(div^E?IUbZ{D zW{;l@7lh+JN>`_MLWBC}Lg*a!d@5wMBHjQLO!QEpYSuURB2KlbZmMPEt&yl9WsV!l z66$f|$M>|R%7vk|;CSCP!o@B5k{+PN)b-i#FMbY6{&88U7Mpo8Kf`jp9XnH4Rs+H>~T z-cKY&G^xrLTf7GAgx01l{3<>=7dPFTwFnLw5Ey>26k|7in8jw^o93mT%gxnn()SQ$ zs8K*AHbvs+i@$My+eha*L%%AJOIRkx#%cX4tlZqDut30NK~FALIJ{RU_t)uo@j7GJ z()#ws_(;h4+__tEC7tEU8XZpFbL!`)ZmD;E&cBFLwIF!cq`Lf5v_w;9JpF+G^8nFs zE|@jo#Rd*E=*E*^MiiV;^g`aS6vUpV8XP5Xyr=s*w_yG&q2eOUorODstTuhXeAXhY zx`r2+tb^(4Pf_{|(F|tydq?7;sHJ31rZ0mY$x)^hm}8{LM(^!UFTKZGkc7^2Q{GQI z|7&2w>rOb+&g_?Ilb6V04O}0crvYQ61}+hy^V)>H7TBvw4b@z&_rV6Wsb~Jzm&7~yk>e&Uk%nP^U)F-a7Y@%6!xIP zV}2Ko1Y}pRGMGI##%8(p^)R1q?MyspC^wu@n6yelx}2G=M=wok=>Vf@%HoJM;$Vwz zZj7s;E-C2r%jA#_z+SRwJ z>Arqzdb3(l_UrvJETkbBd0YnC4~++ol(Lf7uTa(fpB8{Q^6KN+w&`%c@iqfEocsB= z@Xi}?-}~_51NPlZzwIL*a2BBecjE^nQuM#}JXfpETM+CmjJt7kSB#b`XXyJ~^(bl7 zjohbpp9U94pimwG$zsAh3 zt7w0>T^93L##hccn!8Z-f2$fFH*+$`r2h451}U#BjNZU9d(<>1gGT?p4WEFZwdhnz z0|HJ$!Ipc^BhNZN6u;HB-=f=~JPBJO^DT_AYWLmo#XlnpijL)# zKew{&?R?%fOGU#gdr8^e8u}1|ZZQTJn|Cm|uRzH9e+*rM`YOlR`)J?Iv(xngwdYBRuDab{QN zu=VbS`uNWqa}3Y!b!!IvG{#iE9{wRUl>!WSt!>#eW*d?ZzjD~t2%q~1{E7zBNMTDS zjF}ohUb^4O%xfC`>6YE>{u@hM_!dmDVOcNXWkLt`>993TPEL(Vf|6VgON5f)2Sfye z-n0qsY%D=ZkC>P(+^LMlBr$6t0<8La(@j#st=6>5+@SD@P5cFApfcQwO>Uyfk3ZaB zG3SB8+7^59OL-a1c>@Lv`xHw}&R72?Dj<&h&8$F-J+~?fOXcaxz6WUbS|M_>*PIjFUZiUMX9U(fR1t2kk01G;d->VywGdD=Pre4GlzSJy(>XNMrM=6SDw|Lp}&cvkqgi+QZ_~Rn>8jV!o%-{ z2!*Ek_DD2jL>rVK9;;m1$tliRZ{w<$h=I^SIqf_DolB{8<74oYEW$JK&B=LGTU-0$ zhZiviwcz2MKHk?nq4x(#K`y6zc>&ufAc-S(nZjEn@za}*sP^muc01}QN{lo-{7$gx zxh*BTqL3slFcWsF74i}hHZF~`IC2TxK-rlw3VGH(M(%8@0?{ZJgbxK1pIf%!58u0> zT?1(Y8tJq*NpvOe?f$QKD_oet5A(vTOWcHsZYdx=GVG41IxG0!vUICma3J=Jh$F=- z#T7s@Y7pH4;8IDP@;)TqzbEz3WcbtuI-R#k=y)PNOLiz1JsfJe+=+18TkkOc@_BNb zb3WW0dD`3S+7=q9V(q2k(2fHiKR7?1x!Pqz^vj<#RY7nNs(Rdqlek&QXNnd&bZv~n zvsAjds-u~g7OD+I*eV`^^eDUJBMQZLr+CRpzfyV9SCq%KiV4em_M6&T5?}*-^4NV? zae6R!IbOYY6jyNJJC_P0mU6ABJ_g{)-6?J&E@t_onJA<__%4lkL#;|+az88cbrrph zMVV}wxz(d@WwCeUREj@*x*qYVO_F=GBL4K0nk(b&gIura!smJpTY`sETckW3)4Yc% zjxQFyL)}|L@m+4I93rzHoJD}hLq^9Ki~=nbvN*Km)66H>A@=x>SvPs@=v@he;*^3- z7i;g&bQA(Zk`cm`7oXv|qFw}t8orTg&!4{ec?aK{yhE?XyvpU~m}wV%?JGaIr*ksr zoBa2Z3mST8Rxu&;*{w~t)+-)Ls6FVHz(O>^-a#MKuvz+?@L#jg*Fs?hOGV1fgZp0m z1=P8;&Y91|av4Ik1IB)Jci#dwx3ja;+)V9yJ;mSl`TH7Y54vf)68oLHEc5(tUP%sR zO!aPQrjraOaJhW<<71VaEgJR?o}8>~y3geW;90$SS{&eKaF&Y?Xp$G2xby1*`w?m+ zfn=}5NA6-{oY08+IF!C=5>l*DV51(eG?!(0DS;a?3E z*zKvEw3nSkkA-%wmVc2lx@=JAEHB6RR@||VaCN05SB2C7FwZ(}PVmBT?~yVqf}12$ zMTbLSkK-N<-E)U|QT4j?bSem#mWE~zjHQqa*bgr*$jQSS zt5ST6*E6nqFUeqP%K37oW%zRQO>Q#IB2&{jLQ{ex0C88DTD{Fu6AW^~s!LV;7O|&u zbo}SvursH25vqSEUuAb!8vM6$^{oL!J5S)rwJm-A;U}BpyVubqz=l;il<(kiNQSys zlY;&F#1ML=gGjnbXCH~IxfcZbq|@=CT}EM(WoIA{b8vR1dHgsOR+OOqnW%aN*joKv zr(egyrub9kY~?MS+?2Et-jp$qn$eg}8onYx*w=DgF7^u=6)BZ_Kw?(9Y!D+!1tJL; zsn+}-Q$1g6C~Rsk6wi|$eGD$MY9A}Z4hq5*Xnhj}t zO3S#*vn639JGj(>k6dS)fNqW*m2LNVf#&kQz-T3#wnE5Hv;vm3fe6Y?fv%a9g2qQCxxW^xZD*{X`Zg}^71`Wx zv($74`}%a93igVu$0spSg>~FabokFU9f?KN%af8w^?c5qk(8G8jg3I*PUC}e$Mw*k zSZ^wa0%Qay;|Ds(W!;PG+*P9N0a5=V5Xw2q~Ep`$SJgFKgBI z&8z*95ANT)Du=TBT3p(=Slo&eCV@{w8$m!U>+Ns%$R2r1usTVqaS8wR?wK5 zMPE7#&chqYE-pi(rgpkq-u^5nBVpvTR4Juar!TrX+svs~a#amCY&=HIsw}OB?TfDp znb$2*0a8foAmlX1`=BH-^JLq-;5$WU)f`PJ9vmEB#!t z8kMbfjrTJ&vDe^NWmobB6 zv${EDP}L?=;(uBGM_*;w=uu!N=DT*T ze0gEB9P3fzxhh;v!abo{n|FRu$wCt%$MRFToA?n@nZvnE3X(kY;Q})F#fbIKBt{qH zBH*ZFD(h})dVh9y=E-OFEZgD61CjF^b24sL#9#AujE2f@S_q#72(jQM{=Gzh@E0bL zJb5y^y~>EnK>TvCdlpA4S%lR;l)cL4E9uHA-ILcB9+G><&PHB$`)l;7s`gEpg-nO& zxa81J@|mY$i@SIgc+a{a=SSxy^9VLo^(Pnam4j@~S#Hz)K}tT3%|E zYV&M8T-sgmltlr#-^Ez?vjK{VWSJ5JF7jQ>iq%AMkqfQq}c39RXA zubz;l$|OpfgvnD{7J%tD3G`1y+WU~a(*}krO$e5?tJ&9xKh0KWfXSTS*gH>Esqc!Q zs*8<^NOTUE^(#`nnaU=-p4&fr|4_W_QQyk(!iY&Nj*!x9nOAR|QB-1!)s>n!fg);2 zOPRCx*|sp%9Th`Me5S)&vY<{yqSPXXuK5lkI>O`QEi}2=*nZ7ZkV!!*A+O6iA!L_u z^hx<7n&F9pB+4OriKUiu!Yly4fJlwDc=0 zEBm_y3~6nqysRu1U-B&}saDlBGBPq5Sq9G-0!W^RNvFt!9?e=WUJ#pr9>@X4FUY!+ z;ik8gLvs_0zxL0XFS`D023!0RVz47(+voCEcmArqX654kHU&+x2@sd}fX_7s(-sm( zGDUu~h<)%AVA_ArS7FXJX^xwl+667oGJC)txRZEkXO3YETIZH89o|Ll7pC zA^EJ0mmvtIQL4OK{)bhU{G*fF@p8T{SLsf2#5+ICl1uHU6Ff?{t4tr$vcLO)#}$)K zKfkm@VtYHmJeY7`jOa}W-CQmQr$Z!&0S!z{OpYEgqJ6KZXa(KjyieyBc+)R7&CVd@ z0-5{=Vba;3elSLOMO;_80>5resfpv|rk>cWnUQU9o!G4F3N2fu31|mMbI0)W3f5oDhLa4T>zevfar*#Vl&b zhBPx<`i-?$+s^!w@>{rKVbQTVy8hKvx)aOxd_59JBienZrLpjkv+3MIuqsYGslB}L zgpZiZ@q)5R_k|M9EpmZ?bb45*RaL`4gasc33zVnIQ1!MhJeIo6)r@RDFg~mdzJhI5Phgg-kT-Oc5k0(IR0oz$jkGLPWyUOfTkY(S2l|FdPXBAZ(#|^ymhp^?+R3beZrD35m{X4KD=h!bS{_ih2)y z6wKY72e&-JybbQ(v6VwUiSpCpQ2nshy{;5`!~R!jMcf>wuUK5)o=s$%Sq8(~J{QdF zLoC;zk;>&ThS^4tjsW2$w;=xd=eW_T*+88EF(HY!@bY4?+6 z?KlDSHSG`QZ|%#+O>`vtoN~9k(AlLUBqsj-(|u19WXzzehw*R_jG>(T8Jlu5vaU`T znYnm!5~F=7z9dN+thf+6=kT+)kk^u^QB9p1TB+=-P>eJ2+J~E5Gi>W*A;K#U&nN2H zw{4jtBZ($%wS%JtDfOUsN`T4lFo)wCqcx~q2?g9(!68s?={uA8V~6!TZ%U|u z&Tc8wr_+r2y_;K{MF`mj@&3;{#82eDNl=`eidM7z?WcS6E>AyWEddJ>HK%zJxj11I@!Lpf1 zsK-Lx<#{2_HdB+BF&t;XfUrTBdokD(8&3`jxH(;m<{P4|hf)K~lJp~2u~i2wkWBZm ze;$65;m-W;issmyNAR0A${gWTwv-QQ4 zdiXz@+S=$eHD|3y|F5_24(GD}-=?&aGD?I*$P5{Yl9JoVO32KL%&hEaP(;cqm65VH znHiP6vp1EMy^749^XmToe!t^6p69RUkLNy)`}jDJ>$=|8`~8~d>pX==i!XoUrtmef z)DT%&U{CUfGGxdVq|yQGRKJ&+I2wJ&i@xN;4Gi3Mjz>VNh?=_$O5z0D zyNM6?g9J8^Gh!(J!Q(@GSvG@bi9zfx;i3yHH*6lW3Y>oY_Ib;A-*BToop-`sfqf8y zu;s~nWV3X!*<#6BPunfXzNTCArI~Z?^D}FMQ&m${z5Vf8TGX=apSAEM_P3K}SmPR3WEUPt%dbE8!A=72pA^Yp&N? zaAU1*ba~B4)9xq)*i>Ti0vs=8Dk{x&bFDkfQLgd5qwUDEGHz&V@D#^QFVk9xA5pSvWjdv4{4SqH4L0+E3v768$LJOS0RFeY;mf(g0+I~xj!fe>HXUwU0pbu=>^WGQ8=eaKA z_(3FF6lTU7!>;&RBIf-?Lh(AaA&FT|rL$V{%l9`y`tOXesTemVNd9Qe9U>NAIX+&O z#o{bO_mlgrtAbWfJGUP9Brx3IXk7;{1FSpRlAqw85TZ$i+=Si_$vVV#het;TvWg>; z$#q}$sHA9UE_GILK2dDD+JZ;fZF{qTo1&l`MH%DagQU^z35R<+!jG1+{m$1ynT)gAM7~XWg?&n?=eCgkJOvkd`**=<`xpj4Mh3YI#&^jr0=mAQ~ zds?YCV3LkVxT>K5SgxC>#(Bw~mh>Y^-L>4UO|7Kx7REHx*{lEPT=ij};D82Vj-uU- zvlfAs^NY_!v3(DBEL$2VJ=LdLbrDnR@=Ai3ZFze;4GRkkHxJLXOv7!Qp}Y0<2X~(? z*&k!=j0J*{dQ%sKkAP0itKa=jJ^4jjYsAe`A7am+zjOJE`MZEiYK#Si7gM8Kxu(v# zdCQ(-jO|U)bziMIjq4czmSwoiHszWla!z8p&P)9Xo`&Y&!G&fSrf(x775BF7**l4h zffJ7Wd!*xd%eF&@4k2qtw_YaPWV3x>+e242R-HQ2Un)1ZQHRQFkw^!GIr9Vx$?)PS zxp#FgkWZcw$ux0zUb)wL$Uo7xqA@Ge^Uob()(0X|q(tox`hUggZww#o-y)f+PWUB4 zdjSaJI&LF#%kq$thVab!z526-AFH1PaISA$el)4(XXjD4Ryc{l`TW8{%0q`_FeI3C z=CxS5X1wWaL2`=Nk-D^OjW2&ZytQ5(7L2*Ta>>ay*4wBeFz0zlNI9ko8(L!J?*_Su zpZl|JU+I6Cg?PNXvGMUn1_pQ4-PXc=79KnN+;E`q?OX`wPoaTPO8vZ(>CS?S=Y8x7 zI+n96c*O6T_NShdztUQBf7QcZC~veq_jb~In=*@zlyBqlQEbRmyb!_hqaT4`Sk4i5 zsYiwJ;uoaD>FD`$^zAoi^IEyPs49XZ=#An+)g@KtVP4vkqBW};=eSZN4pv2trO|1v zSvCZ?6dAExak-%%$Q2rYoeeSJCvMG#`6xy8lgpZ2?%C)lJ_psrAAwWqE6Nt$~$ zyICId{@+M&q{`OTx73xM-Bo^5e z1NqFt%KCt4;eCm_OuxB0$tUJC8EGb~EE<*` zEXtgrMx-%sGgztlqPi+4LDNp!moxaK?#IOPBOarZYwFv7{-lFH7j9UTR=TJ#x6aCX}&Zn#;1Uq}Mkv zaO^(C*{=|ee4C$7>%|`BPRYfUEGLl;1v`be%_pHJa&~P>5KK7^y=2Np??wYil;Tpv z8)J%9#G4Zj1X#{`?v`iXlyxO#DZa;9wld7!!T6y*y=q9dhWBKOO>gzfXAJc7W@iqi zG;nz)y+!sws1g#29}A1}VqwVi!RN*F1@X1qxzhbo>#c|c=H})kV^t4OQQd#_N;`an zTH4^}_x(~at+aiWzT1q%)NS8UFs&4op2w;3maRKsyqHMV!4NoRtm9))TpSx#<*q~9 zT|+|=@5fX!qKJPD2nljLG?<-;Yr8Jb=*IFx)U*MVJhFc_H+Esf6TdAXs6%wtJH2W&vWo}*+*Dj;1;p7muv=}mM zFq+og`Sa$Z;#k?x3TiZg4>0t;DFS69~B8tmmoLIVC}eG{ngTyz1c-uL0*i>j)W z@P$U06UyURtMv-A6c3j)wmXPGjsN`ihX-jSv2Co!g0p}Bx+qSsSpNKFSOc;}$ta)o zo{~y4xsT5c(W^oB4EtH9l?|Y75V*M(Z%$Aybd=F z9~K6=&2L`0bZI;Ac&5lmbUgjuAgEd&{IkJ?cr94FSn3g-4G3{Yc-Llm1G;Y=i$pN% zGW7gPigRUN?VwXdnKY%O?c@4&tA@z#|H1+s+Y}A1uMFNbb3IogKQ;}R0Evk)0k?)WFsP*+zxxE2xoP@7FuRk?(-GTF* zw~nEE9^2JJ(at|03{Fzb)po#LIQ%j@6`W(}XTxFx?X^nby*9I-pXQQhX6J9Pj)op* zX1=>^&%un_(^^lM&OHJBIU*uVh#T721jfgkhE}m+Jnl_G!Xu{vmxqX6!Z135gYVv( zb$N>Cg>YA}lgR6DLxU_o+Oy8bQbh7G>IIQ>7Zi+jFUXG{iIuNN~{iZP^wc!5o zz+8*!jN9bNBjlIjTQflsTC%aEEo?L3uc$%U3)HF0L}EM%qEVU9Dj;}hWZyRLr=*mE zI0hIonSqZeG+IIQV|gZ`Twf)zD0hi9ncXQ=@6-2^>XRqiQmwy<6-)i&z)63B>i34j zvG5fU*E!)VAwgD;NX1`CBc}@ynq`4UlBh;N*J1CZ+s_}L2r13$*RO}$n?kzYDhF8! z3N7B3-ZBdaP(rHnOjzmb$hwa%Yt_6QquqKl3iMM~rJr@&aU5UVv>pzAzYoI2Lz&~2 zV&T=OHpJc-y@f>LX>Ox|;BsG7^ZVPGH#9%^T%}5JHv4DKQHn8< zEz&AGmFkU$YRH766j;x)G-WhY_Psct8gaOz@$g{WFD?(pfh+{w1b7<07hHaZzzh0V zp+0yJfs_d#EEt?rM=rEerJcww5x#>R0A<^d$?nl>rBNo|1~>rh{QYai+WB-{->B2# z$vXpse6l1i&b&L}!TzZ?w9q`Jt;A00Ayk#oAZ2mUE03zIN9diKz1#bj6D~KPHGU7x zrEJ5B-IyjP^U_LXV`e5rmCoE(b|JsBpC5KOWW%4~Nq$o?U$bDRbtcReERQ@Mhs zLv1r%FEl)4ihG6)R*KSh29ctO3$nO>oH>89-z zy>{8KafBBq#G^G$O-w3KA#6khG~S+k=+dS3Lr^eO%fs$P$wvtW0StRbFe~iT&(4zf z)IfilotGz2(K>hix5J_OoCSx@>9*0PH9s~DS)O+syW@HFiPZfLh5Rw$=}Rr9F)FQ9 zZ%JVx5H8+zjmwMD&k`8gLrz|SD9~*!$hQvEW&|%FU4Rd;==`XGL1V+U$~GOqG+r+#8PuUOgkv0p&iuR}J8AU8){kCK6*0d|i-Ly?61oaxUp z*#qHQ4x~_58L=LunH%h-sXldJm!o1pF4Y-SQjUHg5AZk7%GFv{Cb~~W%x8t z(mbh%%SNu#tH}N=#D!%%`wJZ|`;6J@^^g7*QbDVB;rX$#vEZjquhYJj1HP`$zDY$> zbEj8uFcm=+QT>z|&ilFnGfUeZ$kqLZm&2WG0rZUZ)T#G6fprcx)=iy8Vsm{9MwUA- zA7#mV1mAsKh1|*eVgq}gSK=m{L4@A7>WWi%$-~R7vN|<|{EAVrzS}+dc5KhFjdQBo zezoTrkbU-G9`jgSfm5o2kofoM@~^^*SVH~d68T6hMD2!mVwCxNfXKkf zy=9ct)a8KNka@+%9>*M_0qQWQzYL9xT%FGLhQHU%gxQT#2;V}aShQ!|oeP$WUj&u? zj(u1V^766z+tG+OskD>5`HH0v<+nKBXZ2E>+4d|*_haLnG3vtKKYFX}c62Qhmf@me zyg5SHnv$8@p{p5bC`Mx#8nsd+b)T{Bq9FP2{Iho9!Ud?0F^~|W=>K6h29Xh|(NGc- zz<3}iJ*4M+7Yfh2v5`>*k->x17TahkGN-3X)F2@tLE+u^T3N55m7d68=W)`a^O1W~ z$)2~`ci)L)9Y5pBPrh;a#O*6?dl=_$8%O6+P1AKpr#-mYwR`t&0)dNB>aMOXl9Mn+ z&~~~be+`Y0Lb%t7?qV56mk0R&-RB|TVr^$f8zbs4zX*Z0Gq{Jsc(N}j(=HF4ncvu? zJ==XdY*2~a_NS`Y>|U#ijNC@YLZOVbV6u!YXhp7YbrWuINl^B+Y&CaIan55J($v>G z&89Ez*-^K9<34i1zg>AWF0nc9!RjH6JHg5M9frXGGBzZbaM>jsXJ_WF1Vb@G{{%BfPXekYg@$2E|{5e1p2l)Zgcyn0Ny~!@hd+iYwmXWVBNFTFt%mKCsR|FQc_Zc92>+WaZ~#l85O}uO9E%iPdH021Mw1I;95&O z+`vn@x0GIlcOyFe63d@;1^f?W%T)b%TGrS4(n%70uW#o*SYI}#`;OBPl9Ij87YnXo(+ zxraF2{;$&)nF6#;X)^&ofnmvGd9Uwjxk;wc@QCC(Z~^U!d- zHH#Ewh#&ok;l$&4&9{$lt4}Symo{?nfP3ycs;U8djT*kfX8XJn?=aXPEMkoI;%cmq zg$lJd>^`EYjEszrWo28v9y}l;=zAfS>Fev8_xcZ*<%oPovPR?s>?P!6_Ye&{5FjFr z1ciqxidb@Ky8z(LsX%a9DcB@_K}(Bnbaa$RI?E~%yvCwU9F~1l4u9k^` z(9kE>k%)<$Mc%t|i247+_m!TNbQp{h6>%&_6k85ZM##-y)^*agtpCybIc%W8@<(Ux zE|7A7$ip2L81#TaPoEORWEc?~9(%6PFMP9wm54>7hjV8dYF>fv9E2}~^cW`o{Xtkg z&}x4K^EhOZ?(X8}&z}c_*B%ZRRx^zAf`jyX$&*9DL1hb1xWr;j7_siF*di_U#PtojtY}2<(u#>L2z?T6fI^x5M{+h;$|J7xA z%8&n9y`LgyG(R{n7mQJ;zK*;lUjUx?Yz#7%Enxf_6qOQFDU3OD9zU9Q9;FYyhfphsOW3~L^n8(H z<<`3p-kWRt>oMO6zd)JEQJ*r4bi?isP6dsQi`(W=3Nx^hefsd7y7fHV zpZR0(HVc5KsVplwnG3Usrii;xp54fG%AC2FuJP!f+TmLYbTYhgwxVniAyfAR>Uv(% zx2D`Z4i3swSwdy)xx-E@+V-!l6u2Chl6woH$mT$`0>;qOprB|5X(wQ;N|?8^*1j{{ zlT)*YTqY%zEc-uL-g6`)E zYOX-k?>T*1q%v7ZK)?`JUZ2$evqg^4qQyLCS^QUg42H`_?S=UtKYFKdj51sF)eBh% zxqV_A)2(}Qc28)(yl!*z9;y@De<_&V@+gQrXd!4c5l&}hV(uRr?&BI)sc9C#m@hrA zcWxF1?90l^`ysyy3X$hH6`Am6pvASlbt^x1UEgy<8mIU-hRP3%IdBjn>kzK`h6XOk zVOQ@Orke=~kovnAQr}3`9{M?RhJ?da;?U~PirZ6~Q|yCcyH`j4Y#ur;LeVL`$L5Gp z8;62K@vS>Hqq5qZpHHmH;Tq-VE+5QpuzFur8alsGK&1$I48o*6HJpn)waEG zjicj!Pp1$Nu(_#Xw6t8>@ZKavQ1}?v2It*=t>5BA=Q)HE=)W>sPq| z=$SuAAO|FL=ia@nCr|DtXgi>EK;E0K#Ow;>B`)n$w+a6QYq^DBhb~zerH5ch#{2i> zEiEl`Hh^GYFZyENr|PE2o^=a(=dpHDM7XlI>&0z4a=INxyW81@IV*oVOv~P_eGoDw zbNQX32L%iM*uTicKUD``&u?O$cSBE1g$R=w5sG?z-CGX4pc-i4!Ja zorey_P#>fVdz_U;QhVgB5}w_;E1}&S6l&yk$Ulu+-pQh7>Wc=U-TZfHRF{b<)Z@pu z0ql-^k`$D_ETh6vRU}}PJRjdmngNxG3zOHb5d>yCY-~P0c#*2zC2p$Ny)EE9xAux) zgSb|(u5vvey>Rxz^Ir)8mz8h6PdLTq`G@wcfbg3rPZHrJ@@hWyd|J2gMgHf?hi|Hc z1cg-rSwKK7M2mcVYj_w$(@U-Y3ts|OG0SiRw&TY`ubn+{Vm#MTS(ktU(x@Ktkgx63 zrw=PzkSjURH~vNu9xW!V@cCG$>+|fbY#-r_>ok-#svoG7)p_*kFLM_UEqRtiqD^zs zeze|>>5qZ(5T#^5Dmm?8Fun5R=sgees~jkq0#L9yHZJ6Y`-UmIk%;X*gM#x~betk0 zpB1AjdwNzs>3zJw$;I^;3C00NMqa_7knw&dwh1#;G4c!01}c`F}03ja}dQYklKxkmAwP%*FD~eLpRQzH3`$O$hp;8-mO*4=pDqnAR@BsF+HK4b<5WFnHcB& zwx)hr1^^rX`$ISV(3vwIK6E@&PmTqJ2XL{A=u?p%kB|hy1ax8M;cLHFRt_9FQcsYR zYvvhM?E_kj^9POE>m;TJ@kb_`U1bf#*HAY!Y5RFDh!zHfq31g0&^W--JLxa=7=dnV+0q=^oF5{&$dDV0erHLYOkE#A z>IG{r1X24>K-YuB2*o4!ss)^viq=-DD_5?dt5$}lzr2+OwKq`2hfGaPVc7_P1%%9E zYv0Aj^1~6Qq@-kIX8x!7@H= zPLQf6h1`5@Zpc9VBBss3qm+qQwW{hNS{i-!+%#`;JCt-inf(0y-=U-{Dkf%VZte$_ z2!duiA>l`)VdBo5oI6PibVi6ZI~ci60x0nW z4!BPgCM|a-zj~=B1NcTQ)WqWn%6K_RNiRxTT4#A~G;{n43JMm$H^Twx#9F)+qG@S@ zD!l4BzZjq>v`Is%tE*KzpDD&CXRNA(ywsLK@%0VCZ!rQRMsSCQAObjHo}<+b0V;_K z)#sD(X{8j>($Xj7!?;zXE?fwO_2xvlstjKof@JvL+f16EOEMEWOFGpO`&huFmbxrU zG5!kVnG@X69yJN`{O-#h0+!(rt+C0;Wbw7BY`+)|KfQDfKqEpR-bb5jYHZ8_p5s~o zRj8#^La@Hulp*eC$gzmJDHms`9C}9@_{l+T&FHS49!{Wgd<4+ikNf`Zo63wPr<7G% z6i{NE9UUFZYb|xDaUIPKL`UMry~Rp;8xAzMV>{r{<#z4dncrK-o7baru9NEH&!0ct zoGX^ogxi`OQD#zyK&0lse~ih6sj%Ji&zgQLv`$8z#2#xKT}@1~NQi0wq5TmRIVdRZ z{ZktMU@K@f|AUMC>o~6`E|9=$`YeDG1;;;>)5yvyAU!?(O+6Twuv^~XIQR%`Zf?Ra zVq+U~v?goty%)KB;?Vy6lE%iY$e&02M$We{t&(C~pt7NX9K?8Awr<5D)o-ZFgqzzj zgv#ia_{?|*22vmtCMG4YG5Z!bom6`#en8YAc2qRfBH_Jf2SxSTmj*(U2lnR&qy`F% zT$FQ)??f-8zo}JzOZ5?{or73}LHYFL5e5dEHGd^l)fR?2{XZUg0+?xt&9yj1hnA^a z=!r>Mk*Fc-O!0&sy>p1W#!-zi@9}ZSmKGHi z*)fgXHh0?)J#!`-lZdbz#IV^dN5@#DsIy1T-6`s;%74|PCPOr8AvNH0GpUxU?taqr zFP7O0$MKs!nAqacdLNCbun6>&BTxP=N}``df+I0 z$3m6k{qW%q+^5e7kf9(7Att(4&>9?x6EJnwg(nbgleMX z36dCM8W;LJ5vX^ChzvNtEi6mopHVxP^NTL2na68sX$csEXRrq59;hUszHBlxG(7B3 zwb1D~m|BlaM9zwjmlpyyscPX_Piz-Y&m8>wOp8ju&OvY}5>a-@#=Y4Km($)Z8F?3Bd?@I4vJU8%=iT0gez?X1X*pe1;@No_fn5e(6Z8I^ggaV?oEs&-mSb4#V z@#3#YZJN%%Z|0BM;Z9|fgyvn*|LuI~J22))U^`8EMHUwqxvnx^M@iRb0mb=>nwmtl z@cMd%zngGqY)l6IFZ@t2q#I}e*J4K4{|n*h%x9}<%mMfa{oT8%sa6I5xf!TC95{H; zCp&wwSgnkqeOQb$u+W{nKmE&>FJg}5gfYfx|C=GXEDXE-`|eiQU6?q1Qxg)vf2NoW)Cbac6PhfwL7rsT!O$smQMN7OA(+FyCwIGw(+nY|Yb#ZkvoeRM{f<;f=6J;OarvThc zBh=DHV2tH7HD3_1$6xb`R;G8m67~URaZaEjQVV-4M}8hGp{`1qZ6m9Rld~59@6rH~ zTPn0Hxq!f`MOYDv=j23uToA80VYi{yE~M6M?!F~~!%qMN?y-0_KPWc|OI;xy&~T`<~6Eh8fXMVE`?gQcaEhYw#%QZP49 zBK%WDON%PTLsSXfTr>hgIf>#pVG#Y`j!+hg0o%}ISl8^qzYcv72qOCLw;deRKwgwW z9PusY!|FmgPcU9a{WUD=)ifLsx+5y@fx?}cNyB#k`H5?o$=qVY9ZM~TiX^BWuT(TP zDvr0t2WG)H?oJAAfpZUFI#*J^I^O?b86N2Xe!uP4GUEHqYvW(u+=m`WB1kiX-~X#ZY!D>h=DjG0kR`PAxHoJ=Pw><-9*j`q%%sI zGn#3@nGnLBsz!)Y4g(_u2rk0hb;+v2%|b9o21+bxZj;8#Y5#0+MA+b3~be5CT^fUl|T28cFsH1U{5t zuY^DtuvCQ9baW1;qOw|4NNqzVEZG;39 zh&mz+)(|9$LbZorWW$s+F}(BXKI-3F2pUgnYU()vFA4oa;7jhs#*Xlejd!HdBYrHa zt@Xn`hn%d-bWW%BiTKXRUC7IMcmhy+%|bE)4hsOn)e`M++K~80VlX!w6pKqU{dKUn zGs*i<)0YQ6k>KjQ;Ir2Nh6!uPk75V9>x$UGpdaT9rG?;_NwCu!i)SPxTffL&Jg=sW z33s`niHTacB8YB-MPfg0kHB^R%f)MoRlrQA7aSI82HL795fHr}MDeV`!eJP+Cy+oS zef|A);=r>b&|FQ+Gq`{MK0%qt#O&-&3mEk@-IrAK^mQ0xkV3qMfZY((vjn*u397~Skb|JB zQjX!_(=H3F$bm6I;*D>T=-pW{0jGo_CYV8JXo^jQF_KW1H2n6{h=|L0L72xSfR?J2 zgM(3E1UZRZ3cIQiby{e~$AF3wU7f@QP8cn7TEYZ`vT<-cDk>5uP-tLfa)ym~A?}i8 zu!jBtG2DU9Sw&M5pb214PX2ZqyY@La;|IyD~_%wY3Sn1aSUUT=fc z!cjt=9&rSb(PkL!W-fOGLKIMsudo_`n=fFyo&92qrrblc62Xs@5M7O`r#gWKmlBUA zw)tBb3KEc!F#gbt5OX|s>J)W!{rPn7{V~U?F^odwuws`mF-?5c#!tNJ|L Date: Thu, 13 Jun 2019 14:12:28 +0100 Subject: [PATCH 1525/1783] Convert unit tests to an integrated test Structured as the original unit tests, could be moved back to unit tests once MPI is working there. --- examples/conduction-snb/conduction-snb.cxx | 1 + tests/integrated/test-snb/data/BOUT.inp | 11 ++ tests/integrated/test-snb/makefile | 6 + tests/integrated/test-snb/runtest | 4 + tests/integrated/test-snb/test_snb.cxx | 185 ++++++++++++++++++ tests/unit/physics/test_snb.cxx | 206 --------------------- 6 files changed, 207 insertions(+), 206 deletions(-) create mode 100644 tests/integrated/test-snb/data/BOUT.inp create mode 100644 tests/integrated/test-snb/makefile create mode 100644 tests/integrated/test-snb/runtest create mode 100644 tests/integrated/test-snb/test_snb.cxx delete mode 100644 tests/unit/physics/test_snb.cxx diff --git a/examples/conduction-snb/conduction-snb.cxx b/examples/conduction-snb/conduction-snb.cxx index 59b222ee2f..d43201bb02 100644 --- a/examples/conduction-snb/conduction-snb.cxx +++ b/examples/conduction-snb/conduction-snb.cxx @@ -24,4 +24,5 @@ int main(int argc, char **argv) { dump.write(); BoutFinalise(); + return 0; } diff --git a/tests/integrated/test-snb/data/BOUT.inp b/tests/integrated/test-snb/data/BOUT.inp new file mode 100644 index 0000000000..bf64523209 --- /dev/null +++ b/tests/integrated/test-snb/data/BOUT.inp @@ -0,0 +1,11 @@ +MXG = 0 + +[mesh] +nx = 1 +ny = 16 +nz = 1 + +# Set periodic +ixseps1 = 1000 +ixseps2 = 1000 + diff --git a/tests/integrated/test-snb/makefile b/tests/integrated/test-snb/makefile new file mode 100644 index 0000000000..526313b1cf --- /dev/null +++ b/tests/integrated/test-snb/makefile @@ -0,0 +1,6 @@ + +BOUT_TOP = ../../.. + +SOURCEC = test_snb.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-snb/runtest b/tests/integrated/test-snb/runtest new file mode 100644 index 0000000000..f283dfc8ab --- /dev/null +++ b/tests/integrated/test-snb/runtest @@ -0,0 +1,4 @@ +#!/bin/sh + +make +./test_snb diff --git a/tests/integrated/test-snb/test_snb.cxx b/tests/integrated/test-snb/test_snb.cxx new file mode 100644 index 0000000000..b95095cca9 --- /dev/null +++ b/tests/integrated/test-snb/test_snb.cxx @@ -0,0 +1,185 @@ +#include +#include +#include +#include +#include + +// Convert __LINE__ to string S__LINE__ +#define S(x) #x +#define S_(x) S(x) +#define S__LINE__ S_(__LINE__) + +#define EXPECT_TRUE(expr) \ + if (!expr) { \ + throw BoutException("Line " S__LINE__ " Expected true, got false: " #expr); \ + } + +#define EXPECT_FALSE(expr) \ + if (expr) { \ + throw BoutException("Line " S__LINE__ " Expected false, got true: " #expr); \ + } + +/// Is \p field equal to \p reference, with a tolerance of \p tolerance? +template +bool IsFieldEqual(const T& field, const U& reference, + const std::string& region = "RGN_ALL", + BoutReal tolerance = 1e-10) { + for (auto i : field.getRegion(region)) { + if (fabs(field[i] - reference[i]) > tolerance) { + output.write("Field: %e, reference: %e, tolerance: %e\n", field[i], reference[i], tolerance); + return false; + } + } + return true; +} + +/// Is \p field equal to \p reference, with a tolerance of \p tolerance? +/// Overload for BoutReals +template +bool IsFieldEqual(const T& field, BoutReal reference, + const std::string& region = "RGN_ALL", + BoutReal tolerance = 1e-10) { + for (auto i : field.getRegion(region)) { + if (fabs(field[i] - reference) > tolerance) { + output.write("Field: %e, reference: %e, tolerance: %e\n", field[i], reference, tolerance); + return false; + } + } + return true; +} + +/// Is \p field close to \p reference, with a relative tolerance of \p tolerance? +template +bool IsFieldClose(const T& field, const U& reference, + const std::string& region = "RGN_ALL", + BoutReal tolerance = 1e-4) { + for (auto i : field.getRegion(region)) { + if (fabs(field[i] - reference[i]) > tolerance * (fabs(reference[i]) + fabs(field[i]))) { + output.write("Field: %e, reference: %e, tolerance: %e\n", field[i], reference[i], tolerance * (fabs(reference[i]) + fabs(field[i]))); + return false; + } + } + return true; +} + +int main(int argc, char **argv) { + BoutInitialise(argc, argv); + + /////////////////////////////////////////////////////////// + // When there is a temperature gradient the flux is nonzero + + { + FieldFactory factory; + auto Te = factory.create3D("5 + cos(y)"); + auto Ne = factory.create3D("1e18 * (1 + 0.5*sin(y))"); + + mesh->communicate(Te, Ne); + + HeatFluxSNB snb; + + Field3D Div_q_SH; + Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); + + // Check that flux is not zero + EXPECT_FALSE(IsFieldEqual(Div_q_SH, 0.0, "RGN_NOBNDRY")); + EXPECT_FALSE(IsFieldEqual(Div_q, 0.0, "RGN_NOBNDRY")); + } + + /////////////////////////////////////////////////////////// + // When the temperature is constant there is no flux + + { + FieldFactory factory; + auto Te = factory.create3D("1.5"); + auto Ne = factory.create3D("1e18 * (1 + 0.5*sin(y))"); + + mesh->communicate(Te, Ne); + + HeatFluxSNB snb; + + Field3D Div_q_SH; + Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); + + // Check that flux is zero + EXPECT_TRUE(IsFieldEqual(Div_q_SH, 0.0, "RGN_NOBNDRY")); + EXPECT_TRUE(IsFieldEqual(Div_q, 0.0, "RGN_NOBNDRY")); + } + + /////////////////////////////////////////////////////////// + // In the collisional limit the SH and SNB fluxes are close + + { + FieldFactory factory; + auto Te = factory.create3D("1 + 0.01*sin(y)"); + auto Ne = factory.create3D("1e20 * (1 + 0.5*sin(y))"); + mesh->communicate(Te, Ne); + + HeatFluxSNB snb; + + Field3D Div_q_SH; + Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); + + // Check that flux is zero + EXPECT_TRUE(IsFieldClose(Div_q, Div_q_SH, "RGN_NOBNDRY")); + } + + /////////////////////////////////////////////////////////// + // In the collisionless limit the SH and SNB fluxes are different + + { + FieldFactory factory; + auto Te = factory.create3D("1e3 + 0.01*sin(y)"); + auto Ne = factory.create3D("1e19 * (1 + 0.5*sin(y))"); + mesh->communicate(Te, Ne); + + HeatFluxSNB snb; + + Field3D Div_q_SH; + Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); + + // Check that fluxes are not equal + EXPECT_FALSE(IsFieldClose(Div_q, Div_q_SH, "RGN_NOBNDRY")); + } + + /////////////////////////////////////////////////////////// + // Reversing the temperature gradient reverses the flux + + { + Field3D Ne = 1e19; + + FieldFactory factory; + auto Te = factory.create3D("10 + 0.01*sin(y)"); + mesh->communicate(Te); + + HeatFluxSNB snb; + + Field3D Div_q_SH_1; + Field3D Div_q_1 = snb.divHeatFlux(Te, Ne, &Div_q_SH_1); + + auto Te2 = factory.create3D("10 - 0.01*sin(y)"); + mesh->communicate(Te2); + + Field3D Div_q_SH_2; + Field3D Div_q_2 = snb.divHeatFlux(Te2, Ne, &Div_q_SH_2); + + // Check that fluxes are reversed in y + for (int y = mesh->ystart; y <= mesh->yend; y++) { + if (fabs(Div_q_SH_2(0,y,0) - Div_q_SH_1(0, mesh->yend - y + mesh->ystart,0)) + > 1e-6 * (fabs(Div_q_SH_2(0,y,0)) + fabs(Div_q_SH_1(0,y,0)))) { + throw BoutException("SH: y = %d: %e != %e", y, Div_q_SH_2(0,y,0), Div_q_SH_1(0,mesh->yend - y + mesh->ystart,0)); + } + + if (fabs(Div_q_2(0,y,0) - Div_q_1(0,mesh->yend - y + mesh->ystart,0)) + > 1e-6 * (fabs(Div_q_2(0,y,0)) + fabs(Div_q_1(0,y,0)))) { + throw BoutException("SNB: y = %d: %e != %e", y, Div_q_2(0,y,0), Div_q_1(0,mesh->yend - y + mesh->ystart,0)); + } + } + + } + + BoutFinalise(); + + output << "All tests passed\n"; + + return 0; +} diff --git a/tests/unit/physics/test_snb.cxx b/tests/unit/physics/test_snb.cxx deleted file mode 100644 index 27e0bdb239..0000000000 --- a/tests/unit/physics/test_snb.cxx +++ /dev/null @@ -1,206 +0,0 @@ -#include "gtest/gtest.h" -#include "test_extras.hxx" - -#include "bout/mesh.hxx" -#include "field_factory.hxx" -#include "bout/snb.hxx" - -/// Global mesh -namespace bout{ -namespace globals{ -extern Mesh *mesh; -} // namespace globals -} // namespace bout - -// The unit tests use the global mesh -using namespace bout::globals; - - -/// Test fixture to make sure the global mesh is our fake -/// one. Also initialize the global mesh_staggered for use in tests with -/// staggering. Multiple tests have exactly the same fixture, so use a type -/// alias to make a new test: -/// -/// using MyTest = FakeParallelMeshFixture; -class FakeParallelMeshFixture : public ::testing::Test { -public: - FakeParallelMeshFixture() { - WithQuietOutput quiet{output_info}; - - delete bout::globals::mesh; - bout::globals::mesh = new FakeMesh(nx, ny, nz); - bout::globals::mesh->createDefaultRegions(); - static_cast(bout::globals::mesh)->setCoordinates(nullptr); - /// Note: dy = 1/ny so length in Y is 1 - test_coords = std::make_shared( - bout::globals::mesh, Field2D{1.0}, Field2D{1.0 / ny}, BoutReal{1.0}, Field2D{1.0}, - Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, Field2D{0.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{1.0}, Field2D{1.0}, Field2D{1.0}, - Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, Field2D{0.0}, - false); - static_cast(bout::globals::mesh)->setCoordinates(test_coords); - static_cast(bout::globals::mesh)->setGridDataSource( - new FakeGridDataSource()); - // May need a ParallelTransform to create fields, because create3D calls - // fromFieldAligned - test_coords->setParallelTransform( - bout::utils::make_unique(*bout::globals::mesh)); - - delete mesh_staggered; - mesh_staggered = new FakeMesh(nx, ny, nz); - mesh_staggered->StaggerGrids = true; - static_cast(mesh_staggered)->setCoordinates(nullptr); - static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_XLOW); - static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_YLOW); - static_cast(mesh_staggered)->setCoordinates(nullptr, CELL_ZLOW); - mesh_staggered->createDefaultRegions(); - - test_coords_staggered = std::make_shared( - mesh_staggered, Field2D{1.0, mesh_staggered}, Field2D{1.0, mesh_staggered}, - BoutReal{1.0}, Field2D{1.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, - Field2D{1.0, mesh_staggered}, Field2D{1.0, mesh_staggered}, - Field2D{1.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, - Field2D{0.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, - Field2D{1.0, mesh_staggered}, Field2D{1.0, mesh_staggered}, - Field2D{1.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, - Field2D{0.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, - Field2D{0.0, mesh_staggered}, Field2D{0.0, mesh_staggered}, false); - test_coords_staggered->setParallelTransform( - bout::utils::make_unique(*mesh_staggered)); - } - - virtual ~FakeParallelMeshFixture() { - delete bout::globals::mesh; - bout::globals::mesh = nullptr; - delete mesh_staggered; - mesh_staggered = nullptr; - } - - static constexpr int nx = 1; - static constexpr int ny = 16; - static constexpr int nz = 1; - - Mesh* mesh_staggered = nullptr; - - std::shared_ptr test_coords{nullptr}; - std::shared_ptr test_coords_staggered{nullptr}; -}; - -using SNBTest = FakeParallelMeshFixture; - -// We can create an instance -TEST_F(SNBTest, CreateInstance) { - HeatFluxSNB snb; -} - -// When there is a temperature gradient the flux is nonzero -TEST_F(SNBTest, FluxNotZero) { - - FieldFactory factory; - auto Te = factory.create3D("5 + cos(y)"); - auto Ne = factory.create3D("1e18 * (1 + 0.5*sin(y))"); - - HeatFluxSNB snb; - - Field3D Div_q_SH; - Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); - - // Check that flux is not zero - EXPECT_FALSE(IsFieldEqual(Div_q_SH, 0.0, "RGN_NOBNDRY")); - EXPECT_FALSE(IsFieldEqual(Div_q, 0.0, "RGN_NOBNDRY")); -} - -// When the temperature is constant there is no flux -TEST_F(SNBTest, ZeroTempGradient) { - - FieldFactory factory; - auto Te = factory.create3D("1.5"); - auto Ne = factory.create3D("1e18 * (1 + 0.5*sin(y))"); - - HeatFluxSNB snb; - - Field3D Div_q_SH; - Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); - - // Check that flux is zero - EXPECT_TRUE(IsFieldEqual(Div_q_SH, 0.0, "RGN_NOBNDRY")); - EXPECT_TRUE(IsFieldEqual(Div_q, 0.0, "RGN_NOBNDRY")); -} - -// In the collisional limit the SH and SNB fluxes are close -TEST_F(SNBTest, CollisionalLimitClose) { - - FieldFactory factory; - auto Te = factory.create3D("1 + 0.01*sin(y)"); - auto Ne = factory.create3D("1e20 * (1 + 0.5*sin(y))"); - - HeatFluxSNB snb; - - Field3D Div_q_SH; - Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); - - // Check that flux is zero - EXPECT_TRUE(IsFieldEqual(Div_q, Div_q_SH, "RGN_NOBNDRY")); -} - -// In the collisionless limit the SH and SNB fluxes are different -TEST_F(SNBTest, CollisionlessLimitDifferent) { - - FieldFactory factory; - auto Te = factory.create3D("1e3 + 0.01*sin(y)"); - auto Ne = factory.create3D("1e19 * (1 + 0.5*sin(y))"); - - HeatFluxSNB snb; - - Field3D Div_q_SH; - Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); - - // Check that fluxes are not equal - EXPECT_FALSE(IsFieldEqual(Div_q, Div_q_SH, "RGN_NOBNDRY")); -} - -// Reversing the temperature gradient reverses the flux -TEST_F(SNBTest, FluxReverses) { - - FieldFactory factory; - auto Te = factory.create3D("10 + 0.01*sin(y)"); - auto Ne = factory.create3D("1e19 * (1 + 0.5*sin(y))"); - - HeatFluxSNB snb; - - Field3D Div_q_SH_1; - Field3D Div_q_1 = snb.divHeatFlux(Te, Ne, &Div_q_SH_1); - - auto Te2 = factory.create3D("10 - 0.01*sin(y)"); - - Field3D Div_q_SH_2; - Field3D Div_q_2 = snb.divHeatFlux(Te2, Ne, &Div_q_SH_2); - - // Check that fluxes are reversed - EXPECT_TRUE(IsFieldEqual(Div_q_2, -Div_q_1, "RGN_NOBNDRY")); - EXPECT_TRUE(IsFieldEqual(Div_q_SH_2, -Div_q_SH_1, "RGN_NOBNDRY")); -} - -// Spitzer-Harm is independent of density, but SNB is not -TEST_F(SNBTest, DensityDependence) { - - FieldFactory factory; - auto Te = factory.create3D("10 + 0.01*sin(y)"); - auto Ne = factory.create3D("1e19 * (1 + 0.5*sin(y))"); - - HeatFluxSNB snb; - - Field3D Div_q_SH_1; - Field3D Div_q_1 = snb.divHeatFlux(Te, Ne, &Div_q_SH_1); - - auto Ne2 = factory.create3D("1e17 * (1 + 0.5*sin(y))"); - - Field3D Div_q_SH_2; - Field3D Div_q_2 = snb.divHeatFlux(Te, Ne2, &Div_q_SH_2); - - // SNB result different - EXPECT_FALSE(IsFieldEqual(Div_q_2, Div_q_1, "RGN_NOBNDRY")); - - // Spitzer-Harm not changed - EXPECT_TRUE(IsFieldEqual(Div_q_SH_2, Div_q_SH_1, "RGN_NOBNDRY")); -} From 23824cb6f0abcf8a9c02be42c26e954dead7ea9d Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 13 Jun 2019 14:59:53 +0100 Subject: [PATCH 1526/1783] Make SNB runtest executable Odd permissions on cluster... --- tests/integrated/test-snb/runtest | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tests/integrated/test-snb/runtest diff --git a/tests/integrated/test-snb/runtest b/tests/integrated/test-snb/runtest old mode 100644 new mode 100755 From 3ff8db9fbed7f7a57e684c1d7a65e26c89c24936 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 13 Jun 2019 15:11:14 +0100 Subject: [PATCH 1527/1783] Fix bug in slepc solver: use VecGetArrayRead on const data --- src/solver/impls/slepc/slepc.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index 767c0c380d..153e772ef2 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -337,11 +337,11 @@ void SlepcSolver::vecToFields(Vec &inVec){ */ //Get pointer to data - PetscScalar *point; - VecGetArray(inVec,&point); + const BoutReal *point; + VecGetArrayRead(inVec, &point); //Copy data from point into fields - load_vars(point); + load_vars(const_cast(point)); //Note as the solver instances only have pointers to the //fields we can use the SlepcSolver load_vars even if we're //not using selfSolve=True @@ -353,7 +353,7 @@ void SlepcSolver::vecToFields(Vec &inVec){ } //Restore array - VecRestoreArray(inVec,&point); + VecRestoreArrayRead(inVec, &point); } //This routine packs the local fields into a vector From 2eebb9a89313139aac15fca00d4691dde6d59e2e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 13 Jun 2019 15:12:24 +0100 Subject: [PATCH 1528/1783] Remove explicit setting of EPSView in slepc Can be done on the command line with -eps_view --- src/solver/impls/slepc/slepc.cxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index 153e772ef2..42eb6ce02d 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -298,9 +298,6 @@ int SlepcSolver::run() { //Find the eigenvalues EPSSolve(eps); - //The following prints the used solver settings - EPSView(eps,PETSC_VIEWER_STDOUT_WORLD); - //Analyse and dump to file if(!eigenValOnly) { //if(debug) output<<"Writing eigenpairs"< Date: Thu, 13 Jun 2019 15:48:35 +0100 Subject: [PATCH 1529/1783] Don't write initial state for eigen-box example This adds an extra point in t_array, which is re-purposed for the eigenvalues for eigen-solvers --- examples/eigen-box/data/BOUT.inp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/eigen-box/data/BOUT.inp b/examples/eigen-box/data/BOUT.inp index 333e97d30f..2c58ccd58c 100644 --- a/examples/eigen-box/data/BOUT.inp +++ b/examples/eigen-box/data/BOUT.inp @@ -4,6 +4,7 @@ NOUT = 1 TIMESTEP = 0.2 MYG = 0 +dump_on_restart = false [mesh] From adf92744b48349544f8844174651d0d246e9c946 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 13 Jun 2019 15:58:07 +0100 Subject: [PATCH 1530/1783] pep8-fix eigen-box example visualisation script --- examples/eigen-box/eigenvals.py | 151 ++++++++++++++++---------------- 1 file changed, 77 insertions(+), 74 deletions(-) diff --git a/examples/eigen-box/eigenvals.py b/examples/eigen-box/eigenvals.py index d6d6b52af5..7721f4a8ed 100644 --- a/examples/eigen-box/eigenvals.py +++ b/examples/eigen-box/eigenvals.py @@ -5,83 +5,86 @@ from numpy import argmin, amax, amin, arange + def plot_eigenvals(eigs, data=None): - """ - - """ - fig = plt.figure() - - if data is None: - # If no data supplied, only plot eigenvalues - ax = fig.add_subplot(111) - else: - # If data, plot two figures - ax = fig.add_subplot(211) - - # Check that the data has the right size - if len(data.shape) != 2: - raise ValueError("Expecting data to be 2D") - if data.shape[0] != len(eigs): - raise ValueError("First dimension of data must match length of eigs") - - eigs_r = eigs[:-1:2] - eigs_i = eigs[1::2] - - range_r = amax(eigs_r) - amin(eigs_r) - range_i = amax(eigs_i) - amin(eigs_i) - - ax.plot(eigs_r, eigs_i, 'x') - ax.set_xlabel("Real component") - ax.set_ylabel("Imaginary component") - - overplot, = ax.plot([], [], 'ok') - - if data is not None: - # Add a data plot - ax2 = fig.add_subplot(212) - vector_r, = ax2.plot([],[], '-k', label="Real") - vector_i, = ax2.plot([],[], '-r', label="Imag") - ax2.set_xlabel("X") - ax2.set_ylabel("Eigenvector") - - def onclick(event): - # Check if user clicked inside the plot - if event.xdata is None: - return - - # Find closest data point, but stretch axes so - # real and imaginary components are weighted equally - if(range_r == 0): - dist = ((eigs_i - event.ydata)/range_i)**2 - elif(range_i == 0): - dist = ((eigs_r - event.xdata)/range_r)**2 + """ + + """ + fig = plt.figure() + + if data is None: + # If no data supplied, only plot eigenvalues + ax = fig.add_subplot(111) else: - dist = ((eigs_r - event.xdata)/range_r)**2 + ((eigs_i - event.ydata)/range_i)**2 - - ind = argmin(dist) - - # Update the highlight plot - overplot.set_data([eigs_r[ind]], [eigs_i[ind]]) - - print("Eigenvalue number: %d (%e,%e)" % (ind, eigs_r[ind], eigs_i[ind])) - + # If data, plot two figures + ax = fig.add_subplot(211) + + # Check that the data has the right size + if len(data.shape) != 2: + raise ValueError("Expecting data to be 2D") + if data.shape[0] != len(eigs): + raise ValueError( + "First dimension of data must match length of eigs") + + eigs_r = eigs[:-1:2] + eigs_i = eigs[1::2] + + range_r = amax(eigs_r) - amin(eigs_r) + range_i = amax(eigs_i) - amin(eigs_i) + + ax.plot(eigs_r, eigs_i, 'x') + ax.set_xlabel("Real component") + ax.set_ylabel("Imaginary component") + + overplot, = ax.plot([], [], 'ok') + if data is not None: - # Update plots - nx = data.shape[1] - vector_r.set_data(arange(nx), data[2*ind,:]) - vector_i.set_data(arange(nx), data[2*ind+1,:]) - ax2.relim() - ax2.autoscale_view() - - fig.canvas.draw() - - cid = fig.canvas.mpl_connect('button_press_event', onclick) - plt.show() - + # Add a data plot + ax2 = fig.add_subplot(212) + vector_r, = ax2.plot([], [], '-k', label="Real") + vector_i, = ax2.plot([], [], '-r', label="Imag") + ax2.set_xlabel("X") + ax2.set_ylabel("Eigenvector") + + def onclick(event): + # Check if user clicked inside the plot + if event.xdata is None: + return + + # Find closest data point, but stretch axes so + # real and imaginary components are weighted equally + if(range_r == 0): + dist = ((eigs_i - event.ydata)/range_i)**2 + elif(range_i == 0): + dist = ((eigs_r - event.xdata)/range_r)**2 + else: + dist = ((eigs_r - event.xdata)/range_r)**2 + \ + ((eigs_i - event.ydata)/range_i)**2 + + ind = argmin(dist) + + # Update the highlight plot + overplot.set_data([eigs_r[ind]], [eigs_i[ind]]) + + print("Eigenvalue number: %d (%e,%e)" % + (ind, eigs_r[ind], eigs_i[ind])) + + if data is not None: + # Update plots + nx = data.shape[1] + vector_r.set_data(arange(nx), data[2*ind, :]) + vector_i.set_data(arange(nx), data[2*ind+1, :]) + ax2.relim() + ax2.autoscale_view() + + fig.canvas.draw() + + cid = fig.canvas.mpl_connect('button_press_event', onclick) + plt.show() if __name__ == "__main__": - path = "data" - eigs = collect("t_array", path=path) - data = collect("f", path=path) - plot_eigenvals(eigs, data=data[:,2:-2,0,0]) + path = "data" + eigs = collect("t_array", path=path) + data = collect("f", path=path) + plot_eigenvals(eigs, data=data[:, 2:-2, 0, 0]) From 27ff2d0b0f437139b3673fdce2b3dbf6e86f98f3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 13 Jun 2019 16:20:55 +0100 Subject: [PATCH 1531/1783] Tidy up eigen-box example visualisation script - Make executable - Rename eigs, data to eigenvalues, eigenvectors - Add docstring - Add legend to eigenvector graph - Check eigenvalues length is even - Add titles - Fix spacing between subplots --- examples/eigen-box/eigenvals.py | 97 +++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 41 deletions(-) mode change 100644 => 100755 examples/eigen-box/eigenvals.py diff --git a/examples/eigen-box/eigenvals.py b/examples/eigen-box/eigenvals.py old mode 100644 new mode 100755 index 7721f4a8ed..7b52fc60f2 --- a/examples/eigen-box/eigenvals.py +++ b/examples/eigen-box/eigenvals.py @@ -1,57 +1,72 @@ +#!/usr/bin/env python3 from boutdata.collect import collect import matplotlib.pyplot as plt -from numpy import argmin, amax, amin, arange +from numpy import argmin, amax, amin, arange, ndarray -def plot_eigenvals(eigs, data=None): - """ +def plot_eigenvals(eigenvalues, eigenvectors=None): + """Plot the eigenvalues and, optionally, the eigenvectors for a 1D simulation + + eigenvalues should be a 1D array where the odd indices are the + real components, evens are the imaginary + + eigenvectors should be a 2D array whose first dimension is the + same length as eigenvalues, with the same interpretation """ - fig = plt.figure() - - if data is None: - # If no data supplied, only plot eigenvalues - ax = fig.add_subplot(111) - else: - # If data, plot two figures - ax = fig.add_subplot(211) - - # Check that the data has the right size - if len(data.shape) != 2: - raise ValueError("Expecting data to be 2D") - if data.shape[0] != len(eigs): + + if eigenvalues.shape[0] % 2 != 0: + raise ValueError("Odd number of elements in eigenvalues") + + if eigenvectors is not None: + # Check that the eigenvectors has the right size + if len(eigenvectors.shape) != 2: + raise ValueError("Expecting eigenvectors to be 2D") + if eigenvectors.shape[0] != len(eigenvalues): raise ValueError( - "First dimension of data must match length of eigs") + "First dimension of eigenvectors must match length of eigenvalues") + + # If no eigenvectors supplied, only plot eigenvalues, otherwise + # eigenvalues and eigenvectors + nrows = 1 if eigenvectors is None else 2 + fig, ax = plt.subplots(nrows=nrows) + + # If we've only made one plot, ax won't be a list + if not isinstance(ax, (list, ndarray)): + ax = [ax] - eigs_r = eigs[:-1:2] - eigs_i = eigs[1::2] + eigs_r = eigenvalues[:-1:2] + eigs_i = eigenvalues[1::2] range_r = amax(eigs_r) - amin(eigs_r) range_i = amax(eigs_i) - amin(eigs_i) - ax.plot(eigs_r, eigs_i, 'x') - ax.set_xlabel("Real component") - ax.set_ylabel("Imaginary component") + ax[0].plot(eigs_r, eigs_i, 'x') + ax[0].set_xlabel("Real component") + ax[0].set_ylabel("Imaginary component") + ax[0].set_title("Eigenvalue") - overplot, = ax.plot([], [], 'ok') + overplot, = ax[0].plot([], [], 'ok') - if data is not None: - # Add a data plot - ax2 = fig.add_subplot(212) - vector_r, = ax2.plot([], [], '-k', label="Real") - vector_i, = ax2.plot([], [], '-r', label="Imag") - ax2.set_xlabel("X") - ax2.set_ylabel("Eigenvector") + if eigenvectors is not None: + # Add a eigenvectors plot + vector_r, = ax[1].plot([], [], '-k', label="Real") + vector_i, = ax[1].plot([], [], '-r', label="Imag") + ax[1].legend(loc='upper right') + ax[1].set_xlabel("X") + ax[1].set_ylabel("Amplitude") + ax[1].set_title("Eigenvector") + plt.subplots_adjust(hspace=0.5) def onclick(event): # Check if user clicked inside the plot if event.xdata is None: return - # Find closest data point, but stretch axes so + # Find closest eigenvectors point, but stretch axes so # real and imaginary components are weighted equally if(range_r == 0): dist = ((eigs_i - event.ydata)/range_i)**2 @@ -69,22 +84,22 @@ def onclick(event): print("Eigenvalue number: %d (%e,%e)" % (ind, eigs_r[ind], eigs_i[ind])) - if data is not None: + if eigenvectors is not None: # Update plots - nx = data.shape[1] - vector_r.set_data(arange(nx), data[2*ind, :]) - vector_i.set_data(arange(nx), data[2*ind+1, :]) - ax2.relim() - ax2.autoscale_view() + nx = eigenvectors.shape[1] + vector_r.set_data(arange(nx), eigenvectors[2*ind, :]) + vector_i.set_data(arange(nx), eigenvectors[2*ind+1, :]) + ax[1].relim() + ax[1].autoscale_view() fig.canvas.draw() - cid = fig.canvas.mpl_connect('button_press_event', onclick) + fig.canvas.mpl_connect('button_press_event', onclick) plt.show() if __name__ == "__main__": path = "data" - eigs = collect("t_array", path=path) - data = collect("f", path=path) - plot_eigenvals(eigs, data=data[:, 2:-2, 0, 0]) + eigenvalues = collect("t_array", path=path, info=False) + eigenvectors = collect("f", xguards=False, path=path, info=False) + plot_eigenvals(eigenvalues, eigenvectors[..., 0, 0]) From ee7e87a217fa0c2a747e6498a0fa8d57d36e6201 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 13 Jun 2019 16:28:03 +0100 Subject: [PATCH 1532/1783] Add readme to eigen-box example --- examples/eigen-box/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 examples/eigen-box/README.md diff --git a/examples/eigen-box/README.md b/examples/eigen-box/README.md new file mode 100644 index 0000000000..4615b03b68 --- /dev/null +++ b/examples/eigen-box/README.md @@ -0,0 +1,15 @@ +Eigen-box +========= + +Calculates the eigenvalues and eigenvectors of a simple wave in a 1D box. + +Build and run like: + + make && ./eigen-box + +and visualise the eigenvalues and eigenvectors with: + + ./eigenvals.py + +Click individual eigenvalues in the top plot to see the corresponding +eigenvector in the bottom plot. From e7867c30565bb091375b23a54559e2f10896d741 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 13 Jun 2019 16:52:13 +0100 Subject: [PATCH 1533/1783] Mark EigenBox methods as override, don't name unused argument --- examples/eigen-box/eigen-box.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/eigen-box/eigen-box.cxx b/examples/eigen-box/eigen-box.cxx index b739e19cc5..57c87f5667 100644 --- a/examples/eigen-box/eigen-box.cxx +++ b/examples/eigen-box/eigen-box.cxx @@ -10,12 +10,12 @@ class EigenBox : public PhysicsModel { protected: - int init(bool UNUSED(restarting)) { + int init(bool) override { solver->add(f, "f"); solver->add(g, "g"); return 0; } - int rhs(BoutReal UNUSED(t)) { + int rhs(BoutReal) override { mesh->communicate(f); ddt(g) = D2DX2(f); From 33b48ab96c703300ac4ea342e35b09eafd2c6f66 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 13 Jun 2019 16:52:51 +0100 Subject: [PATCH 1534/1783] Use MXG=1 in eigen box example, use it explicitly for nx and dx --- examples/eigen-box/data/BOUT.inp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/eigen-box/data/BOUT.inp b/examples/eigen-box/data/BOUT.inp index 2c58ccd58c..193cc59bc4 100644 --- a/examples/eigen-box/data/BOUT.inp +++ b/examples/eigen-box/data/BOUT.inp @@ -3,6 +3,7 @@ NOUT = 1 TIMESTEP = 0.2 +MXG = 1 MYG = 0 dump_on_restart = false @@ -10,11 +11,11 @@ dump_on_restart = false length = 1 # Length of the domain -nx = 36 +nx = 32 + 2*MXG ny = 1 nz = 1 -dx = length / (nx - 4) +dx = length / (nx - 2*MXG) dy = 1 [solver] From 46fa059b11fba015378765d02361a1446cdfda1f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 13 Jun 2019 17:37:02 +0100 Subject: [PATCH 1535/1783] Add a simple test case for SLEPc --- tests/integrated/test-slepc-solver/.gitignore | 1 + tests/integrated/test-slepc-solver/README.md | 12 ++++++++ .../test-slepc-solver/data/BOUT.inp | 18 ++++++++++++ tests/integrated/test-slepc-solver/makefile | 5 ++++ tests/integrated/test-slepc-solver/runtest | 28 +++++++++++++++++++ .../test-slepc-solver/test-slepc-solver.cxx | 20 +++++++++++++ 6 files changed, 84 insertions(+) create mode 100644 tests/integrated/test-slepc-solver/.gitignore create mode 100644 tests/integrated/test-slepc-solver/README.md create mode 100644 tests/integrated/test-slepc-solver/data/BOUT.inp create mode 100644 tests/integrated/test-slepc-solver/makefile create mode 100755 tests/integrated/test-slepc-solver/runtest create mode 100644 tests/integrated/test-slepc-solver/test-slepc-solver.cxx diff --git a/tests/integrated/test-slepc-solver/.gitignore b/tests/integrated/test-slepc-solver/.gitignore new file mode 100644 index 0000000000..a664a56dfa --- /dev/null +++ b/tests/integrated/test-slepc-solver/.gitignore @@ -0,0 +1 @@ +test-slepc-solver diff --git a/tests/integrated/test-slepc-solver/README.md b/tests/integrated/test-slepc-solver/README.md new file mode 100644 index 0000000000..2fef88c6d6 --- /dev/null +++ b/tests/integrated/test-slepc-solver/README.md @@ -0,0 +1,12 @@ +Test SLEPc Eigen Solver +======================= + +A simple test for the SLEPc eigen solver. Checks that it can get the +eigenvalue of + + ddt(f) = f * exp(t) + +which is `0.0 + 1.0i`. + +Note that this is just a sanity check and doesn't fully test the +solver. diff --git a/tests/integrated/test-slepc-solver/data/BOUT.inp b/tests/integrated/test-slepc-solver/data/BOUT.inp new file mode 100644 index 0000000000..08a94d56cd --- /dev/null +++ b/tests/integrated/test-slepc-solver/data/BOUT.inp @@ -0,0 +1,18 @@ +NOUT = 1 +TIMESTEP = 1 + +MXG = 1 +MYG = 0 +dump_on_restart = false + +[mesh] +nx = 3 +ny = 1 +nz = 1 + +dx = 1 +dy = 1 + +[solver] +type = "slepc" +neig = 1 diff --git a/tests/integrated/test-slepc-solver/makefile b/tests/integrated/test-slepc-solver/makefile new file mode 100644 index 0000000000..8fc1b74cf5 --- /dev/null +++ b/tests/integrated/test-slepc-solver/makefile @@ -0,0 +1,5 @@ +BOUT_TOP = ../../.. + +SOURCEC = test-slepc-solver.cxx + +include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-slepc-solver/runtest b/tests/integrated/test-slepc-solver/runtest new file mode 100755 index 0000000000..131849346b --- /dev/null +++ b/tests/integrated/test-slepc-solver/runtest @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 + +# requires: slepc + +from boutdata.collect import collect +from boututils.run_wrapper import shell_safe, launch_safe +from numpy import isclose + +print("Making SLEPc eigen solver test") +shell_safe("make > make.log") + +print("Running SLEPc eigen solver test") +status, out = launch_safe("./test-slepc-solver", nproc=1, pipe=True, verbose=True) + +with open("run.log", 'w') as f: + f.write(out) + +eigenvalues = collect("t_array", path="data", info=False) + +expected_eigenvalues = [0., 1.] + +if isclose(expected_eigenvalues, eigenvalues).all(): + print(" => SLEPc test passed") + exit(0) +else: + print(" => SLEPc test failed") + print(" Eigenvalues:", eigenvalues) + exit(1) diff --git a/tests/integrated/test-slepc-solver/test-slepc-solver.cxx b/tests/integrated/test-slepc-solver/test-slepc-solver.cxx new file mode 100644 index 0000000000..7f61b18ea4 --- /dev/null +++ b/tests/integrated/test-slepc-solver/test-slepc-solver.cxx @@ -0,0 +1,20 @@ +// A simple linear problem with one eigenvalue + +#include + +class TestEigenSolver : public PhysicsModel { +protected: + int init(bool UNUSED(restarting)) override { + solver->add(field, "f"); + return 0; + } + int rhs(BoutReal time) override { + mesh->communicate(field); + ddt(field) = field * exp(time); + return 0; + } +private: + Field3D field; +}; + +BOUTMAIN(TestEigenSolver); From 583f4ab449c5bafcc21755d84a8181d54189d8eb Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 13 Jun 2019 17:47:40 +0100 Subject: [PATCH 1536/1783] Use new options interface in slepc solver --- src/solver/impls/slepc/slepc.cxx | 47 +++++++++++++++++++------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index 42eb6ce02d..7f62526f5d 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -147,18 +147,28 @@ SlepcSolver::SlepcSolver(Options *options){ stIsShell=PETSC_FALSE; // Slepc settings in the Solver section + auto& options_ref = *options; - options->get("nEig",nEig,0);//0 means keep the current value, i.e. autoset + nEig = options_ref["nEig"] + .doc("Number of eigenvalues to compute. 0 means keep the current value, " + "i.e. autoset") + .withDefault(0); - options->get("tol",tol,1.0e-6);// Tolerance --> Note this is on SLEPc eig not BOUT - options->get("maxIt",maxIt,PETSC_DECIDE); + tol = options_ref["tol"].doc("SLEPc tolerance").withDefault(1.0e-6); + maxIt = options_ref["maxIt"].doc("Maximum iterations").withDefault(PETSC_DEFAULT); - options->get("mpd", mpd, PETSC_DECIDE); + mpd = options_ref["mpd"] + .doc("Maximum dimension allowed for the projected problem") + .withDefault(PETSC_DEFAULT); - options->get("ddtMode", ddtMode, true); + ddtMode = options_ref["ddtMode"].withDefault(true); - options->get("targRe",targRe,0.0); // Target frequency when using user eig comparison - options->get("targIm",targIm,0.0); // Target growth rate when using user eig comparison + targRe = options_ref["targRe"] + .doc("Target frequency when using user eig comparison") + .withDefault(0.0); + targIm = options_ref["targIm"] + .doc("Target growth rate when using user eig comparison") + .withDefault(0.0); //Convert bout targs to slepc bool userWhichDefault=false; @@ -181,21 +191,19 @@ SlepcSolver::SlepcSolver(Options *options){ //specify targRe/targIm *and* explicitly set userWhich=false userWhichDefault=true; } - options->get("target",target,target); //If 999 we don't set the target. This is SLEPc eig target - options->get("userWhich",userWhich,userWhichDefault); + target = options_ref["target"] + .doc("If 999 we don't set the target. This is SLEPc eig target") + .withDefault(target); + + userWhich = options_ref["userWhich"].withDefault(userWhichDefault); //Generic settings - bool useInitialDefault = true; - if(ddtMode){ - //If ddtMode then we probably don't want to useInitial - useInitialDefault = false; - }; - options->get("useInitial",useInitial,useInitialDefault); - options->get("debugMonitor",debugMonitor,false); + useInitial = options_ref["useInitial"].withDefault(!ddtMode); + debugMonitor = options_ref["debugMonitor"].withDefault(false); + + selfSolve = options_ref["selfSolve"].doc("Solver to advance the state of the system").withDefault(false); - // Solver to advance the state of the system - options->get("selfSolve", selfSolve, false); if(ddtMode && !selfSolve){ //We need to ensure this so that we don't try to use //advanceSolver elsewhere. The other option would be to @@ -204,7 +212,8 @@ SlepcSolver::SlepcSolver(Options *options){ output<<"Overridding selfSolve as ddtMode = true"<get("eigenValOnly", eigenValOnly, false); + eigenValOnly = options_ref["eigenValOnly"].withDefault(false); + if(!selfSolve && !ddtMode) { // Use a sub-section called "advance" advanceSolver=SolverFactory::getInstance()->createSolver(options->getSection("advance")); From c8ef564cca9bf63e1867d5c3ef4e08518086b10a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 13 Jun 2019 18:01:13 +0100 Subject: [PATCH 1537/1783] Make some variables const and reduce scope where possible in slepc --- src/solver/impls/slepc/slepc.cxx | 77 +++++++++++--------------------- 1 file changed, 27 insertions(+), 50 deletions(-) diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index 7f62526f5d..13cc3cd186 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -115,29 +115,19 @@ PetscErrorCode stBackTransformWrapper(ST st, PetscInt nEig, PetscScalar *eigr, PetscFunctionReturn(0); } +// Helper function +std::string formatEig(BoutReal reEig, BoutReal imEig) { -//Helper function -std::string formatEig(BoutReal reEig, BoutReal imEig){ - std::string rePad, imPad; - - if(reEig<0){ - rePad="-"; - }else{ - rePad=" "; - } - - if(imEig<0){ - imPad="-"; - }else{ - imPad="+"; - } + const std::string rePad = (reEig < 0) ? "-" : " "; + const std::string imPad = (imEig < 0) ? "-" : " "; std::stringstream tmp; - tmp.precision(5); tmp<0){ output<<"Found "< Date: Thu, 13 Jun 2019 18:02:48 +0100 Subject: [PATCH 1538/1783] Replace endl with \n in slepc --- src/solver/impls/slepc/slepc.cxx | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index 13cc3cd186..ef7f8109e7 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -199,7 +199,7 @@ SlepcSolver::SlepcSolver(Options *options){ //advanceSolver elsewhere. The other option would be to //create advanceSolver below in ddtMode but we just don't //use it. - output<<"Overridding selfSolve as ddtMode = true"<0){ - output<<"Found "< "; - output<0){ - output<<"Converged eigenvalues :"< Date: Thu, 13 Jun 2019 18:04:55 +0100 Subject: [PATCH 1539/1783] Invert conditional and exit early in slepc analyseresults --- src/solver/impls/slepc/slepc.cxx | 103 ++++++++++++++++--------------- 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index ef7f8109e7..1fa9ab2e45 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -677,75 +677,76 @@ void SlepcSolver::analyseResults(){ //Find how many eigenvalues have been found EPSGetConverged(eps,&nEigFound); + if (nEigFound < 1) { + output<<"Warning : No converged eigenvalues found!\n"; + return; + } + //Now loop over each converged eigenpair and output eigenvalue - if(nEigFound>0){ - output << "Converged eigenvalues :\n" - "\tIndex\tSlepc eig (mag.)\t\t\tBOUT eig (mag.)\n"; - iteration=0; + output << "Converged eigenvalues :\n" + "\tIndex\tSlepc eig (mag.)\t\t\tBOUT eig (mag.)\n"; + + iteration=0; - //Declare and create vectors to store eigenfunctions - Vec vecReal, vecImag; + //Declare and create vectors to store eigenfunctions + Vec vecReal, vecImag; #if PETSC_VERSION_LT(3, 6, 0) - MatGetVecs(shellMat,&vecReal,&vecImag); + MatGetVecs(shellMat,&vecReal,&vecImag); #else - MatCreateVecs(shellMat,&vecReal,&vecImag); + MatCreateVecs(shellMat,&vecReal,&vecImag); #endif - //This allows us to set the simtime in bout++.cxx directly - //rather than calling the monitors which are noisy |--> Not very nice way to do this - extern BoutReal simtime; - - for(PetscInt iEig=0; iEig Not very nice way to do this + extern BoutReal simtime; - //Report - output<<"\t"< Date: Thu, 13 Jun 2019 18:06:10 +0100 Subject: [PATCH 1540/1783] Clang-format slepc solver --- src/solver/impls/slepc/slepc.cxx | 771 ++++++++++++++++--------------- 1 file changed, 392 insertions(+), 379 deletions(-) diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index 1fa9ab2e45..eb97b0f15a 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -23,94 +23,93 @@ * **************************************************************************/ - #ifdef BOUT_HAS_SLEPC #include "slepc.hxx" - +#include #include - -#include - -#include // Cell interpolation +#include #include #include -#include + +#include std::string formatEig(BoutReal reEig, BoutReal imEig); -//The callback function for the shell matrix-multiply operation -//A simple wrapper around the SlepcSolver advanceStep routine -PetscErrorCode advanceStepWrapper(Mat matOperator, Vec inData, Vec outData){ +// The callback function for the shell matrix-multiply operation +// A simple wrapper around the SlepcSolver advanceStep routine +PetscErrorCode advanceStepWrapper(Mat matOperator, Vec inData, Vec outData) { PetscFunctionBegin; SlepcSolver* ctx; - MatShellGetContext(matOperator,(void**) &ctx); //Here we set the ctx pointer to the solver instance - PetscFunctionReturn(ctx->advanceStep(matOperator,inData,outData)); //Actually advance + // Here we set the ctx pointer to the solver instance + MatShellGetContext(matOperator, (void**)&ctx); + // Actually advance + PetscFunctionReturn(ctx->advanceStep(matOperator, inData, outData)); } -//The callback function for the eigenvalue comparison -//A simple wrapper around the SlepcSolver compareEigs routine -PetscErrorCode compareEigsWrapper(PetscScalar ar, PetscScalar ai, PetscScalar br, PetscScalar bi, - PetscInt *res, void *ctx){ +// The callback function for the eigenvalue comparison +// A simple wrapper around the SlepcSolver compareEigs routine +PetscErrorCode compareEigsWrapper(PetscScalar ar, PetscScalar ai, PetscScalar br, + PetscScalar bi, PetscInt* res, void* ctx) { PetscFunctionBegin; - //Cast context as SlepcSolver and call the actual compare routine + // Cast context as SlepcSolver and call the actual compare routine SlepcSolver* myCtx; - myCtx=(SlepcSolver*)ctx; - myCtx->compareState=myCtx->compareEigs(ar,ai,br,bi); + myCtx = (SlepcSolver*)ctx; + myCtx->compareState = myCtx->compareEigs(ar, ai, br, bi); *res = myCtx->compareState; PetscFunctionReturn(0); } - -//The callback function for the monitor -//A simple wrapper around the SlepcSolver compareEigs routine +// The callback function for the monitor +// A simple wrapper around the SlepcSolver compareEigs routine PetscErrorCode monitorWrapper(EPS UNUSED(eps), PetscInt its, PetscInt nconv, - PetscScalar *eigr, PetscScalar *eigi, PetscReal *errest, - PetscInt nest, void *mctx) { + PetscScalar* eigr, PetscScalar* eigi, PetscReal* errest, + PetscInt nest, void* mctx) { PetscFunctionBegin; - //Cast context as SlepcSolver and call the actual compare routine + // Cast context as SlepcSolver and call the actual compare routine SlepcSolver* myCtx; - myCtx=(SlepcSolver*)mctx; - myCtx->monitor(its,nconv,eigr,eigi,errest,nest); + myCtx = (SlepcSolver*)mctx; + myCtx->monitor(its, nconv, eigr, eigi, errest, nest); PetscFunctionReturn(0); } -//The callback function for applying the shell spectral transformation -PetscErrorCode stApplyWrapper(ST st, Vec vecIn, Vec vecOut){ +// The callback function for applying the shell spectral transformation +PetscErrorCode stApplyWrapper(ST st, Vec vecIn, Vec vecOut) { PetscFunctionBegin; - //First get the context of the st object, cast to correct type + // First get the context of the st object, cast to correct type SlepcSolver* myCtx; - STShellGetContext(st,(void**)&myCtx); + STShellGetContext(st, (void**)&myCtx); - //Do the matrix vector multiply -- same as STSHIFT with zero shift - //Use the advanceStepWrapper so any mods made in advanceStep are - //taken into account - advanceStepWrapper(myCtx->shellMat,vecIn,vecOut); + // Do the matrix vector multiply -- same as STSHIFT with zero shift + // Use the advanceStepWrapper so any mods made in advanceStep are + // taken into account + advanceStepWrapper(myCtx->shellMat, vecIn, vecOut); - //Note an alternative approach, which would allow shellMat to remain - //private, would be to extract the ST object during createEPS and set - //the operator their. We could then use STGetOperators to obtain a - //reference to the shell mat. + // Note an alternative approach, which would allow shellMat to remain + // private, would be to extract the ST object during createEPS and set + // the operator their. We could then use STGetOperators to obtain a + // reference to the shell mat. PetscFunctionReturn(0); } -//The callback function for transforming the eigenvalues in the -//custom shell spectral transformation -PetscErrorCode stBackTransformWrapper(ST st, PetscInt nEig, PetscScalar *eigr, - PetscScalar *eigi){ +// The callback function for transforming the eigenvalues in the +// custom shell spectral transformation +PetscErrorCode stBackTransformWrapper(ST st, PetscInt nEig, PetscScalar* eigr, + PetscScalar* eigi) { PetscFunctionBegin; - //First get the context of the st object and cast to correct type + // First get the context of the st object and cast to correct type SlepcSolver* myCtx; - STShellGetContext(st,(void **)&myCtx); + STShellGetContext(st, (void**)&myCtx); - //Convert to bout eigenvalue + // Convert to bout eigenvalue BoutReal tmpR, tmpI; - for(PetscInt iEig=0;iEigslepcToBout(eigr[iEig],eigi[iEig],tmpR,tmpI,true); - eigr[iEig]=tmpR; eigi[iEig]=tmpI; + for (PetscInt iEig = 0; iEig < nEig; iEig++) { + myCtx->slepcToBout(eigr[iEig], eigi[iEig], tmpR, tmpI, true); + eigr[iEig] = tmpR; + eigi[iEig] = tmpI; }; PetscFunctionReturn(0); } @@ -131,10 +130,10 @@ std::string formatEig(BoutReal reEig, BoutReal imEig) { return tmp.str(); } -SlepcSolver::SlepcSolver(Options *options){ +SlepcSolver::SlepcSolver(Options* options) { has_constraints = false; initialised = false; - stIsShell=PETSC_FALSE; + stIsShell = PETSC_FALSE; // Slepc settings in the Solver section auto& options_ref = *options; @@ -160,26 +159,26 @@ SlepcSolver::SlepcSolver(Options *options){ .doc("Target growth rate when using user eig comparison") .withDefault(0.0); - //Convert bout targs to slepc - bool userWhichDefault=false; - if(targRe==0.0 && targIm==0.0){ + // Convert bout targs to slepc + bool userWhichDefault = false; + if (targRe == 0.0 && targIm == 0.0) { target = 999.0; - }else{ - //Ideally we'd set the target here from - //targRe and targIm (using boutToSlepc) to - //convert to slepc target. Unfortunately - //when not in ddtMode the boutToSlepc routine - //requires tstep and nout to be set but these - //aren't available until ::init so for now just - //set target to -1 to signal we need to set it - //later. + } else { + // Ideally we'd set the target here from + // targRe and targIm (using boutToSlepc) to + // convert to slepc target. Unfortunately + // when not in ddtMode the boutToSlepc routine + // requires tstep and nout to be set but these + // aren't available until ::init so for now just + // set target to -1 to signal we need to set it + // later. target = -1.0; - //If we've set a target then we change the default - //for the userWhich variable as targets work best with this - //Note this means we only use target in the case where we - //specify targRe/targIm *and* explicitly set userWhich=false - userWhichDefault=true; + // If we've set a target then we change the default + // for the userWhich variable as targets work best with this + // Note this means we only use target in the case where we + // specify targRe/targIm *and* explicitly set userWhich=false + userWhichDefault = true; } target = options_ref["target"] @@ -188,36 +187,45 @@ SlepcSolver::SlepcSolver(Options *options){ userWhich = options_ref["userWhich"].withDefault(userWhichDefault); - //Generic settings + // Generic settings useInitial = options_ref["useInitial"].withDefault(!ddtMode); debugMonitor = options_ref["debugMonitor"].withDefault(false); - selfSolve = options_ref["selfSolve"].doc("Solver to advance the state of the system").withDefault(false); + selfSolve = options_ref["selfSolve"] + .doc("Solver to advance the state of the system") + .withDefault(false); - if(ddtMode && !selfSolve){ - //We need to ensure this so that we don't try to use - //advanceSolver elsewhere. The other option would be to - //create advanceSolver below in ddtMode but we just don't - //use it. - output<<"Overridding selfSolve as ddtMode = true\n"; + if (ddtMode && !selfSolve) { + // We need to ensure this so that we don't try to use + // advanceSolver elsewhere. The other option would be to + // create advanceSolver below in ddtMode but we just don't + // use it. + output << "Overridding selfSolve as ddtMode = true\n"; selfSolve = true; } eigenValOnly = options_ref["eigenValOnly"].withDefault(false); - if(!selfSolve && !ddtMode) { + if (!selfSolve && !ddtMode) { // Use a sub-section called "advance" - advanceSolver=SolverFactory::getInstance()->createSolver(options->getSection("advance")); - }else{ + advanceSolver = + SolverFactory::getInstance()->createSolver(options->getSection("advance")); + } else { advanceSolver = nullptr; } } -SlepcSolver::~SlepcSolver(){ - if(initialised){ - //Free memory - if(eps){EPSDestroy(&eps);}; - if(shellMat){MatDestroy(&shellMat);}; - if(advanceSolver){delete advanceSolver;}; +SlepcSolver::~SlepcSolver() { + if (initialised) { + // Free memory + if (eps) { + EPSDestroy(&eps); + }; + if (shellMat) { + MatDestroy(&shellMat); + }; + if (advanceSolver) { + delete advanceSolver; + }; initialised = false; } } @@ -226,40 +234,40 @@ int SlepcSolver::init(int NOUT, BoutReal TIMESTEP) { TRACE("Initialising SLEPc solver"); - //Report initialisation + // Report initialisation output.write("Initialising SLEPc solver\n"); if (selfSolve) { - Solver::init(NOUT,TIMESTEP); + Solver::init(NOUT, TIMESTEP); - //If no advanceSolver then can only advance one step at a time - NOUT=1; + // If no advanceSolver then can only advance one step at a time + NOUT = 1; } - //Save for use later + // Save for use later nout = NOUT; tstep = TIMESTEP; - //Now we can calculate the slepc target (see ::SlepcSolver for details) - if(target == -1.0){ - PetscScalar slepcRe,slepcIm; - boutToSlepc(targRe,targIm,slepcRe,slepcIm); - dcomplex tmp(slepcRe,slepcIm); - target=std::abs(tmp); + // Now we can calculate the slepc target (see ::SlepcSolver for details) + if (target == -1.0) { + PetscScalar slepcRe, slepcIm; + boutToSlepc(targRe, targIm, slepcRe, slepcIm); + dcomplex tmp(slepcRe, slepcIm); + target = std::abs(tmp); } - //Read options - comm=PETSC_COMM_WORLD; + // Read options + comm = PETSC_COMM_WORLD; - //Initialise advanceSolver if not self + // Initialise advanceSolver if not self if (!selfSolve && !ddtMode) { advanceSolver->init(NOUT, TIMESTEP); } - //Calculate grid sizes - localSize=getLocalN(); + // Calculate grid sizes + localSize = getLocalN(); - //Also create vector for derivs etc. if SLEPc in charge of solving - if(selfSolve && !ddtMode){ + // Also create vector for derivs etc. if SLEPc in charge of solving + if (selfSolve && !ddtMode) { // Allocate memory f0.reallocate(localSize); f1.reallocate(localSize); @@ -267,46 +275,46 @@ int SlepcSolver::init(int NOUT, BoutReal TIMESTEP) { // Get total problem size int neq; - if(MPI_Allreduce(&localSize, &neq, 1, MPI_INT, MPI_SUM, BoutComm::get())) { + if (MPI_Allreduce(&localSize, &neq, 1, MPI_INT, MPI_SUM, BoutComm::get())) { throw BoutException("MPI_Allreduce failed in SlepcSolver::init"); } - output.write("\t3d fields = %d, 2d fields = %d neq=%d, local_N=%d\n", - n3Dvars(), n2Dvars(), neq, localSize); + output.write("\t3d fields = %d, 2d fields = %d neq=%d, local_N=%d\n", n3Dvars(), + n2Dvars(), neq, localSize); - //Create EPS solver + // Create EPS solver createEPS(); - //Return ok + // Return ok return 0; } int SlepcSolver::run() { - //Now the basic idea with slepc is that: - //Whilst n_eig_converged The first section is handled by calling EPSSolve(eps) with appropriate shellMat //--> The second section has to be handled by this solver - //Find the eigenvalues + // Find the eigenvalues EPSSolve(eps); - //Analyse and dump to file - if(!eigenValOnly) { + // Analyse and dump to file + if (!eigenValOnly) { analyseResults(); } return 0; } -//This routine takes a Vec type object of length localSize and -//unpacks it into the local fields -void SlepcSolver::vecToFields(Vec &inVec){ +// This routine takes a Vec type object of length localSize and +// unpacks it into the local fields +void SlepcSolver::vecToFields(Vec& inVec) { /* Whilst this routine does indeed populate the field variables most (/all?) solvers overwrite this data on call to run() as @@ -328,310 +336,314 @@ void SlepcSolver::vecToFields(Vec &inVec){ 2. ? */ - //Get pointer to data - const BoutReal *point; + // Get pointer to data + const BoutReal* point; VecGetArrayRead(inVec, &point); - //Copy data from point into fields + // Copy data from point into fields load_vars(const_cast(point)); - //Note as the solver instances only have pointers to the - //fields we can use the SlepcSolver load_vars even if we're - //not using selfSolve=True + // Note as the solver instances only have pointers to the + // fields we can use the SlepcSolver load_vars even if we're + // not using selfSolve=True - if(!selfSolve && !ddtMode){ - //Solver class used must support this procedure which resets any internal state - //data such that it now holds the same data as the fields + if (!selfSolve && !ddtMode) { + // Solver class used must support this procedure which resets any internal state + // data such that it now holds the same data as the fields advanceSolver->resetInternalFields(); } - //Restore array + // Restore array VecRestoreArrayRead(inVec, &point); } -//This routine packs the local fields into a vector -void SlepcSolver::fieldsToVec(Vec &outVec){ - //Get pointer to data - PetscScalar *point; - VecGetArray(outVec,&point); +// This routine packs the local fields into a vector +void SlepcSolver::fieldsToVec(Vec& outVec) { + // Get pointer to data + PetscScalar* point; + VecGetArray(outVec, &point); - //Copy fields into point - if(!ddtMode){ + // Copy fields into point + if (!ddtMode) { save_vars(point); - }else{ + } else { save_derivs(point); }; - //Note as the solver instances only have pointers to the - //fields we can use the SlepcSolver save_vars even if we're - //not using selfSolve=True + // Note as the solver instances only have pointers to the + // fields we can use the SlepcSolver save_vars even if we're + // not using selfSolve=True - //Restore array - VecRestoreArray(outVec,&point); + // Restore array + VecRestoreArray(outVec, &point); } -//Create a shell matrix operator -void SlepcSolver::createShellMat(){ - output<<"Creating shellMat with local size : "< Define what routine returns M.x, where M - //is the time advance operator and x are the initial field conditions - MatShellSetOperation(shellMat,MATOP_MULT,(void(*)())&advanceStepWrapper); - - //The above function callback can cause issues as member functions have a hidden "this" - //argument which means if Slepc calls this->advanceStep(Mat,Vec,Vec) this is actually - //this->advanceStep(this,Mat,Vec,Vec) meaing "this" gets redefined to Mat, - //and the two Vecs are mangled, this messes up memory and the code crashes. - //Alternatives include: +// Create a shell matrix operator +void SlepcSolver::createShellMat() { + output << "Creating shellMat with local size : " << localSize << "\n"; + + // Create the shell matrix + // Note we pass the this reference as the matrix context. + // This allows us to access the SlepcSolver internals from within + // routines called directly by Petsc/Slepc (i.e. our wrapper functions) + MatCreateShell(comm, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE, this, + &shellMat); + // Define the mat_mult operation --> Define what routine returns M.x, where M + // is the time advance operator and x are the initial field conditions + MatShellSetOperation(shellMat, MATOP_MULT, (void (*)()) & advanceStepWrapper); + + // The above function callback can cause issues as member functions have a hidden "this" + // argument which means if Slepc calls this->advanceStep(Mat,Vec,Vec) this is actually + // this->advanceStep(this,Mat,Vec,Vec) meaing "this" gets redefined to Mat, + // and the two Vecs are mangled, this messes up memory and the code crashes. + // Alternatives include: // 1. Making advanceStep a static function // 2. Making advanceStep a non-member function - //These alternatives generally divorce the advanceStep from the SlepcSolver class - //which might make it difficult to access required data. - //We've therefore gone with a third option where we define the callback to be a - //non-member function which then gets the context pointer attached to shellMat - //which points to the SlepcSolver instance. This can then be used to call the - //advanceStep member function as if it were called within "this". + // These alternatives generally divorce the advanceStep from the SlepcSolver class + // which might make it difficult to access required data. + // We've therefore gone with a third option where we define the callback to be a + // non-member function which then gets the context pointer attached to shellMat + // which points to the SlepcSolver instance. This can then be used to call the + // advanceStep member function as if it were called within "this". } -//Create an EPS Solver -void SlepcSolver::createEPS(){ - //First need to create shell matrix +// Create an EPS Solver +void SlepcSolver::createEPS() { + // First need to create shell matrix createShellMat(); - //Now construct EPS - EPSCreate(comm,&eps); + // Now construct EPS + EPSCreate(comm, &eps); EPSSetOperators(eps, shellMat, nullptr); - EPSSetProblemType(eps,EPS_NHEP);//Non-hermitian - - //Probably want to read options and set EPS properties - //at this point. - EPSSetDimensions(eps,nEig,PETSC_DECIDE,mpd); - EPSSetTolerances(eps,tol,maxIt); - if(! (target==999)){ - EPSSetTarget(eps,target); + EPSSetProblemType(eps, EPS_NHEP); // Non-hermitian + + // Probably want to read options and set EPS properties + // at this point. + EPSSetDimensions(eps, nEig, PETSC_DECIDE, mpd); + EPSSetTolerances(eps, tol, maxIt); + if (!(target == 999)) { + EPSSetTarget(eps, target); } - //Set the user comparison function - if(userWhich){ - EPSSetEigenvalueComparison(eps,compareEigsWrapper,this); - EPSSetWhichEigenpairs(eps,EPS_WHICH_USER); + // Set the user comparison function + if (userWhich) { + EPSSetEigenvalueComparison(eps, compareEigsWrapper, this); + EPSSetWhichEigenpairs(eps, EPS_WHICH_USER); } - //Update options from command line + // Update options from command line EPSSetFromOptions(eps); - //Register a monitor + // Register a monitor EPSMonitorSet(eps, &monitorWrapper, this, nullptr); - //Initialize shell spectral transformation if selected by user - //Note currently the only way to select this is with the + // Initialize shell spectral transformation if selected by user + // Note currently the only way to select this is with the //"-st_type shell" command line option, should really add a - //BOUT input flag to force it - EPSGetST(eps,&st); - PetscObjectTypeCompare((PetscObject)st,STSHELL,&stIsShell); - if(stIsShell){ - //Set the user-defined routine for applying the operator - STShellSetApply(st,&stApplyWrapper); - - //Set the STShell context to be the slepcSolver so we can access - //the solver internals from within the spectral transform routines - STShellSetContext(st,this); - - //Set the routine to transform the eigenvalues back - STShellSetBackTransform(st,stBackTransformWrapper); - - //Define the transformations name (optional) - PetscObjectSetName((PetscObject)st,"Exponential Linear ST"); + // BOUT input flag to force it + EPSGetST(eps, &st); + PetscObjectTypeCompare((PetscObject)st, STSHELL, &stIsShell); + if (stIsShell) { + // Set the user-defined routine for applying the operator + STShellSetApply(st, &stApplyWrapper); + + // Set the STShell context to be the slepcSolver so we can access + // the solver internals from within the spectral transform routines + STShellSetContext(st, this); + + // Set the routine to transform the eigenvalues back + STShellSetBackTransform(st, stBackTransformWrapper); + + // Define the transformations name (optional) + PetscObjectSetName((PetscObject)st, "Exponential Linear ST"); }; - //Should probably call a routine here which interrogates eps - //to determine the important settings that have been used and dump - //the settings to screen/file/dmp? - //I think there may be a Slepc flag which will do this (to screen) - //but not sure if we can force this is the code (without messing with argv). + // Should probably call a routine here which interrogates eps + // to determine the important settings that have been used and dump + // the settings to screen/file/dmp? + // I think there may be a Slepc flag which will do this (to screen) + // but not sure if we can force this is the code (without messing with argv). - //Set initial space i.e. first guess - if(useInitial){ //Doesn't seem to help the ddtMode very much so recommend off + // Set initial space i.e. first guess + if (useInitial) { // Doesn't seem to help the ddtMode very much so recommend off Vec initVec, rightVec; - bool ddtModeBackup=ddtMode; + bool ddtModeBackup = ddtMode; -#if PETSC_VERSION_LT(3, 6, 0) - MatGetVecs(shellMat,&rightVec,&initVec); +#if PETSC_VERSION_LT(3, 6, 0) + MatGetVecs(shellMat, &rightVec, &initVec); #else - MatCreateVecs(shellMat,&rightVec,&initVec); -#endif - ddtMode=false; //Temporarily disable as initial ddt values not set + MatCreateVecs(shellMat, &rightVec, &initVec); +#endif + ddtMode = false; // Temporarily disable as initial ddt values not set fieldsToVec(initVec); - ddtMode=ddtModeBackup; //Restore state - EPSSetInitialSpace(eps,1,&initVec); + ddtMode = ddtModeBackup; // Restore state + EPSSetInitialSpace(eps, 1, &initVec); VecDestroy(&initVec); VecDestroy(&rightVec); }; } -//This routine takes initial conditions provided by SLEPc, uses this to set the fields, -//advances them with the attached solver and then returns the evolved fields in a slepc -//structure. -//Note: Hidden "this" argument prevents Slepc calling this routine directly -int SlepcSolver::advanceStep(Mat &UNUSED(matOperator), Vec &inData, Vec &outData){ +// This routine takes initial conditions provided by SLEPc, uses this to set the fields, +// advances them with the attached solver and then returns the evolved fields in a slepc +// structure. +// Note: Hidden "this" argument prevents Slepc calling this routine directly +int SlepcSolver::advanceStep(Mat& UNUSED(matOperator), Vec& inData, Vec& outData) { - //First unpack input into fields + // First unpack input into fields vecToFields(inData); - //Now advance + // Now advance int retVal; - if(ddtMode){ - //In ddtMode we just want the time derivative of the fields + if (ddtMode) { + // In ddtMode we just want the time derivative of the fields retVal = run_rhs(0.0); - }else{ - //Here we actually advance one (big) step - if(selfSolve){ - //If we don't have an external solver then we have to advance the solution - //ourself. This is currently done using Euler and only advances by a small step - //Not recommended! - retVal=run_rhs(0.0); - //Here we add dt*ddt(Fields) to fields to advance solution (cf. Euler) + } else { + // Here we actually advance one (big) step + if (selfSolve) { + // If we don't have an external solver then we have to advance the solution + // ourself. This is currently done using Euler and only advances by a small step + // Not recommended! + retVal = run_rhs(0.0); + // Here we add dt*ddt(Fields) to fields to advance solution (cf. Euler) save_vars(std::begin(f0)); save_derivs(std::begin(f1)); - for(int iVec=0;iVecrun(); + } else { + // Here we exploit one of the built in solver implementations to advance the + // prescribed fields by a big (tstep*nstep) step. + retVal = advanceSolver->run(); } } - //Now pack evolved fields into output + // Now pack evolved fields into output fieldsToVec(outData); - //Return + // Return return retVal; } -//This routine can be used by Slepc to decide which of two eigenvalues is "preferred" -//Allows us to look at real and imaginary components seperately which is not possible -//with Slepc built in comparisons when Slepc is compiled without native complex support (required) -//Note must be wrapped by non-member function to be called by Slepc -int SlepcSolver::compareEigs(PetscScalar ar, PetscScalar ai, PetscScalar br, PetscScalar bi){ +// This routine can be used by Slepc to decide which of two eigenvalues is "preferred" +// Allows us to look at real and imaginary components seperately which is not possible +// with Slepc built in comparisons when Slepc is compiled without native complex support +// (required) Note must be wrapped by non-member function to be called by Slepc +int SlepcSolver::compareEigs(PetscScalar ar, PetscScalar ai, PetscScalar br, + PetscScalar bi) { BoutReal arBout, aiBout, brBout, biBout; - //First convert to BOUT values - slepcToBout(ar,ai,arBout,aiBout); - slepcToBout(br,bi,brBout,biBout); + // First convert to BOUT values + slepcToBout(ar, ai, arBout, aiBout); + slepcToBout(br, bi, brBout, biBout); - //Now we calculate the distance between eigenvalues and target. + // Now we calculate the distance between eigenvalues and target. const auto da = sqrt(pow(arBout - targRe, 2) + pow(aiBout - targIm, 2)); const auto db = sqrt(pow(brBout - targRe, 2) + pow(biBout - targIm, 2)); - //Now we decide which eigenvalue is preferred. + // Now we decide which eigenvalue is preferred. int retVal; - //Smallest distance from complex target - //If prefer B we return +ve - if(da>db){ - retVal=1; - //If prefer A we return -ve - }else if(db>da){ - retVal=-1; - //If we don't prefer either we return 0 - }else{ - retVal=0; + // Smallest distance from complex target + // If prefer B we return +ve + if (da > db) { + retVal = 1; + // If prefer A we return -ve + } else if (db > da) { + retVal = -1; + // If we don't prefer either we return 0 + } else { + retVal = 0; }; return retVal; } -//This is an example of a custom monitor which Slepc can call (not directly) to report the current -//status of the run. -//Note we could see how many new eigenpairs have been found since last called and then write their -//data to file so that we get progressive output rather than waiting until the end to write everything. -//Unfortunately it seems that currently SLEPc does not support using EPSGetEigenvector or -//EPSGetEigenpair before EPSSolve has finished. As such it's not possible to write out the eigenvectors -//from this monitor routine. It should still be possible to write the eigenvalues here, but to then -//get the eigenvectors at the correct time indices later would require resetting the time index. I'm -//not sure if the Datafile object supports this. -//Note must be wrapped by non-member function to be called by Slepc +// This is an example of a custom monitor which Slepc can call (not directly) to report +// the current status of the run. Note we could see how many new eigenpairs have been +// found since last called and then write their data to file so that we get progressive +// output rather than waiting until the end to write everything. Unfortunately it seems +// that currently SLEPc does not support using EPSGetEigenvector or EPSGetEigenpair before +// EPSSolve has finished. As such it's not possible to write out the eigenvectors from +// this monitor routine. It should still be possible to write the eigenvalues here, but to +// then get the eigenvectors at the correct time indices later would require resetting the +// time index. I'm not sure if the Datafile object supports this. Note must be wrapped by +// non-member function to be called by Slepc void SlepcSolver::monitor(PetscInt its, PetscInt nconv, PetscScalar eigr[], PetscScalar eigi[], PetscReal errest[], PetscInt UNUSED(nest)) { - static int nConvPrev=0; + static int nConvPrev = 0; - //No output until after first iteration - if(its<1){return;} + // No output until after first iteration + if (its < 1) { + return; + } extern BoutReal simtime; - static bool first=true; - if(eigenValOnly && first){ - first=false; - iteration=0; + static bool first = true; + if (eigenValOnly && first) { + first = false; + iteration = 0; } BoutReal reEigBout, imEigBout; - slepcToBout(eigr[nconv],eigi[nconv],reEigBout,imEigBout); + slepcToBout(eigr[nconv], eigi[nconv], reEigBout, imEigBout); const std::string joinNum = (imEigBout < 0) ? "" : "+"; - //This line more or less replicates the normal slepc output (when using -eps_monitor) - //but reports Bout eigenvalues rather than the Slepc values. Note we haven't changed error estimate. + // This line more or less replicates the normal slepc output (when using -eps_monitor) + // but reports Bout eigenvalues rather than the Slepc values. Note we haven't changed + // error estimate. output << " " << its << " nconv=" << nconv << "\t first unconverged value (error) " << formatEig(reEigBout, imEigBout) << "\t (" << errest[nconv] << ")\n"; - //The following can be quite noisy so may want to add a flag to disable/enable. + // The following can be quite noisy so may want to add a flag to disable/enable. const int newConv = nconv - nConvPrev; - if(newConv>0){ - output<<"Found "< "; - output< 0) { + output << "Found " << newConv << " new converged eigenvalues:\n"; + for (PetscInt i = nConvPrev; i < nconv; i++) { + slepcToBout(eigr[i], eigi[i], reEigBout, imEigBout); + output << "\t" << i << "\t: " << formatEig(eigr[i], eigi[i]) << " --> "; + output << formatEig(reEigBout, imEigBout) << "\n"; + if (eigenValOnly) { + simtime = reEigBout; bout::globals::dump.write(); iteration++; - simtime=imEigBout; + simtime = imEigBout; bout::globals::dump.write(); iteration++; } } } - //Update the number of converged modes already investigated. - nConvPrev=nconv; + // Update the number of converged modes already investigated. + nConvPrev = nconv; }; -//Convert a slepc eigenvalue to a BOUT one -void SlepcSolver::slepcToBout(PetscScalar &reEigIn, PetscScalar &imEigIn, - BoutReal &reEigOut, BoutReal &imEigOut, bool force){ +// Convert a slepc eigenvalue to a BOUT one +void SlepcSolver::slepcToBout(PetscScalar& reEigIn, PetscScalar& imEigIn, + BoutReal& reEigOut, BoutReal& imEigOut, bool force) { - //If not stIsShell then the slepc eigenvalue is actually - //Exp(-i*Eig_Bout*tstep) for ddtMode = false + // If not stIsShell then the slepc eigenvalue is actually + // Exp(-i*Eig_Bout*tstep) for ddtMode = false //-i*Eig_Bout for ddtMode = true - //where Eig_Bout is the actual eigenvalue and tstep is the time step - //the solution is evolved over. - //This routine returns Eig_Bout - - //The optional input force is used by the shell spectral transform - //in the back transform to force a conversion, which allows us to - //otherwise skip any transformation when in shell mode (i.e. the back - //transform routine is the only place we deal with the raw slepc eigenvalue - //in shell ST mode). - - //If shellST and not forcing we just set the input and output eigenvalues - //equal and return. - if(stIsShell && !force){ - reEigOut=reEigIn; - imEigOut=imEigIn; + // where Eig_Bout is the actual eigenvalue and tstep is the time step + // the solution is evolved over. + // This routine returns Eig_Bout + + // The optional input force is used by the shell spectral transform + // in the back transform to force a conversion, which allows us to + // otherwise skip any transformation when in shell mode (i.e. the back + // transform routine is the only place we deal with the raw slepc eigenvalue + // in shell ST mode). + + // If shellST and not forcing we just set the input and output eigenvalues + // equal and return. + if (stIsShell && !force) { + reEigOut = reEigIn; + imEigOut = imEigIn; return; } - const dcomplex slepcEig(reEigIn,imEigIn); - const dcomplex ci(0.0,1.0); + const dcomplex slepcEig(reEigIn, imEigIn); + const dcomplex ci(0.0, 1.0); // Protect against the 0,0 trivial eigenvalue if (ddtMode and std::abs(slepcEig) < 1.0e-10) { @@ -642,21 +654,20 @@ void SlepcSolver::slepcToBout(PetscScalar &reEigIn, PetscScalar &imEigIn, const dcomplex boutEig = ddtMode ? slepcEig * ci : ci * log(slepcEig) / (tstep * nout); - //Set return values - reEigOut=boutEig.real(); - imEigOut=boutEig.imag(); + // Set return values + reEigOut = boutEig.real(); + imEigOut = boutEig.imag(); } -//Convert a BOUT++ eigenvalue to a Slepc one -void SlepcSolver::boutToSlepc(BoutReal &reEigIn, BoutReal &imEigIn, - PetscScalar &reEigOut, PetscScalar &imEigOut, - bool force){ +// Convert a BOUT++ eigenvalue to a Slepc one +void SlepcSolver::boutToSlepc(BoutReal& reEigIn, BoutReal& imEigIn, PetscScalar& reEigOut, + PetscScalar& imEigOut, bool force) { - //If shellST and not forcing we just set the input and output eigenvalues - //equal and return. - if(stIsShell && !force){ - reEigOut=reEigIn; - imEigOut=imEigIn; + // If shellST and not forcing we just set the input and output eigenvalues + // equal and return. + if (stIsShell && !force) { + reEigOut = reEigIn; + imEigOut = imEigIn; return; } @@ -664,89 +675,91 @@ void SlepcSolver::boutToSlepc(BoutReal &reEigIn, BoutReal &imEigIn, const dcomplex ci(0.0, 1.0); const dcomplex slepcEig = ddtMode ? -ci * boutEig : exp(-ci * boutEig * (tstep * nout)); - //Set return values - reEigOut=slepcEig.real(); - imEigOut=slepcEig.imag(); + // Set return values + reEigOut = slepcEig.real(); + imEigOut = slepcEig.imag(); } - -//Interrogate eps to find out how many eigenvalues we've found etc. -void SlepcSolver::analyseResults(){ +// Interrogate eps to find out how many eigenvalues we've found etc. +void SlepcSolver::analyseResults() { PetscInt nEigFound; - //Find how many eigenvalues have been found - EPSGetConverged(eps,&nEigFound); + // Find how many eigenvalues have been found + EPSGetConverged(eps, &nEigFound); if (nEigFound < 1) { - output<<"Warning : No converged eigenvalues found!\n"; + output << "Warning : No converged eigenvalues found!\n"; return; } - //Now loop over each converged eigenpair and output eigenvalue + // Now loop over each converged eigenpair and output eigenvalue output << "Converged eigenvalues :\n" - "\tIndex\tSlepc eig (mag.)\t\t\tBOUT eig (mag.)\n"; + "\tIndex\tSlepc eig (mag.)\t\t\tBOUT eig (mag.)\n"; - iteration=0; + iteration = 0; - //Declare and create vectors to store eigenfunctions + // Declare and create vectors to store eigenfunctions Vec vecReal, vecImag; -#if PETSC_VERSION_LT(3, 6, 0) - MatGetVecs(shellMat,&vecReal,&vecImag); +#if PETSC_VERSION_LT(3, 6, 0) + MatGetVecs(shellMat, &vecReal, &vecImag); #else - MatCreateVecs(shellMat,&vecReal,&vecImag); -#endif + MatCreateVecs(shellMat, &vecReal, &vecImag); +#endif - //This allows us to set the simtime in bout++.cxx directly - //rather than calling the monitors which are noisy |--> Not very nice way to do this + // This allows us to set the simtime in bout++.cxx directly + // rather than calling the monitors which are noisy |--> Not very nice way to do this extern BoutReal simtime; - for(PetscInt iEig=0; iEig Date: Fri, 14 Jun 2019 09:52:41 +0100 Subject: [PATCH 1541/1783] Removed unused variable from slepc solver --- src/solver/impls/slepc/slepc.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index eb97b0f15a..3246701de7 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -586,8 +586,6 @@ void SlepcSolver::monitor(PetscInt its, PetscInt nconv, PetscScalar eigr[], BoutReal reEigBout, imEigBout; slepcToBout(eigr[nconv], eigi[nconv], reEigBout, imEigBout); - const std::string joinNum = (imEigBout < 0) ? "" : "+"; - // This line more or less replicates the normal slepc output (when using -eps_monitor) // but reports Bout eigenvalues rather than the Slepc values. Note we haven't changed // error estimate. From 7bee46f28c14af8d16c521d3f10bd05262f34607 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Jun 2019 09:52:55 +0100 Subject: [PATCH 1542/1783] Fix clobbered sign in front of imaginary component in slepc format --- src/solver/impls/slepc/slepc.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index 3246701de7..2d3ddca3c2 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -118,7 +118,7 @@ PetscErrorCode stBackTransformWrapper(ST st, PetscInt nEig, PetscScalar* eigr, std::string formatEig(BoutReal reEig, BoutReal imEig) { const std::string rePad = (reEig < 0) ? "-" : " "; - const std::string imPad = (imEig < 0) ? "-" : " "; + const std::string imPad = (imEig < 0) ? "-" : "+"; std::stringstream tmp; tmp.precision(5); From 8123a6ea1ab396afbd70962c720a64160ef8a905 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 13 Jun 2019 15:08:57 +0100 Subject: [PATCH 1543/1783] CMake: Add option for ScoreP --- CMakeLists.txt | 32 ++++++++++++++++++++++++++++++++ cmake/FindScoreP.cmake | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 cmake/FindScoreP.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index e44e25dd30..c64d755d66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -445,6 +445,37 @@ if (GETTEXT_FOUND) endif() set(BOUT_HAS_GETTEXT ${GETTEXT_FOUND}) +option(USE_SCOREP "Enable support for Score-P based instrumentation" OFF) +if (USE_SCOREP) + find_package(ScoreP REQUIRED) + if (ScoreP_FOUND) + target_link_libraries(bout++ + PUBLIC ScoreP::ScoreP) + target_compile_definitions(bout++ + PUBLIC "BOUT_HAS_SCOREP") + + if (NOT DEFINED CMAKE_CXX_COMPILER_LAUNCHER) + set_target_properties(bout++ PROPERTIES + CXX_COMPILER_LAUNCHER "${ScoreP_COMPILER_LAUNCHER}") + else() + if (NOT "${CMAKE_CXX_COMPILER_LAUNCHER}" STREQUAL "${ScoreP_COMPILER_LAUNCHER}") + message(FATAL_ERROR "Score-P conflicts with an existing compiler wrapper: ${CMAKE_CXX_COMPILER_LAUNCHER}") + endif() + endif() + endif() +endif() +set(BOUT_HAS_SCOREP ${USE_SCOREP}) + +include(CheckCXXSourceCompiles) +check_cxx_source_compiles("int main() { const char* name = __PRETTY_FUNCTION__; }" + HAS_PRETTY_FUNCTION) +set(BOUT_HAS_PRETTY_FUNCTION ${HAS_PRETTY_FUNCTION}) +if (HAS_PRETTY_FUNCTION) + target_compile_definitions(bout++ + PUBLIC "HAS_PRETTY_FUNCTION" + PUBLIC "BOUT_HAS_PRETTY_FUNCTION") +endif() + # Copy FILENAME from source directory to build directory # and add dependency on TARGET macro(bout_test_copy_file TARGET FILENAME) @@ -569,6 +600,7 @@ message(" LAPACK support : ${BOUT_HAS_LAPACK} OpenMP support : ${BOUT_USE_OPENMP} Natural language support : ${BOUT_HAS_GETTEXT} + ScoreP support : ${BOUT_HAS_SCOREP} === Python === diff --git a/cmake/FindScoreP.cmake b/cmake/FindScoreP.cmake new file mode 100644 index 0000000000..f0345366d5 --- /dev/null +++ b/cmake/FindScoreP.cmake @@ -0,0 +1,33 @@ +find_program(SCOREP_EXECUTABLE scorep) +mark_as_advanced(SCOREP_EXECUTABLE) + +if (NOT SCOREP_EXECUTABLE) + message(FATAL_ERROR "Score-P requested but not executable not found. +Please supply the path using -DCMAKE_PROGRAM_PATH=/path/to/scorep/bin/directory") +endif() + +get_filename_component(SCOREP_TMP "${SCOREP_EXECUTABLE}" DIRECTORY) +get_filename_component(SCOREP_EXEC_LOCATION "${SCOREP_TMP}" DIRECTORY) + +find_path(ScoreP_INCLUDE_DIR + NAMES scorep/SCOREP_User.h + DOC "Score-P include directory" + HINTS "${SCOREP_EXEC_LOCATION}" + PATH_SUFFIXES "include" + ) +mark_as_advanced(ScoreP_INCLUDE_DIR) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ScoreP + REQUIRED_VARS ScoreP_INCLUDE_DIR + ) + +if (ScoreP_FOUND AND NOT TARGET ScoreP::ScoreP) + set(ScoreP_FLAGS "--user;--nocompiler" CACHE STRING "ScoreP wrapper flags") + set(ScoreP_COMPILER_LAUNCHER "${SCOREP_EXECUTABLE};${ScoreP_FLAGS}" CACHE STRING + "ScoreP wrapper and flags") + + add_library(ScoreP::ScoreP INTERFACE IMPORTED) + set_target_properties(ScoreP::ScoreP PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${ScoreP_INCLUDE_DIR}") +endif() From c10788325eda80ce0408a34bed1bb9a6330a6175 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Jun 2019 13:39:19 +0100 Subject: [PATCH 1544/1783] CMake: Add missing module for getting git revision --- cmake/GetGitRevisionDescription.cmake | 168 +++++++++++++++++++++++ cmake/GetGitRevisionDescription.cmake.in | 41 ++++++ 2 files changed, 209 insertions(+) create mode 100644 cmake/GetGitRevisionDescription.cmake create mode 100644 cmake/GetGitRevisionDescription.cmake.in diff --git a/cmake/GetGitRevisionDescription.cmake b/cmake/GetGitRevisionDescription.cmake new file mode 100644 index 0000000000..8ab03bc5f0 --- /dev/null +++ b/cmake/GetGitRevisionDescription.cmake @@ -0,0 +1,168 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ ...]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# git_local_changes() +# +# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes. +# Uses the return code of "git diff-index --quiet HEAD --". +# Does not regard untracked files. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +function(get_git_head_revision _refspecvar _hashvar) + set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories + set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") + get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) + if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) + # We have reached the root directory, we are not in git + set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + return() + endif() + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + endwhile() + # check if this is a submodule + if(NOT IS_DIRECTORY ${GIT_DIR}) + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${GIT_DIR}/HEAD") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" + @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) + set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + describe + ${hash} + ${ARGN} + WORKING_DIRECTORY + "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_local_changes _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + diff-index --quiet HEAD -- + WORKING_DIRECTORY + "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(res EQUAL 0) + set(${_var} "CLEAN" PARENT_SCOPE) + else() + set(${_var} "DIRTY" PARENT_SCOPE) + endif() +endfunction() diff --git a/cmake/GetGitRevisionDescription.cmake.in b/cmake/GetGitRevisionDescription.cmake.in new file mode 100644 index 0000000000..6d8b708efe --- /dev/null +++ b/cmake/GetGitRevisionDescription.cmake.in @@ -0,0 +1,41 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + else() + configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) + file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) + if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") + set(HEAD_HASH "${CMAKE_MATCH_1}") + endif() + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() From 6e77d01f2ebcfdb036308e2e4da1bd808e138cd3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Jun 2019 16:01:03 +0100 Subject: [PATCH 1545/1783] CMake: Add SLEPc support --- CMakeLists.txt | 30 +++-- cmake/FindPETSc.cmake | 21 +++- cmake/FindSLEPc.cmake | 279 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 317 insertions(+), 13 deletions(-) create mode 100644 cmake/FindSLEPc.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index c64d755d66..2bcef36494 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -409,14 +409,29 @@ endif() message(STATUS "LAPACK support: ${LAPACK_FOUND}") set(BOUT_HAS_LAPACK ${LAPACK_FOUND}) -find_package(PETSc) -if (PETSC_FOUND) - target_compile_definitions(bout++ - PUBLIC "BOUT_HAS_PETSC") - target_link_libraries(bout++ PUBLIC PETSC::PETSc) +option(USE_PETSC "Enable support for PETSc" OFF) +if (USE_PETSC) + find_package(PETSc REQUIRED) + if (PETSC_FOUND) + target_compile_definitions(bout++ + PUBLIC "BOUT_HAS_PETSC") + target_link_libraries(bout++ PUBLIC PETSc::PETSc) + endif() +endif() +message(STATUS "PETSc support: ${USE_PETSC}") +set(BOUT_HAS_PETSC ${USE_PETSC}) + +option(USE_SLEPC "Enable support for SLEPc" OFF) +if (USE_SLEPC) + find_package(SLEPc REQUIRED) + if (SLEPC_FOUND) + target_compile_definitions(bout++ + PUBLIC "BOUT_HAS_SLEPC") + target_link_libraries(bout++ PUBLIC SLEPc::SLEPc) + endif() endif() -message(STATUS "PETSc support: ${PETSC_FOUND}") -set(BOUT_HAS_PETSC ${PETSC_FOUND}) +message(STATUS "SLEPc support: ${USE_SLEPC}") +set(BOUT_HAS_SLEPC ${USE_SLEPC}) find_package(SUNDIALS) if (SUNDIALS_FOUND) @@ -594,6 +609,7 @@ message(" -------------------------------- PETSc support : ${BOUT_HAS_PETSC} + SLEPc support : ${BOUT_HAS_SLEPC} SUNDIALS support : ${BOUT_HAS_SUNDIALS} NetCDF support : ${BOUT_HAS_NETCDF} FFTW support : ${BOUT_HAS_FFTW} diff --git a/cmake/FindPETSc.cmake b/cmake/FindPETSc.cmake index e7d4d6522a..b912d29b7d 100644 --- a/cmake/FindPETSc.cmake +++ b/cmake/FindPETSc.cmake @@ -21,6 +21,7 @@ # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # +# Taken from https://github.com/jedbrown/cmake-modules/blob/master/FindPETSc.cmake cmake_policy(VERSION 3.3) @@ -286,12 +287,20 @@ int main(int argc,char *argv[]) { endmacro (PETSC_TEST_RUNS) - find_path (PETSC_INCLUDE_DIR petscts.h HINTS "${PETSC_DIR}" PATH_SUFFIXES include NO_DEFAULT_PATH) - find_path (PETSC_INCLUDE_CONF petscconf.h HINTS "${PETSC_DIR}" PATH_SUFFIXES "${PETSC_ARCH}/include" "bmake/${PETSC_ARCH}" NO_DEFAULT_PATH) + find_path (PETSC_INCLUDE_DIR petscts.h + HINTS "${PETSC_DIR}" + PATH_SUFFIXES include + NO_DEFAULT_PATH) + find_path (PETSC_INCLUDE_CONF petscconf.h + HINTS "${PETSC_DIR}" + PATH_SUFFIXES "${PETSC_ARCH}/include" "bmake/${PETSC_ARCH}" + NO_DEFAULT_PATH) mark_as_advanced (PETSC_INCLUDE_DIR PETSC_INCLUDE_CONF) set (petsc_includes_minimal ${PETSC_INCLUDE_CONF} ${PETSC_INCLUDE_DIR}) - petsc_test_runs ("${petsc_includes_minimal}" "${PETSC_LIBRARIES_TS}" petsc_works_minimal) + petsc_test_runs ("${petsc_includes_minimal}" + "${PETSC_LIBRARIES_TS};MPI::MPI_${PETSC_LANGUAGE_BINDINGS}" + petsc_works_minimal) if (petsc_works_minimal) message (STATUS "Minimal PETSc includes and libraries work. This probably means we are building with shared libs.") set (petsc_includes_needed "${petsc_includes_minimal}") @@ -346,9 +355,9 @@ find_package_handle_standard_args (PETSc FAIL_MESSAGE "PETSc could not be found. Be sure to set PETSC_DIR and PETSC_ARCH.") if (PETSC_FOUND) - if (NOT TARGET PETSC::PETSc) - add_library(PETSC::PETSc UNKNOWN IMPORTED) - set_target_properties(PETSC::PETSc PROPERTIES + if (NOT TARGET PETSc::PETSc) + add_library(PETSc::PETSc UNKNOWN IMPORTED) + set_target_properties(PETSc::PETSc PROPERTIES IMPORTED_LOCATION "${PETSC_LIBRARIES}" INTERFACE_INCLUDE_DIRECTORIES "${PETSC_INCLUDES}" ) diff --git a/cmake/FindSLEPc.cmake b/cmake/FindSLEPc.cmake new file mode 100644 index 0000000000..b4ca57ed89 --- /dev/null +++ b/cmake/FindSLEPc.cmake @@ -0,0 +1,279 @@ +# - Try to find SLEPC +# Once done this will define +# +# SLEPC_FOUND - system has SLEPc +# SLEPC_INCLUDE_DIR - include directories for SLEPc +# SLEPC_LIBARIES - libraries for SLEPc +# SLEPC_DIR - directory where SLEPc is built +# SLEPC_VERSION - version of SLEPc +# SLEPC_VERSION_MAJOR - First number in SLEPC_VERSION +# SLEPC_VERSION_MINOR - Second number in SLEPC_VERSION +# SLEPC_VERSION_SUBMINOR - Third number in SLEPC_VERSION +# +# Assumes that PETSC_DIR and PETSC_ARCH has been set by +# already calling find_package(PETSc) + +#============================================================================= +# Copyright (C) 2010-2012 Garth N. Wells, Anders Logg and Johannes Ring +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +#============================================================================= +# +# Taken from https://github.com/live-clones/libadjoint/blob/master/cmake/modules/FindSLEPc.cmake + +find_package(PETSc REQUIRED) +find_package(MPI REQUIRED) + +# Set debian_arches (PETSC_ARCH for Debian-style installations) +foreach (debian_arches linux kfreebsd) + if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + set(DEBIAN_FLAVORS ${debian_arches}-gnu-c-debug ${debian_arches}-gnu-c-opt ${DEBIAN_FLAVORS}) + else() + set(DEBIAN_FLAVORS ${debian_arches}-gnu-c-opt ${debian_arches}-gnu-c-debug ${DEBIAN_FLAVORS}) + endif() +endforeach() + +# List of possible locations for SLEPC_DIR +set(slepc_dir_locations "") +list(APPEND slepc_dir_locations "/usr/lib/slepc") +list(APPEND slepc_dir_locations "/opt/local/lib/petsc") # Macports +list(APPEND slepc_dir_locations "/usr/local/lib/slepc") +list(APPEND slepc_dir_locations "$ENV{HOME}/slepc") + +# Try to figure out SLEPC_DIR by finding slepc.h +find_path(SLEPC_DIR include/slepc.h + HINTS ${SLEPC_DIR} $ENV{SLEPC_DIR} + PATHS ${slepc_dir_locations} + DOC "SLEPc directory") + +# Report result of search for SLEPC_DIR +if (DEFINED SLEPC_DIR) + message(STATUS "SLEPC_DIR is ${SLEPC_DIR}") +else() + message(STATUS "SLEPC_DIR is empty") +endif() + +# Get variables from SLEPc configuration +if (SLEPC_DIR) + + find_library(SLEPC_LIBRARY + NAMES slepc + HINTS + ${SLEPC_DIR}/lib + $ENV{SLEPC_DIR}/lib + ${SLEPC_DIR}/${PETSC_ARCH}/lib + $ENV{SLEPC_DIR}/$ENV{PETSC_ARCH}/lib + NO_DEFAULT_PATH + DOC "The SLEPc library") + find_library(SLEPC_LIBRARY + NAMES slepc + DOC "The SLEPc library") + mark_as_advanced(SLEPC_LIBRARY) + + # Find SLEPc config file + find_file(SLEPC_CONFIG_FILE NAMES slepc_common PATHS + ${SLEPC_DIR}/lib/slepc/conf + ${SLEPC_DIR}/lib/slepc-conf ${SLEPC_DIR}/conf) + + # Create a temporary Makefile to probe the SLEPc configuration + set(slepc_config_makefile ${PROJECT_BINARY_DIR}/Makefile.slepc) + file(WRITE ${slepc_config_makefile} +"# This file was autogenerated by FindSLEPc.cmake +SLEPC_DIR = ${SLEPC_DIR} +PETSC_ARCH = ${PETSC_ARCH} +PETSC_DIR = ${PETSC_DIR} +include ${SLEPC_CONFIG_FILE} +show : + -@echo -n \${\${VARIABLE}} +") + + # Define macro for getting SLEPc variables from Makefile + macro(SLEPC_GET_VARIABLE var name) + set(${var} "NOTFOUND" CACHE INTERNAL "Cleared" FORCE) + execute_process(COMMAND ${CMAKE_MAKE_PROGRAM} --no-print-directory -f ${slepc_config_makefile} show VARIABLE=${name} + OUTPUT_VARIABLE ${var} + RESULT_VARIABLE slepc_return) + endmacro() + + # Call macro to get the SLEPc variables + slepc_get_variable(SLEPC_INCLUDE SLEPC_INCLUDE) + slepc_get_variable(SLEPC_EXTERNAL_LIB SLEPC_EXTERNAL_LIB) + + # Remove temporary Makefile + file(REMOVE ${slepc_config_makefile}) + + # Extract include paths and libraries from compile command line + include(ResolveCompilerPaths) + resolve_includes(SLEPC_INCLUDE_DIRS "${SLEPC_INCLUDE}") + resolve_libraries(SLEPC_EXTERNAL_LIBRARIES "${SLEPC_EXTERNAL_LIB}") + + # Add variables to CMake cache and mark as advanced + set(SLEPC_INCLUDE_DIRS ${SLEPC_INCLUDE_DIRS} CACHE STRING "SLEPc include paths." FORCE) + set(SLEPC_LIBRARIES ${SLEPC_LIBRARY} CACHE STRING "SLEPc libraries." FORCE) + mark_as_advanced(SLEPC_INCLUDE_DIRS SLEPC_LIBRARIES) +endif() + +if (SLEPC_SKIP_BUILD_TESTS) + set(SLEPC_TEST_RUNS TRUE) + set(SLEPC_VERSION "UNKNOWN") + set(SLEPC_VERSION_OK TRUE) +elseif (SLEPC_LIBRARIES AND SLEPC_INCLUDE_DIRS) + + # Set flags for building test program + set(CMAKE_REQUIRED_INCLUDES ${SLEPC_INCLUDE_DIRS}) + set(CMAKE_REQUIRED_LIBRARIES ${SLEPC_LIBRARIES} PETSc::PETSc MPI::MPI_CXX) + + # Check SLEPc version + set(SLEPC_CONFIG_TEST_VERSION_CPP + "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/slepc_config_test_version.cpp") + file(WRITE ${SLEPC_CONFIG_TEST_VERSION_CPP} " +#include +#include \"slepcversion.h\" + +int main() { + std::cout << SLEPC_VERSION_MAJOR << \".\" + << SLEPC_VERSION_MINOR << \".\" + << SLEPC_VERSION_SUBMINOR; + return 0; +} +") + + try_run( + SLEPC_CONFIG_TEST_VERSION_EXITCODE + SLEPC_CONFIG_TEST_VERSION_COMPILED + ${CMAKE_CURRENT_BINARY_DIR} + ${SLEPC_CONFIG_TEST_VERSION_CPP} + CMAKE_FLAGS + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}" + COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT + RUN_OUTPUT_VARIABLE OUTPUT + ) + + if (SLEPC_CONFIG_TEST_VERSION_EXITCODE EQUAL 0) + set(SLEPC_VERSION ${OUTPUT} CACHE TYPE STRING) + string(REPLACE "." ";" SLEPC_VERSION_LIST ${SLEPC_VERSION}) + list(GET SLEPC_VERSION_LIST 0 SLEPC_VERSION_MAJOR) + list(GET SLEPC_VERSION_LIST 1 SLEPC_VERSION_MINOR) + list(GET SLEPC_VERSION_LIST 2 SLEPC_VERSION_SUBMINOR) + mark_as_advanced(SLEPC_VERSION) + mark_as_advanced(SLEPC_VERSION_MAJOR, SLEPC_VERSION_MINOR, SLEPC_VERSION_SUBMINOR) + endif() + + if (SLEPc_FIND_VERSION) + # Check if version found is >= required version + if (NOT "${SLEPC_VERSION}" VERSION_LESS "${SLEPc_FIND_VERSION}") + set(SLEPC_VERSION_OK TRUE) + endif() + else() + # No specific version requested + set(SLEPC_VERSION_OK TRUE) + endif() + mark_as_advanced(SLEPC_VERSION_OK) + + # Run SLEPc test program + set(SLEPC_TEST_LIB_CPP + "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/slepc_test_lib.cpp") + file(WRITE ${SLEPC_TEST_LIB_CPP} " +#include \"petsc.h\" +#include \"slepceps.h\" +int main() +{ + PetscErrorCode ierr; + int argc = 0; + char** argv = NULL; + ierr = SlepcInitialize(&argc, &argv, PETSC_NULL, PETSC_NULL); + EPS eps; + ierr = EPSCreate(PETSC_COMM_SELF, &eps); CHKERRQ(ierr); + //ierr = EPSSetFromOptions(eps); CHKERRQ(ierr); +#if PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR <= 1 + ierr = EPSDestroy(eps); CHKERRQ(ierr); +#else + ierr = EPSDestroy(&eps); CHKERRQ(ierr); +#endif + ierr = SlepcFinalize(); CHKERRQ(ierr); + return 0; +} +") + + try_run( + SLEPC_TEST_LIB_EXITCODE + SLEPC_TEST_LIB_COMPILED + ${CMAKE_CURRENT_BINARY_DIR} + ${SLEPC_TEST_LIB_CPP} + CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}" + LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} + COMPILE_OUTPUT_VARIABLE SLEPC_TEST_LIB_COMPILE_OUTPUT + RUN_OUTPUT_VARIABLE SLEPC_TEST_LIB_OUTPUT + ) + + if (SLEPC_TEST_LIB_COMPILED AND SLEPC_TEST_LIB_EXITCODE EQUAL 0) + message(STATUS "Performing test SLEPC_TEST_RUNS - Success") + set(SLEPC_TEST_RUNS TRUE) + else() + message(STATUS "Performing test SLEPC_TEST_RUNS - Failed") + + # Test program does not run - try adding SLEPc 3rd party libs and test again + list(APPEND CMAKE_REQUIRED_LIBRARIES ${SLEPC_EXTERNAL_LIBRARIES}) + + try_run( + SLEPC_TEST_3RD_PARTY_LIBS_EXITCODE + SLEPC_TEST_3RD_PARTY_LIBS_COMPILED + ${CMAKE_CURRENT_BINARY_DIR} + ${SLEPC_TEST_LIB_CPP} + CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}" + LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} + COMPILE_OUTPUT_VARIABLE SLEPC_TEST_3RD_PARTY_LIBS_COMPILE_OUTPUT + RUN_OUTPUT_VARIABLE SLEPC_TEST_3RD_PARTY_LIBS_OUTPUT + ) + + if (SLEPC_TEST_3RD_PARTY_LIBS_COMPILED AND SLEPC_TEST_3RD_PARTY_LIBS_EXITCODE EQUAL 0) + message(STATUS "Performing test SLEPC_TEST_3RD_PARTY_LIBS_RUNS - Success") + set(SLEPC_LIBRARIES ${SLEPC_LIBRARIES} ${SLEPC_EXTERNAL_LIBRARIES} + CACHE STRING "SLEPc libraries." FORCE) + set(SLEPC_TEST_RUNS TRUE) + else() + message(STATUS "Performing test SLEPC_TEST_3RD_PARTY_LIBS_RUNS - Failed") + endif() + endif() +endif() + +# Standard package handling +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(SLEPc + "SLEPc could not be found. Be sure to set SLEPC_DIR, PETSC_DIR, and PETSC_ARCH." + SLEPC_LIBRARIES SLEPC_DIR SLEPC_INCLUDE_DIRS SLEPC_TEST_RUNS + SLEPC_VERSION SLEPC_VERSION_OK) + +if (SLEPC_FOUND) + if (NOT TARGET SLEPc::SLEPc) + add_library(SLEPc::SLEPc UNKNOWN IMPORTED) + set_target_properties(SLEPc::SLEPc PROPERTIES + IMPORTED_LOCATION "${SLEPC_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${SLEPC_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES PETSc::PETSc + ) + endif() +endif() From 378f23733592ecebeafc72dec61918d8aaf6b654 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Jun 2019 17:19:13 +0100 Subject: [PATCH 1546/1783] CMake: Add SLEPc test --- tests/integrated/CMakeLists.txt | 1 + tests/integrated/test-slepc-solver/CMakeLists.txt | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 tests/integrated/test-slepc-solver/CMakeLists.txt diff --git a/tests/integrated/CMakeLists.txt b/tests/integrated/CMakeLists.txt index 15ce45cd51..703225efaf 100644 --- a/tests/integrated/CMakeLists.txt +++ b/tests/integrated/CMakeLists.txt @@ -4,5 +4,6 @@ add_subdirectory(test-initial) add_subdirectory(test-invertable-operator) add_subdirectory(test-io) add_subdirectory(test-laplace) +add_subdirectory(test-slepc-solver) add_subdirectory(test-solver) add_subdirectory(test-stopCheck) diff --git a/tests/integrated/test-slepc-solver/CMakeLists.txt b/tests/integrated/test-slepc-solver/CMakeLists.txt new file mode 100644 index 0000000000..f8d7166e3d --- /dev/null +++ b/tests/integrated/test-slepc-solver/CMakeLists.txt @@ -0,0 +1,5 @@ +bout_add_integrated_test(test-slepc-solver + SOURCES test-slepc-solver.cxx + USE_RUNTEST + USE_DATA_BOUT_INP + ) From 5753d09d4ddc5018e46c2c7346f7658a354b07e4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Jun 2019 17:19:27 +0100 Subject: [PATCH 1547/1783] CMake: Fix clobbered literal tab character --- cmake/FindSLEPc.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindSLEPc.cmake b/cmake/FindSLEPc.cmake index b4ca57ed89..3c0e660282 100644 --- a/cmake/FindSLEPc.cmake +++ b/cmake/FindSLEPc.cmake @@ -107,7 +107,7 @@ PETSC_ARCH = ${PETSC_ARCH} PETSC_DIR = ${PETSC_DIR} include ${SLEPC_CONFIG_FILE} show : - -@echo -n \${\${VARIABLE}} + -@echo -n \${\${VARIABLE}} ") # Define macro for getting SLEPc variables from Makefile From c414d6550673d4a5d4fe646e7ffa5a1ebbd54068 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Jun 2019 17:19:55 +0100 Subject: [PATCH 1548/1783] CMake: Add option to enable `output_debug` --- CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bcef36494..dd05a5d4fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -308,6 +308,15 @@ target_compile_definitions(bout++ PUBLIC "CHECK=${CHECK}") set(BOUT_CHECK_LEVEL ${CHECK}) +option(DEBUG_ENABLED "Enable extra debug output" OFF) +if (DEBUG_ENABLED) + target_compile_definitions(bout++ + PUBLIC "DEBUG_ENABLED" + PUBLIC "BOUT_DEBUG_ENABLED") +endif() +message(STATUS "Extra debug output: DEBUG_ENABLED=${DEBUG_ENABLED}") +set(BOUT_DEBUG_ENABLED ${DEBUG_ENABLED}) + option(ENABLE_SIGNAL "SegFault handling" ON) if (ENABLE_SIGNAL) target_compile_definitions(bout++ From 9f80f2532f769dc4aa9bfab4d2409d4f8e9d37b8 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Jun 2019 17:20:23 +0100 Subject: [PATCH 1549/1783] CMake: Ensure all compile definitions are BOUT_ namespaced Keep non-namespaced versions for now --- CMakeLists.txt | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dd05a5d4fe..7e4862a1ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -305,7 +305,8 @@ if (NOT CHECK IN_LIST CHECK_LEVELS) endif() message(STATUS "Runtime checking level: CHECK=${CHECK}") target_compile_definitions(bout++ - PUBLIC "CHECK=${CHECK}") + PUBLIC "CHECK=${CHECK}" + PUBLIC "BOUT_CHECK=${CHECK}") set(BOUT_CHECK_LEVEL ${CHECK}) option(DEBUG_ENABLED "Enable extra debug output" OFF) @@ -320,7 +321,8 @@ set(BOUT_DEBUG_ENABLED ${DEBUG_ENABLED}) option(ENABLE_SIGNAL "SegFault handling" ON) if (ENABLE_SIGNAL) target_compile_definitions(bout++ - PUBLIC "SIGHANDLE") + PUBLIC "SIGHANDLE" + PUBLIC "BOUT_SIGHANDLE") endif() message(STATUS "Signal handling: SIGHANDLE=${ENABLE_SIGNAL}") set(BOUT_USE_SIGNAL ${ENABLE_SIGNAL}) @@ -328,7 +330,8 @@ set(BOUT_USE_SIGNAL ${ENABLE_SIGNAL}) option(ENABLE_COLOR "Output coloring" ON) if (ENABLE_COLOR) target_compile_definitions(bout++ - PUBLIC "LOGCOLOR") + PUBLIC "LOGCOLOR" + PUBLIC "BOUT_LOGCOLOR") endif() message(STATUS "Output coloring: LOGCOLOR=${ENABLE_COLOR}") set(BOUT_USE_COLOR ${ENABLE_COLOR}) @@ -336,7 +339,8 @@ set(BOUT_USE_COLOR ${ENABLE_COLOR}) option(ENABLE_TRACK "Field name tracking" ON) if (ENABLE_TRACK) target_compile_definitions(bout++ - PUBLIC "TRACK") + PUBLIC "TRACK" + PUBLIC "BOUT_TRACK") endif() message(STATUS "Field name tracking: TRACK=${ENABLE_TRACK}") set(BOUT_USE_TRACK ${ENABLE_TRACK}) @@ -356,7 +360,8 @@ if (ENABLE_BACKTRACE) message(FATAL_ERROR "addr2line not found") endif() target_compile_definitions(bout++ - PUBLIC "BACKTRACE") + PUBLIC "BACKTRACE" + PUBLIC "BOUT_BACKTRACE") target_link_libraries(bout++ PUBLIC ${CMAKE_DL_LIBS}) endif() message(STATUS "Enable backtrace: BACKTRACE=${ENABLE_BACKTRACE}") @@ -376,7 +381,8 @@ if (ENABLE_OPENMP) message(FATAL_ERROR "OPENMP_SCHEDULE must be one of ${possible_openmp_schedules}") endif() target_compile_definitions(bout++ - PUBLIC "OPENMP_SCHEDULE=${OPENMP_SCHEDULE}") + PUBLIC "OPENMP_SCHEDULE=${OPENMP_SCHEDULE}" + PUBLIC "BOUT_OPENMP_SCHEDULE=${OPENMP_SCHEDULE}") message(STATUS "OpenMP schedule: ${OPENMP_SCHEDULE}") endif() message(STATUS "Enable OpenMP: ${ENABLE_OPENMP}") @@ -394,7 +400,8 @@ set(BOUT_GIT_REVISION ${GIT_SHA1}) find_package(NetCDF) if (NetCDF_FOUND) target_compile_definitions(bout++ - PUBLIC "NCDF4") + PUBLIC "NCDF4" + PUBLIC "BOUT_HAS_NETCDF") target_link_libraries(bout++ PUBLIC NetCDF::NetCDF_CXX) endif() message(STATUS "NetCDF support: ${NetCDF_FOUND}") @@ -412,7 +419,8 @@ set(BOUT_HAS_FFTW ${FFTW_FOUND}) find_package(LAPACK) if (LAPACK_FOUND) target_compile_definitions(bout++ - PUBLIC "LAPACK") + PUBLIC "LAPACK" + PUBLIC "BOUT_HAS_LAPACK") target_link_libraries(bout++ PUBLIC "${LAPACK_LIBRARIES}") endif() message(STATUS "LAPACK support: ${LAPACK_FOUND}") @@ -447,7 +455,8 @@ if (SUNDIALS_FOUND) target_compile_definitions(bout++ PUBLIC "BOUT_HAS_CVODE" PUBLIC "BOUT_HAS_IDA" - PUBLIC "BOUT_HAS_ARKODE") + PUBLIC "BOUT_HAS_ARKODE" + PUBLIC "BOUT_HAS_SUNDIALS") target_link_libraries(bout++ PUBLIC SUNDIALS_cvode::cvode) target_link_libraries(bout++ PUBLIC SUNDIALS_ida::ida) target_link_libraries(bout++ PUBLIC SUNDIALS_arkode::arkode) From de13e9e48603096937000eaa1812c331e4e77ca7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Jun 2019 17:43:43 +0100 Subject: [PATCH 1550/1783] CMake: Be more consistent in handling config options --- CMakeLists.txt | 74 ++++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e4862a1ca..e2a9ac6429 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -316,7 +316,7 @@ if (DEBUG_ENABLED) PUBLIC "BOUT_DEBUG_ENABLED") endif() message(STATUS "Extra debug output: DEBUG_ENABLED=${DEBUG_ENABLED}") -set(BOUT_DEBUG_ENABLED ${DEBUG_ENABLED}) +set(BOUT_HAS_OUTPUT_DEBUG ${DEBUG_ENABLED}) option(ENABLE_SIGNAL "SegFault handling" ON) if (ENABLE_SIGNAL) @@ -369,12 +369,8 @@ set(BOUT_USE_BACKTRACE ${ENABLE_BACKTRACE}) option(ENABLE_OPENMP "Enable OpenMP support" OFF) if (ENABLE_OPENMP) - find_package(OpenMP) - if (OpenMP_CXX_FOUND) - target_link_libraries(bout++ PUBLIC OpenMP::OpenMP_CXX) - else() - message(FATAL_ERROR "OpenMP support requested but could not be enabled") - endif() + find_package(OpenMP REQUIRED) + target_link_libraries(bout++ PUBLIC OpenMP::OpenMP_CXX) set(possible_openmp_schedules static dynamic guided auto) set(OPENMP_SCHEDULE static CACHE STRINGS "Set OpenMP schedule") if (NOT OPENMP_SCHEDULE IN_LIST possible_openmp_schedules) @@ -397,61 +393,61 @@ set(BOUT_GIT_REVISION ${GIT_SHA1}) # Optional dependencies -find_package(NetCDF) -if (NetCDF_FOUND) +option(USE_NETCDF "Enable support for NetCDF output" ON) +if (USE_NETCDF) + find_package(NetCDF REQUIRED) target_compile_definitions(bout++ PUBLIC "NCDF4" PUBLIC "BOUT_HAS_NETCDF") target_link_libraries(bout++ PUBLIC NetCDF::NetCDF_CXX) endif() -message(STATUS "NetCDF support: ${NetCDF_FOUND}") -set(BOUT_HAS_NETCDF ${NetCDF_FOUND}) +message(STATUS "NetCDF support: ${USE_NETCDF}") +set(BOUT_HAS_NETCDF ${USE_NETCDF}) -find_package(FFTW) -if (FFTW_FOUND) +option(USE_FFTW "Enable support for FFTW" ON) +if (USE_FFTW) + find_package(FFTW REQUIRED) target_compile_definitions(bout++ PUBLIC "BOUT_HAS_FFTW") target_link_libraries(bout++ PUBLIC FFTW::FFTW) endif() -message(STATUS "FFTW support: ${FFTW_FOUND}") -set(BOUT_HAS_FFTW ${FFTW_FOUND}) +message(STATUS "FFTW support: ${USE_FFTW}") +set(BOUT_HAS_FFTW ${USE_FFTW}) -find_package(LAPACK) -if (LAPACK_FOUND) +option(USE_LAPACK "Enable support for LAPACK" ON) +if (USE_LAPACK) + find_package(LAPACK REQUIRED) target_compile_definitions(bout++ PUBLIC "LAPACK" PUBLIC "BOUT_HAS_LAPACK") target_link_libraries(bout++ PUBLIC "${LAPACK_LIBRARIES}") endif() -message(STATUS "LAPACK support: ${LAPACK_FOUND}") -set(BOUT_HAS_LAPACK ${LAPACK_FOUND}) +message(STATUS "LAPACK support: ${USE_LAPACK}") +set(BOUT_HAS_LAPACK ${USE_LAPACK}) -option(USE_PETSC "Enable support for PETSc" OFF) +option(USE_PETSC "Enable support for PETSc time solvers and inversions" OFF) if (USE_PETSC) find_package(PETSc REQUIRED) - if (PETSC_FOUND) - target_compile_definitions(bout++ - PUBLIC "BOUT_HAS_PETSC") - target_link_libraries(bout++ PUBLIC PETSc::PETSc) - endif() + target_compile_definitions(bout++ + PUBLIC "BOUT_HAS_PETSC") + target_link_libraries(bout++ PUBLIC PETSc::PETSc) endif() message(STATUS "PETSc support: ${USE_PETSC}") set(BOUT_HAS_PETSC ${USE_PETSC}) -option(USE_SLEPC "Enable support for SLEPc" OFF) +option(USE_SLEPC "Enable support for SLEPc eigen solver" OFF) if (USE_SLEPC) find_package(SLEPc REQUIRED) - if (SLEPC_FOUND) - target_compile_definitions(bout++ - PUBLIC "BOUT_HAS_SLEPC") - target_link_libraries(bout++ PUBLIC SLEPc::SLEPc) - endif() + target_compile_definitions(bout++ + PUBLIC "BOUT_HAS_SLEPC") + target_link_libraries(bout++ PUBLIC SLEPc::SLEPc) endif() message(STATUS "SLEPc support: ${USE_SLEPC}") set(BOUT_HAS_SLEPC ${USE_SLEPC}) -find_package(SUNDIALS) -if (SUNDIALS_FOUND) +option(USE_SUNDIALS "Enable support for SUNDIALS time solvers" OFF) +if (USE_SUNDIALS) + find_package(SUNDIALS) target_compile_definitions(bout++ PUBLIC "BOUT_HAS_CVODE" PUBLIC "BOUT_HAS_IDA" @@ -461,9 +457,10 @@ if (SUNDIALS_FOUND) target_link_libraries(bout++ PUBLIC SUNDIALS_ida::ida) target_link_libraries(bout++ PUBLIC SUNDIALS_arkode::arkode) endif() -message(STATUS "SUNDIALS support: ${SUNDIALS_FOUND}") -set(BOUT_HAS_SUNDIALS ${SUNDIALS_FOUND}) +message(STATUS "SUNDIALS support: ${USE_SUNDIALS}") +set(BOUT_HAS_SUNDIALS ${USE_SUNDIALS}) +option(USE_NLS "Enable Native Language Support" ON) find_package(Gettext) if (GETTEXT_FOUND) target_compile_definitions(bout++ @@ -635,6 +632,13 @@ message(" OpenMP support : ${BOUT_USE_OPENMP} Natural language support : ${BOUT_HAS_GETTEXT} ScoreP support : ${BOUT_HAS_SCOREP} + Extra debug output : ${BOUT_HAS_OUTPUT_DEBUG} + CHECK level : ${BOUT_CHECK_LEVEL} + Signal handling : ${BOUT_USE_SIGNAL} + Output coloring : ${BOUT_USE_COLOR} + Field name tracking : ${BOUT_USE_TRACK} + Floating point exceptions: ${BOUT_USE_SIGFPE} + Backtrace enabled : ${BOUT_USE_BACKTRACE} === Python === From 19d69b254fb6737746ac0d7725be2a9e39288540 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Jun 2019 17:55:49 +0100 Subject: [PATCH 1551/1783] CMake: Fix wrong name of executable for invertable operator test --- tests/integrated/test-invertable-operator/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integrated/test-invertable-operator/CMakeLists.txt b/tests/integrated/test-invertable-operator/CMakeLists.txt index 6f6ba7b0f2..11d7a112dc 100644 --- a/tests/integrated/test-invertable-operator/CMakeLists.txt +++ b/tests/integrated/test-invertable-operator/CMakeLists.txt @@ -1,4 +1,4 @@ -bout_add_integrated_test(test_invertable_operator +bout_add_integrated_test(invertable_operator SOURCES invertable_operator.cxx USE_RUNTEST USE_DATA_BOUT_INP From d6ed6597a3f7666bf0662fa956a5243212be2e73 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Jun 2019 17:56:07 +0100 Subject: [PATCH 1552/1783] Bugfix: invertable operator test has too tight tolerance The default tolerance to `verify` is 1.e-5 and is an absolute tolerance. The default relative tolerance for the PETSc KSP is 1.e-5. The Python script uses 1.e-3. --- .../integrated/test-invertable-operator/invertable_operator.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integrated/test-invertable-operator/invertable_operator.cxx b/tests/integrated/test-invertable-operator/invertable_operator.cxx index 6580e20726..f41779a074 100644 --- a/tests/integrated/test-invertable-operator/invertable_operator.cxx +++ b/tests/integrated/test-invertable-operator/invertable_operator.cxx @@ -69,7 +69,7 @@ class InvertableOperatorTest : public PhysicsModel { solutionInv = mySolver.invert(n, 0.0); mesh->communicate(solutionInv); - passVerification = mySolver.verify(n); + passVerification = mySolver.verify(n, 1.e-3); solutionLap = laplacianSolver->solve(n); From 6a7c1da173a834eab9079ccb508084a7c207fc77 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Jun 2019 18:01:09 +0100 Subject: [PATCH 1553/1783] Bugfix: wrong type for output_debug in header --- include/output.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/output.hxx b/include/output.hxx index dd27df5699..631c5c630e 100644 --- a/include/output.hxx +++ b/include/output.hxx @@ -252,7 +252,7 @@ template ConditionalOutput &operator<<(ConditionalOutput &out, cons /// To allow statements like "output.write(...)" or "output << ..." /// Output for debugging #ifdef DEBUG_ENABLED -extern Output output_debug; +extern ConditionalOutput output_debug; #else extern DummyOutput output_debug; #endif From d9a3ac3388649cff8dc548830fc122134ea7ad2e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 14 Jun 2019 18:01:28 +0100 Subject: [PATCH 1554/1783] Add build using CMake to Travis --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.travis.yml b/.travis.yml index c22802bce3..1a0aa362fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -76,6 +76,15 @@ matrix: - *default_env - CONFIGURE_OPTIONS="--enable-openmp --with-petsc --with-slepc --with-sundials=$HOME/local" - OMP_NUM_THREADS=2 +#CMAKE + - env: + - *default_env + - OMP_NUM_THREADS=2 + script: + - mkdir build && cd build + - cmake .. -DUSE_PETSC=ON -DUSE_SLEPC=ON -DUSE_SUNDIALS=ON -DSUNDIALS_ROOT="$HOME/local" -DENABLE_OPENMP=ON + - cmake --build . + - ctest --output-on-failure #CLANG - env: - *default_env From a57eb2f00abe0e70e911b9f0b1d4c1c3eae10f0b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 17 Jun 2019 09:43:52 +0100 Subject: [PATCH 1555/1783] CMake: Delete non-existent test files from source list --- tests/unit/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 236bb99e2f..fce0a1a124 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -33,10 +33,8 @@ add_executable(serial_tests ./include/test_mask.cxx ./invert/test_fft.cxx ./mesh/data/test_gridfromoptions.cxx - ./mesh/parallel/test_fci.cxx ./mesh/parallel/test_shiftedmetric.cxx ./mesh/test_boundary_factory.cxx - ./mesh/test_boundary_testtest.cxx ./mesh/test_boutmesh.cxx ./mesh/test_coordinates.cxx ./mesh/test_interpolation.cxx From c91513fe029ee709cd4fe0fdda890efae3eeb4a2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 17 Jun 2019 16:27:05 +0100 Subject: [PATCH 1556/1783] CMake: Skip trying to find LAPACK/PETSc on Cray systems --- CMakeLists.txt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e2a9ac6429..4496eeef36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -416,21 +416,27 @@ set(BOUT_HAS_FFTW ${USE_FFTW}) option(USE_LAPACK "Enable support for LAPACK" ON) if (USE_LAPACK) - find_package(LAPACK REQUIRED) + if (NOT CMAKE_SYSTEM_NAME STREQUAL "CrayLinuxEnvironment") + # Cray wrappers sort this out for us + find_package(LAPACK REQUIRED) + target_link_libraries(bout++ PUBLIC "${LAPACK_LIBRARIES}") + endif() target_compile_definitions(bout++ PUBLIC "LAPACK" PUBLIC "BOUT_HAS_LAPACK") - target_link_libraries(bout++ PUBLIC "${LAPACK_LIBRARIES}") endif() message(STATUS "LAPACK support: ${USE_LAPACK}") set(BOUT_HAS_LAPACK ${USE_LAPACK}) option(USE_PETSC "Enable support for PETSc time solvers and inversions" OFF) if (USE_PETSC) - find_package(PETSc REQUIRED) + if (NOT CMAKE_SYSTEM_NAME STREQUAL "CrayLinuxEnvironment") + # Cray wrappers sort this out for us + find_package(PETSc REQUIRED) + target_link_libraries(bout++ PUBLIC PETSc::PETSc) + endif() target_compile_definitions(bout++ PUBLIC "BOUT_HAS_PETSC") - target_link_libraries(bout++ PUBLIC PETSc::PETSc) endif() message(STATUS "PETSc support: ${USE_PETSC}") set(BOUT_HAS_PETSC ${USE_PETSC}) From 4ce74fd3f05b71f60f28233828c150089badcf96 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 17 Jun 2019 16:48:13 +0100 Subject: [PATCH 1557/1783] CMake: Add docs to Find{FFTW,NetCDF}, use standard variable names --- cmake/FindFFTW.cmake | 31 +++++++++++++++++++++++++------ cmake/FindNetCDF.cmake | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake index d4ebc22818..80b0b79d74 100644 --- a/cmake/FindFFTW.cmake +++ b/cmake/FindFFTW.cmake @@ -1,23 +1,42 @@ -if (FFTW_INCLUDES) +# FindFFTW +# ---------- +# +# Find the Fastest Fourier Transform in the West FFT library +# +# This module uses the ``fftw-wisdom`` executable as a hint for the +# location of the FFTW library. It should be in your PATH. +# +# This module will define the following variables: +# +# :: +# +# FFTW_FOUND - true if FFTW was found +# FFTW_INCLUDE_DIRS - Location of the FFTW includes +# FFTW_LIBRARIES - Required libraries +# +# This module will also export the ``FFTW::FFTW`` target. +# + +if (FFTW_INCLUDE_DIRS) # Already in cache, be silent set (FFTW_FIND_QUIETLY TRUE) -endif (FFTW_INCLUDES) +endif (FFTW_INCLUDE_DIRS) -find_path (FFTW_INCLUDES fftw3.h) +find_path (FFTW_INCLUDE_DIRS fftw3.h) find_library (FFTW_LIBRARIES NAMES fftw3) # handle the QUIETLY and REQUIRED arguments and set FFTW_FOUND to TRUE if # all listed variables are TRUE include (FindPackageHandleStandardArgs) -find_package_handle_standard_args (FFTW DEFAULT_MSG FFTW_LIBRARIES FFTW_INCLUDES) +find_package_handle_standard_args (FFTW DEFAULT_MSG FFTW_LIBRARIES FFTW_INCLUDE_DIRS) -mark_as_advanced (FFTW_LIBRARIES FFTW_INCLUDES) +mark_as_advanced (FFTW_LIBRARIES FFTW_INCLUDE_DIRS) if (FFTW_FOUND AND NOT TARGET FFTW::FFTW) add_library(FFTW::FFTW UNKNOWN IMPORTED) set_target_properties(FFTW::FFTW PROPERTIES IMPORTED_LOCATION "${FFTW_LIBRARIES}" - INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDES}" + INTERFACE_INCLUDE_DIRECTORIES "${FFTW_INCLUDE_DIRS}" ) endif() diff --git a/cmake/FindNetCDF.cmake b/cmake/FindNetCDF.cmake index 14737879f5..3cd6b91f1f 100644 --- a/cmake/FindNetCDF.cmake +++ b/cmake/FindNetCDF.cmake @@ -1,4 +1,26 @@ +# FindNetCDF +# ---------- +# +# Find the NetCDF IO library +# +# This module uses the ``nc-config`` and ``ncxx4-config`` helper scripts +# as hints for the location of the NetCDF libraries. They should be in +# your PATH. +# +# This module will define the following variables: +# +# :: +# +# NetCDF_FOUND - true if NetCDF was found +# NetCDF_VERSION - NetCDF version in format Major.Minor.Release +# NetCDF_INCLUDE_DIRS - Location of the NetCDF includes +# NetCDF_LIBRARIES - Required libraries +# +# This module will also export ``NetCDF::NetCDF_C`` and +# ``NetCDF::NetCDF_CXX`` targets. # Taken from https://github.com/conan-io/conan/issues/2125#issuecomment-351176653 +# This is needed so we can make a clone of the NetCDF C++ target which +# has the name "netcdf-cxx4" by default function(add_cloned_imported_target dst src) add_library(${dst} INTERFACE IMPORTED) foreach(name INTERFACE_LINK_LIBRARIES INTERFACE_INCLUDE_DIRECTORIES INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS) @@ -46,7 +68,7 @@ set(NC_HINTS "") inspect_netcdf_config(NC_HINTS "${NC_CONFIG}" "--includedir") inspect_netcdf_config(NC_HINTS "${NC_CONFIG}" "--prefix") -find_path(NetCDF_INCLUDE_DIR +find_path(NetCDF_C_INCLUDE_DIR NAMES netcdf.h DOC "NetCDF C include directories" HINTS @@ -56,9 +78,9 @@ find_path(NetCDF_INCLUDE_DIR "include" ) message(${NetCDF_INCLUDE_DIR}) -mark_as_advanced(NetCDF_INCLUDE_DIR) +mark_as_advanced(NetCDF_C_INCLUDE_DIR) -find_library(NetCDF_LIBRARY +find_library(NetCDF_C_LIBRARY NAMES netcdf DOC "NetCDF C library" HINTS @@ -67,7 +89,7 @@ find_library(NetCDF_LIBRARY PATH_SUFFIXES "lib" "lib64" ) -mark_as_advanced(NetCDF_LIBRARY) +mark_as_advanced(NetCDF_C_LIBRARY) set(NCXX4_HINTS "") inspect_netcdf_config(NCXX4_HINTS "${NCXX4_CONFIG}" "--includedir") @@ -112,18 +134,18 @@ endif () include(FindPackageHandleStandardArgs) find_package_handle_standard_args(NetCDF - REQUIRED_VARS NetCDF_LIBRARY NetCDF_INCLUDE_DIR NetCDF_CXX_LIBRARY NetCDF_CXX_INCLUDE_DIR + REQUIRED_VARS NetCDF_C_LIBRARY NetCDF_C_INCLUDE_DIR NetCDF_CXX_LIBRARY NetCDF_CXX_INCLUDE_DIR VERSION_VAR NetCDF_VERSION) if (NetCDF_FOUND) - set(NetCDF_INCLUDE_DIRS "${NetCDF_CXX_INCLUDE_DIR}" "${NetCDF_INCLUDE_DIR}") + set(NetCDF_INCLUDE_DIRS "${NetCDF_CXX_INCLUDE_DIR}" "${NetCDF_C_INCLUDE_DIR}") set(NetCDF_LIBRARIES "${NetCDF_CXX_LIBRARY}" "${NetCDF_LIBRARY}") if (NOT TARGET NetCDF::NetCDF) add_library(NetCDF::NetCDF_C UNKNOWN IMPORTED) set_target_properties(NetCDF::NetCDF_C PROPERTIES - IMPORTED_LOCATION "${NetCDF_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_INCLUDE_DIR}" + IMPORTED_LOCATION "${NetCDF_C_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_C_INCLUDE_DIR}" ) add_library(NetCDF::NetCDF_CXX UNKNOWN IMPORTED) set_target_properties(NetCDF::NetCDF_CXX PROPERTIES From c9c9a1b4ba62cef094cc019f4a0d6d2940fddf30 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 17 Jun 2019 16:49:20 +0100 Subject: [PATCH 1558/1783] CMake: Improve the hints for FindNetCDF --- cmake/FindNetCDF.cmake | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/cmake/FindNetCDF.cmake b/cmake/FindNetCDF.cmake index 3cd6b91f1f..055949143d 100644 --- a/cmake/FindNetCDF.cmake +++ b/cmake/FindNetCDF.cmake @@ -47,8 +47,7 @@ function(inspect_netcdf_config VAR NX_CONFIG ARG) OUTPUT_STRIP_TRAILING_WHITESPACE ) if(EXISTS "${NX_CONFIG_OUTPUT}") - list(APPEND ${VAR} ${NX_CONFIG_OUTPUT}) - set(${VAR} ${${VAR}} PARENT_SCOPE) + set(${VAR} ${NX_CONFIG_OUTPUT} PARENT_SCOPE) endif() endfunction() @@ -64,15 +63,15 @@ find_program(NCXX4_CONFIG "ncxx4-config" get_filename_component(NCXX4_CONFIG_TMP "${NCXX4_CONFIG}" DIRECTORY) get_filename_component(NCXX4_CONFIG_LOCATION "${NCXX4_CONFIG_TMP}" DIRECTORY) -set(NC_HINTS "") -inspect_netcdf_config(NC_HINTS "${NC_CONFIG}" "--includedir") -inspect_netcdf_config(NC_HINTS "${NC_CONFIG}" "--prefix") +inspect_netcdf_config(NC_HINTS_INCLUDE_DIR "${NC_CONFIG}" "--includedir") +inspect_netcdf_config(NC_HINTS_PREFIX "${NC_CONFIG}" "--prefix") find_path(NetCDF_C_INCLUDE_DIR NAMES netcdf.h DOC "NetCDF C include directories" HINTS - "${NC_HINTS}" + "${NC_HINTS_INCLUDE_DIR}" + "${NC_HINTS_PREFIX}" "${NC_CONFIG_LOCATION}" PATH_SUFFIXES "include" @@ -84,22 +83,24 @@ find_library(NetCDF_C_LIBRARY NAMES netcdf DOC "NetCDF C library" HINTS - "${NC_HINTS}" + "${NC_HINTS_INCLUDE_DIR}" + "${NC_HINTS_PREFIX}" "${NC_CONFIG_LOCATION}" PATH_SUFFIXES "lib" "lib64" ) mark_as_advanced(NetCDF_C_LIBRARY) -set(NCXX4_HINTS "") -inspect_netcdf_config(NCXX4_HINTS "${NCXX4_CONFIG}" "--includedir") -inspect_netcdf_config(NCXX4_HINTS "${NCXX4_CONFIG}" "--prefix") +inspect_netcdf_config(NCXX4_HINTS_INCLUDE_DIR "${NCXX4_CONFIG}" "--includedir") +inspect_netcdf_config(NCXX4_HINTS_PREFIX "${NCXX4_CONFIG}" "--prefix") find_path(NetCDF_CXX_INCLUDE_DIR NAMES netcdf DOC "NetCDF C++ include directories" HINTS - "${NCXX4_HINTS}" + "${NetCDF_C_INCLUDE_DIR}" + "${NCXX4_HINTS_INCLUDE_DIR}" + "${NCXX4_HINTS_PREFIX}" "${NCXX4_CONFIG_LOCATION}" PATH_SUFFIXES "include" @@ -110,7 +111,8 @@ find_library(NetCDF_CXX_LIBRARY NAMES netcdf_c++4 netcdf-cxx4 DOC "NetCDF C++ library" HINTS - "${NCXX4_HINTS}" + "${NCXX4_HINTS_INCLUDE_DIR}" + "${NCXX4_HINTS_PREFIX}" "${NCXX4_CONFIG_LOCATION}" PATH_SUFFIXES "lib" "lib64" From 52beb8640db27f84b4e258453358ec95508511e3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 17 Jun 2019 16:50:01 +0100 Subject: [PATCH 1559/1783] CMake: Add hints for FindFFTW from fftw-wisdom location --- cmake/FindFFTW.cmake | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake index 80b0b79d74..bf22dfa52b 100644 --- a/cmake/FindFFTW.cmake +++ b/cmake/FindFFTW.cmake @@ -22,9 +22,25 @@ if (FFTW_INCLUDE_DIRS) set (FFTW_FIND_QUIETLY TRUE) endif (FFTW_INCLUDE_DIRS) -find_path (FFTW_INCLUDE_DIRS fftw3.h) +find_program(FFTW_WISDOM "fftw-wisdom" + DOC "Path to fftw-wisdom executable" + ) +get_filename_component(FFTW_WISDOM_TMP "${FFTW_WISDOM}" DIRECTORY) +get_filename_component(FFTW_HINT_DIR "${FFTW_WISDOM_TMP}" DIRECTORY) -find_library (FFTW_LIBRARIES NAMES fftw3) +find_path(FFTW_INCLUDE_DIRS + NAMES fftw3.h + DOC "FFTW include directory" + HINTS "${FFTW_HINT_DIR}" + PATH_SUFFIXES "include" + ) + +find_library (FFTW_LIBRARIES + NAMES fftw3 + DOC "FFTW library location" + HINTS "${FFTW_HINT_DIR}" + PATH_SUFFIXES "lib" "lib64" + ) # handle the QUIETLY and REQUIRED arguments and set FFTW_FOUND to TRUE if # all listed variables are TRUE From 4bf9868cf58c3782b6fe449a7dc6af3fb960dd8d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 17 Jun 2019 16:50:20 +0100 Subject: [PATCH 1560/1783] CMake: Add optional debug output to Find{FFTW,NetCDF} --- cmake/FindFFTW.cmake | 25 ++++++++++++++++++++++ cmake/FindNetCDF.cmake | 47 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake index bf22dfa52b..271e61c79e 100644 --- a/cmake/FindFFTW.cmake +++ b/cmake/FindFFTW.cmake @@ -16,6 +16,13 @@ # # This module will also export the ``FFTW::FFTW`` target. # +# You can also set the following variables: +# +# ``FFTW_ROOT`` +# Specify the path to the FFTW installation to use +# +# ``FFTW_DEBUG`` +# Set to TRUE to get extra debugging output if (FFTW_INCLUDE_DIRS) # Already in cache, be silent @@ -25,6 +32,12 @@ endif (FFTW_INCLUDE_DIRS) find_program(FFTW_WISDOM "fftw-wisdom" DOC "Path to fftw-wisdom executable" ) +if (FFTW_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " FFTW_WISDOM = ${FFTW_WISDOM}" + ) +endif() + get_filename_component(FFTW_WISDOM_TMP "${FFTW_WISDOM}" DIRECTORY) get_filename_component(FFTW_HINT_DIR "${FFTW_WISDOM_TMP}" DIRECTORY) @@ -34,6 +47,12 @@ find_path(FFTW_INCLUDE_DIRS HINTS "${FFTW_HINT_DIR}" PATH_SUFFIXES "include" ) +if (FFTW_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " FFTW_INCLUDE_DIRS = ${FFTW_INCLUDE_DIRS}" + " FFTW_HINT_DIR = ${FFTW_HINT_DIR}" + ) +endif() find_library (FFTW_LIBRARIES NAMES fftw3 @@ -41,6 +60,12 @@ find_library (FFTW_LIBRARIES HINTS "${FFTW_HINT_DIR}" PATH_SUFFIXES "lib" "lib64" ) +if (FFTW_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " FFTW_LIBRARIES = ${FFTW_LIBRARIES}" + " FFTW_HINT_DIR = ${FFTW_HINT_DIR}" + ) +endif() # handle the QUIETLY and REQUIRED arguments and set FFTW_FOUND to TRUE if # all listed variables are TRUE diff --git a/cmake/FindNetCDF.cmake b/cmake/FindNetCDF.cmake index 055949143d..4f7529105d 100644 --- a/cmake/FindNetCDF.cmake +++ b/cmake/FindNetCDF.cmake @@ -18,6 +18,16 @@ # # This module will also export ``NetCDF::NetCDF_C`` and # ``NetCDF::NetCDF_CXX`` targets. +# +# You can also set the following variables: +# +# ``NetCDF_ROOT`` +# Specify the path to the NetCDF installation to use +# +# ``NetCDF_DEBUG`` +# Set to TRUE to get extra debugging output + + # Taken from https://github.com/conan-io/conan/issues/2125#issuecomment-351176653 # This is needed so we can make a clone of the NetCDF C++ target which # has the name "netcdf-cxx4" by default @@ -56,12 +66,20 @@ find_program(NC_CONFIG "nc-config" ) get_filename_component(NC_CONFIG_TMP "${NC_CONFIG}" DIRECTORY) get_filename_component(NC_CONFIG_LOCATION "${NC_CONFIG_TMP}" DIRECTORY) +if (NetCDF_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " NC_CONFIG_LOCATION = ${NC_CONFIG_LOCATION}") +endif() find_program(NCXX4_CONFIG "ncxx4-config" DOC "Path to NetCDF C++ config helper" ) get_filename_component(NCXX4_CONFIG_TMP "${NCXX4_CONFIG}" DIRECTORY) get_filename_component(NCXX4_CONFIG_LOCATION "${NCXX4_CONFIG_TMP}" DIRECTORY) +if (NetCDF_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " NCXX4_CONFIG_LOCATION = ${NCXX4_CONFIG_LOCATION}") +endif() inspect_netcdf_config(NC_HINTS_INCLUDE_DIR "${NC_CONFIG}" "--includedir") inspect_netcdf_config(NC_HINTS_PREFIX "${NC_CONFIG}" "--prefix") @@ -76,7 +94,13 @@ find_path(NetCDF_C_INCLUDE_DIR PATH_SUFFIXES "include" ) -message(${NetCDF_INCLUDE_DIR}) +if (NetCDF_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " NetCDF_C_INCLUDE_DIR = ${NetCDF_C_INCLUDE_DIR}" + " NC_HINTS_INCLUDE_DIR = ${NC_HINTS_INCLUDE_DIR}" + " NC_HINTS_PREFIX = ${NC_HINTS_PREFIX}" + ) +endif() mark_as_advanced(NetCDF_C_INCLUDE_DIR) find_library(NetCDF_C_LIBRARY @@ -89,6 +113,13 @@ find_library(NetCDF_C_LIBRARY PATH_SUFFIXES "lib" "lib64" ) +if (NetCDF_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " NetCDF_C_LIBRARY = ${NetCDF_C_LIBRARY}" + " NC_HINTS_INCLUDE_DIR = ${NC_HINTS_INCLUDE_DIR}" + " NC_HINTS_PREFIX = ${NC_HINTS_PREFIX}" + ) +endif() mark_as_advanced(NetCDF_C_LIBRARY) inspect_netcdf_config(NCXX4_HINTS_INCLUDE_DIR "${NCXX4_CONFIG}" "--includedir") @@ -105,6 +136,13 @@ find_path(NetCDF_CXX_INCLUDE_DIR PATH_SUFFIXES "include" ) +if (NetCDF_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " NetCDF_CXX_INCLUDE_DIR = ${NetCDF_CXX_INCLUDE_DIR}" + " NCXX4_HINTS_INCLUDE_DIR = ${NCXX4_HINTS_INCLUDE_DIR}" + " NCXX4_HINTS_PREFIX = ${NCXX4_HINTS_PREFIX}" + ) +endif() mark_as_advanced(NetCDF_CXX_INCLUDE_DIR) find_library(NetCDF_CXX_LIBRARY @@ -117,6 +155,13 @@ find_library(NetCDF_CXX_LIBRARY PATH_SUFFIXES "lib" "lib64" ) +if (NetCDF_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " NetCDF_CXX_LIBRARY = ${NetCDF_CXX_LIBRARY}" + " NCXX4_HINTS_INCLUDE_DIR = ${NCXX4_HINTS_INCLUDE_DIR}" + " NCXX4_HINTS_PREFIX = ${NCXX4_HINTS_PREFIX}" + ) +endif() mark_as_advanced(NetCDF_CXX_LIBRARY) if (NetCDF_INCLUDE_DIR) From c9c4cc503abbc4c345efc91fba1459ae28d14c69 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 17 Jun 2019 16:55:39 +0100 Subject: [PATCH 1561/1783] Add documentation for necessary CMake flags on Cray machines --- manual/sphinx/user_docs/advanced_install.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/manual/sphinx/user_docs/advanced_install.rst b/manual/sphinx/user_docs/advanced_install.rst index a050fbaace..3bf858386a 100644 --- a/manual/sphinx/user_docs/advanced_install.rst +++ b/manual/sphinx/user_docs/advanced_install.rst @@ -77,6 +77,10 @@ As of 20th April 2018, the following configuration should work $ module load fftw $ module load archer-netcdf/4.1.3 +When using CMake on Cray systems like Archer, you need to pass +``-DCMAKE_SYSTEM_NAME=CrayLinuxEnvironment`` so that the Cray compiler +wrappers are detected properly. + KNL @ Archer ~~~~~~~~~~~~ From afeeade4b1b6b50a5efa2297ca6eafef4f4ff33f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 17 Jun 2019 16:56:40 +0100 Subject: [PATCH 1562/1783] Fix some LaTeX errors --- manual/sphinx/user_docs/coordinates.rst | 17 +++++++++-------- manual/sphinx/user_docs/laplacian.rst | 19 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/manual/sphinx/user_docs/coordinates.rst b/manual/sphinx/user_docs/coordinates.rst index d2a92b3982..23d72863e9 100644 --- a/manual/sphinx/user_docs/coordinates.rst +++ b/manual/sphinx/user_docs/coordinates.rst @@ -1365,10 +1365,10 @@ which can only be true if `\nabla u^i\cdot{\boldsymbol{e}}_j = \delta^i_j` i.e. if -.. raw:: latex +.. math:: - \framebox{Sets of vectors $\ve{e}^i\equiv\nabla u^i$ and $\ve{e}_j$ are - reciprocal} + \text{Sets of vectors $\boldsymbol{e}^i\equiv\nabla u^i$ and + $\boldsymbol{e}_j$ are reciprocal} Since the sets of vectors `\left\{{\boldsymbol{e}}^i\right\}` and @@ -1387,9 +1387,9 @@ metric coefficients `g_{ij} = \mathbf{e_i\cdot e_j}` and orthogonal then `g_{ij}=g^{ij} = 0` for `i\neq j` i.e. the metric is diagonal. -.. raw:: latex +.. math:: - \framebox{$g_{ij} = h_ih_j\hv{e}_i\cdot\hv{e}_j$ and so $g_{ii} = h_i^2$} + \text{$g_{ij} = h_ih_j\boldsymbol{e}_i\cdot\boldsymbol{e}_j$ and so $g_{ii} = h_i^2$} For a general set of coordinates, the nabla operator can be expressed as @@ -1432,17 +1432,18 @@ u^k` in equation :eq:`eq:laplacegen` gives .. math:: :label: eq:general_laplacian - \nabla^2f = \nabla\cdot\nabla f = \nabla\cdot\left(\frac{\partial}{\partial + \begin{aligned} + \nabla^2f &= \nabla\cdot\nabla f = \nabla\cdot\left(\frac{\partial}{\partial x}\nabla x + \frac{\partial}{\partial y}\nabla y + \frac{\partial}{\partial z}\nabla z\right) \nonumber \\ - - = \frac{\partial^2 f}{\partial x^2}\left|\nabla x\right|^2 + \frac{\partial^2 + &= \frac{\partial^2 f}{\partial x^2}\left|\nabla x\right|^2 + \frac{\partial^2 f}{\partial y^2}\left|\nabla y\right|^2 + \frac{\partial^2 f}{\partial z^2}\left|\nabla z\right|^2 \\ +2\frac{\partial^2 f}{\partial x\partial y}\left(\nabla x\cdot\nabla y\right) +2\frac{\partial^2 f}{\partial x\partial z}\left(\nabla x\cdot\nabla z\right) +2\frac{\partial^2 f}{\partial y\partial z}\left(\nabla y\cdot\nabla z\right) \nonumber \\ +\nabla^2x\frac{\partial f}{\partial x} +\nabla^2y\frac{\partial f}{\partial y} + \nabla^2z\frac{\partial f}{\partial z} \nonumber + \end{aligned} Curl defined as: diff --git a/manual/sphinx/user_docs/laplacian.rst b/manual/sphinx/user_docs/laplacian.rst index 7480b3f525..c41a958135 100644 --- a/manual/sphinx/user_docs/laplacian.rst +++ b/manual/sphinx/user_docs/laplacian.rst @@ -556,8 +556,8 @@ introduce some quantities :nowrap: \begin{align} - &A_0 = a(x,y_{\text{current}},z)& &A_1 = dg^{xx}&\\ - &A_2 = dg^{zz}& &A_3 = 2dg^{xz}& + &A_0 = a(x,y_{\text{current}},z) &A_1 = dg^{xx}&\\ + &A_2 = dg^{zz} &A_3 = 2dg^{xz} \end{align} In addition, we have: @@ -566,25 +566,24 @@ Second order approximation (5-point stencil) .. math:: - \texttt{ddx_c} = \frac{\texttt{c2}_{x+1} - \texttt{c2}_{x-1} }{2\texttt{c1}\text{d}x} - - \texttt{ddz_c} = \frac{\texttt{c2}_{z+1} - \texttt{c2}_{z-1} }{2\texttt{c1}\text{d}z} + \texttt{ddx\_c} = \frac{\texttt{c2}_{x+1} - \texttt{c2}_{x-1} }{2\texttt{c1}\text{d}x} \\ + \texttt{ddz\_c} = \frac{\texttt{c2}_{z+1} - \texttt{c2}_{z-1} }{2\texttt{c1}\text{d}z} Fourth order approximation (9-point stencil) .. math:: - \texttt{ddx_c} = \frac{-\texttt{c2}_{x+2} + 8\texttt{c2}_{x+1} - + \texttt{ddx\_c} = \frac{-\texttt{c2}_{x+2} + 8\texttt{c2}_{x+1} - 8\texttt{c2}_{x-1} + \texttt{c2}_{x-1} }{ 12\texttt{c1}\text{d}x} \\ - \texttt{ddz_c} = \frac{-\texttt{c2}_{z+2} + 8\texttt{c2}_{z+1} - + \texttt{ddz\_c} = \frac{-\texttt{c2}_{z+2} + 8\texttt{c2}_{z+1} - 8\texttt{c2}_{z-1} + \texttt{c2}_{z-1} }{ 12\texttt{c1}\text{d}z} This gives .. math:: - A_4 &= dG^x + g^{xx}\texttt{ddx_c} + g^{xz}\texttt{ddz_c} \\ - A_5 &= dG^z + g^{xz}\texttt{ddx_c} + g^{xx}\texttt{ddz_c} + A_4 &= dG^x + g^{xx}\texttt{ddx\_c} + g^{xz}\texttt{ddz\_c} \\ + A_5 &= dG^z + g^{xz}\texttt{ddx\_c} + g^{xx}\texttt{ddz\_c} The coefficients :math:`c_{i+m,j+n}` are finally being set according to the appropriate order of discretisation. The coefficients can be @@ -802,7 +801,7 @@ This scheme was introduced for BOUT++ by Michael Løiten in the `CELMA code his thesis [Løiten2017]_. The iteration can be under-relaxed (see ``naulin_laplace.cxx`` for more details of the -implementation). A factor :math:`0< \text{underrelax_factor}<=1` is used, with a value of 1 corresponding +implementation). A factor :math:`0< \text{underrelax\_factor}<=1` is used, with a value of 1 corresponding to no under-relaxation. If the iteration starts to diverge (the error increases on any step) the underrelax_factor is reduced by a factor of 0.9, and the iteration is restarted from the initial guess. The initial value of underrelax_factor, which underrelax_factor is From 2243c8e0821667e1c038df91758004a8d69fd094 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 17 Jun 2019 17:06:20 +0100 Subject: [PATCH 1563/1783] CMake: Fix for CMake < 3.13: installing targets from subdirectories --- CMakeLists.txt | 2 +- externalpackages/PVODE/CMakeLists.txt | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4496eeef36..12f1c73974 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -575,7 +575,7 @@ endif() # Installation include(GNUInstallDirs) -install(TARGETS bout++ pvode pvpre mpark_variant +install(TARGETS bout++ EXPORT bout++Targets LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" diff --git a/externalpackages/PVODE/CMakeLists.txt b/externalpackages/PVODE/CMakeLists.txt index 9fded327aa..59565c73ad 100644 --- a/externalpackages/PVODE/CMakeLists.txt +++ b/externalpackages/PVODE/CMakeLists.txt @@ -17,10 +17,10 @@ add_library(pvode source/cvode.cpp source/nvector.cpp source/llnlmath.cpp - source/cvspgmr.cpp - source/spgmr.cpp + source/cvspgmr.cpp + source/spgmr.cpp source/iterativ.cpp - source/cvdiag.cpp + source/cvdiag.cpp source/smalldense.cpp include/band.h include/cvdiag.h @@ -42,7 +42,7 @@ target_include_directories(pvode PUBLIC target_link_libraries(pvode PUBLIC MPI::MPI_CXX) add_library(pvpre - precon/pvbbdpre.cpp + precon/pvbbdpre.cpp precon/pvbbdpre.h precon/band.cpp precon/band.h @@ -53,3 +53,12 @@ target_include_directories(pvpre PUBLIC $ ) target_link_libraries(pvpre PUBLIC MPI::MPI_CXX) + +include(GNUInstallDirs) +install(TARGETS pvode pvpre + EXPORT bout++Targets + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + ) From f0de90c5382a86aeb13849af2a8162d5d07530d6 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 18 Jun 2019 09:26:22 +0100 Subject: [PATCH 1564/1783] Ignore UTF8 errors in LaTeX manual build Unfortunately pdflatex support for unicode is poor, and after trying various attempts the solution here is to ignore unicode errors and print "?" instead. https://tex.stackexchange.com/questions/307673/tell-latex-to-ignore-all-unicode-errors Added to preamble in Sphinx conf --- manual/sphinx/conf.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/manual/sphinx/conf.py b/manual/sphinx/conf.py index fc6cfb6088..d763464f78 100755 --- a/manual/sphinx/conf.py +++ b/manual/sphinx/conf.py @@ -210,7 +210,21 @@ def __getattr__(cls, name): # Additional stuff for the LaTeX preamble. # - # 'preamble': '', + 'preamble': r''' +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\makeatletter +\def\UTFviii@defined#1{% + \ifx#1\relax + ?% + \else\expandafter + #1% + \fi +} +\makeatother + + +''', # Latex figure (float) alignment # From b455d42bb3890255dd3a3c7d26be91977f2102ba Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 09:50:07 +0100 Subject: [PATCH 1565/1783] CMake: Fix hints for SUNDIALS: check parent & grandparent dirs --- cmake/FindSUNDIALS.cmake | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cmake/FindSUNDIALS.cmake b/cmake/FindSUNDIALS.cmake index 521f906fe9..b42cd28fea 100644 --- a/cmake/FindSUNDIALS.cmake +++ b/cmake/FindSUNDIALS.cmake @@ -28,7 +28,9 @@ set(SUNDIALS_INCLUDE_DIRS find_library(SUNDIALS_nvecparallel_LIBRARY NAMES sundials_nvecparallel - HINTS "${SUNDIALS_INCLUDE_DIR}/../.." + HINTS + "${SUNDIALS_INCLUDE_DIR}/.." + "${SUNDIALS_INCLUDE_DIR}/../.." PATH_SUFFIXES lib lib64 ) @@ -42,7 +44,9 @@ set(SUNDIALS_COMPONENTS arkode cvode ida) foreach (LIB ${SUNDIALS_COMPONENTS}) find_library(SUNDIALS_${LIB}_LIBRARY NAMES sundials_${LIB} - HINTS "${SUNDIALS_INCLUDE_DIR}/../.." + HINTS + "${SUNDIALS_INCLUDE_DIR}/.." + "${SUNDIALS_INCLUDE_DIR}/../.." PATH_SUFFIXES lib lib64 ) From 1c674231711f80220dcc257416474ef325ffccba Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 09:51:12 +0100 Subject: [PATCH 1566/1783] CMake: Improve FindSUNDIALS docs, add optional debug messages Also: - change name of imported targets to just SUNDIALS:: namespace - set SUNDIALS to be REQUIRED if USE_SUNDIALS --- CMakeLists.txt | 8 +++--- cmake/FindSUNDIALS.cmake | 57 ++++++++++++++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 12f1c73974..86ed3f5c4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -453,15 +453,15 @@ set(BOUT_HAS_SLEPC ${USE_SLEPC}) option(USE_SUNDIALS "Enable support for SUNDIALS time solvers" OFF) if (USE_SUNDIALS) - find_package(SUNDIALS) + find_package(SUNDIALS REQUIRED) target_compile_definitions(bout++ PUBLIC "BOUT_HAS_CVODE" PUBLIC "BOUT_HAS_IDA" PUBLIC "BOUT_HAS_ARKODE" PUBLIC "BOUT_HAS_SUNDIALS") - target_link_libraries(bout++ PUBLIC SUNDIALS_cvode::cvode) - target_link_libraries(bout++ PUBLIC SUNDIALS_ida::ida) - target_link_libraries(bout++ PUBLIC SUNDIALS_arkode::arkode) + target_link_libraries(bout++ PUBLIC SUNDIALS::cvode) + target_link_libraries(bout++ PUBLIC SUNDIALS::ida) + target_link_libraries(bout++ PUBLIC SUNDIALS::arkode) endif() message(STATUS "SUNDIALS support: ${USE_SUNDIALS}") set(BOUT_HAS_SUNDIALS ${USE_SUNDIALS}) diff --git a/cmake/FindSUNDIALS.cmake b/cmake/FindSUNDIALS.cmake index b42cd28fea..425c3c1314 100644 --- a/cmake/FindSUNDIALS.cmake +++ b/cmake/FindSUNDIALS.cmake @@ -1,12 +1,33 @@ +# FindSUNDIALS +# ------------ +# # Find SUNDIALS, the SUite of Nonlinear and DIfferential/ALgebraic equation Solvers # # Currently only actually looks for arkode, cvode and ida, as well as nvecparallel # # This module will define the following variables: -# SUNDIALS_FOUND: true if SUNDIALS was found on the system -# SUNDIALS_INCLUDE_DIRS: Location of the SUNDIALS includes -# SUNDIALS_LIBRARIES: Required libraries -# SUNDIALS_VERSION: Full version string +# +# :: +# +# SUNDIALS_FOUND - true if SUNDIALS was found on the system +# SUNDIALS_INCLUDE_DIRS - Location of the SUNDIALS includes +# SUNDIALS_LIBRARIES - Required libraries +# SUNDIALS_VERSION - Full version string +# +# This module will export the following targets: +# +# ``SUNDIALS::NVecParallel`` +# ``SUNDIALS::arkode`` +# ``SUNDIALS::cvode`` +# ``SUNDIALS::ida`` +# +# You can also set the following variables: +# +# ``SUNDIALS_ROOT`` or ``SUNDIALS_DIR`` (as an environment variable) +# Specify the path to the SUNDIALS installation to use +# +# ``SUNDIALS_DEBUG`` +# Set to TRUE to get extra debugging output include(FindPackageHandleStandardArgs) @@ -16,10 +37,9 @@ find_path(SUNDIALS_INCLUDE_DIR PATH_SUFFIXES include include/sundials DOC "SUNDIALS Directory") -if (SUNDIALS_INCLUDE_DIR) - message(STATUS "Found SUNDIALS include directory: ${SUNDIALS_INCLUDE_DIR}") -else() - message(STATUS "Could not find SUNDIALS include directory") +if (SUNDIALS_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " SUNDIALS_INCLUDE_DIR = ${SUNDIALS_INCLUDE_DIR}") endif() set(SUNDIALS_INCLUDE_DIRS @@ -34,6 +54,11 @@ find_library(SUNDIALS_nvecparallel_LIBRARY PATH_SUFFIXES lib lib64 ) +if (SUNDIALS_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " SUNDIALS_nvecparallel_LIBRARY = ${SUNDIALS_nvecparallel_LIBRARY}") +endif() + if (SUNDIALS_nvecparallel_LIBRARY) list(APPEND SUNDIALS_LIBRARIES "${SUNDIALS_nvecparallel_LIBRARY}") endif() @@ -50,6 +75,11 @@ foreach (LIB ${SUNDIALS_COMPONENTS}) PATH_SUFFIXES lib lib64 ) + if (SUNDIALS_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " SUNDIALS_${LIB}_LIBRARY = ${SUNDIALS_${LIB}_LIBRARY}") + endif() + if (SUNDIALS_${LIB}_LIBRARY) list(APPEND SUNDIALS_LIBRARIES "${SUNDIALS_${LIB}_LIBRARY}") endif() @@ -75,6 +105,11 @@ if (SUNDIALS_INCLUDE_DIR) set(SUNDIALS_VERSION "${SUNDIALS_VERSION_MAJOR}.${SUNDIALS_VERSION_MINOR}.${SUNDIALS_VERSION_PATCH}") endif() +if (SUNDIALS_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " SUNDIALS_VERSION = ${SUNDIALS_VERSION}") +endif() + find_package_handle_standard_args(SUNDIALS REQUIRED_VARS SUNDIALS_LIBRARIES SUNDIALS_INCLUDE_DIR SUNDIALS_INCLUDE_DIRS VERSION_VAR SUNDIALS_VERSION @@ -89,9 +124,9 @@ if (SUNDIALS_FOUND AND NOT TARGET SUNDIALS::SUNDIALS) INTERFACE_INCLUDE_DIRECTORIES "${SUNDIALS_INCLUDE_DIRS}") foreach (LIB ${SUNDIALS_COMPONENTS}) - add_library(SUNDIALS_${LIB}::${LIB} UNKNOWN IMPORTED) - target_link_libraries(SUNDIALS_${LIB}::${LIB} INTERFACE SUNDIALS::NVecParallel) - set_target_properties(SUNDIALS_${LIB}::${LIB} PROPERTIES + add_library(SUNDIALS::${LIB} UNKNOWN IMPORTED) + target_link_libraries(SUNDIALS::${LIB} INTERFACE SUNDIALS::NVecParallel) + set_target_properties(SUNDIALS::${LIB} PROPERTIES IMPORTED_LOCATION "${SUNDIALS_${LIB}_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${SUNDIALS_INCLUDE_DIRS}") endforeach() From bf97676173c2fa8c7047f389e41ab821ad706b00 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 09:53:14 +0100 Subject: [PATCH 1567/1783] Make sure to build SUNDIALS for Travis CMake job Pull out build recipe into standalone script --- .build_sundials_for_travis.sh | 34 ++++++++++++++++++++++++++++++++++ .travis.yml | 1 + .travis_script.sh | 32 ++------------------------------ 3 files changed, 37 insertions(+), 30 deletions(-) create mode 100755 .build_sundials_for_travis.sh diff --git a/.build_sundials_for_travis.sh b/.build_sundials_for_travis.sh new file mode 100755 index 0000000000..bfecfd9db9 --- /dev/null +++ b/.build_sundials_for_travis.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +set -e + +if [[ ! -d $HOME/local/include/sundials ]]; then + echo "****************************************" + echo "Building SUNDIALS" + echo "****************************************" + sundials_ver=4.1.0 + wget https://computation.llnl.gov/projects/sundials/download/sundials-${sundials_ver}.tar.gz + tar xvf sundials-${sundials_ver}.tar.gz + mkdir -p sundials-${sundials_ver}/build && cd sundials-${sundials_ver}/build + cmake -DCMAKE_INSTALL_PREFIX="$HOME/local" \ + -DEXAMPLES_INSTALL=off \ + -DMPI_ENABLE=on \ + -DOPENMP_ENABLE=off \ + -DBUILD_CVODES=off \ + -DBUILD_IDAS=off \ + -DBUILD_KINSOL=off \ + -DBUILD_TESTING=off \ + -DMPI_C_COMPILER="$(command -v mpicc)" \ + -DMPI_CXX_COMPILER="$(command -v mpic++)" \ + -DMPIEXEC_EXECUTABLE="$(command -v mpiexec)" \ + .. + make && make install + cd "${TRAVIS_BUILD_DIR}" + echo "****************************************" + echo "Finished building SUNDIALS" + echo "****************************************" +else + echo "****************************************" + echo "SUNDIALS already installed" + echo "****************************************" +fi diff --git a/.travis.yml b/.travis.yml index 1a0aa362fa..41c6aaf408 100644 --- a/.travis.yml +++ b/.travis.yml @@ -81,6 +81,7 @@ matrix: - *default_env - OMP_NUM_THREADS=2 script: + - ./.build_sundials_for_travis.sh - mkdir build && cd build - cmake .. -DUSE_PETSC=ON -DUSE_SLEPC=ON -DUSE_SUNDIALS=ON -DSUNDIALS_ROOT="$HOME/local" -DENABLE_OPENMP=ON - cmake --build . diff --git a/.travis_script.sh b/.travis_script.sh index 0dc9fce512..4ed3ac39b0 100755 --- a/.travis_script.sh +++ b/.travis_script.sh @@ -45,36 +45,8 @@ do esac done -if [[ ! -d $HOME/local/include/sundials ]]; then - echo "****************************************" - echo "Building SUNDIALS" - echo "****************************************" - sundials_ver=4.1.0 - wget https://computation.llnl.gov/projects/sundials/download/sundials-${sundials_ver}.tar.gz - tar xvf sundials-${sundials_ver}.tar.gz - mkdir -p sundials-${sundials_ver}/build && cd sundials-${sundials_ver}/build - cmake -DCMAKE_INSTALL_PREFIX="$HOME/local" \ - -DEXAMPLES_INSTALL=off \ - -DMPI_ENABLE=on \ - -DOPENMP_ENABLE=off \ - -DBUILD_CVODES=off \ - -DBUILD_IDAS=off \ - -DBUILD_KINSOL=off \ - -DBUILD_TESTING=off \ - -DMPI_C_COMPILER="$(command -v mpicc)" \ - -DMPI_CXX_COMPILER="$(command -v mpic++)" \ - -DMPIEXEC_EXECUTABLE="$(command -v mpiexec)" \ - .. - make && make install - cd "${TRAVIS_BUILD_DIR}" - echo "****************************************" - echo "Finished building SUNDIALS" - echo "****************************************" -else - echo "****************************************" - echo "SUNDIALS already installed" - echo "****************************************" -fi + +./.build_sundials_for_travis.sh export MAKEFLAGS="-j 2 -k" echo "****************************************" From 501d8add585a5c6a3cef474e5e755acd38b4fee9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 10:13:56 +0100 Subject: [PATCH 1568/1783] CMake: Add docs and _DEBUG flag to FindScoreP --- cmake/FindScoreP.cmake | 68 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/cmake/FindScoreP.cmake b/cmake/FindScoreP.cmake index f0345366d5..8bc804b224 100644 --- a/cmake/FindScoreP.cmake +++ b/cmake/FindScoreP.cmake @@ -1,33 +1,75 @@ -find_program(SCOREP_EXECUTABLE scorep) -mark_as_advanced(SCOREP_EXECUTABLE) +# FindScoreP +# ---------- +# +# Find the Score-P profiling tools +# +# This module will define the following variables: +# +# :: +# +# ScoreP_FOUND - true if ScoreP was found +# ScoreP_EXECUTABLE - Path to the ``scorep`` compiler wrapper +# ScoreP_INCLUDE_DIRS - Location of the ScoreP includes +# +# This module will also export the ``ScoreP::ScoreP`` target. +# +# You can also set the following variables: +# +# ``ScoreP_ROOT`` +# Specify the path to the ScoreP installation to use +# +# ``ScoreP_FLAGS`` +# The flags to pass to the ``scorep`` executable as a +# semicolon-separated list. This defaults to ``--user;--nocompiler`` +# +# ``ScoreP_COMPILER_LAUNCHER`` +# The full path to the compiler wrapper plus flags as a +# semicolon-separated list. This defaults to +# ``/path/to/scorep;${ScoreP_FLAGS}`` +# +# ``ScoreP_DEBUG`` +# Set to TRUE to get extra debugging output -if (NOT SCOREP_EXECUTABLE) - message(FATAL_ERROR "Score-P requested but not executable not found. -Please supply the path using -DCMAKE_PROGRAM_PATH=/path/to/scorep/bin/directory") +find_program(ScoreP_EXECUTABLE scorep) +mark_as_advanced(ScoreP_EXECUTABLE) + +get_filename_component(ScoreP_TMP "${ScoreP_EXECUTABLE}" DIRECTORY) +get_filename_component(ScoreP_EXEC_LOCATION "${ScoreP_TMP}" DIRECTORY) + +if (ScoreP_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " ScoreP_EXECUTABLE = ${ScoreP_EXECUTABLE}" + " ScoreP_EXEC_LOCATION = ${ScoreP_EXEC_LOCATION}") endif() -get_filename_component(SCOREP_TMP "${SCOREP_EXECUTABLE}" DIRECTORY) -get_filename_component(SCOREP_EXEC_LOCATION "${SCOREP_TMP}" DIRECTORY) -find_path(ScoreP_INCLUDE_DIR +find_path(ScoreP_INCLUDE_DIRS NAMES scorep/SCOREP_User.h DOC "Score-P include directory" - HINTS "${SCOREP_EXEC_LOCATION}" + HINTS "${ScoreP_EXEC_LOCATION}" PATH_SUFFIXES "include" ) -mark_as_advanced(ScoreP_INCLUDE_DIR) +mark_as_advanced(ScoreP_INCLUDE_DIRS) + +if (ScoreP_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " ScoreP_INCLUDE_DIRS = ${ScoreP_INCLUDE_DIRS}") +endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(ScoreP - REQUIRED_VARS ScoreP_INCLUDE_DIR + REQUIRED_VARS ScoreP_INCLUDE_DIRS ScoreP_EXECUTABLE + FAIL_MESSAGE + "Failed to find ScoreP. Please supply the path to the scorep executable using + -DCMAKE_PROGRAM_PATH=/path/to/scorep/bin/directory" ) if (ScoreP_FOUND AND NOT TARGET ScoreP::ScoreP) set(ScoreP_FLAGS "--user;--nocompiler" CACHE STRING "ScoreP wrapper flags") - set(ScoreP_COMPILER_LAUNCHER "${SCOREP_EXECUTABLE};${ScoreP_FLAGS}" CACHE STRING + set(ScoreP_COMPILER_LAUNCHER "${ScoreP_EXECUTABLE};${ScoreP_FLAGS}" CACHE STRING "ScoreP wrapper and flags") add_library(ScoreP::ScoreP INTERFACE IMPORTED) set_target_properties(ScoreP::ScoreP PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${ScoreP_INCLUDE_DIR}") + INTERFACE_INCLUDE_DIRECTORIES "${ScoreP_INCLUDE_DIRS}") endif() From 1763923b8b733126d51bafc33fd73372dee2fc9e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 13:10:32 +0100 Subject: [PATCH 1569/1783] Move some PVODE headers to be in a more consistent location All PVODE headers are now under `include/pvode`, wherever we're using them, i.e. from both BOUT++ and PVODE itself, both CMake and Autotools --- configure | 2 +- configure.ac | 2 +- externalpackages/PVODE/CMakeLists.txt | 27 ++++++++++--------- .../PVODE/include/{ => pvode}/band.h | 0 .../PVODE/include/{ => pvode}/cvdiag.h | 0 .../PVODE/include/{ => pvode}/cvode.h | 0 .../PVODE/include/{ => pvode}/cvspgmr.h | 0 .../PVODE/include/{ => pvode}/iterativ.h | 0 .../PVODE/include/{ => pvode}/llnlmath.h | 0 .../PVODE/include/{ => pvode}/llnltyps.h | 0 .../PVODE/include/{ => pvode}/nvector.h | 0 .../{precon => include/pvode}/pvbbdpre.h | 0 .../PVODE/include/{ => pvode}/smalldense.h | 0 .../PVODE/include/{ => pvode}/spgmr.h | 0 .../PVODE/include/{ => pvode}/vector.h | 0 externalpackages/PVODE/source/Makefile | 2 +- 16 files changed, 18 insertions(+), 15 deletions(-) rename externalpackages/PVODE/include/{ => pvode}/band.h (100%) rename externalpackages/PVODE/include/{ => pvode}/cvdiag.h (100%) rename externalpackages/PVODE/include/{ => pvode}/cvode.h (100%) rename externalpackages/PVODE/include/{ => pvode}/cvspgmr.h (100%) rename externalpackages/PVODE/include/{ => pvode}/iterativ.h (100%) rename externalpackages/PVODE/include/{ => pvode}/llnlmath.h (100%) rename externalpackages/PVODE/include/{ => pvode}/llnltyps.h (100%) rename externalpackages/PVODE/include/{ => pvode}/nvector.h (100%) rename externalpackages/PVODE/{precon => include/pvode}/pvbbdpre.h (100%) rename externalpackages/PVODE/include/{ => pvode}/smalldense.h (100%) rename externalpackages/PVODE/include/{ => pvode}/spgmr.h (100%) rename externalpackages/PVODE/include/{ => pvode}/vector.h (100%) diff --git a/configure b/configure index 67e5ff5087..d67d2eceee 100755 --- a/configure +++ b/configure @@ -12083,7 +12083,7 @@ fi # Set the correct libraries and copy them to bout as_dir=include/pvode; as_fn_mkdir_p - cp externalpackages/PVODE/precon/pvbbdpre.h externalpackages/PVODE/include/*.h include/pvode + cp -r externalpackages/PVODE/include/pvode include cp externalpackages/PVODE/lib/*.a lib/ EXTRA_LIBS="$EXTRA_LIBS -L\$(BOUT_LIB_PATH) -lpvode -lpvpre" CXXFLAGS="$CXXFLAGS -DBOUT_HAS_PVODE" diff --git a/configure.ac b/configure.ac index 73127108e7..46bd13a54f 100644 --- a/configure.ac +++ b/configure.ac @@ -1140,7 +1140,7 @@ AS_IF([test "$with_pvode" != "no"], [ # Set the correct libraries and copy them to bout AS_MKDIR_P(include/pvode) - cp externalpackages/PVODE/precon/pvbbdpre.h externalpackages/PVODE/include/*.h include/pvode + cp -r externalpackages/PVODE/include/pvode include cp externalpackages/PVODE/lib/*.a lib/ EXTRA_LIBS="$EXTRA_LIBS -L\$(BOUT_LIB_PATH) -lpvode -lpvpre" CXXFLAGS="$CXXFLAGS -DBOUT_HAS_PVODE" diff --git a/externalpackages/PVODE/CMakeLists.txt b/externalpackages/PVODE/CMakeLists.txt index 59565c73ad..47082fcffa 100644 --- a/externalpackages/PVODE/CMakeLists.txt +++ b/externalpackages/PVODE/CMakeLists.txt @@ -22,33 +22,35 @@ add_library(pvode source/iterativ.cpp source/cvdiag.cpp source/smalldense.cpp - include/band.h - include/cvdiag.h - include/cvode.h - include/cvspgmr.h - include/iterativ.h - include/llnlmath.h - include/llnltyps.h - include/nvector.h - include/smalldense.h - include/spgmr.h - include/vector.h + include/pvode/band.h + include/pvode/cvdiag.h + include/pvode/cvode.h + include/pvode/cvspgmr.h + include/pvode/iterativ.h + include/pvode/llnlmath.h + include/pvode/llnltyps.h + include/pvode/nvector.h + include/pvode/smalldense.h + include/pvode/spgmr.h + include/pvode/vector.h ) target_include_directories(pvode PUBLIC + $ $ $ ) target_link_libraries(pvode PUBLIC MPI::MPI_CXX) add_library(pvpre + include/pvode/pvbbdpre.h precon/pvbbdpre.cpp - precon/pvbbdpre.h precon/band.cpp precon/band.h ) target_include_directories(pvpre PUBLIC + $ $ $ ) @@ -62,3 +64,4 @@ install(TARGETS pvode pvpre RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" ) +install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/externalpackages/PVODE/include/band.h b/externalpackages/PVODE/include/pvode/band.h similarity index 100% rename from externalpackages/PVODE/include/band.h rename to externalpackages/PVODE/include/pvode/band.h diff --git a/externalpackages/PVODE/include/cvdiag.h b/externalpackages/PVODE/include/pvode/cvdiag.h similarity index 100% rename from externalpackages/PVODE/include/cvdiag.h rename to externalpackages/PVODE/include/pvode/cvdiag.h diff --git a/externalpackages/PVODE/include/cvode.h b/externalpackages/PVODE/include/pvode/cvode.h similarity index 100% rename from externalpackages/PVODE/include/cvode.h rename to externalpackages/PVODE/include/pvode/cvode.h diff --git a/externalpackages/PVODE/include/cvspgmr.h b/externalpackages/PVODE/include/pvode/cvspgmr.h similarity index 100% rename from externalpackages/PVODE/include/cvspgmr.h rename to externalpackages/PVODE/include/pvode/cvspgmr.h diff --git a/externalpackages/PVODE/include/iterativ.h b/externalpackages/PVODE/include/pvode/iterativ.h similarity index 100% rename from externalpackages/PVODE/include/iterativ.h rename to externalpackages/PVODE/include/pvode/iterativ.h diff --git a/externalpackages/PVODE/include/llnlmath.h b/externalpackages/PVODE/include/pvode/llnlmath.h similarity index 100% rename from externalpackages/PVODE/include/llnlmath.h rename to externalpackages/PVODE/include/pvode/llnlmath.h diff --git a/externalpackages/PVODE/include/llnltyps.h b/externalpackages/PVODE/include/pvode/llnltyps.h similarity index 100% rename from externalpackages/PVODE/include/llnltyps.h rename to externalpackages/PVODE/include/pvode/llnltyps.h diff --git a/externalpackages/PVODE/include/nvector.h b/externalpackages/PVODE/include/pvode/nvector.h similarity index 100% rename from externalpackages/PVODE/include/nvector.h rename to externalpackages/PVODE/include/pvode/nvector.h diff --git a/externalpackages/PVODE/precon/pvbbdpre.h b/externalpackages/PVODE/include/pvode/pvbbdpre.h similarity index 100% rename from externalpackages/PVODE/precon/pvbbdpre.h rename to externalpackages/PVODE/include/pvode/pvbbdpre.h diff --git a/externalpackages/PVODE/include/smalldense.h b/externalpackages/PVODE/include/pvode/smalldense.h similarity index 100% rename from externalpackages/PVODE/include/smalldense.h rename to externalpackages/PVODE/include/pvode/smalldense.h diff --git a/externalpackages/PVODE/include/spgmr.h b/externalpackages/PVODE/include/pvode/spgmr.h similarity index 100% rename from externalpackages/PVODE/include/spgmr.h rename to externalpackages/PVODE/include/pvode/spgmr.h diff --git a/externalpackages/PVODE/include/vector.h b/externalpackages/PVODE/include/pvode/vector.h similarity index 100% rename from externalpackages/PVODE/include/vector.h rename to externalpackages/PVODE/include/pvode/vector.h diff --git a/externalpackages/PVODE/source/Makefile b/externalpackages/PVODE/source/Makefile index 90f680913e..ab6a8cd70f 100644 --- a/externalpackages/PVODE/source/Makefile +++ b/externalpackages/PVODE/source/Makefile @@ -5,7 +5,7 @@ BOUT_TOP = ../../.. -CINCLUDES = -I../include +CINCLUDES = -I../include/pvode FLAGS = $(CXXFLAGS) $(CINCLUDES) # PVODE library file From 01d29c543e04a39671d64f952de2aa38bf967db1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 13:27:16 +0100 Subject: [PATCH 1570/1783] CMake: Rename output debug CMake macro to be more consistent --- CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86ed3f5c4b..fb5dd316d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -310,13 +310,14 @@ target_compile_definitions(bout++ set(BOUT_CHECK_LEVEL ${CHECK}) option(DEBUG_ENABLED "Enable extra debug output" OFF) -if (DEBUG_ENABLED) +option(ENABLE_OUTPUT_DEBUG "Enable extra debug output" OFF) +if (ENABLE_OUTPUT_DEBUG OR DEBUG_ENABLED) target_compile_definitions(bout++ PUBLIC "DEBUG_ENABLED" - PUBLIC "BOUT_DEBUG_ENABLED") + PUBLIC "BOUT_OUTPUT_DEBUG") endif() message(STATUS "Extra debug output: DEBUG_ENABLED=${DEBUG_ENABLED}") -set(BOUT_HAS_OUTPUT_DEBUG ${DEBUG_ENABLED}) +set(BOUT_USE_OUTPUT_DEBUG ${DEBUG_ENABLED}) option(ENABLE_SIGNAL "SegFault handling" ON) if (ENABLE_SIGNAL) @@ -638,7 +639,7 @@ message(" OpenMP support : ${BOUT_USE_OPENMP} Natural language support : ${BOUT_HAS_GETTEXT} ScoreP support : ${BOUT_HAS_SCOREP} - Extra debug output : ${BOUT_HAS_OUTPUT_DEBUG} + Extra debug output : ${BOUT_USE_OUTPUT_DEBUG} CHECK level : ${BOUT_CHECK_LEVEL} Signal handling : ${BOUT_USE_SIGNAL} Output coloring : ${BOUT_USE_COLOR} From fbf94c6d6de1c482fddf0765e4fff9cdb7af5731 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 13:27:43 +0100 Subject: [PATCH 1571/1783] CMake: Install missing Find* modules --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index fb5dd316d0..95fdc0bb92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -610,6 +610,8 @@ install( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindNetCDF.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindPackageMultipass.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindPETSc.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindScoreP.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindSLEPc.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindSUNDIALS.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/ResolveCompilerPaths.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/bout++" From bdf836c8034b7c22a8333ed2d3b7086bedbce5e5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 13:27:57 +0100 Subject: [PATCH 1572/1783] CMake: Only find dependencies installed BOUT++ was built with --- bout++Config.cmake.in | 49 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/bout++Config.cmake.in b/bout++Config.cmake.in index 82d9bcbf1d..a50a356179 100644 --- a/bout++Config.cmake.in +++ b/bout++Config.cmake.in @@ -8,12 +8,16 @@ set(BOUT_USE_TRACK @BOUT_USE_TRACK@) set(BOUT_USE_SIGFPE @BOUT_USE_SIGFPE@) set(BOUT_USE_BACKTRACE @BOUT_USE_BACKTRACE@) set(BOUT_USE_OPENMP @BOUT_USE_OPENMP@) +set(BOUT_HAS_OUTPUT_DEBUG @BOUT_HAS_OUTPUT_DEBUG@) +set(BOUT_CHECK_LEVEL @BOUT_CHECK_LEVEL@) set(BOUT_HAS_PVODE @BOUT_HAS_PVODE@) set(BOUT_HAS_NETCDF @BOUT_HAS_NETCDF@) set(BOUT_HAS_FFTW @BOUT_HAS_FFTW@) set(BOUT_HAS_LAPACK @BOUT_HAS_LAPACK@) set(BOUT_HAS_PETSC @BOUT_HAS_PETSC@) +set(BOUT_HAS_SLEPC @BOUT_HAS_SLEPC@) +set(BOUT_HAS_SCOREP @BOUT_HAS_SCOREP@) set(BOUT_HAS_SUNDIALS @BOUT_HAS_SUNDIALS@) set(BOUT_HAS_GETTEXT @BOUT_HAS_GETTEXT@) @@ -22,6 +26,9 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") if(EXISTS "@PETSC_DIR@") set(PETSC_DIR "@PETSC_DIR@") endif() +if(EXISTS "@SLEPC_DIR@") + set(SLEPC_DIR "@SLEPC_DIR@") +endif() if(EXISTS "@SUNDIALS_ROOT@") set(SUNDIALS_ROOT "@SUNDIALS_ROOT@") endif() @@ -31,19 +38,45 @@ endif() if(EXISTS "@LAPACK_ROOT@") set(LAPACK_ROOT "@LAPACK_ROOT@") endif() +if(EXISTS "@ScoreP_ROOT@") + set(ScoreP_ROOT "@ScoreP_ROOT@") +endif() +if(EXISTS "@NetCDF_ROOT@") + set(NetCDF_ROOT "@NetCDF_ROOT@") +endif() set(mpark_variant_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../lib/cmake/mpark_variant") set(MPIEXEC_EXECUTABLE @MPIEXEC_EXECUTABLE@) find_dependency(MPI @MPI_CXX_VERSION@ EXACT) -find_dependency(OpenMP) -find_dependency(NetCDF @NetCDF_VERSION@ EXACT) -find_dependency(FFTW) -find_dependency(LAPACK) -find_dependency(PETSc @PETSC_VERSION@ EXACT) -find_dependency(SUNDIALS @SUNDIALS_VERSION@ EXACT) -find_dependency(Gettext) -find_dependency(Intl) +if (BOUT_USE_OPENMP) + find_dependency(OpenMP) +endif() +if (BOUT_HAS_NETCDF) + find_dependency(NetCDF @NetCDF_VERSION@ EXACT) +endif() +if (BOUT_HAS_FFTW) + find_dependency(FFTW) +endif() +if (BOUT_HAS_LAPACK) + find_dependency(LAPACK) +endif() +if (BOUT_HAS_PETSC) + find_dependency(PETSc @PETSC_VERSION@ EXACT) +endif() +if (BOUT_HAS_SUNDIALS) + find_dependency(SUNDIALS @SUNDIALS_VERSION@ EXACT) +endif() +if (BOUT_HAS_GETTEXT) + find_dependency(Gettext) + find_dependency(Intl) +endif() find_dependency(mpark_variant) +if (BOUT_HAS_SLEPC) + find_dependency(SLEPc @SLEPC_VERSION@ EXACT) +endif() +if (BOUT_HAS_SCOREP) + find_dependency(ScoreP) +endif() include("${CMAKE_CURRENT_LIST_DIR}/bout++Targets.cmake") From 8b59adde98ddf1cbe06e6066a2baabaa62f504a4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 13:31:15 +0100 Subject: [PATCH 1573/1783] CMake: Add option to disable bundled PVODE support --- CMakeLists.txt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 95fdc0bb92..dedde5b468 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,6 @@ find_package(MPI REQUIRED) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) add_subdirectory(externalpackages/mpark.variant) -add_subdirectory(externalpackages/PVODE) set(BOUT_SOURCES ./include/boundary_factory.hxx @@ -279,7 +278,7 @@ add_library(bout++ ${BOUT_SOURCES} ) add_library(bout++::bout++ ALIAS bout++) -target_link_libraries(bout++ PUBLIC MPI::MPI_CXX pvode pvpre mpark_variant) +target_link_libraries(bout++ PUBLIC MPI::MPI_CXX mpark_variant) target_include_directories(bout++ PUBLIC $ $ @@ -288,7 +287,6 @@ target_include_directories(bout++ PUBLIC target_compile_definitions(bout++ PUBLIC "BOUT_VERSION_STRING=\"4.2.2\"" PUBLIC "BOUT_VERSION_DOUBLE=4.22" - PUBLIC "BOUT_HAS_PVODE" ) set(BOUT_HAS_PVODE TRUE) @@ -394,6 +392,16 @@ set(BOUT_GIT_REVISION ${GIT_SHA1}) # Optional dependencies +option(USE_PVODE "Enable support for bundled PVODE" ON) +if (USE_PVODE) + add_subdirectory(externalpackages/PVODE) + target_link_libraries(bout++ PUBLIC pvode pvpre) + target_compile_definitions(bout++ + PUBLIC "BOUT_HAS_PVODE") +endif() +message(STATUS "PVODE support: ${USE_PVODE}") +set(BOUT_HAS_PVODE ${USE_PVODE}) + option(USE_NETCDF "Enable support for NetCDF output" ON) if (USE_NETCDF) find_package(NetCDF REQUIRED) @@ -632,6 +640,7 @@ message(" BOUT++ Configuration Summary -------------------------------- + Bundled PVODE support : ${BOUT_HAS_PVODE} PETSc support : ${BOUT_HAS_PETSC} SLEPc support : ${BOUT_HAS_SLEPC} SUNDIALS support : ${BOUT_HAS_SUNDIALS} From 812a3a17b23e101952749c81ab430c315b27d165 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 13:37:24 +0100 Subject: [PATCH 1574/1783] CMake: Automagically get git submodules --- CMakeLists.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index dedde5b468..a945f895fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,26 @@ find_package(MPI REQUIRED) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) +# Taken from https://cliutils.gitlab.io/modern-cmake/chapters/projects/submodule.html +find_package(Git QUIET) +if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") + # Update submodules as needed + option(GIT_SUBMODULE "Check submodules during build" ON) + if(GIT_SUBMODULE) + message(STATUS "Submodule update") + execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE GIT_SUBMOD_RESULT) + if(NOT GIT_SUBMOD_RESULT EQUAL "0") + message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules") + endif() + endif() +endif() + +if(NOT EXISTS "${PROJECT_SOURCE_DIR}/externalpackages/mpark.variant/CMakeLists.txt") + message(FATAL_ERROR "The submodules were not downloaded! GIT_SUBMODULE was turned off or failed. Please update submodules and try again.") +endif() + add_subdirectory(externalpackages/mpark.variant) set(BOUT_SOURCES From f0c5c1f41e3dbf153b724d0bcb299f1d922f57cc Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 14:00:18 +0100 Subject: [PATCH 1575/1783] CMake: Make test_functions.cxx, needed for test-initial --- tests/integrated/test-initial/CMakeLists.txt | 10 +++++ .../make_test_functions_include.py | 38 +++++++++++++++++++ tests/integrated/test-initial/makefile | 6 +++ tests/integrated/test-initial/runtest | 18 +++------ 4 files changed, 59 insertions(+), 13 deletions(-) create mode 100755 tests/integrated/test-initial/make_test_functions_include.py diff --git a/tests/integrated/test-initial/CMakeLists.txt b/tests/integrated/test-initial/CMakeLists.txt index 486f07bd18..9d298e3d7b 100644 --- a/tests/integrated/test-initial/CMakeLists.txt +++ b/tests/integrated/test-initial/CMakeLists.txt @@ -1,5 +1,15 @@ bout_add_integrated_test(test_initial SOURCES test_initial.cxx + EXTRA_FILES make_test_functions_include.py USE_RUNTEST USE_DATA_BOUT_INP ) + +execute_process(COMMAND python3 make_test_functions_include.py + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE TEST_INITIAL_MAKE_TEST_FUNCTIONS_RESULT) + +if(NOT TEST_INITIAL_MAKE_TEST_FUNCTIONS_RESULT EQUAL "0") + message(FATAL_ERROR "Unable to make test_functions.cxx needed for test_initial:" + " ${TEST_INITIAL_MAKE_TEST_FUNCTIONS_RESULT}") +endif() diff --git a/tests/integrated/test-initial/make_test_functions_include.py b/tests/integrated/test-initial/make_test_functions_include.py new file mode 100755 index 0000000000..ecfa8d3228 --- /dev/null +++ b/tests/integrated/test-initial/make_test_functions_include.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +import configparser +import itertools +import os + + +def make_test_functions_include(): + """ + Make test_functions.cxx needed for test_initial + """ + datadir = "data" + inputfile = os.path.join(datadir, "BOUT.inp") + + # Read the input file + config = configparser.ConfigParser() + with open(inputfile, "r") as f: + config.read_file(itertools.chain(['[global]'], f), source=inputfile) + + # Find the variables that have a "function" option + varlist = [key for key, values in config.items() if 'function' in values] + + # Remove the coordinate arrays + for coord in ["var_x", "var_y", "var_z"]: + varlist.remove(coord) + + # Make the test case + cxx_snippet = """ + Field3D {name}; + create_and_dump({name}, "{name}"); + """ + + with open("test_functions.cxx", "w") as f: + for var in varlist: + f.write(cxx_snippet.format(name=var)) + + +if __name__ == "__main__": + make_test_functions_include() diff --git a/tests/integrated/test-initial/makefile b/tests/integrated/test-initial/makefile index b314e92006..4647e8a6dd 100644 --- a/tests/integrated/test-initial/makefile +++ b/tests/integrated/test-initial/makefile @@ -3,4 +3,10 @@ BOUT_TOP = ../../.. SOURCEC = test_initial.cxx +test_initial.cxx: + @./make_test_functions_include.py + +clean:: + @-rm -f test_functions.cxx + include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-initial/runtest b/tests/integrated/test-initial/runtest index a37d2238dc..208d22bb1f 100755 --- a/tests/integrated/test-initial/runtest +++ b/tests/integrated/test-initial/runtest @@ -11,6 +11,8 @@ from scipy.special import erf import numpy as np import os +from .make_test_functions_include import make_test_functions_include + #requires not make ######################################## @@ -120,11 +122,13 @@ def min(*args): current = np.minimum(arg, current) return current + def fmod(x, denominator=1.0): """ Modulo operator using fmod convention, (rem in Matlab) """ - return np.fmod(x, denominator) + return np.fmod(x, denominator) + # Rename functions to match BOUT++ naming # Mostly just alternative names to numpy functions @@ -145,7 +149,6 @@ sqrt = np.sqrt tan = np.tan TanhHat = tanhhat pi = np.pi -fmod = np.fmod ######################################## # Running the test @@ -157,7 +160,6 @@ cmd = "./test_initial" datadir = "data" inputfile = os.path.join(datadir, "BOUT.inp") - # Read the input file config = configparser.ConfigParser() with open(inputfile, "r") as f: @@ -170,16 +172,6 @@ varlist = [key for key, values in config.items() if 'function' in values] for coord in ["var_x", "var_y", "var_z"]: varlist.remove(coord) -# Make the test case -cxx_snippet = """ - Field3D {name}; - create_and_dump({name}, "{name}"); -""" - -with open("test_functions.cxx", "w") as f: - for var in varlist: - f.write(cxx_snippet.format(name=var)) - print("Making initial conditions test") shell_safe("make clean") shell_safe("make > make.log") From 66337ffec53759f764667c06f0c532f03bff040c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 14:08:08 +0100 Subject: [PATCH 1576/1783] CMake: Get the libraries/includes for Score-P directly Mostly taken from https://github.com/score-p/scorep_plugin_common/blob/master/FindScorep.cmake However, this is maybe for linking plugins against Score-P? The compiler wrapper certainly does more stuff --- cmake/FindScoreP.cmake | 140 +++++++++++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 26 deletions(-) diff --git a/cmake/FindScoreP.cmake b/cmake/FindScoreP.cmake index 8bc804b224..dd119545e8 100644 --- a/cmake/FindScoreP.cmake +++ b/cmake/FindScoreP.cmake @@ -10,6 +10,8 @@ # ScoreP_FOUND - true if ScoreP was found # ScoreP_EXECUTABLE - Path to the ``scorep`` compiler wrapper # ScoreP_INCLUDE_DIRS - Location of the ScoreP includes +# ScoreP_LIBRARIES - List of libraries need to link against ScoreP +# ScoreP_CXX_FLAGS - Compile definitions # # This module will also export the ``ScoreP::ScoreP`` target. # @@ -29,47 +31,133 @@ # # ``ScoreP_DEBUG`` # Set to TRUE to get extra debugging output +# +# ---------------- +# Part of this module (the bit that parses scorep-config for the libraries) was lifted from +# https://raw.githubusercontent.com/score-p/scorep_plugin_common/master/FindScorep.cmake +# +# Copyright (c) 2016, Technische Universität Dresden, Germany +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are permitted +# provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions +# and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions +# and the following disclaimer in the documentation and/or other materials provided with the +# distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse +# or promote products derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + -find_program(ScoreP_EXECUTABLE scorep) -mark_as_advanced(ScoreP_EXECUTABLE) +find_program(ScoreP_CONFIG scorep-config) +mark_as_advanced(ScoreP_CONFIG) -get_filename_component(ScoreP_TMP "${ScoreP_EXECUTABLE}" DIRECTORY) +get_filename_component(ScoreP_TMP "${ScoreP_CONFIG}" DIRECTORY) get_filename_component(ScoreP_EXEC_LOCATION "${ScoreP_TMP}" DIRECTORY) if (ScoreP_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " ScoreP_EXECUTABLE = ${ScoreP_EXECUTABLE}" + " ScoreP_CONFIG = ${ScoreP_CONFIG}" " ScoreP_EXEC_LOCATION = ${ScoreP_EXEC_LOCATION}") endif() +if(ScoreP_CONFIG) + message(STATUS "SCOREP library found. (using ${ScoreP_CONFIG})") -find_path(ScoreP_INCLUDE_DIRS - NAMES scorep/SCOREP_User.h - DOC "Score-P include directory" - HINTS "${ScoreP_EXEC_LOCATION}" - PATH_SUFFIXES "include" - ) -mark_as_advanced(ScoreP_INCLUDE_DIRS) + execute_process(COMMAND ${ScoreP_CONFIG} "--user" "--nocompiler" "--cppflags" + OUTPUT_VARIABLE ScoreP_CONFIG_FLAGS) + + string(REGEX MATCHALL "-I[^ ]*" ScoreP_CONFIG_INCLUDES "${ScoreP_CONFIG_FLAGS}") + foreach(inc ${ScoreP_CONFIG_INCLUDES}) + string(SUBSTRING ${inc} 2 -1 inc) + list(APPEND ScoreP_INCLUDE_DIRS ${inc}) + endforeach() + + if (ScoreP_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " ScoreP_INCLUDE_DIRS = ${ScoreP_INCLUDE_DIRS}") + endif() + + string(REGEX MATCHALL "(^| +)-[^I][^ ]*" ScoreP_CONFIG_CXXFLAGS "${ScoreP_CONFIG_FLAGS}") + foreach(flag ${ScoreP_CONFIG_CXXFLAGS}) + string(STRIP ${flag} flag) + list(APPEND ScoreP_CXX_FLAGS ${flag}) + endforeach() + + if (ScoreP_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " ScoreP_CXX_FLAGS = ${ScoreP_CXX_FLAGS}") + endif() + + unset(ScoreP_CONFIG_FLAGS) + unset(ScoreP_CONFIG_INCLUDES) + unset(ScoreP_CONFIG_CXXFLAGS) + + execute_process(COMMAND ${ScoreP_CONFIG} "--user" "--nocompiler" "--ldflags" + OUTPUT_VARIABLE _LINK_LD_ARGS) + string( REPLACE " " ";" _LINK_LD_ARGS ${_LINK_LD_ARGS} ) + foreach( _ARG ${_LINK_LD_ARGS} ) + if(${_ARG} MATCHES "^-L") + STRING(REGEX REPLACE "^-L" "" _ARG ${_ARG}) + SET(ScoreP_LINK_DIRS ${ScoreP_LINK_DIRS} ${_ARG}) + endif() + endforeach() + + if (ScoreP_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " ScoreP_LINK_DIRS = ${ScoreP_LINK_DIRS}") + endif() + + execute_process(COMMAND ${ScoreP_CONFIG} "--user" "--nocompiler" "--libs" + OUTPUT_VARIABLE _LINK_LD_ARGS) + string( REPLACE " " ";" _LINK_LD_ARGS ${_LINK_LD_ARGS} ) + foreach( _ARG ${_LINK_LD_ARGS} ) + if(${_ARG} MATCHES "^-l") + string(REGEX REPLACE "^-l" "" _ARG ${_ARG}) + find_library(_SCOREP_LIB_FROM_ARG NAMES ${_ARG} + PATHS + ${ScoreP_LINK_DIRS} + ) + if(_SCOREP_LIB_FROM_ARG) + set(ScoreP_LIBRARIES ${ScoreP_LIBRARIES} ${_SCOREP_LIB_FROM_ARG}) + endif() + unset(_SCOREP_LIB_FROM_ARG CACHE) + endif() + endforeach() + + if (ScoreP_DEBUG) + message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " + " ScoreP_LIBRARIES = ${ScoreP_LIBRARIES}") + endif() -if (ScoreP_DEBUG) - message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " ScoreP_INCLUDE_DIRS = ${ScoreP_INCLUDE_DIRS}") endif() -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(ScoreP - REQUIRED_VARS ScoreP_INCLUDE_DIRS ScoreP_EXECUTABLE - FAIL_MESSAGE - "Failed to find ScoreP. Please supply the path to the scorep executable using - -DCMAKE_PROGRAM_PATH=/path/to/scorep/bin/directory" +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args(ScoreP DEFAULT_MSG + ScoreP_CONFIG + ScoreP_LIBRARIES + ScoreP_INCLUDE_DIRS ) if (ScoreP_FOUND AND NOT TARGET ScoreP::ScoreP) - set(ScoreP_FLAGS "--user;--nocompiler" CACHE STRING "ScoreP wrapper flags") - set(ScoreP_COMPILER_LAUNCHER "${ScoreP_EXECUTABLE};${ScoreP_FLAGS}" CACHE STRING - "ScoreP wrapper and flags") - - add_library(ScoreP::ScoreP INTERFACE IMPORTED) + add_library(ScoreP::ScoreP UNKNOWN IMPORTED) set_target_properties(ScoreP::ScoreP PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${ScoreP_INCLUDE_DIRS}") + INTERFACE_INCLUDE_DIRECTORIES "${ScoreP_INCLUDE_DIRS}" + IMPORTED_LINK_INTERFACE_LIBRARIES "${ScoreP_LIBRARIES}" + INTERFACE_INCLUDE_DEFINITIONS "${ScoreP_CXX_FLAGS}" + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + ) endif() From 9ee898f17efe8c2127316f65572c913f3e33b0b3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 15:58:50 +0100 Subject: [PATCH 1577/1783] CMake: Don't try to be clever with ScoreP: recommend the wrappers This will definitely lead to headaches, but at least it works. It would be better if we could at least set the wrappers ourselves, perhaps via setting CMAKE__COMPILER, but I'm pretty sure that would lead to even more headaches --- CMakeLists.txt | 22 +++++-------------- .../developer_docs/performance_profiling.rst | 16 ++++++++++++++ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a945f895fc..7ff0f10edd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -512,22 +512,12 @@ set(BOUT_HAS_GETTEXT ${GETTEXT_FOUND}) option(USE_SCOREP "Enable support for Score-P based instrumentation" OFF) if (USE_SCOREP) - find_package(ScoreP REQUIRED) - if (ScoreP_FOUND) - target_link_libraries(bout++ - PUBLIC ScoreP::ScoreP) - target_compile_definitions(bout++ - PUBLIC "BOUT_HAS_SCOREP") - - if (NOT DEFINED CMAKE_CXX_COMPILER_LAUNCHER) - set_target_properties(bout++ PROPERTIES - CXX_COMPILER_LAUNCHER "${ScoreP_COMPILER_LAUNCHER}") - else() - if (NOT "${CMAKE_CXX_COMPILER_LAUNCHER}" STREQUAL "${ScoreP_COMPILER_LAUNCHER}") - message(FATAL_ERROR "Score-P conflicts with an existing compiler wrapper: ${CMAKE_CXX_COMPILER_LAUNCHER}") - endif() - endif() - endif() + target_compile_definitions(bout++ + PUBLIC "BOUT_HAS_SCOREP") + message(STATUS "Score-P support enabled. Please make sure you are calling CMake like so: + + SCOREP_WRAPPER=off cmake -DCMAKE_C_COMPILER=scorep-mpicc -DCMAKE_CXX_COMPILER=scorep-mpicxx +") endif() set(BOUT_HAS_SCOREP ${USE_SCOREP}) diff --git a/manual/sphinx/developer_docs/performance_profiling.rst b/manual/sphinx/developer_docs/performance_profiling.rst index d052bf5ca6..c6a6650e82 100644 --- a/manual/sphinx/developer_docs/performance_profiling.rst +++ b/manual/sphinx/developer_docs/performance_profiling.rst @@ -65,6 +65,22 @@ desirable to profile the optimized code, configuring with the flags ``--enable-optimize=3 --enable-checks=0``. Build the code with ``make`` as normal. +With CMake: + +.. code-block:: bash + + $ SCOREP_WRAPPER=off cmake \ + -DCMAKE_C_COMPILER=scorep-mpicc \ + -DCMAKE_CXX_COMPILER=scorep-mpicxx \ + + +This will turn off the instrumentation during the configure +step. Please be aware that if you change ``CMakeLists.txt``, CMake +will try to automatically reconfigure the build, which the Score-P +wrappers interfere with. In this case you will need to restart the +configure step from scratch (i.e. remove the build directory and start +again). + Run and analysis ~~~~~~~~~~~~~~~~ From 22d631860c27c7e86f07b2e2e0b73fea01c72189 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 16:05:56 +0100 Subject: [PATCH 1578/1783] CMake: Add support for `_ROOT` variables for cmake<3.12 --- cmake/FindFFTW.cmake | 7 +++++++ cmake/FindNetCDF.cmake | 19 ++++++++++++++++++- cmake/FindSUNDIALS.cmake | 7 +++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/cmake/FindFFTW.cmake b/cmake/FindFFTW.cmake index 271e61c79e..bf83ffd564 100644 --- a/cmake/FindFFTW.cmake +++ b/cmake/FindFFTW.cmake @@ -29,6 +29,13 @@ if (FFTW_INCLUDE_DIRS) set (FFTW_FIND_QUIETLY TRUE) endif (FFTW_INCLUDE_DIRS) +find_program(FFTW_WISDOM "fftw-wisdom" + PATHS "${FFTW_ROOT}" + PATH_SUFFIXES bin + NO_DEFAULT_PATH + DOC "Path to fftw-wisdom executable" + ) + find_program(FFTW_WISDOM "fftw-wisdom" DOC "Path to fftw-wisdom executable" ) diff --git a/cmake/FindNetCDF.cmake b/cmake/FindNetCDF.cmake index 4f7529105d..81e75e667f 100644 --- a/cmake/FindNetCDF.cmake +++ b/cmake/FindNetCDF.cmake @@ -62,18 +62,35 @@ function(inspect_netcdf_config VAR NX_CONFIG ARG) endfunction() find_program(NC_CONFIG "nc-config" + PATHS "${NetCDF_ROOT}" + PATH_SUFFIXES bin DOC "Path to NetCDF C config helper" + NO_DEFAULT_PATH ) + +find_program(NC_CONFIG "nc-config" + DOC "Path to NetCDF C config helper" + ) + get_filename_component(NC_CONFIG_TMP "${NC_CONFIG}" DIRECTORY) get_filename_component(NC_CONFIG_LOCATION "${NC_CONFIG_TMP}" DIRECTORY) if (NetCDF_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " NC_CONFIG_LOCATION = ${NC_CONFIG_LOCATION}") + " NC_CONFIG_LOCATION = ${NC_CONFIG_LOCATION}" + " NetCDF_ROOT = ${NetCDF_ROOT}") endif() find_program(NCXX4_CONFIG "ncxx4-config" + PATHS "${NetCDF_ROOT}" + PATH_SUFFIXES bin DOC "Path to NetCDF C++ config helper" + NO_DEFAULT_PATH ) + +find_program(NCXX4_CONFIG "ncxx4-config" + DOC "Path to NetCDF C++ config helper" + ) + get_filename_component(NCXX4_CONFIG_TMP "${NCXX4_CONFIG}" DIRECTORY) get_filename_component(NCXX4_CONFIG_LOCATION "${NCXX4_CONFIG_TMP}" DIRECTORY) if (NetCDF_DEBUG) diff --git a/cmake/FindSUNDIALS.cmake b/cmake/FindSUNDIALS.cmake index 425c3c1314..a889072255 100644 --- a/cmake/FindSUNDIALS.cmake +++ b/cmake/FindSUNDIALS.cmake @@ -33,13 +33,16 @@ include(FindPackageHandleStandardArgs) find_path(SUNDIALS_INCLUDE_DIR sundials_config.h - HINTS ENV SUNDIALS_DIR + HINTS + "${SUNDIALS_ROOT}" + ENV SUNDIALS_DIR PATH_SUFFIXES include include/sundials DOC "SUNDIALS Directory") if (SUNDIALS_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " - " SUNDIALS_INCLUDE_DIR = ${SUNDIALS_INCLUDE_DIR}") + " SUNDIALS_INCLUDE_DIR = ${SUNDIALS_INCLUDE_DIR}" + " SUNDIALS_ROOT = ${SUNDIALS_ROOT}") endif() set(SUNDIALS_INCLUDE_DIRS From 2abeb7a8917756792c1b0f0030017bb25edb7357 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 16:07:44 +0100 Subject: [PATCH 1579/1783] CMake: Ensure MPI is found for PETSc --- cmake/FindPETSc.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/FindPETSc.cmake b/cmake/FindPETSc.cmake index b912d29b7d..34e1d4ce3e 100644 --- a/cmake/FindPETSc.cmake +++ b/cmake/FindPETSc.cmake @@ -25,6 +25,8 @@ cmake_policy(VERSION 3.3) +find_package(MPI REQUIRED) + set(PETSC_VALID_COMPONENTS C CXX) From 028731ddbcda0210f7a17db197c38ab433b94668 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 16:08:03 +0100 Subject: [PATCH 1580/1783] CMake: Fix SUNDIALS linking for CMake < 3.13 --- cmake/FindSUNDIALS.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/FindSUNDIALS.cmake b/cmake/FindSUNDIALS.cmake index a889072255..8d0956136c 100644 --- a/cmake/FindSUNDIALS.cmake +++ b/cmake/FindSUNDIALS.cmake @@ -128,9 +128,9 @@ if (SUNDIALS_FOUND AND NOT TARGET SUNDIALS::SUNDIALS) foreach (LIB ${SUNDIALS_COMPONENTS}) add_library(SUNDIALS::${LIB} UNKNOWN IMPORTED) - target_link_libraries(SUNDIALS::${LIB} INTERFACE SUNDIALS::NVecParallel) set_target_properties(SUNDIALS::${LIB} PROPERTIES IMPORTED_LOCATION "${SUNDIALS_${LIB}_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${SUNDIALS_INCLUDE_DIRS}") + INTERFACE_INCLUDE_DIRECTORIES "${SUNDIALS_INCLUDE_DIRS}" + INTERFACE_DEPENDENT_LIBRARIES SUNDIALS::NVecParallel) endforeach() endif() From ad8a6e95408351eefc3319f8dc58329eb4bed005 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 16:08:55 +0100 Subject: [PATCH 1581/1783] CMake: Fix specifying wrong policy for versions < 3.12 --- CMakeLists.txt | 2 +- externalpackages/PVODE/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ff0f10edd..9a429c99d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.1...3.12) -if(${CMAKE_VERSION} VERSION_LESS 3.11) +if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) else() cmake_policy(VERSION 3.12) diff --git a/externalpackages/PVODE/CMakeLists.txt b/externalpackages/PVODE/CMakeLists.txt index 47082fcffa..515c0da717 100644 --- a/externalpackages/PVODE/CMakeLists.txt +++ b/externalpackages/PVODE/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.1...3.12) -if(${CMAKE_VERSION} VERSION_LESS 3.11) +if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) else() cmake_policy(VERSION 3.12) From 8b715a7731a4ab8c00f02d7108311d714686d023 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 16:09:22 +0100 Subject: [PATCH 1582/1783] CMake: Increase minimum required version to 3.9 --- CMakeLists.txt | 2 +- externalpackages/PVODE/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a429c99d4..e076902fba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1...3.12) +cmake_minimum_required(VERSION 3.9...3.12) if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) diff --git a/externalpackages/PVODE/CMakeLists.txt b/externalpackages/PVODE/CMakeLists.txt index 515c0da717..8e1bdfb90c 100644 --- a/externalpackages/PVODE/CMakeLists.txt +++ b/externalpackages/PVODE/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1...3.12) +cmake_minimum_required(VERSION 3.9..3.12) if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) From d0e3c1eed8e6631ad0c1f5886c98d28e2686ea7e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 16:42:16 +0100 Subject: [PATCH 1583/1783] Add docs for basic use of CMake --- manual/sphinx/user_docs/installing.rst | 70 ++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/manual/sphinx/user_docs/installing.rst b/manual/sphinx/user_docs/installing.rst index 2dc88775b9..d95a6e05cc 100644 --- a/manual/sphinx/user_docs/installing.rst +++ b/manual/sphinx/user_docs/installing.rst @@ -274,6 +274,76 @@ configuration:: If not, see :ref:`sec-advancedinstall` for some things you can try to resolve common problems. +.. _sec-cmake: + +CMake +----- + +There is now (experimental) support for `CMake `_. You will need CMake > +3.9. CMake supports out-of-source builds by default, which are A Good +Idea. Basic configuration with CMake looks like:: + + $ mkdir build && cd build + $ cmake .. + +You can then run ``make`` as usual. + +You can see what build options are available with:: + + $ cmake .. -LH + ... + // Enable backtrace + ENABLE_BACKTRACE:BOOL=ON + + // Output coloring + ENABLE_COLOR:BOOL=ON + + // Enable OpenMP support + ENABLE_OPENMP:BOOL=OFF + + // Enable support for PETSc time solvers and inversions + USE_PETSC:BOOL=OFF + ... + +CMake uses the ``-D=`` syntax to control these +variables. You can set ``_ROOT`` to guide CMake in finding +the various optional third-party packages (except for PETSc/SLEPc, +which use ``_DIR``). CMake understands the usual environment variables +for setting the compiler, compiler/linking flags, as well as having +built-in options to control them and things like static vs shared +libraries, etc. See the `CMake documentation +`_ for more infomation. + +A more complicated CMake configuration command +might look like:: + + $ CC=mpicc CXX=mpic++ cmake .. \ + -DUSE_PETSC=ON -DPETSC_DIR=/path/to/petsc/ \ + -DUSE_SLEPC=ON -DSLEPC_DIR=/path/to/slepc/ \ + -DUSE_SUNDIALS=ON -DSUNDIALS_ROOT=/path/to/sundials \ + -DUSE_NETCDF=ON -DNetCDF_ROOT=/path/to/netcdf \ + -DENABLE_OPENMP=ON \ + -DENABLE_SIGFPE=OFF \ + -DCMAKE_BUILD_TYPE=Debug \ + -DBUILD_SHARED_LIBS=ON + -DCMAKE_INSTALL_PREFIX=/path/to/install/BOUT++ + +You can write a CMake configuration file (``CMakeLists.txt``) for your +physics model in only four lines: + +.. code-block:: cmake + + project(blob2d LANGUAGES CXX) + find_package(bout++ REQUIRED) + add_executable(blob2d blob2d.cxx) + target_link_libraries(blob2d PRIVATE bout++::bout++) + +You just need to give CMake the location where you installed BOUT++ +via the ``CMAKE_PREFIX_PATH`` variable:: + + $ mkdir build && cd build + $ cmake .. -DCMAKE_PREFIX_PATH=/path/to/install/BOUT++ + .. _sec-config-nls: Natural Language Support From 28b6864b8b5d7558ed683d32143672507e183dc3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 17:05:04 +0100 Subject: [PATCH 1584/1783] CMake: Fix wrong variable in linking SUNDIALS libraries --- cmake/FindSUNDIALS.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindSUNDIALS.cmake b/cmake/FindSUNDIALS.cmake index 8d0956136c..2896e9b0be 100644 --- a/cmake/FindSUNDIALS.cmake +++ b/cmake/FindSUNDIALS.cmake @@ -131,6 +131,6 @@ if (SUNDIALS_FOUND AND NOT TARGET SUNDIALS::SUNDIALS) set_target_properties(SUNDIALS::${LIB} PROPERTIES IMPORTED_LOCATION "${SUNDIALS_${LIB}_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${SUNDIALS_INCLUDE_DIRS}" - INTERFACE_DEPENDENT_LIBRARIES SUNDIALS::NVecParallel) + INTERFACE_LINK_LIBRARIES SUNDIALS::NVecParallel) endforeach() endif() From 5aacf83d647e56cca38f6e8241662fe4fc096e0d Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 17:20:22 +0100 Subject: [PATCH 1585/1783] Fix libpvpre build with configure after headers were moved --- configure | 2 +- configure.ac | 2 +- externalpackages/PVODE/precon/Makefile | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure b/configure index d67d2eceee..daebd1c0f6 100755 --- a/configure +++ b/configure @@ -12062,7 +12062,7 @@ $as_echo "$as_me: Building PVODE" >&6;} CXX="$MPICXX" CXXFLAGS=$PVODE_FLAGS MKDIR="$MKDIR_P" RANLIB="$RANLIB" $MAKE -C externalpackages/PVODE/precon/ >> config-build.log 2>&1 CXX="$MPICXX" CXXFLAGS=$PVODE_FLAGS MKDIR="$MKDIR_P" RANLIB="$RANLIB" $MAKE -C externalpackages/PVODE/source/ >> config-build.log 2>&1 - if test -f externalpackages/PVODE/lib/libpvode.a ; then : + if test -f externalpackages/PVODE/lib/libpvode.a && test -f externalpackages/PVODE/lib/libpvpre.a; then : { $as_echo "$as_me:${as_lineno-$LINENO}: Successfully built PVODE" >&5 $as_echo "$as_me: Successfully built PVODE" >&6;} diff --git a/configure.ac b/configure.ac index 46bd13a54f..f735f67880 100644 --- a/configure.ac +++ b/configure.ac @@ -1125,7 +1125,7 @@ AS_IF([test "$with_pvode" != "no"], [ CXX="$MPICXX" CXXFLAGS=$PVODE_FLAGS MKDIR="$MKDIR_P" RANLIB="$RANLIB" $MAKE -C externalpackages/PVODE/precon/ >> config-build.log 2>&1 CXX="$MPICXX" CXXFLAGS=$PVODE_FLAGS MKDIR="$MKDIR_P" RANLIB="$RANLIB" $MAKE -C externalpackages/PVODE/source/ >> config-build.log 2>&1 - AS_IF([test -f externalpackages/PVODE/lib/libpvode.a ], [ + AS_IF([test -f externalpackages/PVODE/lib/libpvode.a && test -f externalpackages/PVODE/lib/libpvpre.a], [ AC_MSG_NOTICE([Successfully built PVODE]) AC_MSG_NOTICE([Installing PVODE into BOUT++ sourcetree]) diff --git a/externalpackages/PVODE/precon/Makefile b/externalpackages/PVODE/precon/Makefile index 9a61dd9c98..a84af6776c 100644 --- a/externalpackages/PVODE/precon/Makefile +++ b/externalpackages/PVODE/precon/Makefile @@ -5,7 +5,7 @@ BOUT_TOP = ../../.. -CINCLUDES = -I../include +CINCLUDES = -I../include/pvode FLAGS = $(CXXFLAGS) $(CINCLUDES) # PVODE library file @@ -29,7 +29,7 @@ $(LIBF): $(OBJS) obj: $(MKDIR) obj -obj/%.o: obj %.cpp %.h +obj/%.o: obj %.cpp $(CXX) $(FLAGS) -c -o $@ $*.cpp clean:: From cfaaea0079b2f242eb574564b5159e9ab5825523 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 18 Jun 2019 17:41:26 +0100 Subject: [PATCH 1586/1783] Travis: Fix missing PYTHONPATH for CMake job --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 41c6aaf408..92cf425c3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -80,6 +80,7 @@ matrix: - env: - *default_env - OMP_NUM_THREADS=2 + - PYTHONPATH="${TRAVIS_BUILD_DIR}/tools/pylib:$PYTHONPATH" script: - ./.build_sundials_for_travis.sh - mkdir build && cd build From 960bbb6fdb8567b3bb4a2c0773eacd123468c6b5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 19 Jun 2019 11:26:14 +0100 Subject: [PATCH 1587/1783] Fix test-initial: ensure binary is default target; remove bad import --- tests/integrated/test-initial/makefile | 4 ++-- tests/integrated/test-initial/runtest | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/integrated/test-initial/makefile b/tests/integrated/test-initial/makefile index 4647e8a6dd..a0bbe6445d 100644 --- a/tests/integrated/test-initial/makefile +++ b/tests/integrated/test-initial/makefile @@ -3,10 +3,10 @@ BOUT_TOP = ../../.. SOURCEC = test_initial.cxx +include $(BOUT_TOP)/make.config + test_initial.cxx: @./make_test_functions_include.py clean:: @-rm -f test_functions.cxx - -include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-initial/runtest b/tests/integrated/test-initial/runtest index 208d22bb1f..47256944b3 100755 --- a/tests/integrated/test-initial/runtest +++ b/tests/integrated/test-initial/runtest @@ -11,8 +11,6 @@ from scipy.special import erf import numpy as np import os -from .make_test_functions_include import make_test_functions_include - #requires not make ######################################## From 759a4bcd87183d821ffac3799a7679f911f64ae0 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 19 Jun 2019 13:46:09 +0100 Subject: [PATCH 1588/1783] Rename test-io_hdf5 source file/binary to avoid clash with test-io --- tests/integrated/.gitignore | 1 + tests/integrated/test-io_hdf5/makefile | 2 +- tests/integrated/test-io_hdf5/runtest | 2 +- tests/integrated/test-io_hdf5/{test_io.cxx => test_io_hdf5.cxx} | 0 4 files changed, 3 insertions(+), 2 deletions(-) rename tests/integrated/test-io_hdf5/{test_io.cxx => test_io_hdf5.cxx} (100%) diff --git a/tests/integrated/.gitignore b/tests/integrated/.gitignore index 83c02288ce..0e28280d36 100644 --- a/tests/integrated/.gitignore +++ b/tests/integrated/.gitignore @@ -13,6 +13,7 @@ BOUT.settings /test-interchange-instability/2fluid /test-invpar/test_invpar /test-io/test_io +/test-io_hdf5/test_io_hdf5 /test-laplace/test_laplace /test-restarting/test_restarting /test-smooth/test_smooth diff --git a/tests/integrated/test-io_hdf5/makefile b/tests/integrated/test-io_hdf5/makefile index 03d4d19d78..0e55654a3a 100644 --- a/tests/integrated/test-io_hdf5/makefile +++ b/tests/integrated/test-io_hdf5/makefile @@ -1,6 +1,6 @@ BOUT_TOP = ../../.. -SOURCEC = test_io.cxx +SOURCEC = test_io_hdf5.cxx include $(BOUT_TOP)/make.config diff --git a/tests/integrated/test-io_hdf5/runtest b/tests/integrated/test-io_hdf5/runtest index c7fe2aa11d..26fc190687 100755 --- a/tests/integrated/test-io_hdf5/runtest +++ b/tests/integrated/test-io_hdf5/runtest @@ -35,7 +35,7 @@ for v in vars: print("Running I/O test") success = True for nproc in [1,2,4]: - cmd = "./test_io" + cmd = "./test_io_hdf5" # On some machines need to delete dmp files first # or data isn't written correctly diff --git a/tests/integrated/test-io_hdf5/test_io.cxx b/tests/integrated/test-io_hdf5/test_io_hdf5.cxx similarity index 100% rename from tests/integrated/test-io_hdf5/test_io.cxx rename to tests/integrated/test-io_hdf5/test_io_hdf5.cxx From 638a92698faa7076f8aa80719960eaf79ebf915b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 19 Jun 2019 13:53:30 +0100 Subject: [PATCH 1589/1783] CMake: Add HDF5 support and test --- CMakeLists.txt | 13 +++++++++++++ tests/integrated/CMakeLists.txt | 1 + tests/integrated/test-io_hdf5/CMakeLists.txt | 7 +++++++ 3 files changed, 21 insertions(+) create mode 100644 tests/integrated/test-io_hdf5/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index e076902fba..3a5a2b939d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -433,6 +433,18 @@ endif() message(STATUS "NetCDF support: ${USE_NETCDF}") set(BOUT_HAS_NETCDF ${USE_NETCDF}) +option(USE_HDF5 "Enable support for HDF5 output" ON) +if (USE_HDF5) + find_package(HDF5 REQUIRED COMPONENTS CXX) + target_compile_definitions(bout++ + PUBLIC "HDF5" + PUBLIC "BOUT_HAS_HDF5") + target_link_libraries(bout++ PUBLIC "${HDF5_CXX_LIBRARIES}") + target_include_directories(bout++ PUBLIC "${HDF5_CXX_INCLUDE_DIRS}") +endif() +message(STATUS "HDF5 support: ${USE_HDF5}") +set(BOUT_HAS_HDF5 ${USE_HDF5}) + option(USE_FFTW "Enable support for FFTW" ON) if (USE_FFTW) find_package(FFTW REQUIRED) @@ -655,6 +667,7 @@ message(" SLEPc support : ${BOUT_HAS_SLEPC} SUNDIALS support : ${BOUT_HAS_SUNDIALS} NetCDF support : ${BOUT_HAS_NETCDF} + HDF5 support : ${BOUT_HAS_HDF5} FFTW support : ${BOUT_HAS_FFTW} LAPACK support : ${BOUT_HAS_LAPACK} OpenMP support : ${BOUT_USE_OPENMP} diff --git a/tests/integrated/CMakeLists.txt b/tests/integrated/CMakeLists.txt index 703225efaf..439995f73b 100644 --- a/tests/integrated/CMakeLists.txt +++ b/tests/integrated/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(test-griddata) add_subdirectory(test-initial) add_subdirectory(test-invertable-operator) add_subdirectory(test-io) +add_subdirectory(test-io_hdf5) add_subdirectory(test-laplace) add_subdirectory(test-slepc-solver) add_subdirectory(test-solver) diff --git a/tests/integrated/test-io_hdf5/CMakeLists.txt b/tests/integrated/test-io_hdf5/CMakeLists.txt new file mode 100644 index 0000000000..84f3c07531 --- /dev/null +++ b/tests/integrated/test-io_hdf5/CMakeLists.txt @@ -0,0 +1,7 @@ +bout_add_integrated_test(test_io_hdf5 + SOURCES test_io_hdf5.cxx + USE_RUNTEST + USE_DATA_BOUT_INP + EXTRA_FILES test_io.grd.hdf5 data/benchmark.out.0.hdf5 + REQUIRES HDF5 +) From 270c5a377021463934ebfa625ef73eeaf73d170a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 19 Jun 2019 13:59:32 +0100 Subject: [PATCH 1590/1783] Fix test-io_hdf5 for signalling NaNs Comparison in H5Format::write to avoid out-of-range problems causes FPEs if they are enabled --- tests/integrated/test-io_hdf5/data/BOUT.inp | 3 --- tests/integrated/test-io_hdf5/runtest | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/integrated/test-io_hdf5/data/BOUT.inp b/tests/integrated/test-io_hdf5/data/BOUT.inp index e8f280491b..0985e6bde4 100644 --- a/tests/integrated/test-io_hdf5/data/BOUT.inp +++ b/tests/integrated/test-io_hdf5/data/BOUT.inp @@ -11,6 +11,3 @@ MZ = 4 # Z size grid = "test_io.grd.hdf5" dump_format = "hdf5" # HDF5 format. Alternative is "pdb" or "nc" - -[output] -floats=true diff --git a/tests/integrated/test-io_hdf5/runtest b/tests/integrated/test-io_hdf5/runtest index 26fc190687..0457c75bdc 100755 --- a/tests/integrated/test-io_hdf5/runtest +++ b/tests/integrated/test-io_hdf5/runtest @@ -25,7 +25,7 @@ vars = ['ivar', 'rvar', 'f2d', 'f3d', 'fperp', 'fperp2', 'ivar_evol', 'rvar_evol field_vars = ['f2d', 'f3d', 'fperp', 'fperp2', 'v2d_evol_x', 'v2d_evol_y', 'v2d_evol_z', 'fperp2_evol'] # Field quantities, not scalars -tol = 1e-10 +tol = 1e-6 print("Reading benchmark data") bmk = {} From 06478bfeb034e3e3aae4034335de4a3f6d3b1df5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 19 Jun 2019 14:10:42 +0100 Subject: [PATCH 1591/1783] CMake: Generalise REQUIRES for test macro to any variable --- CMakeLists.txt | 13 +++++++++++-- .../test-invertable-operator/CMakeLists.txt | 2 +- tests/integrated/test-io/CMakeLists.txt | 2 +- tests/integrated/test-io_hdf5/CMakeLists.txt | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a5a2b939d..9df6307996 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -555,20 +555,29 @@ endmacro() # Add a new integrated test # # Required arguments: +# # - TESTNAME: name of the test +# # - SOURCES: list of source files +# # Optional arguments: +# # - USE_RUNTEST: if given, the test uses `./runtest` as the test # command, otherwise it uses the executable +# # - USE_DATA_BOUT_INP: if given, copy `data/BOUT.inp` -# - REQUIRES: list of required dependencies +# +# - EXTRA_FILES: any extra files that are required to run the test +# +# - REQUIRES: list of variables that must be truthy to enable test + function(bout_add_integrated_test TESTNAME) set(options USE_RUNTEST USE_DATA_BOUT_INP) set(multiValueArgs SOURCES EXTRA_FILES REQUIRES) cmake_parse_arguments(BOUT_TEST_OPTIONS "${options}" "" "${multiValueArgs}" ${ARGN}) foreach (REQUIREMENT "${BOUT_TEST_OPTIONS_REQUIRES}") - if (REQUIREMENT AND NOT BOUT_HAS_${REQUIREMENT}) + if (REQUIREMENT AND NOT ${REQUIREMENT}) message(STATUS "Not building test ${TESTNAME}, requirement not met: ${REQUIREMENT}") return() endif() diff --git a/tests/integrated/test-invertable-operator/CMakeLists.txt b/tests/integrated/test-invertable-operator/CMakeLists.txt index 11d7a112dc..2275005dfc 100644 --- a/tests/integrated/test-invertable-operator/CMakeLists.txt +++ b/tests/integrated/test-invertable-operator/CMakeLists.txt @@ -2,5 +2,5 @@ bout_add_integrated_test(invertable_operator SOURCES invertable_operator.cxx USE_RUNTEST USE_DATA_BOUT_INP - REQUIRES PETSC + REQUIRES BOUT_HAS_PETSC ) diff --git a/tests/integrated/test-io/CMakeLists.txt b/tests/integrated/test-io/CMakeLists.txt index 6f4dc5297a..b218c85fa4 100644 --- a/tests/integrated/test-io/CMakeLists.txt +++ b/tests/integrated/test-io/CMakeLists.txt @@ -3,5 +3,5 @@ bout_add_integrated_test(test_io USE_RUNTEST USE_DATA_BOUT_INP EXTRA_FILES test_io.grd.nc data/benchmark.out.0.nc - REQUIRES NETCDF + REQUIRES BOUT_HAS_NETCDF ) diff --git a/tests/integrated/test-io_hdf5/CMakeLists.txt b/tests/integrated/test-io_hdf5/CMakeLists.txt index 84f3c07531..cc08b46e2c 100644 --- a/tests/integrated/test-io_hdf5/CMakeLists.txt +++ b/tests/integrated/test-io_hdf5/CMakeLists.txt @@ -3,5 +3,5 @@ bout_add_integrated_test(test_io_hdf5 USE_RUNTEST USE_DATA_BOUT_INP EXTRA_FILES test_io.grd.hdf5 data/benchmark.out.0.hdf5 - REQUIRES HDF5 + REQUIRES BOUT_HAS_HDF5 ) From c82dfd9bd2b92bb171cf24f19066e75ebc885f36 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 19 Jun 2019 16:31:18 +0100 Subject: [PATCH 1592/1783] CMake: Add a few more integrated tests --- tests/integrated/CMakeLists.txt | 4 ++++ tests/integrated/test-command-args/CMakeLists.txt | 5 +++++ .../test-coordinates-initialization/CMakeLists.txt | 5 +++++ tests/integrated/test-cyclic/CMakeLists.txt | 6 ++++++ tests/integrated/test-delp2/CMakeLists.txt | 5 +++++ tests/integrated/test-initial/CMakeLists.txt | 10 ---------- 6 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 tests/integrated/test-command-args/CMakeLists.txt create mode 100644 tests/integrated/test-coordinates-initialization/CMakeLists.txt create mode 100644 tests/integrated/test-cyclic/CMakeLists.txt create mode 100644 tests/integrated/test-delp2/CMakeLists.txt diff --git a/tests/integrated/CMakeLists.txt b/tests/integrated/CMakeLists.txt index 439995f73b..48a36ebe2c 100644 --- a/tests/integrated/CMakeLists.txt +++ b/tests/integrated/CMakeLists.txt @@ -1,4 +1,8 @@ add_subdirectory(test-attribs) +add_subdirectory(test-command-args) +add_subdirectory(test-coordinates-initialization) +add_subdirectory(test-cyclic) +add_subdirectory(test-delp2) add_subdirectory(test-griddata) add_subdirectory(test-initial) add_subdirectory(test-invertable-operator) diff --git a/tests/integrated/test-command-args/CMakeLists.txt b/tests/integrated/test-command-args/CMakeLists.txt new file mode 100644 index 0000000000..bd77cad4cc --- /dev/null +++ b/tests/integrated/test-command-args/CMakeLists.txt @@ -0,0 +1,5 @@ +bout_add_integrated_test(command-args + SOURCES command-args.cxx + USE_RUNTEST + EXTRA_FILES BOUT.inp + ) diff --git a/tests/integrated/test-coordinates-initialization/CMakeLists.txt b/tests/integrated/test-coordinates-initialization/CMakeLists.txt new file mode 100644 index 0000000000..564957fef1 --- /dev/null +++ b/tests/integrated/test-coordinates-initialization/CMakeLists.txt @@ -0,0 +1,5 @@ +bout_add_integrated_test(test-coordinates-initialization + SOURCES test-coordinates-initialization.cxx + USE_RUNTEST + USE_DATA_BOUT_INP + ) diff --git a/tests/integrated/test-cyclic/CMakeLists.txt b/tests/integrated/test-cyclic/CMakeLists.txt new file mode 100644 index 0000000000..81d24d7aa6 --- /dev/null +++ b/tests/integrated/test-cyclic/CMakeLists.txt @@ -0,0 +1,6 @@ +bout_add_integrated_test(test_cyclic + SOURCES test_cyclic.cxx + USE_RUNTEST + USE_DATA_BOUT_INP + EXTRA_FILES test_io.grd.nc + ) diff --git a/tests/integrated/test-delp2/CMakeLists.txt b/tests/integrated/test-delp2/CMakeLists.txt new file mode 100644 index 0000000000..8665387872 --- /dev/null +++ b/tests/integrated/test-delp2/CMakeLists.txt @@ -0,0 +1,5 @@ +bout_add_integrated_test(test_delp2 + SOURCES test_delp2.cxx + USE_RUNTEST + USE_DATA_BOUT_INP + ) diff --git a/tests/integrated/test-initial/CMakeLists.txt b/tests/integrated/test-initial/CMakeLists.txt index 9d298e3d7b..486f07bd18 100644 --- a/tests/integrated/test-initial/CMakeLists.txt +++ b/tests/integrated/test-initial/CMakeLists.txt @@ -1,15 +1,5 @@ bout_add_integrated_test(test_initial SOURCES test_initial.cxx - EXTRA_FILES make_test_functions_include.py USE_RUNTEST USE_DATA_BOUT_INP ) - -execute_process(COMMAND python3 make_test_functions_include.py - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - RESULT_VARIABLE TEST_INITIAL_MAKE_TEST_FUNCTIONS_RESULT) - -if(NOT TEST_INITIAL_MAKE_TEST_FUNCTIONS_RESULT EQUAL "0") - message(FATAL_ERROR "Unable to make test_functions.cxx needed for test_initial:" - " ${TEST_INITIAL_MAKE_TEST_FUNCTIONS_RESULT}") -endif() From e4e4771750b35611453f424ad2dac09d89bb916c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 19 Jun 2019 16:40:51 +0100 Subject: [PATCH 1593/1783] Remove need for separate included source file in test-initial Uses the new Options API to just find all the sections with `function` in them --- tests/integrated/test-initial/data/BOUT.inp | 4 +- .../make_test_functions_include.py | 38 ---------------- tests/integrated/test-initial/makefile | 6 --- .../integrated/test-initial/test_initial.cxx | 45 ++++++++++--------- 4 files changed, 26 insertions(+), 67 deletions(-) delete mode 100755 tests/integrated/test-initial/make_test_functions_include.py diff --git a/tests/integrated/test-initial/data/BOUT.inp b/tests/integrated/test-initial/data/BOUT.inp index 696f30d998..99b5b6537b 100644 --- a/tests/integrated/test-initial/data/BOUT.inp +++ b/tests/integrated/test-initial/data/BOUT.inp @@ -73,7 +73,7 @@ function = gauss(x) [gauss_width] function = gauss(x, 1.0) -[H] +[h] function = H(x) [log] @@ -121,7 +121,7 @@ function = 4*y [erf] function = erf(x) -[TanhHat] +[tanhhat] function = TanhHat(x, 0.5, 0.4, 0.3) [fmod] diff --git a/tests/integrated/test-initial/make_test_functions_include.py b/tests/integrated/test-initial/make_test_functions_include.py deleted file mode 100755 index ecfa8d3228..0000000000 --- a/tests/integrated/test-initial/make_test_functions_include.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 -import configparser -import itertools -import os - - -def make_test_functions_include(): - """ - Make test_functions.cxx needed for test_initial - """ - datadir = "data" - inputfile = os.path.join(datadir, "BOUT.inp") - - # Read the input file - config = configparser.ConfigParser() - with open(inputfile, "r") as f: - config.read_file(itertools.chain(['[global]'], f), source=inputfile) - - # Find the variables that have a "function" option - varlist = [key for key, values in config.items() if 'function' in values] - - # Remove the coordinate arrays - for coord in ["var_x", "var_y", "var_z"]: - varlist.remove(coord) - - # Make the test case - cxx_snippet = """ - Field3D {name}; - create_and_dump({name}, "{name}"); - """ - - with open("test_functions.cxx", "w") as f: - for var in varlist: - f.write(cxx_snippet.format(name=var)) - - -if __name__ == "__main__": - make_test_functions_include() diff --git a/tests/integrated/test-initial/makefile b/tests/integrated/test-initial/makefile index a0bbe6445d..b314e92006 100644 --- a/tests/integrated/test-initial/makefile +++ b/tests/integrated/test-initial/makefile @@ -4,9 +4,3 @@ BOUT_TOP = ../../.. SOURCEC = test_initial.cxx include $(BOUT_TOP)/make.config - -test_initial.cxx: - @./make_test_functions_include.py - -clean:: - @-rm -f test_functions.cxx diff --git a/tests/integrated/test-initial/test_initial.cxx b/tests/integrated/test-initial/test_initial.cxx index ae2d52894c..cbfbb7eb9e 100644 --- a/tests/integrated/test-initial/test_initial.cxx +++ b/tests/integrated/test-initial/test_initial.cxx @@ -6,38 +6,41 @@ * */ -#include "bout/physicsmodel.hxx" #include "initialprofiles.hxx" +#include "bout/physicsmodel.hxx" + +#include +#include void create_and_dump(Field3D& field, const char* name) { initial_profile(name, field); dump.add(field, name, false); } -void create_and_dump(Field2D& field, const char* name) { - initial_profile(name, field); - dump.add(field, name, false); -} int main(int argc, char** argv) { BoutInitialise(argc, argv); - // Save the coordinate arrays to make the python bit easier - Field3D var_x; - create_and_dump(var_x, "var_x"); - - Field3D var_y; - create_and_dump(var_y, "var_y"); - - Field3D var_z; - create_and_dump(var_z, "var_z"); - - // Include the functions to be tested - // ./runtest generates this file by reading the list of variables in - // data/BOUT.inp, excluding var_{x,y,z} -#include "test_functions.cxx" - - dump.write(); + const auto& sections = Options::root().subsections(); + + // We need a vector of Fields because: + // 1) we don't know at compile time how many we need + // 2) using a local variable inside the loop causes problems with + // dump when the variable goes out of scope + // We also need to reserve the size to avoid allocations + // invalidating the pointers the output file has stored. Sections is + // too large as it includes sections we don't want, but that's ok + std::vector fields(sections.size()); + + for (const auto& section : sections) { + if (!section.second->isSet("function")) { + continue; + } + fields.emplace_back(); + auto& field = fields.back(); + create_and_dump(field, section.first.c_str()); + dump.write(); + } BoutFinalise(); From 3999d9a15f146bb292e686dc25f81200014eea1c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 19 Jun 2019 17:08:59 +0100 Subject: [PATCH 1594/1783] Travis: Install h5py for CMake HDF5 test --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 92cf425c3d..2f0c506b74 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,6 +30,7 @@ addons: - netcdf-bin - hdf5-tools - python3 + - python3-h5py - python3-pip - python3-pytest - python3-numpy From 246e1a1681fd14e97efb454d0470b4c5f0923a62 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 19 Jun 2019 17:26:16 +0100 Subject: [PATCH 1595/1783] CMake: Remove extraneous variable --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9df6307996..3dcc6d7718 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -308,7 +308,6 @@ target_compile_definitions(bout++ PUBLIC "BOUT_VERSION_STRING=\"4.2.2\"" PUBLIC "BOUT_VERSION_DOUBLE=4.22" ) -set(BOUT_HAS_PVODE TRUE) target_compile_features(bout++ PUBLIC cxx_std_11) set_target_properties(bout++ PROPERTIES CXX_EXTENSIONS OFF) From 39c8c006dd8dc9158c82d3402b57a6fe16462e13 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 20 Jun 2019 10:04:13 +0100 Subject: [PATCH 1596/1783] Remove FIXME comment from interp_to Required checking is handled in toFieldAligned now. --- include/interpolation.hxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/interpolation.hxx b/include/interpolation.hxx index ab39ca66da..ab20c0e1ae 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -125,8 +125,6 @@ const T interp_to(const T& var, CELL_LOC loc, const std::string region = "RGN_AL ASSERT0(fieldmesh->ystart >= 2); // We can't interpolate in y unless we're field-aligned - // FIXME: Add check once we label fields as orthogonal/aligned - const T var_fa = toFieldAligned(var, "RGN_NOX"); if (region != "RGN_NOBNDRY") { // repeat the hack above for boundary points From 2e00092cca9bba07ddfdc866f3e89eb1b3e501dd Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 20 Jun 2019 11:27:25 +0100 Subject: [PATCH 1597/1783] CMake: Enable some compiler warnings by default --- CMakeLists.txt | 18 +++++++++++ cmake/EnableCXXWarningIfSupport.cmake | 43 +++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 cmake/EnableCXXWarningIfSupport.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dcc6d7718..9065716034 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -312,6 +312,24 @@ target_compile_definitions(bout++ target_compile_features(bout++ PUBLIC cxx_std_11) set_target_properties(bout++ PROPERTIES CXX_EXTENSIONS OFF) +option(ENABLE_WARNINGS "Enable compiler warnings" ON) +if (ENABLE_WARNINGS) + target_compile_options(bout++ PRIVATE + $<$,$,$>: + -Wall -Wextra > + $<$: + /W4 > + ) + + include(EnableCXXWarningIfSupport) + # Note we explicitly turn off -Wcast-function-type as PETSc *requires* + # we cast a function to the wrong type in MatFDColoringSetFunction + target_enable_cxx_warning_if_supported(bout++ + FLAGS -Wnull-dereference -Wno-cast-function-type + ) + +endif() + # Compile time features set(CHECK_LEVELS 0 1 2 3 4) diff --git a/cmake/EnableCXXWarningIfSupport.cmake b/cmake/EnableCXXWarningIfSupport.cmake new file mode 100644 index 0000000000..70599ccd23 --- /dev/null +++ b/cmake/EnableCXXWarningIfSupport.cmake @@ -0,0 +1,43 @@ +include(CheckCXXCompilerFlag) + +# Add warning FLAGS to TARGET if the compiler supports them +function(target_enable_cxx_warning_if_supported TARGET) + set(multiValueArgs FLAGS) + cmake_parse_arguments(TARGET_ENABLE_WARNING "" "" "${multiValueArgs}" ${ARGN}) + + foreach (WARNING_FLAG IN LISTS TARGET_ENABLE_WARNING_FLAGS) + string(REPLACE "-" "_" WARNING_FLAG_STRIPPED ${WARNING_FLAG}) + + # Note that gcc ignores unknown flags of the form "-Wno-warning" + # for backwards compatibility. Therefore we need to add the + # positive form as an additional flag which it will choke on (if + # it doesn't exist). See: https://gcc.gnu.org/wiki/FAQ#wnowarning + string(FIND ${WARNING_FLAG} "Wno-" NEGATIVE_FLAG_${WARNING_FLAG_STRIPPED}) + if (NEGATIVE_FLAG_${WARNING_FLAG_STRIPPED} EQUAL -1) + set(IS_NEGATIVE_FLAG_${WARNING_FLAG_STRIPPED} FALSE) + else() + set(IS_NEGATIVE_FLAG_${WARNING_FLAG_STRIPPED} TRUE) + endif() + + if (IS_NEGATIVE_FLAG_${WARNING_FLAG_STRIPPED}) + set(ORIGINAL_FLAG ${WARNING_FLAG}) + string(REPLACE "no-" "" WARNING_FLAG ${WARNING_FLAG}) + message(STATUS "Found negative flag: ${ORIGINAL_FLAG}\n" + " replaced with ${WARNING_FLAG}") + endif() + + check_cxx_compiler_flag(${WARNING_FLAG} HAS_FLAG_${WARNING_FLAG_STRIPPED}) + + if (IS_NEGATIVE_FLAG_${WARNING_FLAG_STRIPPED}) + set(WARNING_FLAG ${ORIGINAL_FLAG}) + endif() + + if (HAS_FLAG_${WARNING_FLAG_STRIPPED}) + message(STATUS "Warning flag is supported by compiler: ${WARNING_FLAG}") + + target_compile_options(${TARGET} PRIVATE ${WARNING_FLAG}) + else() + message(STATUS "Warning flag not supported by compiler: ${WARNING_FLAG}") + endif() + endforeach() +endfunction() From fd46f6a2380e1c24f30581cb309f9129ef717b12 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 20 Jun 2019 11:27:56 +0100 Subject: [PATCH 1598/1783] CMake: Fix slepc test missing requirement on SLEPc --- tests/integrated/test-slepc-solver/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integrated/test-slepc-solver/CMakeLists.txt b/tests/integrated/test-slepc-solver/CMakeLists.txt index f8d7166e3d..bc4c178de9 100644 --- a/tests/integrated/test-slepc-solver/CMakeLists.txt +++ b/tests/integrated/test-slepc-solver/CMakeLists.txt @@ -2,4 +2,5 @@ bout_add_integrated_test(test-slepc-solver SOURCES test-slepc-solver.cxx USE_RUNTEST USE_DATA_BOUT_INP + REQUIRES BOUT_HAS_SLEPC ) From bb9dd143b1662d63e93dca793cd4347037ee746c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 20 Jun 2019 11:28:14 +0100 Subject: [PATCH 1599/1783] CMake: Make conditional in bout_add_integrated_test less confusing --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9065716034..8cc7a54f64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -593,8 +593,8 @@ function(bout_add_integrated_test TESTNAME) set(multiValueArgs SOURCES EXTRA_FILES REQUIRES) cmake_parse_arguments(BOUT_TEST_OPTIONS "${options}" "" "${multiValueArgs}" ${ARGN}) - foreach (REQUIREMENT "${BOUT_TEST_OPTIONS_REQUIRES}") - if (REQUIREMENT AND NOT ${REQUIREMENT}) + foreach (REQUIREMENT IN LISTS BOUT_TEST_OPTIONS_REQUIRES) + if (NOT ${REQUIREMENT}) message(STATUS "Not building test ${TESTNAME}, requirement not met: ${REQUIREMENT}") return() endif() From bd6ca8012ba3733667fc563938cc7c1748290df8 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 20 Jun 2019 11:28:34 +0100 Subject: [PATCH 1600/1783] CMake: Change some option defaults to match those from configure --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cc7a54f64..7927d5a2ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -381,7 +381,7 @@ endif() message(STATUS "Field name tracking: TRACK=${ENABLE_TRACK}") set(BOUT_USE_TRACK ${ENABLE_TRACK}) -option(ENABLE_SIGFPE "Signalling floating point exceptions" ON) +option(ENABLE_SIGFPE "Signalling floating point exceptions" OFF) if (ENABLE_SIGFPE) target_compile_definitions(bout++ PUBLIC "BOUT_FPE") @@ -450,7 +450,7 @@ endif() message(STATUS "NetCDF support: ${USE_NETCDF}") set(BOUT_HAS_NETCDF ${USE_NETCDF}) -option(USE_HDF5 "Enable support for HDF5 output" ON) +option(USE_HDF5 "Enable support for HDF5 output" OFF) if (USE_HDF5) find_package(HDF5 REQUIRED COMPONENTS CXX) target_compile_definitions(bout++ From 7597e9b7f4fd0b1822ba212775185216ba786211 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 20 Jun 2019 11:31:54 +0100 Subject: [PATCH 1601/1783] CMake: Fix BOUT_VERSION_* variables to not be hard-coded --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7927d5a2ff..b909ab6482 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -305,8 +305,8 @@ target_include_directories(bout++ PUBLIC ) target_compile_definitions(bout++ - PUBLIC "BOUT_VERSION_STRING=\"4.2.2\"" - PUBLIC "BOUT_VERSION_DOUBLE=4.22" + PUBLIC "BOUT_VERSION_STRING=\"${PROJECT_VERSION}\"" + PUBLIC "BOUT_VERSION_DOUBLE=${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}${PROJECT_VERSION_PATCH}" ) target_compile_features(bout++ PUBLIC cxx_std_11) From 36a567d8c38da1ad77cfd0b9f75eead12dc4f0a3 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Thu, 20 Jun 2019 14:25:48 +0100 Subject: [PATCH 1602/1783] Add default value to Mesh::get for ints --- include/bout/griddata.hxx | 6 ++--- include/bout/mesh.hxx | 3 ++- src/mesh/data/gridfromoptions.cxx | 3 +-- src/mesh/impls/bout/boutmesh.cxx | 44 +++++-------------------------- src/mesh/mesh.cxx | 4 +-- 5 files changed, 15 insertions(+), 45 deletions(-) diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index c764bc58d9..7b1cb315c3 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -53,7 +53,7 @@ public: virtual bool hasVar(const std::string &name) = 0; ///< Test if source can supply a variable virtual bool get(Mesh *m, std::string &sval, const std::string &name) = 0; ///< Get a string - virtual bool get(Mesh *m, int &ival, const std::string &name) = 0; ///< Get an integer + virtual bool get(Mesh *m, int &ival, const std::string &name, int def = 0) = 0; ///< Get an integer virtual bool get(Mesh *m, BoutReal &rval, const std::string &name) = 0; ///< Get a BoutReal number virtual bool get(Mesh *m, Field2D &var, const std::string &name, BoutReal def = 0.0) = 0; @@ -87,7 +87,7 @@ public: bool hasVar(const std::string &name) override; bool get(Mesh *m, std::string &sval, const std::string &name) override; ///< Get a string - bool get(Mesh *m, int &ival, const std::string &name) override; ///< Get an integer + bool get(Mesh *m, int &ival, const std::string &name, int def = 0) override; ///< Get an integer bool get(Mesh *m, BoutReal &rval, const std::string &name) override; ///< Get a BoutReal number bool get(Mesh *m, Field2D &var, const std::string &name, BoutReal def = 0.0) override; @@ -182,7 +182,7 @@ public: * * @return True if option is set, false if ival is default (0) */ - bool get(Mesh *mesh, int &ival, const std::string &name) override; + bool get(Mesh *mesh, int &ival, const std::string &name, int def = 0) override; /*! * Reads BoutReal from options. Uses Options::get to handle diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 6f9d9c3fd8..9318238891 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -134,9 +134,10 @@ class Mesh { /// /// @param[out] ival The value will be put into this variable /// @param[in] name The name of the variable to read + /// @param[in] def The default value if not found /// /// @returns zero if successful, non-zero on failure - int get(int &ival, const std::string &name); + int get(int &ival, const std::string &name, int def = 0); /// Get a BoutReal from the input source /// diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index ff78399bb6..c79f06a0c2 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -20,9 +20,8 @@ bool GridFromOptions::get(Mesh* UNUSED(m), std::string& sval, const std::string& return true; } -bool GridFromOptions::get(Mesh* UNUSED(m), int& ival, const std::string& name) { +bool GridFromOptions::get(Mesh* UNUSED(m), int& ival, const std::string& name, int def) { if (!hasVar(name)) { - constexpr int def{0}; output_warn.write("Variable '%s' not in mesh options. Setting to %d\n", name.c_str(), def); ival = def; diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index ef11247a72..9e9bfc2b2e 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -162,43 +162,13 @@ int BoutMesh::load() { throw BoutException(_("nx must be greater than 2*MXG")); // separatrix location - if (Mesh::get(ixseps1, "ixseps1")) { - ixseps1 = GlobalNx; - output_warn.write( - "\tWARNING: Separatrix location 'ixseps1' not found. Setting to %d\n", ixseps1); - } - if (Mesh::get(ixseps2, "ixseps2")) { - ixseps2 = GlobalNx; - output_warn.write( - "\tWARNING: Separatrix location 'ixseps2' not found. Setting to %d\n", ixseps2); - } - if (Mesh::get(jyseps1_1, "jyseps1_1")) { - jyseps1_1 = -1; - output_warn.write("\tWARNING: Branch-cut 'jyseps1_1' not found. Setting to %d\n", - jyseps1_1); - } - if (Mesh::get(jyseps1_2, "jyseps1_2")) { - jyseps1_2 = ny / 2; - output_warn.write("\tWARNING: Branch-cut 'jyseps1_2' not found. Setting to %d\n", - jyseps1_2); - } - if (Mesh::get(jyseps2_1, "jyseps2_1")) { - jyseps2_1 = jyseps1_2; - output_warn.write("\tWARNING: Branch-cut 'jyseps2_1' not found. Setting to %d\n", - jyseps2_1); - } - if (Mesh::get(jyseps2_2, "jyseps2_2")) { - jyseps2_2 = ny - 1; - output_warn.write("\tWARNING: Branch-cut 'jyseps2_2' not found. Setting to %d\n", - jyseps2_2); - } - - if (Mesh::get(ny_inner, "ny_inner")) { - ny_inner = jyseps2_1; - output_warn.write( - "\tWARNING: Number of inner y points 'ny_inner' not found. Setting to %d\n", - ny_inner); - } + Mesh::get(ixseps1, "ixseps1", GlobalNx); + Mesh::get(ixseps2, "ixseps2", GlobalNx); + Mesh::get(jyseps1_1, "ixseps1_1", -1); + Mesh::get(jyseps1_2, "ixseps1_2", ny / 2); + Mesh::get(jyseps2_1, "ixseps2_1", jyseps1_2); + Mesh::get(jyseps2_2, "ixseps2_2", ny - 1); + Mesh::get(ny_inner, "ny_inner", jyseps2_1); /// Check inputs if (jyseps1_1 < -1) { diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 45076b950a..49f29cfa76 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -58,10 +58,10 @@ int Mesh::get(std::string &sval, const std::string &name) { } /// Get an integer -int Mesh::get(int &ival, const std::string &name) { +int Mesh::get(int &ival, const std::string &name, int def) { TRACE("Mesh::get(ival, %s)", name.c_str()); - if (source == nullptr or !source->get(this, ival, name)) + if (source == nullptr or !source->get(this, ival, name, def)) return 1; return 0; From b2c089e51d47b532c64b21f21370465ce41659a9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 11:29:28 +0100 Subject: [PATCH 1603/1783] Enclose macro arguments in parentheses --- src/sys/boutexception.cxx | 2 +- src/sys/output.cxx | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sys/boutexception.cxx b/src/sys/boutexception.cxx index f99bfbd03f..1e7d7dcd80 100644 --- a/src/sys/boutexception.cxx +++ b/src/sys/boutexception.cxx @@ -101,7 +101,7 @@ void BoutException::makeBacktrace() { { \ buflen = 0; \ buffer = nullptr; \ - if (s == nullptr) { \ + if ((s) == nullptr) { \ message = "No error message given!\n"; \ } else { \ buflen = BoutException::BUFFER_LEN; \ diff --git a/src/sys/output.cxx b/src/sys/output.cxx index 14a78eeef9..a4f25b3330 100644 --- a/src/sys/output.cxx +++ b/src/sys/output.cxx @@ -69,16 +69,16 @@ void Output::close() { remove(file); file.close(); } -#define bout_vsnprintf_(buf, len, fmt, va) \ - { \ - int _vsnprintflen = vsnprintf(buf, len, fmt, va); \ - if (_vsnprintflen + 1 > len) { \ - _vsnprintflen += 1; \ - delete[] buf; \ - buf = new char[_vsnprintflen]; \ - len = _vsnprintflen; \ - vsnprintf(buf, len, fmt, va); \ - } \ +#define bout_vsnprintf_(buf, len, fmt, va) \ + { \ + int _vsnprintflen = vsnprintf(buf, len, fmt, va); \ + if (_vsnprintflen + 1 > (len)) { \ + _vsnprintflen += 1; \ + delete[](buf); \ + (buf) = new char[_vsnprintflen]; \ + (len) = _vsnprintflen; \ + vsnprintf(buf, len, fmt, va); \ + } \ } void Output::write(const char *string, ...) { From 10a488e78a6fc6b43446f398ca74e95d1ec7ad6e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 12:00:12 +0100 Subject: [PATCH 1604/1783] Replace LaplaceXY::roundInt with std::round in globalIndex --- include/bout/invert/laplacexy.hxx | 6 ------ src/invert/laplacexy/laplacexy.cxx | 10 +--------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/include/bout/invert/laplacexy.hxx b/include/bout/invert/laplacexy.hxx index 9b17547808..705ad76351 100644 --- a/include/bout/invert/laplacexy.hxx +++ b/include/bout/invert/laplacexy.hxx @@ -157,12 +157,6 @@ private: */ int globalIndex(int x, int y); Field2D indexXY; ///< Global index (integer stored as BoutReal) - - /*! - * Round a number to the nearest integer - */ - int roundInt(BoutReal f); - }; #endif // BOUT_HAS_PETSC diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index aed537935b..e114bd66a8 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -805,14 +805,6 @@ int LaplaceXY::globalIndex(int x, int y) { return -1; // Out of range // Get the index from a Field2D, round to integer - return roundInt(indexXY(x,y)); + return static_cast(std::round(indexXY(x, y))); } - -int LaplaceXY::roundInt(BoutReal f) { - if(f > 0.0) { - return (int) (f + 0.5); - } - return (int) (f - 0.5); -} - #endif // BOUT_HAS_PETSC From d1f124158d0bcfba856f56ece2a4d4665e0cd36e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 12:01:15 +0100 Subject: [PATCH 1605/1783] Use LaplaceXY::globalIndex instead of implicit conversions --- src/invert/laplacexy/laplacexy.cxx | 74 +++++++++++++++++------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index e114bd66a8..ed990a72fd 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -14,6 +14,8 @@ #include +#include + #undef __FUNCT__ #define __FUNCT__ "laplacePCapply" static PetscErrorCode laplacePCapply(PC pc,Vec x,Vec y) { @@ -114,7 +116,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) if(localmesh->firstX()) { // Lower X boundary for(int y=localmesh->ystart;y<=localmesh->yend;y++) { - int localIndex = indexXY(localmesh->xstart-1,y); + const int localIndex = globalIndex(localmesh->xstart-1, y); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] = 2; // Diagonal sub-matrix @@ -123,7 +125,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) }else { // On another processor for(int y=localmesh->ystart;y<=localmesh->yend;y++) { - int localIndex = indexXY(localmesh->xstart,y); + const int localIndex = globalIndex(localmesh->xstart, y); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] -= 1; o_nnz[localIndex] += 1; @@ -132,7 +134,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) if(localmesh->lastX()) { // Upper X boundary for(int y=localmesh->ystart;y<=localmesh->yend;y++) { - int localIndex = indexXY(localmesh->xend+1,y); + const int localIndex = globalIndex(localmesh->xend+1, y); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] = 2; // Diagonal sub-matrix o_nnz[localIndex] = 0; // Off-diagonal sub-matrix @@ -140,7 +142,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) }else { // On another processor for(int y=localmesh->ystart;y<=localmesh->yend;y++) { - int localIndex = indexXY(localmesh->xend,y); + const int localIndex = globalIndex(localmesh->xend, y); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] -= 1; o_nnz[localIndex] += 1; @@ -153,39 +155,47 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) // NOTE: This assumes that communications in Y are to other // processors. If Y is communicated with this processor (e.g. NYPE=1) // then this will result in PETSc warnings about out of range allocations - - int localIndex = indexXY(x, localmesh->ystart); - ASSERT1( (localIndex >= 0) && (localIndex < localN) ); - //d_nnz[localIndex] -= 1; // Note: Slightly inefficient - o_nnz[localIndex] += 1; - - localIndex = indexXY(x, localmesh->yend); - ASSERT1( (localIndex >= 0) && (localIndex < localN) ); - //d_nnz[localIndex] -= 1; // Note: Slightly inefficient - o_nnz[localIndex] += 1; + { + const int localIndex = globalIndex(x, localmesh->ystart); + ASSERT1( (localIndex >= 0) && (localIndex < localN) ); + //d_nnz[localIndex] -= 1; // Note: Slightly inefficient + o_nnz[localIndex] += 1; + } + { + const int localIndex = globalIndex(x, localmesh->yend); + ASSERT1( (localIndex >= 0) && (localIndex < localN) ); + //d_nnz[localIndex] -= 1; // Note: Slightly inefficient + o_nnz[localIndex] += 1; + } } for(RangeIterator it=localmesh->iterateBndryLowerY(); !it.isDone(); it++) { - int localIndex = indexXY(it.ind, localmesh->ystart-1); - ASSERT1( (localIndex >= 0) && (localIndex < localN) ); - d_nnz[localIndex] = 2; // Diagonal sub-matrix - o_nnz[localIndex] = 0; // Off-diagonal sub-matrix - - localIndex = indexXY(it.ind, localmesh->ystart); - ASSERT1( (localIndex >= 0) && (localIndex < localN) ); - d_nnz[localIndex] += 1; - o_nnz[localIndex] -= 1; + { + const int localIndex = globalIndex(it.ind, localmesh->ystart-1); + ASSERT1( (localIndex >= 0) && (localIndex < localN) ); + d_nnz[localIndex] = 2; // Diagonal sub-matrix + o_nnz[localIndex] = 0; // Off-diagonal sub-matrix + } + { + const int localIndex = globalIndex(it.ind, localmesh->ystart); + ASSERT1( (localIndex >= 0) && (localIndex < localN) ); + d_nnz[localIndex] += 1; + o_nnz[localIndex] -= 1; + } } for(RangeIterator it=localmesh->iterateBndryUpperY(); !it.isDone(); it++) { - int localIndex = indexXY(it.ind, localmesh->yend+1); - ASSERT1( (localIndex >= 0) && (localIndex < localN) ); - d_nnz[localIndex] = 2; // Diagonal sub-matrix - o_nnz[localIndex] = 0; // Off-diagonal sub-matrix - - localIndex = indexXY(it.ind, localmesh->yend); - ASSERT1( (localIndex >= 0) && (localIndex < localN) ); - d_nnz[localIndex] += 1; - o_nnz[localIndex] -= 1; + { + const int localIndex = globalIndex(it.ind, localmesh->yend+1); + ASSERT1( (localIndex >= 0) && (localIndex < localN) ); + d_nnz[localIndex] = 2; // Diagonal sub-matrix + o_nnz[localIndex] = 0; // Off-diagonal sub-matrix + } + { + const int localIndex = globalIndex(it.ind, localmesh->yend); + ASSERT1( (localIndex >= 0) && (localIndex < localN) ); + d_nnz[localIndex] += 1; + o_nnz[localIndex] -= 1; + } } // Pre-allocate MatMPIAIJSetPreallocation( MatA, 0, d_nnz, 0, o_nnz ); From 549f7545661e95b36667c2fa7430ec2317db6e1b Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 12:03:13 +0100 Subject: [PATCH 1606/1783] Fix use-after-move in Solver --- src/solver/solver.cxx | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 1ea44be787..43e5d7f652 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -362,13 +362,13 @@ void Solver::constraint(Vector2D &v, Vector2D &C_v, const std::string name) { // Add suffix, depending on co- /contravariance if (v.covariant) { - constraint(v.x, C_v.x, d.name+"_x"); - constraint(v.y, C_v.y, d.name+"_y"); - constraint(v.z, C_v.z, d.name+"_z"); + constraint(v.x, C_v.x, name+"_x"); + constraint(v.y, C_v.y, name+"_y"); + constraint(v.z, C_v.z, name+"_z"); } else { - constraint(v.x, C_v.x, d.name+"x"); - constraint(v.y, C_v.y, d.name+"y"); - constraint(v.z, C_v.z, d.name+"z"); + constraint(v.x, C_v.x, name+"x"); + constraint(v.y, C_v.y, name+"y"); + constraint(v.z, C_v.z, name+"z"); } } @@ -402,13 +402,13 @@ void Solver::constraint(Vector3D &v, Vector3D &C_v, const std::string name) { // Add suffix, depending on co- /contravariance if (v.covariant) { - constraint(v.x, C_v.x, d.name+"_x"); - constraint(v.y, C_v.y, d.name+"_y"); - constraint(v.z, C_v.z, d.name+"_z"); + constraint(v.x, C_v.x, name+"_x"); + constraint(v.y, C_v.y, name+"_y"); + constraint(v.z, C_v.z, name+"_z"); } else { - constraint(v.x, C_v.x, d.name+"x"); - constraint(v.y, C_v.y, d.name+"y"); - constraint(v.z, C_v.z, d.name+"z"); + constraint(v.x, C_v.x, name+"x"); + constraint(v.y, C_v.y, name+"y"); + constraint(v.z, C_v.z, name+"z"); } } From d649155eae7fb390c11fc1bc48e617dd2ca33b1e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 12:03:38 +0100 Subject: [PATCH 1607/1783] Use std::round instead of (double + 0.5) and implicit conversion --- src/solver/impls/karniadakis/karniadakis.cxx | 2 +- src/solver/solver.cxx | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/solver/impls/karniadakis/karniadakis.cxx b/src/solver/impls/karniadakis/karniadakis.cxx index ce66d4b84b..92d10214c9 100644 --- a/src/solver/impls/karniadakis/karniadakis.cxx +++ b/src/solver/impls/karniadakis/karniadakis.cxx @@ -101,7 +101,7 @@ int KarniadakisSolver::init(int nout, BoutReal tstep) { // Make sure timestep divides into tstep // Number of sub-steps, rounded up - nsubsteps = static_cast(0.5 + tstep / timestep); + nsubsteps = static_cast(std::round(tstep / timestep)); output.write("\tNumber of substeps: %e / %e -> %d\n", tstep, timestep, nsubsteps); diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 43e5d7f652..36ca28f7d5 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -34,6 +34,7 @@ #include "bout/solverfactory.hxx" #include "bout/sys/timer.hxx" +#include #include #include #include @@ -576,7 +577,8 @@ BoutReal Solver::adjustMonitorPeriods(Monitor* new_monitor) { if (new_monitor->timestep > internal_timestep * 1.5) { // Monitor has a larger timestep - new_monitor->period = (new_monitor->timestep / internal_timestep) + .5; + new_monitor->period = + static_cast(std::round(new_monitor->timestep / internal_timestep)); return internal_timestep; } @@ -590,7 +592,8 @@ BoutReal Solver::adjustMonitorPeriods(Monitor* new_monitor) { } // This is the relative increase in timestep - const int multiplier = internal_timestep / new_monitor->timestep + .5; + const auto multiplier = + static_cast(std::round(internal_timestep / new_monitor->timestep)); for (const auto& monitor : monitors) { monitor->period *= multiplier; } @@ -611,13 +614,15 @@ void Solver::finaliseMonitorPeriods(int& NOUT, BoutReal& output_timestep) { "A monitor requested a timestep not compatible with the output_step!"); } if (internal_timestep < output_timestep * 1.5) { - default_monitor_period = output_timestep / internal_timestep + .5; + default_monitor_period = + static_cast(std::round(output_timestep / internal_timestep)); NOUT *= default_monitor_period; output_timestep = internal_timestep; } else { default_monitor_period = 1; // update old monitors - int multiplier = internal_timestep / output_timestep + .5; + const auto multiplier = + static_cast(std::round(internal_timestep / output_timestep)); for (const auto& i : monitors) { i->period = i->period * multiplier; } From abc3caca6d6c75f1fc312937130982ea68f1bb2e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 13:46:01 +0100 Subject: [PATCH 1608/1783] Don't move from const arguments --- src/sys/options.cxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 273ea8effa..0c000329b9 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -135,35 +135,35 @@ bool Options::isSection(const std::string& name) const { } template <> -void Options::assign<>(Field2D val, const std::string source) { +void Options::assign<>(Field2D val, std::string source) { value = std::move(val); attributes["source"] = std::move(source); value_used = false; is_value = true; } template <> -void Options::assign<>(Field3D val, const std::string source) { +void Options::assign<>(Field3D val, std::string source) { value = std::move(val); attributes["source"] = std::move(source); value_used = false; is_value = true; } template <> -void Options::assign<>(Array val, const std::string source) { +void Options::assign<>(Array val, std::string source) { value = std::move(val); attributes["source"] = std::move(source); value_used = false; is_value = true; } template <> -void Options::assign<>(Matrix val, const std::string source) { +void Options::assign<>(Matrix val, std::string source) { value = std::move(val); attributes["source"] = std::move(source); value_used = false; is_value = true; } template <> -void Options::assign<>(Tensor val, const std::string source) { +void Options::assign<>(Tensor val, std::string source) { value = std::move(val); attributes["source"] = std::move(source); value_used = false; From 3261991eeb9eda3e0d73df18365b7b2616497b32 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 16:49:54 +0100 Subject: [PATCH 1609/1783] Avoid some needless copies when a const-ref will do --- src/sys/options.cxx | 2 +- src/sys/options/options_netcdf.cxx | 2 +- tests/unit/include/bout/test_region.cxx | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 0c000329b9..774fff9d5d 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -345,7 +345,7 @@ template <> Field3D Options::as(const Field3D& similar_to) const { } if (bout::utils::holds_alternative(value)) { - Field2D stored_value = bout::utils::get(value); + const Field2D& stored_value = bout::utils::get(value); // Check that meta-data is consistent ASSERT1(areFieldsCompatible(stored_value, similar_to)); diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 8a7813fe13..36aeff32d6 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -382,7 +382,7 @@ void writeGroup(const Options& options, NcGroup group, if (time_it != child.attributes.end()) { // Has a time dimension - auto time_name = bout::utils::get(time_it->second); + const auto& time_name = bout::utils::get(time_it->second); time_dim = group.getDim(time_name, NcGroup::ParentsAndCurrent); if (time_dim.isNull()) { time_dim = group.addDim(time_name); diff --git a/tests/unit/include/bout/test_region.cxx b/tests/unit/include/bout/test_region.cxx index 8e37a30466..6021144956 100644 --- a/tests/unit/include/bout/test_region.cxx +++ b/tests/unit/include/bout/test_region.cxx @@ -129,7 +129,7 @@ TEST_F(RegionTest, numberOfBlocks) { Region region(0, mesh->LocalNx - 1, 0, mesh->LocalNy - 1, 0, mesh->LocalNz - 1, mesh->LocalNy, mesh->LocalNz); - auto blocks = region.getBlocks(); + const auto& blocks = region.getBlocks(); int nmesh = RegionTest::nx * RegionTest::ny * RegionTest::nz; int nblocks = blocks.size(); @@ -413,7 +413,7 @@ TEST_F(RegionTest, regionAsUnique) { // Now get a unique version of the region Region regionUnique2 = regionIn2.asUnique(); - Region::RegionIndices regionIndicesUnique2 = regionUnique2.getIndices(); + const Region::RegionIndices& regionIndicesUnique2 = regionUnique2.getIndices(); EXPECT_EQ(regionIndicesUnique2.size(), 8); @@ -478,7 +478,7 @@ TEST_F(RegionTest, regionSetBlocks) { Region region(0, mesh->LocalNx - 1, 0, mesh->LocalNy - 1, 0, mesh->LocalNz - 1, mesh->LocalNy, mesh->LocalNz); auto blocks = region.getBlocks(); - auto indices = region.getIndices(); + const auto& indices = region.getIndices(); EXPECT_EQ(indices.size(), nmesh); @@ -722,7 +722,7 @@ TEST_F(RegionTest, regionFriendMask) { } auto masked2 = mask(regionIn, mask2); - auto masked2Indices = masked2.getIndices(); + const auto& masked2Indices = masked2.getIndices(); EXPECT_EQ(masked2Indices.size(), indicesIn.size()); // Check size of other regions not changed @@ -762,7 +762,7 @@ TEST_F(RegionTest, regionOperatorAdd) { } auto region4 = region1 + region2 + region2; - auto indices4 = region4.getIndices(); + const auto& indices4 = region4.getIndices(); EXPECT_EQ(indices4.size(), indicesIn1.size() + 2 * indicesIn2.size()); EXPECT_EQ(region1.getIndices().size(), indicesIn1.size()); EXPECT_EQ(region2.getIndices().size(), indicesIn2.size()); From db6f2283adaf425ff561b709a88fbc85f1b9da78 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 17:04:08 +0100 Subject: [PATCH 1610/1783] Don't pass by value when a const-ref will do --- include/bout/solver.hxx | 8 ++++---- include/bout_types.hxx | 6 +++--- src/field/field_data.cxx | 2 +- src/solver/impls/slepc/slepc.hxx | 8 ++++---- src/solver/solver.cxx | 8 ++++---- src/sys/bout_types.cxx | 8 ++++---- src/sys/options/options_netcdf.cxx | 2 +- tests/integrated/test-interpolate/test_interpolate.cxx | 2 +- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index f0d74a57ca..1edcde8a63 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -228,10 +228,10 @@ public: /// Add a variable to be solved. This must be done in the /// initialisation stage, before the simulation starts. - virtual void add(Field2D& v, const std::string name); - virtual void add(Field3D& v, const std::string name); - virtual void add(Vector2D& v, const std::string name); - virtual void add(Vector3D& v, const std::string name); + virtual void add(Field2D& v, const std::string& name); + virtual void add(Field3D& v, const std::string& name); + virtual void add(Vector2D& v, const std::string& name); + virtual void add(Vector3D& v, const std::string& name); /// Returns true if constraints available virtual bool constraints() { return has_constraints; } diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 187d9083c6..7a69848b70 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -40,7 +40,7 @@ constexpr BoutReal BoutNaN = std::numeric_limits::quiet_NaN(); enum CELL_LOC {CELL_DEFAULT=0, CELL_CENTRE=1, CELL_CENTER=1, CELL_XLOW=2, CELL_YLOW=3, CELL_ZLOW=4, CELL_VSHIFT=5}; std::string toString(CELL_LOC location); -CELL_LOC CELL_LOCFromString(std::string location_string); +CELL_LOC CELL_LOCFromString(const std::string& location_string); DEPRECATED(inline std::string CELL_LOC_STRING(CELL_LOC location)) { return toString(location); } @@ -80,7 +80,7 @@ DEPRECATED(inline std::string DIRECTION_STRING(DIRECTION direction)) { enum class YDirectionType { Standard, Aligned }; std::string toString(YDirectionType d); -YDirectionType YDirectionTypeFromString(std::string y_direction_string); +YDirectionType YDirectionTypeFromString(const std::string& y_direction_string); /// Identify kind of a field's z-direction /// - Standard is the default @@ -90,7 +90,7 @@ YDirectionType YDirectionTypeFromString(std::string y_direction_string); enum class ZDirectionType { Standard, Average }; std::string toString(ZDirectionType d); -ZDirectionType ZDirectionTypeFromString(std::string z_direction_string); +ZDirectionType ZDirectionTypeFromString(const std::string& z_direction_string); /// Container for direction types struct DirectionTypes { diff --git a/src/field/field_data.cxx b/src/field/field_data.cxx index a152cdd0c9..c328e32d08 100644 --- a/src/field/field_data.cxx +++ b/src/field/field_data.cxx @@ -77,7 +77,7 @@ void FieldData::addBndryGenerator(FieldGeneratorPtr gen, BndryLoc location) { bndry_generator[reg->location] = gen; } } else { - bndry_generator[location] = gen; + bndry_generator[location] = std::move(gen); } } diff --git a/src/solver/impls/slepc/slepc.hxx b/src/solver/impls/slepc/slepc.hxx index b4c8e092ec..178498c984 100644 --- a/src/solver/impls/slepc/slepc.hxx +++ b/src/solver/impls/slepc/slepc.hxx @@ -96,25 +96,25 @@ public: //////Following overrides all just pass through to advanceSolver // Override virtual add functions in order to pass through to advanceSolver - void add(Field2D &v, const std::string name) override { + void add(Field2D &v, const std::string& name) override { Solver::add(v, name); if (!selfSolve) { advanceSolver->add(v, name); } } - void add(Field3D &v, const std::string name) override { + void add(Field3D &v, const std::string& name) override { Solver::add(v, name); if (!selfSolve) { advanceSolver->add(v, name); } } - void add(Vector2D &v, const std::string name) override { + void add(Vector2D &v, const std::string& name) override { Solver::add(v, name); if (!selfSolve) { advanceSolver->add(v, name); } } - void add(Vector3D &v, const std::string name) override { + void add(Vector3D &v, const std::string& name) override { Solver::add(v, name); if (!selfSolve) { advanceSolver->add(v, name); diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 36ca28f7d5..4702dca623 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -82,7 +82,7 @@ void Solver::setModel(PhysicsModel *m) { * Add fields **************************************************************************/ -void Solver::add(Field2D &v, const std::string name) { +void Solver::add(Field2D &v, const std::string& name) { TRACE("Adding 2D field: Solver::add(%s)", name.c_str()); #if CHECK > 0 @@ -139,7 +139,7 @@ void Solver::add(Field2D &v, const std::string name) { f2d.emplace_back(std::move(d)); } -void Solver::add(Field3D &v, const std::string name) { +void Solver::add(Field3D &v, const std::string& name) { TRACE("Adding 3D field: Solver::add(%s)", name.c_str()); Mesh* mesh = v.getMesh(); @@ -198,7 +198,7 @@ void Solver::add(Field3D &v, const std::string name) { f3d.emplace_back(std::move(d)); } -void Solver::add(Vector2D& v, const std::string name) { +void Solver::add(Vector2D& v, const std::string& name) { TRACE("Adding 2D vector: Solver::add(%s)", name.c_str()); if (varAdded(name)) @@ -237,7 +237,7 @@ void Solver::add(Vector2D& v, const std::string name) { v2d.emplace_back(std::move(d)); } -void Solver::add(Vector3D& v, const std::string name) { +void Solver::add(Vector3D& v, const std::string& name) { TRACE("Adding 3D vector: Solver::add(%s)", name.c_str()); if (varAdded(name)) diff --git a/src/sys/bout_types.cxx b/src/sys/bout_types.cxx index 90dd280d71..9dfec5f39e 100644 --- a/src/sys/bout_types.cxx +++ b/src/sys/bout_types.cxx @@ -15,7 +15,7 @@ const std::string& safeAt(const std::map& mymap, T t) { } template -const T& safeAt(const std::map& mymap, std::string s) { +const T& safeAt(const std::map& mymap, const std::string& s) { AUTO_TRACE(); auto found = mymap.find(s); if (found == mymap.end()) { @@ -34,7 +34,7 @@ std::string toString(CELL_LOC location) { return safeAt(CELL_LOCtoString, location); } -CELL_LOC CELL_LOCFromString(std::string location_string) { +CELL_LOC CELL_LOCFromString(const std::string& location_string) { AUTO_TRACE(); const static std::map stringtoCELL_LOC = { STRENUM(CELL_DEFAULT), STRENUM(CELL_CENTRE), STRENUM(CELL_XLOW), @@ -146,7 +146,7 @@ std::string toString(YDirectionType d) { return safeAt(YDirectionTypeToString, d); } -YDirectionType YDirectionTypeFromString(std::string y_direction_string) { +YDirectionType YDirectionTypeFromString(const std::string& y_direction_string) { AUTO_TRACE(); const static std::map stringToYDirectionType = { {"Standard", YDirectionType::Standard}, @@ -164,7 +164,7 @@ std::string toString(ZDirectionType d) { return safeAt(ZDirectionTypeToString, d); } -ZDirectionType ZDirectionTypeFromString(std::string z_direction_string) { +ZDirectionType ZDirectionTypeFromString(const std::string& z_direction_string) { AUTO_TRACE(); const static std::map stringToZDirectionType = { {"Standard", ZDirectionType::Standard}, diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 36aeff32d6..677f603972 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -10,7 +10,7 @@ using namespace netCDF; namespace { -void readGroup(const std::string& filename, NcGroup group, Options& result) { +void readGroup(const std::string& filename, const NcGroup& group, Options& result) { // Iterate over all variables for (const auto& varpair : group.getVars()) { diff --git a/tests/integrated/test-interpolate/test_interpolate.cxx b/tests/integrated/test-interpolate/test_interpolate.cxx index 5d0a49d54e..32b4503205 100644 --- a/tests/integrated/test-interpolate/test_interpolate.cxx +++ b/tests/integrated/test-interpolate/test_interpolate.cxx @@ -16,7 +16,7 @@ #include "interpolation_factory.hxx" /// Get a FieldGenerator from the options for a variable -std::shared_ptr getGeneratorFromOptions(const std::string varname, +std::shared_ptr getGeneratorFromOptions(const std::string& varname, std::string &func) { Options *options = Options::getRoot()->getSection(varname); options->get("solution", func, "0.0"); From 516818d64771b84be39e89ff66b6e8a487e53f79 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 17:08:26 +0100 Subject: [PATCH 1611/1783] Move local copy when consuming argument passed-by-value --- include/bout/solver.hxx | 8 ++--- src/field/field2d.cxx | 2 +- src/field/field3d.cxx | 2 +- src/mesh/boundary_region.cxx | 9 +++--- src/solver/impls/slepc/slepc.hxx | 16 +++++----- src/solver/solver.cxx | 52 ++++++++++++++++---------------- src/sys/expressionparser.cxx | 3 +- 7 files changed, 47 insertions(+), 45 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 1edcde8a63..4015683a9b 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -238,10 +238,10 @@ public: /// Add constraint functions (optional). These link a variable v to /// a control parameter C_v such that v is adjusted to keep C_v = 0. - virtual void constraint(Field2D& v, Field2D& C_v, const std::string name); - virtual void constraint(Field3D& v, Field3D& C_v, const std::string name); - virtual void constraint(Vector2D& v, Vector2D& C_v, const std::string name); - virtual void constraint(Vector3D& v, Vector3D& C_v, const std::string name); + virtual void constraint(Field2D& v, Field2D& C_v, std::string name); + virtual void constraint(Field3D& v, Field3D& C_v, std::string name); + virtual void constraint(Vector2D& v, Vector2D& C_v, std::string name); + virtual void constraint(Vector3D& v, Vector3D& C_v, std::string name); /// Set a maximum internal timestep (only for explicit schemes) virtual void setMaxTimestep(BoutReal dt) { max_dt = dt; } diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index e9be1c1239..74a17f5874 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -82,7 +82,7 @@ Field2D::Field2D(BoutReal val, Mesh* localmesh) : Field2D(localmesh) { Field2D::Field2D(Array data, Mesh* localmesh, CELL_LOC datalocation, DirectionTypes directions_in) - : Field(localmesh, datalocation, directions_in), data(data) { + : Field(localmesh, datalocation, directions_in), data(std::move(data)) { ASSERT1(fieldmesh != nullptr); diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 99f5df0b91..74ec242923 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -94,7 +94,7 @@ Field3D::Field3D(const BoutReal val, Mesh* localmesh) : Field3D(localmesh) { Field3D::Field3D(Array data, Mesh* localmesh, CELL_LOC datalocation, DirectionTypes directions_in) - : Field(localmesh, datalocation, directions_in), data(data) { + : Field(localmesh, datalocation, directions_in), data(std::move(data)) { TRACE("Field3D: Copy constructor from Array and Mesh"); nx = fieldmesh->LocalNx; diff --git a/src/mesh/boundary_region.cxx b/src/mesh/boundary_region.cxx index e1bdd88201..c504cf0d9b 100644 --- a/src/mesh/boundary_region.cxx +++ b/src/mesh/boundary_region.cxx @@ -4,10 +4,11 @@ #include #include +#include using std::swap; BoundaryRegionXIn::BoundaryRegionXIn(std::string name, int ymin, int ymax, Mesh* passmesh) - : BoundaryRegion(name, -1, 0, passmesh), ys(ymin), ye(ymax) + : BoundaryRegion(std::move(name), -1, 0, passmesh), ys(ymin), ye(ymax) { location = BNDRY_XIN; width = localmesh->xstart; @@ -61,7 +62,7 @@ bool BoundaryRegionXIn::isDone() BoundaryRegionXOut::BoundaryRegionXOut(std::string name, int ymin, int ymax, Mesh* passmesh) - : BoundaryRegion(name, 1, 0, passmesh), ys(ymin), ye(ymax) + : BoundaryRegion(std::move(name), 1, 0, passmesh), ys(ymin), ye(ymax) { location = BNDRY_XOUT; width = localmesh->LocalNx - localmesh->xend - 1; @@ -115,7 +116,7 @@ bool BoundaryRegionXOut::isDone() BoundaryRegionYDown::BoundaryRegionYDown(std::string name, int xmin, int xmax, Mesh* passmesh) - : BoundaryRegion(name, 0, -1, passmesh), xs(xmin), xe(xmax) + : BoundaryRegion(std::move(name), 0, -1, passmesh), xs(xmin), xe(xmax) { location = BNDRY_YDOWN; width = localmesh->ystart; @@ -170,7 +171,7 @@ bool BoundaryRegionYDown::isDone() BoundaryRegionYUp::BoundaryRegionYUp(std::string name, int xmin, int xmax, Mesh* passmesh) - : BoundaryRegion(name, 0, 1, passmesh), xs(xmin), xe(xmax) + : BoundaryRegion(std::move(name), 0, 1, passmesh), xs(xmin), xe(xmax) { location = BNDRY_YUP; width = localmesh->LocalNy - localmesh->yend - 1; diff --git a/src/solver/impls/slepc/slepc.hxx b/src/solver/impls/slepc/slepc.hxx index 178498c984..0150260d5c 100644 --- a/src/solver/impls/slepc/slepc.hxx +++ b/src/solver/impls/slepc/slepc.hxx @@ -143,24 +143,24 @@ public: return advanceSolver->constraints(); } } - void constraint(Field2D &v, Field2D &C_v, const std::string name) override { + void constraint(Field2D &v, Field2D &C_v, std::string name) override { if (!selfSolve) { - advanceSolver->constraint(v, C_v, name); + advanceSolver->constraint(v, C_v, std::move(name)); } } - void constraint(Field3D &v, Field3D &C_v, const std::string name) override { + void constraint(Field3D &v, Field3D &C_v, std::string name) override { if (!selfSolve) { - advanceSolver->constraint(v, C_v, name); + advanceSolver->constraint(v, C_v, std::move(name)); } } - void constraint(Vector2D &v, Vector2D &C_v, const std::string name) override { + void constraint(Vector2D &v, Vector2D &C_v, std::string name) override { if (!selfSolve) { - advanceSolver->constraint(v, C_v, name); + advanceSolver->constraint(v, C_v, std::move(name)); } } - void constraint(Vector3D &v, Vector3D &C_v, const std::string name) override { + void constraint(Vector3D &v, Vector3D &C_v, std::string name) override { if (!selfSolve) { - advanceSolver->constraint(v, C_v, name); + advanceSolver->constraint(v, C_v, std::move(name)); } } diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 4702dca623..8373b4dbe1 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -276,7 +276,7 @@ void Solver::add(Vector3D& v, const std::string& name) { * Constraints **************************************************************************/ -void Solver::constraint(Field2D &v, Field2D &C_v, const std::string name) { +void Solver::constraint(Field2D &v, Field2D &C_v, std::string name) { TRACE("Constrain 2D scalar: Solver::constraint(%s)", name.c_str()); if (name.empty()) { @@ -299,12 +299,12 @@ void Solver::constraint(Field2D &v, Field2D &C_v, const std::string name) { d.constraint = true; d.var = &v; d.F_var = &C_v; - d.name = name; + d.name = std::move(name); f2d.emplace_back(std::move(d)); } -void Solver::constraint(Field3D &v, Field3D &C_v, const std::string name) { +void Solver::constraint(Field3D &v, Field3D &C_v, std::string name) { TRACE("Constrain 3D scalar: Solver::constraint(%s)", name.c_str()); if (name.empty()) { @@ -328,12 +328,12 @@ void Solver::constraint(Field3D &v, Field3D &C_v, const std::string name) { d.var = &v; d.F_var = &C_v; d.location = v.getLocation(); - d.name = name; + d.name = std::move(name); f3d.emplace_back(std::move(d)); } -void Solver::constraint(Vector2D &v, Vector2D &C_v, const std::string name) { +void Solver::constraint(Vector2D &v, Vector2D &C_v, std::string name) { TRACE("Constrain 2D vector: Solver::constraint(%s)", name.c_str()); if (name.empty()) { @@ -351,16 +351,6 @@ void Solver::constraint(Vector2D &v, Vector2D &C_v, const std::string name) { if (initialised) throw BoutException("Error: Cannot add constraints to solver after initialisation\n"); - VarStr d; - - d.constraint = true; - d.var = &v; - d.F_var = &C_v; - d.covariant = v.covariant; - d.name = name; - - v2d.emplace_back(std::move(d)); - // Add suffix, depending on co- /contravariance if (v.covariant) { constraint(v.x, C_v.x, name+"_x"); @@ -371,9 +361,19 @@ void Solver::constraint(Vector2D &v, Vector2D &C_v, const std::string name) { constraint(v.y, C_v.y, name+"y"); constraint(v.z, C_v.z, name+"z"); } + + VarStr d; + + d.constraint = true; + d.var = &v; + d.F_var = &C_v; + d.covariant = v.covariant; + d.name = std::move(name); + + v2d.emplace_back(std::move(d)); } -void Solver::constraint(Vector3D &v, Vector3D &C_v, const std::string name) { +void Solver::constraint(Vector3D &v, Vector3D &C_v, std::string name) { TRACE("Constrain 3D vector: Solver::constraint(%s)", name.c_str()); if (name.empty()) { @@ -391,16 +391,6 @@ void Solver::constraint(Vector3D &v, Vector3D &C_v, const std::string name) { if (initialised) throw BoutException("Error: Cannot add constraints to solver after initialisation\n"); - VarStr d; - - d.constraint = true; - d.var = &v; - d.F_var = &C_v; - d.covariant = v.covariant; - d.name = name; - - v3d.emplace_back(std::move(d)); - // Add suffix, depending on co- /contravariance if (v.covariant) { constraint(v.x, C_v.x, name+"_x"); @@ -411,6 +401,16 @@ void Solver::constraint(Vector3D &v, Vector3D &C_v, const std::string name) { constraint(v.y, C_v.y, name+"y"); constraint(v.z, C_v.z, name+"z"); } + + VarStr d; + + d.constraint = true; + d.var = &v; + d.F_var = &C_v; + d.covariant = v.covariant; + d.name = std::move(name); + + v3d.emplace_back(std::move(d)); } /************************************************************************** diff --git a/src/sys/expressionparser.cxx b/src/sys/expressionparser.cxx index c2aff81960..f76e1df0c0 100644 --- a/src/sys/expressionparser.cxx +++ b/src/sys/expressionparser.cxx @@ -24,6 +24,7 @@ #include +#include #include // for lowercase using std::list; @@ -124,7 +125,7 @@ ExpressionParser::ExpressionParser() { } void ExpressionParser::addGenerator(const string& name, FieldGeneratorPtr g) { - gen[name] = g; + gen[name] = std::move(g); } void ExpressionParser::addBinaryOp(char sym, FieldGeneratorPtr b, int precedence) { From 2816ba91470a5702f9d9f0f6c5855d0b5e7e965e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 17:10:54 +0100 Subject: [PATCH 1612/1783] Fix misleading indentation in multigrid solver --- src/invert/laplace/impls/multigrid/multigrid_solver.cxx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/invert/laplace/impls/multigrid/multigrid_solver.cxx b/src/invert/laplace/impls/multigrid/multigrid_solver.cxx index 47daecfae6..d1a6440efe 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_solver.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_solver.cxx @@ -95,8 +95,9 @@ Multigrid1DP::Multigrid1DP(int level,int lx, int lz, int gx, int dl, int merge, if(nz*2 <= mm) { nz = 2*nz; nx = nx/2; - } - else n = kk; + } else { + n = kk; + } } lx = gnx[0]/nx; From 96f3a7717e8dedc476ba340495cee8662de2e713 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 17:11:20 +0100 Subject: [PATCH 1613/1783] Fix redundant member initialisation --- tests/unit/mesh/data/test_gridfromoptions.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/mesh/data/test_gridfromoptions.cxx b/tests/unit/mesh/data/test_gridfromoptions.cxx index e926e83f93..0efa5be4b7 100644 --- a/tests/unit/mesh/data/test_gridfromoptions.cxx +++ b/tests/unit/mesh/data/test_gridfromoptions.cxx @@ -16,7 +16,7 @@ using namespace bout::globals; class GridFromOptionsTest : public ::testing::Test { public: - GridFromOptionsTest() : options() { + GridFromOptionsTest() { mesh_from_options.StaggerGrids = true; mesh_from_options.xstart = 2; From 685b701a5ea399f666290ed7a1b284d4da41e5f1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 17:14:09 +0100 Subject: [PATCH 1614/1783] Simplify boolean expression in H5Format::is_valid --- src/fileio/impls/hdf5/h5_format.cxx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/fileio/impls/hdf5/h5_format.cxx b/src/fileio/impls/hdf5/h5_format.cxx index f2dc17c550..837fb22dbf 100644 --- a/src/fileio/impls/hdf5/h5_format.cxx +++ b/src/fileio/impls/hdf5/h5_format.cxx @@ -148,9 +148,7 @@ bool H5Format::openw(const char *name, bool append) { } bool H5Format::is_valid() { - if(dataFile<0) - return false; - return true; + return dataFile >= 0; } void H5Format::close() { From 79fdf92b8365c02427a057794d06f60271aeb6c7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 17:15:57 +0100 Subject: [PATCH 1615/1783] Fix static member accessed through instance in OptionsReader --- src/sys/optionsreader.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/optionsreader.cxx b/src/sys/optionsreader.cxx index 05bf0a83ef..c60fc2b2f6 100644 --- a/src/sys/optionsreader.cxx +++ b/src/sys/optionsreader.cxx @@ -84,7 +84,7 @@ void OptionsReader::parseCommandLine(Options* options, int argc, char** argv) { for (int i = 1; i < argc; i++) { // Reset the section - options = options->getRoot(); + options = Options::getRoot(); buffer = argv[i]; if (buffer.length() == 0) { From 40396bb5affce6d2370ff8755fcfa37dfb514cd3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 17:20:29 +0100 Subject: [PATCH 1616/1783] Remove redundant nullptr guards around deletes It's ok to delete nullptr! --- src/field/field2d.cxx | 3 +-- src/field/field3d.cxx | 5 +---- src/mesh/mesh.cxx | 4 +--- src/solver/impls/slepc/slepc.cxx | 4 +--- src/sys/boutcomm.cxx | 2 +- 5 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 74a17f5874..aa695ad42f 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -95,8 +95,7 @@ Field2D::Field2D(Array data, Mesh* localmesh, CELL_LOC datalocation, } Field2D::~Field2D() { - if(deriv) - delete deriv; + delete deriv; } Field2D& Field2D::allocate() { diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 74ec242923..ce81221afb 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -107,10 +107,7 @@ Field3D::Field3D(Array data, Mesh* localmesh, CELL_LOC datalocation, } Field3D::~Field3D() { - /// Delete the time derivative variable if allocated - if (deriv != nullptr) { - delete deriv; - } + delete deriv; } Field3D& Field3D::allocate() { diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 45076b950a..dbbd7310f3 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -35,9 +35,7 @@ Mesh::Mesh(GridDataSource *s, Options* opt) : source(s), options(opt) { } Mesh::~Mesh() { - if (source) { - delete source; - } + delete source; } /************************************************************************** diff --git a/src/solver/impls/slepc/slepc.cxx b/src/solver/impls/slepc/slepc.cxx index 2d3ddca3c2..68dcd4e372 100644 --- a/src/solver/impls/slepc/slepc.cxx +++ b/src/solver/impls/slepc/slepc.cxx @@ -223,9 +223,7 @@ SlepcSolver::~SlepcSolver() { if (shellMat) { MatDestroy(&shellMat); }; - if (advanceSolver) { - delete advanceSolver; - }; + delete advanceSolver; initialised = false; } } diff --git a/src/sys/boutcomm.cxx b/src/sys/boutcomm.cxx index 6b0458eb06..2c6c882b37 100644 --- a/src/sys/boutcomm.cxx +++ b/src/sys/boutcomm.cxx @@ -70,6 +70,6 @@ BoutComm* BoutComm::getInstance() { } void BoutComm::cleanup() { - if(instance != nullptr) delete instance; + delete instance; instance = nullptr; } From 5f98bafb9dfdaba249f748055c6e743986333308 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 17:24:16 +0100 Subject: [PATCH 1617/1783] Use string equality instead of std::string::compare --- src/field/field2d.cxx | 2 +- src/field/field3d.cxx | 6 +++--- src/field/field_factory.cxx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index aa695ad42f..4dc179252d 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -259,7 +259,7 @@ void Field2D::applyBoundary(const std::string ®ion, const std::string &condit bool region_found = false; /// Loop over the mesh boundary regions for (const auto ® : fieldmesh->getBoundaries()) { - if (reg->label.compare(region) == 0) { + if (reg->label == region) { region_found = true; auto op = std::unique_ptr{ dynamic_cast(bfact->create(condition, reg))}; diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index ce81221afb..880790d16c 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -420,7 +420,7 @@ void Field3D::applyBoundary(const std::string ®ion, const std::string &condit bool region_found = false; /// Loop over the mesh boundary regions for (const auto ® : fieldmesh->getBoundaries()) { - if (reg->label.compare(region) == 0) { + if (reg->label == region) { region_found = true; auto op = std::unique_ptr{ dynamic_cast(bfact->create(condition, reg))}; @@ -553,7 +553,7 @@ void Field3D::applyParallelBoundary(const std::string ®ion, const std::string /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundariesPar()) { - if(reg->label.compare(region) == 0) { + if(reg->label == region) { auto op = std::unique_ptr{ dynamic_cast(bfact->create(condition, reg))}; op->apply(*this); @@ -580,7 +580,7 @@ void Field3D::applyParallelBoundary(const std::string ®ion, const std::string /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundariesPar()) { - if(reg->label.compare(region) == 0) { + if(reg->label == region) { // BoundaryFactory can't create boundaries using Field3Ds, so get temporary // boundary of the right type auto tmp = std::unique_ptr{ diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 755f09a7cc..15100e61e0 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -386,7 +386,7 @@ FieldGeneratorPtr FieldFactory::resolve(std::string& name) const { // Check if already looking up this symbol for (const auto& lookup_value : lookup) { - if (key.compare(lookup_value) == 0) { + if (key == lookup_value) { // Name matches, so already looking up output_error << "ExpressionParser lookup stack:\n"; for (const auto& stack_value : lookup) { From f62505df854977e6e3444b09c7503edf6ae31c4a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 10 May 2019 17:26:19 +0100 Subject: [PATCH 1618/1783] Remove redundant returns from void functions --- src/invert/laplace/impls/multigrid/multigrid_alg.cxx | 8 -------- src/mesh/index_derivs.cxx | 5 ----- 2 files changed, 13 deletions(-) diff --git a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx index e2283e02db..43bbc57a81 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_alg.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_alg.cxx @@ -137,7 +137,6 @@ BOUT_OMP(for) smoothings(level,sol,rhs); } - return; } void MultigridAlg::projection(int level,BoutReal *r,BoutReal *pr) @@ -164,7 +163,6 @@ BOUT_OMP(for collapse(2)) } } communications(pr,level-1); - return; } void MultigridAlg::prolongation(int level,BoutReal *x,BoutReal *ix) { @@ -194,7 +192,6 @@ BOUT_OMP(for collapse(2)) } } communications(ix,level+1); - return; } void MultigridAlg::smoothings(int level, BoutReal *x, BoutReal *b) { @@ -256,7 +253,6 @@ BOUT_OMP(for collapse(2)) } communications(x,level); } - return; } void MultigridAlg::pGMRES(BoutReal *sol,BoutReal *rhs,int level,int iplag) { @@ -457,8 +453,6 @@ BOUT_OMP(for) delete [] v[i]; } delete [] v; - - return; } void MultigridAlg::setMultigridC(int UNUSED(plag)) { @@ -758,6 +752,4 @@ BOUT_OMP(for) printf("The average error reduction of MG %d: %14.8f(%18.12f)\n",m+1,rederr,error); fflush(stdout); } - - return; } diff --git a/src/mesh/index_derivs.cxx b/src/mesh/index_derivs.cxx index bfc7f6fd72..539d5072dd 100644 --- a/src/mesh/index_derivs.cxx +++ b/src/mesh/index_derivs.cxx @@ -467,8 +467,6 @@ class FFTDerivativeType { irfft(cv.begin(), ncz, &result[i3D]); // Reverse FFT } } - - return; } template @@ -529,8 +527,6 @@ class FFT2ndDerivativeType { irfft(cv.begin(), ncz, &result[i3D]); // Reverse FFT } } - - return; } template @@ -566,7 +562,6 @@ class SplitFluxDerivativeType { result += bout::derivatives::index::standardDerivative( vel, result.getLocation(), "DEFAULT", region) * interp_to(var, result.getLocation()); - return; } metaData meta{"SPLIT", 2, DERIV::Flux}; }; From bb16ed5036762eb6862f99a3d4e49ed6a4604b85 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 20 May 2019 11:21:28 +0100 Subject: [PATCH 1619/1783] Mark lots of BoutMesh methods as override --- src/mesh/impls/bout/boutmesh.hxx | 108 +++++++++++++++---------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/src/mesh/impls/bout/boutmesh.hxx b/src/mesh/impls/bout/boutmesh.hxx index 7af52c50de..2c81d67450 100644 --- a/src/mesh/impls/bout/boutmesh.hxx +++ b/src/mesh/impls/bout/boutmesh.hxx @@ -18,10 +18,10 @@ class BoutMesh : public Mesh { public: BoutMesh(GridDataSource *s, Options *options = nullptr); - ~BoutMesh(); + ~BoutMesh() override ; /// Read in the mesh from data sources - int load(); + int load() override ; ///////////////////////////////////////////// // Communicate variables @@ -40,70 +40,70 @@ class BoutMesh : public Mesh { /// ... /// mesh->wait(handle); /// - comm_handle send(FieldGroup &g); + comm_handle send(FieldGroup &g) override ; /// Wait for a send operation to complete /// @param[in] handle The handle returned by send() - int wait(comm_handle handle); + int wait(comm_handle handle) override ; ///////////////////////////////////////////// // non-local communications - MPI_Request sendToProc(int xproc, int yproc, BoutReal *buffer, int size, int tag); - comm_handle receiveFromProc(int xproc, int yproc, BoutReal *buffer, int size, int tag); + MPI_Request sendToProc(int xproc, int yproc, BoutReal *buffer, int size, int tag) override ; + comm_handle receiveFromProc(int xproc, int yproc, BoutReal *buffer, int size, int tag) override ; - int getNXPE(); ///< The number of processors in the X direction - int getNYPE(); ///< The number of processors in the Y direction - int getXProcIndex(); ///< This processor's index in X direction - int getYProcIndex(); ///< This processor's index in Y direction + int getNXPE() override ; ///< The number of processors in the X direction + int getNYPE() override ; ///< The number of processors in the Y direction + int getXProcIndex() override ; ///< This processor's index in X direction + int getYProcIndex() override ; ///< This processor's index in Y direction ///////////////////////////////////////////// // X communications - bool firstX(); ///< Is this processor the first in X? i.e. is there a boundary to the left in X? - bool lastX(); ///< Is this processor last in X? i.e. is there a boundary to the right in X? + bool firstX() override ; ///< Is this processor the first in X? i.e. is there a boundary to the left in X? + bool lastX() override ; ///< Is this processor last in X? i.e. is there a boundary to the right in X? /// Send a buffer of data to processor at X index +1 /// /// @param[in] buffer The data to send. Must be at least length \p size /// @param[in] size The number of BoutReals to send /// @param[in] tag A label for the communication. Must be the same at receive - int sendXOut(BoutReal *buffer, int size, int tag); + int sendXOut(BoutReal *buffer, int size, int tag) override ; /// Send a buffer of data to processor at X index -1 /// /// @param[in] buffer The data to send. Must be at least length \p size /// @param[in] size The number of BoutReals to send /// @param[in] tag A label for the communication. Must be the same at receive - int sendXIn(BoutReal *buffer, int size, int tag); + int sendXIn(BoutReal *buffer, int size, int tag) override ; /// Receive a buffer of data from X index +1 /// /// @param[in] buffer A buffer to put the data in. Must already be allocated of length \p size /// @param[in] size The number of BoutReals to receive and put in \p buffer /// @param[in] tag A label for the communication. Must be the same as sent - comm_handle irecvXOut(BoutReal *buffer, int size, int tag); + comm_handle irecvXOut(BoutReal *buffer, int size, int tag) override ; /// Receive a buffer of data from X index -1 /// /// @param[in] buffer A buffer to put the data in. Must already be allocated of length \p size /// @param[in] size The number of BoutReals to receive and put in \p buffer /// @param[in] tag A label for the communication. Must be the same as sent - comm_handle irecvXIn(BoutReal *buffer, int size, int tag); + comm_handle irecvXIn(BoutReal *buffer, int size, int tag) override ; - MPI_Comm getXcomm(int UNUSED(jy)) const {return comm_x; } ///< Return communicator containing all processors in X - MPI_Comm getYcomm(int jx) const; ///< Return communicator containing all processors in Y + MPI_Comm getXcomm(int UNUSED(jy)) const override {return comm_x; } ///< Return communicator containing all processors in X + MPI_Comm getYcomm(int jx) const override ; ///< Return communicator containing all processors in Y /// Is local X index \p jx periodic in Y? /// /// \param[in] jx The local (on this processor) index in X /// \param[out] ts The Twist-Shift angle if periodic - bool periodicY(int jx, BoutReal &ts) const; + bool periodicY(int jx, BoutReal &ts) const override ; /// Is local X index \p jx periodic in Y? /// /// \param[in] jx The local (on this processor) index in X - bool periodicY(int jx) const; + bool periodicY(int jx) const override ; /// Is there a branch cut at this processor's lower boundary? /// @@ -121,62 +121,62 @@ class BoutMesh : public Mesh { /// poloidal circuit if there is a branch cut std::pair hasBranchCutUpper(int jx) const override; - int ySize(int jx) const; ///< The number of points in Y at fixed X index \p jx + int ySize(int jx) const override ; ///< The number of points in Y at fixed X index \p jx ///////////////////////////////////////////// // Y communications - bool firstY() const; - bool lastY() const; - bool firstY(int xpos) const; - bool lastY(int xpos) const; - int UpXSplitIndex(); - int DownXSplitIndex(); - int sendYOutIndest(BoutReal *buffer, int size, int tag); - int sendYOutOutdest(BoutReal *buffer, int size, int tag); - int sendYInIndest(BoutReal *buffer, int size, int tag); - int sendYInOutdest(BoutReal *buffer, int size, int tag); - comm_handle irecvYOutIndest(BoutReal *buffer, int size, int tag); - comm_handle irecvYOutOutdest(BoutReal *buffer, int size, int tag); - comm_handle irecvYInIndest(BoutReal *buffer, int size, int tag); - comm_handle irecvYInOutdest(BoutReal *buffer, int size, int tag); + bool firstY() const override ; + bool lastY() const override ; + bool firstY(int xpos) const override ; + bool lastY(int xpos) const override ; + int UpXSplitIndex() override ; + int DownXSplitIndex() override ; + int sendYOutIndest(BoutReal *buffer, int size, int tag) override ; + int sendYOutOutdest(BoutReal *buffer, int size, int tag) override ; + int sendYInIndest(BoutReal *buffer, int size, int tag) override ; + int sendYInOutdest(BoutReal *buffer, int size, int tag) override ; + comm_handle irecvYOutIndest(BoutReal *buffer, int size, int tag) override ; + comm_handle irecvYOutOutdest(BoutReal *buffer, int size, int tag) override ; + comm_handle irecvYInIndest(BoutReal *buffer, int size, int tag) override ; + comm_handle irecvYInOutdest(BoutReal *buffer, int size, int tag) override ; // Boundary iteration - const RangeIterator iterateBndryLowerY() const; - const RangeIterator iterateBndryUpperY() const; - const RangeIterator iterateBndryLowerInnerY() const; - const RangeIterator iterateBndryLowerOuterY() const; - const RangeIterator iterateBndryUpperInnerY() const; - const RangeIterator iterateBndryUpperOuterY() const; + const RangeIterator iterateBndryLowerY() const override ; + const RangeIterator iterateBndryUpperY() const override ; + const RangeIterator iterateBndryLowerInnerY() const override ; + const RangeIterator iterateBndryLowerOuterY() const override ; + const RangeIterator iterateBndryUpperInnerY() const override ; + const RangeIterator iterateBndryUpperOuterY() const override ; // Boundary regions - std::vector getBoundaries(); - std::vector getBoundariesPar(); - void addBoundaryPar(BoundaryRegionPar* bndry); + std::vector getBoundaries() override ; + std::vector getBoundariesPar() override ; + void addBoundaryPar(BoundaryRegionPar* bndry) override ; - const Field3D smoothSeparatrix(const Field3D &f); + const Field3D smoothSeparatrix(const Field3D &f) override ; int getNx() const {return nx;} int getNy() const {return ny;} - BoutReal GlobalX(int jx) const; - BoutReal GlobalY(int jy) const; - BoutReal GlobalX(BoutReal jx) const; - BoutReal GlobalY(BoutReal jy) const; + BoutReal GlobalX(int jx) const override ; + BoutReal GlobalY(int jy) const override ; + BoutReal GlobalX(BoutReal jx) const override ; + BoutReal GlobalY(BoutReal jy) const override ; BoutReal getIxseps1() const {return ixseps1;} BoutReal getIxseps2() const {return ixseps2;} - void outputVars(Datafile &file); + void outputVars(Datafile &file) override ; - int XGLOBAL(int xloc) const; - int YGLOBAL(int yloc) const; + int XGLOBAL(int xloc) const override ; + int YGLOBAL(int yloc) const override ; int XGLOBAL(BoutReal xloc, BoutReal &xglo) const; int YGLOBAL(BoutReal yloc, BoutReal &yglo) const; - int XLOCAL(int xglo) const; - int YLOCAL(int yglo) const; + int XLOCAL(int xglo) const override ; + int YLOCAL(int yglo) const override ; private: std::string gridname; From b5f6698389dcd7fa769cfca63b2dca981d96fa77 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 20 May 2019 11:23:14 +0100 Subject: [PATCH 1620/1783] Use auto when type is named on rhs --- include/cyclic_reduction.hxx | 2 +- src/sys/options.cxx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/cyclic_reduction.hxx b/include/cyclic_reduction.hxx index 2e8f302072..87b8057781 100644 --- a/include/cyclic_reduction.hxx +++ b/include/cyclic_reduction.hxx @@ -210,7 +210,7 @@ public: int ns = Nsys / nprocs; // Number of systems to assign to all processors int nsextra = Nsys % nprocs; // Number of processors with 1 extra - MPI_Request *req = new MPI_Request[nprocs]; + auto* req = new MPI_Request[nprocs]; if (myns > 0) { // Post receives from all other processors diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 774fff9d5d..0683cd2f17 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -345,8 +345,8 @@ template <> Field3D Options::as(const Field3D& similar_to) const { } if (bout::utils::holds_alternative(value)) { - const Field2D& stored_value = bout::utils::get(value); - + const auto& stored_value = bout::utils::get(value); + // Check that meta-data is consistent ASSERT1(areFieldsCompatible(stored_value, similar_to)); From f86b15354287e926b57c9bb8e28bcc5608ce78c6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 20 May 2019 11:24:13 +0100 Subject: [PATCH 1621/1783] Fix deprecated C++ header in gettext --- include/bout/sys/gettext.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/sys/gettext.hxx b/include/bout/sys/gettext.hxx index 3546921f3b..d4ead5ab44 100644 --- a/include/bout/sys/gettext.hxx +++ b/include/bout/sys/gettext.hxx @@ -6,7 +6,7 @@ #if BOUT_HAS_GETTEXT #include -#include +#include #define GETTEXT_PACKAGE "libbout" From f03c8e5eeb1d5dcd22342cd2aa405ce5af64b95a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 20 May 2019 11:25:14 +0100 Subject: [PATCH 1622/1783] Remove redundant void argument in function cast --- include/bout/invertable_operator.hxx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index cf969e7540..2ff8be019a 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -323,8 +323,7 @@ public: CHKERRQ(ierr); /// Now register Matrix_multiply operation - ierr = - MatShellSetOperation(matOperator, MATOP_MULT, (void (*)(void))(functionWrapper)); + ierr = MatShellSetOperation(matOperator, MATOP_MULT, (void (*)())(functionWrapper)); CHKERRQ(ierr); /// Create the shell matrix representing the operator to invert @@ -335,7 +334,7 @@ public: /// Now register Matrix_multiply operation ierr = MatShellSetOperation(matPreconditioner, MATOP_MULT, - (void (*)(void))(preconditionerWrapper)); + (void (*)())(preconditionerWrapper)); CHKERRQ(ierr); /// Now create and setup the linear solver with the matrix From 70b57907f3680fdbecd551f30b5887351e4af26e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 20 May 2019 11:48:35 +0100 Subject: [PATCH 1623/1783] Fix class member `data` being shadowed by moved-from `data` argument --- src/field/field2d.cxx | 4 ++-- src/field/field3d.cxx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 4dc179252d..2c1b885013 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -80,9 +80,9 @@ Field2D::Field2D(BoutReal val, Mesh* localmesh) : Field2D(localmesh) { *this = val; } -Field2D::Field2D(Array data, Mesh* localmesh, CELL_LOC datalocation, +Field2D::Field2D(Array data_in, Mesh* localmesh, CELL_LOC datalocation, DirectionTypes directions_in) - : Field(localmesh, datalocation, directions_in), data(std::move(data)) { + : Field(localmesh, datalocation, directions_in), data(std::move(data_in)) { ASSERT1(fieldmesh != nullptr); diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 880790d16c..e55aef7eef 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -92,9 +92,9 @@ Field3D::Field3D(const BoutReal val, Mesh* localmesh) : Field3D(localmesh) { *this = val; } -Field3D::Field3D(Array data, Mesh* localmesh, CELL_LOC datalocation, +Field3D::Field3D(Array data_in, Mesh* localmesh, CELL_LOC datalocation, DirectionTypes directions_in) - : Field(localmesh, datalocation, directions_in), data(std::move(data)) { + : Field(localmesh, datalocation, directions_in), data(std::move(data_in)) { TRACE("Field3D: Copy constructor from Array and Mesh"); nx = fieldmesh->LocalNx; From a1cee100c0f1a7caa51a1367645218e4c9dd9115 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 5 Jun 2019 14:24:55 +0100 Subject: [PATCH 1624/1783] Use 'override' everywhere in test_extras --- tests/unit/test_extras.hxx | 201 ++++++++++++++++++++++++------------- 1 file changed, 129 insertions(+), 72 deletions(-) diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 21a5398bb7..dde41c7bd6 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -191,92 +191,140 @@ public: addBoundary(new BoundaryRegionYDown("lower_target", xstart, xend, this)); } - comm_handle send(FieldGroup &UNUSED(g)) { return nullptr; }; - int wait(comm_handle UNUSED(handle)) { return 0; } - MPI_Request sendToProc(int UNUSED(xproc), int UNUSED(yproc), BoutReal *UNUSED(buffer), - int UNUSED(size), int UNUSED(tag)) { + comm_handle send(FieldGroup& UNUSED(g)) override { + return nullptr; + }; + int wait(comm_handle UNUSED(handle)) override { return 0; } + MPI_Request sendToProc(int UNUSED(xproc), int UNUSED(yproc), BoutReal* UNUSED(buffer), + int UNUSED(size), + int UNUSED(tag)) override { return MPI_Request(); } comm_handle receiveFromProc(int UNUSED(xproc), int UNUSED(yproc), - BoutReal *UNUSED(buffer), int UNUSED(size), - int UNUSED(tag)) { + BoutReal* UNUSED(buffer), int UNUSED(size), + int UNUSED(tag)) override { return nullptr; } - int getNXPE() { return 1; } - int getNYPE() { return 1; } - int getXProcIndex() { return 1; } - int getYProcIndex() { return 1; } - bool firstX() { return true; } - bool lastX() { return true; } - int sendXOut(BoutReal *UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) { return 0; } - int sendXIn(BoutReal *UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) { return 0; } - comm_handle irecvXOut(BoutReal *UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) { + int getNXPE() override { return 1; } + int getNYPE() override { return 1; } + int getXProcIndex() override { return 1; } + int getYProcIndex() override { return 1; } + bool firstX() override { return true; } + bool lastX() override { return true; } + int sendXOut(BoutReal* UNUSED(buffer), int UNUSED(size), + int UNUSED(tag)) override { + return 0; + } + int sendXIn(BoutReal* UNUSED(buffer), int UNUSED(size), + int UNUSED(tag)) override { + return 0; + } + comm_handle irecvXOut(BoutReal* UNUSED(buffer), int UNUSED(size), + int UNUSED(tag)) override { return nullptr; } - comm_handle irecvXIn(BoutReal *UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) { + comm_handle irecvXIn(BoutReal* UNUSED(buffer), int UNUSED(size), + int UNUSED(tag)) override { return nullptr; } - MPI_Comm getXcomm(int UNUSED(jy)) const { return MPI_COMM_NULL; } - MPI_Comm getYcomm(int UNUSED(jx)) const { return MPI_COMM_NULL; } - bool periodicY(int UNUSED(jx)) const { return true; } - bool periodicY(int UNUSED(jx), BoutReal &UNUSED(ts)) const { return true; } - std::pair hasBranchCutLower(int UNUSED(jx)) const { + MPI_Comm getXcomm(int UNUSED(jy)) const override { + return MPI_COMM_NULL; + } + MPI_Comm getYcomm(int UNUSED(jx)) const override { + return MPI_COMM_NULL; + } + bool periodicY(int UNUSED(jx)) const override { + return true; + } + bool periodicY(int UNUSED(jx), + BoutReal& UNUSED(ts)) const override { + return true; + } + std::pair + hasBranchCutLower(int UNUSED(jx)) const override { return std::make_pair(false, 0.); } - std::pair hasBranchCutUpper(int UNUSED(jx)) const { + std::pair + hasBranchCutUpper(int UNUSED(jx)) const override { return std::make_pair(false, 0.); } - bool firstY() const { return true; } - bool lastY() const { return true; } - bool firstY(int UNUSED(xpos)) const { return true; } - bool lastY(int UNUSED(xpos)) const { return true; } - int UpXSplitIndex() { return 0; } - int DownXSplitIndex() { return 0; } - int sendYOutIndest(BoutReal *UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) { + bool firstY() const override { return true; } + bool lastY() const override { return true; } + bool firstY(int UNUSED(xpos)) const override { return true; } + bool lastY(int UNUSED(xpos)) const override { return true; } + int UpXSplitIndex() override { return 0; } + int DownXSplitIndex() override { return 0; } + int sendYOutIndest(BoutReal* UNUSED(buffer), int UNUSED(size), + int UNUSED(tag)) override { return 0; } - int sendYOutOutdest(BoutReal *UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) { + int sendYOutOutdest(BoutReal* UNUSED(buffer), int UNUSED(size), + int UNUSED(tag)) override { return 0; } - int sendYInIndest(BoutReal *UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) { + int sendYInIndest(BoutReal* UNUSED(buffer), int UNUSED(size), + int UNUSED(tag)) override { return 0; } - int sendYInOutdest(BoutReal *UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) { + int sendYInOutdest(BoutReal* UNUSED(buffer), int UNUSED(size), + int UNUSED(tag)) override { return 0; } - comm_handle irecvYOutIndest(BoutReal *UNUSED(buffer), int UNUSED(size), - int UNUSED(tag)) { + comm_handle irecvYOutIndest(BoutReal* UNUSED(buffer), int UNUSED(size), + int UNUSED(tag)) override { return nullptr; } - comm_handle irecvYOutOutdest(BoutReal *UNUSED(buffer), int UNUSED(size), - int UNUSED(tag)) { + comm_handle irecvYOutOutdest(BoutReal* UNUSED(buffer), int UNUSED(size), + int UNUSED(tag)) override { return nullptr; } - comm_handle irecvYInIndest(BoutReal *UNUSED(buffer), int UNUSED(size), - int UNUSED(tag)) { + comm_handle irecvYInIndest(BoutReal* UNUSED(buffer), int UNUSED(size), + int UNUSED(tag)) override { return nullptr; } - comm_handle irecvYInOutdest(BoutReal *UNUSED(buffer), int UNUSED(size), - int UNUSED(tag)) { + comm_handle irecvYInOutdest(BoutReal* UNUSED(buffer), int UNUSED(size), + int UNUSED(tag)) override { return nullptr; } - const RangeIterator iterateBndryLowerY() const { return RangeIterator(); } - const RangeIterator iterateBndryUpperY() const { return RangeIterator(); } - const RangeIterator iterateBndryLowerOuterY() const { return RangeIterator(); } - const RangeIterator iterateBndryLowerInnerY() const { return RangeIterator(); } - const RangeIterator iterateBndryUpperOuterY() const { return RangeIterator(); } - const RangeIterator iterateBndryUpperInnerY() const { return RangeIterator(); } - void addBoundary(BoundaryRegion* region) {boundaries.push_back(region);} - std::vector getBoundaries() { return boundaries; } - std::vector getBoundariesPar() { return std::vector(); } - BoutReal GlobalX(int jx) const { return jx; } - BoutReal GlobalY(int jy) const { return jy; } - BoutReal GlobalX(BoutReal jx) const { return jx; } - BoutReal GlobalY(BoutReal jy) const { return jy; } - int XGLOBAL(int UNUSED(xloc)) const { return 0; } - int YGLOBAL(int UNUSED(yloc)) const { return 0; } - int XLOCAL(int UNUSED(xglo)) const { return 0; } - int YLOCAL(int UNUSED(yglo)) const { return 0; } + const RangeIterator iterateBndryLowerY() const override { + return RangeIterator(); + } + const RangeIterator iterateBndryUpperY() const override { + return RangeIterator(); + } + const RangeIterator + iterateBndryLowerOuterY() const override { + return RangeIterator(); + } + const RangeIterator + iterateBndryLowerInnerY() const override { + return RangeIterator(); + } + const RangeIterator + iterateBndryUpperOuterY() const override { + return RangeIterator(); + } + const RangeIterator + iterateBndryUpperInnerY() const override { + return RangeIterator(); + } + void addBoundary(BoundaryRegion* region) override { + boundaries.push_back(region); + } + std::vector getBoundaries() override { + return boundaries; + } + std::vector getBoundariesPar() override { + return std::vector(); + } + BoutReal GlobalX(int jx) const override { return jx; } + BoutReal GlobalY(int jy) const override { return jy; } + BoutReal GlobalX(BoutReal jx) const override { return jx; } + BoutReal GlobalY(BoutReal jy) const override { return jy; } + int XGLOBAL(int UNUSED(xloc)) const override { return 0; } + int YGLOBAL(int UNUSED(yloc)) const override { return 0; } + int XLOCAL(int UNUSED(xglo)) const override { return 0; } + int YLOCAL(int UNUSED(yglo)) const override { return 0; } void initDerivs(Options * opt){ StaggerGrids=true; @@ -330,44 +378,53 @@ private: /// allow testing of methods that use 'source' - in particular allowing /// source->hasXBoundaryGuards and source->hasXBoundaryGuards to be called. class FakeGridDataSource : public GridDataSource { - bool hasVar(const std::string& UNUSED(name)) { return false; } + bool hasVar(const std::string& UNUSED(name)) override { + return false; + } - bool get(Mesh* UNUSED(m), std::string& UNUSED(sval), const std::string& UNUSED(name)) { + bool get(Mesh* UNUSED(m), std::string& UNUSED(sval), + const std::string& UNUSED(name)) override { return false; } - bool get(Mesh* UNUSED(m), int& UNUSED(ival), const std::string& UNUSED(name)) { + bool get(Mesh* UNUSED(m), int& UNUSED(ival), + const std::string& UNUSED(name)) override { return false; } - bool get(Mesh* UNUSED(m), BoutReal& UNUSED(rval), const std::string& UNUSED(name)) { + bool get(Mesh* UNUSED(m), BoutReal& UNUSED(rval), + const std::string& UNUSED(name)) override { return false; } bool get(Mesh* UNUSED(m), Field2D& UNUSED(var), const std::string& UNUSED(name), - BoutReal UNUSED(def) = 0.0) { + BoutReal UNUSED(def) = 0.0) override { return false; } bool get(Mesh* UNUSED(m), Field3D& UNUSED(var), const std::string& UNUSED(name), - BoutReal UNUSED(def) = 0.0) { + BoutReal UNUSED(def) = 0.0) override { return false; } bool get(Mesh* UNUSED(m), FieldPerp& UNUSED(var), const std::string& UNUSED(name), - BoutReal UNUSED(def) = 0.0) { + BoutReal UNUSED(def) = 0.0) override { return false; } - bool get(Mesh* UNUSED(m), std::vector& UNUSED(var), - const std::string& UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, - Direction UNUSED(dir) = GridDataSource::X) { + bool + get(Mesh* UNUSED(m), std::vector& UNUSED(var), const std::string& UNUSED(name), + int UNUSED(len), int UNUSED(offset) = 0, + Direction UNUSED(dir) = GridDataSource::X) override { return false; } - bool get(Mesh* UNUSED(m), std::vector& UNUSED(var), + bool + get(Mesh* UNUSED(m), std::vector& UNUSED(var), const std::string& UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, - Direction UNUSED(dir) = GridDataSource::X) { + Direction UNUSED(dir) = GridDataSource::X) override { return false; } - bool hasXBoundaryGuards(Mesh* UNUSED(m)) { return true; } + bool hasXBoundaryGuards(Mesh* UNUSED(m)) override { + return true; + } - bool hasYBoundaryGuards() { return true; } + bool hasYBoundaryGuards() override { return true; } }; /// Test fixture to make sure the global mesh is our fake @@ -422,7 +479,7 @@ public: bout::utils::make_unique(*mesh_staggered)); } - virtual ~FakeMeshFixture() { + ~FakeMeshFixture() override { delete bout::globals::mesh; bout::globals::mesh = nullptr; delete mesh_staggered; From 7028cd0b1c7168e617dd8cb4cfb9bf4f619e3fb3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 5 Jun 2019 15:48:27 +0100 Subject: [PATCH 1625/1783] Use equals default on trivial constructors/destructors Sometimes requires members to have default initialisation --- include/boundary_op.hxx | 10 +++---- include/boundary_region.hxx | 4 +-- include/bout/fieldgroup.hxx | 7 +++-- include/bout/generic_factory.hxx | 2 +- include/bout/griddata.hxx | 2 +- include/bout/invert/laplacexz.hxx | 2 +- include/bout/invertable_operator.hxx | 2 +- include/bout/paralleltransform.hxx | 2 +- include/bout/physicsmodel.hxx | 12 ++++----- include/bout/region.hxx | 4 +-- include/bout/solverfactory.hxx | 2 +- include/bout/sys/range.hxx | 8 +++--- include/bout/sys/uncopyable.hxx | 4 +-- include/boutcomm.hxx | 8 +++--- include/cyclic_reduction.hxx | 2 +- include/datafile.hxx | 26 +++++++++---------- include/dataformat.hxx | 2 +- include/field.hxx | 12 +++------ include/fieldperp.hxx | 4 +-- include/interpolation.hxx | 2 +- include/interpolation_factory.hxx | 3 ++- include/invert_laplace.hxx | 4 +-- include/msg_stack.hxx | 4 +-- include/options.hxx | 2 +- include/parallel_boundary_op.hxx | 10 +++---- include/utils.hxx | 8 +++--- include/vector2d.hxx | 7 +++-- include/vector3d.hxx | 8 +++--- src/field/vector2d.cxx | 3 +-- src/field/vector3d.cxx | 3 +-- src/fileio/datafile.cxx | 10 ++----- src/physics/physicsmodel.cxx | 4 +-- src/sys/boutcomm.cxx | 3 +-- tests/unit/field/test_field_factory.cxx | 2 +- .../include/bout/test_generic_factory.cxx | 6 ++--- tests/unit/sys/test_expressionparser.cxx | 2 +- 36 files changed, 90 insertions(+), 106 deletions(-) diff --git a/include/boundary_op.hxx b/include/boundary_op.hxx index d0b2761bab..13bd90b820 100644 --- a/include/boundary_op.hxx +++ b/include/boundary_op.hxx @@ -18,8 +18,8 @@ class BoundaryModifier; class BoundaryOpBase { public: - BoundaryOpBase() {} - virtual ~BoundaryOpBase() {} + BoundaryOpBase() = default; + virtual ~BoundaryOpBase() = default; /// Apply a boundary condition on field f virtual void apply(Field2D &f) = 0; @@ -48,7 +48,7 @@ public: apply_to_ddt = false; } BoundaryOp(BoundaryRegion *region) {bndry = region; apply_to_ddt=false;} - ~BoundaryOp() override {} + ~BoundaryOp() override = default; // Note: All methods must implement clone, except for modifiers (see below) virtual BoundaryOp* clone(BoundaryRegion *UNUSED(region), const std::list &UNUSED(args)) { @@ -87,11 +87,11 @@ public: class BoundaryModifier : public BoundaryOp { public: - BoundaryModifier() : op(nullptr) {} + BoundaryModifier() = default; BoundaryModifier(BoundaryOp *operation) : BoundaryOp(operation->bndry), op(operation) {} virtual BoundaryOp* cloneMod(BoundaryOp *op, const std::list &args) = 0; protected: - BoundaryOp *op; + BoundaryOp* op{nullptr}; }; #endif // __BNDRY_OP__ diff --git a/include/boundary_region.hxx b/include/boundary_region.hxx index 09bdc3aa6c..d6ee650984 100644 --- a/include/boundary_region.hxx +++ b/include/boundary_region.hxx @@ -32,7 +32,7 @@ public: BoundaryRegionBase(std::string name, BndryLoc loc, Mesh *passmesh = nullptr) : localmesh(passmesh ? passmesh : bout::globals::mesh), label(std::move(name)), location(loc) {} - virtual ~BoundaryRegionBase() {} + virtual ~BoundaryRegionBase() = default; Mesh* localmesh; ///< Mesh does this boundary region belongs to @@ -56,7 +56,7 @@ public: : BoundaryRegionBase(name, loc, passmesh) {} BoundaryRegion(std::string name, int xd, int yd, Mesh *passmesh = nullptr) : BoundaryRegionBase(name, passmesh), bx(xd), by(yd), width(2) {} - ~BoundaryRegion() override {} + ~BoundaryRegion() override = default; int x,y; ///< Indices of the point in the boundary int bx, by; ///< Direction of the boundary [x+dx][y+dy] is going outwards diff --git a/include/bout/fieldgroup.hxx b/include/bout/fieldgroup.hxx index 42e7bfea39..e1ff8c070f 100644 --- a/include/bout/fieldgroup.hxx +++ b/include/bout/fieldgroup.hxx @@ -18,10 +18,9 @@ /// however Vector2D and Vector3D are stored by reference to their /// components (x,y,z) as Field2D or Field3D objects. class FieldGroup { - public: - FieldGroup() {} - - FieldGroup(const FieldGroup &other) : fvec(other.fvec), f3vec(other.f3vec) {} +public: + FieldGroup() = default; + FieldGroup(const FieldGroup& other) = default; /// Constructor with a single FieldData \p f FieldGroup(FieldData &f) { fvec.push_back(&f); } diff --git a/include/bout/generic_factory.hxx b/include/bout/generic_factory.hxx index 5b70deeb05..1911203a96 100644 --- a/include/bout/generic_factory.hxx +++ b/include/bout/generic_factory.hxx @@ -87,7 +87,7 @@ public: protected: std::map type_map; - Factory() {} + Factory() = default; }; /// Helper class for adding new types to Factory diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index c764bc58d9..b09421cf26 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -48,7 +48,7 @@ class GridDataSource; */ class GridDataSource { public: - virtual ~GridDataSource() {} + virtual ~GridDataSource() = default; virtual bool hasVar(const std::string &name) = 0; ///< Test if source can supply a variable diff --git a/include/bout/invert/laplacexz.hxx b/include/bout/invert/laplacexz.hxx index 34200a648e..0d3cea6f14 100644 --- a/include/bout/invert/laplacexz.hxx +++ b/include/bout/invert/laplacexz.hxx @@ -41,7 +41,7 @@ public: LaplaceXZ(Mesh* m = nullptr, Options* UNUSED(options) = nullptr, const CELL_LOC loc = CELL_CENTRE) : localmesh(m == nullptr ? bout::globals::mesh : m), location(loc) {} - virtual ~LaplaceXZ() {} + virtual ~LaplaceXZ() = default; virtual void setCoefs(const Field2D &A, const Field2D &B) = 0; virtual void setCoefs(const Field3D &A, const Field3D &B) { setCoefs(DC(A), DC(B)); } diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 2ff8be019a..05b5b6654b 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -134,7 +134,7 @@ public: : operatorFunction(func), preconditionerFunction(func), opt(optIn == nullptr ? optIn : Options::getRoot()->getSection("invertableOperator")), - localmesh(localmeshIn == nullptr ? bout::globals::mesh : localmeshIn), doneSetup(false) { + localmesh(localmeshIn == nullptr ? bout::globals::mesh : localmeshIn) { AUTO_TRACE(); }; diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 313bd7b2f1..e0d0735395 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -23,7 +23,7 @@ class Mesh; class ParallelTransform { public: ParallelTransform(Mesh& mesh_in) : mesh(mesh_in) {} - virtual ~ParallelTransform() {} + virtual ~ParallelTransform() = default; /// Given a 3D field, calculate and set the Y up down fields virtual void calcParallelSlices(Field3D &f) = 0; diff --git a/include/bout/physicsmodel.hxx b/include/bout/physicsmodel.hxx index c5dc6aa054..eff9860417 100644 --- a/include/bout/physicsmodel.hxx +++ b/include/bout/physicsmodel.hxx @@ -223,7 +223,7 @@ protected: void setJacobian(jacobianfunc jset) {userjacobian = jset;} /// This is set by a call to initialise, and can be used by models to specify evolving variables - Solver *solver; + Solver* solver{nullptr}; /*! * Specify a variable for the solver to evolve @@ -277,11 +277,11 @@ protected: /// write restarts and pass outputMonitor method inside a Monitor subclass PhysicsModelMonitor modelMonitor; private: - bool splitop; ///< Split operator model? - preconfunc userprecon; ///< Pointer to user-supplied preconditioner function - jacobianfunc userjacobian; ///< Pointer to user-supplied Jacobian-vector multiply function - - bool initialised; ///< True if model already initialised + bool splitop{false}; ///< Split operator model? + preconfunc userprecon{nullptr}; ///< Pointer to user-supplied preconditioner function + jacobianfunc userjacobian{nullptr}; ///< Pointer to user-supplied Jacobian-vector multiply function + + bool initialised{false}; ///< True if model already initialised }; /*! diff --git a/include/bout/region.hxx b/include/bout/region.hxx index d4a63f8bc9..ffa73d18b2 100644 --- a/include/bout/region.hxx +++ b/include/bout/region.hxx @@ -493,7 +493,7 @@ public: // Want to make this private to disable but think it may be needed as we put Regions // into maps which seems to need to be able to make "empty" objects. - Region(){}; + Region()= default;; Region(int xstart, int xend, int ystart, int yend, int zstart, int zend, int ny, int nz, int maxregionblocksize = MAXREGIONBLOCKSIZE) @@ -532,7 +532,7 @@ public: }; /// Destructor - ~Region(){}; + ~Region()= default;; /// Expose the iterator over indices for use in range-based /// for-loops or with STL algorithms, etc. diff --git a/include/bout/solverfactory.hxx b/include/bout/solverfactory.hxx index c805bfe48d..88e54cc19b 100644 --- a/include/bout/solverfactory.hxx +++ b/include/bout/solverfactory.hxx @@ -40,7 +40,7 @@ public: } private: - SolverFactory() {} + SolverFactory() = default; static SolverFactory* instance; }; diff --git a/include/bout/sys/range.hxx b/include/bout/sys/range.hxx index a99a16ece0..b1745fb8c5 100644 --- a/include/bout/sys/range.hxx +++ b/include/bout/sys/range.hxx @@ -27,7 +27,7 @@ class RangeIterator { public: /// Can be given a single range - RangeIterator() : is(1), ie(0), n(nullptr), cur(nullptr) {} + RangeIterator() = default; RangeIterator(int start, int end, RangeIterator *join = nullptr); RangeIterator(int start, int end, const RangeIterator &join); RangeIterator(const RangeIterator &r); @@ -67,9 +67,9 @@ public: RangeIterator *nextRange() const { return n; }; private: - int is, ie; - RangeIterator *n; // Next range. Doesn't change after creation - RangeIterator *cur; // Currently iterating. Changes during iteration + int is{1}, ie{0}; + RangeIterator *n{nullptr}; // Next range. Doesn't change after creation + RangeIterator *cur{nullptr}; // Currently iterating. Changes during iteration int curend; // End of current range bool delete_next = false; // Flag to delete this->n if we created it }; diff --git a/include/bout/sys/uncopyable.hxx b/include/bout/sys/uncopyable.hxx index 54d3624784..c560341d1b 100644 --- a/include/bout/sys/uncopyable.hxx +++ b/include/bout/sys/uncopyable.hxx @@ -6,8 +6,8 @@ /// Inherit from this class (private) to prevent copying class Uncopyable { protected: - Uncopyable() {} - ~Uncopyable() {} + Uncopyable() = default; + ~Uncopyable() = default; Uncopyable(const Uncopyable &) = delete; Uncopyable &operator=(const Uncopyable &) = delete; }; diff --git a/include/boutcomm.hxx b/include/boutcomm.hxx index 8beba92810..b7a196e412 100644 --- a/include/boutcomm.hxx +++ b/include/boutcomm.hxx @@ -58,9 +58,11 @@ public: private: BoutComm(); - - int *pargc; char ***pargv; ///< Command-line arguments. These can be modified by MPI init, so pointers are used - bool hasBeenSet; + + int* pargc{nullptr}; + char*** pargv{nullptr}; ///< Command-line arguments. These can be modified by MPI init, so + ///< pointers are used + bool hasBeenSet{false}; MPI_Comm comm; static BoutComm* instance; ///< The only instance of this class (Singleton) diff --git a/include/cyclic_reduction.hxx b/include/cyclic_reduction.hxx index 87b8057781..9958937e3d 100644 --- a/include/cyclic_reduction.hxx +++ b/include/cyclic_reduction.hxx @@ -58,7 +58,7 @@ template class CyclicReduce { public: CyclicReduce() = default; - CyclicReduce(MPI_Comm c, int size) : comm(c), N(size), Nsys(0) { + CyclicReduce(MPI_Comm c, int size) : comm(c), N(size) { MPI_Comm_size(c, &nprocs); MPI_Comm_rank(c, &myproc); } diff --git a/include/datafile.hxx b/include/datafile.hxx index fc57e0d4b6..c5fc486bd9 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -88,26 +88,26 @@ class Datafile { private: Mesh* mesh; - bool parallel; // Use parallel formats? - bool flush; // Flush after every write? - bool guards; // Write guard cells? - bool floats; // Low precision? - bool openclose; // Open and close file for each write + bool parallel{false}; // Use parallel formats? + bool flush{true}; // Flush after every write? + bool guards{true}; // Write guard cells? + bool floats{false}; // Low precision? + bool openclose{true}; // Open and close file for each write int Lx,Ly,Lz; // The sizes in the x-, y- and z-directions of the arrays to be written - bool enabled; // Enable / Disable writing + bool enabled{true}; // Enable / Disable writing bool init_missing; // Initialise missing variables? - bool shiftOutput; // Do we want to write out in shifted space? - bool shiftInput; // Read in shifted space? - int flushFrequencyCounter; //Counter used in determining when next openclose required - int flushFrequency; //How many write calls do we want between openclose + bool shiftOutput{false}; // Do we want to write out in shifted space? + bool shiftInput{false}; // Read in shifted space? + int flushFrequencyCounter{0}; // Counter used in determining when next openclose required + int flushFrequency{1}; // How many write calls do we want between openclose std::unique_ptr file; size_t filenamelen; static const size_t FILENAMELEN=512; char *filename; - bool writable; // is file open for writing? - bool appending; - bool first_time; // is this the first time the data will be written? + bool writable{false}; // is file open for writing? + bool appending{false}; + bool first_time{true}; // is this the first time the data will be written? /// Shallow copy, not including dataformat, therefore private Datafile(const Datafile& other); diff --git a/include/dataformat.hxx b/include/dataformat.hxx index 37f155f80c..54d683bd38 100644 --- a/include/dataformat.hxx +++ b/include/dataformat.hxx @@ -48,7 +48,7 @@ class FieldPerp; class DataFormat { public: DataFormat(Mesh* mesh_in = nullptr); - virtual ~DataFormat() { } + virtual ~DataFormat() = default; // File opening routines virtual bool openr(const char *name) = 0; virtual bool openr(const std::string &name) { diff --git a/include/field.hxx b/include/field.hxx index 2329c3c17b..6225d5eb5f 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -60,19 +60,13 @@ class Coordinates; * Defines the virtual function SetStencil, used by differencing methods */ class Field { - public: +public: Field() = default; + Field(const Field& other) = default; + virtual ~Field() = default; Field(Mesh* localmesh, CELL_LOC location_in, DirectionTypes directions_in); - // Copy constructor - Field(const Field& f) - : name(f.name), fieldmesh(f.fieldmesh), - fieldCoordinates(f.fieldCoordinates), location(f.location), - directions(f.directions) {} - - virtual ~Field() { } - /// Set variable location for staggered grids to @param new_location /// /// Throws BoutException if new_location is not `CELL_CENTRE` and diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index 63c3e4a336..d3098cbab8 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -62,7 +62,7 @@ class FieldPerp : public Field { * will be shared (non unique) */ FieldPerp(const FieldPerp& f) - : Field(f), yindex(f.yindex), nx(f.nx), nz(f.nz), data(f.data) {} + = default; /*! * Move constructor @@ -76,7 +76,7 @@ class FieldPerp : public Field { */ FieldPerp(BoutReal val, Mesh *localmesh = nullptr); - ~FieldPerp() override {} + ~FieldPerp() override = default; /*! * Assignment operators diff --git a/include/interpolation.hxx b/include/interpolation.hxx index ab20c0e1ae..754e13c324 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -231,7 +231,7 @@ public: : Interpolation(y_offset, mesh) { skip_mask = mask; } - virtual ~Interpolation() {} + virtual ~Interpolation() = default; virtual void calcWeights(const Field3D &delta_x, const Field3D &delta_z) = 0; virtual void calcWeights(const Field3D &delta_x, const Field3D &delta_z, diff --git a/include/interpolation_factory.hxx b/include/interpolation_factory.hxx index d76f2d5854..05197c5de4 100644 --- a/include/interpolation_factory.hxx +++ b/include/interpolation_factory.hxx @@ -34,7 +34,8 @@ private: CreateInterpCallback findInterpolation(const std::string& name); public: - ~InterpolationFactory(){}; + ~InterpolationFactory() = default; + ; /// Create or get the singleton instance of the factory static InterpolationFactory* getInstance(); diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index 68b1d30f91..a13763ebdf 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -120,8 +120,8 @@ const int INVERT_OUT_RHS = 32768; ///< Use input value in RHS at outer boundary class Laplacian { public: Laplacian(Options *options = nullptr, const CELL_LOC loc = CELL_CENTRE, Mesh* mesh_in = nullptr); - virtual ~Laplacian() {} - + virtual ~Laplacian() = default; + /// Set coefficients for inversion. Re-builds matrices if necessary virtual void setCoefA(const Field2D &val) = 0; virtual void setCoefA(const Field3D &val) { setCoefA(DC(val)); } diff --git a/include/msg_stack.hxx b/include/msg_stack.hxx index 1b84d24d2e..e580ab7351 100644 --- a/include/msg_stack.hxx +++ b/include/msg_stack.hxx @@ -65,7 +65,7 @@ class MsgStack; */ class MsgStack { public: - MsgStack() : position(0){}; + MsgStack() = default;; ~MsgStack() { clear(); } #if CHECK > 1 @@ -100,7 +100,7 @@ private: char buffer[256]; ///< Buffer for vsnprintf std::vector stack; ///< Message stack; - std::vector::size_type position; ///< Position in stack + std::vector::size_type position{0}; ///< Position in stack }; /*! diff --git a/include/options.hxx b/include/options.hxx index 21adc01995..89c3e394c4 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -195,7 +195,7 @@ public: /// Constructor AttributeType() = default; /// Copy constructor - AttributeType(const AttributeType& other) : Base(other) {} + AttributeType(const AttributeType& other) = default; /// Move constructor AttributeType(AttributeType&& other) : Base(std::move(other)) {} diff --git a/include/parallel_boundary_op.hxx b/include/parallel_boundary_op.hxx index 29a3caacc6..a8e595df01 100644 --- a/include/parallel_boundary_op.hxx +++ b/include/parallel_boundary_op.hxx @@ -14,7 +14,7 @@ class BoundaryOpPar : public BoundaryOpBase { public: - BoundaryOpPar() : bndry(nullptr), real_value(0.), value_type(REAL) {} + BoundaryOpPar() = default; BoundaryOpPar(BoundaryRegionPar *region, std::shared_ptr value) : bndry(region), gen_values(std::move(value)), value_type(GEN) {} BoundaryOpPar(BoundaryRegionPar *region, Field3D* value) : @@ -25,7 +25,7 @@ public: bndry(region), real_value(value), value_type(REAL) {} - ~BoundaryOpPar() override {} + ~BoundaryOpPar() override = default; // Note: All methods must implement clone, except for modifiers (see below) virtual BoundaryOpPar* clone(BoundaryRegionPar *UNUSED(region), const std::list &UNUSED(args)) {return nullptr; } @@ -46,18 +46,18 @@ public: throw BoutException("Can't apply parallel boundary conditions to Field2D!"); } - BoundaryRegionPar *bndry; + BoundaryRegionPar* bndry{nullptr}; protected: /// Possible ways to get boundary values std::shared_ptr gen_values; Field3D* field_values; - BoutReal real_value; + BoutReal real_value{0.}; /// Where to take boundary values from - the generator, field or BoutReal enum ValueType { GEN, FIELD, REAL }; - const ValueType value_type; + const ValueType value_type{REAL}; BoutReal getValue(int x, int y, int z, BoutReal t); BoutReal getValue(const BoundaryRegionPar &bndry, BoutReal t); diff --git a/include/utils.hxx b/include/utils.hxx index 13d14ca73b..03023a279b 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -130,7 +130,7 @@ public: using data_type = T; using size_type = int; - Matrix() : n1(0), n2(0){}; + Matrix() = default;; Matrix(size_type n1, size_type n2) : n1(n1), n2(n2) { ASSERT2(n1 >= 0); ASSERT2(n2 >= 0); @@ -204,7 +204,7 @@ public: const Array& getData() const { return data; } private: - size_type n1, n2; + size_type n1{0}, n2{0}; /// Underlying 1D storage array Array data; }; @@ -221,7 +221,7 @@ public: using data_type = T; using size_type = int; - Tensor() : n1(0), n2(0), n3(0) {}; + Tensor() = default;; Tensor(size_type n1, size_type n2, size_type n3) : n1(n1), n2(n2), n3(n3) { ASSERT2(n1 >= 0); ASSERT2(n2 >= 0); @@ -302,7 +302,7 @@ public: const Array& getData() const { return data; } private: - size_type n1, n2, n3; + size_type n1{0}, n2{0}, n3{0}; /// Underlying 1D storage array Array data; }; diff --git a/include/vector2d.hxx b/include/vector2d.hxx index bd7be6722f..505e9a73cb 100644 --- a/include/vector2d.hxx +++ b/include/vector2d.hxx @@ -53,7 +53,7 @@ class Vector2D : public FieldData { Field2D x, y, z; ///< components - bool covariant; ///< true if the components are covariant (default) + bool covariant{true}; ///< true if the components are covariant (default) /// In-place conversion to covariant form void toCovariant(); @@ -153,9 +153,8 @@ class Vector2D : public FieldData { void applyBoundary(const char* condition) { applyBoundary(std::string(condition)); } void applyTDerivBoundary() override; private: - - Vector2D *deriv; ///< Time-derivative, can be NULL - CELL_LOC location; ///< Location of the variable in the cell + Vector2D* deriv{nullptr}; ///< Time-derivative, can be NULL + CELL_LOC location{CELL_CENTRE}; ///< Location of the variable in the cell }; // Non-member overloaded operators diff --git a/include/vector3d.hxx b/include/vector3d.hxx index 09df39c7f7..f2ff7d7c2c 100644 --- a/include/vector3d.hxx +++ b/include/vector3d.hxx @@ -92,8 +92,8 @@ class Vector3D : public FieldData { * * Only modify this variable directly if you know what you are doing! * - */ - bool covariant; + */ + bool covariant{true}; /*! * In-place conversion to covariant form. @@ -196,8 +196,8 @@ class Vector3D : public FieldData { void applyBoundary(const char* condition) { applyBoundary(std::string(condition)); } void applyTDerivBoundary() override; private: - Vector3D *deriv; ///< Time-derivative, can be NULL - CELL_LOC location; ///< Location of the variable in the cell + Vector3D* deriv{nullptr}; ///< Time-derivative, can be NULL + CELL_LOC location{CELL_CENTRE}; ///< Location of the variable in the cell }; // Non-member overloaded operators diff --git a/src/field/vector2d.cxx b/src/field/vector2d.cxx index 1dc3d7a2c3..6925279364 100644 --- a/src/field/vector2d.cxx +++ b/src/field/vector2d.cxx @@ -36,8 +36,7 @@ #include #include -Vector2D::Vector2D(Mesh *localmesh) - : x(localmesh), y(localmesh), z(localmesh), covariant(true), deriv(nullptr), location(CELL_CENTRE) {} +Vector2D::Vector2D(Mesh* localmesh) : x(localmesh), y(localmesh), z(localmesh) {} Vector2D::Vector2D(const Vector2D &f) : x(f.x), y(f.y), z(f.z), covariant(f.covariant), deriv(nullptr), diff --git a/src/field/vector3d.cxx b/src/field/vector3d.cxx index 8c06f2755a..eb4ef000da 100644 --- a/src/field/vector3d.cxx +++ b/src/field/vector3d.cxx @@ -37,8 +37,7 @@ #include #include -Vector3D::Vector3D(Mesh *localmesh) - : x(localmesh), y(localmesh), z(localmesh), covariant(true), deriv(nullptr), location(CELL_CENTRE) {} +Vector3D::Vector3D(Mesh* localmesh) : x(localmesh), y(localmesh), z(localmesh) {} Vector3D::Vector3D(const Vector3D &f) : x(f.x), y(f.y), z(f.z), covariant(f.covariant), deriv(nullptr), diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 82c0569511..1a6e4fd46b 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -49,13 +49,8 @@ #include #include "formatfactory.hxx" -Datafile::Datafile(Options *opt, Mesh* mesh_in) - : mesh(mesh_in==nullptr ? bout::globals::mesh : mesh_in), - parallel(false), flush(true), guards(true), floats(false), openclose(true), - enabled(true), shiftOutput(false), shiftInput(false), - flushFrequencyCounter(0), flushFrequency(1), file(nullptr), writable(false), - appending(false), first_time(true) -{ +Datafile::Datafile(Options* opt, Mesh* mesh_in) + : mesh(mesh_in == nullptr ? bout::globals::mesh : mesh_in), file(nullptr) { filenamelen=FILENAMELEN; filename=new char[filenamelen]; filename[0] = 0; // Terminate the string @@ -75,7 +70,6 @@ Datafile::Datafile(Options *opt, Mesh* mesh_in) OPTION(opt, shiftOutput, false); // Do we want to write 3D fields in shifted space? OPTION(opt, shiftInput, false); // Do we want to read 3D fields in shifted space? OPTION(opt, flushFrequency, 1); // How frequently do we flush the file - } Datafile::Datafile(Datafile &&other) noexcept diff --git a/src/physics/physicsmodel.cxx b/src/physics/physicsmodel.cxx index d3cdfbc6bd..abe0190d46 100644 --- a/src/physics/physicsmodel.cxx +++ b/src/physics/physicsmodel.cxx @@ -34,9 +34,7 @@ #include -PhysicsModel::PhysicsModel() - : solver(nullptr), modelMonitor(this), splitop(false), userprecon(nullptr), - userjacobian(nullptr), initialised(false) { +PhysicsModel::PhysicsModel() : modelMonitor(this) { // Set up restart file restart = Datafile(Options::getRoot()->getSection("restart")); diff --git a/src/sys/boutcomm.cxx b/src/sys/boutcomm.cxx index 2c6c882b37..9e24b35c3b 100644 --- a/src/sys/boutcomm.cxx +++ b/src/sys/boutcomm.cxx @@ -3,8 +3,7 @@ BoutComm* BoutComm::instance = nullptr; -BoutComm::BoutComm() - : pargc(nullptr), pargv(nullptr), hasBeenSet(false), comm(MPI_COMM_NULL) {} +BoutComm::BoutComm() : comm(MPI_COMM_NULL) {} BoutComm::~BoutComm() { if(comm != MPI_COMM_NULL) diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index d11d0fb2bc..bdf66ae0fa 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -609,7 +609,7 @@ TYPED_TEST(FieldFactoryCreationTest, CreateOnMeshWithoutCoordinates) { class FieldFactoryTest : public FakeMeshFixture { public: FieldFactoryTest() : FakeMeshFixture{}, factory{mesh} {} - virtual ~FieldFactoryTest() {} + virtual ~FieldFactoryTest() = default; WithQuietOutput quiet_info{output_info}, quiet{output}, quiet_error{output_error}; diff --git a/tests/unit/include/bout/test_generic_factory.cxx b/tests/unit/include/bout/test_generic_factory.cxx index f91e1a3fa9..dc592a010b 100644 --- a/tests/unit/include/bout/test_generic_factory.cxx +++ b/tests/unit/include/bout/test_generic_factory.cxx @@ -10,19 +10,19 @@ class Base { public: - Base() {} + Base() = default; virtual std::string foo() { return "Base"; } }; class Derived1 : public Base { public: - Derived1() {} + Derived1() = default; std::string foo() override { return "Derived1"; } }; class Derived2 : public Base { public: - Derived2() {} + Derived2() = default; std::string foo() override { return "Derived2"; } }; diff --git a/tests/unit/sys/test_expressionparser.cxx b/tests/unit/sys/test_expressionparser.cxx index 5d4e48c75e..61237d564f 100644 --- a/tests/unit/sys/test_expressionparser.cxx +++ b/tests/unit/sys/test_expressionparser.cxx @@ -79,7 +79,7 @@ class IncrementGenerator : public FieldGenerator { // Function that takes no arguments and returns 4.0 class NullaryGenerator : public FieldGenerator { public: - NullaryGenerator() {} + NullaryGenerator() = default; std::shared_ptr clone(const std::list> args) { From 895c4c5e074cfd4dd5e7f94f6c94abc84a307c24 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 5 Jun 2019 15:50:49 +0100 Subject: [PATCH 1626/1783] Provide default copy and move ctors/assignment for Field/FieldGroup The implicitly provided ones are deprecated in C++11 --- include/bout/fieldgroup.hxx | 3 +++ include/field.hxx | 3 +++ 2 files changed, 6 insertions(+) diff --git a/include/bout/fieldgroup.hxx b/include/bout/fieldgroup.hxx index e1ff8c070f..d0d5130286 100644 --- a/include/bout/fieldgroup.hxx +++ b/include/bout/fieldgroup.hxx @@ -21,6 +21,9 @@ class FieldGroup { public: FieldGroup() = default; FieldGroup(const FieldGroup& other) = default; + FieldGroup(FieldGroup&& other) = default; + FieldGroup& operator=(const FieldGroup& other) = default; + FieldGroup& operator=(FieldGroup&& other) = default; /// Constructor with a single FieldData \p f FieldGroup(FieldData &f) { fvec.push_back(&f); } diff --git a/include/field.hxx b/include/field.hxx index 6225d5eb5f..e3b4ac6d61 100644 --- a/include/field.hxx +++ b/include/field.hxx @@ -63,6 +63,9 @@ class Field { public: Field() = default; Field(const Field& other) = default; + Field(Field&& other) = default; + Field& operator=(const Field& other) = default; + Field& operator=(Field&& other) = default; virtual ~Field() = default; Field(Mesh* localmesh, CELL_LOC location_in, DirectionTypes directions_in); From abb18bc2ac441bbb587bc4cb5599d0e22d362604 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 20 Jun 2019 15:30:11 +0100 Subject: [PATCH 1627/1783] Mark some internal options_netcdf functions as maybe_unused --- src/sys/options/options_netcdf.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 677f603972..3723b523d7 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -164,7 +164,7 @@ NcType NcTypeVisitor::operator()(const double& UNUSED(t)) { } template <> -NcType NcTypeVisitor::operator()(const float& UNUSED(t)) { +MAYBE_UNUSED() NcType NcTypeVisitor::operator()(const float& UNUSED(t)) { return ncFloat; } @@ -347,7 +347,7 @@ void NcPutAttVisitor::operator()(const double& value) { var.putAtt(name, ncDouble, value); } template <> -void NcPutAttVisitor::operator()(const float& value) { +MAYBE_UNUSED() void NcPutAttVisitor::operator()(const float& value) { var.putAtt(name, ncFloat, value); } template <> From eec8e1c58d5c0e82462a4b9b530ba50ed72598f3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 20 Jun 2019 16:05:56 +0100 Subject: [PATCH 1628/1783] Use nullptr instead of NULL --- tests/unit/sys/test_optionsreader.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/sys/test_optionsreader.cxx b/tests/unit/sys/test_optionsreader.cxx index 5df3b32a18..734e92bacd 100644 --- a/tests/unit/sys/test_optionsreader.cxx +++ b/tests/unit/sys/test_optionsreader.cxx @@ -44,7 +44,7 @@ class OptionsReaderTest : public ::testing::Test { TEST_F(OptionsReaderTest, BadFilename) { OptionsReader reader; - EXPECT_THROW(reader.read(nullptr, NULL), BoutException); + EXPECT_THROW(reader.read(nullptr, nullptr), BoutException); } TEST_F(OptionsReaderTest, BadCommandLineMultipleEquals) { From 9e27f31491fe600a2b106cc4c2d2c16e6bdb6cc2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 20 Jun 2019 16:07:35 +0100 Subject: [PATCH 1629/1783] Mark more methods as override --- include/bout/physicsmodel.hxx | 2 +- tests/integrated/test-delp2/test_delp2.cxx | 4 ++-- tests/unit/field/test_vector3d.cxx | 2 +- tests/unit/include/bout/test_deriv_store.cxx | 2 +- .../include/test_interpolation_factory.cxx | 2 +- tests/unit/sys/test_expressionparser.cxx | 20 ++++++++++--------- tests/unit/sys/test_options_netcdf.cxx | 2 +- tests/unit/sys/test_optionsreader.cxx | 2 +- 8 files changed, 19 insertions(+), 17 deletions(-) diff --git a/include/bout/physicsmodel.hxx b/include/bout/physicsmodel.hxx index eff9860417..2e6d99db7c 100644 --- a/include/bout/physicsmodel.hxx +++ b/include/bout/physicsmodel.hxx @@ -264,7 +264,7 @@ protected: public: PhysicsModelMonitor() = delete; PhysicsModelMonitor(PhysicsModel *model) : model(model) {} - int call(Solver* UNUSED(solver), BoutReal simtime, int iter, int nout) { + int call(Solver* UNUSED(solver), BoutReal simtime, int iter, int nout) override { // Save state to restart file model->restart.write(); // Call user output monitor diff --git a/tests/integrated/test-delp2/test_delp2.cxx b/tests/integrated/test-delp2/test_delp2.cxx index 283b314bff..0e4913f056 100644 --- a/tests/integrated/test-delp2/test_delp2.cxx +++ b/tests/integrated/test-delp2/test_delp2.cxx @@ -4,7 +4,7 @@ class TestDelp2 : public PhysicsModel { protected: - int init(bool UNUSED(restarting)) { + int init(bool UNUSED(restarting)) override { Options *opt = Options::getRoot()->getSection("diffusion"); OPTION(opt, D, 0.1); OPTION(opt, useFFT, true); @@ -14,7 +14,7 @@ class TestDelp2 : public PhysicsModel { return 0; } - int rhs(BoutReal UNUSED(t)) { + int rhs(BoutReal UNUSED(t)) override { mesh->communicate(n); ddt(n) = D * Delp2(n, CELL_DEFAULT, useFFT); diff --git a/tests/unit/field/test_vector3d.cxx b/tests/unit/field/test_vector3d.cxx index 7cb81beddc..3c8a75ff63 100644 --- a/tests/unit/field/test_vector3d.cxx +++ b/tests/unit/field/test_vector3d.cxx @@ -56,7 +56,7 @@ class Vector3DTest : public ::testing::Test { mesh_staggered->createDefaultRegions(); } - virtual ~Vector3DTest() { + ~Vector3DTest() override { if (mesh != nullptr) { // Delete boundary regions for (auto &r : mesh->getBoundaries()) { diff --git a/tests/unit/include/bout/test_deriv_store.cxx b/tests/unit/include/bout/test_deriv_store.cxx index 5e96dce2e0..649450097a 100644 --- a/tests/unit/include/bout/test_deriv_store.cxx +++ b/tests/unit/include/bout/test_deriv_store.cxx @@ -26,7 +26,7 @@ void flowReturnSixSetToTwo(const FieldType& UNUSED(vel), const FieldType& UNUSED class DerivativeStoreTest : public ::testing::Test { public: DerivativeStoreTest() : store(DerivativeStore::getInstance()) {} - virtual ~DerivativeStoreTest() { store.reset(); } + ~DerivativeStoreTest() override { store.reset(); } DerivativeStore& store; }; diff --git a/tests/unit/include/test_interpolation_factory.cxx b/tests/unit/include/test_interpolation_factory.cxx index 307eebc080..de69cce9a8 100644 --- a/tests/unit/include/test_interpolation_factory.cxx +++ b/tests/unit/include/test_interpolation_factory.cxx @@ -54,7 +54,7 @@ class InterpolationFactoryTest : public FakeMeshFixture { output_info.disable(); output_warn.disable(); } - ~InterpolationFactoryTest() { + ~InterpolationFactoryTest() override { output_warn.enable(); output_info.enable(); InterpolationFactory::getInstance()->cleanup(); diff --git a/tests/unit/sys/test_expressionparser.cxx b/tests/unit/sys/test_expressionparser.cxx index 61237d564f..4decd8ccaa 100644 --- a/tests/unit/sys/test_expressionparser.cxx +++ b/tests/unit/sys/test_expressionparser.cxx @@ -15,7 +15,7 @@ class ExpressionParserSubClass : public ExpressionParser { class ExpressionParserTest : public ::testing::Test { public: - virtual ~ExpressionParserTest() = default; + ~ExpressionParserTest() override = default; ExpressionParserSubClass parser; std::vector x_array = {-1., 0., 1., 5., 10., 3.14e8}; std::vector y_array = {-1., 0., 1., 5., 10., 3.14e8}; @@ -31,7 +31,7 @@ class BinaryGenerator : public FieldGenerator { : a(a), b(b) {} std::shared_ptr - clone(const std::list> args) { + clone(const std::list> args) override { if (args.size() != 2) { throw ParseException( "Incorrect number of arguments to increment function. Expecting 2, got %zu", @@ -41,10 +41,10 @@ class BinaryGenerator : public FieldGenerator { return std::make_shared(args.front(), args.back()); } - BoutReal generate(BoutReal x, BoutReal y, BoutReal z, BoutReal t) { + BoutReal generate(BoutReal x, BoutReal y, BoutReal z, BoutReal t) override { return a->generate(x, y, z, t) + b->generate(x, y, z, t); } - std::string str() const { + std::string str() const override { return std::string{"add(" + a->str() + ", " + b->str() + ")"}; } @@ -57,7 +57,7 @@ class IncrementGenerator : public FieldGenerator { IncrementGenerator(std::shared_ptr gen = nullptr) : gen(gen) {} std::shared_ptr - clone(const std::list> args) { + clone(const std::list> args) override { if (args.size() != 1) { throw ParseException( "Incorrect number of arguments to increment function. Expecting 1, got %d", @@ -67,10 +67,12 @@ class IncrementGenerator : public FieldGenerator { return std::make_shared(args.front()); } - BoutReal generate(BoutReal x, BoutReal y, BoutReal z, BoutReal t) { + BoutReal generate(BoutReal x, BoutReal y, BoutReal z, BoutReal t) override { return gen->generate(x, y, z, t) + 1; } - std::string str() const { return std::string{"increment(" + gen->str() + ")"}; } + std::string str() const override { + return std::string{"increment(" + gen->str() + ")"}; + } private: std::shared_ptr gen; @@ -82,7 +84,7 @@ class NullaryGenerator : public FieldGenerator { NullaryGenerator() = default; std::shared_ptr - clone(const std::list> args) { + clone(const std::list> args) override { if (args.size() != 0) { throw ParseException( "Incorrect number of arguments to nullary function. Expecting 0, got %d", @@ -93,7 +95,7 @@ class NullaryGenerator : public FieldGenerator { } BoutReal generate(BoutReal UNUSED(x), BoutReal UNUSED(y), BoutReal UNUSED(z), - BoutReal UNUSED(t)) { + BoutReal UNUSED(t)) override { return 4.0; } }; diff --git a/tests/unit/sys/test_options_netcdf.cxx b/tests/unit/sys/test_options_netcdf.cxx index 98e92cff55..2bc84841ba 100644 --- a/tests/unit/sys/test_options_netcdf.cxx +++ b/tests/unit/sys/test_options_netcdf.cxx @@ -24,7 +24,7 @@ extern Mesh* mesh; class OptionsNetCDFTest: public FakeMeshFixture { public: OptionsNetCDFTest() : FakeMeshFixture() {} - virtual ~OptionsNetCDFTest() { std::remove(filename.c_str()); } + ~OptionsNetCDFTest() override { std::remove(filename.c_str()); } // A temporary filename std::string filename{std::tmpnam(nullptr)}; diff --git a/tests/unit/sys/test_optionsreader.cxx b/tests/unit/sys/test_optionsreader.cxx index 734e92bacd..08dfcb31db 100644 --- a/tests/unit/sys/test_optionsreader.cxx +++ b/tests/unit/sys/test_optionsreader.cxx @@ -20,7 +20,7 @@ class OptionsReaderTest : public ::testing::Test { std::cout.rdbuf(buffer.rdbuf()); } - virtual ~OptionsReaderTest() { + ~OptionsReaderTest() override { // Clear buffer buffer.str(""); // When done redirect cout to its old self From f722f4c59f29e4eafa722888762fa7fcc0c837c8 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 20 Jun 2019 16:08:23 +0100 Subject: [PATCH 1630/1783] Make =deleted constructors public --- include/bout/sys/uncopyable.hxx | 1 + 1 file changed, 1 insertion(+) diff --git a/include/bout/sys/uncopyable.hxx b/include/bout/sys/uncopyable.hxx index c560341d1b..3091fb9fad 100644 --- a/include/bout/sys/uncopyable.hxx +++ b/include/bout/sys/uncopyable.hxx @@ -8,6 +8,7 @@ class Uncopyable { protected: Uncopyable() = default; ~Uncopyable() = default; +public: Uncopyable(const Uncopyable &) = delete; Uncopyable &operator=(const Uncopyable &) = delete; }; From 35e08b32b5438e96ec4f266728a52f633e634365 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 20 Jun 2019 16:09:25 +0100 Subject: [PATCH 1631/1783] Take constructor arguments by value and std::move --- include/options.hxx | 2 +- include/options_netcdf.hxx | 5 +++-- tests/unit/include/bout/test_generic_factory.cxx | 6 +++--- tests/unit/sys/test_expressionparser.cxx | 5 +++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/options.hxx b/include/options.hxx index 89c3e394c4..2d9936e616 100644 --- a/include/options.hxx +++ b/include/options.hxx @@ -576,7 +576,7 @@ public: /// This constructor needed for map::emplace /// Can be removed in C++17 with map::insert and brace initialisation OptionValue(std::string value, std::string source, bool used) - : value(value), source(source), used(used) {} + : value(std::move(value)), source(std::move(source)), used(used) {} }; /// Read-only access to internal options and sections diff --git a/include/options_netcdf.hxx b/include/options_netcdf.hxx index db7145511c..c90b0f62fb 100644 --- a/include/options_netcdf.hxx +++ b/include/options_netcdf.hxx @@ -52,8 +52,9 @@ public: replace, ///< Overwrite file when writing append ///< Append to file when writing }; - - OptionsNetCDF(const std::string &filename, FileMode mode = FileMode::replace) : filename(filename), file_mode(mode) {} + + OptionsNetCDF(std::string filename, FileMode mode = FileMode::replace) + : filename(std::move(filename)), file_mode(mode) {} /// Read options from file Options read(); diff --git a/tests/unit/include/bout/test_generic_factory.cxx b/tests/unit/include/bout/test_generic_factory.cxx index dc592a010b..b5d66576b6 100644 --- a/tests/unit/include/bout/test_generic_factory.cxx +++ b/tests/unit/include/bout/test_generic_factory.cxx @@ -35,18 +35,18 @@ RegisterInFactory registerme2("derived2"); class BaseComplicated { public: std::string name; - BaseComplicated(std::string name) : name(name) {} + BaseComplicated(std::string name) : name(std::move(name)) {} virtual std::string foo() { return name; } }; class DerivedComplicated1 : public BaseComplicated { public: - DerivedComplicated1(std::string name) : BaseComplicated(name) {} + DerivedComplicated1(std::string name) : BaseComplicated(std::move(name)) {} }; class DerivedComplicated2 : public BaseComplicated { public: - DerivedComplicated2(std::string name) : BaseComplicated(name) {} + DerivedComplicated2(std::string name) : BaseComplicated(std::move(name)) {} }; // Save some typing later diff --git a/tests/unit/sys/test_expressionparser.cxx b/tests/unit/sys/test_expressionparser.cxx index 4decd8ccaa..dbfebc8ae6 100644 --- a/tests/unit/sys/test_expressionparser.cxx +++ b/tests/unit/sys/test_expressionparser.cxx @@ -28,7 +28,7 @@ class BinaryGenerator : public FieldGenerator { public: BinaryGenerator(std::shared_ptr a = nullptr, std::shared_ptr b = nullptr) - : a(a), b(b) {} + : a(std::move(a)), b(std::move(b)) {} std::shared_ptr clone(const std::list> args) override { @@ -54,7 +54,8 @@ class BinaryGenerator : public FieldGenerator { class IncrementGenerator : public FieldGenerator { public: - IncrementGenerator(std::shared_ptr gen = nullptr) : gen(gen) {} + IncrementGenerator(std::shared_ptr gen = nullptr) + : gen(std::move(gen)) {} std::shared_ptr clone(const std::list> args) override { From e723692e1e054ffbf4acb7170db65f7236d0d7f2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 20 Jun 2019 16:09:52 +0100 Subject: [PATCH 1632/1783] Make sure base classes have virtual destructor --- tests/unit/include/bout/test_generic_factory.cxx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/unit/include/bout/test_generic_factory.cxx b/tests/unit/include/bout/test_generic_factory.cxx index b5d66576b6..65903bc7f1 100644 --- a/tests/unit/include/bout/test_generic_factory.cxx +++ b/tests/unit/include/bout/test_generic_factory.cxx @@ -10,19 +10,17 @@ class Base { public: - Base() = default; + virtual ~Base() = default; virtual std::string foo() { return "Base"; } }; class Derived1 : public Base { public: - Derived1() = default; std::string foo() override { return "Derived1"; } }; class Derived2 : public Base { public: - Derived2() = default; std::string foo() override { return "Derived2"; } }; @@ -36,6 +34,7 @@ class BaseComplicated { public: std::string name; BaseComplicated(std::string name) : name(std::move(name)) {} + virtual ~BaseComplicated() = default; virtual std::string foo() { return name; } }; From fab91b23a717e74bf56638db64e606e621b611da Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 20 Jun 2019 16:10:12 +0100 Subject: [PATCH 1633/1783] Fix deprecated header --- tests/unit/bout_test_main.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/bout_test_main.cxx b/tests/unit/bout_test_main.cxx index a8a113ff6e..e72bc5a785 100644 --- a/tests/unit/bout_test_main.cxx +++ b/tests/unit/bout_test_main.cxx @@ -1,4 +1,4 @@ -#include +#include #include "gtest/gtest.h" #include "bout/array.hxx" From e3674f2cba52b4f426d7667816a27aa45207770a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 20 Jun 2019 17:01:09 +0100 Subject: [PATCH 1634/1783] Rename 'coordinates_type' gridfile attribute to 'parallel_transform' Was just a synonym for the compatible parallel transform anyway --- include/bout/paralleltransform.hxx | 2 +- src/mesh/parallel/fci.cxx | 10 +++++----- src/mesh/parallel/identity.cxx | 12 ++++++------ src/mesh/parallel/shiftedmetric.cxx | 12 ++++++------ tools/tokamak_grids/gridgen/hypnotoad_version.pro | 6 ++++-- tools/tokamak_grids/gridgen/process_grid.pro | 6 +++--- 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 313bd7b2f1..69a50a4b66 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -85,7 +85,7 @@ public: protected: /// This method should be called in the constructor to check that if the grid - /// has a 'coordinates_type' variable, it has the correct value + /// has a 'parallel_transform' variable, it has the correct value virtual void checkInputGrid() = 0; Mesh &mesh; ///< The mesh this paralleltransform is part of diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index e97cfa042a..091dac47cd 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -325,13 +325,13 @@ Field3D FCIMap::integrate(Field3D &f) const { } void FCITransform::checkInputGrid() { - std::string coordinates_type = ""; - if (!mesh.get(coordinates_type, "coordinates_type")) { - if (coordinates_type != "fci") { - throw BoutException("Incorrect coordinate system type '"+coordinates_type+"' used " + std::string parallel_transform; + if (!mesh.get(parallel_transform, "parallel_transform")) { + if (parallel_transform != "fci") { + throw BoutException("Incorrect parallel transform type '"+parallel_transform+"' used " "to generate metric components for FCITransform. Should be 'fci'."); } - } // else: coordinate_system variable not found in grid input, indicates older input + } // else: parallel_transform variable not found in grid input, indicates older input // file so must rely on the user having ensured the type is correct } diff --git a/src/mesh/parallel/identity.cxx b/src/mesh/parallel/identity.cxx index ab9e4b89d4..bf2bdc2930 100644 --- a/src/mesh/parallel/identity.cxx +++ b/src/mesh/parallel/identity.cxx @@ -25,13 +25,13 @@ void ParallelTransformIdentity::calcParallelSlices(Field3D& f) { } void ParallelTransformIdentity::checkInputGrid() { - std::string coordinates_type = ""; - if (!mesh.get(coordinates_type, "coordinates_type")) { - if (coordinates_type != "field_aligned") { - throw BoutException("Incorrect coordinate system type '"+coordinates_type+"' used " + std::string parallel_transform; + if (!mesh.get(parallel_transform, "parallel_transform")) { + if (parallel_transform != "identity") { + throw BoutException("Incorrect parallel transform type '"+parallel_transform+"' used " "to generate metric components for ParallelTransformIdentity. Should be " - "'field_aligned'."); + "'identity'."); } - } // else: coordinate_system variable not found in grid input, indicates older input + } // else: parallel_transform variable not found in grid input, indicates older input // file so must rely on the user having ensured the type is correct } diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index a19ebc75af..2a27c67363 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -27,14 +27,14 @@ ShiftedMetric::ShiftedMetric(Mesh& m, CELL_LOC location_in, Field2D zShift_, } void ShiftedMetric::checkInputGrid() { - std::string coordinates_type = ""; - if (!mesh.get(coordinates_type, "coordinates_type")) { - if (coordinates_type != "orthogonal") { - throw BoutException("Incorrect coordinate system type '" + coordinates_type + std::string parallel_transform; + if (!mesh.get(parallel_transform, "parallel_transform")) { + if (parallel_transform != "shiftedmetric") { + throw BoutException("Incorrect parallel transform type '" + parallel_transform + "' used to generate metric components for ShiftedMetric. " - "Should be 'orthogonal'."); + "Should be 'shiftedmetric'."); } - } // else: coordinate_system variable not found in grid input, indicates older input + } // else: parallel_transform variable not found in grid input, indicates older input // file so must rely on the user having ensured the type is correct } diff --git a/tools/tokamak_grids/gridgen/hypnotoad_version.pro b/tools/tokamak_grids/gridgen/hypnotoad_version.pro index b202423e33..11ab982a85 100644 --- a/tools/tokamak_grids/gridgen/hypnotoad_version.pro +++ b/tools/tokamak_grids/gridgen/hypnotoad_version.pro @@ -50,10 +50,12 @@ FUNCTION hypnotoad_version ; 1.2.2 * Revert incorrect change in 1.1.4 to the calculation of 'H' - the ; derivative was with respect to theta, but the integral was in y ; and for non-orthogonal grids thetaxy and yxy are different. - + ; 1.2.3 * Rename 'coordinates_type' to 'parallel_transform', 'orthogonal' + ; to 'shiftedmetric', and 'field_aligned' to 'identity' + major_version = 1 minor_version = 2 - patch_number = 2 + patch_number = 3 RETURN, LONG([major_version, minor_version, patch_number]) diff --git a/tools/tokamak_grids/gridgen/process_grid.pro b/tools/tokamak_grids/gridgen/process_grid.pro index 76414ffd5f..78d36af933 100644 --- a/tools/tokamak_grids/gridgen/process_grid.pro +++ b/tools/tokamak_grids/gridgen/process_grid.pro @@ -1651,14 +1651,14 @@ retrybetacalc: ; type of coordinate system used to calculate metric tensor terms IF orthogonal_coordinates_output EQ 0 THEN BEGIN - coordinates_type = "field_aligned" + parallel_transform = "identity" ENDIF ELSE IF orthogonal_coordinates_output EQ 1 THEN BEGIN - coordinates_type = "orthogonal" + parallel_transform = "shiftedmetric" ENDIF ELSE BEGIN PRINT, "ERROR: Unrecognized orthogonal_coordinates_output value", $ orthogonal_coordinates_output ENDELSE - s = file_write_string(handle, "coordinates_type", coordinates_type) + s = file_write_string(handle, "parallel_transform", parallel_transform) ; Metric tensor terms s = file_write(handle, "g11", g11) From a0a0eb9cad612571395c137219b18f2092e2afdf Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 21 Jun 2019 09:22:43 +0100 Subject: [PATCH 1635/1783] Correct some get calls --- include/bout/griddata.hxx | 3 ++- src/mesh/data/gridfromfile.cxx | 2 +- tests/unit/test_extras.hxx | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index 7b1cb315c3..1e0d31d0cb 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -177,8 +177,9 @@ public: * expressions * * @param[in] mesh Not used + * @param[out] ival The variable which will be set * @param[in] name Name of variable - * @param[out] ival Always given a value, defaults to 0 + * @param[in] def Default value to use if option not found * * @return True if option is set, false if ival is default (0) */ diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 7c8997882f..7dce9f715d 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -134,7 +134,7 @@ bool GridFile::get(Mesh *UNUSED(m), std::string &sval, const std::string &name) * Boolean. True on success. * */ -bool GridFile::get(Mesh *UNUSED(m), int &ival, const std::string &name) { +bool GridFile::get(Mesh *UNUSED(m), int &ival, const std::string &name, int UNUSED(def)) { Timer timer("io"); TRACE("GridFile::get(int)"); diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 21a5398bb7..bad962cdb6 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -335,7 +335,8 @@ class FakeGridDataSource : public GridDataSource { bool get(Mesh* UNUSED(m), std::string& UNUSED(sval), const std::string& UNUSED(name)) { return false; } - bool get(Mesh* UNUSED(m), int& UNUSED(ival), const std::string& UNUSED(name)) { + bool get(Mesh* UNUSED(m), int& UNUSED(ival), const std::string& UNUSED(name), + int UNUSED(def) = 0) { return false; } bool get(Mesh* UNUSED(m), BoutReal& UNUSED(rval), const std::string& UNUSED(name)) { From 7085d4b86ccf4d69f6b8ad190b392c80798a6c7d Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 21 Jun 2019 09:44:26 +0100 Subject: [PATCH 1636/1783] Correct variable names --- src/mesh/impls/bout/boutmesh.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 9e9bfc2b2e..08d24dd587 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -164,10 +164,10 @@ int BoutMesh::load() { // separatrix location Mesh::get(ixseps1, "ixseps1", GlobalNx); Mesh::get(ixseps2, "ixseps2", GlobalNx); - Mesh::get(jyseps1_1, "ixseps1_1", -1); - Mesh::get(jyseps1_2, "ixseps1_2", ny / 2); - Mesh::get(jyseps2_1, "ixseps2_1", jyseps1_2); - Mesh::get(jyseps2_2, "ixseps2_2", ny - 1); + Mesh::get(jyseps1_1, "jyseps1_1", -1); + Mesh::get(jyseps1_2, "jyseps1_2", ny / 2); + Mesh::get(jyseps2_1, "jyseps2_1", jyseps1_2); + Mesh::get(jyseps2_2, "jyseps2_2", ny - 1); Mesh::get(ny_inner, "ny_inner", jyseps2_1); /// Check inputs From aa42cc4bfc0948615c8d7e14101856b6c6ca48b4 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 21 Jun 2019 11:02:13 +0100 Subject: [PATCH 1637/1783] Set default value in cases where there is no mesh --- src/mesh/mesh.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 49f29cfa76..0c835b88ff 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -61,8 +61,11 @@ int Mesh::get(std::string &sval, const std::string &name) { int Mesh::get(int &ival, const std::string &name, int def) { TRACE("Mesh::get(ival, %s)", name.c_str()); - if (source == nullptr or !source->get(this, ival, name, def)) + if (source == nullptr or !source->get(this, ival, name, def)) { + // set ival to default in source==nullptr too: + ival = def; return 1; + } return 0; } From 4ea3f0a7c071b054d69ac5714a564c47b7ff12d7 Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 21 Jun 2019 11:47:34 +0100 Subject: [PATCH 1638/1783] Add "default-defaults" for Fields too --- src/mesh/mesh.cxx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 0c835b88ff..1cc1097814 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -83,8 +83,11 @@ int Mesh::get(BoutReal &rval, const std::string &name) { int Mesh::get(Field2D &var, const std::string &name, BoutReal def) { TRACE("Loading 2D field: Mesh::get(Field2D, %s)", name.c_str()); - if (source == nullptr or !source->get(this, var, name, def)) + if (source == nullptr or !source->get(this, var, name, def)) { + // set val to default in source==nullptr too: + val = def; return 1; + } // Communicate to get guard cell data Mesh::communicate(var); @@ -98,8 +101,11 @@ int Mesh::get(Field2D &var, const std::string &name, BoutReal def) { int Mesh::get(Field3D &var, const std::string &name, BoutReal def, bool communicate) { TRACE("Loading 3D field: Mesh::get(Field3D, %s)", name.c_str()); - if (source == nullptr or !source->get(this, var, name, def)) + if (source == nullptr or !source->get(this, var, name, def)) { + // set val to default in source==nullptr too: + val = def; return 1; + } // Communicate to get guard cell data if(communicate) { @@ -116,8 +122,11 @@ int Mesh::get(FieldPerp &var, const std::string &name, BoutReal def, bool UNUSED(communicate)) { TRACE("Loading FieldPerp: Mesh::get(FieldPerp, %s)", name.c_str()); - if (source == nullptr or !source->get(this, var, name, def)) + if (source == nullptr or !source->get(this, var, name, def)) { + // set val to default in source==nullptr too: + val = def; return 1; + } int yindex = var.getIndex(); if (yindex >= 0 and yindex < var.getMesh()->LocalNy) { From 73dc533346cf33e2185ae846b75776149405542d Mon Sep 17 00:00:00 2001 From: Joseph Parker Date: Fri, 21 Jun 2019 12:21:53 +0100 Subject: [PATCH 1639/1783] Fix typos... --- src/mesh/mesh.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 1cc1097814..39de2dad4e 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -85,7 +85,7 @@ int Mesh::get(Field2D &var, const std::string &name, BoutReal def) { if (source == nullptr or !source->get(this, var, name, def)) { // set val to default in source==nullptr too: - val = def; + var = def; return 1; } @@ -103,7 +103,7 @@ int Mesh::get(Field3D &var, const std::string &name, BoutReal def, bool communic if (source == nullptr or !source->get(this, var, name, def)) { // set val to default in source==nullptr too: - val = def; + var = def; return 1; } @@ -124,7 +124,7 @@ int Mesh::get(FieldPerp &var, const std::string &name, BoutReal def, if (source == nullptr or !source->get(this, var, name, def)) { // set val to default in source==nullptr too: - val = def; + var = def; return 1; } From b81958cdaae9557fadc2e6d00834f8624d7b4e39 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 25 Jun 2019 15:27:50 +0100 Subject: [PATCH 1640/1783] Add defaults to all Mesh::get and GridDataSource::get overloads --- include/bout/griddata.hxx | 32 +++++++++----- include/bout/mesh.hxx | 14 ++++--- src/mesh/data/gridfromfile.cxx | 47 +++++++++++++-------- src/mesh/data/gridfromoptions.cxx | 45 ++++++-------------- src/mesh/mesh.cxx | 70 ++++++++++++++++++------------- tests/unit/test_extras.hxx | 32 +++++--------- 6 files changed, 124 insertions(+), 116 deletions(-) diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index 1e0d31d0cb..3969a385f1 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -52,10 +52,15 @@ public: virtual bool hasVar(const std::string &name) = 0; ///< Test if source can supply a variable - virtual bool get(Mesh *m, std::string &sval, const std::string &name) = 0; ///< Get a string - virtual bool get(Mesh *m, int &ival, const std::string &name, int def = 0) = 0; ///< Get an integer - virtual bool get(Mesh *m, BoutReal &rval, - const std::string &name) = 0; ///< Get a BoutReal number + /// Get a string + virtual bool get(Mesh* m, std::string& sval, const std::string& name, + const std::string& def = "") = 0; + /// Get an integer + virtual bool get(Mesh* m, int& ival, const std::string& name, + int def = 0) = 0; + /// Get a BoutReal number + virtual bool get(Mesh* m, BoutReal& rval, const std::string& name, + BoutReal def = 0.0) = 0; virtual bool get(Mesh *m, Field2D &var, const std::string &name, BoutReal def = 0.0) = 0; virtual bool get(Mesh *m, Field3D &var, const std::string &name, BoutReal def = 0.0) = 0; virtual bool get(Mesh *m, FieldPerp &var, const std::string &name, BoutReal def = 0.0) = 0; @@ -86,11 +91,14 @@ public: bool hasVar(const std::string &name) override; - bool get(Mesh *m, std::string &sval, const std::string &name) override; ///< Get a string - bool get(Mesh *m, int &ival, const std::string &name, int def = 0) override; ///< Get an integer - bool get(Mesh *m, BoutReal &rval, - const std::string &name) override; ///< Get a BoutReal number - bool get(Mesh *m, Field2D &var, const std::string &name, BoutReal def = 0.0) override; + /// Get a string + bool get(Mesh* m, std::string& sval, const std::string& name, + const std::string& def = "") override; + /// Get an integer + bool get(Mesh* m, int& ival, const std::string& name, int def = 0) override; + /// Get a BoutReal number + bool get(Mesh* m, BoutReal& rval, const std::string& name, BoutReal def = 0.0) override; + bool get(Mesh* m, Field2D& var, const std::string& name, BoutReal def = 0.0) override; bool get(Mesh *m, Field3D &var, const std::string &name, BoutReal def = 0.0) override; bool get(Mesh *m, FieldPerp &var, const std::string &name, BoutReal def = 0.0) override { return getField(m, var, name, def); @@ -170,7 +178,8 @@ public: * * @return True if option is set, false if ival is default (0) */ - bool get(Mesh *mesh, std::string &sval, const std::string &name) override; + bool get(Mesh* mesh, std::string& sval, const std::string& name, + const std::string& def = "") override; /*! * Reads integers from options. Uses Options::get to handle @@ -195,7 +204,8 @@ public: * * @return True if option is set, false if ival is default (0) */ - bool get(Mesh *mesh, BoutReal &rval, const std::string &name) override; + bool get(Mesh* mesh, BoutReal& rval, const std::string& name, + BoutReal def = 0.0) override; /*! * Get a Field2D object by finding the option with the given name, diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 9318238891..db2dd7cc4c 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -126,9 +126,10 @@ class Mesh { /// /// @param[out] sval The value will be put into this variable /// @param[in] name The name of the variable to read + /// @param[in] def The default value if not found /// /// @returns zero if successful, non-zero on failure - int get(std::string &sval, const std::string &name); + int get(std::string& sval, const std::string& name, const std::string& def=""); /// Get an integer from the input source /// @@ -137,15 +138,16 @@ class Mesh { /// @param[in] def The default value if not found /// /// @returns zero if successful, non-zero on failure - int get(int &ival, const std::string &name, int def = 0); + int get(int &ival, const std::string &name, int def=0); /// Get a BoutReal from the input source /// /// @param[out] rval The value will be put into this variable /// @param[in] name The name of the variable to read + /// @param[in] def The default value if not found /// /// @returns zero if successful, non-zero on failure - int get(BoutReal &rval, const std::string &name); + int get(BoutReal& rval, const std::string& name, BoutReal def=0.0); /// Get a Field2D from the input source /// including communicating guard cells @@ -186,9 +188,10 @@ class Mesh { /// /// @param[in] var This will be set to the value read /// @param[in] name The name of the vector. Individual fields are read based on this name by appending. See above + /// @param[in] def The default value if not found (used for all the components) /// /// @returns zero always. - int get(Vector2D &var, const std::string &name); + int get(Vector2D &var, const std::string &name, BoutReal def=0.0); /// Get a Vector3D from the input source. /// If \p var is covariant then this gets three @@ -199,9 +202,10 @@ class Mesh { /// /// @param[in] var This will be set to the value read /// @param[in] name The name of the vector. Individual fields are read based on this name by appending. See above + /// @param[in] def The default value if not found (used for all the components) /// /// @returns zero always. - int get(Vector3D &var, const std::string &name); + int get(Vector3D &var, const std::string &name, BoutReal def=0.0); /// Wrapper for GridDataSource::hasVar bool sourceHasVar(const std::string &name); diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 7dce9f715d..83af8eaa3d 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -72,6 +72,17 @@ bool GridFile::hasVar(const std::string &name) { return s.size() != 0; } +namespace { +// Wrapper for writing nicely to the screen +template +void print_read_option(const T& value, const std::string& name, + const std::string& filename, bool success) { + const std::string used_default = success ? "" : " (default)"; + output_info << "\tOption " << name << " = " << value << " (" << filename << ")" + << used_default << std::endl; +} +} + /*! * Read a string from file. If the string is not * found, then string is set to "" and false is returned. @@ -93,7 +104,7 @@ bool GridFile::hasVar(const std::string &name) { * Boolean. True on success. * */ -bool GridFile::get(Mesh *UNUSED(m), std::string &sval, const std::string &name) { +bool GridFile::get(Mesh *UNUSED(m), std::string &sval, const std::string &name, const std::string& def) { Timer timer("io"); TRACE("GridFile::get(std::string)"); @@ -102,15 +113,14 @@ bool GridFile::get(Mesh *UNUSED(m), std::string &sval, const std::string &name) } // strings must be written as attributes, so read from attribute - bool success = file->getAttribute("", name, sval); - if (success) { - output_info << "\tOption " << name << " = " << sval << " (" << filename <<")" << endl; - } else { - sval = ""; + const bool success = file->getAttribute("", name, sval); + if (!success) { + sval = def; } - return success; + print_read_option(sval, name, filename, success); + return success; } /*! @@ -134,7 +144,7 @@ bool GridFile::get(Mesh *UNUSED(m), std::string &sval, const std::string &name) * Boolean. True on success. * */ -bool GridFile::get(Mesh *UNUSED(m), int &ival, const std::string &name, int UNUSED(def)) { +bool GridFile::get(Mesh *UNUSED(m), int &ival, const std::string &name, int def) { Timer timer("io"); TRACE("GridFile::get(int)"); @@ -142,33 +152,36 @@ bool GridFile::get(Mesh *UNUSED(m), int &ival, const std::string &name, int UNUS throw BoutException("File cannot be read"); } - bool success = file->read(&ival, name); - if (success) { - output_info << "\tOption " << name << " = " << ival << " (" << filename <<")" << endl; + const bool success = file->read(&ival, name); + if (!success) { + ival = def; } - return success; + print_read_option(ival, name, filename, success); + return success; } /*! * * */ -bool GridFile::get(Mesh *UNUSED(m), BoutReal &rval, const std::string &name) { +bool GridFile::get(Mesh *UNUSED(m), BoutReal &rval, const std::string &name, BoutReal def) { Timer timer("io"); TRACE("GridFile::get(BoutReal)"); if (!file->is_valid()) { throw BoutException("File cannot be read"); } - bool success = file->read(&rval, name); - if (success) { - output_info << "\tOption " << name << " = " << rval << " (" << filename <<")" << endl; + + const bool success = file->read(&rval, name); + if (!success) { + rval = def; } - return success; + print_read_option(rval, name, filename, success); + return success; } /*! diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index c79f06a0c2..ade485c4f8 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -7,43 +7,24 @@ bool GridFromOptions::hasVar(const std::string& name) { return options->isSet(name); } -bool GridFromOptions::get(Mesh* UNUSED(m), std::string& sval, const std::string& name) { - if (!hasVar(name)) { - const std::string def{}; - output_warn.write("Variable '%s' not in mesh options. Setting to \"%s\"\n", - name.c_str(), def.c_str()); - sval = def; - return false; - } - - options->get(name, sval, ""); - return true; +bool GridFromOptions::get(Mesh* UNUSED(m), std::string& sval, const std::string& name, + const std::string& def) { + const bool has_var = hasVar(name); + sval = (*options)[name].withDefault(def); + return has_var; } bool GridFromOptions::get(Mesh* UNUSED(m), int& ival, const std::string& name, int def) { - if (!hasVar(name)) { - output_warn.write("Variable '%s' not in mesh options. Setting to %d\n", name.c_str(), - def); - ival = def; - return false; - } - - options->get(name, ival, 0); - return true; + const bool has_var = hasVar(name); + ival = (*options)[name].withDefault(def); + return has_var; } -bool GridFromOptions::get(Mesh* UNUSED(m), BoutReal& rval, const std::string& name) { - if (!hasVar(name)) { - constexpr BoutReal def{0.0}; - output_warn.write("Variable '%s' not in mesh options. Setting to %e\n", name.c_str(), - def); - rval = def; - return false; - } - - rval = (*options)[name].withDefault(0.0); - - return true; +bool GridFromOptions::get(Mesh* UNUSED(m), BoutReal& rval, const std::string& name, + BoutReal def) { + const bool has_var = hasVar(name); + rval = (*options)[name].withDefault(def); + return has_var; } bool GridFromOptions::get(Mesh* m, Field2D& var, const std::string& name, BoutReal def) { diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 39de2dad4e..0a85241777 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -47,37 +47,49 @@ Mesh::~Mesh() { * which may then read from a file, options, or other sources. **************************************************************************/ -/// Get a string -int Mesh::get(std::string &sval, const std::string &name) { +namespace { +// Wrapper for writing nicely to the screen +template +void warn_default_used(const T& value, const std::string& name) { + output_warn << "\tWARNING: Mesh has no source. Setting '" << name << "' = " << value + << std::endl; +} +} // namespace + +int Mesh::get(std::string& sval, const std::string& name, const std::string& def) { TRACE("Mesh::get(sval, %s)", name.c_str()); - if (source == nullptr or !source->get(this, sval, name)) - return 1; + if (source == nullptr) { + warn_default_used(def, name); + sval = def; + return true; + } - return 0; + return !source->get(this, sval, name, def); } -/// Get an integer int Mesh::get(int &ival, const std::string &name, int def) { TRACE("Mesh::get(ival, %s)", name.c_str()); - if (source == nullptr or !source->get(this, ival, name, def)) { - // set ival to default in source==nullptr too: + if (source == nullptr) { + warn_default_used(def, name); ival = def; - return 1; + return true; } - return 0; + return !source->get(this, ival, name, def); } -/// A BoutReal number -int Mesh::get(BoutReal &rval, const std::string &name) { +int Mesh::get(BoutReal& rval, const std::string& name, BoutReal def) { TRACE("Mesh::get(rval, %s)", name.c_str()); - if (source == nullptr or !source->get(this, rval, name)) - return 1; + if (source == nullptr) { + warn_default_used(def, name); + rval = def; + return true; + } - return 0; + return !source->get(this, rval, name); } int Mesh::get(Field2D &var, const std::string &name, BoutReal def) { @@ -144,43 +156,43 @@ int Mesh::get(FieldPerp &var, const std::string &name, BoutReal def, * Data get routines **************************************************************************/ -int Mesh::get(Vector2D &var, const std::string &name) { +int Mesh::get(Vector2D &var, const std::string &name, BoutReal def) { TRACE("Loading 2D vector: Mesh::get(Vector2D, %s)", name.c_str()); if(var.covariant) { output << _("\tReading covariant vector ") << name << endl; - get(var.x, name+"_x"); - get(var.y, name+"_y"); - get(var.z, name+"_z"); + get(var.x, name+"_x", def); + get(var.y, name+"_y", def); + get(var.z, name+"_z", def); }else { output << _("\tReading contravariant vector ") << name << endl; - get(var.x, name+"x"); - get(var.y, name+"y"); - get(var.z, name+"z"); + get(var.x, name+"x", def); + get(var.y, name+"y", def); + get(var.z, name+"z", def); } return 0; } -int Mesh::get(Vector3D &var, const std::string &name) { +int Mesh::get(Vector3D &var, const std::string &name, BoutReal def) { TRACE("Loading 3D vector: Mesh::get(Vector3D, %s)", name.c_str()); if(var.covariant) { output << _("\tReading covariant vector ") << name << endl; - get(var.x, name+"_x"); - get(var.y, name+"_y"); - get(var.z, name+"_z"); + get(var.x, name+"_x", def); + get(var.y, name+"_y", def); + get(var.z, name+"_z", def); }else { output << ("\tReading contravariant vector ") << name << endl; - get(var.x, name+"x"); - get(var.y, name+"y"); - get(var.z, name+"z"); + get(var.x, name+"x", def); + get(var.y, name+"y", def); + get(var.z, name+"z", def); } return 0; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index bad962cdb6..c92b997243 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -332,37 +332,25 @@ private: class FakeGridDataSource : public GridDataSource { bool hasVar(const std::string& UNUSED(name)) { return false; } - bool get(Mesh* UNUSED(m), std::string& UNUSED(sval), const std::string& UNUSED(name)) { + bool get(Mesh*, std::string&, const std::string&, const std::string& = "") { return false; } - bool get(Mesh* UNUSED(m), int& UNUSED(ival), const std::string& UNUSED(name), - int UNUSED(def) = 0) { + bool get(Mesh*, int&, const std::string&, int = 0) { return false; } + bool get(Mesh*, BoutReal&, const std::string&, BoutReal = 0.0) { return false; } - bool get(Mesh* UNUSED(m), BoutReal& UNUSED(rval), const std::string& UNUSED(name)) { - return false; - } - bool get(Mesh* UNUSED(m), Field2D& UNUSED(var), const std::string& UNUSED(name), - BoutReal UNUSED(def) = 0.0) { - return false; - } - bool get(Mesh* UNUSED(m), Field3D& UNUSED(var), const std::string& UNUSED(name), - BoutReal UNUSED(def) = 0.0) { - return false; - } - bool get(Mesh* UNUSED(m), FieldPerp& UNUSED(var), const std::string& UNUSED(name), - BoutReal UNUSED(def) = 0.0) { + bool get(Mesh*, Field2D&, const std::string&, BoutReal = 0.0) { return false; } + bool get(Mesh*, Field3D&, const std::string&, BoutReal = 0.0) { return false; } + bool get(Mesh*, FieldPerp&, const std::string&, BoutReal = 0.0) { return false; } - bool get(Mesh* UNUSED(m), std::vector& UNUSED(var), - const std::string& UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, - Direction UNUSED(dir) = GridDataSource::X) { + bool get(Mesh*, std::vector&, const std::string&, int, int = 0, + Direction = GridDataSource::X) { return false; } - bool get(Mesh* UNUSED(m), std::vector& UNUSED(var), - const std::string& UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, - Direction UNUSED(dir) = GridDataSource::X) { + bool get(Mesh*, std::vector&, const std::string&, int, int = 0, + Direction UNUSED(dir) = GridDataSource::X) { return false; } From 4d66f1bbda320cc116d490c9bd43fe81ffa54d9c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 25 Jun 2019 15:59:00 +0100 Subject: [PATCH 1641/1783] Add some basic tests for Mesh::get when Mesh has no source --- tests/unit/mesh/test_mesh.cxx | 77 +++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/tests/unit/mesh/test_mesh.cxx b/tests/unit/mesh/test_mesh.cxx index e428f2551c..2b47ce7f38 100644 --- a/tests/unit/mesh/test_mesh.cxx +++ b/tests/unit/mesh/test_mesh.cxx @@ -156,3 +156,80 @@ TEST_F(MeshTest, Ind3DToPerp) { } } } + +TEST_F(MeshTest, GetStringNoSource) { + std::string string_value; + EXPECT_NE(localmesh.get(string_value, "no_source"), 0); + EXPECT_EQ(string_value, ""); +} + +TEST_F(MeshTest, GetStringNoSourceWithDefault) { + std::string string_value; + const std::string default_value = "some default"; + EXPECT_NE(localmesh.get(string_value, "no_source", default_value), 0); + EXPECT_EQ(string_value, default_value); +} + +TEST_F(MeshTest, GetIntNoSource) { + int int_value; + EXPECT_NE(localmesh.get(int_value, "no_source"), 0); + EXPECT_EQ(int_value, 0); +} + +TEST_F(MeshTest, GetIntNoSourceWithDefault) { + int int_value; + constexpr int default_value = 42; + EXPECT_NE(localmesh.get(int_value, "no_source", default_value), 0); + EXPECT_EQ(int_value, default_value); +} + +TEST_F(MeshTest, GetBoutRealNoSource) { + BoutReal boutreal_value; + EXPECT_NE(localmesh.get(boutreal_value, "no_source"), 0); + EXPECT_EQ(boutreal_value, 0.0); +} + +TEST_F(MeshTest, GetBoutRealNoSourceWithDefault) { + BoutReal boutreal_value; + constexpr BoutReal default_value = 3.14; + EXPECT_NE(localmesh.get(boutreal_value, "no_source", default_value), 0); + EXPECT_DOUBLE_EQ(boutreal_value, default_value); +} + +TEST_F(MeshTest, GetField2DNoSource) { + localmesh.createDefaultRegions(); + localmesh.setCoordinates(nullptr); + + Field2D field2d_value{&localmesh}; + EXPECT_NE(localmesh.get(field2d_value, "no_source"), 0); + EXPECT_TRUE(IsFieldEqual(field2d_value, 0.0)); +} + +TEST_F(MeshTest, GetField2DNoSourceWithDefault) { + localmesh.createDefaultRegions(); + localmesh.setCoordinates(nullptr); + + Field2D field2d_value{&localmesh}; + constexpr BoutReal default_value = 4.2; + EXPECT_NE(localmesh.get(field2d_value, "no_source", default_value), 0); + EXPECT_TRUE(IsFieldEqual(field2d_value, default_value)); +} + +TEST_F(MeshTest, GetField3DNoSource) { + localmesh.createDefaultRegions(); + localmesh.setCoordinates(nullptr); + + Field3D field3d_value{&localmesh}; + EXPECT_NE(localmesh.get(field3d_value, "no_source"), 0); + EXPECT_TRUE(IsFieldEqual(field3d_value, 0.0)); +} + +TEST_F(MeshTest, GetField3DNoSourceWithDefault) { + localmesh.createDefaultRegions(); + localmesh.setCoordinates(nullptr); + + Field3D field3d_value{&localmesh}; + constexpr BoutReal default_value = 4.2; + EXPECT_NE(localmesh.get(field3d_value, "no_source", default_value), 0); + EXPECT_TRUE(IsFieldEqual(field3d_value, default_value)); +} From 8bac5c5640cca5d6fc76a668f95b4d054927e079 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 25 Jun 2019 15:59:18 +0100 Subject: [PATCH 1642/1783] Use WithQuietOutput to silence output in Mesh test --- tests/unit/mesh/test_mesh.cxx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/unit/mesh/test_mesh.cxx b/tests/unit/mesh/test_mesh.cxx index 2b47ce7f38..e65900632a 100644 --- a/tests/unit/mesh/test_mesh.cxx +++ b/tests/unit/mesh/test_mesh.cxx @@ -9,17 +9,15 @@ /// Test fixture to make sure the global mesh is our fake one class MeshTest : public ::testing::Test { -protected: - static void SetUpTestCase() { output_info.disable(); } - - static void TearDownTestCase() { output_info.enable(); } - public: MeshTest() : localmesh(nx, ny, nz) {} static const int nx = 3; static const int ny = 5; static const int nz = 7; FakeMesh localmesh; + + WithQuietOutput info{output_info}; + WithQuietOutput warn{output_warn}; }; TEST_F(MeshTest, CreateDefaultRegions) { From e630264602fc70482db606eb1e587ef2fb5d4907 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 26 Jun 2019 10:19:31 +0100 Subject: [PATCH 1643/1783] Fix default value not being passed to source->get --- src/mesh/mesh.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 0a85241777..f0eb2fc319 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -89,7 +89,7 @@ int Mesh::get(BoutReal& rval, const std::string& name, BoutReal def) { return true; } - return !source->get(this, rval, name); + return !source->get(this, rval, name, def); } int Mesh::get(Field2D &var, const std::string &name, BoutReal def) { From 54a068f527469c10540a1e63ef26eb6703a882b6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 26 Jun 2019 10:20:13 +0100 Subject: [PATCH 1644/1783] Fix GridFromOptions setting default value in Options The default argument to `Mesh::get` is new. Existing calls may be using the return value to set a default, which may or may not be recorded in the `Options` tree. We don't want the default value passed to `GridFromOptions::get` to get recorded in case we don't end up using it. This is for the benefit of the `BOUT.settings` file that records the settings actually used during a simulation --- src/mesh/data/gridfromoptions.cxx | 37 ++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index ade485c4f8..eb105758a6 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -7,24 +7,35 @@ bool GridFromOptions::hasVar(const std::string& name) { return options->isSet(name); } -bool GridFromOptions::get(Mesh* UNUSED(m), std::string& sval, const std::string& name, +namespace { +/// Return value of \p name in \p options, using \p def as a default +/// if it doesn't exist +template +auto getWithDefault(const Options& options, const std::string& name, const T& def) -> T { + // Note! We don't use `Options::withDefault` here because that + // records the default in the `Options` object and we don't know if + // we'll actually end up using that value. This is because + // `GridFromOptions::get` is probably being called via `Mesh::get`, + // and the calling site may use the return value of that to set its + // own default + return options.isSet(name) ? options[name].as() : def; +} +} // namespace + +bool GridFromOptions::get(Mesh*, std::string& sval, const std::string& name, const std::string& def) { - const bool has_var = hasVar(name); - sval = (*options)[name].withDefault(def); - return has_var; + sval = getWithDefault(*options, name, def); + return hasVar(name); } -bool GridFromOptions::get(Mesh* UNUSED(m), int& ival, const std::string& name, int def) { - const bool has_var = hasVar(name); - ival = (*options)[name].withDefault(def); - return has_var; +bool GridFromOptions::get(Mesh*, int& ival, const std::string& name, int def) { + ival = getWithDefault(*options, name, def); + return hasVar(name); } -bool GridFromOptions::get(Mesh* UNUSED(m), BoutReal& rval, const std::string& name, - BoutReal def) { - const bool has_var = hasVar(name); - rval = (*options)[name].withDefault(def); - return has_var; +bool GridFromOptions::get(Mesh*, BoutReal& rval, const std::string& name, BoutReal def) { + rval = getWithDefault(*options, name, def); + return hasVar(name); } bool GridFromOptions::get(Mesh* m, Field2D& var, const std::string& name, BoutReal def) { From 29732818d619ee3892b8d875eb92191807de3168 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 26 Jun 2019 10:22:55 +0100 Subject: [PATCH 1645/1783] Quieten lots of tests due to new warning in Mesh::get with no source --- tests/unit/field/test_field_factory.cxx | 4 +++- tests/unit/include/test_derivs.cxx | 3 ++- tests/unit/mesh/parallel/test_shiftedmetric.cxx | 3 ++- tests/unit/mesh/test_interpolation.cxx | 3 ++- tests/unit/mesh/test_mesh.cxx | 11 +++++++++-- tests/unit/sys/test_expressionparser.cxx | 2 ++ tests/unit/sys/test_options_fields.cxx | 4 +++- tests/unit/test_extras.hxx | 3 ++- 8 files changed, 25 insertions(+), 8 deletions(-) diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index d11d0fb2bc..ca76b07ee5 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -43,7 +43,8 @@ class FieldFactoryCreationTest : public FakeMeshFixture { } } - WithQuietOutput quiet{output_info}; + WithQuietOutput quiet_info{output_info}; + WithQuietOutput quiet_warn{output_warn}; FieldFactory factory; @@ -612,6 +613,7 @@ class FieldFactoryTest : public FakeMeshFixture { virtual ~FieldFactoryTest() {} WithQuietOutput quiet_info{output_info}, quiet{output}, quiet_error{output_error}; + WithQuietOutput quiet_warn{output_warn}; FieldFactory factory; }; diff --git a/tests/unit/include/test_derivs.cxx b/tests/unit/include/test_derivs.cxx index e7b73acaae..0cf35c3366 100644 --- a/tests/unit/include/test_derivs.cxx +++ b/tests/unit/include/test_derivs.cxx @@ -45,7 +45,8 @@ class DerivativesTest : public ::testing::TestWithParam> { public: DerivativesTest() : input{mesh}, expected{mesh} { - WithQuietOutput quiet{output_info}; + WithQuietOutput quiet_info{output_info}; + WithQuietOutput quiet_warn{output_warn}; using Index = Field3D::ind_type; diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index e70fead41b..1cef81f836 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -16,7 +16,8 @@ extern Mesh* mesh; class ShiftedMetricTest : public ::testing::Test { public: ShiftedMetricTest() { - WithQuietOutput quiet{output_info}; + WithQuietOutput quiet_info{output_info}; + WithQuietOutput quiet_warn{output_warn}; delete mesh; mesh = new FakeMesh(nx, ny, nz); diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index 7c03ee9d9f..f59e0ccb96 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -49,7 +49,8 @@ class Field3DInterpToTest : public ::testing::Test { } static void SetUpTestCase() { - WithQuietOutput quiet{output_info}; + WithQuietOutput quiet_info{output_info}; + WithQuietOutput quiet_warn{output_warn}; delete mesh; mesh = new FakeMesh(nx, ny, nz); mesh->StaggerGrids = true; diff --git a/tests/unit/mesh/test_mesh.cxx b/tests/unit/mesh/test_mesh.cxx index e65900632a..7a6d1bd236 100644 --- a/tests/unit/mesh/test_mesh.cxx +++ b/tests/unit/mesh/test_mesh.cxx @@ -16,8 +16,7 @@ class MeshTest : public ::testing::Test { static const int nz = 7; FakeMesh localmesh; - WithQuietOutput info{output_info}; - WithQuietOutput warn{output_warn}; + WithQuietOutput quiet_warn{output_warn}; }; TEST_F(MeshTest, CreateDefaultRegions) { @@ -195,6 +194,8 @@ TEST_F(MeshTest, GetBoutRealNoSourceWithDefault) { } TEST_F(MeshTest, GetField2DNoSource) { + WithQuietOutput warn{output_warn}; + localmesh.createDefaultRegions(); localmesh.setCoordinates(nullptr); @@ -204,6 +205,8 @@ TEST_F(MeshTest, GetField2DNoSource) { } TEST_F(MeshTest, GetField2DNoSourceWithDefault) { + WithQuietOutput warn{output_warn}; + localmesh.createDefaultRegions(); localmesh.setCoordinates(nullptr); @@ -214,6 +217,8 @@ TEST_F(MeshTest, GetField2DNoSourceWithDefault) { } TEST_F(MeshTest, GetField3DNoSource) { + WithQuietOutput warn{output_warn}; + localmesh.createDefaultRegions(); localmesh.setCoordinates(nullptr); @@ -223,6 +228,8 @@ TEST_F(MeshTest, GetField3DNoSource) { } TEST_F(MeshTest, GetField3DNoSourceWithDefault) { + WithQuietOutput warn{output_warn}; + localmesh.createDefaultRegions(); localmesh.setCoordinates(nullptr); diff --git a/tests/unit/sys/test_expressionparser.cxx b/tests/unit/sys/test_expressionparser.cxx index 5d4e48c75e..918f2d204e 100644 --- a/tests/unit/sys/test_expressionparser.cxx +++ b/tests/unit/sys/test_expressionparser.cxx @@ -3,6 +3,7 @@ #include "bout/sys/expressionparser.hxx" #include "bout_types.hxx" #include "unused.hxx" +#include "test_extras.hxx" #include @@ -21,6 +22,7 @@ class ExpressionParserTest : public ::testing::Test { std::vector y_array = {-1., 0., 1., 5., 10., 3.14e8}; std::vector z_array = {-1., 0., 1., 5., 10., 3.14e8}; std::vector t_array = {-1., 0., 1., 5., 10., 3.14e8}; + WithQuietOutput quiet_warn{output_warn}; }; /// For testing, a generator function of two inputs diff --git a/tests/unit/sys/test_options_fields.cxx b/tests/unit/sys/test_options_fields.cxx index c2b6939b6f..df9464bab9 100644 --- a/tests/unit/sys/test_options_fields.cxx +++ b/tests/unit/sys/test_options_fields.cxx @@ -16,7 +16,9 @@ extern Mesh* mesh; } // namespace bout // Reuse the "standard" fixture for FakeMesh -using OptionsFieldTest = FakeMeshFixture; +class OptionsFieldTest : public FakeMeshFixture { + WithQuietOutput quiet_warn{output_warn}; +}; TEST_F(OptionsFieldTest, StoreField3D) { Field3D field = 1.0; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index c92b997243..c716b4dcda 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -368,7 +368,8 @@ class FakeGridDataSource : public GridDataSource { class FakeMeshFixture : public ::testing::Test { public: FakeMeshFixture() { - WithQuietOutput quiet{output_info}; + WithQuietOutput quiet_info{output_info}; + WithQuietOutput quiet_warn{output_warn}; delete bout::globals::mesh; bout::globals::mesh = new FakeMesh(nx, ny, nz); From d79587c6076cc0b7887facd39a7f53e617a240d3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 26 Jun 2019 10:29:57 +0100 Subject: [PATCH 1646/1783] Restore warning from `GridFromOptions::get` if default used --- src/mesh/data/gridfromoptions.cxx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index eb105758a6..aa07abe1c2 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -12,13 +12,18 @@ namespace { /// if it doesn't exist template auto getWithDefault(const Options& options, const std::string& name, const T& def) -> T { + const bool has_var = options.isSet(name); + if (!has_var) { + output_warn.write("Variable '%s' not in mesh options. Setting to ", name.c_str()); + output_warn << def << "\n"; + } // Note! We don't use `Options::withDefault` here because that // records the default in the `Options` object and we don't know if // we'll actually end up using that value. This is because // `GridFromOptions::get` is probably being called via `Mesh::get`, // and the calling site may use the return value of that to set its // own default - return options.isSet(name) ? options[name].as() : def; + return has_var ? options[name].as() : def; } } // namespace From 92930efddc3acd0afef11fe6bb93a3347b8e623a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 26 Jun 2019 10:36:10 +0100 Subject: [PATCH 1647/1783] Use Mesh::get overload with default value for dx, dy, dz --- src/mesh/coordinates.cxx | 45 ++++++++++++---------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 5b026dbe4f..8938920786 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -223,39 +223,28 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) "cells\n")); } - if (mesh->get(dx, "dx")) { - output_warn.write(_("\tWARNING: differencing quantity 'dx' not found. Set to 1.0\n")); - dx = 1.0; - } + mesh->get(dx, "dx", 1.0); dx = interpolateAndExtrapolate(dx, location, extrapolate_x, extrapolate_y); if (mesh->periodicX) { mesh->communicate(dx); } - if (mesh->get(dy, "dy")) { - output_warn.write(_("\tWARNING: differencing quantity 'dy' not found. Set to 1.0\n")); - dy = 1.0; - } + mesh->get(dy, "dy", 1.0); dy = interpolateAndExtrapolate(dy, location, extrapolate_x, extrapolate_y); nz = mesh->LocalNz; - if (mesh->get(dz, "dz")) { - // Couldn't read dz from input - BoutReal ZMIN, ZMAX; - Options* options = Options::getRoot(); - if (options->isSet("zperiod")) { - int zperiod; - OPTION(options, zperiod, 1); - ZMIN = 0.0; - ZMAX = 1.0 / static_cast(zperiod); - } else { - OPTION(options, ZMIN, 0.0); - OPTION(options, ZMAX, 1.0); - } + { + auto& options = Options::root(); + const bool has_zperiod = options.isSet("zperiod"); + const auto zmin = has_zperiod ? 0.0 : options["ZMIN"].withDefault(0.0); + const auto zmax = has_zperiod ? 1.0 / options["zperiod"].withDefault(1.0) + : options["ZMAX"].withDefault(1.0); + + const auto default_dz = (zmax - zmin) * TWOPI / nz; - dz = (ZMAX - ZMIN) * TWOPI / nz; + mesh->get(dz, "dz", default_dz); } // Diagonal components of metric tensor g^{ij} (default to 1) @@ -448,11 +437,7 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, } checkStaggeredGet(mesh, "dx", suffix); - if (mesh->get(dx, "dx"+suffix)) { - output_warn.write( - "\tWARNING: differencing quantity 'dx%s' not found. Set to 1.0\n", suffix.c_str()); - dx = 1.0; - } + mesh->get(dx, "dx"+suffix, 1.0); dx.setLocation(location); dx = interpolateAndExtrapolate(dx, location, extrapolate_x, extrapolate_y); @@ -461,11 +446,7 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, } checkStaggeredGet(mesh, "dy", suffix); - if (mesh->get(dy, "dy"+suffix)) { - output_warn.write( - "\tWARNING: differencing quantity 'dy%s' not found. Set to 1.0\n", suffix.c_str()); - dy = 1.0; - } + mesh->get(dy, "dy"+suffix, 1.0); dy.setLocation(location); dy = interpolateAndExtrapolate(dy, location, extrapolate_x, extrapolate_y); From 6cfba2a5d69dd0b42ed70763669ff09b5e09debf Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 26 Jun 2019 15:13:10 +0100 Subject: [PATCH 1648/1783] Reenable MMS/spatial/advection test --- tests/MMS/spatial/advection/{runtest.broken => runtest} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/MMS/spatial/advection/{runtest.broken => runtest} (100%) diff --git a/tests/MMS/spatial/advection/runtest.broken b/tests/MMS/spatial/advection/runtest similarity index 100% rename from tests/MMS/spatial/advection/runtest.broken rename to tests/MMS/spatial/advection/runtest From 87deb010de944ed89c7675c1d977f63fe0a564f4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 26 Jun 2019 15:13:49 +0100 Subject: [PATCH 1649/1783] Fix python MMS check_scaling function Wrong variable names used --- tools/pylib/boututils/check_scaling.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tools/pylib/boututils/check_scaling.py b/tools/pylib/boututils/check_scaling.py index be22fc074a..af59b0b786 100644 --- a/tools/pylib/boututils/check_scaling.py +++ b/tools/pylib/boututils/check_scaling.py @@ -44,15 +44,14 @@ def check_order(error_list, expected_order, tolerance=2.e-1, spacing=None): if len(error_list) < 2: raise RuntimeError("Expected at least 2 data points to calculate error") - success=True + success = True + for i in range(len(error_list)-1): - if spacing is None: - actual_order = log(errors[i] / errors[i+1]) / log(2) - else: - actual_order = log(errors[i] / errors[i+1]) / log(grid_spacing[i] / grid_spacing[i+1]) + grid_spacing = 2 if spacing is None else spacing[i] / spacing[i+1] + actual_order = log(error_list[i] / error_list[i+1]) / log(grid_spacing) if not isclose(actual_order, expected_order, atol=tolerance, rtol=0): - success=False + success = False return success From a04b95bd3957f9915cb3011888402cead174b534 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 26 Jun 2019 15:14:46 +0100 Subject: [PATCH 1650/1783] Use looser tolerance in MMS/spatial/advection for upwind-3 Checking the convergence order at every pair of points with an absolute tolerance causes the upwind-3 method to fail at the first pair of points. Given that the method is otherwise very good, loosen the tolerance to let it pass --- tests/MMS/spatial/advection/runtest | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/MMS/spatial/advection/runtest b/tests/MMS/spatial/advection/runtest index c71e67a008..f27ced6bef 100755 --- a/tests/MMS/spatial/advection/runtest +++ b/tests/MMS/spatial/advection/runtest @@ -93,7 +93,9 @@ for opts, label, sym, exp_ord in options: order = check_scaling.get_order(dx, error_2) print("Convergence order = {:f} ({:f} at small spacing)".format(*order)) - if check_scaling.check_order(error_2, exp_ord): + # Loose tolerance because upwind-3rd order would otherwise fail at + # low resolution, when it is very good over the rest of the domain + if check_scaling.check_order(error_2, exp_ord, tolerance=3.e-1): print("... Success") else: failures.append(label) From 2d541a5c279866021c131e81fcc3478f04bc2d2f Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 26 Jun 2019 15:16:14 +0100 Subject: [PATCH 1651/1783] Add other bracket methods, Arakawa-old and BRACKET_STD to MMS test --- tests/MMS/spatial/advection/runtest | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/MMS/spatial/advection/runtest b/tests/MMS/spatial/advection/runtest index f27ced6bef..cc2269e26e 100755 --- a/tests/MMS/spatial/advection/runtest +++ b/tests/MMS/spatial/advection/runtest @@ -35,11 +35,17 @@ shell_safe("make > make.log") # List of options to be passed for each test options = [ ("method=2", "Arakawa", "-^", 2), - ("method=1 mesh:ddx:upwind=u1 mesh:ddz:upwind=u1", "1st order upwind", "-o", 1), - ("method=1 mesh:ddx:upwind=u2 mesh:ddz:upwind=u2", "2nd order upwind", "-^", 2), - ("method=1 mesh:ddx:upwind=u3 mesh:ddz:upwind=u3", "3nd order upwind", "-v", 3), - ("method=1 mesh:ddx:upwind=c2 mesh:ddz:upwind=c2", "2nd order central", "-x", 2), - ("method=1 mesh:ddx:upwind=c4 mesh:ddz:upwind=c4", "4th order central", "-+", 4), + ("method=4", "Arakawa-old", "-.", 2), + ("method=1 mesh:ddx:upwind=u1 mesh:ddz:upwind=u1", "SIMPLE: 1st order upwind", "-o", 1), + ("method=1 mesh:ddx:upwind=u2 mesh:ddz:upwind=u2", "SIMPLE: 2nd order upwind", "-^", 2), + ("method=1 mesh:ddx:upwind=u3 mesh:ddz:upwind=u3", "SIMPLE: 3nd order upwind", "-v", 3), + ("method=1 mesh:ddx:upwind=c2 mesh:ddz:upwind=c2", "SIMPLE: 2nd order central", "-x", 2), + ("method=1 mesh:ddx:upwind=c4 mesh:ddz:upwind=c4", "SIMPLE: 4th order central", "-+", 4), + ("method=0 mesh:ddx:upwind=u1 mesh:ddz:upwind=u1", "STD: 1st order upwind", "-o", 1), + ("method=0 mesh:ddx:upwind=u2 mesh:ddz:upwind=u2", "STD: 2nd order upwind", "-^", 2), + ("method=0 mesh:ddx:upwind=u3 mesh:ddz:upwind=u3", "STD: 3nd order upwind", "-v", 3), + ("method=0 mesh:ddx:upwind=c2 mesh:ddz:upwind=c2", "STD: 2nd order central", "-x", 2), + ("method=0 mesh:ddx:upwind=c4 mesh:ddz:upwind=c4", "STD: 4th order central", "-+", 4), # NOTE: WENO3 seems to have two different regimes, one < 3, one > # 3, so it's possible to make it pass by judicious choice of grid # sizes, which is suspicious. It does seem to work correctly in From ecfeebbd45f3ffe9c306ccd4c062f4d82d977505 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 26 Jun 2019 15:17:10 +0100 Subject: [PATCH 1652/1783] Fix deprecated overload of mean/abs in MMS/spatial/advection --- tests/MMS/spatial/advection/advection.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/MMS/spatial/advection/advection.cxx b/tests/MMS/spatial/advection/advection.cxx index dc82774d00..9ef5efa201 100644 --- a/tests/MMS/spatial/advection/advection.cxx +++ b/tests/MMS/spatial/advection/advection.cxx @@ -15,8 +15,8 @@ int main(int argc, char** argv) { Field3D result{bracket(g, f, method)}; Field3D error{result - solution}; - BoutReal l_2{sqrt(mean(SQ(error), true, RGN_NOBNDRY))}; - BoutReal l_inf{max(abs(error), true, RGN_NOBNDRY)}; + BoutReal l_2{sqrt(mean(SQ(error), true, "RGN_NOBNDRY"))}; + BoutReal l_inf{max(abs(error), true, "RGN_NOBNDRY")}; SAVE_ONCE2(f, g); SAVE_ONCE5(solution, result, error, l_2, l_inf); From a184f56fa7835436319d47d840b9d93a292625f1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 26 Jun 2019 15:18:03 +0100 Subject: [PATCH 1653/1783] Move some constants out of rhs in MMS/advection Calculate once during initialisation --- tests/MMS/advection/advection.cxx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/MMS/advection/advection.cxx b/tests/MMS/advection/advection.cxx index c06af19727..8c2303ba41 100644 --- a/tests/MMS/advection/advection.cxx +++ b/tests/MMS/advection/advection.cxx @@ -9,22 +9,23 @@ class AdvectMMS : public PhysicsModel { public: - int init(bool UNUSED(restarting)) { + int init(bool) { solver->add(f, "f"); Options::getRoot()->get("method", method, 0); + g = FieldFactory::get()->create3D("g:solution", Options::getRoot(), mesh, CELL_CENTRE); + + Coordinates *coords = mesh->getCoordinates(); + + dx_sq_sq = SQ(SQ(coords->dx)); + dz_sq_sq = SQ(SQ(coords->dz)); return 0; } - int rhs(BoutReal time) { + int rhs(BoutReal) { mesh->communicate(f); - Coordinates *coords = mesh->getCoordinates(); - - g = FieldFactory::get()->create3D("g:solution", Options::getRoot(), mesh, CELL_CENTRE, time); - ddt(f) = -bracket(g, f, (BRACKET_METHOD) method) - - 20.*(SQ(SQ(coords->dx))*D4DX4(f) + SQ(SQ(coords->dz))*D4DZ4(f)) - //+ 20.*(SQ(coords->dx)*D2DX2(f) + SQ(coords->dz)*D2DZ2(f)) + - 20.*(dx_sq_sq*D4DX4(f) + dz_sq_sq*D4DZ4(f)) ; return 0; @@ -32,6 +33,7 @@ class AdvectMMS : public PhysicsModel { private: int method; Field3D f,g; + Field3D dx_sq_sq, dz_sq_sq; }; BOUTMAIN(AdvectMMS); From abb73d9aa7d7b1832165e716b096c40391003cf1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 26 Jun 2019 15:22:32 +0100 Subject: [PATCH 1654/1783] Reduce size of dissipation term in MMS/advection Necessary to get central scheme to pass --- tests/MMS/advection/advection.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/MMS/advection/advection.cxx b/tests/MMS/advection/advection.cxx index 8c2303ba41..b32b0b438f 100644 --- a/tests/MMS/advection/advection.cxx +++ b/tests/MMS/advection/advection.cxx @@ -25,7 +25,7 @@ class AdvectMMS : public PhysicsModel { int rhs(BoutReal) { mesh->communicate(f); ddt(f) = -bracket(g, f, (BRACKET_METHOD) method) - - 20.*(dx_sq_sq*D4DX4(f) + dz_sq_sq*D4DZ4(f)) + - (dx_sq_sq*D4DX4(f) + dz_sq_sq*D4DZ4(f)) ; return 0; From d767fdf15e50cbb890df6cf0e362064a32ea4706 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 26 Jun 2019 15:30:08 +0100 Subject: [PATCH 1655/1783] Only check MMS error over interior points --- tests/MMS/advection/runtest | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/MMS/advection/runtest b/tests/MMS/advection/runtest index b5798a03f6..1b721d9af2 100755 --- a/tests/MMS/advection/runtest +++ b/tests/MMS/advection/runtest @@ -72,8 +72,7 @@ def run_mms(options,exit=True): f.close() # Collect data - E_f = collect("E_f", tind=[1,1], info=False, path="data") - #E_f = E_f[0,1:-1,0,:] + E_f = collect("E_f", xguards=False, tind=[1,1], info=False, path="data") # Average error over domain l2 = sqrt(mean(E_f**2)) From 447e891cb75f21afd011e8740f0ad9c0dfa25967 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 22:34:37 +0100 Subject: [PATCH 1656/1783] Interface for gyro-average operators using new-style flags Deprecate old interface using single 'flags' argument in favour of new interface with separate inner_flags and outer_flags. --- include/gyro_average.hxx | 84 +++++++++++++++++++++---- src/physics/gyro_average.cxx | 116 +++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+), 11 deletions(-) diff --git a/include/gyro_average.hxx b/include/gyro_average.hxx index 818db3c059..fa12bdc123 100644 --- a/include/gyro_average.hxx +++ b/include/gyro_average.hxx @@ -37,7 +37,7 @@ /// INVERT_BNDRY_ONE | INVERT_IN_RHS | INVERT_OUT_RHS; uses old-style /// Laplacian inversion flags -constexpr int GYRO_FLAGS = 64 + 16384 + 32768; +constexpr int GYRO_FLAGS = INVERT_BNDRY_ONE + INVERT_RHS; /// Gyro-average using Taylor series approximation /// @@ -58,9 +58,28 @@ Field3D gyroTaylor0(const Field3D& f, const Field3D& rho); /// @param[in] f The field to gyro-average /// @param[in] rho Gyro-radius /// @param[in] flags Flags to be passed to the Laplacian inversion operator -Field3D gyroPade0(const Field3D& f, const Field3D& rho, int flags = GYRO_FLAGS); -Field3D gyroPade0(const Field3D& f, const Field2D& rho, int flags = GYRO_FLAGS); -Field3D gyroPade0(const Field3D& f, BoutReal rho, int flags = GYRO_FLAGS); +Field3D gyroPade0(const Field3D& f, const Field3D& rho, int inner_boundary_flags, int outer_boundary_flags); +Field3D gyroPade0(const Field3D& f, const Field2D& rho, int inner_boundary_flags, int outer_boundary_flags); +Field3D gyroPade0(const Field3D& f, BoutReal rho, int inner_boundary_flags, int outer_boundary_flags); + +// Can replace these with default arguments to versions above once the deprecated versions +// below are removed +inline Field3D gyroPade0(const Field3D& f, const Field3D& rho) { + return gyroPade0(f, rho, GYRO_FLAGS, GYRO_FLAGS); +} +inline Field3D gyroPade0(const Field3D& f, const Field2D& rho) { + return gyroPade0(f, rho, GYRO_FLAGS, GYRO_FLAGS); +} +inline Field3D gyroPade0(const Field3D& f, BoutReal rho) { + return gyroPade0(f, rho, GYRO_FLAGS, GYRO_FLAGS); +} + +[[gnu::deprecated("Please use version with separate inner_boundary_flags and outer_boundary_flags")]] +Field3D gyroPade0(const Field3D& f, const Field3D& rho, int flags); +[[gnu::deprecated("Please use version with separate inner_boundary_flags and outer_boundary_flags")]] +Field3D gyroPade0(const Field3D& f, const Field2D& rho, int flags); +[[gnu::deprecated("Please use version with separate inner_boundary_flags and outer_boundary_flags")]] +Field3D gyroPade0(const Field3D& f, BoutReal rho, int flags); /// Pade approximation \f$Gamma_1 = (1 - \frac{1}{2} \rho^2 \nabla_\perp^2)g = f\f$ /// @@ -69,10 +88,34 @@ Field3D gyroPade0(const Field3D& f, BoutReal rho, int flags = GYRO_FLAGS); /// @param[in] f The field to gyro-average /// @param[in] rho Gyro-radius /// @param[in] flags Flags to be passed to the Laplacian inversion operator -Field3D gyroPade1(const Field3D& f, const Field3D& rho, int flags = GYRO_FLAGS); -Field3D gyroPade1(const Field3D& f, const Field2D& rho, int flags = GYRO_FLAGS); -Field3D gyroPade1(const Field3D& f, BoutReal rho, int flags = GYRO_FLAGS); -Field2D gyroPade1(const Field2D& f, const Field2D& rho, int flags = GYRO_FLAGS); +Field3D gyroPade1(const Field3D& f, const Field3D& rho, int inner_boundary_flags, int outer_boundary_flags); +Field3D gyroPade1(const Field3D& f, const Field2D& rho, int inner_boundary_flags, int outer_boundary_flags); +Field3D gyroPade1(const Field3D& f, BoutReal rho, int inner_boundary_flags, int outer_boundary_flags); +Field2D gyroPade1(const Field2D& f, const Field2D& rho, int inner_boundary_flags, int outer_boundary_flags); + +// Can replace these with default arguments to versions above once the deprecated versions +// below are removed +inline Field3D gyroPade1(const Field3D& f, const Field3D& rho) { + return gyroPade1(f, rho, GYRO_FLAGS, GYRO_FLAGS); +} +inline Field3D gyroPade1(const Field3D& f, const Field2D& rho) { + return gyroPade1(f, rho, GYRO_FLAGS, GYRO_FLAGS); +} +inline Field3D gyroPade1(const Field3D& f, BoutReal rho) { + return gyroPade1(f, rho, GYRO_FLAGS, GYRO_FLAGS); +} +inline Field2D gyroPade1(const Field2D& f, const Field2D& rho) { + return gyroPade1(f, rho, GYRO_FLAGS, GYRO_FLAGS); +} + +[[gnu::deprecated("Please use version with separate inner_boundary_flags and outer_boundary_flags")]] +Field3D gyroPade1(const Field3D& f, const Field3D& rho, int flags); +[[gnu::deprecated("Please use version with separate inner_boundary_flags and outer_boundary_flags")]] +Field3D gyroPade1(const Field3D& f, const Field2D& rho, int flags); +[[gnu::deprecated("Please use version with separate inner_boundary_flags and outer_boundary_flags")]] +Field3D gyroPade1(const Field3D& f, BoutReal rho, int flags); +[[gnu::deprecated("Please use version with separate inner_boundary_flags and outer_boundary_flags")]] +Field2D gyroPade1(const Field2D& f, const Field2D& rho, int flags); /// Pade approximation /// @@ -85,8 +128,27 @@ Field2D gyroPade1(const Field2D& f, const Field2D& rho, int flags = GYRO_FLAGS); /// @param[in] f The field to gyro-average /// @param[in] rho Gyro-radius /// @param[in] flags Flags to be passed to the Laplacian inversion operator -Field3D gyroPade2(const Field3D& f, const Field3D& rho, int flags = GYRO_FLAGS); -Field3D gyroPade2(const Field3D& f, const Field2D& rho, int flags = GYRO_FLAGS); -Field3D gyroPade2(const Field3D& f, BoutReal rho, int flags = GYRO_FLAGS); +Field3D gyroPade2(const Field3D& f, const Field3D& rho, int inner_boundary_flags, int outer_boundary_flags); +Field3D gyroPade2(const Field3D& f, const Field2D& rho, int inner_boundary_flags, int outer_boundary_flags); +Field3D gyroPade2(const Field3D& f, BoutReal rho, int inner_boundary_flags, int outer_boundary_flags); + +// Can replace these with default arguments to versions above once the deprecated versions +// below are removed +inline Field3D gyroPade2(const Field3D& f, const Field3D& rho) { + return gyroPade2(f, rho, GYRO_FLAGS, GYRO_FLAGS); +} +inline Field3D gyroPade2(const Field3D& f, const Field2D& rho) { + return gyroPade2(f, rho, GYRO_FLAGS, GYRO_FLAGS); +} +inline Field3D gyroPade2(const Field3D& f, BoutReal rho) { + return gyroPade2(f, rho, GYRO_FLAGS, GYRO_FLAGS); +} + +[[gnu::deprecated("Please use version with separate inner_boundary_flags and outer_boundary_flags")]] +Field3D gyroPade2(const Field3D& f, const Field3D& rho, int flags); +[[gnu::deprecated("Please use version with separate inner_boundary_flags and outer_boundary_flags")]] +Field3D gyroPade2(const Field3D& f, const Field2D& rho, int flags); +[[gnu::deprecated("Please use version with separate inner_boundary_flags and outer_boundary_flags")]] +Field3D gyroPade2(const Field3D& f, BoutReal rho, int flags); #endif // __GYRO_AVERAGE_H__ diff --git a/src/physics/gyro_average.cxx b/src/physics/gyro_average.cxx index 135e53fd16..be54714e43 100644 --- a/src/physics/gyro_average.cxx +++ b/src/physics/gyro_average.cxx @@ -38,6 +38,122 @@ Field3D gyroTaylor0(const Field3D& f, const Field3D& rho) { return f + SQ(rho) * Delp2(f); } +Field3D gyroPade0(const Field3D& f, BoutReal rho, int inner_boundary_flags, int outer_boundary_flags) { + const Field2D a = 1.0; + const Field2D d = -rho * rho; + + // Invert, leaving boundaries unchanged + + Timer timer("invert"); + + auto* lap = Laplacian::defaultInstance(); + + lap->setCoefA(a); + lap->setCoefC(1.0); + lap->setCoefD(d); + lap->setInnerBoundaryFlags(inner_boundary_flags); + lap->setOuterBoundaryFlags(outer_boundary_flags); + + return lap->solve(f).setLocation(f.getLocation()); +} + +Field3D gyroPade0(const Field3D& f, const Field2D& rho, int inner_boundary_flags, int outer_boundary_flags) { + const Field2D a = 1.0; + const Field2D d = -rho * rho; + + // Invert, leaving boundaries unchanged + Timer timer("invert"); + + auto* lap = Laplacian::defaultInstance(); + + lap->setCoefA(a); + lap->setCoefC(1.0); + lap->setCoefD(d); + lap->setInnerBoundaryFlags(inner_boundary_flags); + lap->setOuterBoundaryFlags(outer_boundary_flags); + + return lap->solve(f).setLocation(f.getLocation()); +} + +Field3D gyroPade0(const Field3D& f, const Field3D& rho, int inner_boundary_flags, int outer_boundary_flags) { + // Have to use Z average of rho for efficient inversion + return gyroPade0(f, DC(rho), inner_boundary_flags, outer_boundary_flags); +} + +Field3D gyroPade1(const Field3D& f, BoutReal rho, int inner_boundary_flags, int outer_boundary_flags) { + const Field2D a = 1.0; + const Field2D d = -0.5 * rho * rho; + + // Invert, leaving boundaries unchanged + Timer timer("invert"); + + auto* lap = Laplacian::defaultInstance(); + + lap->setCoefA(a); + lap->setCoefC(1.0); + lap->setCoefD(d); + lap->setInnerBoundaryFlags(inner_boundary_flags); + lap->setOuterBoundaryFlags(outer_boundary_flags); + + return lap->solve(f).setLocation(f.getLocation()); +} + +Field3D gyroPade1(const Field3D& f, const Field2D& rho, int inner_boundary_flags, int outer_boundary_flags) { + const Field2D a = 1.0; + const Field2D d = -0.5 * rho * rho; + + // Invert, leaving boundaries unchanged + Timer timer("invert"); + + auto* lap = Laplacian::defaultInstance(); + + lap->setCoefA(a); + lap->setCoefC(1.0); + lap->setCoefD(d); + lap->setInnerBoundaryFlags(inner_boundary_flags); + lap->setOuterBoundaryFlags(outer_boundary_flags); + + return lap->solve(f).setLocation(f.getLocation()); +} + +Field3D gyroPade1(const Field3D& f, const Field3D& rho, int inner_boundary_flags, int outer_boundary_flags) { + return gyroPade1(f, DC(rho), inner_boundary_flags, outer_boundary_flags); +} + +Field2D gyroPade1(const Field2D& f, const Field2D& rho, int inner_boundary_flags, int outer_boundary_flags) { + // Very inefficient implementation + Field3D tmp = f; + tmp = gyroPade1(tmp, rho, inner_boundary_flags, outer_boundary_flags); + return DC(tmp); +} + +Field3D gyroPade2(const Field3D& f, BoutReal rho, int inner_boundary_flags, int outer_boundary_flags) { + Field3D result = gyroPade1(gyroPade1(f, rho, inner_boundary_flags, outer_boundary_flags), + rho, inner_boundary_flags, outer_boundary_flags); + + result.getMesh()->communicate(result); + result = 0.5 * rho * rho * Delp2(result); + result.applyBoundary("dirichlet"); + return result; +} + +Field3D gyroPade2(const Field3D& f, const Field2D& rho, int inner_boundary_flags, int outer_boundary_flags) { + Field3D result = gyroPade1(gyroPade1(f, rho, inner_boundary_flags, outer_boundary_flags), + rho, inner_boundary_flags, outer_boundary_flags); + result.getMesh()->communicate(result); + result = 0.5 * rho * rho * Delp2(result); + result.applyBoundary("dirichlet"); + return result; +} + +Field3D gyroPade2(const Field3D& f, const Field3D& rho, int inner_boundary_flags, int outer_boundary_flags) { + // Have to use Z average of rho for efficient inversion + return gyroPade2(f, DC(rho), inner_boundary_flags, outer_boundary_flags); +} + +//////////////////////////////////////////////////////////////////////////////// +// Deprecated version of gyroPade operators, using old-style flags +//////////////////////////////////////////////////////////////////////////////// Field3D gyroPade0(const Field3D& f, BoutReal rho, int flags) { const Field2D a = 1.0; const Field2D d = -rho * rho; From 721e8fa263939dbd9437e3334bd36a26aa9922cc Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 22:38:08 +0100 Subject: [PATCH 1657/1783] Deprecate Laplacian::setFlags method Prefer the new-style setGlobalFlags, setInnerFlags and setOuterFlags. --- include/invert_laplace.hxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index 68b1d30f91..a5460fc420 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -183,11 +183,14 @@ public: setCoefEz(f); } - virtual void setFlags(int f); virtual void setGlobalFlags(int f) { global_flags = f; } virtual void setInnerBoundaryFlags(int f) { inner_boundary_flags = f; } virtual void setOuterBoundaryFlags(int f) { outer_boundary_flags = f; } + [[gnu::deprecated("Please use setGlobalFlags, setInnerBoundaryFlags and " + "setOuterBoundaryFlags methods instead")]] + virtual void setFlags(int f); + /// Does this solver use Field3D coefficients (true) or only their DC component (false) virtual bool uses3DCoefs() const { return false; } From 4443bbe4d5675f239b5b5b53bf09a78ada24a248 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 22:39:13 +0100 Subject: [PATCH 1658/1783] Correct setting of INVERT_4TH_ORDER flags in test-petsc_laplace Previously was incorrectly using 'setFlags' instead of 'setGlobalFlags'. --- tests/integrated/test-petsc_laplace/test_petsc_laplace.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integrated/test-petsc_laplace/test_petsc_laplace.cxx b/tests/integrated/test-petsc_laplace/test_petsc_laplace.cxx index ff5d35e470..f4ec3ea384 100644 --- a/tests/integrated/test-petsc_laplace/test_petsc_laplace.cxx +++ b/tests/integrated/test-petsc_laplace/test_petsc_laplace.cxx @@ -248,7 +248,7 @@ int main(int argc, char** argv) { invert_4th->setInnerBoundaryFlags(INVERT_AC_GRAD); invert_4th->setOuterBoundaryFlags(INVERT_AC_GRAD); - invert_4th->setFlags(INVERT_4TH_ORDER); + invert_4th->setGlobalFlags(INVERT_4TH_ORDER); invert_4th->setCoefA(a1); invert_4th->setCoefC(c1); invert_4th->setCoefD(d1); @@ -555,7 +555,7 @@ int main(int argc, char** argv) { BoutReal max_error6; //Output of test invert_4th->setInnerBoundaryFlags(INVERT_AC_GRAD); invert_4th->setOuterBoundaryFlags(INVERT_AC_GRAD); - invert_4th->setFlags(INVERT_4TH_ORDER); + invert_4th->setGlobalFlags(INVERT_4TH_ORDER); invert_4th->setCoefA(a5); invert_4th->setCoefC(c5); invert_4th->setCoefD(d5); From 8fabe79bccc3f20ce45e57e6badb62bb61ab6247 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 22:43:05 +0100 Subject: [PATCH 1659/1783] Remove unnecessary 'setFlags' from laplace-dae example --- examples/constraints/laplace-dae/laplace_dae.cxx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/constraints/laplace-dae/laplace_dae.cxx b/examples/constraints/laplace-dae/laplace_dae.cxx index 801b1ceda6..6dc93839ed 100644 --- a/examples/constraints/laplace-dae/laplace_dae.cxx +++ b/examples/constraints/laplace-dae/laplace_dae.cxx @@ -17,8 +17,6 @@ Field3D phibdry; // Used for calculating error in the boundary bool constraint; -int flags; - Laplacian *phiSolver; ///< Inverts a Laplacian to get phi from U // Preconditioner @@ -33,11 +31,9 @@ int physics_init(bool UNUSED(restarting)) { auto globalOptions = Options::root(); auto options = globalOptions["dae"]; constraint = options["constraint"].withDefault(true); - flags = options["flags"].withDefault(0); // Create a solver for the Laplacian phiSolver = Laplacian::create(); - phiSolver->setFlags(flags); // Just solving one variable, U SOLVE_FOR2(U, Apar); From df05226a49db6750e457ba9fa0a8daa594aab31c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 23:07:48 +0100 Subject: [PATCH 1660/1783] Use options instead of 'phi_flags' and 'apar_flags' in elm-pb example Allows removing use of deprecated 'setFlags' method. --- examples/elm-pb/data/BOUT.inp | 29 +++++++++++------------------ examples/elm-pb/elm_pb.cxx | 11 ++--------- 2 files changed, 13 insertions(+), 27 deletions(-) diff --git a/examples/elm-pb/data/BOUT.inp b/examples/elm-pb/data/BOUT.inp index d9d4ede7d4..97ad044241 100644 --- a/examples/elm-pb/data/BOUT.inp +++ b/examples/elm-pb/data/BOUT.inp @@ -222,24 +222,17 @@ hyperviscos = -1.0 # Radial hyper viscosity phi_curv = true # Include curvature*Grad(phi) in P equation # gamma = 1.6666 -## field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -# 64 - Set the width of the boundary layer to 1 -# 128 - use 4th order differencing -# 256 - Laplacian = 0 inner boundary (combine 2nd & 4th-order) -# 512 - Laplacian = 0 outer boundary ( sometimes works ) - -#phi_flags = 74 # inversion flags for phi (2+8+64+128) -phi_flags = 769 # 256 + 512 - -#apar_flags = 74 # 2+8 -apar_flags = 769 +[phiSolver] +#inner_boundary_flags = 1 + 2 + 128 # INVERT_DC_GRAD + INVERT_AC_GRAD + INVERT_BNDRY_ONE +#outer_boundary_flags = 1 + 2 + 128 # INVERT_DC_GRAD + INVERT_AC_GRAD + INVERT_BNDRY_ONE +inner_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP +outer_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP + +[aparSolver] +#inner_boundary_flags = 1 + 2 + 128 # INVERT_DC_GRAD + INVERT_AC_GRAD + INVERT_BNDRY_ONE +#outer_boundary_flags = 1 + 2 + 128 # INVERT_DC_GRAD + INVERT_AC_GRAD + INVERT_BNDRY_ONE +inner_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP +outer_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP ################################################## # settings for individual variables diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index 8a470ef9ef..49d2917d74 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -109,7 +109,6 @@ class ELMpb : public PhysicsModel { BoutReal vacuum_trans; // Transition width Field3D vac_mask; - int phi_flags, apar_flags; bool nonlinear; bool evolve_jpar; BoutReal g; // Only if compressible @@ -590,10 +589,6 @@ class ELMpb : public PhysicsModel { phi_curv = options["phi_curv"].doc("ExB compression in P equation?").withDefault(true); g = options["gamma"].doc("Ratio of specific heats").withDefault(5.0 / 3.0); - // Field inversion flags - phi_flags = options["phi_flags"].withDefault(0); - apar_flags = options["apar_flags"].withDefault(0); - x = (Psixy - Psiaxis) / (Psibndry - Psiaxis); if (experiment_Er) { // get er from experiment @@ -1063,11 +1058,9 @@ class ELMpb : public PhysicsModel { } // Create a solver for the Laplacian - phiSolver = std::unique_ptr(Laplacian::create()); - phiSolver->setFlags(phi_flags); + phiSolver = std::unique_ptr(Laplacian::create(&options["phiSolver"])); - aparSolver = std::unique_ptr(Laplacian::create()); - aparSolver->setFlags(apar_flags); + aparSolver = std::unique_ptr(Laplacian::create(&options["aparSolver"])); /////////////// CHECK VACUUM /////////////////////// // In vacuum region, initial vorticity should equal zero From ea03b8a38696ed3fe43c1d38f4291ea8195ac787 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 23:18:27 +0100 Subject: [PATCH 1661/1783] Remove phi_flags from reconnect-2field Use [laplace] options to set the boundary flags, rather than a phi_flags variable. --- examples/reconnect-2field/2field.cxx | 4 ---- examples/reconnect-2field/data/BOUT.inp | 15 --------------- 2 files changed, 19 deletions(-) diff --git a/examples/reconnect-2field/2field.cxx b/examples/reconnect-2field/2field.cxx index 6a7f1f8143..69ec60f83d 100644 --- a/examples/reconnect-2field/2field.cxx +++ b/examples/reconnect-2field/2field.cxx @@ -44,7 +44,6 @@ class TwoField : public PhysicsModel { // Method to use: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE BRACKET_METHOD bm; // Bracket method for advection terms - int phi_flags; // Inversion flags bool nonlinear; bool parallel_lc; @@ -85,8 +84,6 @@ class TwoField : public PhysicsModel { eta = options["eta"].doc("Normalised resistivity").withDefault(1e-3); mu = options["mu"].doc("Normalised vorticity").withDefault(1.e-3); - phi_flags = options["phi_flags"].withDefault(0); - switch (options["bracket_method"].withDefault(0)) { case 0: { bm = BRACKET_STD; @@ -213,7 +210,6 @@ class TwoField : public PhysicsModel { // Create a solver for the Laplacian phiSolver = Laplacian::create(); - phiSolver->setFlags(phi_flags); return 0; } diff --git a/examples/reconnect-2field/data/BOUT.inp b/examples/reconnect-2field/data/BOUT.inp index 474dad7f00..3221213403 100644 --- a/examples/reconnect-2field/data/BOUT.inp +++ b/examples/reconnect-2field/data/BOUT.inp @@ -113,21 +113,6 @@ include_jpar0 = false jpar_bndry = 3 -# field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -# 64 - Set the width of the boundary layer to 1 -# 128 - use 4th order differencing -# 256 - Laplacian = 0 inner boundary -# 512 - Laplacian = 0 outer boundary - -phi_flags = 0 # 11 #769 - [All] scale = 0.0 # default size of initial perturbations From ba26f688df88f5911d0a317adf24b6175d910543 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 23:25:11 +0100 Subject: [PATCH 1662/1783] Remove phi_flags and apar_flags from tokamak-2fluid example Use [phiSolver] and [aparSolver] options to set the boundary flags, rather than phi_flags and apar_flags variables. --- examples/tokamak-2fluid/2fluid.cxx | 11 ++--------- examples/tokamak-2fluid/data/BOUT.inp | 17 +++++++---------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/examples/tokamak-2fluid/2fluid.cxx b/examples/tokamak-2fluid/2fluid.cxx index 84d118f327..0ba9a84a0c 100644 --- a/examples/tokamak-2fluid/2fluid.cxx +++ b/examples/tokamak-2fluid/2fluid.cxx @@ -87,8 +87,6 @@ class TwoFluid : public PhysicsModel { int lowPass_z; // Low-pass filter result - int phi_flags, apar_flags; // Inversion flags - // Group of objects for communications FieldGroup comms; @@ -214,9 +212,6 @@ class TwoFluid : public PhysicsModel { lowPass_z = options["lowPass_z"].withDefault(-1); - phi_flags = options["phi_flags"].withDefault(0); - apar_flags = options["apar_flags"].withDefault(0); - evolve_ni = globalOptions["Ni"]["evolve"].withDefault(true); evolve_rho = globalOptions["rho"]["evolve"].withDefault(true); evolve_vi = globalOptions["vi"]["evolve"].withDefault(true); @@ -493,8 +488,7 @@ class TwoFluid : public PhysicsModel { dump.addOnce(wci, "wci"); // Create a solver for the Laplacian - phiSolver = Laplacian::create(); - phiSolver->setFlags(phi_flags); + phiSolver = Laplacian::create(&options["phiSolver"]); if (laplace_extra_rho_term) { // Include the first order term Grad_perp Ni dot Grad_perp phi phiSolver->setCoefC(Ni0); @@ -502,8 +496,7 @@ class TwoFluid : public PhysicsModel { if (! (estatic || ZeroElMass)) { // Create a solver for the electromagnetic potential - aparSolver = Laplacian::create(); - aparSolver->setFlags(apar_flags); + aparSolver = Laplacian::create(&options["aparSolver"]); acoef = (-0.5 * beta_p / fmei) * Ni0; aparSolver->setCoefA(acoef); } diff --git a/examples/tokamak-2fluid/data/BOUT.inp b/examples/tokamak-2fluid/data/BOUT.inp index 35ef03d337..610c00bc58 100644 --- a/examples/tokamak-2fluid/data/BOUT.inp +++ b/examples/tokamak-2fluid/data/BOUT.inp @@ -100,16 +100,13 @@ OhmPe = false # Include Pe in Ohm's law? low_pass_z = -1 # Keep n up to (and including) this number -# field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -phi_flags = 10 # inversion flags for phi -apar_flags = 0 # flags for apar inversion +[phiSolver] +inner_boundary_flags = 1 + 2 # INVERT_DC_GRAD + INVERT_AC_GRAD +outer_boundary_flags = 1 + 2 # INVERT_DC_GRAD + INVERT_AC_GRAD + +[aparSolver] +inner_boundary_flags = 0 +outer_boundary_flags = 0 ################################################## # settings for individual variables From 939e4a43d4c5cc0afc327cd84d8d3ef6fe4b498e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 23:29:10 +0100 Subject: [PATCH 1663/1783] Remove phi_flags and apar_flags from dalf3 example Use [phiSolver] and [aparSolver] options to set the boundary flags, rather than phi_flags and apar_flags variables. --- examples/dalf3/dalf3.cxx | 9 ++------- examples/dalf3/data/BOUT.inp | 22 +++++++--------------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/examples/dalf3/dalf3.cxx b/examples/dalf3/dalf3.cxx index 0587bdd868..d4176e52e4 100644 --- a/examples/dalf3/dalf3.cxx +++ b/examples/dalf3/dalf3.cxx @@ -56,7 +56,6 @@ class DALF3 : public PhysicsModel { BoutReal beta_hat, mu_hat; BoutReal viscosity_par; - int phi_flags, apar_flags; bool split_n0; bool ZeroElMass, estatic; bool curv_kappa; @@ -121,8 +120,6 @@ class DALF3 : public PhysicsModel { auto globalOptions = Options::root(); auto options = globalOptions["dalf3"]; - phi_flags = options["phi_flags"].withDefault(0); - apar_flags = options["apar_flags"].withDefault(0); split_n0 = options["split_n0"].withDefault(false); estatic = options["estatic"].withDefault(false); ZeroElMass = options["ZeroElMass"].withDefault(false); @@ -297,8 +294,7 @@ class DALF3 : public PhysicsModel { } // Create a solver for the Laplacian - phiSolver = Laplacian::create(); - phiSolver->setFlags(phi_flags); + phiSolver = Laplacian::create(&options["phiSolver"]); // LaplaceXY for n=0 solve if (split_n0) { @@ -309,8 +305,7 @@ class DALF3 : public PhysicsModel { // Solver for Apar // ajpar = beta_hat*apar + mu_hat*jpar - aparSolver = Laplacian::create(); - aparSolver->setFlags(apar_flags); + aparSolver = Laplacian::create(&options["aparSolver"]); aparSolver->setCoefA(beta_hat); aparSolver->setCoefD(-mu_hat); diff --git a/examples/dalf3/data/BOUT.inp b/examples/dalf3/data/BOUT.inp index 7a0ea1c363..6ba8f08247 100644 --- a/examples/dalf3/data/BOUT.inp +++ b/examples/dalf3/data/BOUT.inp @@ -95,21 +95,13 @@ bracket_method = 2 # 0 = std, 2 = arakawa, 3 = ctu viscosity = 0.01 viscosity_par = 1.0 -# field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -# 64 - Set the width of the boundary layer to 1 -# 128 - use 4th order differencing -# 256 - Laplacian = 0 inner boundary -# 512 - Laplacian = 0 outer boundary - -phi_flags = 769 -apar_flags = 769 +[phiSolver] +inner_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP +outer_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP + +[aparSolver] +inner_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP +outer_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP split_n0 = true # Split into n=0 and n != 0 From d050ed27942839b58ca9f03270d452c41cc69f57 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 23:32:21 +0100 Subject: [PATCH 1664/1783] Remove phi_flags from lapd-drift example Use [laplace] options to set the boundary flags, rather than a phi_flags variable. --- examples/lapd-drift/lapd/BOUT.inp | 14 +++----------- examples/lapd-drift/lapd_drift.cxx | 6 ------ 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/examples/lapd-drift/lapd/BOUT.inp b/examples/lapd-drift/lapd/BOUT.inp index d2c439ce39..7b73882545 100644 --- a/examples/lapd-drift/lapd/BOUT.inp +++ b/examples/lapd-drift/lapd/BOUT.inp @@ -122,17 +122,9 @@ evolve_source_te = false filter_z = false # Filter in Z filter_z_mode = 1 # Keep this Z harmonic -# field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) - -phi_flags = 9 # inversion flags for phi -apar_flags = 0 # flags for apar inversion +[laplace] +inner_boundary_flags = 1 # INVERT_DC_GRAD +outer_boundary_flags = 2 # INVERT_AC_GRAD ################################################## # settings for individual variables diff --git a/examples/lapd-drift/lapd_drift.cxx b/examples/lapd-drift/lapd_drift.cxx index 96b3cf4125..0198d96be8 100644 --- a/examples/lapd-drift/lapd_drift.cxx +++ b/examples/lapd-drift/lapd_drift.cxx @@ -71,8 +71,6 @@ class LAPDdrift : public PhysicsModel { bool log_density; // Evolve logarithm of the density - int phi_flags, apar_flags; // Inversion flags - bool niprofile; bool evolve_source_ni, evolve_source_te; // If true, evolve a source/sink profile @@ -192,9 +190,6 @@ class LAPDdrift : public PhysicsModel { remove_tor_av_ni = options["remove_tor_av_ni"].withDefault(false); remove_tor_av_te = options["remove_tor_av_te"].withDefault(false); - phi_flags = options["phi_flags"].withDefault(0); - apar_flags = options["apar_flags"].withDefault(0); - nonlinear = options["nonlinear"].withDefault(true); // Toroidal filtering @@ -423,7 +418,6 @@ class LAPDdrift : public PhysicsModel { // Laplacian inversion solver phiSolver = Laplacian::create(); - phiSolver->setFlags(phi_flags); phiSolver->setCoefC(Ni0); return 0; From 2ac367c6409e2e7f2de3f65e0f8786d992e62e42 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 23:35:44 +0100 Subject: [PATCH 1665/1783] Remove phi_flags and apar_flags from shear-alfven-wave example Use [phiSolver] and [aparSolver] options to set the boundary flags, rather than phi_flags and apar_flags variables. --- examples/shear-alfven-wave/2fluid.cxx | 9 ++------- examples/shear-alfven-wave/data/BOUT.inp | 17 +++++++---------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/examples/shear-alfven-wave/2fluid.cxx b/examples/shear-alfven-wave/2fluid.cxx index 6c4df2d83d..c990bdcb20 100644 --- a/examples/shear-alfven-wave/2fluid.cxx +++ b/examples/shear-alfven-wave/2fluid.cxx @@ -108,9 +108,6 @@ class ShearAlfven : public PhysicsModel { nu_perp = options["nu_perp"].withDefault(0.0); ShearFactor = options["ShearFactor"].withDefault(1.0); - phi_flags = options["phi_flags"].withDefault(0); - apar_flags = options["apar_flags"].withDefault(0); - /************* SHIFTED RADIAL COORDINATES ************/ // Check type of parallel transform @@ -226,11 +223,9 @@ class ShearAlfven : public PhysicsModel { SAVE_ONCE(Te_x, Ti_x, Ni_x, rho_s, wci); // Create a solver for the Laplacian - phiSolver = Laplacian::create(); - phiSolver->setFlags(phi_flags); + phiSolver = Laplacian::create(&options["phiSolver"]); - aparSolver = Laplacian::create(); - aparSolver->setFlags(apar_flags); + aparSolver = Laplacian::create(&options["aparSolver"]); aparSolver->setCoefA((-0.5 * beta_p / fmei) * Ni0); return 0; diff --git a/examples/shear-alfven-wave/data/BOUT.inp b/examples/shear-alfven-wave/data/BOUT.inp index 7a69a66d88..372c1ec7f1 100644 --- a/examples/shear-alfven-wave/data/BOUT.inp +++ b/examples/shear-alfven-wave/data/BOUT.inp @@ -63,16 +63,13 @@ nu_perp = 1.0e-20 ShearFactor = 0.0 -# field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -phi_flags = 3 # inversion flags for phi -apar_flags = 0 # flags for apar inversion +[phiSolver] +inner_boundary_flags = 3 # INVERT_DC_GRAD + INVERT_AC_GRAD +outer_boundary_flags = 0 + +[aparSolver] +inner_boundary_flags = 0 +outer_boundary_flags = 0 ################################################## # settings for individual variables From c0038e02b1c28ab99f287152532d3e1a10ce3855 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 23:38:47 +0100 Subject: [PATCH 1666/1783] Remove phi_flags and apar_flags from jorek-compare example Use [laplace] options to set the boundary flags, rather than phi_flags and apar_flags variables. --- examples/jorek-compare/data/BOUT.inp | 17 +++-------------- examples/jorek-compare/jorek_compare.cxx | 5 ----- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/examples/jorek-compare/data/BOUT.inp b/examples/jorek-compare/data/BOUT.inp index 3d2dc5ec71..670698bd1b 100644 --- a/examples/jorek-compare/data/BOUT.inp +++ b/examples/jorek-compare/data/BOUT.inp @@ -115,20 +115,9 @@ parallel_lc = true # Use LtoC and CtoL differencing bracket_method = 2 # 0 = std, 1=simplified, 2 = arakawa, 3 = ctu -# field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -# 64 - Set the width of the boundary layer to 1 -# 128 - use 4th order differencing -# 256 - Laplacian = 0 inner boundary (combine 2nd & 4th-order) -# 512 - Laplacian = 0 outer boundary ( sometimes works ) - -phi_flags = 769 # inversion flags for phi +[laplace] +inner_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP +outer_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP ################################################## # settings for individual variables diff --git a/examples/jorek-compare/jorek_compare.cxx b/examples/jorek-compare/jorek_compare.cxx index 331902e118..859813049f 100644 --- a/examples/jorek-compare/jorek_compare.cxx +++ b/examples/jorek-compare/jorek_compare.cxx @@ -36,8 +36,6 @@ class Jorek : public PhysicsModel { BoutReal viscos_par, viscos_perp, viscos_coll; // Viscosity coefficients BoutReal hyperresist; // Hyper-resistivity coefficient - int phi_flags; - // Constants const BoutReal MU0 = 4.0e-7 * PI; const BoutReal Charge = 1.60217646e-19; // electron charge e (C) @@ -200,8 +198,6 @@ class Jorek : public PhysicsModel { include_profiles = options["include_profiles"].withDefault(false); parallel_lc = options["parallel_lc"].withDefault(true); - phi_flags = options["phi_flags"].withDefault(0); - low_pass_z = options["low_pass_z"].withDefault(-1); // Default is no filtering Wei = options["Wei"].withDefault(1.0); @@ -358,7 +354,6 @@ class Jorek : public PhysicsModel { // Create a solver for the Laplacian phiSolver = Laplacian::create(); - phiSolver->setFlags(phi_flags); if (vorticity_momentum) { phiSolver->setCoefC(rho0); } From b4a4b563bcbeed94b275735f8601867097848d29 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 23:40:39 +0100 Subject: [PATCH 1667/1783] Remove phi_flags and apar_flags from em-drift example Use [laplace] options to set the boundary flags, rather than phi_flags and apar_flags variables. --- examples/em-drift/2fluid.cxx | 11 ++--------- examples/em-drift/data/BOUT.inp | 17 +++++++---------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/examples/em-drift/2fluid.cxx b/examples/em-drift/2fluid.cxx index 961567672a..b1e358c70f 100644 --- a/examples/em-drift/2fluid.cxx +++ b/examples/em-drift/2fluid.cxx @@ -43,8 +43,6 @@ class EMdrift : public PhysicsModel { BoutReal ShearFactor; BoutReal nu_factor; - int phi_flags, apar_flags; // Inversion flags - // Communication object FieldGroup comms; @@ -103,9 +101,6 @@ class EMdrift : public PhysicsModel { ShearFactor = options["ShearFactor"].withDefault(1.0); nu_factor = options["nu_factor"].withDefault(1.0); - phi_flags = options["phi_flags"].withDefault(0); - apar_flags = options["apar_flags"].withDefault(0); - evolve_ajpar = globalOptions["Ajpar"]["evolve"].withDefault(true); if (ZeroElMass) { @@ -231,13 +226,11 @@ class EMdrift : public PhysicsModel { SAVE_ONCE(Te_x, Ti_x, Ni_x, rho_s, wci, zeff, AA); // Create a solver for the Laplacian - phiSolver = Laplacian::create(); - phiSolver->setFlags(phi_flags); + phiSolver = Laplacian::create(&options["phiSolver"]); if (! (estatic || ZeroElMass)) { // Create a solver for the electromagnetic potential - aparSolver = Laplacian::create(); - aparSolver->setFlags(apar_flags); + aparSolver = Laplacian::create(&options["aparSolver"]); acoef = (-0.5 * beta_p / fmei) * Ni0; aparSolver->setCoefA(acoef); } diff --git a/examples/em-drift/data/BOUT.inp b/examples/em-drift/data/BOUT.inp index 27dafe7d6f..5aac7a4fa3 100644 --- a/examples/em-drift/data/BOUT.inp +++ b/examples/em-drift/data/BOUT.inp @@ -68,16 +68,13 @@ ShearFactor = 0.0 nu_factor = 5.18718e-4 #nu_factor = 1e-3 -# field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -phi_flags = 0 # inversion flags for phi -apar_flags = 0 # flags for apar inversion +[phiSolver] +inner_boundary_flags = 0 +outer_boundary_flags = 0 + +[aparSolver] +inner_boundary_flags = 0 +outer_boundary_flags = 0 ################################################## # settings for individual variables From bb075122f57cf8afdbf20b193e72783f117a881e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 23:42:15 +0100 Subject: [PATCH 1668/1783] Remove phi_flags from conducting-wall-mode example Use [laplace] options to set the boundary flags, rather than a phi_flags variable. --- examples/conducting-wall-mode/cwm.cxx | 5 ----- examples/conducting-wall-mode/data/BOUT.inp | 15 ++++----------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/examples/conducting-wall-mode/cwm.cxx b/examples/conducting-wall-mode/cwm.cxx index 9289a2b6ec..859bcbca12 100644 --- a/examples/conducting-wall-mode/cwm.cxx +++ b/examples/conducting-wall-mode/cwm.cxx @@ -45,8 +45,6 @@ class CWM : public PhysicsModel { bool filter_z; int filter_z_mode; - int phi_flags; // Inversion flags - // Coefficients for linear sheath problem Field2D LAMBDA1, LAMBDA2; @@ -119,8 +117,6 @@ class CWM : public PhysicsModel { ShearFactor = options["ShearFactor"].withDefault(1.0); bout_exb = options["bout_exb"].withDefault(false); - phi_flags = options["phi_flags"].withDefault(0); - // Toroidal filtering filter_z = options["filter_z"].withDefault(false); // Filter a single n filter_z_mode = options["filter_z_mode"].withDefault(1); @@ -238,7 +234,6 @@ class CWM : public PhysicsModel { // Create a solver for the Laplacian phiSolver = Laplacian::create(); - phiSolver->setFlags(phi_flags); return 0; } diff --git a/examples/conducting-wall-mode/data/BOUT.inp b/examples/conducting-wall-mode/data/BOUT.inp index 8cee6389f6..2812ae3a48 100644 --- a/examples/conducting-wall-mode/data/BOUT.inp +++ b/examples/conducting-wall-mode/data/BOUT.inp @@ -80,16 +80,9 @@ bout_exb = true # Use the BOUT-06 subset of ExB terms filter_z = true # Filter in Z filter_z_mode = 1 # Keep this Z harmonic -# field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) - -phi_flags = 10 # inversion flags for phi +[laplace] +inner_boundary_flags = 2 # INVERT_AC_GRAD +outer_boundary_flags = 2 # INVERT_AC_GRAD ################################################## # settings for individual variables @@ -117,4 +110,4 @@ scale = -1.0e-8 function = sin(y) * sin(z) -[te] \ No newline at end of file +[te] From aeebb4106c71a0f81b06b7531f65857d52286a52 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 23:44:00 +0100 Subject: [PATCH 1669/1783] Remove phi_flags and apar_flags from gyro-gem example Use [laplace] options to set the boundary flags, rather than phi_flags and apar_flags variables. --- examples/gyro-gem/data/BOUT.inp | 18 +++++++----------- examples/gyro-gem/gem.cxx | 11 ++--------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/examples/gyro-gem/data/BOUT.inp b/examples/gyro-gem/data/BOUT.inp index 235b4c9069..01c6e3afad 100644 --- a/examples/gyro-gem/data/BOUT.inp +++ b/examples/gyro-gem/data/BOUT.inp @@ -86,17 +86,13 @@ output_ddt = false # Save time derivs to file curv_logB = true # For flux-tube, read in logB separately -# field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) - -phi_flags = 0 # inversion flags for phi -apar_flags =0 # flags for apar inversion +[phiSolver] +inner_boundary_flags = 0 +outer_boundary_flags = 0 + +[aparSolver] +inner_boundary_flags = 0 +outer_boundary_flags = 0 low_pass_z = -1 # Toroidal filtering diff --git a/examples/gyro-gem/gem.cxx b/examples/gyro-gem/gem.cxx index efddb22969..38b54093b2 100644 --- a/examples/gyro-gem/gem.cxx +++ b/examples/gyro-gem/gem.cxx @@ -110,8 +110,6 @@ class GEM : public PhysicsModel { // Method to use for brackets: BRACKET_ARAKAWA, BRACKET_STD or BRACKET_SIMPLE const BRACKET_METHOD bm = BRACKET_SIMPLE; - int phi_flags, apar_flags; // Inversion flags - int low_pass_z; // Toroidal (Z) filtering of all variables ////////////////////////////////////////// @@ -172,9 +170,6 @@ class GEM : public PhysicsModel { options["nu_perp"].withDefault(0.01); // Artificial perpendicular dissipation nu_par = options["nu_par"].withDefault(3e-3); // Artificial parallel dissipation - phi_flags = options["phi_flags"].withDefault(0); - apar_flags = options["apar_flags"].withDefault(0); - low_pass_z = options["low_pass_z"].withDefault(-1); // Default is no filtering curv_logB = @@ -533,11 +528,9 @@ class GEM : public PhysicsModel { Apar.setBoundary("Apar"); // Create a solver for the Laplacian - phiSolver = Laplacian::create(); - phiSolver->setFlags(phi_flags); + phiSolver = Laplacian::create(&options["phiSolver"]); - aparSolver = Laplacian::create(); - aparSolver->setFlags(apar_flags); + aparSolver = Laplacian::create(&options["aparSolver"]); aparSolver->setCoefA(beta_e * (1./mu_e - 1./mu_i)); return 0; From a3ee770d9ac9d7b16a9a1c61d04fb06be1410c08 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 23:45:51 +0100 Subject: [PATCH 1670/1783] Remove phi_flags from gravity_reduced example Use [laplace] options to set the boundary flags, rather than a phi_flags variable. --- examples/gravity_reduced/data/BOUT.inp | 19 +++---------------- examples/gravity_reduced/gravity_reduced.cxx | 7 +------ 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/examples/gravity_reduced/data/BOUT.inp b/examples/gravity_reduced/data/BOUT.inp index 47d9bbd0ad..7d817bf9ff 100644 --- a/examples/gravity_reduced/data/BOUT.inp +++ b/examples/gravity_reduced/data/BOUT.inp @@ -90,22 +90,9 @@ viscos_par = 0.1 # Parallel viscosity (< 0 = none) #(try 0.1) viscos_perp = -1.0 # Perpendicular -# field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -# 64 - Set the width of the boundary layer to 1 -# 128 - use 4th order differencing -# 256 - Laplacian = 0 inner boundary -# 512 - Laplacian = 0 outer boundary - -phi_flags = 0 # inversion flags for phi +[laplace] +inner_boundary_flags = 0 +outer_boundary_flags = 0 ################################################## # settings for individual variables diff --git a/examples/gravity_reduced/gravity_reduced.cxx b/examples/gravity_reduced/gravity_reduced.cxx index 0370d88a11..4cf96c0211 100644 --- a/examples/gravity_reduced/gravity_reduced.cxx +++ b/examples/gravity_reduced/gravity_reduced.cxx @@ -50,9 +50,6 @@ class GravityReduced : public PhysicsModel { BoutReal viscos_perp; // Perpendicular viscosity BoutReal hyperviscos; // Hyper-viscosity (radial) - // Number which specifies the boundary condition on phi in the inversion - int phi_flags; - BRACKET_METHOD bm = BRACKET_ARAKAWA; /// Solver for inverting Laplacian @@ -99,7 +96,6 @@ class GravityReduced : public PhysicsModel { output <<"Solving WITHOUT nonlinear terms\n"; } - phi_flags = options["phi_flags"].withDefault(0); phi.setBoundary("phi"); viscos_par = options["viscos_par"].withDefault(0.); @@ -154,14 +150,13 @@ class GravityReduced : public PhysicsModel { // Create a solver for the Laplacian phiSolver = Laplacian::create(); - phiSolver->setFlags(phi_flags); return 0; } int rhs(BoutReal UNUSED(t)) override { // U = Delp2(phi); - phi = phiSolver->solve(U); // Invert Laplacian, setting boundary condition in phi_flags + phi = phiSolver->solve(U); // Invert Laplacian phi.applyBoundary(); // Apply boundary condition in Y mesh->communicate(comms); From dcfa79b9b91611a6da210a420ffff3bb96d23233 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 29 Jun 2019 23:47:37 +0100 Subject: [PATCH 1671/1783] Remove phi_flags and apar_flags from 6field-simple example Use [laplace] options to set the boundary flags, rather than phi_flags and apar_flags variables. --- examples/6field-simple/data/BOUT.inp | 29 +++++++++++----------------- examples/6field-simple/elm_6f.cxx | 11 ++--------- 2 files changed, 13 insertions(+), 27 deletions(-) diff --git a/examples/6field-simple/data/BOUT.inp b/examples/6field-simple/data/BOUT.inp index 8a2a53a0b2..e25d357b79 100644 --- a/examples/6field-simple/data/BOUT.inp +++ b/examples/6field-simple/data/BOUT.inp @@ -229,24 +229,17 @@ hyperviscos = -1.0 # Radial hyper viscosity phi_curv = true # Include curvature*Grad(phi) in P equation # gamma = 1.6666 -## field inversion flags: Add the following -# 1 - Zero-gradient DC component on inner boundary -# 2 - Zero-gradient AC component on inner boundary -# 4 - " DC " " outer " -# 8 - " AC " " outer " -# 16 - Zero all DC components of the result -# 32 - Don't use previous solution to start iterations -# (iterative methods only) -# 64 - Set the width of the boundary layer to 1 -# 128 - use 4th order differencing -# 256 - Laplacian = 0 inner boundary (combine 2nd & 4th-order) -# 512 - Laplacian = 0 outer boundary ( sometimes works ) - -#phi_flags = 74 # inversion flags for phi (2+8+64+128) -phi_flags = 769 # 256 + 512 - -#apar_flags = 74 # 2+8 -apar_flags = 769 +[phiSolver] +#inner_boundary_flags = 1 + 2 + 128 # INVERT_DC_GRAD + INVERT_AC_GRAD + INVERT_BNDRY_ONE +#outer_boundary_flags = 1 + 2 + 128 # INVERT_DC_GRAD + INVERT_AC_GRAD + INVERT_BNDRY_ONE +inner_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP +outer_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP + +[aparSolver] +#inner_boundary_flags = 1 + 2 + 128 # INVERT_DC_GRAD + INVERT_AC_GRAD + INVERT_BNDRY_ONE +#outer_boundary_flags = 1 + 2 + 128 # INVERT_DC_GRAD + INVERT_AC_GRAD + INVERT_BNDRY_ONE +inner_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP +outer_boundary_flags = 1 + 4 # INVERT_DC_GRAD + INVERT_AC_LAP ################################################## # settings for individual variables diff --git a/examples/6field-simple/elm_6f.cxx b/examples/6field-simple/elm_6f.cxx index c4984369c7..946d776301 100644 --- a/examples/6field-simple/elm_6f.cxx +++ b/examples/6field-simple/elm_6f.cxx @@ -132,7 +132,6 @@ BoutReal vacuum_pressure; BoutReal vacuum_trans; // Transition width Field3D vac_mask; -int phi_flags, apar_flags; bool nonlinear; bool evolve_jpar; BoutReal g; // Only if compressible @@ -615,10 +614,6 @@ int physics_init(bool restarting) { phi_curv = options["phi_curv"].withDefault(true); g = options["gamma"].withDefault(5.0 / 3.0); - // Field inversion flags - phi_flags = options["phi_flags"].withDefault(0); - apar_flags = options["apar_flags"].withDefault(0); - if (!include_curvature) b0xcv = 0.0; @@ -1130,11 +1125,9 @@ int physics_init(bool restarting) { SAVE_ONCE3(Ti0, Te0, N0); // Create a solver for the Laplacian - phiSolver = Laplacian::create(); - phiSolver->setFlags(phi_flags); + phiSolver = Laplacian::create(&options["phiSolver"]); - aparSolver = Laplacian::create(); - aparSolver->setFlags(apar_flags); + aparSolver = Laplacian::create(&options["aparSolver"]); /////////////// CHECK VACUUM /////////////////////// // In vacuum region, initial vorticity should equal zero From 624cf70dc004714f5544e6b10e13b7cc8fc865ef Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 30 Jun 2019 01:02:21 +0100 Subject: [PATCH 1672/1783] Update deprecated gyroPade operators in gyro-gem example --- examples/gyro-gem/gem.cxx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/gyro-gem/gem.cxx b/examples/gyro-gem/gem.cxx index 38b54093b2..d50888f696 100644 --- a/examples/gyro-gem/gem.cxx +++ b/examples/gyro-gem/gem.cxx @@ -628,8 +628,8 @@ class GEM : public PhysicsModel { Phi_G = 0.0; } else { // Gyro-reduced potentials - phi_G = gyroPade1(phi, rho_e, INVERT_IN_RHS | INVERT_OUT_RHS); - Phi_G = gyroPade2(phi, rho_e, INVERT_IN_RHS | INVERT_OUT_RHS); + phi_G = gyroPade1(phi, rho_e, INVERT_RHS, INVERT_RHS); + Phi_G = gyroPade2(phi, rho_e, INVERT_RHS, INVERT_RHS); mesh->communicate(phi_G, Phi_G); } @@ -785,8 +785,8 @@ class GEM : public PhysicsModel { // Ion equations // Calculate gyroreduced potentials - phi_G = gyroPade1(phi, rho_i, INVERT_IN_RHS | INVERT_OUT_RHS); - Phi_G = gyroPade2(phi, rho_i, INVERT_IN_RHS | INVERT_OUT_RHS); + phi_G = gyroPade1(phi, rho_i, INVERT_RHS, INVERT_RHS); + Phi_G = gyroPade2(phi, rho_i, INVERT_RHS, INVERT_RHS); mesh->communicate(phi_G, Phi_G); @@ -968,8 +968,8 @@ class GEM : public PhysicsModel { Phi_G = 0.0; } else { // Gyro-reduced potentials - phi_G = gyroPade1(phi, rho_e, INVERT_IN_RHS | INVERT_OUT_RHS); - Phi_G = gyroPade2(phi, rho_e, INVERT_IN_RHS | INVERT_OUT_RHS); + phi_G = gyroPade1(phi, rho_e, INVERT_RHS, INVERT_RHS); + Phi_G = gyroPade2(phi, rho_e, INVERT_RHS, INVERT_RHS); mesh->communicate(phi_G, Phi_G); } @@ -1017,8 +1017,8 @@ class GEM : public PhysicsModel { // Ion equations // Calculate gyroreduced potentials - phi_G = gyroPade1(phi, rho_i, INVERT_IN_RHS | INVERT_OUT_RHS); - Phi_G = gyroPade2(phi, rho_i, INVERT_IN_RHS | INVERT_OUT_RHS); + phi_G = gyroPade1(phi, rho_i, INVERT_RHS, INVERT_RHS); + Phi_G = gyroPade2(phi, rho_i, INVERT_RHS, INVERT_RHS); mesh->communicate(phi_G, Phi_G); From 4f634efebc3dec8a23dfe871f9cc5d69a8617153 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 30 Jun 2019 01:29:15 +0100 Subject: [PATCH 1673/1783] Remove unneeded, old-style INVERT_IN_RHS and INVERT_OUT_RHS --- include/invert_laplace.hxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/invert_laplace.hxx b/include/invert_laplace.hxx index a5460fc420..8a88ecbd2b 100644 --- a/include/invert_laplace.hxx +++ b/include/invert_laplace.hxx @@ -113,9 +113,6 @@ constexpr int INVERT_KX_ZERO = 16; const int INVERT_DC_IN_GRADPARINV = 2097152; */ -const int INVERT_IN_RHS = 16384; ///< Use input value in RHS at inner boundary -const int INVERT_OUT_RHS = 32768; ///< Use input value in RHS at outer boundary - /// Base class for Laplacian inversion class Laplacian { public: From 7ed20c7913c80b090e0b2074ebda1f5de5c3f454 Mon Sep 17 00:00:00 2001 From: hahahasan Date: Mon, 1 Jul 2019 15:49:43 +0100 Subject: [PATCH 1674/1783] Add mesh options for extrapolate_{x,y} Allows extrapolation of metric components into boundary cells to be disabled, as these can create negative values for g11. --- .gitmodules | 3 +++ 3rdparty/variant | 1 + src/mesh/coordinates.cxx | 8 ++++---- 3 files changed, 8 insertions(+), 4 deletions(-) create mode 160000 3rdparty/variant diff --git a/.gitmodules b/.gitmodules index 27c98fc7be..fa166d2a79 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "mpark.variant"] path = externalpackages/mpark.variant url = https://github.com/mpark/variant.git +[submodule "3rdparty/variant"] + path = 3rdparty/variant + url = https://github.com/mpark/variant.git diff --git a/3rdparty/variant b/3rdparty/variant new file mode 160000 index 0000000000..00590420f8 --- /dev/null +++ b/3rdparty/variant @@ -0,0 +1 @@ +Subproject commit 00590420f8d067f67d60b5de15d94b26558164c1 diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 5b026dbe4f..c23c880838 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -210,17 +210,17 @@ Coordinates::Coordinates(Mesh* mesh, Options* options) // 'interpolateAndExtrapolate' to set them. Ensures that derivatives are // smooth at all the boundaries. - const bool extrapolate_x = not mesh->sourceHasXBoundaryGuards(); - const bool extrapolate_y = not mesh->sourceHasYBoundaryGuards(); + const bool extrapolate_x = (*options)["extrapolate_x"].withDefault(not mesh->sourceHasXBoundaryGuards()); + const bool extrapolate_y = (*options)["extrapolate_y"].withDefault(not mesh->sourceHasYBoundaryGuards()); if (extrapolate_x) { output_warn.write(_("WARNING: extrapolating input mesh quantities into x-boundary " - "cells\n")); + "cells. Set option extrapolate_x=false to disable this.\n")); } if (extrapolate_y) { output_warn.write(_("WARNING: extrapolating input mesh quantities into y-boundary " - "cells\n")); + "cells. Set option extrapolate_y=false to disable this.\n")); } if (mesh->get(dx, "dx")) { From 8d091d3070bf78c81630df38ead91eea7c913b3a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Jul 2019 15:56:54 +0100 Subject: [PATCH 1675/1783] Remove extraneous semicolon --- include/interpolation_factory.hxx | 1 - 1 file changed, 1 deletion(-) diff --git a/include/interpolation_factory.hxx b/include/interpolation_factory.hxx index 05197c5de4..b4d916f54d 100644 --- a/include/interpolation_factory.hxx +++ b/include/interpolation_factory.hxx @@ -35,7 +35,6 @@ private: public: ~InterpolationFactory() = default; - ; /// Create or get the singleton instance of the factory static InterpolationFactory* getInstance(); From d6ddd286ccc9dd23ab3c348d1cd33541952fadd0 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Jul 2019 16:04:40 +0100 Subject: [PATCH 1676/1783] Clang-format changes from #1755 --- include/bout/physicsmodel.hxx | 14 +- include/bout/region.hxx | 4 +- include/bout/sys/gettext.hxx | 2 +- include/bout/sys/range.hxx | 6 +- include/bout/sys/uncopyable.hxx | 1 + include/boutcomm.hxx | 4 +- include/datafile.hxx | 11 +- include/fieldperp.hxx | 3 +- include/msg_stack.hxx | 2 +- include/utils.hxx | 6 +- include/vector2d.hxx | 8 +- include/vector3d.hxx | 6 +- src/field/field2d.cxx | 4 +- src/field/field3d.cxx | 8 +- src/fileio/impls/hdf5/h5_format.cxx | 4 +- .../impls/multigrid/multigrid_solver.cxx | 2 +- src/invert/laplacexy/laplacexy.cxx | 24 +-- src/mesh/boundary_region.cxx | 21 +- src/mesh/impls/bout/boutmesh.hxx | 182 ++++++++++-------- src/mesh/mesh.cxx | 4 +- src/solver/impls/slepc/slepc.hxx | 16 +- src/solver/solver.cxx | 38 ++-- src/sys/boutexception.cxx | 46 ++--- src/sys/options/options_netcdf.cxx | 6 +- tests/integrated/test-delp2/test_delp2.cxx | 1 - .../test-interpolate/test_interpolate.cxx | 2 +- tests/unit/test_extras.hxx | 97 +++------- 27 files changed, 243 insertions(+), 279 deletions(-) diff --git a/include/bout/physicsmodel.hxx b/include/bout/physicsmodel.hxx index 2e6d99db7c..064136a541 100644 --- a/include/bout/physicsmodel.hxx +++ b/include/bout/physicsmodel.hxx @@ -270,6 +270,7 @@ protected: // Call user output monitor return model->outputMonitor(simtime, iter, nout); } + private: PhysicsModel *model; }; @@ -277,11 +278,14 @@ protected: /// write restarts and pass outputMonitor method inside a Monitor subclass PhysicsModelMonitor modelMonitor; private: - bool splitop{false}; ///< Split operator model? - preconfunc userprecon{nullptr}; ///< Pointer to user-supplied preconditioner function - jacobianfunc userjacobian{nullptr}; ///< Pointer to user-supplied Jacobian-vector multiply function - - bool initialised{false}; ///< True if model already initialised + /// Split operator model? + bool splitop{false}; + /// Pointer to user-supplied preconditioner function + preconfunc userprecon{nullptr}; + /// Pointer to user-supplied Jacobian-vector multiply function + jacobianfunc userjacobian{nullptr}; + /// True if model already initialised + bool initialised{false}; }; /*! diff --git a/include/bout/region.hxx b/include/bout/region.hxx index ffa73d18b2..f63ac8e2d6 100644 --- a/include/bout/region.hxx +++ b/include/bout/region.hxx @@ -493,7 +493,7 @@ public: // Want to make this private to disable but think it may be needed as we put Regions // into maps which seems to need to be able to make "empty" objects. - Region()= default;; + Region() = default; Region(int xstart, int xend, int ystart, int yend, int zstart, int zend, int ny, int nz, int maxregionblocksize = MAXREGIONBLOCKSIZE) @@ -532,7 +532,7 @@ public: }; /// Destructor - ~Region()= default;; + ~Region() = default; /// Expose the iterator over indices for use in range-based /// for-loops or with STL algorithms, etc. diff --git a/include/bout/sys/gettext.hxx b/include/bout/sys/gettext.hxx index d4ead5ab44..c2576811db 100644 --- a/include/bout/sys/gettext.hxx +++ b/include/bout/sys/gettext.hxx @@ -5,8 +5,8 @@ #if BOUT_HAS_GETTEXT -#include #include +#include #define GETTEXT_PACKAGE "libbout" diff --git a/include/bout/sys/range.hxx b/include/bout/sys/range.hxx index b1745fb8c5..70d33ab741 100644 --- a/include/bout/sys/range.hxx +++ b/include/bout/sys/range.hxx @@ -27,7 +27,7 @@ class RangeIterator { public: /// Can be given a single range - RangeIterator() = default; + RangeIterator() = default; RangeIterator(int start, int end, RangeIterator *join = nullptr); RangeIterator(int start, int end, const RangeIterator &join); RangeIterator(const RangeIterator &r); @@ -68,8 +68,8 @@ public: private: int is{1}, ie{0}; - RangeIterator *n{nullptr}; // Next range. Doesn't change after creation - RangeIterator *cur{nullptr}; // Currently iterating. Changes during iteration + RangeIterator* n{nullptr}; // Next range. Doesn't change after creation + RangeIterator* cur{nullptr}; // Currently iterating. Changes during iteration int curend; // End of current range bool delete_next = false; // Flag to delete this->n if we created it }; diff --git a/include/bout/sys/uncopyable.hxx b/include/bout/sys/uncopyable.hxx index 3091fb9fad..a03cbca663 100644 --- a/include/bout/sys/uncopyable.hxx +++ b/include/bout/sys/uncopyable.hxx @@ -8,6 +8,7 @@ class Uncopyable { protected: Uncopyable() = default; ~Uncopyable() = default; + public: Uncopyable(const Uncopyable &) = delete; Uncopyable &operator=(const Uncopyable &) = delete; diff --git a/include/boutcomm.hxx b/include/boutcomm.hxx index b7a196e412..88ad07e2b6 100644 --- a/include/boutcomm.hxx +++ b/include/boutcomm.hxx @@ -60,8 +60,8 @@ public: BoutComm(); int* pargc{nullptr}; - char*** pargv{nullptr}; ///< Command-line arguments. These can be modified by MPI init, so - ///< pointers are used + char*** pargv{nullptr}; ///< Command-line arguments. These can be modified by MPI init, + ///< so pointers are used bool hasBeenSet{false}; MPI_Comm comm; diff --git a/include/datafile.hxx b/include/datafile.hxx index c5fc486bd9..8aff0caf2e 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -89,16 +89,17 @@ class Datafile { private: Mesh* mesh; bool parallel{false}; // Use parallel formats? - bool flush{true}; // Flush after every write? - bool guards{true}; // Write guard cells? + bool flush{true}; // Flush after every write? + bool guards{true}; // Write guard cells? bool floats{false}; // Low precision? - bool openclose{true}; // Open and close file for each write + bool openclose{true}; // Open and close file for each write int Lx,Ly,Lz; // The sizes in the x-, y- and z-directions of the arrays to be written bool enabled{true}; // Enable / Disable writing bool init_missing; // Initialise missing variables? bool shiftOutput{false}; // Do we want to write out in shifted space? - bool shiftInput{false}; // Read in shifted space? - int flushFrequencyCounter{0}; // Counter used in determining when next openclose required + bool shiftInput{false}; // Read in shifted space? + int flushFrequencyCounter{ + 0}; // Counter used in determining when next openclose required int flushFrequency{1}; // How many write calls do we want between openclose std::unique_ptr file; diff --git a/include/fieldperp.hxx b/include/fieldperp.hxx index d3098cbab8..8d0cc3ee27 100644 --- a/include/fieldperp.hxx +++ b/include/fieldperp.hxx @@ -61,8 +61,7 @@ class FieldPerp : public Field { * Copy constructor. After this the data * will be shared (non unique) */ - FieldPerp(const FieldPerp& f) - = default; + FieldPerp(const FieldPerp& f) = default; /*! * Move constructor diff --git a/include/msg_stack.hxx b/include/msg_stack.hxx index e580ab7351..5182687958 100644 --- a/include/msg_stack.hxx +++ b/include/msg_stack.hxx @@ -65,7 +65,7 @@ class MsgStack; */ class MsgStack { public: - MsgStack() = default;; + MsgStack() = default; ~MsgStack() { clear(); } #if CHECK > 1 diff --git a/include/utils.hxx b/include/utils.hxx index 03023a279b..735f422ca3 100644 --- a/include/utils.hxx +++ b/include/utils.hxx @@ -129,8 +129,8 @@ class Matrix { public: using data_type = T; using size_type = int; - - Matrix() = default;; + + Matrix() = default; Matrix(size_type n1, size_type n2) : n1(n1), n2(n2) { ASSERT2(n1 >= 0); ASSERT2(n2 >= 0); @@ -221,7 +221,7 @@ public: using data_type = T; using size_type = int; - Tensor() = default;; + Tensor() = default; Tensor(size_type n1, size_type n2, size_type n3) : n1(n1), n2(n2), n3(n3) { ASSERT2(n1 >= 0); ASSERT2(n2 >= 0); diff --git a/include/vector2d.hxx b/include/vector2d.hxx index 505e9a73cb..a92b5c984b 100644 --- a/include/vector2d.hxx +++ b/include/vector2d.hxx @@ -46,7 +46,7 @@ class Vector3D; //#include "vector3d.hxx" * (x and y). Implemented as a collection of three Field2D objects. */ class Vector2D : public FieldData { - public: +public: Vector2D(Mesh * fieldmesh = nullptr); Vector2D(const Vector2D &f); ~Vector2D() override; @@ -152,9 +152,9 @@ class Vector2D : public FieldData { } void applyBoundary(const char* condition) { applyBoundary(std::string(condition)); } void applyTDerivBoundary() override; - private: - Vector2D* deriv{nullptr}; ///< Time-derivative, can be NULL - CELL_LOC location{CELL_CENTRE}; ///< Location of the variable in the cell +private: + Vector2D* deriv{nullptr}; ///< Time-derivative, can be NULL + CELL_LOC location{CELL_CENTRE}; ///< Location of the variable in the cell }; // Non-member overloaded operators diff --git a/include/vector3d.hxx b/include/vector3d.hxx index f2ff7d7c2c..29e307c448 100644 --- a/include/vector3d.hxx +++ b/include/vector3d.hxx @@ -83,7 +83,7 @@ class Vector3D : public FieldData { /*! * Flag to specify whether the components (x,y,z) * are co- or contra-variant. - * + * * true if the components are covariant (default) * false if the components are contravariant * @@ -91,7 +91,7 @@ class Vector3D : public FieldData { * the toContravariant and toCovariant methods. * * Only modify this variable directly if you know what you are doing! - * + * */ bool covariant{true}; @@ -196,7 +196,7 @@ class Vector3D : public FieldData { void applyBoundary(const char* condition) { applyBoundary(std::string(condition)); } void applyTDerivBoundary() override; private: - Vector3D* deriv{nullptr}; ///< Time-derivative, can be NULL + Vector3D* deriv{nullptr}; ///< Time-derivative, can be NULL CELL_LOC location{CELL_CENTRE}; ///< Location of the variable in the cell }; diff --git a/src/field/field2d.cxx b/src/field/field2d.cxx index 2c1b885013..9e2ba75492 100644 --- a/src/field/field2d.cxx +++ b/src/field/field2d.cxx @@ -94,9 +94,7 @@ Field2D::Field2D(Array data_in, Mesh* localmesh, CELL_LOC datalocation setLocation(datalocation); } -Field2D::~Field2D() { - delete deriv; -} +Field2D::~Field2D() { delete deriv; } Field2D& Field2D::allocate() { if(data.empty()) { diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index e55aef7eef..13a136ee34 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -106,9 +106,7 @@ Field3D::Field3D(Array data_in, Mesh* localmesh, CELL_LOC datalocation setLocation(datalocation); } -Field3D::~Field3D() { - delete deriv; -} +Field3D::~Field3D() { delete deriv; } Field3D& Field3D::allocate() { if(data.empty()) { @@ -553,7 +551,7 @@ void Field3D::applyParallelBoundary(const std::string ®ion, const std::string /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundariesPar()) { - if(reg->label == region) { + if (reg->label == region) { auto op = std::unique_ptr{ dynamic_cast(bfact->create(condition, reg))}; op->apply(*this); @@ -580,7 +578,7 @@ void Field3D::applyParallelBoundary(const std::string ®ion, const std::string /// Loop over the mesh boundary regions for(const auto& reg : fieldmesh->getBoundariesPar()) { - if(reg->label == region) { + if (reg->label == region) { // BoundaryFactory can't create boundaries using Field3Ds, so get temporary // boundary of the right type auto tmp = std::unique_ptr{ diff --git a/src/fileio/impls/hdf5/h5_format.cxx b/src/fileio/impls/hdf5/h5_format.cxx index 837fb22dbf..92d5db3b8f 100644 --- a/src/fileio/impls/hdf5/h5_format.cxx +++ b/src/fileio/impls/hdf5/h5_format.cxx @@ -147,9 +147,7 @@ bool H5Format::openw(const char *name, bool append) { return true; } -bool H5Format::is_valid() { - return dataFile >= 0; -} +bool H5Format::is_valid() { return dataFile >= 0; } void H5Format::close() { TRACE("H5Format::close"); diff --git a/src/invert/laplace/impls/multigrid/multigrid_solver.cxx b/src/invert/laplace/impls/multigrid/multigrid_solver.cxx index d1a6440efe..aa6e64ca07 100644 --- a/src/invert/laplace/impls/multigrid/multigrid_solver.cxx +++ b/src/invert/laplace/impls/multigrid/multigrid_solver.cxx @@ -95,7 +95,7 @@ Multigrid1DP::Multigrid1DP(int level,int lx, int lz, int gx, int dl, int merge, if(nz*2 <= mm) { nz = 2*nz; nx = nx/2; - } else { + } else { n = kk; } } diff --git a/src/invert/laplacexy/laplacexy.cxx b/src/invert/laplacexy/laplacexy.cxx index ed990a72fd..40af4949fc 100644 --- a/src/invert/laplacexy/laplacexy.cxx +++ b/src/invert/laplacexy/laplacexy.cxx @@ -116,7 +116,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) if(localmesh->firstX()) { // Lower X boundary for(int y=localmesh->ystart;y<=localmesh->yend;y++) { - const int localIndex = globalIndex(localmesh->xstart-1, y); + const int localIndex = globalIndex(localmesh->xstart - 1, y); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] = 2; // Diagonal sub-matrix @@ -134,7 +134,7 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) if(localmesh->lastX()) { // Upper X boundary for(int y=localmesh->ystart;y<=localmesh->yend;y++) { - const int localIndex = globalIndex(localmesh->xend+1, y); + const int localIndex = globalIndex(localmesh->xend + 1, y); ASSERT1( (localIndex >= 0) && (localIndex < localN) ); d_nnz[localIndex] = 2; // Diagonal sub-matrix o_nnz[localIndex] = 0; // Off-diagonal sub-matrix @@ -157,42 +157,42 @@ LaplaceXY::LaplaceXY(Mesh *m, Options *opt, const CELL_LOC loc) // then this will result in PETSc warnings about out of range allocations { const int localIndex = globalIndex(x, localmesh->ystart); - ASSERT1( (localIndex >= 0) && (localIndex < localN) ); - //d_nnz[localIndex] -= 1; // Note: Slightly inefficient + ASSERT1((localIndex >= 0) && (localIndex < localN)); + // d_nnz[localIndex] -= 1; // Note: Slightly inefficient o_nnz[localIndex] += 1; } { const int localIndex = globalIndex(x, localmesh->yend); - ASSERT1( (localIndex >= 0) && (localIndex < localN) ); - //d_nnz[localIndex] -= 1; // Note: Slightly inefficient + ASSERT1((localIndex >= 0) && (localIndex < localN)); + // d_nnz[localIndex] -= 1; // Note: Slightly inefficient o_nnz[localIndex] += 1; } } for(RangeIterator it=localmesh->iterateBndryLowerY(); !it.isDone(); it++) { { - const int localIndex = globalIndex(it.ind, localmesh->ystart-1); - ASSERT1( (localIndex >= 0) && (localIndex < localN) ); + const int localIndex = globalIndex(it.ind, localmesh->ystart - 1); + ASSERT1((localIndex >= 0) && (localIndex < localN)); d_nnz[localIndex] = 2; // Diagonal sub-matrix o_nnz[localIndex] = 0; // Off-diagonal sub-matrix } { const int localIndex = globalIndex(it.ind, localmesh->ystart); - ASSERT1( (localIndex >= 0) && (localIndex < localN) ); + ASSERT1((localIndex >= 0) && (localIndex < localN)); d_nnz[localIndex] += 1; o_nnz[localIndex] -= 1; } } for(RangeIterator it=localmesh->iterateBndryUpperY(); !it.isDone(); it++) { { - const int localIndex = globalIndex(it.ind, localmesh->yend+1); - ASSERT1( (localIndex >= 0) && (localIndex < localN) ); + const int localIndex = globalIndex(it.ind, localmesh->yend + 1); + ASSERT1((localIndex >= 0) && (localIndex < localN)); d_nnz[localIndex] = 2; // Diagonal sub-matrix o_nnz[localIndex] = 0; // Off-diagonal sub-matrix } { const int localIndex = globalIndex(it.ind, localmesh->yend); - ASSERT1( (localIndex >= 0) && (localIndex < localN) ); + ASSERT1((localIndex >= 0) && (localIndex < localN)); d_nnz[localIndex] += 1; o_nnz[localIndex] -= 1; } diff --git a/src/mesh/boundary_region.cxx b/src/mesh/boundary_region.cxx index c504cf0d9b..1e884abc80 100644 --- a/src/mesh/boundary_region.cxx +++ b/src/mesh/boundary_region.cxx @@ -8,8 +8,7 @@ using std::swap; BoundaryRegionXIn::BoundaryRegionXIn(std::string name, int ymin, int ymax, Mesh* passmesh) - : BoundaryRegion(std::move(name), -1, 0, passmesh), ys(ymin), ye(ymax) -{ + : BoundaryRegion(std::move(name), -1, 0, passmesh), ys(ymin), ye(ymax) { location = BNDRY_XIN; width = localmesh->xstart; x = width-1; // First point inside the boundary @@ -60,10 +59,9 @@ bool BoundaryRegionXIn::isDone() /////////////////////////////////////////////////////////////// - -BoundaryRegionXOut::BoundaryRegionXOut(std::string name, int ymin, int ymax, Mesh* passmesh) - : BoundaryRegion(std::move(name), 1, 0, passmesh), ys(ymin), ye(ymax) -{ +BoundaryRegionXOut::BoundaryRegionXOut(std::string name, int ymin, int ymax, + Mesh* passmesh) + : BoundaryRegion(std::move(name), 1, 0, passmesh), ys(ymin), ye(ymax) { location = BNDRY_XOUT; width = localmesh->LocalNx - localmesh->xend - 1; x = localmesh->LocalNx - width; // First point inside the boundary @@ -114,10 +112,9 @@ bool BoundaryRegionXOut::isDone() /////////////////////////////////////////////////////////////// - -BoundaryRegionYDown::BoundaryRegionYDown(std::string name, int xmin, int xmax, Mesh* passmesh) - : BoundaryRegion(std::move(name), 0, -1, passmesh), xs(xmin), xe(xmax) -{ +BoundaryRegionYDown::BoundaryRegionYDown(std::string name, int xmin, int xmax, + Mesh* passmesh) + : BoundaryRegion(std::move(name), 0, -1, passmesh), xs(xmin), xe(xmax) { location = BNDRY_YDOWN; width = localmesh->ystart; y = width-1; // First point inside the boundary @@ -169,10 +166,8 @@ bool BoundaryRegionYDown::isDone() /////////////////////////////////////////////////////////////// - BoundaryRegionYUp::BoundaryRegionYUp(std::string name, int xmin, int xmax, Mesh* passmesh) - : BoundaryRegion(std::move(name), 0, 1, passmesh), xs(xmin), xe(xmax) -{ + : BoundaryRegion(std::move(name), 0, 1, passmesh), xs(xmin), xe(xmax) { location = BNDRY_YUP; width = localmesh->LocalNy - localmesh->yend - 1; y = localmesh->LocalNy - width; // First point inside the boundary diff --git a/src/mesh/impls/bout/boutmesh.hxx b/src/mesh/impls/bout/boutmesh.hxx index 2c81d67450..64dda57284 100644 --- a/src/mesh/impls/bout/boutmesh.hxx +++ b/src/mesh/impls/bout/boutmesh.hxx @@ -18,10 +18,10 @@ class BoutMesh : public Mesh { public: BoutMesh(GridDataSource *s, Options *options = nullptr); - ~BoutMesh() override ; + ~BoutMesh() override; /// Read in the mesh from data sources - int load() override ; + int load() override; ///////////////////////////////////////////// // Communicate variables @@ -40,70 +40,76 @@ class BoutMesh : public Mesh { /// ... /// mesh->wait(handle); /// - comm_handle send(FieldGroup &g) override ; + comm_handle send(FieldGroup& g) override; /// Wait for a send operation to complete /// @param[in] handle The handle returned by send() - int wait(comm_handle handle) override ; + int wait(comm_handle handle) override; ///////////////////////////////////////////// // non-local communications - MPI_Request sendToProc(int xproc, int yproc, BoutReal *buffer, int size, int tag) override ; - comm_handle receiveFromProc(int xproc, int yproc, BoutReal *buffer, int size, int tag) override ; + MPI_Request sendToProc(int xproc, int yproc, BoutReal* buffer, int size, + int tag) override; + comm_handle receiveFromProc(int xproc, int yproc, BoutReal* buffer, int size, + int tag) override; - int getNXPE() override ; ///< The number of processors in the X direction - int getNYPE() override ; ///< The number of processors in the Y direction - int getXProcIndex() override ; ///< This processor's index in X direction - int getYProcIndex() override ; ///< This processor's index in Y direction + int getNXPE() override; ///< The number of processors in the X direction + int getNYPE() override; ///< The number of processors in the Y direction + int getXProcIndex() override; ///< This processor's index in X direction + int getYProcIndex() override; ///< This processor's index in Y direction ///////////////////////////////////////////// // X communications - bool firstX() override ; ///< Is this processor the first in X? i.e. is there a boundary to the left in X? - bool lastX() override ; ///< Is this processor last in X? i.e. is there a boundary to the right in X? + bool firstX() override; ///< Is this processor the first in X? i.e. is there a boundary + ///< to the left in X? + bool lastX() override; ///< Is this processor last in X? i.e. is there a boundary to the + ///< right in X? /// Send a buffer of data to processor at X index +1 /// /// @param[in] buffer The data to send. Must be at least length \p size /// @param[in] size The number of BoutReals to send /// @param[in] tag A label for the communication. Must be the same at receive - int sendXOut(BoutReal *buffer, int size, int tag) override ; + int sendXOut(BoutReal* buffer, int size, int tag) override; /// Send a buffer of data to processor at X index -1 /// /// @param[in] buffer The data to send. Must be at least length \p size /// @param[in] size The number of BoutReals to send /// @param[in] tag A label for the communication. Must be the same at receive - int sendXIn(BoutReal *buffer, int size, int tag) override ; + int sendXIn(BoutReal* buffer, int size, int tag) override; /// Receive a buffer of data from X index +1 /// /// @param[in] buffer A buffer to put the data in. Must already be allocated of length \p size /// @param[in] size The number of BoutReals to receive and put in \p buffer /// @param[in] tag A label for the communication. Must be the same as sent - comm_handle irecvXOut(BoutReal *buffer, int size, int tag) override ; + comm_handle irecvXOut(BoutReal* buffer, int size, int tag) override; /// Receive a buffer of data from X index -1 /// /// @param[in] buffer A buffer to put the data in. Must already be allocated of length \p size /// @param[in] size The number of BoutReals to receive and put in \p buffer /// @param[in] tag A label for the communication. Must be the same as sent - comm_handle irecvXIn(BoutReal *buffer, int size, int tag) override ; + comm_handle irecvXIn(BoutReal* buffer, int size, int tag) override; - MPI_Comm getXcomm(int UNUSED(jy)) const override {return comm_x; } ///< Return communicator containing all processors in X - MPI_Comm getYcomm(int jx) const override ; ///< Return communicator containing all processors in Y + /// Return communicator containing all processors in X + MPI_Comm getXcomm(int UNUSED(jy)) const override { return comm_x; } + /// Return communicator containing all processors in Y + MPI_Comm getYcomm(int jx) const override; /// Is local X index \p jx periodic in Y? /// /// \param[in] jx The local (on this processor) index in X /// \param[out] ts The Twist-Shift angle if periodic - bool periodicY(int jx, BoutReal &ts) const override ; + bool periodicY(int jx, BoutReal& ts) const override; /// Is local X index \p jx periodic in Y? /// /// \param[in] jx The local (on this processor) index in X - bool periodicY(int jx) const override ; + bool periodicY(int jx) const override; /// Is there a branch cut at this processor's lower boundary? /// @@ -121,64 +127,63 @@ class BoutMesh : public Mesh { /// poloidal circuit if there is a branch cut std::pair hasBranchCutUpper(int jx) const override; - int ySize(int jx) const override ; ///< The number of points in Y at fixed X index \p jx + int ySize(int jx) const override; ///< The number of points in Y at fixed X index \p jx ///////////////////////////////////////////// // Y communications - bool firstY() const override ; - bool lastY() const override ; - bool firstY(int xpos) const override ; - bool lastY(int xpos) const override ; - int UpXSplitIndex() override ; - int DownXSplitIndex() override ; - int sendYOutIndest(BoutReal *buffer, int size, int tag) override ; - int sendYOutOutdest(BoutReal *buffer, int size, int tag) override ; - int sendYInIndest(BoutReal *buffer, int size, int tag) override ; - int sendYInOutdest(BoutReal *buffer, int size, int tag) override ; - comm_handle irecvYOutIndest(BoutReal *buffer, int size, int tag) override ; - comm_handle irecvYOutOutdest(BoutReal *buffer, int size, int tag) override ; - comm_handle irecvYInIndest(BoutReal *buffer, int size, int tag) override ; - comm_handle irecvYInOutdest(BoutReal *buffer, int size, int tag) override ; + bool firstY() const override; + bool lastY() const override; + bool firstY(int xpos) const override; + bool lastY(int xpos) const override; + int UpXSplitIndex() override; + int DownXSplitIndex() override; + int sendYOutIndest(BoutReal* buffer, int size, int tag) override; + int sendYOutOutdest(BoutReal* buffer, int size, int tag) override; + int sendYInIndest(BoutReal* buffer, int size, int tag) override; + int sendYInOutdest(BoutReal* buffer, int size, int tag) override; + comm_handle irecvYOutIndest(BoutReal* buffer, int size, int tag) override; + comm_handle irecvYOutOutdest(BoutReal* buffer, int size, int tag) override; + comm_handle irecvYInIndest(BoutReal* buffer, int size, int tag) override; + comm_handle irecvYInOutdest(BoutReal* buffer, int size, int tag) override; // Boundary iteration - const RangeIterator iterateBndryLowerY() const override ; - const RangeIterator iterateBndryUpperY() const override ; - const RangeIterator iterateBndryLowerInnerY() const override ; - const RangeIterator iterateBndryLowerOuterY() const override ; - const RangeIterator iterateBndryUpperInnerY() const override ; - const RangeIterator iterateBndryUpperOuterY() const override ; - + const RangeIterator iterateBndryLowerY() const override; + const RangeIterator iterateBndryUpperY() const override; + const RangeIterator iterateBndryLowerInnerY() const override; + const RangeIterator iterateBndryLowerOuterY() const override; + const RangeIterator iterateBndryUpperInnerY() const override; + const RangeIterator iterateBndryUpperOuterY() const override; // Boundary regions - std::vector getBoundaries() override ; - std::vector getBoundariesPar() override ; - void addBoundaryPar(BoundaryRegionPar* bndry) override ; + std::vector getBoundaries() override; + std::vector getBoundariesPar() override; + void addBoundaryPar(BoundaryRegionPar* bndry) override; - const Field3D smoothSeparatrix(const Field3D &f) override ; + const Field3D smoothSeparatrix(const Field3D& f) override; - int getNx() const {return nx;} - int getNy() const {return ny;} + int getNx() const { return nx; } + int getNy() const { return ny; } - BoutReal GlobalX(int jx) const override ; - BoutReal GlobalY(int jy) const override ; - BoutReal GlobalX(BoutReal jx) const override ; - BoutReal GlobalY(BoutReal jy) const override ; + BoutReal GlobalX(int jx) const override; + BoutReal GlobalY(int jy) const override; + BoutReal GlobalX(BoutReal jx) const override; + BoutReal GlobalY(BoutReal jy) const override; - BoutReal getIxseps1() const {return ixseps1;} - BoutReal getIxseps2() const {return ixseps2;} + BoutReal getIxseps1() const { return ixseps1; } + BoutReal getIxseps2() const { return ixseps2; } - void outputVars(Datafile &file) override ; + void outputVars(Datafile& file) override; - int XGLOBAL(int xloc) const override ; - int YGLOBAL(int yloc) const override ; - int XGLOBAL(BoutReal xloc, BoutReal &xglo) const; - int YGLOBAL(BoutReal yloc, BoutReal &yglo) const; + int XGLOBAL(int xloc) const override; + int YGLOBAL(int yloc) const override; + int XGLOBAL(BoutReal xloc, BoutReal& xglo) const; + int YGLOBAL(BoutReal yloc, BoutReal& yglo) const; - int XLOCAL(int xglo) const override ; - int YLOCAL(int yglo) const override ; + int XLOCAL(int xglo) const override; + int YLOCAL(int yglo) const override; - private: +private: std::string gridname; int nx, ny, nz; ///< Size of the grid in the input file int MX, MY, MZ; ///< size of the grid excluding boundary regions @@ -189,18 +194,18 @@ class BoutMesh : public Mesh { int MYPE; ///< Rank of this processor int PE_YIND; ///< Y index of this processor - int NYPE; // Number of processors in the Y direction + int NYPE; // Number of processors in the Y direction int NZPE; - int MYPE_IN_CORE; // 1 if processor in core + int MYPE_IN_CORE; // 1 if processor in core // Topology int ixseps1, ixseps2, jyseps1_1, jyseps2_1, jyseps1_2, jyseps2_2; int ixseps_inner, ixseps_outer, ixseps_upper, ixseps_lower; int ny_inner; - std::vector ShiftAngle; ///< Angle for twist-shift location + std::vector ShiftAngle; ///< Angle for twist-shift location // Processor number, local <-> global translation int PROC_NUM(int xind, int yind); // (PE_XIND, PE_YIND) -> MYPE @@ -218,13 +223,13 @@ class BoutMesh : public Mesh { int IDATA_DEST, ODATA_DEST; // X inner and outer destinations // Settings - bool TwistShift; // Use a twist-shift condition in core? + bool TwistShift; // Use a twist-shift condition in core? bool symmetricGlobalX; ///< Use a symmetric definition in GlobalX() function bool symmetricGlobalY; - int zperiod; - BoutReal ZMIN, ZMAX; // Range of the Z domain (in fractions of 2pi) + int zperiod; + BoutReal ZMIN, ZMAX; // Range of the Z domain (in fractions of 2pi) int MXG, MYG, MZG; // Boundary sizes @@ -232,33 +237,38 @@ class BoutMesh : public Mesh { void set_connection(int ypos1, int ypos2, int xge, int xlt, bool ts = false); void add_target(int ypos, int xge, int xlt); void topology(); - + void addBoundaryRegions(); ///< Adds 2D and 3D regions for boundaries - - std::vector boundary; // Vector of boundary regions + + std::vector boundary; // Vector of boundary regions std::vector par_boundary; // Vector of parallel boundary regions ////////////////////////////////////////////////// // Communications - bool async_send; ///< Switch to asyncronous sends (ISend, not Send) + bool async_send; ///< Switch to asyncronous sends (ISend, not Send) /// Communication handle /// Used to keep track of communications between send and receive struct CommHandle { - /// Array of receive requests. One for each possible neighbour; one each way in X, two each way in Y + /// Array of receive requests. One for each possible neighbour; one each way in X, two + /// each way in Y MPI_Request request[6]; - /// Array of send requests (for non-blocking send). One for each possible neighbour; one each way in X, two each way in Y + /// Array of send requests (for non-blocking send). One for each possible neighbour; + /// one each way in X, two each way in Y MPI_Request sendreq[6]; - int xbufflen, ybufflen; ///< Length of the buffers used to send/receive (in BoutReals) - Array umsg_sendbuff, dmsg_sendbuff, imsg_sendbuff, omsg_sendbuff; ///< Sending buffers - Array umsg_recvbuff, dmsg_recvbuff, imsg_recvbuff, omsg_recvbuff; ///< Receiving buffers - bool in_progress; ///< Is the communication still going? - + /// Length of the buffers used to send/receive (in BoutReals) + int xbufflen, ybufflen; + /// Sending buffers + Array umsg_sendbuff, dmsg_sendbuff, imsg_sendbuff, omsg_sendbuff; + /// Receiving buffers + Array umsg_recvbuff, dmsg_recvbuff, imsg_recvbuff, omsg_recvbuff; + /// Is the communication still going? + bool in_progress; /// List of fields being communicated FieldGroup var_list; }; - void free_handle(CommHandle *h); + void free_handle(CommHandle* h); CommHandle* get_handle(int xlen, int ylen); void clear_handles(); std::list comm_list; // List of allocated communication handles @@ -271,18 +281,22 @@ class BoutMesh : public Mesh { ////////////////////////////////////////////////// // Surface communications - MPI_Comm comm_inner, comm_middle, comm_outer; ///< Communicators in Y. Inside both separatrices; between separatrices; and outside both separatrices + /// Communicators in Y. Inside both separatrices; between separatrices; + /// and outside both separatrices + MPI_Comm comm_inner, comm_middle, comm_outer; ////////////////////////////////////////////////// // Communication routines /// Create the MPI requests to receive data. Non-blocking call. - void post_receive(CommHandle &ch); + void post_receive(CommHandle& ch); /// Take data from objects and put into a buffer - int pack_data(const std::vector &var_list, int xge, int xlt, int yge, int ylt, BoutReal *buffer); + int pack_data(const std::vector& var_list, int xge, int xlt, int yge, + int ylt, BoutReal* buffer); /// Copy data from a buffer back into the fields - int unpack_data(const std::vector &var_list, int xge, int xlt, int yge, int ylt, BoutReal *buffer); + int unpack_data(const std::vector& var_list, int xge, int xlt, int yge, + int ylt, BoutReal* buffer); }; #endif // __BOUTMESH_H__ diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index dbbd7310f3..5f15a22a01 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -34,9 +34,7 @@ Mesh::Mesh(GridDataSource *s, Options* opt) : source(s), options(opt) { derivs_init(options); // in index_derivs.cxx for now } -Mesh::~Mesh() { - delete source; -} +Mesh::~Mesh() { delete source; } /************************************************************************** * Functions for reading data from external sources diff --git a/src/solver/impls/slepc/slepc.hxx b/src/solver/impls/slepc/slepc.hxx index 0150260d5c..db8d65326a 100644 --- a/src/solver/impls/slepc/slepc.hxx +++ b/src/solver/impls/slepc/slepc.hxx @@ -96,25 +96,25 @@ public: //////Following overrides all just pass through to advanceSolver // Override virtual add functions in order to pass through to advanceSolver - void add(Field2D &v, const std::string& name) override { + void add(Field2D& v, const std::string& name) override { Solver::add(v, name); if (!selfSolve) { advanceSolver->add(v, name); } } - void add(Field3D &v, const std::string& name) override { + void add(Field3D& v, const std::string& name) override { Solver::add(v, name); if (!selfSolve) { advanceSolver->add(v, name); } } - void add(Vector2D &v, const std::string& name) override { + void add(Vector2D& v, const std::string& name) override { Solver::add(v, name); if (!selfSolve) { advanceSolver->add(v, name); } } - void add(Vector3D &v, const std::string& name) override { + void add(Vector3D& v, const std::string& name) override { Solver::add(v, name); if (!selfSolve) { advanceSolver->add(v, name); @@ -143,22 +143,22 @@ public: return advanceSolver->constraints(); } } - void constraint(Field2D &v, Field2D &C_v, std::string name) override { + void constraint(Field2D& v, Field2D& C_v, std::string name) override { if (!selfSolve) { advanceSolver->constraint(v, C_v, std::move(name)); } } - void constraint(Field3D &v, Field3D &C_v, std::string name) override { + void constraint(Field3D& v, Field3D& C_v, std::string name) override { if (!selfSolve) { advanceSolver->constraint(v, C_v, std::move(name)); } } - void constraint(Vector2D &v, Vector2D &C_v, std::string name) override { + void constraint(Vector2D& v, Vector2D& C_v, std::string name) override { if (!selfSolve) { advanceSolver->constraint(v, C_v, std::move(name)); } } - void constraint(Vector3D &v, Vector3D &C_v, std::string name) override { + void constraint(Vector3D& v, Vector3D& C_v, std::string name) override { if (!selfSolve) { advanceSolver->constraint(v, C_v, std::move(name)); } diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index 8373b4dbe1..b0541e701a 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -82,7 +82,7 @@ void Solver::setModel(PhysicsModel *m) { * Add fields **************************************************************************/ -void Solver::add(Field2D &v, const std::string& name) { +void Solver::add(Field2D& v, const std::string& name) { TRACE("Adding 2D field: Solver::add(%s)", name.c_str()); #if CHECK > 0 @@ -139,7 +139,7 @@ void Solver::add(Field2D &v, const std::string& name) { f2d.emplace_back(std::move(d)); } -void Solver::add(Field3D &v, const std::string& name) { +void Solver::add(Field3D& v, const std::string& name) { TRACE("Adding 3D field: Solver::add(%s)", name.c_str()); Mesh* mesh = v.getMesh(); @@ -276,7 +276,7 @@ void Solver::add(Vector3D& v, const std::string& name) { * Constraints **************************************************************************/ -void Solver::constraint(Field2D &v, Field2D &C_v, std::string name) { +void Solver::constraint(Field2D& v, Field2D& C_v, std::string name) { TRACE("Constrain 2D scalar: Solver::constraint(%s)", name.c_str()); if (name.empty()) { @@ -304,7 +304,7 @@ void Solver::constraint(Field2D &v, Field2D &C_v, std::string name) { f2d.emplace_back(std::move(d)); } -void Solver::constraint(Field3D &v, Field3D &C_v, std::string name) { +void Solver::constraint(Field3D& v, Field3D& C_v, std::string name) { TRACE("Constrain 3D scalar: Solver::constraint(%s)", name.c_str()); if (name.empty()) { @@ -329,11 +329,11 @@ void Solver::constraint(Field3D &v, Field3D &C_v, std::string name) { d.F_var = &C_v; d.location = v.getLocation(); d.name = std::move(name); - + f3d.emplace_back(std::move(d)); } -void Solver::constraint(Vector2D &v, Vector2D &C_v, std::string name) { +void Solver::constraint(Vector2D& v, Vector2D& C_v, std::string name) { TRACE("Constrain 2D vector: Solver::constraint(%s)", name.c_str()); if (name.empty()) { @@ -353,13 +353,13 @@ void Solver::constraint(Vector2D &v, Vector2D &C_v, std::string name) { // Add suffix, depending on co- /contravariance if (v.covariant) { - constraint(v.x, C_v.x, name+"_x"); - constraint(v.y, C_v.y, name+"_y"); - constraint(v.z, C_v.z, name+"_z"); + constraint(v.x, C_v.x, name + "_x"); + constraint(v.y, C_v.y, name + "_y"); + constraint(v.z, C_v.z, name + "_z"); } else { - constraint(v.x, C_v.x, name+"x"); - constraint(v.y, C_v.y, name+"y"); - constraint(v.z, C_v.z, name+"z"); + constraint(v.x, C_v.x, name + "x"); + constraint(v.y, C_v.y, name + "y"); + constraint(v.z, C_v.z, name + "z"); } VarStr d; @@ -373,7 +373,7 @@ void Solver::constraint(Vector2D &v, Vector2D &C_v, std::string name) { v2d.emplace_back(std::move(d)); } -void Solver::constraint(Vector3D &v, Vector3D &C_v, std::string name) { +void Solver::constraint(Vector3D& v, Vector3D& C_v, std::string name) { TRACE("Constrain 3D vector: Solver::constraint(%s)", name.c_str()); if (name.empty()) { @@ -393,13 +393,13 @@ void Solver::constraint(Vector3D &v, Vector3D &C_v, std::string name) { // Add suffix, depending on co- /contravariance if (v.covariant) { - constraint(v.x, C_v.x, name+"_x"); - constraint(v.y, C_v.y, name+"_y"); - constraint(v.z, C_v.z, name+"_z"); + constraint(v.x, C_v.x, name + "_x"); + constraint(v.y, C_v.y, name + "_y"); + constraint(v.z, C_v.z, name + "_z"); } else { - constraint(v.x, C_v.x, name+"x"); - constraint(v.y, C_v.y, name+"y"); - constraint(v.z, C_v.z, name+"z"); + constraint(v.x, C_v.x, name + "x"); + constraint(v.y, C_v.y, name + "y"); + constraint(v.z, C_v.z, name + "z"); } VarStr d; diff --git a/src/sys/boutexception.cxx b/src/sys/boutexception.cxx index 1e7d7dcd80..c0b3cdb4f7 100644 --- a/src/sys/boutexception.cxx +++ b/src/sys/boutexception.cxx @@ -97,29 +97,29 @@ void BoutException::makeBacktrace() { /// Common set up for exceptions /// /// Formats the message s using C-style printf formatting -#define INIT_EXCEPTION(s) \ - { \ - buflen = 0; \ - buffer = nullptr; \ - if ((s) == nullptr) { \ - message = "No error message given!\n"; \ - } else { \ - buflen = BoutException::BUFFER_LEN; \ - buffer = new char[buflen]; \ - bout_vsnprintf(buffer, buflen, s); \ - for (int i = 0; i < buflen; ++i) { \ - if (buffer[i] == 0) { \ - if (i > 0 && buffer[i - 1] == '\n') { \ - buffer[i - 1] = 0; \ - } \ - break; \ - } \ - } \ - message.assign(buffer); \ - delete[] buffer; \ - buffer = nullptr; \ - } \ - makeBacktrace(); \ +#define INIT_EXCEPTION(s) \ + { \ + buflen = 0; \ + buffer = nullptr; \ + if ((s) == nullptr) { \ + message = "No error message given!\n"; \ + } else { \ + buflen = BoutException::BUFFER_LEN; \ + buffer = new char[buflen]; \ + bout_vsnprintf(buffer, buflen, s); \ + for (int i = 0; i < buflen; ++i) { \ + if (buffer[i] == 0) { \ + if (i > 0 && buffer[i - 1] == '\n') { \ + buffer[i - 1] = 0; \ + } \ + break; \ + } \ + } \ + message.assign(buffer); \ + delete[] buffer; \ + buffer = nullptr; \ + } \ + makeBacktrace(); \ } BoutException::BoutException(const char *s, ...) { INIT_EXCEPTION(s); } diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index 3723b523d7..cff0d76780 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -164,7 +164,8 @@ NcType NcTypeVisitor::operator()(const double& UNUSED(t)) { } template <> -MAYBE_UNUSED() NcType NcTypeVisitor::operator()(const float& UNUSED(t)) { +MAYBE_UNUSED() +NcType NcTypeVisitor::operator()(const float& UNUSED(t)) { return ncFloat; } @@ -347,7 +348,8 @@ void NcPutAttVisitor::operator()(const double& value) { var.putAtt(name, ncDouble, value); } template <> -MAYBE_UNUSED() void NcPutAttVisitor::operator()(const float& value) { +MAYBE_UNUSED() +void NcPutAttVisitor::operator()(const float& value) { var.putAtt(name, ncFloat, value); } template <> diff --git a/tests/integrated/test-delp2/test_delp2.cxx b/tests/integrated/test-delp2/test_delp2.cxx index 0e4913f056..3e3d45c671 100644 --- a/tests/integrated/test-delp2/test_delp2.cxx +++ b/tests/integrated/test-delp2/test_delp2.cxx @@ -3,7 +3,6 @@ class TestDelp2 : public PhysicsModel { protected: - int init(bool UNUSED(restarting)) override { Options *opt = Options::getRoot()->getSection("diffusion"); OPTION(opt, D, 0.1); diff --git a/tests/integrated/test-interpolate/test_interpolate.cxx b/tests/integrated/test-interpolate/test_interpolate.cxx index 32b4503205..75e5a350ce 100644 --- a/tests/integrated/test-interpolate/test_interpolate.cxx +++ b/tests/integrated/test-interpolate/test_interpolate.cxx @@ -17,7 +17,7 @@ /// Get a FieldGenerator from the options for a variable std::shared_ptr getGeneratorFromOptions(const std::string& varname, - std::string &func) { + std::string& func) { Options *options = Options::getRoot()->getSection(varname); options->get("solution", func, "0.0"); diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index dde41c7bd6..6aec55add1 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -191,13 +191,10 @@ public: addBoundary(new BoundaryRegionYDown("lower_target", xstart, xend, this)); } - comm_handle send(FieldGroup& UNUSED(g)) override { - return nullptr; - }; + comm_handle send(FieldGroup& UNUSED(g)) override { return nullptr; }; int wait(comm_handle UNUSED(handle)) override { return 0; } MPI_Request sendToProc(int UNUSED(xproc), int UNUSED(yproc), BoutReal* UNUSED(buffer), - int UNUSED(size), - int UNUSED(tag)) override { + int UNUSED(size), int UNUSED(tag)) override { return MPI_Request(); } comm_handle receiveFromProc(int UNUSED(xproc), int UNUSED(yproc), @@ -211,12 +208,10 @@ public: int getYProcIndex() override { return 1; } bool firstX() override { return true; } bool lastX() override { return true; } - int sendXOut(BoutReal* UNUSED(buffer), int UNUSED(size), - int UNUSED(tag)) override { + int sendXOut(BoutReal* UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) override { return 0; } - int sendXIn(BoutReal* UNUSED(buffer), int UNUSED(size), - int UNUSED(tag)) override { + int sendXIn(BoutReal* UNUSED(buffer), int UNUSED(size), int UNUSED(tag)) override { return 0; } comm_handle irecvXOut(BoutReal* UNUSED(buffer), int UNUSED(size), @@ -227,25 +222,14 @@ public: int UNUSED(tag)) override { return nullptr; } - MPI_Comm getXcomm(int UNUSED(jy)) const override { - return MPI_COMM_NULL; - } - MPI_Comm getYcomm(int UNUSED(jx)) const override { - return MPI_COMM_NULL; - } - bool periodicY(int UNUSED(jx)) const override { - return true; - } - bool periodicY(int UNUSED(jx), - BoutReal& UNUSED(ts)) const override { - return true; - } - std::pair - hasBranchCutLower(int UNUSED(jx)) const override { + MPI_Comm getXcomm(int UNUSED(jy)) const override { return MPI_COMM_NULL; } + MPI_Comm getYcomm(int UNUSED(jx)) const override { return MPI_COMM_NULL; } + bool periodicY(int UNUSED(jx)) const override { return true; } + bool periodicY(int UNUSED(jx), BoutReal& UNUSED(ts)) const override { return true; } + std::pair hasBranchCutLower(int UNUSED(jx)) const override { return std::make_pair(false, 0.); } - std::pair - hasBranchCutUpper(int UNUSED(jx)) const override { + std::pair hasBranchCutUpper(int UNUSED(jx)) const override { return std::make_pair(false, 0.); } bool firstY() const override { return true; } @@ -286,34 +270,14 @@ public: int UNUSED(tag)) override { return nullptr; } - const RangeIterator iterateBndryLowerY() const override { - return RangeIterator(); - } - const RangeIterator iterateBndryUpperY() const override { - return RangeIterator(); - } - const RangeIterator - iterateBndryLowerOuterY() const override { - return RangeIterator(); - } - const RangeIterator - iterateBndryLowerInnerY() const override { - return RangeIterator(); - } - const RangeIterator - iterateBndryUpperOuterY() const override { - return RangeIterator(); - } - const RangeIterator - iterateBndryUpperInnerY() const override { - return RangeIterator(); - } - void addBoundary(BoundaryRegion* region) override { - boundaries.push_back(region); - } - std::vector getBoundaries() override { - return boundaries; - } + const RangeIterator iterateBndryLowerY() const override { return RangeIterator(); } + const RangeIterator iterateBndryUpperY() const override { return RangeIterator(); } + const RangeIterator iterateBndryLowerOuterY() const override { return RangeIterator(); } + const RangeIterator iterateBndryLowerInnerY() const override { return RangeIterator(); } + const RangeIterator iterateBndryUpperOuterY() const override { return RangeIterator(); } + const RangeIterator iterateBndryUpperInnerY() const override { return RangeIterator(); } + void addBoundary(BoundaryRegion* region) override { boundaries.push_back(region); } + std::vector getBoundaries() override { return boundaries; } std::vector getBoundariesPar() override { return std::vector(); } @@ -378,16 +342,13 @@ private: /// allow testing of methods that use 'source' - in particular allowing /// source->hasXBoundaryGuards and source->hasXBoundaryGuards to be called. class FakeGridDataSource : public GridDataSource { - bool hasVar(const std::string& UNUSED(name)) override { - return false; - } + bool hasVar(const std::string& UNUSED(name)) override { return false; } bool get(Mesh* UNUSED(m), std::string& UNUSED(sval), const std::string& UNUSED(name)) override { return false; } - bool get(Mesh* UNUSED(m), int& UNUSED(ival), - const std::string& UNUSED(name)) override { + bool get(Mesh* UNUSED(m), int& UNUSED(ival), const std::string& UNUSED(name)) override { return false; } bool get(Mesh* UNUSED(m), BoutReal& UNUSED(rval), @@ -407,22 +368,18 @@ class FakeGridDataSource : public GridDataSource { return false; } - bool - get(Mesh* UNUSED(m), std::vector& UNUSED(var), const std::string& UNUSED(name), - int UNUSED(len), int UNUSED(offset) = 0, - Direction UNUSED(dir) = GridDataSource::X) override { + bool get(Mesh* UNUSED(m), std::vector& UNUSED(var), + const std::string& UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, + Direction UNUSED(dir) = GridDataSource::X) override { return false; } - bool - get(Mesh* UNUSED(m), std::vector& UNUSED(var), - const std::string& UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, - Direction UNUSED(dir) = GridDataSource::X) override { + bool get(Mesh* UNUSED(m), std::vector& UNUSED(var), + const std::string& UNUSED(name), int UNUSED(len), int UNUSED(offset) = 0, + Direction UNUSED(dir) = GridDataSource::X) override { return false; } - bool hasXBoundaryGuards(Mesh* UNUSED(m)) override { - return true; - } + bool hasXBoundaryGuards(Mesh* UNUSED(m)) override { return true; } bool hasYBoundaryGuards() override { return true; } }; From cf9316c47b95d43ab9290944cb2ab946abca3954 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Jul 2019 16:48:45 +0100 Subject: [PATCH 1677/1783] Fix typo in bracket method descriptions --- tests/MMS/spatial/advection/runtest | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/MMS/spatial/advection/runtest b/tests/MMS/spatial/advection/runtest index cc2269e26e..a0423fbce5 100755 --- a/tests/MMS/spatial/advection/runtest +++ b/tests/MMS/spatial/advection/runtest @@ -38,12 +38,12 @@ options = [ ("method=4", "Arakawa-old", "-.", 2), ("method=1 mesh:ddx:upwind=u1 mesh:ddz:upwind=u1", "SIMPLE: 1st order upwind", "-o", 1), ("method=1 mesh:ddx:upwind=u2 mesh:ddz:upwind=u2", "SIMPLE: 2nd order upwind", "-^", 2), - ("method=1 mesh:ddx:upwind=u3 mesh:ddz:upwind=u3", "SIMPLE: 3nd order upwind", "-v", 3), + ("method=1 mesh:ddx:upwind=u3 mesh:ddz:upwind=u3", "SIMPLE: 3rd order upwind", "-v", 3), ("method=1 mesh:ddx:upwind=c2 mesh:ddz:upwind=c2", "SIMPLE: 2nd order central", "-x", 2), ("method=1 mesh:ddx:upwind=c4 mesh:ddz:upwind=c4", "SIMPLE: 4th order central", "-+", 4), ("method=0 mesh:ddx:upwind=u1 mesh:ddz:upwind=u1", "STD: 1st order upwind", "-o", 1), ("method=0 mesh:ddx:upwind=u2 mesh:ddz:upwind=u2", "STD: 2nd order upwind", "-^", 2), - ("method=0 mesh:ddx:upwind=u3 mesh:ddz:upwind=u3", "STD: 3nd order upwind", "-v", 3), + ("method=0 mesh:ddx:upwind=u3 mesh:ddz:upwind=u3", "STD: 3rd order upwind", "-v", 3), ("method=0 mesh:ddx:upwind=c2 mesh:ddz:upwind=c2", "STD: 2nd order central", "-x", 2), ("method=0 mesh:ddx:upwind=c4 mesh:ddz:upwind=c4", "STD: 4th order central", "-+", 4), # NOTE: WENO3 seems to have two different regimes, one < 3, one > From 05eea539618e2876a834c9cf7a19554846b0f6b5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Jul 2019 16:50:06 +0100 Subject: [PATCH 1678/1783] Fix poor clang-formatting --- include/datafile.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/datafile.hxx b/include/datafile.hxx index 8aff0caf2e..528b6708de 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -98,8 +98,8 @@ class Datafile { bool init_missing; // Initialise missing variables? bool shiftOutput{false}; // Do we want to write out in shifted space? bool shiftInput{false}; // Read in shifted space? - int flushFrequencyCounter{ - 0}; // Counter used in determining when next openclose required + // Counter used in determining when next openclose required + int flushFrequencyCounter{0}; int flushFrequency{1}; // How many write calls do we want between openclose std::unique_ptr file; From 0740874a05c3f3e28d15986b0987dfdde54cd24c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Jul 2019 17:16:34 +0100 Subject: [PATCH 1679/1783] Drop small resolution from MMS/spatial/advection; restore tolerance --- tests/MMS/spatial/advection/runtest | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/MMS/spatial/advection/runtest b/tests/MMS/spatial/advection/runtest index a0423fbce5..394b586552 100755 --- a/tests/MMS/spatial/advection/runtest +++ b/tests/MMS/spatial/advection/runtest @@ -55,7 +55,11 @@ options = [ ] # List of NX values to use -nxlist = [16, 32, 64, 128, 256] +# Careful! upwind-3rd order fails at low resolution with the default +# tolerance, when it is very good over the rest of the +# domain. _Pretty_ sure this isn't anything to worry about, as there +# must be a lower limit +nxlist = [32, 64, 128, 256] nproc = 2 mthread = 2 @@ -99,9 +103,7 @@ for opts, label, sym, exp_ord in options: order = check_scaling.get_order(dx, error_2) print("Convergence order = {:f} ({:f} at small spacing)".format(*order)) - # Loose tolerance because upwind-3rd order would otherwise fail at - # low resolution, when it is very good over the rest of the domain - if check_scaling.check_order(error_2, exp_ord, tolerance=3.e-1): + if check_scaling.check_order(error_2, exp_ord): print("... Success") else: failures.append(label) From 06610d672c3f69bb81b894d6cf777fcefd7d5ed6 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 1 Jul 2019 17:34:44 +0100 Subject: [PATCH 1680/1783] Remove 3rdparty/variant submodule --- .gitmodules | 3 --- 3rdparty/variant | 1 - 2 files changed, 4 deletions(-) delete mode 160000 3rdparty/variant diff --git a/.gitmodules b/.gitmodules index fa166d2a79..27c98fc7be 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,6 +7,3 @@ [submodule "mpark.variant"] path = externalpackages/mpark.variant url = https://github.com/mpark/variant.git -[submodule "3rdparty/variant"] - path = 3rdparty/variant - url = https://github.com/mpark/variant.git diff --git a/3rdparty/variant b/3rdparty/variant deleted file mode 160000 index 00590420f8..0000000000 --- a/3rdparty/variant +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 00590420f8d067f67d60b5de15d94b26558164c1 From 3de5b1aeadda1df740884f245565486a15665b23 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 2 Jul 2019 14:52:51 +0100 Subject: [PATCH 1681/1783] Store SNB::invertpar as a unique_ptr --- include/bout/snb.hxx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/include/bout/snb.hxx b/include/bout/snb.hxx index 36c1a0e15b..595d17d626 100644 --- a/include/bout/snb.hxx +++ b/include/bout/snb.hxx @@ -1,6 +1,8 @@ #include "../options.hxx" #include "../invert_parderiv.hxx" +#include + /// Calculate heat flux using the Shurtz-Nicolai-Busquet (SNB) model /// /// Useful references: @@ -18,7 +20,7 @@ public: /// Construct using options in given section. explicit HeatFluxSNB(Options &options) { - invertpar = InvertPar::Create(); + invertpar = std::unique_ptr{InvertPar::Create()}; // Read options. Note that the defaults are initialised already r = options["r"].doc("Scaling of the electron-electron mean free path") @@ -28,9 +30,7 @@ public: ngroups = options["ngroups"].doc("Number of energy groups").withDefault(ngroups); } - ~HeatFluxSNB() { - delete invertpar; - } + ~HeatFluxSNB() = default; /// Calculate divergence of heat flux /// Te: Electron temperature in eV @@ -43,7 +43,8 @@ public: Field3D divHeatFlux(const Field3D &Te, const Field3D &Ne, Field3D *Div_Q_SH_out = nullptr); private: - InvertPar *invertpar; ///< Parallel inversion of tridiagonal matrices + /// Parallel inversion of tridiagonal matrices + std::unique_ptr invertpar{nullptr}; BoutReal Z{1}; ///< Average ion charge (1 = Hydrogen) BoutReal r{2}; ///< Electron-electron mean free path scaling factor From 9a0f74bb471425896d4dc2c6bee42845c3b934f4 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 2 Jul 2019 14:56:53 +0100 Subject: [PATCH 1682/1783] Add defaulted/deleted move/copy constructors to HeatFluxSNB --- include/bout/snb.hxx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/bout/snb.hxx b/include/bout/snb.hxx index 595d17d626..325b749009 100644 --- a/include/bout/snb.hxx +++ b/include/bout/snb.hxx @@ -32,6 +32,13 @@ public: ~HeatFluxSNB() = default; + HeatFluxSNB(HeatFluxSNB&&) = default; + HeatFluxSNB& operator=(HeatFluxSNB&&) = default; + + // No copy constructors because invertpar is std::unique_ptr + HeatFluxSNB(const HeatFluxSNB&) = delete; + HeatFluxSNB& operator=(const HeatFluxSNB&) = delete; + /// Calculate divergence of heat flux /// Te: Electron temperature in eV /// Ne: Electron density in m^-3 From 049cde50d5308c02db8e5693703eca6e7c513cda Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 2 Jul 2019 15:04:49 +0100 Subject: [PATCH 1683/1783] Put HeatFluxSNB into bout:: namespace --- examples/conduction-snb/conduction-snb.cxx | 2 ++ include/bout/snb.hxx | 4 ++++ src/physics/snb.cxx | 4 ++++ tests/integrated/test-snb/test_snb.cxx | 2 ++ 4 files changed, 12 insertions(+) diff --git a/examples/conduction-snb/conduction-snb.cxx b/examples/conduction-snb/conduction-snb.cxx index d43201bb02..264420ed2a 100644 --- a/examples/conduction-snb/conduction-snb.cxx +++ b/examples/conduction-snb/conduction-snb.cxx @@ -4,6 +4,8 @@ #include int main(int argc, char **argv) { + using bout::HeatFluxSNB; + BoutInitialise(argc, argv); // Read the density and temperature profiles diff --git a/include/bout/snb.hxx b/include/bout/snb.hxx index 325b749009..972b8dfa63 100644 --- a/include/bout/snb.hxx +++ b/include/bout/snb.hxx @@ -3,6 +3,8 @@ #include +namespace bout { + /// Calculate heat flux using the Shurtz-Nicolai-Busquet (SNB) model /// /// Useful references: @@ -69,3 +71,5 @@ private: return (1./24) * (int_beta4_exp(beta_max) - int_beta4_exp(beta_min)); } }; + +} // namespace bout diff --git a/src/physics/snb.cxx b/src/physics/snb.cxx index 8f53ac3dc6..ed39d6a9f5 100644 --- a/src/physics/snb.cxx +++ b/src/physics/snb.cxx @@ -6,6 +6,8 @@ #include "bout/fv_ops.hxx" #include "bout/constants.hxx" +namespace bout { + Field3D HeatFluxSNB::divHeatFlux(const Field3D &Te, const Field3D &Ne, Field3D *Div_Q_SH_out) { Coordinates *coord = Te.getCoordinates(); @@ -72,3 +74,5 @@ Field3D HeatFluxSNB::divHeatFlux(const Field3D &Te, const Field3D &Ne, Field3D * return Div_Q; } + +} // namespace bout diff --git a/tests/integrated/test-snb/test_snb.cxx b/tests/integrated/test-snb/test_snb.cxx index b95095cca9..740d8ac365 100644 --- a/tests/integrated/test-snb/test_snb.cxx +++ b/tests/integrated/test-snb/test_snb.cxx @@ -63,6 +63,8 @@ bool IsFieldClose(const T& field, const U& reference, } int main(int argc, char **argv) { + using bout::HeatFluxSNB; + BoutInitialise(argc, argv); /////////////////////////////////////////////////////////// From 1e81b361cdb438b8f0a8cf085a63114dba8e05b9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 2 Jul 2019 15:07:37 +0100 Subject: [PATCH 1684/1783] Clang-format HeatFluxSNB --- examples/conduction-snb/conduction-snb.cxx | 8 +- include/bout/snb.hxx | 45 +++++----- src/physics/snb.cxx | 51 +++++------ tests/integrated/test-snb/test_snb.cxx | 98 +++++++++++----------- 4 files changed, 106 insertions(+), 96 deletions(-) diff --git a/examples/conduction-snb/conduction-snb.cxx b/examples/conduction-snb/conduction-snb.cxx index 264420ed2a..451fa25e6e 100644 --- a/examples/conduction-snb/conduction-snb.cxx +++ b/examples/conduction-snb/conduction-snb.cxx @@ -3,19 +3,19 @@ #include #include -int main(int argc, char **argv) { +int main(int argc, char** argv) { using bout::HeatFluxSNB; BoutInitialise(argc, argv); // Read the density and temperature profiles - Options &opt = Options::root(); + Options& opt = Options::root(); Field3D Ne = opt["Ne"].doc("Electron density in m^-3").as(); Field3D Te = opt["Te"].doc("Electron temperature in eV").as(); mesh->communicate(Ne, Te); - + // Calculate divergence of heat flux HeatFluxSNB snb; Field3D Div_Q_SH; @@ -24,7 +24,7 @@ int main(int argc, char **argv) { // Save to the output SAVE_ONCE(Ne, Te, Div_Q, Div_Q_SH); dump.write(); - + BoutFinalise(); return 0; } diff --git a/include/bout/snb.hxx b/include/bout/snb.hxx index 972b8dfa63..12fd7ef3ea 100644 --- a/include/bout/snb.hxx +++ b/include/bout/snb.hxx @@ -1,5 +1,5 @@ -#include "../options.hxx" -#include "../invert_parderiv.hxx" +#include "invert_parderiv.hxx" +#include "options.hxx" #include @@ -9,9 +9,11 @@ namespace bout { /// /// Useful references: /// -/// Braginskii equations by R.Fitzpatrick: http://farside.ph.utexas.edu/teaching/plasma/Plasmahtml/node35.html -/// -/// J.P.Brodrick et al 2017: https://doi.org/10.1063/1.5001079 and https://arxiv.org/abs/1704.08963 +/// Braginskii equations by R.Fitzpatrick: +/// http://farside.ph.utexas.edu/teaching/plasma/Plasmahtml/node35.html +/// +/// J.P.Brodrick et al 2017: https://doi.org/10.1063/1.5001079 and +/// https://arxiv.org/abs/1704.08963 /// /// Shurtz, Nicolai and Busquet 2000: https://doi.org/10.1063/1.1289512 /// @@ -21,17 +23,19 @@ public: HeatFluxSNB() : HeatFluxSNB(Options::root()["snb"]) {} /// Construct using options in given section. - explicit HeatFluxSNB(Options &options) { + explicit HeatFluxSNB(Options& options) { invertpar = std::unique_ptr{InvertPar::Create()}; // Read options. Note that the defaults are initialised already - r = options["r"].doc("Scaling of the electron-electron mean free path") - .withDefault(r); - beta_max = options["beta_max"].doc("Maximum energy group to consider (multiple of eT)") - .withDefault(beta_max); + r = options["r"] + .doc("Scaling of the electron-electron mean free path") + .withDefault(r); + beta_max = options["beta_max"] + .doc("Maximum energy group to consider (multiple of eT)") + .withDefault(beta_max); ngroups = options["ngroups"].doc("Number of energy groups").withDefault(ngroups); } - + ~HeatFluxSNB() = default; HeatFluxSNB(HeatFluxSNB&&) = default; @@ -49,26 +53,27 @@ public: /// /// Returns the divergence of heat flux in units of eV per cubic meter per second /// -> multiply by e=1.602e-19 to get Watts per cubic meter. - Field3D divHeatFlux(const Field3D &Te, const Field3D &Ne, Field3D *Div_Q_SH_out = nullptr); - + Field3D divHeatFlux(const Field3D& Te, const Field3D& Ne, + Field3D* Div_Q_SH_out = nullptr); + private: /// Parallel inversion of tridiagonal matrices std::unique_ptr invertpar{nullptr}; - - BoutReal Z{1}; ///< Average ion charge (1 = Hydrogen) - BoutReal r{2}; ///< Electron-electron mean free path scaling factor + + BoutReal Z{1}; ///< Average ion charge (1 = Hydrogen) + BoutReal r{2}; ///< Electron-electron mean free path scaling factor BoutReal beta_max{10.0}; ///< Maximum energy group to consider (multiple of eT) - int ngroups{40}; ///< Number of energy groups + int ngroups{40}; ///< Number of energy groups /// Indefinite integral of beta^4 * exp(-beta) /// with constant set to zero BoutReal int_beta4_exp(BoutReal beta) { - return - exp(- beta) * (24 + beta * (24 + beta * (12 + beta * (4 + beta)))); + return -exp(-beta) * (24 + beta * (24 + beta * (12 + beta * (4 + beta)))); } - + /// (1/24) * Integral of beta^4 * exp(-beta) from beta_min to beta_max BoutReal groupWeight(BoutReal beta_min, BoutReal beta_max) { - return (1./24) * (int_beta4_exp(beta_max) - int_beta4_exp(beta_min)); + return (1. / 24) * (int_beta4_exp(beta_max) - int_beta4_exp(beta_min)); } }; diff --git a/src/physics/snb.cxx b/src/physics/snb.cxx index ed39d6a9f5..1d88ab3882 100644 --- a/src/physics/snb.cxx +++ b/src/physics/snb.cxx @@ -3,47 +3,49 @@ #include "bout/snb.hxx" #include "derivs.hxx" -#include "bout/fv_ops.hxx" #include "bout/constants.hxx" +#include "bout/fv_ops.hxx" namespace bout { -Field3D HeatFluxSNB::divHeatFlux(const Field3D &Te, const Field3D &Ne, Field3D *Div_Q_SH_out) { - Coordinates *coord = Te.getCoordinates(); +Field3D HeatFluxSNB::divHeatFlux(const Field3D& Te, const Field3D& Ne, + Field3D* Div_Q_SH_out) { + Coordinates* coord = Te.getCoordinates(); - Field3D thermal_speed = sqrt(2.*SI::qe * Te / SI::Me); + Field3D thermal_speed = sqrt(2. * SI::qe * Te / SI::Me); BoutReal Y = SQ(SQ(SI::qe) / (SI::e0 * SI::Me)) / (4 * PI); Field3D coulomb_log = 6.6 - 0.5 * log(Ne * 1e-20) + 1.5 * log(Te); // Thermal electron-electron mean free path [m] - Field3D lambda_ee_T = pow(thermal_speed, 4) / (Y * Ne * coulomb_log); - Field3D lambda_ei_T = lambda_ee_T / Z; // Note: Z rather than Z^2 since Ni = Ne / Z - + Field3D lambda_ee_T = pow(thermal_speed, 4) / (Y * Ne * coulomb_log); + Field3D lambda_ei_T = lambda_ee_T / Z; // Note: Z rather than Z^2 since Ni = Ne / Z + // Thermal electron-ion collision time [s] - Field3D tau_ei_T = lambda_ei_T / thermal_speed; - + Field3D tau_ei_T = lambda_ei_T / thermal_speed; + // Divergence of Spitzer-Harm heat flux // Note: 13.58 from 128/(3pi) Field3D Div_Q_SH = -FV::Div_par_K_Grad_par((Ne * SI::qe * Te / SI::Me) - * (0.25 * 3 * sqrt(PI) * tau_ei_T) - * 13.58 * (Z + 0.24) / (Z + 4.2), + * (0.25 * 3 * sqrt(PI) * tau_ei_T) + * 13.58 * (Z + 0.24) / (Z + 4.2), Te); // User can supply an out parameter to get the S-H heat flux divergence if (Div_Q_SH_out) { *Div_Q_SH_out = Div_Q_SH; } - + Field3D lambda_ee_Tprime = lambda_ee_T / r; Field3D lambda_ei_Tprime = lambda_ei_T * ((Z + 0.25) / (Z + 4.2)); - + // Loop over energy groups. // beta = E / eT is the normalised group energy - - BoutReal beta_last = 0.0; // The last beta value calculated. Ths increases through the loop + + BoutReal beta_last = + 0.0; // The last beta value calculated. Ths increases through the loop BoutReal dbeta = beta_max / ngroups; // Step in beta - Field3D Div_Q = Div_Q_SH; // Divergence of heat flux. Corrections added for each group + Field3D Div_Q = Div_Q_SH; // Divergence of heat flux. Corrections added for each group for (int i = 0; i < ngroups; i++) { BoutReal beta = beta_last + dbeta; @@ -52,13 +54,14 @@ Field3D HeatFluxSNB::divHeatFlux(const Field3D &Te, const Field3D &Ne, Field3D * // Mean free paths for this group Field3D lambda_g_ee = SQ(beta) * lambda_ee_Tprime; Field3D lambda_g_ei = SQ(beta) * lambda_ei_Tprime; - + // Update coefficients in solver - invertpar->setCoefA(1./lambda_g_ee); // Constant term + invertpar->setCoefA(1. / lambda_g_ee); // Constant term - // The divergence term is implemented as a second derivative and first derivative correction - Field3D coefB = (-1./3) * lambda_g_ei; - invertpar->setCoefB(coefB); // Grad2_par2 + // The divergence term is implemented as a second derivative and first derivative + // correction + Field3D coefB = (-1. / 3) * lambda_g_ei; + invertpar->setCoefB(coefB); // Grad2_par2 invertpar->setCoefE(DDY(coefB * coord->J / coord->g_22) / coord->J); // DDY // Solve to get H_g @@ -67,11 +70,11 @@ Field3D HeatFluxSNB::divHeatFlux(const Field3D &Te, const Field3D &Ne, Field3D * // Add correction to divergence of heat flux // Note: The sum of weight over all groups approaches 1 as beta_max -> infinity Div_Q -= weight * Div_Q_SH + H_g / lambda_g_ee; - - // move to next group, updating lower limit + + // move to next group, updating lower limit beta_last = beta; } - + return Div_Q; } diff --git a/tests/integrated/test-snb/test_snb.cxx b/tests/integrated/test-snb/test_snb.cxx index 740d8ac365..fce39291f7 100644 --- a/tests/integrated/test-snb/test_snb.cxx +++ b/tests/integrated/test-snb/test_snb.cxx @@ -1,32 +1,32 @@ #include #include #include -#include #include +#include // Convert __LINE__ to string S__LINE__ #define S(x) #x #define S_(x) S(x) #define S__LINE__ S_(__LINE__) -#define EXPECT_TRUE(expr) \ - if (!expr) { \ +#define EXPECT_TRUE(expr) \ + if (!expr) { \ throw BoutException("Line " S__LINE__ " Expected true, got false: " #expr); \ } -#define EXPECT_FALSE(expr) \ - if (expr) { \ +#define EXPECT_FALSE(expr) \ + if (expr) { \ throw BoutException("Line " S__LINE__ " Expected false, got true: " #expr); \ } /// Is \p field equal to \p reference, with a tolerance of \p tolerance? template bool IsFieldEqual(const T& field, const U& reference, - const std::string& region = "RGN_ALL", - BoutReal tolerance = 1e-10) { + const std::string& region = "RGN_ALL", BoutReal tolerance = 1e-10) { for (auto i : field.getRegion(region)) { if (fabs(field[i] - reference[i]) > tolerance) { - output.write("Field: %e, reference: %e, tolerance: %e\n", field[i], reference[i], tolerance); + output.write("Field: %e, reference: %e, tolerance: %e\n", field[i], reference[i], + tolerance); return false; } } @@ -37,11 +37,11 @@ bool IsFieldEqual(const T& field, const U& reference, /// Overload for BoutReals template bool IsFieldEqual(const T& field, BoutReal reference, - const std::string& region = "RGN_ALL", - BoutReal tolerance = 1e-10) { + const std::string& region = "RGN_ALL", BoutReal tolerance = 1e-10) { for (auto i : field.getRegion(region)) { if (fabs(field[i] - reference) > tolerance) { - output.write("Field: %e, reference: %e, tolerance: %e\n", field[i], reference, tolerance); + output.write("Field: %e, reference: %e, tolerance: %e\n", field[i], reference, + tolerance); return false; } } @@ -51,18 +51,19 @@ bool IsFieldEqual(const T& field, BoutReal reference, /// Is \p field close to \p reference, with a relative tolerance of \p tolerance? template bool IsFieldClose(const T& field, const U& reference, - const std::string& region = "RGN_ALL", - BoutReal tolerance = 1e-4) { + const std::string& region = "RGN_ALL", BoutReal tolerance = 1e-4) { for (auto i : field.getRegion(region)) { - if (fabs(field[i] - reference[i]) > tolerance * (fabs(reference[i]) + fabs(field[i]))) { - output.write("Field: %e, reference: %e, tolerance: %e\n", field[i], reference[i], tolerance * (fabs(reference[i]) + fabs(field[i]))); + if (fabs(field[i] - reference[i]) + > tolerance * (fabs(reference[i]) + fabs(field[i]))) { + output.write("Field: %e, reference: %e, tolerance: %e\n", field[i], reference[i], + tolerance * (fabs(reference[i]) + fabs(field[i]))); return false; } } return true; } -int main(int argc, char **argv) { +int main(int argc, char** argv) { using bout::HeatFluxSNB; BoutInitialise(argc, argv); @@ -76,17 +77,17 @@ int main(int argc, char **argv) { auto Ne = factory.create3D("1e18 * (1 + 0.5*sin(y))"); mesh->communicate(Te, Ne); - + HeatFluxSNB snb; - + Field3D Div_q_SH; Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); - + // Check that flux is not zero EXPECT_FALSE(IsFieldEqual(Div_q_SH, 0.0, "RGN_NOBNDRY")); EXPECT_FALSE(IsFieldEqual(Div_q, 0.0, "RGN_NOBNDRY")); } - + /////////////////////////////////////////////////////////// // When the temperature is constant there is no flux @@ -94,14 +95,14 @@ int main(int argc, char **argv) { FieldFactory factory; auto Te = factory.create3D("1.5"); auto Ne = factory.create3D("1e18 * (1 + 0.5*sin(y))"); - + mesh->communicate(Te, Ne); - + HeatFluxSNB snb; - + Field3D Div_q_SH; Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); - + // Check that flux is zero EXPECT_TRUE(IsFieldEqual(Div_q_SH, 0.0, "RGN_NOBNDRY")); EXPECT_TRUE(IsFieldEqual(Div_q, 0.0, "RGN_NOBNDRY")); @@ -115,16 +116,16 @@ int main(int argc, char **argv) { auto Te = factory.create3D("1 + 0.01*sin(y)"); auto Ne = factory.create3D("1e20 * (1 + 0.5*sin(y))"); mesh->communicate(Te, Ne); - + HeatFluxSNB snb; - + Field3D Div_q_SH; Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); - + // Check that flux is zero EXPECT_TRUE(IsFieldClose(Div_q, Div_q_SH, "RGN_NOBNDRY")); } - + /////////////////////////////////////////////////////////// // In the collisionless limit the SH and SNB fluxes are different @@ -133,55 +134,56 @@ int main(int argc, char **argv) { auto Te = factory.create3D("1e3 + 0.01*sin(y)"); auto Ne = factory.create3D("1e19 * (1 + 0.5*sin(y))"); mesh->communicate(Te, Ne); - + HeatFluxSNB snb; - + Field3D Div_q_SH; Field3D Div_q = snb.divHeatFlux(Te, Ne, &Div_q_SH); - + // Check that fluxes are not equal EXPECT_FALSE(IsFieldClose(Div_q, Div_q_SH, "RGN_NOBNDRY")); } - + /////////////////////////////////////////////////////////// // Reversing the temperature gradient reverses the flux { Field3D Ne = 1e19; - + FieldFactory factory; auto Te = factory.create3D("10 + 0.01*sin(y)"); mesh->communicate(Te); - + HeatFluxSNB snb; - + Field3D Div_q_SH_1; Field3D Div_q_1 = snb.divHeatFlux(Te, Ne, &Div_q_SH_1); - + auto Te2 = factory.create3D("10 - 0.01*sin(y)"); mesh->communicate(Te2); - + Field3D Div_q_SH_2; Field3D Div_q_2 = snb.divHeatFlux(Te2, Ne, &Div_q_SH_2); - + // Check that fluxes are reversed in y for (int y = mesh->ystart; y <= mesh->yend; y++) { - if (fabs(Div_q_SH_2(0,y,0) - Div_q_SH_1(0, mesh->yend - y + mesh->ystart,0)) - > 1e-6 * (fabs(Div_q_SH_2(0,y,0)) + fabs(Div_q_SH_1(0,y,0)))) { - throw BoutException("SH: y = %d: %e != %e", y, Div_q_SH_2(0,y,0), Div_q_SH_1(0,mesh->yend - y + mesh->ystart,0)); + if (fabs(Div_q_SH_2(0, y, 0) - Div_q_SH_1(0, mesh->yend - y + mesh->ystart, 0)) + > 1e-6 * (fabs(Div_q_SH_2(0, y, 0)) + fabs(Div_q_SH_1(0, y, 0)))) { + throw BoutException("SH: y = %d: %e != %e", y, Div_q_SH_2(0, y, 0), + Div_q_SH_1(0, mesh->yend - y + mesh->ystart, 0)); } - - if (fabs(Div_q_2(0,y,0) - Div_q_1(0,mesh->yend - y + mesh->ystart,0)) - > 1e-6 * (fabs(Div_q_2(0,y,0)) + fabs(Div_q_1(0,y,0)))) { - throw BoutException("SNB: y = %d: %e != %e", y, Div_q_2(0,y,0), Div_q_1(0,mesh->yend - y + mesh->ystart,0)); + + if (fabs(Div_q_2(0, y, 0) - Div_q_1(0, mesh->yend - y + mesh->ystart, 0)) + > 1e-6 * (fabs(Div_q_2(0, y, 0)) + fabs(Div_q_1(0, y, 0)))) { + throw BoutException("SNB: y = %d: %e != %e", y, Div_q_2(0, y, 0), + Div_q_1(0, mesh->yend - y + mesh->ystart, 0)); } } - } - + BoutFinalise(); output << "All tests passed\n"; - + return 0; } From a5007a7060074992f51ae7c4d41ee943cee9f7bf Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 2 Jul 2019 15:22:16 +0100 Subject: [PATCH 1685/1783] Add README for SNB example --- examples/conduction-snb/README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 examples/conduction-snb/README.md diff --git a/examples/conduction-snb/README.md b/examples/conduction-snb/README.md new file mode 100644 index 0000000000..2c6aaa68a8 --- /dev/null +++ b/examples/conduction-snb/README.md @@ -0,0 +1,31 @@ +SNB non-local heat conduction +============================= + +The Shurtz, Nicolai and Busquet (SNB) model [Physics of Plasmas 7, 4238 (2000)](https://doi.org/10.1063/1.1289512) is a +multigroup diffusion model which captures some features of kinetic electron heat +conduction. + +If the thermal mean free path is more than a few percent of the gradient scale +length, then the collisional Spitzer-Harm (Braginskii) heat conduction model +tends to over-estimate the heat flux. Flux limiters can in some cases capture +this, but need to be tuned and in general the tuning needed varies in time and +space. In other regions the collisional model can under-estimate the heat flux +due to the high energy tail of the distribution function. This "pre-heat" can be +to some extent captured by the SNB model. + +Sinusoidal perturbation +----------------------- + + python sinusoid.py + +This test case puts a small variation in temperature on top of a periodic background. The background temperature is varied, and the SNB heat flux compared against Spitzer-Harm for a range of mean free paths. + + +Temperature step +---------------- + + python step.py + +This case has a large change in temperature, from nearly 1keV to 200eV over 0.3mm, +relevant to a laser-plasma experiment. This is compared against a kinetic VFP solution. + From 1e4f391b32d7bc5ba6e5f289b36eddeaea29225a Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 2 Jul 2019 15:23:17 +0100 Subject: [PATCH 1686/1783] Codacy doesn't like trailing space Small tidy --- examples/conduction-snb/fit_temperature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/conduction-snb/fit_temperature.py b/examples/conduction-snb/fit_temperature.py index de54cd2dab..1e7f3ddf94 100644 --- a/examples/conduction-snb/fit_temperature.py +++ b/examples/conduction-snb/fit_temperature.py @@ -10,7 +10,7 @@ def te_function(ypos, mid, wwid, w0, w1, w2, Tmax, Tmin, clip=False): if clip: width = np.clip(width, 1e-10, None) - + return Tmax - 0.5 * (1 + np.tanh((ypos - mid)/width)) * (Tmax - Tmin) popt, pcov = optimize.curve_fit(te_function, Te_ref[:,0], Te_ref[:,1], From 8d2d6aad547092217623bd80da36391a62ddeadf Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 9 Jul 2019 12:07:26 +0100 Subject: [PATCH 1687/1783] Fix y-boundary cells of phi in conducting-wall-mode example --- examples/conducting-wall-mode/cwm.cxx | 6 ++++++ examples/conducting-wall-mode/data/BOUT.inp | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/examples/conducting-wall-mode/cwm.cxx b/examples/conducting-wall-mode/cwm.cxx index 859bcbca12..8ce3fbb38d 100644 --- a/examples/conducting-wall-mode/cwm.cxx +++ b/examples/conducting-wall-mode/cwm.cxx @@ -214,6 +214,9 @@ class CWM : public PhysicsModel { SOLVE_FOR(te); comms.add(te); + // Set boundary conditions for phi + phi.setBoundary("phi"); + /************** SETUP COMMUNICATIONS **************/ // add extra variables to communication @@ -252,6 +255,9 @@ class CWM : public PhysicsModel { // Communicate variables mesh->communicate(comms); + // 'initial guess' for phi boundary values, before applying sheath boundary conditions + // to set the parallel current. + phi.applyBoundary(); phi_sheath_bndryconds(); // Evolve rho and te diff --git a/examples/conducting-wall-mode/data/BOUT.inp b/examples/conducting-wall-mode/data/BOUT.inp index 2812ae3a48..30902575a2 100644 --- a/examples/conducting-wall-mode/data/BOUT.inp +++ b/examples/conducting-wall-mode/data/BOUT.inp @@ -111,3 +111,9 @@ scale = -1.0e-8 function = sin(y) * sin(z) [te] + +[phi] +bndry_xin = none +bndry_xout = none +bndry_ydown = free_o3 +bndry_yup = free_o3 From b12ccc1a10ecddb76debcc7168d07616ac150229 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Thu, 11 Jul 2019 04:09:30 +0100 Subject: [PATCH 1688/1783] Add README to CWM example Include link to Brett's slides from BOUT++ workshop. --- examples/conducting-wall-mode/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 examples/conducting-wall-mode/README.md diff --git a/examples/conducting-wall-mode/README.md b/examples/conducting-wall-mode/README.md new file mode 100644 index 0000000000..96e8d7432e --- /dev/null +++ b/examples/conducting-wall-mode/README.md @@ -0,0 +1,10 @@ +Conducting Wall Mode +==================== + +Simplified model for instability driven by sheath boundary condition +and electron temperature gradient in a straight magnetic field. + +Created by B.Friedman to go with his [slides for a hands-on +exercise](https://bout2013.llnl.gov/pdf/2011/talks/Friedman_lapda_afternoon.pdf) +at the 2013 BOUT++ workshop. + From 751290418eb91ce1768a3813cb86b9588fdad7e6 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 12 Jul 2019 17:17:11 +0100 Subject: [PATCH 1689/1783] Fix writing of BoutArrays in DataFile_netCDF Python class Previously tried to check if the input variable was a BoutArray with 't=="BoutArray"', but 't' has already been changed to the data-type of the array entries so the condition always evaluated to 'False'. Instead just try to use 'data.attributes['bout_type']' and catch the 'AttributeError' that is thrown if the variable is not a BoutArray (or 'bout_type' has not been set). --- tools/pylib/boututils/datafile.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/pylib/boututils/datafile.py b/tools/pylib/boututils/datafile.py index 470b5c4f3f..9f846d2369 100644 --- a/tools/pylib/boututils/datafile.py +++ b/tools/pylib/boututils/datafile.py @@ -539,9 +539,9 @@ def write(self, name, data, info=False): # Not found, so add. # Get dimensions - if t == 'BoutArray': - defdims = _bout_dimensions_from_type(data.attributes['bout_type']) - else: + try: + defdims = self._bout_dimensions_from_type(data.attributes['bout_type']) + except AttributeError: defdims_list = [(), ('t',), ('x', 'y'), From f9702c1c6bd2b9a3352e11163cc9045742545abc Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 12 Jul 2019 17:21:25 +0100 Subject: [PATCH 1690/1783] Handle 1d x-direction BoutArrays in Python DataFile Ability to handle 1d BoutArrays, representing a variable that only varies in x, is needed to handle the 'ShiftAngle' in grid files. --- tools/pylib/boututils/datafile.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/pylib/boututils/datafile.py b/tools/pylib/boututils/datafile.py index 9f846d2369..ef2c62c57d 100644 --- a/tools/pylib/boututils/datafile.py +++ b/tools/pylib/boututils/datafile.py @@ -478,6 +478,7 @@ def _bout_type_from_dimensions(self, varname): ('x', 'y', 'z'): "Field3D", ('x', 'y'): "Field2D", ('x', 'z'): "FieldPerp", + ('x'): "ArrayX", (): "scalar", } @@ -492,6 +493,7 @@ def _bout_dimensions_from_type(self, bout_type): "Field3D": ('x', 'y', 'z'), "Field2D": ('x', 'y'), "FieldPerp": ('x', 'z'), + "ArrayX": ('x'), "scalar": (), } @@ -786,6 +788,7 @@ def dimensions(self, varname): "Field3D": ('x', 'y', 'z'), "FieldPerp": ('x', 'z'), "Field2D": ('x', 'y'), + "ArrayX": ('x'), "scalar": (), } try: From 5b742bca0a846287fef1e876177e940479d3e379 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 12 Jul 2019 18:48:13 +0100 Subject: [PATCH 1691/1783] Fix reading of zShift_ylow Previously, some variables did not have location set when loading Coordinates at non-CELL_CENTRE locations from file. --- src/mesh/coordinates.cxx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 018653b656..ebc55394fe 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -436,18 +436,14 @@ Coordinates::Coordinates(Mesh* mesh, Options* options, const CELL_LOC loc, "cells\n")); } - checkStaggeredGet(mesh, "dx", suffix); - mesh->get(dx, "dx"+suffix, 1.0); - dx.setLocation(location); + getAtLoc(mesh, dx, "dx", suffix, location, 1.0); dx = interpolateAndExtrapolate(dx, location, extrapolate_x, extrapolate_y); if (mesh->periodicX) { mesh->communicate(dx); } - checkStaggeredGet(mesh, "dy", suffix); - mesh->get(dy, "dy"+suffix, 1.0); - dy.setLocation(location); + getAtLoc(mesh, dy, "dy", suffix, location, 1.0); dy = interpolateAndExtrapolate(dy, location, extrapolate_x, extrapolate_y); // grid data source has staggered fields, so read instead of interpolating @@ -833,6 +829,7 @@ int Coordinates::geometry(bool recalculate_staggered, localmesh->communicate(d1_dx); d1_dx = interpolateAndExtrapolate(d1_dx, location, true, true, true); } else { + d2x.setLocation(location); // set boundary cells if necessary d2x = interpolateAndExtrapolate(d2x, location, extrapolate_x, extrapolate_y); @@ -847,7 +844,8 @@ int Coordinates::geometry(bool recalculate_staggered, localmesh->communicate(d1_dy); d1_dy = interpolateAndExtrapolate(d1_dy, location, true, true, true); } else { - // Shift d2y to our location + d2y.setLocation(location); + // set boundary cells if necessary d2y = interpolateAndExtrapolate(d2y, location, extrapolate_x, extrapolate_y); d1_dy = -d2y / (dy * dy); @@ -1102,6 +1100,7 @@ void Coordinates::setParallelTransform(Options* options) { throw BoutException("Could not read zShift"+suffix+" from grid file"); } } + zShift.setLocation(location); } else { Field2D zShift_centre; if (localmesh->get(zShift_centre, "zShift")) { From 08954adb807e58bfa49689783a3ea72cc552085f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 14 Jul 2019 14:36:20 +0100 Subject: [PATCH 1692/1783] Set y_direction_out even when LocalNz=1 In ShiftedMetric::shiftZ, no FFT or interpolation needs to be done when LocalNz==1, but we still need to change the YDirectionType of the returned field so that checks can be done as if LocalNz>1. --- src/mesh/parallel/shiftedmetric.cxx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 2a27c67363..b9cdc8aad6 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -188,8 +188,11 @@ const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Tensor& ph ASSERT1(f.getMesh() == &mesh); ASSERT1(f.getLocation() == location); - if (mesh.LocalNz == 1) - return f; // Shifting makes no difference + if (mesh.LocalNz == 1) { + // Shifting does not change the array values + Field3D result = copy(f).setDirectionY(y_direction_out); + return result; + } Field3D result{emptyFrom(f).setDirectionY(y_direction_out)}; @@ -206,8 +209,11 @@ const FieldPerp ShiftedMetric::shiftZ(const FieldPerp& f, const Tensor ASSERT1(f.getMesh() == &mesh); ASSERT1(f.getLocation() == location); - if (mesh.LocalNz == 1) - return f; // Shifting makes no difference + if (mesh.LocalNz == 1) { + // Shifting does not change the array values + FieldPerp result = copy(f).setDirectionY(y_direction_out); + return result; + } FieldPerp result{emptyFrom(f).setDirectionY(y_direction_out)}; From 3e7fb01e7c98cd70b9ef75db4b81e8b4cd2f2fb9 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 15 Jul 2019 13:21:56 +0100 Subject: [PATCH 1693/1783] Add processor indices to dump files Write the variables PE_XIND (x-index of the processor), PE_YIND (y-index of the processor) and MYPE (flat index of the processor) to the dump files. --- src/mesh/impls/bout/boutmesh.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 08d24dd587..5aa9172bef 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2596,6 +2596,9 @@ void BoutMesh::outputVars(Datafile &file) { file.add(MXSUB, "MXSUB", false); file.add(MYSUB, "MYSUB", false); file.add(MZSUB, "MZSUB", false); + file.add(PE_XIND, "PE_XIND", false); + file.add(PE_YIND, "PE_YIND", false); + file.add(MYPE, "MYPE", false); file.add(MXG, "MXG", false); file.add(MYG, "MYG", false); file.add(MZG, "MZG", false); From 43e6afec550dae670bfe877f2827bd449c9fbe41 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 15 Jul 2019 13:57:19 +0100 Subject: [PATCH 1694/1783] Try GitHub url for SUNDIALS if LLNL url fails --- .build_sundials_for_travis.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.build_sundials_for_travis.sh b/.build_sundials_for_travis.sh index bfecfd9db9..24bb0bc286 100755 --- a/.build_sundials_for_travis.sh +++ b/.build_sundials_for_travis.sh @@ -7,8 +7,13 @@ if [[ ! -d $HOME/local/include/sundials ]]; then echo "Building SUNDIALS" echo "****************************************" sundials_ver=4.1.0 - wget https://computation.llnl.gov/projects/sundials/download/sundials-${sundials_ver}.tar.gz - tar xvf sundials-${sundials_ver}.tar.gz + tarball_name=sundials-${sundials_ver}.tar.gz + llnl_url=https://computation.llnl.gov/projects/sundials/download/${tarball_name} + github_url=https://github.com/LLNL/sundials/releases/download/v${sundials_ver}/${tarball_name} + wget ${llnl_url} \ + || wget ${github_url} \ + || (echo "Could not download SUNDIALS! Aborting"; exit 1) + tar xvf ${tarball_name} mkdir -p sundials-${sundials_ver}/build && cd sundials-${sundials_ver}/build cmake -DCMAKE_INSTALL_PREFIX="$HOME/local" \ -DEXAMPLES_INSTALL=off \ From 8fa89259737d87a43f593d61e5140fcfa431471d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 15 Jul 2019 14:59:10 +0100 Subject: [PATCH 1695/1783] Consistent getGlobalXIndex, getGlobalYIndex and getGlobalZIndex methods These replace XGLOBAL and YGLOBAL which are now deprecated. The new methods use a global cell numbering which includes all boundary cells. XGLOBAL and YGLOBAL were inconsistent as XGLOBAL included boundary cells, but YGLOBAL did not. --- include/bout/mesh.hxx | 14 ++++++++++++++ src/mesh/impls/bout/boutmesh.cxx | 19 +++++++++++++++++++ src/mesh/impls/bout/boutmesh.hxx | 4 ++++ tests/unit/test_extras.hxx | 3 +++ 4 files changed, 40 insertions(+) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index db2dd7cc4c..f7c2b097af 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -475,9 +475,11 @@ class Mesh { /// Returns the global X index given a local index /// If the local index includes the boundary cells, then so does the global. + [[gnu::deprecated("Use getGlobalXIndex instead")]] virtual int XGLOBAL(int xloc) const = 0; /// Returns the global Y index given a local index /// The local index must include the boundary, the global index does not. + [[gnu::deprecated("Use getGlobalYIndex instead")]] virtual int YGLOBAL(int yloc) const = 0; /// Returns the local X index given a global index @@ -487,6 +489,18 @@ class Mesh { /// If the global index includes the boundary cells, then so does the local. virtual int YLOCAL(int yglo) const = 0; + /// Returns a global X index given a local index. + /// Global index includes boundary cells, local index includes boundary or guard cells. + virtual int getGlobalXIndex(int xlocal) const = 0; + + /// Returns a global Y index given a local index. + /// Global index includes boundary cells, local index includes boundary or guard cells. + virtual int getGlobalYIndex(int ylocal) const = 0; + + /// Returns a global Z index given a local index. + /// Global index includes boundary cells, local index includes boundary or guard cells. + virtual int getGlobalZIndex(int zlocal) const = 0; + /// Size of the mesh on this processor including guard/boundary cells int LocalNx, LocalNy, LocalNz; diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 08d24dd587..72e5155524 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -1500,6 +1500,10 @@ int BoutMesh::XGLOBAL(BoutReal xloc, BoutReal &xglo) const { return static_cast(xglo); } +/// Returns a global X index given a local index. +/// Global index includes boundary cells, local index includes boundary or guard cells. +int BoutMesh::getGlobalXIndex(int xlocal) const { return xlocal + PE_XIND * MXSUB; } + /// Returns a local X index given a global index int BoutMesh::XLOCAL(int xglo) const { return xglo - PE_XIND * MXSUB; } @@ -1512,6 +1516,17 @@ int BoutMesh::YGLOBAL(BoutReal yloc, BoutReal &yglo) const { return static_cast(yglo); } +/// Returns a global Y index given a local index. +/// Global index includes boundary cells, local index includes boundary or guard cells. +int BoutMesh::getGlobalYIndex(int ylocal) const { + int yglobal = ylocal + PE_YIND * MYSUB; + if (jyseps1_2 > jyseps2_1 and PE_YIND*MYSUB + 2*MYG + 1 > ny_inner) { + // Double null, and we are past the upper target + yglobal += 2*MYG; + } + return yglobal; +} + /// Global Y index given local index and processor int BoutMesh::YGLOBAL(int yloc, int yproc) const { return yloc + yproc * MYSUB - MYG; } @@ -1520,6 +1535,10 @@ int BoutMesh::YLOCAL(int yglo) const { return yglo - PE_YIND * MYSUB + MYG; } int BoutMesh::YLOCAL(int yglo, int yproc) const { return yglo - yproc * MYSUB + MYG; } +/// Returns a global Z index given a local index. +/// Global index includes boundary cells, local index includes boundary or guard cells. +int BoutMesh::getGlobalZIndex(int zlocal) const { return zlocal; } + /// Return the Y processor number given a global Y index int BoutMesh::YPROC(int yind) { if ((yind < 0) || (yind > ny)) diff --git a/src/mesh/impls/bout/boutmesh.hxx b/src/mesh/impls/bout/boutmesh.hxx index 64dda57284..331e230f7c 100644 --- a/src/mesh/impls/bout/boutmesh.hxx +++ b/src/mesh/impls/bout/boutmesh.hxx @@ -180,6 +180,10 @@ class BoutMesh : public Mesh { int XGLOBAL(BoutReal xloc, BoutReal& xglo) const; int YGLOBAL(BoutReal yloc, BoutReal& yglo) const; + int getGlobalXIndex(int xlocal) const override; + int getGlobalYIndex(int ylocal) const override; + int getGlobalZIndex(int zlocal) const override; + int XLOCAL(int xglo) const override; int YLOCAL(int yglo) const override; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 41c5712009..7ebd5997d9 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -287,6 +287,9 @@ public: BoutReal GlobalY(BoutReal jy) const override { return jy; } int XGLOBAL(int UNUSED(xloc)) const override { return 0; } int YGLOBAL(int UNUSED(yloc)) const override { return 0; } + int getGlobalXIndex(int) const override { return 0; } + int getGlobalYIndex(int) const override { return 0; } + int getGlobalZIndex(int) const override { return 0; } int XLOCAL(int UNUSED(xglo)) const override { return 0; } int YLOCAL(int UNUSED(yglo)) const override { return 0; } From de7d55811d07ed1befee07cab1c1fa53ec5b660b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 15 Jul 2019 15:28:54 +0100 Subject: [PATCH 1696/1783] Remove uses of deprecated XGLOBAL and YGLOBAL methods --- examples/6field-simple/elm_6f.cxx | 4 +- examples/elm-pb/elm_pb.cxx | 4 +- src/fileio/dataformat.cxx | 4 +- .../laplace/impls/mumps/mumps_laplace.cxx | 16 +++---- src/mesh/impls/bout/boutmesh.cxx | 32 ++++++++----- src/mesh/impls/bout/boutmesh.hxx | 6 ++- .../test-globalfield/test_globalfield.cxx | 8 ++-- .../test-petsc_laplace/test_petsc_laplace.cxx | 48 +++++++++---------- .../test_petsc_laplace_MAST_grid.cxx | 48 +++++++++---------- 9 files changed, 89 insertions(+), 81 deletions(-) diff --git a/examples/6field-simple/elm_6f.cxx b/examples/6field-simple/elm_6f.cxx index 946d776301..cb1314b58c 100644 --- a/examples/6field-simple/elm_6f.cxx +++ b/examples/6field-simple/elm_6f.cxx @@ -303,9 +303,9 @@ const Field2D N0tanh(BoutReal n0_height, BoutReal n0_ave, BoutReal n0_width, BoutReal xgrid_num = (Jxsep + 1.) / Grid_NX; // output.write("mgx = %e xgrid_num = %e\n", mgx); for (int jy = 0; jy < mesh->LocalNy; jy++) { - int globaly = mesh->YGLOBAL(jy); + int globaly = mesh->getGlobalYIndex(jy); // output.write("local y = %i; global y: %i\n", jy, globaly); - if (mgx > xgrid_num || (globaly <= int(Jysep) - 4) || (globaly > int(Jysep2))) + if (mgx > xgrid_num || (globaly <= int(Jysep) - 2) || (globaly > int(Jysep2) + 2)) mgx = xgrid_num; BoutReal rlx = mgx - n0_center; BoutReal temp = exp(rlx / n0_width); diff --git a/examples/elm-pb/elm_pb.cxx b/examples/elm-pb/elm_pb.cxx index 49d2917d74..3c3308f14a 100644 --- a/examples/elm-pb/elm_pb.cxx +++ b/examples/elm-pb/elm_pb.cxx @@ -247,9 +247,9 @@ class ELMpb : public PhysicsModel { BoutReal mgx = mesh->GlobalX(i.x()); BoutReal xgrid_num = (Jxsep + 1.) / Grid_NX; - int globaly = mesh->YGLOBAL(i.y()); + int globaly = mesh->getGlobalYIndex(i.y()); - if (mgx > xgrid_num || (globaly <= int(Jysep) - 4) || (globaly > int(Jysep2))) + if (mgx > xgrid_num || (globaly <= int(Jysep) - 2) || (globaly > int(Jysep2) + 2)) mgx = xgrid_num; BoutReal rlx = mgx - n0_center; BoutReal temp = exp(rlx / n0_width); diff --git a/src/fileio/dataformat.cxx b/src/fileio/dataformat.cxx index 2059452597..08d9568e3e 100644 --- a/src/fileio/dataformat.cxx +++ b/src/fileio/dataformat.cxx @@ -48,10 +48,10 @@ void DataFormat::writeFieldAttributes(const std::string& name, const FieldPerp& int yindex = f.getIndex(); if (yindex >= 0 and yindex < fieldmesh.LocalNy) { // write global y-index as attribute - setAttribute(name, "yindex_global", fieldmesh.YGLOBAL(f.getIndex())); + setAttribute(name, "yindex_global", fieldmesh.getGlobalYIndex(f.getIndex())); } else { // y-index is not valid, set global y-index to -1 to indicate 'not-valid' - setAttribute(name, "yindex_global", -fieldmesh.ystart-1); + setAttribute(name, "yindex_global", -1); } } diff --git a/src/invert/laplace/impls/mumps/mumps_laplace.cxx b/src/invert/laplace/impls/mumps/mumps_laplace.cxx index 26b8338b7c..03f8f28283 100644 --- a/src/invert/laplace/impls/mumps/mumps_laplace.cxx +++ b/src/invert/laplace/impls/mumps/mumps_laplace.cxx @@ -265,11 +265,11 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc, Mesh *mesh_in = mes } for (int x=localmesh->xstart; x<=localmesh->xend; x++) for (int z=0; zLocalNz; z++) { - int xmm = localmesh->XGLOBAL(x)-2; - int xm = localmesh->XGLOBAL(x)-1; - int x0 = localmesh->XGLOBAL(x); - int xp = localmesh->XGLOBAL(x)+1; - int xpp = localmesh->XGLOBAL(x)+2; + int xmm = localmesh->getGlobalXIndex(x)-2; + int xm = localmesh->getGlobalXIndex(x)-1; + int x0 = localmesh->getGlobalXIndex(x); + int xp = localmesh->getGlobalXIndex(x)+1; + int xpp = localmesh->getGlobalXIndex(x)+2; int zmm = (z-2<0) ? (z-2+meshz) : (z-2); int zm = (z-1<0) ? (z-1+meshz) : (z-1); int z0 = z; @@ -387,9 +387,9 @@ LaplaceMumps::LaplaceMumps(Options *opt, const CELL_LOC loc, Mesh *mesh_in = mes if (localmesh->lastX()) for (int x=localmesh->xend+1; xLocalNx; x++) for (int z=0; zLocalNz; z++) { - int xmm = localmesh->XGLOBAL(localmesh->xend)+x-localmesh->xend-2; - int xm = localmesh->XGLOBAL(localmesh->xend)+x-localmesh->xend-1; - int x0 = localmesh->XGLOBAL(localmesh->xend)+x-localmesh->xend; + int xmm = localmesh->getGlobalXIndex(localmesh->xend)+x-localmesh->xend-2; + int xm = localmesh->getGlobalXIndex(localmesh->xend)+x-localmesh->xend-1; + int x0 = localmesh->getGlobalXIndex(localmesh->xend)+x-localmesh->xend; int z0 = z; if(outer_boundary_flags & INVERT_AC_GRAD) { mumps_struc.irn_loc[i] = x0*meshz + z0 + 1; // Indices for fortran arrays that start at 1 diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 72e5155524..3ee4b1838e 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -469,7 +469,7 @@ int BoutMesh::load() { ShiftAngle.resize(LocalNx); - if (!source->get(this, ShiftAngle, "ShiftAngle", LocalNx, XGLOBAL(0))) { + if (!source->get(this, ShiftAngle, "ShiftAngle", LocalNx, getGlobalXIndex(0))) { ShiftAngle.clear(); } @@ -812,7 +812,7 @@ int BoutMesh::load() { if (PE_XIND == 0) { // Inner either core or PF - int yg = YGLOBAL(MYG); // Get a global index in this processor + int yg = getGlobalYIndexNoBoundaries(MYG); // Get a global index in this processor if (((yg > jyseps1_1) && (yg <= jyseps2_1)) || ((yg > jyseps1_2) && (yg <= jyseps2_2))) { @@ -1299,7 +1299,7 @@ bool BoutMesh::firstY() const { return PE_YIND == 0; } bool BoutMesh::lastY() const { return PE_YIND == NYPE - 1; } bool BoutMesh::firstY(int xpos) const { - int xglobal = XGLOBAL(xpos); + int xglobal = getGlobalXIndex(xpos); int rank; if (xglobal < ixseps_inner) { @@ -1313,7 +1313,7 @@ bool BoutMesh::firstY(int xpos) const { } bool BoutMesh::lastY(int xpos) const { - int xglobal = XGLOBAL(xpos); + int xglobal = getGlobalXIndex(xpos); int rank; int size; @@ -1527,6 +1527,12 @@ int BoutMesh::getGlobalYIndex(int ylocal) const { return yglobal; } +/// Private method that keeps the behaviour of the old YGLOBAL method, excluding all +/// boundary cells, for use inside BoutMesh. +int BoutMesh::getGlobalYIndexNoBoundaries(int ylocal) const { + return ylocal + PE_YIND * MYSUB - MYG; +} + /// Global Y index given local index and processor int BoutMesh::YGLOBAL(int yloc, int yproc) const { return yloc + yproc * MYSUB - MYG; } @@ -2044,12 +2050,12 @@ int BoutMesh::unpack_data(const std::vector &var_list, int xge, int ****************************************************************/ bool BoutMesh::periodicY(int jx) const { - return (XGLOBAL(jx) < ixseps_inner) && MYPE_IN_CORE; + return (getGlobalXIndex(jx) < ixseps_inner) && MYPE_IN_CORE; } bool BoutMesh::periodicY(int jx, BoutReal &ts) const { ts = 0.; - if ((XGLOBAL(jx) < ixseps_inner) && MYPE_IN_CORE) { + if ((getGlobalXIndex(jx) < ixseps_inner) && MYPE_IN_CORE) { if (TwistShift) ts = ShiftAngle[jx]; return true; @@ -2087,8 +2093,8 @@ std::pair BoutMesh::hasBranchCutUpper(int jx) const { } int BoutMesh::ySize(int xpos) const { - int xglobal = XGLOBAL(xpos); - int yglobal = YGLOBAL(MYG); + int xglobal = getGlobalXIndex(xpos); + int yglobal = getGlobalYIndexNoBoundaries(MYG); if ((xglobal < ixseps_lower) && ((yglobal <= jyseps1_1) || (yglobal > jyseps2_2))) { // Lower PF region @@ -2126,7 +2132,7 @@ int BoutMesh::ySize(int xpos) const { } MPI_Comm BoutMesh::getYcomm(int xpos) const { - int xglobal = XGLOBAL(xpos); + int xglobal = getGlobalXIndex(xpos); if (xglobal < ixseps_inner) { return comm_inner; @@ -2507,9 +2513,9 @@ const Field3D BoutMesh::smoothSeparatrix(const Field3D &f) { BoutReal BoutMesh::GlobalX(int jx) const { if (symmetricGlobalX) { // With this definition the boundary sits dx/2 away form the first/last inner points - return (0.5 + XGLOBAL(jx) - (nx - MX) * 0.5) / static_cast(MX); + return (0.5 + getGlobalXIndex(jx) - (nx - MX) * 0.5) / static_cast(MX); } - return static_cast(XGLOBAL(jx)) / static_cast(MX); + return static_cast(getGlobalXIndex(jx)) / static_cast(MX); } BoutReal BoutMesh::GlobalX(BoutReal jx) const { @@ -2527,7 +2533,7 @@ BoutReal BoutMesh::GlobalX(BoutReal jx) const { BoutReal BoutMesh::GlobalY(int jy) const { if (symmetricGlobalY) { - BoutReal yi = YGLOBAL(jy); + BoutReal yi = getGlobalYIndexNoBoundaries(jy); int nycore = (jyseps2_1 - jyseps1_1) + (jyseps2_2 - jyseps1_2); if (yi < ny_inner) { @@ -2539,7 +2545,7 @@ BoutReal BoutMesh::GlobalY(int jy) const { return yi / nycore; } - int ly = YGLOBAL(jy); // global poloidal index across subdomains + int ly = getGlobalYIndexNoBoundaries(jy); // global poloidal index across subdomains int nycore = (jyseps2_1 - jyseps1_1) + (jyseps2_2 - jyseps1_2); if (MYPE_IN_CORE) { diff --git a/src/mesh/impls/bout/boutmesh.hxx b/src/mesh/impls/bout/boutmesh.hxx index 331e230f7c..74a14063a8 100644 --- a/src/mesh/impls/bout/boutmesh.hxx +++ b/src/mesh/impls/bout/boutmesh.hxx @@ -177,8 +177,6 @@ class BoutMesh : public Mesh { int XGLOBAL(int xloc) const override; int YGLOBAL(int yloc) const override; - int XGLOBAL(BoutReal xloc, BoutReal& xglo) const; - int YGLOBAL(BoutReal yloc, BoutReal& yglo) const; int getGlobalXIndex(int xlocal) const override; int getGlobalYIndex(int ylocal) const override; @@ -204,6 +202,10 @@ private: int MYPE_IN_CORE; // 1 if processor in core + int getGlobalYIndexNoBoundaries(int ylocal) const; + int XGLOBAL(BoutReal xloc, BoutReal& xglo) const; + int YGLOBAL(BoutReal yloc, BoutReal& yglo) const; + // Topology int ixseps1, ixseps2, jyseps1_1, jyseps2_1, jyseps1_2, jyseps2_2; int ixseps_inner, ixseps_outer, ixseps_upper, ixseps_lower; diff --git a/tests/integrated/test-globalfield/test_globalfield.cxx b/tests/integrated/test-globalfield/test_globalfield.cxx index 645b48fcd6..1c44023617 100644 --- a/tests/integrated/test-globalfield/test_globalfield.cxx +++ b/tests/integrated/test-globalfield/test_globalfield.cxx @@ -21,8 +21,8 @@ int physics_init(bool UNUSED(restarting)) { for(int x=0;xLocalNx;x++) { for(int y=0;yLocalNy;y++) { - localX(x,y) = mesh->XGLOBAL(x); - localY(x,y) = mesh->YGLOBAL(y); + localX(x,y) = mesh->getGlobalXIndex(x); + localY(x,y) = mesh->getGlobalYIndex(y - mesh->ystart); } } @@ -73,8 +73,8 @@ int physics_init(bool UNUSED(restarting)) { for(int x=0;xLocalNx;x++) for(int y=0;yLocalNy;y++) for(int z=0;zLocalNz;z++) { - localX3D(x,y,z) = mesh->XGLOBAL(x) + z; - localY3D(x,y,z) = mesh->YGLOBAL(y) + z; + localX3D(x,y,z) = mesh->getGlobalXIndex(x) + z; + localY3D(x,y,z) = mesh->getGlobalYIndex(y - mesh->ystart) + z; } // Gather onto one processor (0 by default) diff --git a/tests/integrated/test-petsc_laplace/test_petsc_laplace.cxx b/tests/integrated/test-petsc_laplace/test_petsc_laplace.cxx index f4ec3ea384..dc6f5f4d7d 100644 --- a/tests/integrated/test-petsc_laplace/test_petsc_laplace.cxx +++ b/tests/integrated/test-petsc_laplace/test_petsc_laplace.cxx @@ -61,7 +61,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; f1(jx, jy, jz) = 0. + exp(-(100.*pow(x-p,2)+1.-cos( 2.*PI*(z-q) ))) - 50.*(2.*p*exp(-100.*pow(-p,2))*x + (-p*exp(-100.*pow(-p,2))-(1-p)*exp(-100.*pow(1-p,2)))*pow(x,2) )*exp(-(1.-cos( 2.*PI*(z-q) ))) //make the gradients zero at both x-boundaries @@ -72,7 +72,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; f1(jx, jy, jz) = 0. + exp(-(60.*pow(x-p,2)+1.-cos( 2.*PI*(z-q) ))) - 50.*(2.*p*exp(-60.*pow(-p,2))*x + (-p*exp(-60.*pow(-p,2))-(1-p)*exp(-60.*pow(1-p,2)))*pow(x,2) )*exp(-(1.-cos( 2.*PI*(z-q) ))); //make the gradients zero at both x-boundaries @@ -82,7 +82,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; f1(jx, jy, jz) = 0. + exp(-(60.*pow(x-p,2)+1.-cos( 2.*PI*(z-q) ))) - 50.*(2.*p*exp(-60.*pow(-p,2))*x + (-p*exp(-60.*pow(-p,2))-(1-p)*exp(-60.*pow(1-p,2)))*pow(x,2) )*exp(-(1.-cos( 2.*PI*(z-q) ))); //make the gradients zero at both x-boundaries @@ -97,7 +97,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; d1(jx, jy, jz) = 1. + 0.2*exp(-50.*pow(x-p,2)/4.)*sin(2.*PI*(z-q) * 3.); } @@ -105,7 +105,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; d1(jx, jy, jz) = 1. + 0.2*exp(-50.*pow(x-p,2)/4.)*sin(2.*PI*(z-q) * 3.); // d1(jx, jy, jz) = d1(jx+1, jy, jz); @@ -114,7 +114,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; d1(jx, jy, jz) = 1. + 0.2*exp(-50.*pow(x-p,2)/4.)*sin(2.*PI*(z-q) * 3.); // d1(jx, jy, jz) = d1(jx-1, jy, jz); @@ -126,7 +126,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; c1(jx, jy, jz) = 1. + 0.15*exp(-50.*pow(x-p,2)*2.)*sin(2.*PI*(z-q) * 2.); } @@ -134,7 +134,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; c1(jx, jy, jz) = 1. + 0.15*exp(-50.*pow(x-p,2)*2.)*sin(2.*PI*(z-q) * 2.); // c1(jx, jy, jz) = c1(jx+1, jy, jz); @@ -143,7 +143,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; c1(jx, jy, jz) = 1. + 0.15*exp(-50.*pow(x-p,2)*2.)*sin(2.*PI*(z-q) * 2.); // c1(jx, jy, jz) = c1(jx-1, jy, jz); @@ -155,7 +155,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; a1(jx, jy, jz) = -1. + 0.1*exp(-50.*pow(x-p,2)*2.5)*sin(2.*PI*(z-q) * 7.); } @@ -163,7 +163,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; a1(jx, jy, jz) = -1. + 0.1*exp(-50.*pow(x-p,2)*2.5)*sin(2.*PI*(z-q) * 7.); // a1(jx, jy, jz) = a1(jx+1, jy, jz); @@ -172,7 +172,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; a1(jx, jy, jz) = -1. + 0.1*exp(-50.*pow(x-p,2)*2.5)*sin(2.*PI*(z-q) * 7.); // a1(jx, jy, jz) = a1(jx-1, jy, jz); @@ -389,7 +389,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; f5(jx, jy, jz) = 0. + exp(-(50.*pow(x-p,2)+1.-cos( 2.*PI*(z-q) ))) - 50.*(2.*p*exp(-50.*pow(-p,2))*x + (-p*exp(-50.*pow(-p,2))-(1-p)*exp(-50.*pow(1-p,2)))*pow(x,2) )*exp(-(1.-cos( 2.*PI*(z-q) ))) //make the gradients zero at both x-boundaries @@ -399,7 +399,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; f5(jx, jy, jz) = 0. + exp(-(50.*pow(x-p,2)+1.-cos( 2.*PI*(z-q) ))) - 50.*(2.*p*exp(-50.*pow(-p,2))*x + (-p*exp(-50.*pow(-p,2))-(1-p)*exp(-50.*pow(1-p,2)))*pow(x,2) )*exp(-(1.-cos( 2.*PI*(z-q) ))); //make the gradients zero at both x-boundaries @@ -408,7 +408,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; f5(jx, jy, jz) = 0. + exp(-(50.*pow(x-p,2)+1.-cos( 2.*PI*(z-q) ))) - 50.*(2.*p*exp(-50.*pow(-p,2))*x + (-p*exp(-50.*pow(-p,2))-(1-p)*exp(-50.*pow(1-p,2)))*pow(x,2) )*exp(-(1.-cos( 2.*PI*(z-q) ))); //make the gradients zero at both x-boundaries @@ -420,7 +420,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; d5(jx, jy, jz) = 1. + p*cos(2.*PI*x)*sin(2.*PI*(z-q) * 3.); } @@ -428,7 +428,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; d5(jx, jy, jz) = 1. + p*cos(2.*PI*x)*sin(2.*PI*(z-q) * 3.); } @@ -436,7 +436,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; d5(jx, jy, jz) = 1. + p*cos(2.*PI*x)*sin(2.*PI*(z-q) * 3.); } @@ -447,7 +447,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; c5(jx, jy, jz) = 1. + p*cos(2.*PI*x*5)*sin(2.*PI*(z-q) * 2.); } @@ -455,7 +455,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; c5(jx, jy, jz) = 1. + p*cos(2.*PI*x*5)*sin(2.*PI*(z-q) * 2.); } @@ -463,7 +463,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; c5(jx, jy, jz) = 1. + p*cos(2.*PI*x*5)*sin(2.*PI*(z-q) * 2.); } @@ -474,7 +474,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; a5(jx, jy, jz) = -1. + p*cos(2.*PI*x*2.)*sin(2.*PI*(z-q) * 7.); } @@ -482,7 +482,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; a5(jx, jy, jz) = -1. + p*cos(2.*PI*x*2.)*sin(2.*PI*(z-q) * 7.); } @@ -490,7 +490,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; a5(jx, jy, jz) = -1. + p*cos(2.*PI*x*2.)*sin(2.*PI*(z-q) * 7.); } diff --git a/tests/integrated/test-petsc_laplace_MAST-grid/test_petsc_laplace_MAST_grid.cxx b/tests/integrated/test-petsc_laplace_MAST-grid/test_petsc_laplace_MAST_grid.cxx index a5646c29fb..9cca840d08 100644 --- a/tests/integrated/test-petsc_laplace_MAST-grid/test_petsc_laplace_MAST_grid.cxx +++ b/tests/integrated/test-petsc_laplace_MAST-grid/test_petsc_laplace_MAST_grid.cxx @@ -61,7 +61,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; f1(jx, jy, jz) = 0. + exp(-(50.*pow(x-p,2)+1.-cos( 2.*PI*(z-q) ))) - 50.*(2.*p*exp(-50.*pow(-p,2))*x + (-p*exp(-50.*pow(-p,2))-(1-p)*exp(-50.*pow(1-p,2)))*pow(x,2) )*exp(-(1.-cos( 2.*PI*(z-q) ))) //make the gradients zero at both x-boundaries @@ -71,7 +71,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; f1(jx, jy, jz) = 0. + exp(-(50.*pow(x-p,2)+1.-cos( 2.*PI*(z-q) ))) - 50.*(2.*p*exp(-50.*pow(-p,2))*x + (-p*exp(-50.*pow(-p,2))-(1-p)*exp(-50.*pow(1-p,2)))*pow(x,2) )*exp(-(1.-cos( 2.*PI*(z-q) ))); //make the gradients zero at both x-boundaries @@ -80,7 +80,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; f1(jx, jy, jz) = 0. + exp(-(50.*pow(x-p,2)+1.-cos( 2.*PI*(z-q) ))) - 50.*(2.*p*exp(-50.*pow(-p,2))*x + (-p*exp(-50.*pow(-p,2))-(1-p)*exp(-50.*pow(1-p,2)))*pow(x,2) )*exp(-(1.-cos( 2.*PI*(z-q) ))); //make the gradients zero at both x-boundaries @@ -92,7 +92,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; d1(jx, jy, jz) = 1.e-7*(1. + 0.2*exp(-50.*pow(x-p,2)/4.)*sin(2.*PI*(z-q) * 3.)); } @@ -100,7 +100,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; d1(jx, jy, jz) = 1.e-7*(1. + 0.2*exp(-50.*pow(x-p,2)/4.)*sin(2.*PI*(z-q) * 3.)); } @@ -108,7 +108,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; d1(jx, jy, jz) = 1.e-7*(1. + 0.2*exp(-50.*pow(x-p,2)/4.)*sin(2.*PI*(z-q) * 3.)); } @@ -119,7 +119,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; c1(jx, jy, jz) = 1. + 1.e-6*0.15*exp(-50.*pow(x-p,2)*2.)*sin(2.*PI*(z-q) * 2.); } @@ -127,7 +127,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; c1(jx, jy, jz) = 1. + 1.e-6*0.15*exp(-50.*pow(x-p,2)*2.)*sin(2.*PI*(z-q) * 2.); } @@ -135,7 +135,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; c1(jx, jy, jz) = 1. + 1.e-6*0.15*exp(-50.*pow(x-p,2)*2.)*sin(2.*PI*(z-q) * 2.); } @@ -146,7 +146,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; a1(jx, jy, jz) = -1. + 0.1*exp(-50.*pow(x-p,2)*2.5)*sin(2.*PI*(z-q) * 7.); } @@ -154,7 +154,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; a1(jx, jy, jz) = -1. + 0.1*exp(-50.*pow(x-p,2)*2.5)*sin(2.*PI*(z-q) * 7.); } @@ -162,7 +162,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; a1(jx, jy, jz) = -1. + 0.1*exp(-50.*pow(x-p,2)*2.5)*sin(2.*PI*(z-q) * 7.); } @@ -369,7 +369,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; f5(jx, jy, jz) = 0. + exp(-(50.*pow(x-p,2)+1.-cos( 2.*PI*(z-q) ))) - 50.*(2.*p*exp(-50.*pow(-p,2))*x + (-p*exp(-50.*pow(-p,2))-(1-p)*exp(-50.*pow(1-p,2)))*pow(x,2) )*exp(-(1.-cos( 2.*PI*(z-q) ))) //make the gradients zero at both x-boundaries @@ -379,7 +379,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; f5(jx, jy, jz) = 0. + exp(-(50.*pow(x-p,2)+1.-cos( 2.*PI*(z-q) ))) - 50.*(2.*p*exp(-50.*pow(-p,2))*x + (-p*exp(-50.*pow(-p,2))-(1-p)*exp(-50.*pow(1-p,2)))*pow(x,2) )*exp(-(1.-cos( 2.*PI*(z-q) ))); //make the gradients zero at both x-boundaries @@ -388,7 +388,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; f5(jx, jy, jz) = 0. + exp(-(50.*pow(x-p,2)+1.-cos( 2.*PI*(z-q) ))) - 50.*(2.*p*exp(-50.*pow(-p,2))*x + (-p*exp(-50.*pow(-p,2))-(1-p)*exp(-50.*pow(1-p,2)))*pow(x,2) )*exp(-(1.-cos( 2.*PI*(z-q) ))); //make the gradients zero at both x-boundaries @@ -400,7 +400,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; d5(jx, jy, jz) = 1.e-7*(1. + p*cos(2.*PI*x)*sin(2.*PI*(z-q) * 3.)); } @@ -408,7 +408,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; d5(jx, jy, jz) = 1.e-7*(1. + p*cos(2.*PI*x)*sin(2.*PI*(z-q) * 3.)); } @@ -416,7 +416,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; d5(jx, jy, jz) = 1.e-7*(1. + p*cos(2.*PI*x)*sin(2.*PI*(z-q) * 3.)); } @@ -427,7 +427,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; c5(jx, jy, jz) = 1. + 1.e-6*p*cos(2.*PI*x*5)*sin(2.*PI*(z-q) * 2.); } @@ -435,7 +435,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; c5(jx, jy, jz) = 1. + 1.e-6*p*cos(2.*PI*x*5)*sin(2.*PI*(z-q) * 2.); } @@ -443,7 +443,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; c5(jx, jy, jz) = 1. + 1.e-6*p*cos(2.*PI*x*5)*sin(2.*PI*(z-q) * 2.); } @@ -454,7 +454,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart; jx<=mesh->xend; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; a5(jx, jy, jz) = -1. + p*cos(2.*PI*x*2.)*sin(2.*PI*(z-q) * 7.); } @@ -462,7 +462,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xstart-1; jx>=0; jx--) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; a5(jx, jy, jz) = -1. + p*cos(2.*PI*x*2.)*sin(2.*PI*(z-q) * 7.); } @@ -470,7 +470,7 @@ int main(int argc, char** argv) { for (int jx=mesh->xend+1; jxLocalNx; jx++) for (int jy=0; jyLocalNy; jy++) for (int jz=0; jzLocalNz; jz++) { - BoutReal x = BoutReal(mesh->XGLOBAL(jx)-mesh->xstart)/nx; + BoutReal x = BoutReal(mesh->getGlobalXIndex(jx)-mesh->xstart)/nx; BoutReal z = BoutReal(jz)/nz; a5(jx, jy, jz) = -1. + p*cos(2.*PI*x*2.)*sin(2.*PI*(z-q) * 7.); } From cb4fd1804c1e1297f1b3a6652013dc7ce5be31ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Sat, 27 Jul 2019 13:38:55 +0100 Subject: [PATCH 1697/1783] Update performance/iterator-offsets example --- examples/performance/iterator-offsets/iterator-offsets.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/performance/iterator-offsets/iterator-offsets.cxx b/examples/performance/iterator-offsets/iterator-offsets.cxx index abe0c34f66..81cbd7e6b3 100644 --- a/examples/performance/iterator-offsets/iterator-offsets.cxx +++ b/examples/performance/iterator-offsets/iterator-offsets.cxx @@ -93,14 +93,14 @@ int main(int argc, char **argv) { auto deriv = DerivativeStore::getInstance().getStandardDerivative("C2",DIRECTION::Y, STAGGER::None); ITERATOR_TEST_BLOCK( "DerivativeStore without fetching", - deriv(a, result, RGN_NOY); + deriv(a, result, "RGN_NOY"); ); }; ITERATOR_TEST_BLOCK( "DerivativeStore with fetch", auto deriv = DerivativeStore::getInstance().getStandardDerivative("C2",DIRECTION::Y, STAGGER::None); - deriv(a, result, RGN_NOY); + deriv(a, result, "RGN_NOY"); ); ITERATOR_TEST_BLOCK( From 6472fb4eec6aad89d81e0a6e65464318e9385d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Tue, 30 Jul 2019 14:34:46 +0100 Subject: [PATCH 1698/1783] Don't ignore $MPIRUN --- tests/integrated/test-coordinates-initialization/runtest | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/integrated/test-coordinates-initialization/runtest b/tests/integrated/test-coordinates-initialization/runtest index 759f4526f2..0c56268962 100755 --- a/tests/integrated/test-coordinates-initialization/runtest +++ b/tests/integrated/test-coordinates-initialization/runtest @@ -2,8 +2,9 @@ make || exit +test -z $MPIRUN && MPIRUN=mpirun # Kill the test after 3 seconds, if it hasn't already exited -OMP_NUM_THREADS=1 mpirun -n 3 timeout 3s ./test-coordinates-initialization +OMP_NUM_THREADS=1 $MPIRUN -n 3 timeout 3s ./test-coordinates-initialization e=$? From 4066c7804636c751eebbf08f0a06d83b5e87a558 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 31 Jul 2019 13:36:29 +0100 Subject: [PATCH 1699/1783] More informative error messages when dump/restart files fail to open --- src/fileio/datafile.cxx | 135 ++++++++++++++++++++++++++++------- src/physics/physicsmodel.cxx | 4 +- 2 files changed, 110 insertions(+), 29 deletions(-) diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 1a6e4fd46b..d09458be7b 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -168,7 +168,8 @@ bool Datafile::openr(const char *format, ...) { if(!openclose) { // Open the file now. Otherwise defer until later if(!file->openr(filename, BoutComm::rank())) - throw BoutException("Datafile::open: Failed to open file!"); + throw BoutException("Datafile::open: Failed to open file %s for reading!", + filename); } writable = false; @@ -209,7 +210,7 @@ bool Datafile::openw(const char *format, ...) { appending = false; // Open the file if(!file->openw(filename, BoutComm::rank(), appending)) - throw BoutException("Datafile::open: Failed to open file!"); + throw BoutException("Datafile::open: Failed to open file %s for writing!", filename); appending = true; first_time = true; // newly opened file, so write attributes when variables are first written @@ -317,7 +318,8 @@ bool Datafile::opena(const char *format, ...) { appending = true; // Open the file if(!file->openw(filename, BoutComm::rank(), true)) - throw BoutException("Datafile::open: Failed to open file!"); + throw BoutException("Datafile::open: Failed to open file %s for appending!", + filename); first_time = true; // newly opened file, so write attributes when variables are first written @@ -447,8 +449,15 @@ void Datafile::add(int &i, const char *name, bool save_repeat) { // Check filename has been set if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, BoutComm::rank(), appending)) - throw BoutException("Datafile::add: Failed to open file!"); + if(!file->openw(filename, BoutComm::rank(), appending)) { + if (appending) { + throw BoutException("Datafile::add: Failed to open file %s for appending!", + filename); + } else { + throw BoutException("Datafile::add: Failed to open file %s for writing!", + filename); + } + } appending = true; } @@ -494,8 +503,15 @@ void Datafile::add(BoutReal &r, const char *name, bool save_repeat) { // Open the file if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, BoutComm::rank(), appending)) - throw BoutException("Datafile::add: Failed to open file!"); + if(!file->openw(filename, BoutComm::rank(), appending)) { + if (appending) { + throw BoutException("Datafile::add: Failed to open file %s for appending!", + filename); + } else { + throw BoutException("Datafile::add: Failed to open file %s for writing!", + filename); + } + } appending = true; } @@ -544,8 +560,15 @@ void Datafile::add(Field2D &f, const char *name, bool save_repeat) { // Open the file if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, BoutComm::rank(), appending)) - throw BoutException("Datafile::add: Failed to open file!"); + if(!file->openw(filename, BoutComm::rank(), appending)) { + if (appending) { + throw BoutException("Datafile::add: Failed to open file %s for appending!", + filename); + } else { + throw BoutException("Datafile::add: Failed to open file %s for writing!", + filename); + } + } appending = true; } @@ -594,8 +617,15 @@ void Datafile::add(Field3D &f, const char *name, bool save_repeat) { // Open the file if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, BoutComm::rank(), appending)) - throw BoutException("Datafile::add: Failed to open file!"); + if(!file->openw(filename, BoutComm::rank(), appending)) { + if (appending) { + throw BoutException("Datafile::add: Failed to open file %s for appending!", + filename); + } else { + throw BoutException("Datafile::add: Failed to open file %s for writing!", + filename); + } + } appending = true; } @@ -644,8 +674,15 @@ void Datafile::add(FieldPerp &f, const char *name, bool save_repeat) { // Open the file if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, BoutComm::rank(), appending)) - throw BoutException("Datafile::add: Failed to open file!"); + if(!file->openw(filename, BoutComm::rank(), appending)) { + if (appending) { + throw BoutException("Datafile::add: Failed to open file %s for appending!", + filename); + } else { + throw BoutException("Datafile::add: Failed to open file %s for writing!", + filename); + } + } appending = true; } @@ -694,8 +731,15 @@ void Datafile::add(Vector2D &f, const char *name, bool save_repeat) { // Open the file if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, BoutComm::rank(), appending)) - throw BoutException("Datafile::add: Failed to open file!"); + if(!file->openw(filename, BoutComm::rank(), appending)) { + if (appending) { + throw BoutException("Datafile::add: Failed to open file %s for appending!", + filename); + } else { + throw BoutException("Datafile::add: Failed to open file %s for writing!", + filename); + } + } appending = true; } @@ -750,8 +794,15 @@ void Datafile::add(Vector3D &f, const char *name, bool save_repeat) { // Open the file if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, BoutComm::rank(), appending)) - throw BoutException("Datafile::add: Failed to open file!"); + if(!file->openw(filename, BoutComm::rank(), appending)) { + if (appending) { + throw BoutException("Datafile::add: Failed to open file %s for appending!", + filename); + } else { + throw BoutException("Datafile::add: Failed to open file %s for writing!", + filename); + } + } appending = true; } @@ -783,8 +834,10 @@ bool Datafile::read() { if(openclose) { // Open the file - if(!file->openr(filename, BoutComm::rank())) - throw BoutException("Datafile::read: Failed to open file!"); + if(!file->openr(filename, BoutComm::rank())) { + throw BoutException("Datafile::read: Failed to open file %s for reading!", + filename); + } } if(!file->is_valid()) @@ -904,8 +957,15 @@ bool Datafile::write() { if(openclose && (flushFrequencyCounter % flushFrequency == 0)) { // Open the file - if(!file->openw(filename, BoutComm::rank(), appending)) - throw BoutException("Datafile::write: Failed to open file!"); + if(!file->openw(filename, BoutComm::rank(), appending)) { + if (appending) { + throw BoutException("Datafile::add: Failed to open file %s for appending!", + filename); + } else { + throw BoutException("Datafile::add: Failed to open file %s for writing!", + filename); + } + } appending = true; flushFrequencyCounter = 0; } @@ -1068,8 +1128,15 @@ void Datafile::setAttribute(const std::string &varname, const std::string &attrn if(openclose && (flushFrequencyCounter % flushFrequency == 0)) { // Open the file - if(!file->openw(filename, BoutComm::rank(), appending)) - throw BoutException("Datafile::write: Failed to open file!"); + if(!file->openw(filename, BoutComm::rank(), appending)) { + if (appending) { + throw BoutException("Datafile::add: Failed to open file %s for appending!", + filename); + } else { + throw BoutException("Datafile::add: Failed to open file %s for writing!", + filename); + } + } appending = true; flushFrequencyCounter = 0; } @@ -1095,8 +1162,15 @@ void Datafile::setAttribute(const std::string &varname, const std::string &attrn if(openclose && (flushFrequencyCounter % flushFrequency == 0)) { // Open the file - if(!file->openw(filename, BoutComm::rank(), appending)) - throw BoutException("Datafile::write: Failed to open file!"); + if(!file->openw(filename, BoutComm::rank(), appending)) { + if (appending) { + throw BoutException("Datafile::add: Failed to open file %s for appending!", + filename); + } else { + throw BoutException("Datafile::add: Failed to open file %s for writing!", + filename); + } + } appending = true; flushFrequencyCounter = 0; } @@ -1122,8 +1196,15 @@ void Datafile::setAttribute(const std::string &varname, const std::string &attrn if(openclose && (flushFrequencyCounter % flushFrequency == 0)) { // Open the file - if(!file->openw(filename, BoutComm::rank(), appending)) - throw BoutException("Datafile::write: Failed to open file!"); + if(!file->openw(filename, BoutComm::rank(), appending)) { + if (appending) { + throw BoutException("Datafile::add: Failed to open file %s for appending!", + filename); + } else { + throw BoutException("Datafile::add: Failed to open file %s for writing!", + filename); + } + } appending = true; flushFrequencyCounter = 0; } diff --git a/src/physics/physicsmodel.cxx b/src/physics/physicsmodel.cxx index abe0190d46..0b12c1670e 100644 --- a/src/physics/physicsmodel.cxx +++ b/src/physics/physicsmodel.cxx @@ -117,9 +117,9 @@ int PhysicsModel::postInit(bool restarting) { /// Load restart file if (!restart.openr("%s",filename.c_str())) - throw BoutException("Error: Could not open restart file\n"); + throw BoutException("Error: Could not open restart file %s\n", filename.c_str()); if (!restart.read()) - throw BoutException("Error: Could not read restart file\n"); + throw BoutException("Error: Could not read restart file %s\n", filename.c_str()); restart.close(); } From 1b3bb302ed0434e95e995d9474a2c404258529e2 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 31 Jul 2019 13:50:50 +0100 Subject: [PATCH 1700/1783] Handle exceptions when opening files in Ncxx4 If 'new NcFile(...)' throws, then catch the exception and return 'false' so we use the standard error handling in DataFile, as exceptions from the netCDF library interface are not very informative. --- src/fileio/impls/netcdf4/ncxx4.cxx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/fileio/impls/netcdf4/ncxx4.cxx b/src/fileio/impls/netcdf4/ncxx4.cxx index 0537a999e0..8e6598dc21 100644 --- a/src/fileio/impls/netcdf4/ncxx4.cxx +++ b/src/fileio/impls/netcdf4/ncxx4.cxx @@ -83,7 +83,11 @@ bool Ncxx4::openr(const char *name) { Ncxx4::close(); } - dataFile = new NcFile(name, NcFile::read); + try { + dataFile = new NcFile(name, NcFile::read); + } catch (netCDF::exceptions::NcException&) { + return false; + } if(dataFile->isNull()) { delete dataFile; @@ -138,7 +142,11 @@ bool Ncxx4::openw(const char *name, bool append) { close(); if(append) { - dataFile = new NcFile(name, NcFile::write); + try { + dataFile = new NcFile(name, NcFile::write); + } catch (netCDF::exceptions::NcException&) { + return false; + } if(dataFile->isNull()) { delete dataFile; @@ -193,7 +201,11 @@ bool Ncxx4::openw(const char *name, bool append) { default_rec = tDim.getSize(); }else { - dataFile = new NcFile(name, NcFile::replace); + try { + dataFile = new NcFile(name, NcFile::replace); + } catch (netCDF::exceptions::NcException&) { + return false; + } if(dataFile->isNull()) { delete dataFile; From 01f4eceab2815a347ec3abaff340a47bfeaa55d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 2 Aug 2019 09:11:29 +0100 Subject: [PATCH 1701/1783] remove empty script --- tools/tokamak_grids/pyGridGen/efit2grid.py | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 tools/tokamak_grids/pyGridGen/efit2grid.py diff --git a/tools/tokamak_grids/pyGridGen/efit2grid.py b/tools/tokamak_grids/pyGridGen/efit2grid.py deleted file mode 100644 index 50aa1d17da..0000000000 --- a/tools/tokamak_grids/pyGridGen/efit2grid.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python - -""" -@brief Generate a grid from EFIT aeqdsk and geqdsk files - -""" - -# Read grid files - -# Generate grid - - - From 6fffa5d50016d5917433e2c9132d5c42e43564f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 2 Aug 2019 09:12:49 +0100 Subject: [PATCH 1702/1783] Always call python3 via env --- tools/pylib/_boutcore_build/debug.py | 2 +- tools/pylib/_boutcore_build/geninput.py | 2 +- tools/tokamak_grids/cyclone/cyclone.py | 2 +- tools/tokamak_grids/pyGridGen/aeqdsk.py | 2 +- tools/tokamak_grids/pyGridGen/geqdsk.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/pylib/_boutcore_build/debug.py b/tools/pylib/_boutcore_build/debug.py index a65ed74a0a..8eb8dea3ed 100755 --- a/tools/pylib/_boutcore_build/debug.py +++ b/tools/pylib/_boutcore_build/debug.py @@ -1,4 +1,4 @@ -#!/bin/python3 +#!/usr/bin/env python3 print("Trying import") import debug diff --git a/tools/pylib/_boutcore_build/geninput.py b/tools/pylib/_boutcore_build/geninput.py index c08814480b..7f28d5e650 100644 --- a/tools/pylib/_boutcore_build/geninput.py +++ b/tools/pylib/_boutcore_build/geninput.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import boutcore as bc import numpy as np diff --git a/tools/tokamak_grids/cyclone/cyclone.py b/tools/tokamak_grids/cyclone/cyclone.py index bb2d432fae..519b93dae8 100755 --- a/tools/tokamak_grids/cyclone/cyclone.py +++ b/tools/tokamak_grids/cyclone/cyclone.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from __future__ import print_function from __future__ import division diff --git a/tools/tokamak_grids/pyGridGen/aeqdsk.py b/tools/tokamak_grids/pyGridGen/aeqdsk.py index 9515f40feb..bb7d009b83 100644 --- a/tools/tokamak_grids/pyGridGen/aeqdsk.py +++ b/tools/tokamak_grids/pyGridGen/aeqdsk.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from __future__ import print_function from builtins import str diff --git a/tools/tokamak_grids/pyGridGen/geqdsk.py b/tools/tokamak_grids/pyGridGen/geqdsk.py index 6fc4d0767c..e38c30cfa2 100755 --- a/tools/tokamak_grids/pyGridGen/geqdsk.py +++ b/tools/tokamak_grids/pyGridGen/geqdsk.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from __future__ import print_function from __future__ import division From ad8fc79c1314175e676e2a4885ecae96cbb8d006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 2 Aug 2019 09:15:17 +0100 Subject: [PATCH 1703/1783] Cleanup imports The try: ... catch: is bad, as it prints the error to stdout, rather then stderr. Besides, the try ... catch provides no additional value. --- tools/tokamak_grids/elite/elite2nc | 16 +++------------- tools/tokamak_grids/gato/gato2nc | 28 ++++------------------------ 2 files changed, 7 insertions(+), 37 deletions(-) diff --git a/tools/tokamak_grids/elite/elite2nc b/tools/tokamak_grids/elite/elite2nc index da92144f90..aa181877fb 100755 --- a/tools/tokamak_grids/elite/elite2nc +++ b/tools/tokamak_grids/elite/elite2nc @@ -1,21 +1,11 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Convert an ELITE .eqin file to a NetCDF equilibrium file from __future__ import print_function from builtins import next -try: - import sys - -except ImportError: - print("ERROR: sys module not available") - raise SystemExit - -try: - import numpy as np -except ImportError: - print("ERROR: NumPy module not available") - raise SystemExit +import sys +import numpy as np # Check command-line arguments diff --git a/tools/tokamak_grids/gato/gato2nc b/tools/tokamak_grids/gato/gato2nc index 0deffc3c26..637d96e1de 100755 --- a/tools/tokamak_grids/gato/gato2nc +++ b/tools/tokamak_grids/gato/gato2nc @@ -12,30 +12,10 @@ from __future__ import division from builtins import str from builtins import next from past.utils import old_div -try: - import sys - -except ImportError: - print("ERROR: sys module not available") - raise SystemExit - -try: - import numpy as np -except ImportError: - print("ERROR: NumPy module not available") - raise SystemExit - -try: - import re -except: - print("ERROR: Regular expression module 're' not available") - raise SystemExit - -try: - from boututils.datafile import DataFile -except ImportError: - print("ERROR: Missing boututils.Datafile. Add pylib to your PYTHONPATH") - raise SystemExit +import sys +import numpy as np +import re +from boututils.datafile import DataFile # Check command-line arguments From d2a382ee965b3bb8c25cd973cc2b97264151435a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Schw=C3=B6rer?= Date: Fri, 2 Aug 2019 09:18:27 +0100 Subject: [PATCH 1704/1783] always call python3 --- tools/tokamak_grids/gato/gato2nc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/tokamak_grids/gato/gato2nc b/tools/tokamak_grids/gato/gato2nc index 637d96e1de..f7b40cf378 100755 --- a/tools/tokamak_grids/gato/gato2nc +++ b/tools/tokamak_grids/gato/gato2nc @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Convert a GATO file to a NetCDF equilibrium file # This code should be more resiliant than the C From 24385e19ead5079784b6b8488c2f9128e04e8b6d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 4 Aug 2019 11:13:31 +0100 Subject: [PATCH 1705/1783] Support bool variables in file I/O Allow bool variables to be added to or read from file. bools are stored in the files as ints, and converted when reading/writing. --- include/bout/mesh.hxx | 9 ++ include/datafile.hxx | 2 + manual/sphinx/developer_docs/file_io.rst | 1 + src/fileio/datafile.cxx | 114 +++++++++++++++++- src/mesh/mesh.cxx | 15 +++ .../test-io/data/benchmark.out.0.nc | Bin 138486 -> 145800 bytes tests/integrated/test-io/runtest | 4 +- tests/integrated/test-io/test_io.cxx | 5 + tests/integrated/test-io/test_io.grd.nc | Bin 21460 -> 21732 bytes 9 files changed, 144 insertions(+), 6 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index db2dd7cc4c..08a3ca2c97 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -149,6 +149,15 @@ class Mesh { /// @returns zero if successful, non-zero on failure int get(BoutReal& rval, const std::string& name, BoutReal def=0.0); + /// Get a bool from the input source + /// + /// @param[out] bval The value will be put into this variable + /// @param[in] name The name of the variable to read + /// @param[in] def The default value if not found + /// + /// @returns zero if successful, non-zero on failure + int get(bool &bval, const std::string &name, bool def=false); + /// Get a Field2D from the input source /// including communicating guard cells /// diff --git a/include/datafile.hxx b/include/datafile.hxx index 528b6708de..084955a773 100644 --- a/include/datafile.hxx +++ b/include/datafile.hxx @@ -70,6 +70,7 @@ class Datafile { } void add(int &i, const char *name, bool save_repeat = false); void add(BoutReal &r, const char *name, bool save_repeat = false); + void add(bool &b, const char* name, bool save_repeat = false); void add(Field2D &f, const char *name, bool save_repeat = false); void add(Field3D &f, const char *name, bool save_repeat = false); void add(FieldPerp &f, const char *name, bool save_repeat = false); @@ -126,6 +127,7 @@ class Datafile { // one set per variable type std::vector> int_arr; std::vector> BoutReal_arr; + std::vector> bool_arr; std::vector> f2d_arr; std::vector> f3d_arr; std::vector> fperp_arr; diff --git a/manual/sphinx/developer_docs/file_io.rst b/manual/sphinx/developer_docs/file_io.rst index 908aee349c..d8f9925714 100644 --- a/manual/sphinx/developer_docs/file_io.rst +++ b/manual/sphinx/developer_docs/file_io.rst @@ -56,6 +56,7 @@ interface. } void add(int &i, const char *name, bool save_repeat = false); void add(BoutReal &r, const char *name, bool save_repeat = false); + void add(bool &b, const char* name, bool save_repeat = false); void add(Field2D &f, const char *name, bool save_repeat = false); void add(Field3D &f, const char *name, bool save_repeat = false); void add(FieldPerp &f, const char *name, bool save_repeat = false); diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 1a6e4fd46b..7147d2d42e 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -80,8 +80,9 @@ Datafile::Datafile(Datafile &&other) noexcept flushFrequency(other.flushFrequency), file(std::move(other.file)), writable(other.writable), appending(other.appending), first_time(other.first_time), int_arr(std::move(other.int_arr)), BoutReal_arr(std::move(other.BoutReal_arr)), - f2d_arr(std::move(other.f2d_arr)), f3d_arr(std::move(other.f3d_arr)), - v2d_arr(std::move(other.v2d_arr)), v3d_arr(std::move(other.v3d_arr)) { + bool_arr(std::move(other.bool_arr)), f2d_arr(std::move(other.f2d_arr)), + f3d_arr(std::move(other.f3d_arr)), v2d_arr(std::move(other.v2d_arr)), + v3d_arr(std::move(other.v3d_arr)) { filenamelen = other.filenamelen; filename = other.filename; other.filenamelen = 0; @@ -95,8 +96,8 @@ Datafile::Datafile(const Datafile &other) : enabled(other.enabled), shiftOutput(other.shiftOutput), shiftInput(other.shiftInput), flushFrequencyCounter(other.flushFrequencyCounter), flushFrequency(other.flushFrequency), file(nullptr), writable(other.writable), appending(other.appending), first_time(other.first_time), int_arr(other.int_arr), BoutReal_arr(other.BoutReal_arr), - f2d_arr(other.f2d_arr), f3d_arr(other.f3d_arr), v2d_arr(other.v2d_arr), - v3d_arr(other.v3d_arr) + bool_arr(other.bool_arr), f2d_arr(other.f2d_arr), f3d_arr(other.f3d_arr), + v2d_arr(other.v2d_arr), v3d_arr(other.v3d_arr) { filenamelen=other.filenamelen; filename=new char[filenamelen]; @@ -123,6 +124,7 @@ Datafile& Datafile::operator=(Datafile &&rhs) noexcept { first_time = rhs.first_time; int_arr = std::move(rhs.int_arr); BoutReal_arr = std::move(rhs.BoutReal_arr); + bool_arr = std::move(rhs.bool_arr); f2d_arr = std::move(rhs.f2d_arr); f3d_arr = std::move(rhs.f3d_arr); v2d_arr = std::move(rhs.v2d_arr); @@ -229,6 +231,13 @@ bool Datafile::openw(const char *format, ...) { } } + // Add bools + for(const auto& var : bool_arr) { + if (!file->addVarInt(var.name, var.save_repeat)) { + throw BoutException("Failed to add bool variable %s to Datafile", var.name.c_str()); + } + } + // Add 2D fields for (const auto& var : f2d_arr) { if (!file->addVarField2D(var.name, var.save_repeat)) { @@ -336,6 +345,13 @@ bool Datafile::opena(const char *format, ...) { } } + // Add bools + for(const auto& var : bool_arr) { + if (!file->addVarInt(var.name, var.save_repeat)) { + throw BoutException("Failed to add bool variable %s to Datafile", var.name.c_str()); + } + } + // Add 2D fields for (const auto& var : f2d_arr) { if (!file->addVarField2D(var.name, var.save_repeat)) { @@ -516,6 +532,54 @@ void Datafile::add(BoutReal &r, const char *name, bool save_repeat) { } } +void Datafile::add(bool &b, const char *name, bool save_repeat) { + TRACE("DataFile::add(bool)"); + if (!enabled) + return; + if (varAdded(name)) { + // Check if it's the same variable + if (&b == varPtr(name)) { + output_warn.write("WARNING: variable '%s' added again to Datafile\n", name); + } else { + throw BoutException("Variable with name '%s' already added to Datafile", name); + } + } + + VarStr d; + + d.ptr = &b; + d.name = name; + d.save_repeat = save_repeat; + d.covar = false; + + bool_arr.push_back(d); + + if (writable) { + // Otherwise will add variables when Datafile is opened for writing/appending + if (openclose) { + // Open the file + // Check filename has been set + if (strcmp(filename, "") == 0) + throw BoutException("Datafile::add: Filename has not been set"); + if(!file->openw(filename, BoutComm::rank(), appending)) + throw BoutException("Datafile::add: Failed to open file!"); + appending = true; + } + + if(!file->is_valid()) + throw BoutException("Datafile::add: File is not valid!"); + + // Add variable to file + if (!file->addVarInt(name, save_repeat)) { + throw BoutException("Failed to add bool variable %s to Datafile", name); + } + + if(openclose) { + file->close(); + } + } +} + void Datafile::add(Field2D &f, const char *name, bool save_repeat) { TRACE("DataFile::add(Field2D)"); if (!enabled) @@ -838,6 +902,31 @@ bool Datafile::read() { } } + // Read bools + for(const auto& var : bool_arr) { + int var_as_int = 0; + if(var.save_repeat) { + if(!file->read_rec(&var_as_int, var.name.c_str())) { + if(!init_missing) { + throw BoutException("Missing data for %s in input. Set init_missing=true to set to false.", var.name.c_str()); + } + output_warn.write("\tWARNING: Could not read bool %s. Setting to false\n", var.name.c_str()); + *(var.ptr) = false; + continue; + } + } else { + if(!file->read(&var_as_int, var.name.c_str())) { + if(!init_missing) { + throw BoutException("Missing data for %s in input. Set init_missing=true to set to false.", var.name.c_str()); + } + output_warn.write("\tWARNING: Could not read bool %s. Setting to false\n", var.name.c_str()); + *(var.ptr) = false; + continue; + } + } + *var.ptr = bool(var_as_int); + } + // Read 2D fields for(const auto& var : f2d_arr) { read_f2d(var.name, var.ptr, var.save_repeat); @@ -968,6 +1057,12 @@ bool Datafile::write() { write_real(var.name, var.ptr, var.save_repeat); } + // Write bools + for(const auto& var : bool_arr) { + int var_as_int = int(*var.ptr); + write_int(var.name, &var_as_int, var.save_repeat); + } + // Write 2D fields for (const auto& var : f2d_arr) { write_f2d(var.name, var.ptr, var.save_repeat); @@ -1360,6 +1455,11 @@ bool Datafile::varAdded(const std::string &name) { return true; } + for(const auto& var : bool_arr ) { + if(name == var.name) + return true; + } + for(const auto& var : f2d_arr ) { if(name == var.name) return true; @@ -1395,6 +1495,12 @@ void *Datafile::varPtr(const std::string &name) { } } + for (const auto &var : bool_arr) { + if (name == var.name) { + return static_cast(var.ptr); + } + } + for (const auto &var : f2d_arr) { if (name == var.name) { return static_cast(var.ptr); diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index ae6f2f275d..29c21620a4 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -88,6 +88,21 @@ int Mesh::get(BoutReal& rval, const std::string& name, BoutReal def) { return !source->get(this, rval, name, def); } +int Mesh::get(bool &bval, const std::string &name, bool def) { + TRACE("Mesh::get(bval, %s)", name.c_str()); + + if (source == nullptr) { + warn_default_used(def, name); + bval = def; + return true; + } + + int bval_as_int = 0; + bool success = source->get(this, bval_as_int, name, def); + bval = bool(bval_as_int); + return !success; +} + int Mesh::get(Field2D &var, const std::string &name, BoutReal def) { TRACE("Loading 2D field: Mesh::get(Field2D, %s)", name.c_str()); diff --git a/tests/integrated/test-io/data/benchmark.out.0.nc b/tests/integrated/test-io/data/benchmark.out.0.nc index 0f1d7022f68838691d3dc0084c8b4ccc59f7a88c..35e74423c4020be025fca00476965e6284481f2b 100644 GIT binary patch delta 11282 zcmd^EdstP~wjXQl1#U!egPRQ^C?+Z@J^&*%Q{2kK*9H|8I3(Z$HIr$dtTA7}?#++m8rta76JC)ye@A`v1f4?#2 zYs@j{7<2ONe&f>X#*z?qY46g`(TcS+=d_mi#g$w(R7q4b*RYMsds@xh?GLgr&BB(c zhgJXQS-c@sYnN6wv&L>%uBadUnR&Q`1~uI?AwFi*sAwo?5BMntfFBiJ^vu2VkgJ(p z>Ey?9T|QMj*!;2n?3Vg4t8}&a%-tZgGj&b<^967(9pIbI9&czlQU zW}g?2ux-XF^}<{1#{~=6Ik#5YXWN$g*4%On^yPEdik;v z-w>1!Ms5hohhljc%7grbJRZ3Ol#jsjNR(Ge`DoGqt*muCL%KlnM|x#;xFn=Mag5RH4V$tQELV=S;%A~lY{k&T8Vly zQ8Ej)9>;P%yV$CYa-l{EIIXdUpaivQ54+HAul7OE$<6Fm+h^6?0`E@${x}=fu1u{J zc+EBAJ8W%mYbBfQ5ALW~nO8tZW^5lcc4OObAF?LK4FVTX`GSE06GKv`iWOAADhe?D zllU^!a@Dn(qn0hMvDS=?CZl3T@wOnF+1qzlLzc6u_7?kw`kp3h;;@E5Eb!@{CwGK;-mV{9=~2`XUUhNTl~WIW+7YZ8OX$!> ziDfw*eC&%+y~E4-y&we}d1U$JUXY9(rU&{(K{0P60NxldEDCNQyCK`t3h!X?*t!n~ z!Qc2eec(>!@mRQktXsj+!4S*`XMqT>YlC4EZ`U6J{qu*wT%6N;p6WO_gw@)22Cs3j z4(nalZlpmj8sPZBHt7)Vst?)q#m$5GGHqlH!(7>kj@5R5XeKNU5Xsx{2M>Y?9QuMM zL1Dn=1V!H_f((b^MQ|Gq$D5!ST?>L@j%FRY>3=Tk+N^1(P`fX;u>6GmS`rj%;!kiX zTA>v|VUz%ZFLP-CpRN4PAZ$(WYlLkGnz)Su;DmYpN+`AZu)0oOnrn}W%9@Wmc`5cL z3DIdugKdL8=_=F}jm)J>lDXuoZX_YgX~UBfqQCD>G+EFvJSo;Sj94v zz^7MNp1}?On!q_1`$i%@EU+ni*u#jA3LJQ*(_+NO1Ri*?I2Z8=f#3Ks-Uaao0uSC8 z_ch`(0vDf~?2Y&%fz9XgmLR?$@REX2HpG_%wnil0Kzv!?oy`spL0pg6{@AnbKm2@D zQTQ@_%@-Dyxw+TJ#0|2-+F)T0{jAyCZQDUb^O1yROG=1N=_Qb&SsXN9#zPMi%_9$f znk^+Ex~{KYPSw|j99ByiJ|OAuj|e42Bgf_RVB07Ch$aVaGPPjlq@0;yU-c&m`LdLR zvtfN&+QZVqT&<)*{_OTxA=XU`_Z~CO7Kh>Zew`O~9fT+IY_pYiS^C^sQ?|MG`pkH*Ih8mW2!+nAoM{&OQs z9TM5pHcU(_i?dt%vwsZn>b@{%m(iLy*aogaLIx1Z{k;{`brd+rHbfNKwl2J^)OZD) zQuIUL&X-kuv0U8;Xgy`DB#X<)L2C#iu+iedbG)tvXw{$^q3jrB(4=L8^C;~kdgU%9 zVs&R4M;A?xGhGN;5rz^Ju~VMD068d?M=r=vE{|G}k*^2U-NTj5Adg%SQPvLfumu@k z`6(+t5s&5Z%JWhTx$yFPbhK*v(8a)#k<(W=E{p&#Dsh)vQgd zWZVLFBG#f6pRILaU&L1TZLHk5b;rpdd-L~=uGEX383*6sJ45WyV7@zejvv&0c^!5X z{sMLs6L01dyxh*?HX9dTJ?z(Zc!*5w?D;+&-)A7w_>!V$H;zDYJVZbD%{_6ABGCcM?CzGUTpup2W&|ZBUi)^T5K~CZ6g8s=t zd%(@xUuEe;WFqwN+m=39l&#Y*qWn`d3PVlv!zZFBtzg4) z685F5!(C}%?R|IFu0L^Bhd+r4!K&j`d-UQzlE-$! zE%)?RzU5YH?MiMQXQ65LeFl&G;tU)+LC)ynfZi+hVsrPiKj4f;Zo@<5*$j);G9=lZ z?Z~+Avr7EcvvO=~IZLAQI2M5gp1vyo3agU%3hn@IL*a&CFwKWWs!~S=V(S z9w&}GXIT$+@rtstc=~#oBW}r={gQYdf#5gWZU^yJF*&nt2Mpx*SYK#r>A4Ghuz1$g zs|Li|M(h(yc7u4o@xA@ce$dlDGqkwf@QO@aO?R|cA%I6B{`@oD_PR_m10Sq@=ZH*R zT^qhXCe!?$(FrGcqRFyy{bSx6Qg=o^6n*nV`R5=~+d;`!ugZjZ%{Rr@WR_kRmh!c{ zlx$g4`8~gE=%ZNs_M0*M1*(WO*v7C9nPx4`>f6AgGVi;WKKdVfsUz+P=K}xwh3EBR zoP8bUcIw6o+?z+ISUko}ot1?-$x;QHV@~qq)cc;3%=pbs;E1`>Bz>k#KBgDnukUdT zkE=;9p-JXUvv~9m4!MjbS*?HxO%gf%zMJHy2~gvh()dJfe0DYVipC~!q#)8n#mRq7 z(~D)Li}uIIvFgNGYNtvx(&jwmmIfW~WSo?|%G>#v4ZK1#7*+=LrV zQ72UBtUKKy8$Iw#Vcg}jEgs*lYw;p_V66h)=z(zsrt!c3ZH848Br)$ovrS*R1`|#X z-+ueo{Yz$pw5ZND;7^&9PKrt}Z?)+My|{hf>=tZR;bL{yc6O_9t7d!VcC3Eg|B2T) z@=n>nnVI3=>qWY#OB%?V2$MGvCT}84-b7e>lm7l8K5{3*bR{56`;0K{Gs3jb2-7|z zO#6(m*k^Q6;4GPv6v&i>*VLJSdr0f@bw)mnC$+a~>0JIk-tjZ;%8zdJ25|r z^;!_z?_QtC;msaqD}qGpbXeCu?TkxbQTOP~cLVRV#s8*PEf}g+y~6*O{TD5yiRmeQ z@3N#PO=i0BiRu7jRxTbdD|j(aS63G3)>k#XhyMhhx~P>lfAF}g`b!+^v)B~exH4T4 zsj+UOlKH>6`Tz3u-lP7mH=;zbqJ(DXUns2?(&-=V+=kP= zxy*UGF?^(}w@w)1{Pe-+^LofxcSWOz*1PxRIkeJ>M!TVDegs{$$te|$o^_b8G}K+`9P(F18z6=5_>d5exA>^_{8}@YUu$eGnx6tjjAof*Ou7%*|Ce@_%>vMa z01=fds3d-Aio|{vX#PNtqegF?F(`NBC*NII+KQcyhb^k}JH;Dn9%%bY;%@dr8oy7x zq1GE8fSGqgH>or}0Vy_+oK`^|KtQWNm{x)C=$+HgvUw$I)SPJU;TG1tG*msanvEzi zw_IH<8r@E9>%VHu!&6Ydc9cWEZa(Tq*ZhqB?O@MWQ6I)T^t~6O{JOt?*6PD7nAQD%_Y0mMHO@nRYrk-uIbuzL0wMa1zC|4;i&ThOFAC&X3*J4D zjcM||2g~msk7*PXL0fvR8l{g*j>_jJ!*2M{uaF&Gb>ANr?jAK{Ksss&Q))|?Qd`25 z+7hPJmT==MBxSZjeveC01v*N|mUNU5rlW)~xeQ@)8N%c-gp=1@9xdMK!W4zwSUpf( zznk@4^N^ZjW{*Naug9kqD(oBDc{X?P@O-lCd*as3vI2?);$O8#? z@3!aEykCm^x*O6MYfsr)GcmgA;uT z>8+=RUU#BDL)!aPev%XY1=3lo>bE)3Un0G!{zNw?x&i5`nisk{(btiVe!I59iT)Pp z?CooBJJH|aCEkg?qth*lzI&vF6Rj$&Hh|i8o)pFis*L|LG%2p3G?ky?4F2zC4;*(N* qM~Xx5iqkzx6Fm1Fo}gUo?nVcNvhUTI%8lkPoWE(K03K>2l^^72s36!~aR-pg|Fk*AnoNYyloh{B`_+^S7*>*{!y2 zY>L$t$({ucc4t4!-PsOny-T~5LVK{PsXnd%b|t;t6r0q8el>TkWl7$)hjr|^ODTEh z+7`Cerb;e6#-v4a*w?lm%C42yI@SDa8{oh~oou8&OmcFS!dW2y8^KEW-$<2V%Us)_ zydTQ@qkI6$qfzeTCggD_k4O3IC?AOODoy?d$_Jx-2+9+Y8H!92GQ*gY-c=fo?bbCD z{U)Q5sc;|TR zb=0y}wHl*VeSb?W`>li-s>T`mD5@KsaOmd-r#R~h;R$y=Ak_-M z3(o%i?G_NghvN#JcI@?CCIHU5ep9OdN}3dOt=Pgpm(Q5eie_Vn5>!eId)h70^p+S$Ia z8d=-CkNUwW{;G!{r#t;%1nQ9LRm|+# z2E@B_+i8!OOf!OS^0|5P*=Y|$=s|EdLQjGpBYYfH!+kBB)wOj}noRk8OwFaXPLfd< zli2s$_CixqX!5$4p?z<@N-Wtx7n9WYaR*|_6mn*sbs&*s5IHlyiGfHmi=0{D9Ymxs zPBefVljPrtShA54n;0Jv+?i;yl@dENJ|ZlbXtWszN^DYmL~IxKjZdg~oYwIy;)w!RdPamH&J;MKUDbTV*#fV>_9PT>uE2KP z>c%225P0ES1ND;Pq7h0`Oz*^`t^!Gl{u$jb_DFZ4d5XZN z!Gye=)U2Gqx*jkI2}vOz)I^30S}c+ja!1>V`Pe8q@Y|lE8%ZJGG|3D%dy$MBRg)Q# z16fG7W=2D@!8(j|yu=IGWacMN$jnU5ZqkQD-kL~G$@2~;vbl-OzYs~JkBKb!Jc`H` z8mSu>82EiZVqXEHc-4(F7>36a?Q2pF3Mw2(EE$`3VW>(VR!h>r*`PaviEU--!4MQa zl-Sl9tBgwy4BRwKMcm0HrOh+mU~n5*(z_{J*u8~wz*xc0UM2od*zqvIbkE7_8+kp`%j9~E2}&m2CxGQt9w`~TlQ{RTkUHBkFN7@1Cagk z;qUk)#8#^ng^=U8?{~BK@wu{XB|FqNSgwyPosihU&u)Ihu!MfGU`^f#SNZ<(fI4mY zyy~$>fabO5E|k=?@cdL#Q;Cs06lA_hU4VR3%dI}zfFJ;+YykTk2ZmT7QB8d{JDX9YK-$0|+LeR7)8E zQ#f=6Emwd@&_>X*1Zb(bBQ>t!+IrB^1!&n?OB4XAH@Jb8B6y|CVKdNj1ArqhHatPg z2><~IwOjzayilu)F8HBD{#TSHTG#`agW}g{9F+*W5j>1g3x)t+AnZX>7w*&EP`WN8 zohQ(iY*eWg8x;LI8$Zz5A+L>fL0q4x0ruAbtk^e&6)d{QG5WW9rYYQLUo4o?7At|p zUuI87_kX7n-M=6~?{K(k-V^-dBLHjsV(=S|!+-A=O`%O2!Bmg|<8**?R|9dM zRl8*-qV+bu%dJ#DXNvh{DgDUaWP%YA&b zzGMD-%Ln`~rH~!K1HNCuR1>xDmYU1f#pSYDV;ui<_pn%o_Wv?Tw~=DDG->-gh4WSB z=~d5ZxJ&^Xan`{pdZkw~(A4KD<>cy-Mr0E@e z?=}1yBiMKe958}S9rw}~%J`e77?5f{<<1jgFwK=N>-(m8NzT)l)7$Y&C4~|$FZzOl zOeRy*#EZqJS_~RY{VJ4!RXXU*IPG%^WnxYnf@V!5nliG~KP-bdO3TWG+|k(uQ;DYR ztYmY#Xqrm%?@J1$XB(f>NgD6H7_kDlIEDJF930@sz!-kvA;BiK(4a z9=BD;lAM}5Ieq0EYSfvEZ(DUlD4a2mgp}g#at$dcO3uqHBB4n5{C>+M%rAJ0gp~cC z2@8rAkdSHtyWAk&ZErrF!ZQCafdzu*S0 z&QNRN6CU$>vbv0yzJ*8pZvQqpps)hOS5L=9-|m&daEs?{V&^88EA~IU>c-NuUiyqP zUigendrh-IbJxQu>Z@yI%L%Flq#msI=($YE(JN!U$~QCboR@Bd-yha2m)+6`reLEP zWyi$z_te+dj?PGoi(&)EPnBT{KT~y)viXs!-LW-U4e&^1KKyXz4oA*+%GAyd zC7)c$22s9eWVguI3j5Df_7!L+qUB%hTnOSat%NmQs-0$f1hpy!al>cy8?(F&4)I~R zL-U-|6(Ejb@7cFs3*y%8Qg7R^N)4?wLxI-|;>=u_Hi?(0_I6PhNFrwY+ znON%_ke~_HI(ai32fp|-3%foeQHoLC!3Fj^nSI*;HF;U$b5Q z_=)=Z|HRDNRkAvxUo$f~psK4rAAA1X!DM#d?cD6;uenc>#{6H8kkWrh5X7rD@P2pW z*pl8}Y?)m=%bfq)mxKyRe&2=<)sTdXO9W52cKUIQH?$SW!8NSoH4SqtN|e&s(4wH8 zUbZ<&qCG`us(lGlxl6cxQWta)7bimr{``EoXn-7h5P$sL{g$uNcihvD)h*5zEO2zD z`doa12gC5qtF%T=tdX@f^Rn$B?>dEzD;9bv-`AhH!hV`DSn9`aFY;AhUsAKJbdaCw z%4}k>qn~AWRN+(iKF96^vUQ6W%HGZ_u1wEjmb7szT_~i5nv$cV`eN9@X20E9x!Sa` zD>fMEV`{Kq{_`4K6b*a>7UW}twE?CEJMx~_pm-;K;ir$9{Ws324{Ny0S81|oLm971 zyk$(6=jZKI&6MzK^P+VKoKT2>)n?8+S?%&n|c^t43lP`F$0 zE_STEsq$Ipro&LVRbNzIIrDkS-wEYKue2M2%9(GV@+Y&Or@U;p+Ou8e-xsg6NC%0m zc}0+NFe_#tORM;|cLkpDEi>zjb_I&m09-)QkTrFi>^~lqA-#vX2~6#g69Tcd(7y|NIQJ`INFT< z4r%-Eeg0-f|A6$=(9s!Y^p8jn-rRYX8T}K|hO1{TnbEh9p4q4695eb3(mU4#Cz{ds zxk>Vy{PnhMV@5wxwVSRv+;F5B{RG(2oz?COr7dy4hjH*u2v2*)I));CF8?bXHLgm_=ns48K)kdxztNou_ zlYOCQPp8_WVy7Jyy@6EHySY>DO>_LF zrwhI%t!Ni1wcj7=B31E*W#&4f;c;_PG`wTpu)J^6~ zq+mI>Zbi2QDOeZ$NZQZG^QnVeyG4^+K#3fz?B_GQzy*6X!MB>gasQz)(vpzPSyqy6 Ke^iYWTJ%qcJO70M diff --git a/tests/integrated/test-io/runtest b/tests/integrated/test-io/runtest index 1fa48b2a6f..dc3b3fabb9 100755 --- a/tests/integrated/test-io/runtest +++ b/tests/integrated/test-io/runtest @@ -24,8 +24,8 @@ shell_safe("make > make.log") # Read benchmark values -vars = ['ivar', 'rvar', 'f2d', 'f3d', 'fperp', 'fperp2', 'ivar_evol', 'rvar_evol', 'v2d_evol_x', - 'v2d_evol_y', 'v2d_evol_z', 'fperp2_evol'] +vars = ['ivar', 'rvar', 'bvar', 'f2d', 'f3d', 'fperp', 'fperp2', 'ivar_evol', 'rvar_evol', + 'bvar_evol', 'v2d_evol_x', 'v2d_evol_y', 'v2d_evol_z', 'fperp2_evol'] field_vars = ['f2d', 'f3d', 'fperp', 'fperp2', 'v2d_evol_x', 'v2d_evol_y', 'v2d_evol_z', 'fperp2_evol'] # Field quantities, not scalars diff --git a/tests/integrated/test-io/test_io.cxx b/tests/integrated/test-io/test_io.cxx index 7955ffa947..5ac2b86945 100644 --- a/tests/integrated/test-io/test_io.cxx +++ b/tests/integrated/test-io/test_io.cxx @@ -17,6 +17,7 @@ int main(int argc, char **argv) { // Variables to be read and written int ivar, ivar_evol; BoutReal rvar, rvar_evol; + bool bvar, bvar_evol; Field2D f2d; Field3D f3d; // fperp is at yindex_global=0. @@ -34,6 +35,7 @@ int main(int argc, char **argv) { // Read data from grid file mesh->get(ivar, "ivar"); mesh->get(rvar, "rvar"); + mesh->get(bvar, "bvar"); mesh->get(f2d, "f2d"); mesh->get(f3d, "f3d"); mesh->get(fperp, "fperp"); @@ -42,6 +44,7 @@ int main(int argc, char **argv) { // Non-evolving variables dump.add(ivar, "ivar", false); dump.add(rvar, "rvar", false); + dump.add(bvar, "bvar", false); dump.add(f2d, "f2d", false); dump.add(f3d, "f3d", false); dump.add(fperp, "fperp", false); @@ -50,6 +53,7 @@ int main(int argc, char **argv) { // Evolving variables dump.add(ivar_evol, "ivar_evol", true); dump.add(rvar_evol, "rvar_evol", true); + dump.add(bvar_evol, "bvar_evol", true); dump.add(v2d, "v2d_evol", true); dump.add(v3d, "v3d_evol", true); dump.add(fperp2_evol, "fperp2_evol", true); @@ -60,6 +64,7 @@ int main(int argc, char **argv) { for(int i=0;i<3;i++) { ivar_evol = ivar + i; rvar_evol = rvar + 0.5 * i; + bvar_evol = !bvar_evol; v2d.x = v2d.y = v2d.z = f2d; v3d.x = v3d.y = v3d.z = f3d; fperp2_evol = fperp2; diff --git a/tests/integrated/test-io/test_io.grd.nc b/tests/integrated/test-io/test_io.grd.nc index fe32eec0b5c8e10ce1f1e1a15d8b6aa152520fc8..4afdbb6beb76aa1e10ee1eec314847e60e799c74 100644 GIT binary patch delta 358 zcmcbzobky@#t9lsPeLYYxia!hEV$0X)wnWcvp3^0exAn+46=+23=BD$2NgEU3f^Hc z;bGtb@i0G5DymyHU=gJ27aJOipDoBuoO@YOjTbevt>LaE+|*j=6yoE?z*<+E%FfUTG)#nH$7>rM zhN)oYAx9qv1~#CB#3u`CrmzGZSJc`3kfVrk@;9y3!rTz686XN6&i}j<43uiI$gg!=ll}ER RPJYhuYhnWHW_yFF$^btcLf`-Z From 510d7583808d3a631325b413e570e74db19da1e0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 4 Aug 2019 11:30:17 +0100 Subject: [PATCH 1706/1783] Correct manual - default for 'floats' is true for dump files too We changed the default for the 'floats' option to 'true' for dump files in #404. --- manual/sphinx/user_docs/bout_options.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index b028f133a8..60065e8c85 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -400,7 +400,7 @@ contain a single time-slice, and are controlled by a section called +-------------+----------------------------------------------------+--------------+ | enabled | Writing is enabled | true | +-------------+----------------------------------------------------+--------------+ - | floats | Write floats rather than doubles | true (dmp) | + | floats | Write floats rather than doubles | false | +-------------+----------------------------------------------------+--------------+ | flush | Flush the file to disk after each write | true | +-------------+----------------------------------------------------+--------------+ @@ -413,11 +413,10 @@ contain a single time-slice, and are controlled by a section called | -**enabled** is useful mainly for doing performance or scaling tests, -where you want to exclude I/O from the timings. **floats** is used to -reduce the size of the output files: restart files are stored as double -by default (since these will be used to restart a simulation), but -output dump files are set to floats by default. +**enabled** is useful mainly for doing performance or scaling tests, where you +want to exclude I/O from the timings. **floats** can be used to reduce the size +of the output files: files are stored as double by default, but setting +**floats = true** changes the output to single-precision floats. To enable parallel I/O for either output or restart files, set From e8e9aed0e42421c964f99293831bddc6e939b60f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sun, 4 Aug 2019 22:27:25 +0100 Subject: [PATCH 1707/1783] Add bool variable to test-io_hdf5 --- tests/integrated/test-io/test_io.cxx | 1 + .../test-io_hdf5/data/benchmark.out.0.hdf5 | Bin 500376 -> 666120 bytes tests/integrated/test-io_hdf5/runtest | 4 ++-- .../integrated/test-io_hdf5/test_io.grd.hdf5 | Bin 12480 -> 14536 bytes .../integrated/test-io_hdf5/test_io_hdf5.cxx | 6 ++++++ 5 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/integrated/test-io/test_io.cxx b/tests/integrated/test-io/test_io.cxx index 5ac2b86945..c20f1ce4ad 100644 --- a/tests/integrated/test-io/test_io.cxx +++ b/tests/integrated/test-io/test_io.cxx @@ -61,6 +61,7 @@ int main(int argc, char **argv) { int MYPE; MPI_Comm_rank(BoutComm::get(), &MYPE); + bvar_evol = bvar; for(int i=0;i<3;i++) { ivar_evol = ivar + i; rvar_evol = rvar + 0.5 * i; diff --git a/tests/integrated/test-io_hdf5/data/benchmark.out.0.hdf5 b/tests/integrated/test-io_hdf5/data/benchmark.out.0.hdf5 index 8a719c99b6439f79cbd6f8a52563d3ec63af072c..a4f4b905ff43eeef121eb3c9354be253813375b0 100644 GIT binary patch literal 666120 zcmeF)30zI-8wc>yz9*eYO2>)=R^-x zRZfx9Dtsw@Dv&%>TZ*elr=`nBNnXfF%H@*sfV}vH94Gq6aXOOu+LHLi>kS%UYRYk% zoHV|)l&r=XDvDn@NM;zih_`4ao%RvGu#`@}7BAP6G|aGpLgA8I(&^z!h0|8j=>_8D zmeT2G;%R|2-f(e;f~3M5Q!l+;I2Isr4&ZiTzn zTjJ>~DGl3+_mebQ_kM#1*$goqFtB$&3(-6$8(T+5+qv9CCp$-5r-}B{Bo*g5*f~zL zAIq6r4IJEEIL~~jxRmU^f8PaioJ!&GD}LgHh4@I8lM~mJ)|ZwF!sVjZ+5+NK3%A8{ z?W%F@3M9=`63!JZmzS3>Tt!t9PeG2`AwELHYZb04e5xslBC1U0y+&wo;v-&;Q|D?6 zmyNcc>15+H*TGJ*LOo$cE#Yg?|H2KtwZ5o|vhcs4n&_2uxt@69BcBIa^fQs;M7dR1QC6p3Lnx>6Vd0W=rLoA?G#%_@oUj@P>rJ3cm)9nKmY;|fB*y_009U< z00Izzz?UKLq5Quz{Vly-_0jo%g<|=Cd3pCE;tK$x3vJT$`X|r-ivkOpitWX@481R7 zN1&AufB*y_0D%e=kd^e9B4=61agm>PHUTX;x1mZj11%;iJec!*sc5&MO-TULq<-Y$eVs~*{4aF09h5!U0 z009U<;5`9Z`G4I1{~i@)KmY;|fB*y_009U<00Izz00h2Rf%4D)J5^l%f1r3bApifx z9*$@@1Rwwb2vm>&^8XbCjmP^Z#=yF8@DS42k@I zB_2@NGz1_30SJ5%0?7Y=5xWVEga8B}009U<00Izz00bZa0SJ^yp#1ay3o0)EzgSFx z{C}Aa39JkO2tWV=RX_mw|0=MP(M1SA00Izz00bZa0SG_<0uZS30_C6ocdoen|5owt z{1o~B?)?T2vKeAJU|{cl7NV$5HnxtAwsX0OPIivAP802?NsgR(4t9M100Izz00jP%0P_F;i47}300Izz00bZa0SG_<0uX=z1imPN^3VUf zR9yc5q?rCw{PX{A6_@|d z6H6oi|2ZFVXd46|009Vm4g$#ke-3*AZGZp-AOHafKmY;|fB*y_009V;uR!_d|JPSs z{=b$u^N;+0`5rTf4gm;200LjW0P_D|{yszxAOHafKmY;|fB*y_009U<00JKpDF6Kb z=8DVz>m&dFq5X~J5P$##AOHc80P_Dh4j=#l2tWV=5P$##AOHafKmY0K z{=WzE|6l(RiylG%0uX?}rw~B?|5GR;1_U4g0SG_<0uX=z1Rwwb2teTT7AXJxzk9{y z|A!&}|9Ky6XdMI~009VmE&|B^e=d6h?SKFTAOHafKmY;|fB*y_009V;pFsKN|2--$ z|33ry|MELh5E%jxfB*!(CIRICzoxy3zCZv15P$##AOHafKmY;|fB*#kzd-rt{|{7L z{(oiJ^Zx@a`kBaaO57+3m*DCDcazTLrS;}Z=luV2v$Wn~aU1`CEsmQbt=F{VdS=pk zf69u4`4E5r1Rwwb*#gM_%eKK12tWV=5P$##AOHafKmY;|fWX%xQ2zPBgm%@ET81AF(g5Y2P4v2}E`oy$#hvU9X`nrJ^wQgNPxo#RCNv7EWpz`@;x z^UQ}zN^5axX=-ED+roqsmP19Q`A|z!(W>TFy$U0k50#YG;&Phg0>HGng^Rgq^TegO zwYapf60dI|iDO|cp0+mcW+kd&ZQi@Ey%XomuydGU#EHu`+@!gM(>6xpF#k@sd1ty! zvE^-Sq|2wxwV60=nw_JhIyY9*&askqj+L}?ypebdxKmY;|_y_^y|33l=RUiNX z2tWV=5P$##AOHafKmYm|4&t1{yzZu|1bP-MDrm40SG{#f&`HNuOMh_1_BU( z00bZa0SG_<0uX=z1Rzj}0;SLY>u{nhyS9Kh)xvi3T)S#qy8;DqCzOP9Ma$*o;Y0tGp%9ZH3-#A}Ibb6ibH6j5a|?=?b$6OU{!$EkC*h08|U&vdeJn(JUES)rb= zqG&7`(f`5?ytTflin8#(AWpnQ{H!OMjRyoE009U<00M6bApids23|q{0uX=z1Rwwb z2tWV=5P$##zEXjT%m0t6xct9@c&zyUlK&TvPp`}s4yG^M=Yne`@Az|)#e$dOt;wqG zEv=VVa=mks#e&Hn7@uA;9KN8I_^OJm?dnP6d6hhVzO3~z9|91700h2H0p$O`&i#sB zK>z{}fB*y_009U<00Izz00iC^D1H84tMI;iE#Yna;taK*Fr4iB{?Aq1_&?vio%hH1 z|8MVSyoLY-AOHafye)wI|JxdP4FL#100Izz00bZa0SG_<0ucB*16qYy(=#N-v{~s z&+iCBiy#022teR-6hQv}bKEOv69gat0SG_<0uX=z1Rwwb2teS|3Y35T->2g8|6|IY z{}+${uf!dYj+@`5{300Izz00bZa0SG_<0#!qx{PX{}DlY#&zwG({s8Go5Ul<~rC(R;nkgC~BMNzqrNXR)}A7oQiP1 z;9Ajj0j+~>KmY;|s7eB|^8cdGP0^$0M7t?t+n9(agwH`W{(XrT z5P$##AOHafKmY;|fB*y_009VmAp(_`|2Mo*Vfp{3@8|!uoRI(jLJm;3){B=`G^@6VSqeCqrCMPDWm zq!s1+Im!1Kq}xLY0SG_<0uX=z$H~h7OTUyiV~p(-TgM_P-2Y!>fmaZK00bZa0SG_< z0uX=z1Rwx`FGZjd@BhDBVfX)66Awlt8WTu5{tq`3_y2z>$0*tf0SG_<0-s($R{kI3 z|9pCDM1%kYAOHafKmY;|fB*y_009V8mOv%u{~uIX{=ez_`Tt}Y`Tv0y{Y>OIMb1$2 z2LuEG;_nj3+CRq9dT}M!^On|ItSBo~;rv_DdRt4bS7Hz>ga8B}009VmKmhsw4*+2? z1Rwwb2tWV=5P$##AOHafK;SD7sKoq#P=)3HyS$(O51m!={r}zj4IX4O#B{*G-u)~@ zyV=Rc*3r>+E;rH1&e7IsqWv_uB4nNF3qjQrG=GveG5q(3v2PTwRtxy zQ4MSJ-i7U*IA?~P!we%%T(;pR%`Kd^F%pOQce>3x(`||^Z(}1}K5eee#A(y){v8Qo ztfZY|CG8w5Y3Fz&@fOCn5wAJEZQH^vj5m@@8%d_yNJ<;=3gd0WD~z`huQ1+5yn?VS ztSDSwSpF<&@5EW+Q7IfHG+f}qh$>kr8m$VNB1Rwx` z@)AJ)zr17-7XlD~00bZa0SG_<0uX=z1R(JF2vlPJ|3!u6{|COG|M#0+a{mAG*+Xav z1Rwwb2teS|3n2gh=}i$40uX=z1Rwwb2tWV=5P$##An>^fRAT-=qQdh3li$z(d(T1s z|8qMQ(H;mu00I!GI05AUE6y5Qf&c^{009U<00Izz00bZa0SHuI^(>|J+Ll~TR(miX0uX=z1R(G+ z0?7Y=j1uZV00Izz00bZa0SG_<0uX=z1iowmIZl%+OgT&P&T^byVTa`8#WOS{-P4kk z#izA6@e;vGaX#H!QcqeaajJ#!<>kczRXLr)MGA6;$rYCW-zv_fi+Ut&ulqdl)-9zC zMF{~2KmY;|s6qnB|5u@%jjlof0uX=z1Rwwb2tWV=5P(3H6{y7f|1&Er|9|rR{C}wA zdPQ=T-Sg-;1Rwwb2vlVOlB+|EhANqn{9f00bcLwgB?~Z)@N+1Rwwb2tWV=5P$##AOHafK;Y{XsKorg zyt0^7QivyN3dai)Jw#*mka@2W8l0JATAiycTsGQ%rjw1+TnD?txg1wdSWz?rk?6m8 z#G<10MO9RU{{=7K&;NU``v3WV@%aBLoP#(RC-_smt|-?3dn}jMds=cmH)*}JlIzWp z);m;kz0J~k)fE3$@zwu7|BnL$0uX=z1Rziq1d#u) z3VRuSga8B}009U<00Izz00bZafvPT0iTVHP6_)?6CB8@g?fk#{8sz`0`mvAxLjVF0 zsLBG!|5xR`kG?|y0uX=z1Rwwb2tWV=5P(2c5vaucf9(p(|Leb>|95jk{=cdm;Qs#^Z|D7S|Nqy2^rD9lfB*y_@LvUx|NpOYSPudafB*y_009U<00Izz z00bcL99?okq{{NSAl%k~&fB*y_@Tmo4<^NSA8|pdH zZpzp;CjV|0f00bZa0SG_<0uX=z1Rwx`FGfI)(ssP4lG+?6dwd{6f#iCC_zw_B*7(%p1Bvn) zf;~mo131YjM*lVtFCYK`2tWV=RY2gQ^8am-|E~gv0=ftR2tWV=5P$##AOHafKmY8Ysq_76!nO&# zit_!^>l4m@imy)?zO(hOct@ja5P$##AOL~41Z3s^MW36ZN8$bdmUfN~;>mxX{qT2y z|Fysi2tWV=5P$##AOHafKmY;|fWYT2PT7u_#0hIg)#{ZW}po9PfAOHafKmY;|fB*y_009VmIRd56|9|9oKkr`$ z@H<^}9YC61D4**93gQikGw6C>&dxwfApijgKmY<2B!K*X1wmso5P$##AOHafKmY;| zfB*y_0D(#rD1H9F)c5~$my7cL<$M4Cw{PeD|J(ilmAEUgX$U|70uX>eg$W@4Ut!eP z5Ck9q0SG_<0uX=z1Rwwb2tc6H1l}M2-?*?Xath+R=cVKSXh>S9B`Kxj0TrJw{rkFx zo5ZyrRPp@gD>bjT0maE80}KeNUk9?*g}d`+7lPGlXLsX%voc zB!1$A#i#M$H<#Mu_>M~Qczc8*>3B%VlKm*i`}Y!#7_8W{c+@A36MS22L9t0K$wmbF zVwYlz|D6;_>KPi8T<_l%KGPTFbzE8gRqEp^IjWM5E9tr9Gu=gK76huCfUNxgJAePT zjmf_Q07*X^WG$Dz$7L;-0=wbw2TLhXLI45~fB*y_009U<00Izz00hciK#r?cnCg~} zPcO%r6>d{bvE=-}Gz%>2I)HS!^m@RkEv3yoot-u zI@n2CSWkFRh%N|<{)^8{;x~c#HOIaE{*~q+Kby{>ArSaX1wJbO-}VFf|F@P)-+S-m z|KD0JWkCL4DuEIL5P$##AOHafKmY;|fB*y_Q2qjPoTfORCP}1y=ze!;UcY$WUpil! zKMma=&PQ5G6LgZU$j;v?8g_a2zT|&%{i0Prb-urvFs5LPxQ%Z&QJT;7lgt#Hl=e*0 zfnr6FwBDVP>p4jCzQan+)AG`I3erqUu?&%UnG!xzd;yTbYFT|j%U$(rKo+yn(xFb z-oDbmf2)@muk`&Dr5rzHe?{LVD2iA1{%V&Puk`(``A)pD@84SQ#4CG$YnK?W^!@$j zop@#MZ=HAImA$`pON>|g{))y*D?0wl-rst{c%^-ODF5HXv~ORV9;Oz92ACFxmR!b` zd^d~Z20GbJ8*A%0R(cg${FOb9>o&{I(RREYC%q~zy`E4!p7d(C_}e^1@x-?Ra9r_t z(rH=oq;aIBw0+X=BS_bmwoi197d>Rflg=+5Pde^l@pz(hsOTYGuXuk&=S0z?cs%Ll zl;ZJ3=P1!bRy@%;NAxHjPjv1OJ&MN@odZMkq{HK}I}78S#uh z5U-7lcx`3OZ})+C?PaXjLB{-!ABZO&t@Qo(TPGRuI)5Nu7a8kyl`;Rv55)UP#(E@~ zU;O>Xe;{5r8S%Qyh}Yu-@l0gI6My=>fBx(Ffq1=S#50pIzxM~?{VZd>J~HO_{Xjf( z8S7cdm@k>l`AK(_bOuTYKmY;|fB*!(7=aIsw^Ed!D0}`y^t+qvc%{#uh<@iQidXjh ziRgF5qIhNRujqG6+3`x>U(xTRMe)ksU(xTfMe)ksUqOlSO5b16@61K*D|>%MziSu8 zD|>%MznjaBSNi^ney1;rSN8sjasfs0%HCg5?m%|D()U-Cb0~^e_Wp`;6-DvN-d|B} zLw3B<_g9n?DT-J2{)%!bMe)ksUs3KwcD&N}SCq3UidXjjigGX^{gOOIxnkM$q@{RD)^ql+;w92j+Sc+arQ4BJme+Qraf@$PIv=I@IDi8j zL;_XiIH>6JLGkSspDu6r;@cA+?G^njyie3rPWTBW9Un?s>d9zG&~~MFmZ(dnivQg3 zP9;o000Izz00bcLMGMIKdBIXfuT*#Z|DP8``35{7009U<00I#BIt5Dm^THhbyzq4% z2b3E_ixP14#Q&Hyw>2_q5 z<-K2IZC5(Ks%^i#`-}KE|Kt4s`Tg84eP2q?d(u)mzr0H6c4U?1wOwgkS=*J)m)0w< zQo0>kWqEB^8n^g%rSnnZJdN}8=X;(mulHv~pAU*}ulRI%^-~(R`1XoVi_Ze(_gs8? z#iz?}%i_oty}k1858^`r0{>m0qR$7#w^w}nzxU+h)-1lg;?o}&<-gY|zP;kp|2^`@ zty$6A`?yx276c$r83Gl3J}ADu;?w1AP<(sEr>olb%e%jb4*>{#z5-SK{8zmH(mYXl zmBqJLe7d~0D~(&x+mmh=rT82G2RMiXK9}R5qR$7#w^w|+yj_ZKulRIT+kScX7x8hv z`<%{qI3C|U9;^EKud4SS?}vBa5Ac9TRrgT`W{TCno<@a2Cd&Q^AZ_DDy6}`Rk z?hoQa00RGAprX$Q#kW^{`oH(&+xxgyp%w%n zP#FRheLg6@z2ej5ZBTrB#iy&<_RG7!hz|h>e7*uz{rp$F|K*+kExx_t(-pn_^4=ce zi{JZjfP+Zjb2|yODRZ2a`S0&(W(EdnWa> zj;9aB@0oVj`PH)*q`tP%(wxWsWLz&#qi)|Ia#O55;8j2%ZPq(&=QhKe+6RrQ@wa*+ znKhB?x$wb5nsZL+tZnrt)cd4rU~J21iuYC08GkIE-1Wwocm`jiEsYc!OkVSdJ{Vu4 zL66mg&e3lk{!jMz3nSZ@L3HD2Jn?@Vu!*U+n4UaQv$Pr(M)^IA>-yb}qVB;7t>^1T zlg5&rM!t{l(awweeOj-HpgN(>$Hq4gA?07P$J{k~KqnKWL@F_LxHt zXyVUf`YSX_B!Nlr{yNQr>A{bN+B?HyiF@W&cZJP9GK&aZ)Y>bM)KARp?R7Ddd{(aC z-fX~iI=pFD6ZNCdC}^o-JO4?i=}e&cAAjHRqt;v0vfUQO(}&_;-?BOMn+{1-+xJeR zkxvqdt#vcn=N(5gT;^u1_KzpG-!%^W_|TiS&2n)w$qyxW^H+Ta1|FtG{92FDrg3!t zib-7TwODd+Y@DJuIvwOpc@v#gAG3e1P1M%cOJTVX8ycNm^ci(up7T`cm&k`DdSA zkD=a=H^>i8SfdQfj&^l-B*w-shqJ3(|?ncCO>$OC5E7<1AN2lfsbS zbGr{qq$3v^X=wcOl0FpQ$|8LIuof4HZNBuH0%PeU@BXrxM=T|u{u|;S7uF z^IwwYjK(uV`9!*P>Pk|V^vg6eaC3A>y_e)|6ueu_b3I+}e%$fLm9OaU*(SVYvnVnP zxUgXF_xI^T@%hb{GOzmGr5390t{c3=$gsr)~~i zJ`_K%+c4D)=Mu@_C$E5Jc@Z?aUi~(QEh4F#rs>#Z+Zbxiw{X)9i=$tbwf((8QXFLl z3tZ;Se?)Gb9a1k$Jw+4D;%oS`05UVaxA*0-I8wCeTysX3tJL|-bR+BI59vekCnPmK zd(-p{<$0|-&?}zvZrSg?`A->s%&4oGUCX6W6nMU&)rkwqq&lGU_AHBZ_By}A{d}9} zBp4MMzk9}O>NqlE)p352M(;W7X98rqey1 z&smzvhGg&Bkg_L=aT{E=c5N=t-_Xme<{7KV_c@x?s;OBjtFP*KNvB^TYi2O=%KQa# z{InJHc%w=_#dcVuG9>K*oq9eiL2aTpv%G&hsY|;I5>$Jtni7#s2Zjm^clJnT&d=nm z<5#_;yKg4BnEjJU^4H?5^|jtm@LGe7k4L4l33f+TX8D|8`>tyb&^{1AR%=iC#s8|v z_v|~epo9AZdTqYS{ocY%c5+DLLEoN@CD(0cHAn1@Aw7jY@&n`|nDb^ow`hZ7?0EEr zJIe>XqT7c1-1hf*PMM>E9BN$6WfpxL79VWq&l0uLPd9FnOAor#zY;%Mm0xZ(zq8@} zROTJCG}~rS1f8mL?bVW>Q>e22ho4)%Ty=3K^%}X=`j7gNEc7x>y%f2FVs!5|9@_sn zOELquA66~+-eU?#AOaU52Y4& z7yjtBESqladlS9UERD?z(zVU}JCY2VcfL^DFpUIlw5D4^`ySJ&yb@nmMMK0l1P z&)AFm_bi(n$fiT_hc`D{5K5Wp$My}8&tr?08rU1&dq!`R`W#<Al$Nn}r zg>*d3{B?%jqES!Ap11xxmh%1Uu=Y<9$obmZAsffPq4=~t3f~#uXA8FZ?K-*e3dQbf z6ZzfVAX;-Z;EL~_YW%qk)t6{YeZxkzH$0WI_%iD7IF>-6p<#2LnJ-nxS_!ahZXy17$7t?8Z3-eAUXBoMA*4NLv z5Ji7$+N$mp{#^LioN)%{&t}mDiaI=B5@gfFoCLQ;7sAQ+ zl$!G#mw4t8?|EKt)O8XJTXr}9W(u{cGrU=Y6)EJ|eBR?Rj%n;h_ZoL^JdY#qScNf( z!=u^j7jBpG*URy05q)PVhefe%XJv8^i|4?p`SelyJDwTysKYWmBxQ7-G58Bm2CzQOk%pP7{s>G|WTa$S4&U2Q0 zbVl%u(U(~p-!S*?KR#x>&g&l6t0$6WtfiHKT_#J`b6~9e=oEbttps-Q*6fKTGMenmogzKd&KVBgt+Y*7(;#&eLR{Aow*oQ|K<%k(@%T0^82QR(39qMXWto-KxRig`hNQ` zk1Wo}@t5Xjuz0z%*L$tGO;-||*mE`teBY59+Rh%Tzz;f>pt)md3iGKo@3+3&AJK&N z3s=mvc|x`KFJd!ovM4WL=nqM$uUJ8J|9U!C6WEXT!7KI0CDMQcQS!6ya=hncgCFnb zW-=XxbH6Q5InP|?b+8+-^*Z^TQ@PZ@QjzzIT$*Zg@EIGVn>}pIcw<{fH##g_ychfnNM-AmR@55=Bt7(_-R%gF|h z;pan)irJvV93~*8lQV`~qN8bR2Oj$-g|d!hwc9iznw+wdYJRu%HS<<};&k-na@wu@ zJY~efH*|7GgW27i=y&}g)wT?RLbG-G+*6k(> zf0r55Y5X$FS&!((h?d{`cgZE6N%|A|x0K_zw%Xcap}g?tLP66IW0wqe)#kv;VXYq1 zkO3Zv9`lo_UhT6jY-2cY@8KPnI?Y*1QEl&!?-iFr!AjMWe%qN$vuK$hu(kiIp3Wny=}w8{~Dc6dlkF#iKEk*@n8Eos98K=7B**7-BxmZ%hhAnaV-ld zq~FQ?a&_XEalMRQ(+2v}@fim@lH0_~@&k49X?;_bSLX*NFz4Szp`v4OO=Pq@>IZ?d%Gu)(^eM zMe0Sc;2qC3V)i{^4{m8I?B1A8CaKC@s=L0X!;6M(?B*ZNLRoJ;@8Dz>dU|dBx)XxQ zHoS4lci+FJx+_mgC^v zp`Q-cowH0giFxMuuL|*rVhfv@8E9D~Q~2UT39gfKC^pKWP1mU}Sc7#5>ZE&(dEU|g z^QSq%%uyj>V~kQYe#!`W&qKdvG4B)Hl=%xUQuwucJ`Sn{G;eRb#)MUhyiSz!>od-g zY{em?lof|ksCICtE8SzF>0y%gSluDQpW|DG_1wH5nR%paG4CH8&jdHFrw*%?OYJ*k z3{laFBKN7y&U!xBN$T-?>-=sSLJu_?4i478MwW+q9&D6%YTfZo~kDt{}kpo9xof5AKp@p zpYluoZH03R-uHgFc3`wgEX%ig^uv$+(nvG=r|G{f%%w&0iW6S868?Uq9_u-F88gMRrnST_k#sm3f^O1#SePeA(*ZBHTZ1xM_F`HVX51BWmSH1{n$0F z+oiBrhXu2v(xaKqQ_n8fuK2L4`=f3S+bz%69HRDet7|^n-gC#){pX^Yx>wAm9f7H2 z8}hn)P+kVPP91L5xOyn_Y<8|uyPw0DV1ynsUl~&k_3bhYnNm{$Zo1k6X%#@#;^s;pG2M5l1=srM-@zZZS|@JU0u|o9ZtJa`M_y*< za#!~}`0^ied(*q)2T%4KA^t|qD(C8e@*sYwcmzXj?$W~3c z$q-?lAj+v`$6w>vvpO!xMi-*lw(ng|o;)AOzRj6<=a&HmbS?s4YWB;&5s`1?U%3^iE&&GRFZm3X)57Cvj=_%a8_ng&|Sgw5-CeCJ{n zf4ci^t8KfE$@6}O%HhvKLP`D6+L5{w!x;BN`ssPyBgwO&?(^W7WLnVU_w}({E)ysP z+}t)Yh(<=PUDEz~Dpj_>l~vCqUCN;a?ZzEi(op#RtN!$lAcUV z2D9TRKl!Y7OmYBAb+32OBmNm{^IG3}o@OA)UrIPQMY(|T`>HCeew@p0cUZ8}UM+=f z(oC2>$1$GnS+_BIbT6HL^*FhIqe==hoP8#4i!g6ke}5~J>#ZZ$^g#8eB1$CN@8gnO~6pv(WS>9QJZ{n9=ayT)Q9XPOo5A64d_7}v(25QRj zW0W`9C$@M^V=_8#4_Oq!JfgU~wo?LVsbBZ+&qO9u%EQGf-0|1s(#ZO%&do^HiH6NT2kKY<6_Dur|yhPvP0{TJ;Pn z*!XIFuu(J{u=-~mix*GGCBDt@W!e8wtr0JCMrcG*;)1hpj%7Y#b>{be^Y~~8HR*Og zAT{MVjlOZlM|*D?ZLX8gQK@Wzq$zaiYtKTpHdpyOr_nmn{22(AogA5VC5le=u%|JpcUH z-U&N4Wsr7@>#gePq%w!IO6@0&GGBU2>SoIS%uFGm}x&)Kbkq@#ML+) z?L}er4kbiH=a9#Xzhb?5CD5{U6VKESN@jgkukCtTGn522e}8NJlH=99QtVT0a>;pv zfVy( z#x~jHHsWF5(bv3Ls8`d+f9yR+>mPLsi4o=<+8IAqoEsxNPn_2XUTBxao;{z{vi)h{ z^^v%~L8m(AQDysc?Jr%7yO&GGtzyrsHBMoB7T%Y0+7!*69dpg8bEkk#O+8{A@LN9l zo$ekyN#O`_8mETpUw%SiwU7EvXdFi2gKRoX{5_F&d)2wzyhaAQFl3{)$DUWjYpBF) z?K{FA7|g3Tuw6CY)gjeotlm|oHJ^`KAb*mXG_+qb@z;CwG<0%rpCj`8;2lAm&x9s1 z(+*dS3)&~JKHD$*CmxKYhr53r>13$L8=mOb{eIK~=6-!(TlFK?+1=l5O)okpP}KO| zw{6aFyhifo*w%k#urm#=&sp<}AG6*$tfTI(47#j2!SOM;Hl=wP_1MWKZ2x4KbgU9VyAIFAwUaGqwCZEpqU9C-Hl=)d< z-Zk0{&tm6VJigsy>}~4e+0t0yr$p+Zofjt%=68(q9H*}xpTQ=*_PjN^YZ9fKFRwrF zyL58*)Zc$nFO_QE@7h1@Rv6|A!Bjas5KgIu$* zJ{zg4e)rIUk^hkG*D>F z&g~yYcL`%L>w-?tHa*Tf)ZBl1)FhQ$7ymx-WzcKV-4|W2leh5a#vYL&o9895lvX`P z_RmhC&YH>Ny<*}?OJjlV55k`>{i>Vq7^Z)MnXGlLe#<_RtUC`(YMZXg&v8*P_YKNn zcl}n$t;`Q$&vU&p`C}Y^L3j809`YRT-q&K8#`*PRR%h1vKU-z8-9|n?j}|;3`9q;? zhQ7`soeaN+m%>i4yDN9ETl_4U?bhC}7=G2CW{pXC;HRv}r^=grH?l_#^Q%9q=b>Lu zGo4NrYkQ7Nr7=SWbeq&AmXaPnm@qOYl-W$WGrH@wD0-;8QbA|_U79}3tL_|O9?kIe zDeLV!{F$S{!0$JyCQ^sw-E9mHWsqsi4SnNF3cSyq$X+z_Ce^;O;l$9Zne0;dw4c&P zzoboLMlDLQ%A=H>XBQj0zi86(SPZqyv`iVI8%IONCH~!JO&V)v z^JvbCpPn;;{Lgg*o+Qy_lNt$qy)ww~l25BKBjOkz5_Tlwk7&}m+T-^NSwYNTV*N4U z7lh}(<5ou>Pgd|&wQJe+MC&x_bZU8(!3Odz&V)Gb=VY)r*T@ zT>a;@FSA72NNN#{*JP5;UzxLfYn)~2iL&5NW_VXvp(*s+z}o~&B4*4|Vaa;yH9 z6(Q-&dueQ~_(gGayicvxi(J#ldutP&U{eLY<4VJyhYyWmR%3_#zdoew=b^iqDOin?S< zLsClrj=JhQwJ-qz2tWV=5P$##AOHafe2D`1{jG9;e}g~#t8)J0OFUt|g*u208Dmwf$9OA-dx&pyr*wIBci2tWV=5P$##An-X0d}w?ij6a0& zhcNyS#vj7?Ltp3kLpc9q{5gz2hwwa_aF zKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z@bwCmb^IX1G>jkg^&TDQ83Z5z0SG_<0uX=z1l|?E_z@UC0^>(u{0NL6f$<|SeuO_6 z*UQtW+c${Z6l)K76%a_9^)P+}#*e`G5g0$>>l{A|uH|!nRC#9wb;*>5q|}m>ijq=QQlfwW1Rwwb2tWV=5P$##AOL|c zOJG7$-Bq8PWqWoy^w^85|GylS4YihQ4=S*@CyrLy{}j+b=$C9-A) zBd^R~AjeNzL60}8iH7Y~W9?+@hvl7%MdNa%Wx0AZG%OF9ur>ZFt*>qs2z;I`e zWaj)#&N_b8OS=1Jl8f0tnIwNL&RSpV4F#_?*!XxQr*;sPjW>#~=?ikWj=p#QsE`m94_H&Ci zIL3}gU%0b;&?~xaxX*2WpXZc0D#)S6)m&!L$6@iocK$3;EB$oi7P<7GOZ_YHqgDCk zR`WX>-cM!TF-x;;21U@RI@ew;`8kCu+kg1E<;ztUXHu_`Tdn`7AIU;5)6`3mJ19o? zZsVc-kJF?j^#hM)%kd5N)O599oyQJ7*cjhKH;ql*o!`XluSC+$_MfGCP>o;za^&%u z8&jFUS$^@goRie{)u8QxA+KoXoA2i;X=Ksz)mEL4Tizj`=QdUc20f;$9Vh8+9hF3> zp>uPs2dnWmJt9?SW@RyB%asl;r~hHqg6}=1fE2R)roGd+@deaH|Ds21+ibR=Mxe$j z-xxODWJ%qcT6yGkr%9hd861CZ$J$M4Q?9XgkL4%Tei}wGTV6dg?tX)OFLhd+nk&yg zR%qYCtFgTI+B+`Ec6;JjuG)a7Yj&oQd395t$wOY#)?3$IY<>=BHxpXO#YN|ml0mXh zL-$Z>ad+X5Zp*Ui*1k8<8_m+#ydYiM%)cYapn2yDwGGoq&~{7mJ&yv)zI}C_ZW~W# z=IZmqnEQ;qxPQ;G$$@M-6n}Vgvjw4)nSN~F5cxc|XsLm{;k{?{Myb#7)#v5-%Jv`G zU2*JhgHuSy!^~f2=q(!cWbAqCzhf!izYc5vB!Qf-tsSy){2Pi-+oSNE@qM;no8PXJ z3$IY@t~Qb1?G2(eR|Bs2?y1I~+faRp#?&`#RC~iyIg2l|E~9nnc56A_e)x;gJ2h2! z&fd}a>bOhH`PIYdZnZYC385*swAQ_(I;)*76r3rbx{Y4^JlZ@g2l@Ildos7VSPp$>{*jWS9RAWX9==tVorkF zq6^{VdrHlDj!QiAi1$3NH|jbGhAq3Be=~(z)fwKb!HN{}Y(DSt7{@erqkE0JH=f6l zcdWvg#NpBG^$WL4`RnC)wTQm6l*6LfwzIRI-O)*=9sT<$9W!`DW_ye-#Z1niEVI~w zmeV=!yC#3mcgatt*{wDyjqe^!mF<7qwH?ctCeJUrVEjyfek6NlwC4x6We-_^L5rY< z7HL#F;`KOxy?>~>V#j*D^`0|5^EKD%_rFM;8ylXi*83R^DwrR6dQkzjda&KweMSsB zw`Nhq)V?oilD+e{wU*@2W!r>+5T9IHQ(dpO`lw7++w4;Je!b(#)|)&NR_4*h@bJA( zt|_E!*l_TwDIx6e*(N4t&3#GrWDTubHPdLo;U|7Uo05q8`&NCq-U)0(44$rO*ZK1$h6)a6nZI#MGqaQxVG~7drhX?Iyp%Y5pT4oQgE>+^y*R4ss zc;`7wJ~|_K#^}qejc=HH_a7fKUgvd>>(vv$$Hzyy-UcNI3V75x`v9AEU1RZl&3 z`NqspcF{L1{E*=TdN?5D`%9w=sG(iI8k@$)vCzj9=6fKCLL6(I*EGtb%J%R3w?@#D zF7Y(Fo5z~!+KS$N&;3~4t4kcY?LMGpY@9{|W6ySQ?~zWc^Nv54S!dz5*%J&$|3toLFXUe)unk{?jZf;C+|SHx1Na*jdWbqf6B1{ML1 zs(Ebq+;y4{>OErjZ9?334U8ebi9R09h0a`zs(puP3$=v1-|dd4Q*!+Rp195OVHf0G==%pn)h4Z z?T=_e`-LlJ+B~7!`xmj9Hd&MxF!YC{)K{z^x_>>Ls|oB!`{0%O;}U7WfhhS|cRAj3 zvcZq{b2FKa!nxm;r<`Xl^E%iK*m|A(&Z%5#V5!LaMJ`RXIrxkX(#;+==5iL~HkY8>eq&|cm< zd&l_`BRrll^}t($?<&2d%J%QHQ(<^wawLt7>gTV0H=Sv9H8MYW;t*|BKkV4kAc^K3 z8+G%VyzuiOM#XGUVh$6K(#aV^F457nwF8fRlR{ZXvf6DL5lv26Nj1OQ`kHwwKXE#G zayji*ex5R7;Tt-+qrvR%&GIP7yPa>~%Sd+Pn=P*dHN)wlQ|;A>tzMDiqgqFu^*P>p zW$Sj6kEF6eoyIS-ob`xqjA;42f0tbHnWR6Ve@i)jYpbm-7Rn2ME)+BkF?PvdS8Wcg z9MeW8m!ZwEU_8#7GsneXL6xH_r_+D{26s%M|>9?K9H0#D@fAx`3 zjDHhX@Mi02a_IdBpYz>W(%UvX{IAjJv{$h!pEx?58UMAfgPO$?W?^$S)omrmw_H7D z9oMpeLi(NDFIOjy8Q06`HEp0j9iMS<#EI&{upVl{3d3AnZ0(0(u^LT9S+w6eJlJ&Kn-%w@yPfE(%(9W)a zYW>iAT%=wE3*PZuBWB+t_TZMb!tRafWRj}frMl~DI=pDu#%})MER^-u^A1jCp{Li@ zuR9@_Y{MI;eE0ops=M-(_WC6`%=_4P79H}}l1qzkR}3@a_`4>qT@p15sPn#vNjC9W zEGA;q|HxOF7mZZAw%B-zbM7Xdu!<5Y?r8fk6pOAs(GtdIW#HZ zsb2n#82ag8-8sv2lbC0Y|Edt5D7LVfnSqu?GKDWbl;Ao!hhn1~+H{@zf;Cu|pia8i znCBh+KYyAN%p4UGHpVDbKo zzdqv}$yOXPN?CCzg=z)C~}|L?5yX5ounSWx6bdTA@oqQ;oxBXYh-z-=fS4xIppISs(-}o20J(9 z&Wvl{M9}J6USsUF{He12Tkel`SACH~>DTYx>HKFPo$_sHxBSNl>Zy9d@y|cP=<%|_ z`Qa_q_$j~S-&Q!M;C=6xYX?S~#Ik&=M?d`7FO4*_f13W=!dzM;uQ=glE8*`)>H%v4 z$eAsB*;vDHNh-OR?Q-9GS%q)ma6ed}rQkjGRs5ib9fH}4UxUw9f0RWR6_&c4S61aG z*N(t>^jjM+;&t~Tuwfi}Y307EWE3dr4(sFto*qyRqs_8sn0lVqbaA%_Z*==f9Nn3?;kdLI?lcr%UWLWxG-y5G7bCo z;;~;^$?;A59o?{dLLxiuGI5ScW(-@f{7KY_E!kwBa6}<}s2p#8-zBYPqX;&jV;zmQ zMvqx^&(Ss(CNC**?9EyyT@%Us$fc|c?W0*kxAmHLmkK{$kEHdU+bNnV+n;a#aBKcl zRen_OW5ZUoOkggv{&=7@^f~i09zVV3?B}eHTBF9P^Elq}<|y-7Q%)0?zo1b_$cw7 zdE{kwE_Zd$gD?Lfw?{4FFCMr-FN1rnS$0p3w|;(P&c&I@Owa4i293_ajNQuFdWk9X zgKX85n+y@=38I{8cKkJtJ*(rAY;+--ZTsHkKf3tK*+AQbeA;noaIDXC zMc$*qv4H8((d?edt91uEM>6h8jlUlR#!!RR-#kAuS&4U>ZsD``jW2U>tZAUNOxV1R z$9FDP@u$1rw%WGqm^|-is2u(*B$U)2tsSX5F^q9Pq@SMGJ(4^d>OK#SNu~uoeqSHU zs9SHm~)q=V=C#{H270Qc_e4c83Kk z?bTA)Ce4KDa~$L8o^>0eNB7d{SC5nXH>#vC!`Wxzw)nrG`ukg%TyGu0rVmeBnP>L4FgqpZ?O_`7L;9p=WV55Ig|%T8c?!>l z*Q#ew!NynXgN>rufYm?iSiE>bF7a)KFU$UiYK?fAGeRSh5*M6(b1d@_t24j%o5x2( zs7bf`0jVj^Y4nXVKH7WJXmg!(_Y6LqMeNuaoS~M$4wyT5>8uH*%Jw(1m@lY3NuJ-~ zWio4{aslgL+TT3nTq>zAQ$N4LE0ZozjT2o?k_^2{YL$2YmQ$(M$rGy%_@9mz)btW`q9iG zC$7ffXfFz@cPJquI)^-7{1xlfD}k1+n|P*vP%`VQdTrO!nxQ1H`TJYzmmII=m13W2 zlS|GU94{}64P=V?*9Pty7s$4FbxR9>l15AGt~j`S`$HQ2^71N=EpONyv%LofxSu3* zgQ>@Cr*M38@93b@rU`U+Z~X@@dvDTS!!<8$HpEb{#_!YJxePMUjJ6E13$L8=mOb{eIK~=6-!(TlFK?+1=l5O)okp zP}KO|w{6aFyhifo*w%k#urm#=&sp<}AG6*$tfTI(47#j2!SOM;Hl=wP_1MWKZ2x4KbgU9VyAIFAwUaGqwCZEpqU9C-H zl=)d<-Zk0{&tm6VJigsy>}~4e+0t0yr$p+Zofjt%=68(q9H*}xpTQ=*_PjN^YZ9fK zFRwrFyL58*)Zc$nFO_QE@7h1@Rv6%0H|%Nnf+t%U#tAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## zAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| zfB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafhy?}>Fg2Cq;)zyH9mXO^bO^Ctvb*v zp7UE zCyH?!T()*?{=ataD=4b;T^D$hgG5C{R0NfvfPx|-hIfgGFp@+-C5st#2r4F2W+W*{ za1>CKARve$k|guBBpGrB5hT-1=%%~L`A~KKH|Nx@bK7U{`nXv|xLEb8Vuj~pE(gpRhU*nNNC!9o1_3|d0@mS9*jh|hAo0Wvz>X#!Wt z$h5X%?1083$gcXu&+MOp#Iv$$QAZibvxCEG^m!jtEjoGW|2qYo#UobAVvEooq7vHT zz(Q9pCi_p9q@oX{;%4HBjc_I;y>9d|H=$=}x2zf601HOXqiY^cp>#_*^9@fwU1DpfrQBp(b=uw4nbmRTf7X8|xZyoB z$V0SM=y^32UDowpw_0o-@+!BSFrOq5*^wb(2MbQg|-DyZa zpk&wiT7-Vr)|hTdoPkfHpToC#bi>p{$_Go%dGyFf#aXSU0~UEsd=1RuAlU71r^9{W zFAF9}#p%~eoh=84pBHkhJ`TfDy(HTElLnr}A(o++7h!ZfmTQw%E%JC<7nA<*I}FF{ z9@rG$20=xQ->YL+5!tUqyoGKoB8Rg5Jy>Yt*x~`^+Zp)1Ec7INlmh(rG6{;J z6Cj~-CnJMn8YyuPM9dcUg3C@DJ;C1Z=#Os0`^@|a@KZF}ubYJ+AWd3%I(HC03ZLVT za_fiJcQ2{rWKBb^vH!_yrPIjzgriDq&^Qz+gfOOMXW;5AE%;GxFH~m;c;59IMRB8P zIZ6(tAZzVgwe*7ts**O_Ha=rQn*9Bi^KRp)Oh>e;taAj&!(8X-HWak*JGfx!B?lqU zZ|Kh3Gl<@1xp!1bF(C4!2~UbjGw8>v7f`QF!nFSIDN|Pxxk~q+2VP4IxT6}zb6JN1 z?Dnq+&_I)aauSbnwK|j^44@A6*j>TCO{h^tu}#K!93=V|F4Zgj3nJY6)*C2wA|<1s zV(F9lpe?7CzRI8j%$FYwWIkF3)rNQE=$llO9rURGhG8E#IeTtc<2?(7=V*;xC36rY zqGTZGFoh)a3v^5jM&TS8(rEtk5Zc=te=C3qylOHQ&#!l(&ske^_2sL9KV4L;eDye( zeg0Y37B&W?kLA)F1~hbC^uZH>x2^Ez&ll|qjtofB>?k^`$VHr4_F=J9S*V-R)G(zM z3r}p?Vicvifh?xqROG`$2)+oS=T~+j#+RGzHysPn?&_XsokJ~%kXkreDnbX-Vbe1z z7pD+IDLUkHSOtosWjEcLV!=+ky=%vHxQR>ZQLh?f29T6W+GE=0X{5>2aj~FN;C?JU z_S$J)g1g>h^6R4}B*IE5EW6!}@~eA#KdCi9lUdjH0*7Ugxo9F9c6kJKw?I#I;uv(f zt;rEqp9gmP8-5gO`*~m#9FN2WiHLKP4YLo4vvmsv33F8_-W)P*Y0y71XpULrWQMbGPH9umqES(;`vz>ejhgK5u(p__MB zW!(!dqGh9TqZ|J`vbpy{xM6)WsdvkQL8 zue(!eO9TDnIKvH1^I-gqgD7|~iAFiHN{G2nZH+38C3%QHMU(X!_i~bF zB6Cu0<2sOFYq>=gPam+`e}5F04V^In7Y0r0#j7Te*g9a@{c+ziL7QmPBkW(pZnJ}F^tr2ERfm_pKt2ad~ATsaITVK-s;5~0A z)Ar#aq(^SNqqA)u+Q=H!t$hQiZ0(yN+10(!bW0+Tt~vy6&1=4RDw7B+|D77wl3B=n z|7BlO_hu-w-Lbv?z#Nn~DPK9cgM)}rjZl2Zx$;~nyR}QpYZ4XNC;D5fwt%Hs96jy< z1J+AqDW0Q}$Yh&+KDX}rz~G+R%g0A%p`Ax$?5`*WxR-_33)&4LVsT`7F(MOO44x9R zo3cRZtxfN1#|en%K1k3VCy>_b51InTKasJ07Ax4FMC=GW|AMq*8M;i;6F4MCkkh@2C)Eh?-BwGQz$XC+TT@YO=jQ&LOt zax33Z&M6x5)cNssSfTUzJF@LU9T`#X(Iz0$b23~P27TpCd7N9~cFLevkwV}1=(2bZhy*Oa=SS9|N9ub~H!@Hnw=+<8W{C8cfaaDXnn4B8+1o$N=a5w+hZxx$f&CMKUewX~Rm@SpyVs!f@o zR-Jg7hssG7QvRVq=dD4xKc3604$XoS?U&M085IsEt-I^1Fox1*>z{X(45EkI^i{-+ z8PNOW6D{D{EDR62>^^woH`@4uCI||}D6LZYpTl?CksB8+l*+S;xNggt_UZ97BBzqB zKX{lAy~XQGT=o-lY`4p_Vvn}#cTT^usrX)vsgW_+kZy_C7S>DEKHPERcim!3K`Wh z7ySsdt9}asBjC1y?o~x#o0nqNDCGS~}Cb>yXJf2+tgL{p;Zz zJmTcO(xY`Z3WFg?xmfOKrQX7#I1%(5QKnW;=TJxIIgx zc^dM$e1da$`H5@N!$CVWm}uC=kYFA)EV7ja=eibj+U6%A;D*f^IgxIZwk>pd8Ww|J~H)B}PyGwp>rcnLjQRsI_D)R9AIhgup2ApZhToY$G2%}oB@ztCAk=Z^; zp*`v?h@$6cZ>-w~^b0@MqzBM}oLn%SyO)Awf?o<(`K;VulgAD2?WX{{{R#P|h@~6+ zgo8nf^|Ku`CiX6nYx!(ND$|98EQ=PqOb3L$%B$eozbKnqii)8J=M?|mN8KG@gh_dGb z^^*Gjh2Unz(fq_R=xaY7|7NiT+aE(N{a?vOK@La z02{`t?H8>$2q`z+@=Yeo=-}WHky@TQ$UmLcdXBaPkp&jRC9d2=+{TnfR|*By=nlO| z(jGvh@1h?YTB)!xaBXMuH69|^)wm>Nu^PF!tyU59T{*pdU!$Jz)kD<=)weMzoJ5@( zZ*NCeHwZR|*eP7?L8M(1nfG-DAWcT0vz^KSkE4IT945^nS)RrpZ|&N^ZXm>aZz&7d z?SJNs-k1W+f``VXPu?;s|9>LCo-$PH(UHc>QPS;H7|SVf*m!3ImKa&$R7N9WMXyha z8|^^57nH5;3%3Gi0WIk|?=mbI@^b~Y%%KWR4}WI?CJGa#x!!dfg&M2f>diG1@Hj3# zA(W4a)b4y6c~k!zq!UziOLz7oSM!INsq1HeUcUG$dgDCmQZf|ZqcsH{lG_~4S1ti} z^7I=&Z7yO<9ZmN$eF`Nez9L#pnjv9%WVltBgE-F{=1f;yfb)~u@46oKqqsrR{GRKL z;8Ulw{o4Qom`zXkNM9GgYqM36)QL1ckf1;lxQq=IOeJ@-8FIV<(NevRNSLE12^vZwhijH1$C09N6g1sA^U8 zp_$yakVgG3I3uT=G~&%kbUrqqMTSj+xMHd5dMOri$=WiMmRA73tJew^?IaN|&&!_t zC!CL%YP{`ip-e$8vm>IPDS6Pd{u8aAG7E9PUk~RUr-AQ_tKX#C7|4*nIOf;tZjiPA zxWTHALsU zUH$k(v*>g%Qn`_G?mCH(CsW!okI|qiUb?|6{s+XX1@+m#qC&gS->%W5Nl+1{n09R! zB%H2YQV5Txp+EZ72NrcS#PS2B=GdS>b_=BlFUh1M7D*0>mEbL zG>f#B_tMabcZK!zq+w`!|Jd%98aJVqYNAs+*npx-Pwf#*E=5&;pF5WCNrS=51{L<- zNQ4k0e0b;UN%U=F>D{2yb;v5pdY?kfBoqo?am%H05egT*Q^n_IP+U&Jxzd0R9a>z6>2OqhenfU9-_e?Pa}BvXiJTVF${i1m!Gw{Y^r=k~5S^x+kgmjn z)wKstj+gf!V!wD*dwD7{iR7V%^UVOe{n?#Aj<0|9Jn8_y2hRkN5w0|Bv_o zc>j<0|9Jn8_y2hRkN5w0|Bv_oc>j<0|9Jn8_y7O%_W%Fie?SpFK`ej;umBdo0$2bG zU;!+E1+V}XzyeqR3t#~(fCaDs7Qg~n01IFNEPw^D02aUkSO5!P0W5$8umBdo0$2bG zU;!+E1+V}XzyeqR3t#~(fCaDs7Qg~n01IFNEPw^D02aUkSO5!P0W5$8umBdo0$2bG zU;!+E1+V}XzyeqR3t#~(fCaDs7Qg~n01IFNEPw^D02aUkSO5!P0W5$8umBdo0$2bG zU;!+E1+V}XzyeqR3t#~(fCaDs7Qg~n01IFNEPw^D02aUkSO5!P0W5$8umBdo0$2bG zU;!+E1+V}XzyeqR3t#~(fCaDs7Qg~n01IFNEPw^D02aUkSO5!P0W5$8umBdo0{?}8 zx!JK}93&3X^8fWkV*D3>{Qvk7zqY{t@ms>wh&@`^Yp&qZtU;2b!Qk{Uusk1C9#8}FC4=)b0e_)NV!f06+4vd`}8?NAny_2hg~ zJev-ChRol!b`3$);`VzyLet?V<0M+R_A2JdagswSy%-l` zN6?&r*{`6eaWE1&R&vd90V2vvz3l(!ML%eY93zxD;89_e$V7L8V%5V#!M-z4{$Y_4 zsy~kIw<(;P`Zxe8^4hr)YU3cg=MAGKZW(4Oie4z}PDAK415~> z9KOw?8>S{wK3H@z^3>%2r6p)ULCuN$bKc_ zEp%fMIqX%-n0-=+4mc`6#ZC^w+2*%nlrSGba(449x>SHXhngry)`X!e-OO^a7kwZZ zcq@1L+cK=%ykIcu!9p9y77sAr&cN?wp(o*^6yUd)Nl+A>011^l85tbYNQrwOVz#gs zTz1;%3HE+Re{>t(XXa0UpQ6!z-7EwFY0}Emxr6Xg_#A(fTR*(Mdr2iHYZ`Km{ZC#i zokrFt993e2#-T_dgfT5U16OBh!H;r#p*lmr^RCw@iW^PKQF15+S!>^_r5{XCm9*Km z@fj1+5bruBzUnYxn5Rl5H?@LFQP9n~HoPN8-=w1Kphx{T4Ew;z*>l4h?^!53M{DdVnS&q^B?Cc+DI}p^pkrb%3g^g> zM)RMC(B9toTLDbqRg7rugtH;6Y^Uu1rurVNgESKgmprPxc z51t6TZG|^~zGzo)WI&Q;N6}eDF5=9x4~wPBLfw?6hAFjJcw*BQqbSu4WHJ4wA|Dx z3wGM=T|2JBOwZmh0n(F62Y-8dR{N{kWik;(lnz1b}R=SOnWvA-Mq6Z>t1jXEgOv+-T3E`&Ak`G z4eOgxt$kN;%qc3=T`h@|UvVZ;`RnC3YQy2!2;#$^UGP(W-JMEX8t5m-8E$Br2jg!X zM8SheG|G`xdOWBCzSFljlkB+&L%Uad?wsW!%u{H>kv>dRvgZC@hVPo;%HD_1ZrlF^ ziG)Y!w*55BH=f-!#u`G)l#}bFifHJNbGyItB|4ZT4syCzk%+WwDu-(4rjQg@_FsO? z9OQLh^P*WqDb!{26>K!+Ch7)!SoTRB$XsE@`g~zGSn?kx?-XXj2bsT}U2FM>5=8Dk z_q`fqg+8ao@W+GI)=$HkGHsx4YgB10$wT}pnylBjmyl((cfCN1uV_t=y4AiuwEid@f?*zCfn@uxpmhE z2KUrnK0Y!F?K~o5e?>9Cy)3+5&~6YBizCa65t-m(@RXR{lm$v}ZF*ljPCz{OL4xi$ zfwW$K&=fHKiHz;DSi$}zVn^Wl7o;7_&}EXIz#%z;wAN1^|MOHme7%|UO2qIp%20UH z{jp~rEW)QQUpAXT z*ZZY}=OVD%-)U^>mBz(oShLIE(tuJwYLDy`qJC&b4dvoo??Wd*m&JQPBwztPKe7%z zQs0ZZk%1Dqoq@VDL!{STX@_&Ya?DNJ7hs)#hWJbGSwv3RWURRq0$z$6o>{Ath$`KH z19ahK(EiZxWIsBMsQo_46^=|aG5O@FrNtD4|MY)UZOR0->crDLR8F#x@(&F5qyQ6yVd z%CcTF2YWRqE&0R-A^OI)th9zG5FCw{{QFoJGzrUCv?~{b=_kFUt%9>q640%j99)L7 zuUFnIUfU0W<$33w#p;3G{yP#V(fq$>VWPCEQv07)$f%aN=y#|e^!QWV{(0I1Exr~@ zy*mVm>!+70xU#v(HK&Uc9d(D%(wXL6hfKync;>L{Uk~Tt5hwSRKGl`?Bf-X?M({+w zeR4u--YoFakBN>b9ZhxL0-Vzs3}UqrwXdZ!n8BO#lD1oNn2k*zE^*R`P2 zHa`ggH*C(xiFBj1ZP}YO{^&un&y2-+{man!?D52eB?<%x+uGmd{uey`-^b8g@4-mC z#bc$R9uT~lX)nydOX%4uKR9d6N8S~h=5{B4812Z7%XNRt0P79;DW_FAh^;1HUcJ9U zN10w%@9Iubk%!;U!PGZ1;7m*AnmEfr7}a`>uio5`%=SqN?NM(*6g@|KW8FTWU-+>m zJ%A46g-LM>w#4ysYKVD1BZ}XBx?^oB6{7<2yMGUlsy-ym(=$!1UD;=<|mdxU;FVO z-x?0Wsx$d+{%r`?tts%3+~#n;atXMTr{DN#a}itWXu6;2Qz$X< z713(a3<=94!>z&`#ChH@XS(77oS)Qw*Y&6$#SN0?_grrTpE{lG-v$`KYwZG{Ga?vb^aGS!SE9~dmQ zeCdKMM`{~c%uaAD`&J?zKMvuN6Va1IFY1qsYM&IKp+qB>JgJ~=V7I@z@dH^2Cr%qGR!JKD#Q;-XysRvT$z(#LIRjZ;8&E&R)H0pQ389C*o5pPbS z^RWRfGHepW6-!muOR4OV?5LLiUn%(9;Y&sT1R zzQe7ETec=OVMW=(2%8itB*GYst znbMYdj0RQl(hXkmKOkN$sL%ct721XVc8w-Yf{HN3v}?N{;dJeiLU=R{{n4*Jz>|UAa!=2(>@FIE^|w-FNKGtb?5+hHV-9=7HV* zq`d|CBQIF@dq50&aHb<&8E5aSk89vp_ceo(WKO~&vMu~u_ZT{+S){eRmxfNfE3Bs{4MWrW z$9A{WxCymX6P?<@1{7U-YL8%YDXRMW+_8L58Vp`GsIdP=B7_*>!#iJ3qHh~Z?*^T& zLsn7N`xIg(p-}jWTP~H0P`K!wDn2)Z;&Kwsl?HSm7fnBftvw6~loZXcJ;Fmser~LC zJKBbN0xT{?z8pa|+CB;%)Ft?47$^?sc?tI(vZ#j5G|E2 zBeE;`j@G=JYslqElj=rrYobR`z7u042iyu1ey`^Br;%Ttj_ zBo8&5ZwA=y&+hyg=l|^OU)Y^Lcmp0$2bGU;!+E1+V}XzyeqR3t#~(fCaDs z7Qg~n01IFNEPw^D02aUkSO5!P0W5$8umBdo0$2bGU;!+E1+V}XzyeqR3t#~(fCaDs z7Qg~n01IFNEPw^D02aUkSO5!P0W5$8umBdo0$2bGU;!+E1+V}XzyeqR3t#~(fCaDs z7Qg~n01IFNEPw^D02aUkSO5!P0W5$8umBdo0$2bGU;!+E1+V}XzyeqR3t#~(fCaDs z7Qg~n01IFNEPw^D02aUkSO5!P0W5$8umBdo0$2bGU;!+E1+V}XzyeqR3t#~(fCaDs o7Qg~n01IFNEPw^D02aUkSO5!P0W5$8umBdo0$2bG{BME(1>OUxQvd(} literal 500376 zcmeI*30xFq9|!PR5WyR7@m!A-Z$-3JcK)Lr9)*}n;fV-@r~v_@s3mCy9lhOW>Qx# zpE4z@m*k|u$%!k*Ih)?9FAtPq-cm=?Bz0V!KUjIAQOYExTxlo2(Qwi~j;p3jFR#Qm zuh*xSw>QU?;?($RsVv5|Dki@ZlnJeN%5T&-Gm_;NtW@XURmPQuwepYyv{J`^k{dWw z9Uo_JTGF5{AFIq)$35hV^OX9+COKY)GCuf#5?`s0;@Jvx_3qSDifB;wtDZ{P%3a=W z>e@Q{`S%HY!@F1SZhk$aX|aJp(a}NiTzG6~bWm(~WQ0<2OjKxecw`9Y8_?UovvHbl zU%6B^XV!0lhI2ISzw!%bEaW{|qmgT>_0`heIA3~SUR%fbyCe--uBsDPb-d|4$2o9L zrulYucBVy~lz8@c~qe)wv4B`qCg(UQlKCfYMx7WxOO;$vAIF(UV1gQ1Cdt_FQ34&U0Y>vqofdB*`0D%`=po^#9 zYo?Dd=>yd`C?990&rxYSCOBwBP_*<;9@5LH?@&Sj0uX=z1Rwwb2tWV=5P$##AW&EY z9+&@Dv)bzUswd9>+neS8?d%q}l}`Xj=i;(X0zB*dzm&Jv)|d6=T!wY||H87}&`tkAOHafKmY;|fB*y_009U`F~sY3M>x+2tWV= zMO^^-|DwKy(LV@400Izz00bZa0SG_<0uX=zXS|ocqv?MB@{2TH&BUV7$XRsxRhljj z*5Cg>A^-CK3*|OGi~N6QKmR^~Z+Q3W-OaCu6g4(5C^|YQo(qo+jSh+pkBpF4#f^yy zjSi0t;d}#n`*$`@^X;pY{gg7Gi>an>U#09Pml31o01@#@IYush`^jaGfS%scyB>X& zvY%Y4+re3`hF1tc00Izzz*7kz|Nm5MSO@|TfB*y_009U<00Izz00baVs08vp|NlY$ z<^NM;`e%{5jfDUNAOHafSSf(~zm;I94gm;200Izz00bZa0SG_<0uU&K0(qbR zPs+di|BvzpuqFTByN92bhAYM;DBDuoQN7~+-#6}HwcfA)K3|>MRjoHmo$~Kxl3K5K z?(6;cr7;x(5P$##An;@Y$p1f?6KX*K0uX=z1Rwwb2tWV=5P$##3bR1o=l`eXU;h8B zyd`YO{}<+MiMB%k0uX=z1fEm?`Tr-CLOlpT00Izz00bZa0SG_<0uX>e;T6dH{Qr#n z%l~J}+X4Ci!n;4Bgf>C|0uX=z1Rwwb2tWV=5P$##Y!k@) z{QtcC%l|h;{@=E}0ZT&w0uX?}iz0yh|BJGv(N73K00Izz00bZa0SG_<0uXqS1@b=s z|7rf^|2=Kb|EtgcjZ$_BZ7DgX#eGDXt?h4Tv5GWfv@%y)Klga^)Oe+er(BzqTqI8vw0@ z00bZa0SFX;0P_C@fR0r{00Izz00bZa0SG_<0uX=z1oBxR@ALo5^DqA&gZzI!?><-^ z1Rwwb2ozEQ zKmY;|c!33w|9^ouKDrJ82tWV=5P$##AOHafKmYz zxT@n7F$d1cG~dq7&XkOI;;NbE*lV;69Zc_X-q*f@vA#4&l^0amJ)kt#RT(eIRWi;S z5;-z9Fg89a)HIdjT#OZ+jqjx&(+VD1UaC^u_@iAW&yinUrO8$go&Eg#1isn+T^-b%GzO78WP zYA7H80SFXX0p$OS?50J>AOHafKmY;|fB*y_009U<00LP8`IrB1kbn9At#WQxeto+9 ze-;qlKmY;|fB*!FpaAm!MR22{OAvqn1Rwwb2tWV=5P$##AOHa~0qgVs&Zg_`ot?O> z>;I*YmaqF?lYjUBIr4DcAJ6|a+te6^00bZa0SIIXApf65fj1C<00bZa0SG_<0uX=z z1Rwx`A}f&h`Twu-FaLiD`TrujqoQLFfB*y_@Jt1e|9_^O2nGQNKmY;|fB*y_009U< z00IzrE(P*F|NnLV<^S#NOvdtAfTz3uU%o%R1LrIU;j}SwOiLTDnp$s4?)9{4y=A%A zTddZrpYu5h=IdXn*6WyiJ@e%-4gm;200Iz@1d#v7egFXoKmY;|fB*y_009U<00Iyw z`T}{M|4+@o{C^GG^Z!MEi=&4SfB*y_00HFxu@6810uX=z1Rwwb2tWV=5P$##UIc-> z&;M`Bzx;n2{N=m`WM009U<00Izz00bZa0SG|Al7NOQ z#hD%@t2|Fu!?~KOYV70*rIiJpmC}6No~veBzPz>$CqIc+%T;yas*YFcJ8({>`F3`4 zKqq5;X|UG>G<1;b*vp0dTESRf8l<%^sIq%NX|Ag>UXrV1oHrzLWNct;d{n4uD#y7P zD@tvXe&iNsFE3SbH2!GEW}g>uHq|sv%amK2Ays;4ke~lsj60-E(^iz1eW*%~x4)_N zn&w_lU60l?_j*Iscvo|*1|txF00bZafoCdUDgQ5hZc2ksc<6`_H!pd__?liW>n+|u z00Izz00bZa0SG_<0uX=z1RzjI1PU+AiC8v|=s zXXpDl<@*fk`cOgu0uX=z1R%h1mh%77=cqKq1P6@>ik9C?uekm{+XC+(009U<00Izz z00bZa0SG_<0)<7O;I9AYeDdx3|L?NT2dMY|;qKx3|H875qMZ;)|4|8f7H zXK#&&5P$##AOHafKmY;|fB*y_0D*!MD8T%Gw|vY0|N3bDKf^-)U%vmp6W3FIm;k43 zljHFOk8Gw_)OwfXbv#l*nGm4Xdo}lXQEI(exz`)5)?1x>y}@d|;N0sasP(?fz1~o@ z-q_shS#rR12tWV=5O_WWkpF)^wgXxL0SG_<0uX=z1Rwwb2tWV=5Xeh`0?hxvmT&q0 ztB>aYf4h(C|MPOcLTm^?00Izrz6Fr~f4;X5S_c6LKmY;|fB*y_009U<00Izr76JvB z|M$zc{C_F=T6O8tb@l!~haMpR|19<&#DD+NG1c_#tCaoZGGeqGAR=BV z$H=8`Ke_A?(9>Ib*Q2je_LIwgzMTT3>HU1Wnc5XTIwmwKrZp#*ZrreV(|BNOsgiL} z$KB*nW!%kdzFVL=KO#ObJR%}ATB**3DD4bU+8Ls>Gpx0|hA=mI$*?wUOpAoIR>oT^ z<8DeBC@&BeC@&BeC@&BeC@)|vO%;vvO=Wkb0pW2$rnW>YsjytLfI<8f{wrqMv9Us>Zy|FXuFe#W&itFMl$_0@5uzTA%NH7buw z;G{NUfB*y_@H`11|NlH~4YUOU5P$##AOHafKmY;|fB*y_kT(Jvt_)|&Q7VZ_4d-fF zk;YD*P+D27vr?LmtM}86YKfcgJH z`Ii5m_-OwBP$hZo=K25LJ^Z{hTyajT>;PK%_B9rFhZ)NECbU=Oby%usQ0q;UpF3=+ z-dE~+e^eH*P%%}lcQ*HW2DM&h?)5CJ29qHG0SG{#hzcP8Uqm-7x&;9UKmY;|fB*y_ z009U<00IzrNT2}o|3Ued|6llM{@+mf-}Cq)Q+vMml z1Rwwb2tWV=5P$##AOHafynq4)nEwyUxBUN)kLLduS4IB+1>D`yWe7k30uWFHkpIW7 z009U<00Izz00bZa0SG_<0uU(r0tJ}=AC_$wlM=^Xv->4E)1LFWw-t=_r9rB^pvvw6rMa%kcuB63 zao&)~k+FfX@lm0ssT}8GtmtffFa5}E$zEQnQr!5X&CJg8b6hKFG6o1h00Izz00jO; zz*7ES`aG3}nBbrhLDBMi={3Dv_Itd800bZa0SG_<0uX=z1Rwwb2tc542w0#0uV%`> zm)F+G%Kuk&;;N2Ux@-A7K(mJVb{?Rje6B%0PvBZOHUwG;0SG_<0uabY0p$Pl5gV(5 z00bZa0SG_<0uX=z1Rwwb2o#V&0p9=TZTWlvCttL$^#56ZFTl|lSKBoEe1Nm*8w4De z;3BU*qk!D8S_nV@0uX>eK?+#P|4W~n(%=&wIwHi)OCB-4;`;wA3cP^;1Rwwb2tWV= z5P$##AOHaf6dC~yS6aTGj(oAa@%<~NwrlL=38j^uNcY{52K6pJmZq!u^{DD{e%)D# zD=*D)mcJjsMJeY4)X=6y^5lGgXZHC3PPq?}+P>aB{Jf;^M0};RTiaXhv05W%nX1+s zo_jsPPF_xXHurk2YP_w=0y$TgH72O_>~owx$(pae>8jSNk$b&XYP}=5uUCzW5&{r_ z00auRz!T;F+jwPl68Zlu3cP^;1Rwwb2tWV=5P$##AOHaf6dHj?^Z)Yway0U7{EcS^ z00Iyw;sTcP|I+8CG?=dc?-?2$C68vk9>Q|~vMlfh0uX=z1Rwwb2tWV=5P$## zAn?2k6kPtF8<%hS|CmSf|6kQa{{MO3H_<)_KmY;|$U6b#|MSikks$y92tWV=5P$## zAOHafKmY>Ii@@Wa|Eu0L=7BQU8?T@@T}SVv-U~=;>PpsqeeC5g4mcUV7a$Gxc6L$C zKmY;|fB*y_009U<00Iywc!5Xn|C96izv}h> z>V5y!=K!nU2QZ(m-e12}9XZ)=@%g`5=LfVV1be$;+|2Cr15#LNReAP(0n>8gslbS@$eIX<>w(6;|{6M2VR)9Nn|jySNU5X#_wX(Fq>gE z`kNXrCHHt4O1)NJ=U&e&{Bt*&SNm1Zx>oO33FiuEzfym9p1X~M20`Ej6|j{5&vE~M zH?OQO0H~i0mgcL!uOr3rkFfI{r|jqo?p$zS~?G)&R5R|46bKwp3=ckuDGcw(tU#-J|AET{jBdF zWI7*kL~gaz^Zas&s&BQ6)0_fwk#awe=CPmc{_@1nlYZphu zBERRjhkt+7zgf>s=g<%cJf{Lrl>cw@nEd}k^VQ$I9Qpr;=Bo_I|Em%xApijgKmY;| zfB*y_009U<00Mb0pyA5M`7|Ywrr~nG{$I^9n&1tl}w_0-kw5OV&Q@Zl#a{{!c zImYY%4ax(7)qKAcQVsjepBGTd7+iZv4sX^(Q+x0N0SG_<0uU(50+#as(&wWz_=Ja! z2_CM~rTT>q0Ue5JPdGzdfrA_fd!lOfjrC5RSCXL6%ldkI3D)FRCn=Qv1 z^F;BaOTyK7(zS`%@oev}boL-Sp6&gW6fMWIzQ5Af1hV7V-e1WwJD%AM8k@oevJ`CQ{!-`@&3;@Q4^E9Qu2dw(nC8qfOvR?ZR6_WoAM5zqGi zR?Rh@_5GFZm6pB#+1_6lV?1kz$L0S$y{1q&Y>l7Cn9TXOtbpl^KpI{zOK5{UA|IjR+{1rEjGmoc^TZ*T~QA@Rb>h}@U z<<<5{f8(XWQap9Kc|7&|kmm8EzoF8gE@$3f>2IPmn8#C3rZy{a-3-MlhOuU8`;x)1m z&-F3!8e53h#6rBLkBQgJLcHb{;S%}xh!gTk?#A|C|xpo$& zzxD?X^ue*iiUbQg&wa3KswXj?d3)7X!+#z*CsS{8_00Izz z00baVXapX2zm@F#gzfng>Hlt)<5{0Sk^aw@9nbdsiS&QP?0B~KSNgxD<#^WjSNcC` zc0AkrEB#+KJD%yT^z zt^a+Ka;wkMQ_9H}CQm6>Y`Oo|drG-w%kiFU|CG|2>fbLZC!L@Bmym1wt@n^}b% z7N%+HbZMScSN)NuOFz=RC5jtM=|}pUmrAvc6wBWDliQ#xnJDBoKj*vz)2YW_%k80G z%XJgvpK#&N#19@5!!VxXq#tQ{Ykt(_)Y6(|rMgeMoVDvgee1SsetSLbexNR=me#gg zT}~|vYI$qdi~7&^{%q~`DcJq5#ribzIzL5h-s=r=?o&;7Ol&J`daDE$)|SqoUb`rmjgYU0N)4CRD!c0*XyAITJXr8~dP`d&rgzR47@!5zCtb+X>e(xDZf0dc8ul4&!%(?0`KCzuv_`CXE*6-eGecOLN zHhzxe&0xGv)LUcxv{vsArIxN1R=4jZha7WCDr0hvB*!d_KmY;|fB*y_P(%c*Jzltl z2iWKy5eY*PIM34F_cIn3ccL?YrQ~R-@^zqT!eBZHac=P(v z%XjGL-IC-M7fPN7t9g9)OG$eFjdpabO?w*lO&lK=-+**YZ}Y*^X7cMAo#)N#dk4aB`Fo;G^eT)8FQk;M3A4giS)%NoMira1 zr@c-?`5^;0@v|GgLG5dgrxF{+(gokrbf(h$jt=gnXw?2u{FE*4k$L@rCEC(P{|mad zQ~$@epOd278=k~pJ=B{2BytKLI5&`PEQsI_-5E?VcNl-Je^WBAUux)eUDDP?y7wBt z&7W-HLtS_+t@Vqd>g|is=hJTRUu)my6NY(EwO^uXaM#*oUjIag!#Zxu8`P+-Km9ZQ zG#{N_gNivu)2Sslbq@|yBi|V-JTCWrjV9D-l2?=zgA|CNES zb+!uiST{^p{OvRR`!7|ZP60pZ22P*C57Snnn!o6H^ZF}yj-*D%8qtuEO=w~{Pik8t zkbWN>NI(6$nooawnJ(#mGGA-_K$`z+dH%l>R`BNa`4$&RH^kBK&zFf}@7C@#<>-f` zAGMU-cyN)gntYZ%&>f;%Gg`C7zOMXdle$yFz@EacHlMKn)M?AkH7+mA@NXozbo!Y6 zFglu@JX=cG?2$oVEtt#ub+s2yE%}m?8ttMxH7Bs($eQHU{Tu54{{LuG@mXwJqiOmn zLNXurpuUi*naz*9lEQvX^`{FJylF;BEz^a?>wT7YC*8n{{5a<{)@Q{ev26Rp^j1|* zVM6>I#x1KyE&EI+Tifqd?Q44VCs%f<`Av^KlPBm#eP2!(7jvA|ahuON?Tsa`p1#7m zluuaA1B-O}`#q@H;8dFMVL#q;#YX;Ev9XlCs=KgqD`O4T_=*qaPb2q^ndHA{I~zK} zhs{h#r=_bLh2*dr;9}3G-=m!+X?r=1jfI*!%j5oxZ1+PTSL_3h8X(JAd$T`^pHmw!hSx z$+T;CXFjdFKdsvnK`9=W=zoTIG5OC@{9mr$^AWWN3L!%;u>*Ck>3hYM5Hd%+B2;R3 zNndV3>b8$&)TH~H@6nL+v)JVGJ85SKkuH8QeO@M&?Y~)>dO4R9r=DLy^|sv8efx7; zy7ftY+N0M~|E3~ydG}K?IBuuwM=I0K`XS6m)0DqK)97^1sZ?jyLe}oeAc{HPf!+9` zwBYXaG7J16fkuaZ$@>JZriqj74Gpd((km4^kge@sH>#o#c&sUV-($IWGim`%@#)5Q z>wG~>OFE+))b$L%{(2@APxfSy!PRNL>pptWFpYX~DQrylArujKoK^%+rQso&V&^8| ze5X0{XqPySN^~8@Ui)nu|8n_>bfANaFfVc@+nng4({1OdYP)8_`GHr&MHR2=D_`6o zHi?U(;KnH|RNqJZB4sYkuUbz?F58@qc#z80L=z3%>Lw&zUnaI&XU_sZoXKBs$fQ({ z{w&hxU5ZFLMz*&9;K?A0P0||DPxK|j_W5L2Ybo7~Eye;?Y||xXLLth0K7sjM*W?oYd>Sz7ZjQ=B{ zp1}1!C)T*?Kyl$oG-WI=lq(g%m-Tklt-o&I<2Jeq3)Yo4T&Z_X3~o`4Y;Au`VoRDn z_;a@4KLd5{L*l7+l_XjkeUN>Ya#1&SZ4zy{+<`8n|IT8Qy*)B6UZP6%j*(cqC3BqV zOtF#O$YFp+=r?>e`(Wd0e$vUqG^JMw;X=hIwyW+Mc6`_dzR`(^RKnBIu>89=9v%A~ zq;hvZpf@wzSjMR}y1jp;>JC;~M$uK5vF=fO#iRkn1c#otsmxaaEPCN&e&paGdcQKK zsN<|1?Dn?OjJ>^y=IzL!gUQ3#8(;JkS8$if*7mPxoJmc))MdiUYenZx%PD&B?^I@T z6{bo1h-!J=+hkHD`+prybKWYMn4fv7HgkKeJwRRD&Z$Bb>w+s*l-P_83y>wRhk>@QE zhBpvW9h$L#0so;Yor&6P_%H4FeIlFOA&mXD;1G38Xhm~o-}flr><)iqkPBby_1zTy zp}SafotDNa+u``Zdatnt26?q3kAUbdllvO;CyRLC{f@p~P+ zzHJWeIJurmy~D93ua{)41KdU3b)xU;cje!n{$oe4ZslmWQ!8QLFC7fq&ib=&&VE4p zVI_ph-Z8Af#x897(VevTU`b)#EiIcjX@eM3&-gbeG?voWwr7Le4WPY0wkKQLe?8Ju z=-nrrCGNf`x^KB8&ivV4*ciN8cf0KCx=EKlCie~{gmnX}h*xeU@$YOtOzCGj3P=C` zN8hWKAAjDvE$7AJu=wY_wu1A93c|Oy`?DE`b?meKdQtrN4y{UhkM$Yc znl@#gr^ZK03RgzoVWV3l@a2Zzq(;-~3)4Fi^FP{{%@%zqa$r+o+T}>`{a5blYk4H` zW!|kUoWEb3+H@<$(keEgpM4U^-|-OpP2)LaYx`fmy@#4#OJW~HP7;qE@}aY- z{i##pBJrir^Wu@=seEXgTNL$m8XNa&65BZ|m{!GoPMbWE*w0gM@J-_CvT6GbjV z9>WYa_r#w%=Qxe9aHof`x}S0X)1A^aqJwlwH;mE@AF&g2I67S2QJD4Mzr^=pVyU)U z#cBsXBk#-0`36TXv)OjZx-!A`!usaJs8KT=|6r9D6?0fgnLS| z<;C+A=jmU|jN$7=R2DWljAwV&hqF;{`qQ$Bb%inQ=8ClfNtcOUz(`WN(iyf>w~^`+VI zpR#K=E{O9FyhmZbtR9`uubmss)V?`hMZ8ivUu=hMe^zo3A)+tj1U7`88< z5&QezNGccqHH~;LRj*BJO71s~Z=3HroBZ#7&Vp|Cr@weVH7Cr|NlYz3-j!pn;`%J2ta`2EaeY5>0#neFbK)H=MSBg7|0(!0Vb+I z00Izz00bZa0SG|gc^5GIJ^;QyfbS2yNZ%hY|2_=%f9(I*|MC4Xe1Gi4`2N`Qet3rV zK>z{}fB*y_009U<00Izz00bZa0SG_<0uXpw0b8#hP1uF&N1xUn%RvAF5P$##AOHaf zK%meG;QCSAfBFT!|1_>2#r@Y` zXmeUD;r^qz|0wQ1iu;e^{-e16Xc0KNLl+Lu{v3Ne&prniMj!wI2tWV=5P$##AOHaf6dD1(#YNH$ zaWwq%Wun--wL48Y`XT8@EoCno&~AbYby&pXJ?2H}E1q z&N+?sSusg0+x{@URn=3N5I=`;%j!|fK9kAT_Ip+PnqK|Mm0fCn(__!%3A$0=mlMXt z9A|ah=Ce+FW67(hudpuV6IS!UBAxzz4{A0zl_q@HkM~@$kv~>!ETymNF09Y;G9<`l0Q|~hNzP@6o@9Cw}_Oz)& zI-B^;AAH=tGJ>t`FSTYe?b_X$PwVba>-I!YipM4TpCMjM{<9SSm+SX@MD2k>$k0pd zK%Hy)UU4Oa%n`2$mD*j>ms^m!?V}kr>Hg+>H01m&Hu?Nc+8IKmi(gEimq}&&Z&s#W z&gI0Z=T}g@E%$Wa{@j*seNvzH==IdUsmNU3{ge!j+v)m|%Cxh72=mc2xI4Yf0)I%L(V<`RK7p%g;$(Y6gKLTOO2rOjYx~!Yswe~= zYs%jDST5d-T0m2Ly7ApQUl7xh&gcepJ;SfRo=L@%Jy~RMb(-(Gj~+Bkqh4GJ8`FIV zMFbwF6~R+!cu1z$xk)(RY0f;_C61#KU5ByPe%r>sTz(=Q=-?vEi=4?eC%Wi#+c~P* zu99L<6_F2}#$N ziS5?ev%n8$@)sO3Db=Gti}ZPyB9e}gt?fT}GKgZ6w1)H(eaWzWKH1e;N;hMRv49oZ zbcy5diu>!d73wWNt~VskPa3mNWHS;)mT{F=SHZ=F zF=?Bb*VKdhS-&*n|467OaJ|ooHLf~PTzC>q8OsahN=5Kxy$6L z>YWpVTT~-k+aHtIlBN&-oGtjzK%M)Lc&c3`iIzqmWS^y6)Qw%6L|ZO*pbP20v)E*B zkBp0#s8YRSB-U=p9A`RHY-Bfb7@!gQ4WG?E*tnXXbn-Aw=~Y6wP%(<_s=J0AAGU#S zbYdcv@N_gR|E`Tk$9@N?+}#i8%?vk|acYfj?_a69gO!$1bk$|7d(>VrX+SZ-q33NX z^Hl(gUO1T_Ie3WPugodxIBN&Hy{$B3Z*QV`J2L2C@-X(s7d^!l+-0)0{VN)0QqwMV zneg&j(RtHyiXQwsm6=?HY0^Go-wH?gjIO6?Nwa-y9PW4|ppL>&`a(VW@$ zJ<2z`!yg&s!q<9zH-&%bF4kP9rLhx}cw5`=opFHD=5OOYFW03{Un@=3-s~pSHqAk#*Up_chxR8h=73uIU8F_p2F}eREihTPf21wt^75WD;}#f>`yk z4aJicDhsDVuCb2a>)7>eb7;rO^;GH|jxBk;Bx@buF6yomeOJFL|Mv7BJ9>31N5h?3 z3HyHOVAyunpM7)o1JVyGAyoE`VGTBRVbhQ9q{RnI3iEDh*}O>`#F%=UMrRnmK`&*0XyDf2uvK2lP+GWrf1-6DZ6H~c0wnpR(!-jSI9(Z+1H=tGeM zn+nq|M~d&ia#vr=BZ)8bZe`*8{o>T7TPc=Su?hX`lSuxKhu9z2cJON&&mmje|MKlU z)cjf!`yg_Xc=V7DolWgeoe~#`FNK~Lj|@-cL)+YfV-YT9&I0-Ryn(p1G&lU$QC_>MdM_>3X0 zl(1>Nm>PGFpF908ewu4Ct#z!x*82@L9&;5VTid^+XGP&__gn1F53}iw+QHAr`|@(W!O_cXwq3HWOt8JMzWFd})J(@eSmi~<99B|h zkJp9m#olI#2P?7n*3F}kmpTYvo~*=bT@Pa!?^YMK-`+tLY7`g!ntiY9!t}J;b2|T5 z)2-~wFF)kJ&>tgP+dpVj8uf6R#1?P$V5tH3X<^xG^k$8ry8eIf=Y2|*pzal8sYU!s zR=1WfCANB7KYwXop@C<4@qER3`qwgJ_<9kQg-s6Q*`4*_Y}A|nv}|HsVNAQZVy~gi z#WM~g=>A3rVbq>AY}~d9qFafz^pkfTVcMZxtm#|7i!LP+>AkW|ggG^Kh*y^nV5dEA z(ruSE!s63gSnYbf`RW<(kYnG~G}U7@t8zA;=3iV)$=)+*VVANj&1af^mxqCDZNII@ z&p7_a@js6Lar}?te;ohg_#emrIR3}+KaT%#{Ez%U^8d*HBma;5Kl1;`|0Dm8{6F&l z$p1fo`Ts(5p%NMj0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOL|vDA1>ux3`AVa1YD|ZnSls>AAdkjs;38W2KeSSt*N| zmC7gz2tWV=5P$##AOHafKmY;|C?o=Sj`Y{`>QAohQuCW0dnQlNjrzWvFfQgetK&AG zb=n(CUOjzeHES~jps|;uWD% zyG#0V3sSdzG@~Zn-+Ygd|405G`G4g9k^e{jANhae|B?SMJo*1Za+wmE2>}Q|00Izz z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwx` zLMhOvm$$cu({K;W25z)<-I>?KF~8zB+%t~bx1q2`f0SG_<0uX=z1Rwwb z2ow?lJVy@Ck;8N3nzHvjmWwx|7SI%*ZhW`S7sRxrGrB=t&+zN7XHxNGPZk+mo#wml zqX!Mss27*Q#&jP-5rM~PMetM_9)jn{;W=`6jvSsNhv&%QIdXW89G)Xrc%CDN<9{6g za_t$AF)LVXBZ%CZWf9&6fzMWB1nCqF& zW*k^4mPzhR%{R=YmZuN3$MHXo|8e|}<9{6guN8aTJj|&HQGgYYEEFm zku}My`#048{r}OX;Q5Icc+-rMTBZw&*ZVB* zPP%~?`Ekx^tj~%`V%heG>8+}s!i4xaj9XTZTK1Vtw*LRcs~V2~ar}?te;of0)VU9d zr`lDLXle98_F2kB-PpBBwB>RKx{&@mi%s_S$hdfkD%CqiV(pg9ai%lHMs_2I0UDv- z@Y(ExjX3_t@js6Lar}?te;of8p5y;Qa+wmE2>}Q|00Izz00bZa0SG_<0uX=z1Rwwb z2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$## rAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwx`LMiZnwU7fm diff --git a/tests/integrated/test-io_hdf5/runtest b/tests/integrated/test-io_hdf5/runtest index 0457c75bdc..ec6e65c076 100755 --- a/tests/integrated/test-io_hdf5/runtest +++ b/tests/integrated/test-io_hdf5/runtest @@ -19,8 +19,8 @@ shell_safe("make > make.log") # Read benchmark values -vars = ['ivar', 'rvar', 'f2d', 'f3d', 'fperp', 'fperp2', 'ivar_evol', 'rvar_evol', - 'v2d_evol_x', 'v2d_evol_y', 'v2d_evol_z', 'fperp2_evol'] +vars = ['ivar', 'rvar', 'bvar', 'f2d', 'f3d', 'fperp', 'fperp2', 'ivar_evol', 'rvar_evol', + 'bvar_evol', 'v2d_evol_x', 'v2d_evol_y', 'v2d_evol_z', 'fperp2_evol'] field_vars = ['f2d', 'f3d', 'fperp', 'fperp2', 'v2d_evol_x', 'v2d_evol_y', 'v2d_evol_z', 'fperp2_evol'] # Field quantities, not scalars diff --git a/tests/integrated/test-io_hdf5/test_io.grd.hdf5 b/tests/integrated/test-io_hdf5/test_io.grd.hdf5 index fd29cfdd9682b347341ff311502161b10c10b342..cf9ef5057dc409bf16f1b43c56a758cd68d86fa7 100644 GIT binary patch delta 252 zcmX?*c%pEE2Ga?PiCQU)OcVPRxhxnUpuuS4s&|Z19w z4=aNQROW!e#Eo*3Em#&z7GOKI`4sCnEoDXqb_Pa}G?)NU5@5xQj1U1JIk}tFp6P(a z|+#n1I9vCIGj>GC%+T delta 79 zcmX?6cp!0t2Gaq9iCQU)j1&7685K4sihgI5@^EzwU;u&$5CH@p5Q^ah)8tczewziD a)fgE$CdacZoZMlwU~+get(ivar, "ivar"); mesh->get(rvar, "rvar"); + mesh->get(bvar, "bvar"); mesh->get(f2d, "f2d"); mesh->get(f3d, "f3d"); mesh->get(fperp, "fperp"); @@ -42,6 +44,7 @@ int main(int argc, char **argv) { // Non-evolving variables dump.add(ivar, "ivar", false); dump.add(rvar, "rvar", false); + dump.add(bvar, "bvar", false); dump.add(f2d, "f2d", false); dump.add(f3d, "f3d", false); dump.add(fperp, "fperp", false); @@ -50,6 +53,7 @@ int main(int argc, char **argv) { // Evolving variables dump.add(ivar_evol, "ivar_evol", true); dump.add(rvar_evol, "rvar_evol", true); + dump.add(bvar_evol, "bvar_evol", true); dump.add(v2d, "v2d_evol", true); dump.add(v3d, "v3d_evol", true); dump.add(fperp2_evol, "fperp2_evol", true); @@ -57,9 +61,11 @@ int main(int argc, char **argv) { int MYPE; MPI_Comm_rank(BoutComm::get(), &MYPE); + bvar_evol = bvar; for(int i=0;i<3;i++) { ivar_evol = ivar + i; rvar_evol = rvar + 0.5 * i; + bvar_evol = !bvar_evol; v2d.x = v2d.y = v2d.z = f2d; v3d.x = v3d.y = v3d.z = f3d; fperp2_evol = fperp2; From d46aa7052d27c2c8e7a1daffc8adee43ae3ae8fc Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 6 Aug 2019 16:51:16 +0100 Subject: [PATCH 1708/1783] More informative error messages for Datafile::add(bool) Updates the new bool overload of Datafile::add() with more informative error messages for file opening failure, following the pattern of the other overloads. --- src/fileio/datafile.cxx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index d008aa6fbc..c4d4501256 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -577,8 +577,15 @@ void Datafile::add(bool &b, const char *name, bool save_repeat) { // Check filename has been set if (strcmp(filename, "") == 0) throw BoutException("Datafile::add: Filename has not been set"); - if(!file->openw(filename, BoutComm::rank(), appending)) - throw BoutException("Datafile::add: Failed to open file!"); + if(!file->openw(filename, BoutComm::rank(), appending)) { + if (appending) { + throw BoutException("Datafile::add: Failed to open file %s for appending!", + filename); + } else { + throw BoutException("Datafile::add: Failed to open file %s for writing!", + filename); + } + } appending = true; } From a32718ea96f379a39ac4fbdc997d1e17b964d17f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 7 Aug 2019 11:27:12 +0100 Subject: [PATCH 1709/1783] Remove redundant 'allocate()' calls These are not necessary for fields created with emptyFrom(), because emptyFrom() already allocates the field. --- src/field/field3d.cxx | 1 - src/physics/smoothing.cxx | 2 -- src/physics/sourcex.cxx | 9 --------- 3 files changed, 12 deletions(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 13a136ee34..9c8087b5e4 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -625,7 +625,6 @@ FieldPerp pow(const Field3D &lhs, const FieldPerp &rhs, const std::string& rgn) ASSERT1(areFieldsCompatible(lhs, rhs)); FieldPerp result{emptyFrom(rhs)}; - result.allocate(); BOUT_FOR(i, result.getRegion(rgn)) { result[i] = ::pow(lhs(i, rhs.getIndex()), rhs[i]); diff --git a/src/physics/smoothing.cxx b/src/physics/smoothing.cxx index 021b0f42d3..956aa2ed14 100644 --- a/src/physics/smoothing.cxx +++ b/src/physics/smoothing.cxx @@ -46,7 +46,6 @@ const Field3D smooth_x(const Field3D &f) { TRACE("smooth_x"); Mesh *mesh = f.getMesh(); Field3D result{emptyFrom(f)}; - result.allocate(); // Copy boundary region for(int jy=0;jyLocalNy;jy++) @@ -74,7 +73,6 @@ const Field3D smooth_y(const Field3D &f) { TRACE("smooth_y"); Mesh *mesh = f.getMesh(); Field3D result{emptyFrom(f)}; - result.allocate(); // Copy boundary region for(int jx=0;jxLocalNx;jx++) diff --git a/src/physics/sourcex.cxx b/src/physics/sourcex.cxx index 3fc10228f3..82b23de367 100644 --- a/src/physics/sourcex.cxx +++ b/src/physics/sourcex.cxx @@ -22,7 +22,6 @@ const Field2D source_tanhx(const Field2D &f, BoutReal swidth, BoutReal slength) Mesh* localmesh = f.getMesh(); Field2D result{emptyFrom(f)}; - result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -43,8 +42,6 @@ const Field2D source_expx2(const Field2D &f, BoutReal swidth, BoutReal slength) Field2D result{emptyFrom(f)}; - result.allocate(); - // create a radial buffer zone to set jpar zero near radial boundary BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal lx = localmesh->GlobalX(i.x()) - slength; @@ -64,7 +61,6 @@ const Field3D sink_tanhx(const Field2D &UNUSED(f0), const Field3D &f, BoutReal s Mesh* localmesh = f.getMesh(); Field3D result{emptyFrom(f)}; - result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -86,7 +82,6 @@ const Field3D mask_x(const Field3D &f, bool UNUSED(BoutRealspace)) { Mesh* localmesh = f.getMesh(); Field3D result{emptyFrom(f)}; - result.allocate(); // create a radial buffer zone to set jpar zero near radial boundary BOUT_FOR(i, result.getRegion("RGN_ALL")) { @@ -112,8 +107,6 @@ const Field3D sink_tanhxl(const Field2D &UNUSED(f0), const Field3D &f, BoutReal Field3D result{emptyFrom(f)}; - result.allocate(); - BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal lx = localmesh->GlobalX(i.x()) - slength; BoutReal dampl = TanH(lx / swidth); @@ -135,7 +128,6 @@ const Field3D sink_tanhxr(const Field2D &UNUSED(f0), const Field3D &f, BoutReal Mesh* localmesh = f.getMesh(); Field3D result{emptyFrom(f)}; - result.allocate(); BOUT_FOR(i, result.getRegion("RGN_ALL")) { BoutReal rlx = 1. - localmesh->GlobalX(i.x()) - slength; @@ -157,7 +149,6 @@ const Field3D buff_x(const Field3D &f, bool UNUSED(BoutRealspace)) { Mesh* localmesh = f.getMesh(); Field3D result{emptyFrom(f)}; - result.allocate(); const BoutReal dampl = 1.e0; const BoutReal dampr = 1.e0; From fb03bc1582bb1fff6572a2719204df769e57855a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 20 Aug 2019 17:31:26 +0100 Subject: [PATCH 1710/1783] Implement the INVERT_ZERO_DC flag in LaplaceCyclic --- .../laplace/impls/cyclic/cyclic_laplace.cxx | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index 6c44a4b85e..f1502d50a9 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -232,9 +232,19 @@ FieldPerp LaplaceCyclic::solve(const FieldPerp& rhs, const FieldPerp& x0) { auto k1d = Array((localmesh->LocalNz) / 2 + 1); // ZFFT routine expects input of this length + int startz = 0; + if(global_flags & INVERT_ZERO_DC) { + // No DC component + startz = 1; + } + BOUT_OMP(for nowait) for (int ix = xs; ix <= xe; ix++) { - for (int kz = 0; kz < nmode; kz++) + if (startz == 1) { + k1d[0] = 0.; + } + + for (int kz = startz; kz < nmode; kz++) k1d[kz] = xcmplx(kz, ix - xs); for (int kz = nmode; kz < (localmesh->LocalNz) / 2 + 1; kz++) @@ -440,13 +450,23 @@ Field3D LaplaceCyclic::solve(const Field3D& rhs, const Field3D& x0) { auto k1d = Array((localmesh->LocalNz) / 2 + 1); // ZFFT routine expects input of this length + int startz = 0; + if(global_flags & INVERT_ZERO_DC) { + // No DC component + startz = 1; + } + BOUT_OMP(for nowait) for (int ind = 0; ind < nxny; ++ind) { // Loop over X and Y // ind = (ix - xs)*(ye - ys + 1) + (iy - ys) int ix = xs + ind / ny; int iy = ys + ind % ny; - for (int kz = 0; kz < nmode; kz++) + if (startz == 1) { + k1d[0] = 0.; + } + + for (int kz = startz; kz < nmode; kz++) k1d[kz] = xcmplx3D((iy - ys) * nmode + kz, ix - xs); for (int kz = nmode; kz < localmesh->LocalNz / 2 + 1; kz++) From 894b30db62e80d9991001cfeb8ec0f626096a573 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 22 Aug 2019 09:35:22 +0100 Subject: [PATCH 1711/1783] Remove checks that fail if outloc==CELL_DEFAULT The checks were redundant anyway. --- src/mesh/coordinates.cxx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 018653b656..494318882b 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -1437,8 +1437,6 @@ Field2D Coordinates::Laplace(const Field2D& f, CELL_LOC outloc) { Field2D result = G1 * DDX(f, outloc) + G2 * DDY(f, outloc) + g11 * D2DX2(f, outloc) + g22 * D2DY2(f, outloc) + 2.0 * g12 * D2DXDY(f, outloc); - ASSERT2(result.getLocation() == outloc); - return result; } @@ -1452,7 +1450,5 @@ Field3D Coordinates::Laplace(const Field3D& f, CELL_LOC outloc) { + 2.0 * (g12 * D2DXDY(f, outloc) + g13 * D2DXDZ(f, outloc) + g23 * D2DYDZ(f, outloc)); - ASSERT2(result.getLocation() == f.getLocation()); - return result; } From 476938af9dd4dffdf11f4a88c5f1930ee8f29d85 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Tue, 27 Aug 2019 14:25:04 +0100 Subject: [PATCH 1712/1783] Add manual section on xlC compiler Error in variant when compiling with IBM xlC compiler. --- manual/sphinx/user_docs/advanced_install.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/manual/sphinx/user_docs/advanced_install.rst b/manual/sphinx/user_docs/advanced_install.rst index 3bf858386a..f777260719 100644 --- a/manual/sphinx/user_docs/advanced_install.rst +++ b/manual/sphinx/user_docs/advanced_install.rst @@ -772,3 +772,22 @@ to .. code-block:: cpp typedef long CVODEINT; + +Compiling with IBM xlC compiler fails +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When using the ``xlC`` compiler, an error may occur:: + + variant.hpp(1568) parameter pack "Ts" was referenced but not expanded + + +The workaround is to change line 428 of ``externalpackages/mpark.variant/include/mpark/lib.hpp`` from:: + + #ifdef MPARK_TYPE_PACK_ELEMENT + +to:: + + #ifdef CAUSES_ERROR // MPARK_TYPE_PACK_ELEMENT + +This will force an alternate implementation of type_pack_element to be defined. +See also https://software.intel.com/en-us/forums/intel-c-compiler/topic/501502 From d9e8d28b2c6cc71ccbed1b0798e6bdfa6ce6e191 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 29 Aug 2019 17:37:58 +0100 Subject: [PATCH 1713/1783] Fix initial conditions not being transformed correctly The result field for creating initial conditions was always set to be un-aligned, which resulted in the transform being a no-op. --- src/field/field_factory.cxx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index 15100e61e0..e6f1c37231 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -175,9 +175,10 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC throw BoutException("Couldn't create 3D field from null generator"); } - Field3D result(localmesh); - result.allocate(); - result.setLocation(loc); + const auto y_direction = + transform_from_field_aligned ? YDirectionType::Aligned : YDirectionType::Standard; + + auto result = Field3D(localmesh).setLocation(loc).setDirectionY(y_direction).allocate(); switch (loc) { case CELL_XLOW: { @@ -257,9 +258,10 @@ FieldPerp FieldFactory::createPerp(FieldGeneratorPtr gen, Mesh* localmesh, CELL_ throw BoutException("Couldn't create FieldPerp from null generator"); } - FieldPerp result(localmesh); - result.allocate(); - result.setLocation(loc); + const auto y_direction = + transform_from_field_aligned ? YDirectionType::Aligned : YDirectionType::Standard; + + auto result = FieldPerp(localmesh).setLocation(loc).setDirectionY(y_direction).allocate(); switch (loc) { case CELL_XLOW: { From 653d9cc4e1cac08e25c0a31ccdebd70738839b44 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 4 Sep 2019 19:11:39 +0200 Subject: [PATCH 1714/1783] Implement boundary conditions for CELL_ZLOW fields Previously, in several of the boundary conditions if the field was at CELL_ZLOW, the apply() method silently did nothing, leaving the boundary cells unset. --- src/mesh/boundary_standard.cxx | 158 +++++++++++++++++++++++++++++++-- 1 file changed, 150 insertions(+), 8 deletions(-) diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 60df63a8d3..166c1b3306 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -141,7 +141,7 @@ void BoundaryDirichlet::apply(Field2D &f,BoutReal t) { // Check for staggered grids CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { + if(mesh->StaggerGrids and (loc == CELL_XLOW or loc == CELL_YLOW)) { // Staggered. Need to apply slightly differently if( loc == CELL_XLOW ) { @@ -481,6 +481,69 @@ void BoundaryDirichlet::apply(Field3D &f,BoutReal t) { } } } + } else if (loc == CELL_ZLOW) { + // Shifted in Z + + for(; !bndry->isDone(); bndry->next1d()) { + // Calculate the X and Y normalised values half-way between the guard cell and grid cell + BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell + + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell + + BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell + + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*(zk - 0.5)/(mesh->LocalNz), t); + } + f(bndry->x,bndry->y,zk) = 2*val - f(bndry->x-bndry->bx, bndry->y-bndry->by, zk); + + // We've set the first boundary point using extrapolation in + // the line above. The below block of code is attempting to + // set the rest of the boundary cells also using + // extrapolation. Whilst this choice doesn't impact 2nd order + // methods it has been observed that with higher order + // methods, which actually use these points, the use of + // extrapolation can be unstable. For this reason we have + // commented out the below block and replaced it with the loop + // several lines below, which just sets all the rest of the + // boundary points to be the specified value. We've not + // removed the commented out code as we may wish to revisit + // this in the future, however it may be that this is + // eventually removed. It can be noted that we *don't* apply + // this treatment for other boundary treatments, + // i.e. elsewhere we tend to extrapolate. + + // // Need to set second guard cell, as may be used for interpolation or upwinding derivatives + // for(int i=1;iwidth;i++) { + // int xi = bndry->x + i*bndry->bx; + // int yi = bndry->y + i*bndry->by; + + // f(xi, yi, zk) = 2*f(xi - bndry->bx, yi - bndry->by, zk) - f(xi - 2*bndry->bx, yi - 2*bndry->by, zk); + // // f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + + // } + } + + // This loop is our alternative approach to setting the rest of the boundary + // points. Instead of extrapolating we just use the generated values. This + // can help with the stability of higher order methods. + for (int i = 1; i < bndry->width; i++) { + // Set any other guard cells using the values on the cells + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + xnorm = mesh->GlobalX(xi); + ynorm = mesh->GlobalY(yi); + for(int zk=0;zkLocalNz;zk++) { + if(fg) { + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*(zk - 0.5)/(mesh->LocalNz), t); + } + f(xi, yi, zk) = val; + } + } + } + } else { + throw BoutException("Unrecognised location"); } } else { @@ -599,7 +662,7 @@ void BoundaryDirichlet_O3::apply(Field2D &f,BoutReal t) { // Check for staggered grids CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { + if(mesh->StaggerGrids and (loc == CELL_XLOW or loc == CELL_YLOW)) { // Staggered. Need to apply slightly differently if( loc == CELL_XLOW) { @@ -935,6 +998,34 @@ void BoundaryDirichlet_O3::apply(Field3D &f,BoutReal t) { } } } + } else if (loc == CELL_ZLOW) { + // Shifted in Z + + for(; !bndry->isDone(); bndry->next1d()) { + // Calculate the X and Y normalised values half-way between the guard cell and grid cell + BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell + + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell + + BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell + + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + for(int zk=0;zkLocalNz;zk++) { + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*(zk - 0.5)/(mesh->LocalNz), t); + + f(bndry->x,bndry->y,zk) = (8./3)*val - 2.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk)/3.; + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 3.0*f(xi - bndry->bx, yi - bndry->by, zk) - 3.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + f(xi - 3*bndry->bx, yi - 3*bndry->by, zk); + } + } + } + } else { + throw BoutException("Unrecognized location"); } } else { @@ -1020,7 +1111,7 @@ void BoundaryDirichlet_O4::apply(Field2D &f,BoutReal t) { // Check for staggered grids CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { + if(mesh->StaggerGrids and (loc == CELL_XLOW or loc == CELL_YLOW)) { // Staggered. Need to apply slightly differently if(loc == CELL_XLOW ) { @@ -1373,6 +1464,33 @@ void BoundaryDirichlet_O4::apply(Field3D &f,BoutReal t) { } } } + } else if (loc == CELL_ZLOW) { + // Shifted in Z + for(; !bndry->isDone(); bndry->next1d()) { + // Calculate the X and Y normalised values half-way between the guard cell and grid cell + BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell + + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell + + BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell + + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + for(int zk=0;zkLocalNz;zk++) { + if(fg) + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*(zk - 0.5)/(mesh->LocalNz), t); + + f(bndry->x,bndry->y,zk) = (16./5)*val - 3.*f(bndry->x-bndry->bx, bndry->y-bndry->by,zk) + f(bndry->x-2*bndry->bx, bndry->y-2*bndry->by,zk) - (1./5)*f(bndry->x-3*bndry->bx, bndry->y-3*bndry->by,zk); + + // Need to set remaining guard cells, as may be used for interpolation or upwinding derivatives + for(int i=1;iwidth;i++) { + int xi = bndry->x + i*bndry->bx; + int yi = bndry->y + i*bndry->by; + f(xi, yi, zk) = 4.0*f(xi - bndry->bx, yi - bndry->by, zk) - 6.0*f(xi - 2*bndry->bx, yi - 2*bndry->by, zk) + + 4.0*f(xi - 3*bndry->bx, yi - 3*bndry->by, zk) - f(xi - 4*bndry->bx, yi - 4*bndry->by, zk); + } + } + } + } else { + throw BoutException("Unrecognized location"); } } else { @@ -1604,7 +1722,7 @@ void BoundaryNeumann::apply(Field2D &f,BoutReal t) { // Check for staggered grids CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { + if(mesh->StaggerGrids and (loc == CELL_XLOW or loc == CELL_YLOW)) { // Staggered. Need to apply slightly differently // Use one-sided differencing. Cell is now on // the boundary, so use one-sided differencing @@ -1959,6 +2077,30 @@ void BoundaryNeumann::apply(Field3D &f,BoutReal t) { } } } + } else if (loc == CELL_ZLOW) { + // Shifted in Z + for(; !bndry->isDone(); bndry->next1d()) { + // Calculate the X and Y normalised values half-way between the guard cell and grid cell + BoutReal xnorm = 0.5*( mesh->GlobalX(bndry->x) // In the guard cell + + mesh->GlobalX(bndry->x - bndry->bx) ); // the grid cell + + BoutReal ynorm = 0.5*( mesh->GlobalY(bndry->y) // In the guard cell + + mesh->GlobalY(bndry->y - bndry->by) ); // the grid cell + + BoutReal delta = bndry->bx*metric->dx(bndry->x,bndry->y)+bndry->by*metric->dy(bndry->x,bndry->y); + + for(int zk=0;zkLocalNz;zk++) { + if(fg){ + val = fg->generate(xnorm,TWOPI*ynorm,TWOPI*(zk - 0.5)/(mesh->LocalNz),t); + } + f(bndry->x,bndry->y, zk) = f(bndry->x-bndry->bx, bndry->y-bndry->by, zk) + delta*val; + if (bndry->width == 2){ + f(bndry->x + bndry->bx, bndry->y + bndry->by, zk) = f(bndry->x - 2*bndry->bx, bndry->y - 2*bndry->by, zk) + 3.0*delta*val; + } + } + } + } else { + throw BoutException("Unrecognized location"); } } else { @@ -2721,7 +2863,7 @@ void BoundaryFree_O2::apply(Field2D &f) { // Check for staggered grids CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { + if(mesh->StaggerGrids and (loc == CELL_XLOW or loc == CELL_YLOW)) { // Staggered. Need to apply slightly differently if( loc == CELL_XLOW) { @@ -2820,7 +2962,7 @@ void BoundaryFree_O2::apply(Field3D &f) { // Check for staggered grids CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { + if(mesh->StaggerGrids and (loc == CELL_XLOW or loc == CELL_YLOW)) { // Staggered. Need to apply slightly differently if( loc == CELL_XLOW ) { @@ -2963,7 +3105,7 @@ void BoundaryFree_O3::apply(Field2D &f) { // Check for staggered grids CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { + if(mesh->StaggerGrids and (loc == CELL_XLOW or loc == CELL_YLOW)) { // Staggered. Need to apply slightly differently if( loc == CELL_XLOW) { @@ -3064,7 +3206,7 @@ void BoundaryFree_O3::apply(Field3D &f) { // Check for staggered grids CELL_LOC loc = f.getLocation(); - if(mesh->StaggerGrids && loc != CELL_CENTRE) { + if(mesh->StaggerGrids and (loc == CELL_XLOW or loc == CELL_YLOW)) { // Staggered. Need to apply slightly differently if( loc == CELL_XLOW ) { From 97f0d9eb31dbda0f1b1445031237390a89a148b9 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 11 Sep 2019 10:52:49 +0100 Subject: [PATCH 1715/1783] Fix yupydown test: wrong y-direction returned from DDYs --- tests/integrated/test-yupdown/test_yupdown.cxx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/integrated/test-yupdown/test_yupdown.cxx b/tests/integrated/test-yupdown/test_yupdown.cxx index 57d4b9e41a..39da3443cc 100644 --- a/tests/integrated/test-yupdown/test_yupdown.cxx +++ b/tests/integrated/test-yupdown/test_yupdown.cxx @@ -5,10 +5,7 @@ // Y derivative using yup() and ydown() fields const Field3D DDY_yud(const Field3D &f) { - Field3D result; - result.allocate(); - - result = 0.0; + Field3D result = emptyFrom(f); for(int i=0;iLocalNx;i++) for(int j=mesh->ystart;j<=mesh->yend;j++) @@ -20,9 +17,7 @@ const Field3D DDY_yud(const Field3D &f) { // Y derivative assuming field is aligned in Y const Field3D DDY_aligned(const Field3D &f) { - Field3D result; - result.allocate(); - result = 0.0; + Field3D result = emptyFrom(f); for(int i=0;iLocalNx;i++) for(int j=mesh->ystart;j<=mesh->yend;j++) From bd1e222843195e86cf0a838e9e9768fa830f0684 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 11 Sep 2019 10:53:37 +0100 Subject: [PATCH 1716/1783] Clang-format test-yupydown --- .../integrated/test-yupdown/test_yupdown.cxx | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/integrated/test-yupdown/test_yupdown.cxx b/tests/integrated/test-yupdown/test_yupdown.cxx index 39da3443cc..dc1d09e971 100644 --- a/tests/integrated/test-yupdown/test_yupdown.cxx +++ b/tests/integrated/test-yupdown/test_yupdown.cxx @@ -4,26 +4,26 @@ #include // Y derivative using yup() and ydown() fields -const Field3D DDY_yud(const Field3D &f) { +const Field3D DDY_yud(const Field3D& f) { Field3D result = emptyFrom(f); - - for(int i=0;iLocalNx;i++) - for(int j=mesh->ystart;j<=mesh->yend;j++) - for(int k=0;kLocalNz;k++) - result(i,j,k) = 0.5*(f.yup()(i,j+1,k) - f.ydown()(i,j-1,k)); + + for (int i = 0; i < mesh->LocalNx; i++) + for (int j = mesh->ystart; j <= mesh->yend; j++) + for (int k = 0; k < mesh->LocalNz; k++) + result(i, j, k) = 0.5 * (f.yup()(i, j + 1, k) - f.ydown()(i, j - 1, k)); return result; } // Y derivative assuming field is aligned in Y -const Field3D DDY_aligned(const Field3D &f) { +const Field3D DDY_aligned(const Field3D& f) { Field3D result = emptyFrom(f); - - for(int i=0;iLocalNx;i++) - for(int j=mesh->ystart;j<=mesh->yend;j++) - for(int k=0;kLocalNz;k++) - result(i,j,k) = 0.5*(f(i,j+1,k) - f(i,j-1,k)); - + + for (int i = 0; i < mesh->LocalNx; i++) + for (int j = mesh->ystart; j <= mesh->yend; j++) + for (int k = 0; k < mesh->LocalNz; k++) + result(i, j, k) = 0.5 * (f(i, j + 1, k) - f(i, j - 1, k)); + return result; } @@ -41,12 +41,12 @@ int main(int argc, char** argv) { mesh->get(var, "var"); Field3D var2 = copy(var); - + // Var starts in orthogonal X-Z coordinates // Calculate yup and ydown s.calcParallelSlices(var); - + // Calculate d/dy using yup() and ydown() fields Field3D ddy = DDY(var); @@ -56,13 +56,13 @@ int main(int argc, char** argv) { // Change into field-aligned coordinates Field3D var_aligned = toFieldAligned(var); - + // var now field aligned Field3D ddy_check = DDY_aligned(var_aligned); - + // Shift back to orthogonal X-Z coordinates ddy_check = fromFieldAligned(ddy_check); - + SAVE_ONCE3(ddy, ddy2, ddy_check); dump.write(); From 7a03c5c712d1223fca957ac4050e7dbf6f0e5f32 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 11 Sep 2019 15:27:48 +0100 Subject: [PATCH 1717/1783] Fix bug with wrong y-direction type for input fields when using FCI FCI can't transform into/out of field-aligned coordinates, but default is for input fields (via FieldFactory::create3D) to be initially created in aligned coordinates and transformed back. --- src/field/field_factory.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/field/field_factory.cxx b/src/field/field_factory.cxx index e6f1c37231..d7f3c00eed 100644 --- a/src/field/field_factory.cxx +++ b/src/field/field_factory.cxx @@ -232,6 +232,8 @@ Field3D FieldFactory::create3D(FieldGeneratorPtr gen, Mesh* localmesh, CELL_LOC // Transform from field aligned coordinates, to be compatible with // older BOUT++ inputs. This is not a particularly "nice" solution. result = fromFieldAligned(result, "RGN_ALL"); + } else { + result.setDirectionY(YDirectionType::Standard); } } From c5abb7cb4f9946c0f09e61faa91fca318eb88f20 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 11 Sep 2019 16:21:54 +0100 Subject: [PATCH 1718/1783] Fix shifted metric tests: round-trip tests had wrong argument --- tests/unit/mesh/parallel/test_shiftedmetric.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 1cef81f836..2da2b53186 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -124,7 +124,7 @@ TEST_F(ShiftedMetricTest, ToFieldAligned) { EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_ALL", FFTTolerance)); - EXPECT_TRUE(IsFieldEqual(fromFieldAligned(input), input)); + EXPECT_TRUE(IsFieldEqual(fromFieldAligned(result), input)); EXPECT_TRUE(areFieldsCompatible(result, expected)); EXPECT_FALSE(areFieldsCompatible(result, input)); } @@ -166,7 +166,7 @@ TEST_F(ShiftedMetricTest, FromFieldAligned) { // Loosen tolerance a bit due to FFTs EXPECT_TRUE(IsFieldEqual(result, expected, "RGN_ALL", FFTTolerance)); - EXPECT_TRUE(IsFieldEqual(toFieldAligned(input), input)); + EXPECT_TRUE(IsFieldEqual(toFieldAligned(result), input)); EXPECT_TRUE(areFieldsCompatible(result, expected)); EXPECT_FALSE(areFieldsCompatible(result, input)); } @@ -217,7 +217,7 @@ TEST_F(ShiftedMetricTest, ToFieldAlignedFieldPerp) { // FieldPerp does not have a getRegion2D() method. Values are never set in // the x-guard or x-boundary cells EXPECT_TRUE(IsFieldEqual(result, sliceXZ(expected, 3), "RGN_NOBNDRY", FFTTolerance)); - EXPECT_TRUE(IsFieldEqual(fromFieldAligned(sliceXZ(input,2)), sliceXZ(input, 2))); + EXPECT_TRUE(IsFieldEqual(fromFieldAligned(result), sliceXZ(input, 3))); EXPECT_TRUE(areFieldsCompatible(result, sliceXZ(expected, 3))); EXPECT_FALSE(areFieldsCompatible(result, sliceXZ(input, 3))); } @@ -260,7 +260,7 @@ TEST_F(ShiftedMetricTest, FromFieldAlignedFieldPerp) { // FieldPerp does not have a getRegion2D() method. Values are never set in // the x-guard or x-boundary cells EXPECT_TRUE(IsFieldEqual(result, sliceXZ(expected, 4), "RGN_NOBNDRY", FFTTolerance)); - EXPECT_TRUE(IsFieldEqual(toFieldAligned(sliceXZ(input, 0)), sliceXZ(input, 0))); + EXPECT_TRUE(IsFieldEqual(toFieldAligned(result), sliceXZ(input, 4))); EXPECT_TRUE(areFieldsCompatible(result, sliceXZ(expected, 4))); EXPECT_FALSE(areFieldsCompatible(result, sliceXZ(input, 4))); } From f7b68923d7c825502841e65076b0125b8fb16b3a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 11 Sep 2019 16:22:13 +0100 Subject: [PATCH 1719/1783] Fix deprecation warning in FCI MMS test --- tests/MMS/spatial/fci/fci_mms.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/MMS/spatial/fci/fci_mms.cxx b/tests/MMS/spatial/fci/fci_mms.cxx index dc250d55b7..4c780661a9 100644 --- a/tests/MMS/spatial/fci/fci_mms.cxx +++ b/tests/MMS/spatial/fci/fci_mms.cxx @@ -13,8 +13,8 @@ int main(int argc, char** argv) { Field3D result{Grad_par(input)}; Field3D error{result - solution}; - BoutReal l_2{sqrt(mean(SQ(error), true, RGN_NOBNDRY))}; - BoutReal l_inf{max(abs(error), true, RGN_NOBNDRY)}; + BoutReal l_2{sqrt(mean(SQ(error), true, "RGN_NOBNDRY"))}; + BoutReal l_inf{max(abs(error), true, "RGN_NOBNDRY")}; SAVE_ONCE6(input, solution, result, error, l_2, l_inf); From e969b4767fd2618c6cbe64aa30ae35de176f37a5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 12 Sep 2019 16:51:15 +0100 Subject: [PATCH 1720/1783] Require inputs to to/fromFieldAligned to be in the correct space That is, to/fromFieldAligned are never no-ops. Also requires the FieldPerp overloads to be over RGN_NOX: this region is essentially hardcoded currently, so accepting other regions could be confusing. The y-derivatives still accept fields in either space, and will transform unaligned fields if necessary, returning the result in the same space as the input field. The flow derivatives now require both fields to be in the same space. --- include/bout/index_derivs_interface.hxx | 35 ++++++---- src/mesh/parallel/shiftedmetric.cxx | 70 +++++-------------- .../unit/mesh/parallel/test_shiftedmetric.cxx | 20 +++--- 3 files changed, 54 insertions(+), 71 deletions(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 7a2d44289f..f1cd978c6f 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -205,10 +205,11 @@ T DDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "D return standardDerivative(f, outloc, method, region); } else { - const T f_aligned = toFieldAligned(f, "RGN_NOX"); + const bool is_unaligned = (f.getDirectionY() == YDirectionType::Aligned); + const T f_aligned = is_unaligned ? toFieldAligned(f, "RGN_NOX") : f; T result = standardDerivative(f_aligned, outloc, method, region); - return fromFieldAligned(result, region); + return is_unaligned ? fromFieldAligned(result, region) : result; } } @@ -221,10 +222,11 @@ T D2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = return standardDerivative( f, outloc, method, region); } else { - const T f_aligned = toFieldAligned(f, "RGN_NOX"); + const bool is_unaligned = (f.getDirectionY() == YDirectionType::Aligned); + const T f_aligned = is_unaligned ? toFieldAligned(f, "RGN_NOX") : f; T result = standardDerivative( f_aligned, outloc, method, region); - return fromFieldAligned(result, region); + return is_unaligned ? fromFieldAligned(result, region) : result; } } @@ -237,10 +239,11 @@ T D4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = return standardDerivative( f, outloc, method, region); } else { - const T f_aligned = toFieldAligned(f, "RGN_NOX"); + const bool is_unaligned = (f.getDirectionY() == YDirectionType::Aligned); + const T f_aligned = is_unaligned ? toFieldAligned(f, "RGN_NOX") : f; T result = standardDerivative( f_aligned, outloc, method, region); - return fromFieldAligned(result, region); + return is_unaligned ? fromFieldAligned(result, region) : result; } } @@ -313,11 +316,15 @@ T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, return flowDerivative(vel, f, outloc, method, region); } else { - const T f_aligned = toFieldAligned(f, "RGN_NOX"); - const T vel_aligned = toFieldAligned(vel, "RGN_NOX"); + ASSERT2(f.getDirectionY() == vel.getDirectionY()); + const bool are_unaligned = ((f.getDirectionY() == YDirectionType::Standard) + and (vel.getDirectionY() == YDirectionType::Standard)); + + const T f_aligned = are_unaligned ? toFieldAligned(f, "RGN_NOX") : f; + const T vel_aligned = are_unaligned ? toFieldAligned(vel, "RGN_NOX") : vel; T result = flowDerivative(vel_aligned, f_aligned, outloc, method, region); - return fromFieldAligned(result, region); + return are_unaligned ? fromFieldAligned(result, region) : result; } } @@ -333,11 +340,15 @@ T FDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, return flowDerivative(vel, f, outloc, method, region); } else { - const T f_aligned = toFieldAligned(f, "RGN_NOX"); - const T vel_aligned = toFieldAligned(vel, "RGN_NOX"); + ASSERT2(f.getDirectionY() == vel.getDirectionY()); + const bool are_unaligned = ((f.getDirectionY() == YDirectionType::Standard) + and (vel.getDirectionY() == YDirectionType::Standard)); + + const T f_aligned = are_unaligned ? toFieldAligned(f, "RGN_NOX") : f; + const T vel_aligned = are_unaligned ? toFieldAligned(vel, "RGN_NOX") : vel; T result = flowDerivative(vel_aligned, f_aligned, outloc, method, region); - return fromFieldAligned(result, region); + return are_unaligned ? fromFieldAligned(result, region) : result; } } diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index b9cdc8aad6..1450478d8e 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -121,65 +121,32 @@ void ShiftedMetric::cachePhases() { * and Y is then field aligned. */ const Field3D ShiftedMetric::toFieldAligned(const Field3D& f, const std::string& region) { - switch (f.getDirectionY()) { - case (YDirectionType::Standard): - return shiftZ(f, toAlignedPhs, YDirectionType::Aligned, region); - case (YDirectionType::Aligned): - // f is already in field-aligned coordinates - return f; - default: - throw BoutException("Unrecognized y-direction type for Field3D passed to " - "ShiftedMetric::toFieldAligned"); - // This should never happen, but use 'return f' to avoid compiler warnings - return f; - } + ASSERT2(f.getDirectionY() == YDirectionType::Standard); + return shiftZ(f, toAlignedPhs, YDirectionType::Aligned, region); } -const FieldPerp ShiftedMetric::toFieldAligned(const FieldPerp& f, const std::string& region) { - switch (f.getDirectionY()) { - case (YDirectionType::Standard): - return shiftZ(f, toAlignedPhs, YDirectionType::Aligned, region); - case (YDirectionType::Aligned): - // f is already in field-aligned coordinates - return f; - default: - throw BoutException("Unrecognized y-direction type for FieldPerp passed to " - "ShiftedMetric::toFieldAligned"); - // This should never happen, but use 'return f' to avoid compiler warnings - return f; - } +const FieldPerp ShiftedMetric::toFieldAligned(const FieldPerp& f, + const std::string& region) { + ASSERT2(f.getDirectionY() == YDirectionType::Standard); + // In principle, other regions are possible, but not yet implemented + ASSERT2(region == "RGN_NOX"); + return shiftZ(f, toAlignedPhs, YDirectionType::Aligned, region); } /*! * Shift back, so that X-Z is orthogonal, * but Y is not field aligned. */ -const Field3D ShiftedMetric::fromFieldAligned(const Field3D& f, const std::string& region) { - switch (f.getDirectionY()) { - case (YDirectionType::Aligned): - return shiftZ(f, fromAlignedPhs, YDirectionType::Standard, region); - case (YDirectionType::Standard): - // f is already in orthogonal coordinates - return f; - default: - throw BoutException("Unrecognized y-direction type for Field3D passed to " - "ShiftedMetric::toFieldAligned"); - // This should never happen, but use 'return f' to avoid compiler warnings - return f; - } +const Field3D ShiftedMetric::fromFieldAligned(const Field3D& f, + const std::string& region) { + ASSERT2(f.getDirectionY() == YDirectionType::Aligned); + return shiftZ(f, fromAlignedPhs, YDirectionType::Standard, region); } -const FieldPerp ShiftedMetric::fromFieldAligned(const FieldPerp& f, const std::string& region) { - switch (f.getDirectionY()) { - case (YDirectionType::Aligned): - return shiftZ(f, fromAlignedPhs, YDirectionType::Standard, region); - case (YDirectionType::Standard): - // f is already in orthogonal coordinates - return f; - default: - throw BoutException("Unrecognized y-direction type for FieldPerp passed to " - "ShiftedMetric::toFieldAligned"); - // This should never happen, but use 'return f' to avoid compiler warnings - return f; - } +const FieldPerp ShiftedMetric::fromFieldAligned(const FieldPerp& f, + const std::string& region) { + ASSERT2(f.getDirectionY() == YDirectionType::Aligned); + // In principle, other regions are possible, but not yet implemented + ASSERT2(region == "RGN_NOX"); + return shiftZ(f, fromAlignedPhs, YDirectionType::Standard, region); } const Field3D ShiftedMetric::shiftZ(const Field3D& f, const Tensor& phs, @@ -218,6 +185,7 @@ const FieldPerp ShiftedMetric::shiftZ(const FieldPerp& f, const Tensor FieldPerp result{emptyFrom(f).setDirectionY(y_direction_out)}; int y = f.getIndex(); + // Note that this loop is essentially hardcoded to be RGN_NOX for (int i=mesh.xstart; i<=mesh.xend; ++i) { shiftZ(&f(i, 0), &phs(i, y, 0), &result(i, 0)); } diff --git a/tests/unit/mesh/parallel/test_shiftedmetric.cxx b/tests/unit/mesh/parallel/test_shiftedmetric.cxx index 2da2b53186..9fb0c421f3 100644 --- a/tests/unit/mesh/parallel/test_shiftedmetric.cxx +++ b/tests/unit/mesh/parallel/test_shiftedmetric.cxx @@ -211,13 +211,14 @@ TEST_F(ShiftedMetricTest, ToFieldAlignedFieldPerp) { {4., 5., 1., 3., 2.}, {2., 4., 3., 5., 1.}}}); - FieldPerp result = toFieldAligned(sliceXZ(input, 3)); + FieldPerp result = toFieldAligned(sliceXZ(input, 3), "RGN_NOX"); // Note that the region argument does not do anything for FieldPerp, as // FieldPerp does not have a getRegion2D() method. Values are never set in // the x-guard or x-boundary cells EXPECT_TRUE(IsFieldEqual(result, sliceXZ(expected, 3), "RGN_NOBNDRY", FFTTolerance)); - EXPECT_TRUE(IsFieldEqual(fromFieldAligned(result), sliceXZ(input, 3))); + EXPECT_TRUE(IsFieldEqual(fromFieldAligned(result, "RGN_NOX"), sliceXZ(input, 3), + "RGN_NOBNDRY", FFTTolerance)); EXPECT_TRUE(areFieldsCompatible(result, sliceXZ(expected, 3))); EXPECT_FALSE(areFieldsCompatible(result, sliceXZ(input, 3))); } @@ -254,13 +255,14 @@ TEST_F(ShiftedMetricTest, FromFieldAlignedFieldPerp) { {2., 4., 5., 1., 3.}, {5., 1., 2., 4., 3.}}}); - FieldPerp result = fromFieldAligned(sliceXZ(input, 4)); + FieldPerp result = fromFieldAligned(sliceXZ(input, 4), "RGN_NOX"); // Note that the region argument does not do anything for FieldPerp, as // FieldPerp does not have a getRegion2D() method. Values are never set in // the x-guard or x-boundary cells EXPECT_TRUE(IsFieldEqual(result, sliceXZ(expected, 4), "RGN_NOBNDRY", FFTTolerance)); - EXPECT_TRUE(IsFieldEqual(toFieldAligned(result), sliceXZ(input, 4))); + EXPECT_TRUE(IsFieldEqual(toFieldAligned(result, "RGN_NOX"), sliceXZ(input, 4), "RGN_NOBNDRY", + FFTTolerance)); EXPECT_TRUE(areFieldsCompatible(result, sliceXZ(expected, 4))); EXPECT_FALSE(areFieldsCompatible(result, sliceXZ(input, 4))); } @@ -269,8 +271,9 @@ TEST_F(ShiftedMetricTest, FromToFieldAlignedFieldPerp) { // Note that the region argument does not do anything for FieldPerp, as // FieldPerp does not have a getRegion2D() method. Values are never set in // the x-guard or x-boundary cells - EXPECT_TRUE(IsFieldEqual(fromFieldAligned(toFieldAligned(sliceXZ(input, 2))), - sliceXZ(input, 2), "RGN_NOBNDRY", FFTTolerance)); + EXPECT_TRUE(IsFieldEqual( + fromFieldAligned(toFieldAligned(sliceXZ(input, 2), "RGN_NOX"), "RGN_NOX"), + sliceXZ(input, 2), "RGN_NOBNDRY", FFTTolerance)); } TEST_F(ShiftedMetricTest, ToFromFieldAlignedFieldPerp) { @@ -279,8 +282,9 @@ TEST_F(ShiftedMetricTest, ToFromFieldAlignedFieldPerp) { // the x-guard or x-boundary cells input.setDirectionY(YDirectionType::Aligned); - EXPECT_TRUE(IsFieldEqual(toFieldAligned(fromFieldAligned(sliceXZ(input, 6))), - sliceXZ(input, 6), "RGN_NOBNDRY", FFTTolerance)); + EXPECT_TRUE(IsFieldEqual( + toFieldAligned(fromFieldAligned(sliceXZ(input, 6), "RGN_NOX"), "RGN_NOX"), + sliceXZ(input, 6), "RGN_NOBNDRY", FFTTolerance)); } TEST_F(ShiftedMetricTest, CalcParallelSlices) { From 6d188f68bf46c31549353500829069ac1a122b06 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 20 Sep 2019 16:54:12 +0100 Subject: [PATCH 1721/1783] Allow NYPE to be given instead of NXPE in input files Processor splitting could previously be set manually only by passing NXPE, with NYPE=NPES/NXPE. This commit adds the option to fix NYPE instead, with NXPE=NPES/NYPE. If neither are passed then the splitting is set automatically, as before. --- manual/sphinx/user_docs/bout_options.rst | 7 +++++ src/mesh/impls/bout/boutmesh.cxx | 40 ++++++++++++++++-------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/manual/sphinx/user_docs/bout_options.rst b/manual/sphinx/user_docs/bout_options.rst index 60065e8c85..500b1ccc46 100644 --- a/manual/sphinx/user_docs/bout_options.rst +++ b/manual/sphinx/user_docs/bout_options.rst @@ -296,6 +296,13 @@ direction can be specified: NXPE = 1 # Set number of X processors +Alternatively, the number in the Y direction can be specified (if both are +given, ``NXPE`` takes precedence and ``NYPE`` is ignored): + +.. code-block:: cfg + + NYPE = 1 # Set number of Y processors + If you need to specify complex input values, e.g. numerical values from experiment, you may want to use a grid file. The grid file to use is specified relative to the root directory where the simulation is diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 5aa9172bef..6a9004061b 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -214,25 +214,39 @@ int BoutMesh::load() { numberOfXPoints = 2; } - if (options.isSet("NXPE")) { // Specified NXPE - NXPE = options["NXPE"] - .doc("Decomposition in the radial direction. If not given then calculated " - "automatically.") - .withDefault(1); - if ((NPES % NXPE) != 0) { - throw BoutException( - _("Number of processors (%d) not divisible by NPs in x direction (%d)\n"), NPES, - NXPE); - } + if (options.isSet("NXPE") or options.isSet("NYPE")) { // Specified NXPE + if (options.isSet("NXPE")) { + NXPE = options["NXPE"] + .doc("Decomposition in the radial direction. If not given then calculated " + "automatically.") + .withDefault(1); + if ((NPES % NXPE) != 0) { + throw BoutException( + _("Number of processors (%d) not divisible by NPs in x direction (%d)\n"), NPES, + NXPE); + } - NYPE = NPES / NXPE; + NYPE = NPES / NXPE; + } else { + // NXPE not set, but NYPE is + NYPE = options["NYPE"] + .doc("Decomposition in the parallel direction. Can be given instead of " + "NXPE. If neither is given, then calculated automatically.") + .withDefault(1); + if ((NPES % NYPE) != 0) { + throw BoutException( + _("Number of processors (%d) not divisible by NPs in y direction (%d)\n"), NPES, + NYPE); + } + + NXPE = NPES / NYPE; + } - int nyp = NPES / NXPE; int ysub = ny / NYPE; // Check size of Y mesh if (ysub < MYG) { - throw BoutException("\t -> ny/NYPE (%d/%d = %d) must be >= MYG (%d)\n", ny, nyp, + throw BoutException("\t -> ny/NYPE (%d/%d = %d) must be >= MYG (%d)\n", ny, NYPE, ysub, MYG); } // Check branch cuts From c46aa223f5f8c1838c81e7624e62410fd0ac6f53 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 20 Sep 2019 18:08:22 +0100 Subject: [PATCH 1722/1783] Check all possible processor splittings in test-io Pass all possible values of NXPE and NYPE, as well as passing no argument to use the automatic splitting. --- tests/integrated/test-io/runtest | 107 ++++++++++++++++++------------- 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/tests/integrated/test-io/runtest b/tests/integrated/test-io/runtest index dc3b3fabb9..3bb477135c 100755 --- a/tests/integrated/test-io/runtest +++ b/tests/integrated/test-io/runtest @@ -40,49 +40,70 @@ for v in vars: print("Running I/O test") success = True for nproc in [1,2,4]: - cmd = "./test_io" - - # On some machines need to delete dmp files first - # or data isn't written correctly - shell("rm data/BOUT.dmp.*.nc") - - # Run test case - - print(" %d processor...." % (nproc)) - s, out = launch_safe(cmd, nproc=nproc, pipe=True) - with open("run.log."+str(nproc), "w") as f: - f.write(out) - - # Collect output data - for v in vars: - stdout.write(" Checking variable "+v+" ... ") - result = collect(v, path="data", info=False) - - # Compare benchmark and output - if np.shape(bmk[v]) != np.shape(result): - print("Fail, wrong shape") - success = False - continue - - diff = np.max(np.abs(bmk[v] - result)) - if diff > tol: - print("Fail, maximum difference = "+str(diff)) - success = False - continue - - if v in field_vars: - # Check cell location - if "cell_location" not in result.attributes: - print("Fail: {0} has no cell_location attribute".format(v)) - success = False - continue - - if result.attributes["cell_location"] != "CELL_CENTRE": - print("Fail: Expecting cell_location == CELL_CENTRE, but got {0}".format(result.attributes["cell_location"])) - success = False - continue - - print("Pass") + for split in [None, "NXPE", "NYPE"]: + if split is not None: + npe_max = nproc + else: + npe_max = 1 + for np_split in [i for i in [1,2,4] if i<=npe_max]: + + if split is not None: + extra_args = " "+split+"="+str(np_split) + else: + extra_args = "" + + cmd = "./test_io" + extra_args + + # On some machines need to delete dmp files first + # or data isn't written correctly + shell("rm data/BOUT.dmp.*.nc") + + # Run test case + print(" %d processor...." % (nproc) + extra_args) + s, out = launch_safe(cmd, nproc=nproc, pipe=True) + with open("run.log."+str(nproc), "w") as f: + f.write(out) + + # Check processor splitting + if split is not None: + stdout.write(" Checking "+split+" ... ") + v = collect(split, path="data", info=False) + if v != np_split: + print("Fail, wrong "+split+" expecting %i, got %i" % (np_split, v)) + success = False + else: + print("Pass") + + # Collect output data + for v in vars: + stdout.write(" Checking variable "+v+" ... ") + result = collect(v, path="data", info=False) + + # Compare benchmark and output + if np.shape(bmk[v]) != np.shape(result): + print("Fail, wrong shape") + success = False + continue + + diff = np.max(np.abs(bmk[v] - result)) + if diff > tol: + print("Fail, maximum difference = "+str(diff)) + success = False + continue + + if v in field_vars: + # Check cell location + if "cell_location" not in result.attributes: + print("Fail: {0} has no cell_location attribute".format(v)) + success = False + continue + + if result.attributes["cell_location"] != "CELL_CENTRE": + print("Fail: Expecting cell_location == CELL_CENTRE, but got {0}".format(result.attributes["cell_location"])) + success = False + continue + + print("Pass") if success: print(" => All I/O tests passed") From 9423cd4b385aabe92053c7336f793418b5c8146e Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 24 Sep 2019 10:45:06 +0100 Subject: [PATCH 1723/1783] Fix typo in previous commit: comparison to wrong enum value --- include/bout/index_derivs_interface.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index f1cd978c6f..f09892652a 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -205,7 +205,7 @@ T DDY(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "D return standardDerivative(f, outloc, method, region); } else { - const bool is_unaligned = (f.getDirectionY() == YDirectionType::Aligned); + const bool is_unaligned = (f.getDirectionY() == YDirectionType::Standard); const T f_aligned = is_unaligned ? toFieldAligned(f, "RGN_NOX") : f; T result = standardDerivative(f_aligned, outloc, method, region); @@ -222,7 +222,7 @@ T D2DY2(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = return standardDerivative( f, outloc, method, region); } else { - const bool is_unaligned = (f.getDirectionY() == YDirectionType::Aligned); + const bool is_unaligned = (f.getDirectionY() == YDirectionType::Standard); const T f_aligned = is_unaligned ? toFieldAligned(f, "RGN_NOX") : f; T result = standardDerivative( f_aligned, outloc, method, region); From 52f6c27de591ca0a1acfcddc6b35c06032066316 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 24 Sep 2019 15:45:37 +0100 Subject: [PATCH 1724/1783] Add unit tests to check transform is done/not done in FieldFactory --- tests/unit/field/test_field_factory.cxx | 145 ++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index 5ebeecb01d..0fc3007411 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -9,6 +9,7 @@ #include "bout/constants.hxx" #include "bout/mesh.hxx" #include "bout/traits.hxx" +#include "bout/paralleltransform.hxx" /// Global mesh namespace bout { @@ -768,3 +769,147 @@ TEST_F(FieldFactoryTest, TanhhatArgs) { EXPECT_THROW(factory.parse("tanhhat()"), ParseException); EXPECT_THROW(factory.parse("tanhhat(x, x, x, x, x)"), ParseException); } + +// A mock ParallelTransform to test transform_from_field_aligned +// property of FieldFactory. For now, the transform just returns the +// negative of the input. Ideally, this will get moved to GoogleMock +// when we start using it. +// +// Can turn off the ability to do the transform. Should still be valid +class MockParallelTransform : public ParallelTransform { +public: + MockParallelTransform(Mesh& mesh, bool allow_transform_) + : ParallelTransform(mesh), allow_transform(allow_transform_) {} + ~MockParallelTransform() = default; + + void calcParallelSlices(Field3D&) override {} + + bool canToFromFieldAligned() override { return allow_transform; } + + bool requiresTwistShift(bool, YDirectionType) override { return false; } + + void checkInputGrid() override {} + + const Field3D fromFieldAligned(const Field3D& f, const std::string&) override { + if (f.getDirectionY() != YDirectionType::Aligned) { + throw BoutException("Unaligned field passed to fromFieldAligned"); + } + return -f; + } + + const FieldPerp fromFieldAligned(const FieldPerp& f, const std::string&) override { + if (f.getDirectionY() != YDirectionType::Aligned) { + throw BoutException("Unaligned field passed to fromFieldAligned"); + } + return -f; + } + + const Field3D toFieldAligned(const Field3D& f, const std::string&) override { return -f; } + const FieldPerp toFieldAligned(const FieldPerp& f, const std::string&) override { return -f; } + +private: + const bool allow_transform; +}; + +class FieldFactoryCreateAndTransformTest : public FakeMeshFixture { +public: + FieldFactoryCreateAndTransformTest() : FakeMeshFixture{} { + // We need Coordinates so a parallel transform is available as + // FieldFactory::create3D wants to un-field-align the result + static_cast(mesh)->setCoordinates(test_coords); + } + + WithQuietOutput quiet_info{output_info}; + WithQuietOutput quiet_warn{output_warn}; +}; + +TEST_F(FieldFactoryCreateAndTransformTest, Create2D) { + mesh->getCoordinates()->setParallelTransform( + bout::utils::make_unique(*mesh, true)); + + FieldFactory factory; + + auto output = factory.create2D("x"); + + // Field2Ds can't be transformed, so expect no change + auto expected = makeField( + [](typename Field2D::ind_type& index) -> BoutReal { return index.x(); }, mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TEST_F(FieldFactoryCreateAndTransformTest, Create3D) { + mesh->getCoordinates()->setParallelTransform( + bout::utils::make_unique(*mesh, true)); + + FieldFactory factory; + + auto output = factory.create3D("x"); + + auto expected = makeField( + [](typename Field3D::ind_type& index) -> BoutReal { return -index.x(); }, mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TEST_F(FieldFactoryCreateAndTransformTest, Create2DNoTransform) { + mesh->getCoordinates()->setParallelTransform( + bout::utils::make_unique(*mesh, true)); + + Options options; + options["input"]["transform_from_field_aligned"] = false; + FieldFactory factory{mesh, &options}; + + auto output = factory.create2D("x"); + + // Field2Ds can't be transformed, so expect no change + auto expected = makeField( + [](typename Field2D::ind_type& index) -> BoutReal { return index.x(); }, mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TEST_F(FieldFactoryCreateAndTransformTest, Create3DNoTransform) { + mesh->getCoordinates()->setParallelTransform( + bout::utils::make_unique(*mesh, true)); + + Options options; + options["input"]["transform_from_field_aligned"] = false; + FieldFactory factory{mesh, &options}; + + auto output = factory.create3D("x"); + + auto expected = makeField( + [](typename Field3D::ind_type& index) -> BoutReal { return index.x(); }, mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TEST_F(FieldFactoryCreateAndTransformTest, Create2DCantTransform) { + mesh->getCoordinates()->setParallelTransform( + bout::utils::make_unique(*mesh, false)); + + FieldFactory factory{mesh}; + + auto output = factory.create2D("x"); + + // Field2Ds can't be transformed, so expect no change + auto expected = makeField( + [](typename Field2D::ind_type& index) -> BoutReal { return index.x(); }, mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} + +TEST_F(FieldFactoryCreateAndTransformTest, Create3DCantTransform) { + mesh->getCoordinates()->setParallelTransform( + bout::utils::make_unique(*mesh, false)); + + FieldFactory factory{mesh}; + + auto output = factory.create3D("x"); + + auto expected = makeField( + [](typename Field3D::ind_type& index) -> BoutReal { return index.x(); }, mesh); + + EXPECT_TRUE(IsFieldEqual(output, expected)); +} From 23c6eb59a8b0f4d596fa6249a16365826bbb9ce5 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 24 Sep 2019 17:11:07 +0100 Subject: [PATCH 1725/1783] Simplify some FieldFactory tests - Main creation fixture can now choose not to do final transform, so doesn't need Coordinates - CreateOnMeshWithoutCoordinates moved to non-type-parameterised fixture - Remove comment that is no longer true --- tests/unit/field/test_field_factory.cxx | 43 ++++++------------------- 1 file changed, 9 insertions(+), 34 deletions(-) diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index 0fc3007411..3afdd5ba3b 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -25,23 +25,10 @@ using namespace bout::globals; template class FieldFactoryCreationTest : public FakeMeshFixture { public: - FieldFactoryCreationTest() : FakeMeshFixture{}, factory{mesh} { - // We need Coordinates so a parallel transform is available as - // FieldFactory::create3D wants to un-field-align the result - static_cast(mesh)->setCoordinates(test_coords); - - mesh->getCoordinates()->setParallelTransform( - bout::utils::make_unique(*mesh)); - - for (const auto& location - : std::list{CELL_CENTRE, CELL_XLOW, CELL_YLOW, CELL_ZLOW}) { - - static_cast(mesh_staggered)->setCoordinates(test_coords_staggered, - location); - - mesh_staggered->getCoordinates(location)->setParallelTransform( - bout::utils::make_unique(*mesh_staggered)); - } + FieldFactoryCreationTest() : FakeMeshFixture() { + Options options; + options["input"]["transform_from_field_aligned"] = false; + factory = FieldFactory{mesh, &options}; } WithQuietOutput quiet_info{output_info}; @@ -589,21 +576,6 @@ TYPED_TEST(FieldFactoryCreationTest, CreateOnMesh) { EXPECT_EQ(output.getNz(), nz); } -TYPED_TEST(FieldFactoryCreationTest, CreateOnMeshWithoutCoordinates) { - constexpr auto nx = int{1}; - constexpr auto ny = int{1}; - constexpr auto nz = int{1}; - - FakeMesh localmesh{nx, ny, nz}; - localmesh.setCoordinates(nullptr); - localmesh.createDefaultRegions(); - - // Field2D version doesn't try to transform back - if (bout::utils::is_Field3D::value) { - EXPECT_THROW(this->create("x", nullptr, &localmesh), BoutException); - } -} - // The following tests still use the FieldFactory, but don't need to // be typed and make take longer as they check that exceptions get // thrown. Doing these twice will slow down the test unnecessarily @@ -629,6 +601,11 @@ TEST_F(FieldFactoryTest, RequireMesh) { EXPECT_THROW(local_factory.create3D("x", nullptr, nullptr), BoutException); } +TEST_F(FieldFactoryTest, CreateOnMeshWithoutCoordinates) { + static_cast(mesh)->setCoordinates(nullptr); + EXPECT_THROW(factory.create3D("x"), BoutException); +} + TEST_F(FieldFactoryTest, CleanCache) { auto a_value = int{6}; @@ -642,8 +619,6 @@ TEST_F(FieldFactoryTest, CleanCache) { } TEST_F(FieldFactoryTest, ParseSelfReference) { - // This one doesn't need to be typed, but easier than creating a - // whole new test suite for this one test auto options = Options{}; options["a"] = "a"; From c0c47635a4b34bfd45c213bd6da5cd5ff28d08d7 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 25 Sep 2019 11:46:58 +0100 Subject: [PATCH 1726/1783] Make CELL_LOC strongly typed Convert CELL_LOC to an enum class, but use macros to allow continued use of CELL_DEFAULT, CELL_CENTRE, etc. without prefix CELL_LOC::CELL_DEFAULT, etc. --- include/bout_types.hxx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 7a69848b70..8aa07c9dd3 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -37,7 +37,13 @@ constexpr BoutReal BoutNaN = std::numeric_limits::quiet_NaN(); #define STRENUM(val) {#val, val} /// 4 possible variable locations. Default is for passing to functions -enum CELL_LOC {CELL_DEFAULT=0, CELL_CENTRE=1, CELL_CENTER=1, CELL_XLOW=2, CELL_YLOW=3, CELL_ZLOW=4, CELL_VSHIFT=5}; +enum class CELL_LOC {CELL_DEFAULT=0, CELL_CENTRE=1, CELL_CENTER=1, CELL_XLOW=2, CELL_YLOW=3, CELL_ZLOW=4, CELL_VSHIFT=5}; +#define CELL_DEFAULT CELL_LOC::CELL_DEFAULT +#define CELL_CENTRE CELL_LOC::CELL_CENTRE +#define CELL_XLOW CELL_LOC::CELL_XLOW +#define CELL_YLOW CELL_LOC::CELL_YLOW +#define CELL_ZLOW CELL_LOC::CELL_ZLOW +#define CELL_VSHIFT CELL_LOC::CELL_VSHIFT std::string toString(CELL_LOC location); CELL_LOC CELL_LOCFromString(const std::string& location_string); From 0991045231efa1a8e6562dfb4b503e5c13ede0bd Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 25 Sep 2019 11:47:18 +0100 Subject: [PATCH 1727/1783] Fix conditional 'CELL_CENTRE' -> 'location == CELL_CENTRE' --- src/mesh/coordinates.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 96835ab952..971f0d29db 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -816,7 +816,7 @@ int Coordinates::geometry(bool recalculate_staggered, Field2D d2x(localmesh), d2y(localmesh); // d^2 x / d i^2 // Read correction for non-uniform meshes std::string suffix = getLocationSuffix(location); - if (CELL_CENTRE or (!force_interpolate_from_centre + if (location == CELL_CENTRE or (!force_interpolate_from_centre and localmesh->sourceHasVar("dx"+suffix))) { bool extrapolate_x = not localmesh->sourceHasXBoundaryGuards(); bool extrapolate_y = not localmesh->sourceHasYBoundaryGuards(); From b26cfa64a98243093a186b2afeb2d903c11a0169 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 25 Sep 2019 17:44:17 +0100 Subject: [PATCH 1728/1783] Fix in-place Region methods returning new instances --- include/bout/region.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bout/region.hxx b/include/bout/region.hxx index f63ac8e2d6..ec88541dad 100644 --- a/include/bout/region.hxx +++ b/include/bout/region.hxx @@ -570,7 +570,7 @@ public: }; /// Sort this Region in place - Region sort(){ + Region& sort() { *this = this->asSorted(); return *this; } @@ -592,7 +592,7 @@ public: } /// Make this Region unique in-place - Region unique(){ + Region& unique() { *this = this->asUnique(); return *this; } From 46d34d9405008d5bdf8c557ca32ae4ab5786c51c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 26 Sep 2019 14:20:39 +0100 Subject: [PATCH 1729/1783] Fix typo in ternary in InvertableOperator --- include/bout/invertable_operator.hxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bout/invertable_operator.hxx b/include/bout/invertable_operator.hxx index 05b5b6654b..962ab68d59 100644 --- a/include/bout/invertable_operator.hxx +++ b/include/bout/invertable_operator.hxx @@ -132,8 +132,8 @@ public: InvertableOperator(const function_signature& func = identity, Options* optIn = nullptr, Mesh* localmeshIn = nullptr) : operatorFunction(func), preconditionerFunction(func), - opt(optIn == nullptr ? optIn - : Options::getRoot()->getSection("invertableOperator")), + opt(optIn == nullptr ? Options::getRoot()->getSection("invertableOperator") + : optIn), localmesh(localmeshIn == nullptr ? bout::globals::mesh : localmeshIn) { AUTO_TRACE(); }; From 165a2a4b425c745bef9786371bbf5431c0089cf9 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 28 Sep 2019 17:45:55 +0100 Subject: [PATCH 1730/1783] Cast from benum.CELL_LOC to int in boutcore's getLocation() Allows boutcore to work with CELL_LOC being an 'enum class'. --- tools/pylib/_boutcore_build/boutcore.pyx.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pylib/_boutcore_build/boutcore.pyx.in b/tools/pylib/_boutcore_build/boutcore.pyx.in index 31c422059f..3ae6c51c4b 100755 --- a/tools/pylib/_boutcore_build/boutcore.pyx.in +++ b/tools/pylib/_boutcore_build/boutcore.pyx.in @@ -381,7 +381,7 @@ cat < loc) def ddt(self,val=None): """ From 8b9d74dfa3ca07da7324702fa436b967fe0997bf Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 28 Sep 2019 19:15:14 +0100 Subject: [PATCH 1731/1783] Rename CELL_LOC members to avoid possible macro double-expansion --- include/bout_types.hxx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 8aa07c9dd3..bd117180df 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -37,13 +37,14 @@ constexpr BoutReal BoutNaN = std::numeric_limits::quiet_NaN(); #define STRENUM(val) {#val, val} /// 4 possible variable locations. Default is for passing to functions -enum class CELL_LOC {CELL_DEFAULT=0, CELL_CENTRE=1, CELL_CENTER=1, CELL_XLOW=2, CELL_YLOW=3, CELL_ZLOW=4, CELL_VSHIFT=5}; -#define CELL_DEFAULT CELL_LOC::CELL_DEFAULT -#define CELL_CENTRE CELL_LOC::CELL_CENTRE -#define CELL_XLOW CELL_LOC::CELL_XLOW -#define CELL_YLOW CELL_LOC::CELL_YLOW -#define CELL_ZLOW CELL_LOC::CELL_ZLOW -#define CELL_VSHIFT CELL_LOC::CELL_VSHIFT +enum class CELL_LOC {deflt=0, centre=1, xlow=2, ylow=3, zlow=4, vshift=5}; +#define CELL_DEFAULT CELL_LOC::deflt +#define CELL_CENTRE CELL_LOC::centre +#define CELL_CENTER CELL_LOC::centre +#define CELL_XLOW CELL_LOC::xlow +#define CELL_YLOW CELL_LOC::ylow +#define CELL_ZLOW CELL_LOC::zlow +#define CELL_VSHIFT CELL_LOC::vshift std::string toString(CELL_LOC location); CELL_LOC CELL_LOCFromString(const std::string& location_string); From a617d690b1bab00db4c73528150d07e9d98e0c96 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 28 Sep 2019 19:16:00 +0100 Subject: [PATCH 1732/1783] Special handling for CELL_LOC in boutcore's resolve_enum.pxd.in To allow strings passed as CELL_LOCs in Python code to match the macro names for CELL_DEFAULT, etc., in the C++ code, need some special handling of CELL_LOC. --- .../pylib/_boutcore_build/resolve_enum.pxd.in | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tools/pylib/_boutcore_build/resolve_enum.pxd.in b/tools/pylib/_boutcore_build/resolve_enum.pxd.in index eca61983c4..0a3112da8e 100644 --- a/tools/pylib/_boutcore_build/resolve_enum.pxd.in +++ b/tools/pylib/_boutcore_build/resolve_enum.pxd.in @@ -84,6 +84,24 @@ EOF test $class && echo " \"${name}_${shrt}\":$res," done + if test ${lower} = "cell_loc" + then + # CELL_LOCs are renamed by a macro in the C++ code, so need to handle specially here + echo " \"CELL_DEFAULT\":deflt," + echo " \"DEFAULT\":deflt," + echo " \"CELL_CENTRE\":centre," + echo " \"CENTRE\":centre," + echo " \"CELL_CENTER\":centre," + echo " \"CENTER\":centre," + echo " \"CELL_XLOW\":xlow," + echo " \"XLOW\":xlow," + echo " \"CELL_YLOW\":ylow," + echo " \"YLOW\":ylow," + echo " \"CELL_ZLOW\":zlow," + echo " \"ZLOW\":zlow," + echo " \"CELL_VSHIFT\":vshift," + echo " \"VSHIFT\":vshift," + fi echo " }" test $class && echo " return <$name> opts[str]" || From 5b7a5b98ba309d993e3efc8d9c3d2cf759624de7 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 28 Sep 2019 20:08:10 +0100 Subject: [PATCH 1733/1783] Convert DIFF_METHOD to enum class --- include/bout_types.hxx | 13 +++++++++- .../pylib/_boutcore_build/resolve_enum.pxd.in | 24 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index bd117180df..13cb4c226a 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -53,7 +53,18 @@ DEPRECATED(inline std::string CELL_LOC_STRING(CELL_LOC location)) { } /// Differential methods. Both central and upwind -enum DIFF_METHOD {DIFF_DEFAULT, DIFF_U1, DIFF_U2, DIFF_C2, DIFF_W2, DIFF_W3, DIFF_C4, DIFF_U3, DIFF_FFT, DIFF_SPLIT, DIFF_S2}; +enum class DIFF_METHOD {deflt, u1, u2, c2, w2, w3, c4, u3, fft, split, s2}; +#define DIFF_DEFAULT DIFF_METHOD::deflt +#define DIFF_U1 DIFF_METHOD::u1 +#define DIFF_U2 DIFF_METHOD::u2 +#define DIFF_C2 DIFF_METHOD::c2 +#define DIFF_W2 DIFF_METHOD::w2 +#define DIFF_W3 DIFF_METHOD::w3 +#define DIFF_C4 DIFF_METHOD::c4 +#define DIFF_U3 DIFF_METHOD::u3 +#define DIFF_FFT DIFF_METHOD::fft +#define DIFF_SPLIT DIFF_METHOD::split +#define DIFF_S2 DIFF_METHOD::s2 std::string toString(DIFF_METHOD location); DEPRECATED(inline std::string DIFF_METHOD_STRING(DIFF_METHOD location)) { diff --git a/tools/pylib/_boutcore_build/resolve_enum.pxd.in b/tools/pylib/_boutcore_build/resolve_enum.pxd.in index 0a3112da8e..858e51816d 100644 --- a/tools/pylib/_boutcore_build/resolve_enum.pxd.in +++ b/tools/pylib/_boutcore_build/resolve_enum.pxd.in @@ -101,6 +101,30 @@ EOF echo " \"ZLOW\":zlow," echo " \"CELL_VSHIFT\":vshift," echo " \"VSHIFT\":vshift," + elif test ${lower} = "diff_method" + then + echo " \"DIFF_DEFAULT\":deflt," + echo " \"DEFAULT\":deflt," + echo " \"DIFF_U1\":u1," + echo " \"U1\":u1," + echo " \"DIFF_U2\":u2," + echo " \"U2\":u2," + echo " \"DIFF_C2\":c2," + echo " \"C2\":c2," + echo " \"DIFF_W2\":w2," + echo " \"W2\":w2," + echo " \"DIFF_W3\":w3," + echo " \"W3\":w3," + echo " \"DIFF_C4\":c4," + echo " \"C4\":c4," + echo " \"DIFF_U3\":u3," + echo " \"U3\":u3," + echo " \"DIFF_FFT\":fft," + echo " \"FFT\":fft," + echo " \"DIFF_SPLIT\":split," + echo " \"SPLIT\":split," + echo " \"DIFF_S2\":s2," + echo " \"S2\":s2," fi echo " }" test $class && From 5eb9b80afb08f6e0daca4d8e85226dd4fde49017 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 28 Sep 2019 20:13:28 +0100 Subject: [PATCH 1734/1783] Convert REGION to enum class --- include/bout_types.hxx | 7 ++++++- tools/pylib/_boutcore_build/resolve_enum.pxd.in | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 13cb4c226a..7e67f7e6aa 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -72,7 +72,12 @@ DEPRECATED(inline std::string DIFF_METHOD_STRING(DIFF_METHOD location)) { } /// Specify grid region for looping -enum REGION { RGN_ALL, RGN_NOBNDRY, RGN_NOX, RGN_NOY, RGN_NOZ }; +enum class REGION {all, nobndry, nox, noy, noz}; +#define RGN_ALL REGION::all +#define RGN_NOBNDRY REGION::nobndry +#define RGN_NOX REGION::nox +#define RGN_NOY REGION::noy +#define RGN_NOZ REGION::noz std::string toString(REGION region); DEPRECATED(inline std::string REGION_STRING(REGION region)) { return toString(region); } diff --git a/tools/pylib/_boutcore_build/resolve_enum.pxd.in b/tools/pylib/_boutcore_build/resolve_enum.pxd.in index 858e51816d..569109c8d1 100644 --- a/tools/pylib/_boutcore_build/resolve_enum.pxd.in +++ b/tools/pylib/_boutcore_build/resolve_enum.pxd.in @@ -125,6 +125,13 @@ EOF echo " \"SPLIT\":split," echo " \"DIFF_S2\":s2," echo " \"S2\":s2," + elif test ${lower} = "region" + then + echo " \"RGN_ALL\":all," + echo " \"RGN_NOBNDRY\":nobndry," + echo " \"RGN_NOX\":nox," + echo " \"RGN_NOY\":noy," + echo " \"RGN_NOZ\":noz," fi echo " }" test $class && From 09a27827b3df79ece64faa7c0dda1cbcb46264a1 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 28 Sep 2019 20:36:40 +0100 Subject: [PATCH 1735/1783] Convert BndryLoc to enum class --- include/boundary_region.hxx | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/include/boundary_region.hxx b/include/boundary_region.hxx index d6ee650984..83e6df93d3 100644 --- a/include/boundary_region.hxx +++ b/include/boundary_region.hxx @@ -15,13 +15,20 @@ namespace globals { } // namespace globals /// Location of boundary -enum BndryLoc {BNDRY_XIN=1, - BNDRY_XOUT=2, - BNDRY_YDOWN=4, - BNDRY_YUP=8, - BNDRY_ALL=15, - BNDRY_PAR_FWD=16, // Don't include parallel boundaries - BNDRY_PAR_BKWD=32}; +enum class BndryLoc {xin=1, + xout=2, + ydown=4, + yup=8, + all=15, + par_fwd=16, // Don't include parallel boundaries + par_bkwd=32}; +#define BNDRY_XIN BndryLoc::xin +#define BNDRY_XOUT BndryLoc::xout +#define BNDRY_YDOWN BndryLoc::ydown +#define BNDRY_YUP BndryLoc::yup +#define BNDRY_ALL BndryLoc::all +#define BNDRY_PAR_FWD BndryLoc::par_fwd +#define BNDRY_PAR_BKWD BndryLoc::par_bkwd class BoundaryRegionBase { public: From 8c1cabfae513222ef7175380ec68a6fdceb22d1f Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 28 Sep 2019 20:47:17 +0100 Subject: [PATCH 1736/1783] Convert GridDataSource::Direction to enum class --- include/bout/griddata.hxx | 20 +++++++++++++------- src/mesh/data/gridfromoptions.cxx | 6 +++--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index 2807389a0a..7b76ed6544 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -65,11 +65,17 @@ public: virtual bool get(Mesh *m, Field3D &var, const std::string &name, BoutReal def = 0.0) = 0; virtual bool get(Mesh *m, FieldPerp &var, const std::string &name, BoutReal def = 0.0) = 0; - enum Direction { X = 1, Y = 2, Z = 3 }; + enum class Direction { X = 1, Y = 2, Z = 3 }; + // Define some aliases so GridDataSource::X, GridDataSource::Y and GridDataSource::Z can + // be used, for backward compatibility + static constexpr Direction X = Direction::X; + static constexpr Direction Y = Direction::Y; + static constexpr Direction Z = Direction::Z; + virtual bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, - Direction dir = GridDataSource::X) = 0; + Direction dir = GridDataSource::Direction::X) = 0; virtual bool get(Mesh *m, std::vector &var, const std::string &name, int len, - int offset = 0, Direction dir = GridDataSource::X) = 0; + int offset = 0, Direction dir = GridDataSource::Direction::X) = 0; /// Are x-boundary guard cells read from the source? virtual bool hasXBoundaryGuards(Mesh* m) = 0; @@ -105,9 +111,9 @@ public: } bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, - GridDataSource::Direction dir = GridDataSource::X) override; + GridDataSource::Direction dir = GridDataSource::Direction::X) override; bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, - GridDataSource::Direction dir = GridDataSource::X) override; + GridDataSource::Direction dir = GridDataSource::Direction::X) override; /// Are x-boundary guard cells read from the source? bool hasXBoundaryGuards(Mesh* m) override; @@ -252,7 +258,7 @@ public: * @param[in] dir The direction (X,Y,Z) of the array */ bool get(Mesh *mesh, std::vector &var, const std::string &name, int len, int offset = 0, - GridDataSource::Direction dir = GridDataSource::X) override; + GridDataSource::Direction dir = GridDataSource::Direction::X) override; /*! * Get an array of BoutReals. Uses FieldFactory to generate @@ -268,7 +274,7 @@ public: * @param[in] dir The direction (X,Y,Z) of the array */ bool get(Mesh *mesh, std::vector &var, const std::string &name, int len, int offset = 0, - GridDataSource::Direction dir = GridDataSource::X) override; + GridDataSource::Direction dir = GridDataSource::Direction::X) override; /// Are x-boundary guard cells read from the source? bool hasXBoundaryGuards(Mesh* UNUSED(m)) override { return true; } diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index aa07abe1c2..f271178747 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -123,19 +123,19 @@ bool GridFromOptions::get(Mesh* m, std::vector& var, const std::string var.resize(len); switch (dir) { - case GridDataSource::X: { + case GridDataSource::Direction::X: { for (int x = 0; x < len; x++) { var[x] = gen->generate(m->GlobalX(x - m->OffsetX + offset), 0.0, 0.0, 0.0); } break; } - case GridDataSource::Y: { + case GridDataSource::Direction::Y: { for (int y = 0; y < len; y++) { var[y] = gen->generate(0.0, TWOPI * m->GlobalY(y - m->OffsetY + offset), 0.0, 0.0); } break; } - case GridDataSource::Z: { + case GridDataSource::Direction::Z: { for (int z = 0; z < len; z++) { var[z] = gen->generate( 0.0, 0.0, From 6e78f16153bb79306394fee73eca96a6f6f685ff Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 28 Sep 2019 21:13:11 +0100 Subject: [PATCH 1737/1783] Convert SOLVER_VAR_OP to enum class --- include/bout/solver.hxx | 2 +- src/solver/solver.cxx | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 4015683a9b..95938cfac1 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -91,7 +91,7 @@ constexpr auto SOLVERIMEXBDF2 = "imexbdf2"; constexpr auto SOLVERSNES = "snes"; constexpr auto SOLVERRKGENERIC = "rkgeneric"; -enum SOLVER_VAR_OP {LOAD_VARS, LOAD_DERIVS, SET_ID, SAVE_VARS, SAVE_DERIVS}; +enum class SOLVER_VAR_OP {LOAD_VARS, LOAD_DERIVS, SET_ID, SAVE_VARS, SAVE_DERIVS}; /////////////////////////////////////////////////////////////////// diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index b0541e701a..f418ce0d13 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -804,7 +804,7 @@ void Solver::loop_vars_op(Ind2D i2d, BoutReal *udata, int &p, SOLVER_VAR_OP op, int nz = mesh->LocalNz; switch(op) { - case LOAD_VARS: { + case SOLVER_VAR_OP::LOAD_VARS: { /// Load variables from IDA into BOUT++ // Loop over 2D variables @@ -827,7 +827,7 @@ void Solver::loop_vars_op(Ind2D i2d, BoutReal *udata, int &p, SOLVER_VAR_OP op, } break; } - case LOAD_DERIVS: { + case SOLVER_VAR_OP::LOAD_DERIVS: { /// Load derivatives from IDA into BOUT++ /// Used for preconditioner @@ -852,7 +852,7 @@ void Solver::loop_vars_op(Ind2D i2d, BoutReal *udata, int &p, SOLVER_VAR_OP op, break; } - case SET_ID: { + case SOLVER_VAR_OP::SET_ID: { /// Set the type of equation (Differential or Algebraic) // Loop over 2D variables @@ -884,7 +884,7 @@ void Solver::loop_vars_op(Ind2D i2d, BoutReal *udata, int &p, SOLVER_VAR_OP op, break; } - case SAVE_VARS: { + case SOLVER_VAR_OP::SAVE_VARS: { /// Save variables from BOUT++ into IDA (only used at start of simulation) // Loop over 2D variables @@ -908,7 +908,7 @@ void Solver::loop_vars_op(Ind2D i2d, BoutReal *udata, int &p, SOLVER_VAR_OP op, break; } /// Save time-derivatives from BOUT++ into CVODE (returning RHS result) - case SAVE_DERIVS: { + case SOLVER_VAR_OP::SAVE_DERIVS: { // Loop over 2D variables for(const auto& f : f2d) { @@ -960,7 +960,7 @@ void Solver::load_vars(BoutReal *udata) { f.var->setLocation(f.location); } - loop_vars(udata, LOAD_VARS); + loop_vars(udata, SOLVER_VAR_OP::LOAD_VARS); // Mark each vector as either co- or contra-variant @@ -979,7 +979,7 @@ void Solver::load_derivs(BoutReal *udata) { f.F_var->setLocation(f.location); } - loop_vars(udata, LOAD_DERIVS); + loop_vars(udata, SOLVER_VAR_OP::LOAD_DERIVS); // Mark each vector as either co- or contra-variant @@ -1013,7 +1013,7 @@ void Solver::save_vars(BoutReal *udata) { v.var->toContravariant(); } - loop_vars(udata, SAVE_VARS); + loop_vars(udata, SOLVER_VAR_OP::SAVE_VARS); } void Solver::save_derivs(BoutReal *dudata) { @@ -1041,11 +1041,11 @@ void Solver::save_derivs(BoutReal *dudata) { } } - loop_vars(dudata, SAVE_DERIVS); + loop_vars(dudata, SOLVER_VAR_OP::SAVE_DERIVS); } void Solver::set_id(BoutReal *udata) { - loop_vars(udata, SET_ID); + loop_vars(udata, SOLVER_VAR_OP::SET_ID); } Field3D Solver::globalIndex(int localStart) { From 5de7c58b0a69fd21866074aa90e7a468b2204c42 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 28 Sep 2019 21:17:09 +0100 Subject: [PATCH 1738/1783] Convert BRACKET_METHOD to enum class --- include/difops.hxx | 17 +++++++++++------ tools/pylib/_boutcore_build/other_enums.hxx | 2 +- tools/pylib/_boutcore_build/resolve_enum.pxd.in | 12 ++++++++++++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/include/difops.hxx b/include/difops.hxx index 094c036daa..0bb8018abc 100644 --- a/include/difops.hxx +++ b/include/difops.hxx @@ -314,16 +314,21 @@ const Field3D b0xGrad_dot_Grad(const Field3D &phi, const Field3D &A, CELL_LOC ou /*! * Poisson bracket methods */ -enum BRACKET_METHOD { - BRACKET_STD = 0, ///< Use b0xGrad_dot_Grad - BRACKET_SIMPLE = 1, ///< Keep only terms in X-Z - BRACKET_ARAKAWA = 2, ///< Arakawa method in X-Z (optimised) - BRACKET_CTU = 3, ///< Corner Transport Upwind (CTU) +enum class BRACKET_METHOD { + standard = 0, ///< Use b0xGrad_dot_Grad + simple = 1, ///< Keep only terms in X-Z + arakawa = 2, ///< Arakawa method in X-Z (optimised) + ctu = 3, ///< Corner Transport Upwind (CTU) /// method. Explicit method only, /// needs the timestep from the /// solver - BRACKET_ARAKAWA_OLD = 4 ///< Older version, for regression testing of optimised version. + arakawa_old = 4 ///< Older version, for regression testing of optimised version. }; +#define BRACKET_STD BRACKET_METHOD::standard +#define BRACKET_SIMPLE BRACKET_METHOD::simple +#define BRACKET_ARAKAWA BRACKET_METHOD::arakawa +#define BRACKET_CTU BRACKET_METHOD::ctu +#define BRACKET_ARAKAWA_OLD BRACKET_METHOD::arakawa_old /*! * Compute advection operator terms, which can be cast as diff --git a/tools/pylib/_boutcore_build/other_enums.hxx b/tools/pylib/_boutcore_build/other_enums.hxx index 0584d244bc..8e4c72dffb 100644 --- a/tools/pylib/_boutcore_build/other_enums.hxx +++ b/tools/pylib/_boutcore_build/other_enums.hxx @@ -1,4 +1,4 @@ #ifdef YOU_SHOULDNT_READ_THIS #error YOU_SHOULDNT_BE_HERE -enum BRACKET_METHOD {BRACKET_STD=0, BRACKET_SIMPLE=1, BRACKET_ARAKAWA=2, BRACKET_CTU=3,BRACKET_ARAKAWA_OLD=4 }; +enum class BRACKET_METHOD {standard=0, simple=1, arakawa=2, ctu=3, arakawa_old=4}; #endif diff --git a/tools/pylib/_boutcore_build/resolve_enum.pxd.in b/tools/pylib/_boutcore_build/resolve_enum.pxd.in index 569109c8d1..22e91e0228 100644 --- a/tools/pylib/_boutcore_build/resolve_enum.pxd.in +++ b/tools/pylib/_boutcore_build/resolve_enum.pxd.in @@ -132,6 +132,18 @@ EOF echo " \"RGN_NOX\":nox," echo " \"RGN_NOY\":noy," echo " \"RGN_NOZ\":noz," + elif test ${lower} = "bracket_method" + then + echo " \"BRACKET_STD\":standard," + echo " \"STD\":standard," + echo " \"BRACKET_SIMPLE\":simple," + echo " \"SIMPLE\":simple," + echo " \"BRACKET_ARAKAWA\":arakawa," + echo " \"ARAKAWA\":arakawa," + echo " \"BRACKET_CTU\":ctu," + echo " \"CTU\":ctu," + echo " \"BRACKET_ARAKAWA_OLD\":arakawa_old," + echo " \"ARAKAWA_OLD\":arakawa_old," fi echo " }" test $class && From 4ffc93aaaba9c26b4d420d9fee06fe917e48a781 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 28 Sep 2019 21:24:01 +0100 Subject: [PATCH 1739/1783] Convert BoundaryOpPar::ValueType to enum class --- include/parallel_boundary_op.hxx | 10 +++++----- src/mesh/parallel_boundary_op.cxx | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/parallel_boundary_op.hxx b/include/parallel_boundary_op.hxx index a8e595df01..6235ea9ca4 100644 --- a/include/parallel_boundary_op.hxx +++ b/include/parallel_boundary_op.hxx @@ -16,15 +16,15 @@ class BoundaryOpPar : public BoundaryOpBase { public: BoundaryOpPar() = default; BoundaryOpPar(BoundaryRegionPar *region, std::shared_ptr value) - : bndry(region), gen_values(std::move(value)), value_type(GEN) {} + : bndry(region), gen_values(std::move(value)), value_type(ValueType::GEN) {} BoundaryOpPar(BoundaryRegionPar *region, Field3D* value) : bndry(region), field_values(value), - value_type(FIELD) {} + value_type(ValueType::FIELD) {} BoundaryOpPar(BoundaryRegionPar *region, BoutReal value) : bndry(region), real_value(value), - value_type(REAL) {} + value_type(ValueType::REAL) {} ~BoundaryOpPar() override = default; // Note: All methods must implement clone, except for modifiers (see below) @@ -56,8 +56,8 @@ protected: BoutReal real_value{0.}; /// Where to take boundary values from - the generator, field or BoutReal - enum ValueType { GEN, FIELD, REAL }; - const ValueType value_type{REAL}; + enum class ValueType {GEN, FIELD, REAL}; + const ValueType value_type{ValueType::REAL}; BoutReal getValue(int x, int y, int z, BoutReal t); BoutReal getValue(const BoundaryRegionPar &bndry, BoutReal t); diff --git a/src/mesh/parallel_boundary_op.cxx b/src/mesh/parallel_boundary_op.cxx index 1b13325682..4e62709483 100644 --- a/src/mesh/parallel_boundary_op.cxx +++ b/src/mesh/parallel_boundary_op.cxx @@ -16,7 +16,7 @@ BoutReal BoundaryOpPar::getValue(int x, int y, int z, BoutReal t) { BoutReal value; switch (value_type) { - case GEN: + case ValueType::GEN: // This works but doesn't quite do the right thing... should // generate value on the boundary, but that gives wrong // answer. This instead generates the value at the gridpoint @@ -24,10 +24,10 @@ BoutReal BoundaryOpPar::getValue(int x, int y, int z, BoutReal t) { ynorm = mesh->GlobalY(y); znorm = static_cast(z) / (mesh->LocalNz); return gen_values->generate(xnorm, TWOPI*ynorm, TWOPI*znorm, t); - case FIELD: + case ValueType::FIELD: value = (*field_values)(x,y,z); return value; - case REAL: + case ValueType::REAL: return real_value; default: throw BoutException("Invalid value_type encountered in BoundaryOpPar::getValue"); @@ -46,17 +46,17 @@ BoutReal BoundaryOpPar::getValue(const BoundaryRegionPar &bndry, BoutReal t) { BoutReal value; switch (value_type) { - case GEN: + case ValueType::GEN: // Need to use GlobalX, except with BoutReal as argument... xnorm = mesh->GlobalX(bndry.s_x); ynorm = mesh->GlobalY(bndry.s_y); znorm = bndry.s_z/(mesh->LocalNz); return gen_values->generate(xnorm, TWOPI*ynorm, TWOPI*znorm, t); - case FIELD: + case ValueType::FIELD: // FIXME: Interpolate to s_x, s_y, s_z... value = (*field_values)(bndry.x,bndry.y,bndry.z); return value; - case REAL: + case ValueType::REAL: return real_value; default: throw BoutException("Invalid value_type encountered in BoundaryOpPar::getValue"); From cd7f8a48ac55064270c6c2e319765c8d72343cc5 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 28 Sep 2019 21:13:49 +0100 Subject: [PATCH 1740/1783] Convert Solver::MonitorPosition to enum class --- include/bout/solver.hxx | 11 ++++++++--- src/solver/solver.cxx | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/bout/solver.hxx b/include/bout/solver.hxx index 95938cfac1..eaf75060cf 100644 --- a/include/bout/solver.hxx +++ b/include/bout/solver.hxx @@ -93,6 +93,9 @@ constexpr auto SOLVERRKGENERIC = "rkgeneric"; enum class SOLVER_VAR_OP {LOAD_VARS, LOAD_DERIVS, SET_ID, SAVE_VARS, SAVE_DERIVS}; +/// A type to set where in the list monitors are added +enum class MonitorPosition {BACK, FRONT}; + /////////////////////////////////////////////////////////////////// /*! @@ -197,8 +200,10 @@ public: ///////////////////////////////////////////// // Monitors - /// A type to set where in the list monitors are added - enum MonitorPosition { BACK, FRONT }; + // Alternative names so that Solver::BACK and Solver::FRONT can be used as names for + // MonitorPositions, for backward compatibility. + static constexpr MonitorPosition BACK = MonitorPosition::BACK; + static constexpr MonitorPosition FRONT = MonitorPosition::FRONT; /// Add a \p monitor to be called regularly /// @@ -213,7 +218,7 @@ public: /// Adding new Monitors after the Solver has been initialised is /// only possible if their timestep is a multiple of the Solver's /// timestep. Smaller timesteps will throw an exception. - void addMonitor(Monitor* monitor, MonitorPosition pos = FRONT); + void addMonitor(Monitor* monitor, MonitorPosition pos = MonitorPosition::FRONT); /// Remove a monitor function previously added void removeMonitor(Monitor* monitor); diff --git a/src/solver/solver.cxx b/src/solver/solver.cxx index f418ce0d13..aa0c27db4f 100644 --- a/src/solver/solver.cxx +++ b/src/solver/solver.cxx @@ -643,7 +643,7 @@ void Solver::addMonitor(Monitor* monitor, MonitorPosition pos) { monitor->is_added = true; - if (pos == Solver::FRONT) { + if (pos == MonitorPosition::FRONT) { monitors.push_front(monitor); } else { monitors.push_back(monitor); From 7dbb088b0f0a817e0f319edc28f54793b2735f47 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 28 Sep 2019 22:29:05 +0100 Subject: [PATCH 1741/1783] Fix location checks in boutcore tests --- tests/MMS/derivatives3/runtest | 4 ++-- tests/MMS/upwinding3/runtest | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/MMS/derivatives3/runtest b/tests/MMS/derivatives3/runtest index a10e87157c..a2242c153a 100755 --- a/tests/MMS/derivatives3/runtest +++ b/tests/MMS/derivatives3/runtest @@ -17,9 +17,9 @@ def runtests(functions,derivatives,directions,stag,msg): global errorlist for direction in directions: direction, fac,guards, diff_func = direction - locations=['CENTRE'] + locations=['centre'] if stag: - locations.append(direction.upper()+"LOW") + locations.append(direction.lower()+"low") for funcs, derivative , inloc, outloc in itertools.product(functions, derivatives, locations,locations): infunc, outfunc = funcs diff --git a/tests/MMS/upwinding3/runtest b/tests/MMS/upwinding3/runtest index 2862e7a347..5dc7bcbf60 100755 --- a/tests/MMS/upwinding3/runtest +++ b/tests/MMS/upwinding3/runtest @@ -18,9 +18,9 @@ def runtests(functions,derivatives,directions,stag,msg): global passlist for direction in directions: direction, fac,guards, diff_func = direction - locations=['CENTRE'] + locations=['centre'] if stag: - locations.append(direction.upper()+"LOW") + locations.append(direction.lower()+"low") for funcs, derivative , floc, vloc in itertools.product(functions, derivatives, locations,locations): vfunc, ffunc, outfunc = funcs @@ -40,11 +40,10 @@ def runtests(functions,derivatives,directions,stag,msg): ,outloc=vloc) sim=diff_func(v,f,method=diff,outloc=floc) if sim.getLocation() != floc: - cent=['CENTRE','CENTER'] - if floc in cent and sim.getLocation() in cent: + if floc == 'centre' and sim.getLocation() == 'centre': pass else: - errorlist.append("Location does not match - expected %s but got %s"%(outloc,sim.getLocation())) + errorlist.append("Location does not match - expected %s but got %s"%(floc,sim.getLocation())) ana=boutcore.create3D(outfunc.replace("%s",dirnfac),mesh, outloc=floc) err=sim-ana err=err.getAll().flatten() From 7b6fb4da6b5d327eaef30242700e4d61a1e70f6e Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 30 Sep 2019 17:28:49 +0100 Subject: [PATCH 1742/1783] Delete explicit numbering of enum classes --- include/boundary_region.hxx | 14 +++++++------- include/bout/griddata.hxx | 14 +++++++------- include/bout_types.hxx | 2 +- include/difops.hxx | 14 ++++++-------- src/mesh/data/gridfromoptions.cxx | 6 +++--- tools/pylib/_boutcore_build/other_enums.hxx | 2 +- 6 files changed, 25 insertions(+), 27 deletions(-) diff --git a/include/boundary_region.hxx b/include/boundary_region.hxx index 83e6df93d3..91e375596d 100644 --- a/include/boundary_region.hxx +++ b/include/boundary_region.hxx @@ -15,13 +15,13 @@ namespace globals { } // namespace globals /// Location of boundary -enum class BndryLoc {xin=1, - xout=2, - ydown=4, - yup=8, - all=15, - par_fwd=16, // Don't include parallel boundaries - par_bkwd=32}; +enum class BndryLoc {xin, + xout, + ydown, + yup, + all, + par_fwd, // Don't include parallel boundaries + par_bkwd}; #define BNDRY_XIN BndryLoc::xin #define BNDRY_XOUT BndryLoc::xout #define BNDRY_YDOWN BndryLoc::ydown diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index 7b76ed6544..a07603e38e 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -65,7 +65,7 @@ public: virtual bool get(Mesh *m, Field3D &var, const std::string &name, BoutReal def = 0.0) = 0; virtual bool get(Mesh *m, FieldPerp &var, const std::string &name, BoutReal def = 0.0) = 0; - enum class Direction { X = 1, Y = 2, Z = 3 }; + enum class Direction {X, Y, Z}; // Define some aliases so GridDataSource::X, GridDataSource::Y and GridDataSource::Z can // be used, for backward compatibility static constexpr Direction X = Direction::X; @@ -73,9 +73,9 @@ public: static constexpr Direction Z = Direction::Z; virtual bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, - Direction dir = GridDataSource::Direction::X) = 0; + Direction dir = GridDataSource::X) = 0; virtual bool get(Mesh *m, std::vector &var, const std::string &name, int len, - int offset = 0, Direction dir = GridDataSource::Direction::X) = 0; + int offset = 0, Direction dir = GridDataSource::X) = 0; /// Are x-boundary guard cells read from the source? virtual bool hasXBoundaryGuards(Mesh* m) = 0; @@ -111,9 +111,9 @@ public: } bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, - GridDataSource::Direction dir = GridDataSource::Direction::X) override; + GridDataSource::Direction dir = GridDataSource::X) override; bool get(Mesh *m, std::vector &var, const std::string &name, int len, int offset = 0, - GridDataSource::Direction dir = GridDataSource::Direction::X) override; + GridDataSource::Direction dir = GridDataSource::X) override; /// Are x-boundary guard cells read from the source? bool hasXBoundaryGuards(Mesh* m) override; @@ -258,7 +258,7 @@ public: * @param[in] dir The direction (X,Y,Z) of the array */ bool get(Mesh *mesh, std::vector &var, const std::string &name, int len, int offset = 0, - GridDataSource::Direction dir = GridDataSource::Direction::X) override; + GridDataSource::Direction dir = GridDataSource::X) override; /*! * Get an array of BoutReals. Uses FieldFactory to generate @@ -274,7 +274,7 @@ public: * @param[in] dir The direction (X,Y,Z) of the array */ bool get(Mesh *mesh, std::vector &var, const std::string &name, int len, int offset = 0, - GridDataSource::Direction dir = GridDataSource::Direction::X) override; + GridDataSource::Direction dir = GridDataSource::X) override; /// Are x-boundary guard cells read from the source? bool hasXBoundaryGuards(Mesh* UNUSED(m)) override { return true; } diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 7e67f7e6aa..46eb6712f0 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -37,7 +37,7 @@ constexpr BoutReal BoutNaN = std::numeric_limits::quiet_NaN(); #define STRENUM(val) {#val, val} /// 4 possible variable locations. Default is for passing to functions -enum class CELL_LOC {deflt=0, centre=1, xlow=2, ylow=3, zlow=4, vshift=5}; +enum class CELL_LOC {deflt, centre, xlow, ylow, zlow, vshift}; #define CELL_DEFAULT CELL_LOC::deflt #define CELL_CENTRE CELL_LOC::centre #define CELL_CENTER CELL_LOC::centre diff --git a/include/difops.hxx b/include/difops.hxx index 0bb8018abc..db90f5d7b4 100644 --- a/include/difops.hxx +++ b/include/difops.hxx @@ -315,14 +315,12 @@ const Field3D b0xGrad_dot_Grad(const Field3D &phi, const Field3D &A, CELL_LOC ou * Poisson bracket methods */ enum class BRACKET_METHOD { - standard = 0, ///< Use b0xGrad_dot_Grad - simple = 1, ///< Keep only terms in X-Z - arakawa = 2, ///< Arakawa method in X-Z (optimised) - ctu = 3, ///< Corner Transport Upwind (CTU) - /// method. Explicit method only, - /// needs the timestep from the - /// solver - arakawa_old = 4 ///< Older version, for regression testing of optimised version. + standard, ///< Use b0xGrad_dot_Grad + simple, ///< Keep only terms in X-Z + arakawa, ///< Arakawa method in X-Z (optimised) + ctu, ///< Corner Transport Upwind (CTU) method. Explicit method only, needs the + /// timestep from the solver + arakawa_old ///< Older version, for regression testing of optimised version. }; #define BRACKET_STD BRACKET_METHOD::standard #define BRACKET_SIMPLE BRACKET_METHOD::simple diff --git a/src/mesh/data/gridfromoptions.cxx b/src/mesh/data/gridfromoptions.cxx index f271178747..aa07abe1c2 100644 --- a/src/mesh/data/gridfromoptions.cxx +++ b/src/mesh/data/gridfromoptions.cxx @@ -123,19 +123,19 @@ bool GridFromOptions::get(Mesh* m, std::vector& var, const std::string var.resize(len); switch (dir) { - case GridDataSource::Direction::X: { + case GridDataSource::X: { for (int x = 0; x < len; x++) { var[x] = gen->generate(m->GlobalX(x - m->OffsetX + offset), 0.0, 0.0, 0.0); } break; } - case GridDataSource::Direction::Y: { + case GridDataSource::Y: { for (int y = 0; y < len; y++) { var[y] = gen->generate(0.0, TWOPI * m->GlobalY(y - m->OffsetY + offset), 0.0, 0.0); } break; } - case GridDataSource::Direction::Z: { + case GridDataSource::Z: { for (int z = 0; z < len; z++) { var[z] = gen->generate( 0.0, 0.0, diff --git a/tools/pylib/_boutcore_build/other_enums.hxx b/tools/pylib/_boutcore_build/other_enums.hxx index 8e4c72dffb..12582aaacc 100644 --- a/tools/pylib/_boutcore_build/other_enums.hxx +++ b/tools/pylib/_boutcore_build/other_enums.hxx @@ -1,4 +1,4 @@ #ifdef YOU_SHOULDNT_READ_THIS #error YOU_SHOULDNT_BE_HERE -enum class BRACKET_METHOD {standard=0, simple=1, arakawa=2, ctu=3, arakawa_old=4}; +enum class BRACKET_METHOD {standard, simple, arakawa, ctu, arakawa_old}; #endif From 0b7889ece4be72a50c8d35dbd447a4b50d66046b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 30 Sep 2019 17:33:20 +0100 Subject: [PATCH 1743/1783] Replace enum class macro aliases with constexpr values Should be safer. --- include/boundary_region.hxx | 14 +++++------ include/bout_types.hxx | 46 ++++++++++++++++++------------------- include/difops.hxx | 10 ++++---- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/include/boundary_region.hxx b/include/boundary_region.hxx index 91e375596d..37f9329405 100644 --- a/include/boundary_region.hxx +++ b/include/boundary_region.hxx @@ -22,13 +22,13 @@ enum class BndryLoc {xin, all, par_fwd, // Don't include parallel boundaries par_bkwd}; -#define BNDRY_XIN BndryLoc::xin -#define BNDRY_XOUT BndryLoc::xout -#define BNDRY_YDOWN BndryLoc::ydown -#define BNDRY_YUP BndryLoc::yup -#define BNDRY_ALL BndryLoc::all -#define BNDRY_PAR_FWD BndryLoc::par_fwd -#define BNDRY_PAR_BKWD BndryLoc::par_bkwd +constexpr BndryLoc BNDRY_XIN = BndryLoc::xin; +constexpr BndryLoc BNDRY_XOUT = BndryLoc::xout; +constexpr BndryLoc BNDRY_YDOWN = BndryLoc::ydown; +constexpr BndryLoc BNDRY_YUP = BndryLoc::yup; +constexpr BndryLoc BNDRY_ALL = BndryLoc::all; +constexpr BndryLoc BNDRY_PAR_FWD = BndryLoc::par_fwd; +constexpr BndryLoc BNDRY_PAR_BKWD = BndryLoc::par_bkwd; class BoundaryRegionBase { public: diff --git a/include/bout_types.hxx b/include/bout_types.hxx index 46eb6712f0..ce96e88cb3 100644 --- a/include/bout_types.hxx +++ b/include/bout_types.hxx @@ -38,13 +38,13 @@ constexpr BoutReal BoutNaN = std::numeric_limits::quiet_NaN(); /// 4 possible variable locations. Default is for passing to functions enum class CELL_LOC {deflt, centre, xlow, ylow, zlow, vshift}; -#define CELL_DEFAULT CELL_LOC::deflt -#define CELL_CENTRE CELL_LOC::centre -#define CELL_CENTER CELL_LOC::centre -#define CELL_XLOW CELL_LOC::xlow -#define CELL_YLOW CELL_LOC::ylow -#define CELL_ZLOW CELL_LOC::zlow -#define CELL_VSHIFT CELL_LOC::vshift +constexpr CELL_LOC CELL_DEFAULT = CELL_LOC::deflt; +constexpr CELL_LOC CELL_CENTRE = CELL_LOC::centre; +constexpr CELL_LOC CELL_CENTER = CELL_LOC::centre; +constexpr CELL_LOC CELL_XLOW = CELL_LOC::xlow; +constexpr CELL_LOC CELL_YLOW = CELL_LOC::ylow; +constexpr CELL_LOC CELL_ZLOW = CELL_LOC::zlow; +constexpr CELL_LOC CELL_VSHIFT = CELL_LOC::vshift; std::string toString(CELL_LOC location); CELL_LOC CELL_LOCFromString(const std::string& location_string); @@ -54,17 +54,17 @@ DEPRECATED(inline std::string CELL_LOC_STRING(CELL_LOC location)) { /// Differential methods. Both central and upwind enum class DIFF_METHOD {deflt, u1, u2, c2, w2, w3, c4, u3, fft, split, s2}; -#define DIFF_DEFAULT DIFF_METHOD::deflt -#define DIFF_U1 DIFF_METHOD::u1 -#define DIFF_U2 DIFF_METHOD::u2 -#define DIFF_C2 DIFF_METHOD::c2 -#define DIFF_W2 DIFF_METHOD::w2 -#define DIFF_W3 DIFF_METHOD::w3 -#define DIFF_C4 DIFF_METHOD::c4 -#define DIFF_U3 DIFF_METHOD::u3 -#define DIFF_FFT DIFF_METHOD::fft -#define DIFF_SPLIT DIFF_METHOD::split -#define DIFF_S2 DIFF_METHOD::s2 +constexpr DIFF_METHOD DIFF_DEFAULT = DIFF_METHOD::deflt; +constexpr DIFF_METHOD DIFF_U1 = DIFF_METHOD::u1; +constexpr DIFF_METHOD DIFF_U2 = DIFF_METHOD::u2; +constexpr DIFF_METHOD DIFF_C2 = DIFF_METHOD::c2; +constexpr DIFF_METHOD DIFF_W2 = DIFF_METHOD::w2; +constexpr DIFF_METHOD DIFF_W3 = DIFF_METHOD::w3; +constexpr DIFF_METHOD DIFF_C4 = DIFF_METHOD::c4; +constexpr DIFF_METHOD DIFF_U3 = DIFF_METHOD::u3; +constexpr DIFF_METHOD DIFF_FFT = DIFF_METHOD::fft; +constexpr DIFF_METHOD DIFF_SPLIT = DIFF_METHOD::split; +constexpr DIFF_METHOD DIFF_S2 = DIFF_METHOD::s2; std::string toString(DIFF_METHOD location); DEPRECATED(inline std::string DIFF_METHOD_STRING(DIFF_METHOD location)) { @@ -73,11 +73,11 @@ DEPRECATED(inline std::string DIFF_METHOD_STRING(DIFF_METHOD location)) { /// Specify grid region for looping enum class REGION {all, nobndry, nox, noy, noz}; -#define RGN_ALL REGION::all -#define RGN_NOBNDRY REGION::nobndry -#define RGN_NOX REGION::nox -#define RGN_NOY REGION::noy -#define RGN_NOZ REGION::noz +constexpr REGION RGN_ALL = REGION::all; +constexpr REGION RGN_NOBNDRY = REGION::nobndry; +constexpr REGION RGN_NOX = REGION::nox; +constexpr REGION RGN_NOY = REGION::noy; +constexpr REGION RGN_NOZ = REGION::noz; std::string toString(REGION region); DEPRECATED(inline std::string REGION_STRING(REGION region)) { return toString(region); } diff --git a/include/difops.hxx b/include/difops.hxx index db90f5d7b4..af8629acbb 100644 --- a/include/difops.hxx +++ b/include/difops.hxx @@ -322,11 +322,11 @@ enum class BRACKET_METHOD { /// timestep from the solver arakawa_old ///< Older version, for regression testing of optimised version. }; -#define BRACKET_STD BRACKET_METHOD::standard -#define BRACKET_SIMPLE BRACKET_METHOD::simple -#define BRACKET_ARAKAWA BRACKET_METHOD::arakawa -#define BRACKET_CTU BRACKET_METHOD::ctu -#define BRACKET_ARAKAWA_OLD BRACKET_METHOD::arakawa_old +constexpr BRACKET_METHOD BRACKET_STD = BRACKET_METHOD::standard; +constexpr BRACKET_METHOD BRACKET_SIMPLE = BRACKET_METHOD::simple; +constexpr BRACKET_METHOD BRACKET_ARAKAWA = BRACKET_METHOD::arakawa; +constexpr BRACKET_METHOD BRACKET_CTU = BRACKET_METHOD::ctu; +constexpr BRACKET_METHOD BRACKET_ARAKAWA_OLD = BRACKET_METHOD::arakawa_old; /*! * Compute advection operator terms, which can be cast as From 5936521e36be44d50b3962be69609cac34b07660 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 3 Oct 2019 16:37:10 +0100 Subject: [PATCH 1744/1783] Fix y-extrapolation in BoundaryDirichlet::apply(Field2D&) --- src/mesh/boundary_standard.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 166c1b3306..6895eb2592 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -299,7 +299,7 @@ void BoundaryDirichlet::apply(Field2D &f,BoutReal t) { // Need to set second guard cell, as may be used for interpolation or upwinding derivatives for(int i=1;iwidth;i++) { int xi = bndry->x + i*bndry->bx; - int yi = bndry->y + i*bndry->bx; + int yi = bndry->y + i*bndry->by; f(xi, yi) = 2*f(xi - bndry->bx, yi - bndry->by) - f(xi - 2*bndry->bx, yi - 2*bndry->by); } } From 26becdd4c4e840cab9468a6fe552a2b82d44a4aa Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 8 Oct 2019 09:43:15 +0100 Subject: [PATCH 1745/1783] Fix assignment instead of comparison in ASSERTs --- .../laplace/impls/shoot/shoot_laplace.cxx | 2 +- src/invert/laplace/impls/spt/spt.cxx | 2 +- src/invert/laplace/invert_laplace.cxx | 2 +- src/mesh/boundary_standard.cxx | 44 +++++++++---------- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/invert/laplace/impls/shoot/shoot_laplace.cxx b/src/invert/laplace/impls/shoot/shoot_laplace.cxx index 36a4d13dca..b31a710455 100644 --- a/src/invert/laplace/impls/shoot/shoot_laplace.cxx +++ b/src/invert/laplace/impls/shoot/shoot_laplace.cxx @@ -70,7 +70,7 @@ LaplaceShoot::LaplaceShoot(Options *opt, const CELL_LOC loc, Mesh *mesh_in) } FieldPerp LaplaceShoot::solve(const FieldPerp& rhs) { - ASSERT1(localmesh = rhs.getMesh()); + ASSERT1(localmesh == rhs.getMesh()); ASSERT1(rhs.getLocation() == location); FieldPerp x{emptyFrom(rhs)}; // Result diff --git a/src/invert/laplace/impls/spt/spt.cxx b/src/invert/laplace/impls/spt/spt.cxx index f75abe4f23..1960d38928 100644 --- a/src/invert/laplace/impls/spt/spt.cxx +++ b/src/invert/laplace/impls/spt/spt.cxx @@ -121,7 +121,7 @@ FieldPerp LaplaceSPT::solve(const FieldPerp& b, const FieldPerp& x0) { Field3D LaplaceSPT::solve(const Field3D& b) { ASSERT1(b.getLocation() == location); - ASSERT1(localmesh = b.getMesh()); + ASSERT1(localmesh == b.getMesh()); Timer timer("invert"); Field3D x{emptyFrom(b)}; diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index 0fb6e60ae1..626859c73e 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -144,7 +144,7 @@ Field3D Laplacian::solve(const Field3D& b) { TRACE("Laplacian::solve(Field3D)"); ASSERT1(b.getLocation() == location); - ASSERT1(localmesh = b.getMesh()); + ASSERT1(localmesh == b.getMesh()); Timer timer("invert"); int ys = localmesh->ystart, ye = localmesh->yend; diff --git a/src/mesh/boundary_standard.cxx b/src/mesh/boundary_standard.cxx index 166c1b3306..19c7e3d627 100644 --- a/src/mesh/boundary_standard.cxx +++ b/src/mesh/boundary_standard.cxx @@ -2218,7 +2218,7 @@ void BoundaryNeumann_O4::apply(Field3D &f) { void BoundaryNeumann_O4::apply(Field3D &f,BoutReal t) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); bndry->first(); // Decide which generator to use @@ -2275,7 +2275,7 @@ void BoundaryNeumann_O4::apply_ddt(Field2D &f) { void BoundaryNeumann_O4::apply_ddt(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -2307,7 +2307,7 @@ void BoundaryNeumann_4thOrder::apply(Field2D &f) { void BoundaryNeumann_4thOrder::apply(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Coordinates *metric = f.getCoordinates(); // Set (at 4th order) the gradient at the mid-point between the guard cell and the grid cell to be val // This sets the value of the co-ordinate derivative, i.e. DDX/DDY not Grad_par/Grad_perp.x @@ -2327,7 +2327,7 @@ void BoundaryNeumann_4thOrder::apply_ddt(Field2D &f) { void BoundaryNeumann_4thOrder::apply_ddt(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -2354,7 +2354,7 @@ void BoundaryNeumannPar::apply(Field2D &f) { void BoundaryNeumannPar::apply(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Coordinates *metric = f.getCoordinates(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -2411,7 +2411,7 @@ void BoundaryRobin::apply(Field2D &f) { void BoundaryRobin::apply(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); if(fabs(bval) < 1.e-12) { for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -2436,7 +2436,7 @@ void BoundaryConstGradient::apply(Field2D &f){ void BoundaryConstGradient::apply(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) f(bndry->x, bndry->y, z) = 2.*f(bndry->x - bndry->bx, bndry->y - bndry->by, z) - f(bndry->x - 2*bndry->bx,bndry->y - 2*bndry->by,z); @@ -2486,7 +2486,7 @@ void BoundaryZeroLaplace::apply(Field2D &f) { void BoundaryZeroLaplace::apply(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); int ncz = mesh->LocalNz; Coordinates *metric = f.getCoordinates(); @@ -2578,7 +2578,7 @@ void BoundaryZeroLaplace2::apply(Field2D &f) { void BoundaryZeroLaplace2::apply(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); int ncz = mesh->LocalNz; ASSERT0(ncz % 2 == 0); // Allocation assumes even number @@ -2676,7 +2676,7 @@ void BoundaryConstLaplace::apply(Field3D &f) { } Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Coordinates *metric = f.getCoordinates(); int ncz = mesh->LocalNz; @@ -2746,7 +2746,7 @@ void BoundaryDivCurl::apply(Vector2D &UNUSED(f)) { void BoundaryDivCurl::apply(Vector3D &var) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = var.x.getMesh()); + ASSERT1(mesh == var.x.getMesh()); int jx, jy, jz, jzp, jzm; BoutReal tmp; @@ -2857,7 +2857,7 @@ void BoundaryFree_O2::apply(Field2D &f) { // N.B. Only first guard cells (closest to the grid) should ever be used Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); bndry->first(); // Check for staggered grids @@ -2956,7 +2956,7 @@ void BoundaryFree_O2::apply(Field3D &f) { // Extrapolate from the last evolved simulation cells into the guard cells at 3rd order. Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); bndry->first(); // Check for staggered grids @@ -3076,7 +3076,7 @@ void BoundaryFree_O2::apply_ddt(Field2D &f) { void BoundaryFree_O2::apply_ddt(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -3099,7 +3099,7 @@ BoundaryOp* BoundaryFree_O3::clone(BoundaryRegion *region, const std::listlocalmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); bndry->first(); // Check for staggered grids @@ -3199,7 +3199,7 @@ void BoundaryFree_O3::apply(Field3D &f) { // Extrapolate from the last evolved simulation cells into the guard cells at 3rd order. Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); bndry->first(); @@ -3328,7 +3328,7 @@ void BoundaryFree_O3::apply_ddt(Field2D &f) { void BoundaryFree_O3::apply_ddt(Field3D &f) { Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); Field3D *dt = f.timeDeriv(); for(bndry->first(); !bndry->isDone(); bndry->next()) for(int z=0;zLocalNz;z++) @@ -3381,7 +3381,7 @@ void BoundaryRelax::apply_ddt(Field3D &f) { TRACE("BoundaryRelax::apply_ddt(Field3D)"); Mesh* mesh = bndry->localmesh; - ASSERT1(mesh = f.getMesh()); + ASSERT1(mesh == f.getMesh()); // Make a copy of f Field3D g = f; // NOTE: This is not very efficient... copying entire field @@ -3456,7 +3456,7 @@ void BoundaryToFieldAligned::apply(Field2D &f, BoutReal t) { } void BoundaryToFieldAligned::apply(Field3D &f, BoutReal t) { - ASSERT1(bndry->localmesh = f.getMesh()); + ASSERT1(bndry->localmesh == f.getMesh()); //NOTE: This is not very efficient... updating entire field f = fromFieldAligned(f); @@ -3477,7 +3477,7 @@ void BoundaryToFieldAligned::apply_ddt(Field2D &f) { } void BoundaryToFieldAligned::apply_ddt(Field3D &f) { - ASSERT1(bndry->localmesh = f.getMesh()); + ASSERT1(bndry->localmesh == f.getMesh()); f = fromFieldAligned(f); ddt(f) = fromFieldAligned(ddt(f)); @@ -3503,7 +3503,7 @@ void BoundaryFromFieldAligned::apply(Field2D &f, BoutReal t) { } void BoundaryFromFieldAligned::apply(Field3D &f, BoutReal t) { - ASSERT1(bndry->localmesh = f.getMesh()); + ASSERT1(bndry->localmesh == f.getMesh()); //NOTE: This is not very efficient... shifting entire field f = toFieldAligned(f); @@ -3524,7 +3524,7 @@ void BoundaryFromFieldAligned::apply_ddt(Field2D &f) { } void BoundaryFromFieldAligned::apply_ddt(Field3D &f) { - ASSERT1(bndry->localmesh = f.getMesh()); + ASSERT1(bndry->localmesh == f.getMesh()); f = toFieldAligned(f); ddt(f) = toFieldAligned(ddt(f)); From 27778707a41925bab7bf516a3c4bf4ccb94be4aa Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 9 Oct 2019 11:54:37 +0100 Subject: [PATCH 1746/1783] Fix for Intel enabling -Wnull-dereference despite not accepting it Intel needs an extra flag when checking what are acceptable warning flags --- configure | 41 ++++++++++++++++++++++++++++++++++++++++- configure.ac | 11 ++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/configure b/configure index daebd1c0f6..eb7ccefc5b 100755 --- a/configure +++ b/configure @@ -5614,6 +5614,7 @@ fi # If this is passed to GCC, it will explode, so the flag must be enabled # conditionally. # This check taken from AX_COMPILER_FLAGS_CXXFLAGS +extra_compiler_flags_test="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts -Werror=unknown-warning-option" >&5 $as_echo_n "checking whether C++ compiler accepts -Werror=unknown-warning-option... " >&6; } if ${ax_cv_check_cxxflags___Werror_unknown_warning_option+:} false; then : @@ -5648,11 +5649,49 @@ if test "x$ax_cv_check_cxxflags___Werror_unknown_warning_option" = xyes; then : extra_compiler_flags_test="-Werror=unknown-warning-option" else + : +fi - extra_compiler_flags_test="" +# A similar check to above, but for Intel. -we is undocumented, but +# the equivalent (?) -diag-error gets accepted by GCC. 10006 is +# "unknown option", and 10148 is the more recent "unknown warning +# option" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts -we10006,10148" >&5 +$as_echo_n "checking whether C++ compiler accepts -we10006,10148... " >&6; } +if ${ax_cv_check_cxxflags___we10006_10148+:} false; then : + $as_echo_n "(cached) " >&6 +else + ax_check_save_flags=$CXXFLAGS + CXXFLAGS="$CXXFLAGS -we10006,10148" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ax_cv_check_cxxflags___we10006_10148=yes +else + ax_cv_check_cxxflags___we10006_10148=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXXFLAGS=$ax_check_save_flags fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_cxxflags___we10006_10148" >&5 +$as_echo "$ax_cv_check_cxxflags___we10006_10148" >&6; } +if test "x$ax_cv_check_cxxflags___we10006_10148" = xyes; then : + + extra_compiler_flags_test="-we10006,10148" +else + : +fi if test "x$enable_warnings" != "xno"; then : diff --git a/configure.ac b/configure.ac index f735f67880..ffc914377b 100644 --- a/configure.ac +++ b/configure.ac @@ -218,12 +218,17 @@ AC_SUBST([COVERAGE_FLAGS]) # If this is passed to GCC, it will explode, so the flag must be enabled # conditionally. # This check taken from AX_COMPILER_FLAGS_CXXFLAGS +extra_compiler_flags_test="" AX_CHECK_COMPILE_FLAG([-Werror=unknown-warning-option],[ extra_compiler_flags_test="-Werror=unknown-warning-option" -],[ - extra_compiler_flags_test="" ]) - +# A similar check to above, but for Intel. -we is undocumented, but +# the equivalent (?) -diag-error gets accepted by GCC. 10006 is +# "unknown option", and 10148 is the more recent "unknown warning +# option" +AX_CHECK_COMPILE_FLAG([-we10006,10148],[ + extra_compiler_flags_test="-we10006,10148" +]) AS_IF([test "x$enable_warnings" != "xno"], [ # Some hopefully sensible default compiler warning flags From bda11ff31e7046000a549f0542d4ca2fa9fbe2db Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 11 Oct 2019 11:53:19 +0100 Subject: [PATCH 1747/1783] Remove some superfluous location checks in Laplacian Coefficient locations are checked when set, and checking again in tridagCoefs can cause >20% performance degradation --- src/invert/laplace/invert_laplace.cxx | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index 626859c73e..3696e40258 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -299,12 +299,6 @@ void Laplacian::tridagCoefs(int jx, int jy, BoutReal kwave, localcoords = localmesh->getCoordinates(loc); } - ASSERT1(c1coef == nullptr || c1coef->getLocation() == loc); - ASSERT1(c2coef == nullptr || c2coef->getLocation() == loc); - ASSERT1( (c1coef == nullptr and c2coef == nullptr) - or (c1coef != nullptr and c2coef != nullptr) ); - ASSERT1(d == nullptr || d->getLocation() == loc); - BoutReal coef1, coef2, coef3, coef4, coef5; coef1=localcoords->g11(jx,jy); ///< X 2nd derivative coefficient @@ -369,10 +363,6 @@ void Laplacian::tridagMatrix(dcomplex **avec, dcomplex **bvec, dcomplex **cvec, const Field2D *a, const Field2D *ccoef, const Field2D *d) { - ASSERT1(a->getLocation() == location); - ASSERT1(ccoef->getLocation() == location); - ASSERT1(d->getLocation() == location); - BOUT_OMP(parallel for) for(int kz = 0; kz <= maxmode; kz++) { BoutReal kwave=kz*2.0*PI/coords->zlength(); // wave number is 1/[rad] @@ -430,11 +420,6 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, const Field2D *d, bool includeguards) { - ASSERT1(a->getLocation() == location); - ASSERT1(c1coef->getLocation() == location); - ASSERT1(c2coef->getLocation() == location); - ASSERT1(d->getLocation() == location); - int xs = 0; // xstart set to the start of x on this processor (including ghost points) int xe = localmesh->LocalNx-1; // xend set to the end of x on this processor (including ghost points) @@ -761,13 +746,6 @@ void laplace_tridag_coefs(int jx, int jy, int jz, dcomplex &a, dcomplex &b, dcom int invert_laplace(const FieldPerp &b, FieldPerp &x, int flags, const Field2D *a, const Field2D *c, const Field2D *d) { - // Laplacian::defaultInstance is at CELL_CENTRE - ASSERT1(b.getLocation() == CELL_CENTRE); - ASSERT1(x.getLocation() == CELL_CENTRE); - ASSERT1(a->getLocation() == CELL_CENTRE); - ASSERT1(c->getLocation() == CELL_CENTRE); - ASSERT1(d->getLocation() == CELL_CENTRE); - Laplacian *lap = Laplacian::defaultInstance(); if (a != nullptr) { From 2f088b96939158404c97be95237cec279fc5290c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Mon, 14 Oct 2019 13:17:25 +0100 Subject: [PATCH 1748/1783] Add back C1, C2 consistency check Some refactoring may remove the need for this check as well --- src/invert/laplace/invert_laplace.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/invert/laplace/invert_laplace.cxx b/src/invert/laplace/invert_laplace.cxx index 3696e40258..04046b263c 100644 --- a/src/invert/laplace/invert_laplace.cxx +++ b/src/invert/laplace/invert_laplace.cxx @@ -420,6 +420,10 @@ void Laplacian::tridagMatrix(dcomplex *avec, dcomplex *bvec, dcomplex *cvec, const Field2D *d, bool includeguards) { + // Better have either both or neither C coefficients + ASSERT3((c1coef == nullptr and c2coef == nullptr) + or (c1coef != nullptr and c2coef != nullptr)) + int xs = 0; // xstart set to the start of x on this processor (including ghost points) int xe = localmesh->LocalNx-1; // xend set to the end of x on this processor (including ghost points) From 0a7a5bc98b265f6ee9883c04be1cceafab8c88aa Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 16 Oct 2019 16:48:13 +0100 Subject: [PATCH 1749/1783] Fix typo in D4DY4: wrong YDirectionType --- include/bout/index_derivs_interface.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index f09892652a..778ddb1c15 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -239,7 +239,7 @@ T D4DY4(const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = return standardDerivative( f, outloc, method, region); } else { - const bool is_unaligned = (f.getDirectionY() == YDirectionType::Aligned); + const bool is_unaligned = (f.getDirectionY() == YDirectionType::Standard); const T f_aligned = is_unaligned ? toFieldAligned(f, "RGN_NOX") : f; T result = standardDerivative( f_aligned, outloc, method, region); From d7fbe9319daf304e55a7069a1df415443117feae Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 16 Oct 2019 16:48:42 +0100 Subject: [PATCH 1750/1783] Add consistency check in toFieldAligned for FieldFactory test --- tests/unit/field/test_field_factory.cxx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/unit/field/test_field_factory.cxx b/tests/unit/field/test_field_factory.cxx index 3afdd5ba3b..23ccdeaef7 100644 --- a/tests/unit/field/test_field_factory.cxx +++ b/tests/unit/field/test_field_factory.cxx @@ -779,8 +779,18 @@ class MockParallelTransform : public ParallelTransform { return -f; } - const Field3D toFieldAligned(const Field3D& f, const std::string&) override { return -f; } - const FieldPerp toFieldAligned(const FieldPerp& f, const std::string&) override { return -f; } + const Field3D toFieldAligned(const Field3D& f, const std::string&) override { + if (f.getDirectionY() != YDirectionType::Standard) { + throw BoutException("Aligned field passed to toFieldAligned"); + } + return -f; + } + const FieldPerp toFieldAligned(const FieldPerp& f, const std::string&) override { + if (f.getDirectionY() != YDirectionType::Standard) { + throw BoutException("Aligned field passed to toFieldAligned"); + } + return -f; + } private: const bool allow_transform; From 963ae0525f7fa5c10cfeaea3abb890a351f2aea7 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Thu, 17 Oct 2019 17:02:08 +0100 Subject: [PATCH 1751/1783] Replace 'int startz' with 'bool zero_DC' in cyclic_laplace.cxx Makes intention clearer. --- .../laplace/impls/cyclic/cyclic_laplace.cxx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index f1502d50a9..8bba1416d5 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -232,19 +232,19 @@ FieldPerp LaplaceCyclic::solve(const FieldPerp& rhs, const FieldPerp& x0) { auto k1d = Array((localmesh->LocalNz) / 2 + 1); // ZFFT routine expects input of this length - int startz = 0; + bool zero_DC = false; if(global_flags & INVERT_ZERO_DC) { // No DC component - startz = 1; + zero_DC = true; } BOUT_OMP(for nowait) for (int ix = xs; ix <= xe; ix++) { - if (startz == 1) { + if (zero_DC) { k1d[0] = 0.; } - for (int kz = startz; kz < nmode; kz++) + for (int kz = zero_DC; kz < nmode; kz++) k1d[kz] = xcmplx(kz, ix - xs); for (int kz = nmode; kz < (localmesh->LocalNz) / 2 + 1; kz++) @@ -450,10 +450,10 @@ Field3D LaplaceCyclic::solve(const Field3D& rhs, const Field3D& x0) { auto k1d = Array((localmesh->LocalNz) / 2 + 1); // ZFFT routine expects input of this length - int startz = 0; + bool zero_DC = false; if(global_flags & INVERT_ZERO_DC) { // No DC component - startz = 1; + zero_DC = true; } BOUT_OMP(for nowait) @@ -462,11 +462,11 @@ Field3D LaplaceCyclic::solve(const Field3D& rhs, const Field3D& x0) { int ix = xs + ind / ny; int iy = ys + ind % ny; - if (startz == 1) { + if (zero_DC) { k1d[0] = 0.; } - for (int kz = startz; kz < nmode; kz++) + for (int kz = zero_DC; kz < nmode; kz++) k1d[kz] = xcmplx3D((iy - ys) * nmode + kz, ix - xs); for (int kz = nmode; kz < localmesh->LocalNz / 2 + 1; kz++) From 178bbe92b4ea85981e871b52bb6dd43814cfebf7 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 18 Oct 2019 09:33:51 +0100 Subject: [PATCH 1752/1783] Bugfix: result of InvertParCR::solve tagged in wrong y space --- src/invert/parderiv/impls/cyclic/cyclic.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/invert/parderiv/impls/cyclic/cyclic.cxx b/src/invert/parderiv/impls/cyclic/cyclic.cxx index d344e02865..aeec5f57cb 100644 --- a/src/invert/parderiv/impls/cyclic/cyclic.cxx +++ b/src/invert/parderiv/impls/cyclic/cyclic.cxx @@ -58,7 +58,7 @@ const Field3D InvertParCR::solve(const Field3D &f) { TRACE("InvertParCR::solve(Field3D)"); ASSERT1(localmesh == f.getMesh()); - Field3D result{emptyFrom(f)}; + Field3D result = emptyFrom(f).setDirectionY(YDirectionType::Aligned); Coordinates *coord = f.getCoordinates(); From 3f11101ec43c9b7bbce5b3fbe8e0ab25c8c2a890 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Fri, 18 Oct 2019 19:56:32 +0200 Subject: [PATCH 1753/1783] Bugfixes for writing Vector2D and Vector3D Previously: * a typo meant the z-component was incorrectly named when added to the file * contravariant vectors had their components (incorrectly) added with '_x', '_y' and '_z' suffixes (which should be used for the covariant components), but were written (correctly) with 'x', 'y' and 'z' suffixes, causing a 'variable has not been added' error --- src/fileio/datafile.cxx | 193 +++++++++++++++++++++++++++++----------- 1 file changed, 139 insertions(+), 54 deletions(-) diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 7147d2d42e..4d59a27e03 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -261,27 +261,51 @@ bool Datafile::openw(const char *format, ...) { // 2D vectors for(const auto& var : v2d_arr) { - if (!file->addVarField2D(var.name + "_x", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField2D(var.name + "_y", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField2D(var.name + "_y", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + if(var.covar) { + if (!file->addVarField2D(var.name + "_x", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField2D(var.name + "_y", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField2D(var.name + "_z", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + } + } else { + if (!file->addVarField2D(var.name + "x", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField2D(var.name + "y", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField2D(var.name + "z", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + } } } // 3D vectors for(const auto& var : v3d_arr) { - if (!file->addVarField3D(var.name + "_x", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField3D(var.name + "_y", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField3D(var.name + "_y", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + if(var.covar) { + if (!file->addVarField3D(var.name + "_x", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField3D(var.name + "_y", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField3D(var.name + "_z", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + } + } else { + if (!file->addVarField3D(var.name + "x", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField3D(var.name + "y", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField3D(var.name + "z", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + } } } if (openclose) { @@ -375,27 +399,51 @@ bool Datafile::opena(const char *format, ...) { // 2D vectors for(const auto& var : v2d_arr) { - if (!file->addVarField2D(var.name + "_x", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField2D(var.name + "_y", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField2D(var.name + "_y", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + if (var.covar) { + if (!file->addVarField2D(var.name + "_x", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField2D(var.name + "_y", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField2D(var.name + "_z", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + } + } else { + if (!file->addVarField2D(var.name + "x", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField2D(var.name + "y", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField2D(var.name + "z", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); + } } } // 3D vectors for(const auto& var : v3d_arr) { - if (!file->addVarField3D(var.name + "_x", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField3D(var.name + "_y", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField3D(var.name + "_y", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + if (var.covar) { + if (!file->addVarField3D(var.name + "_x", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField3D(var.name + "_y", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField3D(var.name + "_z", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + } + } else { + if (!file->addVarField3D(var.name + "x", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField3D(var.name + "y", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + } + if (!file->addVarField3D(var.name + "z", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); + } } } if (openclose) { @@ -770,14 +818,27 @@ void Datafile::add(Vector2D &f, const char *name, bool save_repeat) { file->setLowPrecision(); // Add variables to file - if (!file->addVarField2D(d.name + "_x", save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", name); - } - if (!file->addVarField2D(d.name + "_y", save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", name); - } - if (!file->addVarField2D(d.name + "_z", save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", name); + if (d.covar) { + if (!file->addVarField2D(d.name + "_x", save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", name); + } + if (!file->addVarField2D(d.name + "_y", save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", name); + } + if (!file->addVarField2D(d.name + "_z", save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", name); + } + } else { + if (!file->addVarField2D(d.name + "x", save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", name); + } + if (!file->addVarField2D(d.name + "y", save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", name); + } + if (!file->addVarField2D(d.name + "z", save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", name); + } + } if(openclose) { @@ -826,14 +887,26 @@ void Datafile::add(Vector3D &f, const char *name, bool save_repeat) { file->setLowPrecision(); // Add variables to file - if (!file->addVarField3D(d.name + "_x", save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", name); - } - if (!file->addVarField3D(d.name + "_y", save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", name); - } - if (!file->addVarField3D(d.name + "_z", save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", name); + if (d.covar) { + if (!file->addVarField3D(d.name + "_x", save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", name); + } + if (!file->addVarField3D(d.name + "_y", save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", name); + } + if (!file->addVarField3D(d.name + "_z", save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", name); + } + } else { + if (!file->addVarField3D(d.name + "x", save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", name); + } + if (!file->addVarField3D(d.name + "y", save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", name); + } + if (!file->addVarField3D(d.name + "z", save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", name); + } } if(openclose) { @@ -1033,17 +1106,29 @@ bool Datafile::write() { // 2D vectors for(const auto& var : v2d_arr) { Vector2D v = *(var.ptr); - file->writeFieldAttributes(var.name+"_x", v.x); - file->writeFieldAttributes(var.name+"_y", v.y); - file->writeFieldAttributes(var.name+"_z", v.z); + if (var.covar) { + file->writeFieldAttributes(var.name+"_x", v.x); + file->writeFieldAttributes(var.name+"_y", v.y); + file->writeFieldAttributes(var.name+"_z", v.z); + } else { + file->writeFieldAttributes(var.name+"x", v.x); + file->writeFieldAttributes(var.name+"y", v.y); + file->writeFieldAttributes(var.name+"z", v.z); + } } // 3D vectors for(const auto& var : v3d_arr) { Vector3D v = *(var.ptr); - file->writeFieldAttributes(var.name+"_x", v.x); - file->writeFieldAttributes(var.name+"_y", v.y); - file->writeFieldAttributes(var.name+"_z", v.z); + if (var.covar) { + file->writeFieldAttributes(var.name+"_x", v.x); + file->writeFieldAttributes(var.name+"_y", v.y); + file->writeFieldAttributes(var.name+"_z", v.z); + } else { + file->writeFieldAttributes(var.name+"x", v.x); + file->writeFieldAttributes(var.name+"y", v.y); + file->writeFieldAttributes(var.name+"z", v.z); + } } } From 61896c6b957a64f3c9467814add3797a98daa41d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 19 Oct 2019 14:20:29 +0100 Subject: [PATCH 1754/1783] Ensure parallel_transform is only read from grid files, not from options Previously 'mesh:parallel_transform' could be read from options in the input file, causing unexpected/incorrect behaviour, as 'parallel_transform' was intended only for checking that a grid file is compatible with the selected ParallelTransform. This commit adds a method to Mesh to check whether the grid source is a file, and only gets 'parallel_transform' from the grid if it is, preventing parallel_transform from ever being read from options. --- include/bout/griddata.hxx | 4 ++++ include/bout/mesh.hxx | 3 +++ src/mesh/data/gridfromfile.cxx | 2 +- src/mesh/mesh.cxx | 4 ++++ src/mesh/parallel/fci.cxx | 5 +++-- src/mesh/parallel/identity.cxx | 5 +++-- src/mesh/parallel/shiftedmetric.cxx | 5 +++-- 7 files changed, 21 insertions(+), 7 deletions(-) diff --git a/include/bout/griddata.hxx b/include/bout/griddata.hxx index a07603e38e..7fba6751af 100644 --- a/include/bout/griddata.hxx +++ b/include/bout/griddata.hxx @@ -48,6 +48,7 @@ class GridDataSource; */ class GridDataSource { public: + GridDataSource(const bool source_is_file = false) : is_file(source_is_file) {} virtual ~GridDataSource() = default; virtual bool hasVar(const std::string &name) = 0; ///< Test if source can supply a variable @@ -82,6 +83,9 @@ public: /// Are y-boundary guard cells read from the source? virtual bool hasYBoundaryGuards() = 0; + + /// Is the data source a grid file? + const bool is_file; }; /// Interface to grid data in a file diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 08a3ca2c97..51dc57649e 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -216,6 +216,9 @@ class Mesh { /// @returns zero always. int get(Vector3D &var, const std::string &name, BoutReal def=0.0); + /// Test if input source was a grid file + bool isSourceFile() const; + /// Wrapper for GridDataSource::hasVar bool sourceHasVar(const std::string &name); diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 83af8eaa3d..217c49cb3a 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -26,7 +26,7 @@ * destructor */ GridFile::GridFile(std::unique_ptr format, std::string gridfilename) - : file(std::move(format)), filename(std::move(gridfilename)) { + : GridDataSource(true), file(std::move(format)), filename(std::move(gridfilename)) { TRACE("GridFile constructor"); if (! file->openr(filename) ) { diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 29c21620a4..077c2459ff 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -209,6 +209,10 @@ int Mesh::get(Vector3D &var, const std::string &name, BoutReal def) { return 0; } +bool Mesh::isSourceFile() const { + return source->is_file; +} + bool Mesh::sourceHasVar(const std::string &name) { TRACE("Mesh::sourceHasVar(%s)", name.c_str()); if (source == nullptr) diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index 091dac47cd..d4364ef063 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -326,13 +326,14 @@ Field3D FCIMap::integrate(Field3D &f) const { void FCITransform::checkInputGrid() { std::string parallel_transform; - if (!mesh.get(parallel_transform, "parallel_transform")) { + if (mesh.isSourceFile() && !mesh.get(parallel_transform, "parallel_transform")) { if (parallel_transform != "fci") { throw BoutException("Incorrect parallel transform type '"+parallel_transform+"' used " "to generate metric components for FCITransform. Should be 'fci'."); } } // else: parallel_transform variable not found in grid input, indicates older input - // file so must rely on the user having ensured the type is correct + // file or grid from options so must rely on the user having ensured the type is + // correct } void FCITransform::calcParallelSlices(Field3D& f) { diff --git a/src/mesh/parallel/identity.cxx b/src/mesh/parallel/identity.cxx index bf2bdc2930..0d5e796163 100644 --- a/src/mesh/parallel/identity.cxx +++ b/src/mesh/parallel/identity.cxx @@ -26,12 +26,13 @@ void ParallelTransformIdentity::calcParallelSlices(Field3D& f) { void ParallelTransformIdentity::checkInputGrid() { std::string parallel_transform; - if (!mesh.get(parallel_transform, "parallel_transform")) { + if (mesh.isSourceFile() and !mesh.get(parallel_transform, "parallel_transform")) { if (parallel_transform != "identity") { throw BoutException("Incorrect parallel transform type '"+parallel_transform+"' used " "to generate metric components for ParallelTransformIdentity. Should be " "'identity'."); } } // else: parallel_transform variable not found in grid input, indicates older input - // file so must rely on the user having ensured the type is correct + // file or grid from options so must rely on the user having ensured the type is + // correct } diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 1450478d8e..808066b85e 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -28,14 +28,15 @@ ShiftedMetric::ShiftedMetric(Mesh& m, CELL_LOC location_in, Field2D zShift_, void ShiftedMetric::checkInputGrid() { std::string parallel_transform; - if (!mesh.get(parallel_transform, "parallel_transform")) { + if (mesh.isSourceFile() and !mesh.get(parallel_transform, "parallel_transform")) { if (parallel_transform != "shiftedmetric") { throw BoutException("Incorrect parallel transform type '" + parallel_transform + "' used to generate metric components for ShiftedMetric. " "Should be 'shiftedmetric'."); } } // else: parallel_transform variable not found in grid input, indicates older input - // file so must rely on the user having ensured the type is correct + // file or grid from options so must rely on the user having ensured the type is + // correct } void ShiftedMetric::outputVars(Datafile& file) { From 28c7b84d4a7265168b2ea8b193fad3f0a47b2da8 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 19 Oct 2019 15:16:21 +0100 Subject: [PATCH 1755/1783] Return false from Mesh::isSourceFile() if source==nullptr Avoids segfault if Mesh::source has not been created. Mostly needed for unit tests. --- src/mesh/mesh.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 077c2459ff..2887ab8935 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -210,7 +210,7 @@ int Mesh::get(Vector3D &var, const std::string &name, BoutReal def) { } bool Mesh::isSourceFile() const { - return source->is_file; + return source != nullptr and source->is_file; } bool Mesh::sourceHasVar(const std::string &name) { From 1cbd57bf9bb44426da64b8e6374d5187fa9c42fe Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 19 Oct 2019 19:09:35 +0100 Subject: [PATCH 1756/1783] Add unit tests for y-interpolation of field-aligned inputs --- tests/unit/mesh/test_interpolation.cxx | 48 ++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index f59e0ccb96..6d37cb4fea 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -184,6 +184,54 @@ TEST_F(Field3DInterpToTest, CellYlowToCentreNoBndry) { EXPECT_NEAR(output(2, 2, 2), 2.525, 1.e-15); } +TEST_F(Field3DInterpToTest, AlignedCellCentreToYlow) { + + Field3D output = Field3D(mesh); + + // CELL_CENTRE -> CELL_YLOW + input.setLocation(CELL_CENTRE).setDirectionY(YDirectionType::Aligned); + output = interp_to(input, CELL_YLOW); + EXPECT_TRUE(output.getLocation() == CELL_YLOW); + EXPECT_TRUE(output.getDirectionY() == YDirectionType::Aligned); + EXPECT_NEAR(output(2, 2, 2), 2.825, 1.e-15); +} + +TEST_F(Field3DInterpToTest, AlignedCellCentreToYlowNoBndry) { + + Field3D output = Field3D(mesh); + + // CELL_CENTRE -> CELL_YLOW + input.setLocation(CELL_CENTRE).setDirectionY(YDirectionType::Aligned); + output = interp_to(input, CELL_YLOW, "RGN_NOBNDRY"); + EXPECT_TRUE(output.getLocation() == CELL_YLOW); + EXPECT_TRUE(output.getDirectionY() == YDirectionType::Aligned); + EXPECT_NEAR(output(2, 2, 2), 2.825, 1.e-15); +} + +TEST_F(Field3DInterpToTest, AlignedCellYlowToCentre) { + + Field3D output = Field3D(mesh); + + // CELL_YLOW -> CELL_CENTRE + input.setLocation(CELL_YLOW).setDirectionY(YDirectionType::Aligned); + output = interp_to(input, CELL_CENTRE); + EXPECT_TRUE(output.getLocation() == CELL_CENTRE); + EXPECT_TRUE(output.getDirectionY() == YDirectionType::Aligned); + EXPECT_NEAR(output(2, 2, 2), 2.525, 1.e-15); +} + +TEST_F(Field3DInterpToTest, AlignedCellYlowToCentreNoBndry) { + + Field3D output = Field3D(mesh); + + // CELL_YLOW -> CELL_CENTRE + input.setLocation(CELL_YLOW).setDirectionY(YDirectionType::Aligned); + output = interp_to(input, CELL_CENTRE, "RGN_NOBNDRY"); + EXPECT_TRUE(output.getLocation() == CELL_CENTRE); + EXPECT_TRUE(output.getDirectionY() == YDirectionType::Aligned); + EXPECT_NEAR(output(2, 2, 2), 2.525, 1.e-15); +} + TEST_F(Field3DInterpToTest, CellCentreToZlow) { Field3D output = Field3D(mesh); From 6176e13504fb3ad2f40d71f765f64dade7f958b0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 19 Oct 2019 19:11:26 +0100 Subject: [PATCH 1757/1783] Add checks on input to ParallelTransformIdentity::to/fromFieldAligned Makes behaviour of ParallelTransformIdentity implementations of toFieldAligned and fromFieldAligned consistent with the ShiftedMetric implementations in terms of throwing exceptions if passed input in the wrong (aligned/non-aligned) space. --- include/bout/paralleltransform.hxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/bout/paralleltransform.hxx b/include/bout/paralleltransform.hxx index 0b3c154de8..5ad8c729e1 100644 --- a/include/bout/paralleltransform.hxx +++ b/include/bout/paralleltransform.hxx @@ -114,10 +114,12 @@ public: * does nothing */ const Field3D toFieldAligned(const Field3D& f, const std::string& UNUSED(region) = "RGN_ALL") override { + ASSERT2(f.getDirectionY() == YDirectionType::Standard); Field3D result = f; return result.setDirectionY(YDirectionType::Aligned); } const FieldPerp toFieldAligned(const FieldPerp& f, const std::string& UNUSED(region) = "RGN_ALL") override { + ASSERT2(f.getDirectionY() == YDirectionType::Standard); FieldPerp result = f; return result.setDirectionY(YDirectionType::Aligned); } @@ -127,10 +129,12 @@ public: * does nothing */ const Field3D fromFieldAligned(const Field3D& f, const std::string& UNUSED(region) = "RGN_ALL") override { + ASSERT2(f.getDirectionY() == YDirectionType::Aligned); Field3D result = f; return result.setDirectionY(YDirectionType::Standard); } const FieldPerp fromFieldAligned(const FieldPerp& f, const std::string& UNUSED(region) = "RGN_ALL") override { + ASSERT2(f.getDirectionY() == YDirectionType::Aligned); FieldPerp result = f; return result.setDirectionY(YDirectionType::Standard); } From f8f1a56459b4a85487b9b4fa5f7bee5fd68e4481 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 19 Oct 2019 19:45:05 +0100 Subject: [PATCH 1758/1783] Make interp_to return result in the same space as the input --- include/interpolation.hxx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/interpolation.hxx b/include/interpolation.hxx index 754e13c324..1f82c4b50f 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -125,7 +125,11 @@ const T interp_to(const T& var, CELL_LOC loc, const std::string region = "RGN_AL ASSERT0(fieldmesh->ystart >= 2); // We can't interpolate in y unless we're field-aligned - const T var_fa = toFieldAligned(var, "RGN_NOX"); + const bool is_unaligned = (var.getDirectionY() == YDirectionType::Standard); + const T var_fa = is_unaligned ? toFieldAligned(var, "RGN_NOX") : var; + + result.setDirectionY(YDirectionType::Aligned); + if (region != "RGN_NOBNDRY") { // repeat the hack above for boundary points // this avoids a duplicate toFieldAligned call if we had called @@ -152,7 +156,9 @@ const T interp_to(const T& var, CELL_LOC loc, const std::string region = "RGN_AL } } - result = fromFieldAligned(result, "RGN_NOBNDRY"); + if (is_unaligned) { + result = fromFieldAligned(result, "RGN_NOBNDRY"); + } break; } From a5000cdca9a2c26d93acbacbe097bcb054b4e8df Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 19 Oct 2019 22:00:44 +0100 Subject: [PATCH 1759/1783] Fix check in interp_to(Field2D) Setting result.setDirectionY(YDirectionType::Aligned) is incorrect for Field2D, as Field2D is effectively always field-aligned, so YDirectionType::Aligned is not allowed for Field2D. Therefore need to skip 'result.setDirectionY(YDirectionType::Aligned)' for Field2D. --- include/interpolation.hxx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/interpolation.hxx b/include/interpolation.hxx index 1f82c4b50f..853091af34 100644 --- a/include/interpolation.hxx +++ b/include/interpolation.hxx @@ -128,7 +128,12 @@ const T interp_to(const T& var, CELL_LOC loc, const std::string region = "RGN_AL const bool is_unaligned = (var.getDirectionY() == YDirectionType::Standard); const T var_fa = is_unaligned ? toFieldAligned(var, "RGN_NOX") : var; - result.setDirectionY(YDirectionType::Aligned); + if (not std::is_base_of::value) { + // Field2D is axisymmetric, so YDirectionType::Standard and + // YDirectionType::Aligned are equivalent, but trying to set + // YDirectionType::Aligned explicitly is an error + result.setDirectionY(YDirectionType::Aligned); + } if (region != "RGN_NOBNDRY") { // repeat the hack above for boundary points From 9975a327681925e1cc4bf88b71d6cbcc4c1c21f3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Sat, 19 Oct 2019 22:29:44 +0100 Subject: [PATCH 1760/1783] Unit tests for interp_to(Field2D) --- tests/unit/mesh/test_interpolation.cxx | 151 +++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/tests/unit/mesh/test_interpolation.cxx b/tests/unit/mesh/test_interpolation.cxx index 6d37cb4fea..27df2c62ed 100644 --- a/tests/unit/mesh/test_interpolation.cxx +++ b/tests/unit/mesh/test_interpolation.cxx @@ -275,3 +275,154 @@ TEST_F(Field3DInterpToTest, CellZlowToCentreNoBndry) { EXPECT_TRUE(output.getLocation() == CELL_CENTRE); EXPECT_NEAR(output(2, 2, 2), 3.4, 1.e-15); } + +class Field2DInterpToTest : public ::testing::Test { +protected: + Field2DInterpToTest() : input(mesh) { + input = 0.; + input(2, 2) = 2.; + input(1, 2) = 1.8; + input(0, 2) = 1.7; + input(3, 2) = 1.3; + input(4, 2) = 1.5; + input(2, 1) = 3.8; + input(2, 0) = 3.7; + input(2, 3) = 3.3; + input(2, 4) = 3.5; + } + + static void SetUpTestCase() { + WithQuietOutput quiet_info{output_info}; + WithQuietOutput quiet_warn{output_warn}; + delete mesh; + mesh = new FakeMesh(nx, ny, nz); + mesh->StaggerGrids = true; + mesh->xstart = 2; + mesh->ystart = 2; + mesh->xend = nx - 3; + mesh->yend = ny - 3; + + mesh->createDefaultRegions(); + + // We need Coordinates so a parallel transform is available as + // FieldFactory::create3D wants to un-field-align the result + for (const auto& location + : std::list{CELL_CENTRE, CELL_XLOW, CELL_YLOW, CELL_ZLOW}) { + + static_cast(mesh)->setCoordinates(nullptr, location); + static_cast(mesh)->setCoordinates(std::make_shared( + mesh, Field2D{1.0, mesh}, Field2D{1.0, mesh}, BoutReal{1.0}, Field2D{1.0, mesh}, + Field2D{0.0, mesh}, Field2D{1.0, mesh}, Field2D{1.0, mesh}, Field2D{1.0, mesh}, + Field2D{0.0, mesh}, Field2D{0.0, mesh}, Field2D{0.0, mesh}, Field2D{1.0, mesh}, + Field2D{1.0, mesh}, Field2D{1.0, mesh}, Field2D{0.0, mesh}, Field2D{0.0, mesh}, + Field2D{0.0, mesh}, Field2D{0.0, mesh}, Field2D{0.0, mesh}, false), + location); + mesh->getCoordinates(location)->setParallelTransform( + bout::utils::make_unique(*mesh)); + } + } + + static void TearDownTestCase() { + delete mesh; + mesh = nullptr; + } + + Field2D input; + +public: + static const int nx; + static const int ny; + static const int nz; +}; + +const int Field2DInterpToTest::nx = 5; +const int Field2DInterpToTest::ny = 5; +const int Field2DInterpToTest::nz = 7; + +TEST_F(Field2DInterpToTest, CellCentreToXlow) { + + Field2D output = Field2D(mesh); + + // CELL_CENTRE -> CELL_XLOW + input.setLocation(CELL_CENTRE); + output = interp_to(input, CELL_XLOW); + EXPECT_TRUE(output.getLocation() == CELL_XLOW); + EXPECT_NEAR(output(2, 2), 1.95, 1.e-15); +} + +TEST_F(Field2DInterpToTest, CellCentreToXlowNoBndry) { + + Field2D output = Field2D(mesh); + + // CELL_CENTRE -> CELL_XLOW + input.setLocation(CELL_CENTRE); + output = interp_to(input, CELL_XLOW, "RGN_NOBNDRY"); + EXPECT_TRUE(output.getLocation() == CELL_XLOW); + EXPECT_NEAR(output(2, 2), 1.95, 1.e-15); +} + +TEST_F(Field2DInterpToTest, CellXlowToCentre) { + + Field2D output = Field2D(mesh); + + // CELL_XLOW -> CELL_CENTRE + input.setLocation(CELL_XLOW); + output = interp_to(input, CELL_CENTRE); + EXPECT_TRUE(output.getLocation() == CELL_CENTRE); + EXPECT_NEAR(output(2, 2), 1.65, 1.e-15); +} + +TEST_F(Field2DInterpToTest, CellXlowToCentreNoBndry) { + + Field2D output = Field2D(mesh); + + // CELL_XLOW -> CELL_CENTRE + input.setLocation(CELL_XLOW); + output = interp_to(input, CELL_CENTRE, "RGN_NOBNDRY"); + EXPECT_TRUE(output.getLocation() == CELL_CENTRE); + EXPECT_NEAR(output(2, 2), 1.65, 1.e-15); +} + +TEST_F(Field2DInterpToTest, CellCentreToYlow) { + + Field2D output = Field2D(mesh); + + // CELL_CENTRE -> CELL_YLOW + input.setLocation(CELL_CENTRE); + output = interp_to(input, CELL_YLOW); + EXPECT_TRUE(output.getLocation() == CELL_YLOW); + EXPECT_NEAR(output(2, 2), 2.825, 1.e-15); +} + +TEST_F(Field2DInterpToTest, CellCentreToYlowNoBndry) { + + Field2D output = Field2D(mesh); + + // CELL_CENTRE -> CELL_YLOW + input.setLocation(CELL_CENTRE); + output = interp_to(input, CELL_YLOW, "RGN_NOBNDRY"); + EXPECT_TRUE(output.getLocation() == CELL_YLOW); + EXPECT_NEAR(output(2, 2), 2.825, 1.e-15); +} + +TEST_F(Field2DInterpToTest, CellYlowToCentre) { + + Field2D output = Field2D(mesh); + + // CELL_YLOW -> CELL_CENTRE + input.setLocation(CELL_YLOW); + output = interp_to(input, CELL_CENTRE); + EXPECT_TRUE(output.getLocation() == CELL_CENTRE); + EXPECT_NEAR(output(2, 2), 2.525, 1.e-15); +} + +TEST_F(Field2DInterpToTest, CellYlowToCentreNoBndry) { + + Field2D output = Field2D(mesh); + + // CELL_YLOW -> CELL_CENTRE + input.setLocation(CELL_YLOW); + output = interp_to(input, CELL_CENTRE, "RGN_NOBNDRY"); + EXPECT_TRUE(output.getLocation() == CELL_CENTRE); + EXPECT_NEAR(output(2, 2), 2.525, 1.e-15); +} From 7ba3e9c660226c1d5dd4b0c14ab6485c7146a51a Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 21 Oct 2019 10:50:39 +0100 Subject: [PATCH 1761/1783] Finite-volume parallel operators return result in same space as input Make finite-volume parallel derivative operators follow the same behaviour as the finite-difference operators: if the input is field-aligned, return field-aligned result, otherwise transform the result back to non-aligned. --- include/bout/fv_ops.hxx | 13 +++++++++---- src/mesh/fv_ops.cxx | 27 +++++++++++++++++---------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index d9af56a542..62d53a0e1f 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -188,12 +188,16 @@ namespace FV { CellEdges cellboundary; - Field3D f = toFieldAligned(f_in, "RGN_NOX"); - Field3D v = toFieldAligned(v_in, "RGN_NOX"); + ASSERT2(f_in.getDirectionY() == v_in.getDirectionY()); + const bool are_unaligned = ((f_in.getDirectionY() == YDirectionType::Standard) + and (v_in.getDirectionY() == YDirectionType::Standard)); + + Field3D f = are_unaligned ? toFieldAligned(f_in, "RGN_NOX") : f_in; + Field3D v = are_unaligned ? toFieldAligned(v_in, "RGN_NOX") : v_in; Coordinates *coord = f_in.getCoordinates(); - Field3D result{zeroFrom(f_in)}; + Field3D result{zeroFrom(f)}; // Only need one guard cell, so no need to communicate fluxes // Instead calculate in guard cells to preserve fluxes @@ -326,7 +330,7 @@ namespace FV { } } } - return fromFieldAligned(result, "RGN_NOBNDRY"); + return are_unaligned ? fromFieldAligned(result, "RGN_NOBNDRY") : result; } /*! @@ -474,6 +478,7 @@ namespace FV { Field3D vy = toFieldAligned(v.y, "RGN_NOX"); Field3D yresult = 0.0; + yresult.setDirectionY(YDirectionType::Aligned); for(int i=mesh->xstart;i<=mesh->xend;i++) for(int j=mesh->ystart;j<=mesh->yend;j++) for(int k=0;kLocalNz;k++) { diff --git a/src/mesh/fv_ops.cxx b/src/mesh/fv_ops.cxx index 32f84ab55a..ffab49ab43 100644 --- a/src/mesh/fv_ops.cxx +++ b/src/mesh/fv_ops.cxx @@ -75,6 +75,7 @@ namespace FV { fup = fdown = fc = toFieldAligned(f); aup = adown = ac = toFieldAligned(a); + yzresult.setDirectionY(YDirectionType::Aligned); } // Y flux @@ -170,13 +171,14 @@ namespace FV { ASSERT2(Kin.getLocation() == fin.getLocation()); Mesh *mesh = Kin.getMesh(); - Field3D result{zeroFrom(fin)}; bool use_parallel_slices = (Kin.hasParallelSlices() && fin.hasParallelSlices()); const auto& K = use_parallel_slices ? Kin : toFieldAligned(Kin, "RGN_NOX"); const auto& f = use_parallel_slices ? fin : toFieldAligned(fin, "RGN_NOX"); + Field3D result{zeroFrom(f)}; + // K and f fields in yup and ydown directions const auto& Kup = use_parallel_slices ? Kin.yup() : K; const auto& Kdown = use_parallel_slices ? Kin.ydown() : K; @@ -232,13 +234,17 @@ namespace FV { Mesh* mesh = d_in.getMesh(); - Field3D result{zeroFrom(f_in)}; - Coordinates *coord = f_in.getCoordinates(); + ASSERT2(d_in.getDirectionY() == f_in.getDirectionY()); + const bool are_unaligned = ((d_in.getDirectionY() == YDirectionType::Standard) + and (f_in.getDirectionY() == YDirectionType::Standard)); + // Convert to field aligned coordinates - Field3D d = toFieldAligned(d_in, "RGN_NOX"); - Field3D f = toFieldAligned(f_in, "RGN_NOX"); + Field3D d = are_unaligned ? toFieldAligned(d_in, "RGN_NOX") : d_in; + Field3D f = are_unaligned ? toFieldAligned(f_in, "RGN_NOX") : f_in; + + Field3D result{zeroFrom(f)}; for(int i=mesh->xstart;i<=mesh->xend;i++) for(int j=mesh->ystart;j<=mesh->yend;j++) { @@ -277,16 +283,17 @@ namespace FV { } // Convert result back to non-aligned coordinates - return fromFieldAligned(result, "RGN_NOBNDRY"); + return are_unaligned ? fromFieldAligned(result, "RGN_NOBNDRY") : result; } const Field3D D4DY4_Index(const Field3D &f_in, bool bndry_flux) { - Field3D result{zeroFrom(f_in)}; - Mesh* mesh = f_in.getMesh(); // Convert to field aligned coordinates - Field3D f = toFieldAligned(f_in, "RGN_NOX"); + const bool is_unaligned = (f_in.getDirectionY() == YDirectionType::Standard); + Field3D f = is_unaligned ? toFieldAligned(f_in, "RGN_NOX") : f_in; + + Field3D result{zeroFrom(f)}; Coordinates *coord = f_in.getCoordinates(); @@ -387,7 +394,7 @@ namespace FV { } // Convert result back to non-aligned coordinates - return fromFieldAligned(result, "RGN_NOBNDRY"); + return is_unaligned ? fromFieldAligned(result, "RGN_NOBNDRY") : result; } void communicateFluxes(Field3D &f) { From 19254ffec0f276da4b9b2bed8bc679f6136c4cf0 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 21 Oct 2019 11:11:17 +0100 Subject: [PATCH 1762/1783] Transform wave_speed to field-aligned if necessary in FV::Div_par Previously the 'wave_speed' input was (incorrectly) not transformed, even if 'f' and 'v' were. --- include/bout/fv_ops.hxx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/include/bout/fv_ops.hxx b/include/bout/fv_ops.hxx index 62d53a0e1f..b0fcc92cd7 100644 --- a/include/bout/fv_ops.hxx +++ b/include/bout/fv_ops.hxx @@ -172,28 +172,34 @@ namespace FV { /// @param[in] v_in The advection velocity. /// This will be interpolated to cell boundaries /// using linear interpolation - /// @param[in] wave_speed Maximum wave speed in the system + /// @param[in] wave_speed_in Local maximum speed of all waves in the system at each + // point in space /// @param[in] fixflux Fix the flux at the boundary to be the value at the /// midpoint (for boundary conditions) /// /// NB: Uses to/from FieldAligned coordinates template const Field3D Div_par(const Field3D &f_in, const Field3D &v_in, - const Field3D &wave_speed, bool fixflux=true) { + const Field3D &wave_speed_in, bool fixflux=true) { ASSERT1(areFieldsCompatible(f_in, v_in)); - ASSERT1(areFieldsCompatible(f_in, wave_speed)); + ASSERT1(areFieldsCompatible(f_in, wave_speed_in)); Mesh* mesh = f_in.getMesh(); CellEdges cellboundary; ASSERT2(f_in.getDirectionY() == v_in.getDirectionY()); - const bool are_unaligned = ((f_in.getDirectionY() == YDirectionType::Standard) - and (v_in.getDirectionY() == YDirectionType::Standard)); + ASSERT2(f_in.getDirectionY() == wave_speed_in.getDirectionY()); + const bool are_unaligned + = ((f_in.getDirectionY() == YDirectionType::Standard) + and (v_in.getDirectionY() == YDirectionType::Standard) + and (wave_speed_in.getDirectionY() == YDirectionType::Standard)); Field3D f = are_unaligned ? toFieldAligned(f_in, "RGN_NOX") : f_in; Field3D v = are_unaligned ? toFieldAligned(v_in, "RGN_NOX") : v_in; + Field3D wave_speed = are_unaligned ? toFieldAligned(wave_speed_in, "RGN_NOX") + : wave_speed_in; Coordinates *coord = f_in.getCoordinates(); From fc8861ec8289df468596727ab36ac9481300b5b3 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 21 Oct 2019 11:51:10 +0100 Subject: [PATCH 1763/1783] Simplify naming of vector components when writing to Datafile --- src/fileio/datafile.cxx | 243 ++++++++++++++-------------------------- 1 file changed, 84 insertions(+), 159 deletions(-) diff --git a/src/fileio/datafile.cxx b/src/fileio/datafile.cxx index 4d59a27e03..2c3ed5233c 100644 --- a/src/fileio/datafile.cxx +++ b/src/fileio/datafile.cxx @@ -261,51 +261,29 @@ bool Datafile::openw(const char *format, ...) { // 2D vectors for(const auto& var : v2d_arr) { - if(var.covar) { - if (!file->addVarField2D(var.name + "_x", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField2D(var.name + "_y", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField2D(var.name + "_z", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - } else { - if (!file->addVarField2D(var.name + "x", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField2D(var.name + "y", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField2D(var.name + "z", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } + auto name = var.covar ? var.name + "_" : var.name; + if (!file->addVarField2D(name + "x", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", name.c_str()); + } + if (!file->addVarField2D(name + "y", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", name.c_str()); + } + if (!file->addVarField2D(name + "z", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", name.c_str()); } } // 3D vectors for(const auto& var : v3d_arr) { - if(var.covar) { - if (!file->addVarField3D(var.name + "_x", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField3D(var.name + "_y", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField3D(var.name + "_z", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - } else { - if (!file->addVarField3D(var.name + "x", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField3D(var.name + "y", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField3D(var.name + "z", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } + auto name = var.covar ? var.name + "_" : var.name; + if (!file->addVarField3D(name + "x", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", name.c_str()); + } + if (!file->addVarField3D(name + "y", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", name.c_str()); + } + if (!file->addVarField3D(name + "z", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", name.c_str()); } } if (openclose) { @@ -399,51 +377,29 @@ bool Datafile::opena(const char *format, ...) { // 2D vectors for(const auto& var : v2d_arr) { - if (var.covar) { - if (!file->addVarField2D(var.name + "_x", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField2D(var.name + "_y", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField2D(var.name + "_z", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - } else { - if (!file->addVarField2D(var.name + "x", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField2D(var.name + "y", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField2D(var.name + "z", var.save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", var.name.c_str()); - } + auto name = var.covar ? var.name + "_" : var.name; + if (!file->addVarField2D(name + "x", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", name.c_str()); + } + if (!file->addVarField2D(name + "y", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", name.c_str()); + } + if (!file->addVarField2D(name + "z", var.save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", name.c_str()); } } // 3D vectors for(const auto& var : v3d_arr) { - if (var.covar) { - if (!file->addVarField3D(var.name + "_x", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField3D(var.name + "_y", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField3D(var.name + "_z", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - } else { - if (!file->addVarField3D(var.name + "x", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField3D(var.name + "y", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } - if (!file->addVarField3D(var.name + "z", var.save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", var.name.c_str()); - } + auto name = var.covar ? var.name + "_" : var.name; + if (!file->addVarField3D(name + "x", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", name.c_str()); + } + if (!file->addVarField3D(name + "y", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", name.c_str()); + } + if (!file->addVarField3D(name + "z", var.save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", name.c_str()); } } if (openclose) { @@ -818,27 +774,18 @@ void Datafile::add(Vector2D &f, const char *name, bool save_repeat) { file->setLowPrecision(); // Add variables to file - if (d.covar) { - if (!file->addVarField2D(d.name + "_x", save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", name); - } - if (!file->addVarField2D(d.name + "_y", save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", name); - } - if (!file->addVarField2D(d.name + "_z", save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", name); - } - } else { - if (!file->addVarField2D(d.name + "x", save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", name); - } - if (!file->addVarField2D(d.name + "y", save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", name); - } - if (!file->addVarField2D(d.name + "z", save_repeat)) { - throw BoutException("Failed to add Vector2D variable %s to Datafile", name); - } - + auto dname = d.covar ? d.name + "_" : d.name; + if (!file->addVarField2D(dname + "x", save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", + dname.c_str()); + } + if (!file->addVarField2D(dname + "y", save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", + dname.c_str()); + } + if (!file->addVarField2D(dname + "z", save_repeat)) { + throw BoutException("Failed to add Vector2D variable %s to Datafile", + dname.c_str()); } if(openclose) { @@ -887,26 +834,18 @@ void Datafile::add(Vector3D &f, const char *name, bool save_repeat) { file->setLowPrecision(); // Add variables to file - if (d.covar) { - if (!file->addVarField3D(d.name + "_x", save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", name); - } - if (!file->addVarField3D(d.name + "_y", save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", name); - } - if (!file->addVarField3D(d.name + "_z", save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", name); - } - } else { - if (!file->addVarField3D(d.name + "x", save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", name); - } - if (!file->addVarField3D(d.name + "y", save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", name); - } - if (!file->addVarField3D(d.name + "z", save_repeat)) { - throw BoutException("Failed to add Vector3D variable %s to Datafile", name); - } + auto dname = d.covar ? d.name + "_" : d.name; + if (!file->addVarField3D(dname + "x", save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", + dname.c_str()); + } + if (!file->addVarField3D(dname + "y", save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", + dname.c_str()); + } + if (!file->addVarField3D(dname + "z", save_repeat)) { + throw BoutException("Failed to add Vector3D variable %s to Datafile", + dname.c_str()); } if(openclose) { @@ -1106,29 +1045,19 @@ bool Datafile::write() { // 2D vectors for(const auto& var : v2d_arr) { Vector2D v = *(var.ptr); - if (var.covar) { - file->writeFieldAttributes(var.name+"_x", v.x); - file->writeFieldAttributes(var.name+"_y", v.y); - file->writeFieldAttributes(var.name+"_z", v.z); - } else { - file->writeFieldAttributes(var.name+"x", v.x); - file->writeFieldAttributes(var.name+"y", v.y); - file->writeFieldAttributes(var.name+"z", v.z); - } + auto name = var.covar ? var.name + "_" : var.name; + file->writeFieldAttributes(name+"x", v.x); + file->writeFieldAttributes(name+"y", v.y); + file->writeFieldAttributes(name+"z", v.z); } // 3D vectors for(const auto& var : v3d_arr) { Vector3D v = *(var.ptr); - if (var.covar) { - file->writeFieldAttributes(var.name+"_x", v.x); - file->writeFieldAttributes(var.name+"_y", v.y); - file->writeFieldAttributes(var.name+"_z", v.z); - } else { - file->writeFieldAttributes(var.name+"x", v.x); - file->writeFieldAttributes(var.name+"y", v.y); - file->writeFieldAttributes(var.name+"z", v.z); - } + auto name = var.covar ? var.name + "_" : var.name; + file->writeFieldAttributes(name+"x", v.x); + file->writeFieldAttributes(name+"y", v.y); + file->writeFieldAttributes(name+"z", v.z); } } @@ -1165,44 +1094,40 @@ bool Datafile::write() { // 2D vectors for(const auto& var : v2d_arr) { + Vector2D v = *(var.ptr); + auto name = var.name; + if(var.covar) { // Writing covariant vector - Vector2D v = *(var.ptr); v.toCovariant(); - - write_f2d(var.name+"_x", &(v.x), var.save_repeat); - write_f2d(var.name+"_y", &(v.y), var.save_repeat); - write_f2d(var.name+"_z", &(v.z), var.save_repeat); + name += "_"; } else { // Writing contravariant vector - Vector2D v = *(var.ptr); v.toContravariant(); - - write_f2d(var.name+"x", &(v.x), var.save_repeat); - write_f2d(var.name+"y", &(v.y), var.save_repeat); - write_f2d(var.name+"z", &(v.z), var.save_repeat); } + + write_f2d(name+"x", &(v.x), var.save_repeat); + write_f2d(name+"y", &(v.y), var.save_repeat); + write_f2d(name+"z", &(v.z), var.save_repeat); } // 3D vectors for(const auto& var : v3d_arr) { + Vector3D v = *(var.ptr); + auto name = var.name; + if(var.covar) { // Writing covariant vector - Vector3D v = *(var.ptr); v.toCovariant(); - - write_f3d(var.name+"_x", &(v.x), var.save_repeat); - write_f3d(var.name+"_y", &(v.y), var.save_repeat); - write_f3d(var.name+"_z", &(v.z), var.save_repeat); + name += "_"; } else { // Writing contravariant vector - Vector3D v = *(var.ptr); v.toContravariant(); - - write_f3d(var.name+"x", &(v.x), var.save_repeat); - write_f3d(var.name+"y", &(v.y), var.save_repeat); - write_f3d(var.name+"z", &(v.z), var.save_repeat); } + + write_f3d(name+"x", &(v.x), var.save_repeat); + write_f3d(name+"y", &(v.y), var.save_repeat); + write_f3d(name+"z", &(v.z), var.save_repeat); } if(openclose && (flushFrequencyCounter+1 % flushFrequency == 0)){ From aa19b5c3b14b54d87a999613ba3b5b5965111f8d Mon Sep 17 00:00:00 2001 From: John Omotani Date: Mon, 21 Oct 2019 15:42:33 +0100 Subject: [PATCH 1764/1783] Save Bxy, G1, G2 and G3 --- src/mesh/coordinates.cxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx index 971f0d29db..7ad6485814 100644 --- a/src/mesh/coordinates.cxx +++ b/src/mesh/coordinates.cxx @@ -629,6 +629,11 @@ void Coordinates::outputVars(Datafile& file) { file.addOnce(g_23, "g_23" + loc_string); file.addOnce(J, "J" + loc_string); + file.addOnce(Bxy, "Bxy" + loc_string); + + file.addOnce(G1, "G1" + loc_string); + file.addOnce(G2, "G2" + loc_string); + file.addOnce(G3, "G3" + loc_string); getParallelTransform().outputVars(file); } From d981daaa682e3c1816ee435a9209ad987d957de2 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 22 Oct 2019 11:35:42 +0100 Subject: [PATCH 1765/1783] Revert ShiftedMetric::calcParallelSlices to use old form of shiftZ Recent version of shiftZ using std::vector doesn't seem to perform as well as the version that takes pointers :( --- src/mesh/parallel/shiftedmetric.cxx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 1450478d8e..b8325e2ccb 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -218,14 +218,18 @@ void ShiftedMetric::calcParallelSlices(Field3D& f) { return; } - auto results = shiftZ(f, parallel_slice_phases); - - ASSERT3(results.size() == parallel_slice_phases.size()); - f.splitParallelSlices(); - for (std::size_t i = 0; i < results.size(); ++i) { - f.ynext(parallel_slice_phases[i].y_offset) = std::move(results[i]); + for (const auto& phase : parallel_slice_phases) { + auto& f_slice = f.ynext(phase.y_offset); + f_slice.allocate(); + BOUT_FOR(i, mesh.getRegion2D("RGN_NOY")) { + const int ix = i.x(); + const int iy = i.y(); + const int iy_offset = iy + phase.y_offset; + shiftZ(&(f(ix, iy_offset, 0)), &(phase.phase_shift(ix, iy, 0)), + &(f_slice(ix, iy_offset, 0))); + } } } From f0e67c1011f607e3faff104215d23002b1dd68c1 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 22 Oct 2019 11:41:11 +0100 Subject: [PATCH 1766/1783] Skip check for velocity parallel slices if not needed in VDDY Some notes about the choice to be made here: - If we're not staggered, then we don't need the parallel slices for `vel`, and we can use the `YOrthogonal` version if `f` has parallel slices. Otherwise, we need to use the aligned version. - If we are staggered, we can only use the `YOrthogonal` version if both `vel` and `f` have parallel slices. - If we are staggered and only `f` has parallel slices, then we have another choice: calculate the parallel slices for `vel` and use the `YOrthogonal` version; or throw away the slices for `f` and use the aligned version. Which is cheaper depends on how many parallel slices we're using. Our current estimate as of October 2019 is if MYG > 1, it's cheaper to use the aligned version. --- include/bout/index_derivs_interface.hxx | 31 ++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 778ddb1c15..48325aac05 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -308,9 +308,34 @@ template T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); - const bool fHasParallelSlices = (f.hasParallelSlices()); - const bool velHasParallelSlices = (vel.hasParallelSlices()); - if (fHasParallelSlices && velHasParallelSlices) { + + auto* localmesh = f.getMesh(); + const CELL_LOC allowedStaggerLoc = localmesh->getAllowedStaggerLoc(DIRECTION::Y); + const CELL_LOC inloc = f.getLocation(); + const CELL_LOC vloc = vel.getLocation(); + if (outloc == CELL_DEFAULT) { + outloc = inloc; + } + const STAGGER stagger = localmesh->getStagger(vloc, inloc, outloc, allowedStaggerLoc); + + // Some notes about the choice to be made here: + // - If we're not staggered, then we don't need the parallel slices + // for `vel`, and we can use the `YOrthogonal` version if `f` has + // parallel slices. Otherwise, we need to use the aligned version. + // - If we are staggered, we can only use the `YOrthogonal` version if + // both `vel` and `f` have parallel slices. + // - If we are staggered and only `f` has parallel slices, then we + // have another choice: calculate the parallel slices for `vel` + // and use the `YOrthogonal` version; or throw away the slices for + // `f` and use the aligned version. Which is cheaper depends on + // how many parallel slices we're using. Our current estimate as + // of October 2019 is if MYG > 1, it's cheaper to use the aligned + // version. + + const bool fHasParallelSlices = f.hasParallelSlices(); + const bool useVelParallelSlices = (stagger == STAGGER::None) or vel.hasParallelSlices(); + + if (fHasParallelSlices && useVelParallelSlices) { ASSERT1(vel.getDirectionY() == YDirectionType::Standard); ASSERT1(f.getDirectionY() == YDirectionType::Standard); return flowDerivative(vel, f, outloc, From fd20b79652d14ee30a712d87c71236407c8b184c Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Tue, 22 Oct 2019 13:45:25 +0100 Subject: [PATCH 1767/1783] Add comment explaining copy+pasted chunk --- include/bout/index_derivs_interface.hxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/bout/index_derivs_interface.hxx b/include/bout/index_derivs_interface.hxx index 48325aac05..099c7c7d30 100644 --- a/include/bout/index_derivs_interface.hxx +++ b/include/bout/index_derivs_interface.hxx @@ -309,6 +309,10 @@ T VDDY(const T& vel, const T& f, CELL_LOC outloc = CELL_DEFAULT, const std::string& method = "DEFAULT", const std::string& region = "RGN_NOBNDRY") { AUTO_TRACE(); + // Note the following chunk is copy+pasted from flowDerivative + // above. Not pulled out as a separate function due the number of + // local variables from it that flowDerivative ends up needing. + // The two should probably remain in sync! auto* localmesh = f.getMesh(); const CELL_LOC allowedStaggerLoc = localmesh->getAllowedStaggerLoc(DIRECTION::Y); const CELL_LOC inloc = f.getLocation(); From 98c523b4ecbcba50e525c731c51da78d2491f256 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 22 Oct 2019 16:54:28 +0100 Subject: [PATCH 1768/1783] Simplify setting zero_DC in LaplaceCyclic --- src/invert/laplace/impls/cyclic/cyclic_laplace.cxx | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx index 8bba1416d5..c2fc9802ca 100644 --- a/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx +++ b/src/invert/laplace/impls/cyclic/cyclic_laplace.cxx @@ -232,11 +232,7 @@ FieldPerp LaplaceCyclic::solve(const FieldPerp& rhs, const FieldPerp& x0) { auto k1d = Array((localmesh->LocalNz) / 2 + 1); // ZFFT routine expects input of this length - bool zero_DC = false; - if(global_flags & INVERT_ZERO_DC) { - // No DC component - zero_DC = true; - } + const bool zero_DC = global_flags & INVERT_ZERO_DC; BOUT_OMP(for nowait) for (int ix = xs; ix <= xe; ix++) { @@ -450,11 +446,7 @@ Field3D LaplaceCyclic::solve(const Field3D& rhs, const Field3D& x0) { auto k1d = Array((localmesh->LocalNz) / 2 + 1); // ZFFT routine expects input of this length - bool zero_DC = false; - if(global_flags & INVERT_ZERO_DC) { - // No DC component - zero_DC = true; - } + const bool zero_DC = global_flags & INVERT_ZERO_DC; BOUT_OMP(for nowait) for (int ind = 0; ind < nxny; ++ind) { // Loop over X and Y From a07257d6c3784cc2d59c323804d2629b86552df7 Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 22 Oct 2019 17:22:07 +0100 Subject: [PATCH 1769/1783] Methods to get global indices excluding any boundary cells --- include/bout/mesh.hxx | 12 ++++++++++++ src/mesh/impls/bout/boutmesh.cxx | 15 +++++++++++++-- src/mesh/impls/bout/boutmesh.hxx | 4 +++- tests/unit/test_extras.hxx | 3 +++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index f7c2b097af..e68f382f3f 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -493,14 +493,26 @@ class Mesh { /// Global index includes boundary cells, local index includes boundary or guard cells. virtual int getGlobalXIndex(int xlocal) const = 0; + /// Returns a global X index given a local index. + /// Global index excludes boundary cells, local index includes boundary or guard cells. + virtual int getGlobalXIndexNoBoundaries(int xlocal) const = 0; + /// Returns a global Y index given a local index. /// Global index includes boundary cells, local index includes boundary or guard cells. virtual int getGlobalYIndex(int ylocal) const = 0; + /// Returns a global Y index given a local index. + /// Global index excludes boundary cells, local index includes boundary or guard cells. + virtual int getGlobalYIndexNoBoundaries(int ylocal) const = 0; + /// Returns a global Z index given a local index. /// Global index includes boundary cells, local index includes boundary or guard cells. virtual int getGlobalZIndex(int zlocal) const = 0; + /// Returns a global Z index given a local index. + /// Global index excludes boundary cells, local index includes boundary or guard cells. + virtual int getGlobalZIndexNoBoundaries(int zlocal) const = 0; + /// Size of the mesh on this processor including guard/boundary cells int LocalNx, LocalNy, LocalNz; diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 3ee4b1838e..c7566081e7 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -1504,6 +1504,12 @@ int BoutMesh::XGLOBAL(BoutReal xloc, BoutReal &xglo) const { /// Global index includes boundary cells, local index includes boundary or guard cells. int BoutMesh::getGlobalXIndex(int xlocal) const { return xlocal + PE_XIND * MXSUB; } +/// Returns a global X index given a local index. +/// Global index excludes boundary cells, local index includes boundary or guard cells. +int BoutMesh::getGlobalXIndexNoBoundaries(int xlocal) const { + return xlocal + PE_XIND * MXSUB - MXG; +} + /// Returns a local X index given a global index int BoutMesh::XLOCAL(int xglo) const { return xglo - PE_XIND * MXSUB; } @@ -1527,8 +1533,8 @@ int BoutMesh::getGlobalYIndex(int ylocal) const { return yglobal; } -/// Private method that keeps the behaviour of the old YGLOBAL method, excluding all -/// boundary cells, for use inside BoutMesh. +/// Returns a global Y index given a local index. +/// Global index excludes boundary cells, local index includes boundary or guard cells. int BoutMesh::getGlobalYIndexNoBoundaries(int ylocal) const { return ylocal + PE_YIND * MYSUB - MYG; } @@ -1545,6 +1551,11 @@ int BoutMesh::YLOCAL(int yglo, int yproc) const { return yglo - yproc * MYSUB + /// Global index includes boundary cells, local index includes boundary or guard cells. int BoutMesh::getGlobalZIndex(int zlocal) const { return zlocal; } +/// Returns a global Z index given a local index. +/// Global index excludes boundary cells, local index includes boundary or guard cells. +/// Note: at the moment z-direction is always periodic, so has zero boundary cells +int BoutMesh::getGlobalZIndexNoBoundaries(int zlocal) const { return zlocal; } + /// Return the Y processor number given a global Y index int BoutMesh::YPROC(int yind) { if ((yind < 0) || (yind > ny)) diff --git a/src/mesh/impls/bout/boutmesh.hxx b/src/mesh/impls/bout/boutmesh.hxx index 74a14063a8..d561707c95 100644 --- a/src/mesh/impls/bout/boutmesh.hxx +++ b/src/mesh/impls/bout/boutmesh.hxx @@ -179,8 +179,11 @@ class BoutMesh : public Mesh { int YGLOBAL(int yloc) const override; int getGlobalXIndex(int xlocal) const override; + int getGlobalXIndexNoBoundaries(int xlocal) const override; int getGlobalYIndex(int ylocal) const override; + int getGlobalYIndexNoBoundaries(int ylocal) const override; int getGlobalZIndex(int zlocal) const override; + int getGlobalZIndexNoBoundaries(int zlocal) const override; int XLOCAL(int xglo) const override; int YLOCAL(int yglo) const override; @@ -202,7 +205,6 @@ private: int MYPE_IN_CORE; // 1 if processor in core - int getGlobalYIndexNoBoundaries(int ylocal) const; int XGLOBAL(BoutReal xloc, BoutReal& xglo) const; int YGLOBAL(BoutReal yloc, BoutReal& yglo) const; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index 7ebd5997d9..b2bea5ad8a 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -288,8 +288,11 @@ public: int XGLOBAL(int UNUSED(xloc)) const override { return 0; } int YGLOBAL(int UNUSED(yloc)) const override { return 0; } int getGlobalXIndex(int) const override { return 0; } + int getGlobalXIndexNoBoundaries(int) const override { return 0; } int getGlobalYIndex(int) const override { return 0; } + int getGlobalYIndexNoBoundaries(int) const override { return 0; } int getGlobalZIndex(int) const override { return 0; } + int getGlobalZIndexNoBoundaries(int) const override { return 0; } int XLOCAL(int UNUSED(xglo)) const override { return 0; } int YLOCAL(int UNUSED(yglo)) const override { return 0; } From 6a25266d2e7918ba0c949772e9156a9270c436ac Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 22 Oct 2019 17:24:51 +0100 Subject: [PATCH 1770/1783] Replace separate implementation of deprecated XGLOBAL and YGLOBAL Maintaining the old behaviour, for XGLOBAL(xloc) return getXGlobalXIndex(xloc) and for YGLOBAL(yloc) return getGlobalYIndexNoBoundaries(yloc). --- include/bout/mesh.hxx | 6 +++--- src/mesh/impls/bout/boutmesh.cxx | 6 ------ src/mesh/impls/bout/boutmesh.hxx | 3 --- tests/unit/test_extras.hxx | 2 -- 4 files changed, 3 insertions(+), 14 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index e68f382f3f..3b5d7ba205 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -476,11 +476,11 @@ class Mesh { /// Returns the global X index given a local index /// If the local index includes the boundary cells, then so does the global. [[gnu::deprecated("Use getGlobalXIndex instead")]] - virtual int XGLOBAL(int xloc) const = 0; + int XGLOBAL(int xloc) const { return getGlobalXIndex(xloc); } /// Returns the global Y index given a local index /// The local index must include the boundary, the global index does not. - [[gnu::deprecated("Use getGlobalYIndex instead")]] - virtual int YGLOBAL(int yloc) const = 0; + [[gnu::deprecated("Use getGlobalYIndex or getGlobalYIndexNoBoundaries instead")]] + virtual int YGLOBAL(int yloc) const { return getGlobalYIndexNoBoundaries(yloc); } /// Returns the local X index given a global index /// If the global index includes the boundary cells, then so does the local. diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index c7566081e7..d7334d974e 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -1491,9 +1491,6 @@ int BoutMesh::PROC_NUM(int xind, int yind) { return yind * NXPE + xind; } -/// Returns the global X index given a local index -int BoutMesh::XGLOBAL(int xloc) const { return xloc + PE_XIND * MXSUB; } - /// Returns the global X index given a local index int BoutMesh::XGLOBAL(BoutReal xloc, BoutReal &xglo) const { xglo = xloc + PE_XIND * MXSUB; @@ -1513,9 +1510,6 @@ int BoutMesh::getGlobalXIndexNoBoundaries(int xlocal) const { /// Returns a local X index given a global index int BoutMesh::XLOCAL(int xglo) const { return xglo - PE_XIND * MXSUB; } -/// Returns the global Y index given a local index -int BoutMesh::YGLOBAL(int yloc) const { return yloc + PE_YIND * MYSUB - MYG; } - /// Returns the global Y index given a local index int BoutMesh::YGLOBAL(BoutReal yloc, BoutReal &yglo) const { yglo = yloc + PE_YIND * MYSUB - MYG; diff --git a/src/mesh/impls/bout/boutmesh.hxx b/src/mesh/impls/bout/boutmesh.hxx index d561707c95..0546f9b3fe 100644 --- a/src/mesh/impls/bout/boutmesh.hxx +++ b/src/mesh/impls/bout/boutmesh.hxx @@ -175,9 +175,6 @@ class BoutMesh : public Mesh { void outputVars(Datafile& file) override; - int XGLOBAL(int xloc) const override; - int YGLOBAL(int yloc) const override; - int getGlobalXIndex(int xlocal) const override; int getGlobalXIndexNoBoundaries(int xlocal) const override; int getGlobalYIndex(int ylocal) const override; diff --git a/tests/unit/test_extras.hxx b/tests/unit/test_extras.hxx index b2bea5ad8a..322cbd1f99 100644 --- a/tests/unit/test_extras.hxx +++ b/tests/unit/test_extras.hxx @@ -285,8 +285,6 @@ public: BoutReal GlobalY(int jy) const override { return jy; } BoutReal GlobalX(BoutReal jx) const override { return jx; } BoutReal GlobalY(BoutReal jy) const override { return jy; } - int XGLOBAL(int UNUSED(xloc)) const override { return 0; } - int YGLOBAL(int UNUSED(yloc)) const override { return 0; } int getGlobalXIndex(int) const override { return 0; } int getGlobalXIndexNoBoundaries(int) const override { return 0; } int getGlobalYIndex(int) const override { return 0; } From 21f1f3d13b8d44f6b6f4701e3554438399a6de1b Mon Sep 17 00:00:00 2001 From: John Omotani Date: Tue, 22 Oct 2019 17:41:32 +0100 Subject: [PATCH 1771/1783] Rename Mesh::isSourceFile() to Mesh::isDataSourceGridFile() --- include/bout/mesh.hxx | 2 +- src/mesh/mesh.cxx | 2 +- src/mesh/parallel/fci.cxx | 2 +- src/mesh/parallel/identity.cxx | 2 +- src/mesh/parallel/shiftedmetric.cxx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/bout/mesh.hxx b/include/bout/mesh.hxx index 51dc57649e..cbeb25e10c 100644 --- a/include/bout/mesh.hxx +++ b/include/bout/mesh.hxx @@ -217,7 +217,7 @@ class Mesh { int get(Vector3D &var, const std::string &name, BoutReal def=0.0); /// Test if input source was a grid file - bool isSourceFile() const; + bool isDataSourceGridFile() const; /// Wrapper for GridDataSource::hasVar bool sourceHasVar(const std::string &name); diff --git a/src/mesh/mesh.cxx b/src/mesh/mesh.cxx index 2887ab8935..2f23e555a0 100644 --- a/src/mesh/mesh.cxx +++ b/src/mesh/mesh.cxx @@ -209,7 +209,7 @@ int Mesh::get(Vector3D &var, const std::string &name, BoutReal def) { return 0; } -bool Mesh::isSourceFile() const { +bool Mesh::isDataSourceGridFile() const { return source != nullptr and source->is_file; } diff --git a/src/mesh/parallel/fci.cxx b/src/mesh/parallel/fci.cxx index d4364ef063..6cf6c45532 100644 --- a/src/mesh/parallel/fci.cxx +++ b/src/mesh/parallel/fci.cxx @@ -326,7 +326,7 @@ Field3D FCIMap::integrate(Field3D &f) const { void FCITransform::checkInputGrid() { std::string parallel_transform; - if (mesh.isSourceFile() && !mesh.get(parallel_transform, "parallel_transform")) { + if (mesh.isDataSourceGridFile() && !mesh.get(parallel_transform, "parallel_transform")) { if (parallel_transform != "fci") { throw BoutException("Incorrect parallel transform type '"+parallel_transform+"' used " "to generate metric components for FCITransform. Should be 'fci'."); diff --git a/src/mesh/parallel/identity.cxx b/src/mesh/parallel/identity.cxx index 0d5e796163..96a031f502 100644 --- a/src/mesh/parallel/identity.cxx +++ b/src/mesh/parallel/identity.cxx @@ -26,7 +26,7 @@ void ParallelTransformIdentity::calcParallelSlices(Field3D& f) { void ParallelTransformIdentity::checkInputGrid() { std::string parallel_transform; - if (mesh.isSourceFile() and !mesh.get(parallel_transform, "parallel_transform")) { + if (mesh.isDataSourceGridFile() and !mesh.get(parallel_transform, "parallel_transform")) { if (parallel_transform != "identity") { throw BoutException("Incorrect parallel transform type '"+parallel_transform+"' used " "to generate metric components for ParallelTransformIdentity. Should be " diff --git a/src/mesh/parallel/shiftedmetric.cxx b/src/mesh/parallel/shiftedmetric.cxx index 808066b85e..79feeff39a 100644 --- a/src/mesh/parallel/shiftedmetric.cxx +++ b/src/mesh/parallel/shiftedmetric.cxx @@ -28,7 +28,7 @@ ShiftedMetric::ShiftedMetric(Mesh& m, CELL_LOC location_in, Field2D zShift_, void ShiftedMetric::checkInputGrid() { std::string parallel_transform; - if (mesh.isSourceFile() and !mesh.get(parallel_transform, "parallel_transform")) { + if (mesh.isDataSourceGridFile() and !mesh.get(parallel_transform, "parallel_transform")) { if (parallel_transform != "shiftedmetric") { throw BoutException("Incorrect parallel transform type '" + parallel_transform + "' used to generate metric components for ShiftedMetric. " From e21a7e3278e381e297f640a6a2829d1d0cabcf9c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 23 Oct 2019 13:57:27 +0100 Subject: [PATCH 1772/1783] Ensure the scorepwrapper includes msg_stack, which provides `__thefunc__` --- include/bout/scorepwrapper.hxx | 1 + 1 file changed, 1 insertion(+) diff --git a/include/bout/scorepwrapper.hxx b/include/bout/scorepwrapper.hxx index 71248dc652..2fb1689632 100644 --- a/include/bout/scorepwrapper.hxx +++ b/include/bout/scorepwrapper.hxx @@ -2,6 +2,7 @@ #define __BOUT_SCOREP_H__ #include +#include "msg_stack.hxx" #ifdef BOUT_HAS_SCOREP #include From dc967c98d71a3acc64a6bf36837cb3f50faa775b Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Wed, 23 Oct 2019 13:59:34 +0100 Subject: [PATCH 1773/1783] Move the test for PRETTY_FUNCTION out of SCOREP specific section. This ensures we get access to `__PRETTY_FUNCTION__` in `AUTO_TRACE` used as a part of the message stack etc. even if we haven't built with scorep enabled --- configure | 115 +++++++++++++++++++++++++-------------------------- configure.ac | 4 +- 2 files changed, 60 insertions(+), 59 deletions(-) diff --git a/configure b/configure index eb7ccefc5b..29d981e4c3 100755 --- a/configure +++ b/configure @@ -768,6 +768,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -880,6 +881,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1132,6 +1134,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1269,7 +1280,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1422,6 +1433,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -5164,6 +5176,44 @@ if test "x$enable_openmp" = "xyes"; then : fi +# Check if we have access to __PRETTY_FUNCTION__ + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking does C++ compiler support __PRETTY_FUNCTION__" >&5 +$as_echo_n "checking does C++ compiler support __PRETTY_FUNCTION__... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +const char* name = __PRETTY_FUNCTION__; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + CXXFLAGS="$CXXFLAGS -DHAS_PRETTY_FUNCTION" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + ############################################################# # Code coverage using gcov # @@ -12007,42 +12057,6 @@ else # Set a compile-time flag CXXFLAGS="$CXXFLAGS -DBOUT_HAS_SCOREP" MPICXX="$SCOREPPATH --user --nocompiler $MPICXX" - - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking does C++ compiler support __PRETTY_FUNCTION__" >&5 -$as_echo_n "checking does C++ compiler support __PRETTY_FUNCTION__... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -const char* name = __PRETTY_FUNCTION__; - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - CXXFLAGS="$CXXFLAGS -DHAS_PRETTY_FUNCTION" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - HAS_SCOREP="yes" { $as_echo "$as_me:${as_lineno-$LINENO}: Scorep support enabled" >&5 $as_echo "$as_me: Scorep support enabled" >&6;} @@ -13349,21 +13363,16 @@ else /* end confdefs.h. */ #include -#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +$gt_revision_test_code extern int _nl_msg_cat_cntr; extern int *_nl_domain_bindings; -#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_domain_bindings) -#else -#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 -#endif -$gt_revision_test_code int main () { bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings ; return 0; @@ -14116,25 +14125,20 @@ else /* end confdefs.h. */ #include -#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +$gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); -#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) -#else -#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 -#endif -$gt_revision_test_code int main () { bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") ; return 0; @@ -14153,25 +14157,20 @@ rm -f core conftest.err conftest.$ac_objext \ /* end confdefs.h. */ #include -#ifndef __GNU_GETTEXT_SUPPORTED_REVISION +$gt_revision_test_code extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); -#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) -#else -#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 -#endif -$gt_revision_test_code int main () { bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION +return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") ; return 0; diff --git a/configure.ac b/configure.ac index ffc914377b..a219ae1859 100644 --- a/configure.ac +++ b/configure.ac @@ -187,6 +187,9 @@ AS_IF([test "x$enable_openmp" = "xyes"], [ OPENMP_CXXFLAGS="$OPENMP_CXXFLAGS -DOPENMP_SCHEDULE=$OPENMP_SCHEDULE" ]) +# Check if we have access to __PRETTY_FUNCTION__ +BOUT_CHECK_PRETTYFUNCTION + ############################################################# # Code coverage using gcov # @@ -1089,7 +1092,6 @@ Please supply the path using --with-scorep=/path/to/scorep]) # Set a compile-time flag CXXFLAGS="$CXXFLAGS -DBOUT_HAS_SCOREP" MPICXX="$SCOREPPATH --user --nocompiler $MPICXX" - BOUT_CHECK_PRETTYFUNCTION HAS_SCOREP="yes" AC_MSG_NOTICE([Scorep support enabled]) ]) From b088f77f68e97de909a54a9531d6bf5407329c09 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Wed, 23 Oct 2019 15:15:38 +0100 Subject: [PATCH 1774/1783] Regenerate configure with consistent version of autoreconf --- configure | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/configure b/configure index 29d981e4c3..a3cf293907 100755 --- a/configure +++ b/configure @@ -768,7 +768,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -881,7 +880,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1134,15 +1132,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1280,7 +1269,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1433,7 +1422,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -13363,16 +13351,21 @@ else /* end confdefs.h. */ #include -$gt_revision_test_code +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION extern int _nl_msg_cat_cntr; extern int *_nl_domain_bindings; +#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_domain_bindings) +#else +#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 +#endif +$gt_revision_test_code int main () { bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_domain_bindings +return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION ; return 0; @@ -14125,20 +14118,25 @@ else /* end confdefs.h. */ #include -$gt_revision_test_code +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); +#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) +#else +#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 +#endif +$gt_revision_test_code int main () { bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") +return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION ; return 0; @@ -14157,20 +14155,25 @@ rm -f core conftest.err conftest.$ac_objext \ /* end confdefs.h. */ #include -$gt_revision_test_code +#ifndef __GNU_GETTEXT_SUPPORTED_REVISION extern int _nl_msg_cat_cntr; extern #ifdef __cplusplus "C" #endif const char *_nl_expand_alias (const char *); +#define __GNU_GETTEXT_SYMBOL_EXPRESSION (_nl_msg_cat_cntr + *_nl_expand_alias ("")) +#else +#define __GNU_GETTEXT_SYMBOL_EXPRESSION 0 +#endif +$gt_revision_test_code int main () { bindtextdomain ("", ""); -return * gettext ("")$gt_expression_test_code + _nl_msg_cat_cntr + *_nl_expand_alias ("") +return * gettext ("")$gt_expression_test_code + __GNU_GETTEXT_SYMBOL_EXPRESSION ; return 0; From ee455bf07450c8442833ea91611ad01f2457fe5c Mon Sep 17 00:00:00 2001 From: John Omotani Date: Wed, 23 Oct 2019 21:45:32 +0100 Subject: [PATCH 1775/1783] Deprecate CtoL and LtoC differential operators These were an initial version of staggered grids. Staggered grids are now supported by the standard differential operators, so the CtoL and LtoC versions can be deprecated. --- include/difops.hxx | 74 ++++++++++++--- src/mesh/difops.cxx | 213 -------------------------------------------- 2 files changed, 61 insertions(+), 226 deletions(-) diff --git a/include/difops.hxx b/include/difops.hxx index af8629acbb..86959f773f 100644 --- a/include/difops.hxx +++ b/include/difops.hxx @@ -221,22 +221,70 @@ inline const Field3D Grad2_par2(const Field3D& f, CELL_LOC outloc, DIFF_METHOD m * Parallel derivatives, converting between cell-centred and lower cell boundary * These are a simple way to do staggered differencing */ -const Field3D Grad_par_CtoL(const Field3D &var); -const Field2D Grad_par_CtoL(const Field2D &var); -const Field3D Vpar_Grad_par_LCtoC(const Field3D& v, const Field3D& f, - const std::string& region="RGN_NOBNDRY"); -[[gnu::deprecated("Please use Field3D Vpar_Grad_par_LCtoC(const Field3D& v, " \ - "const Field3D &f, const std::string& region = \"RGN_NOBNDRY\") instead")]] \ +[[gnu::deprecated( + "Grad_par_CtoL is deprecated. Staggering is now supported in Grad_par.")]] +inline const Field3D Grad_par_CtoL(const Field3D &var) { + ASSERT2(var.getLocation() == CELL_CENTRE); + return Grad_par(var, CELL_YLOW); +} +[[gnu::deprecated( + "Grad_par_CtoL is deprecated. Staggering is now supported in Grad_par.")]] +inline const Field2D Grad_par_CtoL(const Field2D &var) { + ASSERT2(var.getLocation() == CELL_CENTRE); + return Grad_par(var, CELL_YLOW); +} +[[gnu::deprecated( + "Vpar_Grad_par_LCtoC is deprecated. Staggering is now supported in Vpar_Grad_par.")]] +inline const Field3D Vpar_Grad_par_LCtoC(const Field3D& v, const Field3D& f, + const std::string& region="RGN_NOBNDRY") { + ASSERT2(v.getLocation() == CELL_YLOW); + ASSERT2(f.getLocation() == CELL_CENTRE); + return Vpar_Grad_par(v, f, CELL_CENTRE, region); +} +[[gnu::deprecated( + "Vpar_Grad_par_LCtoC is deprecated. Staggering is now supported in Vpar_Grad_par.")]] inline const Field3D Vpar_Grad_par_LCtoC(const Field3D& v, const Field3D& f, REGION region=RGN_NOBNDRY) { - return Vpar_Grad_par_LCtoC(v, f, toString(region)); + ASSERT2(v.getLocation() == CELL_YLOW); + ASSERT2(f.getLocation() == CELL_CENTRE); + return Vpar_Grad_par(v, f, CELL_CENTRE, toString(region)); +} +[[gnu::deprecated( + "Grad_par_LtoC is deprecated. Staggering is now supported in Grad_par.")]] +inline const Field3D Grad_par_LtoC(const Field3D &var) { + ASSERT2(var.getLocation() == CELL_YLOW); + return Grad_par(var, CELL_CENTRE); +} +[[gnu::deprecated( + "Grad_par_LtoC is deprecated. Staggering is now supported in Grad_par.")]] +inline const Field2D Grad_par_LtoC(const Field2D &var) { + ASSERT2(var.getLocation() == CELL_YLOW); + return Grad_par(var, CELL_CENTRE); +} +[[gnu::deprecated( + "Div_par_LtoC is deprecated. Staggering is now supported in Grad_par.")]] +inline const Field3D Div_par_LtoC(const Field3D &var) { + ASSERT2(var.getLocation() == CELL_YLOW); + return Div_par(var, CELL_CENTRE); +} +[[gnu::deprecated( + "Div_par_LtoC is deprecated. Staggering is now supported in Grad_par.")]] +inline const Field2D Div_par_LtoC(const Field2D &var) { + ASSERT2(var.getLocation() == CELL_YLOW); + return Div_par(var, CELL_CENTRE); +} +[[gnu::deprecated( + "Div_par_CtoL is deprecated. Staggering is now supported in Grad_par.")]] +inline const Field3D Div_par_CtoL(const Field3D &var) { + ASSERT2(var.getLocation() == CELL_CENTRE); + return Div_par(var, CELL_YLOW); +} +[[gnu::deprecated( + "Div_par_CtoL is deprecated. Staggering is now supported in Grad_par.")]] +inline const Field2D Div_par_CtoL(const Field2D &var) { + ASSERT2(var.getLocation() == CELL_CENTRE); + return Div_par(var, CELL_YLOW); } -const Field3D Grad_par_LtoC(const Field3D &var); -const Field2D Grad_par_LtoC(const Field2D &var); -const Field3D Div_par_LtoC(const Field3D &var); -const Field2D Div_par_LtoC(const Field2D &var); -const Field3D Div_par_CtoL(const Field3D &var); -const Field2D Div_par_CtoL(const Field2D &var); /*! * Parallel divergence of diffusive flux, K*Grad_par diff --git a/src/mesh/difops.cxx b/src/mesh/difops.cxx index 1f96e749ae..401ace8640 100644 --- a/src/mesh/difops.cxx +++ b/src/mesh/difops.cxx @@ -262,219 +262,6 @@ const Field3D Div_par_flux(const Field3D &v, const Field3D &f, const std::string return Div_par_flux(v,f, outloc, method); } -/******************************************************************************* -* Parallel derivatives converting between left and cell centred -* NOTE: These are a quick hack to test if this works. The whole staggered grid -* thing needs to be thought through. -*******************************************************************************/ - -const Field3D Grad_par_CtoL(const Field3D &var) { - ASSERT1(var.getLocation() == CELL_CENTRE); - - Mesh *mesh = var.getMesh(); - Field3D result{emptyFrom(var).setLocation(CELL_YLOW)}; - - Coordinates *metric = var.getCoordinates(CELL_YLOW); - - if (var.hasParallelSlices()) { - // NOTE: Need to calculate one more point than centred vars - for(int jx=0; jxLocalNx;jx++) { - for(int jy=1;jyLocalNy;jy++) { - for(int jz=0;jzLocalNz;jz++) { - result(jx, jy, jz) = 2.*(var(jx, jy, jz) - var.ydown()(jx, jy-1, jz)) / (metric->dy(jx, jy) * sqrt(metric->g_22(jx, jy)) + metric->dy(jx, jy-1) * sqrt(metric->g_22(jx, jy-1))); - } - } - } - } else { - // No yup/ydown fields, so transform to cell centred - Field3D var_fa = toFieldAligned(var, "RGN_NOX"); - - for(int jx=0; jxLocalNx;jx++) { - for(int jy=1;jyLocalNy;jy++) { - for(int jz=0;jzLocalNz;jz++) { - result(jx, jy, jz) = 2.*(var_fa(jx, jy, jz) - var_fa(jx, jy-1, jz)) / (metric->dy(jx, jy) * sqrt(metric->g_22(jx, jy)) + metric->dy(jx, jy-1) * sqrt(metric->g_22(jx, jy-1))); - } - } - } - - result = fromFieldAligned(result, "RGN_NOBNDRY"); - } - - return result; -} - -const Field2D Grad_par_CtoL(const Field2D &var) { - Field2D result{emptyFrom(var).setLocation(CELL_YLOW)}; - - Coordinates *metric = var.getCoordinates(CELL_YLOW); - - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - result[i] = (var[i] - var[i.ym()]) / (metric->dy[i] * sqrt(metric->g_22[i])); - } - - return result; -} - - -const Field3D Vpar_Grad_par_LCtoC(const Field3D &v, const Field3D &f, const std::string& region) { - ASSERT1(v.getMesh() == f.getMesh()); - ASSERT1(v.getLocation() == CELL_YLOW); - ASSERT1(f.getLocation() == CELL_CENTRE); - - Field3D result{emptyFrom(f).setLocation(CELL_CENTRE)}; - - bool vUseParallelSlices = v.hasParallelSlices(); - bool fUseParallelSlices = f.hasParallelSlices(); - - if (vUseParallelSlices && fUseParallelSlices) { - // Both v and f have up/down fields - BOUT_OMP(parallel) { - stencil fval, vval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - vval.m = v.ydown()[i.ym()]; - vval.c = v[i]; - vval.p = v.yup()[i.yp()]; - - fval.m = f.ydown()[i.ym()]; - fval.c = f[i]; - fval.p = f.yup()[i.yp()]; - - // Left side - result[i] = (vval.c >= 0.0) ? vval.c * fval.m : vval.c * fval.c; - // Right side - result[i] -= (vval.p >= 0.0) ? vval.p * fval.c : vval.p * fval.p; - } - } - } - else { - // Both must shift to field aligned - // (even if one of v and f has yup/ydown fields, it doesn't make sense to - // multiply them with one in field-aligned and one in non-field-aligned - // coordinates) - Field3D v_fa = toFieldAligned(v, "RGN_NOX"); - Field3D f_fa = toFieldAligned(f, "RGN_NOX"); - - BOUT_OMP(parallel) { - stencil fval, vval; - BOUT_FOR_INNER(i, result.getRegion(region)) { - fval.m = f_fa[i.ym()]; - fval.c = f_fa[i]; - fval.p = f_fa[i.yp()]; - - vval.m = v_fa[i.ym()]; - vval.c = v_fa[i]; - vval.p = v_fa[i.yp()]; - - // Left side - result[i] = (vval.c >= 0.0) ? vval.c * fval.m : vval.c * fval.c; - // Right side - result[i] -= (vval.p >= 0.0) ? vval.p * fval.c : vval.p * fval.p; - } - - result = fromFieldAligned(result, region); - } - } - - return result; -} - -const Field3D Grad_par_LtoC(const Field3D &var) { - const auto varMesh = var.getMesh(); - - if (varMesh->StaggerGrids) { - ASSERT1(var.getLocation() == CELL_YLOW); - } - - Field3D result{emptyFrom(var).setLocation(CELL_CENTRE)}; - - Coordinates *metric = var.getCoordinates(CELL_CENTRE); - - if (var.hasParallelSlices()) { - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - result[i] = (var.yup()[i.yp()] - var[i]) / (metric->dy[i]*sqrt(metric->g_22[i])); - } - } else { - // No yup/ydown field, so transform to field aligned - - Field3D var_fa = toFieldAligned(var, "RGN_NOX"); - - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - result[i] = (var_fa[i.yp()] - var_fa[i]) / (metric->dy[i]*sqrt(metric->g_22[i])); - } - result = fromFieldAligned(result, "RGN_NOBNDRY"); - } - - return result; -} - -const Field2D Grad_par_LtoC(const Field2D &var) { - Field2D result{emptyFrom(var).setLocation(CELL_CENTRE)}; - - Coordinates *metric = var.getCoordinates(CELL_CENTRE); - - BOUT_FOR(i, result.getRegion("RGN_NOBNDRY")) { - result[i] = (var[i.yp()] - var[i]) / (metric->dy[i] * sqrt(metric->g_22[i])); - } - - return result; -} - -const Field2D Div_par_LtoC(const Field2D &var) { - return var.getCoordinates(CELL_CENTRE)->Bxy * - Grad_par_LtoC(var / var.getCoordinates(CELL_YLOW)->Bxy); -} - -const Field3D Div_par_LtoC(const Field3D &var) { - Mesh* mesh = var.getMesh(); - - Field3D result{emptyFrom(var).setLocation(CELL_CENTRE)}; - - Coordinates *metric = var.getCoordinates(CELL_CENTRE); - - // NOTE: Need to calculate one more point than centred vars - for (int jx = 0; jx < mesh->LocalNx; jx++) { - for (int jy = 0; jy < mesh->LocalNy - 1; jy++) { - for (int jz = 0; jz < mesh->LocalNz; jz++) { - result(jx, jy, jz) = metric->Bxy(jx, jy) * 2. * - (var.yup()(jx, jy + 1, jz) / metric->Bxy(jx, jy + 1) - - var(jx, jy, jz) / metric->Bxy(jx, jy)) / - (metric->dy(jx, jy) * sqrt(metric->g_22(jx, jy)) + - metric->dy(jx, jy - 1) * sqrt(metric->g_22(jx, jy - 1))); - } - } - } - - return result; -} - -const Field2D Div_par_CtoL(const Field2D &var) { - return var.getCoordinates(CELL_CENTRE)->Bxy * - Grad_par_CtoL(var / var.getCoordinates(CELL_YLOW)->Bxy); -} - -const Field3D Div_par_CtoL(const Field3D &var) { - Mesh* mesh = var.getMesh(); - - Field3D result{emptyFrom(var).setLocation(CELL_CENTRE)}; - - Coordinates *metric = var.getCoordinates(CELL_CENTRE); - - // NOTE: Need to calculate one more point than centred vars - for (int jx = 0; jx < mesh->LocalNx; jx++) { - for (int jy = 1; jy < mesh->LocalNy; jy++) { - for (int jz = 0; jz < mesh->LocalNz; jz++) { - result(jx, jy, jz) = metric->Bxy(jx, jy) * 2. * - (var(jx, jy, jz) / metric->Bxy(jx, jy) - - var.ydown()(jx, jy - 1, jz) / metric->Bxy(jx, jy - 1)) / - (metric->dy(jx, jy) * sqrt(metric->g_22(jx, jy)) + - metric->dy(jx, jy - 1) * sqrt(metric->g_22(jx, jy - 1))); - } - } - } - - return result; -} - /******************************************************************************* * Grad2_par2 * second parallel derivative From 740124bbf5c89aaf9f3f99001f835796dd218601 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 24 Oct 2019 10:45:37 +0100 Subject: [PATCH 1776/1783] Automagically checkout mpark.variant submodule --- make.config.in | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/make.config.in b/make.config.in index 52c56e0a56..313ccefdf0 100644 --- a/make.config.in +++ b/make.config.in @@ -220,7 +220,13 @@ uninstall: # Builds the library with $(OBJ) which is defined from the SOURCEC variable #################################################################### +MPARK_VARIANT_SENTINEL = $(MPARK_VARIANT_INCLUDE_PATH)/mpark/variant.hpp +$(MPARK_VARIANT_SENTINEL): + @echo "Downloading mpark.variant" + git submodule update --init --recursive $(BOUT_TOP)/externalpackages/mpark.variant + ifeq ("$(TARGET)", "libfast") +libfast: | $(MPARK_VARIANT_SENTINEL) libfast: makefile $(BOUT_CONFIG_FILE) $(BOUT_TOP)/include $(OBJ) $(DIRS) endif From 74047a77ebee14c495b336e72af5f78ad2d99a2c Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 24 Oct 2019 14:59:58 +0100 Subject: [PATCH 1777/1783] Replace Region3D with Region2D in Field3D(Field2D) assignment --- src/field/field3d.cxx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/field/field3d.cxx b/src/field/field3d.cxx index 9c8087b5e4..ea9527fe05 100644 --- a/src/field/field3d.cxx +++ b/src/field/field3d.cxx @@ -285,7 +285,11 @@ Field3D & Field3D::operator=(const Field2D &rhs) { ASSERT1(areFieldsCompatible(*this, rhs)); /// Copy data - BOUT_FOR(i, getRegion("RGN_ALL")) { (*this)[i] = rhs[i]; } + BOUT_FOR(i, rhs.getRegion("RGN_ALL")) { + for (int iz = 0; iz < nz; iz++) { + (*this)(i, iz) = rhs[i]; + } + } return *this; } From f9e52c5f394345f6e0938929ef94d10e02dc97d2 Mon Sep 17 00:00:00 2001 From: David Dickinson Date: Thu, 24 Oct 2019 15:03:02 +0100 Subject: [PATCH 1778/1783] Replace division with multiplication in `Field?D`, `BoutReal` generated field operations --- src/field/gen_fieldops.jinja | 10 ++++++++++ src/field/generated_fieldops.cxx | 15 ++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/field/gen_fieldops.jinja b/src/field/gen_fieldops.jinja index 4bd091ddaf..42e420767a 100644 --- a/src/field/gen_fieldops.jinja +++ b/src/field/gen_fieldops.jinja @@ -39,6 +39,11 @@ {{out.index}} = {{lhs.index}} {{operator}} {{rhs.base_index}}; {% endif %} } + {% elif (operator == "/") and (rhs == "BoutReal") %} + const auto tmp = 1.0 / {{rhs.index}}; + {{region_loop}}({{index_var}}, {{out.name}}.getRegion({{region_name}})) { + {{out.index}} = {{lhs.index}} * tmp; + } {% else %} {{region_loop}}({{index_var}}, {{out.name}}.getRegion({{region_name}})) { {{out.index}} = {{lhs.index}} {{operator}} {{rhs.index}}; @@ -97,6 +102,11 @@ const auto {{mixed_base_ind}} = localmesh->indPerpto3D({{index_var}}, yind); (*this)[{{base_ind_var}}] {{operator}}= {{rhs.index}}; } + {% elif (operator == "/") and (lhs == "Field3D" or lhs == "Field2D") and (rhs =="BoutReal") %} + const auto tmp = 1.0 / {{rhs.index}}; + {{region_loop}}({{index_var}}, this->getRegion({{region_name}})) { + (*this)[{{index_var}}] *= tmp; + } {% else %} {{region_loop}}({{index_var}}, this->getRegion({{region_name}})) { (*this)[{{index_var}}] {{operator}}= {{rhs.index}}; diff --git a/src/field/generated_fieldops.cxx b/src/field/generated_fieldops.cxx index ee9a26f0dd..1058c42340 100644 --- a/src/field/generated_fieldops.cxx +++ b/src/field/generated_fieldops.cxx @@ -491,7 +491,8 @@ Field3D operator/(const Field3D& lhs, const BoutReal rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] / rhs; } + const auto tmp = 1.0 / rhs; + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] * tmp; } checkData(result); return result; @@ -510,7 +511,8 @@ Field3D& Field3D::operator/=(const BoutReal rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] /= rhs; } + const auto tmp = 1.0 / rhs; + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= tmp; } checkData(*this); @@ -939,7 +941,8 @@ Field2D operator/(const Field2D& lhs, const BoutReal rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] / rhs; } + const auto tmp = 1.0 / rhs; + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] * tmp; } checkData(result); return result; @@ -954,7 +957,8 @@ Field2D& Field2D::operator/=(const BoutReal rhs) { checkData(*this); checkData(rhs); - BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] /= rhs; } + const auto tmp = 1.0 / rhs; + BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= tmp; } checkData(*this); @@ -1579,7 +1583,8 @@ FieldPerp operator/(const FieldPerp& lhs, const BoutReal rhs) { checkData(lhs); checkData(rhs); - BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] / rhs; } + const auto tmp = 1.0 / rhs; + BOUT_FOR(index, result.getRegion("RGN_ALL")) { result[index] = lhs[index] * tmp; } checkData(result); return result; From 3f8cb47af91a3c9cdf7884ece3585f68466a33f3 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 24 Oct 2019 15:44:55 +0100 Subject: [PATCH 1779/1783] Add new contributors since 4.2 to citation file --- CITATION.cff | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CITATION.cff b/CITATION.cff index 6f3294c395..0780adb951 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -56,6 +56,10 @@ authors: - family-names: Breyiannia given-names: George + - family-names: Muhammed + given-names: Hasan + affiliation: University of York + - family-names: Seto given-names: Haruki @@ -91,6 +95,9 @@ authors: given-names: Luke orcid: https://orcid.org/0000-0002-9087-9180 + - family-names: Estarellas + given-names: Marta + - family-names: Thomas given-names: Matt From 731593462c546e3851d694ea3e827bd834af38ac Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Thu, 24 Oct 2019 15:45:37 +0100 Subject: [PATCH 1780/1783] Bump version to 4.3.0 --- CITATION.cff | 2 +- configure | 22 +++++++++++----------- configure.ac | 2 +- manual/doxygen/Doxyfile | 2 +- manual/doxygen/Doxyfile_readthedocs | 2 +- manual/sphinx/conf.py | 4 ++-- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 0780adb951..12b3be29ae 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -149,7 +149,7 @@ authors: - family-names: Wang given-names: Zhanhui -version: 4.2.2 +version: 4.3.0 date-released: 2019-03-01 repository-code: https://github.com/boutproject/BOUT-dev url: http://boutproject.github.io/ diff --git a/configure b/configure index a3cf293907..c1cef9668c 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for BOUT++ 4.2.2. +# Generated by GNU Autoconf 2.69 for BOUT++ 4.3.0. # # Report bugs to . # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='BOUT++' PACKAGE_TARNAME='bout--' -PACKAGE_VERSION='4.2.2' -PACKAGE_STRING='BOUT++ 4.2.2' +PACKAGE_VERSION='4.3.0' +PACKAGE_STRING='BOUT++ 4.3.0' PACKAGE_BUGREPORT='bd512@york.ac.uk' PACKAGE_URL='' @@ -1382,7 +1382,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures BOUT++ 4.2.2 to adapt to many kinds of systems. +\`configure' configures BOUT++ 4.3.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1447,7 +1447,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of BOUT++ 4.2.2:";; + short | recursive ) echo "Configuration of BOUT++ 4.3.0:";; esac cat <<\_ACEOF @@ -1583,7 +1583,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -BOUT++ configure 4.2.2 +BOUT++ configure 4.3.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2164,7 +2164,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by BOUT++ $as_me 4.2.2, which was +It was created by BOUT++ $as_me 4.3.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -14942,7 +14942,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by BOUT++ $as_me 4.2.2, which was +This file was extended by BOUT++ $as_me 4.3.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14999,7 +14999,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -BOUT++ config.status 4.2.2 +BOUT++ config.status 4.3.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -16311,7 +16311,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by BOUT++ $as_me 4.2.2, which was +This file was extended by BOUT++ $as_me 4.3.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -16368,7 +16368,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -BOUT++ config.status 4.2.2 +BOUT++ config.status 4.3.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index a219ae1859..2821644220 100644 --- a/configure.ac +++ b/configure.ac @@ -32,7 +32,7 @@ # AC_PREREQ([2.69]) -AC_INIT([BOUT++],[4.2.2],[bd512@york.ac.uk]) +AC_INIT([BOUT++],[4.3.0],[bd512@york.ac.uk]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/manual/doxygen/Doxyfile b/manual/doxygen/Doxyfile index 716863debb..213e3b1251 100644 --- a/manual/doxygen/Doxyfile +++ b/manual/doxygen/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = BOUT++ # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.2.2 +PROJECT_NUMBER = 4.3.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/manual/doxygen/Doxyfile_readthedocs b/manual/doxygen/Doxyfile_readthedocs index 5f704afb2e..1a48ee7a47 100644 --- a/manual/doxygen/Doxyfile_readthedocs +++ b/manual/doxygen/Doxyfile_readthedocs @@ -38,7 +38,7 @@ PROJECT_NAME = BOUT++ # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.2.2 +PROJECT_NUMBER = 4.3.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/manual/sphinx/conf.py b/manual/sphinx/conf.py index d763464f78..31de82f900 100755 --- a/manual/sphinx/conf.py +++ b/manual/sphinx/conf.py @@ -131,9 +131,9 @@ def __getattr__(cls, name): # built documents. # # The short X.Y version. -version = '4.2' +version = '4.3' # The full version, including alpha/beta/rc tags. -release = '4.2.2' +release = '4.3.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From 04487b40bfca1126d84c6c57300962ed77648efa Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 25 Oct 2019 11:45:33 +0100 Subject: [PATCH 1781/1783] Update citation file for v4.3.0 --- CITATION.bib | 8 +++++--- CITATION.cff | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CITATION.bib b/CITATION.bib index f1e4876354..e7cddb2166 100644 --- a/CITATION.bib +++ b/CITATION.bib @@ -1,4 +1,4 @@ -@misc{BOUTv4-2-2, +@misc{BOUTv4-3-0, author = { Benjamin Daniel Dudson and Peter Alec Hill and @@ -14,6 +14,7 @@ @misc{BOUTv4-2-2 Dmitry Meyerson and Eric Grinaker and George Breyiannia and + Hasan Muhammed and Haruki Seto and Hong Zhang and Ilon Joseph and @@ -25,6 +26,7 @@ @misc{BOUTv4-2-2 Kevin Savage and Licheng Wang and Luke Easy and + Marta Estarellas and Matt Thomas and Maxim Umansky and Michael Løiten and @@ -44,9 +46,9 @@ @misc{BOUTv4-2-2 Zhanhui Wang }, title = {BOUT++}, -month = {3}, +month = {10}, year = {2019}, -doi = {10.5281/zenodo.2579077}, +doi = {10.5281/zenodo.3518905}, url = {https://github.com/boutproject/BOUT-dev} } diff --git a/CITATION.cff b/CITATION.cff index 12b3be29ae..9c9eeaf6c4 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -150,10 +150,10 @@ authors: - family-names: Wang given-names: Zhanhui version: 4.3.0 -date-released: 2019-03-01 +date-released: 2019-10-25 repository-code: https://github.com/boutproject/BOUT-dev url: http://boutproject.github.io/ -doi: 10.5281/zenodo.2579077 +doi: 10.5281/zenodo.3518905 license: 'LGPL-3.0-or-later' references: - type: article From 7c291cccc9e024ec33b07c9ac37bdd6e7d995f72 Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 25 Oct 2019 11:46:50 +0100 Subject: [PATCH 1782/1783] Update changelog and summary for v4.3.0 --- CHANGELOG.md | 294 ++++++++++++++++++++++++++++++++++++++++++++++ change_summary.md | 163 +++++++++++++++++++++++++ 2 files changed, 457 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0689b2259c..98034cc1cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,296 @@ # Change Log +## [v4.3.0](https://github.com/boutproject/BOUT-dev/tree/v4.3.0) (2019-10-24) +[Full Changelog](https://github.com/boutproject/BOUT-dev/compare/v4.2.3...v4.3.0) + +**Merged pull requests:** + +- Micro optimise some common routines for v4.3.0-rc [\#1824](https://github.com/boutproject/BOUT-dev/pull/1824) ([d7919](https://github.com/d7919)) +- Automagically checkout mpark.variant submodule [\#1823](https://github.com/boutproject/BOUT-dev/pull/1823) ([ZedThree](https://github.com/ZedThree)) +- Deprecate CtoL and LtoC differential operators [\#1822](https://github.com/boutproject/BOUT-dev/pull/1822) ([johnomotani](https://github.com/johnomotani)) +- Bugfix add missing include and update configure [\#1819](https://github.com/boutproject/BOUT-dev/pull/1819) ([d7919](https://github.com/d7919)) +- Performance fixes: ShiftedMetric and VDDY [\#1816](https://github.com/boutproject/BOUT-dev/pull/1816) ([ZedThree](https://github.com/ZedThree)) +- Save all commonly used geometry variables [\#1815](https://github.com/boutproject/BOUT-dev/pull/1815) ([johnomotani](https://github.com/johnomotani)) +- Make interp\_to and finite-volume parallel operators return result in the same space as the input [\#1813](https://github.com/boutproject/BOUT-dev/pull/1813) ([johnomotani](https://github.com/johnomotani)) +- Ensure parallel\_transform is only read from grid files, not from options [\#1812](https://github.com/boutproject/BOUT-dev/pull/1812) ([johnomotani](https://github.com/johnomotani)) +- Bugfixes for writing Vector2D and Vector3D [\#1809](https://github.com/boutproject/BOUT-dev/pull/1809) ([johnomotani](https://github.com/johnomotani)) +- Bugfix: result of InvertParCR::solve tagged in wrong y space [\#1806](https://github.com/boutproject/BOUT-dev/pull/1806) ([ZedThree](https://github.com/ZedThree)) +- Remove some superfluous location checks in Laplacian [\#1804](https://github.com/boutproject/BOUT-dev/pull/1804) ([ZedThree](https://github.com/ZedThree)) +- Fix for Intel enabling -Wnull-dereference despite not accepting it [\#1801](https://github.com/boutproject/BOUT-dev/pull/1801) ([ZedThree](https://github.com/ZedThree)) +- Fix assignment instead of comparison in ASSERTs [\#1800](https://github.com/boutproject/BOUT-dev/pull/1800) ([ZedThree](https://github.com/ZedThree)) +- Fix y-extrapolation in BoundaryDirichlet::apply\(Field2D&\) [\#1799](https://github.com/boutproject/BOUT-dev/pull/1799) ([johnomotani](https://github.com/johnomotani)) +- Fix typo in ternary in InvertableOperator [\#1798](https://github.com/boutproject/BOUT-dev/pull/1798) ([ZedThree](https://github.com/ZedThree)) +- Fix in-place Region methods returning new instances [\#1797](https://github.com/boutproject/BOUT-dev/pull/1797) ([ZedThree](https://github.com/ZedThree)) +- Make CELL\_LOC strongly typed [\#1796](https://github.com/boutproject/BOUT-dev/pull/1796) ([johnomotani](https://github.com/johnomotani)) +- Allow NYPE to be given instead of NXPE in input files [\#1794](https://github.com/boutproject/BOUT-dev/pull/1794) ([johnomotani](https://github.com/johnomotani)) +- Implement boundary conditions for CELL\_ZLOW fields [\#1793](https://github.com/boutproject/BOUT-dev/pull/1793) ([johnomotani](https://github.com/johnomotani)) +- Fix initial conditions not being transformed correctly [\#1791](https://github.com/boutproject/BOUT-dev/pull/1791) ([ZedThree](https://github.com/ZedThree)) +- Add manual section on xlC compiler [\#1790](https://github.com/boutproject/BOUT-dev/pull/1790) ([bendudson](https://github.com/bendudson)) +- Remove checks in Laplace that fail if outloc==CELL\_DEFAULT [\#1788](https://github.com/boutproject/BOUT-dev/pull/1788) ([johnomotani](https://github.com/johnomotani)) +- Implement the INVERT\_ZERO\_DC flag in LaplaceCyclic [\#1786](https://github.com/boutproject/BOUT-dev/pull/1786) ([johnomotani](https://github.com/johnomotani)) +- Add macro for Scorep instrumentation of a user-defined code region [\#1784](https://github.com/boutproject/BOUT-dev/pull/1784) ([JosephThomasParker](https://github.com/JosephThomasParker)) +- Fix some issues in hypnotoad [\#1783](https://github.com/boutproject/BOUT-dev/pull/1783) ([friva000](https://github.com/friva000)) +- Remove redundant 'allocate\(\)' calls [\#1782](https://github.com/boutproject/BOUT-dev/pull/1782) ([johnomotani](https://github.com/johnomotani)) +- Correct manual - default for 'floats' is true for dump files too [\#1780](https://github.com/boutproject/BOUT-dev/pull/1780) ([johnomotani](https://github.com/johnomotani)) +- Support bool variables in file I/O [\#1779](https://github.com/boutproject/BOUT-dev/pull/1779) ([johnomotani](https://github.com/johnomotani)) +- Scripts cleanup [\#1778](https://github.com/boutproject/BOUT-dev/pull/1778) ([dschwoerer](https://github.com/dschwoerer)) +- File open error messages [\#1777](https://github.com/boutproject/BOUT-dev/pull/1777) ([johnomotani](https://github.com/johnomotani)) +- Don't ignore $MPIRUN [\#1776](https://github.com/boutproject/BOUT-dev/pull/1776) ([dschwoerer](https://github.com/dschwoerer)) +- Update performance/iterator-offsets example [\#1775](https://github.com/boutproject/BOUT-dev/pull/1775) ([dschwoerer](https://github.com/dschwoerer)) +- Bout4to5 script [\#1774](https://github.com/boutproject/BOUT-dev/pull/1774) ([bendudson](https://github.com/bendudson)) +- Consistent global indices [\#1770](https://github.com/boutproject/BOUT-dev/pull/1770) ([johnomotani](https://github.com/johnomotani)) +- Add processor indices to dump files [\#1769](https://github.com/boutproject/BOUT-dev/pull/1769) ([johnomotani](https://github.com/johnomotani)) +- Try GitHub url for SUNDIALS if LLNL url fails [\#1768](https://github.com/boutproject/BOUT-dev/pull/1768) ([ZedThree](https://github.com/ZedThree)) +- Fix reading of zShift\_ylow [\#1767](https://github.com/boutproject/BOUT-dev/pull/1767) ([johnomotani](https://github.com/johnomotani)) +- Fixes for Python DataFile class [\#1766](https://github.com/boutproject/BOUT-dev/pull/1766) ([johnomotani](https://github.com/johnomotani)) +- Fix y-boundary cells of phi in conducting-wall-mode example [\#1765](https://github.com/boutproject/BOUT-dev/pull/1765) ([johnomotani](https://github.com/johnomotani)) +- Add mesh options for extrapolate\_{x,y} [\#1760](https://github.com/boutproject/BOUT-dev/pull/1760) ([bendudson](https://github.com/bendudson)) +- Deprecate Laplacian::setFlags\(\) [\#1758](https://github.com/boutproject/BOUT-dev/pull/1758) ([johnomotani](https://github.com/johnomotani)) +- Fix advection MMS tests [\#1757](https://github.com/boutproject/BOUT-dev/pull/1757) ([ZedThree](https://github.com/ZedThree)) +- Rename 'coordinates\_type' gridfile attribute to 'parallel\_transform' [\#1756](https://github.com/boutproject/BOUT-dev/pull/1756) ([ZedThree](https://github.com/ZedThree)) +- More clang-tidy fixes [\#1755](https://github.com/boutproject/BOUT-dev/pull/1755) ([ZedThree](https://github.com/ZedThree)) +- Add default value to Mesh::get for ints [\#1754](https://github.com/boutproject/BOUT-dev/pull/1754) ([JosephThomasParker](https://github.com/JosephThomasParker)) +- Remove FIXME comment from interp\_to [\#1752](https://github.com/boutproject/BOUT-dev/pull/1752) ([johnomotani](https://github.com/johnomotani)) +- Build pdf manual [\#1751](https://github.com/boutproject/BOUT-dev/pull/1751) ([johnomotani](https://github.com/johnomotani)) +- Bug fix, test and tidy SLEPc solver [\#1749](https://github.com/boutproject/BOUT-dev/pull/1749) ([ZedThree](https://github.com/ZedThree)) +- SNB nonlocal heat flux model [\#1748](https://github.com/boutproject/BOUT-dev/pull/1748) ([bendudson](https://github.com/bendudson)) +- Pin packages in requirements.txt for Sphinx docs [\#1746](https://github.com/boutproject/BOUT-dev/pull/1746) ([ZedThree](https://github.com/ZedThree)) +- Don't mark Coordinates::zShift as const, can't be output [\#1745](https://github.com/boutproject/BOUT-dev/pull/1745) ([ZedThree](https://github.com/ZedThree)) +- Laplacian: FFT include dfdz term, plus manual updates [\#1744](https://github.com/boutproject/BOUT-dev/pull/1744) ([johnomotani](https://github.com/johnomotani)) +- Fix interpolation of staggered zShift [\#1743](https://github.com/boutproject/BOUT-dev/pull/1743) ([johnomotani](https://github.com/johnomotani)) +- Correct calculation of Bxy when interpolating from CELL\_CENTRE [\#1741](https://github.com/boutproject/BOUT-dev/pull/1741) ([johnomotani](https://github.com/johnomotani)) +- Only call checkPositive\(g\) for grid cells [\#1739](https://github.com/boutproject/BOUT-dev/pull/1739) ([johnomotani](https://github.com/johnomotani)) +- Output ParallelTransform variables [\#1736](https://github.com/boutproject/BOUT-dev/pull/1736) ([johnomotani](https://github.com/johnomotani)) +- Fix BoutMesh decomposition on single processor [\#1735](https://github.com/boutproject/BOUT-dev/pull/1735) ([ZedThree](https://github.com/ZedThree)) +- Deprecate some unused methods [\#1734](https://github.com/boutproject/BOUT-dev/pull/1734) ([ZedThree](https://github.com/ZedThree)) +- make sure values\(\) returns valid pointer [\#1733](https://github.com/boutproject/BOUT-dev/pull/1733) ([dschwoerer](https://github.com/dschwoerer)) +- Twistshift for field-aligned variables [\#1732](https://github.com/boutproject/BOUT-dev/pull/1732) ([johnomotani](https://github.com/johnomotani)) +- Add bout::utils::is\_Field and variants [\#1730](https://github.com/boutproject/BOUT-dev/pull/1730) ([ZedThree](https://github.com/ZedThree)) +- Deprecate Karniadakis solver [\#1727](https://github.com/boutproject/BOUT-dev/pull/1727) ([ZedThree](https://github.com/ZedThree)) +- Make MsgStack and BoutException unit tests more flexible [\#1726](https://github.com/boutproject/BOUT-dev/pull/1726) ([ZedThree](https://github.com/ZedThree)) +- Bugfix: use region in Coordinates::calcCovariant/calcContravariant [\#1725](https://github.com/boutproject/BOUT-dev/pull/1725) ([ZedThree](https://github.com/ZedThree)) +- Hardcode all variables for test-solver; remove input file [\#1724](https://github.com/boutproject/BOUT-dev/pull/1724) ([ZedThree](https://github.com/ZedThree)) +- Remove Laplace3D [\#1723](https://github.com/boutproject/BOUT-dev/pull/1723) ([ZedThree](https://github.com/ZedThree)) +- Add function\_traits template and replace SUNDIALS int type macros [\#1722](https://github.com/boutproject/BOUT-dev/pull/1722) ([ZedThree](https://github.com/ZedThree)) +- fix nc-format [\#1721](https://github.com/boutproject/BOUT-dev/pull/1721) ([dschwoerer](https://github.com/dschwoerer)) +- Templated Field functions and deprecate REGION enum arguments [\#1720](https://github.com/boutproject/BOUT-dev/pull/1720) ([johnomotani](https://github.com/johnomotani)) +- More robust staggered Jacobian and RGN\_NOCORNERS [\#1719](https://github.com/boutproject/BOUT-dev/pull/1719) ([johnomotani](https://github.com/johnomotani)) +- Handle attributes for missing variables [\#1718](https://github.com/boutproject/BOUT-dev/pull/1718) ([bendudson](https://github.com/bendudson)) +- Revert "Hypnotoad: 'H' is derivative of integral" [\#1717](https://github.com/boutproject/BOUT-dev/pull/1717) ([johnomotani](https://github.com/johnomotani)) +- Remove deprecated invert\_laplace from gyro\_average [\#1716](https://github.com/boutproject/BOUT-dev/pull/1716) ([ZedThree](https://github.com/ZedThree)) +- Lots of small clang-tidy fixes [\#1715](https://github.com/boutproject/BOUT-dev/pull/1715) ([ZedThree](https://github.com/ZedThree)) +- Tidy up direction-type setters [\#1712](https://github.com/boutproject/BOUT-dev/pull/1712) ([johnomotani](https://github.com/johnomotani)) +- Add implementation of Field2D::applyBoundary\(BoutReal time\) [\#1711](https://github.com/boutproject/BOUT-dev/pull/1711) ([ZedThree](https://github.com/ZedThree)) +- Fix BoutMesh boundary regions [\#1710](https://github.com/boutproject/BOUT-dev/pull/1710) ([ZedThree](https://github.com/ZedThree)) +- Don't run tests that use FFTW if not compiled with it [\#1709](https://github.com/boutproject/BOUT-dev/pull/1709) ([ZedThree](https://github.com/ZedThree)) +- Fixes for FV::Div\_a\_Laplace\_perp [\#1707](https://github.com/boutproject/BOUT-dev/pull/1707) ([bendudson](https://github.com/bendudson)) +- Set y-direction of FieldPerp results in ParallelTransformIdentity [\#1704](https://github.com/boutproject/BOUT-dev/pull/1704) ([johnomotani](https://github.com/johnomotani)) +- Do not calculate parallel slices for field-aligned fields [\#1703](https://github.com/boutproject/BOUT-dev/pull/1703) ([johnomotani](https://github.com/johnomotani)) +- Allow default value of Options to be set from another Options object [\#1702](https://github.com/boutproject/BOUT-dev/pull/1702) ([johnomotani](https://github.com/johnomotani)) +- Fieldperp I/O [\#1699](https://github.com/boutproject/BOUT-dev/pull/1699) ([johnomotani](https://github.com/johnomotani)) +- Set y-direction of results in ParallelTransformIdentity [\#1698](https://github.com/boutproject/BOUT-dev/pull/1698) ([johnomotani](https://github.com/johnomotani)) +- Add support for shifting a FieldPerp toFieldAligned/fromFieldAligned [\#1697](https://github.com/boutproject/BOUT-dev/pull/1697) ([johnomotani](https://github.com/johnomotani)) +- Experimental CMake support [\#1696](https://github.com/boutproject/BOUT-dev/pull/1696) ([ZedThree](https://github.com/ZedThree)) +- Convert Options::isSection\(\) argument to lower case [\#1695](https://github.com/boutproject/BOUT-dev/pull/1695) ([johnomotani](https://github.com/johnomotani)) +- Update required Jinja2 version to avoid CVE-2019-10906 [\#1694](https://github.com/boutproject/BOUT-dev/pull/1694) ([ZedThree](https://github.com/ZedThree)) +- Move Gridfile::get implementations for Field3D/Field2D to .cxx [\#1693](https://github.com/boutproject/BOUT-dev/pull/1693) ([johnomotani](https://github.com/johnomotani)) +- Warn about random failures in test [\#1692](https://github.com/boutproject/BOUT-dev/pull/1692) ([dschwoerer](https://github.com/dschwoerer)) +- Use asynchronous communications in LaplaceMultigrid [\#1691](https://github.com/boutproject/BOUT-dev/pull/1691) ([johnomotani](https://github.com/johnomotani)) +- Remove multiple printing of BOUTLOCALE to stderr [\#1689](https://github.com/boutproject/BOUT-dev/pull/1689) ([johnomotani](https://github.com/johnomotani)) +- Fix elm pb example [\#1688](https://github.com/boutproject/BOUT-dev/pull/1688) ([bendudson](https://github.com/bendudson)) +- Bugfix: bracket operator slowdown [\#1686](https://github.com/boutproject/BOUT-dev/pull/1686) ([johnomotani](https://github.com/johnomotani)) +- Fix and reenable [\#1684](https://github.com/boutproject/BOUT-dev/pull/1684) ([dschwoerer](https://github.com/dschwoerer)) +- call Finalise in test [\#1683](https://github.com/boutproject/BOUT-dev/pull/1683) ([dschwoerer](https://github.com/dschwoerer)) +- Fix comparison of corner boundary cells in test-squash [\#1682](https://github.com/boutproject/BOUT-dev/pull/1682) ([johnomotani](https://github.com/johnomotani)) +- Clear Field3D parallel slices in operator= [\#1681](https://github.com/boutproject/BOUT-dev/pull/1681) ([johnomotani](https://github.com/johnomotani)) +- Ignore new meta-vars in test-squash [\#1679](https://github.com/boutproject/BOUT-dev/pull/1679) ([dschwoerer](https://github.com/dschwoerer)) +- Fix examples [\#1678](https://github.com/boutproject/BOUT-dev/pull/1678) ([dschwoerer](https://github.com/dschwoerer)) +- Add .BOUT.pid.\* files to .gitignore [\#1674](https://github.com/boutproject/BOUT-dev/pull/1674) ([johnomotani](https://github.com/johnomotani)) +- Runge-Kutta-Legendre stabilised explicit method [\#1673](https://github.com/boutproject/BOUT-dev/pull/1673) ([bendudson](https://github.com/bendudson)) +- Unit tests and template-isation of `where` [\#1672](https://github.com/boutproject/BOUT-dev/pull/1672) ([ZedThree](https://github.com/ZedThree)) +- Don't try to build documentation [\#1671](https://github.com/boutproject/BOUT-dev/pull/1671) ([dschwoerer](https://github.com/dschwoerer)) +- Method for Laplace solvers to say whether they use 3D coefficients [\#1669](https://github.com/boutproject/BOUT-dev/pull/1669) ([johnomotani](https://github.com/johnomotani)) +- Fix dereferencing null Coordinates in FieldFactory [\#1667](https://github.com/boutproject/BOUT-dev/pull/1667) ([ZedThree](https://github.com/ZedThree)) +- Bugfix: return fields by reference [\#1663](https://github.com/boutproject/BOUT-dev/pull/1663) ([dschwoerer](https://github.com/dschwoerer)) +- Allow clean exit in boutcore [\#1662](https://github.com/boutproject/BOUT-dev/pull/1662) ([dschwoerer](https://github.com/dschwoerer)) +- Make mixed second-derivative operators more correct [\#1661](https://github.com/boutproject/BOUT-dev/pull/1661) ([johnomotani](https://github.com/johnomotani)) +- Unit tests and various small refactorings of Solver [\#1660](https://github.com/boutproject/BOUT-dev/pull/1660) ([ZedThree](https://github.com/ZedThree)) +- Under-relaxation for LaplaceNaulin [\#1659](https://github.com/boutproject/BOUT-dev/pull/1659) ([johnomotani](https://github.com/johnomotani)) +- Counters for timers, makes them correct with multiple Timer objects [\#1658](https://github.com/boutproject/BOUT-dev/pull/1658) ([johnomotani](https://github.com/johnomotani)) +- Generate FieldPerp arithmetic operators with jinja [\#1655](https://github.com/boutproject/BOUT-dev/pull/1655) ([johnomotani](https://github.com/johnomotani)) +- LaplaceNaulin solver improvement, and more general coefficients for LaplaceCyclic [\#1654](https://github.com/boutproject/BOUT-dev/pull/1654) ([johnomotani](https://github.com/johnomotani)) +- Options type and doc attributes [\#1653](https://github.com/boutproject/BOUT-dev/pull/1653) ([bendudson](https://github.com/bendudson)) +- Fix mesh checks in Laplace implementation headers [\#1652](https://github.com/boutproject/BOUT-dev/pull/1652) ([johnomotani](https://github.com/johnomotani)) +- Minor refactoring of BoutInitialise, BoutFinalise [\#1651](https://github.com/boutproject/BOUT-dev/pull/1651) ([ZedThree](https://github.com/ZedThree)) +- Add name argument to Options::isSection to test for presence of subsection [\#1650](https://github.com/boutproject/BOUT-dev/pull/1650) ([johnomotani](https://github.com/johnomotani)) +- Support SUNDIALS 4.1.0 [\#1649](https://github.com/boutproject/BOUT-dev/pull/1649) ([ZedThree](https://github.com/ZedThree)) +- Make transforming Field3D inputs from field aligned optional [\#1648](https://github.com/boutproject/BOUT-dev/pull/1648) ([johnomotani](https://github.com/johnomotani)) +- Hypnotoad: double precision and y-boundary guard cells [\#1647](https://github.com/boutproject/BOUT-dev/pull/1647) ([johnomotani](https://github.com/johnomotani)) +- Fix y-boundaries of Coordinates fields [\#1646](https://github.com/boutproject/BOUT-dev/pull/1646) ([johnomotani](https://github.com/johnomotani)) +- Add order-only dependency on gtest sentinel to unit test objects [\#1643](https://github.com/boutproject/BOUT-dev/pull/1643) ([ZedThree](https://github.com/ZedThree)) +- Change variable names for output from staggered Coordinates [\#1639](https://github.com/boutproject/BOUT-dev/pull/1639) ([johnomotani](https://github.com/johnomotani)) +- Hypnotoad: enable 'Detailed settings' for nonorthogonal grids [\#1636](https://github.com/boutproject/BOUT-dev/pull/1636) ([johnomotani](https://github.com/johnomotani)) +- Make ParallelTransform location-aware [\#1635](https://github.com/boutproject/BOUT-dev/pull/1635) ([johnomotani](https://github.com/johnomotani)) +- Replace ENUM\ss_STRING functions with toString overloads [\#1634](https://github.com/boutproject/BOUT-dev/pull/1634) ([ZedThree](https://github.com/ZedThree)) +- Last couple of master bugfixes into next [\#1633](https://github.com/boutproject/BOUT-dev/pull/1633) ([ZedThree](https://github.com/ZedThree)) +- Write Field directions as attributes in output files [\#1631](https://github.com/boutproject/BOUT-dev/pull/1631) ([johnomotani](https://github.com/johnomotani)) +- Some small improvements to unit tests [\#1630](https://github.com/boutproject/BOUT-dev/pull/1630) ([ZedThree](https://github.com/ZedThree)) +- Loosen tolerance for CyclicReduce tests [\#1628](https://github.com/boutproject/BOUT-dev/pull/1628) ([ZedThree](https://github.com/ZedThree)) +- Add some basic unit tests for CyclicReduce [\#1625](https://github.com/boutproject/BOUT-dev/pull/1625) ([ZedThree](https://github.com/ZedThree)) +- Direction tagging and emptyFrom [\#1624](https://github.com/boutproject/BOUT-dev/pull/1624) ([johnomotani](https://github.com/johnomotani)) +- Fix spatial advection 2 [\#1623](https://github.com/boutproject/BOUT-dev/pull/1623) ([dschwoerer](https://github.com/dschwoerer)) +- set -e [\#1622](https://github.com/boutproject/BOUT-dev/pull/1622) ([dschwoerer](https://github.com/dschwoerer)) +- Pin pip packages on Travis [\#1621](https://github.com/boutproject/BOUT-dev/pull/1621) ([ZedThree](https://github.com/ZedThree)) +- Fix printf formats in Ncxx4/H5Format::setAttribute\(..., BoutReal\) [\#1620](https://github.com/boutproject/BOUT-dev/pull/1620) ([ZedThree](https://github.com/ZedThree)) +- Use std::map::find to avoid double lookup in getCoordinates [\#1618](https://github.com/boutproject/BOUT-dev/pull/1618) ([johnomotani](https://github.com/johnomotani)) +- Merge v4.2.2 into next [\#1616](https://github.com/boutproject/BOUT-dev/pull/1616) ([ZedThree](https://github.com/ZedThree)) +- Add FDDX\_U2 implementation, plus minor bugfixes [\#1615](https://github.com/boutproject/BOUT-dev/pull/1615) ([johnomotani](https://github.com/johnomotani)) +- Unit tests for GridFromOptions [\#1614](https://github.com/boutproject/BOUT-dev/pull/1614) ([ZedThree](https://github.com/ZedThree)) +- A few small unit test improvements [\#1613](https://github.com/boutproject/BOUT-dev/pull/1613) ([ZedThree](https://github.com/ZedThree)) +- Initial profile tests and tidy [\#1602](https://github.com/boutproject/BOUT-dev/pull/1602) ([ZedThree](https://github.com/ZedThree)) +- Some quality of life improvements for unit tests [\#1601](https://github.com/boutproject/BOUT-dev/pull/1601) ([ZedThree](https://github.com/ZedThree)) +- FieldFactory and ExpressionParser tidy [\#1597](https://github.com/boutproject/BOUT-dev/pull/1597) ([ZedThree](https://github.com/ZedThree)) +- Hypnotoad: more flexible transitions in nonorthogonal grid generation [\#1596](https://github.com/boutproject/BOUT-dev/pull/1596) ([johnomotani](https://github.com/johnomotani)) +- Hypnotoad nonorthogonal fixes [\#1593](https://github.com/boutproject/BOUT-dev/pull/1593) ([johnomotani](https://github.com/johnomotani)) +- More unit tests for derivatives [\#1592](https://github.com/boutproject/BOUT-dev/pull/1592) ([ZedThree](https://github.com/ZedThree)) +- More Field\* tests [\#1591](https://github.com/boutproject/BOUT-dev/pull/1591) ([ZedThree](https://github.com/ZedThree)) +- InterpolationFactory tests [\#1590](https://github.com/boutproject/BOUT-dev/pull/1590) ([ZedThree](https://github.com/ZedThree)) +- Timer tests and refactor [\#1589](https://github.com/boutproject/BOUT-dev/pull/1589) ([ZedThree](https://github.com/ZedThree)) +- Check buffer length [\#1586](https://github.com/boutproject/BOUT-dev/pull/1586) ([dschwoerer](https://github.com/dschwoerer)) +- getmpirun default [\#1584](https://github.com/boutproject/BOUT-dev/pull/1584) ([dschwoerer](https://github.com/dschwoerer)) +- Spanish translation [\#1579](https://github.com/boutproject/BOUT-dev/pull/1579) ([bendudson](https://github.com/bendudson)) +- Make application of INVERT\_SET at outer boundary clearer in cyclic solver [\#1578](https://github.com/boutproject/BOUT-dev/pull/1578) ([johnomotani](https://github.com/johnomotani)) +- Use Xenial on Travis [\#1577](https://github.com/boutproject/BOUT-dev/pull/1577) ([ZedThree](https://github.com/ZedThree)) +- Tidy derivatives [\#1576](https://github.com/boutproject/BOUT-dev/pull/1576) ([d7919](https://github.com/d7919)) +- Hypnotoad: output coordinate system labelling [\#1575](https://github.com/boutproject/BOUT-dev/pull/1575) ([johnomotani](https://github.com/johnomotani)) +- Codecov tweaks [\#1571](https://github.com/boutproject/BOUT-dev/pull/1571) ([ZedThree](https://github.com/ZedThree)) +- Avoid out-of-range access for invalid regions [\#1570](https://github.com/boutproject/BOUT-dev/pull/1570) ([dschwoerer](https://github.com/dschwoerer)) +- Allow Coordinates on staggered grids to be read from grid files [\#1564](https://github.com/boutproject/BOUT-dev/pull/1564) ([johnomotani](https://github.com/johnomotani)) +- Enable communications for simulations with no core, only divertor legs [\#1563](https://github.com/boutproject/BOUT-dev/pull/1563) ([johnomotani](https://github.com/johnomotani)) +- Hypnotoad: add checkbox to output metrics for orthogonal coordinates [\#1562](https://github.com/boutproject/BOUT-dev/pull/1562) ([johnomotani](https://github.com/johnomotani)) +- Hypnotoad: handle case when break of contour is very close to x-point [\#1561](https://github.com/boutproject/BOUT-dev/pull/1561) ([johnomotani](https://github.com/johnomotani)) +- Prevent data corruption [\#1558](https://github.com/boutproject/BOUT-dev/pull/1558) ([dschwoerer](https://github.com/dschwoerer)) +- Locale de [\#1556](https://github.com/boutproject/BOUT-dev/pull/1556) ([dschwoerer](https://github.com/dschwoerer)) +- Fix expr.hxx [\#1555](https://github.com/boutproject/BOUT-dev/pull/1555) ([dschwoerer](https://github.com/dschwoerer)) +- Update name of helper function [\#1553](https://github.com/boutproject/BOUT-dev/pull/1553) ([d7919](https://github.com/d7919)) +- Remove old examples and change to use new options style [\#1550](https://github.com/boutproject/BOUT-dev/pull/1550) ([d7919](https://github.com/d7919)) +- Replace IsField\\*Equal\\* predicates with templated versions [\#1547](https://github.com/boutproject/BOUT-dev/pull/1547) ([ZedThree](https://github.com/ZedThree)) +- Fix bug in DST option for cyclic solve [\#1546](https://github.com/boutproject/BOUT-dev/pull/1546) ([bendudson](https://github.com/bendudson)) +- More derivative tests [\#1545](https://github.com/boutproject/BOUT-dev/pull/1545) ([d7919](https://github.com/d7919)) +- Improve make-script example [\#1542](https://github.com/boutproject/BOUT-dev/pull/1542) ([dschwoerer](https://github.com/dschwoerer)) +- Pass by reference in makeField [\#1541](https://github.com/boutproject/BOUT-dev/pull/1541) ([ZedThree](https://github.com/ZedThree)) +- Replace MMS/spatial/advection with simpler/more complete test [\#1540](https://github.com/boutproject/BOUT-dev/pull/1540) ([ZedThree](https://github.com/ZedThree)) +- Fix time MMS [\#1539](https://github.com/boutproject/BOUT-dev/pull/1539) ([ZedThree](https://github.com/ZedThree)) +- Minor improvments for boutcore [\#1536](https://github.com/boutproject/BOUT-dev/pull/1536) ([dschwoerer](https://github.com/dschwoerer)) +- Remove setLocation\(\) in Field3D::operator=\(FieldPerp\) [\#1535](https://github.com/boutproject/BOUT-dev/pull/1535) ([johnomotani](https://github.com/johnomotani)) +- Derivative unit tests [\#1534](https://github.com/boutproject/BOUT-dev/pull/1534) ([ZedThree](https://github.com/ZedThree)) +- Remove checkData from copy constructor and assignment operator in Fields [\#1533](https://github.com/boutproject/BOUT-dev/pull/1533) ([d7919](https://github.com/d7919)) +- Merge v4.2.1 release into next [\#1532](https://github.com/boutproject/BOUT-dev/pull/1532) ([ZedThree](https://github.com/ZedThree)) +- Write job execution information to dump file [\#1531](https://github.com/boutproject/BOUT-dev/pull/1531) ([JosephThomasParker](https://github.com/JosephThomasParker)) +- Use third order B.C. in MMS/advection/weno3 test case. [\#1528](https://github.com/boutproject/BOUT-dev/pull/1528) ([d7919](https://github.com/d7919)) +- Documentation for Scorep [\#1525](https://github.com/boutproject/BOUT-dev/pull/1525) ([JosephThomasParker](https://github.com/JosephThomasParker)) +- Remove support for scipy/scientific netcdf libraries [\#1524](https://github.com/boutproject/BOUT-dev/pull/1524) ([d7919](https://github.com/d7919)) +- Fix typo in petsc installation instructions [\#1523](https://github.com/boutproject/BOUT-dev/pull/1523) ([bshanahan](https://github.com/bshanahan)) +- Move googletest into externalpackages [\#1522](https://github.com/boutproject/BOUT-dev/pull/1522) ([d7919](https://github.com/d7919)) +- Comment out clang-format options that are not recognised [\#1519](https://github.com/boutproject/BOUT-dev/pull/1519) ([d7919](https://github.com/d7919)) +- Fix assert in definition of FFT 2nd derivative [\#1518](https://github.com/boutproject/BOUT-dev/pull/1518) ([d7919](https://github.com/d7919)) +- Delp2 test requires fftw [\#1513](https://github.com/boutproject/BOUT-dev/pull/1513) ([dschwoerer](https://github.com/dschwoerer)) +- Two stage add coordinates [\#1506](https://github.com/boutproject/BOUT-dev/pull/1506) ([d7919](https://github.com/d7919)) +- Show available options in Factory [\#1497](https://github.com/boutproject/BOUT-dev/pull/1497) ([dschwoerer](https://github.com/dschwoerer)) +- FieldFactory: Separate parsing, looping stages in create{2,3}D [\#1494](https://github.com/boutproject/BOUT-dev/pull/1494) ([bendudson](https://github.com/bendudson)) +- specify python package versions for Travis [\#1493](https://github.com/boutproject/BOUT-dev/pull/1493) ([d7919](https://github.com/d7919)) +- Array flexible backing [\#1492](https://github.com/boutproject/BOUT-dev/pull/1492) ([d7919](https://github.com/d7919)) +- Add Matrix/Tensor::reallocate; check Arrays are of positive size [\#1491](https://github.com/boutproject/BOUT-dev/pull/1491) ([ZedThree](https://github.com/ZedThree)) +- Fix bug in fft Array interface when using odd-length signals [\#1490](https://github.com/boutproject/BOUT-dev/pull/1490) ([ZedThree](https://github.com/ZedThree)) +- Add Array::resize [\#1489](https://github.com/boutproject/BOUT-dev/pull/1489) ([ZedThree](https://github.com/ZedThree)) +- Move map and function definitions into source file for bout\_types [\#1486](https://github.com/boutproject/BOUT-dev/pull/1486) ([d7919](https://github.com/d7919)) +- Testing shiftedmetric [\#1483](https://github.com/boutproject/BOUT-dev/pull/1483) ([ZedThree](https://github.com/ZedThree)) +- Fix location of Coordinates\* in tridagCoefs [\#1481](https://github.com/boutproject/BOUT-dev/pull/1481) ([johnomotani](https://github.com/johnomotani)) +- Make absence of fftw-wisdom non-fatal in configure [\#1475](https://github.com/boutproject/BOUT-dev/pull/1475) ([d7919](https://github.com/d7919)) +- Use namespace for global variables 'mesh' and 'dump' [\#1470](https://github.com/boutproject/BOUT-dev/pull/1470) ([johnomotani](https://github.com/johnomotani)) +- Use non-Fourier Delp2 in test-multigrid\_laplace [\#1469](https://github.com/boutproject/BOUT-dev/pull/1469) ([johnomotani](https://github.com/johnomotani)) +- Reduce code duplication in interp\_to [\#1467](https://github.com/boutproject/BOUT-dev/pull/1467) ([d7919](https://github.com/d7919)) +- Ensure the location is initialised in LaplaceXZ [\#1466](https://github.com/boutproject/BOUT-dev/pull/1466) ([d7919](https://github.com/d7919)) +- Make most examples compilable [\#1458](https://github.com/boutproject/BOUT-dev/pull/1458) ([d7919](https://github.com/d7919)) +- Deprecate invert\_laplace\(\) free functions [\#1453](https://github.com/boutproject/BOUT-dev/pull/1453) ([johnomotani](https://github.com/johnomotani)) +- Remove const from bool return [\#1450](https://github.com/boutproject/BOUT-dev/pull/1450) ([bendudson](https://github.com/bendudson)) +- Verbose output [\#1447](https://github.com/boutproject/BOUT-dev/pull/1447) ([ZedThree](https://github.com/ZedThree)) +- Pass f\_aligned to standardDerivative in DDY/D2DY2/D4DY4 [\#1446](https://github.com/boutproject/BOUT-dev/pull/1446) ([johnomotani](https://github.com/johnomotani)) +- Make free interpolate use the Lagrange4pt class [\#1445](https://github.com/boutproject/BOUT-dev/pull/1445) ([d7919](https://github.com/d7919)) +- Add FieldPerp location [\#1441](https://github.com/boutproject/BOUT-dev/pull/1441) ([d7919](https://github.com/d7919)) +- Removes explicit request for timezone [\#1440](https://github.com/boutproject/BOUT-dev/pull/1440) ([d7919](https://github.com/d7919)) +- Add tool for generic operator inversion [\#1439](https://github.com/boutproject/BOUT-dev/pull/1439) ([d7919](https://github.com/d7919)) +- Be more explicit about how many threads to use in some tests. [\#1438](https://github.com/boutproject/BOUT-dev/pull/1438) ([d7919](https://github.com/d7919)) +- Non-fourier delp2 [\#1436](https://github.com/boutproject/BOUT-dev/pull/1436) ([d7919](https://github.com/d7919)) +- Fix FV::Div\_par\_K\_Grad\_par [\#1434](https://github.com/boutproject/BOUT-dev/pull/1434) ([johnomotani](https://github.com/johnomotani)) +- Location checking in ShiftedMetric::shiftZ\(\) [\#1433](https://github.com/boutproject/BOUT-dev/pull/1433) ([johnomotani](https://github.com/johnomotani)) +- Add region arguments for toFieldAligned/fromFieldAligned [\#1432](https://github.com/boutproject/BOUT-dev/pull/1432) ([johnomotani](https://github.com/johnomotani)) +- Remove result\_fa from interp\_to [\#1427](https://github.com/boutproject/BOUT-dev/pull/1427) ([johnomotani](https://github.com/johnomotani)) +- Options use variant type \(towards a DataFile replacement\) [\#1425](https://github.com/boutproject/BOUT-dev/pull/1425) ([bendudson](https://github.com/bendudson)) +- Adding toString specialisations [\#1424](https://github.com/boutproject/BOUT-dev/pull/1424) ([bendudson](https://github.com/bendudson)) +- Start to introduce zstart and zend [\#1423](https://github.com/boutproject/BOUT-dev/pull/1423) ([d7919](https://github.com/d7919)) +- Make FFTW an optional dependency [\#1422](https://github.com/boutproject/BOUT-dev/pull/1422) ([d7919](https://github.com/d7919)) +- Warnings tidyup derivative overhaul mesh [\#1420](https://github.com/boutproject/BOUT-dev/pull/1420) ([d7919](https://github.com/d7919)) +- Workaround for gcc ICE to do with binding class bound member with [\#1419](https://github.com/boutproject/BOUT-dev/pull/1419) ([d7919](https://github.com/d7919)) +- Ensure we install cython for Travis before netcdf4 [\#1417](https://github.com/boutproject/BOUT-dev/pull/1417) ([d7919](https://github.com/d7919)) +- Move index derivs out of mesh [\#1416](https://github.com/boutproject/BOUT-dev/pull/1416) ([d7919](https://github.com/d7919)) +- Add a couple of sanity tests for ffts [\#1415](https://github.com/boutproject/BOUT-dev/pull/1415) ([ZedThree](https://github.com/ZedThree)) +- Pass zShift to ShiftedMetric constructor \(backwards compatible\) [\#1413](https://github.com/boutproject/BOUT-dev/pull/1413) ([ZedThree](https://github.com/ZedThree)) +- Split backtrace generation and prettification up [\#1412](https://github.com/boutproject/BOUT-dev/pull/1412) ([ZedThree](https://github.com/ZedThree)) +- Add some missing autoconf macros needed to build configure [\#1410](https://github.com/boutproject/BOUT-dev/pull/1410) ([ZedThree](https://github.com/ZedThree)) +- Fix MAYBE\_UNUSED for some compilers [\#1409](https://github.com/boutproject/BOUT-dev/pull/1409) ([ZedThree](https://github.com/ZedThree)) +- List OpenMP schedule options in configure help [\#1408](https://github.com/boutproject/BOUT-dev/pull/1408) ([JosephThomasParker](https://github.com/JosephThomasParker)) +- Remove comm\_group as not used anywhere [\#1406](https://github.com/boutproject/BOUT-dev/pull/1406) ([bendudson](https://github.com/bendudson)) +- Remove restart.split python routine [\#1405](https://github.com/boutproject/BOUT-dev/pull/1405) ([bendudson](https://github.com/bendudson)) +- Small user manual improvements [\#1404](https://github.com/boutproject/BOUT-dev/pull/1404) ([bendudson](https://github.com/bendudson)) +- Remove even more warnings [\#1403](https://github.com/boutproject/BOUT-dev/pull/1403) ([ZedThree](https://github.com/ZedThree)) +- "Dumb" constructor for Coordinates and Vector tests [\#1402](https://github.com/boutproject/BOUT-dev/pull/1402) ([ZedThree](https://github.com/ZedThree)) +- Bugfix: new\_location check in setLocation would always be false [\#1401](https://github.com/boutproject/BOUT-dev/pull/1401) ([ZedThree](https://github.com/ZedThree)) +- Two small improvements to command line options [\#1400](https://github.com/boutproject/BOUT-dev/pull/1400) ([ZedThree](https://github.com/ZedThree)) +- More fixes for invparderiv [\#1399](https://github.com/boutproject/BOUT-dev/pull/1399) ([d7919](https://github.com/d7919)) +- Add implementation of make\_unique [\#1396](https://github.com/boutproject/BOUT-dev/pull/1396) ([ZedThree](https://github.com/ZedThree)) +- Replace deprecated C headers with C++ version [\#1391](https://github.com/boutproject/BOUT-dev/pull/1391) ([ZedThree](https://github.com/ZedThree)) +- Replace abs with std abs [\#1390](https://github.com/boutproject/BOUT-dev/pull/1390) ([d7919](https://github.com/d7919)) +- Adding simple integrated test to compile all example files [\#1389](https://github.com/boutproject/BOUT-dev/pull/1389) ([d7919](https://github.com/d7919)) +- Fix examples so most compile [\#1388](https://github.com/boutproject/BOUT-dev/pull/1388) ([d7919](https://github.com/d7919)) +- Use python unittest in runtests [\#1386](https://github.com/boutproject/BOUT-dev/pull/1386) ([ZedThree](https://github.com/ZedThree)) +- Field\* constructor tidy [\#1385](https://github.com/boutproject/BOUT-dev/pull/1385) ([ZedThree](https://github.com/ZedThree)) +- Overhaul derivatives for vectorisation and user registration [\#1384](https://github.com/boutproject/BOUT-dev/pull/1384) ([d7919](https://github.com/d7919)) +- Don't clobber command line short options when reading input file [\#1382](https://github.com/boutproject/BOUT-dev/pull/1382) ([ZedThree](https://github.com/ZedThree)) +- Bc docs [\#1381](https://github.com/boutproject/BOUT-dev/pull/1381) ([dschwoerer](https://github.com/dschwoerer)) +- Basic Vector support for boutcore [\#1380](https://github.com/boutproject/BOUT-dev/pull/1380) ([dschwoerer](https://github.com/dschwoerer)) +- Fix:Escaping in makefile [\#1379](https://github.com/boutproject/BOUT-dev/pull/1379) ([dschwoerer](https://github.com/dschwoerer)) +- Add documentation [\#1376](https://github.com/boutproject/BOUT-dev/pull/1376) ([dschwoerer](https://github.com/dschwoerer)) +- Remove regeneration test [\#1375](https://github.com/boutproject/BOUT-dev/pull/1375) ([dschwoerer](https://github.com/dschwoerer)) +- Print command line options to output\_info [\#1373](https://github.com/boutproject/BOUT-dev/pull/1373) ([johnomotani](https://github.com/johnomotani)) +- Remove uses of global 'mesh' from Laplacian solvers [\#1371](https://github.com/boutproject/BOUT-dev/pull/1371) ([johnomotani](https://github.com/johnomotani)) +- Set location in LaplaceCyclic::solve\(\) and DC\(\) [\#1367](https://github.com/boutproject/BOUT-dev/pull/1367) ([johnomotani](https://github.com/johnomotani)) +- Move the definition of `\_\_thefunc\_\_` and add AUTO\_TRACE [\#1366](https://github.com/boutproject/BOUT-dev/pull/1366) ([d7919](https://github.com/d7919)) +- Optimisations to certain vector routines [\#1363](https://github.com/boutproject/BOUT-dev/pull/1363) ([d7919](https://github.com/d7919)) +- Clean squashoutput.py [\#1362](https://github.com/boutproject/BOUT-dev/pull/1362) ([dschwoerer](https://github.com/dschwoerer)) +- Fix path for locale files [\#1360](https://github.com/boutproject/BOUT-dev/pull/1360) ([dschwoerer](https://github.com/dschwoerer)) +- Remove last DataIterator references/uses [\#1358](https://github.com/boutproject/BOUT-dev/pull/1358) ([ZedThree](https://github.com/ZedThree)) +- Disable broken tests [\#1356](https://github.com/boutproject/BOUT-dev/pull/1356) ([dschwoerer](https://github.com/dschwoerer)) +- Comment out clang-format directives that need clang-format \>= 6 [\#1353](https://github.com/boutproject/BOUT-dev/pull/1353) ([ZedThree](https://github.com/ZedThree)) +- Support BoutReal and file-level attributes for netCDF and HDF5 files [\#1350](https://github.com/boutproject/BOUT-dev/pull/1350) ([johnomotani](https://github.com/johnomotani)) +- Delete dependency .mk files in clean target [\#1348](https://github.com/boutproject/BOUT-dev/pull/1348) ([bendudson](https://github.com/bendudson)) +- Boundary keywords and bugfix [\#1346](https://github.com/boutproject/BOUT-dev/pull/1346) ([bendudson](https://github.com/bendudson)) +- Add multiple parallel slices [\#1345](https://github.com/boutproject/BOUT-dev/pull/1345) ([ZedThree](https://github.com/ZedThree)) +- Reuse fixture for creating/destroying FakeMesh [\#1344](https://github.com/boutproject/BOUT-dev/pull/1344) ([ZedThree](https://github.com/ZedThree)) +- Clang format update [\#1343](https://github.com/boutproject/BOUT-dev/pull/1343) ([ZedThree](https://github.com/ZedThree)) +- Fix FV::Div\_Par\_K\_Grad\_Par [\#1341](https://github.com/boutproject/BOUT-dev/pull/1341) ([johnomotani](https://github.com/johnomotani)) +- Changing README example to use cross rather than ^ [\#1340](https://github.com/boutproject/BOUT-dev/pull/1340) ([bendudson](https://github.com/bendudson)) +- Remove `using std::string` etc from headers [\#1339](https://github.com/boutproject/BOUT-dev/pull/1339) ([ZedThree](https://github.com/ZedThree)) +- Boutexception backtrace tidy [\#1338](https://github.com/boutproject/BOUT-dev/pull/1338) ([ZedThree](https://github.com/ZedThree)) +- A couple of small bugfixes for Zoidberg [\#1337](https://github.com/boutproject/BOUT-dev/pull/1337) ([ZedThree](https://github.com/ZedThree)) +- Internationalisation with gettext [\#1335](https://github.com/boutproject/BOUT-dev/pull/1335) ([bendudson](https://github.com/bendudson)) +- Expressions improvements: escape chars and unicode [\#1333](https://github.com/boutproject/BOUT-dev/pull/1333) ([bendudson](https://github.com/bendudson)) +- Save run information to settings file [\#1332](https://github.com/boutproject/BOUT-dev/pull/1332) ([bendudson](https://github.com/bendudson)) +- Remove more deprecated derivs boundaries [\#1331](https://github.com/boutproject/BOUT-dev/pull/1331) ([d7919](https://github.com/d7919)) +- Add unary operator+ to fields [\#1329](https://github.com/boutproject/BOUT-dev/pull/1329) ([bendudson](https://github.com/bendudson)) +- Add support for enum class [\#1328](https://github.com/boutproject/BOUT-dev/pull/1328) ([dschwoerer](https://github.com/dschwoerer)) +- Remove deprecated routines [\#1326](https://github.com/boutproject/BOUT-dev/pull/1326) ([d7919](https://github.com/d7919)) + ## [v4.2.2](https://github.com/boutproject/BOUT-dev/tree/v4.2.2) (2019-02-27) [Full Changelog](https://github.com/boutproject/BOUT-dev/compare/v4.2.1...v4.2.2) @@ -1065,3 +1356,6 @@ \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* diff --git a/change_summary.md b/change_summary.md index ab6b0fa035..3096edf9d7 100644 --- a/change_summary.md +++ b/change_summary.md @@ -3,6 +3,169 @@ This is a slightly more readable, and therefore incomplete, summary of the changes from the full [changelog](CHANGELOG.md) +4.3.0 is a big feature release: +- `Field`s are now "tagged" with their "y-direction": that is, whether + they are in field-aligned space or not; as well as their + "z-direction", whether or not they are constant in z. This allows us + to perform more internal checking, for example, that only + field-aligned `Field3D`s are passed to `fromFieldAligned` and that + calculations are done in the correct space +- Add `toFieldAligned` and `fromFieldAligned` free functions +- `bout::utils::is_Field` and variants provide simpler methods of + checking that input types are `Field`s in templated code +- Many, many more functions and operators support staggering. We're + now also much more consistent about checking function arguments have + compatible staggered locations +- New `emptyFrom(f)` and `zeroFrom(f)` helper functions for creating + `Field`s either allocated but initialised, or allocated and + initialised to `0.0` respectively, while ensuring the result is + compatible with the `Field` `f` (same mesh, same staggering, etc.) +- Expressions used in input files now have support for unicode, + escaping characters and implicit multiplication. See + [\#1333](https://github.com/boutproject/BOUT-dev/pull/1333) for more + details. +- Internationalisation support, including translations for French, + German, Spanish, and Simplified and Traditional Chinese +- Keyword arguments for boundaries in input files, e.g. `dirichlet(1, + width=3)` +- File-level attributes in output files +- Write more things to output files, including processor indices and + parallel transform information +- Complete overhaul of the derivative operators: + - derivative operators can now use native vectorisation where + possible, as well parallelisation via OpenMP. + - users can register their own derivative operators and choose + them at runtime + - more consistent handling of staggering in all directions and for + all `Field` types + - better handling of field-aligned `Field`s +- Various bug fixes for parallel derivative inversions +- Introduced `zstart` and `zend`, in preparation for introducing + guard cells in the z-direction +- `Options` has several new features: + - it can now store `Field`s. This uses an [implementation][mpark] + of C++17's `std::variant` backported to work with + C++11. Unfortunately, there are some compilers which have + problems (see [installation issues][xlc] for help) + - `Options::isSection` gained the ability to check whether an + input argument is a subsection or not + - now records the type of the option when used + - gained the `.doc` method which allows documentation to be added + as an attribute, which can be recorded in the `BOUT.settings` + file post-run +- FFTW is now an optional dependency +- A non-Fourier implementation of `Delp2` +- A generic linear operator inversion class (see + [\#1439](https://github.com/boutproject/BOUT-dev/pull/1439)) +- `Array`, `Matrix` and `Tensor` all gained a `reallocate` + method. This allows dynamic resizing of those objects, but + invalidates the existing data +- `FieldFactory` now has separate parsing and generatoring stages, so + functions can be parsed once and evaluated multiple times (e.g. for + time-dependent functions) +- Enable communications for simulations with no core, only divertor + legs +- `Coordinates` on staggered grids can now be read from grid files +- New `FDDX_U2` implementation +- Support for SUNDIALS versions 2.6 to 4.1.0 +- `BoutInitialise` has been pulled apart into separate utility + functions under the `bout::experimental` namespace so that they can + be used individually +- `LaplaceCyclic` now accepts `C1` and `C2` coefficients which may be + different +- `LaplaceNaulin` may use the DC parts of `C` for faster convergence +- `LaplaceNaulin` also gained an under-relaxation factor, which may + improve convergence and robustness +- The `Laplace` solvers gained a `uses3DCoefs` method. This returns + `true` if the solver can make use of `Field3D` coefficients rather + than using the DC component of them +- A new time `Solver`: Runge-Kutta-Legendre stabilised explicit + method, `splitrk`. See + [\#1673](https://github.com/boutproject/BOUT-dev/pull/1673) for more + details +- Experimental support for CMake +- Added `HeatFluxSNB` which calculates heat flux using the + Shurtz-Nicolai-Busquet (SNB) model. Nonlocal (kinetic) corrections + to the Spitzer-Harm collisional heat flux, which become important + when the mean free path becomes a small (~1%) fraction of the + temperature scale length +- The new `BOUT_SCOREP_REGION("name")` will automatically instrument a + scope with [Score-P][scorep] if BOUT++ was compiled with Score-P + support (see the [documentation][scorepdocs] for more information) +- `NYPE` may be given instead of `NXPE` in input files for decomposing + the mesh in `(x, y)` +- Many fixes and improvements for Hypnotoad: + - Use centred differencing to compute `dx` from `psi` instead of + forward differencing + - Fix for when the separatrix is exactly on a grid point + - Fix for when the separatrix is very close to the X-point + - Fix computation of `ShiftAngle` + - Add a checkbox to the 'Output' tab, which if selected outputs + metrics for orthogonal coordinates (i.e. using `ShiftedMetric`) + - We now check what coordinate system was used to generate grid + files in Hypnotoad when reading them in BOUT++ + - _Lots_ of fixes for non-orthogonal grids (see + [\#1593](https://github.com/boutproject/BOUT-dev/pull/1593), + [\#1596](https://github.com/boutproject/BOUT-dev/pull/1596), and + [\#1636](https://github.com/boutproject/BOUT-dev/pull/1636)) + - Use double precision everywhere + - Add option to write y-boundary guard cells + - See [here for a complete + list](https://github.com/boutproject/BOUT-dev/pulls?q=Hypnotoad+is%3Apr+is%3Amerged+created%3A2018-10-16..2019-10-24++base%3Anext) +- Many, many more tests! Unit test coverage since v4.2.0 has doubled +- We have begun to move parts of the codebase into a `bout::` + namespace. This should help ensure we play nice with other + libraries, as well as logically group related things across parts of + the codebase + +[mpark]: https://github.com/mpark/variant +[xlc]: https://bout-dev.readthedocs.io/en/latest/user_docs/advanced_install.html#issues +[scorep]: https://www.vi-hps.org/projects/score-p/ +[scorepdocs]: https://bout-dev.readthedocs.io/en/latest/developer_docs/performance_profiling.html#scorep-scalasca-profiling + +Deprecations: +- `invert_laplace`: create an instance of a `Laplacian` via + `Laplacian::create` and use the `setCoef*` and `solve` methods +- Karniadakis time `Solver`: the current implementation is _very_ slow + and will be removed in 5.0 +- `MsgStack::setPoint`: use `MsgStack::push("")` +- The following `Mesh` methods were experimental, low-level + communication routines that turned out to not be so useful: + - `sendToProc` + - `receiveFromProc` + - `UpXSplitIndex` + - `DownXSplitIndex` + - `sendYOutIndest` + - `sendYOutOutdest` + - `sendYInIndest` + - `sendYInOutdest` + - `irecvYOutIndest` + - `irecvYOutOutdest` + - `irecvYInIndest` + - `irecvYInOutdest` +- `Mesh::XGLOBAL` and `Mesh::YGLOBAL`: use `Mesh::getGlobalXIndex` and + either `Mesh::getGlobalYIndexNoBoundaries` or + `Mesh::getGlobalYIndex` instead. The former (`NoBoundaries`) is a + direct replacement for `YGLOBAL`, whereas the latter includes the + boundaries and so is consistent with `XGLOBAL` which does too +- `Laplacian::setFlags`: use `Laplacian::setGlobalFlags`, + `Laplacian::setInnerBoundaryFlags` and + `Laplacian::setOuterBoundaryFlags` instead +- The staggered parallel differential operators that end `CtoL` or + `LtoC` (e.g. `Div_par_CtoL`, `Grad_par_LtoC`): the corresponding + versions without the suffix now support staggering. For example, + instead of `Div_par_CtoL(f)` use `Div_par(f, CELL_YLOW)` instead + +Removed: +- The `serial` implementation of `parderiv`. The `cyclic` version + works both serially and in parallel +- `comm_group`: not used internally and too low-level to be useful +- Support for the `scipy` and `scientific` netCDF libraries in + `boututils` has been dropped. These were very slow and `scientific` + is no longer available +- `Laplace3D`: use `Laplacian` instead + + 4.2.0 is a big feature release: - Large number of optimisations (as much as 140% faster than v4.1.2!) - OpenMP in many more places, enables parallelisation in Z (as well as From f13b431ab6ce61ddaf696093d9408f3524d47b9a Mon Sep 17 00:00:00 2001 From: Peter Hill Date: Fri, 25 Oct 2019 13:19:58 +0100 Subject: [PATCH 1783/1783] Fix typos and y-direction tagging in changelog --- change_summary.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/change_summary.md b/change_summary.md index 3096edf9d7..6357883445 100644 --- a/change_summary.md +++ b/change_summary.md @@ -5,11 +5,12 @@ the changes from the full [changelog](CHANGELOG.md) 4.3.0 is a big feature release: - `Field`s are now "tagged" with their "y-direction": that is, whether - they are in field-aligned space or not; as well as their - "z-direction", whether or not they are constant in z. This allows us - to perform more internal checking, for example, that only - field-aligned `Field3D`s are passed to `fromFieldAligned` and that - calculations are done in the correct space + they are in field-aligned space or not. This allows us to perform + more internal checking, for example, that only field-aligned + `Field3D`s are passed to `fromFieldAligned` and that calculations + are done in the correct y-direction space. Users may need to call + `f.setDirectionY(YDirectionType::Aligned)` for a `Field3D f` to set + the direction tag - Add `toFieldAligned` and `fromFieldAligned` free functions - `bout::utils::is_Field` and variants provide simpler methods of checking that input types are `Field`s in templated code @@ -17,7 +18,7 @@ the changes from the full [changelog](CHANGELOG.md) now also much more consistent about checking function arguments have compatible staggered locations - New `emptyFrom(f)` and `zeroFrom(f)` helper functions for creating - `Field`s either allocated but initialised, or allocated and + `Field`s either allocated but not initialised, or allocated and initialised to `0.0` respectively, while ensuring the result is compatible with the `Field` `f` (same mesh, same staggering, etc.) - Expressions used in input files now have support for unicode, @@ -60,7 +61,7 @@ the changes from the full [changelog](CHANGELOG.md) - `Array`, `Matrix` and `Tensor` all gained a `reallocate` method. This allows dynamic resizing of those objects, but invalidates the existing data -- `FieldFactory` now has separate parsing and generatoring stages, so +- `FieldFactory` now has separate parsing and generating stages, so functions can be parsed once and evaluated multiple times (e.g. for time-dependent functions) - Enable communications for simulations with no core, only divertor